264 lines
7.0 KiB
Plaintext
264 lines
7.0 KiB
Plaintext
#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 = "gas_airstrike";
|
|
|
|
init()
|
|
{
|
|
precacheLocationSelector( "map_artillery_selector" );
|
|
|
|
config = SpawnStruct();
|
|
config.modelNames = [];
|
|
config.modelNames[ "allies" ] = "vehicle_mig29_desert";
|
|
config.modelNames[ "axis" ] = "vehicle_mig29_desert";
|
|
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 = 5000;
|
|
config.halfDistance = 15000;
|
|
config.heightRange = 500;
|
|
//config.attackTime = 2.0;
|
|
config.outboundFlightAnim = "airstrike_mp_roll";
|
|
config.onAttackDelegate = ::dropBombs;
|
|
config.onFlybyCompleteDelegate = ::cleanupFlyby;
|
|
config.chooseDirection = true;
|
|
config.selectLocationVO = "KS_hqr_airstrike";
|
|
config.inboundVO = "KS_ast_inbound";
|
|
config.bombModel = "projectile_cbu97_clusterbomb";
|
|
config.numBombs = 3;
|
|
// should be 2x the effect radius to have no gaps/overlap
|
|
config.distanceBetweenBombs = 350;
|
|
config.effectRadius = 200;
|
|
config.effectHeight = 120;
|
|
// this should be something else
|
|
// remember to precache this
|
|
//config.effectVFX = LoadFX( "fx/smoke/poisonous_gas_linger_medium_thick_killer_pulse");
|
|
config.effectVFX = LoadFX( "fx/smoke/poisonous_gas_linger_medium_thick_killer_instant");
|
|
config.effectMinDelay = 0.25;
|
|
config.effectMaxDelay = 0.5;
|
|
config.effectLifeSpan = 13;
|
|
config.effectCheckFrequency = 1.0;
|
|
config.effectDamage = 10;
|
|
config.obitWeapon = "gas_strike_mp";
|
|
config.killCamOffset = (0, 0, 60);
|
|
|
|
level.planeConfigs[ KS_NAME ] = config;
|
|
|
|
level.killstreakFuncs[KS_NAME] = ::onUse;
|
|
}
|
|
|
|
onUse( lifeId, streakName )
|
|
{
|
|
assert( isDefined( self ) );
|
|
|
|
// check for active air_superiority strikes
|
|
otherTeam = getOtherTeam( self.team );
|
|
|
|
if ( IsDefined( level.numGasStrikeActive ) )
|
|
{
|
|
self IPrintLnBold( &"KILLSTREAKS_AIR_SPACE_TOO_CROWDED" );
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
result = maps\mp\killstreaks\_plane::selectAirstrikeLocation( lifeId, KS_NAME, ::doStrike );
|
|
|
|
return ( IsDefined( result ) && result );
|
|
}
|
|
}
|
|
|
|
doStrike( lifeId, location, directionYaw, streakName )
|
|
{
|
|
level.numGasStrikeActive = 0;
|
|
|
|
wait ( 1 );
|
|
|
|
planeFlyHeight = maps\mp\killstreaks\_plane::getPlaneFlyHeight();
|
|
|
|
dirVector = AnglesToForward( (0, directionYaw, 0) );
|
|
|
|
doOneFlyby( streakName, lifeId, location, dirVector, planeFlyHeight );
|
|
|
|
self waittill( "gas_airstrike_flyby_complete" );
|
|
|
|
// play outbound 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, streakName );
|
|
|
|
// Box( targetPos, dir[1], (0, 0, 1), false, 200);
|
|
|
|
// 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 );
|
|
}
|
|
|
|
cleanupFlyby( owner, plane, streakName )
|
|
{
|
|
owner notify( "gas_airstrike_flyby_complete" );
|
|
}
|
|
|
|
|
|
dropBombs( pathEnd, flyTime, beginAttackTime, owner, streakName ) // self == plane
|
|
{
|
|
self endon( "death" );
|
|
|
|
wait (beginAttackTime);
|
|
|
|
config = level.planeConfigs[ streakName ];
|
|
|
|
numBombsLeft = config.numBombs;
|
|
timeBetweenBombs = config.distanceBetweenBombs / config.speed;
|
|
|
|
while (numBombsLeft > 0)
|
|
{
|
|
self thread dropOneBomb( owner, streakName );
|
|
|
|
numBombsLeft--;
|
|
wait ( timeBetweenBombs );
|
|
}
|
|
|
|
}
|
|
|
|
dropOneBomb( owner, streakName ) // self == plane
|
|
{
|
|
level.numGasStrikeActive++;
|
|
|
|
plane = self;
|
|
|
|
config = level.planeConfigs[ streakName ];
|
|
|
|
planeDir = AnglesToForward( plane.angles );
|
|
|
|
bomb = spawnBomb( config.bombModel, plane.origin, plane.angles );
|
|
bomb MoveGravity( ( planeDir * ( config.speed / 1.5 ) ), 3.0 );
|
|
|
|
// bomb.lifeId = requiredDeathCount;
|
|
|
|
newBomb = Spawn( "script_model", bomb.origin );
|
|
newBomb SetModel( "tag_origin" );
|
|
newBomb.origin = bomb.origin;
|
|
newBomb.angles = bomb.angles;
|
|
|
|
bomb SetModel( "tag_origin" );
|
|
wait (0.10); // wait two server frames before playing fx
|
|
|
|
bombOrigin = newBomb.origin;
|
|
bombAngles = newBomb.angles;
|
|
if ( level.splitscreen )
|
|
{
|
|
playfxontag( level.airstrikessfx, newBomb, "tag_origin" );
|
|
}
|
|
else
|
|
{
|
|
playfxontag( level.airstrikefx, newBomb, "tag_origin" );
|
|
}
|
|
|
|
wait ( 1.0 );
|
|
|
|
trace = BulletTrace(newBomb.origin, newBomb.origin + (0,0,-1000000), false, undefined);
|
|
impactPosition = trace["position"];
|
|
|
|
// Line( newBomb.origin, impactPosition, (1, 0, 0), 1, true, 20 * config.effectLifeSpan);
|
|
|
|
// artillery damage center?
|
|
|
|
// set up kill cam?
|
|
|
|
// need to wait the right amount of time before
|
|
|
|
bomb onBombImpact( owner, impactPosition, streakName );
|
|
|
|
newBomb delete();
|
|
bomb delete();
|
|
|
|
level.numGasStrikeActive--;
|
|
if (level.numGasStrikeActive == 0)
|
|
{
|
|
level.numGasStrikeActive = undefined;
|
|
}
|
|
}
|
|
|
|
|
|
spawnBomb( modelName, origin, angles )
|
|
{
|
|
bomb = Spawn( "script_model", origin );
|
|
bomb.angles = angles;
|
|
bomb SetModel( modelname );
|
|
|
|
return bomb;
|
|
}
|
|
|
|
onBombImpact( owner, position, streakName ) // self == bomb?
|
|
{
|
|
config = level.planeConfigs[ streakName ];
|
|
|
|
// position = self.origin;
|
|
|
|
effectArea = Spawn( "trigger_radius", position, 0, config.effectRadius, config.effectHeight );
|
|
effectArea.owner = owner;
|
|
|
|
effectRadius = config.effectRadius;
|
|
vfx = SpawnFx( config.effectVFX, position );
|
|
TriggerFX( vfx );
|
|
|
|
wait ( RandomFloatRange( config.effectMinDelay, config.effectMaxDelay ) );
|
|
|
|
timeRemaining = config.effectLifeSpan;
|
|
|
|
// self.primaryWeapon = config.obitWeapon;
|
|
|
|
killCamEnt = Spawn( "script_model", position + config.killCamOffset );
|
|
killCamEnt LinkTo( effectArea );
|
|
self.killCamEnt = killCamEnt;
|
|
//self.killCamEnt SetScriptMoverKillCam( "explosive" );
|
|
|
|
while ( timeRemaining > 0.0 )
|
|
{
|
|
foreach ( character in level.characters )
|
|
{
|
|
character applyGasEffect( owner, position, effectArea, self, config.effectDamage );
|
|
}
|
|
|
|
wait ( config.effectCheckFrequency );
|
|
timeRemaining -= config.effectCheckFrequency;
|
|
}
|
|
|
|
self.killCamEnt Delete();
|
|
|
|
effectArea Delete();
|
|
vfx Delete();
|
|
}
|
|
|
|
applyGasEffect( attacker, position, trigger, inflictor, damage ) // self == target
|
|
{
|
|
if( (attacker isEnemy( self )) && IsAlive( self ) && self IsTouching( trigger ) )
|
|
{
|
|
// rumble
|
|
inflictor RadiusDamage( self.origin, 1, damage, damage, attacker, "MOD_RIFLE_BULLET", "gas_strike_mp");
|
|
// self DoDamage( damage, position, attacker, inflictor, "MOD_UNKNOWN" );
|
|
|
|
if ( !(self isUsingRemote()) )
|
|
{
|
|
duration = maps\mp\perks\_perkfunctions::applyStunResistence( 2.0 );
|
|
self ShellShock( "default", duration );
|
|
}
|
|
}
|
|
} |