boiii-scripts/shared/weapons/_trophy_system.gsc
2023-04-13 17:30:38 +02:00

498 lines
21 KiB
Plaintext

#using scripts\codescripts\struct;
#using scripts\shared\callbacks_shared;
#using scripts\shared\challenges_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\damagefeedback_shared;
#using scripts\shared\scoreevents_shared;
#using scripts\shared\system_shared;
#using scripts\shared\util_shared;
#using scripts\shared\weapons\_tacticalinsertion;
#using scripts\shared\weapons\_weaponobjects;
#using_animtree ( "mp_trophy_system" );
#precache( "fx", "weapon/fx_trophy_flash" );
#precache( "fx", "weapon/fx_trophy_detonation" );
#precache( "fx", "weapon/fx_trophy_radius_indicator" );
#precache( "triggerstring", "MP_TROPHY_SYSTEM_PICKUP" );
#precache( "triggerstring", "MP_TROPHY_SYSTEM_DESTROY" );
#precache( "triggerstring", "MP_TROPHY_SYSTEM_HACKING" );
#namespace trophy_system;
function init_shared()
{
level.trophyLongFlashFX = "weapon/fx_trophy_flash";
level.trophyDetonationFX = "weapon/fx_trophy_detonation";
level.fx_trophy_radius_indicator = "weapon/fx_trophy_radius_indicator";
trophyDeployAnim = %o_trophy_deploy;
trophySpinAnim = %o_trophy_spin;
level thread register();
callback::on_spawned( &createTrophySystemWatcher );
}
//******************************************************************
// *
// *
//******************************************************************
function register()
{
clientfield::register( "missile", "trophy_system_state", 1, 2, "int" );
clientfield::register( "scriptmover", "trophy_system_state", 1, 2, "int" );
}
//******************************************************************
// *
// *
//******************************************************************
function createTrophySystemWatcher() // self == player
{
if( level.gametype == "infect" && self.team == game["attackers"] )
{
return;
}
watcher = self weaponobjects::createUseWeaponObjectWatcher( "trophy_system", self.team );
watcher.onDetonateCallback =&trophySystemDetonate;
watcher.activateSound = "wpn_claymore_alert";
watcher.hackable = true;
watcher.hackerToolRadius = level.equipmentHackerToolRadius;
watcher.hackerToolTimeMs = level.equipmentHackerToolTimeMs;
watcher.ownerGetsAssist = true;
watcher.ignoreDirection = true;
watcher.activationDelay = 0.1;
watcher.headIcon = false;
watcher.enemyDestroy = true;
watcher.onSpawn =&onTrophySystemSpawn;
watcher.onDamage =&watchTrophySystemDamage;
watcher.onDestroyed =&onTrophySystemSmashed;
watcher.onStun =&weaponobjects::weaponStun;
watcher.stunTime = 1;
}
//******************************************************************
// *
// *
//******************************************************************
function onTrophySystemSpawn( watcher, player ) // self == trophy system
{
player endon( "death" );
player endon( "disconnect" );
level endon( "game_ended" );
self endon( "death" );
self UseAnimTree( #animtree );
self weaponobjects::onSpawnUseWeaponObject( watcher, player );
self.trophySystemStationary = false;
moveState = self util::waitTillRollingOrNotMoving();
if ( moveState == "rolling" )
{
self SetAnim( %o_trophy_deploy, 1.0 );
self clientfield::set( "trophy_system_state", 1 );
self util::waitTillNotMoving();
}
self.trophySystemStationary = true;
player AddWeaponStat( self.weapon, "used", 1 );
self.ammo = player ammo_get( self.weapon );
self thread trophyActive( player );
self thread trophyWatchHack();
self SetAnim( %o_trophy_deploy, 0.0 );
self SetAnim( %o_trophy_spin, 1.0 );
self clientfield::set( "trophy_system_state", 2 );
self playsound("wpn_trophy_deploy_start");
self PlayLoopSound( "wpn_trophy_spin", 0.25 );
self setReconModelDeployed();
}
function setReconModelDeployed() // self == trophy system
{
if ( isdefined( self.reconModelEntity ) )
{
self.reconModelEntity clientfield::set( "trophy_system_state", 2 );
}
}
//******************************************************************
// *
// *
//******************************************************************
function trophyWatchHack() // self == trophy system
{
self endon( "death" );
self waittill( "hacked", player );
self clientfield::set( "trophy_system_state", 0 );
}
//******************************************************************
// *
// *
//******************************************************************
function onTrophySystemSmashed( attacker ) // self == trophy system
{
PlayFX( level._effect["tacticalInsertionFizzle"], self.origin );
self playsound ("dst_trophy_smash");
if( isdefined( level.playEquipmentDestroyedOnPlayer ) )
{
self.owner [[level.playEquipmentDestroyedOnPlayer]]( );
}
if ( isdefined(attacker) && self.owner util::IsEnemyPlayer( attacker ) )
{
attacker challenges::destroyedEquipment();
scoreevents::processScoreEvent( "destroyed_trophy_system", attacker, self.owner );
}
self delete();
}
//******************************************************************
// *
// *
//******************************************************************
function trophyActive( owner ) // self == trophy system
{
owner endon( "disconnect" );
self endon( "death" );
self endon( "hacked" );
while( true )
{
if ( !isdefined( self ) )
{
return;
}
if (( level.missileEntities.size < 1 ) || isdefined( self.disabled ))
{
wait( .05 );
continue;
}
for ( index=0; index < level.missileEntities.size; index++ )
{
wait( .05 ); // only handle 1 missile per frame
if ( !isdefined( self ) )
{
return;
}
grenade = level.missileEntities[index];
if ( !isdefined(grenade) )
continue;
if ( grenade == self )
continue;
if ( !grenade.weapon.destroyableByTrophySystem )
{
continue;
}
switch( grenade.model )
{
case "t6_wpn_grenade_supply_projectile":
continue;
}
if ( grenade.weapon == self.weapon )
{
if ( self.trophySystemStationary == false && grenade.trophySystemStationary == true )
{
continue;
}
}
if ( !isdefined( grenade.owner ) )
{
grenade.owner = GetMissileOwner( grenade );
}
if ( isdefined( grenade.owner ))
{
if ( level.teamBased )
{
if ( grenade.owner.team == owner.team )
{
continue;
}
}
else
{
if ( grenade.owner == owner )
{
continue;
}
}
grenadeDistanceSquared = DistanceSquared( grenade.origin, self.origin );
if ( grenadeDistanceSquared < ( 512 * 512 ))
{
if ( BulletTracePassed( grenade.origin, self.origin + (0,0,29), false, self, grenade, false, true ) )
{
playFX( level.trophyLongFlashFX, self.origin + (0,0,15), ( grenade.origin - self.origin ), AnglesToUp( self.angles ) );
// projectileExplode deletes the missile ent
// so need to update index on shuffled-down level.missileEntities[]
owner thread projectileExplode( grenade, self );
index--;
//Eckert - Plays sound when destroying projectile/grenade
self playsound ( "wpn_trophy_alert" );
if ( GetDvarint( "player_sustainAmmo" ) == 0 )
{
self.ammo--;
if ( self.ammo <= 0 )
{
self thread trophySystemDetonate();
}
}
}
}
}
}
}
}
//******************************************************************
// *
// *
//******************************************************************
function projectileExplode( projectile, trophy ) // self == trophy owning player
{
self endon( "death" );
projPosition = projectile.origin;
playFX( level.trophyDetonationFX, projPosition );
projectile notify ( "trophy_destroyed" );
trophy RadiusDamage( projPosition, 128, 105, 10, self );
scoreevents::processScoreEvent( "trophy_defense", self );
self challenges::trophy_defense( projPosition, 512 );
if ( self util::is_item_purchased( "trophy_system" ) )
{
self AddPlayerStat( "destroy_explosive_with_trophy", 1 );
}
self AddWeaponStat( trophy.weapon, "CombatRecordStat", 1 );
projectile delete();
}
//******************************************************************
// *
// *
//******************************************************************
function trophyDestroyTacInsert( tacInsert, trophy ) // self == trophy system owner
{
self endon( "death" );
tacPos = tacInsert.origin;
playFX( level.trophyDetonationFX, tacInsert.origin );
tacInsert thread tacticalinsertion::tacticalInsertionDestroyedByTrophySystem( self, trophy );
trophy RadiusDamage( tacPos, 128, 105, 10, self );
scoreevents::processScoreEvent( "trophy_defense", self );
if ( self util::is_item_purchased( "trophy_system" ) )
{
self AddPlayerStat( "destroy_explosive_with_trophy", 1 );
}
self AddWeaponStat( trophy.weapon, "CombatRecordStat", 1 );
}
//******************************************************************
// *
// *
//******************************************************************
function trophySystemDetonate(attacker, weapon, target)
{
if ( !isdefined( weapon ) || !weapon.isEmp )
{
PlayFX( level._equipment_explode_fx_lg, self.origin );
}
if ( isdefined(attacker) && self.owner util::IsEnemyPlayer( attacker ) )
{
attacker challenges::destroyedEquipment( weapon );
scoreevents::processScoreEvent( "destroyed_trophy_system", attacker, self.owner, weapon );
}
PlaySoundAtPosition ( "exp_trophy_system", self.origin );
self delete();
}
//******************************************************************
// *
// *
//******************************************************************
function watchTrophySystemDamage( watcher ) // self == trophy system
{
self endon( "death" );
self endon( "hacked" );
self SetCanDamage( true );
damageMax = 20;
if ( !self util::isHacked() )
{
self.damageTaken = 0;
}
self.maxhealth = 10000;
self.health = self.maxhealth;
self setmaxhealth( self.maxhealth );
attacker = undefined;
while( true )
{
self waittill ( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, weapon, iDFlags );
attacker = self [[ level.figure_out_attacker ]]( attacker );
if( !isplayer( attacker ))
{
continue;
}
if ( level.teambased )
{
// if we're not hardcore and the team is the same, do not destroy
if( !level.hardcoreMode && self.owner.team == attacker.pers["team"] && self.owner != attacker )
{
continue;
}
}
// most equipment should be flash/concussion-able, so it'll disable for a short period of time
// check to see if the equipment has been flashed/concussed and disable it (checking damage < 5 is a bad idea, so check the weapon name)
// we're currently allowing the owner/teammate to flash their own
// do damage feedback
if ( watcher.stunTime > 0 && weapon.doStun )
{
self thread weaponobjects::stunStart( watcher, watcher.stunTime );
}
if ( weapon.doDamageFeedback )
{
// if we're not on the same team then show damage feedback
if ( level.teambased && self.owner.team != attacker.team )
{
if ( damagefeedback::doDamageFeedback( weapon, attacker ) )
attacker damagefeedback::update();
}
// for ffa just make sure the owner isn't the same
else if ( !level.teambased && self.owner != attacker )
{
if ( damagefeedback::doDamageFeedback( weapon, attacker ) )
attacker damagefeedback::update();
}
}
if ( type == "MOD_MELEE" || weapon.isEmp || weapon.destroysEquipment )
{
self.damageTaken = damageMax;
}
else
{
self.damageTaken += damage;
}
if( self.damageTaken >= damageMax )
{
watcher thread weaponobjects::waitAndDetonate( self, 0.05, attacker, weapon );
return;
}
}
}
function ammo_scavenger( weapon )
{
self ammo_reset();
}
function ammo_reset()
{
self._trophy_system_ammo1 = undefined;
self._trophy_system_ammo2 = undefined;
}
function ammo_get( weapon )
{
totalAmmo = weapon.ammoCountEquipment;
if ( isdefined( self._trophy_system_ammo1 ) && !self util::isHacked() )
{
totalAmmo = self._trophy_system_ammo1;
self._trophy_system_ammo1 = undefined;
if ( isdefined( self._trophy_system_ammo2 ) )
{
self._trophy_system_ammo1 = self._trophy_system_ammo2;
self._trophy_system_ammo2 = undefined;
}
}
return totalAmmo;
}
function ammo_weapon_pickup( ammo )
{
if ( isdefined( ammo ) )
{
if ( isdefined( self._trophy_system_ammo1 ) )
{
self._trophy_system_ammo2 = self._trophy_system_ammo1;
self._trophy_system_ammo1 = ammo;
}
else
{
self._trophy_system_ammo1 = ammo;
}
}
}
function ammo_weapon_hacked( ammo )
{
self ammo_weapon_pickup( ammo );
}