t5_bot_warfare/mods/patch_mp/maps/mp/mp_radiation.gsc
2021-02-18 13:53:14 -06:00

853 lines
24 KiB
Plaintext

#include maps\mp\_utility;
#include common_scripts\utility;
main()
{
precachemodel("tag_origin");
/#
level thread devgui_radiation();
execdevgui("devgui_mp_radiation");
#/
//needs to be first for create fx
maps\mp\mp_radiation_fx::main();
precachemodel("collision_geo_64x64x256");
precachemodel("collision_wall_128x128x10");
precachemodel("collision_geo_256x256x10");
maps\mp\_load::main();
maps\mp\mp_radiation_amb::main();
if ( GetDvarInt( #"xblive_wagermatch" ) == 1 )
{
maps\mp\_compass::setupMiniMap("compass_map_mp_radiation_wager");
}
else
{
maps\mp\_compass::setupMiniMap("compass_map_mp_radiation");
}
//Increase sample size so as to resolve lighting issue
SetDvar("sm_sunSampleSizeNear", ".5" );
// If the team nationalites change in this file,
// you must update the team nationality in the level's csc file as well!
maps\mp\gametypes\_teamset_urbanspecops::level_init();
// Set up the default range of the compass
setdvar("compassmaxrange","2100");
// COLLISION - to prevent players from placing turrets inside a large cylinder brush in the tank room
spawncollision("collision_geo_64x64x256","collider",(1221, 41, 236), (0, 0, 0));
// COLLISION - to prevent players from jumping onto a little ledge of collision
spawncollision("collision_wall_128x128x10","collider",(1042, -309, 309), (0, 0, 0));
spawncollision("collision_wall_128x128x10","collider",(1080, -309, 309), (0, 0, 0));
// COLLISION - to prevent players from dropping turrets in the large grey tanks by the warehouse
spawncollision("collision_geo_64x64x256","collider",(568, 219, 264), (0, 0, 0));
spawncollision("collision_geo_64x64x256","collider",(567, -105, 264), (0, 0, 0));
// COLLISION - to prevent players dropping off the catwalk onto ledge in warehouse
spawncollision("collision_wall_128x128x10","collider",(1157, -345, 186), (0, 270, 0));
spawncollision("collision_wall_128x128x10","collider",(1157, -345, 314), (0, 270, 0));
spawncollision("collision_wall_128x128x10","collider",(1157, -345, 442), (0, 270, 0));
//NOTURRET - spawns radius triggers to stop players from placing turrets in the large cylinders in the NE corner of the map
addNoTurretTrigger((1440, -1116, 145), 230, 256);
addNoTurretTrigger((1446, -1659, 145), 230, 256);
// enable new spawning system
maps\mp\gametypes\_spawning::level_use_unified_spawning(true);
flag_init_func();
level_objects_init();
}
flag_init_func()
{
flag_init("kill_stuck_players");
}
level_objects_init()
{
level._digger_fx = LoadFX( "maps/mp_maps/fx_mp_sand_digger_radiation" );
waittillframeend;
level._door_switch_trig1 = getent_and_assert("switch_trigger1");
level._door_switch_trig2 = getent_and_assert("switch_trigger2");
level._door1 = getent_and_assert("big_door1_clip");
level._door2 = getent_and_assert("big_door2_clip");
level.const_fx_exploder_switch_green_light = 2001;
level.const_fx_exploder_switch_red_light = 2002;
//Gets some diggers digging
level thread digger_dig_init();
//Gets diggers in the background moving
moving_diggers_init();
//Sets up the switchs players can flip to open the double doors
level thread door_switch_func();
if( !level.wagerMatch && !isPregame() )
{
//get my doors opening at the start of the match
level thread double_doors_open_at_start();
}
//Get conveyer belt working
level thread conveyer_belt_init();
}
turnSwitchPanelRed()
{
exploder_stop( level.const_fx_exploder_switch_green_light );
exploder( level.const_fx_exploder_switch_red_light );
}
turnSwitchPanelGreen()
{
exploder_stop( level.const_fx_exploder_switch_red_light );
exploder( level.const_fx_exploder_switch_green_light );
}
//Sets it up so a player can flip a switch and open large double doors
door_switch_func()
{
//Set up the use trigger switches that activate my double doors
level._door_switch_trig1 thread door_switch_setup();
level._door_switch_trig2 thread door_switch_setup();
//Cooldown switches inform the player that the door switch is on cooldown if they try to interact with it
cooldown_switches = GetEntArray("off_trigger","targetname");
AssertEx( cooldown_switches.size > 0, "Missing off_triggers");
for( i = 0; i < cooldown_switches.size; i++)
{
cooldown_switches[i] UseTriggerRequireLookAt();
cooldown_switches[i] SetCursorHint( "HINT_NOICON" );
cooldown_switches[i] SetHintString( &"MP_HOLD_DOOR_SWITCH_UNAVAILABLE");
cooldown_switches[i] trigger_off();
}
turnSwitchPanelRed();
kill_trig1 = getent_and_assert("edge_death_trig1");
kill_trig2 = getent_and_assert("edge_death_trig2");
center_death_trig = getent_and_assert("center_death_trig");
//Set up DVARS for tweaking door opening sequence
d1_new_angle = set_dvar_int_if_unset("scr_d1_new_angle", "123");
d2_new_angle = set_dvar_int_if_unset("scr_d2_new_angle", "-123");
door_model1 = getent_and_assert("big_door1");
door_model2 = getent_and_assert("big_door2");
door_model1 LinkTo(level._door1);
door_model2 LinkTo(level._door2);
door_monster_clip = GetEnt("door_monster_clip","targetname");
//door_monster_clip thread dog_kill();
//snd_door_status tracks if the door is open or closed
snd_door_status = 0;
light_structs = getstructarray("switch_struct","targetname");
AssertEx( light_structs.size > 0, "Missing light structs");
for( i = 0; i < light_structs.size; i++)
{
light_structs[i] thread switch_lights(i);
}
tunnel_structs = getstructarray("tunnel_light_spot","targetname");
AssertEx(tunnel_structs.size > 0, "Missing light structs");
for( i = 0; i < light_structs.size; i++)
{
tunnel_structs[i] thread tunnel_lights(i);
}
while(!level.wagermatch)
{
//This is a switch in the level on the catwalk
waittill_any_ents(level._door_switch_trig1,"trigger",level._door_switch_trig2,"trigger");
//Disables the switch temporarily
level._door_switch_trig1 trigger_off();
level._door_switch_trig2 trigger_off();
for( i = 0; i < cooldown_switches.size; i++)
{
cooldown_switches[i] trigger_on();
}
//Set up DVARS for tweaking door opening sequence. Acceleration and decelation variation added for realistic offset.
door_time = set_dvar_int_if_unset("scr_d1_time", "8");
//The doors have specific accelleration and deceleration values so as give an organic-looking timing offset.
//When the doors are opening, we want Door 2 to accelerate slightly faster so as to avoid clipping.
if(snd_door_status == 0)
{
d1_accel = door_time * .6;
d2_accel = door_time * .7;
d1_decel = door_time * .4;
d2_decel = door_time * .3;
//Monster clip is placed and path nodes are severed to keep dogs from running on the doors
door_monster_clip trigger_on();
door_monster_clip DisconnectPaths();
}
//When the doors are closing, we want Door 1 to accelerate slightly faster so as to avoid clipping.
else
{
d1_accel = door_time * .7;
d2_accel = door_time * .6;
d1_decel = door_time * .3;
d2_decel = door_time * .4;
}
door_cooldown = set_dvar_int_if_unset("scr_door_cooldown", "20");
level._door1 RotateRoll(d1_new_angle, door_time, d1_accel, d1_decel);
level._door2 RotateRoll(d2_new_angle, door_time, d2_accel, d2_decel);
thread dropEverythingOnDoorsToGround();
level thread destroyEquipment();
// Play door opening sound
level._door1 playloopsound ("evt_hydraulic_loop", .5);
level._door1 playsound ("evt_hydraulic_start");
level._door1 thread door_snd_alarm ( 5 );
//This sets it so my doors move in reverse next time they're activated
d1_new_angle = d1_new_angle * -1;
d2_new_angle = d1_new_angle * -1;
//Flag marks the period of time i'm checking for any player caught in moving collision
flag_set("kill_stuck_players");
//Give time for doors to move a moderate amount before starts kill trigger
wait 4;
//Only want to kill players if doors are closing
if(snd_door_status == 1)
{
//These are three seperate trigger brushes I want to check for stuck players
kill_trig1 thread kill_edge_players_func();
kill_trig2 thread kill_edge_players_func();
center_death_trig thread kill_edge_players_func();
}
level._door1 waittill("rotatedone");
//snd_door_status tracks if the door is currently open or closed for seprate open and close audio
if (snd_door_status == 0)
{
//stops the move loop, plays endind sound, and set current door status
level._door1 stoploopsound (1);
center_death_trig playsound ("evt_hydraulic_open");
snd_door_status = 1;
}
else
{
//stops the move loop, plays endind sound, and set current door status
level._door1 stoploopsound (1);
center_death_trig playsound ("evt_hydraulic_close");
//Clip is removed so dogs can path
door_monster_clip ConnectPaths();
door_monster_clip trigger_off();
snd_door_status = 0;
}
flag_clear("kill_stuck_players");
//Special notify to end my check for players caught on collision
level notify ("edge_check");
wait (door_cooldown);
level notify ("no_cooldown");
for( i = 0; i < cooldown_switches.size; i++)
{
cooldown_switches[i] trigger_off();
}
level._door_switch_trig1 trigger_on();
level._door_switch_trig2 trigger_on();
}
}
door_snd_alarm ( alarmTimes )
{
for (i=0; i < alarmTimes; i++)
{
wait (.5);
playsoundatposition("amb_alarm_buzz",(-664,110,436));
playsoundatposition("amb_alarm_buzz",(-664,-72,436));
playsoundatposition("amb_alarm_buzz",(-666,-602,436));
playsoundatposition("amb_alarm_buzz",(-666,660,444));
wait (1.5);
}
}
//Self is the use triggers that activate the double doors
door_switch_setup()
{
self usetriggerrequirelookat();
if ( level.wagerMatch )
{
self SetHintString(&"MP_HOLD_DOOR_SWITCH_UNAVAILABLE");
turnSwitchPanelRed();
}
else
{
self SetHintString(&"MP_HOLD_TO_OPERATE_DOORS");
turnSwitchPanelGreen();
}
while ( !level.wagerMatch )
{
// self is the switch. who is the player that triggered switch
self waittill("trigger", who);
//Added "if" check for when the doors are triggered without a player -Leif
if(IsDefined( who ))
{
who playsound ("evt_hydraulic_switch");
}
wait (1);
}
}
//Self is a trigger. The triggers are placed in places i'm afraid of players getting caught
kill_edge_players_func()
{
level endon ("edge_check");
//This only loops while the doors are moving
while(1)
{
self waittill("trigger", player);
if((player IsTouching(level._door1)) || (player IsTouching(level._door2)))
{
player DoDamage(player.health * 2, self.origin, player, player, 0, "MOD_SUICIDE" );
// TODO: add crushing audio. CDC
}
else
{
wait .05;
}
}
}
//TO DO: Review this function for multiplayer API improvements.
//'Self' is the struct within the panel that operates the double doors
switch_lights( element_number )
{
if ( level.PrematchPeriod > 0 && level.inPrematchPeriod == true )
{
level waittill("prematch_over");
}
while(1)
{
effect_ent = Spawn("script_model", self.origin);
effect_ent SetModel("tag_origin");
//This wait is necesary to get the effect to work on the newly created script model.
wait .1;
//Green light signals the switch is not on cooldown
turnSwitchPanelGreen();
//PlayFXOnTag(level._effect["green_light"], effect_ent,"tag_origin" );
waittill_any_ents(level._door_switch_trig1,"trigger",level._door_switch_trig2,"trigger");
//This function is array threaded, so we must prevent FX from playing in the same frame using this loop
for (i = 0; i < element_number; i++)
{
wait .1;
}
effect_ent Delete();
blinky_effect_ent = Spawn("script_model", self.origin);
blinky_effect_ent SetModel("tag_origin");
//This wait is necesary to get the effect to work on the newly created script model.
wait .1;
//Blink red light signals the double doors are moving
turnSwitchPanelRed();
//PlayFXOnTag(level._effect["blink_light"], blinky_effect_ent,"tag_origin" );
//This notify signals that the doors have stopped moving
level waittill ("edge_check");
for (i = 0; i < element_number; i++)
{
wait .1;
}
blinky_effect_ent Delete();
final_effect_ent = Spawn("script_model", self.origin);
final_effect_ent SetModel("tag_origin");
//This wait is necesary to get the effect to work on the newly created script model.
wait .1;
//Red light signals the switch cannot be used
//PlayFXOnTag(level._effect["red_light"], final_effect_ent,"tag_origin" );
//This notify signals that the doors have stopped moving
level waittill ("no_cooldown");
for (i = 0; i < element_number; i++)
{
wait .1;
}
final_effect_ent Delete();
}
}
//'Self' is the struct within the light bulbs in the Radiation tunnel. This function manages FX in the tunnel
//'Element number' is equal to self's index number in the array that got array threaded.
tunnel_lights(element_number)
{
door_closed = true;
while(1)
{
//Must define may variable to avoid SRE
effect_ent = undefined;
//When door is closed, play "solid" tunnel light effect
if(door_closed)
{
effect_ent = Spawn("script_model", self.origin);
effect_ent SetModel("tag_origin");
//Must wait a moment for the script model to finish spawning
wait .1;
PlayFXOnTag(level._effect["green_light"], effect_ent,"tag_origin" );
}
//Wait until a tunnel double door switch is hit
waittill_any_ents(level._door_switch_trig1,"trigger",level._door_switch_trig2,"trigger");
//This loop makes sure effects do not happen in the same frame, as this function has been array threaded to multiple ents.
for (i = 0; i < element_number; i++)
{
wait .1;
}
//'New effect' is the blinking lights that occur while the double doors are moving
new_effect_ent = Spawn("script_model", self.origin);
new_effect_ent SetModel("tag_origin");
if(IsDefined(effect_ent))
{
effect_ent Delete();
}
//Must wait a moment for the script model to finish spawning
wait .1;
PlayFXOnTag(level._effect["blink_light"], new_effect_ent,"tag_origin" );
level waittill ("edge_check");
for (i = 0; i < element_number; i++)
{
wait .1;
}
new_effect_ent Delete();
if(!door_closed)
{
door_closed = true;
}
else
{
door_closed = false;
}
}
}
//Open doors at start
double_doors_open_at_start()
{
//Set up the double doors to open at the start of the match
if ( level.PrematchPeriod > 0 && level.inPrematchPeriod == true )
{
level waittill("prematch_over");
}
//Slow down my door for other functions to hit waittil's
wait .3;
//Note I didn't use the "useby player[0]" convention due to a hesitance to grab specific players in MP.
level._door_switch_trig1 notify ("trigger");
}
//Set up the devgui to have the ability to operate the doors, adjust door cooldown, rotate times, digger behavior, etc.
devgui_radiation(cmd)
{
while(1)
{
wait(0.5);
devgui_string = GetDvar( #"devgui_notify");
switch(devgui_string)
{
case "":
break;
case "operate_doors":
level._door_switch_trig1 notify ("trigger");
break;
default:
level notify(devgui_string);
break;
}
SetDvar("devgui_notify", "");
}
}
//*****TO DO: MOVE DIGGER FUNCTIONALITY CLIENT SIDE.*********
//Sets it up so I can handle multiple diggers doing a digging action
digger_dig_init()
{
diggers = GetEntArray("digger_body","targetname");
AssertEx( diggers.size > 0, "Unable to find entity with targetname 'digger_body'" );
array_thread(diggers,::digger_dig_think);
}
//Self is the digger's body entity. Function creates a series of movements for the diggers to create a digging behavior
digger_dig_think()
{
body = self;
arm = GetEnt(self.target, "targetname");
AssertEx(IsDefined(arm), "Unable to find arm entity for a digger at " + self.origin );
blade_center = GetEnt(arm.target, "targetname");
AssertEx(IsDefined(blade_center), "Unable to find blade entity for a digger at " + self.origin );
blade_pieces = GetEntArray("digger_blade","targetname");
for( i = 0; i < blade_pieces.size; i++)
{
blade_pieces[i] LinkTo(blade_center);
}
blade_center LinkTo( arm );
arm LinkTo( body );
//play idle sound on body
body playloopsound ("evt_excavator_idle", .5);
if(IsDefined(self.script_float))
{
set_dvar_int_if_unset("scr_dig_delay", self.script_float );
}
else
{
//'20' is the default value for the cooldown on the digger's dig action
set_dvar_int_if_unset("scr_dig_delay", 20 );
}
while(1)
{
arm_move_speed = set_dvar_int_if_unset("scr_arm_move_speed", 11);
blade_spin_speed = set_dvar_int_if_unset("scr_blade_spin_speed", 80);
blade_spin_up_time = set_dvar_int_if_unset("scr_blade_spin_up_time", 3);
body_turn = RandomIntRange(-15,15);
//Must grab the absolute value of the turn value to get proper time fraction, which is the "positive_value_func"
body_turn_speed = (positive_value_func(body_turn)) * .3;
body RotateYaw(body_turn, body_turn_speed, body_turn_speed/4, body_turn_speed/4 );
// play move loop on arm, and rev one shot on body
arm playloopsound ("evt_excavator_move", .5);
body playsound ("evt_excavator_rev");
body waittill ("rotatedone");
arm Unlink(body);
arm RotatePitch(-45, arm_move_speed, arm_move_speed/4, arm_move_speed/4);
arm waittill ("rotatedone");
blade_center UnLink(arm);
blade_center RotatePitch(1800, blade_spin_speed, blade_spin_up_time, blade_spin_up_time);
smokeAngles = ( 0, arm.angles[1]+180, arm.angles[2] );
forward = anglesToForward( smokeAngles );
//playfx ( level.chopper_fx["explode"]["death"], self.origin, forward );
PlayFX( level._digger_fx, ( blade_center.origin[0], blade_center.origin[1], blade_center.origin[2]-560), forward );
//stop loop on arm
//iprintlnbold ("this is the stop I suspect"); //had to comment this out for playtest. -Leif
arm stoploopsound (1);
// play digging loop on blade
blade_center playloopsound ("evt_excavator_blade", .5);
blade_center waittill ("rotatedone");
// stop diggin loop blade
blade_center stoploopsound (.5);
blade_center LinkTo(arm);
arm RotatePitch(45, arm_move_speed, arm_move_speed/4, arm_move_speed/4 );
// play move loop on arm, and rev one shot on body
arm playloopsound ("evt_excavator_move", .5);
body playsound ("evt_excavator_rev");
arm waittill ("rotatedone");
arm LinkTo( body );
body RotateYaw((body_turn * -1), body_turn_speed, body_turn_speed/4, body_turn_speed/4);
body waittill ("rotatedone");
arm stoploopsound (.5);
wait (GetDvarFloat( #"scr_dig_delay" ));
}
}
//Sets it up so the script can easily handle multiple moving diggers
moving_diggers_init()
{
diggers = GetEntArray("moving_digger","targetname");
//AssertEx( diggers.size > 0, "Unable to find entity with targetname 'moving_digger'" );
array_thread(diggers, ::moving_diggers_think);
}
//Sets up diggers that follow structs. Note the script_int K/V pair sets up the move time.
moving_diggers_think()
{
digger_struct = getstruct_and_assert(self.target);
while(1)
{
//Each struct has a script_int key value pair that determines the length of time it takes to complete the move
self MoveTo(digger_struct.origin, digger_struct.script_int);
AssertEx(IsDefined(digger_struct.script_int), "Unable to find digger struct's 'script_int' key value pair for moving digger" );
self waittill("movedone");
//Structs target other structs to determine the digger's path.
if(IsDefined(digger_struct.target))
{
digger_struct = GetStruct(digger_struct.target,"targetname");
}
else
{
break;
}
}
}
//Function needed to get the absolute value of an integer and be sure its a positive number
positive_value_func(num)
{
return(max(1, abs(num)));
}
//Starts a thread to alter player's velocity as long as they're in the trigger
conveyer_belt_init()
{
//Need to set dvar to determine force of momentum in trigger
set_dvar_int_if_unset( "scr_coveyer_speed", 45 );
conveyer_trigger = getent_and_assert("coveyer_trig");
//The trigger targets a script struct. The struct contains angles to determine the force direction.
trigger_struct = getstruct_and_assert(conveyer_trigger.target);
//Find direction that my trigger is pointed toward
trigger_angles = AnglesToForward(trigger_struct.angles);
//Create intensity of conveyer force equal to my script DVar. Store it on my trigger for a seperate function to use.
conveyer_trigger._conveyer_vector = vector_scale(trigger_angles,GetDvarInt( #"scr_coveyer_speed"));
while(1)
{
conveyer_trigger waittill("trigger", player);
if(IsPlayer(player))
{
conveyer_trigger thread trigger_thread(player, ::player_on_conveyer);
}
wait .05;
}
}
//Self is trigger. Function is ran when player jumps into the trigger.
player_on_conveyer(player, endon_string)
{
player endon ("death");
player endon ("disconnect");
player endon(endon_string);
while(1)
{
player_velocity = player GetVelocity();
//Don't want jumping player to be pulled by conveyer
if (player IsOnGround())
{
//Gives player momentum in the direction of the conveyer equal to a dvar I created earlier along with their own momentum
player SetVelocity(player_velocity + self._conveyer_vector);
}
wait .05;
}
}
getent_and_assert(ent_name)
{
thing = GetEnt( ent_name, "targetname");
AssertEx(IsDefined(thing), "Unable to find targetname " + ent_name);
return thing;
}
getstruct_and_assert(struct_name)
{
thing = getstruct( struct_name, "targetname");
AssertEx(IsDefined(thing), "Unable to find struct at " +struct_name);
return thing;
}
dropEverythingOnDoorsToGround()
{
level endon("edge_check");
// keep dropping all to ground to keep the items in physics
// if you only do it once or twice they come back to rest to fast
// if there is a problem with this solution then we are going to need
// to do something for keeping the crates in physics while in contact
// with the doors.
while(1)
{
wait(0.1);
dropAllToGround( (0,0,128), 181, 100 );
}
}
destroyEquipment()
{
level endon ( "edge_check" );
for ( ;; )
{
wait( 2 );
grenades = GetEntArray( "grenade", "classname" );
for ( i = 0; i < grenades.size; i++ )
{
item = grenades[i];
if ( !IsDefined( item.name ) )
{
continue;
}
if ( !IsDefined( item.owner ) )
{
continue;
}
if ( !IsWeaponEquipment( item.name ) )
{
continue;
}
if ( !item IsTouching( level._door1 ) && !item IsTouching( level._door2 ) )
{
continue;
}
watcher = item.owner getWatcherForWeapon( item.name );
if ( !IsDefined( watcher ) )
{
continue;
}
watcher thread maps\mp\gametypes\_weaponobjects::waitAndDetonate( item, 0.0, undefined );
}
}
}
getWatcherForWeapon( weapname )
{
if ( !IsDefined( self ) )
{
return undefined;
}
if ( !IsPlayer( self ) )
{
return undefined;
}
for ( i = 0; i < self.weaponObjectWatcherArray.size; i++ )
{
if ( self.weaponObjectWatcherArray[i].weapon != weapname )
{
continue;
}
return ( self.weaponObjectWatcherArray[i] );
}
return undefined;
}
//spawns triggers to stop players from placing turrets
addNoTurretTrigger( position, radius, height )
{
while( !IsDefined( level.noTurretPlacementTriggers ) )
wait( 0.1 );
trigger = Spawn( "trigger_radius", position, 0, radius, height );
level.noTurretPlacementTriggers[level.noTurretPlacementTriggers.size] = trigger;
}