1
0
Fork 0
forked from fte/fteqw

Initial checkin

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2004-08-21 01:25:48 +00:00
parent c6b579a554
commit a67a6355d2
30 changed files with 25087 additions and 0 deletions

98
engine/common/asm_i386.h Normal file
View file

@ -0,0 +1,98 @@
/*
Copyright (C) 1996-1997 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.
*/
#ifndef __ASM_I386__
#define __ASM_I386__
#if defined(CYGORELF) || defined(ELF)
#define C(label) label
#else
#define C(label) _##label
#endif
//
// !!! note that this file must match the corresponding C structures at all
// times !!!
//
// plane_t structure
// !!! if this is changed, it must be changed in model.h too !!!
// !!! if the size of this is changed, the array lookup in SV_HullPointContents
// must be changed too !!!
#define pl_normal 0
#define pl_dist 12
#define pl_type 16
#define pl_signbits 17
#define pl_pad 18
#define pl_size 20
// hull_t structure
// !!! if this is changed, it must be changed in model.h too !!!
#define hu_clipnodes 0
#define hu_planes 4
#define hu_firstclipnode 8
#define hu_lastclipnode 12
#define hu_clip_mins 16
#define hu_clip_maxs 28
#define hu_available 40
#define hu_size 44
// dnode_t structure
// !!! if this is changed, it must be changed in bspfile.h too !!!
#define nd_planenum 0
#define nd_children 4
#define nd_mins 8
#define nd_maxs 20
#define nd_firstface 32
#define nd_numfaces 36
#define nd_size 40
// sfxcache_t structure
// !!! if this is changed, it much be changed in sound.h too !!!
#define sfxc_length 0
#define sfxc_loopstart 4
#define sfxc_speed 8
#define sfxc_width 12
#define sfxc_stereo 16
#define sfxc_data 20
// channel_t structure
// !!! if this is changed, it much be changed in sound.h too !!!
#define MAXSOUNDCHANNELS 6
#define ch_sfx 0
#define ch_vol ch_sfx+4
#define ch_end ch_vol+4*MAXSOUNDCHANNELS
#define ch_pos ch_end+4
#define ch_looping ch_looping+4
#define ch_entnum ch_entnum+4
#define ch_entchannel ch_entchannel+4
#define ch_origin ch_origin+4
#define ch_dist_mult ch_dist_mult+4
#define ch_master_vol ch_master_vol+4
#define ch_size ch_size+4
// portable_samplepair_t structure
// !!! if this is changed, it much be changed in sound.h too !!!
#define psp_left 0
#define psp_right 4
#define psp_size 8
#endif

447
engine/common/bothdefs.h Normal file
View file

@ -0,0 +1,447 @@
/*
Copyright (C) 1996-1997 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.
*/
#ifndef __BOTHDEFS_H
#define __BOTHDEFS_H
#ifdef __MINGW32_VERSION
#define MINGW
#endif
#ifdef HAVE_CONFIG_H //if it was configured properly, then we have a more correct list of features we want to use.
#include "config.h"
#else
//#define AVAIL_OGGVORBIS
#if !defined(__CYGWIN__) && !defined(MINGW)
#define AVAIL_PNGLIB
#define AVAIL_JPEGLIB
#define AVAIL_ZLIB
#endif
#define AVAIL_MASM
//#define AVAIL_DX7
//set any additional defines or libs in win32
#ifndef AVAIL_MASM
#ifdef _WIN32
#define NOASM
#else
#undef AVAIL_MASM //fixme
#endif
#endif
#ifndef AVAIL_OGGVORBIS
#define NO_OGGVORBIS
#endif
#define SVRANKING
#ifdef MINIMAL
#undef AVAIL_MP3 //no mp3 support
#undef AVAIL_JPEGLIB //no jpeg support
#undef AVAIL_PNGLIB //no png support
#undef USE_MADLIB //no internal mp3 playing
#undef AVAIL_DX7 //no d3d support
#define NO_OGGVORBIS //don't use oggvorbis
#define NOMEDIA //NO playing of avis/cins/roqs
#define NOVOICECHAT //NO sound recording, tcp streaming and playback on a remote client. not finalised.
#define MD3MODELS //we DO want to use quake3 alias models. This might be a minimal build, but we still want this.
#else
#define SIDEVIEWS 4 //enable secondary/reverse views.
#define SP2MODELS //quake2 sprite models
#define MD2MODELS //quake2 alias models
#define MD3MODELS //quake3 alias models
#define HUFFNETWORK //huffman network compression
#define HALFLIFEMODELS //halflife model support (experimental)
#define DOOMWADS //doom wad/map/sprite support
//#define WOLF3DSUPPORT //wolfenstein3d map support (not started yet)
#define Q2BSPS //quake 2 bsp support
#define Q3BSPS //quake 3 bsp support
#define SV_MASTER //starts up a master server
#define SVCHAT //serverside npc chatting. see sv_chat.c
#define Q2SERVER //server can run a q2 game dll and switches to q2 network and everything else.
#define Q2CLIENT //client can connect to q2 servers
#define NQPROT //server and client are capable of using quake1/netquake protocols. (qw is still prefered. uses the command 'nqconnect')
#define FISH //sw rendering only
#define VM_UI //support userinterfaces within Q3 Virtual Machines
//#define VM_CG //make work
#define ZLIB //zip/pk3 support
#define WEBSERVER //http/ftp servers
#define WEBCLIENT //http/ftp clients.
#define EMAILSERVER //smtp/pop3 server should you feel a need
#define EMAILCLIENT //smtp/pop3 clients (email notifications)
#define IRCCLIENT //connects to irc servers.
#define RUNTIMELIGHTING //calculate lit/lux files the first time the map is loaded and doesn't have a loadable lit.
#define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm.
#define CL_MASTER //query master servers and stuff for a dynamic server listing.
#define SERIALMOUSE //means that the engine talks to a serial mouse directly via the com/serial port. Thus allowing duel mice with seperate inputs.
#define R_XFLIP //allow view to be flipped horizontally
#define IN_XFLIP //allow input to be flipped horizontally.
#define TEXTEDITOR
// #define VOICECHAT //experimental
#endif
#endif
//fix things a little...
#ifdef MINGW
#undef ZLIB
#undef AVAIL_ZLIB
#endif
#if defined(VM_UI) || defined(VM_CG)
#define VM_ANY
#endif
#ifdef USE_MADLIB //global option. Specify on compiler command line.
#define AVAIL_MP3 //suposedly anti-gpl. don't use in a distributed binary
#endif
#ifndef ZLIB
#undef AVAIL_ZLIB //no zip/pk3 support
#endif
#ifndef _WIN32
#undef QTERM
#endif
#if (defined(Q2CLIENT) || defined(Q2SERVER))
#ifndef Q2BSPS
#error "Q2 game support without Q2BSP support. doesn't make sense"
#endif
#if !defined(MD2MODELS) || !defined(SP2MODELS)
#error "Q2 game support without full Q2 model support. doesn't make sense"
#endif
#endif
#ifdef SERVERONLY //remove options that don't make sense on only a server
#undef Q2CLIENT
#undef WEBCLIENT
#undef IRCCLIENT
#undef EMAILCLIENT
#undef TEXTEDITOR
#undef RUNTIMELIGHTING
#endif
#ifdef CLIENTONLY //remove optional server componants that make no sence on a client only build.
#undef Q2SERVER
#undef WEBSERVER
#undef EMAILSERVER
#endif
//remove any options that depend upon GL.
#ifndef SERVERONLY
#if defined(SWQUAKE) && !defined(RGLQUAKE) && !defined(GLQUAKE)
#undef DOOMWADS
#undef HALFLIFEMODELS
#undef Q3BSPS
#undef R_XFLIP
#undef RUNTIMELIGHTING
#endif
#endif
#define PROTOCOLEXTENSIONS
#define PRE_SAYONE 2.487 //FIXME: remove.
// defs common to client and server
#define GLQUAKE_VERSION 1.01
#define VERSION 2.55
#define LINUX_VERSION 0.98
//#define VERSION3PART //add the 3rd decimal point of a more precise version.
#define DISTRIBUTION "FTE"
#define DISTRIBUTIONLONG "Forethought Entertainment"
#define ENGINEWEBSITE "http://fte.quakesrc.org/"
#ifdef _WIN32
#define PLATFORM "Win32"
#else
#define PLATFORM "Linux"
#endif
#if (defined(_M_IX86) || defined(__i386__)) && !defined(id386)
#define id386 1
#else
#define id386 0
#endif
#if defined(NOASM) // no asm in dedicated server
#undef id386
#endif
#if id386
#define UNALIGNED_OK 1 // set to 0 if unaligned accesses are not supported
#else
#define UNALIGNED_OK 0
#endif
#ifdef _MSC_VER
#define VARGS __cdecl
#endif
#ifndef VARGS
#define VARGS
#endif
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
#define CACHE_SIZE 32 // used to align key data structures
#define UNUSED(x) (x = x) // for pesky compiler / lint warnings
#define MINIMUM_MEMORY 0x550000
// up / down
#define PITCH 0
// left / right
#define YAW 1
// fall over
#define ROLL 2
#define MAX_SCOREBOARD 16 // max numbers of players
#define SOUND_CHANNELS 8
#define MAX_QPATH 64 // max length of a quake game pathname
#define MAX_OSPATH 256 // max length of a filesystem pathname
#define ON_EPSILON 0.1 // point on plane side epsilon
#define MAX_NQMSGLEN 8000 // max length of a reliable message
#define MAX_Q2MSGLEN 1400
#define MAX_QWMSGLEN 1450
#define MAX_OVERALLMSGLEN MAX_NQMSGLEN
#define MAX_DATAGRAM 1450 // max length of unreliable message
#define MAX_Q2DATAGRAM MAX_Q2MSGLEN
#define MAX_NQDATAGRAM 1024 // max length of unreliable message
#define MAX_OVERALLDATAGRAM MAX_DATAGRAM
#define MAX_BACKBUFLEN 1200
//
// per-level limits
//
#define MAX_EDICTS 2048 // FIXME: ouch! ouch! ouch!
#define MAX_LIGHTSTYLES 64
#define MAX_MODELS 512 // these are sent over the net as bytes
#define MAX_SOUNDS 256 // so they cannot be blindly increased
#define SAVEGAME_COMMENT_LENGTH 39
#define MAX_STYLESTRING 64
//
// stats are integers communicated to the client by the server
//
#define MAX_QW_STATS 32
enum {
STAT_HEALTH = 0,
//STAT_FRAGS = 1,
STAT_WEAPON = 2,
STAT_AMMO = 3,
STAT_ARMOR = 4,
STAT_WEAPONFRAME = 5,
STAT_SHELLS = 6,
STAT_NAILS = 7,
STAT_ROCKETS = 8,
STAT_CELLS = 9,
STAT_ACTIVEWEAPON = 10,
STAT_TOTALSECRETS = 11,
STAT_TOTALMONSTERS = 12,
STAT_SECRETS = 13, // bumped on client side by svc_foundsecret
STAT_MONSTERS = 14, // bumped by svc_killedmonster
STAT_ITEMS = 15,
STAT_VIEWHEIGHT = 16,
STAT_TIME = 17,
#ifdef SIDEVIEWS
STAT_VIEW2 = 20,
#endif
STAT_H2_LEVEL = 32, // changes stat bar
STAT_H2_INTELLIGENCE, // changes stat bar
STAT_H2_WISDOM, // changes stat bar
STAT_H2_STRENGTH, // changes stat bar
STAT_H2_DEXTERITY, // changes stat bar
STAT_H2_BLUEMANA, // changes stat bar
STAT_H2_GREENMANA, // changes stat bar
STAT_H2_EXPERIENCE, // changes stat bar
STAT_H2_CNT_TORCH, // changes stat bar
STAT_H2_CNT_H_BOOST, // changes stat bar
STAT_H2_CNT_SH_BOOST, // changes stat bar
STAT_H2_CNT_MANA_BOOST, // changes stat bar
STAT_H2_CNT_TELEPORT, // changes stat bar
STAT_H2_CNT_TOME, // changes stat bar
STAT_H2_CNT_SUMMON, // changes stat bar
STAT_H2_CNT_INVISIBILITY, // changes stat bar
STAT_H2_CNT_GLYPH, // changes stat bar
STAT_H2_CNT_HASTE, // changes stat bar
STAT_H2_CNT_BLAST, // changes stat bar
STAT_H2_CNT_POLYMORPH, // changes stat bar
STAT_H2_CNT_FLIGHT, // changes stat bar
STAT_H2_CNT_CUBEOFFORCE, // changes stat bar
STAT_H2_CNT_INVINCIBILITY, // changes stat bar
STAT_H2_ARTIFACT_ACTIVE,
STAT_H2_ARTIFACT_LOW,
STAT_H2_MOVETYPE,
STAT_H2_CAMERAMODE,
STAT_H2_HASTED,
STAT_H2_INVENTORY,
STAT_H2_RINGS_ACTIVE,
STAT_H2_RINGS_LOW,
STAT_H2_AMULET,
STAT_H2_BRACER,
STAT_H2_BREASTPLATE,
STAT_H2_HELMET,
STAT_H2_FLIGHT_T,
STAT_H2_WATER_T,
STAT_H2_TURNING_T,
STAT_H2_REGEN_T,
STAT_H2_PUZZLE1A,
STAT_H2_PUZZLE1B,
STAT_H2_PUZZLE1C,
STAT_H2_PUZZLE1D,
STAT_H2_PUZZLE2A,
STAT_H2_PUZZLE2B,
STAT_H2_PUZZLE2C,
STAT_H2_PUZZLE2D,
STAT_H2_PUZZLE3A,
STAT_H2_PUZZLE3B,
STAT_H2_PUZZLE3C,
STAT_H2_PUZZLE3D,
STAT_H2_PUZZLE4A,
STAT_H2_PUZZLE4B,
STAT_H2_PUZZLE4C,
STAT_H2_PUZZLE4D,
STAT_H2_PUZZLE5A,
STAT_H2_PUZZLE5B,
STAT_H2_PUZZLE5C,
STAT_H2_PUZZLE5D,
STAT_H2_PUZZLE6A,
STAT_H2_PUZZLE6B,
STAT_H2_PUZZLE6C,
STAT_H2_PUZZLE6D,
STAT_H2_PUZZLE7A,
STAT_H2_PUZZLE7B,
STAT_H2_PUZZLE7C,
STAT_H2_PUZZLE7D,
STAT_H2_PUZZLE8A,
STAT_H2_PUZZLE8B,
STAT_H2_PUZZLE8C,
STAT_H2_PUZZLE8D,
STAT_H2_MAXHEALTH,
STAT_H2_MAXMANA,
STAT_H2_FLAGS,
MAX_CL_STATS = 128
};
//
// item flags
//
#define IT_SHOTGUN 1
#define IT_SUPER_SHOTGUN 2
#define IT_NAILGUN 4
#define IT_SUPER_NAILGUN 8
#define IT_GRENADE_LAUNCHER 16
#define IT_ROCKET_LAUNCHER 32
#define IT_LIGHTNING 64
#define IT_SUPER_LIGHTNING 128
#define IT_SHELLS 256
#define IT_NAILS 512
#define IT_ROCKETS 1024
#define IT_CELLS 2048
#define IT_AXE 4096
#define IT_ARMOR1 8192
#define IT_ARMOR2 16384
#define IT_ARMOR3 32768
#define IT_SUPERHEALTH 65536
#define IT_KEY1 131072
#define IT_KEY2 262144
#define IT_INVISIBILITY 524288
#define IT_INVULNERABILITY 1048576
#define IT_SUIT 2097152
#define IT_QUAD 4194304
#define IT_SIGIL1 (1<<28)
#define IT_SIGIL2 (1<<29)
#define IT_SIGIL3 (1<<30)
#define IT_SIGIL4 (1<<31)
//
// 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
//split screen stuff
#define MAX_SPLITS 4
//savegame vars
#define SAVEGAME_COMMENT_LENGTH 39
#define SAVEGAME_VERSION 667
#define dem_cmd 0
#define dem_read 1
#define dem_set 2
#define dem_multiple 3
#define dem_single 4
#define dem_stats 5
#define dem_all 6
#endif //ifndef __BOTHDEFS_H

732
engine/common/bspfile.h Normal file
View file

@ -0,0 +1,732 @@
/*
Copyright (C) 1996-1997 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.
*/
// upper design bounds
#define MAX_MAP_HULLSDQ1 4
#define MAX_MAP_HULLSDH2 8
#define MAX_MAP_HULLSM 16
#define MAX_MAP_MODELS 256
#define MAX_MAP_BRUSHES 0x4000
#define MAX_MAP_ENTITIES 1024
#define MAX_MAP_ENTSTRING 65536
#define MAX_MAP_PLANES 8192
#define MAX_MAP_NODES 32767 // because negative shorts are contents
#define MAX_MAP_CLIPNODES 32767 //
#define MAX_MAP_LEAFS 32767 //
#define MAX_MAP_VERTS 65535
#define MAX_MAP_FACES 65535
#define MAX_MAP_MARKSURFACES 65535
#define MAX_MAP_TEXINFO 4096
#define MAX_MAP_EDGES 256000
#define MAX_MAP_SURFEDGES 512000
#define MAX_MAP_MIPTEX 0x200000
#define MAX_MAP_LIGHTING 0x100000
#define MAX_MAP_VISIBILITY 0x200000
// key / value pair sizes
#define MAX_KEY 32
#define MAX_VALUE 1024
//=============================================================================
#define BSPVERSION 29
//HalfLife support
#define BSPVERSIONHL 30
typedef struct
{
int fileofs, filelen;
} lump_t;
#define LUMP_ENTITIES 0
#define LUMP_PLANES 1
#define LUMP_TEXTURES 2
#define LUMP_VERTEXES 3
#define LUMP_VISIBILITY 4
#define LUMP_NODES 5
#define LUMP_TEXINFO 6
#define LUMP_FACES 7
#define LUMP_LIGHTING 8
#define LUMP_CLIPNODES 9
#define LUMP_LEAFS 10
#define LUMP_MARKSURFACES 11
#define LUMP_EDGES 12
#define LUMP_SURFEDGES 13
#define LUMP_MODELS 14
#define HEADER_LUMPS 15
typedef struct
{
float mins[3], maxs[3];
float origin[3];
int headnode[MAX_MAP_HULLSDQ1];
int visleafs; // not including the solid leaf 0
int firstface, numfaces;
} dq1model_t;
typedef struct
{
float mins[3], maxs[3];
float origin[3];
int headnode[MAX_MAP_HULLSDH2];
int visleafs; // not including the solid leaf 0
int firstface, numfaces;
} dh2model_t;
typedef struct
{
int version;
lump_t lumps[HEADER_LUMPS];
} dheader_t;
typedef struct
{
int nummiptex;
int dataofs[4]; // [nummiptex]
} dmiptexlump_t;
#define MIPLEVELS 4
typedef struct miptex_s
{
char name[16];
unsigned width, height;
unsigned offsets[MIPLEVELS]; // four mip maps stored
} miptex_t;
typedef struct
{
float point[3];
} dvertex_t;
// 0-2 are axial planes
#define PLANE_X 0
#define PLANE_Y 1
#define PLANE_Z 2
// 3-5 are non-axial planes snapped to the nearest
#define PLANE_ANYX 3
#define PLANE_ANYY 4
#define PLANE_ANYZ 5
typedef struct
{
float normal[3];
float dist;
int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
} dplane_t;
#define Q1CONTENTS_EMPTY -1
#define Q1CONTENTS_SOLID -2
#define Q1CONTENTS_WATER -3
#define Q1CONTENTS_SLIME -4
#define Q1CONTENTS_LAVA -5
#define Q1CONTENTS_SKY -6
#define FTECONTENTS_EMPTY 0
#define FTECONTENTS_SOLID 1
#define FTECONTENTS_WATER 2
#define FTECONTENTS_SLIME 4
#define FTECONTENTS_LAVA 8
#define FTECONTENTS_SKY 16
#define FTECONTENTS_LADDER 32
#define FTECONTENTS_FLUID (FTECONTENTS_WATER|FTECONTENTS_SLIME|FTECONTENTS_LAVA|FTECONTENTS_SKY) //sky is a fluid for q1 code.
// !!! if this is changed, it must be changed in asm_i386.h too !!!
typedef struct
{
int planenum;
short children[2]; // negative numbers are -(leafs+1), not nodes
short mins[3]; // for sphere culling
short maxs[3];
unsigned short firstface;
unsigned short numfaces; // counting both sides
} dnode_t;
typedef struct
{
int planenum;
short children[2]; // negative numbers are contents
} dclipnode_t;
typedef struct texinfo_s
{
float vecs[2][4]; // [s/t][xyz offset]
int miptex;
int flags;
} texinfo_t;
#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
// note that edge 0 is never used, because negative edge nums are used for
// counterclockwise use of the edge in a face
typedef struct
{
unsigned short v[2]; // vertex numbers
} dedge_t;
#define MAXLIGHTMAPS 4
typedef struct
{
short planenum;
short side;
int firstedge; // we must support > 64k edges
short numedges;
short texinfo;
// lighting info
qbyte styles[MAXLIGHTMAPS];
int lightofs; // start of [numstyles*surfsize] samples
} dface_t;
#define AMBIENT_WATER 0
#define AMBIENT_SKY 1
#define AMBIENT_SLIME 2
#define AMBIENT_LAVA 3
#define NUM_AMBIENTS 4 // automatic ambient sounds
#define NUM_MUSICS 2 // so the streaming media can just switch between the two, allowing it to seamlessly continue.
// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas
// all other leafs need visibility info
typedef struct
{
int contents;
int visofs; // -1 = no visibility info
short mins[3]; // for frustum culling
short maxs[3];
unsigned short firstmarksurface;
unsigned short nummarksurfaces;
qbyte ambient_level[NUM_AMBIENTS];
} dleaf_t;
//============================================================================
#ifndef QUAKE_GAME
// the utilities get to be lazy and just use large static arrays
extern int nummodels;
extern dmodel_t dmodels[MAX_MAP_MODELS];
extern int visdatasize;
extern qbyte dvisdata[MAX_MAP_VISIBILITY];
extern int lightdatasize;
extern qbyte dlightdata[MAX_MAP_LIGHTING];
extern int texdatasize;
extern qbyte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
extern int entdatasize;
extern char dentdata[MAX_MAP_ENTSTRING];
extern int numleafs;
extern dleaf_t dleafs[MAX_MAP_LEAFS];
extern int numplanes;
extern dplane_t dplanes[MAX_MAP_PLANES];
extern int numvertexes;
extern dvertex_t dvertexes[MAX_MAP_VERTS];
extern int numnodes;
extern dnode_t dnodes[MAX_MAP_NODES];
extern int numtexinfo;
extern texinfo_t texinfo[MAX_MAP_TEXINFO];
extern int numfaces;
extern dface_t dfaces[MAX_MAP_FACES];
extern int numclipnodes;
extern dclipnode_t dclipnodes[MAX_MAP_CLIPNODES];
extern int numedges;
extern dedge_t dedges[MAX_MAP_EDGES];
extern int nummarksurfaces;
extern unsigned short dmarksurfaces[MAX_MAP_MARKSURFACES];
extern int numsurfedges;
extern int dsurfedges[MAX_MAP_SURFEDGES];
void LoadBSPFile (char *filename);
void WriteBSPFile (char *filename);
void PrintBSPFileSizes (void);
#endif
#define MIPLEVELS 4
typedef struct q2miptex_s
{
char name[32];
unsigned width, height;
unsigned offsets[MIPLEVELS]; // four mip maps stored
char animname[32]; // next frame in animation chain
int flags;
int contents;
int value;
} q2miptex_t;
/*
==============================================================================
.BSP file format
==============================================================================
*/
#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I')
// little-endian "IBSP"
#define Q2BSPVERSION 38
#define Q3BSPVERSION 46
// upper design bounds
// leaffaces, leafbrushes, planes, and verts are still bounded by
// 16 bit short limits
#define MAX_Q2MAP_MODELS 1024
#define MAX_Q2MAP_BRUSHES MAX_MAP_BRUSHES
#define MAX_Q2MAP_ENTITIES 2048
#define MAX_Q2MAP_ENTSTRING 0x40000
#define MAX_Q2MAP_TEXINFO 8192
#define MAX_Q2MAP_AREAS 256
#define MAX_Q2MAP_AREAPORTALS 1024
#define MAX_Q2MAP_PLANES 65536
#define MAX_Q2MAP_NODES 65536
#define MAX_Q2MAP_BRUSHSIDES 0x30000
#define MAX_Q2MAP_LEAFS 65536
#define MAX_Q2MAP_VERTS 65536
#define MAX_Q2MAP_FACES 65536
#define MAX_Q2MAP_LEAFFACES 65536
#define MAX_Q2MAP_LEAFBRUSHES 65536
#define MAX_Q2MAP_PORTALS 65536
#define MAX_Q2MAP_EDGES 128000
#define MAX_Q2MAP_SURFEDGES 256000
#define MAX_Q2MAP_LIGHTING 0x200000
#define MAX_Q2MAP_VISIBILITY MAX_MAP_VISIBILITY
// key / value pair sizes
#define MAX_KEY 32
#define MAX_VALUE 1024
//=============================================================================
#define Q2LUMP_ENTITIES 0
#define Q2LUMP_PLANES 1
#define Q2LUMP_VERTEXES 2
#define Q2LUMP_VISIBILITY 3
#define Q2LUMP_NODES 4
#define Q2LUMP_TEXINFO 5
#define Q2LUMP_FACES 6
#define Q2LUMP_LIGHTING 7
#define Q2LUMP_LEAFS 8
#define Q2LUMP_LEAFFACES 9
#define Q2LUMP_LEAFBRUSHES 10
#define Q2LUMP_EDGES 11
#define Q2LUMP_SURFEDGES 12
#define Q2LUMP_MODELS 13
#define Q2LUMP_BRUSHES 14
#define Q2LUMP_BRUSHSIDES 15
#define Q2LUMP_POP 16
#define Q2LUMP_AREAS 17
#define Q2LUMP_AREAPORTALS 18
#define Q2HEADER_LUMPS 19
enum Q3LUMP
{
Q3LUMP_ENTITIES =0,
Q3LUMP_SHADERS =1,
Q3LUMP_PLANES =2,
Q3LUMP_NODES =3,
Q3LUMP_LEAFS =4,
Q3LUMP_LEAFSURFACES =5,
Q3LUMP_LEAFBRUSHES =6,
Q3LUMP_MODELS =7,
Q3LUMP_BRUSHES =8,
Q3LUMP_BRUSHSIDES =9,
Q3LUMP_DRAWVERTS =10,
Q3LUMP_DRAWINDEXES =11,
Q3LUMP_FOGS =12,
Q3LUMP_SURFACES =13,
Q3LUMP_LIGHTMAPS =14,
Q3LUMP_LIGHTGRID =15,
Q3LUMP_VISIBILITY =16,
Q3LUMPS_TOTAL
};
typedef struct
{
int ident;
int version;
lump_t lumps[Q2HEADER_LUMPS];
} q2dheader_t;
typedef struct
{
float mins[3], maxs[3];
float origin[3]; // for sounds or lights
int headnode;
int firstface, numfaces; // submodels just draw faces
// without walking the bsp tree
} q2dmodel_t;
typedef struct
{
float mins[3];
float maxs[3];
int firstsurface;
int num_surfaces;
int firstbrush;
int num_brushes;
} q3dmodel_t;
// 0-2 are axial planes
#define PLANE_X 0
#define PLANE_Y 1
#define PLANE_Z 2
// 3-5 are non-axial planes snapped to the nearest
#define PLANE_ANYX 3
#define PLANE_ANYY 4
#define PLANE_ANYZ 5
// contents flags are seperate bits
// a given brush can contribute multiple content bits
// multiple brushes can be in a single leaf
// these definitions also need to be in q_shared.h!
// lower bits are stronger, and will eat weaker brushes completely
#define Q2CONTENTS_SOLID 1 // an eye is never valid in a solid
#define Q2CONTENTS_WINDOW 2 // translucent, but not watery
#define Q2CONTENTS_AUX 4
#define Q2CONTENTS_LAVA 8
#define Q2CONTENTS_SLIME 16
#define Q2CONTENTS_WATER 32
#define Q2CONTENTS_MIST 64
#define Q2LAST_VISIBLE_CONTENTS 64
// remaining contents are non-visible, and don't eat brushes
#define Q2CONTENTS_AREAPORTAL 0x8000
#define Q2CONTENTS_PLAYERCLIP 0x10000
#define Q2CONTENTS_MONSTERCLIP 0x20000
// currents can be added to any other contents, and may be mixed
#define Q2CONTENTS_CURRENT_0 0x40000
#define Q2CONTENTS_CURRENT_90 0x80000
#define Q2CONTENTS_CURRENT_180 0x100000
#define Q2CONTENTS_CURRENT_270 0x200000
#define Q2CONTENTS_CURRENT_UP 0x400000
#define Q2CONTENTS_CURRENT_DOWN 0x800000
#define Q2CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
#define Q2CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
#define Q2CONTENTS_DEADMONSTER 0x4000000
#define Q2CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
#define Q2CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
#define Q3CONTENTS_TRANSLUCENT 0x20000000
#define Q2CONTENTS_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 (Q2CONTENTS_SOLID|Q2CONTENTS_WINDOW)
#define MASK_PLAYERSOLID (Q2CONTENTS_SOLID|Q2CONTENTS_PLAYERCLIP|Q2CONTENTS_WINDOW|Q2CONTENTS_MONSTER)
#define MASK_DEADSOLID (Q2CONTENTS_SOLID|Q2CONTENTS_PLAYERCLIP|Q2CONTENTS_WINDOW)
#define MASK_MONSTERSOLID (Q2CONTENTS_SOLID|Q2CONTENTS_MONSTERCLIP|Q2CONTENTS_WINDOW|Q2CONTENTS_MONSTER)
#define MASK_WATER (Q2CONTENTS_WATER|Q2CONTENTS_LAVA|Q2CONTENTS_SLIME)
#define MASK_OPAQUE (Q2CONTENTS_SOLID|Q2CONTENTS_SLIME|Q2CONTENTS_LAVA)
#define MASK_SHOT (Q2CONTENTS_SOLID|Q2CONTENTS_MONSTER|Q2CONTENTS_WINDOW|Q2CONTENTS_DEADMONSTER)
#define MASK_CURRENT (Q2CONTENTS_CURRENT_0|Q2CONTENTS_CURRENT_90|Q2CONTENTS_CURRENT_180|Q2CONTENTS_CURRENT_270|Q2CONTENTS_CURRENT_UP|Q2CONTENTS_CURRENT_DOWN)
typedef struct
{
int planenum;
int children[2]; // negative numbers are -(leafs+1), not nodes
short mins[3]; // for frustom culling
short maxs[3];
unsigned short firstface;
unsigned short numfaces; // counting both sides
} q2dnode_t;
typedef struct
{
int plane;
int children[2];
int mins[3];
int maxs[3];
} q3dnode_t;
typedef struct q2texinfo_s
{
float vecs[2][4]; // [s/t][xyz offset]
int flags; // miptex flags + overrides
int value; // light emission, etc
char texture[32]; // texture name (textures/ *.wal)
int nexttexinfo; // for animations, -1 = end of chain
} q2texinfo_t;
typedef struct
{
int contents; // OR of all brushes (not needed?)
short cluster;
short area;
short mins[3]; // for frustum culling
short maxs[3];
unsigned short firstleafface;
unsigned short numleaffaces;
unsigned short firstleafbrush;
unsigned short numleafbrushes;
} q2dleaf_t;
typedef struct
{
int cluster;
int area;
int mins[3];
int maxs[3];
int firstleafsurface;
int num_leafsurfaces;
int firstleafbrush;
int num_leafbrushes;
} q3dleaf_t;
typedef struct
{
unsigned short planenum; // facing out of the leaf
short texinfo;
} q2dbrushside_t;
typedef struct
{
int planenum;
int texinfo;
} q3dbrushside_t;
typedef struct
{
int firstside;
int numsides;
int contents;
} q2dbrush_t;
typedef struct
{
int firstside;
int num_sides;
int shadernum;
} q3dbrush_t;
#define ANGLE_UP -1
#define ANGLE_DOWN -2
// the visibility lump consists of a header with a count, then
// qbyte offsets for the PVS and PHS of each cluster, then the raw
// compressed bit vectors
#define DVIS_PVS 0
#define DVIS_PHS 1
typedef struct
{
int numclusters;
int bitofs[8][2]; // bitofs[numclusters][2]
} q2dvis_t;
typedef struct
{
int numclusters;
int rowsize;
unsigned char data[1];
} q3dvis_t;
// each area has a list of portals that lead into other areas
// when portals are closed, other areas may not be visible or
// hearable even if the vis info says that it should be
typedef struct
{
int portalnum;
int otherarea;
} q2dareaportal_t;
typedef struct
{
int numareaportals;
int firstareaportal;
} q2darea_t;
typedef struct
{
char shadername[64];
int surfflags;
int contents;
} dq3shader_t;
typedef struct
{
float n[3];
float d;
} Q3PLANE_t;
struct Q3MODEL
{
float mins[3];
float maxs[3];
int firstsurface;
int num_surfaces;
int firstbrush;
int num_brushes;
};
typedef struct
{
float point[3];
float texcoords[2][2];
float normal[3];
unsigned char color[4];
} q3dvertex_t;
struct Q3FOG
{
char shadername[64] ;
int brushnum;
int visibleside;
};
enum q3surfacetype
{
MST_BAD=0,
MST_PLANAR=1,
MST_PATCH=2,
MST_TRIANGLE_SOUP=3,
MST_FLARE=4
};
typedef struct
{
int shadernum;
int fognum;
int facetype;
int firstvertex;
int num_vertices;
int firstindex;
int num_indexes;
int lightmapnum;
int lightmap_x;
int lightmap_y;
int lightmap_width;
int lightmap_height;
float lightmap_origin[3];
float lightmap_vecs[2][3];
float normal[3];
int patchwidth;
int patchheight;
} q3dface_t;

2665
engine/common/cmd.c Normal file

File diff suppressed because it is too large Load diff

139
engine/common/cmd.h Normal file
View file

@ -0,0 +1,139 @@
/*
Copyright (C) 1996-1997 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.
*/
// cmd.h -- Command buffer and command execution
//===========================================================================
/*
Any number of commands can be added in a frame, from several different sources.
Most commands come from either keybindings or console line input, but remote
servers can also send across commands and entire text files can be execed.
The + command line options are also added to the command buffer.
The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute ();
*/
void Cbuf_Init (void);
// allocates an initial text buffer that will grow as needed
void Cbuf_AddText (const char *text, int level);
// as new commands are generated from the console or keybindings,
// the text is added to the end of the command buffer.
void Cbuf_InsertText (const char *text, int level);
// when a command wants to issue other commands immediately, the text is
// inserted at the beginning of the buffer, before any remaining unexecuted
// commands.
char *Cbuf_GetNext(int level);
void Cbuf_Execute (void);
// Pulls off \n terminated lines of text from the command buffer and sends
// them through Cmd_ExecuteString. Stops when the buffer is empty.
// Normally called once per frame, but may be explicitly invoked.
// Do not call inside a command function!
//===========================================================================
/*
Command execution takes a null terminated string, breaks it into tokens,
then searches for a command or variable that matches the first token.
*/
typedef void (*xcommand_t) (void);
int Cmd_Level(char *name);
void Cmd_Init (void);
void Cmd_RemoveCommand (char *cmd_name);
void Cmd_AddRemCommand (char *cmd_name, xcommand_t function); //removable command
void Cmd_AddCommand (char *cmd_name, xcommand_t function);
// called by the init functions of other parts of the program to
// register commands and functions to call for them.
// The cmd_name is referenced later, so it should not be in temp memory
// if function is NULL, the command will be forwarded to the server
// as a clc_stringcmd instead of executed locally
qboolean Cmd_Exists (char *cmd_name);
// used by the cvar code to check for cvar / command name overlap
char *Cmd_CompleteCommand (char *partial, qboolean fullonly, int matchnum);
// attempts to match a partial command for automatic command line completion
// returns NULL if nothing fits
int Cmd_Argc (void);
char *Cmd_Argv (int arg);
char *Cmd_Args (void);
extern int Cmd_ExecLevel;
// The functions that execute commands get their parameters with these
// functions. Cmd_Argv () will return an empty string, not a NULL
// if arg > argc, so string operations are allways safe.
int Cmd_CheckParm (char *parm);
// Returns the position (1 to argc-1) in the command's argument list
// where the given parameter apears, or 0 if not present
char *Cmd_AliasExist(char *name, int restrictionlevel);
void Alias_WipeStuffedAliaes(void);
void Cmd_TokenizeString (char *text);
// Takes a null terminated string. Does not need to be /n terminated.
// breaks the string up into arg tokens.
void Cmd_ExecuteString (char *text, int restrictionlevel);
#define RESTRICT_MAX 64 //1-64 it's all about bit size. This is max settable. servers are +1
#define RESTRICT_DEFAULT 50 //rcon get's 63, local always gets 64
#define RESTRICT_MIN 1 //rcon get's 63, local always gets 64
#define RESTRICT_LOCAL RESTRICT_MAX
#define RESTRICT_SERVER RESTRICT_MAX+1
#define RESTRICT_RCON rcon_level.value
#define RESTRICT_PROGS RESTRICT_MAX-2
#define Cmd_FromServer() (Cmd_ExecLevel>=RESTRICT_SERVER)
// Parses a single line of text into arguments and tries to execute it
// as if it was typed at the console
void Cmd_ForwardToServer (void);
// adds the current command line as a clc_stringcmd to the client message.
// things like godmode, noclip, etc, are commands directed to the server,
// so when they are typed in at the console, they will need to be forwarded.
qboolean Cmd_FilterMessage (char *message, qboolean sameteam);
void Cmd_MessageTrigger (char *message, int type);
void Cmd_StuffCmds_f (void);
void Cmd_ShiftArgs (int ammount);
char *Cmd_ExpandString (char *input, int maxaccesslevel);
extern cvar_t rcon_level;

4688
engine/common/common.c Normal file

File diff suppressed because it is too large Load diff

290
engine/common/common.h Normal file
View file

@ -0,0 +1,290 @@
/*
Copyright (C) 1996-1997 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.
*/
// comndef.h -- general definitions
typedef unsigned char qbyte;
#define _DEF_BYTE_
// KJB Undefined true and false defined in SciTech's DEBUG.H header
#undef true
#undef false
#ifdef __cplusplus
typedef enum qboolean;//false and true are forcivly defined.
#else
typedef enum {false, true} qboolean;
#endif
#define MAX_INFO_STRING 196
#define MAX_SERVERINFO_STRING 512
#define MAX_LOCALINFO_STRING 32768
//============================================================================
typedef struct sizebuf_s
{
qboolean allowoverflow; // if false, do a Sys_Error
qboolean overflowed; // set to true if the buffer size failed
qbyte *data;
int maxsize;
int cursize;
} sizebuf_t;
void SZ_Clear (sizebuf_t *buf);
void *SZ_GetSpace (sizebuf_t *buf, int length);
void SZ_Write (sizebuf_t *buf, const void *data, int length);
void SZ_Print (sizebuf_t *buf, const char *data); // strcats onto the sizebuf
//============================================================================
typedef struct link_s
{
struct link_s *prev, *next;
} link_t;
void ClearLink (link_t *l);
void RemoveLink (link_t *l);
void InsertLinkBefore (link_t *l, link_t *before);
void InsertLinkAfter (link_t *l, link_t *after);
// (type *)STRUCT_FROM_LINK(link_t *link, type, member)
// ent = STRUCT_FROM_LINK(link,entity_t,order)
// FIXME: remove this mess!
#define STRUCT_FROM_LINK(l,t,m) ((t *)((qbyte *)l - (int)&(((t *)0)->m)))
//============================================================================
#ifndef NULL
#define NULL ((void *)0)
#endif
#define Q_MAXCHAR ((char)0x7f)
#define Q_MAXSHORT ((short)0x7fff)
#define Q_MAXINT ((int)0x7fffffff)
#define Q_MAXLONG ((int)0x7fffffff)
#define Q_MAXFLOAT ((int)0x7fffffff)
#define Q_MINCHAR ((char)0x80)
#define Q_MINSHORT ((short)0x8000)
#define Q_MININT ((int)0x80000000)
#define Q_MINLONG ((int)0x80000000)
#define Q_MINFLOAT ((int)0x7fffffff)
//============================================================================
extern qboolean bigendien;
extern short (*BigShort) (short l);
extern short (*LittleShort) (short l);
extern int (*BigLong) (int l);
extern int (*LittleLong) (int l);
extern float (*BigFloat) (float l);
extern float (*LittleFloat) (float l);
//============================================================================
struct usercmd_s;
extern struct usercmd_s nullcmd;
void MSG_WriteChar (sizebuf_t *sb, int c);
void MSG_WriteByte (sizebuf_t *sb, int c);
void MSG_WriteShort (sizebuf_t *sb, int c);
void MSG_WriteLong (sizebuf_t *sb, int c);
void MSG_WriteFloat (sizebuf_t *sb, float f);
void MSG_WriteString (sizebuf_t *sb, char *s);
void MSG_WriteCoord (sizebuf_t *sb, float f);
void MSG_WriteBigCoord (sizebuf_t *sb, float f);
void MSG_WriteAngle (sizebuf_t *sb, float f);
void MSG_WriteAngle16 (sizebuf_t *sb, float f);
void MSG_WriteDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd);
void MSG_WriteDir (sizebuf_t *sb, float *dir);
extern int msg_readcount;
extern qboolean msg_badread; // set if a read goes beyond end of message
void MSG_BeginReading (void);
int MSG_GetReadCount(void);
int MSG_ReadChar (void);
int MSG_ReadByte (void);
int MSG_ReadShort (void);
int MSG_ReadLong (void);
float MSG_ReadFloat (void);
char *MSG_ReadString (void);
char *MSG_ReadStringLine (void);
float MSG_ReadCoord (void);
void MSG_ReadPos (float *pos);
float MSG_ReadAngle (void);
float MSG_ReadAngle16 (void);
void MSG_ReadDeltaUsercmd (struct usercmd_s *from, struct usercmd_s *cmd);
void MSGQ2_ReadDeltaUsercmd (struct usercmd_s *from, struct usercmd_s *move);
void MSG_ReadData (void *data, int len);
//============================================================================
char *Q_strcpyline(char *out, char *in, int maxlen); //stops at '\n' (and '\r')
#define Q_memset(d, f, c) memset((d), (f), (c))
#define Q_memcpy(d, s, c) memcpy((d), (s), (c))
#define Q_memcmp(m1, m2, c) memcmp((m1), (m2), (c))
#define Q_strcpy(d, s) strcpy((d), (s))
#define Q_strncpy(d, s, n) strncpy((d), (s), (n))
#define Q_strlen(s) ((int)strlen(s))
#define Q_strrchr(s, c) strrchr((s), (c))
#define Q_strcat(d, s) strcat((d), (s))
#define Q_strcmp(s1, s2) strcmp((s1), (s2))
#define Q_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
#define Q_strncpyS(d, s, n) do{const char *____in=(s);char *____out=(d);int ____i; for (____i=0;*(____in); ____i++){if (____i == (n))break;*____out++ = *____in++;}if (____i < (n))*____out='\0';}while(0) //only use this when it should be used. If undiciided, use N
#define Q_strncpyN(d, s, n) do{if (n < 0)Sys_Error("Bad length in strncpyz");Q_strncpyS((d), (s), (n));((char *)(d))[n] = '\0';}while(0) //this'll stop me doing buffer overflows. (guarenteed to overflow if you tried the wrong size.)
#define Q_strncpyNCHECKSIZE(d, s, n) do{if (n < 1)Sys_Error("Bad length in strncpyz");Q_strncpyS((d), (s), (n));((char *)(d))[n-1] = '\0';((char *)(d))[n] = '255';}while(0) //This forces nothing else to be within the buffer. Should be used for testing and nothing else.
#define Q_strncpyz(d, s, n) Q_strncpyN(d, s, (n)-1)
//#define Q_strncpy Please remove all strncpys
/*#ifndef strncpy
#define strncpy Q_strncpy
#endif*/
#ifdef _WIN32
#define Q_strcasecmp(s1, s2) _stricmp((s1), (s2))
#define Q_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n))
#else
#define Q_strcasecmp(s1, s2) strcasecmp((s1), (s2))
#define Q_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n))
#endif
int Q_atoi (char *str);
float Q_atof (char *str);
//============================================================================
extern char com_token[1024];
typedef enum {TTP_UNKNOWN, TTP_STRING} com_tokentype_t;
extern com_tokentype_t com_tokentype;
extern qboolean com_eof;
char *COM_Parse (char *data);
char *COM_ParseCString (char *data);
char *COM_StringParse (char *data);
char *COM_ParseToken (char *data);
char *COM_TrimString(char *str);
extern int com_argc;
extern char **com_argv;
int COM_CheckParm (char *parm);
void COM_AddParm (char *parm);
void COM_Init (void);
void COM_InitArgv (int argc, char **argv);
char *COM_SkipPath (char *pathname);
void COM_StripExtension (char *in, char *out);
void COM_FileBase (char *in, char *out);
void COM_DefaultExtension (char *path, char *extension);
char *COM_FileExtension (char *in);
char *VARGS va(char *format, ...);
// does a varargs printf into a temp buffer
//============================================================================
extern int com_filesize;
struct cache_user_s;
extern char com_gamedir[MAX_OSPATH];
void COM_WriteFile (char *filename, void *data, int len);
typedef struct {
struct searchpath_s *search;
int index;
char rawname[MAX_OSPATH];
int offset;
int len;
} flocation_t;
typedef enum {FSLFRT_LENGTH, FSLFRT_DEPTH_OSONLY, FSLFRT_DEPTH_ANYPATH} FSLF_ReturnType_e;
//if loc is valid, loc->search is always filled in, the others are filled on success.
//returns -1 if couldn't find.
int FS_FLocateFile(char *filename, FSLF_ReturnType_e returntype, flocation_t *loc);
int COM_FOpenFile (char *filename, FILE **file);
void COM_CloseFile (FILE *h);
#define COM_FDepthFile(filename,ignorepacks) FS_FLocateFile(filename,ignorepacks?FSLFRT_DEPTH_OSONLY:FSLFRT_DEPTH_ANYPATH, NULL)
#define COM_FCheckExists(filename) (FS_FLocateFile(filename,FSLFRT_LENGTH, NULL)>0)
int COM_filelength (FILE *f);
qbyte *COM_LoadStackFile (char *path, void *buffer, int bufsize);
qbyte *COM_LoadTempFile (char *path);
qbyte *COM_LoadTempFile2 (char *path); //allocates a little bit more without freeing old temp
qbyte *COM_LoadHunkFile (char *path);
qbyte *COM_LoadMallocFile (char *path);
void COM_LoadCacheFile (char *path, struct cache_user_s *cu);
void COM_CreatePath (char *path);
void COM_Gamedir (char *dir);
char *COM_NextPath (char *prevpath);
void COM_FlushFSCache(void); //a file was written using fopen
void COM_RefreshFSCache_f(void);
qboolean COM_LoadMapPackFile(char *name, int offset);
void COM_FlushTempoaryPacks(void);
void COM_EnumerateFiles (char *match, int (*func)(char *, int, void *), void *parm);
extern struct cvar_s registered;
extern qboolean standard_quake, rogue, hipnotic;
#define MAX_INFO_KEY 64
char *Info_ValueForKey (char *s, char *key);
void Info_RemoveKey (char *s, char *key);
void Info_RemovePrefixedKeys (char *start, char prefix);
void Info_RemoveNonStarKeys (char *start);
void Info_SetValueForKey (char *s, char *key, char *value, int maxsize);
void Info_SetValueForStarKey (char *s, char *key, char *value, int maxsize);
void Info_Print (char *s);
unsigned Com_BlockChecksum (void *buffer, int length);
void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf);
qbyte COM_BlockSequenceCheckByte (qbyte *base, int length, int sequence, unsigned mapchecksum);
qbyte COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence);
qbyte Q2COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence);
int build_number( void );
void TL_InitLanguages(void);
void T_FreeStrings(void);
char *T_GetString(int num);

93
engine/common/crc.c Normal file
View file

@ -0,0 +1,93 @@
/*
Copyright (C) 1996-1997 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.
*/
/* crc.c */
#include "quakedef.h"
#include "crc.h"
// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
// and the initial and final xor values shown below... in other words, the
// CCITT standard CRC used by XMODEM
#define CRC_INIT_VALUE 0xffff
#define CRC_XOR_VALUE 0x0000
static unsigned short crctable[256] =
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
void CRC_Init(unsigned short *crcvalue)
{
*crcvalue = CRC_INIT_VALUE;
}
void CRC_ProcessByte(unsigned short *crcvalue, qbyte data)
{
*crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
}
unsigned short CRC_Value(unsigned short crcvalue)
{
return crcvalue ^ CRC_XOR_VALUE;
}
unsigned short CRC_Block (qbyte *start, int count)
{
unsigned short crc;
CRC_Init (&crc);
while (count--)
crc = (crc << 8) ^ crctable[(crc >> 8) ^ *start++];
return crc;
}

25
engine/common/crc.h Normal file
View file

@ -0,0 +1,25 @@
/*
Copyright (C) 1996-1997 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.
*/
/* crc.h */
void CRC_Init(unsigned short *crcvalue);
void CRC_ProcessByte(unsigned short *crcvalue, qbyte data);
unsigned short CRC_Value(unsigned short crcvalue);
unsigned short CRC_Block (qbyte *start, int count);

647
engine/common/cvar.c Normal file
View file

@ -0,0 +1,647 @@
/*
Copyright (C) 1996-1997 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.
*/
// cvar.c -- dynamic variable tracking
#ifdef SERVERONLY
#include "qwsvdef.h"
#else
#include "quakedef.h"
#endif
cvar_group_t *cvar_groups;
//cvar_t *cvar_vars;
char *cvar_null_string = "";
/*
============
Cvar_FindVar
============
*/
cvar_t *Cvar_FindVar (char *var_name)
{
cvar_group_t *grp;
cvar_t *var;
for (grp=cvar_groups ; grp ; grp=grp->next)
for (var=grp->cvars ; var ; var=var->next)
if (!Q_strcasecmp (var_name, var->name))
return var;
for (grp=cvar_groups ; grp ; grp=grp->next)
for (var=grp->cvars ; var ; var=var->next)
if (var->name2 && !Q_strcasecmp (var_name, var->name2))
return var;
return NULL;
}
cvar_group_t *Cvar_FindGroup (char *group_name)
{
cvar_group_t *grp;
for (grp=cvar_groups ; grp ; grp=grp->next)
if (!Q_strcasecmp (group_name, grp->name))
return grp;
return NULL;
}
cvar_group_t *Cvar_GetGroup(char *gname)
{
cvar_group_t *g;
if (!gname)
gname = "Miscilaneous vars";
g = Cvar_FindGroup(gname);
if (g)
return g;
g = Z_Malloc(sizeof(cvar_group_t));
g->name = gname;
g->next = NULL;
g->next = cvar_groups;
cvar_groups = g;
return g;
}
//lists commands, also prints restriction level
void Cvar_List_f (void)
{
cvar_group_t *grp;
cvar_t *cmd;
int num=0;
for (grp=cvar_groups ; grp ; grp=grp->next)
for (cmd=grp->cvars ; cmd ; cmd=cmd->next)
{
if ((cmd->restriction?cmd->restriction:rcon_level.value) > Cmd_ExecLevel)
continue;
if (!num)
Con_TPrintf(TL_CVARLISTHEADER);
Con_Printf("(%2i) %s\n", (int)(cmd->restriction?cmd->restriction:rcon_level.value), cmd->name);
num++;
}
if (num)
Con_Printf("\n");
}
/*
============
Cvar_VariableValue
============
*/
float Cvar_VariableValue (char *var_name)
{
cvar_t *var;
var = Cvar_FindVar (var_name);
if (!var)
return 0;
return Q_atof (var->string);
}
/*
============
Cvar_VariableString
============
*/
char *Cvar_VariableString (char *var_name)
{
cvar_t *var;
var = Cvar_FindVar (var_name);
if (!var)
return cvar_null_string;
return var->string;
}
/*
============
Cvar_CompleteVariable
============
*/
/* moved to cmd_compleatevariable
char *Cvar_CompleteVariable (char *partial)
{
cvar_group_t *grp;
cvar_t *cvar;
int len;
len = Q_strlen(partial);
if (!len)
return NULL;
// check exact match
for (grp=cvar_groups ; grp ; grp=grp->next)
for (cvar=grp->cvars ; cvar ; cvar=cvar->next)
if (!strcmp (partial,cvar->name))
return cvar->name;
// check partial match
for (grp=cvar_groups ; grp ; grp=grp->next)
for (cvar=grp->cvars ; cvar ; cvar=cvar->next)
if (!Q_strncmp (partial,cvar->name, len))
return cvar->name;
return NULL;
}
*/
#ifdef SERVERONLY
void SV_SendServerInfoChange(char *key, char *value);
#endif
/*
============
Cvar_Set
============
*/
cvar_t *Cvar_SetCore (cvar_t *var, char *value, qboolean force)
{
char *latch=NULL;
if (!var)
return NULL;
if ((var->flags & CVAR_NOSET) && !force)
{
Con_Printf ("variable %s is readonly\n", var->name);
return NULL;
}
if (var->flags & CVAR_SERVEROVERRIDE && !force)
latch = "variable %s is under server control - latched\n";
else if (var->flags & CVAR_LATCH)
latch = "variable %s is latched\n";
else if (var->flags & CVAR_RENDERERLATCH && qrenderer)
latch = "variable %s will be changed after a renderer restart\n";
#ifndef SERVERONLY
else if (var->flags & CVAR_CHEAT && !cls.allow_cheats)
latch = "variable %s is a cheat variable - latched\n";
else if (var->flags & CVAR_SEMICHEAT && !cls.allow_semicheats)
latch = "variable %s is a cheat variable - latched\n";
#endif
if (latch && !force)
{
if (cl_warncmd.value)
Con_Printf (latch, var->name);
if (var->latched_string && !strcmp(var->latched_string, value)) //no point, this would force the same
return NULL;
if (var->latched_string)
Z_Free(var->latched_string);
if (!strcmp(var->string, value)) //latch to the origional value? remove the latch.
{
var->latched_string = NULL;
return NULL;
}
var->latched_string = Z_Malloc(strlen(value)+1);
strcpy(var->latched_string, value);
return NULL;
}
#ifndef CLIENTONLY
if (var->flags & CVAR_SERVERINFO)
{
Info_SetValueForKey (svs.info, var->name, value, MAX_SERVERINFO_STRING);
SV_SendServerInfoChange(var->name, value);
// SV_BroadcastCommand ("fullserverinfo \"%s\"\n", svs.info);
}
#endif
#ifndef SERVERONLY
if (var->flags & CVAR_USERINFO)
{
Info_SetValueForKey (cls.userinfo, var->name, value, MAX_INFO_STRING);
if (cls.state >= ca_connected)
{
#ifdef Q2CLIENT
if (cls.q2server) //q2 just resends the lot. Kinda bad...
{
cls.resendinfo = true;
}
else
#endif
{
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
SZ_Print (&cls.netchan.message, va("setinfo \"%s\" \"%s\"\n", var->name, value));
}
}
}
#endif
if (var->string)
{
if (strcmp(var->string, value))
var->modified++; //only modified if it changed.
Z_Free (var->string); // free the old value string
}
var->string = Z_Malloc (Q_strlen(value)+1);
Q_strcpy (var->string, value);
var->value = Q_atof (var->string);
if (var->latched_string) //we may as well have this here.
{
Z_Free(var->latched_string);
var->latched_string = NULL;
}
return var;
}
void Cvar_ForceCheatVars(qboolean semicheats, qboolean absolutecheats)
{ //this either unlatches if the cheat type is allowed, or enforces a default for full cheats and blank for semicheats.
//this is clientside only.
//if a value is enforced, it is latched to the old value.
cvar_group_t *grp;
cvar_t *var;
char *latch;
for (grp=cvar_groups ; grp ; grp=grp->next)
for (var=grp->cvars ; var ; var=var->next)
{
if (!(var->flags & (CVAR_CHEAT|CVAR_SEMICHEAT)))
continue;
latch = var->latched_string;
var->latched_string = NULL;
if (!latch)
{
latch = var->string;
var->string = NULL;
}
if (var->flags & CVAR_CHEAT)
{
if (!absolutecheats)
Cvar_ForceSet(var, var->defaultstr);
else
Cvar_ForceSet(var, latch);
}
if (var->flags & CVAR_SEMICHEAT)
{
if (!semicheats)
Cvar_ForceSet(var, "");
else
Cvar_ForceSet(var, latch);
}
if (latch)
{
if (!strcmp(var->string, latch))
Z_Free(latch);
else
var->latched_string = latch;
}
}
}
void Cvar_ApplyLatches(int latchflag)
{
cvar_group_t *grp;
cvar_t *var;
for (grp=cvar_groups ; grp ; grp=grp->next)
for (var=grp->cvars ; var ; var=var->next)
{
if (var->flags & latchflag)
{
if (var->latched_string)
{
var->flags &= ~CVAR_NOSET;
Cvar_ForceSet(var, var->latched_string);
}
}
}
}
cvar_t *Cvar_Set (cvar_t *var, char *value)
{
return Cvar_SetCore(var, value, false);
}
cvar_t *Cvar_ForceSet (cvar_t *var, char *value)
{
return Cvar_SetCore(var, value, true);
}
/*
============
Cvar_SetValue
============
*/
void Cvar_SetValue (cvar_t *var, float value)
{
char val[32];
if (value == (int)value)
sprintf (val, "%i",(int)value); //make it look nicer.
else
sprintf (val, "%f",value);
Cvar_Set (var, val);
}
/*
============
Cvar_RegisterVariable
Adds a freestanding variable to the variable list.
============
*/
void Cvar_Register (cvar_t *variable, char *groupname)
{
cvar_t *old;
cvar_group_t *group;
char value[512];
// first check to see if it has allready been defined
old = Cvar_FindVar (variable->name);
if (old)
{
if (old->flags & CVAR_POINTER)
{
cvar_t *prev;
group = Cvar_GetGroup(groupname);
variable->next = old->next;
variable->latched_string = old->latched_string;
variable->string = old->string;
variable->modified = old->modified;
variable->value = old->value;
//cheat prevention - engine set default is the one that stays.
Z_Free(variable->defaultstr);
variable->defaultstr = Z_Malloc (strlen(variable->string)+1); //give it it's default (for server controlled vars and things)
strcpy (variable->defaultstr, variable->string);
if (group->cvars == old)
group->cvars = variable;
else
{
for (prev = group->cvars; prev; prev++)
{
if (prev->next == old)
{
prev->next = variable;
break;
}
}
if (!prev) //this should never happen
Sys_Error("Cvar was not linked\n");
}
Z_Free(old);
return;
}
Con_Printf ("Can't register variable %s, allready defined\n", variable->name);
return;
}
// check for overlap with a command
if (Cmd_Exists (variable->name))
{
Con_Printf ("Cvar_RegisterVariable: %s is a command\n", variable->name);
return;
}
group = Cvar_GetGroup(groupname);
// link the variable in
variable->next = group->cvars;
variable->restriction = 0; //exe registered vars
group->cvars = variable;
// copy the value off, because future sets will Z_Free it
strcpy (value, variable->string);
variable->string = Z_Malloc (1);
variable->defaultstr = Z_Malloc (strlen(value)+1); //give it it's default (for server controlled vars and things)
strcpy (variable->defaultstr, value);
// set it through the function to be consistant
Cvar_SetCore (variable, value, true);
}
/*
void Cvar_RegisterVariable (cvar_t *variable)
{
Cvar_Register(variable, NULL);
}
*/
cvar_t *Cvar_Get(char *name, char *defaultvalue, int flags, char *group)
{
cvar_t *var;
var = Cvar_FindVar(name);
if (var)
{
//allow this to change all < cvar_latch values.
//this allows q2 dlls to apply different flags to a cvar without destroying our important ones (like cheat).
var->flags = (flags & (CVAR_LATCH-1)) | (var->flags & ~(CVAR_LATCH-1));
return var;
}
var = Z_Malloc(sizeof(cvar_t)+strlen(name)+1);
var->name = (char *)(var+1);
strcpy(var->name, name);
var->string = defaultvalue;
var->flags = flags|CVAR_POINTER;
Cvar_Register(var, group);
return var;
}
//prevent the client from altering the cvar until they change map or the server resets the var to the default.
void Cvar_LockFromServer(cvar_t *var, char *str)
{
char *oldlatch;
var->flags |= CVAR_SERVEROVERRIDE;
oldlatch = var->latched_string;
if (oldlatch) //maintaining control
var->latched_string = NULL;
else //taking control
{
oldlatch = Z_Malloc(strlen(var->string)+1);
strcpy(oldlatch, var->string);
}
Cvar_SetCore (var, str, true); //will use all, quote included
var->latched_string = oldlatch; //keep track of the origional value.
}
/*
============
Cvar_Command
Handles variable inspection and changing from the console
============
*/
qboolean Cvar_Command (int level)
{
cvar_t *v;
char *str;
// check variables
v = Cvar_FindVar (Cmd_Argv(0));
if (!v)
return false;
if ((v->restriction?v->restriction:rcon_level.value) > level)
{
Con_Printf ("You do not have the priveledges for %s\n", v->name);
return true;
}
if (v->flags & CVAR_NOTFROMSERVER && Cmd_FromServer())
{
Con_Printf ("Server tried setting %s cvar\n", v->name);
return true;
}
// perform a variable print or set
if (Cmd_Argc() == 1)
{
Con_Printf ("\"%s\" is \"%s\"\n", v->name, v->string);
if (v->latched_string)
Con_Printf ("Latched as \"%s\"\n", v->latched_string);
return true;
}
if (Cmd_Argc() == 2)
str = Cmd_Argv(1);
else
str = Cmd_Args();
if (v->flags & CVAR_NOSET)
{
Con_Printf ("Cvar %s may not be set via the console\n", v->name);
return true;
}
#ifndef SERVERONLY
if (Cmd_ExecLevel > RESTRICT_SERVER)
{ //directed at a secondary player.
char *msg;
msg = va("%i setinfo %s \"%s\"", Cmd_ExecLevel - RESTRICT_SERVER-1, v->name, str);
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
MSG_WriteString (&cls.netchan.message, msg);
return true;
}
if (v->flags & CVAR_SERVEROVERRIDE)
{
if (Cmd_FromServer())
{
if (!strcmp(v->defaultstr, str)) //returning to default
{
v->flags &= ~CVAR_SERVEROVERRIDE;
if (v->latched_string)
str = v->latched_string; //set to the latched
}
else
{
Cvar_LockFromServer(v, str);
return true;
}
}
//let cvar_set latch if needed.
}
else if (Cmd_FromServer())
{
Cvar_LockFromServer(v, str);
return true;
}
#endif
Cvar_Set (v, str); //will use all, quote included
return true;
}
/*
============
Cvar_WriteVariables
Writes lines containing "set variable value" for all variables
with the archive flag set to true.
============
*/
void Cvar_WriteVariables (FILE *f, qboolean all)
{
qboolean writtengroupheader;
cvar_group_t *grp;
cvar_t *var;
char *val;
for (grp=cvar_groups ; grp ; grp=grp->next)
{
writtengroupheader = false;
for (var = grp->cvars ; var ; var = var->next)
if (var->flags & CVAR_ARCHIVE || all)
{
if (!writtengroupheader)
{
writtengroupheader = true;
fprintf(f, "\n// %s\n", grp->name);
}
val = var->string; //latched vars should act differently.
if (var->latched_string)
val = var->latched_string;
if (var->flags & CVAR_USERCREATED)
{
if (var->flags & CVAR_ARCHIVE)
fprintf (f, "seta %s \"%s\"\n", var->name, val);
else
fprintf (f, "set %s \"%s\"\n", var->name, val);
}
else
fprintf (f, "%s \"%s\"\n", var->name, val);
}
}
}
void Cvar_Shutdown(void)
{
cvar_t *var;
cvar_group_t *grp;
while(cvar_groups)
{
while(cvar_groups->cvars)
{
var = cvar_groups->cvars;
cvar_groups->cvars = var->next;
Z_Free(var->string);
if (var->flags & CVAR_POINTER)
Z_Free(var);
}
grp = cvar_groups;
cvar_groups = grp->next;
Z_Free(grp);
}
}

145
engine/common/cvar.h Normal file
View file

@ -0,0 +1,145 @@
/*
Copyright (C) 1996-1997 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.
*/
// cvar.h
/*
cvar_t variables are used to hold scalar or string variables that can be changed or displayed at the console or prog code as well as accessed directly
in C code.
it is sufficient to initialize a cvar_t with just the first two fields, or
you can add a ,true flag for variables that you want saved to the configuration
file when the game is quit:
cvar_t r_draworder = {"r_draworder","1"};
cvar_t scr_screensize = {"screensize","1",true};
Cvars must be registered before use, or they will have a 0 value instead of the float interpretation of the string. Generally, all cvar_t declarations should be registered in the apropriate init function before any console commands are executed:
Cvar_RegisterVariable (&host_framerate);
C code usually just references a cvar in place:
if ( r_draworder.value )
It could optionally ask for the value to be looked up for a string name:
if (Cvar_VariableValue ("r_draworder"))
Interpreted prog code can access cvars with the cvar(name) or
cvar_set (name, value) internal functions:
teamplay = cvar("teamplay");
cvar_set ("registered", "1");
The user can access cvars from the console in two ways:
r_draworder prints the current value
r_draworder 0 sets the current value to 0
Cvars are restricted from having the same names as commands to keep this
interface from being ambiguous.
*/
typedef struct cvar_s
{
//must match q2's definition
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;
//free style :)
char *name2;
char *defaultstr; //default
qbyte restriction;
} cvar_t;
typedef struct cvar_group_s
{
char *name;
struct cvar_group_s *next;
cvar_t *cvars;
} cvar_group_t;
//q2 constants
#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
//freestyle
#define CVAR_POINTER 32 // q2 style. May be converted to q1 if needed. These are often specified on the command line and then converted into q1 when registered properly.
#define CVAR_NOTFROMSERVER 64
#define CVAR_USERCREATED 128 //write a 'set' or 'seta' in front of the var name.
#define CVAR_CHEAT 256 //latch from 0 unless cheats are enabled.
#define CVAR_SEMICHEAT 512 //if strict ruleset, force to 0.
#define CVAR_RENDERERLATCH 1024
#define CVAR_SERVEROVERRIDE 2048 //
#define CVAR_LATCHMASK (CVAR_LATCH|CVAR_RENDERERLATCH|CVAR_SERVEROVERRIDE|CVAR_CHEAT|CVAR_SEMICHEAT) //you're only allowed one of these.
#define CVAR_NEEDDEFAULT CVAR_CHEAT
cvar_t *Cvar_Get (char *var_name, char *value, int flags, char *groupname);
void Cvar_Register (cvar_t *variable, char *cvargroup);
// registers a cvar that allready has the name, string, and optionally the
// archive elements set.
//#define Cvar_RegisterVariable(x) Cvar_Register(x,__FILE__);
cvar_t *Cvar_ForceSet (cvar_t *var, char *value);
cvar_t *Cvar_Set (cvar_t *var, char *value);
// equivelant to "<name> <variable>" typed at the console
void Cvar_SetValue (cvar_t *var, float value);
// expands value to a string and calls Cvar_Set
void Cvar_ApplyLatches(int latchflag);
//sets vars to thier latched values
float Cvar_VariableValue (char *var_name);
// returns 0 if not defined or non numeric
char *Cvar_VariableString (char *var_name);
// returns an empty string if not defined
char *Cvar_CompleteVariable (char *partial);
// attempts to match a partial variable name for command line completion
// returns NULL if nothing fits
qboolean Cvar_Command (int level);
// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known
// command. Returns true if the command was a variable reference that
// was handled. (print or change)
void Cvar_WriteVariables (FILE *f, qboolean all);
// Writes lines containing "set variable value" for all variables
// with the archive flag set to true.
cvar_t *Cvar_FindVar (char *var_name);
void Cvar_Shutdown(void);
void Cvar_ForceCheatVars(qboolean semicheats, qboolean absolutecheats); //locks/unlocks cheat cvars depending on weather we are allowed them.
//extern cvar_t *cvar_vars;

4937
engine/common/gl_q2bsp.c Normal file

File diff suppressed because it is too large Load diff

812
engine/common/huff.c Normal file
View file

@ -0,0 +1,812 @@
/*
Q3Fusion - Quake III Clone Engine
Copyright (C) 2003 Andrey Nazarov
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.
*/
//
// huff.c - Huffman compression routines for data bitstream
//
#include "bothdefs.h"
#ifdef HUFFNETWORK
#include "quakedef.h"
#define ID_INLINE
#define VALUE(a) ((int )(a))
#define NODE(a) ((void *)(a))
#define NODE_START NODE( 1)
#define NODE_NONE NODE(256)
#define NODE_NEXT NODE(257)
#define NOT_REFERENCED 256
#define HUFF_TREE_SIZE 7175
typedef void *tree_t[HUFF_TREE_SIZE];
//
// pre-defined frequency counts for all bytes [0..255]
//
static int q3huffCounts[256] = {
0x3D1CB, 0x0A0E9, 0x01894, 0x01BC2, 0x00E92, 0x00EA6, 0x017DE, 0x05AF3,
0x08225, 0x01B26, 0x01E9E, 0x025F2, 0x02429, 0x0436B, 0x00F6D, 0x006F2,
0x02060, 0x00644, 0x00636, 0x0067F, 0x0044C, 0x004BD, 0x004D6, 0x0046E,
0x006D5, 0x00423, 0x004DE, 0x0047D, 0x004F9, 0x01186, 0x00AF5, 0x00D90,
0x0553B, 0x00487, 0x00686, 0x0042A, 0x00413, 0x003F4, 0x0041D, 0x0042E,
0x006BE, 0x00378, 0x0049C, 0x00352, 0x003C0, 0x0030C, 0x006D8, 0x00CE0,
0x02986, 0x011A2, 0x016F9, 0x00A7D, 0x0122A, 0x00EFD, 0x0082D, 0x0074B,
0x00A18, 0x0079D, 0x007B4, 0x003AC, 0x0046E, 0x006FC, 0x00686, 0x004B6,
0x01657, 0x017F0, 0x01C36, 0x019FE, 0x00E7E, 0x00ED3, 0x005D4, 0x005F4,
0x008A7, 0x00474, 0x0054B, 0x003CB, 0x00884, 0x004E0, 0x00530, 0x004AB,
0x006EA, 0x00436, 0x004F0, 0x004F2, 0x00490, 0x003C5, 0x00483, 0x004A2,
0x00543, 0x004CC, 0x005F9, 0x00640, 0x00A39, 0x00800, 0x009F2, 0x00CCB,
0x0096A, 0x00E01, 0x009C8, 0x00AF0, 0x00A73, 0x01802, 0x00E4F, 0x00B18,
0x037AD, 0x00C5C, 0x008AD, 0x00697, 0x00C88, 0x00AB3, 0x00DB8, 0x012BC,
0x00FFB, 0x00DBB, 0x014A8, 0x00FB0, 0x01F01, 0x0178F, 0x014F0, 0x00F54,
0x0131C, 0x00E9F, 0x011D6, 0x012C7, 0x016DC, 0x01900, 0x01851, 0x02063,
0x05ACB, 0x01E9E, 0x01BA1, 0x022E7, 0x0153D, 0x01183, 0x00E39, 0x01488,
0x014C0, 0x014D0, 0x014FA, 0x00DA4, 0x0099A, 0x0069E, 0x0071D, 0x00849,
0x0077C, 0x0047D, 0x005EC, 0x00557, 0x004D4, 0x00405, 0x004EA, 0x00450,
0x004DD, 0x003EE, 0x0047D, 0x00401, 0x004D9, 0x003B8, 0x00507, 0x003E5,
0x006B1, 0x003F1, 0x004A3, 0x0036F, 0x0044B, 0x003A1, 0x00436, 0x003B7,
0x00678, 0x003A2, 0x00481, 0x00406, 0x004EE, 0x00426, 0x004BE, 0x00424,
0x00655, 0x003A2, 0x00452, 0x00390, 0x0040A, 0x0037C, 0x00486, 0x003DE,
0x00497, 0x00352, 0x00461, 0x00387, 0x0043F, 0x00398, 0x00478, 0x00420,
0x00D86, 0x008C0, 0x0112D, 0x02F68, 0x01E4E, 0x00541, 0x0051B, 0x00CCE,
0x0079E, 0x00376, 0x003FF, 0x00458, 0x00435, 0x00412, 0x00425, 0x0042F,
0x005CC, 0x003E9, 0x00448, 0x00393, 0x0041C, 0x003E3, 0x0042E, 0x0036C,
0x00457, 0x00353, 0x00423, 0x00325, 0x00458, 0x0039B, 0x0044F, 0x00331,
0x0076B, 0x00750, 0x003D0, 0x00349, 0x00467, 0x003BC, 0x00487, 0x003B6,
0x01E6F, 0x003BA, 0x00509, 0x003A5, 0x00467, 0x00C87, 0x003FC, 0x0039F,
0x0054B, 0x00300, 0x00410, 0x002E9, 0x003B8, 0x00325, 0x00431, 0x002E4,
0x003F5, 0x00325, 0x003F0, 0x0031C, 0x003E4, 0x00421, 0x02CC1, 0x034C0
};
static int countinghuffCounts[256];
//
// static Huffman tree
//
static tree_t huffTree;
//
// received from MSG_* code
//
static int huffBitPos;
/*
=======================================================================================
HUFFMAN TREE CONSTRUCTION
=======================================================================================
*/
/*
============
Huff_PrepareTree
============
*/
static ID_INLINE void Huff_PrepareTree( tree_t tree ) {
void **node;
memset( tree, 0, sizeof( tree_t ) );
// create first node
node = &tree[263];
VALUE( tree[0] )++;
node[7] = NODE_NONE;
tree[2] = node;
tree[3] = node;
tree[4] = node;
tree[261] = node;
}
/*
============
Huff_GetNode
============
*/
static ID_INLINE void **Huff_GetNode( void **tree ) {
void **node;
int value;
node = tree[262];
if( !node ) {
value = VALUE( tree[1] )++;
node = &tree[value + 6407];
return node;
}
tree[262] = node[0];
return node;
}
/*
============
Huff_Swap
============
*/
static ID_INLINE void Huff_Swap( void **tree1, void **tree2, void **tree3 ) {
void **a, **b;
a = tree2[2];
if( a ) {
if( a[0] == tree2 ) {
a[0] = tree3;
} else {
a[1] = tree3;
}
} else {
tree1[2] = tree3;
}
b = tree3[2];
if( b ) {
if( b[0] == tree3 ) {
b[0] = tree2;
tree2[2] = b;
tree3[2] = a;
return;
}
b[1] = tree2;
tree2[2] = b;
tree3[2] = a;
return;
}
tree1[2] = tree2;
tree2[2] = NULL;
tree3[2] = a;
}
/*
============
Huff_SwapTrees
============
*/
static ID_INLINE void Huff_SwapTrees( void **tree1, void **tree2 ) {
void **temp;
temp = tree1[3];
tree1[3] = tree2[3];
tree2[3] = temp;
temp = tree1[4];
tree1[4] = tree2[4];
tree2[4] = temp;
if( tree1[3] == tree1 ) {
tree1[3] = tree2;
}
if( tree2[3] == tree2 ) {
tree2[3] = tree1;
}
temp = tree1[3];
if( temp ) {
temp[4] = tree1;
}
temp = tree2[3];
if( temp ) {
temp[4] = tree2;
}
temp = tree1[4];
if( temp ) {
temp[3] = tree1;
}
temp = tree2[4];
if( temp ) {
temp[3] = tree2;
}
}
/*
============
Huff_DeleteNode
============
*/
static ID_INLINE void Huff_DeleteNode( void **tree1, void **tree2 ) {
tree2[0] = tree1[262];
tree1[262] = tree2;
}
/*
============
Huff_IncrementFreq_r
============
*/
static void Huff_IncrementFreq_r( void **tree1, void **tree2 ) {
void **a, **b;
if( !tree2 ) {
return;
}
a = tree2[3];
if( a ) {
a = a[6];
if( a == tree2[6] ) {
b = tree2[5];
if( b[0] != tree2[2] ) {
Huff_Swap( tree1, b[0], tree2 );
}
Huff_SwapTrees( b[0], tree2 );
}
}
a = tree2[4];
if( a && a[6] == tree2[6] ) {
b = tree2[5];
b[0] = a;
} else {
a = tree2[5];
a[0] = 0;
Huff_DeleteNode( tree1, tree2[5] );
}
VALUE( tree2[6] )++;
a = tree2[3];
if( a && a[6] == tree2[6] ) {
tree2[5] = a[5];
} else {
a = Huff_GetNode( tree1 );
tree2[5] = a;
a[0] = tree2;
}
if( tree2[2] ) {
Huff_IncrementFreq_r( tree1, tree2[2] );
if( tree2[4] == tree2[2] ) {
Huff_SwapTrees( tree2, tree2[2] );
a = tree2[5];
if( a[0] == tree2 ) {
a[0] = tree2[2];
}
}
}
}
/*
============
Huff_AddReference
Insert 'ch' into the tree or increment it's frequency
============
*/
static void Huff_AddReference( void **tree, int ch ) {
void **a, **b, **c, **d;
int value;
ch &= 255;
if( tree[ch + 5] ) {
Huff_IncrementFreq_r( tree, tree[ch + 5] );
return; // already added
}
value = VALUE( tree[0] )++;
b = &tree[value * 8 + 263];
value = VALUE( tree[0] )++;
a = &tree[value * 8 + 263];
a[7] = NODE_NEXT;
a[6] = NODE_START;
d = tree[3];
a[3] = d[3];
if( a[3] ) {
d = a[3];
d[4] = a;
d = a[3];
if( d[6] == NODE_START ) {
a[5] = d[5];
} else {
d = Huff_GetNode( tree );
a[5] = d;
d[0] = a;
}
} else {
d = Huff_GetNode( tree );
a[5] = d;
d[0] = a;
}
d = tree[3];
d[3] = a;
a[4] = tree[3];
b[7] = NODE( ch );
b[6] = NODE_START;
d = tree[3];
b[3] = d[3];
if( b[3] ) {
d = b[3];
d[4] = b;
if( d[6] == NODE_START ) {
b[5] = d[5];
} else {
d = Huff_GetNode( tree );
b[5] = d;
d[0] = a;
}
} else {
d = Huff_GetNode( tree );
b[5] = d;
d[0] = b;
}
d = tree[3];
d[3] = b;
b[4] = tree[3];
b[1] = NULL;
b[0] = NULL;
d = tree[3];
c = d[2];
if( c ) {
if( c[0] == tree[3] ) {
c[0] = a;
} else {
c[1] = a;
}
} else {
tree[2] = a;
}
a[1] = b;
d = tree[3];
a[0] = d;
a[2] = d[2];
b[2] = a;
d = tree[3];
d[2] = a;
tree[ch + 5] = b;
Huff_IncrementFreq_r( tree, a[2] );
}
/*
=======================================================================================
BITSTREAM I/O
=======================================================================================
*/
/*
============
Huff_EmitBit
Put one bit into buffer
============
*/
static ID_INLINE void Huff_EmitBit( int bit, qbyte *buffer ) {
if( !(huffBitPos & 7) ) {
buffer[huffBitPos >> 3] = 0;
}
buffer[huffBitPos >> 3] |= bit << (huffBitPos & 7);
huffBitPos++;
}
/*
============
Huff_GetBit
Read one bit from buffer
============
*/
static ID_INLINE int Huff_GetBit( qbyte *buffer ) {
int bit;
bit = buffer[huffBitPos >> 3] >> (huffBitPos & 7);
huffBitPos++;
return (bit & 1);
}
/*
============
Huff_EmitPathToByte
============
*/
static ID_INLINE void Huff_EmitPathToByte( void **tree, void **subtree, qbyte *buffer ) {
if( tree[2] ) {
Huff_EmitPathToByte( tree[2], tree, buffer );
}
if( !subtree ) {
return;
}
//
// emit tree walking control bits
//
if( tree[1] == subtree ) {
Huff_EmitBit( 1, buffer );
} else {
Huff_EmitBit( 0, buffer );
}
}
/*
============
Huff_GetByteFromTree
Get one qbyte using dynamic or static tree
============
*/
static ID_INLINE int Huff_GetByteFromTree( void **tree, qbyte *buffer ) {
if( !tree ) {
return 0;
}
//
// walk through the tree until we get a value
//
while( tree[7] == NODE_NEXT ) {
if( !Huff_GetBit( buffer ) ) {
tree = tree[0];
} else {
tree = tree[1];
}
if( !tree ) {
return 0;
}
}
return VALUE( tree[7] );
}
/*
============
Huff_EmitByteDynamic
Emit one qbyte using dynamic tree
============
*/
static void Huff_EmitByteDynamic( void **tree, int value, qbyte *buffer ) {
void **subtree;
int i;
//
// if qbyte was already referenced, emit path to it
//
subtree = tree[value + 5];
if( subtree ) {
if( subtree[2] ) {
Huff_EmitPathToByte( subtree[2], subtree, buffer );
}
return;
}
//
// qbyte was not referenced, just emit 8 bits
//
Huff_EmitByteDynamic( tree, NOT_REFERENCED, buffer );
for( i=7 ; i>=0 ; i-- ) {
Huff_EmitBit( (value >> i) & 1, buffer );
}
}
/*
=======================================================================================
PUBLIC INTERFACE
=======================================================================================
*/
/*
============
Huff_CompressPacket
Compress message using dynamic Huffman tree,
beginning from specified offset
============
*/
void Huff_EncryptPacket( sizebuf_t *msg, int offset ) {
tree_t tree;
qbyte buffer[MAX_NQMSGLEN];
qbyte *data;
int outLen;
int inLen;
int i;
data = msg->data + offset;
inLen = msg->cursize - offset;
if( inLen <= 0 || inLen >= MAX_NQMSGLEN ) {
return;
}
Huff_PrepareTree( tree );
buffer[0] = inLen >> 8;
buffer[1] = inLen & 0xFF;
huffBitPos = 16;
for( i=0 ; i<inLen ; i++ ) {
Huff_EmitByteDynamic( tree, data[i], buffer );
Huff_AddReference( tree, data[i] );
}
outLen = (huffBitPos >> 3) + 1;
msg->cursize = offset + outLen;
memcpy( data, buffer, outLen );
}
/*
============
Huff_DecompressPacket
Decompress message using dynamic Huffman tree,
beginning from specified offset
============
*/
void Huff_DecryptPacket( sizebuf_t *msg, int offset ) {
tree_t tree;
qbyte buffer[MAX_NQMSGLEN];
qbyte *data;
int outLen;
int inLen;
int i, j;
int ch;
data = msg->data + offset;
inLen = msg->cursize - offset;
if( inLen <= 0 ) {
return;
}
Huff_PrepareTree( tree );
outLen = (data[0] << 8) + data[1];
huffBitPos = 16;
if( outLen > msg->maxsize - offset ) {
outLen = msg->maxsize - offset;
}
for( i=0 ; i<outLen ; i++ ) {
if( (huffBitPos >> 3) > inLen ) {
buffer[i] = 0;
break;
}
ch = Huff_GetByteFromTree( tree[2], data );
if( ch == NOT_REFERENCED ) {
ch = 0; // just read 8 bits
for( j=0 ; j<8 ; j++ ) {
ch <<= 1;
ch |= Huff_GetBit( data );
}
}
buffer[i] = ch;
Huff_AddReference( tree, ch );
}
msg->cursize = offset + outLen;
memcpy( data, buffer, outLen );
}
/*
============
Huff_EmitByte
============
*/
void Huff_EmitByte( int ch, qbyte *buffer, int *count ) {
huffBitPos = *count;
Huff_EmitPathToByte( huffTree[ch + 5], NULL, buffer );
*count = huffBitPos;
}
/*
============
Huff_GetByte
============
*/
int Huff_GetByte( qbyte *buffer, int *count ) {
int ch;
huffBitPos = *count;
ch = Huff_GetByteFromTree( huffTree[2], buffer );
*count = huffBitPos;
return ch;
}
static int madetable;
/*
============
Huff_Init
============
*/
void Huff_Init( int *huffCounts ) {
int i, j;
if (!huffCounts)
huffCounts = q3huffCounts;
// build empty tree
Huff_PrepareTree( huffTree );
// add all pre-defined qbyte references
for( i=0 ; i<256 ; i++ ) {
for( j=0 ; j<huffCounts[i] ; j++ ) {
Huff_AddReference( huffTree, i );
}
}
madetable=Com_BlockChecksum(huffCounts, sizeof(huffCounts));
}
void Huff_LoadTable(char *filename)
{
}
int Huff_PreferedCompressionCRC (void)
{
if (!madetable)
Huff_Init(NULL);
return madetable;
}
qboolean Huff_CompressionCRC(int crc)
{
if (!madetable)
Huff_Init(NULL);
if (crc != madetable)
return false;
return true;
}
/*
============
Huff_CompressPacket
Compress message using loaded Huffman tree,
beginning from specified offset
============
*/
void Huff_CompressPacket( sizebuf_t *msg, int offset )
{
qbyte buffer[MAX_NQMSGLEN];
qbyte *data;
int outLen;
int inLen;
int i;
if (!madetable)
Huff_Init(NULL);
data = msg->data + offset;
inLen = msg->cursize - offset;
if( inLen <= 0 || inLen >= MAX_NQMSGLEN ) {
return;
}
outLen = 0;
for( i=0 ; i<inLen ; i++ )
{
if (i == MAX_NQMSGLEN)
Sys_Error("Compression became too large\n");
Huff_EmitByte(data[i], buffer, &outLen);
countinghuffCounts[data[i]]++;
}
outLen = (huffBitPos >> 3) + 1;
if (outLen > inLen)
{
memmove( data+1, data, inLen );
data[0] = 0x80; //this would have grown the packet.
msg->cursize+=1;
return; //cap it at only 1 qbyte growth.
}
msg->cursize = offset + outLen;
{ //add the bitcount
data[0] = (outLen<<3) - huffBitPos;
data+=1;
msg->cursize+=1;
}
if (msg->cursize > msg->maxsize)
Sys_Error("Compression became too large\n");
memcpy( data, buffer, outLen );
}
/*
============
Huff_DecompressPacket
Decompress message using loaded Huffman tree,
beginning from specified offset
============
*/
void Huff_DecompressPacket( sizebuf_t *msg, int offset )
{
qbyte buffer[MAX_NQMSGLEN];
qbyte *data;
int outLen;
int inLen;
int i;
if (!madetable)
Huff_Init(NULL);
data = msg->data + offset;
inLen = msg->cursize - offset;
if( inLen <= 0 || inLen >= MAX_NQMSGLEN ) {
return;
}
inLen<<=3;
{ //add the bitcount
inLen = inLen-8-data[0];
if (data[0]&0x80)
{ //packet would have grown.
msg->cursize -= 1;
memmove(data, data+1, msg->cursize);
return; //this never happened, okay?
}
data+=1;
}
outLen = 0;
for( i=0 ; outLen<inLen ; i++ )
{
if (i == MAX_NQMSGLEN)
Sys_Error("Decompression became too large\n");
buffer[i] = Huff_GetByte(data, &outLen);
}
msg->cursize = offset + i;
if (msg->cursize > msg->maxsize)
Sys_Error("Decompression became too large\n");
memcpy( msg->data + offset, buffer, i );
}
#endif

417
engine/common/math.s Normal file
View file

@ -0,0 +1,417 @@
/*
Copyright (C) 1996-1997 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.
*/
//
// math.s
// x86 assembly-language math routines.
#include "asm_i386.h"
#include "quakeasm.h"
#if id386
.data
.align 4
Ljmptab: .long Lcase0, Lcase1, Lcase2, Lcase3
.long Lcase4, Lcase5, Lcase6, Lcase7
.text
// TODO: rounding needed?
// stack parameter offset
#define val 4
.globl C(Invert24To16)
C(Invert24To16):
movl val(%esp),%ecx
movl $0x100,%edx // 0x10000000000 as dividend
cmpl %edx,%ecx
jle LOutOfRange
subl %eax,%eax
divl %ecx
ret
LOutOfRange:
movl $0xFFFFFFFF,%eax
ret
#define in 4
#define out 8
#ifndef SERVERONLY
.align 2
.globl C(TransformVector)
C(TransformVector):
movl in(%esp),%eax
movl out(%esp),%edx
flds (%eax) // in[0]
fmuls C(vright) // in[0]*vright[0]
flds (%eax) // in[0] | in[0]*vright[0]
fmuls C(vup) // in[0]*vup[0] | in[0]*vright[0]
flds (%eax) // in[0] | in[0]*vup[0] | in[0]*vright[0]
fmuls C(vpn) // in[0]*vpn[0] | in[0]*vup[0] | in[0]*vright[0]
flds 4(%eax) // in[1] | ...
fmuls C(vright)+4 // in[1]*vright[1] | ...
flds 4(%eax) // in[1] | in[1]*vright[1] | ...
fmuls C(vup)+4 // in[1]*vup[1] | in[1]*vright[1] | ...
flds 4(%eax) // in[1] | in[1]*vup[1] | in[1]*vright[1] | ...
fmuls C(vpn)+4 // in[1]*vpn[1] | in[1]*vup[1] | in[1]*vright[1] | ...
fxch %st(2) // in[1]*vright[1] | in[1]*vup[1] | in[1]*vpn[1] | ...
faddp %st(0),%st(5) // in[1]*vup[1] | in[1]*vpn[1] | ...
faddp %st(0),%st(3) // in[1]*vpn[1] | ...
faddp %st(0),%st(1) // vpn_accum | vup_accum | vright_accum
flds 8(%eax) // in[2] | ...
fmuls C(vright)+8 // in[2]*vright[2] | ...
flds 8(%eax) // in[2] | in[2]*vright[2] | ...
fmuls C(vup)+8 // in[2]*vup[2] | in[2]*vright[2] | ...
flds 8(%eax) // in[2] | in[2]*vup[2] | in[2]*vright[2] | ...
fmuls C(vpn)+8 // in[2]*vpn[2] | in[2]*vup[2] | in[2]*vright[2] | ...
fxch %st(2) // in[2]*vright[2] | in[2]*vup[2] | in[2]*vpn[2] | ...
faddp %st(0),%st(5) // in[2]*vup[2] | in[2]*vpn[2] | ...
faddp %st(0),%st(3) // in[2]*vpn[2] | ...
faddp %st(0),%st(1) // vpn_accum | vup_accum | vright_accum
fstps 8(%edx) // out[2]
fstps 4(%edx) // out[1]
fstps (%edx) // out[0]
ret
#endif
#define EMINS 4+4
#define EMAXS 4+8
#define P 4+12
.align 2
.globl C(BoxOnPlaneSide)
C(BoxOnPlaneSide):
pushl %ebx
movl P(%esp),%edx
movl EMINS(%esp),%ecx
xorl %eax,%eax
movl EMAXS(%esp),%ebx
movb pl_signbits(%edx),%al
cmpb $8,%al
jge Lerror
flds pl_normal(%edx) // p->normal[0]
fld %st(0) // p->normal[0] | p->normal[0]
jmp Ljmptab(,%eax,4)
//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
//dist2= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
Lcase0:
fmuls (%ebx) // p->normal[0]*emaxs[0] | p->normal[0]
flds pl_normal+4(%edx) // p->normal[1] | p->normal[0]*emaxs[0] |
// p->normal[0]
fxch %st(2) // p->normal[0] | p->normal[0]*emaxs[0] |
// p->normal[1]
fmuls (%ecx) // p->normal[0]*emins[0] |
// p->normal[0]*emaxs[0] | p->normal[1]
fxch %st(2) // p->normal[1] | p->normal[0]*emaxs[0] |
// p->normal[0]*emins[0]
fld %st(0) // p->normal[1] | p->normal[1] |
// p->normal[0]*emaxs[0] |
// p->normal[0]*emins[0]
fmuls 4(%ebx) // p->normal[1]*emaxs[1] | p->normal[1] |
// p->normal[0]*emaxs[0] |
// p->normal[0]*emins[0]
flds pl_normal+8(%edx) // p->normal[2] | p->normal[1]*emaxs[1] |
// p->normal[1] | p->normal[0]*emaxs[0] |
// p->normal[0]*emins[0]
fxch %st(2) // p->normal[1] | p->normal[1]*emaxs[1] |
// p->normal[2] | p->normal[0]*emaxs[0] |
// p->normal[0]*emins[0]
fmuls 4(%ecx) // p->normal[1]*emins[1] |
// p->normal[1]*emaxs[1] |
// p->normal[2] | p->normal[0]*emaxs[0] |
// p->normal[0]*emins[0]
fxch %st(2) // p->normal[2] | p->normal[1]*emaxs[1] |
// p->normal[1]*emins[1] |
// p->normal[0]*emaxs[0] |
// p->normal[0]*emins[0]
fld %st(0) // p->normal[2] | p->normal[2] |
// p->normal[1]*emaxs[1] |
// p->normal[1]*emins[1] |
// p->normal[0]*emaxs[0] |
// p->normal[0]*emins[0]
fmuls 8(%ebx) // p->normal[2]*emaxs[2] |
// p->normal[2] |
// p->normal[1]*emaxs[1] |
// p->normal[1]*emins[1] |
// p->normal[0]*emaxs[0] |
// p->normal[0]*emins[0]
fxch %st(5) // p->normal[0]*emins[0] |
// p->normal[2] |
// p->normal[1]*emaxs[1] |
// p->normal[1]*emins[1] |
// p->normal[0]*emaxs[0] |
// p->normal[2]*emaxs[2]
faddp %st(0),%st(3) //p->normal[2] |
// p->normal[1]*emaxs[1] |
// p->normal[1]*emins[1]+p->normal[0]*emins[0]|
// p->normal[0]*emaxs[0] |
// p->normal[2]*emaxs[2]
fmuls 8(%ecx) //p->normal[2]*emins[2] |
// p->normal[1]*emaxs[1] |
// p->normal[1]*emins[1]+p->normal[0]*emins[0]|
// p->normal[0]*emaxs[0] |
// p->normal[2]*emaxs[2]
fxch %st(1) //p->normal[1]*emaxs[1] |
// p->normal[2]*emins[2] |
// p->normal[1]*emins[1]+p->normal[0]*emins[0]|
// p->normal[0]*emaxs[0] |
// p->normal[2]*emaxs[2]
faddp %st(0),%st(3) //p->normal[2]*emins[2] |
// p->normal[1]*emins[1]+p->normal[0]*emins[0]|
// p->normal[0]*emaxs[0]+p->normal[1]*emaxs[1]|
// p->normal[2]*emaxs[2]
fxch %st(3) //p->normal[2]*emaxs[2] +
// p->normal[1]*emins[1]+p->normal[0]*emins[0]|
// p->normal[0]*emaxs[0]+p->normal[1]*emaxs[1]|
// p->normal[2]*emins[2]
faddp %st(0),%st(2) //p->normal[1]*emins[1]+p->normal[0]*emins[0]|
// dist1 | p->normal[2]*emins[2]
jmp LSetSides
//dist1= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
Lcase1:
fmuls (%ecx) // emins[0]
flds pl_normal+4(%edx)
fxch %st(2)
fmuls (%ebx) // emaxs[0]
fxch %st(2)
fld %st(0)
fmuls 4(%ebx) // emaxs[1]
flds pl_normal+8(%edx)
fxch %st(2)
fmuls 4(%ecx) // emins[1]
fxch %st(2)
fld %st(0)
fmuls 8(%ebx) // emaxs[2]
fxch %st(5)
faddp %st(0),%st(3)
fmuls 8(%ecx) // emins[2]
fxch %st(1)
faddp %st(0),%st(3)
fxch %st(3)
faddp %st(0),%st(2)
jmp LSetSides
//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
//dist2= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
Lcase2:
fmuls (%ebx) // emaxs[0]
flds pl_normal+4(%edx)
fxch %st(2)
fmuls (%ecx) // emins[0]
fxch %st(2)
fld %st(0)
fmuls 4(%ecx) // emins[1]
flds pl_normal+8(%edx)
fxch %st(2)
fmuls 4(%ebx) // emaxs[1]
fxch %st(2)
fld %st(0)
fmuls 8(%ebx) // emaxs[2]
fxch %st(5)
faddp %st(0),%st(3)
fmuls 8(%ecx) // emins[2]
fxch %st(1)
faddp %st(0),%st(3)
fxch %st(3)
faddp %st(0),%st(2)
jmp LSetSides
//dist1= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
Lcase3:
fmuls (%ecx) // emins[0]
flds pl_normal+4(%edx)
fxch %st(2)
fmuls (%ebx) // emaxs[0]
fxch %st(2)
fld %st(0)
fmuls 4(%ecx) // emins[1]
flds pl_normal+8(%edx)
fxch %st(2)
fmuls 4(%ebx) // emaxs[1]
fxch %st(2)
fld %st(0)
fmuls 8(%ebx) // emaxs[2]
fxch %st(5)
faddp %st(0),%st(3)
fmuls 8(%ecx) // emins[2]
fxch %st(1)
faddp %st(0),%st(3)
fxch %st(3)
faddp %st(0),%st(2)
jmp LSetSides
//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
//dist2= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
Lcase4:
fmuls (%ebx) // emaxs[0]
flds pl_normal+4(%edx)
fxch %st(2)
fmuls (%ecx) // emins[0]
fxch %st(2)
fld %st(0)
fmuls 4(%ebx) // emaxs[1]
flds pl_normal+8(%edx)
fxch %st(2)
fmuls 4(%ecx) // emins[1]
fxch %st(2)
fld %st(0)
fmuls 8(%ecx) // emins[2]
fxch %st(5)
faddp %st(0),%st(3)
fmuls 8(%ebx) // emaxs[2]
fxch %st(1)
faddp %st(0),%st(3)
fxch %st(3)
faddp %st(0),%st(2)
jmp LSetSides
//dist1= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
Lcase5:
fmuls (%ecx) // emins[0]
flds pl_normal+4(%edx)
fxch %st(2)
fmuls (%ebx) // emaxs[0]
fxch %st(2)
fld %st(0)
fmuls 4(%ebx) // emaxs[1]
flds pl_normal+8(%edx)
fxch %st(2)
fmuls 4(%ecx) // emins[1]
fxch %st(2)
fld %st(0)
fmuls 8(%ecx) // emins[2]
fxch %st(5)
faddp %st(0),%st(3)
fmuls 8(%ebx) // emaxs[2]
fxch %st(1)
faddp %st(0),%st(3)
fxch %st(3)
faddp %st(0),%st(2)
jmp LSetSides
//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
//dist2= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
Lcase6:
fmuls (%ebx) // emaxs[0]
flds pl_normal+4(%edx)
fxch %st(2)
fmuls (%ecx) // emins[0]
fxch %st(2)
fld %st(0)
fmuls 4(%ecx) // emins[1]
flds pl_normal+8(%edx)
fxch %st(2)
fmuls 4(%ebx) // emaxs[1]
fxch %st(2)
fld %st(0)
fmuls 8(%ecx) // emins[2]
fxch %st(5)
faddp %st(0),%st(3)
fmuls 8(%ebx) // emaxs[2]
fxch %st(1)
faddp %st(0),%st(3)
fxch %st(3)
faddp %st(0),%st(2)
jmp LSetSides
//dist1= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
Lcase7:
fmuls (%ecx) // emins[0]
flds pl_normal+4(%edx)
fxch %st(2)
fmuls (%ebx) // emaxs[0]
fxch %st(2)
fld %st(0)
fmuls 4(%ecx) // emins[1]
flds pl_normal+8(%edx)
fxch %st(2)
fmuls 4(%ebx) // emaxs[1]
fxch %st(2)
fld %st(0)
fmuls 8(%ecx) // emins[2]
fxch %st(5)
faddp %st(0),%st(3)
fmuls 8(%ebx) // emaxs[2]
fxch %st(1)
faddp %st(0),%st(3)
fxch %st(3)
faddp %st(0),%st(2)
LSetSides:
// sides = 0;
// if (dist1 >= p->dist)
// sides = 1;
// if (dist2 < p->dist)
// sides |= 2;
faddp %st(0),%st(2) // dist1 | dist2
fcomps pl_dist(%edx)
xorl %ecx,%ecx
fnstsw %ax
fcomps pl_dist(%edx)
andb $1,%ah
xorb $1,%ah
addb %ah,%cl
fnstsw %ax
andb $1,%ah
addb %ah,%ah
addb %ah,%cl
// return sides;
popl %ebx
movl %ecx,%eax // return status
ret
Lerror:
call C(BOPS_Error)
#endif // id386

715
engine/common/mathlib.c Normal file
View file

@ -0,0 +1,715 @@
/*
Copyright (C) 1996-1997 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.
*/
// mathlib.c -- math primitives
#include "quakedef.h"
#include <math.h>
vec3_t vec3_origin = {0,0,0};
int nanmask = 255<<23;
/*-----------------------------------------------------------------*/
#define DEG2RAD( a ) ( a * M_PI ) / 180.0F
void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
{
float d;
vec3_t n;
float inv_denom;
inv_denom = 1.0F / DotProduct( normal, normal );
d = DotProduct( normal, p ) * inv_denom;
n[0] = normal[0] * inv_denom;
n[1] = normal[1] * inv_denom;
n[2] = normal[2] * inv_denom;
dst[0] = p[0] - d * n[0];
dst[1] = p[1] - d * n[1];
dst[2] = p[2] - d * n[2];
}
/*
** assumes "src" is normalized
*/
void PerpendicularVector( vec3_t dst, const vec3_t src )
{
int pos;
int i;
float minelem = 1.0F;
vec3_t tempvec;
/*
** find the smallest magnitude axially aligned vector
*/
for ( pos = 0, i = 0; i < 3; i++ )
{
if ( fabs( src[i] ) < minelem )
{
pos = i;
minelem = fabs( src[i] );
}
}
tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
tempvec[pos] = 1.0F;
/*
** project the point onto the plane defined by src
*/
ProjectPointOnPlane( dst, tempvec, src );
/*
** normalize the result
*/
VectorNormalize( dst );
}
#ifdef _WIN32
#pragma optimize( "", off )
#endif
void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees )
{
float m[3][3];
float im[3][3];
float zrot[3][3];
float tmpmat[3][3];
float rot[3][3];
int i;
vec3_t vr, vup, vf;
vf[0] = dir[0];
vf[1] = dir[1];
vf[2] = dir[2];
PerpendicularVector( vr, dir );
CrossProduct( vr, vf, vup );
m[0][0] = vr[0];
m[1][0] = vr[1];
m[2][0] = vr[2];
m[0][1] = vup[0];
m[1][1] = vup[1];
m[2][1] = vup[2];
m[0][2] = vf[0];
m[1][2] = vf[1];
m[2][2] = vf[2];
memcpy( im, m, sizeof( im ) );
im[0][1] = m[1][0];
im[0][2] = m[2][0];
im[1][0] = m[0][1];
im[1][2] = m[2][1];
im[2][0] = m[0][2];
im[2][1] = m[1][2];
memset( zrot, 0, sizeof( zrot ) );
zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
zrot[0][0] = cos( DEG2RAD( degrees ) );
zrot[0][1] = sin( DEG2RAD( degrees ) );
zrot[1][0] = -sin( DEG2RAD( degrees ) );
zrot[1][1] = cos( DEG2RAD( degrees ) );
R_ConcatRotations( m, zrot, tmpmat );
R_ConcatRotations( tmpmat, im, rot );
for ( i = 0; i < 3; i++ )
{
dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
}
}
#ifdef _WIN32
#pragma optimize( "", on )
#endif
/*-----------------------------------------------------------------*/
float anglemod(float a)
{
#if 0
if (a >= 0)
a -= 360*(int)(a/360);
else
a += 360*( 1 + (int)(-a/360) );
#endif
a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535);
return a;
}
/*
==================
BOPS_Error
Split out like this for ASM to call.
==================
*/
void VARGS BOPS_Error (void)
{
Sys_Error ("BoxOnPlaneSide: Bad signbits");
}
#if !id386
/*
==================
BoxOnPlaneSide
Returns 1, 2, or 1 + 2
==================
*/
int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, mplane_t *p)
{
float dist1, dist2;
int sides;
#if 0 // this is done by the BOX_ON_PLANE_SIDE macro before calling this
// function
// fast axial cases
if (p->type < 3)
{
if (p->dist <= emins[p->type])
return 1;
if (p->dist >= emaxs[p->type])
return 2;
return 3;
}
#endif
// general case
switch (p->signbits)
{
case 0:
dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
break;
case 1:
dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
break;
case 2:
dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
break;
case 3:
dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
break;
case 4:
dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
break;
case 5:
dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
break;
case 6:
dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
break;
case 7:
dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
break;
default:
dist1 = dist2 = 0; // shut up compiler
BOPS_Error ();
break;
}
#if 0
int i;
vec3_t corners[2];
for (i=0 ; i<3 ; i++)
{
if (plane->normal[i] < 0)
{
corners[0][i] = emins[i];
corners[1][i] = emaxs[i];
}
else
{
corners[1][i] = emins[i];
corners[0][i] = emaxs[i];
}
}
dist = DotProduct (plane->normal, corners[0]) - plane->dist;
dist2 = DotProduct (plane->normal, corners[1]) - plane->dist;
sides = 0;
if (dist1 >= 0)
sides = 1;
if (dist2 < 0)
sides |= 2;
#endif
sides = 0;
if (dist1 >= p->dist)
sides = 1;
if (dist2 < p->dist)
sides |= 2;
#ifdef PARANOID
if (sides == 0)
Sys_Error ("BoxOnPlaneSide: sides==0");
#endif
return sides;
}
#endif
void VVPerpendicularVector(vec3_t dst, const vec3_t src)
{
if (!src[0])
{
dst[0] = 1;
dst[1] = dst[2] = 0;
}
else if (!src[1])
{
dst[1] = 1;
dst[0] = dst[2] = 0;
}
else if (!src[2])
{
dst[2] = 1;
dst[0] = dst[1] = 0;
}
else
{
dst[0] = -src[1];
dst[1] = src[0];
dst[2] = 0;
VectorNormalize(dst);
}
}
void VectorVectors(vec3_t forward, vec3_t right, vec3_t up)
{
VVPerpendicularVector(right, forward);
CrossProduct(right, forward, up);
}
void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
{
float angle;
float sr, sp, sy, cr, cp, cy;
angle = angles[YAW] * (M_PI*2 / 360);
sy = sin(angle);
cy = cos(angle);
angle = angles[PITCH] * (M_PI*2 / 360);
sp = sin(angle);
cp = cos(angle);
angle = angles[ROLL] * (M_PI*2 / 360);
sr = sin(angle);
cr = cos(angle);
forward[0] = cp*cy;
forward[1] = cp*sy;
forward[2] = -sp;
right[0] = (-1*sr*sp*cy+-1*cr*-sy);
right[1] = (-1*sr*sp*sy+-1*cr*cy);
right[2] = -1*sr*cp;
up[0] = (cr*sp*cy+-sr*-sy);
up[1] = (cr*sp*sy+-sr*cy);
up[2] = cr*cp;
}
int VectorCompare (vec3_t v1, vec3_t v2)
{
int i;
for (i=0 ; i<3 ; i++)
if (v1[i] != v2[i])
return 0;
return 1;
}
void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc)
{
vecc[0] = veca[0] + scale*vecb[0];
vecc[1] = veca[1] + scale*vecb[1];
vecc[2] = veca[2] + scale*vecb[2];
}
vec_t _DotProduct (vec3_t v1, vec3_t v2)
{
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out)
{
out[0] = veca[0]-vecb[0];
out[1] = veca[1]-vecb[1];
out[2] = veca[2]-vecb[2];
}
void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out)
{
out[0] = veca[0]+vecb[0];
out[1] = veca[1]+vecb[1];
out[2] = veca[2]+vecb[2];
}
void _VectorCopy (vec3_t in, vec3_t out)
{
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
}
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
{
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
}
vec_t Length(vec3_t v)
{
int i;
float length;
length = 0;
for (i=0 ; i< 3 ; i++)
length += v[i]*v[i];
length = sqrt (length); // FIXME
return length;
}
float VectorNormalize (vec3_t v)
{
float length, ilength;
length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
length = sqrt (length); // FIXME
if (length)
{
ilength = 1/length;
v[0] *= ilength;
v[1] *= ilength;
v[2] *= ilength;
}
return length;
}
void VectorInverse (vec3_t v)
{
v[0] = -v[0];
v[1] = -v[1];
v[2] = -v[2];
}
void VectorScale (vec3_t in, vec_t scale, vec3_t out)
{
out[0] = in[0]*scale;
out[1] = in[1]*scale;
out[2] = in[2]*scale;
}
int Q_log2(int val)
{
int answer=0;
while ((val>>=1) != 0)
answer++;
return answer;
}
/*
================
R_ConcatRotations
================
*/
void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
{
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
in1[0][2] * in2[2][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
in1[0][2] * in2[2][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
in1[0][2] * in2[2][2];
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
in1[1][2] * in2[2][0];
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
in1[1][2] * in2[2][1];
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
in1[1][2] * in2[2][2];
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
in1[2][2] * in2[2][0];
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
in1[2][2] * in2[2][1];
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
in1[2][2] * in2[2][2];
}
/*
================
R_ConcatTransforms
================
*/
void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4])
{
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
in1[0][2] * in2[2][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
in1[0][2] * in2[2][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
in1[0][2] * in2[2][2];
out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] +
in1[0][2] * in2[2][3] + in1[0][3];
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
in1[1][2] * in2[2][0];
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
in1[1][2] * in2[2][1];
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
in1[1][2] * in2[2][2];
out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] +
in1[1][2] * in2[2][3] + in1[1][3];
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
in1[2][2] * in2[2][0];
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
in1[2][2] * in2[2][1];
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
in1[2][2] * in2[2][2];
out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
in1[2][2] * in2[2][3] + in1[2][3];
}
/*
===================
FloorDivMod
Returns mathematically correct (floor-based) quotient and remainder for
numer and denom, both of which should contain no fractional part. The
quotient must fit in 32 bits.
====================
*/
void FloorDivMod (double numer, double denom, int *quotient,
int *rem)
{
int q, r;
double x;
#ifndef PARANOID
if (denom <= 0.0)
Sys_Error ("FloorDivMod: bad denominator %d\n", denom);
// if ((floor(numer) != numer) || (floor(denom) != denom))
// Sys_Error ("FloorDivMod: non-integer numer or denom %f %f\n",
// numer, denom);
#endif
if (numer >= 0.0)
{
x = floor(numer / denom);
q = (int)x;
r = (int)floor(numer - (x * denom));
}
else
{
//
// perform operations with positive values, and fix mod to make floor-based
//
x = floor(-numer / denom);
q = -(int)x;
r = (int)floor(-numer - (x * denom));
if (r != 0)
{
q--;
r = (int)denom - r;
}
}
*quotient = q;
*rem = r;
}
/*
===================
GreatestCommonDivisor
====================
*/
int GreatestCommonDivisor (int i1, int i2)
{
if (i1 > i2)
{
if (i2 == 0)
return (i1);
return GreatestCommonDivisor (i2, i1 % i2);
}
else
{
if (i1 == 0)
return (i2);
return GreatestCommonDivisor (i1, i2 % i1);
}
}
#if !id386
// TODO: move to nonintel.c
/*
===================
Invert24To16
Inverts an 8.24 value to a 16.16 value
====================
*/
fixed16_t Invert24To16(fixed16_t val)
{
if (val < 256)
return (0xFFFFFFFF);
return (fixed16_t)
(((double)0x10000 * (double)0x1000000 / (double)val) + 0.5);
}
#endif
void VectorTransform (const vec3_t in1, const float in2[3][4], vec3_t out)
{
out[0] = DotProduct(in1, in2[0]) + in2[0][3];
out[1] = DotProduct(in1, in2[1]) + in2[1][3];
out[2] = DotProduct(in1, in2[2]) + in2[2][3];
}
#ifdef HALFLIFEMODELS
void AngleQuaternion( const vec3_t angles, vec4_t quaternion )
{
float angle;
float sr, sp, sy, cr, cp, cy;
// FIXME: rescale the inputs to 1/2 angle
angle = angles[2] * 0.5;
sy = sin(angle);
cy = cos(angle);
angle = angles[1] * 0.5;
sp = sin(angle);
cp = cos(angle);
angle = angles[0] * 0.5;
sr = sin(angle);
cr = cos(angle);
quaternion[0] = sr*cp*cy-cr*sp*sy; // X
quaternion[1] = cr*sp*cy+sr*cp*sy; // Y
quaternion[2] = cr*cp*sy-sr*sp*cy; // Z
quaternion[3] = cr*cp*cy+sr*sp*sy; // W
}
void QuaternionMatrix( const vec4_t quaternion, float (*matrix)[4] )
{
matrix[0][0] = 1.0 - 2.0 * quaternion[1] * quaternion[1] - 2.0 * quaternion[2] * quaternion[2];
matrix[1][0] = 2.0 * quaternion[0] * quaternion[1] + 2.0 * quaternion[3] * quaternion[2];
matrix[2][0] = 2.0 * quaternion[0] * quaternion[2] - 2.0 * quaternion[3] * quaternion[1];
matrix[0][1] = 2.0 * quaternion[0] * quaternion[1] - 2.0 * quaternion[3] * quaternion[2];
matrix[1][1] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[2] * quaternion[2];
matrix[2][1] = 2.0 * quaternion[1] * quaternion[2] + 2.0 * quaternion[3] * quaternion[0];
matrix[0][2] = 2.0 * quaternion[0] * quaternion[2] + 2.0 * quaternion[3] * quaternion[1];
matrix[1][2] = 2.0 * quaternion[1] * quaternion[2] - 2.0 * quaternion[3] * quaternion[0];
matrix[2][2] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[1] * quaternion[1];
}
void QuaternionSlerp( const vec4_t p, vec4_t q, float t, vec4_t qt )
{
int i;
float omega, cosom, sinom, sclp, sclq;
// decide if one of the quaternions is backwards
float a = 0;
float b = 0;
for (i = 0; i < 4; i++) {
a += (p[i]-q[i])*(p[i]-q[i]);
b += (p[i]+q[i])*(p[i]+q[i]);
}
if (a > b) {
for (i = 0; i < 4; i++) {
q[i] = -q[i];
}
}
cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3];
if ((1.0 + cosom) > 0.00000001) {
if ((1.0 - cosom) > 0.00000001) {
omega = acos( cosom );
sinom = sin( omega );
sclp = sin( (1.0 - t)*omega) / sinom;
sclq = sin( t*omega ) / sinom;
}
else {
sclp = 1.0 - t;
sclq = t;
}
for (i = 0; i < 4; i++) {
qt[i] = sclp * p[i] + sclq * q[i];
}
}
else {
qt[0] = -p[1];
qt[1] = p[0];
qt[2] = -p[3];
qt[3] = p[2];
sclp = sin( (1.0 - t) * 0.5 * M_PI);
sclq = sin( t * 0.5 * M_PI);
for (i = 0; i < 3; i++) {
qt[i] = sclp * p[i] + sclq * qt[i];
}
}
}
#endif

99
engine/common/mathlib.h Normal file
View file

@ -0,0 +1,99 @@
/*
Copyright (C) 1996-1997 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.
*/
// mathlib.h
typedef float vec_t;
typedef vec_t vec2_t[2];
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
typedef vec_t vec5_t[5];
typedef qbyte byte_vec4_t[4];
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 mplane_s;
extern vec3_t vec3_origin;
extern int nanmask;
#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
#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 VectorLength(a) Length(a)
void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc);
vec_t _DotProduct (vec3_t v1, vec3_t v2);
void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out);
void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out);
void _VectorCopy (vec3_t in, vec3_t out);
int VectorCompare (vec3_t v1, vec3_t v2);
vec_t Length (vec3_t v);
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
float VectorNormalize (vec3_t v); // returns vector length
void VectorInverse (vec3_t v);
void VectorScale (vec3_t in, vec_t scale, vec3_t out);
int Q_log2(int val);
void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);
void FloorDivMod (double numer, double denom, int *quotient,
int *rem);
fixed16_t Invert24To16(fixed16_t val);
fixed16_t Mul16_30(fixed16_t multiplier, fixed16_t multiplicand);
int GreatestCommonDivisor (int i1, int i2);
void VectorVectors(vec3_t forward, vec3_t right, vec3_t up);
void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
int VARGS BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane);
float anglemod(float a);
void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
#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)))

306
engine/common/md4.c Normal file
View file

@ -0,0 +1,306 @@
/*
Copyright (C) 1996-1997 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.
*/
/* GLOBAL.H - RSAREF types and constants */
#include <string.h>
/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;
/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */
#ifdef __alpha__
typedef unsigned int UINT4;
#else
typedef unsigned long int UINT4;
#endif
/* MD4.H - header file for MD4C.C */
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991.
All rights reserved.
License to copy and use this software is granted provided that it is identified as the RSA Data Security, Inc. MD4 Message-Digest Algorithm in all material mentioning or referencing this software or this function.
License is also granted to make and use derivative works provided that such works are identified as derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm in all material mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided as is without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this documentation and/or software. */
/* MD4 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD4_CTX;
void MD4Init (MD4_CTX *);
void MD4Update (MD4_CTX *, unsigned char *, unsigned int);
void MD4Final (unsigned char [16], MD4_CTX *);
/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm */
/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
License to copy and use this software is granted provided that it is identified as the
RSA Data Security, Inc. MD4 Message-Digest Algorithm
in all material mentioning or referencing this software or this function.
License is also granted to make and use derivative works provided that such works are identified as
derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm
in all material mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided
as is without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this documentation and/or software. */
/* Constants for MD4Transform routine. */
#define S11 3
#define S12 7
#define S13 11
#define S14 19
#define S21 3
#define S22 5
#define S23 9
#define S24 13
#define S31 3
#define S32 9
#define S33 11
#define S34 15
static void MD4Transform (UINT4 [4], unsigned char [64]);
static void Encode (unsigned char *, UINT4 *, unsigned int);
static void Decode (UINT4 *, unsigned char *, unsigned int);
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G and H are basic MD4 functions. */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
/* ROTATE_LEFT rotates x left n bits. */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s) {(a) += F ((b), (c), (d)) + (x); (a) = ROTATE_LEFT ((a), (s));}
#define GG(a, b, c, d, x, s) {(a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; (a) = ROTATE_LEFT ((a), (s));}
#define HH(a, b, c, d, x, s) {(a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; (a) = ROTATE_LEFT ((a), (s));}
/* MD4 initialization. Begins an MD4 operation, writing a new context. */
void MD4Init (MD4_CTX *context)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */
void MD4Update (MD4_CTX *context, unsigned char *input, unsigned int inputLen)
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.*/
if (inputLen >= partLen)
{
memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD4Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD4Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
}
/* MD4 finalization. Ends an MD4 message-digest operation, writing the the message digest and zeroizing the context. */
void MD4Final (unsigned char digest[16], MD4_CTX *context)
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD4Update (context, PADDING, padLen);
/* Append length (before padding) */
MD4Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.*/
memset ((POINTER)context, 0, sizeof (*context));
}
/* MD4 basic transformation. Transforms state based on block. */
static void MD4Transform (UINT4 state[4], unsigned char block[64])
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11); /* 1 */
FF (d, a, b, c, x[ 1], S12); /* 2 */
FF (c, d, a, b, x[ 2], S13); /* 3 */
FF (b, c, d, a, x[ 3], S14); /* 4 */
FF (a, b, c, d, x[ 4], S11); /* 5 */
FF (d, a, b, c, x[ 5], S12); /* 6 */
FF (c, d, a, b, x[ 6], S13); /* 7 */
FF (b, c, d, a, x[ 7], S14); /* 8 */
FF (a, b, c, d, x[ 8], S11); /* 9 */
FF (d, a, b, c, x[ 9], S12); /* 10 */
FF (c, d, a, b, x[10], S13); /* 11 */
FF (b, c, d, a, x[11], S14); /* 12 */
FF (a, b, c, d, x[12], S11); /* 13 */
FF (d, a, b, c, x[13], S12); /* 14 */
FF (c, d, a, b, x[14], S13); /* 15 */
FF (b, c, d, a, x[15], S14); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 0], S21); /* 17 */
GG (d, a, b, c, x[ 4], S22); /* 18 */
GG (c, d, a, b, x[ 8], S23); /* 19 */
GG (b, c, d, a, x[12], S24); /* 20 */
GG (a, b, c, d, x[ 1], S21); /* 21 */
GG (d, a, b, c, x[ 5], S22); /* 22 */
GG (c, d, a, b, x[ 9], S23); /* 23 */
GG (b, c, d, a, x[13], S24); /* 24 */
GG (a, b, c, d, x[ 2], S21); /* 25 */
GG (d, a, b, c, x[ 6], S22); /* 26 */
GG (c, d, a, b, x[10], S23); /* 27 */
GG (b, c, d, a, x[14], S24); /* 28 */
GG (a, b, c, d, x[ 3], S21); /* 29 */
GG (d, a, b, c, x[ 7], S22); /* 30 */
GG (c, d, a, b, x[11], S23); /* 31 */
GG (b, c, d, a, x[15], S24); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 0], S31); /* 33 */
HH (d, a, b, c, x[ 8], S32); /* 34 */
HH (c, d, a, b, x[ 4], S33); /* 35 */
HH (b, c, d, a, x[12], S34); /* 36 */
HH (a, b, c, d, x[ 2], S31); /* 37 */
HH (d, a, b, c, x[10], S32); /* 38 */
HH (c, d, a, b, x[ 6], S33); /* 39 */
HH (b, c, d, a, x[14], S34); /* 40 */
HH (a, b, c, d, x[ 1], S31); /* 41 */
HH (d, a, b, c, x[ 9], S32); /* 42 */
HH (c, d, a, b, x[ 5], S33); /* 43 */
HH (b, c, d, a, x[13], S34); /* 44 */
HH (a, b, c, d, x[ 3], S31); /* 45 */
HH (d, a, b, c, x[11], S32); /* 46 */
HH (c, d, a, b, x[ 7], S33); /* 47 */
HH (b, c, d, a, x[15], S34); /* 48 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.*/
memset ((POINTER)x, 0, sizeof (x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */
static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */
static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
//===================================================================
unsigned Com_BlockChecksum (void *buffer, int length)
{
int digest[4];
unsigned val;
MD4_CTX ctx;
MD4Init (&ctx);
MD4Update (&ctx, (unsigned char *)buffer, length);
MD4Final ( (unsigned char *)digest, &ctx);
val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
return val;
}
void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf)
{
MD4_CTX ctx;
MD4Init (&ctx);
MD4Update (&ctx, (unsigned char *)buffer, len);
MD4Final ( outbuf, &ctx);
}

422
engine/common/md5.c Normal file
View file

@ -0,0 +1,422 @@
//used by pop3.
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#include "quakedef.h"
#if defined(EMAILCLIENT) || defined(EMAILSERVER)
/* GLOBAL.H - RSAREF types and constants
*/
/* PROTOTYPES should be set to one if and only if the compiler supports
function argument prototyping.
The following makes PROTOTYPES default to 0 if it has not already
been defined with C compiler flags.
*/
#ifndef PROTOTYPES
#define PROTOTYPES 0
#endif
/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;
/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */
typedef unsigned long int UINT4;
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
returns an empty list.
*/
#if PROTOTYPES
#define PROTO_LIST(list) list
#else
#define PROTO_LIST(list) ()
#endif
/* MD5.H - header file for MD5C.C
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/* MD5 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
void MD5Init PROTO_LIST ((MD5_CTX *));
void MD5Update PROTO_LIST
((MD5_CTX *, unsigned char *, unsigned int));
void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
static void Encode PROTO_LIST
((unsigned char *, UINT4 *, unsigned int));
static void Decode PROTO_LIST
((UINT4 *, unsigned char *, unsigned int));
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void MD5Init (context)
MD5_CTX *context; /* context */
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
void MD5Update (context, input, inputLen)
MD5_CTX *context; /* context */
unsigned char *input; /* input block */
unsigned int inputLen; /* length of input block */
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
memcpy
((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
memcpy
((POINTER)&context->buffer[index], (POINTER)&input[i],
inputLen-i);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void MD5Final (digest, context)
unsigned char digest[16]; /* message digest */
MD5_CTX *context; /* context */
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.
*/
memset ((POINTER)context, 0, sizeof (*context));
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void MD5Transform (state, block)
UINT4 state[4];
unsigned char block[64];
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
memset ((POINTER)x, 0, sizeof (x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void Encode (output, input, len)
unsigned char *output;
UINT4 *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
a multiple of 4.
*/
static void Decode (output, input, len)
UINT4 *output;
unsigned char *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
char *MD5_GetPop3APOPString(char *timestamp, char *secrit)
{
static char ret[64];
int digest[4];
MD5_CTX ctx;
MD5Init (&ctx);
MD5Update (&ctx, (unsigned char *)timestamp, strlen(timestamp));
MD5Update (&ctx, (unsigned char *)secrit, strlen(secrit));
MD5Final ( (unsigned char *)digest, &ctx);
sprintf(ret, "%08x%08x%08x%08x", BigLong(digest[0]), BigLong(digest[1]), BigLong(digest[2]), BigLong(digest[3]));
return ret;
}
#endif

165
engine/common/net.h Normal file
View file

@ -0,0 +1,165 @@
/*
Copyright (C) 1996-1997 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.
*/
// net.h -- quake's interface to the networking layer
#define PORT_ANY -1
typedef enum {NA_INVALID, NA_LOOPBACK, NA_IP, NA_IPV6, NA_IPX, NA_BROADCAST_IP, NA_BROADCAST_IP6, NA_BROADCAST_IPX} netadrtype_t;
typedef enum {NS_CLIENT, NS_SERVER} netsrc_t;
typedef struct
{
netadrtype_t type;
union {
qbyte ip[4];
qbyte ip6[16];
qbyte ipx[10];
};
unsigned short port;
} netadr_t;
struct sockaddr_qstorage
{
short sa_family;
unsigned char sa_pad[6];
#if defined(_MSC_VER) || defined(MINGW)
__int64 sa_align;
#else
int sa_align[2];
#endif
unsigned char sa_pad2[112];
};
extern netadr_t net_local_ipadr;
extern netadr_t net_from; // address of who sent the packet
extern sizebuf_t net_message;
//#define MAX_UDP_PACKET (MAX_MSGLEN*2) // one more than msg + header
#define MAX_UDP_PACKET 8192 // one more than msg + header
extern qbyte net_message_buffer[MAX_UDP_PACKET];
extern cvar_t hostname;
void NET_Init (void);
void NET_InitClient (void);
void NET_InitServer (void);
void NET_CloseServer (void);
void UDP_CloseSocket (int socket);
void NET_Shutdown (void);
qboolean NET_GetPacket (netsrc_t socket);
void NET_SendPacket (netsrc_t socket, int length, void *data, netadr_t to);
qboolean NET_CompareAdr (netadr_t a, netadr_t b);
qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b);
char *NET_AdrToString (netadr_t a);
char *NET_BaseAdrToString (netadr_t a);
qboolean NET_StringToAdr (char *s, netadr_t *a);
qboolean NET_IsClientLegal(netadr_t *adr);
qboolean NET_IsLoopBackAddress (netadr_t adr);
//============================================================================
#define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG)
#define MAX_LATENT 32
typedef struct
{
qboolean fatal_error;
#ifdef NQPROT
qboolean isnqprotocol;
struct qsocket_s *qsocket;
#endif
float last_received; // for timeouts
// the statistics are cleared at each client begin, because
// the server connecting process gives a bogus picture of the data
float frame_latency; // rolling average
float frame_rate;
int drop_count; // dropped packets, cleared each level
int good_count; // cleared each level
netadr_t remote_address;
netsrc_t sock;
int qport;
// bandwidth estimator
double cleartime; // if realtime > nc->cleartime, free to go
double rate; // seconds / qbyte
// sequencing variables
int incoming_sequence;
int incoming_acknowledged;
int incoming_reliable_acknowledged; // single bit
int incoming_reliable_sequence; // single bit, maintained local
int outgoing_sequence;
int reliable_sequence; // single bit
int last_reliable_sequence; // sequence number of last send
// reliable staging and holding areas
sizebuf_t message; // writing buffer to send to server
qbyte message_buf[MAX_OVERALLMSGLEN];
int reliable_length;
qbyte reliable_buf[MAX_OVERALLMSGLEN]; // unacked reliable message
// time and size data to calculate bandwidth
int outgoing_size[MAX_LATENT];
double outgoing_time[MAX_LATENT];
qboolean compress;
} netchan_t;
extern int net_drop; // packets dropped before this one
void Netchan_Init (void);
void Netchan_Transmit (netchan_t *chan, int length, qbyte *data);
void Netchan_OutOfBand (netsrc_t sock, netadr_t adr, int length, qbyte *data);
void VARGS Netchan_OutOfBandPrint (netsrc_t sock, netadr_t adr, char *format, ...);
void VARGS Netchan_OutOfBandTPrintf (netsrc_t sock, netadr_t adr, int language, translation_t text, ...);
qboolean Netchan_Process (netchan_t *chan);
void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport);
qboolean Netchan_CanPacket (netchan_t *chan);
qboolean Netchan_CanReliable (netchan_t *chan);
#ifdef HUFFNETWORK
int Huff_PreferedCompressionCRC (void);
qboolean Huff_CompressionCRC(int crc);
void Huff_CompressPacket(sizebuf_t *msg, int offset);
void Huff_DecompressPacket(sizebuf_t *msg, int offset);
#endif
#ifdef NQPROT
#include "../nqnet/nqnet.h"
#endif
int UDP_OpenSocket (int port, qboolean bcast);
int IPX_OpenSocket (int port, qboolean bcast);
void SockadrToNetadr (struct sockaddr_qstorage *s, netadr_t *a);
qboolean NET_Sleep(int msec, qboolean stdinissocket);

534
engine/common/net_chan.c Normal file
View file

@ -0,0 +1,534 @@
/*
Copyright (C) 1996-1997 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.
*/
#include "quakedef.h"
#ifdef _WIN32
#include "winquake.h"
#else
#include "unistd.h"
#endif
#define PACKET_HEADER 8
/*
packet header
-------------
31 sequence
1 does this message contain a reliable payload
31 acknowledge sequence
1 acknowledge receipt of even/odd message
16 qport
The remote connection never knows if it missed a reliable message, the
local side detects that it has been dropped by seeing a sequence acknowledge
higher thatn the last reliable sequence, but without the correct evon/odd
bit for the reliable set.
If the sender notices that a reliable message has been dropped, it will be
retransmitted. It will not be retransmitted again until a message after
the retransmit has been acknowledged and the reliable still failed to get there.
if the sequence number is -1, the packet should be handled without a netcon
The reliable message can be added to at any time by doing
MSG_Write* (&netchan->message, <data>).
If the message buffer is overflowed, either by a single message, or by
multiple frames worth piling up while the last reliable transmit goes
unacknowledged, the netchan signals a fatal error.
Reliable messages are allways placed first in a packet, then the unreliable
message is included if there is sufficient room.
To the receiver, there is no distinction between the reliable and unreliable
parts of the message, they are just processed out as a single larger message.
Illogical packet sequence numbers cause the packet to be dropped, but do
not kill the connection. This, combined with the tight window of valid
reliable acknowledgement numbers provides protection against malicious
address spoofing.
The qport field is a workaround for bad address translating routers that
sometimes remap the client's source port on a packet during gameplay.
If the base part of the net address matches and the qport matches, then the
channel matches even if the IP port differs. The IP port should be updated
to the new value before sending out any replies.
*/
int net_drop;
cvar_t showpackets = {"showpackets", "0"};
cvar_t showdrop = {"showdrop", "0"};
cvar_t qport = {"qport", "0"};
/*
===============
Netchan_Init
===============
*/
void Netchan_Init (void)
{
int port;
// pick a port value that should be nice and random
#ifdef _WIN32
port = ((int)(timeGetTime()*1000) * time(NULL)) & 0xffff;
#else
port = ((int)(getpid()+getuid()*1000) * time(NULL)) & 0xffff;
#endif
Cvar_Register (&showpackets, "Networking");
Cvar_Register (&showdrop, "Networking");
Cvar_Register (&qport, "Networking");
Cvar_SetValue(&qport, port);
}
/*
===============
Netchan_OutOfBand
Sends an out-of-band datagram
================
*/
void Netchan_OutOfBand (netsrc_t sock, netadr_t adr, int length, qbyte *data)
{
sizebuf_t send;
qbyte send_buf[MAX_QWMSGLEN + PACKET_HEADER];
// write the packet header
send.data = send_buf;
send.maxsize = sizeof(send_buf);
send.cursize = 0;
MSG_WriteLong (&send, -1); // -1 sequence means out of band
SZ_Write (&send, data, length);
// send the datagram
//zoid, no input in demo playback mode
#ifndef SERVERONLY
if (!cls.demoplayback)
#endif
NET_SendPacket (sock, send.cursize, send.data, adr);
}
/*
===============
Netchan_OutOfBandPrint
Sends a text message in an out-of-band datagram
================
*/
void VARGS Netchan_OutOfBandPrint (netsrc_t sock, netadr_t adr, char *format, ...)
{
va_list argptr;
static char string[8192]; // ??? why static?
va_start (argptr, format);
_vsnprintf (string,sizeof(string)-1, format,argptr);
va_end (argptr);
Netchan_OutOfBand (sock, adr, strlen(string), (qbyte *)string);
}
#ifndef CLIENTONLY
void VARGS Netchan_OutOfBandTPrintf (netsrc_t sock, netadr_t adr, int language, translation_t text, ...)
{
va_list argptr;
static char string[8192]; // ??? why static?
char *format = langtext(text, language);
string[0] = A2C_PRINT;
va_start (argptr, text);
_vsnprintf (string+1,sizeof(string)-2, format,argptr);
va_end (argptr);
Netchan_OutOfBand (sock, adr, strlen(string), (qbyte *)string);
}
#endif
/*
==============
Netchan_Setup
called to open a channel to a remote system
==============
*/
void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport)
{
memset (chan, 0, sizeof(*chan));
#ifdef NQPROT
chan->qsocket = NULL;
#endif
chan->sock = sock;
chan->remote_address = adr;
chan->last_received = realtime;
chan->message.data = chan->message_buf;
chan->message.allowoverflow = true;
chan->message.maxsize = MAX_QWMSGLEN;//sizeof(chan->message_buf);
chan->qport = qport;
chan->rate = 1.0/2500;
}
/*
===============
Netchan_CanPacket
Returns true if the bandwidth choke isn't active
================
*/
#define MAX_BACKUP 200
qboolean Netchan_CanPacket (netchan_t *chan)
{
if (chan->remote_address.type == NA_LOOPBACK)
return true; //don't ever drop packets due to possible routing problems when there is no routing.
if (chan->cleartime < realtime + MAX_BACKUP*chan->rate)
return true;
return false;
}
/*
===============
Netchan_CanReliable
Returns true if the bandwidth choke isn't
================
*/
qboolean Netchan_CanReliable (netchan_t *chan)
{
if (chan->reliable_length)
return false; // waiting for ack
return Netchan_CanPacket (chan);
}
#ifdef SERVERONLY
qboolean ServerPaused(void);
#endif
/*
===============
Netchan_Transmit
tries to send an unreliable message to a connection, and handles the
transmition / retransmition of the reliable messages.
A 0 length will still generate a packet and deal with the reliable messages.
================
*/
void Netchan_Transmit (netchan_t *chan, int length, qbyte *data)
{
sizebuf_t send;
qbyte send_buf[MAX_OVERALLMSGLEN + PACKET_HEADER];
qboolean send_reliable;
unsigned w1, w2;
int i;
#ifdef NQPROT
if (chan->qsocket && !chan->qsocket->qwprotocol)
{
if (!NET_CanSendMessage (chan->qsocket))
return;
if (!chan->reliable_length && chan->message.cursize)
{
memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize);
chan->reliable_length = chan->message.cursize;
chan->message.cursize = 0;
chan->reliable_sequence ^= 1;
send_reliable = true;
}
send.data = send_buf;
send.maxsize = MAX_NQMSGLEN + PACKET_HEADER;
send.cursize = 0;
chan->outgoing_sequence++;
chan->last_reliable_sequence = chan->outgoing_sequence;
SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
SZ_Write (&send, data, length);
NET_SendMessage(chan->qsocket, &send);
chan->message.cursize = 0;
chan->reliable_length = 0;
return;
}
#endif
// check for message overflow
if (chan->message.overflowed)
{
chan->fatal_error = true;
Con_TPrintf (TL_OUTMESSAGEOVERFLOW
, NET_AdrToString (chan->remote_address));
return;
}
// if the remote side dropped the last reliable message, resend it
send_reliable = false;
if (chan->incoming_acknowledged > chan->last_reliable_sequence
&& chan->incoming_reliable_acknowledged != chan->reliable_sequence)
send_reliable = true;
// if the reliable transmit buffer is empty, copy the current message out
if (!chan->reliable_length && chan->message.cursize)
{
memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize);
chan->reliable_length = chan->message.cursize;
chan->message.cursize = 0;
chan->reliable_sequence ^= 1;
send_reliable = true;
}
// write the packet header
send.data = send_buf;
send.maxsize = MAX_QWMSGLEN + PACKET_HEADER; //dmw wasn't quite true.
send.cursize = 0;
w1 = chan->outgoing_sequence | (send_reliable<<31);
w2 = chan->incoming_sequence | (chan->incoming_reliable_sequence<<31);
chan->outgoing_sequence++;
MSG_WriteLong (&send, w1);
MSG_WriteLong (&send, w2);
// send the qport if we are a client
#ifndef SERVERONLY
if (chan->sock == NS_CLIENT)
MSG_WriteShort (&send, cls.qport);
#endif
// copy the reliable message to the packet first
if (send_reliable)
{
SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
chan->last_reliable_sequence = chan->outgoing_sequence;
}
// add the unreliable part if space is available
if (send.maxsize - send.cursize >= length)
SZ_Write (&send, data, length);
// send the datagram
i = chan->outgoing_sequence & (MAX_LATENT-1);
chan->outgoing_size[i] = send.cursize;
chan->outgoing_time[i] = realtime;
#ifdef HUFFNETWORK
if (chan->compress)
{
int oldsize = send.cursize;
Huff_CompressPacket(&send, (chan->sock == NS_CLIENT)?10:8);
Con_Printf("%i becomes %i\n", oldsize, send.cursize);
// Huff_DecompressPacket(&send, (chan->sock == NS_CLIENT)?10:8);
}
#endif
//zoid, no input in demo playback mode
#ifndef SERVERONLY
if (!cls.demoplayback)
#endif
{
#ifdef NQPROT
if (chan->qsocket)
NET_SendUnreliableMessage(chan->qsocket, &send); //qw protocol adds it's own reliability.
else
#endif
NET_SendPacket (chan->sock, send.cursize, send.data, chan->remote_address);
}
if (chan->cleartime < realtime)
chan->cleartime = realtime + send.cursize*chan->rate;
else
chan->cleartime += send.cursize*chan->rate;
#ifdef SERVERONLY
if (ServerPaused())
chan->cleartime = realtime;
#endif
if (showpackets.value)
Con_Printf ("--> s=%i(%i) a=%i(%i) %i\n"
, chan->outgoing_sequence
, send_reliable
, chan->incoming_sequence
, chan->incoming_reliable_sequence
, send.cursize);
}
/*
=================
Netchan_Process
called when the current net_message is from remote_address
modifies net_message so that it points to the packet payload
=================
*/
qboolean Netchan_Process (netchan_t *chan)
{
unsigned sequence, sequence_ack;
unsigned reliable_ack, reliable_message;
#ifndef CLIENTONLY
int qport;
#endif
if (
#ifndef SERVERONLY
!cls.demoplayback &&
#endif
!NET_CompareAdr (net_from, chan->remote_address))
return false;
// get sequence numbers
MSG_BeginReading ();
sequence = MSG_ReadLong ();
sequence_ack = MSG_ReadLong ();
// read the qport if we are a server
#ifndef CLIENTONLY
if (chan->sock == NS_SERVER)
qport = MSG_ReadShort ();
#endif
reliable_message = sequence >> 31;
reliable_ack = sequence_ack >> 31;
sequence &= ~(1<<31);
sequence_ack &= ~(1<<31);
if (showpackets.value)
Con_Printf ("<-- s=%i(%i) a=%i(%i) %i\n"
, sequence
, reliable_message
, sequence_ack
, reliable_ack
, net_message.cursize);
// get a rate estimation
#if 0
if (chan->outgoing_sequence - sequence_ack < MAX_LATENT)
{
int i;
double time, rate;
i = sequence_ack & (MAX_LATENT - 1);
time = realtime - chan->outgoing_time[i];
time -= 0.1; // subtract 100 ms
if (time <= 0)
{ // gotta be a digital link for <100 ms ping
if (chan->rate > 1.0/5000)
chan->rate = 1.0/5000;
}
else
{
if (chan->outgoing_size[i] < 512)
{ // only deal with small messages
rate = chan->outgoing_size[i]/time;
if (rate > 5000)
rate = 5000;
rate = 1.0/rate;
if (chan->rate > rate)
chan->rate = rate;
}
}
}
#endif
//
// discard stale or duplicated packets
//
if (sequence <= (unsigned)chan->incoming_sequence)
{
if (showdrop.value)
Con_TPrintf (TL_OUTOFORDERPACKET
, NET_AdrToString (chan->remote_address)
, sequence
, chan->incoming_sequence);
return false;
}
//
// dropped packets don't keep the message from being used
//
net_drop = sequence - (chan->incoming_sequence+1);
if (net_drop > 0)
{
chan->drop_count += 1;
if (showdrop.value)
Con_TPrintf (TL_DROPPEDPACKETCOUNT
, NET_AdrToString (chan->remote_address)
, sequence-(chan->incoming_sequence+1)
, sequence);
}
//
// if the current outgoing reliable message has been acknowledged
// clear the buffer to make way for the next
//
if (reliable_ack == (unsigned)chan->reliable_sequence)
chan->reliable_length = 0; // it has been received
//
// if this message contains a reliable message, bump incoming_reliable_sequence
//
chan->incoming_sequence = sequence;
chan->incoming_acknowledged = sequence_ack;
chan->incoming_reliable_acknowledged = reliable_ack;
if (reliable_message)
chan->incoming_reliable_sequence ^= 1;
//
// the message can now be read from the current message pointer
// update statistics counters
//
chan->frame_latency = chan->frame_latency*OLD_AVG
+ (chan->outgoing_sequence-sequence_ack)*(1.0-OLD_AVG);
chan->frame_rate = chan->frame_rate*OLD_AVG
+ (realtime-chan->last_received)*(1.0-OLD_AVG);
chan->good_count += 1;
chan->last_received = realtime;
#ifdef HUFFNETWORK
if (chan->compress)
{
// Huff_CompressPacket(&net_message, (chan->sock == NS_SERVER)?10:8);
Huff_DecompressPacket(&net_message, (chan->sock == NS_SERVER)?10:8);
}
#endif
return true;
}

1260
engine/common/net_wins.c Normal file

File diff suppressed because it is too large Load diff

1060
engine/common/pmove.c Normal file

File diff suppressed because it is too large Load diff

142
engine/common/pmove.h Normal file
View file

@ -0,0 +1,142 @@
/*
Copyright (C) 1996-1997 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.
*/
#define BUTTON_ATTACK 1
#define BUTTON_JUMP 2
typedef enum {
PM_NORMAL, // normal ground movement
PM_OLD_SPECTATOR, // fly, no clip to world (QW bug)
PM_SPECTATOR, // fly, no clip to world
PM_DEAD, // no acceleration
PM_FLY, // fly, bump into walls
PM_NONE, // can't move
PM_FREEZE // can't move or look around (TODO)
} pmtype_t;
#define MAX_PHYSENTS 128
typedef struct
{
vec3_t origin;
vec3_t angles;
model_t *model; // only for bsp models
vec3_t mins, maxs; // only for non-bsp models
int info; // for client or server to identify
} physent_t;
typedef struct
{
/* int sequence; // just for debugging prints
// player state
vec3_t origin;
vec3_t angles;
vec3_t velocity;
int oldbuttons;
float waterjumptime;
qboolean dead;
int spectator;
int hullnum;
// world state
int numphysent;
physent_t physents[MAX_PHYSENTS]; // 0 should be the world
// input
usercmd_t cmd;
// results
int numtouch;
int touchindex[MAX_PHYSENTS];
qboolean onground;
int groundent;
int waterlevel;
int watertype;
pmtype_t pm_type;*/
int sequence; // just for debugging prints
// player state
vec3_t origin;
vec3_t angles;
vec3_t velocity;
qboolean jump_held;
int jump_msec; // msec since last jump
float waterjumptime;
int pm_type;
int hullnum;
// world state
int numphysent;
physent_t physents[MAX_PHYSENTS]; // 0 should be the world
// input
usercmd_t cmd;
qboolean onladder;
// results
int numtouch;
int touchindex[MAX_PHYSENTS];
qboolean onground;
int groundent; // index in physents array, only valid
// when onground is true
int waterlevel;
int watertype;
} playermove_t;
typedef struct {
float gravity;
float stopspeed;
float maxspeed;
float spectatormaxspeed;
float accelerate;
float airaccelerate;
float wateraccelerate;
float friction;
float waterfriction;
float entgravity;
float bunnyspeedcap;
float ktjump;
qboolean slidefix;
qboolean airstep;
} movevars_t;
extern movevars_t movevars;
extern playermove_t pmove;
void PM_PlayerMove (void);
void PM_Init (void);
void PM_InitBoxHull (void);
void PM_CategorizePosition (void);
int PM_HullPointContents (hull_t *hull, int num, vec3_t p);
int PM_PointContents (vec3_t point);
qboolean PM_TestPlayerPosition (vec3_t point);
#ifndef __cplusplus
struct trace_s PM_PlayerTrace (vec3_t start, vec3_t stop);
#endif

344
engine/common/pmovetst.c Normal file
View file

@ -0,0 +1,344 @@
/*
Copyright (C) 1996-1997 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.
*/
#include "quakedef.h"
static hull_t box_hull;
static dclipnode_t box_clipnodes[6];
static mplane_t box_planes[6];
extern vec3_t player_mins;
extern vec3_t player_maxs;
/*
===================
PM_InitBoxHull
Set up the planes and clipnodes so that the six floats of a bounding box
can just be stored out and get a proper hull_t structure.
===================
*/
void PM_InitBoxHull (void)
{
int i;
int side;
box_hull.clipnodes = box_clipnodes;
box_hull.planes = box_planes;
box_hull.firstclipnode = 0;
box_hull.lastclipnode = 5;
Q1BSP_SetHullFuncs(&box_hull);
for (i=0 ; i<6 ; i++)
{
box_clipnodes[i].planenum = i;
side = i&1;
box_clipnodes[i].children[side] = Q1CONTENTS_EMPTY;
if (i != 5)
box_clipnodes[i].children[side^1] = i + 1;
else
box_clipnodes[i].children[side^1] = Q1CONTENTS_SOLID;
box_planes[i].type = i>>1;
box_planes[i].normal[i>>1] = 1;
}
}
/*
===================
PM_HullForBox
To keep everything totally uniform, bounding boxes are turned into small
BSP trees instead of being compared directly.
===================
*/
hull_t *PM_HullForBox (vec3_t mins, vec3_t maxs)
{
box_planes[0].dist = maxs[0];
box_planes[1].dist = mins[0];
box_planes[2].dist = maxs[1];
box_planes[3].dist = mins[1];
box_planes[4].dist = maxs[2];
box_planes[5].dist = mins[2];
return &box_hull;
}
int PM_TransformedHullPointContents (hull_t *hull, vec3_t p, vec3_t origin, vec3_t angles)
{
vec3_t p_l, forward, up, right, temp;
VectorSubtract (p, origin, p_l);
if (!player_mins[2])
p_l[2] -= hull->clip_mins[2]+0.1;
// rotate start and end into the models frame of reference
if (hull != &box_hull &&
(angles[0] || angles[1] || angles[2]) )
{
AngleVectors (angles, forward, right, up);
VectorCopy (p_l, temp);
p_l[0] = DotProduct (temp, forward);
p_l[1] = -DotProduct (temp, right);
p_l[2] = DotProduct (temp, up);
}
return hull->funcs.HullPointContents(hull, p_l);
}
/*
==================
PM_PointContents
==================
*/
int PM_PointContents (vec3_t p)
{
hull_t *hull;
int num;
int pc;
hull = &pmove.physents[0].model->hulls[0];
pc = hull->funcs.HullPointContents(hull, p);
//we need this for e2m2 - waterjumping on to plats wouldn't work otherwise.
for (num = 1; num < pmove.numphysent; num++)
{
if (pmove.physents[num].model)
pc |= PM_TransformedHullPointContents(&pmove.physents[num].model->hulls[0], p, pmove.physents[num].origin, pmove.physents[num].angles);
}
return pc;
}
/*
===============================================================================
LINE TESTING IN HULLS
===============================================================================
*/
// 1/32 epsilon to keep floating point happy
#define DIST_EPSILON (0.03125)
vec3_t trace_extents;
qboolean PM_TransformedHullCheck (hull_t *hull, vec3_t start, vec3_t end, trace_t *trace, vec3_t origin, vec3_t angles)
{
vec3_t start_l, end_l;
vec3_t a;
vec3_t forward, right, up;
vec3_t temp;
qboolean rotated;
qboolean result;
// subtract origin offset
VectorSubtract (start, origin, start_l);
VectorSubtract (end, origin, end_l);
if (!player_mins[2]) //hmm.. hull bigger than player? Or is this hexen2?
{
start_l[2] -= hull->clip_mins[2]+0.1;
end_l[2] -= hull->clip_mins[2]+0.1;
}
// rotate start and end into the models frame of reference
if (hull != &box_hull &&
(angles[0] || angles[1] || angles[2]) )
rotated = true;
else
rotated = false;
if (rotated)
{
AngleVectors (angles, forward, right, up);
VectorCopy (start_l, temp);
start_l[0] = DotProduct (temp, forward);
start_l[1] = -DotProduct (temp, right);
start_l[2] = DotProduct (temp, up);
VectorCopy (end_l, temp);
end_l[0] = DotProduct (temp, forward);
end_l[1] = -DotProduct (temp, right);
end_l[2] = DotProduct (temp, up);
}
// sweep the box through the model
result = hull->funcs.RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, trace);
if (rotated && trace->fraction != 1.0)
{
// FIXME: figure out how to do this with existing angles
// VectorNegate (angles, a);
a[0] = angles[0];
a[1] = angles[1];
a[2] = angles[2];
AngleVectors (a, forward, right, up);
VectorCopy (trace->plane.normal, temp);
trace->plane.normal[0] = DotProduct (temp, forward);
trace->plane.normal[1] = -DotProduct (temp, right);
trace->plane.normal[2] = DotProduct (temp, up);
}
trace->endpos[0] = start[0] + trace->fraction * (end[0] - start[0]);
trace->endpos[1] = start[1] + trace->fraction * (end[1] - start[1]);
trace->endpos[2] = start[2] + trace->fraction * (end[2] - start[2]);
// if (!player_mins[2]) //hmm.. hull bigger than player? Or is this hexen2?
// trace->endpos[2] += hull->clip_mins[2]+0.1;
return result;
}
/*
================
PM_TestPlayerPosition
Returns false if the given player position is not valid (in solid)
================
*/
int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles);
qboolean PM_TestPlayerPosition (vec3_t pos)
{
int i;
physent_t *pe;
vec3_t mins, maxs;
hull_t *hull;
for (i=0 ; i< pmove.numphysent ; i++)
{
pe = &pmove.physents[i];
// get the clipping hull
if (pe->model)
{
#ifdef Q2BSPS
if (pe->model->fromgame == fg_quake2 || pe->model->fromgame == fg_quake3)
{
trace_t trace = CM_TransformedBoxTrace(pos, pos, player_mins, player_maxs, pe->model->hulls[0].firstclipnode, MASK_PLAYERSOLID, pe->origin, pe->angles);
if (trace.fraction == 0)
return false;
continue;
}
#endif
hull = &pe->model->hulls[pmove.hullnum];
if (!hull->available || !hull->planes || !hull->clipnodes)
hull = &pe->model->hulls[1];
}
else
{
VectorSubtract (pe->mins, player_maxs, mins);
VectorSubtract (pe->maxs, player_mins, maxs);
hull = PM_HullForBox (mins, maxs);
}
if (PM_TransformedHullPointContents (hull, pos, pe->origin, pe->angles) & FTECONTENTS_SOLID)
return false;
}
return true;
}
/*
================
PM_PlayerTrace
================
*/
trace_t PM_PlayerTrace (vec3_t start, vec3_t end)
{
trace_t trace, total;
hull_t *hull;
int i;
physent_t *pe;
vec3_t mins, maxs;
// fill in a default trace
memset (&total, 0, sizeof(trace_t));
total.fraction = 1;
total.entnum = -1;
VectorCopy (end, total.endpos);
for (i=0 ; i< pmove.numphysent ; i++)
{
pe = &pmove.physents[i];
// get the clipping hull
if (pe->model)
{
hull = &pmove.physents[i].model->hulls[pmove.hullnum];
if (!hull->available || !hull->clipnodes || !hull->planes)
hull = &pmove.physents[i].model->hulls[1]; //fallback
}
else
{
VectorSubtract (pe->mins, player_maxs, mins);
VectorSubtract (pe->maxs, player_mins, maxs);
hull = PM_HullForBox (mins, maxs);
}
// fill in a default trace
memset (&trace, 0, sizeof(trace_t));
trace.fraction = 1;
trace.allsolid = true;
// trace.startsolid = true;
VectorCopy (end, trace.endpos);
// trace a line through the apropriate clipping hull
#ifdef Q2BSPS
if (pmove.physents[i].model && (pmove.physents[i].model->fromgame == fg_quake2 || pmove.physents[i].model->fromgame == fg_quake3))
{
trace_t tr;
tr = CM_TransformedBoxTrace (start, end, player_mins, player_maxs, pmove.physents[i].model->hulls[0].firstclipnode, MASK_PLAYERSOLID, pe->origin, pe->angles);
trace.startsolid = tr.startsolid;
trace.allsolid = tr.allsolid;
trace.fraction = tr.fraction;
memcpy(&trace.plane, &tr.plane, sizeof(tr.plane));
VectorCopy(tr.endpos, trace.endpos);
}
else
#endif
PM_TransformedHullCheck (hull, start, end, &trace, pe->origin, pe->angles);
if (trace.allsolid)
trace.startsolid = true;
if (trace.startsolid)
trace.fraction = 0;
// did we clip the move?
if (trace.fraction < total.fraction)
{
// fix trace up by the offset
total = trace;
total.entnum = i;
}
}
return total;
}

395
engine/common/q1bsp.c Normal file
View file

@ -0,0 +1,395 @@
#include "quakedef.h"
/*
============================================================================
Physics functions (common)
*/
#if !id386
/*
==================
SV_HullPointContents
==================
*/
static int Q1_HullPointContents (hull_t *hull, int num, vec3_t p)
{
float d;
dclipnode_t *node;
mplane_t *plane;
while (num >= 0)
{
if (num < hull->firstclipnode || num > hull->lastclipnode)
SV_Error ("SV_HullPointContents: bad node number");
node = hull->clipnodes + num;
plane = hull->planes + node->planenum;
if (plane->type < 3)
d = p[plane->type] - plane->dist;
else
d = DotProduct (plane->normal, p) - plane->dist;
if (d < 0)
num = node->children[1];
else
num = node->children[0];
}
return num;
}
#else
int VARGS Q1_HullPointContents (hull_t *hull, int num, vec3_t p);
#endif // !id386
#define DIST_EPSILON (0.03125)
qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
{
dclipnode_t *node;
mplane_t *plane;
float t1, t2;
float frac;
int i;
vec3_t mid;
int side;
float midf;
// check for empty
if (num < 0)
{
if (num != Q1CONTENTS_SOLID)
{
trace->allsolid = false;
if (num == Q1CONTENTS_EMPTY)
trace->inopen = true;
else
trace->inwater = true;
}
else
trace->startsolid = true;
return true; // empty
}
if (num < hull->firstclipnode || num > hull->lastclipnode)
SV_Error ("Q1BSP_RecursiveHullCheck: bad node number");
//
// find the point distances
//
node = hull->clipnodes + num;
plane = hull->planes + node->planenum;
if (plane->type < 3)
{
t1 = p1[plane->type] - plane->dist;
t2 = p2[plane->type] - plane->dist;
}
else
{
t1 = DotProduct (plane->normal, p1) - plane->dist;
t2 = DotProduct (plane->normal, p2) - plane->dist;
}
#if 1
if (t1 >= 0 && t2 >= 0)
return Q1BSP_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
if (t1 < 0 && t2 < 0)
return Q1BSP_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
#else
if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) )
return Q1BSP_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) )
return Q1BSP_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
#endif
// put the crosspoint DIST_EPSILON pixels on the near side
if (t1 < 0)
frac = (t1 + DIST_EPSILON)/(t1-t2);
else
frac = (t1 - DIST_EPSILON)/(t1-t2);
if (frac < 0)
frac = 0;
if (frac > 1)
frac = 1;
midf = p1f + (p2f - p1f)*frac;
for (i=0 ; i<3 ; i++)
mid[i] = p1[i] + frac*(p2[i] - p1[i]);
side = (t1 < 0);
// move up to the node
if (!Q1BSP_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) )
return false;
#ifdef PARANOID
if (Q1BSP_RecursiveHullCheck (sv_hullmodel, mid, node->children[side])
== Q1CONTENTS_SOLID)
{
Con_Printf ("mid PointInHullSolid\n");
return false;
}
#endif
if (Q1_HullPointContents (hull, node->children[side^1], mid)
!= Q1CONTENTS_SOLID)
// go past the node
return Q1BSP_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace);
if (trace->allsolid)
return false; // never got out of the solid area
//==================
// the other side of the node is solid, this is the impact point
//==================
if (!side)
{
VectorCopy (plane->normal, trace->plane.normal);
trace->plane.dist = plane->dist;
}
else
{
VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
trace->plane.dist = -plane->dist;
}
while (Q1_HullPointContents (hull, hull->firstclipnode, mid)
== Q1CONTENTS_SOLID)
{ // shouldn't really happen, but does occasionally
frac -= 0.1;
if (frac < 0)
{
trace->fraction = midf;
VectorCopy (mid, trace->endpos);
Con_DPrintf ("backup past 0\n");
return false;
}
midf = p1f + (p2f - p1f)*frac;
for (i=0 ; i<3 ; i++)
mid[i] = p1[i] + frac*(p2[i] - p1[i]);
}
trace->fraction = midf;
VectorCopy (mid, trace->endpos);
return false;
}
int Q1BSP_HullPointContents(hull_t *hull, vec3_t p)
{
switch(Q1_HullPointContents(hull, hull->firstclipnode, p))
{
case Q1CONTENTS_EMPTY:
return FTECONTENTS_EMPTY;
case Q1CONTENTS_SOLID:
return FTECONTENTS_SOLID;
case Q1CONTENTS_WATER:
return FTECONTENTS_WATER;
case Q1CONTENTS_SLIME:
return FTECONTENTS_SLIME;
case Q1CONTENTS_LAVA:
return FTECONTENTS_LAVA;
case Q1CONTENTS_SKY:
return FTECONTENTS_SKY;
default:
Sys_Error("Q1_PointContents: Unknown contents type");
return FTECONTENTS_SOLID;
}
}
void Q1BSP_SetHullFuncs(hull_t *hull)
{
hull->funcs.RecursiveHullCheck = Q1BSP_RecursiveHullCheck;
hull->funcs.HullPointContents = Q1BSP_HullPointContents;
}
/*
Physics functions (common)
============================================================================
Rendering functions (Client only)
*/
#ifndef SERVERONLY
extern int r_dlightframecount;
//goes through the nodes marking the surfaces near the dynamic light as lit.
void Q1BSP_MarkLights (dlight_t *light, int bit, mnode_t *node)
{
mplane_t *splitplane;
float dist;
msurface_t *surf;
int i;
if (node->contents < 0)
return;
splitplane = node->plane;
dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
if (dist > light->radius)
{
Q1BSP_MarkLights (light, bit, node->children[0]);
return;
}
if (dist < -light->radius)
{
Q1BSP_MarkLights (light, bit, node->children[1]);
return;
}
// mark the polygons
surf = cl.worldmodel->surfaces + node->firstsurface;
for (i=0 ; i<node->numsurfaces ; i++, surf++)
{
if (surf->dlightframe != r_dlightframecount)
{
surf->dlightbits = 0;
surf->dlightframe = r_dlightframecount;
}
surf->dlightbits |= bit;
}
Q1BSP_MarkLights (light, bit, node->children[0]);
Q1BSP_MarkLights (light, bit, node->children[1]);
}
#endif
/*
Rendering functions (Client only)
==============================================================================
Server only functions
*/
extern int fatbytes;
extern qbyte fatpvs[(MAX_MAP_LEAFS+1)/4];
//does the recursive work of Q1BSP_FatPVS
void SV_Q1BSP_AddToFatPVS (vec3_t org, mnode_t *node)
{
int i;
qbyte *pvs;
mplane_t *plane;
float d;
while (1)
{
// if this is a leaf, accumulate the pvs bits
if (node->contents < 0)
{
if (node->contents != Q1CONTENTS_SOLID)
{
pvs = Mod_Q1LeafPVS ( (mleaf_t *)node, sv.worldmodel, NULL);
for (i=0 ; i<fatbytes ; i++)
fatpvs[i] |= pvs[i];
}
return;
}
plane = node->plane;
d = DotProduct (org, plane->normal) - plane->dist;
if (d > 8)
node = node->children[0];
else if (d < -8)
node = node->children[1];
else
{ // go down both
SV_Q1BSP_AddToFatPVS (org, node->children[0]);
node = node->children[1];
}
}
}
/*
=============
Q1BSP_FatPVS
Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the
given point.
=============
*/
void Q1BSP_FatPVS (vec3_t org, qboolean add)
{
fatbytes = (sv.worldmodel->numleafs+31)>>3;
if (!add)
Q_memset (fatpvs, 0, fatbytes);
SV_Q1BSP_AddToFatPVS (org, sv.worldmodel->nodes);
}
qboolean Q1BSP_EdictInFatPVS(edict_t *ent)
{
int i;
for (i=0 ; i < ent->num_leafs ; i++)
if (fatpvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
return true; //we might be able to see this one.
return false; //none of this ents leafs were visible, so neither is the ent.
}
/*
===============
SV_FindTouchedLeafs
Links the edict to the right leafs so we can get it's potential visability.
===============
*/
void Q1BSP_RFindTouchedLeafs (edict_t *ent, mnode_t *node)
{
mplane_t *splitplane;
mleaf_t *leaf;
int sides;
int leafnum;
if (node->contents == Q1CONTENTS_SOLID)
return;
// add an efrag if the node is a leaf
if ( node->contents < 0)
{
if (ent->num_leafs == MAX_ENT_LEAFS)
return;
leaf = (mleaf_t *)node;
leafnum = leaf - sv.worldmodel->leafs - 1;
ent->leafnums[ent->num_leafs] = leafnum;
ent->num_leafs++;
return;
}
// NODE_MIXED
splitplane = node->plane;
sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane);
// recurse down the contacted sides
if (sides & 1)
Q1BSP_RFindTouchedLeafs (ent, node->children[0]);
if (sides & 2)
Q1BSP_RFindTouchedLeafs (ent, node->children[1]);
}
void Q1BSP_FindTouchedLeafs(edict_t *ent)
{
ent->num_leafs = 0;
if (ent->v.modelindex)
Q1BSP_RFindTouchedLeafs (ent, sv.worldmodel->nodes);
}
/*
Server only functions
==============================================================================
*/

1370
engine/common/q2pmove.c Normal file

File diff suppressed because it is too large Load diff

289
engine/common/quakeasm.h Normal file
View file

@ -0,0 +1,289 @@
/*
Copyright (C) 1996-1997 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.
*/
//
// quakeasm.h: general asm header file
//
#ifdef _WIN32
#define __i386__ 1
#endif
#if defined(NOASM)
#define id386 0
#else
#ifdef __i386__
#define id386 1
#else
#define id386 0
#endif
#endif
#ifdef MQUAKE
#define SWQUAKE
#define GLQUAKE
#endif
// !!! must be kept the same as in d_iface.h !!!
#define TRANSPARENT_COLOR 255
#ifndef NeXT
#ifdef SWQUAKE
.extern C(d_zistepu)
.extern C(d_pzbuffer)
.extern C(d_zistepv)
.extern C(d_zrowbytes)
.extern C(d_ziorigin)
.extern C(r_turb_s)
.extern C(r_turb_t)
.extern C(r_turb_pdest)
.extern C(r_turb_spancount)
.extern C(r_turb_turb)
.extern C(r_turb_pbase)
.extern C(r_turb_sstep)
.extern C(r_turb_tstep)
.extern C(r_bmodelactive)
.extern C(d_sdivzstepu)
.extern C(d_tdivzstepu)
.extern C(d_sdivzstepv)
.extern C(d_tdivzstepv)
.extern C(d_sdivzorigin)
.extern C(d_tdivzorigin)
.extern C(sadjust)
.extern C(tadjust)
.extern C(bbextents)
.extern C(bbextentt)
.extern C(cacheblock)
.extern C(d_viewbuffer)
.extern C(cachewidth)
.extern C(d_pzbuffer)
.extern C(d_zrowbytes)
.extern C(d_zwidth)
.extern C(d_scantable)
.extern C(r_lightptr)
.extern C(r_numvblocks)
.extern C(prowdestbase)
.extern C(pbasesource)
.extern C(r_lightwidth)
.extern C(lightright)
.extern C(lightrightstep)
.extern C(lightdeltastep)
.extern C(lightdelta)
.extern C(lightright)
.extern C(lightdelta)
.extern C(sourcetstep)
.extern C(surfrowbytes)
.extern C(lightrightstep)
.extern C(lightdeltastep)
.extern C(r_sourcemax)
.extern C(r_stepback)
.extern C(colormap)
.extern C(blocksize)
.extern C(sourcesstep)
.extern C(lightleft)
.extern C(blockdivshift)
.extern C(blockdivmask)
.extern C(lightleftstep)
.extern C(r_origin)
.extern C(r_ppn)
.extern C(r_pup)
.extern C(r_pright)
.extern C(ycenter)
.extern C(xcenter)
.extern C(d_vrectbottom_particle)
.extern C(d_vrectright_particle)
.extern C(d_vrecty)
.extern C(d_vrectx)
.extern C(d_pix_shift)
.extern C(d_pix_min)
.extern C(d_pix_max)
.extern C(d_y_aspect_shift)
.extern C(screenwidth)
.extern C(r_leftclipped)
.extern C(r_leftenter)
.extern C(r_rightclipped)
.extern C(r_rightenter)
.extern C(modelorg)
.extern C(xscale)
.extern C(r_refdef)
.extern C(yscale)
.extern C(r_leftexit)
.extern C(r_rightexit)
.extern C(r_lastvertvalid)
.extern C(cacheoffset)
.extern C(newedges)
.extern C(removeedges)
.extern C(r_pedge)
.extern C(r_framecount)
.extern C(r_u1)
.extern C(r_emitted)
.extern C(edge_p)
.extern C(surface_p)
.extern C(surfaces)
.extern C(r_lzi1)
.extern C(r_v1)
.extern C(r_ceilv1)
.extern C(r_nearzi)
.extern C(r_nearzionly)
.extern C(edge_aftertail)
.extern C(edge_tail)
.extern C(current_iv)
.extern C(edge_head_u_shift20)
.extern C(span_p)
.extern C(edge_head)
.extern C(fv)
.extern C(edge_tail_u_shift20)
.extern C(r_apoldverts) //trivertex_t
.extern C(r_apnewverts)
.extern C(r_afrntlerp) //float of quantity.
.extern C(r_abacklerp)
.extern C(r_anumverts)
.extern C(aliastransform)
.extern C(r_avertexnormals)
.extern C(r_plightvec)
.extern C(r_ambientlight)
.extern C(r_shadelight)
.extern C(aliasxcenter)
.extern C(aliasycenter)
.extern C(a_sstepxfrac)
.extern C(r_affinetridesc)
.extern C(acolormap)
.extern C(d_pcolormap)
.extern C(r_affinetridesc)
.extern C(d_sfrac)
.extern C(d_ptex)
.extern C(d_pedgespanpackage)
.extern C(d_tfrac)
.extern C(d_light)
.extern C(d_zi)
.extern C(d_pdest)
.extern C(d_pz)
.extern C(d_aspancount)
.extern C(erroradjustup)
.extern C(errorterm)
.extern C(d_xdenom)
.extern C(r_p0)
.extern C(r_p1)
.extern C(r_p2)
.extern C(a_tstepxfrac)
.extern C(r_sstepx)
.extern C(r_tstepx)
.extern C(a_ststepxwhole)
.extern C(zspantable)
.extern C(skintable)
.extern C(r_zistepx)
.extern C(erroradjustdown)
.extern C(d_countextrastep)
.extern C(ubasestep)
.extern C(a_ststepxwhole)
.extern C(a_tstepxfrac)
.extern C(r_lstepx)
.extern C(a_spans)
.extern C(erroradjustdown)
.extern C(d_pdestextrastep)
.extern C(d_pzextrastep)
.extern C(d_sfracextrastep)
.extern C(d_ptexextrastep)
.extern C(d_countextrastep)
.extern C(d_tfracextrastep)
.extern C(d_lightextrastep)
.extern C(d_ziextrastep)
.extern C(d_pdestbasestep)
.extern C(d_pzbasestep)
.extern C(d_sfracbasestep)
.extern C(d_ptexbasestep)
.extern C(ubasestep)
.extern C(d_tfracbasestep)
.extern C(d_lightbasestep)
.extern C(d_zibasestep)
.extern C(zspantable)
.extern C(r_lstepy)
.extern C(r_sstepy)
.extern C(r_tstepy)
.extern C(r_zistepy)
.extern C(D_PolysetSetEdgeTable)
.extern C(D_RasterizeAliasPolySmooth)
.extern float_point5
.extern Float2ToThe31nd
.extern izistep
.extern izi
.extern FloatMinus2ToThe31nd
.extern float_1
.extern float_particle_z_clip
.extern float_minus_1
.extern float_0
.extern fp_16
.extern fp_64k
.extern fp_1m
.extern fp_1m_minus_1
.extern fp_8
.extern entryvec_table
.extern advancetable
.extern sstep
.extern tstep
.extern pspantemp
.extern counttemp
.extern jumptemp
.extern reciprocal_table
.extern DP_Count
.extern DP_u
.extern DP_v
.extern DP_32768
.extern DP_Color
.extern DP_Pix
.extern DP_EntryTable
.extern pbase
.extern s
.extern t
.extern sfracf
.extern tfracf
.extern snext
.extern tnext
.extern spancountminus1
.extern zi16stepu
.extern sdivz16stepu
.extern tdivz16stepu
.extern zi8stepu
.extern sdivz8stepu
.extern tdivz8stepu
.extern reciprocal_table_16
.extern entryvec_table_16
.extern ceil_cw
.extern single_cw
.extern fp_64kx64k
.extern pz
.extern spr8entryvec_table
#endif
.extern C(snd_scaletable)
.extern C(paintbuffer)
// .extern C(snd_linear_count)
.extern C(cursndcard)
.extern C(snd_p)
.extern C(snd_vol)
.extern C(snd_out)
.extern C(vright)
.extern C(vup)
.extern C(vpn)
.extern C(BOPS_Error)
#endif

186
engine/common/tlout.h Normal file
View file

@ -0,0 +1,186 @@
"STL_LANGUAGENAME \"English\"\n"
"STL_CLIENTCONNECTED \"client %s connected\\n\"\n"
"STL_SPECTATORCONNECTED \"spectator %s connected\\n\"\n"
"STL_RECORDEDCLIENTCONNECTED \"recorded client %s connected\\n\"\n"
"STL_RECORDEDSPECTATORCONNECTED \"recorded spectator %s connected\\n\"\n"
"STL_CLIENTWASBANNED \"%s was banned\\n\"\n"
"STL_YOUWEREBANNED \"You were banned\\n\"\n"
"STL_YOUAREBANNED \"You are still banned\\n\"\n"
"STL_CLIENTTIMEDOUT \"Client %s timed out\\n\"\n"
"STL_LOADZOMIBETIMEDOUT \"LoadZombie %s timed out\\n\"\n"
"STL_CLIENTWASKICKED \"%s was kicked\\n\"\n"
"STL_YOUWEREKICKED \"You were kicked\\n\"\n"
"STL_YOUWEREKICKEDNAMESPAM \"You were kicked for name spamming\\n\"\n"
"STL_CLIENTKICKEDNAMESPAM \"%s was kicked for name spamming\\n\"\n"
"STL_GODON \"godmode ON\\n\"\n"
"STL_GODOFF \"godmode OFF\\n\"\n"
"STL_NOCLIPON \"noclip ON\\n\"\n"
"STL_NOCLIPOFF \"noclip OFF\"\n"
"STL_CLIENTISCUFFEDPERMANENTLY \"%s is still cuffed\\n\"\n"
"STL_CLIENTISCUFFED \"%s is was cuffed\\n\"\n"
"STL_CLIENTISSTILLCUFFED \"%s is still cuffed\\n\"\n"
"STL_YOUWERECUFFED \"You were cuffed\\n\"\n"
"STL_YOUARNTCUFFED \"You are no longer cuffed\\n\"\n"
"STL_CLIENTISCRIPPLEDPERMANENTLY \"%s is now crippled permanently\\n\"\n"
"STL_CLIENTISCRIPPLED \"%s is crippled\\n\"\n"
"STL_CLIENTISSTILLCRIPPLED \"%s is still crippled\\n\"\n"
"STL_YOUWERECLIPPLED \"You have been crippled\\n\"\n"
"STL_YOUARNTCRIPPLED \"You are no longer crippled\\n\"\n"
"STL_CLIENTISMUTEDPERMANENTLY \"%s was muted permanently\\n\"\n"
"STL_CLIENTISMUTED \"%s was muted\\n\"\n"
"STL_CLIENTISSTILLMUTED \"%s is muted (still)\\n\"\n"
"STL_YOUAREMUTED \"%s is muted\\n\"\n"
"STL_YOUARNTMUTED \"You are no longer muted\\n\"\n"
"STL_NONAMEASMUTE \"Muted players may not change thier names\\n\"\n"
"STL_MUTEDVOTE \"Sorry, you cannot vote when muted as it may allow you to send a message.\\n\"\n"
"STL_MUTEDCHAT \"You cannot chat while muted\\n\"\n"
"STL_FLOODPROTACTIVE \"floodprot: You can't talk for %i seconds\\n\"\n"
"STL_FLOODPROTTIME \"You can't talk for %i more seconds\\n\"\n"
"STL_BUFFERPROTECTION \"buffer overflow protection: failiure\\n\"\n"
"STL_FIRSTGREETING \"Welcome %s. Your time on this server is being logged and ranked\\n\"\n"
"STL_SHORTGREETING \"Welcome back %s. You have previously spent %i mins connected\\n\"\n"
"STL_BIGGREETING \"Welcome back %s. You have previously spent %i:%i hours connected\\n\"\n"
"STL_POSSIBLEMODELCHEAT \"warning: %s eyes or player model does not match\\n\"\n"
"STL_MAPCHEAT \"Map model file does not match (%s), %i != %i/%i.\\nYou may need a new version of the map, or the proper install files.\\n\"\n"
"STL_INVALIDTRACKCLIENT \"invalid player to track\\n\"\n"
"STL_BADNAME \"Can't change name - new is invalid\\n\"\n"
"STL_CLIENTNAMECHANGE \"%s changed thier name to %s\\n\"\n"
"STL_SERVERPAUSED \"server is paused\\n\"\n"
"STL_UPLOADDENIED \"Upload denied\\n\"\n"
"STL_NAMEDCLIENTDOESNTEXIST \"client does not exist\\n\"\n"
"STL_NOSUISIDEWHENDEAD \"Can't suiside -- Already dead\\n\"\n"
"STL_CANTPAUSE \"Can't pause. Not allowed\\n\"\n"
"STL_CANTPAUSESPEC \"Spectators may not pause the game\\n\"\n"
"STL_CLIENTPAUSED \"%s paused the game\\n\"\n"
"STL_CLIENTUNPAUSED \"%s unpaused the game\\n\"\n"
"STL_CLIENTLESSUNPAUSE \"pause released due to empty server\\n\"\n"
"STL_CURRENTRATE \"current rate is %i\\n\"\n"
"STL_RATESETTO \"rate is changed to %i\\n\"\n"
"STL_CURRENTMSGLEVEL \"current msg level is %i\\n\"\n"
"STL_MSGLEVELSET \"new msg level set to %i\\n\"\n"
"STL_GAMESAVED \"Server has saved the game\\n\"\n"
"STL_CLIENTDROPPED \"%s dropped\\n\"\n"
"STL_SNAPREFUSED \"%s refused remote screenshot\\n\"\n"
"STL_FINALVOTE \"%s casts final vote for '%s'\\n\"\n"
"STL_VOTE \"%s casts a vote for '%s'\\n\"\n"
"STL_SPEEDCHEATKICKED \"%s was kicked for speedcheating (%s)\\n\"\n"
"STL_SPEEDCHEATPOSSIBLE \"Speed cheat possibility, analyzing:\\n %d %.1f %d for: %s\\n\"\n"
"STL_INITED \"======== QuakeWorld Initialized ========\\n\"\n"
"STL_BACKBUFSET \"WARNING %s: [SV_New] Back buffered (%d0, clearing)\\n\"\n"
"STL_MESSAGEOVERFLOW \"WARNING: backbuf [%d] reliable overflow for %s\\n\"\n"
"STL_BUILDINGPHS \"Building PHS...\\n\"\n"
"STL_PHSINFO \"Average leafs visible / hearable / total: %i / %i / %i\\n\"\n"
"STL_BREAKSTATEMENT \"Break Statement\\n\"\n"
"STL_BADSPRINT \"tried to sprint to a non-client\\n\"\n"
"STL_NOPRECACHE \"no precache: %s\\n\"\n"
"STL_CANTFREEWORLD \"cannot free world entity\\n\"\n"
"STL_CANTFREEPLAYERS \"cannot free player entities\\n\"\n"
"STL_COMPILEROVER \"Compile took %f secs\\n\"\n"
"STL_EDICTWASFREE \"%s edict was free\\n\"\n"
"STL_NOFREEEDICTS \"WARNING: no free edicts\\n\"\n"
"STL_NEEDCHEATPARM \"You must run the server with -cheats to enable this command.\\n\"\n"
"STL_USERDOESNTEXIST \"Couldn't find user number %s\\n\"\n"
"STL_MAPCOMMANDUSAGE \"map <levelname> : continue game on a new level\\n\"\n"
"STL_NOVOTING \"Voting was dissallowed\\n\"\n"
"STL_BADVOTE \"You arn't allowed to vote for that\\n\"\n"
"STL_VOTESREMOVED \"All votes removed.\\n\"\n"
"STL_OLDVOTEREMOVED \"Old vote removed.\\n\"\n"
"TL_EXECING \"execing %s\\n\"\n"
"TL_EXECCOMMANDUSAGE \"exec <filename> : execute a script file\\n\"\n"
"TL_EXECFAILED \"couldn't exec %s\\n\"\n"
"TL_FUNCOVERFLOW \"%s: overflow\\n\"\n"
"TL_CURRENTALIASCOMMANDS \"Current alias commands:\\n\"\n"
"TL_ALIASNAMETOOLONG \"Alias name is too long\\n\"\n"
"TL_ALIASRESTRICTIONLEVELERROR \"Alias is already bound with a higher restriction\\n\"\n"
"TL_ALIASLEVELCOMMANDUSAGE \"aliaslevel <var> [execlevel]\\n\"\n"
"TL_ALIASNOTFOUND \"Alias not found\\n\"\n"
"TL_ALIASRAISELEVELERROR \"You arn't allowed to raise a command above your own level\\n\"\n"
"TL_ALIASRESTRICTIONLEVELWARN \"WARNING: %s is available to all clients, any client will be able to use it at the new level.\\n\"\n"
"TL_ALIASRESTRICTLEVEL \"alias %s is set to run at the user level of %i\\n\"\n"
"TL_ALIASLIST \"Alias list:\\n\"\n"
"TL_COMMANDLISTHEADER \"Command list:\\n\"\n"
"TL_CVARLISTHEADER \"CVar list:\\n\"\n"
"TL_RESTRICTCOMMANDRAISE \"You arn't allowed to raise a command above your own level\\n\"\n"
"TL_RESTRICTCOMMANDTOOHIGH \"You arn't allowed to alter a level above your own\\n\"\n"
"TL_RESTRICTCURRENTLEVEL \"%s is restricted to %i\\n\"\n"
"TL_RESTRICTCURRENTLEVELDEFAULT \"%s is restricted to rcon_level (%i)\\n\"\n"
"TL_RESTRICTNOTDEFINED \"restrict: %s not defined\\n\"\n"
"TL_WASRESTIRCTED \"%s was restricted.\\n\"\n"
"TL_COMMANDNOTDEFINED \"Unknown command \\\"%s\\\"\\n\"\n"
"TL_IFSYNTAX \"if <condition> <statement> [elseif <condition> <statement>] [...] [else <statement>]\\n\"\n"
"TL_IFSYNTAXERROR \"Not terminated\\n\"\n"
"TL_SETSYNTAX \"set <var> <equation>\\n\"\n"
"TL_CANTXNOTCONNECTED \"Can't \\\"%s\\\", not connected\\n\"\n"
"TL_SHAREWAREVERSION \"Playing shareware version.\\n\"\n"
"TL_REGISTEREDVERSION \"Playing registered version.\\n\"\n"
"TL_CURRENTSEARCHPATH \"Current search path:\\n\"\n"
"TL_SERACHPATHISPACK \"%s (%i files)\\n\"\n"
"TL_SERACHPATHISZIP \"%s (%i files)\\n\"\n"
"TL_COMPRESSEDFILEOPENFAILED \"Tried opening a handle to a compressed stream - %s\\n\"\n"
"TL_ADDEDPACKFILE \"Added packfile %s (%i files)\\n\"\n"
"TL_COULDNTOPENZIP \"Failed opening zipfile \\\"%s\\\" corrupt?\\n\"\n"
"TL_ADDEDZIPFILE \"Added zipfile %s (%i files)\\n\"\n"
"TL_GAMEDIRAINTPATH \"Gamedir should be a single filename, not a path\\n\"\n"
"TL_KEYHASSLASH \"Can't use a key with a \\\\\\n\"\n"
"TL_KEYHASQUOTE \"Can't use a key with a \\\"\\n\"\n"
"TL_KEYTOOLONG \"Keys and values must be < 64 characters.\\n\"\n"
"TL_INFOSTRINGTOOLONG \"Info string length exceeded\\n\"\n"
"TL_STARKEYPROTECTED \"Can't set * keys\\n\"\n"
"TL_KEYHASNOVALUE \"MISSING VALUE\\n\"\n"
"TL_OVERSIZEPACKETFROM \"Warning: Oversize packet from %s\\n\"\n"
"TL_CONNECTIONLOSTORABORTED \"Connection lost or aborted\\n\"\n"
"TL_NETGETPACKETERROR \"NET_GetPacket: %s\\n\"\n"
"TL_NETSENDERROR \"NET_SendPacket ERROR: %i\\n\"\n"
"TL_NETBINDINTERFACE \"Binding to IP Interface Address of %s\\n\"\n"
"TL_IPADDRESSIS \"IP address %s\\n\"\n"
"TL_UDPINITED \"UDP Initialized\\n\"\n"
"TL_SERVERPORTINITED \"Server port Initialized\\n\"\n"
"TL_CLIENTPORTINITED \"Client port Initialized\\n\"\n"
"TL_OUTMESSAGEOVERFLOW \"%s:Outgoing message overflow\\n\"\n"
"TL_OUTOFORDERPACKET \"%s:Out of order packet %i at %i\\n\"\n"
"TL_DROPPEDPACKETCOUNT \"%s:Dropped %i packets at %i\\n\"\n"
"STL_SERVERUNSPAWNED \"Server ended\\n\"\n"
"STL_SERVERSPAWNED \"Server spawned.\\n\"\n"
"TL_EXEDATETIME \"Exe: %s %s\\n\"\n"
"TL_HEAPSIZE \"%4.1f megabyte heap\\n\"\n"
"TL_VERSION2 \"\\nVersion %4.2f (Build %04d)\\n\\n\"\n"
"TL_SERVERVERSION2 \"\\n%s Version %4.2f (Build %04d)\\n\\n\"\n"
"STL_SAVESYNTAX \"save <savename> : save a game\\n\"\n"
"STL_NORELATIVEPATHS \"Relative pathnames are not allowed.\\n\"\n"
"STL_SAVEGAMETO \"Saving game to %s...\\n\"\n"
"STL_ERRORCOULDNTOPEN \"ERROR: couldn't open.\\n\"\n"
"STL_SAVEDONE \"done.\\n\"\n"
"STL_LOADSYNTAX \"load <savename> : load a game\\n\"\n"
"STL_LOADGAMEFROM \"Loading game from %s...\\n\"\n"
"STL_BADSAVEVERSION \"Savegame is version %i, not %i\\n\"\n"
"STL_LOADFAILED \"Couldn't load map\\n\"\n"
"STL_NOMATERMODE \"Setting nomaster mode.\\n\"\n"
"STL_MASTERAT \"Master server at %s\\n\"\n"
"STL_SENDINGPING \"Sending a ping.\\n\"\n"
"STL_SHUTTINGDOWN \"Shutting down.\\n\"\n"
"STL_LOGGINGOFF \"File logging off.\\n\"\n"
"STL_LOGGINGTO \"Logging text to %s.\\n\"\n"
"STL_FLOGGINGOFF \"Frag file logging off.\\n\"\n"
"STL_FLOGGINGFAILED \"Can't open any logfiles.\\n\"\n"
"STL_FLOGGINGTO \"Logging frags to %s.\\n\"\n"
"STL_USERIDNOTONSERVER \"Userid %i is not on the server\\n\"\n"
"STL_CANTFINDMAP \"Can't find %s\\n\"\n"
"STL_SERVERINFOSETTINGS \"Server info settings:\\n\"\n"
"STL_SERVERINFOSYNTAX \"usage: serverinfo [ <key> <value> ]\\n\"\n"
"STL_LOCALINFOSETTINGS \"Local info settings:\\n\"\n"
"STL_LOCALINFOSYNTAX \"usage: localinfo [ <key> <value> ]\\n\"\n"
"STL_USERINFOSYNTAX \"Usage: info <userid>\\n\"\n"
"STL_FLOODPROTSETTINGS \"Current floodprot settings: \\nAfter %d msgs per %d seconds, silence for %d seconds\\n\"\n"
"STL_FLOODPROTNOTON \"No floodprots enabled.\\n\"\n"
"STL_FLOODPROTSYNTAX \"Usage: floodprot <# of messages> <per # of seconds> <seconds to silence>\\nUse floodprotmsg to set a custom message to say to the flooder.\\n\"\n"
"STL_NONEGATIVEVALUES \"All values must be positive numbers\\n\"\n"
"STL_TRACK10PLUSSMESSAGES \"Can only track up to 10 messages.\\n\"\n"
"STL_FLOODPROTCURRENTMESSAGE \"Current msg: %s\\n\"\n"
"STL_FLOODPROTMESSAGESYNTAX \"Usage: floodprotmsg \\\"<message>\\\"\\n\"\n"
"STL_CURRENTGAMEDIR \"Current gamedir: %s\\n\"\n"
"STL_SVGAMEDIRUSAGE \"Usage: sv_gamedir <newgamedir>\\n\"\n"
"STL_GAMEDIRCANTBEPATH \"*Gamedir should be a single filename, not a path\\n\"\n"
"STL_GAMEDIRUSAGE \"Usage: gamedir <newgamedir>\\n\"\n"
"STL_SNAPTOOMANYFILES \"Snap: Couldn't create a file, clean some out.\\n\"\n"
"STL_SNAPREQUEST \"Requesting snap from user %d...\\n\"\n"
"STL_SNAPUSAGE \"Usage: snap <userid>\\n\"\n"

1508
engine/common/zone.c Normal file

File diff suppressed because it is too large Load diff

157
engine/common/zone.h Normal file
View file

@ -0,0 +1,157 @@
/*
Copyright (C) 1996-1997 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.
*/
/*
memory allocation
H_??? The hunk manages the entire memory block given to quake. It must be
contiguous. Memory can be allocated from either the low or high end in a
stack fashion. The only way memory is released is by resetting one of the
pointers.
Hunk allocations should be given a name, so the Hunk_Print () function
can display usage.
Hunk allocations are guaranteed to be 16 byte aligned.
The video buffers are allocated high to avoid leaving a hole underneath
server allocations when changing to a higher video mode.
Z_??? Zone memory functions used for small, dynamic allocations like text
strings from command input. There is only about 48K for it, allocated at
the very bottom of the hunk.
Cache_??? Cache memory is for objects that can be dynamically loaded and
can usefully stay persistant between levels. The size of the cache
fluctuates from level to level.
To allocate a cachable object
Temp_??? Temp memory is used for file loading and surface caching. The size
of the cache memory is adjusted so that there is a minimum of 512k remaining
for temp memory.
------ Top of Memory -------
high hunk allocations
<--- high hunk reset point held by vid
video buffer
z buffer
surface cache
<--- high hunk used
cachable memory
<--- low hunk used
client and server low hunk allocations
<-- low hunk reset point held by host
startup hunk allocations
Zone block
----- Bottom of Memory -----
*/
void Memory_Init (void *buf, int size);
void Z_Free (void *ptr);
void *Z_Malloc (int size); // returns 0 filled memory
void *Z_MallocNamed (int size, char *, int); // returns 0 filled memory
//#define Z_Malloc(x) Z_MallocNamed2(x, __FILE__, __LINE__ )
void *Z_TagMalloc (int size, int tag);
void Z_FreeTags(int tag);
void Z_DumpHeap (void);
void Z_CheckHeap (void);
int Z_FreeMemory (void);
int Z_Allocated(void);
#ifdef _DEBUG
#define NAMEDMALLOCS
#endif
//Big Zone: allowed to fail, doesn't clear. The expectation is a large file, rather than sensative data structures.
//(this is a nicer name for malloc)
void *BZ_Malloc(int size);
void *BZF_Malloc(int size);
void *BZ_Realloc(void *ptr, int size);
void BZ_Free(void *ptr);
#ifdef NAMEDMALLOCS
#define BZ_Malloc(size) Z_MallocNamed(size, __FILE__, __LINE__)
#define Z_Malloc(size) Z_MallocNamed(size, __FILE__, __LINE__)
#endif
void *Hunk_Alloc (int size); // returns 0 filled memory
void *Hunk_AllocName (int size, char *name);
void *Hunk_HighAllocName (int size, char *name);
int Hunk_LowMark (void);
void Hunk_FreeToLowMark (int mark);
int Hunk_LowMemAvailable(void);
int Hunk_HighMark (void);
void Hunk_FreeToHighMark (int mark);
void *Hunk_TempAlloc (int size);
void *Hunk_TempAllocMore (int size); //Don't clear old temp
void Hunk_Check (void);
typedef struct cache_user_s
{
void *data;
qboolean fake;
} cache_user_t;
void Cache_Flush (void);
void *Cache_Check (cache_user_t *c);
// returns the cached data, and moves to the head of the LRU list
// if present, otherwise returns NULL
void Cache_Free (cache_user_t *c);
void *Cache_Alloc (cache_user_t *c, int size, char *name);
// Returns NULL if all purgable data was tossed and there still
// wasn't enough room.
void Cache_Report (void);