Cube  Diff

Differences From Artifact [184ea10702]:

To Artifact [11dc4e9109]:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43



44

45

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92


93
94


95


96



97








98



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

127
128
129
130
131

132
133
134








135
136
137
138
139
140
141
142
143
144
145
146





147



148



149





150

151




152



153
154
155
156
157
158
159
160
161





162




163





164





165

166

167

168


169
170

171

172

173

174

175

176

177


178
179
180
181
182
183



184
185
186
187
188
189
190

191
192
193
194

195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220


221





222





223





224






225
226


227




228







229
230
231
232
233
234
235
236
237
238
239
240
241
242
243



244
245



246

247


248
249
250
251
252


253
254

255

256
257




258




259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
// one big bad include file for the whole engine... nasty!

#include "tools.h"			

enum                            // block types, order matters!
{
    SOLID = 0,                  // entirely solid cube [only specifies wtex]
    CORNER,                     // half full corner of a wall
    FHF,                        // floor heightfield using neighbour vdelta values
    CHF,                        // idem ceiling
    SPACE,                      // entirely empty cube
    SEMISOLID,                  // generated by mipmapping
    MAXTYPE
};
 
struct sqr
{
    uchar type;                 // one of the above
    char floor, ceil;           // height, in cubes
    uchar wtex, ftex, ctex;     // wall/floor/ceil texture ids
    uchar r, g, b;              // light value at upper left vertex
    uchar vdelta;               // vertex delta, used for heightfield cubes
    char defer;                 // used in mipmapping, when true this cube is not a perfect mip

    char occluded;              // true when occluded
    uchar utex;                 // upper wall tex id
    uchar tag;                  // used by triggers
};

enum                            // hardcoded texture numbers
{
    DEFAULT_SKY = 0,
    DEFAULT_LIQUID,
    DEFAULT_WALL,
    DEFAULT_FLOOR,
    DEFAULT_CEIL
};

enum                            // static entity types
{
    NOTUSED = 0,                // entity slot not in use in map
    LIGHT,                      // lightsource, attr1 = radius, attr2 = intensity
    PLAYERSTART,                // attr1 = angle
    I_SHELLS, I_BULLETS, I_ROCKETS, I_ROUNDS,



    I_HEALTH, I_BOOST,

    I_GREENARMOUR, I_YELLOWARMOUR,

    I_QUAD,
    TELEPORT,                   // attr1 = idx
    TELEDEST,                   // attr1 = angle, attr2 = idx
    MAPMODEL,                   // attr1 = angle, attr2 = idx
    MONSTER,                    // attr1 = angle, attr2 = monstertype
    CARROT,                     // attr1 = tag, attr2 = type
    JUMPPAD,                    // attr1 = zpush, attr2 = ypush, attr3 = xpush
    MAXENTTYPES
};

struct persistent_entity        // map entity
{
    short x, y, z;              // cube aligned position
    short attr1;
    uchar type;                 // type is one of the above
    uchar attr2, attr3, attr4;        
};

struct entity : public persistent_entity    
{
    bool spawned;               // the only dynamic state of a map entity
};

#define MAPVERSION 5            // bump if map format changes, see worldio.cpp

struct header                   // map file format header
{
    char head[4];               // "CUBE"
    int version;                // any >8bit quantity is a little indian
    int headersize;             // sizeof(header)
    int sfactor;                // in bits
    int numents;
    char maptitle[128];
    uchar texlists[3][256];
    int waterlevel;
    int reserved[15];
};

#define SWS(w,x,y,s) (&(w)[(y)*(s)+(x)])
#define SW(w,x,y) SWS(w,x,y,ssize)
#define S(x,y) SW(world,x,y)            // convenient lookup of a lowest mip cube
#define SMALLEST_FACTOR 6               // determines number of mips there can be
#define DEFAULT_FACTOR 8
#define LARGEST_FACTOR 11               // 10 is already insane
#define SOLID(x) ((x)->type==SOLID)
#define MINBORD 2                       // 2 cubes from the edge of the world are always solid
#define OUTBORD(x,y) ((x)<MINBORD || (y)<MINBORD || (x)>=ssize-MINBORD || (y)>=ssize-MINBORD)



struct vec { float x, y, z; };


struct block { int x, y, xs, ys; };


struct mapmodelinfo { int rad, h, zoff, snap; char *name; };












enum { GUN_FIST = 0, GUN_SG, GUN_CG, GUN_RL, GUN_RIFLE, GUN_FIREBALL, GUN_ICEBALL, GUN_SLIMEBALL, GUN_BITE, NUMGUNS };




struct dynent                           // players & monsters
{
    vec o, vel;                         // origin, velocity
    float yaw, pitch, roll;             // used as vec in one place
    float maxspeed;                     // cubes per second, 24 for player
    bool outsidemap;                    // from his eyes
    bool inwater;
    bool onfloor, jumpnext;
    int move, strafe;
    bool k_left, k_right, k_up, k_down; // see input code  
    int timeinair;                      // used for fake gravity
    float radius, eyeheight, aboveeye;  // bounding box size
    int lastupdate, plag, ping;
    int lifesequence;                   // sequence id for each respawn, used in damage test
    int state;                          // one of CS_* below
    int frags;
    int health, armour, armourtype, quadmillis;
    int gunselect, gunwait;
    int lastaction, lastattackgun, lastmove;
    bool attacking;
    int ammo[NUMGUNS];
    int monsterstate;                   // one of M_* below, M_NONE means human
    int mtype;                          // see monster.cpp
    dynent *enemy;                      // monster wants to kill this entity
    float targetyaw;                    // monster wants to look in this direction
    bool blocked, moving;               // used by physics to signal ai
    int trigger;                        // millis at which transition to another monsterstate takes place

    vec attacktarget;                   // delayed attacks
    int anger;                          // how many times already hit by fellow monster
    string name, team;
};


#define SAVEGAMEVERSION 4               // bump if dynent/netprotocol changes or any other savegame/demo data

enum { A_BLUE, A_GREEN, A_YELLOW };     // armour types... take 20/40/60 % off








enum { M_NONE = 0, M_SEARCH, M_HOME, M_ATTACKING, M_PAIN, M_SLEEP, M_AIMING };  // monster states

#define MAXCLIENTS 256                  // in a multiplayer game, can be arbitrarily changed
#define MAXTRANS 5000                   // max amount of data to swallow in 1 go
#define CUBE_SERVER_PORT 28765
#define CUBE_SERVINFO_PORT 28766
#define PROTOCOL_VERSION 122            // bump when protocol changes

// network messages codes, c2s, c2c, s2c
enum
{
    SV_INITS2C, SV_INITC2S, SV_POS, SV_TEXT, SV_SOUND, SV_CDIS,





    SV_DIED, SV_DAMAGE, SV_SHOT, SV_FRAGS,



    SV_TIMEUP, SV_EDITENT, SV_MAPRELOAD, SV_ITEMACC,



    SV_MAPCHANGE, SV_ITEMSPAWN, SV_ITEMPICKUP, SV_DENIED,





    SV_PING, SV_PONG, SV_CLIENTPING, SV_GAMEMODE,

    SV_EDITH, SV_EDITT, SV_EDITS, SV_EDITD, SV_EDITE,




    SV_SENDMAP, SV_RECVMAP, SV_SERVMSG, SV_ITEMLIST,



    SV_EXT,
};     

enum { CS_ALIVE = 0, CS_DEAD, CS_LAGGED, CS_EDITING };

// hardcoded sounds, defined in sounds.cfg
enum
{
    S_JUMP = 0, S_LAND, S_RIFLE, S_PUNCH1, S_SG, S_CG,





    S_RLFIRE, S_RLHIT, S_WEAPLOAD, S_ITEMAMMO, S_ITEMHEALTH,




    S_ITEMARMOUR, S_ITEMPUP, S_ITEMSPAWN, S_TELEPORT, S_NOAMMO, S_PUPOUT,





    S_PAIN1, S_PAIN2, S_PAIN3, S_PAIN4, S_PAIN5, S_PAIN6,





    S_DIE1, S_DIE2,

    S_FLAUNCH, S_FEXPLODE,

    S_SPLASH1, S_SPLASH2,

    S_GRUNT1, S_GRUNT2, S_RUMBLE,


    S_PAINO,
    S_PAINR, S_DEATHR, 

    S_PAINE, S_DEATHE, 

    S_PAINS, S_DEATHS,

    S_PAINB, S_DEATHB, 

    S_PAINP, S_PIGGR2, 

    S_PAINH, S_DEATHH,

    S_PAIND, S_DEATHD,

    S_PIGR1, S_ICEBALL, S_SLIMEBALL,


    S_JUMPPAD,
};

// vertex array format

struct vertex { float u, v, x, y, z; uchar r, g, b, a; }; 




typedef vector<dynent *> dvector;
typedef vector<char *> cvector;
typedef vector<int> ivector;

// globals ooh naughty


extern sqr *world, *wmip[];             // map data, the mips are sequential 2D arrays in memory
extern header hdr;                      // current map header
extern int sfactor, ssize;              // ssize = 2^sfactor
extern int cubicsize, mipsize;          // cubicsize = ssize^2

extern dynent *player1;                 // special client ent that receives input and acts as camera
extern dvector players;                 // all the other clients (in multiplayer)
extern bool editmode;
extern vector<entity> ents;             // map entities
extern vec worldpos;                    // current target of the crosshair in the world
extern int lastmillis;                  // last time
extern int curtime;                     // current frame time
extern int gamemode, nextmode;
extern int xtraverts;
extern bool demoplayback;


#define DMF 16.0f 
#define DAF 1.0f 
#define DVF 100.0f

#define VIRTW 2400                      // virtual screen size for text & HUD
#define VIRTH 1800
#define FONTH 64
#define PIXELTAB (VIRTW/12)

#define PI  (3.1415927f)
#define PI2 (2*PI)

// simplistic vector ops
#define dotprod(u,v) ((u).x * (v).x + (u).y * (v).y + (u).z * (v).z)


#define vmul(u,f)    { (u).x *= (f); (u).y *= (f); (u).z *= (f); }





#define vdiv(u,f)    { (u).x /= (f); (u).y /= (f); (u).z /= (f); }





#define vadd(u,v)    { (u).x += (v).x; (u).y += (v).y; (u).z += (v).z; };





#define vsub(u,v)    { (u).x -= (v).x; (u).y -= (v).y; (u).z -= (v).z; };






#define vdist(d,v,e,s) vec v = s; vsub(v,e); float d = (float)sqrt(dotprod(v,v));
#define vreject(v,u,max) ((v).x>(u).x+(max) || (v).x<(u).x-(max) || (v).y>(u).y+(max) || (v).y<(u).y-(max))


#define vlinterp(v,f,u,g) { (v).x = (v).x*f+(u).x*g; (v).y = (v).y*f+(u).y*g; (v).z = (v).z*f+(u).z*g; }












#define sgetstr() { char *t = text; do { *t = getint(p); } while(*t++); }   // used by networking

#define m_noitems     (gamemode>=4)
#define m_noitemsrail (gamemode<=5)
#define m_arena       (gamemode>=8)
#define m_tarena      (gamemode>=10)
#define m_teammode    (gamemode&1 && gamemode>2)
#define m_sp          (gamemode<0)
#define m_dmsp        (gamemode==-1)
#define m_classicsp   (gamemode==-2)
#define isteam(a,b)   (m_teammode && strcmp(a, b)==0)

enum    // function signatures for script functions, see command.cpp
{
    ARG_1INT, ARG_2INT, ARG_3INT, ARG_4INT,



    ARG_NONE,
    ARG_1STR, ARG_2STR, ARG_3STR, ARG_5STR,



    ARG_DOWN, ARG_DWN1,

    ARG_1EXP, ARG_2EXP,


    ARG_1EST, ARG_2EST,
    ARG_VARI
}; 

// nasty macros for registering script functions, abuses globals to avoid excessive infrastructure


#define COMMANDN(name, fun, nargs) static bool __dummy_##fun = addcommand(#name, (void (*)())fun, nargs)
#define COMMAND(name, nargs) COMMANDN(name, name, nargs)

#define VARP(name, min, cur, max) int name = variable(#name, min, cur, max, &name, NULL, true)

#define VAR(name, min, cur, max)  int name = variable(#name, min, cur, max, &name, NULL, false)
#define VARF(name, min, cur, max, body)  void var_##name(); static int name = variable(#name, min, cur, max, &name, var_##name, false); void var_##name() { body; }




#define VARFP(name, min, cur, max, body) void var_##name(); static int name = variable(#name, min, cur, max, &name, var_##name, true); void var_##name() { body; }





#define ATOI(s) strtol(s, NULL, 0)		// supports hexadecimal numbers

#ifdef WIN32
	#define WIN32_LEAN_AND_MEAN
	#include "windows.h"
	#define _WINDOWS
	#define ZLIB_DLL
#else
	#include <dlfcn.h>
#endif

#include <time.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glext.h>

#include <SDL.h>
#include <SDL_image.h>

#include <enet/enet.h>

#include <zlib.h>

#include "protos.h"				// external function decls



|

|

|
|
|
|
|
|
|

|
|
<
|
|
|
|
|
|
>
|
|
|


|

|
|
|
|
|


|

|
|
|
|
>
>
>
|
>
|
>
|
|
|
|
|
|
|
|


|

|
|
|
|


|
<
|


|

|

|
|
|
|
|
|
|
|
|


|
|
|
|

|
|
|
|
>
>

|
>
>
|
>
>
|
>
>
>

>
>
>
>
>
>
>
>
|
>
>
>

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
|


>
|

|
>
>
>
>
>
>
>
>
|

|
|


|


|
<
|
>
>
>
>
>
|
>
>
>
|
>
>
>
|
>
>
>
>
>
|
>
|
>
>
>
>
|
>
>
>
|
|




|
<
|
>
>
>
>
>
|
>
>
>
>
|
>
>
>
>
>
|
>
>
>
>
>
|
>
|
>
|
>
|
>
>
|
|
>
|
>
|
>
|
>
|
>
|
>
|
>
|
>
>
|




|
>
>
>







>
|
|
|
|
>
|
|

|
|
|
|




<
|
|


|


|

|
|


|
>
>
|
>
>
>
>
>
|
>
>
>
>
>
|
>
>
>
>
>
|
>
>
>
>
>
>
|
|
>
>
|
>
>
>
>
|
>
>
>
>
>
>
>
|

|
|
|
|
|
|
|
|
|

|

|
>
>
>
|
|
>
>
>
|
>
|
>
>
|
|
|

|
>
>
|

>
|
>
|
|
>
>
>
>
|
>
>
>
>

|


|
|
|
|

|





|
|








|
<
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216

217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299

300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434

// one big bad include file for the whole engine... nasty!

#include "tools.h"

enum // block types, order matters!
{
	SOLID = 0, // entirely solid cube [only specifies wtex]
	CORNER,    // half full corner of a wall
	FHF,       // floor heightfield using neighbour vdelta values
	CHF,       // idem ceiling
	SPACE,     // entirely empty cube
	SEMISOLID, // generated by mipmapping
	MAXTYPE
};

struct sqr {

	uchar type;             // one of the above
	char floor, ceil;       // height, in cubes
	uchar wtex, ftex, ctex; // wall/floor/ceil texture ids
	uchar r, g, b;          // light value at upper left vertex
	uchar vdelta;           // vertex delta, used for heightfield cubes
	char defer; // used in mipmapping, when true this cube is not a perfect
	            // mip
	char occluded; // true when occluded
	uchar utex;    // upper wall tex id
	uchar tag;     // used by triggers
};

enum // hardcoded texture numbers
{
	DEFAULT_SKY = 0,
	DEFAULT_LIQUID,
	DEFAULT_WALL,
	DEFAULT_FLOOR,
	DEFAULT_CEIL
};

enum // static entity types
{
	NOTUSED = 0, // entity slot not in use in map
	LIGHT,       // lightsource, attr1 = radius, attr2 = intensity
	PLAYERSTART, // attr1 = angle
	I_SHELLS,
	I_BULLETS,
	I_ROCKETS,
	I_ROUNDS,
	I_HEALTH,
	I_BOOST,
	I_GREENARMOUR,
	I_YELLOWARMOUR,
	I_QUAD,
	TELEPORT, // attr1 = idx
	TELEDEST, // attr1 = angle, attr2 = idx
	MAPMODEL, // attr1 = angle, attr2 = idx
	MONSTER,  // attr1 = angle, attr2 = monstertype
	CARROT,   // attr1 = tag, attr2 = type
	JUMPPAD,  // attr1 = zpush, attr2 = ypush, attr3 = xpush
	MAXENTTYPES
};

struct persistent_entity // map entity
{
	short x, y, z; // cube aligned position
	short attr1;
	uchar type; // type is one of the above
	uchar attr2, attr3, attr4;
};

struct entity : public persistent_entity {

	bool spawned; // the only dynamic state of a map entity
};

#define MAPVERSION 5 // bump if map format changes, see worldio.cpp

struct header // map file format header
{
	char head[4];   // "CUBE"
	int version;    // any >8bit quantity is a little indian
	int headersize; // sizeof(header)
	int sfactor;    // in bits
	int numents;
	char maptitle[128];
	uchar texlists[3][256];
	int waterlevel;
	int reserved[15];
};

#define SWS(w, x, y, s) (&(w)[(y) * (s) + (x)])
#define SW(w, x, y) SWS(w, x, y, ssize)
#define S(x, y) SW(world, x, y) // convenient lookup of a lowest mip cube
#define SMALLEST_FACTOR 6       // determines number of mips there can be
#define DEFAULT_FACTOR 8
#define LARGEST_FACTOR 11 // 10 is already insane
#define SOLID(x) ((x)->type == SOLID)
#define MINBORD 2 // 2 cubes from the edge of the world are always solid
#define OUTBORD(x, y)                                                          \
	((x) < MINBORD || (y) < MINBORD || (x) >= ssize - MINBORD ||           \
	    (y) >= ssize - MINBORD)

struct vec {
	float x, y, z;
};
struct block {
	int x, y, xs, ys;
};
struct mapmodelinfo {
	int rad, h, zoff, snap;
	char *name;
};

enum {
	GUN_FIST = 0,
	GUN_SG,
	GUN_CG,
	GUN_RL,
	GUN_RIFLE,
	GUN_FIREBALL,
	GUN_ICEBALL,
	GUN_SLIMEBALL,
	GUN_BITE,
	NUMGUNS
};

struct dynent // players & monsters
{
	vec o, vel;             // origin, velocity
	float yaw, pitch, roll; // used as vec in one place
	float maxspeed;         // cubes per second, 24 for player
	bool outsidemap;        // from his eyes
	bool inwater;
	bool onfloor, jumpnext;
	int move, strafe;
	bool k_left, k_right, k_up, k_down; // see input code
	int timeinair;                      // used for fake gravity
	float radius, eyeheight, aboveeye;  // bounding box size
	int lastupdate, plag, ping;
	int lifesequence; // sequence id for each respawn, used in damage test
	int state;        // one of CS_* below
	int frags;
	int health, armour, armourtype, quadmillis;
	int gunselect, gunwait;
	int lastaction, lastattackgun, lastmove;
	bool attacking;
	int ammo[NUMGUNS];
	int monsterstate;     // one of M_* below, M_NONE means human
	int mtype;            // see monster.cpp
	dynent *enemy;        // monster wants to kill this entity
	float targetyaw;      // monster wants to look in this direction
	bool blocked, moving; // used by physics to signal ai
	int trigger; // millis at which transition to another monsterstate takes
	             // place
	vec attacktarget; // delayed attacks
	int anger;        // how many times already hit by fellow monster
	string name, team;
};

#define SAVEGAMEVERSION                                                        \
	4 // bump if dynent/netprotocol changes or any other savegame/demo data

enum { A_BLUE, A_GREEN, A_YELLOW }; // armour types... take 20/40/60 % off
enum {
	M_NONE = 0,
	M_SEARCH,
	M_HOME,
	M_ATTACKING,
	M_PAIN,
	M_SLEEP,
	M_AIMING
}; // monster states

#define MAXCLIENTS 256 // in a multiplayer game, can be arbitrarily changed
#define MAXTRANS 5000  // max amount of data to swallow in 1 go
#define CUBE_SERVER_PORT 28765
#define CUBE_SERVINFO_PORT 28766
#define PROTOCOL_VERSION 122 // bump when protocol changes

// network messages codes, c2s, c2c, s2c
enum {

	SV_INITS2C,
	SV_INITC2S,
	SV_POS,
	SV_TEXT,
	SV_SOUND,
	SV_CDIS,
	SV_DIED,
	SV_DAMAGE,
	SV_SHOT,
	SV_FRAGS,
	SV_TIMEUP,
	SV_EDITENT,
	SV_MAPRELOAD,
	SV_ITEMACC,
	SV_MAPCHANGE,
	SV_ITEMSPAWN,
	SV_ITEMPICKUP,
	SV_DENIED,
	SV_PING,
	SV_PONG,
	SV_CLIENTPING,
	SV_GAMEMODE,
	SV_EDITH,
	SV_EDITT,
	SV_EDITS,
	SV_EDITD,
	SV_EDITE,
	SV_SENDMAP,
	SV_RECVMAP,
	SV_SERVMSG,
	SV_ITEMLIST,
	SV_EXT,
};

enum { CS_ALIVE = 0, CS_DEAD, CS_LAGGED, CS_EDITING };

// hardcoded sounds, defined in sounds.cfg
enum {

	S_JUMP = 0,
	S_LAND,
	S_RIFLE,
	S_PUNCH1,
	S_SG,
	S_CG,
	S_RLFIRE,
	S_RLHIT,
	S_WEAPLOAD,
	S_ITEMAMMO,
	S_ITEMHEALTH,
	S_ITEMARMOUR,
	S_ITEMPUP,
	S_ITEMSPAWN,
	S_TELEPORT,
	S_NOAMMO,
	S_PUPOUT,
	S_PAIN1,
	S_PAIN2,
	S_PAIN3,
	S_PAIN4,
	S_PAIN5,
	S_PAIN6,
	S_DIE1,
	S_DIE2,
	S_FLAUNCH,
	S_FEXPLODE,
	S_SPLASH1,
	S_SPLASH2,
	S_GRUNT1,
	S_GRUNT2,
	S_RUMBLE,
	S_PAINO,
	S_PAINR,
	S_DEATHR,
	S_PAINE,
	S_DEATHE,
	S_PAINS,
	S_DEATHS,
	S_PAINB,
	S_DEATHB,
	S_PAINP,
	S_PIGGR2,
	S_PAINH,
	S_DEATHH,
	S_PAIND,
	S_DEATHD,
	S_PIGR1,
	S_ICEBALL,
	S_SLIMEBALL,
	S_JUMPPAD,
};

// vertex array format

struct vertex {
	float u, v, x, y, z;
	uchar r, g, b, a;
};

typedef vector<dynent *> dvector;
typedef vector<char *> cvector;
typedef vector<int> ivector;

// globals ooh naughty

extern sqr *world,
    *wmip[];       // map data, the mips are sequential 2D arrays in memory
extern header hdr; // current map header
extern int sfactor, ssize;     // ssize = 2^sfactor
extern int cubicsize, mipsize; // cubicsize = ssize^2
extern dynent
    *player1; // special client ent that receives input and acts as camera
extern dvector players; // all the other clients (in multiplayer)
extern bool editmode;
extern vector<entity> ents; // map entities
extern vec worldpos;        // current target of the crosshair in the world
extern int lastmillis;      // last time
extern int curtime;         // current frame time
extern int gamemode, nextmode;
extern int xtraverts;
extern bool demoplayback;


#define DMF 16.0f
#define DAF 1.0f
#define DVF 100.0f

#define VIRTW 2400 // virtual screen size for text & HUD
#define VIRTH 1800
#define FONTH 64
#define PIXELTAB (VIRTW / 12)

#define PI (3.1415927f)
#define PI2 (2 * PI)

// simplistic vector ops
#define dotprod(u, v) ((u).x * (v).x + (u).y * (v).y + (u).z * (v).z)
#define vmul(u, f)                                                             \
	{                                                                      \
		(u).x *= (f);                                                  \
		(u).y *= (f);                                                  \
		(u).z *= (f);                                                  \
	}
#define vdiv(u, f)                                                             \
	{                                                                      \
		(u).x /= (f);                                                  \
		(u).y /= (f);                                                  \
		(u).z /= (f);                                                  \
	}
#define vadd(u, v)                                                             \
	{                                                                      \
		(u).x += (v).x;                                                \
		(u).y += (v).y;                                                \
		(u).z += (v).z;                                                \
	};
#define vsub(u, v)                                                             \
	{                                                                      \
		(u).x -= (v).x;                                                \
		(u).y -= (v).y;                                                \
		(u).z -= (v).z;                                                \
	};
#define vdist(d, v, e, s)                                                      \
	vec v = s;                                                             \
	vsub(v, e);                                                            \
	float d = (float)sqrt(dotprod(v, v));
#define vreject(v, u, max)                                                     \
	((v).x > (u).x + (max) || (v).x < (u).x - (max) ||                     \
	    (v).y > (u).y + (max) || (v).y < (u).y - (max))
#define vlinterp(v, f, u, g)                                                   \
	{                                                                      \
		(v).x = (v).x * f + (u).x * g;                                 \
		(v).y = (v).y * f + (u).y * g;                                 \
		(v).z = (v).z * f + (u).z * g;                                 \
	}

#define sgetstr()                                                              \
	{                                                                      \
		char *t = text;                                                \
		do {                                                           \
			*t = getint(p);                                        \
		} while (*t++);                                                \
	} // used by networking

#define m_noitems (gamemode >= 4)
#define m_noitemsrail (gamemode <= 5)
#define m_arena (gamemode >= 8)
#define m_tarena (gamemode >= 10)
#define m_teammode (gamemode & 1 && gamemode > 2)
#define m_sp (gamemode < 0)
#define m_dmsp (gamemode == -1)
#define m_classicsp (gamemode == -2)
#define isteam(a, b) (m_teammode && strcmp(a, b) == 0)

enum // function signatures for script functions, see command.cpp
{
	ARG_1INT,
	ARG_2INT,
	ARG_3INT,
	ARG_4INT,
	ARG_NONE,
	ARG_1STR,
	ARG_2STR,
	ARG_3STR,
	ARG_5STR,
	ARG_DOWN,
	ARG_DWN1,
	ARG_1EXP,
	ARG_2EXP,
	ARG_1EST,
	ARG_2EST,
	ARG_VARI
};

// nasty macros for registering script functions, abuses globals to avoid
// excessive infrastructure
#define COMMANDN(name, fun, nargs)                                             \
	static bool __dummy_##fun = addcommand(#name, (void (*)())fun, nargs)
#define COMMAND(name, nargs) COMMANDN(name, name, nargs)
#define VARP(name, min, cur, max)                                              \
	int name = variable(#name, min, cur, max, &name, NULL, true)
#define VAR(name, min, cur, max)                                               \
	int name = variable(#name, min, cur, max, &name, NULL, false)
#define VARF(name, min, cur, max, body)                                        \
	void var_##name();                                                     \
	static int name =                                                      \
	    variable(#name, min, cur, max, &name, var_##name, false);          \
	void var_##name() { body; }
#define VARFP(name, min, cur, max, body)                                       \
	void var_##name();                                                     \
	static int name =                                                      \
	    variable(#name, min, cur, max, &name, var_##name, true);           \
	void var_##name() { body; }

#define ATOI(s) strtol(s, NULL, 0) // supports hexadecimal numbers

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#define _WINDOWS
#define ZLIB_DLL
#else
#include <dlfcn.h>
#endif

#include <time.h>

#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/glu.h>

#include <SDL.h>
#include <SDL_image.h>

#include <enet/enet.h>

#include <zlib.h>

#include "protos.h" // external function decls