........... Posted July 10, 2020 Share Posted July 10, 2020 I am attempting to create a mod that allows me to toggle my minion ai, to either make them stop kiting or stop attacking/working. That means I need to modify the brain for them. For the brain shadowwaxwellbrain.lua Spoiler require "behaviours/wander" require "behaviours/faceentity" require "behaviours/chaseandattack" require "behaviours/panic" require "behaviours/follow" require "behaviours/attackwall" require "behaviours/standstill" require "behaviours/leash" require "behaviours/runaway" local ShadowWaxwellBrain = Class(Brain, function(self, inst) Brain._ctor(self, inst) end) --Images will help chop, mine and fight. local MIN_FOLLOW_DIST = 0 local TARGET_FOLLOW_DIST = 6 local MAX_FOLLOW_DIST = 8 local START_FACE_DIST = 6 local KEEP_FACE_DIST = 8 local KEEP_WORKING_DIST = 14 local SEE_WORK_DIST = 10 local KEEP_DANCING_DIST = 2 local KITING_DIST = 3 local STOP_KITING_DIST = 5 local RUN_AWAY_DIST = 5 local STOP_RUN_AWAY_DIST = 8 local AVOID_EXPLOSIVE_DIST = 5 local DIG_TAGS = { "stump", "grave" } local function GetLeader(inst) return inst.components.follower.leader end local function GetLeaderPos(inst) return inst.components.follower.leader:GetPosition() end local function GetFaceTargetFn(inst) local target = FindClosestPlayerToInst(inst, START_FACE_DIST, true) return target ~= nil and not target:HasTag("notarget") and target or nil end local function IsNearLeader(inst, dist) local leader = GetLeader(inst) return leader ~= nil and inst:IsNear(leader, dist) end local TOWORK_CANT_TAGS = { "fire", "smolder", "event_trigger", "INLIMBO", "NOCLICK" } local function FindEntityToWorkAction(inst, action, addtltags) local leader = GetLeader(inst) if leader ~= nil then --Keep existing target? local target = inst.sg.statemem.target if target ~= nil and target:IsValid() and not (target:IsInLimbo() or target:HasTag("NOCLICK") or target:HasTag("event_trigger")) and target:IsOnValidGround() and target.components.workable ~= nil and target.components.workable:CanBeWorked() and target.components.workable:GetWorkAction() == action and not (target.components.burnable ~= nil and (target.components.burnable:IsBurning() or target.components.burnable:IsSmoldering())) and target.entity:IsVisible() and target:IsNear(leader, KEEP_WORKING_DIST) then if addtltags ~= nil then for i, v in ipairs(addtltags) do if target:HasTag(v) then return BufferedAction(inst, target, action) end end else return BufferedAction(inst, target, action) end end --Find new target target = FindEntity(leader, SEE_WORK_DIST, nil, { action.id.."_workable" }, TOWORK_CANT_TAGS, addtltags) return target ~= nil and BufferedAction(inst, target, action) or nil end end local function KeepFaceTargetFn(inst, target) return not target:HasTag("notarget") and inst:IsNear(target, KEEP_FACE_DIST) end local function DanceParty(inst) inst:PushEvent("dance") end local function ShouldDanceParty(inst) local leader = GetLeader(inst) return leader ~= nil and leader.sg:HasStateTag("dancing") end local function ShouldAvoidExplosive(target) return target.components.explosive == nil or target.components.burnable == nil or target.components.burnable:IsBurning() end local function ShouldRunAway(target) return not (target.components.health ~= nil and target.components.health:IsDead()) and (not target:HasTag("shadowcreature") or (target.components.combat ~= nil and target.components.combat:HasTarget())) end local function ShouldKite(target, inst) return inst.components.combat:TargetIs(target) and target.components.health ~= nil and not target.components.health:IsDead() end local function ShouldWatchMinigame(inst) if inst.components.follower.leader ~= nil and inst.components.follower.leader.components.minigame_participator ~= nil then if inst.components.combat.target == nil or inst.components.combat.target.components.minigame_participator ~= nil then return true end end return false end local function WatchingMinigame(inst) return (inst.components.follower.leader ~= nil and inst.components.follower.leader.components.minigame_participator ~= nil) and inst.components.follower.leader.components.minigame_participator:GetMinigame() or nil end function ShadowWaxwellBrain:OnStart() local watch_game = WhileNode( function() return ShouldWatchMinigame(self.inst) end, "Watching Game", PriorityNode({ Follow(self.inst, WatchingMinigame, TUNING.MINIGAME_CROWD_DIST_MIN, TUNING.MINIGAME_CROWD_DIST_TARGET, TUNING.MINIGAME_CROWD_DIST_MAX), RunAway(self.inst, "minigame_participator", 5, 7), FaceEntity(self.inst, WatchingMinigame, WatchingMinigame), }, 0.25)) local root = PriorityNode( { watch_game, --#1 priority is dancing beside your leader. Obviously. WhileNode(function() return ShouldDanceParty(self.inst) end, "Dance Party", PriorityNode({ Leash(self.inst, GetLeaderPos, KEEP_DANCING_DIST, KEEP_DANCING_DIST), ActionNode(function() DanceParty(self.inst) end), }, .25)), WhileNode(function() return IsNearLeader(self.inst, KEEP_WORKING_DIST) end, "Leader In Range", PriorityNode({ --All shadows will avoid explosives RunAway(self.inst, { fn = ShouldAvoidExplosive, tags = { "explosive" }, notags = { "INLIMBO" } }, AVOID_EXPLOSIVE_DIST, AVOID_EXPLOSIVE_DIST), --Duelists will try to fight before fleeing IfNode(function() return self.inst.prefab == "shadowduelist" end, "Is Duelist", PriorityNode({ WhileNode(function() return self.inst.components.combat:GetCooldown() > .5 and ShouldKite(self.inst.components.combat.target, self.inst) end, "Dodge", RunAway(self.inst, { fn = ShouldKite, tags = { "_combat", "_health" }, notags = { "INLIMBO" } }, KITING_DIST, STOP_KITING_DIST)), ChaseAndAttack(self.inst), }, .25)), --All shadows will flee from danger at this point RunAway(self.inst, { fn = ShouldRunAway, oneoftags = { "monster", "hostile" }, notags = { "player", "INLIMBO" } }, RUN_AWAY_DIST, STOP_RUN_AWAY_DIST), --Workiers will try to work if not fleeing IfNode(function() return self.inst.prefab == "shadowlumber" end, "Keep Chopping", DoAction(self.inst, function() return FindEntityToWorkAction(self.inst, ACTIONS.CHOP) end)), IfNode(function() return self.inst.prefab == "shadowminer" end, "Keep Mining", DoAction(self.inst, function() return FindEntityToWorkAction(self.inst, ACTIONS.MINE) end)), IfNode(function() return self.inst.prefab == "shadowdigger" end, "Keep Digging", DoAction(self.inst, function() return FindEntityToWorkAction(self.inst, ACTIONS.DIG, DIG_TAGS) end)), }, .25)), Follow(self.inst, GetLeader, MIN_FOLLOW_DIST, TARGET_FOLLOW_DIST, MAX_FOLLOW_DIST), WhileNode(function() return GetLeader(self.inst) ~= nil end, "Has Leader", FaceEntity(self.inst, GetFaceTargetFn, KeepFaceTargetFn)), }, .25) self.bt = BT(self.inst, root) end return ShadowWaxwellBrain I am attempting to add nodes ConstAttack: Spoiler WhileNode(function() return REVISED_MAXWELL_ATT == true and self.inst.prefab == "shadowduelist" end, "Constant Attack", ChaseAndAttack(self.inst) ) and node ConstRun: Spoiler WhileNode(function() return REVISED_MAXWELL_RUN == true end, "Constant Run", RunAway(self.inst, { fn = ShouldRunAway, oneoftags = { "monster", "hostile" }, notags = { "player", "INLIMBO" } }, RUN_AWAY_DIST, STOP_RUN_AWAY_DIST) ) Previously I just copied and overrode the file, but that is apparently terrible modding practice, so I am attempting to do it via AddBrainPostInit Here is the relevant code that I am using: Spoiler AddBrainPostInit("shadowwaxwellbrain", function(brain) local leadInRange = nil for i,node in ipairs(brain.bt.root.children) do if node.name == "Leader In Range" then leadInRange = node break end end if not leadInRange then print("Couldn't find the 'Leader In Range' behaviour in this brain!") return end local priority = nil for i,node in ipairs(leadInRange.children) do if node.name == "Priority" then leadInRange = node break end end if not priority then print("Couldn't find the 'Priority' behaviour in this brain!") return end local runAway = nil for i,node in ipairs(priority.children) do if node.name == "RunAway" then runAway = i break end end if not runAway then print("Couldn't find the 'RunAway' behaviour in this brain!") return end table.insert(priority, runAway+1, WhileNode(function() return REVISED_MAXWELL_RUN == true end, "Constant Run", RunAway(self.inst, { fn = ShouldRunAway, oneoftags = { "monster", "hostile" }, notags = { "player", "INLIMBO" } }, RUN_AWAY_DIST, STOP_RUN_AWAY_DIST) ) ) table.insert(priority, runAway+2, WhileNode(function() return REVISED_MAXWELL_ATT == true and self.inst.prefab == "shadowduelist" end, "Constant Attack", ChaseAndAttack(self.inst) ) ) end) But it can't find any of the nodes for some reason. What am I doing wrong? Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now