]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote branch 'origin/master' into samual/updatecommands
authorSamual <samual@xonotic.org>
Fri, 30 Dec 2011 15:39:48 +0000 (10:39 -0500)
committerSamual <samual@xonotic.org>
Fri, 30 Dec 2011 15:39:48 +0000 (10:39 -0500)
56 files changed:
commands.cfg [new file with mode: 0644]
defaultXonotic.cfg
qcsrc/client/Main.qc
qcsrc/client/command/cl_cmd.qc [new file with mode: 0644]
qcsrc/client/command/cl_cmd.qh [new file with mode: 0644]
qcsrc/client/mapvoting.qc
qcsrc/client/progs.src
qcsrc/client/scoreboard.qc
qcsrc/common/command/generic.qc [new file with mode: 0644]
qcsrc/common/command/generic.qh [new file with mode: 0644]
qcsrc/common/command/markup.qc [new file with mode: 0644]
qcsrc/common/command/markup.qh [new file with mode: 0644]
qcsrc/common/command/rpn.qc [new file with mode: 0644]
qcsrc/common/command/rpn.qh [new file with mode: 0644]
qcsrc/common/command/shared_defs.qh [new file with mode: 0644]
qcsrc/common/gamecommand.qc [deleted file]
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/dpdefs/menudefs.qc
qcsrc/menu/command/menu_cmd.qc [new file with mode: 0644]
qcsrc/menu/command/menu_cmd.qh [new file with mode: 0644]
qcsrc/menu/gamecommand.qc [deleted file]
qcsrc/menu/gamecommand.qh [deleted file]
qcsrc/menu/progs.src
qcsrc/menu/xonotic/dialog_quit.c
qcsrc/server/assault.qc
qcsrc/server/autocvars.qh
qcsrc/server/bot/scripting.qc
qcsrc/server/cl_client.qc
qcsrc/server/cl_impulse.qc
qcsrc/server/cl_player.qc
qcsrc/server/cl_weaponsystem.qc
qcsrc/server/clientcommands.qc [deleted file]
qcsrc/server/command/banning.qc [new file with mode: 0644]
qcsrc/server/command/banning.qh [new file with mode: 0644]
qcsrc/server/command/cmd.qc [new file with mode: 0644]
qcsrc/server/command/cmd.qh [new file with mode: 0644]
qcsrc/server/command/common.qc [new file with mode: 0644]
qcsrc/server/command/common.qh [new file with mode: 0644]
qcsrc/server/command/radarmap.qc [new file with mode: 0644]
qcsrc/server/command/radarmap.qh [new file with mode: 0644]
qcsrc/server/command/sv_cmd.qc [new file with mode: 0644]
qcsrc/server/command/sv_cmd.qh [new file with mode: 0644]
qcsrc/server/command/vote.qc [new file with mode: 0644]
qcsrc/server/command/vote.qh [new file with mode: 0644]
qcsrc/server/defs.qh
qcsrc/server/g_hook.qc
qcsrc/server/g_world.qc
qcsrc/server/gamecommand.qc [deleted file]
qcsrc/server/ipban.qc
qcsrc/server/ipban.qh
qcsrc/server/miscfunctions.qc
qcsrc/server/progs.src
qcsrc/server/sv_main.qc
qcsrc/server/vote.qc [deleted file]
qcsrc/server/vote.qh [deleted file]

diff --git a/commands.cfg b/commands.cfg
new file mode 100644 (file)
index 0000000..c4e2283
--- /dev/null
@@ -0,0 +1,281 @@
+// =================================================================
+//  Master config for managing various command aliases and settings
+// =================================================================
+
+// 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_dedicated "alias" qc_cmd_sv     "sv_cmd $$*"
+if_client    "alias" qc_cmd_cl     "cl_cmd $$*"
+if_client    "alias" qc_cmd_cmd    "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
+// ========
+// networked/server common commands
+alias cvar_changes         "qc_cmd_svcmd  cvar_changes         ${* ?}" // Prints a list of all changed server cvars
+alias cvar_purechanges     "qc_cmd_svcmd  cvar_purechanges     ${* ?}" // Prints a list of all changed gameplay cvars
+alias info                 "qc_cmd_svcmd  info                 ${* ?}" // Request for unique server information set up by admin
+alias ladder               "qc_cmd_svcmd  ladder               ${* ?}" // Get information about top players if supported
+alias lsmaps               "qc_cmd_svcmd  lsmaps               ${* ?}" // List maps which can be used with the current game mode
+alias lsnewmaps            "qc_cmd_svcmd  lsnewmaps            ${* ?}" // List maps which have no records or are seemingly unplayed yet
+alias maplist              "qc_cmd_svcmd  maplist              ${* ?}" // Display full server maplist reply
+alias rankings             "qc_cmd_svcmd  rankings             ${* ?}" // Print information about rankings
+alias records              "qc_cmd_svcmd  records              ${* ?}" // List top 10 records for the current map
+alias teamstatus           "qc_cmd_svcmd  teamstatus           ${* ?}" // Show information about player and team scores
+alias time                 "qc_cmd_svcmd  time                 ${* ?}" // Print different formats/readouts of time
+alias timein               "qc_cmd_svcmd  timein               ${* ?}" // Resume the game from being paused with a timeout
+alias timeout              "qc_cmd_svcmd  timeout              ${* ?}" // Call a timeout which pauses the game for certain amount of time unless unpaused
+alias vote                 "qc_cmd_svcmd  vote                 ${* ?}" // Request an action to be voted upon by players
+alias who                  "qc_cmd_svcmd  who                  ${* ?}" // Display detailed client information about all players
+
+// generic commands (across all programs)
+alias addtolist            "qc_cmd_svmenu addtolist            ${* ?}" // Add a string to a cvar
+alias dumpcommands         "qc_cmd_svmenu dumpcommands         ${* ?}" // Dump all commands on the program to *_cmd_dump.txt
+alias maplist              "qc_cmd_svmenu maplist              ${* ?}" // Automatic control of maplist
+alias removefromlist       "qc_cmd_svmenu removefromlist       ${* ?}" // Remove a string from a cvar
+alias rpn                  "qc_cmd_svmenu rpn                  ${* ?}" // RPN calculator
+//alias settemp            "qc_cmd_svmenu settemp              ${* ?}" // Temporarily set a value to a cvar which is restored later
+//alias settemp_restore    "qc_cmd_svmenu settemp_restore      ${* ?}" // Restore all cvars set by settemp command
+
+// other aliases for common commands
+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 search "apropos ${* ?}"
+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
+alias blurtest             "qc_cmd_cl     blurtest             ${* ?}" // Feature for testing blur postprocessing
+alias debugmodel           "qc_cmd_cl     debugmodel           ${* ?}" // Spawn a debug model manually
+//alias handlevote         "qc_cmd_cl     handlevote           ${* ?}" // System to handle selecting a vote or option
+alias hud                  "qc_cmd_cl     hud                  ${* ?}" // Commands regarding/controlling the HUD system
+alias localprint           "qc_cmd_cl     localprint           ${* ?}" // Create your own centerprint sent to yourself
+//alias mv_download        "qc_cmd_cl     mv_download          ${* ?}" // Retrieve mapshot picture from the server
+alias sendcvar             "qc_cmd_cl     sendcvar             ${* ?}" // Send a cvar to the server (like weaponpriority)
+
+// other aliases for local commands
+alias hud_configure "qc_cmd_cl hud configure"
+alias hud_save "qc_cmd_cl hud save ${* ?}"
+alias radar "qc_cmd_cl hud radar ${* ?}"
+alias scoreboard_columns_help "qc_cmd_cl hud scoreboard_columns_help"
+alias scoreboard_columns_set "qc_cmd_cl 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           "qc_cmd_cmd    autoswitch           ${* ?}" // Whether or not to switch automatically when getting a better weapon
+alias checkfail            "qc_cmd_cmd    checkfail            ${* ?}" // Report if a client-side check failed
+alias clientversion        "qc_cmd_cmd    clientversion        ${* ?}" // Release version of the game
+//alias getmapvotepic      "qc_cmd_cmd    getmapvotepic        ${* ?}" // Retrieve mapshot picture from the server
+alias join                 "qc_cmd_cmd    join                 ${* ?}" // Become a player in the game
+alias ready                "qc_cmd_cmd    ready                ${* ?}" // Qualify as ready to end warmup stage (or restart server if allowed)
+alias reportcvar           "qc_cmd_cmd    reportcvar           ${* ?}" // Old system for sending a client cvar to the server
+//alias say                "qc_cmd_cmd    say                  ${* ?}" // Print a message to chat to all players
+//alias say_team           "qc_cmd_cmd    say_team             ${* ?}" // Print a message to chat to all team mates
+alias selectteam           "qc_cmd_cmd    selectteam           ${* ?}" // Attempt to choose a team to join into
+alias selfstuff            "qc_cmd_cmd    selfstuff            ${* ?}" // Stuffcmd a command to your own client
+alias sentcvar             "qc_cmd_cmd    sentcvar             ${* ?}" // New system for sending a client cvar to the server
+alias spectate             "qc_cmd_cmd    spectate             ${* ?}" // Become an observer
+alias suggestmap           "qc_cmd_cmd    suggestmap           ${* ?}" // Suggest a map to the mapvote at match end
+//alias tell               "qc_cmd_cmd    tell                 ${* ?}" // Send a message directly to a player
+alias voice                "qc_cmd_cmd    voice                ${* ?}" // Send voice message via sound
+
+// 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             "qc_cmd_sv     adminmsg             ${* ?}" // Send an admin message to a client directly
+alias allready             "qc_cmd_sv     allready             ${* ?}" // Restart the server and reset the players
+alias allspec              "qc_cmd_sv     allspec              ${* ?}" // Force all players to spectate
+alias anticheat            "qc_cmd_sv     anticheat            ${* ?}" // Create an anticheat report for a client
+alias bbox                 "qc_cmd_sv     bbox                 ${* ?}" // Print detailed information about world size
+alias bot_cmd              "qc_cmd_sv     bot_cmd              ${* ?}" // Control and send commands to bots
+alias cointoss             "qc_cmd_sv     cointoss             ${* ?}" // Flip a virtual coin and give random result
+alias database             "qc_cmd_sv     database             ${* ?}" // Extra controls of the serverprogs database
+alias defer_clear          "qc_cmd_sv     defer_clear          ${* ?}" // Clear all queued defer commands for a specific client
+alias defer_clear_all      "qc_cmd_sv     defer_clear_all      ${* ?}" // Clear all queued defer commands for all clients
+alias delrec               "qc_cmd_sv     delrec               ${* ?}" // Delete race time record for a map
+alias effectindexdump      "qc_cmd_sv     effectindexdump      ${* ?}" // Dump list of effects from code and effectinfo.txt
+alias extendmatchtime      "qc_cmd_sv     extendmatchtime      ${* ?}" // Increase the timelimit value incrementally
+alias find                 "qc_cmd_sv     find                 ${* ?}" // Search through entities for matching classname
+alias gametype             "qc_cmd_sv     gametype             ${* ?}" // Simple command to change the active gametype
+alias gettaginfo           "qc_cmd_sv     gettaginfo           ${* ?}" // Get specific information about a weapon model
+alias gotomap              "qc_cmd_sv     gotomap              ${* ?}" // Simple command to switch to another map
+alias lockteams            "qc_cmd_sv     lockteams            ${* ?}" // Disable the ability for players to switch or enter teams
+alias make_mapinfo         "qc_cmd_sv     make_mapinfo         ${* ?}" // Automatically rebuild mapinfo files
+alias moveplayer           "qc_cmd_sv     moveplayer           ${* ?}" // Change the team/status of a player
+alias nospectators         "qc_cmd_sv     nospectators         ${* ?}" // Automatically remove spectators from a match
+alias playerdemo           "qc_cmd_sv     playerdemo           ${* ?}" // Control the ability to save demos of players
+alias printstats           "qc_cmd_sv     printstats           ${* ?}" // Dump eventlog player stats and other score information
+alias radarmap             "qc_cmd_sv     radarmap             ${* ?}" // Generate a radar image of the map
+alias reducematchtime      "qc_cmd_sv     reducematchtime      ${* ?}" // Decrease the timelimit value incrementally
+alias setbots              "qc_cmd_sv     setbots              ${* ?}" // Adjust how many bots are in the match
+alias shuffleteams         "qc_cmd_sv     shuffleteams         ${* ?}" // Randomly move players to different teams
+alias stuffto              "qc_cmd_sv     stuffto              ${* ?}" // Send a command to be executed on a client
+alias trace                "qc_cmd_sv     trace                ${* ?}" // Various debugging tools with tracing
+alias unlockteams          "qc_cmd_sv     unlockteams          ${* ?}" // Enable the ability for players to switch or enter teams
+alias warp                 "qc_cmd_sv     warp                 ${* ?}" // Choose different level in campaign
+
+// 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.\""
+
index 46f9066525785481ff4f6057e12001c8a0c62bba..a1d2520257a36c634660de03157b39c020c30f39 100644 (file)
@@ -22,32 +22,9 @@ gameversion_max 65535 // git builds see all versions
 //   gameversion_min = (gameversion / 100) * 100 - 100
 //   gameversion_max = (gameversion / 100) * 100 + 199
 
-// changes a cvar and reports it to the server (for the menu to notify the
-// server about changes)
-alias setreport "set \"$1\" \"$2\" ; sendcvar \"$1\""
-
 seta cl_firststart "" "how many times the client has been run"
 seta cl_startcount 0 "how many times the client has been run"
 
-// detect dedicated server or 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_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 $$*"
-
-// shorthand for the most usual case
-alias qc_cmd "qc_cmd_svmenu $*"
-
 seta g_configversion 0 "Configuration file version (used to upgrade settings) 0: first run, or previous start was <2.4.1  Later, it's overridden by config.cfg, version ranges are defined in config_update.cfg"
 
 // say aliases
@@ -63,39 +40,15 @@ alias asay_drop "say_team (%l) dropped %w ; impulse 17"
 alias +hook +button6
 alias -hook -button6
 alias use "impulse 21"
-alias ready "cmd ready"
-alias lockteams "sv_cmd lockteams"
-alias unlockteams "sv_cmd unlockteams"
-alias nospectators "sv_cmd nospectators"
-alias cointoss "sv_cmd cointoss"
-alias timeout "cmd timeout" //use this command to call a timeout
-alias timein "cmd timein" //use this command to resume the game before timeout is finished
-
-alias bsp "ls maps/*.bsp"
-alias chmap "changelevel $*"
-alias gotomap "sv_cmd gotomap \"$1\""
-
-alias rec "record demos/$1"
-alias ply "playdemo $1"
-alias tdem "timedemo $1"
+
+// for backwards compatibility
 
 alias dropweapon "impulse 17"
 alias +show_info +button7
 alias -show_info -button7
 
-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"
 bind f6 team_auto
 
-alias movetoteam_red "sv_cmd movetoteam $1 red"
-alias movetoteam_blue "sv_cmd movetoteam $1 blue"
-alias movetoteam_pink "sv_cmd movetoteam $1 pink"
-alias movetoteam_yellow "sv_cmd movetoteam $1 yellow"
-alias movetoteam_auto "sv_cmd movetoteam $1 auto"
-
 // merge lightmaps up to 2048x2048 textures
 mod_q3bsp_lightmapmergepower 4
 
@@ -340,11 +293,12 @@ set teamplay_lockonrestart 0 "it set to 1 in a team-based game, the teams are lo
 set g_maxplayers 0     "maximum number of players allowed to play at the same time, set to 0 to allow all players to join the game"
 set g_maxplayers_spectator_blocktime 5 "if the players voted for the \"nospectators\" command, this setting defines the number of seconds a observer/spectator has time to join the game before he gets kicked"
 
-//tournament mod
+// tournament mod
 set g_warmup 0 "split the game into a warmup- and match-stage when set to 1"
 set g_warmup_limit 0   "if set to -1 the warmup-stage is not affected by any timelimit, if set to 0 the usual timelimit also affects warmup-stage, otherwise warmup will be limited to this time in SECONDS (useful for public matches)"
 set g_warmup_allow_timeout 0   "if set to 1 timeouts can also be called in the warmup-stage, when sv_timeout is set to 1"
 set g_warmup_allguns 1 "if set players start with all guns in warmup mode"
+set g_warmup_majority_factor 0.8 "minimum percentage of players ready needed for warmup to end"
 
 set g_chat_nospectators 0      "if 0 spec/observer chat is always visible to the player, if 1 it is never visible to players, if 2 it is only visible to players during warmup stage"
 set sv_vote_nospectators 0     "if set only players can call a vote (thus spectators and observers can't call a vote)"
@@ -425,9 +379,6 @@ cl_movement 1
 cl_movement_track_canjump 0
 cl_stairsmoothspeed 200
 
-seta cl_autoswitch 1 "automatically switch to newly picked up weapons if they are better than what you are carrying"
-alias autoswitch "set cl_autoswitch $1 ; cmd autoswitch $1"
-
 set bot_config_file bots.txt "Name and path of the bot configuration file"
 set bot_number 0       "Minimum number of bots"
 seta bot_usemodelnames 0       "Use player model names for bot names"
@@ -580,7 +531,6 @@ seta menu_sandbox_edit_physics 1
 seta menu_sandbox_edit_force 1
 seta menu_sandbox_edit_material ""
 
-alias menu_showsandboxtools "menu_cmd directmenu SandboxTools"
 bind f7 menu_showsandboxtools
 
 set g_playerclip_collisions 1 "0 = disable collision testing against playerclips, might be useful on some defrag maps"
@@ -588,8 +538,6 @@ set g_botclip_collisions 1 "0 = disable collision testing against botclips, migh
 
 set welcome_message_time 8
 
-alias clearmap "disconnect"
-
 set g_grappling_hook 0 "let players spawn with the grappling hook which allows them to pull themselves up"
 
 set g_invincible_projectiles 0 "set to 1 to disable any damage to projectiles in all balance configs, regardless of g_projectiles_damage"
@@ -1004,8 +952,6 @@ seta cl_notify_carried_items "3" "notify you of carried items when you obtain th
 set serverconfig server.cfg
 set _sv_init 0
 alias startmap_dm "set _sv_init 0; map _init/_init; exec $serverconfig; set _sv_init 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"
 
 // aliases:
 alias +fire +attack
@@ -1035,8 +981,6 @@ alias togglezoom "${_togglezoom}zoom"
 
 alias reload "impulse 20"
 
-alias sandbox "cmd g_sandbox $*"
-
 // movement
 bind w +forward
 bind a +moveleft
@@ -1099,7 +1043,7 @@ bind u "+con_chat_maximize"
 bind m +hud_panel_radar_maximized
 bind i +show_info
 bind PAUSE pause
-bind F10 quit
+bind F10 menu_showquitdialog
 bind F11 disconnect
 bind F12 screenshot
 bind F4 ready
@@ -1153,51 +1097,10 @@ bind kp_enter "+userbind 16"
 bind kp_plus "+userbind 17"
 bind kp_minus "+userbind 18"
 
-set sv_vote_commands "restart fraglimit chmap gotomap nextmap endmatch reducematchtime extendmatchtime allready kick cointoss movetoteam_auto" "these commands can be voted"
-set sv_vote_only_commands ""
-set sv_vote_master_commands "movetoteam_red movetoteam_blue movetoteam_yellow movetoteam_pink" "maybe add kickban here (but then sv_vote_master 0)"
-set rcon_restricted_commands "restart fraglimit chmap gotomap endmatch reducematchtime extendmatchtime allready kick kickban \"sv_cmd bans\" \"sv_cmd unban *\" status \"sv_cmd teamstatus\" movetoteam_auto movetoteam_red movetoteam_blue movetoteam_yellow movetoteam_pink"
-set sv_vote_call 1     "users can call a vote for the above commands"
-set sv_vote_master 1   "users can call a vote to become master"
-set sv_vote_master_password "" "when set, users can use \"vlogin PASSWORD\" to log in as master"
-set sv_vote_change 1   "set to 1 to allow to change you vote/mind"
-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        "which quotient of the PLAYERS constitute a majority? (try: 0.666, 0.75 when using the above)"
-set sv_vote_simple_majority_factor 0.666       "which quotient of the VOTERS constitute a majority too? (0 = off, otherwise it must be higher than or equal to sv_vote_majority_factor)"
-// 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 vyes"
-alias vno "cl_cmd vno"
-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"
-
-alias lsmaps "cmd lsmaps" // lists all maps on server (for vmap, suggestmap, vnextmap)
-alias lsnewmaps "cmd lsnewmaps" // lists all maps on server that do not yet have a record set (race/cts)
 bind F1 vyes
 bind F2 vno
 
 //used for spectate/observer mode
-alias spec "cmd spectate"
 bind F3 spec
 
 // NIX (No Items Xonotic) - at each time, everyone uses the same weapon,
@@ -1232,20 +1135,18 @@ set g_campaign 0
 set g_campaign_forceteam 0 "Forces the player to a given team in campaign mode, 1 = red, 2 = blue, 3 = yellow, 4 = pink"
 seta g_campaign_name "xonoticbeta"
 set g_campaign_skill 0
-alias warp "sv_cmd warp $*"
 
 alias singleplayer_start "g_campaign_index 0; set scmenu_campaign_goto 0"
 alias singleplayer_continue "set scmenu_campaign_goto -1"
 alias singleplayer_levellist "set scmenu_campaign_dump 1; togglemenu; wait; togglemenu"
 
-// Green's fullbright skins
-alias cl_fbskin_green "playermodel models/player/erebus.iqm; playerskin 1; color 3 3"
-alias cl_fbskin_red "playermodel models/player/erebus.iqm; playerskin 1; color 4 4"
-alias cl_fbskin_orange "playermodel models/player/erebus.iqm; playerskin 1; color 14 14"
-alias cl_fbskin_off "playermodel models/player/erebus.iqm; playerskin 0"
+// Green's fullbright skins, updated by Samual
+alias sv_fbskin_unique "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors \"\""
 alias sv_fbskin_green "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors 51"
 alias sv_fbskin_red "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors 68"
 alias sv_fbskin_orange "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors 238"
+alias sv_fbskin_rainbow "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors 95"
+
 alias sv_fbskin_off "sv_defaultcharacter 0; sv_defaultplayerskin 0; sv_defaultplayercolors \"\""
 
 seta sv_servermodelsonly 1
@@ -1267,7 +1168,6 @@ seta g_maplist_votable_suggestions_override_mostrecent 0
 seta g_maplist_votable_nodetail 1      "nodetail only shows total count instead of all vote counts per map, so votes don't influence others that much"
 seta g_maplist_votable_abstain 0       "when 1, you can abstain from your vote"
 seta g_maplist_votable_screenshot_dir "maps levelshots"        "where to look for map screenshots"
-alias suggestmap "cmd suggestmap $1"
 
 set g_chat_flood_spl 3 "normal chat: seconds between lines to not count as flooding"
 set g_chat_flood_lmax 2        "normal chat: maximum number of lines per chat message at once"
@@ -1332,20 +1232,6 @@ seta cl_hidewaypoints 0 "disable static waypoints, only show team waypoints"
 seta g_waypointsprites_turrets 1 "disable turret waypoints"
 seta g_waypointsprites_turrets_maxdist 4000 "max distace for turret sprites"
 
-// command extension
-alias adminmsg "sv_cmd adminmsg $*"
-alias teamstatus       "cmd teamstatus; sv_cmd teamstatus" // yes, it is broken on listen servers that way, but well, who cares :P
-alias printstats       "sv_cmd printstats" // print status on demand
-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 gametype "sv_cmd gametype $*"
-
-alias addfav "qc_cmd addtolist net_slist_favorites $*"
-alias addvote "qc_cmd addtolist sv_vote_commands $*"
-
 // key hunt
 set g_keyhunt 0 "Key Hunt: collect all keys from the enemies and bring them together to score"
 set g_balance_keyhunt_delay_return 60
@@ -1398,17 +1284,9 @@ set g_ban_default_bantime 5400   "90 minutes"
 set g_ban_default_masksize 3   "masksize 0 means banning by UID only, 1 means banning by /8 (IPv6: /32) network, 2 means banning by /16 (IPv6: /48) network, 3 means banning by /24 (IPv6: /56) network, 4 means banning by single IP (IPv6: /64 network)"
 set g_banned_list ""   "format: IP remainingtime IP remainingtime ..."
 set g_banned_list_idmode "1"   "when set, the IP banning system always uses the ID over the IP address (so a user in a banned IP range can connect if they have a valid signed ID)"
-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)
 
 r_labelsprites_scale 0.40625 // labels sprites get displayed at 0.5x from 640x480 to 1280x1024, and at 1x from 1600x1200 onwards
 
-// settemp subsystem. 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"
-
 // usercommands. These can be edited and bound by the menu.
 seta "userbind1_press" "say_team quad soon";  seta "userbind1_release" "";  seta "userbind1_description" "team: quad soon"
 seta "userbind2_press" "say_team free item %x^7 (l:%y^7); g_waypointsprite_team_here_p";  seta "userbind2_release" "";  seta "userbind2_description" "team: free item, icon"
@@ -1511,19 +1389,11 @@ set menu_weaponarena_with_laser 0 "also enable the Laser in this weapon arena"
 
 seta menu_maxplayers 16 "maxplayers value when the menu starts a game"
 
-// 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"
-
 // useful vote aliases
 set timelimit_increment 5
 set timelimit_decrement 5
 set timelimit_min 5
 set timelimit_max 60
-alias extendmatchtime "sv_cmd extendmatchtime"
-alias reducematchtime "sv_cmd reducematchtime"
-alias endmatch "timelimit -1"
 
 // useful keybind to maximize the chat area temporarily
 // HUD code takes care of many of these now...
@@ -1638,8 +1508,6 @@ sv_allowdownloads 0 // download protocol is evil
 
 set g_jump_grunt 0     "Do you make a grunting noise every time you jump? Is it the same grunting noise every time?"
 
-alias allready "sv_cmd allready"
-
 seta cl_weaponpriority "minstanex nex fireball grenadelauncher uzi hagar rifle electro rocketlauncher crylink minelayer shotgun hlac tuba laser porto seeker hook" "weapon priority list"
 seta cl_weaponpriority_useforcycling 0 "when set, weapon cycling by the mouse wheel makes use of the weapon priority list (the special value 2 uses the weapon ID list for cycling)"
 seta cl_weaponpriority0 "rocketlauncher grenadelauncher hagar seeker fireball" "use impulse 200 for prev gun from this list, 210 for best gun, 220 for next gun.  Default value: explosives"
@@ -1654,18 +1522,9 @@ seta cl_weaponpriority8 "" "use impulse 208 for prev gun from this list, 218 for
 seta cl_weaponpriority9 "" "use impulse 209 for prev gun from this list, 219 for best gun, 229 for next gun"
 seta cl_weaponimpulsemode 0 "0: only cycle between currently usable weapons in weapon priority order; 1: cycle between all possible weapons on a key in weapon priority order"
 
-seta sv_status_privacy 1       "hide IP addresses from \"status\" replies shown to clients"
-
 set g_maplist_allow_hidden 0           "allow hidden maps to be, e.g., voted for and in the maplist"
 set g_maplist_allow_frustrating 0      "allow impossible maps to be, e.g., voted for and in the maplist (if set to 2, ONLY impossible maps are allowed)"
 
-if_client set g_start_delay 0  "delay before the game starts, so everyone can join; recommended to set this to like 15 on a public server"
-if_dedicated set g_start_delay 15      "delay before the game starts, so everyone can join; recommended to set this to like 15 on a public server"
-
-alias radar "cl_cmd hud_panel_radar_maximized"
-alias scoreboard_columns_set  "" // aliased later
-alias scoreboard_columns_help "cl_cmd scoreboard_columns_help $*"
-
 alias _gl_flashblend_update_00 "gl_flashblend 1"
 alias _gl_flashblend_update_10 "gl_flashblend 0"
 alias _gl_flashblend_update_01 "gl_flashblend 0"
@@ -1682,9 +1541,6 @@ seta cl_autoscreenshot 0 "client option to automatically take a screenshot once
 
 // must be at the bottom of this file:
 // alias for switching the teamselect menu
-alias menu_showteamselect "menu_cmd directmenu TeamSelect"
-alias menu_showhudexit "menu_cmd directmenu HUDExit"
-alias menu_showhudoptions "menu_cmd directpanelhudmenu $*"
 bind f5 menu_showteamselect
 
 set g_bugrigs 0
@@ -1717,10 +1573,6 @@ set g_ban_sync_trusted_servers_verify 0  "when set to 1, additional bans sent by
 
 set g_showweaponspawns 1       "display sprites for weapon spawns found on the map when a weapon key is pressed and the weapon is not available"
 
-alias records "cmd records"
-alias rankings "cmd rankings"
-alias ladder "cmd ladder"
-
 // ballistics use physical units, but qu based
 //   Quake-Newton: 1 qN  = 1 qu * 1 g / 1 s^2
 //   Quake-Joule:  1 qJ  = 1 qN * 1 qu
@@ -1797,13 +1649,6 @@ set cl_effects_lightningarc_branchfactor_add 0.1
 
 set g_hitplots 0 "when set to 1, hitplots are stored by the server to provide a means of proving that a triggerbot was used"
 seta g_hitplots_individuals "" "the individuals, by IP, that should have their hitplots recorded"
-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 mute "prvm_edictset server $1 muted 1" // I am lazy and not making an actual command of this
-alias unmute "prvm_edictset server $1 muted 0" // dito
-
-rcon_secure 1
 
 set menu_updatecheck 1
 
@@ -2140,6 +1985,9 @@ exec physicsX.cfg
 exec turrets.cfg
 exec vehicles.cfg
 
+// load console command aliases and settings
+exec commands.cfg
+
 // hud cvar descriptions and common settings
 exec _hud_common.cfg
 exec _hud_descriptions.cfg
@@ -2147,6 +1995,12 @@ exec _hud_descriptions.cfg
 // please add any new cvars into the hud_save script in qcsrc/client/hud_config.qc for consistency
 exec hud_luminos.cfg
 
+
+// ... and now that everything is configured/aliased, we can do some things: 
+
+// Change g_start_delay based upon if the server is local or not.
+if_client set g_start_delay 0  "delay before the game starts, so everyone can join; recommended to set this to like 15 on a public server"
+if_dedicated set g_start_delay 15      "delay before the game starts, so everyone can join; recommended to set this to like 15 on a public server"
+
 // enable menu syncing
 alias menu_sync "menu_cmd sync"
-alias scoreboard_columns_set  "cl_cmd scoreboard_columns_set $*"
index fd8afe117c49d2354e0768f3406eabd67b49fdf0..3798edf8a78ca20cb03853a05ccd57b6c614b926 100644 (file)
@@ -3,7 +3,6 @@
 //include "main.qh"
 
 #define DP_CSQC_ENTITY_REMOVE_IS_B0RKED
-
 void menu_show_error()
 {
        drawstring('0 200 0', _("ERROR - MENU IS VISIBLE BUT NO MENU WAS DEFINED!"), '8 8 0', '1 0 0', 1, 0);
@@ -71,6 +70,7 @@ void precache_all_playermodels(string pattern)
 
 string forcefog;
 void WaypointSprite_Load();
+void ConsoleCommand_macro_init();
 void CSQC_Init(void)
 {
        prvm_language = cvar_string("prvm_language");
@@ -115,28 +115,12 @@ void CSQC_Init(void)
                        break;
        maxclients = i;
 
-       registercommand("hud_configure");
-       registercommand("hud_save");
+       //registercommand("hud_configure");
+       //registercommand("hud_save");
        //registercommand("menu_action");
+       
+       ConsoleCommand_macro_init();
 
-       registercommand("+showscores");registercommand("-showscores");
-       registercommand("+showaccuracy");registercommand("-showaccuracy");
-
-#ifndef CAMERATEST
-       if(isdemo())
-       {
-#endif
-               registercommand("+forward");registercommand("-forward");
-               registercommand("+back");registercommand("-back");
-               registercommand("+moveup");registercommand("-moveup");
-               registercommand("+movedown");registercommand("-movedown");
-               registercommand("+moveright");registercommand("-moveright");
-               registercommand("+moveleft");registercommand("-moveleft");
-               registercommand("+roll_right");registercommand("-roll_right");
-               registercommand("+roll_left");registercommand("-roll_left");
-#ifndef CAMERATEST
-       }
-#endif
        registercvar("hud_usecsqc", "1");
        registercvar("scoreboard_columns", "default");
 
@@ -380,290 +364,7 @@ void PostInit(void)
        postinit = true;
 }
 
-// CSQC_ConsoleCommand : Used to parse commands in the console that have been registered with the "registercommand" function
-// Return value should be 1 if CSQC handled the command, otherwise return 0 to have the engine handle it.
 float button_zoom;
-void Cmd_HUD_SetFields(float);
-void Cmd_HUD_Help(float);
-float CSQC_ConsoleCommand(string strMessage)
-{
-       float argc;
-       // Tokenize String
-       argc = tokenize_console(strMessage);
-
-       // Acquire Command
-       string strCmd;
-       strCmd = argv(0);
-
-       if(strCmd == "hud_configure") { // config hud
-               cvar_set("_hud_configure", ftos(!autocvar__hud_configure));
-               return true;
-       } else if(strCmd == "hud_save") { // save hud config
-               if(argv(1) == "" || argv(2)) {
-                       print(_("Usage:\n"));
-                       print(_("hud_save configname   (saves to hud_skinname_configname.cfg)\n"));
-               }
-               else
-                       HUD_Panel_ExportCfg(argv(1));
-               return true;
-       } else if(strCmd == "+showscores") {
-               scoreboard_showscores = true;
-               return true;
-       } else if(strCmd == "-showscores") {
-               scoreboard_showscores = false;
-               return true;
-       } else if(strCmd == "+showaccuracy") {
-               scoreboard_showaccuracy = true;
-               return true;
-       } else if(strCmd == "-showaccuracy") {
-               scoreboard_showaccuracy = false;
-               return true;
-       }
-
-       if(camera_active)
-       if(strCmd == "+forward" || strCmd == "-back") {
-               ++camera_direction_x;
-               return true;
-       } else if(strCmd == "-forward" || strCmd == "+back") {
-               --camera_direction_x;
-               return true;
-       } else if(strCmd == "+moveright" || strCmd == "-moveleft") {
-               --camera_direction_y;
-               return true;
-       } else if(strCmd == "-moveright" || strCmd == "+moveleft") {
-               ++camera_direction_y;
-               return true;
-       } else if(strCmd == "+moveup" || strCmd == "-movedown") {
-               ++camera_direction_z;
-               return true;
-       } else if(strCmd == "-moveup" || strCmd == "+movedown") {
-               --camera_direction_z;
-               return true;
-       } else if(strCmd == "+roll_right" || strCmd == "-roll_left") {
-               ++camera_roll;
-               return true;
-       } else if(strCmd == "+roll_left" || strCmd == "-roll_right") {
-               --camera_roll;
-               return true;
-       }
-
-       return false;
-}
-
-.vector view_ofs;
-entity debug_shotorg;
-void ShotOrg_Draw()
-{
-       self.origin = view_origin + view_forward * self.view_ofs_x + view_right * self.view_ofs_y + view_up * self.view_ofs_z;
-       self.angles = view_angles;
-       self.angles_x = -self.angles_x;
-       if not(self.cnt)
-               self.drawmask = MASK_NORMAL;
-       else
-               self.drawmask = 0;
-}
-void ShotOrg_Draw2D()
-{
-       vector coord2d_topleft, coord2d_topright, coord2d;
-       string s;
-       vector fs;
-
-       s = vtos(self.view_ofs);
-       s = substring(s, 1, strlen(s) - 2);
-       if(tokenize_console(s) == 3)
-               s = strcat(argv(0), " ", argv(1), " ", argv(2));
-
-       coord2d_topleft = project_3d_to_2d(self.origin + view_up * 4 - view_right * 4);
-       coord2d_topright = project_3d_to_2d(self.origin + view_up * 4 + view_right * 4);
-
-       fs = '1 1 0' * ((coord2d_topright_x - coord2d_topleft_x) / stringwidth(s, FALSE, '8 8 0'));
-
-       coord2d = coord2d_topleft;
-       if(fs_x < 8)
-       {
-               coord2d_x += (coord2d_topright_x - coord2d_topleft_x) * (1 - 8 / fs_x) * 0.5;
-               fs = '8 8 0';
-       }
-       coord2d_y -= fs_y;
-       coord2d_z = 0;
-       drawstring(coord2d, s, fs, '1 1 1', 1, 0);
-}
-
-void ShotOrg_Spawn()
-{
-       debug_shotorg = spawn();
-       debug_shotorg.draw = ShotOrg_Draw;
-       debug_shotorg.draw2d = ShotOrg_Draw2D;
-       debug_shotorg.renderflags = RF_VIEWMODEL;
-       debug_shotorg.effects = EF_FULLBRIGHT;
-       precache_model("models/shotorg_adjuster.md3");
-       setmodel(debug_shotorg, "models/shotorg_adjuster.md3");
-       debug_shotorg.scale = 2;
-       debug_shotorg.view_ofs = '25 8 -8';
-}
-
-void DrawDebugModel()
-{
-       if(time - floor(time) > 0.5)
-       {
-               PolyDrawModel(self);
-               self.drawmask = 0;
-       }
-       else
-       {
-               self.renderflags = 0;
-               self.drawmask = MASK_NORMAL;
-       }
-}
-
-void GameCommand(string msg)
-{
-       string s;
-       float argc;
-       entity e;
-       argc = tokenize_console(msg);
-
-       if(argv(0) == "help" || argc == 0)
-       {
-               print(_("Usage: cl_cmd COMMAND..., where possible commands are:\n"));
-               print(_("  scoreboard_columns_set ...\n"));
-               print(_("  scoreboard_columns_help\n"));
-               GameCommand_Generic("help");
-               return;
-       }
-
-       if(GameCommand_Generic(msg))
-               return;
-
-       string cmd;
-       cmd = argv(0);
-       if(cmd == "mv_download") {
-               Cmd_MapVote_MapDownload(argc);
-       }
-       else if(cmd == "hud_panel_radar_maximized")
-       {
-               if(argc == 1)
-                       hud_panel_radar_maximized = !hud_panel_radar_maximized;
-               else
-                       hud_panel_radar_maximized = (stof(argv(1)) != 0);
-       }
-       else if(cmd == "scoreboard_columns_set") {
-               Cmd_HUD_SetFields(argc);
-       }
-       else if(cmd == "scoreboard_columns_help") {
-               Cmd_HUD_Help(argc);
-       }
-#ifdef BLURTEST
-       else if(cmd == "blurtest") {
-               blurtest_time0 = time;
-               blurtest_time1 = time + stof(argv(1));
-               blurtest_radius = stof(argv(2));
-               blurtest_power = stof(argv(3));
-       }
-#endif
-       else if(cmd == "shotorg_move") {
-               if(!debug_shotorg)
-                       ShotOrg_Spawn();
-               else
-                       debug_shotorg.view_ofs = debug_shotorg.view_ofs + stov(argv(1));
-               localcmd("sv_cmd debug_shotorg \"", vtos(debug_shotorg.view_ofs), "\"\n");
-       }
-       else if(cmd == "shotorg_movez") {
-               if(!debug_shotorg)
-                       ShotOrg_Spawn();
-               else
-                       debug_shotorg.view_ofs = debug_shotorg.view_ofs + stof(argv(1)) * (debug_shotorg.view_ofs * (1 / debug_shotorg.view_ofs_x)); // closer/farther, same xy pos
-               localcmd("sv_cmd debug_shotorg \"", vtos(debug_shotorg.view_ofs), "\"\n");
-       }
-       else if(cmd == "shotorg_set") {
-               if(!debug_shotorg)
-                       ShotOrg_Spawn();
-               else
-                       debug_shotorg.view_ofs = stov(argv(1));
-               localcmd("sv_cmd debug_shotorg \"", vtos(debug_shotorg.view_ofs), "\"\n");
-       }
-       else if(cmd == "shotorg_setz") {
-               if(!debug_shotorg)
-                       ShotOrg_Spawn();
-               else
-                       debug_shotorg.view_ofs = debug_shotorg.view_ofs * (stof(argv(1)) / debug_shotorg.view_ofs_x); // closer/farther, same xy pos
-               localcmd("sv_cmd debug_shotorg \"", vtos(debug_shotorg.view_ofs), "\"\n");
-       }
-       else if(cmd == "shotorg_toggle_hide") {
-               if(debug_shotorg)
-               {
-                       debug_shotorg.cnt = !debug_shotorg.cnt;
-               }
-       }
-       else if(cmd == "shotorg_end") {
-               if(debug_shotorg)
-               {
-                       print(vtos(debug_shotorg.view_ofs), "\n");
-                       remove(debug_shotorg);
-                       debug_shotorg = world;
-               }
-               localcmd("sv_cmd debug_shotorg\n");
-       }
-       else if(cmd == "sendcvar") {
-               // W_FixWeaponOrder will trash argv, so save what we need.
-               string thiscvar;
-               thiscvar = strzone(argv(1));
-               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);
-       }
-       else if(cmd == "spawn") {
-               s = argv(1);
-               e = spawn();
-               precache_model(s);
-               setmodel(e, s);
-               setorigin(e, view_origin);
-               e.angles = view_angles;
-               e.draw = DrawDebugModel;
-               e.classname = "debugmodel";
-       }
-    else if(cmd == "vyes")
-    {
-        if(uid2name_dialog)
-        {
-            vote_active = 0; // force the panel to disappear right as we have selected the value (to prevent it from fading out in the normal vote panel pos)
-            vote_prev = 0;
-            localcmd("setreport cl_allow_uid2name 1\n");
-            vote_change = -9999;
-                       uid2name_dialog = 0;
-        }
-        else
-        {
-            localcmd("cmd vote yes\n");
-        }
-    }
-    else if(cmd == "vno")
-    {
-        if(uid2name_dialog)
-        {
-            vote_active = 0;
-            vote_prev = 0;
-            localcmd("setreport cl_allow_uid2name 0\n");
-            vote_change = -9999;
-                       uid2name_dialog = 0;
-        }
-        else
-        {
-            localcmd("cmd vote no\n");
-        }
-    }
-
-       else
-       {
-               print("Invalid command. For a list of supported commands, try cl_cmd help.\n");
-       }
-
-       return;
-}
 
 // CSQC_InputEvent : Used to perform actions based on any key pressed, key released and mouse on the client.
 // Return value should be 1 if CSQC handled the input, otherwise return 0 to have the input passed to the engine.
diff --git a/qcsrc/client/command/cl_cmd.qc b/qcsrc/client/command/cl_cmd.qc
new file mode 100644 (file)
index 0000000..77cbddd
--- /dev/null
@@ -0,0 +1,527 @@
+// ==============================================
+//  CSQC client commands code, written by Samual
+//  Last updated: December 28th, 2011
+// ==============================================
+
+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:
+               {
+                       if(argv(1))
+                       {
+                               Cmd_MapVote_MapDownload(argc);
+                               return; 
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2mv_download^7\n");
+               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:
+               {
+                       if(argv(1))
+                       {
+                               // 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:
+                       print("Incorrect parameters for ^2sendcvar^7\n");
+               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;
+               }
+       }
+}
+
+/* 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
+// ==================================
+
+// Normally do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
+// but for 0.5 compat, we need vyes and vno here as they were replaced... REMOVE THEM AFTER 0.6 RELEASE!!!!
+#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("vyes", LocalCommand_handlevote(request, tokenize_console("handlevote yes")), "") \
+       CLIENT_COMMAND("vno", LocalCommand_handlevote(request, tokenize_console("handlevote no")), "") \
+       /* nothing */
+       
+void LocalCommand_macro_help()
+{
+       #define CLIENT_COMMAND(name,function,description) \
+               { if(strtolower(description) != string_null) { 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;
+}
+
+void LocalCommand_macro_write_aliases(float fh)
+{
+       #define CLIENT_COMMAND(name,function,description) \
+               { CMD_Write_Alias("qc_cmd_cl", name, description); }
+               
+       CLIENT_COMMANDS(0, 0)
+       #undef CLIENT_COMMAND
+       
+       return;
+}
+
+
+// =========================================
+//  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("\nClient console commands:\n");
+                       LocalCommand_macro_help();
+
+                       print("\nGeneric commands shared by all programs:\n");
+                       GenericCommand_macro_help();
+                       
+                       print("\nUsage:^3 cl_cmd COMMAND...^7, where possible commands are listed above.\n");
+                       print("For help about a specific command, type cl_cmd help COMMAND\n");
+                       
+                       return;
+               } 
+               else if(GenericCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
+               {
+                       return;
+               }
+               else if(LocalCommand_macro_usage(argc)) // now try for normal commands too
+               {
+                       return;
+               }
+       } 
+       else if(GenericCommand(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;
+}
\ No newline at end of file
diff --git a/qcsrc/client/command/cl_cmd.qh b/qcsrc/client/command/cl_cmd.qh
new file mode 100644 (file)
index 0000000..f2db76a
--- /dev/null
@@ -0,0 +1,10 @@
+// ==============================================
+//  CSQC client commands code, written by Samual
+//  Last updated: December 17th, 2011
+// ==============================================
+
+void Cmd_HUD_SetFields(float);
+void Cmd_HUD_Help();
+
+// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
+void LocalCommand_macro_write_aliases(float fh);
\ No newline at end of file
index 0af74018eeb58406ed398d38033ce24773674cad..fe22c0f4baf53e14fc4b6418994c31d1ebaa42c0 100644 (file)
@@ -280,7 +280,7 @@ void Cmd_MapVote_MapDownload(float argc)
                return;
        } else {
                print(_("Requesting preview...\n"));
-               localcmd(strcat("\ncmd mv_getpic ", ftos(id), "\n"));
+               localcmd(strcat("\ncmd getmapvotepic ", ftos(id), "\n"));
        }
 }
 
index 7f31cacf2bb779ab769c98462771354af9922f1f..a33570a2f9c3291b7402ea61a7d9eb6a39914e9a 100644 (file)
@@ -17,8 +17,13 @@ Defs.qc
 ../common/util.qh
 ../common/items.qh
 ../common/explosion_equation.qh
-
 ../common/mapinfo.qh
+../common/command/markup.qh
+../common/command/rpn.qh
+../common/command/generic.qh
+../common/command/shared_defs.qh
+
+command/cl_cmd.qh
 
 autocvars.qh
 
@@ -85,12 +90,16 @@ bgmscript.qc
 noise.qc
 
 ../common/util.qc
-../common/gamecommand.qc
+../common/command/markup.qc
+../common/command/rpn.qc
+../common/command/generic.qc
 ../common/mapinfo.qc
 ../common/items.qc
 ../server/w_all.qc
 ../common/explosion_equation.qc
 
+command/cl_cmd.qc
+
 ../warpzonelib/anglestransform.qc
 ../warpzonelib/mathlib.qc
 ../warpzonelib/common.qc
index 9b93aa8a2da929aef037a364f7bf574d95084ea6..05c8df88cfc68f767c1eb268bab64044dc9ef4fa 100644 (file)
@@ -234,7 +234,7 @@ void HUD_UpdateTeamPos(entity Team)
        }
 }
 
-void Cmd_HUD_Help(float argc)
+void Cmd_HUD_Help()
 {
        print(_("You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"));
        print(_("^3|---------------------------------------------------------------|\n"));
@@ -308,17 +308,17 @@ void Cmd_HUD_SetFields(float argc)
        float missing;
 
        // TODO: re enable with gametype dependant cvars?
-       if(argc < 2) // no arguments provided
+       if(argc < 3) // no arguments provided
                argc = tokenizebyseparator(strcat("x ", autocvar_scoreboard_columns), " ");
 
-       if(argc < 2)
+       if(argc < 3)
                argc = tokenizebyseparator(strcat("x ", HUD_DefaultColumnLayout()), " ");
 
-       if(argc == 2)
+       if(argc == 3)
        {
-               if(argv(1) == "default")
+               if(argv(2) == "default")
                        argc = tokenizebyseparator(strcat("x ", HUD_DefaultColumnLayout()), " ");
-               else if(argv(1) == "all")
+               else if(argv(2) == "all")
                {
                        string s;
                        s = "ping pl color name |";
diff --git a/qcsrc/common/command/generic.qc b/qcsrc/common/command/generic.qc
new file mode 100644 (file)
index 0000000..5d6398c
--- /dev/null
@@ -0,0 +1,486 @@
+// =========================================================
+//  Generic program common command code, written by Samual
+//  Last updated: December 28th, 2011
+// =========================================================
+
+// used by generic commands for better help/usage information
+string GetProgramCommandPrefix(void)
+{
+       #ifdef SVQC
+       return "sv_cmd";
+       #endif
+       #ifdef CSQC
+       return "cl_cmd";
+       #endif
+       #ifdef MENUQC
+       return "menu_cmd";
+       #endif
+}
+
+
+// =======================
+//  Command Sub-Functions
+// =======================
+
+void GenericCommand_addtolist(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       float i;
+                       
+                       if(argc >= 2)
+                       {
+                               string original_cvar = argv(1);
+                               string tmp_string = argv(2);
+                               
+                               if(cvar_string(original_cvar) == "") // cvar was empty
+                               {
+                                       cvar_set(original_cvar, tmp_string);
+                               }
+                               else // add it to the end of the list if the list doesn't already have it
+                               {
+                                       argc = tokenizebyseparator(cvar_string(original_cvar), " ");
+                                       
+                                       for(i = 0; i < argc; ++i)
+                                               if(argv(i) == tmp_string)
+                                                       return; // already in list
+                                                       
+                                       cvar_set(original_cvar, strcat(tmp_string, " ", cvar_string(original_cvar)));
+                               }
+                               return;
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2addtolist^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " addtolist variable value"));
+                       print("  Where 'variable' is what to add 'value' to.\n");
+                       return;
+               }
+       }
+}
+
+void GenericCommand_dumpcommands(float request)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       float fh;
+                       string filename = strcat(GetProgramCommandPrefix(), "_dump.txt");
+                       fh = fopen(filename, FILE_WRITE);
+                       
+                       if(fh >= 0)
+                       {
+                               #ifdef SVQC
+                                       CMD_Write("dump of server console commands:\n");
+                                       GameCommand_macro_write_aliases(fh);
+                                       
+                                       CMD_Write("\ndump of networked client only commands:\n");
+                                       ClientCommand_macro_write_aliases(fh);
+                                       
+                                       CMD_Write("\ndump of common commands:\n");
+                                       CommonCommand_macro_write_aliases(fh);
+
+                                       CMD_Write("\ndump of ban commands:\n");
+                                       BanCommand_macro_write_aliases(fh);
+                               #endif
+                                                               
+                               #ifdef CSQC
+                                       CMD_Write("dump of client commands:\n");
+                                       LocalCommand_macro_write_aliases(fh);
+                               #endif
+                               
+                               CMD_Write("\ndump of generic commands:\n");
+                               GenericCommand_macro_write_aliases(fh);
+                               
+                               print("Completed dump of aliases in ^2", GetProgramCommandPrefix(), "_dump.txt^7.\n");
+                               
+                               fclose(fh);
+                       }
+                       else
+                       {
+                               print("^1Error: ^7Could not dump to file!\n");
+                       }
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpcommands"));
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void GenericCommand_maplist(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       string tmp_string;
+                       float i;
+                       
+                       switch(argv(1))
+                       {
+                               case "add": // appends new maps to the maplist
+                               {
+                                       if(argc == 3)
+                                       {
+                                               if (!fexists(strcat("maps/", argv(2), ".bsp")))
+                                               {
+                                                       print("maplist: ERROR: ", argv(2), " does not exist!\n");
+                                                       break;
+                                               }
+                                               
+                                               if(cvar_string("g_maplist") == "")
+                                                       cvar_set("g_maplist", argv(2));
+                                               else
+                                                       cvar_set("g_maplist", strcat(argv(2), " ", cvar_string("g_maplist")));
+                                                       
+                                               return;
+                                       }
+                                       break; // go to usage
+                               }
+                               
+                               case "remove": // scans maplist and only adds back whatever maps were not provided in argv(2)
+                               {
+                                       if(argc == 3)
+                                       {
+                                               argc = tokenizebyseparator(cvar_string("g_maplist"), " ");
+                                               
+                                               for(i = 0; i < argc; ++i)
+                                                       if(argv(i) != argv(2))
+                                                               tmp_string = strcat(tmp_string, " ", argv(i));
+                                                               
+                                               tmp_string = substring(tmp_string, 1, strlen(tmp_string) - 1);
+                                               cvar_set("g_maplist", tmp_string);
+                                               
+                                               return;
+                                       }
+                                       break; // go to usage
+                               }
+                               
+                               case "shuffle": // randomly shuffle the maplist
+                               {
+                                       cvar_set("g_maplist", shufflewords(cvar_string("g_maplist")));
+                                       return;
+                               }
+                               
+                               case "cleanup": // scans maplist and only adds back the ones which are really usable
+                               {
+                                       MapInfo_Enumerate();
+                                       MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
+                                       argc = tokenizebyseparator(cvar_string("g_maplist"), " ");
+                                       
+                                       for(i = 0; i < argc; ++i)
+                                               if(MapInfo_CheckMap(argv(i)))
+                                                       tmp_string = strcat(tmp_string, " ", argv(i));
+                                                       
+                                       tmp_string = substring(tmp_string, 1, strlen(tmp_string) - 1);
+                                       cvar_set("g_maplist", tmp_string);
+                                       
+                                       return;
+                               }
+                                       
+                               default: break;
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2maplist^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " maplist command [map]")); // todo
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void GenericCommand_removefromlist(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argc == 3)
+                       {
+                               float i;
+                               string original_cvar = argv(1);
+                               string removal = argv(2);
+                               string tmp_string;
+                               
+                               argc = tokenizebyseparator(cvar_string(original_cvar), " ");
+                               
+                               for(i = 0; i < argc; ++i)
+                                       if(argv(i) != removal)
+                                               tmp_string = strcat(tmp_string, " ", argv(i));
+                                               
+                               tmp_string = substring(tmp_string, 1, strlen(tmp_string) - 1);
+                               cvar_set(original_cvar, tmp_string);
+                               
+                               return;
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2removefromlist^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " removefromlist variable value"));
+                       print("  Where 'variable' is what cvar to remove 'value' from.\n");
+                       return;
+               }
+       }
+}
+
+void GenericCommand_settemp(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       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(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " settemp \"cvar\" \"arguments\"\n"));
+                       print("  Where 'cvar' is the cvar you want to temporarily set with 'arguments'.\n");
+                       return;
+               }
+       }
+}
+
+void GenericCommand_settemp_restore(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       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;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " settemp_restore\n"));
+                       print("  No arguments required.\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 GenericCommand_(float request)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " "));
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+*/
+
+// ==================================
+//  Macro system for server commands
+// ==================================
+
+// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
+#define GENERIC_COMMANDS(request,arguments,command) \
+       GENERIC_COMMAND("addtolist", GenericCommand_addtolist(request, arguments), "Add a string to a cvar") \
+       GENERIC_COMMAND("dumpcommands", GenericCommand_dumpcommands(request), "Dump all commands on the program to *_cmd_dump.txt") \
+       GENERIC_COMMAND("maplist", GenericCommand_maplist(request, arguments), "Automatic control of maplist") \
+       GENERIC_COMMAND("removefromlist", GenericCommand_removefromlist(request, arguments), "Remove a string from a cvar") \
+       GENERIC_COMMAND("rpn", GenericCommand_rpn(request, arguments, command), "RPN calculator") \
+       GENERIC_COMMAND("settemp", GenericCommand_settemp(request, arguments), "Temporarily set a value to a cvar which is restored later") \
+       GENERIC_COMMAND("settemp_restore", GenericCommand_settemp_restore(request, arguments), "Restore all cvars set by settemp command") \
+       /* nothing */
+
+void GenericCommand_macro_help()
+{
+       #define GENERIC_COMMAND(name,function,description) \
+               { print("  ^2", name, "^7: ", description, "\n"); }
+               
+       GENERIC_COMMANDS(0, 0, "")
+       #undef GENERIC_COMMAND
+       
+       return;
+}
+
+float GenericCommand_macro_command(float argc, string command)
+{
+       #define GENERIC_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(0))) { function; return TRUE; } }
+               
+       GENERIC_COMMANDS(CMD_REQUEST_COMMAND, argc, command)
+       #undef GENERIC_COMMAND
+       
+       return FALSE;
+}
+
+float GenericCommand_macro_usage(float argc)
+{
+       #define GENERIC_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(1))) { function; return TRUE; } }
+               
+       GENERIC_COMMANDS(CMD_REQUEST_USAGE, argc, "")
+       #undef GENERIC_COMMAND
+       
+       return FALSE;
+}
+
+void GenericCommand_macro_write_aliases(float fh)
+{
+       #define GENERIC_COMMAND(name,function,description) \
+               { CMD_Write_Alias("qc_cmd_svmenu", name, description); }
+       
+       GENERIC_COMMANDS(0, 0, "")
+       #undef GENERIC_COMMAND
+       
+       return;
+}
+       
+
+// ===========================================
+//  Main Common Function For Generic Commands
+// ===========================================
+// Commands spread out among all programs (menu, client, and server) 
+
+float GenericCommand(string command)
+{
+       float argc = tokenize_console(command);
+       float n, j, f, i;
+       string s, s2, c;
+       vector rgb;
+
+       // Guide for working with argc arguments by example:
+       // argc:   1    - 2      - 3     - 4
+       // argv:   0    - 1      - 2     - 3 
+       // cmd     vote - master - login - password
+       
+       if(GenericCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
+       {
+               return TRUE; // handled by one of the above GenericCommand_* functions
+       }
+       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), " ", GenericCommand_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;
+       }
+
+       return FALSE;
+}
diff --git a/qcsrc/common/command/generic.qh b/qcsrc/common/command/generic.qh
new file mode 100644 (file)
index 0000000..3078a0f
--- /dev/null
@@ -0,0 +1,17 @@
+// =========================================================
+//  Declarations for common command code, written by Samual
+//  Last updated: December 28th, 2011
+// =========================================================
+
+// Used by other game command systems for common commands,
+// and it returns true if handled, false if not. 
+// Note: It tokenizes its input, so be careful!
+float GenericCommand(string command);
+
+// Returns command prefix specific for whatever program it is compiled in
+string GetProgramCommandPrefix(void); 
+
+// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
+#define CMD_Write(s) fputs(fh, s)
+#define CMD_Write_Alias(execute,command,description) CMD_Write(sprintf("alias %-20s \"%-13s %-20s ${* ?}\" // %s\n", command, execute, command, description))
+void GenericCommand_macro_write_aliases(float fh);
\ No newline at end of file
diff --git a/qcsrc/common/command/markup.qc b/qcsrc/common/command/markup.qc
new file mode 100644 (file)
index 0000000..cb1a8cc
--- /dev/null
@@ -0,0 +1,111 @@
+// =========================================================
+//  Markup chat characters command code, reworked by Samual
+//  Last updated: December 28th, 2011
+// =========================================================
+
+void GenericCommand_markup_init()
+{
+       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 GenericCommand_markup(string s2)
+{
+       float red, ccase, i, j;
+       string s, s3;
+
+       GenericCommand_markup_init();
+
+       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;
+}
diff --git a/qcsrc/common/command/markup.qh b/qcsrc/common/command/markup.qh
new file mode 100644 (file)
index 0000000..6cf09d3
--- /dev/null
@@ -0,0 +1,9 @@
+// ==========================================================
+//  Declarations for markup command code, reworked by Samual
+//  Last updated: December 28th, 2011
+// ==========================================================
+
+#define NUM_MARKUPS    41
+float markup_init;
+string markup_from[NUM_MARKUPS];
+string markup_to[NUM_MARKUPS];
diff --git a/qcsrc/common/command/rpn.qc b/qcsrc/common/command/rpn.qc
new file mode 100644 (file)
index 0000000..d6c624b
--- /dev/null
@@ -0,0 +1,559 @@
+// ========================================
+//  RPN command code, written by divVerent
+//  Last updated: December 28th, 2011
+// ========================================
+
+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)); }
+
+void GenericCommand_rpn(float request, float argc, string command)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       float i, j, f, n, f2, f3, rpnpos;
+                       vector rgb;
+                       string s, s2, c, rpncmd;
+                       
+                       if(!rpn_db)
+                       {
+                               rpn_db = db_create();
+                               db_put(rpn_db, "stack.pointer", "0");
+                               db_put(rpn_db, "stack.pos", "-1");
+                       }
+                       
+                       if(argc >= 2)
+                       {
+                               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;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " rpn EXPRESSION...\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");
+                       return;
+               }
+       }
+}
\ No newline at end of file
diff --git a/qcsrc/common/command/rpn.qh b/qcsrc/common/command/rpn.qh
new file mode 100644 (file)
index 0000000..6ffc5e1
--- /dev/null
@@ -0,0 +1,10 @@
+// =========================================================
+//  Declarations for RPN command code, written by divVerent
+//  Last updated: December 28th, 2011
+// =========================================================
+
+#define MAX_RPN_STACK 16
+float rpn_db;
+float rpn_error;
+float rpn_sp;
+string rpn_stack[MAX_RPN_STACK];
\ No newline at end of file
diff --git a/qcsrc/common/command/shared_defs.qh b/qcsrc/common/command/shared_defs.qh
new file mode 100644 (file)
index 0000000..f06ee32
--- /dev/null
@@ -0,0 +1,8 @@
+// =========================================================
+//  Shared declarations for all commands, written by Samual
+//  Last updated: December 13th, 2011
+// =========================================================
+
+// identifiers for subfunction requests by the command code structure
+#define CMD_REQUEST_COMMAND 1
+#define CMD_REQUEST_USAGE 2
\ No newline at end of file
diff --git a/qcsrc/common/gamecommand.qc b/qcsrc/common/gamecommand.qc
deleted file mode 100644 (file)
index 1d21f08..0000000
+++ /dev/null
@@ -1,863 +0,0 @@
-#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;
-}
index 9daab8b4fdde51d9c5b70ad3ced041394284d034..c3b95d97740ee849fff3332101bf5d4436bef242 100644 (file)
@@ -842,28 +842,48 @@ void get_mi_min_max_texcoords(float mode)
 }
 #endif
 
-void cvar_settemp(string cv, string val)
+float cvar_settemp(string tmp_cvar, string tmp_value)
 {
+       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()
 {
+       float i;
        entity e;
        while((e = find(world, classname, "saved_cvar_value")))
        {
                cvar_set(e.netname, e.message);
                remove(e);
        }
+       
+       return i;
 }
 
 float almost_equals(float a, float b)
@@ -2071,6 +2091,46 @@ float lowestbit(float f)
        return f;
 }
 
+/*
+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);
+}*/
+
+// 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()
 {
index 6d4eb61130b13fd26a75948fb28ff8b2c75d8721..a8dd88c2f05b7b7490bd989a8015969533dc3106 100644 (file)
@@ -20,10 +20,6 @@ void wordwrap_sprint(string s, float l);
 #endif
 void wordwrap_cb(string s, float l, void(string) callback)
 
-float GameCommand_Generic(string cmd);
-// returns TRUE if handled, FALSE otherwise
-// tokenizes its input!
-
 // iterative depth-first search, with fields that go "up", "down left" and "right" in a tree
 // for each element, funcPre is called first, then funcPre and funcPost for all its children, and funcPost last
 void depthfirst(entity start, .entity up, .entity downleft, .entity right, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass);
@@ -89,8 +85,8 @@ string swapInPriorityList(string order, float i, float j);
 
 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)
@@ -277,5 +273,15 @@ float lowestbit(float f);
 entity ReadCSQCEntity()
 #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 8fc5f56f01bfea64bb3fd3b009428dc050e3b598..cf15840a85ab7fcf403b5d4fa3daa0249b40562d 100644 (file)
@@ -431,6 +431,15 @@ float(float bufhandle, string str, float order) bufstr_add = #448;
 void(float bufhandle, float string_index) bufstr_free = #449;
 void(float bufhandle, string pattern, string antipattern) buf_cvarlist = #517;
 
+//DP_QC_STRING_CASE_FUNCTIONS
+//idea: Dresk
+//darkplaces implementation: LordHavoc / Dresk
+//builtin definitions:
+string(string s) strtolower = #480; // returns the passed in string in pure lowercase form
+string(string s) strtoupper = #481; // returns the passed in string in pure uppercase form
+//description:
+//provides simple string uppercase and lowercase functions
+
 //DP_QC_CVAR_DESCRIPTION
 //idea: divVerent
 //DarkPlaces implementation: divVerent
diff --git a/qcsrc/menu/command/menu_cmd.qc b/qcsrc/menu/command/menu_cmd.qc
new file mode 100644 (file)
index 0000000..3be6edc
--- /dev/null
@@ -0,0 +1,187 @@
+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"));
+               GenericCommand("help");
+               return;
+       }
+
+       if(GenericCommand(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"));
+}
diff --git a/qcsrc/menu/command/menu_cmd.qh b/qcsrc/menu/command/menu_cmd.qh
new file mode 100644 (file)
index 0000000..7a18fe2
--- /dev/null
@@ -0,0 +1 @@
+void GameCommand(string command);
diff --git a/qcsrc/menu/gamecommand.qc b/qcsrc/menu/gamecommand.qc
deleted file mode 100644 (file)
index 6a140f4..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-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"));
-}
diff --git a/qcsrc/menu/gamecommand.qh b/qcsrc/menu/gamecommand.qh
deleted file mode 100644 (file)
index 7a18fe2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-void GameCommand(string command);
index 979ae519f77b4ca2ebb4ecb25fb641b9387365c6..1f70e0e7be2f0ce5aef5c87d036d36c696e3122c 100644 (file)
@@ -15,8 +15,12 @@ oo/base.h
 ../common/mapinfo.qh
 ../common/campaign_common.qh
 ../common/items.qh
+../common/command/markup.qh
+../common/command/rpn.qh
+../common/command/generic.qh
+../common/command/shared_defs.qh
 
-gamecommand.qh
+command/menu_cmd.qh
 menu.qh
 draw.qh
 skin.qh
@@ -28,8 +32,10 @@ oo/implementation.h
        classes.c
 
 ../common/util.qc
-../common/gamecommand.qc
-gamecommand.qc
+../common/command/markup.qc
+../common/command/rpn.qc
+../common/command/generic.qc
+command/menu_cmd.qc
 menu.qc
 draw.qc
 xonotic/util.qc
index 6d9dde47b30d80dd2be57c1b396dde04e13f192f..fd84711861d76cf5b1f4cd3545420f07662b1959 100644 (file)
@@ -6,6 +6,7 @@ CLASS(XonoticQuitDialog) EXTENDS(XonoticDialog)
        ATTRIB(XonoticQuitDialog, intendedWidth, float, 0.5)
        ATTRIB(XonoticQuitDialog, rows, float, 3)
        ATTRIB(XonoticQuitDialog, columns, float, 2)
+       ATTRIB(XonoticQuitDialog, name, string, "Quit")
 ENDCLASS(XonoticQuitDialog)
 #endif
 
index 425bbf77933892791bf46b5c96219b50daec758e..2562dca3df803fa93725204eb01f7059ef1cd189 100644 (file)
@@ -372,5 +372,5 @@ void assault_new_round()
 
        // reset the level with a countdown
        cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60));
-       ReadyRestartForce(); // sets game_starttime
+       ReadyRestart_force(); // sets game_starttime
 }
index d41840250eb64754796e2591af4aa2a848d86164..36e66ff38d35f5e6c7c7a7e4ef730294ceeffcb7 100644 (file)
@@ -1073,6 +1073,8 @@ float autocvar_sv_airstrafeaccel_qw;
 float autocvar_sv_airstrafeaccelerate;
 float autocvar_sv_autoscreenshot;
 float autocvar_sv_cheats;
+float autocvar_sv_clientcommand_antispam_time;
+float autocvar_sv_clientcommand_antispam_count;
 float autocvar_sv_curl_serverpackages_auto;
 float autocvar_sv_db_saveasdump;
 float autocvar_sv_defaultcharacter;
@@ -1131,6 +1133,7 @@ float autocvar_sv_ready_restart_repeatable;
 float autocvar_sv_servermodelsonly;
 float autocvar_sv_spectate;
 float autocvar_sv_spectator_speed_multiplier;
+float autocvar_sv_status_privacy;
 float autocvar_sv_stepheight;
 float autocvar_sv_stopspeed;
 float autocvar_sv_strengthsound_antispam_refire_threshold;
@@ -1145,13 +1148,16 @@ float autocvar_sv_vote_call;
 float autocvar_sv_vote_change;
 string autocvar_sv_vote_commands;
 float autocvar_sv_vote_majority_factor;
+float autocvar_sv_vote_majority_factor_of_voted;
 float autocvar_sv_vote_master;
+float autocvar_sv_vote_master_callable;
 string autocvar_sv_vote_master_commands;
 string autocvar_sv_vote_master_password;
+float autocvar_sv_vote_master_playerlimit;
+float autocvar_sv_vote_no_stops_vote;
 float autocvar_sv_vote_nospectators;
 string autocvar_sv_vote_only_commands;
 float autocvar_sv_vote_override_mostrecent;
-float autocvar_sv_vote_simple_majority_factor;
 float autocvar_sv_vote_singlecount;
 float autocvar_sv_vote_stop;
 float autocvar_sv_vote_timeout;
index 4b73ec14b62cae43f8f52eb0295e3ac1f8df8c71..2fdbdd3f4fe8c0a1a7ea237ec1725cf3d1459c72 100644 (file)
@@ -494,7 +494,7 @@ void bot_list_commands()
                bot_commands_init();
 
        print("List of all available commands:\n");
-       print(" Command\t\t\t\tParameter Type\n");
+       print("  Command - Parameter Type\n");
 
        for(i=1;i<BOT_CMD_COUNTER;++i)
        {
@@ -513,7 +513,7 @@ void bot_list_commands()
                                ptype = "none";
                                break;
                }
-               print(strcat(" ",bot_cmd_string[i],"\t\t\t\t<",ptype,"> \n"));
+               print(strcat("  ",bot_cmd_string[i]," - <",ptype,"> \n"));
        }
 }
 
index e8ccc07d73330760e9d856b0ca217c30f8c0df56..a0c5c843a3d0054c56ee2e9e83dab7793409e513 100644 (file)
@@ -1524,7 +1524,7 @@ void ClientConnect (void)
        }
 
        self.jointime = time;
-       self.allowedTimeouts = autocvar_sv_timeout_number;
+       self.allowed_timeouts = autocvar_sv_timeout_number;
 
        if(clienttype(self) == CLIENTTYPE_REAL)
        {
@@ -2599,7 +2599,7 @@ void PlayerPreThink (void)
                }
 
                //don't allow the player to turn around while game is paused!
-               if(timeoutStatus == 2) {
+               if(timeout_status == TIMEOUT_ACTIVE) {
                        // FIXME turn this into CSQC stuff
                        self.v_angle = self.lastV_angle;
                        self.angles = self.lastV_angle;
index 9e662bb848e204b1a5b59dcd283424247d396951..524e796af2e32859054ee3a82522eae1ddb85147 100644 (file)
@@ -46,7 +46,7 @@ void ImpulseCommands (void)
                return;
        self.impulse = 0;
 
-       if (timeoutStatus == 2) //don't allow any impulses while the game is paused
+       if (timeout_status == TIMEOUT_ACTIVE) //don't allow any impulses while the game is paused
                return;
 
        if(CheatImpulse(imp))
index deb08aa9c618769bdb3bdcc67285e0d7447160fc..483446dccfb6c25fb781d38933b9001c5143de56 100644 (file)
@@ -948,7 +948,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f
                                flood = 1;
                }
 
-               if (timeoutStatus == 2) //when game is paused, no flood protection
+               if (timeout_status == TIMEOUT_ACTIVE) // when game is paused, no flood protection
                        source.flood_field = flood = 0;
        }
 
index ae275ac679b6786a094f380577d602ea1d37388a..e049ef8588e2ca97501451d092149e9b037c7679 100644 (file)
@@ -185,8 +185,6 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, vector s_forward, vector m
                vecs = ent.weaponentity.movedir;
        else
                vecs = '0 0 0';
-       if(debug_shotorg != '0 0 0')
-               vecs = debug_shotorg;
 
        dv = v_right * -vecs_y + v_up * vecs_z;
        w_shotorg = ent.origin + ent.view_ofs + dv;
@@ -915,7 +913,7 @@ float weapon_prepareattack_check(float secondary, float attacktime)
                return FALSE;
        }
 
-       if (timeoutStatus == 2) //don't allow the player to shoot while game is paused
+       if (timeout_status == TIMEOUT_ACTIVE) //don't allow the player to shoot while game is paused
                return FALSE;
 
        // do not even think about shooting if switching
diff --git a/qcsrc/server/clientcommands.qc b/qcsrc/server/clientcommands.qc
deleted file mode 100644 (file)
index 7f52f8f..0000000
+++ /dev/null
@@ -1,665 +0,0 @@
-entity nagger;
-float readycount;
-
-float Nagger_SendEntity(entity to, float sendflags)
-{
-       float nags, i, f, b;
-       entity e;
-       WriteByte(MSG_ENTITY, ENT_CLIENT_NAGGER);
-
-       // bits:
-       //   1 = ready
-       //   2 = player needs to ready up
-       //   4 = vote
-       //   8 = player needs to vote
-       //  16 = warmup
-       // sendflags:
-       //  64 = vote counts
-       // 128 = vote string
-
-       nags = 0;
-       if(readycount)
-       {
-               nags |= 1;
-               if(to.ready == 0)
-                       nags |= 2;
-       }
-       if(votecalled)
-       {
-               nags |= 4;
-               if(to.vote_vote == 0)
-                       nags |= 8;
-       }
-       if(inWarmupStage)
-               nags |= 16;
-
-       if(sendflags & 64)
-               nags |= 64;
-
-       if(sendflags & 128)
-               nags |= 128;
-
-       if(!(nags & 4)) // no vote called? send no string
-               nags &~= (64 | 128);
-
-       WriteByte(MSG_ENTITY, nags);
-
-       if(nags & 64)
-       {
-               WriteByte(MSG_ENTITY, vote_yescount);
-               WriteByte(MSG_ENTITY, vote_nocount);
-               WriteByte(MSG_ENTITY, vote_needed_absolute);
-               WriteChar(MSG_ENTITY, to.vote_vote);
-       }
-
-       if(nags & 128)
-               WriteString(MSG_ENTITY, votecalledvote_display);
-
-       if(nags & 1)
-       {
-               for(i = 1; i <= maxclients; i += 8)
-               {
-                       for(f = 0, e = edict_num(i), b = 1; b < 256; b *= 2, e = nextent(e))
-                               if(clienttype(e) != CLIENTTYPE_REAL || e.ready)
-                                       f |= b;
-                       WriteByte(MSG_ENTITY, f);
-               }
-       }
-
-       return TRUE;
-}
-void Nagger_Init()
-{
-       Net_LinkEntity(nagger = spawn(), FALSE, 0, Nagger_SendEntity);
-}
-void Nagger_VoteChanged()
-{
-       if(nagger)
-               nagger.SendFlags |= 128;
-}
-void Nagger_VoteCountChanged()
-{
-       if(nagger)
-               nagger.SendFlags |= 64;
-}
-void Nagger_ReadyCounted()
-{
-       if(nagger)
-               nagger.SendFlags |= 1;
-}
-
-void ReadyCount();
-string MapVote_Suggest(string m);
-
-entity GetPlayer(string name)
-{
-       float num;
-       entity e;
-       string ns;
-
-       if(substring(name, 0, 1) == "#") {
-               num = stof(substring(name, 1, 999));
-               if(num >= 1 && num <= maxclients) {
-                       for((e = world); num > 0; --num, (e = nextent(e)))
-                               ;
-                       //if(clienttype(e) == CLIENTTYPE_REAL)
-                       if(e.classname == "player")
-                               return e;
-               }
-       } else {
-               ns = strdecolorize(name);
-               FOR_EACH_REALPLAYER(e) {
-                       if(!strcasecmp(strdecolorize(e.netname), ns)) {
-                               return e;
-                       }
-               }
-       }
-       return world;
-}
-
-//float ctf_clientcommand();
-float readyrestart_happened;
-.float lms_spectate_warning;
-void spawnfunc_func_breakable();
-
-.float cmd_floodtime;
-.float cmd_floodcount;
-float cmd_floodcheck()
-{
-       if (timeoutStatus != 2)
-       {
-               if(time == self.cmd_floodtime)
-               {
-                       self.cmd_floodcount += 1;
-                       if(self.cmd_floodcount > 8)
-                               return TRUE;
-               }
-               else
-               {
-                       self.cmd_floodtime = time;
-                       self.cmd_floodcount = 1;
-               }
-       }
-       return FALSE;
-}
-
-.float checkfail;
-void SV_ParseClientCommand(string s) {
-       float i;
-       entity e;
-
-       cmd_argc = tokenize_console(s);
-       cmd_string = s;
-       cmd_name = strtolower(argv(0));
-       if(cmd_name != "reportcvar")
-       if(cmd_name != "sentcvar")
-       if(cmd_name != "pause")
-       if(cmd_name != "prespawn")
-       if(cmd_name != "spawn")
-       if(cmd_name != "begin")
-       {
-               if(cmd_floodcheck())
-                       return;
-       }
-
-       if(MUTATOR_CALLHOOK(SV_ParseClientCommand))
-               return; // already handled
-       
-       if(GameCommand_Vote(s, self)) {
-               return;
-       } else if(GameCommand_MapVote(argv(0))) {
-               return;
-       } else if(cmd_name == "checkfail") {
-               print(sprintf("CHECKFAIL: %s (%s) epically failed check %s\n", self.netname, self.netaddress, substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1))));
-               self.checkfail = 1;
-       } else if(cmd_name == "autoswitch") {
-               // be backwards compatible with older clients (enabled)
-               self.autoswitch = ("0" != argv(1));
-               string autoswitchmsg;
-               if (self.autoswitch) {
-                       autoswitchmsg = "on";
-               } else {
-                       autoswitchmsg = "off";
-               }
-               sprint(self, strcat("^1autoswitch turned ", autoswitchmsg, "\n"));
-       } else if(cmd_name == "clientversion") {
-               if not(self.flags & FL_CLIENT)
-                       return;
-               if (argv(1) == "$gameversion") {
-                       //versionmsg = "^1client is too old to get versioninfo.\nUPDATE!!! (http://www.xonotic.com)^8";
-                       // either that or someone wants to be funny
-                       self.version = 1;
-               } else {
-                       self.version = stof(argv(1));
-               }
-               if(self.version < autocvar_gameversion_min || self.version > autocvar_gameversion_max)
-               {
-                       self.version_mismatch = 1;
-                       ClientKill_TeamChange(-2); // observe
-               } else if(autocvar_g_campaign || autocvar_g_balance_teams || autocvar_g_balance_teams_force) {
-                       //JoinBestTeam(self, FALSE, TRUE);
-               } else if(teamplay && !autocvar_sv_spectate && !(self.team_forced > 0)) {
-                       self.classname = "observer";
-                       stuffcmd(self,"menu_showteamselect\n");
-               }
-       } else if(cmd_name == "reportcvar") { // old system
-               if(substring(argv(2), 0, 1) == "$") // undefined cvar: use the default value on the server then
-               {
-                       s = strcat(substring(s, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
-                       cmd_argc = tokenize_console(s);
-               }
-               GetCvars(1);
-       } else if(cmd_name == "sentcvar") { // new system
-               if(cmd_argc == 2) // undefined cvar: use the default value on the server then
-               {
-                       s = strcat(substring(s, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
-                       cmd_argc = tokenize_console(s);
-               }
-               GetCvars(1);
-       } else if(cmd_name == "spectate") {
-               if(cmd_floodcheck())
-                       return;
-               if not(self.flags & FL_CLIENT)
-                       return;
-               if(g_arena)
-                       return;
-               if(g_lms)
-               {
-                       if(self.lms_spectate_warning)
-                       {
-                               // mark player as spectator
-                               PlayerScore_Add(self, SP_LMS_RANK, 666 - PlayerScore_Add(self, SP_LMS_RANK, 0));
-                       }
-                       else
-                       {
-                               self.lms_spectate_warning = 1;
-                               sprint(self, "WARNING: you won't be able to enter the game again after spectating in LMS. Use the same command again to spectate anyway.\n");
-                               return;
-                       }
-               }
-               if(self.classname == "player" && autocvar_sv_spectate == 1) {
-                       ClientKill_TeamChange(-2); // observe
-               }
-               if(g_ca && self.caplayer && (self.classname == "spectator" || self.classname == "observer")) {
-                       // in CA, allow a dead player to move to spectatators (without that, caplayer!=0 will be moved back to the player list)
-                       sprint(self, "WARNING: you will spectate in the next round.\n");
-                       self.caplayer = 0;
-               }
-       } else if(cmd_name == "join") {
-               if not(self.flags & FL_CLIENT)
-                       return;
-               if(!g_arena)
-               if (self.classname != "player" && !lockteams)
-               {
-                       if(nJoinAllowed(1)) {
-                               self.classname = "player";
-                               if(g_ca)
-                                       self.caplayer = 1;
-                               PlayerScore_Clear(self);
-                               bprint ("^4", self.netname, "^4 is playing now\n");
-                               PutClientInServer();
-                               if(autocvar_g_campaign)
-                                       campaign_bots_may_start = 1;
-                       }
-                       else {
-                               //player may not join because of g_maxplayers is set
-                               centerprint(self, PREVENT_JOIN_TEXT);
-                       }
-               }
-       } else if( cmd_name == "selectteam" ) {
-               if not(self.flags & FL_CLIENT)
-                       return;
-               if( !teamplay ) {
-                       sprint( self, "selectteam can only be used in teamgames\n");
-               } else if(autocvar_g_campaign) {
-                       //JoinBestTeam(self, 0);
-               } else if(self.team_forced > 0) {
-                       sprint( self, "selectteam can not be used as your team is forced\n");
-               } else if(lockteams) {
-                       sprint( self, "^7The game has already begun, you must wait until the next map to be able to join a team.\n");
-               } else if( argv(1) == "red" ) {
-                       if(self.team == COLOR_TEAM1 && self.deadflag == DEAD_NO)
-                               sprint( self, "^7You already are on that team.\n");
-                       else if (self.wasplayer && autocvar_g_changeteam_banned)
-                               sprint( self, "^1You cannot change team, forbidden by the server.\n");
-                       else
-                               ClientKill_TeamChange(COLOR_TEAM1);
-               } else if( argv(1) == "blue" ) {
-                       if(self.team == COLOR_TEAM2 && self.deadflag == DEAD_NO)
-                               sprint( self, "^7You already are on that team.\n");
-                       else if (self.wasplayer && autocvar_g_changeteam_banned)
-                               sprint( self, "^1You cannot change team, forbidden by the server.\n");
-                       else
-                               ClientKill_TeamChange(COLOR_TEAM2);
-               } else if( argv(1) == "yellow" ) {
-                       if(self.team == COLOR_TEAM3 && self.deadflag == DEAD_NO)
-                               sprint( self, "^7You already are on that team.\n");
-                       else if (self.wasplayer && autocvar_g_changeteam_banned)
-                               sprint( self, "^1You cannot change team, forbidden by the server.\n");
-                       else
-                               ClientKill_TeamChange(COLOR_TEAM3);
-               } else if( argv(1) == "pink" ) {
-                       if(self.team == COLOR_TEAM4 && self.deadflag == DEAD_NO)
-                               sprint( self, "^7You already are on that team.\n");
-                       else if (self.wasplayer && autocvar_g_changeteam_banned)
-                               sprint( self, "^1You cannot change team, forbidden by the server.\n");
-                       else
-                               ClientKill_TeamChange(COLOR_TEAM4);
-               } else if( argv(1) == "auto" ) {
-                       ClientKill_TeamChange(-1);
-               } else {
-                       sprint( self, strcat( "selectteam none/red/blue/yellow/pink/auto - \"", argv(1), "\" not recognised\n" ) );
-               }
-       } else if(cmd_name == "ready") {
-               if not(self.flags & FL_CLIENT)
-                       return;
-
-               if((inWarmupStage)
-                  || autocvar_sv_ready_restart || g_race_qualifying == 2)
-               {
-                       if(!readyrestart_happened || autocvar_sv_ready_restart_repeatable)
-                       {
-                               if (self.ready) // toggle
-                               {
-                                       self.ready = FALSE;
-                                       bprint(self.netname, "^2 is ^1NOT^2 ready\n");
-                               }
-                               else
-                               {
-                                       self.ready = TRUE;
-                                       bprint(self.netname, "^2 is ready\n");
-                               }
-
-                               // cannot reset the game while a timeout is active!
-                               if(!timeoutStatus)
-                                       ReadyCount();
-                       } else {
-                               sprint(self, "^1Game has already been restarted\n");
-                       }
-               }
-       } else if(cmd_name == "maplist") {
-               sprint(self, maplist_reply);
-       } else if(cmd_name == "lsmaps") {
-               sprint(self, lsmaps_reply);
-       } else if(cmd_name == "lsnewmaps") {
-               sprint(self, lsnewmaps_reply);
-       } else if(cmd_name == "records") {
-               for(i = 0; i < 10; ++i)
-                       sprint(self, records_reply[i]);
-       } else if(cmd_name == "ladder") {
-               sprint(self, ladder_reply);
-       } else if(cmd_name == "rankings") {
-               sprint(self, rankings_reply);
-       } else if(cmd_name == "voice") {
-               if(cmd_argc >= 3)
-                       VoiceMessage(argv(1), substring(s, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
-               else
-                       VoiceMessage(argv(1), "");
-       } else if(cmd_name == "say") {
-               if(cmd_argc >= 2)
-                       Say(self, FALSE, world, substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
-               //clientcommand(self, formatmessage(s));
-       } else if(cmd_name == "say_team") {
-               if(cmd_argc >= 2)
-                       Say(self, TRUE, world, substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
-               //clientcommand(self, formatmessage(s));
-       } else if(cmd_name == "selfstuff") {
-               // this command mainly serves to embed a command to be executed into a demo (HINT: use settemp)
-               stuffcmd(self, substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
-       } else if(cmd_name == "tell") {
-               e = GetCommandPlayerSlotTargetFromTokenizedCommand(cmd_argc, 1);
-               if(e && cmd_argc > ParseCommandPlayerSlotTarget_firsttoken)
-               {
-                       Say(self, FALSE, e, substring(s, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken)), TRUE);
-               }
-               else
-               {
-                       if(cmd_argc > ParseCommandPlayerSlotTarget_firsttoken)
-                               trigger_magicear_processmessage_forallears(self, -1, world, substring(s, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken)));
-                       sprint(self, "ERROR: usage: tell # playerid text...\n");
-               }
-               //clientcommand(self, formatmessage(s));
-       } else if(cmd_name == "info") {
-               cmd_name = builtin_cvar_string(strcat("sv_info_", argv(1))); // This needed fixed for the cvar check
-               if(cmd_name == "")
-                       sprint(self, "ERROR: unsupported info command\n");
-               else
-                       wordwrap_sprint(cmd_name, 1111);
-       } else if(cmd_name == "suggestmap") {
-               sprint(self, strcat(MapVote_Suggest(argv(1)), "\n"));
-       } else if(cmd_name == "timeout") {
-               if not(self.flags & FL_CLIENT)
-                       return;
-               if(autocvar_sv_timeout) {
-                       if(self.classname == "player") {
-                               if(votecalled)
-                                       sprint(self, "^7Error: you can not call a timeout while a vote is active!\n");
-                               else
-                                       evaluateTimeout();
-                       }
-                       else
-                               sprint(self, "^7Error: only players can call a timeout!\n");
-               }
-       } else if(cmd_name == "timein") {
-               if not(self.flags & FL_CLIENT)
-                       return;
-               if(autocvar_sv_timeout) {
-                       evaluateTimein();
-               }
-       } else if(cmd_name == "teamstatus") {
-               Score_NicePrint(self);
-       } else if(cmd_name == "cvar_changes") {
-               sprint(self, cvar_changes);
-       } else if(cmd_name == "cvar_purechanges") {
-               sprint(self, cvar_purechanges);
-       } else if(CheatCommand(cmd_argc)) {
-       } else {
-#if 0
-               //if(ctf_clientcommand())
-               //      return;
-               // grep for Cmd_AddCommand_WithClientCommand to find them all
-               if(cmd_name != "status")
-               //if(cmd_name != "say") // handled above
-               //if(cmd_name != "say_team") // handled above
-               if(cmd_name != "kill")
-               if(cmd_name != "pause")
-               if(cmd_name != "ping")
-               if(cmd_name != "name")
-               if(cmd_name != "color")
-               if(cmd_name != "rate")
-               if(cmd_name != "pmodel")
-               if(cmd_name != "playermodel")
-               if(cmd_name != "playerskin")
-               if(cmd_name != "prespawn")
-               if(cmd_name != "spawn")
-               if(cmd_name != "begin")
-               if(cmd_name != "pings")
-               if(cmd_name != "sv_startdownload")
-               if(cmd_name != "download")
-               {
-                       print("WARNING: Invalid clientcommand by ", self.netname, ": ", s, "\n");
-                       return;
-               }
-#endif
-
-               if(self.jointime > 0 && time > self.jointime + 10 && time > self.nickspamtime) // allow any changes in the first 10 seconds since joining
-               if(cmd_name == "name" || cmd_name == "playermodel") // TODO also playerskin and color?
-               {
-                       if(self.nickspamtime == 0 || time > self.nickspamtime + autocvar_g_nick_flood_timeout)
-                               // good, no serious flood
-                               self.nickspamcount = 1;
-                       else
-                               self.nickspamcount += 1;
-                       self.nickspamtime = time + autocvar_g_nick_flood_penalty;
-
-                       if (timeoutStatus == 2) //when game is paused, no flood protection
-                               self.nickspamcount = self.nickspamtime = 0;
-               }
-
-               clientcommand(self,s);
-       }
-}
-
-void ReadyRestartForce()
-{
-       entity e;
-
-       bprint("^1Server is restarting...\n");
-
-       VoteReset();
-
-       // clear overtime
-       if (checkrules_overtimesadded > 0 && g_race_qualifying != 2) {
-               //we have to decrease timelimit to its original value again!!
-               float newTL;
-               newTL = autocvar_timelimit;
-               newTL -= checkrules_overtimesadded * autocvar_timelimit_overtime;
-               cvar_set("timelimit", ftos(newTL));
-       }
-
-       checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = 0;
-
-
-       readyrestart_happened = 1;
-       game_starttime = time;
-       if(!g_ca && !g_arena)
-               game_starttime += RESTART_COUNTDOWN;
-       restart_mapalreadyrestarted = 0; //reset this var, needed when cvar sv_ready_restart_repeatable is in use
-
-       inWarmupStage = 0; //once the game is restarted the game is in match stage
-
-       //reset the .ready status of all players (also spectators)
-       FOR_EACH_CLIENTSLOT(e)
-               e.ready = 0;
-       readycount = 0;
-       Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
-
-       if(autocvar_teamplay_lockonrestart && teamplay) {
-               lockteams = 1;
-               bprint("^1The teams are now locked.\n");
-       }
-
-       //initiate the restart-countdown-announcer entity
-       if(autocvar_sv_ready_restart_after_countdown && !g_ca && !g_arena)
-       {
-               restartTimer = spawn();
-               restartTimer.think = restartTimer_Think;
-               restartTimer.nextthink = game_starttime;
-       }
-
-       //after a restart every players number of allowed timeouts gets reset, too
-       if(autocvar_sv_timeout)
-       {
-               FOR_EACH_REALPLAYER(e)
-                       e.allowedTimeouts = autocvar_sv_timeout_number;
-       }
-
-       //reset map immediately if this cvar is not set
-       if (!autocvar_sv_ready_restart_after_countdown)
-               reset_map(TRUE);
-
-       if(autocvar_sv_eventlog)
-               GameLogEcho(":restart");
-}
-
-void ReadyRestart()
-{
-       // no arena, assault support yet...
-       if(g_arena | g_assault | gameover | intermission_running | race_completing)
-               localcmd("restart\n");
-       else
-               localcmd("\nsv_hook_gamerestart\n");
-
-       ReadyRestartForce();
-
-       // reset ALL scores, but only do that at the beginning
-       //of the countdown if sv_ready_restart_after_countdown is off!
-       //Otherwise scores could be manipulated during the countdown!
-       if (!autocvar_sv_ready_restart_after_countdown)
-               Score_ClearAll();
-}
-
-/**
- * Counts how many players are ready. If not enough players are ready, the function
- * does nothing. If all players are ready, the timelimit will be extended and the
- * restart_countdown variable is set to allow other functions like PlayerPostThink
- * to detect that the countdown is now active. If the cvar sv_ready_restart_after_countdown
- * is not set the map will be resetted.
- *
- * Function is called after the server receives a 'ready' sign from a player.
- */
-void ReadyCount()
-{
-       entity e;
-       float r, p;
-
-       r = p = 0;
-
-       FOR_EACH_REALPLAYER(e)
-       {
-               p += 1;
-               if(e.ready)
-                       r += 1;
-       }
-
-       readycount = r;
-
-       Nagger_ReadyCounted();
-
-       if(r) // at least one is ready
-       if(r == p) // and, everyone is ready
-               ReadyRestart();
-}
-
-/**
- * Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown
- * is set)
- */
-void restartTimer_Think() {
-       restart_mapalreadyrestarted = 1;
-       reset_map(TRUE);
-       Score_ClearAll();
-       remove(self);
-       return;
-}
-
-/**
- * Checks whether the player who calls the timeout is allowed to do so.
- * If so, it initializes the timeout countdown. It also checks whether another
- * timeout was already running at this time and reacts correspondingly.
- *
- * affected globals/fields: .allowedTimeouts, remainingTimeoutTime, remainingLeadTime,
- *                          timeoutInitiator, timeoutStatus, timeoutHandler
- *
- * This function is called when a player issues the calltimeout command.
- */
-void evaluateTimeout() {
-       if (inWarmupStage && !g_warmup_allow_timeout)
-               return sprint(self, "^7Error: You can not call a timeout in warmup-stage!\n");
-       if (time < game_starttime )
-               return sprint(self, "^7Error: You can not call a timeout while the map is being restarted!\n");
-       if (timeoutStatus != 2) {
-               //if the map uses a timelimit make sure that timeout cannot be called right before the map ends
-               if (autocvar_timelimit) {
-                       //a timelimit was used
-                       float myTl;
-                       myTl = autocvar_timelimit;
-
-                       float lastPossibleTimeout;
-                       lastPossibleTimeout = (myTl*60) - autocvar_sv_timeout_leadtime - 1;
-
-                       if (lastPossibleTimeout < time - game_starttime)
-                               return sprint(self, "^7Error: It is too late to call a timeout now!\n");
-               }
-       }
-       //player may not call a timeout if he has no calls left
-       if (self.allowedTimeouts < 1)
-               return sprint(self, "^7Error: You already used all your timeout calls for this map!\n");
-       //now all required checks are passed
-       self.allowedTimeouts -= 1;
-       bprint(self.netname, " ^7called a timeout (", ftos(self.allowedTimeouts), " timeouts left)!\n"); //write a bprint who started the timeout (and how many he has left)
-       remainingTimeoutTime = autocvar_sv_timeout_length;
-       remainingLeadTime = autocvar_sv_timeout_leadtime;
-       timeoutInitiator = self;
-       if (timeoutStatus == 0) { //if another timeout was already active, don't change its status (which was 1 or 2) to 1, only change it to 1 if no timeout was active yet
-               timeoutStatus = 1;
-               //create the timeout indicator which centerprints the information to all players and takes care of pausing/unpausing
-               timeoutHandler = spawn();
-               timeoutHandler.think = timeoutHandler_Think;
-       }
-       timeoutHandler.nextthink = time; //always let the entity think asap
-
-       //inform all connected clients about the timeout call
-       Announce("timeoutcalled");
-}
-
-/**
- * Checks whether a player is allowed to resume the game. If he is allowed to do it,
- * and the lead time for the timeout is still active, this countdown just will be aborted (the
- * game will never be paused). Otherwise the remainingTimeoutTime will be set to the corresponding
- * value of the cvar sv_timeout_resumetime.
- *
- * This function is called when a player issues the resumegame command.
- */
-void evaluateTimein() {
-       if (!timeoutStatus)
-               return sprint(self, "^7Error: There is no active timeout which could be aborted!\n");
-       if (self != timeoutInitiator)
-               return sprint(self, "^7Error: You may not abort the active timeout. Only the player who called it can do that!\n");
-       if (timeoutStatus == 1) {
-               remainingTimeoutTime = timeoutStatus = 0;
-               timeoutHandler.nextthink = time; //timeoutHandler has to take care of it immediately
-               bprint(strcat("^7The timeout was aborted by ", self.netname, " !\n"));
-       }
-       else if (timeoutStatus == 2) {
-               //only shorten the remainingTimeoutTime if it makes sense
-               if( remainingTimeoutTime > (autocvar_sv_timeout_resumetime + 1) ) {
-                       bprint(strcat("^1Attention: ^7", self.netname, " resumed the game! Prepare for battle!\n"));
-                       remainingTimeoutTime = autocvar_sv_timeout_resumetime;
-                       timeoutHandler.nextthink = time; //timeoutHandler has to take care of it immediately
-               }
-               else
-                       sprint(self, "^7Error: Your resumegame call was discarded!\n");
-
-       }
-}
diff --git a/qcsrc/server/command/banning.qc b/qcsrc/server/command/banning.qc
new file mode 100644 (file)
index 0000000..d575cc7
--- /dev/null
@@ -0,0 +1,222 @@
+// =====================================================
+//  Banning and kicking command code, written by Samual
+//  Last updated: December 29th, 2011
+// =====================================================
+
+void BanCommand_ban(float request, float argc, string command)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argc >= 2)
+                       {
+                               string ip = argv(1);
+                               float reason_arg, bantime;
+                               string reason;
+                               
+                               reason_arg = 2; 
+                               
+                               GET_BAN_ARG(bantime, autocvar_g_ban_default_bantime);
+                               GET_BAN_REASON(reason, "No reason provided");
+
+                               Ban_Insert(ip, bantime, reason, 1);
+                               return;
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2ban^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd ban address [time] [reason]\n");
+                       print("  No arguments required. todo\n");
+                       return;
+               }
+       }
+}
+
+void BanCommand_banlist(float request)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       Ban_View();
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd banlist\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void BanCommand_kickban(float request, float argc, string command)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argc >= 2)
+                       {
+                               entity client = GetIndexedEntity(argc, 1);
+                               float accepted = VerifyClientEntity(client, TRUE, FALSE);
+                               float reason_arg, bantime, masksize;
+                               string reason;
+                               
+                               if(accepted > 0) 
+                               {
+                                       reason_arg = next_token; 
+
+                                       GET_BAN_ARG(bantime, autocvar_g_ban_default_bantime);
+                                       GET_BAN_ARG(masksize, autocvar_g_ban_default_masksize);
+                                       GET_BAN_REASON(reason, "No reason provided");
+
+                                       Ban_KickBanClient(client, bantime, masksize, reason);
+                                       
+                                       return;
+                               }
+                               else
+                               {
+                                       print("kickban: ", GetClientErrorString(accepted, argv(1)), ".\n"); 
+                               }
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2kickban^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd kickban client [bantime] [masksize] [reason]\n");
+                       print("  No arguments required. todo\n");
+                       return;
+               }
+       }
+}
+
+void BanCommand_unban(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argc >= 2)
+                       {
+                               float who;
+                               who = stof(argv(1));
+                               Ban_Delete(who);
+                               return;
+                       }
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd unban banid\n");
+                       print("  Where 'banid' is the ID of the ban of which to remove.\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 BanCommand_(float request)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd \n");
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+*/
+
+
+// ==================================
+//  Macro system for server commands
+// ==================================
+
+// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
+#define BAN_COMMANDS(request,arguments,command) \
+       BAN_COMMAND("ban", BanCommand_ban(request, arguments, command), "Ban an IP address or a range of addresses (like 1.2.3)") \
+       BAN_COMMAND("banlist", BanCommand_banlist(request), "List all existing bans") \
+       BAN_COMMAND("kickban", BanCommand_kickban(request, arguments, command), "Disconnect a client and ban it at the same time") \
+       BAN_COMMAND("unban", BanCommand_unban(request, arguments), "Remove an existing ban") \
+       /* nothing */
+
+void BanCommand_macro_help()
+{
+       #define BAN_COMMAND(name,function,description) \
+               { print("  ^2", name, "^7: ", description, "\n"); }
+               
+       BAN_COMMANDS(0, 0, "")
+       #undef BAN_COMMAND
+       
+       return;
+}
+
+float BanCommand_macro_command(float argc, string command)
+{
+       #define BAN_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(0))) { function; return TRUE; } }
+               
+       BAN_COMMANDS(CMD_REQUEST_COMMAND, argc, command)
+       #undef BAN_COMMAND
+       
+       return FALSE;
+}
+
+float BanCommand_macro_usage(float argc)
+{
+       #define BAN_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(1))) { function; return TRUE; } }
+               
+       BAN_COMMANDS(CMD_REQUEST_USAGE, argc, "")
+       #undef BAN_COMMAND
+       
+       return FALSE;
+}
+
+void BanCommand_macro_write_aliases(float fh)
+{
+       #define BAN_COMMAND(name,function,description) \
+               { CMD_Write_Alias("qc_cmd_sv", name, description); }
+       
+       BAN_COMMANDS(0, 0, "")
+       #undef BAN_COMMAND
+       
+       return;
+}
+
+float BanCommand(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(BanCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
+       {
+               return TRUE; // handled by one of the above GenericCommand_* functions
+       }
+       
+       return FALSE;
+}
\ No newline at end of file
diff --git a/qcsrc/server/command/banning.qh b/qcsrc/server/command/banning.qh
new file mode 100644 (file)
index 0000000..7a61382
--- /dev/null
@@ -0,0 +1,15 @@
+// ====================================
+//  Declarations for kick/ban commands
+//  Last updated: December 29th, 2011
+// =====================================
+
+#define GET_BAN_ARG(v,d) if((argc > reason_arg) && ((v = stof(argv(reason_arg))) != 0)) ++reason_arg; else v = d
+#define GET_BAN_REASON(v,d) if(argc > reason_arg) v = substring(command, argv_start_index(reason_arg), strlen(command) - argv_start_index(reason_arg)); else v = d
+
+void Ban_KickBanClient(entity client, float bantime, float masksize, string reason);
+void Ban_View();
+float Ban_Insert(string ip, float bantime, string reason, float dosync);
+float Ban_Delete(float i);
+
+// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
+void BanCommand_macro_write_aliases(float fh)
\ No newline at end of file
diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc
new file mode 100644 (file)
index 0000000..efdbe95
--- /dev/null
@@ -0,0 +1,730 @@
+// =========================================================
+//  Server side networked commands code, reworked by Samual
+//  Last updated: December 28th, 2011
+// =========================================================
+
+float SV_ParseClientCommand_floodcheck()
+{
+       if not(timeout_status) // not while paused
+       {
+               if(time <= (self.cmd_floodtime + autocvar_sv_clientcommand_antispam_time))
+               {
+                       self.cmd_floodcount += 1;
+                       if(self.cmd_floodcount > autocvar_sv_clientcommand_antispam_count) { return FALSE; } // too much spam, halt
+               }
+               else
+               {
+                       self.cmd_floodtime = time;
+                       self.cmd_floodcount = 1;
+               }
+       }
+       return TRUE; // continue, as we're not flooding yet
+}
+
+
+// =======================
+//  Command Sub-Functions
+// =======================
+
+void ClientCommand_autoswitch(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(1) != "")
+                       {
+                               self.autoswitch = InterpretBoolean(argv(1));
+                               sprint(self, strcat("^1autoswitch is currently turned ", (self.autoswitch ? "on" : "off"), ".\n"));
+                               return;
+                       }
+               }
+                       
+               default:
+                       sprint(self, "Incorrect parameters for ^2autoswitch^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd autoswitch selection\n");
+                       sprint(self, "  Where 'selection' controls if autoswitch is on or off.\n"); 
+                       return;
+               }
+       }
+}
+
+void ClientCommand_checkfail(float request, string command) // internal command, used only by code
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       print(sprintf("CHECKFAIL: %s (%s) epically failed check %s\n", self.netname, self.netaddress, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1))));
+                       self.checkfail = 1;
+                       return; // never fall through to usage
+               }
+                       
+               default:
+                       sprint(self, "Incorrect parameters for ^2checkfail^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd checkfail <message>\n");
+                       sprint(self, "  Where 'message' is the message reported by client about the fail.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_clientversion(float request, float argc) // internal command, used only by code
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(1) != "")
+                       {
+                               if(self.flags & FL_CLIENT)
+                               {
+                                       self.version = ((argv(1) == "$gameversion") ? 1 : stof(argv(1)));
+                                       
+                                       if(self.version < autocvar_gameversion_min || self.version > autocvar_gameversion_max)
+                                       {
+                                               self.version_mismatch = 1;
+                                               ClientKill_TeamChange(-2); // observe
+                                       } 
+                                       else if(autocvar_g_campaign || autocvar_g_balance_teams || autocvar_g_balance_teams_force) 
+                                       {
+                                               //JoinBestTeam(self, FALSE, TRUE);
+                                       } 
+                                       else if(teamplay && !autocvar_sv_spectate && !(self.team_forced > 0)) 
+                                       {
+                                               self.classname = "observer"; // really?
+                                               stuffcmd(self, "menu_showteamselect\n");
+                                       }
+                               }
+                               
+                               return;
+                       }
+               }
+                       
+               default:
+                       sprint(self, "Incorrect parameters for ^2clientversion^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd clientversion version\n");
+                       sprint(self, "  Where 'version' is the game version reported by self.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_getmapvotepic(float request, float argc) // internal command, used only by code
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(1) != "")
+                       {
+                               if(intermission_running)                                
+                                       MapVote_SendPicture(stof(argv(1)));
+
+                               return;
+                       }
+               }
+                       
+               default:
+                       sprint(self, "Incorrect parameters for ^2getmapvotepic^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd getmapvotepic mapid\n");
+                       sprint(self, "  Where 'mapid' is the id number of the map to request an image of on the map vote selection menu.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_join(float request) // legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(self.flags & FL_CLIENT)
+                       {
+                               if(self.classname != "player" && !lockteams && !g_arena)
+                               {
+                                       if(nJoinAllowed(1)) 
+                                       {
+                                               if(g_ca) { self.caplayer = 1; }
+                                               if(autocvar_g_campaign) { campaign_bots_may_start = 1; }
+                                               
+                                               self.classname = "player";
+                                               PlayerScore_Clear(self);
+                                               bprint ("^4", self.netname, "^4 is playing now\n");
+                                               PutClientInServer();
+                                       }
+                                       else 
+                                       {
+                                               //player may not join because of g_maxplayers is set
+                                               centerprint(self, PREVENT_JOIN_TEXT);
+                                       }
+                               }
+                       }
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd join\n");
+                       sprint(self, "  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_ready(float request) // todo: anti-spam for toggling readyness
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(self.flags & FL_CLIENT)
+                       {
+                               if(inWarmupStage || autocvar_sv_ready_restart || g_race_qualifying == 2)
+                               {
+                                       if(!readyrestart_happened || autocvar_sv_ready_restart_repeatable)
+                                       {
+                                               if (self.ready) // toggle
+                                               {
+                                                       self.ready = FALSE;
+                                                       bprint(self.netname, "^2 is ^1NOT^2 ready\n");
+                                               }
+                                               else
+                                               {
+                                                       self.ready = TRUE;
+                                                       bprint(self.netname, "^2 is ready\n");
+                                               }
+
+                                               // cannot reset the game while a timeout is active!
+                                               if not(timeout_status)
+                                                       ReadyCount();
+                                       } else {
+                                               sprint(self, "^1Game has already been restarted\n");
+                                       }
+                               }
+                       }
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd ready\n");
+                       sprint(self, "  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_reportcvar(float request, float argc, string command)
+{      
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(1) != "")
+                       {
+                               float tokens;
+                               string s;
+                               
+                               if(substring(argv(2), 0, 1) == "$") // undefined cvar: use the default value on the server then
+                               {
+                                       s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
+                                       tokens = tokenize_console(s);
+                               }
+                               
+                               GetCvars(1);
+                               
+                               return;
+                       }
+               }
+                       
+               default:
+                       sprint(self, "Incorrect parameters for ^2reportcvar^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd reportcvar <cvar>\n");
+                       sprint(self, "  Where 'cvar' is the cvar plus arguments to send to the server.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_say(float request, float argc, string command)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argc >= 2) { Say(self, FALSE, world, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1); }
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd say <message>\n");
+                       sprint(self, "  Where 'message' is the string of text to say.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_say_team(float request, float argc, string command)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argc >= 2) { Say(self, TRUE, world, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1); }
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd say_team <message>\n");
+                       sprint(self, "  Where 'message' is the string of text to say.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_selectteam(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(1) != "")
+                       {
+                               if(self.flags & FL_CLIENT)
+                               {
+                                       if(teamplay)
+                                               if not(self.team_forced > 0) 
+                                                       if not(lockteams) 
+                                                       {
+                                                               float selection;
+                                                               
+                                                               switch(argv(1))
+                                                               {
+                                                                       case "red": selection = COLOR_TEAM1; break;
+                                                                       case "blue": selection = COLOR_TEAM2; break;
+                                                                       case "yellow": selection = COLOR_TEAM3; break;
+                                                                       case "pink": selection = COLOR_TEAM4; break;
+                                                                       case "auto": selection = (-1); break;
+                                                                       
+                                                                       default: break;
+                                                               }
+                                                               
+                                                               if(selection)
+                                                               {
+                                                                       if(self.team == selection && self.deadflag == DEAD_NO)
+                                                                               sprint(self, "^7You already are on that team.\n");
+                                                                       else if(self.wasplayer && autocvar_g_changeteam_banned)
+                                                                               sprint(self, "^1You cannot change team, forbidden by the server.\n");
+                                                                       else
+                                                                               ClientKill_TeamChange(selection);
+                                                               }
+                                                       }
+                                                       else
+                                                               sprint(self, "^7The game has already begun, you must wait until the next map to be able to join a team.\n");
+                                               else
+                                                       sprint(self, "^7selectteam can not be used as your team is forced\n");
+                                       else
+                                               sprint(self, "^7selectteam can only be used in teamgames\n");
+                               }
+                               return; 
+                       }
+               }
+
+               default:
+                       sprint(self, "Incorrect parameters for ^2selectteam^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd selectteam team\n");
+                       sprint(self, "  Where 'team' is the prefered team to try and join.\n");
+                       sprint(self, "  Full list of options here: \"red, blue, yellow, pink, auto\"\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_selfstuff(float request, string command)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(1) != "")
+                       {
+                               stuffcmd(self, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
+                               return;
+                       }
+               }
+                       
+               default:
+                       sprint(self, "Incorrect parameters for ^2selectteam^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd selfstuff <command>\n");
+                       sprint(self, "  Where 'command' is the string to be stuffed to your client.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_sentcvar(float request, float argc, string command)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(1) != "")
+                       {
+                               float tokens;
+                               string s;
+                               
+                               if(argc == 2) // undefined cvar: use the default value on the server then
+                               {
+                                       s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
+                                       tokens = tokenize_console(s);
+                               }
+                               
+                               GetCvars(1);
+                               
+                               return;
+                       }
+               }
+                       
+               default:
+                       sprint(self, "Incorrect parameters for ^2sentcvar^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd sentcvar <cvar>\n");
+                       sprint(self, "  Where 'cvar' is the cvar plus arguments to send to the server.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_spectate(float request) // legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(self.flags & FL_CLIENT)
+                       {
+                               if(g_arena) { return; } 
+                               if(g_lms)
+                               {
+                                       if(self.lms_spectate_warning)
+                                       {
+                                               // mark player as spectator
+                                               PlayerScore_Add(self, SP_LMS_RANK, 666 - PlayerScore_Add(self, SP_LMS_RANK, 0));
+                                       }
+                                       else
+                                       {
+                                               self.lms_spectate_warning = 1;
+                                               sprint(self, "WARNING: you won't be able to enter the game again after spectating in LMS. Use the same command again to spectate anyway.\n");
+                                               return;
+                                       }
+                               }
+                               
+                               if(self.classname == "player" && autocvar_sv_spectate == 1) 
+                                       ClientKill_TeamChange(-2); // observe
+                               
+                               // in CA, allow a dead player to move to spectatators (without that, caplayer!=0 will be moved back to the player list)
+                               // note: if arena game mode is ever done properly, this needs to be removed.
+                               if(g_ca && self.caplayer && (self.classname == "spectator" || self.classname == "observer"))
+                               {
+                                       sprint(self, "WARNING: you will spectate in the next round.\n");
+                                       self.caplayer = 0;
+                               }
+                       }
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd spectate\n");
+                       sprint(self, "  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_suggestmap(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(1) != "")
+                       {
+                               sprint(self, strcat(MapVote_Suggest(argv(1)), "\n"));
+                               return;
+                       }
+               }
+                       
+               default:
+                       sprint(self, "Incorrect parameters for ^2suggestmap^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd suggestmap map\n");
+                       sprint(self, "  Where 'map' is the name of the map to suggest.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_tell(float request, float argc, string command)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argc >= 3)
+                       {
+                               entity tell_to = GetIndexedEntity(argc, 1);
+                               float tell_accepted = VerifyClientEntity(tell_to, TRUE, FALSE);
+                               
+                               if(tell_accepted > 0) // the target is a real client
+                               {
+                                       if(tell_to != self) // and we're allowed to send to them :D
+                                       {
+                                               Say(self, FALSE, tell_to, substring(command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token)), TRUE);
+                                               return;
+                                       }
+                                       else { print_to(self, "You can't ^2tell^7 a message to yourself."); return; }
+                               }
+                               else if(strtolower(argv(1)) == "world") 
+                               { 
+                                       trigger_magicear_processmessage_forallears(self, -1, world, substring(command, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken)));
+                                       return;
+                               }
+                               else { print_to(self, strcat("tell: ", GetClientErrorString(tell_accepted, argv(1)), ".")); return; }
+                       }
+               }
+                       
+               default:
+                       sprint(self, "Incorrect parameters for ^2tell^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd tell client <message>\n");
+                       sprint(self, "  Where 'client' is the entity number or name of the player to send 'message' to.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_voice(float request, float argc, string command) // legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(1) != "")
+                       {
+                               if(argc >= 3)
+                                       VoiceMessage(argv(1), substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
+                               else
+                                       VoiceMessage(argv(1), "");
+                                       
+                               return;
+                       }
+               }
+                       
+               default:
+                       sprint(self, "Incorrect parameters for ^2voice^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd voice messagetype <soundname>\n");
+                       sprint(self, "  'messagetype' is the type of broadcast to do, like team only or such,\n");
+                       sprint(self, "  and 'soundname' is the string/filename of the sound/voice message to play.\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 ClientCommand_(float request)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd \n");
+                       sprint(self, "  No arguments required.\n");
+                       return;
+               }
+       }
+}
+*/
+
+
+// =====================================
+//  Macro system for networked 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,command) \
+       CLIENT_COMMAND("autoswitch", ClientCommand_autoswitch(request, arguments), "Whether or not to switch automatically when getting a better weapon") \
+       CLIENT_COMMAND("checkfail", ClientCommand_checkfail(request, command), "Report if a client-side check failed") \
+       CLIENT_COMMAND("clientversion", ClientCommand_clientversion(request, arguments), "Release version of the game") \
+       CLIENT_COMMAND("getmapvotepic", ClientCommand_getmapvotepic(request, arguments), "Retrieve mapshot picture from the server") \
+       CLIENT_COMMAND("join", ClientCommand_join(request), "Become a player in the game") \
+       CLIENT_COMMAND("ready", ClientCommand_ready(request), "Qualify as ready to end warmup stage (or restart server if allowed)") \
+       CLIENT_COMMAND("reportcvar", ClientCommand_reportcvar(request, arguments, command), "Old system for sending a client cvar to the server") \
+       CLIENT_COMMAND("say", ClientCommand_say(request, arguments, command), "Print a message to chat to all players") \
+       CLIENT_COMMAND("say_team", ClientCommand_say_team(request, arguments, command), "Print a message to chat to all team mates") \
+       CLIENT_COMMAND("selectteam", ClientCommand_selectteam(request, arguments), "Attempt to choose a team to join into") \
+       CLIENT_COMMAND("selfstuff", ClientCommand_selfstuff(request, command), "Stuffcmd a command to your own client") \
+       CLIENT_COMMAND("sentcvar", ClientCommand_sentcvar(request, arguments, command), "New system for sending a client cvar to the server") \
+       CLIENT_COMMAND("spectate", ClientCommand_spectate(request), "Become an observer") \
+       CLIENT_COMMAND("suggestmap", ClientCommand_suggestmap(request, arguments), "Suggest a map to the mapvote at match end") \
+       CLIENT_COMMAND("tell", ClientCommand_tell(request, arguments, command), "Send a message directly to a player") \
+       CLIENT_COMMAND("voice", ClientCommand_voice(request, arguments, command), "Send voice message via sound") \
+       /* nothing */
+       
+void ClientCommand_macro_help()
+{
+       #define CLIENT_COMMAND(name,function,description) \
+               { sprint(self, "  ^2", name, "^7: ", description, "\n"); }
+               
+       CLIENT_COMMANDS(0, 0, "")
+       #undef CLIENT_COMMAND
+       
+       return;
+}
+
+float ClientCommand_macro_command(float argc, string command)
+{
+       #define CLIENT_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(0))) { function; return TRUE; } }
+               
+       CLIENT_COMMANDS(CMD_REQUEST_COMMAND, argc, command)
+       #undef CLIENT_COMMAND
+       
+       return FALSE;
+}
+
+float ClientCommand_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;
+}
+
+void ClientCommand_macro_write_aliases(float fh)
+{
+       #define CLIENT_COMMAND(name,function,description) \
+               { CMD_Write_Alias("qc_cmd_cmd", name, description); } 
+               
+       CLIENT_COMMANDS(0, 0, "")
+       #undef CLIENT_COMMAND
+       
+       return;
+}
+
+// ======================================
+//  Main Function Called By Engine (cmd)
+// ======================================
+// If this function exists, server game code parses clientcommand before the engine code gets it.
+
+void SV_ParseClientCommand(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
+       
+       // for floodcheck
+       switch(strtolower(argv(0)))
+       {
+               // exempt commands which are not subject to floodcheck
+               case "begin": break; // handled by engine in host_cmd.c
+               case "download": break; // handled by engine in cl_parse.c
+               case "getmapvotepic": break; // handled by server in this file
+               case "pause": break; // handled by engine in host_cmd.c
+               case "prespawn": break; // handled by engine in host_cmd.c
+               case "reportcvar": break; // handled by server in this file
+               case "sentcvar": break; // handled by server in this file
+               case "spawn": break; // handled by engine in host_cmd.c
+               
+               default: 
+                       if(SV_ParseClientCommand_floodcheck())
+                               break; // "TRUE": continue, as we're not flooding yet
+                       else
+                               return print("^1ERROR: ^7ANTISPAM CAUGHT: ", command, ".\n"); // "FALSE": not allowed to continue, halt TODO
+       }
+       
+       /* NOTE: should this be disabled? It can be spammy perhaps, but hopefully it's okay for now */
+       if(argv(0) == "help") 
+       {
+               if(argc == 1) 
+               {
+                       sprint(self, "\nClient networked commands:\n");
+                       ClientCommand_macro_help();
+                       
+                       sprint(self, "\nCommon networked commands:\n");
+                       CommonCommand_macro_help(self);
+                       
+                       sprint(self, "\nUsage:^3 cmd COMMAND...^7, where possible commands are listed above.\n");
+                       sprint(self, "For help about a specific command, type cmd help COMMAND\n");
+                       return;
+               } 
+               else if(CommonCommand_macro_usage(argc, self)) // Instead of trying to call a command, we're going to see detailed information about it
+               {
+                       return;
+               }
+               else if(ClientCommand_macro_usage(argc)) // same, but for normal commands now
+               {
+                       return;
+               }
+       } 
+       else if(MUTATOR_CALLHOOK(SV_ParseClientCommand))
+       {
+               return; // handled by a mutator
+       }
+       else if(CheatCommand(argc)) 
+       {
+               return; // handled by server/cheats.qc
+       }
+       else if(CommonCommand_macro_command(argc, self, command))
+       {
+               return; // handled by server/command/common.qc
+       }
+       else if(ClientCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
+       {
+               return; // handled by one of the above ClientCommand_* functions
+       }
+       else
+               clientcommand(self, command);
+}
\ No newline at end of file
diff --git a/qcsrc/server/command/cmd.qh b/qcsrc/server/command/cmd.qh
new file mode 100644 (file)
index 0000000..e64cbc2
--- /dev/null
@@ -0,0 +1,14 @@
+// =================================================
+//  Declarations for server side networked commands
+//  Last updated: December 26th, 2011
+// =================================================
+
+.float cmd_floodtime;
+.float cmd_floodcount;
+.float lms_spectate_warning;
+.float checkfail;
+
+string MapVote_Suggest(string m);
+
+// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
+void ClientCommand_macro_write_aliases(float fh);
\ No newline at end of file
diff --git a/qcsrc/server/command/common.qc b/qcsrc/server/command/common.qc
new file mode 100644 (file)
index 0000000..fd516c1
--- /dev/null
@@ -0,0 +1,785 @@
+// ====================================================
+//  Shared code for server commands, written by Samual
+//  Last updated: December 27th, 2011
+// ====================================================
+
+// select the proper prefix for usage and other messages
+string GetCommandPrefix(entity caller)
+{
+       if(caller)
+               return "cmd";
+       else
+               return "sv_cmd";
+}
+
+// if client return player nickname, or if server return admin nickname
+string GetCallerName(entity caller)
+{
+       if(caller)
+               return caller.netname;
+       else
+               return admin_name(); //((autocvar_sv_adminnick != "") ? autocvar_sv_adminnick : autocvar_hostname);
+}
+
+// verify that the client provided is acceptable for use
+float VerifyClientEntity(entity client, float must_be_real, float must_be_bots)
+{
+       if not(client.flags & FL_CLIENT)
+               return CLIENT_DOESNT_EXIST;
+       else if(must_be_real && (clienttype(client) != CLIENTTYPE_REAL))
+               return CLIENT_NOT_REAL;
+       else if(must_be_bots && (clienttype(client) != CLIENTTYPE_BOT))
+               return CLIENT_NOT_BOT;
+               
+       return CLIENT_ACCEPTABLE;
+}
+
+// if the client is not acceptable, return a string to be used for error messages
+string GetClientErrorString(float clienterror, string original_input)
+{
+       switch(clienterror)
+       {
+               case CLIENT_DOESNT_EXIST: { return strcat("Client '", original_input, "' doesn't exist"); }
+               case CLIENT_NOT_REAL: { return strcat("Client '", original_input, "' is not real"); }
+               case CLIENT_NOT_BOT: { return strcat("Client '", original_input, "' is not a bot"); }
+               default: { return "Incorrect usage of GetClientErrorString"; }
+       }
+}
+
+// is this entity number even in the possible range of entities?
+float VerifyClientNumber(float tmp_number)
+{
+       if((tmp_number < 1) || (tmp_number > maxclients))
+               return FALSE;
+       else
+               return TRUE;
+}
+
+entity GetIndexedEntity(float argc, float start_index)
+{
+       entity tmp_player, selection;
+       float tmp_number, index;
+       string tmp_string;
+       
+       next_token = -1;
+       index = start_index;
+       
+       if(argc > start_index)
+       {
+               if(substring(argv(index), 0, 1) == "#")
+               {
+                       tmp_string = substring(argv(index), 1, -1);
+                       ++index;
+                       
+                       if(tmp_string != "") // is it all one token? like #1
+                       {
+                               tmp_number = stof(tmp_string);
+                       }
+                       else if(argc > index) // no, it's two tokens? # 1
+                       {
+                               tmp_number = stof(argv(index));
+                               ++index;
+                       }
+               }
+               else // maybe it's ONLY a number?
+               {
+                       tmp_number = stof(argv(index));
+                       ++index;
+               }
+               
+               if(VerifyClientNumber(tmp_number))
+               {
+                       selection = edict_num(tmp_number); // yes, it was a number
+               }
+               else // no, maybe it's a name?
+               {
+                       FOR_EACH_CLIENT(tmp_player)
+                               if (strdecolorize(tmp_player.netname) == strdecolorize(argv(start_index)))
+                                       selection = tmp_player;
+                                       
+                       index = (start_index + 1);
+               }
+       }
+       
+       next_token = index;
+       print(strcat("start_index: ", ftos(start_index), ", next_token: ", ftos(next_token), ", edict: ", ftos(num_for_edict(selection)), ".\n"));
+       return selection;
+}
+
+// find a player which matches the input string, and return their entity
+entity GetFilteredEntity(string input)
+{
+       entity tmp_player, selection;
+       float tmp_number;
+       
+       if(substring(input, 0, 1) == "#")
+               tmp_number = stof(substring(input, 1, -1));
+       else
+               tmp_number = stof(input);
+       
+       if(VerifyClientNumber(tmp_number))
+       {
+               selection = edict_num(tmp_number);
+       }
+       else
+       {
+               FOR_EACH_CLIENT(tmp_player)
+                       if (strdecolorize(tmp_player.netname) == strdecolorize(input))
+                               selection = tmp_player;
+       }
+       
+       return selection;
+}
+
+// same thing, but instead return their edict number
+float GetFilteredNumber(string input)
+{
+       entity selection = GetFilteredEntity(input);
+       float output;
+       
+       if(selection) { output = num_for_edict(selection); }
+
+       return output;
+}
+
+// switch between sprint and print depending on whether the reciever is the server or a player
+void print_to(entity to, string input)
+{
+    if(to)
+        sprint(to, strcat(input, "\n"));
+    else
+        print(input, "\n");
+}
+
+// ==========================================
+//  Supporting functions for common commands
+// ==========================================
+
+// used by CommonCommand_timeout() and CommonCommand_timein() to handle game pausing and messaging and such.
+void timeout_handler_reset()
+{
+       entity tmp_player;
+       
+       timeout_caller = world;
+       timeout_time = 0;
+       timeout_leadtime = 0;
+       
+       FOR_EACH_REALPLAYER(tmp_player)
+               Send_CSQC_Centerprint_Generic_Expire(tmp_player, CPID_TIMEOUT_COUNTDOWN);
+                               
+       remove(self);
+}
+
+void timeout_handler_think() 
+{
+       entity tmp_player;
+       
+       switch(timeout_status)
+       {
+               case TIMEOUT_ACTIVE:
+               {
+                       if(timeout_time > 0) // countdown is still going
+                       {
+                               FOR_EACH_REALPLAYER(tmp_player)
+                                       Send_CSQC_Centerprint_Generic(tmp_player, CPID_TIMEOUT_COUNTDOWN, "Timeout ends in %d seconds!", 1, timeout_time);
+
+                               if(timeout_time == autocvar_sv_timeout_resumetime) // play a warning sound when only <sv_timeout_resumetime> seconds are left
+                                       Announce("prepareforbattle");
+
+                               self.nextthink = time + TIMEOUT_SLOWMO_VALUE; // think again in one second
+                               timeout_time -= 1; // decrease the time counter
+                       }
+                       else // time to end the timeout
+                       {
+                               timeout_status = TIMEOUT_INACTIVE;
+                               
+                               // reset the slowmo value back to normal
+                               cvar_set("slowmo", ftos(orig_slowmo));
+                               
+                               // unlock the view for players so they can move around again
+                               FOR_EACH_REALPLAYER(tmp_player) 
+                                       tmp_player.fixangle = FALSE;
+                                       
+                               timeout_handler_reset();
+                       }
+                       
+                       return;
+               }
+               
+               case TIMEOUT_LEADTIME:
+               {
+                       if(timeout_leadtime > 0) // countdown is still going
+                       {
+                               // centerprint the information to every player
+                               FOR_EACH_REALPLAYER(tmp_player) 
+                                       Send_CSQC_Centerprint_Generic(tmp_player, CPID_TIMEOUT_COUNTDOWN, "Timeout begins in %d seconds!", 1, timeout_leadtime);
+                               
+                               self.nextthink = time + 1; // think again in one second
+                               timeout_leadtime -= 1; // decrease the time counter
+                       }
+                       else // time to begin the timeout
+                       {
+                               timeout_status = TIMEOUT_ACTIVE;
+                               
+                               // set the slowmo value to the timeout default slowmo value
+                               cvar_set("slowmo", ftos(TIMEOUT_SLOWMO_VALUE));
+                               
+                               // reset all the flood variables
+                               FOR_EACH_CLIENT(tmp_player)
+                                       tmp_player.nickspamcount = tmp_player.nickspamtime = tmp_player.floodcontrol_chat =
+                                       tmp_player.floodcontrol_chatteam = tmp_player.floodcontrol_chattell = 
+                                       tmp_player.floodcontrol_voice = tmp_player.floodcontrol_voiceteam = 0;
+                                       
+                               // copy .v_angle to .lastV_angle for every player in order to fix their view during pause (see PlayerPreThink)
+                               FOR_EACH_REALPLAYER(tmp_player) 
+                                       tmp_player.lastV_angle = tmp_player.v_angle;
+                               
+                               self.nextthink = time; // think again next frame to handle it under TIMEOUT_ACTIVE code
+                       }
+                       
+                       return;
+               }
+               
+               
+               case TIMEOUT_INACTIVE:
+               default:
+               {
+                       timeout_handler_reset();
+                       return;
+               }
+       }
+}
+
+
+
+// ===================================================
+//  Common commands used in both sv_cmd.qc and cmd.qc
+// ===================================================
+
+void CommonCommand_cvar_changes(float request, entity caller)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       print_to(caller, cvar_changes);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " cvar_changes"));
+                       print_to(caller, "  No arguments required.");
+                       print_to(caller, "See also: ^2cvar_purechanges^7");
+                       return;
+               }
+       }
+}
+
+void CommonCommand_cvar_purechanges(float request, entity caller)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       print_to(caller, cvar_purechanges);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " cvar_purechanges"));
+                       print_to(caller, "  No arguments required.");
+                       print_to(caller, "See also: ^2cvar_changes^7");
+                       return;
+               }
+       }
+}
+
+void CommonCommand_info(float request, entity caller, float argc) // legacy
+{      
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       string command = builtin_cvar_string(strcat("sv_info_", argv(1))); 
+                       
+                       if(command)
+                               wordwrap_sprint(command, 1000); 
+                       else
+                               print_to(caller, "ERROR: unsupported info command");
+                               
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " info request"));
+                       print_to(caller, "  Where 'request' is the suffixed string appended onto the request for cvar.");
+                       return;
+               }
+       }
+}
+
+void CommonCommand_ladder(float request, entity caller)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       print_to(caller, ladder_reply);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " ladder"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void CommonCommand_lsmaps(float request, entity caller)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       print_to(caller, lsmaps_reply);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " lsmaps"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void CommonCommand_lsnewmaps(float request, entity caller)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       print_to(caller, lsnewmaps_reply);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " lsnewmaps"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void CommonCommand_maplist(float request, entity caller)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       print_to(caller, maplist_reply);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " maplist"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+/*
+void GameCommand_rankings(float request) // this is OLD.... jeez.
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       strunzone(rankings_reply);
+                       rankings_reply = strzone(getrankings());
+                       print(rankings_reply);
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd rankings");
+                       print("  No arguments required.");
+                       return;
+               }
+       }
+}
+*/
+
+void CommonCommand_rankings(float request, entity caller)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       print_to(caller, rankings_reply);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " rankings"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void CommonCommand_records(float request, entity caller)
+{      
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       float i;
+                       
+                       for(i = 0; i < 10; ++i)
+                               print_to(caller, records_reply[i]);
+                               
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " records"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void CommonCommand_teamstatus(float request, entity caller)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       Score_NicePrint(caller);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " teamstatus"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void CommonCommand_time(float request, entity caller)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       print_to(caller, strcat("time = ", ftos(time)));
+                       print_to(caller, strcat("frame start = ", ftos(gettime(GETTIME_FRAMESTART))));
+                       print_to(caller, strcat("realtime = ", ftos(gettime(GETTIME_REALTIME))));
+                       print_to(caller, strcat("hires = ", ftos(gettime(GETTIME_HIRES))));
+                       print_to(caller, strcat("uptime = ", ftos(gettime(GETTIME_UPTIME))));
+                       print_to(caller, strcat("localtime = ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y")));
+                       print_to(caller, strcat("gmtime = ", strftime(FALSE, "%a %b %e %H:%M:%S %Z %Y")));
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " time"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void CommonCommand_timein(float request, entity caller)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(!caller || autocvar_sv_timeout)
+                       {
+                               if not(timeout_status) { print_to(caller, "^7Error: There is no active timeout called."); }
+                               else if(caller && (caller != timeout_caller)) { print_to(caller, "^7Error: You are not allowed to stop the active timeout."); }
+                                       
+                               else // everything should be okay, continue aborting timeout
+                               {
+                                       switch(timeout_status)
+                                       {
+                                               case TIMEOUT_LEADTIME:
+                                               {
+                                                       timeout_status = TIMEOUT_INACTIVE;
+                                                       timeout_time = 0;
+                                                       timeout_handler.nextthink = time; // timeout_handler has to take care of it immediately
+                                                       bprint(strcat("^7The timeout was aborted by ", caller.netname, " !\n"));
+                                                       return;
+                                               }
+                                               
+                                               case TIMEOUT_ACTIVE:
+                                               {
+                                                       timeout_time = autocvar_sv_timeout_resumetime;
+                                                       timeout_handler.nextthink = time; // timeout_handler has to take care of it immediately
+                                                       bprint(strcat("^1Attention: ^7", caller.netname, " resumed the game! Prepare for battle!\n"));
+                                                       return;
+                                               }
+                                               
+                                               default: dprint("timeout status was inactive, but this code was executed anyway?"); return;
+                                       }
+                               }
+                       }
+                       else { print_to(caller, "^1Timeins are not allowed to be called, enable them with sv_timeout 1.\n"); }
+                       
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " timein"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void CommonCommand_timeout(float request, entity caller) // DEAR GOD THIS COMMAND IS TERRIBLE.
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(!caller || autocvar_sv_timeout)
+                       {
+                               float last_possible_timeout = ((autocvar_timelimit * 60) - autocvar_sv_timeout_leadtime - 1);
+                               
+                               if(timeout_status) { print_to(caller, "^7Error: A timeout is already active."); }
+                               else if(vote_called) { print_to(caller, "^7Error: You can not call a timeout while a vote is active."); }
+                               else if(inWarmupStage && !g_warmup_allow_timeout) { print_to(caller, "^7Error: You can not call a timeout in warmup-stage."); }
+                               else if(time < game_starttime) { print_to(caller, "^7Error: You can not call a timeout while the map is being restarted."); }
+                               else if(caller && (caller.allowed_timeouts < 1)) { print_to(caller, "^7Error: You already used all your timeout calls for this map."); }
+                               else if(caller && (caller.classname != "player")) { print_to(caller, "^7Error: You must be a player to call a timeout."); }
+                               else if((autocvar_timelimit) && (last_possible_timeout < time - game_starttime)) { print_to(caller, "^7Error: It is too late to call a timeout now!"); }
+                               
+                               else // everything should be okay, proceed with starting the timeout
+                               {                                       
+                                       if(caller) { caller.allowed_timeouts -= 1; }
+                                       
+                                       bprint(GetCallerName(caller), " ^7called a timeout", (caller ? strcat(" (", ftos(caller.allowed_timeouts), " timeout(s) left)") : string_null), "!\n"); // write a bprint who started the timeout (and how many they have left)
+                                       
+                                       timeout_status = TIMEOUT_LEADTIME;
+                                       timeout_caller = caller;
+                                       timeout_time = autocvar_sv_timeout_length;
+                                       timeout_leadtime = autocvar_sv_timeout_leadtime;
+                                       
+                                       timeout_handler = spawn();
+                                       timeout_handler.think = timeout_handler_think;
+                                       timeout_handler.nextthink = time; // always let the entity think asap
+
+                                       Announce("timeoutcalled");
+                               }
+                       }
+                       else { print_to(caller, "^1Timeouts are not allowed to be called, enable them with sv_timeout 1.\n"); }
+                       
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " timeout"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void CommonCommand_who(float request, entity caller, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       float total_listed_players, tmp_hours, tmp_minutes, tmp_seconds, is_bot;
+                       entity tmp_player;
+                       
+                       float privacy = (caller && autocvar_sv_status_privacy);
+                       string separator = strreplace("%", " ", strcat((argv(1) ? argv(1) : " "), "^7"));
+                       string tmp_netaddress, tmp_crypto_idfp;
+                       
+                       print_to(caller, strcat("List of client information", (privacy ? " (some data is hidden for privacy)" : string_null), ":"));
+                       print_to(caller, sprintf(strreplace(" ", separator, " %-4s %-20s %-5s %-3s %-9s %-16s %s "), 
+                               "ent", "nickname", "ping", "pl", "time", "ip", "crypto_id"));
+                       
+                       FOR_EACH_CLIENT(tmp_player)
+                       {
+                               is_bot = (clienttype(tmp_player) == CLIENTTYPE_BOT);
+                               
+                               if(is_bot)
+                               {
+                                       tmp_netaddress = "null/botclient";
+                                       tmp_crypto_idfp = "null/botclient";
+                               }
+                               else if(privacy)
+                               {
+                                       tmp_netaddress = "hidden";
+                                       tmp_crypto_idfp = "hidden";
+                               }
+                               else
+                               {
+                                       tmp_netaddress = tmp_player.netaddress;
+                                       tmp_crypto_idfp = tmp_player.crypto_idfp;
+                               }
+                               
+                               tmp_hours = tmp_minutes = tmp_seconds = 0;
+                               
+                               tmp_seconds = floor(time - tmp_player.jointime);
+                               tmp_minutes = floor(tmp_seconds / 60);
+                               tmp_hours = floor(tmp_minutes / 60);
+
+                               if(tmp_minutes) { tmp_seconds -= (tmp_minutes * 60); }                          
+                               if(tmp_hours) { tmp_minutes -= (tmp_hours * 60); }
+
+                               print_to(caller, sprintf(strreplace(" ", separator, " #%-3d %-20.20s %-5d %-3d %-9s %-16s %s "), 
+                                       num_for_edict(tmp_player), 
+                                       tmp_player.netname,
+                                       tmp_player.ping, 
+                                       tmp_player.ping_packetloss, 
+                                       sprintf("%02d:%02d:%02d", tmp_hours, tmp_minutes, tmp_seconds),
+                                       tmp_netaddress,
+                                       tmp_crypto_idfp));
+                               
+                               ++total_listed_players;
+                       }
+                       
+                       print_to(caller, strcat("Finished listing ", ftos(total_listed_players), " client(s) out of ", ftos(maxclients), " slots."));
+                       
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " who [separator]"));
+                       print_to(caller, "  Where 'separator' is the optional string to separate the values with, default is a space.");
+                       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 CommonCommand_(float request, entity caller)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " "));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+*/
+
+
+// ==================================
+//  Macro system for common commands
+// ==================================
+
+// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
+#define COMMON_COMMANDS(request,caller,arguments,command) \
+       COMMON_COMMAND("cvar_changes", CommonCommand_cvar_changes(request, caller), "Prints a list of all changed server cvars") \
+       COMMON_COMMAND("cvar_purechanges", CommonCommand_cvar_purechanges(request, caller), "Prints a list of all changed gameplay cvars") \
+       COMMON_COMMAND("info", CommonCommand_info(request, caller, arguments), "Request for unique server information set up by admin") \
+       COMMON_COMMAND("ladder", CommonCommand_ladder(request, caller), "Get information about top players if supported") \
+       COMMON_COMMAND("lsmaps", CommonCommand_lsmaps(request, caller), "List maps which can be used with the current game mode") \
+       COMMON_COMMAND("lsnewmaps", CommonCommand_lsnewmaps(request, caller), "List maps which have no records or are seemingly unplayed yet") \
+       COMMON_COMMAND("maplist", CommonCommand_maplist(request, caller), "Display full server maplist reply") \
+       COMMON_COMMAND("rankings", CommonCommand_rankings(request, caller), "Print information about rankings") \
+       COMMON_COMMAND("records", CommonCommand_records(request, caller), "List top 10 records for the current map") \
+       COMMON_COMMAND("teamstatus", CommonCommand_teamstatus(request, caller), "Show information about player and team scores") \
+       COMMON_COMMAND("time", CommonCommand_time(request, caller), "Print different formats/readouts of time") \
+       COMMON_COMMAND("timein", CommonCommand_timein(request, caller), "Resume the game from being paused with a timeout") \
+       COMMON_COMMAND("timeout", CommonCommand_timeout(request, caller), "Call a timeout which pauses the game for certain amount of time unless unpaused") \
+       COMMON_COMMAND("vote", VoteCommand(request, caller, arguments, command), "Request an action to be voted upon by players") \
+       COMMON_COMMAND("who", CommonCommand_who(request, caller, arguments), "Display detailed client information about all players") \
+       /* nothing */
+
+void CommonCommand_macro_help(entity caller)
+{
+       #define COMMON_COMMAND(name,function,description) \
+               { print_to(caller, strcat("  ^2", name, "^7: ", description)); }
+               
+       COMMON_COMMANDS(0, caller, 0, "")
+       #undef COMMON_COMMAND
+       
+       return;
+}
+
+float CommonCommand_macro_command(float argc, entity caller, string command)
+{
+       #define COMMON_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(0))) { function; return TRUE; } }
+               
+       COMMON_COMMANDS(CMD_REQUEST_COMMAND, caller, argc, command)
+       #undef COMMON_COMMAND
+       
+       return FALSE;
+}
+
+float CommonCommand_macro_usage(float argc, entity caller)
+{
+       #define COMMON_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(1))) { function; return TRUE; } }
+               
+       COMMON_COMMANDS(CMD_REQUEST_USAGE, caller, argc, "")
+       #undef COMMON_COMMAND
+       
+       return FALSE;
+}
+
+void CommonCommand_macro_write_aliases(float fh)
+{
+       #define COMMON_COMMAND(name,function,description) \
+               { CMD_Write_Alias("qc_cmd_svcmd", name, description); }
+               
+       COMMON_COMMANDS(0, world, 0, "")
+       #undef COMMON_COMMAND
+       
+       return;
+}
\ No newline at end of file
diff --git a/qcsrc/server/command/common.qh b/qcsrc/server/command/common.qh
new file mode 100644 (file)
index 0000000..d3ee9cc
--- /dev/null
@@ -0,0 +1,38 @@
+// ============================================================
+//  Shared declarations for server commands, written by Samual
+//  Last updated: December 27th, 2011
+// ============================================================
+
+// client verification results
+#define CLIENT_ACCEPTABLE 1
+#define CLIENT_DOESNT_EXIST -1
+#define CLIENT_NOT_REAL -2
+#define CLIENT_NOT_BOT -3
+
+// definitions for timeouts
+#define TIMEOUT_INACTIVE 0
+#define TIMEOUT_LEADTIME 1
+#define TIMEOUT_ACTIVE 2
+
+// timeout which pauses the game by setting the slowmo value extremely low.
+#define TIMEOUT_SLOWMO_VALUE 0.0001
+
+// global timeout information declarations
+entity timeout_caller; // contains the entity of the player who started the last timeout
+entity timeout_handler; // responsible for centerprinting the timeout countdowns and playing sounds
+float sys_frametime; // gets initialised in worldspawn, saves the value from autocvar_sys_ticrate
+float orig_slowmo; // contains the value of autocvar_slowmo so that, after timeout finished, it isn't set to slowmo 1 necessarily
+float timeout_time; // contains the time in seconds that the active timeout has left
+float timeout_leadtime; // contains the number of seconds left of the leadtime (before the timeout starts)
+float timeout_status; // (values: 0, 1, 2) contains whether a timeout is not active (0), was called but still at leadtime (1) or is active (2)
+.float allowed_timeouts; // contains the number of allowed timeouts for each player
+.vector lastV_angle; //used when pausing the game in order to force the player to keep his old view angle fixed
+
+// allow functions to be used in other code like g_world.qc and teamplay.qc
+void timeout_handler_think();
+
+// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
+void CommonCommand_macro_write_aliases(float fh);
+
+// keep track of the next token to use for argc
+float next_token;
\ No newline at end of file
diff --git a/qcsrc/server/command/radarmap.qc b/qcsrc/server/command/radarmap.qc
new file mode 100644 (file)
index 0000000..16f3212
--- /dev/null
@@ -0,0 +1,427 @@
+// ===============================================
+//     Generates radar map images for use in the HUD
+// ===============================================
+
+float FullTraceFraction(vector a, vector mi, vector ma, vector b)
+{
+       vector c;
+       float white, black;
+
+       white = 0.001;
+       black = 0.001;
+
+       c = a;
+
+       float n, m;
+       n = m = 0;
+
+       while(vlen(c - b) > 1)
+       {
+               ++m;
+
+               tracebox(c, mi, ma, b, MOVE_WORLDONLY, world);
+               ++n;
+
+               if(!trace_startsolid)
+               {
+                       black += vlen(trace_endpos - c);
+                       c = trace_endpos;
+               }
+
+               n += tracebox_inverted(c, mi, ma, b, MOVE_WORLDONLY, world);
+
+               white += vlen(trace_endpos - c);
+               c = trace_endpos;
+       }
+
+       if(n > 200)
+               dprint("HOLY SHIT! FullTraceFraction: ", ftos(n), " total traces, ", ftos(m), " iterations\n");
+
+       return white / (black + white);
+}
+float RadarMapAtPoint_Trace(float x, float y, float w, float h, float zmin, float zsize, float q)
+{
+       vector a, b, mi, ma;
+
+       mi = '0 0 0';
+       ma = '1 0 0' * w + '0 1 0' * h;
+       a = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
+       b = '1 0 0' * x + '0 1 0' * y + '0 0 1' * (zsize + zmin);
+
+       return FullTraceFraction(a, mi, ma, b);
+}
+float RadarMapAtPoint_LineBlock(float x, float y, float w, float h, float zmin, float zsize, float q)
+{
+       vector o, mi, ma;
+       float i, r;
+       vector dz;
+
+       q = 256 * q - 1;
+       // 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value
+
+       mi = '0 0 0';
+       dz = (zsize / q) * '0 0 1';
+       ma = '1 0 0' * w + '0 1 0' * h + dz;
+       o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
+
+       if(x < world.absmin_x - w)
+               return 0;
+       if(y < world.absmin_y - h)
+               return 0;
+       if(x > world.absmax_x)
+               return 0;
+       if(y > world.absmax_y)
+               return 0;
+
+       r = 0;
+       for(i = 0; i < q; ++i)
+       {
+               vector v1, v2;
+               v1 = v2 = o + dz * i + mi;
+               v1_x += random() * (ma_x - mi_x);
+               v1_y += random() * (ma_y - mi_y);
+               v1_z += random() * (ma_z - mi_z);
+               v2_x += random() * (ma_x - mi_x);
+               v2_y += random() * (ma_y - mi_y);
+               v2_z += random() * (ma_z - mi_z);
+               traceline(v1, v2, MOVE_WORLDONLY, world);
+               if(trace_startsolid || trace_fraction < 1)
+                       ++r;
+       }
+       return r / q;
+}
+float RadarMapAtPoint_Block(float x, float y, float w, float h, float zmin, float zsize, float q)
+{
+       vector o, mi, ma;
+       float i, r;
+       vector dz;
+
+       q = 256 * q - 1;
+       // 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value
+
+       mi = '0 0 0';
+       dz = (zsize / q) * '0 0 1';
+       ma = '1 0 0' * w + '0 1 0' * h + dz;
+       o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
+
+       if(x < world.absmin_x - w)
+               return 0;
+       if(y < world.absmin_y - h)
+               return 0;
+       if(x > world.absmax_x)
+               return 0;
+       if(y > world.absmax_y)
+               return 0;
+
+       r = 0;
+       for(i = 0; i < q; ++i)
+       {
+               tracebox(o + dz * i, mi, ma, o + dz * i, MOVE_WORLDONLY, world);
+               if(trace_startsolid)
+                       ++r;
+       }
+       return r / q;
+}
+float RadarMapAtPoint_Sample(float x, float y, float w, float h, float zmin, float zsize, float q)
+{
+       vector a, b, mi, ma;
+
+       q *= 4; // choose q so it matches the regular algorithm in speed
+
+       q = 256 * q - 1;
+       // 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value
+
+       mi = '0 0 0';
+       ma = '1 0 0' * w + '0 1 0' * h;
+       a = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
+       b = '1 0 0' * w + '0 1 0' * h + '0 0 1' * zsize;
+
+       float c, i;
+       c = 0;
+
+       for(i = 0; i < q; ++i)
+       {
+               vector v;
+               v_x = a_x + random() * b_x;
+               v_y = a_y + random() * b_y;
+               v_z = a_z + random() * b_z;
+               traceline(v, v, MOVE_WORLDONLY, world);
+               if(trace_startsolid)
+                       ++c;
+       }
+
+       return c / q;
+}
+void sharpen_set(float x, float v)
+{
+       sharpen_buffer[x + 2 * RADAR_WIDTH_MAX] = v;
+}
+float sharpen_getpixel(float x, float y)
+{
+       if(x < 0)
+               return 0;
+       if(x >= RADAR_WIDTH_MAX)
+               return 0;
+       if(y < 0)
+               return 0;
+       if(y > 2)
+               return 0;
+       return sharpen_buffer[x + y * RADAR_WIDTH_MAX];
+}
+float sharpen_get(float x, float a)
+{
+       float sum;
+       sum = sharpen_getpixel(x, 1);
+       if(a == 0)
+               return sum;
+       sum *= (8 + 1/a);
+       sum -= sharpen_getpixel(x - 1, 0);
+       sum -= sharpen_getpixel(x - 1, 1);
+       sum -= sharpen_getpixel(x - 1, 2);
+       sum -= sharpen_getpixel(x + 1, 0);
+       sum -= sharpen_getpixel(x + 1, 1);
+       sum -= sharpen_getpixel(x + 1, 2);
+       sum -= sharpen_getpixel(x, 0);
+       sum -= sharpen_getpixel(x, 2);
+       return bound(0, sum * a, 1);
+}
+void sharpen_shift(float w)
+{
+       float i;
+       for(i = 0; i < w; ++i)
+       {
+               sharpen_buffer[i] = sharpen_buffer[i + RADAR_WIDTH_MAX];
+               sharpen_buffer[i + RADAR_WIDTH_MAX] = sharpen_buffer[i + 2 * RADAR_WIDTH_MAX];
+               sharpen_buffer[i + 2 * RADAR_WIDTH_MAX] = 0;
+       }
+}
+void sharpen_init(float w)
+{
+       float i;
+       for(i = 0; i < w; ++i)
+       {
+               sharpen_buffer[i] = 0;
+               sharpen_buffer[i + RADAR_WIDTH_MAX] = 0;
+               sharpen_buffer[i + 2 * RADAR_WIDTH_MAX] = 0;
+       }
+}
+void RadarMap_Next()
+{
+       if(radarmapper.count & 4)
+       {
+               localcmd("quit\n");
+       }
+       else if(radarmapper.count & 2)
+       {
+               localcmd(strcat("defer 1 \"sv_cmd radarmap --flags ", ftos(radarmapper.count), strcat(" --res ", ftos(radarmapper.size_x), " ", ftos(radarmapper.size_y), " --sharpen ", ftos(radarmapper.ltime), " --qual ", ftos(radarmapper.size_z)), "\"\n"));
+               GotoNextMap(0);
+       }
+       remove(radarmapper);
+       radarmapper = world;
+}
+void RadarMap_Think()
+{
+       // rough map entity
+       //   cnt: current line
+       //   size: pixel width/height
+       //   maxs: cell width/height
+       //   frame: counter
+       
+       float i, x, l;
+       string si;
+
+       if(self.frame == 0)
+       {
+               // initialize
+               get_mi_min_max_texcoords(1);
+               self.mins = mi_picmin;
+               self.maxs_x = (mi_picmax_x - mi_picmin_x) / self.size_x;
+               self.maxs_y = (mi_picmax_y - mi_picmin_y) / self.size_y;
+               self.maxs_z = mi_max_z - mi_min_z;
+               print("Picture mins/maxs: ", ftos(self.maxs_x), " and ", ftos(self.maxs_y), " should match\n");
+               self.netname = strzone(strcat("gfx/", mi_shortname, "_radar.xpm"));
+               if(!(self.count & 1))
+               {
+                       self.cnt = fopen(self.netname, FILE_READ);
+                       if(self.cnt < 0)
+                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.tga"), FILE_READ);
+                       if(self.cnt < 0)
+                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.png"), FILE_READ);
+                       if(self.cnt < 0)
+                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.jpg"), FILE_READ);
+                       if(self.cnt < 0)
+                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.tga"), FILE_READ);
+                       if(self.cnt < 0)
+                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.png"), FILE_READ);
+                       if(self.cnt < 0)
+                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.jpg"), FILE_READ);
+                       if(self.cnt >= 0)
+                       {
+                               fclose(self.cnt);
+
+                               print(self.netname, " already exists, aborting (you may want to specify --force)\n");
+                               RadarMap_Next();
+                               return;
+                       }
+               }
+               self.cnt = fopen(self.netname, FILE_WRITE);
+               if(self.cnt < 0)
+               {
+                       print("Error writing ", self.netname, "\n");
+                       remove(self);
+                       radarmapper = world;
+                       return;
+               }
+               print("Writing to ", self.netname, "...\n");
+               fputs(self.cnt, "/* XPM */\n");
+               fputs(self.cnt, "static char *RadarMap[] = {\n");
+               fputs(self.cnt, "/* columns rows colors chars-per-pixel */\n");
+               fputs(self.cnt, strcat("\"", ftos(self.size_x), " ", ftos(self.size_y), " 256 2\",\n"));
+               for(i = 0; i < 256; ++i)
+               {
+                       si = substring(doublehex, i*2, 2);
+                       fputs(self.cnt, strcat("\"", si, " c #", si, si, si, "\",\n"));
+               }
+               self.frame += 1;
+               self.nextthink = time;
+               sharpen_init(self.size_x);
+       }
+       else if(self.frame <= self.size_y)
+       {
+               // fill the sharpen buffer with this line
+               sharpen_shift(self.size_x);
+               i = self.count & 24;
+
+               switch(i)
+               {
+                       case 0:
+                       default:
+                               for(x = 0; x < self.size_x; ++x)
+                               {
+                                       l = RadarMapAtPoint_Block(self.mins_x + x * self.maxs_x, self.mins_y + (self.size_y - self.frame) * self.maxs_y, self.maxs_x, self.maxs_y, self.mins_z, self.maxs_z, self.size_z);
+                                       sharpen_set(x, l);
+                               }
+                               break;
+                       case 8:
+                               for(x = 0; x < self.size_x; ++x)
+                               {
+                                       l = RadarMapAtPoint_Trace(self.mins_x + x * self.maxs_x, self.mins_y + (self.size_y - self.frame) * self.maxs_y, self.maxs_x, self.maxs_y, self.mins_z, self.maxs_z, self.size_z);
+                                       sharpen_set(x, l);
+                               }
+                               break;
+                       case 16:
+                               for(x = 0; x < self.size_x; ++x)
+                               {
+                                       l = RadarMapAtPoint_Sample(self.mins_x + x * self.maxs_x, self.mins_y + (self.size_y - self.frame) * self.maxs_y, self.maxs_x, self.maxs_y, self.mins_z, self.maxs_z, self.size_z);
+                                       sharpen_set(x, l);
+                               }
+                               break;
+                       case 24:
+                               for(x = 0; x < self.size_x; ++x)
+                               {
+                                       l = RadarMapAtPoint_LineBlock(self.mins_x + x * self.maxs_x, self.mins_y + (self.size_y - self.frame) * self.maxs_y, self.maxs_x, self.maxs_y, self.mins_z, self.maxs_z, self.size_z);
+                                       sharpen_set(x, l);
+                               }
+                               break;
+               }
+
+               // do we have enough lines?
+               if(self.frame >= 2)
+               {
+                       // write a pixel line
+                       fputs(self.cnt, "\"");
+                       for(x = 0; x < self.size_x; ++x)
+                       {
+                               l = sharpen_get(x, self.ltime);
+                               fputs(self.cnt, substring(doublehex, 2 * floor(l * 256.0), 2));
+                       }
+                       if(self.frame == self.size_y)
+                               fputs(self.cnt, "\"\n");
+                       else
+                       {
+                               fputs(self.cnt, "\",\n");
+                               print(ftos(self.size_y - self.frame), " lines left\n");
+                       }
+               }
+
+               // is this the last line? then write back the missing line
+               if(self.frame == self.size_y)
+               {
+                       sharpen_shift(self.size_x);
+                       // write a pixel line
+                       fputs(self.cnt, "\"");
+                       for(x = 0; x < self.size_x; ++x)
+                       {
+                               l = sharpen_get(x, self.ltime);
+                               fputs(self.cnt, substring(doublehex, 2 * floor(l * 256.0), 2));
+                       }
+                       if(self.frame == self.size_y)
+                               fputs(self.cnt, "\"\n");
+                       else
+                       {
+                               fputs(self.cnt, "\",\n");
+                               print(ftos(self.size_y - self.frame), " lines left\n");
+                       }
+               }
+
+               self.frame += 1;
+               self.nextthink = time;
+       }
+       else
+       {
+               // close the file
+               fputs(self.cnt, "};\n");
+               fclose(self.cnt);
+               print("Finished. Please edit data/", self.netname, " with an image editing application and place it in the TGA format in the gfx folder.\n");
+               RadarMap_Next();
+       }
+}
+
+float RadarMap_Make(float argc)
+{
+       float i;
+       
+       if(!radarmapper)
+       {
+               radarmapper = spawn();
+               radarmapper.classname = "radarmapper";
+               radarmapper.think = RadarMap_Think;
+               radarmapper.nextthink = time;
+               radarmapper.count = 8; // default to the --trace method, as it is faster now
+               radarmapper.ltime = 1;
+               radarmapper.size = '512 512 1';
+               for(i = 1; i < argc; ++i)
+               {
+                       switch(argv(i))
+                       {
+                               case "--force": { radarmapper.count |= 1; break; }
+                               case "--loop": { radarmapper.count |= 2; break; }
+                               case "--quit": { radarmapper.count |= 4; break; }
+                               case "--block": { radarmapper.count &~= 24; break; }
+                               case "--trace": { radarmapper.count &~= 24; radarmapper.count |= 8; break; }
+                               case "--sample": { radarmapper.count &~= 24; radarmapper.count |= 16; break; }
+                               case "--lineblock": { radarmapper.count |= 24; break; }
+                               case "--flags": { ++i; radarmapper.count = stof(argv(i)); break; } // for the recursive call
+                               case "--sharpen": { ++i; radarmapper.ltime = stof(argv(i)); break; } // for the recursive call
+                               case "--res": // minor alias
+                               case "--resolution": { ++i; radarmapper.size_x = stof(argv(i)); ++i; radarmapper.size_y = stof(argv(i)); break; }
+                               case "--qual": // minor alias
+                               case "--quality": { ++i; radarmapper.size_z = stof(argv(i)); break; }
+                               
+                               default: 
+                                       i = argc; 
+                                       remove(radarmapper);
+                                       radarmapper = world;
+                                       break;
+                       }
+               }
+                               
+               if(radarmapper) // after doing the arguments, see if we successfully went forward. 
+               {
+                       print("Radarmap entity spawned.\n");
+                       return TRUE; // if so, don't print usage.
+               }
+       }
+       
+       return FALSE;
+}
\ No newline at end of file
diff --git a/qcsrc/server/command/radarmap.qh b/qcsrc/server/command/radarmap.qh
new file mode 100644 (file)
index 0000000..b92d846
--- /dev/null
@@ -0,0 +1,13 @@
+// ===========================================
+//     Declarations for radarmap generation code
+// ===========================================
+
+entity radarmapper;
+
+float RADAR_WIDTH_MAX = 512;
+float RADAR_HEIGHT_MAX = 512;
+float sharpen_buffer[RADAR_WIDTH_MAX * 3];
+
+string doublehex = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFFFF";
+// FF is contained twice, to map 256 to FF too
+// removes the need to bound()
diff --git a/qcsrc/server/command/sv_cmd.qc b/qcsrc/server/command/sv_cmd.qc
new file mode 100644 (file)
index 0000000..0fa5667
--- /dev/null
@@ -0,0 +1,1807 @@
+// =====================================================
+//  Server side game commands code, reworked by Samual
+//  Last updated: December 29th, 2011
+// =====================================================
+
+//  used by GameCommand_make_mapinfo()
+void make_mapinfo_Think()
+{
+       if(MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
+       {
+               print("Done rebuiling mapinfos.\n");
+               MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
+               remove(self);
+       }
+       else
+       {
+               self.think = make_mapinfo_Think;
+               self.nextthink = time;
+       }
+}
+
+//  used by GameCommand_extendmatchtime() and GameCommand_reducematchtime()
+void changematchtime(float delta, float mi, float ma)
+{
+       float cur;
+       float new;
+       float lim;
+
+       if(delta == 0)
+               return;
+       if(autocvar_timelimit < 0)
+               return;
+
+       if(mi <= 10)
+               mi = 10; // at least ten sec in the future
+       cur = time - game_starttime;
+       if(cur > 0)
+               mi += cur; // from current time!
+
+       lim = autocvar_timelimit * 60;
+
+       if(delta > 0)
+       {
+               if(lim == 0)
+                       return; // cannot increase any further
+               else if(lim < ma)
+                       new = min(ma, lim + delta);
+               else // already above maximum: FAIL
+                       return;
+       }
+       else
+       {
+               if(lim == 0) // infinite: try reducing to max, if we are allowed to
+                       new = max(mi, ma);
+               else if(lim > mi) // above minimum: decrease
+                       new = max(mi, lim + delta);
+               else // already below minimum: FAIL
+                       return;
+       }
+
+       cvar_set("timelimit", ftos(new / 60));
+}
+
+
+// =======================
+//  Command Sub-Functions
+// =======================
+
+void GameCommand_adminmsg(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       entity client;
+                       float accepted;
+                       
+                       string targets = strreplace(",", " ", argv(1));
+                       string original_targets = strreplace(" ", ", ", targets);
+                       string admin_message = argv(2);
+                       float infobartime = stof(argv(3));
+                       
+                       string successful, t;
+                       
+                       if((targets) && (admin_message))
+                       {
+                               for(;targets;)
+                               {
+                                       t = car(targets); targets = cdr(targets);
+                                       
+                                       // Check to see if the player is a valid target
+                                       client = GetFilteredEntity(t);
+                                       accepted = VerifyClientEntity(client, TRUE, FALSE);
+                                       
+                                       if not(accepted > 0) 
+                                       {
+                                               print("adminmsg: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : ".\n")); 
+                                               continue;
+                                       }
+                                       
+                                       // send the centerprint/console print or infomessage
+                                       if(infobartime)
+                                       {
+                                               stuffcmd(client, sprintf("\ninfobar %f \"%s\"\n", infobartime, MakeConsoleSafe(admin_message)));
+                                       }
+                                       else
+                                       {
+                                               centerprint(client, strcat("^3", admin_name(), ":\n^7", admin_message));
+                                               sprint(client, strcat("\{1}\{13}^3", admin_name(), "^7: ", admin_message, "\n"));
+                                       }
+                                       
+                                       successful = strcat(successful, (successful ? ", " : ""), client.netname);
+                                       dprint("Message sent to ", client.netname, "\n");
+                                       continue;
+                               }
+                               
+                               if(successful)
+                                       bprint("Successfully sent message '", admin_message, "' to ", successful, ".\n");
+                               else
+                                       print("No players given (", original_targets, ") could recieve the message.\n");
+                                       
+                               return;
+                       }
+               }
+               
+               default:
+                       print("Incorrect parameters for ^2adminmsg^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd adminmsg clients \"message\" [infobartime]\n");
+                       print("  'clients' is a list (separated by commas) of player entity ID's or nicknames\n");
+                       print("  If infobartime is provided, the message will be sent to infobar.\n");
+                       print("  Otherwise, it will just be sent as a centerprint message.\n");
+                       print("Examples: adminmsg 2,4 \"this infomessage will last for ten seconds\" 10\n");
+                       print("          adminmsg 2,5 \"this message will be a centerprint\"\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_allready(float request)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       ReadyRestart();
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd allready\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_allspec(float request, float argc)
+{      
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       entity client;
+                       string reason = argv(1);
+                       float i;
+                       
+                       FOR_EACH_REALPLAYER(client)
+                       {
+                               self = client;
+                               PutObserverInServer();
+                               ++i;
+                       }
+                       if(i) { bprint(strcat("Successfully forced all (", ftos(i), ") players to spectate", (reason ? strcat(" for reason: '", reason, "'") : ""), ".\n")); }
+                       else { print("No players found to spectate.\n"); }
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd allspec [reason]\n");
+                       print("  Where 'reason' is an optional argument for explanation of allspec command.\n");
+                       print("See also: ^2moveplayer, shuffleteams^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_anticheat(float request, float argc) 
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       entity client = GetIndexedEntity(argc, 1);
+                       float accepted = VerifyClientEntity(client, FALSE, FALSE);
+                       
+                       if(accepted > 0) 
+                       {
+                               self = client;
+                               anticheat_report();
+                               return;
+                       }
+                       else
+                       {
+                               print("anticheat: ", GetClientErrorString(accepted, argv(1)), ".\n"); 
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2anticheat^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd anticheat client\n");
+                       print("  'client' is the entity number or name of the player.\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_bbox(float request) // legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       print("Original size: ", ftos(world.absmin_x), " ", ftos(world.absmin_y), " ", ftos(world.absmin_z));
+                       print(" ", ftos(world.absmax_x), " ", ftos(world.absmax_y), " ", ftos(world.absmax_z), "\n");
+                       print("Currently set size: ", ftos(world.mins_x), " ", ftos(world.mins_y), " ", ftos(world.mins_z));
+                       print(" ", ftos(world.maxs_x), " ", ftos(world.maxs_y), " ", ftos(world.maxs_z), "\n");
+                       print("Solid bounding box size:");
+
+                       tracebox('1 0 0' * world.absmin_x,
+                                                       '0 1 0' * world.absmin_y + '0 0 1' * world.absmin_z,
+                                                       '0 1 0' * world.absmax_y + '0 0 1' * world.absmax_z,
+                                                       '1 0 0' * world.absmax_x,
+                                       MOVE_WORLDONLY,
+                                       world);
+                       if(trace_startsolid)
+                               print(" ", ftos(world.absmin_x));
+                       else
+                               print(" ", ftos(trace_endpos_x));
+
+                       tracebox('0 1 0' * world.absmin_y,
+                                                       '1 0 0' * world.absmin_x + '0 0 1' * world.absmin_z,
+                                                       '1 0 0' * world.absmax_x + '0 0 1' * world.absmax_z,
+                                                       '0 1 0' * world.absmax_y,
+                                       MOVE_WORLDONLY,
+                                       world);
+                       if(trace_startsolid)
+                               print(" ", ftos(world.absmin_y));
+                       else
+                               print(" ", ftos(trace_endpos_y));
+
+                       tracebox('0 0 1' * world.absmin_z,
+                                                       '1 0 0' * world.absmin_x + '0 1 0' * world.absmin_y,
+                                                       '1 0 0' * world.absmax_x + '0 1 0' * world.absmax_y,
+                                                       '0 0 1' * world.absmax_z,
+                                       MOVE_WORLDONLY,
+                                       world);
+                       if(trace_startsolid)
+                               print(" ", ftos(world.absmin_z));
+                       else
+                               print(" ", ftos(trace_endpos_z));
+
+                       tracebox('1 0 0' * world.absmax_x,
+                                                       '0 1 0' * world.absmin_y + '0 0 1' * world.absmin_z,
+                                                       '0 1 0' * world.absmax_y + '0 0 1' * world.absmax_z,
+                                                       '1 0 0' * world.absmin_x,
+                                       MOVE_WORLDONLY,
+                                       world);
+                       if(trace_startsolid)
+                               print(" ", ftos(world.absmax_x));
+                       else
+                               print(" ", ftos(trace_endpos_x));
+
+                       tracebox('0 1 0' * world.absmax_y,
+                                                       '1 0 0' * world.absmin_x + '0 0 1' * world.absmin_z,
+                                                       '1 0 0' * world.absmax_x + '0 0 1' * world.absmax_z,
+                                                       '0 1 0' * world.absmin_y,
+                                       MOVE_WORLDONLY,
+                                       world);
+                       if(trace_startsolid)
+                               print(" ", ftos(world.absmax_y));
+                       else
+                               print(" ", ftos(trace_endpos_y));
+
+                       tracebox('0 0 1' * world.absmax_z,
+                                                       '1 0 0' * world.absmin_x + '0 1 0' * world.absmin_y,
+                                                       '1 0 0' * world.absmax_x + '0 1 0' * world.absmax_y,
+                                                       '0 0 1' * world.absmin_z,
+                                       MOVE_WORLDONLY,
+                                       world);
+                       if(trace_startsolid)
+                               print(" ", ftos(world.absmax_z));
+                       else
+                               print(" ", ftos(trace_endpos_z));
+                               
+                       print("\n");
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd bbox\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2gettaginfo, trace^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_bot_cmd(float request, float argc) // mostly legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       entity bot;
+                       
+                       if(argv(1) == "reset")
+                       {
+                               bot_resetqueues();
+                               return;
+                       }
+                       else if(argv(1) == "load" && argc == 3)
+                       {
+                               float fh, i;
+                               string s;
+                               fh = fopen(argv(2), FILE_READ);
+                               if(fh < 0)
+                               {
+                                       print("cannot open the file\n");
+                                       return;
+                               }
+
+                               i = 0;
+                               while((s = fgets(fh)))
+                               {
+                                       argc = tokenize_console(s);
+
+                                       if(argc >= 3 && argv(0) == "sv_cmd" && argv(1) == "bot_cmd")
+                                       {
+                                               if(argv(2) == "reset")
+                                               {
+                                                       bot_resetqueues();
+                                               }
+                                               else if(argv(2) == "setbots")
+                                               {
+                                                       cvar_settemp("minplayers", "0");
+                                                       cvar_settemp("bot_number", argv(3));
+                                                       if(!bot_fixcount())
+                                                               print("Sorry, could not set requested bot count\n");
+                                               }
+                                               else
+                                               {
+                                                       // let's start at token 2 so we can skip sv_cmd bot_cmd
+                                                       bot = find_bot_by_number(stof(argv(2)));
+                                                       if(bot == world)
+                                                               bot = find_bot_by_name(argv(2));
+                                                       if(bot)
+                                                               bot_queuecommand(bot, strcat(argv(3), " ", argv(4)));
+                                               }
+                                       }
+                                       else
+                                               localcmd(strcat(s, "\n"));
+
+                                       ++i;
+                               }
+                               print(ftos(i), " commands read\n");
+                               fclose(fh);
+                               return;
+                       }
+                       else if(argv(1) == "help")
+                       {
+                               if(argv(2))
+                                       bot_cmdhelp(argv(2));
+                               else
+                                       bot_list_commands();
+                               return;
+                       }
+                       else if(argc >= 3) // this comes last
+                       {
+                               bot = find_bot_by_number(stof(argv(1)));
+                               if(bot == world)
+                                       bot = find_bot_by_name(argv(1));
+                               if(bot)
+                               {
+                                       print(strcat("Command '", strcat(argv(2), " ", argv(3)), "' sent to bot ", bot.netname, "\n"));
+                                       bot_queuecommand(bot, strcat(argv(2), " ", argv(3)));
+                                       return;
+                               }
+                               else
+                                       print(strcat("Error: Can't find bot with the name or id '", argv(1),"' - Did you mistype the command?\n")); // don't return so that usage is shown
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2bot_cmd^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd bot_cmd client command [argument]\n");
+                       print("  'client' can be either the name or entity id of the bot\n");
+                       print("  For full list of commands, see bot_cmd help [command].\n");
+                       print("Examples: sv_cmd bot_cmd client cc \"say something\"\n");
+                       print("          sv_cmd bot_cmd client presskey jump\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_cointoss(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       entity client;
+                       string result1 = (argv(2) ? strcat("^7", argv(1), "^3!\n") : "^1HEADS^3!\n");
+                       string result2 = (argv(2) ? strcat("^7", argv(2), "^3!\n") : "^4TAILS^3!\n");
+                       string choice = ((random() > 0.5) ? result1 : result2);
+                       
+                       FOR_EACH_CLIENT(client)
+                               centerprint(client, strcat("^3Throwing coin... Result: ", choice));
+                       bprint(strcat("^3Throwing coin... Result: ", choice));
+                       return;
+               }
+               
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd cointoss [result1 result2]\n");
+                       print("  Where 'result1' and 'result2' are user created options.\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_database(float request, float argc) // legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argc == 3)
+                       {
+                               if(argv(1) == "save")
+                               {
+                                       db_save(ServerProgsDB, argv(2));
+                                       print(strcat("Copied serverprogs database to '", argv(2), "' in the data directory.\n"));
+                                       return;
+                               }
+                               else if(argv(1) == "dump")
+                               {
+                                       db_dump(ServerProgsDB, argv(2));
+                                       print("DB dumped.\n"); // wtf does this do?
+                                       return;
+                               }
+                               else if(argv(1) == "load")
+                               {
+                                       db_close(ServerProgsDB);
+                                       ServerProgsDB = db_load(argv(2));
+                                       print(strcat("Loaded '", argv(2), "' as new serverprogs database.\n"));
+                                       return;
+                               }
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2database^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd database action filename\n");
+                       print("  Where 'action' is the command to complete,\n");
+                       print("  and 'filename' is what it acts upon.\n");
+                       print("  Full list of commands here: \"save, dump, load.\"\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_defer_clear(float request, float argc)
+{      
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       entity client;
+                       float accepted;
+                       
+                       if(argc >= 2)
+                       {
+                               client = GetIndexedEntity(argc, 1);
+                               accepted = VerifyClientEntity(client, TRUE, FALSE);
+                               
+                               if(accepted > 0)
+                               {
+                                       stuffcmd(client, "defer clear\n");
+                                       print("defer clear stuffed to ", client.netname, "\n");
+                               }
+                               else { print("defer_clear: ", GetClientErrorString(accepted, argv(1)), ".\n"); }
+                               
+                               return;
+                       }
+               }
+               
+               default:
+                       print("Incorrect parameters for ^2defer_clear^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd defer_clear client\n");
+                       print("  'client' is the entity number or name of the player.\n");
+                       print("See also: ^2defer_clear_all^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_defer_clear_all(float request)
+{      
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       entity client;
+                       float i;
+                       float argc;
+                       
+                       FOR_EACH_CLIENT(client)
+                       {
+                               argc = tokenize_console(strcat("defer_clear ", ftos(num_for_edict(client))));
+                               GameCommand_defer_clear(CMD_REQUEST_COMMAND, argc);     
+                               ++i;
+                       }
+                       if(i) { print(strcat("Successfully stuffed defer clear to all clients (", ftos(i), ")\n")); } // should a message be added if no players were found? 
+                       return;
+               }
+               
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd defer_clear_all\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2defer_clear^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_delrec(float request, float argc) // legacy // perhaps merge later with records and printstats and such?
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(1))
+                       {
+                               if(argv(2))
+                                       race_deleteTime(argv(2), stof(argv(1)));
+                               else
+                                       race_deleteTime(GetMapname(), stof(argv(1)));
+                               return;
+                       }
+               }       
+               
+               default:
+                       print("Incorrect parameters for ^2delrec^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd delrec ranking [map]\n");
+                       print("  'ranking' is which ranking level to clear up to, \n");
+                       print("  it will clear all records up to nth place.\n");
+                       print("  if 'map' is not provided it will use current map.\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_effectindexdump(float request) // legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       float fh, d;
+                       string s;
+                       
+                       d = db_create();
+                       print("begin of effects list\n");
+                       db_put(d, "TE_GUNSHOT", "1"); print("effect TE_GUNSHOT is ", ftos(particleeffectnum("TE_GUNSHOT")), "\n");
+                       db_put(d, "TE_GUNSHOTQUAD", "1"); print("effect TE_GUNSHOTQUAD is ", ftos(particleeffectnum("TE_GUNSHOTQUAD")), "\n");
+                       db_put(d, "TE_SPIKE", "1"); print("effect TE_SPIKE is ", ftos(particleeffectnum("TE_SPIKE")), "\n");
+                       db_put(d, "TE_SPIKEQUAD", "1"); print("effect TE_SPIKEQUAD is ", ftos(particleeffectnum("TE_SPIKEQUAD")), "\n");
+                       db_put(d, "TE_SUPERSPIKE", "1"); print("effect TE_SUPERSPIKE is ", ftos(particleeffectnum("TE_SUPERSPIKE")), "\n");
+                       db_put(d, "TE_SUPERSPIKEQUAD", "1"); print("effect TE_SUPERSPIKEQUAD is ", ftos(particleeffectnum("TE_SUPERSPIKEQUAD")), "\n");
+                       db_put(d, "TE_WIZSPIKE", "1"); print("effect TE_WIZSPIKE is ", ftos(particleeffectnum("TE_WIZSPIKE")), "\n");
+                       db_put(d, "TE_KNIGHTSPIKE", "1"); print("effect TE_KNIGHTSPIKE is ", ftos(particleeffectnum("TE_KNIGHTSPIKE")), "\n");
+                       db_put(d, "TE_EXPLOSION", "1"); print("effect TE_EXPLOSION is ", ftos(particleeffectnum("TE_EXPLOSION")), "\n");
+                       db_put(d, "TE_EXPLOSIONQUAD", "1"); print("effect TE_EXPLOSIONQUAD is ", ftos(particleeffectnum("TE_EXPLOSIONQUAD")), "\n");
+                       db_put(d, "TE_TAREXPLOSION", "1"); print("effect TE_TAREXPLOSION is ", ftos(particleeffectnum("TE_TAREXPLOSION")), "\n");
+                       db_put(d, "TE_TELEPORT", "1"); print("effect TE_TELEPORT is ", ftos(particleeffectnum("TE_TELEPORT")), "\n");
+                       db_put(d, "TE_LAVASPLASH", "1"); print("effect TE_LAVASPLASH is ", ftos(particleeffectnum("TE_LAVASPLASH")), "\n");
+                       db_put(d, "TE_SMALLFLASH", "1"); print("effect TE_SMALLFLASH is ", ftos(particleeffectnum("TE_SMALLFLASH")), "\n");
+                       db_put(d, "TE_FLAMEJET", "1"); print("effect TE_FLAMEJET is ", ftos(particleeffectnum("TE_FLAMEJET")), "\n");
+                       db_put(d, "EF_FLAME", "1"); print("effect EF_FLAME is ", ftos(particleeffectnum("EF_FLAME")), "\n");
+                       db_put(d, "TE_BLOOD", "1"); print("effect TE_BLOOD is ", ftos(particleeffectnum("TE_BLOOD")), "\n");
+                       db_put(d, "TE_SPARK", "1"); print("effect TE_SPARK is ", ftos(particleeffectnum("TE_SPARK")), "\n");
+                       db_put(d, "TE_PLASMABURN", "1"); print("effect TE_PLASMABURN is ", ftos(particleeffectnum("TE_PLASMABURN")), "\n");
+                       db_put(d, "TE_TEI_G3", "1"); print("effect TE_TEI_G3 is ", ftos(particleeffectnum("TE_TEI_G3")), "\n");
+                       db_put(d, "TE_TEI_SMOKE", "1"); print("effect TE_TEI_SMOKE is ", ftos(particleeffectnum("TE_TEI_SMOKE")), "\n");
+                       db_put(d, "TE_TEI_BIGEXPLOSION", "1"); print("effect TE_TEI_BIGEXPLOSION is ", ftos(particleeffectnum("TE_TEI_BIGEXPLOSION")), "\n");
+                       db_put(d, "TE_TEI_PLASMAHIT", "1"); print("effect TE_TEI_PLASMAHIT is ", ftos(particleeffectnum("TE_TEI_PLASMAHIT")), "\n");
+                       db_put(d, "EF_STARDUST", "1"); print("effect EF_STARDUST is ", ftos(particleeffectnum("EF_STARDUST")), "\n");
+                       db_put(d, "TR_ROCKET", "1"); print("effect TR_ROCKET is ", ftos(particleeffectnum("TR_ROCKET")), "\n");
+                       db_put(d, "TR_GRENADE", "1"); print("effect TR_GRENADE is ", ftos(particleeffectnum("TR_GRENADE")), "\n");
+                       db_put(d, "TR_BLOOD", "1"); print("effect TR_BLOOD is ", ftos(particleeffectnum("TR_BLOOD")), "\n");
+                       db_put(d, "TR_WIZSPIKE", "1"); print("effect TR_WIZSPIKE is ", ftos(particleeffectnum("TR_WIZSPIKE")), "\n");
+                       db_put(d, "TR_SLIGHTBLOOD", "1"); print("effect TR_SLIGHTBLOOD is ", ftos(particleeffectnum("TR_SLIGHTBLOOD")), "\n");
+                       db_put(d, "TR_KNIGHTSPIKE", "1"); print("effect TR_KNIGHTSPIKE is ", ftos(particleeffectnum("TR_KNIGHTSPIKE")), "\n");
+                       db_put(d, "TR_VORESPIKE", "1"); print("effect TR_VORESPIKE is ", ftos(particleeffectnum("TR_VORESPIKE")), "\n");
+                       db_put(d, "TR_NEHAHRASMOKE", "1"); print("effect TR_NEHAHRASMOKE is ", ftos(particleeffectnum("TR_NEHAHRASMOKE")), "\n");
+                       db_put(d, "TR_NEXUIZPLASMA", "1"); print("effect TR_NEXUIZPLASMA is ", ftos(particleeffectnum("TR_NEXUIZPLASMA")), "\n");
+                       db_put(d, "TR_GLOWTRAIL", "1"); print("effect TR_GLOWTRAIL is ", ftos(particleeffectnum("TR_GLOWTRAIL")), "\n");
+                       db_put(d, "TR_SEEKER", "1"); print("effect TR_SEEKER is ", ftos(particleeffectnum("TR_SEEKER")), "\n");
+                       db_put(d, "SVC_PARTICLE", "1"); print("effect SVC_PARTICLE is ", ftos(particleeffectnum("SVC_PARTICLE")), "\n");
+
+                       fh = fopen("effectinfo.txt", FILE_READ);
+                       while((s = fgets(fh)))
+                       {
+                               tokenize_console(s);
+                               if(argv(0) == "effect")
+                               {
+                                       if(db_get(d, argv(1)) != "1")
+                                       {
+                                               if(particleeffectnum(argv(1)) >= 0)
+                                                       print("effect ", argv(1), " is ", ftos(particleeffectnum(argv(1))), "\n");
+                                               db_put(d, argv(1), "1");
+                                       }
+                               }
+                       }
+                       print("end of effects list\n");
+
+                       db_close(d);
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd effectindexdump\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_extendmatchtime(float request) // legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       changematchtime(autocvar_timelimit_increment * 60, autocvar_timelimit_min * 60, autocvar_timelimit_max * 60);
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd extendmatchtime\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2reducematchtime^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_find(float request, float argc) // legacy // is this even needed? We have prvm_edicts command and such ANYWAY
+{      
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       entity client;
+                       
+                       for(client = world; (client = find(client, classname, argv(1))); )
+                               print(etos(client), "\n");
+                               
+                       return;
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2find^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd find classname\n");
+                       print("  Where 'classname' is the classname to search for.\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_gametype(float request, float argc) // legacy
+{      
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(1) != "")
+                       {
+                               string s = argv(1);
+                               float t = MapInfo_Type_FromString(s), tsave = MapInfo_CurrentGametype();
+                               
+                               if(t)
+                               {
+                                       MapInfo_SwitchGameType(t);
+                                       MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
+                                       if(MapInfo_count > 0)
+                                               bprint("Game type successfully switched to ", s, "\n");
+                                       else
+                                       {
+                                               bprint("Cannot use this game type: no map for it found\n");
+                                               MapInfo_SwitchGameType(tsave);
+                                               MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
+                                       }
+                               }
+                               else
+                                       bprint("Game type switch to ", s, " failed: this type does not exist!\n");
+                                       
+                               return;
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2gametype^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd gametype mode\n");
+                       print("  Where 'mode' is the gametype mode to switch to.\n");
+                       print("See also: ^2gotomap^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_gettaginfo(float request, float argc) // legacy
+{      
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       entity tmp_entity;
+                       float i;
+                       vector v;
+                       
+                       if(argc >= 4)
+                       {
+                               tmp_entity = spawn();
+                               if(argv(1) == "w")
+                                       setmodel(tmp_entity, (nextent(world)).weaponentity.model);
+                               else
+                               {
+                                       precache_model(argv(1));
+                                       setmodel(tmp_entity, argv(1));
+                               }
+                               tmp_entity.frame = stof(argv(2));
+                               if(substring(argv(3), 0, 1) == "#")
+                                       i = stof(substring(argv(3), 1, -1));
+                               else
+                                       i = gettagindex(tmp_entity, argv(3));
+                               if(i)
+                               {
+                                       v = gettaginfo(tmp_entity, i);
+                                       print("model ", tmp_entity.model, " frame ", ftos(tmp_entity.frame), " tag ", gettaginfo_name);
+                                       print(" index ", ftos(i), " parent ", ftos(gettaginfo_parent), "\n");
+                                       print(" vector = ", ftos(v_x), " ", ftos(v_y), " ", ftos(v_z), "\n");
+                                       print(" offset = ", ftos(gettaginfo_offset_x), " ", ftos(gettaginfo_offset_y), " ", ftos(gettaginfo_offset_z), "\n");
+                                       print(" forward = ", ftos(gettaginfo_forward_x), " ", ftos(gettaginfo_forward_y), " ", ftos(gettaginfo_forward_z), "\n");
+                                       print(" right = ", ftos(gettaginfo_right_x), " ", ftos(gettaginfo_right_y), " ", ftos(gettaginfo_right_z), "\n");
+                                       print(" up = ", ftos(gettaginfo_up_x), " ", ftos(gettaginfo_up_y), " ", ftos(gettaginfo_up_z), "\n");
+                                       if(argc >= 6)
+                                       {
+                                               v_y = -v_y;
+                                               localcmd(strcat(argv(4), vtos(v), argv(5), "\n"));
+                                       }
+                               }
+                               else
+                                       print("bone not found\n");
+                                       
+                               remove(tmp_entity);
+                               return;
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2gettaginfo^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd gettaginfo model frame index [command one] [command two]\n");
+                       print("See also: ^2bbox, trace^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_gotomap(float request, float argc) // mostly legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(1))
+                       {
+                               print(GotoMap(argv(1)), "\n");
+                               return;
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2gotomap^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd gotomap map\n");
+                       print("  Where 'map' is the *.bsp file to change to.\n");
+                       print("See also: ^2gametype^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_lockteams(float request)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(teamplay)
+                       {
+                               lockteams = 1;
+                               bprint("^1The teams are now locked.\n");
+                       }
+                       else
+                       {
+                               bprint("lockteams command can only be used in a team-based gamemode.\n");
+                       }
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd lockteams\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2unlockteams^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_make_mapinfo(float request) // legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               { 
+                       entity tmp_entity;
+                       
+                       tmp_entity = spawn();
+                       tmp_entity.classname = "make_mapinfo";
+                       tmp_entity.think = make_mapinfo_Think;
+                       tmp_entity.nextthink = time;
+                       MapInfo_Enumerate();
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd make_mapinfo\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2radarmap^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_moveplayer(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       float accepted;
+                       entity client;
+       
+                       string targets = strreplace(",", " ", argv(1));
+                       string original_targets = strreplace(" ", ", ", targets);
+                       string destination = argv(2);
+                       string notify = argv(3);
+                       
+                       string successful, t;
+                       
+                       // lets see if the target(s) even actually exist.
+                       if((targets) && (destination))
+                       { 
+                               for(;targets;)
+                               {
+                                       t = car(targets); targets = cdr(targets);
+
+                                       // Check to see if the player is a valid target
+                                       client = GetFilteredEntity(t);
+                                       accepted = VerifyClientEntity(client, FALSE, FALSE);
+                                       
+                                       if not(accepted > 0) 
+                                       {
+                                               print("moveplayer: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : ".\n")); 
+                                               continue;
+                                       }
+                                       
+                                       // Where are we putting this player?
+                                       if(destination == "spec" || destination == "spectator") 
+                                       {
+                                               if(client.classname != "spectator" && client.classname != "observer")
+                                               {
+                                                       self = client;
+                                                       PutObserverInServer();
+                                                       
+                                                       successful = strcat(successful, (successful ? ", " : ""), client.netname);
+                                               }
+                                               else
+                                               {
+                                                       print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") is already spectating.\n");
+                                               }
+                                               continue;
+                                       }
+                                       else
+                                       {
+                                               if(client.classname != "spectator" && client.classname != "observer")
+                                               {
+                                                       if(teamplay)
+                                                       {
+                                                               // set up
+                                                               float team_color;
+                                                               float save = client.team_forced;
+                                                               client.team_forced = 0;
+
+                                                               // find the team to move the player to
+                                                               team_color = ColourToNumber(destination);
+                                                               if(team_color == client.team) // already on the destination team
+                                                               {
+                                                                       // keep the forcing undone
+                                                                       print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") is already on the ", ColoredTeamName(client.team), (targets ? ", skipping to next player.\n" : ".\n"));
+                                                                       continue;
+                                                               } 
+                                                               else if(team_color == 0)  // auto team
+                                                               {
+                                                                       team_color = NumberToTeamNumber(FindSmallestTeam(client, FALSE));
+                                                               }
+                                                               else
+                                                               {
+                                                                       CheckAllowedTeams(client);
+                                                               }
+                                                               client.team_forced = save;
+                                                               
+                                                               // Check to see if the destination team is even available
+                                                               switch(team_color) 
+                                                               {
+                                                                       case COLOR_TEAM1: if(c1 == -1) { print("Sorry, can't move player to red team if it doesn't exist.\n"); return; } break;
+                                                                       case COLOR_TEAM2: if(c2 == -1) { print("Sorry, can't move player to blue team if it doesn't exist.\n"); return; } break;
+                                                                       case COLOR_TEAM3: if(c3 == -1) { print("Sorry, can't move player to yellow team if it doesn't exist.\n"); return; } break;
+                                                                       case COLOR_TEAM4: if(c4 == -1) { print("Sorry, can't move player to pink team if it doesn't exist.\n"); return; } break;
+                                                                       
+                                                                       default: print("Sorry, can't move player here if team ", destination, " doesn't exist.\n"); return;
+                                                               }
+                                                               
+                                                               // If so, lets continue and finally move the player
+                                                               client.team_forced = 0;
+                                                               MoveToTeam(client, team_color, 6, stof(notify));
+                                                               successful = strcat(successful, (successful ? ", " : ""), client.netname);
+                                                               print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") has been moved to the ", ColoredTeamName(team_color), ".\n");
+                                                               continue;
+                                                       }
+                                                       else
+                                                       {
+                                                               print("Can't change teams when currently not playing a team game.\n");
+                                                               return;
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       print("Can't change teams if the player isn't in the game.\n"); // well technically we could, but should we allow that? :P 
+                                                       return;
+                                               }
+                                       }
+                               }
+                               
+                               if(successful)
+                                       bprint("Successfully moved players ", successful, " to destination ", destination, ".\n");
+                               else
+                                       print("No players given (", original_targets, ") are able to move.\n");
+                                       
+                               return; // still correct parameters so return to avoid usage print
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2moveplayer^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd moveplayer clients destination [notify]\n");
+                       print("  'clients' is a list (separated by commas) of player entity ID's or nicknames\n");
+                       print("  'destination' is what to send the player to, be it team or spectating\n");
+                       print("  Full list of destinations here: \"spec, spectator, red, blue, yellow, pink, auto.\"\n");
+                       print("  'notify' is whether or not to send messages notifying of the move. Detail below.\n");
+                       print("    0 (00) automove centerprint, admin message; 1 (01) automove centerprint, no admin message\n");
+                       print("    2 (10) no centerprint, admin message; 3 (11) no centerprint, no admin message\n");
+                       print("Examples: sv_cmd moveplayer 1,3,5 red 3\n");
+                       print("          sv_cmd moveplayer 2 spec \n");
+                       print("See also: ^2allspec, shuffleteams^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_nospectators(float request) // legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       blockSpectators = 1;
+                       entity plr;
+                       FOR_EACH_CLIENT(plr) //give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player
+                       {
+                               if(plr.classname == "spectator" || plr.classname == "observer")
+                               {
+                                       plr.spectatortime = time;
+                                       sprint(plr, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));
+                               }
+                       }
+                       bprint(strcat("^7All spectators will be automatically kicked when not joining the game after ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds!\n"));
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd nospectators\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_playerdemo(float request, float argc) // mostly legacy
+{      
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(2) && argv(3))
+                       {
+                               entity client;
+                               float i, n, accepted;
+                               
+                               switch(argv(1))
+                               {
+                                       case "read":
+                                       {
+                                               client = GetIndexedEntity(argc, 2);
+                                               accepted = VerifyClientEntity(client, FALSE, TRUE);
+                                               
+                                               if not(accepted > 0) 
+                                               {
+                                                       print("playerdemo: read: ", GetClientErrorString(accepted, argv(2)), ".\n"); 
+                                                       return;
+                                               }
+                                               
+                                               self = client;
+                                               playerdemo_open_read(argv(next_token));
+                                               return;
+                                       }
+                                       
+                                       case "write":
+                                       {
+                                               client = GetIndexedEntity(argc, 2);
+                                               accepted = VerifyClientEntity(client, FALSE, FALSE);
+                                               
+                                               if not(accepted > 0) 
+                                               {
+                                                       print("playerdemo: write: ", GetClientErrorString(accepted, argv(2)), ".\n"); 
+                                                       return;
+                                               }
+                                               
+                                               self = client;
+                                               playerdemo_open_write(argv(next_token));
+                                               return;
+                                       }
+                                       
+                                       case "auto_read_and_write":
+                                       {
+                                               n = GetFilteredNumber(argv(3));
+                                               cvar_set("bot_number", ftos(n));
+                                               
+                                               localcmd("wait; wait; wait\n");
+                                               for(i = 0; i < n; ++i) { localcmd("sv_cmd playerdemo read ", ftos(i+2), " ", argv(2), ftos(i+1), "\n"); }
+                                               
+                                               localcmd("sv_cmd playerdemo write 1 ", ftos(n+1), "\n");
+                                               return;
+                                       }
+                                       
+                                       case "auto_read":
+                                       {
+                                               n = GetFilteredNumber(argv(3));
+                                               cvar_set("bot_number", ftos(n));
+                                               
+                                               localcmd("wait; wait; wait\n");
+                                               for(i = 0; i < n; ++i) { localcmd("sv_cmd playerdemo read ", ftos(i+2), " ", argv(2), ftos(i+1), "\n"); }
+                                               return;
+                                       }
+                               }
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2playerdemo^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd playerdemo command (entitynumber filename | entitynumber botnumber)\n");
+                       print("  Full list of commands here: \"read, write, auto_read_and_write, auto_read.\"\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_printstats(float request) // legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       DumpStats(FALSE);
+                       print("stats dumped.\n");
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd printstats\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_radarmap(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(RadarMap_Make(argc))
+                               return;
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2radarmap^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd radarmap [--force] [--loop] [--quit] [--block | --trace | --sample | --lineblock] [--sharpen N] [--res W H] [--qual Q]\n");
+                       print("  The quality factor Q is roughly proportional to the time taken.\n");
+                       print("  trace supports no quality factor; its result should look like --block with infinite quality factor.\n");
+                       print("See also: ^2make_mapinfo^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_reducematchtime(float request) // legacy
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       changematchtime(autocvar_timelimit_decrement *-60, autocvar_timelimit_min * 60, autocvar_timelimit_max * 60);
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd reducematchtime\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2extendmatchtime^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_setbots(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argc >= 2)
+                       {
+                               cvar_settemp("minplayers", "0");
+                               cvar_settemp("bot_number", argv(1));
+                               bot_fixcount();
+                               return;
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2setbots^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd setbots botnumber\n");
+                       print("  Where 'botnumber' is the amount of bots to set bot_number cvar to.\n");
+                       print("See also: ^2bot_cmd^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_shuffleteams(float request)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(teamplay)
+                       {
+                               entity tmp_player, client;
+                               float i, x, z, t_teams, t_players, team_color, accepted;
+
+                               // count the total amount of players and total amount of teams
+                               FOR_EACH_PLAYER(tmp_player)
+                               {
+                                       CheckAllowedTeams(tmp_player);
+                                       
+                                       if(c1 >= 0) t_teams = max(1, t_teams);
+                                       if(c2 >= 0) t_teams = max(2, t_teams);
+                                       if(c3 >= 0) t_teams = max(3, t_teams);
+                                       if(c4 >= 0) t_teams = max(4, t_teams);
+                                       
+                                       ++t_players;
+                               }
+                               
+                               // build a list of the players in a random order
+                               FOR_EACH_PLAYER(tmp_player)
+                               {
+                                       for(;;)
+                                       {
+                                               i = bound(1, floor(random() * maxclients) + 1, maxclients);
+                                               
+                                               if(shuffleteams_players[i])
+                                               {
+                                                       continue; // a player is already assigned to this slot
+                                               }
+                                               else
+                                               {
+                                                       shuffleteams_players[i] = num_for_edict(tmp_player);
+                                                       break;
+                                               }
+                                       }
+                               }
+
+                               // finally, from the list made earlier, re-join the players in different order. 
+                               for(i = 1; i <= t_teams; ++i)
+                               {
+                                       // find out how many players to assign to this team
+                                       x = (t_players / t_teams);
+                                       x = ((i == 1) ? ceil(x) : floor(x));
+                                       
+                                       team_color = NumberToTeamNumber(i);
+                                       
+                                       // sort through the random list of players made earlier 
+                                       for(z = 1; z <= maxclients; ++z)
+                                       {                                                       
+                                               if not(shuffleteams_teams[i] >= x)
+                                               {
+                                                       if not(shuffleteams_players[z])
+                                                               continue; // not a player, move on to next random slot
+                                                               
+                                                       if(VerifyClientNumber(shuffleteams_players[z]))
+                                                               self = edict_num(shuffleteams_players[z]);
+
+                                                       if(self.team != team_color) 
+                                                               MoveToTeam(self, team_color, 6, 0);
+
+                                                       shuffleteams_players[z] = 0;
+                                                       shuffleteams_teams[i] = shuffleteams_teams[i] + 1;
+                                               }
+                                               else
+                                               {
+                                                       break; // move on to next team
+                                               }
+                                       }
+                               }
+                               
+                               bprint("Successfully shuffled the players around randomly.\n");
+                               
+                               // clear the buffers now
+                               for (i=0; i<SHUFFLETEAMS_MAX_PLAYERS; ++i)
+                                       shuffleteams_players[i] = 0;
+                               
+                               for (i=0; i<SHUFFLETEAMS_MAX_TEAMS; ++i)
+                                       shuffleteams_teams[i] = 0;
+                       }
+                       else
+                       {
+                               print("Can't shuffle teams when currently not playing a team game.\n");
+                       }
+                       
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd shuffleteams\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2moveplayer, allspec^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_stuffto(float request, float argc)
+{
+       // This... is a fairly dangerous and powerful command... - It allows any arguments to be sent to a client via rcon.
+       // Because of this, it is disabled by default and must be enabled by the server owner when doing compilation. That way,
+       // we can be certain they understand the risks of it... So to enable, compile server with -DSTUFFTO_ENABLED argument.
+       
+       #ifdef STUFFTO_ENABLED
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(argv(2))
+                       {
+                               entity client = GetIndexedEntity(argc, 1));
+                               float accepted = VerifyClientEntity(client, TRUE, FALSE);
+                               
+                               if(accepted > 0)
+                               {
+                                       stuffcmd(client, strcat("\n", argv(next_token), "\n"));
+                                       print(strcat("Command: \"", argv(next_token), "\" sent to ", GetCallerName(client), " (", argv(1) ,").\n"));
+                               }
+                               else
+                                       print("stuffto: ", GetClientErrorString(accepted, argv(1)), ".\n"); 
+                               
+                               return;
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2stuffto^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd stuffto client \"command\"\n");
+                       print("  'client' is the entity number or name of the player,\n");
+                       print("  and 'command' is the command to be sent to that player.\n");
+                       return;
+               }
+       }
+       #else
+       if(request)
+       {
+               print("stuffto command is not enabled on this server.\n");
+               return;
+       }
+       #endif
+}
+
+void GameCommand_trace(float request, float argc)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       // This is kinda a mess, a lot of it is legacy and thus not rewritten/optimized. 
+                       entity e;
+                       vector org, delta, start, end, p, q, q0, pos, vv, dv;
+                       float i, f, safe, unsafe, dq, dqf;
+       
+                       switch(argv(1))
+                       {
+                               case "debug":
+                               {
+                                       print("TEST CASE. If this returns the runaway loop counter error, possibly everything is oaky.\n");
+                                       for(;;)
+                                       {
+                                               org = world.mins;
+                                               delta = world.maxs - world.mins;
+
+                                               start_x = org_x + random() * delta_x;
+                                               start_y = org_y + random() * delta_y;
+                                               start_z = org_z + random() * delta_z;
+
+                                               end_x = org_x + random() * delta_x;
+                                               end_y = org_y + random() * delta_y;
+                                               end_z = org_z + random() * delta_z;
+
+                                               start = stov(vtos(start));
+                                               end = stov(vtos(end));
+
+                                               tracebox(start, PL_MIN, PL_MAX, end, MOVE_NOMONSTERS, world);
+                                               if(!trace_startsolid)
+                                               {
+                                                       p = trace_endpos;
+                                                       tracebox(p, PL_MIN, PL_MAX, p, MOVE_NOMONSTERS, world);
+                                                       if(trace_startsolid || trace_fraction == 1)
+                                                       {
+                                                               rint(42); // do an engine breakpoint on VM_rint so you can get the trace that errnoeously returns startsolid
+                                                               tracebox(start, PL_MIN, PL_MAX, end, MOVE_NOMONSTERS, world);
+                                                               tracebox(p, PL_MIN, PL_MAX, q, MOVE_NOMONSTERS, world);
+
+                                                               if(trace_startsolid)
+                                                               {
+                                                                       // how much do we need to back off?
+                                                                       safe = 1;
+                                                                       unsafe = 0;
+                                                                       for(;;)
+                                                                       {
+                                                                               pos = p * (1 - (safe + unsafe) * 0.5) + start * ((safe + unsafe) * 0.5);
+                                                                               tracebox(pos, PL_MIN, PL_MAX, pos, MOVE_NOMONSTERS, world);
+                                                                               if(trace_startsolid)
+                                                                               {
+                                                                                       if((safe + unsafe) * 0.5 == unsafe)
+                                                                                               break;
+                                                                                       unsafe = (safe + unsafe) * 0.5;
+                                                                               }
+                                                                               else
+                                                                               {
+                                                                                       if((safe + unsafe) * 0.5 == safe)
+                                                                                               break;
+                                                                                       safe = (safe + unsafe) * 0.5;
+                                                                               }
+                                                                       }
+
+                                                                       print("safe distance to back off: ", ftos(safe * vlen(p - start)), "qu\n");
+                                                                       print("unsafe distance to back off: ", ftos(unsafe * vlen(p - start)), "qu\n");
+
+                                                                       tracebox(p, PL_MIN + '0.1 0.1 0.1', PL_MAX - '0.1 0.1 0.1', p, MOVE_NOMONSTERS, world);
+                                                                       if(trace_startsolid)
+                                                                               print("trace_endpos much in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
+                                                                       else
+                                                                               print("trace_endpos just in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
+                                                                       break;
+                                                               }
+
+                                                               q0 = p;
+                                                               dq = 0;
+                                                               dqf = 1;
+                                                               for(;;)
+                                                               {
+                                                                       q = p + normalize(end - p) * (dq + dqf);
+                                                                       if(q == q0)
+                                                                               break;
+                                                                       tracebox(p, PL_MIN, PL_MAX, q, MOVE_NOMONSTERS, world);
+                                                                       if(trace_startsolid)
+                                                                               error("THIS ONE cannot happen");
+                                                                       if(trace_fraction > 0)
+                                                                               dq += dqf * trace_fraction;
+                                                                       dqf *= 0.5;
+                                                                       q0 = q;
+                                                               }
+                                                               if(dq > 0)
+                                                               {
+                                                                       print("trace_endpos still before solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
+                                                                       print("could go ", ftos(dq), " units further to ", vtos(q), "\n");
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       return;
+                               }
+                                       
+                               case "debug2":
+                               {
+                                       e = nextent(world);
+                                       tracebox(e.origin + '0 0 32', e.mins, e.maxs, e.origin + '0 0 -1024', MOVE_NORMAL, e);
+                                       vv = trace_endpos;
+                                       if(trace_fraction == 1)
+                                       {
+                                               print("not above ground, aborting\n");
+                                               return;
+                                       }
+                                       f = 0;
+                                       for(i = 0; i < 100000; ++i)
+                                       {
+                                               dv = randomvec();
+                                               if(dv_z > 0)
+                                                       dv = -1 * dv;
+                                               tracebox(vv, e.mins, e.maxs, vv + dv, MOVE_NORMAL, e);
+                                               if(trace_startsolid)
+                                                       print("bug 1\n");
+                                               if(trace_fraction == 1)
+                                               if(dv_z < f)
+                                               {
+                                                       print("bug 2: ", ftos(dv_x), " ", ftos(dv_y), " ", ftos(dv_z));
+                                                       print(" (", ftos(asin(dv_z / vlen(dv)) * 180 / M_PI), " degrees)\n");
+                                                       f = dv_z;
+                                               }
+                                       }
+                                       print("highest possible dist: ", ftos(f), "\n");
+                                       return;
+                               }
+                               
+                               case "walk":
+                               {
+                                       if(argc == 3)
+                                       {
+                                               e = nextent(world);
+                                               if(tracewalk(e, stov(argv(1)), e.mins, e.maxs, stov(argv(2)), MOVE_NORMAL))
+                                                       print("can walk\n");
+                                               else
+                                                       print("cannot walk\n");
+                                               return;
+                                       }
+                               }
+                               
+                               case "showline":
+                               {
+                                       if(argc == 3)
+                                       {
+                                               vv = stov(argv(1));
+                                               dv = stov(argv(2));
+                                               traceline(vv, dv, MOVE_NORMAL, world);
+                                               trailparticles(world, particleeffectnum("TR_NEXUIZPLASMA"), vv, trace_endpos);
+                                               trailparticles(world, particleeffectnum("TR_CRYLINKPLASMA"), trace_endpos, dv);
+                                               return;
+                                       }
+                               }
+                               
+                               // no default case, just go straight to invalid
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2trace^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd trace command (startpos endpos)\n");
+                       print("  Full list of commands here: \"debug, debug2, walk, showline.\"\n");
+                       print("See also: ^2bbox, gettaginfo^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_unlockteams(float request)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(teamplay)
+                       {
+                               lockteams = 0;
+                               bprint("^1The teams are now unlocked.\n");
+                       }
+                       else
+                       {
+                               bprint("unlockteams command can only be used in a team-based gamemode.\n");
+                       }
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd unlockteams\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2lockteams^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_warp(float request, float argc) // mostly legacy
+{
+       switch (request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(autocvar_g_campaign)
+                       {
+                               if(argc >= 2)
+                               {
+                                       CampaignLevelWarp(stof(argv(1)));
+                                       print("Successfully warped to campaign level ", stof(argv(1)), ".\n");
+                               }       
+                               else
+                               {
+                                       CampaignLevelWarp(-1);
+                                       print("Successfully warped to next campaign level.\n");
+                               }
+                       }
+                       else
+                               print("Not in campaign, can't level warp\n");
+                       return;
+               }
+               
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd level\n");
+                       print("  'level' is the level to change campaign mode to.\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 GameCommand_(float request)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd \n");
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+*/
+
+
+// ==================================
+//  Macro system for server commands
+// ==================================
+
+// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
+// Common commands have double indentation to separate them a bit.
+#define SERVER_COMMANDS(request,arguments,command) \
+       SERVER_COMMAND("adminmsg", GameCommand_adminmsg(request, arguments), "Send an admin message to a client directly") \
+       SERVER_COMMAND("allready", GameCommand_allready(request), "Restart the server and reset the players") \
+       SERVER_COMMAND("allspec", GameCommand_allspec(request, arguments), "Force all players to spectate") \
+       SERVER_COMMAND("anticheat", GameCommand_anticheat(request, arguments), "Create an anticheat report for a client") \
+       SERVER_COMMAND("bbox", GameCommand_bbox(request), "Print detailed information about world size") \
+       SERVER_COMMAND("bot_cmd", GameCommand_bot_cmd(request, arguments), "Control and send commands to bots") \
+       SERVER_COMMAND("cointoss", GameCommand_cointoss(request, arguments), "Flip a virtual coin and give random result") \
+       SERVER_COMMAND("database", GameCommand_database(request, arguments), "Extra controls of the serverprogs database") \
+       SERVER_COMMAND("defer_clear", GameCommand_defer_clear(request, arguments), "Clear all queued defer commands for a specific client") \
+       SERVER_COMMAND("defer_clear_all", GameCommand_defer_clear_all(request), "Clear all queued defer commands for all clients") \
+       SERVER_COMMAND("delrec", GameCommand_delrec(request, arguments), "Delete race time record for a map") \
+       SERVER_COMMAND("effectindexdump", GameCommand_effectindexdump(request), "Dump list of effects from code and effectinfo.txt") \
+       SERVER_COMMAND("extendmatchtime", GameCommand_extendmatchtime(request), "Increase the timelimit value incrementally") \
+       SERVER_COMMAND("find", GameCommand_find(request, arguments), "Search through entities for matching classname") \
+       SERVER_COMMAND("gametype", GameCommand_gametype(request, arguments), "Simple command to change the active gametype") \
+       SERVER_COMMAND("gettaginfo", GameCommand_gettaginfo(request, arguments), "Get specific information about a weapon model") \
+       SERVER_COMMAND("gotomap", GameCommand_gotomap(request, arguments), "Simple command to switch to another map") \
+       SERVER_COMMAND("lockteams", GameCommand_lockteams(request), "Disable the ability for players to switch or enter teams") \
+       SERVER_COMMAND("make_mapinfo", GameCommand_make_mapinfo(request), "Automatically rebuild mapinfo files") \
+       SERVER_COMMAND("moveplayer", GameCommand_moveplayer(request, arguments), "Change the team/status of a player") \
+       SERVER_COMMAND("nospectators", GameCommand_nospectators(request), "Automatically remove spectators from a match") \
+       SERVER_COMMAND("playerdemo", GameCommand_playerdemo(request, arguments), "Control the ability to save demos of players") \
+       SERVER_COMMAND("printstats", GameCommand_printstats(request), "Dump eventlog player stats and other score information") \
+       SERVER_COMMAND("radarmap", GameCommand_radarmap(request, arguments), "Generate a radar image of the map") \
+       SERVER_COMMAND("reducematchtime", GameCommand_reducematchtime(request), "Decrease the timelimit value incrementally") \
+       SERVER_COMMAND("setbots", GameCommand_setbots(request, arguments), "Adjust how many bots are in the match") \
+       SERVER_COMMAND("shuffleteams", GameCommand_shuffleteams(request), "Randomly move players to different teams") \
+       SERVER_COMMAND("stuffto", GameCommand_stuffto(request, arguments), "Send a command to be executed on a client") \
+       SERVER_COMMAND("trace", GameCommand_trace(request, arguments), "Various debugging tools with tracing") \
+       SERVER_COMMAND("unlockteams", GameCommand_unlockteams(request), "Enable the ability for players to switch or enter teams") \
+       SERVER_COMMAND("warp", GameCommand_warp(request, arguments), "Choose different level in campaign") \
+       /* nothing */
+
+void GameCommand_macro_help()
+{
+       #define SERVER_COMMAND(name,function,description) \
+               { print("  ^2", name, "^7: ", description, "\n"); }
+               
+       SERVER_COMMANDS(0, 0, "")
+       #undef SERVER_COMMAND
+       
+       return;
+}
+
+float GameCommand_macro_command(float argc, string command)
+{
+       #define SERVER_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(0))) { function; return TRUE; } }
+               
+       SERVER_COMMANDS(CMD_REQUEST_COMMAND, argc, command)
+       #undef SERVER_COMMAND
+       
+       return FALSE;
+}
+
+float GameCommand_macro_usage(float argc)
+{
+       #define SERVER_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(1))) { function; return TRUE; } }
+               
+       SERVER_COMMANDS(CMD_REQUEST_USAGE, argc, "")
+       #undef SERVER_COMMAND
+       
+       return FALSE;
+}
+
+void GameCommand_macro_write_aliases(float fh)
+{
+       #define SERVER_COMMAND(name,function,description) \
+               { CMD_Write_Alias("qc_cmd_sv", name, description); }
+               
+       SERVER_COMMANDS(0, 0, "")
+       #undef SERVER_COMMAND
+       
+       return;
+}
+       
+
+// =========================================
+//  Main Function Called By Engine (sv_cmd)
+// =========================================
+// If this function exists, game 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("\nServer console commands:\n");
+                       GameCommand_macro_help();
+                       
+                       print("\nBanning commands:\n");
+                       BanCommand_macro_help();
+                       
+                       print("\nCommon networked commands:\n");
+                       CommonCommand_macro_help(world);
+                       
+                       print("\nGeneric commands shared by all programs:\n");
+                       GenericCommand_macro_help();
+                       
+                       print("\nUsage:^3 sv_cmd COMMAND...^7, where possible commands are listed above.\n");
+                       print("For help about a specific command, type sv_cmd help COMMAND\n");
+                       
+                       return;
+               } 
+               else if(BanCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
+               {
+                       return;
+               }
+               else if(CommonCommand_macro_usage(argc, world)) // same here, but for common commands instead
+               {
+                       return;
+               }
+               else if(GenericCommand_macro_usage(argc)) // same here, but for generic commands instead
+               {
+                       return;
+               }
+               else if(GameCommand_macro_usage(argc)) // finally try for normal commands too
+               {
+                       return;
+               }
+       } 
+       else if(BanCommand(command)) 
+       {
+               return; // handled by server/command/ipban.qc
+       }
+       else if(CommonCommand_macro_command(argc, world, command))
+       {
+               return; // handled by server/command/common.qc
+       }
+       else if(GenericCommand(command)) 
+       {
+               return; // handled by common/command/generic.qc
+       }
+       else if(GameCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
+       {
+               return; // handled by one of the above GameCommand_* functions
+       }
+       
+       // nothing above caught the command, must be invalid
+       print(((command != "") ? strcat("Unknown server command \"", command, "\"") : "No command provided"), ". For a list of supported commands, try sv_cmd help.\n");
+       
+       return;
+}
\ No newline at end of file
diff --git a/qcsrc/server/command/sv_cmd.qh b/qcsrc/server/command/sv_cmd.qh
new file mode 100644 (file)
index 0000000..03bd80c
--- /dev/null
@@ -0,0 +1,16 @@
+// =================================================
+//  Declarations for server side game commands
+//  Last updated: December 25th, 2011
+// =================================================
+
+string GotoMap(string m);
+
+void race_deleteTime(string map, float pos);
+
+#define SHUFFLETEAMS_MAX_PLAYERS 255
+#define SHUFFLETEAMS_MAX_TEAMS 4
+float shuffleteams_players[SHUFFLETEAMS_MAX_PLAYERS]; // maximum of 255 player slots
+float shuffleteams_teams[SHUFFLETEAMS_MAX_TEAMS]; // maximum of 4 teams
+
+// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
+void GameCommand_macro_write_aliases(float fh);
\ No newline at end of file
diff --git a/qcsrc/server/command/vote.qc b/qcsrc/server/command/vote.qc
new file mode 100644 (file)
index 0000000..2777203
--- /dev/null
@@ -0,0 +1,988 @@
+// =============================================
+//  Server side voting code, reworked by Samual
+//  Last updated: December 27th, 2011
+// =============================================
+
+//  Nagger for players to know status of voting
+float Nagger_SendEntity(entity to, float sendflags)
+{
+       float nags, i, f, b;
+       entity e;
+       WriteByte(MSG_ENTITY, ENT_CLIENT_NAGGER);
+
+       // bits:
+       //   1 = ready
+       //   2 = player needs to ready up
+       //   4 = vote
+       //   8 = player needs to vote
+       //  16 = warmup
+       // sendflags:
+       //  64 = vote counts
+       // 128 = vote string
+
+       nags = 0;
+       if(readycount)
+       {
+               nags |= 1;
+               if(to.ready == 0)
+                       nags |= 2;
+       }
+       if(vote_called)
+       {
+               nags |= 4;
+               if(to.vote_selection == 0)
+                       nags |= 8;
+       }
+       if(inWarmupStage)
+               nags |= 16;
+
+       if(sendflags & 64)
+               nags |= 64;
+
+       if(sendflags & 128)
+               nags |= 128;
+
+       if(!(nags & 4)) // no vote called? send no string
+               nags &~= (64 | 128);
+
+       WriteByte(MSG_ENTITY, nags);
+
+       if(nags & 64)
+       {
+               WriteByte(MSG_ENTITY, vote_accept_count);
+               WriteByte(MSG_ENTITY, vote_reject_count);
+               WriteByte(MSG_ENTITY, vote_needed_overall);
+               WriteChar(MSG_ENTITY, to.vote_selection);
+       }
+
+       if(nags & 128)
+               WriteString(MSG_ENTITY, vote_called_display);
+
+       if(nags & 1)
+       {
+               for(i = 1; i <= maxclients; i += 8)
+               {
+                       for(f = 0, e = edict_num(i), b = 1; b < 256; b *= 2, e = nextent(e))
+                               if(clienttype(e) != CLIENTTYPE_REAL || e.ready)
+                                       f |= b;
+                       WriteByte(MSG_ENTITY, f);
+               }
+       }
+
+       return TRUE;
+}
+
+void Nagger_Init()
+{
+       Net_LinkEntity(nagger = spawn(), FALSE, 0, Nagger_SendEntity);
+}
+
+void Nagger_VoteChanged()
+{
+       if(nagger)
+               nagger.SendFlags |= 128;
+}
+
+void Nagger_VoteCountChanged()
+{
+       if(nagger)
+               nagger.SendFlags |= 64;
+}
+
+void Nagger_ReadyCounted()
+{
+       if(nagger)
+               nagger.SendFlags |= 1;
+}
+
+
+// =======================
+//  Game logic for voting
+// =======================
+
+void VoteReset() 
+{
+       entity tmp_player;
+
+       FOR_EACH_CLIENT(tmp_player) { tmp_player.vote_selection = 0; }
+
+       if(vote_called)
+       {
+               strunzone(vote_called_command);
+               strunzone(vote_called_display);
+       }
+
+       vote_called = VOTE_NULL;
+       vote_caller = world;
+       vote_endtime = 0;
+       
+       vote_called_command = string_null;
+       vote_called_display = string_null;
+       
+       vote_parsed_command = string_null;
+       vote_parsed_display = string_null;
+
+       Nagger_VoteChanged();
+}
+
+void VoteStop(entity stopper) 
+{
+       bprint("\{1}^2* ^3", GetCallerName(stopper), "^2 stopped ^3", GetCallerName(vote_caller), "^2's vote\n");
+       if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vstop:", ftos(stopper.playerid))); }
+       
+       // Don't force them to wait for next vote, this way they can e.g. correct their vote.
+       if((vote_caller) && (stopper == vote_caller)) { vote_caller.vote_waittime = time + autocvar_sv_vote_stop; }
+
+       VoteReset();
+}
+
+void VoteAccept() 
+{
+       bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ^1", vote_called_display, "^2 was accepted\n");
+       
+       if((vote_called == VOTE_MASTER) && vote_caller)
+               vote_caller.vote_master = 1;
+       else
+               localcmd(strcat(vote_called_command, "\n"));
+       
+       if(vote_caller) { vote_caller.vote_waittime = 0; } // people like your votes, you don't need to wait to vote again
+
+       VoteReset();
+       Announce("voteaccept");
+}
+
+void VoteReject() 
+{
+       bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ", vote_called_display, "^2 was rejected\n");
+       VoteReset();
+       Announce("votefail");
+}
+
+void VoteTimeout() 
+{
+       bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ", vote_called_display, "^2 timed out\n");
+       VoteReset();
+       Announce("votefail");
+}
+
+void VoteSpam(float notvoters, float mincount, string result)
+{
+       bprint(strcat(
+               strcat("\{1}^2* vote results: ^1", ftos(vote_accept_count)),
+               strcat("^2:^1", ftos(vote_reject_count)),
+               ((mincount >= 0) ? strcat("^2 (^1", ftos(mincount), "^2 needed)") : "^2"),
+               strcat(", ^1", ftos(vote_abstain_count), "^2 didn't care"),
+               strcat(", ^1", ftos(notvoters), strcat("^2 didn't ", ((mincount >= 0) ? string_null : "have to "), "vote\n"))));
+       
+       if(autocvar_sv_eventlog)
+       {
+               GameLogEcho(strcat(
+                       strcat(":vote:v", result, ":", ftos(vote_accept_count)),
+                       strcat(":", ftos(vote_reject_count)),
+                       strcat(":", ftos(vote_abstain_count)),
+                       strcat(":", ftos(notvoters)),
+                       strcat(":", ftos(mincount))));
+       }
+}
+
+void VoteCount() 
+{
+       // declarations
+       vote_accept_count = vote_reject_count = vote_abstain_count = 0;
+       
+       float spectators_allowed = ((autocvar_sv_vote_nospectators != 2) 
+                               || ((autocvar_sv_vote_nospectators == 1) && inWarmupStage) 
+                               || (autocvar_sv_vote_nospectators == 0));
+                               
+       float vote_player_count, is_player, notvoters;
+       float vote_real_player_count, vote_real_accept_count;
+       float vote_real_reject_count, vote_real_abstain_count;
+       float vote_needed_of_voted, final_needed_votes;
+       float vote_factor_overall, vote_factor_of_voted;
+       
+       entity tmp_player;
+
+       Nagger_VoteCountChanged();
+       
+       // add up all the votes from each connected client
+       FOR_EACH_REALCLIENT(tmp_player)
+       {
+               is_player = (tmp_player.classname == "player");
+               
+               ++vote_player_count;
+               if(is_player) { ++vote_real_player_count; }
+               
+               switch(tmp_player.vote_selection)
+               {
+                       case VOTE_SELECT_REJECT: { ++vote_reject_count; { if(is_player) ++vote_real_reject_count; } break; }
+                       case VOTE_SELECT_ACCEPT: { ++vote_accept_count; { if(is_player) ++vote_real_reject_count; } break; }
+                       case VOTE_SELECT_ABSTAIN: { ++vote_abstain_count; { if(is_player) ++vote_real_abstain_count; } break; }
+                       default: break;
+               }
+       }
+       
+       // Check to see if there are enough players on the server to allow master voting... otherwise, vote master could be used for evil.
+       if((vote_called == VOTE_MASTER) && autocvar_sv_vote_master_playerlimit > vote_player_count) 
+       {
+               if(vote_caller) { vote_caller.vote_waittime = 0; }
+               print_to(vote_caller, "^1There are not enough players on this server to allow you to become vote master.");
+               VoteReset();
+               return;
+       }
+       
+       // if spectators aren't allowed to vote and there are players in a match, then only count the players in the vote and ignore spectators. 
+       if(!spectators_allowed && (vote_real_player_count > 0))
+       {
+               vote_accept_count = vote_real_accept_count;
+               vote_reject_count = vote_real_reject_count;
+               vote_abstain_count = vote_real_abstain_count;
+               vote_player_count = vote_real_player_count;
+       }
+       
+       // people who have no opinion in any way :D
+       notvoters = (vote_player_count - vote_accept_count - vote_reject_count - vote_abstain_count);
+
+       // determine the goal for the vote to be passed or rejected normally
+       vote_factor_overall = bound(0.5, autocvar_sv_vote_majority_factor, 0.999);
+       vote_needed_overall = floor((vote_player_count - vote_abstain_count) * vote_factor_overall) + 1;
+       
+       // if the vote times out, determine the amount of votes needed of the people who actually already voted
+       vote_factor_of_voted = bound(0.5, autocvar_sv_vote_majority_factor_of_voted, 0.999);
+       vote_needed_of_voted = floor((vote_accept_count + vote_reject_count) * vote_factor_of_voted) + 1;
+       
+       
+       // finally calculate the result of the vote     
+       if(vote_accept_count >= vote_needed_overall)
+       {
+               VoteSpam(notvoters, -1, "yes"); // there is enough acceptions to pass the vote
+               VoteAccept();
+               return;
+       }
+       
+       if(vote_reject_count > vote_player_count - vote_abstain_count - vote_needed_overall)
+       {
+               VoteSpam(notvoters, -1, "no"); // there is enough rejections to deny the vote
+               VoteReject();
+               return;
+       }
+       
+       // there is not enough votes in either direction, now lets just calculate what the voters have said
+       if(time > vote_endtime)
+       {
+               final_needed_votes = vote_needed_overall;
+               
+               if(autocvar_sv_vote_majority_factor_of_voted)
+               {
+                       if(vote_accept_count >= vote_needed_of_voted)
+                       {
+                               VoteSpam(notvoters, min(vote_needed_overall, vote_needed_of_voted), "yes");
+                               VoteAccept();
+                               return;
+                       }
+                       
+                       if(vote_accept_count + vote_reject_count > 0)
+                       {
+                               VoteSpam(notvoters, min(vote_needed_overall, vote_needed_of_voted), "no");
+                               VoteReject();
+                               return;
+                       }
+                       
+                       final_needed_votes = min(vote_needed_overall, vote_needed_of_voted);
+               }
+
+               // it didn't pass or fail, so not enough votes to even make a decision. 
+               VoteSpam(notvoters, final_needed_votes, "timeout");
+               VoteTimeout();
+       }
+}
+
+void VoteThink() 
+{
+       if(vote_endtime > 0) // a vote was called
+       if(time > vote_endtime) // time is up
+       {
+               VoteCount();
+       }
+       
+       return;
+}
+
+
+// =======================
+//  Game logic for warmup
+// =======================
+
+// Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown is set)
+void ReadyRestart_think() 
+{
+       restart_mapalreadyrestarted = 1;
+       reset_map(TRUE);
+       Score_ClearAll();
+       remove(self);
+       
+       return;
+}
+
+// Forces a restart of the game without actually reloading the map // this is a mess...
+void ReadyRestart_force()
+{
+       entity tmp_player, restart_timer;
+
+       bprint("^1Server is restarting...\n");
+
+       VoteReset();
+
+       // clear overtime, we have to decrease timelimit to its original value again.
+       if (checkrules_overtimesadded > 0 && g_race_qualifying != 2) { cvar_set("timelimit", ftos(autocvar_timelimit - (checkrules_overtimesadded * autocvar_timelimit_overtime))); }
+
+       checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = 0;
+
+       readyrestart_happened = 1;
+       game_starttime = time;
+       if(!g_ca && !g_arena) { game_starttime += RESTART_COUNTDOWN; }
+               
+       restart_mapalreadyrestarted = 0; // reset this var, needed when cvar sv_ready_restart_repeatable is in use
+
+       // disable the warmup global for the server
+       inWarmupStage = 0; // once the game is restarted the game is in match stage
+
+       // reset the .ready status of all players (also spectators)
+       FOR_EACH_CLIENTSLOT(tmp_player) { tmp_player.ready = 0; }
+       readycount = 0;
+       Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
+
+       // lock teams with lockonrestart
+       if(autocvar_teamplay_lockonrestart && teamplay) 
+       {
+               lockteams = 1;
+               bprint("^1The teams are now locked.\n");
+       }
+
+       //initiate the restart-countdown-announcer entity
+       if(autocvar_sv_ready_restart_after_countdown && !g_ca && !g_arena)
+       {
+               restart_timer = spawn();
+               restart_timer.think = ReadyRestart_think;
+               restart_timer.nextthink = game_starttime;
+       }
+
+       // after a restart every players number of allowed timeouts gets reset, too
+       if(autocvar_sv_timeout) { FOR_EACH_REALPLAYER(tmp_player) { tmp_player.allowed_timeouts = autocvar_sv_timeout_number; } }
+
+       //reset map immediately if this cvar is not set
+       if not(autocvar_sv_ready_restart_after_countdown) { reset_map(TRUE); }
+
+       if(autocvar_sv_eventlog) { GameLogEcho(":restart"); }
+}
+
+void ReadyRestart()
+{
+       // no arena, assault support yet...
+       if(g_arena | g_assault | gameover | intermission_running | race_completing)
+               localcmd("restart\n");
+       else
+               localcmd("\nsv_hook_gamerestart\n");
+
+       // Reset ALL scores, but only do that at the beginning of the countdown if sv_ready_restart_after_countdown is off!
+       // Otherwise scores could be manipulated during the countdown.
+       if not(autocvar_sv_ready_restart_after_countdown) { Score_ClearAll(); }
+
+       ReadyRestart_force();
+       
+       return;
+}
+
+// Count the players who are ready and determine whether or not to restart the match
+void ReadyCount()
+{
+       entity tmp_player;
+       float ready_needed_factor, ready_needed_count;
+       float t_ready, t_players;
+
+       FOR_EACH_REALPLAYER(tmp_player)
+       {
+               ++t_players;
+               if(tmp_player.ready) { ++t_ready; }
+       }
+
+       readycount = t_ready;
+
+       Nagger_ReadyCounted();
+
+       ready_needed_factor = bound(0.5, cvar("g_warmup_majority_factor"), 0.999);
+       ready_needed_count = floor(t_players * ready_needed_factor) + 1;
+       
+       if(readycount >= ready_needed_count)
+       {
+               ReadyRestart();
+       }
+               
+       return;
+}
+
+
+// ======================================
+//  Supporting functions for VoteCommand
+// ======================================
+
+float Votecommand_check_assignment(entity caller, float assignment)
+{
+       float from_server = (!caller);
+       
+       if((assignment == VC_ASGNMNT_BOTH) 
+               || ((!from_server && assignment == VC_ASGNMNT_CLIENTONLY) 
+               || (from_server && assignment == VC_ASGNMNT_SERVERONLY)))
+       {
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+string VoteCommand_extractcommand(string input, float startpos, float argc) 
+{
+       string output;
+       
+       if((argc - 1) < startpos)
+               output = "";
+       else
+               output = substring(input, argv_start_index(startpos), argv_end_index(-1) - argv_start_index(startpos));
+               
+       return output;
+}
+
+float VoteCommand_checknasty(string vote_command)
+{
+       if((strstrofs(vote_command, ";", 0) >= 0)
+               || (strstrofs(vote_command, "\n", 0) >= 0)
+               || (strstrofs(vote_command, "\r", 0) >= 0)
+               || (strstrofs(vote_command, "$", 0) >= 0))
+               return FALSE;
+               
+       return TRUE;
+}
+
+float VoteCommand_checkinlist(string vote_command, string list)
+{
+       string l = strcat(" ", list, " ");
+       
+       if(strstrofs(l, strcat(" ", vote_command, " "), 0) >= 0)
+               return TRUE;
+       
+       // if gotomap is allowed, chmap is too, and vice versa
+       if(vote_command == "gotomap")
+               if(strstrofs(l, " chmap ", 0) >= 0)
+                       return TRUE;
+                       
+       if(vote_command == "chmap")
+               if(strstrofs(l, " gotomap ", 0) >= 0)
+                       return TRUE;
+       
+       return FALSE;
+}
+
+string ValidateMap(string validated_map, entity caller)
+{
+       validated_map = MapInfo_FixName(validated_map);
+       
+       if(!validated_map)
+       {
+               print_to(caller, "This map is not available on this server.");
+               return string_null;
+       }
+       
+       if(!autocvar_sv_vote_override_mostrecent && caller)
+       {
+               if(Map_IsRecent(validated_map))
+               {
+                       print_to(caller, "This server does not allow for recent maps to be played again. Please be patient for some rounds.");
+                       return string_null;
+               }
+       }
+       
+       if(!MapInfo_CheckMap(validated_map))
+       {
+               print_to(caller, strcat("^1Invalid mapname, \"^3", validated_map, "^1\" does not support the current game mode."));
+               return string_null;
+       }
+
+       return validated_map;
+}
+
+float VoteCommand_parse(entity caller, string vote_command, string vote_list, float startpos, float argc)
+{
+       string first_command;
+       
+       first_command = argv(startpos);
+
+       if not(VoteCommand_checkinlist(first_command, vote_list))
+               return FALSE;
+
+       if(argc < startpos) // These commands won't work without arguments
+       {
+               switch(first_command)
+               {
+                       case "map":
+                       case "chmap":
+                       case "gotomap":
+                       case "kick":
+                       case "kickban":
+                               return FALSE;
+                               
+                       default: { break; }
+               }
+       }
+       
+       switch(first_command) // now go through and parse the proper commands to adjust as needed.
+       {
+               case "kick":
+               case "kickban": // catch all kick/kickban commands
+               {
+                       entity victim = GetIndexedEntity(argc, (startpos + 1));
+                       float accepted = VerifyClientEntity(victim, TRUE, FALSE);
+                       
+                       if(accepted > 0)
+                       {
+                               string reason = ((argc > next_token) ? substring(vote_command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token)) : "No reason provided");
+                               string command_arguments;
+                               
+                               if(first_command == "kickban")
+                                       command_arguments = strcat(ftos(autocvar_g_ban_default_bantime), " ", ftos(autocvar_g_ban_default_masksize), " ~");
+                               else
+                                       command_arguments = reason;
+                               
+                               vote_parsed_command = strcat(first_command, " # ", ftos(num_for_edict(victim)), " ", command_arguments);
+                               vote_parsed_display = strcat("^1", vote_command, " (^7", victim.netname, "^1): ", reason);
+                       }
+                       else { print_to(caller, strcat("vcall: ", GetClientErrorString(accepted, argv(startpos + 1)), ".\n")); return FALSE; }
+                       
+                       break;
+               }
+               
+               case "map":
+               case "chmap":
+               case "gotomap": // re-direct all map selection commands to gotomap
+               {
+                       vote_command = ValidateMap(argv(startpos + 1), caller);
+                       if not(vote_command) { return FALSE; }
+                       vote_parsed_command = strcat("gotomap ", vote_command);
+                       vote_parsed_display = strzone(strcat("^1", vote_parsed_command));
+                       
+                       break;
+               }
+               
+               default: 
+               { 
+                       vote_parsed_command = vote_command;
+                       vote_parsed_display = strzone(strcat("^1", vote_command));
+                       
+                       break; 
+               }
+       }
+
+       return TRUE;
+}
+
+
+// =======================
+//  Command Sub-Functions
+// =======================
+
+void VoteCommand_abstain(float request, entity caller) // CLIENT ONLY
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if not(vote_called) { print_to(caller, "^1No vote called."); }
+                       else if not(caller.vote_selection == VOTE_SELECT_NULL || autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
+                       
+                       else // everything went okay, continue changing vote
+                       {
+                               print_to(caller, "^1You abstained from your vote.");
+                               caller.vote_selection = VOTE_SELECT_ABSTAIN;
+                               msg_entity = caller;
+                               if(!autocvar_sv_vote_singlecount) { VoteCount(); }
+                       }
+                       
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote abstain"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void VoteCommand_call(float request, entity caller, float argc, string vote_command) // BOTH
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       float spectators_allowed = ((autocvar_sv_vote_nospectators != 2) 
+                               || ((autocvar_sv_vote_nospectators == 1) && inWarmupStage) 
+                               || (autocvar_sv_vote_nospectators == 0));
+                               
+                       float tmp_playercount;
+                       entity tmp_player;
+                       
+                       vote_command = VoteCommand_extractcommand(vote_command, 2, argc);
+                       
+                       if not(autocvar_sv_vote_call || !caller) { print_to(caller, "^1Vote calling is not allowed."); }
+                       else if(vote_called) { print_to(caller, "^1There is already a vote called."); }
+                       else if(!spectators_allowed && (caller && (caller.classname != "player"))) { print_to(caller, "^1Only players can call a vote."); }
+                       else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
+                       else if(caller && (time < caller.vote_waittime)) { print_to(caller, strcat("^1You have to wait ^2", ftos(ceil(caller.vote_waittime - time)), "^1 seconds before you can again call a vote.")); }
+                       else if not(VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
+                       else if not(VoteCommand_parse(caller, vote_command, autocvar_sv_vote_commands, 2, argc)) { print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info."); }
+
+                       else // everything went okay, continue with calling the vote
+                       {
+                               vote_caller = caller; // remember who called the vote
+                               vote_called = VOTE_NORMAL;
+                               vote_called_command = strzone(vote_parsed_command);
+                               vote_called_display = strzone(vote_parsed_display);
+                               vote_endtime = time + autocvar_sv_vote_timeout;
+                               
+                               if(caller)
+                               {
+                                       caller.vote_selection = VOTE_SELECT_ACCEPT;
+                                       caller.vote_waittime = time + autocvar_sv_vote_wait;
+                                       msg_entity = caller;
+                               }
+                               
+                               FOR_EACH_REALCLIENT(tmp_player) { ++tmp_playercount; }
+                               if(tmp_playercount > 1) { Announce("votecall"); } // don't announce a "vote now" sound if player is alone
+                               
+                               bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2 calls a vote for ", vote_called_display, "\n");
+                               if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }
+                               Nagger_VoteChanged();
+                               VoteCount(); // needed if you are the only one
+                       }
+                       
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote call command"));
+                       print_to(caller, "  Where 'command' is the command to request a vote upon.");
+                       print_to(caller, strcat("Examples: ", GetCommandPrefix(caller), " vote call gotomap dance"));
+                       print_to(caller, strcat("          ", GetCommandPrefix(caller), " vote call endmatch"));
+                       return;
+               }
+       }
+}
+
+void VoteCommand_master(float request, entity caller, float argc, string vote_command) // CLIENT ONLY
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(autocvar_sv_vote_master)
+                       {
+                               switch(strtolower(argv(2)))
+                               {
+                                       case "do":
+                                       {
+                                               vote_command = VoteCommand_extractcommand(vote_command, 3, argc);
+                                               
+                                               if not(caller.vote_master) { print_to(caller, "^1You do not have vote master privelages."); }
+                                               else if not(VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
+                                               else if not(VoteCommand_parse(caller, vote_command, autocvar_sv_vote_master_commands, 3, argc)) { print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info."); }
+                                               
+                                               else // everything went okay, proceed with command
+                                               {
+                                                       localcmd(strcat(vote_parsed_command, "\n"));
+                                                       print_to(caller, strcat("Executing command '", vote_parsed_display, "' on server."));
+                                                       bprint("\{1}^2* ^3", GetCallerName(caller), "^2 used their ^3master^2 status to do \"^2", vote_parsed_display, "^2\".\n");
+                                                       if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vdo:", ftos(caller.playerid), ":", vote_parsed_display)); }
+                                               }
+                                               
+                                               return;
+                                       }
+                                       
+                                       case "login":
+                                       {
+                                               if not(autocvar_sv_vote_master_password != "") { print_to(caller, "^1Login to vote master is not allowed."); }
+                                               else if(caller.vote_master) { print_to(caller, "^1You are already logged in as vote master."); }
+                                               else if not(autocvar_sv_vote_master_password == argv(3)) { print_to(caller, strcat("Rejected vote master login from ", GetCallerName(caller))); }
+
+                                               else // everything went okay, proceed with giving this player master privilages
+                                               {
+                                                       caller.vote_master = TRUE;
+                                                       print_to(caller, strcat("Accepted vote master login from ", GetCallerName(caller)));
+                                                       bprint("\{1}^2* ^3", GetCallerName(caller), "^2 logged in as ^3master^2\n");
+                                                       if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vlogin:", ftos(caller.playerid))); }
+                                               }
+                                               
+                                               return;
+                                       }
+                                       
+                                       default: // calling a vote for master
+                                       {
+                                               if not(autocvar_sv_vote_master_callable) { print_to(caller, "^1Vote to become vote master is not allowed."); }
+                                               else if(vote_called) { print_to(caller, "^1There is already a vote called."); }
+                                               else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
+                                               
+                                               else // everything went okay, continue with creating vote
+                                               {
+                                                       vote_caller = caller;
+                                                       vote_called = VOTE_MASTER;
+                                                       vote_called_command = strzone("XXX");
+                                                       vote_called_display = strzone("^3master");
+                                                       vote_endtime = time + autocvar_sv_vote_timeout;
+                                                       
+                                                       caller.vote_selection = VOTE_SELECT_ACCEPT;
+                                                       caller.vote_waittime = time + autocvar_sv_vote_wait;
+                                                       
+                                                       bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2 calls a vote to become ^3master^2.\n");
+                                                       if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }
+                                                       Nagger_VoteChanged();
+                                                       VoteCount(); // needed if you are the only one
+                                               }
+                                               
+                                               return;
+                                       }
+                               }
+                       }
+                       else { print_to(caller, "^1Master control of voting is not allowed."); }
+                       
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote master [action [command | password]]"));
+                       print_to(caller, "  If action is left blank, it calls a vote for you to become master.");
+                       print_to(caller, "  Otherwise the actions are either 'do' a command or 'login' as master.");
+                       return;
+               }
+       }
+}
+
+void VoteCommand_no(float request, entity caller) // CLIENT ONLY
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if not(vote_called) { print_to(caller, "^1No vote called."); }
+                       else if not(caller.vote_selection == VOTE_SELECT_NULL || autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
+                       else if(((caller == vote_caller) || caller.vote_master) && autocvar_sv_vote_no_stops_vote) { VoteStop(caller); }
+                       
+                       else // everything went okay, continue changing vote
+                       {
+                               print_to(caller, "^1You rejected the vote.");
+                               caller.vote_selection = VOTE_SELECT_REJECT;
+                               msg_entity = caller;
+                               if(!autocvar_sv_vote_singlecount) { VoteCount(); }
+                       }
+                       
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote no"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void VoteCommand_status(float request, entity caller) // BOTH
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(vote_called)
+                               print_to(caller, strcat("^7Vote for ", vote_called_display, "^7 called by ^7", GetCallerName(vote_caller), "^7."));
+                       else
+                               print_to(caller, "^1No vote called.");
+                               
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote status"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void VoteCommand_stop(float request, entity caller) // BOTH
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if not(vote_called) { print_to(caller, "^1No vote called."); }
+                       else if((caller == vote_caller) || !caller || caller.vote_master) { VoteStop(caller); }
+                       else { print_to(caller, "^1You are not allowed to stop that vote."); }
+                       
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote stop"));
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+
+void VoteCommand_yes(float request, entity caller) // CLIENT ONLY
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if not(vote_called) { print_to(caller, "^1No vote called."); }
+                       else if not(caller.vote_selection == VOTE_SELECT_NULL || autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
+                       
+                       else // everything went okay, continue changing vote
+                       {
+                               print_to(caller, "^1You accepted the vote.");
+                               caller.vote_selection = VOTE_SELECT_ACCEPT;
+                               msg_entity = caller;
+                               if(!autocvar_sv_vote_singlecount) { VoteCount(); }
+                       }
+                       
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote yes"));
+                       print_to(caller, "  No arguments required.");
+                       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 VoteCommand_(float request)
+{
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       
+                       return;
+               }
+                       
+               default:
+               case CMD_REQUEST_USAGE:
+               {
+                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote ");
+                       print_to(caller, "  No arguments required.");
+                       return;
+               }
+       }
+}
+*/
+
+
+// ================================
+//  Macro system for vote commands
+// ================================
+
+// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
+#define VOTE_COMMANDS(request,caller,arguments,command) \
+       VOTE_COMMAND("abstain", VoteCommand_abstain(request, caller), "Abstain your vote in current vote", VC_ASGNMNT_CLIENTONLY) \
+       VOTE_COMMAND("call", VoteCommand_call(request, caller, arguments, command), "Create a new vote for players to decide on", VC_ASGNMNT_BOTH) \
+       VOTE_COMMAND("help", VoteCommand_macro_help(caller, arguments), "Shows this information", VC_ASGNMNT_BOTH) \
+       VOTE_COMMAND("master", VoteCommand_master(request, caller, arguments, command), "Full control over all voting and vote commands", VC_ASGNMNT_CLIENTONLY) \
+       VOTE_COMMAND("no", VoteCommand_no(request, caller), "Select no in current vote", VC_ASGNMNT_CLIENTONLY) \
+       VOTE_COMMAND("status", VoteCommand_status(request, caller), "Prints information about current vote", VC_ASGNMNT_BOTH) \
+       VOTE_COMMAND("stop", VoteCommand_stop(request, caller), "Immediately end a vote", VC_ASGNMNT_BOTH) \
+       VOTE_COMMAND("yes", VoteCommand_yes(request, caller), "Select yes in current vote", VC_ASGNMNT_CLIENTONLY) \
+       /* nothing */
+
+void VoteCommand_macro_help(entity caller, float argc)
+{
+       string command_origin = GetCommandPrefix(caller);
+       
+       if(argc == 2) // help display listing all commands
+       {
+               print("\nVoting commands:\n");
+               #define VOTE_COMMAND(name,function,description,assignment) \
+                       { if(Votecommand_check_assignment(caller, assignment)) { print_to(caller, strcat("  ^2", name, "^7: ", description)); } }
+                       
+               VOTE_COMMANDS(0, caller, 0, "")
+               #undef VOTE_COMMAND
+               
+               print_to(caller, strcat("\nUsage:^3 ", command_origin, " vote COMMAND...^7, where possible commands are listed above.\n"));
+               print_to(caller, strcat("For help about a specific command, type ", command_origin, " vote help COMMAND"));
+               print_to(caller, strcat("\n^7You can call a vote for or execute these commands: ^3", autocvar_sv_vote_commands, "^7 and maybe further ^3arguments^7"));
+       }
+       else // usage for individual command
+       {
+               #define VOTE_COMMAND(name,function,description,assignment) \
+                       { if(Votecommand_check_assignment(caller, assignment)) { if(name == strtolower(argv(2))) { function; return; } } }
+                       
+               VOTE_COMMANDS(CMD_REQUEST_USAGE, caller, argc, "")
+               #undef VOTE_COMMAND
+       }
+       
+       return;
+}
+
+float VoteCommand_macro_command(entity caller, float argc, string vote_command)
+{
+       #define VOTE_COMMAND(name,function,description,assignment) \
+               { if(Votecommand_check_assignment(caller, assignment)) { if(name == strtolower(argv(1))) { function; return TRUE; } } }
+               
+       VOTE_COMMANDS(CMD_REQUEST_COMMAND, caller, argc, vote_command)
+       #undef VOTE_COMMAND
+       
+       return FALSE;
+}
+
+
+// ======================================
+//  Main function handling vote commands
+// ======================================
+
+void VoteCommand(float request, entity caller, float argc, string vote_command) 
+{
+       // Guide for working with argc arguments by example:
+       // argc:   1    - 2      - 3     - 4
+       // argv:   0    - 1      - 2     - 3 
+       // cmd     vote - master - login - password
+       
+       switch(request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if(VoteCommand_macro_command(caller, argc, vote_command))
+                               return;
+               }
+                       
+               default:
+                       print_to(caller, strcat(((argv(1) != "") ? strcat("Unknown vote command \"", argv(1), "\"") : "No command provided"), ". For a list of supported commands, try ", GetCommandPrefix(caller), " vote help.\n"));
+               case CMD_REQUEST_USAGE:
+               {
+                       VoteCommand_macro_help(caller, argc);
+                       return;
+               }
+       }
+}
\ No newline at end of file
diff --git a/qcsrc/server/command/vote.qh b/qcsrc/server/command/vote.qh
new file mode 100644 (file)
index 0000000..748b7ce
--- /dev/null
@@ -0,0 +1,50 @@
+// ================================================
+//  Declarations for the vote system/vote commands
+//  Last updated: December 14th, 2011
+// ================================================
+
+// definitions for command selection between progs
+#define VC_ASGNMNT_BOTH 1
+#define VC_ASGNMNT_CLIENTONLY 2
+#define VC_ASGNMNT_SERVERONLY 3
+
+// vote selection definitions
+#define VOTE_SELECT_ABSTAIN -2
+#define VOTE_SELECT_REJECT -1
+#define VOTE_SELECT_NULL 0
+#define VOTE_SELECT_ACCEPT 1
+
+// different statuses of the current vote
+#define VOTE_NULL 0
+#define VOTE_NORMAL 1
+#define VOTE_MASTER 2
+
+// global vote information declarations
+entity vote_caller; // original caller of the current vote
+float vote_called; // stores status of current vote (See VOTE_*)
+float vote_endtime; // time when the vote is finished
+float vote_accept_count; // total amount of players who accept the vote (counted by VoteCount() function)
+float vote_reject_count; // same as above, but rejected
+float vote_abstain_count; // same as above, but abstained
+float vote_needed_overall; // total amount of players NEEDED for a vote to pass (based on sv_vote_majority_factor)
+.float vote_master; // flag for if the player has vote master privelages 
+.float vote_waittime; // flag for how long the player must wait before they can vote again
+.float vote_selection; // flag for which vote selection the player has made (See VOTE_SELECT_*)
+string vote_called_command; // command sent by client
+string vote_called_display; // visual string of command sent by client
+string vote_parsed_command; // command which is fixed after being parsed
+string vote_parsed_display; // visual string which is fixed after being parsed
+
+// allow functions to be used in other code like g_world.qc and teamplay.qc
+void VoteThink();
+void VoteReset();
+void VoteCommand(float request, entity caller, float argc, string vote_command);
+
+// warmup and nagger stuff
+#define RESTART_COUNTDOWN 10
+entity nagger;
+float readycount; // amount of players who are ready
+float readyrestart_happened; // keeps track of whether a restart has already happened
+float restart_mapalreadyrestarted; // bool, indicates whether reset_map() was already executed
+.float ready; // flag for if a player is ready
+void ReadyCount();
\ No newline at end of file
index 62504ef62f89498bf4c2afeedc12932ac841a6f8..55a32ab3f4372302c1bac16de815b54e23ea7b10 100644 (file)
@@ -270,11 +270,6 @@ float alreadychangedlevel;
 // footstep interval
 .float nextstep;
 
-.float ready;
-#define RESTART_COUNTDOWN 10
-float restart_mapalreadyrestarted; //bool, indicates whether reset_map() was already executed
-entity restartTimer;
-void restartTimer_Think();
 float blockSpectators; //if set, new or existing spectators or observers will be removed unless they become a player within g_maxplayers_spectator_blocktime seconds
 .float spectatortime; //point in time since the client is spectating or observing
 void checkSpectatorBlock();
@@ -286,21 +281,6 @@ void checkSpectatorBlock();
 float nJoinAllowed(float includeMe);
 #define PREVENT_JOIN_TEXT "^1You may not join the game at this time.\n\nThe player limit reached maximum capacity."
 
-//sv_timeout: pauses the game by setting the gamespeed to a really low value (see TIMEOUT_SLOWMO_VALUE)
-#define TIMEOUT_SLOWMO_VALUE 0.0001
-float sys_frametime; // gets initialised in worlspawn, saves the value from autocvar_sys_ticrate
-float remainingTimeoutTime; // contains the time in seconds that the active timeout has left
-float remainingLeadTime; // contains the number of seconds left of the leadtime (before the timeout starts)
-float timeoutStatus; // (values: 0, 1, 2) contains whether a timeout is not active (0), was called but still at leadtime (1) or is active (2)
-.float allowedTimeouts; // contains the number of allowed timeouts for each player
-entity timeoutInitiator; // contains the entity of the player who started the last timeout
-float orig_slowmo; // contains the value of autocvar_slowmo so that, after timeout finished, it isn't set to slowmo 1 necessarily
-.vector lastV_angle; //used when pausing the game in order to force the player to keep his old view angle fixed
-entity timeoutHandler; //responsible for centerprinting the timeout countdowns and playing sounds
-void timeoutHandler_Think();
-void evaluateTimeout();
-void evaluateTimein();
-
 .float spawnshieldtime;
 
 .float lms_nextcheck;
index 84ea0210184792e0f313df1b4e089925f6872359..370f2fb9878041cea1bac0cd540d82d2c450a231 100644 (file)
@@ -382,7 +382,7 @@ void FireGrapplingHook (void)
 
 void GrapplingHookFrame()
 {
-       if(g_grappling_hook && timeoutStatus != 2 && self.weapon != WEP_HOOK)
+       if(g_grappling_hook && timeout_status != TIMEOUT_ACTIVE && self.weapon != WEP_HOOK)
        {
                // offhand hook controls
                if(self.BUTTON_HOOK)
index e4ed89a85a2e7fb347dfbd3c153e6b287008de4a..86cd669d63a48e84996bae4b5249ccaf91f0a5c1 100644 (file)
@@ -95,83 +95,6 @@ void fteqcc_testbugs()
        world.cnt = 0;
 }
 
-/**
- * Takes care of pausing and unpausing the game.
- * Centerprints the information about an upcoming or active timeout to all active
- * players. Also plays reminder sounds.
- */
-void timeoutHandler_Think() {
-       entity plr;
-       if (timeoutStatus == 1) {
-               if (remainingLeadTime > 0) {
-                       //centerprint the information to every player
-                       FOR_EACH_REALCLIENT(plr) {
-                               if(plr.classname == "player") {
-                                       Send_CSQC_Centerprint_Generic(plr, CPID_TIMEOUT_COUNTDOWN, "Timeout begins in %d seconds!", 1, remainingLeadTime);
-                               }
-                       }
-                       remainingLeadTime -= 1;
-                       //think again in 1 second:
-                       self.nextthink = time + 1;
-               }
-               else {
-                       //now pause the game:
-                       timeoutStatus = 2;
-                       //reset all the flood variables
-                       FOR_EACH_CLIENT(plr) {
-                               plr.nickspamcount = plr.nickspamtime = plr.floodcontrol_chat = plr.floodcontrol_chatteam = plr.floodcontrol_chattell = plr.floodcontrol_voice = plr.floodcontrol_voiceteam = 0;
-                       }
-                       cvar_set("slowmo", ftos(TIMEOUT_SLOWMO_VALUE));
-                       //copy .v_angle to .lastV_angle for every player in order to fix their view during pause (see PlayerPreThink)
-                       FOR_EACH_REALPLAYER(plr) {
-                               plr.lastV_angle = plr.v_angle;
-                       }
-                       self.nextthink = time;
-               }
-       }
-       else if (timeoutStatus == 2) {
-               if (remainingTimeoutTime > 0) {
-                       FOR_EACH_REALCLIENT(plr) {
-                               if(plr.classname == "player") {
-                                       Send_CSQC_Centerprint_Generic(plr, CPID_TIMEOUT_COUNTDOWN, "Timeout ends in %d seconds!", 1, remainingTimeoutTime);
-                               }
-                       }
-                       if(remainingTimeoutTime == autocvar_sv_timeout_resumetime) { //play a warning sound when only <sv_timeout_resumetime> seconds are left
-                               Announce("prepareforbattle");
-                       }
-                       remainingTimeoutTime -= 1;
-                       self.nextthink = time + TIMEOUT_SLOWMO_VALUE;
-               }
-               else {
-                       //unpause the game again
-                       remainingTimeoutTime = timeoutStatus = 0;
-                       cvar_set("slowmo", ftos(orig_slowmo));
-                       //and unlock the fixed view again once there is no timeout active anymore
-                       FOR_EACH_REALPLAYER(plr) {
-                               plr.fixangle = FALSE;
-                       }
-                       //get rid of the countdown message
-                       FOR_EACH_REALCLIENT(plr) {
-                               if(plr.classname == "player") {
-                                       Send_CSQC_Centerprint_Generic_Expire(plr, CPID_TIMEOUT_COUNTDOWN);
-                               }
-                       }
-                       remove(self);
-                       return;
-               }
-
-       }
-       else if (timeoutStatus == 0) { //if a player called the resumegame command (which set timeoutStatus to 0 already)
-               FOR_EACH_REALCLIENT(plr) {
-                       if(plr.classname == "player") {
-                               Send_CSQC_Centerprint_Generic_Expire(plr, CPID_TIMEOUT_COUNTDOWN);
-                       }
-               }
-               remove(self);
-               return;
-       }
-}
-
 void GotoFirstMap()
 {
        float n;
@@ -1379,8 +1302,7 @@ void IntermissionThink()
                && ((self.autoscreenshot > 0) && (time > self.autoscreenshot)) )
        {
                self.autoscreenshot = -1;
-               if(clienttype(self) == CLIENTTYPE_REAL)
-                       stuffcmd(self, "\nscreenshot\necho \"^5A screenshot has been taken at request of the server.\"\n");
+               if(clienttype(self) == CLIENTTYPE_REAL) { stuffcmd(self, sprintf("\nautoscreenshot \"%s\" \"%s\"\n", GetMapname(), strftime(FALSE, "%s"))); }
                return;
        }
 
@@ -2048,7 +1970,6 @@ float WinningCondition_Race(float fraglimit)
        return wc;
 }
 
-void ReadyRestart();
 float WinningCondition_QualifyingThenRace(float limit)
 {
        float wc;
@@ -2138,6 +2059,7 @@ CheckRules_World
 Exit deathmatch games upon conditions
 ============
 */
+void ReadyRestart();
 void CheckRules_World()
 {
        float timelimit;
@@ -2334,7 +2256,7 @@ float mapvote_maps_suggested[MAPVOTE_COUNT];
 string mapvote_suggestions[MAPVOTE_COUNT];
 float mapvote_suggestion_ptr;
 float mapvote_voters;
-float mapvote_votes[MAPVOTE_COUNT];
+float mapvote_selections[MAPVOTE_COUNT];
 float mapvote_run;
 float mapvote_detail;
 float mapvote_abstain;
@@ -2491,20 +2413,6 @@ void MapVote_SendPicture(float id)
        WritePicture(MSG_ONE, strcat(mapvote_screenshot_dirs[mapvote_maps_screenshot_dir[id]], "/", mapvote_maps[id]), 3072);
 }
 
-float GameCommand_MapVote(string cmd)
-{
-       if(!intermission_running)
-               return FALSE;
-
-       if(cmd == "mv_getpic")
-       {
-               MapVote_SendPicture(stof(argv(1)));
-               return TRUE;
-       }
-
-       return FALSE;
-}
-
 float MapVote_GetMapMask()
 {
        float mask, i, power;
@@ -2572,7 +2480,7 @@ float MapVote_SendEntity(entity to, float sf)
                if(mapvote_detail)
                        for(i = 0; i < mapvote_count; ++i)
                                if(mapvote_maps[i] != "")
-                                       WriteByte(MSG_ENTITY, mapvote_votes[i]);
+                                       WriteByte(MSG_ENTITY, mapvote_selections[i]);
 
                WriteByte(MSG_ENTITY, to.mapvote);
        }
@@ -2604,16 +2512,16 @@ float MapVote_Finished(float mappos)
        if(autocvar_sv_eventlog)
        {
                result = strcat(":vote:finished:", mapvote_maps[mappos]);
-               result = strcat(result, ":", ftos(mapvote_votes[mappos]), "::");
+               result = strcat(result, ":", ftos(mapvote_selections[mappos]), "::");
                didntvote = mapvote_voters;
                for(i = 0; i < mapvote_count; ++i)
                        if(mapvote_maps[i] != "")
                        {
-                               didntvote -= mapvote_votes[i];
+                               didntvote -= mapvote_selections[i];
                                if(i != mappos)
                                {
                                        result = strcat(result, ":", mapvote_maps[i]);
-                                       result = strcat(result, ":", ftos(mapvote_votes[i]));
+                                       result = strcat(result, ":", ftos(mapvote_selections[i]));
                                }
                        }
                result = strcat(result, ":didn't vote:", ftos(didntvote));
@@ -2638,7 +2546,7 @@ void MapVote_CheckRules_1()
        for(i = 0; i < mapvote_count; ++i) if(mapvote_maps[i] != "")
        {
                //dprint("Map ", ftos(i), ": "); dprint(mapvote_maps[i], "\n");
-               mapvote_votes[i] = 0;
+               mapvote_selections[i] = 0;
        }
 
        mapvote_voters = 0;
@@ -2649,7 +2557,7 @@ void MapVote_CheckRules_1()
                {
                        i = other.mapvote - 1;
                        //dprint("Player ", other.netname, " vote = ", ftos(other.mapvote - 1), "\n");
-                       mapvote_votes[i] = mapvote_votes[i] + 1;
+                       mapvote_selections[i] = mapvote_selections[i] + 1;
                }
        }
 }
@@ -2667,11 +2575,11 @@ float MapVote_CheckRules_2()
 
        mapvote_voters_real = mapvote_voters;
        if(mapvote_abstain)
-               mapvote_voters_real -= mapvote_votes[mapvote_count - 1];
+               mapvote_voters_real -= mapvote_selections[mapvote_count - 1];
 
        RandomSelection_Init();
        for(i = 0; i < mapvote_count_real; ++i) if(mapvote_maps[i] != "")
-               RandomSelection_Add(world, i, string_null, 1, mapvote_votes[i]);
+               RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
        firstPlace = RandomSelection_chosen_float;
        firstPlaceVotes = RandomSelection_best_priority;
        //dprint("First place: ", ftos(firstPlace), "\n");
@@ -2680,7 +2588,7 @@ float MapVote_CheckRules_2()
        RandomSelection_Init();
        for(i = 0; i < mapvote_count_real; ++i) if(mapvote_maps[i] != "")
                if(i != firstPlace)
-                       RandomSelection_Add(world, i, string_null, 1, mapvote_votes[i]);
+                       RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
        secondPlace = RandomSelection_chosen_float;
        secondPlaceVotes = RandomSelection_best_priority;
        //dprint("Second place: ", ftos(secondPlace), "\n");
@@ -2707,12 +2615,12 @@ float MapVote_CheckRules_2()
                        for(i = 0; i < mapvote_count; ++i)
                                if(mapvote_maps[i] != "")
                                {
-                                       didntvote -= mapvote_votes[i];
+                                       didntvote -= mapvote_selections[i];
                                        if(i != firstPlace)
                                                if(i != secondPlace)
                                                {
                                                        result = strcat(result, ":", mapvote_maps[i]);
-                                                       result = strcat(result, ":", ftos(mapvote_votes[i]));
+                                                       result = strcat(result, ":", ftos(mapvote_selections[i]));
                                                        if(i < mapvote_count_real)
                                                        {
                                                                strunzone(mapvote_maps[i]);
diff --git a/qcsrc/server/gamecommand.qc b/qcsrc/server/gamecommand.qc
deleted file mode 100644 (file)
index b4846d2..0000000
+++ /dev/null
@@ -1,1529 +0,0 @@
-string GotoMap(string m);
-void race_deleteTime(string map, float pos);
-
-float FullTraceFraction(vector a, vector mi, vector ma, vector b)
-{
-       vector c;
-       float white, black;
-
-       white = 0.001;
-       black = 0.001;
-
-       c = a;
-
-       float n, m;
-       n = m = 0;
-
-       while(vlen(c - b) > 1)
-       {
-               ++m;
-
-               tracebox(c, mi, ma, b, MOVE_WORLDONLY, world);
-               ++n;
-
-               if(!trace_startsolid)
-               {
-                       black += vlen(trace_endpos - c);
-                       c = trace_endpos;
-               }
-
-               n += tracebox_inverted(c, mi, ma, b, MOVE_WORLDONLY, world);
-
-               white += vlen(trace_endpos - c);
-               c = trace_endpos;
-       }
-
-       if(n > 200)
-               dprint("HOLY SHIT! FullTraceFraction: ", ftos(n), " total traces, ", ftos(m), " iterations\n");
-
-       return white / (black + white);
-}
-
-float RadarMapAtPoint_Trace(float x, float y, float w, float h, float zmin, float zsize, float q)
-{
-       vector a, b, mi, ma;
-
-       mi = '0 0 0';
-       ma = '1 0 0' * w + '0 1 0' * h;
-       a = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
-       b = '1 0 0' * x + '0 1 0' * y + '0 0 1' * (zsize + zmin);
-
-       return FullTraceFraction(a, mi, ma, b);
-}
-float RadarMapAtPoint_LineBlock(float x, float y, float w, float h, float zmin, float zsize, float q)
-{
-       vector o, mi, ma;
-       float i, r;
-       vector dz;
-
-       q = 256 * q - 1;
-       // 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value
-
-       mi = '0 0 0';
-       dz = (zsize / q) * '0 0 1';
-       ma = '1 0 0' * w + '0 1 0' * h + dz;
-       o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
-
-       if(x < world.absmin_x - w)
-               return 0;
-       if(y < world.absmin_y - h)
-               return 0;
-       if(x > world.absmax_x)
-               return 0;
-       if(y > world.absmax_y)
-               return 0;
-
-       r = 0;
-       for(i = 0; i < q; ++i)
-       {
-               vector v1, v2;
-               v1 = v2 = o + dz * i + mi;
-               v1_x += random() * (ma_x - mi_x);
-               v1_y += random() * (ma_y - mi_y);
-               v1_z += random() * (ma_z - mi_z);
-               v2_x += random() * (ma_x - mi_x);
-               v2_y += random() * (ma_y - mi_y);
-               v2_z += random() * (ma_z - mi_z);
-               traceline(v1, v2, MOVE_WORLDONLY, world);
-               if(trace_startsolid || trace_fraction < 1)
-                       ++r;
-       }
-       return r / q;
-}
-float RadarMapAtPoint_Block(float x, float y, float w, float h, float zmin, float zsize, float q)
-{
-       vector o, mi, ma;
-       float i, r;
-       vector dz;
-
-       q = 256 * q - 1;
-       // 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value
-
-       mi = '0 0 0';
-       dz = (zsize / q) * '0 0 1';
-       ma = '1 0 0' * w + '0 1 0' * h + dz;
-       o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
-
-       if(x < world.absmin_x - w)
-               return 0;
-       if(y < world.absmin_y - h)
-               return 0;
-       if(x > world.absmax_x)
-               return 0;
-       if(y > world.absmax_y)
-               return 0;
-
-       r = 0;
-       for(i = 0; i < q; ++i)
-       {
-               tracebox(o + dz * i, mi, ma, o + dz * i, MOVE_WORLDONLY, world);
-               if(trace_startsolid)
-                       ++r;
-       }
-       return r / q;
-}
-float RadarMapAtPoint_Sample(float x, float y, float w, float h, float zmin, float zsize, float q)
-{
-       vector a, b, mi, ma;
-
-       q *= 4; // choose q so it matches the regular algorithm in speed
-
-       q = 256 * q - 1;
-       // 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value
-
-       mi = '0 0 0';
-       ma = '1 0 0' * w + '0 1 0' * h;
-       a = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
-       b = '1 0 0' * w + '0 1 0' * h + '0 0 1' * zsize;
-
-       float c, i;
-       c = 0;
-
-       for(i = 0; i < q; ++i)
-       {
-               vector v;
-               v_x = a_x + random() * b_x;
-               v_y = a_y + random() * b_y;
-               v_z = a_z + random() * b_z;
-               traceline(v, v, MOVE_WORLDONLY, world);
-               if(trace_startsolid)
-                       ++c;
-       }
-
-       return c / q;
-}
-
-// FF is contained twice, to map 256 to FF too
-// removes the need to bound()
-string doublehex = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFFFF";
-
-float RADAR_WIDTH_MAX = 512;
-float RADAR_HEIGHT_MAX = 512;
-float sharpen_buffer[RADAR_WIDTH_MAX * 3];
-
-void sharpen_set(float x, float v)
-{
-       sharpen_buffer[x + 2 * RADAR_WIDTH_MAX] = v;
-}
-
-float sharpen_getpixel(float x, float y)
-{
-       if(x < 0)
-               return 0;
-       if(x >= RADAR_WIDTH_MAX)
-               return 0;
-       if(y < 0)
-               return 0;
-       if(y > 2)
-               return 0;
-       return sharpen_buffer[x + y * RADAR_WIDTH_MAX];
-}
-
-float sharpen_get(float x, float a)
-{
-       float sum;
-       sum = sharpen_getpixel(x, 1);
-       if(a == 0)
-               return sum;
-       sum *= (8 + 1/a);
-       sum -= sharpen_getpixel(x - 1, 0);
-       sum -= sharpen_getpixel(x - 1, 1);
-       sum -= sharpen_getpixel(x - 1, 2);
-       sum -= sharpen_getpixel(x + 1, 0);
-       sum -= sharpen_getpixel(x + 1, 1);
-       sum -= sharpen_getpixel(x + 1, 2);
-       sum -= sharpen_getpixel(x, 0);
-       sum -= sharpen_getpixel(x, 2);
-       return bound(0, sum * a, 1);
-}
-
-void sharpen_shift(float w)
-{
-       float i;
-       for(i = 0; i < w; ++i)
-       {
-               sharpen_buffer[i] = sharpen_buffer[i + RADAR_WIDTH_MAX];
-               sharpen_buffer[i + RADAR_WIDTH_MAX] = sharpen_buffer[i + 2 * RADAR_WIDTH_MAX];
-               sharpen_buffer[i + 2 * RADAR_WIDTH_MAX] = 0;
-       }
-}
-
-void sharpen_init(float w)
-{
-       float i;
-       for(i = 0; i < w; ++i)
-       {
-               sharpen_buffer[i] = 0;
-               sharpen_buffer[i + RADAR_WIDTH_MAX] = 0;
-               sharpen_buffer[i + 2 * RADAR_WIDTH_MAX] = 0;
-       }
-}
-
-entity radarmapper;
-void RadarMap_Next()
-{
-       if(radarmapper.count & 4)
-       {
-               localcmd("quit\n");
-       }
-       else if(radarmapper.count & 2)
-       {
-               localcmd(strcat("defer 1 \"sv_cmd radarmap --flags ", ftos(radarmapper.count), strcat(" --res ", ftos(radarmapper.size_x), " ", ftos(radarmapper.size_y), " --sharpen ", ftos(radarmapper.ltime), " --qual ", ftos(radarmapper.size_z)), "\"\n"));
-               GotoNextMap(0);
-       }
-       remove(radarmapper);
-       radarmapper = world;
-}
-
-// rough map entity
-//   cnt: current line
-//   size: pixel width/height
-//   maxs: cell width/height
-//   frame: counter
-void RadarMap_Think()
-{
-       float i, x, l;
-       string si;
-
-       if(self.frame == 0)
-       {
-               // initialize
-               get_mi_min_max_texcoords(1);
-               self.mins = mi_picmin;
-               self.maxs_x = (mi_picmax_x - mi_picmin_x) / self.size_x;
-               self.maxs_y = (mi_picmax_y - mi_picmin_y) / self.size_y;
-               self.maxs_z = mi_max_z - mi_min_z;
-               print("Picture mins/maxs: ", ftos(self.maxs_x), " and ", ftos(self.maxs_y), " should match\n");
-               self.netname = strzone(strcat("gfx/", mi_shortname, "_radar.xpm"));
-               if(!(self.count & 1))
-               {
-                       self.cnt = fopen(self.netname, FILE_READ);
-                       if(self.cnt < 0)
-                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.tga"), FILE_READ);
-                       if(self.cnt < 0)
-                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.png"), FILE_READ);
-                       if(self.cnt < 0)
-                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.jpg"), FILE_READ);
-                       if(self.cnt < 0)
-                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.tga"), FILE_READ);
-                       if(self.cnt < 0)
-                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.png"), FILE_READ);
-                       if(self.cnt < 0)
-                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.jpg"), FILE_READ);
-                       if(self.cnt >= 0)
-                       {
-                               fclose(self.cnt);
-
-                               print(self.netname, " already exists, aborting (you may want to specify --force)\n");
-                               RadarMap_Next();
-                               return;
-                       }
-               }
-               self.cnt = fopen(self.netname, FILE_WRITE);
-               if(self.cnt < 0)
-               {
-                       print("Error writing ", self.netname, "\n");
-                       remove(self);
-                       radarmapper = world;
-                       return;
-               }
-               print("Writing to ", self.netname, "...\n");
-               fputs(self.cnt, "/* XPM */\n");
-               fputs(self.cnt, "static char *RadarMap[] = {\n");
-               fputs(self.cnt, "/* columns rows colors chars-per-pixel */\n");
-               fputs(self.cnt, strcat("\"", ftos(self.size_x), " ", ftos(self.size_y), " 256 2\",\n"));
-               for(i = 0; i < 256; ++i)
-               {
-                       si = substring(doublehex, i*2, 2);
-                       fputs(self.cnt, strcat("\"", si, " c #", si, si, si, "\",\n"));
-               }
-               self.frame += 1;
-               self.nextthink = time;
-               sharpen_init(self.size_x);
-       }
-       else if(self.frame <= self.size_y)
-       {
-               // fill the sharpen buffer with this line
-               sharpen_shift(self.size_x);
-               i = self.count & 24;
-
-               switch(i)
-               {
-                       case 0:
-                       default:
-                               for(x = 0; x < self.size_x; ++x)
-                               {
-                                       l = RadarMapAtPoint_Block(self.mins_x + x * self.maxs_x, self.mins_y + (self.size_y - self.frame) * self.maxs_y, self.maxs_x, self.maxs_y, self.mins_z, self.maxs_z, self.size_z);
-                                       sharpen_set(x, l);
-                               }
-                               break;
-                       case 8:
-                               for(x = 0; x < self.size_x; ++x)
-                               {
-                                       l = RadarMapAtPoint_Trace(self.mins_x + x * self.maxs_x, self.mins_y + (self.size_y - self.frame) * self.maxs_y, self.maxs_x, self.maxs_y, self.mins_z, self.maxs_z, self.size_z);
-                                       sharpen_set(x, l);
-                               }
-                               break;
-                       case 16:
-                               for(x = 0; x < self.size_x; ++x)
-                               {
-                                       l = RadarMapAtPoint_Sample(self.mins_x + x * self.maxs_x, self.mins_y + (self.size_y - self.frame) * self.maxs_y, self.maxs_x, self.maxs_y, self.mins_z, self.maxs_z, self.size_z);
-                                       sharpen_set(x, l);
-                               }
-                               break;
-                       case 24:
-                               for(x = 0; x < self.size_x; ++x)
-                               {
-                                       l = RadarMapAtPoint_LineBlock(self.mins_x + x * self.maxs_x, self.mins_y + (self.size_y - self.frame) * self.maxs_y, self.maxs_x, self.maxs_y, self.mins_z, self.maxs_z, self.size_z);
-                                       sharpen_set(x, l);
-                               }
-                               break;
-               }
-
-               // do we have enough lines?
-               if(self.frame >= 2)
-               {
-                       // write a pixel line
-                       fputs(self.cnt, "\"");
-                       for(x = 0; x < self.size_x; ++x)
-                       {
-                               l = sharpen_get(x, self.ltime);
-                               fputs(self.cnt, substring(doublehex, 2 * floor(l * 256.0), 2));
-                       }
-                       if(self.frame == self.size_y)
-                               fputs(self.cnt, "\"\n");
-                       else
-                       {
-                               fputs(self.cnt, "\",\n");
-                               print(ftos(self.size_y - self.frame), " lines left\n");
-                       }
-               }
-
-               // is this the last line? then write back the missing line
-               if(self.frame == self.size_y)
-               {
-                       sharpen_shift(self.size_x);
-                       // write a pixel line
-                       fputs(self.cnt, "\"");
-                       for(x = 0; x < self.size_x; ++x)
-                       {
-                               l = sharpen_get(x, self.ltime);
-                               fputs(self.cnt, substring(doublehex, 2 * floor(l * 256.0), 2));
-                       }
-                       if(self.frame == self.size_y)
-                               fputs(self.cnt, "\"\n");
-                       else
-                       {
-                               fputs(self.cnt, "\",\n");
-                               print(ftos(self.size_y - self.frame), " lines left\n");
-                       }
-               }
-
-               self.frame += 1;
-               self.nextthink = time;
-       }
-       else
-       {
-               // close the file
-               fputs(self.cnt, "}\n");
-               fclose(self.cnt);
-               print("Finished. Please edit data/", self.netname, " with an image editing application and place it in the TGA format in the gfx folder.\n");
-               RadarMap_Next();
-       }
-}
-
-void RadarMap(float argc)
-{
-       if(radarmapper)
-               return;
-       float i;
-       radarmapper = spawn();
-       radarmapper.classname = "radarmapper";
-       radarmapper.think = RadarMap_Think;
-       radarmapper.nextthink = time;
-       radarmapper.count = 8; // default to the --trace method, as it is faster now
-       radarmapper.ltime = 1;
-       radarmapper.size_x = 512;
-       radarmapper.size_y = 512;
-       radarmapper.size_z = 1;
-
-       for(i = 1; i < argc; ++i)
-       {
-               if(argv(i) == "--force")
-                       radarmapper.count |= 1;
-               else if(argv(i) == "--loop")
-                       radarmapper.count |= 2;
-               else if(argv(i) == "--quit")
-                       radarmapper.count |= 4;
-               else if(argv(i) == "--block")
-               {
-                       radarmapper.count &~= 24;
-               }
-               else if(argv(i) == "--trace")
-               {
-                       radarmapper.count &~= 24;
-                       radarmapper.count |= 8;
-               }
-               else if(argv(i) == "--sample")
-               {
-                       radarmapper.count &~= 24;
-                       radarmapper.count |= 16;
-               }
-               else if(argv(i) == "--lineblock")
-               {
-                       radarmapper.count |= 24;
-               }
-               else if(argv(i) == "--flags") // for the recursive call
-               {
-                       ++i;
-                       radarmapper.count = stof(argv(i));
-               }
-               else if(argv(i) == "--sharpen") // for the recursive call
-               {
-                       ++i;
-                       radarmapper.ltime = stof(argv(i));
-               }
-               else if(argv(i) == "--res") // resolution
-               {
-                       ++i;
-                       radarmapper.size_x = stof(argv(i));
-                       ++i;
-                       radarmapper.size_y = stof(argv(i));
-               }
-               else if(argv(i) == "--qual") // quality multiplier
-               {
-                       ++i;
-                       radarmapper.size_z = stof(argv(i));
-               }
-               else
-               {
-                       remove(radarmapper);
-                       radarmapper = world;
-                       print("Usage: sv_cmd radarmap [--force] [--loop] [--quit] [--block | --trace | --sample | --lineblock] [--sharpen N] [--res W H] [--qual Q]\n");
-                       print("The quality factor Q is roughly proportional to the time taken.\n");
-                       print("--trace supports no quality factor; its result should look like --block with infinite quality factor.\n");
-                       print("--block \n");
-                       return;
-               }
-       }
-
-       print("Radarmap entity spawned.\n");
-}
-
-void BBox()
-{
-       print("Original size: ", ftos(world.absmin_x), " ", ftos(world.absmin_y), " ", ftos(world.absmin_z));
-       print(" ", ftos(world.absmax_x), " ", ftos(world.absmax_y), " ", ftos(world.absmax_z), "\n");
-       print("Currently set size: ", ftos(world.mins_x), " ", ftos(world.mins_y), " ", ftos(world.mins_z));
-       print(" ", ftos(world.maxs_x), " ", ftos(world.maxs_y), " ", ftos(world.maxs_z), "\n");
-       print("Solid bounding box size:");
-
-       tracebox('1 0 0' * world.absmin_x,
-                '0 1 0' * world.absmin_y + '0 0 1' * world.absmin_z,
-                '0 1 0' * world.absmax_y + '0 0 1' * world.absmax_z,
-                '1 0 0' * world.absmax_x,
-                        MOVE_WORLDONLY,
-                        world);
-       if(trace_startsolid)
-               print(" ", ftos(world.absmin_x));
-       else
-               print(" ", ftos(trace_endpos_x));
-
-       tracebox('0 1 0' * world.absmin_y,
-                '1 0 0' * world.absmin_x + '0 0 1' * world.absmin_z,
-                '1 0 0' * world.absmax_x + '0 0 1' * world.absmax_z,
-                '0 1 0' * world.absmax_y,
-                        MOVE_WORLDONLY,
-                        world);
-       if(trace_startsolid)
-               print(" ", ftos(world.absmin_y));
-       else
-               print(" ", ftos(trace_endpos_y));
-
-       tracebox('0 0 1' * world.absmin_z,
-                '1 0 0' * world.absmin_x + '0 1 0' * world.absmin_y,
-                '1 0 0' * world.absmax_x + '0 1 0' * world.absmax_y,
-                '0 0 1' * world.absmax_z,
-                        MOVE_WORLDONLY,
-                        world);
-       if(trace_startsolid)
-               print(" ", ftos(world.absmin_z));
-       else
-               print(" ", ftos(trace_endpos_z));
-
-       tracebox('1 0 0' * world.absmax_x,
-                '0 1 0' * world.absmin_y + '0 0 1' * world.absmin_z,
-                '0 1 0' * world.absmax_y + '0 0 1' * world.absmax_z,
-                '1 0 0' * world.absmin_x,
-                        MOVE_WORLDONLY,
-                        world);
-       if(trace_startsolid)
-               print(" ", ftos(world.absmax_x));
-       else
-               print(" ", ftos(trace_endpos_x));
-
-       tracebox('0 1 0' * world.absmax_y,
-                '1 0 0' * world.absmin_x + '0 0 1' * world.absmin_z,
-                '1 0 0' * world.absmax_x + '0 0 1' * world.absmax_z,
-                '0 1 0' * world.absmin_y,
-                        MOVE_WORLDONLY,
-                        world);
-       if(trace_startsolid)
-               print(" ", ftos(world.absmax_y));
-       else
-               print(" ", ftos(trace_endpos_y));
-
-       tracebox('0 0 1' * world.absmax_z,
-                '1 0 0' * world.absmin_x + '0 1 0' * world.absmin_y,
-                '1 0 0' * world.absmax_x + '0 1 0' * world.absmax_y,
-                '0 0 1' * world.absmin_z,
-                        MOVE_WORLDONLY,
-                        world);
-       if(trace_startsolid)
-               print(" ", ftos(world.absmax_z));
-       else
-               print(" ", ftos(trace_endpos_z));
-
-       print("\n");
-}
-
-void EffectIndexDump()
-{
-       float d;
-       float fh;
-       string s;
-
-       d = db_create();
-
-       print("begin of effects list\n");
-       db_put(d, "TE_GUNSHOT", "1"); print("effect TE_GUNSHOT is ", ftos(particleeffectnum("TE_GUNSHOT")), "\n");
-       db_put(d, "TE_GUNSHOTQUAD", "1"); print("effect TE_GUNSHOTQUAD is ", ftos(particleeffectnum("TE_GUNSHOTQUAD")), "\n");
-       db_put(d, "TE_SPIKE", "1"); print("effect TE_SPIKE is ", ftos(particleeffectnum("TE_SPIKE")), "\n");
-       db_put(d, "TE_SPIKEQUAD", "1"); print("effect TE_SPIKEQUAD is ", ftos(particleeffectnum("TE_SPIKEQUAD")), "\n");
-       db_put(d, "TE_SUPERSPIKE", "1"); print("effect TE_SUPERSPIKE is ", ftos(particleeffectnum("TE_SUPERSPIKE")), "\n");
-       db_put(d, "TE_SUPERSPIKEQUAD", "1"); print("effect TE_SUPERSPIKEQUAD is ", ftos(particleeffectnum("TE_SUPERSPIKEQUAD")), "\n");
-       db_put(d, "TE_WIZSPIKE", "1"); print("effect TE_WIZSPIKE is ", ftos(particleeffectnum("TE_WIZSPIKE")), "\n");
-       db_put(d, "TE_KNIGHTSPIKE", "1"); print("effect TE_KNIGHTSPIKE is ", ftos(particleeffectnum("TE_KNIGHTSPIKE")), "\n");
-       db_put(d, "TE_EXPLOSION", "1"); print("effect TE_EXPLOSION is ", ftos(particleeffectnum("TE_EXPLOSION")), "\n");
-       db_put(d, "TE_EXPLOSIONQUAD", "1"); print("effect TE_EXPLOSIONQUAD is ", ftos(particleeffectnum("TE_EXPLOSIONQUAD")), "\n");
-       db_put(d, "TE_TAREXPLOSION", "1"); print("effect TE_TAREXPLOSION is ", ftos(particleeffectnum("TE_TAREXPLOSION")), "\n");
-       db_put(d, "TE_TELEPORT", "1"); print("effect TE_TELEPORT is ", ftos(particleeffectnum("TE_TELEPORT")), "\n");
-       db_put(d, "TE_LAVASPLASH", "1"); print("effect TE_LAVASPLASH is ", ftos(particleeffectnum("TE_LAVASPLASH")), "\n");
-       db_put(d, "TE_SMALLFLASH", "1"); print("effect TE_SMALLFLASH is ", ftos(particleeffectnum("TE_SMALLFLASH")), "\n");
-       db_put(d, "TE_FLAMEJET", "1"); print("effect TE_FLAMEJET is ", ftos(particleeffectnum("TE_FLAMEJET")), "\n");
-       db_put(d, "EF_FLAME", "1"); print("effect EF_FLAME is ", ftos(particleeffectnum("EF_FLAME")), "\n");
-       db_put(d, "TE_BLOOD", "1"); print("effect TE_BLOOD is ", ftos(particleeffectnum("TE_BLOOD")), "\n");
-       db_put(d, "TE_SPARK", "1"); print("effect TE_SPARK is ", ftos(particleeffectnum("TE_SPARK")), "\n");
-       db_put(d, "TE_PLASMABURN", "1"); print("effect TE_PLASMABURN is ", ftos(particleeffectnum("TE_PLASMABURN")), "\n");
-       db_put(d, "TE_TEI_G3", "1"); print("effect TE_TEI_G3 is ", ftos(particleeffectnum("TE_TEI_G3")), "\n");
-       db_put(d, "TE_TEI_SMOKE", "1"); print("effect TE_TEI_SMOKE is ", ftos(particleeffectnum("TE_TEI_SMOKE")), "\n");
-       db_put(d, "TE_TEI_BIGEXPLOSION", "1"); print("effect TE_TEI_BIGEXPLOSION is ", ftos(particleeffectnum("TE_TEI_BIGEXPLOSION")), "\n");
-       db_put(d, "TE_TEI_PLASMAHIT", "1"); print("effect TE_TEI_PLASMAHIT is ", ftos(particleeffectnum("TE_TEI_PLASMAHIT")), "\n");
-       db_put(d, "EF_STARDUST", "1"); print("effect EF_STARDUST is ", ftos(particleeffectnum("EF_STARDUST")), "\n");
-       db_put(d, "TR_ROCKET", "1"); print("effect TR_ROCKET is ", ftos(particleeffectnum("TR_ROCKET")), "\n");
-       db_put(d, "TR_GRENADE", "1"); print("effect TR_GRENADE is ", ftos(particleeffectnum("TR_GRENADE")), "\n");
-       db_put(d, "TR_BLOOD", "1"); print("effect TR_BLOOD is ", ftos(particleeffectnum("TR_BLOOD")), "\n");
-       db_put(d, "TR_WIZSPIKE", "1"); print("effect TR_WIZSPIKE is ", ftos(particleeffectnum("TR_WIZSPIKE")), "\n");
-       db_put(d, "TR_SLIGHTBLOOD", "1"); print("effect TR_SLIGHTBLOOD is ", ftos(particleeffectnum("TR_SLIGHTBLOOD")), "\n");
-       db_put(d, "TR_KNIGHTSPIKE", "1"); print("effect TR_KNIGHTSPIKE is ", ftos(particleeffectnum("TR_KNIGHTSPIKE")), "\n");
-       db_put(d, "TR_VORESPIKE", "1"); print("effect TR_VORESPIKE is ", ftos(particleeffectnum("TR_VORESPIKE")), "\n");
-       db_put(d, "TR_NEHAHRASMOKE", "1"); print("effect TR_NEHAHRASMOKE is ", ftos(particleeffectnum("TR_NEHAHRASMOKE")), "\n");
-       db_put(d, "TR_NEXUIZPLASMA", "1"); print("effect TR_NEXUIZPLASMA is ", ftos(particleeffectnum("TR_NEXUIZPLASMA")), "\n");
-       db_put(d, "TR_GLOWTRAIL", "1"); print("effect TR_GLOWTRAIL is ", ftos(particleeffectnum("TR_GLOWTRAIL")), "\n");
-       db_put(d, "TR_SEEKER", "1"); print("effect TR_SEEKER is ", ftos(particleeffectnum("TR_SEEKER")), "\n");
-       db_put(d, "SVC_PARTICLE", "1"); print("effect SVC_PARTICLE is ", ftos(particleeffectnum("SVC_PARTICLE")), "\n");
-
-       fh = fopen("effectinfo.txt", FILE_READ);
-       while((s = fgets(fh)))
-       {
-               tokenize_console(s);
-               if(argv(0) == "effect")
-               {
-                       if(db_get(d, argv(1)) != "1")
-                       {
-                               if(particleeffectnum(argv(1)) >= 0)
-                                       print("effect ", argv(1), " is ", ftos(particleeffectnum(argv(1))), "\n");
-                               db_put(d, argv(1), "1");
-                       }
-               }
-       }
-       print("end of effects list\n");
-
-       db_close(d);
-}
-
-void make_mapinfo_Think()
-{
-       if(MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
-       {
-               print("Done rebuiling mapinfos.\n");
-               MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
-               remove(self);
-       }
-       else
-       {
-               self.think = make_mapinfo_Think;
-               self.nextthink = time;
-       }
-}
-
-void changematchtime(float delta, float mi, float ma)
-{
-       float cur;
-       float new;
-       float lim;
-
-       if(delta == 0)
-               return;
-       if(autocvar_timelimit < 0)
-               return;
-
-       if(mi <= 10)
-               mi = 10; // at least ten sec in the future
-       cur = time - game_starttime;
-       if(cur > 0)
-               mi += cur; // from current time!
-
-       lim = autocvar_timelimit * 60;
-
-       if(delta > 0)
-       {
-               if(lim == 0)
-                       return; // cannot increase any further
-               else if(lim < ma)
-                       new = min(ma, lim + delta);
-               else // already above maximum: FAIL
-                       return;
-       }
-       else
-       {
-               if(lim == 0) // infinite: try reducing to max, if we are allowed to
-                       new = max(mi, ma);
-               else if(lim > mi) // above minimum: decrease
-                       new = max(mi, lim + delta);
-               else // already below minimum: FAIL
-                       return;
-       }
-
-       cvar_set("timelimit", ftos(new / 60));
-}
-
-float g_clientmodel_genericsendentity (entity to, float sf);
-void modelbug_make_svqc();
-void modelbug_make_csqc()
-{
-       Net_LinkEntity(self, TRUE, 0, g_clientmodel_genericsendentity);
-       self.think = modelbug_make_svqc;
-       self.nextthink = time + 1;
-       setorigin(self, self.origin - '0 0 8');
-}
-void modelbug_make_svqc()
-{
-       self.SendEntity = func_null;
-       self.think = modelbug_make_csqc;
-       self.nextthink = time + 1;
-       setorigin(self, self.origin + '0 0 8');
-}
-
-void modelbug()
-{
-       entity e;
-       e = spawn();
-       setorigin(e, nextent(world).origin);
-       precache_model("models/portal.md3");
-       setmodel(e, "models/portal.md3");
-       e.think = modelbug_make_svqc;
-       e.nextthink = time + 1;
-}
-
-void GameCommand(string command)
-{
-       float argc;
-       entity client, e;
-       vector v;
-       float entno, i, n;
-       string s;
-       argc = tokenize_console(command);
-
-       if(argv(0) == "help" || argc == 0)
-       {
-               print("Usage: sv_cmd COMMAND..., where possible commands are:\n");
-               print("  adminmsg clientnumber \"message\" [infobartime]\n");
-               print("  teamstatus\n");
-               print("  printstats\n");
-               print("  make_mapinfo\n");
-               print("  gametype dm|ctf|...\n");
-               print("  savedb filename\n");
-               print("  dumpdb filename\n");
-               print("  loaddb filename\n");
-               print("  allready\n");
-               print("  effectindexdump\n");
-               print("  radarmap [--force] [--quit | --loop] [sharpness]\n");
-               print("  bbox\n");
-               print("  cvar_changes\n");
-               print("  cvar_purechanges\n");
-               print("  find classname\n");
-               print("  extendmatchtime\n");
-               print("  reducematchtime\n");
-               print("  warp [level]\n");
-               GameCommand_Vote("help", world);
-               GameCommand_Ban("help");
-               GameCommand_Generic("help");
-               return;
-       }
-
-       if(GameCommand_Vote(command, world))
-               return;
-
-       if(GameCommand_Ban(command))
-               return;
-
-       if(GameCommand_Generic(command))
-               return;
-
-       if(argv(0) == "printstats")
-       {
-               DumpStats(FALSE);
-               return;
-       }
-
-       if(argv(0) == "make_mapinfo")
-       {
-               e = spawn();
-               e.classname = "make_mapinfo";
-               e.think = make_mapinfo_Think;
-               e.nextthink = time;
-               MapInfo_Enumerate();
-               return;
-       }
-
-       if(argv(0) == "gotomap") if(argc == 2)
-       {
-               print(GotoMap(argv(1)), "\n");
-               return;
-       }
-
-       if(argv(0) == "gametype") if(argc == 2)
-       {
-               float t, tsave;
-               s = argv(1);
-               t = MapInfo_Type_FromString(s);
-               tsave = MapInfo_CurrentGametype();
-               if(t)
-               {
-                       MapInfo_SwitchGameType(t);
-                       MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
-                       if(MapInfo_count > 0)
-                       {
-                               bprint("Game type successfully switched to ", s, "\n");
-                       }
-                       else
-                       {
-                               bprint("Cannot use this game type: no map for it found\n");
-                               MapInfo_SwitchGameType(tsave);
-                               MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
-                       }
-               }
-               else
-                       bprint("Game type switch to ", s, " failed: this type does not exist!\n");
-               return;
-       }
-
-       if(argv(0) == "adminmsg")
-       if(argc >= 3 && argc <= 4)
-       {
-               entno = stof(argv(1));
-
-               if((entno < 0) | (entno > maxclients)) {
-                       print("Player ", argv(1), " doesn't exist\n");
-                       return;
-               }
-
-               n = 0;
-               for(i = (entno ? entno : 1); i <= (entno ? entno : maxclients); ++i)
-               {
-                       client = edict_num(i);
-                       if(client.flags & FL_CLIENT)
-                       {
-                               if(argc == 4)
-                               {
-                                       s = argv(2);
-                                       s = strreplace("\n", "", s);
-                                       s = strreplace("\\", "\\\\", s);
-                                       s = strreplace("$", "$$", s);
-                                       s = strreplace("\"", "\\\"", s);
-                                       stuffcmd(client, sprintf("\ninfobar %f \"%s\"\n", stof(argv(3)), s));
-                               }
-                               else
-                               {
-                                       centerprint(client, strcat("^3", admin_name(), ":\n\n^7", argv(2)));
-                                       sprint(client, strcat("\{1}\{13}^3", admin_name(), "^7: ", argv(2), "\n"));
-                               }
-                               print("Message sent to ", client.netname, "\n");
-                               ++n;
-                       }
-               }
-               if(!n)
-                       print("Client not found\n");
-
-               return;
-       }
-
-       if(argv(0) == "savedb") if(argc == 2)
-       {
-               db_save(ServerProgsDB, argv(1));
-               print("DB saved.\n");
-               return;
-       }
-
-       if(argv(0) == "dumpdb") if(argc == 2)
-       {
-               db_dump(ServerProgsDB, argv(1));
-               print("DB dumped.\n");
-               return;
-       }
-
-       if(argv(0) == "loaddb") if(argc == 2)
-       {
-               db_close(ServerProgsDB);
-               ServerProgsDB = db_load(argv(1));
-               print("DB loaded.\n");
-               return;
-       }
-
-       if (argv(0) == "nospectators")
-       {
-               blockSpectators = 1;
-               entity plr;
-               FOR_EACH_CLIENT(plr) //give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player
-               {
-                       if(plr.classname == "spectator" || plr.classname == "observer")
-                       {
-                               plr.spectatortime = time;
-                               sprint(plr, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));
-                       }
-               }
-               bprint(strcat("^7All spectators will be automatically kicked when not joining the game after ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds!\n"));
-               return;
-       }
-
-       if (argv(0) == "lockteams")
-       {
-               if(teamplay)
-               {
-                       lockteams = 1;
-                       bprint("^1The teams are now locked.\n");
-               }
-               else
-                       bprint("That command can only be used in a team-based gamemode.\n");
-               return;
-       }
-
-       if (argv(0) == "unlockteams")
-       {
-               if(teamplay)
-               {
-                       lockteams = 0;
-                       bprint("^1The teams are now unlocked.\n");
-               }
-               else
-                       bprint("That command can only be used in a team-based gamemode.\n");
-               return;
-       }
-       if(argv(0) == "movetoteam") if(argc == 3 || argc == 4) {
-               //      sv_cmd movetoteam  player_id  team_colour
-               //      sv_cmd movetoteam  player_id  team_colour  type_of_move
-
-               //      type of move
-               //      0 (00) automove centerprint, admin message
-               //      1 (01) automove centerprint, no admin message
-               //      2 (10) no centerprint, admin message
-               //      3 (11) no centerprint, no admin message
-
-               if(!teamplay) {  // death match
-                       print("Currently not playing a team game\n");
-                       return;
-               }
-
-               entno = stof(argv(1));
-
-               // player_id is out of range
-               if((entno < 1) | (entno > maxclients)) {
-                       print("Player ", argv(1), " doesn't exist\n");
-                       return;
-               }
-
-               client = edict_num(entno);
-
-               // player entity is not a client
-               if not(client.flags & FL_CLIENT) {
-                       print("Player ", argv(1), " doesn't exist\n");
-                       return;
-               }
-
-               // find the team to move the player to
-               float team_colour;
-               float save;
-
-               save = client.team_forced;
-               client.team_forced = 0;
-
-               team_colour = ColourToNumber(argv(2));
-
-               if(team_colour == client.team) {  // player already on the team
-                       print("Player ", argv(1), " (", client.netname, ") is already on the ", ColoredTeamName(client.team), "\n");
-                       // keep the forcing undone
-                       return;
-               } else if(team_colour == 0)  // auto team
-                       team_colour = NumberToTeamNumber(FindSmallestTeam(client, FALSE));
-               else
-                       CheckAllowedTeams(client);
-
-               client.team_forced = save;
-
-               switch(team_colour) {
-                       case COLOR_TEAM1:
-                               if(c1 == -1) {
-                                       print("Sorry, there isn't a red team\n");
-                                       return;
-                               }
-                               break;
-
-                       case COLOR_TEAM2:
-                               if(c2 == -1) {
-                                       print("Sorry, there isn't a blue team\n");
-                                       return;
-                               }
-                               break;
-
-                       case COLOR_TEAM3:
-                               if(c3 == -1) {
-                                       print("Sorry, there isn't a yellow team\n");
-                                       return;
-                               }
-                               break;
-
-                       case COLOR_TEAM4:
-                               if(c4 == -1) {
-                                       print("Sorry, there isn't a pink team\n");
-                                       return;
-                               }
-                               break;
-
-                       default:
-                               print("Sorry, team ", argv(2), " doesn't exist\n");
-                               return;
-               }
-               print("Player ", argv(1), " (", client.netname, ") has been moved to the ", ColoredTeamName(team_colour), "\n");
-
-               client.team_forced = 0;
-               MoveToTeam(client, team_colour, 6, stof(argv(3)));
-
-               return;
-       }
-       if (argv(0) == "teamstatus")
-       {
-               Score_NicePrint(world);
-               return;
-       }
-       if (argv(0) == "allready")
-       {
-               ReadyRestart();
-               return;
-       }
-       if (argv(0) == "effectindexdump")
-       {
-               EffectIndexDump();
-               return;
-       }
-       if (argv(0) == "radarmap")
-       {
-               RadarMap(argc);
-               return;
-       }
-       if (argv(0) == "bbox")
-       {
-               BBox();
-               return;
-       }
-       if (argv(0) == "cvar_changes")
-       {
-               print(cvar_changes);
-               return;
-       }
-       if (argv(0) == "cvar_purechanges")
-       {
-               print(cvar_purechanges);
-               return;
-       }
-       if (argv(0) == "find") if(argc == 2)
-       {
-               for(client = world; (client = find(client, classname, argv(1))); )
-                       print(etos(client), "\n");
-               return;
-       }
-       if (argv(0) == "records")
-       {
-               for (i = 0; i < 10; ++i)
-                       print(records_reply[i]);
-               return;
-       }
-       if (argv(0) == "ladder")
-       {
-               print(ladder_reply);
-               return;
-       }
-       if (argv(0) == "rankings")
-       {
-               strunzone(rankings_reply);
-               rankings_reply = strzone(getrankings());
-               print(rankings_reply);
-               return;
-       }
-
-       if(argv(0) == "cointoss")
-       {
-               bprint("^3Throwing coin... Result: ");
-               if (random() > 0.5)
-                       bprint("^1heads ^3!\n");
-               else
-                       bprint("^1tails ^3!\n");
-               return;
-       }
-
-       if(argv(0) == "__FORCE_READY_RESTART")
-       {
-               reset_map(FALSE);
-               return;
-       }
-
-       if(argv(0) == "debug_shotorg")
-       {
-               debug_shotorg = stov(argv(1));
-               debug_shotorg_y = -debug_shotorg_y;
-               return;
-       }
-
-       if(argv(0) == "gettaginfo") if(argc >= 4)
-       {
-               e = spawn();
-               if(argv(1) == "w")
-                       setmodel(e, (nextent(world)).weaponentity.model);
-               else
-               {
-                       precache_model(argv(1));
-                       setmodel(e, argv(1));
-               }
-               e.frame = stof(argv(2));
-               if(substring(argv(3), 0, 1) == "#")
-                       i = stof(substring(argv(3), 1, -1));
-               else
-                       i = gettagindex(e, argv(3));
-               if(i)
-               {
-                       v = gettaginfo(e, i);
-                       print("model ", e.model, " frame ", ftos(e.frame), " tag ", gettaginfo_name);
-                       print(" index ", ftos(i), " parent ", ftos(gettaginfo_parent), "\n");
-                       print(" vector = ", ftos(v_x), " ", ftos(v_y), " ", ftos(v_z), "\n");
-                       print(" offset = ", ftos(gettaginfo_offset_x), " ", ftos(gettaginfo_offset_y), " ", ftos(gettaginfo_offset_z), "\n");
-                       print(" forward = ", ftos(gettaginfo_forward_x), " ", ftos(gettaginfo_forward_y), " ", ftos(gettaginfo_forward_z), "\n");
-                       print(" right = ", ftos(gettaginfo_right_x), " ", ftos(gettaginfo_right_y), " ", ftos(gettaginfo_right_z), "\n");
-                       print(" up = ", ftos(gettaginfo_up_x), " ", ftos(gettaginfo_up_y), " ", ftos(gettaginfo_up_z), "\n");
-                       if(argc >= 6)
-                       {
-                               v_y = -v_y;
-                               localcmd(strcat(argv(4), vtos(v), argv(5), "\n"));
-                       }
-               }
-               else
-                       print("bone not found\n");
-               remove(e);
-               return;
-       }
-
-       if(argv(0) == "time")
-       {
-               print("time = ", ftos(time), "\n");
-               print("frame start = ", ftos(gettime(GETTIME_FRAMESTART)), "\n");
-               print("realtime = ", ftos(gettime(GETTIME_REALTIME)), "\n");
-               print("hires = ", ftos(gettime(GETTIME_HIRES)), "\n");
-               print("uptime = ", ftos(gettime(GETTIME_UPTIME)), "\n");
-               print("localtime = ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y"), "\n");
-               print("gmtime = ", strftime(FALSE, "%a %b %e %H:%M:%S %Z %Y"), "\n");
-               return;
-       }
-
-       if(argv(0) == "tracebug")
-       {
-               print("TEST CASE. If this returns the runaway loop counter error, possibly everything is oaky.\n");
-               for(;;)
-               {
-                       vector org, delta, start, end, p, q, q0, pos;
-                       float safe, unsafe, dq, dqf;
-
-                       org = world.mins;
-                       delta = world.maxs - world.mins;
-
-                       start_x = org_x + random() * delta_x;
-                       start_y = org_y + random() * delta_y;
-                       start_z = org_z + random() * delta_z;
-
-                       end_x = org_x + random() * delta_x;
-                       end_y = org_y + random() * delta_y;
-                       end_z = org_z + random() * delta_z;
-
-                       start = stov(vtos(start));
-                       end = stov(vtos(end));
-
-                       tracebox(start, PL_MIN, PL_MAX, end, MOVE_NOMONSTERS, world);
-                       if(!trace_startsolid)
-                       {
-                               p = trace_endpos;
-                               tracebox(p, PL_MIN, PL_MAX, p, MOVE_NOMONSTERS, world);
-                               if(trace_startsolid || trace_fraction == 1)
-                               {
-                                       rint(42); // do an engine breakpoint on VM_rint so you can get the trace that errnoeously returns startsolid
-                                       tracebox(start, PL_MIN, PL_MAX, end, MOVE_NOMONSTERS, world);
-                                       tracebox(p, PL_MIN, PL_MAX, q, MOVE_NOMONSTERS, world);
-
-                                       if(trace_startsolid)
-                                       {
-                                               // how much do we need to back off?
-                                               safe = 1;
-                                               unsafe = 0;
-                                               for(;;)
-                                               {
-                                                       pos = p * (1 - (safe + unsafe) * 0.5) + start * ((safe + unsafe) * 0.5);
-                                                       tracebox(pos, PL_MIN, PL_MAX, pos, MOVE_NOMONSTERS, world);
-                                                       if(trace_startsolid)
-                                                       {
-                                                               if((safe + unsafe) * 0.5 == unsafe)
-                                                                       break;
-                                                               unsafe = (safe + unsafe) * 0.5;
-                                                       }
-                                                       else
-                                                       {
-                                                               if((safe + unsafe) * 0.5 == safe)
-                                                                       break;
-                                                               safe = (safe + unsafe) * 0.5;
-                                                       }
-                                               }
-
-                                               print("safe distance to back off: ", ftos(safe * vlen(p - start)), "qu\n");
-                                               print("unsafe distance to back off: ", ftos(unsafe * vlen(p - start)), "qu\n");
-
-                                               tracebox(p, PL_MIN + '0.1 0.1 0.1', PL_MAX - '0.1 0.1 0.1', p, MOVE_NOMONSTERS, world);
-                                               if(trace_startsolid)
-                                                       print("trace_endpos much in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
-                                               else
-                                                       print("trace_endpos just in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
-                                               break;
-                                       }
-
-                                       q0 = p;
-                                       dq = 0;
-                                       dqf = 1;
-                                       for(;;)
-                                       {
-                                               q = p + normalize(end - p) * (dq + dqf);
-                                               if(q == q0)
-                                                       break;
-                                               tracebox(p, PL_MIN, PL_MAX, q, MOVE_NOMONSTERS, world);
-                                               if(trace_startsolid)
-                                                       error("THIS ONE cannot happen");
-                                               if(trace_fraction > 0)
-                                                       dq += dqf * trace_fraction;
-                                               dqf *= 0.5;
-                                               q0 = q;
-                                       }
-                                       if(dq > 0)
-                                       {
-                                               print("trace_endpos still before solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
-                                               print("could go ", ftos(dq), " units further to ", vtos(q), "\n");
-                                               break;
-                                       }
-                               }
-                       }
-               }
-       }
-
-       if(argv(0) == "tracebug2")
-       {
-               e = nextent(world);
-               float f;
-               vector vv, dv;
-               tracebox(e.origin + '0 0 32', e.mins, e.maxs, e.origin + '0 0 -1024', MOVE_NORMAL, e);
-               vv = trace_endpos;
-               if(trace_fraction == 1)
-               {
-                       print("not above ground, aborting\n");
-                       return;
-               }
-               f = 0;
-               for(i = 0; i < 100000; ++i)
-               {
-                       dv = randomvec();
-                       if(dv_z > 0)
-                               dv = -1 * dv;
-                       tracebox(vv, e.mins, e.maxs, vv + dv, MOVE_NORMAL, e);
-                       if(trace_startsolid)
-                               print("bug 1\n");
-                       if(trace_fraction == 1)
-                       if(dv_z < f)
-                       {
-                               print("bug 2: ", ftos(dv_x), " ", ftos(dv_y), " ", ftos(dv_z));
-                               print(" (", ftos(asin(dv_z / vlen(dv)) * 180 / M_PI), " degrees)\n");
-                               f = dv_z;
-                       }
-               }
-               print("highest possible dist: ", ftos(f), "\n");
-               return;
-       }
-
-       if(argv(0) == "tracewalk")
-       {
-               e = nextent(world);
-               if(tracewalk(e, stov(argv(1)), e.mins, e.maxs, stov(argv(2)), MOVE_NORMAL))
-                       print("can walk\n");
-               else
-                       print("cannot walk\n");
-               return;
-       }
-
-       if(argv(0) == "onslaught_updatelinks")
-       {
-               onslaught_updatelinks();
-               print("ONS links updated\n");
-               return;
-       }
-
-       if(argv(0) == "bot_cmd")
-       {
-               entity bot;
-
-               if(argv(1) == "help")
-               {
-                       if(argc==2)
-                       {
-                               bot_list_commands();
-                               print("\nsv_cmd bot_cmd reset          #Clear the cmd queues of all bots\n");
-                               print("sv_cmd bot_cmd load <file>    #Load script file\n");
-                               print("\nUse sv_cmd bot_cmd help <command> for more\n\n");
-                               return;
-                       }
-
-                       bot_cmdhelp(argv(2));
-                       return;
-               }
-
-               // Clear all bot queues
-               if(argv(1) == "reset")
-               {
-                       bot_resetqueues();
-                       return;
-               }
-
-               // set bot count
-               if(argv(1) == "setbots")
-               {
-                       if(argc >= 3 && argv(1) == "setbots")
-                       {
-                               cvar_settemp("minplayers", "0");
-                               cvar_settemp("bot_number", argv(2));
-                               bot_fixcount();
-                       }
-               }
-
-               // Load cmds from file
-               if(argv(1) == "load" && argc == 3)
-               {
-                       float fh;
-                       fh = fopen(argv(2), FILE_READ);
-                       if(fh < 0)
-                       {
-                               print("cannot open the file\n");
-                               return;
-                       }
-
-                       i = 0;
-                       while((s = fgets(fh)))
-                       {
-                               argc = tokenize_console(s);
-
-                               if(argc >= 3 && argv(0) == "sv_cmd" && argv(1) == "bot_cmd")
-                               {
-                                       if(argv(2) == "reset")
-                                       {
-                                               bot_resetqueues();
-                                       }
-                                       else if(argv(2) == "setbots")
-                                       {
-                                               cvar_settemp("minplayers", "0");
-                                               cvar_settemp("bot_number", argv(3));
-                                               if(!bot_fixcount())
-                                                       print("Sorry, could not set requested bot count\n");
-                                       }
-                                       else
-                                       {
-                                               // let's start at token 2 so we can skip sv_cmd bot_cmd
-                                               bot = find_bot_by_number(stof(argv(2)));
-                                               if(bot == world)
-                                                       bot = find_bot_by_name(argv(2));
-                                               if(bot)
-                                                       bot_queuecommand(bot, strcat(argv(3), " ", argv(4)));
-                                       }
-                               }
-                               else
-                                       localcmd(strcat(s, "\n"));
-
-                               ++i;
-                       }
-
-                       print(ftos(i), " commands read\n");
-
-                       fclose(fh);
-
-                       return;
-               }
-
-               if(argc < 3)
-               {
-                       print("Usage: sv_cmd bot_cmd <bot name or number> <command> [argument]\n");
-                       print("Examples: bot_cmd <id> cc \"say something\"\n");
-                       print("          bot_cmd <id> presskey jump\n");
-                       print("          .. or sv_cmd bot_cmd help <command> for more\n");
-                       return;
-               }
-
-               bot = find_bot_by_number(stof(argv(1)));
-               if(bot == world)
-                       bot = find_bot_by_name(argv(1));
-
-               if(bot)
-                       bot_queuecommand(bot, strcat(argv(2), " ", argv(3)));
-               else
-                       print(strcat("Error: Unable to find a bot with the name or number '",argv(1),"'\n"));
-
-               return;
-       }
-
-       if(argv(0) == "playerdemo")
-       {
-               if(argv(1) == "read")
-               {
-                       entno = stof(argv(2));
-                       if((entno < 1) | (entno > maxclients)) {
-                               print("Player ", argv(2), " doesn't exist\n");
-                               return;
-                       }
-                       client = edict_num(entno);
-                       if(clienttype(client) != CLIENTTYPE_BOT) {
-                               print("Player ", client.netname, " is not a bot\n");
-                               return;
-                       }
-                       self = client;
-                       playerdemo_open_read(argv(3));
-                       return;
-               }
-               else if(argv(1) == "write")
-               {
-                       entno = stof(argv(2));
-                       if((entno < 1) | (entno > maxclients)) {
-                               print("Player ", argv(2), " doesn't exist\n");
-                               return;
-                       }
-                       client = edict_num(entno);
-                       self = client;
-                       playerdemo_open_write(argv(3));
-                       return;
-               }
-               else if(argv(1) == "auto_read_and_write")
-               {
-                       s = argv(2);
-                       n = stof(argv(3));
-                       cvar_set("bot_number", ftos(n));
-                       localcmd("wait; wait; wait\n");
-                       for(i = 0; i < n; ++i)
-                               localcmd("sv_cmd playerdemo read ", ftos(i+2), " ", s, ftos(i+1), "\n");
-                       localcmd("sv_cmd playerdemo write 1 ", ftos(n+1), "\n");
-                       return;
-               }
-               else if(argv(1) == "auto_read")
-               {
-                       s = argv(2);
-                       n = stof(argv(3));
-                       cvar_set("bot_number", ftos(n));
-                       localcmd("wait; wait; wait\n");
-                       for(i = 0; i < n; ++i)
-                               localcmd("sv_cmd playerdemo read ", ftos(i+2), " ", s, ftos(i+1), "\n");
-                       return;
-               }
-       }
-
-       if(argv(0) == "anticheat")
-       {
-               entno = stof(argv(1));
-               if((entno < 1) | (entno > maxclients)) {
-                       print("Player ", argv(1), " doesn't exist\n");
-                       return;
-               }
-               client = edict_num(entno);
-               if(clienttype(client) != CLIENTTYPE_REAL && clienttype(client) != CLIENTTYPE_BOT) {
-                       print("Player ", client.netname, " is not active\n");
-                       return;
-               }
-               self = client;
-               anticheat_report();
-               return;
-       }
-
-       if(argv(0) == "defer_clear")
-       if(argc == 2)
-       {
-               entno = stof(argv(1));
-
-               // player_id is out of range
-               if((entno < 1) | (entno > maxclients)) {
-                       print("Player ", argv(1), " doesn't exist\n");
-                       return;
-               }
-
-               client = edict_num(entno);
-
-               if not(client.flags & FL_CLIENT) {
-                       print("Player ", argv(1), " doesn't exist\n");
-                       return;
-               }
-
-               if(clienttype(client) == CLIENTTYPE_BOT) {
-                       print("Player ", argv(1), " (", client.netname, ") is a bot\n");
-                       return;
-               }
-
-               stuffcmd(client, "defer clear\n");
-               print("defer clear stuffed to ", argv(1), " (", client.netname, ")\n");
-               return;
-       }
-
-       if(argv(0) == "defer_clear_all")
-       {
-               FOR_EACH_CLIENTSLOT(client)
-                       GameCommand(strcat("defer_clear ", ftos(num_for_edict(client))));       
-
-               return;
-       }
-       if(argv(0) == "delrec")
-       {
-               if(argv(2) != "")
-                       race_deleteTime(argv(2), stof(argv(1)));
-               else
-                       race_deleteTime(GetMapname(), stof(argv(1)));
-
-               return;
-       }
-
-       if(argv(0) == "showtraceline")
-       {
-               vector src, dst;
-               src = stov(argv(1));
-               dst = stov(argv(2));
-               traceline(src, dst, MOVE_NORMAL, world);
-               trailparticles(world, particleeffectnum("TR_NEXUIZPLASMA"), src, trace_endpos);
-               trailparticles(world, particleeffectnum("TR_CRYLINKPLASMA"), trace_endpos, dst);
-               return;
-       }
-
-       if(argv(0) == "extendmatchtime")
-       {
-               changematchtime(autocvar_timelimit_increment* 60, autocvar_timelimit_min*60, autocvar_timelimit_max*60);
-               return;
-       }
-
-       if(argv(0) == "reducematchtime")
-       {
-               changematchtime(autocvar_timelimit_decrement*-60, autocvar_timelimit_min*60, autocvar_timelimit_max*60);
-               return;
-       }
-
-       if(argv(0) == "modelbug")
-       {
-               modelbug();
-               return;
-       }
-
-       if(argv(0) == "warp")
-       {
-               if(autocvar_g_campaign)
-               {
-                       if(argc >= 2)
-                               CampaignLevelWarp(stof(argv(1)));
-                       else
-                               CampaignLevelWarp(-1);
-               }
-               else
-                       print("Not in campaign, can't level warp\n");
-       }
-
-       print("Invalid command. For a list of supported commands, try sv_cmd help.\n");
-}
-
index 66e5a97e5e817670566c84846573debf29d6dbbe..b40a1e3a289ad682f95cfe8a96b35e83d84a9aa3 100644 (file)
@@ -317,17 +317,26 @@ void Ban_LoadBans()
 
 void Ban_View()
 {
-       float i;
+       float i, n;
        string msg;
+       
+       print("^2Listing all existing active bans:\n");
+       
        for(i = 0; i < ban_count; ++i)
        {
                if(time > ban_expire[i])
                        continue;
+                       
+               ++n; // total number of existing bans
+                       
                msg = strcat("#", ftos(i), ": ");
                msg = strcat(msg, ban_ip[i], " is still banned for ");
                msg = strcat(msg, ftos(ban_expire[i] - time), " seconds");
-               print(msg, "\n");
+               
+               print("  ", msg, "\n");
        }
+       
+       print("^2Done listing all active (", ftos(n), ") bans.\n");
 }
 
 float Ban_GetClientIP(entity client)
@@ -574,79 +583,3 @@ void Ban_KickBanClient(entity client, float bantime, float masksize, string reas
        dropclient(client);
         */
 }
-
-float GameCommand_Ban(string command)
-{
-       float argc;
-       float bantime;
-       entity client;
-       float entno;
-       float masksize;
-       string reason;
-       float reasonarg;
-
-       argc = tokenize_console(command);
-       if(argv(0) == "help")
-       {
-               print("  kickban # n m p reason - kickban player n for m seconds, using mask size p (1 to 4)\n");
-               print("  ban ip m reason - ban an IP or range (incomplete IP, like 1.2.3) for m seconds\n");
-               print("  bans - list all existing bans\n");
-               print("  unban n - delete the entry #n from the bans list\n");
-               return TRUE;
-       }
-       if(argv(0) == "kickban")
-       {
-#define INITARG(c) reasonarg = c
-#define GETARG(v,d) if((argc > reasonarg) && ((v = stof(argv(reasonarg))) != 0)) ++reasonarg; else v = d
-#define RESTARG(v) if(argc > reasonarg) v = substring(command, argv_start_index(reasonarg), strlen(command) - argv_start_index(reasonarg)); else v = ""
-               if(argc >= 3)
-               {
-                       entno = stof(argv(2));
-                       if(entno > maxclients || entno < 1)
-                               return TRUE;
-                       client = edict_num(entno);
-
-                       INITARG(3);
-                       GETARG(bantime, autocvar_g_ban_default_bantime);
-                       GETARG(masksize, autocvar_g_ban_default_masksize);
-                       RESTARG(reason);
-
-                       Ban_KickBanClient(client, bantime, masksize, reason);
-                       return TRUE;
-               }
-       }
-       else if(argv(0) == "ban")
-       {
-               if(argc >= 2)
-               {
-                       string ip;
-                       ip = argv(1);
-
-                       INITARG(2);
-                       GETARG(bantime, autocvar_g_ban_default_bantime);
-                       RESTARG(reason);
-
-                       Ban_Insert(ip, bantime, reason, 1);
-                       return TRUE;
-               }
-#undef INITARG
-#undef GETARG
-#undef RESTARG
-       }
-       else if(argv(0) == "bans")
-       {
-               Ban_View();
-               return TRUE;
-       }
-       else if(argv(0) == "unban")
-       {
-               if(argc >= 2)
-               {
-                       float who;
-                       who = stof(argv(1));
-                       Ban_Delete(who);
-                       return TRUE;
-               }
-       }
-       return FALSE;
-}
index 961ca05a809ad1581c3f7d7e6cc5b44a6dfd769b..15939464e00a8579053039af9336e4c814377f3c 100644 (file)
@@ -1,6 +1,6 @@
 void Ban_SaveBans();
 void Ban_LoadBans();
 float Ban_MaybeEnforceBan(entity client);
-float GameCommand_Ban(string command);
+float BanCommand(string command);
 
 void OnlineBanList_URI_Get_Callback(float id, float status, string data);
index 2fa2b6705d9ad66b8a583fd4d0246ed7280a7d7b..afca843b46d31a703ddd6ea94718dba75d5ba2d7 100644 (file)
@@ -2009,14 +2009,6 @@ void URI_Get_Callback(float id, float status, string data)
     }
 }
 
-void print_to(entity e, string s)
-{
-    if (e)
-        sprint(e, strcat(s, "\n"));
-    else
-        print(s, "\n");
-}
-
 string uid2name(string myuid) {
        string s;
        s = db_get(ServerProgsDB, strcat("/uid2name/", myuid));
index a1e9f9e30ef2b9a3ffd716038c2a89880dd80338..98f8197548bb3f1f2ac232493d7b046b412b2dfc 100644 (file)
@@ -17,6 +17,10 @@ sys-post.qh
 ../common/items.qh
 ../common/explosion_equation.qh
 ../common/urllib.qh
+../common/command/markup.qh
+../common/command/rpn.qh
+../common/command/generic.qh
+../common/command/shared_defs.qh
 
 autocvars.qh
 constants.qh
@@ -35,6 +39,13 @@ campaign.qh
 ../common/campaign_common.qh
 ../common/mapinfo.qh
 
+command/common.qh
+command/banning.qh
+command/radarmap.qh
+command/vote.qh
+command/cmd.qh
+command/sv_cmd.qh
+
 accuracy.qh
 csqcprojectile.qh
 ../common/csqcmodel_settings.qh
@@ -60,8 +71,6 @@ race.qh
 
 antilag.qh
 
-vote.qh
-
 playerdemo.qh
 
 // singleplayer stuff
@@ -134,17 +143,20 @@ g_hook.qc
 
 t_swamp.qc
 
-clientcommands.qc
-
-vote.qc
-
 campaign.qc
 ../common/campaign_file.qc
 ../common/campaign_setup.qc
 ../common/urllib.qc
 
-../common/gamecommand.qc
-gamecommand.qc
+../common/command/markup.qc
+../common/command/rpn.qc
+../common/command/generic.qc
+command/common.qc
+command/banning.qc
+command/radarmap.qc
+command/vote.qc
+command/cmd.qc
+command/sv_cmd.qc
 
 assault.qc
 
@@ -152,9 +164,6 @@ ipban.qc
 
 ../common/mapinfo.qc
 
-
-
-
 t_quake3.qc
 t_halflife.qc
 t_quake.qc
index cefba03749ef3569be327dba9186025528d9c728..73c444afec7b8637e0481ecb18ba133d01f471a1 100644 (file)
@@ -196,7 +196,7 @@ void StartFrame (void)
        if(sys_frametime <= 0)
                sys_frametime = 1.0 / 60.0; // somewhat safe fallback
 
-       if (timeoutStatus == 1) // just before the timeout (when timeoutStatus will be 2)
+       if (timeout_status == TIMEOUT_LEADTIME) // just before the timeout (when timeout_status will be TIMEOUT_ACTIVE)
                orig_slowmo = autocvar_slowmo; // slowmo will be restored after the timeout
 
        skill = autocvar_skill;
diff --git a/qcsrc/server/vote.qc b/qcsrc/server/vote.qc
deleted file mode 100644 (file)
index 3043cea..0000000
+++ /dev/null
@@ -1,649 +0,0 @@
-float VoteCheckNasty(string cmd)
-{
-       if(strstrofs(cmd, ";", 0) >= 0)
-               return TRUE;
-       if(strstrofs(cmd, "\n", 0) >= 0)
-               return TRUE;
-       if(strstrofs(cmd, "\r", 0) >= 0)
-               return TRUE;
-       if(strstrofs(cmd, "$", 0) >= 0)
-               return TRUE;
-       return FALSE;
-}
-
-string GetKickVoteVictim_newcommand;
-string GetKickVoteVictim_reason;
-
-entity GetKickVoteVictim(string vote, string cmd, entity caller)
-{
-       float tokens;
-       string ns;
-       entity e;
-       string reason;
-
-       tokens = tokenize_console(vote);
-       ns = "";
-
-       e = GetCommandPlayerSlotTargetFromTokenizedCommand(tokens, 1);
-       if(e)
-       {
-               if(ParseCommandPlayerSlotTarget_firsttoken < tokens)
-                       GetKickVoteVictim_reason = substring(vote, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken));
-               else
-                       GetKickVoteVictim_reason = "";
-
-               reason = "";
-               if(cmd != "vdo" || GetKickVoteVictim_reason == "")
-                       reason = "~"; // by convention, ~ prefixes a "unverified" kickban which will not be networked
-
-               if(substring(GetKickVoteVictim_reason, 0, 1) == "~")
-               {
-                       reason = "~";
-                       GetKickVoteVictim_reason = substring(GetKickVoteVictim_reason, 1, strlen(GetKickVoteVictim_reason) - 1);
-               }
-
-               if(caller)
-                       reason = strcat(reason, "player ", strdecolorize(caller.netname));
-               else
-                       reason = strcat(reason, "console vote");
-               if(GetKickVoteVictim_reason != "")
-                       reason = strcat(reason, ": ", strdecolorize(GetKickVoteVictim_reason));
-
-               if not(cvar_value_issafe(reason))
-                       reason = uri_escape(reason);
-
-               GetKickVoteVictim_newcommand = strcat(argv(0), " # ", ftos(num_for_edict(e)));
-               if(argv(0) == "kickban")
-               {
-                       GetKickVoteVictim_newcommand = strcat(GetKickVoteVictim_newcommand, " ", ftos(autocvar_g_ban_default_bantime), " ", ftos(autocvar_g_ban_default_masksize), " ", reason);
-               }
-               else if(argv(0) == "kick")
-               {
-                       GetKickVoteVictim_newcommand = strcat(GetKickVoteVictim_newcommand, " ", reason);
-               }
-               return e;
-       }
-
-       print_to(caller, strcat("Usage: ", cmd, " ", argv(0), " #playernumber (as in \"status\")\n"));
-       return world;
-}
-
-string RemapVote_display;
-string RemapVote_vote;
-float RemapVote(string vote, string cmd, entity e)
-{
-       float vote_argc;
-       entity victim;
-       vote_argc = tokenize_console(vote);
-
-       if(!VoteAllowed(argv(0), cmd))
-               return FALSE;
-
-       // VoteAllowed tokenizes!
-       vote_argc = tokenize_console(vote);
-
-       // remap chmap to gotomap (forces intermission)
-       if(vote_argc < 2)
-               if(argv(0) == "chmap" || argv(0) == "gotomap" || argv(0) == "kick" || argv(0) == "kickban") // won't work without arguments
-                       return FALSE;
-       if(argv(0) == "chmap")
-       {
-               vote = strcat("gotomap ", substring(vote, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
-               vote_argc = tokenize_console(vote);
-       }
-       if(argv(0) == "gotomap")
-       {
-               if(!(vote = ValidateMap(substring(vote, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), e)))
-                       return FALSE;
-               vote = strcat("gotomap ", vote);
-               vote_argc = tokenize_console(vote); // ValidateMap may have done some stuff to it
-       }
-
-       // make kick and kickban votes a bit nicer (and reject them if formatted badly)
-       if(argv(0) == "kick" || argv(0) == "kickban")
-       {
-               if(!(victim = GetKickVoteVictim(vote, cmd, e)))
-                       return FALSE;
-               RemapVote_vote = GetKickVoteVictim_newcommand;
-               RemapVote_display = strcat("^1", vote, " (^7", victim.netname, "^1): ", GetKickVoteVictim_reason);
-       }
-       else
-       {
-               RemapVote_vote = vote;
-               RemapVote_display = strzone(strcat("^1", vote));
-       }
-
-       return TRUE;
-}
-
-float GameCommand_Vote(string s, entity e) {
-       float playercount;
-       float argc;
-       argc = tokenize_console(s);
-       if(argv(0) == "help") {
-               print_to(e, "  vote COMMANDS ARGUMENTS. See 'vhelp' for more info.");
-               return TRUE;
-       } else if(argv(0) == "vote") {
-               if(argv(1) == "") {
-                       print_to(e, "^1You have to supply a vote command. See 'vhelp' for more info.");
-               } else if(argv(1) == "help") {
-                       VoteHelp(e);
-               } else if(argv(1) == "status") {
-                       if(votecalled) {
-                               print_to(e, strcat("^7Vote for ", votecalledvote_display, "^7 called by ^7", VoteNetname(votecaller), "^7."));
-                       } else {
-                               print_to(e, "^1No vote called.");
-                       }
-               } else if(argv(1) == "call") {
-                       if(!e || autocvar_sv_vote_call) {
-                               if(autocvar_sv_vote_nospectators && e && e.classname != "player") {
-                                       print_to(e, "^1Error: Only players can call a vote."); // TODO invent a cvar name for allowing votes by spectators during warmup anyway
-                               }
-                               else if(timeoutStatus) { //don't allow a vote call during a timeout
-                                       print_to(e, "^1Error: You can not call a vote while a timeout is active.");
-                               }
-                               else if(votecalled) {
-                                       print_to(e, "^1There is already a vote called.");
-                               } else {
-                                       string vote;
-                                       vote = VoteParse(s, argc);
-                                       if(vote == "") {
-                                               print_to(e, "^1Your vote is empty. See 'vhelp' for more info.");
-                                       } else if(e
-                                                       && time < e.vote_next) {
-                                               print_to(e, strcat("^1You have to wait ^2", ftos(ceil(e.vote_next - time)), "^1 seconds before you can again call a vote."));
-                                       } else if(VoteCheckNasty(vote)) {
-                                               print_to(e, "Syntax error in command. See 'vhelp' for more info.");
-                                       } else if(RemapVote(vote, "vcall", e)) {
-                                               votecalledvote = strzone(RemapVote_vote);
-                                               votecalledvote_display = strzone(RemapVote_display);
-                                               votecalled = TRUE;
-                                               votecalledmaster = FALSE;
-                                               votefinished = time + autocvar_sv_vote_timeout;
-                                               votecaller = e; // remember who called the vote
-                                               if(e) {
-                                                       e.vote_vote = 1; // of course you vote yes
-                                                       e.vote_next = time + autocvar_sv_vote_wait;
-                                               }
-                                               bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2 calls a vote for ", votecalledvote_display, "\n");
-                                               if(autocvar_sv_eventlog)
-                                                       GameLogEcho(strcat(":vote:vcall:", ftos(votecaller.playerid), ":", votecalledvote_display));
-                                               Nagger_VoteChanged();
-                                               VoteCount(); // needed if you are the only one
-                                               msg_entity = e;
-
-                                               entity player;
-                                               FOR_EACH_REALCLIENT(player)
-                                               {
-                                                       ++playercount;
-                                               }
-                                               if(playercount > 1) // don't announce a "vote now" sound if player is alone
-                                                       Announce("votecall");
-                                       } else {
-                                               print_to(e, "^1This vote is not ok. See 'vhelp' for more info.");
-                                       }
-                               }
-                       } else {
-                               print_to(e, "^1Vote calling is NOT allowed.");
-                       }
-               } else if(argv(1) == "stop") {
-                       if(!votecalled) {
-                               print_to(e, "^1No vote called.");
-                       } else if(e == votecaller) { // the votecaller can stop a vote
-                               VoteStop(e);
-                       } else if(!e) { // server admin / console can too
-                               VoteStop(e);
-                       } else if(e.vote_master) { // masters can too
-                               VoteStop(e);
-                       } else {
-                               print_to(e, "^1You are not allowed to stop that Vote.");
-                       }
-               } else if(argv(1) == "master") {
-                       if(autocvar_sv_vote_master) {
-                               if(votecalled) {
-                                       print_to(e, "^1There is already a vote called.");
-                               } else {
-                                       votecalled = TRUE;
-                                       votecalledmaster = TRUE;
-                                       votecalledvote = strzone("XXX");
-                                       votecalledvote_display = strzone("^3master");
-                                       votefinished = time + autocvar_sv_vote_timeout;
-                                       votecaller = e; // remember who called the vote
-                                       if(e) {
-                                               e.vote_vote = 1; // of course you vote yes
-                                               e.vote_next = time + autocvar_sv_vote_wait;
-                                       }
-                                       bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2 calls a vote to become ^3master^2.\n");
-                                       if(autocvar_sv_eventlog)
-                                               GameLogEcho(strcat(":vote:vcall:", ftos(votecaller.playerid), ":", votecalledvote_display));
-                                       Nagger_VoteChanged();
-                                       VoteCount(); // needed if you are the only one
-                               }
-                       } else {
-                               print_to(e, "^1Vote to become master is NOT allowed.");
-                       }
-               } else if(argv(1) == "do") {
-                       if(!e || e.vote_master) {
-                               string dovote;
-                               dovote = VoteParse(s, argc);
-                               if(dovote == "") {
-                                       print_to(e, "^1Your command was empty. See 'vhelp' for more info.");
-                               } else if(VoteCheckNasty(dovote)) {
-                                       print_to(e, "Syntax error in command. See 'vhelp' for more info.");
-                               } else if(RemapVote(dovote, "vdo", e)) { // strcat seems to be necessary
-                                       bprint("\{1}^2* ^3", VoteNetname(e), "^2 used their ^3master^2 status to do \"^2", RemapVote_display, "^2\".\n");
-                                       if(autocvar_sv_eventlog)
-                                               GameLogEcho(strcat(":vote:vdo:", ftos(e.playerid), ":", RemapVote_display));
-                                       localcmd(strcat(RemapVote_vote, "\n"));
-                               } else {
-                                       print_to(e, "^1This command is not ok. See 'vhelp' for more info.");
-                               }
-                       } else {
-                               print_to(e, "^1You are NOT a master.  You might need to login or vote to become master first. See 'vhelp' for more info.");
-                       }
-               } else if(argv(1) == "login") {
-                       string masterpwd;
-                       masterpwd = autocvar_sv_vote_master_password;
-                       if(masterpwd != "") {
-                               float granted;
-                               granted = (masterpwd == argv(2));
-                               if (e)
-                                       e.vote_master = granted;
-                               if(granted) {
-                                       print("Accepted master login from ", VoteNetname(e), "\n");
-                                       bprint("\{1}^2* ^3", VoteNetname(e), "^2 logged in as ^3master^2\n");
-                                       if(autocvar_sv_eventlog)
-                                               GameLogEcho(strcat(":vote:vlogin:", ftos(e.playerid)));
-                               }
-                               else
-                                       print("REJECTED master login from ", VoteNetname(e), "\n");
-                       }
-                       else
-                               print_to(e, "^1Login to become master is NOT allowed.");
-               } else if(argv(1) == "yes") {
-                       if(!votecalled) {
-                               print_to(e, "^1No vote called.");
-                       } else if (!e) {
-                               print_to(e, "^1You can't vote from the server console.");
-                       } else if(e.vote_vote == 0
-                                 || autocvar_sv_vote_change) {
-                               msg_entity = e;
-                               print_to(e, "^1You accepted the vote.");
-                               e.vote_vote = 1;
-                               if(!autocvar_sv_vote_singlecount) {
-                                       VoteCount();
-                               }
-                       } else {
-                               print_to(e, "^1You have already voted.");
-                       }
-               } else if(argv(1) == "no") {
-                       if(!votecalled) {
-                               print_to(e, "^1No vote called.");
-                       } else if (!e) {
-                               print_to(e, "^1You can't vote from the server console.");
-                       } else if(e.vote_vote == 0
-                                 || autocvar_sv_vote_change) {
-                               msg_entity = e;
-                               print_to(e, "^1You rejected the vote.");
-                               e.vote_vote = -1;
-                               if(!autocvar_sv_vote_singlecount) {
-                                       VoteCount();
-                               }
-                       } else {
-                               print_to(e, "^1You have already voted.");
-                       }
-               } else if(argv(1) == "abstain" || argv(1) == "dontcare") {
-                       if(!votecalled) {
-                               print_to(e, "^1No vote called.");
-                       } else if (!e) {
-                               print_to(e, "^1You can't vote from the server console.");
-                       } else if(e.vote_vote == 0
-                                 || autocvar_sv_vote_change) {
-                               msg_entity = e;
-                               print_to(e, "^1You abstained from your vote.");
-                               e.vote_vote = -2;
-                               if(!autocvar_sv_vote_singlecount) {
-                                       VoteCount();
-                               }
-                       } else {
-                               print_to(e, "^1You have already voted.");
-                       }
-               } else {
-                       // ignore this?
-                       print_to(e, "^1Unknown vote command.");
-               }
-               return TRUE;
-       }
-       return FALSE;
-}
-
-void VoteHelp(entity e) {
-       string vmasterdis;
-       if(!autocvar_sv_vote_master) {
-               vmasterdis = " ^1(disabled)";
-       }
-
-       string vlogindis;
-       if("" == autocvar_sv_vote_master_password) {
-               vlogindis = " ^1(disabled)";
-       }
-
-       string vcalldis;
-       if(!autocvar_sv_vote_call) {
-               vcalldis = " ^1(disabled)";
-       }
-
-       print_to(e, "^7You can use voting with \"^2cmd vote help^7\" \"^2cmd vote status^7\" \"^2cmd vote call ^3COMMAND ARGUMENTS^7\" \"^2cmd vote stop^7\" \"^2cmd vote master^7\" \"^2cmd vote login^7\" \"^2cmd vote do ^3COMMAND ARGUMENTS^7\" \"^2cmd vote yes^7\" \"^2cmd vote no^7\" \"^2cmd vote abstain^7\" \"^2cmd vote dontcare^7\".");
-       print_to(e, "^7Or if your version is up to date you can use these aliases \"^2vhelp^7\" \"^2vstatus^7\" \"^2vcall ^3COMMAND ARGUMENTS^7\" \"^2vstop^7\" \"^2vmaster^7\" \"^2vlogin^7\" \"^2vdo ^3COMMAND ARGUMENTS^7\" \"^2vyes^7\" \"^2vno^7\" \"^2abstain^7\" \"^2vdontcare^7\".");
-       print_to(e, "^7\"^2help^7\" shows this info.");
-       print_to(e, "^7\"^2status^7\" shows if there is a vote called and who called it.");
-       print_to(e, strcat("^7\"^2call^7\" is used to call a vote. See the list of allowed commands.", vcalldis, "^7"));
-       print_to(e, "^7\"^2stop^7\" can be used by the vote caller or an admin to stop a vote and maybe correct it.");
-       print_to(e, strcat("^7\"^2master^7\" call a vote to become master who can execute commands without a vote", vmasterdis, "^7"));
-       print_to(e, strcat("^7\"^2login^7\" login to become master who can execute commands without a vote.", vlogindis, "^7"));
-       print_to(e, "^7\"^2do^7\" executes a command if you are a master. See the list of allowed commands.");
-       print_to(e, "^7\"^2yes^7\", \"^2no^7\", \"^2abstain^7\" and \"^2dontcare^7\" to make your vote.");
-       print_to(e, "^7If enough of the players vote yes the vote is accepted.");
-       print_to(e, "^7If enough of the players vote no the vote is rejected.");
-       print_to(e, strcat("^7If neither the vote will timeout after ", ftos(autocvar_sv_vote_timeout), "^7 seconds."));
-       print_to(e, "^7You can call a vote for or execute these commands:");
-       print_to(e, strcat("^3", autocvar_sv_vote_commands, "^7 and maybe further ^3arguments^7"));
-}
-
-string VoteNetname(entity e)
-{
-       if(e) {
-               return e.netname;
-       } else {
-               if(autocvar_sv_adminnick != "") {
-                       return autocvar_sv_adminnick;
-               } else {
-                       return autocvar_hostname;
-               }
-       }
-}
-
-string ValidateMap(string m, entity e)
-{
-       m = MapInfo_FixName(m);
-       if(!m)
-       {
-               print_to(e, "This map is not available on this server.");
-               return string_null;
-       }
-       if(!autocvar_sv_vote_override_mostrecent)
-               if(Map_IsRecent(m))
-               {
-                       print_to(e, "This server does not allow for recent maps to be played again. Please be patient for some rounds.");
-                       return string_null;
-               }
-       if(!MapInfo_CheckMap(m))
-       {
-               print_to(e, strcat("^1Invalid mapname, \"^3", m, "^1\" does not support the current game mode."));
-               return string_null;
-       }
-
-       return m;
-}
-
-
-void VoteThink() {
-       if(votefinished > 0) // a vote was called
-       if(time > votefinished) // time is up
-       {
-               VoteCount();
-       }
-}
-
-string VoteParse(string all, float argc) {
-       if(argc < 3)
-               return "";
-       return substring(all, argv_start_index(2), argv_end_index(-1) - argv_start_index(2));
-}
-
-float VoteCommandInList(string votecommand, string list)
-{
-       string l;
-       l = strcat(" ", list, " ");
-       
-       if(strstrofs(l, strcat(" ", votecommand, " "), 0) >= 0)
-               return TRUE;
-       
-       // if gotomap is allowed, chmap is too, and vice versa
-       if(votecommand == "gotomap")
-               if(strstrofs(l, " chmap ", 0) >= 0)
-                       return TRUE;
-       if(votecommand == "chmap")
-               if(strstrofs(l, " gotomap ", 0) >= 0)
-                       return TRUE;
-       
-       return FALSE;
-}
-
-float VoteAllowed(string votecommand, string cmd) {
-       if(VoteCommandInList(votecommand, autocvar_sv_vote_commands))
-               return TRUE;
-
-       if(cmd == "vdo")
-       {
-               if(VoteCommandInList(votecommand, autocvar_sv_vote_master_commands))
-                       return TRUE;
-       }
-       else
-       {
-               if(VoteCommandInList(votecommand, autocvar_sv_vote_only_commands))
-                       return TRUE;
-       }
-
-       return FALSE;
-}
-
-void VoteReset() {
-       entity player;
-
-       FOR_EACH_CLIENT(player)
-       {
-               player.vote_vote = 0;
-       }
-
-       if(votecalled)
-       {
-               strunzone(votecalledvote);
-               strunzone(votecalledvote_display);
-       }
-
-       votecalled = FALSE;
-       votecalledmaster = FALSE;
-       votefinished = 0;
-       votecalledvote = string_null;
-       votecalledvote_display = string_null;
-
-       Nagger_VoteChanged();
-}
-
-void VoteAccept() {
-       bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2's vote for ^1", votecalledvote_display, "^2 was accepted\n");
-       if(votecalledmaster)
-       {
-               if(votecaller) {
-                       votecaller.vote_master = 1;
-               }
-       } else {
-               localcmd(strcat(votecalledvote, "\n"));
-       }
-       if(votecaller) {
-               votecaller.vote_next = 0; // people like your votes,
-                                         // no wait for next vote
-       }
-       VoteReset();
-       Announce("voteaccept");
-}
-
-void VoteReject() {
-       bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2's vote for ", votecalledvote_display, "^2 was rejected\n");
-       VoteReset();
-       Announce("votefail");
-}
-
-void VoteTimeout() {
-       bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2's vote for ", votecalledvote_display, "^2 timed out\n");
-       VoteReset();
-       Announce("votefail");
-}
-
-void VoteStop(entity stopper) {
-       bprint("\{1}^2* ^3", VoteNetname(stopper), "^2 stopped ^3", VoteNetname(votecaller), "^2's vote\n");
-       if(autocvar_sv_eventlog)
-               GameLogEcho(strcat(":vote:vstop:", ftos(stopper.playerid)));
-       if(stopper == votecaller) {
-               // no wait for next vote so you can correct your vote
-               if(votecaller) {
-                       votecaller.vote_next = time + autocvar_sv_vote_stop;
-               }
-       }
-       VoteReset();
-}
-
-void VoteSpam(float notvoters, float mincount, string result)
-{
-       string s;
-       if(mincount >= 0)
-       {
-               s = strcat("\{1}^2* vote results: ^1", ftos(vote_yescount), "^2:^1");
-               s = strcat(s, ftos(vote_nocount), "^2 (^1");
-               s = strcat(s, ftos(mincount), "^2 needed), ^1");
-               s = strcat(s, ftos(vote_abstaincount), "^2 didn't care, ^1");
-               s = strcat(s, ftos(notvoters), "^2 didn't vote\n");
-       }
-       else
-       {
-               s = strcat("\{1}^2* vote results: ^1", ftos(vote_yescount), "^2:^1");
-               s = strcat(s, ftos(vote_nocount), "^2, ^1");
-               s = strcat(s, ftos(vote_abstaincount), "^2 didn't care, ^1");
-               s = strcat(s, ftos(notvoters), "^2 didn't have to vote\n");
-       }
-       bprint(s);
-       if(autocvar_sv_eventlog)
-       {
-               s = strcat(":vote:v", result, ":", ftos(vote_yescount));
-               s = strcat(s, ":", ftos(vote_nocount));
-               s = strcat(s, ":", ftos(vote_abstaincount));
-               s = strcat(s, ":", ftos(notvoters));
-               s = strcat(s, ":", ftos(mincount));
-               GameLogEcho(s);
-       }
-}
-
-void VoteCount() {
-       float playercount;
-       playercount = 0;
-       vote_yescount = 0;
-       vote_nocount = 0;
-       vote_abstaincount = 0;
-       entity player;
-       //same for real players
-       float realplayercount;
-       float realplayeryescount;
-       float realplayernocount;
-       float realplayerabstaincount;
-       realplayercount = realplayernocount = realplayerabstaincount = realplayeryescount = 0;
-
-       Nagger_VoteCountChanged();
-
-       FOR_EACH_REALCLIENT(player)
-       {
-               if(player.vote_vote == -1) {
-                       ++vote_nocount;
-               } else if(player.vote_vote == 1) {
-                       ++vote_yescount;
-               } else if(player.vote_vote == -2) {
-                       ++vote_abstaincount;
-               }
-               ++playercount;
-               //do the same for real players
-               if(player.classname == "player") {
-                       if(player.vote_vote == -1) {
-                               ++realplayernocount;
-                       } else if(player.vote_vote == 1) {
-                               ++realplayeryescount;
-                       } else if(player.vote_vote == -2) {
-                               ++realplayerabstaincount;
-                       }
-                       ++realplayercount;
-               }
-       }
-
-       //in tournament mode, if we have at least one player then don't make the vote dependent on spectators (so specs don't have to press F1)
-       if(autocvar_sv_vote_nospectators)
-       if(realplayercount > 0) {
-               vote_yescount = realplayeryescount;
-               vote_nocount = realplayernocount;
-               vote_abstaincount = realplayerabstaincount;
-               playercount = realplayercount;
-       }
-
-       float votefactor, simplevotefactor;
-       votefactor = bound(0.5, autocvar_sv_vote_majority_factor, 0.999);
-       simplevotefactor = autocvar_sv_vote_simple_majority_factor;
-
-       // FIXME this number is a guess
-       vote_needed_absolute = floor((playercount - vote_abstaincount) * votefactor) + 1;
-       if(simplevotefactor)
-       {
-               simplevotefactor = bound(votefactor, simplevotefactor, 0.999);
-               vote_needed_simple = floor((vote_yescount + vote_nocount) * simplevotefactor) + 1;
-       }
-       else
-               vote_needed_simple = 0;
-
-       if(votecalledmaster
-          && playercount == 1) {
-               // if only one player is on the server becoming vote
-               // master is not allowed.  This could be used for
-               // trolling or worse. 'self' is the user who has
-               // called the vote because this function is called
-               // by SV_ParseClientCommand. Maybe all voting should
-               // be disabled for a single player?
-               print_to(votecaller, "^1You are the only player on this server so you can not become vote master.");
-               if(votecaller) {
-                       votecaller.vote_next = 0;
-               }
-               VoteReset();
-       } else {
-               if(vote_yescount >= vote_needed_absolute)
-               {
-                       VoteSpam(playercount - vote_yescount - vote_nocount - vote_abstaincount, -1, "yes");
-                       VoteAccept();
-               }
-               else if(vote_nocount > playercount - vote_abstaincount - vote_needed_absolute) // that means, vote_yescount cannot reach vote_needed_absolute any more
-               {
-                       VoteSpam(playercount - vote_yescount - vote_nocount - vote_abstaincount, -1, "no");
-                       VoteReject();
-               }
-               else if(time > votefinished)
-               {
-                       if(simplevotefactor)
-                       {
-                               string result;
-                               if(vote_yescount >= vote_needed_simple)
-                                       result = "yes";
-                               else if(vote_yescount + vote_nocount > 0)
-                                       result = "no";
-                               else
-                                       result = "timeout";
-                               VoteSpam(playercount - vote_yescount - vote_nocount - vote_abstaincount, min(vote_needed_absolute, vote_needed_simple), result);
-                               if(result == "yes")
-                                       VoteAccept();
-                               else if(result == "no")
-                                       VoteReject();
-                               else
-                                       VoteTimeout();
-                       }
-                       else
-                       {
-                               VoteSpam(playercount - vote_yescount - vote_nocount - vote_abstaincount, vote_needed_absolute, "timeout");
-                               VoteTimeout();
-                       }
-               }
-       }
-}
diff --git a/qcsrc/server/vote.qh b/qcsrc/server/vote.qh
deleted file mode 100644 (file)
index 75eda98..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-float votecalled;
-string votecalledvote;
-string votecalledvote_display;
-float votecalledmaster;
-entity votecaller;
-float votefinished;
-.float vote_master;
-.float vote_next;
-.float vote_vote;
-float vote_yescount;
-float vote_nocount;
-float vote_abstaincount;
-float vote_needed_absolute;
-float vote_needed_simple;
-
-float VoteCheckNasty(string cmd);
-entity GetKickVoteVictim(string vote, string cmd, entity caller);
-float GameCommand_Vote(string s, entity e);
-void VoteHelp(entity e);
-string VoteNetname(entity e);
-string ValidateMap(string m, entity e);
-void VoteThink();
-string VoteParse(string s, float tokens);
-float VoteAllowed(string vote, string cmd);
-void VoteReset();
-void VoteAccept();
-void VoteReject();
-void VoteTimeout();
-void VoteStop(entity stopper);
-void VoteSpam(float notvoters, float mincount, string result);
-void VoteCount();