#include common_scripts\utility; #include common_scripts\_createfx; CONST_MAX_SP_CREATEFX = 1500; CONST_MAX_SP_CREATESOUND = 384; initFX() { if ( !isdefined( level.func ) ) level.func = []; if ( !isdefined( level.func[ "create_triggerfx" ] ) ) level.func[ "create_triggerfx" ] = ::create_triggerfx; if ( !IsDefined( level._fx ) ) level._fx = SpawnStruct(); create_lock( "createfx_looper", 20 ); level.fxfireloopmod = 1; // wrapper for the exploder function so we dont have to use flags and do ifs/waittills on every exploder call level._fx.exploderFunction = common_scripts\_exploder::exploder_before_load; waittillframeend;// Wait one frame so the effects get setup by the maps fx thread waittillframeend;// Wait another frame so effects can be loaded based on start functions. Without this FX are initialiazed before they are defined by start functions. level._fx.exploderFunction = common_scripts\_exploder::exploder_after_load; level._fx.server_culled_sounds = false; if ( GetDvarInt( "serverCulledSounds" ) == 1 ) level._fx.server_culled_sounds = true; if ( level.createFX_enabled ) level._fx.server_culled_sounds = false; /# SetDevDvarIfUninitialized( "scr_map_exploder_dump", 0 ); SetDevDvarIfUninitialized( "createfx_removedupes", 0 ); if ( GetDvarInt( "r_reflectionProbeGenerate" ) == 1 ) level._fx.server_culled_sounds = true; #/ // Give createfx_common time to delete triggers to free up entity slots. if ( level.createFX_enabled ) { level waittill( "createfx_common_done" ); } /# remove_dupes(); #/ for ( i = 0; i < level.createFXent.size; i++ ) { ent = level.createFXent[ i ]; ent set_forward_and_up_vectors(); switch ( ent.v[ "type" ] ) { case "loopfx": ent thread loopfxthread(); break; case "oneshotfx": ent thread oneshotfxthread(); break; case "soundfx": ent thread create_loopsound(); break; case "soundfx_interval": ent thread create_interval_sound(); break; case "reactive_fx": ent add_reactive_fx(); break; } } check_createfx_limit(); } remove_dupes() { /# if ( GetDvarInt( "createfx_removedupes" ) == 0 ) return; new_ents = []; for ( i = 0; i < level.createFXent.size; i++ ) { add_ent = true; i_ent = level.createFXent[ i ]; for ( j = i + 1; j < level.createFXent.size; j++ ) { j_ent = level.createFXent[ j ]; if ( j_ent.v[ "type" ] == i_ent.v[ "type" ] ) { if ( j_ent.v[ "origin" ] == i_ent.v[ "origin" ] ) { println( "^3--REMOVING DUPE'D " + j_ent.v[ "type" ] + " AT " + j_ent.v[ "origin" ] ); add_ent = false; } } } if ( add_ent ) new_ents[ new_ents.size ] = i_ent; } level.createFXent = new_ents; #/ } check_createfx_limit() { /# if ( !isSP() ) { return; } fx_count = 0; sound_count = 0; foreach ( ent in level.createFXent ) { if ( is_createfx_type( ent, "fx" ) ) fx_count++; else if ( is_createfx_type( ent, "sound" ) ) sound_count++; } println( "^5Total CreateFX FX Ents: " + fx_count ); println( "^5Total CreateFX SOUND Ents: " + sound_count ); check_limit_type( "fx", fx_count ); check_limit_type( "sound", sound_count ); #/ } check_limit_type( type, count ) { /# limit = undefined; if ( type == "fx" ) { limit = CONST_MAX_SP_CREATEFX; } else if ( type == "sound" ) { limit = CONST_MAX_SP_CREATESOUND; } if ( count > limit ) AssertMsg( "CREATEFX: You have too many " + type + " createFX ents. You need to reduce the amount.\nYou have " + count + " and the limit is " + limit ); #/ } print_org( fxcommand, fxId, fxPos, waittime ) { if ( GetDvar( "debug" ) == "1" ) { println( "{" ); println( "\"origin\" \"" + fxPos[ 0 ] + " " + fxPos[ 1 ] + " " + fxPos[ 2 ] + "\"" ); println( "\"classname\" \"script_model\"" ); println( "\"model\" \"fx\"" ); println( "\"script_fxcommand\" \"" + fxcommand + "\"" ); println( "\"script_fxid\" \"" + fxId + "\"" ); println( "\"script_delay\" \"" + waittime + "\"" ); println( "}" ); } } OneShotfx( fxId, fxPos, waittime, fxPos2 ) { // level thread print_org ("OneShotfx", fxId, fxPos, waittime); // level thread OneShotfxthread (fxId, fxPos, waittime, fxPos2); } exploderfx( num, fxId, fxPos, waittime, fxPos2, fireFx, fireFxDelay, fireFxSound, fxSound, fxQuake, fxDamage, soundalias, repeat, delay_min, delay_max, damage_radius, fireFxTimeout, exploder_group ) { if ( 1 ) { ent = createExploder( fxId ); ent.v[ "origin" ] = fxPos; ent.v[ "angles" ] = ( 0, 0, 0 ); if ( isdefined( fxPos2 ) ) ent.v[ "angles" ] = vectortoangles( fxPos2 - fxPos ); ent.v[ "delay" ] = waittime; ent.v[ "exploder" ] = num; if (isdefined(level.createFXexploders)) { // if we're using the optimized lookup, add it in the proper place ary = level.createFXexploders[ ent.v[ "exploder" ] ]; if (!isdefined(ary)) ary = []; ary[ary.size] = ent; level.createFXexploders[ ent.v[ "exploder" ] ] = ary; } // deprecated return; } fx = spawn( "script_origin", ( 0, 0, 0 ) ); // println ("total ", getentarray ("script_origin","classname").size); fx.origin = fxPos; fx.angles = vectortoangles( fxPos2 - fxPos ); // fx.targetname = "exploder"; fx.script_exploder = num; fx.script_fxid = fxId; fx.script_delay = waittime; fx.script_firefx = fireFx; fx.script_firefxdelay = ( fireFxDelay );// for awhile the script exported strings for this value so we cast it to float fx.script_firefxsound = fireFxSound; fx.script_sound = fxSound; fx.script_earthquake = fxQuake; fx.script_damage = ( fxDamage ); fx.script_radius = ( damage_radius ); fx.script_soundalias = soundalias; fx.script_firefxtimeout = ( fireFxTimeout ); fx.script_repeat = ( repeat ); fx.script_delay_min = ( delay_min ); fx.script_delay_max = ( delay_max ); fx.script_exploder_group = exploder_group; forward = anglestoforward( fx.angles ); forward *= ( 150 ); fx.targetPos = fxPos + forward; if ( !isdefined( level._script_exploders ) ) level._script_exploders = []; level._script_exploders[ level._script_exploders.size ] = fx; } /* loopfxRotate(fxId, fxPos, waittime, angle, fxStart, fxStop, timeout) { level thread print_org ("loopfx", fxId, fxPos, waittime); level thread loopfxthread (fxId, fxPos, waittime, fxPos2, fxStart, fxStop, timeout); } */ loopfx( fxId, fxPos, waittime, fxPos2, fxStart, fxStop, timeout ) { println( "Loopfx is deprecated!" ); ent = createLoopEffect( fxId ); ent.v[ "origin" ] = fxPos; ent.v[ "angles" ] = ( 0, 0, 0 ); if ( isdefined( fxPos2 ) ) ent.v[ "angles" ] = vectortoangles( fxPos2 - fxPos ); ent.v[ "delay" ] = waittime; } /* loopfx(fxId, fxPos, waittime, fxPos2, fxStart, fxStop, timeout) { level thread print_org ("loopfx", fxId, fxPos, waittime); level thread loopfxthread (fxId, fxPos, waittime, fxPos2, fxStart, fxStop, timeout); } */ create_looper() { //assert (isdefined(self.looper)); self.looper = playLoopedFx( level._effect[ self.v[ "fxid" ] ], self.v[ "delay" ], self.v[ "origin" ], 0, self.v[ "forward" ], self.v[ "up" ] ); create_loopsound(); } create_loopsound() { self notify( "stop_loop" ); if ( !IsDefined( self.v[ "soundalias" ] ) ) return; if ( self.v[ "soundalias" ] == "nil" ) return; /# if ( GetDvar( "r_reflectionProbeGenerate" ) == "1" ) return; #/ culled = false; end_on = undefined; if ( isdefined( self.v[ "stopable" ] ) && self.v[ "stopable" ] ) { if ( IsDefined( self.looper ) ) end_on = "death"; else end_on = "stop_loop"; } else { if ( level._fx.server_culled_sounds && IsDefined( self.v[ "server_culled" ] ) ) culled = self.v[ "server_culled" ]; } ent = self; if ( IsDefined( self.looper ) ) ent = self.looper; createfx_ent = undefined; if ( level.createFX_enabled ) createfx_ent = self; ent loop_fx_sound_with_angles( self.v[ "soundalias" ], self.v[ "origin" ], self.v[ "angles" ], culled, end_on, createfx_ent ); } create_interval_sound() { self notify( "stop_loop" ); if ( !IsDefined( self.v[ "soundalias" ] ) ) return; if ( self.v[ "soundalias" ] == "nil" ) return; ender = undefined; runner = self; /# if ( GetDvar( "r_reflectionProbeGenerate" ) == "1" ) return; #/ if( ( IsDefined( self.v[ "stopable" ] ) && self.v[ "stopable" ] ) || level.createFX_enabled ) { if ( IsDefined( self.looper ) ) { runner = self.looper; ender = "death"; } else ender = "stop_loop"; } runner thread loop_fx_sound_interval_with_angles( self.v[ "soundalias" ], self.v[ "origin" ], self.v[ "angles" ], ender, undefined, self.v[ "delay_min" ], self.v[ "delay_max" ] ); } loopfxthread() { waitframe(); // println ( "fx testing running Id: ", fxId ); // if ((isdefined (level.scr_sound)) && (isdefined (level.scr_sound[fxId]))) // loopSound(level.scr_sound[fxId], fxPos); if ( isdefined( self.fxStart ) ) level waittill( "start fx" + self.fxStart ); while ( 1 ) { /* if (isdefined (ent.org2)) { fxAngle = vectorNormalize (ent.org2 - ent.org); looper = playLoopedFx( level._effect[fxId], ent.delay, ent.org, 0, fxAngle ); } else looper = playLoopedFx( level._effect[fxId], ent.delay, ent.org, 0 ); */ create_looper(); if ( isdefined( self.timeout ) ) thread loopfxStop( self.timeout ); if ( isdefined( self.fxStop ) ) level waittill( "stop fx" + self.fxStop ); else return; if ( isdefined( self.looper ) ) self.looper delete(); if ( isdefined( self.fxStart ) ) level waittill( "start fx" + self.fxStart ); else return; } } loopfxChangeID( ent ) { self endon( "death" ); ent waittill( "effect id changed", change ); } loopfxChangeOrg( ent ) { self endon( "death" ); for ( ;; ) { ent waittill( "effect org changed", change ); self.origin = change; } } loopfxChangeDelay( ent ) { self endon( "death" ); ent waittill( "effect delay changed", change ); } loopfxDeletion( ent ) { self endon( "death" ); ent waittill( "effect deleted" ); self delete(); } loopfxStop( timeout ) { self endon( "death" ); wait( timeout ); self.looper delete(); } loopSound( sound, Pos, waittime ) { // level thread print_org ("loopSound", sound, Pos, waittime); level thread loopSoundthread( sound, Pos, waittime ); } loopSoundthread( sound, pos, waittime ) { org = spawn( "script_origin", ( pos ) ); org.origin = pos; // println ("hello1 ", org.origin, sound); org playLoopSound( sound ); } gunfireloopfx( fxId, fxPos, shotsMin, shotsMax, shotdelayMin, shotdelayMax, betweenSetsMin, betweenSetsMax ) { thread gunfireloopfxthread( fxId, fxPos, shotsMin, shotsMax, shotdelayMin, shotdelayMax, betweenSetsMin, betweenSetsMax ); } gunfireloopfxthread( fxId, fxPos, shotsMin, shotsMax, shotdelayMin, shotdelayMax, betweenSetsMin, betweenSetsMax ) { level endon( "stop all gunfireloopfx" ); waitframe(); if ( betweenSetsMax < betweenSetsMin ) { temp = betweenSetsMax; betweenSetsMax = betweenSetsMin; betweenSetsMin = temp; } betweenSetsBase = betweenSetsMin; betweenSetsRange = betweenSetsMax - betweenSetsMin; if ( shotdelayMax < shotdelayMin ) { temp = shotdelayMax; shotdelayMax = shotdelayMin; shotdelayMin = temp; } shotdelayBase = shotdelayMin; shotdelayRange = shotdelayMax - shotdelayMin; if ( shotsMax < shotsMin ) { temp = shotsMax; shotsMax = shotsMin; shotsMin = temp; } shotsBase = shotsMin; shotsRange = shotsMax - shotsMin; fxEnt = spawnFx( level._effect[ fxId ], fxPos ); if ( !level.createFX_enabled ) fxEnt willNeverChange(); for ( ;; ) { shotnum = shotsBase + randomint( shotsRange ); for ( i = 0;i < shotnum;i++ ) { triggerFx( fxEnt ); wait( shotdelayBase + randomfloat( shotdelayRange ) ); } wait( betweenSetsBase + randomfloat( betweenSetsRange ) ); } } gunfireloopfxVec( fxId, fxPos, fxPos2, shotsMin, shotsMax, shotdelayMin, shotdelayMax, betweenSetsMin, betweenSetsMax ) { thread gunfireloopfxVecthread( fxId, fxPos, fxPos2, shotsMin, shotsMax, shotdelayMin, shotdelayMax, betweenSetsMin, betweenSetsMax ); } gunfireloopfxVecthread( fxId, fxPos, fxPos2, shotsMin, shotsMax, shotdelayMin, shotdelayMax, betweenSetsMin, betweenSetsMax ) { level endon( "stop all gunfireloopfx" ); waitframe(); if ( betweenSetsMax < betweenSetsMin ) { temp = betweenSetsMax; betweenSetsMax = betweenSetsMin; betweenSetsMin = temp; } betweenSetsBase = betweenSetsMin; betweenSetsRange = betweenSetsMax - betweenSetsMin; if ( shotdelayMax < shotdelayMin ) { temp = shotdelayMax; shotdelayMax = shotdelayMin; shotdelayMin = temp; } shotdelayBase = shotdelayMin; shotdelayRange = shotdelayMax - shotdelayMin; if ( shotsMax < shotsMin ) { temp = shotsMax; shotsMax = shotsMin; shotsMin = temp; } shotsBase = shotsMin; shotsRange = shotsMax - shotsMin; fxPos2 = vectornormalize( fxPos2 - fxPos ); fxEnt = spawnFx( level._effect[ fxId ], fxPos, fxPos2 ); if ( !level.createFX_enabled ) fxEnt willNeverChange(); for ( ;; ) { shotnum = shotsBase + randomint( shotsRange ); for ( i = 0;i < int( shotnum / level.fxfireloopmod );i++ ) { triggerFx( fxEnt ); delay = ( ( shotdelayBase + randomfloat( shotdelayRange ) ) * level.fxfireloopmod ); if ( delay < .05 ) delay = .05; wait delay; } wait( shotdelayBase + randomfloat( shotdelayRange ) ); wait( betweenSetsBase + randomfloat( betweenSetsRange ) ); } } setfireloopmod( value ) { level.fxfireloopmod = 1 / value; } setup_fx() { if ( ( !isdefined( self.script_fxid ) ) || ( !isdefined( self.script_fxcommand ) ) || ( !isdefined( self.script_delay ) ) ) { // println (self.script_fxid); // println (self.script_fxcommand); // println (self.script_delay); // println ("Effect at origin ", self.origin," doesn't have script_fxid/script_fxcommand/script_delay"); // self delete(); return; } // println ("^a Command:", self.script_fxcommand, " Effect:", self.script_fxID, " Delay:", self.script_delay, " ", self.origin); if ( isdefined( self.model ) ) if ( self.model == "toilet" ) { self thread burnville_paratrooper_hack(); return; } org = undefined; if ( isdefined( self.target ) ) { ent = getent( self.target, "targetname" ); if ( isdefined( ent ) ) org = ent.origin; } fxStart = undefined; if ( isdefined( self.script_fxstart ) ) fxStart = self.script_fxstart; fxStop = undefined; if ( isdefined( self.script_fxstop ) ) fxStop = self.script_fxstop; if ( self.script_fxcommand == "OneShotfx" ) OneShotfx( self.script_fxId, self.origin, self.script_delay, org ); if ( self.script_fxcommand == "loopfx" ) loopfx( self.script_fxId, self.origin, self.script_delay, org, fxStart, fxStop ); if ( self.script_fxcommand == "loopsound" ) loopsound( self.script_fxId, self.origin, self.script_delay ); self delete(); } burnville_paratrooper_hack() { normal = ( 0, 0, self.angles[ 1 ] ); // println ("z: paratrooper fx hack: ", normal); id = level._effect[ self.script_fxId ]; origin = self.origin; // if (isdefined (self.script_delay)) // wait (self.script_delay); wait 1; level thread burnville_paratrooper_hack_loop( normal, origin, id ); self delete(); } burnville_paratrooper_hack_loop( normal, origin, id ) { while ( 1 ) { // iprintln ("z: playing paratrooper fx", origin); playfx( id, origin ); wait( 30 + randomfloat( 40 ) ); } } create_triggerfx() { //assert (isdefined(self.looper)); if( ! verify_effects_assignment( self.v[ "fxid" ] ) ) return; self.looper = spawnFx( level._effect[ self.v[ "fxid" ] ], self.v[ "origin" ], self.v[ "forward" ], self.v[ "up" ] ); triggerFx( self.looper, self.v[ "delay" ] ); if ( !level.createFX_enabled ) self.looper willNeverChange(); create_loopsound(); } verify_effects_assignment( effectID ) { if( isdefined ( level._effect[ effectID ] ) ) return true; if( ! isdefined( level._missing_FX ) ) level._missing_FX = []; level._missing_FX[ self.v[ "fxid" ] ] = effectID; verify_effects_assignment_print( effectID ); return false; } verify_effects_assignment_print( effectID ) { level notify ( "verify_effects_assignment_print" ); level endon ( "verify_effects_assignment_print" ); wait .05; //allow errors on the same frame to que up before printing println("Error:"); println("Error:**********MISSING EFFECTS IDS**********"); keys = getarraykeys( level._missing_FX ); foreach( key in keys ) { println( "Error: Missing Effects ID assignment for: "+ key ); } println("Error:"); assertmsg( "Missing Effects ID assignments ( see console )" ); } OneShotfxthread() { wait(0.05); if ( self.v[ "delay" ] > 0 ) wait self.v[ "delay" ]; [[ level.func[ "create_triggerfx" ] ]](); } //--------------------------------------------------------- // Reactive Section //--------------------------------------------------------- CONST_MAX_REACTIVE_SOUND_ENTS = 4; CONST_NEXT_PLAY_TIME = 3000; add_reactive_fx() { // MP should not start this thread in release if ( !isSP() && GetDVar( "createfx" ) == "" ) { return; } if ( !IsDefined( level._fx.reactive_thread ) ) { level._fx.reactive_thread = true; level thread reactive_fx_thread(); } if ( !IsDefined( level._fx.reactive_fx_ents ) ) { level._fx.reactive_fx_ents = []; } level._fx.reactive_fx_ents[ level._fx.reactive_fx_ents.size ] = self; self.next_reactive_time = 3000; } reactive_fx_thread() { if ( !isSp() ) { if ( GetDvar( "createfx" ) == "on" ) { // wait till the player spawns and createfxlogic starts before continuing. flag_wait( "createfx_started" ); } } // TODO: Switch to using level notify instead // HOWEVER!!! we will need the trigger_radius for when we are in CREATEFX mode for MP only!!! // use level.mp_createfx condition // trigger = Spawn( "trigger_radius", level.player.origin, 0, 5000, 5000 ); // trigger SetCanDamage( true ); // trigger EnableLinkTo(); // trigger LinkTo( level.player ); level._fx.reactive_sound_ents = []; explosion_radius = 256; while ( 1 ) { // trigger waittill( "damage", dmg, attacker, dir_vec, point, type ); level waittill( "code_damageradius", attacker, explosion_radius, point, weapon_name ); ents = sort_reactive_ents( point, explosion_radius ); foreach ( i, ent in ents ) ent thread play_reactive_fx( i ); } } vector2d( vec ) { return ( vec[ 0 ], vec[ 1 ], 0 ); } sort_reactive_ents( point, explosion_radius ) { closest = []; time = GetTime(); foreach ( ent in level._fx.reactive_fx_ents ) { if ( ent.next_reactive_time > time ) continue; radius_squared = ent.v[ "reactive_radius" ] + explosion_radius; radius_squared *= radius_squared; if ( DistanceSquared( point, ent.v[ "origin" ] ) < radius_squared ) { closest[ closest.size ] = ent; } } foreach ( ent in closest ) { playerToEnt = vector2d( ent.v[ "origin" ] - level.player.origin ); playerToPoint = vector2d( point - level.player.origin ); vec1 = VectorNormalize( playerToEnt ); vec2 = VectorNormalize( playerToPoint ); ent.dot = VectorDot( vec1, vec2 ); } // Sort from lowest dot to greatest for ( i = 0; i < closest.size - 1; i++ ) { for ( j = i + 1; j < closest.size; j++ ) { if ( closest[ i ].dot > closest[ j ].dot ) { temp = closest[ i ]; closest[ i ] = closest[ j ]; closest[ j ] = temp; } } } // remove the .origin and .dot since we're done with sortbydistance() foreach ( ent in closest ) { ent.origin = undefined; ent.dot = undefined; } // Make sure we only have 4 for ( i = CONST_MAX_REACTIVE_SOUND_ENTS; i < closest.size; i++ ) { closest[ i ] = undefined; } return closest; } play_reactive_fx( num ) { sound_ent = get_reactive_sound_ent(); if ( !IsDefined( sound_ent ) ) return; /# self.is_playing = true; #/ self.next_reactive_time = GeTTime() + CONST_NEXT_PLAY_TIME; sound_ent.origin = self.v[ "origin" ]; sound_ent.is_playing = true; wait( num * RandomFloatRange( 0.05, 0.1 ) ); if ( isSP() ) { sound_ent PlaySound( self.v[ "soundalias" ], "sounddone" ); sound_ent waittill( "sounddone" ); } else { sound_ent PlaySound( self.v[ "soundalias" ] ); wait( 2 ); } // wait for sounddone to be removed compeletely // bug in prague port to iw6 where in the same frame this got called again after the sounddone notify // odd thing, even 0.05 doesn't work. Code should fix this! wait( 0.1 ); sound_ent.is_playing = false; /# self.is_playing = undefined; #/ } get_reactive_sound_ent() { foreach ( ent in level._fx.reactive_sound_ents ) { if ( !ent.is_playing ) return ent; } if ( level._fx.reactive_sound_ents.size < CONST_MAX_REACTIVE_SOUND_ENTS ) { ent = Spawn( "script_origin", ( 0, 0, 0 ) ); ent.is_playing = false; level._fx.reactive_sound_ents[ level._fx.reactive_sound_ents.size ] = ent; return ent; } return undefined; }