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

630 lines
14 KiB
Plaintext

#include maps\mp\_utility;
#include common_scripts\utility;
// Killstreak Data
CONST_DAMAGE_RADIUS = 128;
CONST_DAMAGE_MIN = 2;
CONST_DAMAGE_MAX = 8;
CONST_FIRE_TIME = 5;
CONST_FIRE_RADIUS_SQ = 70 * 70;
CONST_FIRE_DIST_RADIUS_SQ = 50 * 50;
CONST_FIRE_HEIGHT = 80;
init()
{
level.solar_killstreak_duration = 30;
//FX
level.solar_fire_fx = LoadFX( "vfx/fire/fire_xsglow_runner_5s" );
//Sounds
level.solar_reflector_sfx = "mp_solar_array_player";
level.solar_reflector_target_sfx = "mp_solar_array_target";
level.killstreakFuncs["mp_solar"] = ::tryUseSolarReflector;
level.mapKillStreak = "mp_solar";
level.mapKillstreakPickupString = &"MP_SOLAR_MAP_KILLSTREAK_PICKUP";
level.mapKillStreakDamageFeedbackSound = ::handleDamageFeedbackSound;
level.mapCustomBotKillstreakFunc = ::setupBotsForMapKillstreak;
level.killstreakWieldWeapons["killstreak_solar_mp"] = "mp_solar";
}
setupBotsForMapKillstreak()
{
level thread maps\mp\bots\_bots_ks::bot_register_killstreak_func( "mp_solar", maps\mp\bots\_bots_ks::bot_killstreak_never_use, maps\mp\bots\_bots_ks::bot_killstreak_do_not_use );
}
tryUseSolarReflector( lifeId, modules )
{
if ( isDefined( level.solar_reflector_player ) )
{
self iPrintLnBold( &"MP_SOLAR_REFLECTOR_IN_USE" );
return false;
}
if ( self isUsingRemote() )
{
return false;
}
if ( self isAirDenied() )
{
return false;
}
if ( self isEMPed() )
{
return false;
}
result = self maps\mp\killstreaks\_killstreaks::initRideKillstreak();
if ( result != "success" )
return false;
self setUsingRemote( "mp_solar" );
result = setSolarReflectorPlayer( self );
// this needs to get set after we say the player is using it because this could get set to true and then they leave the game
// this fixes a bug where a player calls it, leaves before getting fully in it and then no one else can call it because it thinks it's being used
if( IsDefined( result ) && result )
{
self maps\mp\_matchdata::logKillstreakEvent( "mp_solar", self.origin ); //TODO: set this up for the Solar Reflector.
}
else
{
if ( self isUsingRemote() )
self clearUsingRemote();
}
return ( IsDefined( result ) && result );
}
setSolarReflectorPlayer( player )
{
self endon ( "solar_reflector_player_removed" );
level.solar_reflector_player = player;
thread teamPlayerCardSplash( "used_mp_solar", player );
thread onPlayerConnect();
thread setupPlayerDeath();
player thread overlay();
player thread runBeam();
player thread removeSolarReflectorPlayerAfterTime( level.solar_killstreak_duration );
player thread removeSolarReflectorPlayerWatch();
player thread removeSolarReflectorLevelWatch();
player thread removeSolarReflectorPlayerOnCommand();
return true;
}
beamMinimap(ground_ent)
{
solar_reflector_friendShader = "compassping_orbitallaser_friendly";
solar_reflector_foeShader = "compassping_orbitallaser_hostile";
currentObj = maps\mp\gametypes\_gameobjects::getNextObjID();
objective_add( currentObj, "invisible", (0,0,0) );
objective_OnEntity( currentObj, ground_ent );
objective_state( currentObj, "active" );
if(level.teambased)
objective_team( currentObj, self.team );
else
objective_player( currentObj, self GetEntityNumber() );
objective_icon( currentObj, solar_reflector_friendShader );
friendlyObjID = currentObj;
currentObj = maps\mp\gametypes\_gameobjects::getNextObjID();
objective_add( currentObj, "invisible", (0,0,0) );
objective_OnEntity( currentObj, ground_ent );
objective_state( currentObj, "active" );
if(level.teamBased)
objective_team( currentObj, level.otherTeam[ self.team ] );
else
objective_playerenemyteam( currentObj, self GetEntityNumber() );
objective_icon( currentObj, solar_reflector_foeShader );
enemyObjID = currentObj;
level waittill( "solar_reflector_player_removed" );
_objective_delete( friendlyObjID );
_objective_delete( enemyObjID );
}
beamSounds(cam_ent, ground_ent)
{
waitframe();
ground_ent PlayLoopSound( level.solar_reflector_target_sfx );
cam_ent PlayLoopSound( level.solar_reflector_sfx );
PlaySoundAtPos( cam_ent.origin, "array_beam_start");
level waittill( "solar_reflector_player_removed" );
PlaySoundAtPos( cam_ent.origin, "array_beam_stop");
ground_ent StopLoopSound();
cam_ent StopLoopSound();
}
runBeam()
{
cam_pos = GetStruct("solar_cam_pos", "targetname");
beam_pos = GetStruct("solar_beam_pos", "targetname");
ground_pos = GetStruct("solar_ground_pos", "targetname");
ground_ent = getGroundEnt(ground_pos);
cam_ent = getCameraEnt(cam_pos, ground_pos);
self thread playerSetCamera(cam_ent);
beam_ent = getBeamEnt(beam_pos, ground_pos);
self thread beamMinimap(ground_ent);
self thread beamSounds(cam_ent, ground_ent);
//self thread beamStartFires(ground_ent);
//self thread beamGroundFx(ground_ent); //Moved to laser gdt
runBeamUpdate(beam_ent, cam_ent, ground_ent);
beam_ent.killCamEnt Delete();
beam_ent Delete();
cam_ent Delete();
ground_ent Delete();
}
getCameraEnt(cam_pos, ground_pos)
{
cam_ent = Spawn("script_model", cam_pos.origin );
cam_ent.angles = VectorToAngles(ground_pos.origin - cam_pos.origin);
cam_ent SetModel("tag_player");
return cam_ent;
}
getGroundEnt(ground_pos)
{
ground_ent = Spawn("script_model", ground_pos.origin);
ground_ent.angles = (0,0,0);
ground_ent SetModel("tag_origin");
return ground_ent;
}
playerSetCamera(cam_ent)
{
cam_ent endon("death");
/#
if ( GetDvarInt( "test_mp_solar_killstreak_death", 0 ) != 0 )
return;
#/
self PlayerLinkWeaponViewToDelta( cam_ent, "tag_player", 1.0, 40, 40, 12, 10 );
self SetPlayerAngles( cam_ent GetTagAngles( "tag_player" ) );
self SetClientOmnvar( "fov_scale", 0.2 );
self ThermalVisionFOFOverlayOn();
while(1)
{
self EnableSlowAim( 0.05, 0.05 );
level waittill( "host_migration_begin" );
waitframe();
self SetClientOmnvar( "fov_scale", 0.2 );
self ThermalVisionFOFOverlayOn();
maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
}
}
getBeamEnt(beam_pos, ground_pos)
{
beam_ent = Spawn("script_model", beam_pos.origin );
beam_ent.angles = VectorToAngles(ground_pos.origin - beam_pos.origin);
beam_ent SetModel("tag_laser");
beam_ent LaserOn( "solar_laser" );
offset = (AnglesToForward(beam_ent.angles) * 5000) - (0,0,100);
killCamEnt = Spawn("script_model", beam_pos.origin + offset );
killCamEnt.angles = beam_ent.angles;
killCamEnt LinkTo(beam_ent);
beam_ent.killCamEnt = killCamEnt;
return beam_ent;
}
beamGroundFx(ground_ent)
{
ground_ent endon ( "death" );
lastFX = undefined;
while(1)
{
waitframe();
if ( !isDefined(ground_ent.surfacetype) )
continue;
nextFX = beamGetGroundFX(ground_ent.surfacetype);
if(!IsDefined(lastFX) || lastFX != nextFX)
{
if(IsDefined(lastFX))
StopFXOnTag(lastFX, ground_ent, "tag_origin");
PlayFXOnTag(nextFX, ground_ent, "tag_origin");
lastFX = nextFX;
}
}
}
beamGetGroundFX(surfacetype)
{
switch(surfacetype)
{
case "water":
case "water_waist":
return getfx("steam_column_rising");
default:
return getfx("fx_flare_solar");
}
}
runBeamUpdate(beam_ent, cam_ent, ground_ent)
{
self endon ( "solar_reflector_player_removed" );
speed = 300;
trace_dist = 20000;
beam_ent_pos = SpawnStruct();
beam_ent_pos.origin = ground_ent.origin;
test_dvar = 0;
/#
test_dvar = GetDvarInt( "test_mp_solar_killstreak_death", 0 );
if ( test_dvar )
level.test_start_angles = cam_ent.angles;
#/
while(1)
{
goal_angles = self GetPlayerAngles();
/#
if( test_dvar == 2 )
{
offset = Sin((GetTime()/1000) * 3.14 * 10) * 10;
goal_angles = level.test_start_angles + (0,offset,0);
}
else if ( test_dvar != 0 )
{
goal_angles = level.test_start_angles;
}
#/
goal_angles = (goal_angles[0], goal_angles[1], 0); //GetPlayerAngles is is returning with a very small roll
goal_dir = AnglesToForward(goal_angles);
goal_dist = abs((cam_ent.origin[2] - beam_ent_pos.origin[2])/goal_dir[2]);
goal_point = cam_ent.origin + goal_dir*goal_dist; //Push the point down the the same plane as the ground;
move_dist = Distance2D(goal_point, beam_ent_pos.origin);
if( move_dist <= speed*0.05 )
{
beam_ent_pos.origin = goal_point;
}
else
{
move_dir = goal_point - beam_ent_pos.origin;
move_dir = VectorNormalize(move_dir);
beam_ent_pos.origin += move_dir*speed*0.05;
}
beam_dir = VectorNormalize(beam_ent_pos.origin-beam_ent.origin);
beam_ent RotateTo(VectorToAngles(beam_dir), 0.1);
//beam_ent.angles = anglessnaptocompressedangles( beam_ent.angles );
start = beam_ent.origin;
end = start + beam_dir*trace_dist;
results = BulletTrace(start, end, false);
Assert(results["fraction"]< 1.0);
ground_ent MoveTo(results["position"], .1);
ground_ent.surfacetype = results["surfacetype"];
ground_ent.killCamEnt = beam_ent.killCamEnt;
ground_ent RadiusDamage( ground_ent.origin, CONST_DAMAGE_RADIUS, CONST_DAMAGE_MAX, CONST_DAMAGE_MIN, self, "MOD_EXPLOSIVE", "killstreak_solar_mp" );
waitframe();
}
}
handleDamageFeedbackSound()
{
self.shouldloopdamagefeedback = true;
self.damagefeedbacktimer = 10;
self PlayLocalSound( "MP_solar_hit_alert" );
self PlayRumbleLoopOnEntity("damage_light");
while ( self.damagefeedbacktimer > 0 )
{
self.damagefeedbacktimer--;
wait( 0.05 );
}
self StopRumble("damage_light");
self StopLocalSound( "MP_solar_hit_alert" );
self.shouldloopdamagefeedback = undefined;
}
removeSolarReflectorPlayerOnCommand()
{
self endon ( "solar_reflector_player_removed" );
while ( true )
{
button_hold_time = 0;
while ( self UseButtonPressed() )
{
button_hold_time += 0.05;
if ( button_hold_time > 0.75 )
{
level thread removeSolarReflectorPlayer( self );
return;
}
waitframe();
}
waitframe();
}
}
removeSolarReflectorPlayerWatch()
{
self endon ( "solar_reflector_player_removed" );
self waittill_any("disconnect", "joined_team", "joined_spectators", "spawned", "killstreak_exit");
level thread removeSolarReflectorPlayer( self );
}
removeSolarReflectorLevelWatch()
{
self endon ( "solar_reflector_player_removed" );
level waittill ( "game_cleanup" );
level thread removeSolarReflectorPlayer( self );
}
removeSolarReflectorPlayerAfterTime( removeDelay )
{
self endon ( "solar_reflector_player_removed" );
wait 1; //Don't start timer till we fade up from black
if ( self _hasPerk( "specialty_blackbox" ) && IsDefined( self.specialty_blackbox_bonus ) )
{
removeDelay *= self.specialty_blackbox_bonus;
}
self thread solarRelectorTimer(removeDelay);
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( removeDelay );
/#
while ( GetDvarInt( "test_mp_solar_killstreak_death", 0 ) != 0 )
waitframe();
#/
level thread removeSolarReflectorPlayer( self );
}
solarRelectorTimer( removeDelay )
{
self endon ( "solar_reflector_player_removed" );
endTime = GetTime() + removeDelay*1000;
while(1)
{
self SetClientOmnvar("ui_solar_beam_timer", endTime);
level waittill( "host_migration_begin" );
timePassed = maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
endTime += timePassed;
}
}
removeSolarReflectorPlayer( player )
{
player notify ( "solar_reflector_player_removed" );
level notify ( "solar_reflector_player_removed" );
waittillframeend;
if ( IsDefined(player) )
{
player clearUsingRemote();
player show();
player unlink();
player ThermalVisionFOFOverlayOff();
player setBlurForPlayer( 0, 0 );
player SetClientOmnvar("ui_solar_beam", 0);
player DisableSlowAim();
player SetClientOmnvar( "fov_scale", 1 );
}
level.solar_reflector_player = undefined;
}
overlay()
{
self endon("disconnect");
level endon( "solar_reflector_player_removed" );
wait 1; // Don't show hud till we fade up from black
self setBlurForPlayer( 1.2, 0 );
self SetClientOmnvar("ui_solar_beam", 1);
}
onPlayerConnect()
{
level notify( "solarOnPlayerConnect" );
level endon( "solarOnPlayerConnect" );
level endon( "solar_reflector_player_removed" );
while ( true )
{
level waittill( "connected", player );
player.preKilledFunc = ::playerPreKilled;
player thread onPlayerSpawned();
player thread playerImmuneToFire();
}
}
onPlayerSpawned()
{
level notify( "solarOnPlayerSpawned" );
level endon( "solarOnPlayerSpawned" );
level endon( "solar_reflector_player_removed" );
while ( true )
{
self waittill( "player_spawned" );
self.hideOnDeath = undefined;
}
}
setupPlayerDeath()
{
foreach ( player in level.players )
{
if ( !IsDefined( player ) || player == level.solar_reflector_player )
continue;
player.preKilledFunc = ::playerPreKilled;
player thread onPlayerSpawned();
}
}
playerPlayVaporizeFX()
{
self.hideOnDeath = true;
offset = ( 0, 0, 30 ); // stand;
stance = self GetStance();
if ( stance == "crouch" )
offset = ( 0, 0, 20 );
else if ( stance == "prone" )
offset = ( 0, 0, 10 );
PlayFX( getfx( "solar_killstreak_death" ), self.origin + offset );
}
playerPreKilled( eInflictor, attacker, victim, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, isFauxDeath )
{
if ( sWeapon == "killstreak_solar_mp" )
self playerPlayVaporizeFX();
}
playerImmuneToFire()
{
self endon( "disconnect" );
self.solarImmuneFire = true;
wait CONST_FIRE_TIME;
self.solarImmuneFire = undefined;
}
beamStartFires(ground_ent)
{
level endon( "solar_reflector_player_removed" );
fireFxEnt = SpawnFx( level.solar_fire_fx, ( 0, 0, 0 ) );
lastFirePos = ( 0, 0, 0 );
lastFireTime = GetTime();
while ( true )
{
waitframe();
distSq = Distance2DSquared( ground_ent.origin, lastFirePos );
duration = ( lastFireTime - GetTime() ) / 1000;
if ( distSq > CONST_FIRE_DIST_RADIUS_SQ || duration > CONST_FIRE_TIME )
{
lastFirePos = ground_ent.origin;
if ( !IsDefined(ground_ent.surfacetype) || !isStrStart( ground_ent.surfacetype, "water_") )
{
level thread fireAtPosition( lastFirePos, self );
}
lastFireTime = GetTime();
}
}
}
fireAtPosition( fireOrigin, killstreakPlayer )
{
PlayFX( level.solar_fire_fx, fireOrigin );
endTime = GetTime() + ( CONST_FIRE_TIME * 1000 );
while ( GetTime() < endTime )
{
foreach ( player in level.players )
{
// just connected
if ( IsDefined( player.solarImmuneFire ) )
continue;
// below the fire
if ( player.origin[2] < ( fireOrigin[2] - 5 ) )
continue;
// above the fire
if ( player.origin[2] > ( fireOrigin[2] + CONST_FIRE_HEIGHT ) )
continue;
distSq = Distance2DSquared( player.origin, fireOrigin );
if ( distSq < CONST_FIRE_RADIUS_SQ )
player DoDamage( 4, fireOrigin, killstreakPlayer, killstreakPlayer, "MOD_EXPLOSIVE", "killstreak_solar_mp" );
}
wait 0.1;
}
}