From: David Banks <amoebae@gmail.com>
Date: Wed, 14 Jan 2015 21:41:00 +0000
Subject: Avoid double-counting rotfish

Bug: https://sourceforge.net/p/quakespasm/bugs/7/
---
 Quake/pr_edict.c | 20 ++++++++++++++++++++
 Quake/progs.h    |  1 +
 Quake/server.h   |  1 +
 Quake/sv_main.c  |  2 ++
 Quake/sv_phys.c  | 25 ++++++++++++++++++++++++-
 5 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/Quake/pr_edict.c b/Quake/pr_edict.c
index d414516..a4d7a80 100644
--- a/Quake/pr_edict.c
+++ b/Quake/pr_edict.c
@@ -83,6 +83,7 @@ cvar_t	saved1 = {"saved1", "0", CVAR_ARCHIVE};
 cvar_t	saved2 = {"saved2", "0", CVAR_ARCHIVE};
 cvar_t	saved3 = {"saved3", "0", CVAR_ARCHIVE};
 cvar_t	saved4 = {"saved4", "0", CVAR_ARCHIVE};
+extern cvar_t sv_fishfix;
 
 /*
 =================
@@ -974,6 +975,8 @@ void ED_LoadFromFile (const char *data)
 	dfunction_t	*func;
 	edict_t		*ent = NULL;
 	int		inhibit = 0;
+	int oldcount;
+	sv.fish_counted = false;
 
 	pr_global_struct->time = sv.time;
 
@@ -1035,7 +1038,20 @@ void ED_LoadFromFile (const char *data)
 		}
 
 		pr_global_struct->self = EDICT_TO_PROG(ent);
+
+		if (!sv.fish_counted && sv_fishfix.value && !strcmp(PR_GetString(func->s_name), "monster_fish"))
+		{
+			oldcount = pr_global_struct->total_monsters;
+		}
+		else oldcount = -1;
+
 		PR_ExecuteProgram (func - pr_functions);
+
+		if (oldcount != -1)
+		{
+			if (pr_global_struct->total_monsters > oldcount)
+				sv.fish_counted = true;
+		}
 	}
 
 	Con_DPrintf ("%i entities inhibited\n", inhibit);
@@ -1315,6 +1331,10 @@ const char *PR_GetString (int num)
 	}
 }
 
+const char *PR_GetFunctionName(int num) {
+	return PR_GetString(pr_functions[num].s_name);
+}
+
 int PR_SetEngineString (const char *s)
 {
 	int		i;
diff --git a/Quake/progs.h b/Quake/progs.h
index 8a15416..efd8967 100644
--- a/Quake/progs.h
+++ b/Quake/progs.h
@@ -74,6 +74,7 @@ void PR_ExecuteProgram (func_t fnum);
 void PR_LoadProgs (void);
 
 const char *PR_GetString (int num);
+const char *PR_GetFunctionName (int num);
 int PR_SetEngineString (const char *s);
 int PR_AllocString (int bufferlength, char **ptr);
 
diff --git a/Quake/server.h b/Quake/server.h
index 701cdd7..fc8868b 100644
--- a/Quake/server.h
+++ b/Quake/server.h
@@ -75,6 +75,7 @@ typedef struct
 
 	unsigned	protocol; //johnfitz
 	unsigned	protocolflags;
+	int		fish_counted;
 } server_t;
 
 
diff --git a/Quake/sv_main.c b/Quake/sv_main.c
index 1b98eef..5e41471 100644
--- a/Quake/sv_main.c
+++ b/Quake/sv_main.c
@@ -87,6 +87,7 @@ void SV_Init (void)
 	extern	cvar_t	sv_idealpitchscale;
 	extern	cvar_t	sv_aim;
 	extern	cvar_t	sv_altnoclip; //johnfitz
+	extern  cvar_t  sv_fishfix;
 
 	sv.edicts = NULL; // ericw -- sv.edicts switched to use malloc()
 
@@ -105,6 +106,7 @@ void SV_Init (void)
 	Cvar_RegisterVariable (&sv_nostep);
 	Cvar_RegisterVariable (&sv_freezenonclients);
 	Cvar_RegisterVariable (&sv_altnoclip); //johnfitz
+	Cvar_RegisterVariable (&sv_fishfix);
 
 	Cmd_AddCommand ("sv_protocol", &SV_Protocol_f); //johnfitz
 
diff --git a/Quake/sv_phys.c b/Quake/sv_phys.c
index dfff66c..3ea60ac 100644
--- a/Quake/sv_phys.c
+++ b/Quake/sv_phys.c
@@ -47,7 +47,7 @@ cvar_t	sv_gravity = {"sv_gravity","800",CVAR_NOTIFY|CVAR_SERVERINFO};
 cvar_t	sv_maxvelocity = {"sv_maxvelocity","2000",CVAR_NONE};
 cvar_t	sv_nostep = {"sv_nostep","0",CVAR_NONE};
 cvar_t	sv_freezenonclients = {"sv_freezenonclients","0",CVAR_NONE};
-
+cvar_t	sv_fishfix = {"sv_fishfix", "1", CVAR_ARCHIVE};
 
 #define	MOVE_EPSILON	0.01
 
@@ -125,6 +125,7 @@ qboolean SV_RunThink (edict_t *ent)
 	float	thinktime;
 	float	oldframe; //johnfitz
 	int		i; //johnfitz
+	int oldcount;
 
 	thinktime = ent->v.nextthink;
 	if (thinktime <= 0 || thinktime > sv.time + host_frametime)
@@ -141,8 +142,30 @@ qboolean SV_RunThink (edict_t *ent)
 	pr_global_struct->time = thinktime;
 	pr_global_struct->self = EDICT_TO_PROG(ent);
 	pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
+
+	if ((sv.time == 1.0) && sv_fishfix.value && sv.fish_counted &&
+	    !strcmp(PR_GetString(ent->v.classname), "monster_fish") &&
+	    !strcmp(PR_GetFunctionName(ent->v.think), "swimmonster_start_go"))
+	{
+		oldcount = pr_global_struct->total_monsters;
+	}
+	else oldcount = -1;
+
 	PR_ExecuteProgram (ent->v.think);
 
+	if (oldcount != -1)
+	{
+		if (pr_global_struct->total_monsters - oldcount == 1)
+		{
+			pr_global_struct->total_monsters -= 1;
+			if (sv.fish_counted == 1)
+			{
+				Con_Printf ("Detected fish-count bug in progs.dat; monster count has been adjusted\n");
+				sv.fish_counted++;
+			}
+		}
+	}
+
 //johnfitz -- PROTOCOL_FITZQUAKE
 //capture interval to nextthink here and send it to client for better
 //lerp timing, but only if interval is not 0.1 (which client assumes)
