mirror of
https://github.com/jmarshall23/CnC_Remastered_Collection.git
synced 2026-08-12 08:00:55 +02:00
Added ability to attach Lua/MapScript callbacks to a trigger. Can be set to work with complex trigger actions.
Added scripts path to Lua so that Lua can find scripts within scripts/
This commit is contained in:
+113
-1
@@ -72,6 +72,59 @@ static int Script_NumBuildingTypeForPlayer(lua_State* L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Script_SetTriggerCallback - Adds a lua callback to an existing trigger *
|
||||
* *
|
||||
* SCRIPT INPUT: triggerName (string) - The ININame of the trigger via its class *
|
||||
* callbackName (string) - The function name to be called when the actions *
|
||||
* have been met *
|
||||
* actionIndex (int) (optional) - 0 (default): 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) {
|
||||
|
||||
const char* triggerName = lua_tostring(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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
strncpy(trigger->MapScriptCallback,callbackName,sizeof(trigger->MapScriptCallback ) - 1);
|
||||
trigger->MapScriptActionIndex = actionIndex;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Script_Win - The specified player wins *
|
||||
@@ -779,11 +832,47 @@ static int Script_SetBriefingText(lua_State* L) {
|
||||
* *
|
||||
*=============================================================================================*/
|
||||
void MapScript::CallFunction(const char* functionName) {
|
||||
|
||||
lua_getglobal(L, functionName);
|
||||
lua_pcall(L, 0, 0, 0);
|
||||
|
||||
} //BriefingText
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* 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::Init -- Loads and initializes script for a given map *
|
||||
* *
|
||||
@@ -798,14 +887,35 @@ void MapScript::CallFunction(const char* functionName) {
|
||||
*=============================================================================================*/
|
||||
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)) {
|
||||
luaL_openlibs(L);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************************
|
||||
* Red Alert Vanilla Actions *
|
||||
*=============================================================================================*/
|
||||
@@ -883,6 +993,8 @@ bool MapScript::Init(const char* mapName) {
|
||||
lua_register(L, "GiveCreditsToPlayer", Script_GiveCreditsToPlayer); // Give [player] [credits]
|
||||
lua_register(L, "NumBuildingTypeForPlayer", Script_NumBuildingTypeForPlayer); // Number of buildings of [type] for given [player]
|
||||
|
||||
lua_register(L, "SetTriggerCallback", Script_SetTriggerCallback); // Initiates a given [callback] on an existing [trigger]
|
||||
|
||||
|
||||
/**********************************************************************************************
|
||||
* Script Globals *
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// MapScript.h
|
||||
//
|
||||
|
||||
#ifndef MAPSCRIPT_H
|
||||
#define MAPSCRIPT_H
|
||||
|
||||
// Lua is written in C, so compiler needs to know how to link its libraries
|
||||
extern "C" {
|
||||
# include "lua.h"
|
||||
@@ -15,6 +18,8 @@ class MapScript {
|
||||
public:
|
||||
bool Init(const char* mapName);
|
||||
void CallFunction(const char* functionName);
|
||||
void SetLuaPath(const char* input_path);
|
||||
private:
|
||||
lua_State* L;
|
||||
};
|
||||
#endif
|
||||
+11
-13
@@ -60,7 +60,6 @@
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "function.h"
|
||||
#include "MapScript.h"
|
||||
#ifdef WIN32
|
||||
#include "tcpip.h"
|
||||
#include "ccdde.h"
|
||||
@@ -111,7 +110,6 @@ bool Is_Mission_Counterstrike (char *file_name);
|
||||
bool Is_Mission_Aftermath (char *file_name);
|
||||
#endif
|
||||
|
||||
MapScript* mapScript = nullptr;
|
||||
bool mapScriptPlayStart = false;
|
||||
|
||||
void Cmd_Map(void);
|
||||
@@ -332,13 +330,13 @@ bool Start_Scenario(char * name, bool briefing)
|
||||
}
|
||||
|
||||
// jmarshall: map scripts
|
||||
if (mapScript) {
|
||||
delete mapScript;
|
||||
if (Scen.mapScript) {
|
||||
delete Scen.mapScript;
|
||||
}
|
||||
mapScript = new MapScript();
|
||||
if (!mapScript->Init(name)) {
|
||||
delete mapScript;
|
||||
mapScript = nullptr;
|
||||
Scen.mapScript = new MapScript();
|
||||
if (!Scen.mapScript->Init(name)) {
|
||||
delete Scen.mapScript;
|
||||
Scen.mapScript = nullptr;
|
||||
}
|
||||
else {
|
||||
mapScriptPlayStart = true;
|
||||
@@ -379,11 +377,11 @@ bool Start_Scenario(char * name, bool briefing)
|
||||
// }
|
||||
Theme.Stop();
|
||||
// jmarshall - map scripts
|
||||
if (mapScript) {
|
||||
if (Scen.mapScript) {
|
||||
Hide_Mouse();
|
||||
VisiblePage.Clear();
|
||||
Show_Mouse();
|
||||
mapScript->CallFunction("map_briefing");
|
||||
Scen.mapScript->CallFunction("map_briefing");
|
||||
}
|
||||
else if (briefing) {
|
||||
Hide_Mouse();
|
||||
@@ -430,16 +428,16 @@ bool Start_Scenario(char * name, bool briefing)
|
||||
}
|
||||
|
||||
void Scenario_MapScriptFrame(void) {
|
||||
if (!mapScript)
|
||||
if (!Scen.mapScript)
|
||||
return;
|
||||
|
||||
if (mapScriptPlayStart) {
|
||||
mapScript->CallFunction("map_start");
|
||||
Scen.mapScript->CallFunction("map_start");
|
||||
mapScriptPlayStart = false;
|
||||
return;
|
||||
}
|
||||
|
||||
mapScript->CallFunction("map_frame");
|
||||
Scen.mapScript->CallFunction("map_frame");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#ifndef SCENARIO_H
|
||||
#define SCENARIO_H
|
||||
|
||||
#include "MapScript.h"
|
||||
|
||||
|
||||
/*
|
||||
** This class holds the information about the current game being played. This information is
|
||||
@@ -328,6 +330,12 @@ class ScenarioClass {
|
||||
#endif
|
||||
|
||||
bool warpIntoMap;
|
||||
|
||||
|
||||
/*
|
||||
** MapScript storage, to be accessed by triggers etc.
|
||||
*/
|
||||
MapScript* mapScript = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "function.h"
|
||||
#include "MapScript.h"
|
||||
|
||||
|
||||
#if defined(CHEAT_KEYS) || defined(SCENARIO_EDITOR)
|
||||
@@ -228,6 +229,7 @@ bool TriggerClass::Spring(TEventType event, ObjectClass * obj, CELL cell, bool f
|
||||
bool e1 = Class->Event1(Event1, event, Class->House, obj, forced);
|
||||
bool e2 = false;
|
||||
bool execute = false;
|
||||
bool execute_mapScript = false;
|
||||
|
||||
/*
|
||||
** Forced triggers must presume that the cell parameter is invalid. It then
|
||||
@@ -295,6 +297,13 @@ bool TriggerClass::Spring(TEventType event, ObjectClass * obj, CELL cell, bool f
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** We need to execute this trigger, so is there an attached MapScript callback?
|
||||
*/
|
||||
if (Scen.mapScript != NULL && strlen(MapScriptCallback) > 0) {
|
||||
execute_mapScript = true;
|
||||
}
|
||||
|
||||
/*
|
||||
** For linked trigger events, perform the action associated with the matching
|
||||
** trigger event. Otherwise perform the action for both events.
|
||||
@@ -302,19 +311,45 @@ bool TriggerClass::Spring(TEventType event, ObjectClass * obj, CELL cell, bool f
|
||||
bool ok = false;
|
||||
HousesType hh = Class->House;
|
||||
if (Class->EventControl == MULTI_LINKED) {
|
||||
if (e1 || forced) ok |= Class->Action1(hh, obj, ID, cell);
|
||||
if (e2 && !forced) ok |= Class->Action2(hh, obj, ID, cell);
|
||||
if (e1 || forced) {
|
||||
ok |= Class->Action1(hh, obj, ID, cell);
|
||||
|
||||
// Execute MapScript Callback for action 1?
|
||||
if (ok && execute_mapScript && MapScriptActionIndex <= 1) {
|
||||
Scen.mapScript->CallFunction(MapScriptCallback);
|
||||
}
|
||||
}
|
||||
if (e2 && !forced) {
|
||||
ok |= Class->Action2(hh, obj, ID, cell);
|
||||
|
||||
// Execute MapScript Callback for action 2?
|
||||
if (ok && execute_mapScript && MapScriptActionIndex != 1) {
|
||||
Scen.mapScript->CallFunction(MapScriptCallback);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
switch (Class->ActionControl) {
|
||||
case MULTI_ONLY:
|
||||
ok |= Class->Action1(hh, obj, ID, cell);
|
||||
|
||||
// Execute MapScript Callback for action 1?
|
||||
if (ok && execute_mapScript && MapScriptActionIndex <= 1) {
|
||||
Scen.mapScript->CallFunction(MapScriptCallback);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
case MULTI_AND:
|
||||
ok |= Class->Action1(hh, obj, ID, cell);
|
||||
ok |= Class->Action2(hh, obj, ID, cell);
|
||||
|
||||
// Execute MapScript Callback for action?
|
||||
if (ok && execute_mapScript) {
|
||||
Scen.mapScript->CallFunction(MapScriptCallback);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,12 @@ class TriggerClass {
|
||||
** Some additional padding in case we need to add data to the class and maintain backwards compatibility for save/load
|
||||
*/
|
||||
unsigned char SaveLoadPadding[32];
|
||||
|
||||
/*
|
||||
** Store MapScript callback function and optional action index (because there can be multiple outcomes) -- JJ 6/14/2020
|
||||
*/
|
||||
char MapScriptCallback[32];
|
||||
char MapScriptActionIndex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user