]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into terencehill/itemstime
authorterencehill <piuntn@gmail.com>
Tue, 20 Jan 2015 16:51:44 +0000 (17:51 +0100)
committerterencehill <piuntn@gmail.com>
Tue, 20 Jan 2015 16:51:44 +0000 (17:51 +0100)
Conflicts:
_hud_descriptions.cfg
hud_luminos.cfg
hud_luminos_minimal.cfg
hud_luminos_minimal_xhair.cfg
hud_luminos_old.cfg
hud_nexuiz.cfg
qcsrc/client/hud.qc
qcsrc/client/hud.qh
qcsrc/client/waypointsprites.qc
qcsrc/common/constants.qh
qcsrc/common/util.qh
qcsrc/menu/classes.c
qcsrc/menu/xonotic/mainwindow.c
qcsrc/server/arena.qc
qcsrc/server/cl_client.qc
qcsrc/server/defs.qh
qcsrc/server/g_world.qc
qcsrc/server/t_items.qc

24 files changed:
1  2 
_hud_common.cfg
_hud_descriptions.cfg
defaultXonotic.cfg
hud_luminos.cfg
hud_luminos_minimal.cfg
hud_luminos_minimal_xhair.cfg
hud_luminos_old.cfg
hud_nexuiz.cfg
qcsrc/client/autocvars.qh
qcsrc/client/hud.qc
qcsrc/client/hud.qh
qcsrc/client/hud_config.qc
qcsrc/client/waypointsprites.qc
qcsrc/common/constants.qh
qcsrc/common/stats.qh
qcsrc/common/util.qh
qcsrc/menu/classes.c
qcsrc/menu/xonotic/mainwindow.c
qcsrc/server/cl_client.qc
qcsrc/server/command/vote.qc
qcsrc/server/defs.qh
qcsrc/server/g_world.qc
qcsrc/server/t_items.qc
qcsrc/server/waypointsprites.qc

diff --combined _hud_common.cfg
index 8ab874555db8fefd96507e533d2d6af86732a107,5aa1bbfeea3203469aedb2a4b248d08951d12617..1bdea1c34bf5192bf01b8351f6493b8ddc968689
@@@ -23,6 -23,7 +23,7 @@@ seta hud_colorset_background "7" "neutr
  seta hud_panel_weapons_ammo_full_shells 60 "show 100% of the status bar at this ammo count"
  seta hud_panel_weapons_ammo_full_nails 320 "show 100% of the status bar at this ammo count"
  seta hud_panel_weapons_ammo_full_cells 180 "show 100% of the status bar at this ammo count"
+ seta hud_panel_weapons_ammo_full_plasma 180 "show 100% of the status bar at this ammo count"
  seta hud_panel_weapons_ammo_full_rockets 160 "show 100% of the status bar at this ammo count"
  seta hud_panel_weapons_ammo_full_fuel 100 "show 100% of the status bar at this ammo count"
  
@@@ -37,8 -38,6 +38,8 @@@ seta hud_panel_engineinfo_framecounter_
  seta hud_panel_engineinfo_framecounter_exponentialmovingaverage_new_weight 0.1 "weight of latest data point"
  seta hud_panel_engineinfo_framecounter_exponentialmovingaverage_instantupdate_change_threshold 0.5 "threshold for fps change when to update instantly, to make big fps changes update faster"
  
 +seta hud_panel_itemstime_progressbar_maxtime "30" "when left time is at least this amount, the status bar is full"
 +
  // hud panel aliases
  alias hud_panel_radar_rotate "toggle hud_panel_radar_rotation 0 1 2 3 4"
  alias +hud_panel_radar_maximized "cl_cmd hud radar 1"
@@@ -46,6 -45,8 +47,8 @@@ alias -hud_panel_radar_maximized "cl_cm
  alias hud_panel_radar_maximized "cl_cmd hud radar"
  
  // other hud cvars
+ seta hud_panel_update_interval 2 "how often (in seconds) common panel cvars are reloaded"
  seta hud_showbinds 1  "what to show in the HUD to indicate certain keys to press: 0 display commands, 1 bound keys, 2 both"
  seta hud_showbinds_limit 2    "maximum number of bound keys to show for a command. 0 for unlimited"
  set _hud_showbinds_reload 0   "set it to 1 to reload binds if you changed any. It is reset to 0 automatically"
@@@ -81,7 -82,7 +84,7 @@@ seta hud_contents_fadeintime 0.02 "fact
  seta hud_contents_fadeouttime 0.1 "factor of time it takes for the alpha level to reach normal value when leaving the liquid"
  seta hud_contents_lava_alpha 0.7 "alpha of the lava"
  seta hud_contents_lava_color "0.8 0.1 0" "color blend when inside lava"
- seta hud_contents_slime_alpha 0.7 "alpha of the slime" 
+ seta hud_contents_slime_alpha 0.7 "alpha of the slime"
  seta hud_contents_slime_color "0 0.4 0.1" "color blend when inside slime"
  seta hud_contents_water_alpha 0.5 "alpha of the water"
  seta hud_contents_water_color "0.4 0.3 0.3" "color blend when inside water"
diff --combined _hud_descriptions.cfg
index 5b092524515d8282efea82af72451e43c1c2c4da,270bd2bd9294693bcbf787666f7b3b2d341e2141..5493eceda289effc2eb9e99f3721125822541378
@@@ -128,6 -128,7 +128,7 @@@ seta hud_panel_notify_flip "" "order th
  seta hud_panel_notify_fontsize "" "multiplier for the font size used for player names in the panel"
  seta hud_panel_notify_fadetime "" "fade out time"
  seta hud_panel_notify_time "" "time that a new entry stays until it fades out"
+ seta hud_panel_notify_icon_aspect "" "aspect ratio of total drawing area per icon"
  
  seta hud_panel_timer "" "enable/disable this panel"
  seta hud_panel_timer_pos "" "position of this base of the panel"
@@@ -167,7 -168,7 +168,7 @@@ seta hud_panel_score_bg_color_team "" "
  seta hud_panel_score_bg_alpha "" "if set to something else than \"\" = override default panel background alpha"
  seta hud_panel_score_bg_border "" "if set to something else than \"\" = override default size of border around the background"
  seta hud_panel_score_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
- seta hud_panel_score_rankings "" "show rankings: 1 always show my own score; 2 pure rankings" 
+ seta hud_panel_score_rankings "" "show rankings: 1 always show my own score; 2 pure rankings"
  
  seta hud_panel_racetimer "" "enable/disable this panel"
  seta hud_panel_racetimer_pos "" "position of this base of the panel"
@@@ -199,7 -200,9 +200,9 @@@ seta hud_panel_modicons_bg_color_team "
  seta hud_panel_modicons_bg_alpha "" "if set to something else than \"\" = override default panel background alpha"
  seta hud_panel_modicons_bg_border "" "if set to something else than \"\" = override default size of border around the background"
  seta hud_panel_modicons_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
+ seta hud_panel_modicons_ca_layout "" "2 possible layouts: 0) number of alive players; 1) icons and number of alive players"
  seta hud_panel_modicons_dom_layout "" "3 possible layouts: 0) only icons; 1) icons and percentage of average pps (points per second); 2) icons and average pps"
+ seta hud_panel_modicons_freezetag_layout "" "2 possible layouts: 0) number of alive players; 1) icons and number of alive players"
  
  seta hud_panel_pressedkeys "" "enable/disable this panel, 1 = show only when spectating other players, 2 = show always"
  seta hud_panel_pressedkeys_pos "" "position of this base of the panel"
@@@ -295,21 -298,12 +298,30 @@@ seta hud_panel_centerprint_fade_subsequ
  seta hud_panel_centerprint_fade_subsequent_minfontsize "" "minimum factor for the font size from the subsequent fading effects"
  seta hud_panel_centerprint_fade_minfontsize "" "minimum factor for the font size from the fading in/out effects"
  
+ seta hud_panel_buffs "" "enable/disable this panel"
+ seta hud_panel_buffs_pos "" "position of this panel"
+ seta hud_panel_buffs_size "" "size of this panel"
+ seta hud_panel_buffs_bg "" "if set to something else than \"\" = override default background"
+ seta hud_panel_buffs_bg_color "" "if set to something else than \"\" = override default panel background color"
+ seta hud_panel_buffs_bg_color_team "" "override panel color with team color in team based games"
+ seta hud_panel_buffs_bg_alpha "" "if set to something else than \"\" = override default panel background alpha"
+ seta hud_panel_buffs_bg_border "" "if set to something else than \"\" = override default size of border around the background"
+ seta hud_panel_buffs_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
++
 +seta hud_panel_itemstime "" "enable/disable this panel, it shows left time until important items (mega health, large armor, powerups, superweapons, etc...) respawn in the map: 1 when spectating, 2 even playing in warmup stage"
 +seta hud_panel_itemstime_pos "" "position of this base of the panel"
 +seta hud_panel_itemstime_size "" "size of this panel"
 +seta hud_panel_itemstime_bg "" "if set to something else than \"\" = override default background"
 +seta hud_panel_itemstime_bg_color "" "if set to something else than \"\" = override default panel background color"
 +seta hud_panel_itemstime_bg_color_team "" "override panel color with team color in team based games"
 +seta hud_panel_itemstime_bg_alpha "" "if set to something else than \"\" = override default panel background alpha"
 +seta hud_panel_itemstime_bg_border "" "if set to something else than \"\" = override default size of border around the background"
 +seta hud_panel_itemstime_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
 +seta hud_panel_itemstime_iconalign "" "0 = align icons to the left, 1 = align icons to the right"
 +seta hud_panel_itemstime_progressbar "" "use progressbar behind icons"
 +seta hud_panel_itemstime_progressbar_name "" "name of progressbar to use behind icons"
 +seta hud_panel_itemstime_progressbar_reduced "" "progressbar is displayed only in the text field"
 +seta hud_panel_itemstime_showspawned "" "show icons of already spawned items"
 +seta hud_panel_itemstime_text "" "show text"
 +seta hud_panel_itemstime_ratio "" "ratio between space reserved for text and icon width of each item entry (min value is 2)"
 +seta hud_panel_itemstime_size_dinamic "" "reduce panel size by removing spacing beetwen items"
diff --combined defaultXonotic.cfg
index c68b26936e164030b311d737a69167d4a754af7c,df7044ce562a41c915e9d59d7dc9d7ba5996b683..142d5f83d3762221fddafd6c982f45b8ae1e8963
@@@ -10,7 -10,7 +10,7 @@@
  // e.g. Xonotic 1.5.1 RC1 will be 15101
  set g_xonoticversion git "Xonotic version (formatted for humans)"
  
- gameversion 600 // 0.6.0
+ gameversion 800 // 0.8.0
  gameversion_min 0 // git builds see all versions
  gameversion_max 65535 // git builds see all versions
  
@@@ -34,31 -34,34 +34,34 @@@ seta g_configversion 0     "Configuration f
  // other aliases
  alias +hook +button6
  alias -hook -button6
+ alias +jetpack +button10
+ alias -jetpack -button10
  alias use "impulse 21"
  
  // for backwards compatibility
+ // TODO Remove after 0.8 release!
+ cl_particles_forcetraileffects 1
  
  alias dropweapon "impulse 17"
  alias +show_info +button7
  alias -show_info -button7
  
- bind f6 team_auto
  // merge lightmaps up to 2048x2048 textures
  mod_q3bsp_lightmapmergepower 4
  
  // player defaults
  _cl_color "112.211" // same effect as 112, but menuqc can detect this as the default and not intentionally set
- _cl_name Player
+ _cl_name ""
  _cl_playermodel models/player/erebus.iqm
  _cl_playerskin 0
  
  seta cl_reticle 1 "control for toggling whether ANY zoom reticles are shown"
- seta cl_reticle_stretch 0 "whether to stretch reticles so they fit the screen (brakes image proportions)"
- seta cl_reticle_item_nex 1 "draw aiming reticle for the nex weapon's zoom, 0 disables and values between 0 and 1 change alpha"
+ seta cl_reticle_stretch 0 "whether to stretch reticles so they fit the screen (breaks image proportions)"
+ seta cl_reticle_item_vortex 1 "draw aiming reticle for the vortex weapon's zoom, 0 disables and values between 0 and 1 change alpha"
  seta cl_reticle_item_normal 1 "draw reticle when zooming with the zoom button, 0 disables and values between 0 and 1 change alpha"
- fov 90
- seta cl_velocityzoom 0        "velocity based zooming of fov, negative values zoom out"
+ fov 100
+ seta cl_velocityzoom_enabled 0 "velocity based zooming of fov"
+ seta cl_velocityzoom_factor 0 "factor of fov zooming (negative values zoom out)"
  seta cl_velocityzoom_type 3 "how to factor in speed, 1 = all velocity in all directions, 2 = velocity only in forward direction (can be negative), 3 = velocity only in forward direction (limited to forward only)"
  seta cl_velocityzoom_speed 1000 "target speed for fov factoring"
  seta cl_velocityzoom_time 0.2 "time value for averaging speed values"
@@@ -74,6 -77,11 +77,11 @@@ seta cl_unpress_zoom_on_death 1 "automa
  seta cl_unpress_zoom_on_weapon_switch 1 "automatically unpress zoom when you switch a weapon"
  seta cl_unpress_attack_on_weapon_switch 1 "automatically unpress fire and fire1 attack buttons when you switch a weapon"
  
+ seta cl_spawn_event_particles 1 "pointparticles effect whenever a player spawns"
+ seta cl_spawn_event_sound 1 "sound effect whenever a player spawns"
+ //seta cl_spawn_point_model 0 "place a model at all spawn points" // still needs a model
+ seta cl_spawn_point_particles 1 "pointparticles effect at all spawn points" // managed by effects-.cfg files
  freelook 1
  sensitivity 6
  v_gamma 1
@@@ -86,12 -94,16 +94,16 @@@ vid_fullscreen 
  vid_width 1024
  vid_height 768
  vid_pixelheight 1
+ vid_resizable 0 // cannot be turned on before it is sure it cannot cause a r_restart
+ vid_desktopfullscreen 1
  prvm_language en
  set _menu_prvm_language ""
  set _menu_vid_width "$vid_width"
  set _menu_vid_height "$vid_height"
  set _menu_vid_pixelheight "$vid_pixelheight"
+ set _menu_vid_desktopfullscreen "$vid_desktopfullscreen"
  seta menu_vid_scale 0
+ seta menu_vid_allowdualscreenresolution 0
  // 2D resolution 800x600
  vid_conwidth 800
  vid_conheight 600
@@@ -102,6 -114,36 +114,36 @@@ v_deathtilt 0 // needed for spectators 
  exec sRGB-disable.cfg
  vid_sRGB_fallback 2
  r_hdr_glowintensity 1
+ // #define Image_LinearFloatFromsRGBFloat(c) (((c) <= 0.04045f) ? (c) * (1.0f / 12.92f) : (float)pow(((c) + 0.055f)*(1.0f/1.055f), 2.4f))
+ set rpn_sRGB_to_linear "dup 0.055 add 1.055 div 2.4 pow exch 12.92 div dup 0.0031308 gt when"
+ // #define Image_sRGBFloatFromLinearFloat(c) (((c) < 0.0031308f) ? (c) * 12.92f : 1.055f * (float)pow((c), 1.0f/2.4f) - 0.055f)
+ set rpn_linear_to_sRGB "dup 1.0 2.4 div pow 1.055 mul 0.055 sub exch 12.92 mul dup 0.04045 ge when"
+ // -nosRGB to -sRGB sky shader conversion:
+ //
+ // q3map_sunExt 1 0.6875 0.375 340 25 47 0 16
+ //                                    ^^ elevation
+ //                             ^^^ sunlight
+ // q3map_skylight 110 3
+ //                ^^^ skylight
+ //
+ // With that, do (the last parameter is the ratio of skylight you assume hits
+ // the surfaces, about 0.25 for inner surfaces near sky, about 1.00 on
+ // terrain):
+ // ]skybox_nosRGB_to_sRGB 340 47 110 0.25
+ // rpn: still on stack: new_sunlight:
+ // rpn: still on stack: 380.464142
+ // rpn: still on stack: new_skylight:
+ // rpn: still on stack: 9.32523632
+ //
+ // The equivalent -sRGB shader then will have:
+ //
+ // q3map_sunExt 1 0.6875 0.375 380.464142 25 47 0 16
+ // q3map_skylight 9.32523632 3
+ alias skybox_nosRGB_to_sRGB "rpn $3 402.123 $4 div div $rpn_sRGB_to_linear 402.123 $4 div mul /new_skylight: $3 402.123 $4 div div $1 256 div $2 0.017453 mul sin mul add $rpn_sRGB_to_linear $3 402.123 $4 div div $rpn_sRGB_to_linear sub 256 mul $2 0.017453 mul sin div /new_sunlight:"
+ set cl_orthoview 0 "enable top-down view of the map- meant to be used for radar map images (note: orthoview sets cvars temporarily, requires restart to return them to normal)"
+ set cl_orthoview_nofog 1 "disable fog while in orthoview-- note, should not be enabled on ALL maps, i.e. oilrig works fine with this disabled"
  
  // these settings determine how much the view is affected by movement/damage
  cl_smoothviewheight 0.05 // time of the averaging to the viewheight value so that it creates a smooth transition for crouching and such. 0 for instant transition
@@@ -179,10 -221,14 +221,14 @@@ set sv_ready_restart 0 "if set to 1 all
  set sv_ready_restart_after_countdown 0        "if set to 1 the players and map items are reset after the countdown ended, otherwise they're reset already at the beginning of the countdown"
  set sv_ready_restart_repeatable 0     "allows the players to restart the game as often as needed"
  
- seta cl_hitsound 1 "play a hit notifier sound when you have hit an enemy"
+ seta cl_hitsound 1 "play a hit notifier sound when you have hit an enemy, 1: same pitch 2: increase pitch with more damage 3: decrease pitch with more damage"
  set cl_hitsound_antispam_time 0.05 "don't play the hitsound more often than this"
+ seta cl_hitsound_min_pitch 0.75 "minimum pitch of hit sound"
+ seta cl_hitsound_max_pitch 1.5 "maximum pitch of hit sound"
+ seta cl_hitsound_nom_damage 25 "damage amount at which hitsound bases pitch off"
  
- seta cl_eventchase_death 1 "camera goes into 3rd person mode when the player is dead"
+ seta cl_eventchase_death 1 "camera goes into 3rd person mode when the player is dead; set to 2 to active the effect only when the corpse doesn't move anymore"
+ seta cl_eventchase_nexball 1 "camera goes into 3rd person mode when in nexball game-mode"
  seta cl_eventchase_distance 140 "final camera distance"
  seta cl_eventchase_speed 1.3 "how fast the camera slides back, 0 is instant"
  seta cl_eventchase_maxs "12 12 8" "max size of eventchase camera bbox"
@@@ -199,7 -245,7 +245,7 @@@ set g_maxplayers_spectator_blocktime 5     
  set g_warmup 0        "split the game into a warmup- and match-stage when set to 1"
  set g_warmup_limit 0  "if set to -1 the warmup-stage is not affected by any timelimit, if set to 0 the usual timelimit also affects warmup-stage, otherwise warmup will be limited to this time in SECONDS (useful for public matches)"
  set g_warmup_allow_timeout 0  "if set to 1 timeouts can also be called in the warmup-stage, when sv_timeout is set to 1"
- set g_warmup_allguns 1        "if set players start with all guns in warmup mode"
+ set g_warmup_allguns 1        "provide more weapons on start while in warmup: 0 = normal start weapons, 1 = all guns available on the map, 2 = all normal weapons"
  set g_warmup_majority_factor 0.8 "minimum percentage of players ready needed for warmup to end"
  
  set g_chat_nospectators 0     "if 0 spec/observer chat is always visible to the player, if 1 it is never visible to players, if 2 it is only visible to players during warmup stage"
@@@ -215,8 -261,8 +261,8 @@@ set sv_timeout_number 2    "how many timeo
  set sv_timeout_leadtime 4     "how long the players will be informed that a timeout was called before it starts, in seconds"
  set sv_timeout_resumetime 3   "how long the remaining timeout-time will be after a player called the timein command"
  
- set g_allow_oldnexbeam 0 "If enabled, clients are allowed to use old v2.3 Nexgun beam"
- seta cl_particles_oldnexbeam 0 "Uses the old v2.3 Nexgun beam instead of the new beam, only works if server allows it (g_allow_oldnexbeam 1)"
+ set g_allow_oldvortexbeam 0 "If enabled, clients are allowed to use old v2.3 Vortex beam"
+ seta cl_particles_oldvortexbeam 0 "Uses the old v2.3 Vortex beam instead of the new beam, only works if server allows it (g_allow_oldvortexbeam 1)"
  
  set g_telefrags 1 "telefragging, i.e. killing someone who stands in the way of someone who is teleporting"
  set g_telefrags_teamplay 1 "never telefrag team mates"
@@@ -238,7 -284,7 +284,7 @@@ set cl_deathglow 0.8 "number of second
  
  set sv_gibhealth 100 "Minus health a dead body must have in order to get gibbed"
  
- // fragmessage: This allows extra information to be displayed with the frag centerprints. 
+ // fragmessage: This allows extra information to be displayed with the frag centerprints.
  set sv_fraginfo 1 "Enable extra frag message information, 0 = Never display, 1 = Display only in warmup mode; 2 = Always display"
  set sv_fraginfo_ping 1 "Enable ping display information, 0 = Never display, 1 = Always display (If the player is a bot, it will say bot instead of the ping.)"
  set sv_fraginfo_handicap 1 "Enable handicap display information, 0 = Never display, 1 = Only when the player has handicap on, 2 = Always display (Displays Off if disabled)"
@@@ -277,7 -323,7 +323,7 @@@ seta sv_defaultplayermodel_pink "" "\"\
  seta sv_defaultplayerskin_pink 0
  seta sv_defaultplayercolors ""        "set to 16*shirt+pants to force a color, note: it does NOT depend on defaultcharacter! Set to \"\" to disable"
  set sv_autoscreenshot 0 "if set to 1, the server forces all clients to create a local screenshot once the map ended"
- net_messagetimeout 300
+ net_messagetimeout 30
  net_connecttimeout 30
  sv_jumpstep 1 // step up stairs while jumping, makes it easier to reach ledges
  set ekg 0     "Throw huge amounts of gibs"
@@@ -318,9 -364,9 +364,9 @@@ set bot_ai_keyboard_threshold 0.5
  set bot_ai_aimskill_offset 0.3 "Amount of error induced to the bots aim"
  set bot_ai_aimskill_think 1 "Aiming velocity. Use values below 1 for slower aiming"
  set bot_ai_custom_weapon_priority_distances "300 850" "Define close and far distances in any order. Based on the distance to the enemy bots will choose different weapons"
- set bot_ai_custom_weapon_priority_far   "minstanex nex rifle electro rocketlauncher grenadelauncher hagar hlac crylink laser uzi fireball seeker shotgun tuba minelayer"      "Desired weapons for far distances ordered by priority"
- set bot_ai_custom_weapon_priority_mid   "minstanex rocketlauncher nex fireball seeker grenadelauncher electro uzi crylink hlac hagar shotgun laser rifle tuba minelayer"      "Desired weapons for middle distances ordered by priority"
- set bot_ai_custom_weapon_priority_close "minstanex shotgun nex uzi hlac tuba seeker hagar crylink grenadelauncher electro rocketlauncher laser fireball rifle minelayer"      "Desired weapons for close distances ordered by priority"
+ set bot_ai_custom_weapon_priority_far   "vaporizer vortex rifle electro devastator mortar hagar hlac crylink blaster machinegun fireball seeker shotgun tuba minelayer"       "Desired weapons for far distances ordered by priority"
+ set bot_ai_custom_weapon_priority_mid   "vaporizer devastator vortex fireball seeker mortar electro machinegun crylink hlac hagar shotgun blaster rifle tuba minelayer arc shockwave" "Desired weapons for middle distances ordered by priority"
+ set bot_ai_custom_weapon_priority_close "vaporizer shotgun vortex machinegun hlac tuba seeker hagar crylink mortar electro devastator blaster fireball rifle minelayer arc shockwave" "Desired weapons for close distances ordered by priority"
  set bot_ai_weapon_combo 1     "Enable bots to do weapon combos"
  set bot_ai_weapon_combo_threshold 0.4 "Try to make a combo N seconds after the last attack"
  set bot_ai_friends_aware_pickup_radius "500"  "Bots will not pickup items if a team mate is this distance near the item"
@@@ -362,7 -408,6 +408,6 @@@ pausable 
  set g_spawnshieldtime 1 "number of seconds you are invincible after you spawned, this shield is lost after you fire"
  set 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)"
  set g_shootfromclient 2 "let client decide if it has the gun left or right; if set to 2, center handedness is allowed; see also cl_gunalign"
  set g_shootfromeye 0 "shots are fired from your eye/crosshair; visual gun position can still be influenced by cl_gunalign 1 and 2"
  set g_shootfromcenter 0 "weapon gets moved to the center, shots still come from the barrel of your weapon; visual gun position can still be influenced by cl_gunalign 1 and 2"
@@@ -373,19 -418,9 +418,9 @@@ set g_weapon_throwable 1 "if set to 1, 
  set g_powerups -1 "if set to 0 the strength and shield (invincibility) will not spawn on the map, if 1 they will spawn in all game modes, -1 is game mode default"
  set g_use_ammunition 1 "if set to 0 all weapons have unlimited ammunition"
  set g_pickup_items -1 "if set to 0 all items (health, armor, ammo, weapons...) are removed from the map, if 1 they are forced to spawn"
- set g_minstagib 0     "enable minstagib"
- set g_minstagib_extralives 2  "how many extra lives you will get per powerup"
- set g_minstagib_ammo_start 10 "starting ammo"
- set g_minstagib_ammo_drop 5   "how much ammo you'll get for weapons or cells"
- set g_minstagib_invis_alpha 0.15
- set g_minstagib_speed_highspeed 1.5 "speed-multiplier that applies while you carry the invincibility powerup"
- set g_vampire 0 "set to 1 to enable the vampire mode, where the damage done to your opponent gets added to your own health"
  set g_weaponarena "0" "put in a list of weapons to enable a weapon arena mode, or try \"all\" or \"most\""
  set g_weaponarena_random "0"  "if set to a number, only that weapon count is given on every spawn (randomly)"
- set g_weaponarena_random_with_laser "1"       "additionally, always provide the laser in random weapon arena games"
- set g_midair 0 "if set to 1 you can only apply damage to your opponent while he is airborne"
- set g_midair_shieldtime 0.3 "number of seconds you are still invincible since you lost contact to the ground"
- set g_spawnsound 1 "set to 0 if you don't want to hear the spawn sound when a player spawns"
+ set g_weaponarena_random_with_blaster "1"     "additionally, always provide the blaster in random weapon arena games"
  set g_spawnpoints_auto_move_out_of_solid 0 "if set to 1 you will see a warning if a spawn point was placed inside a solid"
  set g_forced_respawn 0 "if set to 1 and a player died, that player gets automatically respawned once <g_respawn_delay> seconds are over"
  set g_fullbrightplayers 0 "brightens up player models (note that the color, skin or model of the players does not change!)"
@@@ -410,23 -445,6 +445,6 @@@ set g_player_alpha 
  set g_player_brightness 0     "set to 2 for brighter players"
  seta g_balance_cloaked_alpha 0.25
  
- set g_sandbox 0 "allow players to spawn and edit objects around the map"
- set g_sandbox_info 1 "print object information to the server. 1 prints info about spawned / removed objects, 2 also prints info about edited objects"
- set g_sandbox_readonly 0 "when this mode is active, players cannot modify objects or use any sandbox commands"
- set g_sandbox_storage_name default "name of the selected storage to use"
- set g_sandbox_storage_autosave 5 "storage is automatically saved every specified number of seconds"
- set g_sandbox_storage_autoload 1 "if a storage file exists for the given map, automatically load it at startup"
- set g_sandbox_editor_flood 1 "players must wait this many seconds between spawning objects"
- set g_sandbox_editor_maxobjects 1000 "maximum number of objects that may exist at a time"
- set g_sandbox_editor_free 1 "0 = players can only copy or edit their own objects, 1 = players can copy but not edit other objects, 2 = players can copy and edit all object"
- set g_sandbox_editor_distance_spawn 200 "distance at which objects spawn in front of the player"
- set g_sandbox_editor_distance_edit 300 "distance at which players can edit or remove objects they are looking at"
- set g_sandbox_object_scale_min 0.1 "minimum scale that objects can be set to"
- set g_sandbox_object_scale_max 2 "maximum scale that objects can be set to"
- set g_sandbox_object_material_velocity_min 100 "velocity objects must have while colliding for material effects to be applied"
- set g_sandbox_object_material_velocity_factor 0.002 "velocity range which decides the intensity of material effects"
- set cl_sandbox_clipboard ""
  seta menu_sandbox_spawn_model ""
  seta menu_sandbox_attach_bone ""
  seta menu_sandbox_edit_skin 0
@@@ -440,36 -458,24 +458,24 @@@ seta menu_sandbox_edit_physics 
  seta menu_sandbox_edit_force 1
  seta menu_sandbox_edit_material ""
  
- bind f7 menu_showsandboxtools
+ seta menu_monsters_edit_spawn ""
+ seta menu_monsters_edit_skin 0
+ seta menu_monsters_edit_movetarget 1
  
  set g_playerclip_collisions 1 "0 = disable collision testing against playerclips, might be useful on some defrag maps"
  set g_botclip_collisions 1 "0 = disable collision testing against botclips, might be useful on some defrag maps"
  
- set welcome_message_time 8
  set g_grappling_hook 0 "let players spawn with the grappling hook which allows them to pull themselves up"
  
- set g_invincible_projectiles 0 "set to 1 to disable any damage to projectiles in all balance configs, regardless of g_projectiles_damage"
- set g_dodging 0 "set to 1 to enable dodging in games"
- set g_rocket_flying 0 "set to 1 to enable rocket flying in all balance configs"
- seta cl_dodging_timeout 0.2 "determines how long apart (in seconds) two taps on the same direction key are considered a dodge. use 0 to disable"
- set sv_dodging_wall_dodging 0 "set to 1 to allow dodging off walls. 0 to disable"
- set sv_dodging_delay 0.5 "determines how long a player has to wait to be able to dodge again after dodging"
- set sv_dodging_up_speed 200 "the jump velocity of the dodge"
- set sv_dodging_horiz_speed 400 "the horizontal velocity of the dodge"
- set sv_dodging_ramp_time 0.1 "a ramp so that the horizontal part of the dodge is added smoothly (seconds)"
- set sv_dodging_height_threshold 10 "the maximum height above ground where to allow dodging"
- set sv_dodging_wall_distance_threshold 10 "the maximum distance from a wall that still allows dodging"
- set sv_dodging_sound 1 "if 1 dodging makes a sound. if 0 dodging is silent"
+ set g_spawn_alloweffects 1 "allow clients to enable spawn point and event effects such as particles and sounds, see cl_spawn_ cvars for more info"
  set g_spawn_furthest 0.5 "this amount of the spawns shall be far away from any players"
  set g_spawn_useallspawns 0 "use all spawns, e.g. also team spawns in non-teamplay, and all spawns, even enemy spawns, in teamplay"
- set g_spawn_near_teammate 0 "if set, players prefer spawns near a team mate"
- set g_spawn_near_teammate_distance 640 "max distance to consider a spawn to be near a team mate"
  // respawn delay
- set g_respawn_delay 2 "number of seconds you have to wait before you can respawn again"
+ set g_respawn_delay_small 2 "small game number of seconds you have to wait before you can respawn again"
+ set g_respawn_delay_small_count 0 "Player count per team for g_respawn_delay_small. <=0 values mean the minimum amount of players to have gameplay (typically 2 in FFA, 1 in teamplay)."
+ set g_respawn_delay_large 2 "large game number of seconds you have to wait before you can respawn again"
+ set g_respawn_delay_large_count 8 "Player count per team for g_respawn_delay_large. <=0 values mean the minimum amount of players to have gameplay (typically 2 in FFA, 1 in teamplay)."
+ set g_respawn_delay_max 0 "number of seconds you can wait before you're forced to respawn (only effective with g_forced_respawn 1)"
  set g_respawn_waves 0 "respawn in waves (every n seconds), intended to decrease overwhelming base attacks"
  
  // overtime
@@@ -481,7 -487,7 +487,7 @@@ seta timelimit_suddendeath 5 "number o
  set g_tdm 0 "Team Deathmatch: the team who kills their opponents most often wins"
  set g_tdm_on_dm_maps 0 "when this is set, all DM maps automatically support TDM"
  
- seta teamplay_mode 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 teamplay_mode 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 cvars g_mirrordamage*, g_friendlyfire* and g_teamdamage_threshold*"
  seta g_mirrordamage 0.700000  "for teamplay 4: mirror damage factor"
  seta g_mirrordamage_virtual 1 "for teamplay 4: do not actually apply mirror damage, just show graphics effect for it"
  seta g_friendlyfire 0.500000  "for teamplay 4: fiendly fire factor"
@@@ -502,8 -508,6 +508,6 @@@ set g_bloodloss 0   "amount of health b
  
  set g_footsteps 1     "serverside footstep sounds"
  
- set g_deathglow 1.25 "when enabled, players stop glowing after they die (the value specifies glow fading speed)"
  set g_multijump 0     "Number of multiple jumps to allow (jumping again in the air), -1 allows for infinite jumps"
  set g_multijump_add 0 "0 = make the current z velocity equal to jumpvelocity, 1 = add jumpvelocity to the current z velocity"
  set g_multijump_speed -999999 "Minimum vertical speed a player must have in order to jump again"
@@@ -538,12 -542,12 +542,12 @@@ r_mipsprites 
  r_mipskins 1
  r_shadow_realtime_world_lightmaps 1
  cl_decals_fadetime 5
- cl_decals_time 2
+ cl_decals_time 1
  seta cl_gunalign 3 "Gun alignment; 1 = center (if allowed by g_shootfromclient) or right, 2 = center (if allowed by g_shootfromclient) or left, 3 = right only, 4 = left only"
  seta cl_nogibs 0 "reduce number of violence effects, or remove them totally"
  seta cl_particlegibs 0 "simpler gibs"
  seta cl_gibs_damageforcescale 3.5 "force to push around gibs"
- seta cl_gibs_lifetime 5 "average lifetime of gibs"
+ seta cl_gibs_lifetime 2.5 "average lifetime of gibs"
  seta cl_gibs_velocity_scale 1 "gib throw velocity force scale"
  seta cl_gibs_velocity_random 1 "gib throw velocity randomness scale"
  seta cl_gibs_velocity_up 1 "extra z velocity for gibs"
@@@ -555,12 -559,13 +559,13 @@@ seta cl_casings_shell_time 30 "shell ca
  seta cl_casings_bronze_time 10 "bullet casings lifetime"
  seta cl_casings_ticrate 0.1 "ticrate for casings"
  seta cl_casings_sloppy 1 "sloppy casings, may temporarily penetrate walls"
- seta cl_projectiles_sloppy 0 "sloppy projectiles, may temporarily penetrate walls"
+ seta cl_projectiles_sloppy 1 "sloppy projectiles, may temporarily penetrate walls"
  cl_stainmaps 0
  cl_particles_smoke 1
  vid_gl20 1
  r_glsl_deluxemapping 1
  r_glsl_offsetmapping 0
+ r_glsl_offsetmapping_lod 1
  r_glsl_offsetmapping_reliefmapping 0
  r_glsl_offsetmapping_scale 0.02
  // execute effects-normal.cfg to make sure that all effect settings are reset
@@@ -621,19 -626,6 +626,6 @@@ alias togglezoom "${_togglezoom}zoom
  
  alias reload "impulse 20"
  
- // movement
- bind w +forward
- bind a +moveleft
- bind s +back
- bind d +moveright
- bind UPARROW +forward
- bind LEFTARROW +moveleft
- bind DOWNARROW +back
- bind RIGHTARROW +moveright
- bind SHIFT +crouch
- bind ENTER +jump
- bind SPACE +jump
  // weapons
  alias weapon_group_1 "impulse 1"
  alias weapon_group_2 "impulse 2"
@@@ -646,109 -638,6 +638,6 @@@ alias weapon_group_8 "impulse 8
  alias weapon_group_9 "impulse 9"
  alias weapon_group_0 "impulse 14" // cycles the superweapons
  exec weapons.cfg
- bind 0 weapon_group_0
- bind 1 weapon_group_1
- bind 2 weapon_group_2
- bind 3 weapon_group_3
- bind 4 weapon_group_4
- bind 5 weapon_group_5
- bind 6 weapon_group_6
- bind 7 weapon_group_7
- bind 8 weapon_group_8
- bind 9 weapon_group_9
- bind q weaplast
- bind MOUSE1 +fire
- bind MOUSE2 +fire2
- bind MOUSE3 togglezoom
- bind MOUSE4 weaplast
- bind MOUSE5 +hook
- bind MWHEELUP weapnext
- bind MWHEELDOWN weapprev
- bind r reload
- bind BACKSPACE dropweapon
- bind g dropweapon
- bind f +use
- bind v +button8 // drag object
- // misc
- bind e +hook
- bind ` toggleconsole
- bind ~ toggleconsole
- bind TAB +showscores
- bind ESCAPE togglemenu
- bind t messagemode
- bind y messagemode2
- bind z messagemode2
- bind u "+con_chat_maximize"
- bind m +hud_panel_radar_maximized
- bind i +show_info
- bind PAUSE pause
- bind F10 menu_showquitdialog
- bind F11 disconnect
- bind F12 screenshot
- bind F4 ready
- bind ALT +showaccuracy
- // Gamepad defaults. Tested with Logitech Rumblepad 2, I hope similar ones works as well.
- bind JOY1 "+crouch"
- bind JOY2 "+jump"
- bind JOY3 "weapprev"
- bind JOY4 "weapnext"
- bind JOY5 "+fire2"
- bind JOY6 "+fire"
- bind JOY7 "+zoom"
- bind JOY8 "dropweapon"
- bind JOY9 "menu_showteamselect"
- bind JOY10 "+show_info"
- bind JOY11 "+showscores"
- bind JOY12 "+con_chat_maximize"
- seta joyadvanced "1"
- seta joyadvaxisr "2"
- seta joyadvaxisx "3"
- seta joyadvaxisy "1"
- seta joyadvaxisz "4"
- seta joysidesensitivity "1.0"
- seta joypitchsensitivity "0.9"
- seta joyyawsensitivity "-1.8"
- // SDL only
- seta joy_deadzoneforward "0.05"
- seta joy_deadzonepitch "0.05"
- seta joy_deadzoneside "0.05"
- seta joy_deadzoneup "0.05"
- seta joy_deadzoneyaw "0.05"
- seta joy_sensitivitypitch "0.9"
- seta joy_sensitivityyaw "-1.8"
- // team say
- bind kp_ins messagemode
- bind kp_del messagemode2
- bind kp_end "+userbind 1"
- bind kp_downarrow "+userbind 2"
- bind kp_pgdn "+userbind 3"
- bind kp_leftarrow "+userbind 4"
- bind kp_5 "+userbind 6"
- bind kp_rightarrow "+userbind 7"
- bind kp_home "+userbind 9"
- bind kp_uparrow "+userbind 10"
- bind kp_pgup "+userbind 11"
- bind kp_multiply "+userbind 12"
- bind kp_slash "+userbind 13"
- bind kp_enter "+userbind 16"
- bind kp_plus "+userbind 17"
- bind kp_minus "+userbind 18"
- bind F1 vyes
- bind F2 vno
- //used for spectate/observer mode
- bind F3 spec
- // NIX (No Items Xonotic) - at each time, everyone uses the same weapon,
- // and in regular intervals, this weapon is cycled
- set g_nix 0 "No Items Xonotic - instead of pickup items, everyone plays with the same weapon. After some time, a countdown will start, after which everyone will switch to another weapon, and so on"
- set g_nix_with_laser 0 "always carry the laser as an additional weapon in NIX"
- set g_nix_with_healtharmor 0 "when 1, health and armor still show up in NIX"
- set g_nix_with_powerups 0 "when 1, powerups still show up in NIX"
  
  // score log
  set sv_logscores_console 0    "print scores to server console"
@@@ -813,6 -702,12 +702,12 @@@ seta g_maplist_votable_nodetail 1        "node
  seta g_maplist_votable_abstain 0      "when 1, you can abstain from your vote"
  seta g_maplist_votable_screenshot_dir "maps levelshots"       "where to look for map screenshots"
  
+ set sv_vote_gametype 0 "show a vote screen for gametypes before map vote screen"
+ set sv_vote_gametype_keeptwotime 10 "show only 2 options for this amount of time during gametype vote screen"
+ set sv_vote_gametype_options "dm ctf ca lms tdm ft"
+ set sv_vote_gametype_timeout 20
+ set sv_vote_gametype_default_current 1 "Keep the current gametype if no one votes"
  set g_chat_flood_spl 3        "normal chat: seconds between lines to not count as flooding"
  set g_chat_flood_lmax 2       "normal chat: maximum number of lines per chat message at once"
  set g_chat_flood_burst 2      "normal chat: allow bursts of so many chat lines"
@@@ -857,7 -752,6 +752,7 @@@ seta g_waypointsprite_crosshairfadedist
  seta g_waypointsprite_distancefadealpha 1 "alpha multiplier near distance"
  seta g_waypointsprite_distancefadescale 0.7 "scale multiplier near the distance"
  seta g_waypointsprite_distancefadedistancemultiplier 0.5 "distance in map sizes from distance where to stop fading"
 +seta g_waypointsprite_itemstime 2 "show waypoints to indicate that some important items (mega health, large armor) are about to respawn: 1 when spectating, 2 even playing in warmup stage"
  set g_waypointsprite_spam 0 "Debugging feature. Set to 10 and load courtfun in race mode to test."
  alias "g_waypointsprite_personal"     "impulse 30"
  alias "g_waypointsprite_personal_p"   "impulse 31"
@@@ -889,43 -783,7 +784,7 @@@ set g_banned_list_idmode "1"      "when set
  
  r_labelsprites_scale 0.40625 // labels sprites get displayed at 0.5x from 640x480 to 1280x1024, and at 1x from 1600x1200 onwards
  
- // usercommands. These can be edited and bound by the menu.
- seta "userbind1_press" "say_team quad soon";  seta "userbind1_release" "";  seta "userbind1_description" "team: quad soon"
- seta "userbind2_press" "say_team free item %x^7 (l:%y^7); g_waypointsprite_team_here_p";  seta "userbind2_release" "";  seta "userbind2_description" "team: free item, icon"
- seta "userbind3_press" "say_team took item (l:%l^7); g_waypointsprite_team_here";  seta "userbind3_release" "";  seta "userbind3_description" "team: took item, icon"
- seta "userbind4_press" "say_team negative";  seta "userbind4_release" "";  seta "userbind4_description" "team: negative"
- seta "userbind5_press" "say_team positive";  seta "userbind5_release" "";  seta "userbind5_description" "team: positive"
- seta "userbind6_press" "say_team need help (l:%l^7) (h:%h^7 a:%a^7 w:%w^7); g_waypointsprite_team_helpme; cmd voice needhelp";  seta "userbind6_release" "";  seta "userbind6_description" "team: need help, icon"
- seta "userbind7_press" "say_team enemy seen (l:%y^7); g_waypointsprite_team_danger_p; cmd voice incoming";  seta "userbind7_release" "";  seta "userbind7_description" "team: enemy seen, icon"
- seta "userbind8_press" "say_team flag seen (l:%y^7); g_waypointsprite_team_here_p; cmd voice seenflag";  seta "userbind8_release" "";  seta "userbind8_description" "team: flag seen, icon"
- seta "userbind9_press" "say_team defending (l:%l^7) (h:%h^7 a:%a^7 w:%w^7); g_waypointsprite_team_here";  seta "userbind9_release" "";  seta "userbind9_description" "team: defending, icon"
- seta "userbind10_press" "say_team roaming (l:%l^7) (h:%h^7 a:%a^7 w:%w^7); g_waypointsprite_team_here";  seta "userbind10_release" "";  seta "userbind10_description" "team: roaming, icon"
- seta "userbind11_press" "say_team attacking (l:%l^7) (h:%h^7 a:%a^7 w:%w^7); g_waypointsprite_team_here";  seta "userbind11_release" "";  seta "userbind11_description" "team: attacking, icon"
- seta "userbind12_press" "say_team killed flagcarrier (l:%y^7); g_waypointsprite_team_p"; seta "userbind12_release" ""; seta "userbind12_description" "team: killed flag, icon"
- seta "userbind13_press" "say_team dropped flag (l:%d^7); g_waypointsprite_team_here_d"; seta "userbind13_release" ""; seta "userbind13_description" "team: dropped flag, icon"
- seta "userbind14_press" "say_team dropped gun %w^7 (l:%l^7); g_waypointsprite_team_here; wait; dropweapon"; seta "userbind14_release" ""; seta "userbind14_description" "team: drop gun, icon"
- // TODO change this to "use" once we can
- seta "userbind15_press" "say_team dropped flag/key %w^7 (l:%l^7); g_waypointsprite_team_here; wait; +use"; seta "userbind15_release" "-use"; seta "userbind15_description" "team: drop flag/key, icon"
- seta "userbind16_press" "say :-) / nice one"; seta "userbind16_release" ""; seta "userbind16_description" "chat: nice one"
- seta "userbind17_press" "say good game"; seta "userbind17_release" ""; seta "userbind17_description" "chat: good game"
- seta "userbind18_press" "say hi / good luck and have fun"; seta "userbind18_release" ""; seta "userbind18_description" "chat: hi / good luck"
- seta "userbind19_press" "+showscores; +con_chat_maximize"; seta "userbind19_release" "-showscores; -con_chat_maximize"; seta "userbind19_description" "scoreboard / chat history"
- seta "userbind20_press" "toggle cl_capturevideo"; seta "userbind20_release" ""; seta "userbind20_description" "toggle recording .avi"
- seta "userbind21_press" "toggle vid_fullscreen; vid_restart"; seta "userbind21_release" ""; seta "userbind21_description" "toggle fullscreen"
- seta "userbind22_press" ""; seta "userbind22_release" ""; seta "userbind22_description" ""
- seta "userbind23_press" ""; seta "userbind23_release" ""; seta "userbind23_description" ""
- seta "userbind24_press" ""; seta "userbind24_release" ""; seta "userbind24_description" ""
- seta "userbind25_press" ""; seta "userbind25_release" ""; seta "userbind25_description" ""
- seta "userbind26_press" ""; seta "userbind26_release" ""; seta "userbind26_description" ""
- seta "userbind27_press" ""; seta "userbind27_release" ""; seta "userbind27_description" ""
- seta "userbind28_press" ""; seta "userbind28_release" ""; seta "userbind28_description" ""
- seta "userbind29_press" ""; seta "userbind29_release" ""; seta "userbind29_description" ""
- seta "userbind30_press" ""; seta "userbind30_release" ""; seta "userbind30_description" ""
- seta "userbind31_press" ""; seta "userbind31_release" ""; seta "userbind31_description" ""
- seta "userbind32_press" ""; seta "userbind32_release" ""; seta "userbind32_description" ""
- alias _userbind_call "${$1}"
- alias +userbind "_userbind_call userbind${1}_press"
- alias -userbind "_userbind_call userbind${1}_release"
+ exec binds-default.cfg
  
  // we must change its default from 1.0 to 1 to be consistent with menuqc
  set slowmo 1
@@@ -961,19 -819,19 +820,19 @@@ seta scoreboard_accuracy_border_thickne
  seta scoreboard_accuracy_doublerows 0 "use two rows instead of one"
  seta scoreboard_accuracy_nocolors 0 "don't use colors displaying accuracy stats"
  seta scoreboard_accuracy 1 "show weapon accuracy stats panel on scoreboard; colors can be configured with accuracy_color* cvars"
- seta scoreboard_color_bg_r 0 "red color component of the scoreboard background"
- seta scoreboard_color_bg_g 0.4 "green color component of the scoreboard background"
- seta scoreboard_color_bg_b 0.6 "blue color component of the scoreboard background"
- seta scoreboard_color_bg_team 0.5 "team color multiplier of the scoreboard background"
- seta scoreboard_alpha_bg 0.6 "scoreboard background alpha"
+ seta scoreboard_color_bg_r 0.125 "red color component of the scoreboard background"
+ seta scoreboard_color_bg_g 0.55 "green color component of the scoreboard background"
+ seta scoreboard_color_bg_b 0.875 "blue color component of the scoreboard background"
+ seta scoreboard_color_bg_team 0.6 "team color multiplier of the scoreboard background"
+ seta scoreboard_alpha_bg 0.7 "scoreboard background alpha"
  seta scoreboard_alpha_fg 1 "scoreboard foreground alpha"
  seta scoreboard_alpha_name 0.9 "alpha of player text in scoreboard list other than self"
- seta scoreboard_alpha_name_self 1 "alpha of player text in scoreboard list of self" 
+ seta scoreboard_alpha_name_self 1 "alpha of player text in scoreboard list of self"
  seta scoreboard_fadeinspeed 10 "speed at which scoreboard fades in, higher is faster (0 = instant)"
  seta scoreboard_fadeoutspeed 5 "speed at which scoreboard fades out, higher is faster (0 = instant)"
  seta scoreboard_highlight 1 "enable highlighting for rows and columns in the scoreboard"
- seta scoreboard_highlight_alpha 0.10 "highlight alpha value (depends on hud_scoreboard_highlight 1)"
- seta scoreboard_highlight_alpha_self 0.25 "self highlight alpha value"
+ seta scoreboard_highlight_alpha 0.08 "highlight alpha value (depends on hud_scoreboard_highlight 1)"
+ seta scoreboard_highlight_alpha_self 0.3 "self highlight alpha value"
  seta scoreboard_offset_left 0.15 "how far (by percent) the scoreboard is offset from the left screen edge"
  seta scoreboard_offset_right 0.15 "how far (by percent) the scoreboard is offset from the right screen edge"
  seta scoreboard_offset_vertical 0.05 "how far (by percent) the scoreboard is offset from the top and bottom of the screen"
@@@ -990,8 -848,29 +849,29 @@@ seta menu_slist_showfull 1 "show server
  seta menu_slist_showempty 1 "show servers even if they are no empty and have no opponents to play against"
  seta menu_slist_modfilter "" // set to either: !modname or modname. modname of = means "same as we are running now".
  
- // for menu weapon arena
- set menu_weaponarena_with_laser 0 "also enable the Laser in this weapon arena"
+ // other serverlist cvars
+ seta menu_slist_categories 1
+ seta menu_slist_categories_onlyifmultiple 1
+ seta menu_slist_purethreshold 0
+ seta menu_slist_modimpurity 0
+ seta menu_slist_recommendations 3
+ seta menu_slist_recommendations_maxping 150
+ seta menu_slist_recommendations_minfreeslots 1
+ seta menu_slist_recommendations_minhumans 0
+ seta menu_slist_recommendations_purethreshold -1
+ // serverlist category override cvars
+ seta menu_slist_categories_CAT_FAVORITED_override ""
+ seta menu_slist_categories_CAT_RECOMMENDED_override ""
+ seta menu_slist_categories_CAT_NORMAL_override ""
+ seta menu_slist_categories_CAT_SERVERS_override "CAT_NORMAL"
+ seta menu_slist_categories_CAT_XPM_override "CAT_NORMAL"
+ seta menu_slist_categories_CAT_MODIFIED_override ""
+ seta menu_slist_categories_CAT_OVERKILL_override ""
+ seta menu_slist_categories_CAT_INSTAGIB_override ""
+ seta menu_slist_categories_CAT_DEFRAG_override ""
+ seta menu_weaponarena ""
  
  seta menu_maxplayers 16 "maxplayers value when the menu starts a game"
  
@@@ -1036,30 -915,37 +916,37 @@@ set con_completion_gotomap     ma
  set con_completion_vmap               map
  set con_completion_vnextmap   map
  set con_completion_vdomap     map
- set con_completion_playermodel        models/player/*.iqm
+ set con_completion_playermodel        "models/player/*.iqm"
  
+ // helper
  // these non-saved engine cvars shall be saved
- seta cl_port $cl_port
- seta r_showsurfaces $r_showsurfaces
- seta r_ambient $r_ambient
- seta skill 4
- seta gl_finish $gl_finish
- seta v_kicktime $v_kicktime
- seta r_subdivisions_tolerance $r_subdivisions_tolerance
- seta vid_gl20 $vid_gl20
- seta vid_gl13 $vid_gl13
- seta r_drawviewmodel $r_drawviewmodel
- seta v_idlescale $v_idlescale
- seta net_slist_queriespersecond $net_slist_queriespersecond
+ alias makesaved "seta $1 \"${$1 ?}\"
+ makesaved cl_maxfps_alwayssleep
+ makesaved cl_port
+ makesaved gl_finish
+ makesaved net_slist_queriespersecond
+ makesaved r_ambient
+ makesaved r_drawviewmodel
+ makesaved r_showsurfaces
+ makesaved r_subdivisions_tolerance
+ makesaved skill
+ makesaved vid_gl13
+ makesaved vid_gl20
+ makesaved v_idlescale
+ makesaved v_kicktime
+ makesaved music_playlist_list0
+ makesaved music_playlist_random0
  
  // ticrate
- //sys_ticrate 0.0166667
- sys_ticrate 0.0333333
+ //sys_ticrate 0.0166667 // 60fps. This would be ideal, but kills home routers.
+ sys_ticrate 0.0333333 // Use 30fps instead.
  cl_netfps 60 // should match or be a multiple
  sv_gameplayfix_delayprojectiles 0
  sv_gameplayfix_q2airaccelerate 1
  sv_gameplayfix_stepmultipletimes 1
  
+ cl_gameplayfix_fixedcheckwatertransition 1
  // delay for "kill" to prevent abuse
  set g_balance_kill_delay 2
  set g_balance_kill_antispam 5
@@@ -1082,10 -968,6 +969,6 @@@ alias sethostname "set menu_use_default
  
  set sv_foginterval 1 "force enable fog in regular intervals"
  
- set g_physical_items 0 "1 uses ODE physics for dropped weapons, 2 for all items, requires physics_ode to be enabled"
- set g_physical_items_damageforcescale 3 "how affected physical weapons are by damage"
- set g_physical_items_reset 1 "return map items to their original lotation after being picked up"
  // Audio track names (for old-style "cd loop NUMBER" usage)
  set _cdtrack_first "1"
  alias _cdtrack_0 "g_cdtracks_remaplist \"$g_cdtracks_remaplist $1\""
@@@ -1102,12 -984,10 +985,10 @@@ cd remap $g_cdtracks_remaplis
  set sv_intermission_cdtrack ""
  
  set g_cdtracks_dontusebydefault "rising-of-the-phoenix"
- set menu_cdtrack "rising-of-the-phoenix"
+ seta menu_cdtrack "rising-of-the-phoenix"
  
- // maxidle (in seconds): kick players idle for more than that amount of time
- set sv_maxidle 0
- // when sv_maxidle is not 0, assume spectators are idle too
- set sv_maxidle_spectatorsareidle 0
+ set sv_maxidle 0 "kick players idle for more than this amount of time in seconds"
+ set sv_maxidle_spectatorsareidle 0 "when sv_maxidle is not 0, assume spectators are idle too"
  
  // these entities are not referenced by anything directly, they just represent
  // teams and are found by find() when needed
@@@ -1119,14 -999,14 +1000,14 @@@ sv_allowdownloads 0 // download protoco
  
  set g_jump_grunt 0    "Do you make a grunting noise every time you jump? Is it the same grunting noise every time?"
  
- seta cl_weaponpriority "minstanex nex fireball grenadelauncher uzi hagar rifle electro rocketlauncher crylink minelayer shotgun hlac tuba laser porto seeker hook" "weapon priority list"
+ seta cl_weaponpriority "vaporizer vortex fireball mortar machinegun hagar rifle arc electro devastator crylink minelayer shotgun hlac tuba blaster porto seeker hook" "weapon priority list"
  seta cl_weaponpriority_useforcycling 0 "when set, weapon cycling by the mouse wheel makes use of the weapon priority list (the special value 2 uses the weapon ID list for cycling)"
- seta cl_weaponpriority0 "rocketlauncher grenadelauncher hagar seeker fireball" "use impulse 200 for prev gun from this list, 210 for best gun, 220 for next gun.  Default value: explosives"
- seta cl_weaponpriority1 "minstanex nex crylink hlac electro laser"             "use impulse 201 for prev gun from this list, 211 for best gun, 221 for next gun.  Default value: energy"
- seta cl_weaponpriority2 "minstanex nex rifle"                           "use impulse 202 for prev gun from this list, 212 for best gun, 222 for next gun.  Default value: hitscan exact"
- seta cl_weaponpriority3 "minstanex nex rifle uzi shotgun"               "use impulse 203 for prev gun from this list, 213 for best gun, 223 for next gun.  Default value: hitscan all"
- seta cl_weaponpriority4 "grenadelauncher minelayer hlac hagar crylink seeker shotgun"    "use impulse 204 for prev gun from this list, 214 for best gun, 224 for next gun.  Default value: spam weapons"
- seta cl_weaponpriority5 "laser hook porto"                                     "use impulse 205 for prev gun from this list, 215 for best gun, 225 for next gun.  Default value: weapons for moving"
+ seta cl_weaponpriority0 "devastator mortar hagar seeker fireball" "use impulse 200 for prev gun from this list, 210 for best gun, 220 for next gun.  Default value: explosives"
+ seta cl_weaponpriority1 "vaporizer vortex crylink hlac arc electro blaster shockwave"             "use impulse 201 for prev gun from this list, 211 for best gun, 221 for next gun.  Default value: energy"
+ seta cl_weaponpriority2 "vaporizer vortex rifle"                           "use impulse 202 for prev gun from this list, 212 for best gun, 222 for next gun.  Default value: hitscan exact"
+ seta cl_weaponpriority3 "vaporizer vortex rifle machinegun shotgun"               "use impulse 203 for prev gun from this list, 213 for best gun, 223 for next gun.  Default value: hitscan all"
+ seta cl_weaponpriority4 "mortar minelayer hlac hagar crylink seeker shotgun"    "use impulse 204 for prev gun from this list, 214 for best gun, 224 for next gun.  Default value: spam weapons"
+ seta cl_weaponpriority5 "blaster shockwave hook porto"                                     "use impulse 205 for prev gun from this list, 215 for best gun, 225 for next gun.  Default value: weapons for moving"
  seta cl_weaponpriority6 "" "use impulse 206 for prev gun from this list, 216 for best gun, 226 for next gun"
  seta cl_weaponpriority7 "" "use impulse 207 for prev gun from this list, 217 for best gun, 227 for next gun"
  seta cl_weaponpriority8 "" "use impulse 208 for prev gun from this list, 218 for best gun, 228 for next gun"
@@@ -1146,13 -1026,13 +1027,13 @@@ set sv_clones 0      "number of clones a pla
  
  set cl_handicap 1     "the higher, the more damage you will receive (client setting) NOTE: reconnect or use sendcvar command to update the choice."
  
- seta cl_clippedspectating 1 "movement collision for spectators so that you can't pass through walls and such. (client setting) NOTE: reconnect or use sendcvar command to update the choice." 
+ seta cl_clippedspectating 1 "movement collision for spectators so that you can't pass through walls and such. (client setting) NOTE: reconnect or use sendcvar command to update the choice."
  
  seta cl_autoscreenshot 1 "Take a screenshot upon the end of a match... 0 = Disable completely, 1 = Allow sv_autoscreenshot to take a screenshot when requested, 2 = Always take an autoscreenshot anyway."
  
+ seta cl_jetpack_jump 1 "Activate jetpack by pressing jump in the air. 0 = Disable, 1 = Stop when touching ground, 2 = Enable"
  // must be at the bottom of this file:
- // alias for switching the teamselect menu
- bind f5 menu_showteamselect
  
  set g_bugrigs 0
  set g_bugrigs_planar_movement 1       "BROTRR bug emulation"
@@@ -1170,12 -1050,6 +1051,6 @@@ set g_bugrigs_speed_ref 400    "reference 
  set g_bugrigs_speed_pow 2     "reference power for accel and steer responsiveness"
  set g_bugrigs_steer 1 "steering amount"
  
- set g_touchexplode 0
- set g_touchexplode_radius 50
- set g_touchexplode_damage 10
- set g_touchexplode_edgedamage 0
- set g_touchexplode_force 150
  set g_ban_sync_uri "" "sync using this ban list provider (empty string to disable)"
  set g_ban_sync_interval 5     "sync every 5 minutes"
  set g_ban_sync_trusted_servers ""     "request ban lists from these xonotic servers (do not include your own server there, or unbanning may fail)"
@@@ -1189,32 -1063,9 +1064,9 @@@ set g_showweaponspawns 1       "display sprit
  //   Quake-Joule:  1 qJ  = 1 qN * 1 qu
  //   Quake-Pascal: 1 qPa = 1 qN / 1 qu^2
  
- set g_ballistics_materialconstant 1414213562
- set g_ballistics_mindistance 16
+ set g_ballistics_mindistance 2 // enable ballistics starting from 2 qu
  set g_ballistics_density_player 0.50 // players are 2x as easy to pass as walls
  set g_ballistics_density_corpse 0.10 // corpses are 10x as easy to pass as walls
- // unit: qJ / qu^3 (energy needed per volume unit of solid to push/burn away
- // parameter: bullet constant: mass / area in g/qu^2
- // = mass / (pi/4 * caliber^2)
- // with caliber in inches, mass in grams:
- // = 1.273239544735163 * mass / caliber^2
- // with caliber in inches, mass in grains:
- // = 0.082633246453312 * mass / caliber^2
- // bullet max travel distance inside solid:
- //   0.5 * v^2 * bulletconstant / g_ballistics_materialconstant
- // some bullet constants:
- //   http://hypertextbook.com/facts/2000/ShantayArmstrong.shtml
- //     second bullet: caliber .45, mass 16.2g, bullet constant 101.859163578813
- //     third bullet: caliber .338, mass 16.2g, bullet constant 180.5476053421592
- //     fourth bullet: caliber .25, mass 2.3g, bullet constant 46.85521524625399
- //   http://en.wikipedia.org/wiki/.50_BMG
- //     caliber .5, 360 grains, bullet constant 118.9918748927693
- //   AK-47:
- //     caliber .3, 62 grains, bullet constant 56.92512533450383
- //   .3 winchester magnum:
- //     caliber .3, 150 grains, bullet constant 137.7220774221867
  
  set cl_stripcolorcodes 0      "experimental feature (notes: strips ALL color codes from messages!)"
  
@@@ -1242,7 -1093,7 +1094,7 @@@ seta cl_gentle_gibs 0           "client side gen
  seta cl_gentle_messages 0     "client side gentle mode (only replaces frag messages/centerprints)"
  seta cl_gentle_damage 0               "client side gentle mode (only replaces damage flash); when set to 1, a white flash replaces the blood image, when set to 2, a randomily colored flash is used instead"
  
- set g_jetpack 0 "Jetpack mutator (uses the hook's button, can't coexist with the offhand hook, but only with the onhand one)"
+ set g_jetpack 0 "Jetpack mutator"
  
  set g_running_guns 0 "... or wonder, till it drives you mad, what would have followed if you had."
  set g_bastet 0 "don't try"
@@@ -1268,7 -1119,7 +1120,7 @@@ set bot_sound_monopoly 0 "when enabled
  
  set cl_loddistance1 1024
  set cl_loddistance2 3072
- seta cl_playerdetailreduction 1       "the higher, the less detailed player models are displayed (LOD)"
+ seta cl_playerdetailreduction 4       "the higher, the less detailed player models are displayed (LOD)"
  seta cl_modeldetailreduction 1        "the higher, the less detailed certain map models are displayed (LOD)"
  
  set g_mapinfo_settemp_acl "+*" "ACL for mapinfo setting cvars"
@@@ -1277,7 -1128,7 +1129,7 @@@ seta cl_casings_maxcount 100 "maximum a
  seta cl_gibs_maxcount 100 "maximum amount of gibs (must be at least 1)"
  seta cl_vehicle_spiderbot_cross_alpha 0.6
  seta cl_vehicle_spiderbot_cross_size 1
- seta cl_vehicles_hudscale 0.5 
+ seta cl_vehicles_hudscale 0.5
  seta cl_vehicles_hudalpha 0.75
  seta cl_vehicles_hud_tactical 1
  
@@@ -1316,8 -1167,6 +1168,6 @@@ set sv_accuracy_data_send 1 "1 send wea
  set cl_accuracy_data_share 0 "1 share my weapon accuracy data statistics with other players, 0 keep my weapon accuracy data statistics hidden"
  set cl_accuracy_data_receive 0 "1 receive weapon accuracy data statistics at the end of the match"
  
- set developer_fteqccbugs 0 "check fteqcc bugs on startup"
- set _allow_unacceptable_compiler_bugs 0 "don't bail out if certain bugs are detected (HANDLE WITH CARE)"
  set spawn_debug 0 "use all spawns one by one, then abort, to verify all spawnpoints"
  set loddebug 0 "force this LOD level"
  set spawn_debugview 0 "display spawnpoints and their rating on spawn to debug spawnpoint rating calculation"
@@@ -1327,7 -1176,6 +1177,6 @@@ set developer_csqcentities 0 "csqc enti
  set waypoint_benchmark 0 "quit after waypoint loading to benchmark bot navigation code"
  set g_debug_bot_commands 0 "print scripted bot commands before executing"
  set g_debug_defaultsounds 0 "always use default sounds"
- set cl_precacheplayermodels 0 "TODO please check if this needs to be 1 or if precaching a model the server already requested is fast enough to do it at runtime"
  seta cl_forceplayermodels 0 "make everyone look like your own model (requires server to have sv_defaultcharacter 0)"
  seta cl_forceplayercolors 0 "make everyone look like your own color (requires server to have sv_defaultcharacter 0, and is ignored in teamplay with more than two teams)"
  seta cl_forcemyplayermodel "" "set to the model file name you want to show yourself as (does not affect how enemies look with cl_forceplayermodels)"
@@@ -1335,10 -1183,6 +1184,6 @@@ seta cl_forcemyplayerskin 0 "set to th
  seta cl_forcemyplayercolors 0 "set to the color value (encoding is same as _cl_color) for your own player model (ignored in teamplay; does not affect how enemies look with cl_forceplayermodels)"
  seta cl_movement_errorcompensation 1 "try to compensate for prediction errors and reduce preceived lag"
  
- // debug cvars for keyhunt attaching
- set _angles "0 0 0"
- set _origin "0 0 0"
  // campaign internal, set when loading a campaign map1G
  set _campaign_index ""
  set _campaign_name ""
@@@ -1354,6 -1198,9 +1199,9 @@@ set r_showbboxes 
  // we REALLY need the end pos nudging DP bug workaround for trace-to-end-of-solid to work
  collision_endposnudge 1
  
+ // FIXME remove this when the engine feature FINALLY MAYBE works
+ r_glsl_skeletal 0
  // animation tuning
  set cl_lerpanim_maxdelta_framegroups 0.05 // must be faster than fastest weapon refire
  set cl_lerpanim_maxdelta_server 0.1 // must be slower than slowest server controlled anim (e.g. animinfo stuff)
@@@ -1383,25 -1230,7 +1231,7 @@@ volume 
  // sucks less than the old one
  cl_decals_newsystem 1
  
- // NOTE: this only replaces weapons on the map
- // use g_start_weapon_* to also replace the on-startup weapons!
- // example: g_weaponreplace_nex "nex minstanex", then Nexes become MinstaNexes 50% of the times
- // set the cvars to "0" to totally disable a weapon
- set g_weaponreplace_laser ""
- set g_weaponreplace_shotgun ""
- set g_weaponreplace_uzi ""
- set g_weaponreplace_grenadelauncher ""
- set g_weaponreplace_electro ""
- set g_weaponreplace_crylink ""
- set g_weaponreplace_nex ""
- set g_weaponreplace_hagar ""
- set g_weaponreplace_rocketlauncher ""
- set g_weaponreplace_porto ""
- set g_weaponreplace_minstanex ""
- set g_weaponreplace_hook ""
- set g_weaponreplace_tuba ""
- set g_weaponreplace_fireball ""
- set sv_q3acompat_machineshotgunswap 0 "shorthand for swapping uzi and shotgun (for Q3A map compatibility in mapinfo files)"
+ set sv_q3acompat_machineshotgunswap 0 "shorthand for swapping machinegun and shotgun (for Q3A map compatibility in mapinfo files)"
  
  set g_movement_highspeed 1 "movement speed modification factor (only changes movement when above maxspeed)"
  
@@@ -1438,7 -1267,7 +1268,7 @@@ sv_cullentities_trace 
  r_cullentities_trace 0
  
  // less "lagging" of other players, but also less PL tolerant... let's try this
- sv_clmovement_inputtimeout 0.07 // more than 2, less than 3 server frames
+ sv_clmovement_inputtimeout 0.066 // slightly less than 2 frames, so only one frame can be compensated
  
  // exact gloss looks better, e.g. on g-23
  r_shadow_glossexact 1
@@@ -1448,6 -1277,7 +1278,7 @@@ r_shadow_glossintensity 
  r_fakelight 1
  
  r_water_hideplayer 1 // hide your own feet/player model in refraction views, this way you don't see half of your body under water
+ r_water_refractdistort 0.019
  
  // strength sound settings
  set sv_strengthsound_antispam_time 0.1 "minimum distance of strength sounds"
@@@ -1484,7 -1314,7 +1315,7 @@@ mod_q3shader_default_polygonoffset -1
  mod_q3shader_default_polygonfactor 0
  
  // allow fullbright
- set sv_allow_fullbright 0 "when set, clients may use r_fullbright on this server without getting a night vision effect overlay"
+ set sv_allow_fullbright 1 "when set, clients may use r_fullbright on this server without getting a night vision effect overlay"
  
  // auto-teams (team selection by player ID)
  // any player not listed is forced to spectate
@@@ -1528,6 -1358,7 +1359,7 @@@ set snd_soundradius 120
  set snd_softclip 1
  set snd_maxchannelvolume 0
  set snd_streaming_length 2
+ seta menu_snd_sliderscale 2 "0: decibels; 1: linear percent; 2: 0..10 scale; 3: slider size percent"
  seta menu_snd_attenuation_method 1 "Use exponential instead of linear falloff for sound attenuation"
  alias snd_attenuation_method_0 "set menu_snd_attenuation_method 0; set snd_soundradius 1200; set snd_attenuation_exponent 1; set snd_attenuation_decibel 0" // Quake default
  alias snd_attenuation_method_1 "set menu_snd_attenuation_method 1; set snd_soundradius 2400; set snd_attenuation_exponent 4; set snd_attenuation_decibel 0" // nice approximation for method 2
@@@ -1546,22 -1377,23 +1378,23 @@@ snd_identicalsoundrandomization_tic
  scr_loadingscreen_background 0
  scr_loadingscreen_barcolor "0 0.5 1"
  scr_loadingscreen_barheight 12
- scr_loadingscreen_count 14
+ scr_loadingscreen_count 1
  scr_loadingscreen_firstforstartup 1
  scr_loadingscreen_scale 999
  scr_loadingscreen_scale_base 1
  scr_loadingscreen_scale_limit 2
  
  // other config files
- exec mutator_new_toys.cfg // run BEFORE balance to make sure balance wins
- exec balanceXonotic.cfg
+ exec balance-xonotic.cfg
  exec effects-normal.cfg
  exec physicsX.cfg
  exec turrets.cfg
  exec vehicles.cfg
  exec crosshairs.cfg
  exec gamemodes.cfg
+ exec mutators.cfg
  exec notifications.cfg
+ exec monsters.cfg
  
  // load console command aliases and settings
  exec commands.cfg
@@@ -1574,7 -1406,7 +1407,7 @@@ exec _hud_descriptions.cf
  exec hud_luminos.cfg
  
  
- // ... and now that everything is configured/aliased, we can do some things: 
+ // ... and now that everything is configured/aliased, we can do some things:
  
  // Change g_start_delay based upon if the server is local or not.
  if_client set g_start_delay 0 "delay before the game starts, so everyone can join; recommended to set this to like 15 on a public server"
@@@ -1595,4 -1427,7 +1428,7 @@@ set cl_fullbright_items 0 "enable fullb
  set cl_weapon_stay_color "2 0.5 0.5" "Color of picked up weapons when g_weapon_stay > 0"
  set cl_weapon_stay_alpha 0.75 "Alpha of picked up weapons when g_weapon_stay > 0"
  
- seta g_superspectate 0 "server side, allows extended spectator functions through the cmd interface. followpowerup, followstrength, followstshield or followfc [red|blue] will transfer spectation to the relevent player, if any"
+ // Facility for config.cfg use ONLY.
+ // Interpreted in post-config.cfg.
+ seta menu_forced_saved_cvars "" "These cvars will always be saved, despite engine/Xonotic cvar saving status"
+ set menu_reverted_nonsaved_cvars "" "These cvars are currently marked as saved in the flags, but have been reverted and won't stay saved. INTERNAL USE ONLY."
diff --combined hud_luminos.cfg
index 8d7e046c79d4aec17588dd77cbaf26f950c4c19f,f3bc914e6a48be696bd9e3b8879eb90d9ab0254f..212717f97a80c1ec1fbc04c36fca8b4b75b731a0
@@@ -20,11 -20,11 +20,11 @@@ seta hud_progressbar_health_color "0.6 
  seta hud_progressbar_armor_color "0 0.6 0"
  seta hud_progressbar_fuel_color "0.6 0.6 0"
  seta hud_progressbar_nexball_color "0.7 0.1 0"
- seta hud_progressbar_speed_color "1 0.75 0" 
- seta hud_progressbar_acceleration_color "0.5 0.75 1" 
- seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5" 
+ seta hud_progressbar_speed_color "1 0.75 0"
+ seta hud_progressbar_acceleration_color "0.5 0.75 1"
+ seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5"
  
 -seta _hud_panelorder "15 12 9 10 5 6 14 0 7 4 11 2 1 3 8 13 16 "
 +seta _hud_panelorder "15 12 9 10 5 6 14 0 7 4 11 2 1 3 8 13 16 17 "
  
  seta hud_configure_grid "1"
  seta hud_configure_grid_xsize "0.010000"
@@@ -54,7 -54,7 +54,7 @@@ seta hud_panel_weapons_ammo_alpha "1
  seta hud_panel_weapons_aspect "2"
  seta hud_panel_weapons_timeout "1"
  seta hud_panel_weapons_timeout_effect "1"
- seta hud_panel_weapons_timeout_fadebgmin "0.4" 
+ seta hud_panel_weapons_timeout_fadebgmin "0.4"
  seta hud_panel_weapons_timeout_fadefgmin "0.4"
  seta hud_panel_weapons_timeout_speed_in "0.25"
  seta hud_panel_weapons_timeout_speed_out "0.75"
@@@ -126,6 -126,7 +126,7 @@@ seta hud_panel_notify_flip "0
  seta hud_panel_notify_fontsize "0.8"
  seta hud_panel_notify_time "10"
  seta hud_panel_notify_fadetime "3"
+ seta hud_panel_notify_icon_aspect "2"
  
  seta hud_panel_timer 1
  seta hud_panel_timer_pos "0.800000 0.040000"
@@@ -197,7 -198,9 +198,9 @@@ seta hud_panel_modicons_bg_color_team "
  seta hud_panel_modicons_bg_alpha ""
  seta hud_panel_modicons_bg_border ""
  seta hud_panel_modicons_bg_padding "0"
+ seta hud_panel_modicons_ca_layout "1"
  seta hud_panel_modicons_dom_layout "1"
+ seta hud_panel_modicons_freezetag_layout "1"
  
  seta hud_panel_pressedkeys 1
  seta hud_panel_pressedkeys_pos "0.450000 0.720000"
@@@ -288,27 -291,19 +291,37 @@@ seta hud_panel_centerprint_fade_out "0.
  seta hud_panel_centerprint_fade_subsequent "1"
  seta hud_panel_centerprint_fade_subsequent_passone "3"
  seta hud_panel_centerprint_fade_subsequent_passone_minalpha "0.5"
- seta hud_panel_centerprint_fade_subsequent_passtwo "10" 
+ seta hud_panel_centerprint_fade_subsequent_passtwo "10"
  seta hud_panel_centerprint_fade_subsequent_passtwo_minalpha "0.5"
  seta hud_panel_centerprint_fade_subsequent_minfontsize "0.75"
  seta hud_panel_centerprint_fade_minfontsize "0"
  
+ seta hud_panel_buffs 1
+ seta hud_panel_buffs_pos "0.450000 0.855000"
+ seta hud_panel_buffs_size "0.050000 0.070000"
+ seta hud_panel_buffs_bg "0"
+ seta hud_panel_buffs_bg_color ""
+ seta hud_panel_buffs_bg_color_team ""
+ seta hud_panel_buffs_bg_alpha ""
+ seta hud_panel_buffs_bg_border ""
+ seta hud_panel_buffs_bg_padding ""
 +seta hud_panel_itemstime 2
 +seta hud_panel_itemstime_pos "0.030000 0.260000"
 +seta hud_panel_itemstime_size "0.070000 0.230000"
 +seta hud_panel_itemstime_bg "border_itemstime"
 +seta hud_panel_itemstime_bg_color ""
 +seta hud_panel_itemstime_bg_color_team ""
 +seta hud_panel_itemstime_bg_alpha ""
 +seta hud_panel_itemstime_bg_border ""
 +seta hud_panel_itemstime_bg_padding ""
 +seta hud_panel_itemstime_iconalign "0"
 +seta hud_panel_itemstime_progressbar "0"
 +seta hud_panel_itemstime_progressbar_name "progressbar"
 +seta hud_panel_itemstime_progressbar_reduced "0"
 +seta hud_panel_itemstime_showspawned "0"
 +seta hud_panel_itemstime_text "1"
 +seta hud_panel_itemstime_ratio "2"
 +seta hud_panel_itemstime_size_dinamic "1"
 +
  menu_sync
diff --combined hud_luminos_minimal.cfg
index 4cd38574bc775034bbaa8897828b5e53d40ee53d,050689b38caf95d525f07e83f378649fc49dafff..b1a934605b4ece245694b9213f9a4cd13512d662
@@@ -20,11 -20,11 +20,11 @@@ seta hud_progressbar_health_color "0.6 
  seta hud_progressbar_armor_color "0 0.6 0"
  seta hud_progressbar_fuel_color "0.6 0.6 0"
  seta hud_progressbar_nexball_color "0.7 0.1 0"
- seta hud_progressbar_speed_color "1 0.75 0" 
- seta hud_progressbar_acceleration_color "0.5 0.75 1" 
- seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5" 
+ seta hud_progressbar_speed_color "1 0.75 0"
+ seta hud_progressbar_acceleration_color "0.5 0.75 1"
+ seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5"
  
 -seta _hud_panelorder "10 3 0 14 6 9 13 4 1 2 11 12 7 5 8 15 16 "
 +seta _hud_panelorder "10 3 0 14 6 9 13 4 1 2 11 12 7 5 8 15 16 17 "
  
  seta hud_configure_grid "1"
  seta hud_configure_grid_xsize "0.010000"
@@@ -54,7 -54,7 +54,7 @@@ seta hud_panel_weapons_ammo_alpha "1
  seta hud_panel_weapons_aspect "2"
  seta hud_panel_weapons_timeout "0"
  seta hud_panel_weapons_timeout_effect "0"
- seta hud_panel_weapons_timeout_fadebgmin "0" 
+ seta hud_panel_weapons_timeout_fadebgmin "0"
  seta hud_panel_weapons_timeout_fadefgmin "0"
  seta hud_panel_weapons_timeout_speed_in "0.25"
  seta hud_panel_weapons_timeout_speed_out "0.75"
@@@ -126,6 -126,7 +126,7 @@@ seta hud_panel_notify_flip "1
  seta hud_panel_notify_fontsize "0.8"
  seta hud_panel_notify_time "10"
  seta hud_panel_notify_fadetime "3"
+ seta hud_panel_notify_icon_aspect "2"
  
  seta hud_panel_timer 1
  seta hud_panel_timer_pos "0.435000 0"
@@@ -197,7 -198,9 +198,9 @@@ seta hud_panel_modicons_bg_color_team "
  seta hud_panel_modicons_bg_alpha ""
  seta hud_panel_modicons_bg_border ""
  seta hud_panel_modicons_bg_padding ""
+ seta hud_panel_modicons_ca_layout "1"
  seta hud_panel_modicons_dom_layout "1"
+ seta hud_panel_modicons_freezetag_layout "1"
  
  seta hud_panel_pressedkeys 1
  seta hud_panel_pressedkeys_pos "0.450000 0.650000"
@@@ -288,27 -291,19 +291,37 @@@ seta hud_panel_centerprint_fade_out "0.
  seta hud_panel_centerprint_fade_subsequent "1"
  seta hud_panel_centerprint_fade_subsequent_passone "3"
  seta hud_panel_centerprint_fade_subsequent_passone_minalpha "0.5"
- seta hud_panel_centerprint_fade_subsequent_passtwo "10" 
+ seta hud_panel_centerprint_fade_subsequent_passtwo "10"
  seta hud_panel_centerprint_fade_subsequent_passtwo_minalpha "0.5"
  seta hud_panel_centerprint_fade_subsequent_minfontsize "0.75"
  seta hud_panel_centerprint_fade_minfontsize "0"
  
+ seta hud_panel_buffs 1
+ seta hud_panel_buffs_pos "0.450000 0.855000"
+ seta hud_panel_buffs_size "0.050000 0.070000"
+ seta hud_panel_buffs_bg "0"
+ seta hud_panel_buffs_bg_color ""
+ seta hud_panel_buffs_bg_color_team ""
+ seta hud_panel_buffs_bg_alpha ""
+ seta hud_panel_buffs_bg_border ""
+ seta hud_panel_buffs_bg_padding ""
 +seta hud_panel_itemstime 2
 +seta hud_panel_itemstime_pos "0.000000 0.310000"
 +seta hud_panel_itemstime_size "0.070000 0.180000"
 +seta hud_panel_itemstime_bg ""
 +seta hud_panel_itemstime_bg_color ""
 +seta hud_panel_itemstime_bg_color_team ""
 +seta hud_panel_itemstime_bg_alpha ""
 +seta hud_panel_itemstime_bg_border ""
 +seta hud_panel_itemstime_bg_padding ""
 +seta hud_panel_itemstime_iconalign "0"
 +seta hud_panel_itemstime_progressbar "0"
 +seta hud_panel_itemstime_progressbar_name "progressbar"
 +seta hud_panel_itemstime_progressbar_reduced "0"
 +seta hud_panel_itemstime_showspawned "0"
 +seta hud_panel_itemstime_text "1"
 +seta hud_panel_itemstime_ratio "2"
 +seta hud_panel_itemstime_size_dinamic "1"
 +
  menu_sync
index 966ebbb9e0bd56f8d06bc6ae45fd3cca7dc33bf0,8fb6cbe93da88fd67f099c634126551449435fdf..b88d4683c3d49fd76f1da639b8b5f931d0acc16b
@@@ -20,11 -20,11 +20,11 @@@ seta hud_progressbar_health_color "0.6 
  seta hud_progressbar_armor_color "0 0.6 0"
  seta hud_progressbar_fuel_color "0.6 0.6 0"
  seta hud_progressbar_nexball_color "0.7 0.1 0"
- seta hud_progressbar_speed_color "1 0.75 0" 
- seta hud_progressbar_acceleration_color "0.5 0.75 1" 
- seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5" 
+ seta hud_progressbar_speed_color "1 0.75 0"
+ seta hud_progressbar_acceleration_color "0.5 0.75 1"
+ seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5"
  
 -seta _hud_panelorder "15 3 1 2 11 10 0 14 6 9 13 4 12 7 5 8 16 "
 +seta _hud_panelorder "15 3 1 2 11 10 0 14 6 9 13 4 12 7 5 8 16 17 "
  
  seta hud_configure_grid "1"
  seta hud_configure_grid_xsize "0.010000"
@@@ -54,7 -54,7 +54,7 @@@ seta hud_panel_weapons_ammo_alpha "1
  seta hud_panel_weapons_aspect "2"
  seta hud_panel_weapons_timeout "0"
  seta hud_panel_weapons_timeout_effect "0"
- seta hud_panel_weapons_timeout_fadebgmin "0" 
+ seta hud_panel_weapons_timeout_fadebgmin "0"
  seta hud_panel_weapons_timeout_fadefgmin "0"
  seta hud_panel_weapons_timeout_speed_in "0.25"
  seta hud_panel_weapons_timeout_speed_out "0.75"
@@@ -126,6 -126,7 +126,7 @@@ seta hud_panel_notify_flip "1
  seta hud_panel_notify_fontsize "0.8"
  seta hud_panel_notify_time "10"
  seta hud_panel_notify_fadetime "3"
+ seta hud_panel_notify_icon_aspect "2"
  
  seta hud_panel_timer 1
  seta hud_panel_timer_pos "0.435000 0"
@@@ -197,7 -198,9 +198,9 @@@ seta hud_panel_modicons_bg_color_team "
  seta hud_panel_modicons_bg_alpha ""
  seta hud_panel_modicons_bg_border ""
  seta hud_panel_modicons_bg_padding ""
+ seta hud_panel_modicons_ca_layout "1"
  seta hud_panel_modicons_dom_layout "1"
+ seta hud_panel_modicons_freezetag_layout "1"
  
  seta hud_panel_pressedkeys 1
  seta hud_panel_pressedkeys_pos "0.450000 0.690000"
@@@ -288,27 -291,19 +291,37 @@@ seta hud_panel_centerprint_fade_out "0.
  seta hud_panel_centerprint_fade_subsequent "1"
  seta hud_panel_centerprint_fade_subsequent_passone "3"
  seta hud_panel_centerprint_fade_subsequent_passone_minalpha "0.5"
- seta hud_panel_centerprint_fade_subsequent_passtwo "10" 
+ seta hud_panel_centerprint_fade_subsequent_passtwo "10"
  seta hud_panel_centerprint_fade_subsequent_passtwo_minalpha "0.5"
  seta hud_panel_centerprint_fade_subsequent_minfontsize "0.75"
  seta hud_panel_centerprint_fade_minfontsize "0"
  
+ seta hud_panel_buffs 1
+ seta hud_panel_buffs_pos "0.450000 0.855000"
+ seta hud_panel_buffs_size "0.050000 0.070000"
+ seta hud_panel_buffs_bg "0"
+ seta hud_panel_buffs_bg_color ""
+ seta hud_panel_buffs_bg_color_team ""
+ seta hud_panel_buffs_bg_alpha ""
+ seta hud_panel_buffs_bg_border ""
+ seta hud_panel_buffs_bg_padding ""
 +seta hud_panel_itemstime 2
 +seta hud_panel_itemstime_pos "0.000000 0.310000"
 +seta hud_panel_itemstime_size "0.070000 0.180000"
 +seta hud_panel_itemstime_bg ""
 +seta hud_panel_itemstime_bg_color ""
 +seta hud_panel_itemstime_bg_color_team ""
 +seta hud_panel_itemstime_bg_alpha ""
 +seta hud_panel_itemstime_bg_border ""
 +seta hud_panel_itemstime_bg_padding ""
 +seta hud_panel_itemstime_iconalign "0"
 +seta hud_panel_itemstime_progressbar "0"
 +seta hud_panel_itemstime_progressbar_name "progressbar"
 +seta hud_panel_itemstime_progressbar_reduced "0"
 +seta hud_panel_itemstime_showspawned "0"
 +seta hud_panel_itemstime_text "1"
 +seta hud_panel_itemstime_ratio "2"
 +seta hud_panel_itemstime_size_dinamic "1"
 +
  menu_sync
diff --combined hud_luminos_old.cfg
index 463812c61cd6bb4733485ce32f675d94135b6fda,9d71e2e2872cc4f4d6e0624a2d2b5e74064fa5cf..896af911fe9bcd709a2a3ff535c6c8f2d9cad37e
@@@ -20,11 -20,11 +20,11 @@@ seta hud_progressbar_health_color "0.6 
  seta hud_progressbar_armor_color "0 0.6 0"
  seta hud_progressbar_fuel_color "0.6 0.6 0"
  seta hud_progressbar_nexball_color "0.7 0.1 0"
- seta hud_progressbar_speed_color "1 0.75 0" 
- seta hud_progressbar_acceleration_color "0.5 0.75 1" 
- seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5" 
+ seta hud_progressbar_speed_color "1 0.75 0"
+ seta hud_progressbar_acceleration_color "0.5 0.75 1"
+ seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5"
  
 -seta _hud_panelorder "15 10 9 6 8 14 5 0 4 13 2 7 1 3 11 12 16 "
 +seta _hud_panelorder "15 10 9 6 8 14 5 0 4 13 2 7 1 3 11 12 16 17 "
  
  seta hud_configure_grid "1"
  seta hud_configure_grid_xsize "0.010000"
@@@ -54,7 -54,7 +54,7 @@@ seta hud_panel_weapons_ammo_alpha "1
  seta hud_panel_weapons_aspect "2"
  seta hud_panel_weapons_timeout "3"
  seta hud_panel_weapons_timeout_effect "1"
- seta hud_panel_weapons_timeout_fadebgmin "0" 
+ seta hud_panel_weapons_timeout_fadebgmin "0"
  seta hud_panel_weapons_timeout_fadefgmin "0"
  seta hud_panel_weapons_timeout_speed_in "0.25"
  seta hud_panel_weapons_timeout_speed_out "0.75"
@@@ -126,6 -126,7 +126,7 @@@ seta hud_panel_notify_flip "0
  seta hud_panel_notify_fontsize "0.8"
  seta hud_panel_notify_time "10"
  seta hud_panel_notify_fadetime "3"
+ seta hud_panel_notify_icon_aspect "2"
  
  seta hud_panel_timer 1
  seta hud_panel_timer_pos "0.870000 0"
@@@ -197,7 -198,9 +198,9 @@@ seta hud_panel_modicons_bg_color_team "
  seta hud_panel_modicons_bg_alpha ""
  seta hud_panel_modicons_bg_border ""
  seta hud_panel_modicons_bg_padding ""
+ seta hud_panel_modicons_ca_layout "1"
  seta hud_panel_modicons_dom_layout "1"
+ seta hud_panel_modicons_freezetag_layout "1"
  
  seta hud_panel_pressedkeys 1
  seta hud_panel_pressedkeys_pos "0.410000 0.710000"
@@@ -288,27 -291,19 +291,37 @@@ seta hud_panel_centerprint_fade_out "0.
  seta hud_panel_centerprint_fade_subsequent "1"
  seta hud_panel_centerprint_fade_subsequent_passone "3"
  seta hud_panel_centerprint_fade_subsequent_passone_minalpha "0.5"
- seta hud_panel_centerprint_fade_subsequent_passtwo "10" 
+ seta hud_panel_centerprint_fade_subsequent_passtwo "10"
  seta hud_panel_centerprint_fade_subsequent_passtwo_minalpha "0.5"
  seta hud_panel_centerprint_fade_subsequent_minfontsize "0.75"
  seta hud_panel_centerprint_fade_minfontsize "0"
  
+ seta hud_panel_buffs 1
+ seta hud_panel_buffs_pos "0.450000 0.855000"
+ seta hud_panel_buffs_size "0.050000 0.070000"
+ seta hud_panel_buffs_bg "0"
+ seta hud_panel_buffs_bg_color ""
+ seta hud_panel_buffs_bg_color_team ""
+ seta hud_panel_buffs_bg_alpha ""
+ seta hud_panel_buffs_bg_border ""
+ seta hud_panel_buffs_bg_padding ""
 +seta hud_panel_itemstime 2
 +seta hud_panel_itemstime_pos "0.020000 0.490000"
 +seta hud_panel_itemstime_size "0.090000 0.140000"
 +seta hud_panel_itemstime_bg "0"
 +seta hud_panel_itemstime_bg_color ""
 +seta hud_panel_itemstime_bg_color_team ""
 +seta hud_panel_itemstime_bg_alpha ""
 +seta hud_panel_itemstime_bg_border ""
 +seta hud_panel_itemstime_bg_padding ""
 +seta hud_panel_itemstime_iconalign "0"
 +seta hud_panel_itemstime_progressbar "1"
 +seta hud_panel_itemstime_progressbar_name "progressbar"
 +seta hud_panel_itemstime_progressbar_reduced "1"
 +seta hud_panel_itemstime_showspawned "0"
 +seta hud_panel_itemstime_text "1"
 +seta hud_panel_itemstime_ratio "3.5"
 +seta hud_panel_itemstime_size_dinamic "1"
 +
  menu_sync
diff --combined hud_nexuiz.cfg
index 0aa7a4dedffb8e0d7bf865a209ac6b4781ba8514,9e4678293d627419612564b5d12d91a4365d56fc..af05512d0b9589dd7d16619ffe9ebb918829318a
@@@ -20,11 -20,11 +20,11 @@@ seta hud_progressbar_health_color "0.6 
  seta hud_progressbar_armor_color "0 0.6 0"
  seta hud_progressbar_fuel_color "0.6 0.6 0"
  seta hud_progressbar_nexball_color "0.7 0.1 0"
- seta hud_progressbar_speed_color "1 0.75 0" 
- seta hud_progressbar_acceleration_color "0.5 0.75 1" 
- seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5" 
+ seta hud_progressbar_speed_color "1 0.75 0"
+ seta hud_progressbar_acceleration_color "0.5 0.75 1"
+ seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5"
  
 -seta _hud_panelorder "15 0 11 8 5 6 14 9 13 7 2 3 1 10 12 4 16 "
 +seta _hud_panelorder "15 0 11 8 5 6 14 9 13 7 2 3 1 10 12 4 16 17 "
  
  seta hud_configure_grid "1"
  seta hud_configure_grid_xsize "0.01"
@@@ -54,7 -54,7 +54,7 @@@ seta hud_panel_weapons_ammo_alpha "1
  seta hud_panel_weapons_aspect "2"
  seta hud_panel_weapons_timeout "0"
  seta hud_panel_weapons_timeout_effect "0"
- seta hud_panel_weapons_timeout_fadebgmin "0" 
+ seta hud_panel_weapons_timeout_fadebgmin "0"
  seta hud_panel_weapons_timeout_fadefgmin "0"
  seta hud_panel_weapons_timeout_speed_in "0.25"
  seta hud_panel_weapons_timeout_speed_out "0.75"
@@@ -126,6 -126,7 +126,7 @@@ seta hud_panel_notify_flip "0
  seta hud_panel_notify_fontsize "1"
  seta hud_panel_notify_time "10"
  seta hud_panel_notify_fadetime "3"
+ seta hud_panel_notify_icon_aspect "2"
  
  seta hud_panel_timer 1
  seta hud_panel_timer_pos "0.850000 0"
@@@ -197,7 -198,9 +198,9 @@@ seta hud_panel_modicons_bg_color_team "
  seta hud_panel_modicons_bg_alpha ""
  seta hud_panel_modicons_bg_border ""
  seta hud_panel_modicons_bg_padding ""
+ seta hud_panel_modicons_ca_layout "1"
  seta hud_panel_modicons_dom_layout "1"
+ seta hud_panel_modicons_freezetag_layout "1"
  
  seta hud_panel_pressedkeys 1
  seta hud_panel_pressedkeys_pos "0.440000 0.760000"
@@@ -288,27 -291,19 +291,37 @@@ seta hud_panel_centerprint_fade_out "0.
  seta hud_panel_centerprint_fade_subsequent "1"
  seta hud_panel_centerprint_fade_subsequent_passone "3"
  seta hud_panel_centerprint_fade_subsequent_passone_minalpha "0.5"
- seta hud_panel_centerprint_fade_subsequent_passtwo "10" 
+ seta hud_panel_centerprint_fade_subsequent_passtwo "10"
  seta hud_panel_centerprint_fade_subsequent_passtwo_minalpha "0.5"
  seta hud_panel_centerprint_fade_subsequent_minfontsize "0.75"
  seta hud_panel_centerprint_fade_minfontsize "0"
  
+ seta hud_panel_buffs 1
+ seta hud_panel_buffs_pos "0.450000 0.855000"
+ seta hud_panel_buffs_size "0.050000 0.070000"
+ seta hud_panel_buffs_bg "0"
+ seta hud_panel_buffs_bg_color ""
+ seta hud_panel_buffs_bg_color_team ""
+ seta hud_panel_buffs_bg_alpha ""
+ seta hud_panel_buffs_bg_border ""
+ seta hud_panel_buffs_bg_padding ""
 +seta hud_panel_itemstime 2
 +seta hud_panel_itemstime_pos "0.000000 0.290000"
 +seta hud_panel_itemstime_size "0.150000 0.060000"
 +seta hud_panel_itemstime_bg "0"
 +seta hud_panel_itemstime_bg_color ""
 +seta hud_panel_itemstime_bg_color_team ""
 +seta hud_panel_itemstime_bg_alpha ""
 +seta hud_panel_itemstime_bg_border ""
 +seta hud_panel_itemstime_bg_padding ""
 +seta hud_panel_itemstime_iconalign "0"
 +seta hud_panel_itemstime_progressbar "0"
 +seta hud_panel_itemstime_progressbar_name "progressbar"
 +seta hud_panel_itemstime_progressbar_reduced "0"
 +seta hud_panel_itemstime_showspawned "0"
 +seta hud_panel_itemstime_text "1"
 +seta hud_panel_itemstime_ratio "2"
 +seta hud_panel_itemstime_size_dinamic "1"
 +
  menu_sync
index 6a6425a02d1760e3a93165fb4f1c56cff8a066a8,f06c5bfb3bd0f66e6dbc25ad67f201587b50a7c0..bf5e72be42292ecbc80713bb07b5ab93fab2d713
@@@ -54,15 -54,22 +54,22 @@@ float autocvar_cl_gunalign
  float autocvar_cl_hidewaypoints;
  float autocvar_cl_lockview;
  float autocvar_cl_nogibs;
+ float autocvar_cl_orthoview;
+ float autocvar_cl_orthoview_nofog;
  float autocvar_cl_particlegibs;
- float autocvar_cl_particles_oldnexbeam;
+ float autocvar_cl_particles_oldvortexbeam;
  float autocvar_cl_particles_quality;
  float autocvar_cl_projectiles_sloppy;
  float autocvar_cl_readpicture_force;
  var float autocvar_cl_reticle = 1;
- float autocvar_cl_reticle_item_nex;
- float autocvar_cl_reticle_item_normal;
+ var float autocvar_cl_reticle_normal_alpha = 1;
+ var float autocvar_cl_reticle_weapon = 1;
+ var float autocvar_cl_reticle_weapon_alpha = 1;
  float autocvar_cl_reticle_stretch;
+ float autocvar_cl_spawn_event_particles;
+ var float autocvar_cl_spawn_event_sound = 1;
+ // float autocvar_cl_spawn_point_model;
+ float autocvar_cl_spawn_point_particles;
  var float autocvar_cl_spawnzoom = 1;
  var float autocvar_cl_spawnzoom_speed = 1;
  var float autocvar_cl_spawnzoom_factor = 2;
@@@ -70,7 -77,8 +77,8 @@@ float autocvar_cl_stripcolorcodes
  var float autocvar_cl_vehicle_spiderbot_cross_alpha = 0.6;
  var float autocvar_cl_vehicle_spiderbot_cross_size = 1;
  var float autocvar_cl_vehicles_hud_tactical = 1;
- float autocvar_cl_velocityzoom;
+ float autocvar_cl_velocityzoom_enabled;
+ float autocvar_cl_velocityzoom_factor;
  var float autocvar_cl_velocityzoom_type = 3;
  float autocvar_cl_velocityzoom_speed;
  float autocvar_cl_velocityzoom_time;
@@@ -92,14 -100,16 +100,16 @@@ float autocvar_con_notifysize
  string autocvar_crosshair;
  float autocvar_crosshair_alpha;
  string autocvar_crosshair_color;
- float autocvar_crosshair_color_per_weapon;
+ float autocvar_crosshair_color_special;
+ var float autocvar_crosshair_color_special_rainbow_brightness = 2;
+ var float autocvar_crosshair_color_special_rainbow_delay = 0.1;
  float autocvar_crosshair_dot;
  float autocvar_crosshair_dot_alpha;
  string autocvar_crosshair_dot_color;
  var float autocvar_crosshair_dot_color_custom = 1;
  float autocvar_crosshair_dot_size;
  float autocvar_crosshair_effect_scalefade;
float autocvar_crosshair_effect_speed;
var float autocvar_crosshair_effect_time = 0.2;
  var float autocvar_crosshair_enabled = 1;
  float autocvar_crosshair_hitindication;
  string autocvar_crosshair_hitindication_color;
@@@ -107,6 -117,7 +117,7 @@@ string autocvar_crosshair_hitindication
  float autocvar_crosshair_hitindication_speed;
  float autocvar_crosshair_hittest;
  float autocvar_crosshair_hittest_blur;
+ var float autocvar_crosshair_hittest_scale = 1.25;
  float autocvar_crosshair_hittest_showimpact;
  float autocvar_crosshair_per_weapon;
  float autocvar_crosshair_pickup;
@@@ -117,14 -128,18 +128,18 @@@ float autocvar_crosshair_ring_minelayer
  float autocvar_crosshair_ring_minelayer_alpha;
  float autocvar_crosshair_ring_hagar;
  float autocvar_crosshair_ring_hagar_alpha;
- float autocvar_crosshair_ring_nex;
- float autocvar_crosshair_ring_nex_alpha;
- float autocvar_crosshair_ring_nex_currentcharge_movingavg_rate;
- float autocvar_crosshair_ring_nex_currentcharge_scale;
- float autocvar_crosshair_ring_nex_inner_alpha;
- float autocvar_crosshair_ring_nex_inner_color_blue;
- float autocvar_crosshair_ring_nex_inner_color_green;
- float autocvar_crosshair_ring_nex_inner_color_red;
+ var float autocvar_crosshair_ring_vortex = 1;
+ var float autocvar_crosshair_ring_vortex_alpha = 0.15;
+ var float autocvar_crosshair_ring_vortex_currentcharge_movingavg_rate = 0.05;
+ var float autocvar_crosshair_ring_vortex_currentcharge_scale = 30;
+ var float autocvar_crosshair_ring_vortex_inner_alpha = 0.15;
+ var float autocvar_crosshair_ring_vortex_inner_color_blue = 0;
+ var float autocvar_crosshair_ring_vortex_inner_color_green = 0;
+ var float autocvar_crosshair_ring_vortex_inner_color_red = 0.8;
+ var float autocvar_crosshair_ring_arc = 1;
+ var vector autocvar_crosshair_ring_arc_hot_color = '1 0 0';
+ var float autocvar_crosshair_ring_arc_cold_alpha = 0.2;
+ var float autocvar_crosshair_ring_arc_hot_alpha = 0.5;
  float autocvar_crosshair_ring_size;
  float autocvar_crosshair_ring_reload;
  float autocvar_crosshair_ring_reload_alpha;
@@@ -155,7 -170,6 +170,7 @@@ float autocvar_g_waypointsprite_edgeoff
  float autocvar_g_waypointsprite_edgeoffset_right;
  float autocvar_g_waypointsprite_edgeoffset_top;
  float autocvar_g_waypointsprite_fontsize;
 +float autocvar_g_waypointsprite_itemstime;
  float autocvar_g_waypointsprite_minalpha;
  float autocvar_g_waypointsprite_minscale;
  float autocvar_g_waypointsprite_normdistance;
@@@ -164,7 -178,6 +179,6 @@@ float autocvar_g_waypointsprite_spam
  float autocvar_g_waypointsprite_timealphaexponent;
  var float autocvar_g_waypointsprite_turrets = TRUE;
  var float autocvar_g_waypointsprite_turrets_maxdist = 5000;
  var float autocvar_hud_cursormode = TRUE;
  float autocvar_hud_colorflash_alpha;
  float autocvar_hud_configure_checkcollisions;
@@@ -253,23 -266,16 +267,26 @@@ float autocvar_hud_panel_healtharmor_pr
  float autocvar_hud_panel_healtharmor_text;
  float autocvar_hud_panel_infomessages;
  float autocvar_hud_panel_infomessages_flip;
 +float autocvar_hud_panel_itemstime;
 +float autocvar_hud_panel_itemstime_size_dinamic;
 +float autocvar_hud_panel_itemstime_ratio;
 +float autocvar_hud_panel_itemstime_iconalign;
 +float autocvar_hud_panel_itemstime_progressbar;
 +float autocvar_hud_panel_itemstime_progressbar_maxtime;
 +string autocvar_hud_panel_itemstime_progressbar_name;
 +float autocvar_hud_panel_itemstime_progressbar_reduced;
 +float autocvar_hud_panel_itemstime_showspawned;
 +float autocvar_hud_panel_itemstime_text;
  float autocvar_hud_panel_modicons;
+ float autocvar_hud_panel_modicons_ca_layout;
  float autocvar_hud_panel_modicons_dom_layout;
+ float autocvar_hud_panel_modicons_freezetag_layout;
  float autocvar_hud_panel_notify;
  float autocvar_hud_panel_notify_fadetime;
  float autocvar_hud_panel_notify_flip;
  float autocvar_hud_panel_notify_fontsize;
  float autocvar_hud_panel_notify_time;
+ float autocvar_hud_panel_notify_icon_aspect;
  float autocvar_hud_panel_physics;
  float autocvar_hud_panel_physics_acceleration_progressbar_mode;
  float autocvar_hud_panel_physics_acceleration_progressbar_scale;
@@@ -292,6 -298,8 +309,8 @@@ float autocvar_hud_panel_powerups_baral
  float autocvar_hud_panel_powerups_flip;
  float autocvar_hud_panel_powerups_iconalign;
  float autocvar_hud_panel_powerups_progressbar;
+ float autocvar_hud_panel_buffs;
+ //float autocvar_hud_panel_buffs_iconalign;
  string autocvar_hud_panel_powerups_progressbar_shield;
  string autocvar_hud_panel_powerups_progressbar_strength;
  string autocvar_hud_panel_powerups_progressbar_superweapons;
@@@ -313,6 -321,7 +332,7 @@@ float autocvar_hud_panel_score
  float autocvar_hud_panel_score_rankings;
  float autocvar_hud_panel_timer;
  float autocvar_hud_panel_timer_increment;
+ float autocvar_hud_panel_update_interval;
  float autocvar_hud_panel_vote;
  float autocvar_hud_panel_vote_alreadyvoted_alpha;
  string autocvar_hud_panel_vote_bg_alpha;
@@@ -322,6 -331,7 +342,7 @@@ float autocvar_hud_panel_weapons_ammo
  float autocvar_hud_panel_weapons_ammo_alpha;
  string autocvar_hud_panel_weapons_ammo_color;
  float autocvar_hud_panel_weapons_ammo_full_cells;
+ float autocvar_hud_panel_weapons_ammo_full_plasma;
  float autocvar_hud_panel_weapons_ammo_full_fuel;
  float autocvar_hud_panel_weapons_ammo_full_nails;
  float autocvar_hud_panel_weapons_ammo_full_rockets;
@@@ -340,9 -350,19 +361,19 @@@ float autocvar_hud_panel_weapons_timeou
  float autocvar_hud_panel_weapons_timeout_effect;
  float autocvar_hud_panel_weapons_timeout_fadebgmin;
  float autocvar_hud_panel_weapons_timeout_fadefgmin;
- var float autocvar_hud_panel_weapons_timeout_speed_in = 0.25; 
+ var float autocvar_hud_panel_weapons_timeout_speed_in = 0.25;
  var float autocvar_hud_panel_weapons_timeout_speed_out = 0.75;
+ vector autocvar_hud_progressbar_acceleration_color;
+ vector autocvar_hud_progressbar_acceleration_neg_color;
  float autocvar_hud_progressbar_alpha;
+ vector autocvar_hud_progressbar_armor_color;
+ vector autocvar_hud_progressbar_fuel_color;
+ vector autocvar_hud_progressbar_health_color;
+ vector autocvar_hud_progressbar_nexball_color;
+ vector autocvar_hud_progressbar_shield_color;
+ vector autocvar_hud_progressbar_speed_color;
+ vector autocvar_hud_progressbar_strength_color;
+ vector autocvar_hud_progressbar_superweapons_color;
  float autocvar_hud_showbinds;
  float autocvar_hud_showbinds_limit;
  float autocvar__hud_showbinds_reload;
@@@ -398,10 -418,13 +429,13 @@@ float autocvar_vid_conheight
  float autocvar_vid_conwidth;
  float autocvar_vid_pixelheight;
  float autocvar_viewsize;
- float autocvar_crosshair_color_by_health;
  float autocvar_cl_hitsound;
+ var float autocvar_cl_hitsound_min_pitch = 0.75; // minimal difference in minsta
+ var float autocvar_cl_hitsound_max_pitch = 1.5;
+ var float autocvar_cl_hitsound_nom_damage = 25;
  float autocvar_cl_hitsound_antispam_time;
  var float autocvar_cl_eventchase_death = 1;
+ var float autocvar_cl_eventchase_nexball = 1;
  var float autocvar_cl_eventchase_distance = 140;
  var float autocvar_cl_eventchase_speed = 1.3;
  var vector autocvar_cl_eventchase_maxs = '12 12 8';
@@@ -428,7 -451,15 +462,15 @@@ float autocvar_cl_forcemyplayercolors
  float autocvar__cl_color;
  float autocvar__cl_playerskin;
  string autocvar__cl_playermodel;
- float autocvar_cl_precacheplayermodels;
  float autocvar_cl_deathglow;
  float autocvar_developer_csqcentities;
  float autocvar_g_jetpack_attenuation;
+ var string autocvar_crosshair_hmg = ""; 
+ var vector autocvar_crosshair_hmg_color = '0.2 1.0 0.2';
+ var float autocvar_crosshair_hmg_alpha = 1;
+ var float autocvar_crosshair_hmg_size = 1;
+ var string autocvar_crosshair_rpc = ""; 
+ var vector autocvar_crosshair_rpc_color = '0.2 1.0 0.2';
+ var float autocvar_crosshair_rpc_alpha = 1;
+ var float autocvar_crosshair_rpc_size = 1;
+ float autocvar_cl_nade_timer;
diff --combined qcsrc/client/hud.qc
index 390fdb0dd8901efb708d5a02475ff281e37a22d3,8a9aab304c4b7fecf0f09ecc3857660aa97a33b1..9df07461c9bac2f400ef8bfbe8f756f36782739b
@@@ -142,16 -142,16 +142,16 @@@ float stringwidth_nocolors(string s, ve
        return stringwidth(s, FALSE, theSize);
  }
  
- void drawstringright(vector position, string text, vector scale, vector rgb, float theAlpha, float flag)
+ void drawstringright(vector position, string text, vector theScale, vector rgb, float theAlpha, float flag)
  {
-       position_x -= 2 / 3 * strlen(text) * scale_x;
-       drawstring(position, text, scale, rgb, theAlpha, flag);
+       position_x -= 2 / 3 * strlen(text) * theScale_x;
+       drawstring(position, text, theScale, rgb, theAlpha, flag);
  }
  
- void drawstringcenter(vector position, string text, vector scale, vector rgb, float theAlpha, float flag)
+ void drawstringcenter(vector position, string text, vector theScale, vector rgb, float theAlpha, float flag)
  {
-       position_x = 0.5 * (vid_conwidth - 0.6025 * strlen(text) * scale_x);
-       drawstring(position, text, scale, rgb, theAlpha, flag);
+       position_x = 0.5 * (vid_conwidth - 0.6025 * strlen(text) * theScale_x);
+       drawstring(position, text, theScale, rgb, theAlpha, flag);
  }
  
  // return the string of the onscreen race timer
@@@ -218,9 -218,9 +218,9 @@@ string MakeRaceString(float cp, float m
        if(histime < 0)
                return strcat(col, cpname);
        else if(hisname == "")
-               return strcat(col, sprintf(_("%s (%s)"), cpname, timestr));
+               return strcat(col, sprintf("%s (%s)", cpname, timestr));
        else
-               return strcat(col, sprintf(_("%s (%s %s)"), cpname, timestr, strcat(hisname, col, lapstr)));
+               return strcat(col, sprintf("%s (%s %s)", cpname, timestr, strcat(hisname, col, lapstr)));
  }
  
  // Check if the given name already exist in race rankings? In that case, where? (otherwise return 0)
@@@ -242,7 -242,7 +242,7 @@@ float GetPlayerColorForce(float i
  
  float GetPlayerColor(float i)
  {
-       if not(playerslots[i].gotscores) // unconnected
+       if(!playerslots[i].gotscores) // unconnected
                return NUM_SPECTATOR;
        else if(stof(getplayerkeyvalue(i, "frags")) == FRAGS_SPECTATOR)
                return NUM_SPECTATOR;
@@@ -264,8 -264,8 +264,8 @@@ HUD panel
  
  // draw the background/borders
  #define HUD_Panel_DrawBg(theAlpha)\
- 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 * theAlpha, '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER))
+ if(panel.current_panel_bg != "0" && panel.current_panel_bg != "")\
+       draw_BorderPicture(panel_pos - '1 1 0' * panel_bg_border, panel.current_panel_bg, panel_size + '1 1 0' * 2 * panel_bg_border, panel_bg_color, panel_bg_alpha * theAlpha, '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER))
  
  //basically the same code of draw_ButtonPicture and draw_VertButtonPicture for the menu
  void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, float vertical, float baralign, vector theColor, float theAlpha, float drawflag)
@@@ -408,47 -408,10 +408,10 @@@ float weaponorder_cmp(float i, float j
        return aj - ai; // the string is in REVERSE order (higher prio at the right is what we want, but higher prio first is the string)
  }
  
- float GetAmmoStat(float i)
- {
-       switch(i)
-       {
-               case 0: return STAT_SHELLS;
-               case 1: return STAT_NAILS;
-               case 2: return STAT_ROCKETS;
-               case 3: return STAT_CELLS;
-               case 4: return STAT_FUEL;
-               default: return -1;
-       }
- }
- float GetAmmoTypeForWep(float i)
- {
-       switch(i)
-       {
-               case WEP_SHOTGUN: return 0;
-               case WEP_UZI: return 1;
-               case WEP_GRENADE_LAUNCHER: return 2;
-               case WEP_MINE_LAYER: return 2;
-               case WEP_ELECTRO: return 3;
-               case WEP_CRYLINK: return 3;
-               case WEP_HLAC: return 3;
-               case WEP_MINSTANEX: return 3;
-               case WEP_NEX: return 3;
-               case WEP_RIFLE: return 1;
-               case WEP_HAGAR: return 2;
-               case WEP_ROCKET_LAUNCHER: return 2;
-               case WEP_SEEKER: return 2;
-               case WEP_FIREBALL: return 4;
-               case WEP_HOOK: return 3;
-               default: return -1;
-       }
- }
  void HUD_Weapons(void)
  {
        // declarations
-       WEPSET_DECLARE_A(weapons_stat);
-       WEPSET_COPY_AS(weapons_stat);
+       WepSet weapons_stat = WepSet_GetFromStat();
        float i, f, a;
        float screen_ar, center_x = 0, center_y;
        float weapon_count, weapon_id;
        float timein_effect_length = autocvar_hud_panel_weapons_timeout_speed_in; //? 0.375 : 0);
        float timeout_effect_length = autocvar_hud_panel_weapons_timeout_speed_out; //? 0.75 : 0);
  
-       float ammo_type, ammo_full;
+       float ammo_full;
        float barsize_x = 0, barsize_y = 0, baroffset_x = 0, baroffset_y = 0;
        vector ammo_color = '1 0 1';
        float ammo_alpha = 1;
                        return;
                }
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_WEAPONS;
  
        // update generic hud functions
-       HUD_Panel_UpdateCvars(weapons);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
  
        draw_beginBoldFont();
  
        {
                if(autocvar__hud_configure)
                {
-                       if (WEPSET_EMPTY_A(weapons_stat))
+                       if (!weapons_stat)
                                for(i = WEP_FIRST; i <= WEP_LAST; i += floor((WEP_LAST-WEP_FIRST)/5))
-                                       WEPSET_OR_AW(weapons_stat, i);
+                                       weapons_stat |= WepSet_FromWeapon(i);
  
                        if(menu_enabled != 2)
                                HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
                // do we own this weapon?
                weapon_count = 0;
                for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
-                       if(WEPSET_CONTAINS_AW(weapons_stat, weaponorder[i].weapon))
+                       if(weapons_stat & WepSet_FromWeapon(weaponorder[i].weapon))
                                ++weapon_count;
  
                // add it anyway if weaponcomplain is shown
                weapon_size_y = old_panel_size_y / rows;
  
                // change table values to include only the owned weapons
-               // weapon_size won't be changed
+               float columns_save = columns;
                if(weapon_count <= rows)
                {
                        rows = weapon_count;
                else
                        columns = ceil(weapon_count / rows);
  
+               // enlarge weapon_size to match desired aspect ratio in order to capitalize on panel space
+               if(columns < columns_save)
+                       weapon_size_x = min(old_panel_size_x / columns, aspect * weapon_size_y);
                // reduce size of the panel
                panel_size_x = columns * weapon_size_x;
                panel_size_y = rows * weapon_size_y;
  
                // skip this weapon if we don't own it (and onlyowned is enabled)-- or if weapons_complainbubble is showing for this weapon
                if(autocvar_hud_panel_weapons_onlyowned)
-               if not(WEPSET_CONTAINS_AW(weapons_stat, self.weapon) || (self.weapon == complain_weapon))
+               if (!((weapons_stat & WepSet_FromWeapon(self.weapon)) || (self.weapon == complain_weapon)))
                        continue;
  
                // figure out the drawing position of weapon
-               weapon_pos = (panel_pos 
-                       + eX * column * weapon_size_x 
+               weapon_pos = (panel_pos
+                       + eX * column * weapon_size_x
                        + eY * row * weapon_size_y);
  
                // draw background behind currently selected weapon
                }
  
                // drawing all the weapon items
-               if(WEPSET_CONTAINS_AW(weapons_stat, self.weapon))
+               if(weapons_stat & WepSet_FromWeapon(self.weapon))
                {
                        // draw the weapon image
-                       drawpic_aspect_skin(weapon_pos, strcat("weapon", self.netname), weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawpic_aspect_skin(weapon_pos, self.model2, weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
  
                        // draw weapon label string
                        switch(autocvar_hud_panel_weapons_label)
                                        break;
  
                                case 3: // weapon name
-                                       drawstring(weapon_pos, self.netname, '1 1 0' * 0.5 * weapon_size_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                                       drawstring(weapon_pos, strtolower(self.message), '1 1 0' * 0.5 * weapon_size_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                                        break;
  
                                default: // nothing
                        }
  
                        // draw ammo status bar
-                       if(autocvar_hud_panel_weapons_ammo && self.weapon != WEP_TUBA && self.weapon != WEP_LASER && self.weapon != WEP_PORTO)
+                       if(autocvar_hud_panel_weapons_ammo && (self.ammo_field != ammo_none))
                        {
-                               a = 0;
-                               ammo_type = GetAmmoTypeForWep(self.weapon);
-                               if(ammo_type != -1)
-                                       a = getstati(GetAmmoStat(ammo_type)); // how much ammo do we have?
+                               a = getstati(GetAmmoStat(self.ammo_field)); // how much ammo do we have?
  
                                if(a > 0)
                                {
-                                       switch(ammo_type) {
-                                               case 0: ammo_full = autocvar_hud_panel_weapons_ammo_full_shells; break;
-                                               case 1: ammo_full = autocvar_hud_panel_weapons_ammo_full_nails; break;
-                                               case 2: ammo_full = autocvar_hud_panel_weapons_ammo_full_rockets; break;
-                                               case 3: ammo_full = autocvar_hud_panel_weapons_ammo_full_cells; break;
-                                               case 4: ammo_full = autocvar_hud_panel_weapons_ammo_full_fuel; break;
+                                       switch(self.ammo_field)
+                                       {
+                                               case ammo_shells:  ammo_full = autocvar_hud_panel_weapons_ammo_full_shells;  break;
+                                               case ammo_nails:   ammo_full = autocvar_hud_panel_weapons_ammo_full_nails;   break;
+                                               case ammo_rockets: ammo_full = autocvar_hud_panel_weapons_ammo_full_rockets; break;
+                                               case ammo_cells:   ammo_full = autocvar_hud_panel_weapons_ammo_full_cells;   break;
+                                               case ammo_plasma:  ammo_full = autocvar_hud_panel_weapons_ammo_full_plasma;  break;
+                                               case ammo_fuel:    ammo_full = autocvar_hud_panel_weapons_ammo_full_fuel;    break;
                                                default: ammo_full = 60;
                                        }
  
                                                weapon_pos_x + baroffset_x,
                                                weapon_pos_y + baroffset_y,
                                                barsize_x * bound(0, a/ammo_full, 1),
-                                               barsize_y);
-                                       drawpic_aspect_skin(weapon_pos, "weapon_ammo", weapon_size, ammo_color, ammo_alpha, DRAWFLAG_NORMAL);
+                                               barsize_y
+                                       );
+                                       drawpic_aspect_skin(
+                                               weapon_pos,
+                                               "weapon_ammo",
+                                               weapon_size,
+                                               ammo_color,
+                                               ammo_alpha,
+                                               DRAWFLAG_NORMAL
+                                       );
                                        drawresetcliparea();
                                }
                        }
                }
                else // draw a "ghost weapon icon" if you don't have the weapon
                {
-                       drawpic_aspect_skin(weapon_pos, strcat("weapon", self.netname), weapon_size, '0 0 0', panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
+                       drawpic_aspect_skin(weapon_pos, self.model2, weapon_size, '0 0 0', panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
                }
  
                // draw the complain message
  }
  
  // Ammo (#1)
- //
- // TODO: macro
- float GetAmmoItemCode(float i)
+ void DrawNadeScoreBar(vector myPos, vector mySize, vector color)
  {
-       switch(i)
-       {
-               case 0: return IT_SHELLS;
-               case 1: return IT_NAILS;
-               case 2: return IT_ROCKETS;
-               case 3: return IT_CELLS;
-               case 4: return IT_FUEL;
-               default: return -1;
-       }
+       
+       HUD_Panel_DrawProgressBar(
+               myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize_x, 
+               mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize_x, 
+               autocvar_hud_panel_ammo_progressbar_name, 
+               getstatf(STAT_NADE_BONUS_SCORE), 0, 0, color, 
+               autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
  }
  
string GetAmmoPicture(float i)
void DrawAmmoNades(vector myPos, vector mySize, float draw_expanding, float expand_time)
  {
-       switch(i)
+       float theAlpha = 1, a, b;
+       vector nade_color, picpos, numpos;
+       
+       nade_color = Nade_Color(getstati(STAT_NADE_BONUS_TYPE));
+       
+       a = getstatf(STAT_NADE_BONUS);
+       b = getstatf(STAT_NADE_BONUS_SCORE);
+       
+       if(autocvar_hud_panel_ammo_iconalign)
        {
-               case 0: return "ammo_shells";
-               case 1: return "ammo_bullets";
-               case 2: return "ammo_rockets";
-               case 3: return "ammo_cells";
-               case 4: return "ammo_fuel";
-               default: return "";
+               numpos = myPos;
+               picpos = myPos + eX * 2 * mySize_y;
+       }
+       else
+       {
+               numpos = myPos + eX * mySize_y;
+               picpos = myPos;
+       }
+       DrawNadeScoreBar(myPos, mySize, nade_color);
+       if(b > 0 || a > 0)
+       {
+               if(autocvar_hud_panel_ammo_text)
+                       drawstring_aspect(numpos, ftos(a), eX * (2/3) * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+               
+               if(draw_expanding)
+                       drawpic_aspect_skin_expanding(picpos, "nade_nbg", '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, expand_time);
+                       
+               drawpic_aspect_skin(picpos, "nade_bg" , '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(picpos, "nade_nbg" , '1 1 0' * mySize_y, nade_color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
        }
  }
  
- void DrawAmmoItem(vector myPos, vector mySize, float itemcode, float currently_selected, float infinite_ammo)
+ void DrawAmmoItem(vector myPos, vector mySize, .float ammotype, float currently_selected, float infinite_ammo)
  {
-       float a;
-       if(autocvar__hud_configure)
+       float a = 0;
+       if(ammotype != ammo_none)
        {
-               currently_selected = (itemcode == 2); //rockets always selected
-               a = 31 + mod(itemcode*93, 128);
+               if(autocvar__hud_configure)
+               {
+                       currently_selected = (ammotype == ammo_rockets); //rockets always selected
+                       a = 60;
+               }
+               else
+               {
+                       // how much ammo do we have of this ammotype?
+                       a = getstati(GetAmmoStat(ammotype));
+               }
        }
        else
-               a = getstati(GetAmmoStat(itemcode)); // how much ammo do we have of type itemcode?
+       {
+               #if 0
+               infinite_ammo = TRUE;
+               #else
+               return; // just don't draw infinite ammo at all.
+               #endif
+       }
  
        vector color;
        if(infinite_ammo)
                picpos = myPos;
        }
  
-       if (currently_selected)
+       if(currently_selected)
                drawpic_aspect_skin(myPos, "ammo_current_bg", mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
  
-     if(a > 0 && autocvar_hud_panel_ammo_progressbar)
-         HUD_Panel_DrawProgressBar(myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize_x, mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize_x, autocvar_hud_panel_ammo_progressbar_name, a/autocvar_hud_panel_ammo_maxammo, 0, 0, color, autocvar_hud_progressbar_alpha * panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+       if(a > 0 && autocvar_hud_panel_ammo_progressbar)
+               HUD_Panel_DrawProgressBar(myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize_x, mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize_x, autocvar_hud_panel_ammo_progressbar_name, a/autocvar_hud_panel_ammo_maxammo, 0, 0, color, autocvar_hud_progressbar_alpha * panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
  
-     if(autocvar_hud_panel_ammo_text)
-     {
-         if(a > 0 || infinite_ammo)
-             drawstring_aspect(numpos, ftos(a), eX * (2/3) * mySize_x + eY * mySize_y, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
-         else // "ghost" ammo count
-             drawstring_aspect(numpos, ftos(a), eX * (2/3) * mySize_x + eY * mySize_y, '0 0 0', panel_fg_alpha * theAlpha * 0.5, DRAWFLAG_NORMAL);
-     }
+       if(autocvar_hud_panel_ammo_text)
+       {
+               if(a > 0 || infinite_ammo)
+                       drawstring_aspect(numpos, ftos(a), eX * (2/3) * mySize_x + eY * mySize_y, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+               else // "ghost" ammo count
+                       drawstring_aspect(numpos, ftos(a), eX * (2/3) * mySize_x + eY * mySize_y, '0 0 0', panel_fg_alpha * theAlpha * 0.5, DRAWFLAG_NORMAL);
+       }
        if(a > 0 || infinite_ammo)
-               drawpic_aspect_skin(picpos, GetAmmoPicture(itemcode), '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(picpos, GetAmmoPicture(ammotype), '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
        else // "ghost" ammo icon
-               drawpic_aspect_skin(picpos, GetAmmoPicture(itemcode), '1 1 0' * mySize_y, '0 0 0', panel_fg_alpha * theAlpha * 0.5, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(picpos, GetAmmoPicture(ammotype), '1 1 0' * mySize_y, '0 0 0', panel_fg_alpha * theAlpha * 0.5, DRAWFLAG_NORMAL);
  }
  
+ float nade_prevstatus;
+ float nade_prevframe;
+ float nade_statuschange_time;
  void HUD_Ammo(void)
  {
-     if(hud != HUD_NORMAL) return;
+       if(hud != HUD_NORMAL) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_ammo) return;
                if(spectatee_status == -1) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_AMMO;
  
-       HUD_Panel_UpdateCvars(ammo);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
  
        draw_beginBoldFont();
  
        }
  
        float rows = 0, columns, row, column;
+       float nade_cnt = getstatf(STAT_NADE_BONUS), nade_score = getstatf(STAT_NADE_BONUS_SCORE);
+       float draw_nades = (nade_cnt > 0 || nade_score > 0), nade_statuschange_elapsedtime;
+       float total_ammo_count;
        vector ammo_size;
        if (autocvar_hud_panel_ammo_onlycurrent)
-               ammo_size = mySize;
+               total_ammo_count = 1;
        else
+               total_ammo_count = AMMO_COUNT;
+       if(draw_nades)
        {
-               rows = mySize_y/mySize_x;
-               rows = bound(1, floor((sqrt(4 * (3/1) * rows * AMMO_COUNT + rows * rows) + rows + 0.5) / 2), AMMO_COUNT);
-               //                               ^^^ ammo item aspect goes here
+               ++total_ammo_count;
+               if (nade_cnt != nade_prevframe)
+               {
+                       nade_statuschange_time = time;
+                       nade_prevstatus = nade_prevframe;
+                       nade_prevframe = nade_cnt;
+               }
+       }
+       else
+               nade_prevstatus = nade_prevframe = nade_statuschange_time = 0;
+       rows = mySize_y/mySize_x;
+       rows = bound(1, floor((sqrt(4 * (3/1) * rows * (total_ammo_count) + rows * rows) + rows + 0.5) / 2), (total_ammo_count));
+       //                               ^^^ ammo item aspect goes here
  
-               columns = ceil(AMMO_COUNT/rows);
+       columns = ceil((total_ammo_count)/rows);
  
-               ammo_size = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
-       }
+       ammo_size = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
+       
  
        local vector offset = '0 0 0'; // fteqcc sucks
        float newSize;
                ammo_size_y = newSize;
        }
  
-       float i, stat_items, currently_selected, infinite_ammo;
-       infinite_ammo = FALSE;
-       if (autocvar_hud_panel_ammo_onlycurrent)
+       float i;
+       float infinite_ammo = (getstati(STAT_ITEMS, 0, 24) & IT_UNLIMITED_WEAPON_AMMO);
+       row = column = 0;
+       if(autocvar_hud_panel_ammo_onlycurrent)
        {
                if(autocvar__hud_configure)
                {
-                       DrawAmmoItem(pos, ammo_size, 2, true, FALSE); //show rockets
+                       DrawAmmoItem(pos, ammo_size, ammo_rockets, TRUE, FALSE);
                }
                else
                {
-                       stat_items = getstati(STAT_ITEMS, 0, 24);
-                       if (stat_items & IT_UNLIMITED_WEAPON_AMMO)
-                               infinite_ammo = TRUE;
-                       for (i = 0; i < AMMO_COUNT; ++i) {
-                               currently_selected = stat_items & GetAmmoItemCode(i);
-                               if (currently_selected)
-                               {
-                                       DrawAmmoItem(pos, ammo_size, i, true, infinite_ammo);
-                                       break;
-                               }
-                       }
+                       DrawAmmoItem(
+                               pos,
+                               ammo_size,
+                               (get_weaponinfo(switchweapon)).ammo_field,
+                               TRUE,
+                               infinite_ammo
+                       );
+               }
+               ++row;
+               if(row >= rows)
+               {
+                       row = 0;
+                       column = column + 1;
                }
        }
        else
        {
-               stat_items = getstati(STAT_ITEMS, 0, 24);
-               if (stat_items & IT_UNLIMITED_WEAPON_AMMO)
-                       infinite_ammo = TRUE;
+               .float ammotype;
                row = column = 0;
-               for (i = 0; i < AMMO_COUNT; ++i) {
-                       currently_selected = stat_items & GetAmmoItemCode(i);
-                       DrawAmmoItem(pos + eX * column * (ammo_size_x + offset_x) + eY * row * (ammo_size_y + offset_y), ammo_size, i, currently_selected, infinite_ammo);
+               for(i = 0; i < AMMO_COUNT; ++i)
+               {
+                       ammotype = GetAmmoFieldFromNum(i);
+                       DrawAmmoItem(
+                               pos + eX * column * (ammo_size_x + offset_x) + eY * row * (ammo_size_y + offset_y),
+                               ammo_size,
+                               ammotype,
+                               ((get_weaponinfo(switchweapon)).ammo_field == ammotype),
+                               infinite_ammo
+                       );
                        ++row;
                        if(row >= rows)
                        {
                }
        }
  
+       if (draw_nades)
+       {
+               nade_statuschange_elapsedtime = time - nade_statuschange_time;
+               float f = bound(0, nade_statuschange_elapsedtime*2, 1);
+               DrawAmmoNades(pos + eX * column * (ammo_size_x + offset_x) + eY * row * (ammo_size_y + offset_y), ammo_size, nade_prevstatus < nade_cnt && nade_cnt != 0 && f < 1, f);
+       }
        draw_endBoldFont();
  }
  
@@@ -1138,7 -1182,7 +1182,7 @@@ void HUD_Powerups(void
        {
                if(!autocvar_hud_panel_powerups) return;
                if(spectatee_status == -1) return;
-               if not(getstati(STAT_ITEMS, 0, 24) & (IT_STRENGTH | IT_INVINCIBLE | IT_SUPERWEAPON)) return;
+               if(!(getstati(STAT_ITEMS, 0, 24) & (IT_STRENGTH | IT_INVINCIBLE | IT_SUPERWEAPON))) return;
                if (getstati(STAT_HEALTH) <= 0) return;
  
                strength_time = bound(0, getstatf(STAT_STRENGTH_FINISHED) - time, 99);
        }
        else
        {
-               hud_configure_active_panel = HUD_PANEL_POWERUPS;
                strength_time = 15;
                shield_time = 27;
                superweapons_time = 13;
        }
  
-       HUD_Panel_UpdateCvars(powerups);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
  
        draw_beginBoldFont();
  
                const float maxshield = 30;
                float shield = ceil(shield_time);
                if(autocvar_hud_panel_powerups_progressbar)
-               {
-                       HUD_Panel_GetProgressBarColor(shield);
-                       HUD_Panel_DrawProgressBar(pos + shield_offset, mySize, autocvar_hud_panel_powerups_progressbar_shield, shield/maxshield, is_vertical, shield_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
+                       HUD_Panel_DrawProgressBar(pos + shield_offset, mySize, autocvar_hud_panel_powerups_progressbar_shield, shield/maxshield, is_vertical, shield_baralign, autocvar_hud_progressbar_shield_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                if(autocvar_hud_panel_powerups_text)
                {
                        if(shield > 1)
                const float maxstrength = 30;
                float strength = ceil(strength_time);
                if(autocvar_hud_panel_powerups_progressbar)
-               {
-                       HUD_Panel_GetProgressBarColor(strength);
-                       HUD_Panel_DrawProgressBar(pos + strength_offset, mySize, autocvar_hud_panel_powerups_progressbar_strength, strength/maxstrength, is_vertical, strength_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
+                       HUD_Panel_DrawProgressBar(pos + strength_offset, mySize, autocvar_hud_panel_powerups_progressbar_strength, strength/maxstrength, is_vertical, strength_baralign, autocvar_hud_progressbar_strength_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                if(autocvar_hud_panel_powerups_text)
                {
                        if(strength > 1)
                const float maxsuperweapons = 30;
                float superweapons = ceil(superweapons_time);
                if(autocvar_hud_panel_powerups_progressbar)
-               {
-                       HUD_Panel_GetProgressBarColor(superweapons);
-                       HUD_Panel_DrawProgressBar(pos + superweapons_offset, mySize, autocvar_hud_panel_powerups_progressbar_superweapons, superweapons/maxsuperweapons, is_vertical, superweapons_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
+                       HUD_Panel_DrawProgressBar(pos + superweapons_offset, mySize, autocvar_hud_panel_powerups_progressbar_superweapons, superweapons/maxsuperweapons, is_vertical, superweapons_baralign, autocvar_hud_progressbar_superweapons_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                if(autocvar_hud_panel_powerups_text)
                {
                        if(superweapons > 1)
@@@ -1397,15 -1429,12 +1429,12 @@@ void HUD_HealthArmor(void
        }
        else
        {
-               hud_configure_active_panel = HUD_PANEL_HEALTHARMOR;
                health = 150;
                armor = 75;
                fuel = 20;
        }
  
-       HUD_Panel_UpdateCvars(healtharmor);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
        if(autocvar_hud_panel_healtharmor == 2) // combined health and armor display
        {
                vector v;
-               v = healtharmor_maxdamage(health, armor, armorblockpercent);
+               v = healtharmor_maxdamage(health, armor, armorblockpercent, DEATH_WEAPON);
  
                float x;
                x = floor(v_x + 1);
                {
                        biggercount = "health";
                        if(autocvar_hud_panel_healtharmor_progressbar)
-                       {
-                               HUD_Panel_GetProgressBarColor(health);
-                               HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_health, x/maxtotal, 0, (baralign == 1 || baralign == 2), progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                       }
+                               HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_health, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                        if(armor)
              if(autocvar_hud_panel_healtharmor_text)
                                drawpic_aspect_skin(pos + eX * mySize_x - eX * 0.5 * mySize_y, "armor", '0.5 0.5 0' * mySize_y, '1 1 1', panel_fg_alpha * armor / health, DRAWFLAG_NORMAL);
                {
                        biggercount = "armor";
                        if(autocvar_hud_panel_healtharmor_progressbar)
-                       {
-                               HUD_Panel_GetProgressBarColor(armor);
-                               HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, x/maxtotal, 0, (baralign == 1 || baralign == 2), progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                       }
+                               HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                        if(health)
              if(autocvar_hud_panel_healtharmor_text)
                                drawpic_aspect_skin(pos + eX * mySize_x - eX * 0.5 * mySize_y, "health", '0.5 0.5 0' * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                        DrawNumIcon(pos, mySize, x, biggercount, 0, iconalign, HUD_Get_Num_Color(x, maxtotal), 1);
  
                if(fuel)
-               {
-                       HUD_Panel_GetProgressBarColor(fuel);
-                       HUD_Panel_DrawProgressBar(pos, eX * mySize_x + eY * 0.2 * mySize_y, "progressbar", fuel/100, 0, (baralign == 1 || baralign == 3), progressbar_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
-               }
+                       HUD_Panel_DrawProgressBar(pos, eX * mySize_x + eY * 0.2 * mySize_y, "progressbar", fuel/100, 0, (baralign == 1 || baralign == 3), autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
        }
        else
        {
                {
                        if(autocvar_hud_panel_healtharmor_progressbar)
                        {
-                               HUD_Panel_GetProgressBarColor(health);
                                float p_health, pain_health_alpha;
                                p_health = health;
                                pain_health_alpha = 1;
                                                if (time - health_damagetime < 1)
                                                {
                                                        float health_damagealpha = 1 - (time - health_damagetime)*(time - health_damagetime);
-                                                       HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, health_beforedamage/maxhealth, is_vertical, health_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * health_damagealpha, DRAWFLAG_NORMAL);
+                                                       HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, health_beforedamage/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * health_damagealpha, DRAWFLAG_NORMAL);
                                                }
                                        }
                                        prev_health = health;
                                        {
                                                float BLINK_FACTOR = 0.15;
                                                float BLINK_BASE = 0.85;
-                                               float BLINK_FREQ = 9; 
+                                               float BLINK_FREQ = 9;
                                                pain_health_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
                                        }
                                }
-                               HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, p_health/maxhealth, is_vertical, health_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * pain_health_alpha, DRAWFLAG_NORMAL);
+                               HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, p_health/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * pain_health_alpha, DRAWFLAG_NORMAL);
                        }
                        if(autocvar_hud_panel_healtharmor_text)
                                DrawNumIcon(pos + health_offset, mySize, health, "health", is_vertical, health_iconalign, HUD_Get_Num_Color(health, maxhealth), 1);
                {
                        if(autocvar_hud_panel_healtharmor_progressbar)
                        {
-                               HUD_Panel_GetProgressBarColor(armor);
                                float p_armor;
                                p_armor = armor;
                                if (autocvar_hud_panel_healtharmor_progressbar_gfx)
                                                if (time - armor_damagetime < 1)
                                                {
                                                        float armor_damagealpha = 1 - (time - armor_damagetime)*(time - armor_damagetime);
-                                                       HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, armor_beforedamage/maxarmor, is_vertical, armor_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * armor_damagealpha, DRAWFLAG_NORMAL);
+                                                       HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, armor_beforedamage/maxarmor, is_vertical, armor_baralign, autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * armor_damagealpha, DRAWFLAG_NORMAL);
                                                }
                                        }
                                        prev_armor = armor;
                                }
-                               HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, p_armor/maxarmor, is_vertical, armor_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                               HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, p_armor/maxarmor, is_vertical, armor_baralign, autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        if(autocvar_hud_panel_healtharmor_text)
                                DrawNumIcon(pos + armor_offset, mySize, armor, "armor", is_vertical, armor_iconalign, HUD_Get_Num_Color(armor, maxarmor), 1);
                                mySize_x *= 2; //restore full panel size
                        else if (panel_ar < 1/4)
                                mySize_y *= 2; //restore full panel size
-                       HUD_Panel_GetProgressBarColor(fuel);
-                       HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", fuel/100, is_vertical, fuel_baralign, progressbar_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
+                       HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", fuel/100, is_vertical, fuel_baralign, autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
                }
        }
  }
  
  void HUD_Notify_Push(string icon, string attacker, string victim)
  {
-       if(icon != "")
-       {
-               --kn_index;
-               if (kn_index == -1) { kn_index = KN_MAX_ENTRIES-1; }
-               notify_times[kn_index] = time;
+       if (icon == "")
+               return;
  
-               // icon
-               if(notify_icon[kn_index]) { strunzone(notify_icon[kn_index]); }
-               notify_icon[kn_index] = strzone(icon);
+       ++notify_count;
+       --notify_index;
  
-               // attacker
-               if(notify_attackers[kn_index]) { strunzone(notify_attackers[kn_index]); }
-               notify_attackers[kn_index] = strzone(attacker);
+       if (notify_index == -1)
+               notify_index = NOTIFY_MAX_ENTRIES-1;
  
-               // victim
-               if(notify_victims[kn_index]) { strunzone(notify_victims[kn_index]); }
-               notify_victims[kn_index] = strzone(victim);
-       }
- }
+       // Free old strings
+       if (notify_attackers[notify_index])
+               strunzone(notify_attackers[notify_index]);
  
- void HUD_Notify(void)
- {
-       if(!autocvar__hud_configure)
+       if (notify_victims[notify_index])
+               strunzone(notify_victims[notify_index]);
+       if (notify_icons[notify_index])
+               strunzone(notify_icons[notify_index]);
+       // Allocate new strings
+       if (victim != "")
        {
-               if(!autocvar_hud_panel_notify) return;
+               notify_attackers[notify_index] = strzone(attacker);
+               notify_victims[notify_index] = strzone(victim);
        }
        else
-               hud_configure_active_panel = HUD_PANEL_NOTIFY;
+       {
+               // In case of a notification without a victim, the attacker
+               // is displayed on the victim's side. Instead of special
+               // treatment later on, we can simply switch them here.
+               notify_attackers[notify_index] = string_null;
+               notify_victims[notify_index] = strzone(attacker);
+       }
  
-       HUD_Panel_UpdateCvars(notify);
-       HUD_Panel_ApplyFadeAlpha();
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
+       notify_icons[notify_index] = strzone(icon);
+       notify_times[notify_index] = time;
+ }
  
+ void HUD_Notify(void)
+ {
+       if (!autocvar__hud_configure)
+               if (!autocvar_hud_panel_notify)
+                       return;
+       HUD_Panel_UpdateCvars();
        HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
+       if (!autocvar__hud_configure)
+               if (notify_count == 0)
+                       return;
+       vector pos, size;
+       pos  = panel_pos;
+       size = panel_size;
+       if (panel_bg_padding)
        {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
+               pos  += '1 1 0' * panel_bg_padding;
+               size -= '2 2 0' * panel_bg_padding;
        }
  
-       float entries, height;
-       entries = bound(1, floor(KN_MAX_ENTRIES * mySize_y/mySize_x), KN_MAX_ENTRIES);
-       height = mySize_y/entries;
-       
-       vector fontsize;
-       float fontheight = height * autocvar_hud_panel_notify_fontsize;
-       fontsize = '0.5 0.5 0' * fontheight;
+       float fade_start = max(0, autocvar_hud_panel_notify_time);
+       float fade_time = max(0, autocvar_hud_panel_notify_fadetime);
+       float icon_aspect = max(1, autocvar_hud_panel_notify_icon_aspect);
  
-       float a;
-       float when;
-       when = autocvar_hud_panel_notify_time;
-       float fadetime;
-       fadetime = autocvar_hud_panel_notify_fadetime;
+       float entry_count = bound(1, floor(NOTIFY_MAX_ENTRIES * size_y / size_x), NOTIFY_MAX_ENTRIES);
+       float entry_height = size_y / entry_count;
+       float panel_width_half = size_x * 0.5;
+       float icon_width_half = entry_height * icon_aspect / 2;
+       float name_maxwidth = panel_width_half - icon_width_half - size_x * NOTIFY_ICON_MARGIN;
  
-       vector pos_attacker, pos_victim, pos_icon;
-       float width_attacker;
+       vector font_size = '0.5 0.5 0' * entry_height * autocvar_hud_panel_notify_fontsize;
+       vector icon_size = (eX * icon_aspect + eY) * entry_height;
+       vector icon_left = eX * (panel_width_half - icon_width_half);
+       vector attacker_right = eX * name_maxwidth;
+       vector victim_left = eX * (size_x - name_maxwidth);
+       vector attacker_pos, victim_pos, icon_pos;
        string attacker, victim, icon;
+       float i, j, count, step, limit, alpha;
  
-       float i, j, step, limit;
-       if(autocvar_hud_panel_notify_flip) //order items from the top down
+       if (autocvar_hud_panel_notify_flip)
        {
+               // Order items from the top down
                i = 0;
                step = +1;
-               limit = entries;
+               limit = entry_count;
        }
-       else //order items from the bottom up
+       else
        {
-               i = entries - 1;
+               // Order items from the bottom up
+               i = entry_count - 1;
                step = -1;
                limit = -1;
        }
  
-       for(j = kn_index;  i != limit;  i += step, ++j)
+       for (j = notify_index, count = 0; i != limit; i += step, ++j, ++count)
        {
                if(autocvar__hud_configure)
                {
-                       if (step == +1)
-                               a = i;
-                       else // inverse order
-                               a = entries - 1 - i;
-                       attacker = textShortenToWidth(sprintf(_("Player %d"), a+1), 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-                       victim = textShortenToWidth(sprintf(_("Player %d"), a+2), 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-                       icon = strcat("weapon", get_weaponinfo(WEP_FIRST + mod(floor(a*2.4), WEP_LAST)).netname);
-                       a = bound(0, (when - a) / 4, 1);
-                       goto hud_config_notifyprint;
+                       attacker = sprintf(_("Player %d"), count + 1);
+                       victim = sprintf(_("Player %d"), count + 2);
+                       icon = get_weaponinfo(min(WEP_FIRST + count * 2, WEP_LAST)).model2;
+                       alpha = bound(0, 1.2 - count / entry_count, 1);
                }
                else
                {
-                       if (j == KN_MAX_ENTRIES)
+                       if (j == NOTIFY_MAX_ENTRIES)
                                j = 0;
  
-                       if(notify_times[j] + when > time)
-                               a = 1;
-                       else if(fadetime)
+                       if (notify_times[j] + fade_start > time)
+                               alpha = 1;
+                       else if (fade_time != 0)
                        {
-                               a = bound(0, (notify_times[j] + when + fadetime - time) / fadetime, 1);
-                               if(!a)
-                               {
+                               alpha = bound(0, (notify_times[j] + fade_start + fade_time - time) / fade_time, 1);
+                               if (alpha == 0)
                                        break;
-                               }
                        }
                        else
-                       {
                                break;
-                       }
-                       
                        attacker = notify_attackers[j];
                        victim = notify_victims[j];
-                       icon = notify_icon[j];
+                       icon = notify_icons[j];
                }
  
-               //type = notify_deathtype[j];
-               //w = DEATH_WEAPONOF(type);
-               if(icon != "")
+               if (icon != "" && victim != "")
                {
-                       if((attacker != "") && (victim == ""))
-                       {
-                               // Y [used by] X
-                               attacker = textShortenToWidth(attacker, 0.73 * mySize_x - height, fontsize, stringwidth_colors);
-                               pos_attacker = pos + eX * (0.27 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
-                               pos_icon = pos + eX * 0.25 * mySize_x - eX * height + eY * i * height;
+                       vector name_top = eY * (i * entry_height + 0.5 * (entry_height - font_size_y));
  
-                               drawpic_aspect_skin(pos_icon, icon, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                               drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                       }
-                       else if((attacker != "") && (victim != ""))
+                       icon_pos = pos + icon_left + eY * i * entry_height;
+                       drawpic_aspect_skin(icon_pos, icon, icon_size, '1 1 1', panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+                       victim = textShortenToWidth(victim, name_maxwidth, font_size, stringwidth_colors);
+                       victim_pos = pos + victim_left + name_top;
+                       drawcolorcodedstring(victim_pos, victim, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+                       if (attacker != "")
                        {
-                               // X [did action to] Y
-                               attacker = textShortenToWidth(attacker, 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-                               victim = textShortenToWidth(victim, 0.48 * mySize_x - height, fontsize, stringwidth_colors);
- :hud_config_notifyprint
-                               width_attacker = stringwidth(attacker, TRUE, fontsize);
-                               pos_attacker = pos + eX * (0.48 * mySize_x - height - width_attacker) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
-                               pos_victim = pos + eX * (0.52 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
-                               pos_icon = pos + eX * 0.5 * mySize_x - eX * height + eY * i * height;
-                               drawpic_aspect_skin(pos_icon, icon, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                               drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                               drawcolorcodedstring(pos_victim, victim, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                               attacker = textShortenToWidth(attacker, name_maxwidth, font_size, stringwidth_colors);
+                               attacker_pos = pos + attacker_right - eX * stringwidth(attacker, TRUE, font_size) + name_top;
+                               drawcolorcodedstring(attacker_pos, attacker, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
                        }
                }
        }
+       notify_count = count;
  }
  
  // Timer (#5)
@@@ -1795,11 -1815,8 +1815,8 @@@ void HUD_Timer(void
        {
                if(!autocvar_hud_panel_timer) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_TIMER;
  
-       HUD_Panel_UpdateCvars(timer);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
  
        draw_beginBoldFont();
  
@@@ -1863,14 -1880,16 +1880,16 @@@ void HUD_Radar(void
                {
                        if (autocvar_hud_panel_radar == 0) return;
                        if (autocvar_hud_panel_radar != 2 && !teamplay) return;
+                       if(radar_panel_modified)
+                       {
+                               panel.update_time = time; // forces reload of panel attributes
+                               radar_panel_modified = false;
+                       }
                }
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_RADAR;
  
-       HUD_Panel_UpdateCvars(radar);
-       HUD_Panel_ApplyFadeAlpha();
-       
+       HUD_Panel_UpdateCvars();
        float f = 0;
  
        if (hud_panel_radar_maximized && !autocvar__hud_configure)
                panel_size_y = bound(0.2, panel_size_y, 1) * vid_conheight;
                panel_pos_x = (vid_conwidth - panel_size_x) / 2;
                panel_pos_y = (vid_conheight - panel_size_y) / 2;
-               
+               string panel_bg;
                panel_bg = strcat(hud_skin_path, "/border_default"); // always use the default border when maximized
-               if(precache_pic(panel_bg) == "") { panel_bg = "gfx/hud/default/border_default"; } // fallback
-               
+               if(precache_pic(panel_bg) == "")
+                       panel_bg = "gfx/hud/default/border_default"; // fallback
+               if(!radar_panel_modified && panel_bg != panel.current_panel_bg)
+                       radar_panel_modified = true;
+               if(panel.current_panel_bg)
+                       strunzone(panel.current_panel_bg);
+               panel.current_panel_bg = strzone(panel_bg);
                switch(hud_panel_radar_maximized_zoommode)
                {
                        default:
                                f = 1;
                                break;
                }
-               
                switch(hud_panel_radar_maximized_rotation)
                {
                        case 0:
                                f = 1;
                                break;
                }
-               
                switch(hud_panel_radar_rotation)
                {
                        case 0:
  // Score (#7)
  //
  void HUD_UpdatePlayerTeams();
- void HUD_Score_Rankings(vector pos, vector mySize, entity me, float team_count)
+ void HUD_Score_Rankings(vector pos, vector mySize, entity me)
  {
        float score;
        entity tm = world, pl;
@@@ -2159,11 -2185,8 +2185,8 @@@ void HUD_Score(void
                if(!autocvar_hud_panel_score) return;
                if(spectatee_status == -1 && (gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_SCORE;
  
-       HUD_Panel_UpdateCvars(score);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
        vector distribution_color;
        entity tm, pl, me;
  
- #ifdef COMPAT_XON050_ENGINE
-       me = (spectatee_status > 0) ? playerslots[spectatee_status - 1] : playerslots[player_localentnum - 1];
- #else
        me = playerslots[player_localentnum - 1];
- #endif
  
        if((scores_flags[ps_primary] & SFL_TIME) && !teamplay) { // race/cts record display on HUD
                string timer, distrtimer;
        } else if (!teamplay) { // non-teamgames
                if ((spectatee_status == -1 && !autocvar__hud_configure) || autocvar_hud_panel_score_rankings)
                {
-                       HUD_Score_Rankings(pos, mySize, me, 0);
+                       HUD_Score_Rankings(pos, mySize, me);
                        return;
                }
                // me vector := [team/connected frags id]
                drawstring_aspect(pos + eX * 0.75 * mySize_x, distribution_str, eX * 0.25 * mySize_x + eY * (1/3) * mySize_y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
                draw_endBoldFont();
        } else { // teamgames
-               float scores_count = 0, row, column, rows = 0, columns = 0;
+               float row, column, rows = 0, columns = 0;
                local noref vector offset = '0 0 0';
                vector score_pos, score_size; //for scores other than myteam
-               if (spectatee_status == -1 || autocvar_hud_panel_score_rankings)
+               if(autocvar_hud_panel_score_rankings)
+               {
+                       HUD_Score_Rankings(pos, mySize, me);
+                       return;
+               }
+               if(spectatee_status == -1)
                {
-                       for(tm = teams.sort_next; tm, tm.team != NUM_SPECTATOR; tm = tm.sort_next)
-                               ++scores_count;
-                       if (autocvar_hud_panel_score_rankings)
-                       {
-                               HUD_Score_Rankings(pos, mySize, me, scores_count);
-                               return;
-                       }
                        rows = mySize_y/mySize_x;
-                       rows = bound(1, floor((sqrt(4 * (3/1) * rows * scores_count + rows * rows) + rows + 0.5) / 2), scores_count);
+                       rows = bound(1, floor((sqrt(4 * (3/1) * rows * team_count + rows * rows) + rows + 0.5) / 2), team_count);
                        //                               ^^^ ammo item aspect goes here
  
-                       columns = ceil(scores_count/rows);
+                       columns = ceil(team_count/rows);
  
                        score_size = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
  
                        score = tm.(teamscores[ts_primary]);
                        if(autocvar__hud_configure)
                                score = 123;
-                       
                        if (score > max_fragcount)
                                max_fragcount = score;
  
@@@ -2356,11 -2373,8 +2373,8 @@@ void HUD_RaceTimer (void
                if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
                if(spectatee_status == -1) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_RACETIMER;
  
-       HUD_Panel_UpdateCvars(racetimer);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
  
        draw_beginBoldFont();
  
@@@ -2508,7 -2522,7 +2522,7 @@@ float vote_prev; // previous state of v
  float vote_alpha;
  float vote_change; // "time" when vote_active changed
  
- void HUD_VoteWindow(void) 
+ void HUD_Vote(void)
  {
        if(autocvar_cl_allow_uid2name == -1 && (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (serverflags & SERVERFLAG_PLAYERSTATS)))
        {
        }
        else
        {
-               hud_configure_active_panel = HUD_PANEL_VOTE;
                vote_yescount = 3;
                vote_nocount = 2;
                vote_needed = 4;
        if(!vote_alpha)
                return;
  
-       HUD_Panel_UpdateCvars(vote);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
  
        if(uid2name_dialog)
        {
  
  float mod_active; // is there any active mod icon?
  
- // Clan Arena HUD modicons
- void HUD_Mod_CA(vector pos, vector mySize)
+ void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, float layout, float i)
  {
-       mod_active = 1; // CA should never hide the mod icons panel
-       float redalive, bluealive;
-       redalive = getstati(STAT_REDALIVE);
-       bluealive = getstati(STAT_BLUEALIVE);
+       float stat;
+       string pic;
+       vector color;
+ #ifdef GMQCC
+       stat = -1;
+       pic = "";
+       color = '0 0 0';
+ #endif
+       switch(i)
+       {
+               case 0:
+                       stat = getstati(STAT_REDALIVE);
+                       pic = "player_red.tga";
+                       color = '1 0 0';
+                       break;
+               case 1:
+                       stat = getstati(STAT_BLUEALIVE);
+                       pic = "player_blue.tga";
+                       color = '0 0 1';
+                       break;
+               case 2:
+                       stat = getstati(STAT_YELLOWALIVE);
+                       pic = "player_yellow.tga";
+                       color = '1 1 0';
+                       break;
+               default:
+               case 3:
+                       stat = getstati(STAT_PINKALIVE);
+                       pic = "player_pink.tga";
+                       color = '1 0 1';
+                       break;
+       }
  
-       vector redpos, bluepos;
-       if(mySize_x > mySize_y)
+       if(mySize_x/mySize_y > aspect_ratio)
+       {
+               i = aspect_ratio * mySize_y;
+               myPos_x = myPos_x + (mySize_x - i) / 2;
+               mySize_x = i;
+       }
+       else
+       {
+               i = 1/aspect_ratio * mySize_x;
+               myPos_y = myPos_y + (mySize_y - i) / 2;
+               mySize_y = i;
+       }
+       if(layout)
        {
-               redpos = pos;
-               bluepos = pos + eY * 0.5 * mySize_y;
-               drawpic_aspect_skin(redpos, "player_red.tga", 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(redpos + eX * 0.5 * mySize_x, ftos(redalive), 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawpic_aspect_skin(bluepos, "player_blue.tga", 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(bluepos + eX * 0.5 * mySize_x, ftos(bluealive), 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(myPos, pic, eX * 0.7 * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(myPos + eX * 0.7 * mySize_x, ftos(stat), eX * 0.3 * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
        }
        else
+               drawstring_aspect(myPos, ftos(stat), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ // Clan Arena and Freeze Tag HUD modicons
+ void HUD_Mod_CA(vector myPos, vector mySize)
+ {
+       mod_active = 1; // required in each mod function that always shows something
+       float layout;
+       if(gametype == MAPINFO_TYPE_CA)
+               layout = autocvar_hud_panel_modicons_ca_layout;
+       else //if(gametype == MAPINFO_TYPE_FREEZETAG)
+               layout = autocvar_hud_panel_modicons_freezetag_layout;
+       float rows, columns, aspect_ratio;
+       rows = mySize_y/mySize_x;
+       aspect_ratio = (layout) ? 2 : 1;
+       rows = bound(1, floor((sqrt((4 * aspect_ratio * team_count + rows) * rows) + rows + 0.5) / 2), team_count);
+       columns = ceil(team_count/rows);
+       int i;
+       float row = 0, column = 0;
+       vector pos, itemSize;
+       itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
+       for(i=0; i<team_count; ++i)
        {
-               redpos = pos;
-               bluepos = pos + eY * 0.5 * mySize_y;
-               drawpic_aspect_skin(redpos, "player_red.tga", eX * mySize_x + eY * 0.3 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(redpos + eY * 0.3 * mySize_y, ftos(redalive), eX * mySize_x + eY * 0.2 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawpic_aspect_skin(bluepos, "player_blue.tga", eX * mySize_x + eY * 0.3 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(bluepos + eY * 0.3 * mySize_y, ftos(bluealive), eX * mySize_x + eY * 0.2 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               pos = myPos + eX * column * itemSize_x + eY * row * itemSize_y;
+               DrawCAItem(pos, itemSize, aspect_ratio, layout, i);
+               ++row;
+               if(row >= rows)
+               {
+                       row = 0;
+                       ++column;
+               }
        }
  }
  
@@@ -2705,7 -2779,7 +2779,7 @@@ void HUD_Mod_CTF(vector pos, vector myS
        stat_items = getstati(STAT_ITEMS, 0, 24);
        redflag = (stat_items/IT_RED_FLAG_TAKEN) & 3;
        blueflag = (stat_items/IT_BLUE_FLAG_TAKEN) & 3;
-       
        if(redflag || blueflag)
                mod_active = 1;
        else
@@@ -2982,29 -3056,29 +3056,29 @@@ void HUD_Mod_KH(vector pos, vector mySi
  float kaball_prevstatus; // last remembered status
  float kaball_statuschange_time; // time when the status changed
  
- // we don't need to reset for keepaway since it immediately 
+ // we don't need to reset for keepaway since it immediately
  // autocorrects prevstatus as to if the player has the ball or not
  
  void HUD_Mod_Keepaway(vector pos, vector mySize)
  {
        mod_active = 1; // keepaway should always show the mod HUD
-       
        float BLINK_FACTOR = 0.15;
        float BLINK_BASE = 0.85;
-       float BLINK_FREQ = 5; 
+       float BLINK_FREQ = 5;
        float kaball_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
-       
        float stat_items = getstati(STAT_ITEMS, 0, 24);
        float kaball = (stat_items/IT_KEY1) & 1;
-       
        if(kaball != kaball_prevstatus)
        {
                kaball_statuschange_time = time;
                kaball_prevstatus = kaball;
        }
-       
        vector kaball_pos, kaball_size;
-       
        if(mySize_x > mySize_y) {
                kaball_pos = pos + eX * 0.25 * mySize_x;
                kaball_size = eX * 0.5 * mySize_x + eY * mySize_y;
                kaball_pos = pos + eY * 0.25 * mySize_y;
                kaball_size = eY * 0.5 * mySize_y + eX * mySize_x;
        }
-       
        float kaball_statuschange_elapsedtime = time - kaball_statuschange_time;
        float f = bound(0, kaball_statuschange_elapsedtime*2, 1);
-       
        if(kaball_prevstatus && f < 1)
                drawpic_aspect_skin_expanding(kaball_pos, "keepawayball_carrying", kaball_size, '1 1 1', panel_fg_alpha * kaball_alpha, DRAWFLAG_NORMAL, f);
-       
        if(kaball)
                drawpic_aspect_skin(pos, "keepawayball_carrying", eX * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha * kaball_alpha * f, DRAWFLAG_NORMAL);
  }
@@@ -3040,18 -3114,13 +3114,13 @@@ void HUD_Mod_NexBall(vector pos, vecto
        //Manage the progress bar if any
        if (nb_pb_starttime > 0)
        {
-               dt = mod(time - nb_pb_starttime, nb_pb_period);
+               dt = (time - nb_pb_starttime) % nb_pb_period;
                // one period of positive triangle
                p = 2 * dt / nb_pb_period;
                if (p > 1)
                        p = 2 - p;
  
-               //Draw the filling
-               HUD_Panel_GetProgressBarColor(nexball);
-               if(mySize_x > mySize_y)
-                       HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", p, 0, 0, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-               else
-                       HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", p, 1, 0, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+               HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", p, (mySize_x <= mySize_y), 0, autocvar_hud_progressbar_nexball_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
        }
  
        if (stat_items & IT_KEY1)
@@@ -3076,7 -3145,7 +3145,7 @@@ void HUD_Mod_Race(vector pos, vector my
        float f; // yet another function has this
        score = me.(scores[ps_primary]);
  
-       if not((scores_flags[ps_primary] & SFL_TIME) && !teamplay) // race/cts record display on HUD
+       if(!(scores_flags[ps_primary] & SFL_TIME) || teamplay) // race/cts record display on HUD
                return; // no records in the actual race
  
        // clientside personal record
                if(autocvar_cl_autodemo_delete_keeprecords)
                {
                        f = autocvar_cl_autodemo_delete;
-                       f &~= 1;
+                       f &= ~1;
                        cvar_set("cl_autodemo_delete", ftos(f)); // don't delete demo with new record!
                }
        }
@@@ -3277,26 -3346,21 +3346,21 @@@ void DrawDomItem(vector myPos, vector m
  void HUD_Mod_Dom(vector myPos, vector mySize)
  {
        mod_active = 1; // required in each mod function that always shows something
-       entity tm;
-       float teams_count = 0;
-       for(tm = teams.sort_next; tm; tm = tm.sort_next)
-               if(tm.team != NUM_SPECTATOR)
-                       ++teams_count;
  
        float layout = autocvar_hud_panel_modicons_dom_layout;
        float rows, columns, aspect_ratio;
        rows = mySize_y/mySize_x;
        aspect_ratio = (layout) ? 3 : 1;
-       rows = bound(1, floor((sqrt((4 * aspect_ratio * teams_count + rows) * rows) + rows + 0.5) / 2), teams_count);
-       columns = ceil(teams_count/rows);
+       rows = bound(1, floor((sqrt((4 * aspect_ratio * team_count + rows) * rows) + rows + 0.5) / 2), team_count);
+       columns = ceil(team_count/rows);
  
        int i;
        float row = 0, column = 0;
-       for(i=0; i<teams_count; ++i)
+       vector pos, itemSize;
+       itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
+       for(i=0; i<team_count; ++i)
        {
-               vector pos, itemSize;
-               pos = myPos + eX * column * mySize_x*(1/columns) + eY * row * mySize_y*(1/rows);
-               itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
+               pos = myPos + eX * column * itemSize_x + eY * row * itemSize_y;
  
                DrawDomItem(pos, itemSize, aspect_ratio, layout, i);
  
        }
  }
  
+ void HUD_ModIcons_SetFunc()
+ {
+       switch(gametype)
+       {
+               case MAPINFO_TYPE_KEYHUNT:              HUD_ModIcons_GameType = HUD_Mod_KH; break;
+               case MAPINFO_TYPE_CTF:                  HUD_ModIcons_GameType = HUD_Mod_CTF; break;
+               case MAPINFO_TYPE_NEXBALL:              HUD_ModIcons_GameType = HUD_Mod_NexBall; break;
+               case MAPINFO_TYPE_CTS:
+               case MAPINFO_TYPE_RACE:         HUD_ModIcons_GameType = HUD_Mod_Race; break;
+               case MAPINFO_TYPE_CA:
+               case MAPINFO_TYPE_FREEZETAG:    HUD_ModIcons_GameType = HUD_Mod_CA; break;
+               case MAPINFO_TYPE_DOMINATION:   HUD_ModIcons_GameType = HUD_Mod_Dom; break;
+               case MAPINFO_TYPE_KEEPAWAY:     HUD_ModIcons_GameType = HUD_Mod_Keepaway; break;
+       }
+ }
  float mod_prev; // previous state of mod_active to check for a change
  float mod_alpha;
  float mod_change; // "time" when mod_active changed
@@@ -3318,20 -3398,13 +3398,13 @@@ void HUD_ModIcons(void
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_modicons) return;
-               if (gametype != MAPINFO_TYPE_CTF && gametype != MAPINFO_TYPE_KEYHUNT && gametype != MAPINFO_TYPE_NEXBALL && gametype != MAPINFO_TYPE_CTS && gametype != MAPINFO_TYPE_RACE && gametype != MAPINFO_TYPE_CA && gametype != MAPINFO_TYPE_FREEZETAG && gametype != MAPINFO_TYPE_KEEPAWAY && gametype != MAPINFO_TYPE_DOMINATION) return;
+               if(!HUD_ModIcons_GameType) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_MODICONS;
  
-       HUD_Panel_UpdateCvars(modicons);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
  
        draw_beginBoldFont();
  
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
        if(mod_active != mod_prev) {
                mod_change = time;
                mod_prev = mod_active;
  
        if(panel_bg_padding)
        {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
+               panel_pos += '1 1 0' * panel_bg_padding;
+               panel_size -= '2 2 0' * panel_bg_padding;
        }
  
-       // these MUST be ran in order to update mod_active
-       if(gametype == MAPINFO_TYPE_KEYHUNT)
-               HUD_Mod_KH(pos, mySize);
-       else if(gametype == MAPINFO_TYPE_CTF || autocvar__hud_configure)
-               HUD_Mod_CTF(pos, mySize); // forcealpha only needed for ctf icons, as only they are shown in config mode
-       else if(gametype == MAPINFO_TYPE_NEXBALL)
-               HUD_Mod_NexBall(pos, mySize);
-       else if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE)
-               HUD_Mod_Race(pos, mySize);
-       else if(gametype == MAPINFO_TYPE_CA || gametype == MAPINFO_TYPE_FREEZETAG)
-               HUD_Mod_CA(pos, mySize);
-       else if(gametype == MAPINFO_TYPE_DOMINATION)
-               HUD_Mod_Dom(pos, mySize);
-       else if(gametype == MAPINFO_TYPE_KEEPAWAY)
-               HUD_Mod_Keepaway(pos, mySize);
+       if(autocvar__hud_configure)
+               HUD_Mod_CTF(panel_pos, panel_size);
+       else
+               HUD_ModIcons_GameType(panel_pos, panel_size);
  
        draw_endBoldFont();
  }
  
  // Draw pressed keys (#11)
  //
- void HUD_DrawPressedKeys(void)
+ void HUD_PressedKeys(void)
  {
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_pressedkeys) return;
                if(spectatee_status <= 0 && autocvar_hud_panel_pressedkeys < 2) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_PRESSEDKEYS;
  
-       HUD_Panel_UpdateCvars(pressedkeys);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -3452,26 -3510,32 +3510,32 @@@ void HUD_Chat(void
                        return;
                }
                if(autocvar__con_chat_maximized)
+               {
                        if(!hud_draw_maximized) return;
+               }
+               else if(chat_panel_modified)
+               {
+                       panel.update_time = time; // forces reload of panel attributes
+                       chat_panel_modified = false;
+               }
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_CHAT;
  
-       HUD_Panel_UpdateCvars(chat);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
  
        if(autocvar__con_chat_maximized && !autocvar__hud_configure) // draw at full screen height if maximized
        {
                panel_pos_y = panel_bg_border;
                panel_size_y = vid_conheight - panel_bg_border * 2;
-               if(panel_bg == "0") // force a border when maximized
+               if(panel.current_panel_bg == "0") // force a border when maximized
                {
-                       if(precache_pic(panel_bg) == "") {
-                               panel_bg = strcat(hud_skin_path, "/border_default");
-                               if(precache_pic(panel_bg) == "") {
-                                       panel_bg = "gfx/hud/default/border_default";
-                               }
-                       }
+                       string panel_bg;
+                       panel_bg = strcat(hud_skin_path, "/border_default");
+                       if(precache_pic(panel_bg) == "")
+                               panel_bg = "gfx/hud/default/border_default";
+                       if(panel.current_panel_bg)
+                               strunzone(panel.current_panel_bg);
+                       panel.current_panel_bg = strzone(panel_bg);
+                       chat_panel_modified = true;
                }
                panel_bg_alpha = max(0.75, panel_bg_alpha); // force an theAlpha of at least 0.75
        }
@@@ -3530,11 -3594,8 +3594,8 @@@ void HUD_EngineInfo(void
        {
                if(!autocvar_hud_panel_engineinfo) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_ENGINEINFO;
  
-       HUD_Panel_UpdateCvars(engineinfo);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
                frametimeavg = (frametimeavg + frametimeavg1 + frametimeavg2 + currentframetime)/4; // average three frametimes into framecounter for slightly more stable fps readings :P
                frametimeavg2 = frametimeavg1;
                frametimeavg1 = frametimeavg;
-               
                float weight;
                weight = cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage_new_weight");
                if(currentframetime > 0.0001) // filter out insane values which sometimes seem to occur and throw off the average? If you are getting 10,000 fps or more, then you don't need a framerate counter.
@@@ -3593,11 -3654,8 +3654,8 @@@ void HUD_InfoMessages(void
        {
                if(!autocvar_hud_panel_infomessages) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_INFOMESSAGES;
  
-       HUD_Panel_UpdateCvars(infomessages);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
  
        vector fontsize;
        fontsize = '0.20 0.20 0' * mySize_y;
-       
        float a;
        a = panel_fg_alpha;
  
                        if(spectatee_status == -1)
                                s = _("^1Observing");
                        else
- #ifdef COMPAT_XON050_ENGINE
-                               s = sprintf(_("^1Spectating: ^7%s"), GetPlayerName(spectatee_status - 1));
- #else
                                s = sprintf(_("^1Spectating: ^7%s"), GetPlayerName(player_localentnum - 1));
- #endif
                        drawInfoMessage(s)
  
                        if(spectatee_status == -1)
                                s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey("primary fire", "+fire"));
                        else
-                               s = sprintf(_("^1Press ^3%s^1 for another player"), getcommandkey("primary fire", "+fire"));
+                               s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
                        drawInfoMessage(s)
  
                        if(spectatee_status == -1)
                        s = sprintf(_("^1Press ^3%s^1 for gamemode info"), getcommandkey("server info", "+show_info"));
                        drawInfoMessage(s)
  
-                       if(gametype == MAPINFO_TYPE_ARENA)
-                               s = _("^1Wait for your turn to join");
-                       else if(gametype == MAPINFO_TYPE_LMS)
+                       if(gametype == MAPINFO_TYPE_LMS)
                        {
                                entity sk;
                                sk = playerslots[player_localnum];
                }
  
                string blinkcolor;
-               if(mod(time, 1) >= 0.5)
+               if(time % 1 >= 0.5)
                        blinkcolor = "^1";
                else
                        blinkcolor = "^3";
                        }
                }
        }
-       else 
+       else
        {
                s = _("^7Press ^3ESC ^7to show HUD options.");
                drawInfoMessage(s)
@@@ -3784,11 -3836,8 +3836,8 @@@ void HUD_Physics(void
                if(spectatee_status == -1 && (autocvar_hud_panel_physics == 1 || autocvar_hud_panel_physics == 3)) return;
                if(autocvar_hud_panel_physics == 3 && !(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_PHYSICS;
  
-       HUD_Panel_UpdateCvars(physics);
-       HUD_Panel_ApplyFadeAlpha();
+       HUD_Panel_UpdateCvars();
  
        draw_beginBoldFont();
  
                        conversion_factor = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
                        break;
        }
-       
        vector vel = (csqcplayer ? csqcplayer.velocity : pmove_vel);
  
        float max_speed = floor( autocvar_hud_panel_physics_speed_max * conversion_factor + 0.5 );
                        acceleration = (vlen(vel) - vlen(acc_prevspeed));
                else
                        acceleration = (vlen(vel - '0 0 1' * vel_z) - vlen(acc_prevspeed - '0 0 1' * acc_prevspeed_z));
-               
                acceleration = acceleration * (1 / max(0.0001, f)) * (0.0254 / 9.80665);
-               
                acc_prevspeed = vel;
                acc_prevtime = time;
  
        //draw speed
        if(speed)
        if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
-       {
-               HUD_Panel_GetProgressBarColor(speed);
-               HUD_Panel_DrawProgressBar(panel_pos + speed_offset, panel_size, "progressbar", speed/max_speed, 0, speed_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-       }
+               HUD_Panel_DrawProgressBar(panel_pos + speed_offset, panel_size, "progressbar", speed/max_speed, 0, speed_baralign, autocvar_hud_progressbar_speed_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
        vector tmp_offset = '0 0 0', tmp_size = '0 0 0';
        if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
        {
                                        peak_offset_x = (1 - min(top_speed, max_speed)/max_speed) * panel_size_x;
                  else // if (speed_baralign == 2)
                      peak_offset_x = min(top_speed, max_speed)/max_speed * panel_size_x * 0.5;
-                               //if speed is not 0 the speed progressbar already fetched the color
-                               if (speed == 0)
-                                       HUD_Panel_GetProgressBarColor(speed);
                                peak_size_x = floor(panel_size_x * 0.01 + 1.5);
                  peak_size_y = panel_size_y;
                  if (speed_baralign == 2) // draw two peaks, on both sides
                  {
-                     drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size_x + peak_offset_x - peak_size_x), peak_size, progressbar_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                     drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size_x - peak_offset_x + peak_size_x), peak_size, progressbar_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                     drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size_x + peak_offset_x - peak_size_x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                     drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size_x - peak_offset_x + peak_size_x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                  }
                  else
-                     drawfill(panel_pos + speed_offset + eX * (peak_offset_x - peak_size_x), peak_size, progressbar_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                     drawfill(panel_pos + speed_offset + eX * (peak_offset_x - peak_size_x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
  
                        //top speed
        if(acceleration)
        if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 3)
        {
-               if (acceleration < 0)
-                       HUD_Panel_GetProgressBarColor(acceleration_neg);
+               vector progressbar_color;
+               if(acceleration < 0)
+                       progressbar_color = autocvar_hud_progressbar_acceleration_neg_color;
                else
-                       HUD_Panel_GetProgressBarColor(acceleration);
+                       progressbar_color = autocvar_hud_progressbar_acceleration_color;
  
                f = acceleration/autocvar_hud_panel_physics_acceleration_max;
                if (autocvar_hud_panel_physics_acceleration_progressbar_nonlinear)
@@@ -4063,7 -4107,7 +4107,7 @@@ float centerprint_showing
  
  void centerprint_generic(float new_id, string strMessage, float duration, float countdown_num)
  {
-       //print(sprintf("centerprint_generic(%d, '%s^7', %d, %d);\n", new_id, strMessage, duration, countdown_num));
+       //printf("centerprint_generic(%d, '%s^7', %d, %d);\n", new_id, strMessage, duration, countdown_num);
        float i, j;
  
        if(strMessage == "" && new_id == 0)
@@@ -4167,17 -4211,15 +4211,15 @@@ void HUD_CenterPrint (void
        }
        else
        {
-               hud_configure_active_panel = HUD_PANEL_CENTERPRINT;
                if (!hud_configure_prev)
                        reset_centerprint_messages();
                if (time > hud_configure_cp_generation_time)
                {
                        float r;
                        r = random();
-                       if (r > 0.9)
-                               centerprint_generic(floor(r*1000), strcat(sprintf("^3Countdown message at time %s", seconds_tostring(time)), ", seconds left: %d"), 1, 10);
-                       else if (r > 0.8)
+                       if (r > 0.75)
+                               centerprint_generic(floor(r*1000), strcat(sprintf("^3Countdown message at time %s", seconds_tostring(time)), ", seconds left: ^COUNT"), 1, 10);
+                       else if (r > 0.5)
                                centerprint_generic(0, sprintf("^1Multiline message at time %s that\n^1lasts longer than normal", seconds_tostring(time)), 20, 0);
                        else
                                centerprint_hud(sprintf("Message at time %s", seconds_tostring(time)));
                }
        }
  
-       HUD_Panel_UpdateCvars(centerprint);
-       // this panel doesn't fade when showing the scoreboard
-       if(autocvar__menu_alpha)
-               HUD_Panel_ApplyFadeAlpha();
+       // this panel fades only when the menu does
+       float hud_fade_alpha_save = 0;
+       if(scoreboard_fade_alpha)
+       {
+               hud_fade_alpha_save = hud_fade_alpha;
+               hud_fade_alpha = 1 - autocvar__menu_alpha;
+       }
+       HUD_Panel_UpdateCvars();
  
        if(scoreboard_fade_alpha)
        {
+               hud_fade_alpha = hud_fade_alpha_save;
                // move the panel below the scoreboard
                if (scoreboard_bottom >= 0.96 * vid_conheight)
                        return;
                vector target_pos;
-               
                target_pos = eY * scoreboard_bottom + eX * 0.5 * (vid_conwidth - panel_size_x);
-               
                if(target_pos_y > panel_pos_y)
                {
                        panel_pos = panel_pos + (target_pos - panel_pos) * sqrt(scoreboard_fade_alpha);
        float a, sz, align, current_msg_pos_y = 0, msg_size;
        vector pos;
        string ts;
-       n = -1; // if no msg will be displayed, n stays -1
+       float all_messages_expired = TRUE;
  
        pos = panel_pos;
        if (autocvar_hud_panel_centerprint_flip)
                                continue;
                }
  
+               all_messages_expired = FALSE;
  
-               // fade the centerprint_hud in/out 
-               if(centerprint_time[j] < 0)
-                       a = bound(0, (time - centerprint_expire_time[j]) / max(0.0001, autocvar_hud_panel_centerprint_fade_in), 1);
-               else if(centerprint_expire_time[j] - autocvar_hud_panel_centerprint_fade_out > time)
-                       a = bound(0, (time - (centerprint_expire_time[j] - centerprint_time[j])) / max(0.0001, autocvar_hud_panel_centerprint_fade_in), 1);
-               else if(centerprint_expire_time[j] > time)
+               // fade the centerprint_hud in/out
+               if(centerprint_time[j] < 0)  // Expired but forced. Expire time is the fade-in time.
+                       a = (time - centerprint_expire_time[j]) / max(0.0001, autocvar_hud_panel_centerprint_fade_in);
+               else if(centerprint_expire_time[j] - autocvar_hud_panel_centerprint_fade_out > time)  // Regularily printed. Not fading out yet.
+                       a = (time - (centerprint_expire_time[j] - centerprint_time[j])) / max(0.0001, autocvar_hud_panel_centerprint_fade_in);
+               else // Expiring soon, so fade it out.
                        a = (centerprint_expire_time[j] - time) / max(0.0001, autocvar_hud_panel_centerprint_fade_out);
-               else
-                       a = 0;
-               
+               // while counting down show it anyway in order to hold the current message position
+               if (a <= 0.5/255.0 && centerprint_countdown_num[j] == 0)  // Guaranteed invisible - don't show.
+                       continue;
+               if (a > 1)
+                       a = 1;
                // set the size from fading in/out before subsequent fading
-               sz = autocvar_hud_panel_centerprint_fade_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_minfontsize); 
-               
+               sz = autocvar_hud_panel_centerprint_fade_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_minfontsize);
                // also fade it based on positioning
                if(autocvar_hud_panel_centerprint_fade_subsequent)
                {
                        a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passone))), 1); // pass one: all messages after the first have half theAlpha
                        a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passtwo))), 1); // pass two: after that, gradually lower theAlpha even more for each message
                }
-               
+               a *= panel_fg_alpha;
                // finally set the size based on the new theAlpha from subsequent fading
-               sz = sz * (autocvar_hud_panel_centerprint_fade_subsequent_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_subsequent_minfontsize)); 
+               sz = sz * (autocvar_hud_panel_centerprint_fade_subsequent_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_subsequent_minfontsize));
                drawfontscale = sz * '1 1 0';
-               
                if (centerprint_countdown_num[j])
                        n = tokenizebyseparator(strreplace("^COUNT", count_seconds(centerprint_countdown_num[j]), centerprint_messages[j]), "\n");
                else
                                {
                                        if (align)
                                                pos_x = panel_pos_x + (panel_size_x - stringwidth(ts, TRUE, fontsize)) * align;
-                                       drawcolorcodedstring(pos + eY * 0.5 * (1 - sz) * fontsize_y, ts, fontsize, a * panel_fg_alpha, DRAWFLAG_NORMAL);
+                                       if (a > 0.5/255.0)  // Otherwise guaranteed invisible - don't show. This is checked a second time after some multiplications with other factors were done so temporary changes of these cannot cause flicker.
+                                               drawcolorcodedstring(pos + eY * 0.5 * (1 - sz) * fontsize_y, ts, fontsize, a, DRAWFLAG_NORMAL);
                                        pos_y += fontsize_y;
                                }
                                else
                        }
                }
  
-               ++g; // move next position number up 
-               
+               ++g; // move next position number up
                msg_size = pos_y - msg_size;
                if (autocvar_hud_panel_centerprint_flip)
                {
                        pos_y = current_msg_pos_y - CENTERPRINT_SPACING * fontsize_y;
                        if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
                                pos_y += (msg_size + CENTERPRINT_SPACING * fontsize_y) * (1 - sqrt(sz));
-                               
                        if (pos_y < panel_pos_y) // check if the next message can be shown
                        {
                                drawfontscale = '1 1 0';
                        pos_y += CENTERPRINT_SPACING * fontsize_y;
                        if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
                                pos_y -= (msg_size + CENTERPRINT_SPACING * fontsize_y) * (1 - sqrt(sz));
-                               
                        if(pos_y > panel_pos_y + panel_size_y - fontsize_y) // check if the next message can be shown
                        {
                                drawfontscale = '1 1 0';
                }
        }
        drawfontscale = '1 1 0';
-       if (n == -1)
+       if (all_messages_expired)
        {
                centerprint_showing = FALSE;
                reset_centerprint_messages();
        }
  }
  
+ // Buffs (#18)
+ //
+ void HUD_Buffs(void)
+ {
+       float buffs = getstati(STAT_BUFFS, 0, 24);
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_buffs) return;
+               if(spectatee_status == -1) return;
+               if(getstati(STAT_HEALTH) <= 0) return;
+               if(!buffs) return;
+       }
+       else
+       {
+               buffs = Buff_Type_first.items; // force first buff
+       }
+       
+       float b = 0; // counter to tell other functions that we have buffs
+       entity e;
+       string s = "";
+       for(e = Buff_Type_first; e; e = e.enemy) if(buffs & e.items)
+       {
+               ++b;
+               string o = strcat(rgb_to_hexcolor(Buff_Color(e.items)), Buff_PrettyName(e.items));
+               if(s == "")
+                       s = o;
+               else
+                       s = strcat(s, " ", o);
+       }
+       HUD_Panel_UpdateCvars();
+       draw_beginBoldFont();
+       vector pos, mySize;
+       pos = panel_pos;
+       mySize = panel_size;
+       HUD_Panel_DrawBg(bound(0, b, 1));
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               mySize -= '2 2 0' * panel_bg_padding;
+       }
+       //float panel_ar = mySize_x/mySize_y;
+       //float is_vertical = (panel_ar < 1);
+       //float buff_iconalign = autocvar_hud_panel_buffs_iconalign;
+       vector buff_offset = '0 0 0';
+       
+       for(e = Buff_Type_first; e; e = e.enemy) if(buffs & e.items)
+       {
+               //DrawNumIcon(pos + buff_offset, mySize, shield, "shield", is_vertical, buff_iconalign, '1 1 1', 1);
+               drawcolorcodedstring_aspect(pos + buff_offset, s, mySize, panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
+       }
+       draw_endBoldFont();
+ }
  
- // ItemsTime (#17)
++// ItemsTime (#XX)
 +//
 +const float ITEMSTIME_MAXITEMS = 10;
 +float ItemsTime_time[ITEMSTIME_MAXITEMS];
 +string GetItemsTimePicture(float i)
 +{
 +      switch(i)
 +      {
 +              case 0: return "item_large_armor";
 +              case 1: return "item_mega_health";
 +              case 2: return "item_strength";
 +              case 3: return "item_shield";
 +              case 4: return "item_mega_health";
 +              case 5: return "item_strength";
 +              case 6: return "item_shield";
 +              case 7: return "fuelregen";
 +              case 8: return "jetpack";
 +              case 9: return "superweapons";
 +              default: return "";
 +      }
 +}
 +
 +void DrawItemsTimeItem(vector myPos, vector mySize, float ar, float itemcode)
 +{
 +      float t = 0;
 +      vector color = '0 0 0';
 +      float picalpha;
 +      if(ItemsTime_time[itemcode] <= time)
 +      {
 +              float BLINK_FACTOR = 0.15;
 +              float BLINK_BASE = 0.85;
 +              float BLINK_FREQ = 5;
 +              picalpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
 +      }
 +      else
 +      {
 +              picalpha = 1;
 +              t = floor(ItemsTime_time[itemcode] - time + 0.999);
 +              if(t < 5)
 +                      color = '0.7 0 0';
 +              else if(t < 10)
 +                      color = '0.7 0.7 0';
 +              else
 +                      color = '1 1 1';
 +      }
 +
 +      vector picpos, numpos;
 +      if(autocvar_hud_panel_itemstime_iconalign)
 +      {
 +              numpos = myPos;
 +              picpos = myPos + eX * (ar - 1) * mySize_y;
 +      }
 +      else
 +      {
 +              numpos = myPos + eX * mySize_y;
 +              picpos = myPos;
 +      }
 +
 +      if(t > 0 && autocvar_hud_panel_itemstime_progressbar)
 +      {
 +              vector p_pos, p_size;
 +              if(autocvar_hud_panel_itemstime_progressbar_reduced)
 +              {
 +                      p_pos = numpos;
 +                      p_size = eX * ((ar - 1)/ar) * mySize_x + eY * mySize_y;
 +              }
 +              else
 +              {
 +                      p_pos = myPos;
 +                      p_size = mySize;
 +              }
 +              HUD_Panel_DrawProgressBar(p_pos, p_size, autocvar_hud_panel_itemstime_progressbar_name, t/autocvar_hud_panel_itemstime_progressbar_maxtime, 0, autocvar_hud_panel_itemstime_iconalign, color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
 +      }
 +
 +      if(t > 0 && autocvar_hud_panel_itemstime_text)
 +              drawstring_aspect(numpos, ftos(t), eX * ((ar - 1)/ar) * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
 +      drawpic_aspect_skin(picpos, GetItemsTimePicture(itemcode), '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * picalpha, DRAWFLAG_NORMAL);
 +}
 +
 +void HUD_ItemsTime(void)
 +{
 +      if(!autocvar__hud_configure)
 +      {
-               if not(autocvar_hud_panel_itemstime == 1 && spectatee_status != 0
-               || autocvar_hud_panel_itemstime == 2 && (spectatee_status != 0 || warmup_stage))
++              if not((autocvar_hud_panel_itemstime == 1 && spectatee_status != 0)
++              || (autocvar_hud_panel_itemstime == 2 && (spectatee_status != 0 || warmup_stage)))
 +                      return;
 +
 +              ItemsTime_time[0] = getstatf(STAT_ARMOR_LARGE_TIME);
 +              ItemsTime_time[1] = getstatf(STAT_HEALTH_MEGA_TIME);
 +              ItemsTime_time[2] = getstatf(STAT_INVISIBLE_TIME);
 +              ItemsTime_time[3] = getstatf(STAT_SPEED_TIME);
 +              ItemsTime_time[4] = getstatf(STAT_EXTRALIFE_TIME);
 +              ItemsTime_time[5] = getstatf(STAT_STRENGTH_TIME);
 +              ItemsTime_time[6] = getstatf(STAT_SHIELD_TIME);
 +              ItemsTime_time[7] = getstatf(STAT_FUELREGEN_TIME);
 +              ItemsTime_time[8] = getstatf(STAT_JETPACK_TIME);
 +              ItemsTime_time[9] = getstatf(STAT_SUPERWEAPONS_TIME);
 +      }
 +      else
 +      {
-               hud_configure_active_panel = HUD_PANEL_ITEMSTIME;
 +              // do not show here mutator-dependent items
 +              ItemsTime_time[0] = time + 0;
 +              ItemsTime_time[1] = time + 8;
 +              ItemsTime_time[2] = -1; // mutator-dependent
 +              ItemsTime_time[3] = -1; // mutator-dependent
 +              ItemsTime_time[4] = -1; // mutator-dependent
 +              ItemsTime_time[5] = time + 0;
 +              ItemsTime_time[6] = time + 4;
 +              ItemsTime_time[7] = time + 49;
 +              ItemsTime_time[8] = -1;
 +              ItemsTime_time[9] = time + 28;
 +      }
 +
 +      float i;
 +      float count = 0;
 +      if (autocvar_hud_panel_itemstime_showspawned)
 +              for (i = 0; i < ITEMSTIME_MAXITEMS; ++i)
 +                      count += (ItemsTime_time[i] != -1);
 +      else
 +              for (i = 0; i < ITEMSTIME_MAXITEMS; ++i)
 +                      count += (ItemsTime_time[i] > time);
 +      if (count == 0)
 +              return;
 +
-       HUD_Panel_UpdateCvars(itemstime);
-       HUD_Panel_ApplyFadeAlpha();
++      HUD_Panel_UpdateCvars();
++
 +      vector pos, mySize;
 +      pos = panel_pos;
 +      mySize = panel_size;
 +
 +      if(panel_bg_padding)
 +      {
 +              pos += '1 1 0' * panel_bg_padding;
 +              mySize -= '2 2 0' * panel_bg_padding;
 +      }
 +
 +      float rows, columns;
 +      float ar = max(2, autocvar_hud_panel_itemstime_ratio) + 1;
 +      rows = mySize_y/mySize_x;
 +      rows = bound(1, floor((sqrt(4 * ar * rows * count + rows * rows) + rows + 0.5) / 2), count);
 +
 +      columns = ceil(count/rows);
 +
 +      vector itemstime_size;
 +      itemstime_size = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
 +
 +      vector offset = '0 0 0';
 +      float newSize;
 +      if(autocvar_hud_panel_itemstime_size_dinamic)
 +      {
 +              if(autocvar__hud_configure)
 +              if(menu_enabled != 2)
 +                      HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
 +
 +              // reduce panel to avoid spacing items
 +              if(itemstime_size_x / itemstime_size_y < ar)
 +              {
 +                      newSize = rows * itemstime_size_x / ar;
 +                      pos_y += (mySize_y - newSize) / 2;
 +                      mySize_y = newSize;
 +                      itemstime_size_y = mySize_y / rows;
 +              }
 +              else
 +              {
 +                      newSize = columns * itemstime_size_y * ar;
 +                      pos_x += (mySize_x - newSize) / 2;
 +                      mySize_x = newSize;
 +                      itemstime_size_x = mySize_x / columns;
 +              }
 +              panel_pos = pos - '1 1 0' * panel_bg_padding;
 +              panel_size = mySize + '2 2 0' * panel_bg_padding;
 +      }
 +      else
 +      {
 +              if(itemstime_size_x/itemstime_size_y > ar)
 +              {
 +                      newSize = ar * itemstime_size_y;
 +                      offset_x = itemstime_size_x - newSize;
 +                      pos_x += offset_x/2;
 +                      itemstime_size_x = newSize;
 +              }
 +              else
 +              {
 +                      newSize = 1/ar * itemstime_size_x;
 +                      offset_y = itemstime_size_y - newSize;
 +                      pos_y += offset_y/2;
 +                      itemstime_size_y = newSize;
 +              }
 +      }
 +
 +      HUD_Panel_DrawBg(1);
 +
 +      float row = 0, column = 0;
 +      for (i = 0; i < ITEMSTIME_MAXITEMS; ++i) {
 +              if (ItemsTime_time[i] == -1)
 +                      continue;
 +              if (!autocvar_hud_panel_itemstime_showspawned)
 +                      if (ItemsTime_time[i] <= time)
 +                              continue;
 +              DrawItemsTimeItem(pos + eX * column * (itemstime_size_x + offset_x) + eY * row * (itemstime_size_y + offset_y), itemstime_size, ar, i);
 +              ++row;
 +              if(row >= rows)
 +              {
 +                      row = 0;
 +                      column = column + 1;
 +              }
 +      }
 +}
  
  /*
  ==================
@@@ -4585,46 -4486,6 +4694,6 @@@ void HUD_Reset (void
                HUD_Mod_CTF_Reset();
  }
  
- #define HUD_DrawPanel(id)\
- switch (id) {\
-       case (HUD_PANEL_RADAR):\
-               HUD_Radar(); break;\
-       case (HUD_PANEL_WEAPONS):\
-               HUD_Weapons(); break;\
-       case (HUD_PANEL_AMMO):\
-               HUD_Ammo(); break;\
-       case (HUD_PANEL_POWERUPS):\
-               HUD_Powerups(); break;\
-       case (HUD_PANEL_HEALTHARMOR):\
-               HUD_HealthArmor(); break;\
-       case (HUD_PANEL_NOTIFY):\
-               HUD_Notify(); break;\
-       case (HUD_PANEL_TIMER):\
-               HUD_Timer(); break;\
-       case (HUD_PANEL_SCORE):\
-               HUD_Score(); break;\
-       case (HUD_PANEL_RACETIMER):\
-               HUD_RaceTimer(); break;\
-       case (HUD_PANEL_VOTE):\
-               HUD_VoteWindow(); break;\
-       case (HUD_PANEL_MODICONS):\
-               HUD_ModIcons(); break;\
-       case (HUD_PANEL_PRESSEDKEYS):\
-               HUD_DrawPressedKeys(); break;\
-       case (HUD_PANEL_CHAT):\
-               HUD_Chat(); break;\
-       case (HUD_PANEL_ENGINEINFO):\
-               HUD_EngineInfo(); break;\
-       case (HUD_PANEL_INFOMESSAGES):\
-               HUD_InfoMessages(); break;\
-       case (HUD_PANEL_PHYSICS):\
-               HUD_Physics(); break;\
-       case (HUD_PANEL_CENTERPRINT):\
-               HUD_CenterPrint(); break;\
-       case (HUD_PANEL_ITEMSTIME):\
-               HUD_ItemsTime(); break;\
- } ENDS_WITH_CURLY_BRACE
  void HUD_Main (void)
  {
        float i;
        if(scoreboard_fade_alpha)
                hud_fade_alpha = (1 - scoreboard_fade_alpha);
  
-       if(autocvar__hud_configure)
-               if(isdemo())
-                       HUD_Configure_Exit_Force();
+       HUD_Configure_Frame();
  
        if(intermission == 2) // no hud during mapvote
-       {
-               if (autocvar__hud_configure)
-                       HUD_Configure_Exit_Force();
                hud_fade_alpha = 0;
-       }
-       else if(autocvar__menu_alpha == 0 && scoreboard_fade_alpha == 0)
-               hud_fade_alpha = 1;
  
        // panels that we want to be active together with the scoreboard
-       // they must call HUD_Panel_ApplyFadeAlpha(); only when showing the menu
+       // they must fade only when the menu does
        if(scoreboard_fade_alpha == 1)
        {
-               HUD_CenterPrint();
+               (panel = HUD_PANEL(CENTERPRINT)).panel_draw();
                return;
        }
  
                hud_skin_prev = strzone(autocvar_hud_skin);
        }
  
-       // HUD configure visible grid
-       if(autocvar__hud_configure && autocvar_hud_configure_grid && autocvar_hud_configure_grid_alpha)
-       {
-               hud_configure_gridSize_x = bound(0.005, cvar("hud_configure_grid_xsize"), 0.2);
-               hud_configure_gridSize_y = bound(0.005, cvar("hud_configure_grid_ysize"), 0.2);
-               hud_configure_realGridSize_x = hud_configure_gridSize_x * vid_conwidth;
-               hud_configure_realGridSize_y = hud_configure_gridSize_y * vid_conheight;
-               vector s;
-               // x-axis
-               s = eX + eY * vid_conheight;
-               for(i = 1; i < 1/hud_configure_gridSize_x; ++i)
-                       drawfill(eX * i * hud_configure_realGridSize_x, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
-               // y-axis
-               s = eY + eX * vid_conwidth;
-               for(i = 1; i < 1/hud_configure_gridSize_y; ++i)
-                       drawfill(eY * i * hud_configure_realGridSize_y, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
-       }
- #ifdef COMPAT_XON050_ENGINE
-     current_player = (spectatee_status > 0) ? spectatee_status : player_localentnum;
- #else
      current_player = player_localentnum;
- #endif
  
        // draw the dock
        if(autocvar_hud_dock != "" && autocvar_hud_dock != "0")
                vector color;
                float hud_dock_color_team = autocvar_hud_dock_color_team;
                if((teamplay) && hud_dock_color_team) {
-                       color = colormapPaletteColor(myteam, 1) * hud_dock_color_team;
+                       if(autocvar__hud_configure && myteam == NUM_SPECTATOR)
+                               color = '1 0 0' * hud_dock_color_team;
+                       else
+                               color = myteamcolors * hud_dock_color_team;
                }
                else if(autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && hud_dock_color_team) {
                        color = '1 0 0' * hud_dock_color_team;
                        }
                        else if(hud_dock_color == "pants") {
                                f = stof(getplayerkeyvalue(current_player - 1, "colors"));
-                               color = colormapPaletteColor(mod(f, 16), 1);
+                               color = colormapPaletteColor(f % 16, 1);
                        }
                        else
                                color = stov(hud_dock_color);
                        }
                }
                if (warning)
-                       print(_("Automatically fixed wrong/missing panel numbers in _hud_panelorder\n"));
+                       dprint("Automatically fixed wrong/missing panel numbers in _hud_panelorder\n");
  
                cvar_set("_hud_panelorder", s);
                if(hud_panelorder_prev)
        hud_draw_maximized = 0;
        // draw panels in order specified by panel_order array
        for(i = HUD_PANEL_NUM - 1; i >= 0; --i)
-               HUD_DrawPanel(panel_order[i]);
+               (panel = hud_panel[panel_order[i]]).panel_draw();
  
        hud_draw_maximized = 1; // panels that may be maximized must check this var
        // draw maximized panels on top
        if(hud_panel_radar_maximized)
-               HUD_Radar();
+               (panel = HUD_PANEL(RADAR)).panel_draw();
        if(autocvar__con_chat_maximized)
-               HUD_Chat();
+               (panel = HUD_PANEL(CHAT)).panel_draw();
  
-       if(autocvar__hud_configure)
-       {
-               if(tab_panel != -1)
-               {
-                       HUD_Panel_UpdatePosSizeForId(tab_panel)
-                       drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .2, DRAWFLAG_NORMAL);
-               }
-               if(highlightedPanel != -1)
-               {
-                       HUD_Panel_UpdatePosSizeForId(highlightedPanel);
-                       HUD_Panel_HlBorder(panel_bg_border + 1.5 * hlBorderSize, '0 0.5 1', 0.25 * (1 - autocvar__menu_alpha));
-               }
-               if(!hud_configure_prev || hud_configure_prev == -1)
-               {
-                       if(autocvar_hud_cursormode) { setcursormode(1); }
-                       hudShiftState = 0;
-               }
-       }
-       else if (hud_configure_prev && autocvar_hud_cursormode)
-               setcursormode(0);
+       HUD_Configure_PostDraw();
  
        hud_configure_prev = autocvar__hud_configure;
-       if (!autocvar__hud_configure) // hud config mode disabled, enable normal theAlpha stuff again
-               if (menu_enabled)
-                       menu_enabled = 0;
  }
diff --combined qcsrc/client/hud.qh
index b1f02d39d3ba25c9c57c6ae222a846ee1359fa84,d56caf1331e88fa48e9624f20b2cf7982c581f70..66e4e61eb7f64bd6ccd3bea1dffa6a96793f49d1
@@@ -1,14 -1,22 +1,22 @@@
- float panel_order[HUD_PANEL_NUM];
+ #define HUD_PANEL_MAX 24
+ entity hud_panel[HUD_PANEL_MAX];
+ #define HUD_PANEL_FIRST 0
+ float HUD_PANEL_NUM;
+ float HUD_PANEL_LAST;
+ float panel_order[HUD_PANEL_MAX];
  string hud_panelorder_prev;
  
  float hud_draw_maximized;
  float hud_panel_radar_maximized;
+ float chat_panel_modified;
+ float radar_panel_modified;
  
  vector mousepos;
  vector panel_click_distance; // mouse cursor distance from the top left corner of the panel (saved only upon a click)
  vector panel_click_resizeorigin; // coordinates for opposite point when resizing
  float resizeCorner; // 1 = topleft, 2 = topright, 3 = bottomleft, 4 = bottomright
var float highlightedPanel = -1;
entity highlightedPanel;
  float highlightedAction; // 0 = nothing, 1 = move, 2 = resize
  
  const float BORDER_MULTIPLIER = 0.25;
@@@ -41,28 -49,36 +49,36 @@@ const float S_CTRL = 2
  const float S_ALT = 4;
  
  float menu_enabled; // 1 showing the entire HUD, 2 showing only the clicked panel
- float menu_enabled_time;
  
  float hud_fade_alpha;
  
  string hud_skin_path;
  string hud_skin_prev;
  
- var vector progressbar_color;
+ vector myteamcolors;
  
var float highlightedPanel_backup = -1;
entity highlightedPanel_backup;
  var vector panel_pos_backup;
  var vector panel_size_backup;
  
- var float highlightedPanel_copied = -1; //this is good only to know if there is something copied
  var vector panel_size_copied;
  
- var float hud_configure_active_panel; // this panel has recently referred the UpdateCvars macro
- var string panel_name;
+ entity panel;
+ .string panel_name;
+ .float panel_id;
+ .vector current_panel_pos;
+ .vector current_panel_size;
+ .string current_panel_bg;
+ .float current_panel_bg_alpha;
+ .float current_panel_bg_border;
+ .vector current_panel_bg_color;
+ .float current_panel_bg_color_team;
+ .float current_panel_bg_padding;
+ .float current_panel_fg_alpha;
+ .float update_time;
  var float panel_enabled;
  var vector panel_pos;
  var vector panel_size;
- var string panel_bg;
  var string panel_bg_str; // "_str" vars contain the raw value of the cvar, non-"_str" contains what hud.qc code should use
  var vector panel_bg_color;
  var string panel_bg_color_str;
@@@ -76,32 -92,63 +92,64 @@@ var string panel_bg_border_str
  var float panel_bg_padding;
  var string panel_bg_padding_str;
  
+ .void() panel_draw;
  float current_player;
  
 -      HUD_PANEL(BUFFS        , HUD_Buffs        , buffs) 
+ #define HUD_PANELS \
+       HUD_PANEL(WEAPONS      , HUD_Weapons      , weapons) \
+       HUD_PANEL(AMMO         , HUD_Ammo         , ammo) \
+       HUD_PANEL(POWERUPS     , HUD_Powerups     , powerups) \
+       HUD_PANEL(HEALTHARMOR  , HUD_HealthArmor  , healtharmor) \
+       HUD_PANEL(NOTIFY       , HUD_Notify       , notify) \
+       HUD_PANEL(TIMER        , HUD_Timer        , timer) \
+       HUD_PANEL(RADAR        , HUD_Radar        , radar) \
+       HUD_PANEL(SCORE        , HUD_Score        , score) \
+       HUD_PANEL(RACETIMER    , HUD_RaceTimer    , racetimer) \
+       HUD_PANEL(VOTE         , HUD_Vote         , vote) \
+       HUD_PANEL(MODICONS     , HUD_ModIcons     , modicons) \
+       HUD_PANEL(PRESSEDKEYS  , HUD_PressedKeys  , pressedkeys) \
+       HUD_PANEL(CHAT         , HUD_Chat         , chat) \
+       HUD_PANEL(ENGINEINFO   , HUD_EngineInfo   , engineinfo) \
+       HUD_PANEL(INFOMESSAGES , HUD_InfoMessages , infomessages) \
+       HUD_PANEL(PHYSICS      , HUD_Physics      , physics) \
+       HUD_PANEL(CENTERPRINT  , HUD_CenterPrint  , centerprint) \
++      HUD_PANEL(BUFFS        , HUD_Buffs        , buffs) \
++      HUD_PANEL(ITEMSTIME    , HUD_ItemsTime    , itemstime)
+ #define HUD_PANEL(NAME,draw_func,name) \
+       float HUD_PANEL_##NAME; \
+       void draw_func(void); \
+       void RegisterHUD_Panel_##NAME() \
+       { \
+               HUD_PANEL_LAST = HUD_PANEL_##NAME = HUD_PANEL_NUM; \
+               entity hud_panelent = spawn(); \
+               hud_panel[HUD_PANEL_##NAME] = hud_panelent; \
+               hud_panelent.classname = "hud_panel"; \
+               hud_panelent.panel_name = #name; \
+               hud_panelent.panel_id = HUD_PANEL_##NAME; \
+               hud_panelent.panel_draw = draw_func; \
+               ++HUD_PANEL_NUM; \
+       } \
+       ACCUMULATE_FUNCTION(RegisterHUD_Panels, RegisterHUD_Panel_##NAME);
+ HUD_PANELS
+ #undef HUD_PANEL
+ #define HUD_PANEL(NAME) hud_panel[HUD_PANEL_##NAME]
  // Because calling lots of functions in QC apparently cuts fps in half on many machines:
  // ----------------------
  // MACRO HELL STARTS HERE
  // ----------------------
  // Little help for the poor people who have to make sense of this: Start from the bottom ;)
  
- #define HUD_Panel_GetProgressBarColor(item) \
-               progressbar_color = stov(cvar_string("hud_progressbar_" #item "_color"))
- #define HUD_Panel_GetProgressBarColorForString(item) \
- switch(item) {\
-       case "health": HUD_Panel_GetProgressBarColor(health); break;\
-       case "armor": HUD_Panel_GetProgressBarColor(armor); break;\
-       case "strength": HUD_Panel_GetProgressBarColor(strength); break;\
-       case "shield": HUD_Panel_GetProgressBarColor(shield); break;\
-       case "fuel": HUD_Panel_GetProgressBarColor(fuel); break;\
-       case "nexball": HUD_Panel_GetProgressBarColor(nexball); break;\
-       case "speed": HUD_Panel_GetProgressBarColor(speed); break;\
-       case "acceleration": HUD_Panel_GetProgressBarColor(acceleration); break;\
-       case "acceleration_neg": HUD_Panel_GetProgressBarColor(acceleration_neg); break;\
- } ENDS_WITH_CURLY_BRACE
- // Get value for panel_bg: if "" fetch default, else use panel_bg_str
+ // Get value for panel.current_panel_bg: if "" fetch default, else use panel_bg_str
  // comment on last line of macro: // we probably want to see a background in config mode at all times...
  #define HUD_Panel_GetBg()\
+ string panel_bg;\
  if(!autocvar__hud_configure && panel_bg_str == "0") {\
        panel_bg = "0";\
  } else {\
                        }\
                }\
        }\
- }
+ }\
+ if(panel.current_panel_bg)\
+       strunzone(panel.current_panel_bg);\
+ panel.current_panel_bg = strzone(panel_bg);
  
  // Get value for panel_bg_color: if "" fetch default, else use panel_bg_color. Convert pants, shirt or teamcolor into a vector.
  #define HUD_Panel_GetColor()\
  if((teamplay) && panel_bg_color_team) {\
-       panel_bg_color = colormapPaletteColor(myteam, 1) * panel_bg_color_team;\
+       if(autocvar__hud_configure && myteam == NUM_SPECTATOR)\
+               panel_bg_color = '1 0 0' * panel_bg_color_team;\
+       else\
+               panel_bg_color = myteamcolors * panel_bg_color_team;\
  } else if (autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && panel_bg_color_team) {\
        panel_bg_color = '1 0 0' * panel_bg_color_team;\
  } else {\
                if(panel_bg_color_str == "shirt") {\
                        panel_bg_color = colormapPaletteColor(floor(stof(getplayerkeyvalue(current_player - 1, "colors")) / 16), 0);\
                } else if(panel_bg_color_str == "pants") {\
-                       panel_bg_color = colormapPaletteColor(mod(stof(getplayerkeyvalue(current_player - 1, "colors")), 16), 1);\
+                       panel_bg_color = colormapPaletteColor(stof(getplayerkeyvalue(current_player - 1, "colors")) % 16, 1);\
                } else {\
                        panel_bg_color = stov(panel_bg_color_str);\
                }\
@@@ -151,14 -204,6 +205,6 @@@ if(panel_bg_color_team_str == "") {
        panel_bg_color_team = stof(panel_bg_color_team_str);\
  }
  
- // the check doesn't allow to fade this panel when showing the panel-specific menu dialog
- #define HUD_Panel_ApplyFadeAlpha()\
- if(!(menu_enabled == 2 && highlightedPanel == hud_configure_active_panel))\
- {\
-       panel_bg_alpha *= hud_fade_alpha;\
-       panel_fg_alpha *= hud_fade_alpha;\
- } ENDS_WITH_CURLY_BRACE
  // Get value for panel_bg_alpha: if "" fetch default, else use panel_bg_alpha. Also do various menu dialog fadeout/in checks, and minalpha checks
  // comment on line 3 of macro: // do not set a minalpha cap when showing the config dialog for this panel
  #define HUD_Panel_GetBgAlpha()\
@@@ -169,7 -214,7 +215,7 @@@ panel_bg_alpha = stof(panel_bg_alpha_st
  if(autocvar__hud_configure) {\
        if(!panel_enabled)\
                panel_bg_alpha = 0.25;\
-       else if(menu_enabled == 2 && highlightedPanel == hud_configure_active_panel)\
+       else if(menu_enabled == 2 && panel == highlightedPanel)\
                panel_bg_alpha = (1 - autocvar__menu_alpha) * max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha) + autocvar__menu_alpha * panel_bg_alpha;\
        else\
                panel_bg_alpha = max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha);\
@@@ -190,13 -235,6 +236,6 @@@ if(panel_bg_border_str == "") {
        panel_bg_border = stof(panel_bg_border_str);\
  } ENDS_WITH_CURLY_BRACE
  
- // Scale the pos and size vectors to absolute coordinates
- #define HUD_Panel_GetScaledVectors()\
- panel_pos_x *= vid_conwidth;\
- panel_pos_y *= vid_conheight;\
- panel_size_x *= vid_conwidth;\
- panel_size_y *= vid_conheight;
  // Get padding. See comments above, it's similar.
  // last line is a port of the old function, basically always make sure the panel contents are at least 5 pixels tall/wide, to disallow extreme padding values
  #define HUD_Panel_GetPadding()\
@@@ -207,36 -245,12 +246,12 @@@ if(panel_bg_padding_str == "") {
  }\
  panel_bg_padding = min(min(panel_size_x, panel_size_y)/2 - 5, panel_bg_padding);
  
- // Point to the macros above (stupid max macro length)
- #define HUD_Panel_GetStringVars()\
- HUD_Panel_GetBg()\
- if (panel_bg != "0") {\
-       HUD_Panel_GetColorTeam()\
-       HUD_Panel_GetColor()\
-       HUD_Panel_GetBgAlpha()\
-       HUD_Panel_GetBorder()\
- }\
- HUD_Panel_GetFgAlpha()\
- HUD_Panel_GetScaledVectors()\
- HUD_Panel_GetPadding()
- // return smoothly faded pos of given panel when a dialog is active
- var vector menu_enable_panelpos;
- #define HUD_Panel_GetMenuPos() \
- if(panel_size_x > panel_size_y)\
-       menu_enable_panelpos = eX * 0.5 * vid_conwidth - eX * 0.5 * panel_size_x + eY * 0.82 * vid_conheight;\
- else\
-       menu_enable_panelpos = eY * 0.5 * vid_conheight - eY * 0.5 * panel_size_y + eX * 0.7 * vid_conwidth;\
- panel_pos = (1 - autocvar__menu_alpha) * panel_pos + (autocvar__menu_alpha) * menu_enable_panelpos;
- // return smoothly faded size of given panel when a dialog is active
- //var vector menu_enable_maxsize;
- var float menu_enable_maxsize_x;
- var float menu_enable_maxsize_y;
- var vector menu_enable_size;
- #define HUD_Panel_GetMenuSize()\
- menu_enable_maxsize_x = 0.3 * vid_conwidth;\
- menu_enable_maxsize_y = 0.18 * vid_conheight;\
+ // return smoothly faded pos and size of given panel when a dialog is active
+ #define HUD_Panel_UpdatePosSize_ForMenu()\
+ vector menu_enable_pos;\
+ vector menu_enable_size = '0 0 0';\
+ float menu_enable_maxsize_x = 0.3 * vid_conwidth;\
+ float menu_enable_maxsize_y = 0.18 * vid_conheight;\
  if(panel_size_x > panel_size_y)\
  {\
        if(panel_size_y > menu_enable_maxsize_y)\
                menu_enable_size_x = panel_size_x * (menu_enable_maxsize_y/panel_size_y);\
                panel_size = (1 - autocvar__menu_alpha) * panel_size + (autocvar__menu_alpha) * menu_enable_size;\
        }\
+       menu_enable_pos = eX * 0.5 * vid_conwidth - eX * 0.5 * panel_size_x + eY * (vid_conheight - menu_enable_maxsize_y);\
  }\
  else\
  {\
                menu_enable_size_y = panel_size_y * (menu_enable_maxsize_x/panel_size_x);\
                panel_size = (1 - autocvar__menu_alpha) * panel_size + (autocvar__menu_alpha) * menu_enable_size;\
        }\
- }
+       menu_enable_pos = eY * 0.5 * vid_conheight - eY * 0.5 * panel_size_y + eX * (vid_conwidth - menu_enable_maxsize_x);\
+ }\
+ panel_pos = (1 - autocvar__menu_alpha) * panel_pos + (autocvar__menu_alpha) * menu_enable_pos;
  
- // Update all common cvars of given panel name
- #define HUD_Panel_UpdateCvars(name) \
- panel_enabled = autocvar_hud_panel_##name; \
- panel_pos = stov(cvar_string("hud_panel_" #name "_pos")); \
- panel_size = stov(cvar_string("hud_panel_" #name "_size")); \
- panel_bg_str = cvar_string("hud_panel_" #name "_bg"); \
- panel_bg_color_str = cvar_string("hud_panel_" #name "_bg_color"); \
- panel_bg_color_team_str = cvar_string("hud_panel_" #name "_bg_color_team"); \
- panel_bg_alpha_str = cvar_string("hud_panel_" #name "_bg_alpha"); \
- panel_bg_border_str = cvar_string("hud_panel_" #name "_bg_border"); \
- panel_bg_padding_str = cvar_string("hud_panel_" #name "_bg_padding"); \
- HUD_Panel_GetStringVars()\
- if(menu_enabled == 2 && hud_configure_active_panel == highlightedPanel) {\
-       HUD_Panel_GetMenuSize()\
-       HUD_Panel_GetMenuPos()\
+ // Scale the pos and size vectors to absolute coordinates
+ #define HUD_Panel_ScalePosSize()\
+ panel_pos_x *= vid_conwidth; panel_pos_y *= vid_conheight;\
+ panel_size_x *= vid_conwidth; panel_size_y *= vid_conheight;
+ // NOTE: in hud_configure mode cvars must be reloaded every frame
+ #define HUD_Panel_UpdateCvars() \
+ if(panel.update_time <= time) { \
+       if(autocvar__hud_configure) panel_enabled = cvar(strcat("hud_panel_", panel.panel_name)); \
+       panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos"))); \
+       panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size"))); \
+       HUD_Panel_ScalePosSize() \
+       panel_bg_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg")); \
+       panel_bg_color_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_color")); \
+       panel_bg_color_team_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_color_team")); \
+       panel_bg_alpha_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_alpha")); \
+       panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border")); \
+       panel_bg_padding_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_padding")); \
+       HUD_Panel_GetBg()\
+       if (panel.current_panel_bg != "0") {\
+               HUD_Panel_GetColorTeam()\
+               HUD_Panel_GetColor()\
+               HUD_Panel_GetBgAlpha()\
+               HUD_Panel_GetBorder()\
+       }\
+       HUD_Panel_GetFgAlpha()\
+       HUD_Panel_GetPadding()\
+       panel.current_panel_bg_alpha = panel_bg_alpha; \
+       panel.current_panel_fg_alpha = panel_fg_alpha; \
+       if(menu_enabled == 2 && panel == highlightedPanel) {\
+               HUD_Panel_UpdatePosSize_ForMenu()\
+       } else {\
+               panel_bg_alpha *= hud_fade_alpha;\
+               panel_fg_alpha *= hud_fade_alpha;\
+       }\
+       panel.current_panel_pos = panel_pos; \
+       panel.current_panel_size = panel_size; \
+       panel.current_panel_bg_border = panel_bg_border; \
+       panel.current_panel_bg_color = panel_bg_color; \
+       panel.current_panel_bg_color_team = panel_bg_color_team; \
+       panel.current_panel_bg_padding = panel_bg_padding; \
+       panel.update_time = (autocvar__hud_configure) ? time : time + autocvar_hud_panel_update_interval; \
+ } else { \
+       panel_pos = panel.current_panel_pos; \
+       panel_size = panel.current_panel_size; \
+       panel_bg_alpha = panel.current_panel_bg_alpha * hud_fade_alpha; \
+       panel_bg_border = panel.current_panel_bg_border; \
+       panel_bg_color = panel.current_panel_bg_color; \
+       panel_bg_color_team = panel.current_panel_bg_color_team; \
+       panel_bg_padding = panel.current_panel_bg_padding; \
+       panel_fg_alpha = panel.current_panel_fg_alpha * hud_fade_alpha; \
  } ENDS_WITH_CURLY_BRACE
  
- // FTEQCC I HATE YOU WHY DO YOU MAKE ME DO THIS??? :(
- // max macro length is 1024 characters, I must split it up :(
- // Update all common cvars of given panel id
- #define HUD_Panel_UpdateCvarsForId_Part2(id) \
- switch(id) { \
-       case HUD_PANEL_INFOMESSAGES: HUD_Panel_UpdateCvars(infomessages) break; \
-       case HUD_PANEL_PHYSICS: HUD_Panel_UpdateCvars(physics); break;\
-       case HUD_PANEL_CENTERPRINT: HUD_Panel_UpdateCvars(centerprint); break;\
-       case HUD_PANEL_ITEMSTIME: HUD_Panel_UpdateCvars(itemstime); break;\
- }
- #define HUD_Panel_UpdateCvarsForId(id) \
- switch(id) { \
-       case HUD_PANEL_WEAPONS: HUD_Panel_UpdateCvars(weapons) break; \
-       case HUD_PANEL_AMMO: HUD_Panel_UpdateCvars(ammo) break; \
-       case HUD_PANEL_POWERUPS: HUD_Panel_UpdateCvars(powerups) break; \
-       case HUD_PANEL_HEALTHARMOR: HUD_Panel_UpdateCvars(healtharmor) break; \
-       case HUD_PANEL_NOTIFY: HUD_Panel_UpdateCvars(notify) break; \
-       case HUD_PANEL_TIMER: HUD_Panel_UpdateCvars(timer) break; \
-       case HUD_PANEL_RADAR: HUD_Panel_UpdateCvars(radar) break; \
-       case HUD_PANEL_SCORE: HUD_Panel_UpdateCvars(score) break; \
-       case HUD_PANEL_RACETIMER: HUD_Panel_UpdateCvars(racetimer) break; \
-       case HUD_PANEL_VOTE: HUD_Panel_UpdateCvars(vote) break; \
-       case HUD_PANEL_MODICONS: HUD_Panel_UpdateCvars(modicons) break; \
-       case HUD_PANEL_PRESSEDKEYS: HUD_Panel_UpdateCvars(pressedkeys) break; \
-       case HUD_PANEL_CHAT: HUD_Panel_UpdateCvars(chat) break; \
-       case HUD_PANEL_ENGINEINFO: HUD_Panel_UpdateCvars(engineinfo) break; \
-       default: HUD_Panel_UpdateCvarsForId_Part2(id)\
- }
- #define HUD_Panel_UpdatePosSize(name) \
- panel_pos = stov(cvar_string("hud_panel_" #name "_pos")); \
- panel_size = stov(cvar_string("hud_panel_" #name "_size")); \
- HUD_Panel_GetScaledVectors()\
- if(menu_enabled == 2 && hud_configure_active_panel == highlightedPanel) {\
-       HUD_Panel_GetMenuSize()\
-       HUD_Panel_GetMenuPos()\
+ #define HUD_Panel_UpdatePosSize() {\
+ panel_enabled = cvar(strcat("hud_panel_", panel.panel_name)); \
+ panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos"))); \
+ panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size"))); \
+ HUD_Panel_ScalePosSize()\
+ if(menu_enabled == 2 && panel == highlightedPanel) {\
+       HUD_Panel_UpdatePosSize_ForMenu()\
  }\
- panel_bg_border_str = cvar_string("hud_panel_" #name "_bg_border"); \
- HUD_Panel_GetBorder()
- // Update pos and size of given panel id
- #define HUD_Panel_UpdatePosSizeForId_Part2(id) \
- switch(id) { \
-       case HUD_PANEL_INFOMESSAGES: HUD_Panel_UpdatePosSize(infomessages) break;\
-       case HUD_PANEL_PHYSICS: HUD_Panel_UpdatePosSize(physics); break;\
-       case HUD_PANEL_CENTERPRINT: HUD_Panel_UpdatePosSize(centerprint); break;\
-       case HUD_PANEL_ITEMSTIME: HUD_Panel_UpdatePosSize(itemstime); break;\
- }
+ panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border")); \
+ HUD_Panel_GetBorder() \
+ } ENDS_WITH_CURLY_BRACE
  
- #define HUD_Panel_UpdatePosSizeForId(id) \
- switch(id) { \
-       case HUD_PANEL_WEAPONS: HUD_Panel_UpdatePosSize(weapons) break;\
-       case HUD_PANEL_AMMO: HUD_Panel_UpdatePosSize(ammo) break;\
-       case HUD_PANEL_POWERUPS: HUD_Panel_UpdatePosSize(powerups) break;\
-       case HUD_PANEL_HEALTHARMOR: HUD_Panel_UpdatePosSize(healtharmor) break;\
-       case HUD_PANEL_NOTIFY: HUD_Panel_UpdatePosSize(notify) break;\
-       case HUD_PANEL_TIMER: HUD_Panel_UpdatePosSize(timer) break;\
-       case HUD_PANEL_RADAR: HUD_Panel_UpdatePosSize(radar) break;\
-       case HUD_PANEL_SCORE: HUD_Panel_UpdatePosSize(score) break;\
-       case HUD_PANEL_RACETIMER: HUD_Panel_UpdatePosSize(racetimer) break;\
-       case HUD_PANEL_VOTE: HUD_Panel_UpdatePosSize(vote) break;\
-       case HUD_PANEL_MODICONS: HUD_Panel_UpdatePosSize(modicons) break;\
-       case HUD_PANEL_PRESSEDKEYS: HUD_Panel_UpdatePosSize(pressedkeys) break;\
-       case HUD_PANEL_CHAT: HUD_Panel_UpdatePosSize(chat) break;\
-       case HUD_PANEL_ENGINEINFO: HUD_Panel_UpdatePosSize(engineinfo) break;\
-       default: HUD_Panel_UpdatePosSizeForId_Part2(id)\
- }
+ #define NOTIFY_MAX_ENTRIES 10
+ #define NOTIFY_ICON_MARGIN 0.02
  
- #define KN_MAX_ENTRIES 10
+ float notify_index;
+ float notify_count;
+ float notify_times[NOTIFY_MAX_ENTRIES];
+ string notify_attackers[NOTIFY_MAX_ENTRIES];
+ string notify_victims[NOTIFY_MAX_ENTRIES];
+ string notify_icons[NOTIFY_MAX_ENTRIES];
  
- float kn_index;
- float notify_times[KN_MAX_ENTRIES];
- string notify_icon[KN_MAX_ENTRIES];
- string notify_attackers[KN_MAX_ENTRIES];
- string notify_victims[KN_MAX_ENTRIES];
  void HUD_Notify_Push(string icon, string attacker, string victim);
+ var void HUD_ModIcons_GameType(vector pos, vector size);
+ void HUD_ModIcons_SetFunc();
index e2f82d6b6b4f49172df1f2c1cb5e853c1e8524fa,047e012ad65d8670b5502679f1bff01f72cce9c7..5d149fe0a939873b9782af72ce64065137b728f9
@@@ -2,8 -2,8 +2,8 @@@
  // q: quoted, n: not quoted
  #define HUD_Write_Cvar_n(cvar) HUD_Write(strcat("seta ", cvar, " ", cvar_string(cvar), "\n"))
  #define HUD_Write_Cvar_q(cvar) HUD_Write(strcat("seta ", cvar, " \"", cvar_string(cvar), "\"\n"))
- #define HUD_Write_PanelCvar_n(cvar_suf) HUD_Write_Cvar_n(strcat("hud_panel_", panel_name, cvar_suf))
- #define HUD_Write_PanelCvar_q(cvar_suf) HUD_Write_Cvar_q(strcat("hud_panel_", panel_name, cvar_suf))
+ #define HUD_Write_PanelCvar_n(cvar_suf) HUD_Write_Cvar_n(strcat("hud_panel_", panel.panel_name, cvar_suf))
+ #define HUD_Write_PanelCvar_q(cvar_suf) HUD_Write_Cvar_q(strcat("hud_panel_", panel.panel_name, cvar_suf))
  // Save the config
  void HUD_Panel_ExportCfg(string cfgname)
  {
@@@ -52,7 -52,7 +52,7 @@@
                float i;
                for (i = 0; i < HUD_PANEL_NUM; ++i)
                {
-                       HUD_Panel_GetName(i);
+                       panel = hud_panel[i];
  
                        HUD_Write_PanelCvar_n("");
                        HUD_Write_PanelCvar_q("_pos");
                                        HUD_Write_PanelCvar_q("_fontsize");
                                        HUD_Write_PanelCvar_q("_time");
                                        HUD_Write_PanelCvar_q("_fadetime");
+                                       HUD_Write_PanelCvar_q("_icon_aspect");
                                        break;
                                case HUD_PANEL_TIMER:
                                        HUD_Write_PanelCvar_q("_increment");
                                        HUD_Write_PanelCvar_q("_maximized_scale");
                                        HUD_Write_PanelCvar_q("_maximized_size");
                                        HUD_Write_PanelCvar_q("_maximized_rotation");
-                                       HUD_Write_PanelCvar_q("_maximized_zoommode"); 
+                                       HUD_Write_PanelCvar_q("_maximized_zoommode");
                                        break;
                                case HUD_PANEL_SCORE:
                                        HUD_Write_PanelCvar_q("_rankings");
                                        HUD_Write_PanelCvar_q("_alreadyvoted_alpha");
                                        break;
                                case HUD_PANEL_MODICONS:
+                                       HUD_Write_PanelCvar_q("_ca_layout");
                                        HUD_Write_PanelCvar_q("_dom_layout");
+                                       HUD_Write_PanelCvar_q("_freezetag_layout");
                                        break;
                                case HUD_PANEL_PRESSEDKEYS:
                                        HUD_Write_PanelCvar_q("_aspect");
                                        HUD_Write_PanelCvar_q("_fade_subsequent_minfontsize");
                                        HUD_Write_PanelCvar_q("_fade_minfontsize");
                                        break;
 +                              case HUD_PANEL_ITEMSTIME:
 +                                      HUD_Write_PanelCvar_q("_iconalign");
 +                                      HUD_Write_PanelCvar_q("_progressbar");
 +                                      HUD_Write_PanelCvar_q("_progressbar_name");
 +                                      HUD_Write_PanelCvar_q("_progressbar_reduced");
 +                                      HUD_Write_PanelCvar_q("_showspawned");
 +                                      HUD_Write_PanelCvar_q("_text");
 +                                      HUD_Write_PanelCvar_q("_ratio");
 +                                      HUD_Write_PanelCvar_q("_size_dinamic");
 +                                      break;
                        }
                        HUD_Write("\n");
                }
                HUD_Write("menu_sync\n"); // force the menu to reread the cvars, so that the dialogs are updated
  
-               print(sprintf(_("^2Successfully exported to %s! (Note: It's saved in data/data/)\n"), filename));
+               printf(_("^2Successfully exported to %s! (Note: It's saved in data/data/)\n"), filename);
                fclose(fh);
        }
        else
-               print(sprintf(_("^1Couldn't write to %s\n"), filename));
+               printf(_("^1Couldn't write to %s\n"), filename);
  }
  
  void HUD_Configure_Exit_Force()
@@@ -227,10 -220,10 +230,10 @@@ vector HUD_Panel_CheckMove(vector myPos
        myTarget = myPos;
  
        for (i = 0; i < HUD_PANEL_NUM; ++i) {
-               if(i == highlightedPanel || !panel_enabled)
-                       continue;
-               HUD_Panel_UpdatePosSizeForId(i);
+               panel = hud_panel[i];
+               if(panel == highlightedPanel) continue;
+               HUD_Panel_UpdatePosSize()
+               if(!panel_enabled) continue;
  
                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);
+       panel = highlightedPanel;
+       HUD_Panel_UpdatePosSize()
        vector mySize;
        mySize = panel_size;
  
        string s;
        s = strcat(ftos(pos_x/vid_conwidth), " ", ftos(pos_y/vid_conheight));
  
-       HUD_Panel_GetName(highlightedPanel);
-       cvar_set(strcat("hud_panel_", panel_name, "_pos"), s);
+       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
  }
  
  // check if resize will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
@@@ -327,10 -320,10 +330,10 @@@ vector HUD_Panel_CheckResize(vector myS
        ratio = mySize_x/mySize_y;
  
        for (i = 0; i < HUD_PANEL_NUM; ++i) {
-               if(i == highlightedPanel || !panel_enabled)
-                       continue;
-               HUD_Panel_UpdatePosSizeForId(i);
+               panel = hud_panel[i];
+               if(panel == highlightedPanel) continue;
+               HUD_Panel_UpdatePosSize()
+               if(!panel_enabled) continue;
  
                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);
+       panel = highlightedPanel;
+       HUD_Panel_UpdatePosSize()
        vector resizeorigin;
        resizeorigin = panel_click_resizeorigin;
        local noref vector myPos; // fteqcc sucks
        mySize_x = max(0.025 * vid_conwidth, mySize_x);
        mySize_y = max(0.025 * vid_conheight, mySize_y);
  
-       if(highlightedPanel == HUD_PANEL_CHAT) // some panels have their own restrictions, like the chat panel (which actually only moves the engine chat print around). Looks bad if it's too small.
+       if(highlightedPanel == HUD_PANEL(CHAT)) // some panels have their own restrictions, like the chat panel (which actually only moves the engine chat print around). Looks bad if it's too small.
        {
                mySize_x = max(17 * autocvar_con_chatsize, mySize_x);
                mySize_y = max(2 * autocvar_con_chatsize + 2 * panel_bg_padding, mySize_y);
        //if(cvar("hud_configure_checkcollisions_debug"))
                //drawfill(myPos, mySize, '0 1 0', .3, DRAWFLAG_NORMAL);
  
-       HUD_Panel_GetName(highlightedPanel);
        string s;
        s = strcat(ftos(mySize_x/vid_conwidth), " ", ftos(mySize_y/vid_conheight));
-       cvar_set(strcat("hud_panel_", panel_name, "_size"), s);
+       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
  
        s = strcat(ftos(myPos_x/vid_conwidth), " ", ftos(myPos_y/vid_conheight));
-       cvar_set(strcat("hud_panel_", panel_name, "_pos"), s);
+       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
  }
  
  float pressed_key_time;
  vector highlightedPanel_initial_pos, highlightedPanel_initial_size;
  void HUD_Panel_Arrow_Action(float nPrimary)
  {
-       if (highlightedPanel == -1)
+       if(!highlightedPanel)
                return;
  
        hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions);
                        step = (step / 64) * (1 + 2 * (time - pressed_key_time));
        }
  
-       HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+       panel = highlightedPanel;
+       HUD_Panel_UpdatePosSize()
  
        highlightedPanel_initial_pos = panel_pos;
        highlightedPanel_initial_size = panel_size;
                HUD_Panel_SetPos(pos);
        }
  
-       HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+       panel = highlightedPanel;
+       HUD_Panel_UpdatePosSize()
  
        if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
        {
@@@ -636,15 -631,16 +641,16 @@@ float prevMouseClickedTime; // time dur
  vector prevMouseClickedPos; // pos during previous left mouse click, to check for doubleclicks
  
  void HUD_Panel_EnableMenu();
float tab_panels[HUD_PANEL_NUM];
float tab_panel, tab_backward;
entity tab_panels[HUD_PANEL_MAX];
entity tab_panel;
  vector tab_panel_pos;
+ float tab_backward;
  void HUD_Panel_FirstInDrawQ(float id);
  void reset_tab_panels()
  {
        int i;
        for(i = 0; i < HUD_PANEL_NUM; ++i)
-               tab_panels[i] = -1;
+               tab_panels[i] = world;
  }
  float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary)
  {
        if(!autocvar__hud_configure)
                return false;
  
-       // block any input while a menu dialog is fading
-       if(autocvar__menu_alpha)
-               return true;
        if(bInputType == 3)
        {
                mousepos_x = nPrimary;
                return true;
        }
  
+       // block any input while a menu dialog is fading
+       // don't block mousepos read as it leads to cursor jumps in the interaction with the menu
+       if(autocvar__menu_alpha)
+       {
+               hudShiftState = 0;
+               mouseClicked = 0;
+               return true;
+       }
        // allow console bind to work
        string con_keys;
        float keys;
        {
                if (bInputType == 1) //ctrl has been released
                {
-                       if (tab_panel != -1)
+                       if (tab_panel)
                        {
                                //switch to selected panel
                                highlightedPanel = tab_panel;
                                highlightedAction = 0;
-                               HUD_Panel_FirstInDrawQ(highlightedPanel);
+                               HUD_Panel_FirstInDrawQ(highlightedPanel.panel_id);
                        }
-                       tab_panel = -1;
+                       tab_panel = world;
                        reset_tab_panels();
                }
        }
                if (bInputType == 1)
                        return true;
                menu_enabled = 1;
-               menu_enabled_time = time;
                localcmd("menu_showhudexit\n");
        }
        else if(nPrimary == K_BACKSPACE && hudShiftState & S_CTRL)
                //(it should only after every other panel of the hud)
                //It's a minor bug anyway, we can live with it
  
-               float starting_panel;
-               float old_tab_panel = tab_panel;
-               if (tab_panel == -1) //first press of TAB
+               entity starting_panel;
+               entity old_tab_panel = tab_panel;
+               if (!tab_panel) //first press of TAB
                {
-                       if (highlightedPanel != -1)
-                               HUD_Panel_UpdatePosSizeForId(highlightedPanel)
+                       if (highlightedPanel)
+                       {
+                               panel = highlightedPanel;
+                               HUD_Panel_UpdatePosSize()
+                       }
                        else
                                panel_pos = '0 0 0';
-                       starting_panel = highlightedPanel; //can be -1, it means no starting panel
+                       starting_panel = highlightedPanel;
                        tab_panel_pos = panel_pos; //to compute level
                }
                else
                level = floor(tab_panel_pos_y / level_height) * level_height; //starting level
                candidate_pos_x = (!tab_backward) ? vid_conwidth : 0;
                start_pos_x = tab_panel_pos_x;
-               tab_panel = -1;
+               tab_panel = world;
                k=0;
                while(++k)
                {
                        for(i = 0; i < HUD_PANEL_NUM; ++i)
                        {
-                               if (i == tab_panels[i] || i == starting_panel)
+                               panel = hud_panel[i];
+                               if (panel == tab_panels[i] || panel == starting_panel)
                                        continue;
-                               HUD_Panel_UpdatePosSizeForId(i)
+                               HUD_Panel_UpdatePosSize()
                                if (panel_pos_y >= level && (panel_pos_y - level) < level_height)
                                if (  ( !tab_backward && panel_pos_x >= start_pos_x && (panel_pos_x < candidate_pos_x || (panel_pos_x == candidate_pos_x && panel_pos_y <= candidate_pos_y)) )
                                        || ( tab_backward && panel_pos_x <= start_pos_x && (panel_pos_x > candidate_pos_x || (panel_pos_x == candidate_pos_x && panel_pos_y >= candidate_pos_y)) )  )
                                {
-                                       tab_panel = i;
+                                       tab_panel = panel;
                                        tab_panel_pos = candidate_pos = panel_pos;
                                }
                        }
-                       if (tab_panel != -1)
+                       if (tab_panel)
                                break;
                        if (k == LEVELS_NUM) //tab_panel not found
                        {
                                reset_tab_panels();
-                               if (old_tab_panel == -2) //this prevents an infinite loop (should not happen normally)
+                               if (!old_tab_panel)
                                {
-                                       tab_panel = -1;
+                                       tab_panel = world;
                                        return true;
                                }
                                starting_panel = old_tab_panel;
-                               old_tab_panel = -2;
+                               old_tab_panel = world;
                                goto find_tab_panel; //u must find tab_panel!
                        }
                        if (!tab_backward)
                        {
-                               level = mod(level + level_height, vid_conheight);
+                               level = (level + level_height) % vid_conheight;
                                start_pos_x = 0;
                                candidate_pos_x = vid_conwidth;
                        }
                        else
                        {
-                               level = mod(level - level_height, vid_conheight);
+                               level = (level - level_height) % vid_conheight;
                                start_pos_x = vid_conwidth;
                                candidate_pos_x = 0;
                        }
                }
  
-               tab_panels[tab_panel] = tab_panel;
+               tab_panels[tab_panel.panel_id] = tab_panel;
        }
        else if(nPrimary == K_SPACE && hudShiftState & S_CTRL) // enable/disable highlighted panel or dock
        {
                if (bInputType == 1 || mouseClicked)
                        return true;
  
-               if (highlightedPanel != -1)
-               {
-                       HUD_Panel_GetName(highlightedPanel);
-                       cvar_set(strcat("hud_panel_", panel_name), ftos(!(panel_enabled)));
-               }
+               if (highlightedPanel)
+                       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name), ftos(!cvar(strcat("hud_panel_", highlightedPanel.panel_name))));
                else
                        cvar_set(strcat("hud_dock"), (autocvar_hud_dock == "") ? "dock" : "");
        }
                if (bInputType == 1 || mouseClicked)
                        return true;
  
-               if (highlightedPanel != -1)
+               if (highlightedPanel)
                {
-                       HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+                       panel = highlightedPanel;
+                       HUD_Panel_UpdatePosSize()
                        panel_size_copied = panel_size;
-                       highlightedPanel_copied = highlightedPanel;
                }
        }
        else if(nPrimary == 'v' && hudShiftState & S_CTRL) // past copied size on the highlighted panel
                if (bInputType == 1 || mouseClicked)
                        return true;
  
-               if (highlightedPanel_copied == -1 || highlightedPanel == -1)
+               if (panel_size_copied == '0 0 0' || !highlightedPanel)
                        return true;
  
-               HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+               panel = highlightedPanel;
+               HUD_Panel_UpdatePosSize()
  
                // reduce size if it'd go beyond screen boundaries
                vector tmp_size = panel_size_copied;
                highlightedPanel_backup = highlightedPanel;
  
                s = strcat(ftos(tmp_size_x/vid_conwidth), " ", ftos(tmp_size_y/vid_conheight));
-               HUD_Panel_GetName(highlightedPanel);
-               cvar_set(strcat("hud_panel_", panel_name, "_size"), s);
+               cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
        }
        else if(nPrimary == 'z' && hudShiftState & S_CTRL) // undo last action
        {
                if (bInputType == 1 || mouseClicked)
                        return true;
                //restore previous values
-               if (highlightedPanel_backup != -1)
+               if (highlightedPanel_backup)
                {
-                       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);
+                       cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_pos"), s);
                        s = strcat(ftos(panel_size_backup_x/vid_conwidth), " ", ftos(panel_size_backup_y/vid_conheight));
-                       cvar_set(strcat("hud_panel_", panel_name, "_size"), s);
-                       highlightedPanel_backup = -1;
+                       cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_size"), s);
+                       highlightedPanel_backup = world;
                }
        }
        else if(nPrimary == K_UPARROW || nPrimary == K_DOWNARROW || nPrimary == K_LEFTARROW || nPrimary == K_RIGHTARROW)
        {
                if (bInputType == 1)
                        return true;
-               if (highlightedPanel != -1)
+               if (highlightedPanel)
                        HUD_Panel_EnableMenu();
        }
        else if(hit_con_bind)
@@@ -924,7 -924,8 +934,8 @@@ float HUD_Panel_Check_Mouse_Pos(float a
                i = panel_order[j];
                j += 1;
  
-               HUD_Panel_UpdatePosSizeForId(i);
+               panel = hud_panel[i];
+               HUD_Panel_UpdatePosSize()
  
                border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
  
@@@ -982,7 -983,7 +993,7 @@@ void HUD_Panel_FirstInDrawQ(float id
        }
        // now save the new top id
        panel_order[0] = id;
-       
        // let's save them into the cvar by some strcat trickery
        string s = "";
        for(i = 0; i < HUD_PANEL_NUM; ++i)
@@@ -1004,14 -1005,15 +1015,15 @@@ void HUD_Panel_Highlight(float allow_mo
                i = panel_order[j];
                j += 1;
  
-               HUD_Panel_UpdatePosSizeForId(i);
+               panel = hud_panel[i];
+               HUD_Panel_UpdatePosSize()
  
                border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
  
                // move
                if(allow_move && mousepos_x > panel_pos_x && mousepos_y > panel_pos_y && mousepos_x < panel_pos_x + panel_size_x && mousepos_y < panel_pos_y + panel_size_y)
                {
-                       highlightedPanel = i;
+                       highlightedPanel = hud_panel[i];
                        HUD_Panel_FirstInDrawQ(i);
                        highlightedAction = 1;
                        panel_click_distance = mousepos - panel_pos;
                // resize from topleft border
                else if(mousepos_x >= panel_pos_x - border && mousepos_y >= panel_pos_y - border && mousepos_x <= panel_pos_x + 0.5 * panel_size_x && mousepos_y <= panel_pos_y + 0.5 * panel_size_y)
                {
-                       highlightedPanel = i;
+                       highlightedPanel = hud_panel[i];
                        HUD_Panel_FirstInDrawQ(i);
                        highlightedAction = 2;
                        resizeCorner = 1;
                // resize from topright border
                else if(mousepos_x >= panel_pos_x + 0.5 * panel_size_x && mousepos_y >= panel_pos_y - border && mousepos_x <= panel_pos_x + panel_size_x + border && mousepos_y <= panel_pos_y + 0.5 * panel_size_y)
                {
-                       highlightedPanel = i;
+                       highlightedPanel = hud_panel[i];
                        HUD_Panel_FirstInDrawQ(i);
                        highlightedAction = 2;
                        resizeCorner = 2;
                // resize from bottomleft border
                else if(mousepos_x >= panel_pos_x - border && mousepos_y >= panel_pos_y + 0.5 * panel_size_y && mousepos_x <= panel_pos_x + 0.5 * panel_size_x && mousepos_y <= panel_pos_y + panel_size_y + border)
                {
-                       highlightedPanel = i;
+                       highlightedPanel = hud_panel[i];
                        HUD_Panel_FirstInDrawQ(i);
                        highlightedAction = 2;
                        resizeCorner = 3;
                // resize from bottomright border
                else if(mousepos_x >= panel_pos_x + 0.5 * panel_size_x && mousepos_y >= panel_pos_y + 0.5 * panel_size_y && mousepos_x <= panel_pos_x + panel_size_x + border && mousepos_y <= panel_pos_y + panel_size_y + border)
                {
-                       highlightedPanel = i;
+                       highlightedPanel = hud_panel[i];
                        HUD_Panel_FirstInDrawQ(i);
                        highlightedAction = 2;
                        resizeCorner = 4;
                        return;
                }
        }
-       highlightedPanel = -1;
+       highlightedPanel = world;
        highlightedAction = 0;
  }
  
  void HUD_Panel_EnableMenu()
  {
        menu_enabled = 2;
-       menu_enabled_time = time;
-       HUD_Panel_GetName(highlightedPanel);
-       localcmd("menu_showhudoptions ", panel_name, "\n");
+       localcmd("menu_showhudoptions ", highlightedPanel.panel_name, "\n");
  }
  float mouse_over_panel;
  void HUD_Panel_Mouse()
  {
-       // TODO: needs better check... is there any float that contains the current state of the menu? _menu_alpha isn't apparently updated the frame the menu gets enabled
-       if (autocvar__menu_alpha == 0 && time - menu_enabled_time > 0.5)
-               menu_enabled = 0;
-       /*
-       print("menu_enabled: ", ftos(menu_enabled), "\n");
-       print("Highlighted: ", ftos(highlightedPanel), "\n");
-       print("Menu theAlpha: ", ftos(autocvar__menu_alpha), "\n");
-       */
        if(autocvar__menu_alpha == 1)
                return;
  
-       if not(autocvar_hud_cursormode)
+       if (!autocvar_hud_cursormode)
        {
                mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
-               
                mousepos_x = bound(0, mousepos_x, vid_conwidth);
                mousepos_y = bound(0, mousepos_y, vid_conheight);
        }
        {
                if(prevMouseClicked == 0)
                {
-                       if (tab_panel != -1)
+                       if (tab_panel)
                        {
                                //stop ctrl-tab selection
-                               tab_panel = -1;
+                               tab_panel = world;
                                reset_tab_panels();
                        }
                        HUD_Panel_Highlight(mouseClicked & S_MOUSE1); // sets highlightedPanel, highlightedAction, panel_click_distance, panel_click_resizeorigin
-                                                                       // and calls HUD_Panel_UpdatePosSizeForId() for the highlighted panel
-                       if (highlightedPanel != -1)
+                                                                       // and calls HUD_Panel_UpdatePosSize() for the highlighted panel
+                       if (highlightedPanel)
                        {
                                highlightedPanel_initial_pos = panel_pos;
                                highlightedPanel_initial_size = panel_size;
                        }
                        // doubleclick check
-                       if ((mouseClicked & S_MOUSE1) && time - prevMouseClickedTime < 0.4 && highlightedPanel != -1 && prevMouseClickedPos == mousepos)
+                       if ((mouseClicked & S_MOUSE1) && time - prevMouseClickedTime < 0.4 && highlightedPanel && prevMouseClickedPos == mousepos)
                        {
                                mouseClicked = 0; // to prevent spam, I guess.
                                HUD_Panel_EnableMenu();
                        }
                }
                else
-                       HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+               {
+                       panel = highlightedPanel;
+                       HUD_Panel_UpdatePosSize()
+               }
  
-               if (highlightedPanel != -1)
+               if (highlightedPanel)
                {
                        drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
                        if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
                        mouse_over_panel = 0;
                else
                        mouse_over_panel = HUD_Panel_Check_Mouse_Pos(TRUE);
-               if (mouse_over_panel && tab_panel == -1)
+               if (mouse_over_panel && !tab_panel)
                        drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
        }
        // draw cursor after performing move/resize to have the panel pos/size updated before mouse_over_panel
  
        prevMouseClicked = mouseClicked;
  }
+ void HUD_Configure_DrawGrid()
+ {
+       float i;
+       if(autocvar_hud_configure_grid && autocvar_hud_configure_grid_alpha)
+       {
+               hud_configure_gridSize_x = bound(0.005, cvar("hud_configure_grid_xsize"), 0.2);
+               hud_configure_gridSize_y = bound(0.005, cvar("hud_configure_grid_ysize"), 0.2);
+               hud_configure_realGridSize_x = hud_configure_gridSize_x * vid_conwidth;
+               hud_configure_realGridSize_y = hud_configure_gridSize_y * vid_conheight;
+               vector s;
+               // x-axis
+               s = eX + eY * vid_conheight;
+               for(i = 1; i < 1/hud_configure_gridSize_x; ++i)
+                       drawfill(eX * i * hud_configure_realGridSize_x, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
+               // y-axis
+               s = eY + eX * vid_conwidth;
+               for(i = 1; i < 1/hud_configure_gridSize_y; ++i)
+                       drawfill(eY * i * hud_configure_realGridSize_y, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
+       }
+ }
+ float _menu_alpha_prev;
+ void HUD_Configure_Frame()
+ {
+       float i;
+       if(autocvar__hud_configure)
+       {
+               if(isdemo() || intermission == 2)
+               {
+                       HUD_Configure_Exit_Force();
+                       return;
+               }
+               if(!hud_configure_prev || hud_configure_prev == -1)
+               {
+                       if(autocvar_hud_cursormode)
+                               setcursormode(1);
+                       hudShiftState = 0;
+                       for(i = HUD_PANEL_NUM - 1; i >= 0; --i)
+                               hud_panel[panel_order[i]].update_time = time;
+               }
+               // NOTE this check is necessary because _menu_alpha isn't updated the frame the menu gets enabled
+               if(autocvar__menu_alpha != _menu_alpha_prev)
+               {
+                       if(autocvar__menu_alpha == 0)
+                               menu_enabled = 0;
+                       _menu_alpha_prev = autocvar__menu_alpha;
+               }
+               HUD_Configure_DrawGrid();
+       }
+       else if(hud_configure_prev)
+       {
+               if(menu_enabled)
+                       menu_enabled = 0;
+               if(autocvar_hud_cursormode)
+                       setcursormode(0);
+       }
+ }
  
  const float hlBorderSize = 4;
  const string hlBorder = "gfx/hud/default/border_highlighted";
@@@ -1210,3 -1263,22 +1273,22 @@@ void HUD_Panel_HlBorder(float myBorder
        drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * hlBorderSize, hlBorder2, '1 8 0' * hlBorderSize, eY * (panel_size_y + 2 * myBorder - 2 * hlBorderSize) + eX * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
        drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * hlBorderSize + eX * (panel_size_x + 2 * myBorder - hlBorderSize), hlBorder2, '1 8 0' * hlBorderSize, eY * (panel_size_y + 2 * myBorder - 2 * hlBorderSize) + eX * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
  }
+ void HUD_Configure_PostDraw()
+ {
+       if(autocvar__hud_configure)
+       {
+               if(tab_panel)
+               {
+                       panel = tab_panel;
+                       HUD_Panel_UpdatePosSize()
+                       drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .2, DRAWFLAG_NORMAL);
+               }
+               if(highlightedPanel)
+               {
+                       panel = highlightedPanel;
+                       HUD_Panel_UpdatePosSize()
+                       HUD_Panel_HlBorder(panel_bg_border + 1.5 * hlBorderSize, '0 0.5 1', 0.25 * (1 - autocvar__menu_alpha));
+               }
+       }
+ }
index 87341be960f61c1bf60e8ffb1ac74f0946cf992f,2df3dd411bc6d9f4da76ef4124a81fa51658c8fc..3c23911a030e9df1dcab970af6ed1d578aec0898
@@@ -38,14 -38,14 +38,14 @@@ float waypointsprite_alpha
  .float build_starthealth;
  .float build_finished;
  
- float SPRITE_HEALTHBAR_WIDTH = 144;
- float SPRITE_HEALTHBAR_HEIGHT = 9;
- float SPRITE_HEALTHBAR_MARGIN = 6;
- float SPRITE_HEALTHBAR_BORDER = 2;
- float SPRITE_HEALTHBAR_BORDERALPHA = 1;
- float SPRITE_HEALTHBAR_HEALTHALPHA = 0.5;
- float SPRITE_ARROW_SCALE = 1.0;
- float SPRITE_HELPME_BLINK = 2;
const float SPRITE_HEALTHBAR_WIDTH = 144;
const float SPRITE_HEALTHBAR_HEIGHT = 9;
const float SPRITE_HEALTHBAR_MARGIN = 6;
const float SPRITE_HEALTHBAR_BORDER = 2;
const float SPRITE_HEALTHBAR_BORDERALPHA = 1;
const float SPRITE_HEALTHBAR_HEALTHALPHA = 0.5;
const float SPRITE_ARROW_SCALE = 1.0;
const float SPRITE_HELPME_BLINK = 2;
  
  void drawrotpic(vector org, float rot, string pic, vector sz, vector hotspot, vector rgb, float a, float f)
  {
@@@ -96,7 -96,7 +96,7 @@@ void drawhealthbar(vector org, float ro
        o = hotspot;
        ri = '1 0 0';
        up = '0 1 0';
-       
        rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
        o = rotate(o, rot) + org;
        ri = rotate(ri, rot);
  // returns location of sprite text
  vector drawspritearrow(vector o, float ang, vector rgb, float a, float t)
  {
-       float SQRT2 = 1.414;
-       float BORDER; BORDER = 1.5 * t;
-       float TSIZE; TSIZE = 8 * t;
-       float RLENGTH; RLENGTH = 8 * t;
-       float RWIDTH; RWIDTH = 4 * t;
-       float MLENGTH; MLENGTH = 4 * t;
+       float size   = 9.0 * t;
+       float border = 1.5 * t;
+       float margin = 4.0 * t;
+       float borderDiag = border * 1.414;
+       vector arrowX  = eX * size;
+       vector arrowY  = eY * (size+borderDiag);
+       vector borderX = eX * (size+borderDiag);
+       vector borderY = eY * (size+borderDiag+border);
  
        R_BeginPolygon("", DRAWFLAG_NORMAL);
-       R_PolygonVertex(o + rotate(eX * -(TSIZE + BORDER * (1 + SQRT2)) + eY * (TSIZE + BORDER), ang), '0 0 0', '0 0 0', a);
-       R_PolygonVertex(o + rotate(eX *  (TSIZE + BORDER * (1 + SQRT2)) + eY * (TSIZE + BORDER), ang), '0 0 0', '0 0 0', a);
-       R_PolygonVertex(o + rotate(eY * -(        BORDER *      SQRT2),                          ang), '0 0 0', '0 0 0', a);
-       R_EndPolygon();
-       R_BeginPolygon("", DRAWFLAG_NORMAL);
-       R_PolygonVertex(o + rotate(eX * -(RWIDTH + BORDER) + eY * (TSIZE           + BORDER), ang), '0 0 0', '0 0 0', a);
-       R_PolygonVertex(o + rotate(eX * -(RWIDTH + BORDER) + eY * (TSIZE + RLENGTH + BORDER), ang), '0 0 0', '0 0 0', a);
-       R_PolygonVertex(o + rotate(eX *  (RWIDTH + BORDER) + eY * (TSIZE + RLENGTH + BORDER), ang), '0 0 0', '0 0 0', a);
-       R_PolygonVertex(o + rotate(eX *  (RWIDTH + BORDER) + eY * (TSIZE           + BORDER), ang), '0 0 0', '0 0 0', a);
+       R_PolygonVertex(o,                                  '0 0 0', '0 0 0', a);
+       R_PolygonVertex(o + rotate(arrowY  - borderX, ang), '0 0 0', '0 0 0', a);
+       R_PolygonVertex(o + rotate(borderY - borderX, ang), '0 0 0', '0 0 0', a);
+       R_PolygonVertex(o + rotate(borderY + borderX, ang), '0 0 0', '0 0 0', a);
+       R_PolygonVertex(o + rotate(arrowY  + borderX, ang), '0 0 0', '0 0 0', a);
        R_EndPolygon();
  
        R_BeginPolygon("", DRAWFLAG_ADDITIVE);
-       R_PolygonVertex(o + rotate(eX * -TSIZE + eY * TSIZE, ang), '0 0 0', rgb, a);
-       R_PolygonVertex(o + rotate(eX *  TSIZE + eY * TSIZE, ang), '0 0 0', rgb, a);
-       R_PolygonVertex(o + rotate('0 0 0',                  ang), '0 0 0', rgb, a);
-       R_EndPolygon();
-       R_BeginPolygon("", DRAWFLAG_ADDITIVE);
-       R_PolygonVertex(o + rotate(eX * -RWIDTH + eY *  TSIZE,            ang), '0 0 0', rgb, a);
-       R_PolygonVertex(o + rotate(eX * -RWIDTH + eY * (TSIZE + RLENGTH), ang), '0 0 0', rgb, a);
-       R_PolygonVertex(o + rotate(eX *  RWIDTH + eY * (TSIZE + RLENGTH), ang), '0 0 0', rgb, a);
-       R_PolygonVertex(o + rotate(eX *  RWIDTH + eY *  TSIZE,            ang), '0 0 0', rgb, a);
+       R_PolygonVertex(o + rotate(eY * borderDiag, ang), '0 0 0', rgb, a);
+       R_PolygonVertex(o + rotate(arrowY - arrowX, ang), '0 0 0', rgb, a);
+       R_PolygonVertex(o + rotate(arrowY + arrowX, ang), '0 0 0', rgb, a);
        R_EndPolygon();
  
-       return
-               o + rotate(eY * (TSIZE + RLENGTH + MLENGTH), ang);
+       return o + rotate(eY * (borderDiag+size+margin), ang);
  }
  
  // returns location of sprite healthbar
@@@ -212,8 -204,6 +204,8 @@@ float spritelookupblinkvalue(string s
                case "ons-cp-atck-blue": return 2;
                case "ons-cp-dfnd-red":  return 0.5;
                case "ons-cp-dfnd-blue": return 0.5;
 +              case "item_health_mega": return 2;
 +              case "item_armor_large": return 2;
                case "item-invis":       return 2;
                case "item-extralife":   return 2;
                case "item-speed":       return 2;
                case "item-shield":      return 2;
                case "item-fuelregen":   return 2;
                case "item-jetpack":     return 2;
 +              case "wpn-fireball":     return 2; // superweapon
 +              case "wpn-minstanex":    return 2; // superweapon
 +              case "wpn-porto":        return 2; // superweapon
                case "tagged-target":    return 2;
                default:                 return 1;
        }
  }
  vector spritelookupcolor(string s, vector def)
  {
+       if(substring(s, 0, 4) == "wpn-")
+               return (get_weaponinfo(stof(substring(s, 4, strlen(s)))).wpcolor);
        switch(s)
        {
                case "keycarrier-friend": return '0 1 0';
-               case "wpn-laser":         return '1 0.5 0.5';
-               case "wpn-shotgun":       return '0.5 0.25 0';
-               case "wpn-uzi":           return '1 1 0';
-               case "wpn-gl":            return '1 0 0';
-               case "wpn-electro":       return '0 0.5 1';
-               case "wpn-crylink":       return '1 0.5 1';
-               case "wpn-nex":           return '0.5 1 1';
-               case "wpn-hagar":         return '1 1 0.5';
-               case "wpn-rl":            return '1 1 0';
-               case "wpn-porto":         return '0.5 0.5 0.5';
-               case "wpn-minstanex":     return '0.5 1 1';
-               case "wpn-hookgun":       return '0 0.5 0';
-               case "wpn-fireball":      return '1 0.5 0';
-               case "wpn-hlac":          return '0 1 0';
-               case "wpn-campingrifle":  return '0.5 1 0';
-               case "wpn-minelayer":     return '0.75 1 0';
                default:                  return def;
        }
  }
  string spritelookuptext(string s)
  {
+       if(substring(s, 0, 4) == "wpn-") { return (get_weaponinfo(stof(substring(s, 4, strlen(s)))).message); }
+       if(substring(s, 0, 5) == "buff-") { return Buff_PrettyName(Buff_Type_FromSprite(s)); }
        switch(s)
        {
                case "as-push": return _("Push");
                case "race-finish": return _("Finish");
                case "race-start": return _("Start");
                case "race-start-finish": return (race_checkpointtime || race_mycheckpointtime) ? _("Finish") : _("Start");
+               case "goal": return _("Goal");
                case "nb-ball": return _("Ball");
                case "ka-ball": return _("Ball");
                case "ka-ballcarrier": return _("Ball carrier");
-               case "wpn-laser": return _("Laser");
-               case "wpn-shotgun": return _("Shotgun");
-               case "wpn-uzi": return _("Machine Gun");
-               case "wpn-gl": return _("Mortar");
-               case "wpn-electro": return _("Electro");
-               case "wpn-crylink": return _("Crylink");
-               case "wpn-nex": return _("Nex");
-               case "wpn-hagar": return _("Hagar");
-               case "wpn-rl": return _("Rocket Launcher");
-               case "wpn-porto": return _("Port-O-Launch");
-               case "wpn-minstanex": return _("Minstanex");
-               case "wpn-hookgun": return _("Hook");
-               case "wpn-fireball": return _("Fireball");
-               case "wpn-hlac": return _("HLAC");
-               case "wpn-campingrifle": return _("Rifle");
-               case "wpn-minelayer": return _("Mine Layer");
                case "dom-neut": return _("Control point");
                case "dom-red": return _("Control point");
                case "dom-blue": return _("Control point");
                case "dom-yellow": return _("Control point");
                case "dom-pink": return _("Control point");
 +              case "item_health_mega": return _("Mega health");
 +              case "item_armor_large": return _("Large armor");
                case "item-invis": return _("Invisibility");
                case "item-extralife": return _("Extra life");
                case "item-speed": return _("Speed");
                case "item-strength": return _("Strength");
                case "item-shield": return _("Shield");
-               case "item-fuelregen": return _("Fuel regenerator");
-               case "item-jetpack": return _("Jet pack");
-               case "freezetag_frozen": return _("Frozen!");
+               case "item-fuelregen": return _("Fuel regen");
+               case "item-jetpack": return _("Jet Pack");
+               case "frozen": return _("Frozen!");
                case "tagged-target": return _("Tagged");
                case "vehicle": return _("Vehicle");
                default: return s;
@@@ -418,12 -378,6 +385,12 @@@ void Draw_WaypointSprite(
        // choose the sprite
        switch(self.rule)
        {
-                       if not(autocvar_g_waypointsprite_itemstime == 1 && t == NUM_SPECTATOR + 1
-                       || autocvar_g_waypointsprite_itemstime == 2 && (t == NUM_SPECTATOR + 1 || warmup_stage))
 +              case SPRITERULE_SPECTATOR:
++                      if not((autocvar_g_waypointsprite_itemstime == 1 && t == NUM_SPECTATOR + 1)
++                      || (autocvar_g_waypointsprite_itemstime == 2 && (t == NUM_SPECTATOR + 1 || warmup_stage)))
 +                              return;
 +                      spriteimage = self.netname;
 +                      break;
                case SPRITERULE_DEFAULT:
                        if(self.team)
                        {
                return;
  
        ++waypointsprite_newcount;
-       
        float dist;
        dist = vlen(self.origin - view_origin);
-       
        float a;
        a = self.alpha * autocvar_hud_panel_fg_alpha;
  
        if(rgb == '0 0 0')
        {
                self.teamradar_color = '1 0 1';
-               print(sprintf("WARNING: sprite of name %s has no color, using pink so you notice it\n", spriteimage)); 
+               printf("WARNING: sprite of name %s has no color, using pink so you notice it\n", spriteimage);
        }
  
        if(time - floor(time) > 0.5)
        float ang;
  
        o = project_3d_to_2d(self.origin);
-       if(o_z < 0 
-       || o_x < (vid_conwidth * waypointsprite_edgeoffset_left) 
-       || o_y < (vid_conheight * waypointsprite_edgeoffset_top) 
-       || o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))  
+       if(o_z < 0
+       || o_x < (vid_conwidth * waypointsprite_edgeoffset_left)
+       || o_y < (vid_conheight * waypointsprite_edgeoffset_top)
+       || o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))
        || o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
        {
                // scale it to be just in view
        o_z = 0;
  
        float edgedistance_min, crosshairdistance;
-               edgedistance_min = min((o_y - (vid_conheight * waypointsprite_edgeoffset_top)), 
+               edgedistance_min = min((o_y - (vid_conheight * waypointsprite_edgeoffset_top)),
        (o_x - (vid_conwidth * waypointsprite_edgeoffset_left)),
-       (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right)) - o_x, 
+       (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right)) - o_x,
        (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)) - o_y);
  
        float vidscale;
        }
  
        o = drawspritearrow(o, ang, rgb, a, SPRITE_ARROW_SCALE * t);
-       
        string txt;
        if(autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
                txt = _("Spam");
@@@ -747,7 -701,7 +714,7 @@@ void Ent_WaypointSprite(
                if(f & 0x80)
                {
                        self.(teamradar_times[self.teamradar_time_index]) = time;
-                       self.teamradar_time_index = mod(self.teamradar_time_index + 1, MAX_TEAMRADAR_TIMES);
+                       self.teamradar_time_index = (self.teamradar_time_index + 1) % MAX_TEAMRADAR_TIMES;
                }
                self.teamradar_color_x = ReadByte() / 255.0;
                self.teamradar_color_y = ReadByte() / 255.0;
index 898495764b60dfa322ecbf70731da392a24fac20,8586cffa9d539ff5f56067ab570df0e132f43ce6..9b9bded9b98f557f5f3d99bcfd9499d5593980ec
  // Revision 22: hook shot origin
  #define CSQC_REVISION 22
  
- const float AS_STRING         = 1;
- const float AS_INT            = 2;
- const float AS_FLOAT_TRUNCATED        = 2;
- const float AS_FLOAT          = 8;
+ const float AS_STRING = 1;
+ const float AS_INT = 2;
+ const float AS_FLOAT_TRUNCATED = 2;
+ const float AS_FLOAT = 8;
  
  const float TE_CSQC_PICTURE = 100;
  const float TE_CSQC_RACE = 101;
- const float TE_CSQC_SPAWN = 102;
- const float TE_CSQC_ZCURVEPARTICLES = 103;
- const float TE_CSQC_NEXGUNBEAMPARTICLE = 104;
- const float TE_CSQC_LIGHTNINGARC = 105;
- const float TE_CSQC_TEAMNAGGER = 106;
- const float TE_CSQC_PINGPLREPORT = 107;
- const float TE_CSQC_ANNOUNCE = 108;
- const float TE_CSQC_TARGET_MUSIC = 109;
- const float TE_CSQC_WEAPONCOMPLAIN = 110;
- const float TE_CSQC_NEX_SCOPE = 111;
- const float TE_CSQC_MINELAYER_MAXMINES = 112;
- const float TE_CSQC_HAGAR_MAXROCKETS = 113;
- const float TE_CSQC_VEHICLESETUP = 114;
- const float TE_CSQC_SVNOTICE = 115;
+ const float TE_CSQC_VORTEXBEAMPARTICLE = 103;
+ const float TE_CSQC_ARC = 104;
+ const float TE_CSQC_TEAMNAGGER = 105;
+ const float TE_CSQC_PINGPLREPORT = 106;
+ const float TE_CSQC_TARGET_MUSIC = 107;
+ const float TE_CSQC_WEAPONCOMPLAIN = 108;
+ const float TE_CSQC_VORTEX_SCOPE = 109;
+ const float TE_CSQC_MINELAYER_MAXMINES = 110;
+ const float TE_CSQC_HAGAR_MAXROCKETS = 111;
+ const float TE_CSQC_VEHICLESETUP = 112;
+ const float TE_CSQC_SVNOTICE = 113;
+ const float TE_CSQC_SHOCKWAVEPARTICLE = 114;
  
  const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder
  const float RACE_NET_CHECKPOINT_CLEAR = 1;
@@@ -88,23 -86,25 +86,26 @@@ const float ENT_CLIENT_WARPZONE = 24
  const float ENT_CLIENT_WARPZONE_CAMERA = 25;
  const float ENT_CLIENT_TRIGGER_MUSIC = 26;
  const float ENT_CLIENT_HOOK = 27;
- const float ENT_CLIENT_LGBEAM = 28;
- const float ENT_CLIENT_GAUNTLET = 29;
+ const float ENT_CLIENT_ARC_BEAM = 29; // WEAPONTODO: fix numbers
  const float ENT_CLIENT_ACCURACY = 30;
  const float ENT_CLIENT_SHOWNAMES = 31;
  const float ENT_CLIENT_WARPZONE_TELEPORTED = 32;
  const float ENT_CLIENT_MODEL = 33;
  const float ENT_CLIENT_ITEM = 34;
  const float ENT_CLIENT_BUMBLE_RAYGUN = 35;
- const float ENT_CLIENT_NOTIFICATION = 36;
+ const float ENT_CLIENT_SPAWNPOINT = 36;
+ const float ENT_CLIENT_SPAWNEVENT = 37;
+ const float ENT_CLIENT_NOTIFICATION = 38;
+ const float ENT_CLIENT_ELIMINATEDPLAYERS = 39;
  const float ENT_CLIENT_TURRET = 40;
  const float ENT_CLIENT_AUXILIARYXHAIR = 50;
  const float ENT_CLIENT_VEHICLE = 60;
  
+ const float ENT_CLIENT_HEALING_ORB = 80;
  const float SPRITERULE_DEFAULT = 0;
  const float SPRITERULE_TEAMPLAY = 1;
 +const float SPRITERULE_SPECTATOR = 2;
  
  const float RADARICON_NONE = 0;
  const float RADARICON_FLAG = 1;
@@@ -122,112 -122,37 +123,37 @@@ const float RADARICON_TAGGED = 1
  
  ///////////////////////////
  // keys pressed
- const float KEY_FORWARD               =       1;
- const float KEY_BACKWARD      =       2;
- const float KEY_LEFT          =       4;
- const float KEY_RIGHT         =       8;
- const float KEY_JUMP          =       16;
- const float KEY_CROUCH                =       32;
- const float KEY_ATCK          =       64;
- const float KEY_ATCK2         =       128;
+ const float KEY_FORWARD = 1;
+ const float KEY_BACKWARD = 2;
+ const float KEY_LEFT = 4;
+ const float KEY_RIGHT = 8;
+ const float KEY_JUMP = 16;
+ const float KEY_CROUCH = 32;
+ const float KEY_ATCK = 64;
+ const float KEY_ATCK2 = 128;
  
  ///////////////////////////
  // cvar constants
  
float CVAR_SAVE       = 1;
float CVAR_NOTIFY     = 2;
float CVAR_READONLY   = 4;
const float CVAR_SAVE = 1;
const float CVAR_NOTIFY = 2;
const float CVAR_READONLY = 4;
  
  ///////////////////////////
  // csqc communication stuff
  
- const float STAT_KH_KEYS = 32;
- const float STAT_CTF_STATE = 33;
- const float STAT_WEAPONS = 35;
- const float STAT_SWITCHWEAPON = 36;
- const float STAT_GAMESTARTTIME = 37;
- const float STAT_STRENGTH_FINISHED = 38;
- const float STAT_INVINCIBLE_FINISHED = 39;
- const float STAT_PRESSED_KEYS = 42;
- const float STAT_ALLOW_OLDNEXBEAM = 43; // this stat could later contain some other bits of info, like, more server-side particle config
- const float STAT_FUEL = 44;
- const float STAT_NB_METERSTART = 45;
- const float STAT_SHOTORG = 46; // compressShotOrigin
- const float STAT_LEADLIMIT = 47;
- const float STAT_WEAPON_CLIPLOAD = 48;
- const float STAT_WEAPON_CLIPSIZE = 49;
- const float STAT_NEX_CHARGE = 50;
- const float STAT_LAST_PICKUP = 51;
- const float STAT_HUD = 52;
- const float STAT_NEX_CHARGEPOOL = 53;
- const float STAT_HIT_TIME = 54;
- const float STAT_TYPEHIT_TIME = 55;
- const float STAT_LAYED_MINES = 56;
- const float STAT_HAGAR_LOAD = 57;
- const float STAT_SWITCHINGWEAPON = 58;
- const float STAT_SUPERWEAPONS_FINISHED = 59;
- const float STAT_VEHICLESTAT_HEALTH  = 60;
- const float STAT_VEHICLESTAT_SHIELD  = 61;
- const float STAT_VEHICLESTAT_ENERGY  = 62;
- const float STAT_VEHICLESTAT_AMMO1   = 63;
- const float STAT_VEHICLESTAT_RELOAD1 = 64;
- const float STAT_VEHICLESTAT_AMMO2   = 65;
- const float STAT_VEHICLESTAT_RELOAD2 = 66;
- const float STAT_SECRETS_TOTAL = 70;
- const float STAT_SECRETS_FOUND = 71;
- const float STAT_RESPAWN_TIME = 72;
- const float STAT_ARMOR_LARGE_TIME = 80;
- const float STAT_HEALTH_MEGA_TIME = 81;
- const float STAT_INVISIBLE_TIME = 82;
- const float STAT_SPEED_TIME = 83;
- const float STAT_EXTRALIFE_TIME = 84;
- const float STAT_STRENGTH_TIME = 85;
- const float STAT_SHIELD_TIME = 86;
- const float STAT_FUELREGEN_TIME = 87;
- const float STAT_JETPACK_TIME = 88;
- const float STAT_SUPERWEAPONS_TIME = 89;
- // mod stats (1xx)
- const float STAT_REDALIVE = 100;
- const float STAT_BLUEALIVE = 101;
- const float STAT_YELLOWALIVE = 102;
- const float STAT_PINKALIVE = 103;
- // freeze tag
- const float STAT_FROZEN = 104;
- const float STAT_REVIVE_PROGRESS = 105;
- // domination
- const float STAT_DOM_TOTAL_PPS = 100;
- const float STAT_DOM_PPS_RED = 101;
- const float STAT_DOM_PPS_BLUE = 102;
- const float STAT_DOM_PPS_PINK = 103;
- const float STAT_DOM_PPS_YELLOW = 104;
- //const float STAT_SPIDERBOT_AIM     53 // compressShotOrigin
- //const float STAT_SPIDERBOT_TARGET  54 // compressShotOrigin
- // see DP source, quakedef.h
- const float STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW = 222;
- const float STAT_MOVEVARS_AIRSTRAFEACCEL_QW = 223;
- const float STAT_MOVEVARS_MAXSPEED = 244;
- const float STAT_MOVEVARS_AIRACCEL_QW = 254;
  const float CTF_STATE_ATTACK = 1;
  const float CTF_STATE_DEFEND = 2;
  const float CTF_STATE_COMMANDER = 3;
  
  const float HUD_NORMAL = 0;
- const float HUD_VEHICLE_FIRST   = 10;
- const float HUD_SPIDERBOT       = 10;
- const float HUD_WAKIZASHI       = 11;
- const float HUD_RAPTOR          = 12;
- const float HUD_BUMBLEBEE       = 13;
- const float HUD_BUMBLEBEE_GUN   = 14;
- const float HUD_VEHICLE_LAST    = 14;
+ const float HUD_VEHICLE_FIRST = 10;
+ const float HUD_SPIDERBOT = 10;
+ const float HUD_WAKIZASHI = 11;
+ const float HUD_RAPTOR = 12;
+ const float HUD_BUMBLEBEE = 13;
+ const float HUD_BUMBLEBEE_GUN = 14;
+ const float HUD_VEHICLE_LAST = 14;
  
  const vector eX = '1 0 0';
  const vector eY = '0 1 0';
@@@ -235,32 -160,32 +161,32 @@@ const vector eZ = '0 0 1'
  
  // moved that here so the client knows the max.
  // # of maps, I'll use arrays for them :P
- #define MAPVOTE_COUNT 10
+ #define MAPVOTE_COUNT 30
  
  /**
   * Lower scores are better (e.g. suicides)
   */
- #define SFL_LOWER_IS_BETTER     1
+ #define SFL_LOWER_IS_BETTER 1
  
  /**
   * Don't show zero values as scores
   */
- #define SFL_HIDE_ZERO           2
+ #define SFL_HIDE_ZERO 2
  
  /**
   * Allow a column to be hidden (do not automatically add it even if it is a sorting key)
   */
- #define SFL_ALLOW_HIDE         16
+ #define SFL_ALLOW_HIDE 16
  
  /**
   * Display as a rank (with st, nd, rd, th suffix)
   */
- #define SFL_RANK               32
+ #define SFL_RANK 32
  
  /**
   * Display as mm:ss.s, value is stored as 10ths of a second (AND 0 is the worst possible value!)
   */
- #define SFL_TIME               64
+ #define SFL_TIME 64
  
  // not an extra constant yet
  #define SFL_ZERO_IS_WORST SFL_TIME
   * Scoring priority (NOTE: PRIMARY is used for fraglimit)
   */
  #define SFL_SORT_PRIO_SECONDARY 4
- #define SFL_SORT_PRIO_PRIMARY   8
- #define SFL_SORT_PRIO_MASK     12
+ #define SFL_SORT_PRIO_PRIMARY 8
+ #define SFL_SORT_PRIO_MASK 12
  
  /**
   * Score indices
  #define SP_SCORE 3
  // game mode specific indices are not in common/, but in server/scores_rules.qc!
  
- #ifdef COMPAT_XON010_CHANNELS
- float CH_INFO = 0; // only on world and csqc
- float CH_TRIGGER = 0; // only on players; compat: FALSELY CONTROLLED BY "Info"
- float CH_WEAPON_A = 1; // only on players and entities
- float CH_WEAPON_SINGLE = 5; // only on players and entities
- float CH_VOICE = 2; // only on players
- float CH_BGM_SINGLE = 2; // only on csqc; compat: FALSELY CONTROLLED BY "Voice"
- float CH_AMBIENT = 2; // only on csqc; compat: FALSELY CONTROLLED BY "Voice"
- float CH_TRIGGER_SINGLE = 3; // only on players, entities, csqc
- float CH_SHOTS = 4; // only on players, entities, csqc
- float CH_SHOTS_SINGLE = 4; // only on players, entities, csqc
- float CH_WEAPON_B = 5; // only on players and entities
- float CH_PAIN = 6; // only on players and csqc
- float CH_PAIN_SINGLE = 6; // only on players and csqc
- float CH_PLAYER = 7; // only on players and entities
- float CH_TUBA = 5; // only on csqc
- #else
- float CH_INFO = 0;
- float CH_TRIGGER = -3;
- float CH_WEAPON_A = -1;
- float CH_WEAPON_SINGLE = 1;
- float CH_VOICE = -2;
- float CH_BGM_SINGLE = 8;
- float CH_AMBIENT = -9;
- float CH_TRIGGER_SINGLE = 3;
- float CH_SHOTS = -4;
- float CH_SHOTS_SINGLE = 4;
- float CH_WEAPON_B = -1;
- float CH_PAIN = -6;
- float CH_PAIN_SINGLE = 6;
- float CH_PLAYER = -7;
- float CH_TUBA = 5;
- #endif
- float ATTN_NONE                               = 0;
- float ATTN_MIN                                = 0.015625;
- float ATTN_NORM                               = 0.5;
- float ATTN_LARGE                              = 1;
- float ATTN_IDLE                               = 2;
- float ATTN_STATIC                             = 3;
- float ATTN_MAX                                = 3.984375;
+ const float CH_INFO = 0;
+ const float CH_TRIGGER = -3;
+ const float CH_WEAPON_A = -1;
+ const float CH_WEAPON_SINGLE = 1;
+ const float CH_VOICE = -2;
+ const float CH_BGM_SINGLE = 8;
+ const float CH_AMBIENT = -9;
+ const float CH_TRIGGER_SINGLE = 3;
+ const float CH_SHOTS = -4;
+ const float CH_SHOTS_SINGLE = 4;
+ const float CH_WEAPON_B = -1;
+ const float CH_PAIN = -6;
+ const float CH_PAIN_SINGLE = 6;
+ const float CH_PLAYER = -7;
+ const float CH_PLAYER_SINGLE = 7;
+ const float CH_TUBA_SINGLE = 5;
+ const float ATTEN_NONE = 0;
+ const float ATTEN_MIN = 0.015625;
+ const float ATTEN_NORM = 0.5;
+ const float ATTEN_LARGE = 1;
+ const float ATTEN_IDLE = 2;
+ const float ATTEN_STATIC = 3;
+ const float ATTEN_MAX = 3.984375;
  
  #define VOL_BASE 0.7
  #define VOL_BASEVOICE 1.0
  
- // this sets sounds and other properties of the projectiles in csqc
- float PROJECTILE_ELECTRO = 1;
- float PROJECTILE_ROCKET = 2;
- float PROJECTILE_TAG = 3;
- float PROJECTILE_BULLET = 4;
- float PROJECTILE_CRYLINK = 5;
- float PROJECTILE_ELECTRO_BEAM = 6;
- float PROJECTILE_GRENADE = 7;
- float PROJECTILE_GRENADE_BOUNCING = 8;
- float PROJECTILE_MINE = 9;
- float PROJECTILE_LASER = 10;
- float PROJECTILE_HLAC = 11;
- float PROJECTILE_SEEKER = 12;
- float PROJECTILE_FLAC = 13;
- float PROJECTILE_PORTO_RED = 14;
- float PROJECTILE_PORTO_BLUE = 15;
- float PROJECTILE_HOOKBOMB = 16;
- float PROJECTILE_HAGAR = 17;
- float PROJECTILE_HAGAR_BOUNCING = 18;
- float PROJECTILE_BULLET_GLOWING = 19;
- float PROJECTILE_CRYLINK_BOUNCING = 20;
- float PROJECTILE_FIREBALL = 21;
- float PROJECTILE_FIREMINE = 22;
- float PROJECTILE_BULLET_GLOWING_TRACER = 23;
- float PROJECTILE_RAPTORCANNON   = 24;
- float PROJECTILE_RAPTORBOMB     = 25;
- float PROJECTILE_RAPTORBOMBLET  = 26;
- float PROJECTILE_SPIDERROCKET   = 27;
- float PROJECTILE_WAKIROCKET     = 28;
- float PROJECTILE_WAKICANNON     = 29;
- float PROJECTILE_BUMBLE_GUN     = 30;
- float PROJECTILE_BUMBLE_BEAM    = 31;
- float SPECIES_HUMAN        =  0;
- float SPECIES_ROBOT_SOLID  =  1;
- float SPECIES_ALIEN        =  2;
- float SPECIES_ANIMAL       =  3;
- float SPECIES_ROBOT_RUSTY  =  4;
- float SPECIES_ROBOT_SHINY  =  5;
- float SPECIES_RESERVED     = 15;
+ // WEAPONTODO: move this into separate/new projectile handling code // this sets sounds and other properties of the projectiles in csqc
+ const float PROJECTILE_ELECTRO = 1;
+ const float PROJECTILE_ROCKET = 2;
+ const float PROJECTILE_TAG = 3;
+ const float PROJECTILE_CRYLINK = 5;
+ const float PROJECTILE_ELECTRO_BEAM = 6;
+ const float PROJECTILE_GRENADE = 7;
+ const float PROJECTILE_GRENADE_BOUNCING = 8;
+ const float PROJECTILE_MINE = 9;
+ const float PROJECTILE_BLASTER = 10;
+ const float PROJECTILE_HLAC = 11;
+ const float PROJECTILE_SEEKER = 12;
+ const float PROJECTILE_FLAC = 13;
+ const float PROJECTILE_PORTO_RED = 14;
+ const float PROJECTILE_PORTO_BLUE = 15;
+ const float PROJECTILE_HOOKBOMB = 16;
+ const float PROJECTILE_HAGAR = 17;
+ const float PROJECTILE_HAGAR_BOUNCING = 18;
+ const float PROJECTILE_CRYLINK_BOUNCING = 20;
+ const float PROJECTILE_FIREBALL = 21;
+ const float PROJECTILE_FIREMINE = 22;
+ const float PROJECTILE_RAPTORCANNON = 24;
+ const float PROJECTILE_RAPTORBOMB = 25;
+ const float PROJECTILE_RAPTORBOMBLET = 26;
+ const float PROJECTILE_SPIDERROCKET = 27;
+ const float PROJECTILE_WAKIROCKET = 28;
+ const float PROJECTILE_WAKICANNON = 29;
+ const float PROJECTILE_BUMBLE_GUN = 30;
+ const float PROJECTILE_BUMBLE_BEAM = 31;
+ const float PROJECTILE_MAGE_SPIKE = 32;
+ const float PROJECTILE_SHAMBLER_LIGHTNING = 33;
+ const float PROJECTILE_RPC = 60;
+ const float SPECIES_HUMAN = 0;
+ const float SPECIES_ROBOT_SOLID = 1;
+ const float SPECIES_ALIEN = 2;
+ const float SPECIES_ANIMAL = 3;
+ const float SPECIES_ROBOT_RUSTY = 4;
+ const float SPECIES_ROBOT_SHINY = 5;
+ const float SPECIES_RESERVED = 15;
  
  #define FRAGS_PLAYER 0
  #define FRAGS_SPECTATOR -666
  // we can use this frags value for both
  
  // water levels
- float WATERLEVEL_NONE = 0;
- float WATERLEVEL_WETFEET = 1;
- float WATERLEVEL_SWIMMING = 2;
- float WATERLEVEL_SUBMERGED = 3;
- float MAX_SHOT_DISTANCE = 32768;
- // weapon requests
- float WR_SETUP                = 1; // (SVQC) setup weapon data
- float WR_THINK                = 2; // (SVQC) logic to run every frame
- float WR_CHECKAMMO1   = 3; // (SVQC) checks ammo for weapon
- float WR_CHECKAMMO2   = 4; // (SVQC) checks ammo for weapon
- float WR_AIM          = 5; // (SVQC) runs bot aiming code for this weapon
- float WR_PRECACHE     = 6; // (CSQC and SVQC) precaches models/sounds used by this weapon
- float WR_SUICIDEMESSAGE = 7; // (SVQC) notification number for suicide message (may inspect w_deathtype for details)
- float WR_KILLMESSAGE    = 8; // (SVQC) notification number for kill message (may inspect w_deathtype for details)
- float WR_RELOAD         = 9; // (SVQC) does not need to do anything
- float WR_RESETPLAYER    = 10; // (SVQC) does not need to do anything
- float WR_IMPACTEFFECT = 11; // (CSQC) impact effect
- float WR_SWITCHABLE   = 12; // (CSQC) impact effect
- float WR_PLAYERDEATH    = 13; // (SVQC) does not need to do anything
- float WR_GONETHINK    = 14; // (SVQC) logic to run every frame, also if no longer having the weapon as long as the switch away has not been performed
- float HUD_PANEL_WEAPONS               = 0;
- float HUD_PANEL_AMMO          = 1;
- float HUD_PANEL_POWERUPS      = 2;
- float HUD_PANEL_HEALTHARMOR   = 3;
- float HUD_PANEL_NOTIFY                = 4;
- float HUD_PANEL_TIMER         = 5;
- float HUD_PANEL_RADAR         = 6;
- float HUD_PANEL_SCORE         = 7;
- float HUD_PANEL_RACETIMER     = 8;
- float HUD_PANEL_VOTE          = 9;
- float HUD_PANEL_MODICONS      = 10;
- float HUD_PANEL_PRESSEDKEYS   = 11;
- float HUD_PANEL_CHAT          = 12;
- float HUD_PANEL_ENGINEINFO    = 13;
- float HUD_PANEL_INFOMESSAGES  = 14;
- float HUD_PANEL_PHYSICS       = 15;
- float HUD_PANEL_CENTERPRINT   = 16;
- float HUD_PANEL_ITEMSTIME             = 17;
- float HUD_PANEL_NUM                           = 18; // always last panel id + 1, please increment when adding a new panel
- string HUD_PANELNAME_WEAPONS          = "weapons";
- string HUD_PANELNAME_AMMO             = "ammo";
- string HUD_PANELNAME_POWERUPS         = "powerups";
- string HUD_PANELNAME_HEALTHARMOR      = "healtharmor";
- string HUD_PANELNAME_NOTIFY           = "notify";
- string HUD_PANELNAME_TIMER            = "timer";
- string HUD_PANELNAME_RADAR            = "radar";
- string HUD_PANELNAME_SCORE            = "score";
- string HUD_PANELNAME_RACETIMER                = "racetimer";
- string HUD_PANELNAME_VOTE             = "vote";
- string HUD_PANELNAME_MODICONS         = "modicons";
- string HUD_PANELNAME_PRESSEDKEYS      = "pressedkeys";
- string HUD_PANELNAME_CHAT             = "chat";
- string HUD_PANELNAME_ENGINEINFO               = "engineinfo";
- string HUD_PANELNAME_INFOMESSAGES     = "infomessages";
- string HUD_PANELNAME_PHYSICS  = "physics";
- string HUD_PANELNAME_CENTERPRINT      = "centerprint";
- string HUD_PANELNAME_ITEMSTIME                = "itemstime";
+ const float WATERLEVEL_NONE = 0;
+ const float WATERLEVEL_WETFEET = 1;
+ const float WATERLEVEL_SWIMMING = 2;
+ const float WATERLEVEL_SUBMERGED = 3;
 +
  #define SERVERFLAG_ALLOW_FULLBRIGHT 1
  #define SERVERFLAG_TEAMPLAY 2
  #define SERVERFLAG_PLAYERSTATS 4
@@@ -474,17 -326,22 +328,22 @@@ noref var vector autocvar_sv_player_hea
  #define PL_HEAD_z autocvar_sv_player_headsize_z
  
  // spawnpoint prios
- #define SPAWN_PRIO_NEAR_TEAMMATE_FOUND    200
+ #define SPAWN_PRIO_NEAR_TEAMMATE_FOUND 200
  #define SPAWN_PRIO_NEAR_TEAMMATE_SAMETEAM 100
- #define SPAWN_PRIO_RACE_PREVIOUS_SPAWN     50
- #define SPAWN_PRIO_GOOD_DISTANCE           10
+ #define SPAWN_PRIO_RACE_PREVIOUS_SPAWN 50
+ #define SPAWN_PRIO_GOOD_DISTANCE 10
  
  // URI handles
- #define URI_GET_DISCARD              0
- #define URI_GET_IPBAN                1
- #define URI_GET_IPBAN_END           16
- #define URI_GET_CURL                17
- #define URI_GET_CURL_END            32
- #define URI_GET_UPDATENOTIFICATION  33
- #define URI_GET_URLLIB             128
- #define URI_GET_URLLIB_END         191
+ #define URI_GET_DISCARD 0
+ #define URI_GET_IPBAN 1
+ #define URI_GET_IPBAN_END 16
+ #define URI_GET_CURL 17
+ #define URI_GET_CURL_END 32
+ #define URI_GET_UPDATENOTIFICATION 33
+ #define URI_GET_URLLIB 128
+ #define URI_GET_URLLIB_END 191
+ // gametype votes
+ #define GTV_AVAILABLE 0
+ // for later use in per-map gametype filtering
+ #define GTV_FORBIDDEN 2
diff --combined qcsrc/common/stats.qh
index 0000000000000000000000000000000000000000,f0570299794f72d698269b62ac7133a0951258a5..bd34f6f88c0d6cb8a3a032f9b361bb5dc39b485a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,290 +1,290 @@@
 -// 90 empty?
 -// 91 empty?
 -// 92 empty?
 -// 93 empty?
 -// 94 empty?
 -// 95 empty?
 -// 96 empty?
 -// 97 empty?
 -// 98 empty?
 -// 99 empty?
+ // Full list of all stat constants, icnluded in a single location for easy reference
+ // 255 is the current limit (MAX_CL_STATS - 1), engine will need to be modified if you wish to add more stats
+ const float MAX_CL_STATS                = 256;
+ const float STAT_HEALTH                 = 0;
+ // 1 empty?
+ const float STAT_WEAPON                 = 2;
+ const float STAT_AMMO                   = 3;
+ const float STAT_ARMOR                  = 4;
+ const float STAT_WEAPONFRAME            = 5;
+ const float STAT_SHELLS                 = 6;
+ const float STAT_NAILS                  = 7;
+ const float STAT_ROCKETS                = 8;
+ const float STAT_CELLS                  = 9;
+ const float STAT_ACTIVEWEAPON           = 10;
+ const float STAT_TOTALSECRETS           = 11;
+ const float STAT_TOTALMONSTERS          = 12;
+ const float STAT_SECRETS                = 13;
+ const float STAT_MONSTERS               = 14;
+ const float STAT_ITEMS                  = 15;
+ const float STAT_VIEWHEIGHT             = 16;
+ // 17 empty?
+ // 18 empty?
+ // 19 empty?
+ // 20 empty?
+ const float STAT_VIEWZOOM               = 21;
+ // 22 empty?
+ // 23 empty?
+ // 24 empty?
+ // 25 empty?
+ // 26 empty?
+ // 27 empty?
+ // 28 empty?
+ // 29 empty?
+ // 30 empty?
+ // 31 empty?
+ const float STAT_KH_KEYS                = 32;
+ const float STAT_CTF_STATE              = 33;
+ // 34 empty?
+ const float STAT_WEAPONS                = 35;
+ const float STAT_SWITCHWEAPON           = 36;
+ const float STAT_GAMESTARTTIME          = 37;
+ const float STAT_STRENGTH_FINISHED      = 38;
+ const float STAT_INVINCIBLE_FINISHED    = 39;
+ // 40 empty?
+ const float STAT_ARC_HEAT               = 41;
+ const float STAT_PRESSED_KEYS           = 42;
+ const float STAT_ALLOW_OLDVORTEXBEAM    = 43; // this stat could later contain some other bits of info, like, more server-side particle config
+ const float STAT_FUEL                   = 44;
+ const float STAT_NB_METERSTART          = 45;
+ const float STAT_SHOTORG                = 46; // compressShotOrigin
+ const float STAT_LEADLIMIT              = 47;
+ const float STAT_WEAPON_CLIPLOAD        = 48;
+ const float STAT_WEAPON_CLIPSIZE        = 49;
+ const float STAT_VORTEX_CHARGE          = 50;
+ const float STAT_LAST_PICKUP            = 51;
+ const float STAT_HUD                    = 52;
+ const float STAT_VORTEX_CHARGEPOOL      = 53;
+ const float STAT_HIT_TIME               = 54;
+ const float STAT_DAMAGE_DEALT_TOTAL     = 55;
+ const float STAT_TYPEHIT_TIME           = 56;
+ const float STAT_LAYED_MINES            = 57;
+ const float STAT_HAGAR_LOAD             = 58;
+ const float STAT_SWITCHINGWEAPON        = 59;
+ const float STAT_SUPERWEAPONS_FINISHED  = 60;
+ const float STAT_VEHICLESTAT_HEALTH     = 61;
+ const float STAT_VEHICLESTAT_SHIELD     = 62;
+ const float STAT_VEHICLESTAT_ENERGY     = 63;
+ const float STAT_VEHICLESTAT_AMMO1      = 64;
+ const float STAT_VEHICLESTAT_RELOAD1    = 65;
+ const float STAT_VEHICLESTAT_AMMO2      = 66;
+ const float STAT_VEHICLESTAT_RELOAD2    = 67;
+ const float STAT_VEHICLESTAT_W2MODE     = 68;
+ const float STAT_NADE_TIMER             = 69;
+ const float STAT_SECRETS_TOTAL          = 70;
+ const float STAT_SECRETS_FOUND          = 71;
+ const float STAT_RESPAWN_TIME           = 72;
+ const float STAT_ROUNDSTARTTIME         = 73;
+ const float STAT_WEAPONS2               = 74;
+ const float STAT_WEAPONS3               = 75;
+ const float STAT_MONSTERS_TOTAL         = 76;
+ const float STAT_MONSTERS_KILLED        = 77;
+ const float STAT_BUFFS                  = 78;
+ const float STAT_NADE_BONUS             = 79;
+ const float STAT_NADE_BONUS_TYPE        = 80;
+ const float STAT_NADE_BONUS_SCORE       = 81;
+ const float STAT_HEALING_ORB            = 82;
+ const float STAT_HEALING_ORB_ALPHA      = 83;
+ const float STAT_PLASMA                 = 84;
+ const float STAT_OK_AMMO_CHARGE         = 85;
+ const float STAT_OK_AMMO_CHARGEPOOl     = 86;
+ // 87 empty?
+ // 88 empty?
+ // 89 empty?
++const float STAT_ARMOR_LARGE_TIME       = 90;
++const float STAT_HEALTH_MEGA_TIME       = 91;
++const float STAT_INVISIBLE_TIME         = 92;
++const float STAT_SPEED_TIME             = 93;
++const float STAT_EXTRALIFE_TIME         = 94;
++const float STAT_STRENGTH_TIME          = 95;
++const float STAT_SHIELD_TIME            = 96;
++const float STAT_FUELREGEN_TIME         = 97;
++const float STAT_JETPACK_TIME           = 98;
++const float STAT_SUPERWEAPONS_TIME      = 99;
+ /* The following stats change depending on the gamemode, so can share the same ID */
+ // IDs 100 to 104 reserved for gamemodes
+ // freeze tag, clan arena, jailbreak
+ const float STAT_REDALIVE               = 100;
+ const float STAT_BLUEALIVE              = 101;
+ const float STAT_YELLOWALIVE            = 102;
+ const float STAT_PINKALIVE              = 103;
+ // domination
+ const float STAT_DOM_TOTAL_PPS          = 100;
+ const float STAT_DOM_PPS_RED            = 101;
+ const float STAT_DOM_PPS_BLUE           = 102;
+ const float STAT_DOM_PPS_YELLOW         = 103;
+ const float STAT_DOM_PPS_PINK           = 104;
+ // vip
+ const float STAT_VIP                    = 100;
+ const float STAT_VIP_RED                = 101;
+ const float STAT_VIP_BLUE               = 102;
+ const float STAT_VIP_YELLOW             = 103;
+ const float STAT_VIP_PINK               = 104;
+ // key hunt
+ const float STAT_KH_REDKEY_TEAM         = 100;
+ const float STAT_KH_BLUEKEY_TEAM        = 101;
+ const float STAT_KH_YELLOWKEY_TEAM      = 102;
+ const float STAT_KH_PINKKEY_TEAM        = 103;
+ /* Gamemode-specific stats end here */
+ const float STAT_FROZEN                 = 105;
+ const float STAT_REVIVE_PROGRESS        = 106;
+ // 107 empty?
+ // 108 empty?
+ // 109 empty?
+ // 110 empty?
+ // 111 empty?
+ // 112 empty?
+ // 113 empty?
+ // 114 empty?
+ // 115 empty?
+ // 116 empty?
+ // 117 empty?
+ // 118 empty?
+ // 119 empty?
+ // 120 empty?
+ // 121 empty?
+ // 122 empty?
+ // 123 empty?
+ // 124 empty?
+ // 125 empty?
+ // 126 empty?
+ // 127 empty?
+ // 128 empty?
+ // 129 empty?
+ // 130 empty?
+ // 131 empty?
+ // 132 empty?
+ // 133 empty?
+ // 134 empty?
+ // 135 empty?
+ // 136 empty?
+ // 137 empty?
+ // 138 empty?
+ // 139 empty?
+ // 140 empty?
+ // 141 empty?
+ // 142 empty?
+ // 143 empty?
+ // 144 empty?
+ // 145 empty?
+ // 146 empty?
+ // 147 empty?
+ // 148 empty?
+ // 149 empty?
+ // 150 empty?
+ // 151 empty?
+ // 152 empty?
+ // 153 empty?
+ // 154 empty?
+ // 155 empty?
+ // 156 empty?
+ // 157 empty?
+ // 158 empty?
+ // 159 empty?
+ // 160 empty?
+ // 161 empty?
+ // 162 empty?
+ // 162 empty?
+ // 163 empty?
+ // 164 empty?
+ // 165 empty?
+ // 166 empty?
+ // 167 empty?
+ // 168 empty?
+ // 169 empty?
+ // 170 empty?
+ // 171 empty?
+ // 172 empty?
+ // 173 empty?
+ // 174 empty?
+ // 175 empty?
+ // 176 empty?
+ // 177 empty?
+ // 178 empty?
+ // 179 empty?
+ // 180 empty?
+ // 181 empty?
+ // 182 empty?
+ // 183 empty?
+ // 184 empty?
+ // 185 empty?
+ // 186 empty?
+ // 187 empty?
+ // 188 empty?
+ // 189 empty?
+ // 190 empty?
+ // 191 empty?
+ // 192 empty?
+ // 193 empty?
+ // 194 empty?
+ // 195 empty?
+ // 196 empty?
+ // 197 empty?
+ // 198 empty?
+ // 199 empty?
+ // 200 empty?
+ // 201 empty?
+ // 202 empty?
+ // 203 empty?
+ // 204 empty?
+ // 205 empty?
+ // 206 empty?
+ // 207 empty?
+ // 208 empty?
+ // 209 empty?
+ // 210 empty?
+ // 211 empty?
+ // 212 empty?
+ // 213 empty?
+ // 214 empty?
+ // 215 empty?
+ // 216 empty?
+ // 217 empty?
+ // 218 empty?
+ // 219 empty?
+ const float STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR     = 220;
+ const float STAT_MOVEVARS_AIRCONTROL_PENALTY            = 221;
+ const float STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW           = 222;
+ const float STAT_MOVEVARS_AIRSTRAFEACCEL_QW             = 223;
+ const float STAT_MOVEVARS_AIRCONTROL_POWER              = 224;
+ const float STAT_MOVEFLAGS                              = 225;
+ const float STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL   = 226;
+ const float STAT_MOVEVARS_WARSOWBUNNY_ACCEL             = 227;
+ const float STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED          = 228;
+ const float STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL         = 229;
+ const float STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO   = 230;
+ const float STAT_MOVEVARS_AIRSTOPACCELERATE             = 231;
+ const float STAT_MOVEVARS_AIRSTRAFEACCELERATE           = 232;
+ const float STAT_MOVEVARS_MAXAIRSTRAFESPEED             = 233;
+ const float STAT_MOVEVARS_AIRCONTROL                    = 234;
+ const float STAT_FRAGLIMIT                              = 235;
+ const float STAT_TIMELIMIT                              = 236;
+ const float STAT_MOVEVARS_WALLFRICTION                  = 237;
+ const float STAT_MOVEVARS_FRICTION                      = 238;
+ const float STAT_MOVEVARS_WATERFRICTION                 = 239;
+ const float STAT_MOVEVARS_TICRATE                       = 240;
+ const float STAT_MOVEVARS_TIMESCALE                     = 241;
+ const float STAT_MOVEVARS_GRAVITY                       = 242;
+ const float STAT_MOVEVARS_STOPSPEED                     = 243;
+ const float STAT_MOVEVARS_MAXSPEED                      = 244;
+ const float STAT_MOVEVARS_SPECTATORMAXSPEED             = 245;
+ const float STAT_MOVEVARS_ACCELERATE                    = 246;
+ const float STAT_MOVEVARS_AIRACCELERATE                 = 247;
+ const float STAT_MOVEVARS_WATERACCELERATE               = 248;
+ const float STAT_MOVEVARS_ENTGRAVITY                    = 249;
+ const float STAT_MOVEVARS_JUMPVELOCITY                  = 250;
+ const float STAT_MOVEVARS_EDGEFRICTION                  = 251;
+ const float STAT_MOVEVARS_MAXAIRSPEED                   = 252;
+ const float STAT_MOVEVARS_STEPHEIGHT                    = 253;
+ const float STAT_MOVEVARS_AIRACCEL_QW                   = 254;
+ const float STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION    = 255;
diff --combined qcsrc/common/util.qh
index dab177b358277e0862f3b6227cd19ce72c07c5e5,65b4e67a427b5eca7ba99208d874cec288d466be..87cdd99dfd22a45ac4264dab0e58e0c408275165
@@@ -1,6 -1,16 +1,16 @@@
+ // commonly used, but better make them macros
+ #define TRUE 1
+ #define FALSE 0
  // a dummy macro that prevents the "hanging ;" warning
  #define ENDS_WITH_CURLY_BRACE
  
+ #ifdef GMQCC
+ # define ACCUMULATE_FUNCTION(func,otherfunc) \
+       [[accumulate]] void func() { otherfunc(); }
+ # define CALL_ACCUMULATED_FUNCTION(func) \
+       func()
+ #else
  #ifdef HAVE_YO_DAWG_CPP
  // TODO make ascii art pic of xzibit
  // YO DAWG!
@@@ -19,7 -29,7 +29,7 @@@
        func()
  #else
  # define ACCUMULATE_FUNCTION(func,otherfunc) \
-       .void _ACCUMULATE_##func##__##otherfunc;
+       .float _ACCUMULATE_##func##__##otherfunc
  void ACCUMULATE_call(string func)
  {
        float i;
  # define CALL_ACCUMULATED_FUNCTION(func) \
        ACCUMULATE_call(#func)
  #endif
+ #endif
  
  // used for simplifying ACCUMULATE_FUNCTIONs
  #define SET_FIRST_OR_LAST(input,first,count) if(!input) { input = (first + count); }
  #define SET_FIELD_COUNT(field,first,count) if(!field) { field = (first + count); ++count; }
- #define CHECK_MAX_COUNT(name,max,count,type) if(count == max) { error(strcat("Maximum ", type, " hit: ", #name, ": ", ftos(count), ".\n")); }
+ #define CHECK_MAX_COUNT(name,max,count,type) if(count > max) { error(strcat("Maximum ", type, " hit: ", #name, ": ", ftos(count), ".\n")); }
  
  // this returns a tempstring containing a copy of s with additional \n newlines added, it also replaces \n in the text with a real newline
  // NOTE: s IS allowed to be a tempstring
@@@ -87,12 -98,8 +98,8 @@@ void db_put(float db, string key, strin
  float buf_load(string filename);
  void buf_save(float buf, string filename);
  
- // modulo function
- #ifndef MENUQC
- float mod(float a, float b) { return a - (floor(a / b) * b); }   
- #endif
  #define TIME_TO_NTHS(t,n) floor((t) * (n) + 0.4)
+ string format_time(float seconds);
  string mmsss(float t);
  string mmssss(float t);
  
@@@ -151,7 -158,7 +158,7 @@@ float almost_in_bounds(float a, float b
  float power2of(float e);
  float log2of(float x);
  
- string HEXDIGITS = "0123456789ABCDEF0123456789abcdef";
const string HEXDIGITS = "0123456789ABCDEF0123456789abcdef";
  #define HEXDIGIT_TO_DEC_RAW(d) (strstrofs(HEXDIGITS, (d), 0))
  #define HEXDIGIT_TO_DEC(d) ((HEXDIGIT_TO_DEC_RAW(d) | 0x10) - 0x10)
  #define DEC_TO_HEXDIGIT(d) (substring(HEXDIGITS, (d), 1))
@@@ -197,13 -204,11 +204,11 @@@ vector solve_quadratic(float a, float b
  vector solve_shotdirection(vector myorg, vector myvel, vector eorg, vector evel, float spd, float newton_style);
  vector get_shotvelocity(vector myvel, vector mydir, float spd, float newton_style, float mi, float ma);
  
- void check_unacceptable_compiler_bugs();
  float compressShotOrigin(vector v);
  vector decompressShotOrigin(float f);
  
  #ifdef SVQC
- string rankings_reply, ladder_reply, lsmaps_reply, lsnewmaps_reply, maplist_reply; // cached replies
+ string rankings_reply, ladder_reply, lsmaps_reply, maplist_reply, monsterlist_reply; // cached replies
  string records_reply[10];
  #endif
  
@@@ -215,16 -220,22 +220,22 @@@ string RandomSelection_chosen_string
  void RandomSelection_Init();
  void RandomSelection_Add(entity e, float f, string s, float weight, float priority);
  
- vector healtharmor_maxdamage(float h, float a, float armorblock); // returns vector: maxdamage, armorideal, 1 if fully armored
- vector healtharmor_applydamage(float a, float armorblock, float damage); // returns vector: take, save, 0
+ #ifndef MENUQC
+ vector healtharmor_maxdamage(float h, float a, float armorblock, float deathtype); // returns vector: maxdamage, armorideal, 1 if fully armored
+ vector healtharmor_applydamage(float a, float armorblock, float deathtype, float damage); // returns vector: take, save, 0
+ #endif
  
  string getcurrentmod();
  
  #ifndef MENUQC
  #ifdef CSQC
  float ReadInt24_t();
+ vector ReadInt48_t();
+ vector ReadInt72_t();
  #else
  void WriteInt24_t(float dest, float val);
+ void WriteInt48_t(float dest, vector val);
+ void WriteInt72_t(float dest, vector val);
  #endif
  #endif
  
@@@ -255,6 -266,7 +266,7 @@@ float get_model_parameters_species
  string get_model_parameters_sex;
  float get_model_parameters_weight;
  float get_model_parameters_age;
+ string get_model_parameters_description;
  string get_model_parameters_bone_upperbody;
  string get_model_parameters_bone_weapon;
  #define MAX_AIM_BONES 4
@@@ -264,35 -276,6 +276,6 @@@ float get_model_parameters_fixbone
  string get_model_parameters_desc;
  float get_model_parameters(string mod, float skn); // call with string_null to clear; skin -1 means mod is the filename of the txt file and is to be split
  
- // stupid stupid stupid FTEQCC has a max limit on macro sizes, let's work around by splitting the macro into two macros! :(
- #define HUD_Panel_GetName_Part2(id) \
- switch(id) {\
-       case HUD_PANEL_ENGINEINFO: panel_name = HUD_PANELNAME_ENGINEINFO; break; \
-       case HUD_PANEL_INFOMESSAGES: panel_name = HUD_PANELNAME_INFOMESSAGES; break; \
-       case HUD_PANEL_PHYSICS: panel_name = HUD_PANELNAME_PHYSICS; break; \
-       case HUD_PANEL_CENTERPRINT: panel_name = HUD_PANELNAME_CENTERPRINT; break; \
-       case HUD_PANEL_ITEMSTIME: panel_name = HUD_PANELNAME_ITEMSTIME; break; \
- } ENDS_WITH_CURLY_BRACE
- // Get name of specified panel id
- #define HUD_Panel_GetName(id) \
- switch(id) { \
-       case HUD_PANEL_WEAPONS: panel_name = HUD_PANELNAME_WEAPONS; break; \
-       case HUD_PANEL_AMMO: panel_name = HUD_PANELNAME_AMMO; break; \
-       case HUD_PANEL_POWERUPS: panel_name = HUD_PANELNAME_POWERUPS; break; \
-       case HUD_PANEL_HEALTHARMOR: panel_name = HUD_PANELNAME_HEALTHARMOR; break; \
-       case HUD_PANEL_NOTIFY: panel_name = HUD_PANELNAME_NOTIFY; break; \
-       case HUD_PANEL_TIMER: panel_name = HUD_PANELNAME_TIMER; break; \
-       case HUD_PANEL_RADAR: panel_name = HUD_PANELNAME_RADAR; break; \
-       case HUD_PANEL_SCORE: panel_name = HUD_PANELNAME_SCORE; break; \
-       case HUD_PANEL_RACETIMER: panel_name = HUD_PANELNAME_RACETIMER; break; \
-       case HUD_PANEL_VOTE: panel_name = HUD_PANELNAME_VOTE; break; \
-       case HUD_PANEL_MODICONS: panel_name = HUD_PANELNAME_MODICONS; break; \
-       case HUD_PANEL_PRESSEDKEYS: panel_name = HUD_PANELNAME_PRESSEDKEYS; break; \
-       case HUD_PANEL_CHAT: panel_name = HUD_PANELNAME_CHAT; break; \
-     default: HUD_Panel_GetName_Part2(id)\
- }
  vector vec2(vector v);
  
  #ifndef MENUQC
@@@ -316,9 -299,9 +299,9 @@@ const float XENCODE_LEN = 5
  string xencode(float f);
  float xdecode(string s);
  
- #ifndef COMPAT_XON010_CHANNELS
+ // Play all sounds via sound7, for access to the extra channels.
+ // Otherwise, channels 8 to 15 would be blocked for a weird QW feature.
  #define sound(e,c,s,v,a) sound7(e,c,s,v,a,0,0)
- #endif
  
  float lowestbit(float f);
  
@@@ -375,12 -358,23 +358,23 @@@ typedef entity(entity cur, entity near
  typedef float(entity a, entity b, entity pass) isConnectedFunction_t;
  void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t nxt, isConnectedFunction_t iscon, entity pass);
  
+ #ifdef SVQC
+ vector combine_to_vector(float x, float y, float z);
+ vector get_corner_position(entity box, float corner);
+ #endif
  // expand multiple arguments into one argument by stripping parenthesis
  #define XPD(...) __VA_ARGS__
  
- #ifndef MENUQC
+ // Some common varargs functions. Lowercase as they match C.
+ #define printf(...) print(sprintf(__VA_ARGS__))
+ #define dprintf(...) dprint(sprintf(__VA_ARGS__))
+ #define fprintf(file, ...) fputs(file, sprintf(__VA_ARGS__))
+ #define bprintf(...) bprint(sprintf(__VA_ARGS__))
+ //#ifndef MENUQC
  void backtrace(string msg);
- #endif
//#endif
  
  // color code replace, place inside of sprintf and parse the string... defaults described as constants
  // foreground/normal colors
@@@ -431,3 -425,27 +425,27 @@@ void dedicated_print(string input)
  #define PROGNAME "CSQC"
  #endif
  #endif
 -#define COMPARE_INCREASING(to,from) (to < from ? from + to + 2 : to - from)
+ #ifndef MENUQC
+ #define CNT_NORMAL 1
+ #define CNT_GAMESTART 2
+ #define CNT_IDLE 3
+ #define CNT_KILL 4
+ #define CNT_RESPAWN 5
+ #define CNT_ROUNDSTART 6
+ float Announcer_PickNumber(float type, float num);
+ #endif
+ #ifndef MENUQC
+ float Mod_Q1BSP_SuperContentsFromNativeContents(float nativecontents);
+ float Mod_Q1BSP_NativeContentsFromSuperContents(float supercontents);
+ #endif
+ // Quadratic splines (bezier)
+ vector bezier_quadratic_getpoint(vector a, vector p, vector b, float t);
+ vector bezier_quadratic_getderivative(vector a, vector p, vector b, float t);
+ #define APPEND_TO_STRING(list,sep,add) ((list) = (((list) != "") ? strcat(list, sep, add) : (add)))
+ // Returns the correct difference between two always increasing numbers
++#define COMPARE_INCREASING(to,from) (to < from ? from + to + 2 : to - from)
diff --combined qcsrc/menu/classes.c
index 93ae4a838da7d0936d8e72535378cb913dd9e7c7,9f01ee3fbf08dc8c8a633916923eea028f0d14d1..f4cc9c7c948146aee6a92aba293e2bcf9a49712f
  #include "xonotic/bigbutton.c"
  #include "xonotic/commandbutton.c"
  #include "xonotic/bigcommandbutton.c"
+ #include "xonotic/textlabel.c"
  #include "xonotic/dialog_firstrun.c"
  #include "xonotic/dialog_teamselect.c"
  #include "xonotic/dialog_sandboxtools.c"
+ #include "xonotic/dialog_monstertools.c"
  #include "xonotic/dialog_settings.c"
  #include "xonotic/dialog_settings_video.c"
  #include "xonotic/dialog_settings_effects.c"
  #include "xonotic/dialog_settings_audio.c"
+ #include "xonotic/dialog_settings_game.c"
  #include "xonotic/dialog_settings_user.c"
+ #include "xonotic/dialog_settings_user_languagewarning.c"
  #include "xonotic/dialog_settings_misc.c"
  #include "xonotic/dialog_multiplayer.c"
- #include "xonotic/dialog_multiplayer_playersetup.c"
+ #include "xonotic/dialog_multiplayer_profile.c"
  #include "xonotic/tabcontroller.c"
- #include "xonotic/textlabel.c"
  #include "xonotic/slider.c"
  #include "xonotic/slider_resolution.c"
  #include "xonotic/checkbox.c"
  #include "xonotic/checkbox_string.c"
+ #include "xonotic/weaponarenacheckbox.c"
  #include "xonotic/radiobutton.c"
  #include "xonotic/nexposee.c"
  #include "xonotic/rootdialog.c"
@@@ -57,7 -61,6 +61,6 @@@
  #include "xonotic/dialog_quit.c"
  #include "xonotic/dialog_multiplayer_create.c"
  #include "xonotic/dialog_multiplayer_create_mutators.c"
- #include "xonotic/dialog_multiplayer_create_advanced.c"
  #include "xonotic/dialog_multiplayer_create_mapinfo.c"
  #include "xonotic/gametypelist.c"
  #include "xonotic/maplist.c"
  #include "xonotic/dialog_singleplayer_winner.c"
  #include "xonotic/dialog_credits.c"
  #include "xonotic/credits.c"
- #include "xonotic/dialog_multiplayer_playersetup_crosshair.c"
- #include "xonotic/dialog_multiplayer_playersetup_hud.c"
- #include "xonotic/dialog_multiplayer_playersetup_hudconfirm.c"
- #include "xonotic/dialog_multiplayer_playersetup_model.c"
- #include "xonotic/dialog_multiplayer_playersetup_view.c"
- #include "xonotic/dialog_multiplayer_playersetup_weapons.c"
+ #include "xonotic/dialog_settings_game_crosshair.c"
+ #include "xonotic/dialog_settings_game_hud.c"
+ #include "xonotic/dialog_settings_game_hudconfirm.c"
+ #include "xonotic/dialog_settings_game_model.c"
+ #include "xonotic/dialog_settings_game_messages.c"
+ #include "xonotic/dialog_settings_game_view.c"
+ #include "xonotic/dialog_settings_game_weapons.c"
  #include "xonotic/weaponslist.c"
- #include "xonotic/dialog_multiplayer_demo.c"
+ #include "xonotic/dialog_multiplayer_media.c"
+ #include "xonotic/dialog_multiplayer_media_demo.c"
+ #include "xonotic/dialog_multiplayer_media_demo_startconfirm.c"
+ #include "xonotic/dialog_multiplayer_media_demo_timeconfirm.c"
  #include "xonotic/demolist.c"
+ #include "xonotic/screenshotimage.c"
+ #include "xonotic/dialog_multiplayer_media_screenshot.c"
+ #include "xonotic/dialog_multiplayer_media_screenshot_viewer.c"
+ #include "xonotic/screenshotlist.c"
+ #include "xonotic/statslist.c"
+ #include "xonotic/dialog_multiplayer_media_musicplayer.c"
+ #include "xonotic/soundlist.c"
+ #include "xonotic/playlist.c"
  #include "xonotic/colorpicker.c"
  #include "xonotic/colorpicker_string.c"
  #include "xonotic/cvarlist.c"
  #include "xonotic/dialog_hudpanel_weapons.c"
  #include "xonotic/dialog_hudpanel_physics.c"
  #include "xonotic/dialog_hudpanel_centerprint.c"
+ #include "xonotic/dialog_hudpanel_buffs.c"
 +#include "xonotic/dialog_hudpanel_itemstime.c"
  #include "xonotic/slider_picmip.c"
+ #include "xonotic/slider_particles.c"
+ #include "xonotic/slider_sbfadetime.c"
+ #include "xonotic/dialog_settings_misc_reset.c"
index 54ed66ada1c30d6fa87d8e364e03e18574bb4b3c,6fa40bfac69cf687997ec45952d7b10eb7825d12..5174fe09d43b92ff80d7422d088ba0afd47a6040
@@@ -5,20 -5,21 +5,21 @@@ CLASS(MainWindow) EXTENDS(ModalControll
        ATTRIB(MainWindow, firstRunDialog, entity, NULL)
        ATTRIB(MainWindow, advancedDialog, entity, NULL)
        ATTRIB(MainWindow, mutatorsDialog, entity, NULL)
-       ATTRIB(MainWindow, weaponsDialog, entity, NULL)
        ATTRIB(MainWindow, mapInfoDialog, entity, NULL)
        ATTRIB(MainWindow, userbindEditDialog, entity, NULL)
        ATTRIB(MainWindow, winnerDialog, entity, NULL)
        ATTRIB(MainWindow, serverInfoDialog, entity, NULL)
        ATTRIB(MainWindow, cvarsDialog, entity, NULL)
+       ATTRIB(MainWindow, screenshotViewerDialog, entity, NULL)
        ATTRIB(MainWindow, viewDialog, entity, NULL)
-       ATTRIB(MainWindow, modelDialog, entity, NULL)
-       ATTRIB(MainWindow, crosshairDialog, entity, NULL)
-       ATTRIB(MainWindow, hudDialog, entity, NULL)
        ATTRIB(MainWindow, hudconfirmDialog, entity, NULL)
+       ATTRIB(MainWindow, languageWarningDialog, entity, NULL)
        ATTRIB(MainWindow, mainNexposee, entity, NULL)
        ATTRIB(MainWindow, fadedAlpha, float, SKINALPHA_BEHIND)
        ATTRIB(MainWindow, dialogToShow, entity, NULL)
+       ATTRIB(MainWindow, demostartconfirmDialog, entity, NULL)
+       ATTRIB(MainWindow, demotimeconfirmDialog, entity, NULL)
+       ATTRIB(MainWindow, resetDialog, entity, NULL)
  ENDCLASS(MainWindow)
  #endif
  
@@@ -50,61 -51,61 +51,61 @@@ void MainWindow_configureMainWindow(ent
        me.firstRunDialog = i = spawnXonoticFirstRunDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
-       
        // hud_configure dialogs
        i = spawnXonoticHUDExitDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDNotificationDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDAmmoDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDHealthArmorDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDChatDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDModIconsDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDPowerupsDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDPressedKeysDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDRaceTimerDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDRadarDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDScoreDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDTimerDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDVoteDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        i = spawnXonoticHUDWeaponsDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
        i = spawnXonoticHUDInfoMessagesDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+       
        i = spawnXonoticHUDPhysicsDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+       
+       me.screenshotViewerDialog = i = spawnXonoticScreenshotViewerDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
  
        i = spawnXonoticHUDCenterprintDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
  
-       
-       
+       i = spawnXonoticHUDBuffsDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
 +      i = spawnXonoticHUDItemsTimeDialog();
 +      i.configureDialog(i);
 +      me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
++
        // dialogs used by settings
        me.userbindEditDialog = i = spawnXonoticUserbindEditDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
        me.cvarsDialog = i = spawnXonoticCvarsDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
        
-       
-       // dialog used by singleplayer
-       me.winnerDialog = i = spawnXonoticWinnerDialog();
+       me.resetDialog = i = spawnXonoticResetDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
-       
-       // dialog used by multiplayer/join
-       me.serverInfoDialog = i = spawnXonoticServerInfoDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
-       
-       // dialogs used by multiplayer/create
-       me.mapInfoDialog = i = spawnXonoticMapInfoDialog();
+       me.languageWarningDialog = i = spawnXonoticLanguageWarningDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
-       me.advancedDialog = i = spawnXonoticAdvancedDialog();
+       me.hudconfirmDialog = i = spawnXonoticHUDConfirmDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
  
-       me.mutatorsDialog = i = spawnXonoticMutatorsDialog();
+       // dialog used by singleplayer
+       me.winnerDialog = i = spawnXonoticWinnerDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
  
-       // dialogs used by multiplayer/player setup
-       me.crosshairDialog = i = spawnXonoticCrosshairDialog();
+       // dialog used by multiplayer/join
+       me.serverInfoDialog = i = spawnXonoticServerInfoDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
        
-       me.hudDialog = i = spawnXonoticHUDDialog();
+       me.demostartconfirmDialog = i = spawnXonoticDemoStartConfirmDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
  
-       me.hudconfirmDialog = i = spawnXonoticHUDConfirmDialog();
+       me.demotimeconfirmDialog = i = spawnXonoticDemoTimeConfirmDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
-       me.modelDialog = i = spawnXonoticModelDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
-       me.viewDialog = i = spawnXonoticViewDialog();
+       // dialogs used by multiplayer/create
+       me.mapInfoDialog = i = spawnXonoticMapInfoDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
-       me.weaponsDialog = i = spawnXonoticWeaponsDialog();
+       me.mutatorsDialog = i = spawnXonoticMutatorsDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
  
        // mutator dialogs
        i = spawnXonoticSandboxToolsDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS);
-       
-       
        // miscellaneous dialogs
        i = spawnXonoticTeamSelectDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
-       
+       i = spawnXonoticMonsterToolsDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS);
        // main dialogs/windows
        me.mainNexposee = n = spawnXonoticNexposee();
        /*
                i.configureDialog(i);
                n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
                n.setNexposee(n, i, SKINPOSITION_DIALOG_SINGLEPLAYER, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
-               
                i = spawnXonoticMultiplayerDialog();
                i.configureDialog(i);
                n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
                n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
                n.setNexposee(n, i, SKINPOSITION_DIALOG_QUIT, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
                n.pullNexposee(n, i, eY * (SKINHEIGHT_TITLE * SKINFONTSIZE_TITLE / conheight));
-               
        me.addItem(me, n, '0 0 0', '1 1 0', SKINALPHAS_MAINMENU_z);
        me.moveItemAfter(me, n, NULL);
  
        me.initializeDialog(me, n);
  
-       if(cvar_string("_cl_name") == "Player")
+       if(cvar_string("_cl_name") == cvar_defstring("_cl_name"))
                me.dialogToShow = me.firstRunDialog;
  }
  #endif
index 9891e1afdbc42b9e89ce33d5dc3ff02239e1a689,03ab777b941c151ce93fe5cccc92e87cd1d9248e..83ba6d94a28b50b009f0a1189e7d674bf5b91df4
@@@ -1,27 -1,8 +1,8 @@@
- void race_send_recordtime(float msg);
- void race_SendRankings(float pos, float prevpos, float del, float msg);
  void send_CSQC_teamnagger() {
        WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
        WriteByte(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
  }
  
- void Announce(string snd) {
-       WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-       WriteByte(MSG_BROADCAST, TE_CSQC_ANNOUNCE);
-       WriteString(MSG_BROADCAST, snd);
- }
- void AnnounceTo(entity e, string snd) {
-       if (clienttype(e) == CLIENTTYPE_REAL)
-       {
-               msg_entity = e;
-               WriteByte(MSG_ONE, SVC_TEMPENTITY);
-               WriteByte(MSG_ONE, TE_CSQC_ANNOUNCE);
-               WriteString(MSG_ONE, snd);
-       }
- }
  float ClientData_Send(entity to, float sf)
  {
        if(to != self.owner)
@@@ -33,7 -14,7 +14,7 @@@
        entity e;
  
        e = to;
-       if(to.classname == "spectator")
+       if(IS_SPEC(to))
                e = to.enemy;
  
        sf = 0;
@@@ -84,245 -65,16 +65,16 @@@ void ClientData_Touch(entity e
        FOR_EACH_REALCLIENT(e2)
        {
                if(e2 != e)
-                       if(e2.classname == "spectator")
+                       if(IS_SPEC(e2))
                                if(e2.enemy == e)
                                        e2.clientdata.SendFlags = 1;
        }
  }
  
- .vector spawnpoint_score;
  .string netname_previous;
  
- void spawnfunc_info_player_survivor (void)
- {
-       spawnfunc_info_player_deathmatch();
- }
- void spawnfunc_info_player_start (void)
- {
-       spawnfunc_info_player_deathmatch();
- }
- void spawnfunc_info_player_deathmatch (void)
- {
-       self.classname = "info_player_deathmatch";
-       relocate_spawnpoint();
- }
+ void SetSpectator(entity player, entity spectatee);
  
- void spawnpoint_use()
- {
-       if(teamplay)
-       if(have_team_spawns > 0)
-       {
-               self.team = activator.team;
-               some_spawn_has_been_used = 1;
-       }
- }
- // Returns:
- //   _x: prio (-1 if unusable)
- //   _y: weight
- vector Spawn_Score(entity spot, float mindist, float teamcheck)
- {
-       float shortest, thisdist;
-       float prio;
-       entity player;
-       prio = 0;
-       // filter out spots for the wrong team
-       if(teamcheck >= 0)
-               if(spot.team != teamcheck)
-                       return '-1 0 0';
-       if(race_spawns)
-               if(spot.target == "")
-                       return '-1 0 0';
-       if(clienttype(self) == CLIENTTYPE_REAL)
-       {
-               if(spot.restriction == 1)
-                       return '-1 0 0';
-       }
-       else
-       {
-               if(spot.restriction == 2)
-                       return '-1 0 0';
-       }
-       shortest = vlen(world.maxs - world.mins);
-       FOR_EACH_PLAYER(player) if (player != self)
-       {
-               thisdist = vlen(player.origin - spot.origin);
-               if (thisdist < shortest)
-                       shortest = thisdist;
-       }
-       if(shortest > mindist)
-               prio += SPAWN_PRIO_GOOD_DISTANCE;
-       spawn_score = prio * '1 0 0' + shortest * '0 1 0';
-       spawn_spot = spot;
-       // filter out spots for assault
-       if(spot.target != "") {
-               entity ent;
-               float found;
-               found = 0;
-               for(ent = world; (ent = find(ent, targetname, spot.target)); )
-               {
-                       ++found;
-                       if(ent.spawn_evalfunc)
-                       {
-                               entity oldself = self;
-                               self = ent;
-                               spawn_score = ent.spawn_evalfunc(oldself, spot, spawn_score);
-                               self = oldself;
-                               if(spawn_score_x < 0)
-                                       return spawn_score;
-                       }
-               }
-               if(!found)
-               {
-                       dprint("WARNING: spawnpoint at ", vtos(spot.origin), " could not find its target ", spot.target, "\n");
-                       return '-1 0 0';
-               }
-       }
-       MUTATOR_CALLHOOK(Spawn_Score);
-       return spawn_score;
- }
- void Spawn_ScoreAll(entity firstspot, float mindist, float teamcheck)
- {
-       entity spot;
-       for(spot = firstspot; spot; spot = spot.chain)
-               spot.spawnpoint_score = Spawn_Score(spot, mindist, teamcheck);
- }
- entity Spawn_FilterOutBadSpots(entity firstspot, float mindist, float teamcheck)
- {
-       entity spot, spotlist, spotlistend;
-       spotlist = world;
-       spotlistend = world;
-       Spawn_ScoreAll(firstspot, mindist, teamcheck);
-       for(spot = firstspot; spot; spot = spot.chain)
-       {
-               if(spot.spawnpoint_score_x >= 0) // spawning allowed here
-               {
-                       if(spotlistend)
-                               spotlistend.chain = spot;
-                       spotlistend = spot;
-                       if(!spotlist)
-                               spotlist = spot;
-               }
-       }
-       if(spotlistend)
-               spotlistend.chain = world;
-       return spotlist;
- }
- entity Spawn_WeightedPoint(entity firstspot, float lower, float upper, float exponent)
- {
-       // weight of a point: bound(lower, mindisttoplayer, upper)^exponent
-       // multiplied by spot.cnt (useful if you distribute many spawnpoints in a small area)
-       entity spot;
-       RandomSelection_Init();
-       for(spot = firstspot; spot; spot = spot.chain)
-               RandomSelection_Add(spot, 0, string_null, pow(bound(lower, spot.spawnpoint_score_y, upper), exponent) * spot.cnt, (spot.spawnpoint_score_y >= lower) * 0.5 + spot.spawnpoint_score_x);
-       return RandomSelection_chosen_ent;
- }
- /*
- =============
- SelectSpawnPoint
- Finds a point to respawn
- =============
- */
- entity SelectSpawnPoint (float anypoint)
- {
-       float teamcheck;
-       entity spot, firstspot;
-       spot = find (world, classname, "testplayerstart");
-       if (spot)
-               return spot;
-       if(anypoint || autocvar_g_spawn_useallspawns)
-               teamcheck = -1;
-       else if(have_team_spawns > 0)
-       {
-               if(have_team_spawns_forteam[self.team] == 0)
-               {
-                       // we request a spawn for a team, and we have team
-                       // spawns, but that team has no spawns?
-                       if(have_team_spawns_forteam[0])
-                               // try noteam spawns
-                               teamcheck = 0;
-                       else
-                               // if not, any spawn has to do
-                               teamcheck = -1;
-               }
-               else
-                       teamcheck = self.team; // MUST be team
-       }
-       else if(have_team_spawns == 0 && have_team_spawns_forteam[0])
-               teamcheck = 0; // MUST be noteam
-       else
-               teamcheck = -1;
-               // if we get here, we either require team spawns but have none, or we require non-team spawns and have none; use any spawn then
-       // get the entire list of spots
-       firstspot = findchain(classname, "info_player_deathmatch");
-       // filter out the bad ones
-       // (note this returns the original list if none survived)
-       if(anypoint)
-       {
-               spot = Spawn_WeightedPoint(firstspot, 1, 1, 1);
-       }
-       else
-       {
-               float mindist;
-               if (arena_roundbased && !g_ca)
-                       mindist = 800;
-               else
-                       mindist = 100;
-               firstspot = Spawn_FilterOutBadSpots(firstspot, mindist, teamcheck);
-               // there is 50/50 chance of choosing a random spot or the furthest spot
-               // (this means that roughly every other spawn will be furthest, so you
-               // usually won't get fragged at spawn twice in a row)
-               if (random() > autocvar_g_spawn_furthest)
-                       spot = Spawn_WeightedPoint(firstspot, 1, 1, 1);
-               else
-                       spot = Spawn_WeightedPoint(firstspot, 1, 5000, 5); // chooses a far far away spawnpoint
-       }
-       if (!spot)
-       {
-               if(autocvar_spawn_debug)
-                       GotoNextMap(0);
-               else
-               {
-                       if(some_spawn_has_been_used)
-                               return world; // team can't spawn any more, because of actions of other team
-                       else
-                               error("Cannot find a spawn point - please fix the map!");
-               }
-       }
-       return spot;
- }
  
  /*
  =============
@@@ -387,49 -139,49 +139,50 @@@ void PutObserverInServer (void
  {
        entity  spot;
      self.hud = HUD_NORMAL;
-       race_PreSpawnObserver();
+       if(IS_PLAYER(self)) { pointparticles(particleeffectnum("spawn_event_neutral"), self.origin, '0 0 0', 1); }
  
        spot = SelectSpawnPoint (TRUE);
        if(!spot)
                error("No spawnpoints for observers?!?\n");
        RemoveGrapplingHook(self); // Wazat's Grappling Hook
  
-       if(clienttype(self) == CLIENTTYPE_REAL)
+       if(IS_REAL_CLIENT(self))
        {
 +              Item_ItemsTime_Get(self);
                msg_entity = self;
                WriteByte(MSG_ONE, SVC_SETVIEW);
                WriteEntity(MSG_ONE, self);
        }
  
-       MUTATOR_CALLHOOK(MakePlayerObserver);
+       self.frags = FRAGS_SPECTATOR;
  
-       minstagib_stop_countdown(self);
+       MUTATOR_CALLHOOK(MakePlayerObserver);
  
        Portal_ClearAll(self);
-       
+       Unfreeze(self);
        if(self.alivetime)
        {
-               if(!inWarmupStage)
-                       PlayerStats_Event(self, PLAYERSTATS_ALIVETIME, time - self.alivetime);
+               if(!warmup_stage)
+                       PS_GR_P_ADDVAL(self, PLAYERSTATS_ALIVETIME, time - self.alivetime);
                self.alivetime = 0;
        }
  
        if(self.vehicle)
-               vehicles_exit(VHEF_RELESE);         
+               vehicles_exit(VHEF_RELESE);
  
        WaypointSprite_PlayerDead();
  
-       if not(g_ca)  // don't reset teams when moving a ca player to the spectators
+       if (!g_ca)  // don't reset teams when moving a ca player to the spectators
                self.team = -1;  // move this as it is needed to log the player spectating in eventlog
  
-       if(self.killcount != -666) {
-               if(g_lms) {
-                       if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0 && self.lms_spectate_warning != 2)
-                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_NOLIVES, self.netname);
-                       else
-                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_FORFEIT, self.netname);
-               } else { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_SPECTATE, self.netname); }
+       if(self.killcount != -666)
+       {
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_SPECTATE, self.netname);
+               if(autocvar_g_chat_nospectators == 1 || (cvar("g_warmup") && !(warmup_stage || gameover) && autocvar_g_chat_nospectators == 2))
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_CHAT_NOSPECTATORS);
  
                if(self.just_joined == FALSE) {
                        LogTeamchange(self.playerid, -1, 4);
        accuracy_resend(self);
  
        self.spectatortime = time;
-       
        self.classname = "observer";
        self.iscreature = FALSE;
        self.teleportable = TELEPORT_SIMPLE;
        self.pauseregen_finished = 0;
        self.damageforcescale = 0;
        self.death_time = 0;
+       self.respawn_flags = 0;
        self.respawn_time = 0;
+       self.stat_respawn_time = 0;
        self.alpha = 0;
        self.scale = 0;
        self.fade_time = 0;
        self.angles_z = 0;
        self.fixangle = TRUE;
        self.crouch = FALSE;
+       self.revival_time = 0;
  
        setorigin (self, (spot.origin + PL_VIEW_OFS)); // offset it so that the spectator spawns higher off the ground, looks better this way
        self.prevorigin = self.origin;
        self.items = 0;
-       WEPSET_CLEAR_E(self);
+       self.weapons = '0 0 0';
        self.model = "";
        FixPlayermodel();
        setmodel(self, "null");
        self.punchvector = '0 0 0';
        self.oldvelocity = self.velocity;
        self.fire_endtime = -1;
-       if(g_arena)
-       {
-               if(self.version_mismatch)
-               {
-                       self.frags = FRAGS_SPECTATOR;
-                       Spawnqueue_Unmark(self);
-                       Spawnqueue_Remove(self);
-               }
-               else
-               {
-                       self.frags = FRAGS_LMS_LOSER;
-                       Spawnqueue_Insert(self);
-               }
-       }
-       else if(g_lms)
-       {
-               // Only if the player cannot play at all
-               if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
-                       self.frags = FRAGS_SPECTATOR;
-               else
-                       self.frags = FRAGS_LMS_LOSER;
-       }
-       else if(g_ca)
-       {
-               if(self.caplayer)
-                       self.frags = FRAGS_LMS_LOSER;
-               else
-                       self.frags = FRAGS_SPECTATOR;
-       }
-       else if((g_race && g_race_qualifying) || g_cts)
-       {
-               if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
-                       self.frags = FRAGS_LMS_LOSER;
-               else
-                       self.frags = FRAGS_SPECTATOR;
-       }
-       else
-               self.frags = FRAGS_SPECTATOR;
+       self.event_damage = func_null;
  }
  
  .float model_randomizer;
@@@ -562,7 -279,7 +280,7 @@@ void FixPlayermodel(
                if(teamplay)
                {
                        string s;
-                       s = Team_ColorName_Lower(self.team);
+                       s = Static_Team_ColorName_Lower(self.team);
                        if(s != "neutral")
                        {
                                defaultmodel = cvar_string(strcat("sv_defaultplayermodel_", s));
  
                n = tokenize_console(defaultmodel);
                if(n > 0)
+               {
                        defaultmodel = argv(floor(n * self.model_randomizer));
+                       // However, do NOT randomize if the player-selected model is in the list.
+                       for (i = 0; i < n; ++i)
+                               if ((argv(i) == self.playermodel && defaultskin == stof(self.playerskin)) || argv(i) == strcat(self.playermodel, ":", self.playerskin))
+                                       defaultmodel = argv(i);
+               }
  
                i = strstrofs(defaultmodel, ":", 0);
                if(i >= 0)
                                setcolor(self, stof(autocvar_sv_defaultplayercolors));
  }
  
- void PlayerTouchExplode(entity p1, entity p2)
- {
-       vector org;
-       org = (p1.origin + p2.origin) * 0.5;
-       org_z += (p1.mins_z + p2.mins_z) * 0.5;
-       te_explosion(org);
-       entity e;
-       e = spawn();
-       setorigin(e, org);
-       RadiusDamage(e, world, g_touchexplode_damage, g_touchexplode_edgedamage, g_touchexplode_radius, world, g_touchexplode_force, DEATH_TOUCHEXPLODE, world);
-       remove(e);
- }
  /*
  =============
  PutClientInServer
  Called when a client spawns in the server
  =============
  */
  void PutClientInServer (void)
  {
-       if(clienttype(self) == CLIENTTYPE_BOT)
-       {
+       if(IS_BOT_CLIENT(self))
                self.classname = "player";
-               if(g_ca)
-                       self.caplayer = 1;
-       }
-       else if(clienttype(self) == CLIENTTYPE_REAL)
+       else if(IS_REAL_CLIENT(self))
        {
                msg_entity = self;
                WriteByte(MSG_ONE, SVC_SETVIEW);
                WriteEntity(MSG_ONE, self);
        }
  
+       SetSpectator(self, world);
        // reset player keys
        self.itemkeys = 0;
  
-       // player is dead and becomes observer
-       // FIXME fix LMS scoring for new system
-       if(g_lms)
-       {
-               if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0)
-                       self.classname = "observer";
-       }
-       if((g_arena && !self.spawned) || (g_ca && !allowed_to_spawn))
-               self.classname = "observer";
+       MUTATOR_CALLHOOK(PutClientInServer);
  
        if(gameover)
                self.classname = "observer";
  
-       if(self.classname == "player" && (!g_ca || (g_ca && allowed_to_spawn))) {
+       if(IS_PLAYER(self))
+       {
                entity spot, oldself;
                float j;
  
                if(self.team < 0)
                        JoinBestTeam(self, FALSE, TRUE);
  
-               race_PreSpawn();
                spot = SelectSpawnPoint (FALSE);
                if(!spot)
                {
  
                RemoveGrapplingHook(self); // Wazat's Grappling Hook
  
+               if(self.vehicle)
+                       vehicles_exit(VHEF_RELESE);
                self.classname = "player";
                self.wasplayer = TRUE;
                self.iscreature = TRUE;
                self.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID;
                if(autocvar_g_playerclip_collisions)
                        self.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP;
-               if(clienttype(self) == CLIENTTYPE_BOT && autocvar_g_botclip_collisions)
+               if(IS_BOT_CLIENT(self) && autocvar_g_botclip_collisions)
                        self.dphitcontentsmask |= DPCONTENTS_BOTCLIP;
                self.frags = FRAGS_PLAYER;
                if(INDEPENDENT_PLAYERS)
                if(autocvar__notarget)
                        self.flags |= FL_NOTARGET;
                self.takedamage = DAMAGE_AIM;
-               if(g_minstagib)
-                       self.effects = EF_FULLBRIGHT;
-               else
-                       self.effects = 0;
+               self.effects = 0;
                self.effects |= EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
                self.air_finished = time + 12;
                self.dmg = 2;
-               if(autocvar_g_balance_nex_charge)
+               if(WEP_CVAR(vortex, charge))
                {
-                       if(autocvar_g_balance_nex_secondary_chargepool)
-                               self.nex_chargepool_ammo = 1;
-                       self.nex_charge = autocvar_g_balance_nex_charge_start;
+                       if(WEP_CVAR_SEC(vortex, chargepool))
+                               self.vortex_chargepool_ammo = 1;
+                       self.vortex_charge = WEP_CVAR(vortex, charge_start);
                }
  
-               if(inWarmupStage)
+               if(warmup_stage)
                {
                        self.ammo_shells = warmup_start_ammo_shells;
                        self.ammo_nails = warmup_start_ammo_nails;
                        self.ammo_rockets = warmup_start_ammo_rockets;
                        self.ammo_cells = warmup_start_ammo_cells;
+                       self.ammo_plasma = warmup_start_ammo_plasma;
                        self.ammo_fuel = warmup_start_ammo_fuel;
                        self.health = warmup_start_health;
                        self.armorvalue = warmup_start_armorvalue;
-                       WEPSET_COPY_EA(self, warmup_start_weapons);
+                       self.weapons = WARMUP_START_WEAPONS;
                }
                else
                {
                        self.ammo_nails = start_ammo_nails;
                        self.ammo_rockets = start_ammo_rockets;
                        self.ammo_cells = start_ammo_cells;
+                       self.ammo_plasma = start_ammo_plasma;
                        self.ammo_fuel = start_ammo_fuel;
                        self.health = start_health;
                        self.armorvalue = start_armorvalue;
-                       WEPSET_COPY_EA(self, start_weapons);
+                       self.weapons = start_weapons;
                }
  
-               if(WEPSET_CONTAINS_ANY_EA(self, WEPBIT_SUPERWEAPONS)) // exception for minstagib, as minstanex is a superweapon
+               if(self.weapons & WEPSET_SUPERWEAPONS)
                        self.superweapons_finished = time + autocvar_g_balance_superweapons_time;
                else
                        self.superweapons_finished = 0;
  
-               if(!inWarmupStage)
++              if(!warmup_stage)
 +                      Item_ItemsTime_ResetForPlayer(self);
 +
-               if(g_weaponarena_random)
+               if(g_weaponarena_random) // WEAPONTODO: more stuff that should be in a mutator. also: rename those cvars
                {
-                       if(g_weaponarena_random_with_laser)
-                               WEPSET_ANDNOT_EW(self, WEP_LASER);
+                       if(g_weaponarena_random_with_blaster)
+                               self.weapons &= ~WEPSET_BLASTER;
                        W_RandomWeapons(self, g_weaponarena_random);
-                       if(g_weaponarena_random_with_laser)
-                               WEPSET_OR_EW(self, WEP_LASER);
+                       if(g_weaponarena_random_with_blaster)
+                               self.weapons |= WEPSET_BLASTER;
                }
  
                self.items = start_items;
                }
                self.damageforcescale = 2;
                self.death_time = 0;
+               self.respawn_flags = 0;
                self.respawn_time = 0;
+               self.stat_respawn_time = 0;
                self.scale = 0;
                self.fade_time = 0;
                self.pain_frame = 0;
                self.angles = spot.angles;
  
                self.angles_z = 0; // never spawn tilted even if the spot says to
+               if(IS_BOT_CLIENT(self))
+                       self.v_angle = self.angles;
                self.fixangle = TRUE; // turn this way immediately
                self.velocity = '0 0 0';
                self.avelocity = '0 0 0';
                self.punchvector = '0 0 0';
                self.oldvelocity = self.velocity;
                self.fire_endtime = -1;
+               self.revival_time = 0;
  
-               msg_entity = self;
-               WRITESPECTATABLE_MSG_ONE({
-                       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-                       WriteByte(MSG_ONE, TE_CSQC_SPAWN);
-               });
+               entity spawnevent = spawn();
+               spawnevent.owner = self;
+               Net_LinkEntity(spawnevent, FALSE, 0.5, SpawnEvent_Send);
+               // Cut off any still running player sounds.
+               stopsound(self, CH_PLAYER_SINGLE);
  
                self.model = "";
                FixPlayermodel();
                self.lastteleporttime = time; // prevent insane speeds due to changing origin
          self.hud = HUD_NORMAL;
  
-               if(g_arena)
-               {
-                       Spawnqueue_Remove(self);
-                       Spawnqueue_Mark(self);
-               }
-               else if(g_ca)
-                       self.caplayer = 1;
                self.event_damage = PlayerDamage;
  
                self.bot_attack = TRUE;
+               self.monster_attack = TRUE;
+               
+               self.spider_slowness = 0;
  
-               self.statdraintime = time + 5;
                self.BUTTON_ATCK = self.BUTTON_JUMP = self.BUTTON_ATCK2 = 0;
  
                if(self.killcount == -666) {
                self.colormod = '1 1 1' * autocvar_g_player_brightness;
                self.exteriorweaponentity.alpha = default_weapon_alpha;
  
-               self.lms_nextcheck = time + autocvar_g_lms_campcheck_interval*2;
-               self.lms_traveled_distance = 0;
                self.speedrunning = FALSE;
  
-               race_PostSpawn(spot);
                //stuffcmd(self, "chase_active 0");
                //stuffcmd(self, "set viewsize $tmpviewsize \n");
  
-               if(g_assault) {
-                       if(self.team == assault_attacker_team)
-                               Send_Notification(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_ATTACKING);
-                       else
-                               Send_Notification(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_DEFENDING);
-               }
                target_voicescript_clear(self);
  
                // reset fields the weapons may use
                for (j = WEP_FIRST; j <= WEP_LAST; ++j)
                {
-                       weapon_action(j, WR_RESETPLAYER);
+                       WEP_ACTION(j, WR_RESETPLAYER);
  
                        // all weapons must be fully loaded when we spawn
                        entity e;
                        e = get_weaponinfo(j);
                        if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
-                               self.(weapon_load[j]) = cvar(strcat("g_balance_", e.netname, "_reload_ammo"));
+                               self.(weapon_load[j]) = e.reloading_ammo;
                }
  
                oldself = self;
                        activator = world;
                self = oldself;
  
+               Unfreeze(self);
                spawn_spot = spot;
                MUTATOR_CALLHOOK(PlayerSpawn);
  
                self.weaponname = "";
                self.switchingweapon = 0;
  
-               if(!inWarmupStage)
+               if(!warmup_stage)
                        if(!self.alivetime)
                                self.alivetime = time;
  
                antilag_clear(self);
-               if (autocvar_g_spawnsound)
-                       soundat(world, self.origin, CH_TRIGGER, "misc/spawn.wav", VOL_BASE, ATTN_NORM);
-       } else if(self.classname == "observer") {
+       }
+       else if(IS_OBSERVER(self))
+       {
                PutObserverInServer ();
        }
  }
@@@ -949,31 -633,27 +637,27 @@@ float ClientInit_SendEntity(entity to, 
        WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[1]));
        WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[2]));
        WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[3]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(electro_shotorigin[0]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(electro_shotorigin[1]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(electro_shotorigin[2]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(electro_shotorigin[3]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(gauntlet_shotorigin[0]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(gauntlet_shotorigin[1]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(gauntlet_shotorigin[2]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(gauntlet_shotorigin[3]));
+       WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[0]));
+       WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[1]));
+       WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[2]));
+       WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[3]));
        if(sv_foginterval && world.fog != "")
                WriteString(MSG_ENTITY, world.fog);
        else
                WriteString(MSG_ENTITY, "");
        WriteByte(MSG_ENTITY, self.count * 255.0); // g_balance_armor_blockpercent
-       WriteByte(MSG_ENTITY, self.cnt * 255.0); // g_balance_weaponswitchdelay
-       WriteCoord(MSG_ENTITY, self.bouncefactor); // g_balance_grenadelauncher_bouncefactor
-       WriteCoord(MSG_ENTITY, self.bouncestop); // g_balance_grenadelauncher_bouncestop
-       WriteCoord(MSG_ENTITY, self.ebouncefactor); // g_balance_grenadelauncher_bouncefactor
-       WriteCoord(MSG_ENTITY, self.ebouncestop); // g_balance_grenadelauncher_bouncestop
-       WriteByte(MSG_ENTITY, autocvar_g_balance_nex_secondary); // client has to know if it should zoom or not
-       WriteByte(MSG_ENTITY, autocvar_g_balance_rifle_secondary); // client has to know if it should zoom or not
+       WriteCoord(MSG_ENTITY, self.bouncefactor); // g_balance_mortar_bouncefactor // WEAPONTODO
+       WriteCoord(MSG_ENTITY, self.bouncestop); // g_balance_mortar_bouncestop
+       WriteCoord(MSG_ENTITY, self.ebouncefactor); // g_balance_mortar_bouncefactor
+       WriteCoord(MSG_ENTITY, self.ebouncestop); // g_balance_mortar_bouncestop
+       WriteByte(MSG_ENTITY, WEP_CVAR(vortex, secondary)); // client has to know if it should zoom or not // WEAPONTODO
+       WriteByte(MSG_ENTITY, WEP_CVAR(rifle, secondary)); // client has to know if it should zoom or not // WEAPONTODO
        WriteByte(MSG_ENTITY, serverflags); // client has to know if it should zoom or not
-       WriteByte(MSG_ENTITY, autocvar_g_balance_minelayer_limit); // minelayer max mines
-       WriteByte(MSG_ENTITY, autocvar_g_balance_hagar_secondary_load_max); // hagar max loadable rockets
+       WriteByte(MSG_ENTITY, WEP_CVAR(minelayer, limit)); // minelayer max mines // WEAPONTODO
+       WriteByte(MSG_ENTITY, WEP_CVAR_SEC(hagar, load_max)); // hagar max loadable rockets // WEAPONTODO
        WriteCoord(MSG_ENTITY, autocvar_g_trueaim_minrange);
-       WriteByte(MSG_ENTITY, autocvar_g_balance_porto_secondary);
+       WriteByte(MSG_ENTITY, WEP_CVAR(porto, secondary)); // WEAPONTODO
        return TRUE;
  }
  
@@@ -985,19 -665,14 +669,14 @@@ void ClientInit_CheckUpdate(
                self.count = autocvar_g_balance_armor_blockpercent;
                self.SendFlags |= 1;
        }
-       if(self.cnt != autocvar_g_balance_weaponswitchdelay)
-       {
-               self.cnt = autocvar_g_balance_weaponswitchdelay;
-               self.SendFlags |= 1;
-       }
-       if(self.bouncefactor != autocvar_g_balance_grenadelauncher_bouncefactor)
+       if(self.bouncefactor != autocvar_g_balance_mortar_bouncefactor) // WEAPONTODO
        {
-               self.bouncefactor = autocvar_g_balance_grenadelauncher_bouncefactor;
+               self.bouncefactor = autocvar_g_balance_mortar_bouncefactor;
                self.SendFlags |= 1;
        }
-       if(self.bouncestop != autocvar_g_balance_grenadelauncher_bouncestop)
+       if(self.bouncestop != autocvar_g_balance_mortar_bouncestop)
        {
-               self.bouncestop = autocvar_g_balance_grenadelauncher_bouncestop;
+               self.bouncestop = autocvar_g_balance_mortar_bouncestop;
                self.SendFlags |= 1;
        }
        if(self.ebouncefactor != autocvar_g_balance_electro_secondary_bouncefactor)
@@@ -1082,14 -757,13 +761,13 @@@ void ClientKill_Now_TeamChange(
        }
        else if(self.killindicator_teamchange == -2)
        {
-               if(g_ca)
-                       self.caplayer = 0;
                if(blockSpectators)
                        Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
                PutObserverInServer();
        }
        else
                SV_ChangeTeam(self.killindicator_teamchange - 1);
+       self.killindicator_teamchange = 0;
  }
  
  void ClientKill_Now()
            if(!self.killindicator_teamchange)
            {
              self.vehicle_health = -1;
-             Damage(self, self, self, 1 , DEATH_KILL, self.origin, '0 0 0');           
+             Damage(self, self, self, 1 , DEATH_KILL, self.origin, '0 0 0');
            }
        }
  
        if(self.killindicator_teamchange)
                ClientKill_Now_TeamChange();
  
-       // in any case:
-       Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
+       if(IS_PLAYER(self))
+               Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
  
        // now I am sure the player IS dead
  }
@@@ -1148,10 -822,10 +826,10 @@@ void KillIndicator_Think(
        {
                if(self.cnt <= 10)
                        setmodel(self, strcat("models/sprites/", ftos(self.cnt), ".spr32"));
-               if(clienttype(self.owner) == CLIENTTYPE_REAL)
+               if(IS_REAL_CLIENT(self.owner))
                {
                        if(self.cnt <= 10)
-                               AnnounceTo(self.owner, strcat(ftos(self.cnt), ""));
+                               { Send_Notification(NOTIF_ONE, self.owner, MSG_ANNCE, Announcer_PickNumber(CNT_KILL, self.cnt)); }
                }
                self.nextthink = time + 1;
                self.cnt -= 1;
@@@ -1192,7 -866,7 +870,7 @@@ void ClientKill_TeamChange (float targe
                        self.clientkill_nexttime = time + killtime + autocvar_g_balance_kill_antispam;
                }
  
-               if(killtime <= 0 || self.classname != "player" || self.deadflag != DEAD_NO)
+               if(killtime <= 0 || !IS_PLAYER(self) || self.deadflag != DEAD_NO)
                {
                        ClientKill_Now();
                }
                if(targetteam == 0) // just die
                {
                        self.killindicator.colormod = '0 0 0';
-                       if(clienttype(self) == CLIENTTYPE_REAL)
+                       if(IS_REAL_CLIENT(self))
                        if(self.killindicator.cnt > 0)
                                Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_SUICIDE, self.killindicator.cnt);
                }
                else if(targetteam == -1) // auto
                {
                        self.killindicator.colormod = '0 1 0';
-                       if(clienttype(self) == CLIENTTYPE_REAL)
+                       if(IS_REAL_CLIENT(self))
                        if(self.killindicator.cnt > 0)
                                Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_AUTO, self.killindicator.cnt);
                }
                else if(targetteam == -2) // spectate
                {
                        self.killindicator.colormod = '0.5 0.5 0.5';
-                       if(clienttype(self) == CLIENTTYPE_REAL)
+                       if(IS_REAL_CLIENT(self))
                        if(self.killindicator.cnt > 0)
                                Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_SPECTATE, self.killindicator.cnt);
                }
                else
                {
                        self.killindicator.colormod = Team_ColorRGB(targetteam);
-                       if(clienttype(self) == CLIENTTYPE_REAL)
+                       if(IS_REAL_CLIENT(self))
                        if(self.killindicator.cnt > 0)
                                Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, APP_TEAM_NUM_4(targetteam, CENTER_TEAMCHANGE_), self.killindicator.cnt);
                }
  
  void ClientKill (void)
  {
-       if (gameover)
-               return;
+       if(gameover) return;
+       if(self.player_blocked) return;
+       if(self.frozen) return;
  
-       if((g_arena || g_ca) && ((champion && champion.classname == "player" && player_count > 1) || player_count == 1)) // don't allow a kill in this case either
-       {
-               // do nothing
-       }
-     else if(self.freezetag_frozen)
-     {
-         // do nothing
-     }
-       else
-               ClientKill_TeamChange(0);
+       ClientKill_TeamChange(0);
  }
  
  void CTS_ClientKill (entity e) // silent version of ClientKill, used when player finishes a CTS run. Useful to prevent cheating by running back to the start line and starting out with more speed
@@@ -1301,23 -967,6 +971,6 @@@ void FixClientCvars(entity e
                stuffcmd(e, "cl_cmd settemp cl_prydoncursor_notrace 0\n");
        if(autocvar_sv_gentle)
                stuffcmd(e, "cl_cmd settemp cl_gentle 1\n");
-       /*
-        * we no longer need to stuff this. Remove this comment block if you feel
-        * 2.3 and higher (or was it 2.2.3?) don't need these any more
-       stuffcmd(e, strcat("cl_gravity ", ftos(autocvar_sv_gravity), "\n"));
-       stuffcmd(e, strcat("cl_movement_accelerate ", ftos(autocvar_sv_accelerate), "\n"));
-       stuffcmd(e, strcat("cl_movement_friction ", ftos(autocvar_sv_friction), "\n"));
-       stuffcmd(e, strcat("cl_movement_maxspeed ", ftos(autocvar_sv_maxspeed), "\n"));
-       stuffcmd(e, strcat("cl_movement_airaccelerate ", ftos(autocvar_sv_airaccelerate), "\n"));
-       stuffcmd(e, strcat("cl_movement_maxairspeed ", ftos(autocvar_sv_maxairspeed), "\n"));
-       stuffcmd(e, strcat("cl_movement_stopspeed ", ftos(autocvar_sv_stopspeed), "\n"));
-       stuffcmd(e, strcat("cl_movement_jumpvelocity ", ftos(autocvar_sv_jumpvelocity), "\n"));
-       stuffcmd(e, strcat("cl_movement_stepheight ", ftos(autocvar_sv_stepheight), "\n"));
-       stuffcmd(e, strcat("set cl_movement_friction_on_land ", ftos(autocvar_sv_friction_on_land), "\n"));
-       stuffcmd(e, strcat("set cl_movement_airaccel_qw ", ftos(autocvar_sv_airaccel_qw), "\n"));
-       stuffcmd(e, strcat("set cl_movement_airaccel_sideways_friction ", ftos(autocvar_sv_airaccel_sideways_friction), "\n"));
-       stuffcmd(e, "cl_movement_edgefriction 1\n");
-        */
  }
  
  float PlayerInIDList(entity p, string idlist)
        string s;
  
        // NOTE: we do NOT check crypto_keyfp here, an unsigned ID is fine too for this
-       if not(p.crypto_idfp)
+       if (!p.crypto_idfp)
                return 0;
  
        // this function allows abbreviated player IDs too!
@@@ -1355,7 -1004,7 +1008,7 @@@ void ClientConnect (void
  {
        float t;
  
-       if(self.flags & FL_CLIENT)
+       if(IS_CLIENT(self))
        {
                print("Warning: ClientConnect, but already connected!\n");
                return;
                player_count = 0;
        }
  
+       if(IS_REAL_CLIENT(self)) { PlayerStats_PlayerBasic_CheckUpdate(self); }
        PlayerScore_Attach(self);
        ClientData_Attach();
        accuracy_init(self);
  
        anticheat_init();
  
-       race_PreSpawnObserver();
        // identify the right forced team
        if(autocvar_g_campaign)
        {
-               if(clienttype(self) == CLIENTTYPE_REAL) // only players, not bots
+               if(IS_REAL_CLIENT(self)) // only players, not bots
                {
                        switch(autocvar_g_campaign_forceteam)
                        {
  
        JoinBestTeam(self, FALSE, FALSE); // if the team number is valid, keep it
  
-       if((autocvar_sv_spectate == 1 && !g_lms) || autocvar_g_campaign || self.team_forced < 0) {
+       if((autocvar_sv_spectate == 1) || autocvar_g_campaign || self.team_forced < 0) {
                self.classname = "observer";
        } else {
                if(teamplay)
  
        self.playerid = (playerid_last = playerid_last + 1);
  
-       PlayerStats_AddEvent(sprintf("kills-%d", self.playerid));
+       PlayerStats_GameReport_AddEvent(sprintf("kills-%d", self.playerid));
  
-     if(clienttype(self) == CLIENTTYPE_BOT)
-         PlayerStats_AddPlayer(self);
+     if(IS_BOT_CLIENT(self))
+         PlayerStats_GameReport_AddPlayer(self);
  
        if(autocvar_sv_eventlog)
-               GameLogEcho(strcat(":join:", ftos(self.playerid), ":", ftos(num_for_edict(self)), ":", ((clienttype(self) == CLIENTTYPE_REAL) ? self.netaddress : "bot"), ":", self.netname));
+               GameLogEcho(strcat(":join:", ftos(self.playerid), ":", ftos(num_for_edict(self)), ":", ((IS_REAL_CLIENT(self)) ? self.netaddress : "bot"), ":", self.netname));
  
        LogTeamchange(self.playerid, self.team, 1);
  
  
        self.netname_previous = strzone(self.netname);
  
-       if((self.classname == STR_PLAYER && teamplay))
+       if(IS_PLAYER(self) && teamplay)
                Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(self, INFO_JOIN_CONNECT_TEAM_), self.netname);
        else
                Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_CONNECT, self.netname);
        // Wazat's grappling hook
        SetGrappleHookBindings();
  
+       // Jetpack binds
+       stuffcmd(self, "alias +jetpack +button10\n");
+       stuffcmd(self, "alias -jetpack -button10\n");
        // get version info from player
        stuffcmd(self, "cmd clientversion $gameversion\n");
  
        else
                stuffcmd(self, "set _teams_available 0\n");
  
-       if(g_arena || g_ca)
-       {
-               self.classname = "observer";
-               if(g_arena)
-                       Spawnqueue_Insert(self);
-       }
        attach_entcs();
  
        bot_relinkplayerlist();
        self.jointime = time;
        self.allowed_timeouts = autocvar_sv_timeout_number;
  
-       if(clienttype(self) == CLIENTTYPE_REAL)
+       if(IS_REAL_CLIENT(self))
        {
-               if(autocvar_g_bugrigs || WEPSET_EQ_AW(g_weaponarena_weapons, WEP_TUBA))
-                       stuffcmd(self, "cl_cmd settemp chase_active 1\n");
-       }
-       if(g_lms)
-       {
-               if(PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
+               if(!autocvar_g_campaign)
                {
-                       PlayerScore_Add(self, SP_LMS_RANK, 666);
-                       self.frags = FRAGS_SPECTATOR;
+                       self.motd_actived_time = -1;
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
                }
+               if(autocvar_g_bugrigs || (g_weaponarena_weapons == WEPSET_TUBA))
+                       stuffcmd(self, "cl_cmd settemp chase_active 1\n");
        }
  
        if(!sv_foginterval && world.fog != "")
                stuffcmd(self, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n"));
  
-       if(autocvar_g_hitplots || strstrofs(strcat(" ", autocvar_g_hitplots_individuals, " "), strcat(" ", self.netaddress, " "), 0) >= 0)
-       {
-               self.hitplotfh = fopen(strcat("hits-", matchid, "-", self.netaddress, "-", ftos(self.playerid), ".plot"), FILE_WRITE);
-               fputs(self.hitplotfh, strcat("#name ", self.netname, "\n"));
-       }
-       else
-               self.hitplotfh = -1;
-       if(g_race || g_cts) {
-               string rr;
-               if(g_cts)
-                       rr = CTS_RECORD;
-               else
-                       rr = RACE_RECORD;
-               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 = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
-               race_send_speedaward_alltimebest(MSG_ONE);
+       W_HitPlotOpen(self);
  
-               float i;
-               for (i = 1; i <= RANKINGS_CNT; ++i) {
-                       race_SendRankings(i, 0, 0, MSG_ONE);
-               }
-       }
-       else if(autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)) && !g_ca) // teamnagger is currently bad for ca
+       if(autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)) && !g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts
                send_CSQC_teamnagger();
  
        CheatInitClient();
  
-       if(!autocvar_g_campaign)
-               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
        CSQCMODEL_AUTOINIT();
  
        self.model_randomizer = random();
-     
-     if(clienttype(self) != CLIENTTYPE_REAL)
-         return;
-         
-     sv_notice_join();
-     
-     MUTATOR_CALLHOOK(ClientConnect);
+       if(IS_REAL_CLIENT(self))
+               sv_notice_join();
+       MUTATOR_CALLHOOK(ClientConnect);
  }
  /*
  =============
@@@ -1606,21 -1218,19 +1222,19 @@@ void ClientDisconnect (void
        if(self.vehicle)
            vehicles_exit(VHEF_RELESE);
  
-       if not(self.flags & FL_CLIENT)
+       if (!IS_CLIENT(self))
        {
                print("Warning: ClientDisconnect without ClientConnect\n");
                return;
        }
  
-       PlayerStats_AddGlobalInfo(self);
+       PlayerStats_GameReport_FinalizePlayer(self);
+       if(IS_PLAYER(self)) { pointparticles(particleeffectnum("spawn_event_neutral"), self.origin, '0 0 0', 1); }
  
        CheatShutdownClient();
  
-       if(self.hitplotfh >= 0)
-       {
-               fclose(self.hitplotfh);
-               self.hitplotfh = -1;
-       }
+       W_HitPlotClose(self);
  
        anticheat_report();
        anticheat_shutdown();
  
        if(autocvar_sv_eventlog)
                GameLogEcho(strcat(":part:", ftos(self.playerid)));
-               
        Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_DISCONNECT, self.netname);
  
        MUTATOR_CALLHOOK(ClientDisconnect);
  
        Portal_ClearAll(self);
  
+       Unfreeze(self);
        RemoveGrapplingHook(self);
  
        // Here, everything has been done that requires this player to be a client.
  
-       self.flags &~= FL_CLIENT;
+       self.flags &= ~FL_CLIENT;
  
        if (self.chatbubbleentity)
                remove (self.chatbubbleentity);
  
        bot_relinkplayerlist();
  
-       if(g_arena)
-       {
-               Spawnqueue_Unmark(self);
-               Spawnqueue_Remove(self);
-       }
        accuracy_free(self);
        ClientData_Detach();
        PlayerScore_Detach(self);
@@@ -1769,10 -1375,10 +1379,10 @@@ void respawn(void
  
  void play_countdown(float finished, string samp)
  {
-       if(clienttype(self) == CLIENTTYPE_REAL)
+       if(IS_REAL_CLIENT(self))
                if(floor(finished - time - frametime) != floor(finished - time))
                        if(finished - time < 6)
-                               sound (self, CH_INFO, samp, VOL_BASE, ATTN_NORM);
+                               sound (self, CH_INFO, samp, VOL_BASE, ATTEN_NORM);
  }
  
  void player_powerups (void)
        // add a way to see what the items were BEFORE all of these checks for the mutator hook
        olditems = self.items;
  
-       if((self.items & IT_USING_JETPACK) && !self.deadflag)
+       if((self.items & IT_USING_JETPACK) && !self.deadflag && !gameover)
                self.modelflags |= MF_ROCKET;
        else
-               self.modelflags &~= MF_ROCKET;
+               self.modelflags &= ~MF_ROCKET;
  
-       self.effects &~= (EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT | EF_FLAME | EF_NODEPTHTEST);
+       self.effects &= ~(EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT | EF_FLAME | EF_NODEPTHTEST);
  
-       if(self.alpha < 0 || self.deadflag) // don't apply the flags if the player is gibbed
+       if((self.alpha < 0 || self.deadflag) && !self.vehicle) // don't apply the flags if the player is gibbed
                return;
  
        Fire_ApplyDamage(self);
        Fire_ApplyEffect(self);
  
-       if (g_minstagib)
-       {
-               self.effects |= EF_FULLBRIGHT;
-               if (self.items & IT_STRENGTH)
-               {
-                       play_countdown(self.strength_finished, "misc/poweroff.wav");
-                       if (time > self.strength_finished)
-                       {
-                               self.alpha = default_player_alpha;
-                               self.exteriorweaponentity.alpha = default_weapon_alpha;
-                               self.items &~= IT_STRENGTH;
-                               //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_INVISIBILITY, self.netname);
-                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
-                       }
-               }
-               else
-               {
-                       if (time < self.strength_finished)
-                       {
-                               self.alpha = g_minstagib_invis_alpha;
-                               self.exteriorweaponentity.alpha = g_minstagib_invis_alpha;
-                               self.items |= IT_STRENGTH;
-                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_INVISIBILITY, self.netname);
-                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
-                       }
-               }
-               if (self.items & IT_INVINCIBLE)
-               {
-                       play_countdown(self.invincible_finished, "misc/poweroff.wav");
-                       if (time > self.invincible_finished)
-                       {
-                               self.items = self.items - (self.items & IT_INVINCIBLE);
-                               //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_SPEED, self.netname);
-                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SPEED);
-                       }
-               }
-               else
-               {
-                       if (time < self.invincible_finished)
-                       {
-                               self.items = self.items | IT_INVINCIBLE;
-                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SPEED, self.netname);
-                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SPEED);
-                       }
-               }
-       }
-       else // if we're not in minstagib, continue. I added this else to replace the "return" which was here that broke the callhook for this function -- This code is nasty.
+       if (!g_instagib)
        {
                if (self.items & IT_STRENGTH)
                {
                }
                if (self.items & IT_SUPERWEAPON)
                {
-                       if (!WEPSET_CONTAINS_ANY_EA(self, WEPBIT_SUPERWEAPONS))
+                       if (!(self.weapons & WEPSET_SUPERWEAPONS))
                        {
                                self.superweapons_finished = 0;
                                self.items = self.items - (self.items & IT_SUPERWEAPON);
                                if (time > self.superweapons_finished)
                                {
                                        self.items = self.items - (self.items & IT_SUPERWEAPON);
-                                       WEPSET_ANDNOT_EA(self, WEPBIT_SUPERWEAPONS);
+                                       self.weapons &= ~WEPSET_SUPERWEAPONS;
                                        //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_SUPERWEAPON_BROKEN, self.netname);
                                        Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_SUPERWEAPON_BROKEN);
                                }
                        }
                }
-               else if(WEPSET_CONTAINS_ANY_EA(self, WEPBIT_SUPERWEAPONS))
+               else if(self.weapons & WEPSET_SUPERWEAPONS)
                {
                        if (time < self.superweapons_finished || (self.items & IT_UNLIMITED_SUPERWEAPONS))
                        {
                        else
                        {
                                self.superweapons_finished = 0;
-                               WEPSET_ANDNOT_EA(self, WEPBIT_SUPERWEAPONS);
+                               self.weapons &= ~WEPSET_SUPERWEAPONS;
                        }
                }
                else
                        self.superweapons_finished = 0;
                }
        }
-       
        if(autocvar_g_nodepthtestplayers)
                self.effects = self.effects | EF_NODEPTHTEST;
  
        if(autocvar_g_fullbrightplayers)
                self.effects = self.effects | EF_FULLBRIGHT;
  
-       // midair gamemode: damage only while in the air
-       // if in midair mode, being on ground grants temporary invulnerability
-       // (this is so that multishot weapon don't clear the ground flag on the
-       // first damage in the frame, leaving the player vulnerable to the
-       // remaining hits in the same frame)
-       if (self.flags & FL_ONGROUND)
-       if (g_midair)
-               self.spawnshieldtime = max(self.spawnshieldtime, time + autocvar_g_midair_shieldtime);
        if (time >= game_starttime)
        if (time < self.spawnshieldtime)
                self.effects = self.effects | (EF_ADDITIVE | EF_FULLBRIGHT);
@@@ -1997,44 -1546,52 +1550,52 @@@ float CalcRotRegen(float current, floa
  
  void player_regen (void)
  {
-       float minh, mina, minf, maxh, maxa, maxf, limith, limita, limitf, max_mod, regen_mod, rot_mod, limit_mod;
-       maxh = autocvar_g_balance_health_rotstable;
-       maxa = autocvar_g_balance_armor_rotstable;
-       maxf = autocvar_g_balance_fuel_rotstable;
-       minh = autocvar_g_balance_health_regenstable;
-       mina = autocvar_g_balance_armor_regenstable;
-       minf = autocvar_g_balance_fuel_regenstable;
-       limith = autocvar_g_balance_health_limit;
-       limita = autocvar_g_balance_armor_limit;
-       limitf = autocvar_g_balance_fuel_limit;
+       float max_mod, regen_mod, rot_mod, limit_mod;
        max_mod = regen_mod = rot_mod = limit_mod = 1;
+       regen_mod_max = max_mod;
+       regen_mod_regen = regen_mod;
+       regen_mod_rot = rot_mod;
+       regen_mod_limit = limit_mod;
+       if(!MUTATOR_CALLHOOK(PlayerRegen))
+       if(!self.frozen)
+       {
+               float minh, mina, maxh, maxa, limith, limita;
+               maxh = autocvar_g_balance_health_rotstable;
+               maxa = autocvar_g_balance_armor_rotstable;
+               minh = autocvar_g_balance_health_regenstable;
+               mina = autocvar_g_balance_armor_regenstable;
+               limith = autocvar_g_balance_health_limit;
+               limita = autocvar_g_balance_armor_limit;
+               max_mod = regen_mod_max;
+               regen_mod = regen_mod_regen;
+               rot_mod = regen_mod_rot;
+               limit_mod = regen_mod_limit;
+               maxh = maxh * max_mod;
+               minh = minh * max_mod;
+               limith = limith * limit_mod;
+               limita = limita * limit_mod;
  
-       maxh = maxh * max_mod;
-       //maxa = maxa * max_mod;
-       //maxf = maxf * max_mod;
-       minh = minh * max_mod;
-       //mina = mina * max_mod;
-       //minf = minf * max_mod;
-       limith = limith * limit_mod;
-       limita = limita * limit_mod;
-       //limitf = limitf * limit_mod;
+               self.armorvalue = CalcRotRegen(self.armorvalue, mina, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, regen_mod * frametime * (time > self.pauseregen_finished), maxa, autocvar_g_balance_armor_rot, autocvar_g_balance_armor_rotlinear, rot_mod * frametime * (time > self.pauserotarmor_finished), limita);
+               self.health = CalcRotRegen(self.health, minh, autocvar_g_balance_health_regen, autocvar_g_balance_health_regenlinear, regen_mod * frametime * (time > self.pauseregen_finished), maxh, autocvar_g_balance_health_rot, autocvar_g_balance_health_rotlinear, rot_mod * frametime * (time > self.pauserothealth_finished), limith);
+       }
  
-       if(g_lms && g_ca)
-               rot_mod = 0;
+       // if player rotted to death...  die!
+       // check this outside above checks, as player may still be able to rot to death
+       if(self.health < 1)
+               self.event_damage(self, self, 1, DEATH_ROT, self.origin, '0 0 0');
  
-       if (!g_minstagib && !g_ca && (!g_lms || autocvar_g_lms_regenerate))
+       if (!(self.items & IT_UNLIMITED_WEAPON_AMMO))
        {
-               self.armorvalue = CalcRotRegen(self.armorvalue, mina, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, regen_mod * frametime * (time > self.pauseregen_finished), maxa, autocvar_g_balance_armor_rot, autocvar_g_balance_armor_rotlinear, rot_mod * frametime * (time > self.pauserotarmor_finished), limita);
-               self.health = CalcRotRegen(self.health, minh, autocvar_g_balance_health_regen, autocvar_g_balance_health_regenlinear, regen_mod * frametime * (time > self.pauseregen_finished), maxh, autocvar_g_balance_health_rot, autocvar_g_balance_health_rotlinear, rot_mod * frametime * (time > self.pauserothealth_finished), limith);
+               float minf, maxf, limitf;
  
-               // if player rotted to death...  die!
-               if(self.health < 1)
-                       self.event_damage(self, self, 1, DEATH_ROT, self.origin, '0 0 0');
-       }
+               maxf = autocvar_g_balance_fuel_rotstable;
+               minf = autocvar_g_balance_fuel_regenstable;
+               limitf = autocvar_g_balance_fuel_limit;
  
-       if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
-               self.ammo_fuel = CalcRotRegen(self.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, regen_mod * frametime * (time > self.pauseregen_finished) * (self.items & IT_FUEL_REGEN != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, rot_mod * frametime * (time > self.pauserotfuel_finished), limitf);
+               self.ammo_fuel = CalcRotRegen(self.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, frametime * (time > self.pauseregen_finished) * ((self.items & IT_FUEL_REGEN) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > self.pauserotfuel_finished), limitf);
+       }
  }
  
  float zoomstate_set;
@@@ -2053,52 -1610,52 +1614,52 @@@ void GetPressedKeys(void) 
        if (self.movement_x > 0) // get if movement keys are pressed
        {       // forward key pressed
                self.pressedkeys |= KEY_FORWARD;
-               self.pressedkeys &~= KEY_BACKWARD;
+               self.pressedkeys &= ~KEY_BACKWARD;
        }
        else if (self.movement_x < 0)
        {       // backward key pressed
                self.pressedkeys |= KEY_BACKWARD;
-               self.pressedkeys &~= KEY_FORWARD;
+               self.pressedkeys &= ~KEY_FORWARD;
        }
        else
        {       // no x input
-               self.pressedkeys &~= KEY_FORWARD;
-               self.pressedkeys &~= KEY_BACKWARD;
+               self.pressedkeys &= ~KEY_FORWARD;
+               self.pressedkeys &= ~KEY_BACKWARD;
        }
  
        if (self.movement_y > 0)
        {       // right key pressed
                self.pressedkeys |= KEY_RIGHT;
-               self.pressedkeys &~= KEY_LEFT;
+               self.pressedkeys &= ~KEY_LEFT;
        }
        else if (self.movement_y < 0)
        {       // left key pressed
                self.pressedkeys |= KEY_LEFT;
-               self.pressedkeys &~= KEY_RIGHT;
+               self.pressedkeys &= ~KEY_RIGHT;
        }
        else
        {       // no y input
-               self.pressedkeys &~= KEY_RIGHT;
-               self.pressedkeys &~= KEY_LEFT;
+               self.pressedkeys &= ~KEY_RIGHT;
+               self.pressedkeys &= ~KEY_LEFT;
        }
  
        if (self.BUTTON_JUMP) // get if jump and crouch keys are pressed
                self.pressedkeys |= KEY_JUMP;
        else
-               self.pressedkeys &~= KEY_JUMP;
+               self.pressedkeys &= ~KEY_JUMP;
        if (self.BUTTON_CROUCH)
                self.pressedkeys |= KEY_CROUCH;
        else
-               self.pressedkeys &~= KEY_CROUCH;
+               self.pressedkeys &= ~KEY_CROUCH;
  
        if (self.BUTTON_ATCK)
                self.pressedkeys |= KEY_ATCK;
        else
-               self.pressedkeys &~= KEY_ATCK;
+               self.pressedkeys &= ~KEY_ATCK;
        if (self.BUTTON_ATCK2)
                self.pressedkeys |= KEY_ATCK2;
        else
-               self.pressedkeys &~= KEY_ATCK2;
+               self.pressedkeys &= ~KEY_ATCK2;
  }
  
  /*
@@@ -2113,6 -1670,7 +1674,7 @@@ void SpectateCopy(entity spectatee) 
        self.armortype = spectatee.armortype;
        self.armorvalue = spectatee.armorvalue;
        self.ammo_cells = spectatee.ammo_cells;
+       self.ammo_plasma = spectatee.ammo_plasma;
        self.ammo_shells = spectatee.ammo_shells;
        self.ammo_nails = spectatee.ammo_nails;
        self.ammo_rockets = spectatee.ammo_rockets;
        self.strength_finished = spectatee.strength_finished;
        self.invincible_finished = spectatee.invincible_finished;
        self.pressedkeys = spectatee.pressedkeys;
-       WEPSET_COPY_EE(self, spectatee);
+       self.weapons = spectatee.weapons;
        self.switchweapon = spectatee.switchweapon;
        self.switchingweapon = spectatee.switchingweapon;
        self.weapon = spectatee.weapon;
-       self.nex_charge = spectatee.nex_charge;
-       self.nex_chargepool_ammo = spectatee.nex_chargepool_ammo;
+       self.vortex_charge = spectatee.vortex_charge;
+       self.vortex_chargepool_ammo = spectatee.vortex_chargepool_ammo;
        self.hagar_load = spectatee.hagar_load;
+       self.arc_heat_percent = spectatee.arc_heat_percent;
        self.minelayer_mines = spectatee.minelayer_mines;
        self.punchangle = spectatee.punchangle;
        self.view_ofs = spectatee.view_ofs;
        self.dmg_inflictor = spectatee.dmg_inflictor;
        self.v_angle = spectatee.v_angle;
        self.angles = spectatee.v_angle;
-       self.stat_respawn_time = spectatee.stat_respawn_time;
+       self.frozen = spectatee.frozen;
+       self.revive_progress = spectatee.revive_progress;
        if(!self.BUTTON_USE)
                self.fixangle = TRUE;
        setorigin(self, spectatee.origin);
        setsize(self, spectatee.mins, spectatee.maxs);
        SetZoomState(spectatee.zoomstate);
-     
      anticheat_spectatecopy(spectatee);
        self.hud = spectatee.hud;
        if(spectatee.vehicle)
          self.vehicle_reload2 = spectatee.vehicle_reload2;
  
          msg_entity = self;
-         
          WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
              WriteAngle(MSG_ONE,  spectatee.v_angle_x);
              WriteAngle(MSG_ONE,  spectatee.v_angle_y);
              WriteAngle(MSG_ONE,  spectatee.v_angle_z);
  
          //WriteByte (MSG_ONE, SVC_SETVIEW);
-         //    WriteEntity(MSG_ONE, self);            
+         //    WriteEntity(MSG_ONE, self);
          //makevectors(spectatee.v_angle);
-         //setorigin(self, spectatee.origin - v_forward * 400 + v_up * 300);*/    
+         //setorigin(self, spectatee.origin - v_forward * 400 + v_up * 300);*/
      }
  }
  
- float SpectateUpdate() {
+ float SpectateUpdate()
+ {
        if(!self.enemy)
-           return 0;           
+           return 0;
  
-       if (self == self.enemy)
-               return 0;
-       if(self.enemy.classname != "player")
+       if(!IS_PLAYER(self.enemy) || self == self.enemy)
+       {
+               SetSpectator(self, world);
                return 0;
+       }
  
        SpectateCopy(self.enemy);
  
        return 1;
  }
  
+ float SpectateSet()
+ {
+       if(self.enemy.classname != "player")
+               return FALSE;
+       /*if(self.enemy.vehicle)
+       {
+               msg_entity = self;
+               WriteByte(MSG_ONE, SVC_SETVIEW);
+               WriteEntity(MSG_ONE, self.enemy);
+               //stuffcmd(self, "set viewsize $tmpviewsize \n");
+               self.movetype = MOVETYPE_NONE;
+               accuracy_resend(self);
+       }
+       else
+       {*/
+               msg_entity = self;
+               WriteByte(MSG_ONE, SVC_SETVIEW);
+               WriteEntity(MSG_ONE, self.enemy);
+               //stuffcmd(self, "set viewsize $tmpviewsize \n");
+               self.movetype = MOVETYPE_NONE;
+               accuracy_resend(self);
+               if(!SpectateUpdate())
+                       PutObserverInServer();
+       //}
+       return TRUE;
+ }
+ void SetSpectator(entity player, entity spectatee)
+ {
+       entity old_spectatee = player.enemy;
+       player.enemy = spectatee;
+       // WEAPONTODO
+       // these are required to fix the spectator bug with arc
+       if(old_spectatee && old_spectatee.arc_beam) { old_spectatee.arc_beam.SendFlags |= ARC_SF_SETTINGS; }
+       if(player.enemy && player.enemy.arc_beam) { player.enemy.arc_beam.SendFlags |= ARC_SF_SETTINGS; }
+ }
+ float Spectate(entity pl)
+ {
+       if(g_ca && !autocvar_g_ca_spectate_enemies && self.caplayer)
+       if(pl.team != self.team)
+               return 0;
+       SetSpectator(self, pl);
+       return SpectateSet();
+ }
  
  // Returns next available player to spectate if g_ca_spectate_enemies == 0
  entity CA_SpectateNext(entity start) {
        if (start.team == self.team) {
                return start;
        }
-       
        other = start;
        // continue from current player
        while(other && other.team != self.team) {
                other = find(other, classname, "player");
        }
-       
        if (!other) {
                // restart from begining
                other = find(other, classname, "player");
                        other = find(other, classname, "player");
                }
        }
-       
        return other;
  }
  
- float SpectateNext(entity _prefer) {
-       
-       if(_prefer)
-               other = _prefer;        
-       else
-               other = find(self.enemy, classname, "player");
-       
+ float SpectateNext()
+ {
+       other = find(self.enemy, classname, "player");
        if (g_ca && !autocvar_g_ca_spectate_enemies && self.caplayer) {
                // CA and ca players when spectating enemies is forbidden
                other = CA_SpectateNext(other);
                if (!other)
                        other = find(other, classname, "player");
        }
-       
-       if (other)
-               self.enemy = other;
-       if(self.enemy.classname == "player") {
-           /*if(self.enemy.vehicle)
-           {      
-             
-             msg_entity = self;
-             WriteByte(MSG_ONE, SVC_SETVIEW);
-             WriteEntity(MSG_ONE, self.enemy);
-             //stuffcmd(self, "set viewsize $tmpviewsize \n");
-             
-             self.movetype = MOVETYPE_NONE;
-             accuracy_resend(self);
-           }
-           else 
-           {*/         
-             msg_entity = self;
-             WriteByte(MSG_ONE, SVC_SETVIEW);
-             WriteEntity(MSG_ONE, self.enemy);
-             //stuffcmd(self, "set viewsize $tmpviewsize \n");
-             self.movetype = MOVETYPE_NONE;
-             accuracy_resend(self);
-             if(!SpectateUpdate())
-                 PutObserverInServer();
-         //}
-         return 1;
-       } else {
-               return 0;
+       if(other) { SetSpectator(self, other); }
+       return SpectateSet();
+ }
+ float SpectatePrev()
+ {
+       // NOTE: chain order is from the highest to the lower entnum (unlike find)
+       other = findchain(classname, "player");
+       if (!other) // no player
+               return FALSE;
+       entity first = other;
+       // skip players until current spectated player
+       if(self.enemy)
+       while(other && other != self.enemy)
+               other = other.chain;
+       if (g_ca && !autocvar_g_ca_spectate_enemies && self.caplayer)
+       {
+               do { other = other.chain; }
+               while(other && other.team != self.team);
+               if (!other)
+               {
+                       other = first;
+                       while(other.team != self.team)
+                               other = other.chain;
+                       if(other == self.enemy)
+                               return TRUE;
+               }
        }
+       else
+       {
+               if(other.chain)
+                       other = other.chain;
+               else
+                       other = first;
+       }
+       SetSpectator(self, other);
+       return SpectateSet();
  }
  
  /*
@@@ -2289,39 -1908,41 +1912,41 @@@ void ShowRespawnCountdown(
                {
                        self.respawn_countdown = number - 1;
                        if(ceil(self.respawn_time - (time + 0.5)) == number) // only say it if it is the same number even in 0.5s; to prevent overlapping sounds
-                               AnnounceTo(self, strcat(ftos(number), ""));
+                               { Send_Notification(NOTIF_ONE, self, MSG_ANNCE, Announcer_PickNumber(CNT_RESPAWN, number)); }
                }
        }
  }
  
  void LeaveSpectatorMode()
  {
+       if(self.caplayer)
+               return;
        if(nJoinAllowed(self))
        {
                if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0)
                {
                        self.classname = "player";
+                       nades_RemoveBonus(self);
  
                        if(autocvar_g_campaign || autocvar_g_balance_teams)
                                { JoinBestTeam(self, FALSE, TRUE); }
  
                        if(autocvar_g_campaign)
                                { campaign_bots_may_start = 1; }
-                       else
-                               { Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD); }
  
                        Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
-                       
                        PutClientInServer();
  
                        if(IS_PLAYER(self)) { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_PLAY, self.netname); }
                }
-               else if not(g_ca && self.caplayer) { stuffcmd(self, "menu_showteamselect\n"); }
+               else
+                       stuffcmd(self, "menu_showteamselect\n");
        }
        else
        {
                // Player may not join because g_maxplayers is set
-               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
+               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_PREVENT);
        }
  }
  
@@@ -2356,8 -1977,9 +1981,9 @@@ float nJoinAllowed(entity ignore) 
                return maxclients - totalClients;
  
        float currentlyPlaying = 0;
-       FOR_EACH_REALPLAYER(e)
-               currentlyPlaying += 1;
+       FOR_EACH_REALCLIENT(e)
+               if(IS_PLAYER(e) || e.caplayer)
+                       currentlyPlaying += 1;
  
        if(currentlyPlaying < autocvar_g_maxplayers)
                return min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying);
   * g_maxplayers_spectator_blocktime seconds
   */
  void checkSpectatorBlock() {
-       if(self.classname == "spectator" || self.classname == "observer") {
+       if(IS_SPEC(self) || IS_OBSERVER(self))
+       if(!self.caplayer)
+       if(IS_REAL_CLIENT(self))
+       {
                if( time > (self.spectatortime + autocvar_g_maxplayers_spectator_blocktime) ) {
                        Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_QUIT_KICK_SPECTATING);
                        dropclient(self);
        }
  }
  
- .float motd_actived_time; // used for both motd and campaign_message
  void PrintWelcomeMessage()
  {
-       if (self.motd_actived_time == 0) { // is there already a message showing?
+       if(self.motd_actived_time == 0)
+       {
                if (autocvar_g_campaign) {
-                       if ((self.classname == "player" && self.BUTTON_INFO) || (self.classname != "player")) {
+                       if ((IS_PLAYER(self) && self.BUTTON_INFO) || (!IS_PLAYER(self))) {
                                self.motd_actived_time = time;
                                Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, campaign_message);
                        }
                } else {
-                       if ((time - self.jointime > autocvar_welcome_message_time) && self.BUTTON_INFO) {
+                       if (self.BUTTON_INFO) {
                                self.motd_actived_time = time;
                                Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
                        }
                }
-       } else { // showing MOTD or campaign message
+       }
+       else if(self.motd_actived_time > 0) // showing MOTD or campaign message
+       {
                if (autocvar_g_campaign) {
                        if (self.BUTTON_INFO)
                                self.motd_actived_time = time;
-                       else if ((time - self.motd_actived_time > 2) && self.classname == "player") { // hide it some seconds after BUTTON_INFO has been released
+                       else if ((time - self.motd_actived_time > 2) && IS_PLAYER(self)) { // hide it some seconds after BUTTON_INFO has been released
                                self.motd_actived_time = 0;
                                Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
                        }
                } else {
-                       if ((time - self.jointime) > autocvar_welcome_message_time) {
-                               if (self.BUTTON_INFO)
-                                       self.motd_actived_time = time;
-                               else if (time - self.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
-                                       self.motd_actived_time = 0;
-                                       Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
-                               }
+                       if (self.BUTTON_INFO)
+                               self.motd_actived_time = time;
+                       else if (time - self.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
+                               self.motd_actived_time = 0;
+                               Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
                        }
                }
        }
+       else //if(self.motd_actived_time < 0) // just connected, motd is active
+       {
+               if(self.BUTTON_INFO) // BUTTON_INFO hides initial MOTD
+                       self.motd_actived_time = -2; // wait until BUTTON_INFO gets released
+               else if(self.motd_actived_time == -2 || IS_PLAYER(self))
+               {
+                       // instanctly hide MOTD
+                       self.motd_actived_time = 0;
+                       Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
+               }
+       }
  }
  
  void ObserverThink()
        float prefered_movetype;
        if (self.flags & FL_JUMPRELEASED) {
                if (self.BUTTON_JUMP && !self.version_mismatch) {
-                       self.flags &~= FL_JUMPRELEASED;
+                       self.flags &= ~FL_JUMPRELEASED;
                        self.flags |= FL_SPAWNING;
                } else if(self.BUTTON_ATCK && !self.version_mismatch) {
-                       self.flags &~= FL_JUMPRELEASED;
-                       if(SpectateNext(world) == 1) {
+                       self.flags &= ~FL_JUMPRELEASED;
+                       if(SpectateNext()) {
                                self.classname = "spectator";
                        }
                } else {
                        self.flags |= FL_JUMPRELEASED;
                        if(self.flags & FL_SPAWNING)
                        {
-                               self.flags &~= FL_SPAWNING;
+                               self.flags &= ~FL_SPAWNING;
                                LeaveSpectatorMode();
                                return;
                        }
                }
        }
-       PrintWelcomeMessage();
  }
  
  void SpectatorThink()
  {
        if (self.flags & FL_JUMPRELEASED) {
                if (self.BUTTON_JUMP && !self.version_mismatch) {
-                       self.flags &~= FL_JUMPRELEASED;
+                       self.flags &= ~FL_JUMPRELEASED;
                        self.flags |= FL_SPAWNING;
-               } else if(self.BUTTON_ATCK) {
-                       self.flags &~= FL_JUMPRELEASED;
-                       if(SpectateNext(world) == 1) {
+               } else if(self.BUTTON_ATCK || self.impulse == 10 || self.impulse == 15 || self.impulse == 18 || (self.impulse >= 200 && self.impulse <= 209)) {
+                       self.flags &= ~FL_JUMPRELEASED;
+                       if(SpectateNext()) {
+                               self.classname = "spectator";
+                       } else {
+                               self.classname = "observer";
+                               PutClientInServer();
+                       }
+                       self.impulse = 0;
+               } else if(self.impulse == 12 || self.impulse == 16  || self.impulse == 19 || (self.impulse >= 220 && self.impulse <= 229)) {
+                       self.flags &= ~FL_JUMPRELEASED;
+                       if(SpectatePrev()) {
                                self.classname = "spectator";
                        } else {
                                self.classname = "observer";
                                PutClientInServer();
                        }
+                       self.impulse = 0;
                } else if (self.BUTTON_ATCK2) {
-                       self.flags &~= FL_JUMPRELEASED;
+                       self.flags &= ~FL_JUMPRELEASED;
                        self.classname = "observer";
                        PutClientInServer();
                } else {
                        self.flags |= FL_JUMPRELEASED;
                        if(self.flags & FL_SPAWNING)
                        {
-                               self.flags &~= FL_SPAWNING;
+                               self.flags &= ~FL_SPAWNING;
                                LeaveSpectatorMode();
                                return;
                        }
                        PutObserverInServer();
        }
  
-       PrintWelcomeMessage();
        self.flags |= FL_CLIENT | FL_NOTARGET;
  }
  
  void PlayerUseKey()
  {
-       if(self.classname != "player")
+       if (!IS_PLAYER(self))
                return;
  
        if(self.vehicle)
          vehicles_exit(VHEF_NORMAL);
          return;
        }
-       
        // a use key was pressed; call handlers
        MUTATOR_CALLHOOK(PlayerUseKey);
  }
  
- .float touchexplode_time;
+ float isInvisibleString(string s)
+ {
+       float i, n, c;
+       s = strdecolorize(s);
+       for((i = 0), (n = strlen(s)); i < n; ++i)
+       {
+               c = str2chr(s, i);
+               switch(c)
+               {
+                       case 0:
+                       case 32: // space
+                               break;
+                       case 192: // charmap space
+                               if (!autocvar_utf8_enable)
+                                       break;
+                               return FALSE;
+                       case 160: // space in unicode fonts
+                       case 0xE000 + 192: // utf8 charmap space
+                               if (autocvar_utf8_enable)
+                                       break;
+                       default:
+                               return FALSE;
+               }
+       }
+       return TRUE;
+ }
  
  /*
  =============
@@@ -2518,14 -2186,10 +2190,10 @@@ void PlayerPreThink (void
        WarpZone_PlayerPhysics_FixVAngle();
  
        self.stat_game_starttime = game_starttime;
-       self.stat_allow_oldnexbeam = autocvar_g_allow_oldnexbeam;
+       self.stat_round_starttime = round_starttime;
+       self.stat_allow_oldvortexbeam = autocvar_g_allow_oldvortexbeam;
        self.stat_leadlimit = autocvar_leadlimit;
  
-       if(g_arena || (g_ca && !allowed_to_spawn))
-               self.stat_respawn_time = 0;
-       else
-               self.stat_respawn_time = self.respawn_time;
        if(frametime)
        {
                // physics frames: update anticheat stuff
  
        zoomstate_set = 0;
  
-       if(self.netname_previous != self.netname)
-       {
+       // Savage: Check for nameless players
+       if (isInvisibleString(self.netname)) {
+               string new_name = strzone(strcat("Player@", self.netaddress));
+               if(autocvar_sv_eventlog)
+                       GameLogEcho(strcat(":name:", ftos(self.playerid), ":", new_name));
+               if(self.netname_previous)
+                       strunzone(self.netname_previous);
+               self.netname_previous = strzone(new_name);
+               self.netname = self.netname_previous;
+               // stuffcmd(self, strcat("name ", self.netname, "\n"));
+       } else if(self.netname_previous != self.netname) {
                if(autocvar_sv_eventlog)
                        GameLogEcho(strcat(":name:", ftos(self.playerid), ":", self.netname));
                if(self.netname_previous)
                return;
  #endif
  
+       if(self.frozen == 2)
+       {
+               self.revive_progress = bound(0, self.revive_progress + frametime * self.revive_speed, 1);
+               self.health = max(1, self.revive_progress * start_health);
+               self.iceblock.alpha = bound(0.2, 1 - self.revive_progress, 1);
+               if(self.revive_progress >= 1)
+                       Unfreeze(self);
+       }
+       else if(self.frozen == 3)
+       {
+               self.revive_progress = bound(0, self.revive_progress - frametime * self.revive_speed, 1);
+               self.health = max(0, autocvar_g_nades_ice_health + (start_health-autocvar_g_nades_ice_health) * self.revive_progress );
+               
+               if(self.health < 1)
+               {
+                       if(self.vehicle)
+                               vehicles_exit(VHEF_RELESE);
+                       self.event_damage(self, self.frozen_by, 1, DEATH_NADE_ICE_FREEZE, self.origin, '0 0 0');
+               }
+               else if ( self.revive_progress <= 0 )
+                       Unfreeze(self);
+       }
        MUTATOR_CALLHOOK(PlayerPreThink);
  
        if(!self.cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button
                self.usekeypressed = self.BUTTON_USE;
        }
  
-       PrintWelcomeMessage();
+       if(IS_REAL_CLIENT(self))
+               PrintWelcomeMessage();
  
-       if(self.classname == "player") {
- //            if(self.netname == "Wazat")
- //                    bprint(self.classname, "\n");
+       if(IS_PLAYER(self))
+       {
  
                CheckRules_Player();
  
  
                if(frametime)
                {
-                       if(self.weapon == WEP_NEX && autocvar_g_balance_nex_charge)
+                       if(self.weapon == WEP_VORTEX && WEP_CVAR(vortex, charge))
                        {
-                               self.weaponentity_glowmod_x = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
-                               self.weaponentity_glowmod_y = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
-                               self.weaponentity_glowmod_z = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
+                               self.weaponentity_glowmod_x = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_half * min(1, self.vortex_charge / WEP_CVAR(vortex, charge_animlimit));
+                               self.weaponentity_glowmod_y = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_half * min(1, self.vortex_charge / WEP_CVAR(vortex, charge_animlimit));
+                               self.weaponentity_glowmod_z = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_half * min(1, self.vortex_charge / WEP_CVAR(vortex, charge_animlimit));
  
-                               if(self.nex_charge > autocvar_g_balance_nex_charge_animlimit)
+                               if(self.vortex_charge > WEP_CVAR(vortex, charge_animlimit))
                                {
-                                       self.weaponentity_glowmod_x = self.weaponentity_glowmod_x + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
-                                       self.weaponentity_glowmod_y = self.weaponentity_glowmod_y + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
-                                       self.weaponentity_glowmod_z = self.weaponentity_glowmod_z + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
+                                       self.weaponentity_glowmod_x = self.weaponentity_glowmod_x + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_full * (self.vortex_charge - WEP_CVAR(vortex, charge_animlimit)) / (1 - WEP_CVAR(vortex, charge_animlimit));
+                                       self.weaponentity_glowmod_y = self.weaponentity_glowmod_y + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_full * (self.vortex_charge - WEP_CVAR(vortex, charge_animlimit)) / (1 - WEP_CVAR(vortex, charge_animlimit));
+                                       self.weaponentity_glowmod_z = self.weaponentity_glowmod_z + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_full * (self.vortex_charge - WEP_CVAR(vortex, charge_animlimit)) / (1 - WEP_CVAR(vortex, charge_animlimit));
                                }
                        }
                        else
                        player_powerups();
                }
  
-               if (g_minstagib)
-                       minstagib_ammocheck();
                if (self.deadflag != DEAD_NO)
                {
-                       float button_pressed, force_respawn;
                        if(self.personal && g_race_qualifying)
                        {
                                if(time > self.respawn_time)
                                {
                                        self.respawn_time = time + 1; // only retry once a second
+                                       self.stat_respawn_time = self.respawn_time;
                                        respawn();
                                        self.impulse = 141;
                                }
                        }
                        else
                        {
+                               float button_pressed;
                                if(frametime)
                                        player_anim();
                                button_pressed = (self.BUTTON_ATCK || self.BUTTON_JUMP || self.BUTTON_ATCK2 || self.BUTTON_HOOK || self.BUTTON_USE);
-                               force_respawn = (g_lms || g_ca || g_cts || autocvar_g_forced_respawn);
                                if (self.deadflag == DEAD_DYING)
                                {
-                                       if(force_respawn)
+                                       if((self.respawn_flags & RESPAWN_FORCE) && !autocvar_g_respawn_delay_max)
                                                self.deadflag = DEAD_RESPAWNING;
                                        else if(!button_pressed)
                                                self.deadflag = DEAD_DEAD;
                                {
                                        if(button_pressed)
                                                self.deadflag = DEAD_RESPAWNABLE;
+                                       else if(time >= self.respawn_time_max && (self.respawn_flags & RESPAWN_FORCE))
+                                               self.deadflag = DEAD_RESPAWNING;
                                }
                                else if (self.deadflag == DEAD_RESPAWNABLE)
                                {
                                        if(time > self.respawn_time)
                                        {
                                                self.respawn_time = time + 1; // only retry once a second
+                                               self.respawn_time_max = self.respawn_time;
                                                respawn();
                                        }
                                }
                                ShowRespawnCountdown();
+                               if(self.respawn_flags & RESPAWN_SILENT)
+                                       self.stat_respawn_time = 0;
+                               else if((self.respawn_flags & RESPAWN_FORCE) && autocvar_g_respawn_delay_max)
+                                       self.stat_respawn_time = self.respawn_time_max;
+                               else
+                                       self.stat_respawn_time = self.respawn_time;
                        }
  
                        // if respawning, invert stat_respawn_time to indicate this, the client translates it
  
                        return;
                }
-               // FIXME from now on self.deadflag is always 0 (and self.health is never < 1)
-               // so (self.deadflag == DEAD_NO) is always true in the code below
-               if(g_touchexplode)
-               if(time > self.touchexplode_time)
-               if(self.classname == "player")
-               if(self.deadflag == DEAD_NO)
-               if not(IS_INDEPENDENT_PLAYER(self))
-               FOR_EACH_PLAYER(other) if(self != other)
-               {
-                       if(time > other.touchexplode_time)
-                       if(other.deadflag == DEAD_NO)
-                       if not(IS_INDEPENDENT_PLAYER(other))
-                       if(boxesoverlap(self.absmin, self.absmax, other.absmin, other.absmax))
-                       {
-                               PlayerTouchExplode(self, other);
-                               self.touchexplode_time = other.touchexplode_time = time + 0.2;
-                       }
-               }
-               if(g_lms && !self.deadflag && autocvar_g_lms_campcheck_interval)
-               {
-                       vector dist;
-                       // calculate player movement (in 2 dimensions only, so jumping on one spot doesn't count as movement)
-                       dist = self.prevorigin - self.origin;
-                       dist_z = 0;
-                       self.lms_traveled_distance += fabs(vlen(dist));
-                       if((autocvar_g_campaign && !campaign_bots_may_start) || (time < game_starttime))
-                       {
-                               self.lms_nextcheck = time + autocvar_g_lms_campcheck_interval*2;
-                               self.lms_traveled_distance = 0;
-                       }
-                       if(time > self.lms_nextcheck)
-                       {
-                               //sprint(self, "distance: ", ftos(self.lms_traveled_distance), "\n");
-                               if(self.lms_traveled_distance < autocvar_g_lms_campcheck_distance)
-                               {
-                                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_LMS_CAMPCHECK);
-                                       // FIXME KadaverJack: gibbing player here causes playermodel to bounce around, instead of eye.md3
-                                       // I wasn't able to find out WHY that happens, so I put a workaround in place that shall prevent players from being gibbed :(
-                                       Damage(self, self, self, bound(0, autocvar_g_lms_campcheck_damage, self.health + self.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP, self.origin, '0 0 0');
-                               }
-                               self.lms_nextcheck = time + autocvar_g_lms_campcheck_interval;
-                               self.lms_traveled_distance = 0;
-                       }
-               }
  
                self.prevorigin = self.origin;
  
                float do_crouch = self.BUTTON_CROUCH;
                if(self.hook.state)
                        do_crouch = 0;
-               if(self.health <= g_bloodloss)
-                       do_crouch = 1;
                if(self.vehicle)
                        do_crouch = 0;
-               if(self.freezetag_frozen)
+               if(self.frozen)
                        do_crouch = 0;
-               if(self.weapon == WEP_SHOTGUN && self.weaponentity.wframe == WFRAME_FIRE2 && time < self.weapon_nextthink)
+               // WEAPONTODO: THIS SHIT NEEDS TO GO EVENTUALLY
+               // It cannot be predicted by the engine! 
+               if((self.weapon == WEP_SHOCKWAVE || self.weapon == WEP_SHOTGUN) && self.weaponentity.wframe == WFRAME_FIRE2 && time < self.weapon_nextthink)
                        do_crouch = 0;
  
                if (do_crouch)
                        }
                }
  
-               if(self.health <= g_bloodloss && self.deadflag == DEAD_NO)
-               {
-                       if(self.bloodloss_timer < time)
-                       {
-                               self.event_damage(self, self, 1, DEATH_ROT, self.origin, '0 0 0');
-                               self.bloodloss_timer = time + 0.5 + random() * 0.5;
-                       }
-               }
                FixPlayermodel();
  
                GrapplingHookFrame();
                // LordHavoc: allow firing on move frames (sub-ticrate), this gives better timing on slow servers
                //if(frametime)
                {
-                       self.items &~= self.items_added;
+                       self.items &= ~self.items_added;
  
                        W_WeaponFrame();
  
  
                player_regen();
  
-               // rot nex charge to the charge limit
-               if(autocvar_g_balance_nex_charge_rot_rate && self.nex_charge > autocvar_g_balance_nex_charge_limit && self.nex_charge_rottime < time)
-                       self.nex_charge = bound(autocvar_g_balance_nex_charge_limit, self.nex_charge - autocvar_g_balance_nex_charge_rot_rate * frametime / W_TICSPERFRAME, 1);
+               // WEAPONTODO: Add a weapon request for this 
+               // rot vortex charge to the charge limit
+               if(WEP_CVAR(vortex, charge_rot_rate) && self.vortex_charge > WEP_CVAR(vortex, charge_limit) && self.vortex_charge_rottime < time)
+                       self.vortex_charge = bound(WEP_CVAR(vortex, charge_limit), self.vortex_charge - WEP_CVAR(vortex, charge_rot_rate) * frametime / W_TICSPERFRAME, 1);
  
                if(frametime)
                        player_anim();
  
-               if(g_nexball)
-                       nexball_setstatus();
-               
                // secret status
                secrets_setstatus();
-               
+               // monsters status
+               monsters_setstatus();
                self.dmg_team = max(0, self.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
  
                //self.angles_y=self.v_angle_y + 90;   // temp
                if (intermission_running)
                        IntermissionThink ();   // otherwise a button could be missed between
                return;
-       } else if(self.classname == "observer") {
+       } else if(IS_OBSERVER(self)) {
                ObserverThink();
-       } else if(self.classname == "spectator") {
+       } else if(IS_SPEC(self)) {
                SpectatorThink();
        }
  
+       // WEAPONTODO: Add weapon request for this
        if(!zoomstate_set)
-               SetZoomState(self.BUTTON_ZOOM || self.BUTTON_ZOOMSCRIPT || (self.BUTTON_ATCK2 && self.weapon == WEP_NEX) || (self.BUTTON_ATCK2 && self.weapon == WEP_RIFLE && autocvar_g_balance_rifle_secondary == 0));
+               SetZoomState(self.BUTTON_ZOOM || self.BUTTON_ZOOMSCRIPT || (self.BUTTON_ATCK2 && self.weapon == WEP_VORTEX) || (self.BUTTON_ATCK2 && self.weapon == WEP_RIFLE && WEP_CVAR(rifle, secondary) == 0)); // WEAPONTODO
  
        float oldspectatee_status;
        oldspectatee_status = self.spectatee_status;
-       if(self.classname == "spectator")
+       if(IS_SPEC(self))
                self.spectatee_status = num_for_edict(self.enemy);
-       else if(self.classname == "observer")
+       else if(IS_OBSERVER(self))
                self.spectatee_status = num_for_edict(self);
        else
                self.spectatee_status = 0;
        if(self.spectatee_status != oldspectatee_status)
        {
                ClientData_Touch(self);
-               if(g_race || g_cts)
-                       race_InitSpectator();
        }
  
        if(self.teamkill_soundtime)
  
        target_voicescript_next(self);
  
+       // WEAPONTODO: Move into weaponsystem somehow
        // if a player goes unarmed after holding a loaded weapon, empty his clip size and remove the crosshair ammo ring
        if(!self.weapon)
                self.clip_load = self.clip_size = 0;
  }
  
- float isInvisibleString(string s)
- {
-       float i, n, c;
-       s = strdecolorize(s);
-       for((i = 0), (n = strlen(s)); i < n; ++i)
-       {
-               c = str2chr(s, i);
-               switch(c)
-               {
-                       case 0:
-                       case 32: // space
-                               break;
-                       case 192: // charmap space
-                               if (!autocvar_utf8_enable)
-                                       break;
-                               return FALSE;
-                       case 160: // space in unicode fonts
-                       case 0xE000 + 192: // utf8 charmap space
-                               if (autocvar_utf8_enable)
-                                       break;
-                       default:
-                               return FALSE;
-               }
-       }
-       return TRUE;
- }
  /*
  =============
  PlayerPostThink
@@@ -2930,17 -2553,16 +2557,16 @@@ Called every frame for each client afte
  .float idlekick_lasttimeleft;
  void PlayerPostThink (void)
  {
-       // Savage: Check for nameless players
-       if (isInvisibleString(self.netname)) {
-               self.netname = "Player";
-               stuffcmd(self, strcat("name ", self.netname, substring(ftos(random()), 2, -1), "\n"));
-       }
-       if(sv_maxidle && frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
+       if(sv_maxidle > 0 && frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
+       if(IS_PLAYER(self) || sv_maxidle_spectatorsareidle)
        {
                if (time - self.parm_idlesince < 1) // instead of (time == self.parm_idlesince) to support sv_maxidle <= 10
                {
-                       if(self.idlekick_lasttimeleft) { self.idlekick_lasttimeleft = 0; }
+                       if(self.idlekick_lasttimeleft)
+                       {
+                               self.idlekick_lasttimeleft = 0;
+                               Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_IDLING);
+                       }
                }
                else
                {
                        else if(timeleft <= 10)
                        {
                                if(timeleft != self.idlekick_lasttimeleft)
-                                       AnnounceTo(self, ftos(timeleft));
+                                       { Send_Notification(NOTIF_ONE, self, MSG_ANNCE, Announcer_PickNumber(CNT_IDLE, timeleft)); }
                                self.idlekick_lasttimeleft = timeleft;
                        }
                }
  
        //CheckPlayerJump();
  
-       if(self.classname == "player") {
+       if(IS_PLAYER(self)) {
                CheckRules_Player();
                UpdateChatBubble();
                if (self.impulse)
                        return;         // intermission or finale
                GetPressedKeys();
        }
-       
  #ifdef TETRIS
        }
  #endif
        }
        */
  
-       //pointparticles(particleeffectnum("machinegun_impact"), self.origin + self.view_ofs + '0 0 7', '0 0 0', 1);
        if(self.waypointsprite_attachedforcarrier)
-               WaypointSprite_UpdateHealth(self.waypointsprite_attachedforcarrier, '1 0 0' * healtharmor_maxdamage(self.health, self.armorvalue, autocvar_g_balance_armor_blockpercent));
+               WaypointSprite_UpdateHealth(self.waypointsprite_attachedforcarrier, '1 0 0' * healtharmor_maxdamage(self.health, self.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON));
  
        playerdemo_write();
  
-       if((g_cts || g_race) && self.cvar_cl_allow_uidtracking == 1 && self.cvar_cl_allow_uid2name == 1)
-       {
-               if not(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)));
-       */
        CSQCMODEL_AUTOUPDATE();
  }
index b1bae14c18f04c672f8761d643b94ddc525dc10d,214083eaee9f32c080ad221512e3dfe39a28ba58..4eb2ae484a94d0de981f8ca35c43f8dabf6ecd0a
@@@ -33,7 -33,7 +33,7 @@@ float Nagger_SendEntity(entity to, floa
                if(to.vote_selection == 0)
                        nags |= 8;
        }
-       if(inWarmupStage)
+       if(warmup_stage)
                nags |= 16;
  
        if(sendflags & 64)
@@@ -43,7 -43,7 +43,7 @@@
                nags |= 128;
  
        if(!(nags & 4)) // no vote called? send no string
-               nags &~= (64 | 128);
+               nags &= ~(64 | 128);
  
        WriteByte(MSG_ENTITY, nags);
  
@@@ -63,7 -63,7 +63,7 @@@
                for(i = 1; i <= maxclients; i += 8)
                {
                        for(f = 0, e = edict_num(i), b = 1; b < 256; b *= 2, e = nextent(e))
-                               if(clienttype(e) != CLIENTTYPE_REAL || e.ready)
+                               if(!IS_REAL_CLIENT(e) || e.ready)
                                        f |= b;
                        WriteByte(MSG_ENTITY, f);
                }
@@@ -100,7 -100,7 +100,7 @@@ void Nagger_ReadyCounted(
  //  Game logic for voting
  // =======================
  
- void VoteReset() 
+ void VoteReset()
  {
        entity tmp_player;
  
        vote_called = VOTE_NULL;
        vote_caller = world;
        vote_endtime = 0;
-       
        vote_called_command = string_null;
        vote_called_display = string_null;
-       
        vote_parsed_command = string_null;
        vote_parsed_display = string_null;
  
        Nagger_VoteChanged();
  }
  
- void VoteStop(entity stopper) 
+ void VoteStop(entity stopper)
  {
        bprint("\{1}^2* ^3", GetCallerName(stopper), "^2 stopped ^3", GetCallerName(vote_caller), "^2's vote\n");
        if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vstop:", ftos(stopper.playerid))); }
-       
        // Don't force them to wait for next vote, this way they can e.g. correct their vote.
        if((vote_caller) && (stopper == vote_caller)) { vote_caller.vote_waittime = time + autocvar_sv_vote_stop; }
  
        VoteReset();
  }
  
- void VoteAccept() 
+ void VoteAccept()
  {
        bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ^1", vote_called_display, "^2 was accepted\n");
-       
        if((vote_called == VOTE_MASTER) && vote_caller)
                vote_caller.vote_master = 1;
        else
                localcmd(strcat(vote_called_command, "\n"));
-       
        if(vote_caller) { vote_caller.vote_waittime = 0; } // people like your votes, you don't need to wait to vote again
  
        VoteReset();
-       Announce("voteaccept");
+       Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_ACCEPT);
  }
  
- void VoteReject() 
+ void VoteReject()
  {
        bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ", vote_called_display, "^2 was rejected\n");
        VoteReset();
-       Announce("votefail");
+       Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_FAIL);
  }
  
- void VoteTimeout() 
+ void VoteTimeout()
  {
        bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ", vote_called_display, "^2 timed out\n");
        VoteReset();
-       Announce("votefail");
+       Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_FAIL);
  }
  
  void VoteSpam(float notvoters, float mincount, string result)
                ((mincount >= 0) ? strcat("^2 (^1", ftos(mincount), "^2 needed)") : "^2"),
                strcat(", ^1", ftos(vote_abstain_count), "^2 didn't care"),
                strcat(", ^1", ftos(notvoters), strcat("^2 didn't ", ((mincount >= 0) ? "" : "have to "), "vote\n"))));
-       
        if(autocvar_sv_eventlog)
        {
                GameLogEcho(strcat(
        }
  }
  
- void VoteCount(float first_count) 
+ void VoteCount(float first_count)
  {
        // declarations
        vote_accept_count = vote_reject_count = vote_abstain_count = 0;
-       
-       float spectators_allowed = ((autocvar_sv_vote_nospectators != 2) 
-                               || ((autocvar_sv_vote_nospectators == 1) && (inWarmupStage || gameover))
+       float spectators_allowed = ((autocvar_sv_vote_nospectators != 2)
+                               || ((autocvar_sv_vote_nospectators == 1) && (warmup_stage || gameover))
                                || (autocvar_sv_vote_nospectators == 0));
-                               
-       float vote_player_count = 0, is_player, notvoters = 0;
+       float vote_player_count = 0, notvoters = 0;
        float vote_real_player_count = 0, vote_real_accept_count = 0;
        float vote_real_reject_count = 0, vote_real_abstain_count = 0;
        float vote_needed_of_voted, final_needed_votes;
        float vote_factor_overall, vote_factor_of_voted;
-       
        entity tmp_player;
  
        Nagger_VoteCountChanged();
-       
        // add up all the votes from each connected client
        FOR_EACH_REALCLIENT(tmp_player)
        {
-               is_player = (tmp_player.classname == "player");
-               
                ++vote_player_count;
-               if(is_player) { ++vote_real_player_count; }
-               
+               if(IS_PLAYER(tmp_player)) { ++vote_real_player_count; }
                switch(tmp_player.vote_selection)
                {
-                       case VOTE_SELECT_REJECT: { ++vote_reject_count; { if(is_player) ++vote_real_reject_count; } break; }
-                       case VOTE_SELECT_ACCEPT: { ++vote_accept_count; { if(is_player) ++vote_real_reject_count; } break; }
-                       case VOTE_SELECT_ABSTAIN: { ++vote_abstain_count; { if(is_player) ++vote_real_abstain_count; } break; }
+                       case VOTE_SELECT_REJECT: { ++vote_reject_count; { if(IS_PLAYER(tmp_player)) ++vote_real_reject_count; } break; }
+                       case VOTE_SELECT_ACCEPT: { ++vote_accept_count; { if(IS_PLAYER(tmp_player)) ++vote_real_reject_count; } break; }
+                       case VOTE_SELECT_ABSTAIN: { ++vote_abstain_count; { if(IS_PLAYER(tmp_player)) ++vote_real_abstain_count; } break; }
                        default: break;
                }
        }
-       
        // Check to see if there are enough players on the server to allow master voting... otherwise, vote master could be used for evil.
-       if((vote_called == VOTE_MASTER) && autocvar_sv_vote_master_playerlimit > vote_player_count) 
+       if((vote_called == VOTE_MASTER) && autocvar_sv_vote_master_playerlimit > vote_player_count)
        {
                if(vote_caller) { vote_caller.vote_waittime = 0; }
                print_to(vote_caller, "^1There are not enough players on this server to allow you to become vote master.");
                VoteReset();
                return;
        }
-       
-       // if spectators aren't allowed to vote and there are players in a match, then only count the players in the vote and ignore spectators. 
+       // if spectators aren't allowed to vote and there are players in a match, then only count the players in the vote and ignore spectators.
        if(!spectators_allowed && (vote_real_player_count > 0))
        {
                vote_accept_count = vote_real_accept_count;
                vote_abstain_count = vote_real_abstain_count;
                vote_player_count = vote_real_player_count;
        }
-       
        // people who have no opinion in any way :D
        notvoters = (vote_player_count - vote_accept_count - vote_reject_count - vote_abstain_count);
  
        // determine the goal for the vote to be passed or rejected normally
        vote_factor_overall = bound(0.5, autocvar_sv_vote_majority_factor, 0.999);
        vote_needed_overall = floor((vote_player_count - vote_abstain_count) * vote_factor_overall) + 1;
-       
        // if the vote times out, determine the amount of votes needed of the people who actually already voted
        vote_factor_of_voted = bound(0.5, autocvar_sv_vote_majority_factor_of_voted, 0.999);
        vote_needed_of_voted = floor((vote_accept_count + vote_reject_count) * vote_factor_of_voted) + 1;
-       
        // are there any players at all on the server? it could be an admin vote
        if(vote_player_count == 0 && first_count)
        {
-               VoteSpam(0, -1, "yes"); // no players at all, just accept it 
+               VoteSpam(0, -1, "yes"); // no players at all, just accept it
                VoteAccept();
                return;
        }
-       
-       // since there ARE players, finally calculate the result of the vote    
+       // since there ARE players, finally calculate the result of the vote
        if(vote_accept_count >= vote_needed_overall)
        {
                VoteSpam(notvoters, -1, "yes"); // there is enough acceptions to pass the vote
                VoteAccept();
                return;
        }
-       
        if(vote_reject_count > vote_player_count - vote_abstain_count - vote_needed_overall)
        {
                VoteSpam(notvoters, -1, "no"); // there is enough rejections to deny the vote
                VoteReject();
                return;
        }
-       
        // there is not enough votes in either direction, now lets just calculate what the voters have said
        if(time > vote_endtime)
        {
                final_needed_votes = vote_needed_overall;
-               
                if(autocvar_sv_vote_majority_factor_of_voted)
                {
                        if(vote_accept_count >= vote_needed_of_voted)
                                VoteAccept();
                                return;
                        }
-                       
                        if(vote_accept_count + vote_reject_count > 0)
                        {
                                VoteSpam(notvoters, min(vote_needed_overall, vote_needed_of_voted), "no");
                                VoteReject();
                                return;
                        }
-                       
                        final_needed_votes = min(vote_needed_overall, vote_needed_of_voted);
                }
  
-               // it didn't pass or fail, so not enough votes to even make a decision. 
+               // it didn't pass or fail, so not enough votes to even make a decision.
                VoteSpam(notvoters, final_needed_votes, "timeout");
                VoteTimeout();
        }
  }
  
- void VoteThink() 
+ void VoteThink()
  {
        if(vote_endtime > 0) // a vote was called
        if(time > vote_endtime) // time is up
        {
                VoteCount(FALSE);
        }
-       
        return;
  }
  
  //  Game logic for warmup
  // =======================
  
+ // Resets the state of all clients, items, weapons, waypoints, ... of the map.
+ void reset_map(float dorespawn)
+ {
+       entity oldself;
+       oldself = self;
+       if(time <= game_starttime && round_handler_IsActive())
+               round_handler_Reset(game_starttime);
+       MUTATOR_CALLHOOK(reset_map_global);
+       for(self = world; (self = nextent(self)); )
+       if(IS_NOT_A_CLIENT(self))
+       {
+               if(self.reset)
+               {
+                       self.reset();
+                       continue;
+               }
+               if(self.team_saved)
+                       self.team = self.team_saved;
+               if(self.flags & FL_PROJECTILE) // remove any projectiles left
+                       remove(self);
+       }
+       // Waypoints and assault start come LAST
+       for(self = world; (self = nextent(self)); )
+       if(IS_NOT_A_CLIENT(self))
+       {
+               if(self.reset2)
+               {
+                       self.reset2();
+                       continue;
+               }
+       }
+       FOR_EACH_PLAYER(self)
+       if(self.frozen)
+               Unfreeze(self);
+       // Moving the player reset code here since the player-reset depends
+       // on spawnpoint entities which have to be reset first --blub
+       if(dorespawn)
+       if(!MUTATOR_CALLHOOK(reset_map_players))
+       FOR_EACH_CLIENT(self) // reset all players
+       {
+               /*
+               only reset players if a restart countdown is active
+               this can either be due to cvar sv_ready_restart_after_countdown having set
+               restart_mapalreadyrestarted to 1 after the countdown ended or when
+               sv_ready_restart_after_countdown is not used and countdown is still running
+               */
+               if (restart_mapalreadyrestarted || (time < game_starttime))
+               {
+                       //NEW: changed behaviour so that it prevents that previous spectators/observers suddenly spawn as players
+                       if (IS_PLAYER(self)) {
+                               //PlayerScore_Clear(self);
+                               self.killcount = 0;
+                               //stop the player from moving so that he stands still once he gets respawned
+                               self.velocity = '0 0 0';
+                               self.avelocity = '0 0 0';
+                               self.movement = '0 0 0';
+                               PutClientInServer();
+                       }
+               }
+       }
+       if(g_keyhunt)
+               kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round + (game_starttime - time), kh_StartRound);
+       self = oldself;
+ }
  // Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown is set)
- void ReadyRestart_think() 
+ void ReadyRestart_think()
  {
        restart_mapalreadyrestarted = 1;
        reset_map(TRUE);
        Score_ClearAll();
        remove(self);
-       
        return;
  }
  
@@@ -345,37 -418,35 +418,37 @@@ void ReadyRestart_force(
        checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = 0;
  
        readyrestart_happened = 1;
-       game_starttime = time;
-       if(!g_ca && !g_arena) { game_starttime += RESTART_COUNTDOWN; }
+       game_starttime = time + RESTART_COUNTDOWN;
  
-       // clear alivetime
+       // clear player attributes
        FOR_EACH_CLIENT(tmp_player)
        {
                tmp_player.alivetime = 0;
-               PlayerStats_Event(tmp_player, PLAYERSTATS_ALIVETIME, -PlayerStats_Event(tmp_player, PLAYERSTATS_ALIVETIME, 0));
+               tmp_player.killcount = 0;
+               PS_GR_P_ADDVAL(tmp_player, PLAYERSTATS_ALIVETIME, -PS_GR_P_ADDVAL(tmp_player, PLAYERSTATS_ALIVETIME, 0));
        }
  
        restart_mapalreadyrestarted = 0; // reset this var, needed when cvar sv_ready_restart_repeatable is in use
  
        // disable the warmup global for the server
-       inWarmupStage = 0; // once the game is restarted the game is in match stage
+       warmup_stage = 0; // once the game is restarted the game is in match stage
  
 +      Item_ItemsTime_Reset();
 +
        // reset the .ready status of all players (also spectators)
-       FOR_EACH_CLIENTSLOT(tmp_player) { tmp_player.ready = 0; }
+       FOR_EACH_REALCLIENT(tmp_player) { tmp_player.ready = 0; }
        readycount = 0;
        Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
  
        // lock teams with lockonrestart
-       if(autocvar_teamplay_lockonrestart && teamplay) 
+       if(autocvar_teamplay_lockonrestart && teamplay)
        {
                lockteams = 1;
                bprint("^1The teams are now locked.\n");
        }
  
        //initiate the restart-countdown-announcer entity
-       if(autocvar_sv_ready_restart_after_countdown && !g_ca && !g_arena)
+       if(autocvar_sv_ready_restart_after_countdown)
        {
                restart_timer = spawn();
                restart_timer.think = ReadyRestart_think;
        if(autocvar_sv_timeout) { FOR_EACH_REALPLAYER(tmp_player) { tmp_player.allowed_timeouts = autocvar_sv_timeout_number; } }
  
        //reset map immediately if this cvar is not set
-       if not(autocvar_sv_ready_restart_after_countdown) { reset_map(TRUE); }
+       if (!autocvar_sv_ready_restart_after_countdown) { reset_map(TRUE); }
  
        if(autocvar_sv_eventlog) { GameLogEcho(":restart"); }
  }
  void ReadyRestart()
  {
        // no arena, assault support yet...
-       if(g_arena | g_assault | gameover | intermission_running | race_completing)
+       if(g_assault | gameover | intermission_running | race_completing)
                localcmd("restart\n");
        else
                localcmd("\nsv_hook_gamerestart\n");
  
        // Reset ALL scores, but only do that at the beginning of the countdown if sv_ready_restart_after_countdown is off!
        // Otherwise scores could be manipulated during the countdown.
-       if not(autocvar_sv_ready_restart_after_countdown) { Score_ClearAll(); }
+       if (!autocvar_sv_ready_restart_after_countdown) { Score_ClearAll(); }
  
        ReadyRestart_force();
-       
        return;
  }
  
@@@ -415,10 -486,13 +488,13 @@@ void ReadyCount(
        float ready_needed_factor, ready_needed_count;
        float t_ready = 0, t_players = 0;
  
-       FOR_EACH_REALPLAYER(tmp_player)
+       FOR_EACH_REALCLIENT(tmp_player)
        {
-               ++t_players;
-               if(tmp_player.ready) { ++t_ready; }
+               if(IS_PLAYER(tmp_player) || tmp_player.caplayer == 1)
+               {
+                       ++t_players;
+                       if(tmp_player.ready) { ++t_ready; }
+               }
        }
  
        readycount = t_ready;
  
        ready_needed_factor = bound(0.5, cvar("g_warmup_majority_factor"), 0.999);
        ready_needed_count = floor(t_players * ready_needed_factor) + 1;
-       
        if(readycount >= ready_needed_count)
        {
                ReadyRestart();
        }
-               
        return;
  }
  
  float Votecommand_check_assignment(entity caller, float assignment)
  {
        float from_server = (!caller);
-       
-       if((assignment == VC_ASGNMNT_BOTH) 
-               || ((!from_server && assignment == VC_ASGNMNT_CLIENTONLY) 
+       if((assignment == VC_ASGNMNT_BOTH)
+               || ((!from_server && assignment == VC_ASGNMNT_CLIENTONLY)
                || (from_server && assignment == VC_ASGNMNT_SERVERONLY)))
        {
                return TRUE;
        return FALSE;
  }
  
- string VoteCommand_extractcommand(string input, float startpos, float argc) 
+ string VoteCommand_extractcommand(string input, float startpos, float argc)
  {
        string output;
-       
        if((argc - 1) < startpos)
                output = "";
        else
                output = substring(input, argv_start_index(startpos), argv_end_index(-1) - argv_start_index(startpos));
-               
        return output;
  }
  
@@@ -474,30 -548,30 +550,30 @@@ float VoteCommand_checknasty(string vot
                || (strstrofs(vote_command, "\r", 0) >= 0)
                || (strstrofs(vote_command, "$", 0) >= 0))
                return FALSE;
-               
        return TRUE;
  }
  
  float VoteCommand_checkinlist(string vote_command, string list)
  {
        string l = strcat(" ", list, " ");
-       
        if(strstrofs(l, strcat(" ", vote_command, " "), 0) >= 0)
                return TRUE;
-       
        return FALSE;
  }
  
  string ValidateMap(string validated_map, entity caller)
  {
        validated_map = MapInfo_FixName(validated_map);
-       
-       if not(validated_map)
+       if (!validated_map)
        {
                print_to(caller, "This map is not available on this server.");
                return string_null;
        }
-       
        if(!autocvar_sv_vote_override_mostrecent && caller)
        {
                if(Map_IsRecent(validated_map))
                        return string_null;
                }
        }
-       
        if(!MapInfo_CheckMap(validated_map))
        {
                print_to(caller, strcat("^1Invalid mapname, \"^3", validated_map, "^1\" does not support the current game mode."));
@@@ -593,13 -667,25 +669,25 @@@ float VoteCommand_checkargs(float start
  float VoteCommand_parse(entity caller, string vote_command, string vote_list, float startpos, float argc)
  {
        string first_command;
-       
        first_command = argv(startpos);
  
-       if not(VoteCommand_checkinlist(first_command, vote_list))
+       /*printf("VoteCommand_parse(): Command: '%s', Length: %f.\n",
+               substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos)),
+               strlen(substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos)))
+       );*/
+       if(
+               (autocvar_sv_vote_limit > 0)
+               &&
+               (strlen(substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos))) > autocvar_sv_vote_limit)
+       )
                return FALSE;
  
-       if not(VoteCommand_checkargs(startpos, argc))
+       if (!VoteCommand_checkinlist(first_command, vote_list))
+               return FALSE;
+       if (!VoteCommand_checkargs(startpos, argc))
                return FALSE;
  
        switch(first_command) // now go through and parse the proper commands to adjust as needed.
                {
                        entity victim = GetIndexedEntity(argc, (startpos + 1));
                        float accepted = VerifyClientEntity(victim, TRUE, FALSE);
-                       
                        if(accepted > 0)
                        {
-                               string reason = ((argc > next_token) ? substring(vote_command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token)) : "No reason provided");
+                               string reason = ((argc > next_token) ? substring(vote_command, argv_start_index(next_token), strlen(vote_command) - argv_start_index(next_token)) : "No reason provided");
                                string command_arguments;
-                               
                                if(first_command == "kickban")
                                        command_arguments = strcat(ftos(autocvar_g_ban_default_bantime), " ", ftos(autocvar_g_ban_default_masksize), " ~");
                                else
                                        command_arguments = reason;
-                               
                                vote_parsed_command = strcat(first_command, " # ", ftos(num_for_edict(victim)), " ", command_arguments);
                                vote_parsed_display = strcat("^1", vote_command, " (^7", victim.netname, "^1): ", reason);
                        }
                        else { print_to(caller, strcat("vcall: ", GetClientErrorString(accepted, argv(startpos + 1)), ".\n")); return FALSE; }
-                       
                        break;
                }
-               
                case "map":
                case "chmap":
                case "gotomap": // re-direct all map selection commands to gotomap
                {
                        vote_command = ValidateMap(argv(startpos + 1), caller);
-                       if not(vote_command) { return FALSE; }
+                       if (!vote_command) { return FALSE; }
                        vote_parsed_command = strcat("gotomap ", vote_command);
                        vote_parsed_display = strzone(strcat("^1", vote_parsed_command));
-                       
                        break;
                }
-               
-               default: 
-               { 
+               default:
+               {
                        vote_parsed_command = vote_command;
                        vote_parsed_display = strzone(strcat("^1", vote_command));
-                       
-                       break; 
+                       break;
                }
        }
  
@@@ -663,9 -749,9 +751,9 @@@ void VoteCommand_abstain(float request
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if not(vote_called) { print_to(caller, "^1No vote called."); }
-                       else if not(caller.vote_selection == VOTE_SELECT_NULL || autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
-                       
+                       if (!vote_called) { print_to(caller, "^1No vote called."); }
+                       else if(caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
                        else // everything went okay, continue changing vote
                        {
                                print_to(caller, "^1You abstained from your vote.");
                                msg_entity = caller;
                                if(!autocvar_sv_vote_singlecount) { VoteCount(FALSE); }
                        }
-                       
                        return;
                }
-                       
                default:
                case CMD_REQUEST_USAGE:
                {
@@@ -693,23 -779,23 +781,23 @@@ void VoteCommand_call(float request, en
        {
                case CMD_REQUEST_COMMAND:
                {
-                       float spectators_allowed = ((autocvar_sv_vote_nospectators != 2) 
-                               || ((autocvar_sv_vote_nospectators == 1) && inWarmupStage) 
+                       float spectators_allowed = ((autocvar_sv_vote_nospectators != 2)
+                               || ((autocvar_sv_vote_nospectators == 1) && warmup_stage)
                                || (autocvar_sv_vote_nospectators == 0));
-                               
                        float tmp_playercount = 0;
                        entity tmp_player;
-                       
                        vote_command = VoteCommand_extractcommand(vote_command, 2, argc);
-                       
-                       if not(autocvar_sv_vote_call || !caller) { print_to(caller, "^1Vote calling is not allowed."); }
+                       if(!autocvar_sv_vote_call && caller) { print_to(caller, "^1Vote calling is not allowed."); }
                        else if(!autocvar_sv_vote_gamestart && time < game_starttime) { print_to(caller, "^1Vote calling is not allowed before the match has started."); }
                        else if(vote_called) { print_to(caller, "^1There is already a vote called."); }
-                       else if(!spectators_allowed && (caller && (caller.classname != "player"))) { print_to(caller, "^1Only players can call a vote."); }
+                       else if(!spectators_allowed && (caller && !IS_PLAYER(caller))) { print_to(caller, "^1Only players can call a vote."); }
                        else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
                        else if(caller && (time < caller.vote_waittime)) { print_to(caller, strcat("^1You have to wait ^2", ftos(ceil(caller.vote_waittime - time)), "^1 seconds before you can again call a vote.")); }
-                       else if not(VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
-                       else if not(VoteCommand_parse(caller, vote_command, autocvar_sv_vote_commands, 2, argc)) { print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info."); }
+                       else if (!VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
+                       else if (!VoteCommand_parse(caller, vote_command, autocvar_sv_vote_commands, 2, argc)) { print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info."); }
  
                        else // everything went okay, continue with calling the vote
                        {
                                vote_called_command = strzone(vote_parsed_command);
                                vote_called_display = strzone(vote_parsed_display);
                                vote_endtime = time + autocvar_sv_vote_timeout;
-                               
                                if(caller)
                                {
                                        caller.vote_selection = VOTE_SELECT_ACCEPT;
                                        caller.vote_waittime = time + autocvar_sv_vote_wait;
                                        msg_entity = caller;
                                }
-                               
                                FOR_EACH_REALCLIENT(tmp_player) { ++tmp_playercount; }
-                               if(tmp_playercount > 1) { Announce("votecall"); } // don't announce a "vote now" sound if player is alone
-                               
+                               if(tmp_playercount > 1) { Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_CALL); } // don't announce a "vote now" sound if player is alone
                                bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2 calls a vote for ", vote_called_display, "\n");
                                if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }
                                Nagger_VoteChanged();
                                VoteCount(TRUE); // needed if you are the only one
                        }
-                       
                        return;
                }
-                       
                default:
                case CMD_REQUEST_USAGE:
                {
@@@ -763,11 -849,11 +851,11 @@@ void VoteCommand_master(float request, 
                                        case "do":
                                        {
                                                vote_command = VoteCommand_extractcommand(vote_command, 3, argc);
-                                               
-                                               if not(caller.vote_master) { print_to(caller, "^1You do not have vote master privelages."); }
-                                               else if not(VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
-                                               else if not(VoteCommand_parse(caller, vote_command, strcat(autocvar_sv_vote_commands, " ", autocvar_sv_vote_master_commands), 3, argc)) { print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info."); }
-                                               
+                                               if (!caller.vote_master) { print_to(caller, "^1You do not have vote master privelages."); }
+                                               else if (!VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
+                                               else if (!VoteCommand_parse(caller, vote_command, strcat(autocvar_sv_vote_commands, " ", autocvar_sv_vote_master_commands), 3, argc)) { print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info."); }
                                                else // everything went okay, proceed with command
                                                {
                                                        localcmd(strcat(vote_parsed_command, "\n"));
                                                        bprint("\{1}^2* ^3", GetCallerName(caller), "^2 used their ^3master^2 status to do \"^2", vote_parsed_display, "^2\".\n");
                                                        if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vdo:", ftos(caller.playerid), ":", vote_parsed_display)); }
                                                }
-                                               
                                                return;
                                        }
-                                       
                                        case "login":
                                        {
-                                               if not(autocvar_sv_vote_master_password != "") { print_to(caller, "^1Login to vote master is not allowed."); }
+                                               if(autocvar_sv_vote_master_password == "") { print_to(caller, "^1Login to vote master is not allowed."); }
                                                else if(caller.vote_master) { print_to(caller, "^1You are already logged in as vote master."); }
-                                               else if not(autocvar_sv_vote_master_password == argv(3)) { print_to(caller, strcat("Rejected vote master login from ", GetCallerName(caller))); }
+                                               else if(autocvar_sv_vote_master_password != argv(3)) { print_to(caller, strcat("Rejected vote master login from ", GetCallerName(caller))); }
  
                                                else // everything went okay, proceed with giving this player master privilages
                                                {
                                                        bprint("\{1}^2* ^3", GetCallerName(caller), "^2 logged in as ^3master^2\n");
                                                        if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vlogin:", ftos(caller.playerid))); }
                                                }
-                                               
                                                return;
                                        }
-                                       
                                        default: // calling a vote for master
                                        {
-                                               float spectators_allowed = ((autocvar_sv_vote_nospectators != 2) 
-                                                       || ((autocvar_sv_vote_nospectators == 1) && inWarmupStage) 
+                                               float spectators_allowed = ((autocvar_sv_vote_nospectators != 2)
+                                                       || ((autocvar_sv_vote_nospectators == 1) && warmup_stage)
                                                        || (autocvar_sv_vote_nospectators == 0));
-                                               
-                                               if not(autocvar_sv_vote_master_callable) { print_to(caller, "^1Vote to become vote master is not allowed."); }
+                                               if (!autocvar_sv_vote_master_callable) { print_to(caller, "^1Vote to become vote master is not allowed."); }
                                                else if(vote_called) { print_to(caller, "^1There is already a vote called."); }
-                                               else if(!spectators_allowed && (caller && (caller.classname != "player"))) { print_to(caller, "^1Only players can call a vote."); }
+                                               else if(!spectators_allowed && (caller && !IS_PLAYER(caller))) { print_to(caller, "^1Only players can call a vote."); }
                                                else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
-                                               
                                                else // everything went okay, continue with creating vote
                                                {
                                                        vote_caller = caller;
                                                        vote_called_command = strzone("XXX");
                                                        vote_called_display = strzone("^3master");
                                                        vote_endtime = time + autocvar_sv_vote_timeout;
-                                                       
                                                        caller.vote_selection = VOTE_SELECT_ACCEPT;
                                                        caller.vote_waittime = time + autocvar_sv_vote_wait;
-                                                       
                                                        bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2 calls a vote to become ^3master^2.\n");
                                                        if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }
                                                        Nagger_VoteChanged();
                                                        VoteCount(TRUE); // needed if you are the only one
                                                }
-                                               
                                                return;
                                        }
                                }
                        }
                        else { print_to(caller, "^1Master control of voting is not allowed."); }
-                       
                        return;
                }
-                       
                default:
                case CMD_REQUEST_USAGE:
                {
@@@ -850,10 -936,10 +938,10 @@@ void VoteCommand_no(float request, enti
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if not(vote_called) { print_to(caller, "^1No vote called."); }
-                       else if not(caller.vote_selection == VOTE_SELECT_NULL || autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
+                       if (!vote_called) { print_to(caller, "^1No vote called."); }
+                       else if(caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
                        else if(((caller == vote_caller) || caller.vote_master) && autocvar_sv_vote_no_stops_vote) { VoteStop(caller); }
-                       
                        else // everything went okay, continue changing vote
                        {
                                print_to(caller, "^1You rejected the vote.");
                                msg_entity = caller;
                                if(!autocvar_sv_vote_singlecount) { VoteCount(FALSE); }
                        }
-                       
                        return;
                }
-                       
                default:
                case CMD_REQUEST_USAGE:
                {
@@@ -885,10 -971,10 +973,10 @@@ void VoteCommand_status(float request, 
                                print_to(caller, strcat("^7Vote for ", vote_called_display, "^7 called by ^7", GetCallerName(vote_caller), "^7."));
                        else
                                print_to(caller, "^1No vote called.");
-                               
                        return;
                }
-                       
                default:
                case CMD_REQUEST_USAGE:
                {
@@@ -905,13 -991,13 +993,13 @@@ void VoteCommand_stop(float request, en
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if not(vote_called) { print_to(caller, "^1No vote called."); }
+                       if (!vote_called) { print_to(caller, "^1No vote called."); }
                        else if((caller == vote_caller) || !caller || caller.vote_master) { VoteStop(caller); }
                        else { print_to(caller, "^1You are not allowed to stop that vote."); }
-                       
                        return;
                }
-                       
                default:
                case CMD_REQUEST_USAGE:
                {
@@@ -928,9 -1014,9 +1016,9 @@@ void VoteCommand_yes(float request, ent
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if not(vote_called) { print_to(caller, "^1No vote called."); }
-                       else if not(caller.vote_selection == VOTE_SELECT_NULL || autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
-                       
+                       if (!vote_called) { print_to(caller, "^1No vote called."); }
+                       else if(caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
                        else // everything went okay, continue changing vote
                        {
                                print_to(caller, "^1You accepted the vote.");
                                msg_entity = caller;
                                if(!autocvar_sv_vote_singlecount) { VoteCount(FALSE); }
                        }
-                       
                        return;
                }
-                       
                default:
                case CMD_REQUEST_USAGE:
                {
@@@ -960,10 -1046,10 +1048,10 @@@ void VoteCommand_(float request
        {
                case CMD_REQUEST_COMMAND:
                {
-                       
                        return;
                }
-                       
                default:
                case CMD_REQUEST_USAGE:
                {
  void VoteCommand_macro_help(entity caller, float argc)
  {
        string command_origin = GetCommandPrefix(caller);
-       
-       if(argc == 2) // help display listing all commands
+       if(argc == 2 || argv(2) == "help") // help display listing all commands
        {
                print_to(caller, "\nVoting commands:\n");
                #define VOTE_COMMAND(name,function,description,assignment) \
                        { if(Votecommand_check_assignment(caller, assignment)) { print_to(caller, strcat("  ^2", name, "^7: ", description)); } }
-                       
                VOTE_COMMANDS(0, caller, 0, "")
                #undef VOTE_COMMAND
-               
                print_to(caller, strcat("\nUsage:^3 ", command_origin, " vote COMMAND...^7, where possible commands are listed above.\n"));
                print_to(caller, strcat("For help about a specific command, type ", command_origin, " vote help COMMAND"));
                print_to(caller, strcat("\n^7You can call a vote for or execute these commands: ^3", autocvar_sv_vote_commands, "^7 and maybe further ^3arguments^7"));
        {
                #define VOTE_COMMAND(name,function,description,assignment) \
                        { if(Votecommand_check_assignment(caller, assignment)) { if(name == strtolower(argv(2))) { function; return; } } }
-                       
                VOTE_COMMANDS(CMD_REQUEST_USAGE, caller, argc, "")
                #undef VOTE_COMMAND
        }
-       
        return;
  }
  
@@@ -1025,10 -1111,10 +1113,10 @@@ float VoteCommand_macro_command(entity 
  {
        #define VOTE_COMMAND(name,function,description,assignment) \
                { if(Votecommand_check_assignment(caller, assignment)) { if(name == strtolower(argv(1))) { function; return TRUE; } } }
-               
        VOTE_COMMANDS(CMD_REQUEST_COMMAND, caller, argc, vote_command)
        #undef VOTE_COMMAND
-       
        return FALSE;
  }
  
  //  Main function handling vote commands
  // ======================================
  
- void VoteCommand(float request, entity caller, float argc, string vote_command) 
+ void VoteCommand(float request, entity caller, float argc, string vote_command)
  {
        // Guide for working with argc arguments by example:
        // argc:   1    - 2      - 3     - 4
-       // argv:   0    - 1      - 2     - 3 
+       // argv:   0    - 1      - 2     - 3
        // cmd     vote - master - login - password
-       
        switch(request)
        {
                case CMD_REQUEST_COMMAND:
                        if(VoteCommand_macro_command(caller, argc, vote_command))
                                return;
                }
-                       
                default:
                        print_to(caller, strcat(((argv(1) != "") ? strcat("Unknown vote command \"", argv(1), "\"") : "No command provided"), ". For a list of supported commands, try ", GetCommandPrefix(caller), " vote help.\n"));
                case CMD_REQUEST_USAGE:
diff --combined qcsrc/server/defs.qh
index 5fec66259b82bf349c9eb406c11a98c588c6fc7f,757ee65e2799449c1afd71e68aaf2339596faada..8519c657a8d16ba5e1f9eb4337b2d5e51993f79a
@@@ -13,15 -13,15 +13,15 @@@ noref float require_spawnfunc_prefix; /
  #define BUTTON_USE        buttonuse
  #define BUTTON_DRAG       button8
  #define BUTTON_ZOOMSCRIPT button9
+ #define BUTTON_JETPACK    button10
  
  // Globals
  
- float g_cloaked, g_footsteps, g_jump_grunt, g_grappling_hook, g_midair, g_minstagib, g_pinata, g_norecoil, g_minstagib_invis_alpha, g_bloodloss;
+ float g_cloaked, g_footsteps, g_grappling_hook, g_instagib;
  float g_warmup_limit;
  float g_warmup_allguns;
  float g_warmup_allow_timeout;
- float g_race_qualifying;
- float inWarmupStage;
+ float warmup_stage;
  float g_pickup_respawntime_weapon;
  float g_pickup_respawntime_superweapon;
  float g_pickup_respawntime_ammo;
@@@ -46,9 -46,6 +46,6 @@@ entity        activator
  float player_count;
  float currentbots;
  float bots_would_leave;
- float lms_lowest_lives;
- float lms_next_place;
- float LMS_NewPlayerLives();
  
  void UpdateFrags(entity player, float f);
  .float totalfrags;
@@@ -58,7 -55,7 +55,7 @@@ float team1_score, team2_score, team3_s
  float maxclients;
  
  // flag set on worldspawn so that the code knows if it is dedicated or not
- float server_is_dedicated; 
+ float server_is_dedicated;
  
  // Fields
  
@@@ -76,7 -73,8 +73,8 @@@
  //.float      style;
  //.float      skill;
  .float        sounds;
- .float  platmovetype;
+ .string  platmovetype;
+ .float platmovetype_start, platmovetype_end;
  
  .string killtarget;
  
@@@ -85,7 -83,6 +83,6 @@@
  
  .float        pain_finished;                  //Added by Supajoe
  .float        pain_frame;                     //"
- .float        statdraintime;                  // record the one-second intervals between draining health and armour when they're over 100
  .float  crouch;       // Crouching or not?
  
  .float        strength_finished;
  //.float cnt2;
  
  .float play_time;
+ .float respawn_flags;
  .float respawn_time;
+ .float respawn_time_max;
  .float death_time;
  .float fade_time;
  .float fade_rate;
@@@ -134,7 -133,6 +133,7 @@@ void setanim(entity e, vector anim, flo
  
  .float species;
  
 +.float        scheduledrespawntime;
  .float        respawntime;
  .float        respawntimejitter;
  //.float      chasecam;
  .float                dmgtime;
  
  .float                killcount;
- .float hitsound, typehitsound;
+ .float damage_dealt, typehitsound;
  
  .float watersound_finished;
  .float iscreature;
  .string item_pickupsound;
  
  // definitions for weaponsystem
+ // more WEAPONTODO: move these to their proper files
  .entity weaponentity;
  .entity exteriorweaponentity;
  .vector weaponentity_glowmod;
  .float switchingweapon; // weapon currently being switched to (is copied from switchweapon once switch is possible)
  .string weaponname; // name of .weapon
  
+ // WEAPONTODO
  .float autoswitch;
float weapon_action(float wpn, float wrequest);
//float WEP_ACTION(float wpn, float wrequest);
  float client_hasweapon(entity cl, float wpn, float andammo, float complain);
  void w_clear();
  void w_ready();
  .float weapon_nextthink;
  .void() weapon_think;
  
- //float       PLAYER_WEAPONSELECTION_DELAY = );
- float PLAYER_WEAPONSELECTION_SPEED = 18;
- vector        PLAYER_WEAPONSELECTION_RANGE = '0 20 -40';
  
  // weapon states (self.weaponentity.state)
float WS_CLEAR                        = 0; // no weapon selected
float WS_RAISE                        = 1; // raise frame
float WS_DROP                 = 2; // deselecting frame
float WS_INUSE                        = 3; // fire state
float WS_READY                        = 4; // idle frame
const float WS_CLEAR                  = 0; // no weapon selected
const float WS_RAISE                  = 1; // raise frame
const float WS_DROP                   = 2; // deselecting frame
const float WS_INUSE                  = 3; // fire state
const float WS_READY                  = 4; // idle frame
  
  // there is 2 weapon tics that can run in one server frame
  #define W_TICSPERFRAME 2
@@@ -240,14 -236,12 +237,12 @@@ float game_completion_ratio; // 0 at st
  .float winning;
  .float jointime; // time of joining
  .float alivetime; // time of being alive
+ .float motd_actived_time; // used for both motd and campaign_message
  
  float nJoinAllowed(entity ignore);
- #define PREVENT_JOIN_TEXT "^1You may not join the game at this time.\n\nThe player limit reached maximum capacity."
  
  .float spawnshieldtime;
- .float lms_nextcheck;
- .float lms_traveled_distance;
+ .float item_spawnshieldtime;
  
  .entity flagcarried;
  
@@@ -267,6 -261,7 +262,7 @@@ float default_weapon_alpha
  .float cvar_cl_handicap;
  .float cvar_cl_clippedspectating;
  .float cvar_cl_autoscreenshot;
+ .float cvar_cl_jetpack_jump;
  .float cvar_cl_movement_track_canjump;
  .float cvar_cl_newusekeysupported;
  
  .float cvar_cl_allow_uidtracking;
  .string stored_netname;
  
- void Announce(string snd);
- void AnnounceTo(entity e, string snd);
  .float version_nagtime;
  
  #define NUM_JUMPPADSUSED 3
@@@ -295,17 -287,13 +288,13 @@@ string gamemode_name
  
  float startitem_failed;
  
- typedef .float floatfield;
- floatfield Item_CounterField(float it);
- float W_AmmoItemCode(float wpn);
- string W_Name(float weaponid);
  string W_Apply_Weaponreplace(string in);
  
  void FixIntermissionClient(entity e);
  void FixClientCvars(entity e);
  
- WEPSET_DECLARE_A(weaponsInMap);
+ // WEAPONTODO: remove this
+ WepSet weaponsInMap;
  
  .float respawn_countdown; // next number to count
  
@@@ -362,7 -350,6 +351,6 @@@ float next_pingtime
                _VOICEMSG(death) \
                _VOICEMSG(drown) \
                _VOICEMSG(fall) \
-               _VOICEMSG(fall) \
                _VOICEMSG(falling) \
                _VOICEMSG(gasp) \
                _VOICEMSG(jump) \
@@@ -450,8 -437,10 +438,10 @@@ string cvar_changes
  string cvar_purechanges;
  float cvar_purechanges_count;
  
- float game_starttime; //point in time when the countdown is over
+ float game_starttime; //point in time when the countdown to game start is over
+ float round_starttime; //point in time when the countdown to round start is over
  .float stat_game_starttime;
+ .float stat_round_starttime;
  
  .float stat_sv_airaccel_qw;
  .float stat_sv_airstrafeaccel_qw;
@@@ -464,8 -453,7 +454,7 @@@ void W_Porto_Remove (entity p)
  
  .string message2;
  
- vector railgun_start, railgun_end; // filled by FireRailgunBullet, used by damage code for head shot
- .float stat_allow_oldnexbeam;
+ .float stat_allow_oldvortexbeam;
  
  // reset to 0 on weapon switch
  // may be useful to all weapons
@@@ -477,10 -465,11 +466,11 @@@ void target_voicescript_clear(entity pl
  .string target2;
  .string target3;
  .string target4;
+ .string curvetarget;
  .float target_random;
  .float trigger_reverse;
  
- // Nexball 
+ // Nexball
  .entity ballcarried; // Also used for keepaway
  .float metertime;
  float g_nexball_meter_period;
@@@ -499,8 -488,6 +489,6 @@@ void ClientData_Touch(entity e)
  
  float servertime, serverprevtime, serverframetime;
  
- .entity soundentity;
  .float ammo_fuel;
  
  .vector prevorigin;
  .float stat_shotorg; // networked stat for trueaim HUD
  
  string matchid;
- .float hitplotfh;
  
  .float last_pickup;
  
- .float hit_time; 
- .float typehit_time; 
+ .float hit_time;
+ .float typehit_time;
+ .float damage_dealt_total; 
  
  .float stat_leadlimit;
  
@@@ -533,8 -521,6 +522,6 @@@ float client_cefc_accumulator
  float client_cefc_accumulatortime;
  #endif
  
- ..float current_ammo;
  .float weapon_load[WEP_MAXCOUNT];
  .float ammo_none; // used by the reloading system, must always be 0
  .float clip_load;
  
  .entity lastrocket;
  .float minelayer_mines;
- .float nex_charge;
- .float nex_charge_rottime;
- .float nex_chargepool_ammo;
+ .float vortex_charge;
+ .float vortex_charge_rottime;
+ .float vortex_chargepool_ammo;
  .float hagar_load;
  
  .float grab; // 0 = can't grab, 1 = owner can grab, 2 = owner and team mates can grab, 3 = anyone can grab
  
  .float spectatee_status;
  .float zoomstate;
- .float bloodloss_timer;
  .float restriction;
  
  .entity clientdata;
@@@ -566,9 -551,6 +552,6 @@@ string deathmessage
  
  .float just_joined;
  
- .float cvar_cl_accuracy_data_share;
- .float cvar_cl_accuracy_data_receive;
  .float cvar_cl_weaponimpulsemode;
  .float selectweapon; // last selected weapon of the player
  
  .void (float act_state) setactive;
  .entity realowner;
  
- float allowed_to_spawn; // boolean variable used by the clan arena code to determine if a player can spawn (after the round has ended)
 +.float item_armor_large_time;
 +.float item_health_mega_time;
 +.float item_invisible_time;
 +.float item_speed_time;
 +.float item_extralife_time;
 +.float item_strength_time;
 +.float item_shield_time;
 +.float item_fuelregen_time;
 +.float item_jetpack_time;
 +.float item_superweapons_time;
 +
  float serverflags;
  
  .float team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
  
  .float player_blocked;
+ .float weapon_blocked; // weapon use disabled
  
- .float freezetag_frozen;
- .float freezetag_revive_progress;
+ .float frozen; // for freeze attacks
+ .float revive_progress;
+ .float revival_time; // time at which player was last revived
+ .float revive_speed; // NOTE: multiplier (anything above 1 is instaheal)
+ .entity iceblock;
+ .entity frozen_by; // for ice fields
  
  .entity muzzle_flash;
  .float misc_bulletcounter;    // replaces uzi & hlac bullet counter.
@@@ -634,3 -609,12 +621,12 @@@ string modname
  #define MISSILE_IS_CONFUSABLE(m) ((m.missile_flags & MIF_GUIDED_CONFUSABLE) ? TRUE : FALSE)
  #define MISSILE_IS_GUIDED(m) ((m.missile_flags & MIF_GUIDED_ALL) ? TRUE : FALSE)
  #define MISSILE_IS_TRACKING(m) ((m.missile_flags & MIF_GUIDED_TRACKING) ? TRUE : FALSE)
+ ////
+ .entity player_stats;
+ //.float playerid;
+ .string playernick;
+ .float elos;
+ .float ranks;
diff --combined qcsrc/server/g_world.qc
index a485b71f0e9d5a3abbe1a25c66ed00d85fa95f89,0fd5d2de3c2eee8f0e2a8076f22ee753b6965992..0e990171ecffd003ca6fca7454fd57ba585a8dfe
@@@ -14,7 -14,7 +14,7 @@@ void PingPLReport_Think(
        self.nextthink = time + delta;
  
        e = edict_num(self.cnt + 1);
-       if(clienttype(e) == CLIENTTYPE_REAL)
+       if(IS_REAL_CLIENT(e))
        {
                WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
                WriteByte(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
@@@ -41,7 -41,7 +41,7 @@@
                WriteByte(MSG_BROADCAST, 0);
                WriteByte(MSG_BROADCAST, 0);
        }
-       self.cnt = mod(self.cnt + 1, maxclients);
+       self.cnt = (self.cnt + 1) % maxclients;
  }
  void PingPLReport_Spawn()
  {
        pingplreport.nextthink = time;
  }
  
- float SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS = 1;
const float SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS = 1;
  string redirection_target;
  float world_initialized;
  
- string GetMapname();
  string GetGametype();
  void GotoNextMap(float reinit);
  void ShuffleMaplist();
@@@ -82,32 -81,6 +81,6 @@@ void SetDefaultAlpha(
        }
  }
  
- void fteqcc_testbugs()
- {
-       float a, b;
-       if(!autocvar_developer_fteqccbugs)
-               return;
-       dprint("*** fteqcc test: checking for bugs...\n");
-       a = 1;
-       b = 5;
-       if(sqrt(a) - sqrt(b - a) == 0)
-               dprint("*** fteqcc test: found same-function-twice bug\n");
-       else
-               dprint("*** fteqcc test: same-function-twice bug got FINALLY FIXED! HOORAY!\n");
-       world.cnt = -10;
-       world.enemy = world;
-       world.enemy.cnt += 10;
-       if(world.cnt > 0.2 || world.cnt < -0.2) // don't error out if it's just roundoff errors
-               dprint("*** fteqcc test: found += bug\n");
-       else
-               dprint("*** fteqcc test: += bug got FINALLY FIXED! HOORAY!\n");
-       world.cnt = 0;
- }
  void GotoFirstMap()
  {
        float n;
@@@ -216,7 -189,6 +189,6 @@@ void cvar_changes_init(
                // private
                BADCVAR("developer");
                BADCVAR("log_dest_udp");
-               BADCVAR("log_file");
                BADCVAR("net_address");
                BADCVAR("net_address_ipv6");
                BADCVAR("port");
                BADPREFIX("g_playerstats_");
                BADPREFIX("g_respawn_ghosts");
                BADPREFIX("g_voice_flood_");
+               BADPREFIX("log_file");
                BADPREFIX("rcon_");
                BADPREFIX("sv_allowdownloads");
                BADPREFIX("sv_autodemo");
  
                // mapinfo
                BADCVAR("fraglimit");
-               BADCVAR("g_arena");
                BADCVAR("g_assault");
                BADCVAR("g_ca");
+               BADCVAR("g_ca_teams");
                BADCVAR("g_ctf");
                BADCVAR("g_cts");
                BADCVAR("g_dm");
                BADCVAR("g_domination");
                BADCVAR("g_domination_default_teams");
                BADCVAR("g_freezetag");
+               BADCVAR("g_freezetag_teams");
                BADCVAR("g_keepaway");
                BADCVAR("g_keyhunt");
                BADCVAR("g_keyhunt_teams");
-               BADCVAR("g_keyhunt_teams");
                BADCVAR("g_lms");
                BADCVAR("g_nexball");
                BADCVAR("g_onslaught");
  
                // does nothing visible
                BADCVAR("captureleadlimit_override");
-               BADCVAR("g_arena_point_leadlimit");
                BADCVAR("g_balance_kill_delay");
                BADCVAR("g_ca_point_leadlimit");
                BADCVAR("g_ctf_captimerecord_always");
                BADCVAR("sv_fraginfo");
                BADCVAR("sv_timeout");
                BADPREFIX("sv_timeout_");
-               BADCVAR("welcome_message_time");
                BADPREFIX("crypto_");
                BADPREFIX("g_chat_");
                BADPREFIX("g_ctf_captimerecord_");
                BADCVAR("g_balance_teams_scorefactor");
                BADCVAR("g_ban_sync_trusted_servers");
                BADCVAR("g_ban_sync_uri");
+               BADCVAR("g_ca_teams_override");
                BADCVAR("g_ctf_ignore_frags");
                BADCVAR("g_domination_point_limit");
+               BADCVAR("g_freezetag_teams_override");
                BADCVAR("g_friendlyfire");
                BADCVAR("g_fullbrightitems");
                BADCVAR("g_fullbrightplayers");
                BADCVAR("sv_vote_master_commands");
                BADCVAR("sv_vote_master_password");
                BADCVAR("sv_vote_simple_majority_factor");
-               BADCVAR("sys_ticrate");
                BADCVAR("teamplay_mode");
                BADCVAR("timelimit_override");
                BADCVAR("g_spawnshieldtime");
                BADPREFIX("sv_ready_restart_");
  
                // mutators that announce themselves properly to the server browser
-               BADCVAR("g_minstagib");
+               BADCVAR("g_instagib");
                BADCVAR("g_new_toys");
                BADCVAR("g_nix");
+               BADCVAR("g_grappling_hook");
+               BADCVAR("g_jetpack");
  
-               if(autocvar_g_minstagib)
-               {
-                       BADCVAR("g_grappling_hook");
-                       BADCVAR("g_jetpack");
-               }
  #undef BADPREFIX
  #undef BADCVAR
  
@@@ -546,9 -515,11 +515,11 @@@ void spawnfunc___init_dedicated_server(
  
        // needs to be done so early because of the constants they create
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
+       CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
        CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
        CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
        CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
+       CALL_ACCUMULATED_FUNCTION(RegisterBuffs);
  
        MapInfo_Enumerate();
        MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
  void Map_MarkAsRecent(string m);
  float world_already_spawned;
  void Nagger_Init();
 +void Item_ItemsTime_Init();
  void ClientInit_Spawn();
  void WeaponStats_Init();
  void WeaponStats_Shutdown();
  void spawnfunc_worldspawn (void)
  {
        float fd, l, i, j, n;
-       string s, col;
+       string s;
  
        cvar = cvar_normal;
        cvar_string = cvar_string_normal;
  
        remove = remove_safely; // during spawning, watch what you remove!
  
-       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;
        entity head;
        head = nextent(world);
        maxclients = 0;
  
        // needs to be done so early because of the constants they create
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
+       CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
        CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
        CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
        CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
+       CALL_ACCUMULATED_FUNCTION(RegisterBuffs);
  
        ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid));
  
  
        Map_MarkAsRecent(mapname);
  
-       PlayerStats_Init(); // we need this to be initiated before InitGameplayMode
+       PlayerStats_GameReport_Init(); // we need this to be initiated before InitGameplayMode
  
        precache_model ("null"); // we need this one before InitGameplayMode
        InitGameplayMode();
        readlevelcvars();
        GrappleHookInit();
-       ElectroInit();
-       LaserInit();
  
        player_count = 0;
        bot_waypoints_for_items = autocvar_g_waypoints_for_items;
                if(autocvar_g_norecoil)
                        s = strcat(s, ":norecoil");
  
-               // TODO to mutator system
-               if(autocvar_g_midair)
-                       s = strcat(s, ":midair");
-               // TODO to mutator system
-               if(autocvar_g_minstagib)
-                       s = strcat(s, ":minstagib");
                // TODO to mutator system
                if(autocvar_g_powerups == 0)
                        s = strcat(s, ":no_powerups");
        if(autocvar_g_campaign)
                CampaignPostInit();
  
-       fteqcc_testbugs();
        Ban_LoadBans();
  
        MapInfo_Enumerate();
  
        WeaponStats_Init();
  
-       WEPSET_ADDSTAT();
+       WepSet_AddStat();
        addstat(STAT_SWITCHWEAPON, AS_INT, switchweapon);
        addstat(STAT_SWITCHINGWEAPON, AS_INT, switchingweapon);
        addstat(STAT_GAMESTARTTIME, AS_FLOAT, stat_game_starttime);
-       addstat(STAT_ALLOW_OLDNEXBEAM, AS_INT, stat_allow_oldnexbeam);
+       addstat(STAT_ROUNDSTARTTIME, AS_FLOAT, stat_round_starttime);
+       addstat(STAT_ALLOW_OLDVORTEXBEAM, AS_INT, stat_allow_oldvortexbeam);
        Nagger_Init();
  
        addstat(STAT_STRENGTH_FINISHED, AS_FLOAT, strength_finished);
        addstat(STAT_SUPERWEAPONS_FINISHED, AS_FLOAT, superweapons_finished);
        addstat(STAT_PRESSED_KEYS, AS_FLOAT, pressedkeys);
        addstat(STAT_FUEL, AS_INT, ammo_fuel);
+       addstat(STAT_PLASMA, AS_INT, ammo_plasma);
        addstat(STAT_SHOTORG, AS_INT, stat_shotorg);
        addstat(STAT_LEADLIMIT, AS_FLOAT, stat_leadlimit);
        addstat(STAT_WEAPON_CLIPLOAD, AS_INT, clip_load);
        addstat(STAT_WEAPON_CLIPSIZE, AS_INT, clip_size);
        addstat(STAT_LAST_PICKUP, AS_FLOAT, last_pickup);
        addstat(STAT_HIT_TIME, AS_FLOAT, hit_time);
+       addstat(STAT_DAMAGE_DEALT_TOTAL, AS_INT, damage_dealt_total);
        addstat(STAT_TYPEHIT_TIME, AS_FLOAT, typehit_time);
        addstat(STAT_LAYED_MINES, AS_INT, minelayer_mines);
  
-       addstat(STAT_NEX_CHARGE, AS_FLOAT, nex_charge);
-       addstat(STAT_NEX_CHARGEPOOL, AS_FLOAT, nex_chargepool_ammo);
+       addstat(STAT_VORTEX_CHARGE, AS_FLOAT, vortex_charge);
+       addstat(STAT_VORTEX_CHARGEPOOL, AS_FLOAT, vortex_chargepool_ammo);
  
        addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load);
+       
+       addstat(STAT_ARC_HEAT, AS_FLOAT, arc_heat_percent);
  
-       if(g_ca || g_freezetag)
-       {
-               addstat(STAT_REDALIVE, AS_INT, redalive_stat);
-               addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
-               addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat);
-               addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat);
-       }
-       if(g_freezetag)
-       {
-               addstat(STAT_FROZEN, AS_INT, freezetag_frozen);
-               addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
-       }
++      // items time
 +      addstat(STAT_ARMOR_LARGE_TIME, AS_FLOAT, item_armor_large_time);
 +      addstat(STAT_HEALTH_MEGA_TIME, AS_FLOAT, item_health_mega_time);
 +      addstat(STAT_INVISIBLE_TIME, AS_FLOAT, item_invisible_time);
 +      addstat(STAT_SPEED_TIME, AS_FLOAT, item_speed_time);
 +      addstat(STAT_EXTRALIFE_TIME, AS_FLOAT, item_extralife_time);
 +      addstat(STAT_STRENGTH_TIME, AS_FLOAT, item_strength_time);
 +      addstat(STAT_SHIELD_TIME, AS_FLOAT, item_shield_time);
 +      addstat(STAT_FUELREGEN_TIME, AS_FLOAT, item_fuelregen_time);
 +      addstat(STAT_JETPACK_TIME, AS_FLOAT, item_jetpack_time);
 +      addstat(STAT_SUPERWEAPONS_TIME, AS_FLOAT, item_superweapons_time);
 +      Item_ItemsTime_Init();
 +
+       // freeze attacks
+       addstat(STAT_FROZEN, AS_INT, frozen);
+       addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, revive_progress);
  
        // g_movementspeed hack
        addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw);
        addstat(STAT_SECRETS_TOTAL, AS_FLOAT, stat_secrets_total);
        addstat(STAT_SECRETS_FOUND, AS_FLOAT, stat_secrets_found);
  
+       // monsters
+       addstat(STAT_MONSTERS_TOTAL, AS_FLOAT, stat_monsters_total);
+       addstat(STAT_MONSTERS_KILLED, AS_FLOAT, stat_monsters_killed);
        // misc
        addstat(STAT_RESPAWN_TIME, AS_FLOAT, stat_respawn_time);
  
        detect_maptype();
  
        // set up information replies for clients and server to use
-       lsmaps_reply = "^7Maps available: ";
-       lsnewmaps_reply = "^7Maps without a record set: ";
-       for(i = 0, j = 0; i < MapInfo_count; ++i)
-       {
-               if(MapInfo_Get_ByID(i))
-                       if not(MapInfo_Map_flags & MapInfo_ForbiddenFlags())
-                       {
-                               if(mod(i, 2))
-                                       col = "^2";
-                               else
-                                       col = "^3";
-                               ++j;
-                               lsmaps_reply = strcat(lsmaps_reply, col, MapInfo_Map_bspname, " ");
-                               if(g_race && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time"))))
-                                       lsnewmaps_reply = strcat(lsnewmaps_reply, col, MapInfo_Map_bspname, " ");
-                               else if(g_cts && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time"))))
-                                       lsnewmaps_reply = strcat(lsnewmaps_reply, col, MapInfo_Map_bspname, " ");
-                       }
-       }
-       lsmaps_reply = strzone(strcat(lsmaps_reply, "\n"));
-       lsnewmaps_reply = strzone(strcat(((!g_race && !g_cts) ? "Need to be playing race or CTS for lsnewmaps to work." : lsnewmaps_reply), "\n"));
-       maplist_reply = "^7Maps in list: ";
-       n = tokenize_console(autocvar_g_maplist);
-       for(i = 0, j = 0; i < n; ++i)
-       {
-               if(MapInfo_CheckMap(argv(i)))
-               {
-                       if(mod(j, 2))
-                               col = "^2";
-                       else
-                               col = "^3";
-                       maplist_reply = strcat(maplist_reply, col, argv(i), " ");
-                       ++j;
-               }
-       }
-       maplist_reply = strzone(strcat(maplist_reply, "\n"));
-       MapInfo_ClearTemps();
+       maplist_reply = strzone(getmaplist());
+       lsmaps_reply = strzone(getlsmaps());
+       monsterlist_reply = strzone(getmonsterlist());
        for(i = 0; i < 10; ++i)
        {
                s = getrecords(i);
                if (s)
                        records_reply[i] = strzone(s);
        }
        ladder_reply = strzone(getladder());
        rankings_reply = strzone(getrankings());
  
        // begin other init
                s = "";
                n = tokenize_console(cvar_string("sv_curl_serverpackages"));
                for(i = 0; i < n; ++i)
-                       if(substring(argv(i), -14, -1) != "-serverpackage.txt")
+                       if(substring(argv(i), -18, -1) != "-serverpackage.txt")
                        if(substring(argv(i), -14, -1) != ".serverpackage") // OLD legacy
                                s = strcat(s, " ", argv(i));
                fd = search_begin("*-serverpackage.txt", TRUE, FALSE);
                modname = cvar_string("g_mod_balance");
        if(cvar_string("g_mod_config") != cvar_defstring("g_mod_config"))
                modname = cvar_string("g_mod_config");
-       // weird mutators that deserve to count as mod
-       if(autocvar_g_minstagib)
-               modname = "MinstaGib";
        // extra mutators that deserve to count as mod
        MUTATOR_CALLHOOK(SetModname);
  
@@@ -974,7 -873,6 +887,6 @@@ string GetGametype(
        return MapInfo_Type_ToString(MapInfo_LoadedGametype);
  }
  
- string getmapname_stored;
  string GetMapname()
  {
        return mapname;
@@@ -1131,12 -1029,14 +1043,14 @@@ float() MaplistMethod_Iterate = // usua
  {
        float pass, i;
  
+       dprint("Trying MaplistMethod_Iterate\n");
        for(pass = 1; pass <= 2; ++pass)
        {
                for(i = 1; i < Map_Count; ++i)
                {
                        float mapindex;
-                       mapindex = mod(i + Map_Current, Map_Count);
+                       mapindex = (i + Map_Current) % Map_Count;
                        if(Map_Check(mapindex, pass))
                                return mapindex;
                }
  
  float() MaplistMethod_Repeat = // fallback method
  {
+       dprint("Trying MaplistMethod_Repeat\n");
        if(Map_Check(Map_Current, 2))
                return Map_Current;
        return -2;
@@@ -1155,12 -1057,14 +1071,14 @@@ float() MaplistMethod_Random = // rando
  {
        float i, imax;
  
+       dprint("Trying MaplistMethod_Random\n");
        imax = 42;
  
        for(i = 0; i <= imax; ++i)
        {
                float mapindex;
-               mapindex = mod(Map_Current + floor(random() * (Map_Count - 1) + 1), Map_Count); // any OTHER map
+               mapindex = (Map_Current + floor(random() * (Map_Count - 1) + 1)) % Map_Count; // any OTHER map
                if(Map_Check(mapindex, 1))
                        return mapindex;
        }
@@@ -1173,6 -1077,8 +1091,8 @@@ float(float exponent) MaplistMethod_Shu
  {
        float i, j, imax, insertpos;
  
+       dprint("Trying MaplistMethod_Shuffle\n");
        imax = 42;
  
        for(i = 0; i <= imax; ++i)
  void Maplist_Init()
  {
        Map_Count = tokenizebyseparator(autocvar_g_maplist, " ");
-       if(Map_Count == 0)
+       float i;
+       for (i = 0; i < Map_Count; ++i)
+               if (Map_Check(i, 2))
+                       break;
+       if (i == Map_Count)
        {
-               bprint( "Maplist is empty!  Resetting it to default map list.\n" );
-               cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
+               bprint( "Maplist contains no usable maps!  Resetting it to default map list.\n" );
+               cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags() | MAPINFO_FLAG_NOAUTOMAPLIST));
                if(autocvar_g_maplist_shuffle)
                        ShuffleMaplist();
                localcmd("\nmenu_cmd sync\n");
@@@ -1287,13 -1197,27 +1211,27 @@@ float DoNextMapOverride(float reinit
                return TRUE;
        }
        if(autocvar_nextmap != "")
-               if(MapInfo_CheckMap(autocvar_nextmap))
+       {
+               string m;
+               m = GameTypeVote_MapInfo_FixName(autocvar_nextmap);
+               cvar_set("nextmap",m);
+       
+               if(!m || gametypevote)
+                       return FALSE;
+               if(autocvar_sv_vote_gametype)
+               {
+                       Map_Goto_SetStr(m);
+                       return FALSE;
+               }
+               
+               if(MapInfo_CheckMap(m))
                {
-                       Map_Goto_SetStr(autocvar_nextmap);
+                       Map_Goto_SetStr(m);
                        Map_Goto(reinit);
                        alreadychangedlevel = TRUE;
                        return TRUE;
                }
+       }
        if(!reinit && autocvar_lastlevel)
        {
                cvar_settemp_restore();
@@@ -1313,31 -1237,12 +1251,12 @@@ void GotoNextMap(float reinit
                return;
        alreadychangedlevel = TRUE;
  
-       {
-               string nextMap;
-               float allowReset;
-               for(allowReset = 1; allowReset >= 0; --allowReset)
-               {
-                       nextMap = GetNextMap();
-                       if(nextMap != "")
-                               break;
+       string nextMap;
  
-                       if(allowReset)
-                       {
-                               bprint( "Maplist contains no single playable map!  Resetting it to default map list.\n" );
-                               cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
-                               if(autocvar_g_maplist_shuffle)
-                                       ShuffleMaplist();
-                               localcmd("\nmenu_cmd sync\n");
-                       }
-                       else
-                       {
-                               error("Everything is broken - not even the default map list works. Please report this to the developers.");
-                       }
-               }
-               Map_Goto(reinit);
-       }
+       nextMap = GetNextMap();
+       if(nextMap == "")
+               error("Everything is broken - cannot find a next map. Please report this to the developers.");
+       Map_Goto(reinit);
  }
  
  
@@@ -1349,9 -1254,6 +1268,6 @@@ When the player presses attack or jump
  ============
  */
  .float autoscreenshot;
- void() MapVote_Start;
- void() MapVote_Think;
- float mapvote_initialized;
  void IntermissionThink()
  {
        FixIntermissionClient(self);
                && ((self.autoscreenshot > 0) && (time > self.autoscreenshot)) )
        {
                self.autoscreenshot = -1;
-               if(clienttype(self) == CLIENTTYPE_REAL) { stuffcmd(self, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"", GetMapname(), strftime(FALSE, "%s"))); }
+               if(IS_REAL_CLIENT(self)) { stuffcmd(self, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"\n", GetMapname(), strftime(FALSE, "%s"))); }
                return;
        }
  
@@@ -1487,11 -1389,11 +1403,11 @@@ void DumpStats(float final
  
        FOR_EACH_CLIENT(other)
        {
-               if ((clienttype(other) == CLIENTTYPE_REAL) || (clienttype(other) == CLIENTTYPE_BOT && autocvar_sv_logscores_bots))
+               if ((IS_REAL_CLIENT(other)) || (IS_BOT_CLIENT(other) && autocvar_sv_logscores_bots))
                {
                        s = strcat(":player:see-labels:", GetPlayerScoreString(other, 0), ":");
                        s = strcat(s, ftos(rint(time - other.jointime)), ":");
-                       if(other.classname == "player" || g_arena || g_ca || g_lms)
+                       if(IS_PLAYER(other) || other.caplayer == 1 || g_lms)
                                s = strcat(s, ftos(other.team), ":");
                        else
                                s = strcat(s, "spectator:");
@@@ -1556,7 -1458,7 +1472,7 @@@ void FixIntermissionClient(entity e
                        if (e.weaponentity.weaponentity)
                                e.weaponentity.weaponentity.effects = EF_NODRAW;
                }
-               if(clienttype(e) == CLIENTTYPE_REAL)
+               if(IS_REAL_CLIENT(e))
                {
                        stuffcmd(e, "\nscr_printspeed 1000000\n");
                        s = autocvar_sv_intermission_cdtrack;
        }
  }
  
- void minstagib_stop_countdown(entity e);
  /*
  go to the next level for deathmatch
  only called if a time or frag limit has expired
@@@ -1599,11 -1500,7 +1514,7 @@@ void NextLevel(
        DumpStats(TRUE);
  
        // send statistics
-       entity e;
-       PlayerStats_EndMatch(1);
-       FOR_EACH_CLIENT(e)
-               PlayerStats_AddGlobalInfo(e);
-       PlayerStats_Shutdown();
+       PlayerStats_GameReport(TRUE);
        WeaponStats_Shutdown();
  
        Kill_Notification(NOTIF_ALL, world, MSG_CENTER, 0); // kill all centerprints now
        GameLogClose();
  
        FOR_EACH_PLAYER(other) {
-               minstagib_stop_countdown(other);
                FixIntermissionClient(other);
                if(other.winning)
                        bprint(other.netname, " ^7wins.\n");
@@@ -1652,10 -1548,10 +1562,10 @@@ float checkrules_suddendeathwarning
  float checkrules_suddendeathend;
  float checkrules_overtimesadded; //how many overtimes have been already added
  
- float WINNING_NO = 0; // no winner, but time limits may terminate the game
- float WINNING_YES = 1; // winner found
- float WINNING_NEVER = 2; // no winner, enter overtime if time limit is reached
- float WINNING_STARTSUDDENDEATHOVERTIME = 3; // no winner, enter suddendeath overtime NOW
const float WINNING_NO = 0; // no winner, but time limits may terminate the game
const float WINNING_YES = 1; // winner found
const float WINNING_NEVER = 2; // no winner, enter overtime if time limit is reached
const float WINNING_STARTSUDDENDEATHOVERTIME = 3; // no winner, enter suddendeath overtime NOW
  
  float InitiateSuddenDeath()
  {
        // - for this timelimit_overtime needs to be >0 of course
        // - also check the winning condition calculated in the previous frame and only add normal overtime
        //   again, if at the point at which timelimit would be extended again, still no winner was found
-       if (!autocvar_g_campaign && (checkrules_overtimesadded >= 0) && (checkrules_overtimesadded < autocvar_timelimit_overtimes) && autocvar_timelimit_overtime && !(g_race && !g_race_qualifying))
+       if (!autocvar_g_campaign && (checkrules_overtimesadded >= 0) && (checkrules_overtimesadded < autocvar_timelimit_overtimes || autocvar_timelimit_overtimes < 0) && autocvar_timelimit_overtime && !(g_race && !g_race_qualifying))
        {
                return 1; // need to call InitiateOvertime later
        }
@@@ -1691,7 -1587,7 +1601,7 @@@ void InitiateOvertime() // ONLY call th
        tl += autocvar_timelimit_overtime;
        cvar_set("timelimit", ftos(tl));
  
-       Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime);
+       Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60);
  }
  
  float GetWinningCode(float fraglimitreached, float equality)
@@@ -1749,7 -1645,7 +1659,7 @@@ float WinningCondition_Onslaught(
  
        WinningConditionHelper(); // set worldstatus
  
-       if(inWarmupStage)
+       if(warmup_stage)
                return WINNING_NO;
  
        // first check if the game has ended
        return WINNING_NO;
  }
  
- float LMS_NewPlayerLives()
- {
-       float fl;
-       fl = autocvar_fraglimit;
-       if(fl == 0)
-               fl = 999;
-       // first player has left the game for dying too much? Nobody else can get in.
-       if(lms_lowest_lives < 1)
-               return 0;
-       if(!autocvar_g_lms_join_anytime)
-               if(lms_lowest_lives < fl - autocvar_g_lms_last_join)
-                       return 0;
-       return bound(1, lms_lowest_lives, fl);
- }
  // Assault winning condition: If the attackers triggered a round end (by fulfilling all objectives)
  // they win. Otherwise the defending team wins once the timelimit passes.
  void assault_new_round();
@@@ -1965,7 -1843,7 +1857,7 @@@ float WinningCondition_Scores(float lim
        if(WinningConditionHelper_zeroisworst)
                leadlimit = 0; // not supported in this mode
  
-       if(g_dm || g_tdm || g_arena || g_ca || (g_race && !g_race_qualifying) || g_nexball)
+       if(g_dm || g_tdm || g_ca || g_freezetag || (g_race && !g_race_qualifying) || g_nexball)
        // these modes always score in increments of 1, thus this makes sense
        {
                if(leaderfrags != WinningConditionHelper_topscore)
  
                        if (limit)
                        if (leaderfrags == limit - 1)
-                               Announce("1fragleft");
+                               Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_REMAINING_FRAG_1);
                        else if (leaderfrags == limit - 2)
-                               Announce("2fragsleft");
+                               Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_REMAINING_FRAG_2);
                        else if (leaderfrags == limit - 3)
-                               Announce("3fragsleft");
+                               Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_REMAINING_FRAG_3);
                }
        }
  
@@@ -2136,17 -2014,6 +2028,6 @@@ void CheckRules_World(
  
        SetDefaultAlpha();
  
-       /*
-       MapVote_Think should now do that part
-       if (intermission_running)
-               if (time >= intermission_exittime + 60)
-               {
-                       if(!DoNextMapOverride())
-                               GotoNextMap();
-                       return;
-               }
-       */
        if (gameover)   // someone else quit the game already
        {
                if(player_count == 0) // Nobody there? Then let's go to the next map
        fraglimit = autocvar_fraglimit;
        leadlimit = autocvar_leadlimit;
  
-       if(inWarmupStage || time <= game_starttime) // NOTE: this is <= to prevent problems in the very tic where the game starts
+       if(warmup_stage || time <= game_starttime) // NOTE: this is <= to prevent problems in the very tic where the game starts
        {
                if(timelimit > 0)
                        timelimit = 0; // timelimit is not made for warmup
        }
  }
  
- float mapvote_nextthink;
- float mapvote_initialized;
- float mapvote_keeptwotime;
- float mapvote_timeout;
- string mapvote_message;
- #define MAPVOTE_SCREENSHOT_DIRS_COUNT 4
- string mapvote_screenshot_dirs[MAPVOTE_SCREENSHOT_DIRS_COUNT];
- float mapvote_screenshot_dirs_count;
- float mapvote_count;
- float mapvote_count_real;
- string mapvote_maps[MAPVOTE_COUNT];
- float mapvote_maps_screenshot_dir[MAPVOTE_COUNT];
- string mapvote_maps_pakfile[MAPVOTE_COUNT];
- float mapvote_maps_suggested[MAPVOTE_COUNT];
- string mapvote_suggestions[MAPVOTE_COUNT];
- float mapvote_suggestion_ptr;
- float mapvote_voters;
- float mapvote_selections[MAPVOTE_COUNT];
- float mapvote_run;
- float mapvote_detail;
- float mapvote_abstain;
- .float mapvote;
- void MapVote_ClearAllVotes()
- {
-       FOR_EACH_CLIENT(other)
-               other.mapvote = 0;
- }
- string MapVote_Suggest(string m)
+ string GotoMap(string m)
  {
-       float i;
-       if(m == "")
-               return "That's not how to use this command.";
-       if(!autocvar_g_maplist_votable_suggestions)
-               return "Suggestions are not accepted on this server.";
-       if(mapvote_initialized)
-               return "Can't suggest - voting is already in progress!";
-       m = MapInfo_FixName(m);
-       if not(m)
+       m = GameTypeVote_MapInfo_FixName(m);
+       if (!m)
                return "The map you suggested is not available on this server.";
-       if(!autocvar_g_maplist_votable_suggestions_override_mostrecent)
-               if(Map_IsRecent(m))
-                       return "This server does not allow for recent maps to be played again. Please be patient for some rounds.";
+       if (!autocvar_sv_vote_gametype)
        if(!MapInfo_CheckMap(m))
                return "The map you suggested does not support the current game mode.";
-       for(i = 0; i < mapvote_suggestion_ptr; ++i)
-               if(mapvote_suggestions[i] == m)
-                       return "This map was already suggested.";
-       if(mapvote_suggestion_ptr >= MAPVOTE_COUNT)
-       {
-               i = floor(random() * mapvote_suggestion_ptr);
-       }
-       else
-       {
-               i = mapvote_suggestion_ptr;
-               mapvote_suggestion_ptr += 1;
-       }
-       if(mapvote_suggestions[i] != "")
-               strunzone(mapvote_suggestions[i]);
-       mapvote_suggestions[i] = strzone(m);
-       if(autocvar_sv_eventlog)
-               GameLogEcho(strcat(":vote:suggested:", m, ":", ftos(self.playerid)));
-       return strcat("Suggestion of ", m, " accepted.");
- }
- void MapVote_AddVotable(string nextMap, float isSuggestion)
- {
-       float j, i, o;
-       string pakfile, mapfile;
-       if(nextMap == "")
-               return;
-       for(j = 0; j < mapvote_count; ++j)
-               if(mapvote_maps[j] == nextMap)
-                       return;
-       // suggestions might be no longer valid/allowed after gametype switch!
-       if(isSuggestion)
-               if(!MapInfo_CheckMap(nextMap))
-                       return;
-       mapvote_maps[mapvote_count] = strzone(nextMap);
-       mapvote_maps_suggested[mapvote_count] = isSuggestion;
-       pakfile = string_null;
-       for(i = 0; i < mapvote_screenshot_dirs_count; ++i)
-       {
-               mapfile = strcat(mapvote_screenshot_dirs[i], "/", mapvote_maps[i]);
-               pakfile = whichpack(strcat(mapfile, ".tga"));
-               if(pakfile == "")
-                       pakfile = whichpack(strcat(mapfile, ".jpg"));
-               if(pakfile == "")
-                       pakfile = whichpack(strcat(mapfile, ".png"));
-               if(pakfile != "")
-                       break;
-       }
-       if(i >= mapvote_screenshot_dirs_count)
-               i = 0; // FIXME maybe network this error case, as that means there is no mapshot on the server?
-       for(o = strstr(pakfile, "/", 0)+1; o > 0; o = strstr(pakfile, "/", 0)+1)
-               pakfile = substring(pakfile, o, -1);
-       mapvote_maps_screenshot_dir[mapvote_count] = i;
-       mapvote_maps_pakfile[mapvote_count] = strzone(pakfile);
-       mapvote_count += 1;
- }
- void MapVote_Spawn();
- void MapVote_Init()
- {
-       float i;
-       float nmax, smax;
-       MapVote_ClearAllVotes();
-       mapvote_count = 0;
-       mapvote_detail = !autocvar_g_maplist_votable_nodetail;
-       mapvote_abstain = autocvar_g_maplist_votable_abstain;
-       if(mapvote_abstain)
-               nmax = min(MAPVOTE_COUNT - 1, autocvar_g_maplist_votable);
-       else
-               nmax = min(MAPVOTE_COUNT, autocvar_g_maplist_votable);
-       smax = min3(nmax, autocvar_g_maplist_votable_suggestions, mapvote_suggestion_ptr);
-       // we need this for AddVotable, as that cycles through the screenshot dirs
-       mapvote_screenshot_dirs_count = tokenize_console(autocvar_g_maplist_votable_screenshot_dir);
-       if(mapvote_screenshot_dirs_count == 0)
-               mapvote_screenshot_dirs_count = tokenize_console("maps levelshots");
-       mapvote_screenshot_dirs_count = min(mapvote_screenshot_dirs_count, MAPVOTE_SCREENSHOT_DIRS_COUNT);
-       for(i = 0; i < mapvote_screenshot_dirs_count; ++i)
-               mapvote_screenshot_dirs[i] = strzone(argv(i));
-       if(mapvote_suggestion_ptr)
-               for(i = 0; i < 100 && mapvote_count < smax; ++i)
-                       MapVote_AddVotable(mapvote_suggestions[floor(random() * mapvote_suggestion_ptr)], TRUE);
-       for(i = 0; i < 100 && mapvote_count < nmax; ++i)
-               MapVote_AddVotable(GetNextMap(), FALSE);
-       if(mapvote_count == 0)
-       {
-               bprint( "Maplist contains no single playable map!  Resetting it to default map list.\n" );
-               cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
-               if(autocvar_g_maplist_shuffle)
-                       ShuffleMaplist();
-               localcmd("\nmenu_cmd sync\n");
-               for(i = 0; i < 100 && mapvote_count < nmax; ++i)
-                       MapVote_AddVotable(GetNextMap(), FALSE);
-       }
-       mapvote_count_real = mapvote_count;
-       if(mapvote_abstain)
-               MapVote_AddVotable("don't care", 0);
-       //dprint("mapvote count is ", ftos(mapvote_count), "\n");
-       mapvote_keeptwotime = time + autocvar_g_maplist_votable_keeptwotime;
-       mapvote_timeout = time + autocvar_g_maplist_votable_timeout;
-       if(mapvote_count_real < 3 || mapvote_keeptwotime <= time)
-               mapvote_keeptwotime = 0;
-       mapvote_message = "Choose a map and press its key!";
-       MapVote_Spawn();
- }
- void MapVote_SendPicture(float id)
- {
-       msg_entity = self;
-       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-       WriteByte(MSG_ONE, TE_CSQC_PICTURE);
-       WriteByte(MSG_ONE, id);
-       WritePicture(MSG_ONE, strcat(mapvote_screenshot_dirs[mapvote_maps_screenshot_dir[id]], "/", mapvote_maps[id]), 3072);
- }
- float MapVote_GetMapMask()
- {
-       float mask, i, power;
-       mask = 0;
-       for(i = 0, power = 1; i < mapvote_count; ++i, power *= 2)
-               if(mapvote_maps[i] != "")
-                       mask |= power;
-       return mask;
- }
- entity mapvote_ent;
- float MapVote_SendEntity(entity to, float sf)
- {
-       float i;
-       if(sf & 1)
-               sf &~= 2; // if we send 1, we don't need to also send 2
-       WriteByte(MSG_ENTITY, ENT_CLIENT_MAPVOTE);
-       WriteByte(MSG_ENTITY, sf);
-       if(sf & 1)
-       {
-               // flag 1 == initialization
-               for(i = 0; i < mapvote_screenshot_dirs_count; ++i)
-                       WriteString(MSG_ENTITY, mapvote_screenshot_dirs[i]);
-               WriteString(MSG_ENTITY, "");
-               WriteByte(MSG_ENTITY, mapvote_count);
-               WriteByte(MSG_ENTITY, mapvote_abstain);
-               WriteByte(MSG_ENTITY, mapvote_detail);
-               WriteCoord(MSG_ENTITY, mapvote_timeout);
-               if(mapvote_count <= 8)
-                       WriteByte(MSG_ENTITY, MapVote_GetMapMask());
-               else
-                       WriteShort(MSG_ENTITY, MapVote_GetMapMask());
-               for(i = 0; i < mapvote_count; ++i)
-                       if(mapvote_maps[i] != "")
-                       {
-                               if(mapvote_abstain && i == mapvote_count - 1)
-                               {
-                                       WriteString(MSG_ENTITY, ""); // abstain needs no text
-                                       WriteString(MSG_ENTITY, ""); // abstain needs no pack
-                                       WriteByte(MSG_ENTITY, 0); // abstain needs no screenshot dir
-                               }
-                               else
-                               {
-                                       WriteString(MSG_ENTITY, mapvote_maps[i]);
-                                       WriteString(MSG_ENTITY, mapvote_maps_pakfile[i]);
-                                       WriteByte(MSG_ENTITY, mapvote_maps_screenshot_dir[i]);
-                               }
-                       }
-       }
-       if(sf & 2)
-       {
-               // flag 2 == update of mask
-               if(mapvote_count <= 8)
-                       WriteByte(MSG_ENTITY, MapVote_GetMapMask());
-               else
-                       WriteShort(MSG_ENTITY, MapVote_GetMapMask());
-       }
-       if(sf & 4)
-       {
-               if(mapvote_detail)
-                       for(i = 0; i < mapvote_count; ++i)
-                               if(mapvote_maps[i] != "")
-                                       WriteByte(MSG_ENTITY, mapvote_selections[i]);
-               WriteByte(MSG_ENTITY, to.mapvote);
-       }
-       return TRUE;
- }
- void MapVote_Spawn()
- {
-       Net_LinkEntity(mapvote_ent = spawn(), FALSE, 0, MapVote_SendEntity);
- }
- void MapVote_TouchMask()
- {
-       mapvote_ent.SendFlags |= 2;
- }
- void MapVote_TouchVotes(entity voter)
- {
-       mapvote_ent.SendFlags |= 4;
- }
- float MapVote_Finished(float mappos)
- {
-       string result;
-       float i;
-       float didntvote;
-       if(autocvar_sv_eventlog)
-       {
-               result = strcat(":vote:finished:", mapvote_maps[mappos]);
-               result = strcat(result, ":", ftos(mapvote_selections[mappos]), "::");
-               didntvote = mapvote_voters;
-               for(i = 0; i < mapvote_count; ++i)
-                       if(mapvote_maps[i] != "")
-                       {
-                               didntvote -= mapvote_selections[i];
-                               if(i != mappos)
-                               {
-                                       result = strcat(result, ":", mapvote_maps[i]);
-                                       result = strcat(result, ":", ftos(mapvote_selections[i]));
-                               }
-                       }
-               result = strcat(result, ":didn't vote:", ftos(didntvote));
-               GameLogEcho(result);
-               if(mapvote_maps_suggested[mappos])
-                       GameLogEcho(strcat(":vote:suggestion_accepted:", mapvote_maps[mappos]));
-       }
-       FOR_EACH_REALCLIENT(other)
-               FixClientCvars(other);
-       Map_Goto_SetStr(mapvote_maps[mappos]);
-       Map_Goto(0);
-       alreadychangedlevel = TRUE;
-       return TRUE;
- }
- void MapVote_CheckRules_1()
- {
-       float i;
-       for(i = 0; i < mapvote_count; ++i) if(mapvote_maps[i] != "")
-       {
-               //dprint("Map ", ftos(i), ": "); dprint(mapvote_maps[i], "\n");
-               mapvote_selections[i] = 0;
-       }
-       mapvote_voters = 0;
-       FOR_EACH_REALCLIENT(other)
-       {
-               ++mapvote_voters;
-               if(other.mapvote)
-               {
-                       i = other.mapvote - 1;
-                       //dprint("Player ", other.netname, " vote = ", ftos(other.mapvote - 1), "\n");
-                       mapvote_selections[i] = mapvote_selections[i] + 1;
-               }
-       }
- }
- float MapVote_CheckRules_2()
- {
-       float i;
-       float firstPlace, secondPlace;
-       float firstPlaceVotes, secondPlaceVotes;
-       float mapvote_voters_real;
-       string result;
-       if(mapvote_count_real == 1)
-               return MapVote_Finished(0);
-       mapvote_voters_real = mapvote_voters;
-       if(mapvote_abstain)
-               mapvote_voters_real -= mapvote_selections[mapvote_count - 1];
-       RandomSelection_Init();
-       for(i = 0; i < mapvote_count_real; ++i) if(mapvote_maps[i] != "")
-               RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
-       firstPlace = RandomSelection_chosen_float;
-       firstPlaceVotes = RandomSelection_best_priority;
-       //dprint("First place: ", ftos(firstPlace), "\n");
-       //dprint("First place votes: ", ftos(firstPlaceVotes), "\n");
-       RandomSelection_Init();
-       for(i = 0; i < mapvote_count_real; ++i) if(mapvote_maps[i] != "")
-               if(i != firstPlace)
-                       RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]);
-       secondPlace = RandomSelection_chosen_float;
-       secondPlaceVotes = RandomSelection_best_priority;
-       //dprint("Second place: ", ftos(secondPlace), "\n");
-       //dprint("Second place votes: ", ftos(secondPlaceVotes), "\n");
-       if(firstPlace == -1)
-               error("No first place in map vote... WTF?");
-       if(secondPlace == -1 || time > mapvote_timeout || (mapvote_voters_real - firstPlaceVotes) < firstPlaceVotes)
-               return MapVote_Finished(firstPlace);
-       if(mapvote_keeptwotime)
-               if(time > mapvote_keeptwotime || (mapvote_voters_real - firstPlaceVotes - secondPlaceVotes) < secondPlaceVotes)
-               {
-                       float didntvote;
-                       MapVote_TouchMask();
-                       mapvote_message = "Now decide between the TOP TWO!";
-                       mapvote_keeptwotime = 0;
-                       result = strcat(":vote:keeptwo:", mapvote_maps[firstPlace]);
-                       result = strcat(result, ":", ftos(firstPlaceVotes));
-                       result = strcat(result, ":", mapvote_maps[secondPlace]);
-                       result = strcat(result, ":", ftos(secondPlaceVotes), "::");
-                       didntvote = mapvote_voters;
-                       for(i = 0; i < mapvote_count; ++i)
-                               if(mapvote_maps[i] != "")
-                               {
-                                       didntvote -= mapvote_selections[i];
-                                       if(i != firstPlace)
-                                               if(i != secondPlace)
-                                               {
-                                                       result = strcat(result, ":", mapvote_maps[i]);
-                                                       result = strcat(result, ":", ftos(mapvote_selections[i]));
-                                                       if(i < mapvote_count_real)
-                                                       {
-                                                               strunzone(mapvote_maps[i]);
-                                                               mapvote_maps[i] = "";
-                                                               strunzone(mapvote_maps_pakfile[i]);
-                                                               mapvote_maps_pakfile[i] = "";
-                                                       }
-                                               }
-                               }
-                       result = strcat(result, ":didn't vote:", ftos(didntvote));
-                       if(autocvar_sv_eventlog)
-                               GameLogEcho(result);
-               }
-       return FALSE;
- }
- void MapVote_Tick()
- {
-       float keeptwo;
-       float totalvotes;
-       keeptwo = mapvote_keeptwotime;
-       MapVote_CheckRules_1(); // count
-       if(MapVote_CheckRules_2()) // decide
-               return;
-       totalvotes = 0;
-       FOR_EACH_REALCLIENT(other)
-       {
-               // hide scoreboard again
-               if(other.health != 2342)
-               {
-                       other.health = 2342;
-                       other.impulse = 0;
-                       if(clienttype(other) == CLIENTTYPE_REAL)
-                       {
-                               msg_entity = other;
-                               WriteByte(MSG_ONE, SVC_FINALE);
-                               WriteString(MSG_ONE, "");
-                       }
-               }
-               // clear possibly invalid votes
-               if(mapvote_maps[other.mapvote - 1] == "")
-                       other.mapvote = 0;
-               // use impulses as new vote
-               if(other.impulse >= 1 && other.impulse <= mapvote_count)
-                       if(mapvote_maps[other.impulse - 1] != "")
-                       {
-                               other.mapvote = other.impulse;
-                               MapVote_TouchVotes(other);
-                       }
-               other.impulse = 0;
-               if(other.mapvote)
-                       ++totalvotes;
-       }
-       MapVote_CheckRules_1(); // just count
- }
- void MapVote_Start()
- {
-       if(mapvote_run)
-               return;
-       // wait for stats to be sent first
-       if(!playerstats_waitforme)
-               return;
-       MapInfo_Enumerate();
-       if(MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1))
-               mapvote_run = TRUE;
- }
- void MapVote_Think()
- {
-       if(!mapvote_run)
-               return;
-       if(alreadychangedlevel)
-               return;
-       if(time < mapvote_nextthink)
-               return;
-       //dprint("tick\n");
-       mapvote_nextthink = time + 0.5;
-       if(!mapvote_initialized)
-       {
-               if(autocvar_rescan_pending == 1)
-               {
-                       cvar_set("rescan_pending", "2");
-                       localcmd("fs_rescan\nrescan_pending 3\n");
-                       return;
-               }
-               else if(autocvar_rescan_pending == 2)
-               {
-                       return;
-               }
-               else if(autocvar_rescan_pending == 3)
-               {
-                       // now build missing mapinfo files
-                       if(!MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1))
-                               return;
-                       // we're done, start the timer
-                       cvar_set("rescan_pending", "0");
-               }
-               mapvote_initialized = TRUE;
-               if(DoNextMapOverride(0))
-                       return;
-               if(!autocvar_g_maplist_votable || player_count <= 0)
-               {
-                       GotoNextMap(0);
-                       return;
-               }
-               MapVote_Init();
-       }
-       MapVote_Tick();
- }
- string GotoMap(string m)
- {
-       if(!MapInfo_CheckMap(m))
-               return "The map you chose is not available on this server.";
        cvar_set("nextmap", m);
        cvar_set("timelimit", "-1");
        if(mapvote_initialized || alreadychangedlevel)
  
  void EndFrame()
  {
+       anticheat_endframe();
        float altime;
        FOR_EACH_REALCLIENT(self)
        {
-               if(self.classname == "spectator")
-               {
-                       if(self.enemy.typehitsound)
-                               self.typehit_time = time;
-                       else if(self.enemy.hitsound)
-                               self.hit_time = time;
-               }
-               else
+               entity e = IS_SPEC(self) ? self.enemy : self;
+               if(e.typehitsound)
+                       self.typehit_time = time;
+               else if(e.damage_dealt)
                {
-                       if(self.typehitsound)
-                               self.typehit_time = time;
-                       else if(self.hitsound)
-                               self.hit_time = time;
+                       self.hit_time = time;
+                       self.damage_dealt_total += ceil(e.damage_dealt);
                }
        }
        altime = time + frametime * (1 + autocvar_g_antilag_nudge);
        // needed!
        FOR_EACH_CLIENT(self)
        {
-               self.hitsound = FALSE;
                self.typehitsound = FALSE;
+               self.damage_dealt = 0;
                antilag_record(self, altime);
        }
+       FOR_EACH_MONSTER(self)
+               antilag_record(self, altime);
  }
  
  
@@@ -2936,8 -2298,6 +2312,6 @@@ void RestoreGame(
  
  void Shutdown()
  {
-       entity e;
        gameover = 2;
  
        if(world_initialized > 0)
                print("Saving persistent data...\n");
                Ban_SaveBans();
  
-               PlayerStats_EndMatch(0);
-               FOR_EACH_CLIENT(e)
-                       PlayerStats_AddGlobalInfo(e);
-               PlayerStats_Shutdown();
+               // playerstats with unfinished match
+               PlayerStats_GameReport(FALSE);
  
                if(!cheatcount_total)
                {
diff --combined qcsrc/server/t_items.qc
index 766c4ae1c9ea8fba330daa8da171ea333014b133,4455d3fb46a3128ecf541c8d4558286341eb8a4e..c1094e44329164716728f5b1521147c17b1999cf
@@@ -1,64 -1,36 +1,36 @@@
- #define ISF_LOCATION 2
- #define ISF_MODEL    4
- #define ISF_STATUS   8
-     #define ITS_STAYWEP   1
-     #define ITS_ANIMATE1  2
-     #define ITS_ANIMATE2  4
-     #define ITS_AVAILABLE 8
-     #define ITS_ALLOWFB   16
-     #define ITS_ALLOWSI   32
-     #define ITS_POWERUP   64
- #define ISF_COLORMAP 16
- #define ISF_DROP 32
- #define ISF_ANGLES 64
- .float ItemStatus;
  #ifdef CSQC
- var float  autocvar_cl_animate_items = 1;
- var float  autocvar_cl_ghost_items = 0.45;
- var vector autocvar_cl_ghost_items_color = '-1 -1 -1';
- var float  autocvar_cl_fullbright_items = 0;
- var vector autocvar_cl_weapon_stay_color = '2 0.5 0.5';
- var float  autocvar_cl_weapon_stay_alpha = 0.75;
- var float  autocvar_cl_simple_items = 0;
- var string autocvr_cl_simpleitems_postfix = "_simple";
- .float  spawntime;
- .float  gravity;
- .vector colormod;
  void ItemDraw()
- {    
+ {
      if(self.gravity)
-     {        
+     {
          Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
-         if(self.move_flags & FL_ONGROUND) 
+         if(self.move_flags & FL_ONGROUND)
          { // For some reason move_avelocity gets set to '0 0 0' here ...
              self.oldorigin = self.origin;
              self.gravity = 0;
  
-             if(autocvar_cl_animate_items)   
-             { // ... so reset it if animations are requested. 
+             if(autocvar_cl_animate_items)
+             { // ... so reset it if animations are requested.
                  if(self.ItemStatus & ITS_ANIMATE1)
                      self.move_avelocity = '0 180 0';
-                 
                  if(self.ItemStatus & ITS_ANIMATE2)
                      self.move_avelocity = '0 -90 0';
              }
          }
      }
      else if (autocvar_cl_animate_items)
-     {        
+     {
          if(self.ItemStatus & ITS_ANIMATE1)
          {
              self.angles += self.move_avelocity * frametime;
-             setorigin(self, '0 0 10' + self.oldorigin + '0 0 8' * sin(time * 2));        
-         }    
-         
+             setorigin(self, '0 0 10' + self.oldorigin + '0 0 8' * sin(time * 2));
+         }
          if(self.ItemStatus & ITS_ANIMATE2)
          {
              self.angles += self.move_avelocity * frametime;
-             setorigin(self, '0 0 8' + self.oldorigin + '0 0 4' * sin(time * 3));        
+             setorigin(self, '0 0 8' + self.oldorigin + '0 0 4' * sin(time * 3));
          }
      }
  }
@@@ -66,9 -38,9 +38,9 @@@
  void ItemDrawSimple()
  {
      if(self.gravity)
-     {        
-         Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);    
-         
+     {
+         Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
          if(self.move_flags & FL_ONGROUND)
              self.gravity = 0;
      }
@@@ -86,19 -58,30 +58,30 @@@ void ItemRead(float _IsNew
          setorigin(self, self.origin);
          self.oldorigin = self.origin;
      }
-     
-     if(sf & ISF_ANGLES) 
+     if(sf & ISF_ANGLES)
      {
          self.angles_x = ReadCoord();
          self.angles_y = ReadCoord();
-         self.angles_z = ReadCoord();        
+         self.angles_z = ReadCoord();
          self.move_angles = self.angles;
      }
-     
+     if(sf & ISF_SIZE)
+     {
+         self.mins_x = ReadCoord();
+         self.mins_y = ReadCoord();
+         self.mins_z = ReadCoord();
+         self.maxs_x = ReadCoord();
+         self.maxs_y = ReadCoord();
+         self.maxs_z = ReadCoord();
+         setsize(self, self.mins, self.maxs);
+     }
      if(sf & ISF_STATUS) // need to read/write status frist so model can handle simple, fb etc.
      {
-         self.ItemStatus = ReadByte();    
-         
+         self.ItemStatus = ReadByte();
          if(self.ItemStatus & ITS_AVAILABLE)
          {
              self.alpha = 1;
              }
              else
                  self.alpha = -1;
-         }    
-         
+         }
          if(autocvar_cl_fullbright_items)
              if(self.ItemStatus & ITS_ALLOWFB)
                  self.effects |= EF_FULLBRIGHT;
-             
          if(self.ItemStatus & ITS_STAYWEP)
          {
              self.colormod = self.glowmod = autocvar_cl_weapon_stay_color;
              self.alpha = autocvar_cl_weapon_stay_alpha;
-             
          }
-         
          if(self.ItemStatus & ITS_POWERUP)
          {
              if(self.ItemStatus & ITS_AVAILABLE)
                  self.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
              else
-                  self.effects &~= (EF_ADDITIVE | EF_FULLBRIGHT);
+                  self.effects &= ~(EF_ADDITIVE | EF_FULLBRIGHT);
          }
      }
-     
      if(sf & ISF_MODEL)
      {
          self.drawmask  = MASK_NORMAL;
-         self.movetype  = MOVETYPE_NOCLIP;
+         self.movetype  = MOVETYPE_TOSS;
          self.draw       = ItemDraw;
-         
          if(self.mdl)
              strunzone(self.mdl);
-         
          self.mdl = "";
          string _fn = ReadString();
-         
          if(autocvar_cl_simple_items && (self.ItemStatus & ITS_ALLOWSI))
          {
              string _fn2 = substring(_fn, 0 , strlen(_fn) -4);
              self.draw = ItemDrawSimple;
-                     
-             
-             
-             if(fexists(sprintf("%s%s.md3", _fn2, autocvr_cl_simpleitems_postfix)))
-                 self.mdl = strzone(sprintf("%s%s.md3", _fn2, autocvr_cl_simpleitems_postfix));
-             else if(fexists(sprintf("%s%s.dpm", _fn2, autocvr_cl_simpleitems_postfix)))
-                 self.mdl = strzone(sprintf("%s%s.dpm", _fn2, autocvr_cl_simpleitems_postfix));
-             else if(fexists(sprintf("%s%s.iqm", _fn2, autocvr_cl_simpleitems_postfix)))
-                 self.mdl = strzone(sprintf("%s%s.iqm", _fn2, autocvr_cl_simpleitems_postfix));
-             else if(fexists(sprintf("%s%s.obj", _fn2, autocvr_cl_simpleitems_postfix)))
-                 self.mdl = strzone(sprintf("%s%s.obj", _fn2, autocvr_cl_simpleitems_postfix));
+             if(fexists(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix)))
+                 self.mdl = strzone(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix));
+             else if(fexists(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix)))
+                 self.mdl = strzone(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix));
+             else if(fexists(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix)))
+                 self.mdl = strzone(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix));
+             else if(fexists(sprintf("%s%s.obj", _fn2, autocvar_cl_simpleitems_postfix)))
+                 self.mdl = strzone(sprintf("%s%s.obj", _fn2, autocvar_cl_simpleitems_postfix));
              else
              {
                  self.draw = ItemDraw;
                  dprint("Simple item requested for ", _fn, " but no model exsist for it\n");
              }
          }
-         
-         if(self.draw != ItemDrawSimple)        
-             self.mdl = strzone(_fn);                
-         
-         
+         if(self.draw != ItemDrawSimple)
+             self.mdl = strzone(_fn);
          if(self.mdl == "")
              dprint("^1WARNING!^7 self.mdl is unset for item ", self.classname, " tell tZork aboute this!\n");
-         
          precache_model(self.mdl);
          setmodel(self, self.mdl);
      }
-     
      if(sf & ISF_COLORMAP)
          self.colormap = ReadShort();
-     
      if(sf & ISF_DROP)
      {
          self.gravity = 1;
-         self.move_angles = '0 0 0';
+         //self.move_angles = '0 0 0';
          self.move_movetype = MOVETYPE_TOSS;
          self.move_velocity_x = ReadCoord();
          self.move_velocity_y = ReadCoord();
          self.move_velocity_z = ReadCoord();
          self.velocity = self.move_velocity;
          self.move_origin = self.oldorigin;
-         
          if(!self.move_time)
          {
              self.move_time = time;
          else
              self.move_time = max(self.move_time, time);
      }
-         
      if(autocvar_cl_animate_items)
-     {        
+     {
          if(self.ItemStatus & ITS_ANIMATE1)
              self.move_avelocity = '0 180 0';
-                 
          if(self.ItemStatus & ITS_ANIMATE2)
              self.move_avelocity = '0 -90 0';
      }
  #endif
  
  #ifdef SVQC
- float autocvar_sv_simple_items;
  float ItemSend(entity to, float sf)
  {
      if(self.gravity)
          sf |= ISF_DROP;
      else
-         sf &~= ISF_DROP;
-       
-       WriteByte(MSG_ENTITY, ENT_CLIENT_ITEM); 
+         sf &= ~ISF_DROP;
+       WriteByte(MSG_ENTITY, ENT_CLIENT_ITEM);
        WriteByte(MSG_ENTITY, sf);
  
        //WriteByte(MSG_ENTITY, self.cnt);
          WriteCoord(MSG_ENTITY, self.origin_y);
          WriteCoord(MSG_ENTITY, self.origin_z);
      }
-     
      if(sf & ISF_ANGLES)
      {
          WriteCoord(MSG_ENTITY, self.angles_x);
          WriteCoord(MSG_ENTITY, self.angles_z);
      }
  
+     if(sf & ISF_SIZE)
+     {
+         WriteCoord(MSG_ENTITY, self.mins_x);
+         WriteCoord(MSG_ENTITY, self.mins_y);
+         WriteCoord(MSG_ENTITY, self.mins_z);
+         WriteCoord(MSG_ENTITY, self.maxs_x);
+         WriteCoord(MSG_ENTITY, self.maxs_y);
+         WriteCoord(MSG_ENTITY, self.maxs_z);
+     }
      if(sf & ISF_STATUS)
          WriteByte(MSG_ENTITY, self.ItemStatus);
  
      if(sf & ISF_MODEL)
      {
-         
          if(self.mdl == "")
              dprint("^1WARNING!^7 self.mdl is unset for item ", self.classname, "exspect a crash just aboute now\n");
-         
          WriteString(MSG_ENTITY, self.mdl);
      }
-         
-         
      if(sf & ISF_COLORMAP)
          WriteShort(MSG_ENTITY, self.colormap);
  
          WriteCoord(MSG_ENTITY, self.velocity_y);
          WriteCoord(MSG_ENTITY, self.velocity_z);
      }
-         
      return TRUE;
  }
  
+ void ItemUpdate(entity item)
+ {
+       item.SendFlags |= ISF_LOCATION;
+ }
  
  float have_pickup_item(void)
  {
-       // minstagib: only allow filtered items
-       if(g_minstagib)
-               if(self.classname != "minstagib")
-                       return FALSE;
        if(self.flags & FL_POWERUP)
        {
                if(autocvar_g_powerups > 0)
                        return TRUE;
                if(autocvar_g_powerups == 0)
                        return FALSE;
-               if(g_lms)
-                       return FALSE;
-               if(g_ca)
-                       return FALSE;
-               if(g_arena)
-                       return FALSE;
        }
        else
        {
                        return TRUE;
                if(autocvar_g_pickup_items == 0)
                        return FALSE;
-               if(g_lms)
-                       return FALSE;
-               if(g_ca)
-                       return FALSE;
                if(g_weaponarena)
-                       if(!WEPSET_EMPTY_E(self) || (self.items & IT_AMMO))
+                       if(self.weapons || (self.items & IT_AMMO)) // no item or ammo pickups in weaponarena
                                return FALSE;
        }
        return TRUE;
  }
  
- #define ITEM_RESPAWN_TICKS 10
- #define ITEM_RESPAWNTIME(i)         ((i).respawntime + crandom() * (i).respawntimejitter)
-       // range: respawntime - respawntimejitter .. respawntime + respawntimejitter
- #define ITEM_RESPAWNTIME_INITIAL(i) (ITEM_RESPAWN_TICKS + random() * ((i).respawntime + (i).respawntimejitter - ITEM_RESPAWN_TICKS))
-       // range: 10 .. respawntime + respawntimejitter
- floatfield Item_CounterField(float it)
- {
-       switch(it)
-       {
-               case IT_SHELLS:      return ammo_shells;
-               case IT_NAILS:       return ammo_nails;
-               case IT_ROCKETS:     return ammo_rockets;
-               case IT_CELLS:       return ammo_cells;
-               case IT_FUEL:        return ammo_fuel;
-               case IT_5HP:         return health;
-               case IT_25HP:        return health;
-               case IT_HEALTH:      return health;
-               case IT_ARMOR_SHARD: return armorvalue;
-               case IT_ARMOR:       return armorvalue;
-               // add more things here (health, armor)
-               default:             error("requested item has no counter field");
-       }
- #ifdef GMQCC
-       // should never happen
-       return health;
- #endif
- }
- string Item_CounterFieldName(float it)
- {
-       switch(it)
-       {
-               case IT_SHELLS:      return "shells";
-               case IT_NAILS:       return "nails";
-               case IT_ROCKETS:     return "rockets";
-               case IT_CELLS:       return "cells";
-               case IT_FUEL:        return "fuel";
-               // add more things here (health, armor)
-               default:             error("requested item has no counter field name");
-       }
- #ifdef GMQCC
-       // should never happen
-       return string_null;
- #endif
- }
- .float max_armorvalue;
- .float pickup_anyway;
  /*
  float Item_Customize()
  {
        if(self.spawnshieldtime)
                return TRUE;
-       if(!WEPSET_CONTAINS_ALL_EE(other, self))
+       if(self.weapons & ~other.weapons)
        {
                self.colormod = '0 0 0';
                self.glowmod = self.colormod;
  */
  
  void Item_Show (entity e, float mode)
- {    
-       e.effects &~= EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST;
-       e.ItemStatus &~= ITS_STAYWEP;
+ {
+       e.effects &= ~(EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST);
+       e.ItemStatus &= ~ITS_STAYWEP;
        if (mode > 0)
        {
                // make the item look normal, and be touchable
                e.model = string_null;
                e.solid = SOLID_NOT;
                e.spawnshieldtime = 1;
-               e.ItemStatus &~= ITS_AVAILABLE;
+               e.ItemStatus &= ~ITS_AVAILABLE;
        }
        else if((e.flags & FL_WEAPON) && !(e.flags & FL_NO_WEAPON_STAY) && g_weapon_stay)
        {
                e.colormod = '0 0 0';
                e.glowmod = e.colormod;
                e.spawnshieldtime = 1;
-               e.ItemStatus &~= ITS_AVAILABLE;
+               e.ItemStatus &= ~ITS_AVAILABLE;
        }
-       
        if (e.items & IT_STRENGTH || e.items & IT_INVINCIBLE)
-           e.ItemStatus |= ITS_POWERUP;                
-       
+           e.ItemStatus |= ITS_POWERUP;
        if (autocvar_g_nodepthtestitems)
                e.effects |= EF_NODEPTHTEST;
-               
-     
      if (autocvar_g_fullbrightitems)
                e.ItemStatus |= ITS_ALLOWFB;
-       
        if (autocvar_sv_simple_items)
          e.ItemStatus |= ITS_ALLOWSI;
  
      e.SendFlags |= ISF_STATUS;
  }
  
-       if(g_minstagib)
+ void Item_Think()
+ {
+       self.nextthink = time;
+       if(self.origin != self.oldorigin)
+       {
+               self.oldorigin = self.origin;
+               ItemUpdate(self);
+       }
+ }
 +float it_armor_large_time;
 +float it_health_mega_time;
 +float it_invisible_time;
 +float it_speed_time;
 +float it_extralife_time;
 +float it_strength_time;
 +float it_shield_time;
 +float it_fuelregen_time;
 +float it_jetpack_time;
 +float it_superweapons_time;
 +
 +void Item_ItemsTime_Init()
 +{
 +      it_armor_large_time = -1;
 +      it_health_mega_time = -1;
 +      it_invisible_time = -1;
 +      it_speed_time = -1;
 +      it_extralife_time = -1;
 +      it_strength_time = -1;
 +      it_shield_time = -1;
 +      it_fuelregen_time = -1;
 +      it_jetpack_time = -1;
 +      it_superweapons_time = -1;
 +}
 +void Item_ItemsTime_Reset()
 +{
 +      it_armor_large_time = (it_armor_large_time == -1) ? -1 : 0;
 +      it_health_mega_time = (it_health_mega_time == -1) ? -1 : 0;
 +      it_invisible_time   = (it_invisible_time   == -1) ? -1 : 0;
 +      it_speed_time       = (it_speed_time       == -1) ? -1 : 0;
 +      it_extralife_time   = (it_extralife_time   == -1) ? -1 : 0;
 +      it_strength_time    = (it_strength_time    == -1) ? -1 : 0;
 +      it_shield_time      = (it_shield_time      == -1) ? -1 : 0;
 +      it_fuelregen_time   = (it_fuelregen_time   == -1) ? -1 : 0;
 +      it_jetpack_time     = (it_jetpack_time     == -1) ? -1 : 0;
 +      it_superweapons_time= (it_superweapons_time== -1) ? -1 : 0;
 +}
 +void Item_ItemsTime_ResetForPlayer(entity e)
 +{
 +      e.item_armor_large_time = (it_armor_large_time == -1) ? -1 : 0;
 +      e.item_health_mega_time = (it_health_mega_time == -1) ? -1 : 0;
 +      e.item_invisible_time   = (it_invisible_time   == -1) ? -1 : 0;
 +      e.item_speed_time       = (it_speed_time       == -1) ? -1 : 0;
 +      e.item_extralife_time   = (it_extralife_time   == -1) ? -1 : 0;
 +      e.item_strength_time    = (it_strength_time    == -1) ? -1 : 0;
 +      e.item_shield_time      = (it_shield_time      == -1) ? -1 : 0;
 +      e.item_fuelregen_time   = (it_fuelregen_time   == -1) ? -1 : 0;
 +      e.item_jetpack_time     = (it_jetpack_time     == -1) ? -1 : 0;
 +      e.item_superweapons_time= (it_superweapons_time== -1) ? -1 : 0;
 +}
 +void Item_ItemsTime_Get(entity e)
 +{
 +      e.item_armor_large_time = it_armor_large_time;
 +      e.item_health_mega_time = it_health_mega_time;
 +      e.item_invisible_time = it_invisible_time;
 +      e.item_speed_time = it_speed_time;
 +      e.item_extralife_time = it_extralife_time;
 +      e.item_strength_time = it_strength_time;
 +      e.item_shield_time = it_shield_time;
 +      e.item_fuelregen_time = it_fuelregen_time;
 +      e.item_jetpack_time = it_jetpack_time;
 +      e.item_superweapons_time = it_superweapons_time;
 +}
 +float Item_ItemsTime_UpdateTime_Check(float item_time, float t)
 +{
 +      if(t == 0 && item_time == -1)
 +              return TRUE;
 +      if(time < t && (item_time <= time || t < item_time))
 +              return TRUE;
 +      return FALSE;
 +}
 +void Item_ItemsTime_UpdateTime(entity e, float t)
 +{
-                               if(WEPSET_CONTAINS_ANY_EA(e, WEPBIT_SUPERWEAPONS))
++      if(g_instagib)
 +      {
 +              switch(e.items)
 +              {
 +                      case IT_STRENGTH://"item-invis"
 +                              if(Item_ItemsTime_UpdateTime_Check(it_invisible_time, t))
 +                                      it_invisible_time = t;
 +                              break;
 +                      case IT_NAILS://"item-extralife"
 +                              if(Item_ItemsTime_UpdateTime_Check(it_extralife_time, t))
 +                                      it_extralife_time = t;
 +                              break;
 +                      case IT_INVINCIBLE://"item-speed"
 +                              if(Item_ItemsTime_UpdateTime_Check(it_speed_time, t))
 +                                      it_speed_time = t;
 +                              break;
 +              }
 +      }
 +      else
 +      {
 +              switch(e.items)
 +              {
 +                      case IT_HEALTH:
 +                              //if (e.classname == "item_health_mega")
 +                                      if(Item_ItemsTime_UpdateTime_Check(it_health_mega_time, t))
 +                                              it_health_mega_time = t;
 +                              break;
 +                      case IT_ARMOR:
 +                              if (e.classname == "item_armor_large")
 +                                      if(Item_ItemsTime_UpdateTime_Check(it_armor_large_time, t))
 +                                              it_armor_large_time = t;
 +                              break;
 +                      case IT_STRENGTH://"item-strength"
 +                              if(Item_ItemsTime_UpdateTime_Check(it_strength_time, t))
 +                                      it_strength_time = t;
 +                              break;
 +                      case IT_INVINCIBLE://"item-shield"
 +                              if(Item_ItemsTime_UpdateTime_Check(it_shield_time, t))
 +                                      it_shield_time = t;
 +                              break;
 +                      default:
-       if(inWarmupStage)
++                              if(e.weapons & WEPSET_SUPERWEAPONS)
 +                                      if(Item_ItemsTime_UpdateTime_Check(it_superweapons_time, t))
 +                                                      it_superweapons_time = t;
 +              }
 +      }
 +      switch(e.items)
 +      {
 +              case IT_FUEL_REGEN://"item-fuelregen"
 +                      if(Item_ItemsTime_UpdateTime_Check(it_fuelregen_time, t))
 +                              it_fuelregen_time = t;
 +                      break;
 +              case IT_JETPACK://"item-jetpack"
 +                      if(Item_ItemsTime_UpdateTime_Check(it_jetpack_time, t))
 +                              it_jetpack_time = t;
 +                      break;
 +      }
 +}
 +void Item_ItemsTime_GetForAll()
 +{
 +      entity e;
++      if(warmup_stage)
 +      {
 +              FOR_EACH_REALCLIENT(e)
 +                      Item_ItemsTime_Get(e);
 +      }
 +      else
 +      {
 +              FOR_EACH_REALCLIENT(e)
 +              {
 +                      if (e.classname != "player")
 +                              Item_ItemsTime_Get(e);
 +              }
 +      }
 +}
 +
  void Item_Respawn (void)
  {
        Item_Show(self, 1);
-       if(!g_minstagib && self.items == IT_STRENGTH)
-               sound (self, CH_TRIGGER, "misc/strength_respawn.wav", VOL_BASE, ATTN_NORM);     // play respawn sound
-       else if(!g_minstagib && self.items == IT_INVINCIBLE)
-               sound (self, CH_TRIGGER, "misc/shield_respawn.wav", VOL_BASE, ATTN_NORM);       // play respawn sound
+       // this is ugly...
+       if(self.items == IT_STRENGTH)
+               sound (self, CH_TRIGGER, "misc/strength_respawn.wav", VOL_BASE, ATTEN_NORM);    // play respawn sound
+       else if(self.items == IT_INVINCIBLE)
+               sound (self, CH_TRIGGER, "misc/shield_respawn.wav", VOL_BASE, ATTEN_NORM);      // play respawn sound
        else
-               sound (self, CH_TRIGGER, "misc/itemrespawn.wav", VOL_BASE, ATTN_NORM);  // play respawn sound
+               sound (self, CH_TRIGGER, "misc/itemrespawn.wav", VOL_BASE, ATTEN_NORM); // play respawn sound
        setorigin (self, self.origin);
  
-       if(self.flags & FL_POWERUP || self.classname == "item_armor_large" || self.items == IT_HEALTH || WEPSET_CONTAINS_ANY_EA(self, WEPBIT_SUPERWEAPONS))
++      if(self.flags & FL_POWERUP || self.classname == "item_armor_large" || self.items == IT_HEALTH || (self.weapons & WEPSET_SUPERWEAPONS))
 +      {
 +              Item_ItemsTime_UpdateTime(self, 0);
 +              Item_ItemsTime_GetForAll();
 +      }
 +
+       self.think = Item_Think;
+       self.nextthink = time;
 -      
++
        //pointparticles(particleeffectnum("item_respawn"), self.origin + self.mins_z * '0 0 1' + '0 0 48', '0 0 0', 1);
        pointparticles(particleeffectnum("item_respawn"), self.origin + 0.5 * (self.mins + self.maxs), '0 0 0', 1);
  }
@@@ -628,42 -417,24 +572,32 @@@ void Item_RespawnCountdown (void
                        string name;
                        vector rgb = '1 0 1';
                        name = string_null;
-                       if(g_minstagib)
-                       {
-                               switch(self.items)
-                               {
-                                       case IT_STRENGTH:   name = "item-invis"; rgb = '0 0 1'; break;
-                                       case IT_NAILS:      name = "item-extralife"; rgb = '1 0 0'; break;
-                                       case IT_INVINCIBLE: name = "item-speed"; rgb = '1 0 1'; break;
-                               }
-                       }
-                       else
-                       {
-                               switch(self.items)
-                               {
-                                       case IT_STRENGTH:   name = "item-strength"; rgb = '0 0 1'; break;
-                                       case IT_INVINCIBLE: name = "item-shield"; rgb = '1 0 1'; break;
-                                       case IT_HEALTH:
-                                               //if (self.classname == "item_health_mega")
-                                                       {name = "item_health_mega"; rgb = '1 0 0';}
-                                               break;
-                                       case IT_ARMOR:
-                                               if (self.classname == "item_armor_large")
-                                                       {name = "item_armor_large"; rgb = '0 1 0';}
-                                               break;
-                               }
-                       }
                        switch(self.items)
                        {
-                               case IT_FUEL_REGEN:     name = "item-fuelregen"; rgb = '1 0.5 0'; break;
-                               case IT_JETPACK:        name = "item-jetpack"; rgb = '0.5 0.5 0.5'; break;
+                               case IT_FUEL_REGEN: name = "item-fuelregen"; rgb = '1 0.5 0'; break;
+                               case IT_JETPACK:    name = "item-jetpack"; rgb = '0.5 0.5 0.5'; break;
+                               case IT_STRENGTH:   name = "item-strength"; rgb = '0 0 1'; break;
+                               case IT_INVINCIBLE: name = "item-shield"; rgb = '1 0 1'; break;
++                              case IT_HEALTH:
++                                      //if (self.classname == "item_health_mega")
++                                              {name = "item_health_mega"; rgb = '1 0 0';}
++                                      break;
++                              case IT_ARMOR:
++                                      if (self.classname == "item_armor_large")
++                                              {name = "item_armor_large"; rgb = '0 1 0';}
++                                      break;
                        }
+                       item_name = name;
+                       item_color = rgb;
+                       MUTATOR_CALLHOOK(Item_RespawnCountdown);
+                       name = item_name;
+                       rgb = item_color;
                        if(self.flags & FL_WEAPON)
                        {
                                entity wi = get_weaponinfo(self.weapon);
                                if(wi)
                                {
-                                       name = wi.model2;
+                                       name = wi.wpmodel;
                                        rgb = '1 0 0';
                                }
                        }
                        {
                                WaypointSprite_Spawn(name, 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, TRUE, RADARICON_POWERUP, rgb);
                                if(self.waypointsprite_attached)
 +                              {
 +                                      if (self.items == IT_HEALTH || self.items == IT_ARMOR)
 +                                              WaypointSprite_UpdateRule(self.waypointsprite_attached, 0, SPRITERULE_SPECTATOR);
                                        WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
 +                              }
                        }
                        else
                        {
                                localcmd(sprintf("prvm_edict server %d\n", num_for_edict(self)));
                        }
                }
-               sound (self, CH_TRIGGER, "misc/itemrespawncountdown.wav", VOL_BASE, ATTN_NORM); // play respawn sound
+               sound (self, CH_TRIGGER, "misc/itemrespawncountdown.wav", VOL_BASE, ATTEN_NORM);        // play respawn sound
                if(self.waypointsprite_attached)
                {
                        WaypointSprite_Ping(self.waypointsprite_attached);
        }
  }
  
+ void Item_RespawnThink()
+ {
+       self.nextthink = time;
+       if(self.origin != self.oldorigin)
+       {
+               self.oldorigin = self.origin;
+               ItemUpdate(self);
+       }
+       if(time >= self.wait)
+               Item_Respawn();
+ }
  void Item_ScheduleRespawnIn(entity e, float t)
  {
-       if((e.flags & FL_POWERUP) || WEPSET_CONTAINS_ANY_EA(e, WEPBIT_SUPERWEAPONS) || e.classname == "item_armor_large" || e.items == IT_HEALTH)
 -      if((e.flags & FL_POWERUP) || (e.weapons & WEPSET_SUPERWEAPONS))
++      if((e.flags & FL_POWERUP) || (e.weapons & WEPSET_SUPERWEAPONS) || e.classname == "item_armor_large" || e.items == IT_HEALTH)
        {
 +              entity head;
                e.think = Item_RespawnCountdown;
                e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
 +              e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
                e.count = 0;
-               if(WEPSET_CONTAINS_ANY_EA(e, WEPBIT_SUPERWEAPONS))
++              if(e.weapons & WEPSET_SUPERWEAPONS)
 +              {
 +                      for(t = e.scheduledrespawntime, head = world; (head = nextent(head)); )
 +                      {
 +                              if(e == head)
 +                                      continue;
 +                              if(clienttype(head) == CLIENTTYPE_NOTACLIENT)
-                               if(WEPSET_CONTAINS_ANY_EA(head, WEPBIT_SUPERWEAPONS))
++                              if(head.weapons & WEPSET_SUPERWEAPONS)
 +                              if(head.classname != "weapon_info")
 +                              {
 +                                      if(head.scheduledrespawntime <= time)
 +                                      {
 +                                              t = 0;
 +                                              break;
 +                                      }
 +                                      if(head.scheduledrespawntime < t)
 +                                              t = head.scheduledrespawntime;
 +                              }
 +                      }
 +              }
 +              else
 +              {
 +                      for(t = e.scheduledrespawntime, head = world; (head = find(head, classname, e.classname)); )
 +                      {
-                               // in minstagib .classname is "minstagib" for every item
-                               if(e == head || (g_minstagib && e.items != head.items))
++                              // in instagib .classname is "instagib" for every item
++                              if(e == head || (g_instagib && e.items != head.items))
 +                                      continue;
 +                              if(head.scheduledrespawntime <= time)
 +                              {
 +                                      t = 0;
 +                                      break;
 +                              }
 +                              if(head.scheduledrespawntime < t)
 +                                      t = head.scheduledrespawntime;
 +                      }
 +              }
 +              Item_ItemsTime_UpdateTime(e, t);
 +              Item_ItemsTime_GetForAll();
        }
        else
        {
-               e.think = Item_Respawn;
-               e.nextthink = time + t;
-               e.scheduledrespawntime = e.nextthink;
+               e.think = Item_RespawnThink;
+               e.nextthink = time;
++              e.scheduledrespawntime = time + t;
+               e.wait = time + t;
        }
  }
  
@@@ -765,29 -505,25 +713,25 @@@ void Item_ScheduleInitialRespawn(entit
        Item_ScheduleRespawnIn(e, game_starttime - time + ITEM_RESPAWNTIME_INITIAL(e));
  }
  
- float ITEM_MODE_NONE = 0;
- float ITEM_MODE_HEALTH = 1;
- float ITEM_MODE_ARMOR = 2;
- float ITEM_MODE_FUEL = 3;
- float Item_GiveAmmoTo(entity item, entity player, .float ammofield, float ammomax, float mode)
+ float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax, float mode)
  {
-       if (!item.ammofield)
+       if (!item.ammotype)
                return FALSE;
  
        if (item.spawnshieldtime)
        {
-               if ((player.ammofield < ammomax) || item.pickup_anyway)
+               if ((player.ammotype < ammomax) || item.pickup_anyway)
                {
-                       player.ammofield = bound(player.ammofield, ammomax, player.ammofield + item.ammofield);
+                       player.ammotype = bound(player.ammotype, ammomax, player.ammotype + item.ammotype);
                        goto YEAH;
                }
        }
        else if(g_weapon_stay == 2)
        {
-               float mi = min(item.ammofield, ammomax);
-               if (player.ammofield < mi)
+               float mi = min(item.ammotype, ammomax);
+               if (player.ammotype < mi)
                {
-                       player.ammofield = mi;
+                       player.ammotype = mi;
                        goto YEAH;
                }
        }
@@@ -822,130 -558,68 +766,68 @@@ float Item_GiveTo(entity item, entity p
        // if nothing happens to player, just return without taking the item
        pickedup = FALSE;
        _switchweapon = FALSE;
+       // in case the player has autoswitch enabled do the following:
+       // if the player is using their best weapon before items are given, they
+       // probably want to switch to an even better weapon after items are given
+       if (player.autoswitch)
+       if (player.switchweapon == w_getbestweapon(player))
+               _switchweapon = TRUE;
  
-       if (g_minstagib)
-       {
-               float prevcells = player.ammo_cells;
-               pickedup |= Item_GiveAmmoTo(item, player, ammo_fuel, g_pickup_fuel_max, ITEM_MODE_FUEL);
-               pickedup |= Item_GiveAmmoTo(item, player, ammo_cells, 999, ITEM_MODE_NONE);
-               if(player.ammo_cells > prevcells)
-               {
-                       _switchweapon = TRUE;
-                       // play some cool sounds ;)
-                       if (clienttype(player) == CLIENTTYPE_REAL)
-                       {
-                               if(player.health <= 5)
-                                       AnnounceTo(player, "lastsecond");
-                               else if(player.health < 50)
-                                       AnnounceTo(player, "narrowly");
-                       }
-                       // sound not available
-                       // else if(item.items == IT_CELLS)
-                       //      AnnounceTo(player, "ammo");
-                       if (WEPSET_CONTAINS_EW(item, WEP_MINSTANEX))
-                               W_GiveWeapon (player, WEP_MINSTANEX);
-                       player.health = 100;
-               }
-               if((it = (item.items - (item.items & player.items)) & IT_PICKUPMASK))
-               {
-                       pickedup = TRUE;
-                       player.items |= it;
-                       sprint (player, strcat("You got the ^2", item.netname, "\n"));
-               }
-               // extralife powerup
-               if (item.max_health)
-               {
-                       pickedup = TRUE;
-                       // sound not available
-                       // AnnounceTo(player, "_lives");
-                       player.armorvalue = bound(player.armorvalue, 999, player.armorvalue + autocvar_g_minstagib_extralives);
-                       sprint(player, "^3You picked up some extra lives\n");
-               }
+       if (!(player.weapons & WepSet_FromWeapon(player.switchweapon)))
+               _switchweapon = TRUE;
  
-               // invis powerup
-               if (item.strength_finished)
-               {
-                       pickedup = TRUE;
-                       // sound not available
-                       // AnnounceTo(player, "invisible");
-                       player.strength_finished = max(player.strength_finished, time) + autocvar_g_balance_powerup_strength_time;
-               }
+       pickedup |= Item_GiveAmmoTo(item, player, ammo_fuel, g_pickup_fuel_max, ITEM_MODE_FUEL);
+       pickedup |= Item_GiveAmmoTo(item, player, ammo_shells, g_pickup_shells_max, ITEM_MODE_NONE);
+       pickedup |= Item_GiveAmmoTo(item, player, ammo_nails, g_pickup_nails_max, ITEM_MODE_NONE);
+       pickedup |= Item_GiveAmmoTo(item, player, ammo_rockets, g_pickup_rockets_max, ITEM_MODE_NONE);
+       pickedup |= Item_GiveAmmoTo(item, player, ammo_cells, g_pickup_cells_max, ITEM_MODE_NONE);
+       pickedup |= Item_GiveAmmoTo(item, player, ammo_plasma, g_pickup_plasma_max, ITEM_MODE_NONE);
+       pickedup |= Item_GiveAmmoTo(item, player, health, item.max_health, ITEM_MODE_HEALTH);
+       pickedup |= Item_GiveAmmoTo(item, player, armorvalue, item.max_armorvalue, ITEM_MODE_ARMOR);
  
-               // speed powerup
-               if (item.invincible_finished)
-               {
-                       pickedup = TRUE;
-                       // sound not available
-                       // AnnounceTo(player, "speed");
-                       player.invincible_finished = max(player.invincible_finished, time) + autocvar_g_balance_powerup_invincible_time;
-               }
-       }
-       else
+       if (item.flags & FL_WEAPON)
        {
-               // in case the player has autoswitch enabled do the following:
-               // if the player is using their best weapon before items are given, they
-               // probably want to switch to an even better weapon after items are given
-               if (player.autoswitch)
-               if (player.switchweapon == w_getbestweapon(player))
-                       _switchweapon = TRUE;
-               if not(WEPSET_CONTAINS_EW(player, player.switchweapon))
-                       _switchweapon = TRUE;
+               WepSet it;
+               it = item.weapons;
+               it &= ~player.weapons;
  
-               pickedup |= Item_GiveAmmoTo(item, player, ammo_fuel, g_pickup_fuel_max, ITEM_MODE_FUEL);
-               pickedup |= Item_GiveAmmoTo(item, player, ammo_shells, g_pickup_shells_max, ITEM_MODE_NONE);
-               pickedup |= Item_GiveAmmoTo(item, player, ammo_nails, g_pickup_nails_max, ITEM_MODE_NONE);
-               pickedup |= Item_GiveAmmoTo(item, player, ammo_rockets, g_pickup_rockets_max, ITEM_MODE_NONE);
-               pickedup |= Item_GiveAmmoTo(item, player, ammo_cells, g_pickup_cells_max, ITEM_MODE_NONE);
-               pickedup |= Item_GiveAmmoTo(item, player, health, item.max_health, ITEM_MODE_HEALTH);
-               pickedup |= Item_GiveAmmoTo(item, player, armorvalue, item.max_armorvalue, ITEM_MODE_ARMOR);
-               if (item.flags & FL_WEAPON)
+               if (it || (item.spawnshieldtime && item.pickup_anyway))
                {
-                       WEPSET_DECLARE_A(it);
-                       WEPSET_COPY_AE(it, item);
-                       WEPSET_ANDNOT_AE(it, player);
-                       if (!WEPSET_EMPTY_A(it) || (item.spawnshieldtime && self.pickup_anyway))
+                       pickedup = TRUE;
+                       for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+                       if(it & WepSet_FromWeapon(i))
                        {
-                               pickedup = TRUE;
-                               for(i = WEP_FIRST; i <= WEP_LAST; ++i)
-                                       if(WEPSET_CONTAINS_AW(it, i))
-                                               W_GiveWeapon(player, i);
+                               W_DropEvent(WR_PICKUP, player, i, item);
+                               W_GiveWeapon(player, i);
                        }
                }
+       }
  
-               if((it = (item.items - (item.items & player.items)) & IT_PICKUPMASK))
-               {
-                       pickedup = TRUE;
-                       player.items |= it;
-                       sprint (player, strcat("You got the ^2", item.netname, "\n"));
-               }
+       if((it = (item.items - (item.items & player.items)) & IT_PICKUPMASK))
+       {
+               pickedup = TRUE;
+               player.items |= it;
+               Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_ITEM_WEAPON_GOT, item.netname);
+       }
  
-               if (item.strength_finished)
-               {
-                       pickedup = TRUE;
-                       player.strength_finished = max(player.strength_finished, time) + item.strength_finished;
-               }
-               if (item.invincible_finished)
-               {
-                       pickedup = TRUE;
-                       player.invincible_finished = max(player.invincible_finished, time) + item.invincible_finished;
-               }
-               if (item.superweapons_finished)
-               {
-                       pickedup = TRUE;
-                       player.superweapons_finished = max(player.superweapons_finished, time) + item.superweapons_finished;
-               }
+       if (item.strength_finished)
+       {
+               pickedup = TRUE;
+               player.strength_finished = max(player.strength_finished, time) + item.strength_finished;
+       }
+       if (item.invincible_finished)
+       {
+               pickedup = TRUE;
+               player.invincible_finished = max(player.invincible_finished, time) + item.invincible_finished;
+       }
+       if (item.superweapons_finished)
+       {
+               pickedup = TRUE;
+               player.superweapons_finished = max(player.superweapons_finished, time) + item.superweapons_finished;
        }
  
  :skip
        // always eat teamed entities
        if(item.team)
                pickedup = TRUE;
  void Item_Touch (void)
  {
        entity e, head;
-       
        // remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky)
        if(self.classname == "droppedweapon")
        {
                }
        }
  
-       if (other.classname != "player")
+       if (!IS_PLAYER(other))
+               return;
+       if (other.frozen)
                return;
        if (other.deadflag)
                return;
                return;
        if (self.owner == other)
                return;
-       if(MUTATOR_CALLHOOK(ItemTouch))
+       if (time < self.item_spawnshieldtime)
                return;
  
+       switch(MUTATOR_CALLHOOK(ItemTouch))
+       {
+               case MUT_ITEMTOUCH_RETURN: { return; }
+               case MUT_ITEMTOUCH_PICKUP: { goto pickup; }
+       }
        if (self.classname == "droppedweapon")
        {
                self.strength_finished = max(0, self.strength_finished - time);
                return;
        }
  
+       :pickup
        other.last_pickup = time;
  
        pointparticles(particleeffectnum("item_pickup"), self.origin, '0 0 0', 1);
-       sound (other, CH_TRIGGER, self.item_pickupsound, VOL_BASE, ATTN_NORM);
+       sound (other, CH_TRIGGER, self.item_pickupsound, VOL_BASE, ATTEN_NORM);
  
        if (self.classname == "droppedweapon")
                remove (self);
-       else if not(self.spawnshieldtime)
+       else if (!self.spawnshieldtime)
                return;
        else
        {
@@@ -1042,13 -726,13 +934,13 @@@ void Item_Reset(
  
        if(self.classname != "droppedweapon")
        {
-               self.think = func_null;
-               self.nextthink = 0;
+               self.think = Item_Think;
+               self.nextthink = time;
  
                if(self.waypointsprite_attached)
                        WaypointSprite_Kill(self.waypointsprite_attached);
  
-               if((self.flags & FL_POWERUP) | WEPSET_CONTAINS_ANY_EA(self, WEPBIT_SUPERWEAPONS)) // do not spawn powerups initially!
+               if((self.flags & FL_POWERUP) || (self.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
                        Item_ScheduleInitialRespawn(self);
        }
  }
@@@ -1076,7 -760,7 +968,7 @@@ void Item_FindTeam(
                                Item_Show(head, -1);
                                head.state = 1; // state 1 = initially hidden item
                        }
-                       head.effects &~= EF_NODRAW;
+                       head.effects &= ~EF_NODRAW;
                }
  
                Item_Reset();
@@@ -1100,12 -784,12 +992,12 @@@ float weapon_pickupevalfunc(entity play
        float c, j, position;
  
        // See if I have it already
-       if(!WEPSET_CONTAINS_ALL_EE(player, item))
+       if(item.weapons & ~player.weapons)
        {
                // If I can pick it up
                if(!item.spawnshieldtime)
                        c = 0;
-               else if(player.ammo_cells || player.ammo_shells || player.ammo_nails || player.ammo_rockets)
+               else if(player.ammo_cells || player.ammo_shells || player.ammo_plasma || player.ammo_nails || player.ammo_rockets)
                {
                        // Skilled bots will grab more
                        c = bound(0, skill / 10, 1) * 0.5;
  float commodity_pickupevalfunc(entity player, entity item)
  {
        float c, i;
-       float need_shells = FALSE, need_nails = FALSE, need_rockets = FALSE, need_cells = FALSE, need_fuel = FALSE;
+       float need_shells = FALSE, need_nails = FALSE, need_rockets = FALSE, need_cells = FALSE, need_plasma = FALSE, need_fuel = FALSE;
        entity wi;
        c = 0;
  
        {
                wi = get_weaponinfo(i);
  
-               if not(WEPSET_CONTAINS_EW(player, i))
+               if (!(player.weapons & WepSet_FromWeapon(i)))
                        continue;
  
                if(wi.items & IT_SHELLS)
                        need_rockets = TRUE;
                else if(wi.items & IT_CELLS)
                        need_cells = TRUE;
+               else if(wi.items & IT_PLASMA)
+                       need_plasma = TRUE;
                else if(wi.items & IT_FUEL)
-                       need_cells = TRUE;
+                       need_fuel = TRUE;
        }
  
        // TODO: figure out if the player even has the weapon this ammo is for?
        if (item.ammo_cells)
        if (player.ammo_cells < g_pickup_cells_max)
                c = c + max(0, 1 - player.ammo_cells / g_pickup_cells_max);
+       if (need_plasma)
+       if (item.ammo_plasma)
+       if (player.ammo_plasma < g_pickup_plasma_max)
+               c = c + max(0, 1 - player.ammo_plasma / g_pickup_plasma_max);
        if (need_fuel)
        if (item.ammo_fuel)
        if (player.ammo_fuel < g_pickup_fuel_max)
@@@ -1211,23 -901,22 +1109,22 @@@ void Item_Damage(entity inflictor, enti
                RemoveItem();
  }
  
- .float is_item;
  void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, float defaultrespawntimejitter, string itemname, float itemid, float weaponid, float itemflags, float(entity player, entity item) pickupevalfunc, float pickupbasevalue)
  {
        startitem_failed = FALSE;
  
        if(self.model == "")
                self.model = itemmodel;
-       
        if(self.model == "")
      {
          error(strcat("^1Tried to spawn ", itemname, " with no model!\n"));
          return;
      }
-         
        if(self.item_pickupsound == "")
                self.item_pickupsound = pickupsound;
-       
        if(!self.respawntime) // both need to be set
        {
                self.respawntime = defaultrespawntime;
        self.weapon = weaponid;
  
        if(weaponid)
-               WEPSET_COPY_EW(self, weaponid);
-       
+               self.weapons = WepSet_FromWeapon(weaponid);
        self.flags = FL_ITEM | itemflags;
  
        if(MUTATOR_CALLHOOK(FilterItem)) // error means we do not want the item
                if(self.strength_finished || self.invincible_finished || self.superweapons_finished)
                /*
                if(self.items == 0)
-               if(WEPSET_CONTAINS_ALL_AE(WEPBIT_SUPERWEAPONS, self)) // only superweapons
+               if(!(self.weapons & ~WEPSET_SUPERWEAPONS)) // only superweapons
                if(self.ammo_nails == 0)
                if(self.ammo_cells == 0)
                if(self.ammo_rockets == 0)
                        remove (self);
                        return;
                }
-               
-               if(self.angles != '0 0 0')
-             self.SendFlags |= ISF_ANGLES;
  
                self.reset = Item_Reset;
                // it's a level item
                                setsize (self, '-16 -16 0', '16 16 48');
                        else
                                setsize (self, '-16 -16 0', '16 16 32');
                        // note droptofloor returns FALSE if stuck/or would fall too far
                        droptofloor();
                        waypoint_spawnforitem(self);
                        self.is_item = TRUE;
                }
  
-               WEPSET_OR_AW(weaponsInMap, weaponid);
+               weaponsInMap |= WepSet_FromWeapon(weaponid);
  
                precache_model (self.model);
                precache_sound (self.item_pickupsound);
  
                precache_sound ("misc/itemrespawncountdown.wav");
-               if(!g_minstagib && itemid == IT_STRENGTH)
+               if(itemid == IT_STRENGTH)
                        precache_sound ("misc/strength_respawn.wav");
-               else if(!g_minstagib && itemid == IT_INVINCIBLE)
+               else if(itemid == IT_INVINCIBLE)
                        precache_sound ("misc/shield_respawn.wav");
                else
                        precache_sound ("misc/itemrespawn.wav");
  
                if((itemflags & (FL_POWERUP | FL_WEAPON)) || (itemid & (IT_HEALTH | IT_ARMOR | IT_KEY1 | IT_KEY2)))
                        self.target = "###item###"; // for finding the nearest item using find()
 +
 +              Item_ItemsTime_UpdateTime(self, 0);
        }
  
        self.bot_pickup = TRUE;
        self.netname = itemname;
        self.touch = Item_Touch;
        setmodel(self, "null"); // precision set below
-       //self.effects |= EF_LOWPRECISION; 
-       
+       //self.effects |= EF_LOWPRECISION;
        if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
      {
          self.pos1 = '-16 -16 0';
          self.pos2 = '16 16 32';
      }
      setsize (self, self.pos1, self.pos2);
-     
-     if(itemflags & FL_POWERUP) 
+     if(itemflags & FL_POWERUP)
          self.ItemStatus |= ITS_ANIMATE1;
-       
        if(self.armorvalue || self.health)
          self.ItemStatus |= ITS_ANIMATE2;
-       
        if(itemflags & FL_WEAPON)
        {
                if (self.classname != "droppedweapon") // if dropped, colormap is already set up nicely
              self.colormap = 1024; // color shirt=0 pants=0 grey
          else
              self.gravity = 1;
-             
                self.ItemStatus |= ITS_ANIMATE1;
                self.ItemStatus |= ISF_COLORMAP;
        }
        {
                if(!self.cnt)
                        self.cnt = 1; // item probability weight
-                       
                self.effects |= EF_NODRAW; // marker for item team search
                InitializeEntity(self, Item_FindTeam, INITPRIO_FINDTARGET);
        }
        else
                Item_Reset();
-         
      Net_LinkEntity(self, FALSE, 0, ItemSend);
+       
+       self.SendFlags |= ISF_SIZE;
+       if(self.angles)
+               self.SendFlags |= ISF_ANGLES;
  
        // call this hook after everything else has been done
        if(MUTATOR_CALLHOOK(Item_Spawn))
                return;
        }
  }
- /* replace items in minstagib
-  * IT_STRENGTH         = invisibility
-  * IT_NAILS    = extra lives
-  * IT_INVINCIBLE = speed
-  */
- void minstagib_items (float itemid) // will be deleted soon.
- {
-       float rnd;
-       self.classname = "minstagib"; // ...?
-       // replace rocket launchers and nex guns with ammo cells
-       if (itemid == IT_CELLS)
-       {
-               self.ammo_cells = autocvar_g_minstagib_ammo_drop;
-               StartItem ("models/items/a_cells.md3",
-                       "misc/itempickup.wav", 45, 0,
-                       "MinstaNex Ammo", IT_CELLS, 0, 0, generic_pickupevalfunc, 100);
-               return;
-       }
-       // randomize
-       rnd = random() * 3;
-       if (rnd <= 1)
-               itemid = IT_STRENGTH;
-       else if (rnd <= 2)
-               itemid = IT_NAILS;
-       else
-               itemid = IT_INVINCIBLE;
-       // replace with invis
-       if (itemid == IT_STRENGTH)
-       {
-               if(!self.strength_finished)
-                       self.strength_finished = autocvar_g_balance_powerup_strength_time;
-               StartItem ("models/items/g_strength.md3",
-                       "misc/powerup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
-                       "Invisibility", IT_STRENGTH, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_MID);
-       }
-       // replace with extra lives
-       if (itemid == IT_NAILS)
-       {
-               self.max_health = 1;
-               StartItem ("models/items/g_h100.md3",
-                       "misc/megahealth.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
-                       "Extralife", IT_NAILS, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
-       }
-       // replace with speed
-       if (itemid == IT_INVINCIBLE)
-       {
-               if(!self.invincible_finished)
-                       self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
-               StartItem ("models/items/g_invincible.md3",
-                       "misc/powerup_shield.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
-                       "Speed", IT_INVINCIBLE, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_MID);
-       }
- }
- float minst_no_auto_cells;
- void minst_remove_item (void) {
-       if(minst_no_auto_cells)
-               remove(self);
- }
- float weaponswapping;
- float internalteam;
- void weapon_defaultspawnfunc(float wpn)
- {
-       entity e;
-       float t;
-       var .float ammofield;
-       string s;
-       entity oldself;
-       float i, j;
-       float f;
-       if(self.classname != "droppedweapon" && self.classname != "replacedweapon")
-       {
-               e = get_weaponinfo(wpn);
-               if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
-               {
-                       print("Attempted to spawn a mutator-blocked weapon; these guns will in the future require a mutator\n");
-                       /*
-                       objerror("Attempted to spawn a mutator-blocked weapon rejected");
-                       startitem_failed = TRUE;
-                       return;
-                       */
-               }
-               s = W_Apply_Weaponreplace(e.netname);
-               ret_string = s;
-               other = e;
-               MUTATOR_CALLHOOK(SetWeaponreplace);
-               s = ret_string;
-               if(s == "")
-               {
-                       remove(self);
-                       startitem_failed = TRUE;
-                       return;
-               }
-               t = tokenize_console(s);
-               if(t >= 2)
-               {
-                       self.team = --internalteam;
-                       oldself = self;
-                       for(i = 1; i < t; ++i)
-                       {
-                               s = argv(i);
-                               for(j = WEP_FIRST; j <= WEP_LAST; ++j)
-                               {
-                                       e = get_weaponinfo(j);
-                                       if(e.netname == s)
-                                       {
-                                               self = spawn();
-                                               copyentity(oldself, self);
-                                               self.classname = "replacedweapon";
-                                               weapon_defaultspawnfunc(j);
-                                               break;
-                                       }
-                               }
-                               if(j > WEP_LAST)
-                               {
-                                       print("The weapon replace list for ", oldself.classname, " contains an unknown weapon ", s, ". Skipped.\n");
-                               }
-                       }
-                       self = oldself;
-               }
-               if(t >= 1) // always the case!
-               {
-                       s = argv(0);
-                       wpn = 0;
-                       for(j = WEP_FIRST; j <= WEP_LAST; ++j)
-                       {
-                               e = get_weaponinfo(j);
-                               if(e.netname == s)
-                               {
-                                       wpn = j;
-                                       break;
-                               }
-                       }
-                       if(j > WEP_LAST)
-                       {
-                               print("The weapon replace list for ", self.classname, " contains an unknown weapon ", s, ". Skipped.\n");
-                       }
-               }
-               if(wpn == 0)
-               {
-                       remove(self);
-                       startitem_failed = TRUE;
-                       return;
-               }
-       }
-       e = get_weaponinfo(wpn);
-       if(!self.respawntime)
-       {
-               if(WEPSET_CONTAINS_ANY_EA(e, WEPBIT_SUPERWEAPONS))
-               {
-                       self.respawntime = g_pickup_respawntime_superweapon;
-                       self.respawntimejitter = g_pickup_respawntimejitter_superweapon;
-               }
-               else
-               {
-                       self.respawntime = g_pickup_respawntime_weapon;
-                       self.respawntimejitter = g_pickup_respawntimejitter_weapon;
-               }
-       }
-       if(WEPSET_CONTAINS_ANY_EA(e, WEPBIT_SUPERWEAPONS))
-               if(!self.superweapons_finished)
-                       self.superweapons_finished = autocvar_g_balance_superweapons_time;
-       if(e.items)
-       {
-               for(i = 0, j = 1; i < 24; ++i, j *= 2)
-               {
-                       if(e.items & j)
-                       {
-                               ammofield = Item_CounterField(j);
-                               if(!self.ammofield)
-                                       self.ammofield = cvar(strcat("g_pickup_", Item_CounterFieldName(j), "_weapon"));
-                       }
-               }
-       }
-       // pickup anyway
-       if(g_pickup_weapons_anyway)
-               self.pickup_anyway = TRUE;
-       f = FL_WEAPON;
-       // no weapon-stay on superweapons
-       if(WEPSET_CONTAINS_ANY_EA(e, WEPBIT_SUPERWEAPONS))
-               f |= FL_NO_WEAPON_STAY;
-       // weapon stay isn't supported for teamed weapons
-       if(self.team)
-               f |= FL_NO_WEAPON_STAY;
-       // stupid minstagib hack, don't ask
-       if(g_minstagib)
-               if(self.ammo_cells)
-                       self.ammo_cells = autocvar_g_minstagib_ammo_drop;
-       StartItem(e.model, "weapons/weaponpickup.wav", self.respawntime, self.respawntimejitter, e.message, 0, e.weapon, f, weapon_pickupevalfunc, e.bot_pickupbasevalue);
-       if (self.modelindex) // don't precache if self was removed
-               weapon_action(e.weapon, WR_PRECACHE);
- }
- void spawnfunc_weapon_shotgun (void);
- void spawnfunc_weapon_uzi (void) {
-       if(autocvar_sv_q3acompat_machineshotgunswap)
-       if(self.classname != "droppedweapon")
-       {
-               weapon_defaultspawnfunc(WEP_SHOTGUN);
-               return;
-       }
-       weapon_defaultspawnfunc(WEP_UZI);
- }
- void spawnfunc_weapon_shotgun (void) {
-       if(autocvar_sv_q3acompat_machineshotgunswap)
-       if(self.classname != "droppedweapon")
-       {
-               weapon_defaultspawnfunc(WEP_UZI);
-               return;
-       }
-       weapon_defaultspawnfunc(WEP_SHOTGUN);
- }
- void spawnfunc_weapon_nex (void)
- {
-       if (g_minstagib)
-       {
-               minstagib_items(IT_CELLS);
-               self.think = minst_remove_item;
-               self.nextthink = time;
-               return;
-       }
-       weapon_defaultspawnfunc(WEP_NEX);
- }
- void spawnfunc_weapon_minstanex (void)
- {
-       if (g_minstagib)
-       {
-               minstagib_items(IT_CELLS);
-               self.think = minst_remove_item;
-               self.nextthink = time;
-               return;
-       }
-       weapon_defaultspawnfunc(WEP_MINSTANEX);
- }
- void spawnfunc_weapon_rocketlauncher (void)
- {
-       if (g_minstagib)
-       {
-               minstagib_items(IT_CELLS); // replace rocketlauncher with cells
-               self.think = minst_remove_item;
-               self.nextthink = time;
-               return;
-       }
-       weapon_defaultspawnfunc(WEP_ROCKET_LAUNCHER);
- }
  void spawnfunc_item_rockets (void) {
        if(!self.ammo_rockets)
                self.ammo_rockets = g_pickup_rockets;
@@@ -1737,6 -1157,15 +1367,15 @@@ void spawnfunc_item_cells (void) 
        StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "cells", IT_CELLS, 0, 0, commodity_pickupevalfunc, 2000);
  }
  
+ void spawnfunc_item_plasma()
+ {
+       if(!self.ammo_plasma)
+               self.ammo_plasma = g_pickup_plasma;
+       if(!self.pickup_anyway)
+               self.pickup_anyway = g_pickup_ammo_anyway;
+       StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "plasma", IT_PLASMA, 0, 0, commodity_pickupevalfunc, 2000);
+ }
  void spawnfunc_item_shells (void) {
        if(!weaponswapping)
        if(autocvar_sv_q3acompat_machineshotgunswap)
@@@ -1826,9 -1255,6 +1465,6 @@@ void spawnfunc_item_health_large (void
  }
  
  void spawnfunc_item_health_mega (void) {
-       if(g_minstagib) {
-               minstagib_items(IT_NAILS);
-       } else {
                if(!self.max_health)
                        self.max_health = g_pickup_healthmega_max;
                if(!self.health)
                if(!self.pickup_anyway)
                        self.pickup_anyway = g_pickup_healthmega_anyway;
                StartItem ("models/items/g_h100.md3", "misc/megahealth.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Health", IT_HEALTH, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
-       }
  }
  
  // support old misnamed entities
@@@ -1847,40 -1272,21 +1482,21 @@@ void spawnfunc_item_health25() { spawnf
  void spawnfunc_item_health100() { spawnfunc_item_health_mega(); }
  
  void spawnfunc_item_strength (void) {
-       if(g_minstagib) {
-               minstagib_items(IT_STRENGTH);
-       } else {
                precache_sound("weapons/strength_fire.wav");
                if(!self.strength_finished)
                        self.strength_finished = autocvar_g_balance_powerup_strength_time;
                StartItem ("models/items/g_strength.md3", "misc/powerup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Strength Powerup", IT_STRENGTH, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
-       }
  }
  
  void spawnfunc_item_invincible (void) {
-       if(g_minstagib) {
-               minstagib_items(IT_INVINCIBLE);
-       } else {
                if(!self.invincible_finished)
                        self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
                StartItem ("models/items/g_invincible.md3", "misc/powerup_shield.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Shield", IT_INVINCIBLE, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
-       }
- }
- void spawnfunc_item_minst_cells (void) {
-       if (g_minstagib)
-       {
-               minst_no_auto_cells = TRUE;
-               minstagib_items(IT_CELLS);
-       }
-       else
-               remove(self);
  }
  
  // compatibility:
  void spawnfunc_item_quad (void) {self.classname = "item_strength";spawnfunc_item_strength();}
  
- float GiveItems(entity e, float beginarg, float endarg);
  void target_items_use (void)
  {
        if(activator.classname == "droppedweapon")
                return;
        }
  
-       if(activator.classname != "player")
+       if (!IS_PLAYER(activator))
                return;
        if(activator.deadflag != DEAD_NO)
                return;
@@@ -1949,9 -1355,9 +1565,9 @@@ void spawnfunc_target_items (void
                                        e = get_weaponinfo(j);
                                        if(argv(i) == e.netname)
                                        {
-                                               WEPSET_OR_EW(self, j);
+                                               self.weapons |= WepSet_FromWeapon(j);
                                                if(self.spawnflags == 0 || self.spawnflags == 2)
-                                                       weapon_action(e.weapon, WR_PRECACHE);
+                                                       WEP_ACTION(e.weapon, WR_INIT);
                                                break;
                                        }
                                }
                if(self.ammo_nails != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_nails), "nails");
                if(self.ammo_rockets != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_rockets), "rockets");
                if(self.ammo_cells != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_cells), "cells");
+               if(self.ammo_plasma != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_plasma), "plasma");
                if(self.ammo_fuel != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_fuel), "fuel");
                if(self.health != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.health), "health");
                if(self.armorvalue != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.health), "armor");
                {
                        e = get_weaponinfo(j);
                        if(e.weapon)
-                               self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, WEPSET_CONTAINS_EW(self, j), e.netname);
+                               self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.weapons & WepSet_FromWeapon(j)), e.netname);
                }
        }
        self.netname = strzone(self.netname);
                        e = get_weaponinfo(j);
                        if(argv(i) == e.netname)
                        {
-                               weapon_action(e.weapon, WR_PRECACHE);
+                               WEP_ACTION(e.weapon, WR_INIT);
                                break;
                        }
                }
@@@ -2051,8 -1458,6 +1668,6 @@@ void spawnfunc_item_fuel_regen(void
  
  void spawnfunc_item_jetpack(void)
  {
-       if(g_grappling_hook)
-               return; // sorry, but these two can't coexist (same button); spawn fuel instead
        if(!self.ammo_fuel)
                self.ammo_fuel = g_pickup_fuel_jetpack;
        if(start_items & IT_JETPACK)
        StartItem ("models/items/g_jetpack.md3", "misc/itempickup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Jet pack", IT_JETPACK, 0, FL_POWERUP, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
  }
  
- #define OP_SET 0
- #define OP_MIN 1
- #define OP_MAX 2
- #define OP_PLUS 3
- #define OP_MINUS 4
  float GiveWeapon(entity e, float wpn, float op, float val)
  {
-       float v0, v1;
-       v0 = WEPSET_CONTAINS_EW(e, wpn);
+       WepSet v0, v1;
+       v0 = (e.weapons & WepSet_FromWeapon(wpn));
        switch(op)
        {
                case OP_SET:
                        if(val > 0)
-                               WEPSET_OR_EW(e, wpn);
+                               e.weapons |= WepSet_FromWeapon(wpn);
                        else
-                               WEPSET_ANDNOT_EW(e, wpn);
+                               e.weapons &= ~WepSet_FromWeapon(wpn);
                        break;
                case OP_MIN:
                case OP_PLUS:
                        if(val > 0)
-                               WEPSET_OR_EW(e, wpn);
+                               e.weapons |= WepSet_FromWeapon(wpn);
                        break;
                case OP_MAX:
                        if(val <= 0)
-                               WEPSET_ANDNOT_EW(e, wpn);
+                               e.weapons &= ~WepSet_FromWeapon(wpn);
                        break;
                case OP_MINUS:
                        if(val > 0)
-                               WEPSET_ANDNOT_EW(e, wpn);
+                               e.weapons &= ~WepSet_FromWeapon(wpn);
                        break;
        }
-       v1 = WEPSET_CONTAINS_EW(e, wpn);
+       v1 = (e.weapons & WepSet_FromWeapon(wpn));
        return (v0 != v1);
  }
  
@@@ -2110,7 -1508,7 +1718,7 @@@ float GiveBit(entity e, .float fld, flo
                        if(val > 0)
                                e.fld |= bit;
                        else
-                               e.fld &~= bit;
+                               e.fld &= ~bit;
                        break;
                case OP_MIN:
                case OP_PLUS:
                        break;
                case OP_MAX:
                        if(val <= 0)
-                               e.fld &~= bit;
+                               e.fld &= ~bit;
                        break;
                case OP_MINUS:
                        if(val > 0)
-                               e.fld &~= bit;
+                               e.fld &= ~bit;
                        break;
        }
        v1 = (e.fld & bit);
@@@ -2163,12 -1561,12 +1771,12 @@@ void GiveSound(entity e, float v0, floa
        if(v1 <= v0 - t)
        {
                if(snd_decr != "")
-                       sound (e, CH_TRIGGER, snd_decr, VOL_BASE, ATTN_NORM);
+                       sound (e, CH_TRIGGER, snd_decr, VOL_BASE, ATTEN_NORM);
        }
        else if(v0 >= v0 + t)
        {
                if(snd_incr != "")
-                       sound (e, CH_TRIGGER, snd_incr, VOL_BASE, ATTN_NORM);
+                       sound (e, CH_TRIGGER, snd_incr, VOL_BASE, ATTEN_NORM);
        }
  }
  
@@@ -2179,14 -1577,6 +1787,6 @@@ void GiveRot(entity e, float v0, float 
        else if(v0 > v1)
                e.regenfield = max(e.regenfield, time + regentime);
  }
- #define PREGIVE_WEAPONS(e) WEPSET_DECLARE_A(save_weapons); WEPSET_COPY_AE(save_weapons, e)
- #define PREGIVE(e,f) float save_##f; save_##f = (e).f
- #define POSTGIVE_WEAPON(e,b,snd_incr,snd_decr) GiveSound((e), WEPSET_CONTAINS_AW(save_weapons, b), WEPSET_CONTAINS_EW(e, b), 0, snd_incr, snd_decr)
- #define POSTGIVE_BIT(e,f,b,snd_incr,snd_decr) GiveSound((e), save_##f & (b), (e).f & (b), 0, snd_incr, snd_decr)
- #define POSTGIVE_VALUE(e,f,t,snd_incr,snd_decr) GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr)
- #define POSTGIVE_VALUE_ROT(e,f,t,rotfield,rottime,regenfield,regentime,snd_incr,snd_decr) GiveRot((e), save_##f, (e).f, rotfield, rottime, regenfield, regentime); GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr)
  float GiveItems(entity e, float beginarg, float endarg)
  {
        float got, i, j, val, op;
        e.strength_finished = max(0, e.strength_finished - time);
        e.invincible_finished = max(0, e.invincible_finished - time);
        e.superweapons_finished = max(0, e.superweapons_finished - time);
-       
        PREGIVE(e, items);
        PREGIVE_WEAPONS(e);
        PREGIVE(e, strength_finished);
        PREGIVE(e, superweapons_finished);
        PREGIVE(e, ammo_nails);
        PREGIVE(e, ammo_cells);
+       PREGIVE(e, ammo_plasma);
        PREGIVE(e, ammo_shells);
        PREGIVE(e, ammo_rockets);
        PREGIVE(e, ammo_fuel);
                                {
                                        wi = get_weaponinfo(j);
                                        if(wi.weapon)
-                                               if not(wi.spawnflags & WEP_FLAG_MUTATORBLOCKED)
+                                               if (!(wi.spawnflags & WEP_FLAG_MUTATORBLOCKED))
                                                        got += GiveWeapon(e, j, op, val);
                                }
                        case "allammo":
                                got += GiveValue(e, ammo_cells, op, val);
+                               got += GiveValue(e, ammo_plasma, op, val);
                                got += GiveValue(e, ammo_shells, op, val);
                                got += GiveValue(e, ammo_nails, op, val);
                                got += GiveValue(e, ammo_rockets, op, val);
                        case "cells":
                                got += GiveValue(e, ammo_cells, op, val);
                                break;
+                       case "plasma":
+                               got += GiveValue(e, ammo_plasma, op, val);
+                               break;
                        case "shells":
                                got += GiveValue(e, ammo_shells, op, val);
                                break;
                if(wi.weapon)
                {
                        POSTGIVE_WEAPON(e, j, "weapons/weaponpickup.wav", string_null);
-                       if not(WEPSET_CONTAINS_AW(save_weapons, j))
-                               if(WEPSET_CONTAINS_EW(e, j))
-                                       weapon_action(wi.weapon, WR_PRECACHE);
+                       if (!(save_weapons & WepSet_FromWeapon(j)))
+                               if(e.weapons & WepSet_FromWeapon(j))
+                                       WEP_ACTION(wi.weapon, WR_INIT);
                }
        }
        POSTGIVE_VALUE(e, strength_finished, 1, "misc/powerup.wav", "misc/poweroff.wav");
        POSTGIVE_VALUE(e, invincible_finished, 1, "misc/powerup_shield.wav", "misc/poweroff.wav");
        POSTGIVE_VALUE(e, ammo_nails, 0, "misc/itempickup.wav", string_null);
        POSTGIVE_VALUE(e, ammo_cells, 0, "misc/itempickup.wav", string_null);
+       POSTGIVE_VALUE(e, ammo_plasma, 0, "misc/itempickup.wav", string_null);
        POSTGIVE_VALUE(e, ammo_shells, 0, "misc/itempickup.wav", string_null);
        POSTGIVE_VALUE(e, ammo_rockets, 0, "misc/itempickup.wav", string_null);
        POSTGIVE_VALUE_ROT(e, ammo_fuel, 1, pauserotfuel_finished, autocvar_g_balance_pause_fuel_rot, pauseregen_finished, autocvar_g_balance_pause_fuel_regen, "misc/itempickup.wav", string_null);
        POSTGIVE_VALUE_ROT(e, health, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, "misc/megahealth.wav", string_null);
  
        if(e.superweapons_finished <= 0)
-               if(WEPSET_CONTAINS_ANY_EA(self, WEPBIT_SUPERWEAPONS))
+               if(self.weapons & WEPSET_SUPERWEAPONS)
                        e.superweapons_finished = autocvar_g_balance_superweapons_time;
  
-       if (g_minstagib)
-       {
-               e.health = bound(0, e.health, 100);
-               e.armorvalue = bound(0, e.armorvalue, 999);
-       }
        if(e.strength_finished <= 0)
                e.strength_finished = 0;
        else
        else
                e.superweapons_finished += time;
  
-       if not(WEPSET_CONTAINS_EW(e, e.switchweapon))
+       if (!(e.weapons & WepSet_FromWeapon(e.switchweapon)))
                _switchweapon = TRUE;
        if(_switchweapon)
                W_SwitchWeapon_Force(e, w_getbestweapon(e));
index 840858d805dfa4ad5754270fa5c062281765ce87,736cc564cc4c81bffaae6096cddc11b46c8ac867..507c0551b2db4127b10bbe8f7ed21d5b735300b2
@@@ -193,16 -193,11 +193,16 @@@ float WaypointSprite_visible_for_player
                        return FALSE;
  
        // team waypoints
 -      if(self.team && self.rule == SPRITERULE_DEFAULT)
 +      if(self.rule == SPRITERULE_SPECTATOR)
 +      {
-               if(!inWarmupStage && e.classname == "player")
++              if(!warmup_stage && e.classname == "player")
 +                      return FALSE;
 +      }
 +      else if(self.team && self.rule == SPRITERULE_DEFAULT)
        {
                if(self.team != e.team)
                        return FALSE;
-               if(e.classname != "player")
+               if (!IS_PLAYER(e))
                        return FALSE;
        }
  
  
  entity WaypointSprite_getviewentity(entity e)
  {
-       if(e.classname == "spectator")
+       if(IS_SPEC(e))
                e = e.enemy;
        /* TODO idea (check this breaks nothing)
        else if(e.classname == "observer")
@@@ -243,14 -238,8 +243,8 @@@ float WaypointSprite_Customize(
        entity e;
        e = WaypointSprite_getviewentity(other);
  
-       // as a GENERAL rule:
-       // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
-       // but only apply this to real players, not to spectators
-       if(g_minstagib && (self.owner.flags & FL_CLIENT) && (self.owner.items & IT_STRENGTH) && (e == other))
-       {
-               if(!WaypointSprite_isteammate(self.owner, e))
-                       return FALSE;
-       }
+       if(MUTATOR_CALLHOOK(CustomizeWaypoint))
+               return FALSE;
  
        return self.waypointsprite_visible_for_player(e);
  }
@@@ -262,9 -251,9 +256,9 @@@ float WaypointSprite_SendEntity(entity 
        WriteByte(MSG_ENTITY, ENT_CLIENT_WAYPOINT);
  
        sendflags = sendflags & 0x7F;
-       
        if(g_nexball)
-               sendflags &~= 0x80;
+               sendflags &= ~0x80;
        else if(self.max_health || (self.pain_finished && (time < self.pain_finished + 0.25)))
                sendflags |= 0x80;
  
@@@ -473,8 -462,8 +467,8 @@@ entity WaypointSprite_AttachCarrier
        e = WaypointSprite_Spawn(spr, 0, 0, carrier, '0 0 64', world, carrier.team, carrier, waypointsprite_attachedforcarrier, FALSE, icon, rgb);
        if(e)
        {
-               WaypointSprite_UpdateMaxHealth(e, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent) * 2);
-               WaypointSprite_UpdateHealth(e, '1 0 0' * healtharmor_maxdamage(carrier.health, carrier.armorvalue, autocvar_g_balance_armor_blockpercent));
+               WaypointSprite_UpdateMaxHealth(e, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON) * 2);
+               WaypointSprite_UpdateHealth(e, '1 0 0' * healtharmor_maxdamage(carrier.health, carrier.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON));
        }
        return e;
  }