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

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







|
|







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)
	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
		ip = @"";
	if (passwd == nil)
		passwd = @"";

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

	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");
	empty_world(7, true);

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

	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");
	SDL_SetWindowGrab(_window, SDL_TRUE);
	SDL_SetRelativeMouseMode(SDL_TRUE);
	SDL_ShowCursor(0);

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

	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,







|








|


|



|








|




|


|







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");
	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");
	empty_world(7, true);

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

	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");
	SDL_SetWindowGrab(_window, SDL_TRUE);
	SDL_SetRelativeMouseMode(SDL_TRUE);
	SDL_ShowCursor(0);

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

	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
	    !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");
	initsound();

	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");
	localconnect();
	// if this map is changed, also change depthcorrect()
	changemap(@"metl3");

	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;







|


|











|




|







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");
	initsound();

	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");
	localconnect();
	// if this map is changed, also change depthcorrect()
	changemap(@"metl3");

	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
{
	fprintf(f, "name \"%s\"\nteam \"%s\"\n", player1->name, player1->team);
}

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

		conoutf(@"attempting to connect to %s", servername.UTF8String);
		ENetAddress address = {ENET_HOST_ANY, CUBE_SERVER_PORT};

		if (enet_address_set_host(&address, servername.UTF8String) <
		    0) {
			conoutf(@"could not resolve server %s", servername);
			return;
		}


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

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







<
|
|

|
|
>


|


|
>
|

|
|
|
|
|
|
|
|
<







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

	disconnect(1); // reset state
	addserver(servername);

	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 %@", servername);
			return;
		}
	}

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

	}
}

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
		    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);
			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);
		sprintf_sd(msg)(
		    "[map %s uploaded to server, \"getmap\" to receive it]",
		    mapname.UTF8String);
		toserver(msg);
	}
}

void
getmap()
{







<
|








|

|
|







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 %@ 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 %@ to server...", mapname);
		sprintf_sd(msg)(
		    "[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
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);







<
>







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







<
>







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

dynent *
getclient(int cn) // ensure valid entity
{
	if (cn < 0 || cn >= MAXCLIENTS) {
		neterr("clientnum");
		return NULL;
	};

	while (cn >= players.length())
		players.add(NULL);
	return players[cn] ? players[cn] : (players[cn] = newdynent());
}

void
initclient()







|

<
>







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");
		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
// 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)
{
	conoutf(@"illegal network message (%s)", s);
	disconnect();
}

void
changemapserv(char *name, int mode) // forced map change from the server
{
	gamemode = mode;










|

|







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(OFString *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
};

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

	uchar *end = buf + len;
	uchar *p = buf + 2;
	char text[MAXTRANS];
	int cn = -1, type;
	dynent *d = NULL;







|







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");
	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
			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) {
				conoutf(@"server is FULL, disconnecting..");
			};
			break;
		};

		case SV_POS: // position of another client
		{
			cn = getint(p);
			d = getclient(cn);







<
>












<
>
|

<







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

		case SV_INITC2S: // another client either connected or changed
		                 // name/team
		{
			sgetstr();
			if (d->name[0]) // already connected
			{

				if (strcmp(d->name, text))
					conoutf(@"%s is now known as %s",
					    d->name, text);

			} else // 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;
		}








|
<
>



>
|
<



<
>







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 (strcmp(d->name, text))
					conoutf(@"%s is now known as %s",
					    d->name, text);
			} else {
				// 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
		{
			for (int n = getint(p); n; n--)
				getint(p);
			break;
		}

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







|



380
381
382
383
384
385
386
387
388
389
390
		{
			for (int n = getint(p); n; n--)
				getint(p);
			break;
		}

		default:
			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
		b.persist = true;

		idents[b.name] = b;
	} else {
		if (b.type == ID_ALIAS)
			b.action = action;
		else

			conoutf(@"cannot redefine builtin %s with an alias",
			    name.UTF8String);
	}
}
COMMAND(alias, ARG_2STR)

int
variable(OFString *name, int min, int cur, int max, int *storage, void (*fun)(),
    bool persist)







>
|
<







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(
			    @"cannot redefine builtin %@ with an alias", name);

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

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

void
writecfg()
{







|







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 \"%@\"", 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
{
	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
{
	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);
	} else {
		strcpy_s(cl.cref, sf);
	};

	puts(cl.cref);
#ifndef OF_WINDOWS
	fflush(stdout);
#endif
}

void
conoutf(OFString *str, ...)
{
	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);
};



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







|
|











|

|
<
>







|

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







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)

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.UTF8String);
	} else {
		strcpy_s(cl.cref, sf.UTF8String);

	}
	puts(cl.cref);
#ifndef OF_WINDOWS
	fflush(stdout);
#endif
}

void
conoutf(OFConstantString *format, ...)
{
	@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
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;







<
>







<
>







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







<
>



<
>



















<
>






<
>




<
>







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







<
>


<
>







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







<
>







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

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













>
|




|







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

#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
		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!");







<
>











<
>







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







<
>








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
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 char *getcurcommand();
extern void writebinds(FILE *f);

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








|







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(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
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 initclientnet();
extern bool netmapstart();
extern int getclientnum();
extern void changemapserv(char *name, int mode);
extern void writeclientinfo(FILE *f);

// clientgame







|







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(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
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);
			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);
				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);
					return false;
				}

				SDL_FreeSurface(s);
				s = converted;
			} @finally {
				SDL_FreeFormat(format);







<
|








|
|








|
|







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 %@", 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: %@",
				    IRI.string);
				return false;
			}

			@try {
				SDL_Surface *converted =
				    SDL_ConvertSurface(s, format, 0);
				if (converted == NULL) {
					conoutf(@"texture cannot be converted "
					        @"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
			*xs /= 2;
			*ys /= 2;
		}

		void *scaledimg = s->pixels;

		if (*xs != s->w) {
			conoutf(@"warning: quality loss: scaling %s",
			    IRI.string
			        .UTF8String); // 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))







|
<
|







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 %@",

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







<
>







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

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


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








<
>







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

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


// demo functions

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







<
>







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
				    FSOUND_Stream_Play(FSOUND_FREE, stream);
				if (chan >= 0) {
					FSOUND_SetVolume(
					    chan, (musicvol * MAXVOL) / 255);
					FSOUND_SetPaused(chan, false);
				}
			} else {

				conoutf(@"could not play music: %s", sn);
			}
#endif
		}
	}
}
COMMAND(music, ARG_1STR)








>
|







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(
				    @"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
	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);
}

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







|







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(@"%@ 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
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);
	}
	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);
		return NOTUSED;
	}
}

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







<
>


|












|







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(@"%@ 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 \"%@\"", what);
		return NOTUSED;
	}
}

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