From: Mario Date: Tue, 16 Dec 2014 03:36:30 +0000 (+1100) Subject: Merge branch 'master' into Mario/overkill X-Git-Tag: xonotic-v0.8.0~70^2~9 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=5dbda91e68e08abcedef699f99c3654c8f97242b;hp=47c02cec495b4188dfc122b77393429ae257e14b Merge branch 'master' into Mario/overkill --- diff --git a/balance-xpm.cfg b/balance-xpm.cfg index d12637da71..c254bcdf8d 100644 --- a/balance-xpm.cfg +++ b/balance-xpm.cfg @@ -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 index 0000000000..f48842f8cd --- /dev/null +++ b/binds-default.cfg @@ -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 index 0000000000..31a33d77d0 --- /dev/null +++ b/binds-empty-special.cfg @@ -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 index 0000000000..51112bfa05 --- /dev/null +++ b/binds-empty.cfg @@ -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 diff --git a/crosshairs.cfg b/crosshairs.cfg index c94d3a5fb7..52ae30cb5b 100644 --- a/crosshairs.cfg +++ b/crosshairs.cfg @@ -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 diff --git a/defaultXonotic.cfg b/defaultXonotic.cfg index 8fe7f7d94a..2939ddf98d 100644 --- a/defaultXonotic.cfg +++ b/defaultXonotic.cfg @@ -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 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" diff --git a/effects-med.cfg b/effects-med.cfg index 75f7250bd9..84df44948e 100644 --- a/effects-med.cfg +++ b/effects-med.cfg @@ -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 diff --git a/effects-normal.cfg b/effects-normal.cfg index b1a967509e..27756437ef 100644 --- a/effects-normal.cfg +++ b/effects-normal.cfg @@ -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 diff --git a/gamemodes.cfg b/gamemodes.cfg index c31f7f9013..b6cbe92cfc 100644 --- a/gamemodes.cfg +++ b/gamemodes.cfg @@ -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" diff --git a/gfx/menu/luminos/skinvalues.txt b/gfx/menu/luminos/skinvalues.txt index 025475ab74..dcab8a45e1 100755 --- a/gfx/menu/luminos/skinvalues.txt +++ b/gfx/menu/luminos/skinvalues.txt @@ -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' diff --git a/gfx/menu/wickedx/skinvalues.txt b/gfx/menu/wickedx/skinvalues.txt old mode 100755 new mode 100644 index c5062d91a1..94eb09aaa6 --- a/gfx/menu/wickedx/skinvalues.txt +++ b/gfx/menu/wickedx/skinvalues.txt @@ -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' diff --git a/gfx/menu/xaw/skinvalues.txt b/gfx/menu/xaw/skinvalues.txt index 2dc86f698f..6cf666fce5 100644 --- a/gfx/menu/xaw/skinvalues.txt +++ b/gfx/menu/xaw/skinvalues.txt @@ -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' diff --git a/keybinds.txt b/keybinds.txt index 95d24acdbd..0458a548f0 100644 --- a/keybinds.txt +++ b/keybinds.txt @@ -17,15 +17,15 @@ "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" diff --git a/keybinds.txt.de b/keybinds.txt.de index 85d34b9572..9a6d9e9827 100644 --- a/keybinds.txt.de +++ b/keybinds.txt.de @@ -17,15 +17,15 @@ "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" diff --git a/keybinds.txt.es b/keybinds.txt.es index 0c3b8364c2..e7c2fd7441 100644 --- a/keybinds.txt.es +++ b/keybinds.txt.es @@ -17,15 +17,15 @@ "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" diff --git a/keybinds.txt.fr b/keybinds.txt.fr index 17ac954093..09ee3e3e77 100644 --- a/keybinds.txt.fr +++ b/keybinds.txt.fr @@ -19,11 +19,11 @@ "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" diff --git a/keybinds.txt.hu b/keybinds.txt.hu index c4e418d120..53bd46c143 100644 --- a/keybinds.txt.hu +++ b/keybinds.txt.hu @@ -19,11 +19,11 @@ "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ó" diff --git a/keybinds.txt.it b/keybinds.txt.it index e46ef92440..8546bdbe8f 100644 --- a/keybinds.txt.it +++ b/keybinds.txt.it @@ -17,15 +17,15 @@ "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" diff --git a/keybinds.txt.ru b/keybinds.txt.ru index 3431c25f67..3ca70768e2 100644 --- a/keybinds.txt.ru +++ b/keybinds.txt.ru @@ -17,13 +17,13 @@ "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" diff --git a/keybinds.txt.uk b/keybinds.txt.uk index eae9049c1d..8fc522a82d 100644 --- a/keybinds.txt.uk +++ b/keybinds.txt.uk @@ -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" "Крайлінк / ВЛШГ" diff --git a/mutators.cfg b/mutators.cfg index adfcd24052..e8221b4f08 100644 --- a/mutators.cfg +++ b/mutators.cfg @@ -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 // ========= diff --git a/qcsrc/Makefile b/qcsrc/Makefile index edac7388c1..9fde71e103 100644 --- a/qcsrc/Makefile +++ b/qcsrc/Makefile @@ -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) diff --git a/qcsrc/client/Main.qc b/qcsrc/client/Main.qc index d1fe46d235..58bd4f4974 100644 --- a/qcsrc/client/Main.qc +++ b/qcsrc/client/Main.qc @@ -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); diff --git a/qcsrc/client/View.qc b/qcsrc/client/View.qc index 120b682a30..0a5f73b55f 100644 --- a/qcsrc/client/View.qc +++ b/qcsrc/client/View.qc @@ -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) { diff --git a/qcsrc/client/autocvars.qh b/qcsrc/client/autocvars.qh index 90a74a905b..f06c5bfb3b 100644 --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@ -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; diff --git a/qcsrc/client/hud.qc b/qcsrc/client/hud.qc index 216940009d..ea126f9d6d 100644 --- a/qcsrc/client/hud.qc +++ b/qcsrc/client/hud.qc @@ -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), diff --git a/qcsrc/client/progs.src b/qcsrc/client/progs.src index 90f445c517..c21726b4dc 100644 --- a/qcsrc/client/progs.src +++ b/qcsrc/client/progs.src @@ -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 diff --git a/qcsrc/client/sys-pre.qh b/qcsrc/client/sys-pre.qh index 8ebe91903b..2f59e713d3 100644 --- a/qcsrc/client/sys-pre.qh +++ b/qcsrc/client/sys-pre.qh @@ -1,7 +1,3 @@ -#ifdef USE_FTE -#pragma target FTE -#endif - #define CSQC #define ATTEN_NORM builtin_ATTEN_NORM diff --git a/qcsrc/client/weapons/projectile.qc b/qcsrc/client/weapons/projectile.qc index ec5b99d73b..fe047e390e 100644 --- a/qcsrc/client/weapons/projectile.qc +++ b/qcsrc/client/weapons/projectile.qc @@ -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 diff --git a/qcsrc/common/counting.qh b/qcsrc/common/counting.qh index 2559bf3acd..1413a80902 100644 --- a/qcsrc/common/counting.qh +++ b/qcsrc/common/counting.qh @@ -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; } } diff --git a/qcsrc/common/mapinfo.qc b/qcsrc/common/mapinfo.qc index ba1fbeb6f4..2230d5c790 100644 --- a/qcsrc/common/mapinfo.qc +++ b/qcsrc/common/mapinfo.qc @@ -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; diff --git a/qcsrc/common/mapinfo.qh b/qcsrc/common/mapinfo.qh index 60cd26017d..bbcc267b2b 100644 --- a/qcsrc/common/mapinfo.qh +++ b/qcsrc/common/mapinfo.qh @@ -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); diff --git a/qcsrc/common/notifications.qh b/qcsrc/common/notifications.qh index dc47dd3ae4..3774475484 100644 --- a/qcsrc/common/notifications.qh +++ b/qcsrc/common/notifications.qh @@ -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 index 0000000000..813f966be0 --- /dev/null +++ b/qcsrc/common/playerstats.qc @@ -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-: total score of that scoreboard item + * scoreboard-: end-of-game score of that scoreboard item (can differ in non-team games) + * achievement-: achievement counters (their "count" is usually 1 if nonzero at all) + * kills-: number of kills against the indexed player + * rank : rank of player + * acc--hit: total damage dealt + * acc--fired: total damage that all fired projectiles *could* have dealt + * acc--cnt-hit: amount of shots that actually hit + * acc--cnt-fired: amount of fired shots + * acc--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 index 0000000000..26a1efc28c --- /dev/null +++ b/qcsrc/common/playerstats.qh @@ -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 diff --git a/qcsrc/common/util-pre.qh b/qcsrc/common/util-pre.qh index 4e8e1b59c8..3f4c3e57f4 100644 --- a/qcsrc/common/util-pre.qh +++ b/qcsrc/common/util-pre.qh @@ -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 diff --git a/qcsrc/common/util.qc b/qcsrc/common/util.qc index 15cde708ab..671c8d5a59 100644 --- a/qcsrc/common/util.qc +++ b/qcsrc/common/util.qc @@ -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) diff --git a/qcsrc/common/util.qh b/qcsrc/common/util.qh index 61b9ad0e2b..14dd59d048 100644 --- a/qcsrc/common/util.qh +++ b/qcsrc/common/util.qh @@ -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 index dd4fd45f3c..0000000000 --- a/qcsrc/fteqcc-bugs.qc +++ /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)); -} diff --git a/qcsrc/menu/classes.c b/qcsrc/menu/classes.c index 46d0c0269e..bc60898c88 100644 --- a/qcsrc/menu/classes.c +++ b/qcsrc/menu/classes.c @@ -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" @@ -34,13 +35,13 @@ #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" @@ -80,15 +80,24 @@ #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" @@ -114,3 +123,5 @@ #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" diff --git a/qcsrc/menu/item/image.c b/qcsrc/menu/item/image.c index a7e63b0e11..8d1a6de86a 100644 --- a/qcsrc/menu/item/image.c +++ b/qcsrc/menu/item/image.c @@ -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) { diff --git a/qcsrc/menu/item/listbox.c b/qcsrc/menu/item/listbox.c index 0f9502d97f..d4eaab2a7b 100644 --- a/qcsrc/menu/item/listbox.c +++ b/qcsrc/menu/item/listbox.c @@ -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? { diff --git a/qcsrc/menu/item/slider.c b/qcsrc/menu/item/slider.c index b071a1af34..c92db27e98 100644 --- a/qcsrc/menu/item/slider.c +++ b/qcsrc/menu/item/slider.c @@ -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)); diff --git a/qcsrc/menu/item/textslider.c b/qcsrc/menu/item/textslider.c index 37aaeb4ab1..59d8c10db5 100644 --- a/qcsrc/menu/item/textslider.c +++ b/qcsrc/menu/item/textslider.c @@ -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) diff --git a/qcsrc/menu/menu.qc b/qcsrc/menu/menu.qc index b17e91f867..0926458bf3 100644 --- a/qcsrc/menu/menu.qc +++ b/qcsrc/menu/menu.qc @@ -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 diff --git a/qcsrc/menu/progs.src b/qcsrc/menu/progs.src index 9d2f693330..79b0f9023c 100644 --- a/qcsrc/menu/progs.src +++ b/qcsrc/menu/progs.src @@ -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 diff --git a/qcsrc/menu/skin-customizables.inc b/qcsrc/menu/skin-customizables.inc index 6583898bc7..1db6e6775d 100644 --- a/qcsrc/menu/skin-customizables.inc +++ b/qcsrc/menu/skin-customizables.inc @@ -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'); diff --git a/qcsrc/menu/xonotic/checkbox.c b/qcsrc/menu/xonotic/checkbox.c index b1a1af1966..631a430dcc 100644 --- a/qcsrc/menu/xonotic/checkbox.c +++ b/qcsrc/menu/xonotic/checkbox.c @@ -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 diff --git a/qcsrc/menu/xonotic/checkbox_string.c b/qcsrc/menu/xonotic/checkbox_string.c index ecafefed64..aeda757f0e 100644 --- a/qcsrc/menu/xonotic/checkbox_string.c +++ b/qcsrc/menu/xonotic/checkbox_string.c @@ -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 diff --git a/qcsrc/menu/xonotic/demolist.c b/qcsrc/menu/xonotic/demolist.c index cf0e987c0a..f2e209ca4d 100644 --- a/qcsrc/menu/xonotic/demolist.c +++ b/qcsrc/menu/xonotic/demolist.c @@ -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 diff --git a/qcsrc/menu/xonotic/dialog_multiplayer.c b/qcsrc/menu/xonotic/dialog_multiplayer.c index 2c86f79c38..7d234c7fe8 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer.c @@ -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 diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create.c b/qcsrc/menu/xonotic/dialog_multiplayer_create.c index e4aa1d6d97..8ae9107a9a 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_create.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_create.c @@ -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 index e6fffe0936..0000000000 --- a/qcsrc/menu/xonotic/dialog_multiplayer_create_advanced.c +++ /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 diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c b/qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c index e5dec8fff5..9baf36127d 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c @@ -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:"))); diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c b/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c index c276a2cd2e..9e8969ac0f 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c @@ -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 index da85975de9..0000000000 --- a/qcsrc/menu/xonotic/dialog_multiplayer_demo.c +++ /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 diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join.c b/qcsrc/menu/xonotic/dialog_multiplayer_join.c index 91326ad2d5..4636ebbdbb 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_join.c +++ b/qcsrc/menu/xonotic/dialog_multiplayer_join.c @@ -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 index 0000000000..9c47ef58d5 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_multiplayer_media.c @@ -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 index 0000000000..092355126f --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_multiplayer_media_demo.c @@ -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 index 0000000000..a5a97c5503 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.c @@ -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 index 0000000000..5510710c2c --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.c @@ -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 index 0000000000..6132719db6 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.c @@ -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 index 0000000000..146f496be9 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.c @@ -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 index fd4e5cd19b..0000000000 --- a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup.c +++ /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 index c4cdc3e705..0000000000 --- a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_crosshair.c +++ /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 index 8d969fd7a3..0000000000 --- a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_hud.c +++ /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 index 7749a148d9..0000000000 --- a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_hudconfirm.c +++ /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 index d1cdade772..0000000000 --- a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_model.c +++ /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 index b2b440a1c4..0000000000 --- a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_view.c +++ /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 index cfdaf8fdfc..0000000000 --- a/qcsrc/menu/xonotic/dialog_multiplayer_playersetup_weapons.c +++ /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 index 0000000000..a316be73b2 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_multiplayer_profile.c @@ -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 diff --git a/qcsrc/menu/xonotic/dialog_settings.c b/qcsrc/menu/xonotic/dialog_settings.c index 930fa7df97..f7003b44d1 100644 --- a/qcsrc/menu/xonotic/dialog_settings.c +++ b/qcsrc/menu/xonotic/dialog_settings.c @@ -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 diff --git a/qcsrc/menu/xonotic/dialog_settings_audio.c b/qcsrc/menu/xonotic/dialog_settings_audio.c index f3c27915e7..4db408c738 100644 --- a/qcsrc/menu/xonotic/dialog_settings_audio.c +++ b/qcsrc/menu/xonotic/dialog_settings_audio.c @@ -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 diff --git a/qcsrc/menu/xonotic/dialog_settings_effects.c b/qcsrc/menu/xonotic/dialog_settings_effects.c index c56d972d9d..f6b79eb8f3 100644 --- a/qcsrc/menu/xonotic/dialog_settings_effects.c +++ b/qcsrc/menu/xonotic/dialog_settings_effects.c @@ -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 index 0000000000..b75c1ac49a --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_settings_game.c @@ -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 index 0000000000..3e164c11fe --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_settings_game_crosshair.c @@ -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 index 0000000000..fc7e3a136a --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_settings_game_hud.c @@ -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 index 0000000000..7749a148d9 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.c @@ -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 index 0000000000..6f605ccbcb --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_settings_game_messages.c @@ -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 index 0000000000..c2aedc1f7e --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_settings_game_model.c @@ -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 index 0000000000..3fd451265a --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_settings_game_view.c @@ -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 index 0000000000..bc7cc7d7ff --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_settings_game_weapons.c @@ -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 diff --git a/qcsrc/menu/xonotic/dialog_settings_input.c b/qcsrc/menu/xonotic/dialog_settings_input.c index d8554be4f7..4287f1f82e 100644 --- a/qcsrc/menu/xonotic/dialog_settings_input.c +++ b/qcsrc/menu/xonotic/dialog_settings_input.c @@ -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 diff --git a/qcsrc/menu/xonotic/dialog_settings_misc.c b/qcsrc/menu/xonotic/dialog_settings_misc.c index c14a47c9c1..1deda87df0 100644 --- a/qcsrc/menu/xonotic/dialog_settings_misc.c +++ b/qcsrc/menu/xonotic/dialog_settings_misc.c @@ -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 diff --git a/qcsrc/menu/xonotic/dialog_settings_misc_cvars.c b/qcsrc/menu/xonotic/dialog_settings_misc_cvars.c index f511ec361c..c2ea2a5b66 100644 --- a/qcsrc/menu/xonotic/dialog_settings_misc_cvars.c +++ b/qcsrc/menu/xonotic/dialog_settings_misc_cvars.c @@ -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 index 0000000000..8f6da0a552 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_settings_misc_reset.c @@ -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 diff --git a/qcsrc/menu/xonotic/dialog_settings_user.c b/qcsrc/menu/xonotic/dialog_settings_user.c index 5d6a32d563..b3f888594e 100644 --- a/qcsrc/menu/xonotic/dialog_settings_user.c +++ b/qcsrc/menu/xonotic/dialog_settings_user.c @@ -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 diff --git a/qcsrc/menu/xonotic/dialog_settings_video.c b/qcsrc/menu/xonotic/dialog_settings_video.c index db728d6014..a4e8434136 100644 --- a/qcsrc/menu/xonotic/dialog_settings_video.c +++ b/qcsrc/menu/xonotic/dialog_settings_video.c @@ -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); diff --git a/qcsrc/menu/xonotic/gametypelist.c b/qcsrc/menu/xonotic/gametypelist.c index 8883e8bbe4..c7f385761d 100644 --- a/qcsrc/menu/xonotic/gametypelist.c +++ b/qcsrc/menu/xonotic/gametypelist.c @@ -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) diff --git a/qcsrc/menu/xonotic/inputbox.c b/qcsrc/menu/xonotic/inputbox.c index 78bab2bccb..5d7d179995 100644 --- a/qcsrc/menu/xonotic/inputbox.c +++ b/qcsrc/menu/xonotic/inputbox.c @@ -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) { diff --git a/qcsrc/menu/xonotic/keybinder.c b/qcsrc/menu/xonotic/keybinder.c index 57f501f5c1..c312e38265 100644 --- a/qcsrc/menu/xonotic/keybinder.c +++ b/qcsrc/menu/xonotic/keybinder.c @@ -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) diff --git a/qcsrc/menu/xonotic/mainwindow.c b/qcsrc/menu/xonotic/mainwindow.c index dcc4a8a817..6fa40bfac6 100644 --- a/qcsrc/menu/xonotic/mainwindow.c +++ b/qcsrc/menu/xonotic/mainwindow.c @@ -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 index 0000000000..469f177fc6 --- /dev/null +++ b/qcsrc/menu/xonotic/screenshotimage.c @@ -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 index 0000000000..dd8b61ed3f --- /dev/null +++ b/qcsrc/menu/xonotic/screenshotlist.c @@ -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 "." 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 diff --git a/qcsrc/menu/xonotic/serverlist.c b/qcsrc/menu/xonotic/serverlist.c index ed68acd713..8b3a9e9a03 100644 --- a/qcsrc/menu/xonotic/serverlist.c +++ b/qcsrc/menu/xonotic/serverlist.c @@ -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) { diff --git a/qcsrc/menu/xonotic/slider.c b/qcsrc/menu/xonotic/slider.c index aba15ecae6..d63fe1c336 100644 --- a/qcsrc/menu/xonotic/slider.c +++ b/qcsrc/menu/xonotic/slider.c @@ -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 index 0000000000..39f91f933c --- /dev/null +++ b/qcsrc/menu/xonotic/slider_sbfadetime.c @@ -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 index 0000000000..988244816c --- /dev/null +++ b/qcsrc/menu/xonotic/statslist.c @@ -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 + diff --git a/qcsrc/menu/xonotic/textlabel.c b/qcsrc/menu/xonotic/textlabel.c index 757e07ff1b..c0e0806d83 100644 --- a/qcsrc/menu/xonotic/textlabel.c +++ b/qcsrc/menu/xonotic/textlabel.c @@ -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); diff --git a/qcsrc/menu/xonotic/textslider.c b/qcsrc/menu/xonotic/textslider.c index a4448f7deb..844b3efed5 100644 --- a/qcsrc/menu/xonotic/textslider.c +++ b/qcsrc/menu/xonotic/textslider.c @@ -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); diff --git a/qcsrc/menu/xonotic/util.qc b/qcsrc/menu/xonotic/util.qc index 7c46564f45..cf4139fdee 100644 --- a/qcsrc/menu/xonotic/util.qc +++ b/qcsrc/menu/xonotic/util.qc @@ -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)); + } + } +} diff --git a/qcsrc/menu/xonotic/util.qh b/qcsrc/menu/xonotic/util.qh index 3371dd8114..33ecb8c4d4 100644 --- a/qcsrc/menu/xonotic/util.qh +++ b/qcsrc/menu/xonotic/util.qh @@ -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); diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index f20f07047a..d3003d7c46 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -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; diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index 143b2d18b8..b1dccc7b5c 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -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(); diff --git a/qcsrc/server/cl_physics.qc b/qcsrc/server/cl_physics.qc index 913a5a037f..1d47536608 100644 --- a/qcsrc/server/cl_physics.qc +++ b/qcsrc/server/cl_physics.qc @@ -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); diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index b96646dfb6..17569147fb 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -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; } diff --git a/qcsrc/server/command/vote.qc b/qcsrc/server/command/vote.qc index ada537654e..214083eaee 100644 --- a/qcsrc/server/command/vote.qc +++ b/qcsrc/server/command/vote.qc @@ -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 diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index 14e5243615..647030620b 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -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; diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index 7c4b01c2d4..4840e15dd2 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -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; } diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index 019d0a2169..f97a4254df 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -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) { diff --git a/qcsrc/server/mapvoting.qc b/qcsrc/server/mapvoting.qc index 3e1a866203..9a2cb18717 100644 --- a/qcsrc/server/mapvoting.qc +++ b/qcsrc/server/mapvoting.qc @@ -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)) diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index 33010d1741..71294f1942 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -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); } diff --git a/qcsrc/server/mutators/mutator_instagib.qc b/qcsrc/server/mutators/mutator_instagib.qc index 41de5a1b2a..4200b2207a 100644 --- a/qcsrc/server/mutators/mutator_instagib.qc +++ b/qcsrc/server/mutators/mutator_instagib.qc @@ -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 index b95037747b..0000000000 --- a/qcsrc/server/playerstats.qh +++ /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); diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index 9cc8c9954d..78c0b091eb 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -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 diff --git a/qcsrc/server/scores.qc b/qcsrc/server/scores.qc index 7b3742f013..620ce8ce50 100644 --- a/qcsrc/server/scores.qc +++ b/qcsrc/server/scores.qc @@ -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])); } } diff --git a/qcsrc/server/scores.qh b/qcsrc/server/scores.qh index 5960b9f427..c26a4d295e 100644 --- a/qcsrc/server/scores.qh +++ b/qcsrc/server/scores.qh @@ -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. diff --git a/qcsrc/server/t_items.qc b/qcsrc/server/t_items.qc index 2e537b4a34..03081ff4b1 100644 --- a/qcsrc/server/t_items.qc +++ b/qcsrc/server/t_items.qc @@ -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? diff --git a/qcsrc/server/weapons/accuracy.qc b/qcsrc/server/weapons/accuracy.qc index 09d42332ae..8a7f4c5b06 100644 --- a/qcsrc/server/weapons/accuracy.qc +++ b/qcsrc/server/weapons/accuracy.qc @@ -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; diff --git a/qcsrc/server/weapons/tracing.qc b/qcsrc/server/weapons/tracing.qc index 755ab59e59..55e6d5415e 100644 --- a/qcsrc/server/weapons/tracing.qc +++ b/qcsrc/server/weapons/tracing.qc @@ -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 index 0000000000..1499ff1a01 --- /dev/null +++ b/scripts/player_erebus.shader @@ -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 index 0000000000..858a758c6e --- /dev/null +++ b/scripts/player_gak.shader @@ -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 index 0000000000..5a14f12ee6 --- /dev/null +++ b/scripts/player_ignis.shader @@ -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 index 0000000000..0f21b09f00 --- /dev/null +++ b/scripts/player_nyx.shader @@ -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 index 0000000000..49a54c6bee --- /dev/null +++ b/scripts/player_pyria.shader @@ -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 index 0000000000..af5062d1f6 --- /dev/null +++ b/scripts/player_seraphina.shader @@ -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 index 0000000000..3f4b5ed1b8 --- /dev/null +++ b/scripts/player_umbra.shader @@ -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 index 8cc03850f4..0000000000 --- a/scripts/pyria.shader +++ /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 index 0000000000..66974f7448 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 index 0000000000..e825195ef5 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 index 0000000000..1f9ed2f11d 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 index 0000000000..c486aeddb3 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 index 0000000000..df8e31d552 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 index 0000000000..2f3fa9465c 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 index 0000000000..aecf3e0489 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 index 0000000000..219469cb38 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 index 0000000000..7b2fb4c950 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 index 0000000000..f22a578ffe 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 index 0000000000..c1fa10ec13 Binary files /dev/null and b/textures/umbra_reflect.jpg differ