diff --git a/.gitignore b/.gitignore index 4b893ed..7ea87a2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,11 +8,12 @@ /fonts /sound /ui -/*.mix -/*.pal -/*.ini /*.exe /*.ilk -/*.dat -/savegame* +/*.MIX +/*.PAL +/*.INI +/*.DAT +/SAVEGAME* +/cache diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 68f0b3e..598a01b 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -11,6 +11,8 @@ set(CMAKE_VERBOSE_MAKEFILE ON) set(src_io ./redalert/io/userinput.cpp ./redalert/io/userinput.h + ./redalert/io/eventqueue.h + ./redalert/io/eventqueue.cpp ) set(src_win32lib @@ -742,4 +744,4 @@ if (UNIX) set_target_properties(RedAlert PROPERTIES OUTPUT_NAME "RedAlert" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/.." ) endif(UNIX) -target_include_directories(RedAlert PRIVATE ./external/xml/;./external/devil/;./external/;./redalert/win32lib;./external/lua/;./external/imgui;./external/dxsdk/Include;./external/ffmpeg-win32/include;./external/sdl2/include;./win32lib;./external/openal/include) \ No newline at end of file +target_include_directories(RedAlert PRIVATE ./external/xml/;./external/devil/;./external/;./redalert/win32lib;./redalert/io;./external/lua/;./external/imgui;./external/dxsdk/Include;./external/ffmpeg-win32/include;./external/sdl2/include;./win32lib;./external/openal/include) diff --git a/code/redalert/conquer.cpp b/code/redalert/conquer.cpp index 10a55c5..2614ddc 100644 --- a/code/redalert/conquer.cpp +++ b/code/redalert/conquer.cpp @@ -743,7 +743,7 @@ void Keyboard_Process(KeyNumType & input) ** Center the map about the construction yard or construction vehicle ** if one is present. */ - if (key != 0 && key == VK_H) { + if (key != 0 && key == Options.KeyBase) { Unselect_All(); if (PlayerPtr->CurBuildings) { for (index = 0; index < Buildings.Count(); index++) { @@ -875,19 +875,19 @@ void Keyboard_Process(KeyNumType & input) ** Scrolls the tactical map in the direction specified. */ int distance = CELL_LEPTON_W; - if (key != 0 && key == VK_LEFT) { + if (key != 0 && key == KN_LEFT) { Map.Scroll_Map(DIR_W, distance, true); input = KN_NONE; } - if (key != 0 && key == VK_RIGHT) { + if (key != 0 && key == KN_RIGHT) { Map.Scroll_Map(DIR_E, distance, true); input = KN_NONE; } - if (key != 0 && key == VK_UP) { + if (key != 0 && key == KN_UP) { Map.Scroll_Map(DIR_N, distance, true); input = KN_NONE; } - if (key != 0 && key == VK_DOWN) { + if (key != 0 && key == KN_DOWN) { Map.Scroll_Map(DIR_S, distance, true); input = KN_NONE; } diff --git a/code/redalert/display.h b/code/redalert/display.h index 524cc27..f716e4b 100644 --- a/code/redalert/display.h +++ b/code/redalert/display.h @@ -277,7 +277,7 @@ class DisplayClass: public MapClass */ class TacticalClass : public GadgetClass { public: - TacticalClass(void) : GadgetClass(0,0,0,0,LEFTPRESS|LEFTRELEASE|LEFTHELD|LEFTUP|RIGHTPRESS,true) {}; + TacticalClass(void) : GadgetClass(0,0,0,0,KEYBOARD|LEFTPRESS|LEFTRELEASE|LEFTHELD|LEFTUP|RIGHTPRESS,true) {}; int Selection_At_Mouse(unsigned flags, KeyNumType & key); int Command_Object(unsigned flags, KeyNumType & key); diff --git a/code/redalert/edit.cpp b/code/redalert/edit.cpp index 45783a9..d1f3a31 100644 --- a/code/redalert/edit.cpp +++ b/code/redalert/edit.cpp @@ -253,39 +253,8 @@ int EditClass::Action(unsigned flags, KeyNumType & key) } else { #ifdef WIN32 - KeyASCIIType ascii = (KeyASCIIType)(Keyboard->To_ASCII(key) & 0xff); - - /* - ** Allow numeric keypad presses to map to ascii numbers - */ - if ((key & WWKEY_VK_BIT) && ascii >='0' && ascii <= '9') { - - key = (KeyNumType)(key & ~WWKEY_VK_BIT); - if ( (!(flags & LEFTRELEASE)) && (!(flags & RIGHTRELEASE))) { - if (Handle_Key (ascii) ) { - flags &= ~KEYBOARD; - key = KN_NONE; - } - } - } else { - /* - ** Filter out all special keys except return and backspace - */ if ((!(key & WWKEY_VK_BIT) && ascii >= ' ' && ascii <= 255) - || key == KN_RETURN || key == KN_BACKSPACE) { - - - - if ((!(flags & LEFTRELEASE)) && (!(flags & RIGHTRELEASE))) { - if (Handle_Key(Keyboard->To_ASCII(key))) { - flags &= ~KEYBOARD; - key = KN_NONE; - } - } - } else { - flags &= ~KEYBOARD; - key = KN_NONE; - } - } + //KeyASCIIType ascii = (KeyASCIIType)(Keyboard->To_ASCII(key) & 0xff); + Handle_Key(key, flags); } #else //WIN32 @@ -374,11 +343,11 @@ void EditClass::Draw_Text(char const * text) * HISTORY: * * 01/21/1995 JLB : Created. * *=============================================================================================*/ -bool EditClass::Handle_Key(KeyASCIIType ascii) +bool EditClass::Handle_Key(KeyNumType key, unsigned flags) { - unsigned char testAscii = (unsigned char)ascii; + unsigned rawKey = key & 0xff; - switch (ascii) { + switch (rawKey) { /* ** Handle the special case of a non-keyboard event. It is possible that this ** key code might be passed to this routine if this routine has been overridden @@ -387,6 +356,7 @@ bool EditClass::Handle_Key(KeyASCIIType ascii) case 0: break; + /* ** If the return key is pressed, then remove the focus from this edit ** gadget but otherwise let the normal gadget processing proceed. This @@ -394,14 +364,14 @@ bool EditClass::Handle_Key(KeyASCIIType ascii) ** so that the controlling program will know that the text can be ** processed. */ - case KA_RETURN: + case KN_RETURN: Clear_Focus(); return(false); /* ** When the BACKSPACE key is pressed, remove the last character in the edit string. */ - case KA_BACKSPACE: + case KN_BACKSPACE: if (Length) { Length--; String[Length] = '\0'; @@ -414,11 +384,13 @@ bool EditClass::Handle_Key(KeyASCIIType ascii) ** if it can legally be added to the edit string and do so if possible. */ default: + unsigned char keyAscii = UserInput.KeyB.ASCII; + if (key & KN_SHIFT_BIT || key & KN_CAPSLOCK_BIT) keyAscii = toupper(keyAscii); /* ** Don't add a character if the length is greater than edit width. */ - if (((int)String_Pixel_Width(String) + (int)Char_Pixel_Width(testAscii) ) >= (Width-2)) { + if (((int)String_Pixel_Width(String) + (int)Char_Pixel_Width(keyAscii) ) >= (Width-2)) { break; } @@ -431,21 +403,21 @@ bool EditClass::Handle_Key(KeyASCIIType ascii) ** Invisible characters are never added to the string. This is ** especially true for spaces at the beginning of the string. */ - if (!isgraph(testAscii) && testAscii != ' ') break; - if (testAscii == ' ' && Length == 0) break; + if (!isgraph(keyAscii) && keyAscii != ' ') break; + if (keyAscii == ' ' && Length == 0) break; /* ** If this is an upper case only edit gadget, then force the alphabetic ** character to upper case. */ - if ((EditFlags & UPPERCASE) && isalpha(testAscii)) { - testAscii = (KeyASCIIType)toupper(testAscii); + if ((EditFlags & UPPERCASE) && isalpha(keyAscii)) { + rawKey = (KeyASCIIType)toupper(keyAscii); } - if ((!(EditFlags & NUMERIC) || !isdigit(testAscii)) && - (!(EditFlags & ALPHA) || !isalpha(testAscii)) && - (!(EditFlags & MISC) || isalnum(testAscii)) && - testAscii != ' ') { + if ((!(EditFlags & NUMERIC) || !isdigit(keyAscii)) && + (!(EditFlags & ALPHA) || !isalpha(keyAscii)) && + (!(EditFlags & MISC) || isalnum(keyAscii)) && + rawKey != ' ') { break; } @@ -455,8 +427,9 @@ bool EditClass::Handle_Key(KeyASCIIType ascii) ** because the event flag has been cleared. This prevents the gadget's ID ** number from being returned just because the gadget has been edited. */ - String[Length++] = testAscii; + String[Length++] = keyAscii; String[Length] = '\0'; + Flag_To_Redraw(); break; } diff --git a/code/redalert/edit.h b/code/redalert/edit.h index 92168d9..5d861ad 100644 --- a/code/redalert/edit.h +++ b/code/redalert/edit.h @@ -91,7 +91,7 @@ class EditClass : public ControlClass virtual int Action (unsigned flags, KeyNumType &key); virtual void Draw_Background(void); virtual void Draw_Text(char const * text); - virtual bool Handle_Key(KeyASCIIType ascii); + virtual bool Handle_Key(KeyNumType ascii, unsigned flags); private: int IsReadOnly; diff --git a/code/redalert/externs.h b/code/redalert/externs.h index da7f00a..45eb9b1 100644 --- a/code/redalert/externs.h +++ b/code/redalert/externs.h @@ -162,6 +162,7 @@ extern PKey SlowKey; extern RulesClass Rule; extern KeyboardClass * Keyboard; extern UserInputClass UserInput; +extern EventQueueClass EventQueue; extern RandomStraw CryptRandom; extern RandomClass NonCriticalRandomNumber; extern CarryoverClass * Carryover; diff --git a/code/redalert/fixed.cpp b/code/redalert/fixed.cpp index e8add29..abf18cd 100644 --- a/code/redalert/fixed.cpp +++ b/code/redalert/fixed.cpp @@ -32,6 +32,7 @@ * Functions: * * fixed::As_ASCII -- Returns a pointer (static) of this number as an ASCII string. * * fixed::To_ASCII -- Convert a fixed point number into an ASCII string. * + * fixed::To_Float -- Convert a fixed point number into a float value * * fixed::fixed -- Constructor for fixed integral from ASCII initializer. * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -40,6 +41,7 @@ #include #include #include +#include /* @@ -148,6 +150,33 @@ fixed::fixed(char const * ascii) } +/*********************************************************************************************** + * fixed::To_Float -- Convert a fixed point number into a float * + * * + * Use this routine to convert this fixed point number into a float. This can be lossy for * + * fine values. * + * * + * INPUT: none * + * * + * OUTPUT: Returns with the float value of this fixed point number * + * * + * WARNINGS: none * + * * + * HISTORY: * + * 06/27/2020 JJ : Created. * + *=============================================================================================*/ +float fixed::To_Float() const +{ + + unsigned int whole = Data.Composite.Whole; + unsigned int frac = ((unsigned int)Data.Composite.Fraction * 1000U) / PRECISION; + + float this_raw_value = (whole + (frac * .001)); + + return floor(this_raw_value * 100.0 + 0.5) / 100.0; + +} + /*********************************************************************************************** * fixed::To_ASCII -- Convert a fixed point number into an ASCII string. * * * diff --git a/code/redalert/fixed.h b/code/redalert/fixed.h index b141508..3b2ec81 100644 --- a/code/redalert/fixed.h +++ b/code/redalert/fixed.h @@ -206,6 +206,11 @@ class fixed int To_ASCII(char * buffer, int maxlen=-1) const; char const * As_ASCII(void) const; + /* + ** Helper function to convert fixed point number to float (JJ) + */ + float To_Float() const; + /* ** Helper constants that provide some convenient fixed point values. */ diff --git a/code/redalert/function.h b/code/redalert/function.h index dc10fba..ae1810a 100644 --- a/code/redalert/function.h +++ b/code/redalert/function.h @@ -200,7 +200,8 @@ struct NoInitClass { #endif #include "key.h" -#include "io/UserInput.h" +#include "io/userinput.h" +#include "io/eventqueue.h" #include #include "mpu.h" diff --git a/code/redalert/gadget.cpp b/code/redalert/gadget.cpp index 71c1d32..6dba2e5 100644 --- a/code/redalert/gadget.cpp +++ b/code/redalert/gadget.cpp @@ -58,31 +58,31 @@ #include -/* -** This records the current gadget the the gadget system is "stuck on". Such a -** gadget will be processed to the exclusion of all others until the mouse button -** is no longer pressed. -*/ -GadgetClass * GadgetClass::StuckOn = 0; + /* + ** This records the current gadget the the gadget system is "stuck on". Such a + ** gadget will be processed to the exclusion of all others until the mouse button + ** is no longer pressed. + */ +GadgetClass* GadgetClass::StuckOn = 0; /* ** This is a copy of a pointer to the last list used by the gadget input system. ** If a change of list is detected, then all gadgets are forced to be redrawn. */ -GadgetClass * GadgetClass::LastList = 0; +GadgetClass* GadgetClass::LastList = 0; /* ** This points to the gadget that is intercepting all keyboard events. */ -GadgetClass * GadgetClass::Focused = 0; +GadgetClass* GadgetClass::Focused = 0; /* ** This points to the current color scheme for drawing all gadgets. */ -static RemapControlType _GreyScheme = {15}; -RemapControlType * GadgetClass::ColorScheme = &_GreyScheme; +static RemapControlType _GreyScheme = { 15 }; +RemapControlType* GadgetClass::ColorScheme = &_GreyScheme; /*********************************************************************************************** * GadgetClass::GadgetClass -- Constructor for gadget object. * @@ -110,7 +110,7 @@ GadgetClass::GadgetClass(int x, int y, int w, int h, unsigned flags, int sticky) X(x), Y(y), Width(w), Height(h), IsToRepaint(false), IsSticky(sticky), IsDisabled(false), Flags(flags) { if (IsSticky) { - Flags |= LEFTPRESS|LEFTRELEASE; + Flags |= LEFTPRESS | LEFTRELEASE; } } @@ -130,7 +130,7 @@ GadgetClass::GadgetClass(int x, int y, int w, int h, unsigned flags, int sticky) * HISTORY: * * 08/01/1996 JLB : Created. * *=============================================================================================*/ -GadgetClass::GadgetClass(GadgetClass const & gadget) : +GadgetClass::GadgetClass(GadgetClass const& gadget) : X(gadget.X), Y(gadget.Y), Width(gadget.Width), @@ -190,7 +190,7 @@ GadgetClass::~GadgetClass(void) * * * HISTORY: 01/03/1995 MML : Created. * *=========================================================================*/ -int GadgetClass::Clicked_On(KeyNumType & key, unsigned flags, int mousex, int mousey) +int GadgetClass::Clicked_On(KeyNumType& key, unsigned flags, int mousex, int mousey) { /* ** Set flags to match only those events that occur AND are being looked for. If @@ -212,7 +212,7 @@ int GadgetClass::Clicked_On(KeyNumType & key, unsigned flags, int mousex, int mo */ if (this == StuckOn || (flags & KEYBOARD) || - (flags && (mousex - X) < Width && (mousey - Y) < Height)) { + (flags && (mousex - X) < Width && (mousey - Y) < Height)) { return(Action(flags, key)); } @@ -281,10 +281,10 @@ void GadgetClass::Disable(void) * HISTORY: * * 01/15/1995 JLB : Created. * *=============================================================================================*/ -GadgetClass * GadgetClass::Remove(void) +GadgetClass* GadgetClass::Remove(void) { Clear_Focus(); - return(GadgetClass *)LinkClass::Remove(); + return(GadgetClass*)LinkClass::Remove(); } @@ -303,7 +303,7 @@ GadgetClass * GadgetClass::Remove(void) * HISTORY: * * 01/15/1995 JLB : Created. * *=============================================================================================*/ -GadgetClass * GadgetClass::Get_Next(void) const +GadgetClass* GadgetClass::Get_Next(void) const { return(GadgetClass*)LinkClass::Get_Next(); } @@ -324,7 +324,7 @@ GadgetClass * GadgetClass::Get_Next(void) const * HISTORY: * * 01/15/1995 JLB : Created. * *=============================================================================================*/ -GadgetClass * GadgetClass::Get_Prev(void) const +GadgetClass* GadgetClass::Get_Prev(void) const { return(GadgetClass*)LinkClass::Get_Prev(); } @@ -347,7 +347,7 @@ GadgetClass * GadgetClass::Get_Prev(void) const *=============================================================================================*/ void GadgetClass::Delete_List(void) { - GadgetClass * g = this; + GadgetClass* g = this; /* ** Move to head of the list. @@ -365,7 +365,7 @@ void GadgetClass::Delete_List(void) while (g) { g->Clear_Focus(); - GadgetClass * temp = g; + GadgetClass* temp = g; g = g->Get_Next(); delete temp; } @@ -391,7 +391,7 @@ void GadgetClass::Delete_List(void) * HISTORY: * * 01/15/1995 JLB : Created. * *=============================================================================================*/ -int GadgetClass::Action(unsigned flags, KeyNumType &) +int GadgetClass::Action(unsigned flags, KeyNumType&) { /* ** If any of the event flags are active, then this indicates that something probably @@ -450,7 +450,7 @@ int GadgetClass::Draw_Me(int forced) *=============================================================================================*/ void GadgetClass::Draw_All(bool forced) { - GadgetClass * gadget = this; + GadgetClass* gadget = this; while (gadget != NULL) { gadget->Draw_Me(forced); @@ -470,8 +470,10 @@ void GadgetClass::Draw_All(bool forced) * HISTORY: 01/03/1995 MML : Created. * *=========================================================================*/ KeyNumType GadgetClass::Input(void) -{ - KeyNumType key; +{ + EventMessage eventMessage; + KeyNumType key = KN_NONE; + int flags = 0; int forced = false; /* @@ -488,111 +490,52 @@ KeyNumType GadgetClass::Input(void) /* ** Fetch any pending keyboard input. */ - key = Keyboard->Check(); - if (key != 0) { - key = Keyboard->Get(); + UserInput.Process_Input(key, flags); + + if (EventQueue.Check()) { + eventMessage = EventQueue.Get(); + eventMessage.Key_Flags(key, flags); } - /* - ** For mouse button clicks, the mouse position is actually held in the MouseQ... - ** globals rather than their normal Mouse... globals. This is because we need to - ** know the position of the mouse at the exact instant when the click occurred - ** rather the the mouse position at the time we get around to this function. - */ -// jmarshall - UserInput.Process_Input( g_globalKeyNumType, g_globalKeyFlags); - int flags = g_globalKeyFlags; -// jmarshall end - - /* - ** Set the mouse button state flags. These will be passed to the individual - ** buttons so that they can determine what action to perform (if any). - */ - //if (key) { - // if (key == KN_LMOUSE) { - // flags |= LEFTPRESS; - // } - // if (key == KN_RMOUSE) { - // flags |= RIGHTPRESS; - // } - // if (key == (KN_LMOUSE | KN_RLSE_BIT)) { - // flags |= LEFTRELEASE; - // } - // if (key == (KN_RMOUSE | KN_RLSE_BIT)) { - // flags |= RIGHTRELEASE; - // } - //} - - /* - ** If the mouse wasn't responsible for this key code, then it must be from - ** the keyboard. Flag this fact. - */ - if (key && !flags) { - flags |= KEYBOARD; - } - - /* - ** Mouse button up or down action is ignored if there is a keyboard event. This - ** allows keyboard events to fall through normally even if the mouse is over a - ** gadget that is flagged for LEFTUP or RIGHTUP. - */ -// jmarshall - //if (!key) { - // - // /* - // ** Check for the mouse being held down. We can't use the normal input system - // ** for this, so we must examine the actual current state of the mouse - // ** buttons. As a side note, if we determine that the mouse button isn't being - // ** held down, then we automatically know that it must be up -- set the flag - // ** accordingly. - // */ - // if (Keyboard->Down(KN_LMOUSE)) { - // flags |= LEFTHELD; - // } else { - // flags |= LEFTUP; - // } - // if (Keyboard->Down(KN_RMOUSE)) { - // flags |= RIGHTHELD; - // } else { - // flags |= RIGHTUP; - // } - //} -// jmarshall end - /* ** If "sticky" processing is active, then only process the stuck gadget. */ if (StuckOn) { StuckOn->Draw_Me(false); - GadgetClass * oldstuck = StuckOn; + GadgetClass* oldstuck = StuckOn; StuckOn->Clicked_On(key, flags, UserInput.Mouse.X, UserInput.Mouse.Y); - if (StuckOn) { + + if (StuckOn) + { StuckOn->Draw_Me(false); - } else { + } + else { oldstuck->Draw_Me(false); } - } else { - + } + else + { /* ** If there is a gadget that has the keyboard focus, then route all keyboard ** events to it. */ - if (Focused && (flags & KEYBOARD)) { + if (Focused && eventMessage.EventType == EventMessageType::EVENT_KEYBOARD) { Focused->Draw_Me(false); Focused->Clicked_On(key, flags, UserInput.Mouse.X, UserInput.Mouse.Y); if (Focused) { Focused->Draw_Me(false); } - } else { + } + else { /* ** Sweep through all the buttons in the chain and pass the current button state ** and keyboard input data to them. These routines will detect whether they should ** perform some action and return a flag to this effect. They also have the option - ** of changing the key value so that an appropriate return value is use for this + ** of changing the key value so that an appropriate return value is used for this ** processing routine. */ - GadgetClass * next_button = this; + GadgetClass* next_button = this; while (next_button != NULL) { /* @@ -621,6 +564,7 @@ KeyNumType GadgetClass::Input(void) } } } + return(key); } @@ -645,14 +589,14 @@ KeyNumType GadgetClass::Input(void) * HISTORY: * * 01/16/1995 JLB : Created. * *=============================================================================================*/ -ControlClass * GadgetClass::Extract_Gadget(unsigned id) +ControlClass* GadgetClass::Extract_Gadget(unsigned id) { - GadgetClass * g = this; + GadgetClass* g = this; if (id != 0) { while (g != NULL) { if (g->Get_ID() == id) { - return((ControlClass *)g); + return((ControlClass*)g); } g = g->Get_Next(); } @@ -801,7 +745,7 @@ bool GadgetClass::Has_Focus(void) *=============================================================================================*/ int GadgetClass::Is_List_To_Redraw(void) { - GadgetClass * gadget = this; + GadgetClass* gadget = this; while (gadget != NULL) { if (gadget->IsToRepaint) { diff --git a/code/redalert/globals.cpp b/code/redalert/globals.cpp index 1c04133..54e06db 100644 --- a/code/redalert/globals.cpp +++ b/code/redalert/globals.cpp @@ -257,6 +257,7 @@ RulesClass Rule; ** user input class pointer. */ UserInputClass UserInput; +EventQueueClass EventQueue; /*************************************************************************** ** All keyboard input is routed through the object pointed to by this diff --git a/code/redalert/io/eventqueue.cpp b/code/redalert/io/eventqueue.cpp new file mode 100644 index 0000000..512ec54 --- /dev/null +++ b/code/redalert/io/eventqueue.cpp @@ -0,0 +1,157 @@ +#include "../function.h" +#include "eventqueue.h" + +/* + Clears the event queue and frees memory +*/ +void EventQueueClass::Clear() +{ + while (this->eventQueue.size() > 0) { + this->eventQueue.pop(); + } +} + +/* + Inserts a new event message event into the FIFO buffer. +*/ +void EventQueueClass::Put(EventMessage input) +{ + if ( Is_Buffer_Full() ) return; + this->eventQueue.push( input ); +} + +/* + Check if the buffer contains an element +*/ +bool EventQueueClass::Check() const +{ + return !this->Is_Buffer_Empty(); +} + +/* + Get the first (unprocessed) element in the event queue +*/ +EventMessage EventQueueClass::Get() +{ + // wait for buffer + while( !this->Check() ) { } + + EventMessage returnVal = this->eventQueue.front(); + this->eventQueue.pop(); + + return returnVal; +} + +/* + Returns ASCII value of the key in the buffer +*/ +char EventQueueClass::Get_ASCII() +{ + // get the last key from the buffer + EventMessage eventMessage = this->Get(); + return eventMessage.Keyboard.ASCII; +} + +EventMessage::EventMessage(KeyNumType key, char ascii, bool shift, bool alt, bool control, bool capsLock) { + this->Clear(); + + this->Valid = true; + this->EventType = EventMessageType::EVENT_KEYBOARD; + + this->Keyboard.Key = key; + this->Keyboard.Shift = shift; + this->Keyboard.Alt = alt; + this->Keyboard.Control = control; + this->Keyboard.CapsLock = capsLock; + this->Keyboard.ASCII = ascii; +} + +EventMessage::EventMessage(int x, int y, unsigned short button, MouseButtonState buttonState) +{ + this->Clear(); + + this->Valid = true; + this->EventType = EventMessageType::EVENT_MOUSE; + + this->Mouse.x = x; + this->Mouse.y = y; + this->Mouse.Button = button; + this->Mouse.ButtonState = buttonState; + + this->Flags = 0; + + if (buttonState == MouseButtonState::MOUSE_BUTTON_UP) { + this->Flags = (button == KN_LMOUSE) ? GadgetClass::LEFTUP : GadgetClass::RIGHTUP; + } + + if (buttonState == MouseButtonState::MOUSE_BUTTON_DOWN) { + this->Flags = (button == KN_LMOUSE) ? GadgetClass::LEFTPRESS : GadgetClass::RIGHTPRESS; + } + + if (buttonState == MouseButtonState::MOUSE_BUTTON_HOLD) { + this->Flags = (button == KN_LMOUSE) ? GadgetClass::LEFTHELD : GadgetClass::RIGHTHELD; + } + + if (buttonState == MouseButtonState::MOUSE_BUTTON_RELEASE) { + this->Flags = (button == KN_LMOUSE) ? GadgetClass::LEFTRELEASE : GadgetClass::RIGHTRELEASE; + } +} + + +void EventMessage::Key_Flags(KeyNumType& key, int& flags) +{ + if (this->EventType == EventMessageType::EVENT_KEYBOARD) + { + flags = this->Flags; + flags |= GadgetClass::KEYBOARD; + + unsigned short outputKey = this->Keyboard.Key; + + if (this->Keyboard.Shift) outputKey |= KN_SHIFT_BIT; + if (this->Keyboard.Alt) outputKey |= KN_ALT_BIT; + if (this->Keyboard.Control) outputKey |= KN_CTRL_BIT; + + key = (KeyNumType)outputKey; + } + + if (this->EventType == EventMessageType::EVENT_MOUSE) + { + key = (KeyNumType)this->Mouse.Button; + + if (key == KN_LMOUSE) { + switch (this->Mouse.ButtonState) + { + case MouseButtonState::MOUSE_BUTTON_UP: + flags = GadgetClass::LEFTUP; + break; + case MouseButtonState::MOUSE_BUTTON_DOWN: + flags = GadgetClass::LEFTPRESS; + break; + case MouseButtonState::MOUSE_BUTTON_RELEASE: + flags = GadgetClass::LEFTRELEASE; + break; + case MouseButtonState::MOUSE_BUTTON_HOLD: + flags = GadgetClass::LEFTHELD; + break; + } + } + + if (key == KN_RMOUSE) { + switch (this->Mouse.ButtonState) + { + case MouseButtonState::MOUSE_BUTTON_UP: + flags = GadgetClass::LEFTUP; + break; + case MouseButtonState::MOUSE_BUTTON_DOWN: + flags = GadgetClass::RIGHTPRESS; + break; + case MouseButtonState::MOUSE_BUTTON_RELEASE: + flags = GadgetClass::RIGHTRELEASE; + break; + case MouseButtonState::MOUSE_BUTTON_HOLD: + flags = GadgetClass::RIGHTHELD; + break; + } + } + } +} \ No newline at end of file diff --git a/code/redalert/io/eventqueue.h b/code/redalert/io/eventqueue.h new file mode 100644 index 0000000..be92699 --- /dev/null +++ b/code/redalert/io/eventqueue.h @@ -0,0 +1,121 @@ +#pragma once +#include + +/* +* WWKeyboardClass::Buff_Get -- Lowlevel function to get a key from key buffer* +* WWKeyboardClass::Check -- Checks to see if a key is in the buffer* +* WWKeyboardClass::Down -- Checks to see if the specified key is being held down.* +* WWKeyboardClass::Fetch_Element -- Extract the next element in the keyboard buffer.* +* WWKeyboardClass::Get -- Logic to get a metakey from the buffer* +* WWKeyboardClass::Message_Handler -- Process a windows message as it relates to the keyboar* +* WWKeyboardClass::Peek_Element -- Fetches the next element in the keyboard buffer.* +* WWKeyboardClass::To_ASCII -- Convert the key value into an ASCII representation.* +* WWKeyboardClass::Available_Buffer_Room -- Fetch the quantity of free elements in the keybo* +* ----------------------------------------------*/ + +/** +* EVENT QUEUE class +* Supports pumping of event messages using a FIFO buffer. +*/ + +extern UserInputClass UserInput; + +/* + Event type definitions +*/ +typedef enum EventMessageType { + EVENT_NONE, + EVENT_KEYBOARD, + EVENT_MOUSE +}; + +/* + Event types +*/ +class EventMessage { + public: + EventMessageType EventType; + bool Valid; + + EventMessage() { + this->EventType == EVENT_NONE; + + this->Keyboard.Key = KN_NONE; + this->Keyboard.Shift = false; + this->Keyboard.Alt = false; + this->Keyboard.Control = false; + this->Keyboard.CapsLock = false; + + this->Mouse.x = -1; + this->Mouse.y = -1; + this->Mouse.Button = 0; + this->Mouse.ButtonState = MouseButtonState::MOUSE_BUTTON_UP; + + this->Flags = 0; + + this->Valid = false; + } + + // for keyboard + struct { + KeyNumType Key; + char ASCII; + bool Shift; + bool Alt; + bool Control; + bool CapsLock; + } Keyboard; + + // for mouse + struct { + int x; + int y; + unsigned short Button; + MouseButtonState ButtonState; + } Mouse; + + // for cascading functions + unsigned short Flags; + + EventMessage( KeyNumType key, char asciis, bool shift, bool alt, bool control, bool capsLock ); + EventMessage( int x, int y, unsigned short button = KN_LMOUSE, MouseButtonState buttonState = MouseButtonState::MOUSE_BUTTON_DOWN ); + + void Key_Flags(KeyNumType& key, int& flags); + private: + void Clear() { + this->Keyboard.Key = KN_NONE; + this->Keyboard.Shift = false; + this->Keyboard.Alt = false; + this->Keyboard.Control = false; + this->Keyboard.CapsLock = false; + + this->Mouse.x = -1; + this->Mouse.y = -1; + this->Mouse.Button = 0; + this->Mouse.ButtonState = MouseButtonState::MOUSE_BUTTON_UP; + + this->Flags = 0; + + this->Valid = false; + } +}; + +class EventQueueClass { + public: + int Get_Mouse_X() const { return UserInput.Mouse.X; } + int Get_Mouse_Y() const { return UserInput.Mouse.Y; } + + void Clear(); + void Put(EventMessage input); + bool Check() const; + EventMessage Get(); + char EventQueueClass::Get_ASCII(); + + private: + const int MaxCapacity = 100; + + std::queue< EventMessage > eventQueue; + + bool Is_Buffer_Full() const { return this->eventQueue.size() == MaxCapacity; } + bool Is_Buffer_Empty() const { return this->eventQueue.size() == 0; } +}; diff --git a/code/redalert/io/userinput.cpp b/code/redalert/io/userinput.cpp index aadd59c..1d3ce53 100644 --- a/code/redalert/io/userinput.cpp +++ b/code/redalert/io/userinput.cpp @@ -1,18 +1,60 @@ -#include "../FUNCTION.H" -#include "UserInput.h" +#include "../function.h" +#include "userinput.h" -extern KeyboardClass * Keyboard; +extern KeyboardClass* Keyboard; + +std::map sdl_keyMapping_reverse; + +UserInputClass::UserInputClass() +{ + LastAction = InputAction::INPUT_ACTION_NONE; + + // generate reverse keymapping + for (auto it = sdl_keyMapping.begin(); it != sdl_keyMapping.end(); it++) + { + sdl_keyMapping_reverse[it->second] = it->first; + } +} + +bool UserInputClass::KeyboardState::Key_Down(KeyNumType key) const +{ + auto sdl_Key = sdl_keyMapping_reverse.find(key); + if (sdl_Key != sdl_keyMapping_reverse.end()) + { + const SDL_Scancode scanCode = SDL_GetScancodeFromKey(sdl_Key->second); + const Uint8* keyState = SDL_GetKeyboardState(NULL); + return (keyState[scanCode]); + } + return false; +} + +bool UserInputClass::MouseState::Mouse_Down(KeyNumType key) const +{ + // get mouse state, we are only interested in the buttons + const Uint32 MouseState = SDL_GetMouseState(NULL, NULL); + + switch (key) + { + case KN_LMOUSE: + return MouseState & SDL_BUTTON(SDL_BUTTON_LEFT); + break; + case KN_RMOUSE: + return MouseState & SDL_BUTTON(SDL_BUTTON_RIGHT); + break; + } +} void UserInputClass::Process_Input(KeyNumType& key, int& flags) { bool leftMouseProcessed = false; - SDL_GetMouseState(&Mouse.X, &Mouse.Y); + + const Uint32 MouseState = SDL_GetMouseState(&Mouse.X, &Mouse.Y); + + flags = 0; Keyboard->MouseQX = Mouse.X; Keyboard->MouseQY = Mouse.Y; - flags = 0; - static SDL_Event event; memset(&event, 0, sizeof(SDL_Event)); @@ -21,119 +63,158 @@ void UserInputClass::Process_Input(KeyNumType& key, int& flags) switch (event.type) { - case SDL_SYSWMEVENT: - if (event.syswm.msg->msg.win.msg == WM_DESTROY) - { - Invalidate_Cached_Icons(); - VisiblePage.Un_Init(); - HiddenPage.Un_Init(); - AllSurfaces.Release(); - if (!InDebugger) Reset_Video_Mode(); - - PostQuitMessage(0); - - switch (ReadyToQuit) { - case 1: - ReadyToQuit = 2; - break; - case 0: - ExitProcess(0); - break; - } - } - - break; - - case SDL_MOUSEMOTION: - flags = GadgetClass::LEFTUP; - break; - - case SDL_MOUSEBUTTONDOWN: - if (event.button.button == SDL_BUTTON_LEFT) { - Mouse.Button_Left == MouseButtonState::MOUSE_BUTTON_DOWN; - - key = KN_LMOUSE; - flags |= GadgetClass::LEFTPRESS; - - Keyboard->Put_Element(KN_LMOUSE); - - leftMouseProcessed = true; - numFramesLMouse++; - } - else if (event.button.button == SDL_BUTTON_RIGHT) { - Mouse.Button_Right == MouseButtonState::MOUSE_BUTTON_DOWN; - - Keyboard->Put_Element(KN_RMOUSE); - - key = KN_RMOUSE; - flags |= GadgetClass::RIGHTPRESS; - - numFramesLMouse = 0; - } - break; - - case SDL_MOUSEBUTTONUP: - if (event.button.button == SDL_BUTTON_LEFT) { - Mouse.Button_Left == MouseButtonState::MOUSE_BUTTON_RELEASE; - flags &= GadgetClass::LEFTPRESS; - flags |= GadgetClass::LEFTRELEASE; - numFramesLMouse = 0; - } - else if (event.button.button == SDL_BUTTON_RIGHT) { - Mouse.Button_Right == MouseButtonState::MOUSE_BUTTON_RELEASE; - - flags &= GadgetClass::RIGHTPRESS; - flags |= GadgetClass::RIGHTRELEASE; - numFramesLMouse = 0; - } - break; - - case SDL_KEYDOWN: + case SDL_SYSWMEVENT: + if (event.syswm.msg->msg.win.msg == WM_DESTROY) { - if (event.key.keysym.scancode == SDL_SCANCODE_GRAVE) { - renderConsole = !renderConsole; + Invalidate_Cached_Icons(); + VisiblePage.Un_Init(); + HiddenPage.Un_Init(); + AllSurfaces.Release(); + if (!InDebugger) Reset_Video_Mode(); - if (renderConsole) { - ShowCursor(TRUE); - Hide_Mouse(); - } - else { - ShowCursor(FALSE); - Show_Mouse(); - } + PostQuitMessage(0); + + switch (ReadyToQuit) { + case 1: + ReadyToQuit = 2; + break; + case 0: + ExitProcess(0); break; } + } - int keyFlags = 0x00; - if (state[SDL_SCANCODE_RSHIFT] || state[SDL_SCANCODE_LSHIFT]) { - KeyB.Shift = true; - keyFlags |= KN_SHIFT_BIT; - } - if (state[SDL_SCANCODE_RALT] || state[SDL_SCANCODE_LALT]) { - keyFlags |= KN_ALT_BIT; - KeyB.Alt = true; - } - if (state[SDL_SCANCODE_RCTRL] || state[SDL_SCANCODE_LCTRL]) { - keyFlags |= KN_CTRL_BIT; - KeyB.Control = true; - } + break; - // handle match between SDL and internals (non-text keys) - auto element = sdl_keyMapping.find((SDL_KeyCode)event.key.keysym.sym); - if (element != sdl_keyMapping.end()) - { - Keyboard->Put_Element(element->second | keyFlags); - KeyB.ASCII = element->second; - } + /* Mouse is moving */ + case SDL_MOUSEMOTION: + if (!(MouseState & SDL_BUTTON(SDL_BUTTON_LEFT))) + { + flags |= GadgetClass::LEFTUP; + } + break; + + case SDL_MOUSEBUTTONDOWN: + if (event.button.button == SDL_BUTTON_LEFT) { + Mouse.Button_Left == MouseButtonState::MOUSE_BUTTON_DOWN; + + key = KN_LMOUSE; + flags |= GadgetClass::LEFTPRESS; + + EventQueue.Put(EventMessage(Mouse.X, Mouse.Y, KN_LMOUSE)); + + Keyboard->Put_Element(KN_LMOUSE); + + leftMouseProcessed = true; + numFramesLMouse++; + + // after first left-mouse down, abort handling any other SDL events + // because game might first need to switch into rubber band mode + if (numFramesLMouse == 1) return; + } + else if (event.button.button == SDL_BUTTON_RIGHT) { + Mouse.Button_Right == MouseButtonState::MOUSE_BUTTON_DOWN; + + EventQueue.Put(EventMessage(Mouse.X, Mouse.Y, KN_RMOUSE)); + + Keyboard->Put_Element(KN_RMOUSE); + + key = KN_RMOUSE; + flags |= GadgetClass::RIGHTPRESS; + + numFramesLMouse = 0; + } + break; + + case SDL_MOUSEBUTTONUP: + if (event.button.button == SDL_BUTTON_LEFT) { + Mouse.Button_Left == MouseButtonState::MOUSE_BUTTON_RELEASE; + + EventQueue.Put(EventMessage(Mouse.X, Mouse.Y, KN_LMOUSE, MouseButtonState::MOUSE_BUTTON_RELEASE)); + + flags |= GadgetClass::LEFTRELEASE; + numFramesLMouse = 0; + } + else if (event.button.button == SDL_BUTTON_RIGHT) { + Mouse.Button_Right == MouseButtonState::MOUSE_BUTTON_RELEASE; + + EventQueue.Put(EventMessage(Mouse.X, Mouse.Y, KN_RMOUSE, MouseButtonState::MOUSE_BUTTON_RELEASE)); + + flags |= GadgetClass::RIGHTRELEASE; + numFramesLMouse = 0; + } + break; + + // Keyboard key lifted up + case SDL_KEYUP: + flags |= GadgetClass::KEYBOARD; + + break; + + // Keyboard key pressed down + case SDL_KEYDOWN: + { + if (event.key.keysym.scancode == SDL_SCANCODE_GRAVE) { + renderConsole = !renderConsole; + + if (renderConsole) { + ShowCursor(TRUE); + Hide_Mouse(); + } + else { + ShowCursor(FALSE); + Show_Mouse(); + } break; } - case SDL_TEXTINPUT: - // limit to range 0-255 - if (event.text.text[0] == ( event.text.text[0] & 0xFF ) ) - { - KeyB.ASCII = (char)event.text.text[0]; - } + + flags |= GadgetClass::KEYBOARD; + + int keyFlags = 0x00; + KeyB.Shift = false; + KeyB.Alt = false; + KeyB.Control = false; + KeyB.CapsLock = false; + + if (state[SDL_SCANCODE_RSHIFT] || state[SDL_SCANCODE_LSHIFT]) { + KeyB.Shift = true; + keyFlags |= KN_SHIFT_BIT; + } + if (state[SDL_SCANCODE_RALT] || state[SDL_SCANCODE_LALT]) { + keyFlags |= KN_ALT_BIT; + KeyB.Alt = true; + } + if (state[SDL_SCANCODE_RCTRL] || state[SDL_SCANCODE_LCTRL]) { + keyFlags |= KN_CTRL_BIT; + KeyB.Control = true; + } + if (state[SDL_SCANCODE_CAPSLOCK]) { + keyFlags |= KN_CAPSLOCK_BIT; + KeyB.CapsLock = true; + } + + // handle match between SDL and internals ( non-text keys ) + auto element = sdl_keyMapping.find((SDL_KeyCode)event.key.keysym.sym); + if (element != sdl_keyMapping.end()) + { + //EventQueue.Put( element->second | keyFlags ); + EventQueue.Put(EventMessage((KeyNumType)element->second, element->second, KeyB.Shift, KeyB.Alt, KeyB.Control, KeyB.CapsLock)); + + Keyboard->Put_Element(element->second | keyFlags); + + KeyB.LastKey = element->first; + KeyB.ASCII = 0x0; + } + + break; + } + case SDL_TEXTINPUT: + // limit to range 0-255 + if (event.text.text[0] == (event.text.text[0] & 0xFF)) + { + KeyB.ASCII = (char)event.text.text[0]; + } } if (Debug_Map || renderConsole) @@ -145,6 +226,8 @@ void UserInputClass::Process_Input(KeyNumType& key, int& flags) if (!leftMouseProcessed && numFramesLMouse != 0) { Mouse.Button_Left == MouseButtonState::MOUSE_BUTTON_HOLD; - flags = GadgetClass::LEFTHELD; + flags |= GadgetClass::LEFTHELD; + + EventQueue.Put(EventMessage(Mouse.X, Mouse.Y, KN_LMOUSE, MouseButtonState::MOUSE_BUTTON_HOLD)); } } \ No newline at end of file diff --git a/code/redalert/io/userinput.h b/code/redalert/io/userinput.h index 2ef72f3..412e29c 100644 --- a/code/redalert/io/userinput.h +++ b/code/redalert/io/userinput.h @@ -1,9 +1,9 @@ -#ifndef USERINPUT_H -#define USERINPUT_H +#pragma once #include #include #include +#include #include "examples/imgui_impl_sdl.h" @@ -86,65 +86,81 @@ std::map const sdl_keyMapping = { { SDLK_DOWN, KN_DOWN }, { SDLK_LEFT, KN_LEFT }, { SDLK_RIGHT, KN_RIGHT }, + + { SDLK_LALT, KN_LALT }, + { SDLK_RALT, KN_RALT }, + { SDLK_LCTRL, KN_LCTRL }, + { SDLK_RCTRL, KN_RCTRL }, + { SDLK_LSHIFT, KN_LSHIFT }, + { SDLK_RSHIFT, KN_RSHIFT }, }; +extern std::map sdl_keyMapping_reverse; + +const int USERINPUT_SHIFT_BIT = 0x100; +const int USERINPUT_CTRL_BIT = 0x200; +const int USERINPUT_ALT_BIT = 0x400; + +typedef enum { + MOUSE_BUTTON_UP, + MOUSE_BUTTON_DOWN, + MOUSE_BUTTON_HOLD, + MOUSE_BUTTON_RELEASE, +} MouseButtonState; + +typedef enum { + INPUT_ACTION_NONE, + INPUT_ACTION_KEYBOARD, + INPUT_ACTION_MOUSE, +} InputAction; class UserInputClass { +public: + UserInputClass(); + void UserInputClass::Process_Input(KeyNumType& key = g_globalKeyNumType, int& flags = g_globalKeyFlags); + + InputAction LastAction; + + class KeyboardState { public: - typedef enum { - MOUSE_BUTTON_UP, - MOUSE_BUTTON_DOWN, - MOUSE_BUTTON_HOLD, - MOUSE_BUTTON_RELEASE, - } MouseButtonState; + SDL_KeyCode LastKey; + char ASCII; - typedef enum { - INPUT_ACTION_NONE, - INPUT_ACTION_KEYBOARD, - INPUT_ACTION_MOUSE, - } InputAction; + bool Shift; + bool Control; + bool Alt; + bool CapsLock; - void UserInputClass::Process_Input(KeyNumType& key = g_globalKeyNumType, int& flags = g_globalKeyFlags); + bool Key_Down(KeyNumType key) const; - InputAction LastAction; + void ResetState() { + this->Shift = false; + this->Control = false; + this->Alt = false; + } + }; - class KeyboardState { - public: - SDL_KeyCode LastKey; - char ASCII; + KeyboardState KeyB; - bool Shift; - bool Control; - bool Alt; + class MouseState { + public: + int X; + int Y; - void ResetState() { - this->Shift = false; - this->Control = false; - this->Alt = false; - } - }; + MouseButtonState Button_Left; + MouseButtonState Button_Middle; + MouseButtonState Button_Right; - KeyboardState KeyB; + bool UserInputClass::MouseState::Mouse_Down(KeyNumType key) const; - class MouseState { - public: - int X; - int Y; + void ResetState() { + this->Button_Left = MouseButtonState::MOUSE_BUTTON_UP; + this->Button_Middle = MouseButtonState::MOUSE_BUTTON_UP; + this->Button_Right = MouseButtonState::MOUSE_BUTTON_UP; + } + }; - MouseButtonState Button_Left; - MouseButtonState Button_Middle; - MouseButtonState Button_Right; - - void ResetState() { - this->Button_Left = MouseButtonState::MOUSE_BUTTON_UP; - this->Button_Middle = MouseButtonState::MOUSE_BUTTON_UP; - this->Button_Right = MouseButtonState::MOUSE_BUTTON_UP; - } - }; - - MouseState Mouse; - private: - int numFramesLMouse = 0; + MouseState Mouse; +private: + int numFramesLMouse = 0; }; - -#endif \ No newline at end of file diff --git a/code/redalert/key.cpp b/code/redalert/key.cpp index 90626c7..4e80790 100644 --- a/code/redalert/key.cpp +++ b/code/redalert/key.cpp @@ -372,7 +372,7 @@ bool WWKeyboardClass::Down(unsigned short key) return g_globalKeyFlags & GadgetClass::RIGHTPRESS; } - return(GetAsyncKeyState(key & 0xFF) == 0 ? false : true); + return UserInput.KeyB.Key_Down((KeyNumType)key); } diff --git a/code/redalert/key.h b/code/redalert/key.h index 3a09594..263c1ae 100644 --- a/code/redalert/key.h +++ b/code/redalert/key.h @@ -523,121 +523,126 @@ typedef enum KeyASCIIType { typedef enum KeyNumType { - KN_NONE = 0, + KN_NONE = 0, - KN_0 = VK_0, - KN_1 = VK_1, - KN_2 = VK_2, - KN_3 = VK_3, - KN_4 = VK_4, - KN_5 = VK_5, - KN_6 = VK_6, - KN_7 = VK_7, - KN_8 = VK_8, - KN_9 = VK_9, - KN_A = VK_A, - KN_B = VK_B, - KN_BACKSLASH = VK_NONE_DC, - KN_BACKSPACE = VK_BACK, - KN_C = VK_C, - KN_CAPSLOCK = VK_CAPITAL, - KN_CENTER = VK_CLEAR, - KN_COMMA = VK_NONE_BC, - KN_D = VK_D, - KN_DELETE = VK_DELETE, - KN_DOWN = VK_DOWN, - KN_DOWNLEFT = VK_END, - KN_DOWNRIGHT = VK_NEXT, - KN_E = VK_E, - KN_END = VK_END, - KN_EQUAL = VK_NONE_BB, - KN_ESC = VK_ESCAPE, - KN_E_DELETE = VK_DELETE, - KN_E_DOWN = VK_NUMPAD2, - KN_E_END = VK_NUMPAD1, - KN_E_HOME = VK_NUMPAD7, - KN_E_INSERT = VK_INSERT, - KN_E_LEFT = VK_NUMPAD4, - KN_E_PGDN = VK_NUMPAD3, - KN_E_PGUP = VK_NUMPAD9, - KN_E_RIGHT = VK_NUMPAD6, - KN_E_UP = VK_NUMPAD8, - KN_F = VK_F, - KN_F1 = VK_F1, - KN_F10 = 67, - KN_F11 = 68, - KN_F12 = 69, - KN_F2 = 59, - KN_F3 = 60, - KN_F4 = 61, - KN_F5 = 62, - KN_F6 = 63, - KN_F7 = 64, - KN_F8 = 65, - KN_F9 = 66, - KN_G = VK_G, - KN_GRAVE = VK_NONE_C0, - KN_H = VK_H, - KN_HOME = VK_HOME, - KN_I = VK_I, - KN_INSERT = VK_INSERT, - KN_J = VK_J, - KN_K = VK_K, - KN_KEYPAD_ASTERISK= VK_MULTIPLY, - KN_KEYPAD_MINUS = VK_SUBTRACT, - KN_KEYPAD_PLUS = VK_ADD, - KN_KEYPAD_RETURN = VK_RETURN, - KN_KEYPAD_SLASH = VK_DIVIDE, - KN_L = VK_L, - KN_LALT = VK_MENU, - KN_LBRACKET = VK_NONE_DB, - KN_LCTRL = VK_CONTROL, - KN_LEFT = VK_LEFT, - KN_LMOUSE = VK_LBUTTON, - KN_LSHIFT = VK_SHIFT, - KN_M = VK_M, - KN_MINUS = VK_NONE_BD, - KN_N = VK_N, - KN_NUMLOCK = VK_NUMLOCK, - KN_O = VK_O, - KN_P = VK_P, - KN_PAUSE = VK_PAUSE, - KN_PERIOD = VK_NONE_BE, - KN_PGDN = VK_NEXT, - KN_PGUP = VK_PRIOR, - KN_PRNTSCRN = VK_PRINT, - KN_Q = VK_Q, - KN_R = VK_R, - KN_RALT = VK_MENU, - KN_RBRACKET = VK_NONE_DD, - KN_RCTRL = VK_CONTROL, - KN_RETURN = VK_RETURN, - KN_RIGHT = VK_RIGHT, - KN_RMOUSE = VK_RBUTTON, - KN_RSHIFT = VK_SHIFT, - KN_S = VK_S, - KN_SCROLLLOCK = VK_SCROLL, - KN_SEMICOLON = VK_NONE_BA, - KN_SLASH = VK_NONE_BF, - KN_SPACE = VK_SPACE, - KN_SQUOTE = VK_NONE_DE, - KN_T = VK_T, - KN_TAB = VK_TAB, - KN_U = VK_U, - KN_UP = VK_UP, - KN_UPLEFT = VK_HOME, - KN_UPRIGHT = VK_PRIOR, - KN_V = VK_V, - KN_W = VK_W, - KN_X = VK_X, - KN_Y = VK_Y, - KN_Z = VK_Z, + KN_0, + KN_1, + KN_2, + KN_3, + KN_4, + KN_5, + KN_6, + KN_7, + KN_8, + KN_9, + KN_A, + KN_B, + KN_C, + KN_D, + KN_E, + KN_F, + KN_G, + KN_H, + KN_I, + KN_J, + KN_K, + KN_L, + KN_M, + KN_N, + KN_O, + KN_P, + KN_Q, + KN_R, + KN_S, + KN_T, + KN_U, + KN_V, + KN_W, + KN_X, + KN_Y, + KN_Z, + + KN_BACKSLASH, + KN_BACKSPACE, + KN_CAPSLOCK, + KN_CENTER, + KN_COMMA, + KN_DELETE, + KN_DOWN, + KN_DOWNLEFT, + KN_DOWNRIGHT, + KN_END, + KN_EQUAL, + KN_ESC, + KN_E_DELETE, + KN_E_DOWN, + KN_E_END, + KN_E_HOME, + KN_E_INSERT, + KN_E_LEFT, + KN_E_PGDN, + KN_E_PGUP, + KN_E_RIGHT, + KN_E_UP, + KN_GRAVE, + KN_HOME, + KN_INSERT, + KN_KEYPAD_ASTERISK, + KN_KEYPAD_MINUS, + KN_KEYPAD_PLUS, + KN_KEYPAD_RETURN, + KN_KEYPAD_SLASH, + KN_MINUS, + KN_NUMLOCK, + KN_PAUSE, + KN_PERIOD, + KN_PGDN, + KN_PGUP, + KN_PRNTSCRN, + KN_SCROLLLOCK, + KN_SEMICOLON, + KN_SLASH, + KN_SPACE, + KN_SQUOTE, + KN_TAB, + KN_UP, + KN_UPLEFT, + KN_UPRIGHT, + + KN_LALT, + KN_LBRACKET, + KN_LCTRL, + KN_LEFT, + KN_LMOUSE, + KN_LSHIFT, + + KN_RALT, + KN_RBRACKET, + KN_RCTRL, + KN_RETURN, + KN_RIGHT, + KN_RMOUSE, + KN_RSHIFT, + + KN_F1, + KN_F2, + KN_F3, + KN_F4, + KN_F5, + KN_F6, + KN_F7, + KN_F8, + KN_F9, + KN_F10, + KN_F11, + KN_F12, KN_SHIFT_BIT = WWKEY_SHIFT_BIT, KN_CTRL_BIT = WWKEY_CTRL_BIT, KN_ALT_BIT = WWKEY_ALT_BIT, KN_RLSE_BIT = WWKEY_RLS_BIT, KN_BUTTON = WWKEY_BTN_BIT, + KN_CAPSLOCK_BIT = WWKEY_SHIFT_BIT, } KeyNumType; diff --git a/code/redalert/mapscript.cpp b/code/redalert/mapscript.cpp index 4c74838..6608868 100644 --- a/code/redalert/mapscript.cpp +++ b/code/redalert/mapscript.cpp @@ -1,4286 +1,7605 @@ -// MapScript.cpp -// - -#include "FUNCTION.H" -#include "MapScript.h" +#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); +/*********************************************************************************************** + * 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) { - if (houseType != HOUSE_NONE) { + int houseType = lua_tointeger(L, -1); - HouseClass* this_house = HouseClass::As_Pointer((HousesType)houseType); + if (houseType != HOUSE_NONE) { - if (this_house != NULL) { + HouseClass* this_house = HouseClass::As_Pointer((HousesType)houseType); - if (this_house->ID == PlayerPtr->Class->House) { - PlayerPtr->Flag_To_Win(); - } - else { - PlayerPtr->Flag_To_Lose(); - } + if (this_house != NULL) { - bool success = this_house->Fire_Sale(); - lua_pushboolean(L, int(success)); + if (this_house->ID == PlayerPtr->Class->House) { + PlayerPtr->Flag_To_Win(); } - } - - 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; + else { + PlayerPtr->Flag_To_Lose(); } - 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); + bool success = this_house->Fire_Sale(); 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) { + return 1; +} - int in_x = lua_tointeger(L, 1); - int in_y = lua_tointeger(L, 2); +/*********************************************************************************************** + * 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) { - new AnimClass(ANIM_LZ_SMOKE, Cell_Coord(XY_Cell(in_x,in_y))); + int houseType = lua_tointeger(L, -1); - return 1; - } + if (houseType != HOUSE_NONE) { - /*********************************************************************************************** - * 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) { + HouseClass* this_house = HouseClass::As_Pointer((HousesType)houseType); - int houseType = lua_tointeger(L, -1); + if (this_house != NULL) { - 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)); + if (this_house->ID == PlayerPtr->Class->House) { + PlayerPtr->Flag_To_Lose(); } - } - - 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); - Play_Movie((VQType)ret); - 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; - + else { + PlayerPtr->Flag_To_Win(); } + lua_pushboolean(L, 1); } - - 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) { + return 1; +} - int houseType = lua_tointeger(L, -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) { - if (houseType != HOUSE_NONE) { + int houseType = lua_tointeger(L, -1); - HouseClass* this_house = HouseClass::As_Pointer((HousesType)houseType); + if (houseType != HOUSE_NONE) { - if (this_house != NULL) { - this_house->Blockage++; + 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); + Play_Movie((VQType)ret); + 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_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++) { + 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_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); + return 1; +} - if (!PlayerPtr->IsVisionary) { - Map.Sight_From(Scen.Waypoint[ret], Rule.GapShroudRadius, PlayerPtr, false); - } +/*********************************************************************************************** + * 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); - return 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); } - /*********************************************************************************************** - * 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); + return 1; +} - if (!PlayerPtr->IsVisionary) { - int zone = Map[Scen.Waypoint[ret]].Zones[MZONE_CRUSHER]; +/*********************************************************************************************** + * 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; +} - for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) { - if (Map[cell].Zones[MZONE_CRUSHER] == zone) { - Map.Map_Cell(cell, PlayerPtr); - } - } +/*********************************************************************************************** + * 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; +} - 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; } - /*********************************************************************************************** - * 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); + return 1; +} - Sound_Effect((VocType)ret); +/*********************************************************************************************** + * 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; +} - 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); - /*********************************************************************************************** - * 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); + TriggerClass* this_trigger = Triggers.Ptr(triggerIndex); - 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 repeating special weapon * - * * - * 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) { - + if (this_trigger != NULL) { 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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) { - - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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) { - - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - - const char* in_function = 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); - - // 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); - - const char* in_function = 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); - - // 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); - - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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) { - - const char* in_function = 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); - - // 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); - const char* in_function = 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); - - // 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 = new MapScriptObject; - - 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->ID); // Return index for ultrafast 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; - } + 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); } } - - 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) { + return 1; +} - int triggerIndex = lua_tointeger(L, 1); - unsigned char isPersistent = lua_tointeger(L, 2); +/*********************************************************************************************** + * 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) { - TriggerClass* trigger = Triggers.Ptr(triggerIndex); + int weaponType = lua_tointeger(L, 1); - if (trigger != NULL) { + int houseType = -1; + bool immediate = -1; - TriggerTypeClass* trigger_type = trigger->Class; + // Optional houseType parameter + if (lua_gettop(L) >= 2) { + houseType = lua_tointeger(L, 2); + } - trigger_type->IsPersistant = (TriggerTypeClass::PersistantType)isPersistent; + // 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; } - + return 1; +} -/********************************************************************************************** -* Mission Utility Functions * -*=============================================================================================*/ +/*********************************************************************************************** + * 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) { - /*********************************************************************************************** - * 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; + 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); } -/********************************************************************************************** -* Status / Location Utility Functions * -*=============================================================================================*/ + // Optional immediate parameter + if (lua_gettop(L) == 3) { + immediate = lua_toboolean(L, 3); + } - /*********************************************************************************************** - * 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) { + for (int h_index = 0; h_index < Houses.Count(); h_index++) { - int cashToGive = lua_tointeger(L, 1); + HouseClass* house = Houses.Ptr(h_index); - int houseType = -1; + if (house->ID == houseType || houseType == -1) { - // Optional houseType parameter - if (lua_gettop(L) == 2) { - houseType = lua_tointeger(L, 2); + 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) { - if (cashToGive < 0) { - house->Spend_Money(max(0, cashToGive * -1)); - } - else { - house->Refund_Money(cashToGive); - } + 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; } - /*********************************************************************************************** - * 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) { + lua_pushnumber(L, -1); - int houseType = lua_tointeger(L, -1); + return 1; - long result = -1; +} - for (int h_index = 0; h_index < Houses.Count(); h_index++) { +/*********************************************************************************************** + * 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) { - HouseClass* house = Houses.Ptr(h_index); + int houseType = lua_tointeger(L, 1); + int objectType = lua_tointeger(L, 2); - if (house->ID == houseType || houseType == -1) { - result = house->Credits; + 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; } } - lua_pushnumber(L, result); + // 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]; - return 1; - } + if (_trigger != NULL) { + if (_trigger == merge_trigger) { - /*********************************************************************************************** - * 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); + MapTriggers.Delete(t_index); - 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++; + 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; } } } - lua_pushnumber(L, result); - return 1; + // 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; } - /*********************************************************************************************** - * 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); + return 1; +} - int houseType = -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; + } - // 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; + } + + 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; + } - 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++; + return -1; +} - // Within search area - } - else { +/********************************************************************************************** +* 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 this_x = Cell_X(Coord_Cell(aircraft->Coord)); - int this_y = Cell_Y(Coord_Cell(aircraft->Coord)); + int buildingTypeID = lua_tointeger(L, 1); + int attribute_type = lua_tointeger(L, 2); - if (this_x >= in_x1 && this_x <= in_x2 && this_y >= in_y1 && this_y <= in_y2) { - result++; - } - } + 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; } } - lua_pushnumber(L, result); - return 1; - } + }break; + case ATTRIBUTE_SECONDARY_WEAPON: { - /*********************************************************************************************** - * 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 attribute_value = lua_tointeger(L, 3); - int houseType = -1; - - // Optional houseType parameter - if (lua_gettop(L) == 2) { - houseType = lua_tointeger(L, 2); + 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); } - // 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; + // Set the attribute + if (attribute_value < 0) { + this_type_class->SecondaryWeapon = NULL; } - 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++; - } - } - - } + else { + WeaponTypeClass* this_weapon = Weapons.Ptr(attribute_value); + if (this_weapon != NULL) { + this_type_class->SecondaryWeapon = this_weapon; + } + else { + this_type_class->SecondaryWeapon = NULL; } } - lua_pushnumber(L, result); - return 1; - } + }break; + case ATTRIBUTE_SPEED: { - /*********************************************************************************************** - * 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 attribute_value = lua_tointeger(L, 3); - int houseType = -1; + // 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); - // Optional houseType parameter - if (lua_gettop(L) == 2) { - houseType = lua_tointeger(L, 2); - } + // Set the attribute + this_type_class->Speed = (SpeedType)attribute_value; - // 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; - } + }break; + case ATTRIBUTE_MAX_SPEED: { - int result = 0; - for (int u_index = 0; u_index < Infantry.Count(); u_index++) { - InfantryClass* infantry = Infantry.Ptr(u_index); + int attribute_value = lua_tointeger(L, 3); - if (infantry->Owner() == houseType || houseType == -1) { - if (infantry->Class->Type == infantryType || infantryType == -1) { + // 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); - // Count, in general - if (within_area == false) { - result++; + // Set the attribute + this_type_class->MaxSpeed = (MPHType)attribute_value; - // Within search area - } - else { + }break; + case ATTRIBUTE_MAX_AMMO: { - int this_x = Cell_X(Coord_Cell(infantry->Coord)); - int this_y = Cell_Y(Coord_Cell(infantry->Coord)); + int attribute_value = lua_tointeger(L, 3); - if (this_x >= in_x1 && this_x <= in_x2 && this_y >= in_y1 && this_y <= in_y2) { - result++; - } - } + // 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; } - } - } - - 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++; - } - } - + 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; } - } - lua_pushnumber(L, result); - return 1; - } + }break; - /*********************************************************************************************** - * 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); + // Unit Specific + case RTTI_UNITTYPE: { - if (ret > 0 && ret < sizeof(Scen.Waypoint)) { + // What type of attribute? + switch (attribute_type) { + case ATTRIBUTE_CRATE_GOODIE: { - lua_pushnumber(L, Cell_X(Scen.Waypoint[ret])); + 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; - } - - 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])); + }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; + } - lua_pushnumber(L, -1); - - return -1; } + + 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 = lua_tointeger(L, 3); + int in_y = lua_tointeger(L, 4); + + 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(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_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 = lua_tointeger(L, 3); + int in_y = lua_tointeger(L, 4); + + 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(Cell_Coord(XY_Cell(in_x, in_y)), 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(Cell_Coord(XY_Cell(in_x, in_y)), 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::iterator it = Scen.mapScript->ObjectCache.begin(); it != Scen.mapScript->ObjectCache.end(); ++it) {//Error 2-4 - - MapScriptObject* thisCacheObject = (MapScriptObject*)(*it); - - // Here it is - if (thisCacheObject->ID == 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 = new MapScriptObject; - 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(this_object)->Class->Type; - dynamic_cast(this_object)->Trigger = input_trigger; - }break; - case RTTI_UNIT:{ - input_trigger->Class->Event1.Data.Unit = dynamic_cast(this_object)->Class->Type; - dynamic_cast(this_object)->Trigger = input_trigger; - }break; - case RTTI_AIRCRAFT:{ - input_trigger->Class->Event1.Data.Aircraft = dynamic_cast(this_object)->Class->Type; - dynamic_cast(this_object)->Trigger = input_trigger; - }break; - case RTTI_INFANTRY:{ - input_trigger->Class->Event1.Data.Infantry = dynamic_cast(this_object)->Class->Type; - dynamic_cast(this_object)->Trigger = input_trigger; - }break; - } - - } +/*********************************************************************************************** + * 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; } - /*********************************************************************************************** - * 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) { + // Look through cache for object with ID, and return it + for (std::vector::iterator it = Scen.mapScript->ObjectCache.begin(); it != Scen.mapScript->ObjectCache.end(); ++it) {//Error 2-4 - if (input_object_id < 0) { - return false; - } + MapScriptObject* thisCacheObject = (MapScriptObject*)(*it); - for (int _index = 0; _index < Buildings.Count(); _index++) { - BuildingClass* _object = Buildings.Ptr(_index); + // Here it is + if (thisCacheObject->UID == input_object_id) { - if (_object->ID == input_object_id) { - return _index; + // 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; } + } - 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) { + // 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; - if (input_object_id < 0) { - return false; } + else { + _objectIndex = Script_AircraftIndexFromID(input_object_id); + AircraftClass* this_aircraft = Aircraft.Ptr(_objectIndex); + if (this_aircraft != NULL) { - for (int _index = 0; _index < Units.Count(); _index++) { - UnitClass* _object = Units.Ptr(_index); + CacheObject->ID = this_aircraft->ID; + CacheObject->RTTI = this_aircraft->RTTI; + CacheObject->classIndex = _objectIndex; + Scen.mapScript->ObjectCache.push_back(CacheObject); - if (_object->ID == input_object_id) { - return _index; + 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; + + } + } } } - - 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) { + // 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; - if (input_object_id < 0) { - return false; - } + return NULL; +} - for (int _index = 0; _index < Aircraft.Count(); _index++) { - AircraftClass* _object = Aircraft.Ptr(_index); +/*********************************************************************************************** + * 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 (_object->ID == input_object_id) { - return _index; - } - } - - return -1; + if (input_object_id < 0) { + return false; } - /*********************************************************************************************** - * 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; + if (input_trigger == NULL) { + return false; } - /*********************************************************************************************** - * 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) { + ObjectClass* this_object = Script_GetCacheObject(input_object_id); - if (input_object_id < 0) { - return false; + if (this_object != NULL) { + + switch (this_object->RTTI) { + case RTTI_BUILDING: { + input_trigger->Class->Event1.Data.Structure = dynamic_cast(this_object)->Class->Type; + dynamic_cast(this_object)->Trigger = input_trigger; + }break; + case RTTI_UNIT: { + input_trigger->Class->Event1.Data.Unit = dynamic_cast(this_object)->Class->Type; + dynamic_cast(this_object)->Trigger = input_trigger; + }break; + case RTTI_AIRCRAFT: { + input_trigger->Class->Event1.Data.Aircraft = dynamic_cast(this_object)->Class->Type; + dynamic_cast(this_object)->Trigger = input_trigger; + }break; + case RTTI_INFANTRY: { + input_trigger->Class->Event1.Data.Infantry = dynamic_cast(this_object)->Class->Type; + dynamic_cast(this_object)->Trigger = input_trigger; + }break; } - for (int _index = 0; _index < Vessels.Count(); _index++) { - VesselClass* _object = Vessels.Ptr(_index); - - if (_object->ID == input_object_id) { - return _index; - } - } - - return -1; } - /*********************************************************************************************** - * 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) { + return false; +} - lua_getglobal(L, functionName); - lua_pcall(L, 0, 0, 0); - - } +/*********************************************************************************************** + * 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) { - /*********************************************************************************************** - * 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) + 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::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) { - - // 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); + delete ObjectCache[i]; } - /*********************************************************************************************** - * MapScript::Deinit - Deinitialize/free any data used by MapScript (used within destructor) * - * * - * SCRIPT INPUT: none * - * * - * SCRIPT OUTPUT: void * - * * - * WARNINGS: ? * - * * - *=============================================================================================*/ - void MapScript::Deinit() { + ObjectCache.clear(); + + // We will now restore any default Object attributes that were changed in the script + for (std::vector::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; - for (int i = 0; i < ObjectCache.size(); ++i) - { - delete ObjectCache[i]; } - ObjectCache.clear(); - } - /*********************************************************************************************** - * 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) { - char scriptName[256]; + // Remove any cached Object Attributes + for (int i = 0; i < DefaultObjectTypeAttributeCache.size(); ++i) + { + delete DefaultObjectTypeAttributeCache[i]; + } - // Build map path - sprintf(scriptName, "scripts/%s.script", mapName); - L = luaL_newstate(); - - luaL_openlibs(L); - - // Load file - if (luaL_loadfile(L, scriptName)){ - 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)) { - L = NULL; - return false; - } - - // Reserve object cache memory - ObjectCache.reserve(2000); - - /********************************************************************************************** - * 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, "GetCellObject", Script_GetCellObject); // Gets an object (ID - building/vehicle/aircraft/infantry/vessel), if any, at [Cell/X],[Cell/Y] - 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? - - /********************************************************************************************** - * 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 - - /********************************************************************************************** - * Script Globals * - *=============================================================================================*/ - - lua_pushnumber(L, PlayerPtr->ID); // Local player (house) index - lua_setglobal(L, "_localPlayer"); + DefaultObjectTypeAttributeCache.clear(); - return true; - } \ No newline at end of file + 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; +} \ No newline at end of file diff --git a/code/redalert/mapscript.h b/code/redalert/mapscript.h index b3bf2d4..3b914f5 100644 --- a/code/redalert/mapscript.h +++ b/code/redalert/mapscript.h @@ -1,4 +1,4 @@ -// MapScript.h +// mapscript.h // #ifndef MAPSCRIPT_H @@ -15,11 +15,22 @@ extern "C" { // Object Cache Item // Stores an id lookup table struct MapScriptObject { + + int UID; // The UID of the object (to prevent ID collisions) + int ID=-1; // The object's "Global ID" int classIndex=-1; // The object's "Global ID" RTTIType RTTI; // The type of object + }; +// Stores defaults of object attributes whenever they are changed for the first time (for later restoration) +struct MapScriptDefaultObjectAttribute { + RTTIType RTTI; // The type of object + int ID=-1; // The index of the object in its heap + int attribute; + int value; +}; // // MapScript Class @@ -27,6 +38,7 @@ struct MapScriptObject { class MapScript { public: + int cUID = 0; ~MapScript() { Deinit(); }; @@ -34,15 +46,114 @@ public: bool Init(const char* mapName); void Deinit(); + MapScriptObject* CreateCacheObject(); + void CallFunction(const char* functionName); void SetLuaPath(const char* input_path); std::vector ObjectCache; + std::vector DefaultObjectTypeAttributeCache; private: lua_State* L; }; + + +// Enums +typedef enum MapScriptObjectAttributeType : char { + + // Techno types + ATTRIBUTE_TYPE=0, + ATTRIBUTE_STRENGTH, + ATTRIBUTE_MAX_STRENGTH, + ATTRIBUTE_COST, + ATTRIBUTE_SIGHT_RANGE, + ATTRIBUTE_TECH_LEVEL, + ATTRIBUTE_ARMOR, + ATTRIBUTE_PRIMARY_WEAPON, + ATTRIBUTE_SECONDARY_WEAPON, + ATTRIBUTE_SPEED, + ATTRIBUTE_MAX_SPEED, + ATTRIBUTE_MAX_AMMO, + ATTRIBUTE_ROTATION_SPEED, + ATTRIBUTE_CRUSHABLE, + ATTRIBUTE_STEALTHY, + ATTRIBUTE_SELECTABLE, + ATTRIBUTE_LEGAL_TARGET, + ATTRIBUTE_REPAIRABLE, + ATTRIBUTE_SELF_HEALING, + ATTRIBUTE_EXPLODES, + ATTRIBUTE_HAS_CREW, + ATTRIBUTE_MAX_PASSENGERS, + ATTRIBUTE_IS_REPAIRING, + + // Building Specific + ATTRIBUTE_CAPACITY, + ATTRIBUTE_POWER, + ATTRIBUTE_SELLABLE, + + // Unit Specific + ATTRIBUTE_CRATE_GOODIE, + ATTRIBUTE_CRUSHER, + ATTRIBUTE_HARVEST, + ATTRIBUTE_RADAR_EQUIPPED, + ATTRIBUTE_JAMMER, + ATTRIBUTE_GAPPER, + + // Infantry Specific + ATTRIBUTE_FEMALE, + ATTRIBUTE_CAPTURE, + ATTRIBUTE_FRAIDY_CAT, + ATTRIBUTE_CIVILIAN, + ATTRIBUTE_BOMBER, + ATTRIBUTE_DOG + + +} MapScriptObjectAttributeType; + +// Enums +typedef enum MapScriptHouseAttributeType : char { + + // Techno types + HOUSE_ATTRIBUTE_IQ = 0, + HOUSE_ATTRIBUTE_TECH_LEVEL, + HOUSE_ATTRIBUTE_IS_HUMAN, + HOUSE_ATTRIBUTE_FIREPOWER_BIAS, + HOUSE_ATTRIBUTE_GROUNDSPEED_BIAS, + HOUSE_ATTRIBUTE_ARMOR_BIAS, + HOUSE_ATTRIBUTE_ROF_BIAS, + HOUSE_ATTRIBUTE_COST_BIAS, + HOUSE_ATTRIBUTE_REPAIR_DELAY, + HOUSE_ATTRIBUTE_BUILD_DELAY, + HOUSE_ATTRIBUTE_STARTED, + HOUSE_ATTRIBUTE_ALERTED, + HOUSE_ATTRIBUTE_BASE_BUILDING, + HOUSE_ATTRIBUTE_DISCOVERED, + HOUSE_ATTRIBUTE_CAPACITY, + HOUSE_ATTRIBUTE_TIBERIUM, + HOUSE_ATTRIBUTE_CREDITS, + HOUSE_ATTRIBUTE_ALERT_TIMER, + HOUSE_ATTRIBUTE_REPAIR_TIMER, + HOUSE_ATTRIBUTE_POINTS, + HOUSE_ATTRIBUTE_DESTROYED_BUILDINGS, + HOUSE_ATTRIBUTE_DESTROYED_VEHICLES, + HOUSE_ATTRIBUTE_DESTROYED_INFANTRY, + HOUSE_ATTRIBUTE_DESTROYED_AIRCRAFT, + HOUSE_ATTRIBUTE_DESTROYED_VESSELS, + HOUSE_ATTRIBUTE_CAPTURED_BUILDINGS, + HOUSE_ATTRIBUTE_CRATES, + HOUSE_ATTRIBUTE_BUILDING_FACTORIES, + HOUSE_ATTRIBUTE_UNIT_FACTORIES, + HOUSE_ATTRIBUTE_INFANTRY_FACTORIES, + HOUSE_ATTRIBUTE_AIRCRAFT_FACTORIES, + HOUSE_ATTRIBUTE_VESSEL_FACTORIES, + HOUSE_ATTRIBUTE_POWER, + HOUSE_ATTRIBUTE_DRAIN, + HOUSE_ATTRIBUTE_LAST_ATTACKER + +} MapScriptHouseAttributeType; + // Non-Class-Functions bool Script_SetObjectTrigger(int input_object_id, TriggerClass* input_trigger); ObjectClass* Script_GetCacheObject(int input_object_id); @@ -53,4 +164,9 @@ int Script_AircraftIndexFromID(int input_object_id); int Script_InfantryIndexFromID(int input_object_id); int Script_VesselIndexFromID(int input_object_id); +static int Script_SetObjectTypeAttribute(lua_State* L, TechnoTypeClass* this_type_class, MapScriptObjectAttributeType attribute_type); +static int Script_GetObjectTypeAttribute(lua_State* L, TechnoTypeClass* this_type_class, MapScriptObjectAttributeType attribute_type); + +void Script_CacheDefaultObjectTypeAttribute(RTTIType input_rtti, int input_id, MapScriptObjectAttributeType input_attribute, int input_value); + #endif \ No newline at end of file diff --git a/code/redalert/options.cpp b/code/redalert/options.cpp index cff3732..734ddb1 100644 --- a/code/redalert/options.cpp +++ b/code/redalert/options.cpp @@ -591,6 +591,7 @@ void OptionsClass::Load_Settings(void) SlowPalette = ini.Get_Bool(OPTIONS, "SlowPalette", SlowPalette); IsPaletteScroll = ini.Get_Bool(OPTIONS, "PaletteScroll", IsPaletteScroll); + /* KeyForceMove1 = (KeyNumType)ini.Get_Int(HotkeyName, "KeyForceMove1", KeyForceMove1); KeyForceMove2 = (KeyNumType)ini.Get_Int(HotkeyName, "KeyForceMove2", KeyForceMove2); KeyForceAttack1 = (KeyNumType)ini.Get_Int(HotkeyName, "KeyForceAttack1", KeyForceAttack1); @@ -641,7 +642,6 @@ void OptionsClass::Load_Settings(void) KeyTeam9 = (KeyNumType)ini.Get_Int(HotkeyName, "KeyTeam9", KeyTeam9); KeyTeam10 = (KeyNumType)ini.Get_Int(HotkeyName, "KeyTeam10", KeyTeam10); - #ifdef WIN32 KeyForceMove1 = (KeyNumType)(KeyForceMove1 & ~WWKEY_VK_BIT); KeyForceMove2 = (KeyNumType)(KeyForceMove2 & ~WWKEY_VK_BIT); @@ -693,6 +693,7 @@ void OptionsClass::Load_Settings(void) KeyTeam9 = (KeyNumType)(KeyTeam9 & ~WWKEY_VK_BIT); KeyTeam10 = (KeyNumType)(KeyTeam10 & ~WWKEY_VK_BIT); #endif + */ } diff --git a/code/redalert/power.cpp b/code/redalert/power.cpp index b9118ba..8c4edea 100644 --- a/code/redalert/power.cpp +++ b/code/redalert/power.cpp @@ -44,11 +44,11 @@ #include "function.h" -/* -** Points to the shape to use for the "desired" power level indicator. -*/ -void const * PowerClass::PowerShape; -void const * PowerClass::PowerBarShape; + /* + ** Points to the shape to use for the "desired" power level indicator. + */ +void const* PowerClass::PowerShape; +void const* PowerClass::PowerBarShape; PowerClass::PowerButtonClass PowerClass::PowerButton; @@ -137,8 +137,8 @@ void PowerClass::One_Time(void) RadarClass::One_Time(); PowerButton.X = ScreenWidth - (640 - (POWER_X * RESFACTOR)); PowerButton.Y = POWER_Y * RESFACTOR; - PowerButton.Width = (POWER_WIDTH * RESFACTOR)-1; - PowerButton.Height = ScreenHeight - ( POWER_Y * RESFACTOR ) ;// POWER_HEIGHT* RESFACTOR; + PowerButton.Width = (POWER_WIDTH * RESFACTOR) - 1; + PowerButton.Height = ScreenHeight - (POWER_Y * RESFACTOR);// POWER_HEIGHT* RESFACTOR; PowerShape = MFCD::Retrieve("POWER.SHP"); PowerBarShape = MFCD::Retrieve("POWERBAR.SHP"); } @@ -162,13 +162,14 @@ void PowerClass::One_Time(void) *=============================================================================================*/ void PowerClass::Draw_It(bool complete) { - static int _modtable[]={ + static int _modtable[] = { 0, -1, 0, 1, 0, -1, -2, -1, 0, 1, 2, 1 ,0 }; -// jmarshall - render the world before the power bar. + // jmarshall - render the world before the power bar. RadarClass::Draw_It(complete); -// jmarshall end + // jmarshall end + { BStart(BENCH_POWER); @@ -176,7 +177,7 @@ void PowerClass::Draw_It(bool complete) if (Map.IsSidebarActive) { IsToRedraw = false; ShapeFlags_Type flags = SHAPE_NORMAL; - void const * remap = NULL; + void const* remap = NULL; if (FlashTimer > 1 && ((FlashTimer % 3) & 0x01) != 0) { flags = flags | SHAPE_FADING; @@ -190,25 +191,23 @@ void PowerClass::Draw_It(bool complete) int bottomOfBar = (88 * RESFACTOR) + 56; - while(bottomOfBar < PowerButton.Height + 34 ) + while (bottomOfBar < PowerButton.Height + 42) { CC_Draw_Shape(PowerBarShape, 1, ScreenWidth - (640 - (240 * RESFACTOR)), bottomOfBar, WINDOW_MAIN, flags | SHAPE_NORMAL | SHAPE_WIN_REL, remap); bottomOfBar += 8 * RESFACTOR; } - int bottom = ( PowerButton.Y * RESFACTOR ) + PowerButton.Height; + int bottom = bottomOfBar + (28 * RESFACTOR); /* ** Determine how much the power production exceeds or falls short ** of power demands. */ - int power_height = (PowerHeight == DesiredPowerHeight) ? PowerHeight + (_modtable[PowerBounce] * PowerDir) : PowerHeight; - int drain_height = (DrainHeight == DesiredDrainHeight) ? DrainHeight + (_modtable[DrainBounce] * DrainDir) : DrainHeight; + int power_height = (PowerHeight == DesiredPowerHeight) ? PowerHeight + (_modtable[PowerBounce] * PowerDir) : PowerHeight; + int drain_height = (DrainHeight == DesiredDrainHeight) ? DrainHeight + (_modtable[DrainBounce] * DrainDir) : DrainHeight; power_height = Bound(power_height, 0, PowerButton.Height - 2); drain_height = Bound(drain_height, 0, PowerButton.Height - 2); - bottom -= (15 * RESFACTOR); - /* ** Draw the power output graphic on top of the power bar framework. */ @@ -233,23 +232,26 @@ void PowerClass::Draw_It(bool complete) ** ST - 5/2/96 11:23AM */ - power_height = (power_height*(76*RESFACTOR+1)) / (53*RESFACTOR+1); - drain_height = (drain_height*(76*RESFACTOR+1)) / (53*RESFACTOR+1); + power_height = (power_height * (76 * RESFACTOR + 1)) / (53 * RESFACTOR + 1); + drain_height = (drain_height * (76 * RESFACTOR + 1)) / (53 * RESFACTOR + 1); //bottom = (175*RESFACTOR)+1; - LogicPage->Fill_Rect(ScreenWidth - (640 - (245*RESFACTOR)), bottom - power_height, ScreenWidth - (640 - (245*RESFACTOR+1)), bottom, color2 ); - LogicPage->Fill_Rect(ScreenWidth - (640 - (246*RESFACTOR)), bottom - power_height, ScreenWidth - (640 - (246*RESFACTOR+1)), bottom, color1 ); + LogicPage->Fill_Rect(ScreenWidth - (640 - (245 * RESFACTOR)), bottom - power_height, ScreenWidth - (640 - (245 * RESFACTOR + 1)), bottom, color2); + LogicPage->Fill_Rect(ScreenWidth - (640 - (246 * RESFACTOR)), bottom - power_height, ScreenWidth - (640 - (246 * RESFACTOR + 1)), bottom, color1); } /* ** Draw the power drain threshold marker. */ - CC_Draw_Shape(PowerShape, 0, ScreenWidth - (640 - (((POWER_X * RESFACTOR)) +RESFACTOR)), bottom - (drain_height + (2 * RESFACTOR)), WINDOW_MAIN, flags | SHAPE_NORMAL, remap); + if (PlayerPtr->Drain > 0) + { + CC_Draw_Shape(PowerShape, 0, ScreenWidth - (640 - (((POWER_X * RESFACTOR)) + RESFACTOR)), bottom - (drain_height + (2 * RESFACTOR)), WINDOW_MAIN, flags | SHAPE_NORMAL, remap); + } } LogicPage->Unlock(); } BEnd(BENCH_POWER); - } + } } @@ -270,11 +272,11 @@ void PowerClass::Draw_It(bool complete) * 12/20/1994 JLB : Created. * * 12/31/1994 JLB : Uses mouse coordinate parameters. * *=============================================================================================*/ -void PowerClass::AI(KeyNumType &input, int x, int y) +void PowerClass::AI(KeyNumType& input, int x, int y) { if (Map.IsSidebarActive /*IsActive*/) { int olddrain = DrainHeight; - int oldpower = PowerHeight; + int oldpower = PowerHeight; /* @@ -283,13 +285,15 @@ void PowerClass::AI(KeyNumType &input, int x, int y) */ if (PlayerPtr->Power != RecordedPower) { DesiredPowerHeight = Power_Height(PlayerPtr->Power); - RecordedPower = PlayerPtr->Power; - PowerBounce = 12; + RecordedPower = PlayerPtr->Power; + PowerBounce = 12; if (PowerHeight > DesiredPowerHeight) { PowerDir = -1; - } else if (PowerHeight < DesiredPowerHeight) { + } + else if (PowerHeight < DesiredPowerHeight) { PowerDir = 1; - } else { + } + else { PowerBounce = 0; } } @@ -300,13 +304,15 @@ void PowerClass::AI(KeyNumType &input, int x, int y) */ if (PlayerPtr->Drain != RecordedDrain) { DesiredDrainHeight = Power_Height(PlayerPtr->Drain); - RecordedDrain = PlayerPtr->Drain; - DrainBounce = 12; + RecordedDrain = PlayerPtr->Drain; + DrainBounce = 12; if (DrainHeight > DesiredDrainHeight) { DrainDir = -1; - } else if (DrainHeight < DesiredDrainHeight) { + } + else if (DrainHeight < DesiredDrainHeight) { DrainDir = 1; - } else { + } + else { DrainBounce = 0; } } @@ -315,7 +321,8 @@ void PowerClass::AI(KeyNumType &input, int x, int y) IsToRedraw = true; Flag_To_Redraw(false); DrainBounce--; - } else { + } + else { /* ** If we need to move the drain height then do so. */ @@ -328,7 +335,8 @@ void PowerClass::AI(KeyNumType &input, int x, int y) IsToRedraw = true; Flag_To_Redraw(false); PowerBounce--; - } else { + } + else { /* ** If we need to move the power height then do so. */ @@ -345,7 +353,7 @@ void PowerClass::AI(KeyNumType &input, int x, int y) /* ** Flag to redraw if the power bar flash effect has expired. */ -// if (FlashTimer == 1) { + // if (FlashTimer == 1) { if (FlashTimer > 0) { IsToRedraw = true; Flag_To_Redraw(false); @@ -374,7 +382,7 @@ void PowerClass::AI(KeyNumType &input, int x, int y) * HISTORY: * * 06/01/1995 JLB : Created. * *=============================================================================================*/ -void PowerClass::Refresh_Cells(CELL cell, short const * list) +void PowerClass::Refresh_Cells(CELL cell, short const* list) { if (*list == REFRESH_SIDEBAR) { IsToRedraw = true; @@ -398,16 +406,16 @@ void PowerClass::Refresh_Cells(CELL cell, short const * list) *=========================================================================*/ int PowerClass::Power_Height(int value) { - int num = value/ POWER_STEP_LEVEL; // figure out the initial num of DRAIN_VALUE's - int retval = 0; // currently there is no power + int num = value / POWER_STEP_LEVEL; // figure out the initial num of DRAIN_VALUE's + int retval = 0; // currently there is no power /* ** Loop through the different hundreds figuring out the fractional piece ** of each. */ - for (int lp = 0; lp < num; lp ++) { - retval = retval + (((POWER_HEIGHT - 2) - retval) / POWER_STEP_FACTOR); - value -= POWER_STEP_LEVEL; + for (int lp = 0; lp < num; lp++) { + retval = retval + (((POWER_HEIGHT - 2) - retval) / POWER_STEP_FACTOR); + value -= POWER_STEP_LEVEL; } /* @@ -417,7 +425,7 @@ int PowerClass::Power_Height(int value) retval = retval + (((((POWER_HEIGHT - 2) - retval) / POWER_STEP_FACTOR) * value) / POWER_STEP_LEVEL); } - retval = Bound(retval, 0, POWER_HEIGHT-2); + retval = Bound(retval, 0, POWER_HEIGHT - 2); return(retval); } @@ -439,7 +447,7 @@ int PowerClass::Power_Height(int value) * HISTORY: * * 08/07/1995 JLB : Created. * *=============================================================================================*/ -int PowerClass::PowerButtonClass::Action(unsigned flags, KeyNumType & key) +int PowerClass::PowerButtonClass::Action(unsigned flags, KeyNumType& key) { if (!Map.IsSidebarActive) { return(false); @@ -452,7 +460,8 @@ int PowerClass::PowerButtonClass::Action(unsigned flags, KeyNumType & key) Map.Override_Mouse_Shape(MOUSE_NORMAL); if (PlayerPtr->Power_Fraction() < 1 && PlayerPtr->Power > 0) { Map.Help_Text(TXT_POWER_OUTPUT_LOW, -1, -1, GadgetClass::Get_Color_Scheme()->Color); - } else { + } + else { Map.Help_Text(TXT_POWER_OUTPUT, -1, -1, GadgetClass::Get_Color_Scheme()->Color); } GadgetClass::Action(flags, key); diff --git a/code/redalert/shapebtn.cpp b/code/redalert/shapebtn.cpp index ea07f16..7d1dc59 100644 --- a/code/redalert/shapebtn.cpp +++ b/code/redalert/shapebtn.cpp @@ -164,6 +164,7 @@ int ShapeButtonClass::Draw_Me(int forced) } CC_Draw_Shape(ShapeData, shapenum, X, Y, WINDOW_MAIN, SHAPE_NORMAL); + /* ** Display the mouse. */ diff --git a/code/redalert/sidebar.cpp b/code/redalert/sidebar.cpp index f3db0df..06d53d2 100644 --- a/code/redalert/sidebar.cpp +++ b/code/redalert/sidebar.cpp @@ -76,19 +76,19 @@ #include "function.h" -//#undef RESFACTOR -//#define RESFACTOR 1 + //#undef RESFACTOR + //#define RESFACTOR 1 -void * SidebarClass::SidebarShape = NULL; -void * SidebarClass::SidebarMiddleShape = NULL; -void * SidebarClass::SidebarBottomShape = NULL; +void* SidebarClass::SidebarShape = NULL; +void* SidebarClass::SidebarMiddleShape = NULL; +void* SidebarClass::SidebarBottomShape = NULL; /*************************************************************************** ** This holds the translucent table for use with the construction clock ** animation. */ -char SidebarClass::StripClass::ClockTranslucentTable[(1+1)*256]; +char SidebarClass::StripClass::ClockTranslucentTable[(1 + 1) * 256]; /*************************************************************************** @@ -121,9 +121,9 @@ SidebarClass::StripClass::SelectButton[COLUMNS][MAX_VISIBLE]; /* ** Shape data pointers */ -void * SidebarClass::StripClass::LogoShapes = NULL; -void const * SidebarClass::StripClass::ClockShapes; -void const * SidebarClass::StripClass::SpecialShapes[SPC_COUNT]; +void* SidebarClass::StripClass::LogoShapes = NULL; +void const* SidebarClass::StripClass::ClockShapes; +void const* SidebarClass::StripClass::SpecialShapes[SPC_COUNT]; /*********************************************************************************************** @@ -169,16 +169,16 @@ SidebarClass::SidebarClass(void) : * HISTORY: * * 08/06/1996 JLB : Created. * *=============================================================================================*/ -SidebarClass::SidebarClass(NoInitClass const & x) : PowerClass(x) +SidebarClass::SidebarClass(NoInitClass const& x) : PowerClass(x) { /* ** Set up the coordinates for the sidebar strips. These coordinates are for ** the upper left corner. */ -// Column[0].X = COLUMN_ONE_X * RESFACTOR; -// Column[0].Y = COLUMN_ONE_Y * RESFACTOR; -// Column[1].X = COLUMN_TWO_X * RESFACTOR; -// Column[1].Y = COLUMN_TWO_Y * RESFACTOR; + // Column[0].X = COLUMN_ONE_X * RESFACTOR; + // Column[0].Y = COLUMN_ONE_Y * RESFACTOR; + // Column[1].X = COLUMN_TWO_X * RESFACTOR; + // Column[1].Y = COLUMN_TWO_Y * RESFACTOR; } @@ -224,25 +224,25 @@ void SidebarClass::One_Time(void) ** code so that as the sidebar buildable buttons scroll, they get properly ** clipped at the top and bottom edges. */ - WindowList[WINDOW_SIDEBAR][WINDOWX] = ((SIDE_X+8)) * RESFACTOR; + WindowList[WINDOW_SIDEBAR][WINDOWX] = ((SIDE_X + 8)) * RESFACTOR; WindowList[WINDOW_SIDEBAR][WINDOWY] = (SIDE_Y + 1 + TOP_HEIGHT) * RESFACTOR; - WindowList[WINDOW_SIDEBAR][WINDOWWIDTH] = (SIDE_WIDTH) * RESFACTOR; + WindowList[WINDOW_SIDEBAR][WINDOWWIDTH] = (SIDE_WIDTH)*RESFACTOR; WindowList[WINDOW_SIDEBAR][WINDOWHEIGHT] = ScreenHeight; -// WindowList[WINDOW_SIDEBAR][WINDOWHEIGHT] = (StripClass::MAX_VISIBLE * StripClass::OBJECT_HEIGHT-1) * RESFACTOR; + // WindowList[WINDOW_SIDEBAR][WINDOWHEIGHT] = (StripClass::MAX_VISIBLE * StripClass::OBJECT_HEIGHT-1) * RESFACTOR; - /* - ** Top of the window seems to be wrong for the new sidebar. ST - 5/2/96 2:49AM - */ - WindowList[WINDOW_SIDEBAR][WINDOWY] -= 1*RESFACTOR; + /* + ** Top of the window seems to be wrong for the new sidebar. ST - 5/2/96 2:49AM + */ + WindowList[WINDOW_SIDEBAR][WINDOWY] -= 1 * RESFACTOR; /* ** Set up the coordinates for the sidebar strips. These coordinates are for ** the upper left corner. */ -// Column[0].X = COLUMN_ONE_X * RESFACTOR; -// Column[0].Y = COLUMN_ONE_Y * RESFACTOR; -// Column[1].X = COLUMN_TWO_X * RESFACTOR; -// Column[1].Y = COLUMN_TWO_Y * RESFACTOR; + // Column[0].X = COLUMN_ONE_X * RESFACTOR; + // Column[0].Y = COLUMN_ONE_Y * RESFACTOR; + // Column[1].X = COLUMN_TWO_X * RESFACTOR; + // Column[1].Y = COLUMN_TWO_Y * RESFACTOR; Column[0].One_Time(0); Column[1].One_Time(1); @@ -307,8 +307,8 @@ void SidebarClass::Init_IO(void) Repair.IsSticky = true; Repair.ID = BUTTON_REPAIR; - Repair.X = ScreenWidth - (640 - (0x1f2/2)*RESFACTOR); - Repair.Y = (0x96/2)*RESFACTOR; + Repair.X = ScreenWidth - (640 - (0x1f2 / 2) * RESFACTOR); + Repair.Y = (0x96 / 2) * RESFACTOR; Repair.IsPressed = false; Repair.IsToggleType = true; Repair.ReflectButtonState = true; @@ -317,7 +317,7 @@ void SidebarClass::Init_IO(void) Upgrade.IsSticky = true; Upgrade.ID = BUTTON_UPGRADE; Upgrade.X = ScreenWidth - (640 - 0x21f); - Upgrade.Y = (0x96/2)*RESFACTOR; + Upgrade.Y = (0x96 / 2) * RESFACTOR; Upgrade.IsPressed = false; Upgrade.IsToggleType = true; Upgrade.ReflectButtonState = true; @@ -325,14 +325,15 @@ void SidebarClass::Init_IO(void) Zoom.IsSticky = true; Zoom.ID = BUTTON_ZOOM; - Zoom.X = ScreenWidth - (640 - ((0x24c/2)*RESFACTOR)); - Zoom.Y = (0x96/2)*RESFACTOR; + Zoom.X = ScreenWidth - (640 - ((0x24c / 2) * RESFACTOR)); + Zoom.Y = (0x96 / 2) * RESFACTOR; Zoom.IsPressed = false; Zoom.Set_Shape(MFCD::Retrieve("MAP.SHP")); if ((IsRadarActive && Is_Zoomable()) || Session.Type != GAME_NORMAL) { Zoom.Enable(); - } else { + } + else { Zoom.Disable(); } Column[0].Init_IO(0); @@ -344,8 +345,8 @@ void SidebarClass::Init_IO(void) if (IsSidebarActive) { IsSidebarActive = false; Activate(1); -// Background.Zap(); -// Add_A_Button(Background); + // Background.Zap(); + // Add_A_Button(Background); } } } @@ -388,7 +389,7 @@ void SidebarClass::Init_Theater(TheaterType theater) *=============================================================================================*/ void SidebarClass::Reload_Sidebar(void) { - static char * sidebarnames[]={ + static char* sidebarnames[] = { "SIDE?NA.SHP", //NATO "SIDE?NA.SHP", "SIDE?US.SHP", //USSR @@ -402,18 +403,18 @@ void SidebarClass::Reload_Sidebar(void) }; int houseloaded = 0; - if(PlayerPtr) { + if (PlayerPtr) { houseloaded = PlayerPtr->ActLike; } /* Don't have write access to the static char array. ST - 5/20/2019 */ #if (0) - char * sidename = sidebarnames[houseloaded]; - *(sidename+4) = '1'; + char* sidename = sidebarnames[houseloaded]; + *(sidename + 4) = '1'; SidebarShape = (void*)MFCD::Retrieve(sidename); - *(sidename+4) = '2'; + *(sidename + 4) = '2'; SidebarMiddleShape = (void*)MFCD::Retrieve(sidename); - *(sidename+4) = '3'; + *(sidename + 4) = '3'; SidebarBottomShape = (void*)MFCD::Retrieve(sidename); #else char sb_name[16]; @@ -506,7 +507,7 @@ bool SidebarClass::Factory_Link(int factory, RTTIType type, int id) * HISTORY: * * 01/19/1995 JLB : Created. * *=============================================================================================*/ -void SidebarClass::Refresh_Cells(CELL cell, short const * list) +void SidebarClass::Refresh_Cells(CELL cell, short const* list) { if (*list == REFRESH_SIDEBAR) { IsToRedraw = true; @@ -544,14 +545,14 @@ bool SidebarClass::Activate_Repair(int control) control = IsRepairActive ? 0 : 1; } switch (control) { - case 1: - IsRepairActive = true; - break; + case 1: + IsRepairActive = true; + break; - default: - case 0: - IsRepairActive = false; - break; + default: + case 0: + IsRepairActive = false; + break; } if (old != IsRepairActive) { Flag_To_Redraw(false); @@ -591,14 +592,14 @@ bool SidebarClass::Activate_Upgrade(int control) control = IsUpgradeActive ? 0 : 1; } switch (control) { - case 1: - IsUpgradeActive = true; - break; + case 1: + IsUpgradeActive = true; + break; - default: - case 0: - IsUpgradeActive = false; - break; + default: + case 0: + IsUpgradeActive = false; + break; } if (old != IsUpgradeActive) { Flag_To_Redraw(false); @@ -637,14 +638,14 @@ bool SidebarClass::Activate_Demolish(int control) control = IsDemolishActive ? 0 : 1; } switch (control) { - case 1: - IsDemolishActive = true; - break; + case 1: + IsDemolishActive = true; + break; - default: - case 0: - IsDemolishActive = false; - break; + default: + case 0: + IsDemolishActive = false; + break; } if (old != IsDemolishActive) { Flag_To_Redraw(false); @@ -764,7 +765,7 @@ void SidebarClass::Draw_It(bool complete) BStart(BENCH_SIDEBAR); if (IsSidebarActive && (IsToRedraw || complete) && !Debug_Map) { - // IsToRedraw = false; + // IsToRedraw = false; if (LogicPage->Lock()) { /* @@ -772,19 +773,16 @@ void SidebarClass::Draw_It(bool complete) */ int shape = complete ? 0 : 1; - /* - ** The sidebar shape is too big in 640x400 so it needs to be drawn in three chunks. - */ - CC_Draw_Shape(SidebarShape, 0, SIDE_X * RESFACTOR, 8*RESFACTOR, WINDOW_MAIN, SHAPE_WIN_REL); + CC_Draw_Shape(SidebarShape, 0, SIDE_X * RESFACTOR, 8 * RESFACTOR, WINDOW_MAIN, SHAPE_WIN_REL); - // @@ this one repeats - CC_Draw_Shape(SidebarMiddleShape, shape, SIDE_X * RESFACTOR, (8+80)*RESFACTOR, WINDOW_MAIN, SHAPE_WIN_REL); - - CC_Draw_Shape(SidebarBottomShape, shape, SIDE_X * RESFACTOR, ScreenHeight - ( 80*RESFACTOR ), WINDOW_MAIN, SHAPE_WIN_REL); + CC_Draw_Shape(SidebarMiddleShape, shape, SIDE_X * RESFACTOR, (8 + 80) * RESFACTOR, WINDOW_MAIN, SHAPE_WIN_REL); + + CC_Draw_Shape(SidebarBottomShape, shape, SIDE_X * RESFACTOR, ScreenHeight - (80 * RESFACTOR) + 3, WINDOW_MAIN, SHAPE_WIN_REL); Repair.Draw_Me(true); Upgrade.Draw_Me(true); Zoom.Draw_Me(true); + LogicPage->Unlock(); } } @@ -802,7 +800,6 @@ void SidebarClass::Draw_It(bool complete) Zoom.Draw_Me(true); } } - //IsToRedraw = false; BEnd(BENCH_SIDEBAR); } @@ -830,7 +827,7 @@ void SidebarClass::Draw_It(bool complete) * 12/31/1994 JLB : Uses mouse coordinate parameters. * * 06/27/1995 JLB : key toggles sidebar. * *=============================================================================================*/ -void SidebarClass::AI(KeyNumType & input, int x, int y) +void SidebarClass::AI(KeyNumType& input, int x, int y) { bool redraw = true; @@ -894,19 +891,20 @@ void SidebarClass::AI(KeyNumType & input, int x, int y) */ if (PlayerPtr->BScan) { Activate_Repair(true); - } else { + } + else { Activate_Repair(false); } - if (input == (BUTTON_REPAIR|KN_BUTTON)) { + if (input == (BUTTON_REPAIR | KN_BUTTON)) { Repair_Mode_Control(-1); } - if (input == (BUTTON_ZOOM|KN_BUTTON)) { + if (input == (BUTTON_ZOOM | KN_BUTTON)) { Zoom_Mode_Control(); } - if (input == (BUTTON_UPGRADE|KN_BUTTON)) { + if (input == (BUTTON_UPGRADE | KN_BUTTON)) { Sell_Mode_Control(-1); } @@ -1005,18 +1003,18 @@ bool SidebarClass::Activate(int control) ** Determine the new state of the sidebar. */ switch (control) { - case -1: - IsSidebarActive = IsSidebarActive == false; - break; + case -1: + IsSidebarActive = IsSidebarActive == false; + break; - case 1: - IsSidebarActive = true; - break; + case 1: + IsSidebarActive = true; + break; - default: - case 0: - IsSidebarActive = false; - break; + default: + case 0: + IsSidebarActive = false; + break; } /* @@ -1030,7 +1028,7 @@ bool SidebarClass::Activate(int control) ** activate it on the left side of the screen. */ if (IsSidebarActive /*&& X*/) { - Set_View_Dimensions( 0, 8 * RESFACTOR, SeenBuff.Get_Width() - ( SIDE_WIDTH * RESFACTOR ) ); + Set_View_Dimensions(0, 8 * RESFACTOR, SeenBuff.Get_Width() - (SIDE_WIDTH * RESFACTOR)); IsToRedraw = true; Help_Text(TXT_NONE); @@ -1048,7 +1046,8 @@ bool SidebarClass::Activate(int control) Add_A_Button(Map.RadarButton); Map.PowerButton.Zap(); Add_A_Button(Map.PowerButton); - } else { + } + else { Help_Text(TXT_NONE); Set_View_Dimensions(0, 0); Remove_A_Button(Repair); @@ -1086,7 +1085,7 @@ bool SidebarClass::Activate(int control) * HISTORY: * * 12/31/1994 JLB : Created. * *=============================================================================================*/ -SidebarClass::StripClass::StripClass(InitClass const & ) : +SidebarClass::StripClass::StripClass(InitClass const&) : X(0), Y(0), ID(0), @@ -1124,11 +1123,11 @@ SidebarClass::StripClass::StripClass(InitClass const & ) : * HISTORY: * * 12/31/1994 JLB : Created. * *=============================================================================================*/ -void SidebarClass::StripClass::One_Time(int ) +void SidebarClass::StripClass::One_Time(int) { // Sidebar height HEIGHT = ScreenHeight; - MaxButtonsVisible = ( HEIGHT - ( ( SIDE_Y + TOP_HEIGHT + OBJECT_HEIGHT ) * RESFACTOR ) ) / ( OBJECT_HEIGHT * RESFACTOR ); + MaxButtonsVisible = (HEIGHT - ((SIDE_Y + TOP_HEIGHT + OBJECT_HEIGHT) * RESFACTOR)) / (OBJECT_HEIGHT * RESFACTOR); /* ** Sidebar is player team specific in Hires @@ -1139,7 +1138,7 @@ void SidebarClass::StripClass::One_Time(int ) char buffer[_MAX_FNAME]; sprintf(buffer, "%sICON", SpecialWeaponFile[lp]); - char fullname[_MAX_FNAME+_MAX_EXT]; + char fullname[_MAX_FNAME + _MAX_EXT]; _makepath(fullname, NULL, NULL, buffer, ".SHP"); SpecialShapes[lp] = MFCD::Retrieve(fullname); } @@ -1161,7 +1160,7 @@ void SidebarClass::StripClass::One_Time(int ) * HISTORY: * * 05/19/1995 JLB : commented * *=============================================================================================*/ -void const * SidebarClass::StripClass::Get_Special_Cameo(SpecialWeaponType type) +void const* SidebarClass::StripClass::Get_Special_Cameo(SpecialWeaponType type) { if ((unsigned)type < SPC_COUNT) { return(SpecialShapes[type]); @@ -1223,38 +1222,25 @@ void SidebarClass::StripClass::Init_IO(int id) ID = id; UpButton[ID].IsSticky = true; - UpButton[ID].ID = BUTTON_UP+id; + UpButton[ID].ID = BUTTON_UP + id; UpButton[ID].X = X + (UP_X_OFFSET * RESFACTOR); - UpButton[ID].Y = HEIGHT - ( ( OBJECT_HEIGHT + 7 ) * RESFACTOR ); - -#if (FRENCH) -#ifdef WIN32 + UpButton[ID].Y = HEIGHT - ((OBJECT_HEIGHT + 7) * RESFACTOR); UpButton[ID].Set_Shape(MFCD::Retrieve("STRIPUP.SHP")); -#else - UpButton[ID].Set_Shape(MFCD::Retrieve("STUP_FIX.SHP")); -#endif -#else //FRENCH - UpButton[ID].Set_Shape(MFCD::Retrieve("STRIPUP.SHP")); -#endif //FRENCH DownButton[ID].IsSticky = true; - DownButton[ID].ID = BUTTON_DOWN+id; + DownButton[ID].ID = BUTTON_DOWN + id; DownButton[ID].X = X + (DOWN_X_OFFSET * RESFACTOR); - DownButton[ID].Y = HEIGHT - ( (OBJECT_HEIGHT + 7 ) * RESFACTOR ); - - /* - ** Buttons are in a slightly different position in the new sidebar - */ - UpButton[ID].Y--; - DownButton[ID].Y--; - + DownButton[ID].Y = HEIGHT - ((OBJECT_HEIGHT + 7) * RESFACTOR); DownButton[ID].Set_Shape(MFCD::Retrieve("STRIPDN.SHP")); + UpButton[ID].Y += 3; + DownButton[ID].Y += 3; + for (int index = 0; index < MaxButtonsVisible; index++) { - SelectClass & g = SelectButton[ID][index]; + SelectClass& g = SelectButton[ID][index]; g.ID = BUTTON_SELECT; g.X = X; - g.Y = Y + ((OBJECT_HEIGHT*index) * RESFACTOR); + g.Y = Y + ((OBJECT_HEIGHT * index) * RESFACTOR); g.Width = OBJECT_WIDTH * RESFACTOR; g.Height = OBJECT_HEIGHT * RESFACTOR; g.Set_Owner(*this, index); @@ -1279,28 +1265,28 @@ void SidebarClass::StripClass::Init_Theater(TheaterType theater) Reload_LogoShapes(); - if ( (theater != THEATER_NONE) && (theater != ::LastTheater)) { + if ((theater != THEATER_NONE) && (theater != ::LastTheater)) { static TLucentType const ClockCols[1] = { {GREEN, BLACK, 100, 0} -// {GREEN, LTGREY, 180, 0} + // {GREEN, LTGREY, 180, 0} }; /* ** Make sure that remapping doesn't occur on the colors that cycle. */ PaletteClass pal = OriginalPalette; - memset(&pal[CYCLE_COLOR_START*3], 0x3f, CYCLE_COLOR_COUNT*3); + memset(&pal[CYCLE_COLOR_START * 3], 0x3f, CYCLE_COLOR_COUNT * 3); Build_Translucent_Table(pal, &ClockCols[0], 1, (void*)ClockTranslucentTable); -// Mem_Copy(GamePalette, OriginalPalette, 768); -// memset(&GamePalette[CYCLE_COLOR_START*3], 0x3f, CYCLE_COLOR_COUNT*3); + // Mem_Copy(GamePalette, OriginalPalette, 768); + // memset(&GamePalette[CYCLE_COLOR_START*3], 0x3f, CYCLE_COLOR_COUNT*3); - /* - ** Create the translucent table used for the sidebar. - */ -// Build_Translucent_Table(GamePalette, &ClockCols[0], 1, (void*)ClockTranslucentTable); -// GamePalette = OriginalPalette; + /* + ** Create the translucent table used for the sidebar. + */ + // Build_Translucent_Table(GamePalette, &ClockCols[0], 1, (void*)ClockTranslucentTable); + // GamePalette = OriginalPalette; Conquer_Build_Fading_Table(GamePalette, &ClockTranslucentTable[256], BLACK, 100); } @@ -1311,7 +1297,7 @@ void SidebarClass::StripClass::Reload_LogoShapes(void) /* ** Load hi-res strip art here since it is player side specific */ - static char * stripnames[]={ + static char* stripnames[] = { "stripna.shp", //Nato "stripna.shp", "stripus.shp", //USSR @@ -1329,13 +1315,13 @@ void SidebarClass::StripClass::Reload_LogoShapes(void) ** Sidebar art is dependent on the side of the player */ - if(PlayerPtr) { + if (PlayerPtr) { houseloaded = PlayerPtr->ActLike; } -// jmarshall + // jmarshall if (houseloaded >= HOUSE_BAD) return; -// jmarshall end + // jmarshall end LogoShapes = (void*)MFCD::Retrieve(stripnames[houseloaded]); } @@ -1458,8 +1444,9 @@ bool SidebarClass::StripClass::Scroll(bool up) if (up) { if (!TopIndex) return(false); Scroller--; - } else { - if ( TopIndex+ MaxButtonsVisible >= BuildableCount ) return(false); + } + else { + if (TopIndex + MaxButtonsVisible >= BuildableCount) return(false); Scroller++; } return(true); @@ -1510,7 +1497,7 @@ void SidebarClass::StripClass::Flag_To_Redraw(void) * 12/31/1994 JLB : Created. * * 12/31/1994 JLB : Uses mouse coordinate parameters. * *=============================================================================================*/ -bool SidebarClass::StripClass::AI(KeyNumType & input, int , int ) +bool SidebarClass::StripClass::AI(KeyNumType& input, int, int) { bool redraw = false; @@ -1518,13 +1505,13 @@ bool SidebarClass::StripClass::AI(KeyNumType & input, int , int ) ** If this is scroll button for this side strip, then scroll the strip as ** indicated. */ - if (input == (UpButton[ID].ID|KN_BUTTON)) { // && !IsScrolling + if (input == (UpButton[ID].ID | KN_BUTTON)) { // && !IsScrolling UpButton[ID].IsPressed = false; if (!Scroll(true)) { Sound_Effect(VOC_SCOLD); } } - if (input == (DownButton[ID].ID|KN_BUTTON)) { // && !IsScrolling + if (input == (DownButton[ID].ID | KN_BUTTON)) { // && !IsScrolling DownButton[ID].IsPressed = false; if (!Scroll(false)) { Sound_Effect(VOC_SCOLD); @@ -1536,9 +1523,10 @@ bool SidebarClass::StripClass::AI(KeyNumType & input, int , int ) ** logic handler. This might result in up or down scrolling. */ if (!IsScrolling && Scroller) { - if (BuildableCount <= MaxButtonsVisible ) { + if (BuildableCount <= MaxButtonsVisible) { Scroller = 0; - } else { + } + else { /* ** Top of list is moving toward lower ordered entries in the object list. It looks like @@ -1548,7 +1536,8 @@ bool SidebarClass::StripClass::AI(KeyNumType & input, int , int ) if (Scroller < 0) { if (!TopIndex) { Scroller = 0; - } else { + } + else { Scroller++; IsScrollingDown = false; IsScrolling = true; @@ -1556,10 +1545,12 @@ bool SidebarClass::StripClass::AI(KeyNumType & input, int , int ) Slid = 0; } - } else { + } + else { if (TopIndex + MaxButtonsVisible >= BuildableCount) { Scroller = 0; - } else { + } + else { Scroller--; Slid = OBJECT_HEIGHT; IsScrollingDown = true; @@ -1580,7 +1571,8 @@ bool SidebarClass::StripClass::AI(KeyNumType & input, int , int ) Slid = 0; TopIndex++; } - } else { + } + else { Slid += SCROLL_RATE; if (Slid >= OBJECT_HEIGHT) { IsScrolling = false; @@ -1613,7 +1605,7 @@ bool SidebarClass::StripClass::AI(KeyNumType & input, int , int ) int factoryid = Buildables[index].Factory; if (factoryid != -1) { - FactoryClass * factory = Factories.Raw_Ptr(factoryid); + FactoryClass* factory = Factories.Raw_Ptr(factoryid); if (factory && (factory->Has_Changed() || factory->Is_Blocked())) { redraw = true; @@ -1625,28 +1617,28 @@ bool SidebarClass::StripClass::AI(KeyNumType & input, int , int ) ** the main exception to the ability to leave the factory under their own ** power. */ - TechnoClass * pending = factory->Get_Object(); + TechnoClass* pending = factory->Get_Object(); if (pending != NULL) { switch (pending->What_Am_I()) { - case RTTI_VESSEL: - case RTTI_UNIT: - case RTTI_AIRCRAFT: - OutList.Add(EventClass(EventClass::PLACE, pending->What_Am_I(), -1)); - if (!factory->Is_Blocked()) { - Speak(VOX_UNIT_READY); - } - break; + case RTTI_VESSEL: + case RTTI_UNIT: + case RTTI_AIRCRAFT: + OutList.Add(EventClass(EventClass::PLACE, pending->What_Am_I(), -1)); + if (!factory->Is_Blocked()) { + Speak(VOX_UNIT_READY); + } + break; - case RTTI_BUILDING: - Speak(VOX_CONSTRUCTION); - break; + case RTTI_BUILDING: + Speak(VOX_CONSTRUCTION); + break; - case RTTI_INFANTRY: - OutList.Add(EventClass(EventClass::PLACE, pending->What_Am_I(), -1)); - if (!factory->Is_Blocked()) { - Speak(VOX_UNIT_READY); - } - break; + case RTTI_INFANTRY: + OutList.Add(EventClass(EventClass::PLACE, pending->What_Am_I(), -1)); + if (!factory->Is_Blocked()) { + Speak(VOX_UNIT_READY); + } + break; } } } @@ -1687,7 +1679,7 @@ bool SidebarClass::StripClass::AI(KeyNumType & input, int , int ) void SidebarClass::StripClass::Draw_It(bool complete) { if (IsToRedraw || complete) { - // IsToRedraw = false; + // IsToRedraw = false; if (RunningAsDLL) { return; @@ -1702,8 +1694,8 @@ void SidebarClass::StripClass::Draw_It(bool complete) /* ** New sidebar needs to be drawn not filled */ - if ( BuildableCount < MaxButtonsVisible ) { - CC_Draw_Shape( LogoShapes, ID, X+(2*RESFACTOR), Y, WINDOW_MAIN, SHAPE_WIN_REL|SHAPE_NORMAL, 0); + if (BuildableCount < MaxButtonsVisible) { + CC_Draw_Shape(LogoShapes, ID, X + (2 * RESFACTOR), Y, WINDOW_MAIN, SHAPE_WIN_REL | SHAPE_NORMAL, 0); } /* @@ -1721,20 +1713,20 @@ void SidebarClass::StripClass::Draw_It(bool complete) bool completed; int stage; bool darken = false; - void const * shapefile = 0; + void const* shapefile = 0; int shapenum = 0; - void const * remapper = 0; - FactoryClass * factory = 0; - int index = i+TopIndex; + void const* remapper = 0; + FactoryClass* factory = 0; + int index = i + TopIndex; int x = X; - int y = Y + (i*OBJECT_HEIGHT * RESFACTOR); + int y = Y + (i * OBJECT_HEIGHT * RESFACTOR); /* ** If the strip is scrolling, then the offset is adjusted accordingly. */ if (IsScrolling) { - y -= (OBJECT_HEIGHT - Slid) * RESFACTOR; -// y -= OBJECT_HEIGHT - Slid; + y -= (OBJECT_HEIGHT - Slid) * RESFACTOR; + // y -= OBJECT_HEIGHT - Slid; } /* @@ -1742,7 +1734,7 @@ void SidebarClass::StripClass::Draw_It(bool complete) ** slot. This shape pointer is used to draw the underlying graphic there. */ if (index < BuildableCount) { - ObjectTypeClass const * obj = NULL; + ObjectTypeClass const* obj = NULL; SpecialWeaponType spc = SPC_NONE; if (Buildables[index].BuildableType != RTTI_SPECIAL) { @@ -1754,7 +1746,7 @@ void SidebarClass::StripClass::Draw_It(bool complete) ** Fetch the remap table that is appropriate for this object ** type. */ - remapper = PlayerPtr->Remap_Table(false, ((TechnoTypeClass const *)obj)->Remap); + remapper = PlayerPtr->Remap_Table(false, ((TechnoTypeClass const*)obj)->Remap); /* ** If there is already a factory producing this kind of object, then all @@ -1773,28 +1765,31 @@ void SidebarClass::StripClass::Draw_It(bool complete) } shapefile = obj->Get_Cameo_Data(); - shapenum = 0; + shapenum = 0; if (Buildables[index].Factory != -1) { - factory = Factories.Raw_Ptr(Buildables[index].Factory); - production = true; - completed = factory->Has_Completed(); - stage = factory->Completion(); - darken = false; - } else { - production = false; -// darken = IsBuilding; + factory = Factories.Raw_Ptr(Buildables[index].Factory); + production = true; + completed = factory->Has_Completed(); + stage = factory->Completion(); + darken = false; + } + else { + production = false; + // darken = IsBuilding; - /* - ** Darken the imagery if a factory of a matching type is - ** already busy. - */ + /* + ** Darken the imagery if a factory of a matching type is + ** already busy. + */ darken = isbusy; } - } else { + } + else { darken = PlayerPtr->Is_Hack_Prevented(Buildables[index].BuildableType, Buildables[index].BuildableID); } - } else { + } + else { spc = SpecialWeaponType(Buildables[index].BuildableID); shapefile = Get_Special_Cameo(spc); @@ -1815,19 +1810,22 @@ void SidebarClass::StripClass::Draw_It(bool complete) remapper = Map.FadingLight; } - } else { - shapefile = LogoShapes; + } + else { + shapefile = LogoShapes; if (!darken) { - shapenum = SB_BLANK; + shapenum = SB_BLANK; } } - } else { - shapefile = LogoShapes; - shapenum = SB_BLANK; - production = false; + } + else { + shapefile = LogoShapes; + shapenum = SB_BLANK; + production = false; } remapper = 0; + /* ** Now that the shape of the object at the current working slot has been found, ** draw it and any graphic overlays as necessary. @@ -1836,10 +1834,10 @@ void SidebarClass::StripClass::Draw_It(bool complete) */ if (shapenum != SB_BLANK || shapefile != LogoShapes) { CC_Draw_Shape(shapefile, shapenum, - x-(WindowList[WINDOW_SIDEBAR][WINDOWX])+(LEFT_EDGE_OFFSET * RESFACTOR), - y-WindowList[WINDOW_SIDEBAR][WINDOWY], + x - (WindowList[WINDOW_SIDEBAR][WINDOWX]) + (LEFT_EDGE_OFFSET * RESFACTOR), + y - WindowList[WINDOW_SIDEBAR][WINDOWY], WINDOW_SIDEBAR, - SHAPE_NORMAL|SHAPE_WIN_REL| (remapper ? SHAPE_FADING : SHAPE_NORMAL), + SHAPE_NORMAL | SHAPE_WIN_REL | (remapper ? SHAPE_FADING : SHAPE_NORMAL), remapper); /* @@ -1848,11 +1846,11 @@ void SidebarClass::StripClass::Draw_It(bool complete) */ if (darken) { CC_Draw_Shape(ClockShapes, 0, - x-(WindowList[WINDOW_SIDEBAR][WINDOWX])+(LEFT_EDGE_OFFSET * RESFACTOR), - y-WindowList[WINDOW_SIDEBAR][WINDOWY], + x - (WindowList[WINDOW_SIDEBAR][WINDOWX]) + (LEFT_EDGE_OFFSET * RESFACTOR), + y - WindowList[WINDOW_SIDEBAR][WINDOWY], WINDOW_SIDEBAR, - SHAPE_NORMAL|SHAPE_WIN_REL|SHAPE_GHOST, - NULL, ClockTranslucentTable); + SHAPE_NORMAL | SHAPE_WIN_REL | SHAPE_GHOST, + NULL, ClockTranslucentTable); } } @@ -1867,26 +1865,27 @@ void SidebarClass::StripClass::Draw_It(bool complete) ** Display text showing that the object is ready to place. */ CC_Draw_Shape(ObjectTypeClass::PipShapes, PIP_READY, - (x-(WindowList[WINDOW_SIDEBAR][WINDOWX]))+(LEFT_EDGE_OFFSET+15) * RESFACTOR, - (y-WindowList[WINDOW_SIDEBAR][WINDOWY])+(4 * RESFACTOR), - WINDOW_SIDEBAR, SHAPE_CENTER); - } else { + (x - (WindowList[WINDOW_SIDEBAR][WINDOWX])) + (LEFT_EDGE_OFFSET + 15) * RESFACTOR, + (y - WindowList[WINDOW_SIDEBAR][WINDOWY]) + (4 * RESFACTOR), + WINDOW_SIDEBAR, SHAPE_CENTER); + } + else { - CC_Draw_Shape(ClockShapes, stage+1, - x-(WindowList[WINDOW_SIDEBAR][WINDOWX])+(LEFT_EDGE_OFFSET * RESFACTOR), - y-WindowList[WINDOW_SIDEBAR][WINDOWY], - WINDOW_SIDEBAR, - SHAPE_NORMAL|SHAPE_WIN_REL|SHAPE_GHOST, - NULL, ClockTranslucentTable); + CC_Draw_Shape(ClockShapes, stage + 1, + x - (WindowList[WINDOW_SIDEBAR][WINDOWX]) + (LEFT_EDGE_OFFSET * RESFACTOR), + y - WindowList[WINDOW_SIDEBAR][WINDOWY], + WINDOW_SIDEBAR, + SHAPE_NORMAL | SHAPE_WIN_REL | SHAPE_GHOST, + NULL, ClockTranslucentTable); /* ** Display text showing that the construction is temporarily on hold. */ if (factory && !factory->Is_Building()) { CC_Draw_Shape(ObjectTypeClass::PipShapes, PIP_HOLDING, - (x-(WindowList[WINDOW_SIDEBAR][WINDOWX])) + ((LEFT_EDGE_OFFSET+15) * RESFACTOR), - (y-WindowList[WINDOW_SIDEBAR][WINDOWY])+(4 * RESFACTOR), - WINDOW_SIDEBAR, SHAPE_CENTER); + (x - (WindowList[WINDOW_SIDEBAR][WINDOWX])) + ((LEFT_EDGE_OFFSET + 15) * RESFACTOR), + (y - WindowList[WINDOW_SIDEBAR][WINDOWY]) + (4 * RESFACTOR), + WINDOW_SIDEBAR, SHAPE_CENTER); } } } @@ -1932,13 +1931,15 @@ bool SidebarClass::StripClass::Recalc(void) */ bool redraw = false; for (int index = 0; index < BuildableCount; index++) { - TechnoTypeClass const * tech = Fetch_Techno_Type(Buildables[index].BuildableType, Buildables[index].BuildableID); + TechnoTypeClass const* tech = Fetch_Techno_Type(Buildables[index].BuildableType, Buildables[index].BuildableID); if (tech != NULL) { ok = tech->Who_Can_Build_Me(true, false, PlayerPtr->Class->House) != NULL; - } else { + } + else { if ((unsigned)Buildables[index].BuildableID < SPC_COUNT) { ok = PlayerPtr->SuperWeapon[Buildables[index].BuildableID].Is_Present(); - } else { + } + else { ok = false; } } @@ -1948,8 +1949,8 @@ bool SidebarClass::StripClass::Recalc(void) /* ** Removes this entry from the list. */ - if (BuildableCount > 1 && index < BuildableCount-1) { - memcpy(&Buildables[index], &Buildables[index+1], sizeof(Buildables[0])*((BuildableCount-index)-1)); + if (BuildableCount > 1 && index < BuildableCount - 1) { + memcpy(&Buildables[index], &Buildables[index + 1], sizeof(Buildables[0]) * ((BuildableCount - index) - 1)); } TopIndex = 0; IsToRedraw = true; @@ -1988,7 +1989,7 @@ bool SidebarClass::StripClass::Recalc(void) * 01/19/1995 JLB : Created. * *=============================================================================================*/ SidebarClass::StripClass::SelectClass::SelectClass(void) : - ControlClass(0, 0, 0, (OBJECT_WIDTH-1) * RESFACTOR, OBJECT_HEIGHT * RESFACTOR, LEFTPRESS|RIGHTPRESS|LEFTUP), + ControlClass(0, 0, 0, (OBJECT_WIDTH - 1)* RESFACTOR, OBJECT_HEIGHT* RESFACTOR, LEFTPRESS | RIGHTPRESS | LEFTUP), Strip(0), Index(0) { @@ -2014,7 +2015,7 @@ SidebarClass::StripClass::SelectClass::SelectClass(void) : * HISTORY: * * 01/19/1995 JLB : Created. * *=============================================================================================*/ -void SidebarClass::StripClass::SelectClass::Set_Owner(StripClass & strip, int index) +void SidebarClass::StripClass::SelectClass::Set_Owner(StripClass& strip, int index) { Strip = &strip; Index = index; @@ -2041,7 +2042,7 @@ void SidebarClass::StripClass::SelectClass::Set_Owner(StripClass & strip, int in * 01/19/1995 JLB : Created. * * 10/09/1996 JLB : Sonar pulse converted to regular event type. * *=============================================================================================*/ -int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & key) +int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType& key) { if (Strip == NULL) return 0; @@ -2049,9 +2050,9 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k RTTIType otype = Strip->Buildables[index].BuildableType; int oid = Strip->Buildables[index].BuildableID; int fnumber = Strip->Buildables[index].Factory; - RemapControlType * scheme = GadgetClass::Get_Color_Scheme(); + RemapControlType* scheme = GadgetClass::Get_Color_Scheme(); - ObjectTypeClass const * choice = NULL; + ObjectTypeClass const* choice = NULL; SpecialWeaponType spc = SPC_NONE; /* @@ -2061,14 +2062,15 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k ** kind of factory is specified by the "genfactory" value. This can be used to see ** if the factory type is currently busy or not. */ - FactoryClass * factory = PlayerPtr->Fetch_Factory(otype); + FactoryClass* factory = PlayerPtr->Fetch_Factory(otype); Map.Override_Mouse_Shape(MOUSE_NORMAL); if (index < Strip->BuildableCount) { if (otype != RTTI_SPECIAL) { - choice = Fetch_Techno_Type(otype, oid); - } else { + choice = Fetch_Techno_Type(otype, oid); + } + else { spc = SpecialWeaponType(oid); } @@ -2076,9 +2078,10 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k factory = Factories.Raw_Ptr(fnumber); } - } else { - Map.Help_Text(TXT_NONE); - } + } + else { + Map.Help_Text(TXT_NONE); + } if (spc != SPC_NONE) { @@ -2109,16 +2112,19 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k Map.IsTargettingMode = spc; Unselect_All(); Speak(VOX_SELECT_TARGET); - } else { + } + else { OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_SONAR_PULSE, 0)); } - } else { + } + else { PlayerPtr->SuperWeapon[spc].Impatient_Click(); } } } - } else { + } + else { if (choice != NULL) { @@ -2158,7 +2164,8 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k if (!factory->Is_Building()) { Speak(VOX_CANCELED); OutList.Add(EventClass(EventClass::ABANDON, otype, oid)); - } else { + } + else { Speak(VOX_SUSPENDED); OutList.Add(EventClass(EventClass::SUSPEND, otype, oid)); Map.Column[0].IsToRedraw = true; @@ -2188,7 +2195,8 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k */ if (factory->Is_Building()) { Speak(VOX_NO_FACTORY); - } else { + } + else { /* ** If production has completed, then attempt to have the object exit @@ -2196,15 +2204,17 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k */ if (factory->Has_Completed()) { - TechnoClass * pending = factory->Get_Object(); + TechnoClass* pending = factory->Get_Object(); if (!pending && factory->Get_Special_Item()) { Map.IsTargettingMode = SPC_ANY; - } else { - BuildingClass * builder = pending->Who_Can_Build_Me(false, false); + } + else { + BuildingClass* builder = pending->Who_Can_Build_Me(false, false); if (!builder) { OutList.Add(EventClass(EventClass::ABANDON, otype, oid)); Speak(VOX_NO_FACTORY); - } else { + } + else { /* ** If the completed object is a building, then change the @@ -2213,8 +2223,9 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k ** the building is actually placed down. */ if (pending->What_Am_I() == RTTI_BUILDING) { - PlayerPtr->Manual_Place(builder, (BuildingClass *)pending); - } else { + PlayerPtr->Manual_Place(builder, (BuildingClass*)pending); + } + else { /* ** For objects that can leave the factory under their own @@ -2225,18 +2236,21 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k } } } - } else { + } + else { if (PlayerPtr->Is_Hack_Prevented(otype, oid)) { // Eva scolds the player here. - } else { + } + else { /* ** The factory must have been in a suspended state. Resume construction ** normally. */ if (otype == RTTI_INFANTRYTYPE) { Speak(VOX_TRAINING); - } else { + } + else { Speak(VOX_BUILDING); } OutList.Add(EventClass(EventClass::PRODUCE, Strip->Buildables[index].BuildableType, Strip->Buildables[index].BuildableID)); @@ -2244,11 +2258,13 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k } } - } else { + } + else { if (PlayerPtr->Is_Hack_Prevented(otype, oid)) { // Eva scolds the player here. - } else { + } + else { /* ** If this side strip is already busy with production, then ignore the @@ -2256,14 +2272,16 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k */ if (otype == RTTI_INFANTRYTYPE) { Speak(VOX_TRAINING); - } else { + } + else { Speak(VOX_BUILDING); } OutList.Add(EventClass(EventClass::PRODUCE, Strip->Buildables[index].BuildableType, Strip->Buildables[index].BuildableID)); } } } - } else { + } + else { flags = 0; } } @@ -2290,7 +2308,7 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k * HISTORY: * * 03/28/1995 JLB : Created. * *=============================================================================================*/ -int SidebarClass::SBGadgetClass::Action(unsigned , KeyNumType & ) +int SidebarClass::SBGadgetClass::Action(unsigned, KeyNumType&) { Map.Help_Text(TXT_NONE); Map.Override_Mouse_Shape(MOUSE_NORMAL, false); @@ -2387,7 +2405,8 @@ bool SidebarClass::StripClass::Abandon_Production(int factory) Factories.Raw_Ptr(factory)->Abandon(); Buildables[index].Factory = -1; abandon = true; - } else { + } + else { if (Buildables[index].Factory != -1) { noprod = false; } @@ -2437,23 +2456,26 @@ void SidebarClass::Zoom_Mode_Control(void) ** radar spying readout => zoomed */ if (IsRadarActive) { - if (Is_Zoomed() || Session.Type==GAME_NORMAL) { + if (Is_Zoomed() || Session.Type == GAME_NORMAL) { if (Is_Zoomed() || !Spy_Next_House()) { Zoom_Mode(Coord_Cell(TacticalCoord)); } - } else { + } + else { if (!Spying_On_House() && !Is_Player_Names()) { Player_Names(1); - } else { + } + else { Player_Names(0); if (!Spy_Next_House()) { Zoom_Mode(Coord_Cell(TacticalCoord)); } } } - } else { - if (Session.Type!=GAME_NORMAL) { - Player_Names(Is_Player_Names()==0); + } + else { + if (Session.Type != GAME_NORMAL) { + Player_Names(Is_Player_Names() == 0); } } #else @@ -2464,23 +2486,26 @@ void SidebarClass::Zoom_Mode_Control(void) ** radar spying readout => not zoomed */ if (IsRadarActive) { - if (Session.Type==GAME_NORMAL) { + if (Session.Type == GAME_NORMAL) { if (!Spy_Next_House()) { Zoom_Mode(Coord_Cell(TacticalCoord)); } - } else { + } + else { if (!Spying_On_House() && !Is_Player_Names()) { Player_Names(1); - } else { + } + else { Player_Names(0); if (!Spy_Next_House()) { Zoom_Mode(Coord_Cell(TacticalCoord)); } } } - } else { - if (Session.Type!=GAME_NORMAL) { - Player_Names(Is_Player_Names()==0); + } + else { + if (Session.Type != GAME_NORMAL) { + Player_Names(Is_Player_Names() == 0); } } #endif diff --git a/scripts/_Global.script b/scripts/_Global.script index e266642..6b4a09b 100644 --- a/scripts/_Global.script +++ b/scripts/_Global.script @@ -4,115 +4,148 @@ -- * * -- *=======================================================* + -- ********************************************************* + -- * * + -- * Houses (players) * + -- * * + -- ********************************************************* + Houses={ + SPAIN=0, -- YELLOW/GOLD + GREECE=1, -- BLUE-GREY + USSR=2, -- RED + ENGLAND=3, -- GREEN + UKRAINE=4, -- ORANGE + GERMANY=5, -- KHAKI/LIGHT BROWN + FRANCE=6, -- AQUA + TURKEY=7, -- RED-OCHRE + GOODGUY=8, -- BLUE-GREY + BADGUY=9, -- RED + NEUTRAL=10, -- YELLOW/GOLD + SPECIAL=11, -- YELLOW/GOLD + MULTI1=12, -- YELLOW/GOLD + MULTI2=13, -- BLUE-GREY + MULTI3=14, -- RED + MULTI4=15, -- GREEN + MULTI5=16, -- ORANGE + MULTI6=17, -- KHAKI/LIGHT BROWN + MULTI7=18, -- AQUA + MULTI8=19 -- RED-OCHRE + } -- ********************************************************* -- * * -- * Buildings * -- * * -- ********************************************************* - - BUILDING_ATEK=0 -- Allied Technology Centre - BUILDING_IRON=1 -- Iron Curtain - BUILDING_WEAP=2 -- Weapons Factory - BUILDING_PDOX=3 -- Chronosphere - BUILDING_PBOX=4 -- Pillbox - BUILDING_HBOX=5 -- Camouflaged Pillbox - BUILDING_DOME=6 -- Radar Dome - BUILDING_GAP =7 -- Gap Generator - BUILDING_GUN =8 -- Gun Turret - BUILDING_AGUN=9 -- Anti-Aircraft Gun - BUILDING_FTUR=10 -- Flame Turret - BUILDING_FACT=11 -- Construction Yard - BUILDING_PROC=12 -- Ore Refinery - BUILDING_SILO=13 -- Ore Silo - BUILDING_HPAD=14 -- Helicopter Pad - BUILDING_SAM =15 -- SAM Site - BUILDING_AFLD=16 -- Airfield - BUILDING_POWR=17 -- Power Plant - BUILDING_APWR=18 -- Advanced Power Plant - BUILDING_STEK=19 -- Soviet Technology Centre - BUILDING_HOSP=20 -- Hospital - BUILDING_BARR=21 -- Barracks (Allied) - BUILDING_TENT=22 -- Barracks (Soviet) - BUILDING_KENN=23 -- Dog Kennel - BUILDING_FIX =24 -- Service Depot - BUILDING_BIO =25 -- Bio-Research Laboratory - BUILDING_MISS=26 -- Technology Centre/Prison - BUILDING_SYRD=27 -- Ship Yard - BUILDING_SPEN=28 -- Sub Pen - BUILDING_MSLO=29 -- Missile Silo - BUILDING_FCOM=30 -- Forward Command Post - BUILDING_TSLA=31 -- Tesla Coil - BUILDING_WEAF=32 -- Fake Weapons Factory - BUILDING_FACF=33 -- Fake Construction Yard - BUILDING_SYRF=34 -- Fake Ship Yard - BUILDING_SPEF=35 -- Fake Sub Pen - BUILDING_DOMF=36 -- Fake Radar Dome - BUILDING_MINV=43 -- Anti-vehicle mine - BUILDING_MINP=44 -- Anti-personnel mine + + BuildingTypes={ + ATEK=0, -- Allied Technology Centre + IRON=1, -- Iron Curtain + WEAP=2, -- Weapons Factory + PDOX=3, -- Chronosphere + PBOX=4, -- Pillbox + HBOX=5, -- Camouflaged Pillbox + DOME=6, -- Radar Dome + GAP =7, -- Gap Generator + GUN =8, -- Gun Turret + AGUN=9, -- Anti-Aircraft Gun + FTUR=10, -- Flame Turret + FACT=11, -- Construction Yard + PROC=12, -- Ore Refinery + SILO=13, -- Ore Silo + HPAD=14, -- Helicopter Pad + SAM =15, -- SAM Site + AFLD=16, -- Airfield + POWR=17, -- Power Plant + APWR=18, -- Advanced Power Plant + STEK=19, -- Soviet Technology Centre + HOSP=20, -- Hospital + BARR=21, -- Barracks (Allied) + TENT=22, -- Barracks (Soviet) + KENN=23, -- Dog Kennel + FIX =24, -- Service Depot + BIO =25, -- Bio-Research Laboratory + MISS=26, -- Technology Centre/Prison + SYRD=27, -- Ship Yard + SPEN=28, -- Sub Pen + MSLO=29, -- Missile Silo + FCOM=30, -- Forward Command Post + TSLA=31, -- Tesla Coil + WEAF=32, -- Fake Weapons Factory + FACF=33, -- Fake Construction Yard + SYRF=34, -- Fake Ship Yard + SPEF=35, -- Fake Sub Pen + DOMF=36, -- Fake Radar Dome + MINV=43, -- Anti-vehicle mine + MINP=44, -- Anti-personnel mine -- Counterstrike - BUILDING_QUEE=84 -- Queen ant structure - BUILDING_LAR1=85 -- Ant - single ant larva - BUILDING_LAR2=86 -- Ant - two ant larvae - + QUEE=84, -- Queen ant structure + LAR1=85, -- Ant - single ant larva + LAR2=86 -- Ant - two ant larvae + } + -- ********************************************************* -- * * -- * Infantry * -- * * -- ********************************************************* - INFANTRY_E1=0 -- Rifle Infantry - INFANTRY_E2=1 -- Grenadier - INFANTRY_E3=2 -- Rocket Soldier - INFANTRY_E4=3 -- Flamethrower - INFANTRY_E6=4 -- Engineer - INFANTRY_E7=5 -- Tanya - INFANTRY_SPY=6 -- Spy - INFANTRY_THF=7 -- Thief - INFANTRY_MEDI=8 -- Field Medic - INFANTRY_GNRL=9 -- General - INFANTRY_DOG=10 -- Attack Dog - INFANTRY_C1=11 -- Joe - INFANTRY_C2=12 -- Barry - INFANTRY_C3=13 -- Shelly - INFANTRY_C4=14 -- Maria - INFANTRY_C5=15 -- Karen - INFANTRY_C6=16 -- Steve - INFANTRY_C7=17 -- Phil - INFANTRY_C8=18 -- Dwight - INFANTRY_C9=19 -- Erik - INFANTRY_C10=20 -- Scientist - INFANTRY_EINSTEIN=21 -- Prof. Einstein - INFANTRY_DELPHI=22 -- Special 1 - INFANTRY_CHAN=23 -- Special 2 - + InfantryTypes={ + E1=0, -- Rifle Infantry + E2=1, -- Grenadier + E3=2, -- Rocket Soldier + E4=3, -- Flamethrower + E6=4, -- Engineer + E7=5, -- Tanya + SPY=6, -- Spy + THF=7, -- Thief + MEDI=8, -- Field Medic + GNRL=9, -- General + DOG=10, -- Attack Dog + C1=11, -- Joe + C2=12, -- Barry + C3=13, -- Shelly + C4=14, -- Maria + C5=15, -- Karen + C6=16, -- Steve + C7=17, -- Phil + C8=18, -- Dwight + C9=19, -- Erik + C10=20, -- Scientist + EINSTEIN=21, -- Prof. Einstein + DELPHI=22, -- Special 1 + CHAN=23 -- Special 2 + } + -- ********************************************************* -- * * -- * Vehicle * -- * * -- ********************************************************* - VEHICLE_4TNK=0 -- Mammoth Tank - VEHICLE_3TNK=1 -- Heavy Tank - VEHICLE_2TNK=2 -- Medium Tank - VEHICLE_1TNK=3 -- Light Tank - VEHICLE_APC=4 -- Armoured Personnel Carrier - VEHICLE_MNLY=5 -- Mine Layer - VEHICLE_JEEP=6 -- Ranger - VEHICLE_HARV=7 -- Ore Truck - VEHICLE_ARTY=8 -- Artillery - VEHICLE_MRJ=9 -- Mobile Radar Jammer - VEHICLE_MGG=10 -- Mobile Gap Generator - VEHICLE_MCV=11 -- Mobile Construction Vehicle - VEHICLE_2VRL=12 -- V2 Rocket Launcher - VEHICLE_TRUK=13 -- Convoy Truck + VehicleTypes={ + _4TNK=0, -- Mammoth Tank + _3TNK=1, -- Heavy Tank + _2TNK=2, -- Medium Tank + _1TNK=3, -- Light Tank + APC=4, -- Armoured Personnel Carrier + MNLY=5, -- Mine Layer + JEEP=6, -- Ranger + HARV=7, -- Ore Truck + ARTY=8, -- Artillery + MRJ=9, -- Mobile Radar Jammer + MGG=10, -- Mobile Gap Generator + MCV=11, -- Mobile Construction Vehicle + _2VRL=12, -- V2 Rocket Launcher + TRUK=13, -- Convoy Truck -- Counterstrike only: - VEHICLE_ANT1=14 -- First ant type - VEHICLE_ANT2=15 -- Second ant type - VEHICLE_ANT3=16 -- Third ant type + ANT1=14, -- First ant type + ANT2=15, -- Second ant type + ANT3=16 -- Third ant type + } -- ********************************************************* -- * * @@ -120,77 +153,241 @@ -- * * -- ********************************************************* - AIRCRAFT_TRAN=0 -- Chinook Helicopter - AIRCRAFT_BADR=1 -- Badger Bomber - AIRCRAFT_U2=2 -- Spy Plane - AIRCRAFT_MIG=3 -- MIG Attack Plane - AIRCRAFT_YAK=4 -- Yak Attack Plane - AIRCRAFT_HELI=5 -- Longbow Helicopter - AIRCRAFT_HIND=6 -- Hind Helicopter - + AircraftTypes={ + TRAN=0, -- Chinook Helicopter + BADR=1, -- Badger Bomber + U2=2, -- Spy Plane + MIG=3, -- MIG Attack Plane + YAK=4, -- Yak Attack Plane + HELI=5, -- Longbow Helicopter + HIND=6 -- Hind Helicopter + } + -- ********************************************************* -- * * - -- * Houses (players) * + -- * Vessels * -- * * -- ********************************************************* - HOUSE_SPAIN= 0 -- YELLOW/GOLD - HOUSE_GREECE=1 -- BLUE-GREY - HOUSE_USSR=2 -- RED - HOUSE_ENGLAND=3 -- GREEN - HOUSE_UKRAINE=4 -- ORANGE - HOUSE_GERMANY=5 -- KHAKI/LIGHT BROWN - HOUSE_FRANCE=6 -- AQUA - HOUSE_TURKEY=7 -- RED-OCHRE - HOUSE_GOODGUY=8 -- BLUE-GREY - HOUSE_BADGUY=9 -- RED - HOUSE_NEUTRAL=10 -- YELLOW/GOLD - HOUSE_SPECIAL=11 -- YELLOW/GOLD - HOUSE_MULTI1=12 -- YELLOW/GOLD - HOUSE_MULTI2=13 -- BLUE-GREY - HOUSE_MULTI3=14 -- RED - HOUSE_MULTI4=15 -- GREEN - HOUSE_MULTI5=16 -- ORANGE - HOUSE_MULTI6=17 -- KHAKI/LIGHT BROWN - HOUSE_MULTI7=18 -- AQUA - HOUSE_MULTI8=19 -- RED-OCHRE - + VesselTypes={ + SS=0, -- Submarine + DD=1, -- Destroyer + CA=2, -- Cruiser + LST=3, -- Land Sea Tank (transport) + PT=4 -- Gun Boat + } + + -- ********************************************************* + -- * * + -- * Armor Types * + -- * * + -- ********************************************************* + ArmorTypes={ + NONE=0, + WOOD=1, + ALUMINUM=2, + STEEL=3, + CONCRETE=4 + } + + -- ********************************************************* + -- * * + -- * Weapon Types * + -- * * + -- ********************************************************* + WeaponTypes={ + NONE=-1, + COLT45=0, + ACK_ACK=1, + VULCAN=2, + MAVERICK=3, + CAMERA=4, + FIREBALL=5, + RIFLE=6, + CHAIN_GUN=7, + PISTOL=8, + M16=9, + DRAGON=10, + HELLFIRE=11, + GRENADE=12, + _75MM=13, + _90MM=14, + _105MM=15, + _120MM=16, + TURRET_GUN=17, + MAMMOTH_TUSK=18, + _155MM=19, + M60MG=20, + NAPALM=21, + TESLA_ZAP=22, + NIKE=23, + _8INCH=24, + STINGER=25, + TORPEDO=26, + _2INCH=27, + DEPTH_CHARGE=28, + PARA_BOMB=29, + DOGJAW=30, + HEAL=31, + SCUD=32, + FLAMER=33, + REDEYE=34 + } + + + -- ********************************************************* -- * * -- * Special weapons * -- * * -- ********************************************************* - SPECIAL_WEAPON_SONAR=0 - SPECIAL_WEAPON_NUKE=1 - SPECIAL_WEAPON_CHRONO=2 - SPECIAL_WEAPON_PARABOMB=3 - SPECIAL_WEAPON_PARATROOPS=4 - SPECIAL_WEAPON_SPY_PLANE=5 - SPECIAL_WEAPON_IRON_CURTAIN=6 - SPECIAL_WEAPON_GPS=7 - + SpecialWeapons={ + Sonar=0, + Nuke=1, + Chrono=2, + Parabomb=3, + Paratroops=4, + SpyPlane=5, + IronCurtain=6, + GPS=7 + } + -- ********************************************************* -- * * -- * Target types (for use with DesignatePreferredTarget) * -- * * -- ********************************************************* - TARGET_TYPE_ANYTHING=1 - TARGET_TYPE_BUILDINGS=2 - TARGET_TYPE_HARVESTERS=3 - TARGET_TYPE_INFANTRY=4 - TARGET_TYPE_VEHICLES=5 - TARGET_TYPE_SHIPS=6 - TARGET_TYPE_FACTORIES=7 - TARGET_TYPE_BASE_DEFENCES=8 - TARGET_TYPE_BASE_THREATS=9 - TARGET_TYPE_POWER=10 - TARGET_TYPE_FAKE_BUILDINGS=11 - + TargetTypes={ + Anything=1, + Buildings=2, + Harvesters=3, + Infantry=4, + Vehicles=5, + Ships=6, + Factories=7, + BaseDefences=8, + BaseThreats=9, + Power=10, + FakeBuildings=11 + } + -- ********************************************************* -- * * -- * Trigger persistance * -- * * -- ********************************************************* - TRIGGER_VOLATILE=0 - TRIGGER_SEMI_PERSISTENT=1 - TRIGGER_PERSISTENT=2 + PersistenceTypes={ + Volatile=0, + SemiPersistent=1, + Persistent=2 + } + + -- ********************************************************* + -- * * + -- * Obejct Attributes * + -- * * + -- ********************************************************* + ObjectAttributes = { + Type=0, + Strength=1, -- Object attribute + MaxStrength=2, -- Definition attribute + Cost=3, -- Definition attribute + SightRange=4, -- Definition attribute + TechLevel=5, -- Definition attribute + Armor=6, + PrimaryWeapon=7, + SecondaryWeapon=8, + Speed=9, + MaxSpeed=10, + MaxAmmo=11, + RotationSpeed=12, + IsCrushable=13, + IsStealthy=14, + IsSelectable=15, + IsLegalTarget=16, + IsRepairable=17, + IsSelfHealing=18, + Explodes=19, + HasCrew=20, + MaxPassengers=21, + IsRepairing=22, + + -- Building Specific + Capacity=23, + Power=24, + Sellable=25, + + -- Unit Specific + IsCrateGoodie=26, + IsCrusher=27, + IsHarvest=28, + IsRadarEquipped=29, + IsJammer=30, + IsGapper=31, + + -- Infantry Specific + IsFemale=32, + Capture=33, + IsFraidyCat=34, + IsCivilian=35, + IsBomber=36, + IsDog=37 + + } + + -- ********************************************************* + -- * * + -- * House Attributes * + -- * * + -- ********************************************************* + HouseAttributes = { + IQ = 0, + TechLevel =1, + IsHuman=2, + FirepowerBias=3, + GroundspeedBias=4, + ArmorBias=5, + ROFBias=6, + CostBias=7, + RepairDelay=8, + BuildDelay=9, + Started=10, + Alerted=11, + BaseBuilding=12, + Discovered=13, + Capacity=14, + Tiberium=15, + Credits=16, + AlertTimer=17, + RepairTimer=18, + Points=19, + DestroyedBuildings=20, + DestroyedVehicles=21, + DestroyedInfantry=22, + DestroyedAircraft=23, + DestroyedVessels=24, + CapturedBuildings=25, + Crates=26, + BuildingFactories=27, + VehicleFactories=28, + InfantryFactories=29, + AircraftFactories=30, + VesselFactories=31, + + Power=32, + Drain=33, + LastAttacker=34 + } + + -- ********************************************************* + -- * * + -- * Fear Type Attribute Values * + -- * * + -- ********************************************************* + FearTypes={ + None=0, -- No fear at all (default state). + Anxious=10, -- Something makes them scared. + Scared=100, -- Scared enough to take cover. + Panic=200, -- Run away! Run away! + Maximum=255 -- Scared to death. + } \ No newline at end of file