GalaxySugar Posted May 26, 2024 Share Posted May 26, 2024 Been trying to work outside my comfort zone by experimenting with entity behavior / brains. It's not really something I have experience with. I've made Rockjaws act a little more menacing by circling their target / their target's boat before attacking, but when they leap off the boat it breaks their stalking behavior for some reason and I can't figure out why. Also their wandering behavior doesn't work at all...? Experimental Rockjaw Brain: Spoiler require "behaviours/wander" require "behaviours/chaseandattack" require "behaviours/attackwall" require "behaviours/minperiod" require "behaviours/leash" require "behaviours/faceentity" require "behaviours/doaction" require "behaviours/standstill" require("behaviours/runaway") local BrainCommon = require("brains/braincommon") ---------------------------------------------------------------------------------------------------------------------------------------------------- local RESET_COMBAT_DELAY = 10 local MIN_STALKING_TIME = 2 local MAX_STALKING_CHASE_TIME = 4 local RUN_AWAY_DIST = 6 local STOP_RUN_AWAY_DIST = 6 local HUNTER_PARAMS = { tags = { "_combat" }, notags = { "INLIMBO", "playerghost", "invisible", "hidden", "flight", "shadowcreature" }, oneoftags = { "character", "monster", "largecreature", "shadowminion" }, fn = function(ent, inst) --Don't run away from non-hostile animals unless they are attacking us return ent.components.combat:TargetIs(inst) or ent:HasTag("character") or ent:HasTag("monster") or ent:HasTag("shadowminion") end, } local SharkBrain = Class(Brain, function(self, inst) Brain._ctor(self, inst) end) ---------------------------------------------------------------------------------------------------------------------------------------------------- local function isOnWater(inst) return not inst:GetCurrentPlatform() and not TheWorld.Map:IsVisualGroundAtPoint(inst.Transform:GetWorldPosition()) end local function Leap(inst) inst:PushEvent("leap") inst.components.timer:StartTimer("leap_cd", TUNING.MINOTAUR_LEAP_CD * 10) end local function ShouldChase_Boat(inst) return inst.components.combat:HasTarget() and inst.components.combat.target:GetCurrentPlatform() and not inst.components.combat:InCooldown() and not inst.components.timer:TimerExists("leap_cd") end local function Attack(inst) inst:PushEvent("dobite") end --==================-- --==oO STALKING Oo==-- --==================-- local function GetHomePos(inst) return inst.components.knownlocations:GetLocation("prison") end local function ShouldStalk(inst) return inst:IsStalking() and (inst.components.combat:InCooldown() or not inst.components.combat:HasTarget()) end local function ShouldCircle(inst) return inst.components.combat:HasTarget() and inst.components.combat:InCooldown() and not inst:IsStalking() end local function ShouldChase_Water(inst) return inst.components.combat:HasTarget() and not inst.components.combat.target:GetCurrentPlatform() and not inst.components.combat:InCooldown() end local function DoStalking(inst) --print() --print("------------------------") local target = inst:GetStalking() if target ~= nil then if target:GetCurrentPlatform() ~= nil then --print("Target is on a boat") target = target:GetCurrentPlatform() end --print("TARGET : "..target) local x, y, z = inst.Transform:GetWorldPosition() local x1, y1, z1 = target.Transform:GetWorldPosition() local dx = x1 - x local dz = z1 - z local dist = math.sqrt(dx * dx + dz * dz) --print("DIST : "..dist) local strafe_angle = Remap(math.clamp(dist, 4, 8), 4, 8, 135, 75) --print("STRAFE_ANGLE : "..strafe_angle) local rot = inst.Transform:GetRotation() --print("ROTATION : "..rot) local rot1 = math.atan2(-dz, dx) * RADIANS --print("ROT_1 :"..rot1) local rota = rot1 - strafe_angle local rotb = rot1 + strafe_angle --print("ROT_A : "..rota) --print("ROT_A : "..rotb) if DiffAngle(rot, rota) < 30 then rot1 = rota elseif DiffAngle(rot, rotb) < 30 then rot1 = rotb else rot1 = math.random() < 0.5 and rota or rotb end rot1 = rot1 * DEGREES --print("NEW ROT_1 : "..rot1) --print("VECTOR3 : "..(x + math.cos(rot1) * 10, 0, z - math.sin(rot1) * 10)) --print("------------------------") return Vector3(x + math.cos(rot1) * 10, 0, z - math.sin(rot1) * 10) end end local function IsStalkingFar(inst) local target = inst:GetStalking() return target ~= nil and not inst:IsNear(target, 8) end local function IsStalkingTooClose(inst) local target = inst:GetStalking() return target ~= nil and inst:IsNear(target, TUNING.DAYWALKER_ATTACK_RANGE) end local function IsStalkingTooFar(inst) local target = inst:GetStalking() return target ~= nil and not inst:IsNear(target, TUNING.DAYWALKER_ATTACK_RANGE *3) end local function GetFaceTargetFn(inst) return inst.components.combat.target end local function KeepFaceTargetFn(inst, target) return inst.components.combat:TargetIs(target) end --===============-- --==oO CLAMP Oo==-- Unused for now. --===============-- local function PushClamp(inst, target) inst:PushEvent("clamp", {target = self.inst.components.combat.target:GetCurrentPlatform()}) end --================-- --==oO WANDER Oo==-- --================-- local function removefood(inst, target) if inst._removefood ~= nil then inst.foodtoeat = nil inst:RemoveEventCallback("onremove", inst._removefood, target) inst:RemoveEventCallback("onpickup", inst._removefood, target) inst._removefood = nil end end local function isfoodnearby(inst) local target = FindEntity(inst, SEE_DIST, function(item) return inst.components.eater:CanEat(item) and not item:GetCurrentPlatform() and not TheWorld.Map:IsVisualGroundAtPoint(item.Transform:GetWorldPosition()) end) -- don't target food if its too close..ironically if target and target:GetDistanceSqToInst(inst) < 6*6 then return nil end if inst.foodtoeat ~= target then removefood(inst) if target then inst.foodtoeat = target inst._removefood = function() removefood(inst, target) end inst:ListenForEvent("onremove", inst._removefood, target) inst:ListenForEvent("onpickup", inst._removefood, target) return BufferedAction(inst, target, ACTIONS.EAT) end end end local function EatFishAction(inst) if not inst.components.timer:TimerExists("gobble_cooldown") then local target = FindEntity(inst, SEE_FOOD_DIST, function(food) return TheWorld.Map:IsOceanAtPoint(inst.Transform:GetWorldPosition()) end, nil, nil, {"oceanfish"}) if target then inst.foodtarget = target local targetpos = Vector3(target.Transform:GetWorldPosition()) local act = BufferedAction(inst, target, ACTIONS.EAT) act.validfn = function() return not (target.components.inventoryitem and target.components.inventoryitem:IsHeld()) end return act end end return nil end local WANDER_TIMES = {minwalktime=2, randwalktime=0.5, minwaittime=0.0, randwaittime=0.0} local function GetWanderPoint(inst) local target = inst:GetNearestPlayer(true) return target ~= nil and target:GetPosition() or nil end local function getdirectionFn(inst) local DIST = 6 local theta = inst.Transform:GetRotation() * DEGREES local offset = Vector3(DIST * math.cos( theta ), 0, -DIST * math.sin( theta )) local x,y,z = inst.Transform:GetWorldPosition() local r = math.random() * 2 - 1 local newdir = (inst.Transform:GetRotation() + r*r*r * 60) * DEGREES if TheWorld.Map:IsVisualGroundAtPoint(x+offset.x,0,z+offset.z) then newdir = newdir + PI end return newdir end function SharkBrain:OnStart() local root = PriorityNode({ WhileNode(function() return not self.inst.sg:HasStateTag("jumping") end, "NotJumpingBehaviour", PriorityNode({ --IF NOT IN WATER, PUSH AOE ATTACK. No need for any other check, Sharks automatically jump off towards nearest ocean tile. WhileNode(function() return not isOnWater(self.inst) end, "NOT on water", PriorityNode({ DoAction(self.inst, Attack, "attack", true), self.inst:StartAttackCooldown() })), --IF NO TARGET, WANDER AND EAT FISH. This doesn't work at all. WhileNode(function() return isOnWater(self.inst) and not self.inst.components.combat:HasTarget() end, "on water", PriorityNode({ BrainCommon.PanicTrigger(self.inst), DoAction(self.inst, isfoodnearby, "gotofood", true), DoAction(self.inst, EatFishAction, "eat fish", true), Wander(self.inst, GetWanderPoint, 40, WANDER_TIMES, getdirectionFn) })), --CHECK IF WE SHOULD CIRCLE TARGET. WhileNode(function() return ShouldCircle(self.inst) end, "Set Circle Target", PriorityNode({ NotDecorator(ActionNode(function() if self.inst.canstalk and not self.inst.components.timer:TimerExists("stalk_cd") then self.inst:SetStalking(self.inst.components.combat.target) end if self.inst:IsStalking() then self.inst:StartAttackCooldown() else self.inst.components.combat:ResetCooldown() end end)), })), --CIRLCE TARGET. IF TARGET TOO FAR, THEN BYPASS ATTACK COOLDOWN. WhileNode(function() return ShouldStalk(self.inst) end, "Stalking", ParallelNode{ SequenceNode{ ParallelNodeAny{ WaitNode(MIN_STALKING_TIME), ConditionWaitNode(function() return IsStalkingFar(self.inst) end), }, ConditionWaitNode(function() return IsStalkingTooFar(self.inst) end), ActionNode(function() self.inst.components.combat:ResetCooldown() end), }, Leash(self.inst, DoStalking, 0, 0, false), }), --ATTACK TARGET IF COMBAT COOLDOWN TIMER RUNS OUT. --TODO: IF TARGET ON BOAT, SWAP BETWEEN CLAMPING DOWN ON BOAT(like crabking_claw) / RAMMING INTO BOAT / JUMPING ABOARD. --IF OUR TARGET IS IN WATER, CHASE AND ATTACK. WhileNode(function() return ShouldChase_Water(self.inst) end, "Chase", PriorityNode({ WhileNode(function() return self.inst:IsStalking() end, "Stalking Chase", ParallelNodeAny{ SequenceNode{ WaitNode(MAX_STALKING_CHASE_TIME), ActionNode(function() self.inst:SetStalking(nil) end), }, ChaseAndAttack(self.inst, nil, nil, nil, nil, true), }), ChaseAndAttack(self.inst), })), --IF TARGET ON BOAT AND NO LEAP TIMER, LEAP ABOARD BOAT. This stops stalking behaviour after for some reason...? WhileNode(function() return ShouldChase_Boat(self.inst) end, "Leap To Boat", ActionNode(function() Leap(self.inst) end) ), })), }) self.bt = BT(self.inst, root) end return SharkBrain Link to comment https://forums.kleientertainment.com/forums/topic/156363-need-help-with-new-rockjaw-behaviour/ 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