487 lines
21 KiB
Plaintext
487 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\_hacker_tool;
|
|
#using scripts\shared\weapons\_weaponobjects;
|
|
|
|
|
|
|
|
|
|
#precache( "fx", "_t6/misc/fx_equip_tac_insert_light_grn" );
|
|
#precache( "fx", "_t6/misc/fx_equip_tac_insert_light_red" );
|
|
#precache( "fx", "_t6/misc/fx_equip_tac_insert_exp" );
|
|
|
|
#namespace tacticalinsertion;
|
|
|
|
function init_shared()
|
|
{
|
|
if( level.gametype == "infect" )
|
|
{
|
|
level.weaponTacticalInsertion = GetWeapon( "trophy_system" );
|
|
}
|
|
else
|
|
{
|
|
level.weaponTacticalInsertion = GetWeapon( "tactical_insertion" );
|
|
}
|
|
|
|
level._effect["tacticalInsertionFizzle"] = "_t6/misc/fx_equip_tac_insert_exp";
|
|
|
|
clientfield::register( "scriptmover", "tacticalinsertion", 1, 1, "int" );
|
|
|
|
callback::on_spawned( &on_player_spawned );
|
|
}
|
|
|
|
function on_player_spawned()
|
|
{
|
|
self thread begin_other_grenade_tracking();
|
|
}
|
|
|
|
function isTacSpawnTouchingCrates( origin, angles )
|
|
{
|
|
crate_ents = GetEntArray( "care_package", "script_noteworthy" );
|
|
mins = ( -17, -17, -40 );
|
|
maxs = ( 17, 17, 40 );
|
|
for ( i = 0 ; i < crate_ents.size ; i++ )
|
|
{
|
|
if ( crate_ents[i] IsTouchingVolume( origin + (0,0,40), mins, maxs ) )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function overrideSpawn(isPredictedSpawn)
|
|
{
|
|
if ( !isdefined( self.tacticalInsertion ) )
|
|
return false;
|
|
|
|
origin = self.tacticalInsertion.origin;
|
|
angles = self.tacticalInsertion.angles;
|
|
team = self.tacticalInsertion.team;
|
|
|
|
if (!isPredictedSpawn)
|
|
self.tacticalInsertion destroy_tactical_insertion();
|
|
|
|
if ( team != self.team )
|
|
return false;
|
|
|
|
if ( isTacSpawnTouchingCrates( origin ) )
|
|
return false;
|
|
|
|
if (!isPredictedSpawn)
|
|
{
|
|
self.tacticalInsertionTime = getTime();
|
|
self spawn( origin, angles, "tactical insertion" );
|
|
self SetSpawnClientFlag( "SCDFL_DISABLE_LOGGING" );
|
|
self AddWeaponStat( level.weaponTacticalInsertion, "used", 1 );
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function waitAndDelete( time )
|
|
{
|
|
self endon( "death" );
|
|
|
|
// Wait a server frame to let missile fully enter the world
|
|
{wait(.05);};
|
|
|
|
// Delete grenade entity
|
|
self delete();
|
|
}
|
|
|
|
function watch( player )
|
|
{
|
|
// Remove existing tactical insertion, if it exists
|
|
if ( isdefined( player.tacticalInsertion ) )
|
|
{
|
|
player.tacticalInsertion destroy_tactical_insertion();
|
|
}
|
|
|
|
// Spawn tactical insertion
|
|
player thread spawnTacticalInsertion();
|
|
|
|
// Delete grenade entity
|
|
self waitAndDelete( 0.05 );
|
|
}
|
|
|
|
function watchUseTrigger( trigger, callback, playerSoundOnUse, npcSoundOnUse )
|
|
{
|
|
self endon( "delete" );
|
|
|
|
while ( true )
|
|
{
|
|
trigger waittill( "trigger", player );
|
|
|
|
if ( !isAlive( player ) )
|
|
continue;
|
|
|
|
if ( !player isOnGround() )
|
|
continue;
|
|
|
|
if ( isdefined( trigger.triggerTeam ) && ( player.team != trigger.triggerTeam ) )
|
|
continue;
|
|
|
|
if ( isdefined( trigger.triggerTeamIgnore ) && ( player.team == trigger.triggerTeamIgnore ) )
|
|
continue;
|
|
|
|
if ( isdefined( trigger.claimedBy ) && ( player != trigger.claimedBy ) )
|
|
continue;
|
|
|
|
if ( player useButtonPressed() && !player.throwingGrenade && !player meleeButtonPressed() )
|
|
{
|
|
if ( isdefined( playerSoundOnUse ) )
|
|
player playLocalSound( playerSoundOnUse );
|
|
if ( isdefined( npcSoundOnUse ) )
|
|
player playSound( npcSoundOnUse );
|
|
|
|
self thread [[callback]]( player );
|
|
}
|
|
}
|
|
}
|
|
|
|
function watchDisconnect()
|
|
{
|
|
self.tacticalInsertion endon( "delete" );
|
|
|
|
self waittill( "disconnect" );
|
|
self.tacticalInsertion thread destroy_tactical_insertion();
|
|
}
|
|
|
|
function destroy_tactical_insertion(attacker)
|
|
{
|
|
self.owner.tacticalInsertion = undefined;
|
|
self notify( "delete" );
|
|
self.owner notify( "tactical_insertion_destroyed" );
|
|
|
|
self.friendlyTrigger delete();
|
|
self.enemyTrigger delete();
|
|
// "destroyed_explosive" notify, for challenges
|
|
if ( isdefined( attacker ) && isdefined( attacker.pers["team"] ) && isdefined( self.owner ) && isdefined( self.owner.pers["team"] ) )
|
|
{
|
|
if ( level.teambased )
|
|
{
|
|
if ( attacker.pers["team"] != self.owner.pers["team"] )
|
|
{
|
|
attacker notify("destroyed_explosive");
|
|
attacker challenges::destroyedEquipment();
|
|
attacker challenges::destroyedTacticalInsert();
|
|
scoreevents::processScoreEvent( "destroyed_tac_insert", attacker );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( attacker!= self.owner )
|
|
{
|
|
attacker notify("destroyed_explosive");
|
|
attacker challenges::destroyedEquipment();
|
|
attacker challenges::destroyedTacticalInsert();
|
|
scoreevents::processScoreEvent( "destroyed_tac_insert", attacker );
|
|
}
|
|
}
|
|
}
|
|
|
|
self delete();
|
|
}
|
|
|
|
function fizzle( attacker )
|
|
{
|
|
if ( isdefined( self.fizzle ) && self.fizzle )
|
|
return;
|
|
self.fizzle = true;
|
|
PlayFX( level._effect["tacticalInsertionFizzle"], self.origin );
|
|
self playsound ("dst_tac_insert_break");
|
|
//Notify player that their tact insert was destroyed
|
|
if ( isdefined( attacker ) && attacker != self.owner )
|
|
{
|
|
if( isdefined( level.globallogic_audio_dialog_on_player_override ) )//TODO T7 - remove once globallogic_audio is shared
|
|
{
|
|
self.owner [[level.globallogic_audio_dialog_on_player_override]]( "tact_destroyed", "item_destroyed" );
|
|
}
|
|
}
|
|
|
|
self destroy_tactical_insertion( attacker );
|
|
}
|
|
|
|
function pickUp( attacker )
|
|
{
|
|
player = self.owner;
|
|
self destroy_tactical_insertion();
|
|
player GiveWeapon( level.weaponTacticalInsertion );
|
|
player setWeaponAmmoClip( level.weaponTacticalInsertion, 1 );
|
|
}
|
|
|
|
function spawnTacticalInsertion() // self == player
|
|
{
|
|
self endon( "disconnect" );
|
|
|
|
trace = BulletTrace( self.origin, self.origin + (0,0,-30), false, self );
|
|
trace["position"] += ( 0, 0, 1 );
|
|
|
|
if( !self IsOnGround() && BulletTracePassed( self.origin, self.origin + (0,0,-30), false, self ) )
|
|
{
|
|
self GiveWeapon( level.weaponTacticalInsertion );
|
|
self setWeaponAmmoClip( level.weaponTacticalInsertion, 1 );
|
|
return;
|
|
}
|
|
|
|
// Setup model
|
|
self.tacticalInsertion = spawn( "script_model", trace["position"] );
|
|
self.tacticalInsertion setModel( "wpn_t7_trophy_system" );
|
|
self.tacticalInsertion.origin = self.origin + ( 0, 0, 1 );
|
|
self.tacticalInsertion.angles = self.angles;
|
|
self.tacticalInsertion.team = self.team;
|
|
self.tacticalInsertion setTeam( self.team );
|
|
self.tacticalInsertion.owner = self;
|
|
self.tacticalInsertion setOwner( self );
|
|
self.tacticalInsertion setWeapon( level.weaponTacticalInsertion );
|
|
|
|
self.tacticalInsertion endon( "delete" );
|
|
|
|
self.tacticalInsertion hacker_tool::registerWithHackerTool( level.equipmentHackerToolRadius, level.equipmentHackerToolTimeMs );
|
|
|
|
// Make usable
|
|
triggerHeight = 64;
|
|
triggerRadius = 128;
|
|
|
|
self.tacticalInsertion.friendlyTrigger = spawn( "trigger_radius_use", self.tacticalInsertion.origin + ( 0, 0, 3 ) );
|
|
self.tacticalInsertion.friendlyTrigger SetCursorHint( "HINT_NOICON", self.tacticalInsertion );
|
|
self.tacticalInsertion.friendlyTrigger SetHintString( &"MP_TACTICAL_INSERTION_PICKUP" );
|
|
if ( level.teamBased )
|
|
{
|
|
self.tacticalInsertion.friendlyTrigger SetTeamForTrigger( self.team );
|
|
self.tacticalInsertion.friendlyTrigger.triggerTeam = self.team;
|
|
}
|
|
self ClientClaimTrigger( self.tacticalInsertion.friendlyTrigger );
|
|
self.tacticalInsertion.friendlyTrigger.claimedBy = self;
|
|
|
|
self.tacticalInsertion.enemyTrigger = spawn( "trigger_radius_use", self.tacticalInsertion.origin + ( 0, 0, 3 ) );
|
|
self.tacticalInsertion.enemyTrigger SetCursorHint( "HINT_NOICON", self.tacticalInsertion );
|
|
self.tacticalInsertion.enemyTrigger SetHintString( &"MP_TACTICAL_INSERTION_DESTROY" );
|
|
self.tacticalInsertion.enemyTrigger SetInvisibleToPlayer( self );
|
|
if ( level.teamBased )
|
|
{
|
|
self.tacticalInsertion.enemyTrigger SetExcludeTeamForTrigger( self.team );
|
|
self.tacticalInsertion.enemyTrigger.triggerTeamIgnore = self.team;
|
|
}
|
|
|
|
self.tacticalInsertion clientfield::set( "tacticalinsertion", 1 );
|
|
|
|
self thread watchDisconnect();
|
|
watcher = weaponobjects::getWeaponObjectWatcherByWeapon( level.weaponTacticalInsertion );
|
|
self.tacticalInsertion thread watchUseTrigger( self.tacticalInsertion.friendlyTrigger,&pickUp, watcher.pickUpSoundPlayer, watcher.pickUpSound );
|
|
self.tacticalInsertion thread watchUseTrigger( self.tacticalInsertion.enemyTrigger,&fizzle );
|
|
|
|
if ( isdefined( self.tacticalInsertionCount ) )
|
|
self.tacticalInsertionCount++;
|
|
else
|
|
self.tacticalInsertionCount = 1;
|
|
|
|
self.tacticalInsertion SetCanDamage( true );
|
|
self.tacticalInsertion.health = 1;
|
|
|
|
while ( true )
|
|
{
|
|
self.tacticalInsertion waittill( "damage", damage, attacker, direction, point, type, tagName, modelName, partname, weapon, iDFlags );
|
|
|
|
if ( level.teamBased && ( !isdefined( attacker ) || !isPlayer( attacker ) || attacker.team == self.team ) && attacker != self )
|
|
continue;
|
|
|
|
if( attacker != self )
|
|
{
|
|
attacker challenges::destroyedEquipment( weapon );
|
|
attacker challenges::destroyedTacticalInsert();
|
|
scoreevents::processScoreEvent( "destroyed_tac_insert", attacker );
|
|
}
|
|
|
|
// 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.tacticalInsertion.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.tacticalInsertion.owner != attacker )
|
|
{
|
|
if ( damagefeedback::doDamageFeedback( weapon, attacker ) )
|
|
attacker damagefeedback::update();
|
|
}
|
|
}
|
|
|
|
//Notify player that their tact insert was destroyed
|
|
if ( isdefined( attacker ) && attacker != self )
|
|
{
|
|
if( isdefined( level.globallogic_audio_dialog_on_player_override ) )//TODO T7 - remove once globallogic_audio is shared
|
|
{
|
|
self [[level.globallogic_audio_dialog_on_player_override]]( "tact_destroyed", "item_destroyed" );
|
|
}
|
|
}
|
|
|
|
self.tacticalInsertion thread fizzle();
|
|
}
|
|
}
|
|
|
|
function cancel_button_think()
|
|
{
|
|
if ( !isdefined( self.tacticalInsertion ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
text = cancel_text_create();
|
|
|
|
self thread cancel_button_press();
|
|
|
|
event = self util::waittill_any_return( "tactical_insertion_destroyed", "disconnect", "end_killcam", "abort_killcam", "tactical_insertion_canceled", "spawned" );
|
|
|
|
if ( event == "tactical_insertion_canceled" )
|
|
{
|
|
self.tacticalInsertion destroy_tactical_insertion();
|
|
}
|
|
|
|
if ( isdefined( text ) )
|
|
{
|
|
text Destroy();
|
|
}
|
|
}
|
|
|
|
function cancelTackInsertionButton()
|
|
{
|
|
if( level.console )
|
|
return self changeSeatButtonPressed();
|
|
else
|
|
return self jumpButtonPressed();
|
|
}
|
|
|
|
function cancel_button_press()
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "end_killcam" );
|
|
self endon( "abort_killcam" );
|
|
|
|
while( true )
|
|
{
|
|
wait( .05 );
|
|
if ( self cancelTackInsertionButton() )
|
|
break;
|
|
}
|
|
|
|
self notify( "tactical_insertion_canceled" );
|
|
}
|
|
|
|
function cancel_text_create()
|
|
{
|
|
text = NewClientHudElem( self );
|
|
text.archived = false;
|
|
text.y = -100;
|
|
text.alignX = "center";
|
|
text.alignY = "middle";
|
|
text.horzAlign = "center";
|
|
text.vertAlign = "bottom";
|
|
text.sort = 10; // force to draw after the bars
|
|
text.font = "small";
|
|
text.foreground = true;
|
|
text.hideWhenInMenu = true;
|
|
|
|
if ( self IsSplitscreen() )
|
|
{
|
|
text.y = -80;
|
|
text.fontscale = 1.2;
|
|
}
|
|
else
|
|
{
|
|
text.fontscale = 1.6;
|
|
}
|
|
|
|
text setText( &"PLATFORM_PRESS_TO_CANCEL_TACTICAL_INSERTION" );
|
|
text.alpha = 1;
|
|
|
|
return text;
|
|
}
|
|
|
|
function getTacticalInsertions()
|
|
{
|
|
tac_inserts = [];
|
|
|
|
foreach( player in level.players )
|
|
{
|
|
if ( isdefined( player.tacticalInsertion ))
|
|
{
|
|
tac_inserts[ tac_inserts.size ] = player.tacticalInsertion;
|
|
}
|
|
}
|
|
|
|
return tac_inserts;
|
|
}
|
|
|
|
function tacticalInsertionDestroyedByTrophySystem( attacker, trophySystem ) // self == tac insert
|
|
{
|
|
owner = self.owner;
|
|
|
|
if ( isdefined( attacker ))
|
|
{
|
|
attacker challenges::destroyedEquipment( trophySystem.name );
|
|
attacker challenges::destroyedTacticalInsert();
|
|
}
|
|
|
|
self thread fizzle();
|
|
|
|
if( isdefined( owner ))
|
|
{
|
|
owner endon( "death" );
|
|
owner endon( "disconnect" );
|
|
|
|
wait (.05); // prevents clash with the player killed/lead change leader dialog(s)
|
|
|
|
if( isdefined( level.globallogic_audio_dialog_on_player_override ) )//TODO T7 - remove once globallogic_audio is shared
|
|
{
|
|
owner [[level.globallogic_audio_dialog_on_player_override]]( "tact_destroyed", "item_destroyed" );
|
|
}
|
|
}
|
|
}
|
|
|
|
function begin_other_grenade_tracking()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
|
|
self notify( "insertionTrackingStart" );
|
|
self endon( "insertionTrackingStart" );
|
|
|
|
for (;;)
|
|
{
|
|
self waittill ( "grenade_fire", grenade, weapon, cookTime );
|
|
|
|
if ( grenade util::isHacked() )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( weapon == level.weaponTacticalInsertion )
|
|
{
|
|
if( level.gametype == "infect" && self.team == game["defenders"] )
|
|
return;
|
|
|
|
grenade thread watch( self );
|
|
}
|
|
}
|
|
}
|