1 #using scripts\shared\ai_shared;
2 #using scripts\shared\callbacks_shared;
3 #using scripts\shared\clientfield_shared;
4 #using scripts\shared\fx_shared;
5 #using scripts\shared\math_shared;
6 #using scripts\shared\scene_shared;
7 #using scripts\shared\spawner_shared;
8 #using scripts\shared\util_shared;
9 #using scripts\shared\array_shared;
11 #using scripts\shared\ai\systems\animation_state_machine_utility;
12 #using scripts\shared\ai\systems\animation_state_machine_notetracks;
13 #using scripts\shared\ai\systems\animation_state_machine_mocomp;
14 #using scripts\shared\ai\archetype_locomotion_utility;
15 #using scripts\shared\ai\archetype_utility;
16 #using scripts\shared\ai\systems\behavior_tree_utility;
17 #using scripts\shared\ai\systems\blackboard;
18 #using scripts\shared\ai\systems\debug;
19 #using scripts\shared\ai\systems\gib;
20 #using scripts\shared\ai\zombie_utility;
21 #using scripts\shared\ai\zombie_death;
22 #using scripts\shared\ai\zombie_shared;
23 #using scripts\codescripts\struct;
24 #using scripts\shared\ai\archetype_mocomps_utility;
27 #using scripts\shared\ai\systems\ai_interface;
28 #using scripts\shared\ai\archetype_zombie_interface;
30 #insert scripts\shared\ai\archetype_damage_effects.gsh;
32 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
33 #insert scripts\shared\ai\systems\animation_state_machine.gsh;
34 #insert scripts\shared\ai\systems\behavior.gsh;
35 #insert scripts\shared\ai\systems\behavior_tree.gsh;
36 #insert scripts\shared\ai\systems\blackboard.gsh;
37 #insert scripts\shared\ai\systems\gib.gsh;
38 #insert scripts\shared\ai\utility.gsh;
39 #insert scripts\shared\ai\zombie.gsh;
40 #insert scripts\shared\shared.gsh;
41 #insert scripts\shared\version.gsh;
43 #namespace ZombieBehavior;
170 entity.__blackboard = undefined;
181 function private ArchetypeZombieSpecialEffectsCallback( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName )
183 specialDayEffectChance = GetDvarInt(
"tu6_ffotd_zombieSpecialDayEffectsChance", 0);
185 if( specialDayEffectChance && RandomInt(100) < specialDayEffectChance )
187 if( IsDefined( eAttacker ) && IsPlayer( eAttacker ) )
200 if( IsDefined(
self.zombie_arms_position ) )
202 if(
self.zombie_arms_position ==
"up" )
212 if ( IsDefined(
self.zombie_move_speed ) )
214 if(
self.zombie_move_speed ==
"walk" )
218 else if(
self.zombie_move_speed ==
"run" )
222 else if(
self.zombie_move_speed ==
"sprint" )
226 else if(
self.zombie_move_speed ==
"super_sprint" )
230 else if(
self.zombie_move_speed ==
"jump_pad_super_sprint" )
234 else if(
self.zombie_move_speed ==
"burned" )
238 else if(
self.zombie_move_speed ==
"slide" )
248 if( IsDefined(
self.variant_type ) )
250 return self.variant_type;
257 if(
self.missingLegs )
264 if( IsDefined(
self.should_turn ) &&
self.should_turn )
273 if( IsDefined(
self.damage_direction ) )
275 return self.damage_direction;
282 if ( isdefined(
self.low_gravity_variant ) )
284 return self.low_gravity_variant;
294 return !
IS_TRUE(behaviorTreeEntity.missingLegs);
299 if(
IS_TRUE( behaviorTreeEntity.suicidalDeath ) )
302 return !
IS_TRUE(behaviorTreeEntity.missingLegs);
307 if ( IsDefined( behaviorTreeEntity.juke ) && ( behaviorTreeEntity.juke ==
"left" || behaviorTreeEntity.juke ==
"right" ) )
317 if ( isDefined( behaviorTreeEntity.stumble ) )
328 if ( IsDefined( behaviorTreeEntity.jukeDistance ) )
338 behaviorTreeEntity.jukeDistance = undefined;
339 behaviorTreeEntity.juke = undefined;
344 behaviorTreeEntity ClearPath();
349 behaviorTreeEntity.stumble = undefined;
354 behaviorTreeEntity.is_inert =
true;
359 behaviorTreeEntity.is_inert =
false;
369 if (
IS_TRUE( entity.aat_turned ) )
371 if ( IsDefined( entity.enemy ) && !isPlayer( entity.enemy ) )
378 entity.n_aat_turned_zombie_kills++;
383 entity.n_aat_turned_zombie_kills++;
385 else if(
IS_TRUE(entity.enemy.canBeTargetedByTurnedZombies) )
393 if ( IsDefined( entity.enemy ) && (
IS_TRUE( entity.enemy.bgb_in_plain_sight_active ) ||
IS_TRUE( entity.enemy.bgb_idle_eyes_active ) ) )
398 if ( IsDefined( entity.enemy ) &&
IS_TRUE( entity.enemy.allow_zombie_to_target_ai ) )
400 if ( entity.enemy.health > 0 )
402 entity.enemy DoDamage( entity.meleeWeapon.meleeDamage, entity.origin, entity, entity,
"none",
"MOD_MELEE" );
409 Record3DText(
"melee",
self.origin,
RED,
"Script", entity );
414 if ( IsDefined( level.attackableCallback ) )
416 entity.attackable [[ level.attackableCallback ]]( entity );
424 behaviorTreeEntity
delete();
429 if ( isdefined( behaviorTreeEntity.enablePushTime ) )
431 if ( GetTime() >= behaviorTreeEntity.enablePushTime )
433 behaviorTreeEntity PushActors(
true );
434 behaviorTreeEntity.enablePushTime = undefined;
438 if(
IS_TRUE( behaviorTreeEntity.disableTargetService ) )
443 if (
IS_TRUE( behaviorTreeEntity.ignoreall ) )
448 specificTarget = undefined;
451 if( IsDefined( level.zombieLevelSpecificTargetCallback ) )
453 specificTarget = [[level.zombieLevelSpecificTargetCallback]]();
456 if( IsDefined( specificTarget ) )
458 behaviorTreeEntity SetGoal( specificTarget.origin );
460 else if( isdefined( behaviorTreeEntity.v_zombie_custom_goal_pos ) )
462 goalPos = behaviorTreeEntity.v_zombie_custom_goal_pos;
464 if ( isdefined( behaviorTreeEntity.n_zombie_custom_goal_radius ) )
466 behaviorTreeEntity.goalradius = behaviorTreeEntity.n_zombie_custom_goal_radius;
469 behaviorTreeEntity SetGoal( goalPos );
475 if( !IsDefined( player ) )
477 if( IsDefined(
self.ignore_player ) )
479 if(isDefined(level._should_skip_ignore_player_logic) && [[level._should_skip_ignore_player_logic]]() )
484 self.ignore_player = [];
487 self SetGoal(
self.origin );
492 if ( IsDefined( player.last_valid_position ) )
494 if( !
IS_TRUE(
self.zombie_do_not_update_goal ) )
496 if(
IS_TRUE( level.zombie_use_zigzag_path ) )
502 behaviorTreeEntity SetGoal( player.last_valid_position );
510 if( !
IS_TRUE(
self.zombie_do_not_update_goal ) )
512 behaviorTreeEntity SetGoal( behaviorTreeEntity.origin );
523 AIProfile_BeginEntry(
"zombieUpdateZigZagGoal" );
526 const ZM_ZOMBIE_ZIGZAG_GOAL_TOLERENCE_DIST = 72;
527 const ZM_ZOMBIE_ZIGZAZ_ACTIVATION_DIST = 250;
528 shouldRepath =
false;
530 if ( !shouldRepath && IsDefined(
self.favoriteenemy ) )
532 if ( !IsDefined(
self.nextGoalUpdate ) ||
self.nextGoalUpdate <= GetTime() )
537 else if ( DistanceSquared(
self.origin,
self.favoriteenemy.origin ) <=
SQR( ZM_ZOMBIE_ZIGZAZ_ACTIVATION_DIST ) )
542 else if ( IsDefined(
self.pathGoalPos ) )
545 distanceToGoalSqr = DistanceSquared(
self.origin,
self.pathGoalPos );
547 shouldRepath = distanceToGoalSqr <
SQR( ZM_ZOMBIE_ZIGZAG_GOAL_TOLERENCE_DIST );
553 if ( GetTime() >
self.keep_moving_time )
555 self.keep_moving =
false;
561 goalPos =
self.favoriteenemy.origin;
562 if ( IsDefined(
self.favoriteenemy.last_valid_position ) )
564 goalPos =
self.favoriteenemy.last_valid_position;
568 self SetGoal( goalPos );
571 if ( DistanceSquared(
self.origin, goalPos ) >
SQR( ZM_ZOMBIE_ZIGZAZ_ACTIVATION_DIST ) )
573 self.keep_moving =
true;
574 self.keep_moving_time = GetTime() + 250;
575 path =
self CalcApproximatePathToPosition( goalPos,
false );
578 if ( GetDvarInt(
"ai_debugZigZag" ) )
580 for ( index = 1; index < path.size; index++ )
582 RecordLine( path[index - 1], path[index],
ORANGE,
"Animscript",
self );
587 if( IsDefined( level._zombieZigZagDistanceMin ) && IsDefined( level._zombieZigZagDistanceMax ) )
589 min = level._zombieZigZagDistanceMin;
590 max = level._zombieZigZagDistanceMax;
598 deviationDistance = RandomIntRange( min, max );
603 for ( index = 1; index < path.size; index++ )
605 currentSegLength = Distance( path[index - 1], path[index] );
607 if ( ( segmentLength + currentSegLength ) > deviationDistance )
609 remainingLength = deviationDistance - segmentLength;
611 seedPosition = path[index - 1] + ( VectorNormalize( path[index] - path[index - 1] ) * remainingLength );
613 /# RecordCircle( seedPosition, 2,
ORANGE,
"Animscript",
self ); #/
615 innerZigZagRadius = 0;
616 outerZigZagRadius = 96;
619 queryResult = PositionQuery_Source_Navigation(
628 PositionQuery_Filter_InClaimedLocation( queryResult,
self );
630 if ( queryResult.data.size > 0 )
632 point = queryResult.data[ RandomInt( queryResult.data.size ) ];
635 self SetGoal( point.origin );
641 segmentLength += currentSegLength;
645 if( IsDefined( level._zombieZigZagTimeMin ) && IsDefined( level._zombieZigZagTimeMax ) )
647 minTime = level._zombieZigZagTimeMin;
648 maxTime = level._zombieZigZagTimeMax;
657 self.nextGoalUpdate = GetTime() + RandomIntRange(minTime, maxTime);
660 AIProfile_EndEntry();
666 if ( !
IS_TRUE( behaviorTreeEntity.missingLegs ) && !
IS_TRUE( behaviorTreeEntity.knockdown ) )
671 if ( IsDefined( behaviorTreeEntity.dontPushTime ) )
673 if ( GetTime() < behaviorTreeEntity.dontPushTime )
679 zombies = GetAITeamArray( level.zombie_team );
680 foreach( zombie
in zombies )
682 if ( zombie == behaviorTreeEntity )
692 dist_sq = DistanceSquared( behaviorTreeEntity.origin, zombie.origin );
695 behaviorTreeEntity PushActors(
false );
701 behaviorTreeEntity PushActors(
true );
707 if ( isdefined( entity.traverseStartNode ) )
709 entity PushActors(
false );
718 if (
IS_TRUE( entity.missingLegs ) )
723 if ( IsDefined( entity.enemyoverride ) && IsDefined( entity.enemyoverride[1] ) )
728 if ( IsDefined( entity.favoriteenemy ) &&
IS_TRUE( entity.favoriteenemy.b_is_designated_target ) )
733 if (
IS_TRUE( entity.aat_turned ) )
738 if ( IsDefined( entity.attackable ) &&
IS_TRUE( entity.attackable.is_active ) )
740 if ( !IsDefined( entity.attackable_slot ) )
751 dist = Distance2DSquared( entity.origin, entity.attackable_slot.origin );
754 height_offset = Abs( entity.origin[2] - entity.attackable_slot.origin[2] );
755 if ( height_offset < 32 )
757 entity.is_at_attackable =
true;
775 if (
IS_TRUE( entity.missingLegs ) )
780 if ( IsDefined( entity.enemyoverride ) && IsDefined( entity.enemyoverride[1] ) )
785 if ( IsDefined( entity.favoriteenemy ) &&
IS_TRUE( entity.favoriteenemy.b_is_designated_target ) )
790 if (
IS_TRUE( entity.aat_turned ) )
795 if ( IsDefined( entity.attackable ) &&
IS_TRUE( entity.attackable.is_active ) )
797 if (
IS_TRUE( entity.is_at_attackable ) )
808 if( IsDefined( behaviorTreeEntity.enemyoverride ) && IsDefined( behaviorTreeEntity.enemyoverride[1] ) )
813 if( !IsDefined( behaviortreeentity.enemy ) )
818 if( IsDefined( behaviorTreeEntity.marked_for_death ) )
823 if(
IS_TRUE( behaviorTreeEntity.ignoreMelee ) )
828 if( DistanceSquared( behaviorTreeEntity.origin, behaviorTreeEntity.enemy.origin ) >
ZM_MELEE_DIST_SQ )
833 yawToEnemy = AngleClamp180( behaviorTreeEntity.angles[ 1 ] -
GET_YAW( behaviorTreeEntity, behaviorTreeEntity.enemy.origin ) );
842 #define ZM_MELEE_JUMP_DISTANCE_ABOVE 60
843 #define ZM_MELEE_JUMP_DIST 180
844 #define ZM_MELEE_JUMP_CHANCE 0.5
847 if ( !
IS_TRUE( behaviorTreeEntity.low_gravity ) )
852 if( IsDefined( behaviorTreeEntity.enemyoverride ) && IsDefined( behaviorTreeEntity.enemyoverride[1] ) )
857 if( !IsDefined( behaviortreeentity.enemy ) )
862 if( IsDefined( behaviorTreeEntity.marked_for_death ) )
867 if(
IS_TRUE( behaviorTreeEntity.ignoreMelee ) )
872 if ( behaviorTreeEntity.enemy IsOnGround() )
878 if ( ( ( behaviorTreeEntity GetEntityNumber() % 10 ) / 10 ) > jumpChance )
883 predictedPosition = behaviorTreeEntity.enemy.origin + behaviorTreeEntity.enemy GetVelocity() *
SERVER_FRAME * 2;
887 if( Distance2DSquared( behaviorTreeEntity.origin, predictedPosition ) > jumpDistanceSq )
892 yawToEnemy = AngleClamp180( behaviorTreeEntity.angles[ 1 ] -
GET_YAW( behaviorTreeEntity, behaviorTreeEntity.enemy.origin ) );
898 heightToEnemy = behaviorTreeEntity.enemy.origin[2] - behaviorTreeEntity.origin[2];
907 #define ZM_MELEE_JUMP_DISTANCE_ABOVE_WATER 48
908 #define ZM_MIN_IN_WATER_DEPTH 48
909 #define ZM_MELEE_WATER_JUMP_DIST 64
912 if( IsDefined( behaviorTreeEntity.enemyoverride ) && IsDefined( behaviorTreeEntity.enemyoverride[1] ) )
917 if( !IsDefined( behaviortreeentity.enemy ) )
922 if( IsDefined( behaviorTreeEntity.marked_for_death ) )
927 if(
IS_TRUE( behaviorTreeEntity.ignoreMelee ) )
932 if ( behaviorTreeEntity.enemy IsOnGround() )
944 if( Distance2DSquared( behaviorTreeEntity.origin, behaviorTreeEntity.enemy.origin ) > jumpDistanceSq )
949 yawToEnemy = AngleClamp180( behaviorTreeEntity.angles[ 1 ] -
GET_YAW( behaviorTreeEntity, behaviorTreeEntity.enemy.origin ) );
955 heightToEnemy = behaviorTreeEntity.enemy.origin[2] - behaviorTreeEntity.origin[2];
966 if (
IS_TRUE( behaviorTreeEntity.missingLegs ) )
970 if ( !
IS_TRUE( behaviorTreeEntity.canStumble ) )
974 if ( !IsDefined( behaviorTreeEntity.zombie_move_speed ) || behaviorTreeEntity.zombie_move_speed !=
"sprint" )
978 if ( IsDefined( behaviorTreeEntity.stumble ) )
982 if (!IsDefined( behaviorTreeEntity.next_stumble_time ) )
986 if ( GetTime() > behaviorTreeEntity.next_stumble_time )
990 closestPlayer = ArrayGetClosest( behaviorTreeEntity.origin, level.players );
993 if ( IsDefined( behaviorTreeEntity.next_juke_time ) )
995 behaviorTreeEntity.next_juke_time = undefined;
998 behaviorTreeEntity.next_stumble_time = undefined;
999 behaviorTreeEntity.stumble =
true;
1019 if (
IS_TRUE( behaviorTreeEntity.missingLegs ) )
1032 if ( IsDefined( behaviorTreeEntity.juke ) )
1037 if ( !IsDefined( behaviorTreeEntity.next_juke_time ) )
1042 if ( GetTime() > behaviorTreeEntity.next_juke_time )
1044 behaviorTreeEntity.next_juke_time = undefined;
1049 if ( IsDefined( behaviorTreeEntity.next_stumble_time ) )
1051 behaviorTreeEntity.next_stumble_time = undefined;
1055 behaviorTreeEntity.ignoreBackwardPosition =
true;
1061 behaviorTreeEntity.jukeDistance =
"long";
1063 switch( behaviorTreeEntity ZombieBehavior::bb_getlocomotionspeedtype() )
1067 forwardOffset = 122;
1070 forwardOffset = 129;
1078 if ( !IsDefined( behaviorTreeEntity.juke ) || behaviorTreeEntity.juke ==
"forward" )
1082 behaviorTreeEntity.jukeDistance =
"short";
1084 switch( behaviorTreeEntity ZombieBehavior::bb_getlocomotionspeedtype() )
1088 forwardOffset = 127;
1091 forwardOffset = 148;
1096 if( behaviorTreeEntity.juke ==
"forward" )
1099 behaviorTreeEntity.juke = undefined;
1100 behaviorTreeEntity.jukeDistance = undefined;
1118 if( isdefined( behaviorTreeEntity.interdimensional_gun_kill ) &&
1119 !isdefined( behaviorTreeEntity.killby_interdimensional_gun_hole ) &&
1120 IsAlive( behaviorTreeEntity ) )
1130 if(isdefined(behaviorTreeEntity.killby_interdimensional_gun_hole))
1140 entity OrientMode(
"face angle", entity.angles[1] );
1142 entity.pushable =
false;
1143 entity.blockingPain =
true;
1144 entity PathMode(
"dont move" );
1146 entity.hole_pull_speed = 0;
1151 entity OrientMode(
"face enemy" );
1153 entity.pushable =
false;
1154 entity.blockingPain =
true;
1155 entity.clampToNavMesh =
false;
1156 entity PushActors(
false );
1158 entity.jumpStartPosition = entity.origin;
1163 normalizedTime = ( ( entity GetAnimTime( mocompAnim ) * GetAnimLength( mocompAnim ) ) + mocompAnimBlendOutTime ) / mocompDuration;
1165 if (normalizedTime > 0.5)
1167 entity OrientMode(
"face angle", entity.angles[1] );
1172 if ( IsDefined( entity.zombie_move_speed ) )
1174 switch ( entity.zombie_move_speed )
1188 newPosition = entity.origin + AnglesToForward( entity.angles ) * speed;
1191 newTestPosition = ( newPosition[0], newPosition[1], entity.jumpStartPosition[2] );
1192 newValidPosition = GetClosestPointOnNavMesh( newTestPosition, 12, 20 );
1194 if ( IsDefined( newValidPosition ) )
1197 newValidPosition = ( newValidPosition[0], newValidPosition[1], entity.origin[2] );
1202 newValidPosition = entity.origin;
1206 groundPoint = GetClosestPointOnNavMesh( newValidPosition, 12, 20 );
1207 if ( IsDefined( groundPoint ) && groundPoint[2] > newValidPosition[2] )
1209 newValidPosition = ( newValidPosition[0], newValidPosition[1], groundPoint[2] );
1212 entity ForceTeleport( newValidPosition );
1217 entity.pushable =
true;
1218 entity.blockingPain =
false;
1219 entity.clampToNavMesh =
true;
1220 entity PushActors(
true );
1222 groundPoint = GetClosestPointOnNavMesh( entity.origin, 12 );
1223 if ( IsDefined( groundPoint ) )
1225 entity ForceTeleport( groundPoint );
1230 #define VORTEX_Z_OFFSET 36
1234 if(!isdefined(entity.killby_interdimensional_gun_hole))
1236 entity_eye = entity GetEye();
1239 if( entity IsPaused() )
1241 entity SetIgnorePauseWorld(
true );
1242 entity SetEntityPaused(
false );
1245 if ( entity.b_vortex_repositioned !==
true )
1247 entity.b_vortex_repositioned =
true;
1248 v_nearest_navmesh_point = GetClosestPointOnNavMesh( entity.damageOrigin,
VORTEX_Z_OFFSET, 15 );
1249 if ( isdefined(v_nearest_navmesh_point) )
1251 f_distance = Distance( entity.damageOrigin, v_nearest_navmesh_point);
1261 entity_center = entity.origin + ( ( entity_eye - entity.origin ) / 2 );
1262 flyingDir = entity.damageOrigin - entity_center;
1263 lengthFromHole = Length(flyingDir);
1265 if(lengthFromHole < entity.hole_pull_speed)
1267 entity.killby_interdimensional_gun_hole =
true;
1268 entity.allowdeath =
true;
1269 entity.takedamage =
true;
1270 entity.aiOverrideDamage = undefined;
1271 entity.magic_bullet_shield =
false;
1272 level notify(
"interdimensional_kill",entity);
1273 if( IsDefined( entity.interdimensional_gun_weapon ) && IsDefined( entity.interdimensional_gun_attacker ) )
1275 entity
kill(entity.origin, entity.interdimensional_gun_attacker, entity.interdimensional_gun_attacker, entity.interdimensional_gun_weapon);
1279 entity
kill( entity.origin );
1292 flyingDir = VectorNormalize(flyingDir);
1293 entity ForceTeleport(entity.origin + flyingDir * entity.hole_pull_speed);
1300 entity OrientMode(
"face angle", entity.angles[1] );
1302 entity.pushable =
false;
1307 if( !
IS_TRUE( entity.interdimensional_gun_kill_vortex_explosion ) )
1315 entity OrientMode(
"face angle", entity.angles[1] );
1321 normalizedTime = ( entity GetAnimTime( mocompAnim ) + mocompAnimBlendOutTime ) / mocompDuration;
1323 if ( normalizedTime > 0.25 )
1325 entity OrientMode(
"face motion" );
1332 entity OrientMode(
"face motion" );
1338 if( behaviorTreeEntity.missingLegs ===
true )
1348 return IsDefined( entity.traverseStartNode ) &&
1349 IsDefined( entity.traverseEndNode ) &&
1361 if(
IS_TRUE( behaviorTreeEntity.magic_bullet_shield ) )
1366 if( !IsDefined( behaviortreeentity.enemy ) )
1371 if( IsDefined( behaviorTreeEntity.marked_for_death ) )
1386 behaviorTreeEntity.blockingPain =
true;
1388 if( IsDefined( level.zombieMeleeSuicideCallback ) )
1390 behaviorTreeEntity thread [[level.zombieMeleeSuicideCallback]](behaviorTreeEntity);
1403 behaviorTreeEntity.takedamage =
true;
1404 behaviorTreeEntity.allowDeath =
true;
1408 if( IsDefined( level.zombieMeleeSuicideDoneCallback ) )
1410 behaviorTreeEntity thread [[level.zombieMeleeSuicideDoneCallback]](behaviorTreeEntity);
1418 behaviorTreeEntity.moveTime = GetTime();
1419 behaviorTreeEntity.moveOrigin = behaviorTreeEntity.origin;
1424 if( IsDefined( behaviorTreeEntity.stumble ) && !IsDefined( behaviorTreeEntity.move_anim_end_time ) )
1426 stumbleActionResult = behaviorTreeEntity ASTSearch( IString( asmStateName ) );
1429 behaviorTreeEntity.move_anim_end_time = behaviorTreeEntity.moveTime + GetAnimLength( stumbleActionAnimation );
1432 if( IsDefined( behaviorTreeEntity.zombieMoveActionCallback ) )
1434 behaviorTreeEntity [[behaviorTreeEntity.zombieMoveActionCallback]]( behaviorTreeEntity );
1443 if ( IsDefined( behaviorTreeEntity.move_anim_end_time ) && ( GetTime() >= behaviorTreeEntity.move_anim_end_time ) )
1445 behaviorTreeEntity.move_anim_end_time = undefined;
1449 if ( !
IS_TRUE( behaviorTreeEntity.missingLegs ) && ( GetTime() - behaviorTreeEntity.moveTime >
ZM_MOVE_TIME ) )
1451 distSq = Distance2DSquared( behaviorTreeEntity.origin, behaviorTreeEntity.moveOrigin );
1454 behaviorTreeEntity SetAvoidanceMask(
"avoid all" );
1455 behaviorTreeEntity.cant_move =
true;
1457 if ( IsDefined( behaviorTreeEntity.cant_move_cb ) )
1459 behaviorTreeEntity [[ behaviorTreeEntity.cant_move_cb ]]();
1464 behaviorTreeEntity SetAvoidanceMask(
"avoid none" );
1465 behaviorTreeEntity.cant_move =
false;
1468 behaviorTreeEntity.moveTime = GetTime();
1469 behaviorTreeEntity.moveOrigin = behaviorTreeEntity.origin;
1474 if( behaviorTreeEntity IsCurrentBTActionLooping() )
1485 if ( !
IS_TRUE( behaviorTreeEntity.missingLegs ) )
1487 behaviorTreeEntity SetAvoidanceMask(
"avoid none" );
1499 #define CLOSE_EXPLOSIVE SQR(60)
1503 if( !
IS_TRUE( level.zombieAnhilationEnabled ) )
1506 if(
IS_TRUE(
self.forceAnhilateOnDeath ) )
1514 if( IsDefined( attacker ) && IsPlayer( attacker ) && (
IS_TRUE( attacker.forceAnhilateOnDeath ) ||
IS_TRUE( level.forceAnhilateOnDeath ) ) )
1522 attackerDistance = 0;
1524 if ( IsDefined( attacker ) )
1526 attackerDistance = DistanceSquared( attacker.origin,
self.origin );
1529 isExplosive = IsInArray(
1533 "MOD_GRENADE_SPLASH",
1535 "MOD_PROJECTILE_SPLASH",
1539 if ( IsDefined( weapon.weapclass ) && weapon.weapclass ==
"turret" )
1542 if ( IsDefined( inflictor ) )
1544 isDirectExplosive = IsInArray(
1547 "MOD_GRENADE_SPLASH",
1549 "MOD_PROJECTILE_SPLASH",
1553 isCloseExplosive = DistanceSquared( inflictor.origin,
self.origin ) <=
CLOSE_EXPLOSIVE;
1555 if ( isDirectExplosive && isCloseExplosive )
1569 if( IsDefined( entity.enemyoverride ) && IsDefined( entity.enemyoverride[1] ) && entity != entity.enemyoverride[1] )
1571 entity OrientMode(
"face direction", entity.enemyoverride[1].origin - entity.origin );
1576 entity OrientMode(
"face current" );
1583 if( IsDefined( entity.attackable_slot ) )
1585 entity OrientMode(
"face angle", entity.attackable_slot.angles[1] );
1590 entity OrientMode(
"face current" );
1597 if( IsDefined( entity.attackable_slot ) )
1599 entity ForceTeleport( entity.attackable_slot.origin );