From b25087e3e8d44f66b7e87975a4588dc9d12fd6be Mon Sep 17 00:00:00 2001 From: Overhaul Date: Sat, 20 Oct 2007 07:01:16 +0000 Subject: [PATCH] Added LUA support: Control over rain and ambient light, as well as light fixtures Ability to change number of static enemies in a sector Ability to create enemy groups and set their waypoints Ability to set soldier APs, change stance, and change level git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@1529 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- lua/Lua Interpreter.h | 12 ++ lua/lua.cpp | 194 ++----------------- lua/lua_2005Express.vcproj | 12 ++ lua/lua_env.cpp | 87 +++++++++ lua/lua_strategic.cpp | 369 +++++++++++++++++++++++++++++++++++++ lua/lua_tactical.cpp | 199 ++++++++++++++++++++ 6 files changed, 697 insertions(+), 176 deletions(-) create mode 100644 lua/lua_env.cpp create mode 100644 lua/lua_strategic.cpp create mode 100644 lua/lua_tactical.cpp diff --git a/lua/Lua Interpreter.h b/lua/Lua Interpreter.h index 293712f1..59f13187 100644 --- a/lua/Lua Interpreter.h +++ b/lua/Lua Interpreter.h @@ -11,9 +11,21 @@ typedef struct { lua_CFunction get; lua_CFunction set; lua_CFunction call; + lua_CFunction staticcall; } LuaAttrib; void InitializeLua( ); int EvalLua (const wchar_t* buff) ; // The return value is whether to clear the input line, not whether the call succeeded. void ShutdownLua( ); +extern luaL_Reg WStringMethods[]; +extern LuaAttrib Environment[]; +extern LuaAttrib Soldier[]; +extern LuaAttrib Sector[]; + +void CreateLuaClass( lua_State *L, STR8 ClassName, LuaAttrib *Attribs ); +void NewLuaObject( lua_State *L, STR8 ClsName, void *Ptr ); + +void LuaStrategicSetup(lua_State *L); +void LuaTacticalSetup(lua_State *L); +void LuaEnvironmentSetup(lua_State *L); diff --git a/lua/lua.cpp b/lua/lua.cpp index 81425328..b2c09913 100644 --- a/lua/lua.cpp +++ b/lua/lua.cpp @@ -2,20 +2,14 @@ #include #include #include "Lua Interpreter.h" -#include "lwstring.h" -#include "Overhead.h" -#include "Isometric Utils.h" -#include "soldier tile.h" -#include "Soldier Profile.h" -#include "ai.h" +#include +#include "MemMan.h" lua_State *L; #define ARRAY_INDEX " idx" // The space is intentional to make this an out-of-band field -#define SOLDIER_CLASS "ja2_SoldierClass" - void CreateLuaType( lua_State *L, STR8 TypeName, luaL_Reg *LuaAccessors ) { luaL_Reg *idx; @@ -123,6 +117,7 @@ luaL_Reg ClassList[] = { void CreateLuaClass( lua_State *L, STR8 ClassName, LuaAttrib *Attribs ) { luaL_Reg *i; + LuaAttrib *idx; luaL_newmetatable( L, ClassName ); for (i = ClassList; i->name; i++) @@ -132,6 +127,16 @@ void CreateLuaClass( lua_State *L, STR8 ClassName, LuaAttrib *Attribs ) lua_pushcclosure( L, i->func, 1); lua_rawset( L, -3); } + + for (idx=Attribs; idx->name; idx++) + { + if (idx->staticcall) + { + lua_pushstring( L, idx->name); + lua_pushcfunction( L, idx->staticcall); + lua_rawset( L, -3 ); + } + } } @@ -170,167 +175,9 @@ void NewLuaObject( lua_State *L, STR8 ClsName, void *Ptr ) -static int LuaGetMercPtr( lua_State *L) -{ - int v = lua_tointeger( L, 2 ); - luaL_argcheck( L, (v >= 0 && v < TOTAL_SOLDIERS), 2, "The soldier index is out of range"); - if (MercPtrs[ v ] ) - { - NewLuaObject( L, "ja2_SoldierClass", MercPtrs[ v ] ); - } - else - { - lua_pushnil( L ); - } - - return 1; -} - -static luaL_Reg SoldierList[] = { - { "__index", LuaGetMercPtr, }, - { NULL, }, -}; - -int LuaGetSoldierName( lua_State *L ) -{ - SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); - SOLDIERTYPE *pSoldier = *ppSoldier; - if (!pSoldier) - { - lua_pushnil( L ); - } - else - { - luaWS_newstr( L, pSoldier->name); - } - return 1; -} - -int LuaGetSoldierFullName( lua_State *L ) -{ - SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); - SOLDIERTYPE *pSoldier = *ppSoldier; - if (!pSoldier) - { - lua_pushnil( L ); - } - else - { - if (pSoldier->ubProfile < NUM_PROFILES) - { - luaWS_newstr( L, gMercProfiles[pSoldier->ubProfile].zName ); - } - else - { - return LuaGetSoldierName( L); - } - } - return 1; -} - -int LuaGetSoldierGrid( lua_State *L ) -{ - SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); - SOLDIERTYPE *pSoldier = *ppSoldier; - if (!pSoldier) - { - lua_pushnil( L ); - } - else - { - lua_pushinteger( L, pSoldier->sGridNo); - } - return 1; -} - -int LuaSetSoldierGrid( lua_State *L ) -{ - SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); - SOLDIERTYPE *pSoldier = *ppSoldier; - int newgrid = luaL_checkinteger( L, 3); - luaL_argcheck( L, newgrid > 0 && newgrid <= NOWHERE, 2, "The grid number must be on screen!" ); - TeleportSoldier( pSoldier, newgrid, TRUE); - return 0; -} - -int LuaGetSoldierAPs( lua_State *L ) -{ - SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); - SOLDIERTYPE *pSoldier = *ppSoldier; - if (!pSoldier) - { - lua_pushnil( L ); - } - else - { - lua_pushinteger( L, pSoldier->bActionPoints); - } - return 1; -} - -int LuaSetSoldierAPs( lua_State *L ) -{ - SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); - SOLDIERTYPE *pSoldier = *ppSoldier; - int newaps = luaL_checkinteger( L, 3); - luaL_argcheck( L, newaps > 0 && newaps < 256, 2, "The grid number must be on screen!" ); - pSoldier->bActionPoints = (INT8) newaps; - return 0; -} - -int LuaSoldierWalkTo( lua_State *L ) -{ - SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) luaL_checkudata( L, 1, SOLDIER_CLASS ); - SOLDIERTYPE *pSoldier = *ppSoldier; - int newgrid = luaL_checkinteger( L, 2); - luaL_argcheck( L, newgrid > 0 && newgrid <= NOWHERE, 2, "The grid number must be on screen!" ); - pSoldier->bAction = AI_ACTION_WALK; - pSoldier->usActionData = newgrid; - pSoldier->bPathStored = FALSE; - pSoldier->bActionInProgress = ExecuteAction( pSoldier); - return 0; -} - -int LuaSoldierRunTo( lua_State *L ) -{ - SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) luaL_checkudata( L, 1, SOLDIER_CLASS ); - SOLDIERTYPE *pSoldier = *ppSoldier; - int newgrid = luaL_checkinteger( L, 2); - luaL_argcheck( L, newgrid > 0 && newgrid <= NOWHERE, 2, "The grid number must be on screen!" ); - pSoldier->bAction = AI_ACTION_RUN; - pSoldier->usActionData = newgrid; - pSoldier->bPathStored = FALSE; - pSoldier->bActionInProgress = ExecuteAction( pSoldier); - return 0; -} - -int LuaSoldierChangeStance( lua_State *L ) -{ - SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) luaL_checkudata( L, 1, SOLDIER_CLASS ); - SOLDIERTYPE *pSoldier = *ppSoldier; - int newstance = luaL_checkinteger( L, 2); - ChangeSoldierStance( pSoldier, (UINT8) newstance); - return 0; -} - -LuaAttrib Soldier[] = { - { "name", LuaGetSoldierName, }, - { "fullname", LuaGetSoldierFullName, }, - { "grid", LuaGetSoldierGrid, LuaSetSoldierGrid }, - { "APs", LuaGetSoldierAPs, LuaSetSoldierAPs }, - { "walkto", NULL, NULL, LuaSoldierWalkTo }, - { "runto", NULL, NULL, LuaSoldierRunTo }, - { "changestance", NULL, NULL, LuaSoldierChangeStance }, - { NULL, }, -}; - - - -extern luaL_Reg WStringMethods[]; - void InitializeLua( ) { L = lua_open(); @@ -345,15 +192,10 @@ void InitializeLua( ) CreateLuaType( L, "wstring", WStringMethods); lua_setglobal( L, "wstring"); // We also want this class to be known to the script - // Create a soldier type - CreateLuaClass( L, SOLDIER_CLASS, Soldier ); - lua_setglobal( L, SOLDIER_CLASS); // We also want this class to be known to the script - - // Create a soldier list type and create its object - CreateLuaType( L, "ja2_SoldierListClass", SoldierList); - CreateLuaObject( L, NULL ); - // Give this new object a name - lua_setglobal( L, "Soldiers" ); + // Set up the game info + LuaTacticalSetup( L); + LuaStrategicSetup( L); + LuaEnvironmentSetup( L); } int EvalLua (const wchar_t* buff) { @@ -379,7 +221,7 @@ int EvalLua (const wchar_t* buff) { lua_pop(L, 1); /* pop error message from the stack */ return FALSE; } - cout << lua_tostring(L, -1) << endl; + printf( "%s\n", lua_tostring(L, -1)); lua_pop(L, 1); /* pop error message from the stack */ return TRUE; } diff --git a/lua/lua_2005Express.vcproj b/lua/lua_2005Express.vcproj index e82d7d06..16906d30 100644 --- a/lua/lua_2005Express.vcproj +++ b/lua/lua_2005Express.vcproj @@ -184,6 +184,18 @@ RelativePath=".\lua.cpp" > + + + + + + diff --git a/lua/lua_env.cpp b/lua/lua_env.cpp new file mode 100644 index 00000000..87abdf58 --- /dev/null +++ b/lua/lua_env.cpp @@ -0,0 +1,87 @@ +#include "Lua Interpreter.h" +#include "environment.h" + +#define ENVIRONMENT_CLASS "ja2_EnvironmentClass" + +static int LuaGetRainVal( lua_State *L ) +{ + lua_pushinteger( L, guiEnvWeather); + return 1; +} + +static int LuaSetRainVal( lua_State *L ) +{ + int newrain = luaL_checkinteger( L, 3); + luaL_argcheck( L, newrain >= 0 && newrain <= 2, 2, "The rain must be between 0 and 2" ); + if (newrain == 0) + { + EnvEndRainStorm(); + } + else + { + EnvBeginRainStorm( (UINT8)(newrain-1)); + } + return 0; +} + +static int LuaGetAmbient( lua_State *L ) +{ + lua_pushinteger( L, gubEnvLightValue); + return 1; +} + +static int LuaSetAmbient( lua_State *L ) +{ + int newambient = luaL_checkinteger( L, 3); + luaL_argcheck( L, newambient >= 0 && newambient <= 255, 2, "The ambience must be between 0 and 255" ); + gubEnvLightValue = (UINT8)newambient; + if( !gfBasement && !gfCaves ) + gfDoLighting = TRUE; + return 0; +} + +static int LuaSetNightLights( lua_State *L ) +{ + int newprime = luaL_checkinteger( L, 1); + if (newprime) + { + TurnOnNightLights(); + } + else + { + TurnOffNightLights(); + } + return 0; +} + +static int LuaSetPrimeLights( lua_State *L ) +{ + int newprime = luaL_checkinteger( L, 1); + if (newprime) + { + TurnOnPrimeLights(); + } + else + { + TurnOffPrimeLights(); + } + return 0; +} + +static LuaAttrib Environment[] = { + { "rain", LuaGetRainVal, LuaSetRainVal }, + { "ambient", LuaGetAmbient, LuaSetAmbient }, + { "nightlights", NULL, NULL, LuaSetNightLights }, + { "primelights", NULL, NULL, LuaSetPrimeLights }, + { NULL, }, +}; + + +void LuaEnvironmentSetup(lua_State *L) +{ + // Create the environment object + lua_newtable( L); + CreateLuaClass( L, ENVIRONMENT_CLASS, Environment ); + lua_setmetatable( L, -2); + lua_setglobal( L, "Environment"); // We also want this class to be known to the script +} diff --git a/lua/lua_strategic.cpp b/lua/lua_strategic.cpp new file mode 100644 index 00000000..80c23873 --- /dev/null +++ b/lua/lua_strategic.cpp @@ -0,0 +1,369 @@ +#include "Lua Interpreter.h" +#include "Campaign Types.h" +#include "Strategic Movement.h" + +#define SECTOR_CLASS "ja2_SectorClass" +#define MOBILEGROUP_CLASS "ja2_MobileGroup" + +static int LuaGetSectorNumAdmins( lua_State *L ) +{ + SECTORINFO **ppSector = (SECTORINFO**) lua_touserdata( L, 1 ); + SECTORINFO *pSector = *ppSector; + if (!pSector) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pSector->ubNumAdmins); + } + return 1; +} + +static int LuaSetSectorNumAdmins( lua_State *L ) +{ + SECTORINFO **ppSector = (SECTORINFO**) lua_touserdata( L, 1 ); + SECTORINFO *pSector = *ppSector; + int newnum = luaL_checkinteger( L, 3); + luaL_argcheck( L, newnum >= 0 && newnum < 256, 2, "The number of soldiers must be between 0 and 255" ); + pSector->ubNumAdmins = (UINT8) newnum; + return 0; +} + +static int LuaGetSectorNumTroops( lua_State *L ) +{ + SECTORINFO **ppSector = (SECTORINFO**) lua_touserdata( L, 1 ); + SECTORINFO *pSector = *ppSector; + if (!pSector) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pSector->ubNumTroops); + } + return 1; +} + +static int LuaSetSectorNumTroops( lua_State *L ) +{ + SECTORINFO **ppSector = (SECTORINFO**) lua_touserdata( L, 1 ); + SECTORINFO *pSector = *ppSector; + int newnum = luaL_checkinteger( L, 3); + luaL_argcheck( L, newnum >= 0 && newnum < 256, 2, "The number of soldiers must be between 0 and 255" ); + pSector->ubNumTroops = (UINT8) newnum; + return 0; +} + +static int LuaGetSectorNumElites( lua_State *L ) +{ + SECTORINFO **ppSector = (SECTORINFO**) lua_touserdata( L, 1 ); + SECTORINFO *pSector = *ppSector; + if (!pSector) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pSector->ubNumElites); + } + return 1; +} + +static int LuaSetSectorNumElites( lua_State *L ) +{ + SECTORINFO **ppSector = (SECTORINFO**) lua_touserdata( L, 1 ); + SECTORINFO *pSector = *ppSector; + int newnum = luaL_checkinteger( L, 3); + luaL_argcheck( L, newnum >= 0 && newnum < 256, 2, "The number of soldiers must be between 0 and 255" ); + pSector->ubNumElites = (UINT8) newnum; + return 0; +} + +static int LuaGetSectorNumCreatures( lua_State *L ) +{ + SECTORINFO **ppSector = (SECTORINFO**) lua_touserdata( L, 1 ); + SECTORINFO *pSector = *ppSector; + if (!pSector) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pSector->ubNumCreatures); + } + return 1; +} + +static int LuaSetSectorNumCreatures( lua_State *L ) +{ + SECTORINFO **ppSector = (SECTORINFO**) lua_touserdata( L, 1 ); + SECTORINFO *pSector = *ppSector; + int newnum = luaL_checkinteger( L, 3); + luaL_argcheck( L, newnum >= 0 && newnum < 256, 2, "The number of soldiers must be between 0 and 255" ); + pSector->ubNumCreatures = (UINT8) newnum; + return 0; +} + + +LuaAttrib Sector[] = { + { "numadmins", LuaGetSectorNumAdmins, LuaSetSectorNumAdmins }, + { "numtroops", LuaGetSectorNumTroops, LuaSetSectorNumTroops }, + { "numelites", LuaGetSectorNumElites, LuaSetSectorNumElites }, + { "numcreatures", LuaGetSectorNumCreatures, LuaSetSectorNumCreatures }, + { NULL, }, +}; + + +static int LuaGetGroupList( lua_State *L ) +{ + GROUP *pGroup = gpGroupList; + int idx = 0; + + lua_newtable( L); + + //Count the number of active groups + while( pGroup ) + { + lua_pushinteger( L, pGroup->ubGroupID); + lua_rawseti( L, -2, idx++); + pGroup = pGroup->next; + } + + return 1; +} + +static int LuaGetGroup( lua_State *L ) +{ + int grp = luaL_checkinteger( L, 1); + + GROUP *pGroup = GetGroup( (UINT8) grp); + + if (pGroup) + { + NewLuaObject( L, MOBILEGROUP_CLASS, pGroup); + } + else + { + lua_pushnil( L ); + } + + return 1; +} + +static int LuaGroupCreate( lua_State *L ) +{ + UINT32 Sector = luaL_checkinteger( L, 1); + UINT8 NumAdmins = (UINT8) luaL_checkinteger( L, 2); + UINT8 NumTroops = (UINT8) luaL_checkinteger( L, 3); + UINT8 NumElites = (UINT8) luaL_checkinteger( L, 4); + + GROUP *pGroup = CreateNewEnemyGroupDepartingFromSector( Sector, NumAdmins, NumTroops, NumElites ); + + if (pGroup) + { + NewLuaObject( L, MOBILEGROUP_CLASS, pGroup); + } + else + { + lua_pushnil( L ); + } + + return 1; +} + +static int LuaGetGroupID( lua_State *L ) +{ + GROUP **ppGroup = (GROUP**) lua_touserdata( L, 1 ); + GROUP *pGroup = *ppGroup; + if (!pGroup) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pGroup->ubGroupID); + } + return 1; +} + +static int LuaGetGroupX( lua_State *L ) +{ + GROUP **ppGroup = (GROUP**) lua_touserdata( L, 1 ); + GROUP *pGroup = *ppGroup; + if (!pGroup) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pGroup->ubSectorX); + } + return 1; +} + +static int LuaGetGroupY( lua_State *L ) +{ + GROUP **ppGroup = (GROUP**) lua_touserdata( L, 1 ); + GROUP *pGroup = *ppGroup; + if (!pGroup) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pGroup->ubSectorY); + } + return 1; +} + +static int LuaGetGroupZ( lua_State *L ) +{ + GROUP **ppGroup = (GROUP**) lua_touserdata( L, 1 ); + GROUP *pGroup = *ppGroup; + if (!pGroup) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pGroup->ubSectorZ); + } + return 1; +} + +static int LuaGetGroupWaypoints( lua_State *L ) +{ + GROUP **ppGroup = (GROUP**) lua_touserdata( L, 1 ); + GROUP *pGroup = *ppGroup; + + if (!pGroup) + { + lua_pushnil( L ); + } + else + { + WAYPOINT *waypoint = pGroup->pWaypoints; + int idx = 0; + + lua_newtable(L); + while (waypoint) + { + lua_newtable(L); + lua_pushstring(L, "x"); + lua_pushinteger(L, waypoint->x); + lua_rawset(L, -3); + lua_pushstring(L, "y"); + lua_pushinteger(L, waypoint->y); + lua_rawset(L, -3); + + lua_rawseti(L, -2, idx++); + + waypoint = waypoint->next; + } + } + return 1; +} + +static int LuaGetGroupNumAdmins( lua_State *L ) +{ + GROUP **ppGroup = (GROUP**) lua_touserdata( L, 1 ); + GROUP *pGroup = *ppGroup; + if (!pGroup || !pGroup->pEnemyGroup) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pGroup->pEnemyGroup->ubNumAdmins); + } + return 1; +} + +static int LuaGetGroupNumTroops( lua_State *L ) +{ + GROUP **ppGroup = (GROUP**) lua_touserdata( L, 1 ); + GROUP *pGroup = *ppGroup; + if (!pGroup || !pGroup->pEnemyGroup) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pGroup->pEnemyGroup->ubNumTroops); + } + return 1; +} + +static int LuaGetGroupNumElites( lua_State *L ) +{ + GROUP **ppGroup = (GROUP**) lua_touserdata( L, 1 ); + GROUP *pGroup = *ppGroup; + if (!pGroup || !pGroup->pEnemyGroup) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pGroup->pEnemyGroup->ubNumElites); + } + return 1; +} + +static int LuaGroupAddWaypoint( lua_State *L ) +{ + GROUP **ppGroup = (GROUP**) lua_touserdata( L, 1 ); + GROUP *pGroup = *ppGroup; + if (!pGroup) + { + lua_pushinteger( L, 0 ); + } + else + { + int x = lua_tointeger(L, 2); + int y = lua_tointeger(L, 3); + + lua_pushinteger( L, AddWaypointToPGroup( pGroup, (UINT8) x, (UINT8) y) ); + } + return 1; +} + +static LuaAttrib MobileGroup[] = { + { "grouplist", NULL, NULL, NULL, LuaGetGroupList }, + { "get", NULL, NULL, NULL, LuaGetGroup }, + { "new", NULL, NULL, NULL, LuaGroupCreate }, + + { "ID", LuaGetGroupID }, + { "X", LuaGetGroupX }, + { "Y", LuaGetGroupY }, + { "Z", LuaGetGroupZ }, + { "waypoints", LuaGetGroupWaypoints }, + { "numadmins", LuaGetGroupNumAdmins }, + { "numtroops", LuaGetGroupNumTroops }, + { "numelites", LuaGetGroupNumElites }, + { "addwaypoint", NULL, NULL, LuaGroupAddWaypoint }, + { NULL, }, +}; + +void LuaStrategicSetup(lua_State *L) +{ + // Create a sector type + CreateLuaClass( L, SECTOR_CLASS, Sector ); + //lua_setglobal( L, SECTOR_CLASS); // We also want this class to be known to the script + + // Create a sector list type and create its object + lua_createtable (L, 256, 0); + for (int sect=0; sect < 256; sect++) + { + lua_pushinteger( L, sect); + NewLuaObject( L, SECTOR_CLASS, SectorInfo + sect ); + lua_settable( L, -3); + } + + // Give this new object a name + lua_setglobal( L, "Sectors" ); + + // Create a mobile group type + CreateLuaClass( L, MOBILEGROUP_CLASS, MobileGroup ); + lua_setglobal( L, "MobileGroups"); // We also want this class to be known to the script +} diff --git a/lua/lua_tactical.cpp b/lua/lua_tactical.cpp new file mode 100644 index 00000000..d2c6f028 --- /dev/null +++ b/lua/lua_tactical.cpp @@ -0,0 +1,199 @@ +#include "Lua Interpreter.h" +#include "lwstring.h" + +#include "Overhead.h" +#include "Isometric Utils.h" +#include "soldier tile.h" +#include "Soldier Profile.h" +#include "Soldier Functions.h" +#include "ai.h" + +#define SOLDIER_CLASS "ja2_SoldierClass" + +static int LuaGetSoldierName( lua_State *L ) +{ + SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); + SOLDIERTYPE *pSoldier = *ppSoldier; + if (!pSoldier) + { + lua_pushnil( L ); + } + else + { + luaWS_newstr( L, pSoldier->name); + } + return 1; +} + +static int LuaGetSoldierFullName( lua_State *L ) +{ + SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); + SOLDIERTYPE *pSoldier = *ppSoldier; + if (!pSoldier) + { + lua_pushnil( L ); + } + else + { + if (pSoldier->ubProfile < NUM_PROFILES) + { + luaWS_newstr( L, gMercProfiles[pSoldier->ubProfile].zName ); + } + else + { + return LuaGetSoldierName( L); + } + } + return 1; +} + +static int LuaGetSoldierGrid( lua_State *L ) +{ + SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); + SOLDIERTYPE *pSoldier = *ppSoldier; + if (!pSoldier) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pSoldier->sGridNo); + } + return 1; +} + +static int LuaSetSoldierGrid( lua_State *L ) +{ + SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); + SOLDIERTYPE *pSoldier = *ppSoldier; + int newgrid = luaL_checkinteger( L, 3); + luaL_argcheck( L, newgrid > 0 && newgrid <= NOWHERE, 2, "The grid number must be on map" ); + TeleportSoldier( pSoldier, (INT16) newgrid, TRUE); + return 0; +} + +static int LuaGetSoldierLevel( lua_State *L ) +{ + SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); + SOLDIERTYPE *pSoldier = *ppSoldier; + if (!pSoldier) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pSoldier->bLevel); + } + return 1; +} + +static int LuaSetSoldierLevel( lua_State *L ) +{ + SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); + SOLDIERTYPE *pSoldier = *ppSoldier; + int newlevel = luaL_checkinteger( L, 3); + luaL_argcheck( L, newlevel >= 0 && newlevel <= 1, 2, "The level must be 1 or 0" ); + HandlePlacingRoofMarker( pSoldier, pSoldier->sGridNo, (BOOLEAN) newlevel, TRUE ); + SetSoldierHeight( pSoldier, (FLOAT)50*newlevel ); + HandlePlacingRoofMarker( pSoldier, pSoldier->sGridNo, (BOOLEAN) newlevel, TRUE ); + return 0; +} + +static int LuaGetSoldierAPs( lua_State *L ) +{ + SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); + SOLDIERTYPE *pSoldier = *ppSoldier; + if (!pSoldier) + { + lua_pushnil( L ); + } + else + { + lua_pushinteger( L, pSoldier->bActionPoints); + } + return 1; +} + +static int LuaSetSoldierAPs( lua_State *L ) +{ + SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) lua_touserdata( L, 1 ); + SOLDIERTYPE *pSoldier = *ppSoldier; + int newaps = luaL_checkinteger( L, 3); + luaL_argcheck( L, newaps > 0 && newaps < 256, 2, "The grid number must be on screen!" ); + pSoldier->bActionPoints = (INT8) newaps; + return 0; +} + +static int LuaSoldierWalkTo( lua_State *L ) +{ + SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) luaL_checkudata( L, 1, SOLDIER_CLASS ); + SOLDIERTYPE *pSoldier = *ppSoldier; + int newgrid = luaL_checkinteger( L, 2); + luaL_argcheck( L, newgrid > 0 && newgrid <= NOWHERE, 2, "The grid number must be on screen!" ); + pSoldier->bAction = AI_ACTION_WALK; + pSoldier->usActionData = (INT16) newgrid; + pSoldier->bPathStored = FALSE; + pSoldier->bActionInProgress = ExecuteAction( pSoldier); + return 0; +} + +static int LuaSoldierRunTo( lua_State *L ) +{ + SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) luaL_checkudata( L, 1, SOLDIER_CLASS ); + SOLDIERTYPE *pSoldier = *ppSoldier; + int newgrid = luaL_checkinteger( L, 2); + luaL_argcheck( L, newgrid > 0 && newgrid <= NOWHERE, 2, "The grid number must be on screen!" ); + pSoldier->bAction = AI_ACTION_RUN; + pSoldier->usActionData = (INT16) newgrid; + pSoldier->bPathStored = FALSE; + pSoldier->bActionInProgress = ExecuteAction( pSoldier); + return 0; +} + +static int LuaSoldierChangeStance( lua_State *L ) +{ + SOLDIERTYPE **ppSoldier = (SOLDIERTYPE**) luaL_checkudata( L, 1, SOLDIER_CLASS ); + SOLDIERTYPE *pSoldier = *ppSoldier; + int newstance = luaL_checkinteger( L, 2); + ChangeSoldierStance( pSoldier, (UINT8) newstance); + return 0; +} + +static LuaAttrib Soldier[] = { + { "name", LuaGetSoldierName, }, + { "fullname", LuaGetSoldierFullName, }, + { "grid", LuaGetSoldierGrid, LuaSetSoldierGrid }, + { "level", LuaGetSoldierLevel, LuaSetSoldierLevel }, + { "APs", LuaGetSoldierAPs, LuaSetSoldierAPs }, + { "walkto", NULL, NULL, LuaSoldierWalkTo }, + { "runto", NULL, NULL, LuaSoldierRunTo }, + { "changestance", NULL, NULL, LuaSoldierChangeStance }, + { NULL, }, +}; + + +void LuaTacticalSetup(lua_State *L) +{ + // Create a soldier type + CreateLuaClass( L, SOLDIER_CLASS, Soldier ); + lua_setglobal( L, SOLDIER_CLASS); // We also want this class to be known to the script + + // Create a soldier list type and create its object + lua_createtable (L, 256, 0); + for (int sold=0; sold < 256; sold++) + { + lua_pushinteger( L, sold); + if (MercPtrs[ sold ] ) + { + NewLuaObject( L, SOLDIER_CLASS, MercPtrs[ sold ] ); + } + else + { + lua_pushnil( L ); + } + lua_settable( L, -3); + } + + // Give this new object a name + lua_setglobal( L, "Soldiers" ); +}