#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; }