498 lines
21 KiB
Plaintext
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 );
|
|
} |