1423 lines
36 KiB
Plaintext
1423 lines
36 KiB
Plaintext
#include maps\mp\_utility;
|
|
#include common_scripts\utility;
|
|
|
|
main()
|
|
{
|
|
maps\mp\mp_ca_rumble_precache::main();
|
|
maps\createart\mp_ca_rumble_art::main();
|
|
maps\mp\mp_ca_rumble_fx::main();
|
|
|
|
level thread update_mortars(); //setup and update.
|
|
level.air_raid_active = false;
|
|
level.mapCustomCrateFunc = ::rumbleCustomCrateFunc;
|
|
level.mapCustomKillstreakFunc = ::rumbleCustomKillstreakFunc;
|
|
level.mapCustomBotKillstreakFunc = ::rumbleCustomBotKillstreakFunc;
|
|
|
|
maps\mp\_load::main();
|
|
|
|
// AmbientPlay( "ambient_mp_setup_template" );
|
|
|
|
maps\mp\_compass::setupMiniMap( "compass_map_mp_ca_rumble" );
|
|
|
|
setdvar( "r_lightGridEnableTweaks", 1 );
|
|
setdvar( "r_lightGridIntensity", 1.33 );
|
|
|
|
if ( level.ps3 )
|
|
{
|
|
SetDvar( "sm_sunShadowScale", "0.55" ); // ps3 optimization
|
|
SetDvar( "sm_sunsamplesizenear", ".15" );
|
|
}
|
|
else if ( level.xenon )
|
|
{
|
|
SetDvar( "sm_sunShadowScale", "0.56" +
|
|
"" ); // optimization
|
|
SetDvar( "sm_sunsamplesizenear", ".22" );
|
|
}
|
|
else
|
|
{
|
|
SetDvar( "sm_sunShadowScale", "0.9" ); // optimization
|
|
SetDvar( "sm_sunsamplesizenear", ".27" );
|
|
}
|
|
|
|
setdvar_cg_ng( "r_specularColorScale", 1.7, 5 );
|
|
|
|
game["attackers"] = "allies";
|
|
game["defenders"] = "axis";
|
|
|
|
game[ "allies_outfit" ] = "urban";
|
|
game[ "axis_outfit" ] = "woodland";
|
|
|
|
fixMLGCameraPosition();
|
|
|
|
thread setup_fish();
|
|
thread setup_destructibles();
|
|
thread setup_metal_detectors();
|
|
thread setup_watertanks();
|
|
thread setup_bouys();
|
|
thread setup_dock_boats();
|
|
thread setup_monitors();
|
|
|
|
thread update_destroyer();
|
|
thread update_trolley();
|
|
thread update_lighthouse_light();
|
|
|
|
thread setup_fountain_fx();
|
|
|
|
thread update_artillery_fx();
|
|
thread update_heli_fx();
|
|
thread update_flybyjet_fx();
|
|
|
|
thread maps\mp\_dlcalienegg::setupEggForMap( "alienEasterEgg" );
|
|
level thread initExtraCollision();
|
|
}
|
|
|
|
initExtraCollision()
|
|
{
|
|
collision1 = GetEnt( "clip128x128x256", "targetname" );
|
|
collision1Ent = spawn( "script_model", (-459.25, 1848, 487.75) );
|
|
collision1Ent.angles = ( 270, 322.793, 37.2067);
|
|
collision1Ent CloneBrushmodelToScriptmodel( collision1 );
|
|
|
|
collision2 = GetEnt( "clip256x256x128", "targetname" );
|
|
collision2Ent = spawn( "script_model", (-1984, 344, -120) );
|
|
collision2Ent.angles = (0,0,0);
|
|
collision2Ent CloneBrushmodelToScriptmodel( collision2 );
|
|
}
|
|
|
|
RUMBLE_MORTARS_WEIGHT = 85;
|
|
rumbleCustomCrateFunc()
|
|
{
|
|
if(!IsDefined(game["player_holding_level_killstrek"]))
|
|
game["player_holding_level_killstrek"] = false;
|
|
|
|
if(!allowLevelKillstreaks() || game["player_holding_level_killstrek"])
|
|
return;
|
|
|
|
maps\mp\killstreaks\_airdrop::addCrateType( "airdrop_assault", "warhawk_mortars", RUMBLE_MORTARS_WEIGHT, maps\mp\killstreaks\_airdrop::killstreakCrateThink, maps\mp\killstreaks\_airdrop::get_friendly_crate_model(), maps\mp\killstreaks\_airdrop::get_enemy_crate_model(), &"KILLSTREAKS_HINTS_WARHAWK_MORTARS" );
|
|
level thread watch_for_rumble_mortars_crate();
|
|
}
|
|
|
|
watch_for_rumble_mortars_crate()
|
|
{
|
|
while(1)
|
|
{
|
|
level waittill("createAirDropCrate", dropCrate);
|
|
|
|
if(IsDefined(dropCrate) && IsDefined(dropCrate.crateType) && dropCrate.crateType=="warhawk_mortars")
|
|
{
|
|
maps\mp\killstreaks\_airdrop::changeCrateWeight("airdrop_assault", "warhawk_mortars", 0);
|
|
captured = wait_for_capture(dropCrate);
|
|
|
|
if(!captured)
|
|
{
|
|
//reEnable warhawk mortars care packages if it expires with out anyone picking it up
|
|
maps\mp\killstreaks\_airdrop::changeCrateWeight("airdrop_assault", "warhawk_mortars", RUMBLE_MORTARS_WEIGHT);
|
|
}
|
|
else
|
|
{
|
|
//Once its picked up it needs to remain off.
|
|
game["player_holding_level_killstrek"] = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//death and capture are sent on the same frame but death is processed first :(
|
|
wait_for_capture(dropCrate)
|
|
{
|
|
result = watch_for_air_drop_death(dropCrate);
|
|
return !IsDefined(result); //If !isdefined the captured notify was also sent.
|
|
}
|
|
|
|
watch_for_air_drop_death(dropCrate)
|
|
{
|
|
dropCrate endon("captured");
|
|
|
|
dropCrate waittill("death");
|
|
waittillframeend;
|
|
|
|
return true;
|
|
}
|
|
|
|
rumbleCustomKillstreakFunc()
|
|
{
|
|
AddDebugCommand("devgui_cmd \"MP/Killstreak/Level Event:5/Care Package/Rumble Mortars\" \"set scr_devgivecarepackage warhawk_mortars; set scr_devgivecarepackagetype airdrop_assault\"\n");
|
|
AddDebugCommand("devgui_cmd \"MP/Killstreak/Level Event:5/Rumble Mortars\" \"set scr_givekillstreak warhawk_mortars\"\n");
|
|
|
|
level.killStreakFuncs[ "warhawk_mortars" ] = ::tryUseRumbleMortars;
|
|
|
|
level.killstreakWeildWeapons["warhawk_mortar_mp"] ="warhawk_mortars";
|
|
}
|
|
|
|
rumbleCustomBotKillstreakFunc()
|
|
{
|
|
AddDebugCommand("devgui_cmd \"MP/Bots(Killstreak)/Level Events:5/Rumble Mortars\" \"set scr_testclients_givekillstreak warhawk_mortars\"\n");
|
|
maps\mp\bots\_bots_ks::bot_register_killstreak_func( "warhawk_mortars", maps\mp\bots\_bots_ks::bot_killstreak_simple_use );
|
|
}
|
|
|
|
tryUseRumbleMortars(lifeId, streakName)
|
|
{
|
|
if(level.air_raid_active)
|
|
{
|
|
self iPrintLnBold( &"KILLSTREAKS_AIR_SPACE_TOO_CROWDED" );
|
|
return false;
|
|
}
|
|
|
|
game["player_holding_level_killstrek"] = false;
|
|
level notify("rumble_mortar_killstreak", self);
|
|
|
|
return true;
|
|
}
|
|
|
|
mortars_activate_at_end_of_match()
|
|
{
|
|
level endon( "rumble_mortar_killstreak" );
|
|
level waittill ( "spawning_intermission" );
|
|
level.ending_flourish = true;
|
|
mortar_fire(0.1,0.3,6,level.players[0]);
|
|
}
|
|
|
|
|
|
update_mortars()
|
|
{
|
|
level endon("stop_dynamic_events");
|
|
|
|
waitframe(); //allow load main to finish
|
|
|
|
//Build list of structs
|
|
level.mortar_sources = getstructarray("rumble_mortar_source", "targetname");
|
|
foreach(source in level.mortar_sources)
|
|
{
|
|
if(!IsDefined(source.radius))
|
|
source.radius = 300;
|
|
}
|
|
|
|
level.mortar_targets = getstructarray("rumble_mortar_target", "targetname");
|
|
foreach(mortart_target in level.mortar_targets)
|
|
{
|
|
if(!IsDefined(mortart_target.radius))
|
|
mortart_target.radius = 100;
|
|
}
|
|
|
|
while(1)
|
|
{
|
|
level.air_raid_active = false;
|
|
level.air_raid_team_called = "none";
|
|
thread mortars_activate_at_end_of_match();
|
|
level waittill("rumble_mortar_killstreak", player);
|
|
level.air_raid_active = true;
|
|
level.air_raid_team_called = player.team;
|
|
thread mortar_siren(10);
|
|
wait 3; //Delay between siren start and mortar fire
|
|
mortar_fire(.5,.6, 25, player);
|
|
}
|
|
}
|
|
|
|
mortar_siren(siren_time)
|
|
{
|
|
if(!IsDefined(level.mortar_siren_ent))
|
|
{
|
|
level.mortar_siren_ent = getEnt("mortar_siren", "targetname");
|
|
}
|
|
|
|
if(IsDefined(level.mortar_siren_ent))
|
|
{
|
|
level.mortar_siren_ent PlaySound("mortar_siren");
|
|
}
|
|
wait siren_time;
|
|
|
|
if(IsDefined(level.mortar_siren_ent))
|
|
{
|
|
level.mortar_siren_ent StopSounds();
|
|
}
|
|
}
|
|
|
|
mortar_fire(delay_min, delay_max, mortar_time_sec, owner)
|
|
{
|
|
motar_strike_end_time = GetTime() + mortar_time_sec*1000;
|
|
|
|
//pick team appropriate for owner team
|
|
source_structs = random_mortars_get_source_structs(level.air_raid_team_called);
|
|
if (source_structs.size <= 0)
|
|
{
|
|
PrintLn("Rumble Mortars: Didn't find any sources: targetname = rumble_mortar_source");
|
|
return;
|
|
}
|
|
|
|
air_raid_num = 0;
|
|
while(motar_strike_end_time>GetTime())
|
|
{
|
|
mortars_per_loop = 12;
|
|
mortars_launched = 0;
|
|
foreach(player in level.players)
|
|
{
|
|
if(!isReallyAlive(player))
|
|
continue;
|
|
|
|
if(level.teamBased)
|
|
{
|
|
if(player.team == level.air_raid_team_called)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if( IsDefined( owner ) && player == owner)
|
|
continue;
|
|
}
|
|
|
|
if(player.spawnTime+8000>GetTime())
|
|
continue;
|
|
|
|
vel = player GetVelocity();
|
|
|
|
mortar_air_time = RandomFloatRange(3,4);
|
|
|
|
mortar_target_pos = player.origin + (vel*mortar_air_time);
|
|
|
|
nodes_near = GetNodesInRadiusSorted(mortar_target_pos,100,0,60);
|
|
foreach(node in nodes_near)
|
|
{
|
|
if(NodeExposedToSky(node))
|
|
{
|
|
source_struct = random(source_structs);
|
|
|
|
if( random_mortars_fire( source_struct.origin, node.origin, undefined, owner, true, true ) )
|
|
{
|
|
wait RandomFloatRange(delay_min, delay_max);
|
|
mortars_launched++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//If there weren't enough player targets, drop the rest randomly:
|
|
if (level.mortar_targets.size > 0)
|
|
{
|
|
source_structs = array_randomize(source_structs);
|
|
while(mortars_launched<mortars_per_loop)
|
|
{
|
|
source_struct = source_structs[air_raid_num];
|
|
air_raid_num++;
|
|
if(air_raid_num>=source_structs.size)
|
|
air_raid_num = 0;//loop
|
|
|
|
target_struct = random(level.mortar_targets);
|
|
|
|
start = random_point_in_circle(source_struct.origin, source_struct.radius);
|
|
end = random_point_in_circle(target_struct.origin, target_struct.radius);
|
|
thread random_mortars_fire( start, end, undefined, owner, false, true);
|
|
wait RandomFloatRange(delay_min, delay_max);
|
|
mortars_launched++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break; // no targets!
|
|
}
|
|
}
|
|
}
|
|
|
|
random_point_in_circle(origin, radius)
|
|
{
|
|
if(radius>0)
|
|
{
|
|
rand_dir = AnglesToForward((0,RandomFloatRange(0,360),0));
|
|
rand_radius = RandomFloatRange(0, radius);
|
|
origin = origin + (rand_dir*rand_radius);
|
|
}
|
|
|
|
return origin;
|
|
}
|
|
|
|
random_mortars_fire( start_org, end_org, air_time, owner, trace_test, play_fx )
|
|
{
|
|
PlaySoundAtPos( start_org, "mortar_launch" );
|
|
|
|
gravity = (0,0,-800);
|
|
|
|
if(!IsDefined(air_time))
|
|
{
|
|
if ( IsDefined( level.ending_flourish ) && level.ending_flourish )
|
|
air_time = 2.5;
|
|
else
|
|
air_time = RandomFloatRange( 10.0, 12.0 );
|
|
}
|
|
launch_dir = TrajectoryCalculateInitialVelocity(start_org, end_org, gravity, air_time);
|
|
|
|
if(IsDefined(trace_test) && trace_test)
|
|
{
|
|
delta_height = TrajectoryComputeDeltaHeightAtTime(launch_dir[2], -1*gravity[2], air_time/2);
|
|
trace_point = ((end_org - start_org)/2) + start_org + (0,0,delta_height);
|
|
|
|
//self thread drawLine(trace_point, end_org, 60*10, (0,1,0));
|
|
if(BulletTracePassed(trace_point, end_org, false, undefined))
|
|
{
|
|
thread random_mortars_fire_run( start_org, end_org, air_time, owner, launch_dir, play_fx );
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
random_mortars_fire_run( start_org, end_org, air_time, owner, launch_dir, play_fx );
|
|
}
|
|
|
|
random_mortars_fire_run( start_org, end_org, air_time, owner, launch_dir, play_fx )
|
|
{
|
|
dirt_effect_radius = 350;
|
|
|
|
mortar_model = random_mortars_get_model(start_org);
|
|
mortar_model.origin = start_org;
|
|
mortar_model.in_use = true;
|
|
|
|
waitframe();//Model may have just spawned
|
|
PlayFXOnTag( getfx("random_mortars_trail"), mortar_model, "tag_fx");
|
|
|
|
mortar_model.angles = VectorToAngles(launch_dir) * (-1,1,1);
|
|
|
|
delayThread(air_time-2.0, ::random_mortars_incoming_sound, end_org);
|
|
|
|
mortar_model MoveGravity(launch_dir, air_time - 0.05); // dial back by a frame so the mortar/killcam doesn't go below ground.
|
|
mortar_model waittill("movedone");
|
|
|
|
if(level.createFX_enabled && !IsDefined(level.players))
|
|
level.players = [];
|
|
|
|
if(IsDefined(owner))
|
|
{
|
|
mortar_model RadiusDamage(end_org, 250, 750, 500, owner, "MOD_EXPLOSIVE", "warhawk_mortar_mp");
|
|
}
|
|
else
|
|
{
|
|
mortar_model RadiusDamage(end_org, 140, 5, 5, undefined, "MOD_EXPLOSIVE", "warhawk_mortar_mp");
|
|
}
|
|
PlayRumbleOnPosition("artillery_rumble", end_org);
|
|
|
|
//Dirt effect on Players:
|
|
dirt_effect_radiusSq = dirt_effect_radius * dirt_effect_radius;
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( player isUsingRemote() )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( DistanceSquared( end_org, player.origin ) > dirt_effect_radiusSq )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( player DamageConeTrace( end_org ) )
|
|
{
|
|
player thread maps\mp\gametypes\_shellshock::dirtEffect( end_org );
|
|
}
|
|
}
|
|
|
|
if( play_fx )
|
|
{
|
|
PlayFX( getfx("mortar_impact_00"), end_org);
|
|
}
|
|
|
|
mortar_model Delete();
|
|
}
|
|
|
|
random_mortars_incoming_sound(org)
|
|
{
|
|
PlaySoundAtPos( org, "mortar_incoming" );
|
|
}
|
|
|
|
random_mortars_get_model(origin)
|
|
{
|
|
mortar_model = spawn("script_model", origin);
|
|
mortar_model SetModel("projectile_rpg7");
|
|
return mortar_model;
|
|
}
|
|
|
|
random_mortars_get_source_structs( owner_team )
|
|
{
|
|
source_structs = [];
|
|
|
|
if( level.teamBased )
|
|
{
|
|
foreach( struct in level.mortar_sources )
|
|
{
|
|
if (IsDefined(struct.script_team) && struct.script_team == owner_team )
|
|
source_structs[source_structs.size] = struct;
|
|
}
|
|
}
|
|
|
|
//No approprate team source, just use any:
|
|
if (source_structs.size == 0)
|
|
source_structs = level.mortar_sources;
|
|
|
|
return source_structs;
|
|
}
|
|
|
|
setup_destructibles()
|
|
{
|
|
orcas = GetEntArray("dest_orca", "targetname");
|
|
sharks = GetEntArray("dest_shark", "targetname");
|
|
if(sharks.size)
|
|
{
|
|
foreach(shark in sharks)
|
|
shark thread update_destructibles(level._effect["vfx_mp_ca_rumble_shark_hit"], level._effect["vfx_mp_ca_rumble_shark_death"]);
|
|
}
|
|
if(orcas.size)
|
|
{
|
|
foreach(orca in orcas)
|
|
orca thread update_destructibles(level._effect["vfx_mp_ca_rumble_orca_hit"], level._effect["vfx_mp_ca_rumble_orca_death"]);
|
|
}
|
|
}
|
|
|
|
update_destructibles(effect_id, death_effect_id)
|
|
{
|
|
//PrintLn( "Spawning a destructible!" );
|
|
self Show();
|
|
self SetCanDamage( true );
|
|
explosionDirection = undefined;
|
|
|
|
hitCounter = RandomIntRange( 2, 4 );
|
|
while ( hitCounter > 0 )
|
|
{
|
|
self waittill( "damage", amount, attacker, direction_vec, hit_point, damage_type );
|
|
|
|
hitCounter--;
|
|
explosionDirection = direction_vec;
|
|
thread play_hit( effect_id, hit_point, direction_vec);
|
|
|
|
if ( IsSubStr( damage_type, "MELEE") || IsSubStr( damage_type, "GRENADE" ) )
|
|
{
|
|
hitCounter = 0;
|
|
}
|
|
else if ( IsSubStr( damage_type, "BULLET" ) )
|
|
{
|
|
if ( amount > 60.0 )
|
|
{
|
|
hitCounter = 0;
|
|
}
|
|
else
|
|
{
|
|
if ( IsDefined( attacker ) && IsDefined( attacker GetCurrentWeapon() ) && ( WeaponClass( attacker GetCurrentWeapon() ) == "sniper" ) )
|
|
{
|
|
hitCounter = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// if this wasn't a grenade explosion, don't fire off the final effect again
|
|
if (!IsDefined(explosionDirection))
|
|
self waittill( "damage", amount, attacker, direction_vec, hit_point, damage_type );
|
|
else
|
|
direction_vec = explosionDirection;
|
|
|
|
// hide it, set it so it can't be damaged
|
|
self Hide();
|
|
self SetCanDamage( false);
|
|
|
|
// play the final hit effect at the object's origin
|
|
thread play_hit( death_effect_id, self GetOrigin(), direction_vec);
|
|
|
|
//PrintLn("A destructible has been destroyed");
|
|
//wait 5.0;
|
|
//self thread update_destructibles(effect_id, death_effect_id);
|
|
}
|
|
|
|
play_hit( effect_id, spawn_point, spawn_dir)
|
|
{
|
|
//PrintLn("Playing hit!");
|
|
vfx_ent = SpawnFx( effect_id, spawn_point, AnglesToForward( spawn_dir ), AnglesToUp( spawn_dir ) );
|
|
TriggerFX( vfx_ent );
|
|
wait 5.0;
|
|
vfx_ent Delete();
|
|
}
|
|
|
|
#using_animtree( "mp_ca_rumble_animtree" );
|
|
setup_fish()
|
|
{
|
|
//PrintLn( "OZZ>***** Getting fish *****" );
|
|
|
|
// get the fish entity
|
|
fish = GetEnt( "bannerfish", "targetname");
|
|
// if it is defined, thread it
|
|
if (IsDefined(fish))
|
|
{
|
|
fish thread update_fish();
|
|
}
|
|
|
|
}
|
|
|
|
update_fish()
|
|
{
|
|
//PrintLn("OZZ>Entering fish updaters");
|
|
while ( 1 )
|
|
{
|
|
// pick a random integer
|
|
testInt = RandomInt(3);
|
|
self ScriptModelClearAnim();
|
|
if (testInt == 0)
|
|
{
|
|
//PrintLn("OZZ>Playing Animation A");
|
|
self ScriptModelPlayAnim("mp_ca_rumble_fish_swim_anim");
|
|
wait( GetAnimLength( %mp_ca_rumble_fish_swim_anim ) );
|
|
}
|
|
else if (testInt == 1)
|
|
{
|
|
//PrintLn("OZZ>Playing Animation B");
|
|
self ScriptModelPlayAnim("mp_ca_rumble_fish_swim_anim_b");
|
|
wait( GetAnimLength( %mp_ca_rumble_fish_swim_anim_b ) );
|
|
}
|
|
else
|
|
{
|
|
//PrintLn("OZZ>Playing Animation C");
|
|
self ScriptModelPlayAnim("mp_ca_rumble_fish_swim_anim_c");
|
|
wait( GetAnimLength( %mp_ca_rumble_fish_swim_anim_c ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
setup_metal_detectors()
|
|
{
|
|
metal_detectors = GetEntArray( "metal_detector_trigger", "targetname" );
|
|
if ( metal_detectors.size > 0 )
|
|
array_thread( metal_detectors, ::update_metal_detector );
|
|
}
|
|
|
|
update_metal_detector()
|
|
{
|
|
self endon( "detector_destroyed" );
|
|
|
|
my_devices = [];
|
|
detector_devices = GetEntArray( "metal_detector_device", "targetname" );
|
|
foreach ( device in detector_devices )
|
|
{
|
|
if ( DistanceSquared( device.origin, self.origin ) < 10000.0 )
|
|
{
|
|
device.md_health = 100.0;
|
|
device.light_on = GetEnt( device.target, "targetname" );
|
|
device.light_off = GetEnt( device.light_on.target, "targetname" );
|
|
device.light_broke = GetEnt( device.light_off.target, "targetname" );
|
|
device thread metal_detector_damage_monitor( self );
|
|
my_devices = array_add( my_devices, device );
|
|
}
|
|
}
|
|
|
|
self thread metal_detector_monitor_alive( my_devices );
|
|
while ( 1 )
|
|
{
|
|
foreach ( device in my_devices )
|
|
device thread metal_detector_on();
|
|
|
|
self waittill( "trigger" );
|
|
|
|
foreach ( device in my_devices )
|
|
device thread metal_detector_off();
|
|
|
|
wait 5.0;
|
|
}
|
|
}
|
|
|
|
metal_detector_monitor_alive( my_devices )
|
|
{
|
|
self waittill( "detector_damaged" );
|
|
foreach ( device in my_devices )
|
|
device DoDamage( 10000, device.origin );
|
|
|
|
self notify( "detector_destroyed" );
|
|
}
|
|
|
|
metal_detector_damage_monitor( metal_detector )
|
|
{
|
|
self.light_on thread metal_detectorpart_damage_monitor( self );
|
|
self.light_off thread metal_detectorpart_damage_monitor( self );
|
|
|
|
self SetCanDamage( true );
|
|
while ( self.md_health > 0.0 )
|
|
{
|
|
self waittill( "damage", amount, attacker, direction_vec, point, type );
|
|
if ( IsPlayer( attacker ) )
|
|
self.maintain_fx = true;
|
|
self.md_health -= amount;
|
|
}
|
|
|
|
self thread metal_detector_broke( metal_detector );
|
|
}
|
|
|
|
metal_detectorpart_damage_monitor( parent )
|
|
{
|
|
parent endon( "detector_destroyed" );
|
|
|
|
self SetCanDamage( true );
|
|
while ( 1 )
|
|
{
|
|
self waittill( "damage", amount, attacker, direction_vec, point, type );
|
|
parent DoDamage( 10000, parent.origin );
|
|
}
|
|
}
|
|
|
|
metal_detector_on()
|
|
{
|
|
if ( self.md_health <= 0.0 )
|
|
return;
|
|
self.light_on Show();
|
|
self.light_off Hide();
|
|
self.light_broke Hide();
|
|
self PlaySound( "metaldetector_reset" );
|
|
|
|
}
|
|
|
|
metal_detector_off()
|
|
{
|
|
if ( self.md_health <= 0.0 )
|
|
return;
|
|
self.light_on Hide();
|
|
self.light_off Show();
|
|
self.light_broke Hide();
|
|
self PlaySound( "metaldetector_alarm" );
|
|
}
|
|
|
|
metal_detector_broke( metal_detector )
|
|
{
|
|
metal_detector notify( "detector_damaged" );
|
|
self.light_on Hide();
|
|
self.light_off Hide();
|
|
self.light_broke Show();
|
|
|
|
if ( IsDefined( self.maintain_fx ) && ( self.maintain_fx == true ) )
|
|
{
|
|
while ( 1 )
|
|
{
|
|
self.light_broke PlaySound( "metaldetector_sparks" );
|
|
PlayFX( level._effect[ "vfx_metaldetector_explosion" ], self.light_broke.origin + (0.0, 0.0, 7.5) );
|
|
wait RandomFloatRange( 45.0, 150.0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
setup_bouys()
|
|
{
|
|
bouys = GetEntArray( "harbor_bouy", "targetname" );
|
|
if ( bouys.size <= 0 )
|
|
{
|
|
PrintLn( "No bouys found" );
|
|
return;
|
|
}
|
|
|
|
array_thread( bouys, ::update_bouy );
|
|
}
|
|
|
|
update_bouy()
|
|
{
|
|
start_point = self.origin;
|
|
start_rot = self.angles;
|
|
|
|
bob_rateSq = 15.0 * 15.0;
|
|
while( 1 )
|
|
{
|
|
offset = ( 10.0, 10.0, 0.0 ) + randomvector( 10.0 );
|
|
offset *= ( 3.0, 3.0, 2.0 );
|
|
|
|
dest = start_point + offset;
|
|
time = Max( 3.0, DistanceSquared( self.origin, dest ) / bob_rateSq ); // the math isn't perfect, but it's much faster
|
|
|
|
self RotateTo( VectorToAngles( dest - start_point ), time, 1.5, 1.5 );
|
|
self MoveTo( dest, time, 1.5, 1.5 );
|
|
wait time;
|
|
}
|
|
}
|
|
|
|
setup_dock_boats()
|
|
{
|
|
boats = GetEntArray( "dock_boats", "targetname" );
|
|
if ( boats.size <= 0 )
|
|
{
|
|
PrintLn( "No dock boats found" );
|
|
return;
|
|
}
|
|
|
|
array_thread( boats, ::update_dock_boat );
|
|
}
|
|
|
|
update_dock_boat()
|
|
{
|
|
start_rot = self.angles;
|
|
|
|
bobbing_down = true;
|
|
tilt_rate = 1.5;
|
|
while( 1 )
|
|
{
|
|
|
|
tilt = ( 0.0, 0.0, RandomFloatRange( 6.0, 8.0 ) );
|
|
time = Max( 2.0, tilt[2] / tilt_rate );
|
|
|
|
if ( bobbing_down )
|
|
tilt *= -1.0;
|
|
bobbing_down = !bobbing_down;
|
|
|
|
self RotateTo( start_rot + tilt, time, 1.0, 1.0 );
|
|
wait time;
|
|
}
|
|
}
|
|
|
|
setup_monitors()
|
|
{
|
|
monitors = GetEntArray( "rumble_monitor", "targetname" );
|
|
if ( monitors.size <= 0 )
|
|
{
|
|
PrintLn( "No monitors found" );
|
|
return;
|
|
}
|
|
|
|
array_thread( monitors, ::update_monitor );
|
|
}
|
|
|
|
update_monitor()
|
|
{
|
|
damage_state = GetEnt( self.target, "targetname" );
|
|
if ( !IsDefined( damage_state ) )
|
|
{
|
|
PrintLn( "No monitor damage state found." );
|
|
return;
|
|
}
|
|
|
|
self Show();
|
|
self SetCandamage( true );
|
|
damage_state Hide();
|
|
|
|
self waittill( "damage" );
|
|
|
|
self Hide();
|
|
damage_state Show();
|
|
damage_state PlaySound( "flatscreen_sparks" );
|
|
PlayFX( level._effect[ "vfx_flatscreen_explosion" ], damage_state.origin );
|
|
}
|
|
|
|
setup_watertanks()
|
|
{
|
|
level.tank_hitfx_throttle = 600;
|
|
level.tank_hitfx_throttle_max = 1200;
|
|
level.next_tank_hitfx_time = -1.0;
|
|
|
|
watertanks = GetEntArray( "watertank_glass", "targetname" );
|
|
if ( watertanks.size > 0 )
|
|
{
|
|
for ( i=0; i<watertanks.size; i++ )
|
|
watertanks[i] thread update_watertank( i );
|
|
}
|
|
|
|
watertanks = GetEntArray( "watertank_invulnerable", "targetname" );
|
|
array_thread( watertanks, ::update_watertank_invulnerable );
|
|
}
|
|
|
|
update_watertank( index )
|
|
{
|
|
water_surface = GetEnt( self.target, "targetname" );
|
|
if ( !IsDefined( water_surface ) )
|
|
{
|
|
PrintLn( "Water tank is missing a water_surface" );
|
|
return;
|
|
}
|
|
|
|
water_bottom = GetEnt( water_surface.target, "targetname" );
|
|
if ( !IsDefined( water_bottom ) )
|
|
{
|
|
PrintLn( "Water tank is missing a water_bottom" );
|
|
return;
|
|
}
|
|
|
|
broken_glass = GetEnt( water_bottom.target, "targetname" );
|
|
if ( !IsDefined( broken_glass ) )
|
|
{
|
|
PrintLn( "Water tank is missing a broken glass mesh" );
|
|
return;
|
|
}
|
|
|
|
water_surface thread update_watertank_fish();
|
|
water_surface.destroyExplosiveOnCollision = false;
|
|
|
|
broken_glass Hide();
|
|
self SetCanDamage( true );
|
|
self.tank_damage = 0;
|
|
surface_offset = 41.5;
|
|
lowest_hit_z = water_surface.origin[2] + surface_offset;
|
|
drain_rate = 2.0;
|
|
drain_time = 4.0;
|
|
start_time = 1.0;
|
|
stop_time = 2.0;
|
|
|
|
while ( self.tank_damage < 1200.0 )
|
|
{
|
|
self waittill( "damage", amount, attacker, direction_vec, hit_point, damage_type );
|
|
// PrintLn( "Hit at " + amount + " by " + attacker.code_classname + " from " + direction_vec + " at " + hit_point + " by " + damage_type );
|
|
self.tank_damage += amount;
|
|
|
|
if ( !IsSubStr( damage_type, "BULLET" ) )
|
|
continue;
|
|
|
|
if ( !can_allocate_new_tank_crack() )
|
|
continue;
|
|
|
|
current_surface = water_surface.origin[2] + surface_offset;
|
|
if ( hit_point[2] >= current_surface )
|
|
continue;
|
|
|
|
hit_angles = get_watertank_hit_angle( attacker, direction_vec, hit_point );
|
|
if ( !IsDefined( hit_angles ) )
|
|
continue;
|
|
|
|
drain_limit = Min( drain_time * drain_rate, current_surface - water_bottom.origin[2] );
|
|
actual_move_z = Max( water_bottom.origin[2], Max( hit_point[2], current_surface - drain_limit ) );
|
|
move_dist = actual_move_z - current_surface;
|
|
|
|
move_time = Abs( move_dist ) / drain_rate;
|
|
move_time = Max( move_time, start_time + stop_time );
|
|
|
|
self thread spawn_watertank_hit( level._effect["vfx_watertank_bullet_hit"], attacker, hit_angles, hit_point, move_time, water_surface, surface_offset );
|
|
|
|
if ( actual_move_z >= lowest_hit_z )
|
|
continue;
|
|
|
|
lowest_hit_z = actual_move_z;
|
|
water_surface MoveZ( move_dist, move_time, start_time, stop_time );
|
|
}
|
|
|
|
self PlaySound( "water_tank_splash" );
|
|
|
|
water_surface notify ( "tank_destroyed" );
|
|
wait 0.05;
|
|
|
|
attachedExplosives = self GetLinkedChildren();
|
|
foreach ( explosive in attachedExplosives )
|
|
{
|
|
explosive notify( "detonateExplosive" );
|
|
}
|
|
|
|
self Delete();
|
|
water_surface Delete();
|
|
|
|
broken_glass Show();
|
|
broken_glass ScriptModelPlayAnim( "mp_ca_rumble_glass_anim" );
|
|
if ( index == 0 )
|
|
{
|
|
PlayFX( level._effect["vfx_glass_shatter_splash"], (-46.0003, 1409.25, 138.056), AnglesToForward( (0,0,0) ), AnglesToUp( (0,0,0) ) );
|
|
PlayFX( level._effect["vfx_glass_ground_splash"], (-39.7033, 1414.08, 89), AnglesToForward( (270,0,0) ), AnglesToUp( (0,0,0) ) );
|
|
}
|
|
else
|
|
{
|
|
PlayFX( level._effect["vfx_glass_shatter_splash"], (-47.9208, 1144.29, 141.575), AnglesToForward( (0,0,0) ), AnglesToUp( (0,0,0) ) );
|
|
PlayFX( level._effect["vfx_glass_ground_splash"], (-51.5828, 1139.69, 89), AnglesToForward( (270,0,0) ), AnglesToUp( (0,0,0) ) );
|
|
}
|
|
}
|
|
|
|
update_watertank_fish()
|
|
{
|
|
self endon( "death" );
|
|
|
|
wait 2.0;
|
|
effect_id = level._effect["vfx_fish_school"];
|
|
fish_ent = Spawn( "script_model", self.origin );
|
|
fish_ent SetModel( "tag_origin" );
|
|
fish_ent LinkTo( self );
|
|
|
|
self thread maintain_watertank_fish( effect_id, fish_ent );
|
|
|
|
self waittill( "tank_destroyed" );
|
|
|
|
KillFXOnTag( effect_id, fish_ent, "tag_origin" );
|
|
wait 0.05;
|
|
fish_ent Delete();
|
|
}
|
|
|
|
maintain_watertank_fish( effect_id, fish_ent )
|
|
{
|
|
self endon( "tank_destroyed" );
|
|
|
|
while ( 1 )
|
|
{
|
|
PlayFXOnTag( effect_id, fish_ent, "tag_origin" );
|
|
wait 5.0;
|
|
StopFXOnTag( effect_id, fish_ent, "tag_origin" );
|
|
wait 1.0;
|
|
}
|
|
}
|
|
|
|
spawn_watertank_hit( effect_id, attacker, hit_angles, hit_point, drain_time, water_surface, surface_offset )
|
|
{
|
|
allocate_new_tank_crack();
|
|
|
|
water_fx_ent = SpawnFx( effect_id, hit_point, hit_angles );
|
|
TriggerFX( water_fx_ent );
|
|
water_fx_ent PlaySound( "water_tank_hit" );
|
|
|
|
stop_time = GetTime() + drain_time * 1000.0;
|
|
water_fx_ent monitor_watertank_hit( water_surface, stop_time, surface_offset );
|
|
|
|
water_fx_ent StopSounds();
|
|
wait 0.05;
|
|
water_fx_ent Delete();
|
|
}
|
|
|
|
monitor_watertank_hit( water_surface, stop_time, surface_offset )
|
|
{
|
|
water_surface endon( "tank_destroyed" );
|
|
|
|
while ( GetTime() < stop_time )
|
|
{
|
|
if ( self.origin[2] >= ((water_surface.origin[2] + surface_offset) - 1.0) )
|
|
break;
|
|
wait 0.05;
|
|
}
|
|
}
|
|
|
|
update_watertank_invulnerable()
|
|
{
|
|
self SetCanDamage( true );
|
|
while ( 1 )
|
|
{
|
|
self waittill( "damage", amount, attacker, direction_vec, hit_point, damage_type );
|
|
|
|
if ( !IsSubStr( damage_type, "BULLET" ) )
|
|
continue;
|
|
|
|
if ( !can_allocate_new_tank_crack() )
|
|
continue;
|
|
|
|
hit_angles = get_watertank_hit_angle( attacker, direction_vec, hit_point );
|
|
if ( !IsDefined( hit_angles ) )
|
|
continue;
|
|
|
|
allocate_new_tank_crack();
|
|
hit_angles = VectorToAngles( hit_angles );
|
|
PlayFX( level._effect["vfx_watertank_bullet_hit"], hit_point, AnglesToForward( hit_angles ), AnglesToUp( hit_angles ) );
|
|
PlaySoundAtPos( hit_point, "water_tank_hit" );
|
|
}
|
|
}
|
|
|
|
get_watertank_hit_angle( attacker, direction_vec, hit_point )
|
|
{
|
|
E = attacker.origin;
|
|
temp_vec = hit_point - E;
|
|
|
|
trace = BulletTrace( E, E + 1.5 * temp_vec, false, attacker, false );
|
|
if ( IsDefined ( trace[ "normal" ] ) && IsDefined( trace[ "entity" ] ) && (trace["entity"] == self) )
|
|
return trace[ "normal" ];
|
|
|
|
return undefined;
|
|
}
|
|
|
|
can_allocate_new_tank_crack()
|
|
{
|
|
if ( GetTime() < level.next_tank_hitfx_time )
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
allocate_new_tank_crack()
|
|
{
|
|
level.next_tank_hitfx_time = GetTime() + RandomFloatRange( level.tank_hitfx_throttle, level.tank_hitfx_throttle_max );
|
|
}
|
|
|
|
update_trolley()
|
|
{
|
|
waitframe(); // I don't know why a level's "main" is run before other systems have had a chance to set up, but we need to wait
|
|
|
|
trolley = GetEnt( "moving_trolley", "targetname" );
|
|
if ( !IsDefined( trolley ) )
|
|
{
|
|
PrintLn( "Trolley is missing." );
|
|
return;
|
|
}
|
|
|
|
// setup some flags to handle mover collisions against airdrop crates and killstreak drones
|
|
trolley.destroyAirdropOnCollision = true;
|
|
trolley.destroyDroneOnCollision = false;
|
|
|
|
curObjID = maps\mp\gametypes\_gameobjects::getNextObjID();
|
|
Objective_Add( curObjID, "active", trolley.origin,"waypoint_trolley" );
|
|
Objective_OnEntityWithRotation( curObjID, trolley );
|
|
self.curObjID = curObjID;
|
|
|
|
trolley_lights = getstructarray( "trolley_light", "targetname" );
|
|
array_thread( trolley_lights, ::trolley_attach_lights, trolley );
|
|
|
|
trolley_mesh = getent( "moving_trolley_mesh", "targetname" );
|
|
if ( IsDefined( trolley_mesh ) )
|
|
trolley_mesh linkto( trolley );
|
|
|
|
trolley_mesh_extras = getentarray( "moving_trolley_extras", "targetname" );
|
|
if ( trolley_mesh_extras.size > 0 )
|
|
{
|
|
foreach ( extra in trolley_mesh_extras )
|
|
extra linkto( trolley );
|
|
}
|
|
|
|
trolley_wheels = GetEntArray( "moving_trolley_wheel", "targetname" );
|
|
if ( trolley_wheels.size <= 0 )
|
|
{
|
|
Println( "Trolley is missing wheels." );
|
|
return;
|
|
}
|
|
|
|
wheel_offsets = [];
|
|
wheel_rotations = [];
|
|
for ( i=0; i<trolley_wheels.size; i++ )
|
|
{
|
|
wheel_offsets[i] = trolley.origin - trolley_wheels[i].origin;
|
|
wheel_rotations[i] = trolley.angles - trolley_wheels[i].angles;
|
|
}
|
|
|
|
current_point = GetEnt( "trolley_path_start", "targetname" );
|
|
if ( !IsDefined( current_point ) )
|
|
{
|
|
PrintLn( "No trolley path to follow." );
|
|
return;
|
|
}
|
|
|
|
trolley.origin = current_point.origin;
|
|
trolley.angles = current_point.angles;
|
|
for ( i=0; i<trolley_wheels.size; i++ )
|
|
{
|
|
trolley_wheels[i].origin = current_point.origin - RotateVector( wheel_offsets[i], current_point.angles );
|
|
trolley_wheels[i].angles = current_point.angles + wheel_rotations[i];
|
|
}
|
|
|
|
trolley.enabled = true;
|
|
trolley thread monitor_trolley_dvar();
|
|
|
|
default_speed = 140.0;
|
|
stop_time = 0.0;
|
|
start_time = 0.0;
|
|
if ( IsDefined( current_point.script_accel ) )
|
|
start_time = current_point.script_accel;
|
|
|
|
current_point = GetEnt( current_point.target, "targetname" );
|
|
while ( IsDefined( current_point ) )
|
|
{
|
|
if ( !trolley.enabled )
|
|
{
|
|
wait 0.05;
|
|
continue;
|
|
}
|
|
|
|
stop_time = 0.0;
|
|
if ( IsDefined( current_point.script_decel ) )
|
|
stop_time = current_point.script_decel;
|
|
|
|
move_speed = default_speed;
|
|
move_speed /= Max( 1, GetDvarInt( "trolley_throttle", 1 ) );
|
|
|
|
if ( IsDefined( current_point.script_physics ) )
|
|
move_speed *= current_point.script_physics;
|
|
move_time = Distance( trolley.origin, current_point.origin ) / move_speed;
|
|
move_time = Max( move_time, stop_time + start_time );
|
|
|
|
trolley MoveTo( current_point.origin, move_time, start_time, stop_time );
|
|
trolley RotateTo( current_point.angles, move_time, start_time, stop_time );
|
|
|
|
wheel_speed = move_speed * 2.1;
|
|
if ( IsDefined( current_point.script_anglevehicle ) && (current_point.script_anglevehicle == 1) )
|
|
wheel_speed *= -1.0;
|
|
|
|
point_angle = current_point.angles[1];
|
|
for ( i=0; i<trolley_wheels.size; i++ )
|
|
{
|
|
wheel_spot = current_point.origin - RotateVector( wheel_offsets[i], current_point.angles );
|
|
trolley_wheels[i] MoveTo( wheel_spot, move_time, start_time, stop_time );
|
|
wheel_turn = (point_angle + wheel_rotations[i][1] - trolley_wheels[i].angles[1]) / move_time;//(point_angle - trolley_wheels[i].angles[1]) / move_time;
|
|
specific_wheel_speed = wheel_speed;
|
|
if ( IsDefined( trolley_wheels[i].script_index ) && (trolley_wheels[i].script_index == 1) )
|
|
specific_wheel_speed *= -1.0;
|
|
trolley_wheels[i] RotateVelocity( (0,wheel_turn,specific_wheel_speed), move_time, start_time, stop_time );
|
|
}
|
|
|
|
if ( start_time > 0.0 )
|
|
{
|
|
trolley_mesh PlaySoundOnMovingEnt( "trolley_bell" );
|
|
trolley_mesh PlaySoundOnMovingEnt( "trolley_start" );
|
|
wait ( start_time - 0.2 );
|
|
trolley_mesh PlayLoopSound( "trolley_motor" );
|
|
wait 0.2;
|
|
}
|
|
|
|
wait move_time - (start_time + stop_time);
|
|
|
|
if ( stop_time > 0.0 )
|
|
{
|
|
//trolley_mesh PlaySoundOnMovingEnt( "trolley_bell" );
|
|
trolley_mesh PlaySoundOnMovingEnt( "trolley_stop" );
|
|
wait 0.2;
|
|
trolley_mesh StopLoopSound( "trolley_motor" );
|
|
wait ( stop_time - 0.2 );
|
|
}
|
|
|
|
if ( IsDefined( current_point.script_node_pausetime ) )
|
|
wait current_point.script_node_pausetime;
|
|
|
|
for ( i=0; i<trolley_wheels.size; i++ )
|
|
trolley_wheels[i].angles = (trolley_wheels[i].angles[0], point_angle + wheel_rotations[i][1], trolley_wheels[i].angles[2]);
|
|
|
|
start_time = 0.0;
|
|
if ( IsDefined( current_point.script_accel ) )
|
|
start_time = current_point.script_accel;
|
|
|
|
if ( IsDefined( current_point.script_index ) )
|
|
trolley_mesh PlaySoundOnMovingEnt( "trolley_corner" );
|
|
|
|
current_point = GetEnt( current_point.target, "targetname" );
|
|
}
|
|
}
|
|
|
|
trolley_attach_lights( trolley )
|
|
{
|
|
light_mount = Spawn( "script_model", self.origin );
|
|
light_mount.angles = self.angles;
|
|
light_mount SetModel( "tag_origin" );
|
|
light_mount LinkTo( trolley );
|
|
|
|
while ( 1 )
|
|
{
|
|
PlayFXOnTag( level._effect[ "vfx_pot_lights_trolley" ], light_mount, "tag_origin" );
|
|
wait RandomFloatRange( 4.0, 6.0 );
|
|
StopFXOnTag( level._effect[ "vfx_pot_lights_trolley" ], light_mount, "tag_origin" );
|
|
waitframe();
|
|
}
|
|
}
|
|
|
|
monitor_trolley_dvar()
|
|
{
|
|
dvar_name = "trolley_toggle";
|
|
default_value = 0;
|
|
SetDevDvarIfUninitialized( dvar_name, default_value );
|
|
|
|
dvar_throttle = "trolley_throttle";
|
|
default_throttle = 1;
|
|
SetDevDvarIfUninitialized( dvar_throttle, default_throttle );
|
|
|
|
while( 1 )
|
|
{
|
|
value = GetDvarInt( dvar_name, default_value );
|
|
if ( value == default_value )
|
|
{
|
|
waitframe();
|
|
}
|
|
else
|
|
{
|
|
SetDevDvar( dvar_name, default_value );
|
|
self.enabled = !self.enabled;
|
|
}
|
|
}
|
|
}
|
|
|
|
update_destroyer()
|
|
{
|
|
ship = GetEnt( "roaming_destroyer", "targetname" );
|
|
if ( !IsDefined( ship ) )
|
|
{
|
|
PrintLn( "No roaming_destroyer ship." );
|
|
return;
|
|
}
|
|
|
|
current_point = GetEnt( ship.target, "targetname" );
|
|
if ( !IsDefined( current_point ) )
|
|
{
|
|
PrintLn( "No roaming_destroyer ship path to follow." );
|
|
return;
|
|
}
|
|
|
|
ship.origin = current_point.origin;
|
|
ship.angles = current_point.angles;
|
|
|
|
default_speed = 500.0;
|
|
accel_time = 0.0;
|
|
decel_time = 0.0;
|
|
|
|
current_point = GetEnt( current_point.target, "targetname" );
|
|
if ( IsDefined( current_point.script_decel ) )
|
|
decel_time = current_point.script_decel;
|
|
|
|
while ( IsDefined( current_point ) )
|
|
{
|
|
move_speed = default_speed;
|
|
if ( IsDefined( current_point.script_physics ) )
|
|
move_speed = current_point.script_physics;
|
|
accel_time = 0.0;
|
|
if ( IsDefined( current_point.script_accel ) )
|
|
accel_time = current_point.script_accel;
|
|
|
|
base_move_time = Distance( ship.origin, current_point.origin ) / move_speed;
|
|
move_time = Max( base_move_time, accel_time + decel_time );
|
|
|
|
ship MoveTo( current_point.origin, move_time, accel_time, decel_time );
|
|
ship RotateTo( current_point.angles, move_time, accel_time, decel_time );
|
|
wait move_time;
|
|
|
|
next_point = GetEnt( current_point.target, "targetname" );
|
|
if ( IsDefined( next_point ) )
|
|
{
|
|
if ( IsDefined( next_point.script_node_pausetime ) )
|
|
wait next_point.script_node_pausetime;
|
|
decel_time = 0.0;
|
|
if ( IsDefined( next_point.script_decel ) )
|
|
decel_time = next_point.script_decel;
|
|
}
|
|
|
|
current_point = next_point;
|
|
}
|
|
}
|
|
|
|
update_lighthouse_light()
|
|
{
|
|
lighthouse_light = GetEnt( "lighthouse_light", "targetname" );
|
|
if ( !IsDefined( lighthouse_light ) )
|
|
{
|
|
PrintLn( "No lighthouse light." );
|
|
return;
|
|
}
|
|
|
|
if ( !IsDefined( lighthouse_light.animation ) )
|
|
{
|
|
PrintLn( "No animation for the lighthouse light." );
|
|
return;
|
|
}
|
|
|
|
lighthouse_light ScriptModelPlayAnim( "mp_ca_rumble_lighthouse_rotate" );
|
|
}
|
|
|
|
update_artillery_fx()
|
|
{
|
|
fx_alias = level._effect[ "vfx_battleship_firing_timing" ];
|
|
fx_pos = (14701.5, -17741.3, 854.587);
|
|
fx_rot = AnglesToForward((354.236, 135.865, 13.443));
|
|
fx_up = AnglesToUp((354.236, 135.865, 13.443));
|
|
|
|
sound_ent = Spawn( "script_model", fx_pos );
|
|
sound_ent SetModel( "tag_origin" );
|
|
sound_alias = "emt_rumb_dist_arty_fire";
|
|
|
|
wait RandomFloatRange( 5.0, 20.0 );
|
|
while ( 1 )
|
|
{
|
|
next_shot = 30.0 + RandomFloat( 20.0 );
|
|
|
|
sound_ent.origin = fx_pos + (0,0,1000);
|
|
sound_ent MoveTo( sound_ent.origin + (-55000,-60000,16000), LookupSoundLength( sound_alias ) * 0.001, 0.2 );
|
|
sound_ent PlaySoundOnMovingEnt( sound_alias );
|
|
|
|
PlayFX( fx_alias, fx_pos, fx_rot, fx_up );
|
|
|
|
wait next_shot;
|
|
}
|
|
}
|
|
|
|
update_heli_fx()
|
|
{
|
|
fx_alias = level._effect[ "vfx_heli_timing" ];
|
|
fx_pos = (19354.8, -24794.2, 539.564);
|
|
fx_rot = AnglesToForward((0, 190, 0));
|
|
fx_up = AnglesToUp((0, 190, 0));
|
|
|
|
sound_ent = Spawn( "script_model", fx_pos );
|
|
sound_ent SetModel( "tag_origin" );
|
|
sound_alias = "scn_rumb_chopper_by";
|
|
|
|
wait RandomFloatRange( 5.0, 20.0 );
|
|
while ( 1 )
|
|
{
|
|
next_heli = 60.0 + RandomFloat( 30.0 );
|
|
|
|
sound_ent.origin = fx_pos + (0,0,700);
|
|
sound_ent MoveTo( sound_ent.origin + (-55000,-10000,3000), 40.0, 10.0 );
|
|
sound_ent PlaySoundOnMovingEnt( sound_alias );
|
|
|
|
PlayFX( fx_alias, fx_pos, fx_rot, fx_up );
|
|
|
|
wait next_heli;
|
|
}
|
|
}
|
|
|
|
update_flybyjet_fx()
|
|
{
|
|
fx_alias = level._effect[ "vfx_jet_flyby_timing" ];
|
|
fx_pos = (22547.9, -308.47, 1440.73);
|
|
fx_rot = AnglesToForward((0.855041, 223.034, -0.529352));
|
|
fx_up = AnglesToUp((0.855041, 223.034, -0.529352));
|
|
|
|
sound_ent = Spawn( "script_model", fx_pos );
|
|
sound_ent SetModel( "tag_origin" );
|
|
sound_alias = "scn_rumb_jets_by";
|
|
|
|
wait RandomFloatRange( 5.0, 20.0 );
|
|
while ( 1 )
|
|
{
|
|
next_plane = 90.0 + RandomFloat( 30.0 );
|
|
|
|
sound_ent.origin = fx_pos + (0,0,1000);
|
|
sound_ent MoveTo( sound_ent.origin + (-55000,-55000,0), 20.0, 0.6 );
|
|
sound_ent PlaySoundOnMovingEnt( sound_alias );
|
|
|
|
PlayFX( fx_alias, fx_pos, fx_rot, fx_up );
|
|
|
|
wait next_plane;
|
|
}
|
|
}
|
|
|
|
setup_fountain_fx()
|
|
{
|
|
thread update_fountain_fx( (200.517, 631.669, 12), 1.1 );
|
|
thread update_fountain_fx( (-47.933, 575.054, 26) );
|
|
thread update_fountain_fx( (-300.421, 633.173, 8), 1.1 );
|
|
|
|
wait 1.0;
|
|
while ( 1 )
|
|
{
|
|
level notify( "spawn_stair_fountain_fx" );
|
|
wait 8.0;
|
|
}
|
|
}
|
|
|
|
update_fountain_fx( fx_pos, fx_delay )
|
|
{
|
|
fx_alias = level._effect[ "vfx_water_fountain" ];
|
|
|
|
sound_alias = "emt_rumb_fount_spray";
|
|
|
|
while ( 1 )
|
|
{
|
|
level waittill( "spawn_stair_fountain_fx" );
|
|
if ( IsDefined( fx_delay ) && ( fx_delay > 0.0 ) )
|
|
wait fx_delay;
|
|
|
|
PlayFX( fx_alias, fx_pos, AnglesToForward((0,0,0)), AnglesToUp((0,0,0)) );
|
|
|
|
PlaySoundAtPos( fx_pos, sound_alias );
|
|
wait 1.1;
|
|
PlaySoundAtPos( fx_pos + (0.0,32.0,36.0), sound_alias );
|
|
wait 1.1;
|
|
PlaySoundAtPos( fx_pos + (0.0,80.0,68.0), sound_alias );
|
|
wait 1.1;
|
|
PlaySoundAtPos( fx_pos + (0.0,120.0,96.0), sound_alias );
|
|
}
|
|
}
|
|
|
|
// move one of the placed mlg cameras to have a better view of the Fed Blitz goal (bug 161265)
|
|
fixMLGCameraPosition()
|
|
{
|
|
mlgcameras = GetEntArray( "mp_mlg_camera", "classname");
|
|
if ( IsDefined( mlgcameras ) && mlgcameras.size )
|
|
{
|
|
foreach ( camEnt in mlgcameras)
|
|
{
|
|
if ( camEnt.origin == (-1064, -224, 272) )
|
|
{
|
|
camEnt.origin = (-632, -1712, 368);
|
|
camEnt.angles = (10, 113, -1.174);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} |