/ source / blood / src / menu.cpp
menu.cpp
   1  //-------------------------------------------------------------------------
   2  /*
   3  Copyright (C) 2010-2019 EDuke32 developers and contributors
   4  Copyright (C) 2019 Nuke.YKT
   5  
   6  This file is part of NBlood.
   7  
   8  NBlood is free software; you can redistribute it and/or
   9  modify it under the terms of the GNU General Public License version 2
  10  as published by the Free Software Foundation.
  11  
  12  This program is distributed in the hope that it will be useful,
  13  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15  
  16  See the GNU General Public License for more details.
  17  
  18  You should have received a copy of the GNU General Public License
  19  along with this program; if not, write to the Free Software
  20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  21  */
  22  //-------------------------------------------------------------------------
  23  #include "compat.h"
  24  #include "mmulti.h"
  25  #include "common_game.h"
  26  #include "fx_man.h"
  27  #include "music.h"
  28  #include "blood.h"
  29  #include "demo.h"
  30  #include "config.h"
  31  #include "gamemenu.h"
  32  #include "globals.h"
  33  #include "loadsave.h"
  34  #include "menu.h"
  35  #include "messages.h"
  36  #include "network.h"
  37  #include "osdcmds.h"
  38  #include "sfx.h"
  39  #include "screen.h"
  40  #include "sound.h"
  41  #include "tile.h"
  42  #include "view.h"
  43  
  44  void SaveGame(CGameMenuItemZEditBitmap *, CGameMenuEvent *);
  45  
  46  void SaveGameProcess(CGameMenuItemChain *);
  47  void ShowDifficulties();
  48  void SetDifficultyAndStart(CGameMenuItemChain *);
  49  void SetCustomDifficultyMenu(CGameMenuItemChain *);
  50  void SetMonsters(CGameMenuItemZCycle *);
  51  void SetCustomDifficultyAndStart(CGameMenuItemChain *);
  52  void SetFirstLaunchOptions(CGameMenuItemChain *);
  53  void SetMusicVol(CGameMenuItemSlider *);
  54  void SetSoundVol(CGameMenuItemSlider *);
  55  void SetCDVol(CGameMenuItemSlider *);
  56  void SetMonoStereo(CGameMenuItemZBool *);
  57  void SetCrosshair(CGameMenuItemZCycle *);
  58  
  59  void SetQuadDamagePowerup(CGameMenuItemZBool*);
  60  void SetDamageInvul(CGameMenuItemZCycle*);
  61  void SetProjectileBehavior(CGameMenuItemZCycle*);
  62  void SetNapalmFalloff(CGameMenuItemZBool*);
  63  void SetEnemyBehavior(CGameMenuItemZCycle*);
  64  void SetEnemyRandomTNT(CGameMenuItemZBool*);
  65  void SetWeaponsVer(CGameMenuItemZCycle*);
  66  void SetAmmoScale(CGameMenuItemZCycle*);
  67  void SetSectorBehavior(CGameMenuItemZBool*);
  68  void SetHitscanProjectiles(CGameMenuItemZCycle*);
  69  void SetGoreMode(CGameMenuItemZCycle*);
  70  void SetPlayerSpeed(CGameMenuItemZCycle*);
  71  void SetRandomizerMode(CGameMenuItemZCycle*);
  72  void SetRandomizerSeed(CGameMenuItemZEdit *pItem, CGameMenuEvent *pEvent);
  73  
  74  void SetHudSize(CGameMenuItemSlider *);
  75  void SetHudRatio(CGameMenuItemZCycle *);
  76  void SetCenterHoriz(CGameMenuItemZBool *);
  77  void SetSlopeTilting(CGameMenuItemZBool *);
  78  void SetViewBobbing(CGameMenuItemZBool *);
  79  void SetViewSwaying(CGameMenuItemZBool *);
  80  void SetWeaponSwaying(CGameMenuItemZCycle *);
  81  void SetWeaponInterpolate(CGameMenuItemZCycle *);
  82  void SetViewInterpolate(CGameMenuItemZBool *);
  83  void SetLevelCompleteTime(CGameMenuItemZBool *);
  84  void SetMirrorMode(CGameMenuItemZCycle *);
  85  void SetSlowRoomFlicker(CGameMenuItemZBool *);
  86  void SetMouseSensitivity(CGameMenuItemSliderFloat *);
  87  void SetMouseAimFlipped(CGameMenuItemZBool *);
  88  void SetTurnSpeed(CGameMenuItemSlider *);
  89  void SetTurnAcceleration(CGameMenuItemZCycle *);
  90  void SetCenterView(CGameMenuItemZBool *);
  91  void SetJoystickTargetAimAssist(CGameMenuItemZBool *);
  92  void SetRadialMenuToggle(CGameMenuItemZCycle *);
  93  void SetRadialMenuPosition(CGameMenuItemSlider *);
  94  void SetRadialMenuDimBackground(CGameMenuItemZBool *);
  95  void SetRadialMenuDimHUD(CGameMenuItemZBool *);
  96  void SetRadialMenuSlowDown(CGameMenuItemZBool *);
  97  void SetRadialMenuSound(CGameMenuItemZCycle *);
  98  void SetRadialMenuMouseThreshold(CGameMenuItemSlider *);
  99  void SetRadialMenuThreshold(CGameMenuItemSlider *);
 100  void SetRadialMenuYaw(CGameMenuItemZCycle *);
 101  void SetRadialMenuYawInvert(CGameMenuItemZBool *);
 102  void SetRadialMenuPitch(CGameMenuItemZCycle *);
 103  void SetRadialMenuPitchInvert(CGameMenuItemZBool *);
 104  void SetJoystickRumble(CGameMenuItemZBool *);
 105  void SetCrouchToggle(CGameMenuItemZBool *);
 106  void SetCrouchAuto(CGameMenuItemZBool *);
 107  void ResetKeys(CGameMenuItemChain *);
 108  void ResetKeysClassic(CGameMenuItemChain *);
 109  void SetMessages(CGameMenuItemZBool *);
 110  void LoadGame(CGameMenuItemZEditBitmap *, CGameMenuEvent *);
 111  void SetupNetLevels(CGameMenuItemZCycle *);
 112  void NetClearUserMap(CGameMenuItemZCycle *);
 113  void StartNetGame(CGameMenuItemChain *);
 114  void SetupLevelMenuItem(int);
 115  void SetupVideoModeMenu(CGameMenuItemChain *);
 116  void SetupViewMenu(CGameMenuItemChain *);
 117  void SetVideoMode(CGameMenuItemChain *);
 118  void SetWidescreen(CGameMenuItemZBool *);
 119  void SetWeaponSelectMode(CGameMenuItemZCycle *);
 120  void SetDetail(CGameMenuItemSlider *);
 121  void SetVoxels(CGameMenuItemZBool *);
 122  void SetFOV(CGameMenuItemSlider *);
 123  void UpdateVideoModeMenuFrameLimit(CGameMenuItemZCycle *pItem);
 124  void UpdateVideoColorMenu(CGameMenuItemSliderFloat *);
 125  void UpdateVideoPaletteCycleMenu(CGameMenuItemZCycle *);
 126  void UpdateVideoPaletteBoolMenu(CGameMenuItemZBool *);
 127  void ResetVideoColor(CGameMenuItemChain *);
 128  #ifdef USE_OPENGL
 129  void SetupVideoPolymostMenu(CGameMenuItemChain *);
 130  #endif
 131  
 132  char strRestoreGameStrings[kMaxLoadSaveSlot][16] = 
 133  {
 134      "<Empty>",
 135      "<Empty>",
 136      "<Empty>",
 137      "<Empty>",
 138      "<Empty>",
 139      "<Empty>",
 140      "<Empty>",
 141      "<Empty>",
 142      "<Empty>",
 143      "<Empty>",
 144  
 145      "<Empty>",
 146  
 147      "<Empty>",
 148      "<Empty>",
 149  };
 150  
 151  int restoreGameDifficulty[kMaxLoadSaveSlot] = 
 152  {
 153      -1,
 154      -1,
 155      -1,
 156      -1,
 157      -1,
 158      -1,
 159      -1,
 160      -1,
 161      -1,
 162      -1,
 163  
 164      -1,
 165  
 166      -1,
 167      -1,
 168  };
 169  
 170  const char *zNetGameTypes[] =
 171  {
 172      "Cooperative",
 173      "Bloodbath",
 174      "Teams",
 175  };
 176  
 177  const char *zMonsterStrings[] =
 178  {
 179      "None",
 180      "Bring 'em on",
 181      "Respawn (15 Secs)",
 182      "Respawn (30 Secs)",
 183      "Respawn (60 Secs)",
 184      "Respawn (90 Secs)",
 185      "Respawn (120 Secs)",
 186  };
 187  
 188  const char *zWeaponStrings[] =
 189  {
 190      "Do not Respawn",
 191      "Are Permanent",
 192      "Respawn",
 193      "Respawn with Markers",
 194  };
 195  
 196  const char *zItemStrings[] =
 197  {
 198      "Do not Respawn",
 199      "Respawn",
 200      "Respawn with Markers",
 201  };
 202  
 203  const char *zKeyStrings[] =
 204  {
 205      "LOST ON DEATH",
 206      "KEPT ON RESPAWN",
 207      "SHARED",
 208  };
 209  
 210  const char *zKeepItemWeaponStrings[] =
 211  {
 212      "LOST ON DEATH",
 213      "KEEP ON DEATH"
 214  };
 215  
 216  const char *zSpawnProtectStrings[] =
 217  {
 218      "OFF",
 219      "1 SEC",
 220      "2 SECS",
 221      "3 SECS",
 222  };
 223  
 224  const char *zShowWeapon[] =
 225  {
 226      "ALWAYS SHOW",
 227      "HIDE WHEN CLOAKED",
 228      "ALWAYS HIDE"
 229  };
 230  
 231  const char *zShowWeaponTeams[] =
 232  {
 233      "ALWAYS SHOW",
 234      "HIDE WHEN CLOAKED",
 235      "SHOW TEAMS",
 236      "ALWAYS HIDE"
 237  };
 238  
 239  const char *zSpawnWeaponStrings[] =
 240  {
 241      "Pitchfork",
 242      "Flare Pistol",
 243      "Sawed-off",
 244      "Tommy Gun",
 245      "Napalm Launcher",
 246      "Dynamite",
 247      "Spray Can",
 248      "Tesla Cannon",
 249      "Life Leech",
 250      "Voodoo Doll",
 251      "Proximity TNT",
 252      "Remote TNT",
 253      "Random Weapon",
 254      "All Weapons"
 255  };
 256  
 257  const char *zRespawnStrings[] =
 258  {
 259      "Random",
 260      "Smart Random",
 261      "Farthest From Enemies",
 262  };
 263  
 264  const char *pzMirrorModeStrings[] = {
 265      "OFF",
 266      "HORIZONTAL",
 267      "VERTICAL",
 268      "HORIZONTAL+VERTICAL"
 269  };
 270  
 271  const char *zDiffStrings[] =
 272  {
 273      "STILL KICKING",
 274      "PINK ON THE INSIDE",
 275      "LIGHTLY BROILED",
 276      "WELL DONE",
 277      "EXTRA CRISPY",
 278  };
 279  
 280  const char *pzDamageInvulBehaviorStrings[] = {
 281      "Off",
 282      "Shortest",
 283      "Short",
 284      "Medium",
 285      "Long",
 286      "Longest",
 287  };
 288  
 289  const char *pzProjectileBehaviorStrings[] = {
 290      "Original",
 291      "NotBlood",
 292      "Raze",
 293  };
 294  
 295  const char *pzEnemyBehaviorStrings[] = {
 296      "Original",
 297      "NBlood",
 298      "NotBlood",
 299  };
 300  
 301  const char *pzWeaponsVersionStrings[] = {
 302      "Original",
 303      "NotBlood",
 304      "V1.0x",
 305  };
 306  
 307  const char *pzAmmoScaleStrings[] = {
 308      "Original",
 309      "125%",
 310      "150%",
 311      "25%",
 312      "50%",
 313      "75%",
 314  };
 315  
 316  const char *pzHitscanProjectilesStrings[] = {
 317      "Off",
 318      "Slow",
 319      "Medium",
 320      "Fast",
 321  };
 322  
 323  const char *pzGoreStrings[] = {
 324      "Original",
 325      "Extended",
 326      "Excessive",
 327  };
 328  
 329  const char *pzRandomizerModeStrings[] = {
 330      "Off",
 331      "Enemies",
 332      "Pickups",
 333      "Enemies+Pickups",
 334  };
 335  
 336  const char *pzEnemySpeeds[] = {
 337      "Default",
 338      "1.5x",
 339      "2.0x",
 340      "2.5x",
 341      "3.0x",
 342  };
 343  
 344  const char *pzPlayerSpeeds[] = {
 345      "Default",
 346      "1.25x",
 347      "1.50x",
 348      "1.75x",
 349      "2.00x",
 350  };
 351  
 352  char zUserMapName[BMAX_PATH] = "";
 353  const char *zEpisodeNames[6];
 354  const char *zLevelNames[6][kMaxLevels];
 355  static char szRandomizerSeedMenu[9];
 356  
 357  static char MenuGameFuncs[NUMGAMEFUNCTIONS][MAXGAMEFUNCLEN];
 358  static char const *MenuGameFuncNone = "  -None-";
 359  static char const *pzGamefuncsStrings[NUMGAMEFUNCTIONS + 1];
 360  static int nGamefuncsValues[NUMGAMEFUNCTIONS + 1];
 361  static int nGamefuncsNum;
 362  
 363  CGameMenu menuMain;
 364  CGameMenu menuMainWithSave;
 365  CGameMenu menuFirstLaunch;
 366  CGameMenu menuNetMain;
 367  CGameMenu menuNetStart;
 368  CGameMenu menuEpisode;
 369  CGameMenu menuDifficulty;
 370  CGameMenu menuCustomDifficulty;
 371  CGameMenu menuBannedMonsters;
 372  CGameMenu menuBannedItems;
 373  CGameMenu menuControls;
 374  CGameMenu menuMessages;
 375  CGameMenu menuSaveGame;
 376  CGameMenu menuLoadGame;
 377  CGameMenu menuLoading;
 378  CGameMenu menuQuit;
 379  CGameMenu menuRestart;
 380  CGameMenu menuCredits;
 381  CGameMenu menuHelp;
 382  CGameMenu menuNetwork;
 383  CGameMenu menuNetworkHost;
 384  CGameMenu menuNetworkJoin;
 385  CGameMenu menuNetworkGameMode;
 386  CGameMenu menuNetworkGameMonsters;
 387  CGameMenu menuNetworkGameMutators;
 388  
 389  CGameMenuItemQAV itemBloodQAV("", 3, 160, 100, "BDRIP", true);
 390  CGameMenuItemQAV itemCreditsQAV("", 3, 160, 100, "CREDITS", false, true);
 391  CGameMenuItemQAV itemHelp3QAV("", 3, 160, 100, "HELP3", false, false);
 392  CGameMenuItemQAV itemHelp3BQAV("", 3, 160, 100, "HELP3B", false, false);
 393  CGameMenuItemQAV itemHelp4QAV("", 3, 160, 100, "HELP4", false, true);
 394  CGameMenuItemQAV itemHelp5QAV("", 3, 160, 100, "HELP5", false, true);
 395  
 396  CGameMenuItemTitle itemMainTitle(gGameTitle, 1, 160, 20, 2038);
 397  CGameMenuItemChain itemMain1("NEW GAME", 1, 0, 45, 320, 1, &menuEpisode, -1, NULL, 0);
 398  CGameMenuItemChain itemMain2("MULTIPLAYER", 1, 0, 65, 320, 1, &menuNetwork, -1, NULL, 0);
 399  CGameMenuItemChain itemMain3("OPTIONS", 1, 0, 85, 320, 1, &menuOptions, -1, NULL, 0);
 400  CGameMenuItemChain itemMain4("LOAD GAME", 1, 0, 105, 320, 1, &menuLoadGame, -1, NULL, 0);
 401  CGameMenuItemChain itemMain5("HELP", 1, 0, 125, 320, 1, &menuHelp, -1, NULL, 0);
 402  CGameMenuItemChain itemMain6("CREDITS", 1, 0, 145, 320, 1, &menuCredits, -1, NULL, 0);
 403  CGameMenuItemChain itemMain7("QUIT", 1, 0, 165, 320, 1, &menuQuit, -1, NULL, 0);
 404  
 405  CGameMenuItemTitle itemMainSaveTitle(gGameTitle, 1, 160, 20, 2038);
 406  CGameMenuItemChain itemMainSave1("NEW GAME", 1, 0, 45, 320, 1, &menuEpisode, -1, NULL, 0);
 407  CGameMenuItemChain itemMainSave2("OPTIONS", 1, 0, 60, 320, 1, &menuOptions, -1, NULL, 0);
 408  CGameMenuItemChain itemMainSave3("SAVE GAME", 1, 0, 75, 320, 1, &menuSaveGame, -1, SaveGameProcess, 0);
 409  CGameMenuItemChain itemMainSave4("LOAD GAME", 1, 0, 90, 320, 1, &menuLoadGame, -1, NULL, 0);
 410  CGameMenuItemChain itemMainSave5("HELP", 1, 0, 105, 320, 1, &menuHelp, -1, NULL, 0);
 411  CGameMenuItemChain itemMainSave6("CREDITS", 1, 0, 120, 320, 1, &menuCredits, -1, NULL, 0);
 412  CGameMenuItemChain itemMainSave7("END GAME", 1, 0, 135, 320, 1, &menuRestart, -1, NULL, 0);
 413  CGameMenuItemChain itemMainSave8("QUIT", 1, 0, 150, 320, 1, &menuQuit, -1, NULL, 0);
 414  
 415  CGameMenuItemTitle itemFirstLaunchInfo1("THIS IS YOUR FIRST TIME LAUNCHING NOTBLOOD", 1, 160, 45, -1);
 416  CGameMenuItemTitle itemFirstLaunchInfo2("PLEASE SELECT YOUR PREFERRED EXPERIENCE", 1, 160, 65, -1);
 417  CGameMenuItemChain itemFirstLaunchVanilla("DOS BLOOD", 1, 0, 90, 320, 1, NULL, -1, SetFirstLaunchOptions, 0);
 418  CGameMenuItemChain itemFirstLaunchNBlood("NBLOOD", 1, 0, 110, 320, 1, NULL, -1, SetFirstLaunchOptions, 0);
 419  CGameMenuItemChain itemFirstLaunchNotBlood("NOTBLOOD", 1, 0, 130, 320, 1, NULL, -1, SetFirstLaunchOptions, 0);
 420  
 421  CGameMenuItemTitle itemEpisodesTitle("EPISODES", 1, 160, 20, 2038);
 422  CGameMenuItemChain7F2F0 itemEpisodes[kMaxEpisodes-1];
 423  
 424  CGameMenu menuUserMap;
 425  CGameMenuItemChain itemUserMap("< USER MAP >", 1, 0, 60, 320, 1, &menuUserMap, 0, NULL, 0, 8);
 426  CGameMenuItemTitle itemUserMapTitle("USER MAP", 1, 160, 20, 2038);
 427  CGameMenuFileSelect itemUserMapList("", 3, 0, 0, 0, "./", "*.map", gGameOptions.szUserMap, ShowDifficulties, 0);
 428  
 429  CGameMenuItemTitle itemDifficultyTitle("DIFFICULTY", 1, 160, 20, 2038);
 430  CGameMenuItemChain itemDifficulty1("STILL KICKING", 1, 0, 55, 320, 1, NULL, -1, SetDifficultyAndStart, 0);
 431  CGameMenuItemChain itemDifficulty2("PINK ON THE INSIDE", 1, 0, 75, 320, 1, NULL, -1, SetDifficultyAndStart, 1);
 432  CGameMenuItemChain itemDifficulty3("LIGHTLY BROILED", 1, 0, 95, 320, 1, NULL, -1, SetDifficultyAndStart, 2);
 433  CGameMenuItemChain itemDifficulty4("WELL DONE", 1, 0, 115, 320, 1, NULL, -1, SetDifficultyAndStart, 3);
 434  CGameMenuItemChain itemDifficulty5("EXTRA CRISPY", 1, 0, 135, 320, 1, 0, -1, SetDifficultyAndStart, 4);
 435  CGameMenuItemChain itemDifficulty6("< CUSTOM >", 1, 0, 155, 320, 1, &menuCustomDifficulty, -1, SetCustomDifficultyMenu, 0, 8);
 436  
 437  CGameMenuItemTitle itemCustomDifficultyTitle("CUSTOM", 1, 160, 20, 2038);
 438  CGameMenuItemSlider itemCustomDifficultyStartLevel("LEVEL:", 3, 66, 35, 180, 0, 0, kMaxLevels-1, 1, NULL, -1, -1, kMenuSliderValue, 1);
 439  CGameMenuItemZCycle itemCustomDifficultyMonsterSettings("MONSTERS:", 3, 66, 45, 180, 0, SetMonsters, zMonsterStrings, ARRAY_SSIZE(zMonsterStrings), 1);
 440  CGameMenuItemSlider itemCustomDifficultyEnemyQuantity("ENEMIES QUANTITY:", 3, 66, 55, 180, 2, 0, 4, 1, NULL, -1, -1);
 441  CGameMenuItemSlider itemCustomDifficultyEnemyHealth("ENEMIES HEALTH:", 3, 66, 65, 180, 2, 0, 4, 1, NULL, -1, -1);
 442  CGameMenuItemSlider itemCustomDifficultyEnemyDifficulty("ENEMIES DIFFICULTY:", 3, 66, 75, 180, 2, 0, 4, 1, NULL, -1, -1);
 443  CGameMenuItemSlider itemCustomDifficultyPlayerDamage("PLAYER DAMAGE SCALE:", 3, 66, 85, 180, 2, 0, 4, 1, NULL, -1, -1);
 444  CGameMenuItemZCycle itemCustomDifficultyEnemySpeed("ENEMIES SPEED:", 3, 66, 95, 180, 0, 0, pzEnemySpeeds, ARRAY_SSIZE(pzEnemySpeeds), 0);
 445  CGameMenuItemZBool itemCustomDifficultyEnemyShuffle("RANDOMIZE ENEMY POSITIONS:", 3, 66, 105, 180, false, NULL, NULL, NULL);
 446  CGameMenuItemZBool itemCustomDifficultyPitchfork("PITCHFORK START:", 3, 66, 115, 180, false, NULL, NULL, NULL);
 447  CGameMenuItemZBool itemCustomDifficultyPermaDeath("PERMANENT DEATH:", 3, 66, 125, 180, false, NULL, NULL, NULL);
 448  CGameMenuItemChain itemCustomDifficultyBannedMonsters("SET MONSTERS", 3, 66, 137, 180, 1, &menuBannedMonsters, -1, NULL, 0);
 449  CGameMenuItemChain itemCustomDifficultyBannedItems("SET ITEMS", 3, 66, 148, 180, 1, &menuBannedItems, -1, NULL, 0);
 450  CGameMenuItemChain itemCustomDifficultyStart("START GAME", 1, 0, 161, 320, 1, NULL, -1, SetCustomDifficultyAndStart, 0);
 451  
 452  CGameMenuItemTitle itemBannedMonstersTitle("SET MONSTERS", 1, 160, 20, 2038);
 453  CGameMenuItemZBool itemBannedMonstersBats("BATS:", 3, 75, 40, 161, false, NULL, "REMOVE", "KEEP");
 454  CGameMenuItemZBool itemBannedMonstersRats("RATS:", 3, 75, 48, 161, false, NULL, "REMOVE", "KEEP");
 455  CGameMenuItemZBool itemBannedMonstersFish("FISH:", 3, 75, 56, 161, false, NULL, "REMOVE", "KEEP");
 456  CGameMenuItemZBool itemBannedMonstersHands("HANDS:", 3, 75, 64, 161, false, NULL, "REMOVE", "KEEP");
 457  CGameMenuItemZBool itemBannedMonstersGhosts("GHOSTS:", 3, 75, 72, 161, false, NULL, "REMOVE", "KEEP");
 458  CGameMenuItemZBool itemBannedMonstersSpiders("SPIDERS:", 3, 75, 80, 161, false, NULL, "REMOVE", "KEEP");
 459  CGameMenuItemZBool itemBannedMonstersTinyCaleb("TINY CALEBS:", 3, 75, 88, 161, false, NULL, "REMOVE", "KEEP");
 460  CGameMenuItemZBool itemBannedMonstersHellHounds("HELL HOUNDS:", 3, 75, 96, 161, false, NULL, "REMOVE", "KEEP");
 461  CGameMenuItemZBool itemBannedMonstersRatsAttack("RAT ATTACK DISTANCE:", 3, 75, 112, 161, false, NULL, "SHORTER", "DEFAULT");
 462  CGameMenuItemZBool itemBannedMonstersMotherSpiderHealth("MOTHER SPIDER HEALTH:", 3, 75, 120, 161, false, NULL, "HALF", "DEFAULT");
 463  CGameMenuItemZBool itemBannedMonstersTchernobogHealth("TCHERNOBOG HEALTH:", 3, 75, 128, 161, false, NULL, "FULL", "DEFAULT");
 464  
 465  CGameMenuItemTitle itemBannedItemsTitle("SET ITEMS", 1, 160, 20, 2038);
 466  CGameMenuItemZBool itemBannedItemsFlare("FLARE PISTOL:", 3, 75, 32, 161, false, NULL, "REMOVE", "KEEP");
 467  CGameMenuItemZBool itemBannedItemsShotgun("SAWED-OFF:", 3, 75, 40, 161, false, NULL, "REMOVE", "KEEP");
 468  CGameMenuItemZBool itemBannedItemsTommyGun("TOMMY GUN:", 3, 75, 48, 161, false, NULL, "REMOVE", "KEEP");
 469  CGameMenuItemZBool itemBannedItemsNapalm("NAPALM LAUNCHER:", 3, 75, 56, 161, false, NULL, "REMOVE", "KEEP");
 470  CGameMenuItemZBool itemBannedItemsTNT("DYNAMITE:", 3, 75, 64, 161, false, NULL, "REMOVE", "KEEP");
 471  CGameMenuItemZBool itemBannedItemsSpray("SPRAY CAN:", 3, 75, 72, 161, false, NULL, "REMOVE", "KEEP");
 472  CGameMenuItemZBool itemBannedItemsTesla("TESLA CANNON:", 3, 75, 80, 161, false, NULL, "REMOVE", "KEEP");
 473  CGameMenuItemZBool itemBannedItemsLifeLeech("LIFE LEECH:", 3, 75, 88, 161, false, NULL, "REMOVE", "KEEP");
 474  CGameMenuItemZBool itemBannedItemsVoodoo("VOODOO DOLL:", 3, 75, 96, 161, false, NULL, "REMOVE", "KEEP");
 475  CGameMenuItemZBool itemBannedItemsProxy("PROXIMITY TNT:", 3, 75, 104, 161, false, NULL, "REMOVE", "KEEP");
 476  CGameMenuItemZBool itemBannedItemsRemote("REMOTE TNT:", 3, 75, 112, 161, false, NULL, "REMOVE", "KEEP");
 477  CGameMenuItemZBool itemBannedItemsMedKit("DOCTOR'S BAG:", 3, 75, 120, 161, false, NULL, "REMOVE", "KEEP");
 478  CGameMenuItemZBool itemBannedItemsLifeEssence("LIFE ESSENCE/MED POUCH:", 3, 75, 128, 161, false, NULL, "REMOVE", "KEEP");
 479  CGameMenuItemZBool itemBannedItemsLifeSeed("LIFE SEED:", 3, 75, 136, 161, false, NULL, "REMOVE", "KEEP");
 480  CGameMenuItemZBool itemBannedItemsSuperArmor("SUPER ARMOR:", 3, 75, 144, 161, false, NULL, "REMOVE", "KEEP");
 481  CGameMenuItemZBool itemBannedItemsCrystalBall("CRYSTAL BALL:", 3, 75, 152, 161, false, NULL, "REMOVE", "KEEP");
 482  CGameMenuItemZBool itemBannedItemsJumpBoots("JUMP BOOTS:", 3, 75, 160, 161, false, NULL, "REMOVE", "KEEP");
 483  CGameMenuItemZBool itemBannedItemsCloak("INVISIBILITY CLOAK:", 3, 75, 168, 161, false, NULL, "REMOVE", "KEEP");
 484  CGameMenuItemZBool itemBannedItemsDeathMask("INVULNERABILITY MASK:", 3, 75, 176, 161, false, NULL, "REMOVE", "KEEP");
 485  CGameMenuItemZBool itemBannedItemsAkimbo("GUNS AKIMBO:", 3, 75, 184, 161, false, NULL, "REMOVE", "KEEP");
 486  CGameMenuItemZBool itemBannedItemsReflect("REFLECTIVE SHOTS:", 3, 75, 192, 161, false, NULL, "REMOVE", "KEEP");
 487  
 488  CGameMenuItemTitle itemMessagesTitle("MESSAGES", 1, 160, 20, 2038);
 489  CGameMenuItemZBool boolMessages("MESSAGES:", 3, 66, 70, 180, 0, SetMessages, NULL, NULL);
 490  CGameMenuItemSlider sliderMsgCount("MESSAGE COUNT:", 3, 66, 80, 180, gMessageCount, 1, 16, 1, NULL, -1, -1);
 491  CGameMenuItemSlider sliderMsgTime("MESSAGE TIME:", 3, 66, 90, 180, gMessageTime, 1, 8, 1, NULL, -1, -1);
 492  CGameMenuItemZBool boolMsgFont("LARGE FONT:", 3, 66, 100, 180, 0, 0, NULL, NULL);
 493  CGameMenuItemZBool boolMsgIncoming("INCOMING:", 3, 66, 110, 180, 0, 0, NULL, NULL);
 494  CGameMenuItemZBool boolMsgSelf("SELF PICKUP:", 3, 66, 120, 180, 0, 0, NULL, NULL);
 495  CGameMenuItemZBool boolMsgOther("OTHER PICKUP:", 3, 66, 130, 180, 0, 0, NULL, NULL);
 496  CGameMenuItemZBool boolMsgRespawn("RESPAWN:", 3, 66, 140, 180, 0, 0, NULL, NULL);
 497  
 498  CGameMenuItemTitle itemSaveTitle("Save Game", 1, 160, 20, 2038);
 499  CGameMenuItemZEditBitmap itemSaveGame0(NULL, 3, 20, 60, 320, strRestoreGameStrings[kLoadSaveSlot0], 16, 1, SaveGame, kLoadSaveSlot0);
 500  CGameMenuItemZEditBitmap itemSaveGame1(NULL, 3, 20, 70, 320, strRestoreGameStrings[kLoadSaveSlot1], 16, 1, SaveGame, kLoadSaveSlot1);
 501  CGameMenuItemZEditBitmap itemSaveGame2(NULL, 3, 20, 80, 320, strRestoreGameStrings[kLoadSaveSlot2], 16, 1, SaveGame, kLoadSaveSlot2);
 502  CGameMenuItemZEditBitmap itemSaveGame3(NULL, 3, 20, 90, 320, strRestoreGameStrings[kLoadSaveSlot3], 16, 1, SaveGame, kLoadSaveSlot3);
 503  CGameMenuItemZEditBitmap itemSaveGame4(NULL, 3, 20, 100, 320, strRestoreGameStrings[kLoadSaveSlot4], 16, 1, SaveGame, kLoadSaveSlot4);
 504  CGameMenuItemZEditBitmap itemSaveGame5(NULL, 3, 20, 110, 320, strRestoreGameStrings[kLoadSaveSlot5], 16, 1, SaveGame, kLoadSaveSlot5);
 505  CGameMenuItemZEditBitmap itemSaveGame6(NULL, 3, 20, 120, 320, strRestoreGameStrings[kLoadSaveSlot6], 16, 1, SaveGame, kLoadSaveSlot6);
 506  CGameMenuItemZEditBitmap itemSaveGame7(NULL, 3, 20, 130, 320, strRestoreGameStrings[kLoadSaveSlot7], 16, 1, SaveGame, kLoadSaveSlot7);
 507  CGameMenuItemZEditBitmap itemSaveGame8(NULL, 3, 20, 140, 320, strRestoreGameStrings[kLoadSaveSlot8], 16, 1, SaveGame, kLoadSaveSlot8);
 508  CGameMenuItemZEditBitmap itemSaveGame9(NULL, 3, 20, 150, 320, strRestoreGameStrings[kLoadSaveSlot9], 16, 1, SaveGame, kLoadSaveSlot9);
 509  CGameMenuItemZEditBitmap itemSaveGameQuick(NULL, 3, 20, 163, 320, strRestoreGameStrings[kLoadSaveSlotQuick], 16, 1, SaveGame, kLoadSaveSlotQuick);
 510  CGameMenuItemZEditBitmap itemSaveGameAutosaveStart(NULL, 3, 20, 176, 320, strRestoreGameStrings[kLoadSaveSlotSpawn], 16, 1, SaveGame, kLoadSaveSlotSpawn);
 511  CGameMenuItemZEditBitmap itemSaveGameAutosaveKey(NULL, 3, 20, 186, 320, strRestoreGameStrings[kLoadSaveSlotKey], 16, 1, SaveGame, kLoadSaveSlotKey);
 512  CGameMenuItemBitmapLS itemSaveGamePic(NULL, 3, 0, 0, 2050);
 513  
 514  CGameMenuItemTitle itemLoadTitle("Load Game", 1, 160, 20, 2038);
 515  CGameMenuItemZEditBitmap itemLoadGame0(NULL, 3, 20, 60, 320, strRestoreGameStrings[kLoadSaveSlot0], 16, 1, LoadGame, kLoadSaveSlot0);
 516  CGameMenuItemZEditBitmap itemLoadGame1(NULL, 3, 20, 70, 320, strRestoreGameStrings[kLoadSaveSlot1], 16, 1, LoadGame, kLoadSaveSlot1);
 517  CGameMenuItemZEditBitmap itemLoadGame2(NULL, 3, 20, 80, 320, strRestoreGameStrings[kLoadSaveSlot2], 16, 1, LoadGame, kLoadSaveSlot2);
 518  CGameMenuItemZEditBitmap itemLoadGame3(NULL, 3, 20, 90, 320, strRestoreGameStrings[kLoadSaveSlot3], 16, 1, LoadGame, kLoadSaveSlot3);
 519  CGameMenuItemZEditBitmap itemLoadGame4(NULL, 3, 20, 100, 320, strRestoreGameStrings[kLoadSaveSlot4], 16, 1, LoadGame, kLoadSaveSlot4);
 520  CGameMenuItemZEditBitmap itemLoadGame5(NULL, 3, 20, 110, 320, strRestoreGameStrings[kLoadSaveSlot5], 16, 1, LoadGame, kLoadSaveSlot5);
 521  CGameMenuItemZEditBitmap itemLoadGame6(NULL, 3, 20, 120, 320, strRestoreGameStrings[kLoadSaveSlot6], 16, 1, LoadGame, kLoadSaveSlot6);
 522  CGameMenuItemZEditBitmap itemLoadGame7(NULL, 3, 20, 130, 320, strRestoreGameStrings[kLoadSaveSlot7], 16, 1, LoadGame, kLoadSaveSlot7);
 523  CGameMenuItemZEditBitmap itemLoadGame8(NULL, 3, 20, 140, 320, strRestoreGameStrings[kLoadSaveSlot8], 16, 1, LoadGame, kLoadSaveSlot8);
 524  CGameMenuItemZEditBitmap itemLoadGame9(NULL, 3, 20, 150, 320, strRestoreGameStrings[kLoadSaveSlot9], 16, 1, LoadGame, kLoadSaveSlot9);
 525  CGameMenuItemZEditBitmap itemLoadGameQuick(NULL, 3, 20, 163, 320, strRestoreGameStrings[kLoadSaveSlotQuick], 16, 1, LoadGame, kLoadSaveSlotQuick);
 526  CGameMenuItemZEditBitmap itemLoadGameAutosaveStart(NULL, 3, 20, 176, 320, strRestoreGameStrings[kLoadSaveSlotSpawn], 16, 1, LoadGame, kLoadSaveSlotSpawn);
 527  CGameMenuItemZEditBitmap itemLoadGameAutosaveKey(NULL, 3, 20, 186, 320, strRestoreGameStrings[kLoadSaveSlotKey], 16, 1, LoadGame, kLoadSaveSlotKey);
 528  CGameMenuItemBitmapLS itemLoadGamePic(NULL, 3, 0, 0, 2518);
 529  
 530  CGameMenu menuMultiUserMaps;
 531  
 532  CGameMenuItemTitle itemNetStartUserMapTitle("USER MAP", 1, 160, 20, 2038);
 533  CGameMenuFileSelect menuMultiUserMap("", 3, 0, 0, 0, "./", "*.map", zUserMapName);
 534  
 535  void SetNetGameMode(CGameMenuItemZCycle *pItem);
 536  void SetNetShowWeapon(CGameMenuItemZCycle *pItem);
 537  void SetNetMonsterMenu(CGameMenuItemZCycle *pItem);
 538  
 539  CGameMenuItemTitle itemNetStartTitle("MULTIPLAYER", 1, 160, 20, 2038);
 540  CGameMenuItemChain itemNetStart1("GAME:", 3, 66, 35, 180, 0, &menuNetworkGameMode, -1, NULL, 0);
 541  CGameMenuItemZCycle itemNetStart2("EPISODE:", 3, 66, 45, 180, 0, SetupNetLevels, NULL, 0, 0);
 542  CGameMenuItemZCycle itemNetStart3("LEVEL:", 3, 66, 55, 180, 0, NetClearUserMap, NULL, 0, 0);
 543  CGameMenuItemZCycle itemNetStart4("DIFFICULTY:", 3, 66, 65, 180, 0, SetNetMonsterMenu, zDiffStrings, ARRAY_SSIZE(zDiffStrings), 0);
 544  CGameMenuItemChain itemNetStart5("MONSTER SETTING:", 3, 66, 75, 180, 0, &menuNetworkGameMonsters, -1, NULL, 0);
 545  CGameMenuItemZCycle itemNetStart6("WEAPONS:", 3, 66, 85, 180, 0, 0, zWeaponStrings, 4, 0);
 546  CGameMenuItemZCycle itemNetStart7("ITEMS:", 3, 66, 95, 180, 0, 0, zItemStrings, 3, 0);
 547  CGameMenuItemZBool itemNetStartBoolChaseView("CHASE VIEW:", 3, 66, 105, 180, false, NULL, NULL, NULL);
 548  CGameMenuItemZBool itemNetStartBoolHolstering("HOLSTERING:", 3, 66, 115, 180, false, NULL, NULL, NULL);
 549  CGameMenuItemZBool itemNetStartBoolSecondWind("SECOND WIND:", 3, 66, 125, 180, true, 0, NULL, NULL);
 550  CGameMenuItemZBool itemNetStartBoolSpectatorMode("SPECTATING:", 3, 66, 135, 180, false, 0, NULL, NULL);
 551  CGameMenuItemChain itemNetStart8("SET ITEMS", 3, 0, 143, 320, 1, &menuBannedItems, -1, NULL, 0);
 552  CGameMenuItemChain itemNetStart9("SET MUTATORS", 3, 0, 153, 320, 1, &menuNetworkGameMutators, -1, NULL, 0);
 553  CGameMenuItemChain itemNetStart10("USER MAP", 3, 0, 163, 320, 1, &menuMultiUserMaps, 0, NULL, 0);
 554  CGameMenuItemChain itemNetStart11("START GAME", 1, 0, 175, 320, 1, 0, -1, StartNetGame, 0);
 555  
 556  CGameMenuItemTitle itemNetGameTitle("GAME SETTINGS", 1, 160, 20, 2038);
 557  CGameMenuItemZCycle itemNetGameMode("GAME:", 3, 66, 35, 180, 0, SetNetGameMode, zNetGameTypes, ARRAY_SSIZE(zNetGameTypes), 0);
 558  CGameMenuItemSlider itemNetGameSliderScoreLimit("SCORE LIMIT:", 3, 66, 44, 180, 0, 0, 255, 1, NULL, -1, -1, kMenuSliderValue);
 559  CGameMenuItemSlider itemNetGameSliderLivesLimit("LIVES:", 3, 66, 44, 180, 0, 0, 255, 1, NULL, -1, -1, kMenuSliderValue);
 560  CGameMenuItemSlider itemNetGameSliderTimeLimit("TIME LIMIT:", 3, 66, 54, 180, 0, 0, 60, 1, NULL, -1, -1, kMenuSliderValue);
 561  CGameMenuItemZBool itemNetGameBoolExit("LEVEL EXIT:", 3, 66, 65, 180, true, NULL, NULL, NULL);
 562  CGameMenuItemZBool itemNetGameBoolTeleFrag("TELEFRAGS:", 3, 66, 73, 180, true, NULL, NULL, NULL);
 563  CGameMenuItemZBool itemNetGameBoolSkillOverride("PLAYER HANDICAP:", 3, 66, 81, 180, true, NULL, "ALLOWED", "OFF");
 564  CGameMenuItemZBool itemNetGameBoolModelOverride("PLAYER MODEL:", 3, 66, 89, 180, true, NULL, "CULTISTS/CALEB", "CALEB ONLY");
 565  CGameMenuItemZBool itemNetGameBoolPlayerColors("PLAYER COLORS:", 3, 66, 97, 180, true, 0, "EXTENDED", "VANILLA");
 566  CGameMenuItemZBool itemNetGameBoolFriendlyFire("FRIENDLY FIRE:", 3, 66, 105, 180, true, 0, NULL, NULL);
 567  CGameMenuItemZCycle itemNetGameCycleKey("KEYS SETTING:", 3, 66, 113, 180, 0, 0, zKeyStrings, ARRAY_SSIZE(zKeyStrings), 0);
 568  CGameMenuItemZCycle itemNetGameCycleItemWeapon("ITEM/WEAPON SETTING:", 3, 66, 121, 180, 0, SetNetGameMode, zKeepItemWeaponStrings, ARRAY_SSIZE(zKeepItemWeaponStrings), 0);
 569  CGameMenuItemZBool itemNetGameBoolTeamColors("TEAM COLORS:", 3, 66, 97, 180, true, 0, NULL, NULL);
 570  CGameMenuItemZBool itemNetGameBoolAutoTeams("AUTO TEAMS:", 3, 66, 113, 180, true, 0, NULL, NULL);
 571  CGameMenuItemZBool itemNetGameBoolTeamFlags("TEAM FLAGS:", 3, 66, 121, 180, true, 0, NULL, NULL);
 572  CGameMenuItemZCycle itemNetGameCycleSpawnLocation("SPAWN AREA:", 3, 66, 129, 180, 0, 0, zRespawnStrings, ARRAY_SSIZE(zRespawnStrings), 0);
 573  CGameMenuItemZCycle itemNetGameCycleShowWeaponsOverride("ENEMY WEAPONS:", 3, 66, 137, 180, 0, SetNetShowWeapon, zShowWeapon, ARRAY_SSIZE(zShowWeapon), 0);
 574  CGameMenuItemZCycle itemNetGameCycleShowWeaponsOverrideTeams("ENEMY WEAPONS:", 3, 66, 137, 180, 0, SetNetShowWeapon, zShowWeaponTeams, ARRAY_SSIZE(zShowWeaponTeams), 0);
 575  CGameMenuItemZCycle itemNetGameCycleSpawnProtection("SPAWN PROTECTION:", 3, 66, 145, 180, 0, 0, zSpawnProtectStrings, ARRAY_SSIZE(zSpawnProtectStrings), 0);
 576  CGameMenuItemZCycle itemNetGameCycleSpawnWeapon("SPAWN WITH WEAPON:", 3, 66, 153, 180, 0, SetNetGameMode, zSpawnWeaponStrings, ARRAY_SSIZE(zSpawnWeaponStrings), 0);
 577  CGameMenuItemZCycle itemNetGameCycleMirrorModeOverride("MIRROR MODE:", 3, 66, 161, 180, 0, NULL, pzMirrorModeStrings, ARRAY_SSIZE(pzMirrorModeStrings), 0);
 578  
 579  CGameMenuItemTitle itemNetMonsterTitle("MONSTERS", 1, 160, 20, 2038);
 580  CGameMenuItemZCycle itemNetMonsterSettings("MONSTERS:", 3, 66, 40, 180, 0, SetNetMonsterMenu, zMonsterStrings, ARRAY_SSIZE(zMonsterStrings), 0);
 581  CGameMenuItemSlider itemNetMonsterQuantity("MONSTER QUANTITY:", 3, 66, 50, 180, 2, 0, 4, 1, NULL, -1, -1);
 582  CGameMenuItemSlider itemNetMonsterHealth("MONSTER HEALTH:", 3, 66, 60, 180, 2, 0, 4, 1, NULL, -1, -1);
 583  CGameMenuItemZCycle itemNetMonsterSpeed("MONSTER SPEED:", 3, 66, 70, 180, 0, 0, pzEnemySpeeds, ARRAY_SSIZE(pzEnemySpeeds), 0);
 584  CGameMenuItemZBool itemNetMonsterBats("BATS:", 3, 75, 90, 161, false, NULL, "REMOVE", "KEEP");
 585  CGameMenuItemZBool itemNetMonsterRats("RATS:", 3, 75, 98, 161, false, NULL, "REMOVE", "KEEP");
 586  CGameMenuItemZBool itemNetMonsterFish("FISH:", 3, 75, 106, 161, false, NULL, "REMOVE", "KEEP");
 587  CGameMenuItemZBool itemNetMonsterHands("HANDS:", 3, 75, 114, 161, false, NULL, "REMOVE", "KEEP");
 588  CGameMenuItemZBool itemNetMonsterGhosts("GHOSTS:", 3, 75, 122, 161, false, NULL, "REMOVE", "KEEP");
 589  CGameMenuItemZBool itemNetMonsterSpiders("SPIDERS:", 3, 75, 130, 161, false, NULL, "REMOVE", "KEEP");
 590  CGameMenuItemZBool itemNetMonsterTinyCaleb("TINY CALEBS:", 3, 75, 138, 161, false, NULL, "REMOVE", "KEEP");
 591  CGameMenuItemZBool itemNetMonsterHellHounds("HELL HOUNDS:", 3, 75, 146, 161, false, NULL, "REMOVE", "KEEP");
 592  CGameMenuItemZBool itemNetMonsterRatsAttack("RAT ATTACK DISTANCE:", 3, 75, 162, 161, false, NULL, "SHORTER", "DEFAULT");
 593  CGameMenuItemZBool itemNetMonsterMotherSpiderHealth("MOTHER SPIDER HEALTH:", 3, 75, 170, 161, false, NULL, "HALF", "DEFAULT");
 594  CGameMenuItemZBool itemNetMonsterTchernobogHealth("TCHERNOBOG HEALTH:", 3, 75, 178, 161, false, NULL, "FULL", "DEFAULT");
 595  
 596  ///////////////
 597  CGameMenuItemZBool itemNetMutatorBoolQuadDamagePowerup("REPLACE AKIMBO WITH 4X DAMAGE:", 3, 66, 32, 180, false, NULL, NULL, NULL);
 598  CGameMenuItemZCycle itemNetMutatorDamageInvul("INVULNERABILITY DURATION:", 3, 66, 42, 180, 0, NULL, pzDamageInvulBehaviorStrings, ARRAY_SSIZE(pzDamageInvulBehaviorStrings), 0);
 599  CGameMenuItemZCycle itemNetMutatorProjectileBehavior("PROJECTILES BEHAVIOR:", 3, 66, 52, 180, 0, NULL, pzProjectileBehaviorStrings, ARRAY_SSIZE(pzProjectileBehaviorStrings), 0);
 600  CGameMenuItemZBool itemNetMutatorNapalmFalloff("NAPALM GRAVITY FALLOFF:", 3, 66, 62, 180, false, NULL, NULL, NULL);
 601  CGameMenuItemZCycle itemNetMutatorEnemyBehavior("ENEMY BEHAVIOR:", 3, 66, 72, 180, false, NULL, pzEnemyBehaviorStrings, ARRAY_SSIZE(pzEnemyBehaviorStrings), 0);
 602  CGameMenuItemZBool itemNetMutatorBoolEnemyRandomTNT("RANDOM CULTIST TNT:", 3, 66, 82, 180, false, NULL, NULL, NULL);
 603  CGameMenuItemZCycle itemNetMutatorWeaponsVer("WEAPON BEHAVIOR:", 3, 66, 92, 180, 0, NULL, pzWeaponsVersionStrings, ARRAY_SSIZE(pzWeaponsVersionStrings), 0);
 604  CGameMenuItemZCycle itemNetMutatorAmmoScale("AMMO PICKUP SCALE:", 3, 66, 102, 180, 0, NULL, pzAmmoScaleStrings, ARRAY_SSIZE(pzAmmoScaleStrings), 0);
 605  CGameMenuItemZBool itemNetMutatorSectorBehavior("SECTOR BEHAVIOR:", 3, 66, 112, 180, false, NULL, "NOTBLOOD", "ORIGINAL");
 606  CGameMenuItemZCycle itemNetMutatorHitscanProjectiles("HITSCAN PROJECTILES:", 3, 66, 122, 180, 0, NULL, pzHitscanProjectilesStrings, ARRAY_SSIZE(pzHitscanProjectilesStrings), 0);
 607  CGameMenuItemZCycle itemNetMutatorGoreBehavior("GORE BEHAVIOR:", 3, 66, 132, 180, 0, NULL, pzGoreStrings, ARRAY_SSIZE(pzGoreStrings), 0);
 608  CGameMenuItemZCycle itemNetMutatorPlayerSpeed("PLAYER SPEED:", 3, 66, 142, 180, 0, NULL, pzPlayerSpeeds, ARRAY_SSIZE(pzPlayerSpeeds), 0);
 609  CGameMenuItemZCycle itemNetMutatorRandomizerMode("RANDOMIZER MODE:", 3, 66, 152, 180, 0, NULL, pzRandomizerModeStrings, ARRAY_SSIZE(pzRandomizerModeStrings), 0);
 610  CGameMenuItemZEdit itemNetMutatorRandomizerSeed("RANDOMIZER SEED:", 3, 66, 162, 180, szRandomizerSeedMenu, sizeof(szRandomizerSeedMenu), 0, SetRandomizerSeed, 0);
 611  ///////////////////
 612  
 613  CGameMenuItemText itemLoadingText("LOADING...", 1, 160, 100, 1);
 614  
 615  CGameMenuItemTitle itemQuitTitle("QUIT", 1, 160, 20, 2038);
 616  CGameMenuItemText itemQuitText1("Do you really want to quit?", 0, 160, 100, 1);
 617  CGameMenuItemYesNoQuit itemQuitYesNo("[Y/N]", 0, 20, 110, 280, 1, 0);
 618  
 619  CGameMenuItemTitle itemRestartTitle("RESTART GAME", 1, 160, 20, 2038);
 620  CGameMenuItemText itemRestartText1("Do you really want to restart game?", 0, 160, 100, 1);
 621  CGameMenuItemYesNoQuit itemRestartYesNo("[Y/N]", 0, 20, 110, 280, 1, 1);
 622  
 623  CGameMenuItemPicCycle itemCreditsPicCycle(0, 0, NULL, NULL, 0, 0);
 624  CGameMenuItemPicCycle itemOrderPicCycle(0, 0, NULL, NULL, 0, 0);
 625  
 626  enum resflags_t {
 627      RES_FS = 0x1,
 628      RES_WIN = 0x2,
 629  };
 630  
 631  #define MAXRESOLUTIONSTRINGLENGTH 19
 632  
 633  struct resolution_t {
 634      int32_t xdim, ydim;
 635      int32_t flags;
 636      int32_t bppmax;
 637      char name[MAXRESOLUTIONSTRINGLENGTH];
 638  };
 639  
 640  resolution_t gResolution[MAXVALIDMODES];
 641  int gResolutionNum;
 642  const char *gResolutionName[MAXVALIDMODES];
 643  
 644  CGameMenu menuOptions;
 645  CGameMenu menuOptionsGame;
 646  CGameMenu menuOptionsGameMutators;
 647  CGameMenu menuOptionsDisplay;
 648  CGameMenu menuOptionsDisplayView;
 649  CGameMenu menuOptionsDisplayColor;
 650  CGameMenu menuOptionsDisplayMode;
 651  #ifdef USE_OPENGL
 652  CGameMenu menuOptionsDisplayPolymost;
 653  #endif
 654  CGameMenu menuOptionsSound;
 655  CGameMenu menuOptionsPlayer;
 656  CGameMenu menuOptionsControl;
 657  
 658  void SetupOptionsSound(CGameMenuItemChain *pItem);
 659  void SetupPollJoystick(CGameMenuItemChain *pItem);
 660  
 661  CGameMenuItemTitle itemOptionsTitle("OPTIONS", 1, 160, 20, 2038);
 662  CGameMenuItemChain itemOptionsChainGame("GAME SETUP", 1, 0, 50, 320, 1, &menuOptionsGame, -1, NULL, 0);
 663  CGameMenuItemChain itemOptionsChainDisplay("DISPLAY SETUP", 1, 0, 70, 320, 1, &menuOptionsDisplay, -1, NULL, 0);
 664  CGameMenuItemChain itemOptionsChainSound("SOUND SETUP", 1, 0, 90, 320, 1, &menuOptionsSound, -1, SetupOptionsSound, 0);
 665  CGameMenuItemChain itemOptionsChainPlayer("PLAYER SETUP", 1, 0, 110, 320, 1, &menuOptionsPlayer, -1, NULL, 0);
 666  CGameMenuItemChain itemOptionsChainControl("CONTROL SETUP", 1, 0, 130, 320, 1, &menuOptionsControl, -1, SetupPollJoystick, 0);
 667  CGameMenuItemChain itemOptionsChainMutators("MUTATORS", 1, 0, 150, 320, 1, &menuOptionsGameMutators, -1, NULL, 0);
 668  
 669  const char *pzAutoAimStrings[] = {
 670      "NEVER",
 671      "ALWAYS",
 672      "HITSCAN ONLY",
 673      "HITSCAN RATS/EELS ONLY",
 674      "PITCHFORK ONLY"
 675  };
 676  
 677  const char *pzWeaponSwitchStrings[] = {
 678      "NEVER",
 679      "BY RATING",
 680      "IF NEW",
 681      "IF HOLDING PITCHFORK"
 682  };
 683  
 684  const char *pzAutosaveModeStrings[] = {
 685      "OFF",
 686      "NEW LEVEL",
 687      "KEYS+NEW LEVEL",
 688  };
 689  
 690  const char *pzVanillaModeStrings[] = {
 691      "OFF",
 692      "ON",
 693      "DOS MOUSE+ON",
 694  };
 695  
 696  const char *pzCrosshairStrings[] = {
 697      "OFF",
 698      "ON",
 699      "ON (AUTO AIM)"
 700  };
 701  
 702  const char *pzStatsPowerupRatioStrings[] = {
 703      "OFF",
 704      "ON",
 705      "ON (4:3)",
 706      "ON (16:10)",
 707      "ON (16:9)",
 708      "ON (21:9)",
 709  };
 710  
 711  const char *pzWeaponSelectStrings[] = {
 712      "OFF",
 713      "BOTTOM",
 714      "TOP"
 715  };
 716  
 717  const char *pzHudRatioStrings[] = {
 718      "NATIVE",
 719      "4:3",
 720      "16:10",
 721      "16:9",
 722      "21:9",
 723  };
 724  
 725  const char *pzWeaponHBobbingStrings[] = {
 726      "OFF",
 727      "ORIGINAL",
 728      "V1.0X",
 729  };
 730  
 731  const char *pzWeaponInterpolateStrings[] = {
 732      "OFF",
 733      "ONLY SWAYING",
 734      "ALL ANIMATION"
 735  };
 736  
 737  const char *pzSecretStyleStrings[] = {
 738      "ORIGINAL",
 739      "NOTBLOOD",
 740      "GZDOOM"
 741  };
 742  
 743  void SetAutoAim(CGameMenuItemZCycle *pItem);
 744  void SetAutoAimRange(CGameMenuItemSlider *pItem);
 745  void SetAutoRun(CGameMenuItemZBool *pItem);
 746  void SetLevelStats(CGameMenuItemZCycle *pItem);
 747  void SetLevelStatsOnAutomap(CGameMenuItemZBool *pItem);
 748  void SetPowerupDuration(CGameMenuItemZCycle *pItem);
 749  void SetPowerupStyle(CGameMenuItemZBool *pItem);
 750  void SetSecretStyle(CGameMenuItemZCycle *pItem);
 751  void SetShowMapTitle(CGameMenuItemZBool *pItem);
 752  void SetWeaponSwitch(CGameMenuItemZCycle *pItem);
 753  void SetWeaponFastSwitch(CGameMenuItemZBool *pItem);
 754  void SetAutosaveMode(CGameMenuItemZCycle *pItem);
 755  void SetLockSaving(CGameMenuItemZBool *pItem);
 756  void SetRestoreLastSave(CGameMenuItemZBool *pItem);
 757  void SetVanillaMode(CGameMenuItemZCycle *pItem);
 758  
 759  ///////////////
 760  CGameMenuItemTitle itemGameMutatorsTitle("MUTATORS", 1, 160, 20, 2038);
 761  CGameMenuItemZBool itemMutatorBoolQuadDamagePowerup("REPLACE AKIMBO WITH 4X DAMAGE:", 3, 66, 32, 180, false, SetQuadDamagePowerup, NULL, NULL);
 762  CGameMenuItemZCycle itemMutatorDamageInvul("INVULNERABILITY DURATION:", 3, 66, 42, 180, 0, SetDamageInvul, pzDamageInvulBehaviorStrings, ARRAY_SSIZE(pzDamageInvulBehaviorStrings), 0);
 763  CGameMenuItemZCycle itemMutatorProjectileBehavior("PROJECTILES BEHAVIOR:", 3, 66, 52, 180, 0, SetProjectileBehavior, pzProjectileBehaviorStrings, ARRAY_SSIZE(pzProjectileBehaviorStrings), 0);
 764  CGameMenuItemZBool itemMutatorNapalmFalloff("NAPALM GRAVITY FALLOFF:", 3, 66, 62, 180, false, SetNapalmFalloff, NULL, NULL);
 765  CGameMenuItemZCycle itemMutatorEnemyBehavior("ENEMY BEHAVIOR:", 3, 66, 72, 180, 0, SetEnemyBehavior, pzEnemyBehaviorStrings, ARRAY_SSIZE(pzEnemyBehaviorStrings), 0);
 766  CGameMenuItemZBool itemMutatorBoolEnemyRandomTNT("RANDOM CULTIST TNT:", 3, 66, 82, 180, false, SetEnemyRandomTNT, NULL, NULL);
 767  CGameMenuItemZCycle itemMutatorWeaponsVer("WEAPON BEHAVIOR:", 3, 66, 92, 180, 0, SetWeaponsVer, pzWeaponsVersionStrings, ARRAY_SSIZE(pzWeaponsVersionStrings), 0);
 768  CGameMenuItemZCycle itemMutatorAmmoScale("AMMO PICKUP SCALE:", 3, 66, 102, 180, 0, SetAmmoScale, pzAmmoScaleStrings, ARRAY_SSIZE(pzAmmoScaleStrings), 0);
 769  CGameMenuItemZBool itemMutatorSectorBehavior("SECTOR BEHAVIOR:", 3, 66, 112, 180, false, SetSectorBehavior, "NOTBLOOD", "ORIGINAL");
 770  CGameMenuItemZCycle itemMutatorHitscanProjectiles("HITSCAN PROJECTILES:", 3, 66, 122, 180, 0, SetHitscanProjectiles, pzHitscanProjectilesStrings, ARRAY_SSIZE(pzHitscanProjectilesStrings), 0);
 771  CGameMenuItemZCycle itemMutatorGoreBehavior("GORE BEHAVIOR:", 3, 66, 132, 180, 0, SetGoreMode, pzGoreStrings, ARRAY_SSIZE(pzGoreStrings), 0);
 772  CGameMenuItemZCycle itemMutatorPlayerSpeed("PLAYER SPEED:", 3, 66, 142, 180, 0, SetPlayerSpeed, pzPlayerSpeeds, ARRAY_SSIZE(pzPlayerSpeeds), 0);
 773  CGameMenuItemZCycle itemMutatorRandomizerMode("RANDOMIZER MODE:", 3, 66, 152, 180, 0, SetRandomizerMode, pzRandomizerModeStrings, ARRAY_SSIZE(pzRandomizerModeStrings), 0);
 774  CGameMenuItemZEdit itemMutatorRandomizerSeed("RANDOMIZER SEED:", 3, 66, 162, 180, szRandomizerSeedMenu, sizeof(szRandomizerSeedMenu), 0, SetRandomizerSeed, 0);
 775  ///////////////////
 776  
 777  CGameMenuItemTitle itemOptionsGameTitle("GAME SETUP", 1, 160, 20, 2038);
 778  CGameMenuItemZCycle itemOptionsGameCycleAutoAim("AUTO AIM:", 3, 66, 60, 180, 0, SetAutoAim, pzAutoAimStrings, ARRAY_SSIZE(pzAutoAimStrings), 0);
 779  CGameMenuItemSlider itemOptionsGameSliderAutoAimRange("AUTO AIM RANGE:", 3, 66, 70, 180, &gAutoAimRange, 0, 9, 1, SetAutoAimRange, -1, -1, kMenuSliderPercent, 1, 2);
 780  CGameMenuItemZBool itemOptionsGameBoolAutoRun("AUTO RUN:", 3, 66, 80, 180, 0, SetAutoRun, NULL, NULL);
 781  CGameMenuItemZCycle itemOptionsGameWeaponSwitch("EQUIP PICKUPS:", 3, 66, 90, 180, 0, SetWeaponSwitch, pzWeaponSwitchStrings, ARRAY_SSIZE(pzWeaponSwitchStrings), 0);
 782  CGameMenuItemZBool itemOptionsGameWeaponFastSwitch("FAST WEAPON SWITCH:", 3, 66, 100, 180, 0, SetWeaponFastSwitch, NULL, NULL);
 783  CGameMenuItemZCycle itemOptionsGameAutosaveMode("AUTOSAVE TRIGGER:", 3, 66, 120, 180, 0, SetAutosaveMode, pzAutosaveModeStrings, ARRAY_SSIZE(pzAutosaveModeStrings), 0);
 784  CGameMenuItemZBool itemOptionsGameLockSaving("LOCK MANUAL SAVING:", 3, 66, 130, 180, 0, SetLockSaving, "AUTOSAVES ONLY", "NEVER");
 785  CGameMenuItemZBool itemOptionsGameRestoreLastSave("ASK TO RESTORE LAST SAVE:", 3, 66, 140, 180, 0, SetRestoreLastSave, NULL, NULL);
 786  CGameMenuItemZCycle itemOptionsGameBoolVanillaMode("VANILLA MODE:", 3, 66, 150, 180, 0, SetVanillaMode, pzVanillaModeStrings, ARRAY_SSIZE(pzVanillaModeStrings), 0);
 787  
 788  CGameMenuItemTitle itemOptionsDisplayTitle("DISPLAY SETUP", 1, 160, 20, 2038);
 789  CGameMenuItemChain itemOptionsDisplayColor("COLOR CORRECTION", 3, 66, 40, 180, 0, &menuOptionsDisplayColor, -1, NULL, 0);
 790  CGameMenuItemChain itemOptionsDisplayMode("VIDEO MODE", 3, 66, 50, 180, 0, &menuOptionsDisplayMode, -1, SetupVideoModeMenu, 0);
 791  CGameMenuItemChain itemOptionsDisplayView("VIEW SETUP", 3, 66, 60, 180, 0, &menuOptionsDisplayView, -1, NULL, 0);
 792  CGameMenuItemSlider itemOptionsDisplaySliderDetail("DETAIL:", 3, 66, 80, 180, &gDetail, 0, 4, 1, SetDetail, -1, -1);
 793  CGameMenuItemZBool itemOptionsDisplayBoolVoxels("VOXELS:", 3, 66, 90, 180, 0, SetVoxels, NULL, NULL);
 794  CGameMenuItemZCycle itemOptionsDisplayCrosshair("CROSSHAIR:", 3, 66, 100, 180, 0, SetCrosshair, pzCrosshairStrings, ARRAY_SSIZE(pzCrosshairStrings), 0);
 795  CGameMenuItemZCycle itemOptionsDisplayLevelStats("LEVEL STATS:", 3, 66, 110, 180, 0, SetLevelStats, pzStatsPowerupRatioStrings, ARRAY_SSIZE(pzStatsPowerupRatioStrings), 0);
 796  CGameMenuItemZBool itemOptionsDisplayLevelStatsOnAutomap("LEVEL STATS ON AUTOMAP ONLY:", 3, 66, 120, 180, gLevelStatsOnlyOnMap, SetLevelStatsOnAutomap, NULL, NULL);
 797  CGameMenuItemZCycle itemOptionsDisplayPowerupDuration("POWERUP DURATION:", 3, 66, 130, 180, 0, SetPowerupDuration, pzStatsPowerupRatioStrings, ARRAY_SSIZE(pzStatsPowerupRatioStrings), 0);
 798  CGameMenuItemZBool itemOptionsDisplayBoolShowMapTitle("MAP TITLE:", 3, 66, 140, 180, gShowMapTitle, SetShowMapTitle, NULL, NULL);
 799  CGameMenuItemZBool itemOptionsDisplayBoolMessages("MESSAGES:", 3, 66, 150, 180, gMessageState, SetMessages, NULL, NULL);
 800  CGameMenuItemZBool itemOptionsDisplayBoolWidescreen("WIDESCREEN:", 3, 66, 160, 180, r_usenewaspect, SetWidescreen, NULL, NULL);
 801  CGameMenuItemZCycle itemOptionsDisplayWeaponSelect("SHOW WEAPON SELECT:", 3, 66, 170, 180, 0, SetWeaponSelectMode, pzWeaponSelectStrings, ARRAY_SSIZE(pzWeaponSelectStrings), 0);
 802  CGameMenuItemSlider itemOptionsDisplayFOV("FOV:", 3, 66, 180, 180, &gFov, 75, 140, 1, SetFOV, -1, -1, kMenuSliderValue);
 803  
 804  const char *pzRendererStrings[] = {
 805      "CLASSIC",
 806      "POLYMOST"
 807  };
 808  
 809  const int nRendererValues[] = {
 810      REND_CLASSIC,
 811      REND_POLYMOST
 812  };
 813  
 814  const char *pzVSyncStrings[] = {
 815      "ADAPTIVE",
 816      "OFF",
 817      "ON",
 818  #if defined USE_OPENGL && defined _WIN32 && defined RENDERTYPESDL
 819      "KMT"
 820  #endif
 821  };
 822  
 823  const int nVSyncValues[] = {
 824      -1,
 825      0,
 826      1,
 827  #if defined USE_OPENGL && defined _WIN32 && defined RENDERTYPESDL
 828      2
 829  #endif
 830  };
 831  
 832  const char *pzFrameLimitStrings[] = {
 833      "30 FPS",
 834      "60 FPS",
 835      "75 FPS",
 836      "100 FPS",
 837      "120 FPS",
 838      "144 FPS",
 839      "165 FPS",
 840      "240 FPS"
 841  };
 842  
 843  const int nFrameLimitValues[] = {
 844      30,
 845      60,
 846      75,
 847      100,
 848      120,
 849      144,
 850      165,
 851      240
 852  };
 853  
 854  const char *pzInvertPaletteStrings[] = {
 855      "OFF",
 856      "ON",
 857      "INVERT TWICE",
 858  };
 859  
 860  
 861  void PreDrawVideoModeMenu(CGameMenuItem *);
 862  
 863  CGameMenuItemTitle itemOptionsDisplayModeTitle("VIDEO MODE", 1, 160, 20, 2038);
 864  CGameMenuItemZCycle itemOptionsDisplayModeResolution("RESOLUTION:", 3, 66, 60, 180, 0, NULL, NULL, 0, 0, true);
 865  CGameMenuItemZCycle itemOptionsDisplayModeRenderer("RENDERER:", 3, 66, 70, 180, 0, NULL, pzRendererStrings, 2, 0);
 866  #ifdef USE_OPENGL
 867  CGameMenuItemChain itemOptionsDisplayModePolymost("POLYMOST SETUP", 3, 66, 80, 180, 0, &menuOptionsDisplayPolymost, -1, SetupVideoPolymostMenu, 0);
 868  #endif
 869  CGameMenuItemZBool itemOptionsDisplayModeFullscreen("FULLSCREEN:", 3, 66, 90, 180, 0, NULL, NULL, NULL);
 870  CGameMenuItemZCycle itemOptionsDisplayModeVSync("VSYNC:", 3, 66, 100, 180, 0, NULL, pzVSyncStrings, ARRAY_SSIZE(pzVSyncStrings), 0);
 871  CGameMenuItemZCycle itemOptionsDisplayModeFrameLimit("FRAMERATE LIMIT:", 3, 66, 110, 180, 0, UpdateVideoModeMenuFrameLimit, pzFrameLimitStrings, 8, 0);
 872  CGameMenuItemChain itemOptionsDisplayModeApply("APPLY CHANGES", 3, 66, 125, 180, 0, NULL, 0, SetVideoMode, 0);
 873  
 874  void PreDrawDisplayColor(CGameMenuItem *);
 875  
 876  CGameMenuItemTitle itemOptionsDisplayColorTitle("COLOR CORRECTION", 1, 160, 20, -1);
 877  CGameMenuItemZCycle itemOptionsDisplayColorPaletteCustom("PALETTE:", 3, 66, 60, 180, 0, UpdateVideoPaletteCycleMenu, srcCustomPaletteStr, ARRAY_SSIZE(srcCustomPaletteStr), 0);
 878  CGameMenuItemZBool itemOptionsDisplayColorPaletteCIEDE2000("CIEDE2000 COMPARE:", 3, 66, 70, 180, 0, UpdateVideoPaletteBoolMenu, NULL, NULL);
 879  CGameMenuItemZBool itemOptionsDisplayColorPaletteGrayscale("GRAYSCALE PALETTE:", 3, 66, 80, 180, 0, UpdateVideoPaletteBoolMenu, NULL, NULL);
 880  CGameMenuItemZCycle itemOptionsDisplayColorPaletteInvert("INVERT PALETTE:", 3, 66, 90, 180, 0, UpdateVideoPaletteCycleMenu, pzInvertPaletteStrings, ARRAY_SSIZE(pzInvertPaletteStrings), 0);
 881  CGameMenuItemSliderFloat itemOptionsDisplayColorGamma("GAMMA:", 3, 66, 100, 180, &g_videoGamma, MIN_GAMMA, MAX_GAMMA, 0.1f, UpdateVideoColorMenu, -1, -1, kMenuSliderValue);
 882  CGameMenuItemSliderFloat itemOptionsDisplayColorContrast("CONTRAST:", 3, 66, 110, 180, &g_videoContrast, MIN_CONTRAST, MAX_CONTRAST, 0.05f, UpdateVideoColorMenu, -1, -1, kMenuSliderValue);
 883  CGameMenuItemSliderFloat itemOptionsDisplayColorSaturation("SATURATION:", 3, 66, 120, 180, &g_videoSaturation, MIN_SATURATION, MAX_SATURATION, 0.05f, UpdateVideoColorMenu, -1, -1, kMenuSliderValue);
 884  CGameMenuItemSliderFloat itemOptionsDisplayColorVisibility("VISIBILITY:", 3, 66, 130, 180, &r_ambientlight, 0.125f, 4.f, 0.125f, UpdateVideoColorMenu, -1, -1, kMenuSliderValue);
 885  CGameMenuItemChain itemOptionsDisplayColorReset("RESET TO DEFAULTS", 3, 66, 150, 180, 0, NULL, 0, ResetVideoColor, 0);
 886  
 887  CGameMenuItemTitle itemOptionsDisplayViewTitle("VIEW SETUP", 1, 160, 20, 2038);
 888  CGameMenuItemSlider itemOptionsDisplayViewHudSize("HUD SIZE:", 3, 66, 40, 180, &gViewSize, 0, 9, 1, SetHudSize, -1, -1, kMenuSliderValue);
 889  CGameMenuItemZCycle itemOptionsDisplayViewHudRatio("HUD ALIGNMENT:", 3, 66, 50, 180, 0, SetHudRatio, pzHudRatioStrings, ARRAY_SSIZE(pzHudRatioStrings), 0);
 890  CGameMenuItemZBool itemOptionsDisplayViewBoolCenterHoriz("CENTER HORIZON LINE:", 3, 66, 60, 180, gCenterHoriz, SetCenterHoriz, NULL, NULL);
 891  CGameMenuItemZBool itemOptionsDisplayViewBoolSlopeTilting("SLOPE TILTING:", 3, 66, 70, 180, gSlopeTilting, SetSlopeTilting, NULL, NULL);
 892  CGameMenuItemZBool itemOptionsDisplayViewBoolViewBobbing("VIEW BOBBING:", 3, 66, 80, 180, gViewVBobbing, SetViewBobbing, NULL, NULL);
 893  CGameMenuItemZBool itemOptionsDisplayViewBoolViewSwaying("VIEW SWAYING:", 3, 66, 90, 180, gViewHBobbing, SetViewSwaying, NULL, NULL);
 894  CGameMenuItemZCycle itemOptionsDisplayViewWeaponSwaying("WEAPON SWAYING:", 3, 66, 100, 180, 0, SetWeaponSwaying, pzWeaponHBobbingStrings, ARRAY_SSIZE(pzWeaponHBobbingStrings), 0);
 895  CGameMenuItemZCycle itemOptionsDisplayViewWeaponInterpolation("WEAPON SMOOTHING:", 3, 66, 110, 180, 0, SetWeaponInterpolate, pzWeaponInterpolateStrings, ARRAY_SSIZE(pzWeaponInterpolateStrings), 0);
 896  CGameMenuItemZBool itemOptionsDisplayViewBoolInterpolation("VIEW INTERPOLATE:", 3, 66, 120, 180, gViewInterpolateMethod, SetViewInterpolate, "MODERN", "ORIGINAL");
 897  CGameMenuItemZBool itemOptionsDisplayViewBoolLevelCompleteTime("LEVEL TIME AT INTERMISSION:", 3, 66, 130, 180, gShowCompleteTime, SetLevelCompleteTime, "SHOW", "HIDE");
 898  CGameMenuItemZBool itemOptionsDisplayViewBoolPowerupStyle("POWERUP STYLE:", 3, 66, 140, 180, gPowerupStyle, SetPowerupStyle, "NOTBLOOD", "NBLOOD");
 899  CGameMenuItemZCycle itemOptionsDisplayViewSecretMessageStyle("SECRET MESSAGE STYLE:", 3, 66, 150, 180, 0, SetSecretStyle, pzSecretStyleStrings, ARRAY_SSIZE(pzSecretStyleStrings), 0);
 900  CGameMenuItemZCycle itemOptionsDisplayViewMirrorMode("MIRROR MODE:", 3, 66, 160, 180, 0, SetMirrorMode, pzMirrorModeStrings, ARRAY_SSIZE(pzMirrorModeStrings), 0);
 901  CGameMenuItemZBool itemOptionsDisplayViewBoolSlowRoomFlicker("SLOW FLICKERING LIGHTS:", 3, 66, 170, 180, gSlowRoomFlicker, SetSlowRoomFlicker, NULL, NULL);
 902  
 903  #ifdef USE_OPENGL
 904  const char *pzTextureModeStrings[] = {
 905      "CLASSIC",
 906      "FILTERED"
 907  };
 908  
 909  int nTextureModeValues[] = {
 910      TEXFILTER_OFF,
 911      TEXFILTER_ON
 912  };
 913  #endif
 914  
 915  const char *pzAnisotropyStrings[] = {
 916      "MAX",
 917      "NONE",
 918      "2X",
 919      "4X",
 920      "8X",
 921      "16X"
 922  };
 923  
 924  int nAnisotropyValues[] = {
 925      0,
 926      1,
 927      2,
 928      4,
 929      8,
 930      16
 931  };
 932  
 933  const char *pzTexQualityStrings[] = {
 934      "FULL",
 935      "HALF",
 936      "BARF"
 937  };
 938  
 939  const char *pzTexCacheStrings[] = {
 940      "OFF",
 941      "ON",
 942      "COMPRESSED"
 943  };
 944  
 945  void UpdateTextureMode(CGameMenuItemZCycle *pItem);
 946  void UpdateAnisotropy(CGameMenuItemZCycle *pItem);
 947  void UpdateTrueColorTextures(CGameMenuItemZBool *pItem);
 948  void UpdateTexQuality(CGameMenuItemZCycle *pItem);
 949  void UpdatePreloadCache(CGameMenuItemZBool *pItem);
 950  void UpdateTexCache(CGameMenuItemZCycle *pItem);
 951  void UpdateDetailTex(CGameMenuItemZBool *pItem);
 952  void UpdateGlowTex(CGameMenuItemZBool *pItem);
 953  void Update3DModels(CGameMenuItemZBool *pItem);
 954  void UpdateDeliriumBlur(CGameMenuItemZBool *pItem);
 955  void UpdateTexColorIndex(CGameMenuItemZBool *pItem);
 956  void UpdateShadeInterpolation(CGameMenuItemZBool *pItem);
 957  void UpdateYShrearing(CGameMenuItemZBool *pItem);
 958  void UpdateRollAngle(CGameMenuItemSlider *pItem);
 959  #ifdef USE_OPENGL
 960  void PreDrawDisplayPolymost(CGameMenuItem *pItem);
 961  CGameMenuItemTitle itemOptionsDisplayPolymostTitle("POLYMOST SETUP", 1, 160, 20, 2038);
 962  CGameMenuItemZCycle itemOptionsDisplayPolymostTextureMode("TEXTURE MODE:", 3, 66, 40, 180, 0, UpdateTextureMode, pzTextureModeStrings, 2, 0);
 963  CGameMenuItemZCycle itemOptionsDisplayPolymostAnisotropy("ANISOTROPY:", 3, 66, 50, 180, 0, UpdateAnisotropy, pzAnisotropyStrings, 6, 0);
 964  CGameMenuItemZBool itemOptionsDisplayPolymostTrueColorTextures("TRUE COLOR TEXTURES:", 3, 66, 60, 180, 0, UpdateTrueColorTextures, NULL, NULL);
 965  CGameMenuItemZCycle itemOptionsDisplayPolymostTexQuality("GL TEXTURE QUALITY:", 3, 66, 70, 180, 0, UpdateTexQuality, pzTexQualityStrings, 3, 0);
 966  CGameMenuItemZBool itemOptionsDisplayPolymostPreloadCache("PRE-LOAD MAP TEXTURES:", 3, 66, 80, 180, 0, UpdatePreloadCache, NULL, NULL);
 967  CGameMenuItemZCycle itemOptionsDisplayPolymostTexCache("ON-DISK TEXTURE CACHE:", 3, 66, 90, 180, 0, UpdateTexCache, pzTexCacheStrings, 3, 0);
 968  CGameMenuItemZBool itemOptionsDisplayPolymostDetailTex("DETAIL TEXTURES:", 3, 66, 100, 180, 0, UpdateDetailTex, NULL, NULL);
 969  CGameMenuItemZBool itemOptionsDisplayPolymostGlowTex("GLOW TEXTURES:", 3, 66, 110, 180, 0, UpdateGlowTex, NULL, NULL);
 970  CGameMenuItemZBool itemOptionsDisplayPolymost3DModels("3D MODELS:", 3, 66, 120, 180, 0, Update3DModels, NULL, NULL);
 971  CGameMenuItemZBool itemOptionsDisplayPolymostDeliriumBlur("DELIRIUM EFFECT BLUR:", 3, 66, 130, 180, 0, UpdateDeliriumBlur, NULL, NULL);
 972  CGameMenuItemZBool itemOptionsDisplayPolymostUseColorIndexedTex("PALETTE EMULATON:", 3, 66, 140, 180, 0, UpdateTexColorIndex, NULL, NULL);
 973  CGameMenuItemZBool itemOptionsDisplayPolymostShadeInterpolation("PALETTE INTERPOLATION:", 3, 66, 150, 180, 0, UpdateShadeInterpolation, NULL, NULL);
 974  CGameMenuItemZBool itemOptionsDisplayPolymostYShearing("Y-SHEARING:", 3, 66, 160, 180, 0, UpdateYShrearing, NULL, NULL);
 975  CGameMenuItemSlider itemOptionsDisplayPolymostRollAngle("VIEW ROLLING:", 3, 66, 170, 180, &gRollAngle, -5, 5, 1, UpdateRollAngle, -1, -1, kMenuSliderValue);
 976  #endif
 977  
 978  void UpdateSoundToggle(CGameMenuItemZBool *pItem);
 979  void UpdateMusicToggle(CGameMenuItemZBool *pItem);
 980  void UpdateCDToggle(CGameMenuItemZBool *pItem);
 981  void SetDoppler(CGameMenuItemZBool *pItem);
 982  void UpdateSoundVolume(CGameMenuItemSlider *pItem);
 983  void UpdateMusicVolume(CGameMenuItemSlider *pItem);
 984  void UpdateSoundRate(CGameMenuItemZCycle *pItem);
 985  void UpdateNumVoices(CGameMenuItemSlider *pItem);
 986  void UpdateSpeakerAngle(CGameMenuItemSlider *pItem);
 987  void UpdateCalebTalk(CGameMenuItemZCycle *pItem);
 988  void UpdateMusicDevice(CGameMenuItemZCycle *pItem);
 989  void SetSound(CGameMenuItemChain *pItem);
 990  void PreDrawSound(CGameMenuItem *pItem);
 991  const char *pzSoundRateStrings[] = {
 992      "22050HZ",
 993      "44100HZ",
 994      "48000HZ"
 995  };
 996  
 997  int nSoundRateValues[] = {
 998      22050,
 999      44100,
1000      48000
1001  };
1002  
1003  const char *pzCalebTalkStrings[] = {
1004      "ON",
1005      "NO IDLE TALK",
1006      "NO GIB TALK",
1007      "OFF",
1008  };
1009  
1010  int nMusicDeviceValues[] = {
1011      ASS_OPL3,
1012  #ifdef _WIN32
1013      ASS_WinMM,
1014  #endif
1015      ASS_SF2,
1016  };
1017  
1018  const char *pzMusicDeviceStrings[] = {
1019      "OPL3(SB/ADLIB)",
1020  #ifdef _WIN32
1021      "SYSTEM MIDI",
1022  #endif
1023      ".SF2 SYNTH",
1024  };
1025  static char sf2bankfile[BMAX_PATH];
1026  
1027  CGameMenu menuOptionsSoundSF2;
1028  
1029  CGameMenuItemTitle itemOptionsSoundSF2Title("SELECT SF2 BANK", 1, 160, 20, 2038);
1030  CGameMenuFileSelect itemOptionsSoundSF2FS("", 3, 0, 0, 0, "./", "*.sf2", sf2bankfile);
1031  
1032  CGameMenuItemTitle itemOptionsSoundTitle("SOUND SETUP", 1, 160, 20, 2038);
1033  CGameMenuItemZBool itemOptionsSoundSoundToggle("SOUND:", 3, 66, 40, 180, false, UpdateSoundToggle, NULL, NULL);
1034  CGameMenuItemZBool itemOptionsSoundMusicToggle("MUSIC:", 3, 66, 50, 180, false, UpdateMusicToggle, NULL, NULL);
1035  CGameMenuItemZBool itemOptionsSoundMonoStereo("STEREO AUDIO:", 3, 66, 60, 180, false, SetMonoStereo, NULL, NULL);
1036  CGameMenuItemZBool itemOptionsSoundDoppler("DOPPLER EFFECT:", 3, 66, 70, 180, false, SetDoppler, NULL, NULL);
1037  CGameMenuItemSlider itemOptionsSoundSoundVolume("SOUND VOLUME:", 3, 66, 80, 180, &FXVolume, 0, 255, 17, UpdateSoundVolume, -1, -1, kMenuSliderPercent);
1038  CGameMenuItemSlider itemOptionsSoundMusicVolume("MUSIC VOLUME:", 3, 66, 90, 180, &MusicVolume, 0, 255, 17, UpdateMusicVolume, -1, -1, kMenuSliderPercent);
1039  CGameMenuItemZCycle itemOptionsSoundSampleRate("SAMPLE RATE:", 3, 66, 100, 180, 0, UpdateSoundRate, pzSoundRateStrings, ARRAY_SIZE(pzSoundRateStrings), 0);
1040  CGameMenuItemSlider itemOptionsSoundNumVoices("VOICES:", 3, 66, 110, 180, NumVoices, 16, 255, 16, UpdateNumVoices, -1, -1, kMenuSliderValue);
1041  CGameMenuItemSlider itemOptionsSoundSpeakerAngle("SPEAKER ANGLE:", 3, 66, 120, 180, &gSoundEarAng, 15, 90, 5, UpdateSpeakerAngle, -1, -1, kMenuSliderValue);
1042  CGameMenuItemZCycle itemOptionsSoundCalebTalk("CALEB TALK:", 3, 66, 130, 180, 0, UpdateCalebTalk, pzCalebTalkStrings, ARRAY_SIZE(pzCalebTalkStrings), 0);
1043  CGameMenuItemZBool itemOptionsSoundCDToggle("REDBOOK AUDIO:", 3, 66, 140, 180, false, UpdateCDToggle, NULL, NULL);
1044  CGameMenuItemZCycle itemOptionsSoundMusicDevice("MIDI DRIVER:", 3, 66, 150, 180, 0, UpdateMusicDevice, pzMusicDeviceStrings, ARRAY_SIZE(pzMusicDeviceStrings), 0);
1045  CGameMenuItemChain itemOptionsSoundSF2Bank("SF2 BANK", 3, 66, 160, 180, 0, &menuOptionsSoundSF2, 0, NULL, 0);
1046  CGameMenuItemChain itemOptionsSoundApplyChanges("APPLY CHANGES", 3, 66, 170, 180, 0, NULL, 0, SetSound, 0);
1047  
1048  
1049  void UpdatePlayerName(CGameMenuItemZEdit *pItem, CGameMenuEvent *pEvent);
1050  void UpdatePlayerSkill(CGameMenuItemZCycle *pItem);
1051  void UpdatePlayerTeamPreference(CGameMenuItemZCycle *pItem);
1052  void UpdatePlayerColorPreference(CGameMenuItemZCycle *pItem);
1053  void UpdatePlayerModel(CGameMenuItemZBool *pItem);
1054  void SetShowPlayerNames(CGameMenuItemZBool *);
1055  void SetShowWeapons(CGameMenuItemZCycle *);
1056  void UpdateTeamsScoreDisplay(CGameMenuItemZBool *pItem);
1057  void UpdatePlayerChatMessageSound(CGameMenuItemZBool *pItem);
1058  void UpdatePlayerColorMessages(CGameMenuItemZBool *pItem);
1059  void UpdatePlayerKillObituaryMessages(CGameMenuItemZBool *pItem);
1060  void UpdatePlayerKillMessage(CGameMenuItemZBool *pItem);
1061  void UpdatePlayerMultiKill(CGameMenuItemZCycle *pItem);
1062  
1063  const char *pzPlayerMultiKillStrings[] = {
1064      "OFF",
1065      "ON",
1066      "SFX+ON",
1067  };
1068  
1069  const char *pzPlayerSkillStrings[] = {
1070      "-2",
1071      "-1",
1072      "DEFAULT",
1073      "+1",
1074      "+2",
1075  };
1076  
1077  const char *pzPlayerTeamPreferenceStrings[] = {
1078      "NONE",
1079      "BLUE",
1080      "RED"
1081  };
1082  
1083  
1084  const char *pzPlayerColorPreferenceStrings[] = {
1085      "NONE",
1086      "BLUE",
1087      "RED",
1088      "TEAL",
1089      "GRAY",
1090      "YELLOW",
1091      "BROWN",
1092      "COPPER",
1093  };
1094  
1095  const char *pzShowWeaponStrings[] = {
1096      "OFF",
1097      "SPRITE",
1098      "VOXEL"
1099  };
1100  
1101  CGameMenuItemTitle itemOptionsPlayerTitle("PLAYER SETUP", 1, 160, 20, 2038);
1102  CGameMenuItemZEdit itemOptionsPlayerName("PLAYER NAME:", 3, 66, 35, 180, szPlayerName, MAXPLAYERNAME, 0, UpdatePlayerName, 0);
1103  CGameMenuItemZCycle itemOptionsPlayerSkill("HEALTH HANDICAP:", 3, 66, 45, 180, 0, UpdatePlayerSkill, pzPlayerSkillStrings, ARRAY_SIZE(pzPlayerSkillStrings), 0);
1104  CGameMenuItemZCycle itemOptionsPlayerTeamPreference("TEAM PREFERENCE:", 3, 66, 55, 180, 0, UpdatePlayerTeamPreference, pzPlayerTeamPreferenceStrings, ARRAY_SIZE(pzPlayerTeamPreferenceStrings), 0);
1105  CGameMenuItemZCycle itemOptionsPlayerColorPreference("COLOR PREFERENCE:", 3, 66, 65, 180, 0, UpdatePlayerColorPreference, pzPlayerColorPreferenceStrings, ARRAY_SIZE(pzPlayerColorPreferenceStrings), 0);
1106  CGameMenuItemZBool itemOptionsPlayerModel("PLAYER MODEL:", 3, 66, 75, 180, false, UpdatePlayerModel, "CULTIST", "CALEB");
1107  CGameMenuItemZBool itemOptionsPlayerBoolShowPlayerNames("SHOW PLAYER NAMES:", 3, 66, 90, 180, gShowPlayerNames, SetShowPlayerNames, NULL, NULL);
1108  CGameMenuItemZCycle itemOptionsPlayerShowWeapons("SHOW WEAPONS:", 3, 66, 100, 180, 0, SetShowWeapons, pzShowWeaponStrings, ARRAY_SSIZE(pzShowWeaponStrings), 0);
1109  CGameMenuItemZBool itemOptionsPlayerTeamsScoreStyle("TEAMS SCORE STYLE:", 3, 66, 110, 180, true, UpdateTeamsScoreDisplay, "NBLOOD", "ORIGINAL");
1110  CGameMenuItemZBool itemOptionsPlayerChatSound("MESSAGE BEEP:", 3, 66, 120, 180, true, UpdatePlayerChatMessageSound, NULL, NULL);
1111  CGameMenuItemZBool itemOptionsPlayerColorMsg("COLORED MESSAGES:", 3, 66, 130, 180, true, UpdatePlayerColorMessages, NULL, NULL);
1112  CGameMenuItemZBool itemOptionsPlayerObituaryMsg("USE OBITUARY MESSAGES:", 3, 66, 140, 180, true, UpdatePlayerKillObituaryMessages, NULL, NULL);
1113  CGameMenuItemZBool itemOptionsPlayerKillMsg("SHOW KILLS ON HUD:", 3, 66, 150, 180, true, UpdatePlayerKillMessage, NULL, NULL);
1114  CGameMenuItemZCycle itemOptionsPlayerMultiKill("MULTI KILL MESSAGES:", 3, 66, 160, 180, 0, UpdatePlayerMultiKill, pzPlayerMultiKillStrings, ARRAY_SIZE(pzPlayerMultiKillStrings), 0);
1115  
1116  #define JOYSTICKITEMSPERPAGE 16 // this must be an even value, as double tap inputs rely on odd index position
1117  #define MAXJOYSTICKBUTTONPAGES (max(1, (MAXJOYBUTTONSANDHATS*2 / JOYSTICKITEMSPERPAGE))) // we double all buttons/hats so each input can be bind for double tap
1118  
1119  CGameMenu menuOptionsControlKeyboard;
1120  CGameMenu menuKeys;
1121  CGameMenu menuOptionsControlMouse;
1122  CGameMenu menuOptionsControlMouseButtonAssignment;
1123  CGameMenu menuOptionsControlRadial;
1124  CGameMenu menuOptionsControlJoystickButtonAssignment[MAXJOYSTICKBUTTONPAGES];
1125  CGameMenu menuOptionsControlJoystickListAxes; // contains list of editable joystick axes
1126  CGameMenu menuOptionsControlJoystickAxis[MAXJOYAXES]; // options menu for each joystick axis
1127  CGameMenu menuOptionsControlJoystickMisc;
1128  
1129  void SetupMouseMenu(CGameMenuItemChain *pItem);
1130  void SetupJoystickButtonsMenu(CGameMenuItemChain *pItem);
1131  void SetupJoystickAxesMenu(CGameMenuItemChain *pItem);
1132  void SetupJoystickAxisHeatmap(CGameMenuItemChain *pItem);
1133  void SetJoystickScale(CGameMenuItemSlider* pItem);
1134  void SetJoystickAnalogue(CGameMenuItemZCycle* pItem);
1135  void SetJoystickAnalogueInvert(CGameMenuItemZBool* pItem);
1136  void SetJoystickDigitalPos(CGameMenuItemZCycle* pItem);
1137  void SetJoystickDigitalNeg(CGameMenuItemZCycle* pItem);
1138  void SetJoystickDeadzone(CGameMenuItemSlider* pItem);
1139  void SetJoystickSaturate(CGameMenuItemSlider* pItem);
1140  void SetJoystickSnapZone(CGameMenuItemSlider* pItem);
1141  
1142  const char *pzTurnAccelerationStrings[] = {
1143      "OFF",
1144      "ON RUNNING",
1145      "ALWAYS ON",
1146  };
1147  
1148  const char *zRadialMenuToggle[] =
1149  {
1150      "Button Held",
1151      "Button Toggle",
1152      "Weapon Switch",
1153  };
1154  
1155  const char *pzSoundClickStrings[] =
1156  {
1157      "OFF",
1158      "SHARP",
1159      "MEDIUM",
1160      "SOFT",
1161  };
1162  
1163  const char *zRadialMenuAxes[] =
1164  {
1165      "Strafing",
1166      "Moving",
1167      "Turning",
1168      "Look Up/Down",
1169  };
1170  
1171  CGameMenuItemTitle itemOptionsControlTitle("CONTROL SETUP", 1, 160, 20, 2038);
1172  CGameMenuItemChain itemOptionsControlKeyboard("KEYBOARD SETUP", 1, 0, 50, 320, 1, &menuOptionsControlKeyboard, -1, NULL, 0);
1173  CGameMenuItemChain itemOptionsControlMouse("MOUSE SETUP", 1, 0, 70, 320, 1, &menuOptionsControlMouse, -1, SetupMouseMenu, 0);
1174  CGameMenuItemChain itemOptionsControlRadial("RADIAL MENU SETUP", 1, 0, 90, 320, 1, &menuOptionsControlRadial, -1, NULL, 0);
1175  CGameMenuItemChain itemOptionsControlJoystickButtons("JOYSTICK BUTTONS SETUP", 1, 0, 130, 320, 1, &menuOptionsControlJoystickButtonAssignment[0], -1, SetupJoystickButtonsMenu, 0);
1176  CGameMenuItemChain itemOptionsControlJoystickAxes("JOYSTICK AXES SETUP", 1, 0, 150, 320, 1, &menuOptionsControlJoystickListAxes, -1, SetupJoystickAxesMenu, 0);
1177  CGameMenuItemChain itemOptionsControlJoystickMisc("JOYSTICK MISC SETUP", 1, 0, 170, 320, 1, &menuOptionsControlJoystickMisc, -1, NULL, 0);
1178  
1179  CGameMenuItemTitle itemOptionsControlKeyboardTitle("KEYBOARD SETUP", 1, 160, 20, 2038);
1180  CGameMenuItemSlider itemOptionsControlKeyboardSliderTurnSpeed("Key Turn Speed:", 1, 18, 50, 280, &gTurnSpeed, 64, 128, 4, SetTurnSpeed, -1, -1);
1181  CGameMenuItemZCycle itemOptionsControlKeyboardCycleTurnAcceleration("Key Turn Acceleration:", 1, 18, 70, 280, 0, SetTurnAcceleration, pzTurnAccelerationStrings, ARRAY_SIZE(pzTurnAccelerationStrings), 0);
1182  CGameMenuItemZBool itemOptionsControlKeyboardBoolCrouchToggle("Crouch Toggle:", 1, 18, 90, 280, gCrouchToggle, SetCrouchToggle, NULL, NULL);
1183  CGameMenuItemZBool itemOptionsControlKeyboardBoolCrouchAuto("Crouch Auto:", 1, 18, 110, 280, gCrouchAuto, SetCrouchAuto, NULL, NULL);
1184  CGameMenuItemChain itemOptionsControlKeyboardList("Configure Keys...", 1, 0, 130, 320, 1, &menuKeys, -1, NULL, 0);
1185  CGameMenuItemChain itemOptionsControlKeyboardReset("Reset Keys (default)...", 1, 0, 155, 320, 1, &menuKeys, -1, ResetKeys, 0);
1186  CGameMenuItemChain itemOptionsControlKeyboardResetClassic("Reset Keys (classic)...", 1, 0, 175, 320, 1, &menuKeys, -1, ResetKeysClassic, 0);
1187  
1188  CGameMenuItemTitle itemKeysTitle("KEY SETUP", 1, 160, 20, 2038);
1189  CGameMenuItemKeyList itemKeyList("", 3, 56, 40, 200, 16, NUMGAMEFUNCTIONS, 0);
1190  
1191  void SetMouseAimMode(CGameMenuItemZBool *pItem);
1192  void SetMouseVerticalAim(CGameMenuItemZBool *pItem);
1193  void SetMouseXSensitivity(CGameMenuItemSliderFloat *pItem);
1194  void SetMouseYSensitivity(CGameMenuItemSliderFloat*pItem);
1195  
1196  void PreDrawControlMouse(CGameMenuItem *pItem);
1197  void SetMouseButton(CGameMenuItemZCycle *pItem);
1198  void SetJoyButton(CGameMenuItemZCycle *pItem);
1199  
1200  void SetupMouseButtonMenu(CGameMenuItemChain *pItem);
1201  
1202  CGameMenuItemTitle itemOptionsControlMouseTitle("MOUSE SETUP", 1, 160, 20, 2038);
1203  CGameMenuItemChain itemOptionsControlMouseButton("BUTTON ASSIGNMENT", 3, 66, 60, 180, 0, &menuOptionsControlMouseButtonAssignment, 0, SetupMouseButtonMenu, 0);
1204  CGameMenuItemSliderFloat itemOptionsControlMouseSensitivity("SENSITIVITY:", 3, 66, 70, 180, &CONTROL_MouseSensitivity, 0.f, 100.f, 1.f, SetMouseSensitivity, -1, -1, kMenuSliderValue);
1205  CGameMenuItemZBool itemOptionsControlMouseAimFlipped("INVERT AIMING:", 3, 66, 80, 180, false, SetMouseAimFlipped, NULL, NULL);
1206  CGameMenuItemZBool itemOptionsControlMouseAimMode("AIMING TYPE:", 3, 66, 90, 180, false, SetMouseAimMode, "HOLD", "TOGGLE");
1207  CGameMenuItemZBool itemOptionsControlMouseVerticalAim("VERTICAL AIMING:", 3, 66, 100, 180, false, SetMouseVerticalAim, NULL, NULL);
1208  CGameMenuItemSliderFloat itemOptionsControlMouseXSensitivity("HORIZ SENS:", 3, 66, 110, 180, &CONTROL_MouseAxesSensitivity[0], 0.f, 100.f, 1.f, SetMouseXSensitivity, -1, -1, kMenuSliderValue);
1209  CGameMenuItemSliderFloat itemOptionsControlMouseYSensitivity("VERT SENS:", 3, 66, 120, 180, &CONTROL_MouseAxesSensitivity[1], 0.f, 100.f, 1.f, SetMouseYSensitivity, -1, -1, kMenuSliderValue);
1210  
1211  CGameMenuItemTitle itemOptionsControlRadialTitle("RADIAL SETUP", 1, 160, 20, 2038);
1212  CGameMenuItemZCycle itemOptionsControlRadialToggle("USAGE BEHAVIOR:", 3, 66, 45, 180, 0, SetRadialMenuToggle, zRadialMenuToggle, ARRAY_SIZE(zRadialMenuToggle), 0);
1213  CGameMenuItemSlider itemOptionsControlRadialPosition("POSITION:", 3, 66, 55, 180, &gRadialMenuPosition, 0, 320, 16, SetRadialMenuPosition, -1, -1, kMenuSliderPercent);
1214  CGameMenuItemZBool itemOptionsControlRadialDimBackground("DIM BACKGROUND:", 3, 66, 65, 180, 0, SetRadialMenuDimBackground, NULL, NULL);
1215  CGameMenuItemZBool itemOptionsControlRadialDimHUD("TRANSPARENT RADIAL:", 3, 66, 75, 180, 0, SetRadialMenuDimHUD, NULL, NULL);
1216  CGameMenuItemZBool itemOptionsControlRadialSlowDown("MENU SLOW DOWN:", 3, 66, 85, 180, 0, SetRadialMenuSlowDown, NULL, NULL);
1217  CGameMenuItemZCycle itemOptionsControlRadialSound("SOUND CLICK:", 3, 66, 95, 180, 0, SetRadialMenuSound, pzSoundClickStrings, ARRAY_SIZE(pzSoundClickStrings), 0);
1218  CGameMenuItemSlider itemOptionsControlRadialMouseThreshold("MOUSE THRESHOLD:", 3, 66, 105, 180, &gRadialMenuMouseThreshold, 0, 2048, 128, SetRadialMenuMouseThreshold, -1, -1, kMenuSliderPercent);
1219  CGameMenuItemSlider itemOptionsControlRadialThresholdX("JOY X THRESHOLD:", 3, 66, 115, 180, &gRadialMenuThresholdX, 0, 1024, 128, SetRadialMenuThreshold, -1, -1, kMenuSliderPercent);
1220  CGameMenuItemSlider itemOptionsControlRadialThresholdY("JOY Y THRESHOLD:", 3, 66, 125, 180, &gRadialMenuThresholdY, 0, 1024, 128, SetRadialMenuThreshold, -1, -1, kMenuSliderPercent);
1221  CGameMenuItemZCycle itemOptionsControlRadialYaw("JOY X AXIS:", 3, 66, 135, 180, 0, SetRadialMenuYaw, zRadialMenuAxes, ARRAY_SIZE(zRadialMenuAxes), 0);
1222  CGameMenuItemZBool itemOptionsControlRadialYawInvert("JOY X INVERT:", 3, 66, 145, 180, 0, SetRadialMenuPitchInvert, NULL, NULL);
1223  CGameMenuItemZCycle itemOptionsControlRadialPitch("JOY Y AXIS:", 3, 66, 155, 180, 0, SetRadialMenuPitch, zRadialMenuAxes, ARRAY_SIZE(zRadialMenuAxes), 0);
1224  CGameMenuItemZBool itemOptionsControlRadialPitchInvert("JOY Y INVERT:", 3, 66, 165, 180, 0, SetRadialMenuYawInvert, NULL, NULL);
1225  
1226  void SetupNetworkMenu(void);
1227  void SetupNetworkHostMenu(CGameMenuItemChain *pItem);
1228  void SetupNetworkJoinMenu(CGameMenuItemChain *pItem);
1229  void NetworkHostGame(CGameMenuItemChain *pItem);
1230  void NetworkJoinGame(CGameMenuItemChain *pItem);
1231  
1232  char zNetAddressBuffer[48] = "localhost";
1233  char zNetPortBuffer[6] = "23513";
1234  
1235  CGameMenuItemTitle itemNetworkTitle("MULTIPLAYER", 1, 160, 20, 2038);
1236  CGameMenuItemChain itemNetworkHost("HOST A GAME", 1, 0, 70, 320, 1, &menuNetworkHost, -1, SetupNetworkHostMenu, 0);
1237  CGameMenuItemChain itemNetworkJoin("JOIN A GAME", 1, 0, 90, 320, 1, &menuNetworkJoin, -1, SetupNetworkJoinMenu, 0);
1238  CGameMenuItemChain itemNetworkPlayer("PLAYER SETUP", 1, 0, 110, 320, 1, &menuOptionsPlayer, -1, NULL, 0);
1239  
1240  CGameMenuItemTitle itemNetworkHostTitle("HOST A GAME", 1, 160, 20, 2038);
1241  CGameMenuItemSlider itemNetworkHostPlayerNum("PLAYER NUMBER:", 3, 66, 70, 180, 1, 2, kMaxPlayers, 1, NULL, -1, -1, kMenuSliderValue);
1242  CGameMenuItemZEdit itemNetworkHostPort("NETWORK PORT:", 3, 66, 80, 180, zNetPortBuffer, 6, 0, NULL, 0);
1243  CGameMenuItemChain itemNetworkHostHost("HOST A GAME", 3, 66, 100, 180, 1, NULL, -1, NetworkHostGame, 0);
1244  
1245  CGameMenuItemTitle itemNetworkJoinTitle("JOIN A GAME", 1, 160, 20, 2038);
1246  CGameMenuItemZEdit itemNetworkJoinAddress("NETWORK ADDRESS:", 3, 66, 70, 180, zNetAddressBuffer, 48, 0, NULL, 0);
1247  CGameMenuItemZEdit itemNetworkJoinPort("NETWORK PORT:", 3, 66, 80, 180, zNetPortBuffer, 6, 0, NULL, 0);
1248  CGameMenuItemChain itemNetworkJoinJoin("JOIN A GAME", 3, 66, 100, 180, 1, NULL, -1, NetworkJoinGame, 0);
1249  
1250  // There is no better way to do this than manually.
1251  
1252  #define MENUMOUSEFUNCTIONS 12
1253  
1254  static char const *MenuMouseNames[MENUMOUSEFUNCTIONS] = {
1255      "Button 1",
1256      "Double Button 1",
1257      "Button 2",
1258      "Double Button 2",
1259      "Button 3",
1260      "Double Button 3",
1261  
1262      "Wheel Up",
1263      "Wheel Down",
1264  
1265      "Button 4",
1266      "Double Button 4",
1267      "Button 5",
1268      "Double Button 5",
1269  };
1270  
1271  static int32_t MenuMouseDataIndex[MENUMOUSEFUNCTIONS][2] = {
1272      { 0, 0, },
1273      { 0, 1, },
1274      { 1, 0, },
1275      { 1, 1, },
1276      { 2, 0, },
1277      { 2, 1, },
1278  
1279      // note the mouse wheel
1280      { 4, 0, },
1281      { 5, 0, },
1282  
1283      { 3, 0, },
1284      { 3, 1, },
1285      { 6, 0, },
1286      { 6, 1, },
1287  };
1288  
1289  CGameMenuItemZCycle *pItemOptionsControlMouseButton[MENUMOUSEFUNCTIONS];
1290  
1291  char MenuJoyButtonNames[MAXJOYBUTTONSANDHATS*2][64] = {""};
1292  
1293  const char *zJoystickAnalogue[] =
1294  {
1295      "-None-",
1296      "Turning",
1297      "Strafing",
1298      "Moving",
1299      "Look Up/Down",
1300  };
1301  
1302  CGameMenuItemTitle itemJoyButtonsTitle("JOYSTICK SETUP", 1, 160, 20, 2038);
1303  CGameMenuItemZCycle *pItemOptionsControlJoyButton[MAXJOYSTICKBUTTONPAGES][JOYSTICKITEMSPERPAGE];
1304  CGameMenuItemChain *pItemOptionsControlJoyButtonNextPage[MAXJOYSTICKBUTTONPAGES];
1305  
1306  char MenuJoyAxisNames[MAXJOYAXES][64] = {""};
1307  
1308  CGameMenuItemTitle itemJoyAxesTitle("JOYSTICK AXES", 1, 160, 20, 2038);
1309  CGameMenuItemChain *pItemOptionsControlJoystickAxis[MAXJOYAXES]; // dynamic list for each axis
1310  
1311  CGameMenuItemTitle *pItemOptionsControlJoystickAxisName[MAXJOYAXES];
1312  CGameMenuItemSlider *pItemOptionsControlJoystickAxisScale[MAXJOYAXES];
1313  CGameMenuItemZCycle *pItemOptionsControlJoystickAxisAnalogue[MAXJOYAXES];
1314  CGameMenuItemZBool *pItemOptionsControlJoystickAxisAnalogueInvert[MAXJOYAXES];
1315  CGameMenuItemZCycle *pItemOptionsControlJoystickAxisDigitalPos[MAXJOYAXES];
1316  CGameMenuItemZCycle *pItemOptionsControlJoystickAxisDigitalNeg[MAXJOYAXES];
1317  CGameMenuItemSlider *pItemOptionsControlJoystickAxisDeadzone[MAXJOYAXES];
1318  CGameMenuItemSlider *pItemOptionsControlJoystickAxisSaturate[MAXJOYAXES];
1319  CGameMenuItemSlider *pItemOptionsControlJoystickAxisSnapZone[MAXJOYAXES];
1320  CGameMenuItemBitmap ItemOptionsControlJoystickAxisHeatmapPic(NULL, 3, 500, 290, kAxisHeatmapTile);
1321  
1322  CGameMenuItemTitle itemOptionsControlJoystickMiscTitle("JOYSTICK MISC", 1, 160, 20, 2038);
1323  CGameMenuItemZBool itemOptionsControlJoystickMiscCrouchToggle("CROUCH TOGGLE:", 1, 18, 60, 280, gCrouchToggle, SetCrouchToggle, NULL, NULL);
1324  CGameMenuItemZBool itemOptionsControlJoystickMiscCrouchAuto("AUTO CROUCH:", 1, 18, 80, 280, gCrouchAuto, SetCrouchAuto, NULL, NULL);
1325  CGameMenuItemZBool itemOptionsControlJoystickMiscCenterView("CENTER VIEW ON DROP:", 1, 18, 100, 280, gCenterViewOnDrop, SetCenterView, NULL, NULL);
1326  CGameMenuItemZBool itemOptionsControlJoystickMiscTargetAimAssist("TARGET AIM ASSIST:", 1, 18, 120, 280, 0, SetJoystickTargetAimAssist, NULL, NULL);
1327  CGameMenuItemZBool itemOptionsControlJoystickMiscRumble("RUMBLE CONTROLLER:", 1, 18, 140, 280, 0, SetJoystickRumble, NULL, NULL);
1328  
1329  void SetupLoadingScreen(void)
1330  {
1331      menuLoading.Add(&itemLoadingText, true);
1332  }
1333  
1334  void SetupMessagesMenu(void)
1335  {
1336      menuMessages.Add(&itemMessagesTitle, false);
1337      menuMessages.Add(&boolMessages, true);
1338      menuMessages.Add(&sliderMsgCount, false);
1339      menuMessages.Add(&sliderMsgTime, false);
1340      menuMessages.Add(&boolMsgFont, false);
1341      menuMessages.Add(&boolMsgIncoming, false);
1342      menuMessages.Add(&boolMsgSelf, false);
1343      menuMessages.Add(&boolMsgOther, false);
1344      menuMessages.Add(&boolMsgRespawn, false);
1345      menuMessages.Add(&itemBloodQAV, false);
1346  }
1347  
1348  void SetupDifficultyMenu(void)
1349  {
1350      menuDifficulty.Add(&itemDifficultyTitle, false);
1351      menuDifficulty.Add(&itemDifficulty1, false);
1352      menuDifficulty.Add(&itemDifficulty2, false);
1353      menuDifficulty.Add(&itemDifficulty3, true);
1354      menuDifficulty.Add(&itemDifficulty4, false);
1355      menuDifficulty.Add(&itemDifficulty5, false);
1356      menuDifficulty.Add(&itemDifficulty6, false);
1357      menuDifficulty.Add(&itemBloodQAV, false);
1358  
1359      menuCustomDifficulty.Add(&itemCustomDifficultyTitle, false);
1360      menuCustomDifficulty.Add(&itemCustomDifficultyStartLevel, false);
1361      menuCustomDifficulty.Add(&itemCustomDifficultyMonsterSettings, true);
1362      menuCustomDifficulty.Add(&itemCustomDifficultyEnemyQuantity, false);
1363      menuCustomDifficulty.Add(&itemCustomDifficultyEnemyHealth, false);
1364      menuCustomDifficulty.Add(&itemCustomDifficultyEnemyDifficulty, false);
1365      menuCustomDifficulty.Add(&itemCustomDifficultyPlayerDamage, false);
1366      menuCustomDifficulty.Add(&itemCustomDifficultyEnemySpeed, false);
1367      menuCustomDifficulty.Add(&itemCustomDifficultyEnemyShuffle, false);
1368      menuCustomDifficulty.Add(&itemCustomDifficultyPitchfork, false);
1369      menuCustomDifficulty.Add(&itemCustomDifficultyPermaDeath, false);
1370      menuCustomDifficulty.Add(&itemCustomDifficultyBannedMonsters, false);
1371      menuCustomDifficulty.Add(&itemCustomDifficultyBannedItems, false);
1372      menuCustomDifficulty.Add(&itemCustomDifficultyStart, false);
1373      menuCustomDifficulty.Add(&itemBloodQAV, false);
1374      itemCustomDifficultyStartLevel.tooltip_pzTextUpper = "";
1375      itemCustomDifficultyStartLevel.tooltip_pzTextLower = "Set the starting level for this episode";
1376      itemCustomDifficultyEnemyQuantity.tooltip_pzTextUpper = "";
1377      itemCustomDifficultyEnemyQuantity.tooltip_pzTextLower = "Set how many enemies will spawn in the level";
1378      itemCustomDifficultyEnemyHealth.tooltip_pzTextUpper = "";
1379      itemCustomDifficultyEnemyHealth.tooltip_pzTextLower = "Set enemy's starting health";
1380      itemCustomDifficultyEnemyDifficulty.tooltip_pzTextUpper = "";
1381      itemCustomDifficultyEnemyDifficulty.tooltip_pzTextLower = "Set enemy's behavior difficulty";
1382      itemCustomDifficultyPlayerDamage.tooltip_pzTextUpper = "";
1383      itemCustomDifficultyPlayerDamage.tooltip_pzTextLower = "Set player's damage taken scale";
1384      itemCustomDifficultyEnemySpeed.tooltip_pzTextUpper = "";
1385      itemCustomDifficultyEnemySpeed.tooltip_pzTextLower = "Set enemy's movement speed modifier";
1386      itemCustomDifficultyEnemyShuffle.tooltip_pzTextUpper = "";
1387      itemCustomDifficultyEnemyShuffle.tooltip_pzTextLower = "Shuffle enemy's spawn position";
1388      itemCustomDifficultyPitchfork.tooltip_pzTextUpper = "";
1389      itemCustomDifficultyPitchfork.tooltip_pzTextLower = "Player will lose all items on new level";
1390      itemCustomDifficultyPermaDeath.tooltip_pzTextUpper = "";
1391      itemCustomDifficultyPermaDeath.tooltip_pzTextLower = "No saving, and you only live once";
1392      itemCustomDifficultyBannedMonsters.tooltip_pzTextUpper = "";
1393      itemCustomDifficultyBannedMonsters.tooltip_pzTextLower = "Set which monsters to spawn";
1394      itemCustomDifficultyBannedItems.tooltip_pzTextUpper = "";
1395      itemCustomDifficultyBannedItems.tooltip_pzTextLower = "Set which items to spawn";
1396  
1397      menuBannedMonsters.Add(&itemBannedMonstersTitle, false);
1398      menuBannedMonsters.Add(&itemBannedMonstersBats, true);
1399      menuBannedMonsters.Add(&itemBannedMonstersRats, false);
1400      menuBannedMonsters.Add(&itemBannedMonstersFish, false);
1401      menuBannedMonsters.Add(&itemBannedMonstersHands, false);
1402      menuBannedMonsters.Add(&itemBannedMonstersGhosts, false);
1403      menuBannedMonsters.Add(&itemBannedMonstersSpiders, false);
1404      menuBannedMonsters.Add(&itemBannedMonstersTinyCaleb, false);
1405      menuBannedMonsters.Add(&itemBannedMonstersHellHounds, false);
1406      menuBannedMonsters.Add(&itemBannedMonstersRatsAttack, false);
1407      menuBannedMonsters.Add(&itemBannedMonstersMotherSpiderHealth, false);
1408      menuBannedMonsters.Add(&itemBannedMonstersTchernobogHealth, false);
1409      menuBannedMonsters.Add(&itemBloodQAV, false);
1410      itemBannedMonstersSpiders.tooltip_pzTextUpper = "";
1411      itemBannedMonstersSpiders.tooltip_pzTextLower = "Mother spiders are not removed to avoid boss softlocks";
1412      itemBannedMonstersTchernobogHealth.tooltip_pzTextUpper = "";
1413      itemBannedMonstersTchernobogHealth.tooltip_pzTextLower = "Fix overflow health bug for Tchernobog";
1414  
1415      menuBannedItems.Add(&itemBannedItemsTitle, false);
1416      menuBannedItems.Add(&itemBannedItemsFlare, true);
1417      menuBannedItems.Add(&itemBannedItemsShotgun, false);
1418      menuBannedItems.Add(&itemBannedItemsTommyGun, false);
1419      menuBannedItems.Add(&itemBannedItemsNapalm, false);
1420      menuBannedItems.Add(&itemBannedItemsTNT, false);
1421      menuBannedItems.Add(&itemBannedItemsSpray, false);
1422      menuBannedItems.Add(&itemBannedItemsTesla, false);
1423      menuBannedItems.Add(&itemBannedItemsLifeLeech, false);
1424      menuBannedItems.Add(&itemBannedItemsVoodoo, false);
1425      menuBannedItems.Add(&itemBannedItemsProxy, false);
1426      menuBannedItems.Add(&itemBannedItemsRemote, false);
1427      menuBannedItems.Add(&itemBannedItemsMedKit, false);
1428      menuBannedItems.Add(&itemBannedItemsLifeEssence, false);
1429      menuBannedItems.Add(&itemBannedItemsLifeSeed, false);
1430      menuBannedItems.Add(&itemBannedItemsSuperArmor, false);
1431      menuBannedItems.Add(&itemBannedItemsCrystalBall, false);
1432      menuBannedItems.Add(&itemBannedItemsJumpBoots, false);
1433      menuBannedItems.Add(&itemBannedItemsCloak, false);
1434      menuBannedItems.Add(&itemBannedItemsDeathMask, false);
1435      menuBannedItems.Add(&itemBannedItemsAkimbo, false);
1436      menuBannedItems.Add(&itemBannedItemsReflect, false);
1437      menuBannedItems.Add(&itemBloodQAV, false);
1438  }
1439  
1440  void SetupEpisodeMenu(void)
1441  {
1442      menuEpisode.Add(&itemEpisodesTitle, false);
1443      int height;
1444      gMenuTextMgr.GetFontInfo(1, NULL, NULL, &height);
1445      int nOffset = 100;
1446      for (int i = 0; i < gEpisodeCount; i++)
1447      {
1448          EPISODEINFO *pEpisode = &gEpisodeInfo[i];
1449          if (!pEpisode->bloodbath || gGameOptions.nGameType != kGameTypeSinglePlayer)
1450              nOffset -= 10;
1451      }
1452      nOffset = max(min(nOffset, 55), 35);
1453      int j = 0;
1454      for (int i = 0; i < gEpisodeCount; i++)
1455      {
1456          EPISODEINFO *pEpisode = &gEpisodeInfo[i];
1457          if (!pEpisode->bloodbath || gGameOptions.nGameType != kGameTypeSinglePlayer)
1458          {
1459              if (j >= ARRAY_SSIZE(itemEpisodes))
1460                  ThrowError("Too many ini episodes to display (max %d).\n", ARRAY_SSIZE(itemEpisodes));
1461              CGameMenuItemChain7F2F0 *pEpisodeItem = &itemEpisodes[j];
1462              pEpisodeItem->m_nFont = 1;
1463              pEpisodeItem->m_nX = 0;
1464              pEpisodeItem->m_nWidth = 320;
1465              pEpisodeItem->at20 = 1;
1466              pEpisodeItem->m_pzText = pEpisode->title;
1467              pEpisodeItem->m_nY = nOffset+(height+8)*j;
1468              pEpisodeItem->at34 = i;
1469              pEpisodeItem = &itemEpisodes[j];
1470              pEpisodeItem->at24 = &menuDifficulty;
1471              pEpisodeItem->at28 = 3;
1472              pEpisodeItem = &itemEpisodes[j];
1473              pEpisodeItem->bCanSelect = 1;
1474              pEpisodeItem->bEnable = 1;
1475              bool first = j == 0;
1476              menuEpisode.Add(&itemEpisodes[j], first);
1477              if (first)
1478                  SetupLevelMenuItem(j);
1479              j++;
1480          }
1481      }
1482  
1483      if (j < 5) // if menu slots are not all filled, add space for user maps item
1484          itemUserMap.m_nY = 50+(height+8)*5;
1485      else
1486          itemUserMap.m_nY = nOffset+(height+8)*j;
1487      menuEpisode.Add(&itemUserMap, false);
1488      menuEpisode.Add(&itemBloodQAV, false);
1489  
1490      menuUserMap.Add(&itemUserMapTitle, true);
1491      menuUserMap.Add(&itemUserMapList, true);
1492  }
1493  
1494  void SetupMainMenu(void)
1495  {
1496      menuMain.Add(&itemMainTitle, false);
1497      menuMain.Add(&itemMain1, true);
1498      if (gGameOptions.nGameType != kGameTypeSinglePlayer)
1499      {
1500          itemMain1.at24 = &menuNetStart;
1501          itemMain1.at28 = 2;
1502      }
1503      else
1504      {
1505          itemMain1.at24 = &menuEpisode;
1506          itemMain1.at28 = -1;
1507      }
1508      menuMain.Add(&itemMain2, false);
1509      menuMain.Add(&itemMain3, false);
1510      menuMain.Add(&itemMain4, false);
1511      menuMain.Add(&itemMain5, false);
1512      menuMain.Add(&itemMain6, false);
1513      menuMain.Add(&itemMain7, false);
1514      menuMain.Add(&itemBloodQAV, false);
1515  
1516  #ifdef NETCODE_DISABLE
1517      itemMain2.bEnable = 0; // disable multiplayer menu item for non-netcode build
1518  #endif
1519  }
1520  
1521  void SetupMainMenuWithSave(void)
1522  {
1523      menuMainWithSave.Add(&itemMainSaveTitle, false);
1524      menuMainWithSave.Add(&itemMainSave1, true);
1525      if (gGameOptions.nGameType != kGameTypeSinglePlayer)
1526      {
1527          itemMainSave1.at24 = &menuNetStart;
1528          itemMainSave1.at28 = 2;
1529      }
1530      else
1531      {
1532          itemMainSave1.at24 = &menuEpisode;
1533          itemMainSave1.at28 = -1;
1534      }
1535      menuMainWithSave.Add(&itemMainSave2, false);
1536      menuMainWithSave.Add(&itemMainSave3, false);
1537      menuMainWithSave.Add(&itemMainSave4, false);
1538      menuMainWithSave.Add(&itemMainSave5, false);
1539      menuMainWithSave.Add(&itemMainSave6, false);
1540      menuMainWithSave.Add(&itemMainSave7, false);
1541      menuMainWithSave.Add(&itemMainSave8, false);
1542      menuMainWithSave.Add(&itemBloodQAV, false);
1543  
1544      itemMainSave3.bDisableForNet = itemMainSave3.bDisableForPermaDeath = 1;
1545      itemMainSave4.bDisableForNet = 1;
1546      itemMainSave5.bDisableForNet = 1;
1547      itemMainSave6.bDisableForNet = 1;
1548      itemMainSave3.bEnable = !gLockManualSaving; // disable save option in main menu if lock saving mode is set
1549  }
1550  
1551  void SetupFirstLaunchMenu(void)
1552  {
1553      menuFirstLaunch.Add(&itemFirstLaunchInfo1, false);
1554      menuFirstLaunch.Add(&itemFirstLaunchInfo2, false);
1555      menuFirstLaunch.Add(&itemFirstLaunchVanilla, true);
1556      menuFirstLaunch.Add(&itemFirstLaunchNBlood, false);
1557      menuFirstLaunch.Add(&itemFirstLaunchNotBlood, false);
1558      itemFirstLaunchVanilla.tooltip_pzTextUpper = "Set options to match v1.21 DOS Blood and use vanilla mode";
1559      itemFirstLaunchNBlood.tooltip_pzTextUpper = "Set options to match NBlood";
1560      itemFirstLaunchNotBlood.tooltip_pzTextUpper = "Keep default NotBlood options";
1561      itemFirstLaunchNotBlood.tooltip_pzTextLower = "(pick this one if you're unsure)";
1562  }
1563  
1564  void SetupNetStartMenu(void)
1565  {
1566      bool oneEpisode = false;
1567      menuNetStart.Add(&itemNetStartTitle, false);
1568      menuNetStart.Add(&itemNetStart1, false);
1569      for (int i = 0; i < (oneEpisode ? 1 : 6); i++)
1570      {
1571          EPISODEINFO *pEpisode = &gEpisodeInfo[i];
1572          if (i < gEpisodeCount)
1573              itemNetStart2.Add(pEpisode->title, i == 0);
1574      }
1575      menuNetStart.Add(&itemNetStart2, false);
1576      menuNetStart.Add(&itemNetStart3, false);
1577      menuNetStart.Add(&itemNetStart4, false);
1578      menuNetStart.Add(&itemNetStart5, false);
1579      menuNetStart.Add(&itemNetStart6, false);
1580      menuNetStart.Add(&itemNetStart7, false);
1581      menuNetStart.Add(&itemNetStartBoolChaseView, false);
1582      menuNetStart.Add(&itemNetStartBoolHolstering, false);
1583      menuNetStart.Add(&itemNetStartBoolSecondWind, false);
1584      menuNetStart.Add(&itemNetStartBoolSpectatorMode, false);
1585      menuNetStart.Add(&itemNetStart8, false);
1586      menuNetStart.Add(&itemNetStart9, false);
1587      menuNetStart.Add(&itemNetStart10, false);
1588      menuNetStart.Add(&itemNetStart11, false);
1589      menuMultiUserMaps.Add(&itemNetStartUserMapTitle, true);
1590      menuMultiUserMaps.Add(&menuMultiUserMap, true);
1591  
1592      menuNetworkGameMode.Add(&itemNetGameTitle, false);
1593      menuNetworkGameMode.Add(&itemNetGameMode, true);
1594      menuNetworkGameMode.Add(&itemNetGameSliderScoreLimit, false);
1595      menuNetworkGameMode.Add(&itemNetGameSliderTimeLimit, false);
1596      menuNetworkGameMode.Add(&itemNetGameSliderLivesLimit, false);
1597      menuNetworkGameMode.Add(&itemNetGameBoolExit, false);
1598      menuNetworkGameMode.Add(&itemNetGameBoolTeleFrag, false);
1599      menuNetworkGameMode.Add(&itemNetGameBoolSkillOverride, false);
1600      menuNetworkGameMode.Add(&itemNetGameBoolModelOverride, false);
1601      menuNetworkGameMode.Add(&itemNetGameBoolPlayerColors, false);
1602      menuNetworkGameMode.Add(&itemNetGameBoolTeamColors, false);
1603      menuNetworkGameMode.Add(&itemNetGameBoolFriendlyFire, false);
1604      menuNetworkGameMode.Add(&itemNetGameCycleKey, false);
1605      menuNetworkGameMode.Add(&itemNetGameCycleItemWeapon, false);
1606      menuNetworkGameMode.Add(&itemNetGameBoolAutoTeams, false);
1607      menuNetworkGameMode.Add(&itemNetGameBoolTeamFlags, false);
1608      menuNetworkGameMode.Add(&itemNetGameCycleSpawnLocation, false);
1609      menuNetworkGameMode.Add(&itemNetGameCycleShowWeaponsOverride, false);
1610      menuNetworkGameMode.Add(&itemNetGameCycleShowWeaponsOverrideTeams, false);
1611      menuNetworkGameMode.Add(&itemNetGameCycleSpawnProtection, false);
1612      menuNetworkGameMode.Add(&itemNetGameCycleSpawnWeapon, false);
1613      menuNetworkGameMode.Add(&itemNetGameCycleMirrorModeOverride, false);
1614      menuNetworkGameMode.Add(&itemBloodQAV, false);
1615      itemNetGameSliderScoreLimit.tooltip_pzTextUpper = "Set score limit";
1616      itemNetGameSliderScoreLimit.tooltip_pzTextLower = "(0 = no limit)";
1617      itemNetGameSliderTimeLimit.tooltip_pzTextUpper = "Set round limt (in minutes)";
1618      itemNetGameSliderTimeLimit.tooltip_pzTextLower = "(0 = no limit)";
1619      itemNetGameSliderLivesLimit.tooltip_pzTextUpper = "Set number of respawns allowed";
1620      itemNetGameSliderLivesLimit.tooltip_pzTextLower = "(0 = no limit)";
1621      itemNetGameBoolExit.tooltip_pzTextUpper = "Toggle level exit switch functionality";
1622      itemNetGameBoolTeleFrag.tooltip_pzTextUpper = "Toggle telefrags kills";
1623      itemNetGameBoolSkillOverride.tooltip_pzTextUpper = "Toggle player health handicap";
1624      itemNetGameBoolSkillOverride.tooltip_pzTextLower = "(When off, use difficulty setting)";
1625      itemNetGameBoolModelOverride.tooltip_pzTextUpper = "Set global setting for player models";
1626      itemNetGameBoolModelOverride.tooltip_pzTextLower = "(This is applied to all players in round)";
1627      itemNetGameBoolAutoTeams.tooltip_pzTextUpper = "Automatically sort players into teams";
1628      itemNetGameBoolPlayerColors.tooltip_pzTextUpper = "Allow non-vanilla player colors";
1629      itemNetGameBoolTeamColors.tooltip_pzTextUpper = "Highlight players with team colors";
1630      itemNetGameBoolTeamFlags.tooltip_pzTextUpper = "Toggle team flags for teams mode";
1631      itemNetGameCycleSpawnLocation.tooltip_pzTextUpper = "Set spawn location behavior";
1632      itemNetGameCycleShowWeaponsOverride.tooltip_pzTextUpper = "Set global setting for show weapons option";
1633      itemNetGameCycleShowWeaponsOverride.tooltip_pzTextLower = "(This is applied to all players in round)";
1634      itemNetGameCycleShowWeaponsOverrideTeams.tooltip_pzTextUpper = "Set global setting for show weapons option";
1635      itemNetGameCycleShowWeaponsOverrideTeams.tooltip_pzTextLower = "(This is applied to all players in round)";
1636      itemNetGameCycleSpawnProtection.tooltip_pzTextUpper = "Give players invulnerability on spawn";
1637      itemNetGameCycleMirrorModeOverride.tooltip_pzTextUpper = "Set global setting for mirror mode";
1638      itemNetGameCycleMirrorModeOverride.tooltip_pzTextLower = "(This is applied to all players in round)";
1639  
1640      menuNetworkGameMonsters.Add(&itemNetMonsterTitle, false);
1641      menuNetworkGameMonsters.Add(&itemNetMonsterSettings, true);
1642      menuNetworkGameMonsters.Add(&itemNetMonsterQuantity, false);
1643      menuNetworkGameMonsters.Add(&itemNetMonsterHealth, false);
1644      menuNetworkGameMonsters.Add(&itemNetMonsterSpeed, false);
1645      menuNetworkGameMonsters.Add(&itemNetMonsterBats, false);
1646      menuNetworkGameMonsters.Add(&itemNetMonsterRats, false);
1647      menuNetworkGameMonsters.Add(&itemNetMonsterFish, false);
1648      menuNetworkGameMonsters.Add(&itemNetMonsterHands, false);
1649      menuNetworkGameMonsters.Add(&itemNetMonsterGhosts, false);
1650      menuNetworkGameMonsters.Add(&itemNetMonsterSpiders, false);
1651      menuNetworkGameMonsters.Add(&itemNetMonsterTinyCaleb, false);
1652      menuNetworkGameMonsters.Add(&itemNetMonsterHellHounds, false);
1653      menuNetworkGameMonsters.Add(&itemNetMonsterRatsAttack, false);
1654      menuNetworkGameMonsters.Add(&itemNetMonsterMotherSpiderHealth, false);
1655      menuNetworkGameMonsters.Add(&itemNetMonsterTchernobogHealth, false);
1656      menuNetworkGameMonsters.Add(&itemBloodQAV, false);
1657  
1658      //////////////////////
1659      menuNetworkGameMutators.Add(&itemGameMutatorsTitle, false);
1660      menuNetworkGameMutators.Add(&itemNetMutatorBoolQuadDamagePowerup, true);
1661      menuNetworkGameMutators.Add(&itemNetMutatorDamageInvul, false);
1662      menuNetworkGameMutators.Add(&itemNetMutatorProjectileBehavior, false);
1663      menuNetworkGameMutators.Add(&itemNetMutatorNapalmFalloff, false);
1664      menuNetworkGameMutators.Add(&itemNetMutatorEnemyBehavior, false);
1665      menuNetworkGameMutators.Add(&itemNetMutatorBoolEnemyRandomTNT, false);
1666      menuNetworkGameMutators.Add(&itemNetMutatorWeaponsVer, false);
1667      menuNetworkGameMutators.Add(&itemNetMutatorAmmoScale, false);
1668      menuNetworkGameMutators.Add(&itemNetMutatorSectorBehavior, false);
1669      menuNetworkGameMutators.Add(&itemNetMutatorHitscanProjectiles, false);
1670      menuNetworkGameMutators.Add(&itemNetMutatorGoreBehavior, false);
1671      menuNetworkGameMutators.Add(&itemNetMutatorPlayerSpeed, false);
1672      menuNetworkGameMutators.Add(&itemNetMutatorRandomizerMode, false);
1673      menuNetworkGameMutators.Add(&itemNetMutatorRandomizerSeed, false);
1674      menuNetworkGameMutators.Add(&itemBloodQAV, false);
1675      itemNetMutatorBoolQuadDamagePowerup.tooltip_pzTextUpper = "Replaces guns akimbo powerup";
1676      itemNetMutatorBoolQuadDamagePowerup.tooltip_pzTextLower = "with Quake's quad damage";
1677      itemNetMutatorDamageInvul.tooltip_pzTextUpper = "Apply a short invulnerability state";
1678      itemNetMutatorDamageInvul.tooltip_pzTextLower = "on bullet/spirit/tesla damage";
1679      itemNetMutatorProjectileBehavior.tooltip_pzTextUpper = "Use smaller hitboxes and improve collision";
1680      itemNetMutatorProjectileBehavior.tooltip_pzTextLower = "accuracy for player projectiles";
1681      itemNetMutatorNapalmFalloff.tooltip_pzTextUpper = "Set napalm projectiles to";
1682      itemNetMutatorNapalmFalloff.tooltip_pzTextLower = "be affected by gravity";
1683      itemNetMutatorEnemyBehavior.tooltip_pzTextUpper = "Fix various original bugs with enemies";
1684      itemNetMutatorBoolEnemyRandomTNT.tooltip_pzTextUpper = "Set cultist to have a chance of";
1685      itemNetMutatorBoolEnemyRandomTNT.tooltip_pzTextLower = "throwing random projectiles";
1686      itemNetMutatorWeaponsVer.tooltip_pzTextUpper = "Check readme.txt for full";
1687      itemNetMutatorWeaponsVer.tooltip_pzTextLower = "list of weapon changes";
1688      itemNetMutatorAmmoScale.tooltip_pzTextUpper = "Scale ammo pickup amount";
1689      itemNetMutatorSectorBehavior.tooltip_pzTextUpper = "Improve room over room sector logic";
1690      itemNetMutatorHitscanProjectiles.tooltip_pzTextUpper = "Set hitscan enemies to spawn projectiles";
1691  #ifdef NOONE_EXTENSIONS
1692      itemNetMutatorHitscanProjectiles.tooltip_pzTextLower = "(does not support xmapedit enemies)";
1693  #endif
1694      itemNetMutatorGoreBehavior.tooltip_pzTextUpper = "Spawns excessive gibs and increases particles";
1695      itemNetMutatorPlayerSpeed.tooltip_pzTextUpper = "Adjusts the player speed";
1696      itemNetMutatorRandomizerMode.tooltip_pzTextUpper = "Set the randomizer's mode";
1697      itemNetMutatorRandomizerSeed.tooltip_pzTextUpper = "Set the randomizer's seed";
1698      itemNetMutatorRandomizerSeed.tooltip_pzTextLower = "No seed = always use a random seed";
1699      //////////////////////
1700  
1701      itemNetStart2.SetTextIndex(gMultiEpisodeInit != -1 ? gMultiEpisodeInit : 0);
1702      SetupLevelMenuItem(gMultiEpisodeInit != -1 ? gMultiEpisodeInit : 0);
1703      itemNetStart3.SetTextIndex(gMultiLevelInit != -1 ? gMultiLevelInit : 0);
1704      itemNetStart4.SetTextIndex(gMultiDiffInit != -1 ? gMultiDiffInit : 2);
1705      itemNetStart6.SetTextIndex(gMultiWeapons != -1 ? gMultiWeapons : 1);
1706      itemNetStart7.SetTextIndex(gMultiItems != -1 ? gMultiItems : 1);
1707      if (gMultiChaseView)
1708          itemNetStartBoolChaseView.at20 = 1;
1709      if (gMultiHolstering)
1710          itemNetStartBoolHolstering.at20 = 1;
1711      if (gMultiSecondWind > -1)
1712          itemNetStartBoolSecondWind.at20 = !!gMultiSecondWind;
1713      if (gMultiSpectating)
1714          itemNetStartBoolSpectatorMode.at20 = 1;
1715  
1716      itemNetGameMode.SetTextIndex(gMultiModeInit != -1 ? gMultiModeInit : 1);
1717      itemNetGameSliderScoreLimit.nValue = gMultiScoreLimit != -1 ? gMultiScoreLimit : itemNetGameSliderScoreLimit.nValue;
1718      itemNetGameSliderLivesLimit.nValue = gMultiScoreLimit != -1 ? gMultiScoreLimit : itemNetGameSliderLivesLimit.nValue;
1719      itemNetGameSliderTimeLimit.nValue = gMultiTimeLimit != -1 ? gMultiTimeLimit : itemNetGameSliderTimeLimit.nValue;
1720      if (gMultiModeNoExit)
1721          itemNetGameBoolExit.at20 = 0;
1722      itemNetGameBoolAutoTeams.at20 = !gPlayerTeamPreference;
1723      if (gMultiModeNoFlag)
1724          itemNetGameBoolTeamFlags.at20 = 0;
1725      itemNetGameCycleSpawnLocation.SetTextIndex(gMultiSpawnLocation != -1 ? gMultiSpawnLocation : 1);
1726      itemNetGameCycleShowWeaponsOverride.SetTextIndex(1);
1727      itemNetGameCycleShowWeaponsOverrideTeams.SetTextIndex(1);
1728      itemNetGameCycleSpawnProtection.SetTextIndex(gMultiSpawnProtection != -1 ? gMultiSpawnProtection : 0);
1729      SetNetGameMode(&itemNetGameMode); // hide friendly fire/keys menu items depending on game mode
1730  
1731      itemNetMonsterSettings.SetTextIndex(gMultiMonsters != -1 ? gMultiMonsters : 0);
1732      SetNetMonsterMenu(NULL);
1733  
1734      ///////
1735      itemNetMutatorBoolQuadDamagePowerup.at20 = !!gQuadDamagePowerup;
1736      itemNetMutatorDamageInvul.m_nFocus = gDamageInvul % ARRAY_SSIZE(pzDamageInvulBehaviorStrings);
1737      itemNetMutatorProjectileBehavior.m_nFocus = gProjectileBehavior % ARRAY_SSIZE(pzProjectileBehaviorStrings);
1738      itemNetMutatorNapalmFalloff.at20 = !!gNapalmFalloff;
1739      itemNetMutatorEnemyBehavior.m_nFocus = gEnemyBehavior % ARRAY_SSIZE(pzEnemyBehaviorStrings);
1740      itemNetMutatorBoolEnemyRandomTNT.at20 = !!gEnemyRandomTNT;
1741      itemNetMutatorWeaponsVer.m_nFocus = gWeaponsVer % ARRAY_SSIZE(pzWeaponsVersionStrings);
1742      itemNetMutatorAmmoScale.m_nFocus = gAmmoScale % ARRAY_SSIZE(pzAmmoScaleStrings);
1743      itemNetMutatorSectorBehavior.at20 = !!gSectorBehavior;
1744      itemNetMutatorHitscanProjectiles.m_nFocus = gHitscanProjectiles % ARRAY_SSIZE(pzHitscanProjectilesStrings);
1745      itemNetMutatorGoreBehavior.m_nFocus = gGoreBehavior % ARRAY_SSIZE(pzGoreStrings);
1746      itemNetMutatorPlayerSpeed.m_nFocus = gPlayerModSpeed % ARRAY_SSIZE(pzPlayerSpeeds);
1747      itemNetMutatorRandomizerMode.m_nFocus = gRandomizerMode % ARRAY_SSIZE(pzRandomizerModeStrings);
1748      Bstrncpy(szRandomizerSeedMenu, gzRandomizerSeed, sizeof(gPacketStartGame.szRandomizerSeed));
1749      ///////
1750  
1751      menuNetStart.Add(&itemBloodQAV, false);
1752  }
1753  
1754  void SetupSaveGameMenu(void)
1755  {
1756      menuSaveGame.Add(&itemSaveTitle, false);
1757      menuSaveGame.Add(&itemSaveGame0, true);
1758      menuSaveGame.Add(&itemSaveGame1, false);
1759      menuSaveGame.Add(&itemSaveGame2, false);
1760      menuSaveGame.Add(&itemSaveGame3, false);
1761      menuSaveGame.Add(&itemSaveGame4, false);
1762      menuSaveGame.Add(&itemSaveGame5, false);
1763      menuSaveGame.Add(&itemSaveGame6, false);
1764      menuSaveGame.Add(&itemSaveGame7, false);
1765      menuSaveGame.Add(&itemSaveGame8, false);
1766      menuSaveGame.Add(&itemSaveGame9, false);
1767      menuSaveGame.Add(&itemSaveGameQuick, false);
1768      menuSaveGame.Add(&itemSaveGameAutosaveStart, false);
1769      menuSaveGame.Add(&itemSaveGameAutosaveKey, false);
1770      menuSaveGame.Add(&itemSaveGamePic, false);
1771      menuSaveGame.Add(&itemBloodQAV, false);
1772  
1773      itemSaveGame0.at2c = &itemSaveGamePic;
1774      if (!strcmp(strRestoreGameStrings[kLoadSaveSlot0], "<Empty>"))
1775          itemSaveGame0.at37 = 1;
1776  
1777      itemSaveGame1.at2c = &itemSaveGamePic;
1778      if (!strcmp(strRestoreGameStrings[kLoadSaveSlot1], "<Empty>"))
1779          itemSaveGame1.at37 = 1;
1780  
1781      itemSaveGame2.at2c = &itemSaveGamePic;
1782      if (!strcmp(strRestoreGameStrings[kLoadSaveSlot2], "<Empty>"))
1783          itemSaveGame2.at37 = 1;
1784  
1785      itemSaveGame3.at2c = &itemSaveGamePic;
1786      if (!strcmp(strRestoreGameStrings[kLoadSaveSlot3], "<Empty>"))
1787          itemSaveGame3.at37 = 1;
1788  
1789      itemSaveGame4.at2c = &itemSaveGamePic;
1790      if (!strcmp(strRestoreGameStrings[kLoadSaveSlot4], "<Empty>"))
1791          itemSaveGame4.at37 = 1;
1792  
1793      itemSaveGame5.at2c = &itemSaveGamePic;
1794      if (!strcmp(strRestoreGameStrings[kLoadSaveSlot5], "<Empty>"))
1795          itemSaveGame5.at37 = 1;
1796  
1797      itemSaveGame6.at2c = &itemSaveGamePic;
1798      if (!strcmp(strRestoreGameStrings[kLoadSaveSlot6], "<Empty>"))
1799          itemSaveGame6.at37 = 1;
1800  
1801      itemSaveGame7.at2c = &itemSaveGamePic;
1802      if (!strcmp(strRestoreGameStrings[kLoadSaveSlot7], "<Empty>"))
1803          itemSaveGame7.at37 = 1;
1804  
1805      itemSaveGame8.at2c = &itemSaveGamePic;
1806      if (!strcmp(strRestoreGameStrings[kLoadSaveSlot8], "<Empty>"))
1807          itemSaveGame8.at37 = 1;
1808  
1809      itemSaveGame9.at2c = &itemSaveGamePic;
1810      if (!strcmp(strRestoreGameStrings[kLoadSaveSlot9], "<Empty>"))
1811          itemSaveGame9.at37 = 1;
1812  
1813      itemSaveGameQuick.at2c = &itemSaveGamePic;
1814      itemSaveGameAutosaveStart.at2c = &itemSaveGamePic;
1815      itemSaveGameAutosaveKey.at2c = &itemSaveGamePic;
1816  
1817      itemSaveGameQuick.bEnable = 0; // don't let these save slots be selectable
1818      itemSaveGameAutosaveStart.bEnable = 0;
1819      itemSaveGameAutosaveStart.bNoDraw = gAutosave == 0;
1820      itemSaveGameAutosaveKey.bEnable = 0;
1821      itemSaveGameAutosaveKey.bNoDraw = gAutosave != 2;
1822  }
1823  
1824  void SetupLoadGameMenu(void)
1825  {
1826      menuLoadGame.Add(&itemLoadTitle, false);
1827      menuLoadGame.Add(&itemLoadGame0, true);
1828      menuLoadGame.Add(&itemLoadGame1, false);
1829      menuLoadGame.Add(&itemLoadGame2, false);
1830      menuLoadGame.Add(&itemLoadGame3, false);
1831      menuLoadGame.Add(&itemLoadGame4, false);
1832      menuLoadGame.Add(&itemLoadGame5, false);
1833      menuLoadGame.Add(&itemLoadGame6, false);
1834      menuLoadGame.Add(&itemLoadGame7, false);
1835      menuLoadGame.Add(&itemLoadGame8, false);
1836      menuLoadGame.Add(&itemLoadGame9, false);
1837      menuLoadGame.Add(&itemLoadGameQuick, false);
1838      menuLoadGame.Add(&itemLoadGameAutosaveStart, false);
1839      menuLoadGame.Add(&itemLoadGameAutosaveKey, false);
1840      menuLoadGame.Add(&itemLoadGamePic, false);
1841      itemLoadGamePic.at28 = gMenuPicnum;
1842      itemLoadGame0.at35 = 0;
1843      itemLoadGame1.at35 = 0;
1844      itemLoadGame2.at35 = 0;
1845      itemLoadGame3.at35 = 0;
1846      itemLoadGame4.at35 = 0;
1847      itemLoadGame5.at35 = 0;
1848      itemLoadGame6.at35 = 0;
1849      itemLoadGame7.at35 = 0;
1850      itemLoadGame8.at35 = 0;
1851      itemLoadGame9.at35 = 0;
1852      itemLoadGameQuick.at35 = 0;
1853      itemLoadGameAutosaveStart.at35 = 0;
1854      itemLoadGameAutosaveKey.at35 = 0;
1855      itemLoadGameAutosaveStart.bEnable = gAutosave != 0; // remove autosave slots if autosaves are disabled
1856      itemLoadGameAutosaveStart.bNoDraw = gAutosave == 0;
1857      itemLoadGameAutosaveKey.bEnable = gAutosave == 2;
1858      itemLoadGameAutosaveKey.bNoDraw = gAutosave != 2;
1859      itemLoadGame0.at2c = &itemLoadGamePic;
1860      itemLoadGame1.at2c = &itemLoadGamePic;
1861      itemLoadGame2.at2c = &itemLoadGamePic;
1862      itemLoadGame3.at2c = &itemLoadGamePic;
1863      itemLoadGame4.at2c = &itemLoadGamePic;
1864      itemLoadGame5.at2c = &itemLoadGamePic;
1865      itemLoadGame6.at2c = &itemLoadGamePic;
1866      itemLoadGame7.at2c = &itemLoadGamePic;
1867      itemLoadGame8.at2c = &itemLoadGamePic;
1868      itemLoadGame9.at2c = &itemLoadGamePic;
1869      itemLoadGameQuick.at2c = &itemLoadGamePic;
1870      itemLoadGameAutosaveStart.at2c = &itemLoadGamePic;
1871      itemLoadGameAutosaveKey.at2c = &itemLoadGamePic;
1872      menuLoadGame.Add(&itemBloodQAV, false);
1873  }
1874  
1875  void SetupQuitMenu(void)
1876  {
1877      menuQuit.Add(&itemQuitTitle, false);
1878      menuQuit.Add(&itemQuitText1, false);
1879      menuQuit.Add(&itemQuitYesNo, true);
1880      menuQuit.Add(&itemBloodQAV, false);
1881  
1882      menuRestart.Add(&itemRestartTitle, false);
1883      menuRestart.Add(&itemRestartText1, false);
1884      menuRestart.Add(&itemRestartYesNo, true);
1885      menuRestart.Add(&itemBloodQAV, false);
1886  }
1887  
1888  void SetupHelpMenu(void)
1889  {
1890      menuHelp.Add(&itemHelp4QAV, true);
1891      menuHelp.Add(&itemHelp5QAV, false);
1892      menuHelp.Add(&itemHelp3QAV, false);
1893      menuHelp.Add(&itemHelp3BQAV, false);
1894      itemHelp4QAV.bEnable = 1;
1895      itemHelp4QAV.bNoDraw = 1;
1896      itemHelp5QAV.bEnable = 1;
1897      itemHelp5QAV.bNoDraw = 1;
1898      itemHelp3QAV.bEnable = 1;
1899      itemHelp3QAV.bNoDraw = 1;
1900      itemHelp3BQAV.bEnable = 1;
1901      itemHelp3BQAV.bNoDraw = 1;
1902  }
1903  
1904  void SetupCreditsMenu(void)
1905  {
1906      menuCredits.Add(&itemCreditsQAV, true);
1907      itemCreditsQAV.bEnable = 1;
1908      itemCreditsQAV.bNoDraw = 1;
1909  }
1910  
1911  void SetupOptionsMenu(void)
1912  {
1913      menuOptions.Add(&itemOptionsTitle, false);
1914      menuOptions.Add(&itemOptionsChainGame, true);
1915      menuOptions.Add(&itemOptionsChainDisplay, false);
1916      menuOptions.Add(&itemOptionsChainSound, false);
1917      menuOptions.Add(&itemOptionsChainPlayer, false);
1918      menuOptions.Add(&itemOptionsChainControl, false);
1919      menuOptions.Add(&itemOptionsChainMutators, false);
1920      menuOptions.Add(&itemBloodQAV, false);
1921  
1922      menuOptionsGame.Add(&itemOptionsGameTitle, false);
1923      menuOptionsGame.Add(&itemOptionsGameCycleAutoAim, true);
1924      menuOptionsGame.Add(&itemOptionsGameSliderAutoAimRange, false);
1925      menuOptionsGame.Add(&itemOptionsGameBoolAutoRun, false);
1926      menuOptionsGame.Add(&itemOptionsGameWeaponSwitch, false);
1927      menuOptionsGame.Add(&itemOptionsGameWeaponFastSwitch, false);
1928      menuOptionsGame.Add(&itemOptionsGameAutosaveMode, false);
1929      menuOptionsGame.Add(&itemOptionsGameLockSaving, false);
1930      menuOptionsGame.Add(&itemOptionsGameRestoreLastSave, false);
1931      menuOptionsGame.Add(&itemOptionsGameBoolVanillaMode, false);
1932      itemOptionsGameSliderAutoAimRange.bDisableForNet = 1;
1933      itemOptionsGameLockSaving.bDisableForNet = 1;
1934      itemOptionsGameBoolVanillaMode.bDisableForNet = 1;
1935      itemOptionsGameSliderAutoAimRange.tooltip_pzTextUpper = "Set autoaim angle modifier";
1936      itemOptionsGameSliderAutoAimRange.tooltip_pzTextLower = "(single-player only)";
1937      itemOptionsGameWeaponFastSwitch.tooltip_pzTextUpper = "Allow weapon switching while";
1938      itemOptionsGameWeaponFastSwitch.tooltip_pzTextLower = "weapon is being lowered/raised";
1939      itemOptionsGameAutosaveMode.tooltip_pzTextUpper = "Set when autosave will trigger";
1940      itemOptionsGameLockSaving.tooltip_pzTextUpper = "Disable manual saving/save scumming";
1941      itemOptionsGameRestoreLastSave.tooltip_pzTextUpper = "Prompt to restore last save game on death";
1942      itemOptionsGameBoolVanillaMode.tooltip_pzTextUpper = "Disable all non-vanilla features/mutators";
1943      itemOptionsGameBoolVanillaMode.tooltip_pzTextLower = "(v1.21 DOS compatibility mode)";
1944  
1945      //////////////////////
1946      menuOptionsGameMutators.Add(&itemGameMutatorsTitle, false);
1947      menuOptionsGameMutators.Add(&itemMutatorBoolQuadDamagePowerup, true);
1948      menuOptionsGameMutators.Add(&itemMutatorDamageInvul, false);
1949      menuOptionsGameMutators.Add(&itemMutatorProjectileBehavior, false);
1950      menuOptionsGameMutators.Add(&itemMutatorNapalmFalloff, false);
1951      menuOptionsGameMutators.Add(&itemMutatorEnemyBehavior, false);
1952      menuOptionsGameMutators.Add(&itemMutatorBoolEnemyRandomTNT, false);
1953      menuOptionsGameMutators.Add(&itemMutatorWeaponsVer, false);
1954      menuOptionsGameMutators.Add(&itemMutatorAmmoScale, false);
1955      menuOptionsGameMutators.Add(&itemMutatorSectorBehavior, false);
1956      menuOptionsGameMutators.Add(&itemMutatorHitscanProjectiles, false);
1957      menuOptionsGameMutators.Add(&itemMutatorGoreBehavior, false);
1958      menuOptionsGameMutators.Add(&itemMutatorPlayerSpeed, false);
1959      menuOptionsGameMutators.Add(&itemMutatorRandomizerMode, false);
1960      menuOptionsGameMutators.Add(&itemMutatorRandomizerSeed, false);
1961      menuOptionsGameMutators.Add(&itemBloodQAV, false);
1962      itemOptionsChainMutators.bDisableForNet = 1;
1963      itemMutatorBoolQuadDamagePowerup.tooltip_pzTextUpper = "Replaces guns akimbo powerup";
1964      itemMutatorBoolQuadDamagePowerup.tooltip_pzTextLower = "with Quake's quad damage";
1965      itemMutatorDamageInvul.tooltip_pzTextUpper = "Apply a short invulnerability state";
1966      itemMutatorDamageInvul.tooltip_pzTextLower = "on bullet/spirit/tesla damage";
1967      itemMutatorProjectileBehavior.tooltip_pzTextUpper = "Use smaller hitboxes and improve collision";
1968      itemMutatorProjectileBehavior.tooltip_pzTextLower = "accuracy for player projectiles";
1969      itemMutatorNapalmFalloff.tooltip_pzTextUpper = "Set napalm projectiles to";
1970      itemMutatorNapalmFalloff.tooltip_pzTextLower = "be affected by gravity";
1971      itemMutatorEnemyBehavior.tooltip_pzTextUpper = "Fix various original bugs with enemies";
1972      itemMutatorBoolEnemyRandomTNT.tooltip_pzTextUpper = "Set cultist to have a chance of";
1973      itemMutatorBoolEnemyRandomTNT.tooltip_pzTextLower = "throwing random projectiles";
1974      itemMutatorWeaponsVer.tooltip_pzTextUpper = "Check readme.txt for full";
1975      itemMutatorWeaponsVer.tooltip_pzTextLower = "list of weapon changes";
1976      itemMutatorAmmoScale.tooltip_pzTextUpper = "Scale ammo pickup amount";
1977      itemMutatorSectorBehavior.tooltip_pzTextUpper = "Improve room over room sector logic";
1978      itemMutatorHitscanProjectiles.tooltip_pzTextUpper = "Set hitscan enemies to spawn projectiles";
1979  #ifdef NOONE_EXTENSIONS
1980      itemMutatorHitscanProjectiles.tooltip_pzTextLower = "(does not support xmapedit enemies)";
1981  #endif
1982      itemMutatorGoreBehavior.tooltip_pzTextUpper = "Spawns excessive gibs and increases particles";
1983      itemMutatorPlayerSpeed.tooltip_pzTextUpper = "Adjusts the player speed";
1984      itemMutatorRandomizerMode.tooltip_pzTextUpper = "Set the randomizer's mode";
1985      itemMutatorRandomizerSeed.tooltip_pzTextUpper = "Set the randomizer's seed";
1986      itemMutatorRandomizerSeed.tooltip_pzTextLower = "No seed = always use a random seed";
1987      /////////////////////
1988  
1989      menuOptionsGame.Add(&itemBloodQAV, false);
1990      itemOptionsGameCycleAutoAim.m_nFocus = gAutoAim;
1991      itemOptionsGameSliderAutoAimRange.nValue = gAutoAimRange;
1992      itemOptionsGameBoolAutoRun.at20 = !!gAutoRun;
1993      itemOptionsGameWeaponSwitch.m_nFocus = gWeaponSwitch % ARRAY_SSIZE(pzWeaponSwitchStrings);
1994      itemOptionsGameWeaponFastSwitch.at20 = !!gWeaponFastSwitch;
1995      itemOptionsGameAutosaveMode.m_nFocus = gAutosave % ARRAY_SSIZE(pzAutosaveModeStrings);
1996      itemOptionsGameLockSaving.at20 = !!gLockManualSaving;
1997      itemOptionsGameRestoreLastSave.at20 = !!gRestoreLastSave;
1998      itemOptionsGameBoolVanillaMode.m_nFocus = gVanilla % ARRAY_SSIZE(pzVanillaModeStrings);
1999      SetGameVanillaMode(gVanilla); // enable/disable menu items depending on current vanilla mode state
2000  
2001      ///////
2002      itemMutatorBoolQuadDamagePowerup.at20 = !!gQuadDamagePowerup;
2003      itemMutatorDamageInvul.m_nFocus = gDamageInvul % ARRAY_SSIZE(pzDamageInvulBehaviorStrings);
2004      itemMutatorProjectileBehavior.m_nFocus = gProjectileBehavior % ARRAY_SSIZE(pzProjectileBehaviorStrings);
2005      itemMutatorNapalmFalloff.at20 = !!gNapalmFalloff;
2006      itemMutatorEnemyBehavior.m_nFocus = gEnemyBehavior % ARRAY_SSIZE(pzEnemyBehaviorStrings);
2007      itemMutatorBoolEnemyRandomTNT.at20 = !!gEnemyRandomTNT;
2008      itemMutatorWeaponsVer.m_nFocus = gWeaponsVer % ARRAY_SSIZE(pzWeaponsVersionStrings);
2009      itemMutatorAmmoScale.m_nFocus = gAmmoScale % ARRAY_SSIZE(pzAmmoScaleStrings);
2010      itemMutatorSectorBehavior.at20 = !!gSectorBehavior;
2011      itemMutatorHitscanProjectiles.m_nFocus = gHitscanProjectiles % ARRAY_SSIZE(pzHitscanProjectilesStrings);
2012      itemMutatorGoreBehavior.m_nFocus = gGoreBehavior % ARRAY_SSIZE(pzGoreStrings);
2013      itemMutatorPlayerSpeed.m_nFocus = gPlayerModSpeed % ARRAY_SSIZE(pzPlayerSpeeds);
2014      itemMutatorRandomizerMode.m_nFocus = gRandomizerMode % ARRAY_SSIZE(pzRandomizerModeStrings);
2015      Bstrncpy(szRandomizerSeedMenu, gzRandomizerSeed, sizeof(szRandomizerSeedMenu));
2016      ///////
2017  
2018      menuOptionsDisplay.Add(&itemOptionsDisplayTitle, false);
2019      menuOptionsDisplay.Add(&itemOptionsDisplayColor, true);
2020      menuOptionsDisplay.Add(&itemOptionsDisplayMode, false);
2021      menuOptionsDisplay.Add(&itemOptionsDisplayView, false);
2022      menuOptionsDisplay.Add(&itemOptionsDisplaySliderDetail, false);
2023      menuOptionsDisplay.Add(&itemOptionsDisplayBoolVoxels, false);
2024      menuOptionsDisplay.Add(&itemOptionsDisplayCrosshair, false);
2025      menuOptionsDisplay.Add(&itemOptionsDisplayLevelStats, false);
2026      menuOptionsDisplay.Add(&itemOptionsDisplayLevelStatsOnAutomap, false);
2027      menuOptionsDisplay.Add(&itemOptionsDisplayPowerupDuration, false);
2028      menuOptionsDisplay.Add(&itemOptionsDisplayBoolShowMapTitle, false);
2029      menuOptionsDisplay.Add(&itemOptionsDisplayBoolMessages, false);
2030      menuOptionsDisplay.Add(&itemOptionsDisplayBoolWidescreen, false);
2031      menuOptionsDisplay.Add(&itemOptionsDisplayWeaponSelect, false);
2032      menuOptionsDisplay.Add(&itemOptionsDisplayFOV, false);
2033      menuOptionsDisplay.Add(&itemBloodQAV, false);
2034      itemOptionsDisplayBoolVoxels.at20 = usevoxels;
2035      itemOptionsDisplayCrosshair.m_nFocus = gAimReticle % ARRAY_SSIZE(pzCrosshairStrings);
2036      itemOptionsDisplayLevelStats.m_nFocus = gLevelStats % ARRAY_SSIZE(pzStatsPowerupRatioStrings);
2037      itemOptionsDisplayLevelStatsOnAutomap.at20 = gLevelStatsOnlyOnMap;
2038      itemOptionsDisplayLevelStatsOnAutomap.bEnable = !!gLevelStats;
2039      itemOptionsDisplayPowerupDuration.m_nFocus = gPowerupDuration % ARRAY_SSIZE(pzStatsPowerupRatioStrings);
2040      itemOptionsDisplayBoolShowMapTitle.at20 = gShowMapTitle;
2041      itemOptionsDisplayBoolMessages.at20 = gMessageState;
2042      itemOptionsDisplayBoolWidescreen.at20 = r_usenewaspect;
2043      itemOptionsDisplayWeaponSelect.m_nFocus = gShowWeaponSelect % ARRAY_SSIZE(pzWeaponSelectStrings);
2044  
2045      menuOptionsDisplayMode.Add(&itemOptionsDisplayModeTitle, false);
2046      menuOptionsDisplayMode.Add(&itemOptionsDisplayModeResolution, true);
2047      // prepare video setup
2048      for (int i = 0; i < validmodecnt; ++i)
2049      {
2050          int j;
2051          for (j = 0; j < gResolutionNum; ++j)
2052          {
2053              if (validmode[i].xdim == gResolution[j].xdim && validmode[i].ydim == gResolution[j].ydim)
2054              {
2055                  gResolution[j].flags |= validmode[i].fs ? RES_FS : RES_WIN;
2056                  Bsnprintf(gResolution[j].name, MAXRESOLUTIONSTRINGLENGTH, "%d x %d%s", gResolution[j].xdim, gResolution[j].ydim, (gResolution[j].flags & RES_FS) ? "" : "Win");
2057                  gResolutionName[j] = gResolution[j].name;
2058                  if (validmode[i].bpp > gResolution[j].bppmax)
2059                      gResolution[j].bppmax = validmode[i].bpp;
2060                  break;
2061              }
2062          }
2063  
2064          if (j == gResolutionNum) // no match found
2065          {
2066              gResolution[j].xdim = validmode[i].xdim;
2067              gResolution[j].ydim = validmode[i].ydim;
2068              gResolution[j].bppmax = validmode[i].bpp;
2069              gResolution[j].flags = validmode[i].fs ? RES_FS : RES_WIN;
2070              Bsnprintf(gResolution[j].name, MAXRESOLUTIONSTRINGLENGTH, "%d x %d%s", gResolution[j].xdim, gResolution[j].ydim, (gResolution[j].flags & RES_FS) ? "" : "Win");
2071              gResolutionName[j] = gResolution[j].name;
2072              ++gResolutionNum;
2073          }
2074      }
2075      SetupVideoModeMenu(NULL);
2076      itemOptionsDisplayModeResolution.SetTextArray(gResolutionName, gResolutionNum, 0);
2077  #ifdef USE_OPENGL
2078      menuOptionsDisplayMode.Add(&itemOptionsDisplayModeRenderer, false);
2079      menuOptionsDisplayMode.Add(&itemOptionsDisplayModePolymost, false);
2080  #endif
2081      menuOptionsDisplayMode.Add(&itemOptionsDisplayModeFullscreen, false);
2082  #ifdef USE_OPENGL
2083      menuOptionsDisplayMode.Add(&itemOptionsDisplayModeVSync, false);
2084  #endif
2085      menuOptionsDisplayMode.Add(&itemOptionsDisplayModeFrameLimit, false);
2086      menuOptionsDisplayMode.Add(&itemOptionsDisplayModeApply, false);
2087      menuOptionsDisplayMode.Add(&itemBloodQAV, false);
2088  
2089  #ifdef USE_OPENGL
2090      itemOptionsDisplayModeRenderer.pPreDrawCallback = PreDrawVideoModeMenu;
2091      itemOptionsDisplayModePolymost.bEnable = videoGetRenderMode() == REND_POLYMOST;
2092  #endif
2093      itemOptionsDisplayModeFullscreen.pPreDrawCallback = PreDrawVideoModeMenu;
2094  
2095      menuOptionsDisplayColor.Add(&itemOptionsDisplayColorTitle, false);
2096      menuOptionsDisplayColor.Add(&itemOptionsDisplayColorPaletteCustom, true);
2097      menuOptionsDisplayColor.Add(&itemOptionsDisplayColorPaletteCIEDE2000, false);
2098      menuOptionsDisplayColor.Add(&itemOptionsDisplayColorPaletteGrayscale, false);
2099      menuOptionsDisplayColor.Add(&itemOptionsDisplayColorPaletteInvert, false);
2100      menuOptionsDisplayColor.Add(&itemOptionsDisplayColorGamma, false);
2101      menuOptionsDisplayColor.Add(&itemOptionsDisplayColorContrast, false);
2102      menuOptionsDisplayColor.Add(&itemOptionsDisplayColorSaturation, false);
2103      menuOptionsDisplayColor.Add(&itemOptionsDisplayColorVisibility, false);
2104      menuOptionsDisplayColor.Add(&itemOptionsDisplayColorReset, false);
2105      menuOptionsDisplayColor.Add(&itemBloodQAV, false);
2106  
2107      itemOptionsDisplayColorPaletteCustom.m_nFocus = gCustomPalette % ARRAY_SSIZE(srcCustomPaletteStr);
2108      itemOptionsDisplayColorPaletteCIEDE2000.at20 = gCustomPaletteCIEDE2000;
2109      itemOptionsDisplayColorPaletteGrayscale.at20 = gCustomPaletteGrayscale;
2110      itemOptionsDisplayColorPaletteInvert.m_nFocus = gCustomPaletteInvert % ARRAY_SSIZE(pzInvertPaletteStrings);
2111      itemOptionsDisplayColorContrast.pPreDrawCallback = PreDrawDisplayColor;
2112      itemOptionsDisplayColorSaturation.pPreDrawCallback = PreDrawDisplayColor;
2113  
2114      menuOptionsDisplayView.Add(&itemOptionsDisplayViewTitle, false);
2115      menuOptionsDisplayView.Add(&itemOptionsDisplayViewHudSize, true);
2116      menuOptionsDisplayView.Add(&itemOptionsDisplayViewHudRatio, false);
2117      menuOptionsDisplayView.Add(&itemOptionsDisplayViewBoolCenterHoriz, false);
2118      menuOptionsDisplayView.Add(&itemOptionsDisplayViewBoolSlopeTilting, false);
2119      menuOptionsDisplayView.Add(&itemOptionsDisplayViewBoolViewBobbing, false);
2120      menuOptionsDisplayView.Add(&itemOptionsDisplayViewBoolViewSwaying, false);
2121      menuOptionsDisplayView.Add(&itemOptionsDisplayViewWeaponSwaying, false);
2122      menuOptionsDisplayView.Add(&itemOptionsDisplayViewWeaponInterpolation, false);
2123      menuOptionsDisplayView.Add(&itemOptionsDisplayViewBoolInterpolation, false);
2124      menuOptionsDisplayView.Add(&itemOptionsDisplayViewBoolLevelCompleteTime, false);
2125      menuOptionsDisplayView.Add(&itemOptionsDisplayViewBoolPowerupStyle, false);
2126      menuOptionsDisplayView.Add(&itemOptionsDisplayViewSecretMessageStyle, false);
2127      menuOptionsDisplayView.Add(&itemOptionsDisplayViewMirrorMode, false);
2128      menuOptionsDisplayView.Add(&itemOptionsDisplayViewBoolSlowRoomFlicker, false);
2129      menuOptionsDisplayView.Add(&itemBloodQAV, false);
2130      itemOptionsDisplayViewMirrorMode.bDisableForNet = 1;
2131      itemOptionsDisplayViewBoolSlopeTilting.tooltip_pzTextUpper = "";
2132      itemOptionsDisplayViewBoolSlopeTilting.tooltip_pzTextLower = "Tilt view when looking towards slope";
2133      itemOptionsDisplayViewWeaponInterpolation.tooltip_pzTextUpper = "";
2134      itemOptionsDisplayViewWeaponInterpolation.tooltip_pzTextLower = "Interpolate QAV weapon animations (experimental)";
2135      itemOptionsDisplayViewWeaponSwaying.tooltip_pzTextUpper = "";
2136      itemOptionsDisplayViewWeaponSwaying.tooltip_pzTextLower = "Set weapon sway (v1.0x alters tommy cultist behavior)";
2137      itemOptionsDisplayViewBoolInterpolation.tooltip_pzTextUpper = "";
2138      itemOptionsDisplayViewBoolInterpolation.tooltip_pzTextLower = "Set interpolation method (original/integer or modern/float)";
2139      itemOptionsDisplayViewBoolPowerupStyle.tooltip_pzTextUpper = "";
2140      itemOptionsDisplayViewBoolPowerupStyle.tooltip_pzTextLower = "Set the display style for power-ups";
2141      itemOptionsDisplayViewSecretMessageStyle.tooltip_pzTextUpper = "";
2142      itemOptionsDisplayViewSecretMessageStyle.tooltip_pzTextLower = "Set the display style for secrets";
2143      itemOptionsDisplayViewBoolSlowRoomFlicker.tooltip_pzTextUpper = "";
2144      itemOptionsDisplayViewBoolSlowRoomFlicker.tooltip_pzTextLower = "Reduce the speed of flickering sectors (e.g: E1M4)";
2145  
2146      itemOptionsDisplayViewHudRatio.m_nFocus = gHudRatio % ARRAY_SSIZE(pzHudRatioStrings);
2147      itemOptionsDisplayViewBoolCenterHoriz.at20 = gCenterHoriz;
2148      itemOptionsDisplayViewBoolSlopeTilting.at20 = gSlopeTilting;
2149      itemOptionsDisplayViewBoolViewBobbing.at20 = gViewVBobbing;
2150      itemOptionsDisplayViewBoolViewSwaying.at20 = gViewHBobbing;
2151      itemOptionsDisplayViewWeaponSwaying.m_nFocus = gWeaponHBobbing % ARRAY_SSIZE(pzWeaponHBobbingStrings);
2152      itemOptionsDisplayViewWeaponInterpolation.m_nFocus = gWeaponInterpolate % ARRAY_SSIZE(pzWeaponInterpolateStrings);
2153      itemOptionsDisplayViewBoolInterpolation.at20 = gViewInterpolateMethod;
2154      itemOptionsDisplayViewBoolLevelCompleteTime.at20 = gShowCompleteTime;
2155      itemOptionsDisplayViewBoolPowerupStyle.at20 = gPowerupStyle;
2156      itemOptionsDisplayViewSecretMessageStyle.m_nFocus = gSecretStyle % ARRAY_SSIZE(pzSecretStyleStrings);
2157      itemOptionsDisplayViewMirrorMode.m_nFocus = r_mirrormode % ARRAY_SSIZE(pzMirrorModeStrings);
2158      itemOptionsDisplayViewBoolSlowRoomFlicker.at20 = gSlowRoomFlicker;
2159  
2160  #ifdef USE_OPENGL
2161      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostTitle, false);
2162      //menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostTextureMode, true);
2163      //menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostAnisotropy, false);
2164      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostTrueColorTextures, true);
2165      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostTexQuality, false);
2166      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostPreloadCache, false);
2167      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostTexCache, false);
2168      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostDetailTex, false);
2169      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostGlowTex, false);
2170      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymost3DModels, false);
2171      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostDeliriumBlur, false);
2172      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostUseColorIndexedTex, false);
2173      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostShadeInterpolation, false);
2174      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostYShearing, false);
2175      menuOptionsDisplayPolymost.Add(&itemOptionsDisplayPolymostRollAngle, false);
2176      menuOptionsDisplayPolymost.Add(&itemBloodQAV, false);
2177  
2178      itemOptionsDisplayPolymostTexQuality.pPreDrawCallback = PreDrawDisplayPolymost;
2179      itemOptionsDisplayPolymostPreloadCache.pPreDrawCallback = PreDrawDisplayPolymost;
2180      itemOptionsDisplayPolymostTexCache.pPreDrawCallback = PreDrawDisplayPolymost;
2181      itemOptionsDisplayPolymostDetailTex.pPreDrawCallback = PreDrawDisplayPolymost;
2182      itemOptionsDisplayPolymostGlowTex.pPreDrawCallback = PreDrawDisplayPolymost;
2183  #endif
2184  
2185      menuOptionsSound.Add(&itemOptionsSoundTitle, false);
2186      menuOptionsSound.Add(&itemOptionsSoundSoundToggle, true);
2187      menuOptionsSound.Add(&itemOptionsSoundMusicToggle, false);
2188      menuOptionsSound.Add(&itemOptionsSoundMonoStereo, false);
2189      menuOptionsSound.Add(&itemOptionsSoundDoppler, false);
2190      menuOptionsSound.Add(&itemOptionsSoundSoundVolume, false);
2191      menuOptionsSound.Add(&itemOptionsSoundMusicVolume, false);
2192      menuOptionsSound.Add(&itemOptionsSoundSampleRate, false);
2193      menuOptionsSound.Add(&itemOptionsSoundNumVoices, false);
2194      menuOptionsSound.Add(&itemOptionsSoundSpeakerAngle, false);
2195      menuOptionsSound.Add(&itemOptionsSoundCalebTalk, false);
2196      menuOptionsSound.Add(&itemOptionsSoundCDToggle, false);
2197      menuOptionsSound.Add(&itemOptionsSoundMusicDevice, false);
2198      menuOptionsSound.Add(&itemOptionsSoundSF2Bank, false);
2199      itemOptionsSoundSpeakerAngle.tooltip_pzTextUpper = "";
2200      itemOptionsSoundSpeakerAngle.tooltip_pzTextLower = "Set left/right speaker offset angle (in degrees)";
2201      itemOptionsSoundCDToggle.tooltip_pzTextUpper = "";
2202      itemOptionsSoundCDToggle.tooltip_pzTextLower = "Use blood##.ogg/flac files in base folder as redbook audio";
2203  #ifdef _WIN32
2204      itemOptionsSoundMusicDevice.tooltip_pzTextUpper = "";
2205      itemOptionsSoundMusicDevice.tooltip_pzTextLower = "For MIDI, use console cmd mus_mme_device # to choose output";
2206  #endif
2207  
2208      menuOptionsSound.Add(&itemOptionsSoundApplyChanges, false);
2209      menuOptionsSound.Add(&itemBloodQAV, false);
2210  
2211      menuOptionsSoundSF2.Add(&itemOptionsSoundSF2Title, true);
2212      menuOptionsSoundSF2.Add(&itemOptionsSoundSF2FS, true);
2213  
2214      menuOptionsPlayer.Add(&itemOptionsPlayerTitle, false);
2215      menuOptionsPlayer.Add(&itemOptionsPlayerName, true);
2216      menuOptionsPlayer.Add(&itemOptionsPlayerSkill, false);
2217      menuOptionsPlayer.Add(&itemOptionsPlayerTeamPreference, false);
2218      menuOptionsPlayer.Add(&itemOptionsPlayerColorPreference, false);
2219      menuOptionsPlayer.Add(&itemOptionsPlayerModel, false);
2220      menuOptionsPlayer.Add(&itemOptionsPlayerBoolShowPlayerNames, false);
2221      menuOptionsPlayer.Add(&itemOptionsPlayerShowWeapons, false);
2222      menuOptionsPlayer.Add(&itemOptionsPlayerTeamsScoreStyle, false);
2223      menuOptionsPlayer.Add(&itemOptionsPlayerChatSound, false);
2224      menuOptionsPlayer.Add(&itemOptionsPlayerColorMsg, false);
2225      menuOptionsPlayer.Add(&itemOptionsPlayerObituaryMsg, false);
2226      menuOptionsPlayer.Add(&itemOptionsPlayerKillMsg, false);
2227      menuOptionsPlayer.Add(&itemOptionsPlayerMultiKill, false);
2228      menuOptionsPlayer.Add(&itemBloodQAV, false);
2229      itemOptionsPlayerSkill.tooltip_pzTextUpper = "Set player's damage scale handicap";
2230      itemOptionsPlayerSkill.tooltip_pzTextLower = "(higher = more damage)";
2231      itemOptionsPlayerTeamPreference.tooltip_pzTextUpper = "Set player's preferred team";
2232      itemOptionsPlayerColorPreference.tooltip_pzTextUpper = "Set player's preferred color";
2233      itemOptionsPlayerColorPreference.tooltip_pzTextLower = "(for bloodbath/co-op mode)";
2234      itemOptionsPlayerModel.tooltip_pzTextUpper = "Set player's sprite model";
2235      itemOptionsPlayerBoolShowPlayerNames.tooltip_pzTextUpper = "Display player's name";
2236      itemOptionsPlayerBoolShowPlayerNames.tooltip_pzTextLower = "over crosshair";
2237      itemOptionsPlayerShowWeapons.tooltip_pzTextUpper = "Display player's weapon";
2238      itemOptionsPlayerShowWeapons.tooltip_pzTextLower = "over their head";
2239      itemOptionsPlayerChatSound.tooltip_pzTextUpper = "Play beep sound for chat messages";
2240      itemOptionsPlayerColorMsg.tooltip_pzTextUpper = "Color player names for chat messages";
2241      itemOptionsPlayerObituaryMsg.tooltip_pzTextUpper = "Use random obituary kill messages";
2242      itemOptionsPlayerKillMsg.tooltip_pzTextUpper = "Show player killed on screen";
2243      itemOptionsPlayerKillMsg.tooltip_pzTextLower = "(for bloodbath/teams mode)";
2244      itemOptionsPlayerMultiKill.tooltip_pzTextUpper = "Show multi kill alerts on screen";
2245      itemOptionsPlayerMultiKill.tooltip_pzTextLower = "(for bloodbath/teams mode)";
2246  
2247      itemOptionsPlayerSkill.m_nFocus = gSkill % ARRAY_SSIZE(pzPlayerSkillStrings);
2248      itemOptionsPlayerTeamPreference.m_nFocus = gPlayerTeamPreference % ARRAY_SSIZE(pzPlayerTeamPreferenceStrings);
2249      itemOptionsPlayerColorPreference.m_nFocus = gPlayerColorPreference % ARRAY_SSIZE(pzPlayerColorPreferenceStrings);
2250      itemOptionsPlayerModel.at20 = gPlayerModel;
2251      itemOptionsPlayerBoolShowPlayerNames.at20 = gShowPlayerNames;
2252      itemOptionsPlayerShowWeapons.m_nFocus = gShowWeapon;
2253      itemOptionsPlayerTeamsScoreStyle.at20 = gTeamsScoreStyle;
2254      itemOptionsPlayerChatSound.at20 = gChatSnd;
2255      itemOptionsPlayerColorMsg.at20 = gColorMsg;
2256      itemOptionsPlayerObituaryMsg.at20 = gKillObituary;
2257      itemOptionsPlayerKillMsg.at20 = gKillMsg;
2258      itemOptionsPlayerMultiKill.m_nFocus = gMultiKill % ARRAY_SSIZE(pzPlayerMultiKillStrings);
2259  }
2260  
2261  void SetupControlsMenu(void)
2262  {
2263      menuOptionsControl.Add(&itemOptionsControlTitle, false);
2264      menuOptionsControl.Add(&itemOptionsControlKeyboard, true);
2265      menuOptionsControl.Add(&itemOptionsControlMouse, false);
2266      menuOptionsControl.Add(&itemOptionsControlRadial, false);
2267      menuOptionsControl.Add(&itemOptionsControlJoystickButtons, false);
2268      menuOptionsControl.Add(&itemOptionsControlJoystickAxes, false);
2269      menuOptionsControl.Add(&itemOptionsControlJoystickMisc, false);
2270      menuOptionsControl.Add(&itemBloodQAV, false);
2271  
2272      menuOptionsControlKeyboard.Add(&itemOptionsControlKeyboardTitle, false);
2273      menuOptionsControlKeyboard.Add(&itemOptionsControlKeyboardSliderTurnSpeed, true);
2274      menuOptionsControlKeyboard.Add(&itemOptionsControlKeyboardCycleTurnAcceleration, false);
2275      menuOptionsControlKeyboard.Add(&itemOptionsControlKeyboardBoolCrouchToggle, false);
2276      menuOptionsControlKeyboard.Add(&itemOptionsControlKeyboardBoolCrouchAuto, false);
2277      menuOptionsControlKeyboard.Add(&itemOptionsControlKeyboardList, false);
2278      menuOptionsControlKeyboard.Add(&itemOptionsControlKeyboardReset, false);
2279      menuOptionsControlKeyboard.Add(&itemOptionsControlKeyboardResetClassic, false);
2280      menuOptionsControlKeyboard.Add(&itemBloodQAV, false);
2281  
2282      itemOptionsControlKeyboardSliderTurnSpeed.nValue = gTurnSpeed;
2283      itemOptionsControlKeyboardCycleTurnAcceleration.m_nFocus = gTurnAcceleration % ARRAY_SSIZE(pzTurnAccelerationStrings);
2284      itemOptionsControlKeyboardBoolCrouchToggle.at20 = gCrouchToggle;
2285      itemOptionsControlKeyboardBoolCrouchAuto.at20 = gCrouchAuto;
2286  
2287      menuKeys.Add(&itemKeysTitle, false);
2288      menuKeys.Add(&itemKeyList, true);
2289      menuKeys.Add(&itemBloodQAV, false);
2290  
2291      menuOptionsControlMouse.Add(&itemOptionsControlMouseTitle, false);
2292      menuOptionsControlMouse.Add(&itemOptionsControlMouseButton, true);
2293      menuOptionsControlMouse.Add(&itemOptionsControlMouseSensitivity, false);
2294      menuOptionsControlMouse.Add(&itemOptionsControlMouseAimFlipped, false);
2295      menuOptionsControlMouse.Add(&itemOptionsControlMouseAimMode, false);
2296      menuOptionsControlMouse.Add(&itemOptionsControlMouseVerticalAim, false);
2297      menuOptionsControlMouse.Add(&itemOptionsControlMouseXSensitivity, false);
2298      menuOptionsControlMouse.Add(&itemOptionsControlMouseYSensitivity, false);
2299      menuOptionsControlMouse.Add(&itemBloodQAV, false);
2300  
2301      itemOptionsControlMouseVerticalAim.pPreDrawCallback = PreDrawControlMouse;
2302  
2303      menuOptionsControlMouseButtonAssignment.Add(&itemOptionsControlMouseTitle, false);
2304      for (int i = 0, y = 60; i < MENUMOUSEFUNCTIONS; i++)
2305      {
2306          pItemOptionsControlMouseButton[i] = new CGameMenuItemZCycle(MenuMouseNames[i], 3, 66, y, 180, 0, SetMouseButton, pzGamefuncsStrings, NUMGAMEFUNCTIONS+1, 0, true);
2307          dassert(pItemOptionsControlMouseButton[i] != NULL);
2308          menuOptionsControlMouseButtonAssignment.Add(pItemOptionsControlMouseButton[i], i == 0);
2309          y += 10;
2310      }
2311      menuOptionsControlMouseButtonAssignment.Add(&itemBloodQAV, false);
2312  
2313      menuOptionsControlRadial.Add(&itemOptionsControlRadialTitle, false);
2314      menuOptionsControlRadial.Add(&itemOptionsControlRadialToggle, true);
2315      menuOptionsControlRadial.Add(&itemOptionsControlRadialPosition, false);
2316      menuOptionsControlRadial.Add(&itemOptionsControlRadialDimBackground, false);
2317      menuOptionsControlRadial.Add(&itemOptionsControlRadialDimHUD, false);
2318      menuOptionsControlRadial.Add(&itemOptionsControlRadialSlowDown, false);
2319      menuOptionsControlRadial.Add(&itemOptionsControlRadialSound, false);
2320      menuOptionsControlRadial.Add(&itemOptionsControlRadialMouseThreshold, false);
2321      menuOptionsControlRadial.Add(&itemOptionsControlRadialThresholdX, false);
2322      menuOptionsControlRadial.Add(&itemOptionsControlRadialThresholdY, false);
2323      menuOptionsControlRadial.Add(&itemOptionsControlRadialYaw, false);
2324      menuOptionsControlRadial.Add(&itemOptionsControlRadialYawInvert, false);
2325      menuOptionsControlRadial.Add(&itemOptionsControlRadialPitch, false);
2326      menuOptionsControlRadial.Add(&itemOptionsControlRadialPitchInvert, false);
2327      menuOptionsControlRadial.Add(&itemBloodQAV, false);
2328  
2329      itemOptionsControlRadialToggle.m_nFocus = gRadialMenuToggle % ARRAY_SSIZE(zRadialMenuToggle);
2330      itemOptionsControlRadialPosition.nValue = gRadialMenuPosition;
2331      itemOptionsControlRadialDimBackground.at20 = gRadialMenuDimBackground;
2332      itemOptionsControlRadialDimHUD.at20 = gRadialMenuDimHud;
2333      itemOptionsControlRadialSlowDown.at20 = gRadialMenuSlowDown;
2334      itemOptionsControlRadialSound.m_nFocus = gRadialMenuSfx % ARRAY_SSIZE(pzSoundClickStrings);
2335      itemOptionsControlRadialMouseThreshold.nValue = gRadialMenuMouseThreshold;
2336      itemOptionsControlRadialThresholdX.nValue = gRadialMenuThresholdX;
2337      itemOptionsControlRadialThresholdY.nValue = gRadialMenuThresholdY;
2338      itemOptionsControlRadialYaw.m_nFocus = gRadialMenuYaw % ARRAY_SSIZE(zRadialMenuAxes);
2339      itemOptionsControlRadialYawInvert.at20 = gRadialMenuYawInvert;
2340      itemOptionsControlRadialPitch.m_nFocus = gRadialMenuPitch % ARRAY_SSIZE(zRadialMenuAxes);
2341      itemOptionsControlRadialPitchInvert.at20 = gRadialMenuPitchInvert;
2342  }
2343  
2344  void SetupJoystickMenu(void)
2345  {
2346      if (!CONTROL_JoystickEnabled) // joystick disabled, don't bother populating joystick menus
2347      {
2348          itemOptionsControlJoystickButtons.bEnable = 0;
2349          itemOptionsControlJoystickAxes.bEnable = 0;
2350          itemOptionsControlJoystickMisc.bEnable = 0;
2351          return;
2352      }
2353  
2354      menuOptionsControlJoystickMisc.Add(&itemOptionsControlJoystickMiscTitle, false);
2355      menuOptionsControlJoystickMisc.Add(&itemOptionsControlJoystickMiscCrouchToggle, true);
2356      menuOptionsControlJoystickMisc.Add(&itemOptionsControlJoystickMiscCrouchAuto, false);
2357      menuOptionsControlJoystickMisc.Add(&itemOptionsControlJoystickMiscCenterView, false);
2358      menuOptionsControlJoystickMisc.Add(&itemOptionsControlJoystickMiscTargetAimAssist, false);
2359      menuOptionsControlJoystickMisc.Add(&itemOptionsControlJoystickMiscRumble, false);
2360      menuOptionsControlJoystickMisc.Add(&itemBloodQAV, false);
2361      itemOptionsControlJoystickMiscTargetAimAssist.tooltip_pzTextUpper = "Slows camera movement when";
2362      itemOptionsControlJoystickMiscTargetAimAssist.tooltip_pzTextLower = "crosshair is over an enemy";
2363  
2364      itemOptionsControlJoystickMiscCrouchToggle.at20 = gCrouchToggle;
2365      itemOptionsControlJoystickMiscCrouchAuto.at20 = gCrouchAuto;
2366      itemOptionsControlJoystickMiscCenterView.at20 = gCenterViewOnDrop;
2367      itemOptionsControlJoystickMiscTargetAimAssist.at20 = gTargetAimAssist;
2368      itemOptionsControlJoystickMiscRumble.at20 = gSetup.joystickrumble;
2369  
2370      int i = 0, y = 0;
2371      for (int nButton = 0; nButton < joystick.numButtons; nButton++) // store every joystick button/hat name for button list at launch
2372      {
2373          const char *pzButtonName = joyGetName(1, nButton);
2374          if (pzButtonName == NULL) // if we've ran out of button names, store joystick hat names
2375          {
2376              for (int nHats = 0; nHats < (joystick.numHats > 0) * 4; nHats++)
2377              {
2378                  const char *pzHatName = joyGetName(2, nHats);
2379                  if (pzHatName == NULL)
2380                      break;
2381                  Bsnprintf(MenuJoyButtonNames[i++], 64, "%s", pzHatName);
2382                  Bsnprintf(MenuJoyButtonNames[i++], 64, "Double %s", pzHatName);
2383              }
2384              break;
2385          }
2386          Bsnprintf(MenuJoyButtonNames[i++], 64, "%s", pzButtonName);
2387          Bsnprintf(MenuJoyButtonNames[i++], 64, "Double %s", pzButtonName);
2388      }
2389      const int nMaxJoyButtons = i;
2390  
2391      i = 0;
2392      for (int nAxis = 0; nAxis < joystick.numAxes; nAxis++) // store every joystick axes for axes list at launch
2393      {
2394          const char *pzAxisName = joyGetName(0, nAxis);
2395          if (pzAxisName == NULL) // if we've ran out of axes names, stop
2396              break;
2397          Bsnprintf(MenuJoyAxisNames[i++], 64, "%s", pzAxisName);
2398      }
2399      const int nMaxJoyAxes = i;
2400  
2401      if (nMaxJoyButtons <= 0) // joystick has no buttons, disable button menu
2402      {
2403          itemOptionsControlJoystickButtons.bEnable = 0;
2404      }
2405      else
2406      {
2407          i = 0;
2408          for (int nPage = 0; nPage < MAXJOYSTICKBUTTONPAGES; nPage++) // create lists of joystick button items
2409          {
2410              y = 35;
2411              menuOptionsControlJoystickButtonAssignment[nPage].Add(&itemJoyButtonsTitle, false);
2412              for (int nButton = 0; nButton < JOYSTICKITEMSPERPAGE; nButton++) // populate button list
2413              {
2414                  pItemOptionsControlJoyButton[nPage][nButton] = new CGameMenuItemZCycle(MenuJoyButtonNames[i], 3, 66, y, 180, 0, SetJoyButton, pzGamefuncsStrings, NUMGAMEFUNCTIONS+1, 0, true);
2415                  dassert(pItemOptionsControlJoyButton[nPage][nButton] != NULL);
2416                  menuOptionsControlJoystickButtonAssignment[nPage].Add(pItemOptionsControlJoyButton[nPage][nButton], nButton == 0);
2417                  y += 9;
2418                  i++;
2419                  if (i >= nMaxJoyButtons) // if we've reached the total number of buttons, stop populating list
2420                      break;
2421              }
2422              if (i < nMaxJoyButtons) // if we still have more buttons to list, add next page menu item at bottom of page
2423              {
2424                  pItemOptionsControlJoyButtonNextPage[nPage] = new CGameMenuItemChain("NEXT PAGE", 3, 0, 182, 320, 1, &menuOptionsControlJoystickButtonAssignment[nPage+1], -1, NULL, 0);
2425                  dassert(pItemOptionsControlJoyButtonNextPage[nPage] != NULL);
2426                  menuOptionsControlJoystickButtonAssignment[nPage].Add(pItemOptionsControlJoyButtonNextPage[nPage], false);
2427              }
2428              menuOptionsControlJoystickButtonAssignment[nPage].Add(&itemBloodQAV, false);
2429          }
2430      }
2431  
2432      if (nMaxJoyAxes <= 0) // joystick has no axes, disable axis menu
2433      {
2434          itemOptionsControlJoystickAxes.bEnable = 0;
2435          return;
2436      }
2437  
2438      for (int nAxis = 0; nAxis < (int)ARRAY_SIZE(pItemOptionsControlJoystickAxis); nAxis++) // set all possible axis items to null (used for button setup)
2439          pItemOptionsControlJoystickAxis[nAxis] = NULL;
2440  
2441      y = 40;
2442      const char bUseBigFont = nMaxJoyAxes <= 6;
2443      menuOptionsControlJoystickListAxes.Add(&itemJoyAxesTitle, false);
2444      for (int nAxis = 0; nAxis < nMaxJoyAxes; nAxis++) // create list of axes for joystick axis menu
2445      {
2446          pItemOptionsControlJoystickAxis[nAxis] = new CGameMenuItemChain(MenuJoyAxisNames[nAxis], bUseBigFont ? 1 : 3, 66, y, 180, 0, &menuOptionsControlJoystickAxis[nAxis], -1, SetupJoystickAxisHeatmap, 0);
2447          dassert(pItemOptionsControlJoystickAxis[nAxis] != NULL);
2448          menuOptionsControlJoystickListAxes.Add(pItemOptionsControlJoystickAxis[nAxis], nAxis == 0);
2449          y += bUseBigFont ? 20 : 10;
2450      }
2451      menuOptionsControlJoystickListAxes.Add(&itemBloodQAV, false);
2452  
2453      for (int nAxis = 0; nAxis < nMaxJoyAxes; nAxis++) // create settings for each listed joystick axis
2454      {
2455          y = 40;
2456          menuOptionsControlJoystickAxis[nAxis].Add(&itemJoyAxesTitle, false);
2457          pItemOptionsControlJoystickAxisName[nAxis] = new CGameMenuItemTitle(MenuJoyAxisNames[nAxis], 3, 160, y, -1); // get axis name
2458          dassert(pItemOptionsControlJoystickAxisName[nAxis] != NULL);
2459          menuOptionsControlJoystickAxis[nAxis].Add(pItemOptionsControlJoystickAxisName[nAxis], false);
2460          y += 10;
2461          pItemOptionsControlJoystickAxisScale[nAxis] = new CGameMenuItemSlider("AXIS SCALE:", 1, 18, y, 280, &JoystickAnalogueScale[nAxis], fix16_from_int(0), fix16_from_float(2.f), fix16_from_float(0.025f), SetJoystickScale, -1, -1, kMenuSliderQ16); // get axis scale
2462          dassert(pItemOptionsControlJoystickAxisScale[nAxis] != NULL);
2463          menuOptionsControlJoystickAxis[nAxis].Add(pItemOptionsControlJoystickAxisScale[nAxis], true);
2464          y += 22;
2465          pItemOptionsControlJoystickAxisAnalogue[nAxis] = new CGameMenuItemZCycle("ANALOG:", 1, 18, y, 280, 0, SetJoystickAnalogue, zJoystickAnalogue, ARRAY_SSIZE(zJoystickAnalogue), 0); // get analog function
2466          dassert(pItemOptionsControlJoystickAxisAnalogue[nAxis] != NULL);
2467          menuOptionsControlJoystickAxis[nAxis].Add(pItemOptionsControlJoystickAxisAnalogue[nAxis], false);
2468          y += 17;
2469          pItemOptionsControlJoystickAxisAnalogueInvert[nAxis] = new CGameMenuItemZBool("ANALOG INVERT:", 1, 18, y, 280, false, SetJoystickAnalogueInvert, NULL, NULL); // get analog function
2470          dassert(pItemOptionsControlJoystickAxisAnalogueInvert[nAxis] != NULL);
2471          menuOptionsControlJoystickAxis[nAxis].Add(pItemOptionsControlJoystickAxisAnalogueInvert[nAxis], false);
2472          y += 17;
2473          pItemOptionsControlJoystickAxisDigitalPos[nAxis] = new CGameMenuItemZCycle("DIGITAL +:", 1, 18, y, 280, 0, SetJoystickDigitalPos, pzGamefuncsStrings, NUMGAMEFUNCTIONS+1, 0, true); // get digital function
2474          dassert(pItemOptionsControlJoystickAxisDigitalPos[nAxis] != NULL);
2475          menuOptionsControlJoystickAxis[nAxis].Add(pItemOptionsControlJoystickAxisDigitalPos[nAxis], false);
2476          y += 17;
2477          pItemOptionsControlJoystickAxisDigitalNeg[nAxis] = new CGameMenuItemZCycle("DIGITAL -:", 1, 18, y, 280, 0, SetJoystickDigitalNeg, pzGamefuncsStrings, NUMGAMEFUNCTIONS+1, 0, true); // get digital function
2478          dassert(pItemOptionsControlJoystickAxisDigitalNeg[nAxis] != NULL);
2479          menuOptionsControlJoystickAxis[nAxis].Add(pItemOptionsControlJoystickAxisDigitalNeg[nAxis], false);
2480          y += 22;
2481          pItemOptionsControlJoystickAxisDeadzone[nAxis] = new CGameMenuItemSlider("DEAD ZONE:", 1, 18, y, 220, &JoystickAnalogueDead[nAxis], fix16_from_int(0), fix16_from_float(0.5f), fix16_from_float(0.025f), SetJoystickDeadzone, -1, -1, kMenuSliderPercent); // get dead size
2482          dassert(pItemOptionsControlJoystickAxisDeadzone[nAxis] != NULL);
2483          menuOptionsControlJoystickAxis[nAxis].Add(pItemOptionsControlJoystickAxisDeadzone[nAxis], false);
2484          y += 17;
2485          pItemOptionsControlJoystickAxisSaturate[nAxis] = new CGameMenuItemSlider("SATURATE:", 1, 18, y, 220, &JoystickAnalogueSaturate[nAxis], fix16_from_int(0), fix16_from_float(0.5f), fix16_from_float(0.025f), SetJoystickSaturate, -1, -1, kMenuSliderPercent); // get saturate
2486          dassert(pItemOptionsControlJoystickAxisSaturate[nAxis] != NULL);
2487          menuOptionsControlJoystickAxis[nAxis].Add(pItemOptionsControlJoystickAxisSaturate[nAxis], false);
2488          y += 17;
2489          pItemOptionsControlJoystickAxisSnapZone[nAxis] = new CGameMenuItemSlider("SNAP ZONE:", 1, 18, y, 220, &JoystickAnalogueSnap[nAxis], fix16_from_int(0), fix16_from_float(0.5f), fix16_from_float(0.05f), SetJoystickSnapZone, -1, -1, kMenuSliderPercent); // get snap axis zone
2490          dassert(pItemOptionsControlJoystickAxisSnapZone[nAxis] != NULL);
2491          if (CONTROL_GetControllerAxisIsTwinAxisStick(nAxis)) // only add for analog stick axis
2492              menuOptionsControlJoystickAxis[nAxis].Add(pItemOptionsControlJoystickAxisSnapZone[nAxis], false);
2493          menuOptionsControlJoystickAxis[nAxis].Add(&ItemOptionsControlJoystickAxisHeatmapPic, false);
2494          menuOptionsControlJoystickAxis[nAxis].Add(&itemBloodQAV, false);
2495      }
2496      ItemOptionsControlJoystickAxisHeatmapPic.bEnable = 0;
2497  }
2498  
2499  void SetupMenus(void)
2500  {
2501      // prepare gamefuncs and keys
2502      pzGamefuncsStrings[0] = MenuGameFuncNone;
2503      nGamefuncsValues[0] = -1;
2504      int k = 1;
2505      for (int i = 0; i < NUMGAMEFUNCTIONS; ++i)
2506      {
2507          Bstrcpy(MenuGameFuncs[i], gamefunctions[i]);
2508  
2509          for (int j = 0; j < MAXGAMEFUNCLEN; ++j)
2510              if (MenuGameFuncs[i][j] == '_')
2511                  MenuGameFuncs[i][j] = ' ';
2512  
2513          if (gamefunctions[i][0] != '\0')
2514          {
2515              pzGamefuncsStrings[k] = MenuGameFuncs[i];
2516              nGamefuncsValues[k] = i;
2517              ++k;
2518          }
2519      }
2520  
2521      nGamefuncsNum = k;
2522  
2523      SetupLoadingScreen();
2524      SetupMessagesMenu();
2525      SetupSaveGameMenu();
2526      SetupLoadGameMenu();
2527      SetupCreditsMenu();
2528      SetupHelpMenu();
2529      SetupDifficultyMenu();
2530      SetupEpisodeMenu();
2531      SetupMainMenu();
2532      SetupMainMenuWithSave();
2533      SetupFirstLaunchMenu();
2534      SetupNetStartMenu();
2535      SetupQuitMenu();
2536  
2537      SetupOptionsMenu();
2538      SetupControlsMenu();
2539      SetupJoystickMenu();
2540      SetupNetworkMenu();
2541  }
2542  
2543  void UpdateNetworkMenus(void)
2544  {
2545      if (gGameOptions.nGameType != kGameTypeSinglePlayer)
2546      {
2547          itemMain1.at24 = &menuNetStart;
2548          itemMain1.at28 = 2;
2549      }
2550      else
2551      {
2552          itemMain1.at24 = &menuEpisode;
2553          itemMain1.at28 = -1;
2554      }
2555      if (gGameOptions.nGameType != kGameTypeSinglePlayer)
2556      {
2557          itemMainSave1.at24 = &menuNetStart;
2558          itemMainSave1.at28 = 2;
2559      }
2560      else
2561      {
2562          itemMainSave1.at24 = &menuEpisode;
2563          itemMainSave1.at28 = -1;
2564      }
2565  }
2566  
2567  void SetMonoStereo(CGameMenuItemZBool *pItem)
2568  {
2569      gStereo = pItem->at20;
2570      itemOptionsSoundDoppler.bEnable = gStereo;
2571  }
2572  
2573  void SetVoxels(CGameMenuItemZBool *pItem)
2574  {
2575      usevoxels = pItem->at20;
2576  }
2577  
2578  void SetCrosshair(CGameMenuItemZCycle *pItem)
2579  {
2580      gAimReticle = pItem->m_nFocus % ARRAY_SSIZE(pzCrosshairStrings);
2581  }
2582  
2583  void ResetKeys(CGameMenuItemChain *)
2584  {
2585      CONFIG_SetDefaultKeys(keydefaults);
2586  }
2587  
2588  void ResetKeysClassic(CGameMenuItemChain *)
2589  {
2590      CONFIG_SetDefaultKeys(oldkeydefaults);
2591  }
2592  
2593  ////
2594  void SetQuadDamagePowerup(CGameMenuItemZBool* pItem)
2595  {
2596      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2597          gQuadDamagePowerup = pItem->at20;
2598          gGameOptions.bQuadDamagePowerup = gQuadDamagePowerup;
2599      } else {
2600          pItem->at20 = gQuadDamagePowerup;
2601      }
2602  }
2603  
2604  void SetDamageInvul(CGameMenuItemZCycle* pItem)
2605  {
2606      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2607          gDamageInvul = pItem->m_nFocus % ARRAY_SSIZE(pzDamageInvulBehaviorStrings);
2608          gGameOptions.nDamageInvul = gDamageInvul;
2609      } else {
2610          pItem->m_nFocus = gDamageInvul % ARRAY_SSIZE(pzDamageInvulBehaviorStrings);
2611      }
2612  }
2613  
2614  void SetProjectileBehavior(CGameMenuItemZCycle *pItem)
2615  {
2616      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2617          gProjectileBehavior = pItem->m_nFocus % ARRAY_SSIZE(pzProjectileBehaviorStrings);
2618          gGameOptions.nProjectileBehavior = gProjectileBehavior;
2619      } else {
2620          pItem->m_nFocus = gProjectileBehavior % ARRAY_SSIZE(pzProjectileBehaviorStrings);
2621      }
2622  }
2623  
2624  void SetNapalmFalloff(CGameMenuItemZBool *pItem)
2625  {
2626      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2627          gNapalmFalloff = pItem->at20;
2628          gGameOptions.bNapalmFalloff = gNapalmFalloff;
2629      } else {
2630          pItem->at20 = !!gNapalmFalloff;
2631      }
2632  }
2633  
2634  void SetEnemyBehavior(CGameMenuItemZCycle *pItem)
2635  {
2636      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2637          gEnemyBehavior = pItem->m_nFocus % ARRAY_SSIZE(pzEnemyBehaviorStrings);
2638          gGameOptions.nEnemyBehavior = gEnemyBehavior;
2639      } else {
2640          pItem->m_nFocus = gEnemyBehavior % ARRAY_SSIZE(pzEnemyBehaviorStrings);
2641      }
2642  }
2643  
2644  void SetEnemyRandomTNT(CGameMenuItemZBool* pItem)
2645  {
2646      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2647          gEnemyRandomTNT = pItem->at20;
2648          gGameOptions.bEnemyRandomTNT = gEnemyRandomTNT;
2649      } else {
2650          pItem->at20 = !!gEnemyRandomTNT;
2651      }
2652  }
2653  
2654  void SetWeaponsVer(CGameMenuItemZCycle* pItem)
2655  {
2656      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2657          gWeaponsVer = pItem->m_nFocus % ARRAY_SSIZE(pzWeaponsVersionStrings);
2658          gGameOptions.nWeaponsVer = gWeaponsVer;
2659      } else {
2660          pItem->m_nFocus = gWeaponsVer % ARRAY_SSIZE(pzWeaponsVersionStrings);
2661      }
2662  }
2663  
2664  void SetAmmoScale(CGameMenuItemZCycle *pItem)
2665  {
2666      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2667          gAmmoScale = pItem->m_nFocus % ARRAY_SSIZE(pzAmmoScaleStrings);
2668          gGameOptions.nAmmoScale = gAmmoScale;
2669      } else {
2670          pItem->m_nFocus = gAmmoScale % ARRAY_SSIZE(pzAmmoScaleStrings);
2671      }
2672  }
2673  
2674  void SetSectorBehavior(CGameMenuItemZBool *pItem)
2675  {
2676      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2677          gSectorBehavior = pItem->at20;
2678          gGameOptions.bSectorBehavior = gSectorBehavior;
2679      } else {
2680          pItem->at20 = !!gSectorBehavior;
2681      }
2682  }
2683  
2684  void SetHitscanProjectiles(CGameMenuItemZCycle *pItem)
2685  {
2686      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2687          gHitscanProjectiles = pItem->m_nFocus % ARRAY_SSIZE(pzHitscanProjectilesStrings);
2688          gGameOptions.nHitscanProjectiles = gHitscanProjectiles;
2689      } else {
2690          pItem->m_nFocus = gHitscanProjectiles % ARRAY_SSIZE(pzHitscanProjectilesStrings);
2691      }
2692  }
2693  
2694  void SetGoreMode(CGameMenuItemZCycle *pItem)
2695  {
2696      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2697          gGoreBehavior = pItem->m_nFocus % ARRAY_SSIZE(pzGoreStrings);
2698          gGameOptions.nGoreBehavior = gGoreBehavior;
2699      } else {
2700          pItem->m_nFocus = gGoreBehavior % ARRAY_SSIZE(pzGoreStrings);
2701      }
2702  }
2703  
2704  void SetPlayerSpeed(CGameMenuItemZCycle *pItem)
2705  {
2706      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2707          gPlayerModSpeed = pItem->m_nFocus % ARRAY_SSIZE(pzPlayerSpeeds);
2708          gGameOptions.nPlayerSpeed = gPlayerModSpeed;
2709      } else {
2710          pItem->m_nFocus = gPlayerModSpeed % ARRAY_SSIZE(pzPlayerSpeeds);
2711      }
2712  }
2713  
2714  void SetRandomizerMode(CGameMenuItemZCycle *pItem)
2715  {
2716      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1)) {
2717          gRandomizerMode = pItem->m_nFocus % ARRAY_SSIZE(pzRandomizerModeStrings);
2718          gGameOptions.nRandomizerMode = gRandomizerMode;
2719      } else {
2720          pItem->m_nFocus = gRandomizerMode % ARRAY_SSIZE(pzRandomizerModeStrings);
2721      }
2722  }
2723  
2724  void SetRandomizerSeed(CGameMenuItemZEdit *pItem, CGameMenuEvent *pEvent)
2725  {
2726      UNREFERENCED_PARAMETER(pItem);
2727      UNREFERENCED_PARAMETER(pEvent);
2728      Bstrncpy(gzRandomizerSeed, szRandomizerSeedMenu, sizeof(gzRandomizerSeed));
2729      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1))
2730          Bstrncpy(gGameOptions.szRandomizerSeed, gzRandomizerSeed, sizeof(gGameOptions.szRandomizerSeed));
2731  }
2732  ////
2733  
2734  void SetHudSize(CGameMenuItemSlider *pItem)
2735  {
2736      gViewSize = pItem->nValue;
2737      viewResizeView(gViewSize);
2738  }
2739  
2740  void SetHudRatio(CGameMenuItemZCycle *pItem)
2741  {
2742      gHudRatio = pItem->m_nFocus % ARRAY_SSIZE(pzHudRatioStrings);
2743      viewResizeView(gViewSize);
2744  }
2745  
2746  void SetCenterHoriz(CGameMenuItemZBool *pItem)
2747  {
2748      gCenterHoriz = pItem->at20;
2749  }
2750  
2751  void SetSlopeTilting(CGameMenuItemZBool *pItem)
2752  {
2753      gSlopeTilting = pItem->at20;
2754  }
2755  
2756  void SetViewBobbing(CGameMenuItemZBool *pItem)
2757  {
2758      gViewVBobbing = pItem->at20;
2759  }
2760  
2761  void SetViewSwaying(CGameMenuItemZBool *pItem)
2762  {
2763      gViewHBobbing = pItem->at20;
2764  }
2765  
2766  void SetWeaponSwaying(CGameMenuItemZCycle *pItem)
2767  {
2768      gWeaponHBobbing = pItem->m_nFocus % ARRAY_SSIZE(pzWeaponHBobbingStrings);
2769      if (!gDemo.bRecording && !gDemo.bPlaying)
2770      {
2771          if ((numplayers > 1) || (gGameOptions.nGameType != kGameTypeSinglePlayer)) // if multiplayer session is active
2772          {
2773              netBroadcastPlayerInfoUpdate(myconnectindex);
2774              return;
2775          }
2776          gProfile[myconnectindex].nWeaponHBobbing = gWeaponHBobbing;
2777          netBroadcastPlayerInfo(myconnectindex);
2778      }
2779  }
2780  
2781  void SetWeaponInterpolate(CGameMenuItemZCycle *pItem)
2782  {
2783      gWeaponInterpolate = pItem->m_nFocus % ARRAY_SSIZE(pzWeaponInterpolateStrings);
2784  }
2785  
2786  void SetViewInterpolate(CGameMenuItemZBool *pItem)
2787  {
2788      gViewInterpolateMethod = pItem->at20;
2789  }
2790  
2791  void SetLevelCompleteTime(CGameMenuItemZBool *pItem)
2792  {
2793      gShowCompleteTime = pItem->at20;
2794  }
2795  
2796  void SetMirrorMode(CGameMenuItemZCycle *pItem)
2797  {
2798      r_mirrormode = pItem->m_nFocus % ARRAY_SSIZE(pzMirrorModeStrings);
2799  }
2800  
2801  void SetSlowRoomFlicker(CGameMenuItemZBool *pItem)
2802  {
2803      gSlowRoomFlicker = pItem->at20;
2804  }
2805  
2806  void SetMusicVol(CGameMenuItemSlider *pItem)
2807  {
2808      sndSetMusicVolume(pItem->nValue);
2809  }
2810  
2811  void SetSoundVol(CGameMenuItemSlider *pItem)
2812  {
2813      sndSetFXVolume(pItem->nValue);
2814  }
2815  
2816  void SetCDVol(CGameMenuItemSlider *pItem)
2817  {
2818      UNREFERENCED_PARAMETER(pItem);
2819      // NUKE-TODO:
2820  }
2821  
2822  void SetMessages(CGameMenuItemZBool *pItem)
2823  {
2824      gMessageState = pItem->at20;
2825      gGameMessageMgr.SetState(gMessageState);
2826  }
2827  
2828  void SetMouseSensitivity(CGameMenuItemSliderFloat *pItem)
2829  {
2830      CONTROL_MouseSensitivity = pItem->fValue;
2831  }
2832  
2833  void SetMouseAimFlipped(CGameMenuItemZBool *pItem)
2834  {
2835      gMouseAimingFlipped = pItem->at20;
2836  }
2837  
2838  void SetTurnSpeed(CGameMenuItemSlider *pItem)
2839  {
2840      gTurnSpeed = pItem->nValue;
2841  }
2842  
2843  void SetTurnAcceleration(CGameMenuItemZCycle *pItem)
2844  {
2845      gTurnAcceleration = pItem->m_nFocus % ARRAY_SSIZE(pzTurnAccelerationStrings);
2846  }
2847  
2848  void SetCenterView(CGameMenuItemZBool *pItem)
2849  {
2850      gCenterViewOnDrop = pItem->at20;
2851  }
2852  
2853  void SetJoystickTargetAimAssist(CGameMenuItemZBool *pItem)
2854  {
2855      gTargetAimAssist = pItem->at20;
2856  }
2857  
2858  void SetRadialMenuToggle(CGameMenuItemZCycle *pItem)
2859  {
2860      gRadialMenuToggle = pItem->m_nFocus % ARRAY_SSIZE(zRadialMenuToggle);
2861  }
2862  
2863  void SetRadialMenuPosition(CGameMenuItemSlider *pItem)
2864  {
2865      gRadialMenuPosition = pItem->nValue;
2866  }
2867  
2868  void SetRadialMenuDimBackground(CGameMenuItemZBool *pItem)
2869  {
2870      gRadialMenuDimBackground = pItem->at20;
2871  }
2872  
2873  void SetRadialMenuDimHUD(CGameMenuItemZBool *pItem)
2874  {
2875      gRadialMenuDimHud = pItem->at20;
2876  }
2877  
2878  void SetRadialMenuSlowDown(CGameMenuItemZBool *pItem)
2879  {
2880      gRadialMenuSlowDown = pItem->at20;
2881  }
2882  
2883  void SetRadialMenuSound(CGameMenuItemZCycle *pItem)
2884  {
2885      gRadialMenuSfx = pItem->m_nFocus % ARRAY_SIZE(pzSoundClickStrings);
2886  }
2887  
2888  void SetRadialMenuMouseThreshold(CGameMenuItemSlider *pItem)
2889  {
2890      gRadialMenuMouseThreshold = pItem->nValue;
2891  }
2892  
2893  void SetRadialMenuThreshold(CGameMenuItemSlider *pItem)
2894  {
2895      UNREFERENCED_PARAMETER(pItem);
2896      gRadialMenuThresholdX = itemOptionsControlRadialThresholdX.nValue;
2897      gRadialMenuThresholdY = itemOptionsControlRadialThresholdY.nValue;
2898  }
2899  
2900  void SetRadialMenuYaw(CGameMenuItemZCycle *pItem)
2901  {
2902      gRadialMenuYaw = pItem->m_nFocus % ARRAY_SIZE(zRadialMenuAxes);
2903  }
2904  
2905  void SetRadialMenuYawInvert(CGameMenuItemZBool *pItem)
2906  {
2907      gRadialMenuYawInvert = pItem->at20;
2908  }
2909  
2910  void SetRadialMenuPitch(CGameMenuItemZCycle *pItem)
2911  {
2912      gRadialMenuPitch = pItem->m_nFocus % ARRAY_SIZE(zRadialMenuAxes);
2913  }
2914  
2915  void SetRadialMenuPitchInvert(CGameMenuItemZBool *pItem)
2916  {
2917      gRadialMenuPitchInvert = pItem->at20;
2918  }
2919  
2920  void SetJoystickRumble(CGameMenuItemZBool *pItem)
2921  {
2922      gSetup.joystickrumble = pItem->at20;
2923  }
2924  
2925  void SetCrouchToggle(CGameMenuItemZBool *pItem)
2926  {
2927      gCrouchToggle = itemOptionsControlKeyboardBoolCrouchToggle.at20 = itemOptionsControlJoystickMiscCrouchToggle.at20 = pItem->at20;
2928  }
2929  
2930  void SetCrouchAuto(CGameMenuItemZBool *pItem)
2931  {
2932      gCrouchAuto = itemOptionsControlKeyboardBoolCrouchAuto.at20 = itemOptionsControlJoystickMiscCrouchAuto.at20 = pItem->at20;
2933  }
2934  
2935  void SetAutoAim(CGameMenuItemZCycle *pItem)
2936  {
2937      gAutoAim = pItem->m_nFocus;
2938      if (!gDemo.bRecording && !gDemo.bPlaying)
2939      {
2940          if ((numplayers > 1) || (gGameOptions.nGameType != kGameTypeSinglePlayer)) // if multiplayer session is active
2941          {
2942              netBroadcastPlayerInfoUpdate(myconnectindex);
2943              return;
2944          }
2945          gProfile[myconnectindex].nAutoAim = gAutoAim;
2946          netBroadcastPlayerInfo(myconnectindex);
2947      }
2948  }
2949  
2950  void SetAutoAimRange(CGameMenuItemSlider *pItem)
2951  {
2952      gAutoAimRange = pItem->nValue;
2953  }
2954  
2955  void SetAutoRun(CGameMenuItemZBool *pItem)
2956  {
2957      gAutoRun = pItem->at20;
2958  }
2959  
2960  void SetLevelStats(CGameMenuItemZCycle *pItem)
2961  {
2962      gLevelStats = pItem->m_nFocus % ARRAY_SSIZE(pzStatsPowerupRatioStrings);
2963      itemOptionsDisplayLevelStatsOnAutomap.bEnable = !!gLevelStats;
2964      viewResizeView(gViewSize);
2965  }
2966  
2967  void SetLevelStatsOnAutomap(CGameMenuItemZBool *pItem)
2968  {
2969      gLevelStatsOnlyOnMap = pItem->at20;
2970  }
2971  
2972  void SetPowerupDuration(CGameMenuItemZCycle* pItem)
2973  {
2974      gPowerupDuration = pItem->m_nFocus % ARRAY_SSIZE(pzStatsPowerupRatioStrings);
2975      viewResizeView(gViewSize);
2976  }
2977  
2978  void SetPowerupStyle(CGameMenuItemZBool* pItem)
2979  {
2980      gPowerupStyle = pItem->at20;
2981  }
2982  
2983  void SetSecretStyle(CGameMenuItemZCycle *pItem)
2984  {
2985      gSecretStyle = pItem->m_nFocus % ARRAY_SSIZE(pzSecretStyleStrings);
2986  }
2987  
2988  void SetShowMapTitle(CGameMenuItemZBool* pItem)
2989  {
2990      gShowMapTitle = pItem->at20;
2991  }
2992  
2993  void SetWeaponSwitch(CGameMenuItemZCycle *pItem)
2994  {
2995      gWeaponSwitch = pItem->m_nFocus % ARRAY_SSIZE(pzWeaponSwitchStrings);
2996      if (!gDemo.bRecording && !gDemo.bPlaying)
2997      {
2998          if ((numplayers > 1) || (gGameOptions.nGameType != kGameTypeSinglePlayer)) // if multiplayer session is active
2999          {
3000              netBroadcastPlayerInfoUpdate(myconnectindex);
3001              return;
3002          }
3003          gProfile[myconnectindex].nWeaponSwitch = gWeaponSwitch;
3004          netBroadcastPlayerInfo(myconnectindex);
3005      }
3006  }
3007  
3008  void SetWeaponFastSwitch(CGameMenuItemZBool *pItem)
3009  {
3010      gWeaponFastSwitch = pItem->at20;
3011      if (!gDemo.bRecording && !gDemo.bPlaying)
3012      {
3013          if ((numplayers > 1) || (gGameOptions.nGameType != kGameTypeSinglePlayer)) // if multiplayer session is active
3014          {
3015              netBroadcastPlayerInfoUpdate(myconnectindex);
3016              return;
3017          }
3018          gProfile[myconnectindex].bWeaponFastSwitch = gWeaponFastSwitch;
3019          netBroadcastPlayerInfo(myconnectindex);
3020      }
3021  }
3022  
3023  void SetAutosaveMode(CGameMenuItemZCycle *pItem)
3024  {
3025      gAutosave = pItem->m_nFocus % ARRAY_SSIZE(pzAutosaveModeStrings);
3026  
3027      itemLoadGameAutosaveStart.bEnable = gAutosave != 0; // remove autosave slots if autosaves are disabled
3028      itemLoadGameAutosaveStart.bNoDraw = gAutosave == 0;
3029      itemSaveGameAutosaveStart.bNoDraw = gAutosave == 0;
3030      itemLoadGameAutosaveKey.bEnable = gAutosave == 2;
3031      itemLoadGameAutosaveKey.bNoDraw = gAutosave != 2;
3032      itemSaveGameAutosaveKey.bNoDraw = gAutosave != 2;
3033  }
3034  
3035  void SetLockSaving(CGameMenuItemZBool *pItem)
3036  {
3037      gLockManualSaving = pItem->at20;
3038  
3039      itemMainSave3.bEnable = !gLockManualSaving; // hide save option in main menu if lock saving mode is set
3040  }
3041  
3042  void SetRestoreLastSave(CGameMenuItemZBool *pItem)
3043  {
3044      gRestoreLastSave = pItem->at20;
3045  }
3046  
3047  void SetGameVanillaMode(char nState)
3048  {
3049      gVanilla = nState % ARRAY_SSIZE(pzVanillaModeStrings);
3050      itemOptionsGameWeaponFastSwitch.bEnable = !gVanilla;
3051      itemOptionsGameBoolVanillaMode.m_nFocus = gVanilla % ARRAY_SSIZE(pzVanillaModeStrings);
3052      itemOptionsDisplayViewBoolInterpolation.bEnable = !gVanilla;
3053      itemOptionsDisplayViewSecretMessageStyle.bEnable = !gVanilla;
3054      itemOptionsDisplayWeaponSelect.bEnable = !gVanilla;
3055      itemOptionsChainMutators.bEnable = !gVanilla;
3056      VanillaModeUpdate();
3057  }
3058  
3059  void SetVanillaMode(CGameMenuItemZCycle *pItem)
3060  {
3061      if ((gGameOptions.nGameType == kGameTypeSinglePlayer) && (numplayers == 1))
3062      {
3063          SetGameVanillaMode((char)pItem->m_nFocus);
3064          viewClearInterpolations();
3065          viewResizeView(gViewSize);
3066          gGameMessageMgr.Clear();
3067      }
3068      else
3069      {
3070          pItem->m_nFocus = gVanilla % ARRAY_SSIZE(pzVanillaModeStrings);
3071          viewSetMessage("Vanilla mode is disabled for multiplayer");
3072      }
3073  }
3074  
3075  inline unsigned int SetBannedSprites(char bSinglePlayer)
3076  {
3077      unsigned int uSpriteBannedFlags = BANNED_NONE;
3078  
3079      if (bSinglePlayer)
3080      {
3081          // monsters
3082          if (itemBannedMonstersBats.at20)
3083              uSpriteBannedFlags |= BANNED_BATS;
3084          if (itemBannedMonstersRats.at20)
3085              uSpriteBannedFlags |= BANNED_RATS;
3086          if (itemBannedMonstersFish.at20)
3087              uSpriteBannedFlags |= BANNED_FISH;
3088          if (itemBannedMonstersHands.at20)
3089              uSpriteBannedFlags |= BANNED_HANDS;
3090          if (itemBannedMonstersGhosts.at20)
3091              uSpriteBannedFlags |= BANNED_GHOSTS;
3092          if (itemBannedMonstersSpiders.at20)
3093              uSpriteBannedFlags |= BANNED_SPIDERS;
3094          if (itemBannedMonstersTinyCaleb.at20)
3095              uSpriteBannedFlags |= BANNED_TCALEBS;
3096          if (itemBannedMonstersHellHounds.at20)
3097              uSpriteBannedFlags |= BANNED_HHOUNDS;
3098  
3099          // monster behavior tweaks
3100          if (itemBannedMonstersRatsAttack.at20)
3101              uSpriteBannedFlags |= BANNED_RATS_BITE;
3102          if (itemBannedMonstersMotherSpiderHealth.at20)
3103              uSpriteBannedFlags |= BANNED_MSPIDERS_HP;
3104          if (itemBannedMonstersTchernobogHealth.at20)
3105              uSpriteBannedFlags |= BANNED_TCHERNOBOG_HP;
3106      }
3107      else // load from network monster menu
3108      {
3109          // monsters
3110          if (itemNetMonsterBats.at20)
3111              uSpriteBannedFlags |= BANNED_BATS;
3112          if (itemNetMonsterRats.at20)
3113              uSpriteBannedFlags |= BANNED_RATS;
3114          if (itemNetMonsterFish.at20)
3115              uSpriteBannedFlags |= BANNED_FISH;
3116          if (itemNetMonsterHands.at20)
3117              uSpriteBannedFlags |= BANNED_HANDS;
3118          if (itemNetMonsterGhosts.at20)
3119              uSpriteBannedFlags |= BANNED_GHOSTS;
3120          if (itemNetMonsterSpiders.at20)
3121              uSpriteBannedFlags |= BANNED_SPIDERS;
3122          if (itemNetMonsterTinyCaleb.at20)
3123              uSpriteBannedFlags |= BANNED_TCALEBS;
3124          if (itemNetMonsterHellHounds.at20)
3125              uSpriteBannedFlags |= BANNED_HHOUNDS;
3126  
3127          // monster behavior tweaks
3128          if (itemNetMonsterRatsAttack.at20)
3129              uSpriteBannedFlags |= BANNED_RATS_BITE;
3130          if (itemNetMonsterMotherSpiderHealth.at20)
3131              uSpriteBannedFlags |= BANNED_MSPIDERS_HP;
3132          if (itemNetMonsterTchernobogHealth.at20)
3133              uSpriteBannedFlags |= BANNED_TCHERNOBOG_HP;
3134      }
3135  
3136      // weapons
3137      if (itemBannedItemsFlare.at20)
3138          uSpriteBannedFlags |= BANNED_FLARE;
3139      if (itemBannedItemsShotgun.at20)
3140          uSpriteBannedFlags |= BANNED_SHOTGUN;
3141      if (itemBannedItemsTommyGun.at20)
3142          uSpriteBannedFlags |= BANNED_TOMMYGUN;
3143      if (itemBannedItemsNapalm.at20)
3144          uSpriteBannedFlags |= BANNED_NAPALM;
3145      if (itemBannedItemsTNT.at20)
3146          uSpriteBannedFlags |= BANNED_TNT;
3147      if (itemBannedItemsSpray.at20)
3148          uSpriteBannedFlags |= BANNED_SPRAYCAN;
3149      if (itemBannedItemsTesla.at20)
3150          uSpriteBannedFlags |= BANNED_TESLA;
3151      if (itemBannedItemsLifeLeech.at20)
3152          uSpriteBannedFlags |= BANNED_LIFELEECH;
3153      if (itemBannedItemsVoodoo.at20)
3154          uSpriteBannedFlags |= BANNED_VOODOO;
3155      if (itemBannedItemsProxy.at20)
3156          uSpriteBannedFlags |= BANNED_PROXY;
3157      if (itemBannedItemsRemote.at20)
3158          uSpriteBannedFlags |= BANNED_REMOTE;
3159  
3160      // items
3161      if (itemBannedItemsMedKit.at20)
3162          uSpriteBannedFlags |= BANNED_MEDKIT;
3163      if (itemBannedItemsLifeEssence.at20)
3164          uSpriteBannedFlags |= BANNED_LIFEESSENCE;
3165      if (itemBannedItemsLifeSeed.at20)
3166          uSpriteBannedFlags |= BANNED_LIFESEED;
3167      if (itemBannedItemsSuperArmor.at20)
3168          uSpriteBannedFlags |= BANNED_SUPERARMOR;
3169      if (itemBannedItemsCrystalBall.at20)
3170          uSpriteBannedFlags |= BANNED_CRYSTALBALL;
3171  
3172      // powerups
3173      if (itemBannedItemsJumpBoots.at20)
3174          uSpriteBannedFlags |= BANNED_JUMPBOOTS;
3175      if (itemBannedItemsCloak.at20)
3176          uSpriteBannedFlags |= BANNED_CLOAK;
3177      if (itemBannedItemsDeathMask.at20)
3178          uSpriteBannedFlags |= BANNED_DEATHMASK;
3179      if (itemBannedItemsAkimbo.at20)
3180          uSpriteBannedFlags |= BANNED_AKIMBO;
3181      if (itemBannedItemsReflect.at20)
3182          uSpriteBannedFlags |= BANNED_REFLECT;
3183  
3184      return uSpriteBannedFlags;
3185  }
3186  
3187  short gQuickLoadSlot = kLoadSaveNull;
3188  
3189  void ShowDifficulties()
3190  {
3191      gGameMenuMgr.Push(&menuDifficulty, 3);
3192  }
3193  
3194  void SetMonsters(CGameMenuItemZCycle *pItem)
3195  {
3196      UNREFERENCED_PARAMETER(pItem);
3197      const char bEnable = itemCustomDifficultyMonsterSettings.m_nFocus > 0;
3198      itemCustomDifficultyEnemyDifficulty.bEnable = bEnable;
3199      itemCustomDifficultyEnemyQuantity.bEnable = bEnable;
3200      itemCustomDifficultyEnemyHealth.bEnable = bEnable;
3201      itemCustomDifficultyEnemySpeed.bEnable = bEnable;
3202      itemCustomDifficultyEnemyShuffle.bEnable = bEnable;
3203      itemCustomDifficultyBannedMonsters.bEnable = bEnable;
3204  }
3205  
3206  void SetDifficultyAndStart(CGameMenuItemChain *pItem)
3207  {
3208      gGameOptions.nDifficulty = pItem->at30;
3209      gGameOptions.nMonsterSettings = 1;
3210      gGameOptions.nMonsterRespawnTime = 3600; // default (30 secs)
3211      gGameOptions.nEnemyQuantity = gGameOptions.nDifficulty;
3212      gGameOptions.nEnemyHealth = gGameOptions.nDifficulty;
3213      playerSetSkill(gGameOptions.nDifficulty); // set skill to same value as current difficulty
3214      gGameOptions.nEnemySpeed = 0;
3215      gGameOptions.bEnemyShuffle = false;
3216      gGameOptions.bPitchforkOnly = false;
3217      gGameOptions.bPermaDeath = false;
3218      gGameOptions.uSpriteBannedFlags = BANNED_NONE;
3219      gGameOptions.nLevel = 0;
3220      if (!gVanilla) // don't reset gameflags for vanilla mode
3221          gGameOptions.uGameFlags = kGameFlagNone;
3222      gGameOptions.uNetGameFlags = kNetGameFlagNone;
3223      if (gDemo.bPlaying)
3224          gDemo.StopPlayback();
3225      else if (gDemo.bRecording)
3226          gDemo.Close();
3227      gStartNewGame = true;
3228      gAutosaveInCurLevel = false;
3229      gQuickLoadSlot = kLoadSaveNull;
3230      gCheatMgr.ResetCheats();
3231      if (Bstrlen(gGameOptions.szUserMap))
3232      {
3233          levelAddUserMap(gGameOptions.szUserMap);
3234          levelSetupOptions(gGameOptions.nEpisode, gGameOptions.nLevel);
3235          StartLevel(&gGameOptions);
3236          viewResizeView(gViewSize);
3237      }
3238      gGameMenuMgr.Deactivate();
3239  }
3240  
3241  void SetCustomDifficultyMenu(CGameMenuItemChain *pItem)
3242  {
3243      UNREFERENCED_PARAMETER(pItem);
3244      itemCustomDifficultyStartLevel.nValue = 0;
3245      if (Bstrlen(gGameOptions.szUserMap)) // custom map selected, disable level select cycle item
3246      {
3247          itemCustomDifficultyStartLevel.bEnable = 0;
3248      }
3249      else
3250      {
3251          dassert(gGameOptions.nEpisode >= 0 && gGameOptions.nEpisode < gEpisodeCount);
3252          EPISODEINFO *pEpisodeInfo = &gEpisodeInfo[gGameOptions.nEpisode];
3253          if (pEpisodeInfo->nLevels <= 0)
3254              itemCustomDifficultyStartLevel.bEnable = 0;
3255          else
3256          {
3257              itemCustomDifficultyStartLevel.bEnable = 1;
3258              itemCustomDifficultyStartLevel.nRangeHigh = pEpisodeInfo->nLevels-1;
3259          }
3260      }
3261      itemCustomDifficultyStartLevel.bNoDraw = !itemCustomDifficultyStartLevel.bEnable;
3262  }
3263  
3264  void SetCustomDifficultyAndStart(CGameMenuItemChain *pItem)
3265  {
3266      UNREFERENCED_PARAMETER(pItem);
3267      gGameOptions.nDifficulty = ClipRange(itemCustomDifficultyEnemyDifficulty.nValue, 0, 4);
3268      gGameOptions.nMonsterSettings = ClipRange(itemCustomDifficultyMonsterSettings.m_nFocus, 0, ARRAY_SSIZE(zMonsterStrings)-1);
3269      if (gGameOptions.nMonsterSettings <= 1)
3270          gGameOptions.nMonsterRespawnTime = 3600; // default (30 secs)
3271      else if (gGameOptions.nMonsterSettings == 2)
3272          gGameOptions.nMonsterRespawnTime = 15 * kTicRate; // 15 secs
3273      else
3274          gGameOptions.nMonsterRespawnTime = (gGameOptions.nMonsterSettings - 2) * 30 * kTicRate, gGameOptions.nMonsterSettings = ClipRange(gGameOptions.nMonsterSettings, 0, 2);
3275      gGameOptions.nEnemyQuantity = ClipRange(itemCustomDifficultyEnemyQuantity.nValue, 0, 4);
3276      gGameOptions.nEnemyHealth = ClipRange(itemCustomDifficultyEnemyHealth.nValue, 0, 4);
3277      playerSetSkill(itemCustomDifficultyPlayerDamage.nValue);
3278      gGameOptions.nEnemySpeed = ClipRange(itemCustomDifficultyEnemySpeed.m_nFocus, 0, 4);
3279      gGameOptions.bEnemyShuffle = !!itemCustomDifficultyEnemyShuffle.at20;
3280      gGameOptions.bPitchforkOnly = !!itemCustomDifficultyPitchfork.at20;
3281      gGameOptions.bPermaDeath = !!itemCustomDifficultyPermaDeath.at20;
3282      gGameOptions.uSpriteBannedFlags = SetBannedSprites(1);
3283      gGameOptions.nLevel = 0;
3284      if (!gVanilla) // don't reset gameflags for vanilla mode
3285          gGameOptions.uGameFlags = kGameFlagNone;
3286      gGameOptions.uNetGameFlags = kNetGameFlagNone;
3287      if (gDemo.bPlaying)
3288          gDemo.StopPlayback();
3289      else if (gDemo.bRecording)
3290          gDemo.Close();
3291      gStartNewGame = true;
3292      gAutosaveInCurLevel = false;
3293      gQuickLoadSlot = kLoadSaveNull;
3294      gCheatMgr.ResetCheats();
3295      if (Bstrlen(gGameOptions.szUserMap))
3296      {
3297          levelAddUserMap(gGameOptions.szUserMap);
3298          levelSetupOptions(gGameOptions.nEpisode, gGameOptions.nLevel);
3299          StartLevel(&gGameOptions);
3300          viewResizeView(gViewSize);
3301      }
3302      else if (itemCustomDifficultyStartLevel.nValue > 0)
3303          gGameOptions.nLevel = itemCustomDifficultyStartLevel.nValue;
3304      gGameMenuMgr.Deactivate();
3305  }
3306  
3307  void SetFirstLaunchOptions(CGameMenuItemChain *pItem)
3308  {
3309      gSetup.firstlaunch = 0;
3310      if (pItem == &itemFirstLaunchNotBlood)
3311      {
3312          gGameMenuMgr.Pop(); // close menu
3313          return;
3314      }
3315      if (pItem == &itemFirstLaunchVanilla)
3316      {
3317          gSlopeTilting = 1;
3318          gAimReticle = 0;
3319          gAutoAim = 1;
3320          gAutoRun = 0;
3321          gShowWeapon = 0;
3322          gWeaponSwitch = 1;
3323          SetGameVanillaMode(1);
3324          gAutosave = 0;
3325          gRestoreLastSave = 0;
3326          gPowerupDuration = 0;
3327          gPowerupStyle = 0;
3328          gSecretStyle = 0;
3329          gShowCompleteTime = 0;
3330          gHudRatio = 1;
3331          gViewSize = 5;
3332          viewResizeView(gViewSize);
3333          gShowMapTitle = 0;
3334          gWeaponInterpolate = 0;
3335          gCenterHoriz = 0;
3336      }
3337      else if (pItem == &itemFirstLaunchNBlood)
3338      {
3339          gAimReticle = 0;
3340          gAutoAim = 1;
3341          gAutoRun = 0;
3342          gShowWeapon = 0;
3343          gWeaponSwitch = 1;
3344          gAutosave = 0;
3345          gRestoreLastSave = 0;
3346          gPowerupStyle = 0;
3347          gSecretStyle = 0;
3348          gShowCompleteTime = 0;
3349          gHudRatio = 0;
3350          gViewSize = 2;
3351          viewResizeView(gViewSize);
3352          gCenterHoriz = 0;
3353      }
3354      itemOptionsDisplayViewBoolSlopeTilting.at20 = gSlopeTilting;
3355      itemOptionsDisplayCrosshair.m_nFocus = gAimReticle;
3356      itemOptionsGameCycleAutoAim.m_nFocus = gAutoAim;
3357      itemOptionsGameBoolAutoRun.at20 = !!gAutoRun;
3358      itemOptionsGameWeaponSwitch.m_nFocus = gWeaponSwitch;
3359      itemOptionsGameAutosaveMode.m_nFocus = gAutosave;
3360      itemOptionsGameRestoreLastSave.at20 = gRestoreLastSave;
3361      itemOptionsDisplayPowerupDuration.m_nFocus = gPowerupDuration;
3362      itemOptionsDisplayViewBoolPowerupStyle.at20 = gPowerupStyle;
3363      itemOptionsDisplayViewSecretMessageStyle.m_nFocus = gSecretStyle;
3364      itemOptionsDisplayViewBoolLevelCompleteTime.at20 = gShowCompleteTime;
3365      itemOptionsDisplayViewHudRatio.m_nFocus = gHudRatio;
3366      itemOptionsDisplayViewHudSize.nValue = gViewSize;
3367      itemOptionsDisplayBoolShowMapTitle.at20 = gShowMapTitle;
3368      itemOptionsDisplayViewWeaponInterpolation.m_nFocus = gWeaponInterpolate;
3369      itemOptionsDisplayViewBoolCenterHoriz.at20 = gCenterHoriz;
3370      gGameMenuMgr.Pop(); // close menu
3371  }
3372  
3373  void SetVideoMode(CGameMenuItemChain *pItem)
3374  {
3375      UNREFERENCED_PARAMETER(pItem);
3376      resolution_t p = { xres, yres, fullscreen, bpp, 0 };
3377      int32_t prend = videoGetRenderMode();
3378      int32_t pvsync = vsync;
3379  
3380      int32_t nResolution = itemOptionsDisplayModeResolution.m_nFocus;
3381      resolution_t n = { gResolution[nResolution].xdim, gResolution[nResolution].ydim,
3382                         (gResolution[nResolution].flags & RES_FS) ? itemOptionsDisplayModeFullscreen.at20 : 0,
3383                         (nRendererValues[itemOptionsDisplayModeRenderer.m_nFocus] == REND_CLASSIC) ? 8 : gResolution[nResolution].bppmax, 0 };
3384      int32_t UNUSED(nrend) = nRendererValues[itemOptionsDisplayModeRenderer.m_nFocus];
3385      int32_t nvsync = nVSyncValues[itemOptionsDisplayModeVSync.m_nFocus];
3386  
3387      if (videoSetGameMode(n.flags, n.xdim, n.ydim, n.bppmax, upscalefactor) < 0)
3388      {
3389          if (videoSetGameMode(p.flags, p.xdim, p.ydim, p.bppmax, upscalefactor) < 0)
3390          {
3391              videoSetRenderMode(prend);
3392              ThrowError("Failed restoring old video mode.");
3393          }
3394          else
3395          {
3396              onvideomodechange(p.bppmax > 8);
3397              vsync = videoSetVsync(pvsync);
3398          }
3399      }
3400      else onvideomodechange(n.bppmax > 8);
3401  
3402      viewResizeView(gViewSize);
3403      vsync = videoSetVsync(nvsync);
3404      gSetup.fullscreen = fullscreen;
3405      gSetup.xdim = xres;
3406      gSetup.ydim = yres;
3407      gSetup.bpp = bpp;
3408  
3409  #ifdef USE_OPENGL
3410      itemOptionsDisplayModePolymost.bEnable = videoGetRenderMode() == REND_POLYMOST;
3411  #endif
3412  }
3413  
3414  void SetWidescreen(CGameMenuItemZBool *pItem)
3415  {
3416      r_usenewaspect = pItem->at20;
3417  }
3418  
3419  void SetWeaponSelectMode(CGameMenuItemZCycle *pItem)
3420  {
3421      gShowWeaponSelect = pItem->m_nFocus % ARRAY_SSIZE(pzRandomizerModeStrings);
3422  }
3423  
3424  void SetDetail(CGameMenuItemSlider *pItem)
3425  {
3426      gDetail = pItem->nValue;
3427  }
3428  
3429  void SetFOV(CGameMenuItemSlider *pItem)
3430  {
3431      gFov = pItem->nValue;
3432      viewUpdateSkyRatio();
3433  }
3434  
3435  void SetupVideoModeMenu(CGameMenuItemChain *pItem)
3436  {
3437      UNREFERENCED_PARAMETER(pItem);
3438      for (int i = 0; i < gResolutionNum; i++)
3439      {
3440          if (gSetup.xdim == gResolution[i].xdim && gSetup.ydim == gResolution[i].ydim)
3441          {
3442              itemOptionsDisplayModeResolution.m_nFocus = i;
3443              break;
3444          }
3445      }
3446      itemOptionsDisplayModeFullscreen.at20 = gSetup.fullscreen;
3447  #ifdef USE_OPENGL
3448      for (int i = 0; i < 2; i++)
3449      {
3450          if (videoGetRenderMode() == nRendererValues[i])
3451          {
3452              itemOptionsDisplayModeRenderer.m_nFocus = i;
3453              break;
3454          }
3455      }
3456  #endif
3457      for (int i = 0; i < itemOptionsDisplayModeVSync.m_nItems; i++)
3458      {
3459          if (vsync == nVSyncValues[i])
3460          {
3461              itemOptionsDisplayModeVSync.m_nFocus = i;
3462              break;
3463          }
3464      }
3465      const int kMaxFps = r_maxfps == -1 ? round(refreshfreq) : r_maxfps;
3466      for (int i = 0; i < 8; i++)
3467      {
3468          if (kMaxFps == nFrameLimitValues[i])
3469          {
3470              itemOptionsDisplayModeFrameLimit.m_nFocus = i;
3471              break;
3472          }
3473      }
3474  }
3475  
3476  void PreDrawVideoModeMenu(CGameMenuItem *pItem)
3477  {
3478      if (pItem == &itemOptionsDisplayModeFullscreen)
3479          pItem->bEnable = !!(gResolution[itemOptionsDisplayModeResolution.m_nFocus].flags & RES_FS);
3480  #ifdef USE_OPENGL
3481      else if (pItem == &itemOptionsDisplayModeRenderer)
3482          pItem->bEnable = gResolution[itemOptionsDisplayModeResolution.m_nFocus].bppmax > 8;
3483  #endif
3484  }
3485  
3486  void UpdateVideoModeMenuFrameLimit(CGameMenuItemZCycle *pItem)
3487  {
3488      r_maxfps = nFrameLimitValues[pItem->m_nFocus];
3489      g_frameDelay = calcFrameDelay(r_maxfps);
3490  }
3491  
3492  void UpdateVideoColorMenu(CGameMenuItemSliderFloat *pItem)
3493  {
3494      UNREFERENCED_PARAMETER(pItem);
3495      g_videoGamma = itemOptionsDisplayColorGamma.fValue;
3496      g_videoContrast = itemOptionsDisplayColorContrast.fValue;
3497      g_videoSaturation = itemOptionsDisplayColorSaturation.fValue;
3498      r_ambientlight = itemOptionsDisplayColorVisibility.fValue;
3499      r_ambientlightrecip = 1.f/r_ambientlight;
3500      gBrightness = GAMMA_CALC<<2;
3501      videoSetPalette(gBrightness>>2, gLastPal, 0);
3502  }
3503  
3504  void UpdateVideoPalette(void)
3505  {
3506      scrCustomizePalette(gCustomPalette % ARRAY_SSIZE(srcCustomPaletteStr), gCustomPaletteCIEDE2000, gCustomPaletteGrayscale, gCustomPaletteInvert);
3507      videoSetPalette(gBrightness>>2, gLastPal, 0);
3508  #ifdef USE_OPENGL
3509      if (!r_useindexedcolortextures && (videoGetRenderMode() != REND_CLASSIC))
3510      {
3511          videoResetMode();
3512          if (videoSetGameMode(fullscreen, xres, yres, bpp, upscalefactor))
3513              ThrowError("restartvid: Reset failed...\n");
3514          onvideomodechange(gSetup.bpp>8);
3515      }
3516  #endif
3517  }
3518  
3519  void UpdateVideoPaletteCycleMenu(CGameMenuItemZCycle *pItem)
3520  {
3521      UNREFERENCED_PARAMETER(pItem);
3522      gCustomPalette = itemOptionsDisplayColorPaletteCustom.m_nFocus % ARRAY_SSIZE(srcCustomPaletteStr);
3523      gCustomPaletteInvert = itemOptionsDisplayColorPaletteInvert.m_nFocus % ARRAY_SSIZE(pzInvertPaletteStrings);
3524      UpdateVideoPalette();
3525  }
3526  
3527  void UpdateVideoPaletteBoolMenu(CGameMenuItemZBool *pItem)
3528  {
3529      UNREFERENCED_PARAMETER(pItem);
3530      gCustomPaletteCIEDE2000 = itemOptionsDisplayColorPaletteCIEDE2000.at20;
3531      gCustomPaletteGrayscale = itemOptionsDisplayColorPaletteGrayscale.at20;
3532      UpdateVideoPalette();
3533  }
3534  
3535  void PreDrawDisplayColor(CGameMenuItem *pItem)
3536  {
3537      if (pItem == &itemOptionsDisplayColorContrast)
3538          pItem->bEnable = gammabrightness;
3539      else if (pItem == &itemOptionsDisplayColorSaturation)
3540          pItem->bEnable = gammabrightness;
3541  }
3542  
3543  void ResetVideoColor(CGameMenuItemChain *pItem)
3544  {
3545      UNREFERENCED_PARAMETER(pItem);
3546      g_videoGamma = DEFAULT_GAMMA;
3547      g_videoContrast = DEFAULT_CONTRAST;
3548      g_videoSaturation = DEFAULT_SATURATION;
3549      gBrightness = 0;
3550      r_ambientlight = r_ambientlightrecip = 1.f;
3551      gCustomPalette = itemOptionsDisplayColorPaletteCustom.m_nFocus = 0;
3552      gCustomPaletteCIEDE2000 = itemOptionsDisplayColorPaletteCIEDE2000.at20 = 0;
3553      gCustomPaletteGrayscale = itemOptionsDisplayColorPaletteGrayscale.at20 = 0;
3554      gCustomPaletteInvert = itemOptionsDisplayColorPaletteInvert.m_nFocus = 0;
3555      scrCustomizePalette(gCustomPalette % ARRAY_SSIZE(srcCustomPaletteStr), gCustomPaletteCIEDE2000, gCustomPaletteGrayscale, gCustomPaletteInvert);
3556      videoSetPalette(gBrightness>>2, gLastPal, 0);
3557  #ifdef USE_OPENGL
3558      if (!r_useindexedcolortextures && (videoGetRenderMode() != REND_CLASSIC))
3559      {
3560          videoResetMode();
3561          if (videoSetGameMode(fullscreen, xres, yres, bpp, upscalefactor))
3562              ThrowError("restartvid: Reset failed...\n");
3563          onvideomodechange(gSetup.bpp>8);
3564      }
3565  #endif
3566  }
3567  
3568  #ifdef USE_OPENGL
3569  void SetupVideoPolymostMenu(CGameMenuItemChain *pItem)
3570  {
3571      UNREFERENCED_PARAMETER(pItem);
3572      itemOptionsDisplayPolymostTextureMode.m_nFocus = 0;
3573      for (int i = 0; i < 2; i++)
3574      {
3575          if (nTextureModeValues[i] == gltexfiltermode)
3576          {
3577              itemOptionsDisplayPolymostTextureMode.m_nFocus = i;
3578              break;
3579          }
3580      }
3581      itemOptionsDisplayPolymostAnisotropy.m_nFocus = 0;
3582      for (int i = 0; i < 6; i++)
3583      {
3584          if (nAnisotropyValues[i] == glanisotropy)
3585          {
3586              itemOptionsDisplayPolymostAnisotropy.m_nFocus = i;
3587              break;
3588          }
3589      }
3590      itemOptionsDisplayPolymostTrueColorTextures.at20 = usehightile;
3591      itemOptionsDisplayPolymostTexQuality.m_nFocus = r_downsize;
3592      itemOptionsDisplayPolymostPreloadCache.at20 = useprecache;
3593      itemOptionsDisplayPolymostTexCache.m_nFocus = glusetexcache;
3594      itemOptionsDisplayPolymostDetailTex.at20 = r_detailmapping;
3595      itemOptionsDisplayPolymostGlowTex.at20 = r_glowmapping;
3596      itemOptionsDisplayPolymost3DModels.at20 = usemodels;
3597      itemOptionsDisplayPolymostDeliriumBlur.at20 = gDeliriumBlur;
3598      itemOptionsDisplayPolymostUseColorIndexedTex.at20 = r_useindexedcolortextures;
3599      itemOptionsDisplayPolymostShadeInterpolation.at20 = r_shadeinterpolate;
3600      itemOptionsDisplayPolymostShadeInterpolation.bEnable = !!r_useindexedcolortextures;
3601      itemOptionsDisplayPolymostYShearing.at20 = r_yshearing;
3602  }
3603  
3604  void UpdateTextureMode(CGameMenuItemZCycle *pItem)
3605  {
3606      gltexfiltermode = nTextureModeValues[pItem->m_nFocus];
3607      gltexapplyprops();
3608  }
3609  
3610  void UpdateAnisotropy(CGameMenuItemZCycle *pItem)
3611  {
3612      glanisotropy = nAnisotropyValues[pItem->m_nFocus];
3613      gltexapplyprops();
3614  }
3615  
3616  void UpdateTrueColorTextures(CGameMenuItemZBool *pItem)
3617  {
3618      usehightile = pItem->at20;
3619  }
3620  #endif
3621  
3622  void DoModeChange(void)
3623  {
3624      videoResetMode();
3625      if (videoSetGameMode(fullscreen, xres, yres, bpp, upscalefactor))
3626          OSD_Printf("restartvid: Reset failed...\n");
3627      onvideomodechange(gSetup.bpp > 8);
3628  }
3629  
3630  #ifdef USE_OPENGL
3631  void UpdateTexQuality(CGameMenuItemZCycle *pItem)
3632  {
3633      r_downsize = pItem->m_nFocus;
3634      texcache_invalidate();
3635      r_downsizevar = r_downsize;
3636      DoModeChange();
3637  }
3638  
3639  void UpdatePreloadCache(CGameMenuItemZBool *pItem)
3640  {
3641      useprecache = pItem->at20;
3642  }
3643  
3644  void UpdateTexCache(CGameMenuItemZCycle *pItem)
3645  {
3646      glusetexcache = pItem->m_nFocus;
3647  }
3648  
3649  void UpdateDetailTex(CGameMenuItemZBool *pItem)
3650  {
3651      r_detailmapping = pItem->at20;
3652  }
3653  
3654  void UpdateGlowTex(CGameMenuItemZBool *pItem)
3655  {
3656      r_glowmapping = pItem->at20;
3657  }
3658  
3659  void Update3DModels(CGameMenuItemZBool *pItem)
3660  {
3661      usemodels = pItem->at20;
3662  }
3663  
3664  void UpdateDeliriumBlur(CGameMenuItemZBool *pItem)
3665  {
3666      gDeliriumBlur = pItem->at20;
3667  }
3668  
3669  void UpdateTexColorIndex(CGameMenuItemZBool *pItem)
3670  {
3671      r_useindexedcolortextures = pItem->at20;
3672      itemOptionsDisplayPolymostShadeInterpolation.bEnable = pItem->at20;
3673  }
3674  
3675  void UpdateShadeInterpolation(CGameMenuItemZBool *pItem)
3676  {
3677      r_shadeinterpolate = pItem->at20;
3678  }
3679  
3680  void UpdateYShrearing(CGameMenuItemZBool *pItem)
3681  {
3682      r_yshearing = pItem->at20;
3683  }
3684  
3685  void UpdateRollAngle(CGameMenuItemSlider *pItem)
3686  {
3687      gRollAngle = pItem->nValue;
3688  }
3689  
3690  void PreDrawDisplayPolymost(CGameMenuItem *pItem)
3691  {
3692      if (pItem == &itemOptionsDisplayPolymostTexQuality)
3693          pItem->bEnable = usehightile;
3694      else if (pItem == &itemOptionsDisplayPolymostPreloadCache)
3695          pItem->bEnable = usehightile;
3696      else if (pItem == &itemOptionsDisplayPolymostTexCache)
3697          pItem->bEnable = glusetexcompr && usehightile;
3698      else if (pItem == &itemOptionsDisplayPolymostDetailTex)
3699          pItem->bEnable = usehightile;
3700      else if (pItem == &itemOptionsDisplayPolymostGlowTex)
3701          pItem->bEnable = usehightile;
3702  }
3703  #endif
3704  
3705  void SetNetGameMode(CGameMenuItemZCycle *pItem)
3706  {
3707      if ((itemNetGameMode.m_nFocus+1) == kGameTypeCoop) // hide multiplayer game length settings
3708      {
3709          itemNetGameSliderTimeLimit.bEnable = 0;
3710          itemNetGameSliderTimeLimit.bNoDraw = !itemNetGameSliderTimeLimit.bEnable;
3711          itemNetGameSliderScoreLimit.bEnable = 0;
3712          itemNetGameSliderScoreLimit.bNoDraw = !itemNetGameSliderScoreLimit.bEnable;
3713          itemNetGameSliderLivesLimit.bEnable = 1;
3714          itemNetGameSliderLivesLimit.bNoDraw = !itemNetGameSliderLivesLimit.bEnable;
3715          itemNetStartBoolSecondWind.at20 = 0;
3716      }
3717      else // hide co-op game length settings
3718      {
3719          itemNetGameSliderTimeLimit.bEnable = 1;
3720          itemNetGameSliderTimeLimit.bNoDraw = !itemNetGameSliderTimeLimit.bEnable;
3721          itemNetGameSliderScoreLimit.bEnable = 1;
3722          itemNetGameSliderScoreLimit.bNoDraw = !itemNetGameSliderScoreLimit.bEnable;
3723          itemNetGameSliderLivesLimit.bEnable = 0;
3724          itemNetGameSliderLivesLimit.bNoDraw = !itemNetGameSliderLivesLimit.bEnable;
3725          itemNetStartBoolSecondWind.at20 = 1;
3726      }
3727  
3728      if (pItem == &itemNetGameMode)
3729      {
3730          const int nGameType = pItem->m_nFocus+1;
3731          itemNetStart1.m_pzText2 = zNetGameTypes[pItem->m_nFocus];
3732          itemNetGameBoolExit.bEnable = nGameType != kGameTypeCoop;
3733          itemNetGameBoolExit.bNoDraw = !itemNetGameBoolExit.bEnable;
3734          itemNetGameBoolPlayerColors.bEnable = nGameType != kGameTypeTeams;
3735          itemNetGameBoolPlayerColors.bNoDraw = !itemNetGameBoolPlayerColors.bEnable;
3736          itemNetGameBoolFriendlyFire.bEnable = nGameType != kGameTypeBloodBath;
3737          itemNetGameBoolFriendlyFire.bNoDraw = !itemNetGameBoolFriendlyFire.bEnable;
3738          itemNetGameCycleKey.bEnable = nGameType == kGameTypeCoop;
3739          itemNetGameCycleKey.bNoDraw = !itemNetGameCycleKey.bEnable;
3740          itemNetGameCycleItemWeapon.bEnable = nGameType == kGameTypeCoop;
3741          itemNetGameCycleItemWeapon.bNoDraw = !itemNetGameCycleItemWeapon.bEnable;
3742          itemNetGameBoolAutoTeams.bEnable = nGameType == kGameTypeTeams;
3743          itemNetGameBoolAutoTeams.bNoDraw = !itemNetGameBoolAutoTeams.bEnable;
3744          itemNetGameBoolTeamColors.bEnable = nGameType == kGameTypeTeams;
3745          itemNetGameBoolTeamColors.bNoDraw = !itemNetGameBoolTeamColors.bEnable;
3746          itemNetGameBoolTeamFlags.bEnable = nGameType == kGameTypeTeams;
3747          itemNetGameBoolTeamFlags.bNoDraw = !itemNetGameBoolTeamFlags.bEnable;
3748          itemNetGameCycleShowWeaponsOverride.bEnable = nGameType != kGameTypeTeams;
3749          itemNetGameCycleShowWeaponsOverride.bNoDraw = !itemNetGameCycleShowWeaponsOverride.bEnable;
3750          itemNetGameCycleShowWeaponsOverrideTeams.bEnable = nGameType == kGameTypeTeams;
3751          itemNetGameCycleShowWeaponsOverrideTeams.bNoDraw = !itemNetGameCycleShowWeaponsOverrideTeams.bEnable;
3752          itemNetGameCycleSpawnLocation.bEnable = nGameType != kGameTypeCoop;
3753          itemNetGameCycleSpawnLocation.bNoDraw = !itemNetGameCycleSpawnLocation.bEnable;
3754          itemNetStartBoolSpectatorMode.bEnable = nGameType != kGameTypeCoop;
3755          itemNetStartBoolSpectatorMode.bNoDraw = !itemNetStartBoolSpectatorMode.bEnable;
3756          return;
3757      }
3758  
3759      if ((pItem == &itemNetGameCycleItemWeapon) && (pItem->m_nFocus > 0)) // if adjusted keep weapon/item settings, set spawn weapon to pitchfork
3760          itemNetGameCycleSpawnWeapon.m_nFocus = 0;
3761      else if ((pItem == &itemNetGameCycleSpawnWeapon) && (pItem->m_nFocus > 0)) // if adjusted spawn with weapon, turn off keep weapon/item settings as it will overwrite any weapon picked up after spawning
3762          itemNetGameCycleItemWeapon.m_nFocus = 0;
3763  }
3764  
3765  void SetNetShowWeapon(CGameMenuItemZCycle *pItem)
3766  {
3767      if (pItem != &itemNetGameCycleShowWeaponsOverride)
3768          itemNetGameCycleShowWeaponsOverride.SetTextIndex(ClipHigh(pItem->m_nFocus, ARRAY_SIZE(zShowWeapon)-1));
3769      if (pItem != &itemNetGameCycleShowWeaponsOverrideTeams)
3770          itemNetGameCycleShowWeaponsOverrideTeams.SetTextIndex(ClipHigh(pItem->m_nFocus, ARRAY_SIZE(zShowWeaponTeams)-1));
3771  }
3772  
3773  void SetNetMonsterMenu(CGameMenuItemZCycle *pItem)
3774  {
3775      itemNetStart5.m_pzText2 = zMonsterStrings[itemNetMonsterSettings.m_nFocus];
3776  
3777      if ((pItem == &itemNetStart4) || !pItem)
3778      {
3779          itemNetMonsterQuantity.nValue = itemNetStart4.m_nFocus;
3780          itemNetMonsterHealth.nValue = itemNetStart4.m_nFocus;
3781      }
3782  
3783      for (int i = 0; i < menuNetworkGameMonsters.m_nItems; i++)
3784      {
3785          if (menuNetworkGameMonsters.pItemList[i] == &itemNetMonsterTitle)
3786              continue;
3787          if (menuNetworkGameMonsters.pItemList[i] == &itemNetMonsterSettings)
3788              continue;
3789          if (menuNetworkGameMonsters.pItemList[i] == &itemBloodQAV)
3790              continue;
3791          menuNetworkGameMonsters.pItemList[i]->bEnable = itemNetMonsterSettings.m_nFocus != 0;
3792      }
3793  }
3794  
3795  void UpdateSoundToggle(CGameMenuItemZBool *pItem)
3796  {
3797      SoundToggle = pItem->at20;
3798      if (!SoundToggle)
3799          FX_StopAllSounds();
3800  }
3801  
3802  void UpdateMusicToggle(CGameMenuItemZBool *pItem)
3803  {
3804      MusicToggle = pItem->at20;
3805      if (!MusicToggle)
3806          sndStopSong();
3807      else
3808      {
3809          if (gGameStarted || gDemo.bPlaying)
3810              sndPlaySong(gGameOptions.zLevelSong, true);
3811      }
3812  }
3813  
3814  void UpdateCDToggle(CGameMenuItemZBool *pItem)
3815  {
3816      CDAudioToggle = pItem->at20;
3817      if (gGameStarted || gDemo.bPlaying)
3818          levelTryPlayMusicOrNothing(gGameOptions.nEpisode, gGameOptions.nLevel);
3819  }
3820  
3821  void SetDoppler(CGameMenuItemZBool *pItem)
3822  {
3823      DopplerToggle = pItem->at20;
3824  }
3825  
3826  void UpdateSoundVolume(CGameMenuItemSlider *pItem)
3827  {
3828      sndSetFXVolume(pItem->nValue);
3829  }
3830  
3831  void UpdateMusicVolume(CGameMenuItemSlider *pItem)
3832  {
3833      sndSetMusicVolume(pItem->nValue);
3834  }
3835  
3836  void UpdateSoundRate(CGameMenuItemZCycle *pItem)
3837  {
3838      UNREFERENCED_PARAMETER(pItem);
3839  }
3840  
3841  void UpdateNumVoices(CGameMenuItemSlider *pItem)
3842  {
3843      NumVoices = ClipRange(pItem->nValue, 16, 255);
3844  }
3845  
3846  void UpdateSpeakerAngle(CGameMenuItemSlider *pItem)
3847  {
3848      gSoundEarAng = ClipRange(pItem->nValue, 15, 90);
3849  }
3850  
3851  void UpdateCalebTalk(CGameMenuItemZCycle *pItem)
3852  {
3853      gCalebTalk = pItem->m_nFocus % ARRAY_SIZE(pzCalebTalkStrings);
3854  }
3855  
3856  void UpdateMusicDevice(CGameMenuItemZCycle *pItem)
3857  {
3858      UNREFERENCED_PARAMETER(pItem);
3859      itemOptionsSoundSF2Bank.bEnable = 0;
3860      itemOptionsSoundSF2Bank.bNoDraw = 1;
3861      switch (nMusicDeviceValues[itemOptionsSoundMusicDevice.m_nFocus])
3862      {
3863      case ASS_SF2:
3864          itemOptionsSoundSF2Bank.bEnable = 1;
3865          itemOptionsSoundSF2Bank.bNoDraw = 0;
3866          break;
3867      }
3868  }
3869  
3870  void SetSound(CGameMenuItemChain *pItem)
3871  {
3872      UNREFERENCED_PARAMETER(pItem);
3873      MixRate = nSoundRateValues[itemOptionsSoundSampleRate.m_nFocus];
3874      NumVoices = itemOptionsSoundNumVoices.nValue;
3875      MusicDevice = nMusicDeviceValues[itemOptionsSoundMusicDevice.m_nFocus];
3876      Bstrcpy(SF2_BankFile, sf2bankfile);
3877      sfxTerm();
3878      sndTerm();
3879  
3880      sndInit();
3881      sfxInit();
3882  
3883      if (MusicToggle && (gGameStarted || gDemo.bPlaying))
3884          sndPlaySong(gGameOptions.zLevelSong, true);
3885  }
3886  
3887  void PreDrawSound(CGameMenuItem *pItem)
3888  {
3889      UNREFERENCED_PARAMETER(pItem);
3890  }
3891  
3892  void SetupOptionsSound(CGameMenuItemChain *pItem)
3893  {
3894      UNREFERENCED_PARAMETER(pItem);
3895      itemOptionsSoundSoundToggle.at20 = SoundToggle;
3896      itemOptionsSoundMusicToggle.at20 = MusicToggle;
3897      itemOptionsSoundMonoStereo.at20 = gStereo;
3898      itemOptionsSoundCDToggle.at20 = CDAudioToggle;
3899      itemOptionsSoundDoppler.at20 = DopplerToggle;
3900      itemOptionsSoundDoppler.bEnable = gStereo;
3901      itemOptionsSoundSampleRate.m_nFocus = 0;
3902      for (int i = 0; i < 3; i++)
3903      {
3904          if (nSoundRateValues[i] == MixRate)
3905          {
3906              itemOptionsSoundSampleRate.m_nFocus = i;
3907              break;
3908          }
3909      }
3910      itemOptionsSoundNumVoices.nValue = NumVoices;
3911      itemOptionsSoundSpeakerAngle.nValue = gSoundEarAng;
3912      itemOptionsSoundCalebTalk.m_nFocus = gCalebTalk % ARRAY_SIZE(pzCalebTalkStrings);
3913      itemOptionsSoundMusicDevice.m_nFocus = 0;
3914      for (int i = 0; i < (int)ARRAY_SIZE(nMusicDeviceValues); i++)
3915      {
3916          if (nMusicDeviceValues[i] == MusicDevice)
3917          {
3918              itemOptionsSoundMusicDevice.m_nFocus = i;
3919              break;
3920          }
3921      }
3922  
3923      UpdateMusicDevice(NULL);
3924  }
3925  
3926  void SetupPollJoystick(CGameMenuItemChain *pItem)
3927  {
3928      UNREFERENCED_PARAMETER(pItem);
3929      if (CONTROL_JoyPresent && CONTROL_JoystickEnabled && !itemOptionsControlJoystickButtons.bEnable) // if joysticks menu was never initialized, and a controller is now detected, setup the menu
3930      {
3931          itemOptionsControlJoystickButtons.bEnable = 1;
3932          itemOptionsControlJoystickAxes.bEnable = 1;
3933          itemOptionsControlJoystickMisc.bEnable = 1;
3934          SetupJoystickMenu();
3935      }
3936  }
3937  
3938  void UpdatePlayerName(CGameMenuItemZEdit *pItem, CGameMenuEvent *pEvent)
3939  {
3940      UNREFERENCED_PARAMETER(pItem);
3941      if (pEvent->at0 == kMenuEventEnter)
3942          netBroadcastPlayerInfoUpdate(myconnectindex);
3943  }
3944  
3945  void UpdatePlayerSkill(CGameMenuItemZCycle *pItem)
3946  {
3947      gSkill = pItem->m_nFocus % ARRAY_SIZE(pzPlayerSkillStrings);
3948      if ((numplayers > 1) || (gGameOptions.nGameType != kGameTypeSinglePlayer)) // if multiplayer session is active
3949          netBroadcastPlayerInfoUpdate(myconnectindex);
3950  }
3951  
3952  void UpdatePlayerTeamPreference(CGameMenuItemZCycle *pItem)
3953  {
3954      gPlayerTeamPreference = pItem->m_nFocus % ARRAY_SIZE(pzPlayerTeamPreferenceStrings);
3955      if ((numplayers > 1) || (gGameOptions.nGameType != kGameTypeSinglePlayer)) // if multiplayer session is active
3956      {
3957          netBroadcastPlayerInfoUpdate(myconnectindex);
3958          if (gGameOptions.bAutoTeams && (gGameOptions.nGameType == kGameTypeTeams))
3959          {
3960              viewSetMessage("Auto teams is on, cannot change team.", 8, MESSAGE_PRIORITY_INI); // 8: gold
3961              gNetNotifyProfileUpdate = false;
3962          }
3963      }
3964  }
3965  
3966  void UpdatePlayerColorPreference(CGameMenuItemZCycle *pItem)
3967  {
3968      gPlayerColorPreference = pItem->m_nFocus % ARRAY_SIZE(pzPlayerColorPreferenceStrings);
3969      if ((numplayers > 1) || (gGameOptions.nGameType != kGameTypeSinglePlayer)) // if multiplayer session is active
3970          netBroadcastPlayerInfoUpdate(myconnectindex);
3971  }
3972  
3973  void UpdatePlayerModel(CGameMenuItemZBool *pItem)
3974  {
3975      gPlayerModel = pItem->at20;
3976      if ((numplayers > 1) || (gGameOptions.nGameType != kGameTypeSinglePlayer)) // if multiplayer session is active
3977          netBroadcastPlayerInfoUpdate(myconnectindex);
3978  }
3979  
3980  void SetShowPlayerNames(CGameMenuItemZBool *pItem)
3981  {
3982      gShowPlayerNames = pItem->at20;
3983  }
3984  
3985  void SetShowWeapons(CGameMenuItemZCycle *pItem)
3986  {
3987      gShowWeapon = pItem->m_nFocus;
3988  }
3989  
3990  void UpdateTeamsScoreDisplay(CGameMenuItemZBool *pItem)
3991  {
3992      gTeamsScoreStyle = pItem->at20;
3993  }
3994  
3995  void UpdatePlayerChatMessageSound(CGameMenuItemZBool *pItem)
3996  {
3997      gChatSnd = pItem->at20;
3998  }
3999  
4000  void UpdatePlayerColorMessages(CGameMenuItemZBool *pItem)
4001  {
4002      gColorMsg = pItem->at20;
4003  }
4004  
4005  void UpdatePlayerKillObituaryMessages(CGameMenuItemZBool *pItem)
4006  {
4007      gKillObituary = pItem->at20;
4008  }
4009  
4010  void UpdatePlayerKillMessage(CGameMenuItemZBool *pItem)
4011  {
4012      gKillMsg = pItem->at20;
4013  }
4014  
4015  void UpdatePlayerMultiKill(CGameMenuItemZCycle *pItem)
4016  {
4017      gMultiKill = pItem->m_nFocus % ARRAY_SIZE(pzPlayerMultiKillStrings);
4018  }
4019  
4020  void SetMouseAimMode(CGameMenuItemZBool *pItem)
4021  {
4022      gMouseAiming = pItem->at20;
4023  }
4024  
4025  void SetMouseVerticalAim(CGameMenuItemZBool *pItem)
4026  {
4027      gMouseAim = pItem->at20;
4028  }
4029  
4030  void SetMouseXSensitivity(CGameMenuItemSliderFloat *pItem)
4031  {
4032      CONTROL_MouseAxesSensitivity[0] = pItem->fValue;
4033  }
4034  
4035  void SetMouseYSensitivity(CGameMenuItemSliderFloat*pItem)
4036  {
4037      CONTROL_MouseAxesSensitivity[1] = pItem->fValue;
4038  }
4039  
4040  void SetupMouseMenu(CGameMenuItemChain *pItem)
4041  {
4042      UNREFERENCED_PARAMETER(pItem);
4043      itemOptionsControlMouseAimFlipped.at20 = gMouseAimingFlipped;
4044      itemOptionsControlMouseAimMode.at20 = gMouseAiming;
4045      itemOptionsControlMouseVerticalAim.at20 = gMouseAim;
4046      // itemOptionsControlMouseXScale.nValue = CONTROL_MouseAxesScale[0];
4047      // itemOptionsControlMouseYScale.nValue = CONTROL_MouseAxesScale[1];
4048  }
4049  
4050  void SetupJoystickButtonsMenu(CGameMenuItemChain *pItem)
4051  {
4052      UNREFERENCED_PARAMETER(pItem);
4053      const int nMaxJoyButtons = (joystick.numButtons * 2) + ((joystick.numHats > 0) * 4);
4054      for (int nPage = 0; nPage < MAXJOYSTICKBUTTONPAGES; nPage++) // go through each axis and setup binds
4055      {
4056          for (int nButton = 0; nButton < JOYSTICKITEMSPERPAGE; nButton++)
4057          {
4058              if (nButton >= nMaxJoyButtons) // reached end of button list
4059                  return;
4060              const char bDoubleTap = nButton & 1;
4061              const int nJoyButton = ((nPage * JOYSTICKITEMSPERPAGE)>>1) + (nButton>>1); // we halve the button index because button lists are listed in pairs of single tap/double tap inputs
4062              auto pButton = pItemOptionsControlJoyButton[nPage][nButton];
4063              if (!pButton)
4064                  break;
4065              pButton->m_nFocus = 0;
4066              for (int j = 0; j < NUMGAMEFUNCTIONS+1; j++)
4067              {
4068                  if (JoystickFunctions[nJoyButton][bDoubleTap] == nGamefuncsValues[j])
4069                  {
4070                      pButton->m_nFocus = j;
4071                      break;
4072                  }
4073              }
4074          }
4075      }
4076  }
4077  
4078  void SetupJoystickAxesMenu(CGameMenuItemChain *pItem)
4079  {
4080      UNREFERENCED_PARAMETER(pItem);
4081      for (int nAxis = 0; nAxis < MAXJOYAXES; nAxis++) // set settings for each listed joystick axis
4082      {
4083          if (pItemOptionsControlJoystickAxis[nAxis] == NULL) // reached end of list, stop
4084              return;
4085          pItemOptionsControlJoystickAxisScale[nAxis]->nValue = JoystickAnalogueScale[nAxis];
4086          switch (JoystickAnalogueAxes[nAxis])
4087          {
4088          case analog_lookingupanddown:
4089              pItemOptionsControlJoystickAxisAnalogue[nAxis]->m_nFocus = 4;
4090              break;
4091          case analog_moving:
4092              pItemOptionsControlJoystickAxisAnalogue[nAxis]->m_nFocus = 3;
4093              break;
4094          case analog_strafing:
4095              pItemOptionsControlJoystickAxisAnalogue[nAxis]->m_nFocus = 2;
4096              break;
4097          case analog_turning:
4098              pItemOptionsControlJoystickAxisAnalogue[nAxis]->m_nFocus = 1;
4099              break;
4100          default: // unsupported/none
4101              pItemOptionsControlJoystickAxisAnalogue[nAxis]->m_nFocus = 0;
4102              break;
4103          }
4104          pItemOptionsControlJoystickAxisAnalogueInvert[nAxis]->at20 = JoystickAnalogueInvert[nAxis];
4105          pItemOptionsControlJoystickAxisDigitalPos[nAxis]->m_nFocus = 0;
4106          for (int j = 0; j < NUMGAMEFUNCTIONS+1; j++)
4107          {
4108              if (JoystickDigitalFunctions[nAxis][0] == nGamefuncsValues[j])
4109              {
4110                  pItemOptionsControlJoystickAxisDigitalPos[nAxis]->m_nFocus = j;
4111                  break;
4112              }
4113          }
4114          pItemOptionsControlJoystickAxisDigitalNeg[nAxis]->m_nFocus = 0;
4115          for (int j = 0; j < NUMGAMEFUNCTIONS+1; j++)
4116          {
4117              if (JoystickDigitalFunctions[nAxis][1] == nGamefuncsValues[j])
4118              {
4119                  pItemOptionsControlJoystickAxisDigitalNeg[nAxis]->m_nFocus = j;
4120                  break;
4121              }
4122          }
4123          pItemOptionsControlJoystickAxisDeadzone[nAxis]->nValue = JoystickAnalogueDead[nAxis];
4124          pItemOptionsControlJoystickAxisSaturate[nAxis]->nValue = JoystickAnalogueSaturate[nAxis];
4125          pItemOptionsControlJoystickAxisSnapZone[nAxis]->nValue = JoystickAnalogueSnap[nAxis];
4126      }
4127  }
4128  
4129  inline void GenerateJoystickAxisHeatmap(const int nAxis)
4130  {
4131      if (!waloff[kAxisHeatmapTile])
4132      {
4133          tileAllocTile(kAxisHeatmapTile, 48, 48, 0, 0);
4134          tileSetSize(kAxisHeatmapTile, 48, 48);
4135      }
4136      dassert(waloff[kAxisHeatmapTile] != 0);
4137      CONTROL_GetAxisHeatMap(nAxis, (uint8_t*)waloff[kAxisHeatmapTile], 48, 48, 0, 31, true);
4138      tileInvalidate(kAxisHeatmapTile, -1, -1);
4139  }
4140  
4141  void SetupJoystickAxisHeatmap(CGameMenuItemChain* pItem)
4142  {
4143      for (int nAxis = 0; nAxis < MAXJOYAXES; nAxis++)
4144      {
4145          if (pItem == pItemOptionsControlJoystickAxis[nAxis])
4146          {
4147              GenerateJoystickAxisHeatmap(nAxis);
4148              break;
4149          }
4150      }
4151  }
4152  
4153  void SetJoystickScale(CGameMenuItemSlider* pItem)
4154  {
4155      for (int nAxis = 0; nAxis < MAXJOYAXES; nAxis++)
4156      {
4157          if (pItem == pItemOptionsControlJoystickAxisScale[nAxis])
4158          {
4159              JoystickAnalogueScale[nAxis] = pItem->nValue;
4160              CONTROL_SetAnalogAxisScale(nAxis, JoystickAnalogueScale[nAxis], controldevice_joystick);
4161              break;
4162          }
4163      }
4164  }
4165  
4166  void SetJoystickAnalogue(CGameMenuItemZCycle* pItem)
4167  {
4168      for (int nAxis = 0; nAxis < MAXJOYAXES; nAxis++)
4169      {
4170          if (pItem == pItemOptionsControlJoystickAxisAnalogue[nAxis])
4171          {
4172              switch (pItem->m_nFocus)
4173              {
4174              case 4: // looking up/down
4175                  JoystickAnalogueAxes[nAxis] = analog_lookingupanddown;
4176                  break;
4177              case 3: // moving
4178                  JoystickAnalogueAxes[nAxis] = analog_moving;
4179                  break;
4180              case 2: // strafing
4181                  JoystickAnalogueAxes[nAxis] = analog_strafing;
4182                  break;
4183              case 1: // turning
4184                  JoystickAnalogueAxes[nAxis] = analog_turning;
4185                  break;
4186              case 0: // none
4187              default:
4188                  JoystickAnalogueAxes[nAxis] = -1;
4189                  break;
4190              }
4191              CONTROL_MapAnalogAxis(nAxis, JoystickAnalogueAxes[nAxis]);
4192              break;
4193          }
4194      }
4195  }
4196  
4197  void SetJoystickAnalogueInvert(CGameMenuItemZBool* pItem)
4198  {
4199      for (int nAxis = 0; nAxis < MAXJOYAXES; nAxis++)
4200      {
4201          if (pItem == pItemOptionsControlJoystickAxisAnalogueInvert[nAxis])
4202          {
4203              JoystickAnalogueInvert[nAxis] = pItem->at20;
4204              CONTROL_SetAnalogAxisInvert(nAxis, JoystickAnalogueInvert[nAxis]);
4205              break;
4206          }
4207      }
4208  }
4209  
4210  void SetJoystickDigitalPos(CGameMenuItemZCycle* pItem)
4211  {
4212      for (int nAxis = 0; nAxis < MAXJOYAXES; nAxis++)
4213      {
4214          if (pItem == pItemOptionsControlJoystickAxisDigitalPos[nAxis])
4215          {
4216              for (int j = 0; j < NUMGAMEFUNCTIONS+1; j++)
4217              {
4218                  if (JoystickDigitalFunctions[nAxis][0] == nGamefuncsValues[j])
4219                  {
4220                      int nFunc = nGamefuncsValues[pItem->m_nFocus];
4221                      JoystickDigitalFunctions[nAxis][0] = nFunc;
4222                      CONTROL_MapDigitalAxis(nAxis, JoystickDigitalFunctions[nAxis][0], 0);
4223                      return;
4224                  }
4225              }
4226          }
4227      }
4228  }
4229  
4230  void SetJoystickDigitalNeg(CGameMenuItemZCycle* pItem)
4231  {
4232      for (int nAxis = 0; nAxis < MAXJOYAXES; nAxis++)
4233      {
4234          if (pItem == pItemOptionsControlJoystickAxisDigitalNeg[nAxis])
4235          {
4236              for (int j = 0; j < NUMGAMEFUNCTIONS+1; j++)
4237              {
4238                  if (JoystickDigitalFunctions[nAxis][1] == nGamefuncsValues[j])
4239                  {
4240                      int nFunc = nGamefuncsValues[pItem->m_nFocus];
4241                      JoystickDigitalFunctions[nAxis][1] = nFunc;
4242                      CONTROL_MapDigitalAxis(nAxis, JoystickDigitalFunctions[nAxis][1], 1);
4243                      return;
4244                  }
4245              }
4246          }
4247      }
4248  }
4249  
4250  void SetJoystickDeadzone(CGameMenuItemSlider* pItem)
4251  {
4252      for (int nAxis = 0; nAxis < MAXJOYAXES; nAxis++)
4253      {
4254          if (pItem == pItemOptionsControlJoystickAxisDeadzone[nAxis])
4255          {
4256              JoystickAnalogueDead[nAxis] = pItem->nValue;
4257              JOYSTICK_SetDeadZone(nAxis, JoystickAnalogueDead[nAxis], JoystickAnalogueSaturate[nAxis]);
4258              GenerateJoystickAxisHeatmap(nAxis);
4259              break;
4260          }
4261      }
4262  }
4263  
4264  void SetJoystickSaturate(CGameMenuItemSlider* pItem)
4265  {
4266      for (int nAxis = 0; nAxis < MAXJOYAXES; nAxis++)
4267      {
4268          if (pItem == pItemOptionsControlJoystickAxisSaturate[nAxis])
4269          {
4270              JoystickAnalogueSaturate[nAxis] = pItem->nValue;
4271              JOYSTICK_SetDeadZone(nAxis, JoystickAnalogueDead[nAxis], JoystickAnalogueSaturate[nAxis]);
4272              GenerateJoystickAxisHeatmap(nAxis);
4273              break;
4274          }
4275      }
4276  }
4277  
4278  void SetJoystickSnapZone(CGameMenuItemSlider* pItem)
4279  {
4280      for (int nAxis = 0; nAxis < MAXJOYAXES; nAxis++)
4281      {
4282          if (pItem == pItemOptionsControlJoystickAxisSnapZone[nAxis])
4283          {
4284              JoystickAnalogueSnap[nAxis] = pItem->nValue;
4285              JOYSTICK_SetSnapZone(nAxis, JoystickAnalogueSnap[nAxis]);
4286              GenerateJoystickAxisHeatmap(nAxis);
4287              break;
4288          }
4289      }
4290  }
4291  
4292  void PreDrawControlMouse(CGameMenuItem *pItem)
4293  {
4294      if (pItem == &itemOptionsControlMouseVerticalAim)
4295          pItem->bEnable = !gMouseAiming;
4296  }
4297  
4298  void SetMouseButton(CGameMenuItemZCycle *pItem)
4299  {
4300      for (int i = 0; i < MENUMOUSEFUNCTIONS; i++)
4301      {
4302          if (pItem == pItemOptionsControlMouseButton[i])
4303          {
4304              int nFunc = nGamefuncsValues[pItem->m_nFocus];
4305              MouseFunctions[MenuMouseDataIndex[i][0]][MenuMouseDataIndex[i][1]] = nFunc;
4306              CONTROL_MapButton(nFunc, MenuMouseDataIndex[i][0], MenuMouseDataIndex[i][1], controldevice_mouse);
4307              CONTROL_FreeMouseBind(MenuMouseDataIndex[i][0]);
4308              break;
4309          }
4310      }
4311  }
4312  
4313  void SetJoyButton(CGameMenuItemZCycle *pItem)
4314  {
4315      for (int nPage = 0; nPage < MAXJOYSTICKBUTTONPAGES; nPage++) // find selected menu item used for this bind
4316      {
4317          for (int nButton = 0; nButton < JOYSTICKITEMSPERPAGE; nButton++)
4318          {
4319              if (pItem == pItemOptionsControlJoyButton[nPage][nButton]) // found menu item, now bind function to joystick button
4320              {
4321                  const char bDoubleTap = nButton & 1;
4322                  const int nJoyButton = ((nPage * JOYSTICKITEMSPERPAGE)>>1) + (nButton>>1); // we halve the button index because button lists are listed in pairs of single tap/double tap inputs
4323                  int nFunc = nGamefuncsValues[pItem->m_nFocus];
4324                  JoystickFunctions[nJoyButton][bDoubleTap] = nFunc;
4325                  CONTROL_MapButton(nFunc, nJoyButton, bDoubleTap, controldevice_joystick);
4326                  return;
4327              }
4328          }
4329      }
4330  }
4331  
4332  void SetupMouseButtonMenu(CGameMenuItemChain *pItem)
4333  {
4334      UNREFERENCED_PARAMETER(pItem);
4335      for (int i = 0; i < MENUMOUSEFUNCTIONS; i++)
4336      {
4337          auto pItem = pItemOptionsControlMouseButton[i];
4338          pItem->m_nFocus = 0;
4339          for (int j = 0; j < NUMGAMEFUNCTIONS+1; j++)
4340          {
4341              if (MouseFunctions[MenuMouseDataIndex[i][0]][MenuMouseDataIndex[i][1]] == nGamefuncsValues[j])
4342              {
4343                  pItem->m_nFocus = j;
4344                  break;
4345              }
4346          }
4347      }
4348  }
4349  
4350  void SetupNetworkMenu(void)
4351  {
4352      if (strlen(gNetAddress) > 0)
4353          strncpy(zNetAddressBuffer, gNetAddress, sizeof(zNetAddressBuffer)-1);
4354  
4355      menuNetwork.Add(&itemNetworkTitle, false);
4356      menuNetwork.Add(&itemNetworkHost, true);
4357      menuNetwork.Add(&itemNetworkJoin, false);
4358      menuNetwork.Add(&itemNetworkPlayer, false);
4359      menuNetwork.Add(&itemBloodQAV, false);
4360  
4361      menuNetworkHost.Add(&itemNetworkHostTitle, false);
4362      menuNetworkHost.Add(&itemNetworkHostPlayerNum, true);
4363      menuNetworkHost.Add(&itemNetworkHostPort, false);
4364      menuNetworkHost.Add(&itemNetworkHostHost, false);
4365      menuNetworkHost.Add(&itemBloodQAV, false);
4366  
4367      menuNetworkJoin.Add(&itemNetworkJoinTitle, false);
4368      menuNetworkJoin.Add(&itemNetworkJoinAddress, true);
4369      menuNetworkJoin.Add(&itemNetworkJoinPort, false);
4370      menuNetworkJoin.Add(&itemNetworkJoinJoin, false);
4371      menuNetworkJoin.Add(&itemBloodQAV, false);
4372  }
4373  
4374  void SetupNetworkHostMenu(CGameMenuItemChain *pItem)
4375  {
4376      UNREFERENCED_PARAMETER(pItem);
4377  }
4378  
4379  void SetupNetworkJoinMenu(CGameMenuItemChain *pItem)
4380  {
4381      UNREFERENCED_PARAMETER(pItem);
4382  }
4383  
4384  void NetworkHostGame(CGameMenuItemChain *pItem)
4385  {
4386      UNREFERENCED_PARAMETER(pItem);
4387      sndStopSong();
4388      FX_StopAllSounds();
4389      UpdateDacs(0, true);
4390      gNetPlayers = itemNetworkHostPlayerNum.nValue;
4391      gNetPort = strtoul(zNetPortBuffer, NULL, 10);
4392      if (!gNetPort)
4393          gNetPort = kNetDefaultPort;
4394      gNetMode = NETWORK_SERVER;
4395      netInitialize(false);
4396      gGameMenuMgr.Deactivate();
4397      gQuitGame = gRestartGame = true;
4398  }
4399  
4400  void NetworkJoinGame(CGameMenuItemChain *pItem)
4401  {
4402      UNREFERENCED_PARAMETER(pItem);
4403      sndStopSong();
4404      FX_StopAllSounds();
4405      UpdateDacs(0, true);
4406      strcpy(gNetAddress, zNetAddressBuffer);
4407      gNetPort = strtoul(zNetPortBuffer, NULL, 10);
4408      if (!gNetPort)
4409          gNetPort = kNetDefaultPort;
4410      gNetMode = NETWORK_CLIENT;
4411      netInitialize(false);
4412      gGameMenuMgr.Deactivate();
4413      gQuitGame = gRestartGame = true;
4414  }
4415  
4416  void SaveGameProcess(CGameMenuItemChain *pItem)
4417  {
4418      UNREFERENCED_PARAMETER(pItem);
4419  }
4420  
4421  inline void UpdateSaveGameItemText(int nSlot)
4422  {
4423      switch (nSlot) // set save slot text flag
4424      {
4425      case kLoadSaveSlot0:
4426          itemSaveGame0.at37 = 0;
4427          break;
4428      case kLoadSaveSlot1:
4429          itemSaveGame1.at37 = 0;
4430          break;
4431      case kLoadSaveSlot2:
4432          itemSaveGame2.at37 = 0;
4433          break;
4434      case kLoadSaveSlot3:
4435          itemSaveGame3.at37 = 0;
4436          break;
4437      case kLoadSaveSlot4:
4438          itemSaveGame4.at37 = 0;
4439          break;
4440      case kLoadSaveSlot5:
4441          itemSaveGame5.at37 = 0;
4442          break;
4443      case kLoadSaveSlot6:
4444          itemSaveGame6.at37 = 0;
4445          break;
4446      case kLoadSaveSlot7:
4447          itemSaveGame7.at37 = 0;
4448          break;
4449      case kLoadSaveSlot8:
4450          itemSaveGame8.at37 = 0;
4451          break;
4452      case kLoadSaveSlot9:
4453          itemSaveGame9.at37 = 0;
4454          break;
4455      default:
4456          break;
4457      }
4458  }
4459  
4460  void SaveGame(CGameMenuItemZEditBitmap *pItem, CGameMenuEvent *event)
4461  {
4462      char strSaveGameName[BMAX_PATH];
4463      int nSlot = pItem->at28;
4464      if (gGameOptions.nGameType != kGameTypeSinglePlayer || !gGameStarted)
4465          return;
4466      if (event->at0 != 6/* || strSaveGameName[0]*/)
4467      {
4468          gGameMenuMgr.Deactivate();
4469          return;
4470      }
4471      if (G_ModDirSnprintf(strSaveGameName, BMAX_PATH, "game00%02d.sav", nSlot))
4472          return;
4473      memset(gGameOptions.szUserGameName, 0, sizeof(gGameOptions.szSaveGameName));
4474      strcpy(gGameOptions.szUserGameName, strRestoreGameStrings[nSlot]);
4475      memset(gGameOptions.szSaveGameName, 0, sizeof(gGameOptions.szSaveGameName));
4476      sprintf(gGameOptions.szSaveGameName, "%s", strSaveGameName);
4477      gGameOptions.nSaveGameSlot = nSlot;
4478      if (gShowLoadingSavingBackground)
4479      {
4480          viewLoadingScreen(gMenuPicnum, "Saving", "Saving Your Game", strRestoreGameStrings[nSlot]);
4481          videoNextPage();
4482      }
4483      gSaveGameNum = nSlot;
4484      LoadSave::SaveGame(strSaveGameName);
4485      gGameOptions.picEntry = gSavedOffset;
4486      gSaveGameOptions[nSlot] = gGameOptions;
4487      LoadUpdateSaveGame(nSlot, gProfile[myconnectindex].skill);
4488      UpdateSaveGameItemText(nSlot);
4489      gQuickLoadSlot = nSlot;
4490      gGameMenuMgr.Deactivate();
4491      viewSetMessage("Game saved");
4492  }
4493  
4494  void QuickSaveGame(void)
4495  {
4496      char strSaveGameName[BMAX_PATH];
4497      if (gGameOptions.nGameType != kGameTypeSinglePlayer || !gGameStarted)
4498          return;
4499      /*if (strSaveGameName[0])
4500      {
4501          gGameMenuMgr.Deactivate();
4502          return;
4503      }*/
4504      if (G_ModDirSnprintf(strSaveGameName, BMAX_PATH, "game00%02d.sav", kLoadSaveSlotQuick))
4505          return;
4506      memset(gGameOptions.szUserGameName, 0, sizeof(gGameOptions.szSaveGameName));
4507      snprintf(gGameOptions.szUserGameName, sizeof(gGameOptions.szUserGameName), "%s quick", gGameOptions.zLevelName);
4508      memset(gGameOptions.szSaveGameName, 0, sizeof(gGameOptions.szSaveGameName));
4509      sprintf(gGameOptions.szSaveGameName, "%s", strSaveGameName);
4510      gGameOptions.nSaveGameSlot = kLoadSaveSlotQuick;
4511      if (gShowLoadingSavingBackground)
4512      {
4513          viewLoadingScreen(gMenuPicnum, "Saving", "Saving Your Game", strRestoreGameStrings[kLoadSaveSlotQuick]);
4514          videoNextPage();
4515      }
4516      LoadSave::SaveGame(strSaveGameName);
4517      gGameOptions.picEntry = gSavedOffset;
4518      gSaveGameOptions[kLoadSaveSlotQuick] = gGameOptions;
4519      LoadUpdateSaveGame(kLoadSaveSlotQuick, gProfile[myconnectindex].skill);
4520      UpdateSaveGameItemText(kLoadSaveSlotQuick);
4521      gQuickLoadSlot = kLoadSaveSlotQuick;
4522      gGameMenuMgr.Deactivate();
4523      viewSetMessage("Game saved");
4524  }
4525  
4526  void AutosaveGame(bool bLevelStartSave)
4527  {
4528      char strSaveGameName[BMAX_PATH];
4529      int nSlot = bLevelStartSave ? kLoadSaveSlotSpawn : kLoadSaveSlotKey;
4530      if (gGameOptions.nGameType != kGameTypeSinglePlayer || !gGameStarted)
4531          return;
4532      if (G_ModDirSnprintf(strSaveGameName, BMAX_PATH, "gameautosave%1d.sav", nSlot - kLoadSaveSlotSpawn))
4533          return;
4534      snprintf(gGameOptions.szUserGameName, sizeof(gGameOptions.szUserGameName), "%s %s", gGameOptions.zLevelName, nSlot == kLoadSaveSlotSpawn ? "start": "key");
4535      snprintf(gGameOptions.szSaveGameName, sizeof(gGameOptions.szSaveGameName), "%s", strSaveGameName);
4536      gGameOptions.nSaveGameSlot = nSlot;
4537      const PLAYER playerTemp = *gMe; // temp player struct while we make autosaving a little more easier (blood is stressful enough already)
4538      if (!bLevelStartSave) // if key save, reset problematic weapon states
4539      {
4540          playerResetWeaponState(gMe, true);
4541          gMe->invulTime = (int)gFrameClock; // in case they get hitscanned right after loading
4542      }
4543      LoadSave::SaveGame(strSaveGameName);
4544      *gMe = playerTemp; // restore current player struct
4545      if (!bLevelStartSave) // don't print message on level start autosaves
4546          viewSetMessage("Autosaved...");
4547      gGameOptions.picEntry = gSavedOffset;
4548      gSaveGameOptions[nSlot] = gGameOptions;
4549      LoadUpdateSaveGame(nSlot, gProfile[myconnectindex].skill);
4550      gQuickLoadSlot = nSlot;
4551      gAutosaveInCurLevel = true;
4552  }
4553  
4554  void LoadGame(CGameMenuItemZEditBitmap *pItem, CGameMenuEvent *event)
4555  {
4556      UNREFERENCED_PARAMETER(event);
4557      char strLoadGameName[BMAX_PATH];
4558      int nSlot = pItem->at28;
4559      if (gGameOptions.nGameType != kGameTypeSinglePlayer)
4560          return;
4561      if (nSlot <= kLoadSaveSlot10)
4562      {
4563          if (G_ModDirSnprintf(strLoadGameName, BMAX_PATH, "game00%02d.sav", nSlot))
4564              return;
4565      }
4566      else
4567      {
4568          if (G_ModDirSnprintf(strLoadGameName, BMAX_PATH, "gameautosave%1d.sav", nSlot == kLoadSaveSlotSpawn ? 0 : 1))
4569              return;
4570      }
4571      int const bakpathsearchmode = pathsearchmode;
4572      pathsearchmode = 1;
4573      if (!testkopen(strLoadGameName, 0))
4574      {
4575          pathsearchmode = bakpathsearchmode;
4576          return;
4577      }
4578      if (!gGameStarted || LoadSavedInCurrentSession(nSlot)) // if save slot is from a different session, set autosave state to false
4579          gAutosaveInCurLevel = false;
4580      if (gShowLoadingSavingBackground)
4581      {
4582          viewLoadingScreen(gMenuPicnum, "Loading", "Loading Saved Game", strRestoreGameStrings[nSlot]);
4583          videoNextPage();
4584      }
4585      LoadSave::LoadGame(strLoadGameName);
4586      gGameMenuMgr.Deactivate();
4587      gQuickLoadSlot = nSlot;
4588      pathsearchmode = bakpathsearchmode;
4589  }
4590  
4591  void QuickLoadGame(void)
4592  {
4593      char strLoadGameName[BMAX_PATH];
4594      if (gGameOptions.nGameType != kGameTypeSinglePlayer)
4595          return;
4596      if (gQuickLoadSlot < kLoadSaveSlotAutosave)
4597      {
4598          if (G_ModDirSnprintf(strLoadGameName, BMAX_PATH, "game00%02d.sav", gQuickLoadSlot))
4599              return;
4600      }
4601      else
4602      {
4603          if (G_ModDirSnprintf(strLoadGameName, BMAX_PATH, "gameautosave%1d.sav", gQuickLoadSlot == kLoadSaveSlotSpawn ? 0 : 1))
4604              return;
4605      }
4606      int const bakpathsearchmode = pathsearchmode;
4607      pathsearchmode = 1;
4608      if (!testkopen(strLoadGameName, 0))
4609      {
4610          pathsearchmode = bakpathsearchmode;
4611          return;
4612      }
4613      if (!LoadSavedInCurrentSession(gQuickLoadSlot)) // if save slot is from a different session, set autosave state to false
4614          gAutosaveInCurLevel = false;
4615      if (gShowLoadingSavingBackground)
4616      {
4617          viewLoadingScreen(gMenuPicnum, "Loading", "Loading Saved Game", strRestoreGameStrings[gQuickLoadSlot]);
4618          videoNextPage();
4619      }
4620      LoadSave::LoadGame(strLoadGameName);
4621      gGameMenuMgr.Deactivate();
4622      pathsearchmode = bakpathsearchmode;
4623  }
4624  
4625  void SetupLevelMenuItem(int nEpisode)
4626  {
4627      dassert(nEpisode >= 0 && nEpisode < gEpisodeCount);
4628      itemNetStart3.SetTextArray(zLevelNames[nEpisode], gEpisodeInfo[nEpisode].nLevels, 0);
4629  }
4630  
4631  void SetupNetLevels(CGameMenuItemZCycle *pItem)
4632  {
4633      SetupLevelMenuItem(pItem->m_nFocus);
4634      NetClearUserMap(pItem);
4635  }
4636  
4637  void NetClearUserMap(CGameMenuItemZCycle *pItem)
4638  {
4639      UNREFERENCED_PARAMETER(pItem);
4640      memset(zUserMapName, 0, sizeof(zUserMapName));
4641  }
4642  
4643  void StartNetGame(CGameMenuItemChain *pItem)
4644  {
4645      UNREFERENCED_PARAMETER(pItem);
4646      gPacketStartGame.gameType = itemNetGameMode.m_nFocus+1;
4647      if (gPacketStartGame.gameType == kGameTypeSinglePlayer)
4648          gPacketStartGame.gameType = kGameTypeBloodBath;
4649      gPacketStartGame.uNetGameFlags = kNetGameFlagNone;
4650      if (gPacketStartGame.gameType != kGameTypeCoop) // bloodbath/teams score and time limits
4651      {
4652          if (itemNetGameSliderScoreLimit.nValue > 0)
4653              gPacketStartGame.uNetGameFlags |= (ClipRange(itemNetGameSliderScoreLimit.nValue, 1, 255)<<kNetGameFlagScoresLimitBase)&kNetGameFlagScoresLimitMask;
4654          if (itemNetGameSliderTimeLimit.nValue > 0)
4655              gPacketStartGame.uNetGameFlags |= (ClipRange(itemNetGameSliderTimeLimit.nValue, 1, 63)<<kNetGameFlagTimeLimitBase)&kNetGameFlagTimeLimitMask;
4656      }
4657      else if (itemNetGameSliderLivesLimit.nValue > 0) // co-op lives
4658          gPacketStartGame.uNetGameFlags |= (ClipRange(itemNetGameSliderLivesLimit.nValue, 1, 255)<<kNetGameFlagScoresLimitBase)&kNetGameFlagScoresLimitMask;
4659      if (!itemNetGameBoolExit.at20 && (gPacketStartGame.gameType != kGameTypeCoop))
4660          gPacketStartGame.uNetGameFlags |= kNetGameFlagNoLevelExit;
4661      if (!itemNetGameBoolTeleFrag.at20)
4662          gPacketStartGame.uNetGameFlags |= kNetGameFlagNoTeleFrag;
4663      if (!itemNetGameBoolSkillOverride.at20)
4664          gPacketStartGame.uNetGameFlags |= kNetGameFlagSkillIssue;
4665      if (!itemNetGameBoolModelOverride.at20)
4666          gPacketStartGame.uNetGameFlags |= kNetGameFlagCalebOnly;
4667      if (!itemNetGameBoolPlayerColors.at20)
4668          gPacketStartGame.uNetGameFlags |= kNetGameFlagVanillaColors;
4669      if (!itemNetGameBoolTeamColors.at20)
4670          gPacketStartGame.uNetGameFlags |= kNetGameFlagNoTeamColors;
4671      if (!itemNetGameBoolTeamFlags.at20)
4672          gPacketStartGame.uNetGameFlags |= kNetGameFlagNoTeamFlags;
4673      if (itemNetGameCycleSpawnLocation.m_nFocus > 0)
4674          gPacketStartGame.uNetGameFlags |= itemNetGameCycleSpawnLocation.m_nFocus == 1 ? kNetGameFlagSpawnSmart : kNetGameFlagSpawnDist;
4675      if (gPacketStartGame.gameType == kGameTypeTeams)
4676      {
4677          if (itemNetGameCycleShowWeaponsOverrideTeams.m_nFocus == 1)
4678              gPacketStartGame.uNetGameFlags |= kNetGameFlagHideWeaponsCloak;
4679          else if (itemNetGameCycleShowWeaponsOverrideTeams.m_nFocus == 2)
4680              gPacketStartGame.uNetGameFlags |= kNetGameFlagHideWeaponsAlways;
4681          else if (itemNetGameCycleShowWeaponsOverrideTeams.m_nFocus == 3)
4682              gPacketStartGame.uNetGameFlags |= kNetGameFlagHideWeaponsTeams;
4683      }
4684      else
4685      {
4686          if (itemNetGameCycleShowWeaponsOverride.m_nFocus == 1)
4687              gPacketStartGame.uNetGameFlags |= kNetGameFlagHideWeaponsCloak;
4688          else if (itemNetGameCycleShowWeaponsOverride.m_nFocus == 2)
4689              gPacketStartGame.uNetGameFlags |= kNetGameFlagHideWeaponsAlways;
4690      }
4691      if (itemNetGameCycleMirrorModeOverride.m_nFocus & 1)
4692          gPacketStartGame.uNetGameFlags |= kNetGameFlagMirrorHoriz;
4693      if (itemNetGameCycleMirrorModeOverride.m_nFocus & 2)
4694          gPacketStartGame.uNetGameFlags |= kNetGameFlagMirrorVert;
4695      if (!itemNetStartBoolChaseView.at20)
4696          gPacketStartGame.uNetGameFlags |= kNetGameFlagNoChaseView;
4697      if (!itemNetStartBoolHolstering.at20)
4698          gPacketStartGame.uNetGameFlags |= kNetGameFlagNoHolstering;
4699      if ((itemNetStartBoolSecondWind.at20 && gPacketStartGame.gameType == kGameTypeCoop) || (!itemNetStartBoolSecondWind.at20 && gPacketStartGame.gameType != kGameTypeCoop))
4700          gPacketStartGame.uNetGameFlags |= kNetGameFlagSecondWindToggle;
4701      if (itemNetStartBoolSpectatorMode.at20)
4702          gPacketStartGame.uNetGameFlags |= kNetGameFlagSpectatingAllow;
4703      gPacketStartGame.episodeId = itemNetStart2.m_nFocus;
4704      gPacketStartGame.levelId = itemNetStart3.m_nFocus;
4705      gPacketStartGame.difficulty = itemNetStart4.m_nFocus;
4706      gPacketStartGame.weaponSettings = itemNetStart6.m_nFocus;
4707      gPacketStartGame.itemSettings = itemNetStart7.m_nFocus;
4708      gPacketStartGame.respawnSettings = 0;
4709      gPacketStartGame.bFriendlyFire = itemNetGameBoolFriendlyFire.at20;
4710      gPacketStartGame.keySettings = itemNetGameCycleKey.m_nFocus;
4711      gPacketStartGame.itemWeaponSettings = itemNetGameCycleItemWeapon.m_nFocus;
4712      gPacketStartGame.bAutoTeams = itemNetGameBoolAutoTeams.at20;
4713      gPacketStartGame.nSpawnProtection = itemNetGameCycleSpawnProtection.m_nFocus;
4714      gPacketStartGame.nSpawnWeapon = itemNetGameCycleSpawnWeapon.m_nFocus;
4715  
4716      gPacketStartGame.monsterSettings = itemNetMonsterSettings.m_nFocus;
4717      gPacketStartGame.monsterQuantity = ClipRange(itemNetMonsterQuantity.nValue, 0, 4);
4718      gPacketStartGame.monsterHealth = ClipRange(itemNetMonsterHealth.nValue, 0, 4);
4719      gPacketStartGame.monsterSpeed = ClipRange(itemNetMonsterSpeed.m_nFocus, 0, 4);
4720  
4721      ////
4722      SetGameVanillaMode(0); // turn off vanilla mode for multiplayer so menus don't get bugged
4723      gPacketStartGame.bQuadDamagePowerup = itemNetMutatorBoolQuadDamagePowerup.at20;
4724      gPacketStartGame.nDamageInvul = itemNetMutatorDamageInvul.m_nFocus % ARRAY_SSIZE(pzDamageInvulBehaviorStrings);
4725      gPacketStartGame.nProjectileBehavior = itemNetMutatorProjectileBehavior.m_nFocus % ARRAY_SSIZE(pzProjectileBehaviorStrings);
4726      gPacketStartGame.bNapalmFalloff = itemNetMutatorNapalmFalloff.at20;
4727      gPacketStartGame.nEnemyBehavior = itemNetMutatorEnemyBehavior.m_nFocus % ARRAY_SSIZE(pzEnemyBehaviorStrings);
4728      gPacketStartGame.bEnemyRandomTNT = itemNetMutatorBoolEnemyRandomTNT.at20;
4729      gPacketStartGame.nWeaponsVer = itemNetMutatorWeaponsVer.m_nFocus % ARRAY_SSIZE(pzWeaponsVersionStrings);
4730      gPacketStartGame.nAmmoScale = itemNetMutatorAmmoScale.m_nFocus % ARRAY_SSIZE(pzAmmoScaleStrings);
4731      gPacketStartGame.bSectorBehavior = itemNetMutatorSectorBehavior.at20;
4732      gPacketStartGame.nHitscanProjectiles = itemNetMutatorHitscanProjectiles.m_nFocus % ARRAY_SSIZE(pzHitscanProjectilesStrings);
4733      gPacketStartGame.nGoreBehavior = itemNetMutatorGoreBehavior.m_nFocus % ARRAY_SSIZE(pzGoreStrings);
4734      gPacketStartGame.nPlayerSpeed = itemNetMutatorPlayerSpeed.m_nFocus % ARRAY_SSIZE(pzPlayerSpeeds);
4735      gPacketStartGame.randomizerMode = itemNetMutatorRandomizerMode.m_nFocus % ARRAY_SSIZE(pzRandomizerModeStrings);
4736      Bstrncpy(gPacketStartGame.szRandomizerSeed, szRandomizerSeedMenu, sizeof(gPacketStartGame.szRandomizerSeed));
4737      if (gPacketStartGame.szRandomizerSeed[0] == '\0') // if no seed entered, generate new one before sending packet
4738          sprintf(gPacketStartGame.szRandomizerSeed, "%08X", QRandom2(gGameMenuMgr.m_mousepos.x*gGameMenuMgr.m_mousepos.y));
4739      gPacketStartGame.uSpriteBannedFlags = SetBannedSprites(0);
4740      ////
4741      Bstrncpy(gPacketStartGame.userMapName, zUserMapName, sizeof(zUserMapName));
4742      gPacketStartGame.userMap = gPacketStartGame.userMapName[0] != '\0';
4743  
4744      netBroadcastNewGame();
4745      gStartNewGame = 1;
4746      gGameMenuMgr.Deactivate();
4747  }
4748  
4749  void Restart(CGameMenuItemChain *pItem)
4750  {
4751      UNREFERENCED_PARAMETER(pItem);
4752      if (gGameOptions.nGameType == kGameTypeSinglePlayer || numplayers == 1)
4753      {
4754          gQuitGame = true;
4755          gRestartGame = true;
4756      }
4757      else
4758          gQuitRequest = 2;
4759      gGameMenuMgr.Deactivate();
4760  }
4761  
4762  void Quit(CGameMenuItemChain *pItem)
4763  {
4764      UNREFERENCED_PARAMETER(pItem);
4765      if (gGameOptions.nGameType == kGameTypeSinglePlayer || numplayers == 1)
4766          gQuitGame = true;
4767      else
4768          gQuitRequest = 1;
4769      gGameMenuMgr.Deactivate();
4770  }
4771  
4772  void MenuSetupEpisodeInfo(void)
4773  {
4774      memset(zEpisodeNames, 0, sizeof(zEpisodeNames));
4775      memset(zLevelNames, 0, sizeof(zLevelNames));
4776      for (int i = 0; i < 6; i++)
4777      {
4778          if (i < gEpisodeCount)
4779          {
4780              EPISODEINFO *pEpisode = &gEpisodeInfo[i];
4781              zEpisodeNames[i] = pEpisode->title;
4782              for (int j = 0; j < kMaxLevels; j++)
4783              {
4784                  if (j < pEpisode->nLevels)
4785                  {
4786                      zLevelNames[i][j] = pEpisode->levelsInfo[j].Title;
4787                  }
4788              }
4789          }
4790      }
4791  }
4792  
4793  void drawLoadingScreen(int nTile)
4794  {
4795      char buffer[80];
4796      if (gGameOptions.nGameType == kGameTypeSinglePlayer)
4797      {
4798          if (gDemo.bPlaying)
4799              sprintf(buffer, "Loading Demo");
4800          else
4801              sprintf(buffer, "Loading Level");
4802      }
4803      else
4804          sprintf(buffer, "%s", zNetGameTypes[gGameOptions.nGameType-1]);
4805      viewLoadingScreen(nTile, buffer, levelGetTitle(), NULL);
4806  }