Files
CnC_Remastered_Collection/code/REDALERT/MapScript.cpp
T
nev6502 eb7ddd289c Work done on the scripting engine
Probably going to need some discussion
2020-06-12 20:44:44 -06:00

606 lines
37 KiB
C++

// MapScript.cpp
//
#include "FUNCTION.H"
#include "MapScript.h"
/***********************************************************************************************
* Script_GiveCreditsToPlayer - Gives a given player a given amount of credits *
* *
* SCRIPT INPUT: houseType (int) - The player (house) index to count buildings for *
* cashToGive (int) - The amount of cold hard credits to give the player *
* *
* SCRIPT OUTPUT: result (number) - The amount of the given buildings for that player *
* *
* 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_GiveCreditsToPlayer(lua_State* L) {
int houseType = lua_tointeger(L, 1);
int cashToGive = 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) {
house->Refund_Money(cashToGive);
}
}
return 1;
}
/***********************************************************************************************
* Script_NumBuildingTypeForPlayer - Returns the amount of specific buildings for a player *
* *
* SCRIPT INPUT: houseType (int) - The player (house) index to count buildings for *
* structType (int) - The structure index to count buildings for *
* *
* SCRIPT OUTPUT: result (number) - The amount of the given buildings for that player *
* *
* INPUT: lua_State - The current Lua state *
* *
* OUTPUT: int; Did the function run successfully? Return 1 *
* *
* WARNINGS: ? *
* *
*=============================================================================================*/
static int Script_NumBuildingTypeForPlayer(lua_State* L) {
int houseType = lua_tointeger(L, 1);
int structType = lua_tointeger(L, 2);
int result = 0;
for (int b_index = 0; b_index < Buildings.Count(); b_index++) {
BuildingClass* building = Buildings.Ptr(b_index);
if (building->Owner() == houseType) {
if (building->Class->Type == structType) {
result++;
}
}
}
lua_pushnumber(L, result);
return 1;
}
/***********************************************************************************************
* Script_StartMissionTimer - 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_StartMissionTimer(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_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.Start();
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: void *
* *
* 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);
assert(teamPtr != NULL);
ScenarioInit++;
teamPtr->Create_One_Of();
ScenarioInit--;
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 - Reveals the entire map *
* *
* 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_DestroyTrigger(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_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 createEnabled = true;
houseType = lua_tointeger(L, 1);
if (lua_gettop(L) == 2) {
createEnabled = lua_toboolean(L, 2);
}
if (createEnabled) {
HouseClass::As_Pointer((HousesType)houseType)->AlertTime = 0;
}
if (houseType != HOUSE_NONE) {
HouseClass* specified_house = HouseClass::As_Pointer((HousesType)houseType);
specified_house->IsAlerted = createEnabled;
}
return 1;
}
/***********************************************************************************************
* Script_AllowWin - Allows a win...ire map *
* *
* 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::As_Pointer((HousesType)houseType)->Blockage++;
}
return 1;
}
/***********************************************************************************************
* Script_RevealAll - Reveals the entire map TODO: input player *
* *
* SCRIPT INPUT: ret (int) - The waypoint index of which to reveal *
* *
* SCRIPT OUTPUT: void *
* *
* INPUT: lua_State - The current Lua state *
* *
* OUTPUT: int; Did the function run successfully? Return 1 *
* *
* WARNINGS: ? *
* *
*=============================================================================================*/
static int Script_RevealAll(lua_State* L) {
if (!PlayerPtr->IsVisionary) {
PlayerPtr->IsVisionary = true;
for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
Map.Map_Cell(cell, PlayerPtr);
}
}
return 1;
}
/***********************************************************************************************
* Script_RevealCell - Reveals map around given waypoint TODO: input player *
* *
* SCRIPT INPUT: ret (int) - The waypoint index of which to reveal *
* *
* SCRIPT OUTPUT: void *
* *
* INPUT: lua_State - The current Lua state *
* *
* OUTPUT: int; Did the function run successfully? Return 1 *
* *
* WARNINGS: ? *
* *
*=============================================================================================*/
static int Script_RevealCell(lua_State* L) {
int ret = lua_tointeger(L, -1);
if (!PlayerPtr->IsVisionary) {
Map.Sight_From(Scen.Waypoint[ret], Rule.GapShroudRadius, PlayerPtr, false);
}
return 1;
}
/***********************************************************************************************
* Script_RevealZone - Reveals area of map around given waypoint TODO: input player *
* *
* Reveal all cells of the zone that the specified waypoint is located in. This can be *
* used to reveal whole islands or bodies of water *
* *
* SCRIPT INPUT: ret (int) - The waypoint index of which to reveal *
* *
* SCRIPT OUTPUT: void *
* *
* INPUT: lua_State - The current Lua state *
* *
* OUTPUT: int; Did the function run successfully? Return 1 *
* *
* WARNINGS: ? *
* *
*=============================================================================================*/
static int Script_RevealZone(lua_State* L) {
int ret = lua_tointeger(L, -1);
if (!PlayerPtr->IsVisionary) {
int zone = Map[Scen.Waypoint[ret]].Zones[MZONE_CRUSHER];
for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
if (Map[cell].Zones[MZONE_CRUSHER] == zone) {
Map.Map_Cell(cell, PlayerPtr);
}
}
}
return 1;
}
/***********************************************************************************************
* Script_PlaySound - Plays the given Sound *
* *
* SCRIPT INPUT: ret (int) - The sound index of which to play *
* *
* SCRIPT OUTPUT: void *
* *
* INPUT: lua_State - The current Lua state *
* *
* OUTPUT: int; Did the function run successfully? Return 1 *
* *
* WARNINGS: ? *
* *
*=============================================================================================*/
static int Script_PlaySound(lua_State* L) {
int ret = lua_tointeger(L, -1);
Sound_Effect((VocType)ret);
return 1;
}
/***********************************************************************************************
* Script_PlayMusic - Plays the given Music score. *
* *
* 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);
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_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;
}
/***********************************************************************************************
* 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);
} //BriefingText
/***********************************************************************************************
* 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];
sprintf(scriptName, "scripts/%s.script", mapName);
L = luaL_newstate();
if (luaL_loadfile(L, scriptName) || lua_pcall(L, 0, 0, 0)) {
L = NULL;
return false;
}
/**********************************************************************************************
* Red Alert Vanilla Actions *
*=============================================================================================*/
// player wins!
// player loses.
// computer begins factory production.
lua_register(L, "CreateTeam", Script_CreateTeam); // computer creates a certain type of team
// destroy team (comment was redacted. was something offensive originally written?)
// all enemy units go into hunt mode (teams destroyed).
// player gets reinforcements
// (house that gets them is determined by
// the Reinforcement instance)
// Deploy drop zone smoke.
// 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.
// Force trigger to activate.
lua_register(L, "StartMissionTimer", Script_StartMissionTimer); // Start mission timer.
lua_register(L, "StopMissionTimer", Script_StopMissionTimer); // Stop mission timer.
/**********************************************************************************************
* Red Alert Vanilla Events *
*=============================================================================================*/
// player enters this square
// Spied by.
// Thieved by (raided or stolen vehicle).
// player discovers this object
// House has been discovered.
// player attacks this object
// player destroys this object
// Any object event will cause the trigger.
// all house's units destroyed
// all house's buildings destroyed
// all house's units & buildings destroyed
// house reaches this many credits
// Scenario elapsed time from start.
// Pre expired mission timer.
// Number of buildings destroyed.
// Number of units destroyed.
// No factories left.
// Civilian has been evacuated.
// Specified building has been built.
// Specified unit has been built.
// Specified infantry has been built.
// Specified aircraft has been built.
// Specified team member leaves map.
// Enters same zone as waypoint 'x'.
// Crosses horizontal trigger line.
// Crosses vertical trigger line.
// If specified global has been set.
// If specified global has been cleared.
// If all fake structures are gone.
// When power drops below 100%.
// All bridges destroyed.
// Check for building existing.
/**********************************************************************************************
* Utility Functions *
*=============================================================================================*/
lua_register(L, "SetBriefingText", Script_SetBriefingText); // Sets the [text] on the mission briefing screen
lua_register(L, "GiveCreditsToPlayer", Script_GiveCreditsToPlayer); // Give [player] [credits]
lua_register(L, "NumBuildingTypeForPlayer", Script_NumBuildingTypeForPlayer); // Number of buildings of [type] for given [player]
/**********************************************************************************************
* Script Globals *
*=============================================================================================*/
lua_pushnumber(L, PlayerPtr->ID); // Local (human) player
lua_setglobal(L, "_localPlayer");
return true;
}