/*
 * Copyright (C) 1997-2001 Id Software, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * =======================================================================
 *
 * Movement message (forward, backward, left, right, etc) handling.
 *
 * =======================================================================
 */

#include "header/common.h"

vec3_t bytedirs[NUMVERTEXNORMALS] = {
	{-0.525731, 0.000000, 0.850651},
	{-0.442863, 0.238856, 0.864188},
	{-0.295242, 0.000000, 0.955423},
	{-0.309017, 0.500000, 0.809017},
	{-0.162460, 0.262866, 0.951056},
	{0.000000, 0.000000, 1.000000},
	{0.000000, 0.850651, 0.525731},
	{-0.147621, 0.716567, 0.681718},
	{0.147621, 0.716567, 0.681718},
	{0.000000, 0.525731, 0.850651},
	{0.309017, 0.500000, 0.809017},
	{0.525731, 0.000000, 0.850651},
	{0.295242, 0.000000, 0.955423},
	{0.442863, 0.238856, 0.864188},
	{0.162460, 0.262866, 0.951056},
	{-0.681718, 0.147621, 0.716567},
	{-0.809017, 0.309017, 0.500000},
	{-0.587785, 0.425325, 0.688191},
	{-0.850651, 0.525731, 0.000000},
	{-0.864188, 0.442863, 0.238856},
	{-0.716567, 0.681718, 0.147621},
	{-0.688191, 0.587785, 0.425325},
	{-0.500000, 0.809017, 0.309017},
	{-0.238856, 0.864188, 0.442863},
	{-0.425325, 0.688191, 0.587785},
	{-0.716567, 0.681718, -0.147621},
	{-0.500000, 0.809017, -0.309017},
	{-0.525731, 0.850651, 0.000000},
	{0.000000, 0.850651, -0.525731},
	{-0.238856, 0.864188, -0.442863},
	{0.000000, 0.955423, -0.295242},
	{-0.262866, 0.951056, -0.162460},
	{0.000000, 1.000000, 0.000000},
	{0.000000, 0.955423, 0.295242},
	{-0.262866, 0.951056, 0.162460},
	{0.238856, 0.864188, 0.442863},
	{0.262866, 0.951056, 0.162460},
	{0.500000, 0.809017, 0.309017},
	{0.238856, 0.864188, -0.442863},
	{0.262866, 0.951056, -0.162460},
	{0.500000, 0.809017, -0.309017},
	{0.850651, 0.525731, 0.000000},
	{0.716567, 0.681718, 0.147621},
	{0.716567, 0.681718, -0.147621},
	{0.525731, 0.850651, 0.000000},
	{0.425325, 0.688191, 0.587785},
	{0.864188, 0.442863, 0.238856},
	{0.688191, 0.587785, 0.425325},
	{0.809017, 0.309017, 0.500000},
	{0.681718, 0.147621, 0.716567},
	{0.587785, 0.425325, 0.688191},
	{0.955423, 0.295242, 0.000000},
	{1.000000, 0.000000, 0.000000},
	{0.951056, 0.162460, 0.262866},
	{0.850651, -0.525731, 0.000000},
	{0.955423, -0.295242, 0.000000},
	{0.864188, -0.442863, 0.238856},
	{0.951056, -0.162460, 0.262866},
	{0.809017, -0.309017, 0.500000},
	{0.681718, -0.147621, 0.716567},
	{0.850651, 0.000000, 0.525731},
	{0.864188, 0.442863, -0.238856},
	{0.809017, 0.309017, -0.500000},
	{0.951056, 0.162460, -0.262866},
	{0.525731, 0.000000, -0.850651},
	{0.681718, 0.147621, -0.716567},
	{0.681718, -0.147621, -0.716567},
	{0.850651, 0.000000, -0.525731},
	{0.809017, -0.309017, -0.500000},
	{0.864188, -0.442863, -0.238856},
	{0.951056, -0.162460, -0.262866},
	{0.147621, 0.716567, -0.681718},
	{0.309017, 0.500000, -0.809017},
	{0.425325, 0.688191, -0.587785},
	{0.442863, 0.238856, -0.864188},
	{0.587785, 0.425325, -0.688191},
	{0.688191, 0.587785, -0.425325},
	{-0.147621, 0.716567, -0.681718},
	{-0.309017, 0.500000, -0.809017},
	{0.000000, 0.525731, -0.850651},
	{-0.525731, 0.000000, -0.850651},
	{-0.442863, 0.238856, -0.864188},
	{-0.295242, 0.000000, -0.955423},
	{-0.162460, 0.262866, -0.951056},
	{0.000000, 0.000000, -1.000000},
	{0.295242, 0.000000, -0.955423},
	{0.162460, 0.262866, -0.951056},
	{-0.442863, -0.238856, -0.864188},
	{-0.309017, -0.500000, -0.809017},
	{-0.162460, -0.262866, -0.951056},
	{0.000000, -0.850651, -0.525731},
	{-0.147621, -0.716567, -0.681718},
	{0.147621, -0.716567, -0.681718},
	{0.000000, -0.525731, -0.850651},
	{0.309017, -0.500000, -0.809017},
	{0.442863, -0.238856, -0.864188},
	{0.162460, -0.262866, -0.951056},
	{0.238856, -0.864188, -0.442863},
	{0.500000, -0.809017, -0.309017},
	{0.425325, -0.688191, -0.587785},
	{0.716567, -0.681718, -0.147621},
	{0.688191, -0.587785, -0.425325},
	{0.587785, -0.425325, -0.688191},
	{0.000000, -0.955423, -0.295242},
	{0.000000, -1.000000, 0.000000},
	{0.262866, -0.951056, -0.162460},
	{0.000000, -0.850651, 0.525731},
	{0.000000, -0.955423, 0.295242},
	{0.238856, -0.864188, 0.442863},
	{0.262866, -0.951056, 0.162460},
	{0.500000, -0.809017, 0.309017},
	{0.716567, -0.681718, 0.147621},
	{0.525731, -0.850651, 0.000000},
	{-0.238856, -0.864188, -0.442863},
	{-0.500000, -0.809017, -0.309017},
	{-0.262866, -0.951056, -0.162460},
	{-0.850651, -0.525731, 0.000000},
	{-0.716567, -0.681718, -0.147621},
	{-0.716567, -0.681718, 0.147621},
	{-0.525731, -0.850651, 0.000000},
	{-0.500000, -0.809017, 0.309017},
	{-0.238856, -0.864188, 0.442863},
	{-0.262866, -0.951056, 0.162460},
	{-0.864188, -0.442863, 0.238856},
	{-0.809017, -0.309017, 0.500000},
	{-0.688191, -0.587785, 0.425325},
	{-0.681718, -0.147621, 0.716567},
	{-0.442863, -0.238856, 0.864188},
	{-0.587785, -0.425325, 0.688191},
	{-0.309017, -0.500000, 0.809017},
	{-0.147621, -0.716567, 0.681718},
	{-0.425325, -0.688191, 0.587785},
	{-0.162460, -0.262866, 0.951056},
	{0.442863, -0.238856, 0.864188},
	{0.162460, -0.262866, 0.951056},
	{0.309017, -0.500000, 0.809017},
	{0.147621, -0.716567, 0.681718},
	{0.000000, -0.525731, 0.850651},
	{0.425325, -0.688191, 0.587785},
	{0.587785, -0.425325, 0.688191},
	{0.688191, -0.587785, 0.425325},
	{-0.955423, 0.295242, 0.000000},
	{-0.951056, 0.162460, 0.262866},
	{-1.000000, 0.000000, 0.000000},
	{-0.850651, 0.000000, 0.525731},
	{-0.955423, -0.295242, 0.000000},
	{-0.951056, -0.162460, 0.262866},
	{-0.864188, 0.442863, -0.238856},
	{-0.951056, 0.162460, -0.262866},
	{-0.809017, 0.309017, -0.500000},
	{-0.864188, -0.442863, -0.238856},
	{-0.951056, -0.162460, -0.262866},
	{-0.809017, -0.309017, -0.500000},
	{-0.681718, 0.147621, -0.716567},
	{-0.681718, -0.147621, -0.716567},
	{-0.850651, 0.000000, -0.525731},
	{-0.688191, 0.587785, -0.425325},
	{-0.587785, 0.425325, -0.688191},
	{-0.425325, 0.688191, -0.587785},
	{-0.425325, -0.688191, -0.587785},
	{-0.587785, -0.425325, -0.688191},
	{-0.688191, -0.587785, -0.425325}
};

void
MSG_WriteChar(sizebuf_t *sb, int c)
{
	byte *buf;

	buf = SZ_GetSpace(sb, 1);
	buf[0] = c;
}

void
MSG_WriteByte(sizebuf_t *sb, int c)
{
	byte *buf;

	buf = SZ_GetSpace(sb, 1);
	buf[0] = c;
}

void
MSG_WriteShort(sizebuf_t *sb, int c)
{
	byte *buf;

	buf = SZ_GetSpace(sb, 2);
	buf[0] = c & 0xff;
	buf[1] = c >> 8;
}

void
MSG_WriteLong(sizebuf_t *sb, int c)
{
	byte *buf;

	buf = SZ_GetSpace(sb, 4);
	buf[0] = c & 0xff;
	buf[1] = (c >> 8) & 0xff;
	buf[2] = (c >> 16) & 0xff;
	buf[3] = c >> 24;
}

void
MSG_WriteFloat(sizebuf_t *sb, float f)
{
	union
	{
		float f;
		int l;
	} dat;

	dat.f = f;
	dat.l = LittleLong(dat.l);

	SZ_Write(sb, &dat.l, 4);
}

void
MSG_WriteString(sizebuf_t *sb, const char *s)
{
	if (!s)
	{
		SZ_Write(sb, "", 1);
	}

	else
	{
		SZ_Write(sb, s, (int)strlen(s) + 1);
	}
}

void
MSG_WriteCoord(sizebuf_t *sb, float f, int protocol)
{
	if (IS_QII97_PROTOCOL(protocol))
	{
		MSG_WriteShort(sb, (int)(f * 8));
	}
	else
	{
		MSG_WriteFloat(sb, f);
	}
}

void
MSG_WritePos(sizebuf_t *sb, const vec3_t pos, int protocol)
{
	MSG_WriteCoord(sb, pos[0], protocol);
	MSG_WriteCoord(sb, pos[1], protocol);
	MSG_WriteCoord(sb, pos[2], protocol);
}

void
MSG_WriteAngle(sizebuf_t *sb, float f)
{
	MSG_WriteByte(sb, (int)(f * 256 / 360) & 255);
}

void
MSG_WriteAngle16(sizebuf_t *sb, float f)
{
	MSG_WriteShort(sb, ANGLE2SHORT(f));
}

void
MSG_WriteDeltaUsercmd(sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd)
{
	int bits;

	/* Movement messages */
	bits = 0;

	if (cmd->angles[0] != from->angles[0])
	{
		bits |= CM_ANGLE1;
	}

	if (cmd->angles[1] != from->angles[1])
	{
		bits |= CM_ANGLE2;
	}

	if (cmd->angles[2] != from->angles[2])
	{
		bits |= CM_ANGLE3;
	}

	if (cmd->forwardmove != from->forwardmove)
	{
		bits |= CM_FORWARD;
	}

	if (cmd->sidemove != from->sidemove)
	{
		bits |= CM_SIDE;
	}

	if (cmd->upmove != from->upmove)
	{
		bits |= CM_UP;
	}

	if (cmd->buttons != from->buttons)
	{
		bits |= CM_BUTTONS;
	}

	if (cmd->impulse != from->impulse)
	{
		bits |= CM_IMPULSE;
	}

	MSG_WriteByte(buf, bits);

	if (bits & CM_ANGLE1)
	{
		MSG_WriteShort(buf, cmd->angles[0]);
	}

	if (bits & CM_ANGLE2)
	{
		MSG_WriteShort(buf, cmd->angles[1]);
	}

	if (bits & CM_ANGLE3)
	{
		MSG_WriteShort(buf, cmd->angles[2]);
	}

	if (bits & CM_FORWARD)
	{
		MSG_WriteShort(buf, cmd->forwardmove);
	}

	if (bits & CM_SIDE)
	{
		MSG_WriteShort(buf, cmd->sidemove);
	}

	if (bits & CM_UP)
	{
		MSG_WriteShort(buf, cmd->upmove);
	}

	if (bits & CM_BUTTONS)
	{
		MSG_WriteByte(buf, cmd->buttons);
	}

	if (bits & CM_IMPULSE)
	{
		MSG_WriteByte(buf, cmd->impulse);
	}

	MSG_WriteByte(buf, cmd->msec);
	MSG_WriteByte(buf, cmd->lightlevel);
}

void
MSG_WriteDir(sizebuf_t *sb, const vec3_t dir)
{
	int i, best;
	float d, bestd;

	if (!dir)
	{
		MSG_WriteByte(sb, 0);
		return;
	}

	bestd = 0;
	best = 0;

	for (i = 0; i < NUMVERTEXNORMALS; i++)
	{
		d = DotProduct(dir, bytedirs[i]);

		if (d > bestd)
		{
			bestd = d;
			best = i;
		}
	}

	MSG_WriteByte(sb, best);
}

void
MSG_ReadDir(sizebuf_t *sb, vec3_t dir)
{
	int b;

	b = MSG_ReadByte(sb);

	if (b >= NUMVERTEXNORMALS)
	{
		Com_Error(ERR_DROP, "MSF_ReadDir: out of range");
	}

	VectorCopy(bytedirs[b], dir);
}

/*
 * Writes part of a packetentities message.
 * Can delta from either a baseline or a previous packet_entity
 */
void
MSG_WriteDeltaEntity(const entity_xstate_t *from,
		const entity_xstate_t *to,
		sizebuf_t *msg,
		qboolean force,
		qboolean newentity,
		int protocol)
{
	int bits;

	if (!to->number)
	{
		Com_Error(ERR_FATAL, "Unset entity number");
	}

	if (to->number >= MAX_EDICTS)
	{
		Com_Error(ERR_DROP, "%s: bad entity %d >= %d\n",
			__func__, to->number, MAX_EDICTS);
	}

	/* send an update */
	bits = 0;

	if (to->number >= 256)
	{
		bits |= U_NUMBER16; /* number8 is implicit otherwise */
	}

	if (to->origin[0] != from->origin[0])
	{
		bits |= U_ORIGIN1;
	}

	if (to->origin[1] != from->origin[1])
	{
		bits |= U_ORIGIN2;
	}

	if (to->origin[2] != from->origin[2])
	{
		bits |= U_ORIGIN3;
	}

	if (to->angles[0] != from->angles[0])
	{
		bits |= U_ANGLE1;
	}

	if (to->angles[1] != from->angles[1])
	{
		bits |= U_ANGLE2;
	}

	if (to->angles[2] != from->angles[2])
	{
		bits |= U_ANGLE3;
	}

	if (to->skinnum != from->skinnum)
	{
		if ((unsigned)to->skinnum < 256)
		{
			bits |= U_SKIN8;
		}

		else if ((unsigned)to->skinnum < 0x10000)
		{
			bits |= U_SKIN16;
		}

		else
		{
			bits |= (U_SKIN8 | U_SKIN16);
		}
	}

	/* Scale with skins if force or different */
	if ((protocol == PROTOCOL_VERSION) &&
		((to->scale[0] != from->scale[0]) ||
		 (to->scale[1] != from->scale[1]) ||
		 (to->scale[2] != from->scale[2])))
	{
		bits |= (U_SKIN8 | U_SKIN16);
	}

	if (to->frame != from->frame)
	{
		if (to->frame < 256)
		{
			bits |= U_FRAME8;
		}

		else
		{
			bits |= U_FRAME16;
		}
	}

	if (to->effects != from->effects)
	{
		if (to->effects < 256)
		{
			bits |= U_EFFECTS8;
		}

		else if (to->effects < 0x8000)
		{
			bits |= U_EFFECTS16;
		}

		else
		{
			bits |= U_EFFECTS8 | U_EFFECTS16;
		}
	}

	if (to->rr_effects != from->rr_effects || to->rr_mesh != from->rr_mesh)
	{
		bits |= U_EFFECTS8 | U_EFFECTS16;
	}

	if (to->renderfx != from->renderfx)
	{
		if (to->renderfx < 256)
		{
			bits |= U_RENDERFX8;
		}

		else if (to->renderfx < 0x8000)
		{
			bits |= U_RENDERFX16;
		}

		else
		{
			bits |= U_RENDERFX8 | U_RENDERFX16;
		}
	}

	if (to->solid != from->solid)
	{
		bits |= U_SOLID;
	}

	/* event is not delta compressed, just 0 compressed */
	if (to->event)
	{
		bits |= U_EVENT;
	}

	if (to->modelindex != from->modelindex)
	{
		bits |= U_MODEL;
	}

	if (to->modelindex2 != from->modelindex2)
	{
		bits |= U_MODEL2;
	}

	if (to->modelindex3 != from->modelindex3)
	{
		bits |= U_MODEL3;
	}

	if (to->modelindex4 != from->modelindex4)
	{
		bits |= U_MODEL4;
	}

	if (to->sound != from->sound)
	{
		bits |= U_SOUND;
	}

	if (newentity || (to->renderfx & RF_BEAM))
	{
		bits |= U_OLDORIGIN;
	}

	/* write the message */
	if (!bits && !force)
	{
		return; /* nothing to send! */
	}

	if (bits & 0xff000000)
	{
		bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1;
	}

	else if (bits & 0x00ff0000)
	{
		bits |= U_MOREBITS2 | U_MOREBITS1;
	}

	else if (bits & 0x0000ff00)
	{
		bits |= U_MOREBITS1;
	}

	MSG_WriteByte(msg, bits & 255);

	if (bits & 0xff000000)
	{
		MSG_WriteByte(msg, (bits >> 8) & 255);
		MSG_WriteByte(msg, (bits >> 16) & 255);
		MSG_WriteByte(msg, (bits >> 24) & 255);
	}

	else if (bits & 0x00ff0000)
	{
		MSG_WriteByte(msg, (bits >> 8) & 255);
		MSG_WriteByte(msg, (bits >> 16) & 255);
	}

	else if (bits & 0x0000ff00)
	{
		MSG_WriteByte(msg, (bits >> 8) & 255);
	}

	if (bits & U_NUMBER16)
	{
		MSG_WriteShort(msg, to->number);
	}

	else
	{
		MSG_WriteByte(msg, to->number);
	}

	if (IS_QII97_PROTOCOL(protocol))
	{
		if (bits & U_MODEL)
		{
			int modelindex = to->modelindex;

			/* New protocol use 16 bit for model id, and custom player model
			 * id is different to old one, converty back */
			if (modelindex == CUSTOM_PLAYER_MODEL)
			{
				modelindex = QII97_PLAYER_MODEL;
			}
			MSG_WriteByte(msg, modelindex);
		}

		if (bits & U_MODEL2)
		{
			int modelindex = to->modelindex2;

			/* New protocol use 16 bit for model id, and custom player model
			 * id is different to old one, converty back */
			if (modelindex == CUSTOM_PLAYER_MODEL)
			{
				modelindex = QII97_PLAYER_MODEL;
			}
			MSG_WriteByte(msg, modelindex);
		}

		if (bits & U_MODEL3)
		{
			MSG_WriteByte(msg, to->modelindex3);
		}

		if (bits & U_MODEL4)
		{
			MSG_WriteByte(msg, to->modelindex4);
		}
	}
	else
	{
		if (bits & U_MODEL)
		{
			MSG_WriteShort(msg, to->modelindex);
		}

		if (bits & U_MODEL2)
		{
			MSG_WriteShort(msg, to->modelindex2);
		}

		if (bits & U_MODEL3)
		{
			MSG_WriteShort(msg, to->modelindex3);
		}

		if (bits & U_MODEL4)
		{
			MSG_WriteShort(msg, to->modelindex4);
		}
	}

	if (bits & U_FRAME8)
	{
		MSG_WriteByte(msg, to->frame);
	}

	if (bits & U_FRAME16)
	{
		MSG_WriteShort(msg, to->frame);
	}

	if ((bits & U_SKIN8) && (bits & U_SKIN16)) /*used for laser colors */
	{
		MSG_WriteLong(msg, to->skinnum);

		/* Send scale */
		if (protocol == PROTOCOL_VERSION)
		{
			int i;

			for (i = 0; i < 3; i++)
			{
				MSG_WriteFloat(msg, to->scale[i]);
			}
		}
	}

	else if (bits & U_SKIN8)
	{
		MSG_WriteByte(msg, to->skinnum);
	}

	else if (bits & U_SKIN16)
	{
		MSG_WriteShort(msg, to->skinnum);
	}

	if ((bits & (U_EFFECTS8 | U_EFFECTS16)) == (U_EFFECTS8 | U_EFFECTS16))
	{
		MSG_WriteLong(msg, to->effects);
	}

	else if (bits & U_EFFECTS8)
	{
		MSG_WriteByte(msg, to->effects);
	}

	else if (bits & U_EFFECTS16)
	{
		MSG_WriteShort(msg, to->effects);
	}

	/* ReRelease effects */
	if (protocol == PROTOCOL_VERSION)
	{
		if ((bits & (U_EFFECTS8 | U_EFFECTS16)) == (U_EFFECTS8 | U_EFFECTS16))
		{
			MSG_WriteLong(msg, to->rr_effects);
			MSG_WriteLong(msg, to->rr_mesh);
		}

		else if (bits & U_EFFECTS8)
		{
			MSG_WriteByte(msg, to->rr_effects);
			MSG_WriteByte(msg, to->rr_mesh);
		}

		else if (bits & U_EFFECTS16)
		{
			MSG_WriteShort(msg, to->rr_effects);
			MSG_WriteShort(msg, to->rr_mesh);
		}
	}

	if ((bits & (U_RENDERFX8 | U_RENDERFX16)) == (U_RENDERFX8 | U_RENDERFX16))
	{
		MSG_WriteLong(msg, to->renderfx);
	}

	else if (bits & U_RENDERFX8)
	{
		MSG_WriteByte(msg, to->renderfx);
	}

	else if (bits & U_RENDERFX16)
	{
		MSG_WriteShort(msg, to->renderfx);
	}

	if (bits & U_ORIGIN1)
	{
		MSG_WriteCoord(msg, to->origin[0], protocol);
	}

	if (bits & U_ORIGIN2)
	{
		MSG_WriteCoord(msg, to->origin[1], protocol);
	}

	if (bits & U_ORIGIN3)
	{
		MSG_WriteCoord(msg, to->origin[2], protocol);
	}

	if (bits & U_ANGLE1)
	{
		MSG_WriteAngle(msg, to->angles[0]);
	}

	if (bits & U_ANGLE2)
	{
		MSG_WriteAngle(msg, to->angles[1]);
	}

	if (bits & U_ANGLE3)
	{
		MSG_WriteAngle(msg, to->angles[2]);
	}

	if (bits & U_OLDORIGIN)
	{
		MSG_WritePos(msg, to->old_origin, protocol);
	}

	if (bits & U_SOUND)
	{
		MSG_WriteByte(msg, to->sound);
	}

	if (bits & U_EVENT)
	{
		MSG_WriteByte(msg, to->event);
	}

	if (bits & U_SOLID)
	{
		MSG_WriteShort(msg, to->solid);
	}
}

void
MSG_BeginReading(sizebuf_t *msg)
{
	msg->readcount = 0;
}

int
MSG_ReadChar(sizebuf_t *msg_read)
{
	int c;

	if (msg_read->readcount + 1 > msg_read->cursize)
	{
		c = -1;
	}

	else
	{
		c = (signed char)msg_read->data[msg_read->readcount];
	}

	msg_read->readcount++;

	return c;
}

int
MSG_ReadByte(sizebuf_t *msg_read)
{
	int c;

	if (msg_read->readcount + 1 > msg_read->cursize)
	{
		c = -1;
	}

	else
	{
		c = (unsigned char)msg_read->data[msg_read->readcount];
	}

	msg_read->readcount++;

	return c;
}

int
MSG_ReadShort(sizebuf_t *msg_read)
{
	int c;

	if (msg_read->readcount + 2 > msg_read->cursize)
	{
		c = -1;
	}

	else
	{
		c = (short)(msg_read->data[msg_read->readcount]
					+ (msg_read->data[msg_read->readcount + 1] << 8));
	}

	msg_read->readcount += 2;

	return c;
}

int
MSG_ReadLong(sizebuf_t *msg_read)
{
	int c;

	if (msg_read->readcount + 4 > msg_read->cursize)
	{
		c = -1;
	}

	else
	{
		c = msg_read->data[msg_read->readcount]
			+ (msg_read->data[msg_read->readcount + 1] << 8)
			+ (msg_read->data[msg_read->readcount + 2] << 16)
			+ (msg_read->data[msg_read->readcount + 3] << 24);
	}

	msg_read->readcount += 4;

	return c;
}

float
MSG_ReadFloat(sizebuf_t *msg_read)
{
	union
	{
		byte b[4];
		float f;
		int l;
	} dat;

	if (msg_read->readcount + 4 > msg_read->cursize)
	{
		dat.f = -1;
	}

	else
	{
		dat.b[0] = msg_read->data[msg_read->readcount];
		dat.b[1] = msg_read->data[msg_read->readcount + 1];
		dat.b[2] = msg_read->data[msg_read->readcount + 2];
		dat.b[3] = msg_read->data[msg_read->readcount + 3];
	}

	msg_read->readcount += 4;

	dat.l = LittleLong(dat.l);

	return dat.f;
}

char *
MSG_ReadString(sizebuf_t *msg_read)
{
	static char string[2048];
	int l, c;

	l = 0;

	do
	{
		c = MSG_ReadByte(msg_read);

		if ((c == -1) || (c == 0))
		{
			break;
		}

		string[l] = c;
		l++;
	}
	while (l < sizeof(string) - 1);

	string[l] = 0;

	return string;
}

char *
MSG_ReadStringLine(sizebuf_t *msg_read)
{
	static char string[2048];
	int l, c;

	l = 0;

	do
	{
		c = MSG_ReadByte(msg_read);

		if ((c == -1) || (c == 0) || (c == '\n'))
		{
			break;
		}

		string[l] = c;
		l++;
	}
	while (l < sizeof(string) - 1);

	string[l] = 0;

	return string;
}

float
MSG_ReadCoord(sizebuf_t *msg_read, int protocol)
{
	if (IS_QII97_PROTOCOL(protocol))
	{
		return MSG_ReadShort(msg_read) * (0.125f);
	}
	else
	{
		return MSG_ReadFloat(msg_read);
	}
}

void
MSG_ReadPos(sizebuf_t *msg_read, vec3_t pos, int protocol)
{
	pos[0] = MSG_ReadCoord(msg_read, protocol);
	pos[1] = MSG_ReadCoord(msg_read, protocol);
	pos[2] = MSG_ReadCoord(msg_read, protocol);
}

float
MSG_ReadAngle(sizebuf_t *msg_read)
{
	return MSG_ReadChar(msg_read) * 1.40625f;
}

float
MSG_ReadAngle16(sizebuf_t *msg_read)
{
	return SHORT2ANGLE(MSG_ReadShort(msg_read));
}

void
MSG_ReadDeltaUsercmd(sizebuf_t *msg_read, usercmd_t *from, usercmd_t *move)
{
	int bits;

	memcpy(move, from, sizeof(*move));

	bits = MSG_ReadByte(msg_read);

	/* read current angles */
	if (bits & CM_ANGLE1)
	{
		move->angles[0] = MSG_ReadShort(msg_read);
	}

	if (bits & CM_ANGLE2)
	{
		move->angles[1] = MSG_ReadShort(msg_read);
	}

	if (bits & CM_ANGLE3)
	{
		move->angles[2] = MSG_ReadShort(msg_read);
	}

	/* read movement */
	if (bits & CM_FORWARD)
	{
		move->forwardmove = MSG_ReadShort(msg_read);
	}

	if (bits & CM_SIDE)
	{
		move->sidemove = MSG_ReadShort(msg_read);
	}

	if (bits & CM_UP)
	{
		move->upmove = MSG_ReadShort(msg_read);
	}

	/* read buttons */
	if (bits & CM_BUTTONS)
	{
		move->buttons = MSG_ReadByte(msg_read);
	}

	if (bits & CM_IMPULSE)
	{
		move->impulse = MSG_ReadByte(msg_read);
	}

	/* read time to run command */
	move->msec = MSG_ReadByte(msg_read);

	/* read the light level */
	move->lightlevel = MSG_ReadByte(msg_read);
}

void
MSG_ReadData(sizebuf_t *msg_read, void *data, int len)
{
	int i;

	for (i = 0; i < len; i++)
	{
		((byte *)data)[i] = MSG_ReadByte(msg_read);
	}
}

