iw6-scripts-dev/maps/mp/killstreaks/_deployablebox_gun.gsc
2024-12-11 11:28:08 +01:00

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;
}