From 24d0565b3e298a395ded4d93480402ea0b11c9e6 Mon Sep 17 00:00:00 2001
From: terencehill <piuntn@gmail.com>
Date: Fri, 4 Mar 2016 20:02:15 +0100
Subject: [PATCH] Shake the HUD when hurt

---
 _hud_common.cfg                |  5 ++++
 qcsrc/client/hud/hud.qc        | 51 ++++++++++++++++++++++++++++++++++
 qcsrc/client/hud/hud.qh        |  5 ++++
 qcsrc/client/hud/hud_config.qc |  1 +
 qcsrc/client/main.qc           |  1 +
 5 files changed, 63 insertions(+)

diff --git a/_hud_common.cfg b/_hud_common.cfg
index e58a449a26..90a363f7a0 100644
--- a/_hud_common.cfg
+++ b/_hud_common.cfg
@@ -66,6 +66,11 @@ seta hud_panel_update_interval 2 "how often (in seconds) common panel cvars are
 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_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"
diff --git a/qcsrc/client/hud/hud.qc b/qcsrc/client/hud/hud.qc
index 6523dfd339..7a526c7ab1 100644
--- a/qcsrc/client/hud/hud.qc
+++ b/qcsrc/client/hud/hud.qc
@@ -451,6 +451,31 @@ void HUD_Reset()
 		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_ofs.x = ((1 - f) * hud_dynamic_shake_x[i] + f * hud_dynamic_shake_x[i+1]) * vid_conwidth * 0.27;
+	hud_dynamic_shake_ofs.y = ((1 - f) * hud_dynamic_shake_y[i] + f * hud_dynamic_shake_y[i+1]) * vid_conheight * 0.27;
+	hud_dynamic_shake_ofs.z = 0;
+	hud_dynamic_shake_ofs *= hud_dynamic_shake_factor * autocvar_hud_dynamic_shake_scale;
+	return true;
+}
+
 void calc_followmodel_ofs(entity view);
 void Hud_Dynamic_Frame()
 {
@@ -465,6 +490,32 @@ void Hud_Dynamic_Frame()
 	if (fabs(hud_dynamic_ofs.x) < 0.001) hud_dynamic_ofs.x = 0;
 	if (fabs(hud_dynamic_ofs.y) < 0.001) hud_dynamic_ofs.y = 0;
 	if (fabs(hud_dynamic_ofs.z) < 0.001) hud_dynamic_ofs.z = 0;
+
+	float health = STAT(HEALTH);
+	if(autocvar_hud_dynamic_shake > 0 && !autocvar__hud_configure && health > 0)
+	{
+		if(hud_dynamic_shake_factor == -1) // don't allow the effect for this frame
+			hud_dynamic_shake_factor = 0;
+		else
+		{
+			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;
+		}
+	}
 }
 
 void HUD_Main()
diff --git a/qcsrc/client/hud/hud.qh b/qcsrc/client/hud/hud.qh
index b80698ccf4..4a3c1f4e3a 100644
--- a/qcsrc/client/hud/hud.qh
+++ b/qcsrc/client/hud/hud.qh
@@ -149,6 +149,10 @@ float current_player;
 float autocvar_hud_dynamic_follow;
 float autocvar_hud_dynamic_follow_scale;
 
+vector hud_dynamic_shake_ofs;
+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;
@@ -393,6 +397,7 @@ REGISTER_HUD_PANEL(QUICKMENU,       HUD_QuickMenu,      quickmenu,      PANEL_CO
 		panel_bg_padding = panel.current_panel_bg_padding;                                                          \
 		panel_fg_alpha = panel.current_panel_fg_alpha * hud_fade_alpha;                                             \
 	}                                                                                                               \
+	if(hud_dynamic_shake_factor > 0) panel_pos += hud_dynamic_shake_ofs; \
 	if(hud_dynamic_ofs.y) panel_pos.x += hud_dynamic_ofs.y * vid_conwidth; \
 	if(hud_dynamic_ofs.z) panel_pos.y += hud_dynamic_ofs.z * vid_conheight; \
 	if(hud_dynamic_ofs.x) { \
diff --git a/qcsrc/client/hud/hud_config.qc b/qcsrc/client/hud/hud_config.qc
index 2ba78f798a..fe1e19cb83 100644
--- a/qcsrc/client/hud/hud_config.qc
+++ b/qcsrc/client/hud/hud_config.qc
@@ -1263,6 +1263,7 @@ void HUD_Configure_Frame()
 			menu_enabled = 0;
 		if(autocvar_hud_cursormode)
 			setcursormode(0);
+		hud_dynamic_shake_factor = -1;
 	}
 }
 
diff --git a/qcsrc/client/main.qc b/qcsrc/client/main.qc
index 14279816ef..5f49537816 100644
--- a/qcsrc/client/main.qc
+++ b/qcsrc/client/main.qc
@@ -540,6 +540,7 @@ NET_HANDLE(ENT_CLIENT_CLIENTDATA, bool isnew)
 		// clear race stuff
 		race_laptime = 0;
 		race_checkpointtime = 0;
+		hud_dynamic_shake_factor = -1;
 	}
 	if (autocvar_hud_panel_healtharmor_progressbar_gfx)
 	{
-- 
2.39.5