1 #using scripts\codescripts\struct;
3 #using scripts\shared\ai_shared;
4 #using scripts\shared\ai_puppeteer_shared;
5 #using scripts\shared\callbacks_shared;
6 #using scripts\shared\challenges_shared;
7 #using scripts\shared\clientfield_shared;
8 #using scripts\shared\flagsys_shared;
9 #using scripts\shared\killstreaks_shared;
10 #using scripts\shared\objpoints_shared;
11 #using scripts\shared\scoreevents_shared;
12 #using scripts\shared\ai\archetype_utility;
13 #using scripts\shared\ai\systems\gib;
14 #using scripts\shared\entityheadicons_shared;
15 #using scripts\shared\util_shared;
16 #using scripts\shared\vehicleriders_shared;
17 #using scripts\shared\weapons\_heatseekingmissile;
18 #using scripts\shared\ai\systems\blackboard;
20 #using scripts\mp\_challenges;
21 #using scripts\mp\gametypes\_globallogic_audio;
22 #using scripts\mp\killstreaks\_killstreak_bundles;
23 #using scripts\mp\killstreaks\_killstreak_detect;
24 #using scripts\mp\killstreaks\_killstreak_hacking;
25 #using scripts\mp\killstreaks\_killstreakrules;
26 #using scripts\mp\killstreaks\_killstreaks;
27 #using scripts\mp\killstreaks\_supplydrop;
29 #insert scripts\mp\_hacker_tool.gsh;
30 #insert scripts\mp\killstreaks\_killstreaks.gsh;
31 #insert scripts\mp\killstreaks\_remote_weapons.gsh;
32 #insert scripts\shared\shared.gsh;
33 #insert scripts\shared\ai\archetype_damage_effects.gsh;
34 #insert scripts\shared\ai\archetype_robot.gsh;
35 #insert scripts\shared\ai\systems\blackboard.gsh;
36 #insert scripts\shared\ai\systems\gib.gsh;
38 #namespace combat_robot;
40 #define COMBAT_ROBOT_FORWARD_SPAWN_OFFSET 72
41 #define COMBAT_ROBOT_GUARD_RADIUS 1000
42 #define COMBAT_ROBOT_DEFEND_ICON "t7_hud_ks_c54i_drop"
43 #define COMBAT_ROBOT_NAME "combat_robot"
44 #define COMBAT_ROBOT_INFLUENCER "small_vehicle"
45 #define COMBAT_ROBOT_MARKER_NAME "combat_robot_marker"
46 #define INVENTORY_COMBAT_ROBOT_NAME "inventory_combat_robot"
49 #define COMBAT_ROBOT_VELOCITY_SCALAR ( 1 / 8 ) // Scales the initial velocity
50 #define COMBAT_ROBOT_ADD_X_VELOCITY_MIN -20
51 #define COMBAT_ROBOT_ADD_X_VELOCITY_MAX 20
52 #define COMBAT_ROBOT_ADD_Y_VELOCITY_MIN -20
53 #define COMBAT_ROBOT_ADD_Y_VELOCITY_MAX 20
54 #define COMBAT_ROBOT_ADD_Z_VELOCITY_MIN 60
55 #define COMBAT_ROBOT_ADD_Z_VELOCITY_MAX 80
58 #define COMBAT_ROBOT_MIN_SHUTDOWN 3.0
59 #define COMBAT_ROBOT_MAX_SHUTDOWN 4.5
62 #define COMBAT_ROBOT_GIVE_UP_ON_ENEMY 10000
65 #define COMBAT_ROBOT_IGNORE_UNATTACKABLE_ENEMY 5000
67 #define COMBAT_ROBOT_NAV_MESH_VALID_LOCATION_BOUNDARY 18
68 #define COMBAT_ROBOT_NAV_MESH_VALID_LOCATION_TOLERANCE 4
70 #define COMBAT_ROBOT_KILLCAM_TIME_OFFSET ( 750 )
72 #precache( "string", "KILLSTREAK_COMBAT_ROBOT_ESCORT_HINT" );
73 #precache( "string", "KILLSTREAK_COMBAT_ROBOT_GUARD_HINT" );
74 #precache( "string", "KILLSTREAK_COMBAT_ROBOT_INBOUND" );
75 #precache( "string", "KILLSTREAK_COMBAT_ROBOT_NOT_AVAILABLE" );
76 #precache( "string", "KILLSTREAK_COMBAT_ROBOT_HACKED" );
77 #precache( "string", "KILLSTREAK_COMBAT_ROBOT_PATROL_FAIL" );
78 #precache( "string", "KILLSTREAK_DESTROYED_COMBAT_ROBOT" );
79 #precache( "triggerstring", "KILLSTREAK_COMBAT_ROBOT_ESCORT_HINT" );
80 #precache( "triggerstring", "KILLSTREAK_COMBAT_ROBOT_GUARD_HINT" );
82 #precache( "material", COMBAT_ROBOT_DEFEND_ICON );
89 killstreaks::register_dialog(
COMBAT_ROBOT_NAME,
"mpl_killstreak_combat_robot",
"combatRobotDialogBundle",
"combatRobotPilotDialogBundle",
"friendlyCombatRobot",
"enemyCombatRobot",
"enemyCombatRobotMultiple",
"friendlyCombatRobotHacked",
"enemyCombatRobotHacked",
"requestCombatRobot",
"threatCombatRobot" );
101 return GetClosestPointOnNavMesh( player.origin, 48 );
106 desiredSpawnPosition = AnglesToForward( player.angles ) *
109 return GetClosestPointOnNavMesh( desiredSpawnPosition, 48 );
114 corpseDeleteTime = 15000;
120 foreach ( corpse
in GetCorpseArray() )
122 if ( IsDefined( corpse.birthtime ) &&
123 IsDefined( corpse.archetype ) &&
124 corpse.archetype ==
"robot" &&
125 ( corpse.birthtime + corpseDeleteTime ) < GetTime() )
127 deleteCorpses[ deleteCorpses.size ] = corpse;
131 for ( index = 0; index < deleteCorpses.size; index++ )
133 deleteCorpses[ index ] Delete();
136 wait ( corpseDeleteTime / 1000 ) / 2;
143 robot.properName =
"";
145 robot.ignoreTriggerDamage =
true;
148 robot.minWalkDistance = 60;
149 robot.superSprintDistance = 180;
150 robot.robotRusherMinRadius = 64;
151 robot.robotRusherMaxRadius = 120;
152 robot.allowPushActors =
false;
153 robot.chargeMeleeDistance = 0;
155 robot.fovcosinebusy = 0;
156 robot.MaxSightDistSqrd =
SQR( 2000 );
185 if ( !isdefined( robot.objective ) )
187 robot.objective = GetEquipmentHeadObjective( GetWeapon(
"combat_robot_marker" ) );
198 guardMarker =
spawn(
"script_model", ( 0, 0, 0 ) );
199 guardMarker.origin = position;
207 if ( isdefined( robot.guardMarker ) )
209 robot.guardMarker
delete();
215 robot endon(
"death" );
219 if ( ( robot.origin[2] +
ROBOT_HEIGHT / 2.0 ) <= GetWaterHeight( robot.origin ) )
221 robot ASMSetAnimationRate( 0.85 );
225 robot ASMSetAnimationRate( 1.0 );
234 robot endon(
"death" );
236 robot.escorting =
true;
237 robot.guarding =
false;
241 while ( robot.escorting )
243 attackingEnemy =
false;
245 if ( IsDefined( robot.enemy ) && IsAlive( robot.enemy ) )
251 attackingEnemy =
true;
259 if ( !attackingEnemy && IsDefined( robot.owner ) && IsAlive( robot.owner ) )
263 robot.owner.origin + VectorScale( robot.owner GetVelocity(), lookAheadTime );
275 robot endon(
"death" );
277 robot SetIgnoreEnt( enemy,
true );
281 robot SetIgnoreEnt( enemy,
false );
286 robot endon(
"death" );
289 robot SetGoal( position );
291 robot.escorting =
false;
292 robot.guarding =
true;
298 while ( robot.guarding )
300 attackingEnemy =
false;
302 if ( IsDefined( robot.enemy ) && IsAlive( robot.enemy ) )
309 attackingEnemy =
true;
317 if ( !attackingEnemy )
328 robot endon(
"death" );
330 nextSwitchTime = GetTime();
336 if( !isdefined( robot.useTrigger ) )
339 robot.useTrigger waittill(
"trigger" );
341 if ( nextSwitchTime <= GetTime() && IsAlive( player ) )
345 robot.guarding =
false;
346 robot.escorting =
true;
348 player playsoundtoplayer(
"uin_mp_combat_bot_escort", player );
350 if( isdefined( robot.useTrigger ) )
351 robot.useTrigger SetHintString( &
"KILLSTREAK_COMBAT_ROBOT_GUARD_HINT" );
353 if( isdefined( robot.markerFXHandle ) )
354 robot.markerFXHandle
delete();
360 if ( IsDefined( navGuardPosition ) )
362 robot.guarding =
true;
363 robot.escorting =
false;
365 player playsoundtoplayer(
"uin_mp_combat_bot_guard", player );
367 if( isdefined( robot.useTrigger ) )
368 robot.useTrigger SetHintString( &
"KILLSTREAK_COMBAT_ROBOT_ESCORT_HINT" );
370 if( isdefined( robot.markerFXHandle ) )
371 robot.markerFXHandle
delete();
374 if( isdefined( params.ksCombatRobotPatrolFX ) )
376 point = player.origin;
377 if( !isdefined( point ) )
378 point = navGuardPosition;
380 robot.markerFXHandle = SpawnFx( params.ksCombatRobotPatrolFX, point + ( 0, 0, 3 ), ( 0, 0, 1 ), ( 1, 0, 0 ) );
381 robot.markerFXHandle.team = player.team;
382 TriggerFX( robot.markerFXHandle );
384 robot.markerFXHandle SetInvisibleToAll();
385 robot.markerFXHandle SetVisibleToPlayer( player );
390 player iPrintLnBold( &
"KILLSTREAK_COMBAT_ROBOT_PATROL_FAIL" );
394 robot notify(
"bhtn_action_notify",
"modeSwap");
396 nextSwitchTime = GetTime() + 1000;
412 if ( killstreak_id == -1 )
417 context = SpawnStruct();
421 context.hasFlares = 1;
422 context.radius = level.killstreakCoreBundle.ksAirdropRobotRadius;
425 context.perform_physics_trace =
true;
426 context.drop_from_goal_distance2d = 96;
428 context.objective = &
"airdrop_combatrobot";
429 context.killstreakRef = killstreak;
430 context.validLocationSound = level.killstreakCoreBundle.ksValidCombatRobotLocationSound;
431 context.vehiclename =
"combat_robot_dropship";
432 context.killstreak_id = killstreak_id;
436 context.dropOffset = (0, -120, 0);
458 robot endon(
"death" );
459 robot endon(
"combat_robot_land" );
472 helicopter waittill(
"death" );
476 if( isdefined( context.marker ) )
478 context.marker
delete();
479 context.marker = undefined;
481 if( isdefined( context.markerFXHandle ) )
483 context.markerFXHandle
delete();
484 context.markerFXHandle = undefined;
493 player = helicopter.owner;
495 spawnPosition = ( 0,0,0 );
496 spawnAngles = ( 0,0,0 );
498 combatRobot = SpawnActor(
499 "spawner_bo3_robot_grunt_assault_mp",
504 combatRobot.missileTrackDamage = 0;
507 combatRobot thread
_Escort( combatRobot );
516 helicopter.unloadTimeout = 6;
520 combatRobot.maxhealth = combatRobot.health;
524 if ( isdefined( tableHealth ) )
526 combatRobot.maxhealth = tableHealth;
529 combatRobot.health = combatRobot.maxhealth;
530 combatRobot.treat_owner_damage_as_friendly_fire =
true;
531 combatRobot.ignore_team_kills =
true;
532 combatRobot.remoteMissileDamage = combatRobot.maxhealth + 1;
533 combatRobot.rocketDamage = combatRobot.maxhealth / 2 + 1;
536 combatRobot.soundmod =
"drone_land";
540 combatRobot.vehicle = helicopter;
541 combatRobot.vehicle.ignore_seat_check =
true;
544 combatRobot.overrideDropPosition = player.markerPosition;
551 foreach( player
in level.players )
557 context.robot = combatRobot;
563 combatRobot setignoreent( player, player hasperk(
"specialty_nottargetedbyrobot" ) );
583 if ( isdefined(
self ) )
585 self.delete_after_destruction_wait_time = delete_after_destruction_wait_time;
600 robot endon(
"death" );
601 robot endon(
"killstreak_hacked" );
602 robot endon(
"combat_robot_land" );
604 helicopter endon(
"death" );
606 helicopter waittill(
"killstreak_hacked", hacker );
611 robot [[ robot.killstreak_hackedCallback ]]( hacker );
616 robot = context.robot;
617 while( isdefined( robot ) && isdefined( context.marker ) && ( robot
flagsys::get(
"in_vehicle" ) ) )
621 if( isdefined( context.marker ) )
623 context.marker
delete();
624 context.marker = undefined;
626 if( isdefined( context.markerFXHandle ) )
628 context.markerFXHandle
delete();
629 context.markerFXHandle = undefined;
638 combatRobot endon(
"combat_robot_shutdown" );
640 combatRobot waittill(
"death", attacker, damageFromUnderneath, weapon );
643 attacker =
self [[ level.figure_out_attacker ]]( attacker );
645 if ( isdefined( attacker ) && IsPlayer( attacker ) && ( !isdefined( combatRobot.owner ) || combatRobot.owner
util::IsEnemyPlayer( attacker ) ) )
650 LUINotifyEvent( &
"player_callout", 2, &
"KILLSTREAK_DESTROYED_COMBAT_ROBOT", attacker.entnum );
655 combatRobot notify(
"combat_robot_shutdown" );
661 robot endon(
"death" );
662 robot endon(
"combat_robot_shutdown" );
670 robot notify(
"combat_robot_land" );
672 robot.ignoreTriggerDamage =
false;
675 while ( isdefined( robot.traverseStartNode ) )
677 robot waittill(
"traverse_end" );
680 v_on_navmesh = GetClosestPointOnNavMesh( robot.origin, 50, 20 );
682 if ( isdefined ( v_on_navmesh ) )
684 player = robot.owner;
690 robot notify(
"combat_robot_shutdown" );
697 if ( isdefined( robot.useTrigger ) )
699 robot.useTrigger
delete();
701 robot.useTrigger =
spawn(
"trigger_radius_use", player.origin, 32, 32 );
702 robot.useTrigger EnableLinkTo();
703 robot.useTrigger LinkTo( player );
704 robot.useTrigger SetHintLowPriority(
true );
705 robot.useTrigger SetCursorHint(
"HINT_NOICON" );
706 robot.useTrigger SetHintString( &
"KILLSTREAK_COMBAT_ROBOT_GUARD_HINT" );
708 robot.useTrigger SetTeamForTrigger( player.team );
709 robot.useTrigger.team = player.team;
711 player ClientClaimTrigger( robot.useTrigger );
712 player.remoteControlTrigger = robot.useTrigger;
713 robot.useTrigger.ClaimedBy = player;
719 combatRobot notify(
"WatchCombatRobotOwnerDisconnect_singleton" );
720 combatRobot endon(
"WatchCombatRobotOwnerDisconnect_singleton" );
721 combatRobot endon(
"combat_robot_shutdown" );
724 combatRobot notify(
"combat_robot_shutdown" );
729 archetype =
self.archetype;
730 self waittill(
"actor_corpse", corpse);
741 if ( RandomInt( 100 ) >= 50 )
751 combatRobot StartRagdoll();
752 combatRobot LaunchRagdoll(
773 if( isdefined( params.ksExplosionFX ) )
775 PlayFXOnTag( params.ksExplosionFX, combatRobot,
"tag_origin" );
777 Target_Remove( combatRobot );
779 DEFAULT( params.ksExplosionOuterRadius, 200 );
780 DEFAULT( params.ksExplosionInnerRadius, 1 );
781 DEFAULT( params.ksExplosionOuterDamage, 25 );
782 DEFAULT( params.ksExplosionInnerDamage, 350 );
783 DEFAULT( params.ksExplosionMagnitude, 1 );
785 PhysicsExplosionSphere( combatRobot.origin,
786 params.ksExplosionOuterRadius,
787 params.ksExplosionInnerRadius,
788 params.ksExplosionMagnitude,
789 params.ksExplosionOuterDamage,
790 params.ksExplosionInnerDamage );
792 if( isdefined( combatRobot.owner ) )
794 RadiusDamage( combatRobot.origin,
795 params.ksExplosionOuterRadius,
796 params.ksExplosionInnerDamage,
797 params.ksExplosionOuterDamage,
802 if( isdefined( params.ksExplosionRumble ) )
803 combatRobot.owner PlayRumbleOnEntity( params.ksExplosionRumble );
808 combatRobot notify(
"combat_robot_shutdown" );
814 combatRobotTeam = combatRobot.originalteam;
815 combatRobotKillstreakId = combatRobot.killstreak_id;
816 combatRobot waittill(
"combat_robot_shutdown" );
818 combatRobot playsound (
"evt_combat_bot_mech_fail_explode");
820 if( isdefined( combatRobot.useTrigger ) )
821 combatRobot.useTrigger
delete();
823 if( isdefined( combatRobot.markerFXHandle ) )
824 combatRobot.markerFXHandle
delete();
830 if( isdefined( combatRobot ) )
832 if( Target_IsTarget( combatRobot ) )
833 Target_Remove( combatRobot );
834 if( !level.gameEnded )
837 combatRobot Unlink();
846 combatRobot endon(
"combat_robot_shutdown" );
847 combatRobot endon(
"death" );
849 combatRobot PlaySoundOnTag(
"vox_robot_chatter",
"j_head" );
853 soundAlias = undefined;
854 combatRobot waittill(
"bhtn_action_notify", notify_string);
856 switch( notify_string )
862 soundAlias =
"vox_robot_chatter";
866 if( isdefined( soundAlias ) )
868 combatRobot PlaySoundOnTag( soundAlias,
"j_head" );
876 combatRobot endon(
"combat_robot_shutdown" );
877 combatRobot endon(
"death" );
879 combatRobot waittill(
"exiting_vehicle" );
881 combatRobot playsound(
"veh_vtol_supply_robot_launch" );
886 combatRobot endon(
"combat_robot_shutdown" );
887 combatRobot endon(
"death" );
889 combatRobot waittill(
"falling", falltime );
891 wait_time = falltime - .5;
896 combatRobot playsound(
"veh_vtol_supply_robot_land" );
901 combatRobot endon(
"combat_robot_shutdown" );
902 combatRobot endon(
"death" );
904 combatRobot waittill(
"landing" );
906 combatRobot playsound(
"veh_vtol_supply_robot_activate" );
909 function combatRobotDamageOverride( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex, modelIndex )
913 if( combatRobot
flagsys::get(
"in_vehicle" ) && ( sMeansOfDeath ==
"MOD_TRIGGER_HURT" ) )
916 iDamage =
killstreaks::OnDamagePerWeapon(
COMBAT_ROBOT_NAME, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon,
self.maxhealth, undefined,
self.maxhealth*0.4, undefined, 0, undefined,
true, 1.0 );
918 combatRobot.missileTrackDamage += iDamage;
920 if ( iDamage > 0 && isdefined( eAttacker ) )
922 if ( isPlayer( eAttacker) )
924 if ( isdefined( combatRobot.owner ) )