675 lines
19 KiB
Plaintext
675 lines
19 KiB
Plaintext
#include maps\mp\_utility;
|
|
#include common_scripts\utility;
|
|
|
|
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
|
// Init
|
|
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
|
|
|
CONST_LOCK_ON_TIME_MSEC = 1500;
|
|
|
|
LGM_init( fxSplit, fxHoming )
|
|
{
|
|
level._effect[ "laser_guided_launcher_missile_split" ] = LoadFX( fxSplit );
|
|
level._effect[ "laser_guided_launcher_missile_spawn_homing" ] = LoadFX( fxHoming );
|
|
}
|
|
|
|
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
|
// Monitor Player Weapon for Use as CAC Launcher
|
|
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
|
|
|
// Function to use if you want to have a laser guided launcher as
|
|
// a launcher in CAC. Just thread this watch off in _weapons.gsc::init()
|
|
LGM_update_launcherUsage( weaponName, weaponNameHoming )
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
self endon( "faux_spawn" );
|
|
|
|
self thread LGM_monitorLaser();
|
|
|
|
weaponCurr = self GetCurrentWeapon();
|
|
while ( 1 )
|
|
{
|
|
while ( weaponCurr != weaponName )
|
|
{
|
|
self waittill( "weapon_change", weaponCurr );
|
|
}
|
|
|
|
self childthread LGM_firing_monitorMissileFire( weaponCurr, weaponNameHoming );
|
|
|
|
self waittill( "weapon_change", weaponCurr );
|
|
|
|
self LGM_firing_endMissileFire();
|
|
}
|
|
}
|
|
|
|
LGM_monitorLaser()
|
|
{
|
|
self endon( "LGM_player_endMonitorFire" );
|
|
|
|
self waittill_any( "death", "disconnect" );
|
|
|
|
if ( IsDefined( self ) )
|
|
{
|
|
self LGM_disableLaser();
|
|
}
|
|
}
|
|
|
|
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
|
// Monitor Player Firing
|
|
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
|
|
|
LASER_GUIDED_MISSILE_LASER_TRACE_CLOSE_TIME_MSEC = 400; // Time after firing that the trace distance is short. This forces the missiles forward.
|
|
LASER_GUIDED_MISSILE_LASER_TRACE_LENGTH_SHORT = 800;
|
|
LASER_GUIDED_MISSILE_LASER_TRACE_LENGTH = 8000;
|
|
LASER_GUIDED_MISSILE_DELAY_CHILDREN_SPAWN = 0.35;
|
|
LASER_GUIDED_MISSILE_DELAY_CHILDREN_TRACK = 0.1;
|
|
LASER_GUIDED_MISSILE_PITCH_CHILDREN_DIVERGE = 20;
|
|
LASER_GUIDED_MISSILE_YAW_CHILDREN_DIVERGE = 20;
|
|
|
|
LGM_firing_endMissileFire()
|
|
{
|
|
self LGM_disableLaser();
|
|
|
|
self notify( "LGM_player_endMonitorFire" );
|
|
}
|
|
|
|
LGM_firing_monitorMissileFire( weaponName, weaponNameChild, weaponNameHoming )
|
|
{
|
|
self endon( "LGM_player_endMonitorFire" );
|
|
|
|
self LGM_enableLaser();
|
|
|
|
entTarget = undefined;
|
|
|
|
while ( 1 )
|
|
{
|
|
missile = undefined;
|
|
self waittill( "missile_fire", missile, weaponNotified );
|
|
|
|
// Ignore missiles fired by script
|
|
if ( IsDefined( missile.isMagicBullet ) && missile.isMagicBullet )
|
|
continue;
|
|
|
|
// The hind magic bullets missiles on behalf of the player, so ignore without assert.
|
|
if ( weaponNotified != weaponName )
|
|
continue;
|
|
|
|
if ( !IsDefined( entTarget ) )
|
|
{
|
|
entTarget = LGM_requestMissileGuideEnt( self );
|
|
}
|
|
|
|
self thread LGM_firing_delaySpawnChildren( weaponName, weaponNameChild, weaponNameHoming, LASER_GUIDED_MISSILE_DELAY_CHILDREN_SPAWN, LASER_GUIDED_MISSILE_DELAY_CHILDREN_TRACK, missile, entTarget );
|
|
}
|
|
}
|
|
|
|
LGM_firing_delaySpawnChildren( weaponName, weaponNameChild, weaponNameHoming, delaySpawn, delayTrack, missile, entTarget )
|
|
{
|
|
// If the player fires rapidly, cancel the previous missile spawn
|
|
self notify( "monitor_laserGuidedMissile_delaySpawnChildren" );
|
|
self endon( "monitor_laserGuidedMissile_delaySpawnChildren" );
|
|
|
|
// If the player dies this function needs to be cleared up immediately. This is because
|
|
// the target ent gets scrubbed on death so any created missiles may have been
|
|
// removed from the array
|
|
self endon( "death" );
|
|
self endon( "LGM_player_endMonitorFire" );
|
|
|
|
// Only let one set of rockets be guided by releasing
|
|
// any previously fired rockets
|
|
LGM_missilesNotifyAndRelease( entTarget );
|
|
|
|
wait( delaySpawn );
|
|
|
|
// Exit if missile has blown up
|
|
if ( !IsValidMissile( missile ) )
|
|
return;
|
|
|
|
missileOrigin = missile.origin;
|
|
missileFwd = AnglesToForward( missile.angles );
|
|
missileUp = AnglesToUp( missile.angles );
|
|
missileRight = AnglesToRight( missile.angles );
|
|
|
|
missile Delete();
|
|
|
|
// Spawn missile break apart fx
|
|
PlayFX( level._effect[ "laser_guided_launcher_missile_split" ], missileOrigin, missileFwd, missileUp );
|
|
|
|
missiles = [];
|
|
|
|
for ( i = 0; i < 2; i++ )
|
|
{
|
|
pitch = LASER_GUIDED_MISSILE_PITCH_CHILDREN_DIVERGE; // Default Upwards Pitch: Forward and Up n degrees
|
|
yaw = 0;
|
|
|
|
if ( i == 0 ) // Right Missile: Up 45 degrees and then 45 degrees around Z
|
|
{
|
|
yaw = LASER_GUIDED_MISSILE_YAW_CHILDREN_DIVERGE;
|
|
}
|
|
else if ( i == 1 ) // Left Missile: Up 45 degrees and then -45 degrees around Z
|
|
{
|
|
yaw = -1 * LASER_GUIDED_MISSILE_YAW_CHILDREN_DIVERGE;
|
|
}
|
|
else if ( i == 2 )// Middle Missile: Already rotated up
|
|
{
|
|
// All done
|
|
}
|
|
|
|
childMissileFwd = RotatePointAroundVector( missileRight, missileFwd, pitch );
|
|
childMissileFwd = RotatePointAroundVector( missileUp, childMissileFwd, yaw );
|
|
|
|
missileChild = MagicBullet( weaponNameChild, missileOrigin, missileOrigin + childMissileFwd * 180, self );
|
|
missileChild.isMagicBullet = true;
|
|
missiles[ missiles.size ] = missileChild;
|
|
|
|
// Don't spawn missiles on the same frame
|
|
waitframe();
|
|
}
|
|
|
|
wait( delayTrack );
|
|
|
|
missiles = LGM_removeInvalidMissiles( missiles );
|
|
|
|
if ( missiles.size > 0 )
|
|
{
|
|
foreach ( missChild in missiles )
|
|
{
|
|
entTarget.missilesChasing[ entTarget.missilesChasing.size ] = missChild;
|
|
missChild Missile_SetTargetEnt( entTarget );
|
|
|
|
self thread LGM_onMissileNotifies( entTarget, missChild );
|
|
}
|
|
|
|
self thread LGM_firing_monitorPlayerAim( entTarget, weaponNameHoming );
|
|
}
|
|
}
|
|
|
|
LGM_onMissileNotifies( entTarget, missile )
|
|
{
|
|
missile waittill_any( "death", "missile_pairedWithFlare", "LGM_missile_abandoned" );
|
|
|
|
if ( IsDefined( entTarget.missilesChasing ) && entTarget.missilesChasing.size > 0 )
|
|
{
|
|
entTarget.missilesChasing = array_remove( entTarget.missilesChasing, missile );
|
|
entTarget.missilesChasing = LGM_removeInvalidMissiles( entTarget.missilesChasing );
|
|
}
|
|
|
|
if ( !IsDefined( entTarget.missilesChasing ) || entTarget.missilesChasing.size == 0 )
|
|
{
|
|
self notify( "LGM_player_allMissilesDestroyed" );
|
|
}
|
|
}
|
|
|
|
// Handles initial lock visual / audio fx
|
|
|
|
LGM_firing_monitorPlayerAim( entTarget, weaponNameHoming )
|
|
{
|
|
self notify( "LGM_player_newMissilesFired" );
|
|
self endon( "LGM_player_newMissilesFired" );
|
|
|
|
self endon( "LGM_player_allMissilesDestroyed" );
|
|
self endon( "LGM_player_endMonitorFire" );
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
|
|
originGoal = undefined;
|
|
targetVeh = undefined;
|
|
lockOnTime = undefined;
|
|
lockedOn = false;
|
|
|
|
timeTraceFar = GetTime() + LASER_GUIDED_MISSILE_LASER_TRACE_CLOSE_TIME_MSEC;
|
|
|
|
while ( IsDefined( entTarget.missilesChasing ) && entTarget.missilesChasing.size > 0 )
|
|
{
|
|
targetLook = self LGM_targetFind();
|
|
|
|
if ( !IsDefined( targetLook ) )
|
|
{
|
|
// If there was a previous target, clear that target and
|
|
// notify systmes watching the missiles that the
|
|
// target has changed
|
|
if ( IsDefined( targetVeh ) )
|
|
{
|
|
self notify( "LGM_player_targetLost" );
|
|
targetVeh = undefined;
|
|
|
|
foreach ( missile in entTarget.missilesChasing )
|
|
{
|
|
missile notify( "missile_targetChanged" );
|
|
}
|
|
}
|
|
|
|
lockOnTime = undefined;
|
|
lockedOn = false;
|
|
|
|
traceDist = ter_op( GetTime() > timeTraceFar, LASER_GUIDED_MISSILE_LASER_TRACE_LENGTH, LASER_GUIDED_MISSILE_LASER_TRACE_LENGTH_SHORT );
|
|
viewDir = AnglesToForward( self GetPlayerAngles() );
|
|
startPos = self GetEye() + viewDir * 12;
|
|
trace = BulletTrace( startPos, startPos + viewDir * traceDist, true, self, false, false, false );
|
|
|
|
originGoal = trace[ "position" ];
|
|
}
|
|
else
|
|
{
|
|
originGoal = targetLook.origin;
|
|
|
|
newTarget = !IsDefined( targetVeh ) || targetLook != targetVeh;
|
|
targetVeh = targetLook;
|
|
|
|
if ( newTarget || !IsDefined( lockOnTime ) )
|
|
{
|
|
lockOnTime = GetTime() + CONST_LOCK_ON_TIME_MSEC;
|
|
level thread LGM_locking_think( targetVeh, self );
|
|
}
|
|
else if ( GetTime() >= lockOnTime )
|
|
{
|
|
// incoming notify was fired as soon as the player looked at
|
|
// the target
|
|
lockedOn = true;
|
|
self notify( "LGM_player_lockedOn" );
|
|
}
|
|
|
|
if ( lockedOn )
|
|
{
|
|
// In case the current live missiles are paired with flares
|
|
// this script update wait untill after they're removed
|
|
// from missilesChasing
|
|
waittillframeend;
|
|
|
|
if ( entTarget.missilesChasing.size > 0 )
|
|
{
|
|
missileOrigins = [];
|
|
|
|
foreach ( missile in entTarget.missilesChasing )
|
|
{
|
|
if ( !IsValidMissile( missile ) )
|
|
continue;
|
|
|
|
missileOrigins[ missileOrigins.size ] = missile.origin;
|
|
|
|
missile notify( "missile_targetChanged" );
|
|
missile notify( "LGM_missile_abandoned" );
|
|
missile Delete();
|
|
}
|
|
|
|
if ( missileOrigins.size > 0 )
|
|
{
|
|
level thread LGM_locked_think( targetVeh, self, weaponNameHoming, missileOrigins );
|
|
}
|
|
|
|
entTarget.missilesChasing = [];
|
|
}
|
|
else
|
|
{
|
|
// All missiles were removed during the waittillframeend
|
|
break;
|
|
}
|
|
}
|
|
else if ( newTarget )
|
|
{
|
|
LGM_targetNotifyMissiles( targetVeh, self, entTarget.missilesChasing );
|
|
}
|
|
}
|
|
|
|
entTarget.origin = originGoal;
|
|
|
|
waitframe();
|
|
}
|
|
}
|
|
|
|
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
|
// Monitor LaserGuided Missile Ent Pool
|
|
// - Prevent too many ents being created
|
|
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
|
|
|
TARGET_ENT_COUNT_PREFERRED_MAX = 4; // The pool of target ents can get larger than this but should shrink back down when less are needed.
|
|
|
|
LGM_requestMissileGuideEnt( player )
|
|
{
|
|
if ( !IsDefined( level.laserGuidedMissileEnts_inUse ) )
|
|
{
|
|
level.laserGuidedMissileEnts_inUse = [];
|
|
}
|
|
|
|
if ( !IsDefined( level.laserGuidedMissileEnts_ready ) )
|
|
{
|
|
level.laserGuidedMissileEnts_ready = [];
|
|
}
|
|
|
|
ent = undefined;
|
|
|
|
if ( level.laserGuidedMissileEnts_ready.size )
|
|
{
|
|
ent = level.laserGuidedMissileEnts_ready[ 0 ];
|
|
level.laserGuidedMissileEnts_ready = array_remove( level.laserGuidedMissileEnts_ready, ent );
|
|
}
|
|
else
|
|
{
|
|
ent = spawn( "script_origin", player.origin );
|
|
}
|
|
|
|
level.laserGuidedMissileEnts_inUse[ level.laserGuidedMissileEnts_inUse.size ] = ent;
|
|
|
|
level thread LGM_monitorLaserEntCleanUp( ent, player );
|
|
|
|
ent.missilesChasing = [];
|
|
|
|
return ent;
|
|
}
|
|
|
|
LGM_monitorLaserEntCleanUp( entTarget, player )
|
|
{
|
|
player waittill_any( "death", "disconnect", "LGM_player_endMonitorFire" );
|
|
|
|
AssertEx( array_contains( level.laserGuidedMissileEnts_inUse, entTarget ), "LGM_monitorLaserEntCleanUp() attempting to clean up laser target ent not currently in use." );
|
|
|
|
// Scrub ent clean
|
|
AssertEx( IsDefined( entTarget.missilesChasing ) && IsArray( entTarget.missilesChasing ), "LGM_monitorLaserEntCleanUp() given missile ent with now missile array." );
|
|
foreach ( missile in entTarget.missilesChasing )
|
|
{
|
|
if ( IsValidMissile( missile ) )
|
|
{
|
|
missile Missile_ClearTarget();
|
|
}
|
|
}
|
|
|
|
entTarget.missilesChasing = undefined;
|
|
|
|
// Move ent fron in use to ready array
|
|
level.laserGuidedMissileEnts_inUse = array_remove( level.laserGuidedMissileEnts_inUse, entTarget );
|
|
|
|
// If the too many ents exist delete it, otherwise add it to ready array
|
|
if ( level.laserGuidedMissileEnts_ready.size + level.laserGuidedMissileEnts_inUse.size < TARGET_ENT_COUNT_PREFERRED_MAX )
|
|
{
|
|
level.laserGuidedMissileEnts_ready[ level.laserGuidedMissileEnts_ready.size ] = entTarget;
|
|
}
|
|
else
|
|
{
|
|
entTarget Delete();
|
|
}
|
|
}
|
|
|
|
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
|
// Monitor Locking and Locked On
|
|
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
|
|
|
LGM_locking_think( targetVeh, player )
|
|
{
|
|
AssertEx( IsDefined( player ), "LGM_locking_think called with undefined player." );
|
|
|
|
outline = outlineEnableForPlayer( targetVeh, "orange", player, true, "killstreak_personal" );
|
|
|
|
level thread LGM_locking_loopSound( player, "maaws_reticle_tracking", 1.5, "LGM_player_lockingDone" );
|
|
level thread LGM_locking_notifyOnTargetDeath( targetVeh, player );
|
|
|
|
player waittill_any(
|
|
"death", // targetting player died
|
|
"disconnect", // targetting player left game
|
|
"LGM_player_endMonitorFire", // ks system stopped launcher logic
|
|
"LGM_player_newMissilesFired", // player fired again, these missiles are going to be abandoned
|
|
"LGM_player_targetLost", // player looked away or new enemy came into view during lock on
|
|
"LGM_player_lockedOn", // player obtained full lock, this outlin is removed, a new outlin call is made
|
|
"LGM_player_allMissilesDestroyed", // the current set of tracked missiles all died or were paired with flares
|
|
"LGM_player_targetDied" // target destroyed
|
|
);
|
|
|
|
// Some entities delete instantly on death and may
|
|
// be removed at this point
|
|
if ( IsDefined( targetVeh ) )
|
|
{
|
|
outlineDisable( outline, targetVeh );
|
|
}
|
|
|
|
if ( IsDefined( player ) )
|
|
{
|
|
player notify( "LGM_player_lockingDone" );
|
|
|
|
player StopLocalSound( "maaws_reticle_tracking" );
|
|
}
|
|
}
|
|
|
|
LGM_locked_missileOnDeath( missile, targetVeh, groupID )
|
|
{
|
|
targetVeh endon( "death" );
|
|
|
|
missile waittill( "death" );
|
|
|
|
targetVeh.LG_missilesLocked[ groupID ] = array_remove( targetVeh.LG_missilesLocked[ groupID ], missile );
|
|
|
|
if ( targetVeh.LG_missilesLocked[ groupID ].size == 0 )
|
|
{
|
|
targetVeh.LG_missilesLocked[ groupID ] = undefined;
|
|
targetVeh notify( "LGM_target_lockedMissilesDestroyed" );
|
|
}
|
|
}
|
|
|
|
LGM_locking_notifyOnTargetDeath( target, player )
|
|
{
|
|
player endon( "death" );
|
|
player endon( "disconnect" );
|
|
player endon( "LGM_player_lockingDone" );
|
|
|
|
target waittill( "death" );
|
|
|
|
player notify( "LGM_player_targetDied" );
|
|
}
|
|
|
|
LGM_locking_loopSound( player, sound, time, endonPlayer )
|
|
{
|
|
player endon( "death" );
|
|
player endon( "disconnect" );
|
|
player endon( endOnPlayer );
|
|
|
|
while ( 1 )
|
|
{
|
|
player PlayLocalSound( sound );
|
|
wait( time );
|
|
}
|
|
}
|
|
|
|
LGM_locked_spawnMissiles( target, player, weaponNameHoming, missileOrigins )
|
|
{
|
|
target endon( "death" );
|
|
player endon( "death" );
|
|
player endon( "disconnect" );
|
|
|
|
missilesLocked = [];
|
|
|
|
for ( i = 0; i < missileOrigins.size; i++ )
|
|
{
|
|
missileChild = MagicBullet( weaponNameHoming, missileOrigins[ i ], target.origin, player );
|
|
missileChild.isMagicBullet = true;
|
|
missilesLocked[ missilesLocked.size ] = missileChild;
|
|
|
|
PlayFX( level._effect[ "laser_guided_launcher_missile_spawn_homing" ], missileChild.origin, AnglesToForward( missileChild.angles ), AnglesToUp( missileChild.angles ) );
|
|
|
|
// Don't spawn missiles on the same frame
|
|
waitframe();
|
|
}
|
|
|
|
return missilesLocked;
|
|
}
|
|
|
|
// Handles locked on visual / audio fx
|
|
LGM_locked_think( targetVeh, player, weaponNameHoming, missileOrigins )
|
|
{
|
|
AssertEx( missileOrigins.size > 0, "LGM_locked_think() passed empty missile origin array." );
|
|
|
|
if ( missileOrigins.size == 0 )
|
|
return;
|
|
|
|
missilesLocked = LGM_locked_spawnMissiles( targetVeh, player, weaponNameHoming, missileOrigins );
|
|
|
|
// If undefined the player died or the target died
|
|
if ( !IsDefined( missilesLocked ) )
|
|
return;
|
|
|
|
// In case a missile died after the above wait frame
|
|
missilesLocked = LGM_removeInvalidMissiles( missilesLocked );
|
|
if ( missilesLocked.size == 0 )
|
|
return;
|
|
|
|
// Visual and audio fx
|
|
player PlayLocalSound( "maaws_reticle_locked" );
|
|
outlineID = outlineEnableForPlayer( targetVeh, "red", player, false, "killstreak_personal" );
|
|
|
|
// Give missiles their target with an offset
|
|
targetOffset = LGM_getTargetOffset( targetVeh );
|
|
|
|
foreach ( mChild in missilesLocked )
|
|
{
|
|
mChild missile_setTargetAndFlightMode( targetVeh, "direct", targetOffset );
|
|
|
|
LGM_targetNotifyMissiles( targetVeh, player, missilesLocked );
|
|
}
|
|
|
|
if ( !IsDefined( targetVeh.LG_missilesLocked ) )
|
|
{
|
|
targetVeh.LG_missilesLocked = [];
|
|
}
|
|
|
|
// Because multiple sets of missiles from the same or different players
|
|
// can be tracking the helicopter at the same timed, add the missiles
|
|
// to an array by the unique outline ID
|
|
targetVeh.LG_missilesLocked[ outlineID ] = missilesLocked;
|
|
|
|
foreach ( vMiss in missilesLocked )
|
|
{
|
|
level thread LGM_locked_missileOnDeath( vMiss, targetVeh, outlineID );
|
|
}
|
|
|
|
outlineOn = true;
|
|
while ( outlineOn )
|
|
{
|
|
msg = targetVeh waittill_any_return( "death", "LGM_target_lockedMissilesDestroyed" );
|
|
|
|
if ( msg == "death" )
|
|
{
|
|
outlineOn = false;
|
|
if ( IsDefined( targetVeh ) )
|
|
{
|
|
targetVeh.LG_missilesLocked[ outlineID ] = undefined;
|
|
}
|
|
}
|
|
else if ( msg == "LGM_target_lockedMissilesDestroyed" )
|
|
{
|
|
// Two sets of missiles could potentially throw the "LGM_target_lockedMissilesDestroyed"
|
|
// notification on the same frame. Wait until frame end and then check to see if this
|
|
// outline's missiles are all gone
|
|
waittillframeend;
|
|
|
|
if ( !IsDefined( targetVeh.LG_missilesLocked[ outlineID ] ) || targetVeh.LG_missilesLocked[ outlineID ].size == 0 )
|
|
{
|
|
outlineOn = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Targetveh may be deleted at this point
|
|
if ( IsDefined( targetVeh ) )
|
|
{
|
|
outlineDisable( outlineID, targetVeh );
|
|
}
|
|
}
|
|
|
|
LGM_targetFind()
|
|
{
|
|
targets = self maps\mp\gametypes\_weapons::lockOnLaunchers_getTargetArray();
|
|
targets = SortByDistance( targets, self.origin );
|
|
|
|
targetLook = undefined;
|
|
foreach ( target in targets )
|
|
{
|
|
if ( self WorldPointInReticle_Circle( target.origin, 65, 75 ) )
|
|
{
|
|
targetLook = target;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return targetLook;
|
|
}
|
|
|
|
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
|
// LaserGuided Missile Utils
|
|
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
|
|
|
LGM_enableLaser()
|
|
{
|
|
if ( !IsDefined( self.laserGuidedLauncher_laserOn ) || self.laserGuidedLauncher_laserOn == false )
|
|
{
|
|
self.laserGuidedLauncher_laserOn = true;
|
|
self enableWeaponLaser();
|
|
}
|
|
}
|
|
|
|
LGM_disableLaser()
|
|
{
|
|
if ( IsDefined( self.laserGuidedLauncher_laserOn ) && self.laserGuidedLauncher_laserOn == true )
|
|
{
|
|
self disableWeaponLaser();
|
|
}
|
|
|
|
self.laserGuidedLauncher_laserOn = undefined;
|
|
}
|
|
|
|
LGM_removeInvalidMissiles( missiles )
|
|
{
|
|
valid = [];
|
|
foreach ( m in missiles )
|
|
{
|
|
if ( IsValidMissile( m ) )
|
|
{
|
|
valid[ valid.size ] = m;
|
|
}
|
|
}
|
|
return valid;
|
|
}
|
|
|
|
LGM_targetNotifyMissiles( targetVeh, attacker, missiles )
|
|
{
|
|
// General notifies to other systems to handle incoming missiles
|
|
level notify( "laserGuidedMissiles_incoming", attacker, missiles, targetVeh );
|
|
targetVeh notify( "targeted_by_incoming_missile", missiles );
|
|
}
|
|
|
|
LGM_getTargetOffset( target )
|
|
{
|
|
targetPoint = undefined;
|
|
//AH: HACK: The harrier doesn't have the tag_missile_target, but it does have a tag_body.
|
|
// The code works fine without this check, but GetTagOrigin throws an SRE if the tag does not exist.
|
|
if ( target.model != "vehicle_av8b_harrier_jet_mp" )
|
|
targetPoint = target GetTagOrigin( "tag_missile_target" );
|
|
else
|
|
targetPoint = target GetTagOrigin( "tag_body" );
|
|
|
|
if ( !IsDefined( targetPoint ) )
|
|
{
|
|
targetPoint = target GetPointInBounds( 0, 0, 0 );
|
|
AssertMsg( "LGM_getTargetOffset() failed to find tag_missile_target on entity." + target.classname );
|
|
}
|
|
|
|
return targetPoint - target.origin;
|
|
}
|
|
|
|
LGM_missilesNotifyAndRelease( entTarget )
|
|
{
|
|
if ( IsDefined( entTarget.missilesChasing ) && entTarget.missilesChasing.size > 0 )
|
|
{
|
|
foreach ( missChasing in entTarget.missilesChasing )
|
|
{
|
|
if ( IsValidMissile( missChasing ) )
|
|
{
|
|
// Let systems watching incoming missiles know the
|
|
// target has changed
|
|
missChasing notify( "missile_targetChanged" );
|
|
missChasing notify( "LGM_missile_abandoned" );
|
|
missChasing Missile_ClearTarget();
|
|
}
|
|
}
|
|
}
|
|
|
|
entTarget.missilesChasing = [];
|
|
}
|