Merge remote branch 'refs/remotes/origin/fruitiex/racefixes'
authorRudolf Polzer <divverent@alientrap.org>
Wed, 3 Nov 2010 20:42:30 +0000 (21:42 +0100)
committerRudolf Polzer <divverent@alientrap.org>
Wed, 3 Nov 2010 20:43:07 +0000 (21:43 +0100)
Conflicts:
defaultXonotic.cfg
qcsrc/server/defs.qh

14 files changed:
1  2 
defaultXonotic.cfg
qcsrc/client/Main.qc
qcsrc/client/autocvars.qh
qcsrc/client/hud.qc
qcsrc/client/scoreboard.qc
qcsrc/common/constants.qh
qcsrc/common/util.qh
qcsrc/server/cl_client.qc
qcsrc/server/cl_physics.qc
qcsrc/server/clientcommands.qc
qcsrc/server/defs.qh
qcsrc/server/g_world.qc
qcsrc/server/gamecommand.qc
qcsrc/server/miscfunctions.qc

diff --combined defaultXonotic.cfg
index 84157c2bf78089c1f3f9ac64adfc08f2ff012029,0a959f207e70034da2d3b5d899caf8df8528d36b..b340e5ddecb9b2c01c71d120c2dedcd02b48b9e6
@@@ -26,13 -26,11 +26,13 @@@ gameversion_max 65535 // git builds se
  alias setreport "set \"$1\" \"$2\" ; sendcvar \"$1\""
  
  // detect dedicated server or client
 -alias "_detect_dedicated_$qport" "$*"
 +alias "_detect_dedicated_$qport" "${* asis}"
  alias "_detect_dedicated_0" ""
 -alias if_dedicated "_detect_dedicated_$qport ${* asis}"
 +alias _if_dedicated "_detect_dedicated_$qport ${* asis}"
  alias if_client "${* asis}"
 -if_dedicated alias if_client ""
 +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"
  
@@@ -98,8 -96,6 +98,8 @@@ seta crosshair_size 0.3
  seta crosshair_dot 1
  seta crosshair_dot_alpha 1
  seta crosshair_dot_size 1
 +seta crosshair_pickup 0.25
 +seta crosshair_pickup_speed 4
  seta crosshair_per_weapon 0   "when 1, each gun will display a different crosshair"
  seta crosshair_color_override 0       "when 1, crosshair_color_* overrides the per-weapon color"
  seta crosshair_effect_speed -1 "how fast (in seconds) some crosshair effects should take place, 0 = instant, -1 = 2x weapon switch time"
@@@ -111,109 -107,109 +111,109 @@@ seta crosshair_laser ""      "crosshair to d
  seta crosshair_laser_color_red 1      "crosshair color red component to display when wielding the laser"
  seta crosshair_laser_color_green 0.35 "crosshair color green component to display when wielding the laser"
  seta crosshair_laser_color_blue 0.2   "crosshair color blue component to display when wielding the laser"
 -seta crosshair_laser_color_alpha 0.75 "crosshair alpha value to display when wielding the laser"
 +seta crosshair_laser_alpha 0.75       "crosshair alpha value to display when wielding the laser"
  seta crosshair_laser_size 0.4 "crosshair size when wielding the laser"
  seta crosshair_shotgun ""     "crosshair to display when wielding the shotgun"
  seta crosshair_shotgun_color_red 0.7  "crosshair color red component to display when wielding the shotgun"
  seta crosshair_shotgun_color_green 0.7        "crosshair color green component to display when wielding the shotgun"
  seta crosshair_shotgun_color_blue 0.7 "crosshair color blue component to display when wielding the shotgun"
 -seta crosshair_shotgun_color_alpha 1.1        "crosshair alpha value to display when wielding the shotgun"
 +seta crosshair_shotgun_alpha 1.1      "crosshair alpha value to display when wielding the shotgun"
  seta crosshair_shotgun_size 0.65      "crosshair size when wielding the shotgun"
  seta crosshair_uzi "" "crosshair to display when wielding the machinegun"
  seta crosshair_uzi_color_red 0.4      "crosshair color red component to display when wielding the machinegun"
  seta crosshair_uzi_color_green 0.9    "crosshair color green component to display when wielding the machinegun"
  seta crosshair_uzi_color_blue 0.35    "crosshair color blue component to display when wielding the machinegun"
 -seta crosshair_uzi_color_alpha 0.9    "crosshair alpha value to display when wielding the machinegun"
 +seta crosshair_uzi_alpha 0.9  "crosshair alpha value to display when wielding the machinegun"
  seta crosshair_uzi_size 0.6   "crosshair size when wielding the machinegun"
  seta crosshair_grenadelauncher ""     "crosshair to display when wielding the mortar"
  seta crosshair_grenadelauncher_color_red 1    "crosshair color red component to display when wielding the mortar"
  seta crosshair_grenadelauncher_color_green 0.15       "crosshair color green component to display when wielding the mortar"
  seta crosshair_grenadelauncher_color_blue 0   "crosshair color blue component to display when wielding the mortar"
 -seta crosshair_grenadelauncher_color_alpha 1.15       "crosshair alpha value to display when wielding the mortar"
 +seta crosshair_grenadelauncher_alpha 1.15     "crosshair alpha value to display when wielding the mortar"
  seta crosshair_grenadelauncher_size 0.7       "crosshair size when wielding the mortar"
  seta crosshair_minelayer ""   "crosshair to display when wielding the mortar"
  seta crosshair_minelayer_color_red 0.75       "crosshair color red component to display when wielding the mortar"
  seta crosshair_minelayer_color_green 0.75     "crosshair color green component to display when wielding the mortar"
  seta crosshair_minelayer_color_blue 0 "crosshair color blue component to display when wielding the mortar"
 -seta crosshair_minelayer_color_alpha 1.15     "crosshair alpha value to display when wielding the mortar"
 +seta crosshair_minelayer_alpha 1.15   "crosshair alpha value to display when wielding the mortar"
  seta crosshair_minelayer_size 0.9     "crosshair size when wielding the mortar"
  seta crosshair_electro ""     "crosshair to display when wielding the electro"
  seta crosshair_electro_color_red 0.35 "crosshair color red component to display when wielding the electro"
  seta crosshair_electro_color_green 0.5        "crosshair color green component to display when wielding the electro"
  seta crosshair_electro_color_blue 1   "crosshair color blue component to display when wielding the electro"
 -seta crosshair_electro_color_alpha 1  "crosshair alpha value to display when wielding the electro"
 +seta crosshair_electro_alpha 1        "crosshair alpha value to display when wielding the electro"
  seta crosshair_electro_size 0.5       "crosshair size when wielding the electro"
  seta crosshair_crylink ""     "crosshair to display when wielding the crylink"
  seta crosshair_crylink_color_red 0.85 "crosshair color red component to display when wielding the crylink"
  seta crosshair_crylink_color_green 0.25       "crosshair color green component to display when wielding the crylink"
  seta crosshair_crylink_color_blue 1   "crosshair color blue component to display when wielding the crylink"
 -seta crosshair_crylink_color_alpha 0.85       "crosshair alpha value to display when wielding the crylink"
 +seta crosshair_crylink_alpha 0.85     "crosshair alpha value to display when wielding the crylink"
  seta crosshair_crylink_size 0.4       "crosshair size when wielding the crylink"
  seta crosshair_nex "" "crosshair to display when wielding the nex gun"
  seta crosshair_nex_color_red 0        "crosshair color red component to display when wielding the nex gun"
  seta crosshair_nex_color_green 0.9    "crosshair color green component to display when wielding the nex gun"
  seta crosshair_nex_color_blue 1       "crosshair color blue component to display when wielding the nex gun"
 -seta crosshair_nex_color_alpha 0.85   "crosshair alpha value to display when wielding the nex gun"
 +seta crosshair_nex_alpha 0.85 "crosshair alpha value to display when wielding the nex gun"
  seta crosshair_nex_size 0.65  "crosshair size when wielding the nex gun"
  seta crosshair_hagar ""       "crosshair to display when wielding the hagar"
  seta crosshair_hagar_color_red 0.85   "crosshair color red component to display when wielding the hagar"
  seta crosshair_hagar_color_green 0.5  "crosshair color green component to display when wielding the hagar"
  seta crosshair_hagar_color_blue 0.35  "crosshair color blue component to display when wielding the hagar"
 -seta crosshair_hagar_color_alpha 1    "crosshair alpha value to display when wielding the hagar"
 +seta crosshair_hagar_alpha 1  "crosshair alpha value to display when wielding the hagar"
  seta crosshair_hagar_size 0.8 "crosshair size when wielding the hagar"
  seta crosshair_rocketlauncher ""      "crosshair to display when wielding the rocketlauncher"
  seta crosshair_rocketlauncher_color_red 1     "crosshair color red component to display when wielding the rocketlauncher"
  seta crosshair_rocketlauncher_color_green 0.75        "crosshair color green component to display when wielding the rocketlauncher"
  seta crosshair_rocketlauncher_color_blue 0.2  "crosshair color blue component to display when wielding the rocketlauncher"
 -seta crosshair_rocketlauncher_color_alpha 1   "crosshair alpha value to display when wielding the rocketlauncher"
 +seta crosshair_rocketlauncher_alpha 1 "crosshair alpha value to display when wielding the rocketlauncher"
  seta crosshair_rocketlauncher_size 0.5875     "crosshair size when wielding the rocketlauncher"
  seta crosshair_porto ""       "crosshair to display when wielding the porto"
  seta crosshair_porto_color_red 0.5    "crosshair color red component to display when wielding the porto"
  seta crosshair_porto_color_green 1    "crosshair color green component to display when wielding the porto"
  seta crosshair_porto_color_blue 0.5   "crosshair color blue component to display when wielding the porto"
 -seta crosshair_porto_color_alpha 0.85 "crosshair alpha value to display when wielding the porto"
 +seta crosshair_porto_alpha 0.85       "crosshair alpha value to display when wielding the porto"
  seta crosshair_porto_size 0.6 "crosshair size when wielding the porto"
  seta crosshair_minstanex ""   "crosshair to display when wielding the minstanex gun"
  seta crosshair_minstanex_color_red 0.65       "crosshair color red component to display when wielding the minstanex gun"
  seta crosshair_minstanex_color_green 0.65     "crosshair color green component to display when wielding the minstanex gun"
  seta crosshair_minstanex_color_blue 1 "crosshair color blue component to display when wielding the minstanex gun"
 -seta crosshair_minstanex_color_alpha 1        "crosshair alpha value to display when wielding the minstanex gun"
 +seta crosshair_minstanex_alpha 1      "crosshair alpha value to display when wielding the minstanex gun"
  seta crosshair_minstanex_size 0.4     "crosshair size when wielding the minstanex gun"
  seta crosshair_hook ""        "crosshair to display when wielding the hook"
  seta crosshair_hook_color_red 0.65    "crosshair color red component to display when wielding the hook"
  seta crosshair_hook_color_green 1     "crosshair color green component to display when wielding the hook"
  seta crosshair_hook_color_blue 0.85   "crosshair color blue component to display when wielding the hook"
 -seta crosshair_hook_color_alpha 0.85  "crosshair alpha value to display when wielding the hook"
 +seta crosshair_hook_alpha 0.85        "crosshair alpha value to display when wielding the hook"
  seta crosshair_hook_size 0.5  "crosshair size when wielding the hook"
  seta crosshair_hlac ""        "crosshair to display when wielding the H.L.A.C"
  seta crosshair_hlac_color_red 1       "crosshair color red component to display when wielding the H.L.A.C."
  seta crosshair_hlac_color_green 0.65  "crosshair color green component to display when wielding the H.L.A.C."
  seta crosshair_hlac_color_blue 0.2    "crosshair color blue component to display when wielding the H.L.A.C."
 -seta crosshair_hlac_color_alpha 1     "crosshair alpha value to display when wielding the H.L.A.C."
 +seta crosshair_hlac_alpha 1   "crosshair alpha value to display when wielding the H.L.A.C."
  seta crosshair_hlac_size 0.6  "crosshair size when wielding the H.L.A.C."
  seta crosshair_seeker ""      "crosshair to display when wielding the TAG Seeker"
  seta crosshair_seeker_color_red 1     "crosshair color red component to display when wielding the TAG seeker"
  seta crosshair_seeker_color_green 0.35        "crosshair color green component to display when wielding the TAG seeker"
  seta crosshair_seeker_color_blue 0.35 "crosshair color blue component to display when wielding the TAG seeker"
 -seta crosshair_seeker_color_alpha 0.9 "crosshair alpha value to display when wielding the TAG seeker"
 +seta crosshair_seeker_alpha 0.9       "crosshair alpha value to display when wielding the TAG seeker"
  seta crosshair_seeker_size 0.8        "crosshair size when wielding the TAG seeker"
  seta crosshair_campingrifle ""        "crosshair to display when wielding the campingrifle"
  seta crosshair_campingrifle_color_red 0.85    "crosshair color red component to display when wielding the campingrifle"
  seta crosshair_campingrifle_color_green 0.5   "crosshair color green component to display when wielding the campingrifle"
  seta crosshair_campingrifle_color_blue 0.25   "crosshair color blue component to display when wielding the campingrifle"
 -seta crosshair_campingrifle_color_alpha 1     "crosshair alpha value to display when wielding the campingrifle"
 +seta crosshair_campingrifle_alpha 1   "crosshair alpha value to display when wielding the campingrifle"
  seta crosshair_campingrifle_size 0.65 "crosshair size when wielding the campingrifle"
  seta crosshair_tuba ""        "crosshair to display when wielding the tuba"
  seta crosshair_tuba_color_red 0.85    "crosshair color red component to display when wielding the tuba"
  seta crosshair_tuba_color_green 0.5   "crosshair color green component to display when wielding the tuba"
  seta crosshair_tuba_color_blue 0.25   "crosshair color blue component to display when wielding the tuba"
 -seta crosshair_tuba_color_alpha 1     "crosshair alpha value to display when wielding the tuba"
 +seta crosshair_tuba_alpha 1   "crosshair alpha value to display when wielding the tuba"
  seta crosshair_tuba_size 1    "crosshair size when wielding the tuba"
  seta crosshair_fireball ""    "crosshair to display when wielding the fireball"
  seta crosshair_fireball_color_red 0.2 "crosshair color red component to display when wielding the fireball"
  seta crosshair_fireball_color_green 1.0       "crosshair color green component to display when wielding the fireball"
  seta crosshair_fireball_color_blue 0.2        "crosshair color blue component to display when wielding the fireball"
 -seta crosshair_fireball_color_alpha 1 "crosshair alpha value to display when wielding the fireball"
 +seta crosshair_fireball_alpha 1       "crosshair alpha value to display when wielding the fireball"
  seta crosshair_fireball_size 1        "crosshair size when wielding the fireball"
  seta crosshair_ring_size 2    "bullet counter ring size for Rifle, velocity ring for Nex"
  seta crosshair_campingrifle_bulletcounter_alpha 0.15
@@@ -491,7 -487,7 +491,7 @@@ alias g_waypointeditor_unreachable "imp
  
  locs_enable 0
  pausable 0
 -seta g_spawnshieldtime 0.3 "number of seconds you are invincible after you spawned, this shield is lost after you fire"
 +seta g_spawnshieldtime 0.300000 "number of seconds you are invincible after you spawned, this shield is lost after you fire"
  seta g_antilag 2      "AntiLag (0 = no AntiLag, 1 = verified client side hit scan, 2 = server side hit scan in the past, 3 = unverified client side hit scan)"
  set g_antilag_nudge 0 "don't touch"
  set g_antilag_bullets 1 "Bullets AntiLag (0 = no AntiLag, 1 = server side hit scan in the past) - DO NOT TOUCH (severely changes weapon balance)"
@@@ -630,8 -626,9 +630,9 @@@ set g_ons_respawn_waves 
  set g_rc_respawn_waves 0
  set g_rc_respawn_delay 0
  set g_cts_respawn_waves 0
- set g_cts_respawn_delay 0
+ set g_cts_respawn_delay 0.25
  set g_cts_selfdamage 1 "0 = disable all selfdamage and falldamage in cts"
+ set g_cts_finish_kill_delay 10 "prevent cheating by running back to the start line, and starting out with more speed than otherwise possible"
  
  // overtime
  seta timelimit_overtime 2 "duration in minutes of one added overtime, added to the timelimit"
@@@ -642,8 -639,8 +643,8 @@@ seta timelimit_suddendeath 5 "number o
  set g_tdm 0 "Team Deathmatch: the team who kills their opponents most often wins"
  
  seta teamplay_default 4 "default teamplay setting in team games. 1 = no friendly fire, self damage. 2 = friendly fire and self damage enabled. 3 = no friendly fire, but self damage enabled. 4 = obey the following four cvars"
 -seta g_mirrordamage 0.3       "for teamplay 4: mirror damage factor"
 -seta g_friendlyfire 0.1       "for teamplay 4: fiendly fire factor"
 +seta g_mirrordamage 0.300000  "for teamplay 4: mirror damage factor"
 +seta g_friendlyfire 0.100000  "for teamplay 4: fiendly fire factor"
  seta g_teamdamage_threshold 50        "for teamplay 4: threshold over which to apply mirror damage"
  seta g_teamdamage_resetspeed 30       "for teamplay 4: how fast player's teamdamage count decreases"
  
@@@ -1341,9 -1338,6 +1342,9 @@@ alias _userbind_call "${$1}
  alias +userbind "_userbind_call userbind${1}_press"
  alias -userbind "_userbind_call userbind${1}_release"
  
 +// we must change its default from 1.0 to 1 to be consistent with menuqc
 +seta slowmo 1
 +
  seta menu_skin "luminos"
  set menu_slowmo 1
  seta menu_sounds 0 "enables menu sound effects. 1 enables click sounds, 2 also enables hover sounds"
@@@ -1597,8 -1591,8 +1598,8 @@@ seta sv_status_privacy 1        "hide IP addre
  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)"
  
 -seta 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
 +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 ons_map           "cl_cmd radar" // legacy alias
  alias radar             "cl_cmd radar"
@@@ -1657,6 -1651,7 +1658,7 @@@ set g_showweaponspawns 1        "display sprit
  
  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
@@@ -1998,6 -1993,5 +2000,9 @@@ r_font_hinting 
  r_font_disable_freetype 0
  r_font_size_snapping 2
  
 +// database management
 +set sv_db_saveasdump 0 "write server.db in dump format (loads slower, easier to read/parse)"
 +set cl_db_saveasdump 0 "write client.db in dump format (loads slower, easier to read/parse)"
++
+ // uid2name
+ seta cl_allow_uid2name -1 "-1 = ask if the player wants to disable/enable this feature, 0 = disable, 1 = enable uid2name (allows showing your name in race rankings for instance)"
diff --combined qcsrc/client/Main.qc
index 9c50d7a3442d7fd36585ad836d26ced8ea07f6e6,462f289ad2cb032802a2a53bcae44c76a6dbf9be..4846a9fef572aab667fafb724778051d7c69f78c
@@@ -186,10 -186,7 +186,10 @@@ void CSQC_Shutdown(void
        remove(players);
        db_close(binddb);
        db_close(tempdb);
 -      db_save(ClientProgsDB, "client.db");
 +      if(cvar("cl_db_saveasdump"))
 +              db_dump(ClientProgsDB, "client.db");
 +      else
 +              db_save(ClientProgsDB, "client.db");
        db_close(ClientProgsDB);
  
        cvar_clientsettemp_restore();
@@@ -627,6 -624,56 +627,56 @@@ float CSQC_InputEvent(float bInputType
        local float bSkipKey;
        bSkipKey = false;
  
+       if(autocvar_cl_allow_uid2name == -1 && (gametype == GAME_CTS || gametype == GAME_RACE) && panel_fg_alpha && !scoreboard_active) // don't lock keys before we actually see what's going on
+       {
+               /*
+               string vyes_keys;
+               float keys;
+               vyes_keys = findkeysforcommand("vyes");
+               keys = tokenize(vyes_keys);
+               float i;
+               for (i = 0; i < keys; ++i)
+               {
+                       print(ftos(nPrimary), " ", argv(i), "\n"); 
+                       if(nPrimary == stof(argv(i)))
+                       {
+                               vote_active = 0;
+                               cvar_set("cl_allow_uid2name", "1");
+                               return TRUE;
+                       }
+               }
+               string vno_keys;
+               vno_keys = findkeysforcommand("vno");
+               keys = tokenize(vno_keys);
+               float i;
+               for (i = 0; i < keys; ++i)
+               {
+                       if(nPrimary == stof(argv(i)))
+                       {
+                               vote_active = 0;
+                               cvar_set("cl_allow_uid2name", "0");
+                               return TRUE;
+                       }
+               }
+               */ // If only I could grab F1-F12 in CSQC... but no
+               if(nPrimary == 121) // ascii value for y
+               {
+                       vote_active = 0;
+                       cvar_set("cl_allow_uid2name", "1");
+                       return TRUE;
+               }
+               else if(nPrimary == 110) // ascii value for n
+               {
+                       vote_active = 0;
+                       cvar_set("cl_allow_uid2name", "0");
+                       return TRUE;
+               }
+       }
        if (HUD_Panel_InputEvent(bInputType, nPrimary, nSecondary))
                return true;
  
        if(menu_visible)
                if(menu_action(bInputType, nPrimary, nSecondary))
                        return TRUE;
        return bSkipKey;
  }
  
index ac721eda1a5e9456f2b585cdc50ee723f3f3219a,e34df2ff06ce2935feb9dc828697e952ccd89e61..ea0fcecedfa8ac2a716fe6c23f9012f07093571d
@@@ -59,6 -59,7 +59,6 @@@ var string autocvar_hud_panel_weapons_b
  var string autocvar_hud_panel_weapons_bg_padding;
  var float autocvar_hud_panel_weapons_aspect;
  var float autocvar_hud_panel_weapons_accuracy;
 -var float autocvar_hud_panel_weapons_accuracy_yellow;
  var float autocvar_hud_panel_weapons_ammo;
  var vector autocvar_hud_panel_weapons_ammo_color;
  var float autocvar_hud_panel_weapons_ammo_alpha;
@@@ -235,3 -236,5 +235,5 @@@ var string autocvar_hud_panel_infomessa
  var float autocvar_hud_panel_infomessages_flip;
  
  var float autocvar_scoreboard_border_thickness;
+ var float autocvar_cl_allow_uid2name;
diff --combined qcsrc/client/hud.qc
index 379b81075133ad76755665608b73b7341d15abab,c2f4e65c20b2433de0c74cc162b3e2d3f9e749ad..971a791aad847ac58625919380c4b6e81412cba9
@@@ -459,7 -459,7 +459,7 @@@ void HUD_Panel_ExportCfg(string cfgname
                float i;
                for (i = 0; i < HUD_PANEL_NUM; ++i)
                {
 -                      HUD_Panel_GetName(i)
 +                      HUD_Panel_GetName(i);
  
                        fputs(fh, strcat("seta hud_panel_", panel_name, " ", cvar_string(strcat("hud_panel_", panel_name)), "\n"));
                        fputs(fh, strcat("seta hud_panel_", panel_name, "_pos \"", cvar_string(strcat("hud_panel_", panel_name, "_pos")), "\"", "\n"));
@@@ -540,9 -540,7 +540,9 @@@ void HUD_Panel_HlBorder(float myBorder
  if(panel_bg != "0")\
        draw_BorderPicture(panel_pos - '1 1 0' * panel_bg_border, panel_bg, panel_size + '1 1 0' * 2 * panel_bg_border, panel_bg_color, panel_bg_alpha * alpha, '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER));\
  if(highlightedPanel_prev == active_panel && autocvar__hud_configure)\
 -      HUD_Panel_HlBorder(panel_bg_border + 1.5 * hlBorderSize, '0 0.5 1', 0.25 * (1 - autocvar__menu_alpha) * alpha);
 +{\
 +      HUD_Panel_HlBorder(panel_bg_border + 1.5 * hlBorderSize, '0 0.5 1', 0.25 * (1 - autocvar__menu_alpha) * alpha);\
 +} ENDS_WITH_CURLY_BRACE
  
  void HUD_Panel_DrawProgressBar(vector pos, float vertical, vector mySize, vector color, float alpha, float drawflag)
  {
@@@ -596,6 -594,8 +596,6 @@@ vector HUD_Panel_CheckMove(vector myPos
        vector myTarget;
        myTarget = myPos;
  
 -      vector targPos;
 -      vector targSize;
        vector myCenter;
        vector targCenter;
        myCenter = '0 0 0'; // shut up fteqcc, there IS a reference
                if(i == highlightedPanel || !panel_enabled)
                        continue;
  
 -              HUD_Panel_UpdatePosSizeForId(i)
 +              HUD_Panel_UpdatePosSizeForId(i);
  
                panel_pos -= '1 1 0' * panel_bg_border;
                panel_size += '2 2 0' * panel_bg_border;
  
  void HUD_Panel_SetPos(vector pos)
  {
 -      HUD_Panel_UpdatePosSizeForId(highlightedPanel)
 +      HUD_Panel_UpdatePosSizeForId(highlightedPanel);
        vector mySize;
        mySize = panel_size;
  
  vector HUD_Panel_CheckResize(vector mySize, vector resizeorigin) {
        float i;
  
 -      float targBorder;
 -      vector targPos;
 -      vector targSize;
        vector targEndPos;
  
 -      vector dist;
 +      float dist_x, dist_y;
        float ratio;
        ratio = mySize_x/mySize_y;
  
                if(i == highlightedPanel || !panel_enabled)
                        continue;
  
 -              HUD_Panel_UpdatePosSizeForId(i)
 +              HUD_Panel_UpdatePosSizeForId(i);
  
                panel_pos -= '1 1 0' * panel_bg_border;
                panel_size += '2 2 0' * panel_bg_border;
  
  void HUD_Panel_SetPosSize(vector mySize)
  {
 -      HUD_Panel_UpdatePosSizeForId(highlightedPanel)
 +      HUD_Panel_UpdatePosSizeForId(highlightedPanel);
        vector resizeorigin;
        resizeorigin = panel_click_resizeorigin;
        vector myPos;
@@@ -938,7 -941,7 +938,7 @@@ void HUD_Panel_Arrow_Action(float nPrim
  
        highlightedPanel = highlightedPanel_prev;
  
 -      HUD_Panel_UpdatePosSizeForId(highlightedPanel)
 +      HUD_Panel_UpdatePosSizeForId(highlightedPanel);
  
        vector prev_pos, prev_size;
        prev_pos = panel_pos;
                HUD_Panel_SetPos(pos);
        }
  
 -      HUD_Panel_UpdatePosSizeForId(highlightedPanel)
 +      HUD_Panel_UpdatePosSizeForId(highlightedPanel);
  
        if (prev_pos != panel_pos || prev_size != panel_size)
        {
  
  float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary)
  {
 +      string s;
 +
        if(!autocvar__hud_configure)
                return false;
  
                        if (highlightedPanel_copied == -1 || highlightedPanel_prev == -1)
                                return true;
  
 -                      HUD_Panel_UpdatePosSizeForId(highlightedPanel_prev)
 +                      HUD_Panel_UpdatePosSizeForId(highlightedPanel_prev);
  
                        // reduce size if it'd go beyond screen boundaries
                        vector tmp_size = panel_size_copied;
                        panel_size_backup = panel_size;
                        highlightedPanel_backup = highlightedPanel_prev;
  
 -                      string s;
                        s = strcat(ftos(tmp_size_x/vid_conwidth), " ", ftos(tmp_size_y/vid_conheight));
                        cvar_set(strcat("hud_panel_", panel_name, "_size"), s);
                }
                        //restore previous values
                        if (highlightedPanel_backup != -1)
                        {
 -                              HUD_Panel_GetName(highlightedPanel_backup)
 -                              string s;
 +                              HUD_Panel_GetName(highlightedPanel_backup);
                                s = strcat(ftos(panel_pos_backup_x/vid_conwidth), " ", ftos(panel_pos_backup_y/vid_conheight));
                                cvar_set(strcat("hud_panel_", panel_name, "_pos"), s);
                                s = strcat(ftos(panel_size_backup_x/vid_conwidth), " ", ftos(panel_size_backup_y/vid_conheight));
@@@ -1158,7 -1161,7 +1158,7 @@@ float HUD_Panel_HighlightCheck(
                i = panel_order[j];
                j += 1;
  
 -              HUD_Panel_UpdatePosSizeForId(i)
 +              HUD_Panel_UpdatePosSizeForId(i);
  
                panelPos = panel_pos;
                panelSize = panel_size;
@@@ -1242,7 -1245,7 +1242,7 @@@ void HUD_Panel_Highlight(
                i = panel_order[j];
                j += 1;
  
 -              HUD_Panel_UpdatePosSizeForId(i)
 +              HUD_Panel_UpdatePosSizeForId(i);
  
                panelPos = panel_pos;
                panelSize = panel_size;
@@@ -1352,7 -1355,7 +1352,7 @@@ void HUD_Panel_Mouse(
                        prev_size = panel_size;
                }
                else
 -                      HUD_Panel_UpdatePosSizeForId(highlightedPanel)
 +                      HUD_Panel_UpdatePosSizeForId(highlightedPanel);
  
                if (prev_pos != panel_pos || prev_size != panel_size)
                {
                        mouseClicked = 0; // to prevent spam, I guess.
                        menu_enabled = 2;
                        menu_enabled_time = time;
 -                      HUD_Panel_GetName(highlightedPanel)
 +                      HUD_Panel_GetName(highlightedPanel);
                        localcmd("menu_showhudoptions ", panel_name, "\n");
                        return;
                }
                highlightcheck = HUD_Panel_HighlightCheck();
        }
        // draw cursor after performing move/resize to have the panel pos/size updated before highlightcheck
 -      string cursor;
        vector cursorsize;
        cursorsize = '32 32 0';
  
@@@ -1431,7 -1435,7 +1431,7 @@@ float weaponspace[10]
  #define HUD_Weapons_Clear()\
        float idx;\
        for(idx = 0; idx < 10; ++idx)\
 -              weaponspace[idx] = 0;
 +              weaponspace[idx] = 0
  
  entity weaponorder[WEP_MAXCOUNT];
  void weaponorder_swap(float i, float j, entity pass)
        weaponorder[j] = h;
  }
  
 -string weaponorder_cmp_str_save;
  string weaponorder_cmp_str;
  float weaponorder_cmp(float i, float j, entity pass)
  {
@@@ -1470,6 -1475,7 +1470,6 @@@ float GetAmmoTypeForWep(float i
        {
                case WEP_SHOTGUN: return 0;
                case WEP_UZI: return 1;
 -              case WEP_CAMPINGRIFLE: return 1;
                case WEP_GRENADE_LAUNCHER: return 2;
                case WEP_MINE_LAYER: return 2;
                case WEP_ELECTRO: return 3;
                case WEP_HLAC: return 3;
                case WEP_MINSTANEX: return 3;
                case WEP_NEX: return 3;
 +              case WEP_CAMPINGRIFLE: return 1;
                case WEP_HAGAR: return 2;
                case WEP_ROCKET_LAUNCHER: return 2;
                case WEP_SEEKER: return 2;
  
  void HUD_Weapons(void)
  {
 +      float f, screen_ar;
 +      float center_x, center_y;
 +
        if(!autocvar_hud_panel_weapons && !autocvar__hud_configure)
                return;
  
  
        if (timeout && time >= weapontime + timeout && !autocvar__hud_configure)
        {
 -              float f = (time - (weapontime + timeout)) / timeout_effect_length;
 +              f = (time - (weapontime + timeout)) / timeout_effect_length;
                if (cvar("hud_panel_weapons_timeout_effect"))
                {
                        panel_bg_alpha *= (1 - f);
                if (cvar("hud_panel_weapons_timeout_effect") == 1)
                {
                        f *= f; // for a cooler movement
 -                      vector center;
                        center_x = panel_pos_x + panel_size_x/2;
                        center_y = panel_pos_y + panel_size_y/2;
 -                      float screen_ar = vid_conwidth/vid_conheight;
 +                      screen_ar = vid_conwidth/vid_conheight;
                        if (center_x/center_y < screen_ar) //bottom left
                        {
                                if ((vid_conwidth - center_x)/center_y < screen_ar) //bottom
        }
        else if (timeout && time < weaponprevtime + timein_effect_length && !autocvar__hud_configure)
        {
 -              float f = (time - weaponprevtime) / timein_effect_length;
 +              f = (time - weaponprevtime) / timein_effect_length;
                if (cvar("hud_panel_weapons_timeout_effect"))
                {
                        panel_bg_alpha *= (f);
                {
                        f *= f; // for a cooler movement
                        f = 1 - f;
 -                      vector center;
                        center_x = panel_pos_x + panel_size_x/2;
                        center_y = panel_pos_y + panel_size_y/2;
 -                      float screen_ar = vid_conwidth/vid_conheight;
 +                      screen_ar = vid_conwidth/vid_conheight;
                        if (center_x/center_y < screen_ar) //bottom left
                        {
                                if ((vid_conwidth - center_x)/center_y < screen_ar) //bottom
        }
  
        // TODO make this configurable
 -      weaponorder_cmp_str = strcat(" ", weaponorder_byimpulse, " ");
 -
 -      if(weaponorder_cmp_str != weaponorder_cmp_str_save)
 +      if(weaponorder_bypriority != cvar_string("cl_weaponpriority"))
        {
 -              if(weaponorder_cmp_str_save)
 -                      strunzone(weaponorder_cmp_str_save);
 -              weaponorder_cmp_str_save = strzone(weaponorder_cmp_str);
 +              if(weaponorder_bypriority)
 +                      strunzone(weaponorder_bypriority);
 +              if(weaponorder_byimpulse)
 +                      strunzone(weaponorder_byimpulse);
 +
 +              weaponorder_bypriority = strzone(cvar_string("cl_weaponpriority"));
 +              weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(W_FixWeaponOrder_ForceComplete(W_NumberWeaponOrder(weaponorder_bypriority))));
 +              weaponorder_cmp_str = strcat(" ", weaponorder_byimpulse, " ");
 +
                weapon_cnt = 0;
                for(i = WEP_FIRST; i <= WEP_LAST; ++i)
                {
                        }
                }
                heapsort(weapon_cnt, weaponorder_swap, weaponorder_cmp, world);
 +
 +              weaponorder_cmp_str = string_null;
        }
  
        HUD_Panel_DrawBg(1);
                                                default: fullammo = 60;
                                        }
  
 -                                      vector barsize;
 -                                      vector barpos;
 +                                      float barsize_x, barsize_y, barpos_x, barpos_y;
                                        if(wpnsize_x/wpnsize_y > autocvar_hud_panel_weapons_aspect)
                                        {
                                                barsize_x = autocvar_hud_panel_weapons_aspect * wpnsize_y;
@@@ -1957,8 -1956,7 +1957,8 @@@ void HUD_Ammo(void
  
  void DrawNumIcon(float iconalign, vector myPos, vector mySize, float x, string icon, float left, vector color, float alpha)
  {
 -      vector newSize, newPos;
 +      vector newPos;
 +      float newSize_x, newSize_y;
        if(mySize_x/mySize_y > 3)
        {
                newSize_x = 3 * mySize_y;
@@@ -2102,7 -2100,7 +2102,7 @@@ void HUD_Powerups(void) 
  
                        if(autocvar_hud_panel_powerups_progressbar)
                        {
 -                              HUD_Panel_GetProgressBarColor(leftname)
 +                              HUD_Panel_GetProgressBarColorForString(leftname);
                                HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * bound(0, max(strength_time, shield_time), 1), DRAWFLAG_NORMAL);
                        }
                        if(leftcnt > 1)
  
                        if(autocvar_hud_panel_powerups_progressbar)
                        {
 -                              HUD_Panel_GetProgressBarColor(rightname)
 +                              HUD_Panel_GetProgressBarColorForString(rightname);
                                HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * bound(0, max(strength_time, shield_time), 1) * panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        if(rightcnt > 1)
  
                        if(autocvar_hud_panel_powerups_progressbar)
                        {
 -                              HUD_Panel_GetProgressBarColor(leftname)
 +                              HUD_Panel_GetProgressBarColorForString(leftname);
                                HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * bound(0, max(strength_time, shield_time), 1) * panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        if(leftcnt > 1)
  
                        if(autocvar_hud_panel_powerups_progressbar)
                        {
 -                              HUD_Panel_GetProgressBarColor(rightname)
 +                              HUD_Panel_GetProgressBarColorForString(rightname);
                                HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * bound(0, max(strength_time, shield_time), 1) * panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        if(rightcnt > 1)
  
                        if(autocvar_hud_panel_powerups_progressbar)
                        {
 -                              HUD_Panel_GetProgressBarColor(leftname)
 +                              HUD_Panel_GetProgressBarColorForString(leftname);
                                HUD_Panel_DrawProgressBar(barpos, 1, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * bound(0, max(strength_time, shield_time), 1) * panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        if(leftcnt <= 5)
  
                        if(autocvar_hud_panel_powerups_progressbar)
                        {
 -                              HUD_Panel_GetProgressBarColor(rightname)
 +                              HUD_Panel_GetProgressBarColorForString(rightname);
                                HUD_Panel_DrawProgressBar(barpos, 1, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * bound(0, max(strength_time, shield_time), 1) * panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        if(rightcnt <= 5)
@@@ -2303,7 -2301,7 +2303,7 @@@ void HUD_HealthArmor(void
                        biggercount = "health";
                        if(autocvar_hud_panel_healtharmor_progressbar)
                        {
 -                              HUD_Panel_GetProgressBarColor("health")
 +                              HUD_Panel_GetProgressBarColor(health);
                                HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        if(armor)
                        biggercount = "armor";
                        if(autocvar_hud_panel_healtharmor_progressbar)
                        {
 -                              HUD_Panel_GetProgressBarColor("armor")
 +                              HUD_Panel_GetProgressBarColor(armor);
                                HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        if(health)
                                barpos = pos;
                                barsize = eX * mySize_x * min(1, fuel/100) + eY * 0.2 * mySize_y;
                        }
 -                      HUD_Panel_GetProgressBarColor("fuel")
 +                      HUD_Panel_GetProgressBarColor(fuel);
                        HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
                }
        }
  
                                if(autocvar_hud_panel_healtharmor_progressbar)
                                {
 -                                      HUD_Panel_GetProgressBarColor(leftname)
 +                                      HUD_Panel_GetProgressBarColorForString(leftname);
                                        HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                                }
                                DrawNumIcon(autocvar_hud_panel_healtharmor_iconalign, pos, eX * 0.5 * mySize_x + eY * mySize_y, leftcnt, leftname, 1, HUD_Get_Num_Color(leftcnt, 200), 1);
  
                                if(autocvar_hud_panel_healtharmor_progressbar)
                                {
 -                                      HUD_Panel_GetProgressBarColor(rightname)
 +                                      HUD_Panel_GetProgressBarColorForString(rightname);
                                        HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                                }
                                DrawNumIcon(autocvar_hud_panel_healtharmor_iconalign, pos + eX * 0.5 * mySize_x, eX * 0.5 * mySize_x + eY * mySize_y, rightcnt, rightname, 0, HUD_Get_Num_Color(rightcnt, 200), 1);
                                        barpos = pos;
                                        barsize = eX * mySize_x * min(1, fuel/100) + eY * 0.2 * mySize_y;
                                }
 -                              HUD_Panel_GetProgressBarColor("fuel")
 +                              HUD_Panel_GetProgressBarColor(fuel);
                                HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
                        }
                }
  
                                if(autocvar_hud_panel_healtharmor_progressbar)
                                {
 -                                      HUD_Panel_GetProgressBarColor(leftname)
 +                                      HUD_Panel_GetProgressBarColorForString(leftname);
                                        HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                                }
                                DrawNumIcon(autocvar_hud_panel_healtharmor_iconalign, pos, eX * mySize_x + eY * 0.5 * mySize_y, leftcnt, leftname, 1, HUD_Get_Num_Color(leftcnt, 200), 1);
  
                                if(autocvar_hud_panel_healtharmor_progressbar)
                                {
 -                                      HUD_Panel_GetProgressBarColor(rightname)
 +                                      HUD_Panel_GetProgressBarColorForString(rightname);
                                        HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                                }
                                DrawNumIcon(autocvar_hud_panel_healtharmor_iconalign, pos + eY * 0.5 * mySize_y, eX * mySize_x + eY * 0.5 * mySize_y, rightcnt, rightname, 0, HUD_Get_Num_Color(rightcnt, 200), 1);
                                        barpos = pos;
                                        barsize = eX * mySize_x * min(1, fuel/100) + eY * 0.1 * mySize_y;
                                }
 -                              HUD_Panel_GetProgressBarColor("fuel")
 +                              HUD_Panel_GetProgressBarColor(fuel);
                                HUD_Panel_DrawProgressBar(barpos, 0, barsize, progressbar_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
                        }
                }
  
                                if(autocvar_hud_panel_healtharmor_progressbar)
                                {
 -                                      HUD_Panel_GetProgressBarColor(leftname)
 +                                      HUD_Panel_GetProgressBarColorForString(leftname);
                                        HUD_Panel_DrawProgressBar(barpos, 1, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                                }
                                drawpic_aspect_skin(picpos, leftname, '0.4 0.4 0' * mySize_x, '1 1 1', leftalpha * panel_fg_alpha, DRAWFLAG_NORMAL);
  
                                if(autocvar_hud_panel_healtharmor_progressbar)
                                {
 -                                      HUD_Panel_GetProgressBarColor(rightname)
 +                                      HUD_Panel_GetProgressBarColorForString(rightname);
                                        HUD_Panel_DrawProgressBar(barpos, 1, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                                }
                                drawpic_aspect_skin(picpos, rightname, '0.4 0.4 0' * mySize_x, '1 1 1', rightalpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                                        barpos = pos + eY * mySize_y - eY * mySize_y * min(1, fuel/100);
                                        barsize = eX * 0.05 * mySize_x + eY * mySize_y * min(1, fuel/100);
                                }
 -                              HUD_Panel_GetProgressBarColor("fuel")
 +                              HUD_Panel_GetProgressBarColor(fuel);
                                HUD_Panel_DrawProgressBar(barpos, 1, barsize, progressbar_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
                        }
                }
@@@ -2595,6 -2593,9 +2595,9 @@@ void HUD_KillNotify(string s1, string s
        alsoprint = (autocvar_hud_panel_notify_print || !panel_enabled); // print message to console if: notify panel disabled, or cvar to do so enabled
        gentle = (autocvar_cl_gentle || autocvar_cl_gentle_messages);
        
+       if ((msg == MSG_SUICIDE || msg == MSG_KILL || msg == MSG_KILL_ACTION) && gametype == GAME_CTS) // selfkill isn't interesting in CTS and only spams up the notify panel
+               return;
        if(msg == MSG_SUICIDE) {
                w = DEATH_WEAPONOF(type);
                if(WEP_VALID(w)) {
                        HUD_KillNotify_Push(s1, s2, 0, INFO_CAPTUREFLAG);
                        print(s1, "^7 captured the ", s2, s3, "\n");
                }
+       } else if(msg == MSG_RACE) {
+               if(type == RACE_SERVER_RECORD) {
+                       HUD_KillNotify_Push(s1, s2, 1, RACE_SERVER_RECORD);
+               }
+               else if(type == RACE_NEW_RANK) {
+                       HUD_KillNotify_Push(s1, s2, 1, RACE_NEW_RANK);
+               }
+               else if(type == RACE_NEW_TIME) {
+                       HUD_KillNotify_Push(s1, s2, 1, RACE_NEW_TIME);
+               }
+               else if(type == RACE_FAIL) {
+                       HUD_KillNotify_Push(s1, s2, 1, RACE_FAIL);
+               }
        }
  }
  
@@@ -3257,6 -3271,22 +3273,22 @@@ void HUD_Notify (void
                        {
                                s = "notify_void";
                        }
+                       else if(killnotify_deathtype[j] == RACE_SERVER_RECORD)
+                       {
+                               s = "race_newrecordserver";
+                       }
+                       else if(killnotify_deathtype[j] == RACE_NEW_RANK)
+                       {
+                               s = "race_newrankyellow";
+                       }
+                       else if(killnotify_deathtype[j] == RACE_NEW_TIME)
+                       {
+                               s = "race_newtime";
+                       }
+                       else if(killnotify_deathtype[j] == RACE_FAIL)
+                       {
+                               s = "race_newfail";
+                       }
                        if(s != "" && a)
                        {
                                drawpic_aspect_skin(weap_pos, s, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
@@@ -3485,6 -3515,7 +3517,7 @@@ void HUD_Score(void
        }
  
        float score, distribution, leader;
+       string sign;
        vector distribution_color;
        entity tm, pl, me;
        me = (spectatee_status > 0) ? playerslots[spectatee_status - 1] : playerslots[player_localentnum - 1];
                        // distribution display
                        distribution = me.(scores[ps_primary]) - pl.(scores[ps_primary]);
  
-                       distrtimer = ftos(distribution/pow(10, TIME_DECIMALS));
+                       distrtimer = ftos_decimals(fabs(distribution/pow(10, TIME_DECIMALS)), TIME_DECIMALS);
  
                        if (distribution <= 0) {
                                distribution_color = '0 1 0';
+                               sign = "-";
                        }
                        else {
                                distribution_color = '1 0 0';
+                               sign = "+";
                        }
-                       drawstring_aspect(pos + eX * 0.75 * mySize_x, distrtimer, eX * 0.25 * mySize_x + eY * (1/3) * mySize_y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring_aspect(pos + eX * 0.75 * mySize_x, strcat(sign, distrtimer), eX * 0.25 * mySize_x + eY * (1/3) * mySize_y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
                }
                // race record display
                if (distribution <= 0)
@@@ -3747,11 -3780,22 +3782,22 @@@ float vote_change; // "time" when vote_
  
  void HUD_VoteWindow(void) 
  {
+       if(autocvar_cl_allow_uid2name == -1 && (gametype == GAME_CTS || gametype == GAME_RACE))
+       {
+               vote_active = 1;
+               vote_called_vote = strzone(strcat("^2Name ^7instead of \"^1Unregistered player\"", " ^7in stats"));
+       }
        if(!autocvar_hud_panel_vote && !autocvar__hud_configure)
                return;
  
        active_panel = HUD_PANEL_VOTE;
        HUD_Panel_UpdateCvars(vote);
+       if(autocvar_cl_allow_uid2name == -1 && (gametype == GAME_CTS || gametype == GAME_RACE))
+       {
+               panel_pos = eX * 0.3 * vid_conwidth + eY * 0.1 * vid_conheight;
+               panel_size = eX * 0.4 * vid_conwidth + eY * 0.3 * vid_conheight;
+       }
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
        mySize = newSize;
  
        s = "A vote has been called for:";
+       if(autocvar_cl_allow_uid2name == -1 && (gametype == GAME_CTS || gametype == GAME_RACE))
+               s = "Allow servers to store and display your name?";
        drawstring_aspect(pos, s, eX * mySize_x + eY * (2/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL);
-       s = textShortenToWidth(vote_called_vote, mySize_x, '1 1 0' * mySize_y * (1.75/8), stringwidth_colors);
+       s = textShortenToWidth(vote_called_vote, mySize_x, '1 1 0' * mySize_y * (1/8), stringwidth_colors);
        if(autocvar__hud_configure)
                s = "^1Configure the HUD";
        drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize_y, s, eX * mySize_x + eY * (1.75/8) * mySize_y, a, DRAWFLAG_NORMAL);
  
        // print the yes/no counts
        s = strcat("Yes (", getcommandkey("vyes", "vyes"), "): ", ftos(vote_yescount));
+       if(autocvar_cl_allow_uid2name == -1 && (gametype == GAME_CTS || gametype == GAME_RACE))
+               s = strcat("Yes: (press y)");
        drawstring_aspect(pos + eY * (4/8) * mySize_y, s, eX * 0.5 * mySize_x + eY * (1.5/8) * mySize_y, '0 1 0', a, DRAWFLAG_NORMAL);
        s = strcat("No (", getcommandkey("vno", "vno"), "): ", ftos(vote_nocount));
+       if(autocvar_cl_allow_uid2name == -1 && (gametype == GAME_CTS || gametype == GAME_RACE))
+               s = strcat("No: (press n)");
        drawstring_aspect(pos + eX * 0.5 * mySize_x + eY * (4/8) * mySize_y, s, eX * 0.5 * mySize_x + eY * (1.5/8) * mySize_y, '1 0 0', a, DRAWFLAG_NORMAL);
  
        // draw the progress bar backgrounds
@@@ -4223,7 -4273,7 +4275,7 @@@ void HUD_Mod_NexBall(vector pos, vecto
                        barsize = eX * mySize_x + eY * p * mySize_y;
                        vertical = 1;
                }
 -              HUD_Panel_GetProgressBarColor("nexball")
 +              HUD_Panel_GetProgressBarColor(nexball);
                HUD_Panel_DrawProgressBar(pos, vertical, barsize, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
        }
  
@@@ -4287,7 -4337,7 +4339,7 @@@ void HUD_Mod_Race(vector pos, vector my
        } else {
                // text on top
                squareSize = min(mySize_x, mySize_y/2);
 -              textPos = pos + eY * 0.5 * max(0, mySize_y/2 - squareSize) + eX * 0.5 * (mySize_x - squareSize);;
 +              textPos = pos + eY * 0.5 * max(0, mySize_y/2 - squareSize) + eX * 0.5 * (mySize_x - squareSize);
                medalPos = pos + eY * 0.5 * max(0, mySize_y/2 - squareSize) + eY * 0.5 * mySize_y + eX * 0.5 * (mySize_x - squareSize);
        }
  
@@@ -4944,12 -4994,10 +4996,12 @@@ switch (id) {
                HUD_EngineInfo(); break;\
        case (HUD_PANEL_INFOMESSAGES):\
                 HUD_InfoMessages(); break;\
 -}
 +} ENDS_WITH_CURLY_BRACE
  
  void HUD_Main (void)
  {
 +      float i;
 +
        hud_skin_path = strcat("gfx/hud/", autocvar_hud_skin);
  
        // global hud alpha fade
        // HUD configure visible grid
        if(autocvar__hud_configure && autocvar_hud_configure_grid && autocvar_hud_configure_grid_alpha)
        {
 -              float i;
                // x-axis
                for(i = 0; i < 1/bound(0.005, autocvar_hud_configure_grid_xsize, 0.2); ++i)
                {
  
        // draw chat panel on top if it is maximized
        if(autocvar__con_chat_maximized)
 -              HUD_DrawPanel(HUD_PANEL_CHAT);
 +              HUD_Chat(); // HUD_DrawPanel(HUD_PANEL_CHAT);
  
        // TODO hud_'ify these
        if (cvar("cl_showspeed"))
index 2fdf0d22034b2cd9f9f285db4686c9acbda31531,5f0afd7cfdd0476065174b76e71573f181d2079f..b61568a2aeeb9c18ae9f2a16fd14d1892c4be305
@@@ -976,6 -976,7 +976,6 @@@ vector HUD_DrawScoreboardAccuracyStats(
                        float padding;
                        padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value
  
 -                      float weapon_hit, weapon_damage;
                        weapon_damage = weapon_fired[self.weapon-WEP_FIRST];
                        if(weapon_damage)
                        {
@@@ -1043,7 -1044,7 +1043,7 @@@ vector HUD_DrawScoreboardRankings(vecto
        pos_y += hud_fontsize_y;
        vector tmp;
        tmp_x = sbwidth;
-       tmp_y = hud_fontsize_y * RANKINGS_RECEIVED_CNT;
+       tmp_y = 1.25 * hud_fontsize_y * RANKINGS_RECEIVED_CNT;
  
        if (teamplay)
                drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
                n = grecordholder[i];
                p = race_PlaceName(i+1);
                if(grecordholder[i] == GetPlayerName(player_localentnum - 1))
-                       drawfill(pos, '1 0 0' * sbwidth + '0 1 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
+                       drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha_self, DRAWFLAG_NORMAL);
                else if(!mod(i, 2) && scoreboard_highlight)
-                       drawfill(pos, '1 0 0' * sbwidth + '0 1 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
-               drawstring(pos, p, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-               drawstring(pos + '3 0 0' * hud_fontsize_x, TIME_ENCODED_TOSTRING(t), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-               drawcolorcodedstring(pos + '8 0 0' * hud_fontsize_x, n, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+                       drawfill(pos, '1 0 0' * sbwidth + '0 1.25 0' * hud_fontsize_y, hl_rgb, scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
+               drawstring(pos, p, '1 1 0' * hud_fontsize_y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+               drawstring(pos + '3 0 0' * hud_fontsize_y, TIME_ENCODED_TOSTRING(t), '1 1 0' * hud_fontsize_y, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+               drawcolorcodedstring(pos + '8 0 0' * hud_fontsize_y, n, '1 1 0' * hud_fontsize_y, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
                pos_y += 1.25 * hud_fontsize_y;
        }
  
@@@ -1176,11 -1177,11 +1176,11 @@@ void HUD_DrawScoreboard(
  
        if(gametype == GAME_CTS || gametype == GAME_RACE) {
                if(race_speedaward) {
-                       drawcolorcodedstring(pos, strcat("Speed award: ", ftos(race_speedaward), " (", race_speedaward_holder, ")"), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+                       drawcolorcodedstring(pos, strcat("Speed award: ", ftos(race_speedaward), " ^7(", race_speedaward_holder, "^7)"), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
                        pos_y += 1.25 * hud_fontsize_y;
                }
                if(race_speedaward_alltimebest) {
-                       drawcolorcodedstring(pos, strcat("All-time fastest: ", ftos(race_speedaward_alltimebest), " (", race_speedaward_alltimebest_holder, ")"), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+                       drawcolorcodedstring(pos, strcat("All-time fastest: ", ftos(race_speedaward_alltimebest), " ^7(", race_speedaward_alltimebest_holder, "^7)"), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
                        pos_y += 1.25 * hud_fontsize_y;
                }
                pos = HUD_DrawScoreboardRankings(pos, pl, rgb, bg_size);
index 36ea68ddd87db7eac868dbcafb68fc3b04e1f328,4dd3bf76e369d0d44b6cbd88d34005704db5cc20..29029f6e457562aa1a6427d7ff131b5a8d229a98
@@@ -310,8 -310,7 +310,8 @@@ const float STAT_SHOTORG = 46; // compr
  const float STAT_LEADLIMIT = 47;
  const float STAT_BULLETS_LOADED = 48;
  const float STAT_NEX_CHARGE = 49;
 -const float STAT_HUD = 50;
 +const float   STAT_LAST_PICKUP = 50;
 +const float STAT_HUD = 51;
  
  // see DP source, quakedef.h
  const float STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW = 222;
@@@ -565,6 -564,8 +565,8 @@@ float MSG_KILL_ACTION = 3
  float MSG_KILL_ACTION_SPREE = 4;
  float MSG_INFO = 5;
  
+ float MSG_RACE = 10;
  float KILL_TEAM_RED = 10301;
  float KILL_TEAM_BLUE = 10302;
  float KILL_TEAM_SPREE = 10303;
@@@ -590,6 -591,11 +592,11 @@@ float INFO_LOSTFLAG = 10321
  float INFO_RETURNFLAG = 10322;
  float INFO_CAPTUREFLAG = 10323;
  
+ float RACE_SERVER_RECORD = 10400;
+ float RACE_NEW_TIME = 10401;
+ float RACE_NEW_RANK = 10402;
+ float RACE_FAIL = 10403;
  // weapon requests
  float WR_SETUP                = 1; // (SVQC) setup weapon data
  float WR_THINK                = 2; // (SVQC) logic to run every frame
diff --combined qcsrc/common/util.qh
index f1d283238bf7590ab399aa7a75a2a34ab89755a9,65bede381e453829e834ca5e330b42e58034e7ed..2de439ff2732a7775d9670b98e4ce3bd49d11fb2
@@@ -1,6 -1,3 +1,6 @@@
 +// a dummy macro that prevents the "hanging ;" warning
 +#define ENDS_WITH_CURLY_BRACE
 +
  #define ACCUMULATE_FUNCTION(func,otherfunc) \
        #ifdef func \
        void __merge__##otherfunc() { func(); otherfunc(); } \
@@@ -165,7 -162,7 +165,7 @@@ void check_unacceptable_compiler_bugs()
  float compressShotOrigin(vector v);
  vector decompressShotOrigin(float f);
  
- string rankings_reply, lsmaps_reply, lsnewmaps_reply, maplist_reply; // cached replies
+ string rankings_reply, ladder_reply, lsmaps_reply, lsnewmaps_reply, maplist_reply; // cached replies
  string records_reply[10];
  
  float RandomSelection_totalweight;
@@@ -219,7 -216,7 +219,7 @@@ float get_model_parameters(string mod, 
  switch(id) {\
        case HUD_PANEL_ENGINEINFO: panel_name = HUD_PANELNAME_ENGINEINFO; break; \
        case HUD_PANEL_INFOMESSAGES: panel_name = HUD_PANELNAME_INFOMESSAGES; break; \
 -}
 +} ENDS_WITH_CURLY_BRACE
  
  // Get name of specified panel id
  #define HUD_Panel_GetName(id) \
index b03723ae45b78745a353f5919a0da35020e31eeb,76f81c8d7497080cc9ea3a3171631d42f824d859..66a838a31cfa0e2ebdfb8aee4ccad1a6e197bc68
@@@ -1313,6 -1313,22 +1313,22 @@@ void ClientKill (void
                ClientKill_TeamChange(0);
  }
  
+ void CTS_ClientKill_Think (void)
+ {
+       self = self.owner; // set self to the player to be killed
+       sprint(self, "^1You were killed in order to prevent cheating!");
+       ClientKill_Now();
+ }
+ void CTS_ClientKill (float t) // silent version of ClientKill
+ {
+       entity e;
+       e = spawn();
+       e.owner = self;
+       e.think = CTS_ClientKill_Think;
+       e.nextthink = t;
+ }
  void DoTeamChange(float destteam)
  {
        float t, c0;
@@@ -1587,11 -1603,12 +1603,12 @@@ void ClientConnect (void
                        rr = RACE_RECORD;
                t = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "time")));
  
+               msg_entity = self;
                race_send_recordtime(MSG_ONE);
                race_send_speedaward(MSG_ONE);
  
                speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
-               speedaward_alltimebest_holder = db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/netname"));
+               speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
                race_send_speedaward_alltimebest(MSG_ONE);
  
                float i;
@@@ -1695,8 -1712,6 +1712,8 @@@ void ClientDisconnect (void
                strunzone(self.netname_previous);
        if(self.clientstatus)
                strunzone(self.clientstatus);
 +      if(self.weaponorder_byimpulse)
 +              strunzone(self.weaponorder_byimpulse);
  
        ClearPlayerSounds();
  
@@@ -2225,7 -2240,6 +2242,7 @@@ void SpectateCopy(entity spectatee) 
        self.health = spectatee.health;
        self.impulse = 0;
        self.items = spectatee.items;
 +      self.last_pickup = spectatee.last_pickup;
        self.metertime = spectatee.metertime;
        self.strength_finished = spectatee.strength_finished;
        self.invincible_finished = spectatee.invincible_finished;
@@@ -3017,6 -3031,18 +3034,18 @@@ void PlayerPostThink (void
  
        playerdemo_write();
  
+       if((g_cts || g_race) && self.cvar_cl_allow_uid2name)
+       {
+               if(!self.stored_netname)
+                       self.stored_netname = strzone(uid2name(self.crypto_idfp));
+               if(self.stored_netname != self.netname)
+               {
+                       db_put(ServerProgsDB, strcat("uid2name", self.crypto_idfp), self.netname);
+                       strunzone(self.stored_netname);
+                       self.stored_netname = strzone(self.netname);
+               }
+       }
        /*
        if(g_race)
                dprint(sprintf("%f %.6f\n", time, race_GetFractionalLapCount(self)));
index 440c69bf33c13b4ab75f42a4320d543c9c7580f2,782ecd65caa9718805c85878f3976bbaf555e5eb..e211275b0f3eb4f7d1af694562ada31beabe39ae
@@@ -37,6 -37,8 +37,6 @@@ float sv_airspeedlimit_nonqw
  .float multijump_ready;
  .float prevjumpbutton;
  
 -.float nexspeed;
 -
  /*
  =============
  PlayerJump
@@@ -266,7 -268,7 +266,7 @@@ void RaceCarPhysics(
        // using this move type for "big rigs"
        // the engine does not push the entity!
  
 -      float accel, steer, f;
 +      float accel, steer, f, myspeed, steerfactor;
        vector angles_save, rigvel;
  
        angles_save = self.angles;
  
        if(self.flags & FL_ONGROUND || g_bugrigs_air_steering)
        {
 -              float myspeed, upspeed, steerfactor, accelfactor;
 +              float upspeed, accelfactor;
  
                myspeed = self.velocity * v_forward;
                upspeed = self.velocity * v_up;
@@@ -671,6 -673,7 +671,7 @@@ void SpecialCommand(
  
  float speedaward_speed;
  string speedaward_holder;
+ string speedaward_uid;
  void race_send_speedaward(float msg)
  {
        // send the best speed of the round
  
  float speedaward_alltimebest;
  string speedaward_alltimebest_holder;
+ string speedaward_alltimebest_uid;
  void race_send_speedaward_alltimebest(float msg)
  {
        // send the best speed
@@@ -1304,6 -1308,7 +1306,7 @@@ void SV_PlayerPhysics(
                if(vlen(self.velocity - self.velocity_z * '0 0 1') > speedaward_speed) {
                        speedaward_speed = vlen(self.velocity - self.velocity_z * '0 0 1');
                        speedaward_holder = self.netname;
+                       speedaward_uid = self.crypto_idfp;
                        speedaward_lastupdate = time;
                }
                if(speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1) {
                        if (speedaward_speed > speedaward_alltimebest) {
                                speedaward_alltimebest = speedaward_speed;
                                speedaward_alltimebest_holder = speedaward_holder;
+                               speedaward_alltimebest_uid = speedaward_uid;
                                db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed"), ftos(speedaward_alltimebest));
-                               db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/netname"), speedaward_alltimebest_holder);
+                               db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp"), speedaward_alltimebest_uid);
                                race_send_speedaward_alltimebest(MSG_ALL);
                        }
                }
index 0216757e9ccc99e358195b5f0426d1ab67ff6620,a92da718fe3583cdcd068c358f039adf2b2467ca..df19ab592f4779beb94a38881992e37150a43ae0
@@@ -303,6 -303,8 +303,8 @@@ void SV_ParseClientCommand(string s) 
        } else if(cmd == "records") {
                for(i = 0; i < 10; ++i)
                        sprint(self, records_reply[i]);
+       } else if(cmd == "ladder") {
+               sprint(self, ladder_reply);
        } else if(cmd == "rankings") {
                sprint(self, rankings_reply);
        } else if(cmd == "voice") {
                Score_NicePrint(self);
        } else if(cmd == "cvar_changes") {
                sprint(self, cvar_changes);
 +      } else if(cmd == "cvar_purechanges") {
 +              sprint(self, cvar_purechanges);
        } else if(CheatCommand(tokens)) {
        } else {
                //if(ctf_clientcommand())
diff --combined qcsrc/server/defs.qh
index ecca4ac431250e1aba349da70b3d5a02dc7ba988,9295547c530f03e929d6310ffaa267628e43f955..45394eb7925db2bf34fd5e10818131e5646af2dc
@@@ -227,6 -227,7 +227,6 @@@ float WS_READY                     = 4; // idle fram
  void weapon_defaultspawnfunc(float wpn);
  
  string w_deathtypestring;
 -float w_deathtype;
  
  void(entity client, string s) centerprint_builtin = #73;
  .vector dest1, dest2;
@@@ -296,6 -297,7 +296,6 @@@ string getTimeoutText(float addOneSecon
  .entity flagcarried;
  
  .entity lastrocket;
 -.entity lastmine;
  
  .float playerid;
  float playerid_last;
@@@ -327,8 -329,9 +327,11 @@@ float sv_loddistance2
  .float cvar_cl_gunalign;
  .float cvar_cl_noantilag;
  
 +.string weaponorder_byimpulse;
 +
+ .float cvar_cl_allow_uid2name;
+ .string stored_netname;
  void Announce(string snd);
  void AnnounceTo(entity e, string snd);
  
@@@ -523,8 -526,6 +526,8 @@@ string clientstuff
  .string fog;
  
  string cvar_changes;
 +string cvar_purechanges;
 +float cvar_purechanges_count;
  
  float game_starttime; //point in time when the countdown is over
  .float stat_game_starttime;
@@@ -605,8 -606,6 +608,8 @@@ string matchid
  .float stats_hit[WEP_MAXCOUNT];  // for hitscan bullets hit
  .float stats_fired[WEP_MAXCOUNT];  // for hitscan bullets fired
  
 +.float last_pickup;
 +
  FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(stats_hit);
  FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(stats_fired);
  
diff --combined qcsrc/server/g_world.qc
index b24beddd3a2ca06bf6a4b252901caec057b61efc,b761e97c7696a764d2a3fde35b4341089bc5d653..ce7b8e2a15720eec91658e0c48b93faf9e832b8b
@@@ -213,23 -213,16 +213,23 @@@ void cvar_changes_init(
  {
        float h;
        string k, v, d;
 -      float n, i;
 +      float n, i, adding, pureadding;
  
        if(cvar_changes)
                strunzone(cvar_changes);
        cvar_changes = string_null;
 +      if(cvar_purechanges)
 +              strunzone(cvar_purechanges);
 +      cvar_purechanges = string_null;
 +      cvar_purechanges_count = 0;
  
        h = buf_create();
        buf_cvarlist(h, "", "_"); // exclude all _ cvars as they are temporary
        n = buf_getsize(h);
  
 +      adding = TRUE;
 +      pureadding = TRUE;
 +
        for(i = 0; i < n; ++i)
        {
                k = bufstr_get(h, i);
                BADPREFIX("sv_world");
  
                // client
 +              BADPREFIX("chase_");
                BADPREFIX("cl_");
                BADPREFIX("con_");
 +              BADPREFIX("scoreboard_");
                BADPREFIX("g_campaign");
                BADPREFIX("gl_");
                BADPREFIX("joy");
 +              BADPREFIX("hud_");
                BADPREFIX("menu_");
                BADPREFIX("net_slist_");
                BADPREFIX("r_");
                BADPREFIX("sbar_");
                BADPREFIX("scr_");
 +              BADPREFIX("snd_");
                BADPREFIX("userbind");
                BADPREFIX("v_");
                BADPREFIX("vid_");
                BADPREFIX("crosshair");
                BADCVAR("mod_q3bsp_lightmapmergepower");
                BADCVAR("mod_q3bsp_nolightmaps");
 +              BADCVAR("fov");
 +              BADCVAR("mastervolume");
 +              BADCVAR("volume");
 +              BADCVAR("bgmvolume");
  
                // private
                BADCVAR("serverconfig");
                BADCVAR("timestamps");
                BADCVAR("net_address");
                BADCVAR("net_address_ipv6");
 +              BADPREFIX("sv_weaponstats_");
 +              BADCVAR("developer");
 +              BADPREFIX("developer_");
  
                // mapinfo
                BADCVAR("timelimit");
                BADCVAR("g_maplist");
                BADCVAR("g_maplist_mostrecent");
                BADCVAR("sv_motd");
 -#undef BADPREFIX
 -#undef BADCVAR
  
                v = cvar_string(k);
                d = cvar_defstring(k);
 -              if(v != d)
 +              if(v == d)
 +                      continue;
 +
 +              if(adding)
                {
                        cvar_changes = strcat(cvar_changes, k, " \"", v, "\" // \"", d, "\"\n");
                        if(strlen(cvar_changes) > 16384)
                        {
                                cvar_changes = "// too many settings have been changed to show them here\n";
 -                              break;
 +                              adding = 0;
                        }
                }
 +
 +              // now check if the changes are actually gameplay relevant
 +
 +              // does nothing visible
 +              BADPREFIX("prvm_");
 +              BADPREFIX("crypto_");
 +              BADPREFIX("g_chat_");
 +              BADPREFIX("sv_fragmessage_");
 +              BADPREFIX("sv_vote_");
 +              BADPREFIX("timelimit_");
 +
 +              // allowed changes to server admins (please sync this to server.cfg)
 +              // vi commands:
 +              //   :/"impure"/,$d
 +              //   :g!,^\/\/[^ /],d
 +              //   :%s,//\([^ ]*\).*,BADCVAR("\1");,
 +              //   :%!sort
 +              // yes, this does contain some redundant stuff, don't really care
 +              BADCVAR("bot_number");
 +              BADCVAR("bot_prefix");
 +              BADCVAR("bot_suffix");
 +              BADCVAR("capturelimit_override");
 +              BADCVAR("fraglimit_override");
 +              BADCVAR("gametype");
 +              BADCVAR("g_antilag");
 +              BADCVAR("g_balance_teams");
 +              BADCVAR("g_balance_teams_force");
 +              BADCVAR("g_ban_sync_trusted_servers");
 +              BADCVAR("g_ban_sync_uri");
 +              BADCVAR("g_ctf_capture_limit");
 +              BADCVAR("g_ctf_ignore_frags");
 +              BADCVAR("g_ctf_win_mode");
 +              BADCVAR("g_domination_point_limit");
 +              BADCVAR("g_fullbrightitems");
 +              BADCVAR("g_fullbrightplayers");
 +              BADCVAR("g_keyhunt_point_limit");
 +              BADCVAR("g_keyhunt_teams_override");
 +              BADCVAR("g_lms_lives_override");
 +              BADCVAR("g_maplist");
 +              BADCVAR("g_maplist_check_waypoints");
 +              BADCVAR("g_maplist_mostrecent_count");
 +              BADCVAR("g_maplist_shuffle");
 +              BADCVAR("g_maplist_votable");
 +              BADCVAR("g_maplist_votable_abstain");
 +              BADCVAR("g_maplist_votable_nodetail");
 +              BADCVAR("g_maplist_votable_suggestions");
 +              BADCVAR("g_nexball_goallimit");
 +              BADCVAR("g_runematch_point_limit");
 +              BADCVAR("g_start_delay");
 +              BADCVAR("hostname");
 +              BADCVAR("log_file");
 +              BADCVAR("maxplayers");
 +              BADCVAR("minplayers");
 +              BADCVAR("net_address");
 +              BADCVAR("port");
 +              BADCVAR("rcon_password");
 +              BADCVAR("rcon_restricted_commands");
 +              BADCVAR("rcon_restricted_password");
 +              BADCVAR("skill");
 +              BADCVAR("sv_autoscreenshot");
 +              BADCVAR("sv_curl_defaulturl");
 +              BADCVAR("sv_defaultcharacter");
 +              BADCVAR("sv_defaultplayermodel");
 +              BADCVAR("sv_defaultplayerskin");
 +              BADCVAR("sv_maxrate");
 +              BADCVAR("sv_maxidle");
 +              BADCVAR("sv_motd");
 +              BADCVAR("sv_public");
 +              BADCVAR("sv_ready_restart");
 +              BADCVAR("sv_status_privacy");
 +              BADCVAR("sv_vote_call");
 +              BADCVAR("sv_vote_commands");
 +              BADCVAR("sv_vote_majority_factor");
 +              BADCVAR("sv_vote_master");
 +              BADCVAR("sv_vote_master_commands");
 +              BADCVAR("sv_vote_master_password");
 +              BADCVAR("sv_vote_simple_majority_factor");
 +              BADCVAR("timelimit_override");
 +#undef BADPREFIX
 +#undef BADCVAR
 +
 +              if(pureadding)
 +              {
 +                      cvar_purechanges = strcat(cvar_purechanges, k, " \"", v, "\" // \"", d, "\"\n");
 +                      if(strlen(cvar_purechanges) > 16384)
 +                      {
 +                              cvar_purechanges = "// too many settings have been changed to show them here\n";
 +                              pureadding = 0;
 +                      }
 +              }
 +              ++cvar_purechanges_count;
        }
        buf_del(h);
        if(cvar_changes == "")
 -              cvar_changes = "// this server runs at default settings\n";
 +              cvar_changes = "// this server runs at default server settings\n";
        else
 -              cvar_changes = strcat("// this server runs at modified settings:\n", cvar_changes);
 +              cvar_changes = strcat("// this server runs at modified server settings:\n", cvar_changes);
        cvar_changes = strzone(cvar_changes);
 +      if(cvar_purechanges == "")
 +              cvar_purechanges = "// this server runs at default gameplay settings\n";
 +      else
 +              cvar_purechanges = strcat("// this server runs at modified gameplay settings:\n", cvar_purechanges);
 +      cvar_purechanges = strzone(cvar_purechanges);
  }
  
  void detect_maptype()
@@@ -553,8 -438,6 +553,8 @@@ void spawnfunc_worldspawn (void
  
        check_unacceptable_compiler_bugs();
  
 +      cvar_changes_init(); // do this very early now so it REALLY matches the server config
 +
        compressShortVector_init();
  
        allowed_to_spawn = TRUE;
        addstat(STAT_SHOTORG, AS_INT, stat_shotorg);
        addstat(STAT_LEADLIMIT, AS_FLOAT, stat_leadlimit);
        addstat(STAT_BULLETS_LOADED, AS_INT, campingrifle_bulletcounter);
 +      addstat(STAT_LAST_PICKUP, AS_FLOAT, last_pickup);
  
        addstat(STAT_NEX_CHARGE, AS_FLOAT, nex_charge);
  
        addstat(STAT_MOVEVARS_AIRSTRAFEACCEL_QW, AS_FLOAT, stat_sv_airstrafeaccel_qw);
  
        next_pingtime = time + 5;
 -      InitializeEntity(self, cvar_changes_init, INITPRIO_CVARS);
  
        detect_maptype();
  
        {
                records_reply[i] = strzone(getrecords(i));
        }
+       if(g_cts)
+               ladder_reply = strzone(getladder());
  
        rankings_reply = strzone(getrankings());
  
@@@ -2897,19 -2782,9 +2899,19 @@@ void SV_Shutdown(
                print("Saving persistent data...\n");
                Ban_SaveBans();
                if(!cheatcount_total)
 -                      db_save(ServerProgsDB, "server.db");
 +              {
 +                      if(cvar("sv_db_saveasdump"))
 +                              db_dump(ServerProgsDB, "server.db");
 +                      else
 +                              db_save(ServerProgsDB, "server.db");
 +              }
                if(cvar("developer"))
 -                      db_save(TemporaryDB, "server-temp.db");
 +              {
 +                      if(cvar("sv_db_saveasdump"))
 +                              db_dump(TemporaryDB, "server-temp.db");
 +                      else
 +                              db_save(TemporaryDB, "server-temp.db");
 +              }
                CheatShutdown(); // must be after cheatcount check
                db_close(ServerProgsDB);
                db_close(TemporaryDB);
index 9dd7e8784845b615cea2f87ab34f512643c5012d,0d7e0295f9d26b82ee65617fb03b126f9bcc0ba9..90b06a5a3d92a5950fa42d3213263c4f337db8e3
@@@ -1,5 -1,5 +1,5 @@@
  string GotoMap(string m);
- void race_DeleteTime(float pos);
+ void race_deleteTime(string map, float pos);
  
  float FullTraceFraction(vector a, vector mi, vector ma, vector b)
  {
@@@ -651,7 -651,6 +651,7 @@@ void GameCommand(string command
                print("  radarmap [--force] [--quit | --loop] [sharpness]\n");
                print("  bbox\n");
                print("  cvar_changes\n");
 +              print("  cvar_purechanges\n");
                print("  find classname\n");
                GameCommand_Vote("help", world);
                GameCommand_Ban("help");
                print(cvar_changes);
                return;
        }
 +      if (argv(0) == "cvar_purechanges")
 +      {
 +              print(cvar_purechanges);
 +              return;
 +      }
        if (argv(0) == "find") if(argc == 2)
        {
                for(client = world; (client = find(client, classname, argv(1))); )
                        print(records_reply[i]);
                return;
        }
+       if (argv(0) == "ladder")
+       {
+               print(ladder_reply);
+               return;
+       }
        if (argv(0) == "rankings")
        {
                strunzone(rankings_reply);
        }
        if(argv(0) == "delrec")
        {
-               race_DeleteTime(stof(argv(1)));
+               if(argv(2) != "")
+                       race_deleteTime(argv(2), stof(argv(1)));
+               else
+                       race_deleteTime(GetMapname(), stof(argv(1)));
                return;
        }
  
index 668e86f8984003f6096b2f58e36e8086608d3928,bcec7355895744cf74a9887c31f8564b59fd0225..a20c31dd63e18ee5d133bf46dc62b970b1414e8d
@@@ -16,9 -16,6 +16,6 @@@ void WarpZone_crosshair_trace(entity pl
  
  void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints
  void() spawnpoint_use;
- float race_GetTime(float pos);
- string race_GetName(float pos);
- string race_PlaceName(float pos);
  string GetMapname();
  string ColoredTeamName(float t);
  
@@@ -581,19 -578,9 +578,19 @@@ void GetCvars_handleFloatOnce(string th
                        stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
        }
  }
 -string W_FixWeaponOrder_ForceComplete(string s);
 -string W_FixWeaponOrder_AllowIncomplete(string s);
  float w_getbestweapon(entity e);
 +string W_FixWeaponOrder_ForceComplete_AndBuildImpulseList(string wo)
 +{
 +      string o;
 +      o = W_FixWeaponOrder_ForceComplete(wo);
 +      if(self.weaponorder_byimpulse)
 +      {
 +              strunzone(self.weaponorder_byimpulse);
 +              self.weaponorder_byimpulse = string_null;
 +      }
 +      self.weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(o));
 +      return o;
 +}
  void GetCvars(float f)
  {
        string s;
        GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
        GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
        GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
 -      GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
 +      GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete_AndBuildImpulseList);
        GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
        GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
        GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
        GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromxonotic, "cl_forceplayermodelsfromxonotic");
  #endif
        GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
+       GetCvars_handleFloat(s, f, cvar_cl_allow_uid2name, "cl_allow_uid2name");
  
        // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
        if (f > 0)
@@@ -1732,6 -1720,7 +1730,6 @@@ void precache(
  #define INITPRIO_FIRST              0
  #define INITPRIO_GAMETYPE           0
  #define INITPRIO_GAMETYPE_FALLBACK  1
 -#define INITPRIO_CVARS              5
  #define INITPRIO_FINDTARGET        10
  #define INITPRIO_DROPTOFLOOR       20
  #define INITPRIO_SETLOCATION       90
@@@ -2078,6 -2067,106 +2076,106 @@@ void print_to(entity e, string s
          print(s, "\n");
  }
  
+ string uid2name(string myuid) {
+       string s;
+       s = db_get(ServerProgsDB, strcat("uid2name", myuid));
+       
+       if(s == "")
+               s = "^1Unregistered Player";
+       return s;
+ }
+ float race_readTime(string map, float pos)
+ {
+       string rr;
+       if(g_cts)
+               rr = CTS_RECORD;
+       else
+               rr = RACE_RECORD;
+       return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
+ }
+ string race_readUID(string map, float pos)
+ {
+       string rr;
+       if(g_cts)
+               rr = CTS_RECORD;
+       else
+               rr = RACE_RECORD;
+       return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)));
+ }
+ float race_readPos(string map, float t) {
+       float i;
+       for (i = 1; i <= RANKINGS_CNT; ++i)
+               if (race_readTime(map, i) == 0 || race_readTime(map, i) > t)
+                       return i;
+       return 0; // pos is zero if unranked
+ }
+ void race_writeTime(string map, float t, string myuid)
+ {
+       string rr;
+       if(g_cts)
+               rr = CTS_RECORD;
+       else
+               rr = RACE_RECORD;
+       float newpos;
+       newpos = race_readPos(map, t);
+       float i, prevpos;
+       for(i = 1; i <= RANKINGS_CNT; ++i)
+       {
+               if(race_readUID(map, i) == myuid)
+                       prevpos = i;
+       }
+       if (prevpos) { // player improved his existing record, only have to iterate on ranks between new and old recs
+               for (i = prevpos; i > newpos; --i) {
+                       db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
+                       db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
+               }
+       } else { // player has no ranked record yet
+               for (i = RANKINGS_CNT; i > newpos; --i) {
+                       db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
+                       db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
+               }
+       }
+       // store new time itself
+       db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t));
+       db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid);
+ }
+ string race_readName(string map, float pos)
+ {
+       string rr;
+       if(g_cts)
+               rr = CTS_RECORD;
+       else
+               rr = RACE_RECORD;
+       return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
+ }
+ string race_placeName(float pos) {
+       if(floor((mod(pos, 100))/10) * 10 != 10) // examples: 12th, 111th, 213th will not execute this block
+       {
+               if(mod(pos, 10) == 1)
+                       return strcat(ftos(pos), "st");
+               else if(mod(pos, 10) == 2)
+                       return strcat(ftos(pos), "nd");
+               else if(mod(pos, 10) == 3)
+                       return strcat(ftos(pos), "rd");
+               else
+                       return strcat(ftos(pos), "th");
+       }
+       else
+               return strcat(ftos(pos), "th");
+ }
  string getrecords(float page) // 50 records per page
  {
      float rec;
                  r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
                  if (r == 0)
                      continue;
+               // TODO: uid2name
                  h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
                  s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
                  ++rec;
          {
              if (MapInfo_Get_ByID(i))
              {
-                 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
+               r = race_readTime(MapInfo_Map_bspname, 1);
                  if (r == 0)
                      continue;
-                 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
+               h = race_readName(MapInfo_Map_bspname, 1);
                  s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
                  ++rec;
              }
          {
              if (MapInfo_Get_ByID(i))
              {
-                 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
+               r = race_readTime(MapInfo_Map_bspname, 1);
                  if (r == 0)
                      continue;
-                 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
+               h = race_readName(MapInfo_Map_bspname, 1);
                  s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
                  ++rec;
              }
@@@ -2161,11 -2251,11 +2260,11 @@@ string getrankings(
  
      for (i = 1; i <= RANKINGS_CNT; ++i)
      {
-         t = race_GetTime(i);
+         t = race_readTime(map, i);
        if (t == 0)
            continue;
-       n = race_GetName(i);
-       p = race_PlaceName(i);
+       n = race_readName(map, i);
+       p = race_placeName(i);
          s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n");
      }
  
          return strcat("Records for ", map, ":\n", s);
  }
  
+ const float LADDER_FIRSTPOINT = 100;
+ const float LADDER_CNT = 10; // position X still gives LADDER_FIRSTPOINT/X points
+ const float LADDER_SIZE = 30; // ladder shows the top X players
+ string top_uids[LADDER_SIZE];
+ float top_scores[LADDER_SIZE];
+ string getladder()
+ {
+     float i, j, k, uidcnt;
+     string s, temp_s;
+     s = "";
+     temp_s = "";
+     string rr;
+     if(g_cts)
+       rr = CTS_RECORD;
+     else
+       rr = RACE_RECORD;
+     string myuid;
+     for (k = 0; k < MapInfo_count; ++k)
+     {
+         if (MapInfo_Get_ByID(k))
+       {
+               for (i = 0; i <= LADDER_CNT; ++i) { // i = 0 because it is the speed award
+                       if(i == 0) // speed award
+                       {
+                               if(stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/speed"))) == 0)
+                                       continue;
+                               myuid = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/crypto_idfp"));
+                       }
+                       else // normal record, if it exists (else break)
+                       {
+                               if(race_readTime(MapInfo_Map_bspname, i) == 0)
+                                       continue;
+                               myuid = race_readUID(MapInfo_Map_bspname, i);
+                       }
+                       // string s contains:
+                       // arg 0 = # of speed recs
+                       // arg 1 = # of 1st place recs
+                       // arg 2 = # of 2nd place recs
+                       // ... etc
+                       // LADDER_CNT+1 = total points
+                       temp_s = db_get(TemporaryDB, strcat("ladder", myuid));
+                       if (temp_s == "")
+                       {
+                           db_put(TemporaryDB, strcat("uid", ftos(uidcnt)), myuid);
+                           ++uidcnt;
+                           for (j = 0; j <= LADDER_CNT + 1; ++j)
+                           {
+                               if(j != LADDER_CNT + 1)
+                                   temp_s = strcat(temp_s, "0 ");
+                               else
+                                   temp_s = strcat(temp_s, "0");
+                           }
+                       }
+                       tokenize_console(temp_s);
+                       s = "";
+                       if(i == 0) // speed award
+                           for (j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
+                           {
+                               if(j == 0) // speed award
+                                   s = strcat(s, ftos(stof(argv(j)) +1)); // add 1 to speed rec count and write
+                               else
+                                   s = strcat(s, " ", argv(j)); // just copy over everything else
+                           }
+                       else // record
+                           for (j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
+                           {
+                               if(j == 0)
+                                   s = strcat(s, argv(j)); // speed award, dont prefix with " "
+                               else if(j == i) // wanted rec!
+                                   s = strcat(s, " ", ftos(stof(argv(j)) +1)); // update argv(j)
+                               else
+                                   s = strcat(s, " ", argv(j)); // just copy over everything else
+                           }
+                       // total points are (by default) calculated like this:
+                       // speedrec = floor(100 / 10) = 10 points
+                       // 1st place = floor(100 / 1) = 100 points
+                       // 2nd place = floor(100 / 2) = 50 points
+                       // 3rd place = floor(100 / 3) = 33 points
+                       // 4th place = floor(100 / 4) = 25 points
+                       // 5th place = floor(100 / 5) = 20 points
+                       // ... etc
+                       if(i == 0)
+                           s = strcat(s, " ", ftos(stof(argv(LADDER_CNT+1)) + LADDER_FIRSTPOINT / 10)); // speed award, add LADDER_FIRSTPOINT / 10 points
+                       else
+                           s = strcat(s, " ", ftos(stof(argv(LADDER_CNT+1)) + floor(LADDER_FIRSTPOINT / i))); // record, add LADDER_FIRSTPOINT / i points
+                       db_put(TemporaryDB, strcat("ladder", myuid), s);
+               }
+       }
+     }
+     float thiscnt;
+     string thisuid;
+     for (i = 0; i <= uidcnt; ++i) // for each known uid
+     {
+       thisuid = db_get(TemporaryDB, strcat("uid", ftos(i)));
+       temp_s = db_get(TemporaryDB, strcat("ladder", thisuid));
+       tokenize_console(temp_s);
+         thiscnt = stof(argv(LADDER_CNT+1));
+       if(thiscnt > top_scores[LADDER_SIZE-1])
+       for (j = 0; j < LADDER_SIZE; ++j) // for each place in ladder
+       {
+           if(thiscnt > top_scores[j])
+           {
+               for (k = LADDER_SIZE-1; k >= j; --k)
+               {
+                   top_uids[k] = top_uids[k-1];
+                   top_scores[k] = top_scores[k-1];
+               }
+               top_uids[j] = thisuid;
+               top_scores[j] = thiscnt;
+               break;
+           }
+       }
+     }
+     s = "^3-----------------------\n\n";
+     s = strcat(s, "Pos ^3|");
+     s = strcat(s, " ^7Total  ^3|");
+     for (i = 1; i <= LADDER_CNT; ++i)
+     {
+       s = strcat(s, " ^7", race_placeName(i), " ^3|");
+     }
+     s = strcat(s, " ^7Speed awards ^3| ^7Name");
+     s = strcat(s, "\n^3----+--------");
+     for (i = 1; i <= min(9, LADDER_CNT); ++i)
+     {
+       s = strcat(s, "+-----");
+     }
+     if(LADDER_CNT > 9)
+           for (i = 1; i <= LADDER_CNT - 9; ++i)
+           {
+               s = strcat(s, "+------");
+           }
+     s = strcat(s, "+--------------+--------------------\n");
+     for (i = 0; i < LADDER_SIZE; ++i)
+     {
+       temp_s = db_get(TemporaryDB, strcat("ladder", top_uids[i]));
+       tokenize_console(temp_s);
+       if (argv(LADDER_CNT+1) == "") // total is 0, skip
+           continue;
+       s = strcat(s, strpad(4, race_placeName(i+1)), "^3| ^7"); // pos
+       s = strcat(s, strpad(7, argv(LADDER_CNT+1)), "^3| ^7"); // total
+       for (j = 1; j <= min(9, LADDER_CNT); ++j)
+       {
+           s = strcat(s, strpad(4, argv(j)), "^3| ^7"); // 1st, 2nd, 3rd etc cnt
+       }
+       if(LADDER_CNT > 9)
+               for (j = 10; j <= LADDER_CNT; ++j)
+               {
+                   s = strcat(s, strpad(4, argv(j)), " ^3| ^7"); // 1st, 2nd, 3rd etc cnt
+               }
+       s = strcat(s, strpad(13, argv(0)), "^3| ^7"); // speed award cnt
+       s = strcat(s, uid2name(top_uids[i]), "\n"); // name
+     }
+     MapInfo_ClearTemps();
+     if (s == "")
+       return "No ladder on this server!\n";
+     else
+         return strcat("Top ", ftos(LADDER_SIZE), " ladder rankings:\n", s);
+ }
  float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
  {
      float m, i;