shithub: qk1

Download patch

ref: bab80c934d2714937198f25041f8047146158f9c
parent: caa94b6b82aecb7a20e4e6de2cc2f2f9332436f9
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Thu Oct 12 19:48:32 EDT 2023

add basic RMQ net protocol support (for bigger mods)

--- a/cl_input.c
+++ b/cl_input.c
@@ -330,7 +330,7 @@
 	MSG_WriteFloat (&buf, cl.mtime[0]);	// so server can get ping times
 
 	for (i=0 ; i<3 ; i++)
-		sv.protocol->MSG_WriteAngle (&buf, cl.viewangles[i]);
+		cl.protocol->MSG_WriteAngle (&buf, cl.viewangles[i]);
 	
     MSG_WriteShort (&buf, cmd->forwardmove);
     MSG_WriteShort (&buf, cmd->sidemove);
--- a/cl_main.c
+++ b/cl_main.c
@@ -228,14 +228,13 @@
 	
 	for (i=0,ent=cl_entities ; i<cl.num_entities ; i++,ent++)
 	{
-		Con_Printf ("%3d:",i);
 		if (!ent->model)
-		{
-			Con_Printf ("EMPTY\n");
 			continue;
-		}
-		Con_Printf ("%s:%2d  (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n"
-		,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]);
+		Con_Printf ("%3d:%s:%2d  (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n",
+			i,ent->model->name,ent->frame,
+			ent->origin[0], ent->origin[1], ent->origin[2],
+			ent->angles[0], ent->angles[1], ent->angles[2]
+		);
 	}
 }
 
--- a/cl_parse.c
+++ b/cl_parse.c
@@ -47,7 +47,11 @@
 	"svc_finale",			// [string] music [string] text
 	"svc_cdtrack",			// [byte] track [byte] looptrack
 	"svc_sellscreen",
-	"svc_cutscene"
+	"svc_cutscene",
+
+	"svc_spawnbaseline2",
+	"svc_spawnstatic2",
+	"svc_spawnstaticsound2",
 };
 
 //=============================================================================
@@ -91,28 +95,22 @@
     float 	attenuation;  
 	           
     field_mask = MSG_ReadByte(); 
+    volume = (field_mask & SND_VOLUME) ? MSG_ReadByte() : Spktvol;
+	attenuation = (field_mask & SND_ATTENUATION) ? MSG_ReadByte()/64.0 : Spktatt;
+	if(field_mask & (sv.protocol->fl_large_entity | sv.protocol->fl_large_channel)){
+		ent = MSG_ReadShort();
+		channel = MSG_ReadByte();
+	}else{
+		channel = MSG_ReadShort ();
+		ent = channel >> 3;
+		channel &= 7;
+	}
+	sound_num = (field_mask & sv.protocol->fl_large_sound) ? MSG_ReadShort() : MSG_ReadByte();
 
-    if (field_mask & SND_VOLUME)
-		volume = MSG_ReadByte ();
-	else
-		volume = Spktvol;
-	
-    if (field_mask & SND_ATTENUATION)
-		attenuation = MSG_ReadByte () / 64.0;
-	else
-		attenuation = Spktatt;
-	
-	channel = MSG_ReadShort ();
-	sound_num = MSG_ReadByte ();
+	if(ent > MAX_EDICTS)
+		Host_Error("CL_ParseStartSoundPacket: ent = %d", ent);
 
-	ent = channel >> 3;
-	channel &= 7;
-
-	if (ent > MAX_EDICTS)
-		Host_Error ("CL_ParseStartSoundPacket: ent = %d", ent);
-
-	MSG_ReadVec(pos);
-
+	MSG_ReadVec(cl.protocol, pos);
     startsfx (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
 }       
 
@@ -185,10 +183,11 @@
 void CL_ParseServerInfo (void)
 {
 	char	*str;
-	int		i;
+	void	*p;
+	int		i, n;
 	int		nummodels, numsounds;
-	char	model_precache[MAX_MODELS][Npath];
-	char	sound_precache[MAX_SOUNDS][Npath];
+	static char	model_precache[MAX_MODELS][Npath];
+	static char	sound_precache[MAX_SOUNDS][Npath];
 
 	dprint("CL_ParseServerInfo: parsing serverinfo pkt...\n");
 //
@@ -198,11 +197,21 @@
 
 // parse protocol version number
 	i = MSG_ReadLong ();
-	if (i != PROTOCOL_VERSION)
-	{
-		Con_Printf ("Server returned version %d, not %d", i, PROTOCOL_VERSION);
+	free(cl.protocol);
+	p = nil;
+	for(n = 0; n < nelem(protos); n++){
+		if(protos[n].version == i){
+			p = &protos[n];
+			break;
+		}
+	}
+	if(p == nil){
+		Con_Printf ("Server returned unknown protocol version %d", i);
 		return;
 	}
+	cl.protocol = malloc(sizeof(*cl.protocol));
+	memmove(cl.protocol, p, sizeof(*cl.protocol));
+	cl.protocol->MSG_ReadProtocolInfo(cl.protocol);
 
 // parse maxclients
 	cl.maxclients = MSG_ReadByte ();
@@ -302,7 +311,7 @@
 relinked.  Other attributes can change without relinking.
 ==================
 */
-int	bitcounts[16];
+static int	bitcounts[16];
 
 void CL_ParseUpdate (int bits)
 {
@@ -311,7 +320,7 @@
 	int			modnum;
 	qboolean	forcelink;
 	entity_t	*ent;
-	int			num;
+	int			num, skin, colormap;
 
 	if (cls.signon == SIGNONS - 1)
 	{	// first update is the final signon stage
@@ -319,39 +328,66 @@
 		CL_SignonReply ();
 	}
 
-	if (bits & U_MOREBITS)
-	{
-		i = MSG_ReadByte ();
-		bits |= (i<<8);
+	if (bits & U_MOREBITS){
+		bits |= MSG_ReadByte()<<8;
+		if(bits & U_MOREBITS2){
+			bits |= MSG_ReadByte()<<16;
+			if(bits & U_MOREBITS3)
+				bits |= MSG_ReadByte()<<24;
+		}
+		if(bits == -1)
+			Host_Error("CL_ParseUpdate: unexpected EOF while reading extended bits");
 	}
 
-	if (bits & U_LONGENTITY)	
-		num = MSG_ReadShort ();
-	else
-		num = MSG_ReadByte ();
-
+	num = (bits & U_LONGENTITY) ? MSG_ReadShort() : MSG_ReadByte ();
 	ent = CL_EntityNum (num);
 
-for (i=0 ; i<16 ; i++)
-if (bits&(1<<i))
-	bitcounts[i]++;
+	for (i=0 ; i<16 ; i++)
+		if (bits&(1<<i))
+			bitcounts[i]++;
 
-	if (ent->msgtime != cl.mtime[1])
-		forcelink = true;	// no previous frame to lerp from
+	forcelink = ent->msgtime != cl.mtime[1]; // no previous frame to lerp from
+	ent->msgtime = cl.mtime[0];
+
+// shift the known values for interpolation
+	VectorCopy (ent->msg_origins[0], ent->msg_origins[1]);
+	VectorCopy (ent->msg_angles[0], ent->msg_angles[1]);
+
+	modnum = (bits & U_MODEL) ? MSG_ReadByte() : ent->baseline.modelindex;
+	ent->frame = (bits & U_FRAME) ? MSG_ReadByte() : ent->baseline.frame;
+	colormap = (bits & U_COLORMAP) ? MSG_ReadByte() : ent->baseline.colormap;
+	skin = (bits & U_SKIN) ? MSG_ReadByte() : ent->baseline.skin;
+	ent->effects = (bits & U_EFFECTS) ? MSG_ReadByte() : ent->baseline.effects;
+
+	if(colormap == 0)
+		ent->colormap = vid.colormap;
+	else if(colormap > cl.maxclients)
+		fatal("colormap > cl.maxclients");
 	else
-		forcelink = false;
+		ent->colormap = cl.scores[colormap-1].translations;
 
-	ent->msgtime = cl.mtime[0];
-	
-	if (bits & U_MODEL)
-	{
-		modnum = MSG_ReadByte ();
-		if (modnum >= MAX_MODELS)
-			Host_Error ("CL_ParseModel: bad modnum");
+	if(skin != ent->skinnum && num >= 0 && num <= cl.maxclients){
+		// FIXME(sigrid): update the skin
+		ent->skinnum = skin;
 	}
-	else
-		modnum = ent->baseline.modelindex;
-		
+
+	ent->msg_origins[0][0] = (bits & U_ORIGIN1) ? cl.protocol->MSG_ReadCoord() : ent->baseline.origin[0];
+	ent->msg_angles[0][0] = (bits & U_ANGLE1) ? cl.protocol->MSG_ReadAngle() : ent->baseline.angles[0];
+	ent->msg_origins[0][1] = (bits & U_ORIGIN2) ? cl.protocol->MSG_ReadCoord() : ent->baseline.origin[1];
+	ent->msg_angles[0][1] = (bits & U_ANGLE2) ? cl.protocol->MSG_ReadAngle() : ent->baseline.angles[1];
+	ent->msg_origins[0][2] = (bits & U_ORIGIN3) ? cl.protocol->MSG_ReadCoord() : ent->baseline.origin[2];
+	ent->msg_angles[0][2] = (bits & U_ANGLE3) ? cl.protocol->MSG_ReadAngle() : ent->baseline.angles[2];
+
+	if(bits & U_NOLERP)
+		ent->forcelink = true;
+
+	if(bits & cl.protocol->fl_large_frame)
+		ent->frame |= MSG_ReadByte()<<8;
+	if(bits & cl.protocol->fl_large_model)
+		modnum |= MSG_ReadByte()<<8;
+
+	if(modnum < 0 || modnum >= MAX_MODELS)
+		Host_Error("CL_ParseModel: bad modnum: %d (bits 0x%08ux)", modnum, bits);
 	model = cl.model_precache[modnum];
 	if (model != ent->model)
 	{
@@ -368,69 +404,7 @@
 		else
 			forcelink = true;	// hack to make null model players work
 	}
-	
-	if (bits & U_FRAME)
-		ent->frame = MSG_ReadByte ();
-	else
-		ent->frame = ent->baseline.frame;
 
-	if (bits & U_COLORMAP)
-		i = MSG_ReadByte();
-	else
-		i = ent->baseline.colormap;
-	if (!i)
-		ent->colormap = vid.colormap;
-	else
-	{
-		if (i > cl.maxclients)
-			fatal ("i >= cl.maxclients");
-		ent->colormap = cl.scores[i-1].translations;
-	}
-
-	if (bits & U_SKIN)
-		ent->skinnum = MSG_ReadByte();
-	else
-		ent->skinnum = ent->baseline.skin;
-
-	if (bits & U_EFFECTS)
-		ent->effects = MSG_ReadByte();
-	else
-		ent->effects = ent->baseline.effects;
-
-// shift the known values for interpolation
-	VectorCopy (ent->msg_origins[0], ent->msg_origins[1]);
-	VectorCopy (ent->msg_angles[0], ent->msg_angles[1]);
-
-	if (bits & U_ORIGIN1)
-		ent->msg_origins[0][0] = sv.protocol->MSG_ReadCoord ();
-	else
-		ent->msg_origins[0][0] = ent->baseline.origin[0];
-	if (bits & U_ANGLE1)
-		ent->msg_angles[0][0] = sv.protocol->MSG_ReadAngle();
-	else
-		ent->msg_angles[0][0] = ent->baseline.angles[0];
-
-	if (bits & U_ORIGIN2)
-		ent->msg_origins[0][1] = sv.protocol->MSG_ReadCoord ();
-	else
-		ent->msg_origins[0][1] = ent->baseline.origin[1];
-	if (bits & U_ANGLE2)
-		ent->msg_angles[0][1] = sv.protocol->MSG_ReadAngle();
-	else
-		ent->msg_angles[0][1] = ent->baseline.angles[1];
-
-	if (bits & U_ORIGIN3)
-		ent->msg_origins[0][2] = sv.protocol->MSG_ReadCoord ();
-	else
-		ent->msg_origins[0][2] = ent->baseline.origin[2];
-	if (bits & U_ANGLE3)
-		ent->msg_angles[0][2] = sv.protocol->MSG_ReadAngle();
-	else
-		ent->msg_angles[0][2] = ent->baseline.angles[2];
-
-	if ( bits & U_NOLERP )
-		ent->forcelink = true;
-
 	if ( forcelink )
 	{	// didn't have an update last message
 		VectorCopy (ent->msg_origins[0], ent->msg_origins[1]);
@@ -446,18 +420,19 @@
 CL_ParseBaseline
 ==================
 */
-void CL_ParseBaseline (entity_t *ent)
+void CL_ParseBaseline (int withbits, entity_t *ent)
 {
-	int			i;
-	
-	ent->baseline.modelindex = MSG_ReadByte ();
-	ent->baseline.frame = MSG_ReadByte ();
+	int i, bits;
+
+	bits = withbits ? MSG_ReadByte() : 0;
+	ent->baseline.modelindex = (bits & cl.protocol->fl_large_baseline_model) ? MSG_ReadShort() : MSG_ReadByte();
+	ent->baseline.frame = (bits & cl.protocol->fl_large_baseline_frame) ? MSG_ReadShort() : MSG_ReadByte();
 	ent->baseline.colormap = MSG_ReadByte();
 	ent->baseline.skin = MSG_ReadByte();
 	for (i=0 ; i<3 ; i++)
 	{
-		ent->baseline.origin[i] = sv.protocol->MSG_ReadCoord ();
-		ent->baseline.angles[i] = sv.protocol->MSG_ReadAngle ();
+		ent->baseline.origin[i] = cl.protocol->MSG_ReadCoord ();
+		ent->baseline.angles[i] = cl.protocol->MSG_ReadAngle ();
 	}
 }
 
@@ -471,36 +446,26 @@
 */
 void CL_ParseClientdata (unsigned int bits)
 {
-	int		i, j;
-	
-	if (bits & SU_VIEWHEIGHT)
-		cl.viewheight = MSG_ReadChar ();
-	else
-		cl.viewheight = DEFAULT_VIEWHEIGHT;
+	int		i, j, weaponmodel;
 
-	if (bits & SU_IDEALPITCH)
-		cl.idealpitch = MSG_ReadChar ();
-	else
-		cl.idealpitch = 0;
-	
-	VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
+	if(bits & SU_MOREBITS){
+		bits |= MSG_ReadByte() << 16;
+		if(bits & SU_MOREBITS2)
+			bits |= MSG_ReadByte() << 24;
+	}
+
+	cl.viewheight = (bits & SU_VIEWHEIGHT) ? MSG_ReadChar() : DEFAULT_VIEWHEIGHT;
+	cl.idealpitch = (bits & SU_IDEALPITCH) ? MSG_ReadChar() : 0;
+
+	VectorCopy(cl.mvelocity[0], cl.mvelocity[1]);
 	for (i=0 ; i<3 ; i++)
 	{
-		if (bits & (SU_PUNCH1<<i) )
-			cl.punchangle[i] = MSG_ReadChar();
-		else
-			cl.punchangle[i] = 0;
-		if (bits & (SU_VELOCITY1<<i) )
-			cl.mvelocity[0][i] = MSG_ReadChar()*16;
-		else
-			cl.mvelocity[0][i] = 0;
+		cl.punchangle[i] = (bits & (SU_PUNCH1<<i)) ? MSG_ReadChar() : 0;
+		cl.mvelocity[0][i] = (bits & (SU_VELOCITY1<<i)) ? MSG_ReadChar()*16 : 0;
 	}
 
-// [always sent]	if (bits & SU_ITEMS)
-		i = MSG_ReadLong ();
-
-	if (cl.items != i)
-	{	// set flash times
+	i = (bits & SU_ITEMS) ? MSG_ReadLong() : cl.items;
+	if(cl.items != i){ // set flash times
 		Sbar_Changed ();
 		for (j=0 ; j<32 ; j++)
 			if ( (i & (1<<j)) && !(cl.items & (1<<j)))
@@ -507,78 +472,60 @@
 				cl.item_gettime[j] = cl.time;
 		cl.items = i;
 	}
-		
+
 	cl.onground = (bits & SU_ONGROUND) != 0;
 	cl.inwater = (bits & SU_INWATER) != 0;
+	cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
 
-	if (bits & SU_WEAPONFRAME)
-		cl.stats[STAT_WEAPONFRAME] = MSG_ReadByte ();
-	else
-		cl.stats[STAT_WEAPONFRAME] = 0;
-
-	if (bits & SU_ARMOR)
-		i = MSG_ReadByte ();
-	else
-		i = 0;
-	if (cl.stats[STAT_ARMOR] != i)
-	{
+	i = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
+	if(cl.stats[STAT_ARMOR] != i){
 		cl.stats[STAT_ARMOR] = i;
 		Sbar_Changed ();
 	}
 
-	if (bits & SU_WEAPON)
-		i = MSG_ReadByte ();
-	else
-		i = 0;
-	if (cl.stats[STAT_WEAPON] != i)
-	{
-		cl.stats[STAT_WEAPON] = i;
-		Sbar_Changed ();
-	}
+	weaponmodel = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
 	
-	i = MSG_ReadShort ();
-	if (cl.stats[STAT_HEALTH] != i)
-	{
+	i = MSG_ReadShort();
+	if (cl.stats[STAT_HEALTH] != i){
 		cl.stats[STAT_HEALTH] = i;
-		Sbar_Changed ();
+		Sbar_Changed();
 	}
 
-	i = MSG_ReadByte ();
-	if (cl.stats[STAT_AMMO] != i)
-	{
+	i = MSG_ReadByte();
+	if(cl.stats[STAT_AMMO] != i){
 		cl.stats[STAT_AMMO] = i;
-		Sbar_Changed ();
+		Sbar_Changed();
 	}
 
-	for (i=0 ; i<4 ; i++)
-	{
-		j = MSG_ReadByte ();
-		if (cl.stats[STAT_SHELLS+i] != j)
-		{
+	for (i=0 ; i<4 ; i++){
+		j = MSG_ReadByte();
+		if(cl.stats[STAT_SHELLS+i] != j){
 			cl.stats[STAT_SHELLS+i] = j;
-			Sbar_Changed ();
+			Sbar_Changed();
 		}
 	}
 
-	i = MSG_ReadByte ();
-
-	if (standard_quake)
-	{
-		if (cl.stats[STAT_ACTIVEWEAPON] != i)
-		{
+	i = MSG_ReadByte();
+	if(standard_quake){
+		if(cl.stats[STAT_ACTIVEWEAPON] != i){
 			cl.stats[STAT_ACTIVEWEAPON] = i;
-			Sbar_Changed ();
+			Sbar_Changed();
 		}
+	}else if(cl.stats[STAT_ACTIVEWEAPON] != (1<<i)){
+		cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
+		Sbar_Changed();
 	}
-	else
-	{
-		if (cl.stats[STAT_ACTIVEWEAPON] != (1<<i))
-		{
-			cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
-			Sbar_Changed ();
-		}
+
+	if(bits & cl.protocol->fl_large_weaponmodel)
+		weaponmodel |= MSG_ReadByte() << 8;
+	if(cl.stats[STAT_WEAPON] != weaponmodel){
+		cl.stats[STAT_WEAPON] = weaponmodel;
+		Sbar_Changed();
 	}
 
+	if(bits & cl.protocol->fl_large_weaponframe)
+		cl.stats[STAT_WEAPONFRAME] |= MSG_ReadByte() << 8;
+
 	if(cl.viewent.model != cl.model_precache[cl.stats[STAT_WEAPON]]){
 		// FIXME(sigrid) - reset lerp
 	}
@@ -624,7 +571,7 @@
 CL_ParseStatic
 =====================
 */
-void CL_ParseStatic (void)
+void CL_ParseStatic (int withbits)
 {
 	entity_t *ent;
 	int		i;
@@ -634,7 +581,7 @@
 		Host_Error ("Too many static entities");
 	ent = &cl_static_entities[i];
 	cl.num_statics++;
-	CL_ParseBaseline (ent);
+	CL_ParseBaseline(withbits, ent);
 
 // copy it to the current state
 	ent->model = cl.model_precache[ent->baseline.modelindex];
@@ -653,17 +600,17 @@
 CL_ParseStaticSound
 ===================
 */
-void CL_ParseStaticSound (void)
+void CL_ParseStaticSound (int large_sound)
 {
 	vec3_t		org;
 	int			sound_num, vol, atten;
 
-	MSG_ReadVec(org);
-	sound_num = MSG_ReadByte ();
-	vol = MSG_ReadByte ();
-	atten = MSG_ReadByte ();
+	MSG_ReadVec(cl.protocol, org);
+	sound_num = large_sound ? MSG_ReadShort() : MSG_ReadByte();
+	vol = MSG_ReadByte();
+	atten = MSG_ReadByte();
 	
-	staticsfx (cl.sound_precache[sound_num], org, vol, atten);
+	staticsfx(cl.sound_precache[sound_num], org, vol, atten);
 }
 
 
@@ -676,8 +623,8 @@
 */
 void CL_ParseServerMessage (void)
 {
-	int			cmd;
-	int			i;
+	int cmd, i, n;
+	protocol_t *p;
 	
 //
 // if recording demos, copy the message out
@@ -700,7 +647,7 @@
 
 		cmd = MSG_ReadByte ();
 
-		if (cmd == -1)
+		if (cmd < 0)
 		{
 			SHOWNET("END OF MESSAGE");
 			return;		// end of message
@@ -707,10 +654,10 @@
 		}
 
 	// if the high bit of the command byte is set, it is a fast update
-		if (cmd & 128)
+		if (cmd & U_SIGNAL)
 		{
 			SHOWNET("fast update");
-			CL_ParseUpdate (cmd&127);
+			CL_ParseUpdate (cmd);
 			continue;
 		}
 
@@ -733,14 +680,21 @@
 			break;
 			
 		case svc_clientdata:
-			i = (ushort)MSG_ReadShort ();
-			CL_ParseClientdata (i);
+			CL_ParseClientdata((ushort)MSG_ReadShort());
 			break;
 		
 		case svc_version:
-			i = MSG_ReadLong ();
-			if (i != PROTOCOL_VERSION)
-				Host_Error ("CL_ParseServerMessage: Server is protocol %d instead of %d\n", i, PROTOCOL_VERSION);
+			i = MSG_ReadLong();
+			for(p = nil, n = 0; n < nelem(protos); n++){
+				if(protos[n].version == i){
+					p = &protos[n];
+					break;
+				}
+			}
+			if(p == nil)
+				Host_Error("CL_ParseServerMessage: server uses unknown protocol %d\n", i);
+			if(p->version != cl.protocol->version)
+				Host_Error("CL_ParseServerMessage: server decided to switch protocol to %d mid-game?\n", i);
 			break;
 			
 		case svc_disconnect:
@@ -769,7 +723,7 @@
 			
 		case svc_setangle:
 			for (i=0 ; i<3 ; i++)
-				cl.viewangles[i] = sv.protocol->MSG_ReadAngle ();
+				cl.viewangles[i] = cl.protocol->MSG_ReadAngle ();
 			break;
 			
 		case svc_setview:
@@ -823,15 +777,17 @@
 			break;
 
 		case svc_spawnbaseline:
-			i = MSG_ReadShort ();
+		case svc_spawnbaseline2:
+			i = MSG_ReadShort();
 			// must use CL_EntityNum() to force cl.num_entities up
-			CL_ParseBaseline (CL_EntityNum(i));
+			CL_ParseBaseline(cmd == svc_spawnbaseline2, CL_EntityNum(i));
 			break;
 		case svc_spawnstatic:
-			CL_ParseStatic ();
-			break;			
+		case svc_spawnstatic2:
+			CL_ParseStatic(cmd == svc_spawnstatic2);
+			break;
 		case svc_temp_entity:
-			CL_ParseTEnt ();
+			CL_ParseTEnt();
 			break;
 
 		case svc_setpause:
@@ -869,7 +825,8 @@
 			break;
 			
 		case svc_spawnstaticsound:
-			CL_ParseStaticSound ();
+		case svc_spawnstaticsound2:
+			CL_ParseStaticSound(cmd == svc_spawnstaticsound2);
 			break;
 
 		case svc_cdtrack:
--- a/cl_tent.c
+++ b/cl_tent.c
@@ -46,8 +46,8 @@
 	
 	ent = MSG_ReadShort ();
 
-	MSG_ReadVec(start);
-	MSG_ReadVec(end);
+	MSG_ReadVec(cl.protocol, start);
+	MSG_ReadVec(cl.protocol, end);
 
 // override any beam with the same entity
 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
@@ -94,19 +94,19 @@
 	switch (type)
 	{
 	case TE_WIZSPIKE:			// spike hitting wall
-		MSG_ReadVec(pos);
+		MSG_ReadVec(cl.protocol, pos);
 		R_RunParticleEffect (pos, vec3_origin, 20, 30);
 		startsfx (-1, 0, cl_sfx_wizhit, pos, 1, 1);
 		break;
 		
 	case TE_KNIGHTSPIKE:			// spike hitting wall
-		MSG_ReadVec(pos);
+		MSG_ReadVec(cl.protocol, pos);
 		R_RunParticleEffect (pos, vec3_origin, 226, 20);
 		startsfx (-1, 0, cl_sfx_knighthit, pos, 1, 1);
 		break;
 		
 	case TE_SPIKE:			// spike hitting wall
-		MSG_ReadVec(pos);
+		MSG_ReadVec(cl.protocol, pos);
 		R_RunParticleEffect (pos, vec3_origin, 0, 10);
 		if ( rand() % 5 )
 			startsfx (-1, 0, cl_Sfxink1, pos, 1, 1);
@@ -122,7 +122,7 @@
 		}
 		break;
 	case TE_SUPERSPIKE:			// super spike hitting wall
-		MSG_ReadVec(pos);
+		MSG_ReadVec(cl.protocol, pos);
 		R_RunParticleEffect (pos, vec3_origin, 0, 20);
 
 		if ( rand() % 5 )
@@ -140,12 +140,12 @@
 		break;
 		
 	case TE_GUNSHOT:			// bullet hitting wall
-		MSG_ReadVec(pos);
+		MSG_ReadVec(cl.protocol, pos);
 		R_RunParticleEffect (pos, vec3_origin, 0, 20);
 		break;
 		
 	case TE_EXPLOSION:			// rocket explosion
-		MSG_ReadVec(pos);
+		MSG_ReadVec(cl.protocol, pos);
 		R_ParticleExplosion (pos);
 		dl = CL_AllocDlight (0);
 		VectorCopy (pos, dl->origin);
@@ -156,7 +156,7 @@
 		break;
 		
 	case TE_TAREXPLOSION:			// tarbaby explosion
-		MSG_ReadVec(pos);
+		MSG_ReadVec(cl.protocol, pos);
 		R_BlobExplosion (pos);
 
 		startsfx (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
@@ -181,17 +181,17 @@
 // PGM 01/21/97
 
 	case TE_LAVASPLASH:	
-		MSG_ReadVec(pos);
+		MSG_ReadVec(cl.protocol, pos);
 		R_LavaSplash (pos);
 		break;
 	
 	case TE_TELEPORT:
-		MSG_ReadVec(pos);
+		MSG_ReadVec(cl.protocol, pos);
 		R_TeleportSplash (pos);
 		break;
 		
 	case TE_EXPLOSION2:				// color mapped explosion
-		MSG_ReadVec(pos);
+		MSG_ReadVec(cl.protocol, pos);
 		colorStart = MSG_ReadByte ();
 		colorLength = MSG_ReadByte ();
 		R_ParticleExplosion2 (pos, colorStart, colorLength);
--- a/client.h
+++ b/client.h
@@ -119,6 +119,7 @@
 //
 typedef struct
 {
+	protocol_t *protocol;
 	int			movemessages;	// since connecting to this server
 								// throw out the first couple, so the player
 								// doesn't accidentally do something the 
--- a/common.c
+++ b/common.c
@@ -175,7 +175,7 @@
 
 void MSG_WriteAngleInt16 (sizebuf_t *sb, float f)
 {
-	MSG_WriteShort (sb, Qrint(f*65536.0/360.0));
+	MSG_WriteShort (sb, Qrint(f*65536.0/360.0) & 65535);
 }
 
 //
--- a/common.h
+++ b/common.h
@@ -36,6 +36,10 @@
 
 //============================================================================
 
+#define max(a,b) ((a)>(b)?(a):(b))
+#define min(a,b) ((a)<(b)?(a):(b))
+#define clamp(x,a,b) (min(max((x),(a)),(b)))
+
 #define Q_MAXCHAR ((char)0x7f)
 #define Q_MAXSHORT ((short)0x7fff)
 #define Q_MAXINT	((int)0x7fffffff)
@@ -59,8 +63,6 @@
 
 //============================================================================
 
-#define Qrint(f) (int)((f) + ((f) >= 0 ? 0.5 : -0.5))
-
 void MSG_WriteChar (sizebuf_t *sb, int c);
 void MSG_WriteByte (sizebuf_t *sb, int c);
 void MSG_WriteShort (sizebuf_t *sb, int c);
@@ -88,10 +90,16 @@
 float MSG_ReadAngle (void);
 float MSG_ReadAngleInt16 (void);
 
-#define MSG_ReadVec(d) do{ \
-	(d)[0] = sv.protocol->MSG_ReadCoord(); \
-	(d)[1] = sv.protocol->MSG_ReadCoord(); \
-	(d)[2] = sv.protocol->MSG_ReadCoord(); \
+#define MSG_ReadVec(proto, d) do{ \
+	(d)[0] = (proto)->MSG_ReadCoord(); \
+	(d)[1] = (proto)->MSG_ReadCoord(); \
+	(d)[2] = (proto)->MSG_ReadCoord(); \
+}while(0)
+
+#define MSG_WriteVec(proto, sb, s) do{ \
+	(proto)->MSG_WriteCoord(sb, (s)[0]); \
+	(proto)->MSG_WriteCoord(sb, (s)[1]); \
+	(proto)->MSG_WriteCoord(sb, (s)[2]); \
 }while(0)
 
 //============================================================================
--- a/dat.h
+++ b/dat.h
@@ -3,7 +3,7 @@
 extern char *game;
 
 enum{
-	Npath = 64,
+	Npath = 128,
 	Nfspath = 128,
 	Nsav = 12,
 	Nsavcm = 40,
--- a/mathlib.h
+++ b/mathlib.h
@@ -17,6 +17,8 @@
 extern vec3_t vec3_origin;
 extern	int nanmask;
 
+#define Qrint(f) (int)((f) + ((f) >= 0 ? 0.5 : -0.5))
+
 #define	IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
 
 #define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
--- a/mkfile
+++ b/mkfile
@@ -47,6 +47,7 @@
 	pr_cmds.$O\
 	pr_edict.$O\
 	pr_exec.$O\
+	protocol.$O\
 	qk1.$O\
 	r_aclip.$O\
 	r_alias.$O\
--- a/pr_cmds.c
+++ b/pr_cmds.c
@@ -229,7 +229,6 @@
 	for (i=0, check = sv.model_precache ; *check ; i++, check++)
 		if (!strcmp(*check, m))
 			break;
-			
 	if (!*check)
 		PR_RunError ("no precache: %s\n", m);
 	e->v.model = PR_SetStr(m);
@@ -511,15 +510,22 @@
 
 // add an svc_spawnambient command to the level signon packet
 
-	MSG_WriteByte (&sv.signon,svc_spawnstaticsound);
+	if(soundnum >= sv.protocol->limit_sound)
+		return;
+
+	MSG_WriteByte(
+		&sv.signon,
+		soundnum < sv.protocol->large_sound ?
+			svc_spawnstaticsound :
+			svc_spawnstaticsound2
+	);
 	for (i=0 ; i<3 ; i++)
 		sv.protocol->MSG_WriteCoord(&sv.signon, pos[i]);
 
-	MSG_WriteByte (&sv.signon, soundnum);
+	(soundnum < sv.protocol->large_sound ? MSG_WriteByte : MSG_WriteShort)(&sv.signon, soundnum);
+	MSG_WriteByte(&sv.signon, vol*255);
+	MSG_WriteByte(&sv.signon, attenuation*64);
 
-	MSG_WriteByte (&sv.signon, vol*255);
-	MSG_WriteByte (&sv.signon, attenuation*64);
-
 }
 
 /*
@@ -994,7 +1000,7 @@
 	
 	if (sv.state != ss_loading)
 		PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
-		
+
 	s = G_STRING(OFS_PARM0);
 	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
 	PR_CheckEmptyString (s);
--- a/pr_edict.c
+++ b/pr_edict.c
@@ -7,6 +7,7 @@
 dprograms_t		*progs;
 dfunction_t		*pr_functions;
 char			*pr_strings;
+static int		pr_strings_size;
 ddef_t			*pr_fielddefs;
 ddef_t			*pr_globaldefs;
 dstatement_t	*pr_statements;
@@ -81,6 +82,10 @@
 {
 	int i;
 
+	if(s == nil)
+		return 0;
+	if(s >= pr_strings && s < pr_strings+pr_strings_size-1)
+		return s - pr_strings;
 	for(i = 0; i < num_prstr; i++){
 		if(s == prstr[i])
 			return -1-i;
@@ -958,7 +963,7 @@
 	if(prtempstr == nil)
 		prtempstr = malloc(MAX_PRTEMPSTR*PRTEMPSTR_SIZE);
 
-	memset(prstr, 0, MAX_PRSTR*sizeof(*prstr));
+	memset(prstr, 0, max_prstr*sizeof(*prstr));
 	memset(prtempstr, 0, MAX_PRTEMPSTR*PRTEMPSTR_SIZE);
 	num_prstr = 0;
 	num_prtempstr = 0;
@@ -985,6 +990,7 @@
 
 	pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions);
 	pr_strings = (char *)progs + progs->ofs_strings;
+	pr_strings_size = progs->numstrings;
 	pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs);
 	pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);
 	pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);
--- a/pr_exec.c
+++ b/pr_exec.c
@@ -373,9 +373,9 @@
 	s++;	// next statement
 
 	st = &pr_statements[s];
-	a = (eval_t *)&pr_globals[st->a];
-	b = (eval_t *)&pr_globals[st->b];
-	c = (eval_t *)&pr_globals[st->c];
+	a = (eval_t *)&pr_globals[(unsigned short)st->a];
+	b = (eval_t *)&pr_globals[(unsigned short)st->b];
+	c = (eval_t *)&pr_globals[(unsigned short)st->c];
 	
 	if (!--runaway)
 		PR_RunError ("runaway loop error");
@@ -618,9 +618,9 @@
 
 	case OP_DONE:
 	case OP_RETURN:
-		pr_globals[OFS_RETURN] = pr_globals[st->a];
-		pr_globals[OFS_RETURN+1] = pr_globals[st->a+1];
-		pr_globals[OFS_RETURN+2] = pr_globals[st->a+2];
+		pr_globals[OFS_RETURN] = pr_globals[(unsigned short)st->a];
+		pr_globals[OFS_RETURN+1] = pr_globals[(unsigned short)st->a+1];
+		pr_globals[OFS_RETURN+2] = pr_globals[(unsigned short)st->a+2];
 	
 		s = PR_LeaveFunction ();
 		if (pr_depth == exitdepth)
--- a/progs.h
+++ b/progs.h
@@ -11,7 +11,7 @@
 	int				edict;
 } eval_t;	
 
-#define	MAX_ENT_LEAFS	16
+#define	MAX_ENT_LEAFS	32
 typedef struct edict_s
 {
 	qboolean	free;
@@ -18,7 +18,7 @@
 	link_t		area;				// linked to a division node or leaf
 	
 	int			num_leafs;
-	short		leafnums[MAX_ENT_LEAFS];
+	int			leafnums[MAX_ENT_LEAFS];
 
 	entity_state_t	baseline;
 	
--- /dev/null
+++ b/protocol.c
@@ -1,0 +1,72 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "quakedef.h"
+#include "fns.h"
+
+static void
+MSG_WriteProtocolInfoNQ(sizebuf_t *sb, protocol_t *proto)
+{
+	USED(sb, proto);
+}
+
+static void
+MSG_ReadProtocolInfoNQ(protocol_t *proto)
+{
+	USED(proto);
+	proto->flags = 0;
+}
+
+static void
+MSG_WriteProtocolInfoRMQ(sizebuf_t *sb, protocol_t *proto)
+{
+	USED(proto);
+	MSG_WriteLong(sb, PF_RMQ_ANGLE_INT16|PF_RMQ_COORD_INT32);
+}
+
+static void
+MSG_ReadProtocolInfoRMQ(protocol_t *proto)
+{
+	proto->flags = MSG_ReadLong();
+	if(proto->flags != (PF_RMQ_ANGLE_INT16|PF_RMQ_COORD_INT32))
+		fatal("FIXME RMQ protocol implementation limited to angle_int16 and coord_int32");
+}
+
+protocol_t protos[PROTO_NUM] = {
+	[PROTO_NQ] = {
+		.id = PROTO_NQ,
+		.name = "Quake",
+		.version = 15,
+		.limit_entity = 8192,
+		.limit_channel = 8,
+		.limit_sound = 256,
+		.limit_frame = 256,
+		.limit_model = 256,
+		.MSG_WriteCoord = MSG_WriteCoord,
+		.MSG_WriteAngle = MSG_WriteAngle,
+		.MSG_ReadCoord = MSG_ReadCoord,
+		.MSG_ReadAngle = MSG_ReadAngle,
+		.MSG_WriteProtocolInfo = MSG_WriteProtocolInfoNQ,
+		.MSG_ReadProtocolInfo = MSG_ReadProtocolInfoNQ,
+	},
+	[PROTO_RMQ] = {
+		.id = PROTO_RMQ,
+		.name = "RMQ",
+		.version = 999,
+		.fl_large_entity = 1<<3, .large_entity = 8192, .limit_entity = 65536,
+		.fl_large_channel = 1<<3, .large_channel = 8, .limit_channel = 256,
+		.fl_large_sound = 1<<4, .large_sound = 256, .limit_sound = MAX_SOUNDS,
+		.fl_large_frame = 1<<17, .large_frame = 256, .limit_frame = 65536,
+		.fl_large_model = 1<<18, .large_model = 256, .limit_model = MAX_MODELS,
+		.fl_large_weaponframe = 1<<24,
+		.fl_large_weaponmodel = 1<<16,
+		.fl_large_baseline_model = 1<<0,
+		.fl_large_baseline_frame = 1<<1,
+		.MSG_WriteCoord = MSG_WriteCoordInt32,
+		.MSG_WriteAngle = MSG_WriteAngleInt16,
+		.MSG_ReadCoord = MSG_ReadCoordInt32,
+		.MSG_ReadAngle = MSG_ReadAngleInt16,
+		.MSG_WriteProtocolInfo = MSG_WriteProtocolInfoRMQ,
+		.MSG_ReadProtocolInfo = MSG_ReadProtocolInfoRMQ,
+	},
+};
--- a/protocol.h
+++ b/protocol.h
@@ -1,143 +1,179 @@
 // protocol.h -- communications protocols
 
-#define	PROTOCOL_VERSION	15
+enum {
+	PROTO_NQ,
+	PROTO_RMQ,
+	PROTO_NUM,
+};
 
-// if the high bit of the servercmd is set, the low bits are fast update flags:
-#define	U_MOREBITS	(1<<0)
-#define	U_ORIGIN1	(1<<1)
-#define	U_ORIGIN2	(1<<2)
-#define	U_ORIGIN3	(1<<3)
-#define	U_ANGLE2	(1<<4)
-#define	U_NOLERP	(1<<5)		// don't interpolate movement
-#define	U_FRAME		(1<<6)
-#define U_SIGNAL	(1<<7)		// just differentiates from other updates
+// these are the only ones supported with RMQ atm
+enum {
+	PF_RMQ_ANGLE_INT16 = 1<<1,
+	PF_RMQ_COORD_INT32 = 1<<7,
+};
 
-// svc_update can pass all of the fast update bits, plus more
-#define	U_ANGLE1	(1<<8)
-#define	U_ANGLE3	(1<<9)
-#define	U_MODEL		(1<<10)
-#define	U_COLORMAP	(1<<11)
-#define	U_SKIN		(1<<12)
-#define	U_EFFECTS	(1<<13)
-#define	U_LONGENTITY	(1<<14)
+typedef struct protocol_t protocol_t;
 
+struct protocol_t {
+	int id;
+	int version;
+	int flags;
+	char *name;
 
-#define	SU_VIEWHEIGHT	(1<<0)
-#define	SU_IDEALPITCH	(1<<1)
-#define	SU_PUNCH1		(1<<2)
-#define	SU_PUNCH2		(1<<3)
-#define	SU_PUNCH3		(1<<4)
-#define	SU_VELOCITY1	(1<<5)
-#define	SU_VELOCITY2	(1<<6)
-#define	SU_VELOCITY3	(1<<7)
-//define	SU_AIMENT		(1<<8)  AVAILABLE BIT
-#define	SU_ITEMS		(1<<9)
-#define	SU_ONGROUND		(1<<10)		// no data follows, the bit is it
-#define	SU_INWATER		(1<<11)		// no data follows, the bit is it
-#define	SU_WEAPONFRAME	(1<<12)
-#define	SU_ARMOR		(1<<13)
-#define	SU_WEAPON		(1<<14)
+	// flexible limits - messages change
+	u32int fl_large_entity;
+	int large_entity;
+	u32int fl_large_channel;
+	int large_channel;
+	u32int fl_large_sound;
+	int large_sound;
+	u32int fl_large_frame;
+	int large_frame;
+	u32int fl_large_model;
+	int large_model;
+	u32int fl_large_weaponframe;
+	u32int fl_large_weaponmodel;
+	u32int fl_large_baseline_model;
+	u32int fl_large_baseline_frame;
 
-// a sound with no channel is a local only sound
-#define	SND_VOLUME		(1<<0)		// a byte
-#define	SND_ATTENUATION	(1<<1)		// a byte
-#define	SND_LOOPING		(1<<2)		// a long
+	// absolute limits for the protocol
+	int limit_entity;
+	int limit_channel;
+	int limit_model;
+	int limit_frame;
+	int limit_sound;
 
+	void (*MSG_WriteCoord)(sizebuf_t *sb, float f);
+	void (*MSG_WriteAngle)(sizebuf_t *sb, float f);
+	float (*MSG_ReadCoord)(void);
+	float (*MSG_ReadAngle)(void);
 
+	void (*MSG_WriteProtocolInfo)(sizebuf_t *sb, protocol_t *proto);
+	void (*MSG_ReadProtocolInfo)(protocol_t *proto);
+};
+
+extern protocol_t protos[PROTO_NUM];
+
 // defaults for clientinfo messages
 #define	DEFAULT_VIEWHEIGHT	22
 
+// if the high bit of the servercmd is set, the low bits are fast update flags:
+enum {
+	// game types sent by serverinfo
+	// these determine which intermission screen plays
+	GAME_COOP = 0,
+	GAME_DEATHMATCH,
 
-// game types sent by serverinfo
-// these determine which intermission screen plays
-#define	GAME_COOP			0
-#define	GAME_DEATHMATCH		1
+	U_MOREBITS = 1<<0,
+	U_ORIGIN1 = 1<<1,
+	U_ORIGIN2 = 1<<2,
+	U_ORIGIN3 = 1<<3,
+	U_ANGLE2 = 1<<4,
+	U_NOLERP = 1<<5,		// don't interpolate movement
+	U_FRAME = 1<<6,
+	U_SIGNAL = 1<<7,		// just differentiates from other updates
+	// svc_update can pass all of the fast update bits, plus more
+	U_ANGLE1 = 1<<8,
+	U_ANGLE3 = 1<<9,
+	U_MODEL = 1<<10,
+	U_COLORMAP = 1<<11,
+	U_SKIN = 1<<12,
+	U_EFFECTS = 1<<13,
+	U_LONGENTITY = 1<<14,
+	U_MOREBITS2 = 1<<15,
+	// some of the bits here (1<<16…1<<22) are reserved by specific protocols
+	U_MOREBITS3 = 1<<23,
 
-//==================
-// note that there are some defs.qc that mirror to these numbers
-// also related to svc_strings[] in cl_parse
-//==================
+	SU_VIEWHEIGHT = 1<<0,
+	SU_IDEALPITCH = 1<<1,
+	SU_PUNCH1 = 1<<2,
+	SU_PUNCH2 = 1<<3,
+	SU_PUNCH3 = 1<<4,
+	SU_VELOCITY1 = 1<<5,
+	SU_VELOCITY2 = 1<<6,
+	SU_VELOCITY3 = 1<<7,
+	//SU_AIMENT = 1<<8,  AVAILABLE BIT
+	SU_ITEMS = 1<<9,
+	SU_ONGROUND = 1<<10,		// no data follows, the bit is it
+	SU_INWATER = 1<<11,		// no data follows, the bit is it
+	SU_WEAPONFRAME = 1<<12,
+	SU_ARMOR = 1<<13,
+	SU_WEAPON = 1<<14,
+	SU_MOREBITS = 1<<15,
+	// some of the bits here (1<<16…1<<22) are reserved by specific protocols
+	SU_MOREBITS2 = 1<<23,
 
-//
-// server to client
-//
-#define	svc_bad				0
-#define	svc_nop				1
-#define	svc_disconnect		2
-#define	svc_updatestat		3	// [byte] [long]
-#define	svc_version			4	// [long] server version
-#define	svc_setview			5	// [short] entity number
-#define	svc_sound			6	// <see code>
-#define	svc_time			7	// [float] server time
-#define	svc_print			8	// [string] null terminated string
-#define	svc_stufftext		9	// [string] stuffed into client's console buffer
+	// a sound with no channel is a local only sound
+	SND_VOLUME = 1<<0,		// a byte
+	SND_ATTENUATION = 1<<1,		// a byte
+	SND_LOOPING = 1<<2,		// a long
+
+	// server to client
+	svc_bad = 0,
+	svc_nop,
+	svc_disconnect,
+	svc_updatestat, // [byte] [long]
+	svc_version, // [long] server version
+	svc_setview, // [short] entity number
+	svc_sound, // <see code>
+	svc_time, // [float] server time
+	svc_print, // [string] null terminated string
+	svc_stufftext, // [string] stuffed into client's console buffer
 								// the string should be \n terminated
-#define	svc_setangle		10	// [angle3] set the view angle to this absolute value
-	
-#define	svc_serverinfo		11	// [long] version
+	svc_setangle, // [angle3] set the view angle to this absolute value
+	svc_serverinfo, // [long] version
 						// [string] signon string
 						// [string]..[0]model cache
 						// [string]...[0]sounds cache
-#define	svc_lightstyle		12	// [byte] [string]
-#define	svc_updatename		13	// [byte] [string]
-#define	svc_updatefrags		14	// [byte] [short]
-#define	svc_clientdata		15	// <shortbits + data>
-#define	svc_stopsound		16	// <see code>
-#define	svc_updatecolors	17	// [byte] [byte]
-#define	svc_particle		18	// [vec3] <variable>
-#define	svc_damage			19
-	
-#define	svc_spawnstatic		20
-//	svc_spawnbinary		21
-#define	svc_spawnbaseline	22
-	
-#define	svc_temp_entity		23
+	svc_lightstyle, // [byte] [string]
+	svc_updatename, // [byte] [string]
+	svc_updatefrags, // [byte] [short]
+	svc_clientdata, // <shortbits + data>
+	svc_stopsound, // <see code>
+	svc_updatecolors, // [byte] [byte]
+	svc_particle, // [vec3] <variable>
+	svc_damage,
+	svc_spawnstatic,
+	svc_spawnbinary, // unused
+	svc_spawnbaseline,
+	svc_temp_entity,
+	svc_setpause, // [byte] on / off
+	svc_signonnum, // [byte]  used for the signon sequence
+	svc_centerprint, // [string] to put in center of the screen
+	svc_killedmonster,
+	svc_foundsecret,
+	svc_spawnstaticsound, // [coord3] [byte] samp [byte] vol [byte] aten
+	svc_intermission, // [string] music
+	svc_finale, // [string] music [string] text
+	svc_cdtrack, // [byte] track [byte] looptrack
+	svc_sellscreen,
+	svc_cutscene,
 
-#define	svc_setpause		24	// [byte] on / off
-#define	svc_signonnum		25	// [byte]  used for the signon sequence
+	// non-NQ stuff
+	svc_spawnbaseline2 = 42,
+	svc_spawnstatic2,
+	svc_spawnstaticsound2,
 
-#define	svc_centerprint		26	// [string] to put in center of the screen
+	// client to server
+	clc_bad = 0,
+	clc_nop,
+	clc_disconnect,
+	clc_move, // [usercmd_t]
+	clc_stringcmd, // [string] message
 
-#define	svc_killedmonster	27
-#define	svc_foundsecret		28
-
-#define	svc_spawnstaticsound	29	// [coord3] [byte] samp [byte] vol [byte] aten
-
-#define	svc_intermission	30		// [string] music
-#define	svc_finale			31		// [string] music [string] text
-
-#define	svc_cdtrack			32		// [byte] track [byte] looptrack
-#define svc_sellscreen		33
-
-#define svc_cutscene		34
-
-//
-// client to server
-//
-#define	clc_bad			0
-#define	clc_nop 		1
-#define	clc_disconnect	2
-#define	clc_move		3			// [usercmd_t]
-#define	clc_stringcmd	4		// [string] message
-
-
-//
-// temp entity events
-//
-#define	TE_SPIKE			0
-#define	TE_SUPERSPIKE		1
-#define	TE_GUNSHOT			2
-#define	TE_EXPLOSION		3
-#define	TE_TAREXPLOSION		4
-#define	TE_LIGHTNING1		5
-#define	TE_LIGHTNING2		6
-#define	TE_WIZSPIKE			7
-#define	TE_KNIGHTSPIKE		8
-#define	TE_LIGHTNING3		9
-#define	TE_LAVASPLASH		10
-#define	TE_TELEPORT			11
-#define TE_EXPLOSION2		12
-
-// PGM 01/21/97 
-#define TE_BEAM				13
-// PGM 01/21/97 
+	// temp entity events
+	TE_SPIKE = 0,
+	TE_SUPERSPIKE,
+	TE_GUNSHOT,
+	TE_EXPLOSION,
+	TE_TAREXPLOSION,
+	TE_LIGHTNING1,
+	TE_LIGHTNING2,
+	TE_WIZSPIKE,
+	TE_KNIGHTSPIKE,
+	TE_LIGHTNING3,
+	TE_LAVASPLASH,
+	TE_TELEPORT,
+	TE_EXPLOSION2,
+	TE_BEAM,
+};
--- a/quakedef.h
+++ b/quakedef.h
@@ -34,8 +34,8 @@
 //
 #define	MAX_EDICTS		65536
 #define	Nlights	64
-#define	MAX_MODELS		4096			// these are sent over the net as bytes
-#define	MAX_SOUNDS		2048			// so they cannot be blindly increased
+#define	MAX_MODELS		4096			// these are sent over the net as bytes with NQ
+#define	MAX_SOUNDS		2048
 
 #define	MAX_STYLESTRING	64
 
--- a/r_part.c
+++ b/r_part.c
@@ -120,7 +120,7 @@
 	vec3_t		org, dir;
 	int			i, count, msgcount, color;
 	
-	MSG_ReadVec(org);
+	MSG_ReadVec(cl.protocol, org);
 	for (i=0 ; i<3 ; i++)
 		dir[i] = MSG_ReadChar () * (1.0/16);
 	msgcount = MSG_ReadByte ();
--- a/server.h
+++ b/server.h
@@ -11,21 +11,6 @@
 
 typedef enum {ss_loading, ss_active} server_state_t;
 
-enum {
-	PROTO_NQ,
-	PROTO_RMQ,
-	PROTO_NUM,
-};
-
-typedef struct {
-	int id;
-	char *name;
-	void (*MSG_WriteCoord)(sizebuf_t *sb, float f);
-	void (*MSG_WriteAngle)(sizebuf_t *sb, float f);
-	float (*MSG_ReadCoord)(void);
-	float (*MSG_ReadAngle)(void);
-}protocol_t;
-
 typedef struct
 {
 	qboolean	active;				// false if only a net client
@@ -101,62 +86,62 @@
 
 //=============================================================================
 
-// edict->movetype values
-#define	MOVETYPE_NONE			0		// never moves
-#define	MOVETYPE_ANGLENOCLIP	1
-#define	MOVETYPE_ANGLECLIP		2
-#define	MOVETYPE_WALK			3		// gravity
-#define	MOVETYPE_STEP			4		// gravity, special edge handling
-#define	MOVETYPE_FLY			5
-#define	MOVETYPE_TOSS			6		// gravity
-#define	MOVETYPE_PUSH			7		// no clip to world, push and crush
-#define	MOVETYPE_NOCLIP			8
-#define	MOVETYPE_FLYMISSILE		9		// extra size to monsters
-#define	MOVETYPE_BOUNCE			10
+enum {
+	// edict->movetype values
+	MOVETYPE_NONE, // never moves
+	MOVETYPE_ANGLENOCLIP,
+	MOVETYPE_ANGLECLIP,
+	MOVETYPE_WALK, // gravity
+	MOVETYPE_STEP, // gravity, special edge handling
+	MOVETYPE_FLY,
+	MOVETYPE_TOSS, // gravity
+	MOVETYPE_PUSH, // no clip to world, push and crush
+	MOVETYPE_NOCLIP,
+	MOVETYPE_FLYMISSILE, // extra size to monsters
+	MOVETYPE_BOUNCE,
 
-// edict->solid values
-#define	SOLID_NOT				0		// no interaction with other objects
-#define	SOLID_TRIGGER			1		// touch on edge, but not blocking
-#define	SOLID_BBOX				2		// touch on edge, block
-#define	SOLID_SLIDEBOX			3		// touch on edge, but not an onground
-#define	SOLID_BSP				4		// bsp clip, touch on edge, block
+	// edict->solid values
+	SOLID_NOT = 0, // no interaction with other objects
+	SOLID_TRIGGER, // touch on edge, but not blocking
+	SOLID_BBOX, // touch on edge, block
+	SOLID_SLIDEBOX, // touch on edge, but not an onground
+	SOLID_BSP, // bsp clip, touch on edge, block
 
-// edict->deadflag values
-#define	DEAD_NO					0
-#define	DEAD_DYING				1
-#define	DEAD_DEAD				2
+	// edict->deadflag values
+	DEAD_NO = 0,
+	DEAD_DYING,
+	DEAD_DEAD,
 
-#define	DAMAGE_NO				0
-#define	DAMAGE_YES				1
-#define	DAMAGE_AIM				2
+	DAMAGE_NO = 0,
+	DAMAGE_YES,
+	DAMAGE_AIM,
 
-// edict->flags
-#define	FL_FLY					1
-#define	FL_SWIM					2
-//#define	FL_GLIMPSE				4
-#define	FL_CONVEYOR				4
-#define	FL_CLIENT				8
-#define	FL_INWATER				16
-#define	FL_MONSTER				32
-#define	FL_GODMODE				64
-#define	FL_NOTARGET				128
-#define	FL_ITEM					256
-#define	FL_ONGROUND				512
-#define	FL_PARTIALGROUND		1024	// not all corners are valid
-#define	FL_WATERJUMP			2048	// player jumping out of water
-#define	FL_JUMPRELEASED			4096	// for jump debouncing
+	// edict->flags
+	FL_FLY = 1<<0,
+	FL_SWIM = 1<<1,
+	FL_CONVEYOR = 1<<2,
+	FL_CLIENT = 1<<3,
+	FL_INWATER = 1<<4,
+	FL_MONSTER = 1<<5,
+	FL_GODMODE = 1<<6,
+	FL_NOTARGET = 1<<7,
+	FL_ITEM = 1<<8,
+	FL_ONGROUND = 1<<9,
+	FL_PARTIALGROUND = 1<<10, // not all corners are valid
+	FL_WATERJUMP = 1<<11, // player jumping out of water
+	FL_JUMPRELEASED = 1<<12, // for jump debouncing
 
-// entity effects
+	// entity effects
+	EF_BRIGHTFIELD = 1<<0,
+	EF_MUZZLEFLASH = 1<<1,
+	EF_BRIGHTLIGHT = 1<<2,
+	EF_DIMLIGHT = 1<<3,
 
-#define	EF_BRIGHTFIELD			1
-#define	EF_MUZZLEFLASH 			2
-#define	EF_BRIGHTLIGHT 			4
-#define	EF_DIMLIGHT 			8
-
-#define	SPAWNFLAG_NOT_EASY			256
-#define	SPAWNFLAG_NOT_MEDIUM		512
-#define	SPAWNFLAG_NOT_HARD			1024
-#define	SPAWNFLAG_NOT_DEATHMATCH	2048
+	SPAWNFLAG_NOT_EASY = 1<<8,
+	SPAWNFLAG_NOT_MEDIUM = 1<<9,
+	SPAWNFLAG_NOT_HARD = 1<<10,
+	SPAWNFLAG_NOT_DEATHMATCH = 1<<11,
+};
 
 //============================================================================
 
--- a/sv_main.c
+++ b/sv_main.c
@@ -7,25 +7,6 @@
 server_t		sv;
 server_static_t	svs;
 
-static protocol_t protos[PROTO_NUM] = {
-	[PROTO_NQ] = {
-		.id = PROTO_NQ,
-		.name = "Quake",
-		.MSG_WriteCoord = MSG_WriteCoord,
-		.MSG_WriteAngle = MSG_WriteAngle,
-		.MSG_ReadCoord = MSG_ReadCoord,
-		.MSG_ReadAngle = MSG_ReadAngle,
-	},
-	[PROTO_RMQ] = {
-		.id = PROTO_RMQ,
-		.name = "RMQ",
-		.MSG_WriteCoord = MSG_WriteCoordInt32,
-		.MSG_WriteAngle = MSG_WriteAngleInt16,
-		.MSG_ReadCoord = MSG_ReadCoordInt32,
-		.MSG_ReadAngle = MSG_ReadAngleInt16,
-	},
-};
-
 // we can't just change protocol mid-game, so it's saved here first
 static protocol_t *sv_protocol = &protos[PROTO_RMQ];
 
@@ -111,9 +92,7 @@
 	if (sv.datagram.cursize > MAX_DATAGRAM-16)
 		return;	
 	MSG_WriteByte (&sv.datagram, svc_particle);
-	sv.protocol->MSG_WriteCoord (&sv.datagram, org[0]);
-	sv.protocol->MSG_WriteCoord (&sv.datagram, org[1]);
-	sv.protocol->MSG_WriteCoord (&sv.datagram, org[2]);
+	MSG_WriteVec(sv.protocol, &sv.datagram, org);
 	for (i=0 ; i<3 ; i++)
 	{
 		v = dir[i]*16;
@@ -149,17 +128,8 @@
     int field_mask;
     int			i;
 	int			ent;
-	
-	if (volume < 0 || volume > 255)
-		fatal ("SV_StartSound: volume = %d", volume);
 
-	if (attenuation < 0 || attenuation > 4)
-		fatal ("SV_StartSound: attenuation = %f", attenuation);
-
-	if (channel < 0 || channel > 7)
-		fatal ("SV_StartSound: channel = %d", channel);
-
-	if (sv.datagram.cursize > MAX_DATAGRAM-16)
+	if (sv.datagram.cursize > MAX_DATAGRAM-21)
 		return;	
 
 // find precache number for sound
@@ -173,29 +143,41 @@
         Con_Printf ("SV_StartSound: %s not precacheed\n", sample);
         return;
     }
-    
+
+	volume = clamp(volume, 0, 255);
+	attenuation = clamp(attenuation, 0, 4);
+	channel = max(channel, 0);
 	ent = NUM_FOR_EDICT(entity);
-	if(ent > 8191 || channel > 7 || sound_num > 255){ // FIXME(sigrid) - better protocol
+	if(ent >= sv.protocol->limit_entity || channel >= sv.protocol->limit_channel || sound_num >= sv.protocol->limit_sound)
 		return;
-	}
 
-	channel = (ent<<3) | channel;
-
 	field_mask = 0;
-	if (volume != Spktvol)
+	if(ent >= sv.protocol->large_entity || channel >= sv.protocol->large_channel)
+		field_mask |= sv.protocol->fl_large_entity | sv.protocol->fl_large_channel;
+	if(sound_num >= sv.protocol->large_sound)
+		field_mask |= sv.protocol->fl_large_sound;
+	if(volume != Spktvol)
 		field_mask |= SND_VOLUME;
-	if (attenuation != Spktatt)
+	if(attenuation != Spktatt)
 		field_mask |= SND_ATTENUATION;
 
 // directed messages go only to the entity the are targeted on
-	MSG_WriteByte (&sv.datagram, svc_sound);
-	MSG_WriteByte (&sv.datagram, field_mask);
-	if (field_mask & SND_VOLUME)
-		MSG_WriteByte (&sv.datagram, volume);
-	if (field_mask & SND_ATTENUATION)
-		MSG_WriteByte (&sv.datagram, attenuation*64);
-	MSG_WriteShort (&sv.datagram, channel);
-	MSG_WriteByte (&sv.datagram, sound_num);
+	MSG_WriteByte(&sv.datagram, svc_sound);
+	MSG_WriteByte(&sv.datagram, field_mask);
+	if(field_mask & SND_VOLUME)
+		MSG_WriteByte(&sv.datagram, volume);
+	if(field_mask & SND_ATTENUATION)
+		MSG_WriteByte(&sv.datagram, attenuation*64);
+	if(field_mask & (sv.protocol->fl_large_entity | sv.protocol->fl_large_channel)){
+		MSG_WriteShort(&sv.datagram, ent);
+		MSG_WriteByte(&sv.datagram, channel);
+	}else{
+		MSG_WriteShort(&sv.datagram, ent<<3 | channel);
+	}
+	if(field_mask & sv.protocol->fl_large_sound)
+		MSG_WriteShort(&sv.datagram, sound_num);
+	else
+		MSG_WriteByte(&sv.datagram, sound_num);
 	for (i=0 ; i<3 ; i++)
 		sv.protocol->MSG_WriteCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]));
 }           
@@ -218,34 +200,31 @@
 */
 void SV_SendServerinfo (client_t *client)
 {
-	char			**s;
-	char			message[2048];
+	char **s;
+	int n;
+	char tmp[64];
 
 	MSG_WriteByte (&client->message, svc_print);
-	sprint(message, "%c\nVERSION %4.2f SERVER (%ud CRC)\n", 2, VERSION, crcn);
-	MSG_WriteString (&client->message,message);
+	snprint(tmp, sizeof(tmp), "%c\nNeinQuake %4.2f SERVER (%ud CRC)\n", 2, VERSION, crcn);
+	MSG_WriteString (&client->message, tmp);
 
 	MSG_WriteByte (&client->message, svc_serverinfo);
-	MSG_WriteLong (&client->message, PROTOCOL_VERSION);
+	MSG_WriteLong (&client->message, sv.protocol->version);
+	sv.protocol->MSG_WriteProtocolInfo(&client->message, sv.protocol);
 	MSG_WriteByte (&client->message, svs.maxclients);
 
-	if (!coop.value && deathmatch.value)
-		MSG_WriteByte (&client->message, GAME_DEATHMATCH);
-	else
-		MSG_WriteByte (&client->message, GAME_COOP);
+	MSG_WriteByte (&client->message, (!coop.value && deathmatch.value) ? GAME_DEATHMATCH : GAME_COOP);
 
-	sprint (message, PR_Str(sv.edicts->v.message));
+	MSG_WriteString (&client->message, PR_Str(sv.edicts->v.message));
 
-	MSG_WriteString (&client->message,message);
+	for (n = 1, s = sv.model_precache+1 ; *s && n < sv.protocol->limit_model ; s++)
+		MSG_WriteString(&client->message, *s);
+	MSG_WriteByte(&client->message, 0);
 
-	for (s = sv.model_precache+1 ; *s ; s++)
-		MSG_WriteString (&client->message, *s);
-	MSG_WriteByte (&client->message, 0);
+	for (n = 1, s = sv.sound_precache+1 ; *s && n < sv.protocol->limit_sound ; s++)
+		MSG_WriteString(&client->message, *s);
+	MSG_WriteByte(&client->message, 0);
 
-	for (s = sv.sound_precache+1 ; *s ; s++)
-		MSG_WriteString (&client->message, *s);
-	MSG_WriteByte (&client->message, 0);
-
 // send music
 	MSG_WriteByte (&client->message, svc_cdtrack);
 	MSG_WriteByte (&client->message, sv.edicts->v.sounds);
@@ -453,8 +432,8 @@
 */
 void SV_WriteEntitiesToClient (edict_t	*clent, sizebuf_t *msg)
 {
+	u32int	bits;
 	int		e, i;
-	int		bits;
 	byte	*pvs;
 	vec3_t	org;
 	float	miss;
@@ -468,8 +447,6 @@
 	ent = NEXT_EDICT(sv.edicts);
 	for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent))
 	{
-		if (e > 65535) // FIXME(sigrid) - better protocol
-			continue;
 // ignore if not touching a PV leaf
 		if (ent != clent)	// clent is ALLWAYS sent
 		{
@@ -476,7 +453,7 @@
 // ignore ents without visible models
 			if (!ent->v.modelindex || !*PR_Str(ent->v.model))
 				continue;
-			if(ent->v.modelindex > 0xff) // FIXME(sigrid) - better protocol
+			if(ent->v.modelindex >= sv.protocol->limit_model)
 				continue;
 
 			for (i=0 ; i < ent->num_leafs ; i++)
@@ -483,7 +460,7 @@
 				if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
 					break;
 
-			if (i == ent->num_leafs)
+			if (i == ent->num_leafs && ent->num_leafs < MAX_ENT_LEAFS)
 				continue;		// not visible
 		}
 
@@ -502,47 +479,57 @@
 			if ( miss < -0.1 || miss > 0.1 )
 				bits |= U_ORIGIN1<<i;
 		}
-
 		if ( ent->v.angles[0] != ent->baseline.angles[0] )
 			bits |= U_ANGLE1;
-			
 		if ( ent->v.angles[1] != ent->baseline.angles[1] )
 			bits |= U_ANGLE2;
-			
 		if ( ent->v.angles[2] != ent->baseline.angles[2] )
 			bits |= U_ANGLE3;
-			
 		if (ent->v.movetype == MOVETYPE_STEP)
 			bits |= U_NOLERP;	// don't mess up the step animation
-	
 		if (ent->baseline.colormap != ent->v.colormap)
 			bits |= U_COLORMAP;
-			
 		if (ent->baseline.skin != ent->v.skin)
 			bits |= U_SKIN;
-			
 		if (ent->baseline.frame != ent->v.frame)
 			bits |= U_FRAME;
-		
 		if (ent->baseline.effects != ent->v.effects)
 			bits |= U_EFFECTS;
-		
 		if (ent->baseline.modelindex != ent->v.modelindex)
 			bits |= U_MODEL;
-
 		if (e >= 256)
 			bits |= U_LONGENTITY;
-			
-		if (bits >= 256)
+		if((bits & U_FRAME) != 0){
+			if(ent->v.frame >= sv.protocol->limit_frame)
+				bits ^= U_FRAME;
+			else if(ent->v.frame >= sv.protocol->large_frame)
+				bits |= sv.protocol->fl_large_frame;
+		}
+		if((bits & U_MODEL) != 0){
+			if(ent->v.model >= sv.protocol->limit_model)
+				bits ^= U_MODEL;
+			else if(ent->v.model >= sv.protocol->large_model)
+				bits |= sv.protocol->fl_large_model;
+		}
+		if(bits >= (1<<8)){
 			bits |= U_MOREBITS;
-
+			if(bits >= (1<<16)){
+				bits |= U_MOREBITS2;
+				if(bits >= (1<<24))
+					bits |= U_MOREBITS3;
+			}
+		}
 	//
 	// write the message
 	//
-		MSG_WriteByte (msg,bits | U_SIGNAL);
-		
+		MSG_WriteByte (msg, bits | U_SIGNAL);
+
 		if (bits & U_MOREBITS)
 			MSG_WriteByte (msg, bits>>8);
+		if (bits & U_MOREBITS2)
+			MSG_WriteByte (msg, bits>>16);
+		if (bits & U_MOREBITS3)
+			MSG_WriteByte (msg, bits>>24);
 		if (bits & U_LONGENTITY)
 			MSG_WriteShort (msg,e);
 		else
@@ -570,6 +557,10 @@
 			sv.protocol->MSG_WriteCoord (msg, ent->v.origin[2]);
 		if (bits & U_ANGLE3)
 			sv.protocol->MSG_WriteAngle(msg, ent->v.angles[2]);
+		if (bits & sv.protocol->fl_large_frame)
+			MSG_WriteByte(msg, (int)ent->v.frame>>8);
+		if (bits & sv.protocol->fl_large_model)
+			MSG_WriteByte(msg, (int)ent->v.modelindex>>8);
 	}
 }
 
@@ -600,10 +591,10 @@
 */
 void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
 {
-	int		bits;
+	u32int	bits;
 	int		i;
 	edict_t	*other;
-	int		items;
+	int		items, weaponmodel;
 	eval_t	*val;
 
 //
@@ -632,15 +623,13 @@
 	{
 		MSG_WriteByte (msg, svc_setangle);
 		for (i=0 ; i < 3 ; i++)
-			sv.protocol->MSG_WriteAngle (msg, ent->v.angles[i] );
+			sv.protocol->MSG_WriteAngle (msg, ent->v.angles[i]);
 		ent->v.fixangle = 0;
 	}
 
-	bits = 0;
-	
+	bits = SU_ITEMS | SU_WEAPON;
 	if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT)
 		bits |= SU_VIEWHEIGHT;
-		
 	if (ent->v.idealpitch)
 		bits |= SU_IDEALPITCH;
 
@@ -647,45 +636,56 @@
 // stuff the sigil bits into the high bits of items for sbar, or else
 // mix in items2
 	val = GetEdictFieldValue(ent, "items2");
+	items = (int)ent->v.items | (val ? ((int)val->_float << 23) : ((int)pr_global_struct->serverflags << 28));
+	weaponmodel = SV_ModelIndex(PR_Str(ent->v.weaponmodel));
 
-	if (val)
-		items = (int)ent->v.items | ((int)val->_float << 23);
-	else
-		items = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28);
-
-	bits |= SU_ITEMS;
-	
-	if ( (int)ent->v.flags & FL_ONGROUND)
+	if ((int)ent->v.flags & FL_ONGROUND)
 		bits |= SU_ONGROUND;
-	
-	if ( ent->v.waterlevel >= 2)
+	if (ent->v.waterlevel >= 2)
 		bits |= SU_INWATER;
-	
+
 	for (i=0 ; i<3 ; i++)
 	{
 		if (ent->v.punchangle[i])
-			bits |= (SU_PUNCH1<<i);
+			bits |= SU_PUNCH1<<i;
 		if (ent->v.velocity[i])
-			bits |= (SU_VELOCITY1<<i);
+			bits |= SU_VELOCITY1<<i;
 	}
-	
-	if (ent->v.weaponframe)
-		bits |= SU_WEAPONFRAME;
 
+	if (bits & SU_WEAPON){
+		if(weaponmodel >= sv.protocol->limit_model)
+			bits ^= SU_WEAPON; // yikes.
+		else if(weaponmodel >= sv.protocol->large_model)
+			bits |= sv.protocol->fl_large_weaponmodel;
+	}
+	if (ent->v.weaponframe){
+		bits |= SU_WEAPONFRAME;
+		if((int)ent->v.weaponframe >= sv.protocol->limit_frame)
+			bits ^= SU_WEAPONFRAME;
+		else if((int)ent->v.weaponframe >= sv.protocol->large_frame)
+			bits |= sv.protocol->fl_large_weaponframe;
+	}
 	if (ent->v.armorvalue)
 		bits |= SU_ARMOR;
 
-//	if (ent->v.weapon)
-		bits |= SU_WEAPON;
+	if(bits >= (1<<16)){
+		bits |= SU_MOREBITS;
+		if(bits >= (1<<24))
+			bits |= SU_MOREBITS2;
+	}
 
 // send the data
 
 	MSG_WriteByte (msg, svc_clientdata);
 	MSG_WriteShort (msg, bits);
+	if(bits & SU_MOREBITS){
+		MSG_WriteByte(msg, bits>>16);
+		if(bits & SU_MOREBITS2)
+			MSG_WriteByte(msg, bits>>24);
+	}
 
 	if (bits & SU_VIEWHEIGHT)
 		MSG_WriteChar (msg, ent->v.view_ofs[2]);
-
 	if (bits & SU_IDEALPITCH)
 		MSG_WriteChar (msg, ent->v.idealpitch);
 
@@ -705,7 +705,7 @@
 	if (bits & SU_ARMOR)
 		MSG_WriteByte (msg, ent->v.armorvalue);
 	if (bits & SU_WEAPON)
-		MSG_WriteByte (msg, SV_ModelIndex(PR_Str(ent->v.weaponmodel)));
+		MSG_WriteByte (msg, weaponmodel);
 	
 	MSG_WriteShort (msg, ent->v.health);
 	MSG_WriteByte (msg, ent->v.currentammo);
@@ -729,6 +729,11 @@
 			}
 		}
 	}
+
+	if(bits & sv.protocol->fl_large_weaponmodel)
+		MSG_WriteByte(msg, weaponmodel>>8);
+	if(bits & sv.protocol->fl_large_weaponframe)
+		MSG_WriteByte(msg, (int)ent->v.weaponframe>>8);
 }
 
 /*
@@ -944,6 +949,7 @@
 */
 void SV_CreateBaseline (void)
 {
+	u32int bits;
 	int			i;
 	edict_t			*svent;
 	int				entnum;	
@@ -975,15 +981,29 @@
 			svent->baseline.modelindex =
 				SV_ModelIndex(PR_Str(svent->v.model));
 		}
-		
+
+		bits = 0;
+		if(svent->baseline.modelindex >= sv.protocol->limit_model)
+			svent->baseline.modelindex = 0; // yikes.
+		else if(svent->baseline.modelindex >= sv.protocol->large_model)
+			bits |= sv.protocol->fl_large_baseline_model;
+		if(svent->baseline.frame >= sv.protocol->limit_frame)
+			svent->baseline.frame = 0; // yikes.
+		else if(svent->baseline.frame >= sv.protocol->large_frame)
+			bits |= sv.protocol->fl_large_baseline_frame;
+
 	//
 	// add to the message
 	//
-		MSG_WriteByte (&sv.signon,svc_spawnbaseline);		
-		MSG_WriteShort (&sv.signon,entnum);
+		MSG_WriteByte (&sv.signon, bits ? svc_spawnbaseline2 : svc_spawnbaseline);
+		MSG_WriteShort (&sv.signon, entnum);
+		if(bits != 0)
+			MSG_WriteByte(&sv.signon, bits);
 
-		MSG_WriteByte (&sv.signon, svent->baseline.modelindex);
-		MSG_WriteByte (&sv.signon, svent->baseline.frame);
+		((bits & sv.protocol->fl_large_baseline_model) ? MSG_WriteShort : MSG_WriteByte)
+			(&sv.signon, svent->baseline.modelindex);
+		((bits & sv.protocol->fl_large_baseline_frame) ? MSG_WriteShort : MSG_WriteByte)
+			(&sv.signon, svent->baseline.frame);
 		MSG_WriteByte (&sv.signon, svent->baseline.colormap);
 		MSG_WriteByte (&sv.signon, svent->baseline.skin);
 		for (i=0 ; i<3 ; i++)
--- a/view.c
+++ b/view.c
@@ -299,7 +299,7 @@
 	
 	armor = MSG_ReadByte ();
 	blood = MSG_ReadByte ();
-	MSG_ReadVec(from);
+	MSG_ReadVec(cl.protocol, from);
 
 	count = blood*0.5 + armor*0.5;
 	if (count < 10)