1 #using scripts\shared\ai_shared;
2 #using scripts\shared\clientfield_shared;
3 #using scripts\shared\laststand_shared;
4 #using scripts\shared\math_shared;
5 #using scripts\shared\spawner_shared;
6 #using scripts\shared\gameskill_shared;
7 #using scripts\shared\util_shared;
8 #using scripts\shared\system_shared;
10 #using scripts\shared\ai\archetype_cover_utility;
11 #using scripts\shared\ai\archetype_locomotion_utility;
12 #using scripts\shared\ai\archetype_mocomps_utility;
13 #using scripts\shared\ai\archetype_robot_interface;
14 #using scripts\shared\ai\archetype_utility;
16 #using scripts\shared\ai\systems\ai_blackboard;
17 #using scripts\shared\ai\systems\ai_interface;
18 #using scripts\shared\ai\systems\ai_squads;
19 #using scripts\shared\ai\systems\animation_state_machine_mocomp;
20 #using scripts\shared\ai\systems\animation_state_machine_utility;
21 #using scripts\shared\ai\systems\behavior_state_machine;
22 #using scripts\shared\ai\systems\behavior_tree_utility;
23 #using scripts\shared\ai\systems\blackboard;
24 #using scripts\shared\ai\systems\debug;
25 #using scripts\shared\ai\systems\destructible_character;
26 #using scripts\shared\ai\systems\gib;
27 #using scripts\shared\ai\systems\shared;
29 #using scripts\shared\vehicles\_raps;
31 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
32 #insert scripts\shared\shared.gsh;
33 #insert scripts\shared\version.gsh;
34 #insert scripts\shared\ai\archetype_robot.gsh;
35 #insert scripts\shared\ai\utility.gsh;
36 #insert scripts\shared\ai\systems\animation_state_machine.gsh;
37 #insert scripts\shared\ai\systems\behavior.gsh;
38 #insert scripts\shared\ai\systems\behavior_state_machine.gsh;
39 #insert scripts\shared\ai\systems\behavior_tree.gsh;
40 #insert scripts\shared\ai\systems\blackboard.gsh;
41 #insert scripts\shared\ai\systems\gib.gsh;
88 #namespace RobotSoldierBehavior;
233 entity notify(
"emp_fx_start" );
249 return entity.gibDeath;
254 entity.empStopTime = GetTime() + entity.empShutdownTime;
258 entity notify(
"emp_shutdown_start" );
281 entity notify(
"emp_shutdown_end" );
288 assert( IsDefined( entity.traversal ) );
290 traversal = entity.traversal;
292 t = min( ( GetTime() - traversal.startTime ) / traversal.totalTime, 1 );
293 curveRemaining = traversal.curveLength * ( 1 - t );
295 if ( curveRemaining < traversal.landingDistance )
297 traversal.landing =
true;
306 if ( IsDefined( entity.traversal ) )
308 entity Finishtraversal();
316 if ( !IsDefined( entity.traverseStartNode ) ||
317 !IsDefined( entity.traverseEndNode ) )
322 entity.traversal = SpawnStruct();
324 traversal = entity.traversal;
327 traversal.landingDistance = 24;
328 traversal.minimumSpeed = 18;
330 traversal.startNode = entity.traverseStartNode;
331 traversal.endNode = entity.traverseEndNode;
337 traversal.startPoint1 = entity.origin;
338 traversal.endPoint1 = traversal.endNode.origin;
343 faceNormal = GetNavMeshFaceNormal( traversal.endPoint1, 30 );
347 if ( !IsDefined( traversal.endPoint1 ) )
350 traversal.endPoint1 = traversal.endNode.origin;
353 traversal.distanceToEnd = Distance( traversal.startPoint1, traversal.endPoint1 );
354 traversal.absHeightToEnd = Abs( traversal.startPoint1[2] - traversal.endPoint1[2] );
355 traversal.absLengthToEnd = Distance2D( traversal.startPoint1, traversal.endPoint1 );
360 if ( traversal.absLengthToEnd > 200 )
364 else if ( traversal.absLengthToEnd > 120 )
368 else if ( traversal.absLengthToEnd > 80 || traversal.absHeightToEnd > 80 )
373 if ( IsDefined( entity.traversalSpeedBoost ) )
375 speedBoost = entity [[ entity.traversalSpeedBoost ]]();
378 traversal.speedOnCurve = ( traversal.minimumSpeed + speedBoost ) * 12;
382 heightOffset = max( traversal.absHeightToEnd * 0.8, min( traversal.absLengthToEnd, 96 ) );
384 traversal.startPoint2 = entity.origin + ( 0, 0, heightOffset );
385 traversal.endPoint2 = traversal.endPoint1 + ( 0, 0, heightOffset );
388 if ( traversal.startPoint1[2] < traversal.endPoint1[2] )
390 traversal.startPoint2 += ( 0, 0, traversal.absHeightToEnd );
394 traversal.endPoint2 += ( 0, 0, traversal.absHeightToEnd );
398 if ( startIsWallrun || endIsWallrun )
403 if ( startDirection ==
"out" )
406 towardEnd = ( traversal.endNode.origin - entity.origin ) * point2Scale;
408 traversal.startPoint2 = entity.origin + ( towardEnd[0], towardEnd[1], 0 );
409 traversal.endPoint2 = traversal.endPoint1 + ( 0, 0, traversal.absHeightToEnd * point2Scale );
411 traversal.angles = entity.angles;
414 if ( endDirection ==
"in" )
417 towardStart = ( entity.origin - traversal.endNode.origin ) * point2Scale;
419 traversal.startPoint2 = entity.origin + ( 0, 0, traversal.absHeightToEnd * point2Scale );
420 traversal.endPoint2 = traversal.endNode.origin + ( towardStart[0], towardStart[1], 0 );
422 faceNormal = GetNavMeshFaceNormal( traversal.endNode.origin, 30 );
424 moveDirection = VectorCross( faceNormal, ( 0, 0, 1 ) );
426 if ( direction ==
"right" )
428 moveDirection = -moveDirection;
431 traversal.angles = VectortoAngles( moveDirection );
437 traversal.landingDistance = 110;
441 traversal.landingDistance = 60;
445 traversal.speedOnCurve *= 1.2;
450 RecordLine( traversal.startPoint1, traversal.startPoint2,
ORANGE,
"Animscript", entity );
451 RecordLine( traversal.startPoint1, traversal.endPoint1,
ORANGE,
"Animscript", entity );
452 RecordLine( traversal.endPoint1, traversal.endPoint2,
ORANGE,
"Animscript", entity );
453 RecordLine( traversal.startPoint2, traversal.endPoint2,
ORANGE,
"Animscript", entity );
455 Record3DText( traversal.absLengthToEnd, traversal.endPoint1 + (0, 0, 12),
ORANGE,
"Animscript", entity );
460 previousPoint = traversal.startPoint1;
461 traversal.curveLength = 0;
463 for ( index = 1; index <= segments; index++ )
465 t = index / segments;
467 nextPoint =
CalculateCubicBezier( t, traversal.startPoint1, traversal.startPoint2, traversal.endPoint2, traversal.endPoint1 );
470 recordLine( previousPoint, nextPoint,
GREEN,
"Animscript", entity );
473 traversal.curveLength += Distance( previousPoint, nextPoint );
475 previousPoint = nextPoint;
479 traversal.startTime = GetTime();
480 traversal.endTime = traversal.startTime + traversal.curveLength * ( 1000 / traversal.speedOnCurve );
481 traversal.totalTime = traversal.endTime - traversal.startTime;
483 traversal.landing =
false;
490 entity.skipdeath =
true;
493 traversal = entity.traversal;
495 traversal.startTime = GetTime();
496 traversal.endTime = traversal.startTime + traversal.curveLength * ( 1000 / traversal.speedOnCurve );
497 traversal.totalTime = traversal.endTime - traversal.startTime;
508 entity.skipdeath =
false;
509 entity.traversal = undefined;
511 entity notify(
"traverse_end" );
518 if ( !IsAlive( entity ) )
520 entity StartRagdoll();
528 if ( IsDefined( entity.traverseStartNode ) && IsDefined( entity.traverseEndNode ) )
542 startNode = entity.traverseStartNode;
543 endNode = entity.traverseEndNode;
545 if ( IsDefined( startNode ) &&
546 IsDefineD( endNode ) &&
547 entity ShouldStartTraversal() )
552 return startIsWallrun || endIsWallrun;
565 entity SetRepairPaths(
false );
566 entity OrientMode(
"face angle", entity.angles[1] );
567 entity.blockingPain =
true;
568 entity.clampToNavMesh =
false;
572 entity SetAvoidanceMask(
"avoid none" );
577 faceNormal = GetNavMeshFaceNormal( entity.origin, 30 );
578 positionOnWall = GetClosestPointOnNavMesh( entity.origin, 30, 0 );
581 if ( IsDefined( faceNormal ) && IsDefined( positionOnWall ) )
584 faceNormal = ( faceNormal[0], faceNormal[1], 0 );
585 faceNormal = VectorNormalize( faceNormal );
587 moveDirection = VectorCross( faceNormal, ( 0, 0, 1 ) );
589 if ( direction ==
"right" )
591 moveDirection = -moveDirection;
594 forwardPositionOnWall = GetClosestPointOnNavMesh( positionOnWall + moveDirection * 12, 30, 0 );
596 anglesToEnd = VectortoAngles( forwardPositionOnWall - positionOnWall );
598 /# recordLine( positionOnWall, forwardPositionOnWall,
RED,
"Animscript", entity ); #/
600 entity OrientMode(
"face angle", anglesToEnd[1] );
606 entity SetRepairPaths(
true );
607 entity SetAvoidanceMask(
"avoid all" );
608 entity.blockingPain =
false;
609 entity.clampToNavMesh =
true;
614 return pow( 1 - t, 3 ) * p1 +
615 3 *
pow( 1 - t, 2 ) * t * p2 +
616 3 * ( 1 - t ) *
pow( t, 2 ) * p3 +
622 startNode = entity.traverseStartNode;
624 endNode = entity.traverseEndNode;
629 angleToEnd = VectortoAngles( entity.traverseEndNode.origin - entity.traverseStartNode.origin );
630 entity OrientMode(
"face angle", angleToEnd[1] );
632 if ( startIsWallrun )
644 faceNormal = GetNavMeshFaceNormal( endNode.origin, 30 );
646 moveDirection = VectorCross( faceNormal, ( 0, 0, 1 ) );
648 if ( direction ==
"right" )
650 moveDirection = -moveDirection;
653 /# recordLine( endNode.origin, endNode.origin + faceNormal * 20,
RED,
"Animscript", entity ); #/
654 /# recordLine( endNode.origin, endNode.origin + moveDirection * 20,
RED,
"Animscript", entity ); #/
656 angles = VectortoAngles( moveDirection );
657 entity OrientMode(
"face angle", angles[1] );
659 if ( startIsWallrun )
669 entity SetRepairPaths(
false );
670 entity.blockingPain =
true;
671 entity.clampToNavMesh =
false;
673 entity PathMode(
"dont move" );
682 traversal = entity.traversal;
684 entity SetAvoidanceMask(
"avoid none" );
685 entity OrientMode(
"face angle", entity.angles[1] );
686 entity SetRepairPaths(
false );
690 entity.blockingPain =
true;
691 entity.clampToNavMesh =
false;
693 if ( IsDefined( traversal ) && traversal.landing )
702 traversal = entity.traversal;
704 if ( IsDefined( traversal ) )
706 if ( entity IsPaused() )
713 realT = ( GetTime() - traversal.startTime ) / traversal.totalTime;
716 if ( t < 1.0 || realT == 1.0 || !endIsWallrun )
718 currentPos =
CalculateCubicBezier( t, traversal.startPoint1, traversal.startPoint2, traversal.endPoint2, traversal.endPoint1 );
720 angles = entity.angles;
722 if ( IsDefined( traversal.angles ) )
724 angles = traversal.angles;
728 entity ForceTeleport( currentPos, angles,
false );
739 traversal = entity.traversal;
741 if ( IsDefined( traversal ) && GetTime() >= traversal.endTime )
750 entity PathMode(
"move allowed" );
754 entity.clampToNavMesh =
true;
755 entity.blockingPain =
false;
756 entity SetRepairPaths(
true );
757 entity SetAvoidanceMask(
"avoid all" );
762 entity.blockingpain =
true;
764 if ( IsDefined( entity.enemy ) )
766 entity OrientMode(
"face enemy" );
770 entity OrientMode(
"face angle", entity.angles[1] );
778 if ( IsDefined( entity.enemy ) && entity GetAnimTime( mocompAnim ) < 0.5 )
780 entity OrientMode(
"face enemy" );
784 entity OrientMode(
"face angle", entity.angles[1] );
790 entity.blockingpain =
false;
797 faceNormal = GetNavMeshFaceNormal( endPosition, 30 );
799 /# recordLine( startPosition, endPosition,
ORANGE,
"Animscript", entity ); #/
801 if ( IsDefined( faceNormal ) )
803 /# recordLine( endPosition, endPosition + faceNormal * 12,
ORANGE,
"Animscript", entity ); #/
805 angles = VectorToAngles( faceNormal );
806 right = AnglesToRight( angles );
808 d = -VectorDot( right, endPosition );
810 if ( VectorDot( right, startPosition ) + d > 0 )
824 entity.skipdeath =
true;
826 entity PushActors(
false );
827 entity PushPlayer(
true );
828 entity.pushable =
false;
837 entity.skipdeath =
false;
839 entity PushActors(
true );
840 entity PushPlayer(
false );
841 entity.pushable =
true;
847 startNode = entity.traverseStartNode;
848 endNode = entity.traverseEndNode;
850 direction =
"unknown";
851 jumpDirection =
"unknown";
852 traversalType =
"unknown";
854 if ( IsDefined( startNode ) && IsDefined( endNode ) )
867 if ( direction ==
"right" )
892 startNode = entity.traverseStartNode;
893 endNode = entity.traverseEndNode;
895 landDirection =
"unknown";
896 traversalType =
"unknown";
898 if ( IsDefined( startNode ) && IsDefined( endNode ) )
913 startNode = entity.traverseStartNode;
914 endNode = entity.traverseEndNode;
916 if ( IsDefined( startNode ) && IsDefined( endNode ) )
921 if ( startIsWallrun )
923 absLengthToEnd = Distance2D( startNode.origin, endNode.origin );
925 if ( startNode.origin[2] - endNode.origin[2] > 48 &&
926 absLengthToEnd < 250 )
942 startNode = entity.traverseStartNode;
943 endNode = entity.traverseEndNode;
945 if ( IsDefined( startNode ) && IsDefined( endNode ) )
952 absLengthToEnd = Distance2D( startNode.origin, endNode.origin );
954 if ( endNode.origin[2] - startNode.origin[2] > 48 &&
955 absLengthToEnd < 250 )
970 if ( IsDefined( node ) )
1014 if ( SessionModeIsCampaignGame() || SessionModeIsZombiesGame() )
1020 if(
self.accurateFire )
1029 if ( !IsDefined( entity.enemy ) )
1034 aimLimits = entity GetAimLimitsFromEntry(
"robot_crawler" );
1036 yawToEnemy = AngleClamp180(
1037 VectorToAngles( ( entity LastKnownPos( entity.enemy ) ) - entity.origin )[1] - entity.angles[1] );
1041 return yawToEnemy <= ( aimLimits[
AIM_LEFT] + angleEpsilon ) &&
1042 yawToEnemy >= ( aimLimits[
AIM_RIGHT] + angleEpsilon );
1048 entity.__blackboard = undefined;
1061 if ( rightArmGibbed && leftArmGibbed )
1065 else if ( rightArmGibbed )
1069 else if ( leftArmGibbed )
1079 entity.steppedOutOfCover =
false;
1080 entity PathMode(
"move allowed" );
1085 entity PathMode(
"move delayed",
false, RandomFloatRange( 1, 2 ) );
1106 entity.steppedOutOfCoverNode = entity.node;
1113 entity.steppedOutOfCover =
true;
1118 entity PathMode(
"dont move" );
1124 !
IS_TRUE( entity.steppedOutOfCover ) &&
1128 tooCloseJukeDistanceSqr = 240 * 240;
1130 foreach ( event
in jukeEvents )
1132 if ( Distance2DSquared( entity.origin, event.data.origin ) <= tooCloseJukeDistanceSqr )
1146 if ( entity HasPath () &&
1160 if ( !IsDefined( entity.enemy ) || !IsPlayer( entity.enemy ) )
1170 if ( !entity.shouldPreemptiveJuke )
1175 if ( IsDefined( entity.nextPreemptiveJuke ) && entity.nextPreemptiveJuke > GetTime() )
1180 if ( entity.enemy PlayerADS() < entity.nextPreemptiveJukeAds )
1187 if ( IsWeapon( entity.enemy.currentweapon ) &&
1188 IsDefined( entity.enemy.currentweapon.enemycrosshairrange ) &&
1189 entity.enemy.currentweapon.enemycrosshairrange > 0)
1191 jukeMaxDistance = entity.enemy.currentweapon.enemycrosshairrange;
1201 if ( DistanceSquared( entity.origin, entity.enemy.origin ) <
SQR( jukeMaxDistance ) )
1203 angleDifference = AbsAngleClamp180( entity.angles[1] - entity.enemy.angles[1] );
1206 record3DText( angleDifference, entity.origin + (0, 0, 5),
GREEN,
"Animscript" );
1210 if ( angleDifference > 135 )
1212 enemyAngles = entity.enemy GetGunAngles();
1213 toEnemy = entity.enemy.origin - entity.origin;
1214 forward = AnglesToForward( enemyAngles );
1215 dotProduct = Abs( VectorDot( VectorNormalize( toEnemy ), forward ) );
1218 record3DText( ACos( dotProduct ), entity.origin + (0, 0, 10),
GREEN,
"Animscript" );
1222 if ( dotProduct > 0.9848 )
1249 if ( IsDefined( entity.crawlerLifeTime ) &&
1250 entity.crawlerLifeTime <= GetTime() &&
1261 return entity.isCrawler;
1271 entity.isCrawler =
true;
1272 entity.becomeCrawler =
false;
1273 entity AllowPitchAngle( 1 );
1274 entity SetPitchOrient();
1275 entity.crawlerLifeTime = GetTime() + RandomIntRange( 10000, 20000 );
1276 entity notify(
"bhtn_action_notify",
"rbCrawler" );
1281 return entity.becomeCrawler;
1331 if ( entity.controlLevel > 1 )
1333 return "mind_controlled";
1341 entity.combatmode =
"no_cover";
1347 if( !IsDefined( player ) ||
1348 !IsAlive( player ) ||
1349 !IsPlayer( player ) ||
1350 player.sessionstate ==
"spectator" ||
1351 player.sessionstate ==
"intermission" ||
1363 if ( !IsDefined( entity.enemy ) )
1368 distanceToEnemy = Distance2DSquared( entity.origin, entity.enemy.origin );
1373 findPathResult = entity FindPath( entity.origin, entity.enemy.origin,
true,
false );
1375 if ( findPathResult )
1384 return IsDefined( neighbor ) &&
1385 IsDefined( neighbor.archetype ) &&
1386 neighbor.archetype ==
"robot" &&
1387 IsDefined( neighbor.team ) &&
1388 entity.team == neighbor.team &&
1389 entity != neighbor &&
1390 IsDefined( neighbor.enemy ) &&
1400 actors = GetAiArray();
1402 closestEnemy = undefined;
1403 closestEnemyDistance = undefined;
1405 foreach( index, ai
in actors )
1409 enemyDistance = DistanceSquared( entity.origin, ai.origin );
1411 if ( !IsDefined( closestEnemyDistance ) ||
1412 enemyDistance < closestEnemyDistance )
1414 closestEnemyDistance = enemyDistance;
1420 if ( IsDefined( closestEnemy ) )
1422 findPathResult = entity FindPath( closestEnemy.origin, closestEnemy.enemy.origin,
true,
false );
1424 if ( findPathResult )
1433 closest = SpawnStruct();
1435 if ( entities.size > 0 )
1437 closest.entity = entities[0];
1438 closest.distanceSquared = DistanceSquared( entity.origin, closest.entity.origin );
1440 for ( index = 1; index < entities.size; index++ )
1442 distanceSquared = DistanceSquared( entity.origin, entities[index].origin );
1444 if ( distanceSquared < closest.distanceSquared )
1446 closest.distanceSquared = distanceSquared;
1447 closest.entity = entities[index];
1462 if (
IS_TRUE( entity.ignoreall ) )
1468 if ( IsDefined( entity.nextTargetServiceUpdate ) &&
1469 entity.nextTargetServiceUpdate > GetTime() &&
1470 IsAlive( entity.favoriteenemy ) )
1477 if ( !IsDefined( positionOnNavMesh ) )
1483 if ( IsDefined( entity.favoriteenemy ) &&
1484 IsDefined( entity.favoriteenemy._currentRogueRobot ) &&
1485 entity.favoriteenemy._currentRogueRobot == entity )
1487 entity.favoriteenemy._currentRogueRobot = undefined;
1493 players = GetPlayers();
1496 foreach( index, value
in ai )
1499 if ( IsSentient( value ) && entity GetIgnoreEnt( value ) )
1506 if ( value.team != entity.team && IsActor( value ) && !IsDefined( entity.favoriteenemy ) )
1510 if ( IsDefined( enemyPositionOnNavMesh ) &&
1511 entity FindPath( positionOnNavMesh, enemyPositionOnNavMesh,
true,
false ) )
1513 aiEnemies[aiEnemies.size] = value;
1519 foreach( index, value
in players )
1524 if ( IsSentient( value ) && entity GetIgnoreEnt( value ) )
1531 if ( IsDefined( enemyPositionOnNavMesh ) &&
1532 entity FindPath( positionOnNavMesh, enemyPositionOnNavMesh,
true,
false ) )
1534 playerEnemies[playerEnemies.size] = value;
1542 if ( !IsDefined( closestPlayer.entity ) && !IsDefined( closestAI.entity ) )
1547 else if ( !IsDefined( closestAI.entity ) )
1550 entity.favoriteenemy = closestPlayer.entity;
1552 else if ( !IsDefined( closestPlayer.entity ) )
1555 entity.favoriteenemy = closestAI.entity;
1556 entity.favoriteenemy._currentRogueRobot = entity;
1558 else if ( closestAI.distanceSquared < closestPlayer.distanceSquared )
1561 entity.favoriteenemy = closestAI.entity;
1562 entity.favoriteenemy._currentRogueRobot = entity;
1567 entity.favoriteenemy = closestPlayer.entity;
1570 entity.nextTargetServiceUpdate = GetTime() + RandomIntRange( 2500, 3500 );
1614 if ( entity.controlLevel >= 3 )
1620 else if ( IsDefined( entity.enemy ) )
1622 enemyDistSq = DistanceSquared( entity.origin, entity.enemy.origin );
1633 if( !IsDefined( entity.node ) )
1646 behaviorTreeEntity IsAtCoverNodeStrict() &&
1647 behaviorTreeEntity IsFlankedAtCoverNode() &&
1648 !behaviorTreeEntity HasPath();
1653 entity.allowDeath =
false;
1654 entity.noCyberCom =
true;
1661 entity RadiusDamage(
1684 if ( IsAlive( entity ) )
1686 entity.allowDeath =
true;
1690 entity StartRagdoll();
1697 if ( IsDefined( entity.steppedOutOfCover ) &&
1698 IsDefined( entity.steppedOutOfCoverNode ) &&
1699 ( !entity IsCoverValid( entity.steppedOutOfCoverNode ) ||
1701 !entity IsSafeFromGrenade() ) )
1703 entity.steppedOutOfCover =
false;
1704 entity PathMode(
"move allowed" );
1707 if ( IsDefined( entity.resumeCover ) && GetTime() > entity.resumeCover )
1709 entity.combatMode =
"cover";
1710 entity.resumeCover = undefined;
1716 enemyTooClose =
false;
1718 if( IsDefined( entity.enemy ) )
1720 lastKnownEnemyPos = entity LastKnownPos( entity.enemy );
1721 distanceToEnemySqr = Distance2DSquared( entity.origin, lastKnownEnemyPos );
1725 return !enemyTooClose &&
1726 !entity.steppedOutOfCover &&
1727 entity IsAtCoverNodeStrict() &&
1728 entity ShouldUseCoverNode() &&
1729 !entity HasPath() &&
1730 entity IsSafeFromGrenade() &&
1731 entity.combatMode !=
"no_cover";
1736 if ( IsDefined( entity.node ) )
1753 if ( !IsDefined( entity.enemy ) || entity.enemy.health <= 0 )
1761 if ( !IsDefined( positionOnNavMesh ) || !IsDefined( enemyPositionOnNavMesh ) )
1766 findPathResult = entity FindPath( positionOnNavMesh, enemyPositionOnNavMesh,
true,
false );
1769 if ( !findPathResult )
1771 record3DText(
"NO PATH", enemyPositionOnNavMesh + (0, 0, 5),
ORANGE,
"Animscript" );
1772 recordLine( positionOnNavMesh, enemyPositionOnNavMesh,
ORANGE,
"Animscript", entity );
1776 return findPathResult;
1781 if ( !IsDefined( entity.enemy ) || entity.enemy.health <= 0 )
1786 queryResult = PositionQuery_Source_Navigation(
1787 entity.enemy.origin,
1794 PositionQuery_Filter_InClaimedLocation( queryResult, entity );
1796 return queryResult.data.size > 0;
1826 if ( IsAlive( entity ) )
1834 entity.keepclaimednode =
false;
1838 if ( !IsDefined( positionOnNavMesh ) )
1844 if (
IS_TRUE( entity.ignoreall ) )
1846 entity ClearUsePosition();
1850 if ( !IsDefined( entity.enemy ) )
1861 if ( entity.allowPushActors )
1863 if ( IsDefined( entity.enemy ) &&
1864 DistanceSquared( entity.origin, entity.enemy.origin ) >
SQR( 300 ) )
1867 entity PushActors(
false );
1872 entity PushActors(
true );
1876 if ( entity AsmIsTransDecRunning() || entity AsmIsTransitionRunning() )
1882 if ( !IsDefined( entity.lastKnownEnemyPos) )
1884 entity.lastKnownEnemyPos = entity.enemy.origin;
1887 shouldRepath = !IsDefined( entity.lastValidEnemyPos );
1889 if ( !shouldRepath && IsDefined( entity.enemy ) )
1891 if ( IsDefined( entity.nextMoveToPlayerUpdate ) && entity.nextMoveToPlayerUpdate <= GetTime() )
1894 shouldRepath =
true;
1896 else if ( DistanceSquared( entity.lastKnownEnemyPos, entity.enemy.origin ) >
SQR( 72 ) )
1899 shouldRepath =
true;
1901 else if ( DistanceSquared( entity.origin, entity.enemy.origin ) <=
SQR( 120 ) )
1904 shouldRepath =
true;
1906 else if ( IsDefined( entity.pathGoalPos ) )
1909 distanceToGoalSqr = DistanceSquared( entity.origin, entity.pathGoalPos );
1911 shouldRepath = distanceToGoalSqr <
SQR( 72 );
1917 entity.lastKnownEnemyPos = entity.enemy.origin;
1920 queryResult = PositionQuery_Source_Navigation(
1921 entity.lastKnownEnemyPos,
1928 PositionQuery_Filter_InClaimedLocation( queryResult, entity );
1930 if ( queryResult.data.size > 0 )
1932 entity.lastValidEnemyPos = queryResult.data[0].origin;
1935 if ( IsDefined( entity.lastValidEnemyPos ) )
1937 entity UsePosition( entity.lastValidEnemyPos );
1940 if ( DistanceSquared( entity.origin, entity.lastValidEnemyPos ) >
SQR( 240 ) )
1942 path = entity CalcApproximatePathToPosition( entity.lastValidEnemyPos,
false );
1945 if ( GetDvarInt(
"ai_debugZigZag" ) )
1947 for ( index = 1; index < path.size; index++ )
1949 RecordLine( path[index - 1], path[index],
ORANGE,
"Animscript", entity );
1954 deviationDistance = RandomIntRange( 240, 480 );
1959 for ( index = 1; index < path.size; index++ )
1961 currentSegLength = Distance( path[index - 1], path[index] );
1963 if ( ( segmentLength + currentSegLength ) > deviationDistance )
1965 remainingLength = deviationDistance - segmentLength;
1967 seedPosition = path[index - 1] + ( VectorNormalize( path[index] - path[index - 1] ) * remainingLength );
1969 /# RecordCircle( seedPosition, 2,
ORANGE,
"Animscript", entity ); #/
1971 innerZigZagRadius = 0;
1972 outerZigZagRadius = 64;
1975 queryResult = PositionQuery_Source_Navigation(
1984 PositionQuery_Filter_InClaimedLocation( queryResult, entity );
1986 if ( queryResult.data.size > 0 )
1988 point = queryResult.data[ RandomInt( queryResult.data.size ) ];
1991 entity UsePosition( point.origin );
1997 segmentLength += currentSegLength;
2003 entity.nextMoveToPlayerUpdate = GetTime() + RandomIntRange(2000, 3000);
2022 if ( IsDefined( entity.enemy ) &&
2023 IsSentient( entity.enemy ) &&
2024 entity.enemy.health > 0 )
2026 enemyDistSq = DistanceSquared( entity.origin, entity.enemy.origin );
2028 if ( enemyDistSq <
SQR( entity.chargeMeleeDistance ) && Abs( entity.enemy.origin[2] - entity.origin[2] ) < 24 )
2030 yawToEnemy = AngleClamp180( entity.angles[ 1 ] -
2031 GET_YAW(entity, entity.enemy.origin ) );
2042 if ( IsDefined( entity.enemy ) &&
2043 IsSentient( entity.enemy ) &&
2044 entity.enemy.health > 0 &&
2047 if ( !entity CanSee( entity.enemy ) )
2052 return DistanceSquared( entity.origin, entity.enemy.origin ) <
SQR( 132 );
2071 if ( IsDefined( entity.enemy ) &&
2072 IsSentient( entity.enemy ) &&
2073 entity.enemy.health > 0 )
2075 if ( !entity CanSee( entity.enemy ) )
2080 enemyDistSq = DistanceSquared( entity.origin, entity.enemy.origin );
2084 yawToEnemy = AngleClamp180( entity.angles[ 1 ] -
2085 GET_YAW(entity, entity.enemy.origin ) );
2096 if ( IsDefined( entity.enemy ) &&
2097 IsSentient( entity.enemy ) &&
2098 entity.enemy.health > 0 &&
2101 return DistanceSquared( entity.origin, entity.enemy.origin ) <
MELEE_RANGE_SQ;
2132 if ( IsDefined( entity.damageweapon ) && IsDefined( entity.damagemod ) )
2134 weapon = entity.damageweapon;
2136 return entity.damagemod ==
"MOD_GRENADE_SPLASH" &&
2137 IsDefined( weapon.rootweapon ) &&
2138 isSubStr(weapon.rootweapon.name,
"emp_grenade");
2145 if ( IsDefined( entity.enemy ) &&
2157 assert( IsDefined( range ) );
2159 if ( !IsDefined( entity.enemy ) && !entity HasPath() )
2164 goalPos = entity.pathgoalpos;
2166 if ( IsDefined( entity.enemy ) && useEnemyPos )
2168 goalPos = entity LastKnownPos( entity.enemy );
2171 if( !isdefined( goalPos ) )
2176 outsideRange = DistanceSquared( entity.origin, goalPos ) >
SQR( range );
2178 return outsideRange;
2215 if ( IsDefined( entity.enemy ) &&
2216 DistanceSquared( entity.origin, entity.goalPos ) <
SQR( entity.minWalkDistance ) )
2232 if ( IsDefined( entity.enemy ) &&
2233 DistanceSquared( entity.origin, entity.goalPos ) <
SQR( entity.minWalkDistance ) )
2244 switch ( entity.controlLevel )
2247 return IsInArray(
array(
"level_1",
"level_2",
"level_3" ),
2250 return IsInArray(
array(
"level_2",
"level_3" ),
2261 return IsDefined( entity.miniRaps );
2266 velocity = entity GetVelocity();
2267 velocity = ( velocity[0], 0, velocity[1] );
2269 velocitySqr = LengthSquared( velocity );
2271 return velocitySqr >
SQR( 24 );
2277 return entity.controlLevel <= 1;
2282 if ( !entity HasPath() )
2292 if( entity IsFlankedAtCoverNode() )
2297 if( entity ShouldHoldGroundAgainstEnemy() )
2302 shouldUseCoverNode = undefined;
2303 itsBeenAWhile = GetTime() > entity.nextFindBestCoverTime;
2304 isAtScriptGoal = undefined;
2306 if ( IsDefined( entity.robotNode ) )
2308 isAtScriptGoal = entity IsPosAtGoal( entity.robotNode.origin );
2309 shouldUseCoverNode = entity IsCoverValid( entity.robotNode );
2313 isAtScriptGoal = entity IsAtGoal();
2314 shouldUseCoverNode = entity ShouldUseCoverNode();
2317 shouldLookForBetterCover = !shouldUseCoverNode || itsBeenAWhile || !isAtScriptGoal;
2320 recordEntText(
"ChooseBetterCoverReason: shouldUseCoverNode:" + shouldUseCoverNode
2321 +
" itsBeenAWhile:" + itsBeenAWhile
2322 +
" isAtScriptGoal:" + isAtScriptGoal
2323 , entity, ( shouldLookForBetterCover ?
GREEN :
RED ),
"Animscript" );
2327 if ( shouldLookForBetterCover && IsDefined( entity.enemy ) && !entity.keepClaimedNode )
2329 transitionRunning = entity ASMIsTransitionRunning();
2330 subStatePending = entity ASMIsSubStatePending();
2331 transDecRunning = entity AsmIsTransDecRunning();
2332 isBehaviorTreeInRunningState = entity GetBehaviortreeStatus() ==
BHTN_RUNNING;
2334 if ( !transitionRunning && !subStatePending && !transDecRunning && isBehaviorTreeInRunningState )
2336 nodes = entity FindBestCoverNodes( entity.goalRadius, entity.goalPos );
2340 for ( nodeIndex = 0; nodeIndex < nodes.size; nodeIndex++ )
2342 if ( entity.robotNode === nodes[nodeIndex] ||
2343 !IsDefined( nodes[nodeIndex].robotClaimed ) )
2345 node = nodes[nodeIndex];
2351 if ( IsEntity( entity.node ) &&
2352 ( !IsDefined( entity.robotNode ) || entity.robotNode != entity.node ) )
2354 entity.robotNode = entity.node;
2355 entity.robotNode.robotClaimed =
true;
2358 goingToDifferentNode =
2359 IsDefined( node ) &&
2360 ( !IsDefined( entity.robotNode ) || node != entity.robotNode ) &&
2361 ( !IsDefined( entity.steppedOutOfCoverNode ) || entity.steppedOutOfCoverNode != node );
2365 if ( goingToDifferentNode )
2373 searchRadius = entity.goalRadius;
2387 if ( coverNodePoints.size > 0 )
2389 entity UsePosition( coverNodePoints[ RandomInt( coverNodePoints.size ) ] );
2393 entity UsePosition( entity GetNodeOffsetPosition( node ) );
2397 if ( IsDefined( entity.robotNode ) )
2399 entity.robotNode.robotClaimed = undefined;
2402 entity.robotNode = node;
2403 entity.robotNode.robotClaimed =
true;
2405 entity PathMode(
"move delayed",
false, RandomFloatRange( 0.25, 2 ) );
2421 if ( !IsDefined( escortPosition ) )
2426 if ( Distance2DSquared( entity.origin, escortPosition ) <=
2432 if ( IsDefined( entity.escortNextTime ) &&
2433 GetTime() < entity.escortNextTime )
2438 if ( entity GetPathMode() ==
"dont move" )
2445 if ( !IsDefined( positionOnNavMesh ) )
2447 positionOnNavMesh = escortPosition;
2450 queryResult = PositionQuery_Source_Navigation(
2459 PositionQuery_Filter_InClaimedLocation( queryResult, entity );
2461 if ( queryResult.data.size > 0 )
2463 closestPoint = undefined;
2464 closestDistance = undefined;
2466 foreach ( point
in queryResult.data )
2468 if ( !point.inclaimedlocation )
2470 newClosestDistance = Distance2DSquared( entity.origin, point.origin );
2472 if ( !IsDefined( closestPoint ) ||
2473 newClosestDistance < closestDistance )
2475 closestPoint = point.origin;
2476 closestDistance = newClosestDistance;
2481 if ( IsDefined( closestPoint ) )
2483 entity UsePosition( closestPoint );
2484 entity.escortNextTime = GetTime() + RandomIntRange( 200, 300 );
2498 entity PathMode(
"move allowed" );
2500 if ( !IsDefined( entity.enemy ) )
2505 distToEnemySqr = Distance2DSquared( entity.origin, entity.enemy.origin );
2507 if ( distToEnemySqr <=
SQR( entity.robotRusherMaxRadius ) &&
2508 distToEnemySqr >=
SQR( entity.robotRusherMinRadius ) )
2513 if ( IsDefined( entity.rusherNextTime ) &&
2514 GetTime() < entity.rusherNextTime )
2521 if ( !IsDefined( positionOnNavMesh ) )
2523 positionOnNavMesh = entity.enemy.origin;
2526 queryResult = PositionQuery_Source_Navigation(
2528 entity.robotRusherMinRadius,
2529 entity.robotRusherMaxRadius,
2535 PositionQuery_Filter_InClaimedLocation( queryResult, entity );
2536 PositionQuery_Filter_Sight( queryResult, entity.enemy.origin, entity GetEye() - entity.origin, entity, 2, entity.enemy );
2538 if ( queryResult.data.size > 0 )
2540 closestPoint = undefined;
2541 closestDistance = undefined;
2543 foreach ( point
in queryResult.data )
2545 if ( !point.inclaimedlocation && point.visibility ===
true )
2547 newClosestDistance = Distance2DSquared( entity.origin, point.origin );
2549 if ( !IsDefined( closestPoint ) ||
2550 newClosestDistance < closestDistance )
2552 closestPoint = point.origin;
2553 closestDistance = newClosestDistance;
2558 if ( IsDefined( closestPoint ) )
2560 entity UsePosition( closestPoint );
2561 entity.rusherNextTime = GetTime() + RandomIntRange( 500, 1500 );
2575 if ( entity GetPathMode() ==
"dont move" )
2580 if ( ( !IsDefined( entity.guardPosition ) ||
2581 DistanceSquared( entity.origin , entity.guardPosition ) <
SQR( 60 ) ) )
2583 entity PathMode(
"move delayed",
true, RandomFloatRange( 1, 1.5 ) );
2585 queryResult = PositionQuery_Source_Navigation(
2588 entity.goalradius / 2,
2594 PositionQuery_Filter_InClaimedLocation( queryResult, entity );
2596 if ( queryResult.data.size > 0 )
2598 minimumDistanceSq = entity.goalradius * 0.2;
2599 minimumDistanceSq = minimumDistanceSq * minimumDistanceSq;
2603 foreach( point
in queryResult.data )
2605 if ( DistanceSquared( entity.origin, point.origin ) > minimumDistanceSq )
2607 distantPoints[ distantPoints.size ] = point;
2611 if ( distantPoints.size > 0 )
2613 randomPosition = distantPoints[ RandomInt( distantPoints.size ) ];
2615 entity.guardPosition = randomPosition.origin;
2616 entity.intermediateGuardPosition = undefined;
2617 entity.intermediateGuardTime = undefined;
2625 currentTime = GetTime();
2627 if ( !IsDefined( entity.intermediateGuardTime ) ||
2628 entity.intermediateGuardTime < currentTime )
2630 if ( IsDefined( entity.intermediateGuardPosition ) &&
2631 DistanceSquared( entity.intermediateGuardPosition , entity.origin ) <
SQR( 24 ) )
2633 entity.guardPosition = entity.origin;
2636 entity.intermediateGuardPosition = entity.origin;
2637 entity.intermediateGuardTime = currentTime + 3000;
2640 if ( IsDefined( entity.guardPosition ) )
2643 entity UsePosition( entity.guardPosition );
2649 entity.guardPosition = undefined;
2650 entity.intermediateGuardPosition = undefined;
2651 entity.intermediateGuardTime = undefined;
2659 if ( GetDvarInt(
"ai_debugLastKnown" ) && IsDefined( entity.enemy ) )
2661 lastKnownPos = entity LastKnownPos( entity.enemy );
2662 recordLine( entity.origin, lastKnownPos,
ORANGE,
"Animscript", entity );
2663 record3DText(
"lastKnownPos", lastKnownPos + (0, 0, 5),
ORANGE,
"Animscript" );
2668 if ( !IsAlive( entity ) )
2670 if ( IsDefined( entity.robotNode ) )
2673 entity.robotNode.robotClaimed = undefined;
2674 entity.robotNode = undefined;
2680 if ( entity.disableRepath )
2734 if ( entity.weapon.name == level.weaponNone.name )
2745 entity notify(
"bhtn_action_notify",
"rbJuke" );
2756 entity.nextPreemptiveJuke = GetTime() + RandomIntRange( 4000, 6000 );
2757 entity.nextPreemptiveJukeAds = RandomFloatRange( 0.5, 0.95 );
2763 if ( moveMode ==
"rusher" || moveMode ==
"escort" || moveMode ==
"guard" )
2768 if ( !IsDefined( entity.reacquire_state ) )
2770 entity.reacquire_state = 0;
2773 if ( !IsDefined( entity.enemy ) )
2775 entity.reacquire_state = 0;
2779 if ( entity HasPath() )
2794 if ( entity CanSee( entity.enemy ) && entity CanShootEnemy() )
2796 entity.reacquire_state = 0;
2801 dirToEnemy = VectorNormalize( entity.enemy.origin - entity.origin );
2802 forward = AnglesToForward( entity.angles );
2804 if ( VectorDot( dirToEnemy, forward ) <
COS_60 )
2806 entity.reacquire_state = 0;
2810 switch ( entity.reacquire_state )
2816 reacquirePos = entity ReacquireStep( step_size );
2820 if ( !( entity CanSee( entity.enemy ) ) || !( entity CanShootEnemy() ) )
2822 entity FlagEnemyUnattackable();
2829 entity.reacquire_state = 0;
2835 if ( IsVec( reacquirePos ) )
2837 entity UsePosition( reacquirePos );
2841 entity.reacquire_state++;
2886 entity.steppedOutOfCoverNode = undefined;
2895 entity.steppedOutOfCover =
false;
2899 entity PathMode(
"move allowed" );
2906 entity.steppedOutOfCoverNode = entity.node;
2930 entity.steppedOutOfCover =
true;
2931 entity.steppedOutTime = GetTime();
2935 entity PathMode(
"dont move" );
2949 if ( !IsDefined( entity.steppedOutOfCover ) ||
2950 !entity.steppedOutOfCover ||
2951 !IsDefined( entity.steppedOutTime ) ||
2952 !entity.steppedOutOfCover )
2957 exposedTimeInSeconds = (GetTime() - entity.steppedOutTime) / 1000;
2962 suppressed = entity.suppressionMeter > entity.suppressionThreshold;
2964 return exceededtime || ( exceededtime && suppressed );
2971 if ( IsDefined( entity ) && IsDefined( entity.miniRaps ) )
2982 raps = SpawnVehicle(
2986 raps.team = entity.team;
2992 entity.miniRaps = undefined;
2998 #namespace RobotSoldierServerUtils;
3007 else if ( IsInArray(
array(
"head",
"neck",
"helmet" ), hitLoc ) &&
3012 else if ( ( entity.health -
damage ) <= 0 &&
3041 else if ( IsInArray(
array(
"left_hand",
"left_arm_lower",
"left_arm_upper" ), hitLoc ) )
3046 IsInArray(
array(
"right_hand",
"right_arm_lower",
"right_arm_upper" ), hitLoc ) )
3051 IsInArray(
array(
"right_hand",
"right_arm_lower",
"right_arm_upper" ), hitLoc ) )
3070 if ( !IsDefined( attacker ) )
3076 canGibLegs = ( entity.health -
damage ) <= 0 && entity.allowdeath;
3081 canGibLegs = canGibLegs ||
3085 entity.allowdeath );
3088 if ( entity.gibDeath &&
3089 ( entity.health -
damage ) <= 0 &&
3090 entity.allowdeath &&
3097 if ( ( entity.health -
damage ) <= 0 &&
3098 entity.allowdeath &&
3103 entity StartRagdoll();
3105 else if ( canGibLegs &&
3106 IsInArray(
array(
"left_leg_upper",
"left_leg_lower",
"left_foot" ), hitLoc ) &&
3109 if ( ( entity.health -
damage ) > 0 )
3116 else if ( canGibLegs &&
3117 IsInArray(
array(
"right_leg_upper",
"right_leg_lower",
"right_foot" ), hitLoc ) &&
3120 if ( ( entity.health -
damage ) > 0 )
3127 else if ( ( entity.health -
damage ) <= 0 &&
3128 entity.allowdeath &&
3144 inflictor, attacker,
damage, flags, meansOfDeath, weapon, point, dir, hitLoc, offsetTime, boneIndex, modelIndex )
3148 if ( IsDefined( attacker ) && ( attacker.team == entity.team ) )
3168 isExplosive = IsInArray(
3172 "MOD_GRENADE_SPLASH",
3174 "MOD_PROJECTILE_SPLASH",
3186 inflictor, attacker,
damage, meansOfDeath, weapon, dir, hitLoc, offsetTime )
3196 inflictor, attacker,
damage, meansOfDeath, weapon, dir, hitLoc, offsetTime )
3209 isExplosive =
false;
3211 if ( entity.controlLevel >= 3 )
3228 velocity = entity GetVelocity() / 9;
3230 entity StartRagdoll();
3231 entity LaunchRagdoll(
3232 ( velocity[0] + RandomFloatRange( -10, 10 ),
3233 velocity[1] + RandomFloatRange( -10, 10 ),
3234 RandomFloatRange( 40, 50 ) ),
3237 PhysicsExplosionSphere(
3241 isExplosive = IsInArray(
3245 "MOD_GRENADE_SPLASH",
3247 "MOD_PROJECTILE_SPLASH",
3258 inflictor, attacker,
damage, meansOfDeath, weapon, dir, hitLoc, offsetTime )
3262 if ( entity.skipdeath )
3271 possiblePieces = [];
3274 for ( index = 1; index <= pieceCount; index++ )
3279 possiblePieces[ possiblePieces.size ] = index;
3288 randomPiece = RandomIntRange( 0, possiblePieces.size - 1 );
3301 inflictor, attacker,
damage, flags, meansOfDamage, weapon, point, dir, hitLoc, offsetTime, boneIndex, modelIndex )
3305 if( hitLoc !=
"helmet" || hitLoc !=
"head" || hitLoc !=
"neck" )
3307 if( isDefined( attacker ) && !isPlayer( attacker ) && !isVehicle( attacker ) )
3309 dist = DistanceSquared( entity.origin, attacker.origin );
3311 if( dist < 256*256 )
3324 if ( hitLoc ==
"helmet" || hitLoc ==
"head" || hitLoc ==
"neck" )
3329 if ( IsDefined( dir ) &&
3330 IsDefined( meansOfDamage ) &&
3331 IsDefined( hitLoc ) &&
3332 VectorDot( AnglesToForward( entity.angles ), dir ) > 0 )
3335 isBullet = IsInArray(
3336 array(
"MOD_RIFLE_BULLET",
"MOD_PISTOL_BULLET" ),
3339 isTorsoShot = IsInArray(
3340 array(
"torso_upper",
"torso_lower" ),
3343 if ( isBullet && isTorsoShot )
3350 if ( weapon.name ==
"sticky_grenade" )
3352 switch ( meansOfDamage )
3355 entity.stuckWithStickyGrenade =
true;
3357 case "MOD_GRENADE_SPLASH":
3358 if (
IS_TRUE( entity.stuckWithStickyGrenade ) )
3366 if ( meansOfDamage ==
"MOD_TRIGGER_HURT" && entity.ignoreTriggerDamage )
3375 inflictor, attacker,
damage, flags, meansOfDamage, weapon, point, dir, hitLoc, offsetTime, boneIndex, modelIndex )
3379 isExplosive = IsInArray(
3383 "MOD_GRENADE_SPLASH",
3385 "MOD_PROJECTILE_SPLASH",
3399 enemyPositionOnNavMesh = undefined;
3403 enemyPositionOnNavMesh = GetClosestPointOnNavMesh(
3408 if ( IsDefined( enemyPositionOnNavMesh ) )
3414 return enemyPositionOnNavMesh;
3419 if ( !IsDefined( entity.node ) )
3432 entity.isCrawler =
false;
3433 entity.becomeCrawler =
false;
3434 entity.combatmode =
"cover";
3435 entity.fullHealth = entity.health;
3436 entity.controlLevel = 0;
3437 entity.steppedOutOfCover =
false;
3438 entity.ignoreTriggerDamage =
false;
3439 entity.startingWeapon = entity.weapon;
3444 entity.NoFriendlyfire =
true;
3445 entity.ignorerunAndgundist =
true;
3446 entity.disableRepath =
false;
3457 entity.treatAllCoversAsGeneric =
true;
3458 entity.onlyCrouchArrivals =
true;
3460 entity.chargeMeleeDistance = 125;
3461 entity.allowPushActors =
true;
3463 entity.nextPreemptiveJukeAds = RandomFloatRange( 0.5, 0.95 );
3472 if ( GetDvarInt(
"ai_robotForceProcedural" ) )
3489 if ( GetDvarInt(
"ai_robotForceControl" ) == 1 )
3491 else if ( GetDvarInt(
"ai_robotForceControl" ) == 2 )
3493 else if ( GetDvarInt(
"ai_robotForceControl" ) == 3 )
3496 if ( GetDvarInt(
"ai_robotSpawnForceControl" ) == 1 )
3498 else if ( GetDvarInt(
"ai_robotSpawnForceControl" ) == 2 )
3500 else if ( GetDvarInt(
"ai_robotSpawnForceControl" ) == 3 )
3504 if ( GetDvarInt(
"ai_robotForceCrawler" ) == 1 )
3506 else if ( GetDvarInt(
"ai_robotForceCrawler" ) == 2 )
3516 if ( IsDefined( entity ) && !IsDefined( entity.wasp ) )
3518 wasp =
Spawn(
"script_model", ( 0, 0, 0 ) );
3519 wasp SetModel(
"veh_t7_drone_attack_red" );
3520 wasp SetScale( 0.75 );
3521 wasp LinkTo( entity,
"j_spine4", ( 5, -15, 0 ), ( 0, 0, 90 ) );
3528 entity endon(
"death" );
3530 wait RandomFloatRange( 7, 10 );
3532 if ( IsDefined( entity ) && IsDefined( entity.wasp ) )
3534 spawnOffset = ( 5, -15, 0 );
3536 while ( !IsPointInNavvolume( entity.wasp.origin + spawnOffset,
"small volume" ) )
3541 entity.wasp Unlink();
3543 wasp = SpawnVehicle(
"spawner_bo3_wasp_enemy", entity.wasp.origin + spawnOffset, ( 0, 0, 0 ) );
3545 entity.wasp Delete();
3548 entity.wasp = undefined;
3553 entity endon(
"death" );
3555 wait RandomFloatRange(
3567 entity.becomeCrawler =
true;
3573 entity waittill(
"death" );
3575 if ( !IsDefined( entity ) )
3580 if ( IsDefined( entity.miniRaps ) )
3585 entity.miniRaps = undefined;
3588 if ( IsDefined( entity.wasp ) )
3590 entity.wasp Delete();
3591 entity.wasp = undefined;
3599 if ( entity.controlLevel >= 1 )
3604 entity.team =
"team3";
3605 entity.controlLevel = 1;
3614 if ( entity.controlLevel >= 2 )
3619 rogue_melee_weapon = GetWeapon(
"rogue_robot_melee" );
3621 locomotionTypes =
array(
"alt1",
"alt2",
"alt3",
"alt4",
"alt5" );
3624 entity ASMSetAnimationRate( RandomFloatRange( 0.95, 1.05 ) );
3626 entity.combatmode =
"no_cover";
3627 entity SetAvoidanceMask(
"avoid none" );
3628 entity.controlLevel = 2;
3630 entity.meleeweapon = rogue_melee_weapon;
3631 entity.dontDropWeapon =
true;
3632 entity.ignorepathenemyfightdist =
true;
3640 if ( entity.health > entity.maxhealth * 0.6 )
3642 entity.health = int( entity.maxhealth * 0.6 );
3654 if ( entity.controlLevel >= 3 )
3660 entity.controlLevel = 3;
3668 entity.miniRaps = value;
3741 case "forced_level_1":
3742 if ( entity.controlLevel <= 0 )
3747 case "forced_level_2":
3748 if ( entity.controlLevel <= 1 )
3759 case "forced_level_3":
3760 if ( entity.controlLevel <= 2 )
3776 entity.ignorepathenemyfightdist =
false;
3779 if ( value !=
"guard" )
3781 entity.guardPosition = undefined;
3789 entity.ignorepathenemyfightdist =
true;
3792 entity.ignorepathenemyfightdist =
true;
3831 if ( value ==
"gib_legs" || value ==
"remove_legs" )
3857 if ( value ==
"gib_legs" )
3870 if ( !IsVec( value ) )
3875 rogueControlled = IsInArray(
array(
"level_2",
"level_3" ),
3878 if ( !rogueControlled )
3884 entity.favoriteenemy = undefined;
3912 entity.manualTraverseMode =
false;
3915 entity.manualTraverseMode =
true;