Lua save-banks!

* Array of 8 INT32's natively embedded into savedata (net and SP)!
* Initialised to zero whenever a new save (or equivalent) is started, otherwise untouched by the base game.
* Requires reservation to avoid clobber-conflicts.
    * Access via `reserveLuabanks()` - returns a read-write userdata.
    * Assign userdata to local variable or global rawset to use later.

Mostly for future SUGOIlikes, but I'm sure someone could figure out an unrelated usage eventually.
This commit is contained in:
toaster 2019-08-24 18:25:27 +01:00
parent 9d2e7b66ba
commit 4e256b73b2
9 changed files with 191 additions and 8 deletions

View File

@ -716,6 +716,7 @@ void D_StartTitle(void)
botskin = 0;
cv_debug = 0;
emeralds = 0;
memset(&luabanks, 0, sizeof(luabanks));
lastmaploaded = 0;
// In case someone exits out at the same time they start a time attack run,

View File

@ -1908,7 +1908,10 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
precache = false;
if (resetplayer && !FLS)
{
emeralds = 0;
memset(&luabanks, 0, sizeof(luabanks));
}
if (modeattacking)
{
@ -4103,6 +4106,7 @@ void Command_ExitGame_f(void)
botskin = 0;
cv_debug = 0;
emeralds = 0;
memset(&luabanks, 0, sizeof(luabanks));
if (dirmenu)
closefilemenu(true);

View File

@ -418,6 +418,10 @@ extern UINT16 emeralds;
#define EMERALD7 64
#define ALL7EMERALDS(v) ((v & (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) == (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7))
// yes, even in non HAVE_BLUA
#define NUM_LUABANKS 8 // please only make this number go up between versions, never down. you'll break saves otherwise. also, must fit in UINT8
extern INT32 luabanks[NUM_LUABANKS];
extern INT32 nummaprings; //keep track of spawned rings/coins
/** Time attack information, currently a very small structure.

View File

@ -172,6 +172,7 @@ static boolean retrying = false;
UINT8 stagefailed; // Used for GEMS BONUS? Also to see if you beat the stage.
UINT16 emeralds;
INT32 luabanks[NUM_LUABANKS]; // yes, even in non HAVE_BLUA
UINT32 token; // Number of tokens collected in a level
UINT32 tokenlist; // List of tokens collected
boolean gottoken; // Did you get a token? Used for end of act
@ -3778,7 +3779,29 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
// File end marker check
CHECKPOS
if (READUINT8(save_p) != 0x1d) BADSAVE;
switch (READUINT8(save_p))
{
case 0xb7:
{
UINT8 i, banksinuse;
CHECKPOS
banksinuse = READUINT8(save_p);
CHECKPOS
if (banksinuse > NUM_LUABANKS)
BADSAVE
for (i = 0; i < banksinuse; i++)
{
(void)READINT32(save_p);
CHECKPOS
}
if (READUINT8(save_p) != 0x1d)
BADSAVE
}
case 0x1d:
break;
default:
BADSAVE
}
// done
saved = FIL_WriteFile(backup, savebuffer, length);

View File

@ -182,6 +182,8 @@ static const struct {
{META_CAMERA, "camera_t"},
{META_ACTION, "action"},
{META_LUABANKS, "luabanks[]"},
{NULL, NULL}
};
@ -228,6 +230,18 @@ static int lib_isPlayerAdmin(lua_State *L)
return 1;
}
static int lib_reserveLuabanks(lua_State *L)
{
static boolean reserved = false;
if (!lua_lumploading)
return luaL_error(L, "luabanks[] cannot be reserved from within a hook or coroutine!");
if (reserved)
return luaL_error(L, "luabanks[] has already been reserved! Only one savedata-enabled mod at a time may use this feature.");
reserved = true;
LUA_PushUserdata(L, &luabanks, META_LUABANKS);
return 1;
}
// M_RANDOM
//////////////
@ -2736,6 +2750,7 @@ static luaL_Reg lib[] = {
{"chatprintf", lib_chatprintf},
{"userdataType", lib_userdataType},
{"IsPlayerAdmin", lib_isPlayerAdmin},
{"reserveLuabanks", lib_reserveLuabanks},
// m_random
{"P_RandomFixed",lib_pRandomFixed},

View File

@ -18,6 +18,7 @@
#include "p_mobj.h"
#include "p_local.h"
#include "z_zone.h"
#include "doomstat.h" // luabanks[]
#include "lua_script.h"
#include "lua_libs.h"
@ -146,7 +147,7 @@ static int lib_getSpr2default(lua_State *L)
return luaL_error(L, "spr2defaults[] invalid index");
if (i >= free_spr2)
return 0;
return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, 0, free_spr2-1);
lua_pushinteger(L, spr2defaults[i]);
return 1;
@ -1026,6 +1027,61 @@ static int sfxinfo_num(lua_State *L)
return 1;
}
//////////////
// LUABANKS //
//////////////
static int lib_getluabanks(lua_State *L)
{
UINT8 i;
lua_remove(L, 1); // don't care about luabanks[] dummy userdata.
if (lua_isnumber(L, 1))
i = lua_tonumber(L, 1);
else
return luaL_error(L, "luabanks[] invalid index");
if (i >= NUM_LUABANKS)
luaL_error(L, "luabanks[] index %d out of range (%d - %d)", i, 0, NUM_LUABANKS);
lua_pushinteger(L, luabanks[i]);
return 1;
}
static int lib_setluabanks(lua_State *L)
{
UINT8 i;
INT32 j = 0;
if (hud_running)
return luaL_error(L, "Do not alter luabanks[] in HUD rendering code!");
lua_remove(L, 1); // don't care about luabanks[] dummy userdata.
if (lua_isnumber(L, 1))
i = lua_tonumber(L, 1);
else
return luaL_error(L, "luabanks[] invalid index");
if (i >= NUM_LUABANKS)
luaL_error(L, "luabanks[] index %d out of range (%d - %d)", i, 0, NUM_LUABANKS-1);
if (lua_isnumber(L, 2))
j = lua_tonumber(L, 2);
else
return luaL_error(L, "luabanks[] invalid set");
luabanks[i] = j;
return 0;
}
static int lib_luabankslen(lua_State *L)
{
lua_pushinteger(L, NUM_LUABANKS);
return 1;
}
//////////////////////////////
//
// Now push all these functions into the Lua state!
@ -1147,6 +1203,18 @@ int LUA_InfoLib(lua_State *L)
lua_pushvalue(L, -1);
lua_setglobal(L, "S_sfx");
lua_setglobal(L, "sfxinfo");
luaL_newmetatable(L, META_LUABANKS);
lua_pushcfunction(L, lib_getluabanks);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, lib_setluabanks);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, lib_luabankslen);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
return 0;
}

View File

@ -67,6 +67,8 @@ extern lua_State *gL;
#define META_ACTION "ACTIONF_T*"
#define META_LUABANKS "LUABANKS[]*"
boolean luaL_checkboolean(lua_State *L, int narg);
int LUA_EnumLib(lua_State *L);

View File

@ -6885,6 +6885,7 @@ static void M_StartTutorial(INT32 choice)
tutorialmode = true; // turn on tutorial mode
emeralds = 0;
memset(&luabanks, 0, sizeof(luabanks));
M_ClearMenus(true);
gamecomplete = false;
cursaveslot = 0;
@ -7293,7 +7294,29 @@ static void M_ReadSavegameInfo(UINT32 slot)
// File end marker check
CHECKPOS
if (READUINT8(save_p) != 0x1d) BADSAVE;
switch (READUINT8(save_p))
{
case 0xb7:
{
UINT8 i, banksinuse;
CHECKPOS
banksinuse = READUINT8(save_p);
CHECKPOS
if (banksinuse > NUM_LUABANKS)
BADSAVE
for (i = 0; i < banksinuse; i++)
{
(void)READINT32(save_p);
CHECKPOS
}
if (READUINT8(save_p) != 0x1d)
BADSAVE
}
case 0x1d:
break;
default:
BADSAVE
}
// done
Z_Free(savebuffer);
@ -8495,6 +8518,7 @@ static void M_ChooseNightsAttack(INT32 choice)
char nameofdemo[256];
(void)choice;
emeralds = 0;
memset(&luabanks, 0, sizeof(luabanks));
M_ClearMenus(true);
modeattacking = ATTACKING_NIGHTS;
@ -8519,6 +8543,7 @@ static void M_ChooseTimeAttack(INT32 choice)
char nameofdemo[256];
(void)choice;
emeralds = 0;
memset(&luabanks, 0, sizeof(luabanks));
M_ClearMenus(true);
modeattacking = ATTACKING_RECORD;

View File

@ -4109,12 +4109,54 @@ static inline boolean P_NetUnArchiveMisc(void)
return true;
}
static inline void P_ArchiveLuabanksAndConsistency(void)
{
UINT8 i, banksinuse = NUM_LUABANKS;
while (banksinuse && !luabanks[banksinuse-1])
banksinuse--; // get the last used bank
if (banksinuse)
{
WRITEUINT8(save_p, 0xb7); // luabanks marker
WRITEUINT8(save_p, banksinuse);
for (i = 0; i < banksinuse; i++)
WRITEINT32(save_p, luabanks[i]);
}
WRITEUINT8(save_p, 0x1d); // consistency marker
}
static inline boolean P_UnArchiveLuabanksAndConsistency(void)
{
switch (READUINT8(save_p))
{
case 0xb7:
{
UINT8 i, banksinuse = READUINT8(save_p);
if (banksinuse > NUM_LUABANKS)
return false;
for (i = 0; i < banksinuse; i++)
luabanks[i] = READINT32(save_p);
if (READUINT8(save_p) != 0x1d)
return false;
}
case 0x1d:
break;
default:
return false;
}
return true;
}
void P_SaveGame(void)
{
P_ArchiveMisc();
P_ArchivePlayer();
WRITEUINT8(save_p, 0x1d); // consistency marker
// yes, even in non HAVE_BLUA
P_ArchiveLuabanksAndConsistency();
}
void P_SaveNetGame(void)
@ -4153,7 +4195,7 @@ void P_SaveNetGame(void)
LUA_Archive();
#endif
WRITEUINT8(save_p, 0x1d); // consistency marker
P_ArchiveLuabanksAndConsistency();
}
boolean P_LoadGame(INT16 mapoverride)
@ -4165,8 +4207,7 @@ boolean P_LoadGame(INT16 mapoverride)
P_UnArchiveSPGame(mapoverride);
P_UnArchivePlayer();
// Savegame end marker
if (READUINT8(save_p) != 0x1d)
if (!P_UnArchiveLuabanksAndConsistency())
return false;
// Only do this after confirming savegame is ok
@ -4207,5 +4248,5 @@ boolean P_LoadNetGame(void)
// precipitation when loading a netgame save. Instead, precip has to be spawned here.
// This is done in P_NetUnArchiveSpecials now.
return READUINT8(save_p) == 0x1d;
return P_UnArchiveLuabanksAndConsistency();
}