//------------------------------------------------------------------------- /* Copyright (C) 2016 EDuke32 developers and contributors This file is part of EDuke32. EDuke32 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //------------------------------------------------------------------------- #include "ns.h" // Must come before everything else! #include "duke3d.h" #include "menus.h" #include "savegame.h" #include "namesdyn.h" #include "gamevars.h" //#include "vfs.h" BEGIN_RR_NS #define gamevars_c_ gamevar_t aGameVars[MAXGAMEVARS]; int32_t g_gameVarCount = 0; // pointers to weapon gamevar data intptr_t *aplWeaponClip[MAX_WEAPONS]; // number of items in magazine intptr_t *aplWeaponFireDelay[MAX_WEAPONS]; // delay to fire intptr_t *aplWeaponFireSound[MAX_WEAPONS]; // Sound made when firing (each time for automatic) intptr_t *aplWeaponFlags[MAX_WEAPONS]; // Flags for weapon intptr_t *aplWeaponFlashColor[MAX_WEAPONS]; // Muzzle flash color intptr_t *aplWeaponHoldDelay[MAX_WEAPONS]; // delay after release fire button to fire (0 for none) intptr_t *aplWeaponInitialSound[MAX_WEAPONS]; // Sound made when weapon starts firing. zero for no sound intptr_t *aplWeaponReload[MAX_WEAPONS]; // delay to reload (include fire) intptr_t *aplWeaponShoots[MAX_WEAPONS]; // what the weapon shoots intptr_t *aplWeaponShotsPerBurst[MAX_WEAPONS]; // number of shots per 'burst' (one ammo per 'burst') intptr_t *aplWeaponSound2Sound[MAX_WEAPONS]; // Alternate sound sound ID intptr_t *aplWeaponSound2Time[MAX_WEAPONS]; // Alternate sound time intptr_t *aplWeaponSpawn[MAX_WEAPONS]; // the item to spawn intptr_t *aplWeaponSpawnTime[MAX_WEAPONS]; // the frame at which to spawn an item intptr_t *aplWeaponTotalTime[MAX_WEAPONS]; // The total time the weapon is cycling before next fire. intptr_t *aplWeaponWorksLike[MAX_WEAPONS]; // What original the weapon works like // Frees the memory for the *values* of game variables and arrays. Resets their // counts to zero. Call this function as many times as needed. // // Returns: old g_gameVarCount | (g_gameArrayCount<<16). int Gv_Free(void) { for (auto &gameVar : aGameVars) { if (gameVar.flags & GAMEVAR_USER_MASK) ALIGNED_FREE_AND_NULL(gameVar.pValues); gameVar.flags |= GAMEVAR_RESET; } EDUKE32_STATIC_ASSERT(MAXGAMEVARS < 32768); int const varCount = g_gameVarCount; g_gameVarCount = 0; hash_init(&h_gamevars); return varCount; } // Calls Gv_Free() and in addition frees the labels of all game variables and // arrays. // Only call this function at exit void Gv_Clear(void) { Gv_Free(); // Now, only do work that Gv_Free() hasn't done. for (auto & gameVar : aGameVars) DO_FREE_AND_NULL(gameVar.szLabel); } // Note that this entire function is totally architecture dependent and needs to be fixed (which won't be easy...) int Gv_ReadSave(FileReader &kFile) { char tbuf[12]; if (kFile.Read(tbuf, 12)!=12) goto corrupt; if (Bmemcmp(tbuf, "BEG: EDuke32", 12)) { Printf("BEG ERR\n"); return 2; } Gv_Free(); // nuke 'em from orbit, it's the only way to be sure... if (kFile.Read(&g_gameVarCount,sizeof(g_gameVarCount)) != sizeof(g_gameVarCount)) goto corrupt; for (bssize_t i=0; i= MAXGAMEVARS)) { g_errorCnt++; C_ReportError(-1); Printf("%s:%d: error: too many gamevars!\n",g_scriptFileName,g_lineNumber); return; } if (EDUKE32_PREDICT_FALSE(Bstrlen(pszLabel) > (MAXVARLABEL-1))) { g_errorCnt++; C_ReportError(-1); Printf("%s:%d: error: variable name `%s' exceeds limit of %d characters.\n",g_scriptFileName,g_lineNumber,pszLabel, MAXVARLABEL); return; } int gV = hash_find(&h_gamevars,pszLabel); if (gV >= 0 && !(aGameVars[gV].flags & GAMEVAR_RESET)) { // found it... if (EDUKE32_PREDICT_FALSE(aGameVars[gV].flags & (GAMEVAR_PTR_MASK))) { C_ReportError(-1); Printf("%s:%d: warning: cannot redefine internal gamevar `%s'.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6)); return; } else if (EDUKE32_PREDICT_FALSE(!(aGameVars[gV].flags & GAMEVAR_SYSTEM))) { // it's a duplicate in error g_warningCnt++; C_ReportError(WARNING_DUPLICATEDEFINITION); return; } } if (gV == -1) gV = g_gameVarCount; // If it's a user gamevar... if ((aGameVars[gV].flags & GAMEVAR_SYSTEM) == 0) { // Allocate and set its label if (aGameVars[gV].szLabel == NULL) aGameVars[gV].szLabel = (char *)Xcalloc(MAXVARLABEL,sizeof(uint8_t)); if (aGameVars[gV].szLabel != pszLabel) Bstrcpy(aGameVars[gV].szLabel,pszLabel); // and the flags aGameVars[gV].flags=dwFlags; // only free if per-{actor,player} if (aGameVars[gV].flags & GAMEVAR_USER_MASK) ALIGNED_FREE_AND_NULL(aGameVars[gV].pValues); } // if existing is system, they only get to change default value.... aGameVars[gV].defaultValue = lValue; aGameVars[gV].flags &= ~GAMEVAR_RESET; if (gV == g_gameVarCount) { // we're adding a new one. hash_add(&h_gamevars, aGameVars[gV].szLabel, g_gameVarCount++, 0); } // Set initial values. (Or, override values for system gamevars.) if (aGameVars[gV].flags & GAMEVAR_PERPLAYER) { if (!aGameVars[gV].pValues) { aGameVars[gV].pValues = (intptr_t *) Xaligned_alloc(PLAYER_VAR_ALIGNMENT, MAXPLAYERS * sizeof(intptr_t)); Bmemset(aGameVars[gV].pValues, 0, MAXPLAYERS * sizeof(intptr_t)); } for (bssize_t j=MAXPLAYERS-1; j>=0; --j) aGameVars[gV].pValues[j]=lValue; } else if (aGameVars[gV].flags & GAMEVAR_PERACTOR) { if (!aGameVars[gV].pValues) { aGameVars[gV].pValues = (intptr_t *) Xaligned_alloc(ACTOR_VAR_ALIGNMENT, MAXSPRITES * sizeof(intptr_t)); Bmemset(aGameVars[gV].pValues, 0, MAXSPRITES * sizeof(intptr_t)); } for (bssize_t j=MAXSPRITES-1; j>=0; --j) aGameVars[gV].pValues[j]=lValue; } else aGameVars[gV].global = lValue; } static int Gv_GetVarIndex(const char *szGameLabel) { int const gameVar = hash_find(&h_gamevars,szGameLabel); if (EDUKE32_PREDICT_FALSE((unsigned)gameVar >= MAXGAMEVARS)) { Printf(TEXTCOLOR_RED "Gv_GetVarIndex(): INTERNAL ERROR: couldn't find gamevar %s!\n", szGameLabel); return 0; } return gameVar; } static FORCE_INLINE int __fastcall getvar__(int const gameVar, int const spriteNum, int const playerNum) { auto const &var = aGameVars[gameVar & (MAXGAMEVARS-1)]; int returnValue = 0; int const varFlags = var.flags & (GAMEVAR_USER_MASK|GAMEVAR_PTR_MASK); if (!varFlags) returnValue = var.global; else if (varFlags == GAMEVAR_PERACTOR) returnValue = var.pValues[spriteNum & (MAXSPRITES-1)]; else if (varFlags == GAMEVAR_PERPLAYER) returnValue = var.pValues[playerNum & (MAXPLAYERS-1)]; else switch (varFlags & GAMEVAR_PTR_MASK) { case GAMEVAR_RAWQ16PTR: case GAMEVAR_INT32PTR: returnValue = *(int32_t *)var.global; break; case GAMEVAR_INT16PTR: returnValue = *(int16_t *)var.global; break; case GAMEVAR_Q16PTR: returnValue = fix16_to_int(*(fix16_t *)var.global); break; } return NEGATE_ON_CONDITION(returnValue, gameVar & GV_FLAG_NEGATIVE); } int __fastcall Gv_GetVar(int const gameVar, int const spriteNum, int const playerNum) { return getvar__(gameVar, spriteNum, playerNum); } int __fastcall Gv_GetVar(int const gameVar) { return getvar__(gameVar, vm.spriteNum, vm.playerNum); } void __fastcall Gv_GetManyVars(int const numVars, int32_t * const outBuf) { for (native_t j = 0; j < numVars; ++j) outBuf[j] = getvar__(*insptr++, vm.spriteNum, vm.playerNum); } static FORCE_INLINE void __fastcall setvar__(int const gameVar, int const newValue, int const spriteNum, int const playerNum) { gamevar_t &var = aGameVars[gameVar]; int const varFlags = var.flags & (GAMEVAR_USER_MASK|GAMEVAR_PTR_MASK); if (!varFlags) var.global=newValue; else if (varFlags == GAMEVAR_PERACTOR) var.pValues[spriteNum & (MAXSPRITES-1)] = newValue; else if (varFlags == GAMEVAR_PERPLAYER) var.pValues[playerNum & (MAXPLAYERS-1)] = newValue; else switch (varFlags & GAMEVAR_PTR_MASK) { case GAMEVAR_RAWQ16PTR: case GAMEVAR_INT32PTR: *((int32_t *)var.global) = (int32_t)newValue; break; case GAMEVAR_INT16PTR: *((int16_t *)var.global) = (int16_t)newValue; break; case GAMEVAR_Q16PTR: *(fix16_t *)var.global = fix16_from_int((int16_t)newValue); break; } return; } void __fastcall Gv_SetVar(int const gameVar, int const newValue) { setvar__(gameVar, newValue, vm.spriteNum, vm.playerNum); } void __fastcall Gv_SetVar(int const gameVar, int const newValue, int const spriteNum, int const playerNum) { setvar__(gameVar, newValue, spriteNum, playerNum); } int Gv_GetVarByLabel(const char *szGameLabel, int const defaultValue, int const spriteNum, int const playerNum) { int const gameVar = hash_find(&h_gamevars, szGameLabel); return EDUKE32_PREDICT_TRUE(gameVar >= 0) ? Gv_GetVar(gameVar, spriteNum, playerNum) : defaultValue; } static intptr_t *Gv_GetVarDataPtr(const char *szGameLabel) { int const gameVar = hash_find(&h_gamevars, szGameLabel); if (EDUKE32_PREDICT_FALSE((unsigned)gameVar >= MAXGAMEVARS)) return NULL; gamevar_t &var = aGameVars[gameVar]; if (var.flags & (GAMEVAR_USER_MASK | GAMEVAR_PTR_MASK)) return var.pValues; return &(var.global); } void Gv_ResetSystemDefaults(void) { // call many times... char aszBuf[64]; //AddLog("ResetWeaponDefaults"); for (int weaponNum = 0; weaponNum < MAX_WEAPONS; ++weaponNum) { for (int playerNum = 0; playerNum < MAXPLAYERS; ++playerNum) { Bsprintf(aszBuf, "WEAPON%d_CLIP", weaponNum); aplWeaponClip[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_RELOAD", weaponNum); aplWeaponReload[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_FIREDELAY", weaponNum); aplWeaponFireDelay[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_TOTALTIME", weaponNum); aplWeaponTotalTime[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_HOLDDELAY", weaponNum); aplWeaponHoldDelay[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_FLAGS", weaponNum); aplWeaponFlags[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_SHOOTS", weaponNum); aplWeaponShoots[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); if ((unsigned)aplWeaponShoots[weaponNum][playerNum] >= MAXTILES) aplWeaponShoots[weaponNum][playerNum] = 0; Bsprintf(aszBuf, "WEAPON%d_SPAWNTIME", weaponNum); aplWeaponSpawnTime[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_SPAWN", weaponNum); aplWeaponSpawn[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_SHOTSPERBURST", weaponNum); aplWeaponShotsPerBurst[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_WORKSLIKE", weaponNum); aplWeaponWorksLike[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_INITIALSOUND", weaponNum); aplWeaponInitialSound[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_FIRESOUND", weaponNum); aplWeaponFireSound[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_SOUND2TIME", weaponNum); aplWeaponSound2Time[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_SOUND2SOUND", weaponNum); aplWeaponSound2Sound[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); Bsprintf(aszBuf, "WEAPON%d_FLASHCOLOR", weaponNum); aplWeaponFlashColor[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); } } g_aimAngleVarID = Gv_GetVarIndex("AUTOAIMANGLE"); g_angRangeVarID = Gv_GetVarIndex("ANGRANGE"); g_returnVarID = Gv_GetVarIndex("RETURN"); g_weaponVarID = Gv_GetVarIndex("WEAPON"); g_worksLikeVarID = Gv_GetVarIndex("WORKSLIKE"); g_zRangeVarID = Gv_GetVarIndex("ZRANGE"); //AddLog("EOF:ResetWeaponDefaults"); } // Will set members that were overridden at CON translation time to 1. // For example, if // gamevar WEAPON1_SHOOTS 2200 GAMEVAR_PERPLAYER // was specified at file scope, g_weaponOverridden[1].Shoots will be 1. weapondata_t g_weaponOverridden[MAX_WEAPONS]; static weapondata_t weapondefaults[MAX_WEAPONS] = { /* WorksLike, Clip, Reload, FireDelay, TotalTime, HoldDelay, Flags, Shoots, SpawnTime, Spawn, ShotsPerBurst, InitialSound, FireSound, Sound2Time, Sound2Sound, FlashColor */ { KNEE_WEAPON__STATIC, 0, 30, 7, 14, 14, WEAPON_RANDOMRESTART | WEAPON_AUTOMATIC, KNEE__STATIC, 0, 0, 0, 0, 0, 0, 0 }, { PISTOL_WEAPON, 20, 50, 2, 5, 0, WEAPON_AUTOMATIC | WEAPON_HOLSTER_CLEARS_CLIP, SHOTSPARK1__STATIC, 2, SHELL__STATIC, 0, 0, PISTOL_FIRE__STATIC, 0, 0, 255+(95<<8) }, { SHOTGUN_WEAPON__STATIC, 0, 13, 4, 31, 0, WEAPON_CHECKATRELOAD, SHOTGUN__STATIC, 24, SHOTGUNSHELL__STATIC, 7, 0, SHOTGUN_FIRE__STATIC, 15, SHOTGUN_COCK__STATIC, 255+(95<<8) }, { CHAINGUN_WEAPON__STATIC, 0, 30, 1, 12, 10, WEAPON_AUTOMATIC | WEAPON_FIREEVERYTHIRD | WEAPON_AMMOPERSHOT, CHAINGUN__STATIC, 0, SHELL__STATIC, 0, 0, CHAINGUN_FIRE__STATIC, 0, 0, 255+(95<<8) }, { RPG_WEAPON__STATIC, 0, 30, 4, 20, 0, 0, RPG__STATIC, 0, 0, 0, 0, 0, 0, 0, 255+(95<<8) }, { HANDBOMB_WEAPON__STATIC, 0, 30, 6, 19, 12, WEAPON_THROWIT, HEAVYHBOMB__STATIC, 0, 0, 0, 0, 0, 0, 0 }, { SHRINKER_WEAPON__STATIC, 0, 0, 10, 30, 0, WEAPON_GLOWS, SHRINKER__STATIC, 0, 0, 0, SHRINKER_FIRE__STATIC, 0, 0, 0, 176+(252<<8)+(120<<16) }, { DEVISTATOR_WEAPON__STATIC, 0, 30, 2, 5, 5, WEAPON_FIREEVERYOTHER, RPG__STATIC, 0, 0, 2, CAT_FIRE__STATIC, 0, 0, 0, 255+(95<<8) }, { TRIPBOMB_WEAPON__STATIC, 0, 30, 3, 16, 0, WEAPON_STANDSTILL, HANDHOLDINGLASER__STATIC, 0, 0, 0, 0, 0, 0, 0 }, { FREEZE_WEAPON__STATIC, 0, 0, 3, 5, 0, WEAPON_FIREEVERYOTHER, FREEZEBLAST__STATIC, 0, 0, 0, CAT_FIRE__STATIC, CAT_FIRE__STATIC, 0, 0, 72+(88<<8)+(140<<16) }, { HANDREMOTE_WEAPON__STATIC, 0, 30, 2, 10, 0, WEAPON_BOMB_TRIGGER | WEAPON_NOVISIBLE, 0, 0, 0, 0, 0, 0, 0, 0 }, { GROW_WEAPON__STATIC, 0, 0, 3, 30, 0, WEAPON_GLOWS, GROWSPARK__STATIC, 0, 0, 0, EXPANDERSHOOT__STATIC, EXPANDERSHOOT__STATIC, 0, 0, 216+(52<<8)+(20<<16) }, }; // KEEPINSYNC with what is contained above // XXX: ugly static int32_t G_StaticToDynamicTile(int32_t const tile) { switch (tile) { #ifndef EDUKE32_STANDALONE case CHAINGUN__STATIC: return CHAINGUN; case FREEZEBLAST__STATIC: return FREEZEBLAST; case GROWSPARK__STATIC: return GROWSPARK; case HANDHOLDINGLASER__STATIC: return HANDHOLDINGLASER; case HEAVYHBOMB__STATIC: return HEAVYHBOMB; case KNEE__STATIC: return KNEE; case RPG__STATIC: return RPG; case SHELL__STATIC: return SHELL; case SHOTGUNSHELL__STATIC: return SHOTGUNSHELL; case SHOTGUN__STATIC: return SHOTGUN; case SHOTSPARK1__STATIC: return SHOTSPARK1; case SHRINKER__STATIC: return SHRINKER; #endif default: return tile; } } static int32_t G_StaticToDynamicSound(int32_t const sound) { switch (sound) { #ifndef EDUKE32_STANDALONE case CAT_FIRE__STATIC: return CAT_FIRE; case CHAINGUN_FIRE__STATIC: return CHAINGUN_FIRE; case EJECT_CLIP__STATIC: return EJECT_CLIP; case EXPANDERSHOOT__STATIC: return EXPANDERSHOOT; case INSERT_CLIP__STATIC: return INSERT_CLIP; case PISTOL_FIRE__STATIC: return PISTOL_FIRE; case SELECT_WEAPON__STATIC: return SELECT_WEAPON; case SHOTGUN_FIRE__STATIC: return SHOTGUN_FIRE; case SHOTGUN_COCK__STATIC: return SHOTGUN_COCK; case SHRINKER_FIRE__STATIC: return SHRINKER_FIRE; #endif default: return sound; } } // Initialize WEAPONx_* gamevars. Since for Lunatic, they reside on the C side, // they're set directly. In C-CON, a new CON variable is defined together with // its initial value. #ifdef LUNATIC # define ADDWEAPONVAR(Weapidx, Membname) do { \ int32_t j; \ for (j=0; j=0; i--) { Bsprintf(aszBuf, "WEAPON%d_CLIP", i); aplWeaponClip[i] = Gv_GetVarDataPtr(aszBuf); if (!aplWeaponClip[i]) { I_Error("ERROR: NULL weapon! WTF?! %s\n", aszBuf); } Bsprintf(aszBuf, "WEAPON%d_RELOAD", i); aplWeaponReload[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_FIREDELAY", i); aplWeaponFireDelay[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_TOTALTIME", i); aplWeaponTotalTime[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_HOLDDELAY", i); aplWeaponHoldDelay[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_FLAGS", i); aplWeaponFlags[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_SHOOTS", i); aplWeaponShoots[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_SPAWNTIME", i); aplWeaponSpawnTime[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_SPAWN", i); aplWeaponSpawn[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_SHOTSPERBURST", i); aplWeaponShotsPerBurst[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_WORKSLIKE", i); aplWeaponWorksLike[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_INITIALSOUND", i); aplWeaponInitialSound[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_FIRESOUND", i); aplWeaponFireSound[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_SOUND2TIME", i); aplWeaponSound2Time[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_SOUND2SOUND", i); aplWeaponSound2Sound[i] = Gv_GetVarDataPtr(aszBuf); Bsprintf(aszBuf, "WEAPON%d_FLASHCOLOR", i); aplWeaponFlashColor[i] = Gv_GetVarDataPtr(aszBuf); } } void Gv_RefreshPointers(void) { aGameVars[Gv_GetVarIndex("COOP")].global = (intptr_t)&ud.coop; aGameVars[Gv_GetVarIndex("FFIRE")].global = (intptr_t)&ud.ffire; aGameVars[Gv_GetVarIndex("LEVEL")].global = (intptr_t)&ud.level_number; aGameVars[Gv_GetVarIndex("MARKER")].global = (intptr_t)&ud.marker; aGameVars[Gv_GetVarIndex("MONSTERS_OFF")].global = (intptr_t)&ud.monsters_off; aGameVars[Gv_GetVarIndex("MULTIMODE")].global = (intptr_t)&ud.multimode; aGameVars[Gv_GetVarIndex("RESPAWN_INVENTORY")].global = (intptr_t)&ud.respawn_inventory; aGameVars[Gv_GetVarIndex("RESPAWN_ITEMS")].global = (intptr_t)&ud.respawn_items; aGameVars[Gv_GetVarIndex("RESPAWN_MONSTERS")].global = (intptr_t)&ud.respawn_monsters; aGameVars[Gv_GetVarIndex("VOLUME")].global = (intptr_t)&ud.volume_number; } #endif END_RR_NS