252 lines
6.7 KiB
Plaintext
252 lines
6.7 KiB
Plaintext
#include maps\mp\_utility;
|
|
#include common_scripts\utility;
|
|
#include maps\mp\gametypes\_hud_util;
|
|
|
|
BOX_TYPE = "deployable_ammo";
|
|
|
|
// we depend on deployablebox being init'd first
|
|
init ()
|
|
{
|
|
boxConfig = SpawnStruct();
|
|
boxConfig.id = "deployable_weapon_crate";
|
|
boxConfig.weaponInfo = "deployable_weapon_crate_marker_mp";
|
|
boxConfig.modelBase = "mp_weapon_crate";
|
|
boxConfig.modelBombSquad = "mp_weapon_crate_bombsquad";
|
|
boxConfig.hintString = &"KILLSTREAKS_HINTS_DEPLOYABLE_AMMO_USE"; //
|
|
boxConfig.capturingString = &"KILLSTREAKS_DEPLOYABLE_AMMO_TAKING"; //
|
|
boxConfig.event = "deployable_ammo_taken"; //
|
|
boxConfig.streakName = BOX_TYPE; //
|
|
boxConfig.splashName = "used_deployable_ammo"; //
|
|
boxConfig.shaderName = "compass_objpoint_deploy_ammo_friendly";
|
|
boxConfig.headIconOffset = 20;
|
|
boxConfig.lifeSpan = 90.0;
|
|
boxConfig.voGone = "ammocrate_gone";
|
|
boxConfig.useXP = 50;
|
|
boxConfig.xpPopup = "destroyed_ammo";
|
|
boxConfig.voDestroyed = "ammocrate_destroyed";
|
|
boxConfig.deployedSfx = "mp_vest_deployed_ui";
|
|
boxConfig.onUseSfx = "ammo_crate_use";
|
|
boxConfig.onUseCallback = ::onUseDeployable;
|
|
boxConfig.canUseCallback = ::canUseDeployable;
|
|
boxConfig.noUseKillstreak = true;
|
|
boxConfig.useTime = 1000;
|
|
boxConfig.maxHealth = 150;
|
|
boxConfig.damageFeedback = "deployable_bag";
|
|
boxConfig.deathVfx = loadfx( "vfx/gameplay/mp/killstreaks/vfx_ballistic_vest_death" );
|
|
boxConfig.allowMeleeDamage = true;
|
|
boxConfig.allowGrenadeDamage = false; // this doesn't seem dependable, like with c-4. Why isn't this in an object description?
|
|
boxConfig.maxUses = 4;
|
|
|
|
boxConfig.minigunChance = 20; // 1 in minigunChance
|
|
// artificially increase the odds for development
|
|
/#
|
|
boxConfig.miniGunChance = 10;
|
|
#/
|
|
|
|
boxConfig.minigunWeapon = "iw6_minigun_mp";
|
|
boxConfig.ammoRestockCheckFreq = 0.5; // how often we check for new players
|
|
boxConfig.ammoRestockTime = 10.0; // how often players can get restocked
|
|
boxConfig.triggerRadius = 200;
|
|
boxConfig.triggerHeight = 64;
|
|
boxConfig.onDeployCallback = ::onBoxDeployed;
|
|
boxConfig.canUseOtherBoxes = false;
|
|
|
|
level.boxSettings[ BOX_TYPE ] = boxConfig;
|
|
|
|
level.killStreakFuncs[ BOX_TYPE ] = ::tryUseDeployable;
|
|
|
|
level.deployableGunBox_BonusInXUses = RandomIntRange(1, boxConfig.minigunChance + 1);
|
|
|
|
level.deployable_box[ BOX_TYPE ] = []; // storing each created box in their own array
|
|
|
|
maps\mp\gametypes\sotf::defineChestWeapons();
|
|
}
|
|
|
|
tryUseDeployable( lifeId, streakName ) // self == player
|
|
{
|
|
result = self maps\mp\killstreaks\_deployablebox::beginDeployableViaMarker( lifeId, BOX_TYPE );
|
|
|
|
if( ( !IsDefined( result ) || !result ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( !is_aliens() )
|
|
{
|
|
self maps\mp\_matchdata::logKillstreakEvent( BOX_TYPE, self.origin );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
onUseDeployable( boxEnt ) // self == player
|
|
{
|
|
level.deployableGunBox_BonusInXUses--;
|
|
|
|
if ( level.deployableGunBox_BonusInXUses == 0 )
|
|
{
|
|
boxConfig = level.boxSettings[ boxEnt.boxType ];
|
|
|
|
// For when we want to replace the minigun with something else for a specific level (e.g. Venom-X in dome_ns )
|
|
if ( IsDefined( level.deployableBoxGiveWeaponFunc ) )
|
|
[[ level.deployableBoxGiveWeaponFunc ]]( true );
|
|
else
|
|
giveGun( self, boxConfig.minigunWeapon );
|
|
|
|
self maps\mp\gametypes\_missions::processChallenge( "ch_guninabox" );
|
|
|
|
// reset gun chance, but make it very unlikely to get a second one
|
|
level.deployableGunBox_BonusInXUses = RandomIntRange(boxConfig.minigunChance, boxConfig.minigunChance + 1);
|
|
}
|
|
else
|
|
{
|
|
giveRandomGun( self );
|
|
}
|
|
}
|
|
|
|
onBoxDeployed( config ) // self == box
|
|
{
|
|
self thread restockAmmoAura( config );
|
|
}
|
|
|
|
giveRandomGun( player )
|
|
{
|
|
// this is adapted from SOTF / Hunted
|
|
|
|
// give the player a new gun, but make sure he's not carrying a variant of it in either slot
|
|
baseWeapons = [];
|
|
foreach ( gun in player GetWeaponsListPrimaries() )
|
|
{
|
|
baseWeapons[ baseWeapons.size ] = GetWeaponBaseName( gun );
|
|
}
|
|
|
|
newWeapon = undefined;
|
|
while ( true )
|
|
{
|
|
// getRandomWeapon returns an array
|
|
newWeapon = maps\mp\gametypes\sotf::getRandomWeapon( level.weaponArray );
|
|
newBaseWeapon = newWeapon["name"];
|
|
|
|
// make sure he's not carrying this weapon already
|
|
if ( !array_contains( baseWeapons, newBaseWeapon ) )
|
|
break;
|
|
}
|
|
|
|
// get randomAttachments returns a full weapon string
|
|
newWeapon = maps\mp\gametypes\sotf::getRandomAttachments( newWeapon );
|
|
|
|
giveGun( player, newWeapon );
|
|
|
|
}
|
|
|
|
giveGun( player, newWeapon )
|
|
{
|
|
weaponList = player GetWeaponsListPrimaries();
|
|
|
|
primaryCount = 0;
|
|
foreach ( weap in weaponList )
|
|
{
|
|
if ( !maps\mp\gametypes\_weapons::isAltModeWeapon( weap ) )
|
|
{
|
|
primaryCount++;
|
|
}
|
|
}
|
|
|
|
if ( primaryCount > 1 )
|
|
{
|
|
playerPrimary = player.lastDroppableWeapon;
|
|
if ( IsDefined( playerPrimary ) && playerPrimary != "none" )
|
|
{
|
|
player DropItem( playerPrimary );
|
|
}
|
|
}
|
|
|
|
player _giveWeapon( newWeapon );
|
|
player SwitchToWeapon( newWeapon );
|
|
player GiveStartAmmo( newWeapon );
|
|
}
|
|
|
|
restockAmmoAura( config ) // self == box
|
|
{
|
|
self endon( "death" );
|
|
level endon( "game_eneded" );
|
|
|
|
trigger = Spawn( "trigger_radius", self.origin, 0, config.triggerRadius, config.triggerHeight );
|
|
trigger.owner = self;
|
|
self thread maps\mp\gametypes\_weapons::deleteOnDeath( trigger );
|
|
|
|
if ( IsDefined( self.moving_platform ) )
|
|
{
|
|
trigger EnableLinkTo();
|
|
trigger LinkTo( self.moving_platform );
|
|
}
|
|
|
|
rangeSq = config.triggerRadius * config.triggerRadius;
|
|
player = undefined;
|
|
while ( true )
|
|
{
|
|
// trigger waittill( "trigger", player );
|
|
touchingPlayers = trigger GetIsTouchingEntities( level.players );
|
|
|
|
|
|
foreach ( player in touchingPlayers )
|
|
{
|
|
if ( IsDefined( player )
|
|
&& !(self.owner IsEnemy( player ))
|
|
&& self shouldAddAmmo( player ) )
|
|
{
|
|
// self thread addAmmoOverTime( player, rangeSq, config.ammoRestockTime );
|
|
self addAmmo( player, config.ammoRestockTime );
|
|
}
|
|
}
|
|
|
|
wait ( config.ammoRestockCheckFreq );
|
|
}
|
|
}
|
|
|
|
shouldAddAmmo( player ) // self == box
|
|
{
|
|
return ( !IsDefined( player.deployableGunNextAmmoTime )
|
|
|| GetTime() >= player.deployableGunNextAmmoTime );
|
|
}
|
|
|
|
addAmmo( player, freq ) // self == box
|
|
{
|
|
player.deployableGunNextAmmoTime = GetTime() + (freq * 1000);
|
|
maps\mp\gametypes\_weapons::scavengerGiveAmmo( player );
|
|
|
|
player maps\mp\gametypes\_damagefeedback::hudIconType( "boxofguns" );
|
|
}
|
|
|
|
addAmmoOverTime( player, rangeSq, freq ) // self == box
|
|
{
|
|
self endon( "death" );
|
|
player endon( "death" );
|
|
player endon( "disconnect" );
|
|
level endon( "game_ended" );
|
|
|
|
while ( true )
|
|
{
|
|
self addAmmo( player );
|
|
|
|
wait ( freq );
|
|
|
|
if ( DistanceSquared( player.origin, self.origin ) > rangeSq )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
canUseDeployable(boxEnt) // self == player
|
|
{
|
|
if( is_aliens() && isDefined( boxEnt ) && boxEnt.owner == self && !isdefined( boxEnt.air_dropped ) )
|
|
{
|
|
return false;
|
|
}
|
|
if( !is_aliens() )
|
|
return ( !self isJuggernaut() );
|
|
else
|
|
return true;
|
|
} |