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; }