Merge remote branch 'origin/master' into samual/updatecommands
authorSamual <samual@xonotic.org>
Tue, 27 Dec 2011 20:25:20 +0000 (15:25 -0500)
committerSamual <samual@xonotic.org>
Tue, 27 Dec 2011 20:25:20 +0000 (15:25 -0500)
Conflicts:
defaultXonotic.cfg
qcsrc/client/Main.qc
qcsrc/client/main.qh
qcsrc/common/util.qc
qcsrc/common/util.qh

1  2 
commands.cfg
qcsrc/client/Main.qc
qcsrc/client/command/cl_cmd.qc
qcsrc/common/command/generic.qc
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/menu/command/menu_cmd.qc
qcsrc/menu/command/menu_cmd.qh
qcsrc/server/cl_client.qc
qcsrc/server/g_world.qc
qcsrc/server/progs.src

diff --cc commands.cfg
index 22acccd,0000000..754b0b3
mode 100644,000000..100644
--- /dev/null
@@@ -1,276 -1,0 +1,272 @@@
- // This alias allows for common commands to be executed, even on both
- // dedicated servers and normal clients. If dedicated, then it remains
- // as sv_cmd... If a normal client, then it is changed to menu_cmd.
- alias qc_cmd "sv_cmd $*" 
 +// =================================================================
 +//  Master config for managing various command aliases and settings
 +// =================================================================
 +
- alias cvar_changes "${cmd_prefix !} cvar_changes"
- alias cvar_purechanges "${cmd_prefix !} cvar_purechanges"
- alias info "${cmd_prefix !} info ${* ?}"
- alias ladder "${cmd_prefix !} ladder"
- alias lsmaps "${cmd_prefix !} lsmaps"
- alias lsnewmaps "${cmd_prefix !} lsnewmaps"
- alias maplist "${cmd_prefix !} maplist"
- alias rankings "${cmd_prefix !} rankings"
- alias records "${cmd_prefix !} records"
- alias teamstatus "${cmd_prefix !} teamstatus"
- alias time "${cmd_prefix !} time"
- alias timein "${cmd_prefix !} timein"
- alias timeout "${cmd_prefix !} timeout"
- alias vote "${cmd_prefix !} vote ${* ?}"
- alias who "${cmd_prefix !} who ${* ?}"
- alias g_hitplots_add "qc_cmd rpn /g_hitplots_individuals g_hitplots_individuals ${1 !} union def"
- alias g_hitplots_remove "qc_cmd rpn /g_hitplots_individuals g_hitplots_individuals ${1 !} difference def"
- alias g_maplist_add   "qc_cmd maplist add ${* ?}"
- alias g_maplist_remove        "qc_cmd maplist remove ${* ?}"
- alias g_maplist_putfirst      "qc_cmd maplist remove ${* ?} ; qc_cmd maplist add ${* ?}"
- alias g_maplist_shufflenow    "qc_cmd maplist shuffle"
- alias g_maplist_cleanup       "qc_cmd maplist cleanup" // removes maps that don't exist from the map list
- alias addfav "qc_cmd addtolist net_slist_favorites ${* ?}"
- alias addvote "qc_cmd addtolist sv_vote_commands ${* ?}"
 +// Execute commands based on whether it is dedicated a server or a client.
 +alias "_detect_dedicated_$qport" "${* asis}"
 +alias "_detect_dedicated_0" ""
 +alias _if_dedicated "_detect_dedicated_$qport ${* asis}"
 +alias if_client "${* asis}"
 +alias if_dedicated "${* asis}"
 +_if_dedicated alias if_client ""
 +if_client alias if_dedicated ""
 +
 +if_client set cmd_prefix "cmd"
 +if_dedicated set cmd_prefix "sv_cmd"
 +
++if_dedicated "alias" qc_cmd_svmenu "sv_cmd $$*"
++if_client    "alias" qc_cmd_svmenu "menu_cmd $$*"
++if_dedicated "alias" qc_cmd_svcl   "sv_cmd $$*"
++if_client    "alias" qc_cmd_svcl   "cl_cmd $$*"
++if_dedicated "alias" qc_cmd_svcmd  "sv_cmd $$*"
++if_client    "alias" qc_cmd_svcmd  "cmd $$*"
++
 +
 +// ========
 +//  common
 +// ========
- set settemp_list 0
- set settemp_idx 0
- set _settemp_var UNUSED
- alias settemp "_settemp_var \"_settemp_x$settemp_idx\"; qc_cmd rpn /settemp_idx settemp_idx 1 add def; _settemp \"$1\" \"$2\""
- alias _settemp "settemp_list \"1 $1 $_settemp_var $settemp_list\"; set $_settemp_var \"${$1}\"; $1 \"$2\""
- alias settemp_restore "_settemp_restore_${settemp_list asis}"
- alias _settemp_restore_0 "set settemp_var 0; set settemp_list 0"
- alias _settemp_restore_1 "$1 \"${$2}\"; _settemp_restore_${3- asis}"
++alias cvar_changes "qc_cmd_svcmd cvar_changes"
++alias cvar_purechanges "qc_cmd_svcmd cvar_purechanges"
++alias info "qc_cmd_svcmd info ${* ?}"
++alias ladder "qc_cmd_svcmd ladder"
++alias lsmaps "qc_cmd_svcmd lsmaps"
++alias lsnewmaps "qc_cmd_svcmd lsnewmaps"
++alias maplist "qc_cmd_svcmd maplist"
++alias rankings "qc_cmd_svcmd rankings"
++alias records "qc_cmd_svcmd records"
++alias teamstatus "qc_cmd_svcmd teamstatus"
++alias time "qc_cmd_svcmd time"
++alias timein "qc_cmd_svcmd timein"
++alias timeout "qc_cmd_svcmd timeout"
++alias vote "qc_cmd_svcmd vote ${* ?}"
++alias who "qc_cmd_svcmd who ${* ?}"
++
++alias g_hitplots_add "qc_cmd_svmenu rpn /g_hitplots_individuals g_hitplots_individuals ${1 !} union def"
++alias g_hitplots_remove "qc_cmd_svmenu rpn /g_hitplots_individuals g_hitplots_individuals ${1 !} difference def"
++
++alias g_maplist_add   "qc_cmd_svmenu maplist add ${* ?}"
++alias g_maplist_remove        "qc_cmd_svmenu maplist remove ${* ?}"
++alias g_maplist_putfirst      "qc_cmd_svmenu maplist remove ${* ?} ; qc_cmd maplist add ${* ?}"
++alias g_maplist_shufflenow    "qc_cmd_svmenu maplist shuffle"
++alias g_maplist_cleanup       "qc_cmd_svmenu maplist cleanup" // removes maps that don't exist from the map list
++
++alias addfav "qc_cmd_svmenu addtolist net_slist_favorites ${* ?}"
++alias addvote "qc_cmd_svmenu addtolist sv_vote_commands ${* ?}"
 +
 +
 +// ========================
 +//  engine command aliases
 +// ========================
 +alias bsp "ls maps/*.bsp"
 +alias chmap "changelevel ${* ?}"
 +alias clearmap "disconnect"
 +alias ply "playdemo $1"
 +alias rec "record demos/${1 !}"
 +alias sv_loadconfig "exec $serverconfig"
 +alias sv_restart "say \"Server will restart at the end of the match, you will all be reconnected automatically. ${* ?} \"; quit_and_redirect self"
 +alias tdem "timedemo $1"
 +
 +
 +// ===============================================
 +//  menu_cmd (menu command) - menu/command/menu_cmd.qc
 +// ===============================================
 +alias menu_showteamselect "menu_cmd directmenu TeamSelect"
 +alias menu_showhudexit "menu_cmd directmenu HUDExit"
 +alias menu_showhudoptions "menu_cmd directpanelhudmenu ${* ?}"
 +alias menu_showsandboxtools "menu_cmd directmenu SandboxTools"
 +alias menu_showquitdialog "menu_cmd directmenu Quit"
 +
 +// command executed before loading a map by the menu
 +// makes sure maxplayers is at least minplayers or bot_number + 1
 +alias _menu_loadmap_prepare_maxpl "maxplayers $_menu_loadmap_maxplayers"
 +alias menu_loadmap_prepare "disconnect; wait; g_campaign 0; menu_cmd rpn /_menu_loadmap_maxplayers menu_maxplayers minplayers bot_number 1 add max max def; _menu_loadmap_prepare_maxpl; g_maplist_shufflenow"
 +
 +
 +// ==========================================================
 +//  cl_cmd (client local command) - client/command/cl_cmd.qc
 +// ==========================================================
 +// commented out commands are really only intended for internal use
 +if_client alias blurtest "cl_cmd blurtest"
 +if_client alias debugmodel "cl_cmd debugmodel ${* ?}"
 +//if_client alias handlevote "cl_cmd handlevote ${* ?}"
 +if_client alias hud "cl_cmd hud ${* ?}"
 +if_client alias localprint "cl_cmd localprint ${* ?}"
 +//if_client alias mv_download "cl_cmd mv_download ${* ?}"
 +if_client alias sendcvar "cl_cmd sendcvar ${* ?}"
 +//if_client alias settemp "cl_cmd settemp ${* ?}"
 +
 +// other aliases for local commands
 +if_client alias hud_configure "cl_cmd hud configure"
 +if_client alias hud_save "cl_cmd hud save ${* ?}"
 +if_client alias radar "cl_cmd hud radar ${* ?}"
 +if_client alias scoreboard_columns_help "cl_cmd hud scoreboard_columns_help"
 +if_client alias scoreboard_columns_set "cl_cmd hud scoreboard_columns_set ${* ?}"
 +
 +// changes a cvar and reports it to the server (for the client to notify the server about changes)
 +alias setreport "set \"$1\" \"$2\" ; sendcvar \"$1\""
 +
 +
 +// ========================================================
 +//  cmd (client-to-server command) - server/command/cmd.qc
 +// ========================================================
 +set sv_clientcommand_antispam_time 1 "Amount of seconds after a command before another command can be called again without being considered spam. (Use -1 for no antispam limit)"
 +set sv_clientcommand_antispam_count 8 "Amount of commands considered spam before commands are rejected."
 +seta sv_status_privacy 1 "hide IP addresses from \"status\" and \"who\" replies shown to clients"
 +seta cl_autoswitch 1 "automatically switch to newly picked up weapons if they are better than what you are carrying"
 +
 +// commented out commands are really only intended for internal use, or already have declaration in the engine
 +alias autoswitch "cmd autoswitch ${* ?}"
 +alias checkfail "cmd checkfail ${* ?}"
 +alias clientversion "cmd clientversion ${* ?}"
 +//alias getmapvotepic "cmd getmapvotepic ${* ?}"
 +alias join "cmd join"
 +alias ready "cmd ready"
 +alias records "cmd records"
 +alias reportcvar "cmd reportcvar ${* ?}"
 +//alias say "cmd say ${* ?}" // engine already has this declared as a command
 +//alias say_team "cmd say_team ${* ?}" // engine already has this declared as a command
 +alias selectteam "cmd selectteam ${* ?}"
 +alias sentcvar "cmd sentcvar ${* ?}"
 +alias spectate "cmd spectate"
 +alias suggestmap "cmd suggestmap ${* ?}"
 +//alias tell "cmd tell ${* ?}" // engine already has this declared as a command
 +alias voice "cmd voice ${* ?}"
 +
 +// other aliases for client-to-server commands
 +alias autoswitch "set cl_autoswitch ${1 ?} ; cmd autoswitch ${1 ?}" // todo
 +
 +alias team_red "cmd selectteam red; cmd join"
 +alias team_blue "cmd selectteam blue; cmd join"
 +alias team_pink "cmd selectteam pink; cmd join"
 +alias team_yellow "cmd selectteam yellow; cmd join"
 +alias team_auto "cmd selectteam auto; cmd join"
 +
 +alias spec "spectate"
 +
 +// mutator aliases
 +alias sandbox "cmd g_sandbox ${* ?}"
 +
 +
 +// ============================================================
 +//  sv_cmd (server console command) - server/command/sv_cmd.qc
 +// ============================================================
 +alias adminmsg "sv_cmd adminmsg ${* ?}"
 +alias allready "sv_cmd allready"
 +alias allspec "sv_cmd allspec ${* ?}"
 +alias anticheat "sv_cmd anticheat ${* ?}"
 +alias bbox "sv_cmd bbox"
 +alias bot_cmd "sv_cmd bot_cmd ${* ?}"
 +alias cointoss "sv_cmd cointoss ${* ?}"
 +alias database "sv_cmd database ${* ?}"
 +alias defer_clear "sv_cmd defer_clear ${* ?}"
 +alias defer_clear_all "sv_cmd defer_clear_all"
 +alias delrec "sv_cmd delrec ${* ?}"
 +alias effectindexdump "sv_cmd effectindexdump"
 +alias extendmatchtime "sv_cmd extendmatchtime"
 +alias find "sv_cmd find ${* ?}"
 +alias gametype "sv_cmd gametype ${* ?}"
 +alias gettaginfo "sv_cmd gettaginfo ${* ?}"
 +alias gotomap "sv_cmd gotomap ${* ?}"
 +alias lockteams "sv_cmd lockteams"
 +alias make_mapinfo "sv_cmd make_mapinfo"
 +alias modelbug "sv_cmd modelbug"
 +alias moveplayer "sv_cmd moveplayer ${* ?}"
 +alias nospectators "sv_cmd nospectators"
 +alias onslaught_updatelinks "sv_cmd onslaught_updatelinks"
 +alias playerdemo "sv_cmd playerdemo ${* ?}"
 +alias printstats "sv_cmd printstats"
 +alias radarmap "sv_cmd radarmap ${* ?}"
 +alias reducematchtime "sv_cmd reducematchtime"
 +alias setbots "sv_cmd setbots ${* ?}"
 +alias shuffleteams "sv_cmd shuffleteams"
 +alias stuffto "sv_cmd stuffto ${* ?}"
 +alias trace "sv_cmd trace ${* ?}"
 +alias unlockteams "sv_cmd unlockteams"
 +alias warp "sv_cmd warp ${* ?}"
 +
 +// other aliases for server commands
 +alias endmatch "timelimit -1"
 +
 +alias savedb "sv_cmd database save \"${1 ?}\""
 +alias dumpdb "sv_cmd database dump \"${1 ?}\""
 +alias loaddb "sv_cmd database load \"${1 ?}\""
 +
 +alias movetored "moveplayer ${1 ?} red"
 +alias movetoblue "moveplayer ${1 ?} blue"
 +alias movetopink "moveplayer ${1 ?} pink"
 +alias movetoyellow "moveplayer ${1 ?} yellow"
 +alias movetoauto "moveplayer ${1 ?} auto"
 +
 +
 +// =======================================================
 +//  Aliases for settemp subsystem. Warning: Do not touch. 
 +//  Usage: settemp variable value, next map resets it.
 +// =======================================================
++alias settemp "qc_cmd_svcl settemp $$*"
++alias settemp_restore "qc_cmd_svcl settemp_restore"
 +
 +
 +// ===================================
 +//  banning - server/command/ipban.qc
 +// ===================================
 +alias bans "sv_cmd bans"
 +alias ban "sv_cmd ban ${* ?}"         // usage: ban address(maybe incomplete, like 1.2.3) bantime(seconds)
 +alias kickban "sv_cmd kickban ${* ?}" // usage: kickban # playerno bantime(seconds) masksize(bytes)
 +alias unban "sv_cmd unban ${* ?}"     // usage: unban 3 (number from bans)
 +
 +
 +// =================================
 +//  voting - server/command/vote.qc
 +// =================================
 +set sv_vote_call 1 "Allow users to call a vote for the commands in sv_vote_commands"
 +set sv_vote_change 1 "Allow voters to change their mind after already voting"
 +set sv_vote_commands "restart fraglimit chmap gotomap nextmap endmatch reducematchtime extendmatchtime allready kick cointoss movetoauto" "these commands can be voted"
 +set sv_vote_only_commands ""
 +set sv_vote_master_commands "movetored movetoblue movetoyellow movetopink" "Commands which vote masters can execute by themselves" // maybe add kickban here (but then sv_vote_master 0)
 +set sv_vote_master 1  "Allows the use of the vote master system"
 +set sv_vote_master_callable 1 "When set, users can use \"vmaster\" to call a vote to become master of voting commands"
 +set sv_vote_master_password "" "when set, users can use \"vlogin PASSWORD\" to log in as master"
 +set sv_vote_master_playerlimit 2 "Minimum number of players needed for a player to be allowed to vote for master"
 +set sv_vote_no_stops_vote 1 "Allow the vote caller to stop his own vote simply by voting no"
 +set sv_vote_singlecount 0     "set to 1 to count votes once after timeout or to 0 to count with every vote"
 +set sv_vote_timeout 30        "a vote will timeout after this many seconds"
 +set sv_vote_wait 120  "a player can not call a vote again for this many seconds when his vote was not accepted"
 +set sv_vote_stop 15   "a player can not call a vote again for this many seconds when he stopped this vote (e.g. to correct it)"
 +set sv_vote_majority_factor 0.5       "What percentage of the PLAYERS constitute a majority? (Must be at least 0.5, recommended: 0.5)"
 +set sv_vote_majority_factor_of_voted 0.5 "What percentage of the VOTERS constitute a majority too? (Must be at least 0.5, recommended: 0.5)"
 +// when disabled, don't allow game type changes "note: set these two equal to JUST support simple majorities"
 +set sv_vote_override_mostrecent 0
 +
 +alias vhelp "cmd vote help"
 +alias vstatus "cmd vote status"
 +alias vcall "cmd vote call ${* ?}"
 +alias vstop "cmd vote stop"
 +alias vmaster "cmd vote master"
 +alias vlogin "cmd vote login ${* ?}"
 +alias vdo "cmd vote do ${* ?}"
 +alias vyes "cl_cmd handlevote yes"
 +alias vno "cl_cmd handlevote no"
 +alias vdontcare "cmd vote dontcare"
 +alias vabstain "cmd vote abstain"
 +
 +alias vmap "vcall gotomap ${1 ?}"
 +alias vnextmap "vcall nextmap ${1 ?}"
 +alias vkick "vcall kick ${1 ?}"
 +alias vkickban "vcall kickban ${1 ?}"
 +alias vend "vcall endmatch"
 +alias vdomap "vdo gotomap ${1 ?}"
 +alias vdokick "vdo kick ${* ?}"
 +alias vdokickban "vdo kickban ${* ?}"
 +alias vdoend "vdo endmatch"
 +
 +// ======================
 +//  rcon server commands
 +// ======================
 +rcon_secure 1
 +set rcon_restricted_commands "restart fraglimit chmap gotomap endmatch reducematchtime extendmatchtime allready kick kickban \"sv_cmd bans\" \"sv_cmd unban *\" status \"sv_cmd teamstatus\" movetoauto movetored movetoblue movetoyellow movetopink"
 +
 +// =============================
 +//  other miscellaneous aliases
 +// =============================
 +alias autoscreenshot "screenshot screenshots/autoscreenshot/${1 !}-${2 !}.jpg; echo \"^5A screenshot has been taken at request of the server.\""
 +
Simple merge
index 0a1783e,0000000..b7fdc3a
mode 100644,000000..100644
--- /dev/null
@@@ -1,579 -1,0 +1,580 @@@
- //  Last updated: December 16th, 2011
 +// ==============================================
 +//  CSQC client commands code, written by Samual
- }
++//  Last updated: December 27th, 2011
 +// ==============================================
 +
++/*
 +float cvar_clientsettemp(string tmp_cvar, string value)
 +{
 +      float created_saved_value;
 +      entity e;
 +      
 +      if not(tmp_cvar || value)
 +      {
 +              dprint("Error: Invalid usage of cvar_clientsettemp(string, string); !\n");
 +              return FALSE;
 +      }
 +      
 +      for(e = world; (e = find(e, classname, "saved_cvar_value")); )
 +              if(e.netname == tmp_cvar)
 +                      goto saved; // skip creation
 +                      
 +      // creating a new entity to keep track of this cvar
 +      e = spawn();
 +      e.classname = "saved_cvar_value";
 +      e.netname = strzone(tmp_cvar);
 +      e.message = strzone(cvar_string(tmp_cvar));
 +      created_saved_value = TRUE;
 +      
 +      // an entity for this cvar already exists
 +      :saved
 +      
 +      // update the cvar to the value given
 +      cvar_set(tmp_cvar, value);
 +      
 +      return created_saved_value;
 +}
 +
 +float cvar_clientsettemp_restore()
 +{
 +      float i;
 +      entity e;
 +      
 +      for(e = world; (e = find(e, classname, "saved_cvar_value")); )
 +              { cvar_set(e.netname, e.message); ++i; } 
 +              
 +      return i;
-                               float i = cvar_clientsettemp_restore();
++}*/
 +
 +void DrawDebugModel()
 +{
 +      if(time - floor(time) > 0.5)
 +      {
 +              PolyDrawModel(self);
 +              self.drawmask = 0;
 +      }
 +      else
 +      {
 +              self.renderflags = 0;
 +              self.drawmask = MASK_NORMAL;
 +      }
 +}
 +
 +
 +// =======================
 +//  Command Sub-Functions
 +// =======================
 +
 +void LocalCommand_blurtest(float request)
 +{
 +      // Simple command to work with postprocessing temporarily... possibly completely pointless, the glsl shader is used for a real feature now...
 +      // Anyway, to enable it, just compile the client with -DBLURTEST and then you can use the command.
 +      
 +      #ifdef BLURTEST
 +      switch(request)
 +      {
 +              case CMD_REQUEST_COMMAND:
 +              {
 +                      blurtest_time0 = time;
 +                      blurtest_time1 = time + stof(argv(1));
 +                      blurtest_radius = stof(argv(2));
 +                      blurtest_power = stof(argv(3));
 +                      print("Enabled blurtest\n");
 +                      return; 
 +              }
 +                      
 +              default:
 +              case CMD_REQUEST_USAGE:
 +              {
 +                      print("\nUsage:^3 cl_cmd blurtest\n");
 +                      print("  No arguments required.\n");
 +                      return;
 +              }
 +      }
 +      #else
 +      if(request)
 +      {
 +              print("Blurtest is not enabled on this client.\n");
 +              return;
 +      }
 +      #endif
 +}
 +
 +void LocalCommand_debugmodel(float request, float argc)
 +{
 +      switch(request)
 +      {
 +              case CMD_REQUEST_COMMAND:
 +              {
 +                      string modelname = argv(1);
 +                      entity debugmodel_entity;
 +                      
 +                      debugmodel_entity = spawn();
 +                      precache_model(modelname);
 +                      setmodel(debugmodel_entity, modelname);
 +                      setorigin(debugmodel_entity, view_origin);
 +                      debugmodel_entity.angles = view_angles;
 +                      debugmodel_entity.draw = DrawDebugModel;
 +                      debugmodel_entity.classname = "debugmodel";
 +                      
 +                      return; 
 +              }
 +                      
 +              default:
 +              case CMD_REQUEST_USAGE:
 +              {
 +                      print("\nUsage:^3 cl_cmd debugmodel model\n");
 +                      print("  Where 'model' is a string of the model name to use for the debug model.\n");
 +                      return;
 +              }
 +      }
 +}
 +
 +void LocalCommand_handlevote(float request, float argc)
 +{
 +      switch(request)
 +      {
 +              case CMD_REQUEST_COMMAND:
 +              {
 +                      float vote_selection;
 +                      string vote_string;
 +                      
 +                      if(InterpretBoolean(argv(1)))
 +                      {
 +                              vote_selection = 2; 
 +                              vote_string = "yes";
 +                      }
 +                      else
 +                      {
 +                              vote_selection = 1; 
 +                              vote_string = "no"; 
 +                      }
 +                      
 +                      if(vote_selection)
 +                      {
 +                              if(uid2name_dialog) // handled by "uid2name" option
 +                              {
 +                                      vote_active = 0;
 +                                      vote_prev = 0;
 +                                      vote_change = -9999;
 +                                      localcmd(strcat("setreport cl_allow_uid2name ", ftos(vote_selection - 1), "\n"));
 +                                      uid2name_dialog = 0;
 +                              }
 +                              else { localcmd(strcat("cmd vote ", vote_string, "\n")); }
 +                              
 +                              return;
 +                      }
 +              }
 +                      
 +              default:
 +                      print("Incorrect parameters for ^2handlevote^7\n");
 +              case CMD_REQUEST_USAGE:
 +              {
 +                      print("\nUsage:^3 cl_cmd handlevote vote\n");
 +                      print("  Where 'vote' is the selection for either the current poll or uid2name.\n");
 +                      return;
 +              }
 +      }
 +}
 +
 +void LocalCommand_hud(float request, float argc)
 +{
 +      switch(request)
 +      {
 +              case CMD_REQUEST_COMMAND:
 +              {
 +                      switch(argv(1))
 +                      {
 +                              case "configure":
 +                              {
 +                                      cvar_set("_hud_configure", ftos(!autocvar__hud_configure));
 +                                      return;
 +                              }
 +                              
 +                              case "save":
 +                              {
 +                                      if(argv(2))
 +                                      {
 +                                              HUD_Panel_ExportCfg(argv(2));
 +                                              return;
 +                                      }
 +                                      else
 +                                      {
 +                                              break; // go to usage, we're missing the paramater needed here.
 +                                      }
 +                              }
 +                              
 +                              case "scoreboard_columns_set":
 +                              {
 +                                      Cmd_HUD_SetFields(argc); 
 +                                      return;
 +                              }
 +
 +                              case "scoreboard_columns_help":
 +                              {
 +                                      Cmd_HUD_Help();
 +                                      return;
 +                              }
 +                              
 +                              case "radar":
 +                              {
 +                                      hud_panel_radar_maximized = (argv(2) ? InterpretBoolean(argv(2)) : !hud_panel_radar_maximized);
 +                                      return;
 +                              }
 +                      }
 +              }
 +                      
 +              default:
 +                      print("Incorrect parameters for ^2hud^7\n");
 +              case CMD_REQUEST_USAGE:
 +              {
 +                      print("\nUsage:^3 cl_cmd hud action [configname | radartoggle | layout]\n");
 +                      print("  Where 'action' is the command to complete,\n");
 +                      print("  'configname' is the name to save to for \"save\" action,\n");
 +                      print("  'radartoggle' is to control hud_panel_radar_maximized for \"radar\" action,\n");
 +                      print("  and 'layout' is how to organize the scoreboard columns for the set action.\n");
 +                      print("  Full list of commands here: \"configure, save, scoreboard_columns_help, scoreboard_columns_set, radar.\"\n");
 +                      return;
 +              }
 +      }
 +}
 +
 +void LocalCommand_localprint(float request, float argc)
 +{
 +      switch(request)
 +      {
 +              case CMD_REQUEST_COMMAND:
 +              {
 +                      if(argv(1))
 +                      {
 +                              centerprint_hud(argv(1));
 +                              return; 
 +                      }
 +              }
 +                      
 +              default:
 +                      print("Incorrect parameters for ^2localprint^7\n");
 +              case CMD_REQUEST_USAGE:
 +              {
 +                      print("\nUsage:^3 cl_cmd localprint \"message\"\n");
 +                      print("  'message' is the centerprint message to send to yourself.\n");
 +                      return;
 +              }
 +      }
 +}
 +
 +void LocalCommand_mv_download(float request, float argc)
 +{
 +      switch(request)
 +      {
 +              case CMD_REQUEST_COMMAND:
 +              {
 +                      Cmd_MapVote_MapDownload(argc);
 +                      return; 
 +              }
 +                      
 +              default:
 +              case CMD_REQUEST_USAGE:
 +              {
 +                      print("\nUsage:^3 cl_cmd mv_download mapid\n");
 +                      print("  Where 'mapid' is the id number of the map to request an image of on the map vote selection menu.\n");
 +                      return;
 +              }
 +      }
 +}
 +
 +void LocalCommand_sendcvar(float request, float argc)
 +{
 +      switch(request)
 +      {
 +              case CMD_REQUEST_COMMAND:
 +              {
 +                      // W_FixWeaponOrder will trash argv, so save what we need.
 +                      string thiscvar = strzone(argv(1));
 +                      string s = cvar_string(thiscvar);
 +                      
 +                      if(thiscvar == "cl_weaponpriority")
 +                              s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 1);
 +                      else if(substring(thiscvar, 0, 17) == "cl_weaponpriority" && strlen(thiscvar) == 18)
 +                              s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 0);
 +                              
 +                      localcmd("cmd sentcvar ", thiscvar, " \"", s, "\"\n");
 +                      strunzone(thiscvar);
 +                      return; 
 +              }
 +                      
 +              default:
 +              case CMD_REQUEST_USAGE:
 +              {
 +                      print("\nUsage:^3 cl_cmd sendcvar <cvar>\n");
 +                      print("  Where 'cvar' is the cvar plus arguments to send to the server.\n");
 +                      return;
 +              }
 +      }
 +}
 +
 +void LocalCommand_settemp(float request, float argc)
 +{
 +      switch(request)
 +      {
 +              case CMD_REQUEST_COMMAND:
 +              {
 +                      if((argv(1) == "restore") && argv(2))
 +                      {
-                               if(cvar_clientsettemp(argv(1), argv(2)))
++                              float i = cvar_settemp_restore();
 +                              
 +                              if(i)
 +                                      dprint("Restored ", ftos(i), " temporary cvar settings to their original values.\n");
 +                              else
 +                                      dprint("Nothing to restore.\n");
 +                              
 +                              return;
 +                      }
 +                      else if(argc >= 3)
 +                      {
++                              if(cvar_settemp(argv(1), argv(2)))
 +                                      dprint("Creating new settemp tracker for ", argv(1), " and setting it to \"", argv(2), "\" temporarily.\n"); 
 +                              else
 +                                      dprint("Already had a tracker for ", argv(1), ", updating it to \"", argv(2), "\".\n");
 +                      
 +                              return;
 +                      }
 +              }
 +                      
 +              default:
 +                      print("Incorrect parameters for ^2settemp^7\n");
 +              case CMD_REQUEST_USAGE:
 +              {
 +                      print("\nUsage:^3 cl_cmd settemp \"cvar\" | [restore]\n");
 +                      print("  Where 'cvar' is the cvar plus arguments to send to the server,\n");
 +                      print("  or 'restore' allows you to restore all of the original temporary cvar values.\n");
 +                      return;
 +              }
 +      }
 +}
 +
 +/* use this when creating a new command, making sure to place it in alphabetical order... also,
 +** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
 +void LocalCommand_(float request)
 +{
 +      switch(request)
 +      {
 +              case CMD_REQUEST_COMMAND:
 +              {
 +                      
 +                      return; 
 +              }
 +                      
 +              default:
 +              case CMD_REQUEST_USAGE:
 +              {
 +                      print("\nUsage:^3 cl_cmd \n");
 +                      print("  No arguments required.\n");
 +                      return;
 +              }
 +      }
 +}
 +*/
 +
 +
 +// ==================================
 +//  Macro system for client commands
 +// ==================================
 +
 +// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
 +#define CLIENT_COMMANDS(request,arguments) \
 +      CLIENT_COMMAND("blurtest", LocalCommand_blurtest(request), "Feature for testing blur postprocessing") \
 +      CLIENT_COMMAND("debugmodel", LocalCommand_debugmodel(request, arguments), "Spawn a debug model manually") \
 +      CLIENT_COMMAND("handlevote", LocalCommand_handlevote(request, arguments), "System to handle selecting a vote or option") \
 +      CLIENT_COMMAND("hud", LocalCommand_hud(request, arguments), "Commands regarding/controlling the HUD system") \
 +      CLIENT_COMMAND("localprint", LocalCommand_localprint(request, arguments), "Create your own centerprint sent to yourself") \
 +      CLIENT_COMMAND("mv_download", LocalCommand_mv_download(request, arguments), "Retrieve mapshot picture from the server") \
 +      CLIENT_COMMAND("sendcvar", LocalCommand_sendcvar(request, arguments), "Send a cvar to the server (like weaponpriority)") \
 +      CLIENT_COMMAND("settemp", LocalCommand_settemp(request, arguments), "Temporarily set a value to a cvar which is restored by command or end of each match") \
 +      /* nothing */
 +      
 +void LocalCommand_macro_help()
 +{
 +      #define CLIENT_COMMAND(name,function,description) \
 +              { print("  ^2", name, "^7: ", description, "\n"); }
 +              
 +      CLIENT_COMMANDS(0, 0)
 +      #undef CLIENT_COMMAND
 +      
 +      return;
 +}
 +
 +float LocalCommand_macro_command(float argc)
 +{
 +      #define CLIENT_COMMAND(name,function,description) \
 +              { if(name == strtolower(argv(0))) { function; return TRUE; } }
 +              
 +      CLIENT_COMMANDS(CMD_REQUEST_COMMAND, argc)
 +      #undef CLIENT_COMMAND
 +      
 +      return FALSE;
 +}
 +
 +float LocalCommand_macro_usage(float argc)
 +{
 +      #define CLIENT_COMMAND(name,function,description) \
 +              { if(name == strtolower(argv(1))) { function; return TRUE; } }
 +              
 +      CLIENT_COMMANDS(CMD_REQUEST_USAGE, argc)
 +      #undef CLIENT_COMMAND
 +      
 +      return FALSE;
 +}
 +
 +
 +// =========================================
 +//  Main Function Called By Engine (cl_cmd)
 +// =========================================
 +// If this function exists, client code handles gamecommand instead of the engine code.
 +
 +void GameCommand(string command)
 +{
 +      float argc = tokenize_console(command);
 +
 +      // Guide for working with argc arguments by example:
 +      // argc:   1    - 2      - 3     - 4
 +      // argv:   0    - 1      - 2     - 3 
 +      // cmd     vote - master - login - password
 +
 +      if(strtolower(argv(0)) == "help") 
 +      {
 +              if(argc == 1) 
 +              {
 +                      print("\nUsage:^3 cl_cmd COMMAND...^7, where possible commands are:\n");
 +                      LocalCommand_macro_help();
 +                      GameCommand_Generic("help");
 +                      print("For help about specific commands, type cl_cmd help COMMAND\n");
 +                      return;
 +              } 
 +              else if(LocalCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
 +              {
 +                      return;
 +              }
 +      } 
 +      else if(GameCommand_Generic(command)) 
 +      {
 +              return; // handled by common/command/generic.qc
 +      }
 +      else if(LocalCommand_macro_command(argc)) // continue as usual and scan for normal commands
 +      {
 +              return; // handled by one of the above LocalCommand_* functions
 +      }
 +      
 +      // nothing above caught the command, must be invalid
 +      print(((command != "") ? strcat("Unknown client command \"", command, "\"") : "No command provided"), ". For a list of supported commands, try cl_cmd help.\n");
 +      
 +      return;
 +}
 +
 +
 +// ===================================
 +//  Macro system for console commands
 +// ===================================
 +
 +// These functions are here specifically to add special + - commands to the game, and are not really normal commands.
 +// Please add client commands to the function above this, as this is only for special reasons.
 +#define CONSOLE_COMMANDS_NORMAL \
 +      CONSOLE_COMMAND("+showscores", { scoreboard_showscores = TRUE; }) \
 +      CONSOLE_COMMAND("-showscores", { scoreboard_showscores = FALSE; }) \
 +      CONSOLE_COMMAND("+showaccuracy", { scoreboard_showaccuracy = TRUE; }) \
 +      CONSOLE_COMMAND("-showaccuracy", { scoreboard_showaccuracy = FALSE; }) \
 +      /* nothing */
 +      
 +#define CONSOLE_COMMANDS_MOVEMENT \
 +      CONSOLE_COMMAND("+forward", { ++camera_direction_x; }) \
 +      CONSOLE_COMMAND("-forward", { --camera_direction_x; }) \
 +      CONSOLE_COMMAND("+back", { --camera_direction_x; }) \
 +      CONSOLE_COMMAND("-back", { ++camera_direction_x; }) \
 +      CONSOLE_COMMAND("+moveup", { ++camera_direction_z; }) \
 +      CONSOLE_COMMAND("-moveup", { --camera_direction_z; }) \
 +      CONSOLE_COMMAND("+movedown", { --camera_direction_z; }) \
 +      CONSOLE_COMMAND("-movedown", { ++camera_direction_z; }) \
 +      CONSOLE_COMMAND("+moveright", { --camera_direction_y; }) \
 +      CONSOLE_COMMAND("-moveright", { ++camera_direction_y; }) \
 +      CONSOLE_COMMAND("+moveleft", { ++camera_direction_y; }) \
 +      CONSOLE_COMMAND("-moveleft", { --camera_direction_y; }) \
 +      CONSOLE_COMMAND("+roll_right", { ++camera_roll; }) \
 +      CONSOLE_COMMAND("-roll_right", { --camera_roll; }) \
 +      CONSOLE_COMMAND("+roll_left", { --camera_roll; }) \
 +      CONSOLE_COMMAND("-roll_left", { ++camera_roll; }) \
 +      /* nothing */
 +
 +void ConsoleCommand_macro_init()
 +{
 +      // first init normal commands
 +      #define CONSOLE_COMMAND(name,execution) \
 +              { registercommand(name); }
 +
 +      CONSOLE_COMMANDS_NORMAL
 +      #undef CONSOLE_COMMAND
 +      
 +      // then init movement commands
 +      #ifndef CAMERATEST
 +      if(isdemo())
 +      {
 +      #endif
 +              #define CONSOLE_COMMAND(name,execution) \
 +                      { registercommand(name); }
 +
 +              CONSOLE_COMMANDS_MOVEMENT
 +              #undef CONSOLE_COMMAND
 +      #ifndef CAMERATEST
 +      }
 +      #endif
 +      
 +      return;
 +}
 +
 +float ConsoleCommand_macro_normal(float argc)
 +{
 +      #define CONSOLE_COMMAND(name,execution) \
 +              { if(name == strtolower(argv(0))) { { execution } return TRUE; } }
 +              
 +      CONSOLE_COMMANDS_NORMAL
 +      #undef CONSOLE_COMMAND
 +      
 +      return FALSE;
 +}
 +
 +float ConsoleCommand_macro_movement(float argc)
 +{
 +      if(camera_active)
 +      {
 +              #define CONSOLE_COMMAND(name,execution) \
 +                      { if(name == strtolower(argv(0))) { { execution } return TRUE; } }
 +
 +              CONSOLE_COMMANDS_MOVEMENT
 +              #undef CONSOLE_COMMAND
 +      }
 +      
 +      return FALSE;
 +}
 +
 +
 +// ======================================================
 +//  Main Function Called By Engine (registered commands)
 +// ======================================================
 +// Used to parse commands in the console that have been registered with the "registercommand" function
 +
 +float CSQC_ConsoleCommand(string command)
 +{
 +      float argc = tokenize_console(command);
 +
 +      if(ConsoleCommand_macro_normal(argc))
 +      {
 +              return TRUE;
 +      }
 +      else if(ConsoleCommand_macro_movement(argc))
 +      {
 +              return TRUE;
 +      }
 +      
 +      // Return value should be 1 if CSQC handled the command, otherwise return 0 to have the engine handle it.
 +
 +      return FALSE;
 +}
index 9595ed5,0000000..1d21f08
mode 100644,000000..100644
--- /dev/null
@@@ -1,853 -1,0 +1,863 @@@
 +#define MAX_RPN_STACK 16
 +float rpn_db;
 +float rpn_error;
 +float rpn_sp;
 +string rpn_stack[MAX_RPN_STACK];
 +string rpn_pop() {
 +      if(rpn_sp > 0) {
 +              --rpn_sp;
 +              return rpn_stack[rpn_sp];
 +      } else {
 +              print("rpn: stack underflow\n");
 +              rpn_error = TRUE;
 +              return "";
 +      }
 +}
 +void rpn_push(string s) {
 +      if(rpn_sp < MAX_RPN_STACK) {
 +              rpn_stack[rpn_sp] = s;
 +              ++rpn_sp;
 +      } else {
 +              print("rpn: stack overflow\n");
 +              rpn_error = TRUE;
 +      }
 +}
 +string rpn_get() {
 +      if(rpn_sp > 0) {
 +              return rpn_stack[rpn_sp - 1];
 +      } else {
 +              print("rpn: empty stack\n");
 +              rpn_error = TRUE;
 +              return "";
 +      }
 +}
 +void rpn_set(string s) {
 +      if(rpn_sp > 0) {
 +              rpn_stack[rpn_sp - 1] = s;
 +      } else {
 +              print("rpn: empty stack\n");
 +              rpn_error = TRUE;
 +      }
 +}
 +float rpn_getf() { return stof(rpn_get()); }
 +float rpn_popf() { return stof(rpn_pop()); }
 +void rpn_pushf(float f) { return rpn_push(ftos(f)); }
 +void rpn_setf(float f) { return rpn_set(ftos(f)); }
 +
 +#define NUM_MARKUPS   41
 +float markup_init;
 +string markup_from[NUM_MARKUPS];
 +string markup_to[NUM_MARKUPS];
 +void GameCommand_MarkupInit()
 +{
 +      float i;
 +      if (markup_init)
 +              return;
 +      markup_init = 1;
 +      i = 0;
 +      markup_from[i] = "&alien"; markup_to[i] = "\x12"; ++i;
 +      markup_from[i] = "&:-)"; markup_to[i] = "\x13"; ++i;
 +      markup_from[i] = "&:-("; markup_to[i] = "\x14"; ++i;
 +      markup_from[i] = "&x-P"; markup_to[i] = "\x15"; ++i;
 +      markup_from[i] = "&:-/"; markup_to[i] = "\x16"; ++i;
 +      markup_from[i] = "&:-D"; markup_to[i] = "\x17"; ++i;
 +      markup_from[i] = "&<<"; markup_to[i] = "\x18"; ++i;
 +      markup_from[i] = "&>>"; markup_to[i] = "\x19"; ++i;
 +      markup_from[i] = "&dot"; markup_to[i] = "\x1a"; ++i;
 +      markup_from[i] = "&^_"; markup_to[i] = "\x1b"; ++i;
 +      markup_from[i] = "&ysplat"; markup_to[i] = "\x1c"; ++i;
 +      markup_from[i] = "&-]"; markup_to[i] = "\x1d"; ++i;
 +      markup_from[i] = "&--"; markup_to[i] = "\x1e"; ++i;
 +      markup_from[i] = "&[-"; markup_to[i] = "\x1f"; ++i;
 +      markup_from[i] = "&s<"; markup_to[i] = "\x2c"; ++i;
 +      markup_from[i] = "&s>"; markup_to[i] = "\x2e"; ++i;
 +      markup_from[i] = "&<-"; markup_to[i] = "\x7f"; ++i;
 +      markup_from[i] = "&[="; markup_to[i] = "\x80"; ++i;
 +      markup_from[i] = "&=="; markup_to[i] = "\x81"; ++i;
 +      markup_from[i] = "&=]"; markup_to[i] = "\x82"; ++i;
 +      markup_from[i] = "&r!"; markup_to[i] = "\x84"; ++i;
 +      markup_from[i] = "&|o|"; markup_to[i] = "\x85"; ++i;
 +      markup_from[i] = "&|u|"; markup_to[i] = "\x86"; ++i;
 +      markup_from[i] = "&|i|"; markup_to[i] = "\x87"; ++i;
 +      markup_from[i] = "&|c|"; markup_to[i] = "\x88"; ++i;
 +      markup_from[i] = "&[c]"; markup_to[i] = "\x89"; ++i;
 +      markup_from[i] = "&[n]"; markup_to[i] = "\x8a"; ++i;
 +      markup_from[i] = "&[]"; markup_to[i] = "\x8b"; ++i;
 +      markup_from[i] = "&r?"; markup_to[i] = "\x8c"; ++i;
 +      markup_from[i] = "&|>"; markup_to[i] = "\x8d"; ++i;
 +      markup_from[i] = "&splat0"; markup_to[i] = "\x8e"; ++i;
 +      markup_from[i] = "&splat1"; markup_to[i] = "\x8f"; ++i;
 +      markup_from[i] = "&[["; markup_to[i] = "\x90"; ++i;
 +      markup_from[i] = "&]]"; markup_to[i] = "\x91"; ++i;
 +      markup_from[i] = "&splat2"; markup_to[i] = "\x9a"; ++i;
 +      markup_from[i] = "&)("; markup_to[i] = "\x9b"; ++i;
 +      markup_from[i] = "&splat3"; markup_to[i] = "\x9c"; ++i;
 +      markup_from[i] = "&(."; markup_to[i] = "\x9d"; ++i;
 +      markup_from[i] = "&.."; markup_to[i] = "\x9e"; ++i;
 +      markup_from[i] = "&.)"; markup_to[i] = "\x9f"; ++i;
 +      markup_from[i] = "&<|"; markup_to[i] = "\xff"; ++i;
 +}
 +
 +string GameCommand_Markup(string s2)
 +{
 +      float red, ccase, i, j;
 +      string s, s3;
 +
 +      GameCommand_MarkupInit();
 +
 +      s = "";
 +
 +      red = 0;
 +      ccase = 0;
 +      for(i = 0; i < strlen(s2); ++i)
 +      {
 +              for(j = 0; j < NUM_MARKUPS; ++j)
 +              {
 +                      s3 = substring(s2, i, strlen(markup_from[j]));
 +                      if (s3 == markup_from[j])
 +                      {
 +                              s = strcat(s, markup_to[j]);
 +                              i += strlen(markup_from[j]) - 1;
 +                              break;
 +                      }
 +              }
 +
 +              if(j == NUM_MARKUPS)
 +              {
 +                      if(substring(s2, i, 2) == "&&")
 +                      {
 +                              s = strcat(s, strconv(ccase, red, red, "&"));
 +                              ++i;
 +                      }
 +                      else if(substring(s2, i, 2) == "&d")
 +                      {
 +                              red = 2;
 +                              ccase = 0;
 +                              ++i;
 +                      }
 +                      else if(substring(s2, i, 2) == "&a")
 +                      {
 +                              red = 2;
 +                              ccase = 2;
 +                              ++i;
 +                      }
 +                      else if(substring(s2, i, 2) == "&n")
 +                      {
 +                              red = 0;
 +                              ccase = 0;
 +                              ++i;
 +                      }
 +                      else
 +                              s = strcat(s, strconv(ccase, red, red, substring(s2, i, 1)));
 +              }
 +      }
 +
 +      return s;
 +}
 +
 +float GameCommand_Generic(string command)
 +{
 +      float argc;
 +      float i, j, f, n;
 +      vector rgb;
 +      string s, s2, c;
 +      argc = tokenize_console(command);
 +      if(argv(0) == "help")
 +      {
 +              print("  rpn EXPRESSION... - a RPN calculator.\n");
 +              print("    Operator description (x: string, s: set, f: float):\n");
 +              print("    x pop ----------------------------->     : removes the top\n");
 +              print("    x dup -----------------------------> x x : duplicates the top\n");
 +              print("    x x exch --------------------------> x x : swap the top two\n");
 +              print("    /cvarname load --------------------> x   : loads a cvar\n");
 +              print("    /cvarname x def ------------------->     : writes to a cvar\n");
 +              print("    f f add|sub|mul|div|mod|max|min ---> f   : adds/... two numbers\n");
 +              print("    f f eq|ne|gt|ge|lt|le -------------> f   : compares two numbers\n");
 +              print("    f neg|abs|sgn|rand|floor|ceil------> f   : negates/... a number\n");
 +              print("    f f f bound -----------------------> f   : bounds the middle number\n");
 +              print("    f1 f2 b when ----------------------> f   : f1 if b, f2 otherwise\n");
 +              print("    s s union|intersection|difference -> s   : set operations\n");
 +              print("    s shuffle -------------------------> s   : randomly arrange elements\n");
 +              print("    /key /value put ------------------->     : set a database key\n");
 +              print("    /key get --------------------------> s   : get a database value\n");
 +              print("    x dbpush -------------------------->     : pushes the top onto the database\n");
 +              print("    dbpop|dbget -----------------------> x   : removes/reads DB's top\n");
 +              print("    dblen|dbat ------------------------> f   : gets the DB's size/cursor pos\n");
 +              print("    dbclr ----------------------------->     : clear the DB\n");
 +              print("    s dbsave|dbload-------------------->     : save/load the DB to/from a file\n");
 +              print("    x dbins --------------------------->     : moves the top into the DB\n");
 +              print("    dbext|dbread ----------------------> x   : extract/get from the DB's cursor\n");
 +              print("    f dbmov|dbgoto -------------------->     : move or set the DB's cursor\n");
 +              print("    s localtime -----------------------> s   : formats the current local time\n");
 +              print("    s gmtime --------------------------> s   : formats the current UTC time\n");
 +              print("    time ------------------------------> f   : seconds since VM start\n");
 +              print("    s /MD4 digest ---------------------> s   : MD4 digest\n");
 +              print("    s /SHA256 digest ------------------> s   : SHA256 digest\n");
 +              print("    s /formatstring sprintf1s ---------> s   : sprintf with 1 string (pad, cut)\n");
 +              print("    Set operations operate on 'such''strings'.\n");
 +              print("    Unknown tokens insert their cvar value.\n");
 +              print("  maplist add map\n");
 +              print("  maplist remove map\n");
 +              print("  maplist shuffle\n");
 +              print("  maplist cleanup\n");
 +              print("  maplist maplist\n");
 +              print("  maplist lsmaps\n");
 +              print("  maplist lsnewmaps\n");
 +              print("  addtolist variable addedvalue\n");
 +              print("  records\n");
 +              print("  rankings (map argument optional)\n");
++              print("  settemp cvar value\n");
++              print("  settemp_restore\n");
 +              return TRUE;
 +      }
 +      
 +      if(argv(0) == "maplist")
 +      {
 +              if(argv(1) == "add" && argc == 3)
 +              {
 +                      if (!fexists(strcat("maps/", argv(2), ".bsp")))
 +                      {
 +                              print("maplist: ERROR: ", argv(2), " does not exist!\n");
 +                              return TRUE;
 +                      }
 +                      if(cvar_string("g_maplist") == "")
 +                              cvar_set("g_maplist", argv(2));
 +                      else
 +                              cvar_set("g_maplist", strcat(argv(2), " ", cvar_string("g_maplist")));
 +                      return TRUE;
 +              }
 +              else if(argv(1) == "remove" && argc == 3)
 +              {
 +                      s = argv(2);
 +                      n = tokenizebyseparator(cvar_string("g_maplist"), " ");
 +                      s2 = "";
 +                      for(i = 0; i < n; ++i)
 +                              if(argv(i) != s)
 +                                      s2 = strcat(s2, " ", argv(i));
 +                      s2 = substring(s2, 1, strlen(s2) - 1);
 +                      cvar_set("g_maplist", s2);
 +                      return TRUE;
 +              }
 +              else if(argv(1) == "shuffle" && argc == 2)
 +              {
 +                      cvar_set("g_maplist", shufflewords(cvar_string("g_maplist")));
 +                      return TRUE;
 +              }
 +              else if(argv(1) == "cleanup")
 +              {
 +                      MapInfo_Enumerate();
 +                      MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
 +                      n = tokenizebyseparator(cvar_string("g_maplist"), " ");
 +                      s2 = "";
 +                      for(i = 0; i < n; ++i)
 +                              if(MapInfo_CheckMap(argv(i)))
 +                                      s2 = strcat(s2, " ", argv(i));
 +                      s2 = substring(s2, 1, strlen(s2) - 1);
 +                      cvar_set("g_maplist", s2);
 +                      return TRUE;
 +              }
 +              else if(argv(1) == "maplist") {
 +                      print(maplist_reply);
 +                      return TRUE;
 +              }
 +              else if(argv(1) == "lsmaps") {
 +                      print(lsmaps_reply);
 +                      return TRUE;
 +              }
 +              else if(argv(1) == "lsnewmaps") {
 +                      print(lsnewmaps_reply);
 +                      return TRUE;
 +              }
 +      }
 +      else if(argc >= 3 && argv(0) == "red")
 +      {
 +              s = substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2));
 +              localcmd(strcat(argv(1), " ", GameCommand_Markup(s)));
 +              return TRUE;
 +      }
 +      else if(argc >= 3 && crc16(0, argv(0)) == 38566 && crc16(0, strcat(argv(0), argv(0), argv(0))) == 59830)
 +      {
 +              // other test case
 +              s = strconv(2, 0, 0, substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
 +
 +              n = floor(random() * 6 + 2);
 +
 +              s2 = "";
 +              for(i = 0; i < n; ++i)
 +              {
 +                      s2 = strcat(s2, "AH");
 +              }
 +
 +              if(random() < 0.1)
 +                      s2 = strcat(substring(s2, 1, strlen(s2) - 1), "A");
 +
 +              if(s == "")
 +                      s = s2;
 +              else
 +                      if(random() < 0.8)
 +                              s = strcat(s, " ", s2);
 +                      else
 +                              s = strcat(s2, " ", s);
 +
 +              s2 = substring(s, strlen(s) - 2, 2);
 +              if(s2 == "AH" || s2 == "AY")
 +                      s = strcat(s, "))");
 +              else
 +                      s = strcat(s, " ))");
 +
 +              if(random() < 0.1)
 +                      s = substring(s, 0, strlen(s) - 1);
 +
 +              if(random() < 0.1)
 +                      s = strconv(1, 0, 0, s);
 +
 +              localcmd(strcat(argv(1), " ", s));
 +
 +              return TRUE;
 +      }
 +      else if(argc >= 3 && crc16(0, argv(0)) == 3826 && crc16(0, strcat(argv(0), argv(0), argv(0))) == 55790)
 +      {
 +              // test case for terencehill's color codes
 +              s = strdecolorize(substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
 +              s2 = "";
 +              
 +              n = strlen(s);
 +              j = ((6 * max(1, floor(strlen(s)/32 + random() * 2 - 1))) / n) * (1 - 2 * (random() > 0.5));
 +              f = random() * 6;
 +
 +              for(i = 0; i < n; ++i)
 +              {
 +                      c = substring(s, i, 1);
 +
 +                      if(c == ";")
 +                              c = ":";
 +                      else if(c == "^")
 +                      {
 +                              c = "^^";
 +                              if(substring(s, i+1, 1) == "^")
 +                                      ++i;
 +                      }
 +
 +                      if(c != " ")
 +                      {
 +                              rgb = hsl_to_rgb('1 0 0' * (j * i + f) + '0 1 .5');
 +                              c = strcat(rgb_to_hexcolor(rgb), c);
 +                      }
 +                      s2 = strcat(s2, c);
 +              }
 +
 +              localcmd(strcat(argv(1), " ", s2));
 +
 +              return TRUE;
 +      }
 +      else if(argv(0) == "rpn")
 +      {
 +              if(!rpn_db)
 +              {
 +                      rpn_db = db_create();
 +                      db_put(rpn_db, "stack.pointer", "0");
 +                      db_put(rpn_db, "stack.pos", "-1");
 +              }
 +              if(argc >= 2)
 +              {
 +                      float rpnpos;
 +                      string rpncmd;
 +                      float f2, f3;
 +                      rpn_sp = 0;
 +                      rpn_error = FALSE;
 +                      for(rpnpos = 1; rpnpos < argc; ++rpnpos)
 +                      {
 +                              rpncmd = argv(rpnpos);
 +                              f = strlen(rpncmd);
 +                              if(rpncmd == "") {
 +                              } else if(stof(substring(rpncmd, 0, 1)) > 0) {
 +                                      rpn_push(rpncmd);
 +                              } else if(substring(rpncmd, 0, 1) == "0") {
 +                                      rpn_push(rpncmd);
 +                              } else if(f >= 2 && substring(rpncmd, 0, 1) == "+") {
 +                                      rpn_push(rpncmd);
 +                              } else if(f >= 2 && substring(rpncmd, 0, 1) == "-") {
 +                                      rpn_push(rpncmd);
 +                              } else if(f >= 2 && substring(rpncmd, 0, 1) == "/") {
 +                                      rpn_push(substring(rpncmd, 1, strlen(rpncmd) - 1));
 +                              } else if(rpncmd == "clear") {
 +                                      rpn_sp = 0;
 +                              } else if(rpncmd == "def" || rpncmd == "=") {
 +                                      s = rpn_pop();
 +                                      s2 = rpn_pop();
 +
 +                                      if(s2 != "")
 +                                      {
 +#ifdef MENUQC
 +                                              registercvar(s2, "", 0);
 +#else
 +                                              registercvar(s2, "");
 +#endif
 +                                              if(!rpn_error) // don't change cvars if a stack error had happened!
 +                                                      cvar_set(s2, s);
 +                                      }
 +                                      else
 +                                      {
 +                                              print("rpn: empty cvar name for 'def'\n");
 +                                              rpn_error = TRUE;
 +                                      }
 +                              } else if(rpncmd == "defs" || rpncmd == "@") {
 +                                      s = "";
 +                                      i = rpn_popf();
 +                                      j = (i == 0);
 +                                      while(rpn_sp > 1 && (j || i > 0))
 +                                      {
 +                                              s = strcat("/", rpn_pop(), " ", s);
 +                                              --i;
 +                                      }
 +                                      s2 = rpn_pop();
 +                                      if(s2 != "")
 +                                      {
 +#ifdef MENUQC
 +                                              registercvar(s2, "", 0);
 +#else
 +                                              registercvar(s2, "");
 +#endif
 +                                              if(!rpn_error) // don't change cvars if a stack error had happened!
 +                                                      cvar_set(s2, s);
 +                                      }
 +                                      else
 +                                      {
 +                                              print("rpn: empty cvar name for 'defs'\n");
 +                                              rpn_error = TRUE;
 +                                      }
 +                              } else if(rpncmd == "load") {
 +                                      rpn_set(cvar_string(rpn_get()));
 +                              } else if(rpncmd == "exch") {
 +                                      s = rpn_pop();
 +                                      s2 = rpn_get();
 +                                      rpn_set(s);
 +                                      rpn_push(s2);
 +                              } else if(rpncmd == "dup") {
 +                                      rpn_push(rpn_get());
 +                              } else if(rpncmd == "pop") {
 +                                      rpn_pop();
 +                              } else if(rpncmd == "add" || rpncmd == "+") {
 +                                      f = rpn_popf();
 +                                      rpn_setf(rpn_getf() + f);
 +                              } else if(rpncmd == "sub" || rpncmd == "-") {
 +                                      f = rpn_popf();
 +                                      rpn_setf(rpn_getf() - f);
 +                              } else if(rpncmd == "mul" || rpncmd == "*") {
 +                                      f = rpn_popf();
 +                                      rpn_setf(rpn_getf() * f);
 +                              } else if(rpncmd == "div" || rpncmd == "/") {
 +                                      f = rpn_popf();
 +                                      rpn_setf(rpn_getf() / f);
 +                              } else if(rpncmd == "mod" || rpncmd == "%") {
 +                                      f = rpn_popf();
 +                                      f2 = rpn_getf();
 +                                      rpn_setf(f2 - f * floor(f2 / f));
 +                              } else if(rpncmd == "abs") {
 +                                      rpn_setf(fabs(rpn_getf()));
 +                              } else if(rpncmd == "sgn") {
 +                                      f = rpn_getf();
 +                                      if(f < 0)
 +                                              rpn_set("-1");
 +                                      else if(f > 0)
 +                                              rpn_set("1");
 +                                      else
 +                                              rpn_set("0");
 +                              } else if(rpncmd == "neg" || rpncmd == "~") {
 +                                      rpn_setf(-rpn_getf());
 +                              } else if(rpncmd == "floor" || rpncmd == "f") {
 +                                      rpn_setf(floor(rpn_getf()));
 +                              } else if(rpncmd == "ceil" || rpncmd == "c") {
 +                                      rpn_setf(ceil(rpn_getf()));
 +                              } else if(rpncmd == "max") {
 +                                      f = rpn_popf();
 +                                      f2 = rpn_getf();
 +                                      rpn_setf(max(f2, f));
 +                              } else if(rpncmd == "min") {
 +                                      f = rpn_popf();
 +                                      f2 = rpn_getf();
 +                                      rpn_setf(min(f2, f));
 +                              } else if(rpncmd == "bound") {
 +                                      f = rpn_popf();
 +                                      f2 = rpn_popf();
 +                                      f3 = rpn_getf();
 +                                      rpn_setf(bound(f3, f2, f));
 +                              } else if(rpncmd == "when") {
 +                                      f = rpn_popf();
 +                                      f2 = rpn_popf();
 +                                      f3 = rpn_getf();
 +                                      if(f)
 +                                              rpn_setf(f3);
 +                                      else
 +                                              rpn_setf(f2);
 +                              } else if(rpncmd == ">" || rpncmd == "gt") {
 +                                      f = rpn_popf();
 +                                      rpn_setf(rpn_getf() > f);
 +                              } else if(rpncmd == "<" || rpncmd == "lt") {
 +                                      f = rpn_popf();
 +                                      rpn_setf(rpn_getf() < f);
 +                              } else if(rpncmd == "==" || rpncmd == "eq") {
 +                                      f = rpn_popf();
 +                                      rpn_setf(rpn_getf() == f);
 +                              } else if(rpncmd == ">=" || rpncmd == "ge") {
 +                                      f = rpn_popf();
 +                                      rpn_setf(rpn_getf() >= f);
 +                              } else if(rpncmd == "<=" || rpncmd == "le") {
 +                                      f = rpn_popf();
 +                                      rpn_setf(rpn_getf() <= f);
 +                              } else if(rpncmd == "!=" || rpncmd == "ne") {
 +                                      f = rpn_popf();
 +                                      rpn_setf(rpn_getf() != f);
 +                              } else if(rpncmd == "rand") {
 +                                      rpn_setf(ceil(random() * rpn_getf()) - 1);
 +                              } else if(rpncmd == "crc16") {
 +                                      rpn_setf(crc16(FALSE, rpn_get()));
 +                              } else if(rpncmd == "put") {
 +                                      s2 = rpn_pop();
 +                                      if (!rpn_error)
 +                                      {
 +                                              s = rpn_pop();
 +                                              if (!rpn_error)
 +                                                      db_put(rpn_db, s, s2);
 +                                      }
 +                              } else if(rpncmd == "get") {
 +                                      s = rpn_pop();
 +                                      if (!rpn_error)
 +                                              rpn_push(db_get(rpn_db, s));
 +                              } else if(rpncmd == "dbpush") {
 +                                      s = rpn_pop();
 +                                      if(!rpn_error)
 +                                      {
 +                                              i = stof(db_get(rpn_db, "stack.pointer"));
 +                                              db_put(rpn_db, "stack.pointer", ftos(i+1));
 +                                              db_put(rpn_db, strcat("stack.", ftos(i)), s);
 +                                      }
 +                                      if(!i)
 +                                              db_put(rpn_db, "stack.pos", "0");
 +                              } else if(rpncmd == "dbpop") {
 +                                      i = stof(db_get(rpn_db, "stack.pointer"));
 +                                      if(i)
 +                                      {
 +                                              s = ftos(i-1);
 +                                              db_put(rpn_db, "stack.pointer", s);
 +                                              rpn_push(db_get(rpn_db, strcat("stack.", s)));
 +                                              j = stof(db_get(rpn_db, "stack.pos"));
 +                                              if(j >= i)
 +                                                      db_put(rpn_db, "stack.pos", ftos(i-2));
 +                                      } else {
 +                                              rpn_error = 1;
 +                                              print("rpn: database underflow\n");
 +                                      }
 +                              } else if(rpncmd == "dbget") {
 +                                      
 +                                      i = stof(db_get(rpn_db, "stack.pointer"));
 +                                      if(i)
 +                                      {
 +                                              rpn_push(db_get(rpn_db, strcat("stack.", ftos(i-1))));
 +                                      } else {
 +                                              rpn_error = 1;
 +                                              print("rpn: database empty\n");
 +                                      }
 +                              } else if(rpncmd == "dblen") {
 +                                      rpn_push(db_get(rpn_db, "stack.pointer"));
 +                              } else if(rpncmd == "dbclr") {
 +                                      db_close(rpn_db);
 +                                      rpn_db = db_create();
 +                                      db_put(rpn_db, "stack.pointer", "0");
 +                                      db_put(rpn_db, "stack.pos", "-1");
 +                              } else if(rpncmd == "dbsave") {
 +                                      s = rpn_pop();
 +                                      if(!rpn_error)
 +                                              db_save(rpn_db, s);
 +                              } else if(rpncmd == "dbload") {
 +                                      s = rpn_pop();
 +                                      if(!rpn_error)
 +                                      {
 +                                              db_close(rpn_db);
 +                                              rpn_db = db_load(s);
 +                                      }
 +                              } else if(rpncmd == "dbins") {
 +                                      s = rpn_pop();
 +                                      if(!rpn_error)
 +                                              //if(rpn_sp > 0)
 +                                      {
 +                                              j = stof(db_get(rpn_db, "stack.pointer"));
 +                                              i = stof(db_get(rpn_db, "stack.pos"));
 +                                              
 +                                              if(i < 0)
 +                                              {
 +                                                      i = 0;
 +                                                      db_put(rpn_db, "stack.pos", "0");
 +                                              }
 +                                              
 +                                              db_put(rpn_db, "stack.pointer", ftos(j+1));
 +                                              for(--j; j >= i; --j)
 +                                              {
 +                                                      db_put(rpn_db, strcat("stack.", ftos(j+1)),
 +                                                             db_get(rpn_db, (strcat("stack.", ftos(j))))
 +                                                              );
 +                                              }
 +                                              db_put(rpn_db, strcat("stack.", ftos(i)), s);
 +                                      }
 +                              } else if(rpncmd == "dbext") {
 +                                      j = stof(db_get(rpn_db, "stack.pointer"));
 +                                      i = stof(db_get(rpn_db, "stack.pos"));
 +                                      if(!j)
 +                                      {
 +                                              rpn_error = TRUE;
 +                                              print("rpn: empty database\n");
 +                                      } else {
 +                                              --j;
 +                                              rpn_push(db_get(rpn_db, strcat("stack.", ftos(i))));
 +                                              db_put(rpn_db, "stack.pointer", ftos(j));
 +                                              if(i == j)
 +                                              {
 +                                                      db_put(rpn_db, "stack.pos", ftos(j-1));
 +                                              } else {
 +                                                      while(i < j)
 +                                                      {
 +                                                              db_put(rpn_db, strcat("stack.", ftos(i)),
 +                                                                     db_get(rpn_db, (strcat("stack.", ftos(i+1))))
 +                                                                      );
 +                                                              ++i;
 +                                                      }
 +                                              }
 +                                      }
 +                              } else if(rpncmd == "dbread") {
 +                                      s = db_get(rpn_db, "stack.pos");
 +                                      if(stof(s) >= 0)
 +                                      {
 +                                              rpn_push(db_get(rpn_db, strcat("stack.", s)));
 +                                      } else {
 +                                              rpn_error = 1;
 +                                              print("rpn: empty database\n");
 +                                      }
 +                              } else if(rpncmd == "dbat") {
 +                                      rpn_push(db_get(rpn_db, "stack.pos"));
 +                              } else if(rpncmd == "dbmov") {
 +                                      j = stof(db_get(rpn_db, "stack.pointer"));
 +                                      i = stof(db_get(rpn_db, "stack.pos"));
 +                                      i += rpn_popf();
 +                                      if(!rpn_error)
 +                                      {
 +                                              if(i < 0 || i >= j)
 +                                              {
 +                                                      print("rpn: database cursor out of bounds\n");
 +                                                      rpn_error = TRUE;
 +                                              }
 +                                              if(!rpn_error)
 +                                              {
 +                                                      db_put(rpn_db, "stack.pos", ftos(i));
 +                                              }
 +                                      }
 +                              } else if(rpncmd == "dbgoto") {
 +                                      s = rpn_pop();
 +                                      j = stof(db_get(rpn_db, "stack.pointer"));
 +                                      if(!j)
 +                                      {
 +                                              rpn_error = TRUE;
 +                                              print("rpn: empty database, cannot move cursor\n");
 +                                      }
 +                                      if(!rpn_error)
 +                                      {
 +                                              if(s == "end")
 +                                                      i = stof(db_get(rpn_db, "stack.pointer"))-1;
 +                                              else if(s == "beg")
 +                                                      i = 0;
 +                                              else
 +                                                      i = stof(s);
 +                                              
 +                                              j = stof(db_get(rpn_db, "stack.pointer"));
 +                                              if(i < 0 || i >= j)
 +                                              {
 +                                                      print("rpn: database cursor destination out of bounds\n");
 +                                                      rpn_error = TRUE;
 +                                              }
 +                                              if(!rpn_error)
 +                                              {
 +                                                      db_put(rpn_db, "stack.pos", ftos(i));
 +                                              }
 +                                      }
 +                              } else if(rpncmd == "union") {
 +                                      // s s2 union
 +                                      s2 = rpn_pop();
 +                                      s = rpn_get();
 +                                      f = tokenize_console(s);
 +                                      f2 = tokenize_console(strcat(s, " ", s2));
 +                                      // tokens 0..(f-1) represent s
 +                                      // tokens f..f2 represent s2
 +                                      // UNION: add all tokens to s that are in s2 but not in s
 +                                      s = "";
 +                                      for(i = 0; i < f; ++i)  
 +                                              s = strcat(s, " ", argv(i));
 +                                      for(i = f; i < f2; ++i) {
 +                                              for(j = 0; j < f; ++j)
 +                                                      if(argv(i) == argv(j))
 +                                                              goto skip_union;
 +                                              s = strcat(s, " ", argv(i));
 +:skip_union
 +                                      }
 +                                      if(substring(s, 0, 1) == " ")
 +                                              s = substring(s, 1, 99999);
 +                                      rpn_set(s);
 +                                      tokenize_console(command);
 +                              } else if(rpncmd == "intersection") {
 +                                      // s s2 intersection
 +                                      s2 = rpn_pop();
 +                                      s = rpn_get();
 +                                      f = tokenize_console(s);
 +                                      f2 = tokenize_console(strcat(s, " ", s2));
 +                                      // tokens 0..(f-1) represent s
 +                                      // tokens f..f2 represent s2
 +                                      // INTERSECTION: keep only the tokens from s that are also in s2
 +                                      s = "";
 +                                      for(i = 0; i < f; ++i) {
 +                                              for(j = f; j < f2; ++j)
 +                                                      if(argv(i) == argv(j))
 +                                                      {
 +                                                              s = strcat(s, " ", argv(i));
 +                                                              break;
 +                                                      }
 +                                      }
 +                                      if(substring(s, 0, 1) == " ")
 +                                              s = substring(s, 1, 99999);
 +                                      rpn_set(s);
 +                                      tokenize_console(command);
 +                              } else if(rpncmd == "difference") {
 +                                      // s s2 difference
 +                                      s2 = rpn_pop();
 +                                      s = rpn_get();
 +                                      f = tokenize_console(s);
 +                                      f2 = tokenize_console(strcat(s, " ", s2));
 +                                      // tokens 0..(f-1) represent s
 +                                      // tokens f..f2 represent s2
 +                                      // DIFFERENCE: keep only the tokens from s that are not in s2
 +                                      s = "";
 +                                      for(i = 0; i < f; ++i) {
 +                                              for(j = f; j < f2; ++j)
 +                                                      if(argv(i) == argv(j))
 +                                                              goto skip_difference;
 +                                              s = strcat(s, " ", argv(i));
 +:skip_difference
 +                                      }
 +                                      if(substring(s, 0, 1) == " ")
 +                                              s = substring(s, 1, 99999);
 +                                      rpn_set(s);
 +                                      tokenize_console(command);
 +                              } else if(rpncmd == "shuffle") {
 +                                      // s shuffle
 +                                      s = rpn_get();
 +                                      f = tokenize_console(s);
 +
 +                                      for(i = 0; i < f - 1; ++i) {
 +                                              // move a random item from i..f-1 to position i
 +                                              s = "";
 +                                              f2 = floor(random() * (f - i) + i);
 +                                              for(j = 0; j < i; ++j)
 +                                                      s = strcat(s, " ", argv(j));
 +                                              s = strcat(s, " ", argv(f2));
 +                                              for(j = i; j < f; ++j)
 +                                                      if(j != f2)
 +                                                              s = strcat(s, " ", argv(j));
 +                                              f = tokenize_console(s);
 +                                      }
 +
 +                                      if(substring(s, 0, 1) == " ")
 +                                              s = substring(s, 1, 99999);
 +                                      rpn_set(s);
 +                                      tokenize_console(command);
 +                              } else if(rpncmd == "fexists_assert") {
 +                                      s = rpn_pop();
 +                                      if(!rpn_error)
 +                                      {
 +                                              if (!fexists(s))
 +                                              {
 +                                                      print("rpn: ERROR: ", s, " does not exist!\n");
 +                                                      rpn_error = TRUE;
 +                                              }
 +                                      }
 +                              } else if(rpncmd == "fexists") {
 +                                      s = rpn_get();
 +                                      if(!rpn_error)
 +                                      {
 +                                              if (fexists(s))
 +                                                      rpn_setf(1);
 +                                              else
 +                                                      rpn_setf(0);
 +                                      }
 +                              } else if(rpncmd == "localtime") {
 +                                      rpn_set(strftime(TRUE, rpn_get()));
 +                              } else if(rpncmd == "gmtime") {
 +                                      rpn_set(strftime(FALSE, rpn_get()));
 +                              } else if(rpncmd == "time") {
 +                                      rpn_pushf(time);
 +                              } else if(rpncmd == "digest") {
 +                                      s = rpn_pop();
 +                                      rpn_set(digest_hex(s, rpn_get()));
 +                              } else if(rpncmd == "sprintf1s") {
 +                                      s = rpn_pop();
 +                                      rpn_set(sprintf(s, rpn_get()));
 +                              } else {
 +                                      rpn_push(cvar_string(rpncmd));
 +                              }
 +                              if(rpn_error)
 +                                      break;
 +                      }
 +                      while(rpn_sp > 0)
 +                      {
 +                              s = rpn_pop();
 +                              print("rpn: still on stack: ", s, "\n");
 +                      }
 +                      return TRUE;
 +              }
 +      } else if(argv(0) == "addtolist") {
 +              if(argc >= 2)
 +              {
 +                      s = argv(1);
 +                      s2 = argv(2);
 +                      if(cvar_string(s) == "")
 +                              cvar_set(s, s2);
 +                      else {
 +                              n = tokenizebyseparator(cvar_string(s), " ");
 +                              for(i = 0; i < n; ++i)
 +                                      if(argv(i) == s2)
 +                                              return TRUE; // already in list
 +                              cvar_set(s, strcat(s2, " ", cvar_string(s)));
 +                      }
 +              }
 +              return TRUE;
 +      }
 +      else if(argv(0) == "records") {
 +              print(records_reply);
 +              return TRUE;
 +      }
 +      else if(argv(0) == "ladder") {
 +              print(ladder_reply);
 +              return TRUE;
 +      }
 +      else if(argv(0) == "rankings") {
 +              print(rankings_reply);
 +              return TRUE;
 +#ifdef MENUQC
 +      } else if(argv(0) == "cp") {
 +              if(argc >= 2)
 +              {
 +                      s = argv(1);
 +                      for(i = 2; i < argc; ++i)
 +                              s = strcat(s, " ", argv(i));
 +                      centerprint(unescape(s));
 +              }
 +              return TRUE;
 +#endif
 +      }
++      else if(argv(0) == "settemp") {
++              cvar_settemp(argv(1), argv(2));
++              return TRUE;
++      }
++      else if(argv(0) == "settemp_restore") {
++              cvar_settemp_restore();
++              return TRUE;
++      }
 +
 +      return FALSE;
 +}
@@@ -863,45 -863,29 +863,49 @@@ void get_mi_min_max_texcoords(float mod
  }
  #endif
  
- #ifdef CSQC
- void cvar_settemp(string pKey, string pValue)
- {
-       error("cvar_settemp called from CSQC - use cvar_clientsettemp instead!");
- }
- void cvar_settemp_restore()
- {
-       error("cvar_settemp_restore called from CSQC - use cvar_clientsettemp instead!");
- }
- #else
- void cvar_settemp(string pKey, string pValue)
 -void cvar_settemp(string cv, string val)
++float cvar_settemp(string tmp_cvar, string tmp_value)
  {
-       float i;
-       string settemp_var;
-       if(cvar_string(pKey) == pValue)
-               return;
-       i = cvar("settemp_idx");
-       cvar_set("settemp_idx", ftos(i+1));
-       settemp_var = strcat("_settemp_x", ftos(i));
- #ifdef MENUQC
-       registercvar(settemp_var, "", 0);
- #else
-       registercvar(settemp_var, "");
- #endif
-       cvar_set("settemp_list", strcat("1 ", pKey, " ", settemp_var, " ", cvar_string("settemp_list")));
-       cvar_set(settemp_var, cvar_string(pKey));
-       cvar_set(pKey, pValue);
++      float created_saved_value;
+       entity e;
++      
++      if not(tmp_cvar || tmp_value)
++      {
++              dprint("Error: Invalid usage of cvar_settemp(string, string); !\n");
++              return FALSE;
++      }
++      
+       for(e = world; (e = find(e, classname, "saved_cvar_value")); )
 -              if(e.netname == cv)
 -                      goto saved;
++              if(e.netname == tmp_cvar)
++                      goto saved; // skip creation
++                      
++      // creating a new entity to keep track of this cvar
+       e = spawn();
+       e.classname = "saved_cvar_value";
 -      e.netname = strzone(cv);
 -      e.message = strzone(cvar_string(cv));
 -:saved
 -      cvar_set(cv, val);
++      e.netname = strzone(tmp_cvar);
++      e.message = strzone(cvar_string(tmp_cvar));
++      created_saved_value = TRUE;
++      
++      // an entity for this cvar already exists
++      :saved
++      
++      // update the cvar to the value given
++      cvar_set(tmp_cvar, tmp_value);
++      
++      return created_saved_value;
  }
  
--void cvar_settemp_restore()
++float cvar_settemp_restore()
  {
-       // undo what cvar_settemp did
-       float n, i;
-       n = tokenize_console(cvar_string("settemp_list"));
-       for(i = 0; i < n - 3; i += 3)
-               cvar_set(argv(i + 1), cvar_string(argv(i + 2)));
-       cvar_set("settemp_list", "0");
++      float i;
+       entity e;
+       while((e = find(world, classname, "saved_cvar_value")))
+       {
+               cvar_set(e.netname, e.message);
+               remove(e);
+       }
++      
++      return i;
  }
- #endif
  
  float almost_equals(float a, float b)
  {
@@@ -2108,53 -2092,36 +2112,75 @@@ float lowestbit(float f
        return f;
  }
  
- #ifdef CSQC
- entity ReadCSQCEntity()
- {
-       float f;
-       f = ReadShort();
-       if(f == 0)
-               return world;
-       return findfloat(world, entnum, f);
- }
- #endif
 +/*
 +string strlimitedlen(string input, string truncation, float strip_colors, float limit)
 +{
 +      if(strlen((strip_colors ? strdecolorize(input) : input)) <= limit)
 +              return input;
 +      else
 +              return strcat(substring(input, 0, (strlen(input) - strlen(truncation))), truncation);
 +}*/
 +
- #endif
 +// escape the string to make it safe for consoles
 +string MakeConsoleSafe(string input)
 +{
 +      input = strreplace("\n", "", input);
 +      input = strreplace("\\", "\\\\", input);
 +      input = strreplace("$", "$$", input);
 +      input = strreplace("\"", "\\\"", input);
 +      return input;
 +}
 +
 +#ifndef MENUQC
 +// get true/false value of a string with multiple different inputs
 +float InterpretBoolean(string input)
 +{
 +      switch(strtolower(input))
 +      {
 +              case "yes":
 +              case "true":
 +              case "on":
 +                      return TRUE;
 +              
 +              case "no":
 +              case "false":
 +              case "off":
 +                      return FALSE;
 +              
 +              default: return stof(input);
 +      }
 +}
 -
++#endif
++
+ #ifdef CSQC
+ entity ReadCSQCEntity()
+ {
+       float f;
+       f = ReadShort();
+       if(f == 0)
+               return world;
+       return findfloat(world, entnum, f);
+ }
+ #endif
 -}
+ float shutdown_running;
+ #ifdef SVQC
+ void SV_Shutdown()
+ #endif
+ #ifdef CSQC
+ void CSQC_Shutdown()
+ #endif
+ #ifdef MENUQC
+ void m_shutdown()
+ #endif
+ {
+       if(shutdown_running)
+       {
+               print("Recursive shutdown detected! Only restoring cvars...\n");
+       }
+       else
+       {
+               shutdown_running = 1;
+               Shutdown();
+       }
+       cvar_settemp_restore(); // this must be done LAST, but in any case
++}
@@@ -89,8 -90,8 +90,8 @@@ string swapInPriorityList(string order
  
  float cvar_value_issafe(string s);
  
--void cvar_settemp(string pKey, string pValue);
--void cvar_settemp_restore();
++float cvar_settemp(string pKey, string pValue);
++float cvar_settemp_restore();
  
  #ifndef MENUQC
  // modes: 0 = trust q3map2 (_mini images)
@@@ -275,6 -278,5 +278,15 @@@ float lowestbit(float f)
  entity ReadCSQCEntity()
  #endif
  
- #endif
 +#ifndef MENUQC
 +string strtolower(string s);
++#endif
++
++string MakeConsoleSafe(string input);
++
++#ifndef MENUQC
++float InterpretBoolean(string input);
++#endif
++
+ // generic shutdown handler
+ void Shutdown();
index ea2e403,0000000..6a140f4
mode 100644,000000..100644
--- /dev/null
@@@ -1,193 -1,0 +1,187 @@@
- void GameCommand_Init()
- {
-       // make gg call menu QC theCommands
-       localcmd("alias qc_cmd \"menu_cmd $*\"\n");
- }
 +string _dumptree_space;
 +void _dumptree_open(entity pass, entity me)
 +{
 +      string s;
 +      s = me.toString(me);
 +      if(s == "")
 +              s = me.classname;
 +      else
 +              s = strcat(me.classname, ": ", s);
 +      print(_dumptree_space, etos(me), " (", s, ")");
 +      if(me.firstChild)
 +      {
 +              print(" {\n");
 +              _dumptree_space = strcat(_dumptree_space, "  ");
 +      }
 +      else
 +              print("\n");
 +}
 +void _dumptree_close(entity pass, entity me)
 +{
 +      if(me.firstChild)
 +      {
 +              _dumptree_space = substring(_dumptree_space, 0, strlen(_dumptree_space) - 2);
 +              print(_dumptree_space, "}\n");
 +      }
 +}
 +
 +float curl_uri_get_pos;
 +float curl_uri_get_exec[URI_GET_CURL_END - URI_GET_CURL + 1];
 +string curl_uri_get_cvar[URI_GET_CURL_END - URI_GET_CURL + 1];
 +void Curl_URI_Get_Callback(float id, float status, string data)
 +{
 +      float i;
 +      float do_exec;
 +      string do_cvar;
 +      i = id - URI_GET_CURL;
 +      do_exec = curl_uri_get_exec[i];
 +      do_cvar = curl_uri_get_cvar[i];
 +      if(status != 0)
 +      {
 +              print(sprintf(_("error: status is %d\n"), status));
 +              if(do_cvar)
 +                      strunzone(do_cvar);
 +              return;
 +      }
 +      if(do_exec)
 +              localcmd(data);
 +      if(do_cvar)
 +      {
 +              cvar_set(do_cvar, data);
 +              strunzone(do_cvar);
 +      }
 +      if(!do_exec && !do_cvar)
 +              print(data);
 +}
 +
 +void GameCommand(string theCommand)
 +{
 +      float argc;
 +      argc = tokenize_console(theCommand);
 +
 +      if(argv(0) == "help" || argc == 0)
 +      {
 +              print(_("Usage: menu_cmd command..., where possible commands are:\n"));
 +              print(_("  sync - reloads all cvars on the current menu page\n"));
 +              print(_("  directmenu ITEM - select a menu item as main item\n"));
 +              GameCommand_Generic("help");
 +              return;
 +      }
 +
 +      if(GameCommand_Generic(theCommand))
 +              return;
 +
 +      if(argv(0) == "sync")
 +      {
 +              m_sync();
 +              return;
 +      }
 +
 +      if(argv(0) == "directmenu") if(argc == 2)
 +      {
 +              // switch to a menu item
 +              if(!isdemo()) // don't allow this command in demos
 +                      m_goto(argv(1));
 +              return;
 +      }
 +
 +      if(argv(0) == "directpanelhudmenu")
 +      {
 +              // switch to a menu item
 +              m_goto(strcat("HUD", argv(1)));
 +              return;
 +      }
 +
 +      if(argv(0) == "skinselect")
 +      {
 +              m_goto_skin_selector();
 +              return;
 +      }
 +
 +      if(argv(0) == "languageselect")
 +      {
 +              m_goto_language_selector();
 +              return;
 +      }
 +
 +      if(argv(0) == "videosettings")
 +      {
 +              m_goto_video_settings();
 +              return;
 +      }
 +
 +      if(argv(0) == "dumptree")
 +      {
 +              _dumptree_space = "";
 +              depthfirst(main, parent, firstChild, nextSibling, _dumptree_open, _dumptree_close, NULL);
 +              return;
 +      }
 +
 +      if(argv(0) == "curl")
 +      {
 +              float do_exec;
 +              string do_cvar;
 +              float key;
 +              float i, j;
 +              string url;
 +              float buf;
 +              float r;
 +
 +              do_exec = FALSE;
 +              do_cvar = string_null;
 +              key = -1;
 +
 +              for(i = 1; i+1 < argc; ++i)
 +              {
 +                      if(argv(i) == "--cvar" && i+2 < argc)
 +                      {
 +                              ++i;
 +                              do_cvar = strzone(argv(i));
 +                              continue;
 +                      }
 +                      if(argv(i) == "--exec")
 +                      {
 +                              do_exec = TRUE;
 +                              continue;
 +                      }
 +                      if(argv(i) == "--key" && i+2 < argc)
 +                      {
 +                              ++i;
 +                              key = stof(argv(i));
 +                              continue;
 +                      }
 +                      break;
 +              }
 +
 +              // now, argv(i) is the URL
 +              // following args may be POST parameters
 +              url = argv(i);
 +              ++i;
 +              buf = buf_create();
 +              j = 0;
 +              for(; i+1 < argc; i += 2)
 +                      bufstr_set(buf, ++j, sprintf("%s=%s", uri_escape(argv(i)), uri_escape(argv(i+1))));
 +              if(i < argc)
 +                      bufstr_set(buf, ++j, sprintf("submit=%s", uri_escape(argv(i))));
 +
 +              if(j == 0) // no args: GET
 +                      r = crypto_uri_postbuf(url, URI_GET_CURL + curl_uri_get_pos, string_null, string_null, -1, key);
 +              else // with args: POST
 +                      r = crypto_uri_postbuf(url, URI_GET_CURL + curl_uri_get_pos, "application/x-www-form-urlencoded", "&", buf, key);
 +
 +              if(r)
 +              {
 +                      curl_uri_get_exec[curl_uri_get_pos] = do_exec;
 +                      curl_uri_get_cvar[curl_uri_get_pos] = do_cvar;
 +                      curl_uri_get_pos = mod(curl_uri_get_pos + 1, URI_GET_CURL_END - URI_GET_CURL + 1);
 +              }
 +              else
 +                      print(_("error creating curl handle\n"));
 +
 +              buf_del(buf);
 +
 +              return;
 +      }
 +
 +      print(_("Invalid command. For a list of supported commands, try menu_cmd help.\n"));
 +}
index 33eb053,0000000..7a18fe2
mode 100644,000000..100644
--- /dev/null
@@@ -1,2 -1,0 +1,1 @@@
- void GameCommand_Init();
 +void GameCommand(string command);
Simple merge
Simple merge
@@@ -36,15 -34,7 +36,14 @@@ vehicles/vehicles_def.q
  campaign.qh
  ../common/campaign_common.qh
  ../common/mapinfo.qh
- ../common/util.qc
  
 +command/common.qh
 +command/ipban.qh
 +command/radarmap.qh
 +command/vote.qh
 +command/cmd.qh
 +command/sv_cmd.qh
 +
  accuracy.qh
  csqcprojectile.qh
  ../common/csqcmodel_settings.qh