// other hud cvars
seta hud_panel_update_interval 2 "how often (in seconds) common panel cvars are reloaded"
+seta hud_dynamic_follow 1 "HUD moves around following player's movement (effect shared with cl_followmodel, can be enabled independently from it though)"
+seta hud_dynamic_follow_scale 0.01 "HUD following scale"
+seta hud_dynamic_follow_scale_xyz "1 1 1" "HUD following scale for the x, y and z axis"
+
+seta hud_dynamic_shake 1 "shake the HUD when hurt"
+seta hud_dynamic_shake_damage_max 90 "damage value at which the HUD shake effect is maximum"
+seta hud_dynamic_shake_damage_min 10 "damage value at which the HUD shake effect is minimum"
+seta hud_dynamic_shake_scale 0.4 "HUD shake scale"
+
seta hud_showbinds 1 "what to show in the HUD to indicate certain keys to press: 0 display commands, 1 bound keys, 2 both"
seta hud_showbinds_limit 2 "maximum number of bound keys to show for a command. 0 for unlimited"
set _hud_showbinds_reload 0 "set it to 1 to reload binds if you changed any. It is reset to 0 automatically"
string autocvar_hud_skin;
float autocvar_menu_mouse_speed;
string autocvar_menu_skin;
+float autocvar_r_drawviewmodel;
int autocvar_r_fakelight;
int autocvar_r_fullbright;
float autocvar_r_letterbox;
else if(length_ratio < 0)
return;
+ theOrigin = HUD_Shift(theOrigin);
+ theSize = HUD_Scale(theSize);
+
vector square;
vector width, height;
if(vertical) {
if(!theAlpha)
return;
+ pos = HUD_Shift(pos);
+ mySize = HUD_Scale(mySize);
+
string pic;
pic = strcat(hud_skin_path, "/num_leading");
if(precache_pic(pic) == "") {
HUD_Mod_CTF_Reset();
}
+float autocvar_hud_dynamic_shake;
+float autocvar_hud_dynamic_shake_damage_max;
+float autocvar_hud_dynamic_shake_damage_min;
+float autocvar_hud_dynamic_shake_scale;
+float hud_dynamic_shake_x[10] = {0, 1, -0.7, 0.5, -0.3, 0.2, -0.1, 0.1, 0.0, 0};
+float hud_dynamic_shake_y[10] = {0, 0.4, 0.8, -0.2, -0.6, 0.0, 0.3, 0.1, -0.1, 0};
+bool Hud_Shake_Update()
+{
+ if(time - hud_dynamic_shake_time < 0)
+ return false;
+
+ float anim_speed = 17 + 9 * hud_dynamic_shake_factor;
+ float elapsed_time = (time - hud_dynamic_shake_time) * anim_speed;
+ int i = floor(elapsed_time);
+ if(i >= 9)
+ return false;
+
+ float f = elapsed_time - i;
+ hud_dynamic_shake_realofs.x = (1 - f) * hud_dynamic_shake_x[i] + f * hud_dynamic_shake_x[i+1];
+ hud_dynamic_shake_realofs.y = (1 - f) * hud_dynamic_shake_y[i] + f * hud_dynamic_shake_y[i+1];
+ hud_dynamic_shake_realofs.z = 0;
+ hud_dynamic_shake_realofs *= hud_dynamic_shake_factor * autocvar_hud_dynamic_shake_scale;
+ hud_dynamic_shake_realofs.x = bound(-0.1, hud_dynamic_shake_realofs.x, 0.1) * vid_conwidth;
+ hud_dynamic_shake_realofs.y = bound(-0.1, hud_dynamic_shake_realofs.y, 0.1) * vid_conheight;
+ return true;
+}
+
+void calc_followmodel_ofs(entity view);
+void Hud_Dynamic_Frame()
+{
+ vector ofs = '0 0 0';
+ hud_scale = '1 1 0';
+ hud_shift = '0 0 0';
+ if (autocvar_hud_dynamic_follow)
+ {
+ entity view = CSQCModel_server2csqc(player_localentnum - 1);
+ calc_followmodel_ofs(view);
+ ofs = -cl_followmodel_ofs * autocvar_hud_dynamic_follow_scale;
+ ofs.x *= autocvar_hud_dynamic_follow_scale_xyz.z;
+ ofs.y *= autocvar_hud_dynamic_follow_scale_xyz.x;
+ ofs.z *= autocvar_hud_dynamic_follow_scale_xyz.y;
+
+ if (fabs(ofs.x) < 0.001) ofs.x = 0;
+ if (fabs(ofs.y) < 0.001) ofs.y = 0;
+ if (fabs(ofs.z) < 0.001) ofs.z = 0;
+ ofs.x = bound(-0.1, ofs.x, 0.1);
+ ofs.y = bound(-0.1, ofs.y, 0.1);
+ ofs.z = bound(-0.1, ofs.z, 0.1);
+
+ hud_shift.x = ofs.y * vid_conwidth;
+ hud_shift.y = ofs.z * vid_conheight;
+ hud_shift.z = ofs.x;
+
+ hud_scale.x = (1 + hud_shift.z);
+ hud_scale.y = hud_scale.x;
+ }
+
+ if(autocvar_hud_dynamic_shake > 0)
+ {
+ if(hud_dynamic_shake_factor == -1) // don't allow the effect for this frame
+ hud_dynamic_shake_factor = 0;
+ else
+ {
+ float health = STAT(HEALTH);
+ float new_hud_dynamic_shake_factor = 0;
+ if(prev_health - health >= autocvar_hud_dynamic_shake_damage_min && autocvar_hud_dynamic_shake_damage_max > autocvar_hud_dynamic_shake_damage_min)
+ {
+ float m = max(autocvar_hud_dynamic_shake_damage_min, 1);
+ new_hud_dynamic_shake_factor = (prev_health - health - m) / (autocvar_hud_dynamic_shake_damage_max - m);
+ if(new_hud_dynamic_shake_factor >= 1)
+ new_hud_dynamic_shake_factor = 1;
+ if(new_hud_dynamic_shake_factor >= hud_dynamic_shake_factor)
+ {
+ hud_dynamic_shake_factor = new_hud_dynamic_shake_factor;
+ hud_dynamic_shake_time = time;
+ }
+ }
+ if(hud_dynamic_shake_factor)
+ if(!Hud_Shake_Update())
+ hud_dynamic_shake_factor = 0;
+ }
+
+ if(hud_dynamic_shake_factor > 0)
+ {
+ hud_shift.x += hud_dynamic_shake_realofs.x;
+ hud_shift.y += hud_dynamic_shake_realofs.y;
+ }
+ }
+
+ hud_scale_center.x = 0.5 * vid_conwidth;
+ hud_scale_center.y = 0.5 * vid_conheight;
+
+ hud_scale_current = hud_scale;
+ hud_shift_current = hud_shift;
+}
+
void HUD_Main()
{
int i;
HUD_Configure_Frame();
+ Hud_Dynamic_Frame();
+
// panels that we want to be active together with the scoreboard
// they must fade only when the menu does
if(scoreboard_fade_alpha == 1)
#define HUD_PANEL(NAME) HUD_PANEL_##NAME
// draw the background/borders
-#define HUD_Panel_DrawBg(theAlpha) MACRO_BEGIN { \
- if(panel.current_panel_bg != "0" && panel.current_panel_bg != "") \
- draw_BorderPicture(panel_pos - '1 1 0' * panel_bg_border, panel.current_panel_bg, panel_size + '1 1 0' * 2 * panel_bg_border, panel_bg_color, panel_bg_alpha * theAlpha, '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER));\
+#define HUD_Panel_DrawBg(theAlpha) MACRO_BEGIN { \
+ if(panel.current_panel_bg != "0" && panel.current_panel_bg != "") \
+ draw_BorderPicture( \
+ HUD_Shift(panel_pos - '1 1 0' * panel_bg_border), \
+ panel.current_panel_bg, \
+ HUD_Scale(panel_size + '1 1 0' * 2 * panel_bg_border), \
+ panel_bg_color, \
+ panel_bg_alpha * theAlpha, \
+ HUD_Scale('1 1 0' * (panel_bg_border/BORDER_MULTIPLIER)) \
+ ); \
} MACRO_END
int panel_order[hud_panels_MAX];
float current_player;
+float autocvar_hud_dynamic_follow;
+float autocvar_hud_dynamic_follow_scale;
+vector autocvar_hud_dynamic_follow_scale_xyz;
+
+vector hud_dynamic_shake_realofs;
+float hud_dynamic_shake_factor;
+float hud_dynamic_shake_time;
+
+// shared across viewmodel effects and dynamic hud code
+vector cl_followmodel_ofs;
+float cl_followmodel_time;
+
+vector hud_scale;
+vector hud_scale_current;
+vector hud_shift;
+vector hud_shift_current;
+vector hud_scale_center;
+
float stringwidth_colors(string s, vector theSize);
float stringwidth_nocolors(string s, vector theSize);
void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag);
menu_enabled = 0;
if(autocvar_hud_cursormode)
setcursormode(0);
+ hud_dynamic_shake_factor = -1;
}
}
pos = panel_pos;
mySize = panel_size;
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
{
}
}
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if (!centerprint_showing)
// finally set the size based on the new theAlpha from subsequent fading
sz = sz * (autocvar_hud_panel_centerprint_fade_subsequent_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_subsequent_minfontsize));
- drawfontscale = sz * '1 1 0';
+ drawfontscale = hud_scale * sz;
if (centerprint_countdown_num[j])
n = tokenizebyseparator(strreplace("^COUNT", count_seconds(centerprint_countdown_num[j]), centerprint_messages[j]), "\n");
getWrappedLine_remaining = argv(k);
while(getWrappedLine_remaining)
{
- ts = getWrappedLine(panel_size.x * sz, fontsize, stringwidth_colors);
+ ts = getWrappedLine(panel_size.x * hud_scale.x * sz, fontsize, stringwidth_colors);
if (ts != "")
pos.y -= fontsize.y;
else
getWrappedLine_remaining = argv(k);
while(getWrappedLine_remaining)
{
- ts = getWrappedLine(panel_size.x * sz, fontsize, stringwidth_colors);
+ ts = getWrappedLine(panel_size.x * hud_scale.x * sz, fontsize, stringwidth_colors);
if (ts != "")
{
if (align)
- pos.x = panel_pos.x + (panel_size.x - stringwidth(ts, true, fontsize)) * align;
+ pos.x = panel_pos.x + (panel_size.x - stringwidth(ts, true, fontsize) * sz) * align;
if (a > 0.5/255.0) // Otherwise guaranteed invisible - don't show. This is checked a second time after some multiplications with other factors were done so temporary changes of these cannot cause flicker.
- drawcolorcodedstring(pos + eY * 0.5 * (1 - sz) * fontsize.y, ts, fontsize, a, DRAWFLAG_NORMAL);
+ drawcolorcodedstring(pos + eY * 0.5 * (1 - sz * hud_scale.x) * fontsize.y, ts, fontsize, a, DRAWFLAG_NORMAL);
pos.y += fontsize.y;
}
else
if (pos.y < panel_pos.y) // check if the next message can be shown
{
- drawfontscale = '1 1 0';
+ drawfontscale = hud_scale;
return;
}
}
if(pos.y > panel_pos.y + panel_size.y - fontsize.y) // check if the next message can be shown
{
- drawfontscale = '1 1 0';
+ drawfontscale = hud_scale;
return;
}
}
}
- drawfontscale = '1 1 0';
+ drawfontscale = hud_scale;
if (all_messages_expired)
{
centerprint_showing = false;
pos = panel_pos;
mySize = panel_size;
+ HUD_Scale_Disable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
pos = panel_pos;
mySize = panel_size;
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
{
pos = panel_pos;
mySize = panel_size;
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
{
pos = panel_pos;
mySize = panel_size;
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
{
else
mod_alpha = bound(0, 1 - (time - mod_change) * 2, 1);
+ HUD_Scale_Enable();
if(mod_alpha)
HUD_Panel_DrawBg(mod_alpha);
return;
HUD_Panel_UpdateCvars();
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if (!autocvar__hud_configure)
draw_beginBoldFont();
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
{
// Draw panel background
HUD_Panel_UpdateCvars();
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
// Set drawing area
pos = panel_pos;
mySize = panel_size;
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
{
HUD_Panel_UpdateCvars();
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
pos = panel_pos;
mySize = panel_size;
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
{
pos = panel_pos;
mySize = panel_size;
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
{
int color2;
float scale2d, normalsize, bigsize;
- teamradar_origin2d = pos + 0.5 * mySize;
+ teamradar_origin2d = HUD_Shift(pos + 0.5 * mySize);
teamradar_size2d = mySize;
if(minimapname == "")
teamradar_loadcvars();
scale2d = vlen_maxnorm2d(mi_picmax - mi_picmin);
- teamradar_size2d = mySize;
+ teamradar_size2d = HUD_Scale(mySize);
teamradar_extraclip_mins = teamradar_extraclip_maxs = '0 0 0'; // we always center
pos = panel_pos;
mySize = panel_size;
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
{
pos = panel_pos;
mySize = panel_size;
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
{
mySize = panel_size;
a = vote_alpha * (vote_highlighted ? autocvar_hud_panel_vote_alreadyvoted_alpha : 1);
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(a);
a = panel_fg_alpha * a;
}
// draw the background, then change the virtual size of it to better fit other items inside
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
if(center.x == -1)
// clear race stuff
race_laptime = 0;
race_checkpointtime = 0;
+ hud_dynamic_shake_factor = -1;
}
if (autocvar_hud_panel_healtharmor_progressbar_gfx)
{
panel_pos.y = pos.y;
panel_size.x = xmax - xmin;
panel_size.y = ymax - ymin;
+ HUD_Scale_Disable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
void drawpic_tiled(vector pos, string pic, vector sz, vector area, vector color, float theAlpha, float drawflag)
{
+ pos = HUD_Shift(pos);
+ sz = HUD_Scale(sz);
+ area = HUD_Scale(area);
+
vector current_pos = '0 0 0', end_pos, new_size = '0 0 0', ratio = '0 0 0';
end_pos = pos + area;
drawpic_skin(position, pic, theScale, rgb, theAlpha * fadelerp, flag);
}
+void HUD_Scale_Disable()
+{
+ hud_scale = '1 1 0';
+ hud_shift = '0 0 0';
+ drawfontscale = hud_scale;
+}
+
+void HUD_Scale_Enable()
+{
+ hud_scale = hud_scale_current;
+ hud_shift = hud_shift_current;
+ drawfontscale = hud_scale;
+}
+
+vector HUD_Scale(vector v)
+{
+ v.x = HUD_ScaleX(v.x);
+ v.y = HUD_ScaleY(v.y);
+ return v;
+}
+
+vector HUD_Shift(vector v)
+{
+ v.x = HUD_ShiftX(v.x);
+ v.y = HUD_ShiftY(v.y);
+ return v;
+}
+
+float stringwidth(string text, float handleColors, vector sz)
+{
+ vector dfs = drawfontscale;
+ drawfontscale = '1 1 0';
+ float r = stringwidth_builtin(text, handleColors, sz);
+ drawfontscale = dfs;
+ return r;
+}
+
// drawstring wrapper to draw a string as large as possible with preserved aspect ratio into a box
void drawstring_aspect(vector pos, string text, vector sz, vector color, float theAlpha, float drawflag) {
SET_POS_AND_SZ_Y_ASPECT(false);
float sz;
sz = expandingbox_sizefactor_from_fadelerp(fadelerp);
+ drawfontscale = hud_scale * sz;
+ vector dfs = drawfontscale;
drawfontscale = sz * '1 1 0';
- drawstring(position + expandingbox_resize_centered_box_offset(sz, theScale, stringwidth(text, false, theScale * (sz / drawfontscale.x)) / (theScale.x * sz)), text, theScale * (sz / drawfontscale.x), rgb, theAlpha * (1 - fadelerp), flag);
+ float textaspect = stringwidth_builtin(text, false, theScale * (sz / drawfontscale.x)) / (theScale.x * sz);
+ drawfontscale = dfs;
+ drawstring(position + expandingbox_resize_centered_box_offset(sz, theScale, textaspect), text, HUD_Scale(theScale * (sz / drawfontscale.x)), rgb, theAlpha * (1 - fadelerp), flag);
// width parameter:
- // (scale_x * sz / drawfontscale_x) * drawfontscale_x * SIZE1 / (scale_x * sz)
+ // (scale_x * sz / drawfontscale.x) * drawfontscale.x * SIZE1 / (scale_x * sz)
// SIZE1
- drawfontscale = '1 1 0';
+ drawfontscale = hud_scale;
}
// drawstring wrapper to draw a string as large as possible with preserved aspect ratio into a box
float sz;
sz = expandingbox_sizefactor_from_fadelerp(fadelerp);
- drawfontscale = sz * '1 1 0';
- drawcolorcodedstring(position + expandingbox_resize_centered_box_offset(sz, theScale, stringwidth(text, true, theScale * (sz / drawfontscale.x)) / (theScale.x * sz)), text, theScale * (sz / drawfontscale.x), theAlpha * (1 - fadelerp), flag);
- drawfontscale = '1 1 0';
+ drawfontscale = hud_scale * sz;
+ // eventually replace with drawcolorcodedstring
+ drawcolorcodedstring(position + expandingbox_resize_centered_box_offset(sz, theScale, stringwidth_builtin(text, true, theScale * (sz / drawfontscale.x)) / (theScale.x * sz)), text, theScale * (sz / drawfontscale.x), theAlpha * (1 - fadelerp), flag);
+ drawfontscale = hud_scale;
}
void drawcolorcodedstring_aspect_expanding(vector pos, string text, vector sz, float theAlpha, float drawflag, float fadelerp) {
vector project_3d_to_2d(vector vec);
+vector drawfontscale;
#define draw_beginBoldFont() MACRO_BEGIN { drawfont = FONT_USER + 2; } MACRO_END
#define draw_endBoldFont() MACRO_BEGIN { drawfont = FONT_USER + 1; } MACRO_END
void drawpic_tiled(vector pos, string pic, vector sz, vector area, vector color, float theAlpha, float drawflag);
+void HUD_Scale_Disable();
+void HUD_Scale_Enable();
+
+#define HUD_ScaleX(f) (f * hud_scale.x)
+#define HUD_ScaleY(f) (f * hud_scale.y)
+#define HUD_ShiftX(f) (f + hud_shift.x + hud_shift.z * (f - hud_scale_center.x))
+#define HUD_ShiftY(f) (f + hud_shift.y + hud_shift.z * (f - hud_scale_center.y))
+vector HUD_Scale(vector v);
+vector HUD_Shift(vector v);
+
+// call draw*_builtin (and stringwidth_builtin) functions only when
+// pos and size don't have to be scaled by the hud_dynamic code
+// (typically outside the real HUD code)
+
+// NOTE: drawsubpic usually gets called multiple times within an utility function
+// so instead of remapping it, scaling pos and size in every call,
+// we prefer to scale pos and size once for all in the utility function
+
+float stringwidth(string text, float handleColors, vector sz);
+
+#define drawpic(position, pic, size, rgb, alpha, flag) \
+ drawpic_builtin(HUD_Shift(position), pic, HUD_Scale(size), rgb, alpha, flag)
+
+#define drawcharacter(position, character, scale, rgb, alpha, flag) \
+ drawcharacter_builtin(HUD_Shift(position), text, scale, rgb, alpha, flag)
+
+#define drawstring(position, text, scale, rgb, alpha, flag) \
+ drawstring_builtin(HUD_Shift(position), text, scale, rgb, alpha, flag)
+
+#define drawcolorcodedstring(position, text, scale, alpha, flag) \
+ drawcolorcodedstring_builtin(HUD_Shift(position), text, scale, alpha, flag)
+
+#define drawcolorcodedstring2(position, text, scale, rgb, alpha, flag) \
+ drawcolorcodedstring2_builtin(HUD_Shift(position), text, scale, rgb, alpha, flag)
+
+#define drawfill(position, size, rgb, alpha, flag) \
+ drawfill_builtin(HUD_Shift(position), HUD_Scale(size), rgb, alpha, flag)
+
+#define drawsetcliparea(xposition, yposition, w, h) \
+ drawsetcliparea_builtin(HUD_ShiftX(xposition), HUD_ShiftY(yposition), HUD_ScaleX(w), HUD_ScaleY(h))
+
// drawpic wrapper to draw an image as large as possible with preserved aspect ratio into a box
float _drawpic_imgaspect;
vector _drawpic_imgsize;
#define SET_POS_AND_SZ_Y_ASPECT(allow_colors) MACRO_BEGIN { \
float textaspect, oldsz; \
+ vector dfs = drawfontscale; \
+ drawfontscale = '1 1 0'; \
textaspect = stringwidth(text, allow_colors, '1 1 1' * sz.y) / sz.y; \
+ drawfontscale = dfs; \
if(sz.x/sz.y > textaspect) { \
oldsz = sz.x; \
sz.x = sz.y * textaspect; \
// drawstring wrapper to draw a colorcodedstring as large as possible with preserved aspect ratio into a box
void drawcolorcodedstring_aspect(vector pos, string text, vector sz, float theAlpha, float drawflag);
-vector drawfontscale;
void drawstring_expanding(vector position, string text, vector theScale, vector rgb, float theAlpha, float flag, float fadelerp);
// drawstring wrapper to draw a string as large as possible with preserved aspect ratio into a box
void draw_teamradar_icon(vector coord, entity icon, entity pingdata, vector rgb, float a)
{
coord = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(coord));
- drawpic(coord - '4 4 0', strcat("gfx/teamradar_icon_", ftos(icon.m_radaricon)), '8 8 0', rgb, a, 0);
+ drawpic_builtin(coord - '4 4 0', strcat("gfx/teamradar_icon_", ftos(icon.m_radaricon)), '8 8 0', rgb, a, 0);
if(pingdata)
{
if(dt >= 1 || dt <= 0)
continue;
vector v = '2 2 0' * teamradar_size * dt;
- drawpic(coord - 0.5 * v, "gfx/teamradar_ping", v, '1 1 1', (1 - dt) * a, DRAWFLAG_ADDITIVE);
+ drawpic_builtin(coord - 0.5 * v, "gfx/teamradar_ping", v, '1 1 1', (1 - dt) * a, DRAWFLAG_ADDITIVE);
}
}
}
highpass(value.z, frac, ref_store.z, ref_out.z); \
} MACRO_END
-void viewmodel_animate(entity this)
+void calc_followmodel_ofs(entity view)
{
- static float prevtime;
- float frametime = (time - prevtime);
- prevtime = time;
+ if(cl_followmodel_time == time)
+ return; // cl_followmodel_ofs already calculated for this frame
- if (autocvar_chase_active) return;
- if (STAT(HEALTH) <= 0) return;
+ float frac;
+ vector gunorg = '0 0 0';
+ static vector vel_average;
+ static vector gunorg_prev = '0 0 0';
+ static vector gunorg_adjustment_highpass;
+ static vector gunorg_adjustment_lowpass;
+
+ vector vel;
+ if (autocvar_cl_followmodel_velocity_absolute)
+ vel = view.velocity;
+ else
+ {
+ vector forward = '0 0 0', right = '0 0 0', up = '0 0 0';
+ MAKEVECTORS(makevectors, view_angles, forward, right, up);
+ vel.x = view.velocity * forward;
+ vel.y = view.velocity * right * -1;
+ vel.z = view.velocity * up;
+ }
- entity view = CSQCModel_server2csqc(player_localentnum - 1);
+ vel.x = bound(vel_average.x - autocvar_cl_followmodel_limit, vel.x, vel_average.x + autocvar_cl_followmodel_limit);
+ vel.y = bound(vel_average.y - autocvar_cl_followmodel_limit, vel.y, vel_average.y + autocvar_cl_followmodel_limit);
+ vel.z = bound(vel_average.z - autocvar_cl_followmodel_limit, vel.z, vel_average.z + autocvar_cl_followmodel_limit);
- bool clonground = !(view.anim_implicit_state & ANIMIMPLICITSTATE_INAIR);
- static bool oldonground;
- static float hitgroundtime;
- if (clonground)
+ frac = avg_factor(autocvar_cl_followmodel_velocity_lowpass);
+ lowpass3(vel, frac, vel_average, gunorg);
+
+ gunorg *= -autocvar_cl_followmodel_speed * 0.042;
+
+ // perform highpass/lowpass on the adjustment vectors (turning velocity into acceleration!)
+ // trick: we must do the lowpass LAST, so the lowpass vector IS the final vector!
+ frac = avg_factor(autocvar_cl_followmodel_highpass);
+ highpass3(gunorg, frac, gunorg_adjustment_highpass, gunorg);
+ frac = avg_factor(autocvar_cl_followmodel_lowpass);
+ lowpass3(gunorg, frac, gunorg_adjustment_lowpass, gunorg);
+
+ if (autocvar_cl_followmodel_velocity_absolute)
{
- float f = time; // cl.movecmd[0].time
- if (!oldonground)
- hitgroundtime = f;
+ vector fixed_gunorg;
+ vector forward = '0 0 0', right = '0 0 0', up = '0 0 0';
+ MAKEVECTORS(makevectors, view_angles, forward, right, up);
+ fixed_gunorg.x = gunorg * forward;
+ fixed_gunorg.y = gunorg * right * -1;
+ fixed_gunorg.z = gunorg * up;
+ gunorg = fixed_gunorg;
}
- oldonground = clonground;
+ cl_followmodel_ofs = gunorg;
+ cl_followmodel_time = time;
+}
- bool teleported = view.csqcmodel_teleported;
-
+vector leanmodel_ofs(entity view)
+{
float frac;
- if(autocvar_cl_followmodel)
- {
- vector gunorg = '0 0 0';
- static vector vel_average;
- static vector gunorg_prev = '0 0 0';
- static vector gunorg_adjustment_highpass;
- static vector gunorg_adjustment_lowpass;
+ vector gunangles = '0 0 0';
+ static vector gunangles_prev = '0 0 0';
+ static vector gunangles_highpass = '0 0 0';
+ static vector gunangles_adjustment_highpass;
+ static vector gunangles_adjustment_lowpass;
- vector vel;
- if(autocvar_cl_followmodel_velocity_absolute)
- vel = view.velocity;
- else
- {
- vector forward = '0 0 0', right = '0 0 0', up = '0 0 0';
- MAKEVECTORS(makevectors, view_angles, forward, right, up);
- vel.x = view.velocity * forward;
- vel.y = view.velocity * right * -1;
- vel.z = view.velocity * up;
- }
+ if (view.csqcmodel_teleported)
+ gunangles_prev = view_angles;
- vel.x = bound(vel_average.x - autocvar_cl_followmodel_limit, vel.x, vel_average.x + autocvar_cl_followmodel_limit);
- vel.y = bound(vel_average.y - autocvar_cl_followmodel_limit, vel.y, vel_average.y + autocvar_cl_followmodel_limit);
- vel.z = bound(vel_average.z - autocvar_cl_followmodel_limit, vel.z, vel_average.z + autocvar_cl_followmodel_limit);
+ // in the highpass, we _store_ the DIFFERENCE to the actual view angles...
+ gunangles_highpass += gunangles_prev;
+ PITCH(gunangles_highpass) += 360 * floor((PITCH(view_angles) - PITCH(gunangles_highpass)) / 360 + 0.5);
+ YAW(gunangles_highpass) += 360 * floor((YAW(view_angles) - YAW(gunangles_highpass)) / 360 + 0.5);
+ ROLL(gunangles_highpass) += 360 * floor((ROLL(view_angles) - ROLL(gunangles_highpass)) / 360 + 0.5);
+ frac = avg_factor(autocvar_cl_leanmodel_highpass1);
+ highpass2_limited(view_angles, frac, autocvar_cl_leanmodel_limit, gunangles_highpass, gunangles);
+ gunangles_prev = view_angles;
+ gunangles_highpass -= gunangles_prev;
- frac = avg_factor(autocvar_cl_followmodel_velocity_lowpass);
- lowpass3(vel, frac, vel_average, gunorg);
+ PITCH(gunangles) *= -autocvar_cl_leanmodel_speed;
+ YAW(gunangles) *= -autocvar_cl_leanmodel_speed;
- gunorg *= -autocvar_cl_followmodel_speed * 0.042;
+ // we assume here: PITCH = 0, YAW = 1, ROLL = 2
+ frac = avg_factor(autocvar_cl_leanmodel_highpass);
+ highpass2(gunangles, frac, gunangles_adjustment_highpass, gunangles);
+ frac = avg_factor(autocvar_cl_leanmodel_lowpass);
+ lowpass2(gunangles, frac, gunangles_adjustment_lowpass, gunangles);
- // perform highpass/lowpass on the adjustment vectors (turning velocity into acceleration!)
- // trick: we must do the lowpass LAST, so the lowpass vector IS the final vector!
- frac = avg_factor(autocvar_cl_followmodel_highpass);
- highpass3(gunorg, frac, gunorg_adjustment_highpass, gunorg);
- frac = avg_factor(autocvar_cl_followmodel_lowpass);
- lowpass3(gunorg, frac, gunorg_adjustment_lowpass, gunorg);
+ gunangles.x = -gunangles.x; // pitch was inverted, now that actually matters
- if(autocvar_cl_followmodel_velocity_absolute)
- {
- vector fixed_gunorg;
- vector forward = '0 0 0', right = '0 0 0', up = '0 0 0';
- MAKEVECTORS(makevectors, view_angles, forward, right, up);
- fixed_gunorg.x = gunorg * forward;
- fixed_gunorg.y = gunorg * right * -1;
- fixed_gunorg.z = gunorg * up;
- gunorg = fixed_gunorg;
- }
+ return gunangles;
+}
- this.origin += gunorg;
+vector bobmodel_ofs(entity view)
+{
+ bool clonground = !(view.anim_implicit_state & ANIMIMPLICITSTATE_INAIR);
+ static bool oldonground;
+ static float hitgroundtime;
+ if (clonground)
+ {
+ float f = time; // cl.movecmd[0].time
+ if (!oldonground)
+ hitgroundtime = f;
}
+ oldonground = clonground;
- if(autocvar_cl_leanmodel)
+ // calculate for swinging gun model
+ // the gun bobs when running on the ground, but doesn't bob when you're in the air.
+ vector gunorg = '0 0 0';
+ static float bobmodel_scale = 0;
+ static float time_ofs = 0; // makes the effect always restart in the same way
+ if (clonground)
{
- vector gunangles = '0 0 0';
- static vector gunangles_prev = '0 0 0';
- static vector gunangles_highpass = '0 0 0';
- static vector gunangles_adjustment_highpass;
- static vector gunangles_adjustment_lowpass;
+ if (time - hitgroundtime > 0.05)
+ bobmodel_scale = min(1, bobmodel_scale + frametime * 5);
+ }
+ else
+ bobmodel_scale = max(0, bobmodel_scale - frametime * 5);
- if (teleported)
- gunangles_prev = view_angles;
+ float xyspeed = bound(0, vlen(vec2(view.velocity)), 400);
+ if (bobmodel_scale && xyspeed)
+ {
+ float bspeed = xyspeed * 0.01 * autocvar_cl_viewmodel_scale * bobmodel_scale;
+ float s = (time - time_ofs) * autocvar_cl_bobmodel_speed;
+ gunorg.y = bspeed * autocvar_cl_bobmodel_side * sin(s);
+ gunorg.z = bspeed * autocvar_cl_bobmodel_up * cos(s * 2);
+ }
+ else
+ time_ofs = time;
- // in the highpass, we _store_ the DIFFERENCE to the actual view angles...
- gunangles_highpass += gunangles_prev;
- PITCH(gunangles_highpass) += 360 * floor((PITCH(view_angles) - PITCH(gunangles_highpass)) / 360 + 0.5);
- YAW(gunangles_highpass) += 360 * floor((YAW(view_angles) - YAW(gunangles_highpass)) / 360 + 0.5);
- ROLL(gunangles_highpass) += 360 * floor((ROLL(view_angles) - ROLL(gunangles_highpass)) / 360 + 0.5);
- frac = avg_factor(autocvar_cl_leanmodel_highpass1);
- highpass2_limited(view_angles, frac, autocvar_cl_leanmodel_limit, gunangles_highpass, gunangles);
- gunangles_prev = view_angles;
- gunangles_highpass -= gunangles_prev;
+ return gunorg;
+}
- PITCH(gunangles) *= -autocvar_cl_leanmodel_speed;
- YAW(gunangles) *= -autocvar_cl_leanmodel_speed;
+void viewmodel_animate(entity this)
+{
+ if (autocvar_chase_active) return;
+ if (STAT(HEALTH) <= 0) return;
- // we assume here: PITCH = 0, YAW = 1, ROLL = 2
- frac = avg_factor(autocvar_cl_leanmodel_highpass);
- highpass2(gunangles, frac, gunangles_adjustment_highpass, gunangles);
- frac = avg_factor(autocvar_cl_leanmodel_lowpass);
- lowpass2(gunangles, frac, gunangles_adjustment_lowpass, gunangles);
+ entity view = CSQCModel_server2csqc(player_localentnum - 1);
- gunangles.x = -gunangles.x; // pitch was inverted, now that actually matters
- this.angles += gunangles;
+ if (autocvar_cl_followmodel)
+ {
+ calc_followmodel_ofs(view);
+ this.origin += cl_followmodel_ofs;
}
- float xyspeed = bound(0, vlen(vec2(view.velocity)), 400);
+ if (autocvar_cl_leanmodel)
+ this.angles += leanmodel_ofs(view);
// vertical view bobbing code
// TODO: cl_bob
// gun model bobbing code
if (autocvar_cl_bobmodel)
- {
- // calculate for swinging gun model
- // the gun bobs when running on the ground, but doesn't bob when you're in the air.
- static float bobmodel_scale = 0;
- static float time_ofs = 0; // makes the effect always restart in the same way
- if (clonground)
- {
- if (time - hitgroundtime > 0.05)
- bobmodel_scale = min(1, bobmodel_scale + frametime * 5);
- }
- else
- bobmodel_scale = max(0, bobmodel_scale - frametime * 5);
- if(bobmodel_scale && xyspeed)
- {
- float bspeed = xyspeed * 0.01 * autocvar_cl_viewmodel_scale * bobmodel_scale;
- float s = (time - time_ofs) * autocvar_cl_bobmodel_speed;
- vector gunorg = '0 0 0';
- gunorg.y = bspeed * autocvar_cl_bobmodel_side * sin(s);
- gunorg.z = bspeed * autocvar_cl_bobmodel_up * cos(s * 2);
-
- this.origin += gunorg;
- }
- else
- time_ofs = time;
- }
+ this.origin += bobmodel_ofs(view);
}
.vector viewmodel_origin, viewmodel_angles;
void viewmodel_draw(entity this)
{
- if(!activeweapon)
+ if(!activeweapon || !autocvar_r_drawviewmodel)
return;
int mask = (intermission || (STAT(HEALTH) <= 0) || autocvar_chase_active) ? 0 : MASK_NORMAL;
float a = this.alpha;
HUD_Main();
HUD_DrawScoreboard();
+ HUD_Scale_Disable();
}
// crosshair goes VERY LAST
lasthud = hud;
+ HUD_Scale_Disable();
+
if(autocvar__hud_showbinds_reload) // menu can set this one
{
db_close(binddb);
if (pos.z < 0) continue;
pos.z = 0;
pos.y += ofs * sz;
- drawcolorcodedstring2(pos,
+ drawcolorcodedstring2_builtin(pos,
sprintf("%d: '%s'@%s", (it.debug ? it.sv_entnum : etof(it)),
it.classname, it.sourceLoc),
sz * '1 1 0', rgb, 0.5, DRAWFLAG_NORMAL);
HUD_Panel_UpdateCvars();
+ HUD_Scale_Disable();
HUD_Panel_DrawBg(1);
if(panel_bg_padding)
// Required function, draw the game status panel
void bd_hud_status(vector pos, vector mySize)
{
+ HUD_Scale_Disable();
HUD_Panel_DrawBg(1);
vector ts;
ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
// Required function, draw the game status panel
void c4_hud_status(vector pos, vector mySize)
{
+ HUD_Scale_Disable();
HUD_Panel_DrawBg(1);
vector ts;
ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
// Required function, draw the game status panel
void nmm_hud_status(vector pos, vector mySize)
{
+ HUD_Scale_Disable();
HUD_Panel_DrawBg(1);
vector ts;
// Required function, draw the game status panel
void pong_hud_status(vector pos, vector mySize)
{
+ HUD_Scale_Disable();
HUD_Panel_DrawBg(1);
vector ts;
ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
// Required function, draw the game status panel
void pp_hud_status(vector pos, vector mySize)
{
+ HUD_Scale_Disable();
HUD_Panel_DrawBg(1);
vector ts;
ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
// Required function, draw the game status panel
void ps_hud_status(vector pos, vector mySize)
{
+ HUD_Scale_Disable();
HUD_Panel_DrawBg(1);
vector ts;
ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
// Required function, draw the game status panel
void snake_hud_status(vector pos, vector mySize)
{
+ HUD_Scale_Disable();
HUD_Panel_DrawBg(1);
vector ts;
ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
// Required function, draw the game status panel
void ttt_hud_status(vector pos, vector mySize)
{
+ HUD_Scale_Disable();
HUD_Panel_DrawBg(1);
vector ts;
ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
s = strreplace("{health}", sprintf("%d", this.m_damage), s);
s = strreplace("{armor}", sprintf("%d", this.m_armordamage), s);
s = strreplace("{total}", sprintf("%d", this.m_damage + this.m_armordamage), s);
- drawcolorcodedstring2(pos, s, this.m_size * '1 1 0', rgb, this.alpha, DRAWFLAG_NORMAL);
+ drawcolorcodedstring2_builtin(pos, s, this.m_size * '1 1 0', rgb, this.alpha, DRAWFLAG_NORMAL);
}
}
ATTRIB(DamageText, draw2d, void(DamageText), DamageText_draw2d)
}
}
+ HUD_Scale_Enable();
HUD_Panel_DrawBg(1);
float row = 0, column = 0;
string(string name) precache_cubemap = #317;
vector(string picname) draw_getimagesize = #318;
void(string name) freepic = #319;
-float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter = #320;
-float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring = #321;
-float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic = #322;
-float(vector position, vector size, vector rgb, float alpha, float flag) drawfill = #323;
-void(float x, float y, float width, float height) drawsetcliparea = #324;
+float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter_builtin = #320;
+float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring_builtin = #321;
+float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic_builtin = #322;
+float(vector position, vector size, vector rgb, float alpha, float flag) drawfill_builtin = #323;
+void(float x, float y, float width, float height) drawsetcliparea_builtin = #324;
void(void) drawresetcliparea = #325;
-float(vector position, string text, vector scale, float alpha, float flag) drawcolorcodedstring = #326;
-vector(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawcolorcodedstring2 = #326;
+float(vector position, string text, vector scale, float alpha, float flag) drawcolorcodedstring_builtin = #326;
+vector(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawcolorcodedstring2_builtin = #326;
float(float stnum) getstatf = #330;
float(float stnum, ...) getstati = #331; // can optionally take first bit and count
// fix_* parms let you fix badly made fonts by applying some transformations to them
// fix_scale : per-character center-oriented scale (doesn't change line height at all)
// fix_voffset : vertical offset for each character, it's a multiplier to character height
-float stringwidth(string text, float allowColorCodes, vector size) = #327; // get a width of string with given font and char size
+float stringwidth_builtin(string text, float allowColorCodes, vector size) = #327; // get a width of string with given font and char size
float stringwidth_menu(string text, float allowColorCodes, vector size) = #468; // in menu.dat it has different builtin #
//description: engine support for custom fonts in console, hud, qc etc.
// limits:
{
if (theBorderSize.x < 0 && theBorderSize.y < 0) // draw whole image as it is
{
- drawpic(theOrigin, pic, theSize, theColor, theAlpha, 0);
+ drawpic_builtin(theOrigin, pic, theSize, theColor, theAlpha, 0);
return;
}
if (theBorderSize.x == 0 && theBorderSize.y == 0) // no border
void drawstringright(vector position, string text, vector theScale, vector rgb, float theAlpha, int flag)
{
position.x -= 2 / 3 * strlen(text) * theScale.x;
- drawstring(position, text, theScale, rgb, theAlpha, flag);
+ drawstring_builtin(position, text, theScale, rgb, theAlpha, flag);
}
void drawstringcenter(vector position, string text, vector theScale, vector rgb, float theAlpha, int flag)
{
position.x = 0.5 * (vid_conwidth - 0.6025 * strlen(text) * theScale.x);
- drawstring(position, text, theScale, rgb, theAlpha, flag);
+ drawstring_builtin(position, text, theScale, rgb, theAlpha, flag);
}
#endif
#include "sort.qh"
#include "oo.qh"
-#ifndef SVQC
+#ifdef CSQC
+ float stringwidth_colors(string s, vector theSize)
+ {
+ return stringwidth_builtin(s, true, theSize);
+ }
+
+ float stringwidth_nocolors(string s, vector theSize)
+ {
+ return stringwidth_builtin(s, false, theSize);
+ }
+#endif
+#ifdef MENUQC
float stringwidth_colors(string s, vector theSize)
{
return stringwidth(s, true, theSize);
me.TR(me);
me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Damage overlay:")));
me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "hud_damage"));
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeXonoticCheckBox_T(0, "hud_dynamic_follow", _("Dynamic HUD"),
+ _("HUD moves around following player's movement")));
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "hud_dynamic_shake", _("Shake the HUD when hurt")));
me.TR(me);
me.TR(me);
me.TDempty(me, 0.5);