Merge remote branch 'origin/master' into samual/updatecommands
authorSamual <samual@xonotic.org>
Sat, 10 Dec 2011 05:10:47 +0000 (00:10 -0500)
committerSamual <samual@xonotic.org>
Sat, 10 Dec 2011 05:10:47 +0000 (00:10 -0500)
Conflicts:
defaultXonotic.cfg

19 files changed:
commands.cfg [new file with mode: 0644]
defaultXonotic.cfg
qcsrc/client/Main.qc
qcsrc/client/gamecommand.qc [new file with mode: 0644]
qcsrc/client/main.qh
qcsrc/client/progs.src
qcsrc/server/assault.qc
qcsrc/server/autocvars.qh
qcsrc/server/bot/scripting.qc
qcsrc/server/cl_weaponsystem.qc
qcsrc/server/clientcommands.qc
qcsrc/server/defs.qh
qcsrc/server/g_world.qc
qcsrc/server/gamecommand.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/progs.src
qcsrc/server/radarmap.qc [new file with mode: 0644]
qcsrc/server/vote.qc
qcsrc/server/vote.qh

diff --git a/commands.cfg b/commands.cfg
new file mode 100644 (file)
index 0000000..d16aaa5
--- /dev/null
@@ -0,0 +1,189 @@
+// =================================================================
+//  Master config for managing various command aliases and settings
+// =================================================================
+
+// This alias allows for common commands to be executed, even on both
+// dedicated servers and normal clients. If dedicated, then it remains
+// as sv_cmd... If a normal client, then it is changed to menu_cmd.
+alias qc_cmd "sv_cmd $*" 
+
+// 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 ""
+
+
+// ========
+//  common
+// ========
+if_client alias teamstatus "cmd teamstatus"
+if_dedicated alias teamstatus "sv_cmd teamstatus"
+
+if_client alias who "cmd who"
+if_dedicated alias who "sv_cmd who"
+alias w who
+
+alias g_hitplots_add "qc_cmd rpn /g_hitplots_individuals g_hitplots_individuals $1 union def"
+alias g_hitplots_remove "qc_cmd rpn /g_hitplots_individuals g_hitplots_individuals $1 difference def"
+
+alias g_maplist_add    "qc_cmd maplist add $*"
+alias g_maplist_remove "qc_cmd maplist remove $*"
+alias g_maplist_putfirst       "qc_cmd maplist remove $* ; qc_cmd maplist add $*"
+alias g_maplist_shufflenow     "qc_cmd maplist shuffle"
+alias g_maplist_cleanup        "qc_cmd maplist cleanup" // removes maps that don't exist from the map list
+
+alias addfav "qc_cmd addtolist net_slist_favorites $*"
+alias addvote "qc_cmd addtolist sv_vote_commands $*"
+
+
+// ========================
+//  engine command aliases
+// ========================
+alias bsp "ls maps/*.bsp"
+alias chmap "changelevel $*"
+alias rec "record demos/$1"
+alias ply "playdemo $1"
+alias tdem "timedemo $1"
+
+
+// ===============================================
+//  menu_cmd (menu command) - menu/gamecommand.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"
+
+
+// =========================================================
+//  cl_cmd (client console command) - client/gamecommand.qc
+// =========================================================
+alias radar "cl_cmd hud_panel_radar_maximized"
+alias scoreboard_columns_set  "cl_cmd scoreboard_columns_set $*"
+alias scoreboard_columns_set  "" // aliased later
+alias scoreboard_columns_help "cl_cmd scoreboard_columns_help $*"
+
+
+// ===========================================================
+//  cmd (client-to-server command) - server/clientcommands.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 5 "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"
+
+alias records "cmd records"
+alias rankings "cmd rankings"
+alias ladder "cmd ladder"
+
+alias ready "cmd ready"
+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 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 sandbox "cmd g_sandbox $*"
+
+
+// =========================================================
+//  sv_cmd (server console command) - server/gamecommand.qc
+// =========================================================
+alias adminmsg "sv_cmd adminmsg $*"
+alias allready "sv_cmd allready"
+
+alias extendmatchtime "sv_cmd extendmatchtime"
+alias reducematchtime "sv_cmd reducematchtime"
+
+alias printstats       "sv_cmd printstats" // print stats on demand
+
+alias gametype "sv_cmd gametype $*"
+
+alias savedb "sv_cmd database save \"$1\""
+alias dumpdb "sv_cmd database dump \"$1\""
+alias loaddb "sv_cmd database load \"$1\""
+
+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"
+
+alias lockteams "sv_cmd lockteams"
+alias unlockteams "sv_cmd unlockteams"
+alias nospectators "sv_cmd nospectators"
+alias gotomap "sv_cmd gotomap \"$1\""
+alias warp "sv_cmd warp $*"
+
+
+// =======================================================
+//  Aliases for settemp subsystem. Warning: Do not touch. 
+//  Usage: settemp variable value, next map resets it.
+// =======================================================
+set settemp_list 0
+set settemp_idx 0
+set _settemp_var UNUSED
+alias settemp "_settemp_var \"_settemp_x$settemp_idx\"; qc_cmd rpn /settemp_idx settemp_idx 1 add def; _settemp \"$1\" \"$2\""
+alias _settemp "settemp_list \"1 $1 $_settemp_var $settemp_list\"; set $_settemp_var \"${$1}\"; $1 \"$2\""
+alias settemp_restore "_settemp_restore_${settemp_list asis}"
+alias _settemp_restore_0 "set settemp_var 0; set settemp_list 0"
+alias _settemp_restore_1 "$1 \"${$2}\"; _settemp_restore_${3- asis}"
+
+
+// ===========================
+//  banning - server/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/vote.qc
+// =========================
+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"
index a8ca77e..6909037 100644 (file)
@@ -29,15 +29,6 @@ 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 ""
-
 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
@@ -53,39 +44,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
 
@@ -580,7 +547,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"
@@ -1038,8 +1004,6 @@ alias togglezoom "${_togglezoom}zoom"
 
 alias reload "impulse 20"
 
-alias sandbox "cmd g_sandbox $*"
-
 // movement
 bind w +forward
 bind a +moveleft
@@ -1156,44 +1120,6 @@ 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
@@ -1235,7 +1161,6 @@ 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"
@@ -1335,21 +1260,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 qc_cmd   "sv_cmd $*" // menu QC will override this to menu_cmd
-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
@@ -1402,23 +1312,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.
-set settemp_list 0
-set settemp_idx 0
-set _settemp_var UNUSED
-alias settemp "_settemp_var \"_settemp_x$settemp_idx\"; qc_cmd rpn /settemp_idx settemp_idx 1 add def; _settemp \"$1\" \"$2\""
-alias _settemp "settemp_list \"1 $1 $_settemp_var $settemp_list\"; set $_settemp_var \"${$1}\"; $1 \"$2\""
-alias settemp_restore "_settemp_restore_${settemp_list asis}"
-alias _settemp_restore_0 "set settemp_var 0; set settemp_list 0"
-alias _settemp_restore_1 "$1 \"${$2}\"; _settemp_restore_${3- asis}"
-
 // 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"
@@ -1531,8 +1427,6 @@ 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
@@ -1645,8 +1539,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"
@@ -1661,18 +1553,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"
@@ -1689,9 +1572,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
@@ -1724,10 +1604,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
@@ -1799,8 +1675,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
@@ -2141,6 +2015,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
@@ -2148,6 +2025,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 2252f6f..0f28e4b 100644 (file)
@@ -3,28 +3,6 @@
 //include "main.qh"
 
 #define DP_CSQC_ENTITY_REMOVE_IS_B0RKED
-
-void cvar_clientsettemp(string cv, string val)
-{
-       entity e;
-       for(e = world; (e = find(e, classname, "saved_cvar_value")); )
-               if(e.netname == cv)
-                       goto saved;
-       e = spawn();
-       e.classname = "saved_cvar_value";
-       e.netname = strzone(cv);
-       e.message = strzone(cvar_string(cv));
-:saved
-       cvar_set(cv, val);
-}
-
-void cvar_clientsettemp_restore()
-{
-       entity e;
-       for(e = world; (e = find(e, classname, "saved_cvar_value")); )
-                       cvar_set(e.netname, e.message);
-}
-
 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);
@@ -43,6 +21,7 @@ float __engine_check;
 
 string forcefog;
 void WaypointSprite_Load();
+void ConsoleCommand_macro_init();
 void CSQC_Init(void)
 {
        prvm_language = cvar_string("prvm_language");
@@ -87,28 +66,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");
 
@@ -176,6 +139,7 @@ void CSQC_Init(void)
 }
 
 // CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc)
+float cvar_clientsettemp_restore();
 void CSQC_Shutdown(void)
 {
 #ifdef USE_FTE
@@ -343,294 +307,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(_("  settemp cvar value\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 == "settemp") {
-               cvar_clientsettemp(argv(1), argv(2));
-       }
-       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/gamecommand.qc b/qcsrc/client/gamecommand.qc
new file mode 100644 (file)
index 0000000..e9dfb49
--- /dev/null
@@ -0,0 +1,509 @@
+// ==============================================
+//  CSQC client commands code, written by Samual
+//  Last updated: November 26th, 2011
+// ==============================================
+
+       /*
+       if(cmd == "mv_download") {
+               Cmd_MapVote_MapDownload(argc);
+       }
+       else if(cmd == "scoreboard_columns_set") {
+               Cmd_HUD_SetFields(argc);
+       }
+       else if(cmd == "scoreboard_columns_help") {
+               Cmd_HUD_Help(argc);
+       }
+       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");
+        }
+    }
+       */
+
+
+#define GC_REQUEST_COMMAND 1
+#define GC_REQUEST_USAGE 2
+
+void Cmd_HUD_SetFields(float);
+void Cmd_HUD_Help(float);
+
+.vector view_ofs;
+entity debug_shotorg;
+
+
+// ============================
+//  Misc. Supporting Functions
+// ============================
+
+float cvar_clientsettemp(string tmp_cvar, string value)
+{
+       entity e;
+       
+       for(e = world; (e = find(e, classname, "saved_cvar_value")); )
+               if(e.netname == tmp_cvar)
+                       goto saved;
+                       
+       // creating a new entity to keep track of this cvar
+       e = spawn();
+       e.classname = "saved_cvar_value";
+       e.netname = strzone(tmp_cvar);
+       e.message = strzone(cvar_string(tmp_cvar));
+       return TRUE;
+       
+       // an entity for this cvar already exists, update the value
+       :saved
+       cvar_set(tmp_cvar, value);
+       return FALSE;
+}
+
+float cvar_clientsettemp_restore()
+{
+       float i;
+       entity e;
+       
+       for(e = world; (e = find(e, classname, "saved_cvar_value")); )
+               { cvar_set(e.netname, e.message); ++i; } 
+               
+       return i;
+}
+
+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 GameCommand_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 GC_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 GC_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 GameCommand_hud(float request, float argc) // TODO: Add aliases in commands.cfg
+{
+       switch(request)
+       {
+               case GC_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 "radar":
+                               {
+                                       if(argv(2))
+                                               hud_panel_radar_maximized = (stof(argv(2)) != 0);
+                                       else
+                                               hud_panel_radar_maximized = !hud_panel_radar_maximized;
+                                       
+                                       return;
+                               }
+                               
+                               case "scoreboard_columns_set":
+                               {
+                                       Cmd_HUD_SetFields(argc); // todo update this function
+                                       
+                                       return;
+                               }
+
+                               case "scoreboard_columns_help":
+                               {
+                                       Cmd_HUD_Help(argc); // todo update this function
+                                       
+                                       return;
+                               }
+                       }
+                       return; 
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2hud^7\n");
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 cl_cmd hud action [configname | radartoggle]\n");
+                       print("  Where 'action' is the command to complete,\n");
+                       print("  'configname' is the name to save to for \"save\" action,\n");
+                       print("  and 'radartoggle' is to control hud_panel_radar_maximized for \"radar\" action.\n");
+                       print("  Full list of commands here: \"configure, save, radar.\"\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_sendcvar(float request, float argc)
+{
+       switch(request)
+       {
+               case GC_REQUEST_COMMAND:
+               {
+                       // W_FixWeaponOrder will trash argv, so save what we need.
+                       string thiscvar = strzone(argv(1));
+                       string s = cvar_string(thiscvar);
+                       
+                       if(thiscvar == "cl_weaponpriority")
+                               s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 1);
+                       else if(substring(thiscvar, 0, 17) == "cl_weaponpriority" && strlen(thiscvar) == 18)
+                               s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 0);
+                               
+                       localcmd("cmd sentcvar ", thiscvar, " \"", s, "\"\n");
+                       strunzone(thiscvar);
+                       
+                       return; 
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 cl_cmd sendcvar <cvar>\n");
+                       print("  Where 'cvar' is the cvar plus arguments to send to the server.\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_settemp(float request, float argc)
+{
+       switch(request)
+       {
+               case GC_REQUEST_COMMAND:
+               {
+                       if((argv(1) == "restore") && (argc == 3))
+                       {
+                               float i = cvar_clientsettemp_restore();
+                               
+                               if(i)
+                                       dprint("Restored ", ftos(i), " temporary cvar settings to their original values.\n");
+                               else
+                                       dprint("Nothing to restore.\n");
+                       }
+                       else
+                       {
+                               if(cvar_clientsettemp(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:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 cl_cmd settemp <cvar> | [restore]\n");
+                       print("  Where 'cvar' is the cvar plus arguments to send to the server,\n");
+                       print("  or 'restore' allows you to restore all of the original temporary cvar values.\n");
+                       return;
+               }
+       }
+}
+
+/* use this when creating a new command, making sure to place it in alphabetical order.
+void GameCommand_(float request)
+{
+       switch(request)
+       {
+               case GC_REQUEST_COMMAND:
+               {
+                       
+                       return; 
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 cl_cmd \n");
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+*/
+
+
+// ==================================
+//  Macro system for client commands
+// ==================================
+
+// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
+#define CLIENT_COMMANDS(request,arguments) \
+       CLIENT_COMMAND("blurtest", GameCommand_blurtest(request), "Feature for testing blur postprocessing") \
+       CLIENT_COMMAND("hud", GameCommand_hud(request, arguments), "Commands regarding/controlling the HUD system") \
+       CLIENT_COMMAND("sendcvar", GameCommand_sendcvar(request, arguments), "Send a cvar to the server (like weaponpriority)") \
+       CLIENT_COMMAND("settemp", GameCommand_settemp(request, arguments), "Temporarily set a value to a cvar which is restored by command or end of each match") \
+       /* nothing */
+       
+void GameCommand_macro_help()
+{
+       #define CLIENT_COMMAND(name,function,description) \
+               { print("  ^2", name, "^7: ", description, "\n"); }
+               
+       CLIENT_COMMANDS(0, 0)
+       #undef CLIENT_COMMAND
+       
+       return;
+}
+
+float GameCommand_macro_command(float argc)
+{
+       #define CLIENT_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(0))) { function; return TRUE; } }
+               
+       CLIENT_COMMANDS(GC_REQUEST_COMMAND, argc)
+       #undef CLIENT_COMMAND
+       
+       return FALSE;
+}
+
+float GameCommand_macro_usage(float argc)
+{
+       #define CLIENT_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(1))) { function; return TRUE; } }
+               
+       CLIENT_COMMANDS(GC_REQUEST_USAGE, argc)
+       #undef CLIENT_COMMAND
+       
+       return FALSE;
+}
+
+
+// =========================================
+//  Main Function Called By Engine (cl_cmd)
+// =========================================
+// If this function exists, client code handles gamecommand instead of the engine code.
+
+void GameCommand(string command)
+{
+       float argc = tokenize_console(command);
+
+       if(strtolower(argv(0)) == "help") 
+       {
+               if(argc == 1) 
+               {
+                       print("\nUsage:^3 cl_cmd COMMAND...^7, where possible commands are:\n");
+                       GameCommand_macro_help();
+                       GameCommand_Generic("help");
+                       print("For help about specific commands, type cl_cmd help COMMAND\n");
+                       return;
+               } 
+               else if(GameCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
+               {
+                       return;
+               }
+       } 
+       else if(GameCommand_Generic(command)) 
+       {
+               return; // handled by common/gamecommand.qc
+       }
+       else if(GameCommand_macro_command(argc)) // 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("Unknown client command", ((command != "") ? strcat(" \"", command, "\"") : ""), ". 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
index bd9ffe6..ec25ab9 100644 (file)
@@ -159,4 +159,4 @@ entity entcs_receiver[255]; // 255 is the engine limit on maxclients
 float hud;
 float view_quality;
 
-void cvar_clientsettemp(string cv, string val);
+float cvar_clientsettemp(string cv, string val);
index 06b3e8b..f87bfb0 100644 (file)
@@ -75,6 +75,7 @@ movetypes.qc
 prandom.qc
 bgmscript.qc
 noise.qc
+gamecommand.qc
 
 ../common/util.qc
 ../common/gamecommand.qc
index 425bbf7..2562dca 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 8f45f53..97ffc89 100644 (file)
@@ -1081,6 +1081,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;
@@ -1146,6 +1148,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;
@@ -1161,6 +1164,7 @@ float autocvar_sv_vote_change;
 string autocvar_sv_vote_commands;
 float autocvar_sv_vote_majority_factor;
 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_nospectators;
index 6b1eba8..bcc4dc8 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 4acb8da..7ce62e5 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;
index 3deddf8..4795b41 100644 (file)
-entity nagger;
-float readycount;
+// =========================================================
+//  Server side networked commands code, reworked by Samual
+//  Last updated: December 6th, 2011
+// =========================================================
 
-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
+#define CC_REQUEST_COMMAND 1
+#define CC_REQUEST_USAGE 2
 
-       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;
+.float cmd_floodtime;
+.float cmd_floodcount;
+.float checkfail;
+.float lms_spectate_warning;
 
-       if(sendflags & 128)
-               nags |= 128;
+string MapVote_Suggest(string m);
+//void MapVote_SendPicture(float id)
 
-       if(!(nags & 4)) // no vote called? send no string
-               nags &~= (64 | 128);
 
-       WriteByte(MSG_ENTITY, nags);
+// ============================
+//  Misc. Supporting Functions
+// ============================
 
-       if(nags & 64)
+float SV_ParseClientCommand_floodcheck()
+{
+       if (timeoutStatus != 2) // if the game is not paused... but wait, doesn't that mean it could be dos'd by pausing it? eh? (old code)
        {
-               WriteByte(MSG_ENTITY, vote_yescount);
-               WriteByte(MSG_ENTITY, vote_nocount);
-               WriteByte(MSG_ENTITY, vote_needed_absolute);
-               WriteChar(MSG_ENTITY, to.vote_vote);
+               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
+}
 
-       if(nags & 128)
-               WriteString(MSG_ENTITY, votecalledvote_display);
 
-       if(nags & 1)
+// =======================
+//  Command Sub-Functions
+// =======================
+
+void ClientCommand_autoswitch(float request, float argc)
+{
+       switch(request)
        {
-               for(i = 1; i <= maxclients; i += 8)
+               case CC_REQUEST_COMMAND:
+               {
+                       self.autoswitch = ("0" != argv(1));
+                       sprint(self, strcat("^1autoswitch is currently turned ", (self.autoswitch ? "on" : "off"), ".\n"));
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
                {
-                       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);
+                       sprint(self, "\nUsage:^3 cmd autoswitch selection\n");
+                       sprint(self, "  Where 'selection' is 1 or 0 for on or off.\n"); 
+                       return;
                }
        }
-
-       return TRUE;
 }
-void Nagger_Init()
+
+void ClientCommand_checkfail(float request, string command) // used only by client side code
 {
-       Net_LinkEntity(nagger = spawn(), FALSE, 0, Nagger_SendEntity);
+       switch(request)
+       {
+               case CC_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:
+               case CC_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 Nagger_VoteChanged()
+
+void ClientCommand_clientversion(float request, float argc) // used only by client side code
 {
-       if(nagger)
-               nagger.SendFlags |= 128;
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       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; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd clientversion version\n");
+                       sprint(self, "  Where 'version' is the game version reported by self.\n");
+                       return;
+               }
+       }
 }
-void Nagger_VoteCountChanged()
+
+void ClientCommand_cvar_changes(float request)
 {
-       if(nagger)
-               nagger.SendFlags |= 64;
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       sprint(self, cvar_changes);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 sv_cmd cvar_changes\n");
+                       sprint(self, "  No arguments required.\n");
+                       //sprint(self, "See also: ^2cvar_purechanges^7\n");
+                       return;
+               }
+       }
 }
-void Nagger_ReadyCounted()
+
+void ClientCommand_cvar_purechanges(float request)
 {
-       if(nagger)
-               nagger.SendFlags |= 1;
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       sprint(self, cvar_purechanges);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 sv_cmd cvar_purechanges\n");
+                       sprint(self, "  No arguments required.\n");
+                       //sprint(self, "See also: ^2cvar_changes^7\n");
+                       return;
+               }
+       }
 }
 
-void ReadyCount();
-string MapVote_Suggest(string m);
+void ClientCommand_getmapvotepic(float request, float argc)
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       if(intermission_running)                                
+                               MapVote_SendPicture(stof(argv(1)));
 
-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; // never fall through to usage
+               }
+                       
+               default:
+               case CC_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;
                }
        }
-       return world;
 }
 
-//float ctf_clientcommand();
-float readyrestart_happened;
-.float lms_spectate_warning;
-void spawnfunc_func_breakable();
+void ClientCommand_info(float request, float argc)
+{      
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       string command;
+                       
+                       command = builtin_cvar_string(strcat("sv_info_", argv(1))); 
+                       if(command)
+                               wordwrap_sprint(command, 1111); // why 1111?
+                       else
+                               sprint(self, "ERROR: unsupported info command\n");
+                               
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd info request\n");
+                       sprint(self, "  Where 'request' is the suffixed string appended onto the request for cvar.\n");
+                       return;
+               }
+       }
+}
 
-.float cmd_floodtime;
-.float cmd_floodcount;
-float cmd_floodcheck()
+void ClientCommand_join(float request)
 {
-       if (timeoutStatus != 2)
+       switch(request)
        {
-               if(time == self.cmd_floodtime)
+               case CC_REQUEST_COMMAND:
                {
-                       self.cmd_floodcount += 1;
-                       if(self.cmd_floodcount > 8)
-                               return TRUE;
+                       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
                }
-               else
+                       
+               default:
+               case CC_REQUEST_USAGE:
                {
-                       self.cmd_floodtime = time;
-                       self.cmd_floodcount = 1;
+                       sprint(self, "\nUsage:^3 cmd join\n");
+                       sprint(self, "  No arguments required.\n");
+                       return;
                }
        }
-       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())
+void ClientCommand_ladder(float request)
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       sprint(self, ladder_reply);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd ladder\n");
+                       sprint(self, "  No arguments required.\n");
                        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)
+void ClientCommand_lsmaps(float request)
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       sprint(self, lsmaps_reply);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd lsmaps\n");
+                       sprint(self, "  No arguments required.\n");
                        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())
+               }
+       }
+}
+
+void ClientCommand_lsnewmaps(float request)
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       sprint(self, lsnewmaps_reply);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd lsnewmaps\n");
+                       sprint(self, "  No arguments required.\n");
                        return;
-               if not(self.flags & FL_CLIENT)
+               }
+       }
+}
+
+void ClientCommand_maplist(float request)
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       sprint(self, maplist_reply);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd maplist\n");
+                       sprint(self, "  No arguments required.\n");
                        return;
-               if(g_arena)
+               }
+       }
+}
+
+void ClientCommand_rankings(float request)
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       sprint(self, rankings_reply);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd rankings\n");
+                       sprint(self, "  No arguments required.\n");
                        return;
-               if(g_lms)
+               }
+       }
+}
+
+void ClientCommand_ready(float request) 
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
                {
-                       if(self.lms_spectate_warning)
+                       if(self.flags & FL_CLIENT)
                        {
-                               // mark player as spectator
-                               PlayerScore_Add(self, SP_LMS_RANK, 666 - PlayerScore_Add(self, SP_LMS_RANK, 0));
+                               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
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd ready\n");
+                       sprint(self, "  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_records(float request) // TODO: Isn't this flooding with the sprint messages? Old code, but perhaps bad?
+{      
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       float i;
+                       
+                       for(i = 0; i < 10; ++i)
+                               sprint(self, records_reply[i]);
+                               
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd records\n");
+                       sprint(self, "  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void ClientCommand_reportcvar(float request, float argc, string command) // TODO: confirm this works
+{      
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       float tokens;
+                       string s;
+                       
+                       if(substring(argv(2), 0, 1) == "$") // undefined cvar: use the default value on the server then
                        {
-                               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;
+                               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; // never fall through to usage
                }
-               if(self.classname == "player" && autocvar_sv_spectate == 1) {
-                       ClientKill_TeamChange(-2); // observe
+                       
+               default:
+               case CC_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;
                }
-               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;
+       }
+}
+
+void ClientCommand_say(float request, float argc, string command)
+{
+       switch(request)
+       {
+               case CC_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
                }
-       } else if(cmd_name == "join") {
-               if not(self.flags & FL_CLIENT)
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd say <message>\n");
+                       sprint(self, "  Where 'message' is the string of text to say.\n");
                        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);
+               }
+       }
+}
+
+void ClientCommand_say_team(float request, float argc, string command)
+{
+       switch(request)
+       {
+               case CC_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 CC_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) // TODO: Update the messages for this command
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       float selection;
+                       
+                       if (self.flags & FL_CLIENT)
+                       {
+                               if(teamplay)
+                                       if not(self.team_forced > 0) 
+                                               if not(lockteams) 
+                                               {
+                                                       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)
+                                                                       ClientKill_TeamChange(selection);
+                                                               else
+                                                                       sprint(self, "^7You already are on that team.\n");
+                                                       }
+                                               }
+                                               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; // never fall through to usage
                }
-       } else if( cmd_name == "selectteam" ) {
-               if not(self.flags & FL_CLIENT)
+
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       //sprint(self, strcat( "selectteam none/red/blue/yellow/pink/auto - \"", argv(1), "\" not recognised\n" ) );
+                       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;
-               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)
-                               ClientKill_TeamChange(COLOR_TEAM1);
-                       else
-                               sprint( self, "^7You already are on that team.\n");
-               } else if( argv(1) == "blue" ) {
-                       if(self.team != COLOR_TEAM2 || self.deadflag != DEAD_NO)
-                               ClientKill_TeamChange(COLOR_TEAM2);
-                       else
-                               sprint( self, "^7You already are on that team.\n");
-               } else if( argv(1) == "yellow" ) {
-                       if(self.team != COLOR_TEAM3 || self.deadflag != DEAD_NO)
-                               ClientKill_TeamChange(COLOR_TEAM3);
-                       else
-                               sprint( self, "^7You already are on that team.\n");
-               } else if( argv(1) == "pink" ) {
-                       if(self.team != COLOR_TEAM4 || self.deadflag != DEAD_NO)
-                               ClientKill_TeamChange(COLOR_TEAM4);
-                       else
-                               sprint( self, "^7You already are on that team.\n");
-               } 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)
+               }
+       }
+}
+
+void ClientCommand_sentcvar(float request, float argc, string command)
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       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; // never fall through to usage
+               }
+                       
+               default:
+               case CC_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;
+               }
+       }
+}
 
-               if((inWarmupStage)
-                  || autocvar_sv_ready_restart || g_race_qualifying == 2)
+void ClientCommand_spectate(float request)
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
                {
-                       if(!readyrestart_happened || autocvar_sv_ready_restart_repeatable)
+                       if(self.flags & FL_CLIENT)
                        {
-                               if (self.ready) // toggle
+                               if(g_arena) { return; } 
+                               if(g_lms)
                                {
-                                       self.ready = FALSE;
-                                       bprint(self.netname, "^2 is ^1NOT^2 ready\n");
+                                       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;
+                                       }
                                }
-                               else
+                               
+                               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"))
                                {
-                                       self.ready = TRUE;
-                                       bprint(self.netname, "^2 is ready\n");
+                                       sprint(self, "WARNING: you will spectate in the next round.\n");
+                                       self.caplayer = 0;
                                }
-
-                               // cannot reset the game while a timeout is active!
-                               if(!timeoutStatus)
-                                       ReadyCount();
-                       } else {
-                               sprint(self, "^1Game has already been restarted\n");
                        }
+                       return; // never fall through to usage
                }
-       } 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 == "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);
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd spectate\n");
+                       sprint(self, "  No arguments required.\n");
+                       return;
                }
-               else
+       }
+}
+
+void ClientCommand_suggestmap(float request, float argc)
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
                {
-                       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");
+                       sprint(self, strcat(MapVote_Suggest(argv(1)), "\n"));
+                       return; // never fall through to usage
                }
-               //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)
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd suggestmap map\n");
+                       sprint(self, "  Where 'map' is the name of the map to suggest.\n");
                        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");
+       }
+}
+
+void ClientCommand_teamstatus(float request)
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       Score_NicePrint(self);
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd teamstatus\n");
+                       sprint(self, "  No arguments required.\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?
+void ClientCommand_tell(float request, float argc, string command)
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
                {
-                       if(self.nickspamtime == 0 || time > self.nickspamtime + autocvar_g_nick_flood_timeout)
-                               // good, no serious flood
-                               self.nickspamcount = 1;
+                       entity e = GetCommandPlayerSlotTargetFromTokenizedCommand(argc, 1);
+                       
+                       if(e && argc > ParseCommandPlayerSlotTarget_firsttoken)
+                       {
+                               Say(self, FALSE, e, substring(command, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken)), TRUE);
+                       }
                        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;
+                       {
+                               if(argc > ParseCommandPlayerSlotTarget_firsttoken)
+                                       trigger_magicear_processmessage_forallears(self, -1, world, substring(command, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken)));
+                       }
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd tell playerid <message>\n");
+                       sprint(self, "  Where 'playerid' is the entity number of the player to send the 'message' to.\n");
+                       return;
                }
-
-               clientcommand(self,s);
        }
 }
 
-void ReadyRestartForce()
+void ClientCommand_timein(float request)
 {
-       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));
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       if(self.flags & FL_CLIENT)
+                       {
+                               if(autocvar_sv_timeout)
+                               {
+                                       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");
+                                       }
+                               }
+                       }
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd timein\n");
+                       sprint(self, "  No arguments required.\n");
+                       return;
+               }
        }
+}
 
-       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
+void ClientCommand_timeout(float request) // DEAR GOD THIS COMMAND IS TERRIBLE.
+{
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       if(self.flags & FL_CLIENT)
+                       {
+                               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
+                                               {
+                                                       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;
 
-       //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
+                                                                       float lastPossibleTimeout;
+                                                                       lastPossibleTimeout = (myTl*60) - autocvar_sv_timeout_leadtime - 1;
 
-       if(autocvar_teamplay_lockonrestart && teamplay) {
-               lockteams = 1;
-               bprint("^1The teams are now locked.\n");
-       }
+                                                                       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
 
-       //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;
+                                                       //inform all connected clients about the timeout call
+                                                       Announce("timeoutcalled");
+                                               }
+                                       }
+                                       else
+                                               sprint(self, "^7Error: only players can call a timeout!\n");
+                               }
+                       }
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd timeout\n");
+                       sprint(self, "  No arguments required.\n");
+                       return;
+               }
        }
+}
 
-       //after a restart every players number of allowed timeouts gets reset, too
-       if(autocvar_sv_timeout)
+void ClientCommand_voice(float request, float argc, string command)
+{
+       switch(request)
        {
-               FOR_EACH_REALPLAYER(e)
-                       e.allowedTimeouts = autocvar_sv_timeout_number;
+               case CC_REQUEST_COMMAND:
+               {
+                       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; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd voice\n");
+                       sprint(self, "  FIXME ARGUMENTS UNKNOWN.\n");
+                       return;
+               }
        }
-
-       //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()
+string strlimitedlen(string input, float strip_colors, float limit)
 {
-       // no arena, assault support yet...
-       if(g_arena | g_assault | gameover | intermission_running | race_completing)
-               localcmd("restart\n");
+       if(strlen((strip_colors ? strdecolorize(input) : input)) <= limit)
+               return input;
        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();
+               return strcat(substring(input, 0, (strlen(input) - 3)), "...");
 }
 
-/**
- * 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()
+void ClientCommand_who(float request)
 {
-       entity e;
-       float r, p;
-
-       r = p = 0;
+       switch(request)
+       {
+               case CC_REQUEST_COMMAND:
+               {
+                       float total_listed_players, tmp_hours, tmp_minutes, tmp_seconds;
+                       entity tmp_player;
+                       string tmp_player_name;
+                       
+                       sprint(self, strcat("List of client information", (autocvar_sv_status_privacy ? " (some data is hidden for privacy)" : string_null), ":\n"));
+                       sprint(self, sprintf(" %-4s %-20s %-5s %-3s %-9s %-16s %s\n", "ent", "nickname", "ping", "pl", "time", "ip", "crypto_id"));
+                       
+                       FOR_EACH_CLIENT(tmp_player)
+                       {
+                               tmp_player_name = strlimitedlen(tmp_player.netname, TRUE, 20);
+                               
+                               tmp_hours = tmp_minutes = tmp_seconds = 0;
+                               
+                               tmp_seconds = (time - tmp_player.jointime);
+                               tmp_minutes = (tmp_seconds / 60);
+                               
+                               if(tmp_minutes)
+                               {
+                                       tmp_seconds -= (tmp_minutes * 60);
+                                       tmp_hours = (tmp_minutes / 60);
+                                       
+                                       if(tmp_hours) { tmp_minutes -= (tmp_hours * 60); }
+                               }
+                               
+                               sprint(self, sprintf(" %-4s %-20s %-5d %-3d %-9s %-16s %s\n", 
+                                       strcat("#", ftos(num_for_edict(tmp_player))), 
+                                       strcat(tmp_player_name, sprintf("%*s", (20 - strlen(strdecolorize(tmp_player_name))), "")),
+                                       tmp_player.ping, tmp_player.ping_packetloss, 
+                                       sprintf("%02d:%02d:%02d", tmp_hours, tmp_minutes, tmp_seconds),
+                                       (autocvar_sv_status_privacy ? "hidden" : tmp_player.netaddress),
+                                       (autocvar_sv_status_privacy ? "hidden" : tmp_player.crypto_idfp)));
+                                       
+                               ++total_listed_players;
+                       }
+                       
+                       sprint(self, strcat("Finished listing ", ftos(total_listed_players), " client(s). \n"));
+                       
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd who\n");
+                       sprint(self, "  No arguments required.\n");
+                       return;
+               }
+       }
+}
 
-       FOR_EACH_REALPLAYER(e)
+/* use this when creating a new command, making sure to place it in alphabetical order.
+void ClientCommand_(float request)
+{
+       switch(request)
        {
-               p += 1;
-               if(e.ready)
-                       r += 1;
+               case CC_REQUEST_COMMAND:
+               {
+                       
+                       return; // never fall through to usage
+               }
+                       
+               default:
+               case CC_REQUEST_USAGE:
+               {
+                       sprint(self, "\nUsage:^3 cmd \n");
+                       sprint(self, "  No arguments required.\n");
+                       return;
+               }
        }
+}
+*/
 
-       readycount = r;
 
-       Nagger_ReadyCounted();
+// =====================================
+//  Macro system for networked commands
+// =====================================
 
-       if(r) // at least one is ready
-       if(r == p) // and, everyone is ready
-               ReadyRestart();
+// 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("cvar_changes", ClientCommand_cvar_changes(request), "Prints a list of all changed server cvars") \
+       CLIENT_COMMAND("cvar_purechanges", ClientCommand_cvar_purechanges(request), "Prints a list of all changed gameplay cvars") \
+       CLIENT_COMMAND("getmapvotepic", ClientCommand_getmapvotepic(request, arguments), "Retrieve mapshot picture from the server") \
+       CLIENT_COMMAND("info", ClientCommand_info(request, arguments), "Request for unique server information set up by admin") \
+       CLIENT_COMMAND("join", ClientCommand_join(request), "Become a player in the game") \
+       CLIENT_COMMAND("ladder", ClientCommand_ladder(request), "Get information about top players if supported") \
+       CLIENT_COMMAND("lsmaps", ClientCommand_lsmaps(request), "List maps which can be used with the current game mode") \
+       CLIENT_COMMAND("lsnewmaps", ClientCommand_lsnewmaps(request), "List maps which TODO") \
+       CLIENT_COMMAND("maplist", ClientCommand_maplist(request), "Full server maplist reply") \
+       CLIENT_COMMAND("rankings", ClientCommand_rankings(request), "Print information about rankings") \
+       CLIENT_COMMAND("ready", ClientCommand_ready(request), "Qualify as ready to end warmup stage (or restart server if allowed)") \
+       CLIENT_COMMAND("records", ClientCommand_records(request), "List top 10 records for the current map") \
+       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("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("teamstatus", ClientCommand_teamstatus(request), "Print detailed score information for all players") \
+       CLIENT_COMMAND("tell", ClientCommand_tell(request, arguments, command), "Send a message directly to a player") \
+       CLIENT_COMMAND("timein", ClientCommand_timein(request), "Resume the game from being paused with a timeout") \
+       CLIENT_COMMAND("timeout", ClientCommand_timeout(request), "Call a timeout which pauses the game for certain amount of time unless unpaused") \
+       CLIENT_COMMAND("voice", ClientCommand_voice(request, arguments, command), "Send voice message via sound") \
+       CLIENT_COMMAND("vote", VoteCommand(request, self, arguments, command), "Request an action to be voted upon by players") \
+       CLIENT_COMMAND("who", ClientCommand_who(request), "Display detailed client information about all players") \
+       /* nothing */
+       
+void ClientCommand_macro_help()
+{
+       #define CLIENT_COMMAND(name,function,description) \
+               { print("  ^2", name, "^7: ", description, "\n"); }
+               
+       CLIENT_COMMANDS(0, 0, "")
+       #undef CLIENT_COMMAND
+       
+       return;
 }
 
-/**
- * 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;
+float ClientCommand_macro_command(float argc, string command)
+{
+       #define CLIENT_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(0))) { function; return TRUE; } }
+               
+       CLIENT_COMMANDS(CC_REQUEST_COMMAND, argc, command)
+       #undef CLIENT_COMMAND
+       
+       return FALSE;
 }
 
-/**
- * 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");
+float ClientCommand_macro_usage(float argc, string command)
+{
+       #define CLIENT_COMMAND(name,function,description) \
+               { if(name == strtolower(argv(1))) { function; return TRUE; } }
+               
+       CLIENT_COMMANDS(CC_REQUEST_USAGE, argc, command)
+       #undef CLIENT_COMMAND
+       
+       return FALSE;
+}
 
+
+// ======================================
+//  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);
+       
+       // 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 "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; // "FALSE": not allowed to continue, halt
        }
-}
+       
+       /* NOTE: totally disabled for now, however the functionality and descriptions are there if we ever want it.
+       if(argv(0) == "help") 
+       {
+               if(argc == 1) 
+               {
+                       sprint(self, "\nUsage:^3 cmd COMMAND...^7, where possible commands are:\n");
+                       ClientCommand_macro_help;
+                       sprint(self, "For help about specific commands, type cmd help COMMAND\n");
+                       return;
+               } 
+               else if(ClientCommand_macro_usage(argc, command)) // Instead of trying to call a command, we're going to see detailed information about it
+               {
+                       return;
+               }
+       } 
+       else*/ if(MUTATOR_CALLHOOK(SV_ParseClientCommand))
+       {
+               return; // handled by a mutator
+       }
+       else if(CheatCommand(argc)) 
+       {
+               return; // handled by server/cheats.qc
+       }
+       else if(ClientCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
+       {
+               return; // handled by one of the above GameCommand_* functions
+       }
+       else
+               clientcommand(self, command);
+}
\ No newline at end of file
index d32c27a..6d3d6a9 100644 (file)
@@ -266,11 +266,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();
@@ -294,8 +289,6 @@ float orig_slowmo; // contains the value of autocvar_slowmo so that, after timeo
 .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;
 
index d0474b8..9a6348b 100644 (file)
@@ -2026,7 +2026,6 @@ float WinningCondition_Race(float fraglimit)
        return wc;
 }
 
-void ReadyRestart();
 float WinningCondition_QualifyingThenRace(float limit)
 {
        float wc;
@@ -2116,6 +2115,7 @@ CheckRules_World
 Exit deathmatch games upon conditions
 ============
 */
+void ReadyRestart();
 void CheckRules_World()
 {
        float timelimit;
@@ -2312,7 +2312,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;
@@ -2469,20 +2469,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;
@@ -2550,7 +2536,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);
        }
@@ -2582,16 +2568,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));
@@ -2616,7 +2602,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;
@@ -2627,7 +2613,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;
                }
        }
 }
@@ -2645,11 +2631,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");
@@ -2658,7 +2644,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");
@@ -2685,12 +2671,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]);
index 986f2dd..7d24f2e 100644 (file)
-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();
-       }
-       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");
-                       }
-               }
+// =====================================================
+//  Server side game commands code, reworked by Samual
+//  Last updated: December 6th, 2011
+// =====================================================
 
-               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();
-       }
-}
+#define GC_REQUEST_COMMAND 1
+#define GC_REQUEST_USAGE 2
 
-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;
-               }
-       }
+float RadarMap_Make(float argc);
 
-       print("Radarmap entity spawned.\n");
-}
+string GotoMap(string m);
 
-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));
+void race_deleteTime(string map, float pos);
 
-       print("\n");
-}
+#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
 
-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);
-}
+// ============================
+//  Misc. Supporting Functions
+// ============================
 
+//  used by GameCommand_make_mapinfo()
 void make_mapinfo_Think()
 {
        if(MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
@@ -627,6 +38,7 @@ void make_mapinfo_Think()
        }
 }
 
+//  used by GameCommand_extendmatchtime() and GameCommand_reducematchtime()
 void changematchtime(float delta, float mi, float ma)
 {
        float cur;
@@ -668,6 +80,7 @@ void changematchtime(float delta, float mi, float ma)
        cvar_set("timelimit", ftos(new / 60));
 }
 
+//  used by GameCommand_modelbug() // TODO: is this even needed?
 float g_clientmodel_genericsendentity (entity to, float sf);
 void modelbug_make_svqc();
 void modelbug_make_csqc()
@@ -684,846 +97,1914 @@ void modelbug_make_svqc()
        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");
+       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;
-       }
+// =======================
+//  Command Sub-Functions
+// =======================
 
-       if(argv(0) == "adminmsg")
-       if(argc >= 3 && argc <= 4)
+void GameCommand_adminmsg(float request, float argc) // todo: re-write this, plus support multiple clients at once like moveplayer
+{
+       switch(request)
        {
-               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)
+               case GC_REQUEST_COMMAND:
                {
-                       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));
+                       entity client;
+                       float entno = stof(argv(1)); 
+                       float n, i;
+                       string s;
+                       
+                       if(argc >= 3 && argc <= 4) {
+                               if((entno < 0) | (entno > maxclients)) {
+                                       print("Player ", argv(1), " doesn't exist\n");
+                                       return;
                                }
-                               else
+                               n = 0;
+                               for(i = (entno ? entno : 1); i <= (entno ? entno : maxclients); ++i)
                                {
-                                       centerprint(client, strcat("^3", admin_name(), ":\n\n^7", argv(2)));
-                                       sprint(client, strcat("\{1}\{13}^3", admin_name(), "^7: ", argv(2), "\n"));
+                                       client = edict_num(i);
+                                       if(client.flags & FL_CLIENT)
+                                       {
+                                               if(argc == 4)
+                                               {
+                                                       // make the string console safe
+                                                       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"));
+                                               }
+                                               dprint("Message sent to ", client.netname, "\n");
+                                               ++n;
+                                       }
                                }
-                               print("Message sent to ", client.netname, "\n");
-                               ++n;
+                               if(!n) { print(strcat("Client (", argv(1) ,") not found.\n")); } 
+                               return;
                        }
                }
-               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;
+               
+               default:
+                       print("Incorrect parameters for ^2adminmsg^7\n");
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd adminmsg clientnumber \"message\" [infobartime]\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 4 \"this infomessage will last for ten seconds\" 10\n");
+                       print("          adminmsg 2 \"this message will be a centerprint\"\n");
+                       return;
+               }
        }
+}
 
-       if(argv(0) == "loaddb") if(argc == 2)
+void GameCommand_allready(float request)
+{
+       switch(request)
        {
-               db_close(ServerProgsDB);
-               ServerProgsDB = db_load(argv(1));
-               print("DB loaded.\n");
-               return;
+               case GC_REQUEST_COMMAND:
+               {
+                       ReadyRestart();
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd allready\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
        }
+}
 
-       if (argv(0) == "nospectators")
+void GameCommand_allspec(float request, float argc)
+{      
+       switch(request)
        {
-               blockSpectators = 1;
-               entity plr;
-               FOR_EACH_CLIENT(plr) //give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player
+               case GC_REQUEST_COMMAND:
                {
-                       if(plr.classname == "spectator" || plr.classname == "observer")
+                       entity client;
+                       string reason = argv(1);
+                       float i;
+                       
+                       FOR_EACH_REALPLAYER(client)
                        {
-                               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"));
+                               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;
                }
-               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)
+                       
+               default:
+               case GC_REQUEST_USAGE:
                {
-                       lockteams = 1;
-                       bprint("^1The teams are now locked.\n");
+                       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;
                }
-               else
-                       bprint("That command can only be used in a team-based gamemode.\n");
-               return;
        }
+}
 
-       if (argv(0) == "unlockteams")
+void GameCommand_anticheat(float request, float argc)
+{
+       switch(request)
        {
-               if(teamplay)
+               case GC_REQUEST_COMMAND:
                {
-                       lockteams = 0;
-                       bprint("^1The teams are now unlocked.\n");
+                       entity client;
+                       float 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;
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2anticheat^7\n");
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd anticheat clientnumber\n");
+                       print("  where 'clientnumber' is player entity number.\n");
+                       return;
                }
-               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");
+void GameCommand_bbox(float request)
+{
+       switch(request)
+       {
+               case GC_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;
                }
-
-               entno = stof(argv(1));
-
-               // player_id is out of range
-               if((entno < 1) | (entno > maxclients)) {
-                       print("Player ", argv(1), " doesn't exist\n");
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd bbox\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2gettaginfo^7\n");
                        return;
                }
+       }
+}
 
-               client = edict_num(entno);
+void GameCommand_bot_cmd(float request, float argc) // what a mess... old old code.
+{
+       switch(request)
+       {
+               case GC_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;
+                               }
 
-               // player entity is not a client
-               if not(client.flags & FL_CLIENT) {
-                       print("Player ", argv(1), " doesn't exist\n");
-                       return;
-               }
+                               i = 0;
+                               while((s = fgets(fh)))
+                               {
+                                       argc = tokenize_console(s);
 
-               // find the team to move the player to
-               float team_colour;
-               float save;
+                                       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"));
 
-               save = client.team_forced;
-               client.team_forced = 0;
+                                       ++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 GC_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: bot_cmd <id> cc \"say something\"\n");
+                       print("          bot_cmd <id> presskey jump\n");
+                       return;
+               }
+       }
+}
 
-               team_colour = ColourToNumber(argv(2));
+void GameCommand_cointoss(float request, float argc)
+{
+       switch(request)
+       {
+               case GC_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 GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd cointoss [result1 result2]\n");
+                       print("  Where 'result1' and 'result2' are user created options.\n");
+                       return;
+               }
+       }
+}
 
-               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
+void GameCommand_cvar_changes(float request)
+{
+       switch(request)
+       {
+               case GC_REQUEST_COMMAND:
+               {
+                       print(cvar_changes);
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd cvar_changes\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2cvar_purechanges^7\n");
                        return;
-               } else if(team_colour == 0)  // auto team
-                       team_colour = NumberToTeamNumber(FindSmallestTeam(client, FALSE));
-               else
-                       CheckAllowedTeams(client);
+               }
+       }
+}
 
-               client.team_forced = save;
+void GameCommand_cvar_purechanges(float request)
+{
+       switch(request)
+       {
+               case GC_REQUEST_COMMAND:
+               {
+                       print(cvar_purechanges);
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd cvar_purechanges\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2cvar_changes^7\n");
+                       return;
+               }
+       }
+}
 
-               switch(team_colour) {
-                       case COLOR_TEAM1:
-                               if(c1 == -1) {
-                                       print("Sorry, there isn't a red team\n");
+void GameCommand_database(float request, float argc)
+{
+       switch(request)
+       {
+               case GC_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;
                                }
-                               break;
-
-                       case COLOR_TEAM2:
-                               if(c2 == -1) {
-                                       print("Sorry, there isn't a blue team\n");
+                               else if(argv(1) == "dump")
+                               {
+                                       db_dump(ServerProgsDB, argv(2));
+                                       print("DB dumped.\n"); // wtf does this do?
                                        return;
                                }
-                               break;
-
-                       case COLOR_TEAM3:
-                               if(c3 == -1) {
-                                       print("Sorry, there isn't a yellow team\n");
+                               else if(argv(1) == "load")
+                               {
+                                       db_close(ServerProgsDB);
+                                       ServerProgsDB = db_load(argv(2));
+                                       print(strcat("Loaded '", argv(2), "' as new serverprogs database.\n"));
                                        return;
                                }
-                               break;
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2database^7\n");
+               case GC_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;
+               }
+       }
+}
 
-                       case COLOR_TEAM4:
-                               if(c4 == -1) {
-                                       print("Sorry, there isn't a pink team\n");
+void GameCommand_defer_clear(float request, float argc)
+{      
+       switch(request)
+       {
+               case GC_REQUEST_COMMAND:
+               {
+                       entity client;
+                       float entno = stof(argv(1));
+                       
+                       if(argc == 2)
+                       {
+                               // player_id is out of range
+                               if((entno < 1) | (entno > maxclients)) {
+                                       print("Player ", argv(1), " doesn't exist\n");
                                        return;
                                }
-                               break;
+                               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;
+                       }
+               }
+               
+               default:
+                       print("Incorrect parameters for ^2defer_clear^7\n");
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd defer_clear clientnumber\n");
+                       print("  where 'clientnumber' is player entity number.\n");
+                       print("See also: ^2defer_clear_all^7\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_defer_clear_all(float request)
+{      
+       switch(request)
+       {
+               case GC_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(GC_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 GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd defer_clear_all\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2defer_clear^7\n");
+                       return;
+               }
+       }
+}
 
-                       default:
-                               print("Sorry, team ", argv(2), " doesn't exist\n");
+void GameCommand_delrec(float request, float argc) // UNTESTED // perhaps merge later with records and printstats and such?
+{
+       switch(request)
+       {
+               case GC_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 GC_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;
                }
-               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)));
+void GameCommand_effectindexdump(float request)
+{
+       switch(request)
+       {
+               case GC_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");
 
-               return;
+                       db_close(d);
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd effectindexdump\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
        }
-       if (argv(0) == "teamstatus")
+}
+
+void GameCommand_extendmatchtime(float request)
+{
+       switch(request)
        {
-               Score_NicePrint(world);
-               return;
+               case GC_REQUEST_COMMAND:
+               {
+                       changematchtime(autocvar_timelimit_increment* 60, autocvar_timelimit_min*60, autocvar_timelimit_max*60);
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd extendmatchtime\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2reducematchtime^7\n");
+                       return;
+               }
        }
-       if (argv(0) == "allready")
+}
+
+void GameCommand_find(float request, float argc)
+{      
+       switch(request)
        {
-               ReadyRestart();
-               return;
+               case GC_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 GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd find classname\n");
+                       print("  Where 'classname' is the classname to search for.\n");
+                       return;
+               }
        }
-       if (argv(0) == "effectindexdump")
+}
+
+void GameCommand_gametype(float request, float argc)
+{      
+       switch(request)
        {
-               EffectIndexDump();
-               return;
+               case GC_REQUEST_COMMAND:
+               {
+                       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 GC_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;
+               }
        }
-       if (argv(0) == "radarmap")
+}
+
+void GameCommand_gettaginfo(float request, float argc) // UNTESTED // todo: finish usage description for it (but, must first learn this shit)
+{      
+       switch(request)
        {
-               RadarMap(argc);
-               return;
+               case GC_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 GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd gettaginfo\n");
+                       print("  FIXME: Arguments currently unknown\n");
+                       print("See also: ^2bbox^7\n");
+                       return;
+               }
        }
-       if (argv(0) == "bbox")
+}
+
+void GameCommand_gotomap(float request, float argc)
+{
+       switch(request)
        {
-               BBox();
-               return;
+               case GC_REQUEST_COMMAND:
+               {
+                       if(argc == 2)
+                       {
+                               print(GotoMap(argv(1)), "\n");
+                               return;
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2gotomap^7\n");
+               case GC_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;
+               }
        }
-       if (argv(0) == "cvar_changes")
+}
+
+void GameCommand_ladder(float request)
+{
+       switch(request)
        {
-               print(cvar_changes);
-               return;
+               case GC_REQUEST_COMMAND:
+               {
+                       print(ladder_reply);
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd ladder\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
        }
-       if (argv(0) == "cvar_purechanges")
+}
+
+void GameCommand_lockteams(float request)
+{
+       switch(request)
        {
-               print(cvar_purechanges);
-               return;
+               case GC_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 GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd lockteams\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2unlockteams^7\n");
+                       return;
+               }
        }
-       if (argv(0) == "find") if(argc == 2)
+}
+
+void GameCommand_make_mapinfo(float request) // UNTESTED
+{
+       switch(request)
        {
-               for(client = world; (client = find(client, classname, argv(1))); )
-                       print(etos(client), "\n");
-               return;
+               case GC_REQUEST_COMMAND:
+               { 
+                       entity tmp_entity;
+                       
+                       tmp_entity = spawn();
+                       tmp_entity.classname = "make_mapinfo";
+                       tmp_entity.think = make_mapinfo_Think;
+                       tmp_entity.nextthink = time; // this sucks... todo: re-write this -- Use initializeentity later
+                       MapInfo_Enumerate();
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd make_mapinfo\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
        }
-       if (argv(0) == "records")
+}
+
+void GameCommand_modelbug(float request) // UNTESTED // is this even needed anymore? 
+{
+       switch(request)
        {
-               for (i = 0; i < 10; ++i)
-                       print(records_reply[i]);
-               return;
+               case GC_REQUEST_COMMAND:
+               {
+                       modelbug();
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd modelbug\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
        }
-       if (argv(0) == "ladder")
+}
+
+void GameCommand_moveplayer(float request, float argc)
+{
+       switch(request)
        {
-               print(ladder_reply);
-               return;
+               case GC_REQUEST_COMMAND:
+               {
+                       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
+                                       if((GetFilteredNumber(t) < 1) || (GetFilteredNumber(t) > maxclients)) // player_id is out of range
+                                       {
+                                               print("Player ", ftos(GetFilteredNumber(t)), " doesn't exist (out of range)", (targets ? ", skipping to next player.\n" : ".\n"));
+                                               continue; 
+                                       }
+                                       client = edict_num(GetFilteredNumber(t));
+                                       if not(client.flags & FL_CLIENT) // player entity is not a client
+                                       {
+                                               print("Player ", ftos(GetFilteredNumber(t)), " doesn't exist (not a client)", (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 GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd moveplayer clientnumbers destination [notify]\n");
+                       print("  'clientnumbers' is a list (separated by commas) of player entity ID's\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: moveplayer 1,3,5 red 3\n");
+                       print("          moveplayer 2 spec \n");
+                       print("See also: ^2allspec, shuffleteams^7\n");
+                       return;
+               }
        }
-       if (argv(0) == "rankings")
+}
+
+void GameCommand_nospectators(float request)
+{
+       switch(request)
        {
-               strunzone(rankings_reply);
-               rankings_reply = strzone(getrankings());
-               print(rankings_reply);
-               return;
+               case GC_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 GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd nospectators\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_onslaught_updatelinks(float request) // UNTESTED // should this be here? Perhaps some mutatorhook call instead....
+{
+       switch(request)
+       {
+               case GC_REQUEST_COMMAND:
+               {
+                       onslaught_updatelinks();
+                       print("ONS links updated\n");
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd onslaught_updatelinks\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_playerdemo(float request, float argc) // UNTESTED
+{      
+       switch(request)
+       {
+               case GC_REQUEST_COMMAND:
+               {
+                       entity client;
+                       float i, n, entno;
+                       string s;
+                       
+                       switch(argv(1))
+                       {
+                               case "read":
+                               {
+                                       // TODO: Create a general command for looking this up, save a lot of space everywhere in this file
+                                       entno = GetFilteredNumber(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;
+                               }
+                               
+                               case "write":
+                               {
+                                       entno = GetFilteredNumber(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;
+                               }
+                               
+                               case "auto_read_and_write":
+                               {
+                                       s = argv(2);
+                                       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), " ", s, ftos(i+1), "\n");
+                                       localcmd("sv_cmd playerdemo write 1 ", ftos(n+1), "\n");
+                                       return;
+                               }
+                               
+                               case "auto_read":
+                               {
+                                       s = argv(2);
+                                       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), " ", s, ftos(i+1), "\n");
+                                       return;
+                               }
+                               
+                               return;
+                       }
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2radarmap^7\n");
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd \n");
+                       print("  FIXME: Arguments currently unknown\n");
+                       return;
+               }
+       }
+}
+
+void GameCommand_printstats(float request)
+{
+       switch(request)
+       {
+               case GC_REQUEST_COMMAND:
+               {
+                       DumpStats(FALSE);
+                       print("stats dumped.\n");
+                       return;
+               }
+                       
+               default:
+               case GC_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 GC_REQUEST_COMMAND:
+               {
+                       if(RadarMap_Make(argc))
+                               return;
+               }
+                       
+               default:
+                       print("Incorrect parameters for ^2radarmap^7\n");
+               case GC_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");
+                       return;
+               }
        }
+}
 
-       if(argv(0) == "cointoss")
+void GameCommand_rankings(float request) // this is OLD.... jeez.
+{
+       switch(request)
        {
-               bprint("^3Throwing coin... Result: ");
-               if (random() > 0.5)
-                       bprint("^1heads ^3!\n");
-               else
-                       bprint("^1tails ^3!\n");
-               return;
+               case GC_REQUEST_COMMAND:
+               {
+                       strunzone(rankings_reply);
+                       rankings_reply = strzone(getrankings());
+                       print(rankings_reply);
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd rankings\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
        }
+}
 
-       if(argv(0) == "__FORCE_READY_RESTART")
+void GameCommand_records(float request)
+{
+       switch(request)
        {
-               reset_map(FALSE);
-               return;
+               case GC_REQUEST_COMMAND:
+               {
+                       float i;
+                       
+                       for (i = 0; i < 10; ++i)
+                               print(records_reply[i]);
+                               
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd records\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
        }
+}
 
-       if(argv(0) == "debug_shotorg")
+void GameCommand_reducematchtime(float request)
+{
+       switch(request)
        {
-               debug_shotorg = stov(argv(1));
-               debug_shotorg_y = -debug_shotorg_y;
-               return;
+               case GC_REQUEST_COMMAND:
+               {
+                       changematchtime(autocvar_timelimit_decrement*-60, autocvar_timelimit_min*60, autocvar_timelimit_max*60);
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd reducematchtime\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2extendmatchtime^7\n");
+                       return;
+               }
        }
+}
 
-       if(argv(0) == "gettaginfo") if(argc >= 4)
+void GameCommand_setbots(float request, float argc)
+{
+       switch(request)
        {
-               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)
+               case GC_REQUEST_COMMAND:
+               {
+                       if(argc >= 2)
                        {
-                               v_y = -v_y;
-                               localcmd(strcat(argv(4), vtos(v), argv(5), "\n"));
+                               cvar_settemp("minplayers", "0");
+                               cvar_settemp("bot_number", argv(1));
+                               bot_fixcount();
+                               return;
                        }
                }
-               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;
+                       
+               default:
+                       print("Incorrect parameters for ^2setbots^7\n");
+               case GC_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;
+               }
        }
+}
 
-       if(argv(0) == "tracebug")
+void GameCommand_shuffleteams(float request)
+{
+       switch(request)
        {
-               print("TEST CASE. If this returns the runaway loop counter error, possibly everything is oaky.\n");
-               for(;;)
+               case GC_REQUEST_COMMAND:
                {
-                       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)
+                       if(teamplay)
                        {
-                               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);
+                               entity tmp_player;
+                               float i, x, z, t_teams, t_players, team_color;
 
-                                       if(trace_startsolid)
+                               // 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(;;)
                                        {
-                                               // how much do we need to back off?
-                                               safe = 1;
-                                               unsafe = 0;
-                                               for(;;)
+                                               i = bound(1, floor(random() * maxclients) + 1, maxclients);
+                                               
+                                               if(shuffleteams_players[i])
                                                {
-                                                       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;
-                                                       }
+                                                       continue; // a player is already assigned to this slot
                                                }
-
-                                               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)
+                                               {
+                                                       shuffleteams_players[i] = num_for_edict(tmp_player);
                                                        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;
+                               }
+
+                               // 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
+                                                               
+                                                       self = edict_num(shuffleteams_players[z]); // TODO: add sanity checks for this entity to make sure it's okay and not some error.
+                                                               
+                                                       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;
                }
-       }
-
-       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)
+                       
+               default:
+               case GC_REQUEST_USAGE:
                {
-                       print("not above ground, aborting\n");
+                       print("\nUsage:^3 sv_cmd shuffleteams\n");
+                       print("  No arguments required.\n");
+                       print("See also: ^2moveplayer, allspec^7\n");
                        return;
                }
-               f = 0;
-               for(i = 0; i < 100000; ++i)
+       }
+}
+
+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 GC_REQUEST_COMMAND:
                {
-                       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)
+                       entity client;
+                       float entno;
+                       
+                       if(argc == 3)
                        {
-                               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;
+                               entno = GetFilteredNumber(argv(1));
+                               client = world;
+                               if(entno <= maxclients)
+                                       client = edict_num(entno);
+                               if(client.flags & FL_CLIENT)
+                               {
+                                       stuffcmd(client, strcat("\n", argv(2), "\n"));
+                                       print(strcat("Command: \"", argv(2), "\" sent to ", client.netname, " (", argv(1) ,").\n"));
+                               }
+                               else
+                                       print(strcat("Client (", argv(1) ,") not found.\n"));
+                               
+                               return;
                        }
                }
-               print("highest possible dist: ", ftos(f), "\n");
-               return;
+                       
+               default:
+                       print("Incorrect parameters for ^2stuffto^7\n");
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd stuffto clientnumber command\n");
+                       print("  FIXME: Arguments currently unknown\n");
+                       return;
+               }
        }
-
-       if(argv(0) == "tracewalk")
+       #else
+       if(request)
        {
-               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");
+               print("stuffto command is not enabled on this server.\n");
                return;
        }
+       #endif
+}
 
-       if(argv(0) == "onslaught_updatelinks")
+void GameCommand_teamstatus(float request)
+{
+       switch(request)
        {
-               onslaught_updatelinks();
-               print("ONS links updated\n");
-               return;
+               case GC_REQUEST_COMMAND:
+               {
+                       Score_NicePrint(world);
+                       return;
+               }
+                       
+               default:
+               case GC_REQUEST_USAGE:
+               {
+                       print("\nUsage:^3 sv_cmd teamstatus\n");
+                       print("  No arguments required.\n");
+                       return;
+               }
        }
+}
 
-       if(argv(0) == "bot_cmd")
+void GameCommand_time(float request)
+{
+       switch(request)
        {
-               entity bot;
-
-               if(argv(1) == "help")
+               case GC_REQUEST_COMMAND:
                {
-                       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));
+                       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"); // FIXME: Why is strftime broken? is engine problem, I think.
+                       print("gmtime = ", strftime(FALSE, "%a %b %e %H:%M:%S %Z %Y"), "\n");
                        return;
                }
-
-               // Clear all bot queues
-               if(argv(1) == "reset")
+                       
+               default:
+               case GC_REQUEST_USAGE:
                {
-                       bot_resetqueues();
+                       print("\nUsage:^3 sv_cmd time\n");
+                       print("  No arguments required.\n");
                        return;
                }
+       }
+}
 
-               // set bot count
-               if(argv(1) == "setbots")
+void GameCommand_trace(float request, float argc)
+{                                              
+       switch(request)
+       {
+               case GC_REQUEST_COMMAND:
                {
-                       if(argc >= 3 && argv(1) == "setbots")
+                       // TODO: Clean up all of these variables and merge the code below to use only a few
+                       entity e;
+                       vector org, delta, start, end, p, q, q0, pos, vv, dv;
+                       float i, f, safe, unsafe, dq, dqf;
+       
+                &