Skip to content

AI functions

inkoalawetrust edited this page Jul 22, 2025 · 27 revisions

This page covers all the non-movement AI-related functions that are shared by all KAI NPCs.

KAI_CheckMeleeRange()

Parameters:

  • Other: The actor to check the melee range to.
  • Range: The range of the check. Default is -1, which means that the actors' MeleeRange is used instead.
  • Flags: The flags to use for the check.
    • CMR_NOHITFRIEND: Do not run HitFriend() during the check.
    • CMR_3DDISTANCE: Use Distance3D() instead of Distance2D() for the range check. This flag is also used by KAI_CheckMissileRange().
    • CMR_INVERTDIST: Used by KAI_CheckMissileRange(). This flag inverts the distance formula the function uses to decide if the NPC should attack, meaning that the actor is MORE likely to attack the further Other is, instead of less likely. THIS FLAG ALTERS HOW THE AGGRESSIONMULTIPLIER WORKS !
    • CMR_IGNOREDIST: Used by KAI_CheckMissileRange(). Making that function ignore the arbitrary distance check entirely, so the chance of attacking doesn't scale with distance at all.

Return type(s):

  • Returns true if Other is in Range of the caller, false otherwise.

Function:

This function is a ZScript version of CheckMissileRange().

KAI_CheckMissileRange()

Parameters:

  • Other: The actor to check the missile range to.
  • Flags: The flags to use for the check. Uses, the same flags as KAI_CheckMeleeRange().

Return type(s):

  • Returns true if Other is in range of the target, the chance of returning true scales with the distance to the target, like CheckMissileRange(). Unless CMR_IGNOREDIST is true.

Function:

This function is a ZScript version of CheckMissileRange(), besides supporting 3D distance checks, it also supports the AggressionMultiplier property.

KAI_Look()

Parameters:

  • Flags, MinSeeDist, MaxSeeDist, MaxHearDist, FOV, Label: These parameters are the exact same as their A_LookEx() counterparts.
  • ExtraFlags: Extra flags used by KAI_Look() itself, as opposed to A_LookEx's own flags.
    • KAIL_CHASETARGET: If the caller already has a target, then make the actor go to the specified sight state. Useful for when A_LookEx itself doesn't do this.
    • KAIL_NOTEMPSTAND: The caller won't temporarily enable +STANDSTILL if it isn't already enabled, when called by friendly monsters. If this isn't on, then friendly monsters will not begin moving when they hear the player.

Return type(s):

  • None

Function:

This is a generic wrapper for A_LookEx(), that includes a fix for monsters not going to their See state when they already have a target, and also makes friendly monsters not begin moving when they hear a player by default.

KAI_Chase()

See here.

KAI_MoveTowards()

For more information, click here.

KMT_3D_ScaleObstacle(), KMT_3D_DecelWrongVector(), KMT_3D_SpeedLimit(), KMT_3D_MoveBlocked()

For more information, click here.

KAI_MoveAway()

For more information, click here.

KAI_AvoidObstacles()

Parameters:

  • CheckDist: How far ahead of the actor to check for obstacles, in map units.
  • CheckSlices: How many slices around the actor should be checked? i.e if this is set to 16, the function will check every 22.5 degrees from the left to right for an obstructions. This is the "resolution" of the check, so to speak.
  • CheckSpacing: Used by IsPosReachable() (Which is what checks each slice), how far apart should the steps be spaced? Normally it makes sense to space them by the movement speed of the caller.

Return type(s):

  • The position the actor should move to, to try and avoid the obstacle(s) ahead, if any. If all slices around the actor are clear, it just returns a NaN/null vector.
  • If the function found an obstruction around the actor.

Function:

Tries to make the actor avoid any obstacles around it by firing a series of IsPosReachable() checks in a 360 degree field around them. Divided by CheckSlices. If all checks pass, nothing is returned, otherwise, the first clear path is returned as the direction to head to.

KAI_AvoidObstacles3D()

Parameters:

  • HorzTraces: How many horizontal traces to fire. Each set of horizontal traces has its' own set of vertical ones.
  • VertTraces: How many vertical traces to fire per horizontal trace. Can be 0 for a purely horizontal check.
  • Distance: How far away each check can reach.
  • Threshold: How far away the averaged distance of all checks must be from the actors' origin to be considered valid. If under this threshold, it returns NaN. This is here because even if no trace hits anything, the average has some noise, instead of being the same as the actors' origin. Default is 5.
  • Magnitude: Multiplier (Relative to actor origin) for the averaged position of all traces. Negative values scale it between the positive version of the value and 1 based on how close the average distance of all traces that hit something is. So the closer the average of all blocked traces is, the higher the magnitude. Default is 1.
  • MinDist: If ANY trace fired is closer than this distance, the function returns NaN. Can be used as a basic way to make it not interfere with actions that require close contact with objects that are otherwise obstacles. Default is 0.

Return type(s):

  • The averaged position of all traces, this is the position for the actor to head to to avoid the obstacle(s).
  • The average distance of all traces that DID hit something. Can be used to get, for example, an approximation of how close to an obstacle the actor is.

Function:

Fires a sphere (Or just a ring) of traces around the actor, and gets a position by averaging all the end positions of all fired traces. This average can be used to get a position away from any obstacles because if, for example, the left hemisphere of the trace ball is obstructed, then the average would be shifted to the right due to all the prematurely terminated traces on the left hemisphere.

This function is primarily intended for KMT_3D flyers, which (By default) move by continuously propelling themselves. So unlike KAI_AvoidObstacles(), this method is ideally used more continuously, such as for every step or even every tick, to steadily shove the flyer away from obstacles in its' environment.

KAI_CheckCorners()

Parameters:

  • Targ: The actor spot to check if we can be seen by. If the function is used to run from an actor, then Targ can be that actor. But if it's a pure coordinate we are running away from. Then this can instead be something like a KAI_TempPoint at the coordinate we are trying to get out of sight from.
  • Divisions: How many steps between the actors' origin and Distance away to check. For example if Distance is 128MU and this parameter is 8, then a sight check to Targ is ran every 16MU.
  • Distance: How far to the left and right of the actor to check for something to run behind.

Return type(s):

  • Returns a position to the left or right of the caller that they can run behind. If they can't run behind anything, it returns NaN.

Function:

Performs the 2D corner (Left and right) check used by KAI_MoveAway. Checks both sides up to Distance to find the closest spot along the way from where the actor can't be seen by Targ. This function is biased to the right, so if the right side has a 'corner', it'll be picked even if a corner to the left is closer.

KAI_CheckCorners3D()

Parameters:

  • Targ: Same deal as KAI_CheckCorners(). This is what we're trying to hide from.
  • Slices: Similar to KAI_AvoidObstacles(), how many slices is the check split by? i.e a value of 8 produces one check around the caller every 45 degrees.
  • Divisions: How much each slice is split up. These are the individual units at which the visibility to Targ is checked at.
  • Distance: How far out to check for a hiding spot.
  • StartUp: By default, the function fires the checks from the bottom up, biasing the function towards the lowest spot found. If true, the highest valid hiding spot found first is picked.
  • Counterclockwise: Similar to StartUp but makes it so the function is biased to the first right-side hiding spot it finds instead of the first to the left.

Return type(s):

  • Returns the first position found that the actor can hide behind in 3D space. If no hiding spot is found within range, it returns NaN.

Function:

Performs the 3D corner check used by KAI_MoveAway if KMT_3D is passed. Unlike its' 2D counterpart, this function checks all around the actor for a potential hiding spot in a clock-like pattern.

This function can be visualized with the KAI_Debug3DCornerCheck CVAR, showing each point it checks the sight to the target from. Especially useful for actually seeing what StartUp and Counterclockwise do if you are struggling to visualize it from this text.

KAI_Wander()

For more information, click here.

FindRandomMovePos()

For more information, click here.

IsPosReachable()

Parameters:

  • TargetPos: The position to check if the caller has a valid path to.
  • DistCutoff: The amount of map units to trim off the distance between the callers' pos and TargetPos. Useful for subtracting the radius of another actor, so that if you are checking if a position to another actor can be reached, the check doesn't return false because the actor itself is in the way.
  • Spacing: Determines how far apart the position checks from the callers' position to TargetPos are. Default is 0, which makes the spacing be the diameter of the callers' hitbox.
  • IgnoreActors: Makes the check ignore any blocking actors in the way by temporarily enabling +THRUACTORS.
  • Dropoff: Passed to TryMove()'s dropoff parameter.
  • Full3D: If set to true, it will instead call IsPosReachable3D() and return the value of that. Passing all relevant parameters.

Return type(s):

  • Returns true if the caller can move up to TargetPos.
  • Returns a Vector3 to where the check was blocked. If the position from A to B is fully reachable, it returns NaN instead.

Function:

Checks if the caller can move from their current position towards TargetPos without hitting any obstacles along the way. The Spacing parameter can be used to patch up holes in the path check, such as corners being considered possible to cross.

Bugs:

The function will sometimes return true for positions that are behind drops too tall for the caller. It also doesn't seem to account properly for static portals. The former bug I have no idea how to fix, the latter bug I may be able to fix.

IsPosReachable3D()

Parameters:

  • TargetPos, DistCutoff, Spacing, IgnoreActors: Function the same as in IsPosReachable3D().
  • No3DFloor: By default, the function doesn't really return 3D floors as obstructing the path. This flag makes it return false if any of the steps from A to B end up within a solid (Blocking) 3D floor.

Return type(s):

  • Returns true if the caller can move towards TargetPos.
  • Returns a Vector3 to where the check was blocked. If the position from A to B is fully reachable, it returns NaN instead.

Function:

Functions the same as IsPosReachable(), but in 3D space. Used by flying actors. And it's also seemingly more functional than its' 2D counterpart.

CheckSpaceSize()

Parameters:

  • TargetRadius: The maximum radius up to which the function checks for free space at the callers' position.
  • TargetHeight: Ditto, but for the height.
  • Iterations: How many steps between a radius and height of 0 and the target values will be performed, i.e if the radius is 256 and the there's 8 iterations, it'll go like 32, 36, 42, 51, 64, 85, 128, 256. Default is 8 steps.
  • ActorBlock: Should the function also check for blocking actors? Default is false, meaning it's only concerned with level geometry.

Return type(s):

Note: If the space is wide open at the specified target height and radius, all these returns will be -1.

  • How many iterations/steps the function performed before something blocked the caller, steps are counted down, so the more steps left, the more crammed the area generally is, because the function returned that its' crammed sooner.
  • The radius at which the function returned that the space is blocked.
  • Ditto, but for the height.

Function:

Does a crude check for how crammed the area around the caller is. Works by making the callers' hitbox large and large, and checking for collision on every iteration, up to the target size. And returning non -1, -1, 1, value if the check is blocked by level geometry and/or actors that would block the caller along any step of the way.

Example

This code stores all the return values of the function, and checks if the radius at which the space check prematurely ended is less than 192 map units away to arbitrarily determine that the space the caller is in is crammed.

			Int Iterations; Double Rad; Double Eh;
			[Iterations, Rad, Eh] = CheckSpaceSize (384,384,16);
			TooCrammed = Rad < 192; //If there's any level geometry blocking us less than 192MU away, we're in a crammed area.

RetargetVehicleHull()

Parameters:

  • Flags: The flags to use for the retarget. These are mostly flags for not running specific retarget conditions.
    • RVHF_NOTARGETCHANGE: Don't actually change the callers' target to the hull of the turret they are targeting, only return if the retarget SHOULD occur.
    • RVHF_NOTRANSFERDAMAGECHECK: Don't retarget if the turret has +TRANSFERDAMAGE, and the hull its' attached to is bigger than the turret itself.
    • RVHF_NOWEAKHULLCHECK: Don't retarget if the vehicle the turret is attached to is weaker than the turret itself.
    • RVHF_STRONGERHULL: Retarget the hull if it has more health than the turret. Essentially targeting the strongest part of the vehicle.

Return type(s):

  • Returns true if the callers' target is a vehicle turret, and targeting the vehicle the turret is attached to would be more advantageous instead.

Function:

Checks if the callers' target is a vehicle turret, and changes it if it would be more advantageous to target the vehicle itself, this function checks for several conditions to determine if it would be better/easier to target the vehicle rather than its' turret:

  • If the turret has +TRANSFERDAMAGE, and is overall smaller than the vehicle it's on. Then it would make more sense to target the bigger hull, since both actors share the same health pool.
  • If the turret does not have +TRANSFERDAMAGE, but the vehicle it's attached to is weaker than 80% of the turrets' current health. Meaning that it should be easier and quicker to destroy the vehicle itself than its' turret, which it can probably function without anyway.

FindNearestEnemy()

Parameters:

  • Range: The range to look for enemies within, if it's 0 or less, no search is performed. Default is 256 map units.

Return type(s):

  • Returns a pointer to the enemy that is closest to the caller, if any.

Function:

Finds the nearest enemy NPC in Range of the caller that is alive, can be targeted, and is visible. And returns a pointer to them. Used by KAI_LandVehicleChase() to make vehicles stay away from enemies instead of charging headfirst like normal Doom monsters.

GetFAFAimPos()

Parameters:

  • Other: The actor to get the proper aim position to.
  • Offsets: The Vector3 offsets relative to the caller to fire the line of sight checks from. Default is (0,0,0).

Function:

Returns which part of the Other actor the calling NPC can shoot at. Using the A_Face() flags. By default, it returns FAF_MIDDLE, but if the middle of the Other actor is covered, it will return FAF_TOP, and if that is blocked too, it will return FAF_BOTTOM. If the whole actor is blocked, it falls back to FAF_MIDDLE. Used by KAI_TurretRefire() and KAI_TurretCheckLOF.

Example:

This is how KAI_TurretRefire() uses the function after every attack to update what part of the target the turret should aim at: `TurretAimPos = GetFAFAimPos(Target);

GetFAFPosOffset()

Parameters:

  • Other: The actor to get the relative aim position to.
  • AimPos: The FAF_ position we want to get the actual relative coordinates of.

Function:

Returns a relative height to Other based on the AimPos passed. For example if FAF_Middle is passed, the result of Other.Height/2 is returned. Can be used in conjunction with TurretAimPos to get an actual position relative to whatever the turret is aiming, for it to fire at.

KAI_ShareTarget()

Parameters:

  • Sharee: The actor passing their target to the caller.
  • NewTarget: The actor the Sharee wants to pass to the caller.
  • IgnoreAllegiance: The function will set the callers' target to NewTarget even if the Sharee is hostile.

Function:

Used to pass a target from one KAI NPC to another, working in a similar manner to CopyFriendliness()'s target changing code. Does nothing if no NewTarget is passed, if the caller is dormant, if the caller is patrolling with bChaseGoal, or if the NewTarget cannot actually be targeted.

Return type(s):

  • Returns true if the callers' target was successfully set.

Example:

An NPC can call the function on another KAI NPC like this to change their target:

OtherNPC.KAI_ShareTarget(Self,Target);

This will make the OtherNPC change their target to the same one as the NPC doing the target share.

KAI_NPCUseLines()

Return type(s):

  • Returns true if the NPC used a line.

Function:

Makes the NPC use any pushable and usable lines it touches, similar to the native line using code of monsters. Used by KAI_MoveTowards()

KAI_GetFriendPlayer()

Return type(s):

  • Returns the callers' friendplayer.

Function:

Gets the calling NPCs' friendplayer, without running into VM aborts. In most cases, this should be used in place of plainly calling Players[FriendPlayer].

IsInAttackState()

Return type(s):

  • Returns true if the NPC is in any particular attack state.

Function:

This function checks if the caller is in any of the states defined in the AttackStates[] array, but first checks if they are within their MissileState or MeleeState states currently.

GetFirstPlayerNPCGroup()

Parameters:

  • IgnorePlayerLeaders: Ignore the special precedence of player-led groups, and simply return the first group on the list.

Return type(s):

  • Returns the first NPC group found in the NPCs' Groups[] array where the leader is a player, otherwise it just tries to return the first group in the list, if any.

Order functions

These functions are related to the NPCs' order system.

SetNPCOrder()

Parameters:

  • Order: The exact order the NPC should switch to. If Increment is true, this is ignored.
  • Increment: Instead of picking a specific order, move to the next order in the list. And loop back around at the end of the list (ORDER_NONE is ignored).
  • Commander: A pointer to the actor who is demanding the order, if any.
  • IgnoreAllegiance: If there IS a specified Commander, their order will be ignored if they're hostile to the ordered NPC, unless this is true. Default is false.
  • FromACS: Specifies if the function is being called from ACS, default is false. This shouldn't be set to true unless you're actually calling the function from ACS.

Function:

One of the primary functions of the order system. Sets the current built-in order type the NPC is following, or increments through the list. Can also be used to pass a commander making the order in cause it is wanted for any special behavior. The execution of this function can be expanded with OnOrderChange() and AfterOrderChange()

ACS_SetNPCOrder()

Parameters:

  • Activator: A pointer to the functions caller from ACS, which would be the script activator. The activator is used as the Commander so make sure there's no activator when this function is called from ACS if you don't want a commander.
  • NPCTID: The TID of all the NPCs whose order will be changed.
  • Order: The exact order the NPC should switch to. If Increment is true, this is ignored.
  • Increment: Instead of picking a specific order, move to the next order in the list. And loop back around at the end of the list (ORDER_NONE is ignored).
  • IgnoreAllegiance: If there IS a specified Commander, their order will be ignored if they're hostile to the ordered NPC, unless this is true. Default is false.

Function:

A version of SetNPCOrder() that can be called from ACS (Such as for scripted sequences) using ScriptCall().

Example

This is an example of how the function can be used in an Enter ACS script (Where the player entering is the activator). To make all KAI NPCs with a TID of 42 follow the player.

Script "MapInit" Enter
{
	ScriptCall ("KAI_Actor","ACS_SetNPCOrder",45,ORDER_FOLLOW,False,False);
}

Hazard functions

These functions in particular allow NPCs to interact with the hazard system.

InHazardRange()

Parameters:

Return type:

  • Returns true if the NPC is in range of the specified hazard.

Function:

Checks if the calling actor is in the range of the specified hazard, or in the case of HAZ_SECTOR hazards, if the actor is within the same sector that can be found at the hazards' Position vector.

GetHazardDistance()

Parameters:

Function:

Returns the distance to Hazard, either the hazards' Origin, or if it's an attack type hazard, the distance to its' Position vector. Returns a distance of 0 if the NPC is inside the same sector as a sector hazard.

GetHazardOriginPos()

Parameters:

  • Hazard: The hazard to check.
  • AttackerIsOrigin: If it's a HAZARD_ATTACK type hazard, considering the origin to be the hazards' Origin pointer (The shooter), instead of its' Position vector (Where the attack will land)/

Return type:

  • Returns the origin of Hazard. Returns an empty/NaN vector if Hazard is null.

Function:

Gets the origin position of the specified hazard, regardless of type, since different hazard types have different actual origin positions.

GetNearestHazard()

Parameters:

  • HazardList: An array of all the hazards to check.

Function:

Returns the hazard closest to the caller from the list.

GetStrongestHazard()

Parameters:

  • HazardList: An array of all the hazards to check.

Function:

Returns the most dangerous hazard from the list.

See also:

Clone this wiki locally