From b5b74f252950aa64b1f4f3e937fc5058533c1c49 Mon Sep 17 00:00:00 2001
From: Spoike <acceptthis@users.sourceforge.net>
Date: Thu, 23 Mar 2006 19:22:12 +0000
Subject: [PATCH] Rotating BSP fixes, hexen2 fixes, and a few extra bugs...

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2134 fc73d0e0-1445-4013-8a0c-d673dee63da5
---
 engine/client/cl_ents.c      |  3 +-
 engine/client/pr_menu.c      |  3 ++
 engine/common/cvar.c         |  8 +++-
 engine/common/net_wins.c     | 40 +++++++++---------
 engine/common/pmovetst.c     |  6 +--
 engine/ftequake/ftequake.dsp |  2 +
 engine/gl/gl_model.c         |  2 +-
 engine/gl/gl_ppl.c           | 15 ++++++-
 engine/gl/gl_rlight.c        |  7 ++++
 engine/gl/gl_rsurf.c         | 12 ++++++
 engine/qclib/qcc_pr_comp.c   |  6 ++-
 engine/qclib/qcc_pr_lex.c    | 18 +++++++-
 engine/server/pr_cmds.c      | 32 ++++++++++++++-
 engine/server/q3g_public.h   |  7 ++--
 engine/server/sv_chat.c      |  5 ++-
 engine/server/sv_ents.c      |  2 -
 engine/server/sv_init.c      |  9 +++-
 engine/server/sv_main.c      |  6 +++
 engine/server/sv_move.c      |  3 ++
 engine/server/sv_mvd.c       |  6 +--
 engine/server/world.c        | 80 +++++++++++++++++++++++-------------
 21 files changed, 203 insertions(+), 69 deletions(-)

diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c
index 08a3949bc..1fdbb311c 100644
--- a/engine/client/cl_ents.c
+++ b/engine/client/cl_ents.c
@@ -1742,7 +1742,8 @@ void CL_LinkPacketEntities (void)
 		}
 
 		VectorCopy(angles, ent->angles);
-		angles[0]*=-1;
+		if (model && model->type == mod_alias)
+			angles[0]*=-1;	//carmack screwed up when he added alias models - they pitch the wrong way.
 		AngleVectors(angles, ent->axis[0], ent->axis[1], ent->axis[2]);
 		VectorInverse(ent->axis[1]);
 
diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c
index 997508b67..58c93b50b 100644
--- a/engine/client/pr_menu.c
+++ b/engine/client/pr_menu.c
@@ -544,6 +544,9 @@ void PF_CL_drawgetimagesize (progfuncs_t *prinst, struct globalvars_s *pr_global
 
 	float *ret = G_VECTOR(OFS_RETURN);
 
+	if (!p)
+		p = Draw_SafeCachePic(va("%s.tga", picname));
+
 	if (p)
 	{
 		ret[0] = p->width;
diff --git a/engine/common/cvar.c b/engine/common/cvar.c
index 75a833f17..17406d7a8 100644
--- a/engine/common/cvar.c
+++ b/engine/common/cvar.c
@@ -686,7 +686,7 @@ cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
 	}
 #endif
 
-	latch = var->string;
+	latch = var->string;//save off the old value (so cvar_set(var, var->string) works)
 
 	var->string = (char*)Z_Malloc (Q_strlen(value)+1);
 	Q_strcpy (var->string, value);
@@ -920,13 +920,19 @@ void Cvar_RegisterVariable (cvar_t *variable)
 cvar_t *Cvar_Get(const char *name, const char *defaultvalue, int flags, const char *group)
 {
 	cvar_t *var;
+	int old;
 	var = Cvar_FindVar(name);
 
 	if (var)
 	{
 		//allow this to change all < cvar_latch values.
 		//this allows q2 dlls to apply different flags to a cvar without destroying our important ones (like cheat).
+		old = var->flags;
 		var->flags = (var->flags & ~(CVAR_NOSET)) | (flags & (CVAR_NOSET|CVAR_SERVERINFO|CVAR_USERINFO|CVAR_ARCHIVE));
+		if (old != var->flags)
+		{
+			Cvar_Set(var, var->string);
+		}
 		return var;
 	}
 
diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c
index d8d2316d1..459320a7b 100644
--- a/engine/common/net_wins.c
+++ b/engine/common/net_wins.c
@@ -1765,24 +1765,26 @@ vfsfile_t *FS_OpenTCP(char *name)
 {
 	tcpfile_t *newf;
 	int sock;
-	netadr_t adr;
-	if (!NET_StringToAdr(name, &adr))
+	netadr_t adr = {0};
+	if (NET_StringToAdr(name, &adr))
+	{
+		sock = TCP_OpenStream(adr);
+		if (sock == INVALID_SOCKET)
+			return NULL;
+
+		newf = Z_Malloc(sizeof(*newf));
+		newf->sock = sock;
+		newf->funcs.Close = VFSTCP_Close;
+		newf->funcs.Flush = NULL;
+		newf->funcs.GetLen = VFSTCP_GetLen;
+		newf->funcs.ReadBytes = VFSTCP_ReadBytes;
+		newf->funcs.Seek = VFSTCP_Seek;
+		newf->funcs.Tell = VFSTCP_Tell;
+		newf->funcs.WriteBytes = VFSTCP_WriteBytes;
+		newf->funcs.seekingisabadplan = true;
+
+		return &newf->funcs;
+	}
+	else
 		return NULL;
-
-	sock = TCP_OpenStream(adr);
-	if (sock == INVALID_SOCKET)
-		return NULL;
-
-	newf = Z_Malloc(sizeof(*newf));
-	newf->sock = sock;
-	newf->funcs.Close = VFSTCP_Close;
-	newf->funcs.Flush = NULL;
-	newf->funcs.GetLen = VFSTCP_GetLen;
-	newf->funcs.ReadBytes = VFSTCP_ReadBytes;
-	newf->funcs.Seek = VFSTCP_Seek;
-	newf->funcs.Tell = VFSTCP_Tell;
-	newf->funcs.WriteBytes = VFSTCP_WriteBytes;
-	newf->funcs.seekingisabadplan = true;
-
-	return &newf->funcs;
 }
diff --git a/engine/common/pmovetst.c b/engine/common/pmovetst.c
index 3b9b4878b..869cbf964 100644
--- a/engine/common/pmovetst.c
+++ b/engine/common/pmovetst.c
@@ -199,9 +199,9 @@ qboolean PM_TransformedHullCheck (model_t *model, vec3_t start, vec3_t end, trac
 
 		if (trace->fraction != 1.0)
 		{
-			a[0] = angles[0];
-			a[1] = angles[1];
-			a[2] = angles[2];
+			a[0] = -angles[0];
+			a[1] = -angles[1];
+			a[2] = -angles[2];
 			AngleVectors (a, forward, right, up);
 
 			VectorCopy (trace->plane.normal, temp);
diff --git a/engine/ftequake/ftequake.dsp b/engine/ftequake/ftequake.dsp
index 7e2561f63..85ae63635 100644
--- a/engine/ftequake/ftequake.dsp
+++ b/engine/ftequake/ftequake.dsp
@@ -3064,6 +3064,8 @@ SOURCE=..\gl\gl_bloom.c
 
 !ELSEIF  "$(CFG)" == "ftequake - Win32 Debug Dedicated Server"
 
+# PROP Exclude_From_Build 1
+
 !ELSEIF  "$(CFG)" == "ftequake - Win32 Release Dedicated Server"
 
 # PROP Exclude_From_Build 1
diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c
index 30d6165a5..391b5a73c 100644
--- a/engine/gl/gl_model.c
+++ b/engine/gl/gl_model.c
@@ -2194,7 +2194,7 @@ qboolean GLMod_LoadClipnodes (lump_t *l)
 		hull->planes = loadmodel->planes;
 		hull->clip_mins[0] = -48;
 		hull->clip_mins[1] = -48;
-		hull->clip_mins[2] = -50;
+		hull->clip_mins[2] = -50 - 24;
 		hull->clip_maxs[0] = 48;
 		hull->clip_maxs[1] = 48;
 		hull->clip_maxs[2] = 50;
diff --git a/engine/gl/gl_ppl.c b/engine/gl/gl_ppl.c
index d40c5b357..eb105efa1 100644
--- a/engine/gl/gl_ppl.c
+++ b/engine/gl/gl_ppl.c
@@ -1731,12 +1731,25 @@ void PPL_BaseBModelTextures(entity_t *e)
 	currentmodel = model = e->model;
 	s = model->surfaces+model->firstmodelsurface;
 
-	GL_TexEnv(GL_MODULATE);
+	if (currententity->drawflags & DRF_TRANSLUCENT)
+		currententity->shaderRGBAf[3]=0.5;
+	if ((currententity->drawflags & MLS_ABSLIGHT) == MLS_ABSLIGHT)
+	{
+		currententity->shaderRGBAf[0] =
+		currententity->shaderRGBAf[1] =
+		currententity->shaderRGBAf[2] = currententity->abslight/255.0f;
+	}
 
 	if (currententity->shaderRGBAf[3]<1)
+	{
+		GL_TexEnv(GL_MODULATE);
 		qglEnable(GL_BLEND);
+	}
 	else
+	{
+		GL_TexEnv(GL_REPLACE);
 		qglDisable(GL_BLEND);
+	}
 
 	qglColor4fv(currententity->shaderRGBAf);
 
diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c
index fe409933f..6dcc85c10 100644
--- a/engine/gl/gl_rlight.c
+++ b/engine/gl/gl_rlight.c
@@ -711,6 +711,13 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end)
 	float	scale;
 	int			maps;
 
+	if (!cl.worldmodel->lightdata)
+	{
+		l[0]=255;l[1]=255;l[2]=255;
+		l[3]=0;l[4]=1;l[5]=1;
+		return l;
+	}
+
 	if (cl.worldmodel->fromgame == fg_quake2)
 	{
 		if (node->contents != -1)
diff --git a/engine/gl/gl_rsurf.c b/engine/gl/gl_rsurf.c
index fbf07d068..3efce90cd 100644
--- a/engine/gl/gl_rsurf.c
+++ b/engine/gl/gl_rsurf.c
@@ -259,6 +259,18 @@ void GLR_AddStain(vec3_t org, float red, float green, float blue, float radius)
 			parms[1] = org[0] - pe->origin[0];
 			parms[2] = org[1] - pe->origin[1];
 			parms[3] = org[2] - pe->origin[2];
+
+			if (pe->angles[0] || pe->angles[1] || pe->angles[2])
+			{
+				vec3_t f, r, u, temp;
+				AngleVectors(pe->angles, f, r, u);
+				VectorCopy((parms+1), temp);
+				parms[1] = DotProduct(temp, f);
+				parms[2] = -DotProduct(temp, r);
+				parms[3] = DotProduct(temp, u);
+			}
+
+
 			pe->model->funcs.StainNode(pe->model->nodes+pe->model->hulls[0].firstclipnode, parms);
 		}
 	}
diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c
index 116be824d..3f79e7702 100644
--- a/engine/qclib/qcc_pr_comp.c
+++ b/engine/qclib/qcc_pr_comp.c
@@ -2674,9 +2674,13 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *func)	//warning, the func could
 							e = QCC_PR_Statement(pr_opcodes+OP_CONV_FTOI, e, NULL, NULL);
 						else if (p->type == ev_float && e->type->type == ev_integer)	//convert float -> int... is this a constant?
 							e = QCC_PR_Statement(pr_opcodes+OP_CONV_ITOF, e, NULL, NULL);
+						else if (p->type == ev_function && e->type->type == ev_integer && e->constant && !((int*)qcc_pr_globals)[e->ofs])
+						{	//you're allowed to use int 0 to pass a null function pointer
+							//this is basically because __NULL__ is defined as ~0 (int 0)
+						}
 						else if (p->type != ev_variant)	//can cast to variant whatever happens
 						{
-							if (flag_laxcasts)
+							if (flag_laxcasts || (p->type == ev_function && e->type->type == ev_function))
 							{
 								QCC_PR_ParseWarning(WARN_LAXCAST, "type mismatch on parm %i - (%s should be %s)", arg+1, TypeName(e->type), TypeName(p));
 								QCC_PR_ParsePrintDef(WARN_LAXCAST, func);
diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c
index 7656334d7..decee9c6f 100644
--- a/engine/qclib/qcc_pr_lex.c
+++ b/engine/qclib/qcc_pr_lex.c
@@ -162,18 +162,34 @@ void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath)
 {
 	char fullname[10248];
 	char *stripfrom;
+	int doubledots;
 
 	char *end = fullname;
 
 	if (!*newfile)
 		return;
 
+	doubledots = 0;
+	while(!strncmp(newfile, "../", 3) || !strncmp(newfile, "..\\", 3))
+	{
+		newfile+=3;
+		doubledots++;
+	}
+
 	currentfile += strlen(rootpath);	//could this be bad?
 
 	for(stripfrom = currentfile+strlen(currentfile)-1; stripfrom>currentfile; stripfrom--)
 	{
 		if (*stripfrom == '/' || *stripfrom == '\\')
-			break;
+		{
+			if (doubledots>0)
+				doubledots--;
+			else
+			{
+				stripfrom++;
+				break;
+			}
+		}
 	}
 	strcpy(end, rootpath); end = end+strlen(end);
 	if (*fullname && end[-1] != '/')
diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c
index 4282dcd63..69d283e70 100644
--- a/engine/server/pr_cmds.c
+++ b/engine/server/pr_cmds.c
@@ -114,6 +114,7 @@ func_t pr_SV_ShouldPause;
 
 func_t SV_PlayerPhysicsQC;	//DP's DP_SV_PLAYERPHYSICS extension
 func_t EndFrameQC;
+func_t pr_ClassChangeWeapon;
 
 qboolean pr_items2;
 
@@ -540,6 +541,7 @@ void PR_LoadGlabalStruct(void)
 
 	pr_SV_PausedTic = PR_FindFunction(svprogfuncs, "SV_PausedTic", PR_ANY);
 	pr_SV_ShouldPause = PR_FindFunction(svprogfuncs, "SV_ShouldPause", PR_ANY);
+	pr_ClassChangeWeapon = PR_FindFunction(svprogfuncs, "ClassChangeWeapon", PR_ANY);
 
 	if (pr_no_playerphysics.value)
 		SV_PlayerPhysicsQC = 0;
@@ -1262,7 +1264,7 @@ void Q_InitProgs(void)
 				if (f)
 				{
 					pr_globals = PR_globals(svprogfuncs, PR_CURRENT);
-					G_INT(OFS_PARM0) = (int)PR_SetString(svprogfuncs, as);
+					G_INT(OFS_PARM0) = (int)PR_SetString(svprogfuncs, sv_addon[i2].string);
 					PR_ExecuteProgram (svprogfuncs, f);
 				}
 				else
@@ -1328,7 +1330,7 @@ qboolean PR_ShouldTogglePause(client_t *initiator, qboolean newpaused)
 	globalvars_t *pr_globals;
 
 	if (!svprogfuncs || !pr_SV_ShouldPause)
-		return false;
+		return true;
 
 	pr_globals = PR_globals(svprogfuncs, PR_CURRENT);
 
@@ -7478,6 +7480,32 @@ void PF_advanceweaponframe (progfuncs_t *prinst, struct globalvars_s *pr_globals
 	G_FLOAT(OFS_RETURN) = state;
 }
 
+void PR_SetPlayerClass(client_t *cl, int classnum, qboolean fromqc)
+{
+	char		temp[16];
+	if (classnum < 1)
+		return;	//reject it (it would crash the (standard hexen2) mod)
+	if (classnum > 5)
+		return;
+	if (cl->playerclass != classnum)
+	{
+		cl->edict->v->playerclass = classnum;
+		cl->playerclass = classnum;
+
+		sprintf(temp,"%i",(int)classnum);
+		Info_SetValueForKey (cl->userinfo, "cl_playerclass", temp, sizeof(cl->userinfo));
+
+		if (!fromqc)
+		{
+			cl->sendinfo = true;
+			if (cl->state == cs_spawned && pr_ClassChangeWeapon)
+			{
+				pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, cl->edict);
+				PR_ExecuteProgram (svprogfuncs, pr_ClassChangeWeapon);
+			}
+		}
+	}
+}
 
 void PF_setclass (progfuncs_t *prinst, struct globalvars_s *pr_globals)
 {
diff --git a/engine/server/q3g_public.h b/engine/server/q3g_public.h
index 97d585ddd..2eefe82d8 100644
--- a/engine/server/q3g_public.h
+++ b/engine/server/q3g_public.h
@@ -129,7 +129,7 @@ typedef enum {
 	// ClientCommand and ServerCommand parameter access
 
 	G_ARGV,			// ( int n, char *buffer, int bufferLength );
-
+//10
 	G_FS_FOPEN_FILE,	// ( const char *qpath, fileHandle_t *file, fsMode_t mode );
 	G_FS_READ,		// ( void *buffer, int len, fileHandle_t f );
 	G_FS_WRITE,		// ( const void *buffer, int len, fileHandle_t f );
@@ -162,7 +162,7 @@ typedef enum {
 	// All confgstrings are cleared at each level start.
 
 	G_GET_CONFIGSTRING,	// ( int num, char *buffer, int bufferSize );
-
+//20
 	G_GET_USERINFO,		// ( int num, char *buffer, int bufferSize );
 	// userinfo strings are maintained by the server system, so they
 	// are persistant across level loads, while all other game visible
@@ -189,7 +189,7 @@ typedef enum {
 	G_ADJUST_AREA_PORTAL_STATE,	// ( gentity_t *ent, qboolean open );
 
 	G_AREAS_CONNECTED,	// ( int area1, int area2 );
-
+//30
 	G_LINKENTITY,		// ( gentity_t *ent );
 	// an entity will never be sent to a client or used for collision
 	// if it is not passed to linkentity.  If the size, position, or
@@ -219,6 +219,7 @@ typedef enum {
 
 	G_FS_GETFILELIST,
 	G_DEBUG_POLYGON_CREATE,
+//40
 	G_DEBUG_POLYGON_DELETE,
 	G_REAL_TIME,
 	G_SNAPVECTOR,
diff --git a/engine/server/sv_chat.c b/engine/server/sv_chat.c
index 425442d51..116397b3a 100644
--- a/engine/server/sv_chat.c
+++ b/engine/server/sv_chat.c
@@ -119,7 +119,10 @@ void Chat_GetTag(char *filename, float tag, char **text, char **condition, char
 			}
 		}		
 	}
-	Sys_Error("Tag %f not found in file %s", tag, host_client->chat.filename);
+	*text = va("Chat Tag %f not found in file %s", tag, host_client->chat.filename);
+	*condition = "";
+	*options = "";
+	return;
 }
 
 chatvar_t *SV_ChatFindVariable(char *name)
diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c
index 31e9e20d4..9ebbcb322 100644
--- a/engine/server/sv_ents.c
+++ b/engine/server/sv_ents.c
@@ -2546,8 +2546,6 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
 				state->modelindex = SV_ModelIndex(modname);
 			}
 		}
-		if (/*progstype == PROG_H2 &&*/ ent->v->solid == SOLID_BSP)
-			state->angles[0]*=-1;
 
 		if (state->effects & EF_FULLBRIGHT)
 		{
diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c
index 431fbe259..af544d92a 100644
--- a/engine/server/sv_init.c
+++ b/engine/server/sv_init.c
@@ -1022,6 +1022,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
 
 		if (progstype == PROG_H2)
 		{
+			cvar_t *cv;
 			if (coop.value)
 			{
 				eval = PR_FindGlobal(svprogfuncs, "coop", 0);
@@ -1032,11 +1033,13 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
 				eval = PR_FindGlobal(svprogfuncs, "deathmatch", 0);
 				if (eval) eval->_float = deathmatch.value;
 			}
+			cv = Cvar_Get("randomclass", "0", CVAR_LATCH, "Hexen2");
 			eval = PR_FindGlobal(svprogfuncs, "randomclass", 0);
-			if (eval) eval->_float = Cvar_Get("randomclass", "1", CVAR_LATCH, "Hexen2 rules")->value;
+			if (eval && cv) eval->_float = cv->value;
 
+			cv = Cvar_Get("cl_playerclass", "1", CVAR_USERINFO|CVAR_ARCHIVE, "Hexen2");
 			eval = PR_FindGlobal(svprogfuncs, "cl_playerclass", 0);
-			if (eval) eval->_float = 1;
+			if (eval && cv) eval->_float = cv->value;
 		}
 		else
 		{
@@ -1078,6 +1081,8 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
 			spawnflagmask |= SPAWNFLAG_NOT_H2HARD;
 		else
 			spawnflagmask |= SPAWNFLAG_NOT_H2MEDIUM;
+
+		//don't filter based on player class. we're lame and don't have any real concept of player classes.
 	}
 	else if (!deathmatch.value)	//decide if we are to inhibit single player game ents instead
 	{
diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c
index 120a20984..ab0fa397c 100644
--- a/engine/server/sv_main.c
+++ b/engine/server/sv_main.c
@@ -3721,6 +3721,12 @@ void SV_ExtractFromUserinfo (client_t *cl)
 	else
 		cl->drate = 0;	//0 disables the downloading check
 
+	val = Info_ValueForKey (cl->userinfo, "cl_playerclass");
+	if (val)
+	{
+		PR_SetPlayerClass(cl, atoi(val), false);
+	}
+
 	// msg command
 	val = Info_ValueForKey (cl->userinfo, "msg");
 	if (strlen(val))
diff --git a/engine/server/sv_move.c b/engine/server/sv_move.c
index c80468915..ff37137da 100644
--- a/engine/server/sv_move.c
+++ b/engine/server/sv_move.c
@@ -72,7 +72,10 @@ realcheck:
 	start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
 	start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
 	stop[2] = start[2] - 2*pm_stepheight;
+	savedhull = ent->v->hull;
+	ent->v->hull = 0;
 	trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent);
+	ent->v->hull = savedhull;
 
 	if (trace.fraction == 1.0)
 		return false;
diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c
index 4bda693b0..06fd8e99f 100644
--- a/engine/server/sv_mvd.c
+++ b/engine/server/sv_mvd.c
@@ -114,13 +114,13 @@ void DestFlush(qboolean compleate)
 			break;
 
 		case DEST_STREAM:
-			if (d->cacheused)
+			if (d->cacheused && !d->error)
 			{
 				len = send(d->socket, d->cache, d->cacheused, 0);
 				if (len == 0) //client died
 					d->error = true;
-				else if (len > 0)	//error of some kind
-				{
+				else if (len > 0)	//we put some data through
+				{	//move up the buffer
 					d->cacheused -= len;
 					memmove(d->cache, d->cache+len, d->cacheused);
 				}
diff --git a/engine/server/world.c b/engine/server/world.c
index a6396b08e..a39e96933 100644
--- a/engine/server/world.c
+++ b/engine/server/world.c
@@ -389,26 +389,42 @@ void SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
 	if (ent->v->solid == SOLID_BSP && 
 	(ent->v->angles[0] || ent->v->angles[1] || ent->v->angles[2]) )
 	{	// expand for rotation
+
+#if 1
+		int i;
+		float v;
+		float max, min;
+		//q2 method
+		max = 0;
+		for (i=0 ; i<3 ; i++)
+		{
+			v =fabs( ent->v->mins[i]);
+			if (v > max)
+				max = v;
+			v =fabs( ent->v->maxs[i]);
+			if (v > max)
+				max = v;
+		}
+		for (i=0 ; i<3 ; i++)
+		{
+			ent->v->absmin[i] = ent->v->origin[i] - max;
+			ent->v->absmax[i] = ent->v->origin[i] + max;
+		}
+#else
+
 		int			i;
 
 		vec3_t f, r, u;
 		vec3_t mn, mx;
-		
+
 		//we need to link to the correct leaves
 
-		if (progstype == PROG_H2)
-		{
-			ent->v->angles[0]*=-1;
-			AngleVectors(ent->v->angles, f,r,u);
-			ent->v->angles[0]*=-1;
-		}
-		else
-			AngleVectors(ent->v->angles, f,r,u);
+		AngleVectors(ent->v->angles, f,r,u);
 
 		mn[0] = DotProduct(ent->v->mins, f);
 		mn[1] = -DotProduct(ent->v->mins, r);
 		mn[2] = DotProduct(ent->v->mins, u);
-		
+
 		mx[0] = DotProduct(ent->v->maxs, f);
 		mx[1] = -DotProduct(ent->v->maxs, r);
 		mx[2] = DotProduct(ent->v->maxs, u);
@@ -425,6 +441,7 @@ void SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
 				ent->v->absmax[i] = ent->v->origin[i]+mn[i]+0.1;
 			}
 		}
+#endif
 	}
 	else
 	{
@@ -959,22 +976,29 @@ qboolean TransformedTrace (struct model_s *model, int hulloverride, int frame, v
 		if (rotated)
 		{
 			// FIXME: figure out how to do this with existing angles
-	//		VectorNegate (angles, a);
-			a[0] = -angles[0];
-			a[1] = -angles[1];
-			a[2] = -angles[2];
-			AngleVectors (a, forward, right, up);
 
-			VectorCopy (trace->plane.normal, temp);
-			trace->plane.normal[0] = DotProduct (temp, forward);
-			trace->plane.normal[1] = -DotProduct (temp, right);
-			trace->plane.normal[2] = DotProduct (temp, up);
+			if (trace->fraction != 1)
+			{
+				VectorNegate (angles, a);
+				AngleVectors (a, forward, right, up);
 
-			trace->endpos[0] = start[0] + trace->fraction * (end[0] - start[0]);
-			trace->endpos[1] = start[1] + trace->fraction * (end[1] - start[1]);
-			trace->endpos[2] = start[2] + trace->fraction * (end[2] - start[2]);
+				VectorCopy (trace->plane.normal, temp);
+				trace->plane.normal[0] = DotProduct (temp, forward);
+				trace->plane.normal[1] = -DotProduct (temp, right);
+				trace->plane.normal[2] = DotProduct (temp, up);
+
+
+				trace->endpos[0] = start[0] + trace->fraction * (end[0] - start[0]);
+				trace->endpos[1] = start[1] + trace->fraction * (end[1] - start[1]);
+				trace->endpos[2] = start[2] + trace->fraction * (end[2] - start[2]);
+			}
+			else
+			{
+				VectorCopy (end, trace->endpos);
+			}
 		}
-		VectorAdd (trace->endpos, origin, trace->endpos);
+		else
+			VectorAdd (trace->endpos, origin, trace->endpos);
 	}
 	else
 	{
@@ -1115,15 +1139,15 @@ trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t max
 	}
 
 // trace a line through the apropriate clipping hull
-	if (progstype == PROG_H2 && ent->v->solid == SOLID_BSP)
+	if (ent->v->solid != SOLID_BSP)
 	{
-		ent->v->angles[0]*=-1;
-		TransformedTrace(model, 0, ent->v->frame, start, end, mins, maxs, &trace, ent->v->origin, ent->v->angles);
+		ent->v->angles[0]*=-1;	//carmack made bsp models rotate wrongly.
+		TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, &trace, ent->v->origin, ent->v->angles);
 		ent->v->angles[0]*=-1;
 	}
 	else
 	{
-		TransformedTrace(model, 0, ent->v->frame, start, end, mins, maxs, &trace, ent->v->origin, ent->v->angles);
+		TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, &trace, ent->v->origin, ent->v->angles);
 	}
 
 // fix trace up by the offset
@@ -1146,7 +1170,7 @@ trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t max
 			if (model && model->funcs.Trace)
 			{
 				//do the second trace
-				TransformedTrace(model, 0, ent->v->frame, start, end, mins, maxs, &trace, ent->v->origin, ent->v->angles);
+				TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, &trace, ent->v->origin, ent->v->angles);
 			}
 		}