boiii-scripts/mp/killstreaks/_combat_robot.gsc
2023-04-13 17:30:38 +02:00

955 lines
39 KiB
Plaintext

#using scripts\codescripts\struct;
#using scripts\shared\ai_shared;
#using scripts\shared\ai_puppeteer_shared;
#using scripts\shared\callbacks_shared;
#using scripts\shared\challenges_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\flagsys_shared;
#using scripts\shared\killstreaks_shared;
#using scripts\shared\objpoints_shared;
#using scripts\shared\scoreevents_shared;
#using scripts\shared\ai\archetype_utility;
#using scripts\shared\ai\systems\gib;
#using scripts\shared\entityheadicons_shared;
#using scripts\shared\util_shared;
#using scripts\shared\vehicleriders_shared;
#using scripts\shared\weapons\_heatseekingmissile;
#using scripts\shared\ai\systems\blackboard;
#using scripts\mp\_challenges;
#using scripts\mp\gametypes\_globallogic_audio;
#using scripts\mp\killstreaks\_killstreak_bundles;
#using scripts\mp\killstreaks\_killstreak_detect;
#using scripts\mp\killstreaks\_killstreak_hacking;
#using scripts\mp\killstreaks\_killstreakrules;
#using scripts\mp\killstreaks\_killstreaks;
#using scripts\mp\killstreaks\_supplydrop;
#namespace combat_robot;
// Tweaks to how the combat robot's body is thrown after exploding
// Scales the initial velocity
// Time in seconds the combat robot will shutdown before exploding.
// The combat robot will give up chasing an enemy if they haven't attacked them for this long.
// The combat robot will ignore unattackable enemies for this long.
#precache( "string", "KILLSTREAK_COMBAT_ROBOT_ESCORT_HINT" );
#precache( "string", "KILLSTREAK_COMBAT_ROBOT_GUARD_HINT" );
#precache( "string", "KILLSTREAK_COMBAT_ROBOT_INBOUND" );
#precache( "string", "KILLSTREAK_COMBAT_ROBOT_NOT_AVAILABLE" );
#precache( "string", "KILLSTREAK_COMBAT_ROBOT_HACKED" );
#precache( "string", "KILLSTREAK_COMBAT_ROBOT_PATROL_FAIL" );
#precache( "string", "KILLSTREAK_DESTROYED_COMBAT_ROBOT" );
#precache( "triggerstring", "KILLSTREAK_COMBAT_ROBOT_ESCORT_HINT" );
#precache( "triggerstring", "KILLSTREAK_COMBAT_ROBOT_GUARD_HINT" );
#precache( "material", "t7_hud_ks_c54i_drop" );
function init()
{
killstreaks::register( "combat_robot", "combat_robot_marker", "killstreak_" + "combat_robot", "combat_robot" + "_used", &ActivateCombatRobot, undefined, true );
killstreaks::register_alt_weapon( "combat_robot", "lmg_light_robot" );
killstreaks::register_strings( "combat_robot", &"KILLSTREAK_COMBAT_ROBOT_EARNED", &"KILLSTREAK_COMBAT_ROBOT_NOT_AVAILABLE", &"KILLSTREAK_COMBAT_ROBOT_INBOUND", undefined, &"KILLSTREAK_COMBAT_ROBOT_HACKED" );
killstreaks::register_dialog( "combat_robot", "mpl_killstreak_combat_robot", "combatRobotDialogBundle", "combatRobotPilotDialogBundle", "friendlyCombatRobot", "enemyCombatRobot", "enemyCombatRobotMultiple", "friendlyCombatRobotHacked", "enemyCombatRobotHacked", "requestCombatRobot", "threatCombatRobot" );
// TODO: Move to killstreak data
level.killstreaks["inventory_combat_robot"].threatOnKill = true;
level.killstreaks["combat_robot"].threatOnKill = true;
level thread _CleanupRobotCorpses();
}
function private _CalculateProjectedGuardPosition( player )
{
// Find the closest navmesh position projected out from the reticle.
//forwardVector = VectorScale( AnglesToForward( player GetPlayerAngles() ), 4000 );
//guardPoint = BulletTrace( player GetEye(), player GetEye() + forwardVector, true, player );
//return GetClosestPointOnNavMesh( guardPoint["position"], 48 );
return GetClosestPointOnNavMesh( player.origin, 48 );
}
function private _CalculateRobotSpawnPosition( player )
{
desiredSpawnPosition = AnglesToForward( player.angles ) *
72 + player.origin;
return GetClosestPointOnNavMesh( desiredSpawnPosition, 48 );
}
function private _CleanupRobotCorpses()
{
corpseDeleteTime = 15000;
while ( true )
{
deleteCorpses = [];
foreach ( corpse in GetCorpseArray() )
{
if ( IsDefined( corpse.birthtime ) &&
IsDefined( corpse.archetype ) &&
corpse.archetype == "robot" &&
( corpse.birthtime + corpseDeleteTime ) < GetTime() )
{
deleteCorpses[ deleteCorpses.size ] = corpse;
}
}
for ( index = 0; index < deleteCorpses.size; index++ )
{
deleteCorpses[ index ] Delete();
}
wait ( corpseDeleteTime / 1000 ) / 2;
}
}
function ConfigureTeamPost( player, isHacked )
{
robot = self;
robot.properName = "";
// Prevent the robot from being damaged based on a hurt trigger when being called in.
robot.ignoreTriggerDamage = true;
robot.empShutdownTime = ( 750 );
robot.minWalkDistance = 60;
robot.superSprintDistance = 180;
robot.robotRusherMinRadius = 64;
robot.robotRusherMaxRadius = 120;
robot.allowPushActors = false;
robot.chargeMeleeDistance = 0; // Disable charge melee, more effective to shoot.
robot.fovcosine = 0; // 360 degree field of view
robot.fovcosinebusy = 0; // 360 degree field of view even when busy
robot.MaxSightDistSqrd = ( (2000) * (2000) );
Blackboard::SetBlackBoardAttribute( robot, "_robot_mode", "combat" );
// Disable head gibbing.
robot.gib_state = (0 | ( 8 & ( ( 1 << 9 ) - 1 ) ));
robot clientfield::set( "gib_state", robot.gib_state );
_ConfigureRobotTeam( robot, player, isHacked );
robot ai::set_behavior_attribute( "can_become_crawler", false );
robot ai::set_behavior_attribute( "can_be_meleed", false );
robot ai::set_behavior_attribute( "can_initiateaivsaimelee", false );
robot ai::set_behavior_attribute( "supports_super_sprint", true );
}
function private _ConfigureRobotTeam( robot, player, isHacked )
{
if ( isHacked )
{
lightsState = 3;
}
else
{
lightsState = 0;
}
robot ai::set_behavior_attribute( "robot_lights", lightsState );
robot thread WatchCombatRobotOwnerDisconnect( player );
if ( !isdefined( robot.objective ) )
{
robot.objective = GetEquipmentHeadObjective( GetWeapon( "combat_robot_marker" ) );
}
robot thread _WatchModeSwap( robot, player );
robot thread _Underwater( robot );
}
function private _CreateGuardMarker( robot, position )
{
owner = robot.owner;
guardMarker = spawn( "script_model", ( 0, 0, 0 ) );
guardMarker.origin = position;
guardMarker entityheadicons::setEntityHeadIcon( owner.pers["team"], owner, undefined, &"airdrop_combatrobot" );
return guardMarker;
}
function private _DestroyGuardMarker( robot )
{
if ( isdefined( robot.guardMarker ) )
{
robot.guardMarker delete();
}
}
function private _Underwater( robot )
{
robot endon( "death" );
while ( true )
{
if ( ( robot.origin[2] + 72 / 2.0 ) <= GetWaterHeight( robot.origin ) )
{
robot ASMSetAnimationRate( 0.85 );
}
else
{
robot ASMSetAnimationRate( 1.0 );
}
wait 0.1;
}
}
function private _Escort( robot )
{
robot endon( "death" );
robot.escorting = true;
robot.guarding = false;
_DestroyGuardMarker( robot );
while ( robot.escorting )
{
attackingEnemy = false;
if ( IsDefined( robot.enemy ) && IsAlive( robot.enemy ) )
{
if ( ( robot LastKnownTime( robot.enemy ) + 10000 ) >= GetTime() )
{
robot ai::set_behavior_attribute( "move_mode", "rusher" );
attackingEnemy = true;
}
else
{
robot ClearEnemy();
}
}
if ( !attackingEnemy && IsDefined( robot.owner ) && IsAlive( robot.owner ) )
{
lookAheadTime = 1.0;
predicitedPosition =
robot.owner.origin + VectorScale( robot.owner GetVelocity(), lookAheadTime );
robot ai::set_behavior_attribute( "escort_position", predicitedPosition );
robot ai::set_behavior_attribute( "move_mode", "escort" );
}
wait 1;
}
}
function private _IgnoreUnattackableEnemy( robot, enemy )
{
robot endon( "death" );
robot SetIgnoreEnt( enemy, true );
wait 5000 / 1000;
robot SetIgnoreEnt( enemy, false );
}
function private _GuardPosition( robot, position )
{
robot endon( "death" );
robot.goalradius = 1000;
robot SetGoal( position );
robot.escorting = false;
robot.guarding = true;
_DestroyGuardMarker( robot );
robot.guardMarker = _CreateGuardMarker( robot, position );
while ( robot.guarding )
{
attackingEnemy = false;
if ( IsDefined( robot.enemy ) && IsAlive( robot.enemy ) )
{
if ( ( robot LastKnownTime( robot.enemy ) + 10000 ) >= GetTime() )
{
// Robot still within goalradius, continue pursuit.
robot ai::set_behavior_attribute( "move_mode", "rusher" );
attackingEnemy = true;
}
else
{
robot ClearEnemy();
}
}
if ( !attackingEnemy )
{
robot ai::set_behavior_attribute( "move_mode", "guard" );
}
wait 1;
}
}
function _WatchModeSwap( robot, player )
{
robot endon( "death" );
nextSwitchTime = GetTime();
while ( true )
{
{wait(.05);};
if( !isdefined( robot.useTrigger ) )
continue;
robot.useTrigger waittill( "trigger" );
if ( nextSwitchTime <= GetTime() && IsAlive( player ) )
{
if ( ( isdefined( robot.guarding ) && robot.guarding ) )
{
robot.guarding = false;
robot.escorting = true;
player playsoundtoplayer( "uin_mp_combat_bot_escort", player );
robot thread _Escort( robot );
if( isdefined( robot.useTrigger ) )
robot.useTrigger SetHintString( &"KILLSTREAK_COMBAT_ROBOT_GUARD_HINT" );
if( isdefined( robot.markerFXHandle ) )
robot.markerFXHandle delete();
}
else
{
navGuardPosition = _CalculateProjectedGuardPosition( player );
if ( IsDefined( navGuardPosition ) )
{
robot.guarding = true;
robot.escorting = false;
player playsoundtoplayer( "uin_mp_combat_bot_guard", player );
robot thread _GuardPosition( robot, navGuardPosition );
if( isdefined( robot.useTrigger ) )
robot.useTrigger SetHintString( &"KILLSTREAK_COMBAT_ROBOT_ESCORT_HINT" );
if( isdefined( robot.markerFXHandle ) )
robot.markerFXHandle delete();
params = level.killstreakBundle["combat_robot"];
if( isdefined( params.ksCombatRobotPatrolFX ) )
{
point = player.origin;
if( !isdefined( point ) )
point = navGuardPosition;
robot.markerFXHandle = SpawnFx( params.ksCombatRobotPatrolFX, point + ( 0, 0, 3 ), ( 0, 0, 1 ), ( 1, 0, 0 ) );
robot.markerFXHandle.team = player.team;
TriggerFX( robot.markerFXHandle );
robot.markerFXHandle SetInvisibleToAll();
robot.markerFXHandle SetVisibleToPlayer( player );
}
}
else
{
player iPrintLnBold( &"KILLSTREAK_COMBAT_ROBOT_PATROL_FAIL" );
}
}
robot notify("bhtn_action_notify", "modeSwap");
nextSwitchTime = GetTime() + 1000;
}
}
}
function ActivateCombatRobot( killstreak )
{
player = self;
team = self.team;
if( !self supplydrop::isSupplyDropGrenadeAllowed( killstreak ) )
{
return false;
}
killstreak_id = self killstreakrules::killstreakStart( killstreak, team, false, false );
if ( killstreak_id == -1 )
{
return false;
}
context = SpawnStruct();
context.prolog = &Prolog;
context.epilog = &Epilog;
context.hasFlares = 1;
context.radius = level.killstreakCoreBundle.ksAirdropRobotRadius;
context.dist_from_boundary = 18;
context.max_dist_from_location = 4;
context.perform_physics_trace = true;
context.drop_from_goal_distance2d = 96; // combat robot doesn't need this value to be strict (note: drop ship related)
context.isLocationGood = &supplydrop::IsLocationGood;
context.objective = &"airdrop_combatrobot";
context.killstreakRef = killstreak;
context.validLocationSound = level.killstreakCoreBundle.ksValidCombatRobotLocationSound;
context.vehiclename = "combat_robot_dropship";
context.killstreak_id = killstreak_id;
context.tracemask = (1 << 0) | (1 << 2);
// This offset is specific to the exit vtol animation of the combat rider.
context.dropOffset = (0, -120, 0);
result = self supplydrop::useSupplyDropMarker( killstreak_id, context );
if ( !isdefined(result) || !result )
{
killstreakrules::killstreakStop( killstreak, team, killstreak_id );
return false;
}
self killstreaks::play_killstreak_start_dialog( "combat_robot", self.team, killstreak_id );
self killstreakrules::displayKillstreakStartTeamMessageToAll( "combat_robot" );
self AddWeaponStat( GetWeapon( "combat_robot_marker" ), "used", 1 );
return result;
}
function DropKillThread()
{
robot = self;
robot endon( "death" );
robot endon( "combat_robot_land" );
while( true )
{
robot supplydrop::is_touching_crate();
robot supplydrop::is_clone_touching_crate();
{wait(.05);};
}
}
function WatchHelicopterDeath( context )
{
helicopter = self;
helicopter waittill( "death" );
callback::callback( #"on_vehicle_killed" );
if( isdefined( context.marker ) )
{
context.marker delete();
context.marker = undefined;
if( isdefined( context.markerFXHandle ) )
{
context.markerFXHandle delete();
context.markerFXHandle = undefined;
}
supplydrop::DelDropLocation( context.killstreak_id );
}
}
function Prolog( context )
{
helicopter = self;
player = helicopter.owner;
spawnPosition = ( 0,0,0 );
spawnAngles = ( 0,0,0 );
combatRobot = SpawnActor(
"spawner_bo3_robot_grunt_assault_mp",
spawnPosition,
spawnAngles,
"",
true );
combatRobot.missileTrackDamage = 0;
combatRobot killstreaks::configure_team( "combat_robot", context.killstreak_id, player, "small_vehicle", undefined, &ConfigureTeamPost );
combatRobot killstreak_hacking::enable_hacking( "combat_robot", undefined, &HackedCallbackPost );
combatRobot thread _Escort( combatRobot );
combatRobot thread WatchCombatRobotHelicopterHacked( helicopter );
combatRobot thread WatchCombatRobotShutdown();
combatRobot thread WatchCombatRobotDeath();
combatRobot thread killstreaks::WaitForTimeout( "combat_robot", ( 90000 ), &OnCombatRobotTimeout, "combat_robot_shutdown" );
combatRobot thread sndWatchCombatRobotVoxNotifies();
//combatRobot thread debugThread();
helicopter thread WatchHelicopterDeath( context );
helicopter.unloadTimeout = 6;
killstreak_detect::killstreakTargetSet( combatRobot, ( 0, 0, 50 ) );
combatRobot.maxhealth = combatRobot.health;
tableHealth = killstreak_bundles::get_max_health( "combat_robot" );
if ( isdefined( tableHealth ) )
{
combatRobot.maxhealth = tableHealth;
}
combatRobot.health = combatRobot.maxhealth;
combatRobot.treat_owner_damage_as_friendly_fire = true;
combatRobot.ignore_team_kills = true;
combatRobot.remoteMissileDamage = combatRobot.maxhealth + 1;
combatRobot.rocketDamage = combatRobot.maxhealth / 2 + 1;
combatRobot thread heatseekingmissile::MissileTarget_ProximityDetonateIncomingMissile("death");
combatRobot clientfield::set( "enemyvehicle", 1 );
combatRobot.soundmod = "drone_land";
AiUtility::AddAIOverrideDamageCallback( combatRobot, &combatRobotDamageOverride );
combatRobot.vehicle = helicopter;
combatRobot.vehicle.ignore_seat_check = true;
combatRobot vehicle::get_in( helicopter , "driver", true );
combatRobot.overrideDropPosition = player.markerPosition;
combatRobot thread WatchCombatRobotLanding();
combatRobot thread sndWatchExit();
combatRobot thread sndWatchLanding();
combatRobot thread sndWatchActivate();
foreach( player in level.players )
{
combatRobot respectNotTargetedByRobotPerk( player );
}
callback::on_spawned( &respectNotTargetedByRobotPerk, combatRobot );
context.robot = combatRobot;
}
function respectNotTargetedByRobotPerk( player )
{
combatRobot = self;
combatRobot setignoreent( player, player hasperk( "specialty_nottargetedbyrobot" ) );
}
function Epilog( context )
{
helicopter = self;
context.robot thread DropKillThread();
context.robot.startTime = GetTime() + ( 750 ); // set killcam to start a time offset from when drop ship arrives
thread CleanupThread( context );
/# debug_delay_robot_deploy(); #/
helicopter WaitThenSetDeleteAfterDestructionWaitTime( 0.8, (isdefined(self.unloadTimeout)?self.unloadTimeout:0) + 0.1 );
helicopter vehicle::unload( "all", undefined, true, 0.8 ); // removes robot as rider so that it doesn't
}
/#
function debug_delay_robot_deploy()
{
seconds_to_wait = GetDvarInt( "scr_combat_robot_wait_to_deploy", 0 ); // 14 seconds is good to shoot down deploy ship given 3 flares and 2 rockets to kill and sustained ammo
while ( seconds_to_wait > 0 )
{
IPrintLnBold( "Remaining time: " + seconds_to_wait );
wait 1;
seconds_to_wait--;
if ( seconds_to_wait == 0 )
IPrintLnBold( "Jump!!" );
}
}
#/
function WaitThenSetDeleteAfterDestructionWaitTime( set_wait_time, delete_after_destruction_wait_time )
{
wait set_wait_time;
if ( isdefined( self ) )
{
self.delete_after_destruction_wait_time = delete_after_destruction_wait_time;
}
}
function HackedCallbackPost( hacker )
{
robot = self;
robot ClearEnemy();
robot SetupCombatRobotHintTrigger( hacker );
}
function WatchCombatRobotHelicopterHacked( helicopter )
{
robot = self;
robot endon( "death" );
robot endon( "killstreak_hacked" );
robot endon( "combat_robot_land" );
helicopter endon( "death" );
helicopter waittill( "killstreak_hacked", hacker );
if( robot flagsys::get( "in_vehicle" ) == false )
return;
robot [[ robot.killstreak_hackedCallback ]]( hacker );
}
function CleanupThread( context )
{
robot = context.robot;
while( isdefined( robot ) && isdefined( context.marker ) && ( robot flagsys::get( "in_vehicle" ) ) )
{
wait 1;
}
if( isdefined( context.marker ) )
{
context.marker delete();
context.marker = undefined;
if( isdefined( context.markerFXHandle ) )
{
context.markerFXHandle delete();
context.markerFXHandle = undefined;
}
supplydrop::DelDropLocation( context.killstreak_id );
}
}
function WatchCombatRobotDeath()
{
combatRobot = self;
combatRobot endon( "combat_robot_shutdown" );
callback::remove_on_spawned( &respectNotTargetedByRobotPerk, combatRobot );
combatRobot waittill( "death", attacker, damageFromUnderneath, weapon );
// combatRobot waittill( "death", attacker, damageFromUnderneath, weapon, point, dir, modType );
attacker = self [[ level.figure_out_attacker ]]( attacker );
if ( isdefined( attacker ) && IsPlayer( attacker ) && ( !isdefined( combatRobot.owner ) || combatRobot.owner util::IsEnemyPlayer( attacker ) ) )
{
attacker challenges::destroyScoreStreak( weapon, false, true );
attacker challenges::destroyNonAirScoreStreak_PostStatsLock( weapon );
scoreevents::processScoreEvent( "destroyed_combat_robot", attacker, combatRobot.owner, weapon );
LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_COMBAT_ROBOT", attacker.entnum );
}
combatRobot killstreaks::play_destroyed_dialog_on_owner( "combat_robot", combatRobot.killstreak_id );
combatRobot notify( "combat_robot_shutdown" );
}
function WatchCombatRobotLanding()
{
robot = self;
robot endon( "death" );
robot endon( "combat_robot_shutdown" );
// wait for landing
while( robot flagsys::get( "in_vehicle" ) )
{
wait 1;
}
robot notify( "combat_robot_land" );
robot.ignoreTriggerDamage = false;
// only check if on nav mesh after finishing traversals
while ( isdefined( robot.traverseStartNode ) )
{
robot waittill( "traverse_end" );
}
v_on_navmesh = GetClosestPointOnNavMesh( robot.origin, 50, 20 );
///#sphere( robot.origin, 5, ( 1, 0, 0 ), 1, true, 10, 200 );#/
if ( isdefined ( v_on_navmesh ) )
{
player = robot.owner;
robot SetupCombatRobotHintTrigger( player );
}
else
{
robot notify( "combat_robot_shutdown" );
}
}
function SetupCombatRobotHintTrigger( player )
{
robot = self;
if ( isdefined( robot.useTrigger ) )
{
robot.useTrigger delete();
}
robot.useTrigger = spawn( "trigger_radius_use", player.origin, 32, 32 );
robot.useTrigger EnableLinkTo();
robot.useTrigger LinkTo( player );
robot.useTrigger SetHintLowPriority( true );
robot.useTrigger SetCursorHint( "HINT_NOICON" );
robot.useTrigger SetHintString( &"KILLSTREAK_COMBAT_ROBOT_GUARD_HINT" );
robot.useTrigger SetTeamForTrigger( player.team );
robot.useTrigger.team = player.team;
player ClientClaimTrigger( robot.useTrigger );
player.remoteControlTrigger = robot.useTrigger;
robot.useTrigger.ClaimedBy = player;
}
function WatchCombatRobotOwnerDisconnect( player )
{
combatRobot = self;
combatRobot notify( "WatchCombatRobotOwnerDisconnect_singleton" );
combatRobot endon( "WatchCombatRobotOwnerDisconnect_singleton" );
combatRobot endon( "combat_robot_shutdown" );
player util::waittill_any( "joined_team", "disconnect", "joined_spectators" );
combatRobot notify( "combat_robot_shutdown" );
}
function private _corpseWatcher()
{
archetype = self.archetype;
self waittill("actor_corpse", corpse);
corpse clientfield::set("arch_actor_fire_fx", 3);
}
function private _explodeRobot( combatRobot )
{
combatRobot clientfield::set("arch_actor_fire_fx", 1);
clientfield::set(
"robot_mind_control_explosion", 1 );
combatRobot thread _corpseWatcher();
if ( RandomInt( 100 ) >= 50 )
GibServerUtils::GibLeftArm( combatRobot );
else
GibServerUtils::GibRightArm( combatRobot );
GibServerUtils::GibLegs( combatRobot );
GibServerUtils::GibHead( combatRobot );
velocity = combatRobot GetVelocity() * ( 1 / 8 );
combatRobot StartRagdoll();
combatRobot LaunchRagdoll(
( velocity[0] + RandomFloatRange( -20, 20 ),
velocity[1] + RandomFloatRange( -20, 20 ),
RandomFloatRange( 60, 80 ) ),
"j_mainroot" );
}
function OnCombatRobotTimeout()
{
combatRobot = self;
combatRobot killstreaks::play_pilot_dialog_on_owner( "timeout", "combat_robot" );
combatRobot ai::set_behavior_attribute( "shutdown", true );
wait RandomFloatRange( 3.0, 4.5 );
_explodeRobot( combatRobot );
params = level.killstreakBundle["combat_robot"];
if( isdefined( params.ksExplosionFX ) )
{
PlayFXOnTag( params.ksExplosionFX, combatRobot, "tag_origin" );
}
Target_Remove( combatRobot );
if(!isdefined(params.ksExplosionOuterRadius))params.ksExplosionOuterRadius=200;
if(!isdefined(params.ksExplosionInnerRadius))params.ksExplosionInnerRadius=1;
if(!isdefined(params.ksExplosionOuterDamage))params.ksExplosionOuterDamage=25;
if(!isdefined(params.ksExplosionInnerDamage))params.ksExplosionInnerDamage=350;
if(!isdefined(params.ksExplosionMagnitude))params.ksExplosionMagnitude=1;
PhysicsExplosionSphere( combatRobot.origin,
params.ksExplosionOuterRadius,
params.ksExplosionInnerRadius,
params.ksExplosionMagnitude,
params.ksExplosionOuterDamage,
params.ksExplosionInnerDamage );
if( isdefined( combatRobot.owner ) )
{
RadiusDamage( combatRobot.origin,
params.ksExplosionOuterRadius,
params.ksExplosionInnerDamage,
params.ksExplosionOuterDamage,
combatRobot.owner,
"MOD_EXPLOSIVE",
GetWeapon( "combat_robot_marker" ) );
if( isdefined( params.ksExplosionRumble ) )
combatRobot.owner PlayRumbleOnEntity( params.ksExplosionRumble );
}
wait( 0.2 );
combatRobot notify( "combat_robot_shutdown" );
}
function WatchCombatRobotShutdown()
{
combatRobot = self;
combatRobotTeam = combatRobot.originalteam;
combatRobotKillstreakId = combatRobot.killstreak_id;
combatRobot waittill( "combat_robot_shutdown" );
combatRobot playsound ("evt_combat_bot_mech_fail_explode");
if( isdefined( combatRobot.useTrigger ) )
combatRobot.useTrigger delete();
if( isdefined( combatRobot.markerFXHandle ) )
combatRobot.markerFXHandle delete();
_DestroyGuardMarker( combatRobot );
killstreakrules::killstreakStop( "combat_robot", combatRobotTeam, combatRobotKillstreakId );
if( isdefined( combatRobot ) )
{
if( Target_IsTarget( combatRobot ) )
Target_Remove( combatRobot );
if( !level.gameEnded ) // kill and do damage do nothing after game end
{
if( combatRobot flagsys::get( "in_vehicle" ) )
combatRobot Unlink();
combatRobot Kill();
}
}
}
function sndWatchCombatRobotVoxNotifies()
{
combatRobot = self;
combatRobot endon( "combat_robot_shutdown" );
combatRobot endon( "death" );
combatRobot PlaySoundOnTag( "vox_robot_chatter", "j_head" );
while( 1 )
{
soundAlias = undefined;
combatRobot waittill("bhtn_action_notify", notify_string);
switch( notify_string )
{
case "charge":
case "attack_melee":
case "attack_kill":
case "modeSwap":
soundAlias = "vox_robot_chatter";
break;
}
if( isdefined( soundAlias ) )
{
combatRobot PlaySoundOnTag( soundAlias, "j_head" );
wait(1.2);
}
}
}
function sndWatchExit()
{
combatRobot = self;
combatRobot endon( "combat_robot_shutdown" );
combatRobot endon( "death" );
combatRobot waittill( "exiting_vehicle" );
combatRobot playsound( "veh_vtol_supply_robot_launch" );
}
function sndWatchLanding()
{
combatRobot = self;
combatRobot endon( "combat_robot_shutdown" );
combatRobot endon( "death" );
combatRobot waittill( "falling", falltime );
wait_time = falltime - .5;
if ( wait_time > 0 )
wait( wait_time );
combatRobot playsound( "veh_vtol_supply_robot_land" );
}
function sndWatchActivate()
{
combatRobot = self;
combatRobot endon( "combat_robot_shutdown" );
combatRobot endon( "death" );
combatRobot waittill( "landing" );
wait(.1);
combatRobot playsound( "veh_vtol_supply_robot_activate" );
}
function combatRobotDamageOverride( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex, modelIndex )
{
combatRobot = self;
if( combatRobot flagsys::get( "in_vehicle" ) && ( sMeansOfDeath == "MOD_TRIGGER_HURT" ) ) // the dropship goes through hurt triggers sometimes
iDamage = 0;
else
iDamage = killstreaks::OnDamagePerWeapon( "combat_robot", eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, self.maxhealth, undefined, self.maxhealth*0.4, undefined, 0, undefined, true, 1.0 );
combatRobot.missileTrackDamage += iDamage;
if ( iDamage > 0 && isdefined( eAttacker ) )
{
if ( isPlayer( eAttacker) )
{
if ( isdefined( combatRobot.owner ) )
{
challenges::combat_robot_damage( eAttacker, combatRobot.Owner );
}
}
}
return iDamage;
}