1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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
|
-
-
+
+
+
+
+
+
|
// command.cpp: implements the parsing and execution of a tiny script language
// which is largely backwards compatible with the quake console language.
#include "cube.h"
#include <memory>
#import "Alias.h"
#import "Command.h"
#import "Identifier.h"
#import "OFString+Cube.h"
#import "Variable.h"
// contains ALL vars/commands/aliases
static OFMutableDictionary<OFString *, __kindof Identifier *> *identifiers;
static void
cleanup(char **string)
{
free(*string);
}
void
alias(OFString *name, OFString *action)
{
Alias *alias = identifiers[name];
if (alias == nil) {
|
︙ | | |
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
|
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
|
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
-
-
+
+
+
-
+
|
identifiers[name] = command;
return false;
}
// parse any nested set of () or []
char *
parseexp(char *&p, int right)
static char *
parseexp(char **p, int right)
{
int left = *p++;
char *word = p;
int left = *(*p)++;
char *word = *p;
for (int brak = 1; brak;) {
int c = *p++;
int c = *(*p)++;
if (c == '\r')
*(p - 1) = ' '; // hack
*(*p - 1) = ' '; // hack
if (c == left)
brak++;
else if (c == right)
brak--;
else if (!c) {
p--;
(*p)--;
conoutf(@"missing \"%c\"", right);
return NULL;
}
}
char *s = strndup(word, p - word - 1);
char *s = strndup(word, *p - word - 1);
if (left == '(') {
OFString *t;
@try {
t = [OFString
stringWithFormat:@"%d", execute(@(s), true)];
} @finally {
free(s);
}
s = strdup(t.UTF8String);
}
return s;
}
// parse single argument, including expressions
char *
parseword(char *&p)
static char *
parseword(char **p)
{
p += strspn(p, " \t\r");
if (p[0] == '/' && p[1] == '/')
p += strcspn(p, "\n\0");
if (*p == '\"') {
p++;
char *word = p;
p += strcspn(p, "\"\r\n\0");
char *s = strndup(word, p - word);
if (*p == '\"')
p++;
(*p) += strspn(*p, " \t\r");
if ((*p)[0] == '/' && (*p)[1] == '/')
*p += strcspn(*p, "\n\0");
if (**p == '\"') {
(*p)++;
char *word = *p;
*p += strcspn(*p, "\"\r\n\0");
char *s = strndup(word, *p - word);
if (**p == '\"')
(*p)++;
return s;
}
if (*p == '(')
if (**p == '(')
return parseexp(p, ')');
if (*p == '[')
if (**p == '[')
return parseexp(p, ']');
char *word = p;
p += strcspn(p, "; \t\r\n\0");
if (p - word == 0)
char *word = *p;
*p += strcspn(*p, "; \t\r\n\0");
if (*p - word == 0)
return NULL;
return strndup(word, p - word);
return strndup(word, *p - word);
}
// find value of ident referenced with $ in exp
OFString *
lookup(OFString *n)
{
__kindof Identifier *identifier = identifiers[[n substringFromIndex:1]];
|
︙ | | |
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
|
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
|
+
-
-
+
+
-
+
|
return 0;
}
// all evaluation happens here, recursively
int
execute(OFString *string, bool isDown)
{
char *copy __attribute__((__cleanup__(cleanup))) =
std::unique_ptr<char> copy(strdup(string.UTF8String));
char *p = copy.get();
strdup(string.UTF8String);
char *p = copy;
const int MAXWORDS = 25; // limit, remove
OFString *w[MAXWORDS];
int val = 0;
for (bool cont = true; cont;) {
// for each ; seperated statement
int numargs = MAXWORDS;
loopi(MAXWORDS)
{
// collect all argument values
w[i] = @"";
if (i > numargs)
continue;
// parse and evaluate exps
char *s = parseword(p);
char *s = parseword(&p);
if (!s) {
numargs = i;
s = strdup("");
}
@try {
if (*s == '$')
// substitute variables
|
︙ | | |
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
|
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
|
+
-
-
-
+
+
+
+
+
+
+
|
return n + 1;
}
void
at(OFString *s_, OFString *pos)
{
int n = pos.cube_intValue;
char *copy __attribute__((__cleanup__(cleanup))) =
std::unique_ptr<char> copy(strdup(s_.UTF8String));
char *s = copy.get();
loopi(n) s += strspn(s += strcspn(s, " \0"), " ");
strdup(s_.UTF8String);
char *s = copy;
loopi(n)
{
s += strcspn(s, " \0");
s += strspn(s, " ");
}
s[strcspn(s, " \0")] = 0;
concat(@(s));
}
COMMANDN(loop, loopa, ARG_2STR)
COMMANDN(while, whilea, ARG_2STR)
COMMANDN(if, ifthen, ARG_3STR)
|
︙ | | |
︙ | | |
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
-
-
+
+
|
void
initEntities()
{
ents = [[OFMutableArray alloc] init];
}
static void
renderent(Entity *e, OFString *mdlname, float z, float yaw, int frame/* = 0*/,
int numf/* = 1*/, int basetime/* = 0*/, float speed/* = 10.0f*/)
renderent(Entity *e, OFString *mdlname, float z, float yaw, int frame /* = 0*/,
int numf /* = 1*/, int basetime /* = 0*/, float speed /* = 10.0f*/)
{
rendermodel(mdlname, frame, numf, 0, 1.1f,
OFMakeVector3D(e.x, z + S(e.x, e.y)->floor, e.y), yaw, 0, false,
1.0f, speed, 0, basetime);
}
void
|
︙ | | |
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
|
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
|
-
+
-
+
|
continue;
if (e.type < I_SHELLS || e.type > TELEPORT)
continue;
renderent(e, entmdlnames[e.type - I_SHELLS],
(float)(1 +
sin(lastmillis / 100.0 + e.x + e.y) /
20),
lastmillis / 10.0f, 0,1,0,10.0f);
lastmillis / 10.0f, 0, 1, 0, 10.0f);
} else {
switch (e.attr2) {
case 1:
case 3:
continue;
case 2:
case 0:
if (!e.spawned)
continue;
renderent(e, @"carrot",
(float)(1 +
sin(lastmillis / 100.0 + e.x +
e.y) /
20),
lastmillis /
(e.attr2 ? 1.0f : 10.0f),
0, 1, 0, 10.0f);
0, 1, 0, 10.0f);
break;
case 4:
renderent(e, @"switch2", 3,
(float)e.attr3 * 90,
(!e.spawned && !triggertime) ? 1
: 0,
|
︙ | | |
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
|
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
|
-
+
-
+
-
-
-
+
+
+
-
+
-
-
-
-
-
+
+
+
+
+
|
executable('client',
[
'Alias.m',
'Client.m',
'Command.m',
'ConsoleLine.m',
'Cube.mm',
'Cube.m',
'DynamicEntity.m',
'Entity.m',
'Identifier.m',
'KeyMapping.m',
'MD2.m',
'MapModelInfo.m',
'Menu.m',
'MenuItem.m',
'OFString+Cube.m',
'PersistentEntity.m',
'Projectile.m',
'ResolverResult.m',
'ResolverThread.m',
'ServerEntity.m',
'ServerInfo.m',
'Variable.m',
'clients.m',
'clientextras.m',
'clientgame.m',
'clients2c.m',
'commands.mm',
'commands.m',
'console.m',
'editing.m',
'entities.m',
'init.mm',
'menus.m',
'monster.m',
'physics.mm',
'rendercubes.mm',
'renderextras.mm',
'physics.m',
'rendercubes.m',
'renderextras.m',
'rendergl.mm',
'rendermd2.mm',
'renderparticles.mm',
'rendertext.mm',
'rndmap.mm',
'savegamedemo.mm',
'server.mm',
'server.m',
'serverbrowser.mm',
'serverms.mm',
'serverutil.mm',
'sound.mm',
'tools.mm',
'weapon.mm',
'serverms.m',
'serverutil.m',
'sound.m',
'tools.m',
'weapon.m',
'world.mm',
'worldio.mm',
'worldlight.mm',
'worldocull.mm',
'worldrender.mm',
],
dependencies: [
|
︙ | | |
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
-
-
-
-
+
+
+
+
-
+
|
link_with: [enet],
win_subsystem: 'windows')
executable('server',
[
'Client.m',
'ServerEntity.m',
'server.mm',
'serverms.mm',
'serverutil.mm',
'tools.mm',
'server.m',
'serverms.m',
'serverutil.m',
'tools.m',
],
objcpp_args: ['-DSTANDALONE'],
objc_args: ['-DSTANDALONE'],
dependencies: [
objfw_dep,
sdl_dep
],
include_directories: [enet_includes],
link_args: server_link_args,
link_with: [enet],
win_subsystem: 'console')
|
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
|
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
|
-
+
-
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
+
-
-
+
+
-
-
+
-
-
-
+
+
+
+
-
-
+
+
-
-
-
-
+
+
+
+
|
// physics.cpp: no physics books were hurt nor consulted in the construction of
// this code. All physics computations and constants were invented on the fly
// and simply tweaked until they "felt right", and have no basis in reality.
// Collision detection is simplistic but very robust (uses discrete steps at
// fixed fps).
#include "cube.h"
#import "DynamicEntity.h"
#import "Entity.h"
#import "MapModelInfo.h"
// collide with player or monster
bool
static bool
plcollide(
DynamicEntity *d, DynamicEntity *o, float &headspace, float &hi, float &lo)
DynamicEntity *d, DynamicEntity *o, float *headspace, float *hi, float *lo)
{
if (o.state != CS_ALIVE)
return true;
const float r = o.radius + d.radius;
if (fabs(o.o.x - d.o.x) < r && fabs(o.o.y - d.o.y) < r) {
if (d.o.z - d.eyeheight < o.o.z - o.eyeheight) {
if (o.o.z - o.eyeheight < hi)
hi = o.o.z - o.eyeheight - 1;
} else if (o.o.z + o.aboveeye > lo)
lo = o.o.z + o.aboveeye + 1;
if (o.o.z - o.eyeheight < *hi)
*hi = o.o.z - o.eyeheight - 1;
} else if (o.o.z + o.aboveeye > *lo)
*lo = o.o.z + o.aboveeye + 1;
if (fabs(o.o.z - d.o.z) < o.aboveeye + d.eyeheight)
return false;
if (d.monsterstate)
return false; // hack
headspace = d.o.z - o.o.z - o.aboveeye - d.eyeheight;
if (headspace < 0)
headspace = 10;
*headspace = d.o.z - o.o.z - o.aboveeye - d.eyeheight;
if (*headspace < 0)
*headspace = 10;
}
return true;
}
// recursively collide with a mipmapped corner cube
bool
cornertest(int mip, int x, int y, int dx, int dy, int &bx, int &by,
static bool
cornertest(int mip, int x, int y, int dx, int dy, int *bx, int *by, int *bs)
int &bs) // recursively collide with a mipmapped corner cube
{
sqr *w = wmip[mip];
struct sqr *w = wmip[mip];
int sz = ssize >> mip;
bool stest =
SOLID(SWS(w, x + dx, y, sz)) && SOLID(SWS(w, x, y + dy, sz));
mip++;
x /= 2;
y /= 2;
if (SWS(wmip[mip], x, y, ssize >> mip)->type == CORNER) {
bx = x << mip;
by = y << mip;
bs = 1 << mip;
*bx = x << mip;
*by = y << mip;
*bs = 1 << mip;
return cornertest(mip, x, y, dx, dy, bx, by, bs);
}
return stest;
}
// collide with a mapmodel
void
mmcollide(DynamicEntity *d, float &hi, float &lo) // collide with a mapmodel
static void
mmcollide(DynamicEntity *d, float *hi, float *lo)
{
for (Entity *e in ents) {
if (e.type != MAPMODEL)
continue;
MapModelInfo *mmi = getmminfo(e.attr2);
if (mmi == nil || !mmi.h)
continue;
const float r = mmi.rad + d.radius;
if (fabs(e.x - d.o.x) < r && fabs(e.y - d.o.y) < r) {
float mmz =
(float)(S(e.x, e.y)->floor + mmi.zoff + e.attr3);
if (d.o.z - d.eyeheight < mmz) {
if (mmz < hi)
hi = mmz;
} else if (mmz + mmi.h > lo)
lo = mmz + mmi.h;
if (mmz < *hi)
*hi = mmz;
} else if (mmz + mmi.h > *lo)
*lo = mmz + mmi.h;
}
}
}
// all collision happens here
// spawn is a dirty side effect used in spawning
// drop & rise are supplied by the physics below to indicate gravity/push for
|
︙ | | |
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
|
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
|
-
+
-
+
-
+
-
+
-
+
+
|
: -1000.0f;
for (int x = x1; x <= x2; x++)
for (int y = y1; y <= y2; y++) {
// collide with map
if (OUTBORD(x, y))
return false;
sqr *s = S(x, y);
struct sqr *s = S(x, y);
float ceil = s->ceil;
float floor = s->floor;
switch (s->type) {
case SOLID:
return false;
case CORNER: {
int bx = x, by = y, bs = 1;
if (x == x1 && y == y1 &&
cornertest(
0, x, y, -1, -1, bx, by, bs) &&
0, x, y, -1, -1, &bx, &by, &bs) &&
fx1 - bx + fy1 - by <= bs ||
x == x2 && y == y1 &&
cornertest(
0, x, y, 1, -1, bx, by, bs) &&
0, x, y, 1, -1, &bx, &by, &bs) &&
fx2 - bx >= fy1 - by ||
x == x1 && y == y2 &&
cornertest(
0, x, y, -1, 1, bx, by, bs) &&
0, x, y, -1, 1, &bx, &by, &bs) &&
fx1 - bx <= fy2 - by ||
x == x2 && y == y2 &&
cornertest(0, x, y, 1, 1, bx, by, bs) &&
cornertest(
0, x, y, 1, 1, &bx, &by, &bs) &&
fx2 - bx + fy2 - by >= bs)
return false;
break;
}
case FHF: // FIXME: too simplistic collision with
// slopes, makes it feels like tiny stairs
|
︙ | | |
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
|
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
|
-
+
-
+
-
+
-
+
|
if (hi - lo < d.eyeheight + d.aboveeye)
return false;
float headspace = 10;
for (id player in players) {
if (player == [OFNull null] || player == d)
continue;
if (!plcollide(d, player, headspace, hi, lo))
if (!plcollide(d, player, &headspace, &hi, &lo))
return false;
}
if (d != player1)
if (!plcollide(d, player1, headspace, hi, lo))
if (!plcollide(d, player1, &headspace, &hi, &lo))
return false;
// this loop can be a performance bottleneck with many monster on a slow
// cpu, should replace with a blockmap but seems mostly fast enough
for (DynamicEntity *monster in getmonsters())
if (!vreject(d.o, monster.o, 7.0f) && d != monster &&
!plcollide(d, monster, headspace, hi, lo))
!plcollide(d, monster, &headspace, &hi, &lo))
return false;
headspace -= 0.01f;
mmcollide(d, hi, lo); // collide with map models
mmcollide(d, &hi, &lo); // collide with map models
if (spawn) {
// just drop to floor (sideeffect)
d.o = OFMakeVector3D(d.o.x, d.o.y, lo + d.eyeheight);
d.onfloor = true;
} else {
const float space = d.o.z - d.eyeheight - lo;
|
︙ | | |
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
|
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
|
-
-
+
+
|
}
}
// main physics routine, moves a player/monster for a curtime step
// moveres indicated the physics precision (which is lower for monsters and
// multiplayer prediction) local is false for multiplayer prediction
void
moveplayer(DynamicEntity *pl, int moveres, bool local, int curtime)
static void
moveplayer4(DynamicEntity *pl, int moveres, bool local, int curtime)
{
const bool water = hdr.waterlevel > pl.o.z - 0.5f;
const bool floating = (editmode && local) || pl.state == CS_EDITING;
OFVector3D d; // vector of direction we ideally want to move in
d.x = (float)(pl.move * cos(rad(pl.yaw - 90)));
|
︙ | | |
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
|
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
|
-
+
|
// detect wether player is outside map, used for skipping zbuffer clear
// mostly
if (pl.o.x < 0 || pl.o.x >= ssize || pl.o.y < 0 || pl.o.y > ssize)
pl.outsidemap = true;
else {
sqr *s = S((int)pl.o.x, (int)pl.o.y);
struct sqr *s = S((int)pl.o.x, (int)pl.o.y);
pl.outsidemap = SOLID(s) ||
pl.o.z < s->floor - (s->type == FHF ? s->vdelta / 4 : 0) ||
pl.o.z > s->ceil + (s->type == CHF ? s->vdelta / 4 : 0);
}
// automatically apply smooth roll when strafing
|
︙ | | |
407
408
409
410
411
412
413
414
415
416
417
|
409
410
411
412
413
414
415
416
417
418
419
|
-
+
|
}
pl.inwater = water;
}
void
moveplayer(DynamicEntity *pl, int moveres, bool local)
{
loopi(physicsrepeat) moveplayer(pl, moveres, local,
loopi(physicsrepeat) moveplayer4(pl, moveres, local,
i ? curtime / physicsrepeat
: curtime - curtime / physicsrepeat * (physicsrepeat - 1));
}
|
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
|
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
|
-
+
-
+
-
-
-
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
|
// rendercubes.cpp: sits in between worldrender.cpp and rendergl.cpp and fills
// the vertex array for different cube surfaces.
#include "cube.h"
vertex *verts = NULL;
static struct vertex *verts = NULL;
int curvert;
int curmaxverts = 10000;
static int curmaxverts = 10000;
void
setarraypointers()
{
glVertexPointer(3, GL_FLOAT, sizeof(vertex), &verts[0].x);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex), &verts[0].r);
glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), &verts[0].u);
glVertexPointer(3, GL_FLOAT, sizeof(struct vertex), &verts[0].x);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(struct vertex), &verts[0].r);
glTexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), &verts[0].u);
}
void
reallocv()
{
verts =
(vertex *)OFResizeMemory(verts, (curmaxverts *= 2), sizeof(vertex));
OFResizeMemory(verts, (curmaxverts *= 2), sizeof(struct vertex));
curmaxverts -= 10;
setarraypointers();
}
// generating the actual vertices is done dynamically every frame and sits at
// the leaves of all these functions, and are part of the cpu bottleneck on
// really slow machines, hence the macros.
#define vertcheck() \
{ \
if (curvert >= curmaxverts) \
reallocv(); \
}
#define vertf(v1, v2, v3, ls, t1, t2) \
{ \
vertex &v = verts[curvert++]; \
v.u = t1; \
v.v = t2; \
v.x = v1; \
v.y = v2; \
v.z = v3; \
v.r = ls->r; \
v.g = ls->g; \
v.b = ls->b; \
v.a = 255; \
#define vertf(v1, v2, v3, ls, t1, t2) \
{ \
struct vertex *v = &verts[curvert++]; \
v->u = t1; \
v->v = t2; \
v->x = v1; \
v->y = v2; \
v->z = v3; \
v->r = ls->r; \
v->g = ls->g; \
v->b = ls->b; \
v->a = 255; \
}
#define vert(v1, v2, v3, ls, t1, t2) \
{ \
vertf((float)(v1), (float)(v2), (float)(v3), ls, t1, t2); \
}
|
︙ | | |
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
-
+
+
-
-
+
+
|
}
void
finishstrips()
{
stripend();
}
sqr sbright, sdark;
static struct sqr sbright, sdark;
VAR(lighterror, 1, 8, 100);
// floor/ceil quads
void
render_flat(int wtex, int x, int y, int size, int h, sqr *l1, sqr *l2, sqr *l3,
sqr *l4, bool isceil) // floor/ceil quads
render_flat(int wtex, int x, int y, int size, int h, struct sqr *l1,
struct sqr *l2, struct sqr *l3, struct sqr *l4, bool isceil)
{
vertcheck();
if (showm) {
l3 = l1 = &sbright;
l4 = l2 = &sdark;
}
|
︙ | | |
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
+
-
-
+
+
|
vert(x + size, h, y + size, l3, xo + xs, yo + ys);
}
oy = y;
nquads++;
}
// floor/ceil quads on a slope
void
render_flatdelta(int wtex, int x, int y, int size, float h1, float h2, float h3,
float h4, sqr *l1, sqr *l2, sqr *l3, sqr *l4,
bool isceil) // floor/ceil quads on a slope
float h4, struct sqr *l1, struct sqr *l2, struct sqr *l3, struct sqr *l4,
bool isceil)
{
vertcheck();
if (showm) {
l3 = l1 = &sbright;
l4 = l2 = &sdark;
}
|
︙ | | |
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
+
-
-
+
+
|
(float)x + size, h3, (float)y + size, l3, xo + xs, yo + ys);
}
oy = y;
nquads++;
}
// floor/ceil tris on a corner cube
void
render_2tris(sqr *h, sqr *s, int x1, int y1, int x2, int y2, int x3, int y3,
sqr *l1, sqr *l2, sqr *l3) // floor/ceil tris on a corner cube
render_2tris(struct sqr *h, struct sqr *s, int x1, int y1, int x2, int y2,
int x3, int y3, struct sqr *l1, struct sqr *l2, struct sqr *l3)
{
stripend();
vertcheck();
int sx, sy;
int gltex = lookuptexture(h->ftex, &sx, &sy);
float xf = TEXTURESCALE / sx;
|
︙ | | |
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
|
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
|
-
-
+
+
-
+
|
vertf((float)x2, h->ceil, (float)y2, l2, xf * x2, yf * y2);
vertf((float)x1, h->ceil, (float)y1, l1, xf * x1, yf * y1);
addstrip(gltex, curvert - 3, 3);
nquads++;
}
void
render_tris(int x, int y, int size, bool topleft, sqr *h1, sqr *h2, sqr *s,
sqr *t, sqr *u, sqr *v)
render_tris(int x, int y, int size, bool topleft, struct sqr *h1,
struct sqr *h2, struct sqr *s, struct sqr *t, struct sqr *u, struct sqr *v)
{
if (topleft) {
if (h1)
render_2tris(h1, s, x + size, y + size, x, y + size, x,
y, u, v, s);
if (h2)
render_2tris(h2, s, x, y, x + size, y, x + size,
y + size, s, t, v);
} else {
if (h1)
render_2tris(
h1, s, x, y, x + size, y, x, y + size, s, t, u);
if (h2)
render_2tris(h2, s, x + size, y, x + size, y + size, x,
y + size, t, u, v);
}
}
void
render_square(int wtex, float floor1, float floor2, float ceil1, float ceil2,
int x1, int y1, int x2, int y2, int size, sqr *l1, sqr *l2,
int x1, int y1, int x2, int y2, int size, struct sqr *l1, struct sqr *l2,
bool flip) // wall quads
{
stripend();
vertcheck();
if (showm) {
l1 = &sbright;
l2 = &sdark;
|
︙ | | |
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
|
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
|
-
-
+
+
|
int wx1, wy1, wx2, wy2;
VAR(watersubdiv, 1, 4, 64);
VARF(waterlevel, -128, -128, 127,
if (!noteditmode()) hdr.waterlevel = waterlevel);
inline void
vertw(int v1, float v2, int v3, sqr *c, float t1, float t2, float t)
static inline void
vertw(int v1, float v2, int v3, struct sqr *c, float t1, float t2, float t)
{
vertcheck();
vertf((float)v1, v2 - (float)sin(v1 * v3 * 0.1 + t) * 0.2f, (float)v3,
c, t1, t2);
}
inline float
|
︙ | | |
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
|
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
|
-
+
|
float xf = TEXTURESCALE / sx;
float yf = TEXTURESCALE / sy;
float xs = watersubdiv * xf;
float ys = watersubdiv * yf;
float t1 = lastmillis / 300.0f;
float t2 = lastmillis / 4000.0f;
sqr dl;
struct sqr dl;
dl.r = dl.g = dl.b = 255;
for (int xx = wx1; xx < wx2; xx += watersubdiv) {
for (int yy = wy1; yy < wy2; yy += watersubdiv) {
float xo = xf * (xx + t2);
float yo = yf * (yy + t2);
if (yy == wy1) {
|
︙ | | |
︙ | | |
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
-
+
|
linestyle(float width, int r, int g, int b)
{
glLineWidth(width);
glColor3ub(r, g, b);
}
void
box(const block *b, float z1, float z2, float z3, float z4)
box(const struct block *b, float z1, float z2, float z3, float z4)
{
glBegin(GL_POLYGON);
glVertex3f((float)b->x, z1, (float)b->y);
glVertex3f((float)b->x + b->xs, z2, (float)b->y);
glVertex3f((float)b->x + b->xs, z3, (float)b->y + b->ys);
glVertex3f((float)b->x, z4, (float)b->y + b->ys);
glEnd();
|
︙ | | |
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
|
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
|
-
+
-
+
-
+
-
+
|
}
const int MAXSPHERES = 50;
struct sphere {
OFVector3D o;
float size, max;
int type;
sphere *next;
struct sphere *next;
};
sphere spheres[MAXSPHERES], *slist = NULL, *sempty = NULL;
static struct sphere spheres[MAXSPHERES], *slist = NULL, *sempty = NULL;
bool sinit = false;
void
newsphere(const OFVector3D *o, float max, int type)
{
if (!sinit) {
loopi(MAXSPHERES)
{
spheres[i].next = sempty;
sempty = &spheres[i];
}
sinit = true;
}
if (sempty) {
sphere *p = sempty;
struct sphere *p = sempty;
sempty = p->next;
p->o = *o;
p->max = max;
p->size = 1;
p->type = type;
p->next = slist;
slist = p;
}
}
void
renderspheres(int time)
{
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glBindTexture(GL_TEXTURE_2D, 4);
for (sphere *p, **pp = &slist; p = *pp;) {
for (struct sphere *p, **pp = &slist; (p = *pp) != NULL;) {
glPushMatrix();
float size = p->size / p->max;
glColor4f(1.0f, 1.0f, 1.0f, 1.0f - size);
glTranslatef(p->o.x, p->o.z, p->o.y);
glRotatef(lastmillis / 5.0f, 1, 1, 1);
glScalef(p->size, p->size, p->size);
glCallList(1);
|
︙ | | |
︙ | | |
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
-
-
+
+
|
#define MAXOBUF 100000
void process(ENetPacket *packet, int sender);
void multicast(ENetPacket *packet, int sender);
void disconnect_client(int n, OFString *reason);
void
send(int n, ENetPacket *packet)
static void
send_(int n, ENetPacket *packet)
{
if (!packet)
return;
switch (clients[n].type) {
case ST_TCPIP:
enet_peer_send(clients[n].peer, 0, packet);
|
︙ | | |
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
-
+
|
putint(&p, a);
putint(&p, b);
*(ushort *)start = ENET_HOST_TO_NET_16(p - start);
enet_packet_resize(packet, p - start);
if (cn < 0)
process(packet, -1);
else
send(cn, packet);
send_(cn, packet);
if (packet->referenceCount == 0)
enet_packet_destroy(packet);
}
void
sendservmsg(OFString *msg)
{
|
︙ | | |
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
+
-
-
+
+
-
|
void
resetitems()
{
[sents removeAllObjects];
notgotitems = true;
}
// server side item pickup, acknowledge first client that gets it
void
pickup(uint i, int sec, int sender) // server side item pickup, acknowledge
static void
pickup(uint i, int sec, int sender)
// first client that gets it
{
if (i >= (uint)sents.count)
return;
if (sents[i].spawned) {
sents[i].spawned = false;
sents[i].spawnsecs = sec;
send2(true, sender, SV_ITEMACC, i);
|
︙ | | |
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
|
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
|
-
+
|
sgetstr();
int mapsize = getint(&p);
sendmaps(sender, @(text), mapsize, p);
return;
}
case SV_RECVMAP:
send(sender, recvmap(sender));
send_(sender, recvmap(sender));
return;
// allows for new features that require no server updates
case SV_EXT:
for (int n = getint(&p); n; n--)
getint(&p);
break;
|
︙ | | |
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
|
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
|
-
+
-
+
|
if (e.spawned)
putint(&p, i);
}];
putint(&p, -1);
}
*(ushort *)start = ENET_HOST_TO_NET_16(p - start);
enet_packet_resize(packet, p - start);
send(n, packet);
send_(n, packet);
}
void
multicast(ENetPacket *packet, int sender)
{
size_t count = clients.count;
for (size_t i = 0; i < count; i++)
if (i != sender)
send(i, packet);
send_(i, packet);
}
void
localclienttoserver(ENetPacket *packet)
{
process(packet, 0);
|
︙ | | |
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
|
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
|
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
-
-
+
+
+
|
// all server side masterserver and pinging functionality
#include "cube.h"
static ENetSocket mssock = ENET_SOCKET_NULL;
static void
httpgetsend(ENetAddress &ad, OFString *hostname, OFString *req, OFString *ref,
httpgetsend(ENetAddress *ad, OFString *hostname, OFString *req, OFString *ref,
OFString *agent)
{
if (ad.host == ENET_HOST_ANY) {
if (ad->host == ENET_HOST_ANY) {
[OFStdOut writeFormat:@"looking up %@...\n", hostname];
enet_address_set_host(&ad, hostname.UTF8String);
if (ad.host == ENET_HOST_ANY)
enet_address_set_host(ad, hostname.UTF8String);
if (ad->host == ENET_HOST_ANY)
return;
}
if (mssock != ENET_SOCKET_NULL)
enet_socket_destroy(mssock);
mssock = enet_socket_create(ENET_SOCKET_TYPE_STREAM, NULL);
if (mssock == ENET_SOCKET_NULL) {
printf("could not open socket\n");
return;
}
if (enet_socket_connect(mssock, &ad) < 0) {
if (enet_socket_connect(mssock, ad) < 0) {
printf("could not connect\n");
return;
}
ENetBuffer buf;
OFString *httpget = [OFString stringWithFormat:@"GET %@ HTTP/1.0\n"
@"Host: %@\n"
@"Referer: %@\n"
@"User-Agent: %@\n\n",
req, hostname, ref, agent];
buf.data = (void *)httpget.UTF8String;
buf.dataLength = httpget.UTF8StringLength;
[OFStdOut writeFormat:@"sending request to %@...\n", hostname];
enet_socket_send(mssock, NULL, &buf, 1);
}
static void
httpgetrecieve(ENetBuffer &buf)
httpgetrecieve(ENetBuffer *buf)
{
if (mssock == ENET_SOCKET_NULL)
return;
enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
if (enet_socket_wait(mssock, &events, 0) >= 0 && events) {
int len = enet_socket_receive(mssock, NULL, &buf, 1);
int len = enet_socket_receive(mssock, NULL, buf, 1);
if (len <= 0) {
enet_socket_destroy(mssock);
mssock = ENET_SOCKET_NULL;
return;
}
buf.data = ((char *)buf.data) + len;
((char *)buf.data)[0] = 0;
buf.dataLength -= len;
buf->data = ((char *)buf->data) + len;
((char *)buf->data)[0] = 0;
buf->dataLength -= len;
}
}
static uchar *
stripheader(uchar *b)
{
char *s = strstr((char *)b, "\n\r\n");
|
︙ | | |
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
|
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
|
-
+
-
+
-
+
-
+
|
static void
updatemasterserver(int seconds)
{
// send alive signal to masterserver every hour of uptime
if (seconds > updmaster) {
OFString *path = [OFString
stringWithFormat:@"%@register.do?action=add", masterpath];
httpgetsend(masterserver, masterbase, path, @"cubeserver",
httpgetsend(&masterserver, masterbase, path, @"cubeserver",
@"Cube Server");
masterrep[0] = 0;
masterb.data = masterrep;
masterb.dataLength = MAXTRANS - 1;
updmaster = seconds + 60 * 60;
}
}
static void
checkmasterreply()
{
bool busy = mssock != ENET_SOCKET_NULL;
httpgetrecieve(masterb);
httpgetrecieve(&masterb);
if (busy && mssock == ENET_SOCKET_NULL)
printf("masterserver reply: %s\n", stripheader(masterrep));
}
uchar *
retrieveservers(uchar *buf, int buflen)
{
OFString *path =
[OFString stringWithFormat:@"%@retrieve.do?item=list", masterpath];
httpgetsend(
masterserver, masterbase, path, @"cubeserver", @"Cube Server");
&masterserver, masterbase, path, @"cubeserver", @"Cube Server");
ENetBuffer eb;
buf[0] = 0;
eb.data = buf;
eb.dataLength = buflen - 1;
while (mssock != ENET_SOCKET_NULL)
httpgetrecieve(eb);
httpgetrecieve(&eb);
return stripheader(buf);
}
static ENetSocket pongsock = ENET_SOCKET_NULL;
static OFString *serverdesc;
void
|
︙ | | |