Cube  Check-in [46c5779570]

Overview
Comment:Convert more files to pure Objective-C
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 46c577957085f072871cb93b46340fd8349c1e20503a448cc8e6d33ddaea1552
User & Date: js on 2025-03-20 21:52:26
Other Links: manifest | tags
Context
2025-03-20
22:22
Convert remaining files to pure Objective-C check-in: 12cac9666a user: js tags: trunk
21:52
Convert more files to pure Objective-C check-in: 46c5779570 user: js tags: trunk
21:18
Convert more files to pure Objective-C check-in: b250dfa8d4 user: js tags: trunk
Changes

Name change from src/Cube.mm to src/Cube.m.

Renamed and modified src/commands.mm [b377b2846b] to src/commands.m [5ae3539b0c].

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)

Modified src/editing.m from [1b9f6190f4] to [27b5ed2226].

25
26
27
28
29
30
31
32
33
34
35
36





37
38
39
40



41
42
43
44
45
46
47
25
26
27
28
29
30
31





32
33
34
35
36
37



38
39
40
41
42
43
44
45
46
47







-
-
-
-
-
+
+
+
+
+

-
-
-
+
+
+







		};
	});
}

int selh = 0;
bool selset = false;

#define loopselxy(b)                                        \
	{                                                   \
		makeundo();                                 \
		loop(x, sel->xs) loop(y, sel->ys)           \
		{                                           \
#define loopselxy(b)                                               \
	{                                                          \
		makeundo();                                        \
		loop(x, sel->xs) loop(y, sel->ys)                  \
		{                                                  \
			struct sqr *s = S(sel->x + x, sel->y + y); \
			b;                                  \
		}                                           \
		remip(sel, 0);                              \
			b;                                         \
		}                                                  \
		remip(sel, 0);                                     \
	}

int cx, cy, ch;

int curedittex[] = { -1, -1, -1 };

bool dragging = false;
257
258
259
260
261
262
263
264
265


266
267
268
269
270
271
272
257
258
259
260
261
262
263


264
265
266
267
268
269
270
271
272







-
-
+
+







	}
}

void
makeundo()
{
	if (undos == nil)
		undos =
		    [[OFMutableData alloc] initWithItemSize:sizeof(struct block *)];
		undos = [[OFMutableData alloc]
		    initWithItemSize:sizeof(struct block *)];

	struct block *copy = blockcopy(&sel);
	[undos addItem:&copy];
	pruneundos(undomegs << 20);
}

void

Modified src/entities.m from [2808b0e950] to [df6381198b].

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,

Modified src/meson.build from [44296e0cb5] to [a429d4244b].

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')

Renamed and modified src/physics.mm [c9005101f7] to src/physics.m [1c146ff92c].

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));
}

Renamed and modified src/rendercubes.mm [a098c5d67b] to src/rendercubes.m [9b7cf3b555].

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) {

Renamed and modified src/renderextras.mm [5a2fb82c3f] to src/renderextras.m [866128604e].

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);

Renamed and modified src/server.mm [e4950a7889] to src/server.m [761c67a79c].

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);

Renamed and modified src/serverms.mm [67d3e10cf2] to src/serverms.m [c145a0420f].

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

Name change from src/serverutil.mm to src/serverutil.m.

Renamed and modified src/sound.mm [eeaee8a784] to src/sound.m [fab11a9b01].

33
34
35
36
37
38
39
40

41
42
43
44
45
46
47
33
34
35
36
37
38
39

40
41
42
43
44
45
46
47







-
+







}

VAR(soundbufferlen, 128, 1024, 4096);

void
initsound()
{
	memset(soundlocs, 0, sizeof(soundloc) * MAXCHAN);
	memset(soundlocs, 0, sizeof(struct soundloc) * MAXCHAN);
	if (Mix_OpenAudio(SOUNDFREQ, MIX_DEFAULT_FORMAT, 2, soundbufferlen) <
	    0) {
		conoutf(@"sound init failed (SDL_mixer): %s",
		    (size_t)Mix_GetError());
		nosound = true;
	}
	Mix_AllocateChannels(MAXCHAN);
121
122
123
124
125
126
127
128

129
130
131
132
133
134
135
121
122
123
124
125
126
127

128
129
130
131
132
133
134
135







-
+







		vol -= (int)(dist * 3 * soundvol /
		    255); // simple mono distance attenuation
		if (stereo && (v.x != 0 || v.y != 0)) {
			// relative angle of sound along X-Y axis
			float yaw =
			    -atan2(v.x, v.y) - player1.yaw * (PI / 180.0f);
			// range is from 0 (left) to 255 (right)
			pan = int(255.9f * (0.5 * sin(yaw) + 0.5f));
			pan = (int)(255.9f * (0.5 * sin(yaw) + 0.5f));
		}
	}
	vol = (vol * MAXVOL) / 255;
	Mix_Volume(chan, vol);
	Mix_SetPanning(chan, 255 - pan, pan);
}

Renamed and modified src/tools.mm [22d3464477] to src/tools.m [f9cb2ee264].

1
2
3
4
5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10



-







// implementation of generic tools

#include "tools.h"
#include <new>

///////////////////////// misc tools ///////////////////////

void
endianswap(
    void *memory, int stride, int length) // little indians as storage format
{

Renamed and modified src/weapon.mm [b2ede2d0f5] to src/weapon.m [2e4de9f255].

238
239
240
241
242
243
244
245

246
247
248
249
250
251
252
238
239
240
241
242
243
244

245
246
247
248
249
250
251
252







-
+







		    DynamicEntity *monster, size_t i, bool *stop) {
			if (i != notthismonster)
				radialeffect(monster, v, i, qdam, p.owner);
		}];
	}
}

inline void
static inline void
projdamage(DynamicEntity *o, Projectile *p, const OFVector3D *v, int i, int im,
    int qdam)
{
	if (o.state != CS_ALIVE)
		return;

	OFVector3D po = p.o;