/ source / blood / src / m32vars.cpp
m32vars.cpp
  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  
 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  
 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  
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  
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  
252  int32_t __fastcall Gv_GetVar(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              union { int32_t ival; float fval; };
354  
355              fval = *(float *)aGameVars[id].val.plValues;
356              if (negateResult)
357                  fval *= -1;
358              return ival;
359          }
360          case GAMEVAR_INTPTR:
361              return (*((int32_t *)aGameVars[id].val.lValue) ^ -negateResult) + negateResult;
362          case GAMEVAR_SHORTPTR:
363              return (*((int16_t *)aGameVars[id].val.lValue) ^ -negateResult) + negateResult;
364          case GAMEVAR_CHARPTR:
365              return (*((uint8_t *)aGameVars[id].val.lValue) ^ -negateResult) + negateResult;
366          default:
367              M32_ERROR("Gv_GetVarX(): WTF??");
368              return -1;
369          }
370      }
371      case M32_FLAG_LOCAL:
372      {
373          int32_t index = id&(MAXGAMEVARS-1);
374          // no bounds checking since it's done at script compilation time
375          return (((int32_t *)aGameArrays[M32_LOCAL_ARRAY_ID].vals)[index] ^ -negateResult) + negateResult;
376      }
377      }  // switch (id&M32_VARTYPE_MASK)
378  
379      return 0;  // never reached
380  }
381  
382  
383  void __fastcall Gv_SetVar(int32_t id, int32_t lValue)
384  {
385      switch (id&M32_VARTYPE_MASK)
386      {
387      case M32_FLAG_ARRAY:
388      {
389          int32_t index;
390  
391          index = (id>>16)&0xffff;
392          if (!(id&M32_FLAG_CONSTANTINDEX))
393              index = Gv_GetVarN(index);
394  
395          id &= (MAXGAMEARRAYS-1);
396  
397          const int32_t siz = Gv_GetArraySize(id);
398          gamearray_t *const gar = &aGameArrays[id];
399  
400          if (index < 0 || index >= siz)
401          {
402              M32_ERROR("Gv_SetVarX(): invalid array index %s[%d], size=%d", gar->szLabel, index, siz);
403              return;
404          }
405  
406          // NOTE: GAMEARRAY_READONLY arrays can be modified in expert mode.
407          Bassert((gar->dwFlags & GAMEARRAY_STRIDE2) == 0);
408  
409          switch (gar->dwFlags & GAMEARRAY_TYPE_MASK)
410          {
411          case 0:
412          case GAMEARRAY_INT32:
413              ((int32_t *)gar->vals)[index] = lValue;
414              return;
415          case GAMEARRAY_INT16:
416              ((int16_t *)gar->vals)[index] = (int16_t)lValue;
417              return;
418          case GAMEARRAY_UINT8:
419              ((uint8_t *)gar->vals)[index] = (uint8_t)lValue;
420              return;
421          default:
422              M32_ERROR("Gv_SetVarX() (array): WTF??");
423              return;
424          }
425          return;
426      }
427      case M32_FLAG_STRUCT:
428      {
429          int32_t index, memberid;
430  
431          index = (id>>16)&0x7fff;
432          if (!(id&M32_FLAG_CONSTANTINDEX))
433              index = Gv_GetVarN(index);
434  
435          memberid = (id>>2)&63;
436  
437          switch (id&3)
438          {
439          case M32_SPRITE_VAR_ID:
440              VM_AccessSprite(1, index, memberid, lValue);
441              return;
442          case M32_SECTOR_VAR_ID:
443              VM_AccessSector(1, index, memberid, lValue);
444              return;
445          case M32_WALL_VAR_ID:
446              VM_AccessWall(1, index, memberid, lValue);
447              return;
448          case M32_TSPRITE_VAR_ID:
449              VM_AccessTsprite(1, index, memberid, lValue);
450              return;
451          default:
452              M32_ERROR("Gv_SetVarX(): WTF??");
453              return;
454          }
455      }
456      case M32_FLAG_VAR:
457      {
458          id &= (MAXGAMEVARS-1);
459  
460          switch (aGameVars[id].dwFlags & (GAMEVAR_USER_MASK|GAMEVAR_PTR_MASK))
461          {
462          case 0:
463              aGameVars[id].val.lValue=lValue;
464              return;
465          case GAMEVAR_PERBLOCK:
466              aGameVars[id].val.plValues[vm.g_st] = lValue;
467              return;
468          case GAMEVAR_FLOATPTR:
469          {
470              union { int32_t ival; float fval; };
471              ival = lValue;
472  
473              if (fval!=fval || fval<-3.4e38 || fval > 3.4e38)
474              {
475                  M32_ERROR("Gv_SetVarX(): tried to set float var to NaN or infinity");
476                  return;
477              }
478          }
479          fallthrough__;
480          case GAMEVAR_INTPTR:
481              *((int32_t *)aGameVars[id].val.lValue)=(int32_t)lValue;
482              return;
483          case GAMEVAR_SHORTPTR:
484              *((int16_t *)aGameVars[id].val.lValue)=(int16_t)lValue;
485              return;
486          case GAMEVAR_CHARPTR:
487              *((uint8_t *)aGameVars[id].val.lValue)=(uint8_t)lValue;
488              return;
489          default:
490              M32_ERROR("Gv_SetVarX(): WTF??");
491              return;
492          }
493      }
494      case M32_FLAG_LOCAL:
495      {
496          int32_t index = id&(MAXGAMEVARS-1);
497          ((int32_t *)aGameArrays[M32_LOCAL_ARRAY_ID].vals)[index] = lValue;
498          return;
499      }
500      }
501  }
502  
503  static uint8_t alphakeys[] =
504  {
505      KEYSC_SPACE,
506  
507      KEYSC_A, KEYSC_B, KEYSC_C, KEYSC_D, KEYSC_E, KEYSC_F, KEYSC_G, KEYSC_H,
508      KEYSC_I, KEYSC_J, KEYSC_K, KEYSC_L, KEYSC_M, KEYSC_N, KEYSC_O, KEYSC_P,
509      KEYSC_Q, KEYSC_R, KEYSC_S, KEYSC_T, KEYSC_U, KEYSC_V, KEYSC_W, KEYSC_X,
510      KEYSC_Y, KEYSC_Z,
511  };
512  
513  static uint8_t numberkeys[] =
514  {
515      KEYSC_0, KEYSC_1, KEYSC_2, KEYSC_3, KEYSC_4, KEYSC_5, KEYSC_6, KEYSC_7,
516      KEYSC_8, KEYSC_9,
517  };
518  
519  static void Gv_AddSystemVars(void)
520  {
521      // only call ONCE
522      int32_t hlcnt_id, hlscnt_id;
523  
524      // special vars for struct access
525      // MUST be at top and in this order!!!
526      Gv_NewVar("sprite", -1, GAMEVAR_READONLY | GAMEVAR_SYSTEM | GAMEVAR_SPECIAL);
527      Gv_NewVar("sector", -1, GAMEVAR_READONLY | GAMEVAR_SYSTEM | GAMEVAR_SPECIAL);
528      Gv_NewVar("wall", -1, GAMEVAR_READONLY | GAMEVAR_SYSTEM | GAMEVAR_SPECIAL);
529      Gv_NewVar("tsprite", -1, GAMEVAR_READONLY | GAMEVAR_SYSTEM | GAMEVAR_SPECIAL);
530      Gv_NewVar("light", -1, GAMEVAR_READONLY | GAMEVAR_SYSTEM | GAMEVAR_SPECIAL);
531  
532      // these too have to be in here and in order!
533      // keep in sync with m32script.h: IDs of special vars
534  
535      Gv_NewVar("I", 0, GAMEVAR_READONLY | GAMEVAR_SYSTEM);  // THISACTOR
536      Gv_NewVar("RETURN", (intptr_t)&g_iReturnVar, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
537      Gv_NewVar("LOTAG", 0, GAMEVAR_SYSTEM);
538      Gv_NewVar("HITAG", 0, GAMEVAR_SYSTEM);
539      Gv_NewVar("TEXTURE", 0, GAMEVAR_SYSTEM);
540      Gv_NewVar("DOSCRSHOT", (intptr_t)&g_doScreenShot, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
541  
542      Gv_NewVar("xdim",(intptr_t)&xdim, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
543      Gv_NewVar("ydim",(intptr_t)&ydim, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
544      Gv_NewVar("windowx1",(intptr_t)&windowxy1.x, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
545      Gv_NewVar("windowx2",(intptr_t)&windowxy2.x, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
546      Gv_NewVar("windowy1",(intptr_t)&windowxy1.y, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
547      Gv_NewVar("windowy2",(intptr_t)&windowxy2.y, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
548      Gv_NewVar("totalclock",(intptr_t)&totalclock, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
549  
550      Gv_NewVar("viewingrange",(intptr_t)&viewingrange, GAMEVAR_SYSTEM | GAMEVAR_INTPTR | GAMEVAR_READONLY);
551      Gv_NewVar("yxaspect",(intptr_t)&yxaspect, GAMEVAR_SYSTEM | GAMEVAR_INTPTR | GAMEVAR_READONLY);
552  
553  ///    Gv_NewVar("framerate",(intptr_t)&g_frameRate, GAMEVAR_SYSTEM | GAMEVAR_INTPTR | GAMEVAR_READONLY);
554  ///    Gv_NewVar("display_mirror",(intptr_t)&display_mirror, GAMEVAR_SYSTEM | GAMEVAR_CHARPTR);
555  
556      Gv_NewVar("randomseed",(intptr_t)&randomseed, GAMEVAR_SYSTEM | GAMEVAR_INTPTR);
557  
558      Gv_NewVar("numwalls",(intptr_t)&numwalls, GAMEVAR_SYSTEM | GAMEVAR_SHORTPTR | GAMEVAR_READONLY);
559      Gv_NewVar("numsectors",(intptr_t)&numsectors, GAMEVAR_SYSTEM | GAMEVAR_SHORTPTR | GAMEVAR_READONLY);
560      Gv_NewVar("numsprites",(intptr_t)&Numsprites, GAMEVAR_SYSTEM | GAMEVAR_INTPTR | GAMEVAR_READONLY);
561      {
562          static int32_t numtiles;
563          Gv_NewVar("numtiles",(intptr_t)&numtiles, GAMEVAR_SYSTEM | GAMEVAR_INTPTR | GAMEVAR_READONLY);
564      }
565  #ifdef YAX_ENABLE
566      Gv_NewVar("numbunches",(intptr_t)&numyaxbunches, GAMEVAR_SYSTEM | GAMEVAR_INTPTR | GAMEVAR_READONLY);
567  #endif
568  
569  #ifdef USE_OPENGL
570      Gv_NewVar("rendmode",(intptr_t)&rendmode, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
571  #endif
572  
573      // current position
574      Gv_NewVar("posx",(intptr_t)&pos.x, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
575      Gv_NewVar("posy",(intptr_t)&pos.y, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
576      Gv_NewVar("posz",(intptr_t)&pos.z, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
577      Gv_NewVar("ang",(intptr_t)&ang, GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
578      Gv_NewVar("horiz",(intptr_t)&horiz, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
579      Gv_NewVar("cursectnum",(intptr_t)&cursectnum, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
580      Gv_NewVar("hardcoded_movement",(intptr_t)&g_doHardcodedMovement, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
581  
582      Gv_NewVar("searchx",(intptr_t)&searchx, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
583      Gv_NewVar("searchy",(intptr_t)&searchy, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
584      Gv_NewVar("searchstat",(intptr_t)&searchstat, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
585      Gv_NewVar("searchwall",(intptr_t)&searchwall, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
586      Gv_NewVar("searchsector",(intptr_t)&searchsector, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
587      Gv_NewVar("searchbottomwall",(intptr_t)&searchbottomwall, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
588  
589      Gv_NewVar("pointhighlight",(intptr_t)&pointhighlight, GAMEVAR_SHORTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
590      Gv_NewVar("linehighlight",(intptr_t)&linehighlight, GAMEVAR_SHORTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
591  
592      hlcnt_id = g_gameVarCount;
593      Gv_NewVar("highlightcnt",(intptr_t)&highlightcnt, GAMEVAR_SHORTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
594      hlscnt_id = g_gameVarCount;
595      Gv_NewVar("highlightsectorcnt",(intptr_t)&highlightsectorcnt, GAMEVAR_SHORTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
596  
597      // clipboard contents
598      Gv_NewVar("temppicnum",(intptr_t)&temppicnum, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
599      Gv_NewVar("tempcstat",(intptr_t)&tempcstat, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
600      Gv_NewVar("templotag",(intptr_t)&templotag, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
601      Gv_NewVar("temphitag",(intptr_t)&temphitag, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
602      Gv_NewVar("tempextra",(intptr_t)&tempextra, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
603      Gv_NewVar("tempshade",(intptr_t)&tempshade, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
604      Gv_NewVar("temppal",(intptr_t)&temppal, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
605      Gv_NewVar("tempvis",(intptr_t)&tempvis, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
606      Gv_NewVar("tempxrepeat",(intptr_t)&tempxrepeat, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
607      Gv_NewVar("tempyrepeat",(intptr_t)&tempyrepeat, GAMEVAR_INTPTR|GAMEVAR_SYSTEM|GAMEVAR_READONLY);
608  
609      // starting position
610      Gv_NewVar("startposx",(intptr_t)&startpos.x, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
611      Gv_NewVar("startposy",(intptr_t)&startpos.y, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
612      Gv_NewVar("startposz",(intptr_t)&startpos.z, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
613      Gv_NewVar("startang",(intptr_t)&startang, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
614      Gv_NewVar("startsectnum",(intptr_t)&startsectnum, GAMEVAR_READONLY | GAMEVAR_SHORTPTR | GAMEVAR_SYSTEM);
615  
616      Gv_NewVar("mousxplc",(intptr_t)&mousxplc, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
617      Gv_NewVar("mousyplc",(intptr_t)&mousyplc, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
618      Gv_NewVar("mousebits",(intptr_t)&g_mouseBits, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
619  
620      Gv_NewVar("zoom",(intptr_t)&zoom, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
621      Gv_NewVar("drawlinepat",(intptr_t)&m32_drawlinepat, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
622      Gv_NewVar("halfxdim16", (intptr_t)&halfxdim16, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
623      Gv_NewVar("midydim16", (intptr_t)&midydim16, GAMEVAR_READONLY | GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
624      Gv_NewVar("ydim16",(intptr_t)&ydim16, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
625      Gv_NewVar("m32_sideview",(intptr_t)&m32_sideview, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
626  
627      Gv_NewVar("SV1",(intptr_t)&m32_sortvar1, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
628      Gv_NewVar("SV2",(intptr_t)&m32_sortvar2, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
629      Gv_NewVar("spritesortcnt",(intptr_t)&spritesortcnt, GAMEVAR_INTPTR | GAMEVAR_SYSTEM | GAMEVAR_READONLY);
630  
631  #ifdef POLYMER
632      Gv_NewVar("pr_overrideparallax",(intptr_t)&pr_overrideparallax, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
633      Gv_NewVar("pr_parallaxscale",(intptr_t)&pr_parallaxscale, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
634      Gv_NewVar("pr_parallaxbias",(intptr_t)&pr_parallaxbias, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
635      Gv_NewVar("pr_overridespecular",(intptr_t)&pr_overridespecular, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
636      Gv_NewVar("pr_specularpower",(intptr_t)&pr_specularpower, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
637      Gv_NewVar("pr_specularfactor",(intptr_t)&pr_specularfactor, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
638  #else
639      {
640          // dummy Polymer variables for non-Polymer builds
641          static int32_t pr_overrideparallax = 0;
642          static float pr_parallaxscale = 0.1f;
643          static float pr_parallaxbias = 0.0f;
644          static int32_t pr_overridespecular = 0;
645          static float pr_specularpower = 15.0f;
646          static float pr_specularfactor = 1.0f;
647  
648          Gv_NewVar("pr_overrideparallax",(intptr_t)&pr_overrideparallax, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
649          Gv_NewVar("pr_parallaxscale",(intptr_t)&pr_parallaxscale, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
650          Gv_NewVar("pr_parallaxbias",(intptr_t)&pr_parallaxbias, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
651          Gv_NewVar("pr_overridespecular",(intptr_t)&pr_overridespecular, GAMEVAR_INTPTR | GAMEVAR_SYSTEM);
652          Gv_NewVar("pr_specularpower",(intptr_t)&pr_specularpower, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
653          Gv_NewVar("pr_specularfactor",(intptr_t)&pr_specularfactor, GAMEVAR_FLOATPTR | GAMEVAR_SYSTEM);
654      }
655  #endif
656  
657      g_systemVarCount = g_gameVarCount;
658  
659      // must be first!
660      Gv_NewArray(".LOCALS_BASE", NULL, 0, GAMEARRAY_INT32);
661  
662      Gv_NewArray("highlight", (void *)highlight, hlcnt_id,
663                  GAMEARRAY_READONLY|GAMEARRAY_INT16|GAMEARRAY_VARSIZE);
664      Gv_NewArray("highlightsector", (void *)highlightsector, hlscnt_id,
665                  GAMEARRAY_READONLY|GAMEARRAY_INT16|GAMEARRAY_VARSIZE);
666  
667      Gv_NewArray("hsect", (void *)headspritesect, MAXSECTORS+1, GAMEARRAY_READONLY|GAMEARRAY_INT16);
668      Gv_NewArray("psect", (void *)prevspritesect, MAXSPRITES, GAMEARRAY_READONLY|GAMEARRAY_INT16);
669      Gv_NewArray("nsect", (void *)nextspritesect, MAXSPRITES, GAMEARRAY_READONLY|GAMEARRAY_INT16);
670      Gv_NewArray("hstat", (void *)headspritestat, MAXSTATUS+1, GAMEARRAY_READONLY|GAMEARRAY_INT16);
671      Gv_NewArray("pstat", (void *)prevspritestat, MAXSPRITES, GAMEARRAY_READONLY|GAMEARRAY_INT16);
672      Gv_NewArray("nstat", (void *)nextspritestat, MAXSPRITES, GAMEARRAY_READONLY|GAMEARRAY_INT16);
673  #ifdef YAX_ENABLE
674      Gv_NewArray("headsectbunchc", (void *)headsectbunch[0], YAX_MAXBUNCHES, GAMEARRAY_READONLY|GAMEARRAY_INT16);
675      Gv_NewArray("nextsectbunchc", (void *)nextsectbunch[0], MAXSECTORS, GAMEARRAY_READONLY|GAMEARRAY_INT16);
676      Gv_NewArray("headsectbunchf", (void *)headsectbunch[1], YAX_MAXBUNCHES, GAMEARRAY_READONLY|GAMEARRAY_INT16);
677      Gv_NewArray("nextsectbunchf", (void *)nextsectbunch[1], MAXSECTORS, GAMEARRAY_READONLY|GAMEARRAY_INT16);
678  #endif
679      Gv_NewArray("editorcolors", (void *)editorcolors, 256, GAMEARRAY_READONLY|GAMEARRAY_UINT8);
680      Gv_NewArray("tilesizx", (void *)&tilesiz[0].x, MAXTILES, GAMEARRAY_STRIDE2|GAMEARRAY_READONLY|GAMEARRAY_INT16);
681      Gv_NewArray("tilesizy", (void *)&tilesiz[0].y, MAXTILES, GAMEARRAY_STRIDE2|GAMEARRAY_READONLY|GAMEARRAY_INT16);
682  //    Gv_NewArray("picsiz", (void *)picsiz, MAXTILES, GAMEARRAY_READONLY|GAMEARRAY_OFCHAR);
683      Gv_NewArray("picanm", (void *)picanm, MAXTILES, GAMEARRAY_READONLY|GAMEARRAY_INT32);
684  
685      Gv_NewArray("show2dsector", (void *)show2dsector, bitmap_size(MAXSECTORS), GAMEARRAY_READONLY|GAMEARRAY_UINT8);
686      Gv_NewArray("show2dwall", (void *)show2dwall, bitmap_size(MAXWALLS), GAMEARRAY_READONLY|GAMEARRAY_UINT8);
687      Gv_NewArray("show2dsprite", (void *)show2dsprite, bitmap_size(MAXSPRITES), GAMEARRAY_READONLY|GAMEARRAY_UINT8);
688  
689      Gv_NewArray("keystatus", (void *)keystatus, 256, GAMEARRAY_WARN|GAMEARRAY_UINT8);
690      Gv_NewArray("alphakeys", (void *)alphakeys, sizeof(alphakeys), GAMEARRAY_READONLY|GAMEARRAY_UINT8);
691      Gv_NewArray("numberkeys", (void *)numberkeys, sizeof(numberkeys), GAMEARRAY_READONLY|GAMEARRAY_UINT8);
692  
693      g_systemArrayCount = g_gameArrayCount;
694  }
695  
696  void Gv_Init(void)
697  {
698      // only call ONCE
699  
700      Gv_Clear();
701      Gv_AddSystemVars();
702  }