init
This commit is contained in:
298
maps/mp/killstreaks/_air_superiority.gsc
Normal file
298
maps/mp/killstreaks/_air_superiority.gsc
Normal file
@ -0,0 +1,298 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
// replacement for EMP
|
||||
// only affects aircraft
|
||||
// remarkably similar to aastrike, should probably get rid of that...
|
||||
KS_NAME = "air_superiority";
|
||||
kProjectileName = "aamissile_projectile_mp";
|
||||
|
||||
init()
|
||||
{
|
||||
config = SpawnStruct();
|
||||
config.modelNames = [];
|
||||
config.modelNames[ "allies" ] = "vehicle_a10_warthog_iw6_mp";
|
||||
config.modelNames[ "axis" ] = "vehicle_a10_warthog_iw6_mp";
|
||||
config.inboundSfx = "veh_mig29_dist_loop";
|
||||
//config.inboundSfx = "veh_aastrike_flyover_loop";
|
||||
//config.outboundSfx = "veh_aastrike_flyover_outgoing_loop";
|
||||
config.compassIconFriendly = "compass_objpoint_airstrike_friendly";
|
||||
config.compassIconEnemy = "compass_objpoint_airstrike_busy";
|
||||
// sonic boom?
|
||||
config.speed = 4000;
|
||||
config.halfDistance = 20000;
|
||||
config.distFromPlayer = 4000;
|
||||
config.heightRange = 250;
|
||||
//config.attackTime = 2.0;
|
||||
config.numMissileVolleys = 3;
|
||||
config.outboundFlightAnim = "airstrike_mp_roll";
|
||||
config.sonicBoomSfx = "veh_mig29_sonic_boom";
|
||||
config.onAttackDelegate = ::attackEnemyAircraft;
|
||||
config.onFlybyCompleteDelegate = ::cleanupFlyby;
|
||||
config.xpPopup = "destroyed_air_superiority";
|
||||
config.callout = "callout_destroyed_air_superiority";
|
||||
config.voDestroyed = undefined;
|
||||
config.killCamOffset = (-800, 0, 200);
|
||||
|
||||
level.planeConfigs[ KS_NAME ] = config;
|
||||
|
||||
level.killstreakFuncs[KS_NAME] = ::onUse;
|
||||
|
||||
level.teamAirDenied["axis"] = false;
|
||||
level.teamAirDenied["allies"] = false;
|
||||
}
|
||||
|
||||
onUse( lifeId, streakName )
|
||||
{
|
||||
assert( isDefined( self ) );
|
||||
|
||||
// check for active air_superiority strikes
|
||||
otherTeam = getOtherTeam( self.team );
|
||||
if ( (level.teamBased && level.teamAirDenied[ otherTeam] )
|
||||
|| (!level.teamBased && IsDefined( level.airDeniedPlayer ) && level.airDeniedPlayer == self )
|
||||
)
|
||||
{
|
||||
self IPrintLnBold( &"KILLSTREAKS_AIR_SPACE_TOO_CROWDED" );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// scramble the fighters
|
||||
self thread doStrike( lifeId, KS_NAME );
|
||||
|
||||
self maps\mp\_matchdata::logKillstreakEvent( "air_superiority", self.origin );
|
||||
self thread teamPlayerCardSplash( "used_air_superiority", self );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
doStrike( lifeId, streakName )
|
||||
{
|
||||
config = level.planeConfigs[ streakName ];
|
||||
|
||||
flightPlan = self maps\mp\killstreaks\_plane::getPlaneFlightPlan( config.distFromPlayer );
|
||||
|
||||
// play inbound vo
|
||||
|
||||
wait( 1 );
|
||||
|
||||
targetTeam = getOtherTeam(self.team);
|
||||
|
||||
level.teamAirDenied[targetTeam] = true;
|
||||
level.airDeniedPlayer = self;
|
||||
|
||||
doOneFlyby( streakName, lifeId, flightPlan.targetPos, flightPlan.flightDir, flightPlan.height);
|
||||
|
||||
self waittill( "aa_flyby_complete" );
|
||||
|
||||
// coming back around vo
|
||||
wait( 2 );
|
||||
maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
|
||||
|
||||
// don't do second flyby if owner has disconnected
|
||||
if ( IsDefined( self ) )
|
||||
{
|
||||
doOneFlyby( streakName, lifeId, flightPlan.targetPos, -1 * flightPlan.flightDir, flightPlan.height );
|
||||
|
||||
self waittill( "aa_flyby_complete" );
|
||||
}
|
||||
|
||||
level.teamAirDenied[targetTeam] = false;
|
||||
level.airDeniedPlayer = undefined;
|
||||
|
||||
// play outbound vo
|
||||
// should check if there are still enemy aircraft in the air and play appropriate vo
|
||||
}
|
||||
|
||||
doOneFlyby( streakName, lifeId, targetPos, dir, flyHeight )
|
||||
{
|
||||
config = level.planeConfigs[ streakName ];
|
||||
|
||||
// absolute height should be derived from the heightEnt
|
||||
flightPath = maps\mp\killstreaks\_plane::getFlightPath( targetPos, dir, config.halfDistance, true, flyHeight, config.speed, -0.5 * config.halfDistance, streakName );
|
||||
|
||||
// may want to break this up into spawn, move, cleanup components
|
||||
// so that we can reuse the plane
|
||||
level thread maps\mp\killstreaks\_plane::doFlyby( lifeId, self, lifeId,
|
||||
flightPath["startPoint"] + (0, 0, randomInt(config.heightRange) ),
|
||||
flightPath["endPoint"] + (0, 0, randomInt(config.heightRange) ),
|
||||
flightPath["attackTime"],
|
||||
flightPath["flyTime"],
|
||||
dir,
|
||||
streakName );
|
||||
}
|
||||
|
||||
|
||||
attackEnemyAircraft( pathEnd, flyTime, beginAttackTime, owner, streakName ) // self == plane
|
||||
{
|
||||
self endon( "death" );
|
||||
self.owner endon( "killstreak_disowned" );
|
||||
level endon( "game_ended" );
|
||||
|
||||
wait (beginAttackTime);
|
||||
|
||||
targets = findAllTargets( self.owner, self.team );
|
||||
config = level.planeConfigs[ streakName ];
|
||||
numVolleys = config.numMissileVolleys;
|
||||
targetIndex = targets.size - 1;
|
||||
|
||||
while (targetIndex >= 0
|
||||
&& numVolleys > 0
|
||||
)
|
||||
{
|
||||
target = targets[ targetIndex ];
|
||||
if ( IsDefined( target ) && IsAlive( target ) )
|
||||
{
|
||||
self fireAtTarget( target );
|
||||
numVolleys--;
|
||||
wait ( 1 );
|
||||
}
|
||||
targetIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
cleanupFlyby( owner, plane, streakName )
|
||||
{
|
||||
owner notify( "aa_flyby_complete" );
|
||||
}
|
||||
|
||||
// curTargetsStruct is a struct that holds the array of targets
|
||||
// !!! use this hack since arrays are passed by value, while structs are passed by reference
|
||||
findTargetsOfType( attacker, victimTeam, checkFunc, candidateList, curTargetsStruct )
|
||||
{
|
||||
if ( IsDefined( candidateList ) )
|
||||
{
|
||||
foreach ( target in candidateList )
|
||||
{
|
||||
if ( [[ checkFunc ]]( attacker, victimTeam, target ) )
|
||||
{
|
||||
curTargetsStruct.targets[ curTargetsStruct.targets.size ] = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return curTargetsStruct;
|
||||
}
|
||||
|
||||
// unlike the aa strike, we only search for targets once
|
||||
// because we block new air strikes from behing launched
|
||||
// also: probably could flip the order that targets are acquired if we want
|
||||
// the jets to go after low-cost killstreaks first
|
||||
findAllTargets( attacker, attackerTeam )
|
||||
{
|
||||
wrapper = SpawnStruct();
|
||||
wrapper.targets = [];
|
||||
|
||||
// ok, I'm sorry for function pointers, but it makes me sad to do unnecessary if checks all the time
|
||||
// isEnemyFunc will test if the target belongs to an enemy
|
||||
isEnemyFunc = undefined;
|
||||
if ( level.teamBased )
|
||||
{
|
||||
isEnemyFunc = ::isValidTeamTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
isEnemyFunc = ::isValidFFATarget;
|
||||
}
|
||||
victimTeam = undefined;
|
||||
if ( IsDefined( attackerTeam ) )
|
||||
{
|
||||
victimTeam = getOtherTeam( attackerTeam );
|
||||
}
|
||||
|
||||
// 2013-09-02 wallace: Since arrays are passed by value (or so JoeC tells me)
|
||||
// we will wrap up the targets array in a struct that is past by reference
|
||||
// this means that each call to findTargetsOfType is adding targets to the SAME array, not a copy
|
||||
// Destroy player controlled and higher level-KS's last, so put them in the front of the arraw
|
||||
findTargetsOfType( attacker, victimTeam, isEnemyFunc, level.heli_pilot, wrapper );
|
||||
if ( IsDefined( level.lbSniper ) )
|
||||
{
|
||||
if ( [[ isEnemyFunc ]]( attacker, victimTeam, level.lbSniper ) )
|
||||
{
|
||||
wrapper.targets[ wrapper.targets.size ] = level.lbSniper;
|
||||
}
|
||||
}
|
||||
|
||||
findTargetsOfType( attacker, victimTeam, isEnemyFunc, level.planes, wrapper );
|
||||
// 2013-09-03 wallace: ugh, this is stupid. Vanguard puts itself in both remote_uav and littlebird arrays. So, don't use remote_uav as possible targets
|
||||
// findTargetsOfType( attacker, victimTeam, checkFunc, level.remote_uav, wrapper );
|
||||
findTargetsOfType( attacker, victimTeam, isEnemyFunc, level.littleBirds, wrapper );
|
||||
findTargetsOfType( attacker, victimTeam, isEnemyFunc, level.helis, wrapper );
|
||||
|
||||
return wrapper.targets;
|
||||
}
|
||||
|
||||
fireAtTarget( curTarget ) // self == plane
|
||||
{
|
||||
if ( !isDefined(curTarget) )
|
||||
return;
|
||||
|
||||
// do this check in case the plane's owner disconnects mid flight
|
||||
// we still want this pass to finish
|
||||
owner = undefined;
|
||||
if ( IsDefined( self.owner ) )
|
||||
owner = self.owner;
|
||||
|
||||
forwardVec = 384 * AnglesToForward( self.angles );
|
||||
|
||||
startpoint = self GetTagOrigin( "tag_missile_1" ) + forwardVec;
|
||||
rocket1 = MagicBullet( kProjectileName, startPoint, startPoint + forwardVec, owner );
|
||||
rocket1.vehicle_fired_from = self;
|
||||
|
||||
startpoint = self GetTagOrigin( "tag_missile_2" ) + forwardVec;
|
||||
rocket2 = MagicBullet( kProjectileName, startPoint, startPoint + forwardVec, owner );
|
||||
rocket2.vehicle_fired_from = self;
|
||||
|
||||
missiles = [ rocket1, rocket2 ];
|
||||
curTarget notify( "targeted_by_incoming_missile", missiles );
|
||||
|
||||
self thread startMissileGuidance( curTarget, 0.25, missiles );
|
||||
}
|
||||
|
||||
startMissileGuidance( curTarget, igniteTime, missileArray )
|
||||
{
|
||||
wait( igniteTime );
|
||||
|
||||
if ( IsDefined( curTarget ) )
|
||||
{
|
||||
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 ( curTarget.model != "vehicle_av8b_harrier_jet_mp" )
|
||||
targetPoint = curTarget GetTagOrigin( "tag_missile_target" );
|
||||
if ( !IsDefined( targetPoint ) )
|
||||
{
|
||||
targetPoint = curTarget GetTagOrigin( "tag_body" );
|
||||
}
|
||||
targetOffset = targetPoint - curTarget.origin;
|
||||
|
||||
foreach ( missile in missileArray )
|
||||
{
|
||||
if ( IsValidMissile( missile ) )
|
||||
{
|
||||
missile Missile_SetTargetEnt( curTarget, targetOffset );
|
||||
missile Missile_SetFlightmodeDirect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
destroyActiveVehicles( attacker, victimTeam )
|
||||
{
|
||||
// thread all of the things that need to get destroyed, this way we can put frame waits in between each destruction so we don't hit the server with a lot at one time
|
||||
maps\mp\killstreaks\_killstreaks::destroyTargetArray( attacker, victimTeam, "aamissile_projectile_mp", level.helis );
|
||||
maps\mp\killstreaks\_killstreaks::destroyTargetArray( attacker, victimTeam, "aamissile_projectile_mp", level.littleBirds );
|
||||
maps\mp\killstreaks\_killstreaks::destroyTargetArray( attacker, victimTeam, "aamissile_projectile_mp", level.heli_pilot );
|
||||
if ( IsDefined( level.lbSniper ) )
|
||||
{
|
||||
// kind of hack, but destroyTargets does a lot of needed setup
|
||||
tempArray = [];
|
||||
tempArray[0] = level.lbSniper;
|
||||
maps\mp\killstreaks\_killstreaks::destroyTargetArray( attacker, victimTeam, "aamissile_projectile_mp", tempArray );
|
||||
}
|
||||
|
||||
maps\mp\killstreaks\_killstreaks::destroyTargetArray( attacker, victimTeam, "aamissile_projectile_mp", level.remote_uav );
|
||||
maps\mp\killstreaks\_killstreaks::destroyTargetArray( attacker, victimTeam, "aamissile_projectile_mp", level.planes );
|
||||
}
|
Reference in New Issue
Block a user