4 #using scripts\codescripts\struct;
6 #using scripts\shared\gameskill_shared;
7 #using scripts\shared\math_shared;
8 #using scripts\shared\statemachine_shared;
9 #using scripts\shared\system_shared;
10 #using scripts\shared\array_shared;
11 #using scripts\shared\util_shared;
13 #using scripts\shared\vehicle_shared;
14 #using scripts\shared\vehicle_death_shared;
15 #using scripts\shared\vehicle_ai_shared;
17 #using scripts\shared\ai\systems\blackboard;
18 #using scripts\shared\ai\blackboard_vehicle;
20 #using scripts\shared\turret_shared;
21 #using scripts\shared\weapons\_spike_charge_siegebot;
22 #insert scripts\shared\shared.gsh;
23 #insert scripts\shared\statemachine.gsh;
24 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
26 #insert scripts\shared\ai\utility.gsh;
28 #define JUMP_COOLDOWN 7
29 #define DEBUG_ON false
35 #using_animtree( "generic" );
44 self useanimtree( #animtree );
49 self.health =
self.healthdefault;
53 Target_Set(
self, ( 0, 0, 84 ) );
55 self EnableAimAssist();
56 self SetNearGoalNotifyDist( 40 );
59 self.fovcosinebusy = 0.5;
60 self.maxsightdistsqrd =
SQR( 10000 );
62 assert( isdefined(
self.scriptbundlesettings ) );
66 self.goalRadius = 9999999;
67 self.goalHeight = 5000;
68 self SetGoal(
self.origin,
false,
self.goalRadius,
self.goalHeight );
74 self SetGunnerTurretOnTargetRange( 0,
self.settings.gunner_turret_on_target_range );
76 self ASMRequestSubstate(
"locomotion@movement" );
78 if(
self.vehicletype ===
"spawner_enemy_boss_siegebot_zombietron" )
80 self ASMSetAnimationRate( 0.5 );
81 self HidePart(
"tag_turret_canopy_animate" );
82 self HidePart(
"tag_turret_panel_01_d0" );
83 self HidePart(
"tag_turret_panel_02_d0" );
84 self HidePart(
"tag_turret_panel_03_d0" );
85 self HidePart(
"tag_turret_panel_04_d0" );
86 self HidePart(
"tag_turret_panel_05_d0" );
88 else if(
self.vehicletype ==
"zombietron_veh_siegebot" )
90 self ASMSetAnimationRate( 1.429 );
96 if( IsDefined( level.vehicle_initializer_cb ) )
98 [[level.vehicle_initializer_cb]]( self );
101 self.ignoreFireFly =
true;
102 self.ignoreDecoy =
true;
107 if( !SessionModeIsMultiplayerGame() )
116 scale_up = mapfloat( 0, 9, 0.8, 2.0, value );
117 scale_down = mapfloat( 0, 9, 1.0, 0.5, value );
119 self.difficulty_scale_up = scale_up;
120 self.difficulty_scale_down = scale_down;
163 self endon(
"death" );
164 self endon(
"nodeath_thread" );
167 StreamerModelHint(
self.deathmodel, 6 );
170 if ( !isdefined( death_type ) )
172 params.death_type =
"gibbed";
173 death_type = params.death_type;
178 self SetTurretSpinning(
false );
182 self playsound(
"veh_quadtank_sparks");
184 if (
self.vehicletype ===
"spawner_enemy_boss_siegebot_zombietron" )
186 self ASMSetAnimationRate( 1.0 );
189 self.turretRotScale = 3;
190 self SetTurretTargetRelativeAngles( (0,0,0), 0 );
191 self SetTurretTargetRelativeAngles( (0,0,0), 1 );
192 self SetTurretTargetRelativeAngles( (0,0,0), 2 );
194 self ASMRequestSubstate(
"death@stationary" );
196 self waittill(
"model_swap" );
201 self waittill(
"bodyfall large" );
204 self RadiusDamage(
self.origin + (0,0,10),
self.radius * 0.8, 150, 60,
self,
"MOD_CRUSH" );
222 self ClearTargetEntity();
224 self ClearVehGoalPos();
229 self endon(
"death" );
230 self endon(
"exit_vehicle" );
236 selfup = AnglesToUp(
self.angles );
237 worldup = ( 0, 0, 1 );
239 if ( VectorDot( selfup, worldup ) < 0.64 )
248 if ( tileCount > 20 )
250 driver =
self GetSeatOccupant( 0 );
251 self Kill(
self.origin );
260 self endon(
"death" );
261 self endon(
"exit_vehicle" );
263 weapon =
self SeatGetWeapon( 2 );
264 fireTime = weapon.fireTime;
265 driver =
self GetSeatOccupant( 0 );
271 if( driver attackButtonPressed() )
273 self FireWeapon( 2 );
285 self endon(
"death" );
286 self endon(
"exit_vehicle" );
290 self SetGunnerTargetVec(
self GetGunnerTargetVec( 0 ), 1 );
301 if ( !isdefined(
self.abnormal_status ) )
303 self.abnormal_status = spawnStruct();
306 self.abnormal_status.emped =
true;
307 self.abnormal_status.attacker = params.notify_param[1];
308 self.abnormal_status.inflictor = params.notify_param[2];
315 self endon(
"death" );
316 self endon(
"change_state" );
320 if (
self.vehicletype ===
"spawner_enemy_boss_siegebot_zombietron" )
322 self ASMSetAnimationRate( 1.0 );
325 asmState =
"damage_2@pain";
326 self ASMRequestSubstate( asmState );
349 self._enablePain = enabled;
354 self endon(
"death" );
355 self endon(
"change_state" );
359 if (
self.vehicletype ===
"spawner_enemy_boss_siegebot_zombietron" )
361 self ASMSetAnimationRate( 1.0 );
364 if (
self.newDamageLevel == 3 )
366 asmState =
"damage_2@pain";
370 asmState =
"damage_1@pain";
373 self ASMRequestSubstate( asmState );
387 self endon(
"death" );
388 self endon(
"change_state" );
390 self SetTurretTargetRelativeAngles( (0,90,0), 1 );
391 self SetTurretTargetRelativeAngles( (0,90,0), 2 );
404 self endon(
"death" );
405 self endon(
"change_state" );
406 self notify(
"end_movement_thread" );
407 self endon(
"end_movement_thread" );
413 foundpath =
self SetVehGoalPos(
self.current_pathto_pos,
false,
true );
420 self notify(
"near_goal" );
422 self ClearVehGoalPos();
437 if(
self.goalforced )
442 minSearchRadius = 500;
443 maxSearchRadius = 1500;
447 queryResult = PositionQuery_Source_Navigation(
self.origin, minSearchRadius, maxSearchRadius, halfHeight, spacing,
self, spacing );
448 PositionQuery_Filter_DistanceToGoal( queryResult,
self );
451 forward = AnglesToForward(
self.angles );
452 foreach ( point
in queryResult.data )
454 ADD_POINT_SCORE( point,
"random", randomFloatRange( 0, 30 ) );
456 pointDirection = VectorNormalize( point.origin -
self.origin );
457 factor = VectorDot( pointDirection, forward );
460 ADD_POINT_SCORE( point,
"directionDiff", 600 );
462 else if ( factor > 0 )
464 ADD_POINT_SCORE( point,
"directionDiff", 0 );
466 else if ( factor > -0.5 )
468 ADD_POINT_SCORE( point,
"directionDiff", -600 );
472 ADD_POINT_SCORE( point,
"directionDiff", -1200 );
479 if( queryResult.data.size == 0 )
482 return queryResult.data[0].origin;
490 if ( isdefined(
self.jump ) && isDefined(
self.jump.linkEnt) )
492 self.jump.linkEnt Delete();
498 entToWatch waittill(
"death");
505 if ( isdefined(
self.jump ) )
508 self.jump.linkEnt Delete();
512 self.jump = spawnstruct();
513 self.jump.linkEnt =
Spawn(
"script_origin",
self.origin );
515 self.jump.in_air =
false;
528 return (
self.vehicletype ===
"spawner_enemy_boss_siegebot_zombietron" );
533 goal = params.jumpgoal;
535 trace = PhysicsTrace( goal + ( 0, 0, 500 ), goal - ( 0, 0, 10000 ), ( -10, -10, -10 ), ( 10, 10, 10 ),
self,
PHYSICS_TRACE_MASK_VEHICLE );
538 /#debugstar( goal, 60000, (0,1,0) ); #/
539 /#debugstar(
trace[
"position" ], 60000, (0,1,0) ); #/
540 /#line(goal,
trace[
"position" ], (0,1,0), 1,
false, 60000 ); #/
542 if (
trace[
"fraction" ] < 1 )
544 goal =
trace[
"position" ];
547 self.jump.goal = goal;
549 params.scaleForward = 40;
550 params.gravityForce = (0, 0, -6);
551 params.upByHeight = 50;
552 params.landingState =
"land@jump";
561 self endon(
"change_state" );
562 self endon(
"death" );
564 goal =
self.jump.goal;
568 self.jump.linkEnt.origin =
self.origin;
569 self.jump.linkEnt.angles =
self.angles;
573 self LinkTo(
self.jump.linkEnt );
575 self.jump.in_air =
true;
579 /#debugstar( goal, 60000, (0,1,0) ); #/
580 /#debugstar( goal + (0,0,100), 60000, (0,1,0) ); #/
581 /#line(goal, goal + (0,0,100), (0,1,0), 1,
false, 60000 ); #/
585 totalDistance = Distance2D(goal,
self.jump.linkEnt.origin);
586 forward =
FLAT_ORIGIN( ((goal -
self.jump.linkEnt.origin) / totalDistance) );
587 upByDistance = MapFloat( 500, 2000, 46, 52, totalDistance );
588 antiGravityByDistance = 0;
590 initVelocityUp = (0,0,1) * ( upByDistance + params.upByHeight );
591 initVelocityForward = forward * params.scaleForward * MapFloat( 500, 2000, 0.8, 1, totalDistance );
592 velocity = initVelocityUp + initVelocityForward;
595 if (
self.vehicletype ===
"spawner_enemy_boss_siegebot_zombietron" )
597 self ASMSetAnimationRate( 1.0 );
600 self ASMRequestSubstate(
"inair@jump" );
601 self waittill(
"engine_startup" );
603 self waittill(
"leave_ground" );
608 distanceToGoal = Distance2D(
self.jump.linkEnt.origin, goal);
610 antiGravityScaleUp = 1.0;
611 antiGravityScale = 1.0;
612 antiGravity = (0,0,0);
613 if (
DEBUG_ON ) /#line(
self.jump.linkEnt.origin,
self.jump.linkEnt.origin + antiGravity, (0,1,0), 1,
false, 60000 ); #/
615 velocityForwardScale = MapFloat( (
self.radius * 1), (
self.radius * 4), 0.2, 1, distanceToGoal );
616 velocityForward = initVelocityForward * velocityForwardScale;
617 if (
DEBUG_ON ) /#line(
self.jump.linkEnt.origin,
self.jump.linkEnt.origin + velocityForward, (0,1,0), 1,
false, 60000 ); #/
619 oldVerticleSpeed = velocity[2];
620 velocity = (0,0, velocity[2]);
621 velocity += velocityForward + params.gravityForce + antiGravity;
623 if ( oldVerticleSpeed > 0 && velocity[2] < 0 )
625 self ASMRequestSubstate(
"fall@jump" );
628 if ( velocity[2] < 0 &&
self.jump.linkEnt.origin[2] + velocity[2] < goal[2] )
633 heightThreshold = goal[2] + 110;
634 oldHeight =
self.jump.linkEnt.origin[2];
635 self.jump.linkEnt.origin += velocity;
637 if (
self.jump.linkEnt.origin[2] < heightThreshold && ( oldHeight > heightThreshold || ( oldVerticleSpeed > 0 && velocity[2] < 0 ) ) )
639 self notify(
"start_landing" );
640 self ASMRequestSubstate( params.landingState );
643 if (
DEBUG_ON ) /#debugstar(
self.jump.linkEnt.origin, 60000, (1,0,0) ); #/
648 self.jump.linkEnt.origin =
FLAT_ORIGIN(
self.jump.linkEnt.origin ) + ( 0, 0, goal[2] );
649 self notify(
"land_crush" );
652 foreach( player
in level.players )
654 player._takedamage_old = player.takedamage;
655 player.takedamage =
false;
657 self RadiusDamage(
self.origin + ( 0,0,15 ),
self.radiusdamageradius,
self.radiusdamagemax,
self.radiusdamagemin,
self,
"MOD_EXPLOSIVE" );
659 foreach( player
in level.players )
661 player.takedamage = player._takedamage_old;
662 player._takedamage_old = undefined;
664 if ( Distance2DSquared(
self.origin, player.origin ) <
SQR( 200 ) )
666 direction =
FLAT_ORIGIN( ( player.origin -
self.origin ) );
667 if ( Abs( direction[0] ) < 0.01 && Abs( direction[1] ) < 0.01 )
669 direction = ( RandomFloatRange( 1, 2 ), RandomFloatRange( 1, 2 ), 0 );
671 direction = VectorNormalize( direction );
673 player SetVelocity( player GetVelocity() + direction * strength );
675 if ( player.health > 80 )
677 player DoDamage( player.health - 70,
self.origin,
self );
694 self.jump.in_air =
false;
696 self notify (
"jump_finished" );
714 self endon(
"death" );
715 self endon(
"change_state" );
724 self ClearTurretTarget();
725 self SetTurretSpinning(
false );
730 if(
self.vehicletype ===
"spawner_enemy_boss_siegebot_zombietron" )
732 self ASMSetAnimationRate( 0.5 );
735 self ASMRequestSubstate(
"locomotion@movement" );
740 if(
self.goalforced )
745 maxSearchRadius = 800;
750 queryResult = PositionQuery_Source_Navigation(
self.origin, 0, maxSearchRadius, halfHeight, innerSpacing,
self, outerSpacing );
751 PositionQuery_Filter_DistanceToGoal( queryResult,
self );
754 if( isdefined(
self.enemy ) )
756 PositionQuery_Filter_Sight( queryResult,
self.enemy.origin,
self GetEye() -
self.origin,
self, 0,
self.enemy );
760 foreach ( point
in queryResult.data )
762 ADD_POINT_SCORE( point,
"random", randomFloatRange( 0, 30 ) );
764 if( point.disttoorigin2d < 120 )
766 ADD_POINT_SCORE( point,
"tooCloseToSelf", (120 - point.disttoorigin2d) * -1.5 );
769 if( isdefined(
self.enemy ) )
771 ADD_POINT_SCORE( point,
"engagementDist", -point.distAwayFromEngagementArea );
773 if ( !point.visibility )
775 ADD_POINT_SCORE( point,
"visibility", -600 );
783 if( queryResult.data.size == 0 )
786 return queryResult.data[0].origin;
791 self endon(
"death" );
792 self endon(
"change_state" );
793 self endon(
"near_goal" );
794 self endon(
"reached_end_node" );
796 canSeeEnemyCount = 0;
798 old_enemy =
self.enemy;
800 startPath = GetTime();
801 old_origin =
self.origin;
808 self SetMaxSpeedScale( 1 );
809 self SetMaxAccelerationScale( 1 );
810 self SetSpeed(
self.settings.defaultMoveSpeed );
812 if ( isdefined(
self.enemy ) )
814 selfDistToTarget = Distance2D(
self.origin,
self.enemy.origin );
816 farEngagementDist =
self.settings.engagementDistMax + 150;
817 closeEngagementDist =
self.settings.engagementDistMin - 150;
819 if(
self VehCanSee(
self.enemy ) )
821 self SetLookAtEnt(
self.enemy );
822 self SetTurretTargetEnt(
self.enemy );
825 if( selfDistToTarget < farEngagementDist && selfDistToTarget > closeEngagementDist )
830 if( canSeeEnemyCount > 3 && (
vehicle_ai::TimeSince( startPath ) > 5 || Distance2DSquared( old_origin,
self.origin ) >
SQR( move_dist ) ) )
832 self notify(
"near_goal" );
838 self SetMaxSpeedScale( 2.5 );
839 self SetMaxAccelerationScale( 3 );
840 self SetSpeed(
self.settings.defaultMoveSpeed * 2 );
843 else if( (!
self VehSeenRecently(
self.enemy, 1.5 ) &&
self VehSeenRecently(
self.enemy, 15 )) || selfDistToTarget > farEngagementDist )
845 self SetMaxSpeedScale( 1.8 );
846 self SetMaxAccelerationScale( 2 );
847 self SetSpeed(
self.settings.defaultMoveSpeed * 1.5 );
852 canSeeEnemyCount = 0;
855 if ( isdefined(
self.enemy ) )
857 if( !isdefined( old_enemy ) )
859 self notify(
"near_goal" );
861 else if(
self.enemy != old_enemy )
863 self notify(
"near_goal" );
866 if(
self VehCanSee(
self.enemy ) && distance2dSquared(
self.origin,
self.enemy.origin ) <
SQR( 150 ) && Distance2DSquared( old_origin,
self.enemy.origin ) >
SQR( 151 ) )
868 self notify(
"near_goal" );
878 self endon(
"death" );
879 self notify(
"weapon_doors_state" );
880 self endon(
"weapon_doors_state" );
882 if ( isdefined( waittime ) && waittime > 0 )
892 self endon(
"death" );
893 self endon(
"change_state" );
894 self notify(
"end_movement_thread" );
895 self endon(
"end_movement_thread" );
901 if(
self.vehicletype ===
"spawner_enemy_boss_siegebot_zombietron" )
905 params = SpawnStruct();
906 params.jumpgoal =
self.current_pathto_pos;
914 foundpath =
self SetVehGoalPos(
self.current_pathto_pos,
false,
true );
918 if ( isdefined(
self.enemy ) &&
self VehSeenRecently(
self.enemy, 1 ) )
920 self SetLookAtEnt(
self.enemy );
921 self SetTurretTargetEnt(
self.enemy );
926 self notify(
"near_goal" );
928 self ClearVehGoalPos();
929 if ( isdefined(
self.enemy ) &&
self VehSeenRecently(
self.enemy, 2 ) )
937 startAdditionalWaiting = GetTime();
938 while ( isdefined(
self.enemy ) &&
self VehCanSee(
self.enemy ) &&
vehicle_ai::TimeSince( startAdditionalWaiting ) < 1.5 )
947 self notify(
"end_movement_thread" );
948 self notify(
"near_goal" );
950 self ClearVehGoalPos();
951 self ClearTurretTarget();
952 self ClearLookAtEnt();
958 if ( !isdefined( targetAngleDiff ) )
960 targetAngleDiff = 30;
964 v_to_enemy = VectorNormalize( v_to_enemy );
965 goalAngles = VectortoAngles( v_to_enemy );
967 angleDiff = AbsAngleClamp180(
self.angles[1] - goalAngles[1] );
968 if ( angleDiff <= targetAngleDiff )
973 self SetLookAtOrigin( position );
974 self SetTurretTargetVec( position );
977 angleAdjustingStart = GetTime();
980 angleDiff = AbsAngleClamp180(
self.angles[1] - goalAngles[1] );
984 self ClearVehGoalPos();
985 self ClearLookAtEnt();
986 self ClearTurretTarget();
992 angles =
self GetTagAngles(
"tag_barrel" );
993 angles = (0,angles[1],0);
1001 forward = AnglesToForward( angles );
1003 aimpos =
self.origin + forward * 1000;
1004 self SetTurretTargetVec( aimpos );
1008 if( isdefined(
self.enemy ) &&
self VehCanSee(
self.enemy ) )
1010 self SetTurretTargetEnt(
self.enemy );
1011 self SetLookAtEnt(
self.enemy );
1018 forward = AnglesToForward(
self.angles );
1020 aimpos =
self.origin + forward * 1000;
1021 self SetTurretTargetVec( aimpos );
1023 self ClearTurretTarget();
1028 self endon(
"death" );
1029 self endon(
"change_state" );
1030 self endon(
"end_attack_thread" );
1031 self notify(
"end_machinegun_attack_thread" );
1032 self endon(
"end_machinegun_attack_thread" );
1034 self.turretrotscale = 1 *
self.difficulty_scale_up;
1040 if( isdefined(
self.enemy ) &&
self VehCanSee(
self.enemy ) )
1042 self SetLookAtEnt(
self.enemy );
1043 self SetTurretTargetEnt(
self.enemy );
1048 self SetTurretSpinning(
true );
1053 self SetGunnerTargetEnt(
self.enemy, (0,0,0), 0 );
1054 self SetGunnerTargetEnt(
self.enemy, (0,0,0), 1 );
1058 if( isdefined(
self.enemy ) && IsAI(
self.enemy ) )
1060 wait( RandomFloatRange( 0.1, 0.2 ) );
1064 wait( RandomFloatRange( 0.2, 0.3 ) ) *
self.difficulty_scale_down;
1070 self SetTurretSpinning(
false );
1071 self ClearGunnerTarget( 0 );
1072 self ClearGunnerTarget( 1 );
1080 if ( isdefined( target ) )
1082 self SetTurretTargetEnt( target );
1083 self SetGunnerTargetEnt( target, (0,0,-10), 2 );
1085 self FireWeapon( 2, target, (0,0,-10) );
1086 self ClearGunnerTarget( 1 );
1092 self endon(
"death" );
1093 self endon(
"change_state" );
1094 self endon(
"end_attack_thread" );
1095 self notify(
"end_rocket_attack_thread" );
1096 self endon(
"end_rocket_attack_thread" );
1104 self SetGunnerTargetEnt(
self.enemy, (0,0,0), 0 );
1105 self SetGunnerTargetEnt(
self.enemy, (0,0,-10), 2 );
1109 if ( isdefined(
self.enemy ) &&
self VehSeenRecently(
self.enemy, 1 ) )
1114 if ( isdefined(
self.enemy ) )
1127 self ClearGunnerTarget( 0 );
1128 self ClearGunnerTarget( 1 );
1134 function siegebot_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
1136 num_players = GetPlayers().size;
1137 maxDamage =
self.healthdefault * ( 0.40 - 0.02 * num_players );
1138 if ( sMeansOfDeath !==
"MOD_UNKNOWN" && iDamage > maxDamage )
1140 iDamage = maxDamage;
1145 minEmpDownTime = 0.8 *
self.settings.empdowntime;
1146 maxEmpDownTime = 1.2 *
self.settings.empdowntime;
1147 self notify (
"emped", RandomFloatRange( minEmpDownTime, maxEmpDownTime ), eAttacker, eInflictor );
1150 if ( !isdefined(
self.damageLevel ) )
1152 self.damageLevel = 0;
1153 self.newDamageLevel =
self.damageLevel;
1157 if ( newDamageLevel >
self.damageLevel )
1159 self.newDamageLevel = newDamageLevel;
1162 if (
self.newDamageLevel >
self.damageLevel )
1164 self.damageLevel =
self.newDamageLevel;
1166 driver =
self GetSeatOccupant( 0 );
1167 if ( !isdefined( driver ) )
1169 self notify(
"pain" );