Rednukem: Readd gamevars from eduke32 for WW2GI support

# Conflicts:
#	platform/Windows/rednukem.vcxproj
#	platform/Windows/rednukem.vcxproj.filters
#	source/rr/src/events_defs.h
#	source/rr/src/gamedef.h
#	source/rr/src/gamevars.cpp
#	source/rr/src/savegame.cpp
This commit is contained in:
nukeykt 2020-02-07 18:33:08 +09:00 committed by Christoph Oelckers
parent 7909f29691
commit 47572cc01a
10 changed files with 912 additions and 55 deletions

View file

@ -6684,6 +6684,9 @@ static void G_Cleanup(void)
// Xfree(MusicPtr);
Gv_Clear();
hash_free(&h_gamevars);
hash_free(&h_labels);
}

View file

@ -41,6 +41,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
BEGIN_RR_NS
#define LINE_NUMBER (g_lineNumber << 12)
int32_t g_scriptVersion = 14; // 13 = 1.3D-style CON files, 14 = 1.4/1.5 style CON files
char g_scriptFileName[BMAX_PATH] = "(none)"; // file we're currently compiling
@ -61,7 +63,11 @@ static int32_t g_numBraces = 0;
static int32_t C_ParseCommand(int32_t loop);
static int32_t C_SetScriptSize(int32_t size);
static intptr_t apScriptGameEventEnd[MAXEVENTS];
static intptr_t g_parsingActorPtr;
static intptr_t g_scriptEventBreakOffset;
static intptr_t g_scriptEventChainOffset;
static intptr_t g_scriptEventOffset;
static char *textptr;
int32_t g_errorCnt,g_warningCnt;
@ -99,8 +105,12 @@ static tokenmap_t const vm_keywords[] =
{ "addammo", CON_ADDAMMO },
{ "addinventory", CON_ADDINVENTORY },
{ "addkills", CON_ADDKILLS },
{ "addlog", CON_ADDLOGVAR },
{ "addlogvar", CON_ADDLOGVAR },
{ "addphealth", CON_ADDPHEALTH },
{ "addstrength", CON_ADDSTRENGTH },
{ "addvar", CON_ADDVAR },
{ "addvarvar", CON_ADDVARVAR },
{ "addweapon", CON_ADDWEAPON },
{ "ai", CON_AI },
{ "betaname", CON_BETANAME },
@ -121,12 +131,14 @@ static tokenmap_t const vm_keywords[] =
{ "destroyit", CON_DESTROYIT },
{ "else", CON_ELSE },
{ "enda", CON_ENDA },
{ "endevent", CON_ENDEVENT },
{ "endofgame", CON_ENDOFGAME },
{ "ends", CON_ENDS },
{ "fakebubba", CON_FAKEBUBBA },
{ "fall", CON_FALL },
{ "feathers", CON_MAIL },
{ "gamestartup", CON_GAMESTARTUP },
{ "gamevar", CON_GAMEVAR },
{ "garybanjo", CON_GARYBANJO },
{ "getlastpal", CON_GETLASTPAL },
{ "globalsound", CON_GLOBALSOUND },
@ -185,6 +197,12 @@ static tokenmap_t const vm_keywords[] =
{ "ifsquished", CON_IFSQUISHED },
{ "ifstrength", CON_IFSTRENGTH },
{ "iftipcow", CON_IFTIPCOW },
{ "ifvare", CON_IFVARE },
{ "ifvarg", CON_IFVARG },
{ "ifvarl", CON_IFVARL },
{ "ifvarvare", CON_IFVARVARE },
{ "ifvarvarg", CON_IFVARVARG },
{ "ifvarvarl", CON_IFVARVARL },
{ "ifwasweapon", CON_IFWASWEAPON },
{ "ifwind", CON_IFWIND },
{ "include", CON_INCLUDE },
@ -205,6 +223,7 @@ static tokenmap_t const vm_keywords[] =
{ "music", CON_MUSIC },
{ "newpic", CON_NEWPIC },
{ "nullop", CON_NULLOP },
{ "onevent", CON_ONEVENT },
{ "operate", CON_OPERATE },
{ "palfrom", CON_PALFROM },
{ "paper", CON_PAPER },
@ -216,6 +235,8 @@ static tokenmap_t const vm_keywords[] =
{ "resetplayer", CON_RESETPLAYER },
{ "respawnhitag", CON_RESPAWNHITAG },
{ "rndmove", CON_RNDMOVE },
{ "setvar", CON_SETVAR },
{ "setvarvar", CON_SETVARVAR },
{ "sizeat", CON_SIZEAT },
{ "sizeto", CON_SIZETO },
{ "slapplayer", CON_SLAPPLAYER },
@ -243,6 +264,22 @@ static tokenmap_t const vm_keywords[] =
{ "}", CON_RIGHTBRACE },
};
static const vec2_t varvartable[] =
{
{ CON_IFVARVARE, CON_IFVARE },
{ CON_IFVARVARG, CON_IFVARG },
{ CON_IFVARVARL, CON_IFVARL },
{ CON_ADDVARVAR, CON_ADDVAR },
{ CON_SETVARVAR, CON_SETVAR },
};
static inthashtable_t h_varvar = { NULL, INTHASH_SIZE(ARRAY_SIZE(varvartable)) };
static inthashtable_t *const inttables[] = {
&h_varvar,
};
char const * VM_GetKeywordForID(int32_t id)
{
// could be better but this is only called for diagnostics, ayy lmao
@ -258,12 +295,13 @@ char *bitptr; // pointer to bitmap of which bytecode positions contain pointers
#define BITPTR_CLEAR(x) (bitptr[(x)>>3] &= ~(1<<((x)&7)))
#define BITPTR_IS_POINTER(x) (bitptr[(x)>>3] & (1<<((x) &7)))
hashtable_t h_labels = { 11264>>1, NULL };
hashtable_t h_gamevars = { MAXGAMEVARS >> 1, NULL };
hashtable_t h_labels = { 11264>>1, NULL };
static hashtable_t h_keywords = { CON_END>>1, NULL };;
static hashtable_t * const tables[] = {
&h_labels, &h_keywords
&h_labels, &h_keywords, &h_gamevars
};
static hashtable_t * const tables_free [] = {
@ -276,8 +314,14 @@ void C_InitHashes()
{
uint32_t i;
for (i=0; i < ARRAY_SIZE(tables); i++)
hash_init(tables[i]);
for (auto table : tables)
hash_init(table);
for (auto table : inttables)
inthash_init(table);
for (auto &varvar : varvartable)
inthash_add(&h_varvar, varvar.x, varvar.y, 0);
//inithashnames();
initsoundhashnames();
@ -290,7 +334,7 @@ void C_InitHashes()
// "magic" number for { and }, overrides line number in compiled code for later detection
#define IFELSE_MAGIC 31337
static int32_t g_ifElseAborted;
static int32_t g_skipBranch;
static int32_t C_SetScriptSize(int32_t newsize)
{
@ -458,6 +502,9 @@ static int32_t C_SkipComments(void)
while (1);
}
static inline int GetDefID(char const *label) { return hash_find(&h_gamevars, label); }
#define LAST_LABEL (label+(g_labelCnt<<6))
static inline int32_t isaltok(const char c)
{
return (isalnum(c) || c == '{' || c == '}' || c == '/' || c == '\\' || c == '*' || c == '-' || c == '_' ||
@ -502,6 +549,25 @@ static void C_GetNextLabelName(void)
initprintf("%s:%d: debug: label `%s'.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6));
}
static inline void scriptWriteValue(int32_t const value)
{
BITPTR_CLEAR(g_scriptPtr-apScript);
*g_scriptPtr++ = value;
}
// addresses passed to these functions must be within the block of memory pointed to by apScript
static inline void scriptWriteAtOffset(int32_t const value, intptr_t * const addr)
{
BITPTR_CLEAR(addr-apScript);
*(addr) = value;
}
static inline void scriptWritePointer(intptr_t const value, intptr_t * const addr)
{
BITPTR_SET(addr-apScript);
*(addr) = value;
}
static int32_t C_GetKeyword(void)
{
int32_t i;
@ -549,12 +615,10 @@ static int32_t C_GetNextKeyword(void) //Returns its code #
if (EDUKE32_PREDICT_TRUE((i = hash_find(&h_keywords,tempbuf)) >= 0))
{
if (i == CON_LEFTBRACE || i == CON_RIGHTBRACE || i == CON_NULLOP)
*g_scriptPtr = i + (IFELSE_MAGIC<<12);
else *g_scriptPtr = i + (g_lineNumber<<12);
scriptWriteValue(i | (VM_IFELSE_MAGIC<<12));
else scriptWriteValue(i | LINE_NUMBER);
BITPTR_CLEAR(g_scriptPtr-apScript);
textptr += l;
g_scriptPtr++;
if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
initprintf("%s:%d: debug: keyword `%s'.\n", g_scriptFileName, g_lineNumber, tempbuf);
@ -620,6 +684,115 @@ static int32_t parse_hex_constant(const char *hexnum)
return x;
}
static void C_GetNextVarType(int32_t type)
{
int32_t id = 0;
int32_t flags = 0;
auto varptr = g_scriptPtr;
C_SkipComments();
if (!type && !g_labelsOnly && (isdigit(*textptr) || ((*textptr == '-') && (isdigit(*(textptr+1))))))
{
scriptWriteValue(GV_FLAG_CONSTANT);
if (tolower(textptr[1])=='x') // hex constants
scriptWriteValue(parse_hex_constant(textptr+2));
else
scriptWriteValue(parse_decimal_number());
if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
initprintf("%s:%d: debug: constant %ld in place of gamevar.\n", g_scriptFileName, g_lineNumber, (long)(g_scriptPtr[-1]));
#if 1
while (!ispecial(*textptr) && *textptr != ']') textptr++;
#else
C_GetNextLabelName();
#endif
return;
}
else if (*textptr == '-'/* && !isdigit(*(textptr+1))*/)
{
if (EDUKE32_PREDICT_FALSE(type))
{
g_errorCnt++;
C_ReportError(ERROR_SYNTAXERROR);
C_GetNextLabelName();
return;
}
if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
initprintf("%s:%d: debug: flagging gamevar as negative.\n", g_scriptFileName, g_lineNumber); //,Batol(textptr));
flags = GV_FLAG_NEGATIVE;
textptr++;
}
C_GetNextLabelName();
if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,LAST_LABEL)>=0))
{
g_errorCnt++;
C_ReportError(ERROR_ISAKEYWORD);
return;
}
C_SkipComments();
id=GetDefID(LAST_LABEL);
if (id<0) //gamevar not found
{
if (EDUKE32_PREDICT_TRUE(!type && !g_labelsOnly))
{
//try looking for a define instead
Bstrcpy(tempbuf,LAST_LABEL);
id = hash_find(&h_labels,tempbuf);
if (EDUKE32_PREDICT_TRUE(id>=0 && labeltype[id] & LABEL_DEFINE))
{
if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
initprintf("%s:%d: debug: label `%s' in place of gamevar.\n",g_scriptFileName,g_lineNumber,label+(id<<6));
scriptWriteValue(GV_FLAG_CONSTANT);
scriptWriteValue(labelcode[id]);
return;
}
}
g_errorCnt++;
C_ReportError(ERROR_NOTAGAMEVAR);
return;
}
if (EDUKE32_PREDICT_FALSE(type == GAMEVAR_READONLY && aGameVars[id].flags & GAMEVAR_READONLY))
{
g_errorCnt++;
C_ReportError(ERROR_VARREADONLY);
return;
}
else if (EDUKE32_PREDICT_FALSE(aGameVars[id].flags & type))
{
g_errorCnt++;
C_ReportError(ERROR_VARTYPEMISMATCH);
return;
}
if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
initprintf("%s:%d: debug: gamevar `%s'.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
scriptWriteValue(id|flags);
}
#define C_GetNextVar() C_GetNextVarType(0)
static FORCE_INLINE void C_GetManyVarsType(int32_t type, int num)
{
for (; num>0; --num)
C_GetNextVarType(type);
}
#define C_GetManyVars(num) C_GetManyVarsType(0,num)
// returns:
// -1 on EOF or wrong type or error
// 0 if literal value
@ -742,7 +915,7 @@ static int32_t C_CheckMalformedBranch(intptr_t lastScriptPtr)
case CON_ENDS:
case CON_ELSE:
g_scriptPtr = lastScriptPtr + &apScript[0];
g_ifElseAborted = 1;
g_skipBranch = 1;
C_ReportError(-1);
g_warningCnt++;
initprintf("%s:%d: warning: malformed `%s' branch\n",g_scriptFileName,g_lineNumber,
@ -759,14 +932,14 @@ static int32_t C_CheckEmptyBranch(int32_t tw, intptr_t lastScriptPtr)
tw == CON_IFRND || tw == CON_IFHITWEAPON || tw == CON_IFCANSEE || tw == CON_IFCANSEETARGET ||
tw == CON_IFPDISTL || tw == CON_IFPDISTG || tw == CON_IFGOTWEAPONCE)
{
g_ifElseAborted = 0;
g_skipBranch = 0;
return 0;
}
if ((*(g_scriptPtr) & VM_INSTMASK) != CON_NULLOP || *(g_scriptPtr)>>12 != IFELSE_MAGIC)
g_ifElseAborted = 0;
g_skipBranch = 0;
if (EDUKE32_PREDICT_FALSE(g_ifElseAborted))
if (EDUKE32_PREDICT_FALSE(g_skipBranch))
{
C_ReportError(-1);
g_warningCnt++;
@ -942,6 +1115,22 @@ static inline void C_FinishBitOr(int32_t value)
*g_scriptPtr++ = value;
}
static void scriptUpdateOpcodeForVariableType(intptr_t *ins)
{
int opcode = -1;
if (opcode != -1)
{
if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
{
initprintf("%s:%d: %s -> %s for var %s\n", g_scriptFileName, g_lineNumber,
VM_GetKeywordForID(*ins & VM_INSTMASK), VM_GetKeywordForID(opcode), aGameVars[ins[1] & (MAXGAMEVARS-1)].szLabel);
}
scriptWriteAtOffset(opcode | LINE_NUMBER, ins);
}
}
static int32_t C_ParseCommand(int32_t loop)
{
int32_t i, j=0, k=0, tw;
@ -1042,6 +1231,60 @@ static int32_t C_ParseCommand(int32_t loop)
}
continue;
case CON_GAMEVAR:
{
// syntax: gamevar <var1> <initial value> <flags>
// defines var1 and sets initial value.
// flags are used to define usage
// (see top of this files for flags)
if (EDUKE32_PREDICT_FALSE(isdigit(*textptr) || (*textptr == '-')))
{
g_errorCnt++;
C_ReportError(ERROR_SYNTAXERROR);
C_NextLine();
continue;
}
g_scriptPtr--;
C_GetNextLabelName();
if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords, LAST_LABEL)>=0))
{
g_warningCnt++;
C_ReportError(WARNING_VARMASKSKEYWORD);
hash_delete(&h_keywords, LAST_LABEL);
}
int32_t defaultValue = 0;
int32_t varFlags = 0;
if (C_GetKeyword() == -1)
{
C_GetNextValue(LABEL_DEFINE); // get initial value
defaultValue = *(--g_scriptPtr);
j = 0;
while (C_GetKeyword() == -1)
C_BitOrNextValue(&j);
C_FinishBitOr(j);
varFlags = *(--g_scriptPtr);
if (EDUKE32_PREDICT_FALSE((*(g_scriptPtr)&GAMEVAR_USER_MASK)==(GAMEVAR_PERPLAYER|GAMEVAR_PERACTOR)))
{
g_warningCnt++;
varFlags ^= GAMEVAR_PERPLAYER;
C_ReportError(WARNING_BADGAMEVAR);
}
}
Gv_NewVar(LAST_LABEL, defaultValue, varFlags);
continue;
}
case CON_DEFINE:
{
C_GetNextLabelName();
@ -1461,6 +1704,54 @@ static int32_t C_ParseCommand(int32_t loop)
g_checkingIfElse = 0;
continue;
case CON_ONEVENT:
if (EDUKE32_PREDICT_FALSE(g_processingState || g_parsingActorPtr))
{
C_ReportError(ERROR_FOUNDWITHIN);
g_errorCnt++;
}
g_numBraces = 0;
g_scriptPtr--;
g_scriptEventOffset = g_parsingActorPtr = g_scriptPtr - apScript;
C_SkipComments();
j = 0;
while (isaltok(*(textptr+j)))
{
g_szCurrentBlockName[j] = textptr[j];
j++;
}
g_szCurrentBlockName[j] = 0;
// g_labelsOnly = 1;
C_GetNextValue(LABEL_EVENT);
g_labelsOnly = 0;
g_scriptPtr--;
j= *g_scriptPtr; // type of event
g_currentEvent = j;
//Bsprintf(g_szBuf,"Adding Event for %d at %lX",j, g_parsingEventPtr);
//AddLog(g_szBuf);
if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXEVENTS-1))
{
initprintf("%s:%d: error: invalid event ID.\n",g_scriptFileName,g_lineNumber);
g_errorCnt++;
continue;
}
// if event has already been declared then store previous script location
if (!apScriptEvents[j])
{
apScriptEvents[j] = g_scriptEventOffset;
}
else
{
g_scriptEventChainOffset = apScriptEvents[j];
apScriptEvents[j] = g_scriptEventOffset;
}
g_checkingIfElse = 0;
continue;
case CON_CSTAT:
C_GetNextValue(LABEL_DEFINE);
@ -1551,7 +1842,7 @@ static int32_t C_ParseCommand(int32_t loop)
intptr_t const lastScriptPtr = g_scriptPtr - apScript - 1;
g_ifElseAborted = 0;
g_skipBranch = 0;
g_checkingIfElse--;
if (C_CheckMalformedBranch(lastScriptPtr))
@ -1573,6 +1864,143 @@ static int32_t C_ParseCommand(int32_t loop)
continue;
}
case CON_ADDLOGVAR:
g_labelsOnly = 1;
C_GetNextVar();
g_labelsOnly = 0;
continue;
case CON_ADDVAR:
case CON_SETVAR:
setvar:
{
auto ins = &g_scriptPtr[-1];
C_GetNextVarType(GAMEVAR_READONLY);
C_GetNextValue(LABEL_DEFINE);
// replace instructions with special versions for specific var types
scriptUpdateOpcodeForVariableType(ins);
continue;
}
case CON_ADDVARVAR:
case CON_SETVARVAR:
{
setvarvar:
auto ins = &g_scriptPtr[-1];
auto tptr = textptr;
int const lnum = g_lineNumber;
C_GetNextVarType(GAMEVAR_READONLY);
C_GetNextVar();
int const opcode = inthash_find(&h_varvar, *ins & VM_INSTMASK);
if (ins[2] == GV_FLAG_CONSTANT && opcode != -1)
{
if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
{
initprintf("%s:%d: %s -> %s\n", g_scriptFileName, g_lineNumber,
VM_GetKeywordForID(*ins & VM_INSTMASK), VM_GetKeywordForID(opcode));
}
tw = opcode;
scriptWriteAtOffset(opcode | LINE_NUMBER, ins);
g_scriptPtr = &ins[1];
textptr = tptr;
g_lineNumber = lnum;
goto setvar;
}
continue;
}
case CON_IFVARVARE:
case CON_IFVARVARG:
case CON_IFVARVARL:
{
auto const ins = &g_scriptPtr[-1];
auto const lastScriptPtr = &g_scriptPtr[-1] - apScript;
auto const lasttextptr = textptr;
int const lnum = g_lineNumber;
g_skipBranch = false;
C_GetNextVar();
auto const var = g_scriptPtr;
C_GetNextVar();
if (*var == GV_FLAG_CONSTANT)
{
int const opcode = inthash_find(&h_varvar, tw);
if (opcode != -1)
{
if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
{
initprintf("%s:%d: replacing %s with %s\n", g_scriptFileName, g_lineNumber,
VM_GetKeywordForID(*ins & VM_INSTMASK), VM_GetKeywordForID(opcode));
}
scriptWriteAtOffset(opcode | LINE_NUMBER, ins);
tw = opcode;
g_scriptPtr = &ins[1];
textptr = lasttextptr;
g_lineNumber = lnum;
goto ifvar;
}
}
if (C_CheckMalformedBranch(lastScriptPtr))
continue;
auto const offset = g_scriptPtr - apScript;
g_scriptPtr++; // Leave a spot for the fail location
C_ParseCommand(0);
if (C_CheckEmptyBranch(tw, lastScriptPtr))
continue;
auto const tempscrptr = apScript + offset;
scriptWritePointer((intptr_t)g_scriptPtr, tempscrptr);
continue;
}
case CON_IFVARE:
case CON_IFVARG:
case CON_IFVARL:
{
ifvar:
auto const ins = &g_scriptPtr[-1];
auto const lastScriptPtr = &g_scriptPtr[-1] - apScript;
g_skipBranch = false;
C_GetNextVar();
C_GetNextValue(LABEL_DEFINE);
if (C_CheckMalformedBranch(lastScriptPtr))
continue;
scriptUpdateOpcodeForVariableType(ins);
auto const offset = g_scriptPtr - apScript;
g_scriptPtr++; //Leave a spot for the fail location
C_ParseCommand(0);
if (C_CheckEmptyBranch(tw, lastScriptPtr))
continue;
auto const tempscrptr = apScript + offset;
scriptWritePointer((intptr_t)g_scriptPtr, tempscrptr);
j = C_GetKeyword();
if (j == CON_ELSE)
g_checkingIfElse++;
continue;
}
case CON_IFRND:
case CON_IFPDISTL:
@ -1603,7 +2031,7 @@ static int32_t C_ParseCommand(int32_t loop)
intptr_t offset;
intptr_t lastScriptPtr = (g_scriptPtr-&apScript[0]-1);
g_ifElseAborted = 0;
g_skipBranch = 0;
switch (tw)
{
@ -1696,7 +2124,7 @@ static int32_t C_ParseCommand(int32_t loop)
intptr_t offset;
intptr_t lastScriptPtr = (g_scriptPtr-&apScript[0]-1);
g_ifElseAborted = 0;
g_skipBranch = 0;
if (C_CheckMalformedBranch(lastScriptPtr))
continue;
@ -1745,8 +2173,8 @@ static int32_t C_ParseCommand(int32_t loop)
g_scriptPtr -= 2;
if (C_GetKeyword() != CON_ELSE && (*(g_scriptPtr-2) & VM_INSTMASK) != CON_ELSE)
g_ifElseAborted = 1;
else g_ifElseAborted = 0;
g_skipBranch = 1;
else g_skipBranch = 0;
j = C_GetKeyword();
@ -2076,7 +2504,7 @@ static int32_t C_ParseCommand(int32_t loop)
g_warningCnt++;
initprintf("%s:%d: warning: `nullop' found without `else'\n",g_scriptFileName,g_lineNumber);
g_scriptPtr--;
g_ifElseAborted = 1;
g_skipBranch = 1;
}
continue;
@ -2190,6 +2618,9 @@ void C_PrintStats(void)
void C_Compile(const char *fileName)
{
Bmemset(apScriptEvents, 0, sizeof(apScriptEvents));
Bmemset(apScriptGameEventEnd, 0, sizeof(apScriptGameEventEnd));
for (int i=0; i<MAXTILES; i++)
{
Bmemset(&g_tile[i], 0, sizeof(tiledata_t));
@ -2197,6 +2628,7 @@ void C_Compile(const char *fileName)
}
C_InitHashes();
Gv_Init();
auto kFile = fileSystem.OpenFileReader(fileName,0);
@ -2312,15 +2744,33 @@ void C_ReportError(int32_t iError)
case ERROR_OPENBRACKET:
initprintf("%s:%d: error: found more `{' than `}' before `%s'.\n",g_scriptFileName,g_lineNumber,tempbuf);
break;
case ERROR_NOTAGAMEVAR:
initprintf("%s:%d: error: symbol `%s' is not a variable.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
break;
case ERROR_PARAMUNDEFINED:
initprintf("%s:%d: error: parameter `%s' is undefined.\n",g_scriptFileName,g_lineNumber,tempbuf);
break;
case ERROR_SYNTAXERROR:
initprintf("%s:%d: error: syntax error.\n",g_scriptFileName,g_lineNumber);
break;
case ERROR_VARREADONLY:
initprintf("%s:%d: error: variable `%s' is read-only.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
break;
case ERROR_VARTYPEMISMATCH:
initprintf("%s:%d: error: variable `%s' is of the wrong type.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
break;
case WARNING_BADGAMEVAR:
initprintf("%s:%d: warning: variable `%s' should be either per-player OR per-actor, not both.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
break;
case WARNING_DUPLICATEDEFINITION:
initprintf("%s:%d: warning: duplicate definition `%s' ignored.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
break;
case WARNING_LABELSONLY:
initprintf("%s:%d: warning: expected a label, found a constant.\n",g_scriptFileName,g_lineNumber);
break;
case WARNING_VARMASKSKEYWORD:
initprintf("%s:%d: warning: variable `%s' masks keyword.\n", g_scriptFileName, g_lineNumber, LAST_LABEL);
break;
}
}

View file

@ -40,12 +40,16 @@ enum
LABEL_ACTION = 8,
LABEL_AI = 16,
LABEL_MOVE = 32,
LABEL_EVENT = 0x40,
};
#define LABEL_HASPARM2 1
#define LABEL_ISSTRING 2
// "magic" number for { and }, overrides line number in compiled code for later detection
#define VM_IFELSE_MAGIC 31337
#define VM_INSTMASK 0xfff
#define VM_DECODE_LINE_NUMBER(xxx) ((int)((xxx) >> 12))
#define C_CUSTOMERROR(Text, ...) \
do \
@ -66,8 +70,19 @@ enum
extern intptr_t const * insptr;
extern void VM_ScriptInfo(intptr_t const *ptr, int range);
extern hashtable_t h_gamevars;
extern hashtable_t h_labels;
extern int32_t g_aimAngleVarID; // var ID of "AUTOAIMANGLE"
extern int32_t g_angRangeVarID; // var ID of "ANGRANGE"
extern int32_t g_returnVarID; // var ID of "RETURN"
extern int32_t g_weaponVarID; // var ID of "WEAPON"
extern int32_t g_worksLikeVarID; // var ID of "WORKSLIKE"
extern int32_t g_zRangeVarID; // var ID of "ZRANGE"
#include "events_defs.h"
extern intptr_t apScriptEvents[MAXEVENTS];
extern char g_scriptFileName[BMAX_PATH];
extern const uint32_t CheatFunctionFlags[];
@ -151,9 +166,15 @@ enum ScriptError_t
ERROR_FOUNDWITHIN,
ERROR_ISAKEYWORD,
ERROR_OPENBRACKET,
ERROR_NOTAGAMEVAR,
ERROR_PARAMUNDEFINED,
ERROR_SYNTAXERROR,
WARNING_LABELSONLY
ERROR_VARREADONLY,
ERROR_VARTYPEMISMATCH,
WARNING_BADGAMEVAR,
WARNING_DUPLICATEDEFINITION,
WARNING_LABELSONLY,
WARNING_VARMASKSKEYWORD,
};
enum ScriptKeywords_t
@ -306,6 +327,20 @@ enum ScriptKeywords_t
CON_MOTOLOOPSND, // 145
CON_IFSIZEDOWN, // 146
CON_RNDMOVE, // 147
CON_GAMEVAR, // 148
CON_IFVARL, // 149
CON_IFVARG, // 150
CON_SETVARVAR, // 151
CON_SETVAR, // 152
CON_ADDVARVAR, // 153
CON_ADDVAR, // 154
CON_IFVARVARL, // 155
CON_IFVARVARG, // 156
CON_ADDLOGVAR, // 157
CON_ONEVENT, // 158
CON_ENDEVENT, // 159
CON_IFVARE, // 160
CON_IFVARVARE, // 161
CON_END
};
// KEEPINSYNC with the keyword list in lunatic/con_lang.lua

View file

@ -57,10 +57,18 @@ enum vmflags_t
};
int32_t g_tw;
int32_t g_currentEvent = -1;
int32_t g_errorLineNum;
intptr_t const *insptr;
int32_t g_returnVarID = -1; // var ID of "RETURN"
int32_t g_weaponVarID = -1; // var ID of "WEAPON"
int32_t g_worksLikeVarID = -1; // var ID of "WORKSLIKE"
int32_t g_zRangeVarID = -1; // var ID of "ZRANGE"
int32_t g_angRangeVarID = -1; // var ID of "ANGRANGE"
int32_t g_aimAngleVarID = -1; // var ID of "AUTOAIMANGLE"
// for timing events and actors
uint32_t g_actorCalls[MAXTILES];
double g_actorTotalMs[MAXTILES], g_actorMinMs[MAXTILES], g_actorMaxMs[MAXTILES];
@ -122,6 +130,8 @@ static void VM_DeleteSprite(int const spriteNum, int const playerNum)
A_DeleteSprite(spriteNum);
}
intptr_t apScriptEvents[MAXEVENTS];
static int32_t VM_CheckSquished(void)
{
if (RR)
@ -1188,7 +1198,8 @@ GAMEEXEC_STATIC void VM_Execute(native_t loop)
{
case CON_ENDA:
case CON_BREAK:
case CON_ENDS: return;
case CON_ENDS:
case CON_ENDEVENT: return;
case CON_IFRND: VM_CONDITIONAL(rnd(*(++insptr))); continue;
@ -2515,6 +2526,128 @@ GAMEEXEC_STATIC void VM_Execute(native_t loop)
continue;
case CON_IFNOSOUNDS: VM_CONDITIONAL(!A_CheckAnySoundPlaying(vm.spriteNum)); continue;
case CON_IFVARG:
insptr++;
tw = Gv_GetVar(*insptr++);
VM_CONDITIONAL(tw > *insptr);
continue;
case CON_IFVARL:
insptr++;
tw = Gv_GetVar(*insptr++);
VM_CONDITIONAL(tw < *insptr);
continue;
case CON_SETVARVAR:
insptr++;
{
tw = *insptr++;
int const nValue = Gv_GetVar(*insptr++);
if ((aGameVars[tw].flags & (GAMEVAR_USER_MASK | GAMEVAR_PTR_MASK)) == 0)
aGameVars[tw].global = nValue;
else
Gv_SetVar(tw, nValue);
}
continue;
case CON_SETVAR:
Gv_SetVar(insptr[1], insptr[2]);
insptr += 3;
continue;
case CON_ADDVARVAR:
insptr++;
tw = *insptr++;
Gv_AddVar(tw, Gv_GetVar(*insptr++));
continue;
case CON_ADDVAR:
Gv_AddVar(insptr[1], insptr[2]);
insptr += 3;
continue;
case CON_IFVARVARL:
insptr++;
tw = Gv_GetVar(*insptr++);
tw = (tw < Gv_GetVar(*insptr++));
insptr--;
VM_CONDITIONAL(tw);
continue;
case CON_IFVARVARG:
insptr++;
tw = Gv_GetVar(*insptr++);
tw = (tw > Gv_GetVar(*insptr++));
insptr--;
VM_CONDITIONAL(tw);
continue;
case CON_ADDLOGVAR:
insptr++;
{
int32_t m = 1;
char szBuf[256];
int32_t lVarID = *insptr;
if ((lVarID >= g_gameVarCount) || lVarID < 0)
{
if (*insptr == MAXGAMEVARS) // addlogvar for a constant? Har.
insptr++;
else if (EDUKE32_PREDICT_TRUE(*insptr & GV_FLAG_NEGATIVE))
{
m = -m;
lVarID ^= GV_FLAG_NEGATIVE;
}
else
{
// invalid varID
CON_ERRPRINTF("invalid variable\n");
continue;
}
}
Bsprintf(tempbuf, "CONLOGVAR: L=%d %s ", VM_DECODE_LINE_NUMBER(g_tw), aGameVars[lVarID].szLabel);
if (aGameVars[lVarID].flags & GAMEVAR_READONLY)
{
Bsprintf(szBuf, " (read-only)");
Bstrcat(tempbuf, szBuf);
}
if (aGameVars[lVarID].flags & GAMEVAR_PERPLAYER)
{
Bsprintf(szBuf, " (Per Player. Player=%d)", vm.playerNum);
}
else if (aGameVars[lVarID].flags & GAMEVAR_PERACTOR)
{
Bsprintf(szBuf, " (Per Actor. Actor=%d)", vm.spriteNum);
}
else
{
Bsprintf(szBuf, " (Global)");
}
Bstrcat(tempbuf, szBuf);
Bsprintf(szBuf, " =%d\n", Gv_GetVar(lVarID) * m);
Bstrcat(tempbuf, szBuf);
initprintf(OSDTEXT_GREEN "%s", tempbuf);
insptr++;
continue;
}
case CON_IFVARE:
insptr++;
tw = Gv_GetVar(*insptr++);
VM_CONDITIONAL(tw >= *insptr);
continue;
case CON_IFVARVARE:
insptr++;
tw = Gv_GetVar(*insptr++);
tw = (tw == Gv_GetVar(*insptr++));
insptr--;
VM_CONDITIONAL(tw);
continue;
default: // you aren't supposed to be here!
if (RR && ud.recstat == 2)
@ -2537,37 +2670,6 @@ GAMEEXEC_STATIC void VM_Execute(native_t loop)
}
}
// NORECURSE
void A_LoadActor(int32_t spriteNum)
{
vm.spriteNum = spriteNum; // Sprite ID
vm.pSprite = &sprite[spriteNum]; // Pointer to sprite structure
vm.pActor = &actor[spriteNum];
if (g_tile[vm.pSprite->picnum].loadPtr == NULL)
return;
vm.pData = &actor[spriteNum].t_data[0]; // Sprite's 'extra' data
vm.playerNum = -1; // Player ID
vm.playerDist = -1; // Distance
vm.pPlayer = g_player[0].ps;
vm.flags &= ~(VM_RETURN | VM_KILL | VM_NOEXECUTE);
if ((unsigned)vm.pSprite->sectnum >= MAXSECTORS)
{
A_DeleteSprite(vm.spriteNum);
return;
}
insptr = g_tile[vm.pSprite->picnum].loadPtr;
VM_Execute(1);
insptr = NULL;
if (vm.flags & VM_KILL)
A_DeleteSprite(vm.spriteNum);
}
void VM_UpdateAnim(int spriteNum, int32_t *pData)
{
size_t const actionofs = AC_ACTION_ID(pData);

View file

@ -34,10 +34,9 @@ extern int32_t ticrandomseed;
extern vmstate_t vm;
extern int32_t g_tw;
extern int32_t g_currentEvent;
extern int32_t g_errorLineNum;
void A_LoadActor(int32_t spriteNum);
extern uint32_t g_actorCalls[MAXTILES];
extern double g_actorTotalMs[MAXTILES], g_actorMinMs[MAXTILES], g_actorMaxMs[MAXTILES];

View file

@ -23,10 +23,124 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef gamevars_h_
#define gamevars_h_
#define MAXGAMEVARS 2048 // must be a power of two
#define MAXVARLABEL 26
#define GV_FLAG_CONSTANT (MAXGAMEVARS)
#define GV_FLAG_NEGATIVE (MAXGAMEVARS<<1)
// store global game definitions
enum GamevarFlags_t
{
GAMEVAR_PERPLAYER = 0x00000001, // per-player variable
GAMEVAR_PERACTOR = 0x00000002, // per-actor variable
GAMEVAR_USER_MASK = (GAMEVAR_PERPLAYER | GAMEVAR_PERACTOR),
GAMEVAR_RESET = 0x00000008, // INTERNAL, don't use
GAMEVAR_DEFAULT = 0x00000100, // UNUSED, but always cleared for user-defined gamevars
GAMEVAR_NODEFAULT = 0x00000400, // don't reset on actor spawn
GAMEVAR_SYSTEM = 0x00000800, // cannot change mode flags...(only default value)
GAMEVAR_READONLY = 0x00001000, // values are read-only (no setvar allowed)
GAMEVAR_INT32PTR = 0x00002000, // plValues is a pointer to an int32_t
GAMEVAR_INT16PTR = 0x00008000, // plValues is a pointer to a short
GAMEVAR_NORESET = 0x00020000, // var values are not reset when restoring map state
GAMEVAR_SPECIAL = 0x00040000, // flag for structure member shortcut vars
GAMEVAR_NOMULTI = 0x00080000, // don't attach to multiplayer packets
GAMEVAR_Q16PTR = 0x00100000, // plValues is a pointer to a q16.16
GAMEVAR_SERIALIZE = 0x00200000, // write into permasaves
GAMEVAR_RAWQ16PTR = GAMEVAR_Q16PTR | GAMEVAR_SPECIAL, // plValues is a pointer to a q16.16 but we don't want conversion
GAMEVAR_PTR_MASK = GAMEVAR_INT32PTR | GAMEVAR_INT16PTR | GAMEVAR_Q16PTR | GAMEVAR_RAWQ16PTR,
};
// Alignments for per-player and per-actor variables.
#define PLAYER_VAR_ALIGNMENT (sizeof(intptr_t))
#define ACTOR_VAR_ALIGNMENT 16
#define ARRAY_ALIGNMENT 16
#pragma pack(push,1)
typedef struct
{
union {
intptr_t global;
intptr_t *pValues; // array of values when 'per-player', or 'per-actor'
};
intptr_t defaultValue;
uintptr_t flags;
char * szLabel;
} gamevar_t;
#pragma pack(pop)
extern gamevar_t aGameVars[MAXGAMEVARS];
extern int32_t g_gameVarCount;
int __fastcall Gv_GetVar(int const gameVar, int const spriteNum, int const playerNum);
void __fastcall Gv_SetVar(int const gameVar, int const newValue, int const spriteNum, int const playerNum);
int __fastcall Gv_GetVar(int const gameVar);
void __fastcall Gv_GetManyVars(int const numVars, int32_t * const outBuf);
void __fastcall Gv_SetVar(int const gameVar, int const newValue);
template <typename T>
static FORCE_INLINE void Gv_FillWithVars(T & rv)
{
EDUKE32_STATIC_ASSERT(sizeof(T) % sizeof(int32_t) == 0);
EDUKE32_STATIC_ASSERT(sizeof(T) > sizeof(int32_t));
Gv_GetManyVars(sizeof(T)/sizeof(int32_t), (int32_t *)&rv);
}
int Gv_GetVarByLabel(const char *szGameLabel,int defaultValue,int spriteNum,int playerNum);
void Gv_NewVar(const char *pszLabel,intptr_t lValue,uint32_t dwFlags);
static FORCE_INLINE void A_ResetVars(int const spriteNum)
{
for (auto &gv : aGameVars)
{
if ((gv.flags & (GAMEVAR_PERACTOR|GAMEVAR_NODEFAULT)) == GAMEVAR_PERACTOR)
gv.pValues[spriteNum] = gv.defaultValue;
}
}
void Gv_DumpValues(void);
void Gv_InitWeaponPointers(void);
void Gv_RefreshPointers(void);
void Gv_ResetVars(void);
int Gv_ReadSave(buildvfs_kfd kFile);
void Gv_WriteSave(buildvfs_FILE fil);
void Gv_Clear(void);
void Gv_ResetSystemDefaults(void);
void Gv_Init(void);
void Gv_FinalizeWeaponDefaults(void);
#define VM_GAMEVAR_OPERATOR(func, operator) \
static FORCE_INLINE ATTRIBUTE((flatten)) void __fastcall func(int const id, int32_t const operand) \
{ \
auto &var = aGameVars[id]; \
\
switch (var.flags & (GAMEVAR_USER_MASK | GAMEVAR_PTR_MASK)) \
{ \
default: \
var.global operator operand; \
break; \
case GAMEVAR_PERPLAYER: \
var.pValues[vm.playerNum & (MAXPLAYERS-1)] operator operand; \
break; \
case GAMEVAR_PERACTOR: \
var.pValues[vm.spriteNum & (MAXSPRITES-1)] operator operand; \
break; \
case GAMEVAR_INT32PTR: *(int32_t *)var.pValues operator(int32_t) operand; break; \
case GAMEVAR_INT16PTR: *(int16_t *)var.pValues operator(int16_t) operand; break; \
case GAMEVAR_Q16PTR: \
{ \
Fix16 *pfix = (Fix16 *)var.global; \
*pfix operator fix16_from_int(operand); \
break; \
} \
} \
}
VM_GAMEVAR_OPERATOR(Gv_AddVar, +=)
VM_GAMEVAR_OPERATOR(Gv_SubVar, -=)
#undef VM_GAMEVAR_OPERATOR
#endif

View file

@ -56,6 +56,24 @@ extern int32_t PHEIGHT;
#define MAX_WEAPON_RECS 256
enum weaponflags_t {
WEAPON_SPAWNTYPE1 = 0x00000000, // just spawn
WEAPON_HOLSTER_CLEARS_CLIP = 0x00000001, // 'holstering' clears the current clip
WEAPON_GLOWS = 0x00000002, // weapon 'glows' (shrinker and grower)
WEAPON_AUTOMATIC = 0x00000004, // automatic fire (continues while 'fire' is held down
WEAPON_FIREEVERYOTHER = 0x00000008, // during 'hold time' fire every frame
WEAPON_FIREEVERYTHIRD = 0x00000010, // during 'hold time' fire every third frame
WEAPON_RANDOMRESTART = 0x00000020, // restart for automatic is 'randomized' by RND 3
WEAPON_AMMOPERSHOT = 0x00000040, // uses ammo for each shot (for automatic)
WEAPON_BOMB_TRIGGER = 0x00000080, // weapon is the 'bomb' trigger
WEAPON_NOVISIBLE = 0x00000100, // weapon use does not cause user to become 'visible'
WEAPON_THROWIT = 0x00000200, // weapon 'throws' the 'shoots' item...
WEAPON_CHECKATRELOAD = 0x00000400, // check weapon availability at 'reload' time
WEAPON_STANDSTILL = 0x00000800, // player stops jumping before actual fire (like tripbomb in duke)
WEAPON_SPAWNTYPE2 = 0x00001000, // spawn like shotgun shells
WEAPON_SPAWNTYPE3 = 0x00002000, // spawn like chaingun shells
};
enum gamemode_t {
MODE_MENU = 0x00000001,
MODE_DEMO = 0x00000002,
@ -223,6 +241,51 @@ typedef struct {
} playerdata_t;
#pragma pack(pop)
// KEEPINSYNC lunatic/con_lang.lua
typedef struct
{
// NOTE: the member names must be identical to aplWeapon* suffixes.
int32_t WorksLike; // What the original works like
int32_t Clip; // number of items in magazine
int32_t Reload; // delay to reload (include fire)
int32_t FireDelay; // delay to fire
int32_t TotalTime; // The total time the weapon is cycling before next fire.
int32_t HoldDelay; // delay after release fire button to fire (0 for none)
int32_t Flags; // Flags for weapon
int32_t Shoots; // what the weapon shoots
int32_t SpawnTime; // the frame at which to spawn an item
int32_t Spawn; // the item to spawn
int32_t ShotsPerBurst; // number of shots per 'burst' (one ammo per 'burst')
int32_t InitialSound; // Sound made when weapon starts firing. zero for no sound
int32_t FireSound; // Sound made when firing (each time for automatic)
int32_t Sound2Time; // Alternate sound time
int32_t Sound2Sound; // Alternate sound sound ID
int32_t FlashColor; // Muzzle flash color
} weapondata_t;
#ifdef LUNATIC
# define PWEAPON(Player, Weapon, Wmember) (g_playerWeapon[Player][Weapon].Wmember)
extern weapondata_t g_playerWeapon[MAXPLAYERS][MAX_WEAPONS];
#else
# define PWEAPON(Player, Weapon, Wmember) (aplWeapon ## Wmember [Weapon][Player])
extern intptr_t *aplWeaponClip[MAX_WEAPONS]; // number of items in clip
extern intptr_t *aplWeaponReload[MAX_WEAPONS]; // delay to reload (include fire)
extern intptr_t *aplWeaponFireDelay[MAX_WEAPONS]; // delay to fire
extern intptr_t *aplWeaponHoldDelay[MAX_WEAPONS]; // delay after release fire button to fire (0 for none)
extern intptr_t *aplWeaponTotalTime[MAX_WEAPONS]; // The total time the weapon is cycling before next fire.
extern intptr_t *aplWeaponFlags[MAX_WEAPONS]; // Flags for weapon
extern intptr_t *aplWeaponShoots[MAX_WEAPONS]; // what the weapon shoots
extern intptr_t *aplWeaponSpawnTime[MAX_WEAPONS]; // the frame at which to spawn an item
extern intptr_t *aplWeaponSpawn[MAX_WEAPONS]; // the item to spawn
extern intptr_t *aplWeaponShotsPerBurst[MAX_WEAPONS]; // number of shots per 'burst' (one ammo per 'burst'
extern intptr_t *aplWeaponWorksLike[MAX_WEAPONS]; // What original the weapon works like
extern intptr_t *aplWeaponInitialSound[MAX_WEAPONS]; // Sound made when initialy firing. zero for no sound
extern intptr_t *aplWeaponFireSound[MAX_WEAPONS]; // Sound made when firing (each time for automatic)
extern intptr_t *aplWeaponSound2Time[MAX_WEAPONS]; // Alternate sound time
extern intptr_t *aplWeaponSound2Sound[MAX_WEAPONS]; // Alternate sound sound ID
extern intptr_t *aplWeaponFlashColor[MAX_WEAPONS]; // Color for polymer muzzle flash
#endif
// KEEPINSYNC lunatic/_defs_game.lua
typedef struct {
int32_t cur, count; // "cur" is the only member that is *used*

View file

@ -1935,6 +1935,11 @@ end_vol4a:
pPlayer->gm = 0;
M_ClearMenus();
Gv_ResetVars();
Gv_InitWeaponPointers();
Gv_RefreshPointers();
Gv_ResetSystemDefaults();
//AddLog("Newgame");
for (bssize_t i=0; i<(MAXVOLUMES*MAXLEVELS); i++)

View file

@ -348,6 +348,19 @@ typedef struct dataspec_
intptr_t cnt;
} dataspec_t;
typedef struct dataspec_gv_
{
uint32_t flags;
void * ptr;
uint32_t size;
intptr_t cnt;
} dataspec_gv_t;
#define SV_DEFAULTCOMPRTHRES 8
static uint8_t savegame_diffcompress; // 0:none, 1:Ken's LZW in cache1d.c
static uint8_t savegame_comprthres;
#define DS_DYNAMIC 1 // dereference .ptr one more time
#define DS_STRING 2
#define DS_CMP 4
@ -970,6 +983,7 @@ static const dataspec_t svgm_anmisc[] =
{ DS_END, 0, 0, 0 }
};
static dataspec_gv_t *svgm_vars=NULL;
static uint8_t *dosaveplayer2(FileWriter *fil, uint8_t *mem);
static int32_t doloadplayer2(FileReader &fil, uint8_t **memptr);
static void postloadplayer(int32_t savegamep);
@ -983,6 +997,46 @@ static uint8_t *svdiff;
#include "gamedef.h"
#define SV_SKIPMASK (/*GAMEVAR_SYSTEM|*/ GAMEVAR_READONLY | GAMEVAR_PTR_MASK | /*GAMEVAR_NORESET |*/ GAMEVAR_SPECIAL)
static char svgm_vars_string [] = "blK:vars";
// setup gamevar data spec for snapshotting and diffing... gamevars must be loaded when called
static void sv_makevarspec()
{
int vcnt = 0;
for (int i = 0; i < g_gameVarCount; i++)
vcnt += (aGameVars[i].flags & SV_SKIPMASK) ? 0 : 1;
svgm_vars = (dataspec_gv_t *)Xrealloc(svgm_vars, (vcnt + 2) * sizeof(dataspec_gv_t));
svgm_vars[0].flags = DS_STRING;
svgm_vars[0].ptr = svgm_vars_string;
svgm_vars[0].cnt = 1;
vcnt = 1;
for (int i = 0; i < g_gameVarCount; i++)
{
if (aGameVars[i].flags & SV_SKIPMASK)
continue;
unsigned const per = aGameVars[i].flags & GAMEVAR_USER_MASK;
svgm_vars[vcnt].flags = 0;
svgm_vars[vcnt].ptr = (per == 0) ? &aGameVars[i].global : aGameVars[i].pValues;
svgm_vars[vcnt].size = sizeof(intptr_t);
svgm_vars[vcnt].cnt = (per == 0) ? 1 : (per == GAMEVAR_PERPLAYER ? MAXPLAYERS : MAXSPRITES);
++vcnt;
}
svgm_vars[vcnt].flags = DS_END;
svgm_vars[vcnt].ptr = NULL;
svgm_vars[vcnt].size = 0;
svgm_vars[vcnt].cnt = 0;
}
void sv_freemem()
{
DO_FREE_AND_NULL(svsnapshot);
@ -1007,7 +1061,9 @@ int32_t sv_saveandmakesnapshot(FileWriter &fil, int8_t spot, bool isAutoSave)
savehead_t h;
// calculate total snapshot size
svsnapsiz = calcsz(svgm_udnetw) + calcsz(svgm_secwsp) + calcsz(svgm_script) + calcsz(svgm_anmisc);
sv_makevarspec();
svsnapsiz = calcsz((const dataspec_t *)svgm_vars);
svsnapsiz += calcsz(svgm_udnetw) + calcsz(svgm_secwsp) + calcsz(svgm_script) + calcsz(svgm_anmisc);
// create header
@ -1225,6 +1281,7 @@ uint32_t sv_writediff(FileWriter *fil)
cmpspecdata(svgm_secwsp, &p, &d);
cmpspecdata(svgm_script, &p, &d);
cmpspecdata(svgm_anmisc, &p, &d);
cmpspecdata((const dataspec_t *)svgm_vars, &p, &d);
if (p != svsnapshot+svsnapsiz)
OSD_Printf("sv_writediff: dump+siz=%p, p=%p!\n", svsnapshot+svsnapsiz, p);
@ -1256,6 +1313,7 @@ int32_t sv_readdiff(FileReader &fil)
if (applydiff(svgm_secwsp, &p, &d)) return -4;
if (applydiff(svgm_script, &p, &d)) return -5;
if (applydiff(svgm_anmisc, &p, &d)) return -6;
if (applydiff((const dataspec_t *)svgm_vars, &p, &d)) return -7;
int i = 0;
@ -1369,6 +1427,9 @@ static uint8_t *dosaveplayer2(FileWriter *fil, uint8_t *mem)
PRINTSIZE("script");
mem=writespecdata(svgm_anmisc, fil, mem); // animates, quotes & misc.
PRINTSIZE("animisc");
Gv_WriteSave(fil); // gamevars
mem=writespecdata((const dataspec_t *)svgm_vars, 0, mem);
PRINTSIZE("vars");
return mem;
}
@ -1389,6 +1450,23 @@ static int32_t doloadplayer2(FileReader &fil, uint8_t **memptr)
if (readspecdata(svgm_anmisc, &fil, &mem)) return -6;
PRINTSIZE("animisc");
int i;
if ((i = Gv_ReadSave(fil))) return i;
if (mem)
{
int32_t i;
sv_makevarspec();
for (i=1; svgm_vars[i].flags!=DS_END; i++)
{
Bmemcpy(mem, svgm_vars[i].ptr, svgm_vars[i].size*svgm_vars[i].cnt); // careful! works because there are no DS_DYNAMIC's!
mem += svgm_vars[i].size*svgm_vars[i].cnt;
}
}
PRINTSIZE("vars");
if (memptr)
*memptr = mem;
return 0;
@ -1405,6 +1483,7 @@ int32_t sv_updatestate(int32_t frominit)
if (readspecdata(svgm_secwsp, nullptr, &p)) return -4;
if (readspecdata(svgm_script, nullptr, &p)) return -5;
if (readspecdata(svgm_anmisc, nullptr, &p)) return -6;
if (readspecdata((const dataspec_t *)svgm_vars, -1, &p)) return -8;
if (p != pbeg+svsnapsiz)
{
@ -1529,6 +1608,12 @@ static void postloadplayer(int32_t savegamep)
// if (savegamep) ?
G_ResetTimers(0);
#ifdef USE_STRUCT_TRACKERS
Bmemset(sectorchanged, 0, sizeof(sectorchanged));
Bmemset(spritechanged, 0, sizeof(spritechanged));
Bmemset(wallchanged, 0, sizeof(wallchanged));
#endif
#ifdef POLYMER
//9
if (videoGetRenderMode() == REND_POLYMER)

View file

@ -88,6 +88,7 @@ typedef struct {
#ifndef NEW_MAP_FORMAT
wallext_t wallext[MAXWALLS];
#endif
intptr_t *vars[MAXGAMEVARS];
#ifdef YAX_ENABLE
int32_t numyaxbunches;
# if !defined NEW_MAP_FORMAT