814 lines
21 KiB
Plaintext
814 lines
21 KiB
Plaintext
#include common_scripts\utility;
|
|
#include maps\mp\_utility;
|
|
|
|
init()
|
|
{
|
|
level.riot_shield_names = [];
|
|
level.riot_shield_names[level.riot_shield_names.size] = "riotshield_mp";
|
|
level.riot_shield_names[level.riot_shield_names.size] = "iw5_riotshieldt6_mp";
|
|
level.riot_shield_names[level.riot_shield_names.size] = "iw5_riotshieldt6loot0_mp";
|
|
level.riot_shield_names[level.riot_shield_names.size] = "iw5_riotshieldt6loot1_mp";
|
|
level.riot_shield_names[level.riot_shield_names.size] = "iw5_riotshieldt6loot2_mp";
|
|
level.riot_shield_names[level.riot_shield_names.size] = "iw5_riotshieldt6loot3_mp";
|
|
level.riot_shield_names[level.riot_shield_names.size] = "iw5_riotshieldjugg_mp";
|
|
|
|
precacheAnims();
|
|
|
|
// loadfx( "weapon/riotshield/fx_riotshield_depoly_lights" );
|
|
// loadfx( "weapon/riotshield/fx_riotshield_depoly_dust" );
|
|
|
|
level.riot_shield_collision = GetEnt( "riot_shield_collision", "targetname" );
|
|
|
|
level._effect[ "riot_shield_shock_fx" ] = LoadFX( "vfx/explosion/riotshield_stun" );
|
|
level._effect[ "riot_shield_deploy_smoke" ] = LoadFX( "vfx/smoke/riotshield_deploy_smoke" );
|
|
level._effect[ "riot_shield_deploy_lights" ] = LoadFX( "vfx/lights/riotshield_deploy_lights" );
|
|
}
|
|
|
|
|
|
#using_animtree ( "mp_riotshield" );
|
|
precacheAnims()
|
|
{
|
|
PrecacheMpAnim( "npc_deployable_riotshield_stand_deploy" );
|
|
PrecacheMpAnim( "npc_deployable_riotshield_stand_destroyed" );
|
|
PrecacheMpAnim( "npc_deployable_riotshield_stand_shot" );
|
|
PrecacheMpAnim( "npc_deployable_riotshield_stand_shot_back" );
|
|
PrecacheMpAnim( "npc_deployable_riotshield_stand_melee_front" );
|
|
PrecacheMpAnim( "npc_deployable_riotshield_stand_melee_back" );
|
|
}
|
|
|
|
|
|
hasRiotShield() // self == player
|
|
{
|
|
return ( IsDefined( self.frontShieldModel ) || IsDefined( self.backShieldModel ) );
|
|
}
|
|
|
|
|
|
hasRiotShieldEquipped() // self == player
|
|
{
|
|
return ( IsDefined( self.frontShieldModel ) );
|
|
}
|
|
|
|
|
|
weaponIsRiotShield( inWeaponName )
|
|
{
|
|
inBaseWeaponName = GetWeaponBaseName( inWeaponName );
|
|
if ( !IsDefined( inBaseWeaponName ) )
|
|
inBaseWeaponName = inWeaponName;
|
|
|
|
foreach( weaponName in level.riot_shield_names )
|
|
{
|
|
if ( weaponName == inBaseWeaponName )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
weaponIsShockPlantRiotShield( inWeaponName )
|
|
{
|
|
if ( !weaponIsRiotShield( inWeaponName ) )
|
|
return false;
|
|
|
|
return IsSubStr( inWeaponName, "shockplant" );
|
|
}
|
|
|
|
|
|
getOtherRiotShieldName( inWeaponName )
|
|
{
|
|
foundInputWeapon = false;
|
|
weapons = self GetWeaponsListPrimaries();
|
|
foreach( weapon in weapons )
|
|
{
|
|
if ( weaponIsRiotShield( weapon ) )
|
|
{
|
|
if ( ( weapon == inWeaponName ) && !foundInputWeapon )
|
|
foundInputWeapon = true;
|
|
else
|
|
return weapon;
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
|
|
updateFrontAndBackShields( newWeapon ) // self == player
|
|
{
|
|
// note this function must play nice with _detachAll().
|
|
self.frontShieldModel = undefined;
|
|
self.backShieldModel = undefined;
|
|
|
|
if ( !IsDefined( newWeapon ) )
|
|
newWeapon = self GetCurrentPrimaryWeapon();
|
|
|
|
if ( weaponIsRiotShield( newWeapon ) )
|
|
{
|
|
self.frontShieldModel = GetWeaponModel( newWeapon );
|
|
}
|
|
|
|
otherShield = getOtherRiotShieldName( newWeapon );
|
|
if ( IsDefined( otherShield ) )
|
|
{
|
|
assert( weaponIsRiotShield( otherShield ) );
|
|
self.backShieldModel = GetWeaponModel( otherShield );
|
|
}
|
|
|
|
self RefreshShieldModels( newWeapon );
|
|
}
|
|
|
|
|
|
riotShield_clear()
|
|
{
|
|
self.frontShieldModel = undefined;
|
|
self.backShieldModel = undefined;
|
|
}
|
|
|
|
entIsStuckToShield()
|
|
{
|
|
if ( !self IsLinked() )
|
|
return false;
|
|
|
|
tagName = self GetLinkedTagName();
|
|
if ( !IsDefined( tagName ) )
|
|
return false;
|
|
|
|
switch( tagName )
|
|
{
|
|
case "tag_weapon_left": // Front shield
|
|
case "tag_shield_back": // Back shield
|
|
case "tag_inhand": // Exo shield
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
watchRiotShieldUse() // self == player
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
self endon ( "faux_spawn" );
|
|
|
|
// watcher for attaching the model to correct player bones
|
|
self thread trackRiotShield();
|
|
|
|
for ( ;; )
|
|
{
|
|
self waittill( "raise_riotshield" );
|
|
self thread startRiotshieldDeploy();
|
|
}
|
|
}
|
|
|
|
riotshield_watch_for_change_weapon() // self == player
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
self endon( "faux_spawn" );
|
|
self endon( "riotshield_change_weapon" );
|
|
|
|
newWeapon = undefined;
|
|
|
|
self waittill( "weapon_change", newWeapon );
|
|
|
|
self notify ( "riotshield_change_weapon", newWeapon );
|
|
}
|
|
|
|
riotshield_watch_for_start_change_weapon() // self == player
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
self endon( "faux_spawn" );
|
|
self endon( "riotshield_change_weapon" );
|
|
|
|
newWeapon = undefined;
|
|
|
|
// SetDvarIfUninitialized( "scr_twoshield_wait", 1.0 );
|
|
|
|
while( 1 )
|
|
{
|
|
self waittill( "weapon_switch_started", newWeapon );
|
|
|
|
// Climbing a ladder instantly switches
|
|
if ( self IsOnLadder() )
|
|
{
|
|
self thread riotshield_watch_for_ladder_early_exit();
|
|
break;
|
|
}
|
|
|
|
// If you have two shields, handle the swap time manually
|
|
if ( IsDefined( self.frontShieldModel ) && IsDefined( self.backShieldModel ) )
|
|
{
|
|
// wait( GetDvarFloat( "scr_twoshield_wait", 1.0 ) );
|
|
wait( 0.5 );
|
|
break;
|
|
}
|
|
}
|
|
|
|
self notify ( "riotshield_change_weapon", newWeapon );
|
|
}
|
|
|
|
riotshield_watch_for_ladder_early_exit() // self == player
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
self endon( "faux_spawn" );
|
|
self endon( "weapon_change" ); // Stop worrying once the ladder weapon change completes
|
|
|
|
while( self IsOnLadder() )
|
|
waitframe();
|
|
|
|
self notify ( "riotshield_change_weapon", self GetCurrentPrimaryWeapon() );
|
|
}
|
|
|
|
riotshield_watch_for_exo_shield_pullback() // self == player
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
self endon( "faux_spawn" );
|
|
self endon( "riotshield_change_weapon" );
|
|
|
|
newWeapon = undefined;
|
|
|
|
exo_shield_weapon = maps\mp\_exo_shield::get_exo_shield_weapon();
|
|
|
|
self waittillmatch( "grenade_pullback", exo_shield_weapon );
|
|
|
|
// Allow time for the flag to get set
|
|
while( !IsDefined( self.exo_shield_on ) || !self.exo_shield_on )
|
|
waitframe();
|
|
|
|
self notify ( "riotshield_change_weapon", exo_shield_weapon );
|
|
}
|
|
|
|
riotshield_watch_for_exo_shield_release() // self == player
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
self endon( "faux_spawn" );
|
|
self endon( "riotshield_change_weapon" );
|
|
|
|
if ( !IsDefined( self.exo_shield_on ) || !self.exo_shield_on )
|
|
return;
|
|
|
|
newWeapon = undefined;
|
|
|
|
exo_shield_weapon = maps\mp\_exo_shield::get_exo_shield_weapon();
|
|
|
|
self waittillmatch( "battery_discharge_end", exo_shield_weapon );
|
|
|
|
// Allow time for the flag to clear
|
|
while( IsDefined( self.exo_shield_on ) && self.exo_shield_on )
|
|
waitframe();
|
|
|
|
self notify ( "riotshield_change_weapon", self getCurrentWeapon() );
|
|
}
|
|
|
|
|
|
trackRiotShield() // self == player
|
|
{
|
|
self endon ( "death" );
|
|
self endon ( "disconnect" );
|
|
self endon ( "faux_spawn" );
|
|
|
|
self notify( "track_riot_shield" );
|
|
self endon ( "track_riot_shield" );
|
|
|
|
self updateFrontAndBackShields( self.currentWeaponAtSpawn );
|
|
|
|
self.lastNonShieldWeapon = "none";
|
|
|
|
for ( ;; )
|
|
{
|
|
self thread watchRiotshieldPickup();
|
|
|
|
prevWeapon = self getCurrentWeapon();
|
|
if ( IsDefined( self.exo_shield_on ) && self.exo_shield_on )
|
|
prevWeapon = maps\mp\_exo_shield::get_exo_shield_weapon();
|
|
|
|
self thread riotshield_watch_for_change_weapon();
|
|
self thread riotshield_watch_for_start_change_weapon();
|
|
self thread riotshield_watch_for_exo_shield_pullback();
|
|
self thread riotshield_watch_for_exo_shield_release();
|
|
self waittill ( "riotshield_change_weapon", newWeapon );
|
|
|
|
if ( weaponIsRiotShield( newWeapon ) )
|
|
{
|
|
if ( self hasRiotShield() )
|
|
{
|
|
if ( IsDefined( self.riotshieldTakeWeapon ))
|
|
{
|
|
self TakeWeapon( self.riotshieldTakeWeapon );
|
|
self.riotshieldTakeWeapon = undefined;
|
|
}
|
|
}
|
|
|
|
if( isValidNonShieldWeapon( prevWeapon ) )
|
|
{
|
|
self.lastNonShieldWeapon = prevWeapon;
|
|
}
|
|
}
|
|
|
|
updateRiotShieldAttachForNewWeapon( newWeapon );
|
|
}
|
|
}
|
|
|
|
|
|
updateRiotShieldAttachForNewWeapon( newWeapon ) // self == player
|
|
{
|
|
// Do nothing, we want to keep that weapon on their arm. Will get another changeweapon when finished mantling
|
|
if ( ( self IsMantling() ) && ( newWeapon == "none" ) )
|
|
return;
|
|
|
|
updateFrontAndBackShields( newWeapon );
|
|
}
|
|
|
|
|
|
watchRiotshieldPickup() // self == player
|
|
{
|
|
self endon ( "death" );
|
|
self endon ( "disconnect" );
|
|
self endon ( "track_riot_shield" );
|
|
|
|
self notify ( "watch_riotshield_pickup" );
|
|
self endon ( "watch_riotshield_pickup" );
|
|
|
|
// tagTMR<NOTE>: fix for rare case when riotshield is given by the server
|
|
// but the client fails to equip because of prone
|
|
|
|
self waittill ( "pickup_riotshield" );
|
|
self endon ( "weapon_change" );
|
|
|
|
/#println( "Picked up riotshield, expecting weapon_change notify..." );#/
|
|
|
|
wait 0.5;
|
|
|
|
/#println( "picked up shield but didn't change weapons, attach it!" );#/
|
|
|
|
updateRiotShieldAttachForNewWeapon( self getCurrentWeapon() );
|
|
}
|
|
|
|
|
|
isValidNonShieldWeapon( weapon )
|
|
{
|
|
if( maps\mp\_utility::isKillstreakWeapon( weapon ) )
|
|
return false;
|
|
|
|
if( weapon == "none" )
|
|
return false;
|
|
|
|
if ( maps\mp\gametypes\_class::isValidEquipment( weapon, true ) ||
|
|
maps\mp\gametypes\_class::isValidEquipment( weapon, false ) )
|
|
return false;
|
|
|
|
if ( weaponIsRiotShield( weapon ) )
|
|
return false;
|
|
|
|
if ( WeaponClass(weapon) == "ball" )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
startRiotshieldDeploy() // self == player
|
|
{
|
|
self thread watchRiotshieldDeploy();
|
|
}
|
|
|
|
|
|
handleRiotShieldShockPlant() // self == player
|
|
{
|
|
shield_ent = self.riotshieldEntity;
|
|
assert( IsDefined( shield_ent ) );
|
|
|
|
min_damage = 10;
|
|
max_damage = 50;
|
|
radius = 150;
|
|
radius_sq = ( radius * radius );
|
|
|
|
event_origin = self.riotshieldEntity.origin + ( 0, 0, -25 );
|
|
|
|
self RadiusDamage( event_origin, radius, max_damage, min_damage, self, "MOD_EXPLOSIVE" );
|
|
|
|
PlayFX( level._effect[ "riot_shield_shock_fx" ], event_origin, AnglesToForward( self.riotshieldEntity.angles + ( -90, 0, 0 )) );
|
|
|
|
foreach( player in level.players )
|
|
{
|
|
if ( isReallyAlive( player ) && !IsAlliedSentient( player, self ) )
|
|
{
|
|
if ( DistanceSquared( event_origin, player.origin ) < radius_sq )
|
|
{
|
|
player ShellShock( "concussion_grenade_mp", 1 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
watchRiotshieldDeploy() // self == player
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
|
|
self notify( "start_riotshield_deploy" );
|
|
self endon( "start_riotshield_deploy" );
|
|
|
|
self waittill( "startdeploy_riotshield" );
|
|
|
|
self PlaySound( "wpn_riot_shield_plant_mech" );
|
|
|
|
self waittill( "deploy_riotshield", deploy_attempt );
|
|
|
|
// if we have a deployed riotshield in the world, delete if we attempt to deploy another
|
|
if ( IsDefined( self.riotshieldEntity ))
|
|
{
|
|
self.riotshieldEntity thread damageThenDestroyRiotshield();
|
|
waitframe(); // give it some time to clean up
|
|
}
|
|
|
|
curWeapon = self GetCurrentWeapon();
|
|
self SetWeaponModelVariant( curWeapon, 0 );
|
|
|
|
shockVersion = weaponIsShockPlantRiotShield( curWeapon );
|
|
|
|
self PlaySound( "wpn_riot_shield_plant_punch" );
|
|
if ( shockVersion )
|
|
self PlaySound( "wpn_riot_shield_blast_punch" );
|
|
|
|
//self SetPlacementHint( 1 );
|
|
|
|
placement_hint = false;
|
|
|
|
if ( deploy_attempt )
|
|
{
|
|
placement = self CanPlaceRiotshield();
|
|
|
|
if ( placement["result"] && riotshieldDistanceTest( placement["origin"] ) )
|
|
{
|
|
zoffset = 28;
|
|
|
|
shield_ent = self spawnRiotshieldCover( placement["origin"] + ( 0, 0, zoffset ), placement["angles"] );
|
|
coll_ent = self spawnRiotshieldCollision( placement["origin"] + ( 0, 0, zoffset ), placement["angles"], shield_ent );
|
|
item_ent = DeployRiotShield( self, shield_ent );
|
|
|
|
primaries = self GetWeaponsListPrimaries();
|
|
|
|
/#
|
|
assert( IsDefined( item_ent ) );
|
|
assert( !IsDefined( self.riotshieldRetrieveTrigger ) );
|
|
assert( !IsDefined( self.riotshieldEntity ) );
|
|
assert( !IsDefined( self.riotshieldCollisionEntity ) );
|
|
#/
|
|
|
|
self.riotshieldRetrieveTrigger = item_ent;
|
|
self.riotshieldEntity = shield_ent;
|
|
self.riotshieldCollisionEntity = coll_ent;
|
|
|
|
if ( shockVersion )
|
|
self thread handleRiotShieldShockPlant();
|
|
else
|
|
PlayFXOnTag( getfx( "riot_shield_deploy_smoke" ), shield_ent, "tag_weapon" );
|
|
|
|
//shield_ent SetClientField( "riotshield_state", RIOTSHIELD_STATE_DEPLOYED );
|
|
// TODO: spawn thread to: play deploy anim on shield, play dust fx at shield origin, wait 0.8, playfxontag light fx at tag_fx on shield
|
|
shield_ent ScriptModelPlayAnimDeltaMotion( "npc_deployable_riotshield_stand_deploy" );
|
|
// Play Dust FX at shield origin
|
|
// spawn thread:
|
|
thread spawnShieldLights( shield_ent );
|
|
|
|
|
|
switchToKnife = false;
|
|
if( self.lastNonShieldWeapon != "none" && self hasWeapon( self.lastNonShieldWeapon ) )
|
|
self SwitchToWeaponImmediate( self.lastNonShieldWeapon );
|
|
else if ( primaries.size > 0 )
|
|
self SwitchToWeaponImmediate( primaries[0] );
|
|
else
|
|
switchToKnife = true;
|
|
|
|
if ( !self HasWeapon( "iw5_combatknife_mp" ) )
|
|
{
|
|
self GiveWeapon( "iw5_combatknife_mp" );
|
|
self.riotshieldTakeWeapon = "iw5_combatknife_mp";
|
|
}
|
|
|
|
if ( switchToKnife )
|
|
self SwitchToWeaponImmediate( "iw5_combatknife_mp" );
|
|
|
|
// Moving platforms.
|
|
data = SpawnStruct();
|
|
data.deathOverrideCallback = ::damageThenDestroyRiotshield;
|
|
shield_ent thread maps\mp\_movers::handle_moving_platforms( data );
|
|
|
|
self thread watchDeployedRiotshieldEnts();
|
|
|
|
self thread deleteShieldOnTriggerDeath( self.riotshieldRetrieveTrigger );
|
|
self thread deleteShieldOnTriggerPickup( self.riotshieldRetrieveTrigger, self.riotshieldEntity );
|
|
self thread deleteShieldOnPlayerDeathOrDisconnect( shield_ent );
|
|
|
|
self.riotshieldEntity thread watchDeployedRiotshieldDamage();
|
|
level notify( "riotshield_planted", self );
|
|
}
|
|
else
|
|
{
|
|
placement_hint = true;
|
|
|
|
clip_max_ammo = WeaponClipSize( curWeapon );
|
|
self setWeaponAmmoClip( curWeapon, clip_max_ammo );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// tagTMR<NOTE>: just lowering the shield not trying to deploy
|
|
placement_hint = true;
|
|
}
|
|
|
|
if ( placement_hint )
|
|
{
|
|
self SetRiotshieldFailHint();
|
|
}
|
|
}
|
|
|
|
spawnShieldLights(ent)
|
|
{
|
|
level endon( "game_ended" );
|
|
ent endon( "death" );
|
|
|
|
wait 0.6;
|
|
PlayFXOnTag( getfx( "riot_shield_deploy_lights" ), ent, "tag_weapon" );
|
|
}
|
|
|
|
riotshieldDistanceTest( origin )
|
|
{
|
|
/#
|
|
assert ( IsDefined( origin ) );
|
|
#/
|
|
|
|
min_dist_squared = GetDvarFloat( "riotshield_deploy_limit_radius" );
|
|
min_dist_squared *= min_dist_squared;
|
|
|
|
foreach( player in level.players )
|
|
{
|
|
if ( IsDefined( player.riotshieldEntity ) )
|
|
{
|
|
dist_squared = DistanceSquared( player.riotshieldEntity.origin, origin );
|
|
if ( min_dist_squared > dist_squared )
|
|
{
|
|
/#
|
|
println( "Shield placement denied! Failed distance check to other riotshields." );
|
|
#/
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
spawnRiotshieldCover( origin, angles ) // self == player
|
|
{
|
|
shield_ent = Spawn( "script_model", origin );
|
|
shield_ent.targetname = "riotshield_mp";
|
|
shield_ent.angles = angles;
|
|
|
|
model = undefined;
|
|
curWeapon = self GetCurrentPrimaryWeapon();
|
|
if ( weaponIsRiotShield( curWeapon ) )
|
|
model = GetWeaponModel( curWeapon );
|
|
|
|
if ( !IsDefined( model ) )
|
|
model = "npc_deployable_riot_shield_base";
|
|
|
|
shield_ent SetModel( model );
|
|
// shield_ent SetEntityOwner( self ); // Removing this as it causes traces from the player to pass through it unintentionally (grenades and missiles especially)
|
|
shield_ent.owner = self;
|
|
shield_ent.team = self.team;
|
|
// shield_ent SetTeam( self.team );
|
|
|
|
// shield_ent UseAnimTree( #animtree );
|
|
|
|
return shield_ent;
|
|
}
|
|
|
|
|
|
spawnRiotshieldCollision( origin, angles, shield_ent ) // self == player
|
|
{
|
|
coll_ent = Spawn( "script_model", origin, 1 ); // third param is spawn flag for dynamic pathing
|
|
coll_ent.targetname = "riotshield_coll_mp";
|
|
coll_ent.angles = angles;
|
|
coll_ent SetModel( "tag_origin" );
|
|
coll_ent.owner = self;
|
|
coll_ent.team = self.team;
|
|
coll_ent CloneBrushmodelToScriptModel( level.riot_shield_collision );
|
|
coll_ent DisconnectPaths();
|
|
|
|
return coll_ent;
|
|
}
|
|
|
|
|
|
watchDeployedRiotshieldEnts() // self == player
|
|
{
|
|
/#
|
|
assert( IsDefined( self.riotshieldRetrieveTrigger ) );
|
|
assert( IsDefined( self.riotshieldEntity ) );
|
|
assert( IsDefined( self.riotshieldCollisionEntity ) );
|
|
#/
|
|
|
|
self waittill( "destroy_riotshield" );
|
|
|
|
if ( IsDefined( self.riotshieldRetrieveTrigger ) )
|
|
{
|
|
self.riotshieldRetrieveTrigger delete();
|
|
}
|
|
|
|
if ( IsDefined( self.riotshieldCollisionEntity ) )
|
|
{
|
|
self.riotshieldCollisionEntity ConnectPaths();
|
|
self.riotshieldCollisionEntity delete();
|
|
}
|
|
|
|
if ( IsDefined( self.riotshieldEntity ) )
|
|
{
|
|
self.riotshieldEntity delete();
|
|
}
|
|
}
|
|
|
|
|
|
deleteShieldOnTriggerPickup( shield_trigger, shield_ent ) // self == player
|
|
{
|
|
level endon( "game_ended" );
|
|
shield_trigger endon( "death" );
|
|
|
|
shield_trigger waittill( "trigger", player );
|
|
|
|
// Transfer any linked entities from the deployed shield to the player's arm at the same offset
|
|
HandlePickupDeployedRiotshield( player, shield_ent );
|
|
|
|
self notify( "destroy_riotshield" );
|
|
}
|
|
|
|
|
|
deleteShieldOnTriggerDeath( shield_trigger ) // self == player
|
|
{
|
|
level endon( "game_ended" );
|
|
|
|
shield_trigger waittill( "death" );
|
|
self notify( "destroy_riotshield" );
|
|
}
|
|
|
|
|
|
deleteShieldOnPlayerDeathOrDisconnect( shield_ent ) // self == player
|
|
{
|
|
shield_ent endon( "death" );
|
|
shield_ent endon( "damageThenDestroyRiotshield" );
|
|
|
|
self waittill_any( "death", "disconnect", "remove_planted_weapons" );
|
|
|
|
shield_ent thread damageThenDestroyRiotshield();
|
|
}
|
|
|
|
|
|
watchDeployedRiotshieldDamage() // self == riotshield script_model ent
|
|
{
|
|
self endon( "death" );
|
|
|
|
damageMax = GetDvarInt( "riotshield_deployed_health" );
|
|
self.damageTaken = 0;
|
|
|
|
nextDamageAnimTime = 0;
|
|
|
|
while( true )
|
|
{
|
|
self.maxhealth = 100000;
|
|
self.health = self.maxhealth;
|
|
|
|
self waittill( "damage", damage, attacker, direction, point, type, modelName, tagName, partname, iDFlags, weaponName );
|
|
|
|
if( !isdefined( attacker ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/#
|
|
assert( isDefined( self.owner ) && isDefined( self.owner.team ));
|
|
#/
|
|
|
|
if ( isplayer( attacker ) )
|
|
{
|
|
if ( ( level.teamBased ) && ( attacker.team == self.owner.team ) && ( attacker != self.owner ) )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
isMeleeDamage = false;
|
|
isBulletDamage = false;
|
|
|
|
if ( isMeleeMOD( type ) )
|
|
{
|
|
isMeleeDamage = true;
|
|
damage *= GetDvarfloat( "riotshield_melee_damage_scale" );
|
|
}
|
|
else if ( type == "MOD_PISTOL_BULLET" || type == "MOD_RIFLE_BULLET" )
|
|
{
|
|
isBulletDamage = true;
|
|
damage *= GetDvarfloat( "riotshield_bullet_damage_scale" );
|
|
}
|
|
else if ( type == "MOD_GRENADE" || type == "MOD_GRENADE_SPLASH" || type == "MOD_EXPLOSIVE" || type == "MOD_EXPLOSIVE_SPLASH" || type == "MOD_PROJECTILE" || type == "MOD_PROJECTILE_SPLASH")
|
|
{
|
|
damage *= GetDvarfloat( "riotshield_explosive_damage_scale" );
|
|
}
|
|
else if ( type == "MOD_IMPACT" )
|
|
{
|
|
damage *= GetDvarFloat( "riotshield_projectile_damage_scale" );
|
|
}
|
|
else if ( type == "MOD_CRUSH" )
|
|
{
|
|
damage = damageMax;
|
|
}
|
|
|
|
self.damageTaken += damage;
|
|
|
|
if( self.damageTaken >= damageMax )
|
|
{
|
|
self thread damageThenDestroyRiotshield( attacker, weaponName );
|
|
break;
|
|
}
|
|
else if ( ( isMeleeDamage || isBulletDamage ) && ( GetTime() >= nextDamageAnimTime ) )
|
|
{
|
|
nextDamageAnimTime = GetTime() + 500;
|
|
|
|
fromBack = false;
|
|
shield_fwd = AnglesToForward( self.angles );
|
|
if ( VectorDot( direction, shield_fwd ) > 0 )
|
|
fromBack = true;
|
|
|
|
if ( isMeleeDamage )
|
|
{
|
|
if ( fromBack )
|
|
self ScriptModelPlayAnimDeltaMotion( "npc_deployable_riotshield_stand_melee_back" );
|
|
else
|
|
self ScriptModelPlayAnimDeltaMotion( "npc_deployable_riotshield_stand_melee_front" );
|
|
}
|
|
else
|
|
{
|
|
Assert( isBulletDamage );
|
|
if ( fromBack )
|
|
self ScriptModelPlayAnimDeltaMotion( "npc_deployable_riotshield_stand_shot_back" );
|
|
else
|
|
self ScriptModelPlayAnimDeltaMotion( "npc_deployable_riotshield_stand_shot" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
damageThenDestroyRiotshield(attacker, weaponName) // self == riotshield script_model ent
|
|
{
|
|
self notify( "damageThenDestroyRiotshield" );
|
|
self endon( "death" );
|
|
|
|
if ( IsDefined( self.owner.riotshieldRetrieveTrigger ) )
|
|
{
|
|
self.owner.riotshieldRetrieveTrigger delete();
|
|
}
|
|
|
|
if ( IsDefined( self.owner.riotshieldCollisionEntity ) )
|
|
{
|
|
self.owner.riotshieldCollisionEntity ConnectPaths();
|
|
self.owner.riotshieldCollisionEntity delete();
|
|
}
|
|
|
|
|
|
self.owner.riotshieldEntity = undefined;
|
|
|
|
self NotSolid();
|
|
// self SetClientField( "riotshield_state", RIOTSHIELD_STATE_DESTROYED );
|
|
// TODO: stop fx, play sound, play destroyed anim, wait, force not simple dobj...?
|
|
// Stop FX on shield
|
|
// Play destroyed sound
|
|
self ScriptModelPlayAnimDeltaMotion( "npc_deployable_riotshield_stand_destroyed" );
|
|
// Wait
|
|
// Force not simple dobj?
|
|
|
|
// if (isdefined (attacker) && isdefined (weaponName) && attacker != self.owner && isplayer( attacker ) )
|
|
// {
|
|
// maps\mp\_scoreevents::processScoreEvent( "destroyed_shield", attacker, self.owner, weaponName );
|
|
// }
|
|
|
|
wait( GetDvarFloat( "riotshield_destroyed_cleanup_time" ) );
|
|
|
|
self delete();
|
|
}
|
|
|
|
|
|
watchRiotshieldStuckEntityDeath( grenade, owner ) // self == entity stuck with nade
|
|
{
|
|
grenade endon( "death" );
|
|
|
|
self waittill_any( "damageThenDestroyRiotshield", "death", "disconnect", "weapon_change", "deploy_riotshield" );
|
|
|
|
grenade Detonate( owner );
|
|
} |