//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"
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"
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 ${* ?}"
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"
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
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
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
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
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
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
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;
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;
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:
#include <client/hud/panel/radar.qc>
#include <client/hud/panel/score.qc>
#include <client/hud/panel/scoreboard.qc>
+#include <client/hud/panel/strafehud.qc>
#include <client/hud/panel/timer.qc>
#include <client/hud/panel/vote.qc>
#include <client/hud/panel/weapons.qc>
#include <client/hud/panel/radar.qh>
#include <client/hud/panel/score.qh>
#include <client/hud/panel/scoreboard.qh>
+#include <client/hud/panel/strafehud.qh>
#include <client/hud/panel/timer.qh>
#include <client/hud/panel/vote.qh>
#include <client/hud/panel/weapons.qh>
--- /dev/null
+// Name: StrafeHUD
+// Author: Juhu
+
+// FIXME: strafehud disabled in spectate due to lack of IS_ONGROUND()
+
+#include "strafehud.qh"
+
+#include <client/autocvars.qh>
+#include <client/defs.qh>
+#include <client/miscfunctions.qh>
+#include <client/main.qh>
+#include <common/mapinfo.qh>
+#include <lib/csqcmodel/cl_player.qh>
+
+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();
+}
--- /dev/null
+#pragma once
+#include "../panel.qh"
#include <menu/xonotic/dialog_hudpanel_racetimer.qc>
#include <menu/xonotic/dialog_hudpanel_radar.qc>
#include <menu/xonotic/dialog_hudpanel_score.qc>
+#include <menu/xonotic/dialog_hudpanel_strafehud.qc>
#include <menu/xonotic/dialog_hudpanel_timer.qc>
#include <menu/xonotic/dialog_hudpanel_vote.qc>
#include <menu/xonotic/dialog_hudpanel_weapons.qc>
#include <menu/xonotic/dialog_hudpanel_racetimer.qh>
#include <menu/xonotic/dialog_hudpanel_radar.qh>
#include <menu/xonotic/dialog_hudpanel_score.qh>
+#include <menu/xonotic/dialog_hudpanel_strafehud.qh>
#include <menu/xonotic/dialog_hudpanel_timer.qh>
#include <menu/xonotic/dialog_hudpanel_vote.qh>
#include <menu/xonotic/dialog_hudpanel_weapons.qh>
--- /dev/null
+#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")));
+}
--- /dev/null
+#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)
#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"
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);