1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010 EDuke32 developers and contributors
4 
5 This file is part of EDuke32.
6 
7 EDuke32 is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License version 2
9 as published by the Free Software Foundation.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 
15 See the GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 //-------------------------------------------------------------------------
22 
23 // This object is shared by the editors of *all* Build games!
24 
25 #include "m32script.h"
26 #include "m32def.h"
27 #include "osd.h"
28 #include "keys.h"
29 #ifdef POLYMER
30 #include "polymer.h"
31 #endif
32 
33 #define _m32vars_c_
34 #include "m32structures.cpp"
35 
Gv_Clear(void)36 static void Gv_Clear(void)
37 {
38     // only call this function ONCE...
39     int32_t i=(MAXGAMEVARS-1);
40 
41     //AddLog("Gv_Clear");
42 
43     for (; i>=0; i--)
44     {
45         DO_FREE_AND_NULL(aGameVars[i].szLabel);
46 
47         if (aGameVars[i].dwFlags & GAMEVAR_USER_MASK)
48             DO_FREE_AND_NULL(aGameVars[i].val.plValues);
49 
50         aGameVars[i].val.lValue = 0;
51         aGameVars[i].dwFlags |= GAMEVAR_RESET;
52 
53         if (i >= MAXGAMEARRAYS)
54             continue;
55 
56         gamearray_t *const gar = &aGameArrays[i];
57 
58         DO_FREE_AND_NULL(gar->szLabel);
59 
60         if (gar->dwFlags & GAMEARRAY_NORMAL)
61             DO_FREE_AND_NULL(gar->vals);
62 
63         gar->dwFlags |= GAMEARRAY_RESET;
64     }
65 
66     g_gameVarCount = g_gameArrayCount = 0;
67 
68     hash_init(&h_gamevars);
69     hash_init(&h_arrays);
70 }
71 
72 #define ASSERT_IMPLIES(x, y) Bassert(!(x) || (y))
73 
Gv_NewArray(const char * pszLabel,void * arrayptr,intptr_t asize,uint32_t dwFlags)74 void Gv_NewArray(const char *pszLabel, void *arrayptr, intptr_t asize, uint32_t dwFlags)
75 {
76     ASSERT_IMPLIES(dwFlags&GAMEARRAY_VARSIZE, dwFlags&GAMEARRAY_READONLY);
77     ASSERT_IMPLIES(dwFlags&GAMEARRAY_STRIDE2, dwFlags&GAMEARRAY_READONLY);
78     ASSERT_IMPLIES(dwFlags&GAMEARRAY_TYPE_MASK,
79                    g_gameArrayCount==0 || (dwFlags&(GAMEARRAY_READONLY|GAMEARRAY_WARN)));
80 
81     if (g_gameArrayCount >= MAXGAMEARRAYS)
82     {
83         C_CUSTOMERROR("too many arrays! (max: %d)", MAXGAMEARRAYS);
84         return;
85     }
86 
87     if (Bstrlen(pszLabel) > (MAXARRAYLABEL-1))
88     {
89         C_CUSTOMERROR("array name `%s' exceeds limit of %d characters.", pszLabel, MAXARRAYLABEL);
90         return;
91     }
92 
93     const int32_t i = hash_find(&h_arrays, pszLabel);
94 
95     if (i>=0 && !(aGameArrays[i].dwFlags & GAMEARRAY_RESET))
96     {
97         // found it it's a duplicate in error
98 
99         if (aGameArrays[i].dwFlags&GAMEARRAY_TYPE_MASK)
100             C_CUSTOMWARNING("ignored redefining system array `%s'.", pszLabel);
101 
102 //        C_ReportError(WARNING_DUPLICATEDEFINITION);
103         return;
104     }
105 
106     if (!(dwFlags&GAMEARRAY_VARSIZE) && !(dwFlags&GAMEARRAY_TYPE_MASK) && (asize<=0 || asize>65536))
107     {
108         // the dummy array with index 0 sets the size to 0 so that accidental accesses as array
109         // will complain.
110         C_CUSTOMERROR("invalid array size %d. Must be between 1 and 65536", (int)asize);
111         return;
112     }
113 
114     gamearray_t *const gar = &aGameArrays[g_gameArrayCount];
115 
116     if (gar->szLabel == NULL)
117         gar->szLabel = (char *)Xcalloc(MAXARRAYLABEL, sizeof(char));
118     if (gar->szLabel != pszLabel)
119         Bstrcpy(gar->szLabel, pszLabel);
120 
121     if (!(dwFlags & GAMEARRAY_TYPE_MASK))
122         gar->vals = (int32_t *)Xcalloc(asize, sizeof(int32_t));
123     else
124         gar->vals = arrayptr;
125 
126     gar->size = asize;
127     gar->dwFlags = dwFlags & ~GAMEARRAY_RESET;
128 
129     hash_add(&h_arrays, gar->szLabel, g_gameArrayCount, 1);
130     g_gameArrayCount++;
131 }
132 
Gv_NewVar(const char * pszLabel,intptr_t lValue,uint32_t dwFlags)133 void Gv_NewVar(const char *pszLabel, intptr_t lValue, uint32_t dwFlags)
134 {
135     int32_t i, j;
136 
137     //Bsprintf(g_szBuf,"Gv_NewVar(%s, %d, %X)",pszLabel, lValue, dwFlags);
138     //AddLog(g_szBuf);
139 
140     if (g_gameVarCount >= MAXGAMEVARS)
141     {
142         C_CUSTOMERROR("too many gamevars! (max: %d)", MAXGAMEVARS);
143         return;
144     }
145 
146     if (Bstrlen(pszLabel) > (MAXVARLABEL-1))
147     {
148         C_CUSTOMERROR("variable name `%s' exceeds limit of %d characters.", pszLabel, MAXVARLABEL);
149         return;
150     }
151 
152     i = hash_find(&h_gamevars,pszLabel);
153 
154     if (i >= 0 && !(aGameVars[i].dwFlags & GAMEVAR_RESET))
155     {
156         // found it...
157         if (aGameVars[i].dwFlags & GAMEVAR_PTR_MASK)
158         {
159             C_ReportError(-1);
160             initprintf("%s:%d: warning: cannot redefine internal gamevar `%s'.\n",g_szScriptFileName,g_lineNumber,label+(g_numLabels<<6));
161             return;
162         }
163         else if (!(aGameVars[i].dwFlags & GAMEVAR_SYSTEM))
164         {
165             // it's a duplicate in error
166 //            g_numCompilerWarnings++;
167 //            C_ReportError(WARNING_DUPLICATEDEFINITION);
168             return;
169         }
170     }
171 
172     if (i == -1)
173         i = g_gameVarCount;
174 
175     // Set values
176     if ((aGameVars[i].dwFlags & GAMEVAR_SYSTEM) == 0)
177     {
178         if (aGameVars[i].szLabel == NULL)
179             aGameVars[i].szLabel = (char *)Xcalloc(MAXVARLABEL, sizeof(uint8_t));
180         if (aGameVars[i].szLabel != pszLabel)
181             Bstrcpy(aGameVars[i].szLabel,pszLabel);
182         aGameVars[i].dwFlags = dwFlags;
183 
184         if (aGameVars[i].dwFlags & GAMEVAR_USER_MASK)
185         {
186             // only free if not system
187             DO_FREE_AND_NULL(aGameVars[i].val.plValues);
188         }
189     }
190 
191     // if existing is system, they only get to change default value....
192     aGameVars[i].lDefault = lValue;
193     aGameVars[i].dwFlags &= ~GAMEVAR_RESET;
194 
195     if (i == g_gameVarCount)
196     {
197         // we're adding a new one.
198         hash_add(&h_gamevars, aGameVars[i].szLabel, g_gameVarCount++, 0);
199     }
200 
201     if (aGameVars[i].dwFlags & GAMEVAR_PERBLOCK)
202     {
203         if (!aGameVars[i].val.plValues)
204             aGameVars[i].val.plValues = (int32_t *)Xcalloc(1+MAXEVENTS+g_stateCount, sizeof(int32_t));
205         for (j=0; j<1+MAXEVENTS+g_stateCount; j++)
206             aGameVars[i].val.plValues[j] = lValue;
207     }
208     else aGameVars[i].val.lValue = lValue;
209 }
210 
Gv_GetVarN(int32_t id)211 int32_t __fastcall Gv_GetVarN(int32_t id)  // 'N' for "no side-effects"... vars and locals only!
212 {
213     if (id == M32_THISACTOR_VAR_ID)
214         return vm.spriteNum;
215 
216     switch (id&M32_VARTYPE_MASK)
217     {
218     case M32_FLAG_VAR:
219         id &= (MAXGAMEVARS-1);
220 
221         switch (aGameVars[id].dwFlags & (GAMEVAR_USER_MASK|GAMEVAR_PTR_MASK))
222         {
223         case 0:
224             return aGameVars[id].val.lValue;
225         case GAMEVAR_PERBLOCK:
226             return aGameVars[id].val.plValues[vm.g_st];
227         case GAMEVAR_FLOATPTR:
228         case GAMEVAR_INTPTR:
229             return *((int32_t *)aGameVars[id].val.lValue);
230         case GAMEVAR_SHORTPTR:
231             return *((int16_t *)aGameVars[id].val.lValue);
232         case GAMEVAR_CHARPTR:
233             return *((uint8_t *)aGameVars[id].val.lValue);
234         default:
235             M32_ERROR("Gv_GetVarN(): WTF??");
236             return -1;
237         }
238 
239     case M32_FLAG_LOCAL:
240     {
241         int32_t index = id&(MAXGAMEVARS-1);
242         // no bounds checking since it's done at script compilation time
243         return ((int32_t *)aGameArrays[M32_LOCAL_ARRAY_ID].vals)[index];
244     }
245 
246     default:
247         M32_ERROR("Gv_GetVarN(): invalid var code %0x08x", id);
248         return -1;
249     }
250 }
251 
Gv_GetVarX(int32_t id)252 int32_t __fastcall Gv_GetVarX(int32_t id)
253 {
254     int32_t negateResult = !!(id&M32_FLAG_NEGATE);
255 
256     if (id == M32_THISACTOR_VAR_ID)
257         return vm.spriteNum;
258 
259     id &= ~M32_FLAG_NEGATE;
260 
261     if ((id & M32_BITS_MASK) == M32_FLAG_CONSTANT)
262     {
263         switch (id&3)
264         {
265         case 0:
266             return ((int16_t)(id>>16));
267         case 1:
268             return constants[(id>>16)&0xffff];
269         case 2:
270             return (labelval[(id>>16)&0xffff] ^ -negateResult) + negateResult;
271         default:
272             M32_ERROR("Gv_GetVarX() (constant): WTF??");
273             return -1;
274         }
275     }
276 
277 
278     switch (id&M32_VARTYPE_MASK)
279     {
280     case M32_FLAG_ARRAY:
281     {
282         int32_t index;
283 
284         index = (int32_t)((id>>16)&0xffff);
285         if (!(id&M32_FLAG_CONSTANTINDEX))
286             index = Gv_GetVarN(index);
287 
288         id &= (MAXGAMEARRAYS-1);
289 
290         const int32_t siz = Gv_GetArraySize(id);
291         const gamearray_t *const gar = &aGameArrays[id];
292 
293         if (index < 0 || index >= siz)
294         {
295             M32_ERROR("Gv_GetVarX(): invalid array index (%s[%d])", gar->szLabel, index);
296             return -1;
297         }
298 
299         if (gar->dwFlags & GAMEARRAY_STRIDE2)
300             index <<= 1;
301 
302         switch (gar->dwFlags & GAMEARRAY_TYPE_MASK)
303         {
304         case 0:
305         case GAMEARRAY_INT32:
306             return (((int32_t *)gar->vals)[index] ^ -negateResult) + negateResult;
307         case GAMEARRAY_INT16:
308             return (((int16_t *)gar->vals)[index] ^ -negateResult) + negateResult;
309         case GAMEARRAY_UINT8:
310             return (((uint8_t *)gar->vals)[index] ^ -negateResult) + negateResult;
311         default:
312             M32_ERROR("Gv_GetVarX() (array): WTF??");
313             return -1;
314         }
315     }
316     case M32_FLAG_STRUCT:
317     {
318         int32_t index, memberid;
319 
320         index = (id>>16)&0x7fff;
321         if (!(id&M32_FLAG_CONSTANTINDEX))
322             index = Gv_GetVarN(index);
323 
324         memberid = (id>>2)&63;
325 
326         switch (id&3)
327         {
328         case M32_SPRITE_VAR_ID:
329             return (VM_AccessSprite(0, index, memberid, 0) ^ -negateResult) + negateResult;
330         case M32_SECTOR_VAR_ID:
331             return (VM_AccessSector(0, index, memberid, 0) ^ -negateResult) + negateResult;
332         case M32_WALL_VAR_ID:
333             return (VM_AccessWall(0, index, memberid, 0) ^ -negateResult) + negateResult;
334         case M32_TSPRITE_VAR_ID:
335             return (VM_AccessTsprite(0, index, memberid, 0) ^ -negateResult) + negateResult;
336         default:
337             M32_ERROR("Gv_GetVarX(): WTF??");
338             return -1;
339         }
340     }
341     case M32_FLAG_VAR:
342     {
343         id &= (MAXGAMEVARS-1);
344 
345         switch (aGameVars[id].dwFlags & (GAMEVAR_USER_MASK|GAMEVAR_PTR_MASK))
346         {
347         case 0:
348             return (aGameVars[id].val.lValue ^ -negateResult) + negateResult;
349         case GAMEVAR_PERBLOCK:
350             return (aGameVars[id].val.plValues[vm.g_st] ^ -negateResult) + negateResult;
351         case GAMEVAR_FLOATPTR:
352         {
353             float fval = *(float *)aGameVars[id].val.lValue;
354             if (negateResult)
355                 fval *= -1;
356             return *(int32_t *)&fval;
357         }
358         case GAMEVAR_INTPTR:
359             return (*((int32_t *)aGameVars[id].val.lValue) ^ -negateResult) + negateResult;
360         case GAMEVAR_SHORTPTR:
361             return (*((int16_t *)aGameVars[id].val.lValue) ^ -negateResult) + negateResult;
362         case GAMEVAR_CHARPTR:
363             return (*((uint8_t *)aGameVars[id].val.lValue) ^ -negateResult) + negateResult;
364         default:
365             M32_ERROR("Gv_GetVarX(): WTF??");
366             return -1;
367         }
368     }
369     case M32_FLAG_LOCAL:
370     {
371         int32_t index = id&(MAXGAMEVARS-1);
372         // no bounds checking since it's done at script compilation time
373         return (((int32_t *)aGameArrays[M32_LOCAL_ARRAY_ID].vals)[index] ^ -negateResult) + negateResult;
374     }
375     }  // switch (id&M32_VARTYPE_MASK)
376 
377     return 0;  // never reached
378 }
379 
380 
Gv_SetVarX(int32_t id,int32_t lValue)381 void __fastcall Gv_SetVarX(int32_t id, int32_t lValue)
382 {
383     switch (id&M32_VARTYPE_MASK)
384     {
385     case M32_FLAG_ARRAY:
386     {
387         int32_t index;
388 
389         index = (id>>16)&0xffff;
390         if (!(id&M32_FLAG_CONSTANTINDEX))
391             index = Gv_GetVarN(index);
392 
393         id &= (MAXGAMEARRAYS-1);
394 
395         const int32_t siz = Gv_GetArraySize(id);
396         gamearray_t *const gar = &aGameArrays[id];
397 
398         if (index < 0 || index >= siz)
399         {
400             M32_ERROR("Gv_SetVarX(): invalid array index %s[%d], size=%d", gar->szLabel, index, siz);
401             return;
402         }
403 
404         // NOTE: GAMEARRAY_READONLY arrays can be modified in expert mode.
405         Bassert((gar->dwFlags & GAMEARRAY_STRIDE2) == 0);
406 
407         switch (gar->dwFlags & GAMEARRAY_TYPE_MASK)
408         {
409         case 0:
410         case GAMEARRAY_INT32:
411             ((int32_t *)gar->vals)[index] = lValue;
412             return;
413         case GAMEARRAY_INT16:
414             ((int16_t *)gar->vals)[index] = (int16_t)lValue;
415             return;
416         case GAMEARRAY_UINT8:
417             ((uint8_t *)gar->vals)[index] = (uint8_t)lValue;
418             return;
419         default:
420             M32_ERROR("Gv_SetVarX() (array): WTF??");
421             return;
422         }
423         return;
424     }
425     case M32_FLAG_STRUCT:
426     {
427         int32_t index, memberid;
428 
429         index = (id>>16)&0x7fff;
430         if (!(id&M32_FLAG_CONSTANTINDEX))
431             index = Gv_GetVarN(index);
432 
433         memberid = (id>>2)&63;
434 
435         switch (id&3)
436         {
437         case M32_SPRITE_VAR_ID:
438             VM_AccessSprite(1, index, memberid, lValue);
439             return;
440         case M32_SECTOR_VAR_ID:
441             VM_AccessSector(1, index, memberid, lValue);
442             return;
443         case M32_WALL_VAR_ID:
444             VM_AccessWall(1, index, memberid, lValue);
445             return;
446         case M32_TSPRITE_VAR_ID:
447             VM_AccessTsprite(1, index, memberid, lValue);
448             return;
449         default:
450             M32_ERROR("Gv_SetVarX(): WTF??");
451             return;
452         }
453     }
454     case M32_FLAG_VAR:
455     {
456         id &= (MAXGAMEVARS-1);
457 
458         switch (aGameVars[id].dwFlags & (GAMEVAR_USER_MASK|GAMEVAR_PTR_MASK))
459         {
460         case 0:
461             aGameVars[id].val.lValue=lValue;
462             return;
463         case GAMEVAR_PERBLOCK:
464             aGameVars[id].val.plValues[vm.g_st] = lValue;
465             return;
466         case GAMEVAR_FLOATPTR:
467         {
468             int32_t ival = lValue;
469             float fval = *(float *)&ival;
470             if (fval!=fval || fval<-3.4e38 || fval > 3.4e38)
471             {
472                 M32_ERROR("Gv_SetVarX(): tried to set float var to NaN or infinity");
473                 return;
474             }
475         }
476         fallthrough__;
477         case GAMEVAR_INTPTR:
478             *((int32_t *)aGameVars[id].val.lValue)=(int32_t)lValue;
479             return;
480         case GAMEVAR_SHORTPTR:
481             *((int16_t *)aGameVars[id].val.lValue)=(int16_t)lValue;
482             return;
483         case GAMEVAR_CHARPTR:
484             *((uint8_t *)aGameVars[id].val.lValue)=(uint8_t)lValue;
485             return;
486         default:
487             M32_ERROR("Gv_SetVarX(): WTF??");
488             return;
489         }
490     }
491     case M32_FLAG_LOCAL:
492     {
493         int32_t index = id&(MAXGAMEVARS-1);
494         ((int32_t *)aGameArrays[M32_LOCAL_ARRAY_ID].vals)[index] = lValue;
495         return;
496     }
497     }
498 }
499 
500 static uint8_t alphakeys[] =
501 {
502     KEYSC_SPACE,
503 
504     KEYSC_A, KEYSC_B, KEYSC_C, KEYSC_D, KEYSC_E, KEYSC_F, KEYSC_G, KEYSC_H,
505     KEYSC_I, KEYSC_J, KEYSC_K, KEYSC_L, KEYSC_M, KEYSC_N, KEYSC_O, KEYSC_P,
506     KEYSC_Q, KEYSC_R, KEYSC_S, KEYSC_T, KEYSC_U, KEYSC_V, KEYSC_W, KEYSC_X,
507     KEYSC_Y, KEYSC_Z,
508 };
509 
510 static uint8_t numberkeys[] =
511 {
512     KEYSC_0, KEYSC_1, KEYSC_2, KEYSC_3, KEYSC_4, KEYSC_5, KEYSC_6, KEYSC_7,
513     KEYSC_8, KEYSC_9,
514 };
515 
Gv_AddSystemVars(void)516 static void Gv_AddSystemVars(void)
517 {
518     // only call ONCE
519     int32_t hlcnt_id, hlscnt_id;
520 
521     // special vars for struct access
522     // MUST be at top and in this order!!!
523     Gv_NewVar("sprite", -1, GAMEVAR_READONLY | GAMEVAR_SYSTEM | GAMEVAR_SPECIAL);
524     Gv_NewVar("sector", -1, GAMEVAR_READONLY | GAMEVAR_SYSTEM | GAMEVAR_SPECIAL);
525     Gv_NewVar("wall", -1, GAMEVAR_READONLY | GAMEVAR_SYSTEM | GAMEVAR_SPECIAL);
526     Gv_NewVar("tsprite", -1, GAMEVAR_READONLY | GAMEVAR_SYSTEM | GAMEVAR_SPECIAL);
527     Gv_NewVar("light", -1, GAMEVAR_READONLY | GAMEVAR_SYSTEM | GAMEVAR_SPECIAL);
528 
529     // these too have to be in here and in order!
530     // keep in sync with m32script.h: IDs of special vars
531 
532     Gv_NewVar("I", 0, GAMEVAR_READONLY | GAMEVAR_SYSTEM);  // THISACTOR
533     Gv_NewVar("RETURN", (intptr_t)&g_iReturnVar, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
534     Gv_NewVar("LOTAG", 0, GAMEVAR_SYSTEM);
535     Gv_NewVar("HITAG", 0, GAMEVAR_SYSTEM);
536     Gv_NewVar("TEXTURE", 0, GAMEVAR_SYSTEM);
537     Gv_NewVar("DOSCRSHOT", (intptr_t)&g_doScreenShot, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
538 
539     Gv_NewVar("xdim",(intptr_t)&xdim, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
540     Gv_NewVar("ydim",(intptr_t)&ydim, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
541     Gv_NewVar("windowx1",(intptr_t)&windowxy1.x, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
542     Gv_NewVar("windowx2",(intptr_t)&windowxy2.x, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
543     Gv_NewVar("windowy1",(intptr_t)&windowxy1.y, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
544     Gv_NewVar("windowy2",(intptr_t)&windowxy2.y, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
545     Gv_NewVar("totalclock",(intptr_t)&totalclock, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
546 
547     Gv_NewVar("viewingrange",(intptr_t)&viewingrange, GAMEVAR_SYSTEM | GAMEVAR_INTPTR | GAMEVAR_READONLY);
548     Gv_NewVar("yxaspect",(intptr_t)&yxaspect, GAMEVAR_SYSTEM | GAMEVAR_INTPTR | GAMEVAR_READONLY);
549 
550 ///    Gv_NewVar("framerate",(intptr_t)&g_frameRate, GAMEVAR_SYSTEM | GAMEVAR_INTPTR | GAMEVAR_READONLY);
551 ///    Gv_NewVar("display_mirror",(intptr_t)&display_mirror, GAMEVAR_SYSTEM | GAMEVAR_CHARPTR);
552 
553     Gv_NewVar("randomseed",(intptr_t)&randomseed, GAMEVAR_SYSTEM | GAMEVAR_INTPTR);
554 
555     Gv_NewVar("numwalls",(intptr_t)&numwalls, GAMEVAR_SYSTEM | GAMEVAR_SHORTPTR | GAMEVAR_READONLY);
556     Gv_NewVar("numsectors",(intptr_t)&numsectors, GAMEVAR_SYSTEM | GAMEVAR_SHORTPTR | GAMEVAR_READONLY);
557     Gv_NewVar("numsprites",(intptr_t)&Numsprites, GAMEVAR_SYSTEM | GAMEVAR_INTPTR | GAMEVAR_READONLY);
558     {
559         static int32_t numtiles;
560         Gv_NewVar("numtiles",(intptr_t)&numtiles, GAMEVAR_SYSTEM | GAMEVAR_INTPTR | GAMEVAR_READONLY);
561     }
562 #ifdef YAX_ENABLE
563     Gv_NewVar("numbunches",(intptr_t)&numyaxbunches, GAMEVAR_SYSTEM | GAMEVAR_INTPTR | GAMEVAR_READONLY);
564 #endif
565 
566 #ifdef USE_OPENGL
567     Gv_NewVar("rendmode",(intptr_t)&rendmode, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
568 #endif
569 
570     // current position
571     Gv_NewVar("posx",(intptr_t)&pos.x, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
572     Gv_NewVar("posy",(intptr_t)&pos.y, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
573     Gv_NewVar("posz",(intptr_t)&pos.z, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
574     Gv_NewVar("ang",(intptr_t)&ang, GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
575     Gv_NewVar("horiz",(intptr_t)&horiz, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
576     Gv_NewVar("cursectnum",(intptr_t)&cursectnum, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
577     Gv_NewVar("hardcoded_movement",(intptr_t)&g_doHardcodedMovement, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
578 
579     Gv_NewVar("searchx",(intptr_t)&searchx, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
580     Gv_NewVar("searchy",(intptr_t)&searchy, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
581     Gv_NewVar("searchstat",(intptr_t)&searchstat, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
582     Gv_NewVar("searchwall",(intptr_t)&searchwall, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
583     Gv_NewVar("searchsector",(intptr_t)&searchsector, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
584     Gv_NewVar("searchbottomwall",(intptr_t)&searchbottomwall, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
585 
586     Gv_NewVar("pointhighlight",(intptr_t)&pointhighlight, GAMEVAR_SHORTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
587     Gv_NewVar("linehighlight",(intptr_t)&linehighlight, GAMEVAR_SHORTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
588 
589     hlcnt_id = g_gameVarCount;
590     Gv_NewVar("highlightcnt",(intptr_t)&highlightcnt, GAMEVAR_SHORTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
591     hlscnt_id = g_gameVarCount;
592     Gv_NewVar("highlightsectorcnt",(intptr_t)&highlightsectorcnt, GAMEVAR_SHORTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
593 
594     // clipboard contents
595     Gv_NewVar("temppicnum",(intptr_t)&temppicnum, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
596     Gv_NewVar("tempcstat",(intptr_t)&tempcstat, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
597     Gv_NewVar("templotag",(intptr_t)&templotag, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
598     Gv_NewVar("temphitag",(intptr_t)&temphitag, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
599     Gv_NewVar("tempextra",(intptr_t)&tempextra, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
600     Gv_NewVar("tempshade",(intptr_t)&tempshade, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
601     Gv_NewVar("temppal",(intptr_t)&temppal, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
602     Gv_NewVar("tempvis",(intptr_t)&tempvis, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
603     Gv_NewVar("tempxrepeat",(intptr_t)&tempxrepeat, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
604     Gv_NewVar("tempyrepeat",(intptr_t)&tempyrepeat, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
605 
606     // starting position
607     Gv_NewVar("startposx",(intptr_t)&startpos.x, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
608     Gv_NewVar("startposy",(intptr_t)&startpos.y, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
609     Gv_NewVar("startposz",(intptr_t)&startpos.z, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
610     Gv_NewVar("startang",(intptr_t)&startang, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
611     Gv_NewVar("startsectnum",(intptr_t)&startsectnum, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
612 
613     Gv_NewVar("mousxplc",(intptr_t)&mousxplc, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
614     Gv_NewVar("mousyplc",(intptr_t)&mousyplc, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
615 
616     Gv_NewVar("zoom",(intptr_t)&zoom, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
617     Gv_NewVar("drawlinepat",(intptr_t)&m32_drawlinepat, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
618     Gv_NewVar("halfxdim16", (intptr_t)&halfxdim16, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
619     Gv_NewVar("midydim16", (intptr_t)&midydim16, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
620     Gv_NewVar("ydim16",(intptr_t)&ydim16, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
621     Gv_NewVar("m32_sideview",(intptr_t)&m32_sideview, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
622 
623     Gv_NewVar("SV1",(intptr_t)&m32_sortvar1, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
624     Gv_NewVar("SV2",(intptr_t)&m32_sortvar2, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
625     Gv_NewVar("spritesortcnt",(intptr_t)&spritesortcnt, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
626 
627 #ifdef POLYMER
628     Gv_NewVar("pr_overrideparallax",(intptr_t)&pr_overrideparallax, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
629     Gv_NewVar("pr_parallaxscale",(intptr_t)&pr_parallaxscale, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
630     Gv_NewVar("pr_parallaxbias",(intptr_t)&pr_parallaxbias, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
631     Gv_NewVar("pr_overridespecular",(intptr_t)&pr_overridespecular, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
632     Gv_NewVar("pr_specularpower",(intptr_t)&pr_specularpower, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
633     Gv_NewVar("pr_specularfactor",(intptr_t)&pr_specularfactor, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
634 #else
635     {
636         // dummy Polymer variables for non-Polymer builds
637         static int32_t pr_overrideparallax = 0;
638         static float pr_parallaxscale = 0.1f;
639         static float pr_parallaxbias = 0.0f;
640         static int32_t pr_overridespecular = 0;
641         static float pr_specularpower = 15.0f;
642         static float pr_specularfactor = 1.0f;
643 
644         Gv_NewVar("pr_overrideparallax",(intptr_t)&pr_overrideparallax, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
645         Gv_NewVar("pr_parallaxscale",(intptr_t)&pr_parallaxscale, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
646         Gv_NewVar("pr_parallaxbias",(intptr_t)&pr_parallaxbias, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
647         Gv_NewVar("pr_overridespecular",(intptr_t)&pr_overridespecular, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
648         Gv_NewVar("pr_specularpower",(intptr_t)&pr_specularpower, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
649         Gv_NewVar("pr_specularfactor",(intptr_t)&pr_specularfactor, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
650     }
651 #endif
652 
653     g_systemVarCount = g_gameVarCount;
654 
655     // must be first!
656     Gv_NewArray(".LOCALS_BASE", NULL, 0, GAMEARRAY_INT32);
657 
658     Gv_NewArray("highlight", (void *)highlight, hlcnt_id,
659                 GAMEARRAY_READONLY|GAMEARRAY_INT16|GAMEARRAY_VARSIZE);
660     Gv_NewArray("highlightsector", (void *)highlightsector, hlscnt_id,
661                 GAMEARRAY_READONLY|GAMEARRAY_INT16|GAMEARRAY_VARSIZE);
662 
663     Gv_NewArray("hsect", (void *)headspritesect, MAXSECTORS+1, GAMEARRAY_READONLY|GAMEARRAY_INT16);
664     Gv_NewArray("psect", (void *)prevspritesect, MAXSPRITES, GAMEARRAY_READONLY|GAMEARRAY_INT16);
665     Gv_NewArray("nsect", (void *)nextspritesect, MAXSPRITES, GAMEARRAY_READONLY|GAMEARRAY_INT16);
666     Gv_NewArray("hstat", (void *)headspritestat, MAXSTATUS+1, GAMEARRAY_READONLY|GAMEARRAY_INT16);
667     Gv_NewArray("pstat", (void *)prevspritestat, MAXSPRITES, GAMEARRAY_READONLY|GAMEARRAY_INT16);
668     Gv_NewArray("nstat", (void *)nextspritestat, MAXSPRITES, GAMEARRAY_READONLY|GAMEARRAY_INT16);
669 #ifdef YAX_ENABLE
670     Gv_NewArray("headsectbunchc", (void *)headsectbunch[0], YAX_MAXBUNCHES, GAMEARRAY_READONLY|GAMEARRAY_INT16);
671     Gv_NewArray("nextsectbunchc", (void *)nextsectbunch[0], MAXSECTORS, GAMEARRAY_READONLY|GAMEARRAY_INT16);
672     Gv_NewArray("headsectbunchf", (void *)headsectbunch[1], YAX_MAXBUNCHES, GAMEARRAY_READONLY|GAMEARRAY_INT16);
673     Gv_NewArray("nextsectbunchf", (void *)nextsectbunch[1], MAXSECTORS, GAMEARRAY_READONLY|GAMEARRAY_INT16);
674 #endif
675     Gv_NewArray("editorcolors", (void *)editorcolors, 256, GAMEARRAY_READONLY|GAMEARRAY_UINT8);
676     Gv_NewArray("tilesizx", (void *)&tilesiz[0].x, MAXTILES, GAMEARRAY_STRIDE2|GAMEARRAY_READONLY|GAMEARRAY_INT16);
677     Gv_NewArray("tilesizy", (void *)&tilesiz[0].y, MAXTILES, GAMEARRAY_STRIDE2|GAMEARRAY_READONLY|GAMEARRAY_INT16);
678 //    Gv_NewArray("picsiz", (void *)picsiz, MAXTILES, GAMEARRAY_READONLY|GAMEARRAY_OFCHAR);
679     Gv_NewArray("picanm", (void *)picanm, MAXTILES, GAMEARRAY_READONLY|GAMEARRAY_INT32);
680 
681     Gv_NewArray("show2dsector", (void *)show2dsector, (MAXSECTORS+7)>>3, GAMEARRAY_READONLY|GAMEARRAY_UINT8);
682     Gv_NewArray("show2dwall", (void *)show2dwall, (MAXWALLS+7)>>3, GAMEARRAY_READONLY|GAMEARRAY_UINT8);
683     Gv_NewArray("show2dsprite", (void *)show2dsprite, (MAXSPRITES+7)>>3, GAMEARRAY_READONLY|GAMEARRAY_UINT8);
684 
685     Gv_NewArray("keystatus", (void *)keystatus, 256, GAMEARRAY_WARN|GAMEARRAY_UINT8);
686     Gv_NewArray("alphakeys", (void *)alphakeys, sizeof(alphakeys), GAMEARRAY_READONLY|GAMEARRAY_UINT8);
687     Gv_NewArray("numberkeys", (void *)numberkeys, sizeof(numberkeys), GAMEARRAY_READONLY|GAMEARRAY_UINT8);
688 
689     g_systemArrayCount = g_gameArrayCount;
690 }
691 
Gv_Init(void)692 void Gv_Init(void)
693 {
694     // only call ONCE
695 
696     Gv_Clear();
697     Gv_AddSystemVars();
698 }
699