]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Mario/overkill
authorMario <zacjardine@y7mail.com>
Tue, 16 Dec 2014 03:36:30 +0000 (14:36 +1100)
committerMario <zacjardine@y7mail.com>
Tue, 16 Dec 2014 03:36:30 +0000 (14:36 +1100)
139 files changed:
balance-xpm.cfg
binds-default.cfg [new file with mode: 0644]
binds-empty-special.cfg [new file with mode: 0644]
binds-empty.cfg [new file with mode: 0644]
crosshairs.cfg
defaultXonotic.cfg
effects-med.cfg
effects-normal.cfg
gamemodes.cfg
gfx/menu/luminos/skinvalues.txt
gfx/menu/wickedx/skinvalues.txt [changed mode: 0755->0644]
gfx/menu/xaw/skinvalues.txt
keybinds.txt
keybinds.txt.de
keybinds.txt.es
keybinds.txt.fr
keybinds.txt.hu
keybinds.txt.it
keybinds.txt.ru
keybinds.txt.uk
mutators.cfg
qcsrc/Makefile
qcsrc/client/Main.qc
qcsrc/client/View.qc
qcsrc/client/autocvars.qh
qcsrc/client/hud.qc
qcsrc/client/progs.src
qcsrc/client/sys-pre.qh
qcsrc/client/weapons/projectile.qc
qcsrc/common/counting.qh
qcsrc/common/mapinfo.qc
qcsrc/common/mapinfo.qh
qcsrc/common/notifications.qh
qcsrc/common/playerstats.qc [new file with mode: 0644]
qcsrc/common/playerstats.qh [new file with mode: 0644]
qcsrc/common/util-pre.qh
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/fteqcc-bugs.qc [deleted file]
qcsrc/menu/classes.c
qcsrc/menu/item/image.c
qcsrc/menu/item/listbox.c
qcsrc/menu/item/slider.c
qcsrc/menu/item/textslider.c
qcsrc/menu/menu.qc
qcsrc/menu/progs.src
qcsrc/menu/skin-customizables.inc
qcsrc/menu/xonotic/checkbox.c
qcsrc/menu/xonotic/checkbox_string.c
qcsrc/menu/xonotic/demolist.c
qcsrc/menu/xonotic/dialog_multiplayer.c
qcsrc/menu/xonotic/dialog_multiplayer_create.c
qcsrc/menu/xonotic/dialog_multiplayer_create_advanced.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c
qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c
qcsrc/menu/xonotic/dialog_multiplayer_demo.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_join.c
qcsrc/menu/xonotic/dialog_multiplayer_media.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_media_demo.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_playersetup.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_playersetup_crosshair.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_playersetup_hud.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_playersetup_hudconfirm.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_playersetup_model.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_playersetup_view.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_playersetup_weapons.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_profile.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings.c
qcsrc/menu/xonotic/dialog_settings_audio.c
qcsrc/menu/xonotic/dialog_settings_effects.c
qcsrc/menu/xonotic/dialog_settings_game.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_crosshair.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_hud.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_messages.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_model.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_view.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_weapons.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_input.c
qcsrc/menu/xonotic/dialog_settings_misc.c
qcsrc/menu/xonotic/dialog_settings_misc_cvars.c
qcsrc/menu/xonotic/dialog_settings_misc_reset.c [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_user.c
qcsrc/menu/xonotic/dialog_settings_video.c
qcsrc/menu/xonotic/gametypelist.c
qcsrc/menu/xonotic/inputbox.c
qcsrc/menu/xonotic/keybinder.c
qcsrc/menu/xonotic/mainwindow.c
qcsrc/menu/xonotic/screenshotimage.c [new file with mode: 0644]
qcsrc/menu/xonotic/screenshotlist.c [new file with mode: 0644]
qcsrc/menu/xonotic/serverlist.c
qcsrc/menu/xonotic/slider.c
qcsrc/menu/xonotic/slider_sbfadetime.c [new file with mode: 0644]
qcsrc/menu/xonotic/statslist.c [new file with mode: 0644]
qcsrc/menu/xonotic/textlabel.c
qcsrc/menu/xonotic/textslider.c
qcsrc/menu/xonotic/util.qc
qcsrc/menu/xonotic/util.qh
qcsrc/server/autocvars.qh
qcsrc/server/cl_client.qc
qcsrc/server/cl_physics.qc
qcsrc/server/cl_player.qc
qcsrc/server/command/vote.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_world.qc
qcsrc/server/mapvoting.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/mutator_instagib.qc
qcsrc/server/playerstats.qh [deleted file]
qcsrc/server/progs.src
qcsrc/server/scores.qc
qcsrc/server/scores.qh
qcsrc/server/t_items.qc
qcsrc/server/weapons/accuracy.qc
qcsrc/server/weapons/tracing.qc
scripts/player_erebus.shader [new file with mode: 0644]
scripts/player_gak.shader [new file with mode: 0644]
scripts/player_ignis.shader [new file with mode: 0644]
scripts/player_nyx.shader [new file with mode: 0644]
scripts/player_pyria.shader [new file with mode: 0644]
scripts/player_seraphina.shader [new file with mode: 0644]
scripts/player_umbra.shader [new file with mode: 0644]
scripts/pyria.shader [deleted file]
textures/erebus_reflect.tga [new file with mode: 0644]
textures/erebusfullbright_reflect.tga [new file with mode: 0644]
textures/gak_reflect.tga [new file with mode: 0644]
textures/gakarmor_reflect.tga [new file with mode: 0644]
textures/ignis_reflect.tga [new file with mode: 0644]
textures/ignishead_reflect.tga [new file with mode: 0644]
textures/nyx_reflect.tga [new file with mode: 0644]
textures/pyria_reflect.jpg [new file with mode: 0644]
textures/seraphina_reflect.jpg [new file with mode: 0644]
textures/shadowhead_reflect.tga [new file with mode: 0644]
textures/umbra_reflect.jpg [new file with mode: 0644]

index d12637da71f3478ccc92321c66f616f00310dc2e..c254bcdf8d5118efd4b5f1aec0d687c609c63388 100644 (file)
@@ -188,7 +188,7 @@ set g_maxpushtime 8.0 "timeout for kill credit when your damage knocks someone i
 // }}}
 
 // {{{ powerups
-set g_balance_powerup_invincible_takedamage 0.33 // only 1/3th damage is taken
+set g_balance_powerup_invincible_takedamage 0.33 // only 1/3rd damage is taken
 set g_balance_powerup_invincible_time 30
 set g_balance_powerup_strength_damage 3
 set g_balance_powerup_strength_force 3
diff --git a/binds-default.cfg b/binds-default.cfg
new file mode 100644 (file)
index 0000000..f48842f
--- /dev/null
@@ -0,0 +1,155 @@
+// alias for switching the teamselect menu
+bind f5 menu_showteamselect
+
+bind f6 team_auto
+
+bind f7 menu_showsandboxtools
+
+// 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
+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
+
+// 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_here_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"
\ No newline at end of file
diff --git a/binds-empty-special.cfg b/binds-empty-special.cfg
new file mode 100644 (file)
index 0000000..31a33d7
--- /dev/null
@@ -0,0 +1,161 @@
+bind AUX1 ""
+bind AUX2 ""
+bind AUX3 ""
+bind AUX4 ""
+bind AUX5 ""
+bind AUX6 ""
+bind AUX7 ""
+bind AUX8 ""
+bind AUX9 ""
+bind AUX10 ""
+bind AUX11 ""
+bind AUX12 ""
+bind AUX13 ""
+bind AUX14 ""
+bind AUX15 ""
+bind AUX16 ""
+bind AUX17 ""
+bind AUX18 ""
+bind AUX19 ""
+bind AUX20 ""
+bind AUX21 ""
+bind AUX22 ""
+bind AUX23 ""
+bind AUX24 ""
+bind AUX25 ""
+bind AUX26 ""
+bind AUX27 ""
+bind AUX28 ""
+bind AUX29 ""
+bind AUX30 ""
+bind AUX31 ""
+bind AUX32 ""
+
+bind MIDINOTE0 ""
+bind MIDINOTE1 ""
+bind MIDINOTE2 ""
+bind MIDINOTE3 ""
+bind MIDINOTE4 ""
+bind MIDINOTE5 ""
+bind MIDINOTE6 ""
+bind MIDINOTE7 ""
+bind MIDINOTE8 ""
+bind MIDINOTE9 ""
+bind MIDINOTE10 ""
+bind MIDINOTE11 ""
+bind MIDINOTE12 ""
+bind MIDINOTE13 ""
+bind MIDINOTE14 ""
+bind MIDINOTE15 ""
+bind MIDINOTE16 ""
+bind MIDINOTE17 ""
+bind MIDINOTE18 ""
+bind MIDINOTE19 ""
+bind MIDINOTE20 ""
+bind MIDINOTE21 ""
+bind MIDINOTE22 ""
+bind MIDINOTE23 ""
+bind MIDINOTE24 ""
+bind MIDINOTE25 ""
+bind MIDINOTE26 ""
+bind MIDINOTE27 ""
+bind MIDINOTE28 ""
+bind MIDINOTE29 ""
+bind MIDINOTE30 ""
+bind MIDINOTE31 ""
+bind MIDINOTE32 ""
+bind MIDINOTE33 ""
+bind MIDINOTE34 ""
+bind MIDINOTE35 ""
+bind MIDINOTE36 ""
+bind MIDINOTE37 ""
+bind MIDINOTE38 ""
+bind MIDINOTE39 ""
+bind MIDINOTE40 ""
+bind MIDINOTE41 ""
+bind MIDINOTE42 ""
+bind MIDINOTE43 ""
+bind MIDINOTE44 ""
+bind MIDINOTE45 ""
+bind MIDINOTE46 ""
+bind MIDINOTE47 ""
+bind MIDINOTE48 ""
+bind MIDINOTE49 ""
+bind MIDINOTE50 ""
+bind MIDINOTE51 ""
+bind MIDINOTE52 ""
+bind MIDINOTE53 ""
+bind MIDINOTE54 ""
+bind MIDINOTE55 ""
+bind MIDINOTE56 ""
+bind MIDINOTE57 ""
+bind MIDINOTE58 ""
+bind MIDINOTE59 ""
+bind MIDINOTE60 ""
+bind MIDINOTE61 ""
+bind MIDINOTE62 ""
+bind MIDINOTE63 ""
+bind MIDINOTE64 ""
+bind MIDINOTE65 ""
+bind MIDINOTE66 ""
+bind MIDINOTE67 ""
+bind MIDINOTE68 ""
+bind MIDINOTE69 ""
+bind MIDINOTE70 ""
+bind MIDINOTE71 ""
+bind MIDINOTE72 ""
+bind MIDINOTE73 ""
+bind MIDINOTE74 ""
+bind MIDINOTE75 ""
+bind MIDINOTE76 ""
+bind MIDINOTE77 ""
+bind MIDINOTE78 ""
+bind MIDINOTE79 ""
+bind MIDINOTE80 ""
+bind MIDINOTE81 ""
+bind MIDINOTE82 ""
+bind MIDINOTE83 ""
+bind MIDINOTE84 ""
+bind MIDINOTE85 ""
+bind MIDINOTE86 ""
+bind MIDINOTE87 ""
+bind MIDINOTE88 ""
+bind MIDINOTE89 ""
+bind MIDINOTE90 ""
+bind MIDINOTE91 ""
+bind MIDINOTE92 ""
+bind MIDINOTE93 ""
+bind MIDINOTE94 ""
+bind MIDINOTE95 ""
+bind MIDINOTE96 ""
+bind MIDINOTE97 ""
+bind MIDINOTE98 ""
+bind MIDINOTE99 ""
+bind MIDINOTE100 ""
+bind MIDINOTE101 ""
+bind MIDINOTE102 ""
+bind MIDINOTE103 ""
+bind MIDINOTE104 ""
+bind MIDINOTE105 ""
+bind MIDINOTE106 ""
+bind MIDINOTE107 ""
+bind MIDINOTE108 ""
+bind MIDINOTE109 ""
+bind MIDINOTE110 ""
+bind MIDINOTE111 ""
+bind MIDINOTE112 ""
+bind MIDINOTE113 ""
+bind MIDINOTE114 ""
+bind MIDINOTE115 ""
+bind MIDINOTE116 ""
+bind MIDINOTE117 ""
+bind MIDINOTE118 ""
+bind MIDINOTE119 ""
+bind MIDINOTE120 ""
+bind MIDINOTE121 ""
+bind MIDINOTE122 ""
+bind MIDINOTE123 ""
+bind MIDINOTE124 ""
+bind MIDINOTE125 ""
+bind MIDINOTE126 ""
+bind MIDINOTE127 ""
\ No newline at end of file
diff --git a/binds-empty.cfg b/binds-empty.cfg
new file mode 100644 (file)
index 0000000..51112bf
--- /dev/null
@@ -0,0 +1,144 @@
+bind TAB ""
+bind ENTER ""
+bind ESCAPE ""
+bind SPACE ""
+
+bind BACKSPACE ""
+bind UPARROW ""
+bind DOWNARROW ""
+bind LEFTARROW ""
+bind RIGHTARROW ""
+
+bind ALT ""
+bind CTRL ""
+bind SHIFT ""
+
+bind F1 ""
+bind F2 ""
+bind F3 ""
+bind F4 ""
+bind F5 ""
+bind F6 ""
+bind F7 ""
+bind F8 ""
+bind F9 ""
+bind F10 ""
+bind F11 ""
+bind F12 ""
+
+bind INS ""
+bind DEL ""
+bind PGDN ""
+bind PGUP ""
+bind HOME ""
+bind END ""
+
+bind PAUSE ""
+
+bind NUMLOCK ""
+bind CAPSLOCK ""
+bind SCROLLOCK ""
+
+bind KP_INS ""
+bind KP_0 ""
+bind KP_END ""
+bind KP_1 ""
+bind KP_DOWNARROW ""
+bind KP_2 ""
+bind KP_PGDN ""
+bind KP_3 ""
+bind KP_LEFTARROW ""
+bind KP_4 ""
+bind KP_5 ""
+bind KP_RIGHTARROW ""
+bind KP_6 ""
+bind KP_HOME ""
+bind KP_7 ""
+bind KP_UPARROW ""
+bind KP_8 ""
+bind KP_PGUP ""
+bind KP_9 ""
+bind KP_DEL ""
+bind KP_PERIOD ""
+bind KP_SLASH ""
+bind KP_DIVIDE ""
+bind KP_MULTIPLY ""
+bind KP_MINUS ""
+bind KP_PLUS ""
+bind KP_ENTER ""
+bind KP_EQUALS ""
+
+bind PRINTSCREEN ""
+
+bind SEMICOLON ""
+bind TILDE ""
+bind BACKQUOTE ""
+bind QUOTE ""
+bind APOSTROPHE ""
+bind BACKSLASH ""
+
+bind MOUSE1 ""
+bind MOUSE2 ""
+bind MOUSE3 ""
+bind MWHEELUP ""
+bind MWHEELDOWN ""
+bind MOUSE4 ""
+bind MOUSE5 ""
+bind MOUSE6 ""
+bind MOUSE7 ""
+bind MOUSE8 ""
+bind MOUSE9 ""
+bind MOUSE10 ""
+bind MOUSE11 ""
+bind MOUSE12 ""
+bind MOUSE13 ""
+bind MOUSE14 ""
+bind MOUSE15 ""
+bind MOUSE16 ""
+
+bind JOY1 ""
+bind JOY2 ""
+bind JOY3 ""
+bind JOY4 ""
+bind JOY5 ""
+bind JOY6 ""
+bind JOY7 ""
+bind JOY8 ""
+bind JOY9 ""
+bind JOY10 ""
+bind JOY11 ""
+bind JOY12 ""
+bind JOY13 ""
+bind JOY14 ""
+bind JOY15 ""
+bind JOY16 ""
+
+bind JOY_UP ""
+bind JOY_DOWN ""
+bind JOY_LEFT ""
+bind JOY_RIGHT ""
+
+bind X360_DPAD_UP ""
+bind X360_DPAD_DOWN ""
+bind X360_DPAD_LEFT ""
+bind X360_DPAD_RIGHT ""
+bind X360_START ""
+bind X360_BACK ""
+bind X360_LEFT_THUMB ""
+bind X360_RIGHT_THUMB ""
+bind X360_LEFT_SHOULDER ""
+bind X360_RIGHT_SHOULDER ""
+bind X360_A ""
+bind X360_B ""
+bind X360_X ""
+bind X360_Y ""
+bind X360_LEFT_TRIGGER ""
+bind X360_RIGHT_TRIGGER ""
+bind X360_LEFT_THUMB_UP ""
+bind X360_LEFT_THUMB_DOWN ""
+bind X360_LEFT_THUMB_LEFT ""
+bind X360_LEFT_THUMB_RIGHT ""
+bind X360_RIGHT_THUMB_UP ""
+bind X360_RIGHT_THUMB_DOWN ""
+bind X360_RIGHT_THUMB_LEFT ""
+bind X360_RIGHT_THUMB_RIGHT ""
\ No newline at end of file
index c94d3a5fb7a1962300d656540cd5420d140fd910..52ae30cb5baaf085432fca0cfc6c5a3af41a2ed6 100644 (file)
@@ -32,8 +32,9 @@ seta crosshair_hitindication_speed 5
 
 // hit testing/tracing for special effects for the crosshair
 set g_trueaim_minrange 44 "TrueAim minimum range (TrueAim adjusts shots so they hit the crosshair point even though the gun is not at the screen center)"
-seta crosshair_hittest 1 "do a crosshair hit evaluation; also, the crosshair is scaled by the given number when aiming at an enemy, and blurred when aiming at a team mate"
+seta crosshair_hittest 1 "do a crosshair hit evaluation, applying effects from the _blur, _scale, and _showipact cvars"
 seta crosshair_hittest_blur 1 "blur the crosshair if the shot is obstructed"
+seta crosshair_hittest_scale 1.25 "enlarge crosshair if aiming at an enemy, shrink crosshair if shot is obstructed or aiming at a teammate"
 seta crosshair_hittest_showimpact 0 "move the crosshair to the actual impact location if obstructed"
 
 // change color based on special case
index 8fe7f7d94ad755c7d366a8bde497d176d6e0a3a7..2939ddf98df7f07340feac19c4d481ed1c320e9a 100644 (file)
@@ -44,8 +44,6 @@ 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
 
@@ -60,7 +58,8 @@ seta cl_reticle_stretch 0 "whether to stretch reticles so they fit the screen (b
 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 100
-seta cl_velocityzoom 0 "velocity based zooming of fov, negative values zoom out"
+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"
@@ -226,7 +225,7 @@ 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"
@@ -420,8 +419,6 @@ set g_pickup_items -1 "if set to 0 all items (health, armor, ammo, weapons...) a
 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_blaster "1"      "additionally, always provide the blaster 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_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!)"
@@ -459,8 +456,6 @@ seta menu_sandbox_edit_physics 1
 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
@@ -629,19 +624,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"
@@ -654,102 +636,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
 
 // score log
 set sv_logscores_console 0     "print scores to server console"
@@ -895,43 +781,7 @@ set g_banned_list_idmode "1"       "when set, the IP banning system always uses the ID
 
 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_here_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
@@ -1177,8 +1027,6 @@ seta cl_clippedspectating 1 "movement collision for spectators so that you can't
 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."
 
 // 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"
@@ -1313,8 +1161,6 @@ set sv_accuracy_data_send 1 "1 send weapon accuracy data statistics and improved
 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"
index 75f7250bd95b34d5fbf70aebba7ba81d7cc407c5..84df44948e2e4b602f96c4db88e07c60fefb1b3f 100644 (file)
@@ -6,7 +6,7 @@ cl_particles_quality 0.8
 cl_damageeffect 0
 cl_spawn_point_particles 0
 cl_playerdetailreduction 4
-cl_cubemaps_extra 1
+cl_cubemaps_extra 0
 gl_flashblend 0
 gl_picmip 0
 mod_q3bsp_nolightmaps 0
index b1a967509e7e0b41d0bfc699fcbad2e85bbbd982..27756437effdb9292acc2b070a844a6f6deea0f5 100644 (file)
@@ -6,7 +6,7 @@ cl_particles_quality 1.0
 cl_damageeffect 1
 cl_spawn_point_particles 1
 cl_playerdetailreduction 4
-cl_cubemaps_extra 1
+cl_cubemaps_extra 0
 gl_flashblend 0
 gl_picmip 0
 mod_q3bsp_nolightmaps 0
index c31f7f9013a9d4e4e0fc26262175878985d71ecd..b6cbe92cfcba116c79de77e667e30d35d2c6601a 100644 (file)
@@ -18,6 +18,7 @@ alias asay_drop "say_team (%l) dropped %w ; impulse 17"
 // =================
 //  gamestart hooks
 // =================
+seta cl_matchcount 0 // incremented by cl_hook_gameend and used by playerstats to know when to 
 alias _cl_hook_gamestart "set _cl_hook_gametype $1; _cl_hook_gamestart_stage2"
 alias _cl_hook_gamestart_stage2 "cl_hook_gamestart_all; cl_hook_gamestart_${_cl_hook_gametype}"
 alias cl_hook_gamestart_all
@@ -37,7 +38,7 @@ alias cl_hook_gamestart_cts
 alias cl_hook_gamestart_ka
 alias cl_hook_gamestart_ft
 alias cl_hook_gamestart_inv
-alias cl_hook_gameend
+alias cl_hook_gameend "rpn /cl_matchcount dup load 1 + =" // increase match count every time a game ends
 alias cl_hook_activeweapon
 
 alias _sv_hook_gamestart "set _sv_hook_gametype $1; _sv_hook_gamestart_stage2"
index 025475ab746ad5962d9c004f1ac84e6373fe4841..dcab8a45e1fbda88a0f2267d41a1eee814d68356 100755 (executable)
@@ -23,7 +23,7 @@ MARGIN_COLORPICKER              '0 0 0'
 //   uses "border" images
 //   uses "closebutton" images
 MARGIN_TOP                      8
-MARGIN_BOTTOM                   12
+MARGIN_BOTTOM                   16
 MARGIN_LEFT                     16
 MARGIN_RIGHT                    16
 MARGIN_COLUMNS                  4
@@ -47,6 +47,8 @@ ALPHA_DISABLED                  0.2
 ALPHA_BEHIND                    0.5
 ALPHA_TEXT                      0.7
 COLOR_TEXT                      '1 1 1'
+ALPHA_HEADER                    0.5
+COLOR_HEADER                    '1 1 1'
 
 // mouse
 //   uses "cursor" images
@@ -142,6 +144,12 @@ COLOR_SERVERLIST_CATEGORY       '1 1 1'
 COLOR_SKINLIST_TITLE            '1 1 1'
 COLOR_SKINLIST_AUTHOR           '0.6875 0.84375 1'
 
+// item: demo list
+COLOR_DEMOLIST_SUBDIR           '0.5 0.5 0.5'
+
+// item: screenshot list
+COLOR_SCREENSHOTLIST_SUBDIR     '0.5 0.5 0.5'
+
 //------------------------------------------------------------------------------
 // Images (colors multiplied to images)
 //------------------------------------------------------------------------------
@@ -184,6 +192,7 @@ COLOR_DIALOG_MODEL              '1 1 1'
 COLOR_DIALOG_CROSSHAIR          '1 1 1'
 COLOR_DIALOG_HUD                '1 1 1'
 COLOR_DIALOG_SERVERINFO         '1 1 1'
+COLOR_DIALOG_SCREENSHOTVIEWER   '1 1 1'
 COLOR_DIALOG_CVARS              '1 0 0'
 COLOR_DIALOG_HUDCONFIRM         '1 0 0'
 
old mode 100755 (executable)
new mode 100644 (file)
index c5062d9..94eb09a
@@ -23,7 +23,7 @@ MARGIN_COLORPICKER              '0 0 0'
 //   uses "border" images
 //   uses "closebutton" images
 MARGIN_TOP                      8
-MARGIN_BOTTOM                   12
+MARGIN_BOTTOM                   16
 MARGIN_LEFT                     16
 MARGIN_RIGHT                    16
 MARGIN_COLUMNS                  4
@@ -47,6 +47,8 @@ ALPHA_DISABLED                  0.2
 ALPHA_BEHIND                    0.5
 ALPHA_TEXT                      0.7
 COLOR_TEXT                      '1 1 1'
+ALPHA_HEADER                    0.5
+COLOR_HEADER                    '1 1 1'
 
 // mouse
 //   uses "cursor" images
@@ -142,6 +144,12 @@ COLOR_SERVERLIST_CATEGORY       '1 1 1'
 COLOR_SKINLIST_TITLE            '1 1 1'
 COLOR_SKINLIST_AUTHOR           '0 0.375 0.75'
 
+// item: demo list
+COLOR_DEMOLIST_SUBDIR           '0.5 0.5 0.5'
+
+// item: screenshot list
+COLOR_SCREENSHOTLIST_SUBDIR     '0.5 0.5 0.5'
+
 //------------------------------------------------------------------------------
 // Images (colors multiplied to images)
 //------------------------------------------------------------------------------
@@ -184,6 +192,7 @@ COLOR_DIALOG_MODEL              '1 1 1'
 COLOR_DIALOG_CROSSHAIR          '1 1 1'
 COLOR_DIALOG_HUD                '1 1 1'
 COLOR_DIALOG_SERVERINFO         '1 1 1'
+COLOR_DIALOG_SCREENSHOTVIEWER   '1 1 1'
 COLOR_DIALOG_CVARS              '1 0 0'
 COLOR_DIALOG_HUDCONFIRM         '1 0 0'
 
index 2dc86f698f19f531bfcf7aa99798fcc8d051f8b5..6cf666fce5c109cedd7c5759cd0a03915d5f7940 100644 (file)
@@ -36,6 +36,7 @@ COLOR_DIALOG_MODEL              '1 1 1'
 COLOR_DIALOG_CROSSHAIR          '1 1 1'
 COLOR_DIALOG_HUD                '1 1 1'
 COLOR_DIALOG_SERVERINFO         '1 1 1'
+COLOR_DIALOG_SCREENSHOTVIEWER   '1 1 1'
 COLOR_DIALOG_CVARS              '1 0 0'
 COLOR_DIALOG_HUDCONFIRM         '1 0 0'
 
@@ -63,6 +64,8 @@ ALPHA_DISABLED                  0.2
 ALPHA_BEHIND                    1
 ALPHA_TEXT                      0.7
 COLOR_TEXT                      '1 1 1'
+ALPHA_HEADER                    0.5
+COLOR_HEADER                    '1 1 1'
 
 // item: button
 //   uses "button" images
@@ -118,7 +121,7 @@ COLOR_CVARLIST_CONTROLS         '1 0 0'
 //   uses "border" images
 //   uses "closebutton" images
 MARGIN_TOP                      8
-MARGIN_BOTTOM                   12
+MARGIN_BOTTOM                   16
 MARGIN_LEFT                     16
 MARGIN_RIGHT                    16
 MARGIN_COLUMNS                  4
@@ -209,6 +212,12 @@ COLOR_SERVERINFO_IP             '0 0 0'
 COLOR_SKINLIST_TITLE            '1 1 1'
 COLOR_SKINLIST_AUTHOR           '0.5 0.5 0.5'
 
+// item: demo list
+COLOR_DEMOLIST_SUBDIR           '0.5 0.5 0.5'
+
+// item: screenshot list
+COLOR_SCREENSHOTLIST_SUBDIR     '0.5 0.5 0.5'
+
 // item: slider
 //   uses "slider" images
 COLOR_SLIDER_N                  '1 1 1'
index 95d24acdbd67f30279c8f2f18aa94134dd2838a4..0458a548f06839238c17ee38cb0484d04b48a118 100644 (file)
 "weaplast"                              "previously used"
 "weapbest"                              "best"
 "reload"                                "reload"
-"weapon_group_1"                        "Laser"
+"weapon_group_1"                        "Blaster"
 "weapon_group_2"                        "Shotgun"
-"weapon_group_3"                        "Machine Gun"
+"weapon_group_3"                        "Machine Gun / Arc"
 "weapon_group_4"                        "Mortar / Mine Layer"
 "weapon_group_5"                        "Electro"
 "weapon_group_6"                        "Crylink / HLAC"
-"weapon_group_7"                        "Nex / Rifle"
+"weapon_group_7"                        "Vortex / Rifle"
 "weapon_group_8"                        "Hagar / Seeker"
-"weapon_group_9"                        "Rocket Launcher / Fireball"
+"weapon_group_9"                        "Devastator / Fireball"
 "weapon_group_0"                        "Port-O-Launch / Hook"
 ""                                      ""
 ""                                      "View"
index 85d34b95723301db8d66a21e5b65341d33ca2ef4..9a6d9e98272e3214c8e8bdb86fef39f2f169c5fa 100644 (file)
 "weaplast"                              "zuletzt benutzte"
 "weapbest"                              "beste"
 "reload"                                "nachladen"
-"weapon_group_1"                        "Laser"
+"weapon_group_1"                        "Blaster"
 "weapon_group_2"                        "Schrotgewehr"
-"weapon_group_3"                        "Maschinengewehr"
+"weapon_group_3"                        "Maschinengewehr / Arc"
 "weapon_group_4"                        "Mortar / Mine Layer"
 "weapon_group_5"                        "Electro"
 "weapon_group_6"                        "Crylink / HLAC"
-"weapon_group_7"                        "Nex / Gewehr"
+"weapon_group_7"                        "Vortex / Gewehr"
 "weapon_group_8"                        "Hagar / Seeker"
-"weapon_group_9"                        "Rocket Launcher / Fireball"
+"weapon_group_9"                        "Devastator / Fireball"
 "weapon_group_0"                        "Port-O-Launch / Enterhaken"
 ""                                      ""
 ""                                      "Anzeige"
index 0c3b8364c203f1e130de8c9d092b96f311ad17fa..e7c2fd7441fe7f83624dde0475565684be997ed5 100644 (file)
 "weaplast"                              "anteriormente usado"
 "weapbest"                              "mejor"
 "reload"                                "recargar"
-"weapon_group_1"                        "Laser"
+"weapon_group_1"                        "Blaster"
 "weapon_group_2"                        "Shotgun"
-"weapon_group_3"                        "Machine Gun"
+"weapon_group_3"                        "Machine Gun / Arc"
 "weapon_group_4"                        "Mortar / Mine Layer"
 "weapon_group_5"                        "Electro"
 "weapon_group_6"                        "Crylink / HLAC"
-"weapon_group_7"                        "Nex / Rifle"
+"weapon_group_7"                        "Vortex / Rifle"
 "weapon_group_8"                        "Hagar / Seeker"
-"weapon_group_9"                        "Rocket Launcher / Fireball"
+"weapon_group_9"                        "Devastator / Fireball"
 "weapon_group_0"                        "Port-O-Launch / Hook"
 ""                                      ""
 ""                                      "Vista"
index 17ac95409331156a0b3d4973815b055379a2d10b..09ee3e3e7707b100a4ab62ed929bc4b7a9a82da4 100644 (file)
 "reload"                                "recharger"
 "weapon_group_1"                        "Laser"
 "weapon_group_2"                        "Fusil"
-"weapon_group_3"                        "Mitrailleuse"
+"weapon_group_3"                        "Mitrailleuse / Arc"
 "weapon_group_4"                        "Mortier / Poseur de Mines"
 "weapon_group_5"                        "Electro"
 "weapon_group_6"                        "Crylink / HLAC"
-"weapon_group_7"                        "Nex / Fusil de précision"
+"weapon_group_7"                        "Vortex / Fusil de précision"
 "weapon_group_8"                        "Hagar / Seeker"
 "weapon_group_9"                        "Lance-roquettes / Fireball"
 "weapon_group_0"                        "Port-O-Launch / Grappin"
index c4e418d120fef0551819ecc39dfe180a79b1c2ff..53bd46c14341b30d194beba4c6abe1c168f5b7a8 100644 (file)
 "reload"                                "újratöltés"
 "weapon_group_1"                        "Lézer"
 "weapon_group_2"                        "Vadászpuska"
-"weapon_group_3"                        "Géppuska"
+"weapon_group_3"                        "Géppuska / Arc"
 "weapon_group_4"                        "Mortar / Aknavető"
 "weapon_group_5"                        "Electro"
 "weapon_group_6"                        "Crylink / HLAC"
-"weapon_group_7"                        "Nex / Puska"
+"weapon_group_7"                        "Vortex / Puska"
 "weapon_group_8"                        "Hagar / Seeker"
 "weapon_group_9"                        "Rakétavető / Tűzlabda"
 "weapon_group_0"                        "Port-O-Launch / Kampó"
index e46ef92440616e732199569bf175ba717b8042d6..8546bdbe8f1c5d74e26857acb08b78f34b65e873 100644 (file)
 "weaplast"                              "ultima usata"
 "weapbest"                              "migliore"
 "reload"                                "ricarica"
-"weapon_group_1"                        "Laser"
+"weapon_group_1"                        "Blaster"
 "weapon_group_2"                        "Shotgun"
-"weapon_group_3"                        "Machine Gun"
+"weapon_group_3"                        "Machine Gun / Arc"
 "weapon_group_4"                        "Mortar / Mine Layer"
 "weapon_group_5"                        "Electro"
 "weapon_group_6"                        "Crylink / HLAC"
-"weapon_group_7"                        "Nex / Rifle"
+"weapon_group_7"                        "Vortex / Rifle"
 "weapon_group_8"                        "Hagar / Seeker"
-"weapon_group_9"                        "Rocket Launcher / Fireball"
+"weapon_group_9"                        "Devastator / Fireball"
 "weapon_group_0"                        "Port-O-Launch / Hook"
 ""                                      ""
 ""                                      "Vista"
index 3431c25f67e721fec122dfea5a8b5e37167b430d..3ca70768e26591c49b5ce8787cd9ae9783cb6608 100644 (file)
 "weaplast"                              "ранее использованное"
 "weapbest"                              "лучшее"
 "reload"                                "перезарядить"
-"weapon_group_1"                        "Laser"
+"weapon_group_1"                        "Blaster"
 "weapon_group_2"                        "Shotgun"
-"weapon_group_3"                        "Machine Gun"
+"weapon_group_3"                        "Machine Gun / Arc"
 "weapon_group_4"                        "Mortar / Mine Layer"
 "weapon_group_5"                        "Electro"
 "weapon_group_6"                        "Crylink / HLAC"
-"weapon_group_7"                        "Nex / Rifle"
+"weapon_group_7"                        "Vortex / Rifle"
 "weapon_group_8"                        "Hagar / Seeker"
 "weapon_group_9"                        "Rocket Launcher / Fireball"
 "weapon_group_0"                        "Port-O-Launch / Hook"
index eae9049c1dddfe833b867b90d042eda509ae4c47..8fc522a82d4840c706ae2423c22dac800e6d7929 100644 (file)
@@ -19,7 +19,7 @@
 "reload"                                "перезарядити"
 "weapon_group_1"                        "Лазер"
 "weapon_group_2"                        "Рушниця"
-"weapon_group_3"                        "Автомат"
+"weapon_group_3"                        "Автомат / Arc"
 "weapon_group_4"                        "Мортира / Міноукладчик"
 "weapon_group_5"                        "Електро"
 "weapon_group_6"                        "Крайлінк / ВЛШГ"
index adfcd240522d7e07f21cbbecef049650c0ec755b..e8221b4f084a93936e20d5972a338c0bf1c43279 100644 (file)
@@ -68,6 +68,13 @@ set g_overkill_ammo_decharge_hmg 0.01
 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"
 
 
+// ========
+//  midair
+// ========
+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"
+
+
 // =========
 //  sandbox
 // =========
index edac7388c10b06cedfa04d9a13038fcb32a08d79..9fde71e103e2bdeb1030c1c06545d60ee9aac231 100644 (file)
@@ -35,7 +35,7 @@ $(QCCVERSIONFILE):
        $(RM) qccversion.*
        echo This file intentionally left blank. > $@
 
-FILES_CSPROGS = $(shell find client common warpzonelib csqcmodellib -type f -not -name fteqcc.log -not -name qc.asm) $(wildcard server/w_*.qc)
+FILES_CSPROGS = $(shell find client common warpzonelib csqcmodellib -type f -not -name fteqcc.log -not -name qc.asm)
 ../csprogs.dat: $(FILES_CSPROGS) $(QCCVERSIONFILE)
        @echo make[1]: Entering directory \`$(PWD)/client\'
        cd client && $(QCC) $(QCCFLAGS)
@@ -43,12 +43,12 @@ FILES_CSPROGS = $(shell find client common warpzonelib csqcmodellib -type f -not
 server/precache-for-csqc.inc: $(FILES_CSPROGS)
        sh collect-precache.sh
 
-FILES_PROGS = $(shell find server common warpzonelib csqcmodellib -type f -not -name fteqcc.log -not -name qc.asm) $(wildcard server/w_*.qc)
+FILES_PROGS = $(shell find server common warpzonelib csqcmodellib -type f -not -name fteqcc.log -not -name qc.asm)
 ../progs.dat: $(FILES_PROGS) $(QCCVERSIONFILE) server/precache-for-csqc.inc
        @echo make[1]: Entering directory \`$(PWD)/server\'
        cd server && $(QCC) $(QCCFLAGS)
 
-FILES_MENU = $(shell find menu common warpzonelib -type f -not -name fteqcc.log -not -name qc.asm) $(wildcard server/w_*.qc)
+FILES_MENU = $(shell find menu common warpzonelib -type f -not -name fteqcc.log -not -name qc.asm)
 ../menu.dat: $(FILES_MENU) $(QCCVERSIONFILE)
        @echo make[1]: Entering directory \`$(PWD)/menu\'
        cd menu && $(QCC) $(QCCFLAGS)
index d1fe46d235f5b609d1dbc1951df875e844fcabec..58bd4f497478544bb9527df0388a9f68454c7658 100644 (file)
@@ -28,29 +28,12 @@ void menu_sub_null()
 {
 }
 
-#ifdef USE_FTE
-float __engine_check;
-#endif
-
 string forcefog;
 void WaypointSprite_Load();
 void ConsoleCommand_macro_init();
 void CSQC_Init(void)
 {
        prvm_language = cvar_string("prvm_language");
-#ifdef USE_FTE
-#pragma target ID
-       __engine_check = checkextension("DP_SV_WRITEPICTURE");
-       if(!__engine_check)
-       {
-               print(_("^3Your engine build is outdated\n^3This Server uses a newer QC VM. Please update!\n"));
-               localcmd("\ndisconnect\n");
-               return;
-       }
-#pragma target FTE
-#endif
-
-       check_unacceptable_compiler_bugs();
 
 #ifdef WATERMARK
        dprintf("^4CSQC Build information: ^1%s\n", WATERMARK);
@@ -167,13 +150,6 @@ void CSQC_Init(void)
 // CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc)
 void Shutdown(void)
 {
-#ifdef USE_FTE
-#pragma TARGET id
-       if(!__engine_check)
-               return 0;
-#pragma TARGET fte
-#endif
-
        WarpZone_Shutdown();
 
        remove(teams);
index 120b682a3020f083e28856052cd5980d74c17129..0a5f73b55fe05a3eda69637907e5642e50fd44e6 100644 (file)
@@ -162,7 +162,7 @@ vector GetCurrentFov(float fov)
        else
                setsensitivityscale(1);
 
-       if(autocvar_cl_velocityzoom && autocvar_cl_velocityzoom_type) // _type = 0 disables velocity zoom too
+       if(autocvar_cl_velocityzoom_enabled && autocvar_cl_velocityzoom_type) // _type = 0 disables velocity zoom too
        {
                if(intermission) { curspeed = 0; }
                else
@@ -183,7 +183,7 @@ vector GetCurrentFov(float fov)
 
                velocityzoom = bound(0, drawframetime / max(0.000000001, autocvar_cl_velocityzoom_time), 1); // speed at which the zoom adapts to player velocity
                avgspeed = avgspeed * (1 - velocityzoom) + (curspeed / autocvar_cl_velocityzoom_speed) * velocityzoom;
-               velocityzoom = exp(float2range11(avgspeed * -autocvar_cl_velocityzoom / 1) * 1);
+               velocityzoom = exp(float2range11(avgspeed * -autocvar_cl_velocityzoom_factor / 1) * 1);
 
                //print(ftos(avgspeed), " avgspeed, ", ftos(curspeed), " curspeed, ", ftos(velocityzoom), " return\n"); // for debugging
        }
@@ -394,6 +394,30 @@ float contentavgalpha, liquidalpha_prev;
 vector liquidcolor_prev;
 
 float eventchase_current_distance;
+float eventchase_running;
+float WantEventchase()
+{
+       if(autocvar_cl_orthoview)
+               return FALSE;
+       if(intermission)
+               return TRUE;
+       if(spectatee_status >= 0)
+       {
+               if(autocvar_cl_eventchase_nexball && gametype == MAPINFO_TYPE_NEXBALL && !(WepSet_GetFromStat() & WepSet_FromWeapon(WEP_PORTO)))
+                       return TRUE;
+               if(autocvar_cl_eventchase_death && (getstati(STAT_HEALTH) <= 0))
+               {
+                       if(autocvar_cl_eventchase_death == 2)
+                       {
+                               // don't stop eventchase once it's started (even if velocity changes afterwards)
+                               if(self.velocity == '0 0 0' || eventchase_running)
+                                       return TRUE;
+                       }
+                       else return TRUE;
+               }
+       }
+       return FALSE;
+}
 
 vector damage_blurpostprocess, content_blurpostprocess;
 
@@ -495,9 +519,10 @@ void CSQC_UpdateView(float w, float h)
        // event chase camera
        if(autocvar_chase_active <= 0) // greater than 0 means it's enabled manually, and this code is skipped
        {
-               WepSet weapons_stat = WepSet_GetFromStat();
-               if(((spectatee_status >= 0 && (autocvar_cl_eventchase_death && is_dead)) || intermission) && !autocvar_cl_orthoview || (autocvar_cl_eventchase_nexball && gametype == MAPINFO_TYPE_NEXBALL && !(weapons_stat & WepSet_FromWeapon(WEP_PORTO))))
+               if(WantEventchase())
                {
+                       eventchase_running = TRUE;
+
                        // make special vector since we can't use view_origin (It is one frame old as of this code, it gets set later with the results this code makes.)
                        vector current_view_origin = (csqcplayer ? csqcplayer.origin : pmove_org);
 
@@ -538,6 +563,7 @@ void CSQC_UpdateView(float w, float h)
                }
                else if(autocvar_chase_active < 0) // time to disable chase_active if it was set by this code
                {
+                       eventchase_running = FALSE;
                        cvar_set("chase_active", "0");
                        eventchase_current_distance = 0; // start from 0 next time
                }
@@ -821,10 +847,7 @@ void CSQC_UpdateView(float w, float h)
        {
                // apply night vision effect
                vector tc_00, tc_01, tc_10, tc_11;
-               vector rgb;
-               rgb_x = 0; // fteqcc sucks
-               rgb_y = 0; // fteqcc sucks
-               rgb_z = 0; // fteqcc sucks
+               vector rgb = '0 0 0';
 
                if(!nightvision_noise)
                {
index 90a74a905b9bfaa1771ed3a9e157c9df9bdc234c..f06c5bfb3bd0f66e6dbc25ad67f201587b50a7c0 100644 (file)
@@ -77,7 +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;
@@ -116,6 +117,7 @@ string autocvar_crosshair_hitindication_per_weapon_color;
 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;
index 216940009dfed6fa0071e0e859686803b090f8d9..ea126f9d6d64b63c6bf64e2992775c45d99744c3 100644 (file)
@@ -933,16 +933,16 @@ void DrawAmmoItem(vector myPos, vector mySize, .float ammotype, float currently_
        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(ammotype), '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
        else // "ghost" ammo icon
@@ -985,7 +985,7 @@ void HUD_Ammo(void)
        if (autocvar_hud_panel_ammo_onlycurrent)
                total_ammo_count = 1;
        else
-               total_ammo_count = AMMO_COUNT - 1; // fuel
+               total_ammo_count = AMMO_COUNT;
 
        if(draw_nades)
        {
@@ -1045,6 +1045,7 @@ void HUD_Ammo(void)
                                TRUE,
                                infinite_ammo
                        );
+               }
 
                ++row;
                if(row >= rows)
@@ -1052,7 +1053,6 @@ void HUD_Ammo(void)
                        row = 0;
                        column = column + 1;
                }
-               }
        }
        else
        {
@@ -1060,7 +1060,6 @@ void HUD_Ammo(void)
                row = column = 0;
                for(i = 0; i < AMMO_COUNT; ++i)
                {
-                       if(i == 4) continue; // fuel
                        ammotype = GetAmmoFieldFromNum(i);
                        DrawAmmoItem(
                                pos + eX * column * (ammo_size_x + offset_x) + eY * row * (ammo_size_y + offset_y),
index 90f445c517b4623b70672f9a8ae2f90c09197338..c21726b4dcc655433bbe3d4f80365b0e3dc6e94f 100644 (file)
@@ -15,6 +15,7 @@ Defs.qc
 ../warpzonelib/common.qh
 ../warpzonelib/client.qh
 
+../common/playerstats.qh
 ../common/teams.qh
 ../common/util.qh
 ../common/nades.qh
@@ -107,6 +108,7 @@ noise.qc
 
 ../common/test.qc
 ../common/util.qc
+../common/playerstats.qc
 ../common/notifications.qc
 ../common/command/markup.qc
 ../common/command/rpn.qc
index 8ebe91903bcd4c6df2e935d7ce8a30a9217acd1a..2f59e713d35385f039b08c3cf10e7a6186fb498c 100644 (file)
@@ -1,7 +1,3 @@
-#ifdef USE_FTE
-#pragma target FTE
-#endif
-
 #define CSQC
 
 #define ATTEN_NORM builtin_ATTEN_NORM
index ec5b99d73b1ffed4fc1e5161e9b379dc9e1b604e..fe047e390ef7525cfb050c0019973d7dbc750ee5 100644 (file)
@@ -45,7 +45,6 @@ void Projectile_DrawTrail(vector to)
        }
 }
 
-.float proj_time;
 void Projectile_Draw()
 {
        vector rot;
@@ -54,9 +53,6 @@ void Projectile_Draw()
        float drawn;
        float t;
        float a;
-       float dt = time - self.proj_time;
-
-       self.proj_time = time;
 
        f = self.move_flags;
 
@@ -143,7 +139,6 @@ void Projectile_Draw()
        if(Nade_IDFromProjectile(self.cnt) != 0)
                trailorigin += v_up * 4;
 
-       if(dt > 0)
        if(drawn)
                Projectile_DrawTrail(trailorigin);
        else
@@ -204,7 +199,6 @@ void Ent_Projectile()
        self.count = (f & 0x80);
        self.iflags = (self.iflags & IFLAG_INTERNALMASK) | IFLAG_AUTOANGLES | IFLAG_ANGLES | IFLAG_ORIGIN;
        self.solid = SOLID_TRIGGER;
-       self.proj_time = time;
        //self.effects = EF_NOMODELFLAGS;
 
        // this should make collisions with bmodels more exact, but it leads to
index 2559bf3acd9ff8e822163d961f61c3e8fbd81d3b..1413a80902d1fb338abed1881ea942c2929bf608 100644 (file)
@@ -192,6 +192,24 @@ string process_time(float outputtype, float seconds)
                                        ((output != "") ? sprintf(", %s", output) : ""));
                        }
 
+                       return output;
+               }
+               case 3:
+               {
+                       string output = "";
+
+                       output = count_hours(tmp_hours);
+
+                       if(tmp_weeks) { tmp_days += (tmp_weeks * 7); }
+                       if(tmp_years) { tmp_days += (tmp_years * 365); }
+                       if(tmp_days)
+                       {
+                               output = sprintf(
+                                       "%s%s",
+                                       count_days(tmp_days),
+                                       ((output != "") ? sprintf(", %s", output) : ""));
+                       }
+
                        return output;
                }
        }
index ba1fbeb6f495d4077097e64170463926a3af1010..2230d5c790385c0823b1184101395f4edf95396e 100644 (file)
@@ -566,6 +566,15 @@ string _MapInfo_GetDefaultEx(float t)
        return "";
 }
 
+float _MapInfo_GetTeamPlayBool(float t)
+{
+       entity e;
+       for(e = MapInfo_Type_first; e; e = e.enemy)
+               if(t == e.items)
+                       return e.team;
+       return FALSE;
+}
+
 void _MapInfo_Map_ApplyGametypeEx(string s, float pWantedType, float pThisType)
 {
        string sa, k, v;
index 60cd26017d471dda13c1c9ddcf5e96b40cdc9c10..bbcc267b2bdbf5d05005155768419c357516e84c 100644 (file)
@@ -7,10 +7,11 @@ entity MapInfo_Type_last;
 .string netname; // game type name as in cvar (with g_ prefix)
 .string mdl; // game type short name
 .string message; // human readable name
+.float team; // does this gametype support teamplay?
 .string model2; // game type defaults
 .string gametype_description; // game type description
 
-#define REGISTER_GAMETYPE(hname,sname,g_name,NAME,defaults,gdescription) \
+#define REGISTER_GAMETYPE(hname,sname,g_name,NAME,gteamplay,defaults,gdescription) \
        var float MAPINFO_TYPE_##NAME; \
        var entity MapInfo_Type##g_name; \
        void RegisterGametypes_##g_name() \
@@ -22,6 +23,7 @@ entity MapInfo_Type_last;
                MapInfo_Type##g_name.netname = #g_name; \
                MapInfo_Type##g_name.mdl = #sname; \
                MapInfo_Type##g_name.message = hname; \
+               MapInfo_Type##g_name.team = gteamplay; \
                MapInfo_Type##g_name.model2 = defaults; \
                MapInfo_Type##g_name.gametype_description = gdescription; \
                if(!MapInfo_Type_first) \
@@ -35,49 +37,49 @@ entity MapInfo_Type_last;
 #define IS_GAMETYPE(NAME) \
        (MapInfo_LoadedGametype == MAPINFO_TYPE_##NAME)
 
-REGISTER_GAMETYPE(_("Deathmatch"),dm,g_dm,DEATHMATCH,"timelimit=20 pointlimit=30 leadlimit=0",_("Kill all enemies"));
+REGISTER_GAMETYPE(_("Deathmatch"),dm,g_dm,DEATHMATCH,FALSE,"timelimit=20 pointlimit=30 leadlimit=0",_("Kill all enemies"));
 #define g_dm IS_GAMETYPE(DEATHMATCH)
 
-REGISTER_GAMETYPE(_("Last Man Standing"),lms,g_lms,LMS,"timelimit=20 lives=9 leadlimit=0",_("Survive and kill until the enemies have no lives left"));
+REGISTER_GAMETYPE(_("Last Man Standing"),lms,g_lms,LMS,FALSE,"timelimit=20 lives=9 leadlimit=0",_("Survive and kill until the enemies have no lives left"));
 #define g_lms IS_GAMETYPE(LMS)
 
-REGISTER_GAMETYPE(_("Race"),rc,g_race,RACE,"timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0",_("Race against other players to the finish line"));
+REGISTER_GAMETYPE(_("Race"),rc,g_race,RACE,FALSE,"timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0",_("Race against other players to the finish line"));
 #define g_race IS_GAMETYPE(RACE)
 
-REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,"timelimit=20 skill=-1",_("Race for fastest time"));
+REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,FALSE,"timelimit=20 skill=-1",_("Race for fastest time"));
 #define g_cts IS_GAMETYPE(CTS)
 
-REGISTER_GAMETYPE(_("Team Deathmatch"),tdm,g_tdm,TEAM_DEATHMATCH,"timelimit=20 pointlimit=50 teams=2 leadlimit=0",_("Kill all enemy teammates"));
+REGISTER_GAMETYPE(_("Team Deathmatch"),tdm,g_tdm,TEAM_DEATHMATCH,TRUE,"timelimit=20 pointlimit=50 teams=2 leadlimit=0",_("Kill all enemy teammates"));
 #define g_tdm IS_GAMETYPE(TEAM_DEATHMATCH)
 
-REGISTER_GAMETYPE(_("Capture the Flag"),ctf,g_ctf,CTF,"timelimit=20 caplimit=10 leadlimit=6",_("Find and bring the enemy flag to your base to capture it"));
+REGISTER_GAMETYPE(_("Capture the Flag"),ctf,g_ctf,CTF,TRUE,"timelimit=20 caplimit=10 leadlimit=6",_("Find and bring the enemy flag to your base to capture it"));
 #define g_ctf IS_GAMETYPE(CTF)
 
-REGISTER_GAMETYPE(_("Clan Arena"),ca,g_ca,CA,"timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill all enemy teammates to win the round"));
+REGISTER_GAMETYPE(_("Clan Arena"),ca,g_ca,CA,TRUE,"timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill all enemy teammates to win the round"));
 #define g_ca IS_GAMETYPE(CA)
 
-REGISTER_GAMETYPE(_("Domination"),dom,g_domination,DOMINATION,"timelimit=20 pointlimit=200 teams=2 leadlimit=0",_("Capture all the control points to win"));
+REGISTER_GAMETYPE(_("Domination"),dom,g_domination,DOMINATION,TRUE,"timelimit=20 pointlimit=200 teams=2 leadlimit=0",_("Capture all the control points to win"));
 #define g_domination IS_GAMETYPE(DOMINATION)
 
-REGISTER_GAMETYPE(_("Key Hunt"),kh,g_keyhunt,KEYHUNT,"timelimit=20 pointlimit=1000 teams=3 leadlimit=0",_("Gather all the keys to win the round"));
+REGISTER_GAMETYPE(_("Key Hunt"),kh,g_keyhunt,KEYHUNT,TRUE,"timelimit=20 pointlimit=1000 teams=3 leadlimit=0",_("Gather all the keys to win the round"));
 #define g_keyhunt IS_GAMETYPE(KEYHUNT)
 
-REGISTER_GAMETYPE(_("Assault"),as,g_assault,ASSAULT,"timelimit=20",_("Destroy obstacles to find and destroy the enemy power core before time runs out"));
+REGISTER_GAMETYPE(_("Assault"),as,g_assault,ASSAULT,TRUE,"timelimit=20",_("Destroy obstacles to find and destroy the enemy power core before time runs out"));
 #define g_assault IS_GAMETYPE(ASSAULT)
 
-REGISTER_GAMETYPE(_("Onslaught"),ons,g_onslaught,ONSLAUGHT,"timelimit=20",_("Capture control points to reach and destroy the enemy generator"));
+REGISTER_GAMETYPE(_("Onslaught"),ons,g_onslaught,ONSLAUGHT,TRUE,"timelimit=20",_("Capture control points to reach and destroy the enemy generator"));
 #define g_onslaught IS_GAMETYPE(ONSLAUGHT)
 
-REGISTER_GAMETYPE(_("Nexball"),nb,g_nexball,NEXBALL,"timelimit=20 pointlimit=5 leadlimit=0",_("XonSports"));
+REGISTER_GAMETYPE(_("Nexball"),nb,g_nexball,NEXBALL,TRUE,"timelimit=20 pointlimit=5 leadlimit=0",_("XonSports"));
 #define g_nexball IS_GAMETYPE(NEXBALL)
 
-REGISTER_GAMETYPE(_("Freeze Tag"),ft,g_freezetag,FREEZETAG,"timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill enemies to freeze them, stand next to teammates to revive them"));
+REGISTER_GAMETYPE(_("Freeze Tag"),ft,g_freezetag,FREEZETAG,TRUE,"timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill enemies to freeze them, stand next to teammates to revive them"));
 #define g_freezetag IS_GAMETYPE(FREEZETAG)
 
-REGISTER_GAMETYPE(_("Keepaway"),ka,g_keepaway,KEEPAWAY,"timelimit=20 pointlimit=30",_("Hold the ball to get points for kills"));
+REGISTER_GAMETYPE(_("Keepaway"),ka,g_keepaway,KEEPAWAY,TRUE,"timelimit=20 pointlimit=30",_("Hold the ball to get points for kills"));
 #define g_keepaway IS_GAMETYPE(KEEPAWAY)
 
-REGISTER_GAMETYPE(_("Invasion"),inv,g_invasion,INVASION,"pointlimit=50 teams=0",_("Survive against waves of monsters"));
+REGISTER_GAMETYPE(_("Invasion"),inv,g_invasion,INVASION,FALSE,"pointlimit=50 teams=0",_("Survive against waves of monsters"));
 #define g_invasion IS_GAMETYPE(INVASION)
 
 const float MAPINFO_FEATURE_WEAPONS       = 1; // not defined for instagib-only maps
@@ -142,6 +144,7 @@ string MapInfo_ListAllAllowedMaps(float pFlagsRequired, float pFlagsForbidden);
 
 // gets a gametype from a string
 string _MapInfo_GetDefaultEx(float t);
+float _MapInfo_GetTeamPlayBool(float t);
 float MapInfo_Type_FromString(string t);
 string MapInfo_Type_Description(float t);
 string MapInfo_Type_ToString(float t);
index dc47dd3ae45e2b8718ef801ea36a630fc02da0a5..3774475484541d90baa2e610ba33726f08f79c58 100644 (file)
@@ -501,7 +501,7 @@ void Send_Notification_WOCOVA(
     MSG_INFO_NOTIF(1, INFO_WATERMARK,                      1, 0, "s1", "",                          "",                     _("^F3SVQC Build information: ^F4%s"), "") \
     MSG_INFO_NOTIF(1, INFO_WEAPON_ACCORDEON_MURDER,              3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "weapontuba",             _("^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Accordeon%s%s"), "") \
     MSG_INFO_NOTIF(1, INFO_WEAPON_ACCORDEON_SUICIDE,             2, 1, "s1 s2loc spree_lost", "s1",                 "weapontuba",             _("^BG%s^K1 hurt their own ears with the @!#%%'n Accordeon%s%s"), "") \
-    MSG_INFO_NOTIF(1, INFO_WEAPON_ARC_MURDER,                    3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "weaponhlac",             _("^BG%s%s^K1 was electrocuted by ^BG%s^K1's Arc%s%s"), "") \
+    MSG_INFO_NOTIF(1, INFO_WEAPON_ARC_MURDER,                    3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "weaponarc",              _("^BG%s%s^K1 was electrocuted by ^BG%s^K1's Arc%s%s"), "") \
     MSG_INFO_NOTIF(1, INFO_WEAPON_BLASTER_MURDER,                3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "weaponlaser",            _("^BG%s%s^K1 was shot to death by ^BG%s^K1's Blaster%s%s"), "") \
     MSG_INFO_NOTIF(1, INFO_WEAPON_BLASTER_SUICIDE,               2, 1, "s1 s2loc spree_lost", "s1",                 "weaponlaser",            _("^BG%s^K1 shot themself to hell with their Blaster%s%s"), "") \
     MSG_INFO_NOTIF(1, INFO_WEAPON_CRYLINK_MURDER,                3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "weaponcrylink",          _("^BG%s%s^K1 felt the strong pull of ^BG%s^K1's Crylink%s%s"), "") \
diff --git a/qcsrc/common/playerstats.qc b/qcsrc/common/playerstats.qc
new file mode 100644 (file)
index 0000000..813f966
--- /dev/null
@@ -0,0 +1,1054 @@
+#ifdef SVQC
+void PlayerStats_Prematch(void)
+{
+       //foobar
+}
+
+void PlayerStats_GameReport_AddPlayer(entity e)
+{
+       if((PS_GR_OUT_DB < 0) || (e.playerstats_id)) { return; }
+
+       // set up player identification
+       string s = string_null;
+
+       if((e.crypto_idfp != "") && (e.cvar_cl_allow_uidtracking == 1))
+               { s = e.crypto_idfp; }
+       else if(IS_BOT_CLIENT(e))
+               { s = sprintf("bot#%g#%s", skill, e.cleanname); }
+               
+       if((s == "") || find(world, playerstats_id, s)) // already have one of the ID - next one can't be tracked then!
+       {
+               if(IS_BOT_CLIENT(e))
+                       { s = sprintf("bot#%d", e.playerid); }
+               else
+                       { s = sprintf("player#%d", e.playerid); }
+       }
+       
+       e.playerstats_id = strzone(s);
+
+       // now add the player to the database
+       string key = sprintf("%s:*", e.playerstats_id);
+       string p = db_get(PS_GR_OUT_DB, key);
+       
+       if(p == "")
+       {
+               if(PS_GR_OUT_PL)
+               {
+                       db_put(PS_GR_OUT_DB, key, PS_GR_OUT_PL);
+                       strunzone(PS_GR_OUT_PL);
+               }
+               else { db_put(PS_GR_OUT_DB, key, "#"); }
+               PS_GR_OUT_PL = strzone(e.playerstats_id);
+       }
+}
+
+void PlayerStats_GameReport_AddTeam(float t)
+{
+       if(PS_GR_OUT_DB < 0) { return; }
+
+       string key = sprintf("%d", t);
+       string p = db_get(PS_GR_OUT_DB, key);
+       
+       if(p == "")
+       {
+               if(PS_GR_OUT_TL)
+               {
+                       db_put(PS_GR_OUT_DB, key, PS_GR_OUT_TL);
+                       strunzone(PS_GR_OUT_TL);
+               }
+               else { db_put(PS_GR_OUT_DB, key, "#"); }
+               PS_GR_OUT_TL = strzone(key);
+       }
+}
+
+void PlayerStats_GameReport_AddEvent(string event_id)
+{
+       if(PS_GR_OUT_DB < 0) { return; }
+
+       string key = sprintf("*:%s", event_id);
+       string p = db_get(PS_GR_OUT_DB, key);
+       
+       if(p == "")
+       {
+               if(PS_GR_OUT_EVL)
+               {
+                       db_put(PS_GR_OUT_DB, key, PS_GR_OUT_EVL);
+                       strunzone(PS_GR_OUT_EVL);
+               }
+               else { db_put(PS_GR_OUT_DB, key, "#"); }
+               PS_GR_OUT_EVL = strzone(event_id);
+       }
+}
+
+// referred to by PS_GR_P_ADDVAL and PS_GR_T_ADDVAL
+float PlayerStats_GameReport_Event(string prefix, string event_id, float value)
+{
+       if((prefix == "") || PS_GR_OUT_DB < 0) { return 0; }
+
+       string key = sprintf("%s:%s", prefix, event_id);
+       float val = stof(db_get(PS_GR_OUT_DB, key));
+       val += value;
+       db_put(PS_GR_OUT_DB, key, ftos(val));
+       return val;
+}
+
+void PlayerStats_GameReport_Accuracy(entity p)
+{
+       entity w;
+       float i;
+
+       for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+       {
+               w = get_weaponinfo(i);
+
+               #define ACCMAC(suffix,field) \
+                       PS_GR_P_ADDVAL(p, sprintf("acc-%s-%s", w.netname, suffix), p.accuracy.(field[i-1]));
+
+               ACCMAC("hit", accuracy_hit)
+               ACCMAC("fired", accuracy_fired)
+               ACCMAC("cnt-hit", accuracy_cnt_hit)
+               ACCMAC("cnt-fired", accuracy_cnt_fired)
+               ACCMAC("frags", accuracy_frags)
+
+               #undef ACCMAC
+       }
+}
+
+void PlayerStats_GameReport_FinalizePlayer(entity p)
+{
+       if((p.playerstats_id == "") || PS_GR_OUT_DB < 0) { return; }
+
+       // add global info!
+       if(p.alivetime)
+       {
+               PS_GR_P_ADDVAL(p, PLAYERSTATS_ALIVETIME, time - p.alivetime);
+               p.alivetime = 0;
+       }
+
+       db_put(PS_GR_OUT_DB, sprintf("%s:_playerid", p.playerstats_id), ftos(p.playerid));
+
+       if(p.cvar_cl_allow_uid2name == 1 || IS_BOT_CLIENT(p))
+               db_put(PS_GR_OUT_DB, sprintf("%s:_netname", p.playerstats_id), p.netname);
+
+       if(teamplay)
+               db_put(PS_GR_OUT_DB, sprintf("%s:_team", p.playerstats_id), ftos(p.team));
+
+       if(stof(db_get(PS_GR_OUT_DB, sprintf("%s:%s", p.playerstats_id, PLAYERSTATS_ALIVETIME))) > 0)
+               PS_GR_P_ADDVAL(p, PLAYERSTATS_JOINS, 1);
+
+       PlayerStats_GameReport_Accuracy(p);
+
+       if(IS_REAL_CLIENT(p))
+       {
+               if(p.latency_cnt)
+               {
+                       float latency = (p.latency_sum / p.latency_cnt);
+                       if(latency) { PS_GR_P_ADDVAL(p, PLAYERSTATS_AVGLATENCY, latency); }
+               }
+       }
+
+       strunzone(p.playerstats_id);
+       p.playerstats_id = string_null;
+}
+
+void PlayerStats_GameReport(float finished)
+{
+       if(PS_GR_OUT_DB < 0) { return; }
+       
+       PlayerScore_Sort(score_dummyfield, 0, 0, 0);
+       PlayerScore_Sort(scoreboard_pos, 1, 1, 1);
+       if(teamplay) { PlayerScore_TeamStats(); }
+
+       entity p;
+       FOR_EACH_CLIENT(p)
+       {
+               // add personal score rank
+               PS_GR_P_ADDVAL(p, PLAYERSTATS_RANK, p.score_dummyfield);
+
+               // scoreboard data
+               if(p.scoreboard_pos)
+               {
+                       // scoreboard is valid!
+                       PS_GR_P_ADDVAL(p, PLAYERSTATS_SCOREBOARD_VALID, 1);
+
+                       // add scoreboard position
+                       PS_GR_P_ADDVAL(p, PLAYERSTATS_SCOREBOARD_POS, p.scoreboard_pos);
+
+                       // add scoreboard data
+                       PlayerScore_PlayerStats(p);
+
+                       // if the match ended normally, add winning info
+                       if(finished)
+                       {
+                               PS_GR_P_ADDVAL(p, PLAYERSTATS_WINS, p.winning);
+                               PS_GR_P_ADDVAL(p, PLAYERSTATS_MATCHES, 1);
+                       }
+               }
+
+               // collect final player information
+               PlayerStats_GameReport_FinalizePlayer(p);
+       }
+
+       if(autocvar_g_playerstats_gamereport_uri != "")
+       {
+               PlayerStats_GameReport_DelayMapVote = TRUE;
+               url_multi_fopen(
+                       autocvar_g_playerstats_gamereport_uri,
+                       FILE_APPEND,
+                       PlayerStats_GameReport_Handler,
+                       world
+               );
+       }
+       else
+       {
+               PlayerStats_GameReport_DelayMapVote = FALSE;
+               db_close(PS_GR_OUT_DB);
+               PS_GR_OUT_DB = -1;
+       }
+}
+
+void PlayerStats_GameReport_Init() // initiated before InitGameplayMode so that scores are added properly
+{
+       if(autocvar_g_playerstats_gamereport_uri == "") { return; }
+
+       PS_GR_OUT_DB = -1;
+       PS_GR_OUT_DB = db_create();
+
+       if(PS_GR_OUT_DB >= 0)
+       {
+               PlayerStats_GameReport_DelayMapVote = TRUE;
+
+               serverflags |= SERVERFLAG_PLAYERSTATS;
+
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_ALIVETIME);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_AVGLATENCY);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_WINS);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_MATCHES);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_JOINS);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_SCOREBOARD_VALID);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_SCOREBOARD_POS);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_RANK);
+
+               // accuracy stats
+               entity w;
+               float i;
+               for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+               {
+                       w = get_weaponinfo(i);
+                       PlayerStats_GameReport_AddEvent(strcat("acc-", w.netname, "-hit"));
+                       PlayerStats_GameReport_AddEvent(strcat("acc-", w.netname, "-fired"));
+                       PlayerStats_GameReport_AddEvent(strcat("acc-", w.netname, "-cnt-hit"));
+                       PlayerStats_GameReport_AddEvent(strcat("acc-", w.netname, "-cnt-fired"));
+                       PlayerStats_GameReport_AddEvent(strcat("acc-", w.netname, "-frags"));
+               }
+
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_3);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_5);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_10);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_15);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_20);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_25);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_30);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_BOTLIKE);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD);
+               PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM);
+       }
+       else { PlayerStats_GameReport_DelayMapVote = FALSE; }
+}
+
+void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
+{
+       string t, tn;
+       string p, pn;
+       string e, en;
+       string nn, tt;
+       string s;
+
+       switch(status)
+       {
+               // ======================================
+               // -- OUTGOING GAME REPORT INFORMATION --
+               // ======================================
+               /* SPECIFICATIONS:
+                * V: format version (always a fixed number) - this MUST be the first line!
+                * #: comment (MUST be ignored by any parser)
+                * R: release information on the server
+                * G: game type
+                * O: mod name (icon request) as in server browser
+                * M: map name
+                * I: match ID (see "matchid" in g_world.qc)
+                * S: "hostname" of the server
+                * C: number of "unpure" cvar changes
+                * U: UDP port number of the server
+                * D: duration of the match
+                * L: "ladder" in which the server is participating in
+                * P: player ID of an existing player; this also sets the owner for all following "n", "e" and "t" lines (lower case!)
+                * Q: team number of an existing team (format: team#NN); this also sets the owner for all following "e" lines (lower case!)
+                * i: player index
+                * n: nickname of the player (optional)
+                * t: team ID
+                * e: followed by an event name, a space, and the event count/score
+                *  event names can be:
+                *   alivetime: total playing time of the player
+                *   avglatency: average network latency compounded throughout the match
+                *   wins: number of games won (can only be set if matches is set)
+                *   matches: number of matches played to the end (not aborted by map switch)
+                *   joins: number of matches joined (always 1 unless player never played during the match)
+                *   scoreboardvalid: set to 1 if the player was there at the end of the match
+                *   total-<scoreboardname>: total score of that scoreboard item
+                *   scoreboard-<scoreboardname>: end-of-game score of that scoreboard item (can differ in non-team games)
+                *   achievement-<achievementname>: achievement counters (their "count" is usually 1 if nonzero at all)
+                *   kills-<index>: number of kills against the indexed player
+                *   rank <number>: rank of player
+                *   acc-<weapon netname>-hit: total damage dealt
+                *   acc-<weapon netname>-fired: total damage that all fired projectiles *could* have dealt
+                *   acc-<weapon netname>-cnt-hit: amount of shots that actually hit
+                *   acc-<weapon netname>-cnt-fired: amount of fired shots
+                *   acc-<weapon netname>-frags: amount of frags dealt by weapon
+                */
+               case URL_READY_CANWRITE:
+               {
+                       url_fputs(fh, "V 9\n");
+                       #ifdef WATERMARK
+                       url_fputs(fh, sprintf("R %s\n", WATERMARK));
+                       #endif
+                       url_fputs(fh, sprintf("G %s\n", GetGametype()));
+                       url_fputs(fh, sprintf("O %s\n", modname));
+                       url_fputs(fh, sprintf("M %s\n", GetMapname()));
+                       url_fputs(fh, sprintf("I %s\n", matchid));
+                       url_fputs(fh, sprintf("S %s\n", cvar_string("hostname")));
+                       url_fputs(fh, sprintf("C %d\n", cvar_purechanges_count));
+                       url_fputs(fh, sprintf("U %d\n", cvar("port")));
+                       url_fputs(fh, sprintf("D %f\n", max(0, time - game_starttime)));
+                       url_fputs(fh, sprintf("L %s\n", autocvar_g_playerstats_gamereport_ladder));
+
+                       // TEAMS
+                       if(teamplay)
+                       {
+                               for(t = PS_GR_OUT_TL; (tn = db_get(PS_GR_OUT_DB, sprintf("%d", stof(t)))) != ""; t = tn)
+                               {
+                                       // start team section
+                                       url_fputs(fh, sprintf("Q team#%s\n", t));
+
+                                       // output team events // todo: does this do unnecessary loops? perhaps we should do a separate "team_events_last" tracker..."
+                                       for(e = PS_GR_OUT_EVL; (en = db_get(PS_GR_OUT_DB, sprintf("*:%s", e))) != ""; e = en)
+                                       {
+                                               float v = stof(db_get(PS_GR_OUT_DB, sprintf("team#%d:%s", stof(t), e)));
+                                               if(v != 0) { url_fputs(fh, sprintf("e %s %g\n", e, v)); }
+                                       }
+                               }
+                       }
+
+                       // PLAYERS
+                       for(p = PS_GR_OUT_PL; (pn = db_get(PS_GR_OUT_DB, sprintf("%s:*", p))) != ""; p = pn)
+                       {
+                               // start player section
+                               url_fputs(fh, sprintf("P %s\n", p));
+
+                               // playerid/index (entity number for this server)
+                               nn = db_get(PS_GR_OUT_DB, sprintf("%s:_playerid", p));
+                               if(nn != "") { url_fputs(fh, sprintf("i %s\n", nn)); }
+
+                               // player name 
+                               nn = db_get(PS_GR_OUT_DB, sprintf("%s:_netname", p));
+                               if(nn != "") { url_fputs(fh, sprintf("n %s\n", nn)); }
+
+                               // team identification number
+                               if(teamplay)
+                               {
+                                       tt = db_get(PS_GR_OUT_DB, sprintf("%s:_team", p));
+                                       url_fputs(fh, sprintf("t %s\n", tt));
+                               }
+
+                               // output player events
+                               for(e = PS_GR_OUT_EVL; (en = db_get(PS_GR_OUT_DB, sprintf("*:%s", e))) != ""; e = en)
+                               {
+                                       float v = stof(db_get(PS_GR_OUT_DB, sprintf("%s:%s", p, e)));
+                                       if(v != 0) { url_fputs(fh, sprintf("e %s %g\n", e, v)); }
+                               }
+                       }
+                       url_fputs(fh, "\n");
+                       url_fclose(fh);
+                       break;
+               }
+
+               // ======================================
+               // -- INCOMING GAME REPORT INFORMATION --
+               // ======================================
+               /* SPECIFICATIONS:
+                * stuff
+                */
+               case URL_READY_CANREAD:
+               {
+                       // url_fclose is processing, we got a response for writing the data
+                       // this must come from HTTP
+                       dprint("Got response from player stats server:\n");
+                       while((s = url_fgets(fh))) { dprint("  ", s, "\n"); }
+                       dprint("End of response.\n");
+                       url_fclose(fh);
+                       break;
+               }
+               
+               case URL_READY_CLOSED:
+               {
+                       // url_fclose has finished
+                       dprint("Player stats written\n");
+                       PlayerStats_GameReport_DelayMapVote = FALSE;
+                       if(PS_GR_OUT_DB >= 0)
+                       {
+                               db_close(PS_GR_OUT_DB);
+                               PS_GR_OUT_DB = -1;
+                       }
+                       break;
+               }
+               
+               case URL_READY_ERROR:
+               default:
+               {
+                       print("Player stats writing failed: ", ftos(status), "\n");
+                       PlayerStats_GameReport_DelayMapVote = FALSE;
+                       if(PS_GR_OUT_DB >= 0)
+                       {
+                               db_close(PS_GR_OUT_DB);
+                               PS_GR_OUT_DB = -1;
+                       }
+                       break;
+               }
+       }
+}
+
+void PlayerStats_PlayerBasic(entity joiningplayer, float newrequest)
+{
+       // http://stats.xonotic.org/player/GgXRw6piDtFIbMArMuiAi8JG4tiin8VLjZgsKB60Uds=/elo.txt
+       if(autocvar_g_playerstats_playerbasic_uri != "")
+       {
+               string uri = autocvar_g_playerstats_playerbasic_uri;
+               if(joiningplayer.crypto_idfp != "")
+               {
+                       // create the database if it doesn't already exist
+                       if(PS_B_IN_DB < 0)
+                       {
+                               PS_B_IN_DB = -1;
+                               PS_B_IN_DB = db_create();
+                       }
+
+                       // now request the information
+                       uri = strcat(uri, "/player/", uri_escape(uri_escape(joiningplayer.crypto_idfp)), "/elo.txt");
+                       dprint("Retrieving playerstats from URL: ", uri, "\n");
+                       url_single_fopen(
+                               uri,
+                               FILE_APPEND,
+                               PlayerStats_PlayerBasic_Handler,
+                               joiningplayer
+                       );
+
+                       // set status appropriately // todo: check whether the player info exists in the database previously
+                       if(newrequest)
+                       {
+                               // database still contains useful information, so don't clear it of a useful status
+                               joiningplayer.playerstats_basicstatus = PS_B_STATUS_WAITING;
+                       }
+                       else
+                       {
+                               // database was previously empty or never hit received status for some reason
+                               joiningplayer.playerstats_basicstatus = PS_B_STATUS_UPDATING;
+                       }
+               }
+       }
+       else
+       {
+               // server has this disabled, kill the DB and set status to idle
+               if(PS_B_IN_DB >= 0)
+               {
+                       entity player;
+
+                       db_close(PS_B_IN_DB);
+                       PS_B_IN_DB = -1;
+
+                       FOR_EACH_REALCLIENT(player) { player.playerstats_basicstatus = PS_B_STATUS_IDLE; }
+               }
+       }
+}
+
+void PlayerStats_PlayerBasic_CheckUpdate(entity joiningplayer)
+{
+       // determine whether we should retrieve playerbasic information again
+
+       #if 0
+       printf("PlayerStats_PlayerBasic_CheckUpdate('%s'): %f\n",
+               joiningplayer.netname,
+               time
+       );
+       #endif
+
+       // TODO: check to see if this playerid is inside the database already somehow...
+       // for now we'll just check the field, but this won't work for players who disconnect and reconnect properly
+       // although maybe we should just submit another request ANYWAY?
+       if(!joiningplayer.playerstats_basicstatus)
+       {
+               PlayerStats_PlayerBasic(
+                       joiningplayer,
+                       (joiningplayer.playerstats_basicstatus == PS_B_STATUS_RECEIVED)
+               );
+       }
+}
+
+void PlayerStats_PlayerBasic_Handler(entity fh, entity p, float status)
+{
+       switch(status)
+       {
+               case URL_READY_CANWRITE:
+               {
+                       dprint("-- Sending data to player stats server\n");
+                       /*url_fputs(fh, "V 1\n");
+                       #ifdef WATERMARK
+                       url_fputs(fh, sprintf("R %s\n", WATERMARK));
+                       #endif
+                       url_fputs(fh, sprintf("l %s\n", cvar_string("_menu_prvm_language"))); // language
+                       url_fputs(fh, sprintf("c %s\n", cvar_string("_menu_prvm_country"))); // country
+                       url_fputs(fh, sprintf("g %s\n", cvar_string("_menu_prvm_gender"))); // gender
+                       url_fputs(fh, sprintf("n %s\n", cvar_string("_cl_name"))); // name
+                       url_fputs(fh, sprintf("m %s %s\n", cvar_string("_cl_playermodel"), cvar_string("_cl_playerskin"))); // model/skin
+                       */url_fputs(fh, "\n");
+                       url_fclose(fh);
+                       break;
+               }
+               
+               case URL_READY_CANREAD:
+               {
+                       string s = "";
+                       dprint("-- Got response from player stats server:\n");
+                       //string gametype = string_null;
+                       while((s = url_fgets(fh)))
+                       {
+                               dprint("  ", s, "\n");
+                               /*
+                               string key = "", value = "", data = "";
+
+                               n = tokenizebyseparator(s, " "); // key (value) data
+                               if (n == 1)
+                                       continue;
+                               else if (n == 2)
+                               {
+                               key = argv(0);
+                               data = argv(1);
+                               }
+                               else if (n >= 3)
+                               {
+                                                               key = argv(0);
+                                                               value = argv(1);
+                                                               data = argv(2);
+                               }
+
+                               if (data == "")
+                               continue;
+
+                               if (key == "#")
+                               continue;
+                               else if (key == "V")
+                               PlayerInfo_AddItem(p, "_version", data);
+                               else if (key == "R")
+                               PlayerInfo_AddItem(p, "_release", data);
+                               else if (key == "T")
+                               PlayerInfo_AddItem(p, "_time", data);
+                               else if (key == "S")
+                               PlayerInfo_AddItem(p, "_statsurl", data);
+                               else if (key == "P")
+                               PlayerInfo_AddItem(p, "_hashkey", data);
+                               else if (key == "n")
+                               PlayerInfo_AddItem(p, "_playernick", data);
+                               else if (key == "i")
+                               PlayerInfo_AddItem(p, "_playerid", data);
+                               else if (key == "G")
+                               gametype = data;
+                               else if (key == "e" && value != "")
+                               {
+                               if (gametype == "")
+                               PlayerInfo_AddItem(p, value, data);
+                               else
+                               PlayerInfo_AddItem(p, sprintf("%s/%s", gametype, value), data);
+                               }
+                               else
+                               continue;
+                               */
+                       }
+                       dprint("-- End of response.\n");
+                       url_fclose(fh);
+                       break;
+               }
+               case URL_READY_CLOSED:
+               {
+                       // url_fclose has finished
+                       print("Player stats synchronized with server\n");
+                       break;
+               }
+               
+               case URL_READY_ERROR:
+               default:
+               {
+                       print("Receiving player stats failed: ", ftos(status), "\n");
+                       break;
+               }
+       }
+}
+#endif // SVQC
+
+#ifdef MENUQC
+
+
+#if 0 // reading the entire DB at once
+       string e = "", en = "";
+       float i = 0;
+       for(e = PS_D_IN_EVL; (en = db_get(PS_D_IN_DB, e)) != ""; e = en)
+       {
+               print(sprintf("%d:%s:%s\n", i, e, db_get(PS_D_IN_DB, sprintf("#%s", e))));
+               ++i;
+       }
+#endif
+
+void PlayerStats_PlayerDetail_AddItem(string event, string data)
+{
+       if(PS_D_IN_DB < 0) { return; }
+
+       // create a marker for the event so that we can access it later
+       string marker = sprintf("%s", event);
+       if(db_get(PS_D_IN_DB, marker) == "")
+       {
+               if(PS_D_IN_EVL)
+               {
+                       db_put(PS_D_IN_DB, marker, PS_D_IN_EVL);
+                       strunzone(PS_D_IN_EVL);
+               }
+               else { db_put(PS_D_IN_DB, marker, "#"); } 
+               PS_D_IN_EVL = strzone(marker);
+       }
+
+       // now actually set the event data
+       db_put(PS_D_IN_DB, sprintf("#%s", event), data);
+       dprint("Added item ", sprintf("#%s", event), "=", data, " to PS_D_IN_DB\n");
+}
+
+void PlayerStats_PlayerDetail(void)
+{
+       // http://stats.xonotic.org/player/me
+       if((autocvar_g_playerstats_playerdetail_uri != "") && (crypto_getmyidstatus(0) > 0))
+       {
+               // create the database if it doesn't already exist
+               if(PS_D_IN_DB < 0)
+               {
+                       PS_D_IN_DB = -1;
+                       PS_D_IN_DB = db_create();
+               }
+
+               //uri = strcat(uri, "/player/", uri_escape(crypto_getmyidfp(0)));
+               dprint("Retrieving playerstats from URL: ", autocvar_g_playerstats_playerdetail_uri, "\n");
+               url_single_fopen(
+                       autocvar_g_playerstats_playerdetail_uri,
+                       FILE_APPEND,
+                       PlayerStats_PlayerDetail_Handler,
+                       world
+               );
+
+               PlayerStats_PlayerDetail_Status = PS_D_STATUS_WAITING;
+       }
+       else
+       {
+               // player has this disabled, kill the DB and set status to idle
+               if(PS_D_IN_DB >= 0)
+               {
+                       db_close(PS_D_IN_DB);
+                       PS_D_IN_DB = -1;
+               }
+
+               PlayerStats_PlayerDetail_Status = PS_D_STATUS_IDLE;
+       }
+}
+
+void PlayerStats_PlayerDetail_CheckUpdate(void)
+{
+       // determine whether we should retrieve playerdetail information again
+       float gamecount = cvar("cl_matchcount");
+
+       #if 0
+       printf("PlayerStats_PlayerDetail_CheckUpdate(): %f >= %f, %d > %d\n",
+               time,
+               PS_D_NEXTUPDATETIME,
+               PS_D_LASTGAMECOUNT,
+               gamecount
+       );
+       #endif
+
+       if(
+               (time >= PS_D_NEXTUPDATETIME)
+               ||
+               (gamecount > PS_D_LASTGAMECOUNT)
+       )
+       {
+               PlayerStats_PlayerDetail();
+               PS_D_NEXTUPDATETIME = (time + autocvar_g_playerstats_playerdetail_autoupdatetime);
+               PS_D_LASTGAMECOUNT = gamecount;
+       }
+}
+
+void PlayerStats_PlayerDetail_Handler(entity fh, entity unused, float status)
+{
+       switch(status)
+       {
+               case URL_READY_CANWRITE:
+               {
+                       dprint("PlayerStats_PlayerDetail_Handler(): Sending data to player stats server...\n");
+                       url_fputs(fh, "V 1\n");
+                       #ifdef WATERMARK
+                       url_fputs(fh, sprintf("R %s\n", WATERMARK));
+                       #endif
+                       url_fputs(fh, sprintf("l %s\n", cvar_string("_menu_prvm_language"))); // language
+                       //url_fputs(fh, sprintf("c %s\n", cvar_string("_cl_country"))); // country
+                       //url_fputs(fh, sprintf("g %s\n", cvar_string("_cl_gender"))); // gender
+                       url_fputs(fh, sprintf("n %s\n", cvar_string("_cl_name"))); // name
+                       url_fputs(fh, sprintf("m %s %s\n", cvar_string("_cl_playermodel"), cvar_string("_cl_playerskin"))); // model/skin
+                       url_fputs(fh, "\n");
+                       url_fclose(fh);
+                       break;
+               }
+               
+               case URL_READY_CANREAD:
+               {
+                       //print("PlayerStats_PlayerDetail_Handler(): Got response from player stats server:\n");
+                       string input = "";
+                       string gametype = "overall";
+                       while((input = url_fgets(fh)))
+                       {
+                               float count = tokenizebyseparator(input, " ");
+                               string key = "", event = "", data = "";
+
+                               if(argv(0) == "#") { continue; }
+                               
+                               if(count == 2)
+                               {
+                                       key = argv(0);
+                                       data = substring(input, argv_start_index(1), strlen(input) - argv_start_index(1));
+                               }
+                               else if(count >= 3)
+                               {
+                                       key = argv(0);
+                                       event = argv(1);
+                                       data = substring(input, argv_start_index(2), strlen(input) - argv_start_index(2));
+                               }
+                               else { continue; }
+
+                               switch(key)
+                               {
+                                       // general info
+                                       case "V": PlayerStats_PlayerDetail_AddItem("version", data); break;
+                                       case "R": PlayerStats_PlayerDetail_AddItem("release", data); break;
+                                       case "T": PlayerStats_PlayerDetail_AddItem("time", data); break;
+
+                                       // player info
+                                       case "S": PlayerStats_PlayerDetail_AddItem("statsurl", data); break;
+                                       case "P": PlayerStats_PlayerDetail_AddItem("hashkey", data); break;
+                                       case "n": PlayerStats_PlayerDetail_AddItem("playernick", data); break;
+                                       case "i": PlayerStats_PlayerDetail_AddItem("playerid", data); break;
+
+                                       // other/event info
+                                       case "G": gametype = data; break;
+                                       case "e":
+                                       {
+                                               if(event != "" && data != "")
+                                               {
+                                                       PlayerStats_PlayerDetail_AddItem(
+                                                               sprintf(
+                                                                       "%s/%s",
+                                                                       gametype,
+                                                                       event
+                                                               ),
+                                                               data
+                                                       );
+                                               }
+                                               break;
+                                       }
+                                       
+                                       default:
+                                       {
+                                               printf(
+                                                       "PlayerStats_PlayerDetail_Handler(): ERROR: "
+                                                       "Key went unhandled? Is our version outdated?\n"
+                                                       "PlayerStats_PlayerDetail_Handler(): "
+                                                       "Key '%s', Event '%s', Data '%s'\n",
+                                                       key,
+                                                       event,
+                                                       data
+                                               );
+                                               break;
+                                       }
+                               }
+
+                               #if 0
+                               print(sprintf(
+                                       "PlayerStats_PlayerDetail_Handler(): "
+                                       "Key '%s', Event '%s', Data '%s'\n",
+                                       key,
+                                       event,
+                                       data
+                               ));
+                               #endif
+                       }
+                       //print("PlayerStats_PlayerDetail_Handler(): End of response.\n");
+                       url_fclose(fh);
+                       PlayerStats_PlayerDetail_Status = PS_D_STATUS_RECEIVED;
+                       statslist.getStats(statslist);
+                       break;
+               }
+
+               case URL_READY_CLOSED:
+               {
+                       // url_fclose has finished
+                       print("PlayerStats_PlayerDetail_Handler(): Player stats synchronized with server.\n");
+                       break;
+               }
+
+               case URL_READY_ERROR:
+               default:
+               {
+                       print("PlayerStats_PlayerDetail_Handler(): Receiving player stats failed: ", ftos(status), "\n");
+                       PlayerStats_PlayerDetail_Status = PS_D_STATUS_ERROR;
+                       if(PS_D_IN_DB >= 0)
+                       {
+                               db_close(PS_D_IN_DB);
+                               PS_D_IN_DB = -1;
+                       }
+                       break;
+               }
+       }
+}
+#endif
+
+/*
+void PlayerInfo_AddPlayer(entity e)
+{
+       if(playerinfo_db < 0)
+               return;
+
+       string key;
+       key = sprintf("#%d:*", e.playerid); // TODO: use hashkey instead?
+
+       string p;
+       p = db_get(playerinfo_db, key);
+       if(p == "")
+       {
+               if(playerinfo_last)
+               {
+                       db_put(playerinfo_db, key, playerinfo_last);
+                       strunzone(playerinfo_last);
+               }
+               else
+                       db_put(playerinfo_db, key, "#");
+               playerinfo_last = strzone(ftos(e.playerid));
+               print("  Added player ", ftos(e.playerid), " to playerinfo_db\n");//DEBUG//
+       }
+}
+
+void PlayerInfo_AddItem(entity e, string item_id, string val)
+{
+       if(playerinfo_db < 0)
+               return;
+
+       string key;
+       key = sprintf("*:%s", item_id);
+
+       string p;
+       p = db_get(playerinfo_db, key);
+       if(p == "")
+       {
+               if(playerinfo_events_last)
+               {
+                       db_put(playerinfo_db, key, playerinfo_events_last);
+                       strunzone(playerinfo_events_last);
+               }
+               else
+                       db_put(playerinfo_db, key, "#");
+               playerinfo_events_last = strzone(item_id);
+       }
+
+       key = sprintf("#%d:%s", e.playerid, item_id);
+       db_put(playerinfo_db, key, val);
+       print("  Added item ", key, "=", val, " to playerinfo_db\n");//DEBUG//
+}
+
+string PlayerInfo_GetItem(entity e, string item_id)
+{
+       if(playerinfo_db < 0)
+               return "";
+
+       string key;
+       key = sprintf("#%d:%s",  e.playerid, item_id);
+       return db_get(playerinfo_db, key);
+}
+
+string PlayerInfo_GetItemLocal(string item_id)
+{
+        entity p = spawn();
+        p.playerid = 0;
+        return PlayerInfo_GetItem(p, item_id);
+}
+
+void PlayerInfo_ready(entity fh, entity p, float status)
+{
+       float n;
+       string s;
+
+        PlayerInfo_AddPlayer(p);
+
+       switch(status)
+       {
+                case URL_READY_CANWRITE:
+                        print("-- Sending data to player stats server\n");
+                       url_fputs(fh, "V 1\n");
+#ifdef WATERMARK
+                       url_fputs(fh, sprintf("R %s\n", WATERMARK));
+#endif
+#ifdef MENUQC
+                        url_fputs(fh, sprintf("l %s\n", cvar_string("_menu_prvm_language"))); // language
+                        url_fputs(fh, sprintf("c %s\n", cvar_string("_menu_prvm_country"))); // country
+                        url_fputs(fh, sprintf("g %s\n", cvar_string("_menu_prvm_gender"))); // gender
+                        url_fputs(fh, sprintf("n %s\n", cvar_string("_cl_name"))); // name
+                        url_fputs(fh, sprintf("m %s %s\n", cvar_string("_cl_playermodel"), cvar_string("_cl_playerskin"))); // model/skin
+#endif
+                       url_fputs(fh, "\n");
+                       url_fclose(fh);
+                        break;
+                case URL_READY_CANREAD:
+                       print("-- Got response from player stats server:\n");
+                       string gametype = string_null;
+                       while((s = url_fgets(fh)))
+                       {
+                               print("  ", s, "\n");
+
+                               string key = "", value = "", data = "";
+
+                               n = tokenizebyseparator(s, " "); // key (value) data
+                               if (n == 1)
+                                        continue;
+                               else if (n == 2)
+                               {
+                                       key = argv(0);
+                                       data = argv(1);
+                               }
+                               else if (n >= 3)
+                               {
+                                        key = argv(0);
+                                        value = argv(1);
+                                        data = argv(2);
+                               }
+
+                               if (data == "")
+                                       continue;
+
+                               if (key == "#")
+                                       continue;
+                               else if (key == "V")
+                                       PlayerInfo_AddItem(p, "_version", data);
+                               else if (key == "R")
+                                       PlayerInfo_AddItem(p, "_release", data);
+                               else if (key == "T")
+                                       PlayerInfo_AddItem(p, "_time", data);
+                               else if (key == "S")
+                                       PlayerInfo_AddItem(p, "_statsurl", data);
+                               else if (key == "P")
+                                       PlayerInfo_AddItem(p, "_hashkey", data);
+                               else if (key == "n")
+                                       PlayerInfo_AddItem(p, "_playernick", data);
+                               else if (key == "i")
+                                       PlayerInfo_AddItem(p, "_playerid", data);
+                               else if (key == "G")
+                                       gametype = data;
+                               else if (key == "e" && value != "")
+                               {
+                                       if (gametype == "")
+                                               PlayerInfo_AddItem(p, value, data);
+                                       else
+                                               PlayerInfo_AddItem(p, sprintf("%s/%s", gametype, value), data);
+                               }
+                               else
+                                       continue;
+                       }
+                       print("-- End of response.\n");
+                       url_fclose(fh);
+                       break;
+               case URL_READY_CLOSED:
+                       // url_fclose has finished
+                       print("Player stats synchronized with server\n");
+                       break;
+               case URL_READY_ERROR:
+               default:
+                       print("Receiving player stats failed: ", ftos(status), "\n");
+                       break;
+       }
+}
+
+void PlayerInfo_Init()
+{
+       playerinfo_db = -1;
+       playerinfo_db = db_create();
+}
+
+#ifdef SVQC
+void PlayerInfo_Basic(entity p)
+{
+        print("-- Getting basic PlayerInfo for player ",ftos(p.playerid)," (SVQC)\n");
+
+       if(playerinfo_db < 0)
+               return;
+
+        string uri;
+        uri = autocvar_g_playerinfo_uri;
+       if(uri != "" && p.crypto_idfp != "")
+       {
+               uri = strcat(uri, "/elo/", uri_escape(p.crypto_idfp));
+               print("Retrieving playerstats from URL: ", uri, "\n");
+               url_single_fopen(uri, FILE_READ, PlayerInfo_ready, p);
+       }
+}
+#endif
+
+#ifdef MENUQC
+void PlayerInfo_Details()
+{
+        print("-- Getting detailed PlayerInfo for local player (MENUQC)\n");
+
+       if(playerinfo_db < 0)
+               return;
+
+        string uri;
+        uri = autocvar_g_playerinfo_uri; // FIXME
+       if(uri != "" && crypto_getmyidstatus(0) > 0)
+       {
+               //uri = strcat(uri, "/player/", uri_escape(crypto_getmyidfp(0)));
+                uri = strcat(uri, "/player/me");
+               print("Retrieving playerstats from URL: ", uri, "\n");
+               url_single_fopen(uri, FILE_APPEND, PlayerInfo_ready, world);
+       }
+}
+#endif
+
+#ifdef CSQC
+/*
+ * FIXME - crypto_* builtin functions missing in CSQC (csprogsdefs.qc:885)
+void PlayerInfo_Details()
+{
+        print("-- Getting detailed PlayerInfo for local player (CSQC)\n");
+
+       if(playerinfo_db < 0)
+               return;
+
+        string uri;
+        uri = autocvar_g_playerinfo_uri; // FIXME
+       if(uri != "" && crypto_getmyidstatus(0) > 0)
+       {
+               uri = strcat(uri, "/player/", uri_escape(crypto_getmyidfp(0)));
+               print("Retrieving playerstats from URL: ", uri, "\n");
+               url_single_fopen(uri, FILE_READ, PlayerInfo_ready, p);
+       }
+}
+
+#endif
+*/
diff --git a/qcsrc/common/playerstats.qh b/qcsrc/common/playerstats.qh
new file mode 100644 (file)
index 0000000..26a1efc
--- /dev/null
@@ -0,0 +1,115 @@
+#ifdef SVQC
+//float PS_PM_IN_DB;   // playerstats_prematch_in_db      // db for info COLLECTED at the beginning of a match
+float PS_GR_OUT_DB;  // playerstats_gamereport_out_db   // db of info SENT at the end of a match
+//float PS_GR_IN_DB;   // playerstats_gamereport_in_db    // db for info COLLECTED at the end of a match
+float PS_B_IN_DB;    // playerstats_playerbasic_in_db   // db for info COLLECTED for basic player info (ELO)
+#endif
+
+#ifdef MENUQC
+float PS_D_IN_DB; // playerstats_playerdetail_in_db  // db for info COLLECTED for detailed player profile display
+#endif
+
+#ifdef SVQC
+//string PS_PM_IN_EVL;   // playerstats_prematch_in_events_last
+string PS_GR_OUT_TL;   // playerstats_gamereport_out_teams_last
+string PS_GR_OUT_PL;   // playerstats_gamereport_out_players_las
+string PS_GR_OUT_EVL;  // playerstats_gamereport_out_events_last
+//string PS_GR_IN_PL;    // playerstats_gamereport_in_players_last
+//string PS_GR_IN_EVL;   // playerstats_gamereport_in_events_last
+//string PS_B_IN_PL;     // playerstats_playerbasic_in_players_last
+//string PS_B_IN_EVL;    // playerstats_playerbasic_in_events_last
+#endif
+
+#ifdef MENUQC
+string PS_D_IN_EVL; // playerstats_playerdetail_in_events_last
+#endif
+
+#ifdef SVQC
+
+// time the player was alive and kicking
+const string PLAYERSTATS_ALIVETIME  = "alivetime";
+const string PLAYERSTATS_AVGLATENCY = "avglatency";
+const string PLAYERSTATS_WINS = "wins";
+const string PLAYERSTATS_MATCHES = "matches";
+const string PLAYERSTATS_JOINS = "joins";
+const string PLAYERSTATS_SCOREBOARD_VALID = "scoreboardvalid";
+const string PLAYERSTATS_RANK = "rank";
+const string PLAYERSTATS_SCOREBOARD_POS = "scoreboardpos";
+
+const string PLAYERSTATS_TOTAL = "total-";
+const string PLAYERSTATS_SCOREBOARD = "scoreboard-";
+
+const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_3 = "achievement-kill-spree-3";
+const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_5 = "achievement-kill-spree-5";
+const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_10 = "achievement-kill-spree-10";
+const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_15 = "achievement-kill-spree-15";
+const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_20 = "achievement-kill-spree-20";
+const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_25 = "achievement-kill-spree-25";
+const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_30 = "achievement-kill-spree-30";
+const string PLAYERSTATS_ACHIEVEMENT_BOTLIKE = "achievement-botlike";
+const string PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD = "achievement-firstblood";
+const string PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM = "achievement-firstvictim";
+
+// delay map switch until this is set
+float PlayerStats_GameReport_DelayMapVote;
+
+// call at initialization
+void PlayerStats_GameReport_Init();
+
+// add a new player
+void PlayerStats_GameReport_AddPlayer(entity e);
+
+// add a new team
+void PlayerStats_GameReport_AddTeam(float t);
+
+// add a new event
+void PlayerStats_GameReport_AddEvent(string event_id);
+
+// call on each event to track, or at player disconnect OR match end for "global stuff"
+#define PS_GR_P_ADDVAL(ent,eventid,val) PlayerStats_GameReport_Event(ent.playerstats_id, eventid, val)
+#define PS_GR_T_ADDVAL(team,eventid,val) PlayerStats_GameReport_Event(sprintf("team#%d", team), eventid, val)
+float PlayerStats_GameReport_Event(string prefix, string event_id, float value);
+
+void PlayerStats_GameReport_Accuracy(entity p);
+
+// call this whenever a player leaves
+void PlayerStats_GameReport_FinalizePlayer(entity p);
+
+// call this at the end of the match
+void PlayerStats_GameReport(float finished);
+
+void PlayerStats_GameReport_Handler(entity fh, entity pass, float status);
+
+.string playerstats_id;
+
+//string autocvar_g_playerstats_uri;
+
+string autocvar_g_playerstats_gamereport_ladder;
+var string autocvar_g_playerstats_gamereport_uri = "http://stats.xonotic.org/stats/submit";
+
+#define PS_B_STATUS_ERROR -2
+#define PS_B_STATUS_IDLE -1
+#define PS_B_STATUS_WAITING 0
+#define PS_B_STATUS_RECEIVED 1
+#define PS_B_STATUS_UPDATING 2
+.float playerstats_basicstatus;
+var string autocvar_g_playerstats_playerbasic_uri = "http://stats.xonotic.org";
+
+void PlayerStats_PlayerBasic(entity joiningplayer, float newrequest);
+void PlayerStats_PlayerBasic_CheckUpdate(entity joiningplayer);
+void PlayerStats_PlayerBasic_Handler(entity fh, entity p, float status);
+#endif //SVQC
+#ifdef MENUQC
+float PS_D_NEXTUPDATETIME;
+float PS_D_LASTGAMECOUNT;
+#define PS_D_STATUS_ERROR -2
+#define PS_D_STATUS_IDLE -1
+#define PS_D_STATUS_WAITING 0
+#define PS_D_STATUS_RECEIVED 1
+var float PlayerStats_PlayerDetail_Status = PS_D_STATUS_IDLE;
+var string autocvar_g_playerstats_playerdetail_uri = "http://stats.xonotic.org/player/me";
+var float autocvar_g_playerstats_playerdetail_autoupdatetime = 1800; // automatically update every 30 minutes anyway
+void PlayerStats_PlayerDetail(void);
+void PlayerStats_PlayerDetail_CheckUpdate(void);
+void PlayerStats_PlayerDetail_Handler(entity fh, entity p, float status);
+#endif
index 4e8e1b59c8d35ac69ea37fe0f410f74eb1f79d92..3f4c3e57f4f8f2095eafb3fa41f31415572d1d20 100644 (file)
@@ -1,23 +1,6 @@
-#ifdef FTEQCC
-#pragma flag enable subscope
-#pragma flag enable lo
-#endif
-
-// FTEQCC can do this
-// #define HAVE_YO_DAWG_CPP
-// No, this is an ex-"feature" and non-C11.
-
 #ifndef NOCOMPAT
 //# define WORKAROUND_XON010
 //# define COMPAT_XON050_ENGINE
 # define COMPAT_NO_MOD_IS_XONOTIC
 # define COMPAT_XON060_DONTCRASH_CHECKPVS
 #endif
-
-#ifdef FTEQCC
-#ifdef WATERMARK
-const string FTEQCC_SUCKS_WATERMARKS_THROUGH_C60_FULLERENES = WATERMARK();
-#undef WATERMARK
-#define WATERMARK FTEQCC_SUCKS_WATERMARKS_THROUGH_C60_FULLERENES
-#endif
-#endif
index 15cde708ab84978e148be46ae7abf388c7ea33b7..671c8d5a593e23f9c552a700172cc57b9cf7139c 100644 (file)
@@ -408,6 +408,22 @@ void buf_save(float buf, string pFilename)
        fclose(fh);
 }
 
+string format_time(float seconds)
+{
+       float days, hours, minutes;
+       seconds = floor(seconds + 0.5);
+        days = floor(seconds / 864000);
+        seconds -= days * 864000;
+        hours = floor(seconds / 36000);
+        seconds -= hours * 36000;
+       minutes = floor(seconds / 600);
+       seconds -= minutes * 600;
+        if (days > 0)
+                return sprintf(_("%d days, %02d:%02d:%02d"), days, hours, minutes, seconds);
+        else
+                return sprintf(_("%02d:%02d:%02d"), hours, minutes, seconds);
+}
+
 string mmsss(float tenths)
 {
        float minutes;
@@ -1703,19 +1719,6 @@ vector get_shotvelocity(vector myvel, vector mydir, float spd, float newton_styl
        return myvel + spd * mydir;
 }
 
-void check_unacceptable_compiler_bugs()
-{
-       if(cvar("_allow_unacceptable_compiler_bugs"))
-               return;
-       tokenize_console("foo bar");
-       if(strcat(argv(0), substring("foo bar", 4, 7 - argv_start_index(1))) == "barbar")
-               error("fteqcc bug introduced with revision 3178 detected. Please upgrade fteqcc to a later revision, downgrade fteqcc to revision 3177, or pester Spike until he fixes it. You can set _allow_unacceptable_compiler_bugs 1 to skip this check, but expect stuff to be horribly broken then.");
-
-       string s = "";
-       if (!s)
-               error("The empty string counts as false. We do not want that!");
-}
-
 float compressShotOrigin(vector v)
 {
        float x, y, z;
@@ -2585,7 +2588,6 @@ vector get_corner_position(entity box, float corner)
 #endif
 
 // todo: this sucks, lets find a better way to do backtraces?
-#ifndef MENUQC
 void backtrace(string msg)
 {
        float dev, war;
@@ -2607,7 +2609,6 @@ void backtrace(string msg)
        cvar_set("developer", ftos(dev));
        cvar_set("prvm_backtraceforwarnings", ftos(war));
 }
-#endif
 
 // color code replace, place inside of sprintf and parse the string
 string CCR(string input)
index 61b9ad0e2b06dde9c4621dd25f2b25d9af5e52ab..14dd59d04888e6e8f5478d5808b060cd0b33cd12 100644 (file)
@@ -104,6 +104,7 @@ 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);
 
@@ -208,8 +209,6 @@ vector solve_quadratic(float a, float b, float c);
 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);
 
@@ -378,9 +377,9 @@ vector get_corner_position(entity box, float corner);
 #define fprintf(file, ...) fputs(file, sprintf(__VA_ARGS__))
 #define bprintf(...) bprint(sprintf(__VA_ARGS__))
 
-#ifndef MENUQC
+//#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
diff --git a/qcsrc/fteqcc-bugs.qc b/qcsrc/fteqcc-bugs.qc
deleted file mode 100644 (file)
index dd4fd45..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-void error(...) = #1;
-float id(float x) { return x; }
-
-void Oassignments(float foo) // pass 1
-{
-       float bar;
-       bar = 2;
-       bar = (foo ? 0 : (foo & 1));
-       if(bar == 2)
-               error("FTEQCC SUCKS");
-}
-
-void Oreturn_only(float foo) // pass 0
-{
-       if(foo)
-       {
-               return;
-       }
-}
-
-void Oreturn_only_trap(void)
-{
-       error("FTEQCC SUCKS");
-}
-
-.float fld;
-void Ono_assignments(entity e, float wep) // pass an e with e.fld == 1, and wep == 3. e.fld will be 2 instead of 3. Observe the INDIRECT and the SUB use the same field for storage, wreaking havoc.
-{
-               ((e).fld |= id(wep - 1));
-}
index 46d0c0269e01d8a3532941343457e1cb39fe346b..bc60898c88213dec842d73b2930dbca094ebb77f 100644 (file)
@@ -26,6 +26,7 @@
 #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_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"
@@ -60,7 +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/colorpicker.c"
 #include "xonotic/colorpicker_string.c"
 #include "xonotic/cvarlist.c"
 #include "xonotic/dialog_hudpanel_buffs.c"
 #include "xonotic/slider_picmip.c"
 #include "xonotic/slider_particles.c"
+#include "xonotic/slider_sbfadetime.c"
+#include "xonotic/dialog_settings_misc_reset.c"
index a7e63b0e116f88c2c1327794a436a7a03fda599b..8d1a6de86af32f3f0e9889287df1c49b497b45b0 100644 (file)
@@ -5,9 +5,22 @@ CLASS(Image) EXTENDS(Item)
        METHOD(Image, toString, string(entity))
        METHOD(Image, resizeNotify, void(entity, vector, vector, vector, vector))
        METHOD(Image, updateAspect, void(entity))
+       METHOD(Image, initZoom, void(entity))
+       METHOD(Image, setZoom, void(entity, float, float))
+       METHOD(Image, drag_setStartPos, float(entity, vector))
+       METHOD(Image, drag, float(entity, vector))
        ATTRIB(Image, src, string, string_null)
        ATTRIB(Image, color, vector, '1 1 1')
-       ATTRIB(Image, forcedAspect, float, 0)
+       ATTRIB(Image, forcedAspect, float, 0) // special values: -1 keep image aspect ratio, -2 keep image size but bound to the containing box, -3 always keep image size
+       ATTRIB(Image, zoomBox, float, 0) // used by forcedAspect -2 when the image is larger than the containing box
+       ATTRIB(Image, zoomFactor, float, 1)
+       ATTRIB(Image, zoomOffset, vector, '0.5 0.5 0')
+       ATTRIB(Image, zoomSnapToTheBox, float, 1) // snap the zoomed in image to the box borders when zooming/dragging it
+       ATTRIB(Image, zoomTime, float, 0)
+       ATTRIB(Image, zoomLimitedByTheBox, float, 0) // forbids zoom if image would be larger than the containing box
+       ATTRIB(Image, zoomMax, float, 0)
+       ATTRIB(Image, start_zoomOffset, vector, '0 0 0')
+       ATTRIB(Image, start_coords, vector, '0 0 0')
        ATTRIB(Image, imgOrigin, vector, '0 0 0')
        ATTRIB(Image, imgSize, vector, '0 0 0')
 ENDCLASS(Image)
@@ -22,14 +35,28 @@ void Image_configureImage(entity me, string path)
 {
        me.src = path;
 }
+void Image_initZoom(entity me)
+{
+       me.zoomOffset = '0.5 0.5 0';
+       me.zoomFactor = 1;
+       if (me.forcedAspect == -2)
+               me.zoomBox = -1; // calculate zoomBox at the first updateAspect call
+       if (me.zoomLimitedByTheBox)
+               me.zoomMax = -1; // calculate zoomMax at the first updateAspect call
+}
+
 void Image_draw(entity me)
 {
+       if(me.imgSize_x > 1 || me.imgSize_y > 1)
+               draw_SetClip();
        draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
+       if(me.imgSize_x > 1 || me.imgSize_y > 1)
+               draw_ClearClip();
        SUPER(Image).draw(me);
 }
 void Image_updateAspect(entity me)
 {
-       float asp;
+       float asp = 0;
        if(me.size_x <= 0 || me.size_y <= 0)
                return;
        if(me.forcedAspect == 0)
@@ -39,26 +66,162 @@ void Image_updateAspect(entity me)
        }
        else
        {
+               vector sz = '0 0 0';
                if(me.forcedAspect < 0)
                {
-                       vector sz;
-                       sz = draw_PictureSize(me.src);
+                       if (me.src != "")
+                               sz = draw_PictureSize(me.src);
+                       if(sz_x <= 0 || sz_y <= 0)
+                       {
+                               // image is broken or doesn't exist, set the size for the placeholder image
+                               sz_x = me.size_x;
+                               sz_y = me.size_y;
+                       }
                        asp = sz_x / sz_y;
                }
                else
                        asp = me.forcedAspect;
-               if(me.size_x > asp * me.size_y)
+
+               if(me.forcedAspect <= -2)
+               {
+                       me.imgSize_x = sz_x / me.size_x;
+                       me.imgSize_y = sz_y / me.size_y;
+                       if(me.zoomBox < 0 && (me.imgSize_x > 1 || me.imgSize_y > 1))
+                       {
+                               // image larger than the containing box, zoom it out to fit into the box
+                               if(me.size_x > asp * me.size_y)
+                                       me.zoomBox = (me.size_y * asp / me.size_x) / me.imgSize_x;
+                               else
+                                       me.zoomBox = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
+                               me.zoomFactor = me.zoomBox;
+                       }
+               }
+               else
+               {
+                       if(me.size_x > asp * me.size_y)
+                       {
+                               // x too large, so center x-wise
+                               me.imgSize = eY + eX * (me.size_y * asp / me.size_x);
+                       }
+                       else
+                       {
+                               // y too large, so center y-wise
+                               me.imgSize = eX + eY * (me.size_x / (asp * me.size_y));
+                       }
+               }
+       }
+
+       if (me.zoomMax < 0)
+       {
+               if(me.zoomBox > 0)
+                       me.zoomMax = me.zoomBox;
+               else
+               {
+                       if(me.size_x > asp * me.size_y)
+                               me.zoomMax = (me.size_y * asp / me.size_x) / me.imgSize_x;
+                       else
+                               me.zoomMax = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
+               }
+       }
+
+       if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
+               me.zoomFactor = me.zoomMax;
+       if (me.zoomFactor)
+               me.imgSize = me.imgSize * me.zoomFactor;
+
+       if(me.imgSize_x > 1 || me.imgSize_y > 1)
+       {
+               if(me.zoomSnapToTheBox)
+               {
+                       if(me.imgSize_x > 1)
+                               me.zoomOffset_x = bound(0.5/me.imgSize_x, me.zoomOffset_x, 1 - 0.5/me.imgSize_x);
+                       else
+                               me.zoomOffset_x = bound(1 - 0.5/me.imgSize_x, me.zoomOffset_x, 0.5/me.imgSize_x);
+
+                       if(me.imgSize_y > 1)
+                               me.zoomOffset_y = bound(0.5/me.imgSize_y, me.zoomOffset_y, 1 - 0.5/me.imgSize_y);
+                       else
+                               me.zoomOffset_y = bound(1 - 0.5/me.imgSize_y, me.zoomOffset_y, 0.5/me.imgSize_y);
+               }
+               else
+               {
+                       me.zoomOffset_x = bound(0, me.zoomOffset_x, 1);
+                       me.zoomOffset_y = bound(0, me.zoomOffset_y, 1);
+               }
+       }
+       else
+               me.zoomOffset = '0.5 0.5 0';
+
+       me.imgOrigin_x = 0.5 - me.zoomOffset_x * me.imgSize_x;
+       me.imgOrigin_y = 0.5 - me.zoomOffset_y * me.imgSize_y;
+}
+float Image_drag_setStartPos(entity me, vector coords)
+{
+       //if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
+       {
+               me.start_zoomOffset = me.zoomOffset;
+               me.start_coords = coords;
+       }
+       return 1;
+}
+float Image_drag(entity me, vector coords)
+{
+       if(me.imgSize_x > 1 || me.imgSize_y > 1)
+       {
+               me.zoomOffset_x = me.start_zoomOffset_x + (me.start_coords_x - coords_x) / me.imgSize_x;
+               me.zoomOffset_y = me.start_zoomOffset_y + (me.start_coords_y - coords_y) / me.imgSize_y;
+               me.updateAspect(me);
+       }
+       return 1;
+}
+void Image_setZoom(entity me, float z, float atMousePosition)
+{
+       float prev_zoomFactor;
+       prev_zoomFactor = me.zoomFactor;
+       if (z < 0) // multiply by the current zoomFactor (but can also snap to real dimensions or to box)
+       {
+               me.zoomFactor *= -z;
+               float realSize_in_the_middle, boxSize_in_the_middle;
+               realSize_in_the_middle = ((prev_zoomFactor - 1) * (me.zoomFactor - 1) < 0);
+               boxSize_in_the_middle = (me.zoomBox > 0 && (prev_zoomFactor - me.zoomBox) * (me.zoomFactor - me.zoomBox) < 0);
+               if (realSize_in_the_middle && boxSize_in_the_middle)
                {
-                       // x too large, so center x-wise
-                       me.imgSize = eY + eX * (me.size_y * asp / me.size_x);
+                       // snap to real dimensions or to box
+                       if (prev_zoomFactor < me.zoomFactor)
+                               me.zoomFactor = min(1, me.zoomBox);
+                       else
+                               me.zoomFactor = max(1, me.zoomBox);
                }
+               else if (realSize_in_the_middle)
+                       me.zoomFactor = 1; // snap to real dimensions
+               else if (boxSize_in_the_middle)
+                       me.zoomFactor = me.zoomBox; // snap to box
+       }
+       else if (z == 0) // reset (no zoom)
+       {
+               if (me.zoomBox > 0)
+                       me.zoomFactor = me.zoomBox;
                else
+                       me.zoomFactor = 1;
+       }
+       else // directly set
+               me.zoomFactor = z;
+       me.zoomFactor = bound(1/16, me.zoomFactor, 16);
+       if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
+               me.zoomFactor = me.zoomMax;
+       if (prev_zoomFactor != me.zoomFactor)
+       {
+               me.zoomTime = time;
+               if (atMousePosition)
                {
-                       // y too large, so center y-wise
-                       me.imgSize = eX + eY * (me.size_x / (asp * me.size_y));
+                       me.zoomOffset_x = me.start_zoomOffset_x + (me.start_coords_x - 0.5) / me.imgSize_x;
+                       me.zoomOffset_y = me.start_zoomOffset_y + (me.start_coords_y - 0.5) / me.imgSize_y;
+                       // updateAspect will reset zoomOffset to '0.5 0.5 0' if
+                       // with this zoomFactor the image will not be zoomed in
+                       // (updateAspect will check the new values of imgSize).
                }
-               me.imgOrigin = '0.5 0.5 0' - 0.5 * me.imgSize;
        }
+       me.updateAspect(me);
 }
 void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
 {
index 0f9502d97f022bb7c434da93aa4c6cf219e25df3..d4eaab2a7b8277e51866df26756550f5c6378c8c 100644 (file)
@@ -309,7 +309,7 @@ void ListBox_updateControlTopBottom(entity me)
                me.controlBottom = min((me.scrollPos + 1) / me.getTotalHeight(me), 1);
 
                float minfactor;
-               minfactor = 1 * me.controlWidth / me.size_y * me.size_x;
+               minfactor = 2 * me.controlWidth / me.size_y * me.size_x;
                f = me.controlBottom - me.controlTop;
                if(f < minfactor) // FIXME good default?
                {
index b071a1af34109ebe4c6adb536abda42d82b859d8..c92db27e984f84be22a86ff2ae8049d190c3d478 100644 (file)
@@ -104,7 +104,7 @@ float Slider_keyDown(entity me, float key, float ascii, float shift)
        if(me.disabled)
                return 0;
        inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
-       if(key == K_LEFTARROW || key == K_KP_LEFTARROW || key == K_MWHEELUP)
+       if(key == K_LEFTARROW || key == K_KP_LEFTARROW || key == K_MWHEELDOWN)
        {
                if(inRange)
                        me.setValue(me, median(me.valueMin, me.value - me.valueKeyStep, me.valueMax));
@@ -112,7 +112,7 @@ float Slider_keyDown(entity me, float key, float ascii, float shift)
                        me.setValue(me, me.valueMax);
                return 1;
        }
-       if(key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_MWHEELDOWN)
+       if(key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_MWHEELUP)
        {
                if(inRange)
                        me.setValue(me, median(me.valueMin, me.value + me.valueKeyStep, me.valueMax));
@@ -120,7 +120,7 @@ float Slider_keyDown(entity me, float key, float ascii, float shift)
                        me.setValue(me, me.valueMin);
                return 1;
        }
-       if(key == K_PGUP || key == K_KP_PGUP)
+       if(key == K_PGDN || key == K_KP_PGDN)
        {
                if(inRange)
                        me.setValue(me, median(me.valueMin, me.value - me.valuePageStep, me.valueMax));
@@ -128,7 +128,7 @@ float Slider_keyDown(entity me, float key, float ascii, float shift)
                        me.setValue(me, me.valueMax);
                return 1;
        }
-       if(key == K_PGDN || key == K_KP_PGDN)
+       if(key == K_PGUP || key == K_KP_PGUP)
        {
                if(inRange)
                        me.setValue(me, median(me.valueMin, me.value + me.valuePageStep, me.valueMax));
index 37aaeb4ab1dda7c4cf7b7493f4293a27e907c393..59d8c10db59f6053009f51b90bd39a7c2561c645 100644 (file)
@@ -28,9 +28,9 @@ string TextSlider_valueToIdentifier(entity me, float val)
 string TextSlider_valueToText(entity me, float val)
 {
        if(val >= me.nValues)
-               return _("custom");
+               return _("Custom");
        if(val < 0)
-               return _("custom");
+               return _("Custom");
        return me.(valueStrings[val]);
 }
 void TextSlider_setValueFromIdentifier(entity me, string id)
index b17e91f867bf949bc015244e4881fe3d4f057fb5..0926458bf37989f3100460e788b12b50c95a0fbd 100644 (file)
@@ -53,8 +53,6 @@ void m_init()
        prvm_language = strzone(prvm_language);
        cvar_set("_menu_prvm_language", prvm_language);
 
-       check_unacceptable_compiler_bugs();
-
 #ifdef WATERMARK
        dprintf("^4MQC Build information: ^1%s\n", WATERMARK);
 #endif
@@ -93,6 +91,9 @@ void m_init()
                        m_hide();
                cvar_set("_menu_initialized", "1");
        }
+
+       //PlayerInfo_Details();
+       PlayerStats_PlayerDetail_CheckUpdate();
 }
 
 const float MENU_ASPECT = 1.25; // 1280x1024
index 9d2f693330509499d0f3dd948537b9fd13517266..79b0f9023cd28dedfbde120252393dd53ffb172b 100644 (file)
@@ -14,6 +14,7 @@ config.qh
 
 oo/base.h
 
+../common/playerstats.qh
 ../common/teams.qh
 ../common/constants.qh
 ../common/mapinfo.qh
@@ -40,6 +41,7 @@ oo/implementation.h
 
 ../common/util.qc
 ../common/test.qc
+../common/playerstats.qc
 ../common/command/markup.qc
 ../common/command/rpn.qc
 ../common/command/generic.qc
index 6583898bc7ff8dfc5c50f4e0fa59291a91bcbd6b..1db6e6775d6533f35d9271dfdda1c34515b21ce4 100644 (file)
@@ -71,6 +71,7 @@ SKINBEGIN
        SKINVECTOR(COLOR_DIALOG_HUD, '1 0.7 0.7');
        SKINVECTOR(COLOR_DIALOG_SERVERINFO, '0.7 0.7 1');
        SKINVECTOR(COLOR_DIALOG_CVARS, '1 0 0');
+       SKINVECTOR(COLOR_DIALOG_SCREENSHOTVIEWER, '0.7 0.7 1');
        SKINVECTOR(COLOR_DIALOG_HUDCONFIRM, '1 0 0');
 
        // nexposee positions of windows (they are the scale transformation
@@ -99,7 +100,9 @@ SKINBEGIN
        SKINFLOAT(ALPHA_BEHIND, 0.5);
        SKINFLOAT(ALPHA_TEXT, 0.7);
        SKINVECTOR(COLOR_TEXT, '1 1 1');
-       
+       SKINFLOAT(ALPHA_HEADER, 0.5);
+       SKINVECTOR(COLOR_HEADER, '1 1 1');
+
        // item: button
        SKINSTRING(GFX_BUTTON, "button");
        SKINSTRING(GFX_BUTTON_GRAY, "buttongray");
@@ -251,6 +254,12 @@ SKINBEGIN
        SKINVECTOR(COLOR_SKINLIST_TITLE, '1 1 1');
        SKINVECTOR(COLOR_SKINLIST_AUTHOR, '0.4 0.4 0.7');
 
+       // item: demo list
+       SKINVECTOR(COLOR_DEMOLIST_SUBDIR, '0.5 0.5 0.5');
+
+       // item: screenshot list
+       SKINVECTOR(COLOR_SCREENSHOTLIST_SUBDIR, '0.5 0.5 0.5');
+
        // item: slider
        SKINSTRING(GFX_SLIDER, "slider");
        SKINVECTOR(COLOR_SLIDER_N, '1 1 1');
index b1a1af1966dfd5b44f7bf2f26910443f09cc84c5..631a430dcc455947d8c63e83e0e24297ba5dd7ae 100644 (file)
@@ -15,6 +15,7 @@ CLASS(XonoticCheckBox) EXTENDS(CheckBox)
        ATTRIB(XonoticCheckBox, cvarName, string, string_null)
        METHOD(XonoticCheckBox, loadCvars, void(entity))
        METHOD(XonoticCheckBox, saveCvars, void(entity))
+       ATTRIB(XonoticCheckBox, sendCvars, float, 0)
 
        ATTRIB(XonoticCheckBox, alpha, float, SKINALPHA_TEXT)
        ATTRIB(XonoticCheckBox, disabledAlpha, float, SKINALPHA_DISABLED)
@@ -97,5 +98,7 @@ void XonoticCheckBox_saveCvars(entity me)
                cvar_set(me.cvarName, ftos(me.yesValue));
        else
                cvar_set(me.cvarName, ftos(me.noValue));
+
+       CheckSendCvars(me, me.cvarName);
 }
 #endif
index ecafefed646811efc4749056e41ec4812a9289a6..aeda757f0e83718cbca511cace58aa2c9fc04d85 100644 (file)
@@ -15,6 +15,7 @@ CLASS(XonoticCheckBoxString) EXTENDS(CheckBox)
        ATTRIB(XonoticCheckBoxString, cvarName, string, string_null)
        METHOD(XonoticCheckBoxString, loadCvars, void(entity))
        METHOD(XonoticCheckBoxString, saveCvars, void(entity))
+       ATTRIB(XonoticCheckBoxString, sendCvars, float, 0)
 
        ATTRIB(XonoticCheckBoxString, alpha, float, SKINALPHA_TEXT)
        ATTRIB(XonoticCheckBoxString, disabledAlpha, float, SKINALPHA_DISABLED)
@@ -65,5 +66,7 @@ void XonoticCheckBoxString_saveCvars(entity me)
                cvar_set(me.cvarName, me.yesString);
        else
                cvar_set(me.cvarName, me.noString);
+
+       CheckSendCvars(me, me.cvarName);
 }
 #endif
index cf0e987c0a475dc34fbe920dfc9fa5cd9b6c3686..f2e209ca4d2b38190cdc64ec1f382f4756e4569d 100644 (file)
@@ -6,6 +6,7 @@ CLASS(XonoticDemoList) EXTENDS(XonoticListBox)
        METHOD(XonoticDemoList, drawListBoxItem, void(entity, float, vector, float))
        METHOD(XonoticDemoList, getDemos, void(entity))
        METHOD(XonoticDemoList, startDemo, void(entity))
+       METHOD(XonoticDemoList, timeDemo, void(entity))
        METHOD(XonoticDemoList, demoName, string(entity, float))
        METHOD(XonoticDemoList, clickListBoxItem, void(entity, float, vector))
        METHOD(XonoticDemoList, keyDown, float(entity, float, float, float))
@@ -25,9 +26,9 @@ CLASS(XonoticDemoList) EXTENDS(XonoticListBox)
        ATTRIB(XonoticDemoList, filterString, string, string_null)
 ENDCLASS(XonoticDemoList)
 
+entity demolist; // for reference elsewhere
 entity makeXonoticDemoList();
-void StartDemo_Click(entity btn, entity me);
-void TimeDemo_Click(entity btn, entity me);
+void DemoList_Refresh_Click(entity btn, entity me);
 void DemoList_Filter_Change(entity box, entity me);
 #endif
 
@@ -47,40 +48,75 @@ void XonoticDemoList_configureXonoticDemoList(entity me)
        me.getDemos(me);
 }
 
-string XonoticDemoList_demoName(entity me, float i )
+string XonoticDemoList_demoName(entity me, float i)
 {
        string s;
-       s = search_getfilename(me.listDemo, i);
-       s = substring(s, 6, strlen(s) - 6 - 4);  // demos/, .dem
+       s = bufstr_get(me.listDemo, i);
+
+       if(substring(s, 0, 1) == "/")
+               s = substring(s, 1, strlen(s) - 1);  // remove the first forward slash
+
        return s;
 }
 
-
-void XonoticDemoList_getDemos(entity me)
+// if subdir is TRUE look in subdirectories too (1 level)
+void getDemos_for_ext(entity me, string ext, float subdir)
 {
        string s;
-
+       if (subdir)
+               s="demos/*/";
+       else
+               s="demos/";
        if(me.filterString)
-               //subdirectory in filterString allowed
-               s=strcat("demos/*", me.filterString, "*.dem");
+               s=strcat(s, me.filterString, ext);
        else
-               s="demos/*.dem";
-
-       //dprint("Search demos with the pattern ", s, "\n");
-       if(me.listDemo >= 0)
-               search_end(me.listDemo);
+               s=strcat(s, "*", ext);
+
+       float list, i, n;
+       list = search_begin(s, FALSE, TRUE);
+       if(list >= 0)
+       {
+               n = search_getsize(list);
+               for(i = 0; i < n; ++i)
+               {
+                       s = search_getfilename(list, i); // get initial full file name
+                       s = substring(s, 6, (strlen(s) - 6 - 4)); // remove "demos/" prefix and ".dem" suffix
+                       s = strdecolorize(s); // remove any pre-existing colors
+                       if(subdir)
+                       {
+                               s = strreplace("/", "^7/", s); // clear colors at the forward slash
+                               s = strcat("/", rgb_to_hexcolor(SKINCOLOR_DEMOLIST_SUBDIR), s); // add a forward slash for sorting, then color
+                               bufstr_add(me.listDemo, s, TRUE);
+                       }
+                       else { bufstr_add(me.listDemo, s, TRUE); }
+               }
+               search_end(list);
+       }
 
-       me.listDemo = search_begin(s, FALSE, TRUE);
+       if (subdir)
+               getDemos_for_ext(me, ext, FALSE);
+}
 
-       if(me.listDemo < 0)
-               me.nItems=0;
-       else
-               me.nItems=search_getsize(me.listDemo);
+void XonoticDemoList_getDemos(entity me)
+{
+       if (me.listDemo >= 0)
+               buf_del(me.listDemo);
+       me.listDemo = buf_create();
+       if (me.listDemo < 0)
+       {
+               me.nItems = 0;
+               return;
+       }
+       getDemos_for_ext(me, ".dem", TRUE);
+       me.nItems = buf_getsize(me.listDemo);
+       if(me.nItems > 0)
+               buf_sort(me.listDemo, 128, FALSE);
 }
 
 void XonoticDemoList_destroy(entity me)
 {
-       search_end(me.listDemo);
+       if(me.nItems > 0)
+               buf_del(me.listDemo);
 }
 
 void XonoticDemoList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
@@ -104,7 +140,7 @@ void XonoticDemoList_drawListBoxItem(entity me, float i, vector absSize, float i
 
        s = me.demoName(me,i);
        s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
+       draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 1);
 }
 
 void XonoticDemoList_showNotify(entity me)
@@ -112,13 +148,24 @@ void XonoticDemoList_showNotify(entity me)
        me.getDemos(me);
 }
 
+void DemoList_Refresh_Click(entity btn, entity me)
+{
+       me.getDemos(me);
+       me.setSelected(me, 0); //always select the first element after a list update
+}
+
 void DemoList_Filter_Change(entity box, entity me)
 {
        if(me.filterString)
                strunzone(me.filterString);
 
        if(box.text != "")
-               me.filterString = strzone(box.text);
+       {
+               if (strstrofs(box.text, "*", 0) >= 0 || strstrofs(box.text, "?", 0) >= 0)
+                       me.filterString = strzone(box.text);
+               else
+                       me.filterString = strzone(strcat("*", box.text, "*"));
+       }
        else
                me.filterString = string_null;
 
@@ -128,20 +175,36 @@ void DemoList_Filter_Change(entity box, entity me)
 void XonoticDemoList_startDemo(entity me)
 {
        string s;
-       s = me.demoName(me,me.selectedItem);
+       s = me.demoName(me, me.selectedItem);
+       s = strdecolorize(s);
+
        localcmd("playdemo \"demos/", s, ".dem\" \nwait \ntogglemenu\n");
 }
 
-void StartDemo_Click(entity btn, entity me)
+void XonoticDemoList_timeDemo(entity me)
 {
-       me.startDemo(me);
+       string s;
+       s = me.demoName(me, me.selectedItem);
+       s = strdecolorize(s);
+
+       localcmd("timedemo \"demos/", s, ".dem\" \nwait \ntogglemenu\n");
 }
 
-void TimeDemo_Click(entity btn, entity me)
+void DemoConfirm_ListClick_Check_Gamestatus(entity me)
 {
-       string s;
-       s = me.demoName(me,me.selectedItem);
-       localcmd("timedemo \"demos/", s, ".dem\" \nwait \ntogglemenu\n");
+       if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER))) // we're not in a match, lets watch the demo
+       {
+               me.startDemo(me);
+       }
+       else // already in a match, player has to confirm
+       {
+               DialogOpenButton_Click_withCoords(
+                       me,
+                       main.demostartconfirmDialog,
+                       boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size),
+                       boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size)
+               );
+       }
 }
 
 void XonoticDemoList_clickListBoxItem(entity me, float i, vector where)
@@ -151,7 +214,7 @@ void XonoticDemoList_clickListBoxItem(entity me, float i, vector where)
                {
                        // DOUBLE CLICK!
                        me.setSelected(me, i);
-                       me.startDemo(me);
+                       DemoConfirm_ListClick_Check_Gamestatus(me);
                }
        me.lastClickedDemo = i;
        me.lastClickedTime = time;
@@ -159,12 +222,15 @@ void XonoticDemoList_clickListBoxItem(entity me, float i, vector where)
 
 float XonoticDemoList_keyDown(entity me, float scan, float ascii, float shift)
 {
-       if(scan == K_ENTER || scan == K_KP_ENTER) {
-               me.startDemo(me);
+       if(scan == K_ENTER || scan == K_KP_ENTER)
+       {
+               DemoConfirm_ListClick_Check_Gamestatus(me);
                return 1;
        }
        else
+       {
                return SUPER(XonoticDemoList).keyDown(me, scan, ascii, shift);
+       }
 }
 #endif
 
index 2c86f79c38fe322dfe77e8a16cd862a17c896029..7d234c7fe84907a024e1de737d5b73810f0014d0 100644 (file)
@@ -13,15 +13,17 @@ ENDCLASS(XonoticMultiplayerDialog)
 void XonoticMultiplayerDialog_fill(entity me)
 {
        entity mc, e;
-       mc = makeXonoticTabController(me.rows - 2);
+       mc = makeXonoticTabController(me.rows - 1);
        me.TR(me);
                me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Servers"), makeXonoticServerListTab()));
                me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Create"), makeXonoticServerCreateTab()));
-               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Demos"), makeXonoticDemoBrowserTab()));
-               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Player Setup"), makeXonoticPlayerSettingsTab()));
+               //me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Demos"), makeXonoticDemoBrowserTab()));
+               //me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Screenshots"), makeXonoticScreenshotBrowserTab()));
+               //me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Players"), makeXonoticDemoBrowserTab()));
+               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Media"), makeXonoticMediaTab()));
+               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Profile"), makeXonoticProfileTab()));
 
        me.TR(me);
-       me.TR(me);
-               me.TD(me, me.rows - 2, me.columns, mc);
+               me.TD(me, me.rows - 1, me.columns, mc);
 }
 #endif
index e4aa1d6d97d30600e76a779ee1d26ce228f920d5..8ae9107a9af0d53c4c02968e5fe599099890b281 100644 (file)
@@ -5,20 +5,54 @@ CLASS(XonoticServerCreateTab) EXTENDS(XonoticTab)
        METHOD(XonoticServerCreateTab, gameTypeSelectNotify, void(entity))
        ATTRIB(XonoticServerCreateTab, title, string, _("Create"))
        ATTRIB(XonoticServerCreateTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticServerCreateTab, rows, float, 22)
+       ATTRIB(XonoticServerCreateTab, rows, float, 23)
        ATTRIB(XonoticServerCreateTab, columns, float, 6.2) // added extra .2 for center space
 
        ATTRIB(XonoticServerCreateTab, mapListBox, entity, NULL)
        ATTRIB(XonoticServerCreateTab, sliderFraglimit, entity, NULL)
+       ATTRIB(XonoticServerCreateTab, sliderTeams, entity, NULL)
        ATTRIB(XonoticServerCreateTab, sliderTimelimit, entity, NULL)
-       ATTRIB(XonoticServerCreateTab, checkboxFraglimit, entity, NULL)
-       ATTRIB(XonoticServerCreateTab, checkboxFraglimitMapinfo, entity, NULL)
+       ATTRIB(XonoticServerCreateTab, labelFraglimit, entity, NULL)
+       ATTRIB(XonoticServerCreateTab, labelTeams, entity, NULL)
 ENDCLASS(XonoticServerCreateTab)
 entity makeXonoticServerCreateTab();
 #endif
 
 #ifdef IMPLEMENTATION
 
+void GameType_ConfigureSliders(entity e, entity l, string pLabel, float pMin, float pMax, float pStep, string pCvar)
+{
+       if(pCvar == "")
+       {
+               e.configureXonoticTextSlider(e, string_null);
+               l.setText(l, pLabel);
+               e.disabled = l.disabled = TRUE;
+       }
+       else
+       {
+               e.configureXonoticTextSlider(e, pCvar);
+               
+               // clear old values
+               float i;
+               for(i = 0; i <= e.nValues; ++i);
+               {
+                       if(e.(valueStrings[i])) { strunzone(e.(valueStrings[i])); }
+                       if(e.(valueIdentifiers[i])) { strunzone(e.(valueIdentifiers[i])); }
+               }
+               e.clearValues(e);
+
+               // set new values
+               e.addValue(e, strzone(_("Default")), strzone("-1"));
+               for(i = pMin; i <= pMax; i += pStep) { e.addValue(e, strzone(ftos(i)), strzone(ftos(i))); }
+               e.addValue(e, strzone(_("Unlimited")), strzone("0"));
+               e.configureXonoticTextSliderValues(e);
+
+               // set text field
+               l.setText(l, pLabel);
+               e.disabled = l.disabled = FALSE;
+       }
+}
+
 entity makeXonoticServerCreateTab()
 {
        entity me;
@@ -31,35 +65,47 @@ void XonoticServerCreateTab_fill(entity me)
 {
        entity e, e0;
 
+       me.gotoRC(me, 0.5, 0);
+               me.TD(me, 1, 3, makeXonoticHeaderLabel(_("Gametype")));
        me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Game type:")));
-       me.TR(me);
-               me.TD(me, 8, 3, e = makeXonoticGametypeList());
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-               //me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Match settings:"))); // pointless, overcrowds the dialog imo
-       me.TR(me);
-               me.sliderTimelimit = makeXonoticSlider(1.0, 60.0, 1, "timelimit_override");
-               me.TD(me, 1, 1, e = makeXonoticSliderCheckBox(0, 1, me.sliderTimelimit, _("Time limit:")));
-               me.TD(me, 1, 2, me.sliderTimelimit);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticSliderCheckBox(-1, 0, me.sliderTimelimit, _("Use map specified default")));
-       me.TR(me);
-               me.sliderFraglimit = makeXonoticSlider(1.0, 2000.0, 5, "fraglimit_override");
-               me.TD(me, 1, 1, e = makeXonoticSliderCheckBox(0, 1, me.sliderFraglimit, _("Point limit:")));
-                       me.checkboxFraglimit = e;
-               me.TD(me, 1, 2, me.sliderFraglimit);
+               me.TD(me, 10.5, 3, e = makeXonoticGametypeList());
+
+       me.gotoRC(me, 12.5, 0);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Time limit:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("timelimit_override"));
+                       e.addValue(e, ZCTX(_("TIMLIM^Default")), "-1");
+                       e.addValue(e, ZCTX(_("TIMLIM^1 minute")), "1");
+                       e.addValue(e, ZCTX(_("TIMLIM^2 minutes")), "2");
+                       e.addValue(e, ZCTX(_("TIMLIM^3 minutes")), "3");
+                       e.addValue(e, ZCTX(_("TIMLIM^4 minutes")), "4");
+                       e.addValue(e, ZCTX(_("TIMLIM^5 minutes")), "5");
+                       e.addValue(e, ZCTX(_("TIMLIM^6 minutes")), "6");
+                       e.addValue(e, ZCTX(_("TIMLIM^7 minutes")), "7");
+                       e.addValue(e, ZCTX(_("TIMLIM^8 minutes")), "8");
+                       e.addValue(e, ZCTX(_("TIMLIM^9 minutes")), "9");
+                       e.addValue(e, ZCTX(_("TIMLIM^10 minutes")), "10");
+                       e.addValue(e, ZCTX(_("TIMLIM^15 minutes")), "15");
+                       e.addValue(e, ZCTX(_("TIMLIM^20 minutes")), "20");
+                       e.addValue(e, ZCTX(_("TIMLIM^25 minutes")), "25");
+                       e.addValue(e, ZCTX(_("TIMLIM^30 minutes")), "30");
+                       e.addValue(e, ZCTX(_("TIMLIM^40 minutes")), "40");
+                       e.addValue(e, ZCTX(_("TIMLIM^50 minutes")), "50");
+                       e.addValue(e, ZCTX(_("TIMLIM^60 minutes")), "60");
+                       e.addValue(e, ZCTX(_("TIMLIM^Infinite")), "0");
+                       e.configureXonoticTextSliderValues(e);
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticSliderCheckBox(-1, 0, me.sliderFraglimit, _("Use map specified default")));
-                       me.checkboxFraglimitMapinfo = e;
+               me.TD(me, 1, 1, me.labelFraglimit = makeXonoticTextLabel(0, _("Frag limit:")));
+               me.TD(me, 1, 2, me.sliderFraglimit = makeXonoticTextSlider("fraglimit_override"));
+                       GameType_ConfigureSliders(me.sliderFraglimit, me.labelFraglimit, _("Frag limit:"), 5, 100, 5, "fraglimit_override");
+
+       me.gotoRC(me, 15, 0);
+               me.TD(me, 1, 1, me.labelTeams = makeXonoticTextLabel(0, _("Teams:")));
+               me.TD(me, 1, 2, e = me.sliderTeams = makeXonoticTextSlider(string_null));
+                       e.addValue(e, _("Default"), "0");
+                       e.addValue(e, _("2 teams"), "2");
+                       e.addValue(e, _("3 teams"), "3");
+                       e.addValue(e, _("4 teams"), "4");
+                       e.configureXonoticTextSliderValues(e);
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Player slots:")));
                me.TD(me, 1, 2, makeXonoticSlider(1, 32, 1, "menu_maxplayers"));
@@ -83,37 +129,33 @@ void XonoticServerCreateTab_fill(entity me)
                        e.addValue(e, _("Godlike"), "10");
                        e.configureXonoticTextSliderValues(e);
                        setDependent(e, "bot_number", 0, -1);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticButton(_("Mutators..."), '0 0 0'));
-                       e.onClick = DialogOpenButton_Click;
-                       e.onClickEntity = main.mutatorsDialog;
-                       main.mutatorsDialog.refilterEntity = me.mapListBox;
-               me.TD(me, 1, 2, e0 = makeXonoticTextLabel(0, string_null));
+
+       me.gotoRC(me, me.rows - 3.5, 0);
+               me.TD(me, 1, 3, e0 = makeXonoticTextLabel(0.5, string_null));
                        e0.textEntity = main.mutatorsDialog;
                        e0.allowCut = 1;
+                       //e0.allowWrap = 1;
        me.TR(me);
                me.TDempty(me, 0.5);
-               me.TD(me, 1, 2, e = makeXonoticButton(_("Advanced settings..."), '0 0 0'));
+               me.TD(me, 1, 2, e = makeXonoticButton(_("Mutators"), '0 0 0'));
                        e.onClick = DialogOpenButton_Click;
-                       e.onClickEntity = main.advancedDialog;
-                       main.advancedDialog.refilterEntity = me.mapListBox;
+                       e.onClickEntity = main.mutatorsDialog;
+                       main.mutatorsDialog.refilterEntity = me.mapListBox;
 
-       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+       me.gotoRC(me, 0.5, 3.2); me.setFirstColumn(me, me.currentColumn);
                me.mapListBox = makeXonoticMapList();
-               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Map list:")));
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Maplist")));
                        makeCallback(e, me.mapListBox, me.mapListBox.refilterCallback);
        me.TR(me);
                me.TD(me, me.rows - 4, 3, me.mapListBox);
-       me.gotoRC(me, me.rows - 3, 3.5);
-               me.TDempty(me, 0.25);
+       me.gotoRC(me, me.rows - 2.5, 3.2);
+               me.TDempty(me, 0.375);
                me.TD(me, 1, 1.125, e = makeXonoticButton(_("Select all"), '0 0 0'));
                        e.onClick = MapList_All;
                        e.onClickEntity = me.mapListBox;
                me.TD(me, 1, 1.125, e = makeXonoticButton(_("Select none"), '0 0 0'));
                        e.onClick = MapList_None;
                        e.onClickEntity = me.mapListBox;
-               me.TDempty(me, 0.25);
 
        me.gotoRC(me, me.rows - 1, 0);
                me.TD(me, 1, me.columns, e = makeXonoticButton(_("Start Multiplayer!"), '0 0 0'));
@@ -124,45 +166,47 @@ void XonoticServerCreateTab_fill(entity me)
        me.gameTypeChangeNotify(me);
 }
 
-void GameType_ConfigureSliders(entity e, entity l, entity l2, string pLabel, float pMin, float pMax, float pStep, string pCvar)
-{
-       if(pCvar == "")
-       {
-               e.configureXonoticSlider(e, pMin, pMax, pStep, string_null);
-               l.setText(l, pLabel);
-               e.disabled = l.disabled = l2.disabled = TRUE;
-       }
-       else
-       {
-               e.configureXonoticSlider(e, pMin, pMax, pStep, pCvar);
-               l.setText(l, pLabel);
-               e.disabled = l.disabled = l2.disabled = FALSE;
-       }
-}
-
 void XonoticServerCreateTab_gameTypeChangeNotify(entity me)
 {
        // tell the map list to update
        float gt;
-       entity e, l, l2;
+       entity e, l;
        gt = MapInfo_CurrentGametype();
        e = me.sliderFraglimit;
-       l = me.checkboxFraglimit;
-       l2 = me.checkboxFraglimitMapinfo;
+       l = me.labelFraglimit;
+
        switch(gt)
        {
-               case MAPINFO_TYPE_CTF:        GameType_ConfigureSliders(e, l, l2, _("Capture limit:"),   1,   20, 1, "capturelimit_override");     break;
-               case MAPINFO_TYPE_DOMINATION: GameType_ConfigureSliders(e, l, l2, _("Point limit:"),    50,  500, 10, "g_domination_point_limit"); break;
-               case MAPINFO_TYPE_KEYHUNT:    GameType_ConfigureSliders(e, l, l2, _("Point limit:"),   200, 1500, 50, "g_keyhunt_point_limit");    break;
-               case MAPINFO_TYPE_LMS:        GameType_ConfigureSliders(e, l, l2, _("Lives:"),           3,   50,  1, "g_lms_lives_override");     break;
-               case MAPINFO_TYPE_RACE:       GameType_ConfigureSliders(e, l, l2, _("Laps:"),            1,   25,  1, "g_race_laps_limit");        break;
-               case MAPINFO_TYPE_NEXBALL:    GameType_ConfigureSliders(e, l, l2, _("Goals:"),           1,   50,  1, "g_nexball_goallimit");      break;
-               case MAPINFO_TYPE_ASSAULT:    GameType_ConfigureSliders(e, l, l2, _("Point limit:"),    50,  500, 10, "");                         break;
-               case MAPINFO_TYPE_ONSLAUGHT:  GameType_ConfigureSliders(e, l, l2, _("Point limit:"),    50,  500, 10, "");                         break;
-               case MAPINFO_TYPE_CTS:        GameType_ConfigureSliders(e, l, l2, _("Point limit:"),    50,  500, 10, "");                         break;
-               case MAPINFO_TYPE_INVASION:   GameType_ConfigureSliders(e, l, l2, _("Point limit:"),     5,    0,  5, "");                         break;
-               default:                      GameType_ConfigureSliders(e, l, l2, _("Frag limit:"),      5,  100,  5, "fraglimit_override");       break;
+               case MAPINFO_TYPE_CTF:        GameType_ConfigureSliders(e, l, _("Capture limit:"),   1,   20, 1, "capturelimit_override");     break;
+               case MAPINFO_TYPE_DOMINATION: GameType_ConfigureSliders(e, l, _("Point limit:"),    50,  500, 10, "g_domination_point_limit"); break;
+               case MAPINFO_TYPE_KEYHUNT:    GameType_ConfigureSliders(e, l, _("Point limit:"),   200, 1500, 50, "g_keyhunt_point_limit");    break;
+               case MAPINFO_TYPE_LMS:        GameType_ConfigureSliders(e, l, _("Lives:"),           3,   50,  1, "g_lms_lives_override");     break;
+               case MAPINFO_TYPE_RACE:       GameType_ConfigureSliders(e, l, _("Laps:"),            1,   25,  1, "g_race_laps_limit");        break;
+               case MAPINFO_TYPE_NEXBALL:    GameType_ConfigureSliders(e, l, _("Goals:"),           1,   50,  1, "g_nexball_goallimit");      break;
+               case MAPINFO_TYPE_ASSAULT:    GameType_ConfigureSliders(e, l, _("Point limit:"),    50,  500, 10, "");                         break;
+               case MAPINFO_TYPE_ONSLAUGHT:  GameType_ConfigureSliders(e, l, _("Point limit:"),    50,  500, 10, "");                         break;
+               case MAPINFO_TYPE_CTS:        GameType_ConfigureSliders(e, l, _("Point limit:"),    50,  500, 10, "");                         break;
+               case MAPINFO_TYPE_INVASION:   GameType_ConfigureSliders(e, l, _("Point limit:"),     5,    0,  5, "");                         break;
+               default:                      GameType_ConfigureSliders(e, l, _("Frag limit:"),      5,  100,  5, "fraglimit_override");       break;
        }
+
+       float x = FALSE;
+       e = me.sliderTeams;
+       switch(gt)
+       {
+               case MAPINFO_TYPE_CA:               x = TRUE; e.configureXonoticTextSlider(e, "g_ca_teams_override");          break;
+               case MAPINFO_TYPE_DOMINATION:       x = TRUE; e.configureXonoticTextSlider(e, "g_domination_teams_override");  break;
+               case MAPINFO_TYPE_FREEZETAG:        x = TRUE; e.configureXonoticTextSlider(e, "g_freezetag_teams_override");   break;
+               case MAPINFO_TYPE_KEEPAWAY:         x = TRUE; e.configureXonoticTextSlider(e, "g_keepaway_teams_override");    break;
+               case MAPINFO_TYPE_KEYHUNT:          x = TRUE; e.configureXonoticTextSlider(e, "g_keyhunt_teams_override");     break;
+               case MAPINFO_TYPE_TEAM_DEATHMATCH:  x = TRUE; e.configureXonoticTextSlider(e, "g_tdm_teams_override");         break;
+
+               default: x = FALSE; e.configureXonoticTextSlider(e, string_null); break;
+       }
+       e.configureXonoticTextSliderValues(e);
+       e.value = 0;
+       me.sliderTeams.disabled = me.labelTeams.disabled = !x;
+
        me.mapListBox.refilter(me.mapListBox);
 }
 
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create_advanced.c b/qcsrc/menu/xonotic/dialog_multiplayer_create_advanced.c
deleted file mode 100644 (file)
index e6fffe0..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticAdvancedDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticAdvancedDialog, fill, void(entity))
-       METHOD(XonoticAdvancedDialog, showNotify, void(entity))
-       METHOD(XonoticAdvancedDialog, close, void(entity))
-       ATTRIB(XonoticAdvancedDialog, title, string, _("Advanced server settings"))
-       ATTRIB(XonoticAdvancedDialog, color, vector, SKINCOLOR_DIALOG_ADVANCED)
-       ATTRIB(XonoticAdvancedDialog, intendedWidth, float, 0.5)
-       ATTRIB(XonoticAdvancedDialog, rows, float, 17)
-       ATTRIB(XonoticAdvancedDialog, columns, float, 3)
-       ATTRIB(XonoticAdvancedDialog, refilterEntity, entity, NULL)
-ENDCLASS(XonoticAdvancedDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticAdvancedDialog_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-
-void XonoticAdvancedDialog_fill(entity me)
-{
-       entity e;
-       me.TR(me);
-               me.TD(me, 1, 3, makeXonoticTextLabel(0, _("Game settings:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, makeXonoticCheckBox(0, "sv_spectate", _("Allow spectating")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, makeXonoticTextLabel(0, _("Spawn shield:")));
-               me.TD(me, 1, 1.6, makeXonoticSlider(0, 15, 0.5, "g_spawnshieldtime"));
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, makeXonoticTextLabel(0, _("Game speed:")));
-               me.TD(me, 1, 1.6, makeXonoticSlider(0.5, 2.0, 0.1, "slowmo"));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, makeXonoticTextLabel(0, _("Teamplay settings:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, makeXonoticTextLabel(0, _("Friendly fire scale:")));
-               me.TD(me, 1, 1.6, makeXonoticSlider(0, 1.0, 0.05, "g_friendlyfire"));
-       me.TR(me);
-               me.TDempty(me, 0.4);
-               me.TD(me, 1, 2.6, makeXonoticCheckBox(0, "g_friendlyfire_virtual", _("Virtual friendly fire (effect only)")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, makeXonoticTextLabel(0, _("Friendly fire penalty:")));
-               me.TD(me, 1, 1.6, makeXonoticSlider(0, 1.0, 0.05, "g_mirrordamage"));
-       me.TR(me);
-               me.TDempty(me, 0.4);
-               me.TD(me, 1, 2.6, makeXonoticCheckBox(0, "g_mirrordamage_virtual", _("Virtual penalty (effect only)")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, makeXonoticTextLabel(0, _("Teams:")));
-               me.TD(me, 1, 1.6, e = makeXonoticTextSlider("g_tdm_teams_override g_domination_teams_override g_ca_teams_override g_freezetag_teams_override g_keyhunt_teams_override"));
-                       e.addValue(e, "Default", "0");
-                       e.addValue(e, "2 teams", "2");
-                       e.addValue(e, "3 teams", "3");
-                       e.addValue(e, "4 teams", "4");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, makeXonoticTextLabel(0, _("Map voting:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("g_maplist_votable"));
-                       e.addValue(e, _("No voting"), "0");
-                       e.addValue(e, _("2 choices"), "2");
-                       e.addValue(e, _("3 choices"), "3");
-                       e.addValue(e, _("4 choices"), "4");
-                       e.addValue(e, _("5 choices"), "5");
-                       e.addValue(e, _("6 choices"), "6");
-                       e.addValue(e, _("7 choices"), "7");
-                       e.addValue(e, _("8 choices"), "8");
-                       e.addValue(e, _("9 choices"), "9");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 3, makeXonoticCheckBoxEx(0.5, 0, "sv_vote_simple_majority_factor", _("Simple majority wins vcall")));
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-
-void XonoticAdvancedDialog_close(entity me)
-{
-       if(me.refilterEntity)
-               me.refilterEntity.refilter(me.refilterEntity);
-       SUPER(XonoticAdvancedDialog).close(me);
-}
-#endif
index e5dec8fff5478e8948d14539f259cfec3026cd35..9baf36127dfe56648994b79735a84a5c124a06a3 100644 (file)
@@ -5,7 +5,7 @@ CLASS(XonoticMapInfoDialog) EXTENDS(XonoticDialog)
        ATTRIB(XonoticMapInfoDialog, title, string, _("Map Information"))
        ATTRIB(XonoticMapInfoDialog, color, vector, SKINCOLOR_DIALOG_MAPINFO)
        ATTRIB(XonoticMapInfoDialog, intendedWidth, float, 1.0)
-       ATTRIB(XonoticMapInfoDialog, rows, float, 12)
+       ATTRIB(XonoticMapInfoDialog, rows, float, 11)
        ATTRIB(XonoticMapInfoDialog, columns, float, 10)
 
        ATTRIB(XonoticMapInfoDialog, previewImage, entity, NULL)
@@ -22,7 +22,6 @@ CLASS(XonoticMapInfoDialog) EXTENDS(XonoticDialog)
        ATTRIB(XonoticMapInfoDialog, currentMapAuthor, string, string_null)
        ATTRIB(XonoticMapInfoDialog, currentMapDescription, string, string_null)
        ATTRIB(XonoticMapInfoDialog, currentMapPreviewImage, string, string_null)
-       ATTRIB(XonoticMapInfoDialog, currentMapFeaturesText, string, string_null)
 ENDCLASS(XonoticMapInfoDialog)
 #endif
 
@@ -40,20 +39,17 @@ void XonoticMapInfoDialog_loadMapInfo(entity me, float i, entity mlb)
                strunzone(me.currentMapAuthor);
                strunzone(me.currentMapDescription);
                strunzone(me.currentMapPreviewImage);
-               strunzone(me.currentMapFeaturesText);
        }
        me.currentMapBSPName = strzone(MapInfo_Map_bspname);
        me.currentMapTitle = strzone(strdecolorize(MapInfo_Map_title));
        me.currentMapAuthor = strzone(strdecolorize(MapInfo_Map_author));
        me.currentMapDescription = strzone(MapInfo_Map_description);
-       me.currentMapFeaturesText = strzone((MapInfo_Map_supportedFeatures & MAPINFO_FEATURE_WEAPONS) ? _("Full item placement") : _("InstaGib only"));
        me.currentMapPreviewImage = strzone(strcat("/maps/", MapInfo_Map_bspname));
 
        me.frame.setText(me.frame, me.currentMapBSPName);
        me.titleLabel.setText(me.titleLabel, me.currentMapTitle);
        me.authorLabel.setText(me.authorLabel, me.currentMapAuthor);
        me.descriptionLabel.setText(me.descriptionLabel, me.currentMapDescription);
-       me.featuresLabel.setText(me.featuresLabel, me.currentMapFeaturesText);
        if(draw_PictureSize(me.currentMapPreviewImage) == '0 0 0')
                me.previewImage.src = "nopreview_map";
        else
@@ -89,11 +85,6 @@ void XonoticMapInfoDialog_fill(entity me)
                        e.colorL = SKINCOLOR_MAPLIST_AUTHOR;
                        e.allowCut = 1;
                        me.authorLabel = e;
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Features:")));
-               me.TD(me, 1, w-1, e = makeXonoticTextLabel(0, ""));
-                       e.allowCut = 1;
-                       me.featuresLabel = e;
        me.TR(me);
                me.TD(me, 1, w, e = makeXonoticTextLabel(0, _("Game types:")));
 
index c276a2cd2efd8b41f4a3f88f67e64315c346311c..9e8969ac0f77126ba163a16c7734685050356f8a 100644 (file)
@@ -7,7 +7,7 @@ CLASS(XonoticMutatorsDialog) EXTENDS(XonoticDialog)
        ATTRIB(XonoticMutatorsDialog, title, string, _("Mutators"))
        ATTRIB(XonoticMutatorsDialog, color, vector, SKINCOLOR_DIALOG_MUTATORS)
        ATTRIB(XonoticMutatorsDialog, intendedWidth, float, 0.9)
-       ATTRIB(XonoticMutatorsDialog, rows, float, 19)
+       ATTRIB(XonoticMutatorsDialog, rows, float, 20)
        ATTRIB(XonoticMutatorsDialog, columns, float, 6)
        ATTRIB(XonoticMutatorsDialog, refilterEntity, entity, NULL)
 ENDCLASS(XonoticMutatorsDialog)
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_demo.c b/qcsrc/menu/xonotic/dialog_multiplayer_demo.c
deleted file mode 100644 (file)
index da85975..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticDemoBrowserTab) EXTENDS(XonoticTab)
-       METHOD(XonoticDemoBrowserTab, fill, void(entity))
-       ATTRIB(XonoticDemoBrowserTab, title, string, _("Demo"))
-       ATTRIB(XonoticDemoBrowserTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticDemoBrowserTab, rows, float, 22)
-       ATTRIB(XonoticDemoBrowserTab, columns, float, 4)
-       ATTRIB(XonoticDemoBrowserTab, name, string, "DemoBrowser")
-ENDCLASS(XonoticDemoBrowserTab)
-entity makeXonoticDemoBrowserTab();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticDemoBrowserTab()
-{
-       entity me;
-       me = spawnXonoticDemoBrowserTab();
-       me.configureDialog(me);
-       return me;
-}
-void XonoticDemoBrowserTab_fill(entity me)
-{
-       entity e, dlist;
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "cl_autodemo", _("Automatically record demos while playing")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 0.5, e = makeXonoticTextLabel(0, _("Filter:")));
-               me.TD(me, 1, 3.5, e = makeXonoticInputBox(0, string_null));
-                       dlist = makeXonoticDemoList();
-                       e.onChange = DemoList_Filter_Change;
-                       e.onChangeEntity = dlist;
-                       dlist.controlledTextbox = e;
-
-       me.TR(me);
-               me.TD(me, me.rows - 4, me.columns, dlist);
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(_("Timedemo"), '0 0 0'));
-                       e.onClick = TimeDemo_Click;
-                       e.onClickEntity = dlist;
-               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(ZCTX(_("DEMO^Play")), '0 0 0'));
-                       e.onClick = StartDemo_Click;
-                       e.onClickEntity = dlist;
-}
-#endif
index 91326ad2d5fd7498111e19c88b09588d8226623e..4636ebbdbbfe3321e25b1a2f7a18b246e414849c 100644 (file)
@@ -3,7 +3,7 @@ CLASS(XonoticServerListTab) EXTENDS(XonoticTab)
        METHOD(XonoticServerListTab, fill, void(entity))
        ATTRIB(XonoticServerListTab, title, string, _("Join"))
        ATTRIB(XonoticServerListTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticServerListTab, rows, float, 22)
+       ATTRIB(XonoticServerListTab, rows, float, 23)
        ATTRIB(XonoticServerListTab, columns, float, 6.5)
 ENDCLASS(XonoticServerListTab)
 entity makeXonoticServerListTab();
@@ -24,12 +24,14 @@ void XonoticServerListTab_fill(entity me)
 
        slist  = makeXonoticServerList();
 
-       me.TR(me);
-               me.TD(me, 1, 0.4, e = makeXonoticTextLabel(0, _("Filter:")));
-               me.TD(me, 1, me.columns - 0.6 * 3 - 0.9 - 0.4, e = makeXonoticInputBox(0, string_null));
+       me.gotoRC(me, 0.5, 0);
+               me.TD(me, 1, 0.6, e = makeXonoticTextLabel(1, _("Filter:")));
+               me.TD(me, 1, 2.8, e = makeXonoticInputBox(0, string_null));
                        e.onChange = ServerList_Filter_Change;
                        e.onChangeEntity = slist;
                        slist.controlledTextbox = e;
+
+       me.gotoRC(me, 0.5, 3.6);
                me.TD(me, 1, 0.9, e = makeXonoticCheckBox(0, "menu_slist_categories", ZCTX(_("SRVS^Categories"))));
                        e.onClickEntity = slist;
                        e.onClick = ServerList_Categories_Click;
@@ -43,14 +45,14 @@ void XonoticServerListTab_fill(entity me)
                        e.onClick = ServerList_ShowFull_Click;
                me.TD(me, 1, 0.6, e = makeXonoticCheckBox(0, "net_slist_pause", _("Pause")));
 
-       me.TR(me);
+       me.gotoRC(me, 2, 0);
                me.TD(me, 1, 1, slist.sortButton1 = makeXonoticButton(string_null, '0 0 0'));
                me.TD(me, 1, 1, slist.sortButton2 = makeXonoticButton(string_null, '0 0 0'));
                me.TD(me, 1, 1, slist.sortButton3 = makeXonoticButton(string_null, '0 0 0'));
                me.TD(me, 1, 1, slist.sortButton4 = makeXonoticButton(string_null, '0 0 0'));
                me.TD(me, 1, 1, slist.sortButton5 = makeXonoticButton(string_null, '0 0 0'));
        me.TR(me);
-               me.TD(me, me.rows - 4, me.columns, slist);
+               me.TD(me, me.rows - 5, me.columns, slist);
 
        me.gotoRC(me, me.rows - 2, 0);
                me.TD(me, 1, 0.6, e = makeXonoticTextLabel(0, _("Address:")));
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media.c b/qcsrc/menu/xonotic/dialog_multiplayer_media.c
new file mode 100644 (file)
index 0000000..9c47ef5
--- /dev/null
@@ -0,0 +1,33 @@
+#ifdef INTERFACE
+CLASS(XonoticMediaTab) EXTENDS(XonoticTab)
+       METHOD(XonoticMediaTab, fill, void(entity))
+       ATTRIB(XonoticMediaTab, title, string, _("Demo"))
+       ATTRIB(XonoticMediaTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticMediaTab, rows, float, 23)
+       ATTRIB(XonoticMediaTab, columns, float, 2)
+       ATTRIB(XonoticMediaTab, name, string, "Media")  
+ENDCLASS(XonoticMediaTab)
+entity makeXonoticMediaTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticMediaTab()
+{
+       entity me;
+       me = spawnXonoticMediaTab();
+       me.configureDialog(me);
+       return me;
+}
+void XonoticMediaTab_fill(entity me)
+{
+       entity mc, e;
+       mc = makeXonoticTabController(me.rows - 2);
+
+       me.gotoRC(me, 0.5, 0);
+               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Demos"), makeXonoticDemoBrowserTab()));
+               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Screenshots"), makeXonoticScreenshotBrowserTab()));
+
+       me.gotoRC(me, 3, 0);
+               me.TD(me, me.rows - 2, me.columns, mc);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_demo.c b/qcsrc/menu/xonotic/dialog_multiplayer_media_demo.c
new file mode 100644 (file)
index 0000000..0923551
--- /dev/null
@@ -0,0 +1,73 @@
+#ifdef INTERFACE
+CLASS(XonoticDemoBrowserTab) EXTENDS(XonoticTab)
+       METHOD(XonoticDemoBrowserTab, fill, void(entity))
+       ATTRIB(XonoticDemoBrowserTab, title, string, _("Demo"))
+       ATTRIB(XonoticDemoBrowserTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticDemoBrowserTab, rows, float, 21)
+       ATTRIB(XonoticDemoBrowserTab, columns, float, 6.5)
+       ATTRIB(XonoticDemoBrowserTab, name, string, "DemoBrowser")
+       ATTRIB(XonoticDemoBrowserTab, democlicktype, float, 0)
+ENDCLASS(XonoticDemoBrowserTab)
+entity makeXonoticDemoBrowserTab();
+const float DMO_PLAY = 1;
+const float DMO_TIME = 2;
+#endif
+
+#ifdef IMPLEMENTATION
+void DemoConfirm_Check_Gamestatus(entity btn, entity me)
+{
+       if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER))) // we're not in a match, lets watch the demo
+       {
+               if(btn.democlicktype == DMO_PLAY)
+                       { demolist.startDemo(demolist); }
+               else if(btn.democlicktype == DMO_TIME)
+                       { demolist.timeDemo(demolist); }
+       }
+       else // already in a match, player has to confirm
+       {
+               if(btn.democlicktype == DMO_PLAY)
+                       { DialogOpenButton_Click(btn, main.demostartconfirmDialog); }
+               else if(btn.democlicktype == DMO_TIME)
+                       { DialogOpenButton_Click(btn, main.demotimeconfirmDialog); }
+       }
+}
+
+entity makeXonoticDemoBrowserTab()
+{
+       entity me;
+       me = spawnXonoticDemoBrowserTab();
+       me.configureDialog(me);
+       return me;
+}
+void XonoticDemoBrowserTab_fill(entity me)
+{
+       entity e;
+       demolist = makeXonoticDemoList();
+
+       me.TR(me);
+               me.TD(me, 1, 0.6, e = makeXonoticTextLabel(1, _("Filter:")));
+               me.TD(me, 1, 2.9, e = makeXonoticInputBox(0, string_null));
+                       e.onChange = DemoList_Filter_Change;
+                       e.onChangeEntity = demolist;
+                       demolist.controlledTextbox = e;
+
+       me.gotoRC(me, 0, 3.7);
+               me.TD(me, 1, 1.5, e = makeXonoticCheckBox(0, "cl_autodemo", _("Auto record demos")));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("Refresh"), '0 0 0'));
+                       e.onClick = DemoList_Refresh_Click;
+                       e.onClickEntity = demolist;
+
+       me.gotoRC(me, 1.5, 0);
+               me.TD(me, me.rows - 2.5, me.columns, demolist);
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(_("Timedemo"), '0 0 0'));
+                       e.democlicktype = DMO_TIME;
+                       e.onClick = DemoConfirm_Check_Gamestatus;
+                       e.onClickEntity = me; // demolist is global anyway
+               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(ZCTX(_("DEMO^Play")), '0 0 0'));
+                       e.democlicktype = DMO_PLAY;
+                       e.onClick = DemoConfirm_Check_Gamestatus;
+                       e.onClickEntity = me; // demolist is global anyway
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.c b/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.c
new file mode 100644 (file)
index 0000000..a5a97c5
--- /dev/null
@@ -0,0 +1,31 @@
+#ifdef INTERFACE
+CLASS(XonoticDemoStartConfirmDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticDemoStartConfirmDialog, fill, void(entity))
+       ATTRIB(XonoticDemoStartConfirmDialog, title, string, _("Disconnect"))
+       ATTRIB(XonoticDemoStartConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
+       ATTRIB(XonoticDemoStartConfirmDialog, intendedWidth, float, 0.5)
+       ATTRIB(XonoticDemoStartConfirmDialog, rows, float, 4)
+       ATTRIB(XonoticDemoStartConfirmDialog, columns, float, 2)
+ENDCLASS(XonoticDemoStartConfirmDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void Handle_StartDemo_Click(entity unused, entity me) { demolist.startDemo(demolist); }
+void XonoticDemoStartConfirmDialog_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Playing a demo will disconnect you from the current match.")));
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you really wish to disconnect now?")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^Yes")), '1 0 0'));
+                       e.onClick = Handle_StartDemo_Click;
+                       e.onClickEntity = demolist;
+               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^No")), '0 1 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.c b/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.c
new file mode 100644 (file)
index 0000000..5510710
--- /dev/null
@@ -0,0 +1,31 @@
+#ifdef INTERFACE
+CLASS(XonoticDemoTimeConfirmDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticDemoTimeConfirmDialog, fill, void(entity))
+       ATTRIB(XonoticDemoTimeConfirmDialog, title, string, _("Disconnect"))
+       ATTRIB(XonoticDemoTimeConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
+       ATTRIB(XonoticDemoTimeConfirmDialog, intendedWidth, float, 0.5)
+       ATTRIB(XonoticDemoTimeConfirmDialog, rows, float, 4)
+       ATTRIB(XonoticDemoTimeConfirmDialog, columns, float, 2)
+ENDCLASS(XonoticDemoTimeConfirmDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void Handle_TimeDemo_Click(entity unused, entity unused) { demolist.timeDemo(demolist); }
+void XonoticDemoTimeConfirmDialog_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Timing a demo will disconnect you from the current match.")));
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you really wish to disconnect now?")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^Yes")), '1 0 0'));
+                       e.onClick = Handle_TimeDemo_Click;
+                       e.onClickEntity = demolist;
+               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^No")), '0 1 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.c b/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.c
new file mode 100644 (file)
index 0000000..6132719
--- /dev/null
@@ -0,0 +1,82 @@
+#ifdef INTERFACE
+CLASS(XonoticScreenshotBrowserTab) EXTENDS(XonoticTab)
+       METHOD(XonoticScreenshotBrowserTab, fill, void(entity))
+       ATTRIB(XonoticScreenshotBrowserTab, title, string, "Screenshot")
+       ATTRIB(XonoticScreenshotBrowserTab, intendedWidth, float, 1)
+       ATTRIB(XonoticScreenshotBrowserTab, rows, float, 21)
+       ATTRIB(XonoticScreenshotBrowserTab, columns, float, 6.5)
+       ATTRIB(XonoticScreenshotBrowserTab, name, string, "ScreenshotBrowser")
+       
+       METHOD(XonoticScreenshotBrowserTab, loadPreviewScreenshot, void(entity, string))
+       ATTRIB(XonoticScreenshotBrowserTab, screenshotImage, entity, NULL)
+       ATTRIB(XonoticScreenshotBrowserTab, currentScrPath, string, string_null)
+ENDCLASS(XonoticScreenshotBrowserTab)
+entity makeXonoticScreenshotBrowserTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticScreenshotBrowserTab()
+{
+       entity me;
+       me = spawnXonoticScreenshotBrowserTab();
+       me.configureDialog(me);
+       return me;
+}
+void XonoticScreenshotBrowserTab_loadPreviewScreenshot(entity me, string scrImage)
+{
+       if (me.currentScrPath == scrImage)
+               return;
+       if (me.currentScrPath)
+               strunzone(me.currentScrPath);
+       me.currentScrPath = strzone(scrImage);
+       me.screenshotImage.load(me.screenshotImage, me.currentScrPath);
+}
+void XonoticScreenshotBrowserTab_fill(entity me)
+{
+       entity e, slist;
+       slist = makeXonoticScreenshotList();
+       float slist_height = me.rows - 2;
+
+
+       me.TR(me);
+               me.TD(me, 1, 0.6, e = makeXonoticTextLabel(1, _("Filter:")));
+               me.TD(me, 1, 2.4, e = makeXonoticInputBox(0, string_null));
+                       e.onChange = ScreenshotList_Filter_Would_Change;
+                       e.onChangeEntity = slist;
+                       slist.screenshotViewerDialog = main.screenshotViewerDialog;
+                       main.screenshotViewerDialog.scrList = slist;
+
+       me.gotoRC(me, 0, 3.1);
+               me.TD(me, 1, 1.9, e = makeXonoticCheckBoxEx(2, 1, "cl_autoscreenshot", _("Auto screenshot scoreboard")));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("Refresh"), '0 0 0'));
+                       e.onClick = ScreenshotList_Refresh_Click;
+                       e.onClickEntity = slist;
+                       
+       /*me.TR(me);
+               me.TD(me, 1, 0.5, e = makeXonoticTextLabel(0, "Filter:"));
+               me.TD(me, 1, me.columns - 1.5, e = makeXonoticInputBox(0, string_null));
+                       e.onChange = ScreenshotList_Filter_Would_Change;
+                       e.onChangeEntity = slist;
+                       slist.screenshotViewerDialog = main.screenshotViewerDialog;
+                       main.screenshotViewerDialog.scrList = slist;
+               me.TD(me, 1, 1, e = makeXonoticButton(_("Refresh"), '0 0 0'));
+                       e.onClick = ScreenshotList_Refresh_Click;
+                       e.onClickEntity = slist;*/
+                       
+       me.gotoRC(me, 1.5, 0);
+               me.TD(me, me.rows - 2.5, me.columns, slist);
+
+       me.gotoRC(me, slist_height + 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("Open in the viewer"), '0 0 0'));
+                       e.onClick = StartScreenshot_Click;
+                       e.onClickEntity = slist;
+/*
+       me.TR(me);
+               me.TD(me, me.rows - me.currentRow, me.columns, e = makeXonoticScreenshotImage());
+                       e.showTitle = 0;
+                       me.screenshotImage = e;
+                       slist.screenshotPreview = e;
+                       slist.screenshotBrowserDialog = me;
+*/
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.c b/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.c
new file mode 100644 (file)
index 0000000..146f496
--- /dev/null
@@ -0,0 +1,171 @@
+#ifdef INTERFACE
+CLASS(XonoticScreenshotViewerDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticScreenshotViewerDialog, fill, void(entity))
+       METHOD(XonoticScreenshotViewerDialog, keyDown, float(entity, float, float, float))
+       METHOD(XonoticScreenshotViewerDialog, loadScreenshot, void(entity, string))
+       METHOD(XonoticScreenshotViewerDialog, close, void(entity))
+       ATTRIB(XonoticScreenshotViewerDialog, title, string, "Screenshot Viewer")
+       ATTRIB(XonoticScreenshotViewerDialog, name, string, "ScreenshotViewer")
+       ATTRIB(XonoticScreenshotViewerDialog, intendedWidth, float, 1)
+       ATTRIB(XonoticScreenshotViewerDialog, rows, float, 25)
+       ATTRIB(XonoticScreenshotViewerDialog, columns, float, 4)
+       ATTRIB(XonoticScreenshotViewerDialog, color, vector, SKINCOLOR_DIALOG_SCREENSHOTVIEWER)
+       ATTRIB(XonoticScreenshotViewerDialog, scrList, entity, NULL)
+       ATTRIB(XonoticScreenshotViewerDialog, screenshotImage, entity, NULL)
+       ATTRIB(XonoticScreenshotViewerDialog, slideShowButton, entity, NULL)
+       ATTRIB(XonoticScreenshotViewerDialog, currentScrPath, string, string_null)
+ENDCLASS(XonoticScreenshotViewerDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+float music_playlist_index_backup;
+void XonoticScreenshotViewerDialog_loadScreenshot(entity me, string scrImage)
+{
+       // disable music as it can lag depending on image loading time
+       if(!cvar("menu_screenshotviewer_enablemusic"))
+       if(cvar("music_playlist_index") != 999) // if the playlist isn't paused
+       {
+               // pause music
+               if(cvar("music_playlist_index") != -1)
+               {
+                       music_playlist_index_backup = cvar("music_playlist_index");
+                       cvar_set("music_playlist_sampleposition0", "0");
+                       cvar_set("music_playlist_index", "999");
+               }
+               else
+                       localcmd("\ncd pause\n");
+       }
+
+       if (me.currentScrPath == scrImage)
+               return;
+       if (me.currentScrPath)
+               strunzone(me.currentScrPath);
+       me.currentScrPath = strzone(scrImage);
+       me.screenshotImage.load(me.screenshotImage, me.currentScrPath);
+       me.frame.setText(me.frame, me.screenshotImage.screenshotTitle);
+}
+void prevScreenshot_Click(entity btn, entity me)
+{
+       me.scrList.goScreenshot(me.scrList, -1);
+}
+void nextScreenshot_Click(entity btn, entity me)
+{
+       me.scrList.goScreenshot(me.scrList, +1);
+}
+void increaseZoom_Click(entity btn, entity me)
+{
+       me.screenshotImage.setZoom(me.screenshotImage, -2, FALSE);
+}
+void decreaseZoom_Click(entity btn, entity me)
+{
+       me.screenshotImage.setZoom(me.screenshotImage, -1/2, FALSE);
+}
+void resetZoom_Click(entity btn, entity me)
+{
+       me.screenshotImage.setZoom(me.screenshotImage, 0, FALSE);
+}
+void toggleSlideShow_Click(entity btn, entity me)
+{
+       if (me.slideShowButton.forcePressed)
+       {
+               me.scrList.stopSlideShow(me.scrList);
+               me.slideShowButton.forcePressed = 0;
+       }
+       else
+       {
+               me.scrList.startSlideShow(me.scrList);
+               me.slideShowButton.forcePressed = 1;
+       }
+}
+float XonoticScreenshotViewerDialog_keyDown(entity me, float key, float ascii, float shift)
+{
+       switch(key)
+       {
+               case K_KP_LEFTARROW:
+               case K_LEFTARROW:
+                       me.scrList.goScreenshot(me.scrList, -1);
+                       return 1;
+               case K_KP_RIGHTARROW:
+               case K_RIGHTARROW:
+                       me.scrList.goScreenshot(me.scrList, +1);
+                       return 1;
+               case K_KP_ENTER:
+               case K_ENTER:
+               case K_SPACE:
+                       // we cannot use SPACE/ENTER directly, as in a dialog they are needed
+                       // to press buttons while browsing with only the keyboard
+                       if (shift & S_CTRL)
+                       {
+                               toggleSlideShow_Click(world, me);
+                               return 1;
+                       }
+                       return SUPER(XonoticScreenshotViewerDialog).keyDown(me, key, ascii, shift);
+               default:
+                       if (key == K_MWHEELUP || ascii == '+')
+                       {
+                               me.screenshotImage.setZoom(me.screenshotImage, -2, (key == K_MWHEELUP));
+                               return 1;
+                       }
+                       else if (key == K_MWHEELDOWN || ascii == '-')
+                       {
+                               me.screenshotImage.setZoom(me.screenshotImage, -1/2, (key == K_MWHEELDOWN));
+                               return 1;
+                       }
+                       if (me.scrList.keyDown(me.scrList, key, ascii, shift))
+                       {
+                               // keyDown has already changed the selected item
+                               me.scrList.goScreenshot(me.scrList, 0);
+                               return 1;
+                       }
+                       return SUPER(XonoticScreenshotViewerDialog).keyDown(me, key, ascii, shift);
+       }
+}
+void XonoticScreenshotViewerDialog_close(entity me)
+{
+       // resume music
+       if(!cvar("menu_screenshotviewer_enablemusic"))
+       if(cvar("music_playlist_index") == 999)
+       {
+               cvar_set("music_playlist_index", ftos(music_playlist_index_backup));
+       }
+       else
+               localcmd("\ncd resume\n");
+
+       me.scrList.stopSlideShow(me.scrList);
+       me.slideShowButton.forcePressed = 0;
+       SUPER(XonoticScreenshotViewerDialog).close(me);
+}
+void XonoticScreenshotViewerDialog_fill(entity me)
+{
+       entity e;
+       me.TR(me);
+               me.TD(me, me.rows - 1, me.columns, e = makeXonoticScreenshotImage());
+                       e.showTitle = 0; // dialog title is enough
+                       me.screenshotImage = e;
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TDempty(me, 1/20 * me.columns);
+               me.TD(me, 1, 1/20 * me.columns, e = makeXonoticButton("-", '0 0 0'));
+                       e.onClick = decreaseZoom_Click;
+                       e.onClickEntity = me;
+               me.TD(me, 1, 1/20 * me.columns, e = makeXonoticButton("+", '0 0 0'));
+                       e.onClick = increaseZoom_Click;
+                       e.onClickEntity = me;
+               me.TD(me, 1, 2/20 * me.columns, e = makeXonoticButton(_("Reset"), '0 0 0'));
+                       e.onClick = resetZoom_Click;
+                       e.onClickEntity = me;
+
+               me.TDempty(me, 2/20 * me.columns);
+               me.TD(me, 1, 3/20 * me.columns, e = makeXonoticButton(_("Previous"), '0 0 0'));
+                       e.onClick = prevScreenshot_Click;
+                       e.onClickEntity = me;
+               me.TD(me, 1, 3/20 * me.columns, e = makeXonoticButton(_("Next"), '0 0 0'));
+                       e.onClick = nextScreenshot_Click;
+                       e.onClickEntity = me;
+
+               me.TDempty(me, 2/20 * me.columns);
+               me.TD(me, 1, 4/20 * me.columns, e = makeXonoticButton(_("Slide show"), '0 0 0'));
+                       e.onClick = toggleSlideShow_Click;
+                       e.onClickEntity = me;
+                       me.slideShowButton = e;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup.c b/qcsrc/menu/xonotic/dialog_multiplayer_playersetup.c
deleted file mode 100644 (file)
index fd4e5cd..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticPlayerSettingsTab) EXTENDS(XonoticTab)
-       METHOD(XonoticPlayerSettingsTab, fill, void(entity))
-       METHOD(XonoticPlayerSettingsTab, draw, void(entity))
-       ATTRIB(XonoticPlayerSettingsTab, title, string, _("Player Setup"))
-       ATTRIB(XonoticPlayerSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticPlayerSettingsTab, rows, float, 22)
-       ATTRIB(XonoticPlayerSettingsTab, columns, float, 6.2) // added extra .2 for center space
-       ATTRIB(XonoticPlayerSettingsTab, playerNameLabel, entity, NULL)
-       ATTRIB(XonoticPlayerSettingsTab, playerNameLabelAlpha, float, 0)
-ENDCLASS(XonoticPlayerSettingsTab)
-entity makeXonoticPlayerSettingsTab();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticPlayerSettingsTab()
-{
-       entity me;
-       me = spawnXonoticPlayerSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-void XonoticPlayerSettingsTab_draw(entity me)
-{
-       if(cvar_string("_cl_name") == cvar_defstring("_cl_name"))
-               me.playerNameLabel.alpha = ((mod(time * 2, 2) < 1) ? 1 : 0);
-       else
-               me.playerNameLabel.alpha = me.playerNameLabelAlpha;
-       SUPER(XonoticPlayerSettingsTab).draw(me);
-}
-void XonoticPlayerSettingsTab_fill(entity me)
-{
-       entity e, pms, label, box;
-       float i;
-
-       me.TR(me);
-               me.TD(me, 1, 0.5, me.playerNameLabel = makeXonoticTextLabel(0, _("Name:")));
-                       me.playerNameLabelAlpha = me.playerNameLabel.alpha;
-               me.TD(me, 1, 2.5, label = makeXonoticTextLabel(0, string_null));
-                       label.allowCut = 1;
-                       label.allowColors = 1;
-                       label.alpha = 1;
-       me.TR(me);
-               me.TD(me, 1, 3.0, box = makeXonoticInputBox(1, "_cl_name"));
-                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
-                       box.maxLength = -127; // negative means encoded length in bytes
-                       box.saveImmediately = 1;
-                       box.enableClearButton = 0;
-                       label.textEntity = box;
-       me.TR(me);
-               me.TD(me, 5, 1, e = makeXonoticColorpicker(box));
-               me.TD(me, 5, 2, e = makeXonoticCharmap(box));
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-
-       me.TR(me);
-               me.TDempty(me, 1);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Model:")));
-       me.TR(me);
-               me.TDempty(me, 1);
-               pms = makeXonoticPlayerModelSelector();
-               me.TD(me, 1, 0.3, e = makeXonoticButton("<<", '0 0 0'));
-                       e.onClick = PlayerModelSelector_Prev_Click;
-                       e.onClickEntity = pms;
-               me.TD(me, me.rows - (me.currentRow + 2), 1.4, pms);
-               me.TD(me, 1, 0.3, e = makeXonoticButton(">>", '0 0 0'));
-                       e.onClick = PlayerModelSelector_Next_Click;
-                       e.onClickEntity = pms;
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0.5, _("Glowing color:")));
-               for(i = 0; i < 15; ++i)
-               {
-                       if(mod(i, 5) == 0)
-                               me.TR(me);
-                       me.TDNoMargin(me, 1, 0.2, e = makeXonoticColorButton(1, 0, i), '0 1 0');
-               }
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0.5, _("Detail color:")));
-               for(i = 0; i < 15; ++i)
-               {
-                       if(mod(i, 5) == 0)
-                               me.TR(me);
-                       me.TDNoMargin(me, 1, 0.2, e = makeXonoticColorButton(2, 1, i), '0 1 0');
-               }
-
-       // crosshair_enabled: 0 = no crosshair options, 1 = no crosshair selection, but everything else enabled, 2 = all crosshair options enabled
-       // FIXME: In the future, perhaps make one global crosshair_type cvar which has 0 for disabled, 1 for custom, 2 for per weapon, etc?
-       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticRadioButton(3, "crosshair_enabled", "0", _("No crosshair")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticRadioButton(3, "crosshair_per_weapon", string_null, _("Per weapon crosshair")));
-               makeMulti(e, "crosshair_enabled");
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticRadioButton(3, "crosshair_enabled", "2", _("Custom crosshair")));
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               for(i = 1; i <= 14; ++i) {
-                       me.TDNoMargin(me, 1, 2 / 14, e = makeXonoticCrosshairButton(4, i), '1 1 0');
-                               setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
-               }
-               // show a larger preview of the selected crosshair
-               me.TDempty(me, 0.1);
-               me.TDNoMargin(me, 3, 0.8, e = makeXonoticCrosshairButton(7, -1), '1 1 0'); // crosshair -1 makes this a preview
-                       setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               for(i = 15; i <= 28; ++i) {
-                       me.TDNoMargin(me, 1, 2 / 14, e = makeXonoticCrosshairButton(4, i), '1 1 0');
-                               setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
-               }
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair size:")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 1.0, 0.01, "crosshair_size"));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair alpha:")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.1, "crosshair_alpha"));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair color:")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 1, e = makeXonoticRadioButton(5, "crosshair_color_special", "1", _("Per weapon")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 1, e = makeXonoticRadioButton(5, "crosshair_color_special", "2", _("By health")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(5, "crosshair_color_special", "0", _("Custom")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-               me.TD(me, 2, 2, e = makeXonoticColorpickerString("crosshair_color", "crosshair_color"));
-                       setDependentAND(e, "crosshair_color_special", 0, 0, "crosshair_enabled", 1, 2);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.5);
-               me.TD(me, 1, 2, e = makeXonoticButton(_("Other crosshair settings"), '0 0 0'));
-                       e.onClick = DialogOpenButton_Click;
-                       e.onClickEntity = main.crosshairDialog;
-               setDependent(e, "crosshair_enabled", 1, 2);
-               // TODO: show status of crosshair dot and hittest and pickups and such here with text
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.5);
-               me.TD(me, 1, 2, e = makeXonoticButton(_("Model settings"), '0 0 0'));
-                       e.onClick = DialogOpenButton_Click;
-                       e.onClickEntity = main.modelDialog;
-               // TODO: show csqc model settings like forcemyplayer and deglowing/ghosting bodies with text here
-       me.TR(me);
-               me.TDempty(me, 0.5);
-               me.TD(me, 1, 2, e = makeXonoticButton(_("View settings"), '0 0 0'));
-                       e.onClick = DialogOpenButton_Click;
-                       e.onClickEntity = main.viewDialog;
-               // TODO: show fov and other settings with text here
-       me.TR(me);
-               me.TDempty(me, 0.5);
-               me.TD(me, 1, 2, e = makeXonoticButton(_("Weapon settings"), '0 0 0'));
-                       e.onClick = DialogOpenButton_Click;
-                       e.onClickEntity = main.weaponsDialog;
-               // I don't really think this is useful as is, and especially it doesn't look very clean...
-               // In the future, if ALL of these buttons had some information, then it would be justified/clean
-               //me.TD(me, 1, 1, e0 = makeXonoticTextLabel(0, string_null));
-               //      e0.textEntity = main.weaponsDialog;
-               //      e0.allowCut = 1;
-       me.TR(me);
-               me.TDempty(me, 0.5);
-               me.TD(me, 1, 2, e = makeXonoticButton(_("HUD settings"), '0 0 0'));
-                       e.onClick = DialogOpenButton_Click;
-                       e.onClickEntity = main.hudDialog;
-               // TODO: show hud config name with text here
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "color -1 -1;name \"$_cl_name\";sendcvar cl_weaponpriority;sendcvar cl_autoswitch;sendcvar cl_forceplayermodels;sendcvar cl_forceplayermodelsfromxonotic;playermodel $_cl_playermodel;playerskin $_cl_playerskin", COMMANDBUTTON_APPLY));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_crosshair.c b/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_crosshair.c
deleted file mode 100644 (file)
index c4cdc3e..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticCrosshairDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticCrosshairDialog, toString, string(entity))
-       METHOD(XonoticCrosshairDialog, fill, void(entity))
-       METHOD(XonoticCrosshairDialog, showNotify, void(entity))
-       ATTRIB(XonoticCrosshairDialog, title, string, _("Crosshair settings"))
-       ATTRIB(XonoticCrosshairDialog, color, vector, SKINCOLOR_DIALOG_CROSSHAIR)
-       ATTRIB(XonoticCrosshairDialog, intendedWidth, float, 0.5)
-       ATTRIB(XonoticCrosshairDialog, rows, float, 18)
-       ATTRIB(XonoticCrosshairDialog, columns, float, 3)
-ENDCLASS(XonoticCrosshairDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticCrosshairDialog_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-string XonoticCrosshairDialog_toString(entity me)
-{
-       return "hi"; // TODO: show status of crosshair dot and hittest and pickups and such here with text
-}
-void XonoticCrosshairDialog_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "crosshair_dot", _("Enable center crosshair dot")));
-               setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Dot size:")));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.2, 2, 0.1, "crosshair_dot_size"));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Dot alpha:")));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 1, 0.1, "crosshair_dot_alpha"));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Dot color:")));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 2, e = makeXonoticRadioButton(1, "crosshair_dot_color_custom", "0", _("Use normal crosshair color")));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               me.TD(me, 1, 0.8, e = makeXonoticRadioButton(1, "crosshair_dot_color_custom", "1", _("Custom")));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-               me.TD(me, 2, 2, e = makeXonoticColorpickerString("crosshair_dot_color", "crosshair_dot_color"));
-                       setDependentAND3(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2, "crosshair_dot_color_custom", 1, 1);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Crosshair animations:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "crosshair_effect_scalefade", _("Smooth effects of crosshairs")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "crosshair_ring", _("Use rings to indicate weapon status")));
-                       makeMulti(e, "crosshair_ring_reload");
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Hit testing:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("crosshair_hittest"));
-                       e.addValue(e, ZCTX(_("HTTST^Disabled")), "0");
-                       e.addValue(e, ZCTX(_("HTTST^TrueAim")), "1");
-                       e.addValue(e, ZCTX(_("HTTST^Enemies")), "1.25");
-                       e.configureXonoticTextSliderValues(e);
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "crosshair_hittest_blur", _("Blur crosshair if the shot is obstructed")));
-                       setDependentAND(e, "crosshair_hittest", 1, 100, "crosshair_enabled", 1, 2);
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.5, 0, "crosshair_hitindication", _("Animate when hitting an enemy")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.25, 0, "crosshair_pickup", _("Animate when picking up an item")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-
-       me.TR(me);
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_hud.c b/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_hud.c
deleted file mode 100644 (file)
index 8d969fd..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticHUDDialog, toString, string(entity))
-       METHOD(XonoticHUDDialog, fill, void(entity))
-       METHOD(XonoticHUDDialog, showNotify, void(entity))
-       ATTRIB(XonoticHUDDialog, title, string, _("HUD settings"))
-       ATTRIB(XonoticHUDDialog, color, vector, SKINCOLOR_DIALOG_HUD)
-       ATTRIB(XonoticHUDDialog, intendedWidth, float, 0.5)
-       ATTRIB(XonoticHUDDialog, rows, float, 18)
-       ATTRIB(XonoticHUDDialog, columns, float, 3)
-ENDCLASS(XonoticHUDDialog)
-void HUDSetup_Start(entity me, entity btn);
-#endif
-
-#ifdef IMPLEMENTATION
-void HUDSetup_Check_Gamestatus(entity me, entity btn)
-{
-       if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER))) // we're not in a match, ask the player if they want to start one anyway
-       {
-               DialogOpenButton_Click(me, main.hudconfirmDialog);
-       }
-       else // already in a match, lets just cut to the point and open up the hud editor directly
-       {
-               HUDSetup_Start(me, btn);
-       }
-}
-void XonoticHUDDialog_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-string XonoticHUDDialog_toString(entity me)
-{
-       return "hi"; // TODO: show hud config name with text here
-}
-void XonoticHUDDialog_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Damage:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Overlay:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "hud_damage"));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Factor:")));
-               setDependent(e, "hud_damage", 0.001, 100);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.025, 0.1, 0.025, "hud_damage_factor"));
-               setDependent(e, "hud_damage", 0.001, 100);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Fade rate:")));
-               setDependent(e, "hud_damage", 0.001, 100);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.25, 1, 0.05, "hud_damage_fade_rate"));
-               setDependent(e, "hud_damage", 0.001, 100);
-       me.TR(me);
-
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_hidewaypoints", _("Waypoints")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Scale:")));
-               setDependent(e, "cl_hidewaypoints", 0, 0);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.5, 1.5, 0.05, "g_waypointsprite_scale"));
-               setDependent(e, "cl_hidewaypoints", 0, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Alpha:")));
-               setDependent(e, "cl_hidewaypoints", 0, 0);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 1, 0.05, "g_waypointsprite_alpha"));
-               setDependent(e, "cl_hidewaypoints", 0, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Edge offset:")));
-               setDependent(e, "cl_hidewaypoints", 0, 0);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0, 0.3, 0.01, "g_waypointsprite_edgeoffset_bottom"));
-               makeMulti(e, "g_waypointsprite_edgeoffset_top g_waypointsprite_edgeoffset_left g_waypointsprite_edgeoffset_right");
-               setDependent(e, "cl_hidewaypoints", 0, 0);
-       me.TR(me);
-
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "hud_shownames", _("Show names above players")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(25, 0, "hud_shownames_crosshairdistance", _("Only when near crosshair")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "hud_shownames_status", _("Display health and armor")));
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.5);
-               me.TD(me, 1, 2, e = makeXonoticButton(_("Enter HUD editor"), '0 0 0'));
-                       e.onClick = HUDSetup_Check_Gamestatus;
-                       e.onClickEntity = me;
-               // TODO: show hud config name with text here
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_hudconfirm.c b/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_hudconfirm.c
deleted file mode 100644 (file)
index 7749a14..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDConfirmDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticHUDConfirmDialog, fill, void(entity))
-       ATTRIB(XonoticHUDConfirmDialog, title, string, _("Enter HUD editor"))
-       ATTRIB(XonoticHUDConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
-       ATTRIB(XonoticHUDConfirmDialog, intendedWidth, float, 0.5)
-       ATTRIB(XonoticHUDConfirmDialog, rows, float, 4)
-       ATTRIB(XonoticHUDConfirmDialog, columns, float, 2)
-ENDCLASS(XonoticHUDConfirmDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void HUDSetup_Start(entity me, entity btn)
-{
-       if (!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
-               localcmd("map hudsetup/hudsetup", "\n");
-       else
-               localcmd("togglemenu 0\n");
-
-       localcmd("_hud_configure 1", "\n");
-}
-
-void XonoticHUDConfirmDialog_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("In order for the HUD editor to show, you must first be in game.")));
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you wish to start a local game to set up the HUD?")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("HDCNFRM^Yes")), '1 0 0'));
-                       e.onClick = HUDSetup_Start;
-                       e.onClickEntity = me;
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("HDCNFRM^No")), '0 1 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_model.c b/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_model.c
deleted file mode 100644 (file)
index d1cdade..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticModelDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticModelDialog, toString, string(entity))
-       METHOD(XonoticModelDialog, fill, void(entity))
-       METHOD(XonoticModelDialog, showNotify, void(entity))
-       ATTRIB(XonoticModelDialog, title, string, _("Model settings"))
-       ATTRIB(XonoticModelDialog, color, vector, SKINCOLOR_DIALOG_MODEL)
-       ATTRIB(XonoticModelDialog, intendedWidth, float, 0.5)
-       ATTRIB(XonoticModelDialog, rows, float, 7)
-       ATTRIB(XonoticModelDialog, columns, float, 3)
-ENDCLASS(XonoticModelDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticModelDialog_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-string XonoticModelDialog_toString(entity me)
-{
-       return "hi"; // TODO: show csqc model settings like forcemyplayer and deglowing/ghosting bodies with text here
-}
-void XonoticModelDialog_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Body fading:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(0, 2, 0.2, "cl_deathglow"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Gibs:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_nogibs"));
-                       e.addValue(e, ZCTX(_("GIBS^None")), "1");
-                       e.addValue(e, ZCTX(_("GIBS^Few")), "0.75");
-                       e.addValue(e, ZCTX(_("GIBS^Many")), "0.5");
-                       e.addValue(e, ZCTX(_("GIBS^Lots")), "0");
-                       e.configureXonoticTextSliderValues(e);
-                       setDependent(e, "cl_gentle", 0, 0);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_forceplayermodels", _("Force player models to mine")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_forceplayercolors", _("Force player colors to mine")));
-       me.TR(me);
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_view.c b/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_view.c
deleted file mode 100644 (file)
index b2b440a..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticViewDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticViewDialog, toString, string(entity))
-       METHOD(XonoticViewDialog, fill, void(entity))
-       METHOD(XonoticViewDialog, showNotify, void(entity))
-       ATTRIB(XonoticViewDialog, title, string, _("View settings"))
-       ATTRIB(XonoticViewDialog, color, vector, SKINCOLOR_DIALOG_VIEW)
-       ATTRIB(XonoticViewDialog, intendedWidth, float, 0.9)
-       ATTRIB(XonoticViewDialog, rows, float, 11)
-       ATTRIB(XonoticViewDialog, columns, float, 6.2) // added extra .2 for center space
-ENDCLASS(XonoticViewDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticViewDialog_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-string XonoticViewDialog_toString(entity me)
-{
-       return "hi"; // TODO: show fov and other settings with text here
-}
-void XonoticViewDialog_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Field of view:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(60, 130, 5, "fov"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Zoom:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_reticle"));
-                       e.addValue(e, ZCTX(_("RETICLE^Fullscreen")), "0");
-                       e.addValue(e, ZCTX(_("RETICLE^With reticle")), "1");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Factor:"))));
-               me.TD(me, 1, 2, e = makeXonoticSlider(2, 16, 0.5, "cl_zoomfactor"));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Speed:"))));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_zoomspeed"));
-                       e.addValue(e, "1", "1"); // Samual: for() loop doesn't work here, even though it would make sense.
-                       e.addValue(e, "2", "2");
-                       e.addValue(e, "3", "3");
-                       e.addValue(e, "4", "4");
-                       e.addValue(e, "5", "5");
-                       e.addValue(e, "6", "6");
-                       e.addValue(e, "7", "7");
-                       e.addValue(e, "8", "8");
-                       e.addValue(e, ZCTX(_("ZOOM^Instant")), "-1");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Sensitivity:"))));
-               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.1, "cl_zoomsensitivity"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Velocity zoom:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_velocityzoom_type"));
-                       e.addValue(e, ZCTX(_("VZOOM^Disabled")), "0");
-                       e.addValue(e, ZCTX(_("VZOOM^Forward only")), "2");
-                       e.addValue(e, ZCTX(_("VZOOM^All directions")), "1");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, ZCTX(_("VZOOM^Speed"))));
-               me.TD(me, 1, 2, e = makeXonoticSlider(-1, 1, 0.2, "cl_velocityzoom"));
-               setDependent(e, "cl_velocityzoom_type", 1, 3);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_clippedspectating", _("Allow passing through walls while spectating")));
-
-       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "chase_active", "0", _("1st person perspective")));
-               makeMulti(e, "crosshair_hittest_showimpact");
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.05, 0, "cl_bobfall", _("Smooth the view when landing from a jump")));
-               setDependent(e, "chase_active", -1, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.05, 0, "cl_smoothviewheight", _("Smooth the view while crouching")));
-               setDependent(e, "chase_active", -1, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(1, 0, "v_idlescale", _("View waving while idle")));
-               setDependent(e, "chase_active", -1, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.01, 0, "cl_bob", _("View bobbing while walking around")));
-               makeMulti(e, "cl_bob2");
-               setDependent(e, "chase_active", -1, 0);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "chase_active", "1", _("3rd person perspective")));
-               makeMulti(e, "crosshair_hittest_showimpact");
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Back distance")));
-               setDependent(e, "chase_active", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(10, 100, 1, "chase_back"));
-               setDependent(e, "chase_active", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Up distance")));
-               setDependent(e, "chase_active", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(10, 50, 1, "chase_up"));
-               setDependent(e, "chase_active", 1, 1);
-       me.TR(me);
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_weapons.c b/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_weapons.c
deleted file mode 100644 (file)
index cfdaf8f..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticWeaponsDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticWeaponsDialog, toString, string(entity))
-       METHOD(XonoticWeaponsDialog, fill, void(entity))
-       METHOD(XonoticWeaponsDialog, showNotify, void(entity))
-       ATTRIB(XonoticWeaponsDialog, title, string, _("Weapon settings"))
-       ATTRIB(XonoticWeaponsDialog, color, vector, SKINCOLOR_DIALOG_WEAPONS)
-       ATTRIB(XonoticWeaponsDialog, intendedWidth, float, 0.7)
-       ATTRIB(XonoticWeaponsDialog, rows, float, 12)
-       ATTRIB(XonoticWeaponsDialog, columns, float, 5.2)
-       ATTRIB(XonoticWeaponsDialog, weaponsList, entity, NULL)
-ENDCLASS(XonoticWeaponsDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticWeaponsDialog_showNotify(entity me)
-{
-        loadAllCvars(me);
-}
-string XonoticWeaponsDialog_toString(entity me)
-{
-       return me.weaponsList.toString(me.weaponsList);
-}
-void XonoticWeaponsDialog_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 2, makeXonoticTextLabel(0, _("Weapon priority list:")));
-       me.TR(me);
-               me.TD(me, 8, 2, e = me.weaponsList = makeXonoticWeaponsList());
-       me.gotoRC(me, 9, 0);
-               me.TD(me, 1, 1, e = makeXonoticButton(_("Up"), '0 0 0'));
-                       e.onClick = WeaponsList_MoveUp_Click;
-                       e.onClickEntity = me.weaponsList;
-               me.TD(me, 1, 1, e = makeXonoticButton(_("Down"), '0 0 0'));
-                       e.onClick = WeaponsList_MoveDown_Click;
-                       e.onClickEntity = me.weaponsList;
-
-       me.gotoRC(me, 0, 2.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_weaponpriority_useforcycling", _("Use priority list for weapon cycling")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_autoswitch", _("Auto switch weapons on pickup")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "r_drawviewmodel", _("Draw 1st person weapon model")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "cl_gunalign", "4", _("Left align")));
-                       setDependent(e, "r_drawviewmodel", 1, 1);
-               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "cl_gunalign", "1", _("Center")));
-                       setDependent(e, "r_drawviewmodel", 1, 1);
-               me.TD(me, 1, 1.0, e = makeXonoticRadioButton(1, "cl_gunalign", "3", _("Right align")));
-                       setDependent(e, "r_drawviewmodel", 1, 1);
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_followmodel", _("Gun model swaying")));
-               makeMulti(e, "cl_leanmodel");
-               setDependent(e, "r_drawviewmodel", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_bobmodel", _("Gun model bobbing")));
-               setDependent(e, "r_drawviewmodel", 1, 1);
-       //me.TR(me);
-       //me.TR(me);
-       //      me.TDempty(me, 0.2);
-       //      me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, ZCTX(_("VWMDL^Scale"))));
-       //      setDependent(e, "r_drawviewmodel", 1, 1);
-       //      me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 2, 0.1, "cl_viewmodel_scale"));
-       //      setDependent(e, "r_drawviewmodel", 1, 1);
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_profile.c b/qcsrc/menu/xonotic/dialog_multiplayer_profile.c
new file mode 100644 (file)
index 0000000..a316be7
--- /dev/null
@@ -0,0 +1,164 @@
+#ifdef INTERFACE
+CLASS(XonoticProfileTab) EXTENDS(XonoticTab)
+       METHOD(XonoticProfileTab, fill, void(entity))
+       METHOD(XonoticProfileTab, draw, void(entity))
+       ATTRIB(XonoticProfileTab, title, string, _("Profile"))
+       ATTRIB(XonoticProfileTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticProfileTab, rows, float, 23)
+       ATTRIB(XonoticProfileTab, columns, float, 6.1) // added extra .2 for center space
+       ATTRIB(XonoticProfileTab, playerNameLabel, entity, NULL)
+       ATTRIB(XonoticProfileTab, playerNameLabelAlpha, float, SKINALPHA_HEADER)
+ENDCLASS(XonoticProfileTab)
+entity makeXonoticProfileTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticProfileTab()
+{
+       entity me;
+       me = spawnXonoticProfileTab();
+       me.configureDialog(me);
+       return me;
+}
+void XonoticProfileTab_draw(entity me)
+{
+       if(cvar_string("_cl_name") == "Player")
+               me.playerNameLabel.alpha = ((mod(time * 2, 2) < 1) ? 1 : 0);
+       else
+               me.playerNameLabel.alpha = me.playerNameLabelAlpha;
+       SUPER(XonoticProfileTab).draw(me);
+}
+void XonoticProfileTab_fill(entity me)
+{
+       entity e, pms, label, box;
+       float i;
+
+       // ==============
+       //  NAME SECTION
+       // ==============
+       me.gotoRC(me, 0.5, 0);
+               me.TD(me, 1, 3, me.playerNameLabel = makeXonoticHeaderLabel(_("Name")));
+
+       me.gotoRC(me, 1.5, 0);
+               me.TD(me, 1, 3, label = makeXonoticTextLabel(0.5, string_null));
+                       label.allowCut = 1;
+                       label.allowColors = 1;
+                       label.alpha = 1;
+                       label.isBold = TRUE;
+                       label.fontSize = SKINFONTSIZE_TITLE;
+
+       me.gotoRC(me, 2.5, 0);
+               me.TD(me, 1, 3.0, box = makeXonoticInputBox(1, "_cl_name"));
+                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
+                       box.maxLength = -127; // negative means encoded length in bytes
+                       box.saveImmediately = 1;
+                       box.enableClearButton = 0;
+                       label.textEntity = box;
+       me.TR(me);
+               me.TD(me, 5, 1, e = makeXonoticColorpicker(box));
+               me.TD(me, 5, 2, e = makeXonoticCharmap(box));
+
+       // ===============
+       //  MODEL SECTION
+       // ===============
+       //me.gotoRC(me, 0.5, 3.1); me.setFirstColumn(me, me.currentColumn); // TOP RIGHT
+       //me.gotoRC(me, 9, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM RIGHT
+       me.gotoRC(me, 9, 0); me.setFirstColumn(me, me.currentColumn); // BOTTOM LEFT
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Model")));
+
+       me.TR(me);
+               //me.TDempty(me, 0); // MODEL LEFT, COLOR RIGHT
+               me.TDempty(me, 1); // MODEL RIGHT, COLOR LEFT
+               pms = makeXonoticPlayerModelSelector();
+               me.TD(me, 1, 0.3, e = makeXonoticButton("<<", '0 0 0'));
+                       e.onClick = PlayerModelSelector_Prev_Click;
+                       e.onClickEntity = pms;
+               me.TD(me, 11.5, 1.4, pms);
+               me.TD(me, 1, 0.3, e = makeXonoticButton(">>", '0 0 0'));
+                       e.onClick = PlayerModelSelector_Next_Click;
+                       e.onClickEntity = pms;
+
+       //me.setFirstColumn(me, me.currentColumn + 2); // MODEL LEFT, COLOR RIGHT
+       me.gotoRC(me, me.currentRow, 0); me.setFirstColumn(me, me.currentColumn); // MODEL RIGHT, COLOR LEFT
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticHeaderLabel(_("Glowing color")));
+               for(i = 0; i < 15; ++i)
+               {
+                       if(mod(i, 5) == 0)
+                               me.TR(me);
+                       me.TDNoMargin(me, 1, 0.2, e = makeXonoticColorButton(1, 0, i), '0 1 0');
+               }
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticHeaderLabel(_("Detail color")));
+               for(i = 0; i < 15; ++i)
+               {
+                       if(mod(i, 5) == 0)
+                               me.TR(me);
+                       me.TDNoMargin(me, 1, 0.2, e = makeXonoticColorButton(2, 1, i), '0 1 0');
+               }
+
+       // ====================
+       //  STATISTICS SECTION
+       // ====================
+       me.gotoRC(me, 0.5, 3.1); me.setFirstColumn(me, me.currentColumn); // TOP RIGHT
+       //me.gotoRC(me, 9, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM RIGHT
+       //me.gotoRC(me, 9, 0); me.setFirstColumn(me, me.currentColumn); // BOTTOM LEFT
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Statistics")));
+
+       me.TR(me);
+               me.TDempty(me, 0.25);
+               me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, "cl_allow_uidtracking", _("Allow player statistics to track your client")));
+       me.TR(me);
+               me.TDempty(me, 0.25);
+               me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, "cl_allow_uid2name", _("Allow player statistics to use your nickname")));
+               setDependent(e, "cl_allow_uidtracking", 1, 1);
+       me.gotoRC(me, 4, 3.1); // TOP RIGHT
+       //me.gotoRC(me, 12.5, 3.1); // BOTTOM RIGHT 
+       //me.gotoRC(me, 12.5, 0); // BOTTOM LEFT
+               me.TDempty(me, 0.25);
+               me.TD(me, 9, 2.5, statslist = makeXonoticStatsList());
+               //setDependent(statslist, "cl_allow_uidtracking", 1, 1);
+
+       // =================
+       //  COUNTRY SECTION
+       // =================
+       me.gotoRC(me, 16, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM SECTION, TOP POS
+       //me.gotoRC(me, 13.5, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM SECTION, TOP POS
+       //me.gotoRC(me, 0.5, 3.1); me.setFirstColumn(me, me.currentColumn); // TOP SECTION, TOP POS
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Country")));
+
+       me.TR(me);
+               me.TDempty(me, 0.5);
+               me.TD(me, 4.5, 2, e = makeXonoticLanguageList()); // todo: cl_country: create proper country list
+
+
+       // ================
+       //  GENDER SECTION
+       // ================
+       me.gotoRC(me, 13.5, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM SECTION, TOP POS
+       //me.gotoRC(me, 19.5, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM SECTION, BOTTOM POS
+       //me.gotoRC(me, 6.5, 3.1); me.setFirstColumn(me, me.currentColumn); // TOP SECTION, BOTTOM POS
+       #if 0
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Gender:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_gender"));
+                       e.addValue(e, ZCTX(_("GENDER^Undisclosed")), "0");
+                       e.addValue(e, ZCTX(_("GENDER^Female")), "1");
+                       e.addValue(e, ZCTX(_("GENDER^Male")), "2");
+                       e.configureXonoticTextSliderValues(e);
+       #else
+                       me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Gender")));
+               me.TR(me);
+                       #define GENDERWIDTH_OFFSET 0.25
+                       #define GENDERWIDTH_LENGTH 2.5
+                       #define GENDERWIDTH_ITEM (GENDERWIDTH_LENGTH / 3)
+                       me.TDempty(me, GENDERWIDTH_OFFSET);
+                       me.TD(me, 1, GENDERWIDTH_ITEM, e = makeXonoticRadioButton(3, "cl_gender", "2", _("Female")));
+                       me.TD(me, 1, GENDERWIDTH_ITEM, e = makeXonoticRadioButton(3, "cl_gender", "1", _("Male")));
+                       me.TD(me, 1, GENDERWIDTH_ITEM, e = makeXonoticRadioButton(3, "cl_gender", "0", _("Undisclosed")));
+       #endif
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "color -1 -1;name \"$_cl_name\";sendcvar cl_weaponpriority;sendcvar cl_autoswitch;sendcvar cl_forceplayermodels;sendcvar cl_forceplayermodelsfromxonotic;playermodel $_cl_playermodel;playerskin $_cl_playerskin", COMMANDBUTTON_APPLY));
+}
+#endif
index 930fa7df9789c02dcabc26860d90f540e63b89b0..f7003b44d1c5ae94504cf0fc8fb7f75c8c8ca6a6 100644 (file)
@@ -4,7 +4,7 @@ CLASS(XonoticSettingsDialog) EXTENDS(XonoticDialog)
        ATTRIB(XonoticSettingsDialog, title, string, _("Settings"))
        ATTRIB(XonoticSettingsDialog, color, vector, SKINCOLOR_DIALOG_SETTINGS)
        ATTRIB(XonoticSettingsDialog, intendedWidth, float, 0.96)
-       ATTRIB(XonoticSettingsDialog, rows, float, 19)
+       ATTRIB(XonoticSettingsDialog, rows, float, 17)
        ATTRIB(XonoticSettingsDialog, columns, float, 6)
 ENDCLASS(XonoticSettingsDialog)
 #endif
@@ -13,16 +13,17 @@ ENDCLASS(XonoticSettingsDialog)
 void XonoticSettingsDialog_fill(entity me)
 {
        entity mc;
-       mc = makeXonoticTabController(me.rows - 2);
+       mc = makeXonoticTabController(me.rows - 2.5);
        me.TR(me);
-               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Input"),   makeXonoticInputSettingsTab()));
-               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Video"),   makeXonoticVideoSettingsTab()));
-               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Effects"), makeXonoticEffectsSettingsTab()));
-               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Audio"),   makeXonoticAudioSettingsTab()));
-               me.TD(me, 1, 1, mc.makeTabButton(mc, _("User"),    makeXonoticUserSettingsTab()));
-               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Misc"),    makeXonoticMiscSettingsTab()));
+               me.TD(me, 1, 2, mc.makeTabButton(mc, _("Video"),   makeXonoticVideoSettingsTab()));
+               me.TD(me, 1, 2, mc.makeTabButton(mc, _("Effects"), makeXonoticEffectsSettingsTab()));
+               me.TD(me, 1, 2, mc.makeTabButton(mc, _("Audio"),   makeXonoticAudioSettingsTab()));
        me.TR(me);
-       me.TR(me);
-               me.TD(me, me.rows - 2, me.columns, mc);
+               me.TD(me, 1, 1.5, mc.makeTabButton(mc, _("Game"),   makeXonoticGameSettingsTab()));
+               me.TD(me, 1, 1.5, mc.makeTabButton(mc, _("Input"),   makeXonoticInputSettingsTab()));
+               me.TD(me, 1, 1.5, mc.makeTabButton(mc, _("User"),    makeXonoticUserSettingsTab()));
+               me.TD(me, 1, 1.5, mc.makeTabButton(mc, _("Misc"),    makeXonoticMiscSettingsTab()));
+       me.gotoRC(me, 2.5, 0);
+               me.TD(me, me.rows - 2.5, me.columns, mc);
 }
 #endif
index f3c27915e781206f53fe4543614ab741497fc3bf..4db408c7382b3fe9096854507ef55c87d6061bfd 100644 (file)
@@ -3,7 +3,7 @@ CLASS(XonoticAudioSettingsTab) EXTENDS(XonoticTab)
        METHOD(XonoticAudioSettingsTab, fill, void(entity))
        ATTRIB(XonoticAudioSettingsTab, title, string, _("Audio"))
        ATTRIB(XonoticAudioSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticAudioSettingsTab, rows, float, 17)
+       ATTRIB(XonoticAudioSettingsTab, rows, float, 14.5)
        ATTRIB(XonoticAudioSettingsTab, columns, float, 6.2) // added extra .2 for center space
 ENDCLASS(XonoticAudioSettingsTab)
 entity makeXonoticAudioSettingsTab();
@@ -20,7 +20,7 @@ entity makeXonoticAudioSettingsTab()
 
 void XonoticAudioSettingsTab_fill(entity me)
 {
-       entity e, s, sl;
+       entity e, s;
 
        me.TR(me);
                s = makeXonoticDecibelsSlider(-40, 0, 0.4, "mastervolume");
@@ -123,13 +123,16 @@ void XonoticAudioSettingsTab_fill(entity me)
                        e.addValue(e, _("7.1"), "8");
                        e.configureXonoticTextSliderValues(e);
        me.TR(me);
-               me.TD(me, 1, 1.2, e = makeXonoticCheckBox(0, "snd_swapstereo", _("Swap Stereo")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "snd_swapstereo", _("Swap stereo output channels")));
                setDependent(e, "snd_channels", 1.5, 0.5);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "snd_spatialization_control", _("Headphone friendly mode")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "snd_spatialization_control", _("Headphone friendly mode")));
                setDependent(e, "snd_channels", 1.5, 0.5);
        me.TR(me);
        me.TR(me);
                me.TD(me, 1, 3, makeXonoticCheckBox(0, "cl_hitsound", _("Hit indication sound")));
+               e.sendCvars = TRUE;
        me.TR(me);
                me.TD(me, 1, 3, makeXonoticCheckBox(0, "con_chatsound", _("Chat message sound")));
        me.TR(me);
@@ -144,23 +147,20 @@ void XonoticAudioSettingsTab_fill(entity me)
                        e.addValue(e, ZCTX(_("WRN^Both")), "3");
                        e.configureXonoticTextSliderValues(e);
        me.TR(me);
-       me.TR(me);
-               sl = makeXonoticSlider(0.15, 1, 0.05, "cl_autotaunt");
-                       sl.valueDisplayMultiplier = 100;
-                       sl.valueDigits = 0;
-               me.TD(me, 1, 3, e = makeXonoticSliderCheckBox(0, 1, sl, _("Automatic taunts")));
-               if(sl.value != e.savedValue)
-                       e.savedValue = 0.65; // default
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, makeXonoticTextLabel(0, _("Frequency:")));
-               me.TD(me, 1, 2, sl);
+               me.TD(me, 1, 1, makeXonoticTextLabel(0, _("Automatic taunts:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_autotaunt"));
+                       e.addValue(e, _("Never"), "0");
+                       e.addValue(e, _("Sometimes"), "0.35");
+                       e.addValue(e, _("Often"), "0.65");
+                       e.addValue(e, _("Always"), "1");
+                       e.configureXonoticTextSliderValues(e);
+                       e.sendCvars = TRUE;
        me.TR(me);
        me.TR(me);
                if(cvar("developer"))
                        me.TD(me, 1, 3, makeXonoticCheckBox(0, "showsound", _("Debug info about sounds")));
 
        me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "snd_restart; snd_attenuation_method_$menu_snd_attenuation_method; sendcvar cl_hitsound; sendcvar cl_autotaunt; sendcvar cl_voice_directional; sendcvar cl_voice_directional_taunt_attenuation", COMMANDBUTTON_APPLY));
+               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "snd_restart; snd_attenuation_method_${menu_snd_attenuation_method}", COMMANDBUTTON_APPLY));
 }
 #endif
index c56d972d9da92eac957a6a3888709eef3a444456..f6b79eb8f340ec651ffb241b269c55cae4ae8968 100644 (file)
@@ -3,7 +3,7 @@ CLASS(XonoticEffectsSettingsTab) EXTENDS(XonoticTab)
        METHOD(XonoticEffectsSettingsTab, fill, void(entity))
        ATTRIB(XonoticEffectsSettingsTab, title, string, _("Effects"))
        ATTRIB(XonoticEffectsSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticEffectsSettingsTab, rows, float, 17)
+       ATTRIB(XonoticEffectsSettingsTab, rows, float, 14.5)
        ATTRIB(XonoticEffectsSettingsTab, columns, float, 6.2) // added extra .2 for center space
 ENDCLASS(XonoticEffectsSettingsTab)
 entity makeXonoticEffectsSettingsTab();
@@ -130,22 +130,30 @@ void XonoticEffectsSettingsTab_fill(entity me)
                        e.configureXonoticTextSliderValues(e);
                        setDependentAND(e, "vid_gl20", 1, 1, "r_water", 1, 1);
        me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_decals", _("Decals")));
-               me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_decals_models", _("Decals on models")));
-                       setDependent(e, "cl_decals", 1, 1);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_particles", _("Particles")));
+               me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_spawn_point_particles", _("Spawnpoint effects")));
+                       makeMulti(e, "cl_spawn_event_particles");
+                       setDependent(e, "cl_particles", 1, 1);
        me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Quality:")));
+                       setDependent(e, "cl_particles", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticParticlesSlider());
+                       setDependent(e, "cl_particles", 1, 1);
+               me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:")));
-                       setDependent(e, "cl_decals", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(200, 500, 20, "r_drawdecals_drawdistance"));
-                       setDependent(e, "cl_decals", 1, 1);
-       me.TR(me);
+                       setDependent(e, "cl_particles", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(200, 500, 20, "r_drawparticles_drawdistance"));
+                       setDependent(e, "cl_particles", 1, 1);
+               me.TR(me);
                me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Time:")));
-                       setDependent(e, "cl_decals", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(1, 20, 1, "cl_decals_fadetime"));
-                       setDependent(e, "cl_decals", 1, 1);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Damage effects:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_damageeffect"));
+                       e.addValue(e, _("Disabled"), "0");
+                       e.addValue(e, _("Skeletal"), "1");
+                       e.addValue(e, _("All"), "2");
+                       e.configureXonoticTextSliderValues(e);
 
        me.gotoRC(me, 1.25, 3.2); me.setFirstColumn(me, me.currentColumn);
                me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "r_coronas", "0", _("No dynamic lighting")));
@@ -172,6 +180,7 @@ void XonoticEffectsSettingsTab_fill(entity me)
                me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "r_coronas_occlusionquery", _("Fade corona according to visibility")));
                        setDependent(e, "r_coronas", 1, 1);
        me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_cubemaps_extra", _("Extra reflective effects")));
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_bloom", _("Bloom")));
                me.TD(me, 1, 2, e = makeXonoticCheckBoxEx(0.5, 0, "hud_postprocessing_maxbluralpha", _("Extra postprocessing effects")));
@@ -185,23 +194,16 @@ void XonoticEffectsSettingsTab_fill(entity me)
                me.TD(me, 1, 2, s);
        me.TR(me);
        me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_particles", _("Particles")));
-               me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_spawn_point_particles", _("Spawnpoint effects")));
-                       makeMulti(e, "cl_spawn_event_particles");
-                       setDependent(e, "cl_particles", 1, 1);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_decals", _("Decals")));
+               me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_decals_models", _("Decals on models")));
+                       setDependent(e, "cl_decals", 1, 1);
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Quality:")));
-                       setDependent(e, "cl_particles", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticParticlesSlider());
-                       setDependent(e, "cl_particles", 1, 1);
-               me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:")));
                        setDependent(e, "cl_decals", 1, 1);
                me.TD(me, 1, 2, e = makeXonoticSlider(200, 500, 20, "r_drawdecals_drawdistance"));
                        setDependent(e, "cl_decals", 1, 1);
-               me.TR(me);
+       me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Time:")));
                        setDependent(e, "cl_decals", 1, 1);
diff --git a/qcsrc/menu/xonotic/dialog_settings_game.c b/qcsrc/menu/xonotic/dialog_settings_game.c
new file mode 100644 (file)
index 0000000..b75c1ac
--- /dev/null
@@ -0,0 +1,54 @@
+#ifdef INTERFACE
+CLASS(XonoticGameSettingsTab) EXTENDS(XonoticTab)
+       METHOD(XonoticGameSettingsTab, fill, void(entity))
+       ATTRIB(XonoticGameSettingsTab, title, string, _("Game"))
+       ATTRIB(XonoticGameSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameSettingsTab, rows, float, 14.5)
+       ATTRIB(XonoticGameSettingsTab, columns, float, 6.5)
+ENDCLASS(XonoticGameSettingsTab)
+entity makeXonoticGameSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticGameSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameSettingsTab_fill(entity me)
+{
+       entity mc;
+       mc = makeXonoticTabController(me.rows - 1.5);
+       
+       me.TR(me);
+               me.TDempty(me, 0.25);
+               me.TD(me, 1, 1, mc.makeTabButton(mc, _("View"),           makeXonoticGameViewSettingsTab()));
+               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Crosshair"),      makeXonoticGameCrosshairSettingsTab()));
+               me.TD(me, 1, 1, mc.makeTabButton(mc, _("HUD"),            makeXonoticGameHUDSettingsTab()));
+               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Messages"),       makeXonoticGameMessageSettingsTab()));
+               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Weapons"),        makeXonoticGameWeaponsSettingsTab()));
+               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Models"),         makeXonoticGameModelSettingsTab()));
+
+       me.gotoRC(me, 1.5, 0);
+               me.TD(me, me.rows - 1.5, me.columns, mc);
+               
+       /*
+
+         makeXonoticGameViewSettingsTab()));
+         makeXonoticGameGeneralSettingsTab()));
+       makeXonoticGameCrosshairSettingsTab()));
+       
+              makeXonoticGameWeaponSettingsTab()));
+       l"),   makeXonoticGamePlayermodelSettingsTab()));
+              makeXonoticGameHUDSettingsTab()));
+       on"),  makeXonoticGameNotificationSettingsTab()));
+
+
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_gentle", _("Disable gore effects and harsh language"))); // also set sv_gentle
+       */
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_crosshair.c b/qcsrc/menu/xonotic/dialog_settings_game_crosshair.c
new file mode 100644 (file)
index 0000000..3e164c1
--- /dev/null
@@ -0,0 +1,163 @@
+#ifdef INTERFACE
+CLASS(XonoticGameCrosshairSettingsTab) EXTENDS(XonoticTab)
+       //METHOD(XonoticGameCrosshairSettingsTab, toString, string(entity))
+       METHOD(XonoticGameCrosshairSettingsTab, fill, void(entity))
+       METHOD(XonoticGameCrosshairSettingsTab, showNotify, void(entity))
+       ATTRIB(XonoticGameCrosshairSettingsTab, title, string, _("Crosshair"))
+       ATTRIB(XonoticGameCrosshairSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameCrosshairSettingsTab, rows, float, 13)
+       ATTRIB(XonoticGameCrosshairSettingsTab, columns, float, 6.2)
+ENDCLASS(XonoticGameCrosshairSettingsTab)
+entity makeXonoticGameCrosshairSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticGameCrosshairSettingsTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+entity makeXonoticGameCrosshairSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameCrosshairSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameCrosshairSettingsTab_fill(entity me)
+{
+       entity e;
+       float i;
+
+       // crosshair_enabled: 0 = no crosshair options, 1 = no crosshair selection, but everything else enabled, 2 = all crosshair options enabled
+       // FIXME: In the future, perhaps make one global crosshair_type cvar which has 0 for disabled, 1 for custom, 2 for per weapon, etc?
+       me.TR(me); //me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_enabled", "0", _("No crosshair")));
+       //me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_per_weapon", string_null, _("Per weapon")));
+               makeMulti(e, "crosshair_enabled");
+       //me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_enabled", "2", _("Custom")));
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               for(i = 1; i <= 14; ++i) {
+                       me.TDNoMargin(me, 1, 2 / 14, e = makeXonoticCrosshairButton(4, i), '1 1 0');
+                               setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
+               }
+               // show a larger preview of the selected crosshair
+               me.TDempty(me, 0.1);
+               me.TDNoMargin(me, 3, 0.8, e = makeXonoticCrosshairButton(7, -1), '1 1 0'); // crosshair -1 makes this a preview
+                       setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               for(i = 15; i <= 28; ++i) {
+                       me.TDNoMargin(me, 1, 2 / 14, e = makeXonoticCrosshairButton(4, i), '1 1 0');
+                               setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
+               }
+       me.TR(me);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair size:")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 1.9, e = makeXonoticSlider(0.1, 1.0, 0.01, "crosshair_size"));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair alpha:")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 1.9, e = makeXonoticSlider(0, 1, 0.1, "crosshair_alpha"));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair color:")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(5, "crosshair_color_special", "1", _("Per weapon")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(5, "crosshair_color_special", "2", _("By health")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticRadioButton(5, "crosshair_color_special", "0", _("Custom")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+               me.TD(me, 2, 2, e = makeXonoticColorpickerString("crosshair_color", "crosshair_color"));
+                       setDependentAND(e, "crosshair_color_special", 0, 0, "crosshair_enabled", 1, 2);
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 2.9, e = makeXonoticCheckBox(0, "crosshair_ring", _("Use rings to indicate weapon status")));
+                       makeMulti(e, "crosshair_ring_reload");
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       //me.TR(me);
+       //      me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Ring size:")));
+       //              setDependentAND(e, "crosshair_ring", 1, 1, "crosshair_enabled", 1, 2);
+       //      me.TD(me, 1, 2, e = makeXonoticSlider(2, 4, 0.1, "crosshair_ring_size"));
+       //              setDependentAND(e, "crosshair_ring", 1, 1, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.3);
+               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Ring alpha:")));
+                       setDependentAND(e, "crosshair_ring", 1, 1, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 1.8, e = makeXonoticSlider(0.1, 1, 0.1, "crosshair_ring_alpha"));
+                       setDependentAND(e, "crosshair_ring", 1, 1, "crosshair_enabled", 1, 2);
+       
+       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "crosshair_dot", _("Enable center crosshair dot")));
+               setDependent(e, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Dot size:")));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.2, 2, 0.1, "crosshair_dot_size"));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Dot alpha:")));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 1, 0.1, "crosshair_dot_alpha"));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Dot color:")));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 2, e = makeXonoticRadioButton(1, "crosshair_dot_color_custom", "0", _("Use normal crosshair color")));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticRadioButton(1, "crosshair_dot_color_custom", "1", _("Custom")));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+               me.TD(me, 2, 2, e = makeXonoticColorpickerString("crosshair_dot_color", "crosshair_dot_color"));
+                       setDependentAND3(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2, "crosshair_dot_color_custom", 1, 1);
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "crosshair_effect_scalefade", _("Smooth effects of crosshairs")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "crosshair_hittest_blur", _("Blur crosshair if the shot is obstructed")));
+                       setDependentAND(e, "crosshair_hittest", 1, 100, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(1.25, 0, "crosshair_hittest_scale", _("Enlarge crosshair if targeting an enemy")));
+                       setDependentAND(e, "crosshair_hittest", 1, 100, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(0.5, 0, "crosshair_hitindication", _("Animate crosshair when hitting an enemy")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(0.25, 0, "crosshair_pickup", _("Animate crosshair when picking up an item")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       /*me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Hit testing:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("crosshair_hittest"));
+                       e.addValue(e, ZCTX(_("HTTST^Disabled")), "0");
+                       e.addValue(e, ZCTX(_("HTTST^TrueAim")), "1");
+                       e.addValue(e, ZCTX(_("HTTST^Enemies")), "1.25");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "crosshair_enabled", 1, 2);*/
+                       
+       /*me.TR(me);
+                       
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;*/
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_hud.c b/qcsrc/menu/xonotic/dialog_settings_game_hud.c
new file mode 100644 (file)
index 0000000..fc7e3a1
--- /dev/null
@@ -0,0 +1,173 @@
+#ifdef INTERFACE
+CLASS(XonoticGameHUDSettingsTab) EXTENDS(XonoticTab)
+       //METHOD(XonoticGameHUDSettingsTab, toString, string(entity))
+       METHOD(XonoticGameHUDSettingsTab, fill, void(entity))
+       METHOD(XonoticGameHUDSettingsTab, showNotify, void(entity))
+       ATTRIB(XonoticGameHUDSettingsTab, title, string, _("HUD"))
+       ATTRIB(XonoticGameHUDSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameHUDSettingsTab, rows, float, 13)
+       ATTRIB(XonoticGameHUDSettingsTab, columns, float, 6.2)
+ENDCLASS(XonoticGameHUDSettingsTab)
+entity makeXonoticGameHUDSettingsTab();
+void HUDSetup_Start(entity me, entity btn);
+#endif
+
+#ifdef IMPLEMENTATION
+void HUDSetup_Check_Gamestatus(entity me, entity btn)
+{
+       if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER))) // we're not in a match, ask the player if they want to start one anyway
+       {
+               DialogOpenButton_Click(me, main.hudconfirmDialog);
+       }
+       else // already in a match, lets just cut to the point and open up the hud editor directly
+       {
+               HUDSetup_Start(me, btn);
+       }
+}
+void XonoticGameHUDSettingsTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+entity makeXonoticGameHUDSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameHUDSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameHUDSettingsTab_fill(entity me)
+{
+       entity e;
+
+       // todo:
+       // threshold: hud_damage_pain_threshold_lower_health
+       // scoreboard_alpha*
+
+       //me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Scoreboard")));
+       //me.TR(me);
+       //      me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Alpha:")));
+       //      me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "scoreboard_alpha_bg"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Fading speed:")));
+               me.TD(me, 1, 2, e = makeXonoticScoreboardFadeTimeSlider());
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Side padding:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.05, 0.3, 0.01, "scoreboard_offset_left"));
+                       makeMulti(e, "scoreboard_offset_right");
+
+       me.TR(me);
+       //me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "scoreboard_respawntime_decimals", _("Show decimals in respawn countdown")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "scoreboard_accuracy", _("Show accuracy underneath scoreboard")));
+
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Waypoints")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_hidewaypoints", _("Display waypoint markers for objectives on the map")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Alpha:")));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 1, 0.05, "g_waypointsprite_alpha"));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Fontsize:")));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+               me.TD(me, 1, 2, e = makeXonoticSlider(5, 16, 1, "g_waypointsprite_fontsize"));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Edge offset:")));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 0.3, 0.01, "g_waypointsprite_edgeoffset_bottom"));
+                       makeMulti(e, "g_waypointsprite_edgeoffset_top g_waypointsprite_edgeoffset_left g_waypointsprite_edgeoffset_right");
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+
+       me.TR(me);
+       //me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.25, 1, "g_waypointsprite_crosshairfadealpha", _("Fade when near the crosshair")));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+
+       #if 0
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Damage")));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Overlay:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "hud_damage"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Factor:")));
+                       setDependent(e, "hud_damage", 0.001, 100);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.025, 0.1, 0.025, "hud_damage_factor"));
+                       setDependent(e, "hud_damage", 0.001, 100);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Fade rate:")));
+                       setDependent(e, "hud_damage", 0.001, 100);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.25, 1, 0.05, "hud_damage_fade_rate"));
+                       setDependent(e, "hud_damage", 0.001, 100);
+       me.TR(me);
+       #endif
+
+       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Player Names")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "hud_shownames", _("Show names above players")));
+
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Alpha:")));
+                       setDependent(e, "hud_shownames", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 1, 0.05, "hud_shownames_alpha"));
+                       setDependent(e, "hud_shownames", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Fontsize:")));
+                       setDependent(e, "hud_shownames", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(5, 16, 1, "hud_shownames_fontsize"));
+                       setDependent(e, "hud_shownames", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Max distance:")));
+                       setDependent(e, "hud_shownames", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(2000, 10000, 500, "hud_shownames_maxdistance"));
+                       setDependent(e, "hud_shownames", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Decolorize:")));
+                       setDependent(e, "hud_shownames", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("hud_shownames_decolorize"));
+                       e.addValue(e, ZCTX(_("Never")), "0");
+                       e.addValue(e, ZCTX(_("Teamplay")), "1");
+                       e.addValue(e, ZCTX(_("Always")), "2");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "hud_shownames", 1, 1);
+
+       me.TR(me);
+       //me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(25, 0, "hud_shownames_crosshairdistance", _("Only when near crosshair")));
+                       setDependent(e, "hud_shownames", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "hud_shownames_status", _("Display health and armor")));
+                       setDependent(e, "hud_shownames", 1, 1);
+
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Damage overlay:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "hud_damage"));
+       me.TR(me);
+       me.TR(me);
+               me.TDempty(me, 0.5);
+               me.TD(me, 1, 2, e = makeXonoticButton(_("Enter HUD editor"), '0 0 0'));
+                       e.onClick = HUDSetup_Check_Gamestatus;
+                       e.onClickEntity = me;
+               // TODO: show hud config name with text here
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.c b/qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.c
new file mode 100644 (file)
index 0000000..7749a14
--- /dev/null
@@ -0,0 +1,40 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDConfirmDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticHUDConfirmDialog, fill, void(entity))
+       ATTRIB(XonoticHUDConfirmDialog, title, string, _("Enter HUD editor"))
+       ATTRIB(XonoticHUDConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
+       ATTRIB(XonoticHUDConfirmDialog, intendedWidth, float, 0.5)
+       ATTRIB(XonoticHUDConfirmDialog, rows, float, 4)
+       ATTRIB(XonoticHUDConfirmDialog, columns, float, 2)
+ENDCLASS(XonoticHUDConfirmDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void HUDSetup_Start(entity me, entity btn)
+{
+       if (!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
+               localcmd("map hudsetup/hudsetup", "\n");
+       else
+               localcmd("togglemenu 0\n");
+
+       localcmd("_hud_configure 1", "\n");
+}
+
+void XonoticHUDConfirmDialog_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("In order for the HUD editor to show, you must first be in game.")));
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you wish to start a local game to set up the HUD?")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("HDCNFRM^Yes")), '1 0 0'));
+                       e.onClick = HUDSetup_Start;
+                       e.onClickEntity = me;
+               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("HDCNFRM^No")), '0 1 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_messages.c b/qcsrc/menu/xonotic/dialog_settings_game_messages.c
new file mode 100644 (file)
index 0000000..6f605cc
--- /dev/null
@@ -0,0 +1,119 @@
+#ifdef INTERFACE
+CLASS(XonoticGameMessageSettingsTab) EXTENDS(XonoticTab)
+       //METHOD(XonoticGameWeaponsSettingsTab, toString, string(entity))
+       METHOD(XonoticGameMessageSettingsTab, fill, void(entity))
+       METHOD(XonoticGameMessageSettingsTab, showNotify, void(entity))
+       ATTRIB(XonoticGameMessageSettingsTab, title, string, _("Messages"))
+       ATTRIB(XonoticGameMessageSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameMessageSettingsTab, rows, float, 13)
+       ATTRIB(XonoticGameMessageSettingsTab, columns, float, 6)
+       ATTRIB(XonoticGameMessageSettingsTab, weaponsList, entity, NULL)
+ENDCLASS(XonoticGameMessageSettingsTab)
+entity makeXonoticGameMessageSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticGameMessageSettingsTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+entity makeXonoticGameMessageSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameMessageSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameMessageSettingsTab_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Frag Information")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_show_sprees", _("Display information about killing sprees")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "notification_show_sprees_info_specialonly", _("Only display sprees if they are achievements")));
+                       makeMulti(e, "notification_show_sprees_center_specialonly");
+                       setDependent(e, "notification_show_sprees", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "notification_show_sprees_center", _("Show spree information in centerprints")));
+                       setDependent(e, "notification_show_sprees", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(3, 0, "notification_show_sprees_info", _("Show spree information in death messages")));
+                       setDependent(e, "notification_show_sprees", 1, 1);
+       #if 0
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Sprees in info messages:")));
+                       setDependent(e, "notification_show_sprees", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("notification_show_sprees_info"));
+                       e.addValue(e, ZCTX(_("Disabled")), "0");
+                       e.addValue(e, ZCTX(_("Target")), "1");
+                       e.addValue(e, ZCTX(_("Attacker")), "2");
+                       e.addValue(e, ZCTX(_("Both")), "3");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "notification_show_sprees", 1, 1);
+       #endif
+       me.TR(me);
+               me.TDempty(me, 0.4);
+               me.TD(me, 1, 2.6, e = makeXonoticCheckBox(0, "notification_show_sprees_info_newline", _("Print on a seperate line")));
+                       setDependent(e, "notification_show_sprees", 1, 1);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_CHOICE_FRAG", _("Add extra frag information to centerprint when available")));
+                       makeMulti(e, "notification_CHOICE_FRAGGED notification_CHOICE_TYPEFRAG notification_CHOICE_TYPEFRAGGED");
+                       e.sendCvars = TRUE;
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_show_location", _("Add frag location to death messages when available")));
+
+       me.gotoRC(me, 9, 0); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Gamemode Settings")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_CHOICE_CTF_CAPTURE_TIME_RED", _("Display capture times in Capture The Flag")));
+                       makeMulti(e, "notification_CHOICE_CTF_CAPTURE_TIME_BLUE notification_CHOICE_CTF_CAPTURE_BROKEN_RED notification_CHOICE_CTF_CAPTURE_BROKEN_BLUE notification_CHOICE_CTF_CAPTURE_UNBROKEN_RED notification_CHOICE_CTF_CAPTURE_UNBROKEN_BLUE ");
+                       e.sendCvars = TRUE;
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_CHOICE_CTF_PICKUP_ENEMY", _("Display name of flag stealer in Capture The Flag")));
+                       makeMulti(e, "notification_CHOICE_CTF_PICKUP_TEAM");
+                       e.sendCvars = TRUE;
+
+       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Other")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(4, 1, "con_notify", _("Display console messages in the top left corner")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_allow_chatboxprint", _("Display all info messages in the chatbox")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_INFO_QUIT_DISCONNECT", _("Display player statuses in the chatbox")));
+                       makeMulti(e, "notification_INFO_QUIT_KICK_IDLING notification_INFO_JOIN_CONNECT_TEAM_BLUE notification_INFO_JOIN_CONNECT_TEAM_PINK notification_INFO_JOIN_CONNECT_TEAM_RED notification_INFO_JOIN_CONNECT_TEAM_YELLOW");
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_CENTER_POWERUP_INVISIBILITY", _("Powerup notifications")));
+                       makeMulti(e, "notification_CENTER_POWERUP_SHIELD notification_CENTER_POWERUP_SPEED notification_CENTER_POWERUP_STRENGTH notification_CENTER_POWERDOWN_INVISIBILITY notification_CENTER_POWERDOWN_SHIELD notification_CENTER_POWERDOWN_SPEED notification_CENTER_POWERDOWN_STRENGTH notification_CENTER_SUPERWEAPON_BROKEN notification_CENTER_SUPERWEAPON_LOST notification_CENTER_SUPERWEAPON_PICKUP notification_INFO_POWERUP_INVISIBILITY notification_INFO_POWERUP_SHIELD notification_INFO_POWERUP_SPEED notification_INFO_POWERUP_STRENGTH");
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_CENTER_ITEM_WEAPON_DONTHAVE", _("Weapon centerprint notifications")));
+                       makeMulti(e, "notification_CENTER_ITEM_WEAPON_DROP notification_CENTER_ITEM_WEAPON_GOT notification_CENTER_ITEM_WEAPON_NOAMMO notification_CENTER_ITEM_WEAPON_PRIMORSEC notification_CENTER_ITEM_WEAPON_UNAVAILABLE"); 
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_INFO_ITEM_WEAPON_DONTHAVE", _("Weapon info message notifications")));
+                       makeMulti(e, "notification_INFO_ITEM_WEAPON_DROP notification_INFO_ITEM_WEAPON_GOT notification_INFO_ITEM_WEAPON_NOAMMO notification_INFO_ITEM_WEAPON_PRIMORSEC notification_INFO_ITEM_WEAPON_UNAVAILABLE"); 
+
+       me.gotoRC(me, 9, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Announcers")));
+       #if 0
+       // there's just not enough room for this, and it's not important enough to justify...
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 0, "notification_ANNCE_NUM_RESPAWN_1", _("Respawn countdown sounds")));
+                       makeMulti(e, "notification_ANNCE_NUM_RESPAWN_2 notification_ANNCE_NUM_RESPAWN_3 notification_ANNCE_NUM_RESPAWN_4 notification_ANNCE_NUM_RESPAWN_5 notification_ANNCE_NUM_RESPAWN_6 notification_ANNCE_NUM_RESPAWN_7 notification_ANNCE_NUM_RESPAWN_8 notification_ANNCE_NUM_RESPAWN_9 notification_ANNCE_NUM_RESPAWN_10");
+       #endif
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(1, 0, "notification_ANNCE_KILLSTREAK_03", _("Killstreak sounds")));
+                       makeMulti(e, "notification_ANNCE_KILLSTREAK_05 notification_ANNCE_KILLSTREAK_10 notification_ANNCE_KILLSTREAK_15 notification_ANNCE_KILLSTREAK_20 notification_ANNCE_KILLSTREAK_25 notification_ANNCE_KILLSTREAK_30");
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(1, 0, "notification_ANNCE_ACHIEVEMENT_AIRSHOT", _("Achievement sounds")));
+                       makeMulti(e, "notification_ANNCE_ACHIEVEMENT_AMAZING notification_ANNCE_ACHIEVEMENT_AWESOME notification_ANNCE_ACHIEVEMENT_BOTLIKE notification_ANNCE_ACHIEVEMENT_ELECTROBITCH notification_ANNCE_ACHIEVEMENT_IMPRESSIVE notification_ANNCE_ACHIEVEMENT_YODA");
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_model.c b/qcsrc/menu/xonotic/dialog_settings_game_model.c
new file mode 100644 (file)
index 0000000..c2aedc1
--- /dev/null
@@ -0,0 +1,74 @@
+#ifdef INTERFACE
+CLASS(XonoticGameModelSettingsTab) EXTENDS(XonoticTab)
+       //METHOD(XonoticGameModelSettingsTab, toString, string(entity))
+       METHOD(XonoticGameModelSettingsTab, fill, void(entity))
+       METHOD(XonoticGameModelSettingsTab, showNotify, void(entity))
+       ATTRIB(XonoticGameModelSettingsTab, title, string, _("Model"))
+       ATTRIB(XonoticGameModelSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameModelSettingsTab, rows, float, 13)
+       ATTRIB(XonoticGameModelSettingsTab, columns, float, 5)
+ENDCLASS(XonoticGameModelSettingsTab)
+entity makeXonoticGameModelSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticGameModelSettingsTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+entity makeXonoticGameModelSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameModelSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameModelSettingsTab_fill(entity me)
+{
+       entity e;
+       //float i;
+       
+       // Note that this is pretty terrible currently due to the lack of options for this tab...
+       // There is really not many other decent places for these options, additionally
+       // later I would like quite a few more options in this tab.
+
+       me.gotoRC(me, 0, 1); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Items")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_simple_items", _("Use simple 2D images instead of item models")));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Unavailable alpha:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.1, "cl_ghost_items"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Unavailable color:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_ghost_items_color"));
+                       e.addValue(e, ZCTX(_("GHOITEMS^Black")), "-1 -1 -1");
+                       e.addValue(e, ZCTX(_("GHOITEMS^Dark")), "0.1 0.1 0.1");
+                       e.addValue(e, ZCTX(_("GHOITEMS^Tinted")), "0.6 0.6 0.6");
+                       e.addValue(e, ZCTX(_("GHOITEMS^Normal")), "1 1 1");
+                       e.addValue(e, ZCTX(_("GHOITEMS^Blue")), "-1 -1 3");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "cl_ghost_items", 0.001, 1);
+
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Players")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_forceplayermodels", _("Force player models to mine")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_forceplayercolors", _("Force player colors to mine")));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Body fading:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 2, 0.2, "cl_deathglow"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Gibs:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_nogibs"));
+                       e.addValue(e, ZCTX(_("GIBS^None")), "1");
+                       e.addValue(e, ZCTX(_("GIBS^Few")), "0.75");
+                       e.addValue(e, ZCTX(_("GIBS^Many")), "0.5");
+                       e.addValue(e, ZCTX(_("GIBS^Lots")), "0");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "cl_gentle", 0, 0);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_view.c b/qcsrc/menu/xonotic/dialog_settings_game_view.c
new file mode 100644 (file)
index 0000000..3fd4512
--- /dev/null
@@ -0,0 +1,124 @@
+#ifdef INTERFACE
+CLASS(XonoticGameViewSettingsTab) EXTENDS(XonoticTab)
+       //METHOD(XonoticGameCrosshairSettingsTab, toString, string(entity))
+       METHOD(XonoticGameViewSettingsTab, fill, void(entity))
+       METHOD(XonoticGameViewSettingsTab, showNotify, void(entity))
+       ATTRIB(XonoticGameViewSettingsTab, title, string, _("View"))
+       ATTRIB(XonoticGameViewSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameViewSettingsTab, rows, float, 13)
+       ATTRIB(XonoticGameViewSettingsTab, columns, float, 6.2)
+ENDCLASS(XonoticGameViewSettingsTab)
+entity makeXonoticGameViewSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticGameViewSettingsTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+entity makeXonoticGameViewSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameViewSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameViewSettingsTab_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "chase_active", "0", _("1st person perspective")));
+               makeMulti(e, "crosshair_hittest_showimpact");
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_eventchase_death", _("Slide to third person upon death")));
+               setDependent(e, "chase_active", -1, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.05, 0, "cl_bobfall", _("Smooth the view when landing from a jump")));
+               setDependent(e, "chase_active", -1, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.05, 0, "cl_smoothviewheight", _("Smooth the view while crouching")));
+               setDependent(e, "chase_active", -1, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(1, 0, "v_idlescale", _("View waving while idle")));
+               setDependent(e, "chase_active", -1, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.01, 0, "cl_bob", _("View bobbing while walking around")));
+               makeMulti(e, "cl_bob2");
+               setDependent(e, "chase_active", -1, 0);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "chase_active", "1", _("3rd person perspective")));
+               makeMulti(e, "crosshair_hittest_showimpact");
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Back distance")));
+               setDependent(e, "chase_active", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(10, 100, 1, "chase_back"));
+               setDependent(e, "chase_active", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Up distance")));
+               setDependent(e, "chase_active", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(10, 50, 1, "chase_up"));
+               setDependent(e, "chase_active", 1, 1);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_clippedspectating", _("Allow passing through walls while spectating")));
+       
+       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Field of view:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(60, 130, 5, "fov"));
+       me.TR(me);
+       me.TR(me);
+               //me.TDempty(me, 0.2);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Zoom factor:"))));
+               me.TD(me, 1, 2, e = makeXonoticSlider(2, 16, 0.5, "cl_zoomfactor"));
+       me.TR(me);
+               //me.TDempty(me, 0.2);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Zoom speed:"))));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_zoomspeed"));
+                       e.addValue(e, "1", "1"); // Samual: for() loop doesn't work here, even though it would make sense.
+                       e.addValue(e, "2", "2");
+                       e.addValue(e, "3", "3");
+                       e.addValue(e, "4", "4");
+                       e.addValue(e, "5", "5");
+                       e.addValue(e, "6", "6");
+                       e.addValue(e, "7", "7");
+                       e.addValue(e, "8", "8");
+                       e.addValue(e, ZCTX(_("ZOOM^Instant")), "-1");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               //me.TDempty(me, 0.2);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Zoom sensitivity:"))));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.1, "cl_zoomsensitivity"));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_velocityzoom_enabled", _("Velocity zoom")));
+               me.TD(me, 1, 2, e = makeXonoticCheckBoxEx(3, 1, "cl_velocityzoom_type", _("Forward movement only")));
+                       setDependent(e, "cl_velocityzoom_enabled", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, ZCTX(_("VZOOM^Factor"))));
+                       setDependentAND(e, "cl_velocityzoom_enabled", 1, 1, "cl_velocityzoom_type", 1, 3);
+               me.TD(me, 1, 2, e = makeXonoticSlider(-1, 1, 0.1, "cl_velocityzoom_factor"));
+                       setDependentAND(e, "cl_velocityzoom_enabled", 1, 1, "cl_velocityzoom_type", 1, 3);
+       me.TR(me);
+       me.TR(me);
+               //me.TDempty(me, 0.2);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_reticle", _("Display reticle 2D overlay while zooming")));
+       me.TR(me);
+               //me.TDempty(me, 0.2);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_unpress_zoom_on_death", _("Release zoom when you die or respawn")));
+                       makeMulti(e, "cl_unpress_zoom_on_spawn");
+       me.TR(me);
+               //me.TDempty(me, 0.2);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_unpress_zoom_on_weapon_switch", _("Release zoom when you switch weapons")));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_weapons.c b/qcsrc/menu/xonotic/dialog_settings_game_weapons.c
new file mode 100644 (file)
index 0000000..bc7cc7d
--- /dev/null
@@ -0,0 +1,77 @@
+#ifdef INTERFACE
+CLASS(XonoticGameWeaponsSettingsTab) EXTENDS(XonoticTab)
+       //METHOD(XonoticGameWeaponsSettingsTab, toString, string(entity))
+       METHOD(XonoticGameWeaponsSettingsTab, fill, void(entity))
+       METHOD(XonoticGameWeaponsSettingsTab, showNotify, void(entity))
+       ATTRIB(XonoticGameWeaponsSettingsTab, title, string, _("Weapons"))
+       ATTRIB(XonoticGameWeaponsSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameWeaponsSettingsTab, rows, float, 13)
+       ATTRIB(XonoticGameWeaponsSettingsTab, columns, float, 6)
+       ATTRIB(XonoticGameWeaponsSettingsTab, weaponsList, entity, NULL)
+ENDCLASS(XonoticGameWeaponsSettingsTab)
+entity makeXonoticGameWeaponsSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticGameWeaponsSettingsTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+entity makeXonoticGameWeaponsSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameWeaponsSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameWeaponsSettingsTab_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TDempty(me, 0.25);
+               me.TD(me, 1, 2.5, e = makeXonoticHeaderLabel(_("Weapon Priority List")));
+       me.TR(me);
+               me.TDempty(me, 0.25);
+               me.TD(me, 10, 2.5, e = me.weaponsList = makeXonoticWeaponsList());
+       me.gotoRC(me, 11, 0.25);
+               me.TD(me, 1, 1.25, e = makeXonoticButton(_("Up"), '0 0 0'));
+                       e.onClick = WeaponsList_MoveUp_Click;
+                       e.onClickEntity = me.weaponsList;
+               me.TD(me, 1, 1.25, e = makeXonoticButton(_("Down"), '0 0 0'));
+                       e.onClick = WeaponsList_MoveDown_Click;
+                       e.onClickEntity = me.weaponsList;
+
+       me.gotoRC(me, 0, 3); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_weaponpriority_useforcycling", _("Use priority list for weapon cycling")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_weaponimpulsemode", _("Cycle through only usable weapon selections")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_autoswitch", _("Auto switch weapons on pickup")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_unpress_attack_on_weapon_switch", _("Release attack buttons when you switch weapons")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "r_drawviewmodel", _("Draw 1st person weapon model")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "cl_gunalign", "4", _("Left align")));
+                       setDependent(e, "r_drawviewmodel", 1, 1);
+               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "cl_gunalign", "1", _("Center")));
+                       setDependent(e, "r_drawviewmodel", 1, 1);
+               me.TD(me, 1, 1.0, e = makeXonoticRadioButton(1, "cl_gunalign", "3", _("Right align")));
+                       setDependent(e, "r_drawviewmodel", 1, 1);
+       me.TR(me);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_followmodel", _("Gun model swaying")));
+               makeMulti(e, "cl_leanmodel");
+               setDependent(e, "r_drawviewmodel", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_bobmodel", _("Gun model bobbing")));
+               setDependent(e, "r_drawviewmodel", 1, 1);
+}
+#endif
index d8554be4f7af38285bcb259d87ec22a894cd2284..4287f1f82e37d52bb8be673378a3ac372e99f469 100644 (file)
@@ -3,7 +3,7 @@ CLASS(XonoticInputSettingsTab) EXTENDS(XonoticTab)
        METHOD(XonoticInputSettingsTab, fill, void(entity))
        ATTRIB(XonoticInputSettingsTab, title, string, _("Input"))
        ATTRIB(XonoticInputSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticInputSettingsTab, rows, float, 17)
+       ATTRIB(XonoticInputSettingsTab, rows, float, 14.5)
        ATTRIB(XonoticInputSettingsTab, columns, float, 6.2) // added extra .2 for center space
 ENDCLASS(XonoticInputSettingsTab)
 entity makeXonoticInputSettingsTab();
@@ -17,15 +17,22 @@ entity makeXonoticInputSettingsTab()
        me.configureDialog(me);
        return me;
 }
+
+void CheckBox_Click_Redisplay(entity me, entity checkbox)
+{
+       CheckBox_Click(me, checkbox);
+       cmd("\ndefer 0.2 \"togglemenu 1\"\n");
+       //m_display();
+}
 void XonoticInputSettingsTab_fill(entity me)
 {
        entity e;
-       entity kb;
+       entity kb = makeXonoticKeyBinder();
 
        me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Key bindings:")));
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Key Bindings")));
        me.TR(me);
-               me.TD(me, me.rows - 4, 3, kb = makeXonoticKeyBinder());
+               me.TD(me, me.rows - 4, 3, kb);
        me.gotoRC(me, me.rows - 3, 0);
                me.TD(me, 1, 1, e = makeXonoticButton(_("Change key..."), '0 0 0'));
                        e.onClick = KeyBinder_Bind_Change;
@@ -41,52 +48,62 @@ void XonoticInputSettingsTab_fill(entity me)
                        e.onClick = KeyBinder_Bind_Clear;
                        e.onClickEntity = kb;
                        kb.clearButton = e;
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticButton(_("Reset all"), '0 0 0'));
+                       e.onClick = KeyBinder_Bind_Reset_All;
+                       e.onClickEntity = kb;
 
        me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "con_closeontoggleconsole", _("Pressing \"enter console\" key also closes it")));
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Mouse")));
        me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_movement_track_canjump", _("Automatically repeat jumping if holding jump")));
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Sensitivity:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(1, 32, 0.2, "sensitivity"));
        me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "m_filter", _("Smooth aiming")));
        me.TR(me);
-               if(cvar_type("joy_enable") & CVAR_TYPEFLAG_ENGINE)
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "joy_enable", _("Use joystick input")));
-               else if(cvar_type("joystick") & CVAR_TYPEFLAG_ENGINE)
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "joystick", _("Use joystick input")));
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(1.022, "m_pitch", _("Invert aiming")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "menu_mouse_absolute", _("Use system mouse positioning")));
+                       makeMulti(e, "hud_cursormode");
+                       e.onClick = CheckBox_Click_Redisplay;
+                       e.onClickEntity = e;
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "m_accelerate", _("Enable built in mouse acceleration")));
+       me.TR(me);
+               if(cvar_type("vid_dgamouse") & CVAR_TYPEFLAG_ENGINE)
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "vid_dgamouse", _("Disable system mouse acceleration")));
+               else if(cvar_type("apple_mouse_noaccel") & CVAR_TYPEFLAG_ENGINE)
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "apple_mouse_noaccel", _("Disable system mouse acceleration")));
                else
                {
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, string_null, _("Use joystick input")));
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, string_null, _("Disable system mouse acceleration")));
                        e.disabled = 1; // the option is never available in this case, just there for show
                }
+
        me.TR(me);
        me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Mouse:")));
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Other")));
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Sensitivity:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(1, 32, 0.2, "sensitivity"));
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "con_closeontoggleconsole", _("Pressing \"enter console\" key also closes it")));
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "m_filter", _("Smooth aiming")));
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_movement_track_canjump", _("Automatically repeat jumping if holding jump")));
+                       e.sendCvars = TRUE;
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(1.022, "m_pitch", _("Invert aiming")));
        me.TR(me);
-               me.TDempty(me, 0.2);
-               if(cvar_type("vid_dgamouse") & CVAR_TYPEFLAG_ENGINE)
-                       me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "vid_dgamouse", _("Disable system mouse acceleration")));
-               else if(cvar_type("apple_mouse_noaccel") & CVAR_TYPEFLAG_ENGINE)
-                       me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "apple_mouse_noaccel", _("Disable system mouse acceleration")));
+               if(cvar_type("joy_enable") & CVAR_TYPEFLAG_ENGINE)
+               {
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "joy_enable", _("Use joystick input")));
+                       setDependent(e, "joy_detected", 1, 10000000);
+               }
+               else if(cvar_type("joystick") & CVAR_TYPEFLAG_ENGINE)
+               {
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "joystick", _("Use joystick input")));
+                       setDependent(e, "joy_detected", 1, 10000000);
+               }
                else
                {
-                       me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, string_null, _("Disable system mouse acceleration")));
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, string_null, _("Use joystick input")));
                        e.disabled = 1; // the option is never available in this case, just there for show
                }
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "m_accelerate", _("Enable built in mouse acceleration")));
-
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "sendcvar cl_movement_track_canjump", COMMANDBUTTON_APPLY));
 }
 #endif
index c14a47c9c1633c0714b3ae8054a6f5a06c56b8bd..1deda87df078a26c24569b2bf1dd6cb54155b1b6 100644 (file)
@@ -3,7 +3,7 @@ CLASS(XonoticMiscSettingsTab) EXTENDS(XonoticTab)
        METHOD(XonoticMiscSettingsTab, fill, void(entity))
        ATTRIB(XonoticMiscSettingsTab, title, string, _("Misc"))
        ATTRIB(XonoticMiscSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticMiscSettingsTab, rows, float, 17)
+       ATTRIB(XonoticMiscSettingsTab, rows, float, 14.5)
        ATTRIB(XonoticMiscSettingsTab, columns, float, 6.2)
 ENDCLASS(XonoticMiscSettingsTab)
 entity makeXonoticMiscSettingsTab();
@@ -23,10 +23,13 @@ void XonoticMiscSettingsTab_fill(entity me)
        //entity sk;
 
        me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Network:")));
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Network")));
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Speed:")));
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Client UDP port:")));
+               me.TD(me, 1, 1.5, e = makeXonoticInputBox(0, "cl_port"));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Bandwidth:")));
                me.TD(me, 1, 2, e = makeXonoticTextSlider("_cl_rate"));
                        e.addValue(e, _("56k"), "4000");
                        e.addValue(e, _("ISDN"), "7000");
@@ -35,55 +38,40 @@ void XonoticMiscSettingsTab_fill(entity me)
                        e.addValue(e, _("Broadband"), "66666");
                        e.configureXonoticTextSliderValues(e);
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Input packets/s:")));
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Input packets/s:")));
                me.TD(me, 1, 2, e = makeXonoticSlider(20, 100, 5, "cl_netfps"));
        me.TR(me);
-               if(cvar("developer"))
-               {
-                       me.TDempty(me, 0.2);
-                       me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Local latency:")));
-                       me.TD(me, 1, 2, e = makeXonoticSlider(0, 1000, 25, "cl_netlocalping"));
-               }
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Server queries/s:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(20, 100, 10, "net_slist_queriespersecond"));
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticTextLabel(0, _("Client UDP port:")));
-               me.TD(me, 1, 1, e = makeXonoticInputBox(0, "cl_port"));
-                       e.enableClearButton = 0;
        me.TR(me);
-               me.TDempty(me, 0.2);
-               if(cvar_type("crypto_aeslevel") & CVAR_TYPEFLAG_ENGINE)
-                       me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(2, 1, "crypto_aeslevel", _("Use encryption (AES) when available")));
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Downloads:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(1, 5, 1, "cl_curl_maxdownloads"));
        me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Speed (kB/s):")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(10, 2000, 50, "cl_curl_maxspeed"));
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "shownetgraph", _("Show netgraph")));
+               if(cvar("developer"))
+               {
+                       me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Local latency:")));
+                       me.TD(me, 1, 2, e = makeXonoticSlider(0, 1000, 25, "cl_netlocalping"));
+               }
        me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "shownetgraph", _("Show netgraph")));
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_movement", _("Client-side movement prediction")));
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_movement", _("Client-side movement prediction")));
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_movement_errorcompensation", _("Movement error compensation")));
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_movement_errorcompensation", _("Movement error compensation")));
                setDependent(e, "cl_movement", 1, 1);
        me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Downloads:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Maximum:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(1, 5, 1, "cl_curl_maxdownloads"));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Speed (kB/s):")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(10, 1500, 10, "cl_curl_maxspeed"));
-       me.TR(me);
+               if(cvar_type("crypto_aeslevel") & CVAR_TYPEFLAG_ENGINE)
+                       me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "crypto_aeslevel", _("Use encryption (AES) when available"))); // TODO: move up
 
        me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Framerate:")));
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Framerate")));
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Maximum:")));
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Maximum:")));
                me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_maxfps"));
                        e.addValue(e, ZCTX(_("MAXFPS^5 fps")), "5");
                        e.addValue(e, ZCTX(_("MAXFPS^10 fps")), "10");
@@ -99,8 +87,7 @@ void XonoticMiscSettingsTab_fill(entity me)
                        e.addValue(e, ZCTX(_("MAXFPS^Unlimited")), "0");
                        e.configureXonoticTextSliderValues(e);
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Target:")));
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Target:")));
                me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_minfps"));
                        e.addValue(e, ZCTX(_("TRGT^Disabled")), "0");
                        e.addValue(e, ZCTX(_("TRGT^30 fps")), "30");
@@ -112,8 +99,7 @@ void XonoticMiscSettingsTab_fill(entity me)
                        e.addValue(e, ZCTX(_("TRGT^200 fps")), "200");
                        e.configureXonoticTextSliderValues(e);
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Idle limit:")));
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Idle limit:")));
                me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_maxidlefps"));
                        e.addValue(e, ZCTX(_("IDLFPS^10 fps")), "10");
                        e.addValue(e, ZCTX(_("IDLFPS^20 fps")), "20");
@@ -123,13 +109,13 @@ void XonoticMiscSettingsTab_fill(entity me)
                        e.configureXonoticTextSliderValues(e);
        me.TR(me);
        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "showfps", _("Show frames per second")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_maxfps_alwayssleep", _("Save processing time for other apps")));
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_maxfps_alwayssleep", _("Save processing time for other apps")));
                setDependent(e, "cl_maxfps", 1, 1000);
        me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "showfps", _("Show frames per second")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Other")));
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Menu tooltips:")));
                me.TD(me, 1, 2, e = makeXonoticTextSlider("menu_tooltips"));
@@ -138,18 +124,20 @@ void XonoticMiscSettingsTab_fill(entity me)
                        e.addValue(e, ZCTX(_("TLTIP^Advanced")), "2");
                        e.configureXonoticTextSliderValues(e);
        me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "showtime", _("Show current time")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "showdate", _("Show current date")));
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "showtime", _("Show current date and time")));
+                       makeMulti(e, "showdate");
        me.TR(me);
                me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "developer", _("Enable developer mode")));
-       me.TR(me);
+
        me.TR(me);
                me.TDempty(me, 0.5);
                me.TD(me, 1, 2, e = makeXonoticButton(_("Advanced settings..."), '0 0 0'));
                        e.onClick = DialogOpenButton_Click;
                        e.onClickEntity = main.cvarsDialog;
        me.TR(me);
+               me.TDempty(me, 0.5);
+               me.TD(me, 1, 2, e = makeXonoticButton(_("Factory reset"), '0 0 0'));
+                       e.onClick = DialogOpenButton_Click;
+                       e.onClickEntity = main.resetDialog;
 }
 #endif
index f511ec361cb6fbf4bd44e803fe341a41b2db7d49..c2ea2a5b66167c8dfc366bd8361ba0238a7e9c22 100644 (file)
@@ -28,6 +28,9 @@ void XonoticCvarsDialog_fill(entity me) // in this dialog, use SKINCOLOR_CVARLIS
                cvarlist.colorC =
                SKINCOLOR_CVARLIST_CONTROLS;
 
+       // todo:
+       // add button which does cvar_resettodefaults_saveonly
+
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Cvar filter:")));
                me.TD(me, 1, me.columns - 1, e = makeXonoticInputBox(0, string_null));
diff --git a/qcsrc/menu/xonotic/dialog_settings_misc_reset.c b/qcsrc/menu/xonotic/dialog_settings_misc_reset.c
new file mode 100644 (file)
index 0000000..8f6da0a
--- /dev/null
@@ -0,0 +1,28 @@
+#ifdef INTERFACE
+CLASS(XonoticResetDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticResetDialog, fill, void(entity))
+       ATTRIB(XonoticResetDialog, title, string, _("Factory reset"))
+       ATTRIB(XonoticResetDialog, color, vector, SKINCOLOR_DIALOG_QUIT)
+       ATTRIB(XonoticResetDialog, intendedWidth, float, 0.5)
+       ATTRIB(XonoticResetDialog, rows, float, 4)
+       ATTRIB(XonoticResetDialog, columns, float, 2)
+       ATTRIB(XonoticResetDialog, name, string, "Factory reset")
+ENDCLASS(XonoticResetDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticResetDialog_fill(entity me)
+{
+       entity e;
+       me.TR(me);
+               me.TD(me, 1, 2, makeXonoticTextLabel(0.5, _("Are you sure you want to reset all settings?")));
+       me.TR(me);
+               me.TD(me, 1, 2, makeXonoticTextLabel(0.5, _("This will create a backup config in your data directory")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCommandButton(_("Yes"), '1 0 0', "saveconfig backup.cfg\n;\n exec defaultXonotic.cfg\n", 0));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("No"), '0 1 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
index 5d6a32d563586bde88a96ef9f0479e2f106bbef0..b3f888594eae083f767a4a36df28e50843bd0650 100644 (file)
@@ -3,8 +3,8 @@ CLASS(XonoticUserSettingsTab) EXTENDS(XonoticTab)
        METHOD(XonoticUserSettingsTab, fill, void(entity))
        ATTRIB(XonoticUserSettingsTab, title, string, _("User"))
        ATTRIB(XonoticUserSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticUserSettingsTab, rows, float, 17)
-       ATTRIB(XonoticUserSettingsTab, columns, float, 5)
+       ATTRIB(XonoticUserSettingsTab, rows, float, 14.5)
+       ATTRIB(XonoticUserSettingsTab, columns, float, 6)
 ENDCLASS(XonoticUserSettingsTab)
 entity makeXonoticUserSettingsTab();
 #endif
@@ -24,11 +24,13 @@ void XonoticUserSettingsTab_fill(entity me)
        entity sk;
 
        me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0, _("Menu skins:")));
+               me.TDempty(me, 0.25);
+               me.TD(me, 1, 2.5, e = makeXonoticHeaderLabel(_("Menu Skins")));
        me.TR(me);
-               me.TD(me, me.rows - 2, 2, sk = makeXonoticSkinList());
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, 2, e = makeXonoticButton(_("Set skin"), '0 0 0'));
+               me.TDempty(me, 0.25);
+               me.TD(me, me.rows - 2.5, 2.5, sk = makeXonoticSkinList());
+       me.gotoRC(me, me.rows - 1.5, 0.25);
+               me.TD(me, 1, 2.5, e = makeXonoticButton(_("Set skin"), '0 0 0'));
                        e.onClick = SetSkin_Click;
                        e.onClickEntity = sk;
 
@@ -61,31 +63,34 @@ void XonoticUserSettingsTab_fill(entity me)
                        e.onClick = SetLanguage_Click;
                        e.onClickEntity = sk;*/
 
-       me.gotoRC(me, 0, 2.85); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Text language:")));
-       me.TR(me);
-               me.TD(me, 6, 1.5, sk = makeXonoticLanguageList());
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
+       me.gotoRC(me, 0, 3.75); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 1.5, e = makeXonoticHeaderLabel(_("Text Language")));
        me.TR(me);
+               me.TD(me, 8, 1.5, sk = makeXonoticLanguageList());
+
+       me.gotoRC(me, 9, 3.75); me.setFirstColumn(me, me.currentColumn);
                me.TD(me, 1, 1.5, e = makeXonoticButton(_("Set language"), '0 0 0'));
                        e.onClick = SetLanguage_Click;
                        e.onClickEntity = sk;
 
-       me.gotoRC(me, 9, 2.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_gentle", _("Disable gore effects and harsh language")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_allow_uidtracking", _("Allow player statistics to track your client")));
-       me.TR(me);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_allow_uid2name", _("Allow player statistics to use your nickname")));
-               setDependent(e, "cl_allow_uidtracking", 1, 1);
+       me.gotoRC(me, 11.5, 3.25); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, "cl_gentle", _("Disable gore effects and harsh language")));
+
+       //me.TR(me);
+       //      me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Menu tooltips:")));
+       //      me.TD(me, 1, 2, e = makeXonoticTextSlider("menu_tooltips"));
+       //              e.addValue(e, ZCTX(_("TLTIP^Disabled")), "0");
+       //              e.addValue(e, ZCTX(_("TLTIP^Standard")), "1");
+       //              e.addValue(e, ZCTX(_("TLTIP^Advanced")), "2");
+       //              e.configureXonoticTextSliderValues(e);
+       //me.TR(me);
+       //      me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_allow_uidtracking", _("Allow player statistics to track your client"))); // TODO: move to profile tab
+       //me.TR(me);
+       //      me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_allow_uid2name", _("Allow player statistics to use your nickname")));
+       //      setDependent(e, "cl_allow_uidtracking", 1, 1);
 
-       me.gotoRC(me, me.rows - 3, 2.6);
-               me.TD(me, 1, 2, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "sendcvar cl_gentle; sendcvar cl_allow_uidtracking; sendcvar cl_allow_uid2name;", COMMANDBUTTON_APPLY));
+       //me.gotoRC(me, me.rows - 1, 2.6);
+       //      me.TD(me, 1, 2, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "sendcvar cl_gentle; sendcvar cl_allow_uidtracking; sendcvar cl_allow_uid2name;", COMMANDBUTTON_APPLY));
 
 }
 #endif
index db728d601494407d9aa58077b594d73c48999823..a4e8434136963b3d7c00723f62f325756c81d92d 100644 (file)
@@ -3,7 +3,7 @@ CLASS(XonoticVideoSettingsTab) EXTENDS(XonoticTab)
        METHOD(XonoticVideoSettingsTab, fill, void(entity))
        ATTRIB(XonoticVideoSettingsTab, title, string, _("Video"))
        ATTRIB(XonoticVideoSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticVideoSettingsTab, rows, float, 17)
+       ATTRIB(XonoticVideoSettingsTab, rows, float, 14.5)
        ATTRIB(XonoticVideoSettingsTab, columns, float, 6.2) // added extra .2 for center space
        ATTRIB(XonoticVideoSettingsTab, name, string, "videosettings")
 ENDCLASS(XonoticVideoSettingsTab)
@@ -49,6 +49,8 @@ void XonoticVideoSettingsTab_fill(entity me)
                me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "vid_vsync", _("Vertical Synchronization")));
 
        me.TR(me);
+               if(cvar("developer"))
+                       { me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "v_flipped", _("Flip view horizontally"))); }
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Anisotropy:")));
                me.TD(me, 1, 2, e = makeXonoticTextSlider("gl_texture_anisotropy"));
@@ -135,8 +137,6 @@ void XonoticVideoSettingsTab_fill(entity me)
                me.TR(me);
                        me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "r_trippy", _("Trippy vertices (easter egg)")));
                                setDependent(e, "vid_gl20", 1, 1);
-               me.TR(me);
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "v_flipped", _("Flip view horizontally")));
        }
 
        me.gotoRC(me, me.rows - 1, 0);
index 8883e8bbe4aff519e8c020d4295db2e227154a66..c7f385761d804cac0f94177a4fc8625a37748e37 100644 (file)
@@ -10,8 +10,7 @@ CLASS(XonoticGametypeList) EXTENDS(XonoticListBox)
        METHOD(XonoticGametypeList, keyDown, float(entity, float, float, float))
 
        ATTRIB(XonoticGametypeList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticGametypeList, realUpperMargin1, float, 0)
-       ATTRIB(XonoticGametypeList, realUpperMargin2, float, 0)
+       ATTRIB(XonoticGametypeList, realUpperMargin, float, 0)
        ATTRIB(XonoticGametypeList, columnIconOrigin, float, 0)
        ATTRIB(XonoticGametypeList, columnIconSize, float, 0)
        ATTRIB(XonoticGametypeList, columnNameOrigin, float, 0)
@@ -84,7 +83,14 @@ void XonoticGametypeList_drawListBoxItem(entity me, float i, vector absSize, flo
 
        draw_Picture(me.columnIconOrigin * eX, GameType_GetIcon(i), me.columnIconSize * eX + eY, '1 1 1', SKINALPHA_LISTBOX_SELECTED);
        s = GameType_GetName(i);
-       draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.5 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
+       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+       
+       if(_MapInfo_GetTeamPlayBool(GameType_GetID(i)))
+               s = _("teamplay");
+       else
+               s = _("free for all");
+
+       draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 1.0 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
        //s = GameType_GetTeams(i);
        //draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 1.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
 }
@@ -95,12 +101,11 @@ void XonoticGametypeList_resizeNotify(entity me, vector relOrigin, vector relSiz
 
        me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize_y * me.itemHeight));
        me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize_x * (1 - me.controlWidth)));
-       me.realUpperMargin1 = 0.5 * (1 - me.realFontSize_y);
-       me.realUpperMargin2 = me.realUpperMargin1 + me.realFontSize_y;
+       me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
        me.columnIconOrigin = 0;
        me.columnIconSize = me.itemAbsSize_y / me.itemAbsSize_x;
-       me.columnNameOrigin = me.columnIconOrigin + me.columnIconSize;
-       me.columnNameSize = 1 - me.columnIconSize - 2 * me.realFontSize_x;
+       me.columnNameOrigin = me.columnIconOrigin + me.columnIconSize + (0.5 * me.realFontSize_x);
+       me.columnNameSize = 1 - me.columnIconSize - (1.5 * me.realFontSize_x);
 }
 
 float XonoticGametypeList_keyDown(entity me, float scan, float ascii, float shift)
index 78bab2bccb33418b146c79e75cf08fc4722211f2..5d7d179995028719bc107d1158edcd91678bc1e8 100644 (file)
@@ -26,6 +26,7 @@ CLASS(XonoticInputBox) EXTENDS(InputBox)
        ATTRIB(XonoticInputBox, cvarName, string, string_null)
        METHOD(XonoticInputBox, loadCvars, void(entity))
        METHOD(XonoticInputBox, saveCvars, void(entity))
+       ATTRIB(XonoticInputBox, sendCvars, float, 0)
        METHOD(XonoticInputBox, keyDown, float(entity, float, float, float))
 
        ATTRIB(XonoticInputBox, saveImmediately, float, 0)
@@ -81,6 +82,7 @@ void XonoticInputBox_saveCvars(entity me)
        if (!me.cvarName)
                return;
        cvar_set(me.cvarName, me.text);
+       CheckSendCvars(me, me.cvarName);
 }
 float XonoticInputBox_keyDown(entity me, float key, float ascii, float shift)
 {
index 57f501f5c145a050724cb570045aa4b332622a74..c312e382656105a4824bd3b6e3c3568df0ee36ae 100644 (file)
@@ -238,6 +238,13 @@ void KeyBinder_Bind_Clear(entity btn, entity me)
        localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
        cvar_set("_hud_showbinds_reload", "1");
 }
+void KeyBinder_Bind_Reset_All(entity btn, entity me)
+{
+       localcmd("unbindall\n");
+       localcmd("exec binds-default.cfg\n");
+       localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
+       cvar_set("_hud_showbinds_reload", "1");
+}
 void XonoticKeyBinder_clickListBoxItem(entity me, float i, vector where)
 {
        if(i == me.lastClickedKey)
index dcc4a8a81729e440fbf042ddc448d4f16a83cbb2..6fa40bfac69cf687997ec45952d7b10eb7825d12 100644 (file)
@@ -5,21 +5,21 @@ CLASS(MainWindow) EXTENDS(ModalController)
        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
 
@@ -117,10 +117,14 @@ void MainWindow_configureMainWindow(entity me)
        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);
@@ -139,64 +143,49 @@ void MainWindow_configureMainWindow(entity me)
        me.cvarsDialog = i = spawnXonoticCvarsDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       me.languageWarningDialog = i = spawnXonoticLanguageWarningDialog();
+       
+       me.resetDialog = i = spawnXonoticResetDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
 
-
-       // dialog used by singleplayer
-       me.winnerDialog = i = spawnXonoticWinnerDialog();
-       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();
+       me.languageWarningDialog = i = spawnXonoticLanguageWarningDialog();
        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.hudconfirmDialog = i = spawnXonoticHUDConfirmDialog();
        i.configureDialog(i);
        me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
 
-       me.advancedDialog = i = spawnXonoticAdvancedDialog();
-       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);
diff --git a/qcsrc/menu/xonotic/screenshotimage.c b/qcsrc/menu/xonotic/screenshotimage.c
new file mode 100644 (file)
index 0000000..469f177
--- /dev/null
@@ -0,0 +1,95 @@
+#ifdef INTERFACE
+CLASS(XonoticScreenshotImage) EXTENDS(XonoticImage)
+       METHOD(XonoticScreenshotImage, configureXonoticScreenshotImage, void(entity))
+       METHOD(XonoticScreenshotImage, load, void(entity, string))
+       METHOD(XonoticScreenshotImage, draw, void(entity))
+       ATTRIB(XonoticScreenshotImage, focusable, float, 1) // mousePress and mouseDrag work only if focusable is set
+       METHOD(XonoticScreenshotImage, mousePress, float(entity, vector))
+       METHOD(XonoticScreenshotImage, mouseDrag, float(entity, vector))
+       METHOD(XonoticScreenshotImage, mouseMove, float(entity, vector))
+       METHOD(XonoticScreenshotImage, resizeNotify, void(entity, vector, vector, vector, vector))
+       ATTRIB(XonoticScreenshotImage, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticScreenshotImage, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticScreenshotImage, showTitle, float, 1)
+       ATTRIB(XonoticScreenshotImage, screenshotTime, float, 0)
+       ATTRIB(XonoticScreenshotImage, screenshotTitle, string, string_null)
+ENDCLASS(XonoticScreenshotImage)
+entity makeXonoticScreenshotImage();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticScreenshotImage()
+{
+       entity me;
+       me = spawnXonoticScreenshotImage();
+       me.configureXonoticScreenshotImage(me);
+       return me;
+}
+
+void XonoticScreenshotImage_configureXonoticScreenshotImage(entity me)
+{
+       me.configureXonoticImage(me, string_null, -2);
+       me.zoomLimitedByTheBox = FALSE; // enable this to forbid enlarging the image more than the containing box (if making use of draw_SetClip is a too bad thing)
+       me.zoomSnapToTheBox = FALSE; // disabled: it's cooler
+}
+
+void XonoticScreenshotImage_load(entity me, string theImage)
+{
+       me.screenshotTime = time;
+       me.src = theImage;
+       if (me.screenshotTitle)
+               strunzone(me.screenshotTitle);
+       me.screenshotTitle = strzone(substring(me.src, 13, strlen(theImage) - 13)); //strip "/screenshots/"
+
+       me.initZoom(me); // this image may have a different size
+       me.setZoom(me, 0, 0);
+}
+
+float XonoticScreenshotImage_mousePress(entity me, vector coords)
+{
+       return me.drag_setStartPos(me, coords);
+}
+
+float XonoticScreenshotImage_mouseDrag(entity me, vector coords)
+{
+       return me.drag(me, coords);
+}
+
+float XonoticScreenshotImage_mouseMove(entity me, vector coords)
+{
+       return me.drag_setStartPos(me, coords);
+}
+
+void XonoticScreenshotImage_draw(entity me)
+{
+       if (me.src != "")
+       {
+               float theAlpha;
+               SUPER(XonoticScreenshotImage).draw(me);
+               if (me.showTitle && time < me.screenshotTime + 4) // 3 seconds at full alpha, 1 second fading out
+               {
+                       theAlpha = (4 - (time - me.screenshotTime));
+                       draw_CenterText('0.5 0 0', me.screenshotTitle, me.realFontSize, '1 1 1', theAlpha, FALSE);
+               }
+               if (time < me.zoomTime + 2) // 1 seconds at full alpha, 1 second fading out
+               {
+                       string zoomString;
+                       float z;
+                       z = me.zoomFactor * 100;
+                       if (z - floor(z) == 0)
+                               zoomString = sprintf("%d%%", z);
+                       else
+                               zoomString = sprintf("%.2f%%", z);
+                       theAlpha = (2 - (time - me.zoomTime));
+                       draw_Text('0.05 0.95 0', zoomString, me.realFontSize, '1 1 1', theAlpha, FALSE);
+               }
+       }
+}
+
+void XonoticScreenshotImage_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(XonoticScreenshotImage).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+       me.realFontSize_y = me.fontSize / absSize_y;
+       me.realFontSize_x = me.fontSize / absSize_x;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/screenshotlist.c b/qcsrc/menu/xonotic/screenshotlist.c
new file mode 100644 (file)
index 0000000..dd8b61e
--- /dev/null
@@ -0,0 +1,307 @@
+#ifdef INTERFACE
+CLASS(XonoticScreenshotList) EXTENDS(XonoticListBox)
+       METHOD(XonoticScreenshotList, configureXonoticScreenshotList, void(entity))
+       ATTRIB(XonoticScreenshotList, rowsPerItem, float, 1)
+       METHOD(XonoticScreenshotList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticScreenshotList, setSelected, void(entity, float))
+       METHOD(XonoticScreenshotList, draw, void(entity))
+       METHOD(XonoticScreenshotList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticScreenshotList, getScreenshots, void(entity))
+       METHOD(XonoticScreenshotList, previewScreenshot, void(entity))
+       METHOD(XonoticScreenshotList, startScreenshot, void(entity))
+       METHOD(XonoticScreenshotList, screenshotName, string(entity, float))
+       METHOD(XonoticScreenshotList, clickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticScreenshotList, keyDown, float(entity, float, float, float))
+       METHOD(XonoticScreenshotList, destroy, void(entity))
+       METHOD(XonoticScreenshotList, showNotify, void(entity))
+       ATTRIB(XonoticScreenshotList, listScreenshot, float, -1)
+       ATTRIB(XonoticScreenshotList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticScreenshotList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticScreenshotList, columnNameSize, float, 0)
+       ATTRIB(XonoticScreenshotList, realUpperMargin, float, 0)
+       ATTRIB(XonoticScreenshotList, origin, vector, '0 0 0')
+       ATTRIB(XonoticScreenshotList, itemAbsSize, vector, '0 0 0')
+       ATTRIB(XonoticScreenshotList, lastClickedScreenshot, float, -1)
+       ATTRIB(XonoticScreenshotList, lastClickedTime, float, 0)
+       ATTRIB(XonoticScreenshotList, filterString, string, string_null)
+       ATTRIB(XonoticScreenshotList, filterBox, entity, NULL)
+       ATTRIB(XonoticScreenshotList, filterTime, float, 0)
+
+       ATTRIB(XonoticScreenshotList, newScreenshotTime, float, 0)
+       ATTRIB(XonoticScreenshotList, newSlideShowScreenshotTime, float, 0)
+       ATTRIB(XonoticScreenshotList, prevSelectedItem, float, 0)
+
+       ATTRIB(XonoticScreenshotList, screenshotBrowserDialog, entity, NULL)
+       ATTRIB(XonoticScreenshotList, screenshotPreview, entity, NULL)
+       ATTRIB(XonoticScreenshotList, screenshotViewerDialog, entity, NULL)
+       METHOD(XonoticScreenshotList, goScreenshot, void(entity, float))
+       METHOD(XonoticScreenshotList, startSlideShow, void(entity))
+       METHOD(XonoticScreenshotList, stopSlideShow, void(entity))
+ENDCLASS(XonoticScreenshotList)
+
+entity makeXonoticScreenshotList();
+void StartScreenshot_Click(entity btn, entity me);
+void ScreenshotList_Refresh_Click(entity btn, entity me);
+void ScreenshotList_Filter_Would_Change(entity box, entity me);
+void ScreenshotList_Filter_Change(entity box, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+
+entity makeXonoticScreenshotList()
+{
+       entity me;
+       me = spawnXonoticScreenshotList();
+       me.configureXonoticScreenshotList(me);
+       return me;
+}
+
+void XonoticScreenshotList_configureXonoticScreenshotList(entity me)
+{
+       me.configureXonoticListBox(me);
+       me.getScreenshots(me);
+}
+
+string XonoticScreenshotList_screenshotName(entity me, float i)
+{
+       string s;
+       s = bufstr_get(me.listScreenshot, i);
+
+       if(substring(s, 0, 1) == "/")
+               s = substring(s, 1, strlen(s) - 1);  // remove the first forward slash
+
+       return s;
+}
+
+// if subdir is TRUE look in subdirectories too (1 level)
+void getScreenshots_for_ext(entity me, string ext, float subdir)
+{
+       string s;
+       if (subdir)
+               s="screenshots/*/";
+       else
+               s="screenshots/";
+       if(me.filterString)
+               s=strcat(s, me.filterString, ext);
+       else
+               s=strcat(s, "*", ext);
+
+       float list, i, n;
+       list = search_begin(s, FALSE, TRUE);
+       if(list >= 0)
+       {
+               n = search_getsize(list);
+               for(i = 0; i < n; ++i)
+               {
+                       s = search_getfilename(list, i); // get initial full file name
+                       s = substring(s, 12, (strlen(s) - 12 - 4)); // remove "screenshots/" prefix and ".<ext>" suffix
+                       s = strdecolorize(s); // remove any pre-existing colors
+                       if(subdir)
+                       {
+                               s = strreplace("/", "^7/", s); // clear colors at the forward slash
+                               s = strcat("/", rgb_to_hexcolor(SKINCOLOR_SCREENSHOTLIST_SUBDIR), s); // add a forward slash for sorting, then color
+                               bufstr_add(me.listScreenshot, s, TRUE);
+                       }
+                       else { bufstr_add(me.listScreenshot, s, TRUE); }
+               }
+               search_end(list);
+       }
+
+       if (subdir)
+               getScreenshots_for_ext(me, ext, FALSE);
+}
+
+void XonoticScreenshotList_getScreenshots(entity me)
+{
+       if (me.listScreenshot >= 0)
+               buf_del(me.listScreenshot);
+       me.listScreenshot = buf_create();
+       if (me.listScreenshot < 0)
+       {
+               me.nItems = 0;
+               return;
+       }
+       getScreenshots_for_ext(me, ".jpg", TRUE);
+       getScreenshots_for_ext(me, ".tga", TRUE);
+       getScreenshots_for_ext(me, ".png", TRUE);
+       me.nItems = buf_getsize(me.listScreenshot);
+       if(me.nItems > 0)
+               buf_sort(me.listScreenshot, 128, FALSE);
+}
+
+void XonoticScreenshotList_destroy(entity me)
+{
+       if(me.nItems > 0)
+               buf_del(me.listScreenshot);
+}
+
+void XonoticScreenshotList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemAbsSize = '0 0 0';
+       SUPER(XonoticScreenshotList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+
+       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize_y * me.itemHeight));
+       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize_x * (1 - me.controlWidth)));
+       me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+
+       me.columnNameOrigin = me.realFontSize_x;
+       me.columnNameSize = 1 - 2 * me.realFontSize_x;
+}
+
+void XonoticScreenshotList_setSelected(entity me, float i)
+{
+       if (me.newSlideShowScreenshotTime)
+               me.startSlideShow(me);
+       me.prevSelectedItem = me.selectedItem;
+       SUPER(XonoticScreenshotList).setSelected(me, i);
+       if (me.pressed && me.selectedItem != me.prevSelectedItem)
+       {
+               // while dragging the scrollbar (or an item)
+               // for a smooth mouse movement do not load immediately the new selected images
+               me.newScreenshotTime = time + 0.22; // dragging an item we need a delay > 0.2 (from listbox: me.dragScrollTimer = time + 0.2;)
+       }
+       else if (time > me.newScreenshotTime)
+       {
+               me.newScreenshotTime = 0;
+               me.previewScreenshot(me); // load the preview on selection change
+       }
+}
+
+void XonoticScreenshotList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       string s;
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+       s = me.screenshotName(me,i);
+       s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 1);
+}
+
+void XonoticScreenshotList_showNotify(entity me)
+{
+       me.getScreenshots(me);
+       me.previewScreenshot(me);
+}
+
+void ScreenshotList_Refresh_Click(entity btn, entity me)
+{
+       me.getScreenshots(me);
+       me.setSelected(me, 0); //always select the first element after a list update
+}
+
+void ScreenshotList_Filter_Change(entity box, entity me)
+{
+       if(me.filterString)
+               strunzone(me.filterString);
+
+       if(box.text != "")
+       {
+               if (strstrofs(box.text, "*", 0) >= 0 || strstrofs(box.text, "?", 0) >= 0)
+                       me.filterString = strzone(box.text);
+               else
+                       me.filterString = strzone(strcat("*", box.text, "*"));
+       }
+       else
+               me.filterString = string_null;
+
+       ScreenshotList_Refresh_Click(world, me);
+}
+
+void ScreenshotList_Filter_Would_Change(entity box, entity me)
+{
+       me.filterBox = box;
+       me.filterTime = time + 0.5;
+}
+
+void XonoticScreenshotList_draw(entity me)
+{
+       if (me.filterTime && time > me.filterTime)
+       {
+               ScreenshotList_Filter_Change(me.filterBox, me);
+               me.filterTime = 0;
+       }
+       if (me.newScreenshotTime && time > me.newScreenshotTime)
+       {
+               me.previewScreenshot(me);
+               me.newScreenshotTime = 0;
+       }
+       else if (me.newSlideShowScreenshotTime && time > me.newSlideShowScreenshotTime)
+       {
+               if (me.selectedItem == me.nItems - 1) //last screenshot?
+               {
+                       // restart from the first screenshot
+                       me.setSelected(me, 0);
+                       me.goScreenshot(me, +0);
+               }
+               else
+                       me.goScreenshot(me, +1);
+       }
+       SUPER(XonoticScreenshotList).draw(me);
+}
+
+void XonoticScreenshotList_startSlideShow(entity me)
+{
+       me.newSlideShowScreenshotTime = time + 3;
+}
+
+void XonoticScreenshotList_stopSlideShow(entity me)
+{
+       me.newSlideShowScreenshotTime = 0;
+}
+
+void XonoticScreenshotList_goScreenshot(entity me, float d)
+{
+       if(!me.screenshotViewerDialog)
+               return;
+       me.setSelected(me, me.selectedItem + d);
+       me.screenshotViewerDialog.loadScreenshot(me.screenshotViewerDialog, strcat("/screenshots/", strdecolorize(me.screenshotName(me,me.selectedItem))));
+}
+
+void XonoticScreenshotList_startScreenshot(entity me)
+{
+       me.screenshotViewerDialog.loadScreenshot(me.screenshotViewerDialog, strcat("/screenshots/", strdecolorize(me.screenshotName(me,me.selectedItem))));
+       // pop up screenshot
+       DialogOpenButton_Click_withCoords(NULL, me.screenshotViewerDialog, me.origin + eX * (me.columnNameOrigin * me.size_x) + eY * ((me.itemHeight * me.selectedItem - me.scrollPos) * me.size_y), eY * me.itemAbsSize_y + eX * (me.itemAbsSize_x * me.columnNameSize));
+}
+
+void XonoticScreenshotList_previewScreenshot(entity me)
+{
+       if(!me.screenshotBrowserDialog)
+               return;
+       if (me.nItems <= 0)
+               me.screenshotBrowserDialog.loadPreviewScreenshot(me.screenshotBrowserDialog, "");
+       else
+               me.screenshotBrowserDialog.loadPreviewScreenshot(me.screenshotBrowserDialog, strcat("/screenshots/", strdecolorize(me.screenshotName(me,me.selectedItem))));
+}
+
+void StartScreenshot_Click(entity btn, entity me)
+{
+       me.startScreenshot(me);
+}
+
+void XonoticScreenshotList_clickListBoxItem(entity me, float i, vector where)
+{
+       if(i == me.lastClickedScreenshot)
+               if(time < me.lastClickedTime + 0.3)
+               {
+                       // DOUBLE CLICK!
+                       // pop up screenshot
+                       me.setSelected(me, i);
+                       me.startScreenshot(me);
+               }
+       me.lastClickedScreenshot = i;
+       me.lastClickedTime = time;
+}
+
+float XonoticScreenshotList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if(scan == K_ENTER || scan == K_KP_ENTER || scan == K_MOUSE2 || scan == K_SPACE) {
+               me.startScreenshot(me);
+               return 1;
+       }
+       if(scan == K_MWHEELUP || scan == K_MWHEELDOWN)
+               me.newScreenshotTime = time + 0.2;
+       return SUPER(XonoticScreenshotList).keyDown(me, scan, ascii, shift);
+}
+#endif
index ed68acd713ed1861de710deb46c1fdbe449ba81b..8b3a9e9a0394caf9f443e27499ce37d46aea4556 100644 (file)
@@ -957,7 +957,10 @@ void ServerList_Info_Click(entity btn, entity me)
 {
        if (me.nItems != 0)
                main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
-       DialogOpenButton_Click(me, main.serverInfoDialog);
+
+       vector org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
+       vector sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
+       DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
 }
 void XonoticServerList_clickListBoxItem(entity me, float i, vector where)
 {
index aba15ecae625d244fda71f4eb60f9c623a61787b..d63fe1c336c8ae2d2577803b67bd12cbfe59b5cb 100644 (file)
@@ -16,6 +16,7 @@ CLASS(XonoticSlider) EXTENDS(Slider)
        ATTRIB(XonoticSlider, cvarName, string, string_null)
        METHOD(XonoticSlider, loadCvars, void(entity))
        METHOD(XonoticSlider, saveCvars, void(entity))
+       ATTRIB(XonoticSlider, sendCvars, float, 0)
 
        ATTRIB(XonoticSlider, alpha, float, SKINALPHA_TEXT)
        ATTRIB(XonoticSlider, disabledAlpha, float, SKINALPHA_DISABLED)
@@ -73,5 +74,7 @@ void XonoticSlider_saveCvars(entity me)
                return;
 
        cvar_set(me.cvarName, ftos(me.value));
+
+       CheckSendCvars(me, me.cvarName);
 }
 #endif
diff --git a/qcsrc/menu/xonotic/slider_sbfadetime.c b/qcsrc/menu/xonotic/slider_sbfadetime.c
new file mode 100644 (file)
index 0000000..39f91f9
--- /dev/null
@@ -0,0 +1,43 @@
+#ifdef INTERFACE
+CLASS(XonoticScoreboardFadeTimeSlider) EXTENDS(XonoticTextSlider)
+       METHOD(XonoticScoreboardFadeTimeSlider, configureXonoticScoreboardFadeTimeSlider, void(entity))
+       METHOD(XonoticScoreboardFadeTimeSlider, loadCvars, void(entity))
+       METHOD(XonoticScoreboardFadeTimeSlider, saveCvars, void(entity))
+ENDCLASS(XonoticScoreboardFadeTimeSlider)
+entity makeXonoticScoreboardFadeTimeSlider();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticScoreboardFadeTimeSlider()
+{
+       entity me;
+       me = spawnXonoticScoreboardFadeTimeSlider();
+       me.configureXonoticScoreboardFadeTimeSlider(me);
+       return me;
+}
+void XonoticScoreboardFadeTimeSlider_configureXonoticScoreboardFadeTimeSlider(entity me)
+{
+       me.configureXonoticTextSlider(me, "scoreboard_fadeinspeed");
+       me.addValue(me, ZCTX(_("PART^Slow")),     "5 2.5");
+       me.addValue(me, ZCTX(_("PART^Normal")),   "10 5");
+       me.addValue(me, ZCTX(_("PART^Fast")),     "15 7.5");
+       me.addValue(me, ZCTX(_("PART^Instant")),  "0 0");
+       me.configureXonoticTextSliderValues(me);
+}
+void XonoticScoreboardFadeTimeSlider_loadCvars(entity me)
+{
+       me.setValueFromIdentifier(me, sprintf("%s %s",
+               cvar_string("scoreboard_fadeinspeed"),
+               cvar_string("scoreboard_fadeoutspeed")
+       ));
+}
+void XonoticScoreboardFadeTimeSlider_saveCvars(entity me)
+{
+       if(me.value >= 0 || me.value < me.nValues)
+       {
+               tokenize_console(me.getIdentifier(me));
+               cvar_set("scoreboard_fadeinspeed", argv(0));
+               cvar_set("scoreboard_fadeoutspeed", argv(1));
+       }
+}
+#endif
diff --git a/qcsrc/menu/xonotic/statslist.c b/qcsrc/menu/xonotic/statslist.c
new file mode 100644 (file)
index 0000000..9882448
--- /dev/null
@@ -0,0 +1,362 @@
+#ifdef INTERFACE
+CLASS(XonoticStatsList) EXTENDS(XonoticListBox)
+       METHOD(XonoticStatsList, configureXonoticStatsList, void(entity))
+       ATTRIB(XonoticStatsList, rowsPerItem, float, 1.4)
+       METHOD(XonoticStatsList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticStatsList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticStatsList, getStats, void(entity))
+       METHOD(XonoticStatsList, clickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticStatsList, keyDown, float(entity, float, float, float))
+       METHOD(XonoticStatsList, destroy, void(entity))
+       METHOD(XonoticStatsList, showNotify, void(entity))
+
+       ATTRIB(XonoticStatsList, listStats, float, -1)
+       ATTRIB(XonoticStatsList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticStatsList, realUpperMargin, float, 0)
+       ATTRIB(XonoticStatsList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticStatsList, columnNameSize, float, 0)
+
+       ATTRIB(XonoticStatsList, lastClickedDemo, float, -1)
+       ATTRIB(XonoticStatsList, lastClickedTime, float, 0)
+ENDCLASS(XonoticStatsList)
+
+entity statslist; // for reference elsewhere
+entity makeXonoticStatsList();
+#endif
+
+#ifdef IMPLEMENTATION
+
+entity makeXonoticStatsList()
+{
+       entity me;
+       me = spawnXonoticStatsList();
+       me.configureXonoticStatsList(me);
+       return me;
+}
+
+void XonoticStatsList_configureXonoticStatsList(entity me)
+{
+       me.configureXonoticListBox(me);
+       me.getStats(me);
+}
+
+string XonoticStatsList_convertDate(string input)
+{
+       // 2013-12-21
+       // 0123456789
+       if(strlen(input) != 10)
+               return input;
+
+       string monthname = "";
+
+       switch(stof(substring(input, 5, 2)))
+       {
+               case 1:  monthname = _("January");    break;
+               case 2:  monthname = _("February");   break;
+               case 3:  monthname = _("March");      break;
+               case 4:  monthname = _("April");      break;
+               case 5:  monthname = _("May");        break;
+               case 6:  monthname = _("June");       break;
+               case 7:  monthname = _("July");       break;
+               case 8:  monthname = _("August");     break;
+               case 9:  monthname = _("September");  break;
+               case 10: monthname = _("October");    break;
+               case 11: monthname = _("November");   break;
+               case 12: monthname = _("December");   break;
+               default: return input; // failed, why?
+       }
+
+       return sprintf(
+               "%s %s, %d",
+               monthname,
+               count_ordinal(stof(substring(input, 8, 2))),
+               stof(substring(input, 0, 4))
+       );
+}
+
+void XonoticStatsList_getStats(entity me)
+{
+       dprint("XonoticStatsList_getStats() at time: ", ftos(time), "\n");
+       // delete the old buffer if it exists
+       if(me.listStats >= 0)
+               buf_del(me.listStats);
+
+       // create the new buffer if we have a stats buffer
+       if(PS_D_IN_DB >= 0)
+               me.listStats = buf_create();
+
+       // now confirmation, if we didn't create a buffer then just return now
+       if(me.listStats < 0)
+       {
+               me.nItems = 0;
+               return;
+       }
+
+       float order = 0;
+       string e = "", en = "", data = "";
+
+       string outstr = ""; // NOTE: out string MUST use underscores for spaces here, we'll replace them later
+       string orderstr = "";
+
+       float out_total_matches = -1;
+       float out_total_wins = -1;
+       float out_total_losses = -1;
+
+       float out_total_kills = -1;
+       float out_total_deaths = -1;
+
+       for(e = PS_D_IN_EVL; (en = db_get(PS_D_IN_DB, e)) != ""; e = en)
+       {
+               order = 0;
+               outstr = "";
+               orderstr = "";
+               data = db_get(PS_D_IN_DB, sprintf("#%s", e));
+
+               // non-gamemode specific stuff
+               switch(e)
+               {
+                       case "overall/joined_dt":
+                       {
+                               order = 1;
+                               outstr = _("Joined:");
+                               data = XonoticStatsList_convertDate(car(data));
+                               break;
+                       }
+                       case "overall/last_seen_dt":
+                       {
+                               order = 1;
+                               outstr = _("Last_Seen:");
+                               data = XonoticStatsList_convertDate(car(data));
+                               break;
+                       }
+                       case "overall/alivetime":
+                       {
+                               order = 1;
+                               outstr = _("Time_Played:");
+                               data = process_time(3, stof(data));
+                               break;
+                       }
+                       case "overall/favorite-map":
+                       {
+                               order = 2;
+                               outstr = _("Favorite_Map:");
+                               data = car(data);
+                               break;
+                       }
+                       case "overall/matches":
+                       {
+                               order = -1;
+                               out_total_matches = stof(data);
+                               break;
+                       }
+                       case "overall/wins":
+                       {
+                               order = -1;
+                               out_total_wins = stof(data);
+                               break;
+                       }
+                       case "overall/total-kills":
+                       {
+                               order = -1;
+                               out_total_kills = stof(data);
+                               break;
+                       }
+                       case "overall/total-deaths":
+                       {
+                               order = -1;
+                               out_total_deaths = stof(data);
+                               break;
+                       }
+               }
+
+               if((order == -1) && (out_total_matches >= 0) && (out_total_wins >= 0))
+               {
+                       bufstr_add(me.listStats, sprintf("003Matches: %d", out_total_matches), TRUE);
+                       
+                       if(out_total_matches > 0) // don't show extra info if there are no matches played
+                       {
+                               out_total_losses = max(0, (out_total_matches - out_total_wins));
+                               bufstr_add(me.listStats, sprintf("003Wins/Losses: %d/%d", out_total_wins, out_total_losses), TRUE);
+                               bufstr_add(me.listStats, sprintf("004Win_Percentage: %d%%", ((out_total_wins / out_total_matches) * 100)), TRUE);
+                       }
+
+                       out_total_matches = -1;
+                       out_total_wins = -1;
+                       out_total_losses = -1;
+                       continue;
+               }
+
+               if((order == -1) && (out_total_kills >= 0) && (out_total_deaths >= 0))
+               {
+                       bufstr_add(me.listStats, sprintf("005Kills/Deaths: %d/%d", out_total_kills, out_total_deaths), TRUE);
+
+                       // if there are no deaths, just show kill count 
+                       if(out_total_deaths > 0)
+                               bufstr_add(me.listStats, sprintf("006Kill_Ratio: %.2f", (out_total_kills / out_total_deaths)), TRUE);
+                       else
+                               bufstr_add(me.listStats, sprintf("006Kill_Ratio: %.2f", out_total_kills), TRUE);
+
+                       out_total_kills = -1;
+                       out_total_deaths = -1;
+                       continue;
+               }
+
+               // game mode specific stuff
+               if(order > 0)
+               {
+                       orderstr = sprintf("%03d", order);
+               }
+               else
+               {
+                       float dividerpos = strstrofs(e, "/", 0);
+                       
+                       string gametype = substring(e, 0, dividerpos);
+                       if(gametype == "overall") { continue; }
+                       
+                       string event = substring(e, (dividerpos + 1), strlen(e) - (dividerpos + 1));
+
+                       // if we are ranked, read these sets of possible options
+                       if(stof(db_get(PS_D_IN_DB, sprintf("#%s/rank", gametype))))
+                       {
+                               switch(event)
+                               {
+                                       case "matches":
+                                       {
+                                               order = 1;
+                                               outstr = sprintf(_("%s_Matches:"), strtoupper(gametype));
+                                               //data = sprintf(_("%d (unranked)"), data);
+                                               break;
+                                       }
+                                       case "elo":
+                                       {
+                                               order = 2;
+                                               outstr = sprintf(_("%s_ELO:"), strtoupper(gametype));
+                                               data = sprintf("%d", stof(data));
+                                               break;
+                                       }
+                                       case "rank":
+                                       {
+                                               order = 3;
+                                               outstr = sprintf(_("%s_Rank:"), strtoupper(gametype));
+                                               data = sprintf("%d", stof(data));
+                                               break;
+                                       }
+                                       case "percentile":
+                                       {
+                                               order = 4;
+                                               outstr = sprintf(_("%s_Percentile:"), strtoupper(gametype));
+                                               data = sprintf("%d%%", stof(data));
+                                               break;
+                                       }
+                                       
+                                       #if 0
+                                       case "favorite-map":
+                                       {
+                                               order = 5;
+                                               outstr = sprintf(_("%s_Favorite_Map:"), strtoupper(gametype));
+                                               //data = sprintf(_("%d (unranked)"), data);
+                                               break;
+                                       }
+                                       #endif
+                                       
+                                       default: continue; // nothing to see here
+                               }
+
+                               // now set up order for sorting later
+                               orderstr = sprintf("%2.2s%d", gametype, order);
+                       }
+                       else if(event == "matches")
+                       {
+                               outstr = sprintf(_("%s_Matches:"), strtoupper(gametype));
+                               data = sprintf(_("%d (unranked)"), stof(data));
+
+                               // unranked game modes ALWAYS get put last
+                               orderstr = "zzz";
+                       }
+                       else { continue; }
+               }
+
+               bufstr_add(me.listStats, sprintf("%s%s %s", orderstr, outstr, data), TRUE);
+       }
+
+       me.nItems = buf_getsize(me.listStats);
+       if(me.nItems > 0)
+               buf_sort(me.listStats, 128, FALSE);
+}
+
+void XonoticStatsList_destroy(entity me)
+{
+       if(me.nItems > 0)
+               buf_del(me.listStats);
+}
+
+void XonoticStatsList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemAbsSize = '0 0 0';
+       SUPER(XonoticStatsList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+
+       me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize_y * me.itemHeight));
+       me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize_x * (1 - me.controlWidth)));
+       me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+
+#if 0
+       me.columnNameOrigin = me.realFontSize_x;
+       me.columnNameSize = 0.5 - me.realFontSize_x; // end halfway at maximum length
+       me.columnDataOrigin = me.columnNameOrigin + me.columnNameSize;
+       me.columnDataSize = 1 - me.columnNameSize - me.realFontSize_x; // fill the rest of the control
+#else
+       me.columnNameOrigin = me.realFontSize_x;
+       me.columnNameSize = 1 - 2 * me.realFontSize_x;
+#endif
+}
+
+void XonoticStatsList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+       string data = bufstr_get(me.listStats, i);
+       string s = car(data);
+       string d = cdr(data);
+       
+       s = substring(s, 3, strlen(s) - 3);
+       s = strreplace("_", " ", s);
+       s = draw_TextShortenToWidth(s, 0.5 * me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 1);
+
+       d = draw_TextShortenToWidth(d, me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize), 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 1 * (me.columnNameSize - draw_TextWidth(d, 0, me.realFontSize))) * eX, d, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 1);
+}
+
+void XonoticStatsList_showNotify(entity me)
+{
+       PlayerStats_PlayerDetail_CheckUpdate();
+}
+
+void XonoticStatsList_clickListBoxItem(entity me, float i, vector where)
+{
+       if(i == me.lastClickedDemo)
+               if(time < me.lastClickedTime + 0.3)
+               {
+                       // DOUBLE CLICK!
+                       me.setSelected(me, i);
+                       //DemoConfirm_ListClick_Check_Gamestatus(me);
+               }
+       me.lastClickedDemo = i;
+       me.lastClickedTime = time;
+}
+
+float XonoticStatsList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if(scan == K_ENTER || scan == K_KP_ENTER)
+       {
+               //DemoConfirm_ListClick_Check_Gamestatus(me);
+               return 1;
+       }
+       else
+       {
+               return SUPER(XonoticStatsList).keyDown(me, scan, ascii, shift);
+       }
+}
+#endif
+
index 757e07ff1bc74e77408c5b22e364ea1727863275..c0e0806d83dc379e5276d48f2c30fc5a95ec3c0e 100644 (file)
@@ -17,6 +17,15 @@ entity makeXonoticTextLabel(float theAlign, string theText)
        me.configureXonoticTextLabel(me, theAlign, theText);
        return me;
 }
+entity makeXonoticHeaderLabel(string theText)
+{
+       entity me;
+       me = makeXonoticTextLabel(0.5, theText);
+       me.colorL = SKINCOLOR_HEADER;
+       me.alpha = SKINALPHA_HEADER;
+       me.isBold = TRUE;
+       return me;
+}
 void XonoticTextLabel_configureXonoticTextLabel(entity me, float theAlign, string theText)
 {
        me.configureLabel(me, theText, me.fontSize, theAlign);
index a4448f7debe19757ae7cc70ce21c3b61c0df3a8d..844b3efed531b4399d5cbce3bee17e01e37e1e70 100644 (file)
@@ -17,6 +17,7 @@ CLASS(XonoticTextSlider) EXTENDS(TextSlider)
        ATTRIB(XonoticTextSlider, cvarName, string, string_null)
        METHOD(XonoticTextSlider, loadCvars, void(entity))
        METHOD(XonoticTextSlider, saveCvars, void(entity))
+       ATTRIB(XonoticTextSlider, sendCvars, float, 0)
 
        ATTRIB(XonoticTextSlider, alpha, float, SKINALPHA_TEXT)
        ATTRIB(XonoticTextSlider, disabledAlpha, float, SKINALPHA_DISABLED)
@@ -84,6 +85,7 @@ void XonoticTextSlider_saveCvars(entity me)
                {
                        // this is a special case to allow spaces in the identifiers
                        cvar_set(argv(0), me.getIdentifier(me));
+                       CheckSendCvars(me, argv(0));
                }
                else
                {
@@ -92,12 +94,18 @@ void XonoticTextSlider_saveCvars(entity me)
                        if(m == n + 1)
                        {
                                for(i = 0; i < n; ++i)
+                               {
                                        cvar_set(argv(i), argv(n));
+                                       CheckSendCvars(me, argv(i));
+                               }
                        }
                        else if(m == n * 2)
                        {
                                for(i = 0; i < n; ++i)
+                               {
                                        cvar_set(argv(i), argv(i + n));
+                                       CheckSendCvars(me, argv(i));
+                               }
                        }
                        else
                                error("XonoticTextSlider: invalid identifier ", me.getIdentifier(me), " does not match cvar list ", me.cvarName);
index 7c46564f45f2d696196d9342c62c7260203549d7..cf4139fdeea9c51582fecfdd7d710fb9782b2abb 100644 (file)
@@ -92,6 +92,8 @@ void saveCvarsMulti(entity me)
                        cvar_set(substring(argv(i), 1, strlen(argv(i))), ((s == "0") ? "1" : "0"));
                else
                        cvar_set(argv(i), s);
+
+               CheckSendCvars(me, argv(i));
        }
 }
 void makeMulti(entity e, string otherCvars)
@@ -707,22 +709,6 @@ string GameType_GetIcon(float cnt)
        return "";
 }
 
-/*string GameType_GetTeams(float cnt) // poor implementation, later something else could be done that's better?
-{
-       float i = GameType_GetID(cnt);
-       string s = _MapInfo_GetDefaultEx(i);
-
-       if(i)
-       {
-               if(strstrofs(s, "teams", 0) >= 0)
-                       return _("teamplay");
-               else
-                       return _("free for all");
-       }
-
-       return _("tuba for all");
-}*/
-
 void dialog_hudpanel_common_notoggle(entity me, string panelname)
 {
        float i;
@@ -781,3 +767,15 @@ void dialog_hudpanel_common_notoggle(entity me, string panelname)
                                        e.addValue(e, strzone(ftos_decimals(i - 5, 0)), strzone(ftos(i - 5)));
                                e.configureXonoticTextSliderValues(e);
 }
+
+void CheckSendCvars(entity me, string cvarnamestring)
+{
+       if(me.sendCvars)
+       {
+               printf("Sending cvar: %s -> %s\n", cvarnamestring, cvar_string(cvarnamestring));
+               if(gamestatus & (GAME_CONNECTED | GAME_ISSERVER))
+               {
+                       cmd(sprintf("\nsendcvar %s\n", cvarnamestring));
+               }
+       }
+}
index 3371dd8114637a90a4735b7204c7e59d87047e08..33ecb8c4d4c984754975c1b3ea1d5a8267da1c77 100644 (file)
@@ -49,3 +49,5 @@ string _Nex_ExtResponseSystem_PromotedServers;
 float _Nex_ExtResponseSystem_PromotedServersNeedsRefresh;
 string _Nex_ExtResponseSystem_RecommendedServers;
 float _Nex_ExtResponseSystem_RecommendedServersNeedsRefresh;
+
+void CheckSendCvars(entity me, string cvarnamestring);
index f20f07047af715517e226dcad8c7f8090bedfc27..d3003d7c4656b5fad4268b08b054a276327b5201 100644 (file)
@@ -64,7 +64,6 @@ float autocvar_bot_wander_enable;
 float autocvar_captureleadlimit_override;
 #define autocvar_capturelimit_override cvar("capturelimit_override")
 #define autocvar_developer cvar("developer")
-float autocvar_developer_fteqccbugs;
 float autocvar_ekg;
 #define autocvar_fraglimit cvar("fraglimit")
 #define autocvar_fraglimit_override cvar("fraglimit_override")
@@ -447,7 +446,6 @@ float autocvar_g_pickup_shells_max;
 float autocvar_g_player_alpha;
 float autocvar_g_player_brightness;
 float autocvar_g_playerclip_collisions;
-string autocvar_g_playerstats_uri;
 float autocvar_g_powerups;
 float autocvar_g_projectiles_damage;
 float autocvar_g_projectiles_keep_owner;
index 143b2d18b82f6396948a08785d28e52b45b47c88..b1dccc7b5c3bc4e3e6517106fd7919eb5976f393 100644 (file)
@@ -165,7 +165,7 @@ void PutObserverInServer (void)
        if(self.alivetime)
        {
                if(!warmup_stage)
-                       PlayerStats_Event(self, PLAYERSTATS_ALIVETIME, time - self.alivetime);
+                       PS_GR_P_ADDVAL(self, PLAYERSTATS_ALIVETIME, time - self.alivetime);
                self.alivetime = 0;
        }
 
@@ -967,23 +967,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)
@@ -1047,6 +1030,8 @@ void ClientConnect (void)
                player_count = 0;
        }
 
+       if(IS_REAL_CLIENT(self)) { PlayerStats_PlayerBasic_CheckUpdate(self); }
+
        PlayerScore_Attach(self);
        ClientData_Attach();
        accuracy_init(self);
@@ -1125,10 +1110,10 @@ void ClientConnect (void)
 
        self.playerid = (playerid_last = playerid_last + 1);
 
-       PlayerStats_AddEvent(sprintf("kills-%d", self.playerid));
+       PlayerStats_GameReport_AddEvent(sprintf("kills-%d", self.playerid));
 
     if(IS_BOT_CLIENT(self))
-        PlayerStats_AddPlayer(self);
+        PlayerStats_GameReport_AddPlayer(self);
 
        if(autocvar_sv_eventlog)
                GameLogEcho(strcat(":join:", ftos(self.playerid), ":", ftos(num_for_edict(self)), ":", ((IS_REAL_CLIENT(self)) ? self.netaddress : "bot"), ":", self.netname));
@@ -1235,9 +1220,9 @@ void ClientDisconnect (void)
                return;
        }
 
-       if(IS_PLAYER(self)) { pointparticles(particleeffectnum("spawn_event_neutral"), self.origin, '0 0 0', 1); }
+       PlayerStats_GameReport_FinalizePlayer(self);
 
-       PlayerStats_AddGlobalInfo(self);
+       if(IS_PLAYER(self)) { pointparticles(particleeffectnum("spawn_event_neutral"), self.origin, '0 0 0', 1); }
 
        CheatShutdownClient();
 
index 913a5a037ff17daf31730201ec5b5ba1bac5c37b..1d47536608b3446f97663a2d4906b7091bb0412c 100644 (file)
@@ -1137,20 +1137,6 @@ void SV_PlayerPhysics()
                        self.jumppadcount = 0;
                }
 
-#ifdef LETS_TEST_FTEQCC
-               if(self.velocity_x || self.velocity_y)
-               {
-                       // good
-               }
-               else
-               {
-                       if(self.velocity_x)
-                               checkclient();
-                       if(self.velocity_y)
-                               checkclient();
-               }
-#endif
-
                v = self.velocity;
                v_z = 0;
                f = vlen(v);
index b96646dfb6f28ea5fb352e42f61ac70a6ce25497..17569147fb091d9e08f9ee4ea7e877287c69f34d 100644 (file)
@@ -502,7 +502,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht
 
                if(self.alivetime)
                {
-                       PlayerStats_Event(self, PLAYERSTATS_ALIVETIME, time - self.alivetime);
+                       PS_GR_P_ADDVAL(self, PLAYERSTATS_ALIVETIME, time - self.alivetime);
                        self.alivetime = 0;
                }
 
index ada537654e8818973dcbdaa94b447aa2ee6784d5..214083eaee9f32c080ad221512e3dfe39a28ba58 100644 (file)
@@ -425,7 +425,7 @@ void ReadyRestart_force()
        {
                tmp_player.alivetime = 0;
                tmp_player.killcount = 0;
-               PlayerStats_Event(tmp_player, PLAYERSTATS_ALIVETIME, -PlayerStats_Event(tmp_player, PLAYERSTATS_ALIVETIME, 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
index 14e524361574933419a563ab07240f7e70ac3a54..647030620b52cd5d470fcb67445d50da91850bae 100644 (file)
@@ -607,3 +607,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;
index 7c4b01c2d45ebae7b4b224bb561b9b764bf1aaab..4840e15dd25d6916239fb221de8fbd721d47cec0 100644 (file)
@@ -99,7 +99,7 @@ void GiveFrags (entity attacker, entity targ, float f, float deathtype)
                // regular frag
                PlayerScore_Add(attacker, SP_KILLS, 1);
                if(targ.playerid)
-                       PlayerStats_Event(attacker, sprintf("kills-%d", targ.playerid), 1);
+                       PS_GR_P_ADDVAL(attacker, sprintf("kills-%d", targ.playerid), 1);
        }
 
        PlayerScore_Add(targ, SP_DEATHS, 1);
@@ -419,7 +419,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, float deathtype)
                                case counta: \
                                { \
                                        Send_Notification(NOTIF_ONE, attacker, MSG_ANNCE, ANNCE_KILLSTREAK_##countb); \
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
+                                       PS_GR_P_ADDVAL(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
                                        break; \
                                }
                        switch(attacker.killcount)
@@ -433,8 +433,8 @@ void Obituary(entity attacker, entity inflictor, entity targ, float deathtype)
                        {
                                checkrules_firstblood = TRUE;
                                notif_firstblood = TRUE; // modify the current messages so that they too show firstblood information
-                               PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
-                               PlayerStats_Event(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
+                               PS_GR_P_ADDVAL(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
+                               PS_GR_P_ADDVAL(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
 
                                // tell spree_inf and spree_cen that this is a first-blood and first-victim event
                                kill_count_to_attacker = -1;
@@ -541,7 +541,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, float deathtype)
                if(PlayerScore_Add(targ, SP_SCORE, 0) == -5)
                {
                        Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_ACHIEVEMENT_BOTLIKE);
-                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
+                       PS_GR_P_ADDVAL(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
                }
        }
 
@@ -727,7 +727,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float
                                                                attacker.dmg_take += v_x;
                                                                attacker.dmg_save += v_y;
                                                                attacker.dmg_inflictor = inflictor;
-                                                               mirrordamage = v_z; // = 0, to make fteqcc stfu
+                                                               mirrordamage = v_z;
                                                                mirrorforce = 0;
                                                        }
 
index 019d0a2169dbfa0baea915e2a152e9e3b6af4fa7..f97a4254dff37f194d242f65119cfe6f55e624b8 100644 (file)
@@ -81,32 +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;
@@ -572,8 +546,6 @@ void spawnfunc_worldspawn (void)
 
        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();
@@ -647,7 +619,7 @@ void spawnfunc_worldspawn (void)
 
        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();
@@ -722,8 +694,6 @@ void spawnfunc_worldspawn (void)
        if(autocvar_g_campaign)
                CampaignPostInit();
 
-       fteqcc_testbugs();
-
        Ban_LoadBans();
 
        MapInfo_Enumerate();
@@ -1529,11 +1499,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
@@ -2339,8 +2305,6 @@ void RestoreGame()
 
 void Shutdown()
 {
-       entity e;
-
        gameover = 2;
 
        if(world_initialized > 0)
@@ -2349,10 +2313,8 @@ void Shutdown()
                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)
                {
index 3e1a86620314020cfe4ac7e6c8a61fd58480e377..9a2cb1871706d7cb40978ac6a805ef05b093ee7f 100644 (file)
@@ -543,12 +543,11 @@ void MapVote_Tick()
 
 void MapVote_Start()
 {
-       if(mapvote_run)
-               return;
+       // if mapvote is already running, don't do this initialization again
+       if(mapvote_run) { return; }
 
-       // wait for stats to be sent first
-       if(!playerstats_waitforme)
-               return;
+       // don't start mapvote until after playerstats gamereport is sent
+       if(PlayerStats_GameReport_DelayMapVote) { return; }
 
        MapInfo_Enumerate();
        if(MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1))
index 33010d174171b6b55e989669d3650e4b598b4caf..71294f1942affd51f53f1c37183a580a63d8122f 100644 (file)
@@ -526,7 +526,7 @@ void GetCvars(float f)
                if (s == "cl_weaponpriority")
                        self.switchweapon = w_getbestweapon(self);
                if (s == "cl_allow_uidtracking")
-                       PlayerStats_AddPlayer(self);
+                       PlayerStats_GameReport_AddPlayer(self);
        }
 }
 
@@ -797,11 +797,11 @@ void readplayerstartcvars()
 
        if(start_items & IT_UNLIMITED_WEAPON_AMMO)
        {
-               start_ammo_rockets = 999;
                start_ammo_shells = 999;
+               start_ammo_nails = 999;
+               start_ammo_rockets = 999;
                start_ammo_cells = 999;
                start_ammo_plasma = 999;
-               start_ammo_nails = 999;
                start_ammo_fuel = 999;
        }
        else
@@ -820,6 +820,7 @@ void readplayerstartcvars()
                warmup_start_ammo_nails = start_ammo_nails;
                warmup_start_ammo_rockets = start_ammo_rockets;
                warmup_start_ammo_cells = start_ammo_cells;
+               warmup_start_ammo_plasma = start_ammo_plasma;
                warmup_start_ammo_fuel = start_ammo_fuel;
                warmup_start_health = start_health;
                warmup_start_armorvalue = start_armorvalue;
@@ -830,9 +831,10 @@ void readplayerstartcvars()
                if (!g_weaponarena && !g_ca)
                {
                        warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
-                       warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
                        warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
                        warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
+                       warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
+                       warmup_start_ammo_plasma = cvar("g_warmup_start_ammo_plasma");
                        warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
                        warmup_start_health = cvar("g_warmup_start_health");
                        warmup_start_armorvalue = cvar("g_warmup_start_armor");
@@ -878,16 +880,16 @@ void readplayerstartcvars()
 
        start_ammo_shells = max(0, start_ammo_shells);
        start_ammo_nails = max(0, start_ammo_nails);
+       start_ammo_rockets = max(0, start_ammo_rockets);
        start_ammo_cells = max(0, start_ammo_cells);
        start_ammo_plasma = max(0, start_ammo_plasma);
-       start_ammo_rockets = max(0, start_ammo_rockets);
        start_ammo_fuel = max(0, start_ammo_fuel);
 
        warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
        warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
+       warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
        warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
        warmup_start_ammo_plasma = max(0, warmup_start_ammo_plasma);
-       warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
        warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
 }
 
index 41de5a1b2a56a66ef282d8280acd671441cd5f7f..4200b2207a9c5872def34c817b6efd3e772ae234 100644 (file)
@@ -289,12 +289,17 @@ MUTATOR_HOOKFUNCTION(instagib_PlayerDamage)
 
 MUTATOR_HOOKFUNCTION(instagib_SetStartItems)
 {
-       start_ammo_cells = cvar("g_instagib_ammo_start");
+       start_health       = warmup_start_health       = 100;
+       start_armorvalue   = warmup_start_armorvalue   = 0;
 
-       start_health = 100;
-       start_armorvalue = 0;
-       start_weapons = WEPSET_VAPORIZER;
-       warmup_start_weapons = WEPSET_VAPORIZER;
+       start_ammo_shells  = warmup_start_ammo_shells  = 0;
+       start_ammo_nails   = warmup_start_ammo_nails   = 0;
+       start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_instagib_ammo_start");
+       start_ammo_plasma  = warmup_start_ammo_plasma  = 0;
+       start_ammo_rockets = warmup_start_ammo_rockets = 0;
+       start_ammo_fuel    = warmup_start_ammo_fuel    = 0;
+
+       start_weapons = warmup_start_weapons = WEPSET_VAPORIZER;
        start_items |= IT_UNLIMITED_SUPERWEAPONS;
 
        return FALSE;
diff --git a/qcsrc/server/playerstats.qh b/qcsrc/server/playerstats.qh
deleted file mode 100644 (file)
index b950377..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-// time the player was alive and kicking
-const string PLAYERSTATS_ALIVETIME  = "alivetime";
-const string PLAYERSTATS_AVGLATENCY = "avglatency";
-const string PLAYERSTATS_WINS = "wins";
-const string PLAYERSTATS_MATCHES = "matches";
-const string PLAYERSTATS_JOINS = "joins";
-const string PLAYERSTATS_SCOREBOARD_VALID = "scoreboardvalid";
-const string PLAYERSTATS_RANK = "rank";
-const string PLAYERSTATS_SCOREBOARD_POS = "scoreboardpos";
-
-const string PLAYERSTATS_TOTAL = "total-";
-const string PLAYERSTATS_SCOREBOARD = "scoreboard-";
-
-const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_3 = "achievement-kill-spree-3";
-const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_5 = "achievement-kill-spree-5";
-const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_10 = "achievement-kill-spree-10";
-const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_15 = "achievement-kill-spree-15";
-const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_20 = "achievement-kill-spree-20";
-const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_25 = "achievement-kill-spree-25";
-const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_30 = "achievement-kill-spree-30";
-const string PLAYERSTATS_ACHIEVEMENT_BOTLIKE = "achievement-botlike";
-const string PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD = "achievement-firstblood";
-const string PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM = "achievement-firstvictim";
-
-// delay map switch until this is set
-float playerstats_waitforme;
-
-// call at initialization
-void PlayerStats_Init();
-
-// add a new player
-void PlayerStats_AddPlayer(entity e);
-
-// add a new team
-void PlayerStats_AddTeam(float t);
-
-// add a new event
-void PlayerStats_AddEvent(string event_id);
-
-// call on each event to track, or at player disconnect OR match end for "global stuff"
-float PlayerStats_Event(entity e, string event_id, float value);
-
-// add a team score
-float PlayerStats_TeamScore(float t, string event_id, float value);
-
-// call at game over
-void PlayerStats_Shutdown(); // send stats to the server
-
-// call this whenever a player leaves
-void PlayerStats_AddGlobalInfo(entity p);
-
-// call this at the end of the match
-void PlayerStats_EndMatch(float finished);
index 9cc8c9954de7f377264353159510ff2ffa9bc99d..78c0b091eb7ecf70205b4086adf96146084a73e9 100644 (file)
@@ -78,7 +78,7 @@ csqceffects.qc
 
 anticheat.qh
 cheats.qh
-playerstats.qh
+../common/playerstats.qh
 
 portals.qh
 
@@ -234,7 +234,7 @@ playerdemo.qc
 
 anticheat.qc
 cheats.qc
-playerstats.qc
+../common/playerstats.qc
 
 round_handler.qc
 
index 7b3742f0136c0367e58ad17306d3f62faaa0b710..620ce8ce50e3a4a38812ab85b38b8fc1b2c4b195 100644 (file)
@@ -88,7 +88,7 @@ void TeamScore_Spawn(float t, string name)
        Net_LinkEntity(ts, FALSE, 0, TeamScore_SendEntity);
        teamscorekeepers[t - 1] = ts;
        ++teamscores_entities_count;
-       PlayerStats_AddTeam(t);
+       PlayerStats_GameReport_AddTeam(t);
 }
 
 float TeamScore_AddToTeam(float t, float scorefield, float score)
@@ -157,8 +157,8 @@ void ScoreInfo_SetLabel_PlayerScore(float i, string label, float scoreflags)
        }
        if(label != "")
        {
-               PlayerStats_AddEvent(strcat(PLAYERSTATS_TOTAL, label));
-               PlayerStats_AddEvent(strcat(PLAYERSTATS_SCOREBOARD, label));
+               PlayerStats_GameReport_AddEvent(strcat(PLAYERSTATS_TOTAL, label));
+               PlayerStats_GameReport_AddEvent(strcat(PLAYERSTATS_SCOREBOARD, label));
        }
 }
 
@@ -173,8 +173,8 @@ void ScoreInfo_SetLabel_TeamScore(float i, string label, float scoreflags)
        }
        if(label != "")
        {
-               PlayerStats_AddEvent(strcat(PLAYERSTATS_TOTAL, label));
-               PlayerStats_AddEvent(strcat(PLAYERSTATS_SCOREBOARD, label));
+               PlayerStats_GameReport_AddEvent(strcat(PLAYERSTATS_TOTAL, label));
+               PlayerStats_GameReport_AddEvent(strcat(PLAYERSTATS_SCOREBOARD, label));
        }
 }
 
@@ -347,7 +347,7 @@ float PlayerScore_Add(entity player, float scorefield, float score)
                if(scores_label[scorefield] != "")
                        s.SendFlags |= pow(2, scorefield);
        if(!warmup_stage)
-               PlayerStats_Event(s.owner, strcat(PLAYERSTATS_TOTAL, scores_label[scorefield]), score);
+               PS_GR_P_ADDVAL(s.owner, strcat(PLAYERSTATS_TOTAL, scores_label[scorefield]), score);
        return (s.(scores[scorefield]) += score);
 }
 
@@ -914,7 +914,7 @@ void PlayerScore_PlayerStats(entity p)
        for(i = 0; i < MAX_SCORE; ++i)
                if(s.(scores[i]) != 0)
                        if(scores_label[i] != "")
-                               PlayerStats_Event(s.owner, strcat(PLAYERSTATS_SCOREBOARD, scores_label[i]), s.(scores[i]));
+                               PS_GR_P_ADDVAL(s.owner, strcat(PLAYERSTATS_SCOREBOARD, scores_label[i]), s.(scores[i]));
 }
 
 void PlayerScore_TeamStats(void)
@@ -930,6 +930,6 @@ void PlayerScore_TeamStats(void)
                        if(sk.(teamscores[i]) != 0)
                                if(teamscores_label[i] != "")
                                        // the +1 is important here!
-                                       PlayerStats_TeamScore(t+1, strcat(PLAYERSTATS_SCOREBOARD, teamscores_label[i]), sk.(teamscores[i]));
+                                       PS_GR_T_ADDVAL(t+1, strcat(PLAYERSTATS_SCOREBOARD, teamscores_label[i]), sk.(teamscores[i]));
        }
 }
index 5960b9f427fc3a459550dd0585fd8eacee686134..c26a4d295ea78cc9ab977d447f336ce7dbcd424f 100644 (file)
@@ -1,6 +1,7 @@
 entity scores_initialized; // non-world when scores labels/rules have been set
 .float scores[MAX_SCORE];
 .float teamscores[MAX_TEAMSCORE];
+.float scoreboard_pos;
 
 /**
  * Attaches a PlayerScore entity to a player. Use that in ClientConnect.
index 2e537b4a3428877827eb62376e29d1bdcfb7d4ad..03081ff4b1526e5f3cc0a486aec68f50c874ee23 100644 (file)
@@ -855,7 +855,7 @@ float commodity_pickupevalfunc(entity player, entity item)
                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?
index 09d42332ae51dbf408a4284fdbd7b947f0fb517b..8a7f4c5b061d76d93d29984777bc9f4881df60f3 100644 (file)
@@ -110,6 +110,7 @@ float accuracy_isgooddamage(entity attacker, entity targ)
 
        if(!warmup_stage)
        if(targ.deadflag == DEAD_NO)
+       if(!targ.frozen)
        if(mutator_check == MUT_ACCADD_INVALID || (mutator_check == MUT_ACCADD_VALID && IS_CLIENT(targ)))
        if(DIFF_TEAM(attacker, targ))
                return TRUE;
index 755ab59e593e4906319debced03fd205fb16ca8e..55e6d5415e154bf583c1f5892c485a336aea40b8 100644 (file)
@@ -290,7 +290,7 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f
                f = ExponentialFalloff(mindist, maxdist, halflifedist, ent.railgundistance);
                ffs = ExponentialFalloff(mindist, maxdist, forcehalflifedist, ent.railgundistance);
 
-               if(accuracy_isgooddamage(self.realowner, ent))
+               if(accuracy_isgooddamage(self, ent))
                        totaldmg += bdamage * f;
 
                // apply the damage
diff --git a/scripts/player_erebus.shader b/scripts/player_erebus.shader
new file mode 100644 (file)
index 0000000..1499ff1
--- /dev/null
@@ -0,0 +1,26 @@
+erebus
+{
+       dpreflectcube cubemaps/default/sky
+       {
+               map textures/erebus.tga
+               rgbgen lightingDiffuse
+       }
+}
+
+erebusfullbright
+{
+       dpreflectcube cubemaps/default/sky
+       {
+               map textures/erebusfullbright.tga
+               rgbgen lightingDiffuse
+       }
+}
+
+shadowhead
+{
+       dpreflectcube cubemaps/default/sky
+       {
+               map textures/shadowhead.tga
+               rgbgen lightingDiffuse
+       }
+}
diff --git a/scripts/player_gak.shader b/scripts/player_gak.shader
new file mode 100644 (file)
index 0000000..858a758
--- /dev/null
@@ -0,0 +1,17 @@
+gak
+{
+       dpreflectcube cubemaps/default/sky
+       {
+               map textures/gak.tga
+               rgbgen lightingDiffuse
+       }
+}
+
+gakarmor
+{
+       dpreflectcube cubemaps/default/sky
+       {
+               map textures/gakarmor.tga
+               rgbgen lightingDiffuse
+       }
+}
diff --git a/scripts/player_ignis.shader b/scripts/player_ignis.shader
new file mode 100644 (file)
index 0000000..5a14f12
--- /dev/null
@@ -0,0 +1,17 @@
+ignis
+{
+       dpreflectcube cubemaps/default/sky
+       {
+               map textures/ignis.tga
+               rgbgen lightingDiffuse
+       }
+}
+
+ignishead
+{
+       dpreflectcube cubemaps/default/sky
+       {
+               map textures/ignishead.tga
+               rgbgen lightingDiffuse
+       }
+}
diff --git a/scripts/player_nyx.shader b/scripts/player_nyx.shader
new file mode 100644 (file)
index 0000000..0f21b09
--- /dev/null
@@ -0,0 +1,9 @@
+nyx
+{
+       dpreflectcube cubemaps/default/sky
+       {
+               map textures/nyx.tga
+               rgbgen lightingDiffuse
+       }
+}
+
diff --git a/scripts/player_pyria.shader b/scripts/player_pyria.shader
new file mode 100644 (file)
index 0000000..49a54c6
--- /dev/null
@@ -0,0 +1,22 @@
+pyria
+{
+       dpreflectcube cubemaps/default/sky
+       {
+               map textures/pyria.tga
+               rgbgen lightingDiffuse
+       }
+}
+
+pyriahair
+{
+
+       surfaceparm trans
+       cull none
+
+       {
+               map textures/pyriahair
+               alphaFunc GE128
+               blendFunc blend
+               rgbGen identity
+       }
+}
diff --git a/scripts/player_seraphina.shader b/scripts/player_seraphina.shader
new file mode 100644 (file)
index 0000000..af5062d
--- /dev/null
@@ -0,0 +1,8 @@
+seraphina
+{
+       dpreflectcube cubemaps/default/sky
+       {
+               map textures/seraphina.tga
+               rgbgen lightingDiffuse
+       }
+}
diff --git a/scripts/player_umbra.shader b/scripts/player_umbra.shader
new file mode 100644 (file)
index 0000000..3f4b5ed
--- /dev/null
@@ -0,0 +1,9 @@
+umbra
+{
+       dpreflectcube cubemaps/default/sky
+       {
+               map textures/umbra.tga
+               rgbgen lightingDiffuse
+       }
+}
+
diff --git a/scripts/pyria.shader b/scripts/pyria.shader
deleted file mode 100644 (file)
index 8cc0385..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-pyriahair
-{
-
-       surfaceparm trans
-       cull none
-
-       {
-               map textures/pyriahair
-               alphaFunc GE128
-               blendFunc blend
-               rgbGen identity
-       }
-}
diff --git a/textures/erebus_reflect.tga b/textures/erebus_reflect.tga
new file mode 100644 (file)
index 0000000..66974f7
Binary files /dev/null and b/textures/erebus_reflect.tga differ
diff --git a/textures/erebusfullbright_reflect.tga b/textures/erebusfullbright_reflect.tga
new file mode 100644 (file)
index 0000000..e825195
Binary files /dev/null and b/textures/erebusfullbright_reflect.tga differ
diff --git a/textures/gak_reflect.tga b/textures/gak_reflect.tga
new file mode 100644 (file)
index 0000000..1f9ed2f
Binary files /dev/null and b/textures/gak_reflect.tga differ
diff --git a/textures/gakarmor_reflect.tga b/textures/gakarmor_reflect.tga
new file mode 100644 (file)
index 0000000..c486aed
Binary files /dev/null and b/textures/gakarmor_reflect.tga differ
diff --git a/textures/ignis_reflect.tga b/textures/ignis_reflect.tga
new file mode 100644 (file)
index 0000000..df8e31d
Binary files /dev/null and b/textures/ignis_reflect.tga differ
diff --git a/textures/ignishead_reflect.tga b/textures/ignishead_reflect.tga
new file mode 100644 (file)
index 0000000..2f3fa94
Binary files /dev/null and b/textures/ignishead_reflect.tga differ
diff --git a/textures/nyx_reflect.tga b/textures/nyx_reflect.tga
new file mode 100644 (file)
index 0000000..aecf3e0
Binary files /dev/null and b/textures/nyx_reflect.tga differ
diff --git a/textures/pyria_reflect.jpg b/textures/pyria_reflect.jpg
new file mode 100644 (file)
index 0000000..219469c
Binary files /dev/null and b/textures/pyria_reflect.jpg differ
diff --git a/textures/seraphina_reflect.jpg b/textures/seraphina_reflect.jpg
new file mode 100644 (file)
index 0000000..7b2fb4c
Binary files /dev/null and b/textures/seraphina_reflect.jpg differ
diff --git a/textures/shadowhead_reflect.tga b/textures/shadowhead_reflect.tga
new file mode 100644 (file)
index 0000000..f22a578
Binary files /dev/null and b/textures/shadowhead_reflect.tga differ
diff --git a/textures/umbra_reflect.jpg b/textures/umbra_reflect.jpg
new file mode 100644 (file)
index 0000000..c1fa10e
Binary files /dev/null and b/textures/umbra_reflect.jpg differ