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

1764 lines
52 KiB
Plaintext

#include maps\mp\_utility;
#include common_scripts\utility;
#include maps\mp\_audio;
LASER_DROP_PITCH_OFFLINE = -10;
LASER_DROP_PITCH_ONLINE = 5;
//TODO: write this for teambased/multi team based and FFA
init()
{
initLaserFX();
initLaserSound();
initLaser();
initLaserEnts();
level.killstreakFuncs["mp_laser2"] = ::tryUseMPLaser;
level.mapKillStreak = "mp_laser2";
level.mapKillstreakPickupString = &"MP_LASER2_MAP_KILLSTREAK_PICKUP";
level.mapKillStreakDamageFeedbackSound = ::handleDamageFeedbackSound;
level.killstreak_laser_fxmode = 0;
level.mapCustomBotKillstreakFunc = ::setupBotsForMapKillstreak;
}
setupBotsForMapKillstreak()
{
level thread maps\mp\bots\_bots_ks::bot_register_killstreak_func( "mp_laser2", maps\mp\bots\_bots_ks::bot_killstreak_simple_use );
}
initLaserFX()
{
level.laser_fx["beahm"] = LoadFX( "vfx/muzzleflash/laser_wv_mp_laser" );
level.laser_fx["beahm_smoke"] = LoadFX( "vfx/muzzleflash/laser_wv_mp_laser_smoke" );
level.laser_fx["laser_field1"] = LoadFX( "vfx/map/mp_laser2/laser_core_lvl1" );
level.laser_fx["laser_field1_cheap"] = LoadFX( "vfx/map/mp_laser2/laser_core_lvl1_cheap" );
level.laser_fx["laser_field2"] = LoadFX( "vfx/map/mp_laser2/laser_core_lvl2" );
level.laser_fx["laser_field2_cheap"] = LoadFX( "vfx/map/mp_laser2/laser_core_lvl2_cheap" );
level.laser_fx["laser_field3"] = LoadFX( "vfx/map/mp_laser2/laser_core_lvl3" );
//level.laser_fx["laser_field1_up"] = LoadFX( "vfx/map/mp_laser2/laser_core_up_lvl1" );
level.laser_fx["laser_field2_up"] = LoadFX( "vfx/map/mp_laser2/laser_core_up_lvl2" );
level.laser_fx["laser_field3_up"] = LoadFX( "vfx/map/mp_laser2/laser_core_up_lvl3" );
level.laser_fx["laser_field1_up_slow"] = LoadFX( "vfx/map/mp_laser2/laser_core_up_slow_lvl1" );
//level.laser_fx["laser_field1_down"] = LoadFX( "vfx/map/mp_laser2/laser_core_down_lvl1" );
level.laser_fx["laser_field2_down"] = LoadFX( "vfx/map/mp_laser2/laser_core_down_lvl2" );
level.laser_fx["laser_field3_down"] = LoadFX( "vfx/map/mp_laser2/laser_core_down_lvl3" );
level.laser_fx["laser_field1_down_slow"] = LoadFX( "vfx/map/mp_laser2/laser_core_down_slow_lvl1" );
//level.laser_fx["laser_field2_down_slow"] = LoadFX( "vfx/map/mp_laser2/laser_core_down_slow_lvl2" );
//level.laser_fx["laser_field3_down_slow"] = LoadFX( "vfx/map/mp_laser2/laser_core_down_slow_lvl3" );
level.laser_fx["laser_charge1"] = LoadFX( "vfx/map/mp_laser2/laser_energy_fire_lvl1" );
level.laser_fx["laser_beam_done1"] = LoadFX( "vfx/map/mp_laser2/laser_energy_beam_done_lvl1" );
level.laser_fx["hatch_light"] = Loadfx( "vfx/lights/mp_laser2/light_lasercore_glow" );
level.laser_fx["hatch_light_close"] = Loadfx( "vfx/lights/mp_laser2/light_lasercore_glow_close" );
level.laser_fx["laser_steam"] = LoadFX( "vfx/map/mp_laser2/laser_core_steam" );
level.laser_fx["laser_movement_sparks"] = LoadFX( "vfx/sparks/machinery_scrape_sparks_looping" );
}
initLaserSound()
{
// Dialog.
game["dialog"]["laser_deactivated"] = "laser_deactivated";
game["dialog"]["laser_offline"] = "laser_offline";
game["dialog"]["laser_strength"] = "laser_strength";
}
initLaser()
{
laser = spawnStruct();
laser.health = 999999; // keep it from dying anywhere in code
laser.maxHealth = 1000; // this is the health we'll check
laser.burstMin = 20;
laser.burstMax = 120;
laser.pauseMin = 0.15;
laser.pauseMax = 0.35;
laser.sentryModeOn = "sentry_manual";
laser.sentryModeOff = "sentry_offline";
laser.timeOut = 45.0;
laser.spinupTime = 0.05;
laser.overheatTime = 8.0;
laser.cooldownTime = 0.1;
laser.fxTime = 0.3;
laser.streakName = "sky_laser_turret";
laser.weaponInfo = "sky_laser_mp";
laser.useweaponinfo = "killstreak_laser2_mp";
laser.modelBase = "mp_sky_laser_turret_head";
laser.modelDestroyed = "mp_sky_laser_turret_head";
laser.headIcon = true;
laser.teamSplash = "used_mp_laser2";
laser.shouldSplash = false;
laser.voDestroyed = "laser_deactivated";
laser.voOffline = "laser_offline";
laser.vopower = "laser_strength";
laser.coreShellshock = "default";
if ( !IsDefined( level.sentrySettings ) )
level.sentrySettings = [];
level.sentrySettings[ "sky_laser_turret" ] = laser;
level.killstreakWieldWeapons["mp_laser2_core"] = "mp_laser2";
}
initLaserEnts()
{
sentryType = "sky_laser_turret";
PreCacheItem( "mp_laser2_core" );
PreCacheModel( "lsr_laser_button_01_obj" );
laserEnt = GetEnt( "lasergun", "targetname");
assertEx( isDefined( laserEnt ), "ent with targetname of lasergun is undefined" );
laserEnt hide();
laserEnt laserlightfill();
laserEnt.FxEnts = laserEnt laser_initFxEnts();
laserEnt.offSwitch = laserEnt laser_initOffSwitch();
laserEnt.lifter = GetEnt( "laser_animated_prop", "targetname");
laserEnt.lifter.parts = getentarray( "lsr_animated_parts", "targetname" );
laserEnt.lifter laserlightfill();
assertEx( isDefined( laserEnt ), "ent with targetname of laser_lifter is undefined" );
laserEnt.moveOrgs = laserEnt.lifter laser_initMoveOrgs();
laserEnt.lifter.animUp = "lsr_laser_turret_up";
laserEnt.lifter.animDown = "lsr_laser_turret_down";
laserEnt.lifter.animIdleDown = "lsr_laser_turret_idle_down";
laserEnt.lifter.animIdleUp = "lsr_laser_turret_idle_up";
laserEnt.GeneratorHat = GetEnt( "generator_hat", "targetname");
assertEx( isDefined( laserEnt ), "ent with targetname of generator_hat is undefined" );
laserEnt.GeneratorHat.anim_up = "laser_button_on";
laserEnt.GeneratorHat.anim_down = "laser_button_off";
laserEnt.GeneratorHat.anim_idle_up = "laser_button_idle_on";
laserEnt.GeneratorHat.anim_idle_down = "laser_button_idle_off";
laserEnt.coreDamageTrig = getent( "trig_lasercore_damage", "targetname" );
assertEx( isDefined( laserEnt.coreDamageTrig ), "ent with targetname of trig_lasercore_damage is undefined" );
laserEnt.coreDeathTrig = getent( "trig_lasercore_death", "targetname" );
assertEx( isDefined( laserEnt.coreDeathTrig ), "ent with targetname of trig_lasercore_death is undefined" );
laserEnt.firingDamageTrig = getent( "trig_laserfire_damage", "targetname" );
assertEx( isDefined( laserEnt.firingDamageTrig ), "ent with targetname of trig_laserfire_damage is undefined" );
laserEnt.ownerList = [];
laserEnt.collision = SpawnStruct();
laserEnt.collision.col_base = GetEnt( "laser_collision_base", "targetname");
laserEnt.collision.col_head = GetEnt( "laser_collision_head", "targetname");
//laserEnt.collision.col_gun = GetEnt( "laser_collision_gun", "targetname");
laserEnt.flaps_top = getentarray( "lsr_flap_top", "targetname" );
laserEnt.attachments = getentarray( "lsr_geo_attach", "targetname" );
laserEnt.lifter LinkGeoToTurret(laserEnt, true);
flaps_bottom = getentarray( "lsr_flap_bottom", "targetname" );
laserEnt.flaps = array_combine( laserEnt.flaps_top, flaps_bottom);
foreach( flap in laserEnt.flaps )
{
flap.col_base = getent( flap.target, "targetname" );
if( isDefined( flap.col_base ) )
flap.col_base.unresolved_collision_kill = true;
flap.col_T = getent( flap.col_base.target, "targetname" );
if( isDefined( flap.col_T ) )
flap.col_T.unresolved_collision_kill = true;
flap.col_base LinkToSynchronizedParent( flap, "mainFlapBase" );
flap.col_T LinkToSynchronizedParent( flap, "mainFlap_T" );
}
laserEnt.flap_animClose = "lsr_energy_hatch_close";
laserEnt.flap_animIdleClose = "lsr_energy_hatch_close_idle";
laserEnt.flap_animOpen = "lsr_energy_hatch_open";
laserEnt.flap_animIdleOpen = "lsr_energy_hatch_open_idle";
level.sentryGun = laserEnt;
level.sentryGun laser_initSentry( sentryType );
}
LinkGeoToTurret(laser, ShouldLink)
{
if(ShouldLink == false)
{
laser.collision.col_base unlink();
laser.collision.col_head unlink();
//laser.collision.col_gun unlink();
foreach( flap in laser.flaps_top )
flap unlink();
foreach( attachment in laser.attachments )
attachment unlink();
foreach( part in laser.lifter.parts )
part unlink();
}
else if(ShouldLink == true)
{
laser.collision.col_base linkto(self, "tag_origin");
laser.collision.col_head linkto(self, "tag_aim_pivot");
//laser.collision.col_gun linkto(self, "cannon_f");
foreach( flap in laser.flaps_top )
flap linktoSynchronizedParent( self );
foreach( attachment in laser.attachments )
attachment linktoSynchronizedParent( self );
foreach( part in laser.lifter.parts )
part linktoSynchronizedParent( self );
}
}
laser_initMoveOrgs()
{
locEnt_top = getStruct( "laser_lifter_top_loc", "targetname" );
locEnt_bottom = getStruct( "laser_lifter_bottom_loc", "targetname" );
assertEx( isDefined( locEnt_top ), "struct with targetname of laser_lifter_top_loc is undefined" );
assertEx( isDefined( locEnt_bottom ), "struct with targetname of laser_lifter_bottom_loc is undefined" );
locEnt_dist = locEnt_top.origin - locEnt_bottom.origin;
moveOrgs = [];
moveOrgs["bottom"] = self.origin;
moveOrgs["top"] = self.origin + locEnt_dist;
return moveOrgs;
}
laser_initFxEnts()
{
charge_up = undefined;
coreStruct = getstruct( "laser_core_fx_pos", "targetname" );
assertEx( isDefined( coreStruct ), "struct with targetname of laser_core_fx_pos is undefined" );
charge_up = coreStruct spawn_tag_origin();
charge_up show();
FxEnts = [];
FxEnts["charge_up"] = charge_up;
return FxEnts;
}
laser_initOffSwitch()
{
trigger = GetEnt( "laser_use_trig", "targetname" );
offSwitchEnt = GetEnt( "laser_switch", "targetname" );
assertEx( isDefined( offSwitchEnt ), "ent with targetname of laser_switch is not defined" );
assertEx( isDefined( trigger ), "ent with targetname of laser_use_trig is not defined" );
offSwitch = [];
switch_obj = spawn( "script_model", offSwitchEnt.origin );
switch_obj.angles = offSwitchEnt.angles;
switch_obj setmodel( "lsr_laser_button_01_obj" );
switch_obj hide();
visuals = [switch_obj];
use_zone = maps\mp\gametypes\_gameobjects::createUseObject( "none", trigger, visuals, (0,0,64) );
use_zone maps\mp\gametypes\_gameobjects::allowUse( "none" );
use_zone maps\mp\gametypes\_gameobjects::setUseTime( 5 );
use_zone maps\mp\gametypes\_gameobjects::setUseText( &"MP_LASERTURRET_HACKING" );
use_zone maps\mp\gametypes\_gameobjects::setUseHintText( &"MP_LASERTURRET_HACK" );
use_zone.onBeginUse = ::laser_offSwitch_onBeginUse;
use_zone.onEndUse = ::laser_offSwitch_onEndUse;
use_zone.onUse = ::laser_offSwitch_onUsePlantObject;
use_zone.onCantUse = ::laser_offSwitch_onCantUse;
use_zone.useWeapon = "search_dstry_bomb_mp";
offSwitch = [];
offSwitch["switch_obj"] = switch_obj;
offSwitch["use_zone"] = use_zone;
return offSwitch;
}
laser_offSwitch_onBeginUse( player )
{
// IPrintLnBold("using switch");
}
laser_offSwitch_onEndUse( team, player, result )
{
// IPrintLnBold("end using switch");
}
laser_offSwitch_onUsePlantObject( player )
{
level.sentryGun endon ( "death" );
level endon ( "game_ended" );
// IPrintLnBold("planting on switch");
if ( IsDefined( level.sentryGun.owner ) )
{
level.sentryGun.owner thread leaderDialogOnPlayer( level.sentrySettings[ level.sentryGun.sentryType ].voDestroyed );
}
player playSound( "mp_bomb_plant" );
damage = level.sentrySettings[ "sky_laser_turret" ].maxhealth;
level.sentryGun notify
( "damage", //"damage"
damage, //damage
player, //attacker
( 0, 0, 0 ), //direction_vec
( 0, 0, 0 ), //point
"MOD_UNKNOWN", //meansOfDeath
undefined, //modelName
undefined, //tagName
undefined, //partName
undefined, //iDFlags
"none" );//weapon
}
laser_offSwitch_onCantUse( player )
{
// IPrintLnBold("switch cant use");
}
laser_initSentry( sentryType ) // self == sentry, turret, sam
{
self.sentryType = sentryType;
self setModel( level.sentrySettings[ self.sentryType ].modelBase );
self.shouldSplash = true; // we only want to splash on the first placement
self setCanDamage( false );
self makeTurretInoperable();
self SetLeftArc( 180 );
self SetRightArc( 180 );
self SetTopArc( 80 );
self SetDefaultDropPitch( LASER_DROP_PITCH_OFFLINE ); // setting this mainly prevents Turret_RestoreDefaultDropPitch() from running
self.laser_on = false;
self.lifter ScriptModelPlayAnimDeltaMotion( self.lifter.animIdleDown );
foreach( part in self.lifter.parts )
{
part ScriptModelPlayAnimDeltaMotion( self.lifter.animIdleDown );
}
// needs a kill cam ent
killCamEnt = Spawn( "script_model", self GetTagOrigin( "tag_laser" ) );
killCamEnt LinkTo( self );
self.killCamEnt = killCamEnt;
self.killCamEnt SetScriptMoverKillCam( "explosive" );
//HINT: this is different than other autosentries since the turret isn't placed it should be solid all the time
self maps\mp\killstreaks\_autosentry::sentry_makeSolid();
self setTurretModeChangeWait( true );
self laser_setInactive();
//TODO: don't need to do fakedeath. Do real death but modify maps/_autosentry::sentry_handleDeath function to not delete the turret
self thread laser_handleDamage();
self thread laser_handleFakeDeath();
self thread maps\mp\killstreaks\_autosentry::sentry_beepSounds();
//self makeUsable();
}
laser_handleDamage()
{
self endon( "death" );
level endon( "game_ended" );
while ( true )
{
self.health = level.sentrySettings[ self.sentryType ].health;
self.maxHealth = level.sentrySettings[ self.sentryType ].maxHealth;
self.damageTaken = 0; // how much damage has it taken
self waittill( "damage", damage, attacker, direction_vec, point, meansOfDeath, modelName, tagName, partName, iDFlags, weapon );
// don't allow people to destroy equipment on their team if FF is off
if ( !maps\mp\gametypes\_weapons::friendlyFireCheck( self.owner, attacker ) )
continue;
if ( IsDefined( iDFlags ) && ( iDFlags & level.iDFLAGS_PENETRATION ) )
self.wasDamagedFromBulletPenetration = true;
// up the damage for airstrikes, stealth bombs, and bomb sites
switch( weapon )
{
case "artillery_mp":
case "stealth_bomb_mp":
damage *= 4;
break;
case "bomb_site_mp":
damage = self.maxHealth;
break;
}
if ( meansOfDeath == "MOD_MELEE" )
self.damageTaken += self.maxHealth;
modifiedDamage = damage;
if ( isPlayer( attacker ) )
{
attacker maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "sentry" );
if ( attacker _hasPerk( "specialty_armorpiercing" ) )
{
modifiedDamage = damage * level.armorPiercingMod;
}
}
// in case we are shooting from a remote position, like being in the osprey gunner shooting this
if( IsDefined( attacker.owner ) && IsPlayer( attacker.owner ) )
{
attacker.owner maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "sentry" );
}
if( IsDefined( weapon ) )
{
shortWeapon = maps\mp\_utility::strip_suffix( weapon, "_lefthand" );
switch( shortWeapon )
{
case "ac130_105mm_mp":
case "ac130_40mm_mp":
case "stinger_mp":
case "remotemissile_projectile_mp":
self.largeProjectileDamage = true;
modifiedDamage = self.maxHealth + 1;
break;
case "artillery_mp":
case "stealth_bomb_mp":
self.largeProjectileDamage = false;
modifiedDamage += ( damage * 4 );
break;
case "bomb_site_mp":
case "emp_grenade_mp":
case "emp_grenade_var_mp":
self.largeProjectileDamage = false;
modifiedDamage = self.maxHealth + 1;
break;
}
maps\mp\killstreaks\_killstreaks::killstreakHit( attacker, weapon, self );
}
self.damageTaken += modifiedDamage;
if ( self.damageTaken >= self.maxHealth )
{
thread maps\mp\gametypes\_missions::vehicleKilled( self.owner, self, undefined, attacker, damage, meansOfDeath, weapon );
if ( isPlayer( attacker ) && (!IsDefined(self.owner) || attacker != self.owner) )
{
level thread maps\mp\gametypes\_rank::awardGameEvent( "kill", attacker, weapon, undefined, meansOfDeath );
}
if ( IsDefined( self.owner ) )
self.owner thread leaderDialogOnPlayer( level.sentrySettings[ self.sentryType ].voDestroyed, undefined, undefined, self.origin );
self notify( "fakedeath" );
}
}
}
laser_handleFakeDeath()
{
self endon( "death" );
level endon( "game_ended" );
for ( ;; )
{
self waittill( "fakedeath" );
self laser_setInactive();
self.ownerList = [];
self SetSentryOwner( undefined );
self.samTargetEnt = undefined;
if ( level.teamBased )
{
self.team = undefined;
}
if( IsDefined( self.ownerTrigger ) )
self.ownerTrigger delete();
self playSound( "sentry_explode" );
if ( IsDefined( self.inUseBy ) )//TODO: I don't think I'm using this. take it out.
{
//playFxOnTag( common_scripts\utility::getFx( "sentry_explode_mp" ), self, "tag_origin" );
//playFxOnTag( common_scripts\utility::getFx( "sentry_smoke_mp" ), self, "tag_aim" );
self.inUseBy.turret_overheat_bar maps\mp\gametypes\_hud_util::destroyElem();
self.inUseBy maps\mp\killstreaks\_autosentry::restorePerks();
self.inUseBy maps\mp\killstreaks\_autosentry::restoreWeapons();
self notify( "deleting" );
wait ( 1.0 );
//StopFXOnTag( common_scripts\utility::getFx( "sentry_explode_mp" ), self, "tag_origin" );
//StopFXOnTag( common_scripts\utility::getFx( "sentry_smoke_mp" ), self, "tag_aim" );
}
else
{
//playFxOnTag( common_scripts\utility::getFx( "sentry_explode_mp" ), self, "tag_aim" );
wait ( 1.5 );
self playSound( "sentry_explode_smoke" );
for ( smokeTime = 8; smokeTime > 0; smokeTime -= 0.4 )
{
//playFxOnTag( common_scripts\utility::getFx( "sentry_smoke_mp" ), self, "tag_aim" );
wait ( 0.4 );
}
}
}
}
/*
=============
///ScriptDocBegin
"Name: tryUseMPLaser( <lifeId> )"
"Summary: function called when a player tries to use the mp_laser2 map-based killstreak"
"Module: Entity"
"CallOn: a player"
"MandatoryArg: <lifeId>: "
"Example: level.killstreakFuncs["mp_laser2"] = ::tryUseMPLaser;"
"SPMP: MP"
///ScriptDocEnd
=============
*/
tryUseMPLaser( lifeId, modules )
{
if ( !self playerCanUseLaser() )
{
self iPrintLnBold( &"MP_LASERTURRET_ENEMY" );
return false;
}
if ( self isUsingRemote() )
{
return false;
}
if ( self isAirDenied() )
{
return false;
}
if ( self isEMPed() )
{
return false;
}
if( isDefined( level.sentryGun.locked ) && level.sentryGun.locked == true )
{
self iPrintLnBold( &"MP_LASERTURRET_BUSY" );
return false;
}
self maps\mp\_matchdata::logKillstreakEvent( "mp_laser2", self.origin );
level.sentryGun laser_setOwner( self );
mode = level.sentryGun getMode();
if( ( !isDefined( level.sentryGun.mode ) || level.sentryGun.mode == "off" ) && ( !isDefined( level.sentryGun.moving ) || level.sentryGun.moving == false ) )//TODO: check if we still need to do this .mode hack should be able to just use GetMode()
{
self laser_setPlaceSentry( level.sentryGun, level.sentryGun.sentryType );
}
return true;
}
playerCanUseLaser()
{
assertEx( isPlayer( self ), "playerCanUseLaser() called on non-player entity type: " + self.classname );
assertEx( isDefined( level.sentryGun ), "playerCanUseLaser() called without a laser entity" );
if( !isDefined( level.sentryGun ) )
return false;
if ( level.teamBased )
{
//check to see if other team owns it
if( isDefined( level.sentryGun.team ) && level.sentryGun.team != self.team )
return false;
}
else
{
//check if the laser is already owned by someone... anyone
foreach( owner in level.sentryGun.ownerList )
{
if( (isDefined( owner ) && owner != self ) )
return false;
}
}
return true;
}
laser_setOwner( owner )
{
assertEx( IsDefined( owner ), "laser_setOwner() called without owner specified" );
assertEx( isPlayer( owner ), "laser_setOwner() called on non-player entity type: " + owner.classname );
self.owner = owner;
self.ownerList = array_add( self.ownerList, owner );
self SetSentryOwner( self.owner );
self SetTurretMinimapVisible( true, "sam_turret" );
if ( level.teamBased )
{
self.team = self.owner.team;
self setTurretTeam( self.team );
}
self thread laser_handleOwnerDisconnect( owner );
self thread player_sentry_timeOut( owner );
if (self.ownerList.size > 1)
self thread playLaserContainmentSwap();
}
laser_handleOwnerDisconnect( owner )
{
self endon ( "death" );
self endon ( "fakedeath" );
level endon ( "game_ended" );
owner common_scripts\utility::waittill_any( "disconnect", "joined_team", "joined_spectators" );
self.ownerList = array_remove( self.ownerList, owner );
if( owner != self.owner )
self thread stopLaserContainmentSwap();
else if( owner == self.owner )
{
next_owner = getNextPlayerInOwnerQueue( self.ownerList );
if( isDefined( next_owner ) )
{
self laser_setOwner( next_owner );
}
else
{
self notify( "fakedeath" );
}
}
}
array_removeFirstInQueue( ents, remover )
{
indexents = [];
indexent = undefined;
for( i=0; i<ents.size; i++ )
{
if( ents[i] == remover )
{
indexents[ indexents.size ] = i;
}
}
indexent = indexents[ indexents.size - 1 ];
newents = [];
for( i=0; i<ents.size; i++ )
{
if ( i != indexent )
newents[ newents.size ] = ents[i];
}
return newents;
}
getNextPlayerInOwnerQueue( array )
{
if( !isDefined( array ) )
{
return undefined;
}
array = array_reverse( array );
foreach( ent in array )
{
if( isDefined( ent ) && isPlayer( ent ) && isAlive( ent ) )
{
return ent;
}
}
return undefined; //array is defined but empty of players
}
laser_setPlaceSentry( sentryGun, sentryType )
{
self endon ( "death" );
self endon ( "disconnect" );
player = self;
if ( ! player maps\mp\_utility::validateUseStreak() )
return false;
player.last_sentry = sentryType;
sentryGun laser_setPlaced( self );
return true;
}
laser_setPlaced( player )
{
//TODO: don't need this since the model is the same //self setModel( level.sentrySettings[ self.sentryType ].modelBase );
// failsafe check, for some reason this could be manual and setSentryCarried doesn't like that
if( self GetMode() == "manual" )
{
self SetMode( level.sentrySettings[ self.sentryType ].sentryModeOff );
self.mode = "off";//HACK: checking the mode wasn't consistent so had to add my own var to check against
}
self setSentryCarrier( undefined );
self setCanDamage( true );
//TODO: do we need to define this? is it false by default? will killstreaks work correctly without this?
if( IsDefined( self.owner ) )
self.owner.isCarrying = false;
self thread laser_setActive( player );
self thread playLaserCoreEvent();
self thread playLaserContainmentStart();
self playSound( "sentry_gun_plant" );
self notify ( "placed" );
}
playLaserCoreEvent()
{
wait 2.0;
PlayFXOnTag( level.laser_fx[ "laser_steam" ], self.FxEnts["charge_up"], "tag_origin" );
}
StopLaserCoreEvent()
{
wait 4;
StopFXOnTag( level.laser_fx[ "laser_steam" ], self.FxEnts["charge_up"], "tag_origin" );
//turn on exploder for off state fx
//level delayThread( 3.5, common_scripts\_exploder::activate_clientside_exploder, 200);
level noself_delayCall( 3.5, ::ActivatePersistentClientExploder, 200 );
}
StartLaserLights()
{
laserLgtEnts = GetScriptableArray( "laser_light", "targetname" );
foreach ( laserLgtEnt in laserLgtEnts )
{
laserLgtEnt SetScriptablePartState("lsr_part_a", "laser_on_a");
}
laserLgtEnts = GetScriptableArray( "laser_light_b", "targetname" );
foreach ( laserLgtEnt in laserLgtEnts )
{
laserLgtEnt SetScriptablePartState("lsr_part_b", "laser_on_b");
}
laserLgtEnts = GetScriptableArray( "laser_point_lights", "targetname" );
foreach ( laserLgtEnt in laserLgtEnts )
{
laserLgtEnt SetScriptablePartState("static_part1", "warning");
}
}
StopLaserLights()
{
laserLgtEnts = GetScriptableArray( "laser_light", "targetname" );
foreach ( laserLgtEnt in laserLgtEnts )
{
laserLgtEnt SetScriptablePartState("lsr_part_a", "laser_off_a");
}
laserLgtEnts = GetScriptableArray( "laser_light_b", "targetname" );
foreach ( laserLgtEnt in laserLgtEnts )
{
laserLgtEnt SetScriptablePartState("lsr_part_b", "laser_off_b");
}
laserLgtEnts = GetScriptableArray( "laser_point_lights", "targetname" );
foreach ( laserLgtEnt in laserLgtEnts )
{
laserLgtEnt SetScriptablePartState("static_part1", "healthy");
}
}
playLaserContainmentStart()
{
level.killstreak_laser_fxmode = 1;
//turn off exploder for off state fx
stopclientexploder(200);
PlayFXOnTag( level.laser_fx[ "hatch_light" ], self.FxEnts["charge_up"], "tag_origin" );
PlayFXOnTag( level.laser_fx[ "hatch_light" ], level.sentryGun.lifter, "tag_origin" );
wait 5.33; //time for laser platform to start animating up
StartLaserLights();
PlayFXOnTag( level.laser_fx[ "laser_field1_up_slow" ], self.FxEnts["charge_up"], "tag_origin" );
wait 1.0; //time for laser field up slow effect to play
PlayFXOnTag( level.laser_fx[ "laser_field1" ], self.FxEnts["charge_up"], "tag_origin" );
//turn on exploder for lighting laser cannon
//level delayThread( 3.5, common_scripts\_exploder::activate_clientside_exploder, 150);
}
playLaserContainmentSwap()
{
if( !isDefined( self.ownerList ) || self.ownerList.size < 1 )
return;
level.killstreak_laser_fxmode = self.ownerList.size;
fxId = level.killstreak_laser_fxmode;
switch( fxId )
{
case 0:
break;
case 1:
/*PlayFXOnTag( level.laser_fx[ "laser_field1_up" ], self.FxEnts["charge_up"], "tag_origin" );
wait 1.0;
PlayFXOnTag( level.laser_fx[ "laser_field1" ], self.FxEnts["charge_up"], "tag_origin" );*/
break;
case 2:
StopFXOnTag( level.laser_fx[ "laser_field1" ], self.FxEnts["charge_up"], "tag_origin" );
PlayFXOnTag( level.laser_fx[ "laser_field1_cheap" ], self.FxEnts["charge_up"], "tag_origin" );
PlayFXOnTag( level.laser_fx[ "laser_field2_up" ], self.FxEnts["charge_up"], "tag_origin" );
wait 1.0;
laserOrngLgtEnts = GetScriptableArray( "laser_light", "targetname" );
foreach ( laserOrngLgtEnt in laserOrngLgtEnts )
{
laserOrngLgtEnt SetScriptablePartState("lsr_part_a", "laser_on_02_a");
}
laserLgtEnts = GetScriptableArray( "laser_light_b", "targetname" );
foreach ( laserLgtEnt in laserLgtEnts )
{
laserLgtEnt SetScriptablePartState("lsr_part_b", "laser_on_02_b");
}
PlayFXOnTag( level.laser_fx[ "laser_field2" ], self.FxEnts["charge_up"], "tag_origin" );
break;
case 3:
StopFXOnTag( level.laser_fx[ "laser_field2" ], self.FxEnts["charge_up"], "tag_origin" );
PlayFXOnTag( level.laser_fx[ "laser_field2_cheap" ], self.FxEnts["charge_up"], "tag_origin" );
PlayFXOnTag( level.laser_fx[ "laser_field3_up" ], self.FxEnts["charge_up"], "tag_origin" );
wait 1.0;
laserYellowLgtEnts = GetScriptableArray( "laser_light", "targetname" );
foreach ( laserYellowLgtEnt in laserYellowLgtEnts )
{
laserYellowLgtEnt SetScriptablePartState("lsr_part_a", "laser_on_03_a");
}
laserLgtEnts = GetScriptableArray( "laser_light_b", "targetname" );
foreach ( laserLgtEnt in laserLgtEnts )
{
laserLgtEnt SetScriptablePartState("lsr_part_b", "laser_on_03_b");
}
PlayFXOnTag( level.laser_fx[ "laser_field3" ], self.FxEnts["charge_up"], "tag_origin" );
break;
default:
break;
}
}
stopLaserContainmentSwap()
{
if( !isDefined( level.killstreak_laser_fxmode ))
return;
fxId = level.killstreak_laser_fxmode;
level.killstreak_laser_fxmode = self.ownerList.size;
wait 1.0; //time for next stage of containment to come up.
switch( fxId )
{
case 0:
break;
case 1:
//PlayFXOnTag( level.laser_fx[ "laser_field1_down" ], self.FxEnts["charge_up"], "tag_origin" );
//StopFXOnTag( level.laser_fx[ "laser_field1" ], self.FxEnts["charge_up"], "tag_origin" );
break;
case 2:
PlayFXOnTag( level.laser_fx[ "laser_field2_down" ], self.FxEnts[ "charge_up" ], "tag_origin" );
StopFXOnTag( level.laser_fx[ "laser_field2" ], self.FxEnts[ "charge_up" ], "tag_origin" );
StopFXOnTag( level.laser_fx[ "laser_field1_cheap" ], self.FxEnts[ "charge_up" ], "tag_origin" );
PlayFXOnTag( level.laser_fx[ "laser_field1" ], self.FxEnts[ "charge_up" ], "tag_origin" );
laserLgtEnts = GetScriptableArray( "laser_light", "targetname" );
foreach ( laserLgtEnt in laserLgtEnts )
{
laserLgtEnt SetScriptablePartState("lsr_part_a", "laser_on_a");
}
laserLgtEnts = GetScriptableArray( "laser_light_b", "targetname" );
foreach ( laserLgtEnt in laserLgtEnts )
{
laserLgtEnt SetScriptablePartState("lsr_part_b", "laser_on_b");
}
break;
case 3:
PlayFXOnTag( level.laser_fx[ "laser_field3_down" ], self.FxEnts["charge_up"], "tag_origin" );
StopFXOnTag( level.laser_fx[ "laser_field3" ], self.FxEnts["charge_up"], "tag_origin" );
StopFXOnTag( level.laser_fx[ "laser_field2_cheap" ], self.FxEnts[ "charge_up" ], "tag_origin" );
PlayFXOnTag( level.laser_fx[ "laser_field2" ], self.FxEnts[ "charge_up" ], "tag_origin" );
laserLgtEnts = GetScriptableArray( "laser_light", "targetname" );
foreach ( laserLgtEnt in laserLgtEnts )
{
laserLgtEnt SetScriptablePartState("lsr_part_a", "laser_on_02_a");
}
laserLgtEnts = GetScriptableArray( "laser_light_b", "targetname" );
foreach ( laserLgtEnt in laserLgtEnts )
{
laserLgtEnt SetScriptablePartState("lsr_part_b", "laser_on_02_b");
}
break;
default:
break;
}
}
stopLaserContainmentEnd()
{
if( !isDefined( level.killstreak_laser_fxmode ))
return;
fxId = level.killstreak_laser_fxmode;
level.killstreak_laser_fxmode = 0;
wait 1.6; //time for laser to start animating down. TODO: use a notetrack for this
switch( fxId )
{
case 0:
break;
case 1:
PlayFXOnTag( level.laser_fx[ "laser_field1_down_slow" ], self.FxEnts["charge_up"], "tag_origin" );
KillFXOnTag( level.laser_fx[ "laser_field1" ], self.FxEnts["charge_up"], "tag_origin" );
StopLaserLights();
//turn off laser cannon lighting
//StopClientExploder(150);
wait 1.5;
PlayFXOnTag( level.laser_fx[ "hatch_light_close" ], self.FxEnts["charge_up"], "tag_origin" );
PlayFXOnTag( level.laser_fx[ "hatch_light_close" ], level.sentryGun.lifter, "tag_origin" );
break;
/*case 2:
PlayFXOnTag( level.laser_fx[ "laser_field2_down_slow" ], self.FxEnts[ "charge_up" ], "tag_origin" );
KillFXOnTag( level.laser_fx[ "laser_field2" ], self.FxEnts[ "charge_up" ], "tag_origin" );
KillFXOnTag( level.laser_fx[ "laser_field1" ], self.FxEnts["charge_up"], "tag_origin" );
break;
case 3:
PlayFXOnTag( level.laser_fx[ "laser_field3_down_slow" ], self.FxEnts["charge_up"], "tag_origin" );
KillFXOnTag( level.laser_fx[ "laser_field3" ], self.FxEnts["charge_up"], "tag_origin" );
KillFXOnTag( level.laser_fx[ "laser_field2" ], self.FxEnts[ "charge_up" ], "tag_origin" );
KillFXOnTag( level.laser_fx[ "laser_field1" ], self.FxEnts["charge_up"], "tag_origin" );
break;*/
default:
break;
}
}
laser_setInactive()
{
self.samTargetEnt = undefined;
self ClearTargetEntity();
self setMode( level.sentrySettings[ self.sentryType ].sentryModeOff );
self.mode = "off";
//self makeUnusable();
entNum = self GetEntityNumber();
self maps\mp\killstreaks\_autosentry::removeFromTurretList( entNum );
if ( level.teamBased )
{
self setTeamHeadIcon_large( "none", (0,0,0) );
}
else if ( IsDefined( self.owner ) )
{
self setTeamHeadIcon_large( "none", (0,0,0) );
}
self SetDefaultDropPitch( LASER_DROP_PITCH_OFFLINE );
level.sentryGun SetTurretMinimapVisible( false );
self SetTurretMinimapVisible( false );
self setCanDamage( false );
self laser_coreDamage_deactivated( self.coreDamageTrig );
self laser_coreDamage_deactivated( self.coreDeathTrig );
if( self.lifter.origin != self.moveOrgs["bottom"] )//these functions shouldn't happen at init
{
self laser_usableOffSwitch_off();
self thread StopLaserCoreEvent();
self thread stopLaserContainmentEnd();
self thread laser_handleMoveBottom();
}
}
laser_handleMoveBottom()
{
self endon ( "death" );
self endon ( "fakedeath" );
level endon ( "game_ended" );
assert( isDefined( self.lifter ) );
foreach( part in self.lifter.parts )
assert( isDefined( part ) );
self.locked = true; //lock while the laser is moving down
self.moving = true;
wait( 1 );
self LinkGeoToTurret(self, false);
self.lifter show();
self.lifter LinkGeoToTurret(self, true);
self hide();
// Xform Down
notetracktoaliasarray = [];
notetracktoaliasarray[ "laser_xform_down_sec1_start" ] = "laser_xform_down_sec1_start";
notetracktoaliasarray[ "laser_xform_down_sec1_end" ] = "laser_xform_down_sec1_end";
notetracktoaliasarray[ "laser_xform_down_sec2_start" ] = "laser_xform_down_sec2_start";
notetracktoaliasarray[ "laser_xform_down_sec2_end" ] = "laser_xform_down_sec2_end";
self.lifter ScriptModelPlayAnimDeltaMotion( self.lifter.animDown, "laser_xform_down_sec1_start" );
foreach( part in self.lifter.parts )
{
part ScriptModelPlayAnimDeltaMotion( self.lifter.animDown, "laser_xform_down_sec1_start" );
}
self.lifter thread snd_play_on_notetrack( notetracktoaliasarray, "laser_xform_down_sec1_start" );
foreach( flap in self.flaps )
{
if( isDefined( flap.targetname ) && flap.targetname == "lsr_flap_bottom" )//need the collision to match the anim
flap ScriptModelPlayAnimDeltaMotion( self.flap_animClose );
else
flap ScriptModelPlayAnim( self.flap_animClose );
}
self.lifter thread aud_play_laser_move_down( 6 );
self.lifter thread playMovementSparks(2.5);
self.lifter delayThread( 6, ::stopMovementSparks );
wait( 7.8 );//HACK: length on anim
self.moving = false;
self.locked = false;
}
laser_handleMoveTop()
{
self endon ( "death" );
self endon ( "fakedeath" );
level endon ( "game_ended" );
assert( isDefined( self.lifter ) );
foreach( part in self.lifter.parts )
assert( isDefined( part ) );
self.moving = true;
// Xform Up
notetracktoaliasarray = [];
notetracktoaliasarray[ "laser_xform_up_sec1_start" ] = "laser_xform_up_sec1_start";
notetracktoaliasarray[ "laser_xform_up_sec1_end" ] = "laser_xform_up_sec1_end";
notetracktoaliasarray[ "laser_xform_up_sec2_start" ] = "laser_xform_up_sec2_start";
notetracktoaliasarray[ "laser_xform_up_sec2_end" ] = "laser_xform_up_sec2_end";
self.lifter ScriptModelPlayAnimDeltaMotion( self.lifter.animUp, "laser_xform_up_sec1_start" );
foreach( part in self.lifter.parts )
{
part ScriptModelPlayAnimDeltaMotion( self.lifter.animUp, "laser_xform_up_sec1_start" );
}
self.lifter thread snd_play_on_notetrack( notetracktoaliasarray, "laser_xform_up_sec1_start" );
foreach( flap in self.flaps )
{
if( isDefined( flap.targetname ) && flap.targetname == "lsr_flap_bottom" )//need the collision to match the anim
flap ScriptModelPlayAnimDeltaMotion( self.flap_animOpen );
else
flap ScriptModelPlayAnim( self.flap_animOpen );
}
self.lifter thread aud_play_laser_move_up( 5.0 );
self.lifter thread playMovementSparks( 1.5 );
self.lifter delaythread( 5.0, ::stopMovementSparks );
wait( 8 );//HACK: length of anim
self.lifter LinkGeoToTurret(self, false);
self show();
self LinkGeoToTurret(self, true);
self.lifter hide();
waittillframeend;
self.moving = false;
}
aud_play_laser_move_up( delay_time )
{
thread snd_play_in_space_delayed( "laser_beam_power_up", ( 15,382,902 ), 5.2 );
thread snd_play_linked( "laser_platform_move_up_start", self );
thread aud_laser_energy_beam_start();
thread snd_play_loop_in_space( "laser_platform_move_alarm_lp", ( -1, 355, 945 ),"aud_stop_laser_alarm", 2 );
wait( delay_time );
thread snd_play_linked( "laser_platform_move_up_end", self );
level notify( "aud_stop_laser_alarm" );
}
aud_play_laser_move_down( delay_time )
{
thread snd_play_in_space_delayed( "laser_beam_power_down", ( 15,382,902 ), 1.25 );
thread aud_laser_pre_move_down();
wait(2.5);
move_down_sound = thread snd_play_linked( "laser_platform_move_down_start", self );
wait( 3 );
thread snd_play_linked( "laser_platform_move_down_legs_fold", self );
move_down_sound scalevolume( 0.0, 0.05 );
move_down_sound stopsounds();
level notify( "aud_laser_energy_lp_off" );
wait( 0.7 );
thread snd_play_linked( "laser_platform_move_down_end", self );
}
aud_laser_pre_move_down()
{
wait(1);
pre_move_down_sound = thread snd_play_linked( "laser_platform_pre_move_down", self );
}
aud_laser_energy_beam_start()
{
thread snd_play_loop_in_space( "laser_base_pulse_energy_lp", ( -13, 393, 352 ),"aud_laser_energy_lp_off", 2 );
thread snd_play_loop_in_space( "laser_base_pulse_low_lp", ( -13, 393, 352 ),"aud_laser_energy_lp_off", 2 );
thread snd_play_loop_in_space( "laser_base_pulse_motor_lp", ( -13, 393, 352 ),"aud_laser_energy_lp_off", 2 );
}
playMovementSparks(waitTime)
{
wait waitTime;
foreach( part in self.parts )
{
if( part.model == "mp_sky_laser_turret_lega" )
PlayFXOnTag(level.laser_fx["laser_movement_sparks"], part, "fx_joint_0");
}
}
stopMovementSparks()
{
foreach( part in self.parts )
{
if( part.model == "mp_sky_laser_turret_lega" )
StopFXOnTag(level.laser_fx["laser_movement_sparks"], part, "fx_joint_0");
}
}
player_sentry_timeOut( player )
{
self endon ( "death" );
self endon ( "fakedeath" );
level endon ( "game_ended" );
player endon( "disconnect" );
player endon( "joined_team" );
player endon( "joined_spectators" );
lifeSpan = level.sentrySettings[ self.sentryType ].timeOut;
while ( lifeSpan )
{
wait ( 1.0 );
maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
lifeSpan = max( 0, lifeSpan - 1.0 );
}
if( isDefined( player ) )
{
self.ownerList = array_removeFirstInQueue( self.ownerList, player );
if( self.ownerList.size != 0 )
{
player thread leaderDialogOnPlayer( level.sentrySettings[ level.sentryGun.sentryType ].vopower );
self thread stopLaserContainmentSwap();
}
else
{
player thread leaderDialogOnPlayer( level.sentrySettings[ level.sentryGun.sentryType ].voOffline );
self notify( "fakedeath" );
}
}
}
laser_setActive( player )
{
foreach ( player in level.players )
{
entNum = self GetEntityNumber();
self maps\mp\killstreaks\_autosentry::addToTurretList( entNum );
}
if( self.shouldSplash )
{
level thread maps\mp\_utility::teamPlayerCardSplash( level.sentrySettings[ self.sentryType ].teamSplash, self.owner, self.owner.team );
self.shouldSplash = false;
}
self laser_coreDamage_activated( self.coreDamageTrig );
self laser_coreDamage_activated( self.coreDeathTrig, true );
self laser_handleMoveTop();
self SetDefaultDropPitch( LASER_DROP_PITCH_ONLINE );
self SetMode( level.sentrySettings[ self.sentryType ].sentryModeOn );
self.mode = "on";
self laser_usableOffSwitch_on();
if( level.sentrySettings[ self.sentryType ].headIcon )
{
if ( level.teamBased )
{
self setTeamHeadIcon_large( self.team, (0,0,400) );
}
else
{
self setTeamHeadIcon_large( self.team, (0,0,400) );
}
}
self thread laser_attackTargets();
self thread laser_watchDisabled();
}
laser_usableOffSwitch_off()
{
self.GeneratorHat ScriptModelPlayAnim(self.GeneratorHat.anim_down);
level.sentryGun.offSwitch["use_zone"] maps\mp\gametypes\_gameobjects::disableObject();
level.sentryGun.offSwitch["switch_obj"] hide();
}
laser_usableOffSwitch_on()
{
laserOwner = "none";
if( isDefined( level.sentryGun.owner ) && isDefined( level.sentryGun.owner.team ) )
{
laserOwner = level.sentryGun.owner.team;
}
self.GeneratorHat ScriptModelPlayAnim(self.GeneratorHat.anim_up);
level.sentryGun.offSwitch["use_zone"].interactTeam = "enemy";
level.sentryGun.offSwitch["use_zone"] maps\mp\gametypes\_gameobjects::setOwnerTeam( laserOwner );
foreach( player in level.players )
{
if( player.team != laserOwner && laserOwner != "none" )
{
player.laserOffSwitch_isVisible = true;
level.sentryGun.offSwitch["switch_obj"] showtoplayer( player );
}
}
}
setTeamHeadIcon_large( team, offset ) // "allies", "axis", "all", "none"
{
if ( !level.teamBased )
return;
if ( !isDefined( self.entityHeadIconTeam ) )
{
self.entityHeadIconTeam = "none";
self.entityHeadIcon = undefined;
}
shader = game["entity_headicon_" + team];
self.entityHeadIconTeam = team;
if ( isDefined( offset ) )
self.entityHeadIconOffset = offset;
else
self.entityHeadIconOffset = (0,0,0);
self notify( "kill_entity_headicon_thread" );
if ( team == "none" )
{
if ( isDefined( self.entityHeadIcon ) )
self.entityHeadIcon destroy();
return;
}
headIcon = newTeamHudElem( team );
headIcon.archived = true;
headIcon.x = self.origin[0] + self.entityHeadIconOffset[0];
headIcon.y = self.origin[1] + self.entityHeadIconOffset[1];
headIcon.z = self.origin[2] + self.entityHeadIconOffset[2];
headIcon.alpha = 1;
headIcon setShader( shader, 50, 50 );
headIcon setWaypoint( false, false, false, true );
self.entityHeadIcon = headIcon;
self thread maps\mp\_entityheadicons::keepIconPositioned();
self thread maps\mp\_entityheadicons::destroyHeadIconsOnDeath();
}
setPlayerHeadIcon_large( player, offset ) // "allies", "axis", "all", "none"
{
if ( level.teamBased )
return;
if ( !isDefined( self.entityHeadIconTeam ) )
{
self.entityHeadIconTeam = "none";
self.entityHeadIcon = undefined;
}
self notify( "kill_entity_headicon_thread" );
if ( !isDefined( player ) )
{
if ( isDefined( self.entityHeadIcon ) )
self.entityHeadIcon destroy();
return;
}
team = player.team;
self.entityHeadIconTeam = team;
if ( isDefined( offset ) )
self.entityHeadIconOffset = offset;
else
self.entityHeadIconOffset = (0,0,0);
shader = game["entity_headicon_" + team];
headIcon = newClientHudElem( player );
headIcon.archived = true;
headIcon.x = self.origin[0] + self.entityHeadIconOffset[0];
headIcon.y = self.origin[1] + self.entityHeadIconOffset[1];
headIcon.z = self.origin[2] + self.entityHeadIconOffset[2];
headIcon.alpha = 1;
headIcon setShader( shader, 50, 50 );
headIcon setWaypoint( false, false, false, true );
self.entityHeadIcon = headIcon;
self thread maps\mp\_entityheadicons::keepIconPositioned();
self thread maps\mp\_entityheadicons::destroyHeadIconsOnDeath();
}
laser_watchDisabled()
{
self endon ( "death" );
self endon ( "fakedeath" );
level endon ( "game_ended" );
self notify ( "laser_watchDisabled" );
self endon ( "laser_watchDisabled" );//only have one of these threads running at a time
while( true )
{
// this handles any flash or concussion damage
self waittill( "emp_damage", attacker, duration );//TODO: rename "emp_damage". It is really poorly named. It actually is coming from concussion and frags but not the emp. look at laser_handleDamage or sentry_handleDamage for the real emp damage.
PlayFXOnTag( common_scripts\utility::getfx( "sentry_explode_mp" ), self, "tag_aim" );
self SetDefaultDropPitch( LASER_DROP_PITCH_OFFLINE );
self SetMode( level.sentrySettings[ self.sentryType ].sentryModeOff );
self.mode = "none";
//TODO: what happens if someone activates it during this time?
wait( duration );
self SetDefaultDropPitch( LASER_DROP_PITCH_ONLINE );
self SetMode( level.sentrySettings[ self.sentryType ].sentryModeOn );
self.mode = "on";
}
}
laser_attackTargets() // self == sam
{
self endon ( "death" );
self endon ( "fakedeath" );
level endon ( "game_ended" );
self notify ( "laser_attackTargets" );
self endon ( "laser_attackTargets" );//only have one of these threads running at a time
self.samTargetEnt = undefined;
self.samMissileGroups = [];
while( true )
{
self.samTargetEnt = maps\mp\killstreaks\_autosentry::sam_acquireTarget();
self laser_fireOnTarget();
wait( 0.05 );
}
}
laser_watchLightBeam() // self == sam turret
{
self endon( "death" );
level endon( "game_ended" );
//Start the deadly laser beam's FX.
wait ( 0.5 );
if( !isDefined( self.ownerList ) || self.ownerList.size < 1 )
return;
fxId = self.ownerList.size;
PlayFXOnTag( level.laser_fx[ "laser_charge1" ], self.FxEnts["charge_up"], "tag_origin" );
PlayFXOnTag( level.laser_fx[ "beahm" ], self, "tag_laser" );
self laser_coreDamage_activated( self.firingDamageTrig );
fire_start_sfx = snd_play_linked( "wpn_skylaser_fire_startup", self );
self thread play_loop_sound_on_entity( "wpn_skylaser_beam_lp" );
self LaserOn( "mp_laser2_laser" );
while( IsDefined( self.samTargetEnt ) && IsDefined( self GetTurretTarget( true ) ) && self GetTurretTarget( true ) == self.samTargetEnt )
{
wait( 0.05 );
}
//Stop the deadly laser beam's FX.
self LaserOff();
StopFXOnTag( level.laser_fx[ "laser_charge1" ], self.FxEnts[ "charge_up" ], "tag_origin" );
PlayFXOnTag( level.laser_fx[ "laser_beam_done1" ], self.FxEnts[ "charge_up" ], "tag_origin" );
StopFXOnTag( level.laser_fx[ "beahm" ], self, "tag_laser" );
PlayFXOnTag( level.laser_fx[ "beahm_smoke" ], self, "tag_laser" );
self laser_coreDamage_deactivated( self.firingDamageTrig );
self stop_loop_sound_on_entity( "wpn_skylaser_beam_lp" );
fire_stop_sfx = snd_play_linked( "wpn_skylaser_beam_stop", self );
if( isdefined( fire_start_sfx ) )
{
fire_start_sfx StopSounds();
}
}
laser_fireOnTarget() // self == sam turret
{
self endon( "death" );
self endon( "fakedeath" );
level endon( "game_ended" );
// locked on to target, turn on laser and fire
if( IsDefined( self.samTargetEnt ) )
{
// because we hide the orbital support platform and don't really delete it
if( isDefined( level.orbitalsupport_planeModel ) && self.samTargetEnt == level.orbitalsupport_planeModel && !IsDefined( level.orbitalsupport_player ) )
{
self.samTargetEnt = undefined;
self ClearTargetEntity();
return;
}
self SetTargetEntity( self.samTargetEnt );
self waittill( "turret_on_target" );
if( !IsDefined( self.samTargetEnt ) )
return;
// turn on the laser, also watch for if the target is crashing or leaving
if( !self.laser_on )
{
self thread laser_watchLightBeam();
self thread maps\mp\killstreaks\_autosentry::sam_watchLaser();
self thread maps\mp\killstreaks\_autosentry::sam_watchCrashing();
self thread maps\mp\killstreaks\_autosentry::sam_watchLeaving();
self thread maps\mp\killstreaks\_autosentry::sam_watchLineOfSight();
}
wait( 0.5 );
if( !IsDefined( self.samTargetEnt ) )
return;
// because we hide the orbital support platform and don't really delete it
if( isDefined( level.orbitalsupport_planeModel ) && self.samTargetEnt == level.orbitalsupport_planeModel && !IsDefined( level.orbitalsupport_player ) )
{
self.samTargetEnt = undefined;
self ClearTargetEntity();
return;
}
// need to shoot the turret so it'll show up on the mini-map as it shoots, it will shoot blanks
self ShootTurret();
//Use a damage radius to deal damage to aerial targets.
self fireLaserBeam();
}
}
fireLaserBeam()
{
self endon( "death" );
self endon( "fakedeath" );
level endon( "game_ended" );
trace_start = self GetTagOrigin( "tag_laser" );
trace_vector = AnglesToForward( self GetTagAngles( "tag_laser" ) );
trace_end = trace_start + 15000 * trace_vector;
LaserTraceData = BulletTrace( trace_start, trace_end, true, self );
//HACK: The target is an Orbital Support Platform. Place a RadiusDamage directly on the AC-130's position because the BulletTrace is not hitting the AC-130.
if ( isDefined( level.orbitalSupport_planemodel ) && self.samTargetEnt == level.orbitalSupport_planemodel && IsDefined( level.orbitalSupport_player ) )
{
//TODO: add some VO notifying the Orbital Support Platform user that they are getting shot down by a LAZER!
RadiusDamage( level.orbitalSupport_planemodel.origin, 512, 100, 100, self.owner, "MOD_EXPLOSIVE", "killstreak_laser2_mp" );
}
//HACK: the target is an Orbital carepackage
else if( isDefined( self.samTargetEnt.isPodRocket ) && self.samTargetEnt.isPodRocket )
{
//TODO: add some VO notifying the Orbital Support Platform user that they are getting shot down by a LAZER!
self.samTargetEnt notify( "damage", 1000, self.owner, undefined, undefined, "mod_explosive", undefined, undefined, undefined, undefined, "killstreak_laser2_mp" );//HACK: shouldn't have to call damage notify
}
else
{
RadiusDamage( LaserTraceData[ "position" ], 512, 200, 200, self.owner, "MOD_EXPLOSIVE", "killstreak_laser2_mp" );
}
}
//Laser Power Core stuff
laser_coreDamage_activated( trig, b_kill )
{
level endon( "game_ended" );
self thread watchPlayerEnterLaserCore( trig, b_kill );
trig trigger_on();
}
laser_coreDamage_deactivated( trig )
{
level endon( "game_ended" );
trig notify( "laser_coreDamage_deactivated" );
trig trigger_off();
}
watchPlayerEnterLaserCore( trig, b_kill )
{
//self is laser
level endon( "game_ended" );
trig endon( "laser_coreDamage_deactivated" );
while( true )
{
trig waittill( "trigger", player );
if ( !isPlayer( player ) )
continue;
if ( !isAlive( player ) )
continue;
if ( isDefined( player.laserCoreTrigIDs ) && IsDefined( player.laserCoreTrigIDs[ trig.targetname ] ) && player.laserCoreTrigIDs[ trig.targetname ] == 1 )
{
continue;
}
else
{
if ( !IsDefined( player.laserCoreTrigIDs ) )
player.laserCoreTrigIDs = [];
player.laserCoreTrigIDs[ trig.targetname ] = 1;
player thread player_laserCoreEffect( trig, b_kill );
// laserCoreEffect may kill the player
if ( IsAlive( player ) )
{
player thread player_watchExitLaserCore( trig );
player thread player_watchDeath( trig );
}
else
{
player.laserCoreTrigIDs[ trig.targetname ] = 0;
}
}
}
}
player_watchExitLaserCore( trig )
{
//self is player
level endon( "game_ended" );
self endon( "player_leftLaserCoreTrigger" + trig.targetname);
self endon( "stop_watching_trig" );
while( self isTouching( trig ) )
{
wait( .05 );
}
if ( IsDefined( self.laserCoreTrigIDs ) )
{
self.laserCoreTrigIDs[ trig.targetname ] = 0;
}
self player_resetLaserCoreValues();
self notify( "player_leftLaserCoreTrigger" + trig.targetname );
}
player_laserCoreEffect( trig, b_kill )
{
//self is player
level endon( "game_ended" );
self endon( "player_leftLaserCoreTrigger" + trig.targetname );
self endon( "stop_watching_trig" );
if( isDefined( b_kill ) && b_kill )
{
self _suicide();//kill even if friendly fire
return;
}
self.poison = 0;
shellshockName = level.sentrySettings[ level.sentryGun.sentryType ].coreShellshock;
if( !isDefined( self.usingRemote ) && !isDefined( self.rideVisionSet ) )
{
self VisionSetNakedForPlayer( "aftermath", .5 );
self shellshock( shellshockName, 60);
}
else
self.laserCoreVisualsBlocked = true;
while( 1 )
{
self.poison ++;
switch( self.poison )
{
case 1:
self ViewKick( 1, self.origin );
break;
case 2:
self ViewKick( 3, self.origin );
self player_doLaserCoreDamage(15);
break;
case 3:
self ViewKick( 15, self.origin );
self player_doLaserCoreDamage(15);
break;
case 4:
self ViewKick( 75, self.origin );
self _suicide( );//kill even if friendly fire
return;
}
wait( 1 );
}
}
player_watchDeath( trig )
{
level endon( "game_ended" );
self endon( "player_leftLaserCoreTrigger" + trig.targetname);
self common_scripts\utility::waittill_any( "disconnect", "joined_team", "joined_spectators", "death" );
self.laserCoreTrigIDs = undefined;
self player_resetLaserCoreValues();
self notify( "stop_watching_trig" );
}
player_resetLaserCoreValues()
{
//self is the player
if( !isDefined( self.laserCoreVisualsBlocked ) )
{
self stopShellShock();
self thread revertVisionSetForPlayer( .5 );
}
self.laserCoreVisualsBlocked = undefined;
}
laserlightfill()
{
PlayFXOnTag( getFx( "light_laser_fill" ), self, "tag_origin" );
}
player_doLaserCoreDamage( iDamage )
{
if( !isdefined( level.sentryGun.owner ) )
return;
//TODO: Handle friendly fire
//TODO: change the weapon to the laser2 weapon and update matchdata.def
self thread [[ level.callbackPlayerDamage ]](
self,// eInflictor The entity that causes the damage.( e.g. a turret )
level.sentryGun.owner,// eAttacker The entity that is attacking.
iDamage,// iDamage Integer specifying the amount of damage done
0,// iDFlags Integer specifying flags that are to be applied to the damage
"MOD_TRIGGER_HURT",// sMeansOfDeath Integer specifying the method of death
"mp_laser2_core",// sWeapon The weapon number of the weapon used to inflict the damage
self.origin,// vPoint The point the damage is from?
( 0,0,0 ) - self.origin,// vDir The direction of the damage
"none",// sHitLoc The location of the hit
0// psOffsetTime The time offset for the damage
);
}
/*
=============
///ScriptDocBegin
"Name: handleDamageFeedbackSound()"
"Summary: "
"Module: Entity"
"CallOn: a player who is doing damage to someone else and should get a damage feedback sound."
"Example: self thread handleDamageFeedbackSound();"
"SPMP: MP"
///ScriptDocEnd
=============
*/
handleDamageFeedbackSound( killer_ent )
{
// self.shouldloopdamagefeedback = true;
// self.damagefeedbacktimer = 2;//HACK time of audio looping
//
// self PlayLocalSound( "MP_hit_alert" );
//
// while ( isDefined( killer_ent.laser_on ) && killer_ent.laser_on )
// {
// self PlayLocalSound( "MP_solar_hit_alert" );
// killer_ent waitForTimeOrNotify( self.damagefeedbacktimer, "laser_off" );
// }
//
// self StopLocalSound( "MP_solar_hit_alert" );
// self PlayLocalSound( "MP_hit_alert" );
// self.shouldloopdamagefeedback = undefined;
}