From fb83735877a5aced5699155d6394049b2ff1e96a Mon Sep 17 00:00:00 2001
From: Mario <mario.mario@y7mail.com>
Date: Sun, 1 Sep 2013 02:22:26 +1000
Subject: [PATCH] Move monster waypoint handling to the client

---
 monsters.cfg                               |   1 -
 qcsrc/client/autocvars.qh                  |   2 +
 qcsrc/common/monsters/cl_monsters.qc       | 151 ++++++++++++++++++++-
 qcsrc/common/monsters/monster/mage.qc      |   2 +-
 qcsrc/common/monsters/monsters.qh          |  12 +-
 qcsrc/common/monsters/sv_monsters.qc       |  20 +--
 qcsrc/server/autocvars.qh                  |   1 -
 qcsrc/server/command/cmd.qc                |   7 +-
 qcsrc/server/command/sv_cmd.qc             |   2 -
 qcsrc/server/mutators/gamemode_invasion.qc |   2 -
 10 files changed, 163 insertions(+), 37 deletions(-)

diff --git a/monsters.cfg b/monsters.cfg
index 05f6fca8a8..d7bd5c9684 100644
--- a/monsters.cfg
+++ b/monsters.cfg
@@ -170,7 +170,6 @@ set g_monsters_owners 1
 set g_monsters_teams 1
 set g_monsters_spawnshieldtime 2
 set g_monsters_typefrag 1
-set g_monsters_healthbars 1
 set g_monsters_target_range 2000
 set g_monsters_target_infront 0
 set g_monsters_attack_range 120
diff --git a/qcsrc/client/autocvars.qh b/qcsrc/client/autocvars.qh
index 8175695abb..eca2961a21 100644
--- a/qcsrc/client/autocvars.qh
+++ b/qcsrc/client/autocvars.qh
@@ -169,6 +169,8 @@ float autocvar_g_waypointsprite_spam;
 float autocvar_g_waypointsprite_timealphaexponent;
 var float autocvar_g_waypointsprite_turrets = TRUE;
 var float autocvar_g_waypointsprite_turrets_maxdist = 5000;
+var float autocvar_g_waypointsprite_monsters = TRUE;
+var float autocvar_g_waypointsprite_monsters_maxdist = 5000;
 var float autocvar_hud_cursormode = TRUE;
 float autocvar_hud_colorflash_alpha;
 float autocvar_hud_configure_checkcollisions;
diff --git a/qcsrc/common/monsters/cl_monsters.qc b/qcsrc/common/monsters/cl_monsters.qc
index bc02a37a54..ff7e9f7ae0 100644
--- a/qcsrc/common/monsters/cl_monsters.qc
+++ b/qcsrc/common/monsters/cl_monsters.qc
@@ -22,6 +22,151 @@ void monster_die()
 	self.solid = SOLID_CORPSE;
 }
 
+void monster_draw2d()
+{
+	if(self.netname == "")
+		return;
+	
+	if(!autocvar_g_waypointsprite_monsters)
+		return;
+		
+	if(autocvar_cl_hidewaypoints)
+		return;
+		
+	if(self.health <= 0)
+		return;
+
+	float dist = vlen(self.origin - view_origin);
+	float t = (GetPlayerColor(player_localnum) + 1);	
+
+	vector o;
+	string txt;
+	
+	if(autocvar_cl_vehicles_hud_tactical)
+	if(dist < 10240 && t != self.team)
+	{
+		// TODO: Vehicle tactical hud
+		o = project_3d_to_2d(self.origin + '0 0 32');
+		if(o_z < 0 
+		|| o_x < (vid_conwidth * waypointsprite_edgeoffset_left) 
+		|| o_y < (vid_conheight * waypointsprite_edgeoffset_top) 
+		|| o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))  
+		|| o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
+			return; // Dont draw wp's for monsters out of view
+		o_z = 0;
+		if(hud != HUD_NORMAL)
+		{		
+			switch(hud)
+			{
+				case HUD_SPIDERBOT:
+				case HUD_WAKIZASHI:
+				case HUD_RAPTOR:
+				case HUD_BUMBLEBEE:  
+					vector pz = drawgetimagesize("gfx/vehicles/vth-mover.tga") * 0.25;
+					drawpic(o - pz * 0.5, "gfx/vehicles/vth-mover.tga", pz , '1 1 1', 0.75, DRAWFLAG_NORMAL);
+					break;
+			}
+		}
+	}
+	
+	if(dist > self.maxdistance)
+		return;
+
+	string spriteimage = self.netname;
+	float a = self.alpha * autocvar_hud_panel_fg_alpha;
+	vector rgb = spritelookupcolor(spriteimage, self.teamradar_color);
+
+	
+	if(self.maxdistance > waypointsprite_normdistance)
+		a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
+	else if(self.maxdistance > 0)
+		a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
+
+	if(rgb == '0 0 0')
+	{
+		self.teamradar_color = '1 0 0';
+		print(sprintf("WARNING: sprite of name %s has no color, using red so you notice it\n", spriteimage)); 
+	}
+
+	txt = self.netname;
+	if(autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
+		txt = _("Spam");
+	else
+		txt = spritelookuptext(spriteimage);
+	
+	if(autocvar_g_waypointsprite_uppercase)
+		txt = strtoupper(txt);
+
+	if(a > 1)
+	{
+		rgb *= a;
+		a = 1;
+	}
+
+	if(a <= 0)
+		return;
+		
+	rgb = fixrgbexcess(rgb);
+
+	o = project_3d_to_2d(self.origin + '0 0 64');
+	if(o_z < 0 
+	|| o_x < (vid_conwidth * waypointsprite_edgeoffset_left) 
+	|| o_y < (vid_conheight * waypointsprite_edgeoffset_top) 
+	|| o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))  
+	|| o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
+		return; // Dont draw wp's for monsters out of view
+
+	o_z = 0;
+
+	float edgedistance_min, crosshairdistance;
+		edgedistance_min = min((o_y - (vid_conheight * waypointsprite_edgeoffset_top)), 
+	(o_x - (vid_conwidth * waypointsprite_edgeoffset_left)),
+	(vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right)) - o_x, 
+	(vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)) - o_y);
+
+	float vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
+
+	crosshairdistance = sqrt( pow(o_x - vid_conwidth/2, 2) + pow(o_y - vid_conheight/2, 2) );
+
+	t = waypointsprite_scale * vidscale;
+	a *= waypointsprite_alpha;
+
+	{
+		a = a * (1 - (1 - waypointsprite_distancefadealpha) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
+		t = t * (1 - (1 - waypointsprite_distancefadescale) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
+	}
+	if (edgedistance_min < waypointsprite_edgefadedistance) {
+		a = a * (1 - (1 - waypointsprite_edgefadealpha) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
+		t = t * (1 - (1 - waypointsprite_edgefadescale) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
+	}
+	if(crosshairdistance < waypointsprite_crosshairfadedistance) {
+		a = a * (1 - (1 - waypointsprite_crosshairfadealpha) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
+		t = t * (1 - (1 - waypointsprite_crosshairfadescale) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
+	}
+
+	draw_beginBoldFont();
+	o = drawspritearrow(o, M_PI, rgb, a, SPRITE_ARROW_SCALE * t);		
+	o = drawspritetext(o, M_PI, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
+	drawhealthbar(
+			o,
+			0,
+			self.health / 255,
+			'0 0 0',
+			'0 0 0',
+			0.5 * SPRITE_HEALTHBAR_WIDTH * t,
+			0.5 * SPRITE_HEALTHBAR_HEIGHT * t,
+			SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize,
+			SPRITE_HEALTHBAR_BORDER * t,
+			0,
+			rgb,
+			a * SPRITE_HEALTHBAR_BORDERALPHA,
+			rgb,
+			a * SPRITE_HEALTHBAR_HEALTHALPHA,
+			DRAWFLAG_NORMAL
+			);
+	draw_endBoldFont();
+}
+
 void monster_draw()
 {
 	float dt;
@@ -30,7 +175,7 @@ void monster_draw()
 	self.move_time = time;
 	if(dt <= 0)
 		return;
-    
+	
 	fixedmakevectors(self.angles);
 	//movelib_groundalign4point(50, 25, 0.25, 45);
 	setorigin(self, self.origin + self.velocity * dt);
@@ -58,7 +203,11 @@ void monster_construct()
 	self.move_time		= time;
 	self.drawmask		= MASK_NORMAL;
 	self.alpha			= 1;
+	self.gravity		= 1;
 	self.draw			= monster_draw;
+	self.draw2d			= monster_draw2d;
+	self.maxdistance	= autocvar_g_waypointsprite_monsters_maxdist;
+	self.teamradar_color = '1 0 0';
 }
 
 void ent_monster()
diff --git a/qcsrc/common/monsters/monster/mage.qc b/qcsrc/common/monsters/monster/mage.qc
index 8bb3da3d2a..f6140c6614 100644
--- a/qcsrc/common/monsters/monster/mage.qc
+++ b/qcsrc/common/monsters/monster/mage.qc
@@ -292,7 +292,7 @@ void mage_heal()
 		{
 			pointparticles(particleeffectnum("healing_fx"), head.origin, '0 0 0', 1);
 			head.health = bound(0, head.health + MON_CVAR(mage, heal_allies), head.max_health);
-			WaypointSprite_UpdateHealth(head.sprite, head.health);
+			self.SendFlags |= MSF_STATUS;
 		}
 	}
 	
diff --git a/qcsrc/common/monsters/monsters.qh b/qcsrc/common/monsters/monsters.qh
index 0c9d4b8888..b070a181cc 100644
--- a/qcsrc/common/monsters/monsters.qh
+++ b/qcsrc/common/monsters/monsters.qh
@@ -28,12 +28,12 @@ const float MON_FLAG_SUPERMONSTER = 2048; // incredibly powerful monster
 #ifndef MENUQC
 .float anim_start_time;
 
-float MSF_UPDATE       = 2;
-float MSF_STATUS       = 4;
-float MSF_SETUP        = 8;
-float MSF_ANG          = 16;
-float MSF_MOVE         = 32;
-float MSF_ANIM         = 64;
+float MSF_UPDATE		= 2;
+float MSF_STATUS		= 4;
+float MSF_SETUP			= 8;
+float MSF_ANG			= 16;
+float MSF_MOVE			= 32;
+float MSF_ANIM			= 64;
 
 float MSF_FULL_UPDATE  = 16777215;
 #endif
diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc
index 5760dad4fa..f8858cd4eb 100644
--- a/qcsrc/common/monsters/sv_monsters.qc
+++ b/qcsrc/common/monsters/sv_monsters.qc
@@ -449,7 +449,7 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
 		self.revive_progress = bound(0, self.revive_progress + frametime * self.revive_speed, 1);
 		self.health = max(1, self.max_health * self.revive_progress);
 		
-		if(self.sprite) WaypointSprite_UpdateHealth(self.sprite, self.health);
+		self.SendFlags |= MSF_STATUS;
 			
 		movelib_beak_simple(stopspeed);
 			
@@ -695,7 +695,7 @@ void monsters_reset()
 	self.attack_finished_single = 0;
 	self.moveto = self.origin;
 	
-	WaypointSprite_UpdateHealth(self.sprite, self.health);
+	self.SendFlags |= MSF_STATUS;
 }
 
 float monster_send(entity to, float sf)
@@ -788,8 +788,6 @@ void monster_die()
 	self.ltime = time + 5;
 	
 	monster_dropitem();
-
-	WaypointSprite_Kill(self.sprite);
 		
 	if(self.weaponentity)
 	{
@@ -845,9 +843,6 @@ void monsters_damage (entity inflictor, entity attacker, float damage, float dea
 		self.weaponentity.health -= damage;
 		
 	self.health -= damage;
-	
-	if(self.sprite)
-		WaypointSprite_UpdateHealth(self.sprite, self.health);
 		
 	self.dmg_time = time;
 
@@ -867,10 +862,6 @@ void monsters_damage (entity inflictor, entity attacker, float damage, float dea
 		
 	if(self.health <= 0)
 	{
-		// Update one more time to avoid waypoint fading without emptying healthbar
-		if(self.sprite)
-			WaypointSprite_UpdateHealth(self.sprite, 0);
-		
 		if(deathtype == DEATH_KILL)
 			self.candrop = FALSE; // killed by mobkill command
 			
@@ -939,13 +930,6 @@ void monster_spawn()
 	
 	if(teamplay)
 		self.monster_attack = TRUE; // we can have monster enemies in team games
-		
-	if(autocvar_g_monsters_healthbars)
-	{
-		WaypointSprite_Spawn(strzone(strdecolorize(self.monster_name)), 0, 600, self, '0 0 1' * (self.maxs_z + 15), world, 0, self, sprite, FALSE, RADARICON_DANGER, ((self.team) ? Team_ColorRGB(self.team) : '1 0 0'));	
-		WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
-		WaypointSprite_UpdateHealth(self.sprite, self.health);
-	}
 	
 	monster_sound(self.msound_spawn, 0, FALSE);
 
diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh
index adeccc73cd..264d55408c 100644
--- a/qcsrc/server/autocvars.qh
+++ b/qcsrc/server/autocvars.qh
@@ -1243,7 +1243,6 @@ float autocvar_g_monsters_miniboss_healthboost;
 float autocvar_g_monsters_drop_time;
 float autocvar_g_monsters_spawnshieldtime;
 float autocvar_g_monsters_teams;
-float autocvar_g_monsters_healthbars;
 float autocvar_g_monsters_respawn_delay;
 float autocvar_g_monsters_respawn;
 float autocvar_g_touchexplode_radius;
diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc
index 68b1457fcb..88801e125d 100644
--- a/qcsrc/server/command/cmd.qc
+++ b/qcsrc/server/command/cmd.qc
@@ -196,7 +196,6 @@ void ClientCommand_mobedit(float request, float argc)
 			
 			switch(argv(1))
 			{
-				case "name": trace_ent.monster_name = strzone(strdecolorize(argv(2))); if(trace_ent.sprite) WaypointSprite_UpdateSprites(trace_ent.sprite, trace_ent.monster_name, "", ""); return;
 				case "skin": if(trace_ent.monsterid != MON_MAGE) { trace_ent.skin = stof(argv(2)); trace_ent.SendFlags |= MSF_STATUS; } return;
 				case "movetarget": trace_ent.monster_moveflags = stof(argv(2)); return;
 			}
@@ -206,7 +205,7 @@ void ClientCommand_mobedit(float request, float argc)
 		case CMD_REQUEST_USAGE:
 		{
 			sprint(self, "\nUsage:^3 cmd mobedit [argument]\n");
-			sprint(self, "  Where 'argument' can be name, color or movetarget.\n");
+			sprint(self, "  Where 'argument' can be skin or movetarget.\n");
 			return;
 		}
 	}
@@ -256,12 +255,11 @@ void ClientCommand_mobspawn(float request, float argc)
 		case CMD_REQUEST_COMMAND:
 		{
 			entity e;
-			string tospawn, mname;
+			string tospawn;
 			float moveflag;
 			
 			moveflag = (argv(2) ? stof(argv(2)) : 1); // follow owner if not defined
 			tospawn = strtolower(argv(1));
-			mname = argv(3);
 			
 			if(tospawn == "list")
 			{
@@ -295,7 +293,6 @@ void ClientCommand_mobspawn(float request, float argc)
 				//WarpZone_TraceLine(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * 150, MOVE_NORMAL, self);
 			
 				e = spawnmonster(tospawn, 0, self, self, trace_endpos, FALSE, moveflag);
-				if(mname) e.monster_name = strzone(mname);
 				
 				sprint(self, strcat("Spawned ", e.monster_name, "\n"));
 			}
diff --git a/qcsrc/server/command/sv_cmd.qc b/qcsrc/server/command/sv_cmd.qc
index 508dd17860..569480b5c7 100644
--- a/qcsrc/server/command/sv_cmd.qc
+++ b/qcsrc/server/command/sv_cmd.qc
@@ -153,8 +153,6 @@ void GameCommand_butcher(float request)
 			
 			FOR_EACH_MONSTER(head)
 			{
-				WaypointSprite_Kill(head.sprite);
-				
 				if(head.weaponentity)
 					remove(head.weaponentity);
 					
diff --git a/qcsrc/server/mutators/gamemode_invasion.qc b/qcsrc/server/mutators/gamemode_invasion.qc
index 3355a7c7d2..af717a1385 100644
--- a/qcsrc/server/mutators/gamemode_invasion.qc
+++ b/qcsrc/server/mutators/gamemode_invasion.qc
@@ -68,7 +68,6 @@ float Invasion_CheckWinner()
 	{
 		FOR_EACH_MONSTER(head)
 		{
-			WaypointSprite_Kill(head.sprite);
 			if(head.weaponentity) remove(head.weaponentity);
 			if(head.iceblock) remove(head.iceblock);
 			remove(head);
@@ -183,7 +182,6 @@ MUTATOR_HOOKFUNCTION(invasion_MonsterSpawn)
 {
 	if(self.realowner == world)
 	{
-		WaypointSprite_Kill(self.sprite);
 		if(self.weaponentity) remove(self.weaponentity);
 		if(self.iceblock) remove(self.iceblock);
 		remove(self);
-- 
2.39.5