We have upgraded to the latest version of MediaWiki and now support TLS1.2 and transcoding!
Please contact us via Discord or Twitter if you experience any problems.

Proto:Call of Duty 4: Modern Warfare (Windows)/Build 253/descent.gsc

From The Cutting Room Floor
Jump to navigation Jump to search

This is a sub-page of Proto:Call of Duty 4: Modern Warfare (Windows)/Build 253.

#include maps\_utility;
#include maps\_anim;
#include maps\mo_tools;
 
main()
{
    maps\descent_fx::main();
    maps\_blackhawk::main("vehicle_blackhawk");
    maps\_load::main();
    maps\descent_anim::main();
    maps\mo_globals::main("descent");
    maps\mo_fastrope::main();
    level thread maps\descent_amb::main();
 
    flag_init("floor2_pipehall_go");
    flag_init("floor3_kitchen_doorkicked");
    flag_init("insite_of_elevator");
    flag_init("random_events_hole");
    flag_init("random_events_inner");
    flag_init("move_on_to_pipehall");
    
    level.xenon = false;
    
    if (isdefined( getdvar("xenonGame") ) && getdvar("xenonGame") == "true" )
        level.xenon = true;
    
    jumptoInit();
    playerInit();
    misc_precacheInit();
    misc_radiusInit();
        
    thread objective_main();
    thread random_event_main();
    
    misc_soundDebug();
    if(level.soundDebug != "none")
        return;
    
    switch(level.jumptoFL)
    {
        case "NA":{}
        case "1":   thread floor1_main();
        case "2":   thread floor2_main();
        case "3":   thread floor3_main();
        case "4":   thread floor4_main();
    }
    jumptoThink();
    thread playerFall();
}
 
misc_soundDebug()
{
    if (getdvar("debug_sound") == "")
        setdvar("debug_sound", ""); 
    if (!isdefined(getdvar ("debug_sound")))
        setdvar ("debug_sound", "");
        
    string1 = getdvar("debug_sound");
    if(!(isdefined(string1) && string1 != ""))
    {
        level.soundDebug = "none";
        return;
    }
    
    level.soundDebug = string1;
    
    if(issubstr("screams", string1))
        random_event_lock("quake", "script_noteworthy");    
    
    flag_set("random_events_hole");
    flag_set("random_events_inner");
    trig = getent("floor2_stairs_start","targetname");
    trig notify("trigger");
}
 
misc_radiusInit()
{
    trigs = getentarray("trigger_radius","classname");
    array_thread(trigs, ::misc_radiusHandle);   
}
 
misc_radiusHandle()
{
    if(!isdefined(self.script_color_allies) && !isdefined(self.script_color_axis) && !(isdefined(self.script_noteworthy) && self.script_noteworthy == "friendly_spawner") )
        return;
    
    self waittill("trigger");
    wait .05;
 
    self.origin += (0, 0, -100000);
    if ( isDefined( self.realOrigin ) )
        self.realOrigin = self.origin;
}
 
misc_precacheInit()
{
    precacheModel("defaultactor");
    precacheModel("vehicle_mig29_desert");
    
    level.strings["obj_alassad"]        = &"DESCENT_OBJ_ALASSAD";
    level.strings["obj_photo_backhall"] = &"DESCENT_OBJ_PHOTO_BACKHALL";
    level.strings["obj_photo_bathroom"] = &"DESCENT_OBJ_PHOTO_BATHROOM";
    level.strings["obj_photo_dropdown"] = &"DESCENT_OBJ_PHOTO_DROPDOWN";
    level.strings["obj_photo_final"]    = &"DESCENT_OBJ_PHOTO_FINAL";
    level.strings["obj_photo_prison"]   = &"DESCENT_OBJ_PHOTO_PRISON";
    level.strings["obj_photo_stairs"]   = &"DESCENT_OBJ_PHOTO_STAIRS";
    level.strings["obj_secure"]         = &"DESCENT_OBJ_SECURE";
    level.strings["obj_detpack"]        = &"DESCENT_OBJ_DETPACK";
    level.strings["hint_fastrope"]      = &"DESCENT_HINTSTR_FASTROPE";
    level.strings["hint_camera_out"]    = &"DESCENT_HINTSTR_CAMERA_OUT";
    level.strings["hint_camera_click"]  = &"DESCENT_HINTSTR_CAMERA_CLICK";
    level.strings["intro1"]             = &"DESCENT_TITLE"; 
    level.strings["intro2"]             = &"DESCENT_DATE";
    level.strings["intro3"]             = &"DESCENT_PLACE";
    level.strings["intro4"]             = &"DESCENT_INFO";
    
    precacheString(level.strings["obj_alassad"]);
    precacheString(level.strings["obj_photo_backhall"]);
    precacheString(level.strings["obj_photo_bathroom"]);
    precacheString(level.strings["obj_photo_dropdown"]);
    precacheString(level.strings["obj_photo_final"]);
    precacheString(level.strings["obj_photo_prison"]);
    precacheString(level.strings["obj_photo_stairs"]);
    precacheString(level.strings["obj_secure"]);
    precacheString(level.strings["obj_detpack"]);
    precacheString(level.strings["hint_fastrope"]);
    precacheString(level.strings["hint_camera_out"]);
    precacheString(level.strings["hint_camera_click"]);
    precacheString(level.strings["intro1"]);
    precacheString(level.strings["intro2"]);
    precacheString(level.strings["intro3"]);
    precacheString(level.strings["intro4"]);
}
 
playerFall()
{
    while(1)
    {
        thread playerFallLogic();
        level waittill("player_fall_on");
    }
}
playerFallLogic()
{
    level notify("player_fall_off");
    level endon("player_fall_off"); 
 
    fallspeed = 50;
 
    height = level.player.origin[2];
    while(1)
    {
        newheight = level.player.origin[2];
        if( (height - newheight) > fallspeed ) 
        {
            thread playerFallDeath();
            break;
        }
        height = newheight;
        wait .1;
    }
}
 
playerFallDeath()
{
    level.player thread play_sound_on_entity("descent_ge1_yell");
    while(1)
    {
        level.player waittill("damage", dmg, other);
        if((isdefined(other.classname) && other.classname == "worldspawn"))
            break;
    }
    level.player enableHealthShield( false );
    level.player dodamage(level.player.health + 100000, level.player.origin);
    level.player enableHealthShield( true ); 
}
 
playerInit()
{
    level.player takeAllWeapons();
    level.player giveWeapon("USP");
    level.player giveWeapon("m4_grunt");
    level.player giveWeapon("fraggrenade");
    level.player switchToWeapon("m4_grunt");
    thread playerAmmo();
}
 
playerAmmo()
{
    while (1)
    {
        currentweapon = level.player getCurrentWeapon();
        currentammo = level.player getFractionMaxAmmo(currentweapon);
 
        if (currentammo < .2)
            level.player giveMaxAmmo(currentweapon);
        wait 5;
    }
}
 
/************************************************************************************************************************************/
/************************************************************************************************************************************/
/*                                                          OBJECTIVE LOGIC                                                         */
/************************************************************************************************************************************/
/************************************************************************************************************************************/
 
objective_camera(name, final)
{
    trig = level.obj_camera[name];
    trig objective_camera_dialog_introduce();
    level notify("objective_camera_" + name);
    
    trig thread objective_camera_on();
    
    objective_string(1, level.strings["obj_photo_" + name]);
    objective_position(1, trig getorigin());
    
    trig thread objective_camera_dialog_nag();
    trig thread objective_camera_dialog_correct();
    trig waittill("objective_done");
    
    wait 1;
    trig play_sound_on_entity("descent_ge1_datareceived");
    
    wait 3;
    if(!isdefined(final))
    {
        rand = randomint(2);
    
        switch(rand)
        {
            case 0:{    trig play_sound_on_entity("descent_ge1_negativeguy");       }break;
            case 1:{    trig play_sound_on_entity("descent_ge1_facialscan");    }break;
            //case 2:{  trig play_sound_on_entity("descent_ge1_nothim");    }break;         
        }
        wait .5;
        
        trig thread play_sound_on_entity("descent_ge1_letsgo");
    
        objective_string(1, level.strings["obj_alassad"]);
        objective_position(1, level.objective_position["obj_alassad"]); 
    }
    
    else
    {
        trig play_sound_on_entity("descent_ge1_positivescan");
        objective_string_nomessage(1, level.strings["obj_alassad"]);
        objective_state(1,  "done");    
    }
    
    autosave_by_name("objective_camera_" + name);
}
 
objective_camera_dialog_nag()
{
    self endon("objective_done");
    self endon("click");
    
    self.nagrand = 1;
    rand = 0;
    
    while(1)
    {
        wait 15;
        
        while(1)
        {
            rand = randomint(2);
            if(rand != self.nagrand)
                break;
            wait .05;
        }
        self.nagrand = rand;
        
        switch(rand)
        {
            case 0:{    self play_sound_on_entity("descent_ge4_comeonman");     }break;
            case 1:{    self play_sound_on_entity("descent_ge4_whatthehell");   }break;     
        }
    }
}
 
objective_camera_dialog_correct()
{
    self endon("objective_done");
    
    self.correctrand = 0;
    rand = 0;
    
    while(1)
    {
        self waittill("click");
        
        wait .25;
        
        while(1)
        {
            rand = randomint(3);
            if(rand != self.correctrand)
                break;
            wait .05;
        }
        self.correctrand = rand;
        
        switch(rand)
        {
            case 0:{    self play_sound_on_entity("descent_ge4_nohisface");     }break;
            case 1:{    self play_sound_on_entity("descent_ge4_identifyboots"); }break;
            case 2:{    self play_sound_on_entity("descent_ge4_zoomonface");    }break;     
        }
    }
}
 
objective_camera_dialog_introduce()
{
    rand = randomint(4);
    
    switch(rand)
    {
        case 0:{    self play_sound_on_entity("descent_ge4_takepicture");   }break;
        case 1:{    self play_sound_on_entity("descent_ge4_mightbehim");    }break;
        case 2:{    self play_sound_on_entity("descent_ge4_bealassad");     }break;     
        case 3:{    self play_sound_on_entity("descent_ge4_foundsomebody"); }break;     
    }
}
 
 
 
objective_camera_on()
{
    org = self getorigin();
    dist = 128;
    check = dist * dist;
    
    while(distancesquared(level.player.origin, org) > check)
        wait .1;
    
    hint = hint_create(level.strings["hint_camera_out"]);
    self thread objective_camera_off(hint);
    self thread objective_camera_click(hint);
}
 
objective_camera_click(hint)
{
    hint endon("left_area");    
    while( !(level.player useButtonPressed()) )
        wait .05;
    
    playerWeaponTake();
    hint hint_delete();
    playerCameraGive();
    hint = hint_create(level.strings["hint_camera_click"]);
    
    self thread objective_camera_off(hint);
    
    hint endon("left_area");
    
    while(1)
    {
        while( !(level.player attackButtonPressed()) )
            wait .05;
        
        play_sound_in_space("end_of_autoclip",level.player.origin);
        self notify("click");
        
        if(level.player islookingat(self))
            break;
 
        wait .05;
    }
    hint hint_delete();
    playerCameraTake();
    playerWeaponGive();
    
    self notify("objective_done");
}
 
objective_camera_off(hint)
{
    hint endon("death");
    
    org = self getorigin();
    dist = 256;
    check = dist * dist;
    
    while(distancesquared(level.player.origin, org) < check)
        wait .1;
    
    hint notify("left_area");   
    playerCameraTake();
    playerWeaponGive();
    thread objective_camera_on();
    hint thread hint_delete();  
}
 
playerCameraGive()
{
    level.camera endon("take_away");
    level.camera show();
    
    level.camera.given = true;
    level.camera.fov = getdvar("cg_fov");
    
    
    thread playerCameraHold();
    wait .5;
    thread playerCameraZoom();
}
 
playerCameraHold()
{
    level.camera endon("take_away");
    while(1)
    {
        height = 60;
        if(level.player getstance() == "crouch")
            height = 40;
        else if(level.player getstance() == "prone")
            height = 12;
        ang1        = level.player getplayerangles();
        ang         = level.player.angles;
        forward2    = anglestoforward(ang1);
        forward2    = vector_multiply(forward2, 20);
        up          = anglestoup(ang);
        up          = vector_multiply(up, height);
        up2         = anglestoup(ang1);
        up2         = vector_multiply(up2, -2);
        org         = (level.player.origin + up + forward2 + up2);
        
        level.camera.angles = (ang1);
        level.camera moveto(org, .12);
        wait .05;
    }
}
 
playerCameraZoom()
{
    level.camera endon("take_away");    
    
    range = 0.0;
    while(1)
    {
        while(!(level.player useButtonPressed()) )
        {
            if(range > 0)
                range -= 5;
            setsaveddvar("cg_fov", int(level.camera.fov) - (range));    
            wait .05;   
        }
        
        if(range < 30)
                range += 5;
        setsaveddvar("cg_fov", int(level.camera.fov) - (range));        
        wait .05;   
    }
}
 
playerCameraTake()
{
    if(!isdefined(level.camera.given))
        return;
    level.camera.givin = undefined;
    level.camera notify("take_away");
    level.camera hide();
    level.camera unlink();
    
    waittillframeend;
    if( getdvar("cg_fov") != level.camera.fov )
        setsaveddvar("cg_fov", level.camera.fov);
}
 
objective_camera_init()
{
    level.camera = getent("player_camera","targetname");
    level.camera hide();
    
    obj = getentarray("objective_camera", "targetname");
    level.obj_camera = [];
    for(i=0; i<obj.size; i++)
        level.obj_camera[obj[i].script_noteworthy] = obj[i];
}
 
objective_main()
{
    objective_camera_init();
    if(level.jumpto == "start")
        wait 5;
    objnum = 1;
    objective_add(1, "active");
    objective_string_nomessage(1, level.strings["obj_alassad"]);
    if(level.jumpto != "start")
        objective_current(1);
    thread objective_move(level.jumpto, 1);
    objnum++;
    
    switch(level.jumpto)
    {
        case "start":{
            node = getstruct("obj_pos_secure", "targetname");
            objective_add(objnum, "active", level.strings["obj_secure"], node.origin);
            objective_current(objnum);
                
            level waittill("secured_landing_zone");
            
            objective_state(objnum,  "done");
            objnum++;
            
            trig = getentarray("floor1_start_breach", "script_noteworthy");//if the player already blew through the wall
                if(trig.size)
                {
                    objective_add(objnum, "active", level.strings["obj_detpack"], trig[0] getorigin());
                    objective_current(objnum);
                
                    array_wait(trig, "trigger", 0);
                    wait (trig[0].time);
                
                    objective_state(objnum,  "done");
                    objnum++;
                }
            objective_current(1);
            //objective_string(1, level.strings["obj_alassad"]);
            }
        case "office":{
            thread objective_move("start", 1, "office");
            }
        case "bathroom":{       
            thread objective_move("start", 1, "bathroom");  
            }
        case "loadingdock":{
            }
        case "road":{
            }
        case "gate":{
            thread objective_move("road", 1, "gate");   
            }
        case "food":{
            }
        case "dropdown":{
            }
        case "pipehall":{
            }
        case "airfilter":{
            }
        case "boiler":{
            }
        case "stairs":{
            }
        case "backhall":{
            }
        case "backhall2":{
            thread objective_move("backhall5", 1, undefined, "floor3_new_route");
            }
        case "cafeteria":{
            }
        case "kitchen":{
            }
        case "shaft":{
            thread objective_move("kitchen", 1,"shaft");
            }
        case "fubar":{
            }
    }   
}
 
objective_move(name, objnum, check, msg)
{
    if(isdefined(check) && level.jumpto != check)
        return;
    
    if(!isdefined(level.objective_position))
        level.objective_position = [];
    
    if(isdefined(msg))
        level waittill(msg);
        
    level notify("objective_move_" + objnum);
    level endon("objective_move_" + objnum);
    
    trig = getent("objective_move_" + name, "targetname");
    
    while(isdefined(trig))
    {
        objective_position(objnum, trig.origin);
        level.objective_position["obj_alassad"] = trig.origin;
        trig waittill("trigger");
        if(!isdefined(trig.target))
            trig = undefined;
        else
            trig = getent(trig.target, "targetname");   
    }
}
 
/************************************************************************************************************************************/
/************************************************************************************************************************************/
/*                                                          JUMPTO LOGIC                                                            */
/************************************************************************************************************************************/
/************************************************************************************************************************************/
 
jumptoInit()
{
    if (getdvar("jumpto") == "")
        setdvar("jumpto", "");
    
    if (!isdefined(getdvar ("jumpto")))
        setdvar ("jumpto", "");
        
    //skip to a point in the level
    string1 = getdvar("start");
    string2 = getdvar("jumpto");
    level.jumptoFL  = "NA";
    level.jumpto    = "start";
    
    if(isdefined(string1) && string1 != "")
        level.jumpto = string1;
    if(isdefined(string2) && string2 != "")
        level.jumpto = string2;
    
    jumpnum = 1;
    if(level.jumpto == "office" || level.jumpto == "" + jumpnum)    
    {   level.jumptoFL = "1"; level.jumpto = "office"; return; }
    jumpnum++;
        if(level.jumpto == "bathroom" || level.jumpto == "" + jumpnum)  
    {   level.jumptoFL = "1"; level.jumpto = "bathroom"; return; }
    jumpnum++;
    if(level.jumpto == "loadingdock" || level.jumpto == "" + jumpnum)   
    {   level.jumptoFL = "1"; level.jumpto = "loadingdock"; return; }
    jumpnum++;
    if(level.jumpto == "road" || level.jumpto == "" + jumpnum)  
    {   level.jumptoFL = "1"; level.jumpto = "road"; return; }
    jumpnum++;
    if(level.jumpto == "gate" || level.jumpto == "" + jumpnum)  
    {   level.jumptoFL = "1"; level.jumpto = "gate";  return; }
    jumpnum++;
    if(level.jumpto == "food" || level.jumpto == "" + jumpnum)
    {   level.jumptoFL = "1"; level.jumpto = "food";  return; }
    jumpnum++;
    if(level.jumpto == "dropdown" || level.jumpto == "" + jumpnum)
    {   level.jumptoFL = "1"; level.jumpto = "dropdown";  return; }
    jumpnum++;
    if(level.jumpto == "pipehall" || level.jumpto == "floor2" || level.jumpto == "" + jumpnum)
    {   level.jumptoFL = "2"; level.jumpto = "pipehall";  return; }
    jumpnum++;
    if(level.jumpto == "airfilter" || level.jumpto == "" + jumpnum)
    {   level.jumptoFL = "2"; level.jumpto = "airfilter";  return; }
    jumpnum++;
    if(level.jumpto == "boiler" || level.jumpto == "" + jumpnum)
    {   level.jumptoFL = "2"; level.jumpto = "boiler";  return; }
    jumpnum++;
    if(level.jumpto == "stairs" || level.jumpto == "" + jumpnum)
    {   level.jumptoFL = "2"; level.jumpto = "stairs";  return; }
    jumpnum++;
    if(level.jumpto == "backhall" || level.jumpto == "floor3" || level.jumpto == "" + jumpnum)
    {   level.jumptoFL = "3"; level.jumpto = "backhall";  return; }
    jumpnum++;
    if(level.jumpto == "backhall2" || level.jumpto == "" + jumpnum)
    {   level.jumptoFL = "3"; level.jumpto = "backhall2";  return;  }
    jumpnum++;
    if(level.jumpto == "cafeteria" || level.jumpto == "" + jumpnum)
    {   level.jumptoFL = "3"; level.jumpto = "cafeteria";  return;  }
    jumpnum++;
    if(level.jumpto == "kitchen" || level.jumpto == "" + jumpnum)
    {   level.jumptoFL = "3"; level.jumpto = "kitchen";  return;    }
    jumpnum++;
    if(level.jumpto == "shaft" || level.jumpto == "elevator" || level.jumpto == "" + jumpnum)
    {   level.jumptoFL = "3"; level.jumpto = "shaft";  return;  }
    jumpnum++;
    if(level.jumpto == "fubar" || level.jumpto == "floor4" || level.jumpto == "" + jumpnum)
    {   level.jumptoFL = "4"; level.jumpto = "fubar";  return; }
    jumpnum++;
}
 
jumptoThink()
{
    jumptoRandomTrig(level.jumpto);
    trig = [];
    on = getent("random_quake_on","targetname"); //inner random events
    on.jumptoRandomType = "trigger";
    off = getent("floor1_dummies2_trig","targetname");
    off.jumptoRandomType = "off";
    
    switch(level.jumpto)
    {
        case "bathroom":{
            trig = array_add(trig, off);
            trig[trig.size] = getent("floor1_office_backup", "targetname");
            trig[trig.size-1].jumptoRandomType = "off";
            trig[trig.size] = getentarray("floor1_start_breach", "script_noteworthy")[0];
            trig[trig.size-1].jumptoRandomType = "trigger";
            }   
        case "office":{
            trig = array_add(trig, off);
            trig[trig.size] = getent("floor1_intro_runners", "target");
            trig[trig.size-1].jumptoRandomType = "off";
            trig[trig.size] = getent("floor1_intro_enemy_trig", "targetname");
            trig[trig.size-1].jumptoRandomType = "off";
            trig = array_combine(trig, getentarray("auto2164","targetname"));
            }break;
        case "loadingdock":{
            trig = array_add(trig, off);
            trig = array_combine(trig, getentarray("auto29","targetname"));
            }break;
        case "road":{
            trig = array_add(trig, on);
            trig = array_add(trig, off);
            trig = array_combine(trig, getentarray("auto28","targetname"));
            }break;
        case "gate":{
            trig = array_add(trig, on);
            trig = array_add(trig, off);
            trig = array_combine(trig, getentarray("auto53","targetname"));
            }break;
        case "food":{
            trig = array_add(trig, on);
            trig = array_add(trig, off);
            trig = array_combine(trig, getentarray("auto75","targetname"));
            }break; 
        case "dropdown":{
            trig = array_add(trig, on);
            trig = array_add(trig, off);
            trig = array_combine(trig, getentarray("auto81","targetname")); 
            }break; 
        case "pipehall":{
            trig = array_add(trig, off);
            }break;
        case "airfilter":{
            trig = array_add(trig, on);
            trig = array_combine(trig, getentarray("auto315","targetname")); 
            }break;
        case "boiler":{
            trig = array_add(trig, on);
            trig = array_combine(trig, getentarray("floor2_airfilter_start","targetname"));
            }break;
        case "stairs":{
            trig = array_add(trig, on);
            trig = array_combine(trig, getentarray("auto362","targetname"));
            }break;
        case "backhall":{
            trig = array_add(trig, on);
            trig = array_combine(trig, getentarray("floor2_stairs_start","targetname"));
            }break; 
        case "backhall2":{
            trig = array_add(trig, on);
            trig = array_combine(trig, getentarray("floor2_stairs_start","targetname"));
            }break; 
        case "cafeteria":{
            trig = array_add(trig, on);
            trig[trig.size] = getent("auto216", "targetname");//door to the gameroom area that needs to open
            trig[trig.size-1].jumptoRandomType = "open";
            trig = array_combine(trig, getentarray("auto185","targetname"));
            }break;
        case "kitchen":{
            trig = array_add(trig, on);
            }break; 
        case "shaft":{
            trig = array_add(trig, on);
            trig = array_combine(trig, getentarray("floor3_kitchen_spawner","targetname"));
            }break;
        case "fubar":{
            trig = array_add(trig, on);
            trig = array_combine(trig, getentarray("floor4_elevatorguys","targetname"));
            }break;
    }
        
    array_thread(trig, ::jumptoRandomTrigThink);
    
    if(level.jumpto != "start")
        flag_set("random_events_inner");
    
    node = getstruct(("jumpto_" + level.jumpto), "targetname");
    if(!isdefined(node))
        return;
    level.player setorigin (node.origin + (0,0,32));
    level.player setplayerangles (node.angles);
}
 
jumptoRandomTrig(name)
{
    array = getentarray("jumptoRandomTrig", "script_noteworthy");
    for(i=0;i<array.size;i++)
    {
        attr = strtok(array[i].script_parameters, ":;, ");
        for(j=0;j<attr.size; j++)
        {
            if(attr[j] == name)
            {
                array[i].jumptoRandomType = tolower(attr[j+1]);
                array[i] thread jumptoRandomTrigThink();
                break;  
            }
        }
    }
}
 
jumptoRandomTrigThink()
{
    if(self.classname != "trigger_multiple" && self.classname != "trigger_radius" && (!isdefined(self.jumptoRandomType)) )
        return;
    if(!isdefined(self.jumptoRandomType))
        self.jumptoRandomType = "trigger";
    switch(self.jumptoRandomType)
    {
        case "trigger":     {wait .1; self notify("trigger");   }break;
        case "off":         {self trigger_off();                }break;
        case "open":        {self door_breach_door();           }break;
    }
}
 
/************************************************************************************************************************************/
/************************************************************************************************************************************/
/*                                                          *FLOOR 1*                                                               */
/************************************************************************************************************************************/
/************************************************************************************************************************************/
 
floor1_main()
{
    switch(level.jumpto)
    {
        case "start":{
            floor1_intro();
            flag_set("random_events_inner");
            floor1_intro_breach();
            }
        case "office":{
            wait .1;
            flag_set("random_events_hole");
            floor1_office();
            }
        case "bathroom":{
            thread floor1_bathroom_guy();
            floor1_bathroom();
            }
        case "loadingdock":{
            floor1_loadingdock();
            }
        case "road":{
            floor1_road();
            }
        case "gate":{
            floor1_gate();
            }
        case "food":{
            thread floor1_food();
            }
        case "dropdown":{
            floor1_dropdown();
            }
    }
}
 
floor1_bathroom_guy()
{
    node = getnode("floor1_restroom_blocknode", "targetname");
    spawner = getentarray("floor1_restroom_friendlies","target");
    chain = getent("floor1_restroomdone_chain","targetname");
    trig = getent("floor1_bathroom_start","targetname");
    
    trig waittill("trigger");
    
    guy = spawner[0] maps\mo_globals::friendly_spawner_think();
    guy.ignoreme = true;
    guy thread magic_bullet_shield();
    guy pushplayer(true);
    createThreatBiasGroup("bathroomguy");
    guy setthreatbiasgroup("bathroomguy");
    setignoremegroup("axis", "bathroomguy");
    wait .5;
    guy disable_ai_color();
    guy setgoalnode(node);
    guy.goalradius = node.radius;
    
    chain waittill("trigger");
    
    guy pushplayer(false);
    guy.ignoreme = false;
    guy notify("stop magic bullet shield");
    guy enable_ai_color();
    guy setthreatbiasgroup();
}
 
floor1_bathroom()
{
    trig = getent("floor1_bathroom_start","targetname");
    chain = getent("floor1_restroomdone_chain","targetname");
    
    trig waittill("trigger");
    
    wait .5;
    
    ai = getaiarray("allies");
    array_wait(ai, "goal", .5);
    
    objective_camera("bathroom");
    
    chain notify("trigger");
}
 
floor1_intro()
{
    thread floor1_intro_fx();
    thread floor1_intro_officer();
    spwn = getentarray("floor1_intro_runners","targetname");
    array_thread(spwn, ::floor1_intro_runners);
    spawners = getentarray("intro_ally_dummies1","targetname");
    array_thread(spawners, ::floor1_intro_dummies1);
    spawners = getentarray("intro_ally_dummies2", "targetname");
    array_thread(spawners, ::floor1_intro_dummies2);
 
    //for clear dialogue
    spwn = array_combine(spwn, getentarray("floor1_intro_enemy","targetname"));
    temp = getent("floor1_dummies2_trig","targetname");
    spwn = array_combine(spwn, getentarray(temp.target, "targetname"));
 
    musicPlay("descent_intro_music"); 
    //level thread maps\_introscreen::introscreen_delay(level.strings["intro1"], level.strings["intro2"], level.strings["intro3"], level.strings["intro4"], 2, 2, 1);
    //player blackhawk repel shit
    floor1_intro_player();
    autosave_by_name("default");
    thread play_sound_in_space("descent_ga1_theyreup", (1912, -408, -180));
    
    ai = get_ai("floor1_intro_enemy", "axis", "script_noteworthy");
    officer = get_ai("floor1_intro_officer", "axis", "script_noteworthy");
    ai = array_combine(ai, officer);
    for(i=0; i<ai.size; i++)
    {
        ai[i].suppressionwait = 0;
        ai[i].anim_forced_cover = "show";
    }
    
    wait 2.5;
    thread play_sound_in_space("descent_ga1_hurryup", (1920, 0, -116));
    ai_clear_dialog(spwn);
 
    thread floor1_events_handler();
}
 
floor1_intro_officer()
{
    model = getent("floor2_objective_guy", "targetname");
    spawner = getent("floor1_intro_officer","script_noteworthy");
    guy = undefined;
 
    model hide();
    
    while(1)
    {
        spawner waittill("spawned", guy);
        if(!spawn_failed(guy))
            break;
    }
    
    guy waittill("death");
    model show();
}
 
floor1_intro_fx()
{
    ent = getstruct("intro_temp_explosions","targetname");
    wait 5;
    playfx(level._effect["exp_randomevent"], ent.origin, anglestoforward(ent.angles));
    thread play_sound_in_space("bricks_exploding", ent.origin);
    
    ent = getstruct(ent.target,"targetname");
    wait 5;
    playfx(level._effect["exp_randomevent"], ent.origin, anglestoforward(ent.angles));
    thread play_sound_in_space("bricks_exploding", ent.origin);
    
    ent = getstruct(ent.target,"targetname");
    wait 2;
    playfx(level._effect["exp_randomevent"], ent.origin, anglestoforward(ent.angles));
    thread play_sound_in_space("bricks_exploding", ent.origin);
    
    ent = getstruct(ent.target,"targetname");
    wait 5;
    playfx(level._effect["exp_randomevent"], ent.origin, anglestoforward(ent.angles));
    thread play_sound_in_space("bricks_exploding", ent.origin);
    
    ent = getstruct(ent.target,"targetname");
    wait 15;
    playfx(level._effect["exp_randomevent"], ent.origin, anglestoforward(ent.angles));
    thread play_sound_in_space("bricks_exploding", ent.origin);     
}
 
floor1_events_handler()
{
    //the player has almost landed so lets turn the bottom half of the random events on...wait for the 2nd helicopter to pass by before turning the rest on
    random_event_lock("flyby", "script_noteworthy");
    random_event_lock("dropoff","script_noteworthy");
    flag_set("random_events_hole");
    
    heli = level.fastrope_globals.helicopters[maps\mo_fastrope::fastrope_heliname("intro_ally_dummies1")];
    heli.vehicle waittill("going_home");
    wait 2;
    random_event_unlock("flyby","script_noteworthy");
    random_event_unlock("dropoff","script_noteworthy");
}
 
floor1_intro_player()
{
    trig =  getent("intro_spawners","targetname");
    temp = getentarray("intro_spawners", "target");
    name = temp[0].targetname;
    
    trig notify ("trigger");
        
    wait .1;
 
    heli = level.fastrope_globals.helicopters[maps\mo_fastrope::fastrope_heliname(name)];
    wait .1;
    level.player setplayerangles((30, 45, 0));
    
    wait 1;
    heli.model play_sound_on_entity("descent_plt_thirtyseconds");
    wait 5;
    heli.model play_sound_on_entity("descent_cop_intelreports");
    heli.model play_sound_on_entity("descent_cop_yourobjective");
    wait .75;
    heli.model play_sound_on_entity("descent_jns_cameradetail");
    wait 6;
    heli.model play_sound_on_entity("descent_plt_fiveseconds");
    
    
    heli.vehicle waittill("reached_wait_node");
    
    heli.model play_sound_on_entity("descent_jns_letsdoit");
}
 
floor1_intro_breach2(chain)
{
    chain2 = getent("floor1_office_chain", "script_noteworthy");
    chain waittill("trigger");
    level notify("secured_landing_zone");
    chain2 waittill("trigger");
    
    ai = getaiarray("axis");
    for(i=0; i<ai.size; i++)
        ai[i] delete();
}
 
floor1_intro_breach()
{
    chain2 = getent("floor1_office_prechain","targetname"); 
    chain = getent("intro_wallbreach_chain","targetname");
    
    thread floor1_intro_breach2(chain2);
    chain2 endon("trigger");
    
    level waittill("ai_clear_dialog_done");
    wait .25;
    
    //play_sound_in_space("descent_ge3_exithallway", (1448, -712, 28));
    play_sound_in_space("descent_cmd_badshape", (1448, -712, 28));
    level notify("secured_landing_zone");
    chain notify("trigger");
    play_sound_in_space("descent_cmd_plantdetpack", (1472, -1024, 28));
}
 
floor1_intro_dummies2death()
{
    self endon("survived");
    
    org = self.origin;
    self waittill("death");
        
    ai = get_ai("floor1_intro_dummy2bad", "axis", "script_noteworthy");
    if(ai.size)
        ai[0] dodamage(ai[0].health + 200, org);
}
 
floor1_intro_dummies2()
{
    guy = undefined;
    trig = getent("floor1_dummies2_trig","targetname");
    while(1)
    {
        self waittill("spawned", guy);
        if(!spawn_failed(guy))
            break;
    }
    
    wait .1;
    self notify("death");//this gets him off the friendly logic
    level.friendly_globals.cur_num--;
    guy thread floor1_intro_dummies2death();
    guy endon("death");
    
    guy.health = guy.health * 2;
    guy.baseaccuracy = 1;
    
    trig waittill("trigger");
    wait 1;
    
    ai = get_ai("floor1_intro_dummy2bad", "axis", "script_noteworthy");
    if(ai.size)
        array_wait(ai, "death");
    
    guy notify("survived");
    
    node = getnode("floor1_intro_dummy2node","targetname");
    guy set_forcegoal();
    guy setgoalnode(node);
    guy.goalradius = node.radius;
    
    guy waittill("goal");
    guy delete();
}
 
floor1_intro_dummies1()
{
    guy = undefined;
    while(1)
    {
        self waittill("spawned", guy);
        if(!spawn_failed(guy))
            break;
    }
    
    wait .1;
    self notify("death");//this gets him off the friendly logic
    level.friendly_globals.cur_num--;
    guy endon("death");
    guy waittill("goal");
    guy delete();
}
 
floor1_intro_runners()
{
    node = getnode(self.target, "targetname");
    guy = undefined;
    while(1)
    {
        self waittill("spawned", guy);
        if(!spawn_failed(guy))
            break;
    }
    
    guy.pathenemyfightdist  = guy.pathenemyfightdist * 1.75;
    guy.pathenemylookahead  = guy.pathenemylookahead * 1.75;
    guy.maxsightdistsqrd    = guy.maxsightdistsqrd * 1.75;
    //guy thread floor1_intro_runnersthink(node);
    guy thread floor1_intro_runnersdelete();
}
 
floor1_intro_runnersthink(node)
{
    self endon("death");
    while(1)
    {
        set_forcegoal();
        wait randomfloatrange(2, 4);
        while(1)
        {
            if(self cansee(level.player))
                break;
            wait .5;
        }
        self setgoalpos(self.origin);
        unset_forcegoal();
        wait randomfloatrange(5,8);
        self setgoalnode(node);
    }   
}
 
floor1_intro_runnersdelete()
{
    self endon("death");    
    self waittill("goal");
    self delete();
}
 
floor1_dropdown_allies()
{
    node = getnode("floor2_dropdown_ally_goal","targetname");
    clip = getent("floor2_dropdown_clip","targetname");
    spawners = getentarray("dropdown_spawners","targetname");
    trig = getent("dropdown2_friendlies","targetname");
    
    wait 1;
    while(level.floor2_dropdown_baddies)
        level waittill("floor2_dropdown_baddies");  
    
    for(i=0; i<spawners.size; i++)
        spawners[i] delete();
    
    ai = getaiarray("allies");
    
    org = (0,0,0);
    
    clip notsolid();
    clip connectpaths();
    clip delete();
    
    for(i=0; i<ai.size; i++)
    {
        if(isdefined(ai[i] get_force_color()) )
            continue;
        
        wait randomfloat(.5);
        
        ai[i] thread floor1_dropdown_allies_think(node);
        org = ai[i].origin; 
    }
    
    if(flag("floor2_pipehall_go"))
        return;
    
    level endon("floor2_pipehall_go");
    
    thread play_sound_in_space("descent_ge3_thanksfellas", (1500, -883, -271));
    
    wait 2; 
        
    thread play_sound_in_space("descent_ge3_anytime", trig getorigin());
    flag_set("move_on_to_pipehall");
    trig notify("trigger");
}
 
floor1_dropdown_allies_think(node)
{
    self setgoalnode(node);
    self.goalradius = node.radius;
    self endon("death");
    self waittill("goal");
    self delete();
}
 
floor1_dropdown_baddies()
{
    while(1)
    {
        self waittill("spawned", guy);
        if(!spawn_failed(guy))
            break;
    }
    level.floor2_dropdown_baddies++;
    guy waittill("death");
    level.floor2_dropdown_baddies--;
    level notify("floor2_dropdown_baddies");    
}
 
floor1_dropdown_pipehallcheck()
{
    trig = getent("floor2_pipehall_go","targetname");
    trig waittill("trigger");
    
    flag_set("floor2_pipehall_go");
    
    ai = get_ai("floor2_dropdown_badies","axis","script_noteworthy");
    for(i=0; i<ai.size; i++)
        ai[i] dodamage(ai[i].health + 100, ai[i].origin);
}
 
floor1_dropdown()
{
    trig = getent("dropdown_yellowspawners","targetname");
    drop = getent("objective_move_dropdown2","targetname");
    spawners = getentarray("dropdown_forcecolor_switch", "targetname");
    baddies = getentarray("floor2_dropdown_badies","script_noteworthy");
    forcethis = spawners;
    
    temp = getentarray("dropdown_yellowspawners","target");
    for(i=0; i<temp.size; i++)
    {
        if(isdefined(temp[i].script_parameters) && issubstr(temp[i].script_parameters, "hack_floor2specialguy") )
            forcethis[forcethis.size] = temp[i];
    }
    
    level.floor2_dropdown_baddies = 0;
    array_thread(baddies, ::floor1_dropdown_baddies);
    thread floor1_dropdown_pipehallcheck();
    thread floor1_dropdown_objective();
    
    trig waittill("trigger");
    
    level notify("player_fall_off");
    
    thread play_sound_in_space("descent_ge3_troubledownthere", (1085, 228, 0));
    
    thread floor1_dropdown_allies();
    //wait for the fight to last 15 second or immediately if the trigger is hit
    drop wait_timeout("trigger", 10);
    
    if(flag("move_on_to_pipehall"))
        return;
    for(i=0; i<spawners.size; i++)
        spawners[i] set_force_color("yellow");
    
    for(i=0; i<forcethis.size; i++)
        forcethis[i].force_this_color = "yellow";
        
    ai = getaiarray("allies");
    
    org = (0,0,0);
    for(i=0; i<ai.size; i++)
    {
        if(isdefined(ai[i] get_force_color()) && ai[i] check_force_color("red") )
        {
            wait randomfloat(.5);
            ai[i] set_force_color("yellow");
            org = ai[i].origin;     
        }
    }
    
    thread play_sound_in_space("descent_ge1_letsgo", org);
}
 
floor1_dropdown_objective()
{
    chain = getent("dropdown_chain","targetname");
    trig = getent("food_done_chain","targetname");
    trig waittill("trigger");
    
    wait 1;
    
    ai = get_ai("red", "allies", "script_forcecolor");
    array_wait(ai, "goal", 0);
    
    objective_camera("dropdown");
    
    chain notify("trigger");
}
 
floor1_road()
{
    trig = getent("floor1_road_backup","target");
    spwn = getentarray(trig.target,"targetname");
    spwn = array_combine(spwn, getentarray("floor1_road_enemies","targetname"));
    
    trig waittill("trigger");
    thread play_sound_in_space("descent_ga1_dirkadirka", (1587, -1836, 0)); 
    ai_clear_dialog(spwn);
}
 
floor1_gate()
{
    
}
 
floor1_loadingdock()
{
    flee = getent("loadingdock_flee","targetname");
    trig = getent("loadingdock_start","targetname");
    
    flee thread floor1_loadingdock_flee();
    trig waittill ("trigger");
    backup = getentarray("floor1_loadingdock_guys","targetname");
    
    wait .25;
    
    ai = getaiarray("axis");
    floodspawner_switch(ai, backup);
    
    level.loadingdockdeaths = 0;
    array_thread(ai, ::floor1_loadingdock_death);
    array_thread(backup, ::floor1_loadingdock_spwner);
    
    flee endon("trigger");
    
    while(level.loadingdockdeaths < 4)
        level waittill("loadingdockdeath");
        
    flee notify("trigger");
}
 
floor1_loadingdock_flee()
{
    self waittill("trigger");
    thread play_sound_in_space("descent_ga1_retreat", (2864, -1272, 28));   
}
floor1_loadingdock_spwner()
{
    self endon("death");
    while(1)
    {
        self waittill("spawned", guy);
        if(spawn_failed(guy))
            continue;
            
        guy thread floor1_loadingdock_death();
    }
}
 
floor1_loadingdock_death()
{
    self waittill("death"); 
    level.loadingdockdeaths++;
    level notify("loadingdockdeath");
}
 
floor1_food()
{
    chain = getent("dropdown_chain","targetname");
    trig = getent("food_enemycheck", "targetname");
    spwn = getentarray("floor1_food_enemies", "targetname");
    
    thread floor1_food_endchain(chain);
    thread floor1_food_breach(chain);
    
    trig waittill("trigger");
    waittillframeend;
    ai_clear_dialog(spwn, chain, "trigger");
}
 
floor1_food_breach(chain)
{
    chain endon("trigger");
    
    check = getent("floor1_food_breach_check","script_noteworthy");
    trig = getent("floor1_food_enemies","target");
    
    check waittill("trigger");
    trig notify("trigger");
}
 
floor1_food_endchain(chain)
{
    chain endon("trigger");
    
    trig = getent("food_enemycheck", "targetname");
    trig waittill("trigger");
    
    axis = getaiarray("axis");
    if(axis.size)
        array_wait(axis, "death");  
 
    trig = getent("food_done_chain","targetname");
    trig notify("trigger");
}
 
floor1_office()
{
    thread floor1_office_breach();
    trig = getent("floor1_office_backup", "targetname");
    spwn = getentarray(trig.target, "targetname");
    
    trig waittill("trigger");
    waittillframeend;
    ai_clear_dialog(spwn);
}
 
floor1_office_breach()
{
    check   = getent("office_breach_check","script_noteworthy");
    trig    = getentarray("floor1_office_breach", "script_noteworthy");
    spwn    = getent("floor1_office_backup", "targetname");
    end     = getent("loadingdock_start","targetname");
    
    end endon("trigger");
        
    array_wait(trig, "trigger", 0);
    
    thread play_sound_in_space("descent_ga1_behindwall", (2208, -488, 28));
    
    wait(trig[0].time);
    spwn notify("trigger");
}
 
/************************************************************************************************************************************/
/************************************************************************************************************************************/
/*                                                          *FLOOR 2*                                                               */
/************************************************************************************************************************************/
/************************************************************************************************************************************/
 
floor2_main()
{
    jumpto = level.jumpto;
    if(level.jumptoFL != "2")
        jumpto = "start";
    
    switch(jumpto)
    {
        case "start":{
            floor2_dropdown();
            }
        case "pipehall":{
            floor2_pipehall();
            }
        case "airfilter":{
            floor2_airfilter();
            }
        case "boiler":{
            floor2_boiler();
            }   
        case "stairs":{
            floor2_stairs();
            }
    }
}
 
floor2_stairs()
{
    chain = getent("floor1_stairsdone_chain","targetname");
    trig = getent("stairs_dropin_friendlies","targetname"); 
    
    trig waittill("trigger");
    
    wait 1;
    
    ai = getaiarray("allies");
    array_wait(ai, "goal", 0);
    
    objective_camera("stairs");
    
    chain notify("trigger");
}
 
floor2_dropdown()
{
    trig = getent("dropdown2_friendlies","targetname");
    drop = getent("objective_move_dropdown2","targetname");
    temp = getentarray("dropdown_yellowspawners","target");
    
    forcethis = undefined;
    for(i=0; i<temp.size; i++)
    {
        if(isdefined(temp[i].script_parameters) && issubstr(temp[i].script_parameters, "hack_floor2specialguy") )
            forcethis = temp[i];
    }
    drop thread floor2_dropdown_playerfall();
    drop waittill("trigger");
    
    if(!flag("move_on_to_pipehall"))
        trig waittill("trigger");
    flag_set("move_on_to_pipehall");
    
    ai = get_ai("yellow", "allies", "script_forcecolor");
    for(i=0; i<ai.size; i++)
        ai[i] set_force_color("red");
    
    forcethis.force_this_color = "red";
}
 
floor2_dropdown_playerfall()
{
    self waittill("trigger");
    wait 1;
    level notify("player_fall_on");
}
 
floor2_pipehall()
{
    thread floor2_pipehall_killspawner();
    
    trig = getent("floor2_pipehall_donechain","targetname");
    trig waittill("trigger");
    
    ai = getaiarray("allies");
    for(i=0; i<ai.size; i++)
        ai[i] set_force_color("red");
}
 
floor2_pipehall_killspawner()
{
    start = getent("floor2_pipehall_enemies","target");
    spwn = getentarray(start.target,"targetname");
    trig = getent("floor2_pipehall_donechain","targetname");
    
    trig endon("trigger");
    
    start waittill("trigger");
    waittillframeend;
    ai_clear_dialog(spwn);
    
    level waittill("ai_clear_dialog_done");
        
    trig notify("trigger");
}
 
floor2_airfilter()
{
    thread floor2_airfilter_wav2();
    thread floor2_airfilter_wallbreach();
    
    watch = getent("floor2_airfilter_watchleft","targetname");
    flank = getent("floor2_airfilter_flankingus","targetname");
    kill = getent("floor2_airfilter_wav2_trig","targetname");
    
    trig = getent("floor2_airfilter_wav1","target");
    flankers = getent("floor2_airfilter_flankers","targetname");
    
    
    trig waittill("trigger");
    wait 1;
    thread play_sound_in_space("descent_ga1_downthere", (2008, 1808, -180));
    
    wait randomfloatrange(2, 3);
    thread play_sound_in_space("descent_ge1_flankem", trig.origin);
    flankers notify("trigger");
    
    kill endon("trigger");
    
    watch waittill("trigger");
    thread play_sound_in_space("descent_ge3_leftside", (1264, 1712, -264));
    flank waittill("trigger");
    thread play_sound_in_space("descent_ge3_flankingus", (1502, 1760, -244));
}
 
floor2_airfilter_wallbreach()
{
    kill = getent("floor2_airfilter_wav2_trig","targetname");
    trig = getent("floor2_airfilter_flank_chain", "targetname");
    right = getent("floor2_airfilter_comingright","targetname");
    
    kill endon("trigger");
    
    trig waittill("trigger");
    
    thread play_sound_in_space("descent_ge3_leftflank", trig.origin);
    
    right waittill("trigger");
    thread play_sound_in_space("descent_ga1_comingright", (2008, 1808, -180));  
}
 
floor2_airfilter_wav2()
{
    trig = getent("floor2_airfilter_wav2_trig","targetname");
    backup = getentarray("floor2_airfilter_wav2", "targetname");
    
    trig waittill("trigger");
    
    axis = get_ai("floor2_airfilter_wav1", "axis", "script_noteworthy");
    floodspawner_switch(axis, backup);
}
 
floor2_boiler()
{
    chain = getent("floor2_boiler_done","targetname");
    kill = getent("floor2_boiler_killspawner","targetname");
    spwn = getentarray("floor2_boiler_wav3","targetname");
    spwn = array_combine(spwn, getentarray("floor2_airfilter_wav2", "targetname"));
    
    kill waittill("trigger");
        
    ai = get_ai("floor2_airfilter_lowerguys","axis","script_noteworthy");
    for(i=0; i< ai.size; i++)
        ai[i] delete();
    
    waittillframeend;   
    ai_clear_dialog(spwn);
 
    level waittill("ai_clear_dialog_done");
 
    chain notify("trigger");
}
 
/************************************************************************************************************************************/
/************************************************************************************************************************************/
/*                                                          *FLOOR 3*                                                               */
/************************************************************************************************************************************/
/************************************************************************************************************************************/
 
floor3_main()
{
    jumpto = level.jumpto;
    if(level.jumptoFL != "3")
        jumpto = "start";
    
    switch(jumpto)
    {
        case "start":{
            }
        case "backhall":{
            floor3_backhall();
            }
        case "backhall2":{
            floor3_backhall2();
            }
        case "cafeteria":{
            floor3_cafeteria();
            }
        case "kitchen":{
            floor3_kitchen();
            }
        case "shaft":{
            thread floor3_elevator_jumpto();
            floor3_elevator();
            }
    }
}
 
floor3_elevator_jumpto()
{
    if(level.jumpto!= "shaft")
        return;
    wait .1;
    
    endnodes    = getnodearray("elevator_waitnodes","targetname");
    ai = getaiarray("allies");
    for(i=0; i<ai.size; i++)
    {
        ai[i] setgoalnode( endnodes[i]);
        ai[i].goalradius = endnodes[i].radius;  
        ai[i] disable_ai_color();
    }
}
 
floor3_elevator()
{
    trig = getentarray("elevator_repel","targetname");
    trig[0] setHintString(level.strings["hint_fastrope"]);
    trig = array_add(trig, getent(trig[0].target, "targetname"));
    check1 = getent("floor3_player_closetoelevator","targetname");
    check2 = getent("floor3_player_insiteelevator","targetname");
    node = getnode(check2.target, "targetname");
    
    ent = getstruct(node.target, "targetname");
    maps\mo_fastrope::fastrope_calc(ent);
    
    check1 waittill("trigger");
    ai = getaiarray("allies");
    array_thread(ai, ::floor3_elevator_think, node);
    
    check2 waittill("trigger");
    flag_set("insite_of_elevator");
    
    array_wait(trig, "trigger", 0);
    
    player_fastrope_go(ent);    
    level.player unlink();
}
 
floor3_elevator_think(node)
{
    /*  
    ent = undefined;
    ent = getstruct(name, "target");
    //is it a node?
    if(! (isdefined(ent.script_noteworthy) && ent.script_noteworthy == "fastrope_friendly_vehicle") )
    {
        struct = undefined;
        //if so does it exist already?
        struct = level.friendly_globals.fastrope_nodes[("node_" + name)];
        //if we find it - then it's a node we've already made
        if(isdefined(struct))
            return struct;
            
        //otherwise lets make it
        struct = spawnstruct();
        struct.origin = ent.origin;
        struct.angles = ent.angles;
        struct.targetname   = ("node_" + name);
        struct.target = ent.target;
        struct.fastrope_que = [];
        struct friendly_fastrope_calc(ent);
        
        level.friendly_globals.fastrope_nodes[struct.targetname] = struct;
        return struct;
    }   
*/
    
    ent = getstruct(node.target, "targetname");
    self pushplayer(true);
    
    if(!isdefined(ent.fastrope_que))
        ent.fastrope_que = [];
    index = ent.fastrope_que.size;
    ent.fastrope_que[ent.fastrope_que.size] = self;
    
    while(ent.fastrope_que[0] != self)
        ent waittill("check_fastrope_que");
 
    //run to the node
    self setgoalnode(node);
    self.goalradius = node.radius;
    self thread floor3_elevator_think2(ent, index);
    
    flag_wait("insite_of_elevator");
    //get the guys behind you movin
    waittillframeend;
    ent.fastrope_que =  array_remove(ent.fastrope_que, self);
    ent thread floor3_elevator_que_check();
}
 
floor3_elevator_think2(ent, index)
{
    self waittill("goal");
    //lets go!  
    flag_wait("insite_of_elevator");
    //this is where you would animated a jump to the rope
    
    pos = [];
    pos[0] = 0;
    pos[1] = .25;
    pos[2] = -1.5;
    pos[3] = 1;
    pos[4] = 0;
    pos[5] = .25;
    pos[6] = -1.5;
    pos[7] = 1;
    
    displacement = (0, ( (45 * pos[index]) + 45 ) ,0);
    
    pivot = spawn("script_origin", self.origin);
    self linkto(pivot);
    self.animname   = "fastrope_friendly";
    
    pivot moveto(ent.origin, .05);
    pivot.angles = ent.startangle + displacement;
    
    wait .1;
    
    //go go go
    self pushplayer(false);
    self set_force_color("red");
    self enable_ai_color();
    pivot movez(ent.range * -1, ent.time);
    pivot thread anim_loop_solo(self, "loop", undefined, "stopanimscripted"); 
    wait ent.time;
    
    pivot notify ("stopanimscripted");
    pivot.angles = self.angles;
    pivot anim_single_solo (self, "land");
    
    self unlink();
    pivot delete();
}
 
floor3_elevator_que_check()
{
    wait 2;
    self notify ("check_fastrope_que");
}
 
floor3_backhall2()
{
    trig = getent("floor3_goto_backhall2_kick","targetname");
    
    chain = getent("floor3_goto_backhall2_kick2","targetname");
    node2 = getnode("floor3_backhall2_kick_node2","targetname");
    door2 = getentarray(node2.target, "targetname");
    chain2_spwntrig = getent(door2[0].target, "targetname");
    
        bd_spawner  = getent("floor3_backdraft_guy","targetname");
        bd_node     = getnode(bd_spawner.target, "targetname");
        door2[0].script_parameters = "xleft";
    
    trig waittill("trigger");
    
    wait .5;
    
    ai = get_ai("red", "allies", "script_forcecolor");
    
    array_wait(ai, "goal", 0);
    objective_camera("backhall");
    
    //kicker = get_closest_living(node.origin, ai);
    
    
    //this will have to be custom
    /*  thread door_breach(node, kicker, door, "backdraft");
        kicker waittillmatch("single anim", "kick");
    
        wait .2;
    
        ang = anglestoforward(node.angles + (0,180,0));
        playfx(level._effect["exp_breach"], node.origin, ang);*/
    //////////////
    chain notify("trigger");
 
    ai = get_ai("red", "allies", "script_forcecolor");
    array_wait(ai, "goal", .5);//time out after x seconds if at least one guy is there
    kicker = get_closest_living(node2.origin, ai);
    
        bd_guy = undefined;
        while(1)
        {
            bd_guy = bd_spawner dospawn();
            if(!spawn_failed(bd_guy))
                break;
            wait .1;
        }
    
    thread door_breach(node2, kicker, door2, "backdraft");
        
    wait .15;
                
        bd_guy traverseMode("noclip");
        bd_guy.animname = "guy";
        bd_guy.deathanim = level.scr_anim["guy"]["backdraft"];
        bd_node anim_reach_solo (bd_guy, "backdraft");
        bd_guy animscripted("backdraft", bd_node.origin, bd_node.angles, level.scr_anim["guy"]["backdraft"]);
        wait .5;
        bd_guy stopanimscripted();
        bd_guy dodamage(bd_guy.health + 100, (0,0,0));
        
        wait 1;
        thread play_sound_in_space("grenade_explode_default", bd_node.origin);
        wait 2;
    
    chain2_spwntrig notify("trigger");
}
 
floor3_backhall()
{
    trig = getent("floor3_backhall_explosion","targetname");
    whole = getent(trig.target, "targetname");
    broken = getent(whole.target, "targetname");
    broken notsolid();
    
    flyer = getent("floor3_backhall_flyer","targetname");
    coughers = getentarray("floor3_backhall_guys","targetname");
    
    broken hide();
    
    trig waittill("trigger");
    
    earthquake(0.25, .25, (whole getorigin()), 5000);
    ang = anglestoforward((0, 180, 0)); 
    playfx(level._effect["exp_backhall"], (whole getorigin()), ang);
    
    whole delete();
    broken show();
    maps\_fx::loopfx("fire_crawl", (3051,-696,-309), 2, (3061,-695,-187));
    maps\_fx::loopfx("fire_crawl", (3048,-524,-307), 2, (3058,-523,-185));
    
    flyer thread floor3_backhall_flyer();
    array_thread(coughers, ::floor3_backhall_coughers);
    wait .5;
    broken solid();
    
    play_sound_in_space("descent_ga1_whathappened", (3024, -704, -372));
    thread play_sound_in_space("descent_ga1_idontknow", (3024, -704, -372));
}
 
#using_animtree("generic_human");
floor3_backhall_coughers()
{
    while(1)
    {
        guy = self stalingradSpawn();
        if(!spawn_failed(guy))
            break;
        wait .1;    
    }
    
    node = getnode(self.target, "targetname");
    guy.animname = "guy";
    
    guy.walk_combatanim2        = %wounded_run_forward1;
    guy.walk_combatanim         = %wounded_run_forward1;
    guy.walk_noncombatanim2     = %wounded_run_forward1;
    guy.walk_noncombatanim      = %wounded_run_forward1;
    guy.run_combatanim          = %wounded_run_forward1;
    guy.anim_combatrunanim      = %wounded_run_forward1;
    guy.run_noncombatanim       = %wounded_run_forward1;
    
    guy set_forcegoal();
    guy.goalradius = 16;
    guy setgoalnode(node);
    guy waittill("goal");
    
    guy thread floor3_backhall_coughers2(node);
    node thread anim_loop_solo(guy, "dazed", undefined, "stop_dazed");//, undefined, "stop");
    
    wait 4;
    node notify("stop_dazed");
}
 
floor3_backhall_coughers2(node)
{
    self unset_forcegoal();
    self.goalradius = 128;
    
    self waittill("damage");
    node notify("stop_dazed");
}
 
floor3_backhall_flyer()
{
    while(1)
    {
        guy = self stalingradSpawn();
        if(!spawn_failed(guy))
            break;
        wait .1;    
    }
    node = getnode(self.target, "targetname");
    guy.animname = "guy";
    guy traverseMode("noclip");
    
    node thread anim_single_solo(guy, "backhallexp");
    wait .05;
    guy stopanimscripted();
    guy.deathanim = level.scr_anim["guy"]["backhallexp"];
    guy dodamage(guy.health + 10000000, (0,0,0));
}
 
floor3_kitchen_closedoors()
{
    trig = getent("floor3_cafeteria_lockdoors", "targetname");
    trig waittill("trigger");
    
    self notsolid();
    if (self.spawnflags & 1)
        self connectpaths();
    
    x = 0;
    y = 0;
    z = 0;
    
    switch( self.script_parameters )
    {
        case "right":   {y = randomfloatrange(88, 92);}break;
        case "left":    {y = -1 * randomfloatrange(88, 92);}break;
    }
    
    time = .2;
    ang = (x,y,z);
    self rotateto(ang, time,0.05,0.05);
    
    wait time;
    
    self solid();
    self disconnectpaths();
}
 
floor3_kitchen_spawner(kitchen_struct)
{
    trig = getent("floor3_player_closetoelevator","targetname");
    trig endon("trigger");
    self endon("death");
    while(1)
    {
        self waittill("spawned", guy);
        if(spawn_failed(guy))
            continue;   
        
        guy floor3_kitchen_setup(kitchen_struct);
        if(!flag("floor3_kitchen_doorkicked"))
        {
            guy thread floor3_kitchen_think();
            continue;
        }
        guy thread floor3_kitchen_thinkend();
    }
}
 
 
floor3_kitchen_setup(kitchen_struct)
{
    self disable_ai_color();
    if(self check_force_color("yellow"))
    {   
        for(i=0; i<kitchen_struct.ywaitnodes.size; i++)
        {
            if(isdefined(kitchen_struct.ywaitnodes[i].taken))
                continue;
            kitchen_struct.ywaitnodes[i].taken = true;;
            self.waitnode = kitchen_struct.ywaitnodes[i];
            self.kicknode = kitchen_struct.ykicknode;
            self.kickdoor = kitchen_struct.ykickdoor;
            break;
        }
    }
    else
    {
        for(i=0; i<kitchen_struct.rwaitnodes.size; i++)
        {
            if(isdefined(kitchen_struct.rwaitnodes[i].taken))
                continue;
            kitchen_struct.rwaitnodes[i].taken = true;
            self.waitnode = kitchen_struct.rwaitnodes[i];
            self.kicknode = kitchen_struct.rkicknode;
            self.kickdoor = kitchen_struct.rkickdoor;
            break;
        }
    }
    
    for(i=0; i<kitchen_struct.endnodes.size; i++)
    {
        if(isdefined(kitchen_struct.endnodes[i].taken))
            continue;
        kitchen_struct.endnodes[i].taken = true;
        self.endnode = kitchen_struct.endnodes[i];
        break;
    }
}
 
floor3_kitchen()
{
    kitchen_struct = spawnstruct();
    //grab all the variables
    kitchen_struct.ywaitnodes   = getnodearray("floor3_kitchen_yellows", "targetname");
    kitchen_struct.ykicknode    = getnode("floor3_kitchen_kickyellow", "targetname"); 
    kitchen_struct.ykickdoor    = getentarray(kitchen_struct.ykicknode.target, "targetname");
    
    kitchen_struct.rwaitnodes   = getnodearray("floor3_kitchen_reds","targetname");
    kitchen_struct.rkicknode    = getnode("floor3_kitchen_kickred", "targetname");
    kitchen_struct.rkickdoor    = getentarray(kitchen_struct.rkicknode.target, "targetname");
    
    kitchen_struct.endnodes     = getnodearray("elevator_waitnodes","targetname");
    kitchen_struct.trigs        = getentarray("floor3_kitchen_start","targetname");
    doors       = array_combine(kitchen_struct.ykickdoor, kitchen_struct.rkickdoor);
    spawners    = getentarray("floor3_kitchen_spawner","target");
    spawners    = array_combine(spawners, getentarray("floor3_cafeteria_spawner","target"));
    
    level.floor3_kitchen_readytokick = [];
    level.floor3_kitchen_readytokick["yellow"] = false;
    level.floor3_kitchen_readytokick["red"] = false;
    
    //make sure the doors close before the player sees them
    array_thread(doors,::floor3_kitchen_closedoors);
    
    if(level.jumpto != "kitchen")
        level waittill("ai_clear_dialog_done");
    
    //grab the ai and set them up
    ai = getaiarray("allies");
    array_thread(ai, ::floor3_kitchen_setup, kitchen_struct);
    array_thread(spawners, ::floor3_kitchen_spawner, kitchen_struct);
    waittillframeend;
    
    //send them on their ways
    array_thread(ai, ::floor3_kitchen_think);
    
    //as soon as first guy is ready - lets see where the player is
    level waittill("floor3_kitchen_readytokick");
    array_wait(kitchen_struct.trigs, "trigger", 0);
    
    //now lets see which group to teleport
    color = [];
    color["teleport"] = "none";
    color["kick"] = "none";
    
    while(1)
    {
        wait .1;
        if(level.player istouching(kitchen_struct.trigs[0]))
        {
            if(!level.floor3_kitchen_readytokick[kitchen_struct.trigs[0].script_noteworthy])
                continue;
            color["teleport"]   = kitchen_struct.trigs[1].script_noteworthy;
            color["kick"]       = kitchen_struct.trigs[0].script_noteworthy;
        }
        else
        {
            if(!level.floor3_kitchen_readytokick[kitchen_struct.trigs[1].script_noteworthy])
                continue;
            color["teleport"]   = kitchen_struct.trigs[0].script_noteworthy;
            color["kick"]       = kitchen_struct.trigs[1].script_noteworthy;
        }
        break;
    }
    teleports = get_ai(color["teleport"], "allies", "script_forcecolor");
    array_notify(teleports, "teleport");
    normals = get_ai(color["kick"], "allies", "script_forcecolor");
    kickers = [];
    //who's ready to kick the door in the players view?
    for(i=0; i<normals.size; i++)
    {
        if(isdefined(normals[i].readytokick))
            kickers[kickers.size] = normals[i]; 
    }
    //dont move this to another line - above this is where we regrab the AI
    //because we regrab them - the spawner thread doesn't need to wait and 
    //do it on it's own - it just lets the guy who was spawned before this
    //get grabbed here and follow the logic
    flag_set("floor3_kitchen_doorkicked");
    
    switch(color["kick"])
    {
        case "red":{
            //move the guys the player can't see through the door immediately
            array_thread(teleports[0].kickdoor, ::door_breach_door);
            array_thread(teleports, ::floor3_kitchen_thinkend);
            
            wait .15;
            //kick down the door for the player
            kicker = get_closest_living(kickers[0].kicknode.origin, kickers, 128);
            door_breach(kicker.kicknode, kicker, kicker.kickdoor, "shootkick");
            array_thread(normals, ::floor3_kitchen_thinkend);   
        }break;
        case "yellow":{
            
            //kick down the door for the player
            kicker = get_closest_living(kickers[0].kicknode.origin, kickers, 128);
            thread door_breach(kicker.kicknode, kicker, kicker.kickdoor, "shootkick");
            
            wait .33;
            //move the guys the player can't see through the door immediately
            array_thread(teleports[0].kickdoor, ::door_breach_door);
            array_thread(teleports, ::floor3_kitchen_thinkend);
            
            kicker waittillmatch("single anim", "kick");
            array_thread(normals, ::floor3_kitchen_thinkend);
        }break; 
    }
}
 
floor3_kitchen_think()
{
    self thread floor3_kitchen_thinkdeath();
    
    self endon("death");
    self pushplayer(true);
    self setgoalnode(self.waitnode);
    self.goalradius = self.waitnode.radius;
    
    self thread floor3_kitchen_think2();
    
    self waittill("goal");
    level notify("floor3_kitchen_readytokick");
    color = self get_force_color();
    if(color == "r")
        level.floor3_kitchen_readytokick["red"] = true;
    else
        level.floor3_kitchen_readytokick["yellow"] = true;
        
    self.readytokick = true;
}
floor3_kitchen_thinkdeath()
{
    waitnode = self.waitnode;
    endnode = self.endnode;
    self waittill("death");
    
    waitnode.taken = undefined;
    endnode.taken = undefined;
}
floor3_kitchen_think2()
{
    self endon("goal");
    self waittill("teleport");
    self teleport(self.waitnode.origin);
}
 
floor3_kitchen_thinkend()
{
    self endon("death");
    self setgoalnode(self.endnode);
    self.goalradius = self.endnode.radius;
    self waittill("goal");
    self pushplayer(false);
}
 
floor3_cafeteria()
{
    start = getent("floor3_cafeteria_start", "targetname");
    spwntrig = getent(start.target, "targetname");
    array = getentarray(spwntrig.target, "targetname");
    backup = getentarray("floor3_cafeteria_replacements","targetname");
    backuptrig = getent("floor3_cafeteria_backuptrig","targetname");
    backup2 = getentarray("floor3_cafeteria_replacements2","targetname");
    backuptrig2 = getent("floor3_set_replacements2", "targetname");
    spwn = array_combine(backup, backup2);
    last = getent("floor3_cafeteria_lastkiller","targetname");
    
    start waittill("trigger");
    
    ai = getaiarray("axis");
    for(i=0; i<ai.size; i++)
        ai[i] set_force_color("blue");
    
    if(ai.size < 12)
    {
        diff = 12 - ai.size;
        x = array.size - diff;
        while(x > 0)
        {
            spwn = random(array);
            array = array_remove(array, spwn);
            spwn delete();
            x--;
        }
        spwntrig notify("trigger");
    }
    
    backuptrig waittill("trigger");
    ai = getaiarray("axis");
    floodspawner_switch(ai, backup);
    
    thread play_sound_in_space("descent_ga1_theyrecoming", (1416, 360, -336));  
    
    backuptrig2 waittill("trigger");
    ai = getaiarray("axis");
    floodspawner_switch(ai, backup2);
    
    thread play_sound_in_space("descent_ga1_retreat", (640, 352, -340));
    
    last waittill("trigger");
    waittillframeend;
    ai_clear_dialog(spwn);
}
 
/************************************************************************************************************************************/
/************************************************************************************************************************************/
/*                                                          *FLOOR 4*                                                               */
/************************************************************************************************************************************/
/************************************************************************************************************************************/
 
floor4_main()
{
    jumpto = level.jumpto;
    if(level.jumptoFL != "4")
        jumpto = "start";
    
    array_thread(getentarray("fastrope_friendlies_noheli","script_noteworthy"), ::floor4_fastrope_spawner_think);
    
    switch(jumpto)
    {
        case "start":{
            floor4_prison();
            }
        case "fubar":{
            floor4_fubar();
            }
    }
}
 
floor4_prison()
{
    chain = getent("floor4_startchain","targetname");
    trig = getent("floor4_elevatorguys", "targetname");
    trig waittill ("trigger");
    
    wait .5;
    
    ai = getaiarray("allies");
    array_wait(ai, "goal", 0);
    
    objective_camera("prison");
    
    chain notify("trigger");
}
 
floor4_fubar()
{
    wave4 = getentarray("floor4_wave4","targetname");
    trig = getent("floor4_wave3","target");
    chain = getent("objective_move_fubar","targetname");
    
    array_thread(wave4, ::floor4_fubar_wave4);
    flag_clear( "random_events_hole" ); 
    trig waittill("trigger");
    
    ai = getaiarray("axis");
    level.floor4_fubar_deaths = 0;
    array_thread(ai, ::floor4_fubar_deaths);
    floodspawner_switch(ai, wave4);
    
    wait .1;
 
    while(level.floor4_fubar_deaths)
        level waittill("floor4_fubar_deaths");
    
    autosave_by_name("final_fight");
    
    random_event_lock("exp_upper","script_noteworthy");
    random_event_lock("exp_lower","script_noteworthy");
    
    wait .5;
    play_sound_in_space("descent_cmd_lastofthem", (1464, -336, -967));
    wait .75;
    play_sound_in_space("descent_cmd_marinesonme", (1464, -336, -967));
    play_sound_in_space("descent_ge1_yessir", (1464, -336, -967));
    
    chain notify("trigger");
 
    wait .25;
    
    ai = get_ai("red", "allies", "script_forcecolor");
    array_wait(ai, "goal", 1);
    
    objective_camera("final", true);
    musicPlay("descent_end_music"); 
    wait .5;
    ai = get_ai("red", "allies", "script_forcecolor");
    ai[0] play_sound_on_entity("descent_cmd_welldonemarines");
//  wait .5;
//  play_sound_in_space("descent_ge1_jeezelook", (1464, -336, -967));
//  ai[1] play_sound_on_entity("descent_ge1_seenlikethat");
    ai[0] play_sound_on_entity("descent_cmd_noson");    
    
    maps\_endmission::nextmission();
}
 
floor4_fubar_wave4()
{
    guy = undefined;
    while(1)
    {
        self waittill("spawned", guy);
        if(!spawn_failed(guy))
            break;
    }   
    
    guy thread floor4_fubar_deaths();
}
 
floor4_fubar_deaths()
{
    level.floor4_fubar_deaths++;
    self waittill("death");
    level.floor4_fubar_deaths--;
    level notify("floor4_fubar_deaths");
}
 
floor4_fastrope_spawner_think()
{
    self endon("death");
    ent = getstruct(self.targetname, "target");
    while(1)
    {
        self waittill("spawned", guy);
        if(spawn_failed(guy))
            continue;   
            
        guy thread floor4_fastrope_guy_think(ent);
    }
}
 
floor4_fastrope_guy_think(ent)
{
    self endon("death");
    maps\mo_fastrope::fastrope_calc(ent); 
    
    if(!isdefined(ent.fastrope_que))
        ent.fastrope_que = [];
    index = ent.fastrope_que.size;
    ent.fastrope_que[ent.fastrope_que.size] = self;
    
    waittillframeend;
    while(ent.fastrope_que[0] != self)
        ent waittill("check_fastrope_que");
    
    waittillframeend;
    ent.fastrope_que =  array_remove(ent.fastrope_que, self);
    ent thread floor3_elevator_que_check();
    
    pos = [];
    pos[0] = 0;
    pos[1] = .25;
    pos[2] = -1.5;
    pos[3] = 1;
    pos[4] = 0;
    pos[5] = .25;
    pos[6] = -1.5;
    pos[7] = 1;
    displacement = (0, ( (45 * pos[index]) + 45 ) ,0);
    
    pivot = spawn("script_origin", self.origin);
    self linkto(pivot);
    self.animname   = "fastrope_friendly";
    
    pivot moveto(ent.origin, .05);
    pivot.angles = ent.startangle + displacement;
    
    wait .1;
    
    //go go go
    pivot thread anim_loop_solo(self, "loop", undefined, "stopanimscripted"); 
    pivot movez(ent.range *- 1, ent.time);
    wait ent.time;
    
    pivot notify ("stopanimscripted");
    pivot.angles = self.angles;
    pivot anim_single_solo (self, "land");
    
    self unlink();
    pivot delete();
}
 
/************************************************************************************************************************************/
/************************************************************************************************************************************/
/*                                                          *RANDOM EVENTS*                                                         */
/************************************************************************************************************************************/
/************************************************************************************************************************************/
 
random_event_main()
{
    //SETUP
    on = getent("random_quake_on","targetname");
    //main hole
    level.random_event_process = [];
    level.random_event_locked = [];
    level.random_event = [];
    level.random_event["upper"] = getstructarray("flyby", "script_noteworthy");
    level.random_event["upper"] = array_combine(level.random_event["upper"], getstructarray("dropoff", "script_noteworthy"));
    level.random_event["upper"] = array_combine(level.random_event["upper"], getstructarray("exp_upper", "script_noteworthy"));
    level.random_event["lower"] = getstructarray("exp_lower","script_noteworthy");
    level.random_event["inner"] = [];
    
    //inner structure
    struct = spawnstruct();
    struct.script_noteworthy = "quake";
    struct.origin = on getorigin();
    level.random_event["inner"][level.random_event["inner"].size] = struct;
    level.random_event["inner"][level.random_event["inner"].size] = struct;
    level.random_event["inner"][level.random_event["inner"].size] = struct;//this gives me more quakes than screams
    struct = spawnstruct();
    struct.script_noteworthy = "scream";
    struct.origin = on getorigin();
    level.random_event["inner"][level.random_event["inner"].size] = struct;
    
    //the functions for the types
    level.random_event_process["flyby"]     = ::random_event_flyby;
    level.random_event_process["dropoff"]   = ::random_event_dropoff;
    level.random_event_process["exp_upper"] = ::random_event_exp_upper;
    level.random_event_process["exp_lower"] = ::random_event_exp_lower;
    level.random_event_process["quake"]     = ::random_event_quake;
    level.random_event_process["scream"]    = ::random_event_scream;
    
    //call the logic
    thread random_event_hole();
    thread random_event_inner();
}
 
random_event_inner()
{
    on = getent("random_quake_on","targetname");
    off = getent(on.target, "targetname");
    
    flag_wait("random_events_inner");
    
    while(1)
    {
        on waittill("trigger");
        on thread random_event_inner_logic();
        off waittill("trigger");    
        on notify("stop");
    }
}
 
random_event_inner_logic()
{
    self endon("stop");
    
    valid = true;
    event = undefined;
    while(1)
    {
        if(!valid)
            wait 2;
        else
        {
            if(level.soundDebug != "none")
                wait 1;
            else
                wait(randomfloatrange(20, 60));
                
            wait 2;
            event = random(level.random_event["inner"]);
        }
        
        valid = event [[level.random_event_process[event.script_noteworthy]]]();
    }
}
 
random_event_quake()
{
    
    vec = (0,level.player.angles[1], 0);
    forward = anglestoforward(vec);
    right = anglestoright(vec);
    forward = vector_multiply(forward, 200);
    right = vector_multiply(right, (randomfloat(64) - 32));
    start = level.player.origin;
    end = start + forward + right;
    
    pos = physicstrace(start, end );
    if(pos!= end)
        return false;
    
    start = end;
    pos = physicstrace(start, (start + (0,0,512)) );
    
    up = anglestoup(vec);
    playfx(level._effect["debri_ceiling"], pos, (pos - up));    
    
    thread play_sound_in_space("descent_quake_rumble", self.origin);//distant_explosion_triggered
    earthquake(0.15, 6, level.player.origin, 2048); 
    wait .5;
    thread play_sound_in_space("ceiling_debris", pos);//distant_explosion_triggered
    wait 5;
    return true;
}
random_event_scream()
{
    if(level.soundDebug != "none")
        play_sound_in_space("descent_ge1_yellfaraway", self.origin);
    return true;
}
 
random_event_hole()
{
    trig = getentarray("center_hole_lookat","targetname");
    prevevent = random(level.random_event["upper"]);
    
    while(1)
    {
        flag_wait("random_events_hole");
        array_thread(trig, ::random_event_trigs);
        array_wait(trig, "trigger", 0);
        waittillframeend;
        array_notify(trig, "stop");
    
        if(!flag("random_events_hole"))
            continue;
    
        if(!level.random_event[level.randomeventtrig].size)
        {
            wait .1;
            continue;
        }
        while(1)
        {
            event = random(level.random_event[level.randomeventtrig]);
            if(event != prevevent)
                break;
        }
        prevevent = event;
        event [[level.random_event_process[event.script_noteworthy]]]();
        if(level.soundDebug != "none")
            wait 1;
        else
            wait 15;
    }
}
 
random_event_lock(name, type)
{
    title = random_event_lockname(name, type);
    lock = spawnstruct();
    lock.position = "none";
    lock.array = undefined;
 
    lock.array = random_event_lock_logic(name, type, "upper");
    if(lock.array.size)
    {
        lock.position = "upper";
        level.random_event_locked[title] = lock;
        return;
    }
    
    lock.array = random_event_lock_logic(name, type, "lower");
    if(lock.array.size)
    {
        lock.position = "lower";
        level.random_event_locked[title] = lock;
        return;
    }
    
    lock.array = random_event_lock_logic(name, type, "inner");
    if(lock.array.size)
    {
        lock.position = "inner";
        level.random_event_locked[title] = lock;
        return;
    }
}
 
random_event_lock_logic(name, type, pos)
{
    array = [];
    index = 0;
    while(index < level.random_event[pos].size)
    {
        string = undefined;
        switch(type)
        {
            case "target":{
                string = level.random_event[pos][index].target;
            }break;
            case "targetname":{
                string = level.random_event[pos][index].targetname;
            }break;
            case "script_noteworthy":{
                string = level.random_event[pos][index].script_noteworthy;  
            }break;
        }
        if(isdefined(string) && string == name)
        {
            array[array.size] = level.random_event[pos][index];
            level.random_event[pos] = array_remove(level.random_event[pos], level.random_event[pos][index]);
            continue;
        }
        index++;
    }
    
    return array;
}
 
random_event_unlock(name, type)
{
    title = random_event_lockname(name, type);
    lock = level.random_event_locked[title];
    if(!isdefined(lock) || lock.array.size == 0)
        return;
        
    level.random_event_locked[title] = undefined;
    level.random_event[lock.position] = array_combine(level.random_event[lock.position], lock.array);
    level notify("random_event_unlocked");  
}
 
random_event_lockname(name, type)
{
    return ("event_" + type + name);
}
 
random_event_trigs()
{
    self endon("stop");
    self waittill("trigger");
    level.randomeventtrig = self.script_noteworthy;
}
 
random_event_dropoff()
{
    trig = getent(self.target, "targetname");
    node = getnode(trig.target, "targetname");
    spwners = getentarray(trig.targetname, "target");
    
    array_thread(spwners, ::random_event_dropoff_spwners, node);
    waittillframeend;
    
    old = level.friendly_globals.curr_trigger;//this line and the one 3 down make sure the correct friendly triggers stay on (also insures that these spawners can be spawned again)
    trig notify ("trigger");
    waittillframeend;
    old notify("trigger");
    node wait_timeout("reached", 20);
}
 
random_event_dropoff_spwners(node)
{
    while(1)
    {
        self waittill("spawned", guy);
        if(!spawn_failed(guy))
            break;
    }
    
    wait .1;
    self notify("death");//this gets him off the friendly logic
    level.friendly_globals.cur_num--;
    guy endon("death");
    
    guy setgoalnode(node); 
    guy.goalradius = node.radius;
    
    guy waittill("goal");
    node notify("reached");
    guy delete();
}
 
random_event_flyby()
{
    nodes = getvehiclenodearray(self.target, "targetname");
    
    for(i=0; i<nodes.size; i++)
    {
        plane = random_event_flyby_makeplane(nodes[i]);
        plane thread random_event_flyby_flyplane();
        wait randomfloatrange(.25, 1.5);
    }
}
 
random_event_flyby_flyplane()
{
    self thread play_sound_on_entity("descent_flyover_sonicboom");
    self startpath();
    self waittill("reached_end_node");
    self delete();
}
 
random_event_flyby_makeplane(node)
{
    plane = spawnVehicle( "vehicle_mig29_desert", "plane", "blackhawk", node.origin, (0,0,0) );
    plane setmodel ("vehicle_mig29_desert");
    plane attachPath( node );
    
    return plane;
}
 
random_event_exp_upper()
{
    self random_event_exp();
    thread random_event_exp_lock("exp_upper");
}
 
random_event_exp_lower()
{
    self random_event_exp();
    thread random_event_exp_lock("exp_lower");
}
 
random_event_exp_lock(pos)
{
    //this is to make sure explosions don't happen too often
    random_event_lock(pos, "script_noteworthy");
    wait 90;
    random_event_unlock(pos, "script_noteworthy");
}
 
random_event_exp()
{
    vec = anglestoforward(self.angles); 
    playfx(level._effect["exp_randomevent"], self.origin, vec);
    thread play_sound_in_space("bricks_exploding");
    earthquake(0.25, 1, self.origin, 2048); 
}