2505 lines
71 KiB
Plaintext
2505 lines
71 KiB
Plaintext
#include maps\mp\_utility;
|
|
#include common_scripts\utility;
|
|
#include maps\mp\gametypes\_hud_util;
|
|
|
|
CRATE_KILLCAM_OFFSET = ( 0, 0, 300);
|
|
GRAVITY_UNITS_PER_SECOND = 800;
|
|
|
|
DUMMY_CRATE_MODEL = "carepackage_dummy_iw6";
|
|
FRIENDLY_CRATE_MODEL = "carepackage_friendly_iw6";
|
|
ENEMY_CRATE_MODEL = "carepackage_enemy_iw6";
|
|
|
|
DUMMY_JUGGERNAUT_CRATE_MODEL = "mp_juggernaut_carepackage_dummy";
|
|
FRIENDLY_JUGGERNAUT_CRATE_MODEL = "mp_juggernaut_carepackage";
|
|
ENEMY_JUGGERNAUT_CRATE_MODEL = "mp_juggernaut_carepackage_red";
|
|
|
|
CONST_CRATE_OWNER_USE_TIME = 500;
|
|
CONST_CRATE_OTHER_USE_TIME = 3000;
|
|
|
|
init()
|
|
{
|
|
level._effect[ "airdrop_crate_destroy" ] = LoadFX( "vfx/gameplay/mp/killstreaks/vfx_airdrop_crate_dust_kickup" );
|
|
level._effect[ "airdrop_dust_kickup" ] = LoadFX( "vfx/gameplay/mp/killstreaks/vfx_airdrop_crate_dust_kickup" );
|
|
|
|
|
|
PrecacheMpAnim( "juggernaut_carepackage" );
|
|
|
|
setAirDropCrateCollision( "airdrop_crate" ); // old care package entities
|
|
setAirDropCrateCollision( "care_package" ); // new care package entities
|
|
assert( IsDefined(level.airDropCrateCollision) );
|
|
|
|
level.killStreakFuncs["airdrop_assault"] = ::tryUseAirdrop;
|
|
level.killStreakFuncs["airdrop_support"] = ::tryUseAirdrop;
|
|
level.killStreakFuncs["airdrop_juggernaut"] = ::tryUseAirdrop;
|
|
level.killStreakFuncs["airdrop_juggernaut_recon"] = ::tryUseAirdrop;
|
|
level.killStreakFuncs["airdrop_juggernaut_maniac"] = ::tryUseAirdrop;
|
|
|
|
level.numDropCrates = 0;
|
|
level.littleBirds = [];
|
|
level.crateTypes = [];
|
|
level.crateMaxVal = [];
|
|
|
|
// ASSAULT
|
|
// Drop Type Type Weight Function Friendly Model Enemy Model Hint String Dummy Model
|
|
addCrateType( "airdrop_assault", "uplink", 25, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_UPLINK_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_assault", "ims", 25, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_IMS_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_assault", "guard_dog", 20, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_GUARD_DOG_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_assault", "drone_hive", 20, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_DRONE_HIVE_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_assault", "sentry", 10, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_SENTRY_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_assault", "helicopter", 10, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_HELICOPTER_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_assault", "ball_drone_backup", 4, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_BALL_DRONE_BACKUP_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_assault", "vanguard", 4, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_VANGUARD_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_assault", "airdrop_juggernaut_maniac", 3, ::juggernautCrateThink, FRIENDLY_JUGGERNAUT_CRATE_MODEL, ENEMY_JUGGERNAUT_CRATE_MODEL, &"KILLSTREAKS_HINTS_JUGGERNAUT_MANIAC_PICKUP", DUMMY_JUGGERNAUT_CRATE_MODEL );
|
|
addCrateType( "airdrop_assault", "airdrop_juggernaut", 2, ::juggernautCrateThink, FRIENDLY_JUGGERNAUT_CRATE_MODEL, ENEMY_JUGGERNAUT_CRATE_MODEL, &"KILLSTREAKS_HINTS_JUGGERNAUT_PICKUP", DUMMY_JUGGERNAUT_CRATE_MODEL );
|
|
addCrateType( "airdrop_assault", "heli_pilot", 1, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_HELI_PILOT_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_assault", "odin_assault", 1, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_ODIN_ASSAULT_PICKUP", DUMMY_CRATE_MODEL );
|
|
|
|
// SUPPORT
|
|
addCrateType( "airdrop_support", "uplink_support", 25, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_UPLINK_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_support", "deployable_vest", 25, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_DEPLOYABLE_VEST_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_support", "deployable_ammo", 20, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_DEPLOYABLE_AMMO_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_support", "ball_drone_radar", 20, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_BALL_DRONE_RADAR_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_support", "aa_launcher", 10, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_AA_LAUNCHER_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_support", "jammer", 10, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_JAMMER_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_support", "air_superiority", 4, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_AIR_SUPERIORITY_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_support", "recon_agent", 4, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_RECON_AGENT_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_support", "heli_sniper", 4, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_HELI_SNIPER_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_support", "uav_3dping", 3, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_UAV_3DPING_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_support", "airdrop_juggernaut_recon", 1, ::juggernautCrateThink, FRIENDLY_JUGGERNAUT_CRATE_MODEL, ENEMY_JUGGERNAUT_CRATE_MODEL, &"KILLSTREAKS_HINTS_JUGGERNAUT_RECON_PICKUP", DUMMY_JUGGERNAUT_CRATE_MODEL );
|
|
addCrateType( "airdrop_support", "odin_support", 1, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_ODIN_SUPPORT_PICKUP", DUMMY_CRATE_MODEL );
|
|
|
|
// KILLSTREAKS
|
|
// Drop Type Type Weight Function Friendly Model Enemy Model Hint String Dummy Model
|
|
addCrateType( "airdrop_juggernaut", "airdrop_juggernaut", 100, ::juggernautCrateThink, FRIENDLY_JUGGERNAUT_CRATE_MODEL, ENEMY_JUGGERNAUT_CRATE_MODEL, &"KILLSTREAKS_HINTS_JUGGERNAUT_PICKUP", DUMMY_JUGGERNAUT_CRATE_MODEL );
|
|
addCrateType( "airdrop_juggernaut_recon", "airdrop_juggernaut_recon", 100, ::juggernautCrateThink, FRIENDLY_JUGGERNAUT_CRATE_MODEL, ENEMY_JUGGERNAUT_CRATE_MODEL, &"KILLSTREAKS_HINTS_JUGGERNAUT_RECON_PICKUP", DUMMY_JUGGERNAUT_CRATE_MODEL );
|
|
addCrateType( "airdrop_juggernaut_maniac", "airdrop_juggernaut_maniac", 100, ::juggernautCrateThink, FRIENDLY_JUGGERNAUT_CRATE_MODEL, ENEMY_JUGGERNAUT_CRATE_MODEL, &"KILLSTREAKS_HINTS_JUGGERNAUT_MANIAC_PICKUP", DUMMY_JUGGERNAUT_CRATE_MODEL );
|
|
|
|
//Grind
|
|
//
|
|
addCrateType( "airdrop_grnd", "uplink", 25, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_UPLINK_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "ims", 25, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_IMS_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "guard_dog", 20, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_GUARD_DOG_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "drone_hive", 20, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_DRONE_HIVE_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "sentry", 10, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_SENTRY_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "helicopter", 10, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_HELICOPTER_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "ball_drone_backup", 4, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_BALL_DRONE_BACKUP_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "vanguard", 4, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_VANGUARD_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "airdrop_juggernaut_maniac", 3, ::juggernautCrateThink, FRIENDLY_JUGGERNAUT_CRATE_MODEL, ENEMY_JUGGERNAUT_CRATE_MODEL, &"KILLSTREAKS_HINTS_JUGGERNAUT_MANIAC_PICKUP", DUMMY_JUGGERNAUT_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "airdrop_juggernaut", 2, ::juggernautCrateThink, FRIENDLY_JUGGERNAUT_CRATE_MODEL, ENEMY_JUGGERNAUT_CRATE_MODEL, &"KILLSTREAKS_HINTS_JUGGERNAUT_PICKUP", DUMMY_JUGGERNAUT_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "heli_pilot", 1, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_HELI_PILOT_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "deployable_vest", 25, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_DEPLOYABLE_VEST_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "deployable_ammo", 20, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_DEPLOYABLE_AMMO_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "ball_drone_radar", 20, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_BALL_DRONE_RADAR_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "aa_launcher", 20, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_AA_LAUNCHER_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "jammer", 10, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_JAMMER_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "air_superiority", 10, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_AIR_SUPERIORITY_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "recon_agent", 15, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_RECON_AGENT_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "heli_sniper", 10, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_HELI_SNIPER_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "uav_3dping", 5, ::killstreakCrateThink, FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL, &"KILLSTREAKS_HINTS_UAV_3DPING_PICKUP", DUMMY_CRATE_MODEL );
|
|
addCrateType( "airdrop_grnd", "airdrop_juggernaut_recon", 5, ::juggernautCrateThink, FRIENDLY_JUGGERNAUT_CRATE_MODEL, ENEMY_JUGGERNAUT_CRATE_MODEL, &"KILLSTREAKS_HINTS_JUGGERNAUT_RECON_PICKUP", DUMMY_JUGGERNAUT_CRATE_MODEL );
|
|
|
|
if( IsDefined(level.customCrateFunc) )
|
|
[[level.customCrateFunc]]( FRIENDLY_CRATE_MODEL, ENEMY_CRATE_MODEL );
|
|
|
|
if( IsDefined(level.mapCustomCrateFunc) )
|
|
[[level.mapCustomCrateFunc]]();
|
|
|
|
generateMaxWeightedCrateValue();
|
|
|
|
config = SpawnStruct();
|
|
config.xpPopup = "destroyed_airdrop";
|
|
// !!! NEED VO
|
|
config.voDestroyed = undefined;
|
|
config.callout = "callout_destroyed_airdrop";
|
|
config.samDamageScale = 0.09;
|
|
// xpval = 200
|
|
level.heliConfigs[ "airdrop" ] = config;
|
|
|
|
maps\mp\gametypes\_rank::registerScoreInfo( "little_bird", 200 );
|
|
|
|
/#
|
|
SetDevDvarIfUninitialized( "scr_crateOverride", "" );
|
|
SetDevDvarIfUninitialized( "scr_crateTypeOverride", "" );
|
|
|
|
SetDevDvarIfUninitialized( "scr_airDrop_max_linear_velocity", 1200 );
|
|
SetDevDvarIfUninitialized( "scr_airDrop_slowdown_max_linear_velocity", 600 );
|
|
#/
|
|
}
|
|
|
|
generateMaxWeightedCrateValue()
|
|
{
|
|
foreach( dropType, dropTypeArray in level.crateTypes )
|
|
{
|
|
level.crateMaxVal[ dropType ] = 0;
|
|
foreach( crateType in dropTypeArray )
|
|
{
|
|
type = crateType.type;
|
|
if( !level.crateTypes[ dropType ][ type ].raw_weight )
|
|
{
|
|
level.crateTypes[ dropType ][ type ].weight = level.crateTypes[ dropType ][ type ].raw_weight;
|
|
continue;
|
|
}
|
|
|
|
level.crateMaxVal[ dropType ] += level.crateTypes[ dropType ][ type ].raw_weight;
|
|
level.crateTypes[ dropType ][ type ].weight = level.crateMaxVal[ dropType ];
|
|
}
|
|
}
|
|
}
|
|
|
|
changeCrateWeight(dropType, crateType, crateWeight)
|
|
{
|
|
if(!IsDefined(level.crateTypes[ dropType ]) || !IsDefined(level.crateTypes[ dropType ][ crateType ]))
|
|
return;
|
|
|
|
level.crateTypes[ dropType ][ crateType ].raw_weight = crateWeight;
|
|
generateMaxWeightedCrateValue();
|
|
}
|
|
|
|
setAirDropCrateCollision( carePackageName )
|
|
{
|
|
airDropCrates = GetEntArray( carePackageName, "targetname" );
|
|
|
|
if( !IsDefined(airDropCrates) || (airDropCrates.size == 0 ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
level.airDropCrateCollision = GetEnt( airDropCrates[0].target, "targetname" );
|
|
|
|
foreach( crate in airDropCrates )
|
|
{
|
|
crate deleteCrate();
|
|
}
|
|
}
|
|
|
|
addCrateType( dropType, crateType, crateWeight, crateFunc, crateModelFriendly, crateModelEnemy, hintString, optionalHint, crateModelDummy )
|
|
{
|
|
if( !IsDefined( crateModelFriendly ) )
|
|
crateModelFriendly = FRIENDLY_CRATE_MODEL;
|
|
if( !IsDefined( crateModelEnemy ) )
|
|
crateModelEnemy = ENEMY_CRATE_MODEL;
|
|
if( !IsDefined( crateModelDummy ) )
|
|
crateModelDummy = DUMMY_CRATE_MODEL;
|
|
|
|
level.crateTypes[ dropType ][ crateType ] = SpawnStruct();
|
|
level.crateTypes[ dropType ][ crateType ].dropType = dropType;
|
|
level.crateTypes[ dropType ][ crateType ].type = crateType;
|
|
level.crateTypes[ dropType ][ crateType ].raw_weight = crateWeight;
|
|
level.crateTypes[ dropType ][ crateType ].weight = crateWeight;
|
|
level.crateTypes[ dropType ][ crateType ].func = crateFunc;
|
|
level.crateTypes[ dropType ][ crateType ].model_name_friendly = crateModelFriendly;
|
|
level.crateTypes[ dropType ][ crateType ].model_name_enemy = crateModelEnemy;
|
|
level.crateTypes[ dropType ][ crateType ].model_name_dummy = crateModelDummy;
|
|
|
|
if( IsDefined( hintString ) )
|
|
game[ "strings" ][ crateType + "_hint" ] = hintString;
|
|
|
|
if( IsDefined( optionalHint ) )
|
|
game[ "strings" ][ crateType + "_optional_hint" ] = optionalHint;
|
|
}
|
|
|
|
|
|
getRandomCrateType( dropType )
|
|
{
|
|
value = RandomInt( level.crateMaxVal[ dropType ] );
|
|
|
|
selectedCrateType = undefined;
|
|
foreach( crateType in level.crateTypes[ dropType ] )
|
|
{
|
|
type = crateType.type;
|
|
if( !level.crateTypes[ dropType ][ type ].weight )
|
|
continue;
|
|
|
|
selectedCrateType = type;
|
|
|
|
if( level.crateTypes[ dropType ][ type ].weight > value )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return( selectedCrateType );
|
|
}
|
|
|
|
|
|
getCrateTypeForDropType( dropType )
|
|
{
|
|
switch ( dropType )
|
|
{
|
|
case "airdrop_sentry_minigun":
|
|
return "sentry";
|
|
case "airdrop_predator_missile":
|
|
return "predator_missile";
|
|
case "airdrop_juggernaut":
|
|
return "airdrop_juggernaut";
|
|
case "airdrop_juggernaut_def":
|
|
return "airdrop_juggernaut_def";
|
|
case "airdrop_juggernaut_gl":
|
|
return "airdrop_juggernaut_gl";
|
|
case "airdrop_juggernaut_recon":
|
|
return "airdrop_juggernaut_recon";
|
|
case "airdrop_juggernaut_maniac":
|
|
return "airdrop_juggernaut_maniac";
|
|
case "airdrop_remote_tank":
|
|
return "remote_tank";
|
|
case "airdrop_lase":
|
|
return "lasedStrike";
|
|
case "airdrop_assault":
|
|
case "airdrop_support":
|
|
case "airdrop_escort":
|
|
case "airdrop_mega":
|
|
case "airdrop_grnd":
|
|
case "airdrop_grnd_mega":
|
|
case "airdrop_sotf":
|
|
default:
|
|
if( IsDefined(level.getRandomCrateTypeForGameMode) )
|
|
return [[level.getRandomCrateTypeForGameMode]]( dropType );
|
|
|
|
return getRandomCrateType( dropType );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************
|
|
* Usage functions
|
|
***********************************************************/
|
|
|
|
tryUseAirdrop( lifeId, streakName )
|
|
{
|
|
dropType = streakName;
|
|
result = undefined;
|
|
|
|
if ( !IsDefined( dropType ) )
|
|
dropType = "airdrop_assault";
|
|
|
|
numIncomingVehicles = 1;
|
|
if( ( level.littleBirds.size >= 4 || level.fauxVehicleCount >= 4 ) && dropType != "airdrop_mega" && !isSubStr( toLower( dropType ), "juggernaut" ) )
|
|
{
|
|
self iPrintLnBold( &"KILLSTREAKS_AIR_SPACE_TOO_CROWDED" );
|
|
return false;
|
|
}
|
|
else if( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxVehicleCount + numIncomingVehicles >= maxVehiclesAllowed() )
|
|
{
|
|
self iPrintLnBold( &"KILLSTREAKS_TOO_MANY_VEHICLES" );
|
|
return false;
|
|
}
|
|
else if( dropType == "airdrop_lase" && IsDefined( level.lasedStrikeCrateActive ) && level.lasedStrikeCrateActive )
|
|
{
|
|
self iPrintLnBold( &"KILLSTREAKS_AIR_SPACE_TOO_CROWDED" );
|
|
return false;
|
|
}
|
|
|
|
if ( dropType != "airdrop_mega" && !isSubStr( toLower( dropType ), "juggernaut" ) )
|
|
{
|
|
self thread watchDisconnect();
|
|
}
|
|
|
|
// increment the faux vehicle count before we spawn the vehicle so no other vehicles try to spawn
|
|
if( !IsSubStr( dropType, "juggernaut" ) )
|
|
incrementFauxVehicleCount();
|
|
|
|
result = self beginAirdropViaMarker( lifeId, dropType );
|
|
|
|
if ( (!IsDefined( result ) || !result) )
|
|
{
|
|
self notify( "markerDetermined" );
|
|
|
|
// decrement the faux vehicle count since this failed to spawn
|
|
decrementFauxVehicleCount();
|
|
|
|
return false;
|
|
}
|
|
|
|
if ( dropType == "airdrop_mega" )
|
|
thread teamPlayerCardSplash( "used_airdrop_mega", self );
|
|
|
|
self notify( "markerDetermined" );
|
|
|
|
self maps\mp\_matchdata::logKillstreakEvent( dropType, self.origin );
|
|
|
|
return true;
|
|
}
|
|
|
|
watchDisconnect()
|
|
{
|
|
self endon( "markerDetermined" );
|
|
|
|
self waittill( "disconnect" );
|
|
return;
|
|
}
|
|
|
|
|
|
/**********************************************************
|
|
* Marker functions
|
|
***********************************************************/
|
|
|
|
beginAirdropViaMarker( lifeId, dropType )
|
|
{
|
|
self notify( "beginAirdropViaMarker" );
|
|
self endon( "beginAirdropViaMarker" );
|
|
|
|
self endon( "disconnect" );
|
|
level endon( "game_ended" );
|
|
|
|
// reworked this to thread all of the functions at once and then watch for what returns
|
|
// this fixes an infinite care package bug where you can kill the player as they throw it and they'll respawn with another one
|
|
self.threwAirDropMarker = undefined;
|
|
self.threwAirDropMarkerIndex = undefined;
|
|
self thread watchAirDropWeaponChange( lifeId, dropType );
|
|
self thread watchAirDropMarkerUsage( lifeId, dropType );
|
|
self thread watchAirDropMarker( lifeId, dropType );
|
|
|
|
result = self waittill_any_return( "notAirDropWeapon", "markerDetermined" );
|
|
if( IsDefined( result ) && result == "markerDetermined" )
|
|
return true;
|
|
// result comes back as undefined if the player is killed while throwing, so we need to check to see if they threw the marker before dying
|
|
else if( !IsDefined( result ) && IsDefined( self.threwAirDropMarker ) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
watchAirDropWeaponChange( lifeId, dropType )
|
|
{
|
|
level endon( "game_ended" );
|
|
|
|
self notify( "watchAirDropWeaponChange" );
|
|
self endon( "watchAirDropWeaponChange" );
|
|
|
|
self endon( "disconnect" );
|
|
self endon( "markerDetermined" );
|
|
|
|
while( self isChangingWeapon() )
|
|
wait ( 0.05 );
|
|
|
|
currentWeapon = self getCurrentWeapon();
|
|
|
|
if ( maps\mp\killstreaks\_killstreaks::isAirdropMarker( currentWeapon ) )
|
|
airdropMarkerWeapon = currentWeapon;
|
|
else
|
|
airdropMarkerWeapon = undefined;
|
|
|
|
while( maps\mp\killstreaks\_killstreaks::isAirdropMarker( currentWeapon ) /*|| currentWeapon == "none"*/ )
|
|
{
|
|
self waittill( "weapon_switch_started", currentWeapon );
|
|
|
|
if ( maps\mp\killstreaks\_killstreaks::isAirdropMarker( currentWeapon ) )
|
|
airdropMarkerWeapon = currentWeapon;
|
|
}
|
|
|
|
if( IsDefined( self.threwAirDropMarker ) )
|
|
{
|
|
// need to take the killstreak weapon here because the weapon_change happens before it can be taken in _killstreaks::waitTakeKillstreakWeapon()
|
|
killstreakWeapon = getKillstreakWeapon( self.pers["killstreaks"][self.threwAirDropMarkerIndex].streakName );
|
|
self TakeWeapon( killstreakWeapon );
|
|
|
|
self notify( "markerDetermined" );
|
|
}
|
|
else
|
|
self notify( "notAirDropWeapon" );
|
|
}
|
|
|
|
watchAirDropMarkerUsage( lifeId, dropType )
|
|
{
|
|
level endon( "game_ended" );
|
|
|
|
self notify( "watchAirDropMarkerUsage" );
|
|
self endon( "watchAirDropMarkerUsage" );
|
|
|
|
self endon( "disconnect" );
|
|
self endon( "markerDetermined" );
|
|
|
|
while( true )
|
|
{
|
|
self waittill( "grenade_pullback", weaponName );
|
|
|
|
// could've thrown a grenade while holding the airdrop weapon
|
|
if( !maps\mp\killstreaks\_killstreaks::isAirdropMarker( weaponName ) )
|
|
continue;
|
|
|
|
self _disableUsability();
|
|
|
|
self beginAirDropMarkerTracking();
|
|
}
|
|
}
|
|
|
|
watchAirDropMarker( lifeId, dropType )
|
|
{
|
|
level endon( "game_ended" );
|
|
|
|
self notify( "watchAirDropMarker" );
|
|
self endon( "watchAirDropMarker" );
|
|
|
|
self endon( "disconnect" );
|
|
self endon( "markerDetermined" );
|
|
|
|
while( true )
|
|
{
|
|
self waittill( "grenade_fire", airDropWeapon, weapname );
|
|
|
|
if ( !maps\mp\killstreaks\_killstreaks::isAirdropMarker( weapname ) )
|
|
continue;
|
|
|
|
self.threwAirDropMarker = true;
|
|
self.threwAirDropMarkerIndex = self.killstreakIndexWeapon;
|
|
airDropWeapon thread airdropDetonateOnStuck();
|
|
|
|
airDropWeapon.owner = self;
|
|
airDropWeapon.weaponName = weapname;
|
|
|
|
airDropWeapon thread airDropMarkerActivate( dropType );
|
|
}
|
|
}
|
|
|
|
beginAirDropMarkerTracking()
|
|
{
|
|
level endon( "game_ended" );
|
|
|
|
self notify( "beginAirDropMarkerTracking" );
|
|
self endon( "beginAirDropMarkerTracking" );
|
|
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
|
|
self waittill_any( "grenade_fire", "weapon_change" );
|
|
self _enableUsability();
|
|
}
|
|
|
|
airDropMarkerActivate( dropType, lifeId )
|
|
{
|
|
level endon( "game_ended" );
|
|
|
|
self notify( "airDropMarkerActivate" );
|
|
self endon( "airDropMarkerActivate" );
|
|
|
|
self waittill( "explode", position );
|
|
|
|
owner = self.owner;
|
|
|
|
// // TODO: DEV ONLY DELETE
|
|
// ent = Spawn( "script_model", position + ( 0, 0, 20 ) );
|
|
// ent SetModel( "mp_juggernaut_carepackage" );
|
|
// ent ScriptModelPlayAnim( "juggernaut_carepackage" );
|
|
|
|
if ( !IsDefined( owner ) )
|
|
return;
|
|
|
|
if ( owner isKillStreakDenied() )
|
|
return;
|
|
|
|
if( IsSubStr( toLower( dropType ), "escort_airdrop" ) && IsDefined( level.chopper ) )
|
|
return;
|
|
|
|
//// play an additional smoke fx that is longer than the normal for the escort airdrop
|
|
//if( IsSubStr( toLower( dropType ), "escort_airdrop" ) && IsDefined( level.chopper_fx["smoke"]["signal_smoke_30sec"] ) )
|
|
//{
|
|
// PlayFX( level.chopper_fx["smoke"]["signal_smoke_30sec"], position, ( 0, 0, -1 ) );
|
|
//}
|
|
|
|
wait 0.05;
|
|
|
|
if ( IsSubStr( toLower( dropType ), "juggernaut" ) )
|
|
level doC130FlyBy( owner, position, randomFloat( 360 ), dropType );
|
|
else if ( IsSubStr( toLower( dropType ), "escort_airdrop" ) )
|
|
owner maps\mp\killstreaks\_escortairdrop::finishSupportEscortUsage( lifeId, position, randomFloat( 360 ), "escort_airdrop" );
|
|
else
|
|
level doFlyBy( owner, position, randomFloat( 360 ), dropType );
|
|
}
|
|
|
|
/**********************************************************
|
|
* crate functions
|
|
***********************************************************/
|
|
initAirDropCrate()
|
|
{
|
|
self.inUse = false;
|
|
self hide();
|
|
|
|
if ( IsDefined( self.target ) )
|
|
{
|
|
self.collision = getEnt( self.target, "targetname" );
|
|
self.collision notSolid();
|
|
}
|
|
else
|
|
{
|
|
self.collision = undefined;
|
|
}
|
|
}
|
|
|
|
|
|
deleteOnOwnerDeath( owner )
|
|
{
|
|
wait ( 0.25 );
|
|
self linkTo( owner, "tag_origin", (0,0,0), (0,0,0) );
|
|
|
|
owner waittill ( "death" );
|
|
|
|
self delete();
|
|
}
|
|
|
|
|
|
crateTeamModelUpdater() // self == crate team model (the logo)
|
|
{
|
|
self endon ( "death" );
|
|
|
|
self hide();
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( player.team != "spectator" )
|
|
self ShowToPlayer( player );
|
|
}
|
|
|
|
for ( ;; )
|
|
{
|
|
level waittill ( "joined_team" );
|
|
|
|
self hide();
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( player.team != "spectator" )
|
|
self ShowToPlayer( player );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
crateModelTeamUpdater( showForTeam ) // self == crate model (friendly or enemy)
|
|
{
|
|
self endon ( "death" );
|
|
|
|
self hide();
|
|
|
|
foreach ( player in level.players )
|
|
{
|
|
// Freeroam spectator
|
|
if ( player.team == "spectator" )
|
|
{
|
|
if ( showForTeam == "allies" )
|
|
self ShowToPlayer( player );
|
|
}
|
|
// Spectating player or being part of the team
|
|
else if( player.team == showForTeam )
|
|
self ShowToPlayer( player );
|
|
}
|
|
|
|
for ( ;; )
|
|
{
|
|
level waittill ( "joined_team" );
|
|
|
|
self hide();
|
|
foreach ( player in level.players )
|
|
{
|
|
// Freeroam spectator
|
|
if ( player.team == "spectator" )
|
|
{
|
|
if ( showForTeam == "allies" )
|
|
self ShowToPlayer( player );
|
|
}
|
|
// Spectating player or being part of the team
|
|
else if( player.team == showForTeam )
|
|
self ShowToPlayer( player );
|
|
}
|
|
}
|
|
}
|
|
|
|
crateModelEnemyTeamsUpdater( ownerTeam ) // self == crate model (enemyTeams only)
|
|
{
|
|
self endon ( "death" );
|
|
|
|
self hide();
|
|
|
|
foreach ( player in level.players )
|
|
{
|
|
if( player.team != ownerTeam )
|
|
self ShowToPlayer( player );
|
|
}
|
|
|
|
for ( ;; )
|
|
{
|
|
level waittill ( "joined_team" );
|
|
|
|
self hide();
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( player.team != ownerTeam )
|
|
self ShowToPlayer( player );
|
|
}
|
|
}
|
|
}
|
|
|
|
// for FFA
|
|
crateModelPlayerUpdater( owner, friendly ) // self == crate model (friendly or enemy)
|
|
{
|
|
self endon ( "death" );
|
|
|
|
self hide();
|
|
|
|
foreach ( player in level.players )
|
|
{
|
|
if( friendly && IsDefined( owner ) && player != owner )
|
|
continue;
|
|
if( !friendly && IsDefined( owner ) && player == owner )
|
|
continue;
|
|
|
|
self ShowToPlayer( player );
|
|
}
|
|
|
|
for ( ;; )
|
|
{
|
|
level waittill ( "joined_team" );
|
|
|
|
self hide();
|
|
foreach ( player in level.players )
|
|
{
|
|
if( friendly && IsDefined( owner ) && player != owner )
|
|
continue;
|
|
if( !friendly && IsDefined( owner ) && player == owner )
|
|
continue;
|
|
|
|
self ShowToPlayer( player );
|
|
}
|
|
}
|
|
}
|
|
|
|
crateUseTeamUpdater( team )
|
|
{
|
|
self endon ( "death" );
|
|
|
|
for ( ;; )
|
|
{
|
|
setUsableByTeam( team );
|
|
|
|
level waittill ( "joined_team" );
|
|
}
|
|
}
|
|
|
|
crateUseTeamUpdater_multiTeams( team )
|
|
{
|
|
self endon ( "death" );
|
|
|
|
for ( ;; )
|
|
{
|
|
setUsableByOtherTeams( team );
|
|
|
|
level waittill ( "joined_team" );
|
|
|
|
}
|
|
}
|
|
|
|
crateUseJuggernautUpdater()
|
|
{
|
|
if ( !isSubStr( self.crateType, "juggernaut" ) )
|
|
return;
|
|
|
|
self endon( "death" );
|
|
level endon( "game_ended" );
|
|
|
|
for ( ;; )
|
|
{
|
|
level waittill ( "juggernaut_equipped", player );
|
|
|
|
self disablePlayerUse( player );
|
|
self thread crateUsePostJuggernautUpdater( player );
|
|
}
|
|
}
|
|
|
|
crateUsePostJuggernautUpdater( player )
|
|
{
|
|
self endon( "death" );
|
|
level endon( "game_ended" );
|
|
player endon( "disconnect" );
|
|
|
|
player waittill( "death" );
|
|
self enablePlayerUse( player );
|
|
}
|
|
|
|
createAirDropCrate( owner, dropType, crateType, startPos, dropPoint, crateColor )
|
|
{
|
|
dropCrate = Spawn( "script_model", startPos );
|
|
|
|
dropCrate.curProgress = 0;
|
|
dropCrate.useTime = 0;
|
|
dropCrate.useRate = 0;
|
|
dropCrate.team = self.team;
|
|
dropCrate.destination = dropPoint;
|
|
dropCrate.id = "care_package";
|
|
|
|
if ( IsDefined( owner ) )
|
|
dropCrate.owner = owner;
|
|
else
|
|
dropCrate.owner = undefined;
|
|
|
|
dropCrate.crateType = crateType;
|
|
dropCrate.dropType = dropType;
|
|
dropCrate.targetname = "care_package";
|
|
|
|
dummy_model = DUMMY_CRATE_MODEL;
|
|
if ( isDefined ( level.custom_dummy_crate_model ))
|
|
dummy_model = level.custom_dummy_crate_model;
|
|
|
|
dropCrate SetModel( dummy_model );
|
|
|
|
if ( crateType == "airdrop_jackpot" )
|
|
{
|
|
dropCrate.friendlyModel = Spawn( "script_model", startPos );
|
|
dropCrate.friendlyModel SetModel( level.crateTypes[ dropType ][ crateType ].model_name_friendly );
|
|
dropCrate.friendlyModel thread deleteOnOwnerDeath( dropCrate );
|
|
}
|
|
else
|
|
{
|
|
dropCrate.friendlyModel = Spawn( "script_model", startPos );
|
|
dropCrate.friendlyModel SetModel( level.crateTypes[ dropType ][ crateType ].model_name_friendly );
|
|
|
|
if( IsDefined(level.highLightAirDrop) && level.highLightAirDrop )
|
|
{
|
|
if( !IsDefined(crateColor) )
|
|
crateColor = 2;
|
|
|
|
dropCrate.friendlyModel HudOutlineEnable( crateColor, false );
|
|
dropCrate.outlineColor = crateColor;
|
|
}
|
|
|
|
dropCrate.enemyModel = Spawn( "script_model", startPos );
|
|
dropCrate.enemyModel SetModel( level.crateTypes[ dropType ][ crateType ].model_name_enemy );
|
|
|
|
dropCrate.friendlyModel SetEntityOwner( dropCrate );
|
|
dropCrate.enemyModel SetEntityOwner( dropCrate );
|
|
|
|
dropCrate.friendlyModel thread deleteOnOwnerDeath( dropCrate );
|
|
if( level.teambased )
|
|
dropCrate.friendlyModel thread crateModelTeamUpdater( dropCrate.team );
|
|
else
|
|
dropCrate.friendlyModel thread crateModelPlayerUpdater( owner, true );
|
|
|
|
dropCrate.enemyModel thread deleteOnOwnerDeath( dropCrate );
|
|
if( level.multiTeambased )
|
|
dropCrate.enemyModel thread crateModelEnemyTeamsUpdater( dropCrate.team );
|
|
else if( level.teambased )
|
|
dropCrate.enemyModel thread crateModelTeamUpdater( level.otherTeam[dropCrate.team] );
|
|
else
|
|
dropCrate.enemyModel thread crateModelPlayerUpdater( owner, false );
|
|
}
|
|
|
|
dropCrate.inUse = false;
|
|
|
|
dropCrate CloneBrushmodelToScriptmodel( level.airDropCrateCollision );
|
|
dropCrate thread entity_path_disconnect_thread( 1.0 );
|
|
|
|
dropCrate.killCamEnt = Spawn( "script_model", dropCrate.origin + CRATE_KILLCAM_OFFSET, 0, true );
|
|
dropCrate.killCamEnt SetScriptMoverKillCam( "explosive" );
|
|
dropCrate.killCamEnt LinkTo( dropCrate );
|
|
|
|
level.numDropCrates++;
|
|
dropCrate thread dropCrateExistence(dropPoint);
|
|
level notify("createAirDropCrate", dropCrate);
|
|
|
|
return dropCrate;
|
|
}
|
|
|
|
dropCrateExistence(dropPoint)
|
|
{
|
|
level endon( "game_ended" );
|
|
|
|
self waittill( "death" );
|
|
|
|
// SOTF - Needed for clearing the used position for the killed crate
|
|
if(IsDefined(level.crateKill))
|
|
[[level.crateKill]](dropPoint);
|
|
|
|
level.numDropCrates--;
|
|
}
|
|
|
|
crateSetupForUse( hintString, icon )
|
|
{
|
|
self setCursorHint( "HINT_NOICON" );
|
|
self setHintString( hintString );
|
|
self makeUsable();
|
|
|
|
friendlyShader = "compass_objpoint_ammo_friendly";
|
|
enemyShader = "compass_objpoint_ammo_enemy";
|
|
|
|
if( IsDefined(level.objVisAll) )
|
|
enemyShader = "compass_objpoint_ammo_friendly";
|
|
|
|
if( !IsDefined(self.objIdFriendly) )
|
|
self.objIdFriendly = createObjective( friendlyShader, self.team, true );
|
|
|
|
if( !IsDefined(self.objIdEnemy) )
|
|
self.objIdEnemy = createObjective( enemyShader, level.otherTeam[ self.team ], false );
|
|
|
|
self thread crateUseTeamUpdater();
|
|
self thread crateUseJuggernautUpdater();
|
|
|
|
if( isSubStr( self.crateType, "juggernaut" ) )
|
|
{
|
|
foreach ( player in level.players )
|
|
if ( player isJuggernaut() )
|
|
self thread crateUsePostJuggernautUpdater( player );
|
|
}
|
|
|
|
headIcon = undefined;
|
|
if( level.teamBased )
|
|
headIcon = self maps\mp\_entityheadIcons::setHeadIcon( self.team, icon, (0,0,24), 14, 14, false, undefined, undefined, undefined, undefined, false );
|
|
else if ( IsDefined( self.owner ) )
|
|
headIcon = self maps\mp\_entityheadIcons::setHeadIcon( self.owner, icon, (0,0,24), 14, 14, false, undefined, undefined, undefined, undefined, false );
|
|
if ( IsDefined( headIcon ) )
|
|
headIcon.showInKillcam = false;
|
|
|
|
// make sure the head icon for crates are visible to everyone
|
|
if( IsDefined(level.iconVisAll) )
|
|
[[level.iconVisAll]](self, icon);
|
|
else
|
|
{
|
|
// MLG: make sure spectators can see this crate headicon as well
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( player.team == "spectator" )
|
|
headIcon = self maps\mp\_entityheadIcons::setHeadIcon( player, icon, (0,0,24), 14, 14, false, undefined, undefined, undefined, undefined, false );
|
|
}
|
|
}
|
|
}
|
|
|
|
createObjective( shaderName, team, friendly )
|
|
{
|
|
curObjID = maps\mp\gametypes\_gameobjects::getNextObjID();
|
|
objective_add( curObjID, "invisible", (0,0,0) );
|
|
if ( !IsDefined( self GetLinkedParent() ) )
|
|
Objective_Position( curObjID, self.origin );
|
|
else
|
|
Objective_OnEntity( curObjID, self );
|
|
objective_state( curObjID, "active" );
|
|
|
|
objective_icon( curObjID, shaderName );
|
|
|
|
if( !level.teamBased && IsDefined( self.owner ) )
|
|
if( friendly )
|
|
Objective_PlayerTeam( curObjId, self.owner GetEntityNumber() );
|
|
else
|
|
Objective_PlayerEnemyTeam( curObjId, self.owner GetEntityNumber() );
|
|
else
|
|
Objective_Team( curObjID, team );
|
|
|
|
// SOTF - Make this objective visible to all
|
|
if ( IsDefined( level.objVisAll ) )
|
|
[[ level.objVisAll ]]( curObjID );
|
|
|
|
return curObjID;
|
|
}
|
|
|
|
|
|
setUsableByTeam( team )
|
|
{
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( isSubStr( self.crateType, "juggernaut" ) && player isJuggernaut() )
|
|
{
|
|
self DisablePlayerUse( player );
|
|
}
|
|
else if ( isSubStr( self.crateType, "lased" ) && IsDefined(player.hasSoflam) && player.hasSoflam )
|
|
{
|
|
self DisablePlayerUse( player );
|
|
}
|
|
else if ( !IsDefined( team ) || team == player.team )
|
|
self EnablePlayerUse( player );
|
|
else
|
|
self DisablePlayerUse( player );
|
|
}
|
|
}
|
|
|
|
//adding reverse logic version for when there are more than two teams
|
|
setUsableByOtherTeams( team )
|
|
{
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( isSubStr( self.crateType, "juggernaut" ) && player isJuggernaut() )
|
|
{
|
|
self DisablePlayerUse( player );
|
|
}
|
|
else if ( !IsDefined( team ) || team != player.team )
|
|
self EnablePlayerUse( player );
|
|
else
|
|
self DisablePlayerUse( player );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
dropTheCrate( dropPoint, dropType, lbHeight, dropImmediately, crateOverride, startPos, dropImpulse, previousCrateTypes, tagName )
|
|
{
|
|
dropCrate = [];
|
|
self.owner endon ( "disconnect" );
|
|
|
|
if ( !IsDefined( crateOverride ) )
|
|
{
|
|
// verify emergency airdrops don't drop dupes
|
|
if ( IsDefined( previousCrateTypes ) )
|
|
{
|
|
foundDupe = undefined;
|
|
crateType = undefined;
|
|
for ( i=0; i<100; i++ )
|
|
{
|
|
crateType = getCrateTypeForDropType( dropType );
|
|
foundDupe = false;
|
|
for ( j=0; j<previousCrateTypes.size; j++ )
|
|
{
|
|
if ( crateType == previousCrateTypes[j] )
|
|
{
|
|
foundDupe = true;
|
|
break;
|
|
}
|
|
}
|
|
if ( foundDupe == false )
|
|
break;
|
|
}
|
|
// if 100 attempts fail, just get whatever, we tried
|
|
if ( foundDupe == true )
|
|
{
|
|
crateType = getCrateTypeForDropType( dropType );
|
|
}
|
|
}
|
|
else
|
|
crateType = getCrateTypeForDropType( dropType );
|
|
}
|
|
else
|
|
crateType = crateOverride;
|
|
|
|
if ( !IsDefined( dropImpulse ) )
|
|
dropImpulse = (RandomInt(50),RandomInt(50),RandomInt(50));
|
|
|
|
dropCrate = createAirDropCrate( self.owner, dropType, crateType, startPos, dropPoint );
|
|
|
|
switch( dropType )
|
|
{
|
|
case "airdrop_mega":
|
|
case "nuke_drop":
|
|
case "airdrop_juggernaut":
|
|
case "airdrop_juggernaut_recon":
|
|
case "airdrop_juggernaut_maniac":
|
|
dropCrate LinkTo( self, "tag_ground" , (64,32,-128) , (0,0,0) );
|
|
break;
|
|
case "airdrop_escort":
|
|
case "airdrop_osprey_gunner":
|
|
dropCrate LinkTo( self, tagName, (0,0,0), (0,0,0) );
|
|
break;
|
|
default:
|
|
dropCrate LinkTo( self, "tag_ground" , (32,0,5) , (0,0,0) );
|
|
break;
|
|
}
|
|
|
|
dropCrate.angles = (0,0,0);
|
|
dropCrate show();
|
|
dropSpeed = self.veh_speed;
|
|
|
|
// don't do a drop impulse if this is considered a juggernaut crate, this could happen for level killstreaks (predator, myers)
|
|
if( IsSubStr( crateType, "juggernaut" ) )
|
|
dropImpulse = (0,0,0);
|
|
|
|
self thread waitForDropCrateMsg( dropCrate, dropImpulse, dropType, crateType );
|
|
dropCrate.droppingToGround = true;
|
|
|
|
return crateType;
|
|
}
|
|
|
|
|
|
killPlayerFromCrate_DoDamage( hitEnt )
|
|
{
|
|
if( IsDefined(level.noAirDropKills) && level.noAirDropKills )
|
|
return;
|
|
|
|
hitEnt DoDamage( 1000, hitEnt.origin, self, self, "MOD_CRUSH" );
|
|
}
|
|
|
|
|
|
killPlayerFromCrate_FastVelocityPush()
|
|
{
|
|
self endon( "death" );
|
|
|
|
while( 1 )
|
|
{
|
|
self waittill( "player_pushed", hitEnt, platformMPH );
|
|
if ( isPlayer( hitEnt ) || isAgent( hitEnt ) )
|
|
{
|
|
if ( platformMPH[2] < -20 )
|
|
{
|
|
self killPlayerFromCrate_DoDamage( hitEnt );
|
|
}
|
|
}
|
|
wait 0.05;
|
|
}
|
|
}
|
|
|
|
airdrop_override_death_moving_platform( data )
|
|
{
|
|
// Put back in if ready to allow airdrop destroy.
|
|
if ( IsDefined( data.lastTouchedPlatform.destroyAirdropOnCollision ) && data.lastTouchedPlatform.destroyAirdropOnCollision )
|
|
{
|
|
PlayFX( getfx( "airdrop_crate_destroy" ), self.origin );
|
|
self deleteCrate();
|
|
}
|
|
}
|
|
|
|
cleanup_crate_capture()
|
|
{
|
|
children = self GetLinkedChildren( true );
|
|
if ( !IsDefined( children ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach ( player in children )
|
|
{
|
|
if( !IsPlayer( player ) )
|
|
continue;
|
|
|
|
if ( IsDefined( player.isCapturingCrate ) && player.isCapturingCrate )
|
|
{
|
|
parent = player GetLinkedParent();
|
|
if ( IsDefined( parent ) )
|
|
{
|
|
player maps\mp\gametypes\_gameobjects::updateUIProgress( parent, false );
|
|
player unlink();
|
|
}
|
|
|
|
if ( isAlive( player ) )
|
|
player _enableWeapon();
|
|
|
|
player.isCapturingCrate = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
airdrop_override_invalid_moving_platform( data )
|
|
{
|
|
// Need to wait for parent to be gone.
|
|
wait( 0.05 );
|
|
|
|
self notify( "restarting_physics" );
|
|
self cleanup_crate_capture();
|
|
self PhysicsLaunchServer( (0,0,0), data.dropImpulse, data.airDrop_max_linear_velocity );
|
|
self thread physicsUpdater( data.dropType, data.crateType );
|
|
self thread physicsWaiter( data.dropType, data.crateType, data.dropImpulse, data.airDrop_max_linear_velocity );
|
|
}
|
|
|
|
waitForDropCrateMsg( dropCrate, dropImpulse, dropType, crateType, optionalVelocity, dropImmediately )
|
|
{
|
|
dropCrate endon("death");
|
|
|
|
if( !IsDefined(dropImmediately) || !dropImmediately )
|
|
self waittill ( "drop_crate" );
|
|
|
|
airDrop_max_linear_velocity = 1200;
|
|
|
|
/#
|
|
airDrop_max_linear_velocity = getdvarfloat( "scr_airDrop_max_linear_velocity", 1200 );
|
|
#/
|
|
|
|
if( IsDefined(optionalVelocity) )
|
|
airDrop_max_linear_velocity = optionalVelocity;
|
|
|
|
dropCrate Unlink();
|
|
dropCrate PhysicsLaunchServer( (0,0,0), dropImpulse, airDrop_max_linear_velocity );
|
|
dropCrate thread physicsUpdater( dropType, crateType );
|
|
dropCrate thread physicsWaiter( dropType, crateType, dropImpulse, airDrop_max_linear_velocity );
|
|
dropCrate thread killPlayerFromCrate_FastVelocityPush();
|
|
dropCrate.unresolved_collision_func = ::killPlayerFromCrate_DoDamage;
|
|
|
|
if( IsDefined( dropCrate.killCamEnt ) )
|
|
{
|
|
// Adding offset for Carestrike killcam to follow lobbed care packages
|
|
if ( IsDefined( dropCrate.carestrike ) )
|
|
{
|
|
horizontal_offset = -2100;
|
|
}
|
|
else
|
|
horizontal_offset = 0;
|
|
|
|
// calculate the time it takes to get from here to the ground
|
|
dropCrate.killCamEnt Unlink();
|
|
groundTrace = BulletTrace( dropCrate.origin, dropCrate.origin + ( 0, 0, -10000 ), false, dropCrate );
|
|
travelDistance = Distance( dropCrate.origin, groundTrace[ "position" ] );
|
|
//travelDistance *= 2;
|
|
travelTime = travelDistance / GRAVITY_UNITS_PER_SECOND;
|
|
//travleTime = sqrt( travelTime );
|
|
dropCrate.killCamEnt MoveTo( groundTrace[ "position" ] + CRATE_KILLCAM_OFFSET + ( horizontal_offset, 0, 0 ), travelTime );
|
|
//dropCrate.killCamEnt MoveGravity( ( 0, 0, -1 ), travelTime );
|
|
}
|
|
}
|
|
|
|
physicsUpdater( dropType, crateType )
|
|
{
|
|
self endon( "restarting_physics" );
|
|
self endon( "physics_finished" );
|
|
|
|
// wait for airplane/helicopter to move out the way
|
|
wait( 0.5 );
|
|
|
|
while( true )
|
|
{
|
|
if ( !isDefined( self ) )
|
|
return;
|
|
|
|
// bullet cast down - don't use clipshot
|
|
groundTrace = BulletTrace( self.origin, self.origin + ( 0, 0, -60 ), false, self, false, false, false, true );
|
|
if ( groundTrace[ "fraction" ] < 1.0 )
|
|
{
|
|
airDrop_slowdown_max_linear_velocity = 600;
|
|
/#
|
|
airDrop_slowdown_max_linear_velocity = getdvarfloat( "scr_airDrop_slowdown_max_linear_velocity", 600 );
|
|
#/
|
|
|
|
self PhysicsSetMaxLinVel( airDrop_slowdown_max_linear_velocity );
|
|
self thread waitAndAnimate();
|
|
return;
|
|
}
|
|
|
|
// wait till next frame
|
|
waitframe();
|
|
}
|
|
}
|
|
|
|
waitAndAnimate() // self == care package
|
|
{
|
|
self endon( "death" );
|
|
|
|
wait( 0.035 );
|
|
|
|
PlayFX( level._effect[ "airdrop_dust_kickup" ], self.origin + ( 0, 0, 5 ), ( 0, 0, 1 ) );
|
|
self.friendlyModel ScriptModelPlayAnim( "juggernaut_carepackage" );
|
|
self.enemyModel ScriptModelPlayAnim( "juggernaut_carepackage" );
|
|
}
|
|
|
|
physicsWaiter( dropType, crateType, dropImpulse, airDrop_max_linear_velocity )
|
|
{
|
|
self endon( "restarting_physics" );
|
|
self waittill( "physics_finished" );
|
|
|
|
// ent = Spawn( "script_model", self.origin );
|
|
// ent.angles = self.angles;
|
|
// ent SetModel( "mp_juggernaut_carepackage" );
|
|
// self Hide();
|
|
// ent ScriptModelPlayAnim( "juggernaut_carepackage" );
|
|
|
|
self.droppingToGround = false;
|
|
self thread [[ level.crateTypes[ dropType ][ crateType ].func ]]( dropType );
|
|
level thread dropTimeOut( self, self.owner, crateType );
|
|
|
|
// Handle moving platform.
|
|
data = SpawnStruct();
|
|
data.endonString = "restarting_physics";
|
|
data.deathOverrideCallback = ::airdrop_override_death_moving_platform;
|
|
data.invalidParentOverrideCallback = ::airdrop_override_invalid_moving_platform;
|
|
data.dropType = dropType;
|
|
data.crateType = crateType;
|
|
data.dropImpulse = dropImpulse;
|
|
data.airDrop_max_linear_velocity = airDrop_max_linear_velocity;
|
|
self thread maps\mp\_movers::handle_moving_platforms( data );
|
|
|
|
if ( self.friendlyModel touchingBadTrigger() )
|
|
{
|
|
self deleteCrate();
|
|
return;
|
|
}
|
|
|
|
if( IsDefined(self.owner) && ( abs(self.origin[2] - self.owner.origin[2]) > 3000 ) )
|
|
{
|
|
self deleteCrate();
|
|
}
|
|
}
|
|
|
|
//deletes if crate wasnt used after 90 seconds
|
|
dropTimeOut( dropCrate, owner, crateType )
|
|
{
|
|
if( IsDefined(level.noCrateTimeOut) && (level.noCrateTimeOut) )
|
|
return;
|
|
|
|
level endon ( "game_ended" );
|
|
dropCrate endon( "death" );
|
|
|
|
if ( dropCrate.dropType == "nuke_drop" )
|
|
return;
|
|
|
|
timeOut = 90.0;
|
|
if ( crateType == "supply" )
|
|
timeOut = 20.0;
|
|
|
|
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( timeOut );
|
|
|
|
while ( dropCrate.curProgress != 0 )
|
|
wait 1;
|
|
|
|
dropCrate deleteCrate();
|
|
}
|
|
|
|
|
|
getPathStart( coord, yaw )
|
|
{
|
|
pathRandomness = 100;
|
|
lbHalfDistance = 15000;
|
|
|
|
direction = (0,yaw,0);
|
|
|
|
startPoint = coord + ( AnglesToForward( direction ) * ( -1 * lbHalfDistance ) );
|
|
startPoint += ( (randomfloat(2) - 1)*pathRandomness, (randomfloat(2) - 1)*pathRandomness, 0 );
|
|
|
|
return startPoint;
|
|
}
|
|
|
|
|
|
getPathEnd( coord, yaw )
|
|
{
|
|
pathRandomness = 150;
|
|
lbHalfDistance = 15000;
|
|
|
|
direction = (0,yaw,0);
|
|
|
|
endPoint = coord + ( AnglesToForward( direction + ( 0, 90, 0 ) ) * lbHalfDistance );
|
|
endPoint += ( (randomfloat(2) - 1)*pathRandomness , (randomfloat(2) - 1)*pathRandomness , 0 );
|
|
|
|
return endPoint;
|
|
}
|
|
|
|
|
|
getFlyHeightOffset( dropSite )
|
|
{
|
|
lbFlyHeight = 850;
|
|
|
|
heightEnt = GetEnt( "airstrikeheight", "targetname" );
|
|
|
|
if ( !IsDefined( heightEnt ) )//old system
|
|
{
|
|
/#
|
|
println( "NO DEFINED AIRSTRIKE HEIGHT SCRIPT_ORIGIN IN LEVEL" );
|
|
#/
|
|
if ( IsDefined( level.airstrikeHeightScale ) )
|
|
{
|
|
if ( level.airstrikeHeightScale > 2 )
|
|
{
|
|
lbFlyHeight = 1500;
|
|
return( lbFlyHeight * (level.airStrikeHeightScale ) );
|
|
}
|
|
|
|
return( lbFlyHeight * level.airStrikeHeightScale + 256 + dropSite[2] );
|
|
}
|
|
else
|
|
return ( lbFlyHeight + dropsite[2] );
|
|
}
|
|
else
|
|
{
|
|
return heightEnt.origin[2];
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**********************************************************
|
|
* Helicopter Functions
|
|
***********************************************************/
|
|
|
|
doFlyBy( owner, dropSite, dropYaw, dropType, heightAdjustment, crateOverride )
|
|
{
|
|
if ( !IsDefined( owner ) )
|
|
return;
|
|
|
|
// safety check against script directly calling doFlyBy without propperly checking vehicle counts
|
|
if( currentActiveVehicleCount() >= maxVehiclesAllowed() )
|
|
return;
|
|
|
|
flyHeight = self getFlyHeightOffset( dropSite );
|
|
if ( IsDefined( heightAdjustment ) )
|
|
flyHeight += heightAdjustment;
|
|
foreach( littlebird in level.littlebirds )
|
|
{
|
|
if ( IsDefined( littlebird.dropType ) )
|
|
flyHeight += 128;
|
|
}
|
|
|
|
pathGoal = dropSite * (1,1,0) + (0,0,flyHeight);
|
|
pathStart = getPathStart( pathGoal, dropYaw );
|
|
pathEnd = getPathEnd( pathGoal, dropYaw );
|
|
|
|
pathGoal = pathGoal + ( AnglesToForward( ( 0, dropYaw, 0 ) ) * -50 );
|
|
|
|
chopper = heliSetup( owner, pathStart, pathGoal );
|
|
|
|
if( IsDefined(level.highLightAirDrop) && level.highLightAirDrop )
|
|
chopper HudOutlineEnable( 3, false );
|
|
|
|
assert ( IsDefined( chopper ) );
|
|
|
|
chopper endon( "death" );
|
|
|
|
/#
|
|
if( GetDvar( "scr_crateOverride" ) != "" )
|
|
{
|
|
crateOverride = GetDvar( "scr_crateOverride" );
|
|
dropType = GetDvar( "scr_crateTypeOverride" );
|
|
}
|
|
#/
|
|
|
|
chopper.dropType = dropType;
|
|
|
|
chopper setVehGoalPos( pathGoal, 1 );
|
|
|
|
chopper thread dropTheCrate( dropSite, dropType, flyHeight, false, crateOverride, pathStart );
|
|
|
|
wait ( 2 );
|
|
|
|
chopper Vehicle_SetSpeed( 75, 40 );
|
|
chopper SetYawSpeed( 180, 180, 180, .3 );
|
|
|
|
chopper waittill ( "goal" );
|
|
wait( .10 );
|
|
chopper notify( "drop_crate" );
|
|
chopper setvehgoalpos( pathEnd, 1 );
|
|
chopper Vehicle_SetSpeed( 300, 75 );
|
|
chopper.leaving = true;
|
|
chopper waittill ( "goal" );
|
|
chopper notify( "leaving" );
|
|
chopper notify( "delete" );
|
|
|
|
// decrement the faux vehicle count right before it is deleted this way we know for sure it is gone
|
|
decrementFauxVehicleCount();
|
|
|
|
chopper delete();
|
|
}
|
|
|
|
doMegaFlyBy( owner, dropSite, dropYaw, dropType )
|
|
{
|
|
level thread doFlyBy( owner, dropSite, dropYaw, dropType, 0 );
|
|
wait( RandomIntRange( 1,2 ) );
|
|
level thread doFlyBy( owner, dropSite + (128,128,0), dropYaw, dropType, 128 );
|
|
wait( RandomIntRange( 1,2 ) );
|
|
level thread doFlyBy( owner, dropSite + (172,256,0), dropYaw, dropType, 256 );
|
|
wait( RandomIntRange( 1,2 ) );
|
|
level thread doFlyBy( owner, dropSite + (64,0,0), dropYaw, dropType, 0 );
|
|
}
|
|
|
|
doC130FlyBy( owner, dropSite, dropYaw, dropType )
|
|
{
|
|
planeHalfDistance = 18000;
|
|
planeFlySpeed = 3000;
|
|
yaw = VectorToYaw( dropsite - owner.origin );
|
|
|
|
direction = ( 0, yaw, 0 );
|
|
|
|
flyHeight = self getFlyHeightOffset( dropSite );
|
|
|
|
pathStart = dropSite + ( AnglesToForward( direction ) * ( -1 * planeHalfDistance ) );
|
|
pathStart = pathStart * ( 1, 1, 0 ) + ( 0, 0, flyHeight );
|
|
|
|
pathEnd = dropSite + ( AnglesToForward( direction ) * planeHalfDistance );
|
|
pathEnd = pathEnd * ( 1, 1, 0 ) + ( 0, 0, flyHeight );
|
|
|
|
d = length( pathStart - pathEnd );
|
|
flyTime = ( d / planeFlySpeed );
|
|
|
|
c130 = c130Setup( owner, pathStart, pathEnd );
|
|
c130.veh_speed = planeFlySpeed;
|
|
c130.dropType = dropType;
|
|
c130 PlayLoopSound( "veh_ac130_dist_loop" );
|
|
|
|
c130.angles = direction;
|
|
forward = AnglesToForward( direction );
|
|
c130 MoveTo( pathEnd, flyTime, 0, 0 );
|
|
|
|
minDist = Distance2D( c130.origin, dropSite );
|
|
boomPlayed = false;
|
|
|
|
for(;;)
|
|
{
|
|
dist = Distance2D( c130.origin, dropSite );
|
|
|
|
// handle missing our target
|
|
if ( dist < minDist )
|
|
minDist = dist;
|
|
else if ( dist > minDist )
|
|
break;
|
|
|
|
if ( dist < 320 )
|
|
{
|
|
break;
|
|
}
|
|
else if ( dist < 768 )
|
|
{
|
|
earthquake( 0.15, 1.5, dropSite, 1500 );
|
|
if ( !boomPlayed )
|
|
{
|
|
c130 playSound( "veh_ac130_sonic_boom" );
|
|
//c130 thread stopLoopAfter( 0.5 );
|
|
boomPlayed = true;
|
|
}
|
|
}
|
|
|
|
wait ( .05 );
|
|
}
|
|
wait( 0.05 );
|
|
|
|
dropImpulse = (0,0,0);
|
|
|
|
if ( !is_aliens() )
|
|
{
|
|
crateType[0] = c130 thread dropTheCrate( dropSite, dropType, flyHeight, false, undefined, pathStart, dropImpulse );
|
|
}
|
|
wait ( 0.05 );
|
|
c130 notify ( "drop_crate" );
|
|
|
|
newPathEnd = dropSite + ( AnglesToForward( direction ) * (planeHalfDistance*1.5) );
|
|
c130 MoveTo( newPathEnd, flyTime/2, 0, 0 );
|
|
|
|
wait ( 6 );
|
|
c130 delete();
|
|
}
|
|
|
|
|
|
doMegaC130FlyBy( owner, dropSite, dropYaw, dropType, forwardOffset )
|
|
{
|
|
planeHalfDistance = 24000;
|
|
planeFlySpeed = 2000;
|
|
yaw = VectorToYaw( dropsite - owner.origin );
|
|
direction = ( 0, yaw, 0 );
|
|
forward = AnglesToForward( direction );
|
|
|
|
if ( IsDefined( forwardOffset ) )
|
|
dropSite = dropSite + forward * forwardOffset;
|
|
|
|
flyHeight = self getFlyHeightOffset( dropSite );
|
|
|
|
pathStart = dropSite + ( AnglesToForward( direction ) * ( -1 * planeHalfDistance ) );
|
|
pathStart = pathStart * ( 1, 1, 0 ) + ( 0, 0, flyHeight );
|
|
|
|
pathEnd = dropSite + ( AnglesToForward( direction ) * planeHalfDistance );
|
|
pathEnd = pathEnd * ( 1, 1, 0 ) + ( 0, 0, flyHeight );
|
|
|
|
d = length( pathStart - pathEnd );
|
|
flyTime = ( d / planeFlySpeed );
|
|
|
|
c130 = c130Setup( owner, pathStart, pathEnd );
|
|
c130.veh_speed = planeFlySpeed;
|
|
c130.dropType = dropType;
|
|
c130 PlayLoopSound( "veh_ac130_dist_loop" );
|
|
|
|
c130.angles = direction;
|
|
forward = AnglesToForward( direction );
|
|
c130 MoveTo( pathEnd, flyTime, 0, 0 );
|
|
|
|
minDist = Distance2D( c130.origin, dropSite );
|
|
boomPlayed = false;
|
|
|
|
for(;;)
|
|
{
|
|
dist = Distance2D( c130.origin, dropSite );
|
|
|
|
// handle missing our target
|
|
if ( dist < minDist )
|
|
minDist = dist;
|
|
else if ( dist > minDist )
|
|
break;
|
|
|
|
if ( dist < 256 )
|
|
{
|
|
break;
|
|
}
|
|
else if ( dist < 768 )
|
|
{
|
|
earthquake( 0.15, 1.5, dropSite, 1500 );
|
|
if ( !boomPlayed )
|
|
{
|
|
c130 playSound( "veh_ac130_sonic_boom" );
|
|
//c130 thread stopLoopAfter( 0.5 );
|
|
boomPlayed = true;
|
|
}
|
|
}
|
|
|
|
wait ( .05 );
|
|
}
|
|
wait( 0.05 );
|
|
|
|
crateType[0] = c130 thread dropTheCrate( dropSite, dropType, flyHeight, false, undefined, pathStart );
|
|
wait ( 0.05 );
|
|
c130 notify ( "drop_crate" );
|
|
wait ( 0.05 );
|
|
|
|
crateType[1] = c130 thread dropTheCrate( dropSite, dropType, flyHeight, false, undefined, pathStart, undefined, crateType );
|
|
wait ( 0.05 );
|
|
c130 notify ( "drop_crate" );
|
|
wait ( 0.05 );
|
|
|
|
crateType[2] = c130 thread dropTheCrate( dropSite, dropType, flyHeight, false, undefined, pathStart, undefined, crateType );
|
|
wait ( 0.05 );
|
|
c130 notify ( "drop_crate" );
|
|
wait ( 0.05 );
|
|
|
|
crateType[3] = c130 thread dropTheCrate( dropSite, dropType, flyHeight, false, undefined, pathStart, undefined, crateType );
|
|
wait ( 0.05 );
|
|
c130 notify ( "drop_crate" );
|
|
|
|
wait ( 4 );
|
|
c130 delete();
|
|
}
|
|
|
|
|
|
dropNuke( dropSite, owner, dropType )
|
|
{
|
|
planeHalfDistance = 24000;
|
|
planeFlySpeed = 2000;
|
|
yaw = RandomInt( 360 );
|
|
|
|
direction = ( 0, yaw, 0 );
|
|
|
|
flyHeight = self getFlyHeightOffset( dropSite );
|
|
|
|
pathStart = dropSite + ( AnglesToForward( direction ) * ( -1 * planeHalfDistance ) );
|
|
pathStart = pathStart * ( 1, 1, 0 ) + ( 0, 0, flyHeight );
|
|
|
|
pathEnd = dropSite + ( AnglesToForward( direction ) * planeHalfDistance );
|
|
pathEnd = pathEnd * ( 1, 1, 0 ) + ( 0, 0, flyHeight );
|
|
|
|
d = length( pathStart - pathEnd );
|
|
flyTime = ( d / planeFlySpeed );
|
|
|
|
c130 = c130Setup( owner, pathStart, pathEnd );
|
|
c130.veh_speed = planeFlySpeed;
|
|
c130.dropType = dropType;
|
|
c130 PlayLoopSound( "veh_ac130_dist_loop" );
|
|
|
|
c130.angles = direction;
|
|
forward = AnglesToForward( direction );
|
|
c130 MoveTo( pathEnd, flyTime, 0, 0 );
|
|
|
|
// TODO: fix this... it's bad. if we miss our distance (which could happen if plane speed is changed in the future) we stick in this thread forever
|
|
boomPlayed = false;
|
|
minDist = Distance2D( c130.origin, dropSite );
|
|
for(;;)
|
|
{
|
|
dist = Distance2D( c130.origin, dropSite );
|
|
|
|
// handle missing our target
|
|
if ( dist < minDist )
|
|
minDist = dist;
|
|
else if ( dist > minDist )
|
|
break;
|
|
|
|
if ( dist < 256 )
|
|
{
|
|
break;
|
|
}
|
|
else if ( dist < 768 )
|
|
{
|
|
earthquake( 0.15, 1.5, dropSite, 1500 );
|
|
if ( !boomPlayed )
|
|
{
|
|
c130 playSound( "veh_ac130_sonic_boom" );
|
|
//c130 thread stopLoopAfter( 0.5 );
|
|
boomPlayed = true;
|
|
}
|
|
}
|
|
|
|
wait ( .05 );
|
|
}
|
|
|
|
c130 thread dropTheCrate( dropSite, dropType, flyHeight, false, "nuke", pathStart );
|
|
wait ( 0.05 );
|
|
c130 notify ( "drop_crate" );
|
|
|
|
wait ( 4 );
|
|
c130 delete();
|
|
}
|
|
|
|
stopLoopAfter( delay )
|
|
{
|
|
self endon ( "death" );
|
|
|
|
wait ( delay );
|
|
self stoploopsound();
|
|
}
|
|
|
|
|
|
playloopOnEnt( alias )
|
|
{
|
|
soundOrg = Spawn( "script_origin", ( 0, 0, 0 ) );
|
|
soundOrg hide();
|
|
soundOrg endon( "death" );
|
|
thread delete_on_death( soundOrg );
|
|
|
|
soundOrg.origin = self.origin;
|
|
soundOrg.angles = self.angles;
|
|
soundOrg linkto( self );
|
|
|
|
soundOrg PlayLoopSound( alias );
|
|
|
|
self waittill( "stop sound" + alias );
|
|
soundOrg stoploopsound( alias );
|
|
soundOrg delete();
|
|
}
|
|
|
|
|
|
// spawn C130 at a start node and monitors it
|
|
c130Setup( owner, pathStart, pathGoal )
|
|
{
|
|
forward = vectorToAngles( pathGoal - pathStart );
|
|
c130 = SpawnPlane( owner, "script_model", pathStart, "compass_objpoint_c130_friendly", "compass_objpoint_c130_enemy" );
|
|
c130 SetModel( "vehicle_ac130_low_mp" );
|
|
|
|
if ( !IsDefined( c130 ) )
|
|
return;
|
|
|
|
//chopper playLoopSound( "littlebird_move" );
|
|
c130.owner = owner;
|
|
c130.team = owner.team;
|
|
level.c130 = c130;
|
|
|
|
return c130;
|
|
}
|
|
|
|
// spawn helicopter at a start node and monitors it
|
|
heliSetup( owner, pathStart, pathGoal )
|
|
{
|
|
|
|
forward = vectorToAngles( pathGoal - pathStart );
|
|
|
|
vehicle = "littlebird_mp";
|
|
|
|
// SOTF - Vehicle override so that compass marker always appears as friendly, no matter who the owner is
|
|
if ( IsDefined( level.vehicleOverride ) )
|
|
vehicle = level.vehicleOverride;
|
|
|
|
lb = SpawnHelicopter( owner, pathStart, forward, vehicle, level.littlebird_model );
|
|
|
|
if ( !IsDefined( lb ) )
|
|
return;
|
|
|
|
lb maps\mp\killstreaks\_helicopter::addToLittleBirdList();
|
|
lb thread maps\mp\killstreaks\_helicopter::removeFromLittleBirdListOnDeath();
|
|
|
|
//lb playLoopSound( "littlebird_move" );
|
|
|
|
lb.maxhealth = 500; // this is the health we'll check
|
|
lb.owner = owner;
|
|
lb.team = owner.team;
|
|
lb.isAirdrop = true;
|
|
lb thread watchTimeOut();
|
|
lb thread heli_existence();
|
|
lb thread heliDestroyed();
|
|
lb thread maps\mp\killstreaks\_helicopter::heli_damage_monitor( "airdrop" );
|
|
lb SetMaxPitchRoll( 45, 85 );
|
|
lb Vehicle_SetSpeed( 250, 175 );
|
|
lb.heliType = "airdrop";
|
|
|
|
// hide the wings
|
|
lb HidePart( "tag_wings" );
|
|
|
|
return lb;
|
|
}
|
|
|
|
watchTimeOut()
|
|
{
|
|
level endon( "game_ended" );
|
|
self endon( "leaving" );
|
|
self endon( "helicopter_gone" );
|
|
self endon( "death" );
|
|
|
|
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( 25.0 );
|
|
|
|
self notify( "death" );
|
|
}
|
|
|
|
heli_existence()
|
|
{
|
|
self waittill_any( "crashing", "leaving" );
|
|
|
|
self notify( "helicopter_gone" );
|
|
}
|
|
|
|
heliDestroyed()
|
|
{
|
|
self endon( "leaving" );
|
|
self endon( "helicopter_gone" );
|
|
|
|
self waittill( "death" );
|
|
|
|
if (! IsDefined(self) )
|
|
return;
|
|
|
|
self Vehicle_SetSpeed( 25, 5 );
|
|
self thread lbSpin( RandomIntRange(180, 220) );
|
|
|
|
wait( RandomFloatRange( .5, 1.5 ) );
|
|
|
|
self notify( "drop_crate" );
|
|
|
|
lbExplode();
|
|
}
|
|
|
|
// crash explosion
|
|
lbExplode()
|
|
{
|
|
forward = ( self.origin + ( 0, 0, 1 ) ) - self.origin;
|
|
playfx ( level.chopper_fx["explode"]["death"]["cobra"], self.origin, forward );
|
|
|
|
// play heli explosion sound
|
|
self playSound( "exp_helicopter_fuel" );
|
|
self notify ( "explode" );
|
|
|
|
// decrement the faux vehicle count right before it is deleted this way we know for sure it is gone
|
|
decrementFauxVehicleCount();
|
|
|
|
self delete();
|
|
}
|
|
|
|
|
|
lbSpin( speed )
|
|
{
|
|
self endon( "explode" );
|
|
|
|
// tail explosion that caused the spinning
|
|
playfxontag( level.chopper_fx["explode"]["medium"], self, "tail_rotor_jnt" );
|
|
playfxontag( level.chopper_fx["fire"]["trail"]["medium"], self, "tail_rotor_jnt" );
|
|
|
|
self setyawspeed( speed, speed, speed );
|
|
while ( isdefined( self ) )
|
|
{
|
|
self settargetyaw( self.angles[1]+(speed*0.9) );
|
|
wait ( 1 );
|
|
}
|
|
}
|
|
|
|
/**********************************************************
|
|
* crate trigger functions
|
|
***********************************************************/
|
|
|
|
nukeCaptureThink()
|
|
{
|
|
while ( IsDefined( self ) )
|
|
{
|
|
self waittill ( "trigger", player );
|
|
|
|
if ( !player isOnGround() )
|
|
continue;
|
|
|
|
if ( !useHoldThink( player ) )
|
|
continue;
|
|
|
|
self notify ( "captured", player );
|
|
}
|
|
}
|
|
|
|
crateOtherCaptureThink( useText )
|
|
{
|
|
self endon( "restarting_physics" );
|
|
|
|
while ( IsDefined( self ) )
|
|
{
|
|
self waittill ( "trigger", player );
|
|
|
|
if ( IsDefined( self.owner ) && player == self.owner )
|
|
continue;
|
|
|
|
if ( !self validateOpenConditions( player ) )
|
|
continue;
|
|
|
|
if ( IsDefined( level.overrideCrateUseTime ) )
|
|
useTime = level.overrideCrateUseTime;
|
|
else
|
|
useTime = undefined;
|
|
|
|
player.isCapturingCrate = true;
|
|
useEnt = self createUseEnt();
|
|
result = useEnt useHoldThink( player, useTime, useText );
|
|
|
|
if ( IsDefined( useEnt ) )
|
|
useEnt delete();
|
|
|
|
if ( !IsDefined( player ) )
|
|
return;
|
|
|
|
if ( !result )
|
|
{
|
|
player.isCapturingCrate = false;
|
|
continue;
|
|
}
|
|
|
|
player.isCapturingCrate = false;
|
|
self notify ( "captured", player );
|
|
}
|
|
}
|
|
|
|
crateOwnerCaptureThink( useText )
|
|
{
|
|
self endon( "restarting_physics" );
|
|
|
|
while ( IsDefined( self ) )
|
|
{
|
|
self waittill ( "trigger", player );
|
|
|
|
if ( IsDefined( self.owner ) && player != self.owner )
|
|
continue;
|
|
|
|
if ( !self validateOpenConditions( player ) )
|
|
continue;
|
|
|
|
player.isCapturingCrate = true;
|
|
if ( !useHoldThink( player, CONST_CRATE_OWNER_USE_TIME, useText ) )
|
|
{
|
|
player.isCapturingCrate = false;
|
|
continue;
|
|
}
|
|
|
|
player.isCapturingCrate = false;
|
|
self notify ( "captured", player );
|
|
}
|
|
}
|
|
|
|
crateAllCaptureThink( useText )
|
|
{
|
|
// self == crate
|
|
self endon( "restarting_physics" );
|
|
|
|
// This should be used in the case you want the crate to act as a neutral object,
|
|
// where everyone can access it with the same use time
|
|
self.crateUseEnts = [];
|
|
|
|
while ( IsDefined( self ) )
|
|
{
|
|
self waittill ( "trigger", player );
|
|
|
|
if ( !self validateOpenConditions( player ) )
|
|
continue;
|
|
|
|
if ( IsDefined( level.overrideCrateUseTime ) )
|
|
useTime = level.overrideCrateUseTime;
|
|
else
|
|
useTime = undefined;
|
|
|
|
self childthread crateAllUseLogic( player, useTime, useText );
|
|
}
|
|
}
|
|
|
|
crateAllUseLogic( player, useTime, useText )
|
|
{
|
|
player.isCapturingCrate = true;
|
|
|
|
AssertEx( !IsDefined( self.crateUseEnts[ player.name ] ), "Crate already has useEnt for " + player.name );
|
|
|
|
// Store the useEnts per crate, so we can check who is still using it later
|
|
self.crateUseEnts[ player.name ] = self createUseEnt();
|
|
|
|
// Store to remove the ent later
|
|
useEntToRemove = self.crateUseEnts[ player.name ];
|
|
|
|
// Wait until the player finishes using the crate
|
|
result = self.crateUseEnts[ player.name ] useHoldThink( player, useTime, useText, self );
|
|
|
|
// No longer using the crate? Delete the ent
|
|
if ( IsDefined( self.crateUseEnts ) && IsDefined( useEntToRemove ) )
|
|
{
|
|
self.crateUseEnts = array_remove_keep_index( self.crateUseEnts, useEntToRemove );
|
|
useEntToRemove delete();
|
|
}
|
|
|
|
if ( !IsDefined( player ) )
|
|
return;
|
|
|
|
player.isCapturingCrate = false;
|
|
|
|
if ( result )
|
|
self notify ( "captured", player );
|
|
}
|
|
|
|
updateCrateUseState()
|
|
{
|
|
// self == crate
|
|
self.inUse = false;
|
|
|
|
// Check each existing useEnt linked to the crate, and see if they are in use
|
|
foreach ( useEnt in self.crateUseEnts )
|
|
{
|
|
if ( useEnt.inUse )
|
|
{
|
|
self.inUse = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
validateOpenConditions( opener )
|
|
{
|
|
//if ( !opener isOnGround() )
|
|
//return false;
|
|
|
|
// don't let a juggernaut pick up a juggernaut crate
|
|
if ( ( self.crateType == "airdrop_juggernaut_recon" || self.crateType == "airdrop_juggernaut" || self.crateType == "airdrop_juggernaut_maniac" ) && opener isJuggernaut() )
|
|
return false;
|
|
|
|
//dont allow opening if the player is on a heli sniper
|
|
if ( isDefined( opener.OnHeliSniper ) && opener.OnHeliSniper )
|
|
return false;
|
|
|
|
// don't let them open crates while using killstreaks, except being juggernaut
|
|
currWeapon = opener GetCurrentWeapon();
|
|
if( isKillstreakWeapon( currWeapon ) && !isJuggernautWeapon( currWeapon ) )
|
|
return false;
|
|
|
|
if( IsDefined( opener.changingWeapon ) && isKillstreakWeapon( opener.changingWeapon ) && !IsSubStr( opener.changingWeapon, "jugg_mp" ) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
killstreakCrateThink( dropType )
|
|
{
|
|
self endon( "restarting_physics" );
|
|
self endon ( "death" );
|
|
|
|
if ( IsDefined( game["strings"][self.crateType + "_hint"] ) )
|
|
crateHint = game["strings"][self.crateType + "_hint"];
|
|
else
|
|
crateHint = &"PLATFORM_GET_KILLSTREAK";
|
|
|
|
crateSetupForUse( crateHint, getKillstreakOverheadIcon( self.crateType ) );
|
|
|
|
self thread crateOtherCaptureThink();
|
|
self thread crateOwnerCaptureThink();
|
|
|
|
for ( ;; )
|
|
{
|
|
self waittill ( "captured", player );
|
|
|
|
if( IsPlayer( player ) )
|
|
{
|
|
player SetClientOmnvar( "ui_securing", 0 );
|
|
player.ui_securing = undefined;
|
|
}
|
|
|
|
if ( IsDefined( self.owner ) && player != self.owner )
|
|
{
|
|
if ( !level.teamBased || player.team != self.team )
|
|
{
|
|
switch( dropType )
|
|
{
|
|
case "airdrop_assault":
|
|
case "airdrop_support":
|
|
case "airdrop_escort":
|
|
case "airdrop_osprey_gunner":
|
|
player thread maps\mp\gametypes\_missions::genericChallenge( "hijacker_airdrop" );
|
|
player thread hijackNotify( self, "airdrop" );
|
|
break;
|
|
case "airdrop_sentry_minigun":
|
|
player thread maps\mp\gametypes\_missions::genericChallenge( "hijacker_airdrop" );
|
|
player thread hijackNotify( self, "sentry" );
|
|
break;
|
|
case "airdrop_remote_tank":
|
|
player thread maps\mp\gametypes\_missions::genericChallenge( "hijacker_airdrop" );
|
|
player thread hijackNotify( self, "remote_tank" );
|
|
break;
|
|
case "airdrop_mega":
|
|
player thread maps\mp\gametypes\_missions::genericChallenge( "hijacker_airdrop_mega" );
|
|
player thread hijackNotify( self, "emergency_airdrop" );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self.owner thread maps\mp\gametypes\_rank::giveRankXP( "killstreak_giveaway", Int(( maps\mp\killstreaks\_killstreaks::getStreakCost( self.crateType ) / 10 ) * 50) );
|
|
//self.owner maps\mp\gametypes\_hud_message::playerCardSplashNotify( "giveaway_airdrop", player );
|
|
self.owner thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "sharepackage", Int(( maps\mp\killstreaks\_killstreaks::getStreakCost( self.crateType ) / 10 ) * 50) );
|
|
}
|
|
}
|
|
|
|
player playLocalSound( "ammo_crate_use" );
|
|
player thread maps\mp\killstreaks\_killstreaks::giveKillstreak( self.crateType, false, false, self.owner );
|
|
|
|
player maps\mp\gametypes\_hud_message::killstreakSplashNotify( self.crateType, undefined );
|
|
|
|
self deleteCrate();
|
|
}
|
|
}
|
|
|
|
//NOT USED
|
|
lasedStrikeCrateThink( dropType )
|
|
{
|
|
self endon( "restarting_physics" );
|
|
self endon ( "death" );
|
|
|
|
crateSetupForUse( game["strings"]["marker_hint"], getKillstreakOverheadIcon( self.crateType ) );
|
|
|
|
level.lasedStrikeCrateActive = true;
|
|
self thread crateOwnerCaptureThink();
|
|
self thread crateOtherCaptureThink();
|
|
|
|
numCount = 0;
|
|
|
|
remote = self thread maps\mp\killstreaks\_lasedStrike::spawnRemote( self.owner );
|
|
level.lasedStrikeDrone = remote;
|
|
level.lasedStrikeActive = true;
|
|
|
|
level.soflamCrate = self;
|
|
|
|
for ( ;; )
|
|
{
|
|
self waittill ( "captured", player );
|
|
|
|
if ( IsDefined( self.owner ) && player != self.owner )
|
|
{
|
|
if ( !level.teamBased || player.team != self.team )
|
|
{
|
|
self deleteCrate();
|
|
}
|
|
}
|
|
|
|
//self DisablePlayerUse( player );
|
|
self maps\mp\killstreaks\_airdrop::setUsableByTeam( self.team );
|
|
|
|
player thread maps\mp\killstreaks\_lasedStrike::giveMarker();
|
|
|
|
numCount++;
|
|
|
|
if ( numCount >= 5 )
|
|
self deleteCrate();
|
|
}
|
|
}
|
|
|
|
|
|
nukeCrateThink( dropType )
|
|
{
|
|
self endon( "restarting_physics" );
|
|
self endon ( "death" );
|
|
|
|
crateSetupForUse( &"PLATFORM_CALL_NUKE", getKillstreakOverheadIcon( self.crateType ) );
|
|
|
|
self thread nukeCaptureThink();
|
|
|
|
for ( ;; )
|
|
{
|
|
self waittill ( "captured", player );
|
|
|
|
player thread [[ level.killstreakFuncs[ self.crateType ] ]]( level.gtnw );
|
|
level notify( "nukeCaptured", player );
|
|
|
|
if ( IsDefined( level.gtnw ) && level.gtnw )
|
|
player.capturedNuke = 1;
|
|
|
|
player playLocalSound( "ammo_crate_use" );
|
|
self deleteCrate();
|
|
}
|
|
}
|
|
|
|
|
|
juggernautCrateThink( dropType )
|
|
{
|
|
self endon( "restarting_physics" );
|
|
self endon ( "death" );
|
|
|
|
crateSetupForUse( game["strings"][self.crateType + "_hint"], getKillstreakOverheadIcon( self.crateType ) );
|
|
|
|
self thread crateOtherCaptureThink();
|
|
self thread crateOwnerCaptureThink();
|
|
|
|
for ( ;; )
|
|
{
|
|
self waittill ( "captured", player );
|
|
|
|
if ( IsDefined( self.owner ) && player != self.owner )
|
|
{
|
|
if ( !level.teamBased || player.team != self.team )
|
|
{
|
|
if ( self.crateType == "airdrop_juggernaut_maniac" )
|
|
{
|
|
player thread hijackNotify( self, "maniac" );
|
|
}
|
|
else if ( isStrStart( self.crateType, "juggernaut_" ) )
|
|
{
|
|
player thread hijackNotify( self, self.crateType );
|
|
}
|
|
else
|
|
{
|
|
player thread hijackNotify( self, "juggernaut" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self.owner thread maps\mp\gametypes\_rank::giveRankXP( "killstreak_giveaway", Int( maps\mp\killstreaks\_killstreaks::getStreakCost( self.crateType ) / 10 ) * 50 );
|
|
|
|
if ( self.crateType == "airdrop_juggernaut_maniac" )
|
|
{
|
|
self.owner maps\mp\gametypes\_hud_message::playerCardSplashNotify( "giveaway_juggernaut_maniac", player );
|
|
}
|
|
else if ( isStrStart( self.crateType, "juggernaut_" ) )
|
|
{
|
|
self.owner maps\mp\gametypes\_hud_message::playerCardSplashNotify( "giveaway_" + self.crateType, player );
|
|
}
|
|
else
|
|
{
|
|
self.owner maps\mp\gametypes\_hud_message::playerCardSplashNotify( "giveaway_juggernaut", player );
|
|
}
|
|
}
|
|
}
|
|
|
|
player playLocalSound( "ammo_crate_use" );
|
|
|
|
juggType = "juggernaut";
|
|
switch( self.crateType )
|
|
{
|
|
case "airdrop_juggernaut":
|
|
juggType = "juggernaut";
|
|
break;
|
|
case "airdrop_juggernaut_recon":
|
|
juggType = "juggernaut_recon";
|
|
break;
|
|
case "airdrop_juggernaut_maniac":
|
|
juggType = "juggernaut_maniac";
|
|
break;
|
|
default:
|
|
if ( isStrStart( self.crateType, "juggernaut_" ) )
|
|
{
|
|
juggType = self.crateType;
|
|
}
|
|
break;
|
|
}
|
|
|
|
player thread maps\mp\killstreaks\_juggernaut::giveJuggernaut( juggType );
|
|
|
|
self deleteCrate();
|
|
}
|
|
}
|
|
|
|
|
|
sentryCrateThink( dropType )
|
|
{
|
|
self endon ( "death" );
|
|
|
|
crateSetupForUse( game["strings"]["sentry_hint"], getKillstreakOverheadIcon( self.crateType ) );
|
|
|
|
self thread crateOtherCaptureThink();
|
|
self thread crateOwnerCaptureThink();
|
|
|
|
for ( ;; )
|
|
{
|
|
self waittill ( "captured", player );
|
|
|
|
if ( IsDefined( self.owner ) && player != self.owner )
|
|
{
|
|
if ( !level.teamBased || player.team != self.team )
|
|
{
|
|
if ( isSubStr(dropType, "airdrop_sentry" ) )
|
|
player thread hijackNotify( self, "sentry" );
|
|
else
|
|
player thread hijackNotify( self, "emergency_airdrop" );
|
|
}
|
|
else
|
|
{
|
|
self.owner thread maps\mp\gametypes\_rank::giveRankXP( "killstreak_giveaway", Int( maps\mp\killstreaks\_killstreaks::getStreakCost( "sentry" ) / 10 ) * 50 );
|
|
self.owner maps\mp\gametypes\_hud_message::playerCardSplashNotify( "giveaway_sentry", player );
|
|
}
|
|
}
|
|
|
|
player playLocalSound( "ammo_crate_use" );
|
|
player thread sentryUseTracker();
|
|
|
|
self deleteCrate();
|
|
}
|
|
}
|
|
|
|
|
|
deleteCrate()
|
|
{
|
|
self notify( "crate_deleting" );
|
|
|
|
if ( IsDefined( self.usedBy ) )
|
|
{
|
|
// Loop through all of the players still using this object, and make sure their omnvars are being reset properly
|
|
foreach ( player in self.usedBy )
|
|
{
|
|
player SetClientOmnvar( "ui_securing", 0 );
|
|
player.ui_securing = undefined;
|
|
}
|
|
}
|
|
|
|
if ( IsDefined( self.objIdFriendly ) )
|
|
_objective_delete( self.objIdFriendly );
|
|
|
|
if ( IsDefined( self.objIdEnemy ) )
|
|
{
|
|
if( level.multiTeamBased )
|
|
{
|
|
foreach( obj in self.objIdEnemy )
|
|
{
|
|
_objective_delete( obj );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_objective_delete( self.objIdEnemy );
|
|
}
|
|
}
|
|
|
|
if ( IsDefined( self.bomb ) && IsDefined( self.bomb.killcamEnt ) )
|
|
self.bomb.killcamEnt delete();
|
|
|
|
if ( IsDefined( self.bomb ) )
|
|
self.bomb delete();
|
|
|
|
if ( IsDefined( self.killCamEnt ) )
|
|
self.killCamEnt delete();
|
|
|
|
if ( IsDefined( self.dropType ) )
|
|
PlayFX( getfx( "airdrop_crate_destroy" ), self.origin );
|
|
|
|
|
|
self delete();
|
|
}
|
|
|
|
sentryUseTracker()
|
|
{
|
|
if ( !self maps\mp\killstreaks\_autosentry::giveSentry( "sentry_minigun" ) )
|
|
self maps\mp\killstreaks\_killstreaks::giveKillstreak( "sentry" );
|
|
}
|
|
|
|
|
|
hijackNotify( crate, crateType )
|
|
{
|
|
self notify( "hijacker", crateType, crate.owner );
|
|
}
|
|
|
|
|
|
refillAmmo( refillEquipment )
|
|
{
|
|
weaponList = self GetWeaponsListAll();
|
|
|
|
if ( refillEquipment )
|
|
{
|
|
if ( self _hasPerk( "specialty_tacticalinsertion" ) && self getAmmoCount( "flare_mp" ) < 1 )
|
|
self givePerkOffhand( "specialty_tacticalinsertion", false );
|
|
}
|
|
|
|
foreach ( weaponName in weaponList )
|
|
{
|
|
if ( isSubStr( weaponName, "grenade" ) || ( GetSubStr( weaponName, 0, 2 ) == "gl" ) )
|
|
{
|
|
if ( !refillEquipment || self getAmmoCount( weaponName ) >= 1 )
|
|
continue;
|
|
}
|
|
|
|
self giveMaxAmmo( weaponName );
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************
|
|
* Capture crate functions
|
|
***********************************************************/
|
|
useHoldThink( player, useTime, useText, crate )
|
|
{
|
|
self maps\mp\_movers::script_mover_link_to_use_object( player );
|
|
|
|
player _disableWeapon();
|
|
|
|
self.curProgress = 0;
|
|
self.inUse = true;
|
|
self.useRate = 0;
|
|
|
|
if( IsDefined( crate ) )
|
|
crate updateCrateUseState();
|
|
|
|
if ( IsDefined( useTime ) )
|
|
self.useTime = useTime;
|
|
else
|
|
self.useTime = CONST_CRATE_OTHER_USE_TIME;
|
|
|
|
result = useHoldThinkLoop( player );
|
|
assert ( IsDefined( result ) );
|
|
|
|
if ( isAlive( player ) )
|
|
player _enableWeapon();
|
|
|
|
// Took this out of the above check, otherwise the player will not get unlinked from the crate they are using
|
|
// This would cause an issue where the player's camera might rotate 90 degrees during their death animation, since they are still linked
|
|
if ( IsDefined( player ) )
|
|
{
|
|
maps\mp\_movers::script_mover_unlink_from_use_object( player );
|
|
}
|
|
|
|
if ( !IsDefined( self ) )
|
|
return false;
|
|
|
|
self.inUse = false;
|
|
self.curProgress = 0;
|
|
|
|
if( IsDefined( crate ) )
|
|
crate updateCrateUseState();
|
|
|
|
return ( result );
|
|
}
|
|
|
|
useHoldThinkLoop( player )
|
|
{
|
|
while( player maps\mp\killstreaks\_deployablebox::isPlayerUsingBox( self ) )
|
|
{
|
|
if ( !player maps\mp\_movers::script_mover_use_can_link( self ) )
|
|
{
|
|
player maps\mp\gametypes\_gameobjects::updateUIProgress( self, false );
|
|
return false;
|
|
}
|
|
|
|
self.curProgress += (50 * self.useRate);
|
|
|
|
if ( IsDefined(self.objectiveScaler) )
|
|
self.useRate = 1 * self.objectiveScaler;
|
|
else
|
|
self.useRate = 1;
|
|
|
|
player maps\mp\gametypes\_gameobjects::updateUIProgress( self, true );
|
|
|
|
if ( self.curProgress >= self.useTime )
|
|
{
|
|
player maps\mp\gametypes\_gameobjects::updateUIProgress( self, false );
|
|
return ( isReallyAlive( player ) );
|
|
}
|
|
|
|
wait 0.05;
|
|
}
|
|
|
|
if ( isDefined(self) )
|
|
player maps\mp\gametypes\_gameobjects::updateUIProgress( self, false );
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
createUseEnt()
|
|
{
|
|
useEnt = Spawn( "script_origin", self.origin );
|
|
useEnt.curProgress = 0;
|
|
useEnt.useTime = 0;
|
|
useEnt.useRate = 3000;
|
|
useEnt.inUse = false;
|
|
useEnt.id = self.id;
|
|
useEnt linkto( self );
|
|
|
|
useEnt thread deleteUseEnt( self );
|
|
|
|
return ( useEnt );
|
|
}
|
|
|
|
|
|
deleteUseEnt( owner )
|
|
{
|
|
self endon ( "death" );
|
|
|
|
owner waittill ( "death" );
|
|
|
|
if ( IsDefined( self.usedBy ) )
|
|
{
|
|
// Loop through all of the players still using this object, and make sure their omnvars are being reset properly
|
|
foreach ( player in self.usedBy )
|
|
{
|
|
player SetClientOmnvar( "ui_securing", 0 );
|
|
player.ui_securing = undefined;
|
|
}
|
|
}
|
|
|
|
self delete();
|
|
}
|
|
|
|
|
|
airdropDetonateOnStuck()
|
|
{
|
|
self endon ( "death" );
|
|
|
|
self waittill( "missile_stuck" );
|
|
|
|
self detonate();
|
|
}
|
|
|
|
throw_linked_care_packages( animating_model, offset, throw_vec, delete_volume )
|
|
{
|
|
if( IsDefined( level.carePackages ) )
|
|
{
|
|
foreach( carePackage in level.carePackages )
|
|
{
|
|
if( IsDefined(carePackage.inUse) && carePackage.inUse )
|
|
continue;
|
|
|
|
parent = carePackage GetLinkedParent();
|
|
if( isdefined( parent ) && ( parent == animating_model ) )
|
|
{
|
|
thread spawn_new_care_package( carePackage, offset, throw_vec );
|
|
if( IsDefined( delete_volume ) )
|
|
{
|
|
delayThread( 1.0, ::remove_care_packages_in_volume, delete_volume );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
spawn_new_care_package( package, offset, throw_vec )
|
|
{
|
|
owner = package.owner;
|
|
dropType = package.dropType;
|
|
crateType = package.crateType;
|
|
origin = package.origin;
|
|
|
|
package maps\mp\killstreaks\_airdrop::deleteCrate();
|
|
|
|
newCrate = owner maps\mp\killstreaks\_airdrop::createAirDropCrate( owner, dropType, crateType, origin + offset , origin + offset );
|
|
newCrate.droppingtoground = true;
|
|
|
|
newCrate thread [[ level.crateTypes[ newCrate.dropType ][ newCrate.crateType ].func ]]( newCrate.dropType );
|
|
|
|
waitframe();
|
|
|
|
newCrate CloneBrushmodelToScriptmodel( level.airDropCrateCollision );
|
|
newCrate thread entity_path_disconnect_thread( 1.0 );
|
|
newCrate PhysicsLaunchServer( newCrate.origin, throw_vec );
|
|
|
|
if ( IsBot( newCrate.owner ) )
|
|
{
|
|
wait( 0.1 );
|
|
newCrate.owner notify( "new_crate_to_take" );
|
|
}
|
|
}
|
|
|
|
remove_care_packages_in_volume( volume )
|
|
{
|
|
if( IsDefined( level.carePackages ) )
|
|
{
|
|
foreach( carePackage in level.carePackages )
|
|
{
|
|
if( IsDefined( carePackage ) && IsDefined( carePackage.friendlyModel ) && ( carePackage.friendlyModel IsTouching( volume ) ) )
|
|
{
|
|
carePackage maps\mp\killstreaks\_airdrop::deleteCrate();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
get_dummy_crate_model()
|
|
{
|
|
return DUMMY_CRATE_MODEL;
|
|
}
|
|
|
|
get_enemy_crate_model()
|
|
{
|
|
return ENEMY_CRATE_MODEL;
|
|
}
|
|
|
|
get_friendly_crate_model()
|
|
{
|
|
return FRIENDLY_CRATE_MODEL;
|
|
}
|
|
|
|
get_dummy_juggernaut_crate_model()
|
|
{
|
|
return DUMMY_JUGGERNAUT_CRATE_MODEL;
|
|
}
|
|
|
|
get_enemy_juggernaut_crate_model()
|
|
{
|
|
return ENEMY_JUGGERNAUT_CRATE_MODEL;
|
|
}
|
|
|
|
get_friendly_juggernaut_crate_model()
|
|
{
|
|
return FRIENDLY_JUGGERNAUT_CRATE_MODEL;
|
|
}
|