#include "function.H"
#include "mapscript.h"

/**********************************************************************************************
* Red Alert Vanilla Actions                                                                   *
*=============================================================================================*/

/***********************************************************************************************
 * Script_Win - The specified player wins                                                      *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int) - The player (house that wins)                             *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_Win(lua_State* L) {

    int houseType = lua_tointeger(L, -1);

    if (houseType != HOUSE_NONE) {

        HouseClass* this_house = HouseClass::As_Pointer((HousesType)houseType);

        if (this_house != NULL) {

            if (this_house->ID == PlayerPtr->Class->House) {
                PlayerPtr->Flag_To_Win();
            }
            else {
                PlayerPtr->Flag_To_Lose();
            }

            bool success = this_house->Fire_Sale();
            lua_pushboolean(L, int(success));
        }
    }

    return 1;
}

/***********************************************************************************************
 * Script_Lose - The specified player loses                                                    *
 *                                                                                             *
 *   SCRIPT INPUT:	ret (int) - The waypoint index of which to reveal                          *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_Lose(lua_State* L) {

    int houseType = lua_tointeger(L, -1);

    if (houseType != HOUSE_NONE) {

        HouseClass* this_house = HouseClass::As_Pointer((HousesType)houseType);

        if (this_house != NULL) {

            if (this_house->ID == PlayerPtr->Class->House) {
                PlayerPtr->Flag_To_Lose();
            }
            else {
                PlayerPtr->Flag_To_Win();
            }

            lua_pushboolean(L, 1);
        }
    }

    return 1;
}

/***********************************************************************************************
 * Script_BeginProduction - This will enable production to begin for the house specified       *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int) - The AI player (house) index to allow winning for         *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_BeginProduction(lua_State* L) {

    int houseType = lua_tointeger(L, -1);

    if (houseType != HOUSE_NONE) {

        HouseClass* this_house = HouseClass::As_Pointer((HousesType)houseType);

        if (this_house != NULL) {
            this_house->Begin_Production();
        }
    }

    return 1;
}

/***********************************************************************************************
 * Script_CreateTeam - Attempts to create team (as defined in map)                             *
 *                                                                                             *
 *   SCRIPT INPUT:	teamType (int) - The team index to attempt to create                       *
 *                                                                                             *
 *   SCRIPT OUTPUT:  success (bool) - Did a team get created?                                  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CreateTeam(lua_State* L) {

    const char* teamType = lua_tostring(L, 1);

    TeamTypeClass* teamPtr = TeamTypeClass::From_Name(teamType);

    if (teamPtr != NULL) {
        ScenarioInit++;

        bool success = false;

        TeamClass* new_team = teamPtr->Create_One_Of();

        if (new_team != NULL) {
            success = true;
        }

        lua_pushboolean(L, int(success));

        ScenarioInit--;
    }

    return 1;
}

/***********************************************************************************************
 * Script_DestroyTeam - Destroy all teams of the type specified                                *
 *                                                                                             *
 *   SCRIPT INPUT:	teamType (int) - The team index to attempt to destroy                      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_DestroyTeam(lua_State* L) {

    const char* teamType = lua_tostring(L, 1);

    TeamTypeClass* teamPtr = TeamTypeClass::From_Name(teamType);

    if (teamPtr != NULL) {

        teamPtr->Destroy_All_Of();

    }

    return 1;
}

/***********************************************************************************************
 * Script_AllHunt - Force all units of specified house to go into hunt mode                    *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int) - The AI player (house) index to allow winning for         *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_AllHunt(lua_State* L) {

    int houseType = lua_tointeger(L, -1);

    if (houseType != HOUSE_NONE) {

        HouseClass* this_house = HouseClass::As_Pointer((HousesType)houseType);

        if (this_house != NULL) {
            this_house->Do_All_To_Hunt();
        }
    }

    return 1;
}

/***********************************************************************************************
 * Script_Reinforcements - Attempts to create reinforcements as defined by team                *
 *                                                                                             *
 *   SCRIPT INPUT:	teamType (int) - The team index to attempt to create                       *
 *                                                                                             *
 *   SCRIPT OUTPUT:  success (bool) - Did Do_Reinforcements return true?                       *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_Reinforcements(lua_State* L) {

    const char* teamType = lua_tostring(L, 1);

    TeamTypeClass* teamPtr = TeamTypeClass::From_Name(teamType);

    if (teamPtr != NULL) {
        bool success = Do_Reinforcements(teamPtr);
        lua_pushboolean(L, int(success));
    }
    else {
        lua_pushboolean(L, 0);
    }

    return 1;
}

/***********************************************************************************************
 * Script_DropZoneFlare - Places drop down smoke at specified waypoint location                *
 *                                                                                             *
 *   SCRIPT INPUT:	in_x (int) - The Cell/X location to drop the smoke                         *
 *                	in_y (int) - The Cell/Y location to drop the smoke                         *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_DropZoneFlare(lua_State* L) {

    int in_x = lua_tointeger(L, 1);
    int in_y = lua_tointeger(L, 2);

    new AnimClass(ANIM_LZ_SMOKE, Cell_Coord(XY_Cell(in_x, in_y)));

    return 1;
}

/***********************************************************************************************
 * Script_FireSale - Make AI house give up, selling everything and going all in on attack      *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int) - The AI player (house) index to allow winning for         *
 *                                                                                             *
 *   SCRIPT OUTPUT:  success (bool) - Did the action get performed?                            *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_FireSale(lua_State* L) {

    int houseType = lua_tointeger(L, -1);

    if (houseType != HOUSE_NONE) {

        HouseClass* this_house = HouseClass::As_Pointer((HousesType)houseType);

        if (this_house != NULL) {
            bool success = this_house->Fire_Sale();
            lua_pushboolean(L, int(success));
        }
    }

    return 1;
}

/***********************************************************************************************
 * Script_PlayMovie - Plays the given movie                                                    *
 *                                                                                             *
 *   SCRIPT INPUT:	ret (int) - The movie index of which to play                               *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_PlayMovie(lua_State* L) {
    //int ret = lua_tointeger(L, -1);
    const char* movieName = lua_tostring(L, -1);
    Play_Movie(movieName);
    return 1;
}

/***********************************************************************************************
 * Script_TriggerText - Triggers text to display in-game                                       *
 *                                                                                             *
 *   SCRIPT INPUT:	textIndex (int) - The text index to display (from tutorial.ini)            *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_TriggerText(lua_State* L) {
    int textIndex = lua_tointeger(L, -1);

    // TODO: Implement colors / flags

    // JJQUESTION: This appears right but doesn't do anything. Is text broken at the moment?
    if (textIndex > 0 && textIndex < sizeof(TutorialText)) {

        Session.Messages.Add_Message(NULL, textIndex, (char*)TutorialText[textIndex], PCOLOR_GREEN, TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, Rule.MessageDelay * TICKS_PER_MINUTE);
    }

    return 1;
}

/***********************************************************************************************
 * Script_DestroyTrigger - Destroys a given trigger                                            *
 *                                                                                             *
 *   SCRIPT INPUT:	ret (int) - The index/id of the trigger of which to destroy                *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_DestroyTrigger(lua_State* L) {

    int triggerIndex = lua_tointeger(L, -1);

    TriggerClass* this_trigger = Triggers.Ptr(triggerIndex);

    if (this_trigger != NULL) {
        Detach_This_From_All(this_trigger->As_Target());
        delete Triggers.Ptr(triggerIndex);
    }

    return 1;
}

/***********************************************************************************************
 * Script_AutoCreate - Allows house AI to begin creating autocreate teams                      *
 *                                                                                             *
 *  Autocreation means that instead of a teamtype being                                        *
 *  manually created by a Create Team trigger action, that                                     *
 *  it will be subject to the autocreate function. Each                                        *
 *  computer country can have its autocreation function                                        *
 *  turned on through a trigger action, after which the                                        *
 *  creation of the teamtypes that have autocreation turned                                    *
 *  on will be subject to being created, at the whim of the                                    *
 *  autocreate function. See [TeamTypes] Section for more                                      *
 *  details.                                                                                   *
 *                        - The Red Alert Single Player Mission Creation Guide                 *
 *                                                                                             *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int) - The AI player (house) index to allow autocreate for      *
 *                  createEnables (bool, default yes) - Allow autocreate on/off                *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_AutoCreate(lua_State* L) {

    int houseType = 0;
    bool autoCreateEnabled = true;

    houseType = lua_tointeger(L, 1);

    // If there is a second argument given, process it
    if (lua_gettop(L) == 2) {
        autoCreateEnabled = lua_toboolean(L, 2);
    }

    if (houseType != HOUSE_NONE) {

        HouseClass* this_house = HouseClass::As_Pointer((HousesType)houseType);

        if (this_house != NULL) {

            // If we are enabling auto creation by the house, clear alert
            if (autoCreateEnabled) {
                this_house->AlertTime = 0; // TODO - don't assume successful pointer
            }

            // Now set the parameter
            this_house->IsAlerted = autoCreateEnabled;

        }

    }

    return 1;
}

/***********************************************************************************************
 * Script_AllowWin - Allows a win                                                              *
 *                                                                                             *
 *   Used when you want a specific objective                                                   *
 *   to be met before the mission is accomplished.  In other words, if the                     *
 *   trigger with this action assigned to it hasn't been fired, but the                        *
 *   actual WIN trigger has been fired, the mission will not end until this                    *
 *   "allow win" trigger is fired.                                                             *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int) - The AI player (house) index to allow winning for         *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_AllowWin(lua_State* L) {

    int houseType = lua_tointeger(L, -1);

    if (houseType != HOUSE_NONE) {

        HouseClass* this_house = HouseClass::As_Pointer((HousesType)houseType);

        if (this_house != NULL) {
            this_house->Blockage++;
        }
    }

    return 1;
}

/***********************************************************************************************
 * Script_RevealAll - Reveals the entire map  TODO: input player                               *
 *                                                                                             *
 *   SCRIPT INPUT:	ret (int) - The waypoint index of which to reveal                          *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_RevealAll(lua_State* L) {
    if (!PlayerPtr->IsVisionary) {
        PlayerPtr->IsVisionary = true;
        for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
            Map.Map_Cell(cell, PlayerPtr);
        }
    }

    return 1;
}

/***********************************************************************************************
 * Script_RevealCell - Reveals map around given waypoint  TODO: input player                   *
 *                                                                                             *
 *   SCRIPT INPUT:	ret (int) - The waypoint index of which to reveal                          *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_RevealCell(lua_State* L) {
    int ret = lua_tointeger(L, -1);

    if (!PlayerPtr->IsVisionary) {
        Map.Sight_From(Scen.Waypoint[ret], Rule.GapShroudRadius, PlayerPtr, false);
    }

    return 1;
}

/***********************************************************************************************
 * Script_RevealZone - Reveals area of map around given waypoint  TODO: input player           *
 *                                                                                             *
 *   Reveal all cells of the zone that the specified waypoint is located in. This can be       *
 *   used to reveal whole islands or bodies of water                                           *
 *                                                                                             *
 *   SCRIPT INPUT:	ret (int) - The waypoint index of which to reveal                          *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_RevealZone(lua_State* L) {
    int ret = lua_tointeger(L, -1);

    if (!PlayerPtr->IsVisionary) {
        int zone = Map[Scen.Waypoint[ret]].Zones[MZONE_CRUSHER];

        for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
            if (Map[cell].Zones[MZONE_CRUSHER] == zone) {
                Map.Map_Cell(cell, PlayerPtr);
            }
        }

    }

    return 1;
}

/***********************************************************************************************
 * Script_PlaySound - Plays the given Sound                                                    *
 *                                                                                             *
 *   SCRIPT INPUT:	ret (int) - The sound index of which to play                               *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_PlaySound(lua_State* L) {
    int ret = lua_tointeger(L, -1);

    Sound_Effect((VocType)ret);

    return 1;
}

/***********************************************************************************************
 * Script_PlayMusic - Plays the given Music score.                                             *
 *                                                                                             *
 *   Plays music score at given index. Negative numbers stop any music playing.                *
 *                                                                                             *
 *     SCRIPT INPUT:	ret (int) - The music index of which to play                           *
 *                                                                                             *
 *     SCRIPT OUTPUT:  void                                                                    *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_PlayMusic(lua_State* L) {
    int ret = lua_tointeger(L, -1);

    if (ret < 0) {
        Theme.Stop();
    }
    else {
        Theme.Play_Song((ThemeType)ret);
    }

    return 1;
}

/***********************************************************************************************
 * Script_PlaySpeech - Plays the given Speech audio                                            *
 *                                                                                             *
 *   SCRIPT INPUT:	ret (int) - The speech index of which to play                              *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_PlaySpeech(lua_State* L) {
    int ret = lua_tointeger(L, -1);
    Speak((VoxType)ret);
    return 1;
}

/***********************************************************************************************
 * Script_StartMissionTimer - Starts the in-game mission timer                                 *
 *                                                                                             *
 *   SCRIPT INPUT:	none                                                                       *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_StartMissionTimer(lua_State* L) {
    Scen.MissionTimer.Start();
    Map.Redraw_Tab();
    return 1;
}

/***********************************************************************************************
 * Script_StopMissionTimer - Stops the in-game mission timer                                   *
 *                                                                                             *
 *   SCRIPT INPUT:	none                                                                       *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_StopMissionTimer(lua_State* L) {
    Scen.MissionTimer.Stop();
    return 1;
}

/***********************************************************************************************
 * Script_IncreaseMissionTimer - Increases the mission timer by the given amount               *
 *                                                                                             *
 *   SCRIPT INPUT:	ret (int) - amount of time in tenths of a minute to increase by            *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_IncreaseMissionTimer(lua_State* L) {
    int ret = lua_tointeger(L, -1);
    Scen.MissionTimer = Scen.MissionTimer + (ret * (TICKS_PER_MINUTE / 10));
    Map.Redraw_Tab();
    return 1;
}

/***********************************************************************************************
 * Script_DecreaseMissionTimer - Decreases the mission timer by the given amount               *
 *                                                                                             *
 *   SCRIPT INPUT:	ret (int) - amount of time in tenths of a minute to decrease by            *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_DecreaseMissionTimer(lua_State* L) {
    int ret = lua_tointeger(L, -1);
    Scen.MissionTimer = Scen.MissionTimer - (ret * (TICKS_PER_MINUTE / 10));
    if (Scen.MissionTimer < 0) { Scen.MissionTimer = 0; }
    Map.Redraw_Tab();
    return 1;
}

/***********************************************************************************************
 * Script_SetMissionTimer - Sets and starts the in-game mission timer                          *
 *                                                                                             *
 *   SCRIPT INPUT:	ret (int) - amount of time in tenths of a minute                           *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_SetMissionTimer(lua_State* L) {
    int ret = lua_tointeger(L, -1);
    Scen.MissionTimer = Scen.MissionTimer + (ret * (TICKS_PER_MINUTE / 10));
    Scen.MissionTimer.Start();
    Map.Redraw_Tab();
    return 1;
}

/***********************************************************************************************
 * Script_SetGlobalValue - Sets the global value to "set" position (on)                        *
 *                                                                                             *
 *   SCRIPT INPUT:	global_value (int) - The global to set to "set"                            *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_SetGlobalValue(lua_State* L) {
    int global_value = lua_tointeger(L, -1);
    Scen.Set_Global_To(global_value, true);
    return 1;
}

/***********************************************************************************************
 * Script_ClearGlobalValue - Sets the global value to "clear" position (off)                   *
 *                                                                                             *
 *   SCRIPT INPUT:	global_value (int) - The global to set to "off"                            *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_ClearGlobalValue(lua_State* L) {
    int global_value = lua_tointeger(L, -1);
    Scen.Set_Global_To(global_value, false);
    return 1;
}

/***********************************************************************************************
 * Script_AutoBaseBuilding - Sets AI basebuilding on/off for given house                       *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)    - The player (house) index of the AI                    *
 *                	on_off (bool)      - Enable / disable auto base building                   *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_AutoBaseBuilding(lua_State* L) {
    int houseType = lua_tointeger(L, 1);
    bool on_off = lua_toboolean(L, 2);

    HouseClass* this_house = Houses.Ptr(houseType);
    if (this_house != NULL) {
        this_house->IsBaseBuilding = on_off;
    }

    return 1;
}

/***********************************************************************************************
 * Script_StopMissionTimer - Stops the in-game mission timer                                   *
 *                                                                                             *
 *   SCRIPT INPUT:	none                                                                       *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CreepShadow(lua_State* L) {
    Map.Encroach_Shadow(PlayerPtr);
    return 1;
}

/***********************************************************************************************
 * Script_DestroyTriggerBuilding - Stops the in-game mission timer                             *
 *                                                                                             *
 *   SCRIPT INPUT:	triggerIndex (int) - The index of the trigger previously created           *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_DestroyTriggerBuilding(lua_State* L) {
    int triggerIndex = lua_tointeger(L, -1);

    TriggerClass* this_trigger = Triggers.Ptr(triggerIndex);

    if (this_trigger != NULL) {
        for (int index = 0; index < Buildings.Count(); index++) {

            BuildingClass* this_building = Buildings.Ptr(index);

            if (this_building->Trigger == this_trigger && this_building->Strength > 0) {
                int damage = this_building->Strength;
                this_building->Take_Damage(damage, 0, WARHEAD_AP, 0, true);
            }

        }
    }

    return 1;
}

/***********************************************************************************************
 * Script_GiveOneTimeSpecialWeapon - Gives specified house a one time special weapon           *
 *                                                                                             *
 *   SCRIPT INPUT:	weaponType (int) - The special weapon type to give                         *
 *                	houseType (int)  - The player (house) index to give this to (-1 for all)   *
 *                	immediate(bool)  - should the weapon be fully charged?                     *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_GiveOneTimeSpecialWeapon(lua_State* L) {

    int weaponType = lua_tointeger(L, 1);

    int houseType = -1;
    bool immediate = -1;

    // Optional houseType parameter
    if (lua_gettop(L) >= 2) {
        houseType = lua_tointeger(L, 2);
    }

    // Optional immediate parameter
    if (lua_gettop(L) >= 2) {
        immediate = lua_toboolean(L, 3);
    }

    for (int h_index = 0; h_index < Houses.Count(); h_index++) {

        HouseClass* house = Houses.Ptr(h_index);

        if (house->ID == houseType || houseType == -1) {

            house->SuperWeapon[weaponType].Enable(TACTION_1_SPECIAL, true);

            if (immediate) {
                house->SuperWeapon[weaponType].Forced_Charge(true);
            }

            if (PlayerPtr == house) {
                Map.Add(RTTI_SPECIAL, weaponType);
                Map.Column[1].Flag_To_Redraw();
            }

            if (houseType >= 0) {
                break;
            }
        }

    }

    return 1;
}

/***********************************************************************************************
 * Script_GiveSpecialWeapon - Gives specified house a repeating special weapon                 *
 *                                                                                             *
 *   SCRIPT INPUT:	weaponType (int) - The special weapon type to give                         *
 *                	houseType (int)  - The player (house) index to give this to (-1 for all)   *
 *                	immediate(bool)  - should the weapon be fully charged?                     *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_GiveSpecialWeapon(lua_State* L) {

    int weaponType = lua_tointeger(L, 1);

    int houseType = -1;
    bool immediate = -1;

    // Optional houseType parameter
    if (lua_gettop(L) >= 2) {
        houseType = lua_tointeger(L, 2);
    }

    // Optional immediate parameter
    if (lua_gettop(L) == 3) {
        immediate = lua_toboolean(L, 3);
    }

    for (int h_index = 0; h_index < Houses.Count(); h_index++) {

        HouseClass* house = Houses.Ptr(h_index);

        if (house->ID == houseType || houseType == -1) {

            house->SuperWeapon[weaponType].Enable(TACTION_FULL_SPECIAL, true);

            if (immediate) {
                house->SuperWeapon[weaponType].Forced_Charge(true);
            }

            if (PlayerPtr == house) {
                Map.Add(RTTI_SPECIAL, weaponType);
                Map.Column[1].Flag_To_Redraw();
            }

            if (houseType >= 0) {
                break;
            }
        }

    }

    return 1;
}

/***********************************************************************************************
 * Script_DesignatePreferredTarget - Gives specified house a prefferable type of target        *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)  - The player (house) index to set targetting for (or -1)  *
 *                	targetType (int) - The target type index to set to                         *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_DesignatePreferredTarget(lua_State* L) {

    int houseType = lua_tointeger(L, 1);
    unsigned char targetType = lua_tointeger(L, 2);

    if (targetType >= 1 && targetType <= 11) {

        for (int h_index = 0; h_index < Houses.Count(); h_index++) {

            HouseClass* house = Houses.Ptr(h_index);

            if (house->ID == houseType || houseType == -1) {

                house->PreferredTarget = (QuarryType)targetType;

                // Discontinue giving out free cash if a specific house was specified
                if (houseType >= 0) {
                    break;
                }

            }

        }

    }

    return 1;
}

/***********************************************************************************************
 * Script_LaunchFakeNukes - All nuke silos begin launching duds                                *
 *                                                                                             *
 *   SCRIPT INPUT:	none                                                                       *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_LaunchFakeNukes(lua_State* L) {

    for (int index = 0; index < Buildings.Count(); index++) {
        BuildingClass* bldg = Buildings.Ptr(index);
        if (*bldg == STRUCT_MSLO) {
            bldg->Assign_Mission(MISSION_MISSILE);
        }
    }

    return 1;
}

/**********************************************************************************************
* Red Alert Vanilla Events                                                                    *
*=============================================================================================*/

/***********************************************************************************************
 * Script_CreateCellCallback - Creates an ENTERED_BY trigger and attaches a callback           *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) index to test for entry         *
 *                  in_x (int)            - The cell/X location of the cell to test            *
 *                  in_y (int)            - The cell/Y location of the cell to test            *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CellCallback(lua_State* L) {

    // TODO: option 6 arguments to allow x2,y2 (for a rect)

    int houseType = lua_tointeger(L, 1);
    int in_x = lua_tointeger(L, 2);
    int in_y = lua_tointeger(L, 3);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 4) {
        in_function = (char*)lua_tostring(L, 4);
    }

    // A house must be specified
    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_PLAYER_ENTERED;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.House = (HousesType)houseType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        // Get the cell and set the trigger
        this_trigger->Cell = XY_Cell(in_x, in_y);
        Map[XY_Cell(in_x, in_y)].Trigger = this_trigger;

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_CreateSpiedByCallback - Creates a SPIED_BY trigger and attaches a callback           *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID (int)        - The building ID being spied                        *
 *                	houseType (int)       - The house (player) index doing the spying          *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_SpiedByCallback(lua_State* L) {

    int objectID = lua_tointeger(L, 1);
    int houseType = lua_tointeger(L, 2);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 3) {
        in_function = (char*)lua_tostring(L, 3);
    }

    BuildingClass* this_building = Buildings.Ptr(objectID);

    // A house must be specified
    if (houseType >= 0 && houseType < HouseTypes.Count() && this_building != NULL) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)this_building->House->ID;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_SPIED;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.House = (HousesType)houseType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        // Set the building
        this_building->Trigger = this_trigger;

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_CreateDiscoveryCallback - Creates a TEVENT_DISCOVERED trigger and attaches a callback*
 *                                                                                             *
 *  Trigger is sprung when the given object is discovered                                      *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID (int)        - The object's ID being discovered                   *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_ObjectDiscoveryCallback(lua_State* L) {

    int objectID = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    // A house must be specified
    if (objectID >= 0) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = HousesType::HOUSE_NONE;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_DISCOVERED;
        this_trigger_type->EventControl = MULTI_ONLY;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        Script_SetObjectTrigger(objectID, this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_HouseDiscoveredCallback - Initiates when given house is discovered                   *
 *                                                                                             *
 *  Trigger is sprung when an object belonging to the given house is discovered                *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) index that has been discovered  *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_HouseDiscoveredCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    // A house must be specified
    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = HOUSE_NONE;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::VOLATILE;

        this_trigger_type->Event1 = TEVENT_HOUSE_DISCOVERED;
        this_trigger_type->EventControl = MULTI_ONLY;

        this_trigger_type->Event1.Data.House = (HousesType)houseType;

        // Create instance of trigger type

        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[PlayerPtr->Class->House].Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_ObjectAttackedCallback - Trigger that springs when object is attacked by anyone      *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID (int)        - The object's ID being discovered                   *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_ObjectAttackedCallback(lua_State* L) {

    int objectID = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    // An object must be specified
    if (objectID >= 0) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = HousesType::HOUSE_NONE;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_ATTACKED;
        this_trigger_type->EventControl = MULTI_ONLY;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        Script_SetObjectTrigger(objectID, this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_ObjectDestroyedCallback - Trigger that springs when object is destroyed by anyone    *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID (int)        - The object's ID being discovered                   *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_ObjectDestroyedCallback(lua_State* L) {

    int objectID = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    // An object must be specified
    if (objectID >= 0) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = HousesType::HOUSE_NONE;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_DESTROYED;
        this_trigger_type->EventControl = MULTI_ONLY;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        Script_SetObjectTrigger(objectID, this_trigger);



        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_AnyEventCallback -                                                                   *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID (int)        - The object's ID being discovered                   *
 *                  houseType (int)       - The house (player) index                           *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_AnyEventCallback(lua_State* L) {

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 1) {
        in_function = (char*)lua_tostring(L, 1);
    }

    // Create trigger type
    TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
    this_trigger_type->House = HousesType::HOUSE_NONE;
    this_trigger_type->IsActive = 1;
    this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

    this_trigger_type->Event1 = TEVENT_ANY;
    this_trigger_type->EventControl = MULTI_ONLY;

    // Create instance of trigger type
    TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

    if (in_function[0] != '\0') {
        // Copy the callback function into the trigger
        strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
    }

    LogicTriggers.Add(this_trigger);

    // Output the new trigger's ID
    lua_pushnumber(L, this_trigger->ID);

    return 1;

}

/***********************************************************************************************
 * Script_AllUnitsDestroyedCallback -  Called when all of a house's units are destroyed        *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) index owner of said units       *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_AllUnitsDestroyedCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    // A house must be specified
    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = HousesType::HOUSE_NONE;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_UNITS_DESTROYED;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.House = (HousesType)houseType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[(HousesType)houseType].Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_AllBuildingsDestroyedCallback -  Called when all of a house's buildings are destroyed*
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) index owner of said buildings   *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_AllBuildingsDestroyedCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    // A house must be specified
    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = HousesType::HOUSE_NONE;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_BUILDINGS_DESTROYED;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.House = (HousesType)houseType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[(HousesType)houseType].Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_AllDestroyedCallback -  Called when everything belonging to a house is destyroyed    *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) index that got pwned            *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_AllDestroyedCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    // A house must be specified
    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = HousesType::HOUSE_NONE;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_ALL_DESTROYED;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.House = (HousesType)houseType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[(HousesType)houseType].Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_CreditsReachedCallback -  Called when given house meets given amount of credits      *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) index to test against           *
 *                  in_credits (int)      - The amount of credits                              *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CreditsReachedCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);
    int in_credits = lua_tointeger(L, 2);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 3) {
        in_function = (char*)lua_tostring(L, 3);
    }

    // A house must be specified
    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_CREDITS;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.Value = in_credits;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[(HousesType)houseType].Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_TimeReachedCallback -  Called when the given amount of time has elapsed              *
 *                                                                                             *
 *   SCRIPT INPUT:	in_time (int)         - The time (in tenths of a second) that was reached  *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_TimeReachedCallback(lua_State* L) {

    int in_time = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    // Create trigger type
    TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
    this_trigger_type->House = HOUSE_NONE;
    this_trigger_type->IsActive = 1;
    this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

    this_trigger_type->Event1 = TEVENT_TIME;
    this_trigger_type->EventControl = MULTI_ONLY;
    this_trigger_type->Event1.Data.Value = in_time;

    // Create instance of trigger type
    TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

    if (in_function[0] != '\0') {
        // Copy the callback function into the trigger
        strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
    }

    LogicTriggers.Add(this_trigger);

    // Output the new trigger's ID
    lua_pushnumber(L, this_trigger->ID);

    return 1;

}

/***********************************************************************************************
 * Script_MissionTimerCallback -  Called when the mission timer has expired                    *
 *                                                                                             *
 *   SCRIPT INPUT:	in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_MissionTimerCallback(lua_State* L) {

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 1) {
        in_function = (char*)lua_tostring(L, 1);
    }

    // Create trigger type
    TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
    this_trigger_type->House = HOUSE_NONE;
    this_trigger_type->IsActive = 1;
    this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

    this_trigger_type->Event1 = TEVENT_MISSION_TIMER_EXPIRED;
    this_trigger_type->EventControl = MULTI_ONLY;

    // Create instance of trigger type
    TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

    if (in_function[0] != '\0') {
        // Copy the callback function into the trigger
        strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
    }

    LogicTriggers.Add(this_trigger);

    // Output the new trigger's ID
    lua_pushnumber(L, this_trigger->ID);

    return 1;

}

/***********************************************************************************************
 * Script_UnitsDestroyedCallback -  Called when given number of a house's units are destroyed  *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) index owner of said units       *
 *                  in_number (int)       - The number of units that have must be destroyed    *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_UnitsDestroyedCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);
    int in_number = lua_tointeger(L, 2);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 3) {
        in_function = (char*)lua_tostring(L, 3);
    }

    // A house must be specified
    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_NUNITS_DESTROYED;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.Value = in_number;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[(HousesType)houseType].Add(this_trigger);


        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/************************************************************************************************
 * Script_BuildingsDestroyedCallback -  Called when number of a house's buildings are destroyed *
 *                                                                                              *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) index owner of said buildings    *
 *                  in_number (int)       - The number of buildings that have must be destroyed *
 *                  in_function (string)  - The callback function to execute upon trigger       *
 *                                                                                              *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions   *
 *                                                                                              *
 * INPUT:  lua_State - The current Lua state                                                    *
 *                                                                                              *
 * OUTPUT:  int; Did the function run successfully? Return 1                                    *
 *                                                                                              *
 * WARNINGS:  ?                                                                                 *
 *                                                                                              *
 *==============================================================================================*/
static int Script_BuildingsDestroyedCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);
    int in_number = lua_tointeger(L, 2);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 3) {
        in_function = (char*)lua_tostring(L, 3);
    }

    // A house must be specified
    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_NBUILDINGS_DESTROYED;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.Value = in_number;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[(HousesType)houseType].Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_NoFactoriesCallback -  Called when no more factories exist for a house               *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) index that got pwned            *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_NoFactoriesCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    // A house must be specified
    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_NOFACTORIES;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.Value = -1;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[(HousesType)houseType].Add(this_trigger);


        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_CivilianEscapeCallback - Called when civilians get evacuated from map                *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) owner of civilians escaped      *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CivilianEscapeCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_EVAC_CIVILIAN;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.Value = -1;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        LogicTriggers.Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;
    }

    lua_pushnumber(L, -1);

    return 1;

}

/***********************************************************************************************
 * Script_BuildingBuiltCallback - Called when a specified house builds a specified building    *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) owner that built the building   *
 *                  objectType (int)      - The index / building type to check for             *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_BuildingBuiltCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);
    int objectType = lua_tointeger(L, 2);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 3) {
        in_function = (char*)lua_tostring(L, 3);
    }

    if (objectType >= 0 && houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_BUILD;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.Value = objectType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[houseType].Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;

}

/***********************************************************************************************
 * Script_UnitBuiltCallback - Called when a specified house builds a specified unit            *
 *                                                                                             *
 *  Does not trigger for units that spawn with buildings (ie. ore truck)                       *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) owner that built the unit       *
 *                  objectType (int)      - The index / unit type to check for                 *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_UnitBuiltCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);
    int objectType = lua_tointeger(L, 2);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 3) {
        in_function = (char*)lua_tostring(L, 3);
    }

    if (objectType >= 0 && houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_BUILD_UNIT;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.Value = objectType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[houseType].Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;

}

/***********************************************************************************************
 * Script_InfantryBuiltCallback - Called when a specified house builds a specified infantry    *
 *                                                                                             *
 *  Does not trigger for infantry gained by selling a building                                 *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) owner that built the infantry   *
 *                  objectType (int)      - The index / infantry type to check for             *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_InfantryBuiltCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);
    int objectType = lua_tointeger(L, 2);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 3) {
        in_function = (char*)lua_tostring(L, 3);
    }

    if (objectType >= 0 && houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_BUILD_INFANTRY;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.Value = objectType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[houseType].Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;

}

/***********************************************************************************************
 * Script_AircraftBuiltCallback - Called when a specified house builds a specified aircraft    *
 *                                                                                             *
 *  Does not trigger for units that spawn with buildings                                       *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) owner that built the unit       *
 *                  objectType (int)      - The index / unit type to check for                 *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_AircraftBuiltCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);
    int objectType = lua_tointeger(L, 2);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 3) {
        in_function = (char*)lua_tostring(L, 3);
    }

    if (objectType >= 0 && houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_BUILD_AIRCRAFT;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.Value = objectType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[houseType].Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;

}

/***********************************************************************************************
 * Script_TeamLeavesMapCallback - Called when the specified team leaves the map                *
 *                                                                                             *
 *   SCRIPT INPUT:	in_team (int)         - The team index that has left the map               *
 *                	in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_TeamLeavesMapCallback(lua_State* L) {

    int in_team = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }
    TeamTypeClass* this_team = TeamTypes.Ptr(in_team);

    if (this_team != NULL) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = this_team->House;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_LEAVES_MAP;
        this_trigger_type->EventControl = MULTI_ONLY;


        this_trigger_type->Event1.Team = this_team;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        LogicTriggers.Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    // Output the new trigger's ID
    lua_pushnumber(L, -1);

    return 1;

}

/***********************************************************************************************
 * Script_ZoneEntryCallback - Called when a specified house enters zone of given position      *
 *                                                                                             *
 *  Does not trigger for units that spawn with buildings                                       *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) owner that built the unit       *
 *                  in_x (int)            - The cell/X location of the cell to test            *
 *                  in_y (int)            - The cell/Y location of the cell to test            *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_ZoneEntryCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);
    int in_x = lua_tointeger(L, 2);
    int in_y = lua_tointeger(L, 3);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 4) {
        in_function = (char*)lua_tostring(L, 4);
    }

    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_ENTERS_ZONE;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.House = (HousesType)houseType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        // Get the cell and set the trigger
        this_trigger->Cell = XY_Cell(in_x, in_y);
        MapTriggers.Add(this_trigger);


        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;

}

/***********************************************************************************************
 * Script_HorizontalCrossCallback - Called when a specified house's units cross the given X    *
 *                                                                                             *
 *  Does not trigger for units that spawn with buildings                                       *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) owner that owns the unit        *
 *                  in_x (int)            - The cell/X location that must be crossed           *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_HorizontalCrossCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);
    int in_x = lua_tointeger(L, 2);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 3) {
        in_function = (char*)lua_tostring(L, 3);
    }

    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_CROSS_VERTICAL;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.House = (HousesType)houseType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        // Find a free spot and set the trigger
        int addY = 0;
        for (addY = 0; addY < Map.MapCellHeight; addY++) {
            TriggerClass* trigger = Map[XY_Cell(in_x, Map.MapCellY + addY)].Trigger;
            if (trigger == NULL) {
                this_trigger->Cell = XY_Cell(in_x, Map.MapCellY + addY);
                Map[XY_Cell(in_x, Map.MapCellY + addY)].Trigger = this_trigger;
                break;
            }
        }

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;

}

/***********************************************************************************************
 * Script_VerticalCrossCallback - Called when a specified house's units cross the given Y      *
 *                                                                                             *
 *  Does not trigger for units that spawn with buildings                                       *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) owner that owns the unit        *
 *                  in_y (int)            - The cell/Y location that must be crossed           *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_VerticalCrossCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);
    int in_y = lua_tointeger(L, 2);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 3) {
        in_function = (char*)lua_tostring(L, 3);
    }

    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

        this_trigger_type->Event1 = TEVENT_CROSS_HORIZONTAL; // <- Their description doesn't make sense, not mine
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.House = (HousesType)houseType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        // Find a free spot and set the trigger
        int addX = 0;
        for (addX = 0; addX < Map.MapCellWidth; addX++) {
            TriggerClass* trigger = Map[XY_Cell(Map.MapCellX + addX, in_y)].Trigger;
            if (trigger == NULL) {
                this_trigger->Cell = XY_Cell(Map.MapCellX + addX, in_y);
                Map[XY_Cell(Map.MapCellX + addX, in_y)].Trigger = this_trigger;
                break;
            }
        }

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;

}

/***********************************************************************************************
 * Script_GlobalSetCallback -  activated when the global value is in the "set" poisition       *
 *                                                                                             *
 *   SCRIPT INPUT:	in_global             - The global value to set                            *
 *                	in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_GlobalSetCallback(lua_State* L) {

    int in_global = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    // Create trigger type
    TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
    this_trigger_type->House = HOUSE_NONE;
    this_trigger_type->IsActive = 1;
    this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

    this_trigger_type->Event1 = TEVENT_GLOBAL_SET;
    this_trigger_type->EventControl = MULTI_ONLY;
    this_trigger_type->Event1.Data.Value = in_global;

    // Create instance of trigger type
    TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

    if (in_function[0] != '\0') {
        // Copy the callback function into the trigger
        strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
    }

    LogicTriggers.Add(this_trigger);

    // Output the new trigger's ID
    lua_pushnumber(L, this_trigger->ID);

    return 1;
}

/***********************************************************************************************
 * Script_GlobalSetCallback -  activated when the global value is in the "cleared" poisition   *
 *                                                                                             *
 *   SCRIPT INPUT:	in_global             - The global value to set to "cleared"               *
 *                	in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_GlobalClearedCallback(lua_State* L) {

    int in_global = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    // Create trigger type
    TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
    this_trigger_type->House = HOUSE_NONE;
    this_trigger_type->IsActive = 1;
    this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

    this_trigger_type->Event1 = TEVENT_GLOBAL_CLEAR;
    this_trigger_type->EventControl = MULTI_ONLY;
    this_trigger_type->Event1.Data.Value = in_global;

    // Create instance of trigger type
    TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

    if (in_function[0] != '\0') {
        // Copy the callback function into the trigger
        strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
    }

    LogicTriggers.Add(this_trigger);

    // Output the new trigger's ID
    lua_pushnumber(L, this_trigger->ID);

    return 1;
}

/***********************************************************************************************
 * Script_LowPowerCallback - Initiates when given house becomes low on power                   *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)       - The house (player) index that has been discovered  *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_LowPowerCallback(lua_State* L) {

    int houseType = lua_tointeger(L, 1);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 2) {
        in_function = (char*)lua_tostring(L, 2);
    }

    // A house must be specified
    if (houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = HOUSE_NONE;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::VOLATILE;

        this_trigger_type->Event1 = TEVENT_LOW_POWER;
        this_trigger_type->EventControl = MULTI_ONLY;

        this_trigger_type->Event1.Data.House = (HousesType)houseType;

        // Create instance of trigger type

        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[PlayerPtr->Class->House].Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/***********************************************************************************************
 * Script_AllBridgesDestroyedCallback - Called when all map's bridges have been destroyed      *
 *                                                                                             *
 *   SCRIPT INPUT:	in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_AllBridgesDestroyedCallback(lua_State* L) {

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 1) {
        in_function = (char*)lua_tostring(L, 1);
    }

    // Create trigger type
    TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
    this_trigger_type->House = HousesType::HOUSE_NONE;
    this_trigger_type->IsActive = 1;
    this_trigger_type->IsPersistant = TriggerTypeClass::PERSISTANT;

    this_trigger_type->Event1 = TEVENT_ALL_BRIDGES_DESTROYED;
    this_trigger_type->EventControl = MULTI_ONLY;

    // Create instance of trigger type
    TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

    if (in_function[0] != '\0') {
        // Copy the callback function into the trigger
        strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
    }

    LogicTriggers.Add(this_trigger);

    // Output the new trigger's ID
    lua_pushnumber(L, this_trigger->ID);

    return 1;

}

/***********************************************************************************************
 * Script_BuildingExistsCallback - Called if a given building exists for a given house         *
 *                                                                                             *
 *   SCRIPT INPUT:	buildingType (int)    - The building type to check for                     *
 *                  houseType (int)       - The house (player) index owner of said building    *
 *                  in_function (string)  - The callback function to execute upon trigger      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID - The ID of the trigger created for use with Trigger Functions  *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_BuildingExistsCallback(lua_State* L) {

    int buildingType = lua_tointeger(L, 1);
    int houseType = lua_tointeger(L, 2);

    char* in_function = "";

    // Optional callback function
    if (lua_gettop(L) >= 3) {
        in_function = (char*)lua_tostring(L, 3);
    }

    // A house must be specified
    if (buildingType >= 0 && houseType >= 0 && houseType < HouseTypes.Count()) {

        // Create trigger type
        TriggerTypeClass* this_trigger_type = new TriggerTypeClass();
        this_trigger_type->House = (HousesType)houseType;
        this_trigger_type->IsActive = 1;
        this_trigger_type->IsPersistant = TriggerTypeClass::VOLATILE;
        this_trigger_type->Event1 = TEVENT_BUILDING_EXISTS;
        this_trigger_type->EventControl = MULTI_ONLY;
        this_trigger_type->Event1.Data.Value = buildingType;

        // Create instance of trigger type
        TriggerClass* this_trigger = Find_Or_Make(this_trigger_type);

        if (in_function[0] != '\0') {
            // Copy the callback function into the trigger
            strncpy(this_trigger->MapScriptCallback, in_function, sizeof(this_trigger->MapScriptCallback) - 1);
        }

        HouseTriggers[(HousesType)houseType].Add(this_trigger);

        // Output the new trigger's ID
        lua_pushnumber(L, this_trigger->ID);

        return 1;

    }

    lua_pushnumber(L, -1);

    return 1;
}

/**********************************************************************************************
* Trigger Utility Functions                                                                   *
*=============================================================================================*/

/***********************************************************************************************
 * Script_Script_TriggerAddCell - Adds a cell to any cell based callback                       *
 *                                                                                             *
 *  The map editor will always be the fastest way to do this, but here in case it's needed     *
 *                                                                                             *
 *   SCRIPT INPUT:	triggerIndex (int)       - The trigger ID of which to add a cell           *
 *                  in_x (int)               - The Cell/X location of the new cell             *
 *                  in_y (int)               - The Cell/Y location of the new cell             *
 *                  in_x2 (int) (opt. gr. 2) - The second Cell/X location (for bounding box)   *
 *                  in_y2 (int) (opt. gr. 2) - The second Cell/Y location (for bounding box)   *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_TriggerAddCell(lua_State* L) {

    int triggerIndex = lua_tointeger(L, 1);

    int in_x = lua_tointeger(L, 2);
    int in_y = lua_tointeger(L, 3);

    int in_x2 = in_x;
    int in_y2 = in_y;

    // Optional secondary group bounding box parameter
    if (lua_gettop(L) == 5) {
        in_x2 = lua_tointeger(L, 4);
        in_y2 = lua_tointeger(L, 5);
    }

    TriggerClass* this_trigger = Triggers.Ptr(triggerIndex);

    if (this_trigger != NULL) {
        for (int _x = in_x; _x <= in_x2; _x++) {
            for (int _y = in_y; _y <= in_y2; _y++) {
                Map[XY_Cell(_x, _y)].Trigger = this_trigger;
            }
        }
    }



    return 1;
}

/***********************************************************************************************
 * Script_SetTriggerCallback - Adds a lua callback to an existing trigger                      *
 *                                                                                             *
 *   SCRIPT INPUT:	triggerIndex (int)       - The trigger of which to get                     *
 *                                                                                             *
 *                	callbackName (string)    - The function name to be called when the         *
 *                                             actions have been met                           *
 *                                                                                             *
 *                  actionIndex (int) (opt.) - 0: always callback on any of the given paths    *
 *                                                of the trigger                               *
 *                                             1: only callback on first action                *
 *                                             2: only callback on second action               *
 *                                                                                             *
 *   SCRIPT OUTPUT:  result (number) - The amount of matching buildings for that player        *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_SetTriggerCallback(lua_State* L) {

    int triggerIndex = lua_tointeger(L, 1);

    const char* callbackName = lua_tostring(L, 2);
    char actionIndex = 0;

    // Optional actionIndex parameter
    if (lua_gettop(L) == 3) {
        actionIndex = lua_tointeger(L, 2);
    }

    TriggerClass* trigger = Triggers.Ptr(triggerIndex);

    if (trigger != NULL) {

        strncpy(trigger->MapScriptCallback, callbackName, sizeof(trigger->MapScriptCallback) - 1);
        trigger->MapScriptActionIndex = actionIndex;

    }

    return 1;
}

/***********************************************************************************************
 * Script_GetCellObject - Gets an object (if any) on a cell and returns the ID                 *
 *                                                                                             *
 *   SCRIPT INPUT:	in_x (int)       - The cell/X location of the cell to pick from            *
 *                  in_y (int)       - The cell/Y location of the cell to pick from            *
 *                                                                                             *
 *   SCRIPT OUTPUT:  result (number) - The ID of the building on the cell, or -1 if none       *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_GetCellObject(lua_State* L) {

    int in_x = lua_tointeger(L, 1);
    int in_y = lua_tointeger(L, 2);

    long result = -1;

    ObjectClass* this_object = Map[XY_Cell(in_x, in_y)].Cell_Object();

    if (this_object == NULL) {

        lua_pushnumber(L, -1);
        return 1;
    }

    MapScriptObject* CacheObject = Scen.mapScript->CreateCacheObject();

    CacheObject->ID = this_object->ID;
    CacheObject->RTTI = this_object->RTTI;
    CacheObject->classIndex = -1;

    switch (this_object->RTTI) {
    case RTTI_BUILDING: {
        CacheObject->classIndex = Script_BuildingIndexFromID(this_object->ID);
    }break;
    case RTTI_UNIT: {
        CacheObject->classIndex = Script_UnitIndexFromID(this_object->ID);
    }break;
    case RTTI_AIRCRAFT: {
        CacheObject->classIndex = Script_AircraftIndexFromID(this_object->ID);
    }break;
    case RTTI_INFANTRY: {
        CacheObject->classIndex = Script_InfantryIndexFromID(this_object->ID);
    }break;
    case RTTI_VESSEL: {
        CacheObject->classIndex = Script_VesselIndexFromID(this_object->ID);
    }break;
    }

    if (CacheObject->classIndex == -1 || CacheObject->ID < 0) {
        delete CacheObject;
        lua_pushnumber(L, -1);
    }
    else {
        Scen.mapScript->ObjectCache.push_back(CacheObject);
        lua_pushnumber(L, CacheObject->UID); // Return UID for faster lookup
    }

    return 1;
}

/***********************************************************************************************
 * Script_Merge_Triggers - Adds the event from trigger 2 to trigger 1 and discards trigger 2   *
 *                                                                                             *
 *   SCRIPT INPUT:	triggerIndex (int)     - The trigger ID of which will be the result        *
 *                  mergeTriggerIndex (int)- The trigger ID of which is being merged           *
 *                                                                                             *
 *   SCRIPT OUTPUT:  result (number) - The amount of matching buildings for that player        *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_MergeTriggers(lua_State* L) {

    int triggerIndex = lua_tointeger(L, 1);
    int mergeTriggerIndex = lua_tointeger(L, 2);

    TriggerClass* resulting_trigger = Triggers.Ptr(triggerIndex);
    TriggerTypeClass* resulting_trigger_type = resulting_trigger->Class;
    TriggerClass* merge_trigger = Triggers.Ptr(mergeTriggerIndex);

    if (resulting_trigger != NULL && merge_trigger != NULL) {

        // Set event 2 to event 1 of the merge trigger
        resulting_trigger_type->Event2.Event = (TEventType)merge_trigger->Class->Event1.Event;
        resulting_trigger_type->Event2.Data.Value = (long)merge_trigger->Class->Event1.Data.Value;
        resulting_trigger_type->Event2.Team = (TeamTypeClass*)merge_trigger->Class->Event1.Team;

        // Make this an "AND" coniditional trigger (event 1 AND event 2)
        resulting_trigger->Class->EventControl = MULTI_AND;
        resulting_trigger->Class->ActionControl = MULTI_ONLY;

        // TODO: only do these individual cleanups for actions that they represent (for efficiency)

        // Now switch over any LogicTrigger references (we're getting rid of the second trigger)
        for (int t_index = 0; t_index < LogicTriggers.Count(); t_index++) {

            TriggerClass* _trigger = LogicTriggers[t_index];

            if (_trigger == merge_trigger) {

                LogicTriggers.Delete(t_index);

                bool find_existing_result;
                for (int t2_index = 0; t2_index < LogicTriggers.Count(); t2_index++) {
                    if (LogicTriggers[t2_index] == resulting_trigger) {
                        find_existing_result = true;
                        break;
                    }
                }
                if (!find_existing_result) {
                    LogicTriggers.Add(resulting_trigger);
                }

                break;
            }

        }

        // Now switch over any MapTrigger references (we're getting rid of the second trigger)
        for (int t_index = 0; t_index < MapTriggers.Count(); t_index++) {
            TriggerClass* _trigger = MapTriggers[t_index];

            if (_trigger != NULL) {
                if (_trigger == merge_trigger) {

                    MapTriggers.Delete(t_index);

                    bool find_existing_result;
                    for (int t2_index = 0; t2_index < MapTriggers.Count(); t2_index++) {
                        if (MapTriggers[t2_index] == resulting_trigger) {
                            find_existing_result = true;
                            break;
                        }
                    }
                    if (!find_existing_result) {
                        MapTriggers.Add(resulting_trigger);
                    }

                    break;
                }
            }

        }

        // Now switch over any HouseTrigger references (we're getting rid of the second trigger)
        for (int h_index = 0; h_index < Houses.Count(); h_index++) {
            for (int t_index = 0; t_index < HouseTriggers[h_index].Count(); t_index++) {

                TriggerClass* _trigger = HouseTriggers[h_index][t_index];

                if (_trigger != NULL) {
                    if (_trigger == merge_trigger) {

                        HouseTriggers[h_index].Delete(t_index);

                        bool find_existing_result;
                        for (int t2_index = 0; t2_index < HouseTriggers[h_index].Count(); t2_index++) {
                            if (HouseTriggers[h_index][t2_index] == resulting_trigger) {
                                find_existing_result = true;
                                break;
                            }
                        }
                        if (!find_existing_result) {
                            HouseTriggers[h_index].Add(resulting_trigger);
                        }

                        break;
                    }
                }

            }
        }

        // Go through the map and replace any celltriggers
        for (int _x = Map.MapCellX; _x <= Map.MapCellX + Map.MapCellWidth; _x++) {
            for (int _y = Map.MapCellY; _y <= Map.MapCellY + Map.MapCellHeight; _y++) {
                if (Map[XY_Cell(_x, _y)].Trigger == merge_trigger) {
                    Map[XY_Cell(_x, _y)].Trigger = resulting_trigger;
                }
            }
        }

        // Now that we've merged the contents, and it's no longer being referred to, we can safely delete the merge trigger
        Detach_This_From_All(merge_trigger->As_Target());
        delete merge_trigger;
    }

    return 1;
}

/***********************************************************************************************
 * Script_GetTriggerByName - Gets the trigger with a given name                                *
 *                                                                                             *
 *   SCRIPT INPUT:	triggerName (string); The input trigger name                               *
 *                                                                                             *
 *   SCRIPT OUTPUT:  triggerID (int) - The index of the trigger with this name                 *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_GetTriggerByName(lua_State* L) {

    const char* triggerName = lua_tostring(L, 1);

    // Find the trigger and set up callback
    for (int t_index = 0; t_index < Triggers.Count(); t_index++) {
        TriggerClass* trigger = Triggers.Ptr(t_index);

        if (trigger != NULL) {

            if (strcmp(trigger->Name(), triggerName) == 0) {

                TriggerTypeClass* this_type = trigger->Class;
                lua_pushnumber(L, t_index);

                return 1;

                break;
            }

        }

    }

    lua_pushnumber(L, -1);

    return -1;
}

/***********************************************************************************************
 * Script_TriggerSetPersistence - Sets whether a trigger runs once or indefinitely             *
 *                                                                                             *
 *   SCRIPT INPUT:	triggerIndex (int)     - The trigger ID of which this will apply           *
 *                	isPersistent (int)     - The persistence value                             *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_TriggerSetPersistence(lua_State* L) {

    int triggerIndex = lua_tointeger(L, 1);
    unsigned char isPersistent = lua_tointeger(L, 2);

    TriggerClass* trigger = Triggers.Ptr(triggerIndex);

    if (trigger != NULL) {

        TriggerTypeClass* trigger_type = trigger->Class;

        trigger_type->IsPersistant = (TriggerTypeClass::PersistantType)isPersistent;


    }

    return -1;
}


/**********************************************************************************************
* Modification Utility Functions                                                              *
*=============================================================================================*/

/**********************************************************************************************
* Script_SetObjectAttribute - Sets attributes for specific objects or object types            *
*                                                                                             *
*   SCRIPT INPUT:	objectID        (int)  - The ID of the object                             *
*                	attribute_type  (int)  - The attribute to change                          *
*                	attribute_value (int)  - The value to set the attribute to                *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_SetObjectAttribute(lua_State* L) {

    int objectID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    ObjectClass* this_object = Script_GetCacheObject(objectID);

    // Get the appropriate technotype
    if (this_object != NULL) {

        // Global attributes / Multi object attributes
        switch ((MapScriptObjectAttributeType)attribute_type) {
        case ATTRIBUTE_TYPE: {

        }break;
        case ATTRIBUTE_STRENGTH: {

            int attribute_value = lua_tointeger(L, 3);
            this_object->Strength = attribute_value;

        }break;

        case ATTRIBUTE_IS_REPAIRING: {

            int attribute_value = lua_tointeger(L, 3);

            switch (this_object->RTTI) {
            case RTTI_BUILDING: {

                BuildingClass* this_building = (BuildingClass*)this_object;
                this_building->IsRepairing = attribute_value;

            }break;
            case RTTI_VESSEL: {

                VesselClass* this_vessel = (VesselClass*)this_object;
                this_vessel->IsSelfRepairing = attribute_value;

            }break;
            }
        }break;

            // Object Class specific
        default: {

            TechnoTypeClass* this_type_class;

            switch (this_object->RTTI) {
            case RTTI_BUILDING:

                this_type_class = BuildingTypes.Ptr(this_object->Class_Of().ID);

                break;
            case RTTI_UNIT:

                this_type_class = UnitTypes.Ptr(this_object->Class_Of().ID);

                break;
            case RTTI_INFANTRY:

                this_type_class = InfantryTypes.Ptr(this_object->Class_Of().ID);

                break;
            case RTTI_VESSEL:

                this_type_class = VesselTypes.Ptr(this_object->Class_Of().ID);

                break;
            case RTTI_AIRCRAFT:

                this_type_class = AircraftTypes.Ptr(this_object->Class_Of().ID);

                break;
            }


            if (this_type_class != NULL) {
                Script_SetObjectTypeAttribute(L, this_type_class, (MapScriptObjectAttributeType)attribute_type);
            }

        }break;

        }

    }


    return -1;
}

/**********************************************************************************************
* Script_SetBuildingTypeAttribute - Sets attributes for a building types                      *
*                                                                                             *
*   SCRIPT INPUT:	buildingTypeID  (int)  - The ID of the building type class                *
*                	attribute_type  (int)  - The attribute to change                          *
*                	attribute_value (int)  - The value to set the attribute to                *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_SetBuildingTypeAttribute(lua_State* L) {

    int buildingTypeID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    TechnoTypeClass* this_type_class = BuildingTypes.Ptr(buildingTypeID);

    if (this_type_class != NULL) {
        Script_SetObjectTypeAttribute(L, this_type_class, (MapScriptObjectAttributeType)attribute_type);
    }

    return -1;
}

/**********************************************************************************************
* Script_SetVehicleTypeAttribute - Sets attributes for vehicle types                          *
*                                                                                             *
*   SCRIPT INPUT:	vehicleTypeID  (int)   - The ID of the vehicle type class                 *
*                	attribute_type  (int)  - The attribute to change                          *
*                	attribute_value (int)  - The value to set the attribute to                *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_SetVehicleTypeAttribute(lua_State* L) {

    int vehicleTypeID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    TechnoTypeClass* this_type_class = UnitTypes.Ptr(vehicleTypeID);

    if (this_type_class != NULL) {
        Script_SetObjectTypeAttribute(L, this_type_class, (MapScriptObjectAttributeType)attribute_type);
    }

    return -1;
}

/**********************************************************************************************
* Script_SetInfantryTypeAttribute - Sets attributes for infantry types                        *
*                                                                                             *
*   SCRIPT INPUT:	infantryTypeID  (int)  - The ID of the infantry type class                *
*                	attribute_type  (int)  - The attribute to change                          *
*                	attribute_value (int)  - The value to set the attribute to                *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_SetInfantryTypeAttribute(lua_State* L) {

    int infantryTypeID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    TechnoTypeClass* this_type_class = InfantryTypes.Ptr(infantryTypeID);

    if (this_type_class != NULL) {
        Script_SetObjectTypeAttribute(L, this_type_class, (MapScriptObjectAttributeType)attribute_type);
    }

    return -1;
}

/**********************************************************************************************
* Script_SetVesselTypeAttribute - Sets attributes for vessel types                            *
*                                                                                             *
*   SCRIPT INPUT:	vesselTypeID    (int)  - The ID of the vessel type class                  *
*                	attribute_type  (int)  - The attribute to change                          *
*                	attribute_value (int)  - The value to set the attribute to                *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_SetVesselTypeAttribute(lua_State* L) {

    int vesselTypeID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    TechnoTypeClass* this_type_class = VesselTypes.Ptr(vesselTypeID);

    if (this_type_class != NULL) {
        Script_SetObjectTypeAttribute(L, this_type_class, (MapScriptObjectAttributeType)attribute_type);
    }

    return -1;
}

/**********************************************************************************************
* Script_SetAircraftTypeAttribute - Sets attributes for aircraft types                        *
*                                                                                             *
*   SCRIPT INPUT:	aircraftTypeID  (int)  - The ID of the aircraft type class                *
*                	attribute_type  (int)  - The attribute to change                          *
*                	attribute_value (int)  - The value to set the attribute to                *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_SetAircraftTypeAttribute(lua_State* L) {

    int aircraftTypeID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    TechnoTypeClass* this_type_class = AircraftTypes.Ptr(aircraftTypeID);

    if (this_type_class != NULL) {
        Script_SetObjectTypeAttribute(L, this_type_class, (MapScriptObjectAttributeType)attribute_type);
    }

    return -1;
}

/**********************************************************************************************
* Script_SetObjectTypeAttribute - Sets attributes for specific object types globally          *
*                                                                                             *
*  Used internally by MapScript to retrieve input and set attributes for TechnoTypeClass      *
*                                                                                             *
*   SCRIPT INPUT:	this_type_class (TechnoTypeClass*) - The techno type                      *
*                	attribute_type  (MapScriptObjectAttributeType)  - The attribute to change       *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_SetObjectTypeAttribute(lua_State* L, TechnoTypeClass* this_type_class, MapScriptObjectAttributeType attribute_type) {

    switch (attribute_type) {
    case ATTRIBUTE_MAX_STRENGTH: {

        int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->MaxStrength);

        // Set the attribute
        this_type_class->MaxStrength = attribute_value;

    }break;

    case ATTRIBUTE_COST: {

        int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->Cost);

        // Set the attribute
        this_type_class->Cost = attribute_value;

    }break;
    case ATTRIBUTE_SIGHT_RANGE: {

        int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->SightRange);

        // Set the attribute
        this_type_class->SightRange = attribute_value;

    }break;
    case ATTRIBUTE_TECH_LEVEL: {

        int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->Level);

        // Set the attribute
        this_type_class->Level = attribute_value;

    }break;
    case ATTRIBUTE_ARMOR: {

        int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->Armor);

        // Set the attribute
        this_type_class->Armor = (ArmorType)attribute_value;

    }break;
    case ATTRIBUTE_PRIMARY_WEAPON: {

        int attribute_value = lua_tointeger(L, 3);

        if (this_type_class->PrimaryWeapon != NULL) {
            // Cache default value if first time changing this attribute
            Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->PrimaryWeapon->ID);
        }
        else {
            // Cache default value if first time changing this attribute
            Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, -1);
        }

        // Set the attribute
        if (attribute_value < 0) {
            this_type_class->PrimaryWeapon = NULL;
        }
        else {
            WeaponTypeClass* this_weapon = Weapons.Ptr(attribute_value);
            if (this_weapon != NULL) {
                this_type_class->PrimaryWeapon = this_weapon;
            }
            else {
                this_type_class->PrimaryWeapon = NULL;
            }
        }

    }break;
    case ATTRIBUTE_SECONDARY_WEAPON: {

        int attribute_value = lua_tointeger(L, 3);

        if (this_type_class->PrimaryWeapon != NULL) {
            // Cache default value if first time changing this attribute
            Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->SecondaryWeapon->ID);
        }
        else {
            // Cache default value if first time changing this attribute
            Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, -1);
        }

        // Set the attribute
        if (attribute_value < 0) {
            this_type_class->SecondaryWeapon = NULL;
        }
        else {
            WeaponTypeClass* this_weapon = Weapons.Ptr(attribute_value);
            if (this_weapon != NULL) {
                this_type_class->SecondaryWeapon = this_weapon;
            }
            else {
                this_type_class->SecondaryWeapon = NULL;
            }
        }

    }break;
    case ATTRIBUTE_SPEED: {

        int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->Speed);

        // Set the attribute
        this_type_class->Speed = (SpeedType)attribute_value;

    }break;
    case ATTRIBUTE_MAX_SPEED: {

        int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->MaxSpeed);

        // Set the attribute
        this_type_class->MaxSpeed = (MPHType)attribute_value;

    }break;
    case ATTRIBUTE_MAX_AMMO: {

        int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->MaxAmmo);

        // Set the attribute
        this_type_class->MaxAmmo = attribute_value;

    }break;
    case ATTRIBUTE_ROTATION_SPEED: {

        int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->ROT);

        // Set the attribute
        this_type_class->ROT = attribute_value;

    }break;
    case ATTRIBUTE_CRUSHABLE: {

        unsigned int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->IsCrushable);

        // Set the attribute
        this_type_class->IsCrushable = attribute_value;

    }break;
    case ATTRIBUTE_STEALTHY: {

        unsigned int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->IsStealthy);

        // Set the attribute
        this_type_class->IsStealthy = attribute_value;

    }break;
    case ATTRIBUTE_SELECTABLE: {

        unsigned int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->IsSelectable);

        // Set the attribute
        this_type_class->IsSelectable = attribute_value;

    }break;
    case ATTRIBUTE_LEGAL_TARGET: {

        unsigned int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->IsLegalTarget);

        // Set the attribute
        this_type_class->IsLegalTarget = attribute_value;

    }break;
    case ATTRIBUTE_REPAIRABLE: {

        unsigned int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->IsRepairable);

        // Set the attribute
        this_type_class->IsRepairable = attribute_value;

    }break;
    case ATTRIBUTE_SELF_HEALING: {

        unsigned int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->IsSelfHealing);

        // Set the attribute
        this_type_class->IsSelfHealing = attribute_value;

    }break;
    case ATTRIBUTE_EXPLODES: {

        unsigned int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->IsExploding);

        // Set the attribute
        this_type_class->IsExploding = attribute_value;

    }break;
    case ATTRIBUTE_HAS_CREW: {

        unsigned int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->IsCrew);

        // Set the attribute
        this_type_class->IsCrew = attribute_value;

    }break;
    case ATTRIBUTE_MAX_PASSENGERS: {

        int attribute_value = lua_tointeger(L, 3);

        // Cache default value if first time changing this attribute
        Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_type_class->MaxPassengers);

        // Set the attribute
        this_type_class->MaxPassengers = attribute_value;

    }break;
    default: {

        // Object class specific attributes
        // Welcome to the web of switches]

        // Type of object
        switch (this_type_class->RTTI) {

            // Building Specific
        case RTTI_BUILDINGTYPE: {

            // What type of attribute?
            switch (attribute_type) {
            case ATTRIBUTE_CAPACITY: {

                int attribute_value = lua_tointeger(L, 3);

                BuildingTypeClass* this_building_class = (BuildingTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_building_class->Capacity);

                // Set the attribute
                this_building_class->Capacity = attribute_value;

            }break;
            case ATTRIBUTE_POWER: {

                int attribute_value = lua_tointeger(L, 3);

                // Both power and drain are different variables
                // And so we do some trickery here to fill
                // the right values based on postivie/negative input

                BuildingTypeClass* this_building_class = (BuildingTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_building_class->Power - this_building_class->Drain);

                // Set the attribute
                if (attribute_value > 0) {
                    this_building_class->Power = attribute_value;
                    this_building_class->Drain = 0;
                }
                else {
                    this_building_class->Power = 0;
                    this_building_class->Drain = attribute_value * -1; // Flip negative power input
                }

            }break;
            case ATTRIBUTE_SELLABLE: {

                int attribute_value = lua_tointeger(L, 3);

                BuildingTypeClass* this_building_class = (BuildingTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_building_class->IsUnsellable * -1);

                // Set the attribute
                // Personal opinion; sellable makes more sense than unsellable
                // This replacement could be seen as IsUnNonSellable, or... IsSellable
                if (attribute_value == 1) {
                    this_building_class->IsUnsellable = 0;
                }
                else {
                    this_building_class->IsUnsellable = 1;
                }

            }break;
            }

        }break;


            // Unit Specific
        case RTTI_UNITTYPE: {

            // What type of attribute?
            switch (attribute_type) {
            case ATTRIBUTE_CRATE_GOODIE: {

                int attribute_value = lua_tointeger(L, 3);

                UnitTypeClass* this_unit_class = (UnitTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_unit_class->IsCrateGoodie);

                // Set the attribute
                this_unit_class->IsCrateGoodie = attribute_value;

            }break;
            case ATTRIBUTE_CRUSHER: {

                int attribute_value = lua_tointeger(L, 3);

                UnitTypeClass* this_unit_class = (UnitTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_unit_class->IsCrusher);

                // Set the attribute
                this_unit_class->IsCrusher = attribute_value;

            }break;
            case ATTRIBUTE_HARVEST: {

                int attribute_value = lua_tointeger(L, 3);

                UnitTypeClass* this_unit_class = (UnitTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_unit_class->IsToHarvest);

                // Set the attribute
                this_unit_class->IsToHarvest = attribute_value;

            }break;
            case ATTRIBUTE_RADAR_EQUIPPED: {

                int attribute_value = lua_tointeger(L, 3);

                UnitTypeClass* this_unit_class = (UnitTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_unit_class->IsRadarEquipped);

                // Set the attribute
                this_unit_class->IsRadarEquipped = attribute_value;

            }break;
            case ATTRIBUTE_JAMMER: {

                int attribute_value = lua_tointeger(L, 3);

                UnitTypeClass* this_unit_class = (UnitTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_unit_class->IsJammer);

                // Set the attribute
                this_unit_class->IsJammer = attribute_value;

            }break;
            case ATTRIBUTE_GAPPER: {

                int attribute_value = lua_tointeger(L, 3);

                UnitTypeClass* this_unit_class = (UnitTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_unit_class->IsGapper);

                // Set the attribute
                this_unit_class->IsGapper = attribute_value;

            }break;
            }

        }break;


            // Infantry Specific
        case RTTI_INFANTRYTYPE: {

            // What type of attribute?
            switch (attribute_type) {
            case ATTRIBUTE_FEMALE: {

                int attribute_value = lua_tointeger(L, 3);

                InfantryTypeClass* this_infantry_class = (InfantryTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_infantry_class->IsFemale);

                // Set the attribute
                this_infantry_class->IsFemale = attribute_value;

            }break;
            case ATTRIBUTE_CAPTURE: {

                int attribute_value = lua_tointeger(L, 3);

                InfantryTypeClass* this_infantry_class = (InfantryTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_infantry_class->IsCapture);

                // Set the attribute
                this_infantry_class->IsCapture = attribute_value;

            }break;
            case ATTRIBUTE_FRAIDY_CAT: {

                int attribute_value = lua_tointeger(L, 3);

                InfantryTypeClass* this_infantry_class = (InfantryTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_infantry_class->IsFraidyCat);

                // Set the attribute
                this_infantry_class->IsFraidyCat = attribute_value;

            }break;
            case ATTRIBUTE_CIVILIAN: {

                int attribute_value = lua_tointeger(L, 3);

                InfantryTypeClass* this_infantry_class = (InfantryTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_infantry_class->IsCivilian);

                // Set the attribute
                this_infantry_class->IsCivilian = attribute_value;

            }break;
            case ATTRIBUTE_BOMBER: {

                int attribute_value = lua_tointeger(L, 3);

                InfantryTypeClass* this_infantry_class = (InfantryTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_infantry_class->IsBomber);

                // Set the attribute
                this_infantry_class->IsBomber = attribute_value;

            }break;
            case ATTRIBUTE_DOG: {

                int attribute_value = lua_tointeger(L, 3);

                InfantryTypeClass* this_infantry_class = (InfantryTypeClass*)this_type_class;

                // Cache default value if first time changing this attribute
                Script_CacheDefaultObjectTypeAttribute(this_type_class->RTTI, this_type_class->ID, attribute_type, this_infantry_class->IsDog);

                // Set the attribute
                this_infantry_class->IsDog = attribute_value;

            }break;

            }

        }break;

        } // End of object specific switch

    }break;

    } // End of attribute switch 

    return -1;
}

/**********************************************************************************************
* Script_GetObjectAttribute - Gets attributes for specific objects or object types            *
*                                                                                             *
*   SCRIPT INPUT:	objectID        (int)  - The ID of the object                             *
*                	attribute_type  (int)  - The attribute to change                          *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_GetObjectAttribute(lua_State* L) {

    int objectID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    ObjectClass* this_object = Script_GetCacheObject(objectID);

    // Get the appropriate technotype
    if (this_object != NULL) {

        // Global attributes / Multi object attributes
        switch ((MapScriptObjectAttributeType)attribute_type) {
        case ATTRIBUTE_TYPE: {

            // Send the attribute
            lua_pushinteger(L, this_object->RTTI);
            return 1;

        }break;
        case ATTRIBUTE_STRENGTH: {

            // Send the attribute
            lua_pushinteger(L, this_object->Strength);
            return 1;

        }break;

        case ATTRIBUTE_IS_REPAIRING: {

            switch (this_object->RTTI) {
            case RTTI_BUILDING: {

                BuildingClass* this_building = (BuildingClass*)this_object;

                // Send the attribute
                lua_pushinteger(L, this_building->IsRepairing);
                return 1;

            }break;
            case RTTI_VESSEL: {

                VesselClass* this_vessel = (VesselClass*)this_object;

                // Send the attribute
                lua_pushinteger(L, this_vessel->IsSelfRepairing);
                return 1;

            }break;
            }
        }break;

            // Object Class specific
        default: {

            TechnoTypeClass* this_type_class = NULL;

            switch (this_object->RTTI) {
            case RTTI_BUILDING:

                this_type_class = BuildingTypes.Ptr(this_object->Class_Of().ID);

                break;
            case RTTI_UNIT:

                this_type_class = UnitTypes.Ptr(this_object->Class_Of().ID);

                break;
            case RTTI_INFANTRY:

                this_type_class = InfantryTypes.Ptr(this_object->Class_Of().ID);

                break;
            case RTTI_VESSEL:

                this_type_class = VesselTypes.Ptr(this_object->Class_Of().ID);

                break;
            case RTTI_AIRCRAFT:

                this_type_class = AircraftTypes.Ptr(this_object->Class_Of().ID);

                break;
            }

            // Type attribute retrieval
            if (this_type_class != NULL) {
                return Script_SetObjectTypeAttribute(L, this_type_class, (MapScriptObjectAttributeType)attribute_type);
            }

        }break;

        }

    }


    return -1;
}

/**********************************************************************************************
* Script_GetBuildingTypeAttribute - Gets attributes for a building types                      *
*                                                                                             *
*   SCRIPT INPUT:	buildingTypeID  (int)  - The ID of the building type class                *
*                	attribute_type  (int)  - The attribute to change                          *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_GetBuildingTypeAttribute(lua_State* L) {

    int buildingTypeID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    TechnoTypeClass* this_type_class = BuildingTypes.Ptr(buildingTypeID);

    if (this_type_class != NULL) {
        return Script_GetObjectTypeAttribute(L, this_type_class, (MapScriptObjectAttributeType)attribute_type);
    }

    return -1;
}

/**********************************************************************************************
* Script_GetVehicleTypeAttribute - Gets attributes for vehicle types                          *
*                                                                                             *
*   SCRIPT INPUT:	vehicleTypeID  (int)   - The ID of the vehicle type class                 *
*                	attribute_type  (int)  - The attribute to change                          *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_GetVehicleTypeAttribute(lua_State* L) {

    int vehicleTypeID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    TechnoTypeClass* this_type_class = UnitTypes.Ptr(vehicleTypeID);

    if (this_type_class != NULL) {
        return Script_GetObjectTypeAttribute(L, this_type_class, (MapScriptObjectAttributeType)attribute_type);
    }

    return -1;
}

/**********************************************************************************************
* Script_GetInfantryTypeAttribute - Gets attributes for infantry types                        *
*                                                                                             *
*   SCRIPT INPUT:	infantryTypeID  (int)  - The ID of the infantry type class                *
*                	attribute_type  (int)  - The attribute to change                          *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_GetInfantryTypeAttribute(lua_State* L) {

    int infantryTypeID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    TechnoTypeClass* this_type_class = InfantryTypes.Ptr(infantryTypeID);

    if (this_type_class != NULL) {
        return Script_GetObjectTypeAttribute(L, this_type_class, (MapScriptObjectAttributeType)attribute_type);
    }

    return -1;
}

/**********************************************************************************************
* Script_GetVesselTypeAttribute - Gets attributes for vessel types                            *
*                                                                                             *
*   SCRIPT INPUT:	vesselTypeID    (int)  - The ID of the vessel type class                  *
*                	attribute_type  (int)  - The attribute to change                          *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_GetVesselTypeAttribute(lua_State* L) {

    int vesselTypeID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    TechnoTypeClass* this_type_class = VesselTypes.Ptr(vesselTypeID);

    if (this_type_class != NULL) {
        return Script_GetObjectTypeAttribute(L, this_type_class, (MapScriptObjectAttributeType)attribute_type);
    }

    return -1;
}

/**********************************************************************************************
* Script_GetAircraftTypeAttribute - Gets attributes for aircraft types                        *
*                                                                                             *
*   SCRIPT INPUT:	aircraftTypeID  (int)  - The ID of the aircraft type class                *
*                	attribute_type  (int)  - The attribute to change                          *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_GetAircraftTypeAttribute(lua_State* L) {

    int aircraftTypeID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    TechnoTypeClass* this_type_class = AircraftTypes.Ptr(aircraftTypeID);

    if (this_type_class != NULL) {
        return Script_GetObjectTypeAttribute(L, this_type_class, (MapScriptObjectAttributeType)attribute_type);
    }

    return -1;
}

/**********************************************************************************************
* Script_GetObjectTypeAttribute - Gets attributes for specific object types globally          *
*                                                                                             *
*  Used internally by MapScript to send input and get attributes for TechnoTypeClass          *
*                                                                                             *
*   SCRIPT INPUT:	this_type_class (TechnoTypeClass*) - The techno type                      *
*                	attribute_type  (MapScriptObjectAttributeType)  - The attribute to change *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_GetObjectTypeAttribute(lua_State* L, TechnoTypeClass* this_type_class, MapScriptObjectAttributeType attribute_type) {

    switch (attribute_type) {
    case ATTRIBUTE_MAX_STRENGTH: {

        // Send the attribute
        lua_pushinteger(L, this_type_class->MaxStrength);
        return 1;

    }break;

    case ATTRIBUTE_COST: {

        // Send the attribute
        lua_pushinteger(L, this_type_class->Cost);
        return 1;

    }break;
    case ATTRIBUTE_SIGHT_RANGE: {

        // Send the attribute
        lua_pushinteger(L, this_type_class->SightRange);
        return 1;

    }break;
    case ATTRIBUTE_TECH_LEVEL: {

        // Send the attribute
        lua_pushinteger(L, this_type_class->Level);
        return 1;

    }break;
    case ATTRIBUTE_ARMOR: {

        // Send the attribute
        lua_pushinteger(L, this_type_class->Armor);
        return 1;

    }break;
    case ATTRIBUTE_PRIMARY_WEAPON: {

        if (this_type_class->PrimaryWeapon != NULL) {
            // Send the attribute
            lua_pushinteger(L, this_type_class->PrimaryWeapon->ID);
            return 1;
        }
        else {
            // Send the attribute
            lua_pushinteger(L, -1);
            return 1;
        }

    }break;
    case ATTRIBUTE_SECONDARY_WEAPON: {

        if (this_type_class->SecondaryWeapon != NULL) {
            // Send the attribute
            lua_pushinteger(L, this_type_class->SecondaryWeapon->ID);
            return 1;
        }
        else {
            // Send the attribute
            lua_pushinteger(L, -1);
            return 1;
        }

    }break;
    case ATTRIBUTE_SPEED: {

        // Send the attribute
        lua_pushinteger(L, this_type_class->Speed);
        return 1;

    }break;
    case ATTRIBUTE_MAX_SPEED: {

        // Send the attribute
        lua_pushinteger(L, this_type_class->MaxSpeed);
        return 1;

    }break;
    case ATTRIBUTE_MAX_AMMO: {

        // Send the attribute
        lua_pushinteger(L, this_type_class->MaxAmmo);
        return 1;

    }break;
    case ATTRIBUTE_ROTATION_SPEED: {

        // Send the attribute
        lua_pushboolean(L, this_type_class->ROT);
        return 1;

    }break;
    case ATTRIBUTE_CRUSHABLE: {

        // Send the attribute
        lua_pushboolean(L, this_type_class->IsCrushable);
        return 1;

    }break;
    case ATTRIBUTE_STEALTHY: {

        // Send the attribute
        lua_pushboolean(L, this_type_class->IsStealthy);
        return 1;

    }break;
    case ATTRIBUTE_SELECTABLE: {

        // Send the attribute
        lua_pushboolean(L, this_type_class->IsSelectable);
        return 1;

    }break;
    case ATTRIBUTE_LEGAL_TARGET: {

        // Send the attribute
        lua_pushboolean(L, this_type_class->IsLegalTarget);
        return 1;

    }break;
    case ATTRIBUTE_REPAIRABLE: {

        // Send the attribute
        lua_pushboolean(L, this_type_class->IsRepairable);
        return 1;

    }break;
    case ATTRIBUTE_SELF_HEALING: {

        // Send the attribute
        lua_pushboolean(L, this_type_class->IsSelfHealing);
        return 1;

    }break;
    case ATTRIBUTE_EXPLODES: {

        // Send the attribute
        lua_pushboolean(L, this_type_class->IsExploding);
        return 1;

    }break;
    case ATTRIBUTE_HAS_CREW: {

        // Send the attribute
        lua_pushboolean(L, this_type_class->IsCrew);
        return 1;

    }break;
    case ATTRIBUTE_MAX_PASSENGERS: {

        // Send the attribute
        lua_pushinteger(L, this_type_class->MaxPassengers);
        return 1;

    }break;
    default: {

        // Object class specific attributes
        // Welcome to the web of switches]

        // Type of object
        switch (this_type_class->RTTI) {

            // Building Specific
        case RTTI_BUILDINGTYPE: {

            // What type of attribute?
            switch (attribute_type) {
            case ATTRIBUTE_CAPACITY: {

                BuildingTypeClass* this_building_class = (BuildingTypeClass*)this_type_class;

                // Send the attribute
                lua_pushinteger(L, this_building_class->Capacity);
                return 1;

            }break;
            case ATTRIBUTE_POWER: {

                // Both power and drain are different variables
                // And so we do some trickery here to fill
                // the right values based on postivie/negative input

                BuildingTypeClass* this_building_class = (BuildingTypeClass*)this_type_class;

                int this_value = this_building_class->Power - this_building_class->Drain;

                // Send the attribute
                lua_pushinteger(L, this_value);
                return 1;

            }break;
            case ATTRIBUTE_SELLABLE: {

                BuildingTypeClass* this_building_class = (BuildingTypeClass*)this_type_class;

                // Set the attribute
                // Personal opinion; sellable makes more sense than unsellable
                // This replacement could be seen as IsUnNonSellable, or... IsSellable
                if (this_building_class->IsUnsellable == 1) {
                    // Send the attribute
                    lua_pushinteger(L, 0);
                    return 1;
                }
                else {
                    // Send the attribute
                    lua_pushinteger(L, 1);
                    return 1;
                }

            }break;
            }

        }break;


            // Unit Specific
        case RTTI_UNITTYPE: {

            // What type of attribute?
            switch (attribute_type) {
            case ATTRIBUTE_CRATE_GOODIE: {

                UnitTypeClass* this_unit_class = (UnitTypeClass*)this_type_class;

                // Send the attribute
                lua_pushboolean(L, this_unit_class->IsCrateGoodie);
                return 1;

            }break;
            case ATTRIBUTE_CRUSHER: {

                UnitTypeClass* this_unit_class = (UnitTypeClass*)this_type_class;

                // Send the attribute
                lua_pushboolean(L, this_unit_class->IsCrusher);
                return 1;

            }break;
            case ATTRIBUTE_HARVEST: {

                UnitTypeClass* this_unit_class = (UnitTypeClass*)this_type_class;

                // Send the attribute
                lua_pushboolean(L, this_unit_class->IsToHarvest);
                return 1;

            }break;
            case ATTRIBUTE_RADAR_EQUIPPED: {

                UnitTypeClass* this_unit_class = (UnitTypeClass*)this_type_class;

                // Send the attribute
                lua_pushboolean(L, this_unit_class->IsRadarEquipped);
                return 1;

            }break;
            case ATTRIBUTE_JAMMER: {

                UnitTypeClass* this_unit_class = (UnitTypeClass*)this_type_class;

                // Send the attribute
                lua_pushboolean(L, this_unit_class->IsJammer);
                return 1;

            }break;
            case ATTRIBUTE_GAPPER: {

                UnitTypeClass* this_unit_class = (UnitTypeClass*)this_type_class;

                // Send the attribute
                lua_pushboolean(L, this_unit_class->IsGapper);
                return 1;

            }break;
            }

        }break;


            // Infantry Specific
        case RTTI_INFANTRYTYPE: {

            // What type of attribute?
            switch (attribute_type) {
            case ATTRIBUTE_FEMALE: {

                InfantryTypeClass* this_infantry_class = (InfantryTypeClass*)this_type_class;

                // Send the attribute
                lua_pushboolean(L, this_infantry_class->IsFemale);
                return 1;

            }break;
            case ATTRIBUTE_CAPTURE: {

                InfantryTypeClass* this_infantry_class = (InfantryTypeClass*)this_type_class;

                // Send the attribute
                lua_pushboolean(L, this_infantry_class->IsCapture);
                return 1;

            }break;
            case ATTRIBUTE_FRAIDY_CAT: {

                InfantryTypeClass* this_infantry_class = (InfantryTypeClass*)this_type_class;

                // Send the attribute
                lua_pushboolean(L, this_infantry_class->IsFraidyCat);
                return 1;

            }break;
            case ATTRIBUTE_CIVILIAN: {

                InfantryTypeClass* this_infantry_class = (InfantryTypeClass*)this_type_class;

                // Send the attribute
                lua_pushboolean(L, this_infantry_class->IsCivilian);
                return 1;

            }break;
            case ATTRIBUTE_BOMBER: {

                InfantryTypeClass* this_infantry_class = (InfantryTypeClass*)this_type_class;

                // Send the attribute
                lua_pushboolean(L, this_infantry_class->IsBomber);
                return 1;

            }break;
            case ATTRIBUTE_DOG: {

                InfantryTypeClass* this_infantry_class = (InfantryTypeClass*)this_type_class;

                // Send the attribute
                lua_pushboolean(L, this_infantry_class->IsDog);
                return 1;

            }break;

            }

        }break;

        } // End of object specific switch

    }break;

    } // End of attribute switch 


    // Didn't find result
    return -1;

}

/**********************************************************************************************
* Script_SetHouseAttribute - Sets attributes for specific houses                              *
*                                                                                             *
*   SCRIPT INPUT:	houseID         (int)  - The ID of the house                              *
*                	attribute_type  (int)  - The attribute to change                          *
*                	attribute_value (int)  - The value to set the attribute to                *
*                                                                                             *
*   SCRIPT OUTPUT:  void                                                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_SetHouseAttribute(lua_State* L) {

    int houseID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    HouseClass* this_house = Houses.Ptr(houseID);

    // Get the appropriate technotype
    if (this_house != NULL) {

        switch (attribute_type) {
        case HOUSE_ATTRIBUTE_IQ: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->Control.IQ = attribute_value;
            this_house->IQ = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_TECH_LEVEL: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->Control.TechLevel = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_IS_HUMAN: {

            int attribute_value = lua_tointeger(L, 3);

            if (attribute_value == 1) {
                this_house->IsHuman = 1;
                this_house->WasHuman = 1;
            }
            else {
                this_house->IsHuman = 0;
            }


        }break;
        case HOUSE_ATTRIBUTE_FIREPOWER_BIAS: {

            float attribute_value = lua_tonumber(L, 3);

            this_house->FirepowerBias = (fixed)attribute_value * Rule.Diff[this_house->Difficulty].FirepowerBias;

        }break;
        case HOUSE_ATTRIBUTE_GROUNDSPEED_BIAS: {

            float attribute_value = lua_tonumber(L, 3);

            this_house->GroundspeedBias = (fixed)attribute_value * Rule.Diff[this_house->Difficulty].GroundspeedBias;

        }break;
        case HOUSE_ATTRIBUTE_ARMOR_BIAS: {

            float attribute_value = lua_tonumber(L, 3);

            this_house->ArmorBias = (fixed)attribute_value * Rule.Diff[this_house->Difficulty].ArmorBias;

        }break;
        case HOUSE_ATTRIBUTE_ROF_BIAS: {

            float attribute_value = lua_tonumber(L, 3);

            this_house->ROFBias = (fixed)attribute_value * Rule.Diff[this_house->Difficulty].ROFBias;

        }break;
        case HOUSE_ATTRIBUTE_COST_BIAS: {

            float attribute_value = lua_tonumber(L, 3);

            this_house->CostBias = (fixed)attribute_value * Rule.Diff[this_house->Difficulty].CostBias;

        }break;
        case HOUSE_ATTRIBUTE_REPAIR_DELAY: {

            float attribute_value = lua_tonumber(L, 3);

            this_house->RepairDelay = (fixed)attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_BUILD_DELAY: {

            float attribute_value = lua_tonumber(L, 3);

            this_house->BuildDelay = (fixed)attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_STARTED: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->IsStarted = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_ALERTED: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->IsAlerted = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_BASE_BUILDING: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->IsBaseBuilding = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_DISCOVERED: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->IsDiscovered = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_CAPACITY: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->Capacity = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_TIBERIUM: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->Tiberium = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_CREDITS: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->Credits = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_ALERT_TIMER: {

            float attribute_value = lua_tonumber(L, 3);

            this_house->AlertTime = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_REPAIR_TIMER: {

            float attribute_value = lua_tonumber(L, 3);

            this_house->RepairTimer = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_POINTS: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->PointTotal = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_DESTROYED_BUILDINGS: {

            // Non writable

        }break;
        case HOUSE_ATTRIBUTE_DESTROYED_INFANTRY: {

            // Non writable

        }break;
        case HOUSE_ATTRIBUTE_DESTROYED_VEHICLES: {

            // Non writable

        }break;
        case HOUSE_ATTRIBUTE_DESTROYED_AIRCRAFT: {

            // Non writable

        }break;
        case HOUSE_ATTRIBUTE_DESTROYED_VESSELS: {

            // Non writable

        }break;
        case HOUSE_ATTRIBUTE_CAPTURED_BUILDINGS: {

            // Non writable

        }break;
        case HOUSE_ATTRIBUTE_CRATES: {

            // Non writable

        }break;

        case HOUSE_ATTRIBUTE_BUILDING_FACTORIES: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->BuildingFactories = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_UNIT_FACTORIES: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->UnitFactories = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_INFANTRY_FACTORIES: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->InfantryFactories = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_AIRCRAFT_FACTORIES: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->AircraftFactories = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_VESSEL_FACTORIES: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->VesselFactories = attribute_value;

        }break;

        case HOUSE_ATTRIBUTE_POWER: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->Power = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_DRAIN: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->Drain = attribute_value;

        }break;
        case HOUSE_ATTRIBUTE_LAST_ATTACKER: {

            int attribute_value = lua_tointeger(L, 3);

            this_house->WhoLastHurtMe = (HousesType)attribute_value;

        }break;
        }

    }


    return -1;
}

/**********************************************************************************************
* Script_GetHouseAttribute - Sets attributes for specific houses                              *
*                                                                                             *
*   SCRIPT INPUT:	houseID         (int)  - The ID of the house                              *
*                	attribute_type  (int)  - The attribute to change                          *
*                                                                                             *
*   SCRIPT OUTPUT:  (mixed) - The value of the attribute                                      *
*                                                                                             *
* INPUT:  lua_State - The current Lua state                                                   *
*                                                                                             *
* OUTPUT:  int; Did the function run successfully? Return 1                                   *
*                                                                                             *
* WARNINGS:  ?                                                                                *
*                                                                                             *
*=============================================================================================*/
static int Script_GetHouseAttribute(lua_State* L) {

    int houseID = lua_tointeger(L, 1);
    int attribute_type = lua_tointeger(L, 2);

    HouseClass* this_house = Houses.Ptr(houseID);

    // Get the appropriate technotype
    if (this_house != NULL) {

        switch (attribute_type) {
        case HOUSE_ATTRIBUTE_IQ: {

            lua_pushnumber(L, this_house->IQ);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_TECH_LEVEL: {

            lua_pushnumber(L, this_house->Control.TechLevel);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_IS_HUMAN: {

            lua_pushboolean(L, this_house->IsHuman);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_FIREPOWER_BIAS: {

            lua_pushnumber(L, (float)this_house->FirepowerBias.To_Float());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_GROUNDSPEED_BIAS: {

            lua_pushnumber(L, (float)this_house->GroundspeedBias.To_Float());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_ARMOR_BIAS: {

            lua_pushnumber(L, (float)this_house->ArmorBias.To_Float());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_ROF_BIAS: {

            lua_pushnumber(L, this_house->ROFBias.To_Float());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_COST_BIAS: {

            lua_pushnumber(L, (float)this_house->CostBias.To_Float());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_REPAIR_DELAY: {

            lua_pushnumber(L, (float)this_house->RepairDelay.To_Float());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_BUILD_DELAY: {

            lua_pushnumber(L, (float)this_house->BuildDelay.To_Float());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_STARTED: {

            lua_pushboolean(L, this_house->IsStarted);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_ALERTED: {

            lua_pushboolean(L, this_house->IsAlerted);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_BASE_BUILDING: {

            lua_pushboolean(L, this_house->IsBaseBuilding);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_DISCOVERED: {

            lua_pushboolean(L, this_house->IsDiscovered);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_CAPACITY: {

            lua_pushinteger(L, this_house->Capacity);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_TIBERIUM: {

            lua_pushinteger(L, this_house->Tiberium);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_CREDITS: {

            lua_pushinteger(L, this_house->Credits);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_ALERT_TIMER: {

            lua_pushnumber(L, this_house->AlertTime);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_REPAIR_TIMER: {

            lua_pushnumber(L, this_house->RepairTimer);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_POINTS: {

            lua_pushinteger(L, this_house->PointTotal);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_DESTROYED_BUILDINGS: {

            lua_pushinteger(L, (int)this_house->DestroyedBuildings->Get_All_Totals());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_DESTROYED_INFANTRY: {

            lua_pushinteger(L, (int)this_house->DestroyedInfantry->Get_All_Totals());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_DESTROYED_VEHICLES: {

            lua_pushinteger(L, (int)this_house->DestroyedUnits->Get_All_Totals());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_DESTROYED_AIRCRAFT: {

            lua_pushinteger(L, (int)this_house->DestroyedAircraft->Get_All_Totals());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_DESTROYED_VESSELS: {

            lua_pushinteger(L, (int)this_house->DestroyedVessels->Get_All_Totals());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_CAPTURED_BUILDINGS: {

            lua_pushinteger(L, (int)this_house->CapturedBuildings->Get_All_Totals());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_CRATES: {

            lua_pushinteger(L, (int)this_house->TotalCrates->Get_All_Totals());
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_AIRCRAFT_FACTORIES: {

            lua_pushinteger(L, this_house->AircraftFactories);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_INFANTRY_FACTORIES: {

            lua_pushinteger(L, this_house->InfantryFactories);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_UNIT_FACTORIES: {

            lua_pushinteger(L, this_house->UnitFactories);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_VESSEL_FACTORIES: {

            lua_pushinteger(L, this_house->VesselFactories);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_BUILDING_FACTORIES: {

            lua_pushinteger(L, this_house->BuildingFactories);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_POWER: {

            lua_pushnumber(L, this_house->Power);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_DRAIN: {

            lua_pushnumber(L, this_house->Drain);
            return 1;

        }break;
        case HOUSE_ATTRIBUTE_LAST_ATTACKER: {

            lua_pushnumber(L, this_house->WhoLastHurtMe);
            return 1;

        }break;
        }

    }

    lua_pushnumber(L, -1);

    return -1;
}

/***********************************************************************************************
 * Script_BuildUnit - Builds a given unit in a given factory                                   *
 *                                                                                             *
 *   SCRIPT INPUT:	factoryObject (int) - The factory object id                                *
 *                                                                                             *
 *                	unitType (int)    - The unit type index for the unit to make (unit in a    *
 *                                      general sense, not a vehicle)                          *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_BuildUnit(lua_State* L) {

    int factoryObject = lua_tointeger(L, 1);
    int unitType = lua_tointeger(L, 2);

    BuildingClass* this_factory = (BuildingClass*)Script_GetCacheObject(factoryObject);

    // Get the appropriate technotype
    if (this_factory != NULL && this_factory->IsActive) {

        int result = true;

        switch (this_factory->Class->ID) {
        case STRUCT_WEAP: {

            UnitTypeClass* unit_to_place = UnitTypes.Ptr(unitType);
            UnitClass* new_unit = (UnitClass*)unit_to_place->Create_One_Of(this_factory->House);

            if (this_factory->Exit_Object(new_unit)) {

                int _objectIndex = -1;
                MapScriptObject* CacheObject = Scen.mapScript->CreateCacheObject();
                CacheObject->ID = -1;

                _objectIndex = Script_UnitIndexFromID(new_unit->ID);

                CacheObject->ID = new_unit->ID;
                CacheObject->RTTI = new_unit->RTTI;
                CacheObject->classIndex = _objectIndex;
                Scen.mapScript->ObjectCache.push_back(CacheObject);

                lua_pushnumber(L, CacheObject->UID);
                return 1;

            }
            else {
                delete new_unit;
            }

            lua_pushnumber(L, -1);
            return 1;

        }break;
        case STRUCT_TENT:
        case STRUCT_BARRACKS: {

            InfantryTypeClass* unit_to_place = InfantryTypes.Ptr(unitType);
            InfantryClass* new_unit = (InfantryClass*)unit_to_place->Create_One_Of(this_factory->House);

            if (this_factory->Exit_Object(new_unit)) {

                int _objectIndex = -1;
                MapScriptObject* CacheObject = Scen.mapScript->CreateCacheObject();
                CacheObject->ID = -1;

                _objectIndex = Script_InfantryIndexFromID(new_unit->ID);

                CacheObject->ID = new_unit->ID;
                CacheObject->RTTI = new_unit->RTTI;
                CacheObject->classIndex = _objectIndex;
                Scen.mapScript->ObjectCache.push_back(CacheObject);

                lua_pushnumber(L, CacheObject->UID);
                return 1;

            }
            else {
                delete new_unit;
            }

            lua_pushnumber(L, -1);
            return 1;

        }break;
        case STRUCT_KENNEL: {

            InfantryTypeClass* unit_to_place = InfantryTypes.Ptr(unitType);
            InfantryClass* new_unit = (InfantryClass*)unit_to_place->Create_One_Of(this_factory->House);

            if (this_factory->Exit_Object(new_unit)) {

                int _objectIndex = -1;
                MapScriptObject* CacheObject = Scen.mapScript->CreateCacheObject();
                CacheObject->ID = -1;

                _objectIndex = Script_InfantryIndexFromID(new_unit->ID);

                CacheObject->ID = new_unit->ID;
                CacheObject->RTTI = new_unit->RTTI;
                CacheObject->classIndex = _objectIndex;
                Scen.mapScript->ObjectCache.push_back(CacheObject);

                lua_pushnumber(L, CacheObject->UID);
                return 1;

            }
            else {
                delete new_unit;
            }

            lua_pushnumber(L, -1);
            return 1;

        }break;
        case STRUCT_HELIPAD:
        case STRUCT_AIRSTRIP: {

            AircraftTypeClass* unit_to_place = AircraftTypes.Ptr(unitType);
            AircraftClass* new_unit = (AircraftClass*)unit_to_place->Create_One_Of(this_factory->House);

            if (this_factory->Exit_Object(new_unit)) {

                int _objectIndex = -1;
                MapScriptObject* CacheObject = Scen.mapScript->CreateCacheObject();
                CacheObject->ID = -1;

                _objectIndex = Script_AircraftIndexFromID(new_unit->ID);

                CacheObject->ID = new_unit->ID;
                CacheObject->RTTI = new_unit->RTTI;
                CacheObject->classIndex = _objectIndex;
                Scen.mapScript->ObjectCache.push_back(CacheObject);

                lua_pushnumber(L, CacheObject->UID);
                return 1;

            }
            else {
                delete new_unit;
            }

            lua_pushnumber(L, -1);
            return 1;

        }break;
        case STRUCT_SUB_PEN:
        case STRUCT_SHIP_YARD: {

            VesselTypeClass* unit_to_place = VesselTypes.Ptr(unitType);
            VesselClass* new_unit = (VesselClass*)unit_to_place->Create_One_Of(this_factory->House);

            if (this_factory->Exit_Object(new_unit)) {

                int _objectIndex = -1;
                MapScriptObject* CacheObject = Scen.mapScript->CreateCacheObject();
                CacheObject->ID = -1;

                _objectIndex = Script_VesselIndexFromID(new_unit->ID);

                CacheObject->ID = new_unit->ID;
                CacheObject->RTTI = new_unit->RTTI;
                CacheObject->classIndex = _objectIndex;
                Scen.mapScript->ObjectCache.push_back(CacheObject);

                lua_pushnumber(L, CacheObject->UID);
                return 1;

            }
            else {
                delete new_unit;
            }

            lua_pushnumber(L, -1);
            return 1;

        }break;
        }

    }


    lua_pushnumber(L, -1);
    return 1;
}

/***********************************************************************************************
 * Script_CreateVehicle - Creates a given unit out of thin air                                 *
 *                                                                                             *
 *   SCRIPT INPUT:	objectIndex(int) - The unit type to create                                 *
 *                                                                                             *
 *                  houseType  (int) - The player (house) index to create the unit for         *
 *                                                                                             *
 *                  in_x       (int) - X location to create object                             *
 *                                                                                             *
 *                  in_y       (int) - Y location to create object                             *
 *                                                                                             *
 *   SCRIPT OUTPUT:  (int) the cached object ID for use with Mapscript Functions               *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CreateVehicle(lua_State* L) {

    int objectIndex = lua_tointeger(L, 1);
    int houseType = lua_tointeger(L, 2);
	int in_x = 0;
	int in_y = 0;

	COORDINATE coord;
	if (lua_gettop(L) == 3) {
		CELL cell = lua_tointeger(L, 3);
		coord = Cell_Coord(cell);
	}
	else {
		in_x = lua_tointeger(L, 3);
		in_y = lua_tointeger(L, 4);
		coord = Cell_Coord(XY_Cell(in_x, in_y));
	}

    HouseClass* this_house = Houses.Ptr(houseType);

    UnitTypeClass* unit_to_place = UnitTypes.Ptr(objectIndex);

    if (this_house != NULL && unit_to_place != NULL) {
        UnitClass* new_unit = (UnitClass*)unit_to_place->Create_One_Of(this_house);
        if (new_unit != NULL) {

            bool new_unit_placed = false;

            if (new_unit->Unlimbo(coord)) {

                new_unit_placed = true;
            }

            /*
            **	Try to place the object into a nearby cell if something is preventing
            **	placement at the given location.
            */
            if (!new_unit_placed) {
                CELL cell = Map.Nearby_Location(coord, new_unit->Class->Speed);
                if (new_unit->Unlimbo(::Cell_Coord(cell))) {
                    new_unit_placed = true;
                }
            }


            if (new_unit_placed) {
                int _objectIndex = -1;
                MapScriptObject* CacheObject = Scen.mapScript->CreateCacheObject();
                CacheObject->ID = -1;

                _objectIndex = Script_UnitIndexFromID(new_unit->ID);

                CacheObject->ID = new_unit->ID;
                CacheObject->RTTI = new_unit->RTTI;
                CacheObject->classIndex = _objectIndex;
                Scen.mapScript->ObjectCache.push_back(CacheObject);

                lua_pushnumber(L, CacheObject->UID);
                return 1;
            }
        }
    }

    lua_pushnumber(L, -1);
    return 1;
}


/***********************************************************************************************
 * Script_CreateInfantry - Creates a given Infantry out of thin air                            *
 *                                                                                             *
 *   SCRIPT INPUT:	objectIndex(int) - The Infantry type to create                             *
 *                                                                                             *
 *                  houseType  (int) - The player (house) index to create the Infantry for     *
 *                                                                                             *
 *                  in_x       (int) - X location to create object                             *
 *                                                                                             *
 *                  in_y       (int) - Y location to create object                             *
 *                                                                                             *
 *   SCRIPT OUTPUT:  (int) the cached object ID for use with Mapscript Functions               *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CreateInfantry(lua_State* L) {

    int objectIndex = lua_tointeger(L, 1);
    int houseType = lua_tointeger(L, 2);
    int in_x = 0;
    int in_y = 0;
    
    COORDINATE coord;
	if (lua_gettop(L) == 3) {
        CELL cell = lua_tointeger(L, 3);
        coord = Cell_Coord(cell);
	}
    else {
        in_x = lua_tointeger(L, 3);
        in_y = lua_tointeger(L, 4);
        coord = Cell_Coord(XY_Cell(in_x, in_y));
    }

    HouseClass* this_house = Houses.Ptr(houseType);

    InfantryTypeClass* unit_to_place = InfantryTypes.Ptr(objectIndex);

    if (this_house != NULL && unit_to_place != NULL) {
        InfantryClass* new_unit = (InfantryClass*)unit_to_place->Create_One_Of(this_house);
        if (new_unit != NULL) {

            bool new_unit_placed = false;

            if (new_unit->Unlimbo(coord, DIR_S)) {

                new_unit_placed = true;
            }

            /*
            **	Try to place the object into a nearby cell if something is preventing
            **	placement at the given location.
            */
            if (!new_unit_placed) {
                CELL cell = Map.Nearby_Location(coord, new_unit->Class->Speed);
                if (new_unit->Unlimbo(::Cell_Coord(cell), DIR_S)) {
                    new_unit_placed = true;
                }
            }


            if (new_unit_placed) {
                int _objectIndex = -1;
                MapScriptObject* CacheObject = Scen.mapScript->CreateCacheObject();
                CacheObject->ID = -1;

                _objectIndex = Script_InfantryIndexFromID(new_unit->ID);

                CacheObject->ID = new_unit->ID;
                CacheObject->RTTI = new_unit->RTTI;
                CacheObject->classIndex = _objectIndex;
                Scen.mapScript->ObjectCache.push_back(CacheObject);

                lua_pushnumber(L, CacheObject->UID);
                return 1;
            }
        }
    }

    lua_pushnumber(L, -1);
    return 1;
}

/***********************************************************************************************
 * Script_CreateAircraft - Creates a given Aircraft out of thin air                            *
 *                                                                                             *
 *   SCRIPT INPUT:	objectIndex(int) - The Aircraft type to create                             *
 *                                                                                             *
 *                  houseType  (int) - The player (house) index to create the Aircraft for     *
 *                                                                                             *
 *                  in_x       (int) - X location to create object                             *
 *                                                                                             *
 *                  in_y       (int) - Y location to create object                             *
 *                                                                                             *
 *   SCRIPT OUTPUT:  (int) the cached object ID for use with Mapscript Functions               *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CreateAircraft(lua_State* L) {

    int objectIndex = lua_tointeger(L, 1);
    int houseType = lua_tointeger(L, 2);
    int in_x = lua_tointeger(L, 3);
    int in_y = lua_tointeger(L, 4);

    HouseClass* this_house = Houses.Ptr(houseType);

    AircraftTypeClass* unit_to_place = AircraftTypes.Ptr(objectIndex);

    if (this_house != NULL && unit_to_place != NULL) {
        AircraftClass* new_unit = (AircraftClass*)unit_to_place->Create_One_Of(this_house);
        if (new_unit != NULL) {

            bool new_unit_placed = false;

            if (new_unit->Unlimbo(Cell_Coord(XY_Cell(in_x, in_y)))) {

                new_unit_placed = true;
            }

            /*
            **	Try to place the object into a nearby cell if something is preventing
            **	placement at the given location.
            */
            if (!new_unit_placed) {
                CELL cell = Map.Nearby_Location(Cell_Coord(XY_Cell(in_x, in_y)), new_unit->Class->Speed);
                if (new_unit->Unlimbo(::Cell_Coord(cell))) {
                    new_unit_placed = true;
                }
            }


            if (new_unit_placed) {
                int _objectIndex = -1;
                MapScriptObject* CacheObject = Scen.mapScript->CreateCacheObject();
                CacheObject->ID = -1;

                _objectIndex = Script_AircraftIndexFromID(new_unit->ID);

                CacheObject->ID = new_unit->ID;
                CacheObject->RTTI = new_unit->RTTI;
                CacheObject->classIndex = _objectIndex;
                Scen.mapScript->ObjectCache.push_back(CacheObject);

                lua_pushnumber(L, CacheObject->UID);
                return 1;
            }
        }
    }

    lua_pushnumber(L, -1);
    return 1;
}

/***********************************************************************************************
 * Script_CreateVessel - Creates a given Vessel out of thin air                                *
 *                                                                                             *
 *   SCRIPT INPUT:	objectIndex(int) - The Vessel type to create                               *
 *                                                                                             *
 *                  houseType  (int) - The player (house) index to create the Vessel for       *
 *                                                                                             *
 *                  in_x       (int) - X location to create object                             *
 *                                                                                             *
 *                  in_y       (int) - Y location to create object                             *
 *                                                                                             *
 *   SCRIPT OUTPUT:  (int) the cached object ID for use with Mapscript Functions               *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CreateVessel(lua_State* L) {

    int objectIndex = lua_tointeger(L, 1);
    int houseType = lua_tointeger(L, 2);
    int in_x = lua_tointeger(L, 3);
    int in_y = lua_tointeger(L, 4);

    HouseClass* this_house = Houses.Ptr(houseType);

    VesselTypeClass* unit_to_place = VesselTypes.Ptr(objectIndex);

    if (this_house != NULL && unit_to_place != NULL) {
        VesselClass* new_unit = (VesselClass*)unit_to_place->Create_One_Of(this_house);
        if (new_unit != NULL) {

            bool new_unit_placed = false;

            if (new_unit->Unlimbo(Cell_Coord(XY_Cell(in_x, in_y)))) {

                new_unit_placed = true;
            }

            /*
            **	Try to place the object into a nearby cell if something is preventing
            **	placement at the given location.
            */
            if (!new_unit_placed) {
                CELL cell = Map.Nearby_Location(Cell_Coord(XY_Cell(in_x, in_y)), new_unit->Class->Speed);
                if (new_unit->Unlimbo(::Cell_Coord(cell))) {
                    new_unit_placed = true;
                }
            }


            if (new_unit_placed) {
                int _objectIndex = -1;
                MapScriptObject* CacheObject = Scen.mapScript->CreateCacheObject();
                CacheObject->ID = -1;

                _objectIndex = Script_VesselIndexFromID(new_unit->ID);

                CacheObject->ID = new_unit->ID;
                CacheObject->RTTI = new_unit->RTTI;
                CacheObject->classIndex = _objectIndex;
                Scen.mapScript->ObjectCache.push_back(CacheObject);

                lua_pushnumber(L, CacheObject->UID);
                return 1;
            }
        }
    }

    lua_pushnumber(L, -1);
    return 1;
}


/**********************************************************************************************
* Object Orders Functions                                                                     *
*=============================================================================================*/

/***********************************************************************************************
 * Script_OrderMove - Assigns a movement order to an object                                    *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID   (int) - The object ID (retrieved via MS functions)              *
 *                                                                                             *
 *                  in_x       (int) - X location to move object to                            *
 *                                                                                             *
 *                  in_y       (int) - Y location to move object to                            *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_OrderMove(lua_State* L) {

    int objectID = lua_tointeger(L, 1);
    int in_x = lua_tointeger(L, 2);
    int in_y = lua_tointeger(L, 3);

    ObjectClass* this_object = Script_GetCacheObject(objectID);

    if (this_object != NULL) {

        if (this_object->IsRecentlyCreated) {
            Queue_Mission(TargetClass(this_object), MISSION_QMOVE, 0, As_Target(XY_Cell(in_x, in_y)));
        }

        Queue_Mission(TargetClass(this_object), MISSION_QMOVE, 0, As_Target(XY_Cell(in_x, in_y)));

        lua_pushnumber(L, 1);
        return 1;

    }

    lua_pushnumber(L, -1);
    return 1;

}

/***********************************************************************************************
 * Script_OrderAttackCell - Assigns an attack order to an object for a specific cell           *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID   (int) - The object ID (retrieved via MS functions)              *
 *                                                                                             *
 *                  in_x       (int) - X location to attack                                    *
 *                                                                                             *
 *                  in_y       (int) - Y location to attack                                    *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_OrderAttackCell(lua_State* L) {

    int objectID = lua_tointeger(L, 1);

    int in_x = lua_tointeger(L, 2);
    int in_y = lua_tointeger(L, 3);

    ObjectClass* this_object = Script_GetCacheObject(objectID);

    if (this_object != NULL) {

        TARGET this_target = 0;
        if (in_x >= 0 && in_y >= 0) {
            this_target = As_Target(XY_Cell(in_x, in_y));
        }

        if (this_object->IsRecentlyCreated) {
            Queue_Mission(TargetClass(this_object), MISSION_ATTACK, this_target, this_target);
        }

        Queue_Mission(TargetClass(this_object), MISSION_ATTACK, this_target, this_target);

        lua_pushnumber(L, 1);
        return 1;

    }

    lua_pushnumber(L, -1);
    return 1;

}

/***********************************************************************************************
 * Script_OrderAttack - Assigns an attack order to an object                                   *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID   (int) - The object ID (retrieved via MS functions)              *
 *                                                                                             *
 *                  in_x       (int) - X location to attack                                    *
 *                                                                                             *
 *                  in_y       (int) - Y location to attack                                    *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_OrderAttack(lua_State* L) {

    int objectID = lua_tointeger(L, 1);

    int in_x = -1;
    int in_y = -1;
    if (lua_gettop(L) == 3) {
        in_x = lua_tointeger(L, 2);
        in_y = lua_tointeger(L, 3);
    }

    ObjectClass* this_object = Script_GetCacheObject(objectID);

    if (this_object != NULL) {

        TARGET this_target = 0;
        if (in_x >= 0 && in_y >= 0) {
            this_target = As_Target(XY_Cell(in_x, in_y));
        }

        if (this_object->IsRecentlyCreated) {
            Queue_Mission(TargetClass(this_object), MISSION_ATTACK, 0, this_target);
        }

        Queue_Mission(TargetClass(this_object), MISSION_ATTACK, 0, this_target);

        lua_pushnumber(L, 1);
        return 1;

    }

    lua_pushnumber(L, -1);
    return 1;

}

/***********************************************************************************************
 * Script_OrderHunt - Assigns a hunt order to an object                                        *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID   (int) - The object ID (retrieved via MS functions)              *
 *                                                                                             *
 *                  in_x  (opt)(int) - X location to attack                                    *
 *                                                                                             *
 *                  in_y  (opt)(int) - Y location to attack                                    *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_OrderHunt(lua_State* L) {

    int objectID = lua_tointeger(L, 1);

    int in_x = -1;
    int in_y = -1;
    if (lua_gettop(L) == 3) {
        in_x = lua_tointeger(L, 2);
        in_y = lua_tointeger(L, 3);
    }

    ObjectClass* this_object = Script_GetCacheObject(objectID);

    if (this_object != NULL) {

        TARGET this_target = 0;
        if (in_x >= 0 && in_y >= 0) {
            this_target = As_Target(XY_Cell(in_x, in_y));
        }

        if (this_object->IsRecentlyCreated) {
            Queue_Mission(TargetClass(this_object), MISSION_HUNT, 0, this_target);
        }

        Queue_Mission(TargetClass(this_object), MISSION_HUNT, 0, this_target);

        lua_pushnumber(L, 1);
        return 1;

    }

    lua_pushnumber(L, -1);
    return 1;

}

/***********************************************************************************************
 * Script_OrderGuard - Assigns a guard order to an object                                      *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID   (int) - The object ID (retrieved via MS functions)              *
 *                                                                                             *
 *                  in_x  (opt)(int) - X location to attack                                    *
 *                                                                                             *
 *                  in_y  (opt)(int) - Y location to attack                                    *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_OrderGuard(lua_State* L) {

    int objectID = lua_tointeger(L, 1);

    int in_x = -1;
    int in_y = -1;
    if (lua_gettop(L) == 3) {
        in_x = lua_tointeger(L, 2);
        in_y = lua_tointeger(L, 3);
    }

    ObjectClass* this_object = Script_GetCacheObject(objectID);

    if (this_object != NULL) {

        TARGET this_target = 0;
        if (in_x >= 0 && in_y >= 0) {
            this_target = As_Target(XY_Cell(in_x, in_y));
        }

        if (this_object->IsRecentlyCreated) {
            Queue_Mission(TargetClass(this_object), MISSION_GUARD, 0, this_target);
        }

        Queue_Mission(TargetClass(this_object), MISSION_GUARD, 0, this_target);

        lua_pushnumber(L, 1);
        return 1;

    }

    lua_pushnumber(L, -1);
    return 1;

}

/***********************************************************************************************
 * Script_OrderRetreat - Assigns a retreat order to an object                                  *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID   (int) - The object ID (retrieved via MS functions)              *
 *                                                                                             *
 *                  in_x  (opt)(int) - X location to attack                                    *
 *                                                                                             *
 *                  in_y  (opt)(int) - Y location to attack                                    *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_OrderRetreat(lua_State* L) {

    int objectID = lua_tointeger(L, 1);

    int in_x = -1;
    int in_y = -1;
    if (lua_gettop(L) == 3) {
        in_x = lua_tointeger(L, 2);
        in_y = lua_tointeger(L, 3);
    }

    ObjectClass* this_object = Script_GetCacheObject(objectID);

    if (this_object != NULL) {

        TARGET this_target = 0;
        if (in_x >= 0 && in_y >= 0) {
            this_target = As_Target(XY_Cell(in_x, in_y));
        }

        if (this_object->IsRecentlyCreated) {
            Queue_Mission(TargetClass(this_object), MISSION_RETREAT, 0, this_target);
        }

        Queue_Mission(TargetClass(this_object), MISSION_RETREAT, 0, this_target);

        lua_pushnumber(L, 1);
        return 1;

    }

    lua_pushnumber(L, -1);
    return 1;

}

/***********************************************************************************************
 * Script_OrderEnter - Assigns an enter order to an object                                     *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID   (int) - The object ID (retrieved via MS functions)              *
 *                                                                                             *
 *                  in_x  (opt)(int) - X location to enter (building / unit)                   *
 *                                                                                             *
 *                  in_y  (opt)(int) - Y location to enter (building / unit)                   *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_OrderEnter(lua_State* L) {

    int objectID = lua_tointeger(L, 1);

    int in_x = -1;
    int in_y = -1;
    if (lua_gettop(L) == 3) {
        in_x = lua_tointeger(L, 2);
        in_y = lua_tointeger(L, 3);
    }

    ObjectClass* this_object = Script_GetCacheObject(objectID);

    if (this_object != NULL) {

        TARGET this_target = 0;
        if (in_x >= 0 && in_y >= 0) {
            this_target = As_Target(XY_Cell(in_x, in_y));
        }

        if (this_object->IsRecentlyCreated) {
            Queue_Mission(TargetClass(this_object), MISSION_ENTER, this_target, this_target);
        }

        Queue_Mission(TargetClass(this_object), MISSION_ENTER, this_target, this_target);

        lua_pushnumber(L, 1);
        return 1;

    }

    lua_pushnumber(L, -1);
    return 1;

}

/***********************************************************************************************
 * Script_OrderCapture - Assigns a capture order to an object                                  *
 *                                                                                             *
 *   SCRIPT INPUT:	objectID   (int) - The object ID (retrieved via MS functions)              *
 *                                                                                             *
 *                  in_x  (opt)(int) - X location to capture (building)                        *
 *                                                                                             *
 *                  in_y  (opt)(int) - Y location to capture (building)                        *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_OrderCapture(lua_State* L) {

    int objectID = lua_tointeger(L, 1);

    int in_x = -1;
    int in_y = -1;
    if (lua_gettop(L) == 3) {
        in_x = lua_tointeger(L, 2);
        in_y = lua_tointeger(L, 3);
    }

    ObjectClass* this_object = Script_GetCacheObject(objectID);

    if (this_object != NULL) {

        TARGET this_target = 0;
        if (in_x >= 0 && in_y >= 0) {
            this_target = As_Target(XY_Cell(in_x, in_y));
        }

        if (this_object->IsRecentlyCreated) {
            Queue_Mission(TargetClass(this_object), MISSION_CAPTURE, this_target, this_target);
        }

        Queue_Mission(TargetClass(this_object), MISSION_CAPTURE, this_target, this_target);

        lua_pushnumber(L, 1);
        return 1;

    }

    lua_pushnumber(L, -1);
    return 1;

}

/**********************************************************************************************
* Mission Utility Functions                                                                   *
*=============================================================================================*/

/***********************************************************************************************
 * Script_SetBriefingText - Sets the text on the mission briefing screen                       *
 *                                                                                             *
 *   SCRIPT INPUT:	(char*); The input text                                                    *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_SetBriefingText(lua_State* L) {
    strcpy(Scen.BriefingText, lua_tostring(L, -1));
    return -1;
}

/**********************************************************************************************
* Status / Location Utility Functions                                                         *
*=============================================================================================*/

/***********************************************************************************************
 * Script_GiveCredits - Gives or takes a given amount of credits to / from a player            *
 *                                                                                             *
 *   SCRIPT INPUT:	cashToGive (int) - The amount of cold hard credits to give the player.     *
 *                                     Negative numbers may be used to *take* money            *
 *                                                                                             *
 *                	houseType (int)  - The player (house) index to complete this transaction   *
 *                                     for, or -1 to give to all players                       *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   6/11/2020 - JM Created                                                                    *
 *   6/12/2020 - JJ Added player (house) index input                                           *
 *=============================================================================================*/
static int Script_GiveCredits(lua_State* L) {

    int cashToGive = lua_tointeger(L, 1);

    int houseType = -1;

    // Optional houseType parameter
    if (lua_gettop(L) == 2) {
        houseType = lua_tointeger(L, 2);
    }

    for (int h_index = 0; h_index < Houses.Count(); h_index++) {

        HouseClass* house = Houses.Ptr(h_index);

        if (house->ID == houseType || houseType == -1) {

            if (cashToGive < 0) {
                house->Spend_Money(max(0, cashToGive * -1));
            }
            else {
                house->Refund_Money(cashToGive);
            }

            // Discontinue giving out free cash if a specific house was specified
            if (houseType >= 0) {
                break;
            }
        }

    }

    return 1;
}

/***********************************************************************************************
 * Script_GetCredits - Gets how many credits the given player has                              *
 *                                                                                             *
 *   SCRIPT INPUT:	houseType (int)  - The player (house) index to get credits for             *
 *                                                                                             *
 *   SCRIPT OUTPUT:  result (number) - The amount of credits the player has                    *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_GetCredits(lua_State* L) {

    int houseType = lua_tointeger(L, -1);

    long result = -1;

    for (int h_index = 0; h_index < Houses.Count(); h_index++) {

        HouseClass* house = Houses.Ptr(h_index);

        if (house->ID == houseType || houseType == -1) {
            result = house->Credits;

            break;
        }

    }

    lua_pushnumber(L, result);

    return 1;
}

/***********************************************************************************************
 * Script_CountBuildings - Returns the amount of specific buildings for a player               *
 *                                                                                             *
 *   Optionally, you can return only building at a particular cell or in a rectangular area    *
 *   using the two groups of optional coordinate inputs                                        *
 *                                                                                             *
 *   SCRIPT INPUT:	structType (int) - The structure index to count buildings for              *
 *                                     or -1 for all structures                                *
 *                                                                                             *
 *                	houseType (int)  - The player (house) index to count buildings for         *
 *                	                   or -1 to for all players                                *
 *                                                                                             *
 *                                     NOTE: -1 for either index input acts as ALL             *
 *                                                                                             *
 *                  in_x1 (int) (optional A) - Only include buildings at or beginning at this  *
 *                                             Cell/X location                                 *
 *                                                                                             *
 *                  in_y1 (int) (optional A) - Only include buildings at or beginning at this  *
 *                                             Cell/Y location                                 *
 *                                                                                             *
 *                  in_x2 (int) (optional B) - Only include buildings at or before this Cell/X *
 *                                             location                                        *
 *                                                                                             *
 *                  in_y2 (int) (optional B) - Only include buildings at or before this Cell/Y *
 *                                             location                                        *
 *                                                                                             *
 *   SCRIPT OUTPUT:  result (number) - The amount of matching buildings for that player        *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CountBuildings(lua_State* L) {
    int structType = lua_tointeger(L, 1);

    int houseType = -1;

    // Optional houseType parameter
    if (lua_gettop(L) == 2) {
        houseType = lua_tointeger(L, 2);
    }

    // Optional search area
    bool within_area = false;
    int in_x1, in_x2, in_y1, in_y2;
    if (lua_gettop(L) == 4) {
        in_x1 = lua_tointeger(L, 3);
        in_y1 = lua_tointeger(L, 4);
        in_x2 = in_x1;
        in_y2 = in_y1;
        within_area = true;
    }
    else if (lua_gettop(L) == 6) {
        in_x1 = lua_tointeger(L, 3);
        in_y1 = lua_tointeger(L, 4);
        in_x2 = lua_tointeger(L, 5);
        in_y2 = lua_tointeger(L, 6);
        within_area = true;
    }

    int result = 0;
    for (int b_index = 0; b_index < Buildings.Count(); b_index++) {
        BuildingClass* building = Buildings.Ptr(b_index);

        if (building->Owner() == houseType || houseType == -1) {
            if (building->Class->Type == structType || structType == -1) {

                // Count, in general
                if (within_area == false) {
                    result++;

                    // Within search area
                }
                else {

                    int this_x = Cell_X(Coord_Cell(building->Coord));
                    int this_y = Cell_Y(Coord_Cell(building->Coord));

                    if (this_x >= in_x1 && this_x <= in_x2 && this_y >= in_y1 && this_y <= in_y2) {
                        result++;
                    }
                }

            }
        }
    }

    lua_pushnumber(L, result);
    return 1;
}

/***********************************************************************************************
 * Script_CountAircraft - Returns the amount of specific aircraft for a player                 *
 *                                                                                             *
 *   Optionally, you can return only aircraft at a particular cell or in a rectangular area    *
 *   using the two groups of optional coordinate inputs                                        *
 *                                                                                             *
 *   SCRIPT INPUT:	aircraftType (int) - The aircraft index to count aircraft for              *
 *                                       or -1 for all aircraft                                *
 *                                                                                             *
 *                	houseType (int)    - The player (house) index to count aircraft for        *
 *                                       or -1 for all players                                 *
 *                                                                                             *
 *                                       NOTE: -1 for either index input acts as ALL           *
 *                                                                                             *
 *                  in_x1 (int) (optional A) - Only include aircraft at or beginning at this   *
 *                                             Cell/X location                                 *
 *                                                                                             *
 *                  in_y1 (int) (optional A) - Only include aircraft at or beginning at this   *
 *                                             Cell/Y location                                 *
 *                                                                                             *
 *                  in_x2 (int) (optional B) - Only include aircraft at or before this Cell/X  *
 *                                             location                                        *
 *                                                                                             *
 *                  in_y2 (int) (optional B) - Only include aircraft at or before this Cell/Y  *
 *                                             location                                        *
 *                                                                                             *
 *   SCRIPT OUTPUT:  result (number) - The amount of matching aircraft for that player         *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CountAircraft(lua_State* L) {
    int aircraftType = lua_tointeger(L, 1);

    int houseType = -1;

    // Optional houseType parameter
    if (lua_gettop(L) == 2) {
        houseType = lua_tointeger(L, 2);
    }

    // Optional search area
    bool within_area = false;
    int in_x1, in_x2, in_y1, in_y2;
    if (lua_gettop(L) == 4) {
        in_x1 = lua_tointeger(L, 3);
        in_y1 = lua_tointeger(L, 4);
        in_x2 = in_x1;
        in_y2 = in_y1;
        within_area = true;
    }
    else if (lua_gettop(L) == 6) {
        in_x1 = lua_tointeger(L, 3);
        in_y1 = lua_tointeger(L, 4);
        in_x2 = lua_tointeger(L, 5);
        in_y2 = lua_tointeger(L, 6);
        within_area = true;
    }

    int result = 0;
    for (int a_index = 0; a_index < Aircraft.Count(); a_index++) {
        AircraftClass* aircraft = Aircraft.Ptr(a_index);

        if (aircraft->Owner() == houseType || houseType == -1) {
            if (aircraft->Class->Type == aircraftType || aircraftType == -1) {

                // Count, in general
                if (within_area == false) {
                    result++;

                    // Within search area
                }
                else {

                    int this_x = Cell_X(Coord_Cell(aircraft->Coord));
                    int this_y = Cell_Y(Coord_Cell(aircraft->Coord));

                    if (this_x >= in_x1 && this_x <= in_x2 && this_y >= in_y1 && this_y <= in_y2) {
                        result++;
                    }
                }

            }
        }
    }

    lua_pushnumber(L, result);
    return 1;
}

/***********************************************************************************************
 * Script_CountUnits - Returns the amount of specific units for a player                       *
 *                                                                                             *
 *   Optionally, you can return only units at a particular cell or in a rectangular area       *
 *   using the two groups of optional coordinate inputs                                        *
 *                                                                                             *
 *   SCRIPT INPUT:	unitType (int)  - The unit index to count units for                        *
 *                                    or -1 for all units                                      *
 *                                                                                             *
 *                	houseType (int) - The player (house) index to count units for              *
 *                                    or -1 for all players                                    *
 *                                                                                             *
 *                                    NOTE: -1 for either index input acts as ALL              *
 *                                                                                             *
 *                  in_x1 (int) (optional A) - Only include units at or beginning at this      *
 *                                             Cell/X location                                 *
 *                                                                                             *
 *                  in_y1 (int) (optional A) - Only include units at or beginning at this      *
 *                                             Cell/Y location                                 *
 *                                                                                             *
 *                  in_x2 (int) (optional B) - Only include units at or before this Cell/X     *
 *                                             location                                        *
 *                                                                                             *
 *                  in_y2 (int) (optional B) - Only include units at or before this Cell/Y     *
 *                                             location                                        *
 *                                                                                             *
 *   SCRIPT OUTPUT:  result (number) - The amount of matching units for that player            *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CountUnits(lua_State* L) {
    int unitType = lua_tointeger(L, 1);

    int houseType = -1;

    // Optional houseType parameter
    if (lua_gettop(L) == 2) {
        houseType = lua_tointeger(L, 2);
    }

    // Optional search area
    bool within_area = false;
    int in_x1, in_x2, in_y1, in_y2;
    if (lua_gettop(L) == 4) {
        in_x1 = lua_tointeger(L, 3);
        in_y1 = lua_tointeger(L, 4);
        in_x2 = in_x1;
        in_y2 = in_y1;
        within_area = true;
    }
    else if (lua_gettop(L) == 6) {
        in_x1 = lua_tointeger(L, 3);
        in_y1 = lua_tointeger(L, 4);
        in_x2 = lua_tointeger(L, 5);
        in_y2 = lua_tointeger(L, 6);
        within_area = true;
    }

    int result = 0;
    for (int u_index = 0; u_index < Units.Count(); u_index++) {
        UnitClass* unit = Units.Ptr(u_index);

        if (unit->Owner() == houseType || houseType == -1) {
            if (unit->Class->Type == unitType || unitType == -1) {

                // Count, in general
                if (within_area == false) {
                    result++;

                    // Within search area
                }
                else {

                    int this_x = Cell_X(Coord_Cell(unit->Coord));
                    int this_y = Cell_Y(Coord_Cell(unit->Coord));

                    if (this_x >= in_x1 && this_x <= in_x2 && this_y >= in_y1 && this_y <= in_y2) {
                        result++;
                    }
                }

            }
        }
    }

    lua_pushnumber(L, result);
    return 1;
}

/***********************************************************************************************
 * Script_CountInfantry - Returns the amount of specific infantry for a player                 *
 *                                                                                             *
 *   Optionally, you can return only infantry at a particular cell or in a rectangular area    *
 *   using the two groups of optional coordinate inputs                                        *
 *                                                                                             *
 *   SCRIPT INPUT:	infantryType (int) - The infantry index to count infantry for              *
 *                                       or -1 for all infantry                                *
 *                                                                                             *
 *                	houseType (int)    - The player (house) index to count infantry for        *
 *                                       or -1 for all players                                 *
 *                                                                                             *
 *                                       NOTE: -1 for either index input acts as ALL           *
 *                                                                                             *
 *                  in_x1 (int) (optional A) - Only include infantry at or beginning at this   *
 *                                             Cell/X location                                 *
 *                                                                                             *
 *                  in_y1 (int) (optional A) - Only include infantry at or beginning at this   *
 *                                             Cell/Y location                                 *
 *                                                                                             *
 *                  in_x2 (int) (optional B) - Only include infantry at or before this Cell/X  *
 *                                             location                                        *
 *                                                                                             *
 *                  in_y2 (int) (optional B) - Only include infantry at or before this Cell/Y  *
 *                                             location                                        *
 *                                                                                             *
 *   SCRIPT OUTPUT:  result (number) - The amount of matching infantry for that player         *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CountInfantry(lua_State* L) {
    int infantryType = lua_tointeger(L, 1);

    int houseType = -1;

    // Optional houseType parameter
    if (lua_gettop(L) == 2) {
        houseType = lua_tointeger(L, 2);
    }

    // Optional search area
    bool within_area = false;
    int in_x1, in_x2, in_y1, in_y2;
    if (lua_gettop(L) == 4) {
        in_x1 = lua_tointeger(L, 3);
        in_y1 = lua_tointeger(L, 4);
        in_x2 = in_x1;
        in_y2 = in_y1;
        within_area = true;
    }
    else if (lua_gettop(L) == 6) {
        in_x1 = lua_tointeger(L, 3);
        in_y1 = lua_tointeger(L, 4);
        in_x2 = lua_tointeger(L, 5);
        in_y2 = lua_tointeger(L, 6);
        within_area = true;
    }

    int result = 0;
    for (int u_index = 0; u_index < Infantry.Count(); u_index++) {
        InfantryClass* infantry = Infantry.Ptr(u_index);

        if (infantry->Owner() == houseType || houseType == -1) {
            if (infantry->Class->Type == infantryType || infantryType == -1) {

                // Count, in general
                if (within_area == false) {
                    result++;

                    // Within search area
                }
                else {

                    int this_x = Cell_X(Coord_Cell(infantry->Coord));
                    int this_y = Cell_Y(Coord_Cell(infantry->Coord));

                    if (this_x >= in_x1 && this_x <= in_x2 && this_y >= in_y1 && this_y <= in_y2) {
                        result++;
                    }
                }

            }
        }
    }

    lua_pushnumber(L, result);
    return 1;
}

/***********************************************************************************************
 * Script_CountVessels - Returns the amount of specific vessels for a player                   *
 *                                                                                             *
 *   Optionally, you can return only vessels at a particular cell or in a rectangular area     *
 *   using the two groups of optional coordinate inputs                                        *
 *                                                                                             *
 *   SCRIPT INPUT:	vesselType (int) - The vessel index to count vessels for                   *
 *                                     or -1 for all vessels                                   *
 *                                                                                             *
 *                	houseType (int)  - The player (house) index to count vessels for           *
 *                                     or -1 for all players                                   *
 *                                                                                             *
 *                                     NOTE: -1 for either index input acts as ALL             *
 *                                                                                             *
 *                  in_x1 (int) (optional A) - Only include vessels at or beginning at this    *
 *                                             Cell/X location                                 *
 *                                                                                             *
 *                  in_y1 (int) (optional A) - Only include vessels at or beginning at this    *
 *                                             Cell/Y location                                 *
 *                                                                                             *
 *                  in_x2 (int) (optional B) - Only include vessels at or before this Cell/X   *
 *                                             location                                        *
 *                                                                                             *
 *                  in_y2 (int) (optional B) - Only include vessels at or before this Cell/X   *
 *                                             location                                        *
 *                                                                                             *
 *   SCRIPT OUTPUT:  result (number) - The amount of matching vessels for that player          *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_CountVessels(lua_State* L) {
    int vesselType = lua_tointeger(L, 1);

    int houseType = -1;

    // Optional houseType parameter
    if (lua_gettop(L) == 2) {
        houseType = lua_tointeger(L, 2);
    }

    // Optional search area
    bool within_area = false;
    int in_x1, in_x2, in_y1, in_y2;
    if (lua_gettop(L) == 4) {
        in_x1 = lua_tointeger(L, 3);
        in_y1 = lua_tointeger(L, 4);
        in_x2 = in_x1;
        in_y2 = in_y1;
        within_area = true;
    }
    else if (lua_gettop(L) == 6) {
        in_x1 = lua_tointeger(L, 3);
        in_y1 = lua_tointeger(L, 4);
        in_x2 = lua_tointeger(L, 5);
        in_y2 = lua_tointeger(L, 6);
        within_area = true;
    }

    int result = 0;
    for (int u_index = 0; u_index < Vessels.Count(); u_index++) {
        VesselClass* vessel = Vessels.Ptr(u_index);

        if (vessel->Owner() == houseType || houseType == -1) {
            if (vessel->Class->Type == vesselType || vesselType == -1) {

                // Count, in general
                if (within_area == false) {
                    result++;

                    // Within search area
                }
                else {

                    int this_x = Cell_X(Coord_Cell(vessel->Coord));
                    int this_y = Cell_Y(Coord_Cell(vessel->Coord));

                    if (this_x >= in_x1 && this_x <= in_x2 && this_y >= in_y1 && this_y <= in_y2) {
                        result++;
                    }
                }

            }
        }
    }

    lua_pushnumber(L, result);
    return 1;
}

/***********************************************************************************************
 * Script_GetWaypointX - Gets the Cell/X Coordinate of Waypoint                                *
 *                                                                                             *
 *   SCRIPT INPUT:	waypointIndex (int) - The waypoint's index to grab the X coordinate for    *
 *                                                                                             *
 *   SCRIPT OUTPUT:  outX (int) - The Cell/X coordinate of the waypoint                        *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_GetWaypointX(lua_State* L) {

    int ret = lua_tointeger(L, -1);

    if (ret > 0 && ret < sizeof(Scen.Waypoint)) {

        lua_pushnumber(L, Cell_X(Scen.Waypoint[ret]));

        return 1;

    }

    lua_pushnumber(L, -1);

    return -1;
}

/***********************************************************************************************
 * Script_GetWaypointY - Gets the Cell/Y Coordinate of Waypoint                                *
 *                                                                                             *
 *   SCRIPT INPUT:	waypointIndex (int) - The waypoint's index to grab the Y coordinate for    *
 *                                                                                             *
 *   SCRIPT OUTPUT:  outX (int) - The Cell/Y coordinate of the waypoint                        *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_GetWaypointY(lua_State* L) {

    int ret = lua_tointeger(L, -1);

    if (ret > 0 && ret < sizeof(Scen.Waypoint)) {

        lua_pushnumber(L, Cell_Y(Scen.Waypoint[ret]));

        return 1;

    }

    lua_pushnumber(L, -1);

    return -1;
}

/**********************************************************************************************
* Special / Debug Functions                                                                   *
*=============================================================================================*/

/***********************************************************************************************
 * Script_Console_Print - Prints text to the console                                           *
 *                                                                                             *
 *   SCRIPT INPUT:	inputText (string) - The text to print to the console                      *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * INPUT:  lua_State - The current Lua state                                                   *
 *                                                                                             *
 * OUTPUT:  int; Did the function run successfully? Return 1                                   *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
static int Script_Console_Print(lua_State* L) {

    const char* inputText = lua_tostring(L, -1); // grab path string from top of stack

    Console_Printf(inputText);

    return -1;
}


/**********************************************************************************************
* MapScript Internal Functions                                                                *
*=============================================================================================*/

/***********************************************************************************************
 * MapScript::GetCacheObject -- Returns ObjectClass from cache with given ID                   *
 *                                                                                             *
 * INPUT:  input_object_id (int)         - Input object ID                                     *
 *                                                                                             *
 * OUTPUT:  this_object (ObjectClass*)   - The object with the ID or NULL                      *
 *                                                                                             *
 * WARNINGS:  none                                                                             *
 *                                                                                             *
 *=============================================================================================*/
ObjectClass* Script_GetCacheObject(int input_object_id) {

    if (input_object_id < 0) {
        return false;
    }

    // Look through cache for object with ID, and return it
    for (std::vector<MapScriptObject*>::iterator it = Scen.mapScript->ObjectCache.begin(); it != Scen.mapScript->ObjectCache.end(); ++it) {//Error 2-4

        MapScriptObject* thisCacheObject = (MapScriptObject*)(*it);

        // Here it is
        if (thisCacheObject->UID == input_object_id) {

            // Determine type of object and return it from cache. If it doesn't exist any longer, remove it from cache
            switch (thisCacheObject->RTTI) {
            case RTTI_BUILDING: {
                BuildingClass* this_building = Buildings.Ptr(thisCacheObject->classIndex);
                if (this_building != NULL) {
                    return this_building;
                }
                else {
                    it = Scen.mapScript->ObjectCache.erase(it); // Cache item exists but is invalidated; remove from cache
                    return NULL;
                }
            }break;
            case RTTI_UNIT: {
                UnitClass* this_unit = Units.Ptr(thisCacheObject->classIndex);
                if (this_unit != NULL) {
                    return this_unit;
                }
                else {
                    it = Scen.mapScript->ObjectCache.erase(it); // Cache item exists but is invalidated; remove from cache
                    return NULL;
                }
            }break;
            case RTTI_AIRCRAFT: {
                AircraftClass* this_aircraft = Aircraft.Ptr(thisCacheObject->classIndex);
                if (this_aircraft != NULL) {
                    return this_aircraft;
                }
                else {
                    it = Scen.mapScript->ObjectCache.erase(it); // Cache item exists but is invalidated; remove from cache
                    return NULL;
                }
            }break;
            case RTTI_INFANTRY: {
                InfantryClass* this_infantry = Infantry.Ptr(thisCacheObject->classIndex);
                if (this_infantry != NULL) {
                    return this_infantry;
                }
                else {
                    it = Scen.mapScript->ObjectCache.erase(it); // Cache item exists but is invalidated; remove from cache
                    return NULL;
                }
            }break;
            case RTTI_VESSEL: {
                VesselClass* this_vessel = Vessels.Ptr(thisCacheObject->classIndex);
                if (this_vessel != NULL) {
                    return this_vessel;
                }
                else {
                    it = Scen.mapScript->ObjectCache.erase(it); // Cache item exists but is invalidated; remove from cache
                    return NULL;
                }
            }break;
            }

        }

    }

    // Not found in cache; let's find the object by ID the hard way... If scripting is done well, this doesn't get hit
    int _objectIndex = -1;
    MapScriptObject* CacheObject = Scen.mapScript->CreateCacheObject();
    CacheObject->ID = -1;

    _objectIndex = Script_BuildingIndexFromID(input_object_id);
    BuildingClass* this_building = Buildings.Ptr(_objectIndex);
    if (this_building != NULL) {

        CacheObject->ID = this_building->ID;
        CacheObject->RTTI = this_building->RTTI;
        CacheObject->classIndex = _objectIndex;
        Scen.mapScript->ObjectCache.push_back(CacheObject);

        return this_building;

    }
    else {
        _objectIndex = Script_UnitIndexFromID(input_object_id);
        UnitClass* this_unit = Units.Ptr(_objectIndex);
        if (this_unit != NULL) {

            CacheObject->ID = this_unit->ID;
            CacheObject->RTTI = this_unit->RTTI;
            CacheObject->classIndex = _objectIndex;
            Scen.mapScript->ObjectCache.push_back(CacheObject);

            return this_unit;

        }
        else {
            _objectIndex = Script_AircraftIndexFromID(input_object_id);
            AircraftClass* this_aircraft = Aircraft.Ptr(_objectIndex);
            if (this_aircraft != NULL) {

                CacheObject->ID = this_aircraft->ID;
                CacheObject->RTTI = this_aircraft->RTTI;
                CacheObject->classIndex = _objectIndex;
                Scen.mapScript->ObjectCache.push_back(CacheObject);

                return this_aircraft;

            }
            else {
                _objectIndex = Script_VesselIndexFromID(input_object_id);
                VesselClass* this_vessel = Vessels.Ptr(_objectIndex);
                if (this_vessel != NULL) {

                    CacheObject->ID = this_vessel->ID;
                    CacheObject->RTTI = this_vessel->RTTI;
                    CacheObject->classIndex = _objectIndex;
                    Scen.mapScript->ObjectCache.push_back(CacheObject);

                    return this_vessel;

                }
                else {
                    _objectIndex = Script_InfantryIndexFromID(input_object_id);
                    InfantryClass* this_infantry = Infantry.Ptr(_objectIndex);
                    if (this_infantry != NULL) {

                        CacheObject->ID = this_infantry->ID;
                        CacheObject->RTTI = this_infantry->RTTI;
                        CacheObject->classIndex = _objectIndex;
                        Scen.mapScript->ObjectCache.push_back(CacheObject);

                        return this_infantry;

                    }
                }
            }
        }
    }

    // Looks like we didn't find anything. They probably shouldn't have gotten this far in the first place so it was worth a try.
    delete CacheObject;

    return NULL;
}

/***********************************************************************************************
 * Script_SetObjectTrigger -- Figures out what kind of object is given and sets up trigger     *
 *                                                                                             *
 * INPUT:  input_object (ObjectClass*)   - Input object                                        *
 *         input_trigger (TriggerClass*) - Input Trigger                                       *
 *                                                                                             *
 * OUTPUT:  bool; Was the object found? Does the trigger exist?                                *
 *                                                                                             *
 * WARNINGS:  none                                                                             *
 *                                                                                             *
 *=============================================================================================*/
bool Script_SetObjectTrigger(int input_object_id, TriggerClass* input_trigger) {

    if (input_object_id < 0) {
        return false;
    }

    if (input_trigger == NULL) {
        return false;
    }

    ObjectClass* this_object = Script_GetCacheObject(input_object_id);

    if (this_object != NULL) {

        switch (this_object->RTTI) {
        case RTTI_BUILDING: {
            input_trigger->Class->Event1.Data.Structure = dynamic_cast<BuildingClass*>(this_object)->Class->Type;
            dynamic_cast<BuildingClass*>(this_object)->Trigger = input_trigger;
        }break;
        case RTTI_UNIT: {
            input_trigger->Class->Event1.Data.Unit = dynamic_cast<UnitClass*>(this_object)->Class->Type;
            dynamic_cast<UnitClass*>(this_object)->Trigger = input_trigger;
        }break;
        case RTTI_AIRCRAFT: {
            input_trigger->Class->Event1.Data.Aircraft = dynamic_cast<AircraftClass*>(this_object)->Class->Type;
            dynamic_cast<AircraftClass*>(this_object)->Trigger = input_trigger;
        }break;
        case RTTI_INFANTRY: {
            input_trigger->Class->Event1.Data.Infantry = dynamic_cast<InfantryClass*>(this_object)->Class->Type;
            dynamic_cast<InfantryClass*>(this_object)->Trigger = input_trigger;
        }break;
        }

    }

    return false;
}

/***********************************************************************************************
 * Script_BuildingIndexFromID -- Returns BuildingClass or NULL depending on the input               *
 *                                                                                             *
 * INPUT:  input_object_id (int)   - Input object ID                                           *
 *                                                                                             *
 * OUTPUT:  bool; Was the object found? Does the trigger exist?                                *
 *                                                                                             *
 * WARNINGS:  none                                                                             *
 *                                                                                             *
 *=============================================================================================*/
int Script_BuildingIndexFromID(int input_object_id) {

    if (input_object_id < 0) {
        return false;
    }

    for (int _index = 0; _index < Buildings.Count(); _index++) {
        BuildingClass* _object = Buildings.Ptr(_index);

        if (_object->ID == input_object_id) {
            return _index;
        }
    }

    return -1;
}

/***********************************************************************************************
 * Script_UnitIndexFromID -- Returns UnitClass* or NULL depending on the input                      *
 *                                                                                             *
 * INPUT:  input_unit_id (int)   - Input Unit ID                                               *
 *                                                                                             *
 * OUTPUT:  bool; Was the object found? Does the trigger exist?                                *
 *                                                                                             *
 * WARNINGS:  none                                                                             *
 *                                                                                             *
 *=============================================================================================*/
int Script_UnitIndexFromID(int input_object_id) {

    if (input_object_id < 0) {
        return false;
    }

    for (int _index = 0; _index < Units.Count(); _index++) {
        UnitClass* _object = Units.Ptr(_index);

        if (_object->ID == input_object_id) {
            return _index;
        }
    }

    return -1;
}

/***********************************************************************************************
 * Script_AircraftIndexFromID -- Returns AircraftClass* or NULL depending on the input              *
 *                                                                                             *
 * INPUT:  input_object_id (int)   - Input object ID                                           *
 *                                                                                             *
 * OUTPUT:  bool; Was the object found? Does the trigger exist?                                *
 *                                                                                             *
 * WARNINGS:  none                                                                             *
 *                                                                                             *
 *=============================================================================================*/
int Script_AircraftIndexFromID(int input_object_id) {

    if (input_object_id < 0) {
        return false;
    }

    for (int _index = 0; _index < Aircraft.Count(); _index++) {
        AircraftClass* _object = Aircraft.Ptr(_index);

        if (_object->ID == input_object_id) {
            return _index;
        }
    }

    return -1;
}

/***********************************************************************************************
 * Script_InfantryIndexFromID -- Returns InfantryClass* or NULL depending on the input              *
 *                                                                                             *
 * INPUT:  input_unit_id (int)   - Input Infantry ID                                           *
 *                                                                                             *
 * OUTPUT:  bool; Was the object found? Does the trigger exist?                                *
 *                                                                                             *
 * WARNINGS:  none                                                                             *
 *                                                                                             *
 *=============================================================================================*/
int Script_InfantryIndexFromID(int input_object_id) {

    if (input_object_id < 0) {
        return false;
    }

    for (int _index = 0; _index < Infantry.Count(); _index++) {
        InfantryClass* _object = Infantry.Ptr(_index);

        if (_object->ID == input_object_id) {
            return _index;
        }
    }

    return -1;
}

/***********************************************************************************************
 * Script_VesselIndexFromID -- Returns VesselClass* or NULL depending on the input                  *
 *                                                                                             *
 * INPUT:  input_unit_id (int)   - Input vessel ID                                             *
 *                                                                                             *
 * OUTPUT:  bool; Was the object found? Does the trigger exist?                                *
 *                                                                                             *
 * WARNINGS:  none                                                                             *
 *                                                                                             *
 *=============================================================================================*/
int Script_VesselIndexFromID(int input_object_id) {

    if (input_object_id < 0) {
        return false;
    }

    for (int _index = 0; _index < Vessels.Count(); _index++) {
        VesselClass* _object = Vessels.Ptr(_index);

        if (_object->ID == input_object_id) {
            return _index;
        }
    }

    return -1;
}

/***********************************************************************************************
 * Script_CacheDefaultAttribute - Caches an attribute value upon first usage for restoration   *
 *                                                                                             *
 *   SCRIPT INPUT:	input_rtti (RTTIType) - The RTTI type for the attrtibute                   *
 *                	input_id   (int)      - The ID of the typeclass                            *
 *                	input_attribute (int) - The attribute to cache                             *
 *                	input_value (int)     - The value if the cache item doesn't exist          *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
void Script_CacheDefaultObjectTypeAttribute(RTTIType input_rtti, int input_id, MapScriptObjectAttributeType input_attribute, int input_value) {

    bool cache_item_found = false;
    for (std::vector<MapScriptDefaultObjectAttribute*>::iterator it = Scen.mapScript->DefaultObjectTypeAttributeCache.begin(); it != Scen.mapScript->DefaultObjectTypeAttributeCache.end(); ++it) {//Error 2-4

        MapScriptDefaultObjectAttribute* cachedAttribute = (MapScriptDefaultObjectAttribute*)(*it);

        if (input_rtti == cachedAttribute->RTTI && input_id == cachedAttribute->ID && input_attribute == cachedAttribute->attribute) {
            cache_item_found = true;
            break;
        }

    }

    // Cached attribute does not exist; let's cache!
    if (!cache_item_found) {

        MapScriptDefaultObjectAttribute* cachedAttribute = new MapScriptDefaultObjectAttribute;
        cachedAttribute->RTTI = input_rtti;
        cachedAttribute->ID = input_id;
        cachedAttribute->attribute = input_attribute;
        cachedAttribute->value = input_value;
        Scen.mapScript->DefaultObjectTypeAttributeCache.push_back(cachedAttribute);

    }

}

/***********************************************************************************************
 * MapScript::CallFunction - Calls a given function within the current script                  *
 *                                                                                             *
 * INPUT:  functionName - The name of the function to call                                     *
 *                                                                                             *
 * OUTPUT:  void                                                                               *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
void MapScript::CallFunction(const char* functionName) {

    lua_getglobal(L, functionName);
    lua_pcall(L, 0, 0, 0);

}

/***********************************************************************************************
 * MapScript::setLuaPath - Sets Lua's path / extensions to search for scripts                  *
 *                                                                                             *
 *   This helps Lua know where/how to look for files when using require(), otherwise we could  *
 *   hard code path/extension as we did previously                                             *
 *                                                                                             *
 * INPUT:  pathvalue - See lua documentation RE: LUA_PATH to know how to deal with this        *
 *                                                                                             *
 * OUTPUT:  void                                                                               *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
void MapScript::SetLuaPath(const char* input_path)
{

    // Needs space to keep the initial paths
    char new_path[1024];

    // Set new GLOBALS.package.path
    lua_getglobal(L, "package");
    lua_getfield(L, -1, "path"); // get field "path" from table at top of stack (-1)
    const char* cur_path = lua_tostring(L, -1); // grab path string from top of stack

    sprintf(new_path, "%s;%s", cur_path, input_path);

    lua_pop(L, 1);
    lua_pushstring(L, new_path);
    lua_setfield(L, -2, "path");
    lua_pop(L, 1);
}

/***********************************************************************************************
 * MapScript::CreateCacheObject -- Initializes a cached object for a new cache entry           *
 *                                                                                             *
 * INPUT:  mapName - The script path                                                           *
 *                                                                                             *
 * OUTPUT:  bool; did the map script load and initialize?                                      *
 *                                                                                             *
 * WARNINGS:  none                                                                             *
 *                                                                                             *
 *=============================================================================================*/
MapScriptObject* MapScript::CreateCacheObject() {

    MapScriptObject* CacheObject = new MapScriptObject;

    cUID++;
    CacheObject->UID = cUID;

    return CacheObject;

}

/***********************************************************************************************
 * MapScript::Deinit - Deinitialize/free any data used by MapScript (used within destructor)   *
 *                                                                                             *
 *   SCRIPT INPUT:	none                                                                       *
 *                                                                                             *
 *   SCRIPT OUTPUT:  void                                                                      *
 *                                                                                             *
 * WARNINGS:  ?                                                                                *
 *                                                                                             *
 *=============================================================================================*/
void MapScript::Deinit() {

    // Remove any cached objects
    for (int i = 0; i < ObjectCache.size(); ++i)
    {
        delete ObjectCache[i];
    }

    ObjectCache.clear();

    // We will now restore any default Object attributes that were changed in the script
    for (std::vector<MapScriptDefaultObjectAttribute*>::iterator it = DefaultObjectTypeAttributeCache.begin(); it != DefaultObjectTypeAttributeCache.end(); ++it) {//Error 2-4

        MapScriptDefaultObjectAttribute* cachedAttribute = (MapScriptDefaultObjectAttribute*)(*it);

        switch (cachedAttribute->RTTI) {

        case RTTI_BUILDINGTYPE: {
            lua_getglobal(L, "SetBuildingTypeAttribute");
            lua_pushnumber(L, cachedAttribute->ID);
            lua_pushnumber(L, cachedAttribute->attribute);
            lua_pushnumber(L, cachedAttribute->value);
            lua_pcall(L, 3, 1, 0);
        }break;
        case RTTI_UNITTYPE: {
            lua_getglobal(L, "SetUnitTypeAttribute");
            lua_pushnumber(L, cachedAttribute->ID);
            lua_pushnumber(L, cachedAttribute->attribute);
            lua_pushnumber(L, cachedAttribute->value);
            lua_pcall(L, 3, 1, 0);
        }break;
        case RTTI_INFANTRYTYPE: {
            lua_getglobal(L, "SetInfantryTypeAttribute");
            lua_pushnumber(L, cachedAttribute->ID);
            lua_pushnumber(L, cachedAttribute->attribute);
            lua_pushnumber(L, cachedAttribute->value);
            lua_pcall(L, 3, 1, 0);
        }break;
        case RTTI_AIRCRAFTTYPE: {
            lua_getglobal(L, "SetAircraftTypeAttribute");
            lua_pushnumber(L, cachedAttribute->ID);
            lua_pushnumber(L, cachedAttribute->attribute);
            lua_pushnumber(L, cachedAttribute->value);
            lua_pcall(L, 3, 1, 0);
        }break;
        case RTTI_VESSELTYPE: {
            lua_getglobal(L, "SetVesselTypeAttribute");
            lua_pushnumber(L, cachedAttribute->ID);
            lua_pushnumber(L, cachedAttribute->attribute);
            lua_pushnumber(L, cachedAttribute->value);
            lua_pcall(L, 3, 1, 0);
        }break;

        }

    }

    // Remove any cached Object Attributes
    for (int i = 0; i < DefaultObjectTypeAttributeCache.size(); ++i)
    {
        delete DefaultObjectTypeAttributeCache[i];
    }

    DefaultObjectTypeAttributeCache.clear();


    for (int index = 0; index < Warheads.Count(); index++) {
        Warheads.Ptr(index)->Read_INI(RuleINI);
    }

    for (int proj = 0; proj < BulletTypes.Count(); proj++) {
        BulletTypes.Ptr(proj)->Read_INI(RuleINI);
    }

    for (int windex = 0; windex < Weapons.Count(); windex++) {
        Weapons.Ptr(windex)->Read_INI(RuleINI);
    }

    for (int uindex = 0; uindex < UnitTypes.Count(); uindex++) {
        UnitTypes.Ptr(uindex)->Read_INI(RuleINI);
    }

    for (int iindex = 0; iindex < InfantryTypes.Count(); iindex++) {
        InfantryTypes.Ptr(iindex)->Read_INI(RuleINI);
    }

    for (int vindex = 0; vindex < VesselTypes.Count(); vindex++) {
        VesselTypes.Ptr(vindex)->Read_INI(RuleINI);
    }

    for (int aindex = 0; aindex < AircraftTypes.Count(); aindex++) {
        AircraftTypes.Ptr(aindex)->Read_INI(RuleINI);
    }

    for (int bindex = 0; bindex < BuildingTypes.Count(); bindex++) {
        BuildingTypes.Ptr(bindex)->Read_INI(RuleINI);
    }

}


/***********************************************************************************************
 * MapScript::Init -- Loads and initializes script for a given map                             *
 *                                                                                             *
 *    This routine is called at the beginning of a mission                                     *
 *                                                                                             *
 * INPUT:  mapName - The script path                                                           *
 *                                                                                             *
 * OUTPUT:  bool; did the map script load and initialize?                                      *
 *                                                                                             *
 * WARNINGS:  none                                                                             *
 *                                                                                             *
 *=============================================================================================*/
bool MapScript::Init(const char* mapName) {

    this->cUID = 0;

    char scriptName[256];

    // Build map path
    sprintf(scriptName, "scripts/%s.script", mapName);
    L = luaL_newstate();

    luaL_openlibs(L);

    // Load file
    if (luaL_loadfile(L, scriptName)) {
        Console_Printf(lua_tostring(L, -1));
        L = NULL;
        return false;
    }

    // TODO: I've tried several combinations of paths (including "scripts/?"), 
    // but I can only get "require 'basefilename'" to work within a 
    // script, not "require 'basefilename.script'". This may be completely 
    // normal within lua, but it seems odd.

    // This allows require() to work
    SetLuaPath(";scripts/?.script;");

    if (lua_pcall(L, 0, 0, 0)) {
        Console_Printf(lua_tostring(L, -1));
        L = NULL;
        return false;
    }

    // Reserve object cache memory
    ObjectCache.reserve(2000);

    // Reserve type attribute cache memory (to restore rules after script)
    DefaultObjectTypeAttributeCache.reserve(1000);

    /**********************************************************************************************
    * Red Alert Vanilla Actions                                                                   *
    *=============================================================================================*/

    lua_register(L, "Win", Script_Win);                                             // player wins!
    lua_register(L, "Lose", Script_Lose);                                           // player loses.
    lua_register(L, "BeginProduction", Script_BeginProduction);                     // computer begins factory production.
    lua_register(L, "CreateTeam", Script_CreateTeam);                               // computer creates a certain type of team
    lua_register(L, "DestroyTeam", Script_DestroyTeam);                             // destroy team (comment was redacted. was something offensive originally written?)
    lua_register(L, "AllHunt", Script_AllHunt);                                     // all enemy units go into hunt mode (teams destroyed).
    lua_register(L, "Reinforcements", Script_Reinforcements);                       // player gets reinforcements (house that gets them is determined by the Reinforcement instance)
    lua_register(L, "DropZoneFlare", Script_DropZoneFlare);                         // Deploy drop zone smoke.
    lua_register(L, "FireSale", Script_FireSale);	                                // Sell all buildings and go on rampage.
    lua_register(L, "PlayMovie", Script_PlayMovie);							        // Play movie (temporarily suspend game).
    lua_register(L, "TriggerText", Script_TriggerText);                             // Triggers a text message display.
    lua_register(L, "DestroyTrigger", Script_DestroyTrigger);                       // Destroy specified trigger.
    lua_register(L, "AutoCreate", Script_AutoCreate);                               // Computer to autocreate teams.
    // Win if captured, lose if destroyed                                           // function does not exist
    lua_register(L, "AllowWin", Script_AllowWin);                                   // Allows winning if triggered.
    lua_register(L, "RevealAll", Script_RevealAll);                                 // Reveal the entire map.
    lua_register(L, "RevealCell", Script_RevealCell);                               // Reveal map around cell #.
    lua_register(L, "RevealZone", Script_RevealZone);                               // Reveal all of specified zone.
    lua_register(L, "PlaySound", Script_PlaySound);                                 // Play sound effect.
    lua_register(L, "PlayMusic", Script_PlayMusic);                                 // Play musical score.
    lua_register(L, "PlaySpeech", Script_PlaySpeech);						        // Play EVA speech.
        // TODO: Force trigger to activate.
    lua_register(L, "StartMissionTimer", Script_StartMissionTimer);			        // Start mission timer.
    lua_register(L, "StopMissionTimer", Script_StopMissionTimer);			        // Stop mission timer.
    lua_register(L, "IncreaseMissionTimer", Script_IncreaseMissionTimer);           // Increase mission timer time.
    lua_register(L, "DecreaseMissionTimer", Script_DecreaseMissionTimer);           // Decrease mission timer time.
    lua_register(L, "SetMissionTimer", Script_SetMissionTimer);                     // Set and start the mission timer.
    lua_register(L, "SetGlobalValue", Script_SetGlobalValue);	                    // Set global variable.
    lua_register(L, "ClearGlobalValue", Script_ClearGlobalValue);                   // Clear global variable.
    lua_register(L, "AutoBaseBuilding", Script_AutoBaseBuilding);                   // Automated base building.
    lua_register(L, "CreepShadow", Script_CreepShadow);                             // Shadow grows back one 'step'.
    lua_register(L, "DestroyTriggerBuilding", Script_DestroyTriggerBuilding);       // Destroys the building this trigger is attached to. (in the case of scripging, we can supply the trigger)
    lua_register(L, "GiveOneTimeSpecialWeapon", Script_GiveOneTimeSpecialWeapon);   // Add a one-time special weapon ability to house.
    lua_register(L, "GiveSpecialWeapon", Script_GiveSpecialWeapon);                 // Add a repeating special weapon ability to house.
    lua_register(L, "DesignatePreferredTarget", Script_DesignatePreferredTarget);   // Designates preferred target for house.
    lua_register(L, "LaunchFakeNukes", Script_LaunchFakeNukes);                     // Launch fake nuclear missiles from all silos

/**********************************************************************************************
* Red Alert Vanilla Events                                                                    *
*=============================================================================================*/

    lua_register(L, "CellCallback", Script_CellCallback);                                   // player enters this square (or group of squares)
    lua_register(L, "SpiedByCallback", Script_SpiedByCallback);                             // Spied by.
    // Thieved by (raided or stolen vehicle).                                               // This doesn't appear to be implemented in the engine (?)
    lua_register(L, "ObjectDiscoveryCallback", Script_ObjectDiscoveryCallback);             // player discovers this object
    lua_register(L, "HouseDiscoveredCallback", Script_HouseDiscoveredCallback);             // House has been discovered.
    lua_register(L, "ObjectAttackedCallback", Script_ObjectAttackedCallback);               // player attacks this object
    lua_register(L, "ObjectDestroyedCallback", Script_ObjectDestroyedCallback);             // player destroys this object
    lua_register(L, "AnyEventCallback", Script_AnyEventCallback);                           // Any object event will cause the trigger.
    lua_register(L, "AllUnitsDestroyedCallback", Script_AllUnitsDestroyedCallback);         // all house's units destroyed
    lua_register(L, "AllBuildingsDestroyedCallback", Script_AllBuildingsDestroyedCallback); // all house's buildings destroyed
    lua_register(L, "AllDestroyedCallback", Script_AllDestroyedCallback);                   // all house's units & buildings destroyed
    lua_register(L, "CreditsReachedCallback", Script_CreditsReachedCallback);               // house reaches this many credits
    lua_register(L, "TimeReachedCallback", Script_TimeReachedCallback);                     // Scenario elapsed time from start.
    lua_register(L, "MissionTimerCallback", Script_MissionTimerCallback);                   // Pre expired mission timer.
    lua_register(L, "BuildingsDestroyedCallback", Script_BuildingsDestroyedCallback);       // Number of buildings destroyed.
    lua_register(L, "UnitsDestroyedCallback", Script_UnitsDestroyedCallback);               // Number of units destroyed.
    lua_register(L, "NoFactoriesCallback", Script_NoFactoriesCallback);                     // No factories left.
    lua_register(L, "CivilianEscapeCallback", Script_CivilianEscapeCallback);               // Civilian has been evacuated.
    lua_register(L, "BuildingBuiltCallback", Script_BuildingBuiltCallback);                 // Specified building has been built.
    lua_register(L, "UnitBuiltCallback", Script_UnitBuiltCallback);                         // Specified unit has been built.
    lua_register(L, "InfantryBuiltCallback", Script_InfantryBuiltCallback);                 // Specified infantry has been built.
    lua_register(L, "AircraftBuiltCallback", Script_AircraftBuiltCallback);                 // Specified aircraft has been built.
    lua_register(L, "TeamLeavesMapCallback", Script_TeamLeavesMapCallback);                 // Specified team member leaves map.
    lua_register(L, "ZoneEntryCallback", Script_ZoneEntryCallback);                         // Enters same zone as waypoint 'x'.
    lua_register(L, "HorizontalCrossCallback", Script_HorizontalCrossCallback);             // Crosses horizontal trigger line.
    lua_register(L, "VerticalCrossCallback", Script_VerticalCrossCallback);                 // Crosses vertical trigger line.
    lua_register(L, "GlobalSetCallback", Script_GlobalSetCallback);                         // If specified global has been set. (somewhat useless with Scripting)
    lua_register(L, "GlobalClearedCallback", Script_GlobalClearedCallback);                 // If specified global has been cleared. (somewhat useless with Scripting)
    // If all fake structures are gone.                                                     // This doesn't appear to be implemented in the engine (?)
    lua_register(L, "LowPowerCallback", Script_LowPowerCallback);                           // When power drops below 100%.
    lua_register(L, "AllBridgesDestroyedCallback", Script_AllBridgesDestroyedCallback);     // All bridges destroyed.
    lua_register(L, "BuildingExistsCallback", Script_BuildingExistsCallback);               // Check for building existing.

/**********************************************************************************************
* Trigger Utility Functions                                                                   *
*=============================================================================================*/

    lua_register(L, "SetTriggerCallback", Script_SetTriggerCallback);	            // Initiates a given [callback] on an existing [trigger] // TODO: Make this work via name OR ID
    lua_register(L, "TriggerAddCell", Script_TriggerAddCell);	                    // Initiates a given [callback] on an existing [trigger]
    lua_register(L, "MergeTriggers", Script_MergeTriggers);	                        // Combines the events of two triggers (for multi-event triggers :)
    lua_register(L, "GetTriggerByName", Script_GetTriggerByName);	                // Gets the ID of the trigger with a given name
    lua_register(L, "TriggerSetPersistence", Script_TriggerSetPersistence);	        // Does a trigger go on and on or just run once?

/**********************************************************************************************
* Object Functions                                                                            *
*=============================================================================================*/
    lua_register(L, "GetCellObject", Script_GetCellObject);	                        // Gets an object (ID - building/vehicle/aircraft/infantry/vessel), if any, at [Cell/X],[Cell/Y]

    lua_register(L, "SetObjectAttribute", Script_SetObjectAttribute);	            // Sets an object's attributes (strength, etc.)
    lua_register(L, "SetBuildingTypeAttribute", Script_SetBuildingTypeAttribute);	// Sets the attribute of a Building type
    lua_register(L, "SetVehicleTypeAttribute", Script_SetVehicleTypeAttribute);	    // Sets the attribute of a Vehicle type
    lua_register(L, "SetInfantryTypeAttribute", Script_SetInfantryTypeAttribute);	// Sets the attribute of an Infantry type
    lua_register(L, "SetVesselTypeAttribute", Script_SetVesselTypeAttribute);	    // Sets the attribute of a Vessel type
    lua_register(L, "SetAircraftTypeAttribute", Script_SetAircraftTypeAttribute);	// Sets the attribute of an Aircraft type

    lua_register(L, "GetObjectAttribute", Script_GetObjectAttribute);	            // Sets an object's attributes (strength, etc.)
    lua_register(L, "GetBuildingTypeAttribute", Script_GetBuildingTypeAttribute);	// Sets the attribute of a Building type
    lua_register(L, "GetVehicleTypeAttribute", Script_GetVehicleTypeAttribute);	    // Sets the attribute of a Vehicle type
    lua_register(L, "GetInfantryTypeAttribute", Script_GetInfantryTypeAttribute);	// Sets the attribute of an Infantry type
    lua_register(L, "GetVesselTypeAttribute", Script_GetVesselTypeAttribute);	    // Sets the attribute of a Vessel type
    lua_register(L, "GetAircraftTypeAttribute", Script_GetAircraftTypeAttribute);	// Sets the attribute of an Aircraft type

    lua_register(L, "SetHouseAttribute", Script_SetHouseAttribute);	                // Sets a house's attributes
    lua_register(L, "GetHouseAttribute", Script_GetHouseAttribute);	                // Gets a house's attributes

    lua_register(L, "BuildUnit", Script_BuildUnit);	                                // Builds a unit in a given factory / barracks / naval yard / etc
    lua_register(L, "CreateVehicle", Script_CreateVehicle);                         // Creates a unit out of thin air
    lua_register(L, "CreateInfantry", Script_CreateInfantry);                       // Creates a unit out of thin air
    lua_register(L, "CreateAircraft", Script_CreateAircraft);                       // Creates a unit out of thin air
    lua_register(L, "CreateVessel", Script_CreateVessel);                           // Creates a unit out of thin air

/**********************************************************************************************
* Object Orders Functions                                                                     *
*=============================================================================================*/

    lua_register(L, "OrderMove", Script_OrderMove);                                 // Assigns a movement order to the object
    lua_register(L, "OrderAttack", Script_OrderAttack);                             // Assigns an attack order to the object
    lua_register(L, "OrderHunt", Script_OrderHunt);                                 // Assigns a hunt order to the object
    lua_register(L, "OrderGuard", Script_OrderGuard);                               // Assigns a guard order to the object
    lua_register(L, "OrderEnter", Script_OrderEnter);                               // Assigns a enter order to the object
    lua_register(L, "OrderCapture", Script_OrderCapture);                           // Assigns a capture order to the object

/**********************************************************************************************
* Mission Utility Functions                                                                   *
*=============================================================================================*/

    lua_register(L, "SetBriefingText", Script_SetBriefingText);						// Sets the [text] on the mission briefing screen

/**********************************************************************************************
* Status / Location Utility Functions                                                         *
*=============================================================================================*/

    lua_register(L, "GiveCredits", Script_GiveCredits);                             // Give [credits] to [player] 
    lua_register(L, "GetCredits", Script_GetCredits);                               // Get [player]'s [credits]

    lua_register(L, "CountBuildings", Script_CountBuildings);	                    // Number of buildings of [type] for given [player]
    lua_register(L, "CountAircraft", Script_CountAircraft);	                        // Number of units of [type] for given [player]
    lua_register(L, "CountUnits", Script_CountUnits);	                            // Number of units of [type] for given [player]
    lua_register(L, "CountInfantry", Script_CountInfantry);	                        // Number of infantry of [type] for given [player]
    lua_register(L, "CountVessels", Script_CountVessels);	                        // Number of vessels of [type] for given [player]

    lua_register(L, "GetWaypointX", Script_GetWaypointX);	                        // Get Cell/X of waypoint
    lua_register(L, "GetWaypointY", Script_GetWaypointY);	                        // Get Cell/Y of waypoint

/**********************************************************************************************
* Special / Debug Functions                                                                   *
*=============================================================================================*/

    lua_register(L, "PrintConsole", Script_Console_Print);	                        // Print text to console 

/**********************************************************************************************
* Script Globals                                                                              *
*=============================================================================================*/

    lua_pushnumber(L, PlayerPtr->ID);                                                // Local player (house) index
    lua_setglobal(L, "_localPlayer");


    return true;
}