Cube  Check-in [003b06901f]

Overview
Comment:Clean up console output functions
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 003b06901f169b5d97cbbaa313ad31a2493d2a56b295cffda136500ecc5d4f05
User & Date: js on 2025-03-05 21:55:28
Other Links: manifest | tags
Context
2025-03-05
22:24
Clean up key mapping check-in: 31ef5be209 user: js tags: trunk
21:55
Clean up console output functions check-in: 003b06901f user: js tags: trunk
21:29
Clean up file handling check-in: 3d55e077f7 user: js tags: trunk
Changes

Modified src/Cube.mm from [ee205df0bd] to [398e5608de].

32
33
34
35
36
37
38
39
40


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


39
40
41
42
43
44
45
46
47






-
-
+
+







	bool dedicated, windowed;
	int par = 0, uprate = 0, maxcl = 4;
	OFString *__autoreleasing sdesc, *__autoreleasing ip;
	OFString *__autoreleasing master, *__autoreleasing passwd;

	processInitQueue();

#define log(s) conoutf(@"init: %s", s)
	log("sdl");
#define log(s) conoutf(@"init: %@", s)
	log(@"sdl");

	const OFOptionsParserOption options[] = {
	    {'d', @"dedicated", 0, &dedicated, NULL},
	    {'t', @"window", 0, &windowed, NULL},
	    {'w', @"width", 1, NULL, NULL}, {'h', @"height", 1, NULL, NULL},
	    {'u', @"upload-rate", 1, NULL, NULL},
	    {'n', @"server-desc", 1, NULL, &sdesc}, {'i', @"ip", 1, NULL, &ip},
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
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






-
+








-
+


-
+



-
+








-
+




-
+


-
+







		ip = @"";
	if (passwd == nil)
		passwd = @"";

	if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | par) < 0)
		fatal(@"Unable to initialize SDL");

	log("net");
	log(@"net");
	if (enet_initialize() < 0)
		fatal(@"Unable to initialise network module");

	initclient();
	// never returns if dedicated
	initserver(dedicated, uprate, sdesc.UTF8String, ip.UTF8String,
	    master.UTF8String, passwd, maxcl);

	log("world");
	log(@"world");
	empty_world(7, true);

	log("video: sdl");
	log(@"video: sdl");
	if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
		fatal(@"Unable to initialize SDL Video");

	log("video: mode");
	log(@"video: mode");
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	if ((_window = SDL_CreateWindow("cube engine", SDL_WINDOWPOS_UNDEFINED,
	         SDL_WINDOWPOS_UNDEFINED, _width, _height,
	         SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL |
	             (!windowed ? SDL_WINDOW_FULLSCREEN : 0))) == NULL ||
	    SDL_GL_CreateContext(_window) == NULL)
		fatal(@"Unable to create OpenGL screen");

	log("video: misc");
	log(@"video: misc");
	SDL_SetWindowGrab(_window, SDL_TRUE);
	SDL_SetRelativeMouseMode(SDL_TRUE);
	SDL_ShowCursor(0);

	log("gl");
	log(@"gl");
	gl_init(_width, _height);

	log("basetex");
	log(@"basetex");
	_gameDataIRI = [OFFileManager.defaultManager currentDirectoryIRI];
	_userDataIRI = [OFFileManager.defaultManager currentDirectoryIRI];
	int xs, ys;
	if (!installtex(2,
	        [_userDataIRI IRIByAppendingPathComponent:@"data/newchars.png"],
	        &xs, &ys, false) ||
	    !installtex(3,
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
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






-
+


-
+











-
+




-
+







	    !installtex(1,
	        [_userDataIRI
	            IRIByAppendingPathComponent:@"data/crosshair.png"],
	        &xs, &ys, false))
		fatal(@"could not find core textures (hint: run cube from the "
		      @"parent of the bin directory)");

	log("sound");
	log(@"sound");
	initsound();

	log("cfg");
	log(@"cfg");
	newmenu(@"frags\tpj\tping\tteam\tname");
	newmenu(@"ping\tplr\tserver");
	exec(@"data/keymap.cfg");
	exec(@"data/menus.cfg");
	exec(@"data/prefabs.cfg");
	exec(@"data/sounds.cfg");
	exec(@"servers.cfg");
	if (!execfile(@"config.cfg"))
		execfile(@"data/defaults.cfg");
	exec(@"autoexec.cfg");

	log("localconnect");
	log(@"localconnect");
	localconnect();
	// if this map is changed, also change depthcorrect()
	changemap(@"metl3");

	log("mainloop");
	log(@"mainloop");
	int ignore = 5;
	for (;;) {
		int millis = SDL_GetTicks() * gamespeed / 100;
		if (millis - lastmillis > 200)
			lastmillis = millis - 200;
		else if (millis - lastmillis < 1)
			lastmillis = millis - 1;

Modified src/client.mm from [74876b82b8] to [733d35b36f].

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






-
-
-
+
+

-
-
+
+
+


-
+


-
-
+
+
+

-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-







{
	fprintf(f, "name \"%s\"\nteam \"%s\"\n", player1->name, player1->team);
}

void
connects(OFString *servername)
{
	@autoreleasepool {
		disconnect(1); // reset state
		addserver(servername);
	disconnect(1); // reset state
	addserver(servername);

		conoutf(@"attempting to connect to %s", servername.UTF8String);
		ENetAddress address = {ENET_HOST_ANY, CUBE_SERVER_PORT};
	conoutf(@"attempting to connect to %@", servername);
	ENetAddress address = {ENET_HOST_ANY, CUBE_SERVER_PORT};
	@autoreleasepool {
		if (enet_address_set_host(&address, servername.UTF8String) <
		    0) {
			conoutf(@"could not resolve server %s", servername);
			conoutf(@"could not resolve server %@", servername);
			return;
		}

		clienthost = enet_host_create(NULL, 1, rate, rate);
	}

	clienthost = enet_host_create(NULL, 1, rate, rate);

		if (clienthost) {
			enet_host_connect(clienthost, &address, 1);
			enet_host_flush(clienthost);
			connecting = lastmillis;
			connattempts = 0;
		} else {
			conoutf(@"could not connect to server");
			disconnect();
	if (clienthost) {
		enet_host_connect(clienthost, &address, 1);
		enet_host_flush(clienthost);
		connecting = lastmillis;
		connattempts = 0;
	} else {
		conoutf(@"could not connect to server");
		disconnect();
		}
	}
}

void
disconnect(int onlyclean, int async)
{
	if (clienthost) {

Modified src/clientextras.mm from [8bec7c55fe] to [0dee11d744].

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






-
-
+








-
+

-
-
+
+







		    NULL, MAXTRANS + mapsize, ENET_PACKET_FLAG_RELIABLE);
		uchar *start = packet->data;
		uchar *p = start + 2;
		putint(p, SV_SENDMAP);
		sendstring(mapname.UTF8String, p);
		putint(p, mapsize);
		if (65535 - (p - start) < mapdata.count) {
			conoutf(
			    @"map %s is too large to send", mapname.UTF8String);
			conoutf(@"map %@ is too large to send", mapname);
			enet_packet_destroy(packet);
			return;
		}
		memcpy(p, mapdata.items, mapdata.count);
		p += mapsize;
		*(ushort *)start = ENET_HOST_TO_NET_16(p - start);
		enet_packet_resize(packet, p - start);
		sendpackettoserv(packet);
		conoutf(@"sending map %s to server...", mapname.UTF8String);
		conoutf(@"sending map %@ to server...", mapname);
		sprintf_sd(msg)(
		    "[map %s uploaded to server, \"getmap\" to receive it]",
		    mapname.UTF8String);
		    "[map %@ uploaded to server, \"getmap\" to receive it]",
		    mapname);
		toserver(msg);
	}
}

void
getmap()
{

Modified src/clientgame.mm from [48319d1ae1] to [810509b4e7].

156
157
158
159
160
161
162
163

164
165
166
167
168
169
170
156
157
158
159
160
161
162

163
164
165
166
167
168
169
170






-
+







arenarespawn()
{
	if (arenarespawnwait) {
		if (arenarespawnwait < lastmillis) {
			arenarespawnwait = 0;
			conoutf(@"new round starting... fight!");
			respawnself();
		};
		}
	} else if (arenadetectwait == 0 || arenadetectwait < lastmillis) {
		arenadetectwait = 0;
		int alive = 0, dead = 0;
		char *lastteam = NULL;
		bool oneteam = true;
		loopv(players) if (players[i])
		    arenacount(players[i], alive, dead, lastteam, oneteam);
298
299
300
301
302
303
304
305

306
307
308
309
310
311
312
298
299
300
301
302
303
304

305
306
307
308
309
310
311
312






-
+







		float dy = (rnd(21) - 10) / 10.0f * i;
		d->o.x += dx;
		d->o.y += dy;
		if (collide(d, true, 0, 0))
			return;
		d->o.x -= dx;
		d->o.y -= dy;
	};
	}
	conoutf(@"can't find entity spawn spot! (%d, %d)", (int)d->o.x,
	    (int)d->o.y);
	// leave ent at original pos, possibly stuck
};

int spawncycle = -1;
int fixspawn = 2;
473
474
475
476
477
478
479
480

481
482

483
484
485
486
487
488
489
473
474
475
476
477
478
479

480
481

482
483
484
485
486
487
488
489






-
+

-
+







	}
}

dynent *
getclient(int cn) // ensure valid entity
{
	if (cn < 0 || cn >= MAXCLIENTS) {
		neterr("clientnum");
		neterr(@"clientnum");
		return NULL;
	};
	}
	while (cn >= players.length())
		players.add(NULL);
	return players[cn] ? players[cn] : (players[cn] = newdynent());
}

void
initclient()

Modified src/clients2c.mm from [4923c509fd] to [8a230870d2].

1
2
3
4
5
6
7
8
9
10
11

12
13

14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10

11
12

13
14
15
16
17
18
19
20









-
+

-
+







// client processing of the incoming network stream

#include "cube.h"

extern int clientnum;
extern bool c2sinit, senditemstoserver;
extern OFString *toservermap;
extern string clientpassword;

void
neterr(char *s)
neterr(OFString *s)
{
	conoutf(@"illegal network message (%s)", s);
	conoutf(@"illegal network message (%@)", s);
	disconnect();
}

void
changemapserv(char *name, int mode) // forced map change from the server
{
	gamemode = mode;
55
56
57
58
59
60
61
62

63
64
65
66
67
68
69
55
56
57
58
59
60
61

62
63
64
65
66
67
68
69






-
+







};

void
localservertoclient(
    uchar *buf, int len) // processes any updates from the server
{
	if (ENET_NET_TO_HOST_16(*(ushort *)buf) != len)
		neterr("packet length");
		neterr(@"packet length");
	incomingdemodata(buf, len);

	uchar *end = buf + len;
	uchar *p = buf + 2;
	char text[MAXTRANS];
	int cn = -1, type;
	dynent *d = NULL;
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
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






-
+












-
-
+
+

-







			int prot = getint(p);
			if (prot != PROTOCOL_VERSION) {
				conoutf(@"you are using a different game "
				        @"protocol (you: %d, server: %d)",
				    PROTOCOL_VERSION, prot);
				disconnect();
				return;
			};
			}
			toservermap = @"";
			clientnum = cn; // we are now fully connected
			if (!getint(p))
				// we are the first client on this server, set
				// map
				toservermap = getclientmap();
			sgetstr();
			if (text[0] && strcmp(text, clientpassword)) {
				conoutf(@"you need to set the correct password "
				        @"to join this server!");
				disconnect();
				return;
			};
			if (getint(p) == 1) {
			}
			if (getint(p) == 1)
				conoutf(@"server is FULL, disconnecting..");
			};
			break;
		};

		case SV_POS: // position of another client
		{
			cn = getint(p);
			d = getclient(cn);
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
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






-
+
-
+



+
-
+
-



-
+







			break;
		}

		case SV_INITC2S: // another client either connected or changed
		                 // name/team
		{
			sgetstr();
			if (d->name[0]) // already connected
			if (d->name[0]) {
			{
				// already connected
				if (strcmp(d->name, text))
					conoutf(@"%s is now known as %s",
					    d->name, text);
			} else {
			} else // new client
				// new client
			{
				c2sinit =
				    false; // send new players my info again
				conoutf(@"connected: %s", text);
			};
			}
			strcpy_s(d->name, text);
			sgetstr();
			strcpy_s(d->team, text);
			d->lifesequence = getint(p);
			break;
		}

381
382
383
384
385
386
387
388

389
390
391
380
381
382
383
384
385
386

387
388
389
390






-
+



		{
			for (int n = getint(p); n; n--)
				getint(p);
			break;
		}

		default:
			neterr("type");
			neterr(@"type");
			return;
		}
}

Modified src/command.mm from [9583e64f42] to [931e4eb08f].

50
51
52
53
54
55
56

57

58
59
60
61
62
63
64
65
50
51
52
53
54
55
56
57

58

59
60
61
62
63
64
65






+
-
+
-







		b.persist = true;

		idents[b.name] = b;
	} else {
		if (b.type == ID_ALIAS)
			b.action = action;
		else
			conoutf(
			conoutf(@"cannot redefine builtin %s with an alias",
			    @"cannot redefine builtin %@ with an alias", name);
			    name.UTF8String);
	}
}
COMMAND(alias, ARG_2STR)

int
variable(OFString *name, int min, int cur, int max, int *storage, void (*fun)(),
    bool persist)
573
574
575
576
577
578
579
580

581
582
583
584
585
586
587
573
574
575
576
577
578
579

580
581
582
583
584
585
586
587






-
+







}

void
exec(OFString *cfgfile)
{
	if (!execfile(cfgfile)) {
		@autoreleasepool {
			conoutf(@"could not read \"%s\"", cfgfile.UTF8String);
			conoutf(@"could not read \"%@\"", cfgfile);
		}
	}
}

void
writecfg()
{

Modified src/console.mm from [d534e6476d] to [ea51019800].

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






-
-
+
+











-
+

-
+
-
+







-
+

-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+







{
	conskip += n;
	if (conskip < 0)
		conskip = 0;
}
COMMANDN(conskip, setconskip, ARG_1INT)

void
conline(const char *sf, bool highlight) // add a line to the console buffer
static void
conline(OFString *sf, bool highlight) // add a line to the console buffer
{
	cline cl;
	cl.cref = conlines.length() > 100
	              ? conlines.pop().cref
	              : newstringbuf(""); // constrain the buffer size
	cl.outtime = lastmillis;          // for how long to keep line on screen
	conlines.insert(0, cl);
	if (highlight) // show line in a different colour, for chat etc.
	{
		cl.cref[0] = '\f';
		cl.cref[1] = 0;
		strcat_s(cl.cref, sf);
		strcat_s(cl.cref, sf.UTF8String);
	} else {
		strcpy_s(cl.cref, sf);
		strcpy_s(cl.cref, sf.UTF8String);
	};
	}
	puts(cl.cref);
#ifndef OF_WINDOWS
	fflush(stdout);
#endif
}

void
conoutf(OFString *str, ...)
conoutf(OFConstantString *format, ...)
{
	sprintf_sdv(sf, str.UTF8String);
	const char *s = sf;
	int n = 0;
	while (strlen(s) > WORDWRAP) // cut strings to fit on screen
	{
		string t;
		strn0cpy(t, s, WORDWRAP + 1);
		conline(t, n++ != 0);
		s += WORDWRAP;
	}
	conline(s, n != 0);
	@autoreleasepool {
		va_list arguments;
		va_start(arguments, format);

		OFString *string = [[OFString alloc] initWithFormat:format
		                                          arguments:arguments];

		va_end(arguments);

		int n = 0;
		while (string.length > WORDWRAP) {
			conline([string substringToIndex:WORDWRAP], n++ != 0);
			string = [string substringFromIndex:WORDWRAP];
		}
		conline(string, n != 0);
};
	}
}

void
renderconsole() // render buffer taking into account time & scrolling
{
	int nd = 0;
	char *refs[ndraw];
	loopv(conlines) if (conskip ? i >= conskip - 1 ||

Modified src/editing.mm from [78d08b56c5] to [c8df421539].

91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
91
92
93
94
95
96
97

98
99
100
101
102
103
104
105

106
107
108
109
110
111
112
113






-
+







-
+







bool
noteditmode()
{
	correctsel();
	if (!editmode)
		conoutf(@"this function is only allowed in edit mode");
	return !editmode;
};
}

bool
noselection()
{
	if (!selset)
		conoutf(@"no selection");
	return !selset;
};
}

#define EDITSEL                                                                \
	if (noteditmode() || noselection())                                    \
		return;
#define EDITSELMP                                                              \
	if (noteditmode() || noselection() || multiplayer())                   \
		return;
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
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






-
+



-
+



















-
+






-
+




-
+







void
editundo()
{
	EDITMP;
	if (undos.empty()) {
		conoutf(@"nothing more to undo");
		return;
	};
	}
	block *p = undos.pop();
	blockpaste(*p);
	free(p);
};
}

block *copybuf = NULL;

void
copy()
{
	EDITSELMP;
	if (copybuf)
		free(copybuf);
	copybuf = blockcopy(sel);
};

void
paste()
{
	EDITMP;
	if (!copybuf) {
		conoutf(@"nothing to paste");
		return;
	};
	}
	sel.xs = copybuf->xs;
	sel.ys = copybuf->ys;
	correctsel();
	if (!selset || sel.xs != copybuf->xs || sel.ys != copybuf->ys) {
		conoutf(@"incorrect selection");
		return;
	};
	}
	makeundo();
	copybuf->x = sel.x;
	copybuf->y = sel.y;
	blockpaste(*copybuf);
};
}

void
tofronttex() // maintain most recently used of the texture lists when applying
             // texture
{
	loopi(3)
	{
443
444
445
446
447
448
449
450

451
452
453

454
455
456
457
458
459
460
443
444
445
446
447
448
449

450
451
452

453
454
455
456
457
458
459
460






-
+


-
+







{
	EDITSEL;
	if (type == CORNER &&
	    (sel.xs != sel.ys || sel.xs == 3 || sel.xs > 4 && sel.xs != 8 ||
	        sel.x & ~-sel.xs || sel.y & ~-sel.ys)) {
		conoutf(@"corner selection must be power of 2 aligned");
		return;
	};
	}
	edittypexy(type, sel);
	addmsg(1, 6, SV_EDITS, sel.x, sel.y, sel.xs, sel.ys, type);
};
}

void
heightfield(int t)
{
	edittype(t == 0 ? FHF : CHF);
}
COMMAND(heightfield, ARG_1INT)

Modified src/entities.mm from [1ac9739b65] to [fa2e7605f2].

213
214
215
216
217
218
219
220

221
222
223
224
225
226
227
213
214
215
216
217
218
219

220
221
222
223
224
225
226
227






-
+







{
	int e = -1, tag = ents[n].attr1, beenhere = -1;
	for (;;) {
		e = findentity(TELEDEST, e + 1);
		if (e == beenhere || e < 0) {
			conoutf(@"no teleport destination for tag %d", tag);
			return;
		};
		}
		if (beenhere < 0)
			beenhere = e;
		if (ents[e].attr2 == tag) {
			d->o.x = ents[e].x;
			d->o.y = ents[e].y;
			d->o.z = ents[e].z;
			d->yaw = ents[e].attr1;

Modified src/monster.mm from [a11e61394d] to [34205145ec].

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












+
-
+




-
+







// monster.cpp: implements AI for single player monsters, currently client only

#include "cube.h"

dvector monsters;
int nextmonster, spawnremain, numkilled, monstertotal, mtimestart;

VARF(skill, 1, 3, 10, conoutf(@"skill is now %d", skill));

dvector &
getmonsters()
{
	return monsters;
}
};

void
restoremonsterstate()
{
	loopv(monsters) if (monsters[i]->state == CS_DEAD) numkilled++;
}; // for savegames
} // for savegames

#define TOTMFREQ 13
#define NUMMONSTERTYPES 8

struct monstertype // see docs for how these values modify behaviour
{
	short gun, speed, health, freq, lag, rate, pain, loyalty, mscale,
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
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






-
+











-
+







		player1->frags = numkilled;
		playsound(monstertypes[m->mtype].diesound, &m->o);
		int remain = monstertotal - numkilled;
		if (remain > 0 && remain <= 5)
			conoutf(@"only %d monster(s) remaining", remain);
	} else {
		playsound(monstertypes[m->mtype].painsound, &m->o);
	};
	}
};

void
endsp(bool allkilled)
{
	conoutf(allkilled ? @"you have cleared the map!"
	                  : @"you reached the exit!");
	conoutf(@"score: %d kills in %d seconds", numkilled,
	    (lastmillis - mtimestart) / 1000);
	monstertotal = 0;
	startintermission();
};
}

void
monsterthink()
{
	if (m_dmsp && spawnremain && lastmillis > nextmonster) {
		if (spawnremain-- == monstertotal)
			conoutf(@"The invasion has begun!");
397
398
399
400
401
402
403
404

405
406
407
408
409
410
411
412
398
399
400
401
402
403
404

405
406
407
408
409
410
411
412
413






-
+








			if (dist < 4)
				teleport((int)(&e - &ents[0]), monsters[i]);
		};
	};

	loopv(monsters) if (monsters[i]->state == CS_ALIVE)
	    monsteraction(monsters[i]);
};
}

void
monsterrender()
{
	loopv(monsters) renderclient(monsters[i], false,
	    monstertypes[monsters[i]->mtype].mdlname, monsters[i]->mtype == 5,
	    monstertypes[monsters[i]->mtype].mscale / 10.0f);
}

Modified src/protos.h from [8b1e3ca44e] to [c2d6bbe699].

15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
15
16
17
18
19
20
21

22
23
24
25
26
27
28
29






-
+







extern void alias(OFString *name, OFString *action);
extern OFString *getalias(OFString *name);
extern void writecfg();

// console
extern void keypress(int code, bool isdown, int cooked);
extern void renderconsole();
extern void conoutf(OFString *s, ...);
extern void conoutf(OFConstantString *format, ...);
extern char *getcurcommand();
extern void writebinds(FILE *f);

// init
extern void enqueueInit(void (^init)(void));
extern void processInitQueue(void);

74
75
76
77
78
79
80
81

82
83
84
85
86
87
88
74
75
76
77
78
79
80

81
82
83
84
85
86
87
88






-
+







extern void toserver(char *text);
extern void addmsg(int rel, int num, int type, ...);
extern bool multiplayer();
extern bool allowedittoggle();
extern void sendpackettoserv(void *packet);
extern void gets2c();
extern void c2sinfo(dynent *d);
extern void neterr(char *s);
extern void neterr(OFString *s);
extern void initclientnet();
extern bool netmapstart();
extern int getclientnum();
extern void changemapserv(char *name, int mode);
extern void writeclientinfo(FILE *f);

// clientgame

Modified src/rendergl.mm from [86ca5a8f24] to [7db200290d].

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






-
-
+








-
-
+
+








-
-
+
+







bool
installtex(int tnum, OFIRI *IRI, int *xs, int *ys, bool clamp)
{
	@autoreleasepool {
		SDL_Surface *s =
		    IMG_Load(IRI.fileSystemRepresentation.UTF8String);
		if (s == NULL) {
			conoutf(
			    @"couldn't load texture %s", IRI.string.UTF8String);
			conoutf(@"couldn't load texture %@", IRI.string);
			return false;
		}

		if (s->format->BitsPerPixel != 24) {
			SDL_PixelFormat *format =
			    SDL_AllocFormat(SDL_PIXELFORMAT_RGB24);
			if (format == NULL) {
				conoutf(
				    @"texture cannot be converted to 24bpp: %s",
				    IRI.string.UTF8String);
				    @"texture cannot be converted to 24bpp: %@",
				    IRI.string);
				return false;
			}

			@try {
				SDL_Surface *converted =
				    SDL_ConvertSurface(s, format, 0);
				if (converted == NULL) {
					conoutf(@"texture cannot be converted "
					        @"to 24bpp: %s",
					    IRI.string.UTF8String);
					        @"to 24bpp: %@",
					    IRI.string);
					return false;
				}

				SDL_FreeSurface(s);
				s = converted;
			} @finally {
				SDL_FreeFormat(format);
131
132
133
134
135
136
137
138

139
140

141
142
143
144
145
146
147
130
131
132
133
134
135
136

137


138
139
140
141
142
143
144
145






-
+
-
-
+







			*xs /= 2;
			*ys /= 2;
		}

		void *scaledimg = s->pixels;

		if (*xs != s->w) {
			conoutf(@"warning: quality loss: scaling %s",
			conoutf(@"warning: quality loss: scaling %@",
			    IRI.string
			        .UTF8String); // for voodoo cards under linux
			    IRI.string); // for voodoo cards under linux
			scaledimg = alloc(*xs * *ys * 3);
			gluScaleImage(GL_RGB, s->w, s->h, GL_UNSIGNED_BYTE,
			    s->pixels, *xs, *ys, GL_UNSIGNED_BYTE, scaledimg);
		}

		if (gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, *xs, *ys, GL_RGB,
		        GL_UNSIGNED_BYTE, scaledimg))

Modified src/savegamedemo.mm from [ba5f21d861] to [01f038147b].

91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
91
92
93
94
95
96
97

98
99
100
101
102
103
104
105






-
+







savestate(char *fn)
{
	stop();
	f = gzopen(fn, "wb9");
	if (!f) {
		conoutf(@"could not write %s", fn);
		return;
	};
	}
	gzwrite(f, (void *)"CUBESAVE", 8);
	gzputc(f, islittleendian);
	gzputi(SAVEGAMEVERSION);
	gzputi(sizeof(dynent));
	@autoreleasepool {
		gzwrite(f, getclientmap().UTF8String, _MAXDEFSTR);
	}
182
183
184
185
186
187
188
189

190
191
192
193
194
195
196
182
183
184
185
186
187
188

189
190
191
192
193
194
195
196






-
+







void
loadgameout()
{
	stop();
	conoutf(@"loadgame incomplete: savegame from a different version of "
	        @"this map");
};
}

void
loadgamerest()
{
	if (demoplayback || !f)
		return;

233
234
235
236
237
238
239
240

241
242
243
244
245
246
247
233
234
235
236
237
238
239

240
241
242
243
244
245
246
247






-
+







	};

	conoutf(@"savegame restored");
	if (demoloading)
		startdemo();
	else
		stop();
};
}

// demo functions

int starttime = 0;
int playbacktime = 0;
int ddamage, bdamage;
OFVector3D dorig;

Modified src/sound.mm from [b06342c3fd] to [320b4f8793].

109
110
111
112
113
114
115

116

117
118
119
120
121
122
123
109
110
111
112
113
114
115
116

117
118
119
120
121
122
123
124






+
-
+







				    FSOUND_Stream_Play(FSOUND_FREE, stream);
				if (chan >= 0) {
					FSOUND_SetVolume(
					    chan, (musicvol * MAXVOL) / 255);
					FSOUND_SetPaused(chan, false);
				}
			} else {
				conoutf(
				conoutf(@"could not play music: %s", sn);
				    @"could not play music: %@", IRI.string);
			}
#endif
		}
	}
}
COMMAND(music, ARG_1STR)

Modified src/weapon.mm from [32ce1b4cac] to [efed2ffe54].

46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
46
47
48
49
50
51
52

53
54
55
56
57
58
59
60






-
+







	else if (s != GUN_RIFLE && player1->ammo[GUN_RIFLE])
		s = GUN_RIFLE;
	else
		s = GUN_FIST;
	if (s != player1->gunselect)
		playsoundc(S_WEAPLOAD);
	player1->gunselect = s;
	// conoutf(@"%s selected", (int)guns[s].name.UTF8String);
	// conoutf(@"%@ selected", (int)guns[s].name);
}

int
reloadtime(int gun)
{
	return guns[gun].attackdelay;
}

Modified src/world.mm from [061f7f026c] to [dc3bab95c0].

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






-
+


-
+












-
+







void
delent()
{
	int e = closestent();
	if (e < 0) {
		conoutf(@"no more entities");
		return;
	};
	}
	int t = ents[e].type;
	@autoreleasepool {
		conoutf(@"%s entity deleted", entnames[t].UTF8String);
		conoutf(@"%@ entity deleted", entnames[t]);
	}
	ents[e].type = NOTUSED;
	addmsg(1, 10, SV_EDITENT, e, NOTUSED, 0, 0, 0, 0, 0, 0, 0);
	if (t == LIGHT)
		calclight();
}

int
findtype(OFString *what)
{
	@autoreleasepool {
		loopi(MAXENTTYPES) if ([what isEqual:entnames[i]]) return i;
		conoutf(@"unknown entity type \"%s\"", what.UTF8String);
		conoutf(@"unknown entity type \"%@\"", what);
		return NOTUSED;
	}
}

entity *
newentity(int x, int y, int z, OFString *what, int v1, int v2, int v3, int v4)
{