]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/hud/panel/strafehud.qc
change the way default values are reset
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hud / panel / strafehud.qc
1 // Name:   StrafeHUD
2 // Author: Juhu
3
4 // FIXME: strafehud doesn't work properly in spectate due to lack of IS_ONGROUND()
5
6 #include "strafehud.qh"
7
8 #include <client/autocvars.qh>
9 #include <client/miscfunctions.qh>
10 #include <common/ent_cs.qh>
11 #include <common/mapinfo.qh>
12 #include <common/mapobjects/trigger/swamp.qh>
13 #include <common/physics/movetypes/movetypes.qh>
14 #include <common/physics/player.qh>
15 #include <lib/csqcmodel/cl_player.qh>
16
17 bool strafehud_fwd = true;
18 float strafehud_demo_angle = -37;
19 float strafehud_demo_direction = 1;
20 float strafehud_demo_time = 0;
21 float strafehud_state_onground_time = 0;
22 float strafehud_state_strafekeys_time = 0;
23 bool strafehud_state_onground = true;
24 bool strafehud_state_strafekeys = false;
25 bool strafehud_turn = false;
26 float strafehud_turnangle;
27
28 void HUD_StrafeHUD()
29 {
30     entity strafeplayer;
31
32     if(!autocvar__hud_configure)
33     {
34         if(!autocvar_hud_panel_strafehud) return;
35         if(spectatee_status == -1 && (autocvar_hud_panel_strafehud == 1 || autocvar_hud_panel_strafehud == 3)) return;
36         if(autocvar_hud_panel_strafehud == 3 && !(ISGAMETYPE(RACE) || ISGAMETYPE(CTS))) return;
37     }
38
39     HUD_Panel_LoadCvars();
40
41     if (autocvar_hud_panel_strafehud_dynamichud)
42         HUD_Scale_Enable();
43     else
44         HUD_Scale_Disable();
45     HUD_Panel_DrawBg();
46     if(panel_bg_padding)
47     {
48         panel_pos  += '1 1 0' * panel_bg_padding;
49         panel_size -= '2 2 0' * panel_bg_padding;
50     }
51
52     if(spectatee_status > 0)
53     {
54         strafeplayer = CSQCModel_server2csqc(player_localentnum - 1);
55     }
56     else
57     {
58         strafeplayer = csqcplayer;
59     }
60
61     // draw strafehud
62     if(csqcplayer && strafeplayer)
63     {
64         // autocvars
65         float strafehud_bar_alpha                 = autocvar_hud_panel_strafehud_bar_alpha;
66         vector strafehud_bar_color                = autocvar_hud_panel_strafehud_bar_color;
67         vector strafehud_bestangle_color          = autocvar_hud_panel_strafehud_indicator_color;
68         vector strafehud_bestangle_opposite_color = autocvar_hud_panel_strafehud_indicator_switch_color;
69         vector strafehud_good_color               = autocvar_hud_panel_strafehud_good_color;
70         vector strafehud_warning_color            = autocvar_hud_panel_strafehud_warning_color;
71         vector strafehud_alert_color              = autocvar_hud_panel_strafehud_alert_color;
72         vector strafehud_direction_color          = autocvar_hud_panel_strafehud_direction_color;
73         float strafehud_timeout_air               = autocvar_hud_panel_strafehud_timeout_air;    // timeout for slick ramps
74         float strafehud_timeout_ground            = autocvar_hud_panel_strafehud_timeout_ground; // timeout for strafe jumping in general
75         float strafehud_timeout_strafe            = autocvar_hud_panel_strafehud_timeout_strafe; // timeout for jumping with strafe keys only
76         float strafehud_indicator_minspeed        = autocvar_hud_panel_strafehud_indicator_minspeed;
77
78         // physics
79         float  strafehud_onground                 = IS_ONGROUND(strafeplayer);
80         float  strafehud_speed                    = !autocvar__hud_configure ? vlen(vec2(csqcplayer.velocity)) : 1337; // use local csqcmodel entity for this even when spectating, flickers too much otherwise
81         float  strafehud_maxspeed_crouch_mod      = IS_DUCKED(strafeplayer) ? .5 : 1;
82         float  strafehud_maxspeed_swamp_mod       = strafeplayer.in_swamp ? strafeplayer.swamp_slowdown : 1;
83         float  strafehud_maxspeed_phys            = strafehud_onground ? PHYS_MAXSPEED(strafeplayer) : PHYS_MAXAIRSPEED(strafeplayer);
84         float  strafehud_maxspeed                 = !autocvar__hud_configure ? (strafehud_maxspeed_phys * strafehud_maxspeed_crouch_mod * strafehud_maxspeed_swamp_mod) : 320;
85         float  strafehud_vel_angle                = vectoangles(strafeplayer.velocity).y;
86         float  strafehud_view_angle               = view_angles.y + 180;
87         float  strafehud_angle;
88         float  strafehud_direction;
89         vector strafehud_movement                 = PHYS_INPUT_MOVEVALUES(strafeplayer);
90         int    strafehud_keys                     = STAT(PRESSED_KEYS);
91         float  strafehud_wishangle;
92         float  strafehud_shiftangle;
93         float  strafehud_moveangle;
94
95         // HUD
96         float  strafehud_hudangle;
97         vector strafehud_currentangle_color       = strafehud_warning_color;
98         vector strafehud_currentangle_size        = '0 0 0';
99         float  strafehud_currentangle_offset;
100         vector strafehud_bestangle_size           = '0 0 0';
101         bool   strafehud_bestangle_visible        = true;
102         float  strafehud_bestangle                = 0;
103         float  strafehud_bestangle_offset;
104         float  strafehud_accelzone_offset;
105         vector strafehud_accelzone_size;
106         float  strafehud_overturn_offset;
107         vector strafehud_overturn_size;
108         float  strafehud_mirror_overturn_offset;
109         vector strafehud_mirror_overturn_size;
110         vector strafehud_direction_size_1         = '0 0 0';
111         vector strafehud_direction_size_2         = '0 0 0';
112
113         strafehud_indicator_minspeed = strafehud_indicator_minspeed < 0 ? strafehud_maxspeed + .1 : strafehud_indicator_minspeed;
114
115         // determine whether the player is strafing forwards or backwards
116         if(strafeplayer == csqcplayer) // if entity is local player
117         {
118             if(strafehud_movement_x > 0)
119             {
120                 strafehud_fwd = true;
121             }
122             else if(strafehud_movement_x < 0)
123             {
124                 strafehud_fwd = false;
125             }
126         }
127         else // alternatively determine direction by querying pressed keys
128         {
129             if((strafehud_keys & KEY_FORWARD) && !(strafehud_keys & KEY_BACKWARD))
130             {
131                 strafehud_fwd = true;
132             }
133             else if(!(strafehud_keys & KEY_FORWARD) && (strafehud_keys & KEY_BACKWARD))
134             {
135                 strafehud_fwd = false;
136             }
137         }
138
139         // determine player wishdir
140         if(strafeplayer == csqcplayer) // if entity is local player
141         {
142             if(strafehud_movement_x == 0)
143             {
144                 if(strafehud_movement_y < 0)
145                 {
146                     strafehud_wishangle = -90;
147                 }
148                 else if(strafehud_movement_y > 0)
149                 {
150                     strafehud_wishangle = 90;
151                 }
152                 else
153                 {
154                     strafehud_wishangle = 0;
155                 }
156             }
157             else
158             {
159                 if(strafehud_movement_y == 0)
160                 {
161                     strafehud_wishangle = 0;
162                 }
163                 else
164                 {
165                     strafehud_wishangle = RAD2DEG * atan2(strafehud_movement_y, strafehud_movement_x);
166                 }
167             }
168         }
169         else // alternatively calculate wishdir by querying pressed keys
170         {
171             if(strafehud_keys & KEY_FORWARD)
172             {
173                 strafehud_wishangle = 45;
174             }
175             else if(strafehud_keys & KEY_BACKWARD)
176             {
177                 strafehud_wishangle = 135;
178             }
179             else
180             {
181                 strafehud_wishangle = 90;
182             }
183             if(strafehud_keys & KEY_LEFT)
184             {
185                 strafehud_wishangle *= -1;
186             }
187             else if(!(strafehud_keys & KEY_RIGHT))
188             {
189                 strafehud_wishangle = 0;
190             }
191         }
192
193         // determine how much the angle shifts in the hud
194         strafehud_shiftangle = fabs(remainder(strafehud_wishangle, 90));
195         if(strafehud_shiftangle > 45)
196         {
197             strafehud_shiftangle = 45 - fabs(remainder(strafehud_wishangle, 45));
198         }
199         strafehud_shiftangle = 90 - strafehud_shiftangle;
200
201         if(autocvar_hud_panel_strafehud_angle == 0)
202         {
203             if(autocvar__hud_configure)
204             {
205                 strafehud_hudangle = 45;
206             }
207             else
208             {
209                 strafehud_hudangle = strafehud_shiftangle;
210             }
211         }
212         else
213         {
214             strafehud_hudangle = bound(1, fabs(autocvar_hud_panel_strafehud_angle), 360) / 2; // sanity check this cvar for now
215         }
216
217         // detecting strafe turning
218         if(!autocvar__hud_configure)
219         {
220             if(strafehud_onground != strafehud_state_onground)
221             {
222                 strafehud_state_onground_time = time;
223             }
224             strafehud_state_onground = strafehud_onground;
225             if((fabs(strafehud_wishangle) == 90) != strafehud_state_strafekeys)
226             {
227                 strafehud_state_strafekeys_time = time;
228             }
229             strafehud_state_strafekeys = fabs(strafehud_wishangle) == 90;
230             if((strafehud_keys & KEY_FORWARD) || (strafehud_keys & KEY_BACKWARD))
231             {
232                 strafehud_turn = false;
233             }
234             else if(strafehud_onground)
235             {
236                 if((time - strafehud_state_onground_time) >= strafehud_timeout_ground)
237                 {
238                     strafehud_turn = false;
239                 }
240             }
241             else // air strafe only
242             {
243                 if(fabs(strafehud_wishangle) == 90)
244                 {
245                     if((time - strafehud_state_onground_time) >= strafehud_timeout_air)
246                     {
247                         strafehud_turn = true; // CPMA turning
248                         strafehud_turnangle = strafehud_wishangle;
249                     }
250                 }
251                 else if((time - strafehud_state_strafekeys_time) >= strafehud_timeout_strafe)
252                 {
253                     strafehud_turn = false;
254                 }
255             }
256             if(strafehud_turn)
257             {
258                 strafehud_maxspeed = PHYS_MAXAIRSTRAFESPEED(strafeplayer) * strafehud_maxspeed_swamp_mod; // no crouching here because it doesn't affect air strafing
259                 strafehud_wishangle = strafehud_turnangle;
260             }
261         }
262
263         // add a background to the strafe-o-meter
264         HUD_Panel_DrawProgressBar(panel_pos, panel_size, "progressbar", 1, 0, 0, strafehud_bar_color, strafehud_bar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
265
266         // get current strafing angle ranging from -180° to +180°
267         if(!autocvar__hud_configure)
268         {
269             if(!strafehud_fwd) strafehud_wishangle += strafehud_wishangle < 0 ? 180 : strafehud_wishangle > 0 ? -180 : 0;
270             if(strafehud_speed > 0)
271             {
272                 if(!strafehud_fwd) strafehud_view_angle += strafehud_view_angle < 0 ? 180 : strafehud_view_angle > 0 ? -180 : 0;
273                 strafehud_angle = strafehud_view_angle - strafehud_vel_angle;
274
275                 if     (strafehud_angle >  180) strafehud_angle = -360 + strafehud_angle;
276                 else if(strafehud_angle < -180) strafehud_angle =  360 + strafehud_angle;
277
278                 strafehud_angle = 180 - strafehud_angle;
279                 if(strafehud_angle > 180)
280                 {
281                     strafehud_angle = -fabs(360 - strafehud_angle);
282                 }
283
284                 // making the hud less flickery in case of rounding errors
285                 if(strafehud_angle > 179.9 || strafehud_angle < -179.9)
286                 {
287                     strafehud_currentangle_color = strafehud_alert_color;
288                     strafehud_angle = 0;
289                 }
290                 if(strafehud_angle < .1 && strafehud_angle > -.1)
291                 {
292                     strafehud_angle = 0;
293                 }
294             }
295             else
296             {
297                 strafehud_angle = 0;
298             }
299         }
300         else // simulate turning for HUD setup
301         {
302             if(autocvar__hud_panel_strafehud_demo && ((time - strafehud_demo_time) >= .025))
303             {
304                 strafehud_demo_time = time;
305                 strafehud_demo_angle += 1 * strafehud_demo_direction;
306                 if(fabs(strafehud_demo_angle) >= 55)
307                 {
308                     strafehud_demo_direction = -strafehud_demo_direction;
309                 }
310             }
311             strafehud_angle = strafehud_demo_angle;
312             strafehud_wishangle = 45 * (strafehud_demo_angle > 0 ? 1 : -1);
313         }
314
315         if (autocvar_v_flipped)
316         {
317             strafehud_angle = -strafehud_angle;
318             strafehud_wishangle = -strafehud_wishangle;
319         }
320
321         strafehud_moveangle = strafehud_angle + strafehud_wishangle;
322
323         if(strafehud_wishangle != 0)
324         {
325             strafehud_direction = strafehud_wishangle > 0 ? 1 : -1;
326         }
327         else
328         {
329             strafehud_direction = strafehud_moveangle > 0 ? 1 : strafehud_moveangle < 0 ? -1 : 0;
330         }
331
332         switch(autocvar_hud_panel_strafehud_mode)
333         {
334             default:
335             case 0: // view centered
336
337             // mark the ideal strafe angle
338             if(strafehud_speed >= strafehud_indicator_minspeed)
339             {
340                 strafehud_bestangle_size.x = floor(panel_size.x * .01 + .5);
341                 strafehud_bestangle_size.y = floor(panel_size.y + .5);
342                 if (strafehud_direction != 0)
343                 {
344                     strafehud_bestangle = (strafehud_speed > strafehud_maxspeed ? acos(strafehud_maxspeed / strafehud_speed) : 0) * RAD2DEG * strafehud_direction - strafehud_wishangle;
345                     if (fabs(strafehud_bestangle) <= strafehud_hudangle)
346                     {
347                         float strafehud_maxangle = 90 - fabs(strafehud_wishangle);
348                         strafehud_bestangle_offset = floor(strafehud_bestangle/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5);
349                         strafehud_accelzone_offset = strafehud_direction < 0 ? 0 : strafehud_bestangle_offset + strafehud_bestangle_size.x;
350                         strafehud_accelzone_size = panel_size;
351                         strafehud_accelzone_size.x = strafehud_direction < 0 ? strafehud_bestangle_offset : panel_size.x - strafehud_accelzone_offset;
352                         if(strafehud_hudangle > strafehud_maxangle)
353                         {
354                             float strafehud_mirrorangle = 90 - strafehud_shiftangle - (180 - strafehud_hudangle);
355                             strafehud_overturn_size = strafehud_mirror_overturn_size = panel_size;
356                             strafehud_overturn_size.x = floor((panel_size.x * (strafehud_hudangle - strafehud_maxangle) / strafehud_hudangle) / 2 + .5);
357                             strafehud_mirror_overturn_size.x = panel_size.x * strafehud_mirrorangle / 360;
358                             if(strafehud_direction < 0)
359                             {
360                                 strafehud_overturn_offset = 0;
361                                 strafehud_accelzone_offset += strafehud_overturn_size.x;
362                                 strafehud_accelzone_size.x -= strafehud_overturn_size.x;
363                                 strafehud_mirror_overturn_offset = panel_size.x - strafehud_mirror_overturn_size.x;
364                             }
365                             else
366                             {
367                                 strafehud_overturn_offset = panel_size.x - strafehud_overturn_size.x;
368                                 strafehud_accelzone_size.x -= strafehud_overturn_size.x;
369                                 strafehud_mirror_overturn_offset = 0;
370                             }
371                             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);
372                             if(strafehud_mirrorangle > 0)
373                             {
374                                 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);
375                             }
376                         }
377                         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);
378                         strafehud_bestangle_offset = floor(-strafehud_bestangle/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5);
379                         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);
380                         strafehud_bestangle_offset = floor(strafehud_bestangle/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5);
381                         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);
382                     }
383                     strafehud_direction_size_1.x = floor(panel_size.x * .0075 + .5);
384                     strafehud_direction_size_1.y = panel_size.y;
385                     strafehud_direction_size_2.x = floor(strafehud_direction_size_1.x * 3 + .5);
386                     strafehud_direction_size_2.y = strafehud_direction_size_1.x;
387                     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);
388                     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);
389                     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);
390                 }
391                 else
392                 {
393                     strafehud_bestangle = (strafehud_speed > strafehud_maxspeed ? acos(strafehud_maxspeed / strafehud_speed) : 0) * RAD2DEG;
394                     if (fabs(strafehud_bestangle) <= strafehud_hudangle)
395                     {
396                         strafehud_bestangle_offset = floor(-strafehud_bestangle/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5);
397                         drawfill(panel_pos + eX * (strafehud_bestangle_offset - strafehud_bestangle_size.x), strafehud_bestangle_size, strafehud_bestangle_opposite_color, panel_fg_alpha, DRAWFLAG_NORMAL);
398                         strafehud_bestangle_offset = floor(strafehud_bestangle/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5);
399                         drawfill(panel_pos + eX * (strafehud_bestangle_offset), strafehud_bestangle_size, strafehud_bestangle_opposite_color, panel_fg_alpha, DRAWFLAG_NORMAL);
400                     }
401                 }
402             }
403             else
404             {
405                 strafehud_bestangle_visible = false;
406             }
407
408             // draw the actual strafe angle
409             if (strafehud_bestangle_visible)
410             {
411                 if ((strafehud_direction > 0 && strafehud_angle >= strafehud_bestangle) ||
412                     (strafehud_direction < 0 && strafehud_angle <= strafehud_bestangle))
413                 strafehud_currentangle_color = strafehud_good_color;
414             }
415
416             if (fabs(strafehud_moveangle) > 89.9)
417             {
418                 strafehud_currentangle_color = strafehud_alert_color;
419             }
420
421             if (strafehud_speed <= (strafehud_maxspeed + .1) && strafehud_currentangle_color != strafehud_alert_color)
422             {
423                 strafehud_currentangle_color = strafehud_good_color;
424             }
425
426             strafehud_currentangle_offset = floor(bound(-strafehud_hudangle, strafehud_angle, strafehud_hudangle)/strafehud_hudangle * panel_size.x/2 + panel_size.x/2 + .5);
427
428             strafehud_currentangle_size.x = floor(panel_size.x * .005 + .5);
429             strafehud_currentangle_size.y = floor(panel_size.y * 1.5 + .5);
430             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);
431             break;
432             case 1: // angle centered
433                 // TODO: implement angle centered strafehud
434         }
435     }
436 }