====== Lua AI Common Function Repository ====== -- AI function repository by king bore haha / george -- Made for DS1, but knowledge is very compatible with other games. -- OnIf. Allows mid-action logic -- Example: "combo 1, OnIf" allows you to recheck the target's distance and angle and decide the combo followup attack afterwards. function OnIf_######(ai, goal, codeNo) -- Change ###### to the number ID defined in goal_list.lua (example: for Gwyn, it would be 537000) -- GOAL_COMMON_If codeNo can be checked here for different behavior. if codeNo == 10 then -- -- Action go here elseif codeNo == 20 then -- Action go here end return end goal:AddSubGoal(GOAL_COMMON_If, 10, codeNo) -- codeNo checked in onIf function to allow different behavior -- OnIf v2.0, devised by Meowmaritus ENABLE_COMBO_ATK_CANCEL(GOAL_COMMON_If) -- Allows GOAL_COMMON_If to utilize Combo recovery events. (Personally, I put this in "if.lua".) function OnIf_######(ai, goal, codeNo) -- Change ###### to the number ID defined in goal_list.lua (example: for Gwyn, it would be 537000) -- GOAL_COMMON_If codeNo can be checked here for different behavior. if codeNo == 3000 then -- -- Action go here elseif codeNo == 3010 then -- Action go here end -- goal:AddSubGoal(GOAL_COMMON_ComboFinal, 0, 0, TARGET_ENE_0, 0, 0) -- forcibly end combo (no matter what) return end goal:AddSubGoal(GOAL_COMMON_If, 10, codeNo) -- codeNo checked in onIf function to allow different behavior -- goal:AddSubGoal -- Add an AI goal. first in, first out goal:AddtopGoal -- Add an AI goal. PROBABLY added to the top of priority list goal:ClearSubGoal() -- Clear all queued goals ai:GetRandam_Int(ValueMin, ValueMax) -- generate integer between values ai:GetRandam_Float(ValueMin, ValueMax) -- generate float between values -- Event request. Gets value from EMEVD command RequestCharacterAICommand(EntityID, SendValue, SlotNumber) -- Extremely useful reviving information from EMEVD -- Also works with EMEVD command RequestCharacterAICommandAndEventValue, but don't use that because it sucks and is broken (it requires reset AI for it to work) local EventSlot = 0 ai:GetEventRequest(EventSlot) -- return value of event slot (0 by default) -- Timers. Used to keep track of time local TimerSlot = 0 -- which timer to use. Values start at 0, end at 3 (4 total) local TimerAmount = 60 -- time in seconds to set timer ai:IsFinishTimer(TimerSlot) -- returns true/false ai:GetTimer(TimerSlot) -- returns number of seconds left on timer ai:SetTimer(TimerSlot, TimerAmount) -- sets timer -- Store a value that can be checked later local NumberSlot = 0 -- Which slot to store value in. Values start at 0, end AT LEAST at 6 local Value = 420 -- Value to use ai:SetNumber(NumberSlot, Value) -- set value ai:GetNumber(NumberSlot) -- check value -- HasSpecialEffectId -- Check if target has a special effect local SpecialEffectID = 5470 -- ID of special effect to check ai:HasSpecialEffectId(TargetType, SpecialEffectID) -- true if target/self has special effect ai:HasSpecialEffectId(TARGET_SELF, 5470) -- true if target/self has special effect -- GetNpcThinkParamID -- Returns NpcThinkParam ID being used. Extremely useful for variant behavior. local myThinkID = ai:GetNpcThinkParamID() -- Target Types (TargetType) -- Any instance of a targetType in list list can be replaced with any other type. (Example: replacing an attack's TARGET_ENE_0 with TARGET_FRI_0 will make them aim at an ally) -- (In example commands, I used in default target types that are USUALLY what you want) TARGET_NONE TARGET_SELF -- self TARGET_ENE_0 -- enemy TARGET_FRI_0 -- ally TARGET_EVENT -- unused TARGET_LOCALPLAYER -- the player (host) TARGET_LowHp_Friend -- unused POINT_EVENT -- location of a specific map region. Set with SetEventMoveTarget -- ai:SetEventMoveTarget(RegionEntityID) -- set POINT_EVENT (targetType) location to a map region -- Example: move to map region ai:SetEventMoveTarget(RegionEntityID) goal:AddSubGoal(GOAL_COMMON_ApproachTarget, 20, POINT_EVENT, 1, TARGET_SELF, false, -1) -- -- GetHpRate -- Check HP ratio of a target. Values are 0 to 1 (1 = 100% HP, 0 = 0% HP) ai:GetHpRate(TargetType) local HpRate = ai:GetHpRate(TARGET_SELF) -- GetDist -- Check target's distance in comparison to self's origin position (in meters) -- Distance is offset by self's npcParam hitRadius -- If target is within hitRadius, distance will be negative. Distance will continue to decrease as target approaches origin -- -- Lowest possible value is when target is at self origin, which would have a distance of negative hitRadius -- If target is outside of hitRadius, distance will be positive. Distance will continue to increase as target leaves origin -- -- If target is exactly hitRadius's distance away, distance will be exactly 0 ai:GetDist(TargetType); local targetDist = ai:GetDist(TARGET_ENE_0); -- GetDistY / GetDistYSigned -- Check target's elevation in comparison to self (in meters) ai:GetDistY(TARGET_ENE_0) -- Returns absolute elevation difference (positive value only). ai:GetDistYSigned(TARGET_ENE_0) -- Returns elevation difference (+ or -). negative values = target is lower, positive values = target is higher -- IsInsideTargetRegion -- Check if target is inside of a map region ai:IsInsideTargetRegion(TargetType, MapRegionEntityID) -- Check if target is inside of a map region -- Direction Types (DirectionType) AI_DIR_TYPE_F -- Front AI_DIR_TYPE_B -- Back AI_DIR_TYPE_L -- Left AI_DIR_TYPE_R -- Right AI_DIR_TYPE_CENTER -- Center (? Used with certain commands.) AI_DIR_TYPE_Top -- Above AI_DIR_TYPE_ToF -- Above Front? AI_DIR_TYPE_ToB -- Above Back? AI_DIR_TYPE_ToL -- Above Left? AI_DIR_TYPE_ToR -- Above right? -- Distance Types (DistType) -- Values refer to npcthinkParam fields. Can be substituted with variable values (in "meters") DIST_Near DIST_Middle DIST_Far DIST_Out DIST_None -- IsInsideTarget -- Check if a target is within an direction and angle local DirectionType = AI_DIR_TYPE_F -- direction to check for target local Angle = 50 -- Angle to check that target is within ai:IsInsideTarget(TARGET_ENE_0, DirectionType, Angle) ai:IsInsideTarget(TARGET_ENE_0, AI_DIR_TYPE_F, 50) -- GOAL_COMMON_ApproachTarget -- Approach a target until within a certain distance local CancelTime = 4 -- time in seconds before goal is canceled local Dist = 3 -- Minimum distance to target for goal completion local GuardID = -1 -- Determines guarding (NOT AN ANIMATION ID) -1 = do not guard. -- non-c0000: 9910 = guard,, 9920 = special guarding (uses different IDs). -- c0000: 4 = guard local WalkBool = false -- Which movement animations to use. false = dash, true = walk goal:AddSubGoal(GOAL_COMMON_ApproachTarget, CancelTime, TARGET_ENE_0, Dist, TARGET_SELF, WalkBool, GuardID) goal:AddSubGoal(GOAL_COMMON_ApproachTarget, 4, TARGET_ENE_0, 3, TARGET_SELF, false, -1) -- Approach enemy goal:AddSubGoal(GOAL_COMMON_ApproachTarget, 10, POINT_INITIAL, 2, TARGET_SELF, false, -1) -- Return to home. Usually followed by Wait -- Note: Attack goals have additional parameters for up angle/down angle anim offsets, which is used for a small amount of enemies. -- GOAL_COMMON_ComboAttackTunableSpin / GOAL_COMMON_ComboRepeat / GOAL_COMMON_ComboFinal -- Combo attacks while turning. Works by using TAE combo recovery events during animations, making them end earlier local CancelTime = 5 -- Time in seconds before goal is canceled local AnimationID = 700 -- Animation ID to use local SpinTime = 1 -- Time in seconds to turn and face target before making action. See SpinAngle local SpinAngle = 90 -- Angle to face target before making action. see SpinTime local Dist = DIST_Middle -- Maximum distance before ending combo early. Can use DistType or an actual value. goal:AddSubGoal(GOAL_COMMON_ComboAttackTunableSpin, CancelTime, AnimationID, TARGET_ENE_0, Dist, SpinTime, SpinAngle) -- always add first goal:AddSubGoal(GOAL_COMMON_ComboRepeat, CancelTime, AnimationID, TARGET_ENE_0, Dist, 0, -1) -- add between GOAL_COMMON_ComboAttackTunableSpin and GOAL_COMMON_ComboFinal as many times as needed goal:AddSubGoal(GOAL_COMMON_ComboFinal, CancelTime, AnimationID, TARGET_ENE_0, Dist, 0, -1) -- always add last -- goal:AddSubGoal(GOAL_COMMON_ComboAttackTunableSpin, 5, 3000, TARGET_ENE_0, DIST_Middle, 1, 90) -- always add first goal:AddSubGoal(GOAL_COMMON_ComboRepeat, 5, 3001, TARGET_ENE_0, DIST_Middle, 0, -1) -- add between GOAL_COMMON_ComboAttackTunableSpin and GOAL_COMMON_ComboFinal as many times as needed goal:AddSubGoal(GOAL_COMMON_ComboFinal, 5, 3002, TARGET_ENE_0, DIST_Middle, 0, -1) -- always add -- goal:AddSubGoal(GOAL_COMMON_ComboAttackTunableSpin, 5, 3000, TARGET_ENE_0, DIST_Middle, 1, 90) -- always add first goal:AddSubGoal(GOAL_COMMON_ComboFinal, 5, 3002, TARGET_ENE_0, DIST_Middle, 0, -1) -- always add last -- goal:AddSubGoal(GOAL_COMMON_ComboAttackTunableSpin, 5, 3000, TARGET_ENE_0, DIST_Middle, 1, 90) -- always add first goal:AddSubGoal(GOAL_COMMON_ComboRepeat, 5, 3001, TARGET_ENE_0, DIST_Middle, 0, -1) -- add between GOAL_COMMON_ComboAttackTunableSpin and GOAL_COMMON_ComboFinal as many times as needed goal:AddSubGoal(GOAL_COMMON_ComboRepeat, 5, 3002, TARGET_ENE_0, DIST_Middle, 0, -1) -- add between GOAL_COMMON_ComboAttackTunableSpin and GOAL_COMMON_ComboFinal as many times as needed goal:AddSubGoal(GOAL_COMMON_ComboFinal, 5, 3001, TARGET_ENE_0, DIST_Middle, 0, -1) -- always add last -- -- GOAL_COMMON_AttackTunableSpin -- Attack while turning. Uses (slower) TAE attack recovery, rather than combo attack recovery. local CancelTime = 5 -- Time in seconds before goal is canceled local AnimationID = 700 -- Animation ID to use local SpinTime = 1 -- Time in seconds to turn and face target before making action. See SpinAngle local SpinAngle = 90 -- Angle to face target before making action. see SpinTime local Dist = DIST_Middle -- Maximum distance before ending combo early. Can use DistType or an actual value. goal:AddSubGoal(GOAL_COMMON_AttackTunableSpin, CancelTime, AnimationID, TARGET_ENE_0, Dist, SpinTime, SpinAngle) -- GOAL_COMMON_NonspinningAttack -- Attack, but don't require/allow turning goal:AddSubGoal(GOAL_COMMON_NonspinningAttack, CancelTime, AnimationID, TARGET_ENE_0, DIST_None) goal:AddSubGoal(GOAL_COMMON_NonspinningAttack, 5, 3000, TARGET_ENE_0, DIST_None) -- GOAL_COMMON_SpinStep -- Used for dodging. Useful for preventing jumping off of cliffs local CancelTime = 5 -- Time in seconds before goal is canceled local AnimationID = 700 -- Animation ID to use local SpinTime = 0 -- time in seconds to turn and face target before making action (Untested, may not actually work) local DirectionType = AI_DIR_TYPE_B -- direction to check if map collision exists local SafeDist = 3 -- distance to check if map collision exists. Cancels if it does not. goal:AddSubGoal(GOAL_COMMON_SpinStep, CancelTime, AnimationID, TARGET_ENE_0, SpinTime, DirectionType, SafeDist) goal:AddSubGoal(GOAL_COMMON_SpinStep, 4, 700, TARGET_ENE_0, 0, AI_DIR_TYPE_B, 3) -- GOAL_COMMON_MoveToSomewhere -- Move to a position. Can offset move target coordinates by angle + distance -- Offset coordinates example these would make the move target 10 units above the target -- OffsetDirectionType = AI_DIR_TYPE_TOP -- OffsetDistance = 10 local CancelTime = 20 -- time in seconds before goal is canceled local Dist = 1.5 -- Minimum distance to target for goal completion local WalkBool = false -- Which movement animations to use. false = dash, true = walk local OffsetDirectionType = AI_DIR_TYPE_CENTER -- direction to use for target offset. Use AI_DIR_TYPE_CENTER for no offset. local OffsetDistance = 0 -- distance to use for target offset goal:AddSubGoal(GOAL_COMMON_MoveToSomewhere, CancelTime, TARGET_ENE_0, OffsetDirectionType, Dist, TARGET_SELF, WalkBool, OffsetDistance) goal:AddSubGoal(GOAL_COMMON_MoveToSomewhere, 20, TARGET_ENE_0, AI_DIR_TYPE_CENTER, 1.5, TARGET_SELF, false, 0) -- AddObserveArea -- Constantly check if a target is within defined angle & distance -- To be used with INTERUPT_Inside_ObserveArea local ObserveNo = 0 -- index. Vanilla uses 0-7 local DirectionType = AI_DIR_TYPE_B -- direction to check if map collision exists local Angle = 60 -- angle to check if target is within local Dist = 2 -- distance to check if target is within ai:AddObserveArea(ObserveNo, TARGET_ENE_0, TARGET_SELF, DirectionType, Angle, Dist) ai:AddObserveArea(0, TARGET_ENE_0, TARGET_SELF, AI_DIR_TYPE_B, 60, 2) -- check if target is behind and close ai:IsInterupt(INTERUPT_Inside_ObserveArea) -- Triggers upon ANY AddObserveArea passing -- IsOnNearMeshByPos -- Check if map collision exists in target's direction + distance -- Useful for not jumping off the map during some actions. local Dist = 2 -- distance to check ai:IsOnNearMeshByPos(TargetType, DirectionType, Dist) ai:IsOnNearMeshByPos(TARGET_SELF, AI_DIR_TYPE_B, 2) -- GOAL_COMMON_LeaveTarget -- Move away from target local CancelTime = 5 -- Time in seconds before goal is canceled local Dist = ai:GetRandam_Float(1.5, 2) -- Minimum distance to target for goal completion local GuardID = -1 -- Determines guarding (NOT AN ANIMATION ID) -1 = do not guard. -- non-c0000: 9910 = guard,, 9920 = special guarding (uses different IDs). -- c0000: 4 = guard local WalkBool = true -- Which movement animations to use. false = dash, true = walk goal:AddSubGoal(GOAL_COMMON_LeaveTarget, CancelTime, TARGET_ENE_0, Dist, TARGET_ENE_0, WalkBool, GuardID) goal:AddSubGoal(GOAL_COMMON_LeaveTarget, 5, TARGET_ENE_0, ai:GetRandam_Float(1.5, 2), TARGET_ENE_0, true, -1) local Duration -- how long to leave target for OR cancel time? probably latter local LeaveDist -- minimum Distance to reach before goal completion? local WalkBool = false local GuardID = -1 -- Determines guarding (NOT AN ANIMATION ID) -1 = do not guard. -- non-c0000: 9910 = guard,, 9920 = special guarding (uses different IDs). -- c0000: 4 = guard local LeftOrRight -- right = 1, left = 0 local UnkTrue = true -- unknown. always true goal:AddSubGoal(GOAL_COMMON_SidewayMove, Duration, TARGET_ENE_0, LeftOrRight, Angle, WalkBool, UnkTrue, GuardID) goal:AddSubGoal(GOAL_COMMON_SidewayMove, ai:GetRandam_Float(1.5, 3), TARGET_ENE_0, ai:GetRandam_Int(0, 1), ai:GetRandam_Int(30, 45), true, true, -1) goal:AddSubGoal(GOAL_COMMON_Wait, ai:GetRandam_Float(1.5, 2.5), TARGET_NONE, 0, 0, 0) goal:AddSubGoal(GOAL_COMMON_Turn, 3.0, TARGET_ENE_0, TurnAngle) -- Approach_and_Attack_Act -- Simplified function. uses GOAL_COMMON_ApproachTarget and GOAL_COMMON_AttackTunableSpin -- Checks distance to decide dash vs walk -- Adds random chance of guarding. local AppDist = 4 -- Minimum distance to target for goal completion local DashDist = 10 -- Minimum distance to target to start dashing instead of walking local Odds_Guard = 0 -- % chance (0 - 100) to guard while approaching. Uses GuardID 9910 local AnimationID = 3000 -- Animation ID to use local AttDist local TurnTime local TurnFaceAngle Approach_and_Attack_Act(ai, goal, AppDist, DashDist, Odds_Guard, AttID, AttDist, TurnTime, TurnFaceAngle) Approach_Act(ai, goal, AppDist, DashDist, Odds_Guard, life) Approach_or_Leave_Act(ai, goal, LeaveDist, AppDist, DashDist, Odds_Guard) Backstab_Act(ai, goal, ObserveNo, ApproachDist, TimerIndex, Time) -- NPC_Approach_Act -- Simplified function for c0000 approaches local AppDist = 4 -- Minimum distance to target for goal completion local DashDist = 10 -- Minimum distance to target to start dashing instead of walking local Odds_Guard = 0 -- % chance (0 - 100) to guard while approaching. Uses GuardID 9910 NPC_Approach_Act(ai, goal, AppDist, DashDist, Odds_Guard) NPC_Approach_Act(ai, goal, 4, 10, 0) ai:StartDash() -- for c0000 NPCs. Use before an approach act to make them dash (used in NPC_Approach_Act) ai:EndDash() -- ChkNearLowHpFriend -- Check HP of all allies within defined distance local HpRatio = .8 local Dist = 20 ai:ChkNearLowHpFriend(HpRatio, Dist) -- Get and check current role in AI queue, determined by number of allies and team attack effective counter (npcThinkParam) local role = ai:GetTeamOrder(ORDER_TYPE_Role) -- Get TeamAttackEffectivity role if role == ROLE_TYPE_Attack then -- true if self in AI queue <= 100 elseif role == ROLE_TYPE_Torimaki then -- true if self in AI queue > 100 and <= 200 elseif role == ROLE_TYPE_Kankyaku then -- true if self in AI queue > 200 end goal:AddSubGoal(GOAL_COMMON_AttackTunableSpin, CancelTime, AnimationID, TARGET_ENE_0, Dist, SpinTime, SpinAngle) -- GOAL_COMMON_NonspinningAttack -- Attack, but don't require/allow turning goal:AddSubGoal(GOAL_COMMON_NonspinningAttack, CancelTime, AnimationID, TARGET_ENE_0, DIST_None) goal:AddSubGoal(GOAL_COMMON_NonspinningAttack, 5, 3000, TARGET_ENE_0, DIST_None) -- GOAL_COMMON_SpinStep -- Used for dodging. Useful for preventing jumping off of cliffs local CancelTime = 5 -- Time in seconds before goal is canceled local AnimationID = 700 -- Animation ID to use local SpinTime = 0 -- time in seconds to turn and face target before making action (Untested, may not actually work) local DirectionType = AI_DIR_TYPE_B -- direction to check if map collision exists local SafeDist = 3 -- distance to check if map collision exists. Cancels if it does not. goal:AddSubGoal(GOAL_COMMON_SpinStep, CancelTime, AnimationID, TARGET_ENE_0, SpinTime, DirectionType, SafeDist) goal:AddSubGoal(GOAL_COMMON_SpinStep, 4, 700, TARGET_ENE_0, 0, AI_DIR_TYPE_B, 3) -- GOAL_COMMON_MoveToSomewhere -- Move to a position. Can offset move target coordinates by angle + distance -- Offset coordinates example these would make the move target 10 units above the target -- OffsetDirectionType = AI_DIR_TYPE_TOP -- OffsetDistance = 10 local CancelTime = 20 -- time in seconds before goal is canceled local Dist = 1.5 -- Minimum distance to target for goal completion local WalkBool = false -- Which movement animations to use. false = dash, true = walk local OffsetDirectionType = AI_DIR_TYPE_CENTER -- direction to use for target offset. Use AI_DIR_TYPE_CENTER for no offset. local OffsetDistance = 0 -- distance to use for target offset goal:AddSubGoal(GOAL_COMMON_MoveToSomewhere, CancelTime, TARGET_ENE_0, OffsetDirectionType, Dist, TARGET_SELF, WalkBool, OffsetDistance) goal:AddSubGoal(GOAL_COMMON_MoveToSomewhere, 20, TARGET_ENE_0, AI_DIR_TYPE_CENTER, 1.5, TARGET_SELF, false, 0) -- AddObserveArea -- Constantly check if a target is within defined angle & distance -- To be used with INTERUPT_Inside_ObserveArea local ObserveNo = 0 -- index. Vanilla uses 0-7 local DirectionType = AI_DIR_TYPE_B -- direction to check if map collision exists local Angle = 60 -- angle to check if target is within local Dist = 2 -- distance to check if target is within ai:AddObserveArea(ObserveNo, TARGET_ENE_0, TARGET_SELF, DirectionType, Angle, Dist) ai:AddObserveArea(0, TARGET_ENE_0, TARGET_SELF, AI_DIR_TYPE_B, 60, 2) -- check if target is behind and close ai:IsInterupt(INTERUPT_Inside_ObserveArea) -- Triggers upon ANY AddObserveArea passing -- IsOnNearMeshByPos -- Check if map collision exists in target's direction + distance -- Useful for not jumping off the map during some actions. local Dist = 2 -- distance to check ai:IsOnNearMeshByPos(TargetType, DirectionType, Dist) ai:IsOnNearMeshByPos(TARGET_SELF, AI_DIR_TYPE_B, 2) -- GOAL_COMMON_LeaveTarget -- Move away from target local CancelTime = 5 -- Time in seconds before goal is canceled local Dist = ai:GetRandam_Float(1.5, 2) -- Minimum distance to target for goal completion local GuardID = -1 -- Determines guarding (NOT AN ANIMATION ID) -1 = do not guard. -- non-c0000: 9910 = guard,, 9920 = special guarding (uses different IDs). -- c0000: 4 = guard local WalkBool = true -- Which movement animations to use. false = dash, true = walk goal:AddSubGoal(GOAL_COMMON_LeaveTarget, CancelTime, TARGET_ENE_0, Dist, TARGET_ENE_0, WalkBool, GuardID) goal:AddSubGoal(GOAL_COMMON_LeaveTarget, 5, TARGET_ENE_0, ai:GetRandam_Float(1.5, 2), TARGET_ENE_0, true, -1) local Duration -- how long to leave target for OR cancel time? probably latter local LeaveDist -- minimum Distance to reach before goal completion? local WalkBool = false local GuardID = -1 -- Determines guarding (NOT AN ANIMATION ID) -1 = do not guard. -- non-c0000: 9910 = guard,, 9920 = special guarding (uses different IDs). -- c0000: 4 = guard local LeftOrRight -- right = 1, left = 0 local UnkTrue = true -- unknown. always true goal:AddSubGoal(GOAL_COMMON_SidewayMove, Duration, TARGET_ENE_0, LeftOrRight, Angle, WalkBool, UnkTrue, GuardID) goal:AddSubGoal(GOAL_COMMON_Wait, ai:GetRandam_Float(1.5, 2.5), TARGET_NONE, 0, 0, 0) goal:AddSubGoal(GOAL_COMMON_Turn, 3.0, TARGET_ENE_0, TurnAngle) -- Approach_and_Attack_Act -- Simplified function. uses GOAL_COMMON_ApproachTarget and GOAL_COMMON_AttackTunableSpin -- Checks distance to decide dash vs walk -- Adds random chance of guarding. local AppDist = 4 -- Minimum distance to target for goal completion local DashDist = 10 -- Minimum distance to target to start dashing instead of walking local Odds_Guard = 0 -- % chance (0 - 100) to guard while approaching. Uses GuardID 9910 local AnimationID = 3000 -- Animation ID to use local AttDist local TurnTime local TurnFaceAngle Approach_and_Attack_Act(ai, goal, AppDist, DashDist, Odds_Guard, AttID, AttDist, TurnTime, TurnFaceAngle) Approach_Act(ai, goal, AppDist, DashDist, Odds_Guard, life) Approach_or_Leave_Act(ai, goal, LeaveDist, AppDist, DashDist, Odds_Guard) Backstab_Act(ai, goal, ObserveNo, ApproachDist, TimerIndex, Time) -- NPC_Approach_Act -- Simplified function for c0000 approaches local AppDist = 4 -- Minimum distance to target for goal completion local DashDist = 10 -- Minimum distance to target to start dashing instead of walking local Odds_Guard = 0 -- % chance (0 - 100) to guard while approaching. Uses GuardID 9910 NPC_Approach_Act(ai, goal, AppDist, DashDist, Odds_Guard) NPC_Approach_Act(ai, goal, 4, 10, 0) ai:StartDash() -- for c0000 NPCs. Use before an approach act to make them dash (used in NPC_Approach_Act) ai:EndDash() -- ChkNearLowHpFriend -- Check HP of all allies within defined distance local HpRatio = .8 local Dist = 20 ai:ChkNearLowHpFriend(HpRatio, Dist) -- Get and check current role in AI queue, determined by number of allies and team attack effective counter (npcThinkParam) local role = ai:GetTeamOrder(ORDER_TYPE_Role) -- Get TeamAttackEffectivity role if role == ROLE_TYPE_Attack then -- true if self in AI queue <= 100 elseif role == ROLE_TYPE_Torimaki then -- true if self in AI queue > 100 and <= 200 elseif role == ROLE_TYPE_Kankyaku then -- true if self in AI queue > 200 end