2024-12-11 11:28:08 +01:00

396 lines
11 KiB
Plaintext

#include common_scripts\utility;
//////////////////////////////////////////////////////////////////////////////
// CONSTANTS //
//////////////////////////////////////////////////////////////////////////////
level_limit_pipe_fx = 8;
max_fires_from_entity = 4;
level_pipe_fx_chance = 33;
//////////////////////////////////////////////////////////////////////////////
// LOGIC //
//////////////////////////////////////////////////////////////////////////////
main()
{
if ( IsDefined( level.pipes_init ) )
return;
level.pipes_init = true;
//level._pipe_fx_time = 25; //handle this individually for different pipe types
pipes = GetEntArray( "pipe_shootable", "targetname" );
if ( !pipes.size )
return;
level._pipes = SpawnStruct();
level._pipes.num_pipe_fx = 0;
pipes thread precacheFX();
pipes thread methodsInit();
thread post_load( pipes );
}
post_load( pipes )
{
waittillframeend;// insure that structs are initialized
if( level.createFX_enabled )
return;
array_thread( pipes, ::pipesetup );
}
pipesetup()
{
self SetCanDamage( true );
self SetCanRadiusDamage( false ); // optimization
self.pipe_fx_array = [];
node = undefined;
if ( IsDefined( self.target ) )
{
node = getstruct( self.target, "targetname" );
self.A = node.origin;
vec = AnglesToForward( node.angles );
vec = ( vec * 128 );
self.B = self.A + vec;
}
else
{
vec = AnglesToForward( self.angles );
vec1 = ( vec * 64 );
self.A = self.origin + vec1;
vec1 = ( vec * -64 );
self.B = self.origin + vec1;
}
self thread pipe_wait_loop();
}
pipe_wait_loop()
{
P = ( 0, 0, 0 );// just to initialize P as a vector
hasTakenDamage = false;
remaining = max_fires_from_entity;
while ( 1 )
{
self waittill( "damage", damage, attacker, direction_vec, P, type );
// random so we don't get so many fx, but the very first time is guarenteed
if ( hasTakenDamage )
{
if ( randomint( 100 ) <= level_pipe_fx_chance )
continue;
}
hasTakenDamage = true;
result = self pipe_logic( direction_vec, P, type, attacker );
if ( result )
remaining--;
if ( remaining <= 0 )
break;
}
self SetCanDamage( false );
}
pipe_logic( direction_vec, P, type, damageOwner )
{
if ( level._pipes.num_pipe_fx > level_limit_pipe_fx )
return false;
if ( !isDefined( level._pipes._pipe_methods[ type ] ) )
P = self pipe_calc_nofx( P, type );
else
P = self [[ level._pipes._pipe_methods[ type ] ]]( P, type );
if ( !isdefined( P ) )
return false;
if ( IsDefined( damageOwner.classname ) && damageOwner.classname == "worldspawn" )
return false;
foreach ( value in self.pipe_fx_array )
{
if ( DistanceSquared( P, value.origin ) < 25 )
return false;
}
//calculate the vector derived from the center line of our pipe and the point of damage
// generate a vector from the attacker's eye to the impact point (AI) or origin to impact point (non-AI)
E = undefined;
if( IsAI( damageOwner ))
E = damageOwner GetEye();
else
E = damageOwner.origin;
temp_vec = P - E;
// Extend the vector (this is to ensure it intersects the damaged entity, tracing to the point itself generated new points which were slightly off and bad normals) and return a trace
trace = BulletTrace ( E, E + 1.5 * temp_vec, false, damageOwner, false );
if ( isdefined ( trace [ "normal" ] ) && isdefined ( trace [ "entity" ] ) && trace ["entity"] == self )
{
vec = trace[ "normal" ];
// Use the surface normal of the impact point to generate the angles for the burst effect
self thread pipefx( P, vec, damageOwner );
return true;
}
return false;
}
pipefx( P, vec, damageOwner )
{
time = level._pipes.fx_time[ self.script_noteworthy ] ;
fx_time = level._pipes._pipe_fx_time[ self.script_noteworthy ] ;
intervals = Int( fx_time / time );// loops for 25 seconds
intervals_end = 30;
hitsnd = level._pipes._sound[ self.script_noteworthy + "_hit" ];
loopsnd = level._pipes._sound[ self.script_noteworthy + "_loop" ];
endsnd = level._pipes._sound[ self.script_noteworthy + "_end" ];
snd = Spawn( "script_origin", P );
// snd Hide();
snd PlaySound( hitsnd );
snd PlayLoopSound( loopsnd );
self.pipe_fx_array[ self.pipe_fx_array.size ] = snd;
if ( isSP() || self.script_noteworthy != "steam" )
self thread pipe_damage( P, vec, damageOwner, snd );
//if it is a barrel, rotate the emitter angle over time
if( self.script_noteworthy == "oil_leak" )
{
efx_rot = Spawn( "script_model", P );
efx_rot SetModel( "tag_origin" );
efx_rot.angles = VectorToAngles( vec );
PlayFXOnTag( level._pipes._effect[ self.script_noteworthy ] , efx_rot, "tag_origin" );
level._pipes.num_pipe_fx++;
efx_rot RotatePitch( 90, time, 1, 1 );
wait time;
StopFXOnTag( level._pipes._effect[ self.script_noteworthy ] , efx_rot, "tag_origin" );
intervals--;
}
else
{
//do it once without checking for newer fx being played ( we're the newest )
PlayFX( level._pipes._effect[ self.script_noteworthy ], P, vec );
level._pipes.num_pipe_fx++;
wait time;
intervals--;
}
//now check for other fx and rest of intervals
while ( level._pipes.num_pipe_fx <= level_limit_pipe_fx && intervals > 0 )
{
if( self.script_noteworthy == "oil_leak" )
{
efx_rot = Spawn( "script_model", P );
efx_rot SetModel( "tag_origin" );
efx_rot.angles = VectorToAngles( vec );
PlayFXOnTag( level._pipes._effect[ self.script_noteworthy ] , efx_rot, "tag_origin" );
level._pipes.num_pipe_fx++;
efx_rot RotatePitch( 90, time, 1, 1 );
wait time;
StopFXOnTag( level._pipes._effect[ self.script_noteworthy ] , efx_rot, "tag_origin" );
}
else
{
//do it once without checking for newer fx being played ( we're the newest )
PlayFX( level._pipes._effect[ self.script_noteworthy ], P, vec );
wait time;
intervals--;
}
}
snd PlaySound( endsnd );
wait( .5 );
snd StopLoopSound( loopsnd );
snd Delete();
self.pipe_fx_array = array_removeUndefined( self.pipe_fx_array );
level._pipes.num_pipe_fx--;
}
pipe_damage( P, vec, damageOwner, fx )
{
if ( !allow_pipe_damage() )
return;
fx endon( "death" );
origin = fx.origin + ( VectorNormalize( vec ) * 40 );
dmg = level._pipes._dmg[ self.script_noteworthy ];
while ( 1 )
{
// do not pass damage owner if they have disconnected before the barrels explode.. the barrels?
if ( !isdefined( self.damageOwner ) )
{
// MOD_TRIGGER_HURT so they dont do dirt on the player's screen
self RadiusDamage( origin, 36, dmg, dmg * 0.75, undefined, "MOD_TRIGGER_HURT" );
}
else
{
// MOD_TRIGGER_HURT so they dont do dirt on the player's screen
self RadiusDamage( origin, 36, dmg, dmg * 0.75, damageOwner, "MOD_TRIGGER_HURT" );
}
wait( 0.4 );
}
}
allow_pipe_damage()
{
if( !isSP() )
return false;
if ( !isDefined( level.pipesDamage ) )
return true;
return ( level.pipesDamage );
}
//////////////////////////////////////////////////////////////////////////////
// CALCULATIONS / SETUP //
//////////////////////////////////////////////////////////////////////////////
methodsInit()
{
level._pipes._pipe_methods = [];
level._pipes._pipe_methods[ "MOD_UNKNOWN" ] = ::pipe_calc_splash;
level._pipes._pipe_methods[ "MOD_PISTOL_BULLET" ] = ::pipe_calc_ballistic;
level._pipes._pipe_methods[ "MOD_RIFLE_BULLET" ] = ::pipe_calc_ballistic;
level._pipes._pipe_methods[ "MOD_GRENADE" ] = ::pipe_calc_splash;
level._pipes._pipe_methods[ "MOD_GRENADE_SPLASH" ] = ::pipe_calc_splash;
level._pipes._pipe_methods[ "MOD_PROJECTILE" ] = ::pipe_calc_splash;
level._pipes._pipe_methods[ "MOD_PROJECTILE_SPLASH" ] = ::pipe_calc_splash;
level._pipes._pipe_methods[ "MOD_TRIGGER_HURT" ] = ::pipe_calc_splash;
level._pipes._pipe_methods[ "MOD_EXPLOSIVE" ] = ::pipe_calc_splash;
level._pipes._pipe_methods[ "MOD_EXPLOSIVE_BULLET" ] = ::pipe_calc_splash;
}
pipe_calc_ballistic( P, type )
{
return P;
}
pipe_calc_splash( P, type )
{
vec = VectorNormalize( VectorFromLineToPoint( self.A, self.B, P ) );
P = PointOnSegmentNearestToPoint( self.A, self.B, P );
return( P + ( vec * 4 ) );
}
pipe_calc_nofx( P, type )
{
return undefined;
}
precacheFX()
{
steam = false;
fire = false;
steam_small = false;
oil_leak = false;
oil_cap = false;
foreach ( value in self )
{
if ( value.script_noteworthy == "water" )
value.script_noteworthy = "steam";
if ( value.script_noteworthy == "steam" )
{
value willNeverChange();
steam = true;
}
else if ( value.script_noteworthy == "fire" )
{
value willNeverChange();
fire = true;
}
else if ( value.script_noteworthy == "steam_small" )
{
value willNeverChange();
steam_small = true;
}
else if ( value.script_noteworthy == "oil_leak" )
{
value willNeverChange();
oil_leak = true;
}
else if ( value.script_noteworthy == "oil_cap" )
{
value willNeverChange();
oil_cap = true;
}
else
{
println( "Unknown 'pipe_shootable' script_noteworthy type '%s'\n", value.script_noteworthy );
}
}
if ( steam )
{
level._pipes._effect[ "steam" ] = LoadFX( "fx/impacts/pipe_steam" );
level._pipes._sound[ "steam_hit" ] = "mtl_steam_pipe_hit";
level._pipes._sound[ "steam_loop" ] = "mtl_steam_pipe_hiss_loop";
level._pipes._sound[ "steam_end" ] = "mtl_steam_pipe_hiss_loop_end";
level._pipes.fx_time[ "steam" ] = 3;
level._pipes._dmg[ "steam" ] = 5;
level._pipes._pipe_fx_time["steam"] = 25;
}
if ( steam_small )
{
level._pipes._effect[ "steam_small" ] = LoadFX( "fx/impacts/pipe_steam_small" );
level._pipes._sound[ "steam_small_hit" ] = "mtl_steam_pipe_hit";
level._pipes._sound[ "steam_small_loop" ] = "mtl_steam_pipe_hiss_loop";
level._pipes._sound[ "steam_small_end" ] = "mtl_steam_pipe_hiss_loop_end";
level._pipes.fx_time[ "steam_small" ] = 3;
level._pipes._dmg[ "steam_small" ] = 5;
level._pipes._pipe_fx_time["steam_small"] = 25;
}
if ( fire )
{
level._pipes._effect[ "fire" ] = LoadFX( "fx/impacts/pipe_fire" );
level._pipes._sound[ "fire_hit" ] = "mtl_gas_pipe_hit";
level._pipes._sound[ "fire_loop" ] = "mtl_gas_pipe_flame_loop";
level._pipes._sound[ "fire_end" ] = "mtl_gas_pipe_flame_end";
level._pipes.fx_time[ "fire" ] = 3;
level._pipes._dmg[ "fire" ] = 5;
level._pipes._pipe_fx_time["fire"] = 25;
}
if ( oil_leak )
{
level._pipes._effect[ "oil_leak" ] = LoadFX( "fx/impacts/pipe_oil_barrel_spill" );
// level._pipes._effect[ "oil_leak_end" ] = LoadFX( "fx/impacts/pipe_oil_barrel_spill_ending1" );
level._pipes._sound[ "oil_leak_hit" ] = "mtl_oil_barrel_hit";
level._pipes._sound[ "oil_leak_loop" ] = "mtl_oil_barrel_hiss_loop";
level._pipes._sound[ "oil_leak_end" ] = "mtl_oil_barrel_hiss_loop_end";
level._pipes.fx_time[ "oil_leak" ] = 6;
level._pipes._pipe_fx_time["oil_leak"] = 6;
level._pipes._dmg[ "oil_leak" ] = 5;
}
if ( oil_cap )
{
level._pipes._effect[ "oil_cap" ] = LoadFX( "fx/impacts/pipe_oil_barrel_squirt" );
level._pipes._sound[ "oil_cap_hit" ] = "mtl_steam_pipe_hit";
level._pipes._sound[ "oil_cap_loop" ] = "mtl_steam_pipe_hiss_loop";
level._pipes._sound[ "oil_cap_end" ] = "mtl_steam_pipe_hiss_loop_end";
level._pipes.fx_time[ "oil_cap" ] = 3;
level._pipes._dmg[ "oil_cap" ] = 5;
level._pipes._pipe_fx_time["oil_cap"] = 5;
}
}