From b41b6505ce8ba88ffaec5025bca59b0d31a76330 Mon Sep 17 00:00:00 2001 From: Juhu <> Date: Wed, 29 Apr 2020 18:01:54 +0200 Subject: [PATCH] Adding StrafeHUD for Xonotic --- _hud_common.cfg | 27 ++ _hud_descriptions.cfg | 9 + hud_luma.cfg | 9 + hud_luminos.cfg | 9 + hud_luminos_minimal.cfg | 9 + hud_luminos_minimal_xhair.cfg | 9 + hud_luminos_old.cfg | 9 + hud_nexuiz.cfg | 9 + qcsrc/client/autocvars.qh | 26 + qcsrc/client/hud/hud.qh | 1 + qcsrc/client/hud/panel/_mod.inc | 1 + qcsrc/client/hud/panel/_mod.qh | 1 + qcsrc/client/hud/panel/strafehud.qc | 459 ++++++++++++++++++ qcsrc/client/hud/panel/strafehud.qh | 2 + qcsrc/menu/xonotic/_mod.inc | 1 + qcsrc/menu/xonotic/_mod.qh | 1 + .../menu/xonotic/dialog_hudpanel_strafehud.qc | 105 ++++ .../menu/xonotic/dialog_hudpanel_strafehud.qh | 13 + qcsrc/menu/xonotic/mainwindow.qc | 5 + 19 files changed, 705 insertions(+) create mode 100644 qcsrc/client/hud/panel/strafehud.qc create mode 100644 qcsrc/client/hud/panel/strafehud.qh create mode 100644 qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc create mode 100644 qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qh diff --git a/_hud_common.cfg b/_hud_common.cfg index 0479f389b..a0f0c8a29 100644 --- a/_hud_common.cfg +++ b/_hud_common.cfg @@ -47,6 +47,7 @@ seta hud_panel_itemstime 2 "enable this panel, 1 = show when spectating, //seta hud_panel_scoreboard 1 "enable this panel" seta hud_panel_scoreboard_accuracy 1 "show weapon accuracy stats panel on scoreboard; colors can be configured with accuracy_color* cvars" seta hud_panel_scoreboard_ctf_leaderboard 1 "show a capture time rankings leaderboard in the scoreboard if allowed by the server" +seta hud_panel_strafehud 0 "enable this panel, 1 = show if not observing, 2 = show always, 3 = show only in race/cts if not observing" seta hud_panel_weapons_dynamichud 1 "apply the dynamic hud effects to this panel" seta hud_panel_ammo_dynamichud 1 "apply the dynamic hud effects to this panel" @@ -66,6 +67,7 @@ seta hud_panel_physics_dynamichud 1 "apply the dynamic hud effects to t seta hud_panel_centerprint_dynamichud 1 "apply the dynamic hud effects to this panel" seta hud_panel_itemstime_dynamichud 1 "apply the dynamic hud effects to this panel" seta hud_panel_scoreboard_dynamichud 0 "apply the dynamic hud effects to this panel" +seta hud_panel_strafehud_dynamichud 1 "apply the dynamic hud effects to this panel" seta hud_panel_weapons_ammo_full_shells 60 "show 100% of the status bar at this ammo count" seta hud_panel_weapons_ammo_full_nails 320 "show 100% of the status bar at this ammo count" @@ -120,6 +122,31 @@ seta hud_panel_scoreboard_accuracy_showdelay 2 "how long to delay displaying acc seta hud_panel_scoreboard_accuracy_showdelay_minpos 0.75 "delay displaying the accuracy panel only if its position is lower than this percentage of the screen height from the top" seta hud_panel_scoreboard_team_size_position 0 "where to show the team size (0 = do not show, 1 = left of scoreboard, 2 = right of scoreboard), will move team scores to the other side if necessary" +seta _hud_panel_strafehud_demo "0" "HUD changes angle during configure" +seta hud_panel_strafehud_mode "0" "strafehud mode: \"0\" = movement centered, \"1\" = angle centered" +seta hud_panel_strafehud_bar_alpha ".2" "opacity of the strafe meter" +seta hud_panel_strafehud_bar_alpha_default "1" "use default opacity for strafe bar" +seta hud_panel_strafehud_bar_color "1 1 1" "color of the strafe meter" +seta hud_panel_strafehud_bar_color_default "1" "use default color for strafe bar"" +seta hud_panel_strafehud_indicator_color "0 1 0" "color of the strafe angle indicator" +seta hud_panel_strafehud_indicator_switch_color "1 1 0" "color of the strafe angle indicator on the opposite side" +seta hud_panel_strafehud_indicator_color_default "1" "use default colors for angle indicators" +seta hud_panel_strafehud_angle "0" "the maximum angle displayed on the HUD, \"0\" = dynamic" +seta hud_panel_strafehud_good_color "0 1 1" "indicator color of the actual strafe angle if the angle matches the ideal angle" +seta hud_panel_strafehud_warning_color "1 1 0" "indicator color of the actual strafe angle if the angle doesn't match the ideal angle" +seta hud_panel_strafehud_alert_color "1 0 1" "indicator color of the actual strafe angle if the angle has a critical value" +seta hud_panel_strafehud_angle_color_default "1" "use default colors for angle indicator" +seta hud_panel_strafehud_angle_alpha ".8" "indicator transparency of the actual strafe angle" +seta hud_panel_strafehud_direction_color ".5 .25 1" "direction indicator color" +seta hud_panel_strafehud_direction_color_default "1" "use default color for direction markers" +seta hud_panel_strafehud_timeout_air_default "0" "use default value for the air timeout" +seta hud_panel_strafehud_timeout_air "0" "time after take off before changing HUD mode (prevents flickering on slick ramps)" +seta hud_panel_strafehud_timeout_ground_default "0" "use default value for the ground timeout" +seta hud_panel_strafehud_timeout_ground ".03333333" "time after landing before changing HUD mode (prevents flickering on regular strafe turns)" +seta hud_panel_strafehud_timeout_strafe_default "0" "use default value for the strafe turning timeout" +seta hud_panel_strafehud_timeout_strafe ".1" "time after releasing the strafe keys before changing mode (prevents flickering when switching between left/right strafe turning)" +seta hud_panel_strafehud_indicator_minspeed "-1" "speed at which HUD indicators will be shown, uses maxspeed if negative" + // hud panel aliases alias quickmenu "cl_cmd hud quickmenu ${* ?}" diff --git a/_hud_descriptions.cfg b/_hud_descriptions.cfg index 3f0355b5f..fc724ffff 100644 --- a/_hud_descriptions.cfg +++ b/_hud_descriptions.cfg @@ -380,3 +380,12 @@ seta hud_panel_scoreboard_table_highlight_alpha_self "" "self highlight alpha of seta hud_panel_scoreboard_bg_teams_color_team "" "override panel team color in team tables" seta hud_panel_scoreboard_accuracy_doublerows "" "use two rows instead of one" seta hud_panel_scoreboard_accuracy_nocolors "" "don't use colors displaying accuracy stats" + +seta hud_panel_strafehud_pos "" "position of this base of the panel" +seta hud_panel_strafehud_size "" "size of this panel" +seta hud_panel_strafehud_bg "" "if set to something else than \"\" = override default background" +seta hud_panel_strafehud_bg_color "" "if set to something else than \"\" = override default panel background color" +seta hud_panel_strafehud_bg_color_team "" "override panel color with team color in team based games" +seta hud_panel_strafehud_bg_alpha "" "if set to something else than \"\" = override default panel background alpha" +seta hud_panel_strafehud_bg_border "" "if set to something else than \"\" = override default size of border around the background" +seta hud_panel_strafehud_bg_padding "" "if set to something else than \"\" = override default padding of contents from border" diff --git a/hud_luma.cfg b/hud_luma.cfg index 7b8361816..9217a8a32 100644 --- a/hud_luma.cfg +++ b/hud_luma.cfg @@ -382,4 +382,13 @@ seta hud_panel_scoreboard_bg_teams_color_team "0" seta hud_panel_scoreboard_accuracy_doublerows "0" seta hud_panel_scoreboard_accuracy_nocolors "0" +seta hud_panel_strafehud_pos "0.230000 0.550000" +seta hud_panel_strafehud_size "0.540000 0.040000" +seta hud_panel_strafehud_bg "0" +seta hud_panel_strafehud_bg_color "" +seta hud_panel_strafehud_bg_color_team "" +seta hud_panel_strafehud_bg_alpha "0.7" +seta hud_panel_strafehud_bg_border "" +seta hud_panel_strafehud_bg_padding "" + menu_sync diff --git a/hud_luminos.cfg b/hud_luminos.cfg index a7e95f56f..bfffb30be 100644 --- a/hud_luminos.cfg +++ b/hud_luminos.cfg @@ -382,4 +382,13 @@ seta hud_panel_scoreboard_bg_teams_color_team "0" seta hud_panel_scoreboard_accuracy_doublerows "1" seta hud_panel_scoreboard_accuracy_nocolors "0" +seta hud_panel_strafehud_pos "0.245000 0.550000" +seta hud_panel_strafehud_size "0.510000 0.040000" +seta hud_panel_strafehud_bg "" +seta hud_panel_strafehud_bg_color "" +seta hud_panel_strafehud_bg_color_team "" +seta hud_panel_strafehud_bg_alpha "" +seta hud_panel_strafehud_bg_border "" +seta hud_panel_strafehud_bg_padding "" + menu_sync diff --git a/hud_luminos_minimal.cfg b/hud_luminos_minimal.cfg index 646b149d6..af7f90f79 100644 --- a/hud_luminos_minimal.cfg +++ b/hud_luminos_minimal.cfg @@ -382,4 +382,13 @@ seta hud_panel_scoreboard_bg_teams_color_team "0.7" seta hud_panel_scoreboard_accuracy_doublerows "1" seta hud_panel_scoreboard_accuracy_nocolors "0" +seta hud_panel_strafehud_pos "0.320000 0.550000" +seta hud_panel_strafehud_size "0.360000 0.025000" +seta hud_panel_strafehud_bg "" +seta hud_panel_strafehud_bg_color "" +seta hud_panel_strafehud_bg_color_team "" +seta hud_panel_strafehud_bg_alpha "" +seta hud_panel_strafehud_bg_border "" +seta hud_panel_strafehud_bg_padding "" + menu_sync diff --git a/hud_luminos_minimal_xhair.cfg b/hud_luminos_minimal_xhair.cfg index f8716369d..52b2ce834 100644 --- a/hud_luminos_minimal_xhair.cfg +++ b/hud_luminos_minimal_xhair.cfg @@ -382,4 +382,13 @@ seta hud_panel_scoreboard_bg_teams_color_team "0.7" seta hud_panel_scoreboard_accuracy_doublerows "1" seta hud_panel_scoreboard_accuracy_nocolors "0" +seta hud_panel_strafehud_pos "0.245000 0.700000" +seta hud_panel_strafehud_size "0.510000 0.015000" +seta hud_panel_strafehud_bg "" +seta hud_panel_strafehud_bg_color "" +seta hud_panel_strafehud_bg_color_team "" +seta hud_panel_strafehud_bg_alpha "" +seta hud_panel_strafehud_bg_border "" +seta hud_panel_strafehud_bg_padding "" + menu_sync diff --git a/hud_luminos_old.cfg b/hud_luminos_old.cfg index 16b498a75..1836bf804 100644 --- a/hud_luminos_old.cfg +++ b/hud_luminos_old.cfg @@ -382,4 +382,13 @@ seta hud_panel_scoreboard_bg_teams_color_team "0.7" seta hud_panel_scoreboard_accuracy_doublerows "1" seta hud_panel_scoreboard_accuracy_nocolors "0" +seta hud_panel_strafehud_pos "0.230000 0.540000" +seta hud_panel_strafehud_size "0.540000 0.025000" +seta hud_panel_strafehud_bg "" +seta hud_panel_strafehud_bg_color "" +seta hud_panel_strafehud_bg_color_team "" +seta hud_panel_strafehud_bg_alpha "" +seta hud_panel_strafehud_bg_border "" +seta hud_panel_strafehud_bg_padding "" + menu_sync diff --git a/hud_nexuiz.cfg b/hud_nexuiz.cfg index 0e0f079e8..b5af55df9 100644 --- a/hud_nexuiz.cfg +++ b/hud_nexuiz.cfg @@ -382,4 +382,13 @@ seta hud_panel_scoreboard_bg_teams_color_team "0.7" seta hud_panel_scoreboard_accuracy_doublerows "1" seta hud_panel_scoreboard_accuracy_nocolors "0" +seta hud_panel_strafehud_pos "0.290000 0.550000" +seta hud_panel_strafehud_size "0.420000 0.050000" +seta hud_panel_strafehud_bg "0" +seta hud_panel_strafehud_bg_color "" +seta hud_panel_strafehud_bg_color_team "" +seta hud_panel_strafehud_bg_alpha "" +seta hud_panel_strafehud_bg_border "" +seta hud_panel_strafehud_bg_padding "" + menu_sync diff --git a/qcsrc/client/autocvars.qh b/qcsrc/client/autocvars.qh index 4c6696cde..e392231be 100644 --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@ -210,6 +210,7 @@ bool autocvar_hud_panel_infomessages_dynamichud = false; bool autocvar_hud_panel_physics_dynamichud = true; bool autocvar_hud_panel_centerprint_dynamichud = true; //bool autocvar_hud_panel_itemstime_dynamichud = true; +bool autocvar_hud_panel_strafehud_dynamichud = true; bool autocvar_hud_panel_healtharmor_hide_ondeath = false; bool autocvar_hud_panel_ammo_hide_ondeath = false; bool autocvar_hud_panel_powerups_hide_ondeath = false; @@ -319,6 +320,31 @@ float autocvar_hud_panel_radar_maximized_rotation; int autocvar_hud_panel_radar_maximized_zoommode; bool autocvar_hud_panel_score; bool autocvar_hud_panel_score_rankings; +bool autocvar_hud_panel_strafehud; +bool autocvar__hud_panel_strafehud_demo; +int autocvar_hud_panel_strafehud_mode; +float autocvar_hud_panel_strafehud_bar_alpha; +bool autocvar_hud_panel_strafehud_bar_alpha_default; +vector autocvar_hud_panel_strafehud_bar_color; +bool autocvar_hud_panel_strafehud_bar_color_default; +vector autocvar_hud_panel_strafehud_indicator_color; +bool autocvar_hud_panel_strafehud_indicator_color_default; +vector autocvar_hud_panel_strafehud_indicator_switch_color; +float autocvar_hud_panel_strafehud_angle; +vector autocvar_hud_panel_strafehud_good_color; +vector autocvar_hud_panel_strafehud_warning_color; +vector autocvar_hud_panel_strafehud_alert_color; +bool autocvar_hud_panel_strafehud_angle_color_default; +float autocvar_hud_panel_strafehud_angle_alpha; +vector autocvar_hud_panel_strafehud_direction_color; +bool autocvar_hud_panel_strafehud_direction_color_default; +float autocvar_hud_panel_strafehud_timeout_air; +bool autocvar_hud_panel_strafehud_timeout_air_default; +float autocvar_hud_panel_strafehud_timeout_ground; +bool autocvar_hud_panel_strafehud_timeout_ground_default; +float autocvar_hud_panel_strafehud_timeout_strafe; +bool autocvar_hud_panel_strafehud_timeout_strafe_default; +float autocvar_hud_panel_strafehud_indicator_minspeed; bool autocvar_hud_panel_timer; bool autocvar_hud_panel_timer_increment; float autocvar_hud_panel_update_interval; diff --git a/qcsrc/client/hud/hud.qh b/qcsrc/client/hud/hud.qh index d05b04090..970b902a1 100644 --- a/qcsrc/client/hud/hud.qh +++ b/qcsrc/client/hud/hud.qh @@ -228,6 +228,7 @@ REGISTER_HUD_PANEL(MAPVOTE, MapVote_Draw, PANEL_CONFIG_NO REGISTER_HUD_PANEL(ITEMSTIME, HUD_ItemsTime, PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME ) // ITEMSTIME REGISTER_HUD_PANEL(QUICKMENU, HUD_QuickMenu, PANEL_CONFIG_MAIN , PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME ) // QUICKMENU REGISTER_HUD_PANEL(SCOREBOARD, Scoreboard_Draw, PANEL_CONFIG_NO , PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME | PANEL_SHOW_MAPVOTE | PANEL_SHOW_WITH_SB) // SCOREBOARD +REGISTER_HUD_PANEL(STRAFEHUD, HUD_StrafeHUD, PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME ) // STRAFEHUD // always add new panels to the end of list // Because calling lots of functions in QC apparently cuts fps in half on many machines: diff --git a/qcsrc/client/hud/panel/_mod.inc b/qcsrc/client/hud/panel/_mod.inc index 7a9575213..68e368ed1 100644 --- a/qcsrc/client/hud/panel/_mod.inc +++ b/qcsrc/client/hud/panel/_mod.inc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/client/hud/panel/_mod.qh b/qcsrc/client/hud/panel/_mod.qh index c24b5c000..1b45f0cd0 100644 --- a/qcsrc/client/hud/panel/_mod.qh +++ b/qcsrc/client/hud/panel/_mod.qh @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/client/hud/panel/strafehud.qc b/qcsrc/client/hud/panel/strafehud.qc new file mode 100644 index 000000000..62e6c5518 --- /dev/null +++ b/qcsrc/client/hud/panel/strafehud.qc @@ -0,0 +1,459 @@ +// Name: StrafeHUD +// Author: Juhu + +// FIXME: strafehud disabled in spectate due to lack of IS_ONGROUND() + +#include "strafehud.qh" + +#include +#include +#include +#include +#include +#include + +bool strafehud_fwd = true; +float strafehud_demo_angle = -37; +float strafehud_demo_direction = 1; +float strafehud_demo_time = 0; +float strafehud_state_onground_time = 0; +float strafehud_state_strafekeys_time = 0; +bool strafehud_state_onground = true; +bool strafehud_state_strafekeys = false; +bool strafehud_turn = false; +float strafehud_turnangle; + +void HUD_StrafeHUD() +{ + entity strafeplayer; + + if(!autocvar__hud_configure) + { + if(!autocvar_hud_panel_strafehud) return; + if(spectatee_status == -1 && (autocvar_hud_panel_strafehud == 1 || autocvar_hud_panel_strafehud == 3)) return; + if(autocvar_hud_panel_strafehud == 3 && !(ISGAMETYPE(RACE) || ISGAMETYPE(CTS))) return; + } + + HUD_Panel_LoadCvars(); + + draw_beginBoldFont(); + + if (autocvar_hud_panel_strafehud_dynamichud) + HUD_Scale_Enable(); + else + HUD_Scale_Disable(); + HUD_Panel_DrawBg(); + if(panel_bg_padding) + { + panel_pos += '1 1 0' * panel_bg_padding; + panel_size -= '2 2 0' * panel_bg_padding; + } + + if(spectatee_status > 0) + { + strafeplayer = CSQCModel_server2csqc(player_localentnum - 1); + } + else + { + strafeplayer = csqcplayer; + } + + // draw strafehud + if(csqcplayer && strafeplayer) + { + // autocvars + float strafehud_bar_alpha = autocvar_hud_panel_strafehud_bar_alpha_default + ? .2 + : autocvar_hud_panel_strafehud_bar_alpha; + vector strafehud_bar_color = autocvar_hud_panel_strafehud_bar_color_default + ? '1 1 1' + : autocvar_hud_panel_strafehud_bar_color; + vector strafehud_bestangle_color = autocvar_hud_panel_strafehud_indicator_color_default + ? '0 1 0' + : autocvar_hud_panel_strafehud_indicator_color; + vector strafehud_bestangle_opposite_color = autocvar_hud_panel_strafehud_indicator_color_default + ? '1 1 0' + : autocvar_hud_panel_strafehud_indicator_switch_color; + vector strafehud_good_color = autocvar_hud_panel_strafehud_angle_color_default + ? '0 1 1' + : autocvar_hud_panel_strafehud_good_color; + vector strafehud_warning_color = autocvar_hud_panel_strafehud_angle_color_default + ? '1 1 0' + : autocvar_hud_panel_strafehud_warning_color; + vector strafehud_alert_color = autocvar_hud_panel_strafehud_angle_color_default + ? '1 0 1' + : autocvar_hud_panel_strafehud_alert_color; + vector strafehud_direction_color = autocvar_hud_panel_strafehud_direction_color_default + ? '.5 .25 1' + : autocvar_hud_panel_strafehud_direction_color; + float strafehud_timeout_air = autocvar_hud_panel_strafehud_timeout_air_default // timeout for slick ramps + ? 0 + : autocvar_hud_panel_strafehud_timeout_air; + float strafehud_timeout_ground = autocvar_hud_panel_strafehud_timeout_ground_default // timeout for strafe jumping in general + ? .03333333 + : autocvar_hud_panel_strafehud_timeout_ground; + float strafehud_timeout_strafe = autocvar_hud_panel_strafehud_timeout_strafe_default // timeout for jumping with strafe keys only + ? .1 + : autocvar_hud_panel_strafehud_timeout_strafe; + float strafehud_indicator_minspeed = autocvar_hud_panel_strafehud_indicator_minspeed; + + // physics + float strafehud_onground = IS_ONGROUND(strafeplayer); + float strafehud_speed = !autocvar__hud_configure ? vlen(vec2(csqcplayer.velocity)) : 1337; // use local csqcmodel entity for this even when spectating, flickers too much otherwise + float strafehud_maxspeed_crouch_mod = IS_DUCKED(strafeplayer) ? .5 : 1; + float strafehud_maxspeed_swamp_mod = strafeplayer.in_swamp ? strafeplayer.swamp_slowdown : 1; + float strafehud_maxspeed_phys = strafehud_onground ? PHYS_MAXSPEED(strafeplayer) : PHYS_MAXAIRSPEED(strafeplayer); + float strafehud_maxspeed = !autocvar__hud_configure ? (strafehud_maxspeed_phys * strafehud_maxspeed_crouch_mod * strafehud_maxspeed_swamp_mod) : 320; + float strafehud_vel_angle = vectoangles(strafeplayer.velocity).y; + float strafehud_view_angle = view_angles.y + 180; + float strafehud_angle; + float strafehud_direction; + vector strafehud_movement = PHYS_INPUT_MOVEVALUES(strafeplayer); + int strafehud_keys = STAT(PRESSED_KEYS); + float strafehud_wishangle; + float strafehud_shiftangle; + float strafehud_moveangle; + + // HUD + float strafehud_hudangle; + vector strafehud_currentangle_color = strafehud_warning_color; + vector strafehud_currentangle_size = '0 0 0'; + float strafehud_currentangle_offset; + vector strafehud_bestangle_size = '0 0 0'; + bool strafehud_bestangle_visible = true; + float strafehud_bestangle = 0; + float strafehud_bestangle_offset; + float strafehud_accelzone_offset; + vector strafehud_accelzone_size; + float strafehud_overturn_offset; + vector strafehud_overturn_size; + float strafehud_mirror_overturn_offset; + vector strafehud_mirror_overturn_size; + vector strafehud_direction_size_1 = '0 0 0'; + vector strafehud_direction_size_2 = '0 0 0'; + + strafehud_indicator_minspeed = strafehud_indicator_minspeed < 0 ? strafehud_maxspeed + .1 : strafehud_indicator_minspeed; + + // determine whether the player is strafing forwards or backwards + if(strafeplayer == csqcplayer) // if entity is local player + { + if(strafehud_movement_x > 0) + { + strafehud_fwd = true; + } + else if(strafehud_movement_x < 0) + { + strafehud_fwd = false; + } + } + else // alternatively determine direction by querying pressed keys + { + if((strafehud_keys & KEY_FORWARD) && !(strafehud_keys & KEY_BACKWARD)) + { + strafehud_fwd = true; + } + else if(!(strafehud_keys & KEY_FORWARD) && (strafehud_keys & KEY_BACKWARD)) + { + strafehud_fwd = false; + } + } + + // determine player wishdir + if(strafeplayer == csqcplayer) // if entity is local player + { + if(strafehud_movement_x == 0) + { + if(strafehud_movement_y < 0) + { + strafehud_wishangle = -90; + } + else if(strafehud_movement_y > 0) + { + strafehud_wishangle = 90; + } + else + { + strafehud_wishangle = 0; + } + } + else + { + if(strafehud_movement_y == 0) + { + strafehud_wishangle = 0; + } + else + { + strafehud_wishangle = RAD2DEG * atan2(strafehud_movement_y, strafehud_movement_x); + } + } + } + else // alternatively calculate wishdir by querying pressed keys + { + if(strafehud_keys & KEY_FORWARD) + { + strafehud_wishangle = 45; + } + else if(strafehud_keys & KEY_BACKWARD) + { + strafehud_wishangle = 135; + } + else + { + strafehud_wishangle = 90; + } + if(strafehud_keys & KEY_LEFT) + { + strafehud_wishangle *= -1; + } + else if(!(strafehud_keys & KEY_RIGHT)) + { + strafehud_wishangle = 0; + } + } + + // determine how much the angle shifts in the hud + strafehud_shiftangle = fabs(remainder(strafehud_wishangle, 90)); + if(strafehud_shiftangle > 45) + { + strafehud_shiftangle = 45 - fabs(remainder(strafehud_wishangle, 45)); + } + strafehud_shiftangle = 90 - strafehud_shiftangle; + + if(autocvar_hud_panel_strafehud_angle == 0) + { + if(autocvar__hud_configure) + { + strafehud_hudangle = 45; + } + else + { + strafehud_hudangle = strafehud_shiftangle; + } + } + else + { + strafehud_hudangle = bound(1, fabs(autocvar_hud_panel_strafehud_angle), 360) / 2; // sanity check this cvar for now + } + + // detecting strafe turning + if(!autocvar__hud_configure) + { + if(strafehud_onground != strafehud_state_onground) + { + strafehud_state_onground_time = time; + } + strafehud_state_onground = strafehud_onground; + if((fabs(strafehud_wishangle) == 90) != strafehud_state_strafekeys) + { + strafehud_state_strafekeys_time = time; + } + strafehud_state_strafekeys = fabs(strafehud_wishangle) == 90; + if((strafehud_keys & KEY_FORWARD) || (strafehud_keys & KEY_BACKWARD)) + { + strafehud_turn = false; + } + else if(strafehud_onground) + { + if((time - strafehud_state_onground_time) >= strafehud_timeout_ground) + { + strafehud_turn = false; + } + } + else // air strafe only + { + if(fabs(strafehud_wishangle) == 90) + { + if((time - strafehud_state_onground_time) >= strafehud_timeout_air) + { + strafehud_turn = true; // CPMA turning + strafehud_turnangle = strafehud_wishangle; + } + } + else if((time - strafehud_state_strafekeys_time) >= strafehud_timeout_strafe) + { + strafehud_turn = false; + } + } + if(strafehud_turn) + { + strafehud_maxspeed = PHYS_MAXAIRSTRAFESPEED(strafeplayer) * strafehud_maxspeed_swamp_mod; // no crouching here because it doesn't affect air strafing + strafehud_wishangle = strafehud_turnangle; + } + } + + // add a background to the strafe-o-meter + HUD_Panel_DrawProgressBar(panel_pos, panel_size, "progressbar", 1, 0, 0, strafehud_bar_color, strafehud_bar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL); + + // get current strafing angle ranging from -180° to +180° + if(!autocvar__hud_configure) + { + if(!strafehud_fwd) strafehud_wishangle += strafehud_wishangle < 0 ? 180 : strafehud_wishangle > 0 ? -180 : 0; + if(strafehud_speed > 0) + { + if(!strafehud_fwd) strafehud_view_angle += strafehud_view_angle < 0 ? 180 : strafehud_view_angle > 0 ? -180 : 0; + strafehud_angle = strafehud_view_angle - strafehud_vel_angle; + + if (strafehud_angle > 180) strafehud_angle = -360 + strafehud_angle; + else if(strafehud_angle < -180) strafehud_angle = 360 + strafehud_angle; + + strafehud_angle = 180 - strafehud_angle; + if(strafehud_angle > 180) + { + strafehud_angle = -fabs(360 - strafehud_angle); + } + + // making the hud less flickery in case of rounding errors + if(strafehud_angle > 179.9 || strafehud_angle < -179.9) + { + strafehud_currentangle_color = strafehud_alert_color; + strafehud_angle = 0; + } + if(strafehud_angle < .1 && strafehud_angle > -.1) + { + strafehud_angle = 0; + } + } + else + { + strafehud_angle = 0; + } + } + else // simulate turning for HUD setup + { + if(autocvar__hud_panel_strafehud_demo && ((time - strafehud_demo_time) >= .025)) + { + strafehud_demo_time = time; + strafehud_demo_angle += 1 * strafehud_demo_direction; + if(fabs(strafehud_demo_angle) >= 55) + { + strafehud_demo_direction = -strafehud_demo_direction; + } + } + strafehud_angle = strafehud_demo_angle; + strafehud_wishangle = 45 * (strafehud_demo_angle > 0 ? 1 : -1); + } + + if (autocvar_v_flipped) + { + strafehud_angle = -strafehud_angle; + strafehud_wishangle = -strafehud_wishangle; + } + + strafehud_moveangle = strafehud_angle + strafehud_wishangle; + + if(strafehud_wishangle != 0) + { + strafehud_direction = strafehud_wishangle > 0 ? 1 : -1; + } + else + { + strafehud_direction = strafehud_moveangle > 0 ? 1 : strafehud_moveangle < 0 ? -1 : 0; + } + + switch(autocvar_hud_panel_strafehud_mode) + { + default: + case 0: // view centered + + // mark the ideal strafe angle + if(strafehud_speed >= strafehud_indicator_minspeed) + { + strafehud_bestangle_size.x = floor(panel_size.x * .01 + .5); + strafehud_bestangle_size.y = floor(panel_size.y + .5); + if (strafehud_direction != 0) + { + strafehud_bestangle = (strafehud_speed > strafehud_maxspeed ? acos(strafehud_maxspeed / strafehud_speed) : 0) * RAD2DEG * strafehud_direction - strafehud_wishangle; + if (fabs(strafehud_bestangle) <= strafehud_hudangle) + { + float strafehud_maxangle = 90 - fabs(strafehud_wishangle); + strafehud_bestangle_offset = floor(strafehud_bestangle/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5); + strafehud_accelzone_offset = strafehud_direction < 0 ? 0 : strafehud_bestangle_offset + strafehud_bestangle_size.x; + strafehud_accelzone_size = panel_size; + strafehud_accelzone_size.x = strafehud_direction < 0 ? strafehud_bestangle_offset : panel_size.x - strafehud_accelzone_offset; + if(strafehud_hudangle > strafehud_maxangle) + { + float strafehud_mirrorangle = 90 - strafehud_shiftangle - (180 - strafehud_hudangle); + strafehud_overturn_size = strafehud_mirror_overturn_size = panel_size; + strafehud_overturn_size.x = floor((panel_size.x * (strafehud_hudangle - strafehud_maxangle) / strafehud_hudangle) / 2 + .5); + strafehud_mirror_overturn_size.x = panel_size.x * strafehud_mirrorangle / 360; + if(strafehud_direction < 0) + { + strafehud_overturn_offset = 0; + strafehud_accelzone_offset += strafehud_overturn_size.x; + strafehud_accelzone_size.x -= strafehud_overturn_size.x; + strafehud_mirror_overturn_offset = panel_size.x - strafehud_mirror_overturn_size.x; + } + else + { + strafehud_overturn_offset = panel_size.x - strafehud_overturn_size.x; + strafehud_accelzone_size.x -= strafehud_overturn_size.x; + strafehud_mirror_overturn_offset = 0; + } + HUD_Panel_DrawProgressBar(panel_pos + eX * strafehud_overturn_offset, strafehud_overturn_size, "progressbar", 1, 0, 0, strafehud_alert_color, strafehud_bar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL); + if(strafehud_mirrorangle > 0) + { + HUD_Panel_DrawProgressBar(panel_pos + eX * strafehud_mirror_overturn_offset, strafehud_mirror_overturn_size, "progressbar", 1, 0, 0, strafehud_alert_color, strafehud_bar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL); + } + } + HUD_Panel_DrawProgressBar(panel_pos + eX * strafehud_accelzone_offset, strafehud_accelzone_size, "progressbar", 1, 0, 0, strafehud_bestangle_color, strafehud_bar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL); + strafehud_bestangle_offset = floor(-strafehud_bestangle/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5); + drawfill(panel_pos + eX * (strafehud_bestangle_offset - (-strafehud_direction < 0 ? strafehud_bestangle_size.x : 0)), strafehud_bestangle_size, strafehud_bestangle_opposite_color, panel_fg_alpha, DRAWFLAG_NORMAL); + strafehud_bestangle_offset = floor(strafehud_bestangle/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5); + drawfill(panel_pos + eX * (strafehud_bestangle_offset - (strafehud_direction < 0 ? strafehud_bestangle_size.x : 0)), strafehud_bestangle_size, strafehud_bestangle_color, panel_fg_alpha, DRAWFLAG_NORMAL); + } + strafehud_direction_size_1.x = floor(panel_size.x * .0075 + .5); + strafehud_direction_size_1.y = panel_size.y; + strafehud_direction_size_2.x = floor(strafehud_direction_size_1.x * 3 + .5); + strafehud_direction_size_2.y = strafehud_direction_size_1.x; + drawfill(panel_pos + eX * (strafehud_direction < 0 ? -strafehud_direction_size_1.x : panel_size.x), strafehud_direction_size_1, strafehud_direction_color, panel_fg_alpha, DRAWFLAG_NORMAL); + drawfill(panel_pos + eX * (strafehud_direction < 0 ? -strafehud_direction_size_1.x : panel_size.x - strafehud_direction_size_2.x + strafehud_direction_size_1.x) - eY * strafehud_direction_size_2.y, strafehud_direction_size_2, strafehud_direction_color, panel_fg_alpha, DRAWFLAG_NORMAL); + drawfill(panel_pos + eX * (strafehud_direction < 0 ? -strafehud_direction_size_1.x : panel_size.x - strafehud_direction_size_2.x + strafehud_direction_size_1.x) + eY * panel_size.y, strafehud_direction_size_2, strafehud_direction_color, panel_fg_alpha, DRAWFLAG_NORMAL); + } + else + { + strafehud_bestangle = (strafehud_speed > strafehud_maxspeed ? acos(strafehud_maxspeed / strafehud_speed) : 0) * RAD2DEG; + if (fabs(strafehud_bestangle) <= strafehud_hudangle) + { + strafehud_bestangle_offset = floor(-strafehud_bestangle/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5); + drawfill(panel_pos + eX * (strafehud_bestangle_offset - strafehud_bestangle_size.x), strafehud_bestangle_size, strafehud_bestangle_opposite_color, panel_fg_alpha, DRAWFLAG_NORMAL); + strafehud_bestangle_offset = floor(strafehud_bestangle/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5); + drawfill(panel_pos + eX * (strafehud_bestangle_offset), strafehud_bestangle_size, strafehud_bestangle_opposite_color, panel_fg_alpha, DRAWFLAG_NORMAL); + } + } + } + else + { + strafehud_bestangle_visible = false; + } + + // draw the actual strafe angle + if (strafehud_bestangle_visible) + { + if ((strafehud_direction > 0 && strafehud_angle >= strafehud_bestangle) || + (strafehud_direction < 0 && strafehud_angle <= strafehud_bestangle)) + strafehud_currentangle_color = strafehud_good_color; + } + + if (fabs(strafehud_moveangle) > 89.9) + { + strafehud_currentangle_color = strafehud_alert_color; + } + + if (strafehud_speed <= (strafehud_maxspeed + .1) && strafehud_currentangle_color != strafehud_alert_color) + { + strafehud_currentangle_color = strafehud_good_color; + } + + strafehud_currentangle_offset = floor(bound(-strafehud_hudangle, strafehud_angle, strafehud_hudangle)/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5); + + strafehud_currentangle_size.x = floor(panel_size.x * .005 + .5); + strafehud_currentangle_size.y = floor(panel_size.y * 1.5 + .5); + drawfill(panel_pos - '0 1 0'*floor(panel_size.y * .25 + .5) + eX * (strafehud_currentangle_offset - strafehud_currentangle_size.x/2), strafehud_currentangle_size, strafehud_currentangle_color, autocvar_hud_panel_strafehud_angle_alpha * panel_fg_alpha, DRAWFLAG_NORMAL); + break; + case 1: // angle centered + // TODO: implement angle centered strafehud + } + } + draw_endBoldFont(); +} diff --git a/qcsrc/client/hud/panel/strafehud.qh b/qcsrc/client/hud/panel/strafehud.qh new file mode 100644 index 000000000..6db88c68b --- /dev/null +++ b/qcsrc/client/hud/panel/strafehud.qh @@ -0,0 +1,2 @@ +#pragma once +#include "../panel.qh" diff --git a/qcsrc/menu/xonotic/_mod.inc b/qcsrc/menu/xonotic/_mod.inc index e77af222b..0f9a960c9 100644 --- a/qcsrc/menu/xonotic/_mod.inc +++ b/qcsrc/menu/xonotic/_mod.inc @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/menu/xonotic/_mod.qh b/qcsrc/menu/xonotic/_mod.qh index 50eabce95..a7ea15376 100644 --- a/qcsrc/menu/xonotic/_mod.qh +++ b/qcsrc/menu/xonotic/_mod.qh @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc b/qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc new file mode 100644 index 000000000..394e96b47 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qc @@ -0,0 +1,105 @@ +#include "dialog_hudpanel_strafehud.qh" + +#include "textlabel.qh" +#include "textslider.qh" +#include "checkbox.qh" +#include "slider.qh" + +void XonoticHUDStrafeHUDDialog_fill(entity me) +{ + entity e; + string panelname = "strafehud"; + + me.TR(me); + me.TD(me, 1, 4, e = makeXonoticTextSlider("hud_panel_strafehud")); + e.addValue(e, _("Disable"), "0"); + e.addValue(e, _("Enable"), "1"); + e.addValue(e, _("Enable even observing"), "2"); + e.addValue(e, _("Enable only in Race/CTS"), "3"); + e.configureXonoticTextSliderValues(e); + + dialog_hudpanel_main_settings(me, panelname); + + me.TR(me); + me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("StrafeHUD mode:"))); + + me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_strafehud_mode")); + e.addValue(e, _("View centered"), "0"); + e.addValue(e, _("Angle centered"), "1"); + e.configureXonoticTextSliderValues(e); + setDependentStringNotEqual(e, "hud_panel_strafehud_mode", "0"); // until multiple modes are actually supported + me.TR(me); + me.TD(me, 1, 1.2, e = makeXonoticCheckBoxString("1", "0", "_hud_panel_strafehud_demo", _("Demo mode"))); + me.TDempty(me, 0.4); + + me.TD(me, 1, 0.6, e = makeXonoticTextLabel(0, _("Range:"))); + me.TD(me, 1, 1.8, e = makeXonoticSlider(0, 360, 5, "hud_panel_strafehud_angle")); + me.TR(me); + me.TD(me, 1, 2, e = makeXonoticTextLabel(0, _("Strafe bar:"))); + + me.TD(me, 1, 2, e = makeXonoticTextLabel(0, _("Current angle:"))); + me.TR(me); + me.TDempty(me, 0.1); + me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Color:"))); + me.TDempty(me, 0.1); + me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Alpha:"))); + + me.TDempty(me, 0.1); + me.TD(me, 1, 0.56666666, e = makeXonoticTextLabel(0, _("Good:"))); + me.TDempty(me, 0.1); + me.TD(me, 1, 0.56666666, e = makeXonoticTextLabel(0, _("Neutral:"))); + me.TDempty(me, 0.1); + me.TD(me, 1, 0.56666666, e = makeXonoticTextLabel(0, _("Overturn:"))); + me.TR(me); + me.TDempty(me, 0.1); + me.TD(me, 2, 0.9, e = makeXonoticColorpickerString("hud_panel_strafehud_bar_color", "hud_panel_strafehud_bar_color")); + setDependentStringNotEqual(e, "hud_panel_strafehud_bar_color_default", "1"); + me.TDempty(me, 0.1); + me.TD(me, 1, 0.9, e = makeXonoticSlider(0, 1, 0.1, "hud_panel_strafehud_bar_alpha")); + setDependentStringNotEqual(e, "hud_panel_strafehud_bar_alpha_default", "1"); + + me.TDempty(me, 0.1); + me.TD(me, 2, 0.56666666, e = makeXonoticColorpickerString("hud_panel_strafehud_good_color", "hud_panel_strafehud_good_color")); + setDependentStringNotEqual(e, "hud_panel_strafehud_angle_color_default", "1"); + me.TDempty(me, 0.1); + me.TD(me, 2, 0.56666666, e = makeXonoticColorpickerString("hud_panel_strafehud_warning_color", "hud_panel_strafehud_warning_color")); + setDependentStringNotEqual(e, "hud_panel_strafehud_angle_color_default", "1"); + me.TDempty(me, 0.1); + me.TD(me, 2, 0.56666666, e = makeXonoticColorpickerString("hud_panel_strafehud_alert_color", "hud_panel_strafehud_alert_color")); + setDependentStringNotEqual(e, "hud_panel_strafehud_angle_color_default", "1"); + me.TR(me); + me.TR(me); + me.TDempty(me, 0.1); + me.TD(me, 1, 0.9, e = makeXonoticCheckBoxString("1", "0", "hud_panel_strafehud_bar_color_default", _("Use default"))); + me.TDempty(me, 0.1); + me.TD(me, 1, 0.9, e = makeXonoticCheckBoxString("1", "0", "hud_panel_strafehud_bar_alpha_default", _("Use default"))); + + me.TDempty(me, 0.1); + me.TD(me, 1, 1.9, e = makeXonoticCheckBoxString("1", "0", "hud_panel_strafehud_angle_color_default", _("Use default"))); + me.TR(me); + me.TD(me, 1, 2, e = makeXonoticTextLabel(0, _("Ideal angle:"))); + + me.TD(me, 1, 2, e = makeXonoticTextLabel(0, _("Direction marker:"))); + me.TR(me); + me.TDempty(me, 0.1); + me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Active:"))); + me.TDempty(me, 0.1); + me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Inactive:"))); + + me.TDempty(me, 0.1); + me.TD(me, 2, 1.9, e = makeXonoticColorpickerString("hud_panel_strafehud_direction_color", "hud_panel_strafehud_direction_color")); + setDependentStringNotEqual(e, "hud_panel_strafehud_direction_color_default", "1"); + me.TR(me); + me.TDempty(me, 0.1); + me.TD(me, 2, 0.9, e = makeXonoticColorpickerString("hud_panel_strafehud_indicator_color", "hud_panel_strafehud_indicator_color")); + setDependentStringNotEqual(e, "hud_panel_strafehud_indicator_color_default", "1"); + me.TDempty(me, 0.1); + me.TD(me, 2, 0.9, e = makeXonoticColorpickerString("hud_panel_strafehud_indicator_switch_color", "hud_panel_strafehud_indicator_switch_color")); + setDependentStringNotEqual(e, "hud_panel_strafehud_indicator_color_default", "1"); + me.TR(me); + me.TDempty(me, 2.1); + me.TD(me, 1, 1.9, e = makeXonoticCheckBoxString("1", "0", "hud_panel_strafehud_direction_color_default", _("Use default"))); + me.TR(me); + me.TDempty(me, 0.1); + me.TD(me, 1, 1.9, e = makeXonoticCheckBoxString("1", "0", "hud_panel_strafehud_indicator_color_default", _("Use default"))); +} diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qh b/qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qh new file mode 100644 index 000000000..40e37c599 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_hudpanel_strafehud.qh @@ -0,0 +1,13 @@ +#pragma once + +#include "rootdialog.qh" +CLASS(XonoticHUDStrafeHUDDialog, XonoticRootDialog) + METHOD(XonoticHUDStrafeHUDDialog, fill, void(entity)); + ATTRIB(XonoticHUDStrafeHUDDialog, title, string, _("StrafeHUD Panel")); + ATTRIB(XonoticHUDStrafeHUDDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT); + ATTRIB(XonoticHUDStrafeHUDDialog, intendedWidth, float, 0.4); + ATTRIB(XonoticHUDStrafeHUDDialog, rows, float, 21.5); + ATTRIB(XonoticHUDStrafeHUDDialog, columns, float, 4); + ATTRIB(XonoticHUDStrafeHUDDialog, name, string, "HUDstrafehud"); + ATTRIB(XonoticHUDStrafeHUDDialog, requiresConnection, float, true); +ENDCLASS(XonoticHUDStrafeHUDDialog) diff --git a/qcsrc/menu/xonotic/mainwindow.qc b/qcsrc/menu/xonotic/mainwindow.qc index 55f922929..89a61fb0d 100644 --- a/qcsrc/menu/xonotic/mainwindow.qc +++ b/qcsrc/menu/xonotic/mainwindow.qc @@ -25,6 +25,7 @@ #include "dialog_hudpanel_centerprint.qh" #include "dialog_hudpanel_itemstime.qh" #include "dialog_hudpanel_quickmenu.qh" +#include "dialog_hudpanel_strafehud.qh" #include "dialog_settings_input_userbind.qh" #include "dialog_settings_bindings_reset.qh" @@ -190,6 +191,10 @@ void MainWindow_configureMainWindow(entity me) i.configureDialog(i); me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + i = NEW(XonoticHUDStrafeHUDDialog); + i.configureDialog(i); + me.addItemRightCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + // dialogs used by settings me.userbindEditDialog = i = NEW(XonoticUserbindEditDialog); i.configureDialog(i); -- 2.39.2