s1-scripts-dev/raw/maps/mp/killstreaks/_remoteturret.gsc
2025-05-21 16:23:17 +02:00

2294 lines
57 KiB
Plaintext

#include maps\mp\_utility;
#include common_scripts\utility;
#include maps\mp\gametypes\_hud_util;
/*
Remote Turret killstreak: the player will throw this and it will stick to the ground and give a remote view with a small turret
*/
// Killstreak Data
ENTER_MESSAGE_ALPHA = 0.25;
ENTER_MESSAGE_FADE_TIME = 1.5;
CONST_REMOTE_TURRET_SENTRY_BURSTMIN = 20;
CONST_REMOTE_TURRET_SENTRY_BURSTMAX = 120;
CONST_REMOTE_TURRET_SENTRY_PAUSEMIN = 0.15;
CONST_REMOTE_TURRET_SENTRY_PAUSEMAX = 0.35;
CONST_REMOTE_TURRET_SENTRY_SPINUPTIME = 0.05;
CONST_REMOTE_TURRET_SENTRY_OVERHEATTIME = 4.0;
CONST_REMOTE_TURRET_SENTRY_COOLDOWNTIME = 0.1;
CONST_REMOTE_TURRET_SENTRY_FXTIME = 0.3;
CONST_REMOTE_TURRET_SENTRY_HORZ_ARC = 80;
CONST_REMOTE_TURRET_SENTRY_HORZ_ARC_FULL = 180;
CONST_REMOTE_TURRET_SENTRY_TOP_ARC = 50;
CONST_REMOTE_TURRET_SENTRY_BOTTOM_ARC = 30;
CONST_REMOTE_TURRET_BEAM_WEAPINFO = "remote_energy_turret_mp";
CONST_REMOTE_TURRET_MG_WEAPINFO = "sentry_minigun_mp";
CONST_REMOTE_TURRET_ROCKET_WEAPINFO = "killstreakmahem_mp";
init()
{
if ( !IsDefined( level.turretType ) )
level.turretType = [];
level.turretType[ "mg_turret" ] = "remote_mg_turret";
level.killStreakFuncs[ "remote_mg_turret" ] = ::tryUseRemoteMGTurret;
level.killStreakFuncs[ "remote_mg_sentry_turret" ] = ::tryUseRemoteMGSentryTurret;
// level.killstreakWieldWeapons["remote_turret_mp"] = "remote_mg_sentry_turret";
level.killstreakWieldWeapons["remote_energy_turret_mp"] = "remote_mg_sentry_turret";
level.killstreakWieldWeapons["sentry_minigun_mp"] = "remote_mg_sentry_turret";
level.killstreakWieldWeapons["killstreakmahem_mp"] = "remote_mg_sentry_turret";
if ( !IsDefined( level.turretSettings ) )
level.turretSettings = [];
level.turretSettings[ "mg_turret" ] = spawnStruct();
level.turretSettings[ "mg_turret" ].sentryModeOn = "sentry";
level.turretSettings[ "mg_turret" ].sentryModeOff = "sentry_offline";
level.turretSettings[ "mg_turret" ].timeOut = 60.0;
level.turretSettings[ "mg_turret" ].maxHealth = 1000; // this is what we check against for death
level.turretSettings[ "mg_turret" ].streakName = "remote_mg_turret";
//level.turretSettings[ "mg_turret" ].modelBombSquad = "mp_remote_turret_bombsquad";
level.turretSettings[ "mg_turret" ].teamSplash = "used_remote_mg_turret";
level.turretSettings[ "mg_turret" ].hintEnter = &"MP_ENTER_REMOTE_TURRET";
level.turretSettings[ "mg_turret" ].hintPickUp = &"MP_HOLD_TO_CARRY";
level.turretSettings[ "mg_turret" ].hintRipOff = &"MP_TURRET_RIP_OFF";
level.turretSettings[ "mg_turret" ].hintDropTurret = &"MP_TURRET_DROP";
level.turretSettings[ "mg_turret" ].placeString = &"MP_TURRET_PLACE";
level.turretSettings[ "mg_turret" ].cannotPlaceString = &"MP_TURRET_CANNOT_PLACE";
level.turretSettings[ "mg_turret" ].laptopInfo = "killstreak_remote_turret_mp";
level._effect[ "sentry_explode_mp" ] = LoadFX( "vfx/explosion/remote_sentry_death" );
level._effect[ "sentry_smoke_mp" ] = LoadFX( "vfx/smoke/vehicle_sentrygun_damaged_smoke" );
level._effect[ "sentry_overheat_mp" ] = LoadFX( "vfx/distortion/sentrygun_overheat" );
level._effect[ "antenna_light_mp" ] = LoadFX( "vfx/lights/light_detonator_blink" );
level._effect[ "sentry_stunned_mp" ] = LoadFX( "vfx/sparks/emp_drone_damage" );
level._effect[ "sentry_laser_flash" ] = LoadFX( "vfx/fire/remote_sentry_laser_flash" );
level._effect[ "sentry_gone" ] = LoadFX( "vfx/explosion/remote_sentry_death_smoke" );
level._effect[ "sentry_rocket_muzzleflash_wv" ] = LoadFX( "vfx/muzzleflash/rpg_flash_wv" );
level._effect[ "sentry_rocket_muzzleflash_view" ] = LoadFX( "vfx/muzzleflash/rpg_flash_view" );
game["dialog"][ "ks_sentrygun_destroyed" ] = "ks_sentrygun_destroyed";
/#
SetDevDvarIfUninitialized( "scr_remote_turret_timeout", 0 );
SetDevDvarIfUninitialized( "scr_remote_turret_destroy", 0 );
#/
}
tryUseRemoteMGSentryTurret( lifeId, modules )
{
result = tryUseRemoteTurret( lifeId, "mg_turret", true, modules );
if( result )
{
self maps\mp\_matchdata::logKillstreakEvent( level.turretSettings[ "mg_turret" ].streakName, self.origin );
}
// we're done carrying for sure and sometimes this might not get reset
// this fixes a bug where you could be carrying and have it in a place where it won't plant, get killed, now you can't scroll through killstreaks
self.isCarrying = false;
return result;
}
tryUseRemoteMGTurret( lifeId, modules )
{
result = tryUseRemoteTurret( lifeId, "mg_turret", false, modules );
if( result )
{
self maps\mp\_matchdata::logKillstreakEvent( level.turretSettings[ "mg_turret" ].streakName, self.origin );
}
// we're done carrying for sure and sometimes this might not get reset
// this fixes a bug where you could be carrying and have it in a place where it won't plant, get killed, now you can't scroll through killstreaks
self.isCarrying = false;
return result;
}
takeKillstreakWeapons( turretType ) // self == owner
{
self maps\mp\killstreaks\_killstreaks::takeKillstreakWeaponIfNoDupe( level.turretSettings[ turretType ].laptopInfo );
}
tryUseRemoteTurret( lifeId, turretType, isSentry, modules )
{
if ( IsDefined( self.turret ) )
{
self IPrintLnBold( &"KILLSTREAKS_SENTRY_IN_USE" );
return false;
}
turret = createTurretForPlayer( turretType, self, isSentry, modules );
if ( isdefined ( level.isHorde ) && level.isHorde && self.killstreakIndexWeapon == 1 )
self.hordeClassTurret = turret;
self playerAddNotifyCommands();
// returning from this streak activation seems to strip this?
// manually removing and restoring
self removePerks();
self.carriedTurret = turret;
self setCarryingTurret( turret, true );
self.carriedTurret = undefined;
self thread restorePerks();
// if we failed to place the turret, it will have been deleted at this point
if ( isDefined( turret ) )
return true;
else
return false;
}
setupHeavyResistanceModel()
{
if ( self.heavyResistance )
self HidePart( "TAG_OPTIC_STANDARD" );
else
self HidePart( "TAG_OPTIC_RESISTANCE" );
}
setupRippableModel()
{
if ( !self.rippable )
self HidePart( "TAG_HANDLES" );
}
setModelTurretBaseOnly()
{
if ( IsDefined( self.model ) && self.model != "" )
self ShowAllParts();
if ( self.energyTurret )
self SetModel( "npc_sentry_energy_turret_empty_base" );
else if ( self.rocketTurret )
self SetModel( "npc_sentry_rocket_turret_empty_base" );
else
self SetModel( "npc_sentry_minigun_turret_empty_base" );
self setupHeavyResistanceModel();
self setupRippableModel();
}
setModelRemoteTurret()
{
if ( IsDefined( self.model ) && self.model != "" )
self ShowAllParts();
if ( self.energyTurret )
self SetModel( "npc_sentry_energy_turret_base" );
else if ( self.rocketTurret )
self SetModel( "npc_sentry_rocket_turret_base" );
else
self SetModel( "npc_sentry_minigun_turret_base" );
self setupHeavyResistanceModel();
self setupRippableModel();
}
setModelTurretPlacementGood()
{
if ( IsDefined( self.model ) && self.model != "" )
self ShowAllParts();
if ( self.energyTurret )
self SetModel( "npc_sentry_energy_turret_base_yellow_obj" );
else if ( self.rocketTurret )
self SetModel( "npc_sentry_rocket_turret_base_yellow_obj" );
else
self SetModel( "npc_sentry_minigun_turret_base_yellow_obj" );
self setupHeavyResistanceModel();
self setupRippableModel();
}
setModelTurretPlacementFailed()
{
if ( IsDefined( self.model ) && self.model != "" )
self ShowAllParts();
if ( self.energyTurret )
self SetModel( "npc_sentry_energy_turret_base_red_obj" );
else if ( self.rocketTurret )
self SetModel( "npc_sentry_rocket_turret_base_red_obj" );
else
self SetModel( "npc_sentry_minigun_turret_base_red_obj" );
self setupHeavyResistanceModel();
self setupRippableModel();
}
///////////////////////////////////////////////////
// CARRY FUNCTIONS
//////////////////////////////////////////////////
setCarryingTurret( turret, allowCancel ) // self == player
{
self endon ( "death" );
self endon ( "disconnect" );
level endon( "game_ended" );
if ( !isReallyAlive( self ) )
{
turret Delete();
return;
}
turret turret_setCarried( self );
killstreakWeapon = self getKillstreakWeapon( "remote_mg_sentry_turret" );
lastWeapon = self GetCurrentPrimaryWeapon();
if ( !maps\mp\gametypes\_weapons::isValidLastWeapon( lastWeapon ) || lastWeapon == "iw5_underwater_mp" )
lastWeapon = self getLastWeapon();
if ( !allowCancel )
{
self _giveWeapon( killstreakWeapon, 0 );
self SwitchToWeapon( killstreakWeapon );
self.water_last_weapon = killstreakWeapon;
self _disableWeaponSwitch();
}
for ( ;; )
{
result = waittill_any_return( "place_turret", "cancel_turret", "force_cancel_placement" );
if ( result == "cancel_turret" || result == "force_cancel_placement" )
{
if ( result == "cancel_turret" && !allowCancel )
continue;
turret turret_setCancelled();
if ( !allowCancel )
{
if ( !IsDefined( self.underWater ) )
self playerSwitchAwayFromHoldingTurret( lastWeapon, killstreakWeapon );
else
self.water_last_weapon = lastWeapon;
self _enableWeaponSwitch();
}
return false;
}
if ( IsDefined( turret ) )
{
if ( !turret.canBePlaced )
continue;
turret turret_setPlaced();
}
if ( !allowCancel )
{
if ( !IsDefined( self.underWater ) )
self playerSwitchAwayFromHoldingTurret( lastWeapon, killstreakWeapon );
else
self.water_last_weapon = lastWeapon;
self _enableWeaponSwitch();
}
return true;
}
}
playerSwitchAwayFromHoldingTurret( lastWeapon, killstreakWeapon )
{
self endon ( "death" );
self endon ( "disconnect" );
self switch_to_last_weapon( lastWeapon );
while ( self GetCurrentPrimaryWeapon() != lastWeapon )
waitframe();
self.water_last_weapon = lastWeapon;
self maps\mp\killstreaks\_killstreaks::takeKillstreakWeaponIfNoDupe( killstreakWeapon);
}
setRipOffTurretHead( turret ) // self == player
{
self endon ( "death" );
self endon ( "disconnect" );
assert( isReallyAlive( self ) );
assert( isPlayer( self ) );
turret SetCanDamage( false );
turret SetContents( 0 );
turret FreeEntitySentient();
turret.carriedBy = self;
self.isCarrying = false;
turret turret_setInactive();
turret setModelTurretBaseOnly();
turret notify( "carried" );
turret notify( "ripped" );
turret SetTurretMinimapVisible( false );
turret thread deleteAfterTime( 20 );
turret.remoteEnt makeGloballyUnusableByType();
if ( turret.energyTurret )
self thread maps\mp\killstreaks\_rippedturret::playerGiveTurretHead( "turretheadenergy_mp" );
else if ( turret.rocketTurret )
self thread maps\mp\killstreaks\_rippedturret::playerGiveTurretHead( "turretheadrocket_mp" );
else
self thread maps\mp\killstreaks\_rippedturret::playerGiveTurretHead( "turretheadmg_mp" );
turret PlaySound( "sentry_gun_detach" );
}
deleteAfterTime( time )
{
self endon( "death" );
level maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( time );
if( IsDefined( self ) )
{
deathSoundsAndFX();
self delete();
}
}
deathSoundsAndFX()
{
org = self GetTagOrigin( "TAG_AIM_PIVOT" );
PlayFX( getfx( "sentry_gone" ), org );
playSoundAtPos( org, "sentry_gun_self_destruct" );
}
removePerks()
{
if ( self _hasPerk( "specialty_explosivebullets" ) )
{
self.restorePerk = "specialty_explosivebullets";
self _unsetPerk( "specialty_explosivebullets" );
}
}
restorePerks()
{
if ( isDefined( self.restorePerk ) )
{
self givePerk( self.restorePerk, false );
self.restorePerk = undefined;
}
}
waitRestorePerks()
{
self endon( "death" );
self endon( "disconnect" );
level endon( "game_ended" );
wait( 0.05 );
self restorePerks();
}
turret_quickDeath( data )
{
self.quick_death = true;
self notify ( "death" );
}
turret_setPlaced() // self == turret
{
self setModelRemoteTurret();
self thread sentry_attackTargets();
// self thread sentry_guardian();
self SetSentryCarrier( undefined );
self SetCanDamage( true );
self.carriedBy forceUseHintOff();
self.carriedBy = undefined;
if( IsDefined( self.owner ) )
{
self.owner.isCarrying = false;
self make_entity_sentient_mp( self.owner.team );
}
// Moving platforms.
data = SpawnStruct();
data.linkParent = self.placementLinkEntity;
data.endonString = "carried";
data.deathOverrideCallback = ::turret_quickDeath;
self thread maps\mp\_movers::handle_moving_platforms( data );
// TODO: get sound for this
self playSound( "sentry_gun_deploy" );
self thread turret_setActive();
self notify ( "placed" );
}
turret_setCancelled()
{
self.carriedBy forceUseHintOff();
if( IsDefined( self.owner ) )
self.owner.isCarrying = false;
self delete();
}
turret_setCarried( carrier ) // self == turret
{
assert( isPlayer( carrier ) );
assertEx( carrier == self.owner, "turret_setCarried() specified carrier does not own this turret" );
self setModelTurretPlacementGood();
self SetCanDamage( false );
self SetSentryCarrier( carrier );
self SetContents( 0 );
self FreeEntitySentient();
self Unlink();
self.carriedBy = carrier;
carrier.isCarrying = true;
carrier thread updateTurretPlacement( self );
self thread turret_onCarrierDeath( carrier );
self thread turret_onCarrierDisconnect( carrier );
self thread turret_onCarrierChangedTeam( carrier );
self thread turret_onGameEnded();
self SetDefaultDropPitch( -89.0 );
self turret_setInactive();
self notify ( "carried" );
}
updateTurretPlacement( turret )
{
self endon ( "death" );
self endon ( "disconnect" );
level endon ( "game_ended" );
turret endon ( "placed" );
turret endon ( "death" );
turret.canBePlaced = true;
turret.placementLinkEntity = undefined;
lastCanPlaceTurret = -1; // force initial update
for( ;; )
{
placement = self canPlayerPlaceSentry( true );
turret.origin = placement[ "origin" ];
turret.angles = placement[ "angles" ];
turret.canBePlaced = self isOnGround() && placement[ "result" ] && ( abs(turret.origin[2]-self.origin[2]) < 10 && !turret isTouchingWater() );
if ( IsDefined( placement[ "entity" ] ) )
turret.placementLinkEntity = placement[ "entity" ];
else
turret.placementLinkEntity = undefined;
if ( turret.canBePlaced != lastCanPlaceTurret )
{
if ( turret.canBePlaced )
{
turret setModelTurretPlacementGood();
self ForceUseHintOn( level.turretSettings[ turret.turretType ].placeString );
}
else
{
turret setModelTurretPlacementFailed();
self ForceUseHintOn( level.turretSettings[ turret.turretType ].cannotPlaceString );
}
}
lastCanPlaceTurret = turret.canBePlaced;
wait ( 0.05 );
}
}
isTouchingWater()
{
if( !isDefined( level.water_triggers ) )
return false;
else
{
foreach( trig in level.water_triggers )
{
if( self IsTouching( trig ) )
return true;
}
}
return false;
}
turret_onCarrierDeath( carrier ) // self == turret
{
self endon ( "placed" );
self endon ( "death" );
self endon( "ripped" );
carrier waittill ( "death" );
if ( self.canBePlaced )
{
self turret_setPlaced();
}
else
{
if ( IsDefined( self.owner ) )
self.owner.isCarrying = false;
self delete();
}
}
turret_onCarrierDisconnect( carrier ) // self == turret
{
self endon ( "placed" );
self endon ( "death" );
self endon( "ripped" );
carrier waittill ( "disconnect" );
self delete();
}
turret_onCarrierChangedTeam( carrier ) // self == turret
{
self endon ( "placed" );
self endon ( "death" );
self endon( "ripped" );
carrier waittill_any( "joined_team", "joined_spectators" );
self delete();
}
turret_onGameEnded( carrier ) // self == turret
{
self endon ( "placed" );
self endon ( "death" );
self endon( "ripped" );
level waittill ( "game_ended" );
self delete();
}
///////////////////////////////////////////////////
// END CARRY FUNCTIONS
//////////////////////////////////////////////////
createTurretForPlayer( turretType, owner, isSentry, modules )
{
assertEx( IsDefined( owner ), "createTurretForPlayer() called without owner specified" );
turretWeapon = CONST_REMOTE_TURRET_MG_WEAPINFO;
if ( array_contains( modules, "sentry_energy_turret" ) )
turretWeapon = CONST_REMOTE_TURRET_BEAM_WEAPINFO;
turret = SpawnTurret( "misc_turret", owner.origin, turretWeapon );
turret.angles = owner.angles;
turret.owner = owner;
turret.health = level.turretSettings[ turretType ].maxHealth;
turret.maxHealth = level.turretSettings[ turretType ].maxHealth;
turret.turretType = turretType;
turret.stunned = false;
turret.directHacked = false;
turret.modules = modules;
turret.heavyResistance = array_contains( turret.modules, "sentry_heavy_resistance" );
turret.antiIntrusion = array_contains( turret.modules, "sentry_anti_intrusion" );
turret.rocketTurret = array_contains( turret.modules, "sentry_rocket_turret" );
turret.energyTurret = array_contains( turret.modules, "sentry_energy_turret" );
turret.rippable = array_contains( turret.modules, "sentry_rippable" );
turret.isSentry = array_contains( turret.modules, "sentry_guardian" );
turret.is360 = array_contains( turret.modules, "sentry_360" );
turret.weaponInfo = turretWeapon;
turret setModelRemoteTurret();
if ( turret.rocketTurret )
{
turret TurretFireDisable();
turret.weaponInfo = CONST_REMOTE_TURRET_ROCKET_WEAPINFO;
}
if ( turret.rocketTurret || turret.energyTurret )
turret TurretSetBarrelSpinEnabled( false );
//turret ThermalDrawEnable();
turret SetTurretModeChangeWait( true );
turret turret_setInactive();
turret SetSentryOwner( owner );
turret SetTurretMinimapVisible( true, turretType );
if ( turret.is360 )
{
turret SetLeftArc( CONST_REMOTE_TURRET_SENTRY_HORZ_ARC_FULL );
turret SetRightArc( CONST_REMOTE_TURRET_SENTRY_HORZ_ARC_FULL );
}
else
{
turret SetLeftArc( CONST_REMOTE_TURRET_SENTRY_HORZ_ARC );
turret SetRightArc( CONST_REMOTE_TURRET_SENTRY_HORZ_ARC );
}
turret SetTopArc( CONST_REMOTE_TURRET_SENTRY_TOP_ARC );
turret SetBottomArc( CONST_REMOTE_TURRET_SENTRY_BOTTOM_ARC );
turret SetDefaultDropPitch( -89.0 ); // setting this mainly prevents Turret_RestoreDefaultDropPitch() from running
turret thread turret_handleOwnerDisconnect();
owner.turret = turret;
turret.damageFade = 1.0;
turret thread turret_incrementDamageFade();
turret thread sentry_attackTargets();
return turret;
}
//turret_createBombSquadModel() // self == turret
//{
// bombSquadModel = spawn( "script_model", self.origin );
// bombSquadModel.angles = self.angles;
// bombSquadModel hide();
//
// team = undefined;
// if( level.teambased )
// team = level.otherTeam[ self.team ];
//
// bombSquadModel thread maps\mp\gametypes\_weapons::bombSquadVisibilityUpdater( team, self.owner );
// bombSquadModel SetModel( level.turretSettings[ self.turretType ].modelBombSquad );
// bombSquadModel linkTo( self );
// bombSquadModel SetContents( 0 );
//
// self waittill ( "death" );
//
// bombSquadModel delete();
//}
turret_setActive() // self == turret
{
self endon( "death" );
self.owner endon( "disconnect" );
self MakeUnusable();
self MakeTurretSolid();
if( !IsDefined( self.owner ) )
return;
owner = self.owner;
level.turrets[self GetEntityNumber()] = self;
// destroy any other remote turrets and put this one in the list
if( IsDefined( owner.remoteTurretList ) )
{
foreach( turret in owner.remoteTurretList )
{
turret notify( "death" );
}
}
owner.remoteTurretList = [];
owner.remoteTurretList[0] = self;
if ( !IsDefined( self.remoteEnt ) )
{
self.remoteEnt = Spawn( "script_model", self.origin + ( 0, 0, 1 ) );
self.remoteEnt SetModel( "tag_origin" );
self.remoteEnt.owner = owner;
self.remoteEnt makeGloballyUsableByType( "killstreakRemote", level.turretSettings[ self.turretType ].hintEnter, owner );
}
else
{
self.remoteEnt enableGloballyUsableByType();
}
// show a message to pick up the turret
owner.using_remote_turret = false;
owner.pickup_message_deleted = undefined;
owner.enter_message_deleted = undefined;
owner thread watchOwnerMessageOnDeath( self );
if ( level.teamBased )
{
self.team = owner.team;
self setTurretTeam( owner.team );
self maps\mp\_entityheadicons::setTeamHeadIcon( self.team, ( 0, 0, 65 ), "tag_origin" );
}
else
{
self maps\mp\_entityheadicons::setPlayerHeadIcon( self.owner, ( 0, 0, 65 ), "tag_origin" );
}
// spawn a trigger so we know if the owner is within range to pick it up
self.ownerTrigger = Spawn( "trigger_radius", self.origin + ( 0, 0, 1 ), 0, 32, 64 );
assert( IsDefined( self.ownerTrigger ) );
self.pickupEnt = Spawn( "script_model", self.origin + ( 0, 0, 1 ) );
self.pickupEnt SetModel( "tag_origin" );
self.pickupEnt.owner = owner;
owner thread player_handleTurretPickup( self );
owner thread player_handleTurretHints( self );
if ( self.rippable )
owner thread player_handleTurretRippable( self );
self thread watchEnterAndExit();
self thread turret_handleDeath();
self thread maps\mp\gametypes\_damage::setEntityDamageCallback( self.maxhealth, undefined, ::onTurretDeath, ::turret_ModifyDamage, true );
self thread turret_timeOut();
self thread turret_gameEnd();
self thread turret_watchEMP();
if ( !self.heavyResistance )
self thread turret_watchDisabled();
if ( self.antiIntrusion )
self thread turret_createAntiIntrusionKillcamEnt();
//self thread turret_createBombSquadModel();
self thread turret_handlePitch();
self thread turret_handleLaser();
// Target drones (low priority - the auto aim will attack any other enemy first)
if( IsDefined( level.isHorde ) && level.isHorde )
self thread turret_hordeShootDronesAndTurrets();
/# self thread turret_watchDestroy(); #/
}
turret_ModifyDamage( attacker, weapon, type, damage )
{
modifiedDamage = self maps\mp\gametypes\_damage::modifyDamage( attacker, weapon, type, damage );
if( IsDefined(self.owner) && (modifiedDamage > 0) )
{
self.owner PlayRumbleOnEntity( "damage_heavy" );
self.owner thread maps\mp\killstreaks\_aerial_utility::playerShowStreakStaticForDamage();
}
return modifiedDamage;
}
onTurretDeath( attacker, weapon, meansOfDeath, damage )
{
self notify( "death", attacker, meansOfDeath, weapon );
// assists for marking autosentry with orbitalsupport buddy.
if( IsDefined( self.tagMarkedBy ) && (self.tagMarkedBy != attacker) )
self.tagMarkedBy thread maps\mp\killstreaks\_marking_util::playerProcessTaggedAssist( self );
if( IsDefined( level.isHorde ) && level.isHorde )
{
if( !IsPlayer( attacker ) )
attacker = attacker.owner;
}
self maps\mp\gametypes\_damage::onKillstreakKilled( attacker, weapon, meansOfDeath, damage, "sentry_gun_destroyed", undefined, undefined, false );
self LaserOff();
//StopFXOnTag( getfx( "sentry_laser_flash" ), self, "tag_flash" );
}
playerShowTurretOverlay( turret ) // self == player
{
self endon( "disconnect" );
self endon( "playerHideTurretOverlay" );
wait 0.5;
omnvarValue = 0;
if( turret.weaponInfo == CONST_REMOTE_TURRET_MG_WEAPINFO )
{
omnvarValue = 1;
}
else if( turret.weaponInfo == CONST_REMOTE_TURRET_BEAM_WEAPINFO )
{
omnvarValue = 2;
}
else if ( turret.weaponInfo == CONST_REMOTE_TURRET_ROCKET_WEAPINFO )
{
omnvarValue = 3;
}
self SetClientOmnvar( "ui_sentry_ammo_type", omnvarValue );
self SetClientOmnvar( "ui_sentry_toggle", true );
self maps\mp\killstreaks\_aerial_utility::playerEnableStreakStatic();
}
playerHideTurretOverlay() // self == player
{
self notify( "playerHideTurretOverlay" );
self SetClientOmnvar( "ui_sentry_toggle", false );
self maps\mp\killstreaks\_aerial_utility::playerDisableStreakStatic();
}
playerWaittillWeaponSwitchOver( weapon )
{
self endon( "weapon_change" );
self waittill( "weapon_switch_started", newWeapon );
if ( weapon != newWeapon )
return;
while ( self IsSwitchingWeapon() )
waitframe();
}
startUsingRemoteTurret( leftArc, rightArc, topArc, bottomArc, isCoop ) // self == turret
{
if ( !IsDefined( isCoop ) )
isCoop = false;
owner = self.owner;
if ( !isCoop )
{
owner PlayerLinkTo( self.remoteEnt );
owner PlayerLinkedOffsetEnable();
owner _giveWeapon( level.turretSettings[ self.turretType ].laptopInfo );
owner SwitchToWeapon( level.turretSettings[ self.turretType ].laptopInfo );
owner DisableOffhandWeapons();
owner DisableOffhandSecondaryWeapons();
owner playerWaittillWeaponSwitchOver( level.turretSettings[ self.turretType ].laptopInfo );
newWeapon = owner GetCurrentWeapon();
if ( newWeapon != level.turretSettings[ self.turretType ].laptopInfo )
{
owner takeKillstreakWeapons( self.turretType );
owner EnableOffhandWeapons();
owner EnableOffhandSecondaryWeapons();
owner Unlink();
return false;
}
}
self.remoteControlled = true;
self sentry_stopAttackingTargets();
owner thread playerDoRideKillstreak( self, isCoop );
owner waittill( "initRideKillstreak_complete", success );
if ( !success )
return false;
owner playerSaveAngles();
owner setUsingRemote( self.turretType );
self notify( "remoteControlledUpdate" );
self.killCamStartTime = GetTime();
// with the way we do visionsets we need to wait for the clearRideIntro() is done before we set thermal
owner thread waitSetThermal( 1.0, self );
if ( getDvarInt( "camera_thirdPerson" ) )
owner setThirdPersonDOF( false );
owner PlayerLinkWeaponViewToDelta( self, "tag_player", 0, leftArc, rightArc, topArc, bottomArc, false );
owner PlayerLinkedSetViewZNear( false );
owner PlayerLinkedSetUseBaseAngleForViewClamp( true );
owner RemoteControlTurret( self );
if ( IsDefined( self.remoteEnt ) )
self.remoteEnt disableGloballyUsableByType();
self turret_clearPickupHints();
owner thread playerShowTurretOverlay( self );
if ( self.rocketTurret )
owner thread playerMonitorRocketTurretFire( self );
if( owner isJuggernaut() )
owner.juggernautOverlay.alpha = 0;
self thread playLoopSoundToPlayers( "sentry_gun_remote_view_bg", ( 0, 0, 60 ), [owner] );
return true;
}
waitSetThermal( delay, remoteTurret )
{
self endon( "disconnect" );
remoteTurret endon( "death" );
wait( delay );
// self VisionSetThermalForPlayer( game["thermal_vision"], 1.5 );
// self ThermalVisionOn();
self ThermalVisionFOFOverlayOn();
}
stopUsingRemoteTurret( showMessage ) // self == turret
{
if ( !IsDefined( self.remoteControlled ) || !self.remoteControlled )
return;
self.remoteControlled = undefined;
self notify( "remoteControlledUpdate" );
owner = self.owner;
owner takeKillstreakWeapons( self.turretType );
owner EnableOffhandWeapons();
owner EnableOffhandSecondaryWeapons();
self thread sentry_attackTargets();
// take the killstreak weapon
killstreakWeapon = getKillstreakWeapon( level.turretSettings[ self.turretType ].streakName );
owner maps\mp\killstreaks\_killstreaks::takeKillstreakWeaponIfNoDupe( killstreakWeapon );
lastWeapon = owner getLastWeapon();
if ( IsDefined( owner.underWater ) && owner.underWater )
lastWeapon = owner maps\mp\_utility::get_water_weapon();
owner switchToWeapon( lastWeapon );
if ( !IsDefined( showMessage ) )
showMessage = true;
owner Unlink();
if ( owner isUsingRemote() )
{
owner ThermalVisionFOFOverlayOff();
owner RemoteControlTurretOff( self );
if ( owner isUsingRemote() )
owner clearUsingRemote();
if ( getDvarInt( "camera_thirdPerson" ) )
owner setThirdPersonDOF( true );
}
if ( self turret_isStunned() )
owner StopShellShock();
if( !self turret_isStunned() && showMessage && ( !IsDefined( owner.using_remote_turret_when_died ) || !owner.using_remote_turret_when_died ) )
self.remoteEnt enableGloballyUsableByType();
if( owner isJuggernaut() )
owner.juggernautOverlay.alpha = 1;
owner playerHideTurretOverlay();
self notify( "stop soundsentry_gun_remote_view_bg" );
if ( IsDefined( owner.killCamEnt ) )
owner.killCamEnt delete();
self playerRestoreAngles();
self notify( "exit" );
}
playerDoRideKillstreak( turret, isCoop )
{
type = "remote_turret";
if ( isCoop )
type = "coop";
result = self maps\mp\killstreaks\_killstreaks::initRideKillstreak( type );
if ( !IsDefined( self ) )
return;
if ( result != "success" || turret turret_isStunned() || IsDefined( turret.dead ) )
{
if ( result != "disconnect" || turret turret_isStunned() || IsDefined( turret.dead ) )
{
self thread playerRemoteKillstreakShowHud();
turret stopUsingRemoteTurret( !isCoop );
}
self notify( "initRideKillstreak_complete", false );
return;
}
self notify( "initRideKillstreak_complete", true );
}
watchOwnerMessageOnDeath( turret ) // self == owner
{
self endon( "disconnect" );
turret endon( "death" );
turret endon( "ripped" );
// we need to reset the lower message when the owner dies, this way the respawn message shows
self.using_remote_turret_when_died = false;
while( true )
{
if( IsAlive( self ) )
self waittill( "death" );
turret.remoteEnt disableGloballyUsableByType();
turret turret_clearPickupHints();
if( self.using_remote_turret )
self.using_remote_turret_when_died = true;
else
self.using_remote_turret_when_died = false;
self waittill( "spawned_player" );
self.using_remote_turret_when_died = false;
turret.remoteEnt enableGloballyUsableByType();
}
}
watchEnterAndExit() // self == turret
{
self endon( "death" );
self endon( "carried" );
level endon( "game_ended" );
owner = self.owner;
thread watchEnterAndExitInput();
while( true )
{
if ( owner player_shouldDisableRemoteEnter( self ) )
{
if ( !IsDefined( owner.enter_message_deleted ) || !owner.enter_message_deleted )
{
owner.enter_message_deleted = true;
self.remoteEnt disableGloballyUsableByType();
}
}
else
{
if( IsDefined( owner.enter_message_deleted ) && owner.enter_message_deleted )
{
self.remoteEnt enableGloballyUsableByType();
owner.enter_message_deleted = false;
}
}
waitframe();
}
}
player_shouldDisableRemoteEnter( turret )
{
currentWeapon = self GetCurrentWeapon();
return ( turret turret_isStunned() ||
self player_isUsingKillstreak( turret ) ||
( IsDefined( self.underWater ) && self.underWater ) ||
self.using_remote_turret ||
currentWeapon == "none" ||
self IsTouching( turret.ownerTrigger ) ||
( self IsLinked() && !self.using_remote_turret ) ||
( IsDefined( self.empGrenaded ) && self.empGrenaded )
);
}
watchEnterAndExitInput() // self == turret
{
self endon( "death" );
self endon( "carried" );
level endon( "game_ended" );
owner = self.owner;
topArc = CONST_REMOTE_TURRET_SENTRY_TOP_ARC;
bottomArc = CONST_REMOTE_TURRET_SENTRY_BOTTOM_ARC;
leftArc = CONST_REMOTE_TURRET_SENTRY_HORZ_ARC;
rightArc = CONST_REMOTE_TURRET_SENTRY_HORZ_ARC;
if ( self.is360 )
{
leftArc = CONST_REMOTE_TURRET_SENTRY_HORZ_ARC_FULL;
rightArc = CONST_REMOTE_TURRET_SENTRY_HORZ_ARC_FULL;
}
while( true )
{
self waittillRemoteTurretUsedReturn();
owner.using_remote_turret = true;
success = self startUsingRemoteTurret( leftArc, rightArc, topArc, bottomArc );
if ( success )
{
wait 2.0;
self waittillRemoteTurretLeaveReturn();
owner.using_remote_turret = false;
self stopUsingRemoteTurret();
wait 2.0; // these waits are to keep you from going in and out by holding X too long
}
else
{
owner.using_remote_turret = false;
}
}
}
waittillRemoteTurretUsedReturn() // self == turret
{
owner = self.owner;
while ( true )
{
self.remoteEnt waittill( "trigger" );
if ( owner playerCanUseTurret( self ) )
return;
}
}
waittillRemoteTurretLeaveReturn() //self == turret
{
owner = self.owner;
while ( true )
{
useHold = 0;
while ( owner UseButtonPressed() )
{
useHold += 0.05;
if ( useHold > 1 && owner playerCanUseTurret( self ) )
return;
waitframe();
}
waitframe();
}
}
playerCanUseTurret( turret )
{
if ( self FragButtonPressed() || IsDefined( self.throwingGrenade ) || self SecondaryOffhandButtonPressed() )
return false;
if ( self IsUsingTurret() || !self IsOnGround() )
return false;
if ( IsDefined( turret.ownerTrigger ) && self IsTouching( turret.ownerTrigger ) )
return false;
if ( IsDefined( self.empGrenaded ) && self.empGrenaded )
return false;
if( IsDefined( self.isCarrying ) && self.isCarrying )
return false;
if( IsDefined( self.isCapturingCrate ) && self.isCapturingCrate )
return false;
if( !IsAlive( self ) )
return false;
if( !self.using_remote_turret && self isUsingRemote() )
return false;
// bail out, if the owner is already linked to another entity
if ( self IsLinked() && !self.using_remote_turret )
return false;
return true;
}
player_isUsingKillstreak( turret )
{
currentWeapon = self GetCurrentWeapon();
return ( self isJuggernaut() || self isUsingRemote() || self isInRemoteTransition() ||
( isKillstreakWeapon( currentWeapon ) &&
currentWeapon != "killstreak_remote_turret_mp" &&
currentWeapon != CONST_REMOTE_TURRET_MG_WEAPINFO &&
currentWeapon != CONST_REMOTE_TURRET_BEAM_WEAPINFO &&
currentWeapon != level.turretSettings[ turret.turretType ].laptopInfo &&
currentWeapon != "none" &&
currentWeapon != "turretheadmg_mp" &&
currentWeapon != "turretheadenergy_mp" &&
currentWeapon != "turretheadrocket_mp" )
);
}
player_handleTurretHints( turret ) // self == owner( player )
{
self endon( "disconnect" );
level endon( "game_ended" );
turret endon( "death" );
if( IsBot(self) )
return;
if( !IsDefined( turret.ownerTrigger ) || !IsDefined( turret.pickupEnt ) )
return;
turret.pickupEnt endon( "death" );
while( true )
{
if( self player_shouldClearTurretPickupHints( turret ) )
{
if( !IsDefined( self.pickup_message_deleted ) || !self.pickup_message_deleted )
{
self.pickup_message_deleted = true;
turret turret_clearPickupHints();
}
}
else
{
if( IsDefined( self.pickup_message_deleted ) && self.pickup_message_deleted )
{
turret thread turret_setPickupHints();
self.pickup_message_deleted = false;
}
}
waitframe();
}
}
player_shouldClearTurretPickupHints( turret )
{
currentWeapon = self GetCurrentWeapon();
return ( turret turret_isStunned() ||
self player_isUsingKillstreak( turret ) ||
( IsDefined( self.underWater ) && self.underWater ) ||
self.using_remote_turret ||
currentWeapon == "none" ||
!self IsTouching( turret.ownerTrigger ) ||
!isReallyAlive( self ) ||
!self IsOnGround() ||
IsDefined( turret.carriedBy )
);
}
player_handleTurretPickup( turret ) // self == owner( player )
{
self endon( "disconnect" );
level endon( "game_ended" );
turret endon( "death" );
// defensive bot hack because they keep picking it up right after they place it
if( IsBot(self) )
return;
if( !IsDefined( turret.ownerTrigger ) || !IsDefined( turret.pickupEnt ) )
return;
turret.pickupEnt endon( "death" );
buttonTime = 0;
while( true )
{
// need to make sure we can't pick up the remote turret while already in a killstreak (like ac130)
if ( player_isUsingKillstreak( turret ) )
{
waitframe();
continue;
}
if( !self IsTouching( turret.ownerTrigger ) )
{
waitframe();
continue;
}
if( isReallyAlive( self ) &&
self IsTouching( turret.ownerTrigger ) &&
!IsDefined( turret.carriedBy ) &&
self IsOnGround() )
{
// entering and exiting the remote turret
timeUsed = 0;
while ( self UseButtonPressed() )
{
if( !isReallyAlive( self ) )
break;
if ( !self IsTouching( turret.ownerTrigger ) )
break;
if ( self FragButtonPressed() || self SecondaryOffhandButtonPressed() || IsDefined( self.throwingGrenade ) )
break;
if ( self IsLinked() || !self IsOnGround() || self IsUsingTurret() || self isUsingRemote() )
break;
if ( IsDefined( self.isCarrying ) && self.isCarrying )
break;
if ( IsDefined( self.isCapturingCrate ) && self.isCapturingCrate )
break;
if ( IsDefined( self.empGrenaded ) && self.empGrenaded )
break;
if( IsDefined( self.using_remote_turret ) && self.using_remote_turret )
break;
if ( IsDefined( self.ball_carried ) )
break;
timeUsed += 0.05;
if( timeUsed > 0.75 )
{
turret PlaySound( "sentry_gun_pick_up" );
turret SetMode( level.turretSettings[ turret.turretType ].sentryModeOff );
turret sentry_stopAttackingTargets();
self thread setCarryingTurret( turret, false );
turret turret_clearPickupHints();
self.remoteTurretList = undefined;
turret.pickupEnt Delete();
turret.ownerTrigger delete();
return;
}
waitframe();
}
}
waitframe();
}
}
player_handleTurretRippable( turret ) // self == owner (player)
{
self endon( "disconnect" );
level endon( "game_ended" );
turret endon( "death" );
// defensive bot hack because they keep picking it up right after they place it
if( IsBot(self) )
return;
if( !IsDefined( turret.ownerTrigger ) || !IsDefined( turret.pickupEnt ) )
return;
turret.pickupEnt endon( "death" );
buttonTime = 0;
while( true )
{
// need to make sure we can't pick up the remote turret while already in a killstreak (like ac130)
if( player_isUsingKillstreak( turret ) )
{
wait( 0.05 );
continue;
}
if ( self maps\mp\killstreaks\_rippedturret::playerHasTurretHeadWeapon() )
{
waitframe();
continue;
}
// since we can pick this back up, if we're not in the trigger clear the message
if( !self IsTouching( turret.ownerTrigger ) )
{
wait( 0.05 );
continue;
}
if( isReallyAlive( self ) &&
self IsTouching( turret.ownerTrigger ) &&
!IsDefined( turret.carriedBy ) &&
self IsOnGround() )
{
if ( self UseButtonPressed() )
{
if( IsDefined( self.using_remote_turret ) && self.using_remote_turret )
continue;
buttonTime = 0;
while ( self UseButtonPressed() )
{
buttonTime += 0.05;
wait( 0.05 );
}
if ( buttonTime >= 0.5 )
continue;
buttonTime = 0;
while ( !self UseButtonPressed() && buttonTime < 0.5 )
{
buttonTime += 0.05;
wait( 0.05 );
}
if ( buttonTime >= 0.5 )
continue;
if ( !isReallyAlive( self ) )
continue;
if( IsDefined( self.using_remote_turret ) && self.using_remote_turret )
continue;
if ( IsDefined( self.ball_carried ) )
continue;
turret SetMode( level.turretSettings[ turret.turretType ].sentryModeOff );
turret sentry_stopAttackingTargets();
self thread setRipOffTurretHead( turret );
turret turret_clearPickupHints();
self.remoteTurretList = undefined;
turret.pickupEnt Delete();
turret.ownerTrigger Delete();
return;
}
}
wait( 0.05 );
}
}
turret_blinky_light() // self == turret
{
self endon( "death" );
self endon( "carried" );
while ( true )
{
//PlayLoopedFX( getfx( "antenna_light_mp" ), 1.0, self GetTagOrigin( "tag_fx" ) );
PlayFXOnTag( getfx( "antenna_light_mp" ), self, "tag_fx" );
wait( 1.0 );
StopFXOnTag( getfx( "antenna_light_mp" ), self, "tag_fx" );
}
}
turret_setInactive() // self == turret
{
self SetMode( level.turretSettings[ self.turretType ].sentryModeOff );
self sentry_stopAttackingTargets();
if ( level.teamBased )
self maps\mp\_entityheadicons::setTeamHeadIcon( "none", ( 0, 0, 0 ) );
else if ( isDefined( self.owner ) )
self maps\mp\_entityheadicons::setPlayerHeadIcon( undefined, ( 0, 0, 0 ) );
if( !IsDefined( self.owner ) )
return;
owner = self.owner;
level.turrets[self GetEntityNumber()] = undefined;
if ( IsDefined( self.remoteEnt ) )
self.remoteEnt disableGloballyUsableByType();
if( IsDefined( owner.using_remote_turret ) && owner.using_remote_turret )
{
owner ThermalVisionOff();
owner ThermalVisionFOFOverlayOff();
owner RemoteControlTurretOff( self );
owner unlink();
lastWeapon = owner getLastWeapon();
if ( IsDefined( owner.underWater ) && owner.underWater )
lastWeapon = owner maps\mp\_utility::get_water_weapon();
owner switchToWeapon( lastWeapon );
if ( owner isUsingRemote() )
owner clearUsingRemote();
if ( getDvarInt( "camera_thirdPerson" ) )
owner setThirdPersonDOF( true );
// just in case the turret is killed before you can get in it, the initRideKillstreak() does _disableUsability() and we unfortunately kill the thread on death
if( IsDefined( owner.disabledUsability ) && owner.disabledUsability )
{
// if we go to last stand while using the remote turret, we don't want usability turned back on
if ( IsDefined( level.isHorde ) && level.isHorde && IsDefined( owner.lastStand ) && owner.lastStand )
{
// make sure we get rid of the addition to disabledUsability from the call in initRideKillstreak without allowing enable to be called
if (owner.disabledUsability > 1)
owner.disabledUsability--;
}
else
owner _enableUsability();
}
owner takeKillstreakWeapons( self.turretType );
// turn juggernaut overlay back on
if( owner isJuggernaut() )
owner.juggernautOverlay.alpha = 1;
}
}
turret_handleOwnerDisconnect() // self == turret
{
self endon ( "death" );
level endon ( "game_ended" );
self notify ( "turret_handleOwner" );
self endon ( "turret_handleOwner" );
self.owner waittill_any( "disconnect", "joined_team", "joined_spectators" );
self notify( "death" );
}
turret_gameEnd()
{
self endon( "death" );
level waittill( "game_ended" );
if ( isDefined( self.owner ) )
{
self.owner playerHideTurretOverlay();
}
}
turret_timeOut() // self == turret
{
self endon( "death" );
level endon ( "game_ended" );
if ( IsDefined( self.timeoutStarted ) )
return;
self.timeoutStarted = true;
lifeSpan = level.turretSettings[ self.turretType ].timeOut;
self.owner SetClientOmnvar( "ui_sentry_lifespan", lifeSpan );
/#
if ( GetDvar( "scr_remote_turret_timeout", "0" ) != "0" )
lifeSpan = GetDvarFloat( "scr_remote_turret_timeout" );
#/
while ( lifeSpan )
{
wait ( 1.0 );
maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
if ( !IsDefined( self.carriedBy ) )
lifeSpan = max( 0, lifeSpan - 1.0 );
}
if ( isDefined( self.owner ) )
{
self.owner playerHideTurretOverlay();
}
self notify ( "death" );
}
turret_handleDeath() // self == turret
{
self endon( "carried" );
entNum = self GetEntityNumber();
self maps\mp\killstreaks\_autosentry::addToTurretList( entNum );
self waittill ( "death", attacker, meansOfDeath, weapon );
self ClearTargetEntity();
self turret_deathSounds( attacker, weapon );
self.damagecallback = undefined;
self SetCanDamage( false );
self SetDamageCallbackOn( false );
self FreeEntitySentient();
self LaserOff();
self.dead = true;
self maps\mp\killstreaks\_autosentry::removeFromTurretList( entNum );
// this handles cases of deletion
if ( !isDefined( self ) )
return;
self turret_clearPickupHints();
self turret_setInactive();
self setDefaultDropPitch( 35 );
self SetSentryOwner( undefined );
self SetTurretMinimapVisible( false );
if ( IsDefined( self.remoteEnt ) )
self.remoteEnt makeGloballyUnusableByType();
owner = self.owner;
if( IsDefined( owner ) )
{
self stopUsingRemoteTurret();
owner.using_remote_turret = false;
owner.turret = undefined;
owner restorePerks();
owner playerRemoveNotifyCommands();
if( owner GetCurrentWeapon() == "none" )
{
lastWeapon = owner getLastWeapon();
if ( IsDefined( owner.underWater ) && owner.underWater )
lastWeapon = owner maps\mp\_utility::get_water_weapon();
owner switchToWeapon( lastWeapon );
}
}
// TODO: get sound
self playSound( "sentry_gun_death_exp" );
if ( !IsDefined( self.quick_death ) || !self.quick_death )
{
PlayFXOnTag( getFx( "sentry_explode_mp" ), self, "TAG_AIM_PIVOT" );
wait ( 1.5 );
//self playSound( "sentry_explode_smoke" );
for ( smokeTime = 8; smokeTime > 0; smokeTime -= 0.4 )
{
PlayFXOnTag( getFx( "sentry_smoke_mp" ), self, "tag_aim" );
wait ( 0.4 );
}
}
self notify( "deleting" );
if( IsDefined( self.target_ent ) )
self.target_ent delete();
if( IsDefined( self.ownerTrigger ) )
self.ownerTrigger delete();
if ( IsDefined( self.pickupEnt ) )
self.pickupEnt Delete();
if ( IsDefined( self.remoteEnt ) )
self.remoteEnt Delete();
if ( IsDefined( self.rocketMuzzleFlashEnt ) )
self.rocketMuzzleFlashEnt Delete();
deathSoundsAndFX();
self delete();
}
turret_deathSounds( attacker, weapon )
{
if ( IsDefined( self.owner ) && IsDefined( attacker ) && self.owner != attacker )
self.owner thread leaderDialogOnPlayer( "ks_sentrygun_destroyed", undefined, undefined, self.origin );
}
turret_incrementDamageFade() // self == turret
{
self endon( "death" );
level endon( "game_ended" );
// this is for the ui
damaged = false;
while( true )
{
if( self.damageFade < 1.0 )
{
//self.owner SetClientOmnvar( "remoteTurretDamageFade", self.damageFade );
self.damageFade += 0.1;
damaged = true;
}
else
{
if( damaged )
{
self.damageFade = 1.0;
//self.owner SetClientOmnvar( "remoteTurretDamageFade", self.damageFade );
damaged = false;
}
}
wait( 0.1 );
}
}
turret_setPickupHints() // self == turret
{
self notify( "turretClearPickupHints" );
self endon( "turretClearPickupHints" );
Assert( IsDefined( self.pickupEnt ) );
self.pickupEnt MakeUsable();
self.pickupEnt SetHintString( level.turretSettings[ self.turretType ].hintPickUp );
self.pickupEnt SetCursorHint( "HINT_NOICON" );
self.pickupEnt SetHintStringVisibleOnlyToOwner( true );
if ( self.rippable )
{
while ( true )
{
hintStringSet = false;
if ( !hintStringSet && IsDefined( self.owner ) && !(self.owner maps\mp\killstreaks\_rippedturret::playerHasTurretHeadWeapon()) )
{
self.pickupEnt SetSecondaryHintString( level.turretSettings[ self.turretType ].hintRipOff );
hintStringSet = true;
}
else if ( hintStringSet )
{
self.pickupEnt SetSecondaryHintString( "" );
hintStringSet = false;
}
waitframe();
}
}
}
turret_clearPickupHints() // self == turret
{
self notify( "turretClearPickupHints" );
if ( !IsDefined( self.pickupEnt ) )
return;
self.pickupEnt MakeUnusable();
self.pickupEnt SetHintString( "" );
self.pickupEnt SetSecondaryHintString( "" );
self.pickupEnt SetHintStringVisibleOnlyToOwner( false );
}
/* ============================
Sentry Logic Functions
============================ */
// TODO: if we keep the remote turret we should try to merge this with _autosentry.gsc
sentry_stopAttackingTargets()
{
self notify( "sentry_stop" );
}
sentry_attackTargets( shootFunc )
{
if ( !self.isSentry )
return;
self endon( "sentry_stop" );
self endon( "death" );
level endon( "game_ended" );
self notify( "sentry_start" );
self.momentum = 0;
self.heatLevel = 0;
self.overheated = false;
if ( !self.rocketTurret )
self thread sentry_heatMonitor( CONST_REMOTE_TURRET_MG_WEAPINFO, CONST_REMOTE_TURRET_SENTRY_OVERHEATTIME, CONST_REMOTE_TURRET_SENTRY_COOLDOWNTIME );
self SetMode( level.turretSettings[ "mg_turret" ].sentryModeOn );
self.fireReadyTime = GetTime();
for ( ;; )
{
self waittill_either( "turretstatechange", "cooled" );
if ( self isFiringTurret() )
self thread turret_startShooting( shootFunc );
else
self thread turret_stopShooting();
}
}
turret_startShooting( shootFunc )
{
if ( self.rocketTurret )
{
self thread turret_fireRockets();
}
else
{
self thread sentry_burstFireStart( shootFunc );
}
}
turret_stopShooting()
{
if ( self.rocketTurret )
{
self thread turret_stopRockets();
}
else
{
self sentry_spinDown();
self thread sentry_burstFireStop();
}
}
playerMonitorRocketTurretFire( turret ) // self = player
{
self endon ( "disconnect" );
level endon ( "game_ended" );
turret endon ( "death" );
turret endon ( "sentry_start" );
turret endon ( "exit" );
turret.fireReadyTime = GetTime();
while ( true )
{
self waittill( "turret_fire" );
maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
if( IsDefined( level.hostMigrationTimer ) )
continue;
if ( GetTime() >= turret.fireReadyTime )
turret thread turret_fireRocket( false );
}
}
sentry_targetLockSound()
{
self endon ( "death" );
self endon( "sentry_stop" );
self playSound( "sentry_gun_beep" );
wait ( 0.1 );
self playSound( "sentry_gun_beep" );
wait ( 0.1 );
self playSound( "sentry_gun_beep" );
}
sentry_spinUp()
{
self endon( "death" );
self endon( "sentry_stop" );
self thread sentry_targetLockSound();
while ( self.momentum < CONST_REMOTE_TURRET_SENTRY_SPINUPTIME )
{
self.momentum += 0.1;
wait ( 0.1 );
}
}
sentry_spinDown()
{
self.momentum = 0;
}
sentry_burstFireStart( shootFunc )
{
self endon( "death" );
self endon( "sentry_stop" );
self endon( "stop_shooting" );
level endon( "game_ended" );
self sentry_spinUp();
fireTime = weaponFireTime( CONST_REMOTE_TURRET_MG_WEAPINFO );
minShots = CONST_REMOTE_TURRET_SENTRY_BURSTMIN;
maxShots = CONST_REMOTE_TURRET_SENTRY_BURSTMAX;
minPause = CONST_REMOTE_TURRET_SENTRY_PAUSEMIN;
maxPause = CONST_REMOTE_TURRET_SENTRY_PAUSEMAX;
for ( ;; )
{
numShots = randomIntRange( minShots, maxShots + 1 );
for ( i = 0; i < numShots && !self.overheated; i++ )
{
if ( IsDefined( shootFunc ) )
self [[ shootFunc ]]();
else
self shootTurret();
self.heatLevel += fireTime;
wait ( fireTime );
}
wait ( randomFloatRange( minPause, maxPause ) );
}
}
turret_stopRockets()
{
self notify( "stop_shooting" );
}
turret_fireRockets()
{
self endon( "death" );
self endon( "sentry_stop" );
self endon( "stop_shooting" );
level endon( "game_ended" );
self.fireReadyTime = GetTime();
while ( true )
{
if ( GetTime() >= self.fireReadyTime )
self thread turret_fireRocket( true );
waitframe();
}
}
turret_fireRocket( isAutoTurret )
{
level endon( "game_ended" );
start = self GetTagOrigin( "tag_flash" );
dir = AnglesToForward( self GetTagAngles( "tag_flash" ) );
end = start + ( dir * 10000 );
start = start + ( dir * 10 );
trace = BulletTrace( start, end, true );
entHit = trace["entity"];
hitEnemyPlayer = 0;
if( IsDefined( level.isHorde ) && level.isHorde )
hitEnemyPlayer = ( IsDefined( entHit ) && IsDefined( entHit.team ) && ( self.team != entHit.team ) );
else
hitEnemyPlayer = ( IsDefined( entHit ) && IsPlayer( entHit ) && !IsAlliedSentient(self.owner, entHit) );
if ( !hitEnemyPlayer && isAutoTurret )
return;
self playRumbleOnEntity( "damage_heavy" );
rocket = MagicBullet( CONST_REMOTE_TURRET_ROCKET_WEAPINFO, start, end, self.owner );
if ( isAutoTurret )
reloadTime = 2500;
else
reloadTime = 1250;
self.fireReadyTime = GetTime() + reloadTime;
if ( !isAutoTurret )
{
PlayFXOnTagForClients( getfx( "sentry_rocket_muzzleflash_view" ), self, "tag_flash", self.owner );
if ( !IsDefined( self.rocketMuzzleFlashEnt ) )
self.rocketMuzzleFlashEnt = spawnMuzzleFlashEnt( self, "tag_flash", self.owner );
PlayFXOnTag( getfx( "sentry_rocket_muzzleflash_wv" ), self.rocketMuzzleFlashEnt, "tag_origin" );
}
else
{
PlayFXOnTag( getfx( "sentry_rocket_muzzleflash_wv" ), self, "tag_flash" );
}
}
spawnMuzzleFlashEnt( parent, tagname, hideFromPlayer )
{
muzzleEnt = Spawn( "script_model", ( 0, 0, 0 ) );
muzzleEnt SetModel( "tag_origin" );
muzzleEnt LinkTo( parent, tagname, ( 0, 0, 0 ), ( 0, 0, 0 ) );
muzzleEnt Hide();
foreach ( player in level.players )
{
if ( player != hideFromPlayer )
muzzleEnt ShowToPlayer( player );
}
thread onPlayerConnectMuzzleFlashEnt( muzzleEnt );
return muzzleEnt;
}
onPlayerConnectMuzzleFlashEnt( muzzleEnt )
{
muzzleEnt endon( "death" );
while ( true )
{
level waittill( "connected", player );
self thread onPlayerSpawnedMuzzleFlashEnt( muzzleEnt, player );
}
}
onPlayerSpawnedMuzzleFlashEnt( muzzleEnt, player )
{
muzzleEnt endon( "death" );
player endon( "disconnect" );
player waittill( "spawned_player" );
muzzleEnt ShowToPlayer( player );
}
sentry_burstFireStop()
{
self notify( "stop_shooting" );
}
sentry_heatMonitor( weapInfo, overheatTime, overheatCoolDown )
{
self endon ( "death" );
self endon( "sentry_stop" );
fireTime = weaponFireTime( weapInfo );
lastHeatLevel = 0;
lastFxTime = 0;
for ( ;; )
{
if ( self.heatLevel != lastHeatLevel )
wait ( fireTime );
else
self.heatLevel = max( 0, self.heatLevel - 0.05 );
if ( self.heatLevel > overheatTime )
{
self.overheated = true;
self TurretSetBarrelSpinEnabled( false );
self thread playHeatFX();
switch( self.turretType )
{
case "mg_turret":
playFxOnTag( getFx( "sentry_smoke_mp" ), self, "tag_aim" );
//self thread PlaySmokeFX();
break;
default:
break;
}
while ( self.heatLevel )
{
self.heatLevel = max( 0, self.heatLevel - overheatCoolDown );
wait ( 0.1 );
}
self TurretSetBarrelSpinEnabled( true );
self.overheated = false;
self notify( "not_overheated" );
}
lastHeatLevel = self.heatLevel;
wait ( 0.05 );
}
}
playHeatFX()
{
self endon( "death" );
self endon( "sentry_stop" );
self endon( "not_overheated" );
level endon ( "game_ended" );
self notify( "playing_heat_fx" );
self endon( "playing_heat_fx" );
for( ;; )
{
playFxOnTag( getFx( "sentry_overheat_mp" ), self, "tag_flash" );
wait( CONST_REMOTE_TURRET_SENTRY_FXTIME );
}
}
turret_watchEMP()
{
self endon( "carried" );
self endon( "death" );
level endon( "game_ended" );
self waittill( "emp_damage" );
self notify( "death" );
}
turret_watchDisabled()
{
self endon( "carried" );
self endon( "death" );
level endon( "game_ended" );
while( true )
{
// this handles any flash or concussion damage
self waittill( "concussed" );
duration = 4;
PlayFXOnTag( getfx( "sentry_stunned_mp" ), self, "tag_aim" );
self notify( "stunned" );
self.stunned = true;
if ( self.isSentry )
{
self SetDefaultDropPitch( 35 );
self SetMode( level.turretSettings[ self.turretType ].sentryModeOff );
}
if ( IsDefined( self.remoteControlled ) && self.remoteControlled )
self stopUsingRemoteTurret();
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( duration );
StopFXOnTag( getfx( "sentry_stunned_mp" ), self, "tag_aim" );
if ( self.isSentry )
{
self SetDefaultDropPitch( 0 );
self SetMode( level.turretSettings[ self.turretType ].sentryModeOn );
}
self.stunned = false;
self notify( "stunnedDone" );
}
}
turret_isStunned()
{
return ( IsDefined( self.stunned ) && self.stunned );
}
turret_createAntiIntrusionKillcamEnt()
{
ent = Spawn( "script_model", self.origin + ( 0, 0, 60 ) );
self.killCamEnt = ent;
self waittill_any( "death", "carried" );
wait 3;
ent Delete();
}
turret_handleLaser()
{
self endon( "death" );
if ( !self.isSentry )
return;
self LaserOn( "mp_sentry_turret" );
//PlayFXOnTag( getfx( "sentry_laser_flash" ), self, "tag_flash" );
self waittill( "carried" );
self LaserOff();
//StopFXOnTag( getfx( "sentry_laser_flash" ), self, "tag_flash" );
}
turret_handlePitch()
{
self endon( "carried" );
self endon( "death" );
if ( self.isSentry )
{
self SetDefaultDropPitch( 0 );
return;
}
else
{
self SetDefaultDropPitch( 35 );
}
while ( true )
{
self waittill( "remoteControlledUpdate" );
if ( IsDefined( self.remoteControlled ) && self.remoteControlled )
self SetDefaultDropPitch( 0 );
else
self SetDefaultDropPitch( 35 );
}
}
// Target the closest drone or turret
// The aiming function will automatic ignore this target if a regular enemy is nearby.
turret_hordeShootDronesAndTurrets() // self == turret
{
self endon( "death" );
CONST_TURRET_MIDHEIGHT = (0,0,40);
while( true )
{
minDistance = 5000000; // A target within 2,236 units
closestDrone = undefined;
foreach( drone in level.flying_attack_drones )
{
dist = DistanceSquared( self.origin, drone.origin );
if( dist < minDistance )
{
if( SightTracePassed( self.origin + CONST_TURRET_MIDHEIGHT, drone.origin, false, undefined ) )
{
minDistance = dist;
closestDrone = drone;
}
}
}
closestSentry = undefined;
foreach( sentry in level.hordeSentryArray )
{
dist = DistanceSquared( self.origin, sentry.origin );
if( dist < minDistance )
{
if( SightTracePassed( self.origin + CONST_TURRET_MIDHEIGHT, sentry.origin + CONST_TURRET_MIDHEIGHT, false, undefined ) )
{
minDistance = dist;
closestSentry = sentry;
}
}
}
// If there's a sentry, that means it's closer
if( IsDefined( closestSentry ) )
self SetTargetEntity( closestSentry, CONST_TURRET_MIDHEIGHT); // Don't aim at the origin that's on the ground...aim above it
else if( IsDefined( closestDrone ) )
self SetTargetEntity( closestDrone );
waitframe;
}
}
playerAddNotifyCommands()
{
self NotifyOnPlayerCommand( "turret_fire" , "+attack" );
self NotifyOnPlayerCommand( "turret_fire" , "+attack_akimbo_accessible" );
self NotifyOnPlayerCommand( "place_turret", "+attack" );
self NotifyOnPlayerCommand( "place_turret", "+attack_akimbo_accessible" ); // support accessibility control scheme
if ( !IsBot( self ) )
{
self NotifyOnPlayerCommand( "cancel_turret", "weapnext" );
self NotifyOnPlayerCommand( "cancel_turret", "+actionslot 4" );
if ( !level.console )
{
self NotifyOnPlayerCommand( "cancel_turret", "+actionslot 5" );
self NotifyOnPlayerCommand( "cancel_turret", "+actionslot 6" );
self NotifyOnPlayerCommand( "cancel_turret", "+actionslot 7" );
self NotifyOnPlayerCommand( "cancel_turret", "+actionslot 8" );
}
}
}
playerRemoveNotifyCommands()
{
self NotifyOnPlayerCommandRemove( "turret_fire", "+attack" );
self NotifyOnPlayerCommandRemove( "turret_fire" , "+attack_akimbo_accessible" );
self NotifyOnPlayerCommandRemove( "place_turret", "+attack" );
self NotifyOnPlayerCommandRemove( "place_turret", "+attack_akimbo_accessible" ); // support accessibility control scheme
if ( !IsBot( self ) )
{
self NotifyOnPlayerCommandRemove( "cancel_turret", "+actionslot 4" );
if ( !level.console )
{
self NotifyOnPlayerCommandRemove( "cancel_turret", "weapnext" );
self NotifyOnPlayerCommandRemove( "cancel_turret", "+actionslot 5" );
self NotifyOnPlayerCommandRemove( "cancel_turret", "+actionslot 6" );
self NotifyOnPlayerCommandRemove( "cancel_turret", "+actionslot 7" );
self NotifyOnPlayerCommandRemove( "cancel_turret", "+actionslot 8" );
}
}
}
/#
turret_watchDestroy()
{
self endon( "death" );
self endon( "carried" );
level endon( "game_ended" );
while ( true )
{
if ( GetDvarInt( "scr_remote_turret_destroy", 0 ) != 0 )
break;
waitframe();
}
SetDvar( "scr_remote_turret_destroy", 0 );
self notify( "death" );
}
#/