/ source / blood / src / osdcmd.cpp
osdcmd.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  
  24  #include "build.h"
  25  #include "baselayer.h"
  26  #include "keyboard.h"
  27  #include "control.h"
  28  #include "osd.h"
  29  #include "compat.h"
  30  #include "mmulti.h"
  31  #include "sndcards.h"
  32  #include "fx_man.h"
  33  #include "common_game.h"
  34  #include "config.h"
  35  #include "blood.h"
  36  #include "demo.h"
  37  #include "gamemenu.h"
  38  #include "globals.h"
  39  #include "levels.h"
  40  #include "menu.h"
  41  #include "messages.h"
  42  #include "network.h"
  43  #include "osdcmds.h"
  44  #include "screen.h"
  45  #include "sound.h"
  46  #include "sfx.h"
  47  #include "view.h"
  48  
  49  
  50  static inline int osdcmd_quit(osdcmdptr_t UNUSED(parm))
  51  {
  52      UNREFERENCED_CONST_PARAMETER(parm);
  53      OSD_ShowDisplay(0);
  54      QuitGame();
  55      return OSDCMD_OK;
  56  }
  57  
  58  static int osdcmd_changelevel(osdcmdptr_t parm)
  59  {
  60      int32_t volume,level;
  61      char *p;
  62  
  63      if (parm->numparms != 2) return OSDCMD_SHOWHELP;
  64  
  65      volume = strtol(parm->parms[0], &p, 10) - 1;
  66      if (p[0]) return OSDCMD_SHOWHELP;
  67      level = strtol(parm->parms[1], &p, 10) - 1;
  68      if (p[0]) return OSDCMD_SHOWHELP;
  69  
  70      if (volume < 0) return OSDCMD_SHOWHELP;
  71      if (level < 0) return OSDCMD_SHOWHELP;
  72  
  73      if (volume >= 6)
  74      {
  75          OSD_Printf("changelevel: invalid volume number (range 1-%d)\n",6);
  76          return OSDCMD_OK;
  77      }
  78  
  79      if (level >= gEpisodeInfo[volume].nLevels)
  80      {
  81          OSD_Printf("changelevel: invalid level number\n");
  82          return OSDCMD_SHOWHELP;
  83      }
  84  
  85      if (gDemo.bPlaying)
  86          gDemo.StopPlayback();
  87      else if (gDemo.bRecording)
  88          gDemo.Close();
  89  
  90      if (numplayers > 1)
  91      {
  92          gPacketStartGame.episodeId = volume;
  93          gPacketStartGame.levelId = level;
  94          netBroadcastNewGame();
  95          gStartNewGame = 1;
  96          gGameMenuMgr.Deactivate();
  97          return OSDCMD_OK;
  98      }
  99      else if (gGameStarted && !gDemo.bPlaying && !gDemo.bRecording) // keep items while changing level
 100      {
 101          gGameOptions.uGameFlags |= kGameFlagContinuing;
 102      }
 103      levelSetupOptions(volume, level);
 104      StartLevel(&gGameOptions);
 105      viewResizeView(gViewSize);
 106      gGameMenuMgr.Deactivate();
 107  
 108      return OSDCMD_OK;
 109  }
 110  
 111  static int osdcmd_map(osdcmdptr_t parm)
 112  {
 113      char filename[BMAX_PATH];
 114  
 115      const int32_t wildcardp = parm->numparms==1 &&
 116          (Bstrchr(parm->parms[0], '*') != NULL);
 117  
 118      if (parm->numparms != 1 || wildcardp)
 119      {
 120          BUILDVFS_FIND_REC *r;
 121          fnlist_t fnlist = FNLIST_INITIALIZER;
 122          int32_t maxwidth = 0;
 123  
 124          if (wildcardp)
 125              maybe_append_ext(filename, sizeof(filename), parm->parms[0], ".map");
 126          else
 127              Bstrcpy(filename, "*.MAP");
 128  
 129          fnlist_getnames(&fnlist, "/", filename, -1, 0);
 130          gSysRes.FNAddFiles(&fnlist, filename);
 131  
 132          for (r=fnlist.findfiles; r; r=r->next)
 133              maxwidth = max<int>(maxwidth, Bstrlen(r->name));
 134  
 135          if (maxwidth > 0)
 136          {
 137              int32_t x = 0;
 138              maxwidth += 3;
 139              OSD_Printf(OSDTEXT_RED "Map listing:\n");
 140              for (r=fnlist.findfiles; r; r=r->next)
 141              {
 142                  OSD_Printf("%-*s",maxwidth,r->name);
 143                  x += maxwidth;
 144                  if (x > OSD_GetCols() - maxwidth)
 145                  {
 146                      x = 0;
 147                      OSD_Printf("\n");
 148                  }
 149              }
 150              if (x) OSD_Printf("\n");
 151              OSD_Printf(OSDTEXT_RED "Found %d maps\n", fnlist.numfiles);
 152          }
 153  
 154          fnlist_clearnames(&fnlist);
 155  
 156          return OSDCMD_SHOWHELP;
 157      }
 158  
 159      strcpy(filename, parm->parms[0]);
 160      ChangeExtension(filename, "");
 161  
 162      if (!gSysRes.Lookup(filename, "MAP"))
 163      {
 164          OSD_Printf(OSD_ERROR "map: file \"%s\" not found.\n", filename);
 165          return OSDCMD_OK;
 166      }
 167  
 168      if (gDemo.bPlaying)
 169          gDemo.StopPlayback();
 170      else if (gDemo.bRecording)
 171          gDemo.Close();
 172  
 173      int bFound = 0;
 174      for (int i = 0; i < gEpisodeCount; i++)
 175      {
 176          auto pEpisodeInfo = &gEpisodeInfo[i];
 177          for (int j = 0; j < pEpisodeInfo->nLevels; j++)
 178          {
 179              auto pLevelInfo = &pEpisodeInfo->levelsInfo[j];
 180              if (!Bstrcasecmp(pLevelInfo->Filename, filename))
 181              {
 182                  gGameOptions.nEpisode = i;
 183                  gGameOptions.nLevel = j;
 184                  bFound = 1;
 185              }
 186          }
 187      }
 188      if (!bFound)
 189          levelAddUserMap(filename);
 190  
 191      if (numplayers > 1)
 192      {
 193          gPacketStartGame.episodeId = gGameOptions.nEpisode;
 194          gPacketStartGame.levelId = gGameOptions.nLevel;
 195          netBroadcastNewGame();
 196          gStartNewGame = 1;
 197          gGameMenuMgr.Deactivate();
 198          return OSDCMD_OK;
 199      }
 200      levelSetupOptions(gGameOptions.nEpisode, gGameOptions.nLevel);
 201      StartLevel(&gGameOptions);
 202      viewResizeView(gViewSize);
 203      gGameMenuMgr.Deactivate();
 204  
 205      return OSDCMD_OK;
 206  }
 207  
 208  static int osdcmd_demo(osdcmdptr_t parm)
 209  {
 210      if (numplayers > 1)
 211      {
 212          OSD_Printf("Command not allowed in multiplayer\n");
 213          return OSDCMD_OK;
 214      }
 215      if (gDemo.bRecording)
 216          gDemo.Close();
 217  
 218      //if (g_player[myconnectindex].ps->gm & MODE_GAME)
 219      //{
 220      //    OSD_Printf("demo: Must not be in a game.\n");
 221      //    return OSDCMD_OK;
 222      //}
 223  
 224      if (parm->numparms != 1/* && parm->numparms != 2*/)
 225          return OSDCMD_SHOWHELP;
 226  
 227      gDemo.SetupPlayback(parm->parms[0]);
 228      gGameStarted = 0;
 229      gDemo.Playback();
 230  
 231      return OSDCMD_OK;
 232  }
 233  
 234  static int osdcmd_demorecord(osdcmdptr_t parm)
 235  {
 236      int32_t volume,level;
 237      char *p;
 238  
 239      if (numplayers > 1)
 240      {
 241          OSD_Printf("Command not allowed in multiplayer\n");
 242          return OSDCMD_OK;
 243      }
 244  
 245      if (parm->numparms != 3) return OSDCMD_SHOWHELP;
 246  
 247      volume = strtol(parm->parms[0], &p, 10) - 1;
 248      if (p[0]) return OSDCMD_SHOWHELP;
 249      level = strtol(parm->parms[1], &p, 10) - 1;
 250      if (p[0]) return OSDCMD_SHOWHELP;
 251  
 252      if (volume < 0) return OSDCMD_SHOWHELP;
 253      if (level < 0) return OSDCMD_SHOWHELP;
 254  
 255      if (volume >= 6)
 256      {
 257          OSD_Printf("changelevel: invalid volume number (range 1-%d)\n",6);
 258          return OSDCMD_OK;
 259      }
 260  
 261      if (level >= gEpisodeInfo[volume].nLevels)
 262      {
 263          OSD_Printf("changelevel: invalid level number\n");
 264          return OSDCMD_SHOWHELP;
 265      }
 266  
 267      if (gDemo.bPlaying)
 268      {
 269          gDemo.StopPlayback();
 270          OSD_Printf("Cannot record while playing back demo, stopping demo...\n");
 271          return OSDCMD_OK;
 272      }
 273      if (gDemo.bRecording)
 274          gDemo.Close();
 275      gGameStarted = 0;
 276  
 277      gGameMenuMgr.Deactivate();
 278      gGameOptions.nDifficulty = ClipRange(strtol(parm->parms[2], &p, 10) - 1, 0, 4);
 279      LevelWarpAndRecord(volume, level);
 280  
 281      return OSDCMD_OK;
 282  }
 283  
 284  int osdcmd_restartvid(osdcmdptr_t UNUSED(parm))
 285  {
 286      UNREFERENCED_CONST_PARAMETER(parm);
 287      videoResetMode();
 288      if (videoSetGameMode(gSetup.fullscreen,gSetup.xdim,gSetup.ydim,gSetup.bpp,0))
 289          ThrowError("restartvid: Reset failed...\n");
 290      onvideomodechange(gSetup.bpp>8);
 291      viewResizeView(gViewSize);
 292  
 293      return OSDCMD_OK;
 294  }
 295  
 296  static int osdcmd_music(osdcmdptr_t parm)
 297  {
 298      char buffer[128];
 299      if (parm->numparms == 1)
 300      {
 301          int32_t sel = levelGetMusicIdx(parm->parms[0]);
 302  
 303          if (sel == -1)
 304              return OSDCMD_SHOWHELP;
 305  
 306          if (sel == -2)
 307          {
 308              OSD_Printf("%s is not a valid episode/level number pair\n", parm->parms[0]);
 309              return OSDCMD_OK;
 310          }
 311  
 312          int nEpisode = sel/kMaxLevels;
 313          int nLevel = sel%kMaxLevels;
 314  
 315          if (!levelTryPlayMusic(nEpisode, nLevel))
 316          {
 317              if (CDAudioToggle)
 318                  snprintf(buffer, sizeof(buffer), "Playing track %i", gEpisodeInfo[nEpisode].levelsInfo[nLevel].SongId);
 319              else
 320                  snprintf(buffer, sizeof(buffer), "Playing %s", gEpisodeInfo[nEpisode].levelsInfo[nLevel].Song);
 321              viewSetMessage(buffer);
 322          }
 323          else
 324          {
 325              OSD_Printf("No music defined for %s\n", parm->parms[0]);
 326          }
 327  
 328          return OSDCMD_OK;
 329      }
 330  
 331      return OSDCMD_SHOWHELP;
 332  }
 333  
 334  static int osdcmd_vidmode(osdcmdptr_t parm)
 335  {
 336      int32_t newbpp = gSetup.bpp, newwidth = gSetup.xdim,
 337              newheight = gSetup.ydim, newfs = gSetup.fullscreen;
 338      int32_t tmp;
 339  
 340      if (parm->numparms < 1 || parm->numparms > 4) return OSDCMD_SHOWHELP;
 341  
 342      switch (parm->numparms)
 343      {
 344      case 1: // bpp switch
 345          tmp = Batol(parm->parms[0]);
 346          if (!(tmp==8 || tmp==16 || tmp==32))
 347              return OSDCMD_SHOWHELP;
 348          newbpp = tmp;
 349          break;
 350      case 2: // res switch
 351          newwidth = Batol(parm->parms[0]);
 352          newheight = Batol(parm->parms[1]);
 353          break;
 354      case 3: // res & bpp switch
 355      case 4:
 356          newwidth = Batol(parm->parms[0]);
 357          newheight = Batol(parm->parms[1]);
 358          tmp = Batol(parm->parms[2]);
 359          if (!(tmp==8 || tmp==16 || tmp==32))
 360              return OSDCMD_SHOWHELP;
 361          newbpp = tmp;
 362          if (parm->numparms == 4)
 363              newfs = (Batol(parm->parms[3]) != 0);
 364          break;
 365      }
 366  
 367      if (videoSetGameMode(newfs,newwidth,newheight,newbpp,upscalefactor))
 368      {
 369          LOG_F(ERROR, "vidmode: Mode change failed!");
 370          if (videoSetGameMode(gSetup.fullscreen, gSetup.xdim, gSetup.ydim, gSetup.bpp, upscalefactor))
 371              ThrowError("vidmode: Reset failed!\n");
 372      }
 373      gSetup.bpp = newbpp;
 374      gSetup.xdim = newwidth;
 375      gSetup.ydim = newheight;
 376      gSetup.fullscreen = newfs;
 377      onvideomodechange(gSetup.bpp>8);
 378      viewResizeView(gViewSize);
 379      return OSDCMD_OK;
 380  }
 381  
 382  static int osdcmd_crosshaircolor(osdcmdptr_t parm)
 383  {
 384      if (parm->numparms != 3)
 385      {
 386          OSD_Printf("crosshaircolor: r:%d g:%d b:%d\n",CrosshairColors.r,CrosshairColors.g,CrosshairColors.b);
 387          return OSDCMD_SHOWHELP;
 388      }
 389  
 390      uint8_t const r = Batol(parm->parms[0]);
 391      uint8_t const g = Batol(parm->parms[1]);
 392      uint8_t const b = Batol(parm->parms[2]);
 393  
 394      g_isAlterDefaultCrosshair = true;
 395      viewSetCrosshairColor(r,g,b);
 396  
 397      if (!OSD_ParsingScript())
 398          OSD_Printf("%s\n", parm->raw);
 399  
 400      return OSDCMD_OK;
 401  }
 402  
 403  static int osdcmd_resetcrosshair(osdcmdptr_t UNUSED(parm))
 404  {
 405      UNREFERENCED_CONST_PARAMETER(parm);
 406      g_isAlterDefaultCrosshair = false;
 407      viewResetCrosshairToDefault();
 408  
 409      return OSDCMD_OK;
 410  }
 411  
 412  static int osdcmd_give(osdcmdptr_t parm)
 413  {
 414      if (numplayers != 1 || !gGameStarted || gDemo.bPlaying || gDemo.bRecording || gMe->pXSprite->health == 0)
 415      {
 416          OSD_Printf("give: Cannot give while dead or not in a single-player game.\n");
 417          return OSDCMD_OK;
 418      }
 419  
 420      if (parm->numparms != 1) return OSDCMD_SHOWHELP;
 421  
 422      if (!Bstrcasecmp(parm->parms[0], "all"))
 423      {
 424          SetWeapons(true);
 425          SetAmmo(true);
 426          SetToys(true);
 427          SetArmor(true);
 428          SetKeys(true);
 429          gCheatMgr.m_bPlayerCheated = true;
 430          return OSDCMD_OK;
 431      }
 432      else if (!Bstrcasecmp(parm->parms[0], "health"))
 433      {
 434          actHealDude(gMe->pXSprite, 200, 200);
 435          gCheatMgr.m_bPlayerCheated = true;
 436          return OSDCMD_OK;
 437      }
 438      else if (!Bstrcasecmp(parm->parms[0], "weapons"))
 439      {
 440          SetWeapons(true);
 441          gCheatMgr.m_bPlayerCheated = true;
 442          return OSDCMD_OK;
 443      }
 444      else if (!Bstrcasecmp(parm->parms[0], "ammo"))
 445      {
 446          SetAmmo(true);
 447          gCheatMgr.m_bPlayerCheated = true;
 448          return OSDCMD_OK;
 449      }
 450      else if (!Bstrcasecmp(parm->parms[0], "armor"))
 451      {
 452          SetArmor(true);
 453          gCheatMgr.m_bPlayerCheated = true;
 454          return OSDCMD_OK;
 455      }
 456      else if (!Bstrcasecmp(parm->parms[0], "keys"))
 457      {
 458          SetKeys(true);
 459          gCheatMgr.m_bPlayerCheated = true;
 460          return OSDCMD_OK;
 461      }
 462      else if (!Bstrcasecmp(parm->parms[0], "inventory"))
 463      {
 464          SetToys(true);
 465          gCheatMgr.m_bPlayerCheated = true;
 466          return OSDCMD_OK;
 467      }
 468      return OSDCMD_SHOWHELP;
 469  }
 470  
 471  static int osdcmd_god(osdcmdptr_t UNUSED(parm))
 472  {
 473      UNREFERENCED_CONST_PARAMETER(parm);
 474      if (numplayers == 1 && gGameStarted && !gDemo.bPlaying && !gDemo.bRecording)
 475      {
 476          SetGodMode(!gMe->godMode);
 477          gCheatMgr.m_bPlayerCheated = true;
 478      }
 479      else
 480          OSD_Printf("god: Not in a single-player game.\n");
 481  
 482      return OSDCMD_OK;
 483  }
 484  
 485  static int osdcmd_noclip(osdcmdptr_t UNUSED(parm))
 486  {
 487      UNREFERENCED_CONST_PARAMETER(parm);
 488  
 489      if (numplayers == 1 && gGameStarted && !gDemo.bPlaying && !gDemo.bRecording)
 490      {
 491          SetClipMode(!gNoClip);
 492          gCheatMgr.m_bPlayerCheated = true;
 493      }
 494      else
 495      {
 496          OSD_Printf("noclip: Not in a single-player game.\n");
 497      }
 498  
 499      return OSDCMD_OK;
 500  }
 501  
 502  static int osdcmd_notarget(osdcmdptr_t UNUSED(parm))
 503  {
 504      UNREFERENCED_CONST_PARAMETER(parm);
 505  
 506      if (numplayers == 1 && gGameStarted && !gDemo.bPlaying && !gDemo.bRecording)
 507      {
 508          SetTargetMode(!gNoTarget);
 509          gCheatMgr.m_bPlayerCheated = true;
 510      }
 511      else
 512      {
 513          OSD_Printf("notarget: Not in a single-player game.\n");
 514      }
 515  
 516      return OSDCMD_OK;
 517  }
 518  
 519  static int osdcmd_fly(osdcmdptr_t UNUSED(parm))
 520  {
 521      UNREFERENCED_CONST_PARAMETER(parm);
 522      if (numplayers == 1 && gGameStarted && !gDemo.bPlaying && !gDemo.bRecording)
 523      {
 524          SetFlyMode(!gFlyMode);
 525          gCheatMgr.m_bPlayerCheated = true;
 526      }
 527      else
 528          OSD_Printf("fly: Not in a single-player game.\n");
 529  
 530      return OSDCMD_OK;
 531  }
 532  
 533  static int osdcmd_restartsound(osdcmdptr_t UNUSED(parm))
 534  {
 535      UNREFERENCED_CONST_PARAMETER(parm);
 536      sfxTerm();
 537      sndTerm();
 538  
 539      sndInit();
 540      sfxInit();
 541  
 542      if (MusicToggle && (gGameStarted || gDemo.bPlaying || gDemo.bRecording))
 543          sndPlaySong(gGameOptions.zLevelSong, true);
 544  
 545      return OSDCMD_OK;
 546  }
 547  
 548  void onvideomodechange(int32_t newmode)
 549  {
 550  #if 0
 551      uint8_t palid;
 552  
 553      // XXX?
 554      if (!newmode || g_player[screenpeek].ps->palette < BASEPALCOUNT)
 555          palid = g_player[screenpeek].ps->palette;
 556      else
 557          palid = BASEPAL;
 558  
 559  #ifdef POLYMER
 560      if (videoGetRenderMode() == REND_POLYMER)
 561      {
 562          int32_t i = 0;
 563  
 564          while (i < MAXSPRITES)
 565          {
 566              if (actor[i].lightptr)
 567              {
 568                  polymer_deletelight(actor[i].lightId);
 569                  actor[i].lightptr = NULL;
 570                  actor[i].lightId = -1;
 571              }
 572              i++;
 573          }
 574      }
 575  #endif
 576  
 577      videoSetPalette(ud.brightness>>2, palid, 0);
 578      g_restorePalette = -1;
 579  #endif
 580  
 581  #ifdef POLYMER
 582      if (videoGetRenderMode() == REND_POLYMER)
 583      {
 584          int32_t i = 0;
 585  
 586          while (i < MAXSPRITES)
 587          {
 588              if (gPolymerLight[i].lightptr)
 589              {
 590                  polymer_deletelight(gPolymerLight[i].lightId);
 591                  gPolymerLight[i].lightptr = NULL;
 592                  gPolymerLight[i].lightId = -1;
 593              }
 594              i++;
 595          }
 596      }
 597  #endif
 598      if (newmode)
 599          scrResetPalette();
 600      UpdateDacs(gLastPal, false);
 601  }
 602  
 603  static int osdcmd_button(osdcmdptr_t parm)
 604  {
 605      static char const s_gamefunc_[] = "gamefunc_";
 606      int constexpr strlen_gamefunc_  = ARRAY_SIZE(s_gamefunc_) - 1;
 607  
 608      char const *p = parm->name + strlen_gamefunc_;
 609  
 610  //    if (g_player[myconnectindex].ps->gm == MODE_GAME) // only trigger these if in game
 611      if (gInputMode == INPUT_MODE_0)
 612          CONTROL_ButtonFlags[CONFIG_FunctionNameToNum(p)] = 1; // FIXME
 613  
 614      return OSDCMD_OK;
 615  }
 616  
 617  const char *const ConsoleButtons[] =
 618  {
 619      "mouse1", "mouse2", "mouse3", "mouse4", "mwheelup",
 620      "mwheeldn", "mouse5", "mouse6", "mouse7", "mouse8"
 621  };
 622  
 623  static int osdcmd_bind(osdcmdptr_t parm)
 624  {
 625      char buffer[2048];
 626      if (parm->numparms==1 && !Bstrcasecmp(parm->parms[0],"showkeys"))
 627      {
 628          for (auto & s : sctokeylut)
 629              OSD_Printf("%s\n", s.key);
 630          for (auto ConsoleButton : ConsoleButtons)
 631              OSD_Printf("%s\n",ConsoleButton);
 632          return OSDCMD_OK;
 633      }
 634  
 635      if (parm->numparms==0)
 636      {
 637          int j=0;
 638  
 639          OSD_Printf("Current key bindings:\n");
 640  
 641          for (int i=0; i<MAXBOUNDKEYS+MAXMOUSEBUTTONS; i++)
 642              if (CONTROL_KeyIsBound(i))
 643              {
 644                  j++;
 645                  OSD_Printf("%-9s %s\"%s\"\n", CONTROL_KeyBinds[i].key, CONTROL_KeyBinds[i].repeat?"":"norepeat ",
 646                             CONTROL_KeyBinds[i].cmdstr);
 647              }
 648  
 649          if (j == 0)
 650              OSD_Printf("No binds found.\n");
 651  
 652          return OSDCMD_OK;
 653      }
 654  
 655      int i, j, repeat;
 656  
 657      for (i=0; i < ARRAY_SSIZE(sctokeylut); i++)
 658      {
 659          if (!Bstrcasecmp(parm->parms[0], sctokeylut[i].key))
 660              break;
 661      }
 662  
 663      // didn't find the key
 664      if (i == ARRAY_SSIZE(sctokeylut))
 665      {
 666          for (i=0; i<MAXMOUSEBUTTONS; i++)
 667              if (!Bstrcasecmp(parm->parms[0],ConsoleButtons[i]))
 668                  break;
 669  
 670          if (i >= MAXMOUSEBUTTONS)
 671              return OSDCMD_SHOWHELP;
 672  
 673          if (parm->numparms < 2)
 674          {
 675              if (CONTROL_KeyBinds[MAXBOUNDKEYS + i].cmdstr && CONTROL_KeyBinds[MAXBOUNDKEYS + i ].key)
 676                  OSD_Printf("%-9s %s\"%s\"\n", ConsoleButtons[i], CONTROL_KeyBinds[MAXBOUNDKEYS + i].repeat?"":"norepeat ",
 677                  CONTROL_KeyBinds[MAXBOUNDKEYS + i].cmdstr);
 678              else OSD_Printf("%s is unbound\n", ConsoleButtons[i]);
 679              return OSDCMD_OK;
 680          }
 681  
 682          j = 1;
 683  
 684          repeat = 1;
 685          if (!Bstrcasecmp(parm->parms[j],"norepeat"))
 686          {
 687              repeat = 0;
 688              j++;
 689          }
 690  
 691          Bstrcpy(buffer,parm->parms[j++]);
 692          for (; j<parm->numparms; j++)
 693          {
 694              Bstrcat(buffer," ");
 695              Bstrcat(buffer,parm->parms[j++]);
 696          }
 697  
 698          CONTROL_BindMouse(i, buffer, repeat, ConsoleButtons[i]);
 699  
 700          if (!OSD_ParsingScript())
 701              OSD_Printf("%s\n",parm->raw);
 702          return OSDCMD_OK;
 703      }
 704  
 705      if (parm->numparms < 2)
 706      {
 707          if (CONTROL_KeyIsBound(sctokeylut[i].sc))
 708              OSD_Printf("%-9s %s\"%s\"\n", sctokeylut[i].key, CONTROL_KeyBinds[sctokeylut[i].sc].repeat?"":"norepeat ",
 709                         CONTROL_KeyBinds[sctokeylut[i].sc].cmdstr);
 710          else OSD_Printf("%s is unbound\n", sctokeylut[i].key);
 711  
 712          return OSDCMD_OK;
 713      }
 714  
 715      j = 1;
 716  
 717      repeat = 1;
 718      if (!Bstrcasecmp(parm->parms[j],"norepeat"))
 719      {
 720          repeat = 0;
 721          j++;
 722      }
 723  
 724      Bstrcpy(buffer,parm->parms[j++]);
 725      for (; j<parm->numparms; j++)
 726      {
 727          Bstrcat(buffer," ");
 728          Bstrcat(buffer,parm->parms[j++]);
 729      }
 730  
 731      CONTROL_BindKey(sctokeylut[i].sc, buffer, repeat, sctokeylut[i].key);
 732  
 733      char *cp = buffer;
 734  
 735      // Populate the keyboard config menu based on the bind.
 736      // Take care of processing one-to-many bindings properly, too.
 737      static char const s_gamefunc_[] = "gamefunc_";
 738      int constexpr strlen_gamefunc_  = ARRAY_SIZE(s_gamefunc_) - 1;
 739  
 740      while ((cp = Bstrstr(cp, s_gamefunc_)))
 741      {
 742          cp += strlen_gamefunc_;
 743  
 744          char *semi = Bstrchr(cp, ';');
 745  
 746          if (semi)
 747              *semi = 0;
 748  
 749          j = CONFIG_FunctionNameToNum(cp);
 750  
 751          if (semi)
 752              cp = semi+1;
 753  
 754          if (j != -1)
 755          {
 756              KeyboardKeys[j][1] = KeyboardKeys[j][0];
 757              KeyboardKeys[j][0] = sctokeylut[i].sc;
 758  //            CONTROL_MapKey(j, sctokeylut[i].sc, ud.config.KeyboardKeys[j][0]);
 759  
 760              if (j == gamefunc_Show_Console)
 761                  OSD_CaptureKey(sctokeylut[i].sc);
 762          }
 763      }
 764  
 765      if (!OSD_ParsingScript())
 766          OSD_Printf("%s\n",parm->raw);
 767  
 768      return OSDCMD_OK;
 769  }
 770  
 771  static int osdcmd_unbindall(osdcmdptr_t UNUSED(parm))
 772  {
 773      UNREFERENCED_CONST_PARAMETER(parm);
 774  
 775      for (int i = 0; i < MAXBOUNDKEYS; ++i)
 776          CONTROL_FreeKeyBind(i);
 777  
 778      for (int i = 0; i < MAXMOUSEBUTTONS; ++i)
 779          CONTROL_FreeMouseBind(i);
 780  
 781      for (auto &KeyboardKey : KeyboardKeys)
 782          KeyboardKey[0] = KeyboardKey[1] = 0xff;
 783  
 784      if (!OSD_ParsingScript())
 785          OSD_Printf("unbound all controls\n");
 786  
 787      return OSDCMD_OK;
 788  }
 789  
 790  static int osdcmd_unbind(osdcmdptr_t parm)
 791  {
 792      if (parm->numparms != 1)
 793          return OSDCMD_SHOWHELP;
 794  
 795      for (auto ConsoleKey : sctokeylut)
 796      {
 797          if (ConsoleKey.key && !Bstrcasecmp(parm->parms[0], ConsoleKey.key))
 798          {
 799              CONTROL_FreeKeyBind(ConsoleKey.sc);
 800              OSD_Printf("unbound key %s\n", ConsoleKey.key);
 801              return OSDCMD_OK;
 802          }
 803      }
 804  
 805      for (int i = 0; i < MAXMOUSEBUTTONS; i++)
 806      {
 807          if (!Bstrcasecmp(parm->parms[0], ConsoleButtons[i]))
 808          {
 809              CONTROL_FreeMouseBind(i);
 810              OSD_Printf("unbound %s\n", ConsoleButtons[i]);
 811              return OSDCMD_OK;
 812          }
 813      }
 814  
 815      return OSDCMD_SHOWHELP;
 816  }
 817  
 818  static int osdcmd_unbound(osdcmdptr_t parm)
 819  {
 820      if (parm->numparms != 1)
 821          return OSDCMD_OK;
 822  
 823      int const gameFunc = CONFIG_FunctionNameToNum(parm->parms[0]);
 824  
 825      if (gameFunc != -1)
 826          KeyboardKeys[gameFunc][0] = 0;
 827  
 828      return OSDCMD_OK;
 829  }
 830  
 831  static int osdcmd_quicksave(osdcmdptr_t UNUSED(parm))
 832  {
 833      UNREFERENCED_CONST_PARAMETER(parm);
 834      if (!gGameStarted || gDemo.bPlaying || gDemo.bRecording || gGameMenuMgr.m_bActive)
 835          OSD_Printf("quicksave: not in a game.\n");
 836      else if (gGameOptions.bPermaDeath)
 837          OSD_Printf("quicksave: in permadeath mode.\n");
 838      else gDoQuickSave = 1;
 839      return OSDCMD_OK;
 840  }
 841  
 842  static int osdcmd_quickload(osdcmdptr_t UNUSED(parm))
 843  {
 844      UNREFERENCED_CONST_PARAMETER(parm);
 845      if (!gGameStarted || gDemo.bPlaying || gDemo.bRecording || gGameMenuMgr.m_bActive)
 846          OSD_Printf("quickload: not in a game.\n");
 847      else gDoQuickSave = 2;
 848      return OSDCMD_OK;
 849  }
 850  
 851  static int gLastSayTick = 0;
 852  
 853  static int osdcmd_say(osdcmdptr_t parm)
 854  {
 855      if (parm->numparms < 1) return OSDCMD_SHOWHELP;
 856  
 857      const int nSecond = gLevelTime > 0 ? gLevelTime / kTicsPerSec : 0;
 858      if (!gGameStarted)
 859          OSD_Printf("say: game not started.\n");
 860      else if (parm->parms[0][0] == '\0')
 861          return OSDCMD_SHOWHELP;
 862      else if (gLastSayTick == nSecond)
 863          return OSDCMD_OK; // on cooldown
 864      else
 865      {
 866          gLastSayTick = nSecond;
 867          char sMsg[MAXRIDECULELENGTH];
 868          for (int32_t i = 0, nLength = 0; i < parm->numparms; i++)
 869          {
 870              int nParmLength = 0;
 871              while (parm->parms[i][nParmLength] != '\0')
 872              {
 873                  if (nLength == MAXRIDECULELENGTH - 1)
 874                      break;
 875                  sMsg[nLength++] = parm->parms[i][nParmLength++];
 876              }
 877              if ((i == parm->numparms - 1) || (nLength == MAXRIDECULELENGTH - 1))
 878              {
 879                  sMsg[nLength] = '\0';
 880                  break;
 881              }
 882              sMsg[nLength++] = ' ';
 883          }
 884          gPlayerMsg.Set(sMsg);
 885          gPlayerMsg.Send();
 886      }
 887  
 888      return OSDCMD_OK;
 889  }
 890  
 891  static int osdcmd_say_team(osdcmdptr_t parm)
 892  {
 893      if (parm->numparms < 1) return OSDCMD_SHOWHELP;
 894  
 895      const int nSecond = gLevelTime > 0 ? gLevelTime / kTicsPerSec : 0;
 896      if (!gGameStarted)
 897          OSD_Printf("say_team: game not started.\n");
 898      else if (gGameOptions.nGameType != kGameTypeTeams)
 899          OSD_Printf("say_team: team game not active.\n");
 900      else if (parm->parms[0][0] == '\0')
 901          return OSDCMD_SHOWHELP;
 902      else if (gLastSayTick == nSecond)
 903          return OSDCMD_OK; // on cooldown
 904      else
 905      {
 906          gLastSayTick = nSecond;
 907          char sMsg[MAXRIDECULELENGTH];
 908          for (int32_t i = 0, nLength = 0; i < parm->numparms; i++)
 909          {
 910              int nParmLength = 0;
 911              while (parm->parms[i][nParmLength] != '\0')
 912              {
 913                  if (nLength == MAXRIDECULELENGTH - 1)
 914                      break;
 915                  sMsg[nLength++] = parm->parms[i][nParmLength++];
 916              }
 917              if ((i == parm->numparms - 1) || (nLength == MAXRIDECULELENGTH - 1))
 918              {
 919                  sMsg[nLength] = '\0';
 920                  break;
 921              }
 922              sMsg[nLength++] = ' ';
 923          }
 924          gPlayerMsg.bTeamMessage = gGameOptions.nGameType == kGameTypeTeams;
 925          gPlayerMsg.Set(sMsg);
 926          gPlayerMsg.Send();
 927      }
 928  
 929      return OSDCMD_OK;
 930  }
 931  
 932  static int osdcmd_screenshot(osdcmdptr_t parm)
 933  {
 934      static const char *fn = "blud0000.png";
 935  
 936      if (parm->numparms == 1 && !Bstrcasecmp(parm->parms[0], "tga"))
 937          videoCaptureScreenTGA(fn, 0);
 938      else videoCaptureScreen(fn, 0);
 939  
 940      return OSDCMD_OK;
 941  }
 942  
 943  #if 0
 944  static int osdcmd_savestate(osdcmdptr_t UNUSED(parm))
 945  {
 946      UNREFERENCED_PARAMETER(parm);
 947      G_SaveMapState();
 948      return OSDCMD_OK;
 949  }
 950  
 951  static int osdcmd_restorestate(osdcmdptr_t UNUSED(parm))
 952  {
 953      UNREFERENCED_PARAMETER(parm);
 954      G_RestoreMapState();
 955      return OSDCMD_OK;
 956  }
 957  #endif
 958  
 959  #if 0
 960  #ifdef DEBUGGINGAIDS
 961  static int osdcmd_inittimer(osdcmdptr_t parm)
 962  {
 963      if (parm->numparms != 1)
 964      {
 965          OSD_Printf("%dHz timer\n",g_timerTicsPerSecond);
 966          return OSDCMD_SHOWHELP;
 967      }
 968  
 969      G_InitTimer(Batol(parm->parms[0]));
 970  
 971      OSD_Printf("%s\n",parm->raw);
 972      return OSDCMD_OK;
 973  }
 974  #endif
 975  #endif
 976  
 977  static int osdcmd_cvar_set_game(osdcmdptr_t parm)
 978  {
 979      int const r = osdcmd_cvar_set(parm);
 980  
 981      if (r != OSDCMD_OK) return r;
 982  
 983      if (!Bstrcasecmp(parm->name, "r_upscalefactor"))
 984      {
 985          if (in3dmode())
 986          {
 987              videoSetGameMode(fullscreen, xres, yres, bpp, gUpscaleFactor);
 988              viewResizeView(gViewSize);
 989              OSD_Printf("Render resolution set to %dx%d\n", xdim, ydim);
 990          }
 991      }
 992      else if (!Bstrcasecmp(parm->name, "r_renderscale"))
 993      {
 994          if (in3dmode())
 995              viewSetRenderScale(1);
 996      }
 997      else if (!Bstrcasecmp(parm->name, "r_size"))
 998      {
 999          //ud.statusbarmode = (ud.screen_size < 8);
1000          viewResizeView(gViewSize);
1001      }
1002      else if (!Bstrcasecmp(parm->name, "r_ambientlight"))
1003      {
1004          if (r_ambientlight == 0)
1005              r_ambientlightrecip = 256.f;
1006          else r_ambientlightrecip = 1.f/r_ambientlight;
1007      }
1008      else if (!Bstrcasecmp(parm->name, "vid_gamma"))
1009      {
1010          gBrightness = GAMMA_CALC;
1011          gBrightness <<= 2;
1012          videoSetPalette(gBrightness>>2,gLastPal,0);
1013      }
1014      else if (!Bstrcasecmp(parm->name, "vid_brightness") || !Bstrcasecmp(parm->name, "vid_contrast"))
1015      {
1016          videoSetPalette(gBrightness>>2,gLastPal,0);
1017      }
1018      else if (!Bstrcasecmp(parm->name, "snd_fmpianofix"))
1019      {
1020          sndLoadGMTimbre();
1021      }
1022  #if 0
1023      else if (!Bstrcasecmp(parm->name, "hud_scale")
1024               || !Bstrcasecmp(parm->name, "hud_statusbarmode")
1025               || !Bstrcasecmp(parm->name, "r_rotatespritenowidescreen"))
1026      {
1027          G_UpdateScreenArea();
1028      }
1029      else if (!Bstrcasecmp(parm->name, "skill"))
1030      {
1031          if (numplayers > 1)
1032              return r;
1033  
1034          ud.player_skill = ud.m_player_skill;
1035      }
1036      else if (!Bstrcasecmp(parm->name, "osdscale"))
1037      {
1038          osdrscale = 1.f/osdscale;
1039  
1040          if (xdim && ydim)
1041              OSD_ResizeDisplay(xdim, ydim);
1042      }
1043      else if (!Bstrcasecmp(parm->name, "wchoice"))
1044      {
1045          if (parm->numparms == 1)
1046          {
1047              if (g_forceWeaponChoice) // rewrite ud.wchoice because osdcmd_cvar_set already changed it
1048              {
1049                  int j = 0;
1050  
1051                  while (j < 10)
1052                  {
1053                      ud.wchoice[j] = g_player[myconnectindex].wchoice[j] + '0';
1054                      j++;
1055                  }
1056  
1057                  ud.wchoice[j] = 0;
1058              }
1059              else
1060              {
1061                  char const *c = parm->parms[0];
1062  
1063                  if (*c)
1064                  {
1065                      int j = 0;
1066  
1067                      while (*c && j < 10)
1068                      {
1069                          g_player[myconnectindex].wchoice[j] = *c - '0';
1070                          c++;
1071                          j++;
1072                      }
1073  
1074                      while (j < 10)
1075                      {
1076                          if (j == 9)
1077                              g_player[myconnectindex].wchoice[9] = 1;
1078                          else
1079                              g_player[myconnectindex].wchoice[j] = 2;
1080  
1081                          j++;
1082                      }
1083                  }
1084              }
1085  
1086              g_forceWeaponChoice = 0;
1087          }
1088  
1089          /*    Net_SendClientInfo();*/
1090      }
1091  #endif
1092  
1093      return r;
1094  }
1095  
1096  static int osdcmd_cvar_set_multi(osdcmdptr_t parm)
1097  {
1098      int const r = osdcmd_cvar_set_game(parm);
1099  
1100      if (r != OSDCMD_OK) return r;
1101  
1102      //G_UpdatePlayerFromMenu();
1103  
1104      return r;
1105  }
1106  
1107  int32_t registerosdcommands(void)
1108  {
1109      FX_InitCvars();
1110  
1111      char buffer[256];
1112      static osdcvardata_t cvars_game[] =
1113      {
1114          { "crosshair", "enable/disable crosshair (0: off, 1: on, 2: on [autoaim])", (void *)&gAimReticle, CVAR_INT, 0, 2 },
1115          { "crosshairoffsetx", "set X axis offset for crosshair (-32 to 32)", (void *)&gAimReticleOffsetX, CVAR_INT, -32, 32 },
1116          { "crosshairoffsety", "set Y axis offset for crosshair (-32 to 32)", (void *)&gAimReticleOffsetY, CVAR_INT, -32, 32 },
1117  
1118          { "cl_autoaim", "enable/disable weapon autoaim", (void *)&gAutoAim, CVAR_INT|CVAR_MULTI, 0, 4 },
1119          { "cl_autoaimrange", "set auto aim range angle modifier (default: 4, single-player only)", (void *)&gAutoAimRange, CVAR_INT, 0, 9 },
1120  //        { "cl_automsg", "enable/disable automatically sending messages to all players", (void *)&ud.automsg, CVAR_BOOL, 0, 1 },
1121          { "cl_autodivingsuit", "enable/disable automatic diving suit equipping when entering water (always enabled in multiplayer)", (void *)&gAutoDivingSuit, CVAR_BOOL, 0, 1 },
1122          { "cl_autorun", "enable/disable autorun", (void *)&gAutoRun, CVAR_BOOL, 0, 1 },
1123  //
1124  //        { "cl_autosave", "enable/disable autosaves", (void *) &ud.autosave, CVAR_BOOL, 0, 1 },
1125  //        { "cl_autosavedeletion", "enable/disable automatic deletion of autosaves", (void *) &ud.autosavedeletion, CVAR_BOOL, 0, 1 },
1126  //        { "cl_maxautosaves", "number of autosaves to keep before deleting the oldest", (void *) &ud.maxautosaves, CVAR_INT, 1, 100 },
1127  //
1128  //        { "cl_autovote", "enable/disable automatic voting", (void *)&ud.autovote, CVAR_INT, 0, 2 },
1129  //
1130  //        { "cl_cheatmask", "configure what cheats show in the cheats menu", (void *)&cl_cheatmask, CVAR_UINT, 0, ~0 },
1131  //
1132  //        { "cl_obituaries", "enable/disable multiplayer death messages", (void *)&ud.obituaries, CVAR_BOOL, 0, 1 },
1133  //        { "cl_democams", "enable/disable demo playback cameras", (void *)&ud.democams, CVAR_BOOL, 0, 1 },
1134  //
1135  //        { "cl_idplayers", "enable/disable name display when aiming at opponents", (void *)&ud.idplayers, CVAR_BOOL, 0, 1 },
1136  //
1137  
1138          { "cl_calebtalk", "enable/disable Caleb's dialog lines (0: on, 1: no idle, 2: no explosion/gib, 3: off)", (void *)&gCalebTalk, CVAR_INT, 0, 3 },
1139          { "cl_chatsnd", "enable/disable multiplayer chat message beep", (void *)&gChatSnd, CVAR_BOOL, 0, 1 },
1140          { "cl_interpolate", "enable/disable view interpolation", (void *)&gViewInterpolate, CVAR_BOOL, 0, 1 },
1141          { "cl_interpolatemethod", "set view interpolation method (0: original [integer], 1: notblood [floating-point])", (void *)&gViewInterpolateMethod, CVAR_BOOL, 0, 1 },
1142          { "cl_interpolateweapon", "enable/disable view interpolation for drawn weapon (0: disable, 1: position, 2: position/qav animation)", (void *)&gWeaponInterpolate, CVAR_INT, 0, 2 },
1143          { "cl_colormsg", "enable/disable colored player names in messages", (void *)&gColorMsg, CVAR_BOOL, 0, 1 },
1144          { "cl_dim", "enable/disable dimming background when menu is active", (void *)&gViewDim, CVAR_BOOL, 0, 1 },
1145          { "cl_ghostshutup", "enable/disable reducing the screaming of ghost enemies", (void *)&gGhostScream, CVAR_BOOL, 0, 1 },
1146          { "cl_healthblink", "enable/disable health blinking when under 15 health points", (void *)&gHealthBlink, CVAR_BOOL, 0, 1 },
1147          { "cl_killmsg", "enable/disable kill messages", (void *)&gKillMsg, CVAR_BOOL, 0, 1 },
1148          { "cl_killobituaries", "enable/disable random obituary kill messages", (void *)&gKillObituary, CVAR_BOOL, 0, 1 },
1149          { "cl_multikill", "enable/disable multi kill messages (0: disable, 1: enable, 2: enable + audio alert)", (void *)&gMultiKill, CVAR_INT, 0, 2 },
1150          { "cl_viewhbob", "enable/disable view horizontal bobbing", (void *)&gViewHBobbing, CVAR_BOOL, 0, 1 },
1151          { "cl_viewvbob", "enable/disable view vertical bobbing", (void *)&gViewVBobbing, CVAR_BOOL, 0, 1 },
1152          { "cl_weaponhbob", "enable/disable weapon horizontal bobbing (0: off, 1: original, 2: V1.0x)", (void *)&gWeaponHBobbing, CVAR_INT|CVAR_MULTI, 0, 2 },
1153          { "cl_randomizerscale", "enable/disable randomly scaling enemies for randomizer mode (0: disable, 1: only with seed cheats, 2: always) (always use 1 in multiplayer)", (void *)&gRandomizerScaleMode, CVAR_INT, 0, 2 },
1154          { "cl_slopetilting", "enable/disable slope tilting", (void *)&gSlopeTilting, CVAR_BOOL, 0, 1 },
1155          { "cl_slopecrosshair", "enable/disable adjusting crosshair position for slope tilting", (void *)&gSlopeReticle, CVAR_BOOL, 0, 1 },
1156          { "cl_showplayernames", "enable/disable showing player names in multiplayer when looking at other players", (void *)&gShowPlayerNames, CVAR_BOOL, 0, 1 },
1157          { "cl_showspeed", "enable/disable showing player speed", (void*)&gShowSpeed, CVAR_BOOL, 0, 1 },
1158          { "cl_showweapon", "enable/disable show weapons (0: disable, 1: sprite, 2: voxel)", (void *)&gShowWeapon, CVAR_INT, 0, 2 },
1159          { "cl_showloadsavebackdrop", "enable/disable the menu backdrop for loading/saving game", (void *)&gShowLoadingSavingBackground, CVAR_BOOL, 0, 1 },
1160          { "cl_slowroomflicker", "enable/disable slowed flickering speed for sectors (such as E1M4's snake pit room)", (void *)&gSlowRoomFlicker, CVAR_BOOL, 0, 1 },
1161          { "cl_shadowsfake3d", "enable/disable 3d projection for fake sprite shadows", (void *)&gShadowsFake3D, CVAR_BOOL, 0, 1 },
1162          { "cl_smoketrail3d", "enable/disable 3d smoke trail positioning for tnt/spray can (single-player only)", (void *)&gSmokeTrail3D, CVAR_BOOL, 0, 1 },
1163          { "cl_projectileoldsprite", "enable/disable old pink sprite for hitscan projectiles", (void *)&gProjectileOldSprite, CVAR_BOOL, 0, 1 },
1164  
1165          { "cl_rollangle", "sets how much your screen tilts when strafing (polymost)", (void *)&gRollAngle, CVAR_INT, -5, 5 },
1166          { "cl_runmode", "enable/disable modernized run key operation", (void *)&gRunKeyMode, CVAR_BOOL, 0, 1 },
1167  //
1168  //        { "cl_showcoords", "show your position in the game world", (void *)&ud.coords, CVAR_INT, 0,
1169  //#ifdef USE_OPENGL
1170  //          2
1171  //#else
1172  //          1
1173  //#endif
1174  //        },
1175  //
1176  //        { "cl_viewbob", "enable/disable player head bobbing", (void *)&ud.viewbob, CVAR_BOOL, 0, 1 },
1177  //
1178  //        { "cl_weaponsway", "enable/disable player weapon swaying", (void *)&ud.weaponsway, CVAR_BOOL, 0, 1 },
1179          { "cl_shotgunaltfirereload", "enable/disable alt fire as reload for shotgun when fired one shell (always off in multiplayer)", (void *)&gShotgunAltFireReload, CVAR_BOOL, 0, 1 },
1180          { "cl_gibnoclip", "toggles gib clipping (always on in multiplayer)", (void *)&gGibNoClip, CVAR_BOOL, 0, 1 },
1181          { "cl_weaponswitch", "enable/disable auto weapon switching", (void *)&gWeaponSwitch, CVAR_INT|CVAR_MULTI, 0, 3 },
1182          { "cl_weaponfastswitch", "enable/disable fast weapon switching", (void *)&gWeaponFastSwitch, CVAR_BOOL|CVAR_MULTI, 0, 1 },
1183          { "cl_packitemswitch", "enable/disable item slot switching to activated item (always enabled in multiplayer)", (void *)&gPackSlotSwitch, CVAR_BOOL, 0, 1 },
1184          { "color", "set preferred player color palette in multiplayer (0: none, 1: blue, 2: red, 3: teal, 4: gray, 5: yellow, 6: brown, 7: copper)", (void *)&gPlayerColorPreference, CVAR_INT, 0, 7 },
1185  //
1186  //        { "color", "changes player palette", (void *)&ud.color, CVAR_INT|CVAR_MULTI, 0, MAXPALOOKUPS-1 },
1187  //
1188  //        { "crosshairscale","changes the size of the crosshair", (void *)&ud.crosshairscale, CVAR_INT, 10, 100 },
1189  //
1190  //        { "demorec_diffs","enable/disable diff recording in demos",(void *)&demorec_diffs_cvar, CVAR_BOOL, 0, 1 },
1191  //        { "demorec_force","enable/disable forced demo recording",(void *)&demorec_force_cvar, CVAR_BOOL|CVAR_NOSAVE, 0, 1 },
1192  //        {
1193  //            "demorec_difftics","sets game tic interval after which a diff is recorded",
1194  //            (void *)&demorec_difftics_cvar, CVAR_INT, 2, 60*REALGAMETICSPERSEC
1195  //        },
1196  //        { "demorec_diffcompress","Compression method for diffs. (0: none, 1: KSLZW)",(void *)&demorec_diffcompress_cvar, CVAR_INT, 0, 1 },
1197  //        { "demorec_synccompress","Compression method for input. (0: none, 1: KSLZW)",(void *)&demorec_synccompress_cvar, CVAR_INT, 0, 1 },
1198  //        { "demorec_seeds","enable/disable recording of random seed for later sync checking",(void *)&demorec_seeds_cvar, CVAR_BOOL, 0, 1 },
1199  //        { "demoplay_diffs","enable/disable application of diffs in demo playback",(void *)&demoplay_diffs, CVAR_BOOL, 0, 1 },
1200  //        { "demoplay_showsync","enable/disable display of sync status",(void *)&demoplay_showsync, CVAR_BOOL, 0, 1 },
1201  //
1202  //        { "hud_althud", "enable/disable alternate mini-hud", (void *)&ud.althud, CVAR_BOOL, 0, 1 },
1203  //        { "hud_custom", "change the custom hud", (void *)&ud.statusbarcustom, CVAR_INT, 0, ud.statusbarrange },
1204  //        { "hud_position", "aligns the status bar to the bottom/top", (void *)&ud.hudontop, CVAR_BOOL, 0, 1 },
1205          { "hud_bgnewborder", "enable/disable new hud bottom border background image (only for r_size 5)", (void *)&gHudBgNewBorder, CVAR_BOOL, 0, 1 },
1206          { "hud_bgscale", "enable/disable hud background image scaling for resolution", (void *)&gHudBgScale, CVAR_BOOL, 0, 1 },
1207          { "hud_bgvanilla", "enable/disable hud vanilla background image override (0: default, 1: use new tile, 2: use original tile)", (void *)&gHudBgVanilla, CVAR_INT, 0, 2 },
1208          { "hud_competitivemode", "enable/disable large hud frame for view size 4", (void*)&gHudCompetitiveMode, CVAR_BOOL, 0, 1 },
1209  //        { "hud_bgstretch", "enable/disable background image stretching in wide resolutions", (void *)&ud.bgstretch, CVAR_BOOL, 0, 1 },
1210          { "hud_messages", "enable/disable showing messages", (void *)&gMessageState, CVAR_BOOL, 0, 1 },
1211  //        { "hud_messagetime", "length of time to display multiplayer chat messages", (void *)&ud.msgdisptime, CVAR_INT, 0, 3600 },
1212  //        { "hud_numbertile", "first tile in alt hud number set", (void *)&althud_numbertile, CVAR_INT, 0, MAXUSERTILES-10 },
1213  //        { "hud_numberpal", "pal for alt hud numbers", (void *)&althud_numberpal, CVAR_INT, 0, MAXPALOOKUPS-1 },
1214  //        { "hud_shadows", "enable/disable althud shadows", (void *)&althud_shadows, CVAR_BOOL, 0, 1 },
1215  //        { "hud_flashing", "enable/disable althud flashing", (void *)&althud_flashing, CVAR_BOOL, 0, 1 },
1216  //        { "hud_glowingquotes", "enable/disable \"glowing\" quote text", (void *)&hud_glowingquotes, CVAR_BOOL, 0, 1 },
1217  //        { "hud_scale","changes the hud scale", (void *)&ud.statusbarscale, CVAR_INT|CVAR_FUNCPTR, 36, 100 },
1218  //        { "hud_showmapname", "enable/disable map name display on load", (void *)&hud_showmapname, CVAR_BOOL, 0, 1 },
1219          { "hud_secretstyle", "set secrets message style (0: original, 1: notblood, 2: gzdoom)", (void *)&gSecretStyle, CVAR_INT, 0, 2 },
1220          { "hud_stats", "enable/disable level statistics display (0: off, 1: on [default], 2: on [4:3], 3: on [16:10], 4: on [16:9], 5: on [21:9])", (void *)&gLevelStats, CVAR_INT, 0, 5 },
1221          { "hud_statsautomaponly", "enable/disable showing level statistics display only on map view", (void *)&gLevelStatsOnlyOnMap, CVAR_BOOL, 0, 1 },
1222          { "hud_ratio", "set aspect ratio screen position for hud (0: native, 1: 4:3, 2: 16:10, 3: 16:9, 3: 21:9)", (void*)&gHudRatio, CVAR_INT, 0, 4 },
1223          { "hud_powerupduration", "enable/disable displaying the remaining time for power-ups (0: off, 1: on [default], 2: on [4:3], 3: on [16:10], 4: on [16:9], 5: on [21:9])", (void *)&gPowerupDuration, CVAR_INT, 0, 5 },
1224          { "hud_powerupdurationshowoxygen", "enable/disable oxygen supply as a power-up", (void *)&gPowerupShowOxygenSupply, CVAR_BOOL, 0, 1 },
1225          { "hud_powerupdurationstyle", "set the display style for the remaining time for power-ups (0: nblood, 1: notblood)", (void *)&gPowerupStyle, CVAR_BOOL, 0, 1 },
1226          { "hud_powerupdurationticks", "set the tickrate divide value used for displaying the remaining time for power-ups (default: 100, realtime seconds: 120)", (void *)&gPowerupTicks, CVAR_INT, 20, 240 },
1227          { "hud_showendtime", "enable/disable displaying the level completion time on end screen", (void*)&gShowCompleteTime, CVAR_BOOL, 0, 1 },
1228          { "hud_showmaptitle", "enable/disable displaying the map title at the beginning of the maps", (void*)& gShowMapTitle, CVAR_BOOL, 0, 1 },
1229          { "hud_showweaponselect", "enable/disable weapon select bar display (0: none, 1: bottom, 2: top)", (void*)&gShowWeaponSelect, CVAR_INT, 0, 2 },
1230          { "hud_showweaponselecttimestart", "length of time for selected weapon bar to appear", (void*)&gShowWeaponSelectTimeStart, CVAR_INT, 2, 25 },
1231          { "hud_showweaponselecttimehold", "length of time to display selected weapon bar", (void*)&gShowWeaponSelectTimeHold, CVAR_INT, 10, 100 },
1232          { "hud_showweaponselecttimeend", "length of time for selected weapon weapon bar to disappear", (void*)&gShowWeaponSelectTimeEnd, CVAR_INT, 2, 25 },
1233          { "hud_showweaponselectposition", "position offset for selected weapon weapon bar", (void*)&gShowWeaponSelectPosition, CVAR_INT, 10, 50 },
1234          { "hud_showweaponselectscale", "sets scale for selected weapon weapon bar (default: 10, range: 5-20)", (void*)&gShowWeaponSelectScale, CVAR_INT, 5, 20 },
1235          { "hud_teamscorestyle", "set the display style for the teams score display (0: original, 1: nblood)", (void *)&gTeamsScoreStyle, CVAR_BOOL, 0, 1 },
1236  //        { "hud_textscale", "sets multiplayer chat message size", (void *)&ud.textscale, CVAR_INT, 100, 400 },
1237  //        { "hud_weaponscale","changes the weapon scale", (void *)&ud.weaponscale, CVAR_INT, 10, 100 },
1238  //        { "hud_statusbarmode", "change overlay mode of status bar", (void *)&ud.statusbarmode, CVAR_BOOL|CVAR_FUNCPTR, 0, 1 },
1239  //
1240  //#ifdef EDUKE32_TOUCH_DEVICES
1241  //        { "hud_hidestick", "hide the touch input stick", (void *)&droidinput.hideStick, CVAR_BOOL, 0, 1 },
1242  //#endif
1243  //
1244          { "horizcenter", "enable/disable centered horizon line", (void *)&gCenterHoriz, CVAR_BOOL, 0, 1 },
1245          { "deliriumblur", "enable/disable delirium blur effect(polymost)", (void *)&gDeliriumBlur, CVAR_BOOL, 0, 1 },
1246          { "detail", "change the detail graphics setting (0-4)", (void *)&gDetail, CVAR_INT|CVAR_FUNCPTR, 0, 4 },
1247          { "fov", "change the field of view", (void *)&gFov, CVAR_INT|CVAR_FUNCPTR, 75, 140 },
1248  
1249          { "in_aimmode", "0: toggle, 1: hold to aim", (void *)&gMouseAiming, CVAR_BOOL, 0, 1 },
1250          { "in_centerviewondrop", "enable/disable recenter view when dropping down onto ground", (void *)&gCenterViewOnDrop, CVAR_BOOL, 0, 1 },
1251          { "in_crouchauto", "enable/disable automatic crouching for small crawl spaces", (void*)&gCrouchAuto, CVAR_BOOL, 0, 1 },
1252          { "in_crouchmode", "toggles crouch button (0: hold, 1: toggle)", (void *)&gCrouchToggle, CVAR_BOOL, 0, 1 },
1253          {
1254              "in_mousebias", "emulates the original mouse code's weighting of input towards whichever axis is moving the most at any given time",
1255              (void *)&MouseBias, CVAR_INT, 0, 32
1256          },
1257          { "in_mousedeadzone", "amount of mouse movement to filter out", (void *)&MouseDeadZone, CVAR_INT, 0, 512 },
1258          { "in_mouseflip", "invert vertical mouse movement", (void *)&gMouseAimingFlipped, CVAR_BOOL, 0, 1 },
1259          { "in_mousemode", "toggles vertical mouse view", (void *)&gMouseAim, CVAR_BOOL, 0, 1 },
1260          { "in_radialmenuslowdown", "enable/disable the radial menu slow down behavior", (void*)&gRadialMenuSlowDown, CVAR_BOOL, 0, 1 },
1261          { "in_radialmenumousethreshold", "sets the radial menu mouse threshold (0-2048)", (void*)&gRadialMenuMouseThreshold, CVAR_INT, 0, 2048 },
1262          { "in_radialmenuthresholdx", "sets the radial x menu threshold (0-1024)", (void*)&gRadialMenuThresholdX, CVAR_INT, 0, 1024 },
1263          { "in_radialmenuthresholdy", "sets the radial y menu threshold (0-1024)", (void*)&gRadialMenuThresholdY, CVAR_INT, 0, 1024 },
1264          { "in_radialmenutoggle", "sets the radial menu behavior (0: held, 1: toggle, 2: on next/prev weapon)", (void*)&gRadialMenuToggle, CVAR_INT, 0, 2 },
1265          { "in_radialmenuposition", "sets the radial menu position", (void*)&gRadialMenuPosition, CVAR_INT, 0, 320 },
1266          { "in_radialmenudim", "enable/disable radial menu dimming background", (void*)&gRadialMenuDimBackground, CVAR_BOOL, 0, 1 },
1267          { "in_radialmenudimhud", "enable/disable radial menu dimming hud", (void*)&gRadialMenuDimHud, CVAR_BOOL, 0, 1 },
1268          { "in_radialmenuyaw", "sets the radial menu yaw input (0: strafe, 1: move, 2: turn, 3: look)", (void*)&gRadialMenuYaw, CVAR_INT, 0, 3 },
1269          { "in_radialmenuyawinvert", "enable/disable invert radial menu yaw input", (void*)&gRadialMenuYawInvert, CVAR_BOOL, 0, 1 },
1270          { "in_radialmenupitch", "sets the radial menu pitch input (0: strafe, 1: move, 2: turn, 3: look)", (void*)&gRadialMenuPitch, CVAR_INT, 0, 3 },
1271          { "in_radialmenupitchinvert", "enable/disable invert radial menu pitch input", (void*)&gRadialMenuPitchInvert, CVAR_BOOL, 0, 1 },
1272          { "in_radialmenuclick", "set radial menu sound effect click", (void*)&gRadialMenuSfx, CVAR_INT, 0, 3 },
1273          { "in_targetaimassist", "enable/disable slowing camera movement when aiming towards a target (joystick only)", (void *)&gTargetAimAssist, CVAR_BOOL, 0, 1 },
1274          { "in_turnaccelmode", "set keyboard turning acceleration mode (0: off, 1: only when running, 2: always on)", (void *)&gTurnAcceleration, CVAR_INT, 0, 2 },
1275          { "in_turnspeed", "keyboard turning speed", (void *)&gTurnSpeed, CVAR_INT, 64, 124 },
1276  
1277  //
1278          { "model", "set player model for multiplayer (0: caleb, 1: cultist)", (void *)&gPlayerModel, CVAR_BOOL, 0, 1 },
1279          { "mus_enabled", "enables/disables music", (void *)&MusicToggle, CVAR_BOOL, 0, 1 },
1280          { "mus_restartonload", "restart the music when loading a saved game with the same map or not", (void *)&MusicRestartsOnLoadToggle, CVAR_BOOL, 0, 1 },
1281          { "mus_volume", "controls music volume", (void *)&MusicVolume, CVAR_INT, 0, 255 },
1282          { "mus_device", "music device", (void *)&MusicDevice, CVAR_INT, 0, ASS_NumSoundCards },
1283          { "mus_redbook", "enables/disables redbook audio", (void *)&CDAudioToggle, CVAR_BOOL, 0, 1 },
1284          { "mus_redbookfallback", "enables/disables redbook audio if midi song is not specified for level (mus_redbook must already be enabled)", (void *)&CDAudioFallback, CVAR_BOOL, 0, 1 },
1285          { "net_address","sets network address used for multiplayer", (void *)zNetAddressBuffer, CVAR_STRING|CVAR_FUNCPTR, 0, 48 },
1286          { "net_port","sets network port used for multiplayer", (void *)zNetPortBuffer, CVAR_STRING|CVAR_FUNCPTR, 0, 6 },
1287  //
1288  //        { "osdhightile", "enable/disable hires art replacements for console text", (void *)&osdhightile, CVAR_BOOL, 0, 1 },
1289  //        { "osdscale", "adjust console text size", (void *)&osdscale, CVAR_FLOAT|CVAR_FUNCPTR, 1, 4 },
1290  //
1291  //        { "r_camrefreshdelay", "minimum delay between security camera sprite updates, 120 = 1 second", (void *)&ud.camera_time, CVAR_INT, 1, 240 },
1292  //        { "r_drawweapon", "enable/disable weapon drawing", (void *)&ud.drawweapon, CVAR_INT, 0, 2 },
1293          { "r_showfps", "show the frame rate counter", (void *)&gShowFps, CVAR_INT, 0, 3 },
1294          { "r_showfpsperiod", "time in seconds before averaging min and max stats for r_showfps 2+", (void *)&gFramePeriod, CVAR_INT, 0, 5 },
1295  //        { "r_shadows", "enable/disable sprite and model shadows", (void *)&ud.shadows, CVAR_BOOL, 0, 1 },
1296          { "r_size", "change size of viewable area", (void *)&gViewSize, CVAR_INT|CVAR_FUNCPTR, 0, 9 },
1297  //        { "r_rotatespritenowidescreen", "pass bit 1024 to all CON rotatesprite calls", (void *)&g_rotatespriteNoWidescreen, CVAR_BOOL|CVAR_FUNCPTR, 0, 1 },
1298          { "r_upscalefactor", "increase performance by rendering at upscalefactor less than the screen resolution and upscale to the full resolution in the software renderer", (void *)&gUpscaleFactor, CVAR_INT|CVAR_FUNCPTR, 1, 16 },
1299          { "r_renderscale", "adjust internal rendering resolution by scale while keeping hud elements native to full resolution (only for software renderer)", (void *)&gRenderScale, CVAR_INT|CVAR_FUNCPTR, 1, 32 },
1300          { "r_precache", "enable/disable the pre-level caching routine", (void *)&useprecache, CVAR_BOOL, 0, 1 },
1301  //
1302          { "r_ambientlight", "sets the global map light level",(void *)&r_ambientlight, CVAR_FLOAT|CVAR_FUNCPTR, 0, 10 },
1303  
1304          { "skill", "changes the skill handicap for multiplayer (default: 2, range: 0-4)", (void *)&gSkill, CVAR_INT, 0, 4 },
1305  //
1306  //        { "snd_ambience", "enables/disables ambient sounds", (void *)&ud.config.AmbienceToggle, CVAR_BOOL, 0, 1 },
1307          { "snd_ding", "enable/disable hit noise when damaging an enemy. the sound can be changed by replacing the 'notblood.pk3/NOTHIT.RAW' file", (void *)&gSoundDing, CVAR_BOOL, 0, 1 },
1308          { "snd_dingvol", "set volume for hit sound (default: 75, range: 1-255)", (void *)&gSoundDingVol, CVAR_INT, 1, 255 },
1309          { "snd_dingminfreq", "set min damage frequency for hit sound (default: 22050, range: 11025-44100)", (void *)&gSoundDingMinPitch, CVAR_INT, 11025, 44100 },
1310          { "snd_dingmaxfreq", "set max damage frequency for hit sound (default: 22050, range: 11025-44100)", (void *)&gSoundDingMaxPitch, CVAR_INT, 11025, 44100 },
1311          { "snd_dingkill", "enable/disable kill noise when killing an enemy. the sound can be changed by replacing the 'notblood.pk3/NOTKILL.RAW' file", (void*)&gSoundDingKill, CVAR_BOOL, 0, 1 },
1312          { "snd_dingkillvol", "set volume for kill sound (default: 255, range: 1-255)", (void*)&gSoundDingKillVol, CVAR_INT, 1, 255 },
1313          { "snd_dingkillfreq", "set frequency for kill sound (default: 22050, range: 11025-44100)", (void*)&gSoundDingKillPitch, CVAR_INT, 11025, 44100 },
1314          { "snd_doppler", "enables/disables audio doppler effect (stereo only)", (void *)&DopplerToggle, CVAR_BOOL, 0, 1 },
1315          { "snd_enabled", "enables/disables sound effects", (void *)&SoundToggle, CVAR_BOOL, 0, 1 },
1316          { "snd_earangle", "set the listening ear offset (15-90 degrees)", (void *)&gSoundEarAng, CVAR_INT, 15, 90 },
1317          { "snd_fxvolume", "controls volume for sound effects", (void *)&FXVolume, CVAR_INT, 0, 255 },
1318          { "snd_mixrate", "sound mixing rate", (void *)&MixRate, CVAR_INT, 0, 48000 },
1319          { "snd_numchannels", "the number of sound channels (1: mono, 2: stereo)", (void *)&NumChannels, CVAR_INT, 1, 2 },
1320          { "snd_numvoices", "the number of concurrent sounds", (void *)&NumVoices, CVAR_INT, 1, 255 },
1321  #ifdef ASS_REVERSESTEREO
1322          { "snd_reversestereo", "reverses the stereo channels", (void *)&ReverseStereo, CVAR_BOOL, 0, 1 },
1323  #endif
1324          { "snd_speed", "set the speed of sound m/s used for doppler calculation (default: 343, range: 10-1000)", (void *)&gSoundSpeed, CVAR_INT, 10, 1000 },
1325          { "snd_stereo", "enable/disable 3d stereo sound", (void *)&gStereo, CVAR_BOOL, 0, 1 },
1326          { "snd_fmpianofix", "enable/disable fm piano timbre fix", (void*)&gFMPianoFix, CVAR_BOOL|CVAR_FUNCPTR, 0, 1 },
1327          { "snd_occlusion", "enable/disable lowering sound volume by 50% for occluded sound sources", (void *)&gSoundOcclusion, CVAR_BOOL, 0, 1 },
1328  //        { "snd_speech", "enables/disables player speech", (void *)&ud.config.VoiceToggle, CVAR_INT, 0, 5 },
1329  //
1330  //        { "team","change team in multiplayer", (void *)&ud.team, CVAR_INT|CVAR_MULTI, 0, 3 },
1331          { "team", "set preferred team in multiplayer (0: none, 1: blue, 2: red)", (void *)&gPlayerTeamPreference, CVAR_INT, 0, 2 },
1332  //
1333  //#ifdef EDUKE32_TOUCH_DEVICES
1334  //        { "touch_sens_move_x","touch input sensitivity for moving forward/back", (void *)&droidinput.forward_sens, CVAR_FLOAT, 1, 9 },
1335  //        { "touch_sens_move_y","touch input sensitivity for strafing", (void *)&droidinput.strafe_sens, CVAR_FLOAT, 1, 9 },
1336  //        { "touch_sens_look_x", "touch input sensitivity for turning left/right", (void *) &droidinput.yaw_sens, CVAR_FLOAT, 1, 9 },
1337  //        { "touch_sens_look_y", "touch input sensitivity for looking up/down", (void *) &droidinput.pitch_sens, CVAR_FLOAT, 1, 9 },
1338  //        { "touch_invert", "invert look up/down touch input", (void *) &droidinput.invertLook, CVAR_INT, 0, 1 },
1339  //#endif
1340  //
1341          { "vid_gamma","gamma/brightness correction",(void *) &g_videoGamma, CVAR_FLOAT|CVAR_FUNCPTR, (int)floor(MIN_GAMMA), (int)ceil(MAX_GAMMA) },
1342          { "vid_contrast","contrast correction",(void *) &g_videoContrast, CVAR_FLOAT|CVAR_FUNCPTR, (int)floor(MIN_CONTRAST), (int)ceil(MAX_CONTRAST) },
1343          { "vid_saturation","saturation correction",(void *) &g_videoSaturation, CVAR_FLOAT|CVAR_FUNCPTR, (int)floor(MIN_SATURATION), (int)ceil(MAX_SATURATION) },
1344  //        { "wchoice","sets weapon autoselection order", (void *)ud.wchoice, CVAR_STRING|CVAR_FUNCPTR, 0, MAX_WEAPONS },
1345      };
1346  //
1347  //    osdcmd_cheatsinfo_stat.cheatnum = -1;
1348  //
1349      for (auto & cv : cvars_game)
1350      {
1351          switch (cv.flags & (CVAR_FUNCPTR|CVAR_MULTI))
1352          {
1353              case CVAR_FUNCPTR:
1354                  OSD_RegisterCvar(&cv, osdcmd_cvar_set_game); break;
1355              case CVAR_MULTI:
1356              case CVAR_FUNCPTR|CVAR_MULTI:
1357                  OSD_RegisterCvar(&cv, osdcmd_cvar_set_multi); break;
1358              default:
1359                  OSD_RegisterCvar(&cv, osdcmd_cvar_set); break;
1360          }
1361      }
1362  //
1363  //    if (VOLUMEONE)
1364  //        OSD_RegisterFunction("changelevel","changelevel <level>: warps to the given level", osdcmd_changelevel);
1365  //    else
1366  //    {
1367      OSD_RegisterFunction("changelevel","changelevel <volume> <level>: warps to the given level", osdcmd_changelevel);
1368      OSD_RegisterFunction("map","map <mapfile>: loads the given user map", osdcmd_map);
1369      OSD_RegisterFunction("demo","demo <demofile or demonum>: starts the given demo", osdcmd_demo);
1370  //    }
1371  //
1372  //    OSD_RegisterFunction("addpath","addpath <path>: adds path to game filesystem", osdcmd_addpath);
1373      OSD_RegisterFunction("bind",R"(bind <key> <string>: associates a keypress with a string of console input. Type "bind showkeys" for a list of keys and "listsymbols" for a list of valid console commands.)", osdcmd_bind);
1374  //    OSD_RegisterFunction("cmenu","cmenu <#>: jumps to menu", osdcmd_cmenu);
1375      OSD_RegisterFunction("crosshaircolor","crosshaircolor: changes the crosshair color", osdcmd_crosshaircolor);
1376      OSD_RegisterFunction("crosshairreset", "crosshairreset: restores the original crosshair", osdcmd_resetcrosshair);
1377  //
1378  //#if !defined NETCODE_DISABLE
1379  //    OSD_RegisterFunction("connect","connect: connects to a multiplayer game", osdcmd_connect);
1380  //    OSD_RegisterFunction("disconnect","disconnect: disconnects from the local multiplayer game", osdcmd_disconnect);
1381  //#endif
1382  
1383      for (auto & func : gamefunctions)
1384      {
1385          if (func[0] == '\0')
1386              continue;
1387  
1388  //        if (!Bstrcmp(gamefunctions[i],"Show_Console")) continue;
1389  
1390          Bsprintf(buffer, "gamefunc_%s", func);
1391  
1392          char *const t = Bstrtolower(Xstrdup(buffer));
1393  
1394          Bstrcat(buffer, ": game button");
1395  
1396          OSD_RegisterFunction(t, Xstrdup(buffer), osdcmd_button);
1397      }
1398  
1399      OSD_RegisterFunction("fly","fly: toggles fly mode", osdcmd_fly);
1400      OSD_RegisterFunction("give","give <all|health|weapons|ammo|armor|keys|inventory>: gives requested item", osdcmd_give);
1401      OSD_RegisterFunction("god","god: toggles god mode", osdcmd_god);
1402  //    OSD_RegisterFunction("activatecheat","activatecheat <id>: activates a cheat code", osdcmd_activatecheat);
1403  //
1404  //    OSD_RegisterFunction("initgroupfile","initgroupfile <path>: adds a grp file into the game filesystem", osdcmd_initgroupfile);
1405  //#ifdef DEBUGGINGAIDS
1406  //    OSD_RegisterFunction("inittimer","debug", osdcmd_inittimer);
1407  //#endif
1408  //#if !defined NETCODE_DISABLE
1409  //    OSD_RegisterFunction("kick","kick <id>: kicks a multiplayer client.  See listplayers.", osdcmd_kick);
1410  //    OSD_RegisterFunction("kickban","kickban <id>: kicks a multiplayer client and prevents them from reconnecting.  See listplayers.", osdcmd_kickban);
1411  //
1412  //    OSD_RegisterFunction("listplayers","listplayers: lists currently connected multiplayer clients", osdcmd_listplayers);
1413  //#endif
1414      OSD_RegisterFunction("music","music E<ep>L<lev>: change music", osdcmd_music);
1415  //
1416  //#if !defined NETCODE_DISABLE
1417  //    OSD_RegisterFunction("name","name: change your multiplayer nickname", osdcmd_name);
1418  //#endif
1419  //
1420      OSD_RegisterFunction("noclip","noclip: toggles clipping mode", osdcmd_noclip);
1421      OSD_RegisterFunction("notarget","notarget: toggles ai player detection", osdcmd_notarget);
1422  //
1423  //#if !defined NETCODE_DISABLE
1424  //    OSD_RegisterFunction("password","password: sets multiplayer game password", osdcmd_password);
1425  //#endif
1426  //
1427  //    OSD_RegisterFunction("printtimes", "printtimes: prints VM timing statistics", osdcmd_printtimes);
1428  //
1429  //    OSD_RegisterFunction("purgesaves", "purgesaves: deletes obsolete and unreadable save files", osdcmd_purgesaves);
1430  //
1431      OSD_RegisterFunction("quicksave","quicksave: performs a quick save", osdcmd_quicksave);
1432      OSD_RegisterFunction("quickload","quickload: performs a quick load", osdcmd_quickload);
1433      OSD_RegisterFunction("quit","quit: exits the game immediately", osdcmd_quit);
1434      OSD_RegisterFunction("exit","exit: exits the game immediately", osdcmd_quit);
1435  //
1436  //    OSD_RegisterFunction("restartmap", "restartmap: restarts the current map", osdcmd_restartmap);
1437      OSD_RegisterFunction("record", "record <episode> <map> <difficulty 1-5>: start a demo recording", osdcmd_demorecord);
1438      OSD_RegisterFunction("restartsound","restartsound: reinitializes the sound system",osdcmd_restartsound);
1439      OSD_RegisterFunction("restartvid","restartvid: reinitializes the video mode",osdcmd_restartvid);
1440  //#if !defined LUNATIC
1441  //    OSD_RegisterFunction("addlogvar","addlogvar <gamevar>: prints the value of a gamevar", osdcmd_addlogvar);
1442  //    OSD_RegisterFunction("setvar","setvar <gamevar> <value>: sets the value of a gamevar", osdcmd_setvar);
1443  //    OSD_RegisterFunction("setvarvar","setvarvar <gamevar1> <gamevar2>: sets the value of <gamevar1> to <gamevar2>", osdcmd_setvar);
1444  //    OSD_RegisterFunction("setactorvar","setactorvar <actor#> <gamevar> <value>: sets the value of <actor#>'s <gamevar> to <value>", osdcmd_setactorvar);
1445  //#else
1446  //    OSD_RegisterFunction("lua", "lua \"Lua code...\": runs Lunatic code", osdcmd_lua);
1447  //#endif
1448      OSD_RegisterFunction("say","display player message", osdcmd_say);
1449      OSD_RegisterFunction("say_team","display player message to team", osdcmd_say_team);
1450      OSD_RegisterFunction("screenshot","screenshot [format]: takes a screenshot.", osdcmd_screenshot);
1451  //
1452  //    OSD_RegisterFunction("spawn","spawn <picnum> [palnum] [cstat] [ang] [x y z]: spawns a sprite with the given properties",osdcmd_spawn);
1453  
1454      OSD_RegisterFunction("unbind","unbind <key>: unbinds a key", osdcmd_unbind);
1455      OSD_RegisterFunction("unbindall","unbindall: unbinds all keys", osdcmd_unbindall);
1456      OSD_RegisterFunction("unbound", NULL, osdcmd_unbound);
1457  
1458      OSD_RegisterFunction("vidmode","vidmode <xdim> <ydim> <bpp> <fullscreen>: change the video mode",osdcmd_vidmode);
1459  #ifdef USE_OPENGL
1460      baselayer_osdcmd_vidmode_func = osdcmd_vidmode;
1461  #endif
1462  //
1463  //#ifndef NETCODE_DISABLE
1464  //    OSD_RegisterFunction("dumpmapstates", "Dumps current snapshots to CL/Srv_MapStates.bin", osdcmd_dumpmapstate);
1465  //    OSD_RegisterFunction("playerinfo", "Prints information about the current player", osdcmd_playerinfo);
1466  //#endif
1467  
1468      return 0;
1469  }
1470  
1471  void GAME_onshowosd(int shown)
1472  {
1473      // G_UpdateScreenArea();
1474  
1475      mouseLockToWindow((!shown) + 2);
1476  
1477      //osdshown = shown;
1478  
1479      // XXX: it's weird to fake a keypress like this.
1480  //    if (numplayers == 1 && ((shown && !ud.pause_on) || (!shown && ud.pause_on)))
1481  //        KB_KeyDown[sc_Pause] = 1;
1482  }
1483  
1484  void GAME_clearbackground(int numcols, int numrows)
1485  {
1486      COMMON_clearbackground(numcols, numrows);
1487  }
1488