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
This commit is contained in:
hendricks266 2012-12-13 02:33:53 +00:00
parent a2f585fcfb
commit 6f2fa332dd
7 changed files with 162 additions and 42 deletions

View file

@ -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,

View file

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

View file

@ -155,6 +155,7 @@ enum ScriptError_t
ERROR_SYMBOLNOTRECOGNIZED,
ERROR_SYNTAXERROR,
ERROR_VARREADONLY,
ERROR_ARRAYREADONLY,
ERROR_VARTYPEMISMATCH,
WARNING_BADGAMEVAR,
WARNING_DUPLICATECASE,

View file

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

View file

@ -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<MAXGAMEARRAYS; i++)
{
if (aGameArrays[i].szLabel != NULL && aGameArrays[i].bReset)
Gv_NewArray(aGameArrays[i].szLabel,aGameArrays[i].size);
if (aGameArrays[i].szLabel != NULL && (aGameArrays[i].dwFlags & GAMEARRAY_RESET))
Gv_NewArray(aGameArrays[i].szLabel,aGameArrays[i].plValues,aGameArrays[i].size,aGameArrays[i].dwFlags);
}
}
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 i;
@ -404,11 +407,20 @@ int32_t Gv_NewArray(const char *pszLabel, int32_t asize)
return 0;
}
i = hash_find(&h_arrays,pszLabel);
if (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)

View file

@ -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);

View file

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