From 6f2fa332dde9c3ab3ce373116dbc96f5d539332f Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Thu, 13 Dec 2012 02:33:53 +0000 Subject: [PATCH] Port system gamearray access from M32Script to CON. Expose tilesizx and tilesizy. Also, fix deficient logic in Gv_Free and Gv_Clear (both M32 and CON) so that gamevar and gamearray erasure results are (closer to) correct, and so that the game does not crash when system arrays are accessed from CON because they all have been nulled. git-svn-id: https://svn.eduke32.com/eduke32@3274 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/build/include/m32script.h | 2 +- polymer/eduke32/source/gamedef.c | 32 +++++++-- polymer/eduke32/source/gamedef.h | 1 + polymer/eduke32/source/gameexec.c | 63 +++++++++++++++--- polymer/eduke32/source/gamevars.c | 79 ++++++++++++++++++----- polymer/eduke32/source/gamevars.h | 20 ++++-- polymer/eduke32/source/m32vars.c | 7 +- 7 files changed, 162 insertions(+), 42 deletions(-) diff --git a/polymer/eduke32/build/include/m32script.h b/polymer/eduke32/build/include/m32script.h index 73afd2116..4226ed7a3 100644 --- a/polymer/eduke32/build/include/m32script.h +++ b/polymer/eduke32/build/include/m32script.h @@ -133,7 +133,7 @@ enum GamearrayFlags_t { GAMEARRAY_READONLY = 0x00001000, GAMEARRAY_WARN = 0x00002000, - GAMEARRAY_NORMAL = 0, + GAMEARRAY_NORMAL = 0x00004000, GAMEARRAY_OFCHAR = 0x00000001, GAMEARRAY_OFSHORT = 0x00000002, GAMEARRAY_OFINT = 0x00000004, diff --git a/polymer/eduke32/source/gamedef.c b/polymer/eduke32/source/gamedef.c index 4cc08c813..6bdcdc6ca 100644 --- a/polymer/eduke32/source/gamedef.c +++ b/polymer/eduke32/source/gamedef.c @@ -2337,7 +2337,7 @@ static int32_t C_ParseCommand(int32_t loop) } C_GetNextValue(LABEL_DEFINE); - Gv_NewArray(label+(g_numLabels<<6),*(g_scriptPtr-1)); + Gv_NewArray(label+(g_numLabels<<6),NULL,*(g_scriptPtr-1), GAMEARRAY_NORMAL); g_scriptPtr -= 2; // no need to save in script... continue; @@ -3863,6 +3863,13 @@ static int32_t C_ParseCommand(int32_t loop) { bitptr[(g_scriptPtr-script)>>3] &= ~(BITPTR_POINTER<<((g_scriptPtr-script)&7)); *g_scriptPtr++=i; + + if (aGameArrays[i].dwFlags & GAMEARRAY_READONLY) + { + C_ReportError(ERROR_ARRAYREADONLY); + g_numCompilerErrors++; + return 1; + } } else { @@ -3894,16 +3901,24 @@ static int32_t C_ParseCommand(int32_t loop) case CON_RESIZEARRAY: C_GetNextLabelName(); i=GetADefID(label+(g_numLabels<<6)); - if (i < 0) + if (i >= 0) + { + bitptr[(g_scriptPtr-script)>>3] &= ~(BITPTR_POINTER<<((g_scriptPtr-script)&7)); + *g_scriptPtr++ = i; + if (tw==CON_RESIZEARRAY && (aGameArrays[i].dwFlags & GAMEARRAY_TYPE_MASK)) + { + C_ReportError(-1); + initprintf("can't resize system array `%s'.", label+(g_numLabels<<6)); + return 1; + } + } + else { g_numCompilerErrors++; C_ReportError(ERROR_NOTAGAMEARRAY); return 1; } - bitptr[(g_scriptPtr-script)>>3] &= ~(BITPTR_POINTER<<((g_scriptPtr-script)&7)); - *g_scriptPtr++=i; - C_SkipComments(); C_GetNextVarType(tw==CON_GETARRAYSIZE ? GAMEVAR_READONLY : 0); continue; @@ -6031,10 +6046,10 @@ void C_Compile(const char *filenam) initprintf("Script compiled in %dms, %ld*%db, version %s\n", getticks() - startcompiletime, (unsigned long)(g_scriptPtr-script), (int32_t)sizeof(intptr_t), (g_scriptVersion == 14?"1.4+":"1.3D")); - initprintf("%d/%d labels, %d/%d variables\n", g_numLabels, + initprintf("%d/%d labels, %d/%d variables, %d/%d arrays\n", g_numLabels, (int32_t)min((MAXSECTORS * sizeof(sectortype)/sizeof(int32_t)), MAXSPRITES * sizeof(spritetype)/(1<<6)), - g_gameVarCount, MAXGAMEVARS); + g_gameVarCount, MAXGAMEVARS, g_gameArrayCount, MAXGAMEARRAYS); for (i=MAXQUOTES-1; i>=0; i--) if (ScriptQuotes[i]) @@ -6220,6 +6235,9 @@ void C_ReportError(int32_t iError) case ERROR_VARREADONLY: initprintf("%s:%d: error: variable `%s' is read-only.\n",g_szScriptFileName,g_lineNumber,label+(g_numLabels<<6)); break; + case ERROR_ARRAYREADONLY: + initprintf("%s:%d: error: array `%s' is read-only.\n",g_szScriptFileName,g_lineNumber,label+(g_numLabels<<6)); + break; case ERROR_VARTYPEMISMATCH: initprintf("%s:%d: error: variable `%s' is of the wrong type.\n",g_szScriptFileName,g_lineNumber,label+(g_numLabels<<6)); break; diff --git a/polymer/eduke32/source/gamedef.h b/polymer/eduke32/source/gamedef.h index 0f415c787..db39c0c97 100644 --- a/polymer/eduke32/source/gamedef.h +++ b/polymer/eduke32/source/gamedef.h @@ -155,6 +155,7 @@ enum ScriptError_t ERROR_SYMBOLNOTRECOGNIZED, ERROR_SYNTAXERROR, ERROR_VARREADONLY, + ERROR_ARRAYREADONLY, ERROR_VARTYPEMISMATCH, WARNING_BADGAMEVAR, WARNING_DUPLICATECASE, diff --git a/polymer/eduke32/source/gameexec.c b/polymer/eduke32/source/gameexec.c index 7b208e8be..01eadf4a2 100644 --- a/polymer/eduke32/source/gameexec.c +++ b/polymer/eduke32/source/gameexec.c @@ -4196,6 +4196,11 @@ nullquote: j,vm.g_i,TrackerCast(sprite[vm.g_i].picnum),vm.g_p); continue; } + if (aGameArrays[j].dwFlags & GAMEARRAY_READONLY) + { + OSD_Printf("Tried to set on read-only array `%s'", aGameArrays[j].szLabel); + continue; + } aGameArrays[j].plValues[index]=value; continue; } @@ -4265,7 +4270,8 @@ nullquote: insptr++; { int32_t j=*insptr++; - Gv_SetVarX(*insptr++,aGameArrays[j].size); + Gv_SetVarX(*insptr++, (aGameArrays[j].dwFlags&GAMEARRAY_VARSIZE) ? + Gv_GetVarX(aGameArrays[j].size) : aGameArrays[j].size); } continue; @@ -4287,16 +4293,53 @@ nullquote: case CON_COPY: insptr++; { - int32_t j=*insptr++; - int32_t index = Gv_GetVarX(*insptr++); - int32_t j1=*insptr++; - int32_t index1 = Gv_GetVarX(*insptr++); - int32_t value = Gv_GetVarX(*insptr++); + int32_t si=*insptr++, ssiz = 0; + int32_t sidx = Gv_GetVarX(*insptr++); //, vm.g_i, vm.g_p); + int32_t di=*insptr++, dsiz = 0; + int32_t didx = Gv_GetVarX(*insptr++); + int32_t numelts = Gv_GetVarX(*insptr++); - if (index > aGameArrays[j].size || index1 > aGameArrays[j1].size) continue; - if ((index+value)>aGameArrays[j].size) value=aGameArrays[j].size-index; - if ((index1+value)>aGameArrays[j1].size) value=aGameArrays[j1].size-index1; - Bmemcpy(aGameArrays[j1].plValues+index1, aGameArrays[j].plValues+index, value * sizeof(intptr_t)); + if (si<0 || si>=g_gameArrayCount) + { + CON_ERRPRINTF("Invalid array %d!", si); + dsiz = 1; + } + if (di<0 || di>=g_gameArrayCount) + { + CON_ERRPRINTF("Invalid array %d!", di); + dsiz = 1; + } + if (aGameArrays[di].dwFlags & GAMEARRAY_READONLY) + { + CON_ERRPRINTF("Array %d is read-only!", di); + dsiz = 1; + } + if (dsiz) continue; // dirty replacement for VMFLAG_ERROR + + ssiz = (aGameArrays[si].dwFlags&GAMEARRAY_VARSIZE) ? + Gv_GetVarX(aGameArrays[si].size) : aGameArrays[si].size; + dsiz = (aGameArrays[di].dwFlags&GAMEARRAY_VARSIZE) ? + Gv_GetVarX(aGameArrays[si].size) : aGameArrays[di].size; + + if (sidx > ssiz || didx > dsiz) continue; + if ((sidx+numelts) > ssiz) numelts = ssiz-sidx; + if ((didx+numelts) > dsiz) numelts = dsiz-didx; + + switch (aGameArrays[si].dwFlags & GAMEARRAY_TYPE_MASK) + { + case 0: + case GAMEARRAY_OFINT: + Bmemcpy((int32_t *)aGameArrays[di].plValues + didx, (int32_t *)aGameArrays[si].plValues + sidx, numelts * sizeof(int32_t)); + break; + case GAMEARRAY_OFSHORT: + for (; numelts>0; numelts--) + ((int32_t *)aGameArrays[di].plValues)[didx++] = ((int16_t *)aGameArrays[si].plValues)[sidx++]; + break; + case GAMEARRAY_OFCHAR: + for (; numelts>0; numelts--) + ((int32_t *)aGameArrays[di].plValues)[didx++] = ((uint8_t *)aGameArrays[si].plValues)[sidx++]; + break; + } continue; } diff --git a/polymer/eduke32/source/gamevars.c b/polymer/eduke32/source/gamevars.c index 934e0e090..01763e856 100644 --- a/polymer/eduke32/source/gamevars.c +++ b/polymer/eduke32/source/gamevars.c @@ -52,11 +52,13 @@ static void Gv_Free(void) /* called from Gv_ReadSave() and Gv_ResetVars() */ if (i >= MAXGAMEARRAYS) continue; - if (aGameArrays[i].plValues) + if ((aGameArrays[i].dwFlags & GAMEARRAY_NORMAL) && aGameArrays[i].plValues) + { Bfree(aGameArrays[i].plValues); + aGameArrays[i].plValues=NULL; + } - aGameArrays[i].plValues=NULL; - aGameArrays[i].bReset=1; + aGameArrays[i].dwFlags |= GAMEARRAY_RESET; } g_gameVarCount=g_gameArrayCount=0; hash_init(&h_gamevars); @@ -76,7 +78,6 @@ static void Gv_Clear(void) if (aGameVars[i].szLabel) Bfree(aGameVars[i].szLabel); aGameVars[i].szLabel=NULL; - aGameVars[i].dwFlags=0; if ((aGameVars[i].dwFlags & GAMEVAR_USER_MASK) && aGameVars[i].val.plValues) { @@ -91,10 +92,12 @@ static void Gv_Clear(void) Bfree(aGameArrays[i].szLabel); aGameArrays[i].szLabel=NULL; - if (aGameArrays[i].plValues) + if ((aGameArrays[i].dwFlags & GAMEARRAY_NORMAL) && aGameArrays[i].plValues) + { Bfree(aGameArrays[i].plValues); - aGameArrays[i].plValues=NULL; - aGameArrays[i].bReset=1; + aGameArrays[i].plValues=NULL; + } + aGameArrays[i].dwFlags |= GAMEARRAY_RESET; } g_gameVarCount=g_gameArrayCount=0; hash_init(&h_gamevars); @@ -379,12 +382,12 @@ void Gv_ResetVars(void) /* this is called during a new game and nowhere else */ for (i=0; i=0 && !aGameArrays[i].bReset) + if (i >=0 && !(aGameArrays[i].dwFlags & GAMEARRAY_RESET)) { // found it it's a duplicate in error + g_numCompilerWarnings++; - C_ReportError(WARNING_DUPLICATEDEFINITION); + + if (aGameArrays[i].dwFlags&GAMEARRAY_TYPE_MASK) + { + C_ReportError(-1); + initprintf("ignored redefining system array `%s'.", pszLabel); + } + else + C_ReportError(WARNING_DUPLICATEDEFINITION); + return 0; } @@ -418,9 +430,15 @@ int32_t Gv_NewArray(const char *pszLabel, int32_t asize) aGameArrays[i].szLabel=(char *)Bcalloc(MAXVARLABEL,sizeof(uint8_t)); if (aGameArrays[i].szLabel != pszLabel) Bstrcpy(aGameArrays[i].szLabel,pszLabel); - aGameArrays[i].plValues=(intptr_t *)Bcalloc(asize,GAR_ELTSZ); + + if (!(dwFlags & GAMEARRAY_TYPE_MASK)) + aGameArrays[i].plValues=(intptr_t *)Bcalloc(asize,GAR_ELTSZ); + else + aGameArrays[i].plValues=(intptr_t *)arrayptr; + aGameArrays[i].size=asize; - aGameArrays[i].bReset=0; + aGameArrays[i].dwFlags = dwFlags & ~GAMEARRAY_RESET; + g_gameArrayCount++; hash_add(&h_arrays, aGameArrays[i].szLabel, i, 1); return 1; @@ -753,16 +771,33 @@ int32_t __fastcall Gv_GetVarX(register int32_t id) if (id&(MAXGAMEVARS<<2)) // array { register int32_t index=Gv_GetVarX(*insptr++); + int32_t siz; id &= (MAXGAMEVARS-1);// ~((MAXGAMEVARS<<2)|(MAXGAMEVARS<<1)); - if ((unsigned)index >= (unsigned)aGameArrays[id].size) + if (aGameArrays[id].dwFlags & GAMEARRAY_VARSIZE) + siz = Gv_GetVarX(aGameArrays[id].size); + else + siz = aGameArrays[id].size; + + if (index < 0 || index >= siz) { negateResult = index; goto badindex; } - return ((aGameArrays[id].plValues[index] ^ -negateResult) + negateResult); + switch (aGameArrays[id].dwFlags & GAMEARRAY_TYPE_MASK) + { + case 0: + case GAMEARRAY_OFINT: + return (((int32_t *)aGameArrays[id].plValues)[index] ^ -negateResult) + negateResult; + case GAMEARRAY_OFSHORT: + return (((int16_t *)aGameArrays[id].plValues)[index] ^ -negateResult) + negateResult; + case GAMEARRAY_OFCHAR: + return (((uint8_t *)aGameArrays[id].plValues)[index] ^ -negateResult) + negateResult; + default: + goto arraywtf; + } } if (id&(MAXGAMEVARS<<3)) // struct shortcut vars @@ -878,8 +913,12 @@ badwall: CON_ERRPRINTF("Gv_GetVarX(): invalid wall ID %d\n", id); return -1; +arraywtf: + CON_ERRPRINTF("Gv_GetVarX() (array): WTF?\n"); + return -1; + wtf: - CON_ERRPRINTF("Gv_GetVar(): WTF?\n"); + CON_ERRPRINTF("Gv_GetVarX(): WTF?\n"); return -1; } } @@ -1624,6 +1663,12 @@ static void Gv_AddSystemVars(void) #else Gv_NewVar("rendmode", 0, GAMEVAR_READONLY | GAMEVAR_SYSTEM); #endif + + // must be first! + Gv_NewArray(".LOCALS_BASE", NULL, 0, GAMEARRAY_OFINT); + + Gv_NewArray("tilesizx", (void *)tilesizx, MAXTILES, GAMEARRAY_READONLY|GAMEARRAY_OFSHORT); + Gv_NewArray("tilesizy", (void *)tilesizy, MAXTILES, GAMEARRAY_READONLY|GAMEARRAY_OFSHORT); } void Gv_Init(void) diff --git a/polymer/eduke32/source/gamevars.h b/polymer/eduke32/source/gamevars.h index f945ff8b0..0aded2c36 100644 --- a/polymer/eduke32/source/gamevars.h +++ b/polymer/eduke32/source/gamevars.h @@ -52,8 +52,20 @@ enum GamevarFlags_t { #define MAXARRAYLABEL MAXVARLABEL enum GamearrayFlags_t { - GAMEARRAY_NORMAL = 0, - GAMEARRAY_NORESET = 0x00000001, + + GAMEARRAY_READONLY = 0x00001000, + GAMEARRAY_WARN = 0x00002000, + + GAMEARRAY_NORMAL = 0x00004000, + GAMEARRAY_OFCHAR = 0x00000001, + GAMEARRAY_OFSHORT = 0x00000002, + GAMEARRAY_OFINT = 0x00000004, + GAMEARRAY_TYPE_MASK = GAMEARRAY_OFCHAR|GAMEARRAY_OFSHORT|GAMEARRAY_OFINT, + + GAMEARRAY_VARSIZE = 0x00000020, + + GAMEARRAY_RESET = 0x00000008, +/// GAMEARRAY_NORESET = 0x00000001, }; #pragma pack(push,1) @@ -71,7 +83,7 @@ typedef struct { char *szLabel; intptr_t *plValues; // array of values intptr_t size; - intptr_t bReset; + intptr_t dwFlags; } gamearray_t; #pragma pack(pop) @@ -85,7 +97,7 @@ extern int32_t g_gameArrayCount; int32_t __fastcall Gv_GetVar(register int32_t id,register int32_t iActor,register int32_t iPlayer); int32_t __fastcall Gv_GetVarX(register int32_t id); int32_t Gv_GetVarByLabel(const char *szGameLabel,int32_t lDefault,int32_t iActor,int32_t iPlayer); -int32_t Gv_NewArray(const char *pszLabel,int32_t asize); +int32_t Gv_NewArray(const char *pszLabel,void *arrayptr,intptr_t asize,uint32_t dwFlags); int32_t Gv_NewVar(const char *pszLabel,intptr_t lValue,uint32_t dwFlags); int32_t Gv_ReadSave(int32_t fil,int32_t newbehav); void __fastcall A_ResetVars(register int32_t iActor); diff --git a/polymer/eduke32/source/m32vars.c b/polymer/eduke32/source/m32vars.c index e5e57b16f..c62466239 100644 --- a/polymer/eduke32/source/m32vars.c +++ b/polymer/eduke32/source/m32vars.c @@ -44,7 +44,6 @@ static void Gv_Clear(void) Bfree(aGameVars[i].szLabel); aGameVars[i].szLabel = NULL; - aGameVars[i].dwFlags = 0; if ((aGameVars[i].dwFlags & GAMEVAR_USER_MASK) && aGameVars[i].val.plValues) { @@ -63,10 +62,12 @@ static void Gv_Clear(void) aGameArrays[i].szLabel = NULL; - if (aGameArrays[i].vals) + if ((aGameArrays[i].dwFlags & GAMEARRAY_NORMAL) && aGameArrays[i].vals) + { Bfree(aGameArrays[i].vals); + aGameArrays[i].vals=NULL; + } - aGameArrays[i].vals = NULL; aGameArrays[i].dwFlags |= GAMEARRAY_RESET; }