2025-05-21 16:23:17 +02:00

2288 lines
64 KiB
Plaintext

#include maps\mp\_utility;
#include common_scripts\utility;
#include maps\mp\gametypes\_hud_util;
#include maps\mp\_audio;
//rocket fire settings
CONST_rocket_reload_time = 6;
CONST_rocket_fire_interval = 0.05;
CONST_WARBIRD_RELOAD_MASH_TIME_RATIO = (50 / CONST_rocket_reload_time); // => 50 ms time decrease per button press / 6 sec max reload time
//warbird combat tuning
CONST_target_aquire_time = 1;
CONST_los_recheck_time = 0.25;
CONST_warbird_move_time_min = 4;
CONST_warbird_move_time_max = 8;
CONST_warbird_timeout = 30;
CONST_warbird_timeout_upgrade = 45;
//warbird cloak tuning
CONST_cloak_duration = 10;
CONST_cloak_cooldown_min_duration = 5;
CONST_second_warbird_height = 500;
init()
{
level.warbirdSetting = [];
level.warbirdSetting[ "Warbird" ] = SpawnStruct();
level.warbirdSetting[ "Warbird" ].vehicle = "warbird_player_mp";
level.warbirdSetting[ "Warbird" ].modelBase = "vehicle_xh9_warbird_low_cloaked_in_out_mp_cloak";
level.warbirdSetting[ "Warbird" ].heliType = "warbird";
level.warbirdSetting[ "Warbird" ].maxHealth = level.heli_maxhealth;
level.killstreakFuncs[ "warbird" ] = ::tryUseWarbird;
level.killstreakWieldWeapons["warbird_remote_turret_mp"] = "warbird";
level.killstreakWieldWeapons["warbird_player_turret_mp"] = "warbird";
level.killstreakWieldWeapons["warbird_missile_mp"] = "warbird";
level.killstreakWieldWeapons["paint_missile_killstreak_mp"] = "warbird";
if ( !IsDefined( level.SpawnedWarbirds ) )
level.SpawnedWarbirds = [];
if ( !IsDefined( level.warbirdInUse ) )
level.warbirdInUse = false;
level.chopper_fx["light"]["warbird"] = LoadFX( "vfx/lights/air_light_wingtip_red" );
level.chopper_fx["engine"]["warbird"] = LoadFX( "vfx/distortion/distortion_warbird_mp" );
maps\mp\killstreaks\_aerial_utility::makeHeliType( "warbird", "vfx/explosion/vehicle_warbird_explosion_midair", ::warbirdLightFX );
maps\mp\killstreaks\_aerial_utility::addAirExplosion( "warbird", "vfx/explosion/vehicle_warbird_explosion_midair" );
/#
SetDvarIfUninitialized( "scr_player_notarget", 0 );
SetDvarIfUninitialized( "scr_warbird_timeout", 0 );
SetDvarIfUninitialized( "scr_warbird_testcloak", 0 );
#/
// Coop Buddy Assistance VO
game["dialog"][ "assist_mp_warbird" ] = "ks_warbird_joinreq";
game["dialog"][ "pilot_sup_mp_warbird" ] = "pilot_sup_mp_warbird";
game["dialog"][ "pilot_aslt_mp_warbird" ] = "pilot_aslt_mp_warbird";
game["dialog"][ "ks_warbird_destroyed" ] = "ks_warbird_destroyed";
// initHeliAI();
}
tryUseWarbird( lifeId, modules )
{
if ( !self CanUseWarbird() )
{
self IPrintLnBold( &"KILLSTREAKS_AIR_SPACE_TOO_CROWDED" );
return false;
}
else if ( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxVehicleCount + 1 >= maxVehiclesAllowed() )
{
self IPrintLnBold( &"MP_TOO_MANY_VEHICLES" );
return false;
}
// increment the faux vehicle count before we spawn the vehicle so no other vehicles try to spawn
incrementFauxVehicleCount();
level.warbirdInUse = true;
hasAIOption = array_contains( modules, "warbird_ai_attack" ) || array_contains( modules, "warbird_ai_follow" );
if ( !hasAIOption )
{
self thread playerClearWarbirdOnTeamChange();
result = self maps\mp\killstreaks\_killstreaks::initRideKillstreak( "warbird" );
if ( result != "success" )
{
decrementFauxVehicleCount();
level.warbirdInUse = false;
return false;
}
self setUsingRemote( "warbird" );
}
result = self SetupWarbirdKillStreak( lifeId, modules );
if( result )
{
self maps\mp\_matchdata::logKillstreakEvent( "warbird", self.origin );
}
return result;
}
playerClearWarbirdOnTeamChange()
{
self endon( "rideKillstreakBlack" );
self endon( "rideKillstreakFailed" );
self waittill( "joined_team" );
level.warbirdInUse = false;
decrementFauxVehicleCount();
}
CanUseWarbird()
{
return ( !level.warbirdInUse );
}
IsControllingWarbird()
{
return ( IsDefined( self.ControllingWarbird ) && self.ControllingWarbird );
}
warbirdMakeVehicleSolidCapsule()
{
self endon( "death" );
//added frame for heli to spawn fully
waitframe();
//radius and offset should match vehHelicopterBoundsRadius (GDT) and bg_vehicle_sphere_bounds_offset_z.
self MakeVehicleSolidCapsule( 300, -9, 160 );
}
setupPlayerCommands( modules )
{
if ( IsBot( self ) )
return;
self NotifyOnPlayerCommand( "SwitchVisionMode" , "+actionslot 1" );
self NotifyOnPlayerCommand( "SwitchWeapon" , "weapnext" );
self NotifyOnPlayerCommand( "ToggleControlState" , "+activate" );
self NotifyOnPlayerCommand( "ToggleControlCancel", "-activate" );
self NotifyOnPlayerCommand( "ToggleControlState" , "+usereload" );
self NotifyOnPlayerCommand( "ToggleControlCancel", "-usereload" );
self NotifyOnPlayerCommand( "StartFire" , "+attack" );
self NotifyOnPlayerCommand( "StartFire" , "+attack_akimbo_accessible" );
if ( IsDefined( modules ) && array_contains( modules, "warbird_cloak" ) )
self NotifyOnPlayerCommand( "Cloak" , "+smoke" );
}
disablePlayercommands( warbird )
{
if ( IsBot( self ) )
return;
self NotifyOnPlayerCommandRemove( "SwitchVisionMode" , "+actionslot 1" );
self NotifyOnPlayerCommandRemove( "SwitchWeapon" , "weapnext" );
self NotifyOnPlayerCommandRemove( "ToggleControlState" , "+activate" );
self NotifyOnPlayerCommandRemove( "ToggleControlCancel", "-activate" );
self NotifyOnPlayerCommandRemove( "ToggleControlState" , "+usereload" );
self NotifyOnPlayerCommandRemove( "ToggleControlCancel", "-usereload" );
self NotifyOnPlayerCommandRemove( "StartFire" , "+attack" );
self NotifyOnPlayerCommandRemove( "StartFire" , "+attack_akimbo_accessible" );
if ( IsDefined( warbird ) && warbird.canCloak )
self NotifyOnPlayerCommandRemove( "Cloak" , "+smoke" );
}
SetupWarbirdKillStreak( lifeId, modules )
{
self endon( "warbirdStreakComplete" );
self setupPlayerCommands( modules );
self.PossessWarbird = false;
self.ControllingWarbird = false;
self.WarbirdInit = true;
flightPathNodes = BuildValidFlightPaths();
SpawnPoint = FindBestSpawnLocation( flightPathNodes );
SpawnPoint = RotateHeliSpawn( SpawnPoint );
warbird = SpawnHelicopter( self, SpawnPoint.origin, SpawnPoint.angles, level.warbirdSetting[ "Warbird" ].vehicle, level.warbirdSetting[ "Warbird" ].modelBase );
warbird.currentNode = SpawnPoint;
if ( !IsDefined( warbird ) )
return false;
warbird thread warbird_audio();
warbird Hide();
warbird thread warbirdMakeVehicleSolidCapsule();
warbird.TargetEnt = Spawn( "script_origin", ( 0, 0, 0 ) );
warbird.vehicleType = "Warbird";
warbird.heli_type = level.warbirdSetting[ "Warbird" ].heliType;//level.warbirdSetting[ "Warbird" ].modelBase;
warbird.heliType = level.warbirdSetting[ "Warbird" ].heliType;
warbird.attractor = Missile_CreateAttractorEnt( warbird, level.heli_attract_strength, level.heli_attract_range );
warbird.lifeId = lifeId;
warbird.team = self.pers[ "team" ];
warbird.pers[ "team" ] = self.pers[ "team" ];
warbird.owner = self;
warbird.maxhealth = level.warbirdSetting[ "Warbird" ].maxHealth;
warbird.zOffset = ( 0, 0, 0 );
warbird.targeting_delay = level.heli_targeting_delay;
warbird.primaryTarget = undefined;
warbird.secondaryTarget = undefined;
warbird.attacker = undefined;
warbird.currentstate = "ok";
warbird.pickNewTarget = true;
warbird.lineOfSight = false;
warbird.overheattime = 6;
warbird.firetime = 0;
warbird.weaponfire = false;
warbird.IsMoving = true;
warbird.CloakCooldown = 0;
warbird.isCrashing = false;
warbird.IsPossessed = false;
warbird.modules = modules;
warbird.aiAttack = array_contains( warbird.modules, "warbird_ai_attack" );
warbird.aiFollow = array_contains( warbird.modules, "warbird_ai_follow" );
warbird.hasAI = ( warbird.aiAttack || warbird.aiFollow );
warbird.canCloak = array_contains( warbird.modules, "warbird_cloak" );
warbird.hasRockets = array_contains( warbird.modules, "warbird_rockets" );
warbird.coopOffensive = array_contains( warbird.modules, "warbird_coop_offensive" );
warbird.extraFlare = array_contains( warbird.modules, "warbird_flares" );
if ( warbird.extraFlare )
warbird.numExtraFlares = 1;
else
warbird.numExtraFlares = 0;
if ( warbird.hasRockets )
warbird.RocketClip = 3;
else
warbird.RocketClip = 0;
warbird.RemainingRocketShots = warbird.RocketClip;
//add global usable that the user can activate to possess the warbird
if ( warbird.hasAI )
{
warbird.UsableEnt = Spawn( "script_origin", (0, 0, 0) );
warbird.UsableEnt LinkTo( warbird );
warbird.UsableEnt makeGloballyUsableByType( "killstreakRemote", &"MP_WARBIRD_PLAYER_PROMPT", self );
}
//------------------
warbird thread [[ level.lightFxFunc[ "warbird" ] ]]();
warbird make_entity_sentient_mp( warbird.team );
if(!IsDefined(level.SpawnedWarbirds))
level.SpawnedWarbirds = [];
level.SpawnedWarbirds = array_add(level.SpawnedWarbirds,warbird);
warbird maps\mp\killstreaks\_aerial_utility::addToHeliList();
warbird thread maps\mp\killstreaks\_aerial_utility::heli_flares_monitor( warbird.numExtraFlares );
warbird thread maps\mp\killstreaks\_aerial_utility::heli_leave_on_disconnect( self );
warbird thread maps\mp\killstreaks\_aerial_utility::heli_leave_on_changeTeams( self );
warbird thread maps\mp\killstreaks\_aerial_utility::heli_leave_on_gameended( self );
lifeSpan = CONST_warbird_timeout;
if ( array_contains( warbird.modules, "warbird_time" ) )
lifeSpan = CONST_warbird_timeout_upgrade;
if ( self _hasPerk( "specialty_blackbox" ) && IsDefined( self.specialty_blackbox_bonus ) )
{
lifeSpan *= self.specialty_blackbox_bonus;
}
/#
if ( GetDvar( "scr_warbird_timeout", "0" ) != "0" )
lifeSpan = GetDvarFloat( "scr_warbird_timeout" );
#/
warbird.endTime = GetTime() + ( lifeSpan * 1000 );
warbird thread maps\mp\killstreaks\_aerial_utility::heli_leave_on_timeout( lifeSpan );
warbird thread maps\mp\killstreaks\_aerial_utility::heli_monitorEMP();
warbird thread maps\mp\gametypes\_damage::setEntityDamageCallback( warbird.maxhealth, undefined, ::warbirdOnDeath, maps\mp\killstreaks\_aerial_utility::heli_ModifyDamage, true );
warbird thread warbird_health();
warbird thread maps\mp\killstreaks\_aerial_utility::heli_existance();
self thread MonitorAIWarbirdDeathorTimeout( warbird );
self thread MonitorPlayerDisconnect( warbird );
warbird.warbirdTurret = warbird spawn_warbird_turret( "warbird_remote_turret_mp", "vehicle_xh9_warbird_turret_cloaked_inout_killstreak_mp_cloak", "tag_player_mp", false );
warbird.warbirdTurret Hide();
if ( !warbird.aiAttack && !warbird.aiFollow )
warbird.warbirdTurret ShowToPlayer( self );
buddyTurretWeaponInfo = "orbitalsupport_big_turret_mp";
if ( warbird.coopOffensive )
buddyTurretWeaponInfo = "warbird_remote_turret_mp";
warbird.warbirdBuddyTurret = warbird spawn_warbird_turret( buddyTurretWeaponInfo, "vehicle_xh9_warbird_turret_cloaked_inout_killstreak_mp_cloak", "tag_playerbuddy_mp", true );
warbird.warbirdBuddyTurret Hide();
self thread SetupCloaking( warbird );
thread WarbirdOverheatBarColorMonitor( warbird, warbird.warbirdTurret );
if ( warbird.aiAttack || warbird.aiFollow )
{
self thread playerMonitorWarbirdPossession( warbird );
}
else
{
self thread PlayerControlWarbirdSetup( warbird );
}
/#
thread testFlares( self );
#/
if(IsDefined(warbird))
{
if ( level.teamBased )
level thread handleCoopJoining( warbird, self );
return true;
}
else
return false;
}
playerMonitorWarbirdPossession( warbird ) // self == player
{
self endon( "warbirdStreakComplete" );
warbird waittill( "cloaked" );
waitframe();
while (true)
{
self MonitorAIWarbirdSwitch( warbird );
warbird.UsableEnt waittill( "trigger" );
self thread manuallyJoinWarbird();
self PlayerControlWarbirdSetup( warbird );
}
}
manuallyJoinWarbird()
{
self.manuallyJoiningKillStreak = true;
self waittill_any( "death", "initRideKillstreak_complete", "warbirdStreakComplete" );
self.manuallyJoiningKillStreak = false;
}
warbirdOnDeath( attacker, weapon, meansOfDeath, damage )
{
self maps\mp\gametypes\_damage::onKillstreakKilled( attacker, weapon, meansOfDeath, damage, "warbird_destroyed", "ks_warbird_destroyed", "callout_destroyed_warbird", true );
}
SetupCloaking( warbird )
{
warbird.cloakState = 0;
self CloakingTransition( warbird, true, true ); // turn cloaking on to force a state change when we make it visible
}
////=================================================================================================================//
//// WARBIRD HUD //
////=================================================================================================================//
WarbirdRocketHudUpdate( warbird )
{
if ( !warbird.hasRockets )
return;
switch(warbird.RemainingRocketShots)
{
case 0:
self SetClientOmnvar( "ui_warbird_missile", 0 );
break;
case 1:
self SetClientOmnvar( "ui_warbird_missile", 1 );
break;
case 2:
self SetClientOmnvar( "ui_warbird_missile", 2 );
break;
case 3:
self SetClientOmnvar( "ui_warbird_missile", 3 );
break;
}
}
SetupWarbirdHud( warbird, isBuddy, primaryPlayer ) //self = player, primaryPlayer = the killstreak's primary owner, if coop
{
self endon( "warbirdStreakComplete" );
warbird endon( "death" );
self endon( "ResumeWarbirdAI" );
if ( !IsDefined( isBuddy ) )
isBuddy = false;
// Anyone spectating this player should be forced into first person
self ForceFirstPersonWhenFollowed();
self maps\mp\killstreaks\_aerial_utility::playerDisableStreakStatic();
wait( 0.05 );
if ( isBuddy )
self SetClientOmnvar( "ui_warbird_toggle", 2 );
else
self SetClientOmnvar( "ui_warbird_toggle", 1 );
self maps\mp\killstreaks\_aerial_utility::playerEnableStreakStatic();
self SetClientOmnvar( "ui_warbird_cloak", false );
self SetClientOmnvar( "ui_warbird_countdown", warbird.endTime ); //UI countdowns automatically subtract the current match time, so we have to add it back here with GetTime().
if ( !isBuddy )
self WarbirdRocketHudUpdate( warbird );
if ( isBuddy && !warbird.coopOffensive )
self SetClientOmnvar( "ui_warbird_weapon", 3 );
else if ( isBuddy && warbird.coopOffensive )
self SetClientOmnvar( "ui_warbird_weapon", 0 );
else if ( warbird.hasRockets )
self SetClientOmnvar( "ui_warbird_weapon", 1 );
else
self SetClientOmnvar( "ui_warbird_weapon", 0 );
if( isBuddy )
{
coop_primary_num = primaryPlayer getEntityNumber();
self SetClientOmnvar( "ui_coop_primary_num", coop_primary_num );
}
if ( warbird.canCloak && !isBuddy )
self SetClientOmnvar( "ui_warbird_cloaktext", 1 );
else
self SetClientOmnvar( "ui_warbird_cloaktext", 0 );
self SetClientOmnvar( "ui_killstreak_optic", false );
}
WarbirdOverheatBarColorMonitor( warbird, warbirdTurret )
{
self endon( "warbirdStreakComplete" );
warbird endon( "death" );
while( true )
{
warbirdTurret.heat_level = warbirdTurret GetTurretHeat();
self SetClientOmnvar( "ui_warbird_heat", warbirdTurret.heat_level );
isOverheated = false;
if ( IsDefined( warbirdTurret ) )
isOverheated = warbirdTurret IsTurretOverheated();
if ( isOverheated )
{
self SetClientOmnvar( "ui_warbird_fire", 1 );
}
else if ( warbirdTurret.heat_level > 0.7 )
{
self SetClientOmnvar( "ui_warbird_fire", 2 );
}
else
{
self SetClientOmnvar( "ui_warbird_fire", 0 );
}
// if ( isOverheated )
// level thread handleOverheatWithMashHelp( self, warbirdTurret );
while ( isOverheated )
{
wait 0.05;
isOverheated = warbirdTurret IsTurretOverheated();
warbirdTurret.heat_level = warbirdTurret GetTurretHeat();
self SetClientOmnvar( "ui_warbird_heat", warbirdTurret.heat_level );
}
self notify( "overheatFinished" );
waitframe();
}
}
//handleOverheatWithMashHelp( player, warbirdTurret )
//{
// warbirdTurret endon( "death" );
//
// heatDecreasePerButtonUp = ( 1 / 3 ) / 40;
//
// maxDecreaseHeat = 0.3;
//
//// numTimes = 0;
//// startTime = GetTime();
//
// while ( true )
// {
// result = player waittill_any_return_no_endon_death( "ToggleControlCancel", "overheatFinished" );
// if ( IsDefined( result ) && result == "overheatFinished" )
// break;
//
// isOverheated = warbirdTurret IsTurretOverheated();
// if ( !isOverheated )
// break;
//
// if ( maxDecreaseHeat - heatDecreasePerButtonUp >= 0 )
// {
// heat = warbirdTurret GetTurretHeat();
// heat -= heatDecreasePerButtonUp;
// maxDecreaseHeat -= heatDecreasePerButtonUp;
// heat = clamp( heat, 0, 1 );
// warbirdTurret SetTurretHeatWhenOverheating( heat );
//// numTimes++;
// }
// }
//
//// time = (GetTime() - startTime)/1000;
//// heatRemoved = (numTimes * heatDecreasePerButtonUp);
//// PrintLn( "Heat: NumUps: " + numTimes + ", HeatRemoved: " + heatRemoved + ", TimeReload: " + time );
//}
////=================================================================================================================//
//// TURRET SETUP //
////=================================================================================================================//
/*
=============
"Summary: returns a misc_turret that is attached self (a warbird)."
"<turretweaponinfo>: the turret type from turretsettings.gdt"
"<modelname>: the model to use for the turret"
"<linktotag>: the tag to which the turret will be attached"
=============
*/
spawn_warbird_turret( turretweaponinfo, modelname, linktotag, isBuddy )
{
spawned_turret = SpawnTurret( "misc_turret", self GetTagOrigin( linktotag ), turretweaponinfo, false );
spawned_turret.angles = self GetTagAngles( linktotag );
spawned_turret SetModel( modelname );
spawned_turret SetDefaultDropPitch( 45.0 );
spawned_turret LinkTo( self, linktotag, ( 0,0,0 ), ( 0,0,0 ) );
spawned_turret.owner = self.owner;
spawned_turret.health = 99999;
spawned_turret.maxHealth = 1000;
spawned_turret.damageTaken = 0;
spawned_turret.stunned = false;
spawned_turret.stunnedTime = 0.0;
spawned_turret SetCanDamage( false );
spawned_turret SetCanRadiusDamage( false );
spawned_turret.team = self.team;
spawned_turret.pers["team"] = self.team;
if ( level.teamBased )
{
spawned_turret SetTurretTeam( self.team );
}
spawned_turret SetMode( "sentry_manual" );
spawned_turret SetSentryOwner( self.owner );
spawned_turret SetTurretMinimapVisible( false );
spawned_turret.chopper = self;
if ( isBuddy )
{
spawned_turret.fireSoundent = Spawn( "script_model", self GetTagOrigin( linktotag ) );
spawned_turret.fireSoundent SetModel( "tag_origin" );
spawned_turret.fireSoundent LinkToSynchronizedParent( self, linktotag, ( 0, 0, 0 ), ( 0, 0, 0 ) );
}
return spawned_turret;
}
takeover_warbird_turret_buddy( warbird )
{
if ( getDvarInt( "camera_thirdPerson" ) )
self setThirdPersonDOF( false );
warbird.warbirdBuddyTurret.owner = self;
warbird.warbirdBuddyTurret SetMode( "sentry_manual" );
warbird.warbirdBuddyTurret SetSentryOwner( self );
self PlayerLinkWeaponViewToDelta( warbird.warbirdBuddyTurret, "tag_player", 0, 180, 180, -20, 180, false );
self PlayerLinkedSetViewZNear( false );
self PlayerLinkedSetUseBaseAngleForViewClamp( true );
self RemoteControlTurret( warbird.warbirdBuddyTurret, 45, warbird.angles[1] );
}
////=================================================================================================================//
//// WARBIRD SPAWN LOGIC //
////=================================================================================================================//
FindBestSpawnLocation(AttackPoints)
{
SpawnPoints = get_array_of_closest( self.origin, AttackPoints );
return SpawnPoints[ 0 ];
}
RotateHeliSpawn( SpawnPoint )
{
MapCenter = maps\mp\killstreaks\_aerial_utility::getHeliAnchor();
//Get the spawn forward direction as a vector
SpawnPointForward = AnglesToForward( SpawnPoint.angles );
//Get a vector from the spawn to the center
VectorToCenter = MapCenter.origin - SpawnPoint.origin;
//vector to angles
NewOrientation = VectorToAngles( VectorToCenter );
SpawnPoint.angles = NewOrientation;
return SpawnPoint;
}
BuildValidFlightPaths()
{
self endon( "warbirdStreakComplete" );
if ( !IsDefined( level.warbirdFlightPathNodes ) )
level.warbirdFlightPathNodes = [];
else
return level.warbirdFlightPathNodes;
firstNode = maps\mp\killstreaks\_aerial_utility::getEntOrStruct( "heli_loop_start", "targetname" );
prevNode = firstNode;
warbirdHeight = maps\mp\killstreaks\_aerial_utility::getHeliAnchor();
heightOriginZ = warbirdHeight.origin[2];
while ( true )
{
nextNode = maps\mp\killstreaks\_aerial_utility::getEntOrStruct( prevNode.target, "targetname" );
prevNode.next = nextNode;
nextNode.prev = prevNode;
nextNode.origin = ( nextNode.origin[0], nextNode.origin[1], heightOriginZ );
if ( IsInArray( level.warbirdFlightPathNodes, nextNode ) )
break;
level.warbirdFlightPathNodes = array_add( level.warbirdFlightPathNodes, nextNode );
prevNode = nextNode;
}
foreach ( node in level.warbirdflightPathNodes )
{
Assert( IsDefined( node.next ) );
assert( IsDefined( node.prev ) );
}
return level.warbirdFlightPathNodes;
}
IsInArray( array, Ent )
{
if ( IsDefined( array ) )
{
foreach ( Index in array )
{
if ( Index == Ent )
return true;
}
}
return false;
}
////=================================================================================================================//
//// WARBIRD DEATH & BOUNDARY //
////=================================================================================================================//
MonitorWarbirdSafeArea( warbird )
{
self endon( "warbirdStreakComplete" );
self endon( "ResumeWarbirdAI" );
self thread maps\mp\killstreaks\_aerial_utility::playerHandleBoundaryStatic( warbird, "warbirdStreakComplete", "ResumeWarbirdAI" );
warbird waittill( "outOfBounds" );
wait 2;
warbird thread maps\mp\killstreaks\_aerial_utility::heli_leave();
}
////=================================================================================================================//
//// AI Movement //
////=================================================================================================================//
WarbirdAIAttack( warbird )
{
self thread WarbirdFire( warbird );
self thread WarbirdLookAtEnemy( warbird );
self thread WarbirdMoveToAttackPoint( warbird );
// self thread debugEnemy( warbird );
}
//debugEnemy( warbird )
//{
// self endon( "warbirdPlayerControlled" );
// self endon( "warbirdStreakComplete" );
// while ( true )
// {
// if ( IsDefined( warbird.enemy_target ) )
// Line( warbird.origin, warbird.enemy_target.origin, ( 0, 1, 0 ), 1 );
//
// waitframe();
// }
//}
WarbirdMoveToAttackPoint( warbird )
{
self endon( "warbirdPlayerControlled" );
self endon( "warbirdStreakComplete" );
baseSpeed = 40;
warbird Vehicle_SetSpeed( baseSpeed, baseSpeed / 4, baseSpeed / 4 );
warbird SetNearGoalNotifyDist( 100 );
nextNode = warbird.currentNode;
// get to the closest node
if ( !IsDefined( nextNode ) )
{
SortedNodes = get_array_of_closest( warbird.origin, BuildValidFlightPaths() );
start = warbird.origin;
for ( i = 0; i < SortedNodes.size; i++ )
{
end = SortedNodes[i].origin;
if ( maps\mp\killstreaks\_aerial_utility::flyNodeOrgTracePassed( start, end, warbird ) )
{
dir = end - start;
dist = Distance( start, end );
dirRight = RotateVector( dir, ( 0, 90, 0 ) );
startWing = start + ( dirRight * 100 );
endWing = startWing + ( dir * dist );
if ( maps\mp\killstreaks\_aerial_utility::flyNodeOrgTracePassed( startWing, endWing, warbird ) )
{
dirLeft = RotateVector( dir , ( 0, -90, 0 ) );
startWing = start + ( dirLeft * 100 );
endWing = startWing + ( dir * dist );
if ( maps\mp\killstreaks\_aerial_utility::flyNodeOrgTracePassed( startWing, endWing, warbird ) )
{
nextNode = SortedNodes[i];
break;
}
}
}
waitframe();
}
}
else
{
nextNode = nextNode.next;
}
if ( !IsDefined( nextNode ) )
return;
while ( true )
{
stopAtNode = false;
if ( warbird.aiFollow )
stopAtNode = true;
warbird SetVehGoalPos( nextNode.origin, stopAtNode );
warbird.IsMoving = true;
warbird waittill( "near_goal" );
warbird.currentNode = nextNode;
warbird.IsMoving = false;
nextNode = waitUntilMoveReturnNode( warbird );
warbird.currentNode = undefined;
}
}
waitUntilMoveReturnNode( warbird )
{
if ( warbird.aiFollow && IsDefined( warbird.owner ) )
{
curNode = warbird.currentNode;
prevNode = curNode.next;
nextNode = curNode.prev;
while ( IsDefined( warbird.owner ) )
{
curDistSq = Distance2DSquared( warbird.owner.origin, curNode.origin );
prevDistSq = Distance2DSquared( warbird.owner.origin, prevNode.origin );
nextDistSq = Distance2DSquared( warbird.owner.origin, nextNode.origin );
if ( prevDistSq < curDistSq && prevDistSq < nextDistSq )
return prevNode;
else if ( nextDistSq < curDistSq && nextDistSq < prevDistSq )
return nextNode;
waitframe();
}
}
else // aiattack
{
// wait( RandomFloatRange( CONST_warbird_move_time_min, CONST_warbird_move_time_max ) );
return warbird.currentNode.next;
}
}
WarbirdLookAtEnemy( warbird )
{
self endon( "warbirdPlayerControlled" );
self endon( "warbirdStreakComplete" );
while ( 1 )
{
if ( IsDefined( warbird.enemy_target ) )
{
MonitorLookAtEnt( warbird );
warbird.warbirdTurret ClearTargetEntity();
}
waitframe();
}
}
MonitorLookAtEnt( warbird )
{
self endon( "warbirdPlayerControlled" );
self endon( "warbirdStreakComplete" );
warbird endon( "pickNewTarget" );
warbird SetLookAtEnt( warbird.enemy_target );
warbird.warbirdTurret SetTargetEntity( warbird.enemy_target );
warbird.enemy_target waittill_either( "death", "disconnect" );
warbird.pickNewTarget = true;
warbird.lineOfSight = false;
}
////=================================================================================================================//
//// AI ATTACK //
////=================================================================================================================//
WarbirdFire( warbird )
{
self endon( "warbirdPlayerControlled" );
self endon( "warbirdStreakComplete" );
thread FireAi( warbird );
while ( true )
{
if ( warbird.pickNewTarget )
{
allGuys = level.participants;
enemyTargets = [];
foreach ( guy in allGuys )
{
/#
if ( !IsAI( guy ) && GetDvar( "scr_player_notarget", 0 ) != "0" )
continue;
#/
if ( guy.team != self.team )
enemyTargets = array_add( enemyTargets, guy );
}
if ( warbird.aiAttack )
enemyTargets = SortByDistance( enemyTargets, warbird.origin );
else
enemyTargets = SortByDistance( enemyTargets, self.origin );
enemy_target = undefined;
foreach ( guy in enemyTargets )
{
if ( !IsDefined( guy ) )
continue;
if ( !IsAlive( guy ) )
continue;
if ( guy _hasPerk( "specialty_blindeye" ) )
continue;
// 5 second ignore on spawn
if ( isDefined( guy.spawntime ) && ( ( ( GetTime() - guy.spawntime ) / 1000 ) < 5 ) )
continue;
enemy_target = guy;
warbird.enemy_target = enemy_target;
CheckWarbirdTargetLos( warbird );
break;
}
}
warbird notify( "LostLOS" );
wait( 0.05 );
}
}
FireAi( warbird )
{
self endon( "warbirdPlayerControlled" );
self endon( "warbirdStreakComplete" );
warbird.RemainingRocketShots = warbird.RocketClip;
while ( true )
{
waitframe();
if ( !IsDefined( warbird.enemy_target ) || !IsAlive( warbird.enemy_target ) || !warbird.lineOfSight )
continue;
if ( warbird.hasRockets && warbird.RemainingRocketShots )
{
FireAiRocket( warbird );
}
warbird.warbirdTurret ShootTurret();
}
}
FireAiRocket( warbird )
{
missile_tag_origin = warbird GetTagOrigin( "tag_missile_right" );
player_forward = VectorNormalize( AnglesToForward( warbird.angles ) );
warbird_velocity = warbird Vehicle_GetVelocity();
missile = MagicBullet( "warbird_missile_mp", missile_tag_origin + warbird_velocity / 10, self GetEye() + warbird_velocity + player_forward * 1000, self );
missile.killCamEnt = warbird;
PlayFXOnTag( level.chopper_fx[ "rocketlaunch" ][ "warbird" ], warbird, "tag_missile_right" );
missile Missile_SetTargetEnt( warbird.enemy_target );
missile Missile_SetFlightmodeDirect();
warbird.RemainingRocketShots--;
if ( warbird.RemainingRocketShots <= 0 )
thread WarbirdAiRocketReload( warbird );
waittillRocketDeath( warbird, missile );
}
WarbirdAiRocketReload( warbird )
{
warbird endon( "warbirdStreakComplete" );
wait CONST_rocket_reload_time;
warbird.RemainingRocketShots = warbird.RocketClip;
}
waittillRocketDeath( warbird, missile )
{
warbird.enemy_target endon( "death" );
warbird.enemy_target endon( "disconnect" );
missile waittill( "death" );
}
CheckWarbirdTargetLos( warbird )
{
self endon( "warbirdPlayerControlled" );
self endon( "warbirdStreakComplete" );
warbird.enemy_target endon( "death" );
warbird.enemy_target endon( "disconnect" );
while ( true )
{
// occasionally check if you still have LOS to target
turret_flash_pos = warbird GetTagOrigin( "TAG_FLASH1" );
target_pos = warbird.enemy_target GetEye();
target_dir = VectorNormalize( target_pos - turret_flash_pos );
start_pos = turret_flash_pos + ( target_dir * 20 );
trace = BulletTrace( start_pos, target_pos, false, warbird, false, false, false, false, false );
if ( !CheckTargetIsInVision( warbird ) && trace["fraction"] < 1 )
{
warbird.lineOfSight = false;
warbird.pickNewTarget = true;
warbird.enemy_target = undefined;
warbird notify( "pickNewTarget" );
return;
}
warbird.lineOfSight = true;
wait CONST_los_recheck_time;
}
}
CheckTargetIsInVision( warbird )
{
WarbirdForward = AnglesToForward( warbird.angles );
WarbirdToEnemyLocation = warbird.enemy_target.origin - warbird.origin;
DotProductToEnemyLocation = VectorDot( WarbirdForward, WarbirdToEnemyLocation );
return DotProductToEnemyLocation < 0;
}
////=================================================================================================================//
//// PLAYER CONTROL //
////=================================================================================================================//
PlayerControlWarbirdSetup( warbird )
{
self endon( "warbirdStreakComplete" );
self.PossessWarbird = true;
self.ControllingWarbird = true;
warbird.player = self;
warbird.currentNode = undefined;
self playerSaveAngles();
waitframe();
self notify( "warbirdPlayerControlled" );
warbird.IsPossessed = true;
warbird.killCamStartTime = undefined;
warbird.warbirdTurret.killCamEnt = undefined;
//set the using remote before setting weapon or initing the ride killstreak so that it is disabled properly for warbird death & timeouts
if(self.WarbirdInit != true)
{
self _giveWeapon( "killstreak_predator_missile_mp" );
self SwitchToWeapon( "killstreak_predator_missile_mp" );
while ( self GetCurrentWeapon() != "killstreak_predator_missile_mp" )
waitframe();
self thread PlayerDoRideKillstreak( warbird, false );
self waittill( "initRideKillstreak_complete", success );
if ( !success )
return;
self setUsingRemote( "Warbird" );
}
self thread SetupWarbirdHud( warbird );
self thread MonitorWarbirdSafeArea( warbird );
// with the way we do visionsets we need to wait for the clearRideIntro() is done before we set thermal
self thread waitSetThermal( 0.5 );
self thread setWarbirdVisionSetPerMap( 0.5 );
self EnableSlowAim(.3,.3);
self pauseWarbirdEngineFXForPlayer( warbird );
warbird.PlayerAttachPoint = Spawn( "script_model", ( 0, 0, 0 ) );
warbird.PlayerAttachPoint SetModel( "tag_player" );
warbird.PlayerAttachPoint Hide();
WarbirdPlayerTagOrigin = ( warbird GetTagOrigin( "tag_origin" ) );
WarbirdPlayerTagAngles = warbird GetTagAngles( "tag_origin" );
forward = AnglesToForward( WarbirdPlayerTagAngles );
WarbirdPlayerTagOrigin = WarbirdPlayerTagOrigin + ( forward * 165 );
WarbirdPlayerTagOrigin += ( 0, 0, -10 );
warbird.PlayerAttachPoint.origin = WarbirdPlayerTagOrigin;
warbird.PlayerAttachPoint.angles = WarbirdPlayerTagAngles;
warbird.PlayerAttachPoint LinkTo( warbird, "tag_player_mp" );
//warbird VehicleTurretControlOn( self );
self Unlink();
warbird CancelAIMove( warbird );
self thread WarbirdRocketDamageIndicator( warbird );
//self thread WarbirdFreeRangeMode( warbird );
self RemoteControlVehicle( warbird );
self thread WeaponSetup( warbird );
self thread PlayerCloakReady( warbird );
warbird.warbirdTurret SetMode( "sentry_manual" );
self RemoteControlTurret( warbird.warbirdTurret, 45 );
while ( self.PossessWarbird )
self ExitWarbirdControlState( warbird );
self playerRestoreAngles();
if ( !warbird.aiAttack && !warbird.aiFollow )
warbird thread maps\mp\killstreaks\_aerial_utility::heli_leave();
}
setWarbirdVisionSetPerMap( delay ) // self == player
{
self endon( "disconnect" );
self endon( "warbirdStreakComplete" );
wait( delay );
if ( IsDefined( level.warbirdVisionSet ) )
{
self SetClientTriggerVisionSet( level.warbirdVisionSet, 0 );
}
// self maps\mp\killstreaks\_aerial_utility::handle_player_starting_aerial_view();
}
removeWarbirdVisionSetPerMap( delay ) // self == player
{
self SetClientTriggerVisionSet( "", delay );
// self maps\mp\killstreaks\_aerial_utility::handle_player_ending_aerial_view();
}
PlayerDoRideKillstreak( warbird, isBuddy )
{
if ( !IsDefined( isBuddy ) )
isBuddy = false;
type = "warbird";
if ( isBuddy )
type = "coop";
result = self maps\mp\killstreaks\_killstreaks::initRideKillstreak( type );
if ( result != "success" || ( isBuddy && !level.warbirdInUse ) || !IsDefined( warbird ) || ( IsDefined( warbird.isleaving ) && warbird.isleaving ) )
{
if ( isBuddy )
self removeWarbirdBuddy( warbird, result == "disconnect" );
else if ( result != "disconnect" )
self playerReset( warbird );
self notify( "initRideKillstreak_complete", false );
return;
}
self notify( "initRideKillstreak_complete", true );
}
ExitWarbirdControlState( warbird )
{
self endon( "warbirdStreakComplete" );
self waittill( "ToggleControlState" );
self thread CancelExitButtonPressMonitor();
self.PossessWarbird = false;
wait 0.5;
self notify( "ExitHoldTimeComplete" );
}
CancelExitButtonPressMonitor()
{
self endon( "warbirdStreakComplete" );
self endon( "ExitHoldTimeComplete" );
self waittill( "ToggleControlCancel" );
self.PossessWarbird = true;
}
waitSetThermal( delay )
{
self endon( "warbirdStreakComplete" );
self endon( "ResumeWarbirdAI" );
wait( delay );
self ThermalVisionFOFOverlayOn();
self SetBlurForPlayer( 1.1, 0 );
adsAperature = 135;
adsFocalDistance = 0;
normalAperature = 60;
normalFocalDistance = 0;
focusSpeed = 12;
aperatureSpeed = 5;
self maps\mp\killstreaks\_aerial_utility::thermalVision( "warbirdThermalOff", adsAperature, adsFocalDistance, normalAperature, normalFocalDistance, focusSpeed, aperatureSpeed );
}
//=================================================================================================================//
// PLAYER CLOAK //
//=================================================================================================================//
PlayerCloakReady( warbird, init )
{
self endon( "warbirdStreakComplete" );
self endon( "ResumeWarbirdAI" );
/#
if ( GetDvar( "scr_warbird_testcloak", 0 ) != "0" )
self thread playerTestCloak();
#/
if(IsDefined(self.WarbirdInit) && self.WarbirdInit==true)
{
warbird waittill( "cloaked" );
self waittill_any_return_no_endon_death( "ForceUncloak", "Cloak", "ResumeWarbirdAI" );
self SwitchToVisible( warbird );
warbird.PlayerAttachPoint play_sound_on_entity( "warbird_cloak_deactivate" );
//warbird HideAllParts();
//waitframe();
//warbird ShowAllParts();
}
while( true )
{
thread PlayerCloakActivated( warbird );
thread PlayerCloakCooldown( warbird );
//wait the current cloak cooldown before switching to ready.
if(warbird.CloakCooldown != 0)
{
self SetClientOmnvar( "ui_warbird_cloaktext", 3 );
wait warbird.CloakCooldown;
}
self thread CloakReadyDialog();
if ( warbird.canCloak )
self SetClientOmnvar( "ui_warbird_cloaktext", 1 );
self waittill( "Cloak" );
self notify( "ActivateCloak" );
warbird play_sound_on_entity( "warbird_cloak_activate" );
/#
if ( GetDvar( "scr_warbird_testcloak", 0 ) != "0" )
continue;
#/
//the cloak has been used and has fully recharged.
self waittill( "CloakCharged" );
}
}
/#
playerTestCloak()
{
self endon( "warbirdStreakComplete" );
while ( true )
{
if ( level.player SecondaryOffhandButtonPressed() )
{
self notify( "Cloak" );
wait 3;
}
waitframe();
}
}
#/
PlayerCloakActivated( warbird )
{
self endon( "warbirdStreakComplete" );
self endon( "ResumeWarbirdAI" );
self waittill( "ActivateCloak" );
cloakMS = CONST_cloak_duration * 1000;
self SetClientOmnvar( "ui_warbird_cloaktime", cloakMS + GetTime() );
self SwitchToCloaked( warbird );
self thread CloakActivatedDialog( warbird );
self SetClientOmnvar( "ui_warbird_cloaktext", 2 );
warbird.CloakCooldown = CONST_cloak_cooldown_min_duration;
thread CloakCooldown( warbird );
self thread PlayerCloakWaitForExit( warbird );
}
PlayerCloakCooldown( warbird )
{
self endon( "warbirdStreakComplete" );
self waittill( "UnCloak" );
self thread PlayCloakOverheatDialog( warbird );
self SwitchToVisible( warbird );
self SetClientOmnvar( "ui_warbird_cloaktext", 3 );
self thread CloakDeactivatedDialog( warbird );
}
CloakCooldown( warbird )
{
self endon( "warbirdStreakComplete" );
self waittill( "UnCloak" );
while(warbird.CloakCooldown>0)
{
warbird.CloakCooldown -= 0.5;
wait 0.5;
}
warbird.CloakCooldown = 0;
self notify( "CloakCharged" );
}
PlayerCloakWaitForExit( warbird )
{
self endon( "warbirdStreakComplete" );
start = GetTime();
self waittill_any_timeout_no_endon_death( CONST_cloak_duration, "ForceUncloak", "Cloak", "ResumeWarbirdAI" );
end = GetTime();
cooldownDuration = max( ( end - start ), CONST_cloak_cooldown_min_duration * 1000 );
warbird.CloakCooldown = cooldownDuration / 1000;
cooldownEnd = GetTime() + cooldownDuration;
self SetClientOmnvar( "ui_warbird_cloakdur", cooldownEnd );
self notify( "UnCloak" );
}
SwitchToCloaked( warbird )
{
if(IsDefined(warbird))
{
thread CloakingTransition( warbird, true );
Missile_DeleteAttractor( warbird.attractor );
self SetClientOmnvar( "ui_warbird_cloak", true );
thread MonitorDamageWhileCloaking( warbird );
}
}
SwitchToVisible( warbird )
{
if(IsDefined(warbird))
{
thread CloakingTransition( warbird, false );
warbird.attractor = Missile_CreateAttractorEnt( warbird, level.heli_attract_strength, level.heli_attract_range );
self SetClientOmnvar( "ui_warbird_cloak", false );
}
}
CloakingTransition( warbird, enable, init )
{
warbird notify( "cloaking_transition" );
warbird endon( "cloaking_transition" );
warbird endon( "warbirdStreakComplete" );
if ( enable )
{
if ( warbird.cloakState == -2 )
return;
warbird.cloakState = -1;
warbird CloakingEnable();
warbird.warbirdTurret CloakingEnable();
if ( warbird.coopOffensive )
warbird.warbirdBuddyTurret CloakingEnable();
warbird Vehicle_SetMinimapVisible( false );
if ( !isdefined(init) || !init )
wait 0.2; // should match the code values for the transition + a small time
else
wait 1.5; // during init, we want to give enough time for the cloaking to start then hide, before we unhide
warbird Show();
warbird.warbirdTurret Show();
if ( warbird.coopOffensive )
warbird.warbirdBuddyTurret Show();
warbird.cloakState = -2;
// don't hide the turret for the owner if possessed
warbird notify( "cloaked" );
warbird stopWarbirdEngineFX();
}
else
{
if ( warbird.cloakState == 2 )
return;
warbird.cloakState = 1;
warbird CloakingDisable();
warbird Vehicle_SetMinimapVisible( true );
warbird.warbirdTurret CloakingDisable();
if ( warbird.coopOffensive )
warbird.warbirdBuddyTurret CloakingDisable();
wait 2.2; // should match the code values for the transition
warbird.cloakState = 2;
warbird playWarbirdEngineFX();
}
}
CloakDeactivatedDialog( warbird )
{
self endon( "CloakCharged" );
self endon( "warbirdStreakComplete" );
self endon( "ResumeWarbirdAI" );
while ( true )
{
self waittill( "Cloak" );
// iprintlnbold("OH NO YOU DON'T...");
warbird.PlayerAttachPoint play_sound_on_entity( "warbird_cloak_notready" );
wait 1;
}
}
CloakReadyDialog()
{
//warbird.PlayerAttachPoint thread play_sound_on_entity( "warbird_turret_overheat_warning" );
}
CloakActivatedDialog( warbird )
{
// warbird.PlayerAttachPoint thread play_sound_on_entity( "weap_warbirdrocket_reload" );
}
PlayCloakOverheatDialog( warbird )
{
// warbird.PlayerAttachPoint thread play_sound_on_entity( "weap_warbirdrocket_reload" );
warbird.PlayerAttachPoint play_sound_on_entity( "warbird_cloak_deactivate" );
}
CloakWarbirdExit( warbird, player ) //self = player
{
if ( IsDefined( warbird ) && warbird.isCrashing == false )
{
if ( IsDefined( player ) )
player notify( "ActivateCloak" );
thread CloakingTransition( warbird, true );
Missile_DeleteAttractor( warbird.attractor );
}
}
MonitorDamageWhileCloaking( warbird )
{
self endon( "UnCloak" );
self endon( "warbirdStreakComplete" );
self endon( "ResumeWarbirdAI" );
//wait for the warbird to be fully cloaked
wait 1;
//if the warbird recieves any damage while fully cloaked it automatically ends the cloak behavior.
warbird waittill( "damage", Amount, Attacker, DirectionVec, Point, DamageType );
self notify( "ForceUncloak" );
}
//=================================================================================================================//
// PLAYER DAMAGE MONITORS //
//=================================================================================================================//
WarbirdRocketDamageIndicator( warbird )
{
self endon( "ResumeWarbirdAI" );
self endon( "warbirdStreakComplete" );
while(1)
{
warbird waittill( "damage", Amount, Attacker, DirectionVec, Point, DamageType );
if( DamageType == "MOD_PROJECTILE" )
{
Earthquake ( .75, 1, warbird.origin, 1000 );
self ShellShock( "frag_grenade_mp", 0.5 );
}
}
}
////=================================================================================================================//
//// PLAYER ATTACK //
////=================================================================================================================//
UpdateShootingLocation( warbird )
{
self endon( "warbirdStreakComplete" );
level endon( "ResumeWarbirdAI" );
while ( true )
{
angles = self GetPlayerAngles();
eye = warbird.PlayerAttachPoint.origin;
forward = AnglesToForward( angles );
TargetPos = eye + ( forward * 4000 );
warbird.TargetEnt.origin = TargetPos;
//ForceTurretAimAtEnt( warbird, level.TargetEnt );
wait 0.05;
}
}
MonitorWeaponSelection( warbird )
{
self endon( "warbirdStreakComplete" );
self endon( "ResumeWarbirdAI" );
self.current_warbird_weapon = "turret";
warbird.warbirdTurret TurretFireEnable();
if ( !warbird.hasRockets )
return;
while ( 1 )
{
self waittill( "SwitchWeapon" );
if ( self.current_warbird_weapon == "turret" )
{
self.current_warbird_weapon = "missiles";
warbird.warbirdTurret TurretFireDisable();
self SetClientOmnvar( "ui_warbird_weapon", 2 );
}
else if ( self.current_warbird_weapon == "missiles" )
{
self.current_warbird_weapon = "turret";
warbird.warbirdTurret TurretFireEnable();
self SetClientOmnvar( "ui_warbird_weapon", 1 );
}
self PlayLocalSound( "warbird_weapon_cycle_plr" );
}
}
WeaponSetup( warbird )
{
if ( warbird.hasRockets )
self thread FireWarbirdRockets( warbird );
self thread MonitorWeaponSelection( warbird );
self thread UpdateShootingLocation( warbird );
//self thread MonitorWarbirdMachineGun( warbird );
self thread force_uncloak_on_fire( warbird );
}
waittillTurretFired( warbird )
{
warbird endon( "warbirdStreakComplete" );
warbird.warbirdTurret endon( "turret_fire" );
if ( warbird.coopOffensive )
warbird.warbirdBuddyTurret endon( "turret_fire" );
level waittill( "forever" );
}
force_uncloak_on_fire( warbird ) //self = player
{
level endon( "game_ended" );
self endon( "warbirdStreakComplete" );
while ( true )
{
waittillTurretFired( warbird );
self notify( "ForceUncloak" );
wait( 0.05 );
}
}
FireWarbirdThreatGrenades( warbird )
{
warbird endon( "warbirdStreakComplete" );
self endon( "warbirdStreakComplete" );
self endon( "warbird_player_removed" );
while ( true )
{
self waittill( "StartFire" );
self maps\mp\killstreaks\_aerial_utility::playerFakeShootPaintMissile( warbird.warbirdBuddyTurret.fireSoundent );
PlayFXOnTag(level.chopper_fx["rocketlaunch"]["warbird"], warbird, "tag_origin" );
wait 2;
}
}
FireWarbirdRockets( warbird )
{
self endon( "ResumeWarbirdAI" );
self endon( "warbirdStreakComplete" );
warbird.RemainingRocketShots = warbird.RocketClip;
while ( true )
{
if ( self.guid == "bot0" || self.guid == "bot1" || self.guid == "bot2" || self.guid == "bot3" ) //HACK: dirty, dirty hack to get the bots to continuously fire missiles. Strip this out before we ship!!!
{
wait( 3 );
}
else
{
self waittill( "StartFire" );
}
if ( self.current_warbird_weapon == "missiles" || ( self.guid == "bot0" || self.guid == "bot1" || self.guid == "bot2" || self.guid == "bot3" ) ) //HACK: dirty, dirty hack to get the bots to continuously fire missiles. Strip this out before we ship!!!
{
Earthquake ( 0.4, 1, warbird.origin, 1000 );
self PlayRumbleOnEntity( "ac130_105mm_fire" );
missile_tag_origin = warbird GetTagOrigin( "tag_missile_right" );
player_forward = VectorNormalize( AnglesToForward( self GetPlayerAngles() ) );
warbird_velocity = warbird GetEntityVelocity();
missile = MagicBullet( "warbird_missile_mp", missile_tag_origin + warbird_velocity/10, self GetEye() + warbird_velocity + player_forward * 1000, self );
PlayFXOnTag(level.chopper_fx["rocketlaunch"]["warbird"], warbird, "tag_missile_right");
missile Missile_SetTargetEnt( warbird.TargetEnt );
missile Missile_SetFlightmodeDirect();
warbird.RemainingRocketShots--;
self notify( "ForceUncloak" );
WarbirdRocketHudUpdate( warbird );
if ( warbird.RemainingRocketShots == 0 )
{
thread WarbirdRocketReloadSound( warbird, CONST_rocket_reload_time );
// waittillReloadedWithMashHelp( CONST_rocket_reload_time, self, "rockets" );
wait CONST_rocket_reload_time;
warbird.RemainingRocketShots = warbird.RocketClip;
self notify( "rocketReloadComplete" );
WarbirdRocketHudUpdate( warbird );
}
else
{
wait CONST_rocket_fire_interval;
}
}
}
}
WarbirdRocketReloadSound( warbird, reload_time )
{
self endon( "rocketReloadComplete" );
self endon( "ResumeWarbirdAI" );
self endon( "warbirdStreakComplete" );
missile_count = 3;
self PlayLocalSound( "warbird_missile_reload_bed" );
wait(0.5);
while ( true )
{
self PlayLocalSound( "warbird_missile_reload" );
wait( reload_time / missile_count );
}
}
////=================================================================================================================//
//// BUDDY - UI //
////=================================================================================================================//
handleCoopJoining( warbird, player )
{
splashRef = "warbird_coop_defensive";
joinText = &"MP_JOIN_WARBIRD_DEF";
buddyJoinedVO = "pilot_sup_mp_warbird";
joinedVO = "copilot_sup_mp_paladin";
if ( warbird.coopOffensive )
{
splashRef = "warbird_coop_offensive";
joinText = &"MP_JOIN_WARBIRD_OFF";
buddyJoinedVO = "pilot_aslt_mp_warbird";
joinedVO = "copilot_aslt_mp_paladin";
}
while ( true )
{
id = maps\mp\killstreaks\_coop_util::promptForStreakSupport( player.team, joinText, splashRef, "assist_mp_warbird", buddyJoinedVO, player, joinedVO );
level thread watchForJoin( id, warbird, player );
result = waittillPromptComplete( warbird, "buddyJoinedStreak" );
maps\mp\killstreaks\_coop_util::stopPromptForStreakSupport( id );
if ( !IsDefined( result ) )
return;
result = waittillPromptComplete( warbird, "buddyLeftWarbird" );
if ( !IsDefined( result ) )
return;
}
}
waittillPromptComplete( warbird, text )
{
warbird endon( "warbirdStreakComplete" );
warbird waittill( text );
return true;
}
watchForJoin( id, warbird, player )
{
warbird endon( "warbirdStreakComplete" );
buddy = maps\mp\killstreaks\_coop_util::waittillBuddyJoinedStreak( id );
warbird notify( "buddyJoinedStreak" );
buddy thread buddyJoinWarbirdSetup( warbird, player );
}
////=================================================================================================================//
//// BUDDY //
////=================================================================================================================//
buddyJoinWarbirdSetup( warbird, primaryPlayer )
{
warbird endon( "warbirdStreakComplete" );
self endon( "warbirdStreakComplete" );
self endon( "warbird_player_removed" );
self thread WarbirdOverheatBarColorMonitor( warbird, warbird.warbirdBuddyTurret );
warbird.buddy = self;
self.ControllingWarbird = true;
self thread PlayerDoRideKillstreak( warbird, true );
self waittill( "initRideKillstreak_complete", success );
if ( !success )
return;
self setUsingRemote( "Warbird" );
self playerSaveAngles();
self thread SetupWarbirdHud( warbird, true, primaryPlayer );
self thread MonitorBuddyWarbirdDeathorTimeout( warbird );
self thread MonitorBuddyDisconnect( warbird );
// with the way we do visionsets we need to wait for the clearRideIntro() is done before we set thermal
self thread waitSetThermal( 0.5 );
self thread setWarbirdVisionSetPerMap( 0.5 );
self pauseWarbirdEngineFXForPlayer( warbird );
self thread WarbirdRocketDamageIndicator( warbird );
self takeover_warbird_turret_buddy( warbird );
self setupPlayerCommands();
if ( !warbird.coopOffensive )
self thread FireWarbirdThreatGrenades( warbird );
if ( !IsBot( self ) )
self thread removeWarbirdBuddyOnCommand( warbird );
}
removeWarbirdBuddy( warbird, disconnected )
{
self notify ( "warbird_player_removed" );
if ( !disconnected )
{
self playerResetWarbirdOmnvars();
self SetBlurForPlayer( 0, 0 );
self notify( "warbirdThermalOff" );
maps\mp\killstreaks\_aerial_utility::disableOrbitalThermal( self );
self thread removeWarbirdVisionSetPerMap( 1.5 );
self ThermalVisionFOFOverlayOff();
if ( IsDefined( warbird.warbirdBuddyTurret ) && self IsControllingWarbird() )
self RemoteControlTurretOff( warbird.warbirdBuddyTurret );
self.ControllingWarbird = undefined;
self EnableWeapons();
self Unlink();
self maps\mp\killstreaks\_coop_util::playerResetAfterCoopStreak();
self DisableSlowAim();
self disablePlayercommands( warbird );
self restartWarbirdEngineFXForPlayer( warbird );
if ( self isUsingRemote() )
self clearUsingRemote();
self playerRemoteKillstreakShowHud();
self playerRestoreAngles();
}
warbird notify( "buddyLeftWarbird" );
warbird.buddy = undefined;
}
MonitorBuddyWarbirdDeathorTimeout( warbird )
{
self endon( "disconnect" );
warbird waittill_any( "leaving", "death", "crashing" );
self notify( "warbirdStreakComplete" );
self notify ( "StopWaitForDisconnect" );
waittillframeend;
maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
self thread removeWarbirdBuddy( warbird, false );
}
MonitorBuddyDisconnect( warbird )
{
self endon( "StopWaitForDisconnect" );
self waittill( "disconnect" );
thread removeWarbirdBuddy( warbird, true );
}
removeWarbirdBuddyOnCommand(warbird)
{
self endon( "warbird_player_removed" );
while ( true )
{
self waittill( "ToggleControlState" );
self thread startWarbirdBuddyExitCommand(warbird);
self thread cancelWarbirdBuddyExitCommand();
}
}
startWarbirdBuddyExitCommand(warbird)
{
self endon( "warbird_player_removed" );
self endon( "ToggleControlCancel" );
self.warbird_buddy_exit = true;
wait( 0.5 );
if ( self.warbird_buddy_exit == true )
{
self thread removeWarbirdBuddy( warbird, false );
}
}
cancelWarbirdBuddyExitCommand()
{
self endon( "warbird_player_removed" );
self waittill( "ToggleControlCancel" );
self.warbird_buddy_exit = false;
}
////=================================================================================================================//
//// RESUME AI FUNC //
////=================================================================================================================//
MonitorAIWarbirdSwitch( warbird, init )
{
self endon( "warbirdStreakComplete" );
self.WarbirdInit = false;
self notify( "ResumeWarbirdAI" );
self notify( "warbirdThermalOff" );
warbird.IsPossessed = false;
self thread CloakingTransition( warbird, false ); // ensure the player sees the warbird
warbird.warbirdTurret SetMode( "auto_nonai" );
self playerResetWarbirdOmnvars();
waittillframeend;
// startNode = level.heli_start_nodes[ randomInt( level.heli_start_nodes.size ) ];
// warbird thread heli_think( -1, warbird.owner, startNode, warbird.owner.team, "warbird" );
self thread WarbirdAIAttack( warbird );
warbird.killCamStartTime = GetTime();
warbird.warbirdTurret.killCamEnt = warbird;
warbird.player = undefined;
if ( self isUsingRemote() )
self playerReset( warbird );
waitframe();
}
////=================================================================================================================//
//// DEATH TIMEOUT & DISCONNECT //
////=================================================================================================================//
MonitorAIWarbirdDeathorTimeout( warbird )
{
self endon( "disconnect" );
thread CheckForCrashing( warbird );
result = warbird waittill_any_return( "leaving", "death", "crashing" );
self playerResetAfterWarbird( warbird );
level thread warbirdCleanup( warbird, self, (result != "death") );
}
warbirdCleanup( warbird, player, waitUntilDeath )
{
level.SpawnedWarbirds = array_remove(level.SpawnedWarbirds,warbird);
level.warbirdInUse = false;
if ( IsDefined( warbird.UsableEnt ) )
warbird.UsableEnt makeGloballyUnusableByType();
thread CloakWarbirdExit( warbird, player );
if ( IsDefined( warbird.attractor ) )
Missile_DeleteAttractor( warbird.attractor );
if ( IsDefined( warbird.PlayerAttachPoint ) )
warbird.PlayerAttachPoint Delete();
warbird.enemy_target = undefined;
if ( waitUntilDeath )
warbird waittill( "death" );
else
waittillframeend;
result = maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
if ( result != 0 )
waitframe();
warbird.warbirdTurret Delete();
if ( IsDefined( warbird.warbirdBuddyTurret ) )
{
if ( IsDefined( warbird.warbirdBuddyTurret.fireSoundent ) )
warbird.warbirdBuddyTurret.fireSoundent Delete();
warbird.warbirdBuddyTurret Delete();
}
if ( IsDefined( warbird.UsableEnt ) )
warbird.UsableEnt Delete();
}
playerResetAfterWarbird( warbird ) // self == player
{
self notify( "warbirdStreakComplete" );
warbird notify( "warbirdStreakComplete" );
waittillframeend;
self playerResetWarbirdOmnvars();
///// check to see if player is actually in the warbird, because if they are in another vehicle then this will change that UI
if ( warbird.IsPossessed && !self isInRemoteTransition() )
{
self playerReset( warbird );
warbird.IsPossessed = false;
}
self disablePlayerCommands( warbird );
self notify ( "StopWaitForDisconnect" );
}
playerReset( warbird ) // self == player
{
self SetBlurForPlayer( 0, 0 );
maps\mp\killstreaks\_aerial_utility::disableOrbitalThermal( self );
self ThermalVisionFOFOverlayOff();
self thread removeWarbirdVisionSetPerMap( 1.5 );
//warbird VehicleTurretControlOff( self );
self RemoteControlVehicleOff();
if ( IsDefined( warbird.warbirdTurret ) && self IsControllingWarbird() )
self RemoteControlTurretOff( warbird.warbirdTurret );
self.ControllingWarbird = undefined;
self.PossessWarbird = undefined;
self EnableWeapons();
self Unlink();
if ( self isUsingRemote() )
{
self clearUsingRemote();
}
else
{
curWeapon = self getCurrentWeapon();
if( curWeapon == "none" || isKillstreakWeapon( curWeapon ) )
self switchToWeapon( self Getlastweapon() );
self playerRemoteKillstreakShowHud();
}
self thread playerDelayControl();
if ( warbird.hasAI )
self maps\mp\killstreaks\_killstreaks::takeKillstreakWeaponIfNoDupe( "killstreak_predator_missile_mp" );
self EnableWeaponSwitch();
self DisableSlowAim();
if ( !IsDefined( warbird.isleaving ) || !warbird.isleaving )
self restartWarbirdEngineFXForPlayer( warbird );
self playerRestoreAngles();
}
playerDelayControl() // self == player
{
self endon( "disconnect" );
self freezeControlsWrapper( true );
wait( 0.5 );
self freezeControlsWrapper( false );
}
CheckForCrashing( warbird )
{
warbird waittill_any( "crashing", "death" );
warbird.isCrashing = true;
}
//I think this will take care of the player leaving mid match. The warbird should just fly away and all the spawned entities should get deleted.
MonitorPlayerDisconnect( warbird )
{
self endon ( "StopWaitForDisconnect" );
self waittill( "disconnect" );
warbird notify( "warbirdStreakComplete" );
self notify( "warbirdStreakComplete" );
self notify( "warbirdThermalOff" );
warbird thread maps\mp\killstreaks\_aerial_utility::heli_leave();
level thread warbirdCleanup( warbird, self, true );
}
play_sound_on_entity( alias )
{
self PlaySound( alias );
}
warbird_health()
{
self endon( "death" );
self endon( "leaving" );
self endon( "crashing" );
self.currentstate = "ok";
self.laststate = "ok";
self setdamagestage( 3 );
damageState = 3;
self setDamageStage( damageState );
for ( ;; )
{
if ( self.damageTaken >= (self.maxhealth * 0.33) && damageState == 3 )
{
damageState = 2;
self setDamageStage( damageState );
self.currentstate = "light smoke";
playFxOnTag( level.chopper_fx["damage"]["light_smoke"], self, "tag_static_main_rotor_l" );
}
else if ( self.damageTaken >= (self.maxhealth * 0.66) && damageState == 2 )
{
damageState = 1;
self setDamageStage( damageState );
self.currentstate = "heavy smoke";
stopFxOnTag( level.chopper_fx["damage"]["light_smoke"], self, "tag_static_main_rotor_l" );
playFxOnTag( level.chopper_fx["damage"]["heavy_smoke"], self, "tag_static_main_rotor_l" );
}
else if( self.damageTaken >= self.maxhealth )
{
damageState = 0;
self setDamageStage( damageState );
//stopFxOnTag( level.chopper_fx["damage"]["light_smoke"], self, "tag_static_main_rotor_l" );
//stopFxOnTag( level.chopper_fx["damage"]["heavy_smoke"], self, "tag_static_main_rotor_l" );
if ( IsDefined( self.largeProjectileDamage ) && self.largeProjectileDamage )
{
self thread maps\mp\killstreaks\_aerial_utility::heli_explode( true );
}
else
{
playFxOnTag( level.chopper_fx["damage"]["on_fire"], self, "TAG_TAIL_FX" );
self thread maps\mp\killstreaks\_aerial_utility::heli_crash();
}
}
wait 0.05;
}
}
playerResetWarbirdOmnvars()
{
self SetClientOmnvar( "ui_warbird_heat", 0 );
self SetClientOmnvar( "ui_warbird_flares", 0 );
self SetClientOmnvar( "ui_warbird_fire", 0 );
self SetClientOmnvar( "ui_warbird_cloak", false );
self SetClientOmnvar( "ui_warbird_cloaktime", 0 );
self SetClientOmnvar( "ui_warbird_cloakdur", 0 );
self SetClientOmnvar( "ui_warbird_countdown", 0 );
self SetClientOmnvar( "ui_warbird_missile", -1 );
self SetClientOmnvar( "ui_warbird_weapon", 0 );
self SetClientOmnvar( "ui_warbird_cloaktext", 0 );
self SetClientOmnvar( "ui_warbird_toggle", 0 );
self SetClientOmnvar( "ui_coop_primary_num", 0 );
self maps\mp\killstreaks\_aerial_utility::playerDisableStreakStatic();
self DisableForceFirstPersonWhenFollowed();
}
//waittillReloadedWithMashHelp( reloadTime, player, type )
//{
// self endon( "playerReloadTimeout" + type );
//
// player thread playerReloadTimeout( reloadTime, type );
//
// timeDecreasePerButtonUp = reloadTime * CONST_WARBIRD_RELOAD_MASH_TIME_RATIO;
// reloadTimeMS = reloadTime * 1000;
// reloadTimeComplete = GetTime() + reloadTimeMS;
//
// maxDecreaseTime = reloadTimeMS * 0.2;
//
//// numTimes = 0;
//// startTime = GetTime();
//
// while ( GetTime() < reloadTimeComplete )
// {
// if ( maxDecreaseTime - timeDecreasePerButtonUp >= 0 )
// {
// player waittill( "ToggleControlCancel" );
// reloadTimeComplete -= timeDecreasePerButtonUp;
//// numTimes++;
// }
// }
//
// player notify( "playerReloadTimeoutMashed" + type );
//
//// time = (GetTime() - startTime)/1000;
//// timeRemoved = (numTimes * timeDecreasePerButtonUp)/1000;
//// PrintLn( "NumUps: " + numTimes + ", TimeRemoved: " + timeRemoved + ", TimeReload: " + time );
//}
//
//playerReloadTimeout( reloadTime, type )
//{
// self endon( "disconnect" );
// self endon( "playerReloadTimeoutMashed" + type );
//
// wait reloadTime;
//
// self notify( "playerReloadTimeout" + type );
//}
////=========================================================================================//
//// VFX //
////=========================================================================================//
/*
=============
"Name: playWarbirdEngineFX()"
"Summary: plays warbird engine effects on a warbird"
=============
*/
playWarbirdEngineFX()
{
PlayFXOnTag( level.chopper_fx["engine"]["warbird"], self, "tag_static_main_rotor_r" );
PlayFXOnTag( level.chopper_fx["engine"]["warbird"], self, "tag_static_main_rotor_l" );
if ( IsDefined( self.player ) )
self.player pauseWarbirdEngineFXForPlayer( self );
if ( IsDefined( self.buddy ) )
self.buddy pauseWarbirdEngineFXForPlayer( self );
}
stopWarbirdEngineFX()
{
StopFXOnTag( level.chopper_fx["engine"]["warbird"], self, "tag_static_main_rotor_r" );
StopFXOnTag( level.chopper_fx["engine"]["warbird"], self, "tag_static_main_rotor_l" );
}
pauseWarbirdEngineFXForPlayer( warbird )
{
if ( !IsDefined( warbird ) )
return;
StopFXOnTagForClient( level.chopper_fx["engine"]["warbird"], warbird, "tag_static_main_rotor_r", self );
StopFXOnTagForClient( level.chopper_fx["engine"]["warbird"], warbird, "tag_static_main_rotor_l", self );
}
restartWarbirdEngineFXForPlayer( warbird )
{
if ( !IsDefined( warbird ) )
return;
if ( maps\mp\killstreaks\_aerial_utility::vehicleIsCloaked() )
return;
PlayFXOnTagForClients( level.chopper_fx["engine"]["warbird"], warbird, "tag_static_main_rotor_r", self );
PlayFXOnTagForClients( level.chopper_fx["engine"]["warbird"], warbird, "tag_static_main_rotor_l", self );
}
////=========================================================================================//
//// AUDIO //
////=========================================================================================//
warbird_audio()
{
if(isdefined( self ))
{
//self snd_veh_play_loops( "warbird_close_lp", "warbird_close_stress_lp", "warbird_chopper_dist_lp" );
}
}
warbirdLightFX()
{
self endon( "death" );
while ( true )
{
self.owner waittill( "UnCloak" );
playFXOnTag( level.chopper_fx["light"]["warbird"], self, "tag_light_body_L" );
wait ( 0.05 );
playFXOnTag( level.chopper_fx["light"]["warbird"], self, "tag_light_body_R" );
wait ( 0.05 );
playFXOnTag( level.chopper_fx["light"]["warbird"], self, "tag_light_tail" );
self.owner waittill( "ActivateCloak" );
stopFXOnTag( level.chopper_fx["light"]["warbird"], self, "tag_light_body_L" );
wait ( 0.05 );
stopFXOnTag( level.chopper_fx["light"]["warbird"], self, "tag_light_body_R" );
wait ( 0.05 );
stopFXOnTag( level.chopper_fx["light"]["warbird"], self, "tag_light_tail" );
}
}
/#
testFlares( player )
{
player endon( "warbirdStreakComplete" );
SetDvarIfUninitialized( "scr_warbird_flares", "0" );
cur = "none";
while ( true )
{
if ( GetDvarInt( "scr_warbird_flares", 0 ) == 0 )
{
waitframe();
continue;
}
SetDvar( "scr_warbird_flares", "0" );
if ( cur == "none" )
{
player SetClientOmnvar( "ui_warbird_flares", 3 );
cur = "threat";
}
else if ( cur == "threat" )
{
player SetClientOmnvar( "ui_warbird_flares", 1 );
cur = "flare1";
}
else if ( cur == "flare1" )
{
player SetClientOmnvar( "ui_warbird_flares", 2 );
cur = "flare2";
}
else // if ( cur == "flare2" )
{
player SetClientOmnvar( "ui_warbird_flares", 0 );
cur = "none";
}
waitframe();
}
}
#/