/*
 * 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.
 *
 * =======================================================================
 *
 * This is the main header file shared between client, renderer, server
 * and the game. Do NOT edit this file unless you know what you're
 * doing. Changes here may break the client <-> renderer <-> server
 * <-> game API, leading to problems with mods!
 *
 * =======================================================================
 */

#ifndef ROGUE_SHARED_H
#define ROGUE_SHARED_H

#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>

typedef int qboolean;
typedef unsigned char byte;

#ifndef NULL
 #define NULL ((void *)0)
#endif

// stuff to align variables/arrays and for noreturn
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L // C11 or newer
	#define YQ2_ALIGNAS_SIZE(SIZE)  _Alignas(SIZE)
	#define YQ2_ALIGNAS_TYPE(TYPE)  _Alignas(TYPE)
	// must be used as prefix (YQ2_ATTR_NORETURN void bla();)!
	#define YQ2_ATTR_NORETURN       _Noreturn
	#define YQ2_STATIC_ASSERT(C, M) _Static_assert((C), M)
  #if defined(__GNUC__)
	#define YQ2_ATTR_MALLOC         __attribute__ ((__malloc__))
	#define YQ2_ATTR_INLINE         __attribute__((always_inline)) inline
	#define YQ2_ATTR_RETURNS_NONNULL __attribute__ ((returns_nonnull))
  #elif defined(_MSC_VER)
	#define YQ2_ATTR_MALLOC         __declspec(restrict)
	#define YQ2_ATTR_INLINE         __forceinline
	#define YQ2_ATTR_RETURNS_NONNULL
  #else
	// no equivalent per see
	#define YQ2_ATTR_MALLOC
	#define YQ2_ATTR_INLINE         inline
	#define YQ2_ATTR_RETURNS_NONNULL
  #endif
#elif defined(__GNUC__) // GCC and clang should support this attribute
	#define YQ2_ALIGNAS_SIZE(SIZE)  __attribute__(( __aligned__(SIZE) ))
	#define YQ2_ALIGNAS_TYPE(TYPE)  __attribute__(( __aligned__(__alignof__(TYPE)) ))
	// must be used as prefix (YQ2_ATTR_NORETURN void bla();)!
	#define YQ2_ATTR_NORETURN       __attribute__ ((noreturn))
	#define YQ2_ATTR_RETURNS_NONNULL __attribute__ ((returns_nonnull))
	#define YQ2_ATTR_MALLOC         __attribute__ ((__malloc__))
	#define YQ2_ATTR_INLINE         __attribute__((always_inline)) inline
	// GCC supports this extension since 4.6
	#define YQ2_STATIC_ASSERT(C, M) _Static_assert((C), M)
#elif defined(_MSC_VER)
	// Note: We prefer VS2019 16.8 or newer in C11 mode (/std:c11),
	//       then the __STDC_VERSION__ >= 201112L case above is used

	#define YQ2_ALIGNAS_SIZE(SIZE)  __declspec(align(SIZE))
	// FIXME: for some reason, the following line doesn't work
	//#define YQ2_ALIGNAS_TYPE( TYPE )  __declspec(align(__alignof(TYPE)))

  #ifdef _WIN64 // (hopefully) good enough workaround
	#define YQ2_ALIGNAS_TYPE(TYPE)  __declspec(align(8))
  #else // 32bit
	#define YQ2_ALIGNAS_TYPE(TYPE)  __declspec(align(4))
  #endif // _WIN64

	// must be used as prefix (YQ2_ATTR_NORETURN void bla();)!
	#define YQ2_ATTR_NORETURN       __declspec(noreturn)
	#define YQ2_ATTR_RETURNS_NONNULL
	#define YQ2_ATTR_MALLOC         __declspec(restrict)
	#define YQ2_ATTR_INLINE         __forceinline
	#define YQ2_STATIC_ASSERT(C, M) assert((C) && M)
#else
	#warning "Please add a case for your compiler here to align correctly"
	#define YQ2_ALIGNAS_SIZE(SIZE)
	#define YQ2_ALIGNAS_TYPE(TYPE)
	#define YQ2_ATTR_NORETURN
	#define YQ2_ATTR_RETURNS_NONNULL
	#define YQ2_ATTR_MALLOC
	#define YQ2_ATTR_INLINE         inline
	#define YQ2_STATIC_ASSERT(C, M) assert((C) && M)
#endif

#if defined(__GNUC__)
	/* ISO C11 _Noreturn can't be attached to function pointers, so
	 * use the gcc/clang-specific version for function pointers, even
	 * in C11 mode. MSVC __declspec(noreturn) seems to have the same
	 * restriction as _Noreturn so can't be used here either. */
	#define YQ2_ATTR_NORETURN_FUNCPTR  __attribute__ ((noreturn))
#else
	#define YQ2_ATTR_NORETURN_FUNCPTR  /* nothing */
#endif

/* Calculate length of a static array
 * Example: for (i = 0; i < ARRLEN(arr); i++)
 */
#define ARRLEN(a) (sizeof(a) / sizeof(*a))

/* Calculate a pointer to the end of a static array
 * Example: for (i = arr; i < ARREND(arr); i++)
 */
#define ARREND(a) &a[ARRLEN(a)]

/* angle indexes */
#define PITCH 0                     /* up / down */
#define YAW 1                       /* left / right */
#define ROLL 2                      /* fall over */

#define Q_min(a, b) (((a) < (b)) ? (a) : (b))
#define Q_max(a, b) (((a) > (b)) ? (a) : (b))
#define Q_clamp(x, l, u) ((l) > (x) ? (l) : (x) > (u) ? (u) : (x))
#define Q_signf(x) ((x) < 0.0f ? -1.0f : 1.0f)

#define MAX_STRING_CHARS 2048       /* max length of a string passed to Cmd_TokenizeString */
#define MAX_STRING_TOKENS 80        /* max tokens resulting from Cmd_TokenizeString */
#define MAX_TOKEN_CHARS 1024        /* max length of an individual token */

#define MAX_QPATH 64                /* max length of a quake game pathname */

/*
 * DG: For some stupid reason, SV_WriteServerFile() and SV_ReadeServerFile() used
 * MAX_OSPATH as buffer length for CVAR_LATCH CVARS and saved the whole buffer
 * into $game/save/current/server.ssv, so changing MAX_OSPATH breaks savegames...
 * Unfortunately, for some other fucking reason MAX_OSPATH was 128 for non-Windows
 * which is just horrible.. so I introduced LATCH_CVAR_SAVELENGTH with the stupid
 * values so I could bump MAX_OSPATH.
 * TODO: whenever you break savegame compatibility next, make
 *       LATCH_CVAR_SAVELENGTH system-independent (or remove it and hardcode a
 *       sensible value in the two functions)
 */

#ifdef _WIN32
 #define MAX_OSPATH 256             /* max length of a filesystem pathname (same as MAX_PATH) */
 #define LATCH_CVAR_SAVELENGTH 256

 // by default dlls don't export any functions, use this to
 // make a function visible (for GetGameAPI(), GetRefAPI() and similar)
 #define Q2_DLL_EXPORTED  __declspec(dllexport)

#else // not Win32 (Linux, BSD, Mac, ..)

 #define MAX_OSPATH 4096            /* max length of a filesystem pathname */
 #define LATCH_CVAR_SAVELENGTH 128

 // by default our .so/.dylibs don't export any functions, use this to
 // make a function visible (for GetGameAPI(), GetRefAPI() and similar)
 #define Q2_DLL_EXPORTED  __attribute__((__visibility__("default")))
#endif

#ifdef _MSC_VER
 #define PRINTF_ATTR(FMT, VARGS)
#else // at least GCC/mingw and clang support this
 #define PRINTF_ATTR(FMT, VARGS) __attribute__((format(printf, FMT , VARGS )))
#endif

/* per-level limits */
#define MAX_CLIENTS 256             /* absolute limit */
#define MAX_EDICTS 1024             /* must change protocol to increase more */
#define MAX_LIGHTSTYLES 256
#define MAX_MODELS 256              /* these are sent over the net as bytes */
#define MAX_SOUNDS 256              /* so they cannot be blindly increased */
#define MAX_IMAGES 256
#define MAX_ITEMS 256
#define MAX_GENERAL (MAX_CLIENTS * 2)       /* general config strings */

/* game print flags */
#define PRINT_LOW 0                 /* pickup messages */
#define PRINT_MEDIUM 1              /* death messages */
#define PRINT_HIGH 2                /* critical messages */
#define PRINT_CHAT 3                /* chat messages */

#define ERR_FATAL 0                 /* exit the entire game with a popup window */
#define ERR_DROP 1                  /* print to console and disconnect from game */
#define ERR_DISCONNECT 2            /* don't kill server */

#define PRINT_ALL 0
#define PRINT_DEVELOPER 1           /* only print when "developer 1" */
#define PRINT_ALERT 2

/* destination class for gi.multicast() */
typedef enum
{
	MULTICAST_ALL,
	MULTICAST_PHS,
	MULTICAST_PVS,
	MULTICAST_ALL_R,
	MULTICAST_PHS_R,
	MULTICAST_PVS_R
} multicast_t;

/*
 * ==============================================================
 *
 * MATHLIB
 *
 * ==============================================================
 */

typedef float vec_t;
typedef vec_t vec3_t[3];
typedef vec_t vec5_t[5];
typedef float quat_t[4]; // x, y, z, w

typedef int fixed4_t;
typedef int fixed8_t;
typedef int fixed16_t;

#ifndef M_PI
 #define M_PI 3.14159265358979323846 /* matches value in gcc v2 math.h */
#endif

struct cplane_s;

extern vec3_t vec3_origin;

#define nanmask (255 << 23)

#define IS_NAN(x) (((*(int *)&x) & nanmask) == nanmask)

// FIXME: use int instead of long, it's only used with int anyway?
#define Q_ftol(f) (long)(f)

#define DotProduct(x, y) (x[0] * y[0] + x[1] * y[1] + x[2] * y[2])
#define VectorSubtract(a, b, c)	\
	(c[0] = a[0] - b[0], c[1] = a[1] - b[1], c[2] =	\
	 a[2] - b[2])
#define VectorAdd(a, b, c) \
	(c[0] = a[0] + b[0], c[1] = a[1] + b[1], c[2] =	\
	 a[2] + b[2])
#define VectorCopy(a, b) (b[0] = a[0], b[1] = a[1], b[2] = a[2])
#define VectorClear(a) (a[0] = a[1] = a[2] = 0)
#define VectorNegate(a, b) (b[0] = -a[0], b[1] = -a[1], b[2] = -a[2])
#define VectorSet(v, x, y, z) (v[0] = (x), v[1] = (y), v[2] = (z))

void VectorMA(const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc);

/* just in case you do't want to use the macros */
vec_t _DotProduct(const vec3_t v1, const vec3_t v2);
void _VectorSubtract(const vec3_t veca, const vec3_t vecb, vec3_t out);
void _VectorAdd(const vec3_t veca, const vec3_t vecb, vec3_t out);
void _VectorCopy(const vec3_t in, vec3_t out);

void ClearBounds(vec3_t mins, vec3_t maxs);
void AddPointToBounds(const vec3_t v, vec3_t mins, vec3_t maxs);
void ClosestPointOnBounds(const vec3_t p, const vec3_t amin, const vec3_t amax, vec3_t out);
qboolean IsZeroVector(vec3_t v);
int VectorCompare(const vec3_t v1, const vec3_t v2);
vec_t VectorLengthSquared(vec3_t v);
vec_t VectorLength(const vec3_t v);
void CrossProduct(const vec3_t v1, const vec3_t v2, vec3_t cross);
vec_t VectorNormalize(vec3_t v); /* returns vector length */
vec_t VectorNormalize2(const vec3_t v, vec3_t out);
void VectorInverse(vec3_t v);
void VectorInverse2(const vec3_t v, vec3_t out);
void VectorScale(const vec3_t in, const vec_t scale, vec3_t out);
void VectorLerp(const vec3_t v1, const vec3_t v2, const vec_t factor, vec3_t out);
void VectorToQuat(const vec3_t v, quat_t out);
void QuatInverse(const quat_t q, quat_t out);
void QuatMultiply(const quat_t q1, const quat_t q2, quat_t out);
void QuatAngleAxis(const vec3_t v, float angle, quat_t out);
void RotateVectorByUnitQuat(vec3_t v, quat_t q_unit);
float Q_magnitude(float x, float y);
int Q_log2(int val);

void R_ConcatRotations(const float in1[3][3], const float in2[3][3], float out[3][3]);
void R_ConcatTransforms(const float in1[3][4], const float in2[3][4], float out[3][4]);

void AngleVectors(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
void AngleVectors2(const vec3_t value1, vec3_t angles);
int BoxOnPlaneSide(const vec3_t emins, const vec3_t emaxs, const struct cplane_s *plane);
float anglemod(float a);
float LerpAngle(float a1, float a2, float frac);

#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \
	(((p)->type < 3) ? \
	 ( \
		 ((p)->dist <= (emins)[(p)->type]) ? \
		 1 \
		 : \
		 ( \
			 ((p)->dist >= (emaxs)[(p)->type]) ? \
			 2 \
			 : \
			 3 \
		 ) \
	 ) \
	 : \
	 BoxOnPlaneSide((emins), (emaxs), (p)))

void ProjectPointOnPlane(vec3_t dst, const vec3_t p, const vec3_t normal);
void PerpendicularVector(vec3_t dst, const vec3_t src);
void RotatePointAroundVector(vec3_t dst,
		const vec3_t dir,
		const vec3_t point,
		float degrees);

/* ============================================= */

const char *COM_SkipPath(const char *pathname);
void COM_StripExtension(const char *in, char *out);
YQ2_ATTR_RETURNS_NONNULL const char *COM_FileExtension(const char *in);
void COM_FileBase(const char *in, char *out);
void COM_FilePath(const char *in, char *out);
void COM_DefaultExtension(char *path, const char *extension);

YQ2_ATTR_RETURNS_NONNULL const char *COM_Parse(char **data_p);

/* data is an in/out parm, returns a parsed out token */
void Com_sprintf(char *dest, int size, const char *fmt, ...);

void Com_PageInMemory(const byte *buffer, int size);

/* ============================================= */

/* portable case insensitive compare */
int Q_stricmp(const char *s1, const char *s2);
int Q_strcasecmp(const char *s1, const char *s2);
int Q_strncasecmp(const char *s1, const char *s2, int n);
char *Q_strcasestr(const char *s1, const char *s2);

/* portable string lowercase */
char *Q_strlwr(char *s);

/* portable safe string copy/concatenate */
int Q_strlcpy(char *dst, const char *src, int size);
int Q_strlcat(char *dst, const char *src, int size);

/* Copies only ASCII chars > 31 && < 127 from s to d, up to n - 1
 * Returns space needed to fully copy s to d (minus null char)
 * Does not modify d at all if n is 0
 * Example: needed = Q_strlcpy_ascii(d, "b\robby", 3)
 *          needed is 5 and d contains "bo\0"
 */
size_t Q_strlcpy_ascii(char *d, const char *s, size_t n);

/* Delete n characters from s starting at index i */
void Q_strdel(char *s, size_t i, size_t n);

/* Insert src into dest starting at index i, total, n is the total size of the buffer */
/* Returns length of src on success, 0 if there is not enough space in dest for src */
size_t Q_strins(char *dest, const char *src, size_t i, size_t n);
qboolean Q_strisnum(const char *s);

/* fix backslashes in path */
void Q_replacebackslash(char *curr);

/* A strchr that can search for multiple characters
 * chrs is a string of characters to search for
 * If found, returns a pointer to that char inside s, NULL otherwise
 */
const char *Q_strchrs(const char *s, const char *chrs);

/* Returns a pointer to c in s if found
 * Otherwise returns a pointer to the null-terminator at the end of s
 */
char *Q_strchr0(const char *s, char c);

/* ============================================= */

/* Unicode wrappers that also make sure it's a regular file around fopen(). */
FILE *Q_fopen(const char *file, const char *mode);

/* Comparator function for qsort(), compares case-insensitive strings. */
int Q_sort_stricmp(const void *s1, const void *s2);

/* Comparator function for qsort(), compares strings. */
int Q_sort_strcomp(const void *s1, const void *s2);

/* ============================================= */

short BigShort(short l);
short LittleShort(short l);
int BigLong(int l);
int LittleLong(int l);
float BigFloat(float l);
float LittleFloat(float l);

void Swap_Init(void);
char *va(const char *format, ...)  PRINTF_ATTR(1, 2);

/* ============================================= */

/* key / value info strings */
#define MAX_INFO_KEY 64
#define MAX_INFO_VALUE 64
#define MAX_INFO_KEYVAL ((MAX_INFO_KEY - 1) + (MAX_INFO_VALUE - 1) + 3) /* 3 for 2 backslashes and null char */
#define MAX_INFO_STRING 512

char *Info_ValueForKey(const char *s, const char *key);
void Info_RemoveKey(char *s, const char *key);
void Info_SetValueForKey(char *s, const char *key, const char *value);
qboolean Info_Validate(const char *s);

/* ============================================= */

/* Random number generator */
int randk(void);
float frandk(void);
float crandk(void);
void randk_seed(void);

/*
 * ==============================================================
 *
 * SYSTEM SPECIFIC
 *
 * ==============================================================
 */

extern int curtime; /* time returned by last Sys_Milliseconds */

int Sys_Milliseconds(void);
void Sys_Mkdir(const char *path);
qboolean Sys_IsDir(const char *path);
qboolean Sys_IsFile(const char *path);

/* large block stack allocation routines */
YQ2_ATTR_MALLOC void *Hunk_Begin(int maxsize);
YQ2_ATTR_MALLOC void *Hunk_Alloc(int size);
void Hunk_Free(void *buf);
int Hunk_End(void);

/* directory searching */
#define SFF_ARCH 0x01
#define SFF_HIDDEN 0x02
#define SFF_RDONLY 0x04
#define SFF_SUBDIR 0x08
#define SFF_SYSTEM 0x10

/* pass in an attribute mask of things you wish to REJECT */
char *Sys_FindFirst(const char *path, unsigned musthave, unsigned canthave);
char *Sys_FindNext(unsigned musthave, unsigned canthave);
void Sys_FindClose(void);

/* this is only here so the functions in shared source files can link */
YQ2_ATTR_NORETURN void Sys_Error(const char *error, ...);
void Com_Printf(const char *msg, ...);

/*
 * ==========================================================
 *
 * CVARS (console variables)
 *
 * ==========================================================
 */

#ifndef CVAR
 #define CVAR

 #define CVAR_ARCHIVE 1     /* set to cause it to be saved to vars.rc */
 #define CVAR_USERINFO 2    /* added to userinfo  when changed */
 #define CVAR_SERVERINFO 4  /* added to serverinfo when changed */
 #define CVAR_NOSET 8       /* don't allow change from console at all, */
							/* but can be set from the command line */
 #define CVAR_LATCH 16      /* save changes until server restart */

/* nothing outside the Cvar_*() functions should modify these fields! */
typedef struct cvar_s
{
	char *name;
	char *string;
	char *latched_string; /* for CVAR_LATCH vars */
	int flags;
	qboolean modified; /* set each time the cvar is changed */
	float value;
	struct cvar_s *next;

	/* Added by YQ2. Must be at the end to preserve ABI. */
	char *default_string;
} cvar_t;

#endif /* CVAR */

/*
 * ==============================================================
 *
 * COLLISION DETECTION
 *
 * ==============================================================
 */

/* lower bits are stronger, and will eat weaker brushes completely */
#define CONTENTS_SOLID 1                /* an eye is never valid in a solid */
#define CONTENTS_WINDOW 2               /* translucent, but not watery */
#define CONTENTS_AUX 4
#define CONTENTS_LAVA 8
#define CONTENTS_SLIME 16
#define CONTENTS_WATER 32
#define CONTENTS_MIST 64
#define LAST_VISIBLE_CONTENTS 64

/* remaining contents are non-visible, and don't eat brushes */
#define CONTENTS_AREAPORTAL 0x8000

#define CONTENTS_PLAYERCLIP 0x10000
#define CONTENTS_MONSTERCLIP 0x20000

/* currents can be added to any other contents, and may be mixed */
#define CONTENTS_CURRENT_0 0x40000
#define CONTENTS_CURRENT_90 0x80000
#define CONTENTS_CURRENT_180 0x100000
#define CONTENTS_CURRENT_270 0x200000
#define CONTENTS_CURRENT_UP 0x400000
#define CONTENTS_CURRENT_DOWN 0x800000

#define CONTENTS_ORIGIN 0x1000000           /* removed before bsping an entity */

#define CONTENTS_MONSTER 0x2000000          /* should never be on a brush, only in game */
#define CONTENTS_DEADMONSTER 0x4000000
#define CONTENTS_DETAIL 0x8000000           /* brushes to be added after vis leafs */
#define CONTENTS_TRANSLUCENT 0x10000000     /* auto set if any surface has trans */
#define CONTENTS_LADDER 0x20000000

#define SURF_LIGHT 0x1          /* value will hold the light strength */

#define SURF_SLICK 0x2          /* effects game physics */

#define SURF_SKY 0x4            /* don't draw, but add to skybox */
#define SURF_WARP 0x8           /* turbulent water warp */
#define SURF_TRANS33 0x10
#define SURF_TRANS66 0x20
#define SURF_FLOWING 0x40       /* scroll towards angle */
#define SURF_NODRAW 0x80        /* don't bother referencing the texture */

/* content masks */
#define MASK_ALL (-1)
#define MASK_SOLID (CONTENTS_SOLID | CONTENTS_WINDOW)
#define MASK_PLAYERSOLID \
	(CONTENTS_SOLID | CONTENTS_PLAYERCLIP |	\
	 CONTENTS_WINDOW | CONTENTS_MONSTER)
#define MASK_DEADSOLID (CONTENTS_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_WINDOW)
#define MASK_MONSTERSOLID \
	(CONTENTS_SOLID | CONTENTS_MONSTERCLIP | \
	 CONTENTS_WINDOW | CONTENTS_MONSTER)
#define MASK_WATER (CONTENTS_WATER | CONTENTS_LAVA | CONTENTS_SLIME)
#define MASK_OPAQUE (CONTENTS_SOLID | CONTENTS_SLIME | CONTENTS_LAVA)
#define MASK_SHOT \
	(CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_WINDOW | \
	 CONTENTS_DEADMONSTER)
#define MASK_CURRENT \
	(CONTENTS_CURRENT_0 | CONTENTS_CURRENT_90 |	\
	 CONTENTS_CURRENT_180 | CONTENTS_CURRENT_270 | \
	 CONTENTS_CURRENT_UP | \
	 CONTENTS_CURRENT_DOWN)

/* gi.BoxEdicts() can return a list of either solid or trigger entities */
#define AREA_SOLID 1
#define AREA_TRIGGERS 2

/* plane_t structure */
typedef struct cplane_s
{
	vec3_t normal;
	float dist;
	byte type; /* for fast side tests */
	byte signbits; /* signx + (signy<<1) + (signz<<2) */
	byte pad[2];
} cplane_t;

/* structure offset for asm code */
#define CPLANE_NORMAL_X 0
#define CPLANE_NORMAL_Y 4
#define CPLANE_NORMAL_Z 8
#define CPLANE_DIST 12
#define CPLANE_TYPE 16
#define CPLANE_SIGNBITS 17
#define CPLANE_PAD0 18
#define CPLANE_PAD1 19

typedef struct cmodel_s
{
	vec3_t mins, maxs;
	vec3_t origin; /* for sounds or lights */
	int headnode;
} cmodel_t;

typedef struct csurface_s
{
	char name[16];
	int flags; /* SURF_* */
	int value; /* unused */
} csurface_t;

typedef struct mapsurface_s  /* used internally due to name len probs */
{
	csurface_t c;
	char rname[32];
} mapsurface_t;

/* a trace is returned when a box is swept through the world */
typedef struct
{
	qboolean allsolid;      /* if true, plane is not valid */
	qboolean startsolid;    /* if true, the initial point was in a solid area */
	float fraction;         /* time completed, 1.0 = didn't hit anything */
	vec3_t endpos;          /* final position */
	cplane_t plane;         /* surface normal at impact */
	csurface_t *surface;    /* surface hit */
	int contents;           /* contents on other side of surface hit */
	struct edict_s *ent;    /* not set by CM_*() functions */
} trace_t;

/* pmove_state_t is the information necessary for client side movement */
/* prediction */
typedef enum
{
	/* can accelerate and turn */
	PM_NORMAL,
	PM_SPECTATOR,
	/* no acceleration or turning */
	PM_DEAD,
	PM_GIB, /* different bounding box */
	PM_FREEZE
} pmtype_t;

/* pmove->pm_flags */
#define PMF_DUCKED 1
#define PMF_JUMP_HELD 2
#define PMF_ON_GROUND 4
#define PMF_TIME_WATERJUMP 8    /* pm_time is waterjump */
#define PMF_TIME_LAND 16        /* pm_time is time before rejump */
#define PMF_TIME_TELEPORT 32    /* pm_time is non-moving time */
#define PMF_NO_PREDICTION 64    /* temporarily disables prediction (used for grappling hook) */

/* this structure needs to be communicated bit-accurate/
 * from the server to the client to guarantee that
 * prediction stays in sync, so no floats are used.
 * if any part of the game code modifies this struct, it
 * will result in a prediction error of some degree. */
typedef struct
{
	pmtype_t pm_type;

	short origin[3];            /* 12.3 */
	short velocity[3];          /* 12.3 */
	byte pm_flags;              /* ducked, jump_held, etc */
	byte pm_time;               /* each unit = 8 ms */
	short gravity;
	short delta_angles[3];      /* add to command angles to get view direction
								 * changed by spawns, rotating objects, and teleporters */
} pmove_state_t;

/* button bits */
#define BUTTON_ATTACK 1
#define BUTTON_USE 2
#define BUTTON_ANY 128 /* any key whatsoever */

/* usercmd_t is sent to the server each client frame */
typedef struct usercmd_s
{
	byte msec;
	byte buttons;
	short angles[3];
	short forwardmove, sidemove, upmove;
	byte impulse;           /* remove? */
	byte lightlevel;        /* light level the player is standing on */
} usercmd_t;

#define MAXTOUCH 32
typedef struct
{
	/* state (in / out) */
	pmove_state_t s;

	/* command (in) */
	usercmd_t cmd;
	qboolean snapinitial;           /* if s has been changed outside pmove */

	/* results (out) */
	int numtouch;
	struct edict_s *touchents[MAXTOUCH];

	vec3_t viewangles;              /* clamped */
	float viewheight;

	vec3_t mins, maxs;              /* bounding box size */

	struct edict_s *groundentity;
	int watertype;
	int waterlevel;

	/* callbacks to test the world */
	trace_t (*trace)(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
	int (*pointcontents)(vec3_t point);
} pmove_t;

/* entity_state_t->effects
 * Effects are things handled on the client side (lights, particles,
 * frame animations)  that happen constantly on the given entity.
 * An entity that has effects will be sent to the client even if
 * it has a zero index model. */
#define EF_ROTATE 0x00000001                /* rotate (bonus items) */
#define EF_GIB 0x00000002                   /* leave a trail */
#define EF_BLASTER 0x00000008               /* redlight + trail */
#define EF_ROCKET 0x00000010                /* redlight + trail */
#define EF_GRENADE 0x00000020
#define EF_HYPERBLASTER 0x00000040
#define EF_BFG 0x00000080
#define EF_COLOR_SHELL 0x00000100
#define EF_POWERSCREEN 0x00000200
#define EF_ANIM01 0x00000400                /* automatically cycle between frames 0 and 1 at 2 hz */
#define EF_ANIM23 0x00000800                /* automatically cycle between frames 2 and 3 at 2 hz */
#define EF_ANIM_ALL 0x00001000              /* automatically cycle through all frames at 2hz */
#define EF_ANIM_ALLFAST 0x00002000          /* automatically cycle through all frames at 10hz */
#define EF_FLIES 0x00004000
#define EF_QUAD 0x00008000
#define EF_PENT 0x00010000
#define EF_TELEPORTER 0x00020000            /* particle fountain */
#define EF_FLAG1 0x00040000
#define EF_FLAG2 0x00080000
#define EF_IONRIPPER 0x00100000
#define EF_GREENGIB 0x00200000
#define EF_BLUEHYPERBLASTER 0x00400000
#define EF_SPINNINGLIGHTS 0x00800000
#define EF_PLASMA 0x01000000
#define EF_TRAP 0x02000000
#define EF_TRACKER 0x04000000
#define EF_DOUBLE 0x08000000
#define EF_SPHERETRANS 0x10000000
#define EF_TAGTRAIL 0x20000000
#define EF_HALF_DAMAGE 0x40000000
#define EF_TRACKERTRAIL 0x80000000

/* entity_state_t->renderfx flags */
#define RF_MINLIGHT 1               /* allways have some light (viewmodel) */
#define RF_VIEWERMODEL 2            /* don't draw through eyes, only mirrors */
#define RF_WEAPONMODEL 4            /* only draw through eyes */
#define RF_FULLBRIGHT 8             /* allways draw full intensity */
#define RF_DEPTHHACK 16             /* for view weapon Z crunching */
#define RF_TRANSLUCENT 32
#define RF_FRAMELERP 64
#define RF_BEAM 128
#define RF_CUSTOMSKIN 256           /* skin is an index in image_precache */
#define RF_GLOW 512                 /* pulse lighting for bonus items */
#define RF_SHELL_RED 1024
#define RF_SHELL_GREEN 2048
#define RF_SHELL_BLUE 4096
#define RF_NOSHADOW 8192        /* don't draw a shadow */
#define RF_IR_VISIBLE 0x00008000            /* 32768 */
#define RF_SHELL_DOUBLE 0x00010000          /* 65536 */
#define RF_SHELL_HALF_DAM 0x00020000
#define RF_USE_DISGUISE 0x00040000

/* player_state_t->refdef flags */
#define RDF_UNDERWATER 1            /* warp the screen as apropriate */
#define RDF_NOWORLDMODEL 2          /* used for player configuration screen */
#define RDF_IRGOGGLES 4
#define RDF_UVGOGGLES 8

/* muzzle flashes / player effects */
#define MZ_BLASTER 0
#define MZ_MACHINEGUN 1
#define MZ_SHOTGUN 2
#define MZ_CHAINGUN1 3
#define MZ_CHAINGUN2 4
#define MZ_CHAINGUN3 5
#define MZ_RAILGUN 6
#define MZ_ROCKET 7
#define MZ_GRENADE 8
#define MZ_LOGIN 9
#define MZ_LOGOUT 10
#define MZ_RESPAWN 11
#define MZ_BFG 12
#define MZ_SSHOTGUN 13
#define MZ_HYPERBLASTER 14
#define MZ_ITEMRESPAWN 15
#define MZ_IONRIPPER 16
#define MZ_BLUEHYPERBLASTER 17
#define MZ_PHALANX 18
#define MZ_SILENCED 128             /* bit flag ORed with one of the above numbers */
#define MZ_ETF_RIFLE 30
#define MZ_UNUSED 31
#define MZ_SHOTGUN2 32
#define MZ_HEATBEAM 33
#define MZ_BLASTER2 34
#define MZ_TRACKER 35
#define MZ_NUKE1 36
#define MZ_NUKE2 37
#define MZ_NUKE4 38
#define MZ_NUKE8 39

/* monster muzzle flashes */
#define MZ2_TANK_BLASTER_1 1
#define MZ2_TANK_BLASTER_2 2
#define MZ2_TANK_BLASTER_3 3
#define MZ2_TANK_MACHINEGUN_1 4
#define MZ2_TANK_MACHINEGUN_2 5
#define MZ2_TANK_MACHINEGUN_3 6
#define MZ2_TANK_MACHINEGUN_4 7
#define MZ2_TANK_MACHINEGUN_5 8
#define MZ2_TANK_MACHINEGUN_6 9
#define MZ2_TANK_MACHINEGUN_7 10
#define MZ2_TANK_MACHINEGUN_8 11
#define MZ2_TANK_MACHINEGUN_9 12
#define MZ2_TANK_MACHINEGUN_10 13
#define MZ2_TANK_MACHINEGUN_11 14
#define MZ2_TANK_MACHINEGUN_12 15
#define MZ2_TANK_MACHINEGUN_13 16
#define MZ2_TANK_MACHINEGUN_14 17
#define MZ2_TANK_MACHINEGUN_15 18
#define MZ2_TANK_MACHINEGUN_16 19
#define MZ2_TANK_MACHINEGUN_17 20
#define MZ2_TANK_MACHINEGUN_18 21
#define MZ2_TANK_MACHINEGUN_19 22
#define MZ2_TANK_ROCKET_1 23
#define MZ2_TANK_ROCKET_2 24
#define MZ2_TANK_ROCKET_3 25

#define MZ2_INFANTRY_MACHINEGUN_1 26
#define MZ2_INFANTRY_MACHINEGUN_2 27
#define MZ2_INFANTRY_MACHINEGUN_3 28
#define MZ2_INFANTRY_MACHINEGUN_4 29
#define MZ2_INFANTRY_MACHINEGUN_5 30
#define MZ2_INFANTRY_MACHINEGUN_6 31
#define MZ2_INFANTRY_MACHINEGUN_7 32
#define MZ2_INFANTRY_MACHINEGUN_8 33
#define MZ2_INFANTRY_MACHINEGUN_9 34
#define MZ2_INFANTRY_MACHINEGUN_10 35
#define MZ2_INFANTRY_MACHINEGUN_11 36
#define MZ2_INFANTRY_MACHINEGUN_12 37
#define MZ2_INFANTRY_MACHINEGUN_13 38

#define MZ2_SOLDIER_BLASTER_1 39
#define MZ2_SOLDIER_BLASTER_2 40
#define MZ2_SOLDIER_SHOTGUN_1 41
#define MZ2_SOLDIER_SHOTGUN_2 42
#define MZ2_SOLDIER_MACHINEGUN_1 43
#define MZ2_SOLDIER_MACHINEGUN_2 44

#define MZ2_GUNNER_MACHINEGUN_1 45
#define MZ2_GUNNER_MACHINEGUN_2 46
#define MZ2_GUNNER_MACHINEGUN_3 47
#define MZ2_GUNNER_MACHINEGUN_4 48
#define MZ2_GUNNER_MACHINEGUN_5 49
#define MZ2_GUNNER_MACHINEGUN_6 50
#define MZ2_GUNNER_MACHINEGUN_7 51
#define MZ2_GUNNER_MACHINEGUN_8 52
#define MZ2_GUNNER_GRENADE_1 53
#define MZ2_GUNNER_GRENADE_2 54
#define MZ2_GUNNER_GRENADE_3 55
#define MZ2_GUNNER_GRENADE_4 56

#define MZ2_CHICK_ROCKET_1 57

#define MZ2_FLYER_BLASTER_1 58
#define MZ2_FLYER_BLASTER_2 59

#define MZ2_MEDIC_BLASTER_1 60

#define MZ2_GLADIATOR_RAILGUN_1 61

#define MZ2_HOVER_BLASTER_1 62

#define MZ2_ACTOR_MACHINEGUN_1 63

#define MZ2_SUPERTANK_MACHINEGUN_1 64
#define MZ2_SUPERTANK_MACHINEGUN_2 65
#define MZ2_SUPERTANK_MACHINEGUN_3 66
#define MZ2_SUPERTANK_MACHINEGUN_4 67
#define MZ2_SUPERTANK_MACHINEGUN_5 68
#define MZ2_SUPERTANK_MACHINEGUN_6 69
#define MZ2_SUPERTANK_ROCKET_1 70
#define MZ2_SUPERTANK_ROCKET_2 71
#define MZ2_SUPERTANK_ROCKET_3 72

#define MZ2_BOSS2_MACHINEGUN_L1 73
#define MZ2_BOSS2_MACHINEGUN_L2 74
#define MZ2_BOSS2_MACHINEGUN_L3 75
#define MZ2_BOSS2_MACHINEGUN_L4 76
#define MZ2_BOSS2_MACHINEGUN_L5 77
#define MZ2_BOSS2_ROCKET_1 78
#define MZ2_BOSS2_ROCKET_2 79
#define MZ2_BOSS2_ROCKET_3 80
#define MZ2_BOSS2_ROCKET_4 81

#define MZ2_FLOAT_BLASTER_1 82

#define MZ2_SOLDIER_BLASTER_3 83
#define MZ2_SOLDIER_SHOTGUN_3 84
#define MZ2_SOLDIER_MACHINEGUN_3 85
#define MZ2_SOLDIER_BLASTER_4 86
#define MZ2_SOLDIER_SHOTGUN_4 87
#define MZ2_SOLDIER_MACHINEGUN_4 88
#define MZ2_SOLDIER_BLASTER_5 89
#define MZ2_SOLDIER_SHOTGUN_5 90
#define MZ2_SOLDIER_MACHINEGUN_5 91
#define MZ2_SOLDIER_BLASTER_6 92
#define MZ2_SOLDIER_SHOTGUN_6 93
#define MZ2_SOLDIER_MACHINEGUN_6 94
#define MZ2_SOLDIER_BLASTER_7 95
#define MZ2_SOLDIER_SHOTGUN_7 96
#define MZ2_SOLDIER_MACHINEGUN_7 97
#define MZ2_SOLDIER_BLASTER_8 98
#define MZ2_SOLDIER_SHOTGUN_8 99
#define MZ2_SOLDIER_MACHINEGUN_8 100

#define MZ2_MAKRON_BFG 101
#define MZ2_MAKRON_BLASTER_1 102
#define MZ2_MAKRON_BLASTER_2 103
#define MZ2_MAKRON_BLASTER_3 104
#define MZ2_MAKRON_BLASTER_4 105
#define MZ2_MAKRON_BLASTER_5 106
#define MZ2_MAKRON_BLASTER_6 107
#define MZ2_MAKRON_BLASTER_7 108
#define MZ2_MAKRON_BLASTER_8 109
#define MZ2_MAKRON_BLASTER_9 110
#define MZ2_MAKRON_BLASTER_10 111
#define MZ2_MAKRON_BLASTER_11 112
#define MZ2_MAKRON_BLASTER_12 113
#define MZ2_MAKRON_BLASTER_13 114
#define MZ2_MAKRON_BLASTER_14 115
#define MZ2_MAKRON_BLASTER_15 116
#define MZ2_MAKRON_BLASTER_16 117
#define MZ2_MAKRON_BLASTER_17 118
#define MZ2_MAKRON_RAILGUN_1 119
#define MZ2_JORG_MACHINEGUN_L1 120
#define MZ2_JORG_MACHINEGUN_L2 121
#define MZ2_JORG_MACHINEGUN_L3 122
#define MZ2_JORG_MACHINEGUN_L4 123
#define MZ2_JORG_MACHINEGUN_L5 124
#define MZ2_JORG_MACHINEGUN_L6 125
#define MZ2_JORG_MACHINEGUN_R1 126
#define MZ2_JORG_MACHINEGUN_R2 127
#define MZ2_JORG_MACHINEGUN_R3 128
#define MZ2_JORG_MACHINEGUN_R4 129
#define MZ2_JORG_MACHINEGUN_R5 130
#define MZ2_JORG_MACHINEGUN_R6 131
#define MZ2_JORG_BFG_1 132
#define MZ2_BOSS2_MACHINEGUN_R1 133
#define MZ2_BOSS2_MACHINEGUN_R2 134
#define MZ2_BOSS2_MACHINEGUN_R3 135
#define MZ2_BOSS2_MACHINEGUN_R4 136
#define MZ2_BOSS2_MACHINEGUN_R5 137

#define MZ2_CARRIER_MACHINEGUN_L1 138
#define MZ2_CARRIER_MACHINEGUN_R1 139
#define MZ2_CARRIER_GRENADE 140
#define MZ2_TURRET_MACHINEGUN 141
#define MZ2_TURRET_ROCKET 142
#define MZ2_TURRET_BLASTER 143
#define MZ2_STALKER_BLASTER 144
#define MZ2_DAEDALUS_BLASTER 145
#define MZ2_MEDIC_BLASTER_2 146
#define MZ2_CARRIER_RAILGUN 147
#define MZ2_WIDOW_DISRUPTOR 148
#define MZ2_WIDOW_BLASTER 149
#define MZ2_WIDOW_RAIL 150
#define MZ2_WIDOW_PLASMABEAM 151
#define MZ2_CARRIER_MACHINEGUN_L2 152
#define MZ2_CARRIER_MACHINEGUN_R2 153
#define MZ2_WIDOW_RAIL_LEFT 154
#define MZ2_WIDOW_RAIL_RIGHT 155
#define MZ2_WIDOW_BLASTER_SWEEP1 156
#define MZ2_WIDOW_BLASTER_SWEEP2 157
#define MZ2_WIDOW_BLASTER_SWEEP3 158
#define MZ2_WIDOW_BLASTER_SWEEP4 159
#define MZ2_WIDOW_BLASTER_SWEEP5 160
#define MZ2_WIDOW_BLASTER_SWEEP6 161
#define MZ2_WIDOW_BLASTER_SWEEP7 162
#define MZ2_WIDOW_BLASTER_SWEEP8 163
#define MZ2_WIDOW_BLASTER_SWEEP9 164
#define MZ2_WIDOW_BLASTER_100 165
#define MZ2_WIDOW_BLASTER_90 166
#define MZ2_WIDOW_BLASTER_80 167
#define MZ2_WIDOW_BLASTER_70 168
#define MZ2_WIDOW_BLASTER_60 169
#define MZ2_WIDOW_BLASTER_50 170
#define MZ2_WIDOW_BLASTER_40 171
#define MZ2_WIDOW_BLASTER_30 172
#define MZ2_WIDOW_BLASTER_20 173
#define MZ2_WIDOW_BLASTER_10 174
#define MZ2_WIDOW_BLASTER_0 175
#define MZ2_WIDOW_BLASTER_10L 176
#define MZ2_WIDOW_BLASTER_20L 177
#define MZ2_WIDOW_BLASTER_30L 178
#define MZ2_WIDOW_BLASTER_40L 179
#define MZ2_WIDOW_BLASTER_50L 180
#define MZ2_WIDOW_BLASTER_60L 181
#define MZ2_WIDOW_BLASTER_70L 182
#define MZ2_WIDOW_RUN_1 183
#define MZ2_WIDOW_RUN_2 184
#define MZ2_WIDOW_RUN_3 185
#define MZ2_WIDOW_RUN_4 186
#define MZ2_WIDOW_RUN_5 187
#define MZ2_WIDOW_RUN_6 188
#define MZ2_WIDOW_RUN_7 189
#define MZ2_WIDOW_RUN_8 190
#define MZ2_CARRIER_ROCKET_1 191
#define MZ2_CARRIER_ROCKET_2 192
#define MZ2_CARRIER_ROCKET_3 193
#define MZ2_CARRIER_ROCKET_4 194
#define MZ2_WIDOW2_BEAMER_1 195
#define MZ2_WIDOW2_BEAMER_2 196
#define MZ2_WIDOW2_BEAMER_3 197
#define MZ2_WIDOW2_BEAMER_4 198
#define MZ2_WIDOW2_BEAMER_5 199
#define MZ2_WIDOW2_BEAM_SWEEP_1 200
#define MZ2_WIDOW2_BEAM_SWEEP_2 201
#define MZ2_WIDOW2_BEAM_SWEEP_3 202
#define MZ2_WIDOW2_BEAM_SWEEP_4 203
#define MZ2_WIDOW2_BEAM_SWEEP_5 204
#define MZ2_WIDOW2_BEAM_SWEEP_6 205
#define MZ2_WIDOW2_BEAM_SWEEP_7 206
#define MZ2_WIDOW2_BEAM_SWEEP_8 207
#define MZ2_WIDOW2_BEAM_SWEEP_9 208
#define MZ2_WIDOW2_BEAM_SWEEP_10 209
#define MZ2_WIDOW2_BEAM_SWEEP_11 210

extern vec3_t monster_flash_offset[];

/* Temp entity events are for things that happen
 * at a location seperate from any existing entity.
 * Temporary entity messages are explicitly constructed
 * and broadcast. */
typedef enum
{
	TE_GUNSHOT,
	TE_BLOOD,
	TE_BLASTER,
	TE_RAILTRAIL,
	TE_SHOTGUN,
	TE_EXPLOSION1,
	TE_EXPLOSION2,
	TE_ROCKET_EXPLOSION,
	TE_GRENADE_EXPLOSION,
	TE_SPARKS,
	TE_SPLASH,
	TE_BUBBLETRAIL,
	TE_SCREEN_SPARKS,
	TE_SHIELD_SPARKS,
	TE_BULLET_SPARKS,
	TE_LASER_SPARKS,
	TE_PARASITE_ATTACK,
	TE_ROCKET_EXPLOSION_WATER,
	TE_GRENADE_EXPLOSION_WATER,
	TE_MEDIC_CABLE_ATTACK,
	TE_BFG_EXPLOSION,
	TE_BFG_BIGEXPLOSION,
	TE_BOSSTPORT,           /* used as '22' in a map, so DON'T RENUMBER!!! */
	TE_BFG_LASER,
	TE_GRAPPLE_CABLE,
	TE_WELDING_SPARKS,
	TE_GREENBLOOD,
	TE_BLUEHYPERBLASTER,
	TE_PLASMA_EXPLOSION,
	TE_TUNNEL_SPARKS,
	TE_BLASTER2,
	TE_RAILTRAIL2,
	TE_FLAME,
	TE_LIGHTNING,
	TE_DEBUGTRAIL,
	TE_PLAIN_EXPLOSION,
	TE_FLASHLIGHT,
	TE_FORCEWALL,
	TE_HEATBEAM,
	TE_MONSTER_HEATBEAM,
	TE_STEAM,
	TE_BUBBLETRAIL2,
	TE_MOREBLOOD,
	TE_HEATBEAM_SPARKS,
	TE_HEATBEAM_STEAM,
	TE_CHAINFIST_SMOKE,
	TE_ELECTRIC_SPARKS,
	TE_TRACKER_EXPLOSION,
	TE_TELEPORT_EFFECT,
	TE_DBALL_GOAL,
	TE_WIDOWBEAMOUT,
	TE_NUKEBLAST,
	TE_WIDOWSPLASH,
	TE_EXPLOSION1_BIG,
	TE_EXPLOSION1_NP,
	TE_FLECHETTE
} temp_event_t;

#define SPLASH_UNKNOWN 0
#define SPLASH_SPARKS 1
#define SPLASH_BLUE_WATER 2
#define SPLASH_BROWN_WATER 3
#define SPLASH_SLIME 4
#define SPLASH_LAVA 5
#define SPLASH_BLOOD 6

/* sound channels:
 * channel 0 never willingly overrides
 * other channels (1-7) allways override
 * a playing sound on that channel */
#define CHAN_AUTO 0
#define CHAN_WEAPON 1
#define CHAN_VOICE 2
#define CHAN_ITEM 3
#define CHAN_BODY 4
/* modifier flags */
#define CHAN_NO_PHS_ADD 8           /* send to all clients, not just ones in PHS (ATTN 0 will also do this) */
#define CHAN_RELIABLE 16            /* send by reliable message, not datagram */

/* sound attenuation values */
#define ATTN_NONE 0                 /* full volume the entire level */
#define ATTN_NORM 1
#define ATTN_IDLE 2
#define ATTN_STATIC 3               /* diminish very rapidly with distance */

/* player_state->stats[] indexes */
#define STAT_HEALTH_ICON 0
#define STAT_HEALTH 1
#define STAT_AMMO_ICON 2
#define STAT_AMMO 3
#define STAT_ARMOR_ICON 4
#define STAT_ARMOR 5
#define STAT_SELECTED_ICON 6
#define STAT_PICKUP_ICON 7
#define STAT_PICKUP_STRING 8
#define STAT_TIMER_ICON 9
#define STAT_TIMER 10
#define STAT_HELPICON 11
#define STAT_SELECTED_ITEM 12
#define STAT_LAYOUTS 13
#define STAT_FRAGS 14
#define STAT_FLASHES 15                 /* cleared each frame, 1 = health, 2 = armor */
#define STAT_CHASE 16
#define STAT_SPECTATOR 17

#define MAX_STATS 32

/* dmflags->value flags */
#define DF_NO_HEALTH 0x00000001         /* 1 */
#define DF_NO_ITEMS 0x00000002          /* 2 */
#define DF_WEAPONS_STAY 0x00000004      /* 4 */
#define DF_NO_FALLING 0x00000008        /* 8 */
#define DF_INSTANT_ITEMS 0x00000010     /* 16 */
#define DF_SAME_LEVEL 0x00000020        /* 32 */
#define DF_SKINTEAMS 0x00000040         /* 64 */
#define DF_MODELTEAMS 0x00000080        /* 128 */
#define DF_NO_FRIENDLY_FIRE 0x00000100  /* 256 */
#define DF_SPAWN_FARTHEST 0x00000200    /* 512 */
#define DF_FORCE_RESPAWN 0x00000400     /* 1024 */
#define DF_NO_ARMOR 0x00000800          /* 2048 */
#define DF_ALLOW_EXIT 0x00001000        /* 4096 */
#define DF_INFINITE_AMMO 0x00002000     /* 8192 */
#define DF_QUAD_DROP 0x00004000         /* 16384 */
#define DF_FIXED_FOV 0x00008000         /* 32768 */
#define DF_QUADFIRE_DROP 0x00010000     /* 65536 */
#define DF_NO_MINES 0x00020000
#define DF_NO_STACK_DOUBLE 0x00040000
#define DF_NO_NUKES 0x00080000
#define DF_NO_SPHERES 0x00100000

#define ROGUE_VERSION_STRING "08/21/1998 Beta 2 for Ensemble"

/*
 * ==========================================================
 *
 * ELEMENTS COMMUNICATED ACROSS THE NET
 *
 * ==========================================================
 */

#define ANGLE2SHORT(x) ((int)((x) * 65536 / 360) & 65535)
#define SHORT2ANGLE(x) ((x) * (360.0 / 65536))

/* config strings are a general means of communication from
 * the server to all connected clients. Each config string
 * can be at most MAX_QPATH characters. */
#define CS_NAME 0
#define CS_CDTRACK 1
#define CS_SKY 2
#define CS_SKYAXIS 3                /* %f %f %f format */
#define CS_SKYROTATE 4
#define CS_STATUSBAR 5              /* display program string */
#define CS_STATUSBAR_END 29
#define CS_STATUSBAR_SPACE(i) ((CS_STATUSBAR_END - (i)) * MAX_QPATH)

#define CS_AIRACCEL 29              /* air acceleration control */
#define CS_MAXCLIENTS 30
#define CS_MAPCHECKSUM 31           /* for catching cheater maps */

#define CS_MODELS 32
#define CS_SOUNDS (CS_MODELS + MAX_MODELS)
#define CS_IMAGES (CS_SOUNDS + MAX_SOUNDS)
#define CS_LIGHTS (CS_IMAGES + MAX_IMAGES)
#define CS_ITEMS (CS_LIGHTS + MAX_LIGHTSTYLES)
#define CS_PLAYERSKINS (CS_ITEMS + MAX_ITEMS)
#define CS_GENERAL (CS_PLAYERSKINS + MAX_CLIENTS)
#define MAX_CONFIGSTRINGS (CS_GENERAL + MAX_GENERAL)

/* ============================================== */

/* entity_state_t->event values
 * entity events are for effects that take place reletive
 * to an existing entities origin.  Very network efficient.
 * All muzzle flashes really should be converted to events... */
typedef enum
{
	EV_NONE,
	EV_ITEM_RESPAWN,
	EV_FOOTSTEP,
	EV_FALLSHORT,
	EV_FALL,
	EV_FALLFAR,
	EV_PLAYER_TELEPORT,
	EV_OTHER_TELEPORT
} entity_event_t;

/* entity_state_t is the information conveyed from the server
 * in an update message about entities that the client will
 * need to render in some way */
typedef struct entity_state_s
{
	int number;             /* edict index */

	vec3_t origin;
	vec3_t angles;
	vec3_t old_origin;      /* for lerping */
	int modelindex;
	int modelindex2, modelindex3, modelindex4;      /* weapons, CTF flags, etc */
	int frame;
	int skinnum;
	unsigned int effects;
	int renderfx;
	int solid;              /* for client side prediction, 8*(bits 0-4) is x/y radius */
							/* 8*(bits 5-9) is z down distance, 8(bits10-15) is z up */
							/* gi.linkentity sets this properly */
	int sound;              /* for looping sounds, to guarantee shutoff */
	int event;              /* impulse events -- muzzle flashes, footsteps, etc */
							/* events only go out for a single frame, they */
							/* are automatically cleared each frame */
} entity_state_t;

/* ============================================== */

/* player_state_t is the information needed in addition to pmove_state_t
 * to rendered a view.  There will only be 10 player_state_t sent each second,
 * but the number of pmove_state_t changes will be reletive to client
 * frame rates */
typedef struct
{
	pmove_state_t pmove;        /* for prediction */

	vec3_t viewangles;          /* for fixed views */
	vec3_t viewoffset;          /* add to pmovestate->origin */
	vec3_t kick_angles;         /* add to view direction to get render angles */
								/* set by weapon kicks, pain effects, etc */

	vec3_t gunangles;
	vec3_t gunoffset;
	int gunindex;
	int gunframe;

	float blend[4];             /* rgba full screen effect */
	float fov;                  /* horizontal field of view */
	int rdflags;                /* refdef flags */

	short stats[MAX_STATS];     /* fast status bar updates */
} player_state_t;

size_t verify_fread(void *, size_t, size_t, FILE *);
size_t verify_fwrite(void *, size_t, size_t, FILE *);

/* Returns the next power of 2 value greater-than-or-equal to i
 * Examples:
 *   NextPow2(733) == 1024
 *   NextPow2(2048) == 2048
 * Returns 1 if i == 0 and 0 if i == (1 << 31)
 */
unsigned int NextPow2(unsigned int i);

/* Returns the next power of 2 value greater than i
 * Examples:
 *   NextPow2gt(733) == 1024
 *   NextPow2gt(2048) == 4096
 * Returns 1 if i == 0 and 0 if i == (1 << 31)
 */
unsigned int NextPow2gt(unsigned int i);

/* Bitlist
 * API for using arrays of bits with maximum space efficiency
*/

/* number of bits per array index */
typedef char bitlist_t;
#define BITLIST_BPU (sizeof(bitlist_t) * 8)

/* calculate length of array given number of bits n
 * Example: bitlist_t mybits[BITLIST_SIZE(512)];
*/
#define BITLIST_SIZE(n) (1 + (((n) - 1) / BITLIST_BPU))

/* Set bit i to 1 or clear it to 0 */
#define BITLIST_SET(l, i) l[(i) / BITLIST_BPU] |= 1 << ((i) % BITLIST_BPU)
#define BITLIST_CLEAR(l, i) l[(i) / BITLIST_BPU] &= ~(1 << ((i) % BITLIST_BPU))

/* test the value of bit i */
#define BITLIST_ISSET(l, i) (l[(i) / BITLIST_BPU] & (1 << ((i) % BITLIST_BPU))) != 0

#endif /* ROGUE_SHARED_H */
