1 /*
2 	C-Dogs SDL
3 	A port of the legendary (and fun) action/arcade cdogs.
4 	Copyright (c) 2013-2016, 2019-2021 Cong Xu
5 	All rights reserved.
6 
7 	Redistribution and use in source and binary forms, with or without
8 	modification, are permitted provided that the following conditions are met:
9 
10 	Redistributions of source code must retain the above copyright notice, this
11 	list of conditions and the following disclaimer.
12 	Redistributions in binary form must reproduce the above copyright notice,
13 	this list of conditions and the following disclaimer in the documentation
14 	and/or other materials provided with the distribution.
15 
16 	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 	POSSIBILITY OF SUCH DAMAGE.
27 */
28 #include "editor_ui_classic.h"
29 
30 #include <cdogs/draw/draw_actor.h>
31 #include <cdogs/font.h>
32 #include <cdogs/gamedata.h>
33 
34 #include "editor_ui_common.h"
35 
36 #define Y_ABS 200
37 
MISSION_CHECK_TYPE_FUNC(MAPTYPE_CLASSIC)38 MISSION_CHECK_TYPE_FUNC(MAPTYPE_CLASSIC)
39 static const char *MissionGetWallCountStr(UIObject *o, void *data)
40 {
41 	static char s[128];
42 	UNUSED(o);
43 	Campaign *co = data;
44 	if (!CampaignGetCurrentMission(co))
45 		return NULL;
46 	sprintf(s, "Walls: %d", CampaignGetCurrentMission(co)->u.Classic.Walls);
47 	return s;
48 }
MissionGetWallLengthStr(UIObject * o,void * data)49 static const char *MissionGetWallLengthStr(UIObject *o, void *data)
50 {
51 	static char s[128];
52 	UNUSED(o);
53 	Campaign *co = data;
54 	if (!CampaignGetCurrentMission(co))
55 		return NULL;
56 	sprintf(s, "Len: %d", CampaignGetCurrentMission(co)->u.Classic.WallLength);
57 	return s;
58 }
MissionGetCorridorWidthStr(UIObject * o,void * data)59 static const char *MissionGetCorridorWidthStr(UIObject *o, void *data)
60 {
61 	static char s[128];
62 	UNUSED(o);
63 	Campaign *co = data;
64 	if (!CampaignGetCurrentMission(co))
65 		return NULL;
66 	sprintf(
67 		s, "CorridorWidth: %d",
68 		CampaignGetCurrentMission(co)->u.Classic.CorridorWidth);
69 	return s;
70 }
MissionGetRoomCountStr(UIObject * o,void * data)71 static const char *MissionGetRoomCountStr(UIObject *o, void *data)
72 {
73 	static char s[128];
74 	UNUSED(o);
75 	Campaign *co = data;
76 	if (!CampaignGetCurrentMission(co))
77 		return NULL;
78 	sprintf(
79 		s, "Rooms: %d", CampaignGetCurrentMission(co)->u.Classic.Rooms.Count);
80 	return s;
81 }
MissionGetRoomMinStr(UIObject * o,void * data)82 static const char *MissionGetRoomMinStr(UIObject *o, void *data)
83 {
84 	static char s[128];
85 	UNUSED(o);
86 	Campaign *co = data;
87 	if (!CampaignGetCurrentMission(co))
88 		return NULL;
89 	sprintf(
90 		s, "RoomMin: %d", CampaignGetCurrentMission(co)->u.Classic.Rooms.Min);
91 	return s;
92 }
MissionGetRoomMaxStr(UIObject * o,void * data)93 static const char *MissionGetRoomMaxStr(UIObject *o, void *data)
94 {
95 	static char s[128];
96 	UNUSED(o);
97 	Campaign *co = data;
98 	if (!CampaignGetCurrentMission(co))
99 		return NULL;
100 	sprintf(
101 		s, "RoomMax: %d", CampaignGetCurrentMission(co)->u.Classic.Rooms.Max);
102 	return s;
103 }
MissionDrawEdgeRooms(UIObject * o,GraphicsDevice * g,struct vec2i pos,void * data)104 static void MissionDrawEdgeRooms(
105 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data)
106 {
107 	UNUSED(o);
108 	UNUSED(g);
109 	Campaign *co = data;
110 	if (!CampaignGetCurrentMission(co))
111 		return;
112 	DisplayFlag(
113 		svec2i_add(pos, o->Pos), "Edge rooms",
114 		CampaignGetCurrentMission(co)->u.Classic.Rooms.Edge,
115 		UIObjectIsHighlighted(o));
116 }
MissionDrawRoomsOverlap(UIObject * o,GraphicsDevice * g,struct vec2i pos,void * data)117 static void MissionDrawRoomsOverlap(
118 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data)
119 {
120 	UNUSED(o);
121 	UNUSED(g);
122 	UNUSED(pos);
123 	Campaign *co = data;
124 	if (!CampaignGetCurrentMission(co))
125 		return;
126 	DisplayFlag(
127 		svec2i_add(pos, o->Pos), "Room overlap",
128 		CampaignGetCurrentMission(co)->u.Classic.Rooms.Overlap,
129 		UIObjectIsHighlighted(o));
130 }
MissionGetRoomWallCountStr(UIObject * o,void * data)131 static const char *MissionGetRoomWallCountStr(UIObject *o, void *data)
132 {
133 	static char s[128];
134 	UNUSED(o);
135 	Campaign *co = data;
136 	if (!CampaignGetCurrentMission(co))
137 		return NULL;
138 	sprintf(
139 		s, "RoomWalls: %d",
140 		CampaignGetCurrentMission(co)->u.Classic.Rooms.Walls);
141 	return s;
142 }
MissionGetRoomWallLenStr(UIObject * o,void * data)143 static const char *MissionGetRoomWallLenStr(UIObject *o, void *data)
144 {
145 	static char s[128];
146 	UNUSED(o);
147 	Campaign *co = data;
148 	if (!CampaignGetCurrentMission(co))
149 		return NULL;
150 	sprintf(
151 		s, "RoomWallLen: %d",
152 		CampaignGetCurrentMission(co)->u.Classic.Rooms.WallLength);
153 	return s;
154 }
MissionGetRoomWallPadStr(UIObject * o,void * data)155 static const char *MissionGetRoomWallPadStr(UIObject *o, void *data)
156 {
157 	static char s[128];
158 	UNUSED(o);
159 	Campaign *co = data;
160 	if (!CampaignGetCurrentMission(co))
161 		return NULL;
162 	sprintf(
163 		s, "RoomWallPad: %d",
164 		CampaignGetCurrentMission(co)->u.Classic.Rooms.WallPad);
165 	return s;
166 }
MissionGetSquareCountStr(UIObject * o,void * data)167 static const char *MissionGetSquareCountStr(UIObject *o, void *data)
168 {
169 	static char s[128];
170 	UNUSED(o);
171 	Campaign *co = data;
172 	if (!CampaignGetCurrentMission(co))
173 		return NULL;
174 	sprintf(s, "Sqr: %d", CampaignGetCurrentMission(co)->u.Classic.Squares);
175 	return s;
176 }
MissionDrawExitEnabled(UIObject * o,GraphicsDevice * g,struct vec2i pos,void * data)177 static void MissionDrawExitEnabled(
178 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data)
179 {
180 	UNUSED(o);
181 	UNUSED(g);
182 	Campaign *co = data;
183 	if (!CampaignGetCurrentMission(co))
184 		return;
185 	DisplayFlag(
186 		svec2i_add(pos, o->Pos), "Exit",
187 		CampaignGetCurrentMission(co)->u.Classic.ExitEnabled,
188 		UIObjectIsHighlighted(o));
189 }
MissionDrawDoorEnabled(UIObject * o,GraphicsDevice * g,struct vec2i pos,void * data)190 static void MissionDrawDoorEnabled(
191 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data)
192 {
193 	UNUSED(o);
194 	UNUSED(g);
195 	Campaign *co = data;
196 	Mission *m = CampaignGetCurrentMission(co);
197 	if (!m)
198 		return;
199 	DisplayFlag(
200 		svec2i_add(pos, o->Pos), "Doors",
201 		m->u.Classic.Doors.Enabled,
202 		UIObjectIsHighlighted(o));
203 }
MissionGetDoorMinStr(UIObject * o,void * data)204 static const char *MissionGetDoorMinStr(UIObject *o, void *data)
205 {
206 	static char s[128];
207 	UNUSED(o);
208 	Campaign *co = data;
209 	if (!CampaignGetCurrentMission(co))
210 		return NULL;
211 	sprintf(
212 		s, "DoorMin: %d", CampaignGetCurrentMission(co)->u.Classic.Doors.Min);
213 	return s;
214 }
MissionGetDoorMaxStr(UIObject * o,void * data)215 static const char *MissionGetDoorMaxStr(UIObject *o, void *data)
216 {
217 	static char s[128];
218 	UNUSED(o);
219 	Campaign *co = data;
220 	if (!CampaignGetCurrentMission(co))
221 		return NULL;
222 	sprintf(
223 		s, "DoorMax: %d", CampaignGetCurrentMission(co)->u.Classic.Doors.Max);
224 	return s;
225 }
MissionDrawDoorRandomPos(UIObject * o,GraphicsDevice * g,struct vec2i pos,void * data)226 static void MissionDrawDoorRandomPos(
227 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data)
228 {
229 	UNUSED(o);
230 	UNUSED(g);
231 	Campaign *co = data;
232 	Mission *m = CampaignGetCurrentMission(co);
233 	if (!m)
234 		return;
235 	DisplayFlag(
236 		svec2i_add(pos, o->Pos), "DoorRandomPos",
237 		m->u.Classic.Doors.RandomPos,
238 		UIObjectIsHighlighted(o));
239 }
MissionGetPillarCountStr(UIObject * o,void * data)240 static const char *MissionGetPillarCountStr(UIObject *o, void *data)
241 {
242 	static char s[128];
243 	UNUSED(o);
244 	Campaign *co = data;
245 	if (!CampaignGetCurrentMission(co))
246 		return NULL;
247 	sprintf(
248 		s, "Pillars: %d",
249 		CampaignGetCurrentMission(co)->u.Classic.Pillars.Count);
250 	return s;
251 }
MissionGetPillarMinStr(UIObject * o,void * data)252 static const char *MissionGetPillarMinStr(UIObject *o, void *data)
253 {
254 	static char s[128];
255 	UNUSED(o);
256 	Campaign *co = data;
257 	if (!CampaignGetCurrentMission(co))
258 		return NULL;
259 	sprintf(
260 		s, "PillarMin: %d",
261 		CampaignGetCurrentMission(co)->u.Classic.Pillars.Min);
262 	return s;
263 }
MissionGetPillarMaxStr(UIObject * o,void * data)264 static const char *MissionGetPillarMaxStr(UIObject *o, void *data)
265 {
266 	static char s[128];
267 	UNUSED(o);
268 	Campaign *co = data;
269 	if (!CampaignGetCurrentMission(co))
270 		return NULL;
271 	sprintf(
272 		s, "PillarMax: %d",
273 		CampaignGetCurrentMission(co)->u.Classic.Pillars.Max);
274 	return s;
275 }
276 
MissionChangeWallCount(void * data,int d)277 static EditorResult MissionChangeWallCount(void *data, int d)
278 {
279 	Campaign *co = data;
280 	CampaignGetCurrentMission(co)->u.Classic.Walls =
281 		CLAMP(CampaignGetCurrentMission(co)->u.Classic.Walls + d, 0, 200);
282 	return EDITOR_RESULT_CHANGED;
283 }
MissionChangeWallLength(void * data,int d)284 static EditorResult MissionChangeWallLength(void *data, int d)
285 {
286 	Campaign *co = data;
287 	CampaignGetCurrentMission(co)->u.Classic.WallLength =
288 		CLAMP(CampaignGetCurrentMission(co)->u.Classic.WallLength + d, 1, 100);
289 	return EDITOR_RESULT_CHANGED;
290 }
MissionChangeCorridorWidth(void * data,int d)291 static EditorResult MissionChangeCorridorWidth(void *data, int d)
292 {
293 	Campaign *co = data;
294 	CampaignGetCurrentMission(co)->u.Classic.CorridorWidth = CLAMP(
295 		CampaignGetCurrentMission(co)->u.Classic.CorridorWidth + d, 1, 5);
296 	return EDITOR_RESULT_CHANGED;
297 }
MissionChangeRoomCount(void * data,int d)298 static EditorResult MissionChangeRoomCount(void *data, int d)
299 {
300 	Campaign *co = data;
301 	CampaignGetCurrentMission(co)->u.Classic.Rooms.Count = CLAMP(
302 		CampaignGetCurrentMission(co)->u.Classic.Rooms.Count + d, 0, 100);
303 	return EDITOR_RESULT_CHANGED;
304 }
MissionChangeRoomMin(void * data,int d)305 static EditorResult MissionChangeRoomMin(void *data, int d)
306 {
307 	Campaign *co = data;
308 	CampaignGetCurrentMission(co)->u.Classic.Rooms.Min =
309 		CLAMP(CampaignGetCurrentMission(co)->u.Classic.Rooms.Min + d, 5, 50);
310 	CampaignGetCurrentMission(co)->u.Classic.Rooms.Max =
311 		MAX(CampaignGetCurrentMission(co)->u.Classic.Rooms.Min,
312 			CampaignGetCurrentMission(co)->u.Classic.Rooms.Max);
313 	return EDITOR_RESULT_CHANGED;
314 }
MissionChangeRoomMax(void * data,int d)315 static EditorResult MissionChangeRoomMax(void *data, int d)
316 {
317 	Campaign *co = data;
318 	CampaignGetCurrentMission(co)->u.Classic.Rooms.Max =
319 		CLAMP(CampaignGetCurrentMission(co)->u.Classic.Rooms.Max + d, 5, 50);
320 	CampaignGetCurrentMission(co)->u.Classic.Rooms.Min =
321 		MIN(CampaignGetCurrentMission(co)->u.Classic.Rooms.Min,
322 			CampaignGetCurrentMission(co)->u.Classic.Rooms.Max);
323 	return EDITOR_RESULT_CHANGED;
324 }
MissionChangeEdgeRooms(void * data,int d)325 static EditorResult MissionChangeEdgeRooms(void *data, int d)
326 {
327 	UNUSED(d);
328 	Campaign *co = data;
329 	CampaignGetCurrentMission(co)->u.Classic.Rooms.Edge =
330 		!CampaignGetCurrentMission(co)->u.Classic.Rooms.Edge;
331 	return EDITOR_RESULT_CHANGED;
332 }
MissionChangeRoomsOverlap(void * data,int d)333 static EditorResult MissionChangeRoomsOverlap(void *data, int d)
334 {
335 	UNUSED(d);
336 	Campaign *co = data;
337 	CampaignGetCurrentMission(co)->u.Classic.Rooms.Overlap =
338 		!CampaignGetCurrentMission(co)->u.Classic.Rooms.Overlap;
339 	return EDITOR_RESULT_CHANGED;
340 }
MissionChangeRoomWallCount(void * data,int d)341 static EditorResult MissionChangeRoomWallCount(void *data, int d)
342 {
343 	Campaign *co = data;
344 	CampaignGetCurrentMission(co)->u.Classic.Rooms.Walls =
345 		CLAMP(CampaignGetCurrentMission(co)->u.Classic.Rooms.Walls + d, 0, 50);
346 	return EDITOR_RESULT_CHANGED;
347 }
MissionChangeRoomWallLen(void * data,int d)348 static EditorResult MissionChangeRoomWallLen(void *data, int d)
349 {
350 	Campaign *co = data;
351 	CampaignGetCurrentMission(co)->u.Classic.Rooms.WallLength = CLAMP(
352 		CampaignGetCurrentMission(co)->u.Classic.Rooms.WallLength + d, 1, 50);
353 	return EDITOR_RESULT_CHANGED;
354 }
MissionChangeRoomWallPad(void * data,int d)355 static EditorResult MissionChangeRoomWallPad(void *data, int d)
356 {
357 	Campaign *co = data;
358 	CampaignGetCurrentMission(co)->u.Classic.Rooms.WallPad = CLAMP(
359 		CampaignGetCurrentMission(co)->u.Classic.Rooms.WallPad + d, 1, 10);
360 	return EDITOR_RESULT_CHANGED;
361 }
MissionChangeSquareCount(void * data,int d)362 static EditorResult MissionChangeSquareCount(void *data, int d)
363 {
364 	Campaign *co = data;
365 	CampaignGetCurrentMission(co)->u.Classic.Squares =
366 		CLAMP(CampaignGetCurrentMission(co)->u.Classic.Squares + d, 0, 100);
367 	return EDITOR_RESULT_CHANGED;
368 }
MissionChangeExitEnabled(void * data,int d)369 static EditorResult MissionChangeExitEnabled(void *data, int d)
370 {
371 	UNUSED(d);
372 	Campaign *co = data;
373 	CampaignGetCurrentMission(co)->u.Classic.ExitEnabled =
374 		!CampaignGetCurrentMission(co)->u.Classic.ExitEnabled;
375 	return EDITOR_RESULT_CHANGED;
376 }
MissionChangeDoorEnabled(void * data,int d)377 static EditorResult MissionChangeDoorEnabled(void *data, int d)
378 {
379 	UNUSED(d);
380 	Campaign *co = data;
381 	Mission *m = CampaignGetCurrentMission(co);
382 	m->u.Classic.Doors.Enabled = !m->u.Classic.Doors.Enabled;
383 	return EDITOR_RESULT_CHANGED;
384 }
MissionChangeDoorMin(void * data,int d)385 static EditorResult MissionChangeDoorMin(void *data, int d)
386 {
387 	Campaign *co = data;
388 	Mission *m = CampaignGetCurrentMission(co);
389 	m->u.Classic.Doors.Min = CLAMP(m->u.Classic.Doors.Min + d, 1, 6);
390 	m->u.Classic.Doors.Max =
391 		MAX(m->u.Classic.Doors.Min, m->u.Classic.Doors.Max);
392 	return EDITOR_RESULT_CHANGED;
393 }
MissionChangeDoorMax(void * data,int d)394 static EditorResult MissionChangeDoorMax(void *data, int d)
395 {
396 	Campaign *co = data;
397 	Mission *m = CampaignGetCurrentMission(co);
398 	m->u.Classic.Doors.Max = CLAMP(m->u.Classic.Doors.Max + d, 1, 6);
399 	m->u.Classic.Doors.Min =
400 		MIN(m->u.Classic.Doors.Min, m->u.Classic.Doors.Max);
401 	return EDITOR_RESULT_CHANGED;
402 }
MissionChangeDoorRandomPos(void * data,int d)403 static EditorResult MissionChangeDoorRandomPos(void *data, int d)
404 {
405 	UNUSED(d);
406 	Campaign *co = data;
407 	Mission *m = CampaignGetCurrentMission(co);
408 	m->u.Classic.Doors.RandomPos = !m->u.Classic.Doors.RandomPos;
409 	return EDITOR_RESULT_CHANGED;
410 }
MissionChangePillarCount(void * data,int d)411 static EditorResult MissionChangePillarCount(void *data, int d)
412 {
413 	Campaign *co = data;
414 	Mission *m = CampaignGetCurrentMission(co);
415 	m->u.Classic.Pillars.Count = CLAMP(m->u.Classic.Pillars.Count + d, 0, 50);
416 	return EDITOR_RESULT_CHANGED;
417 }
MissionChangePillarMin(void * data,int d)418 static EditorResult MissionChangePillarMin(void *data, int d)
419 {
420 	Campaign *co = data;
421 	Mission *m = CampaignGetCurrentMission(co);
422 	m->u.Classic.Pillars.Min = CLAMP(m->u.Classic.Pillars.Min + d, 1, 50);
423 	m->u.Classic.Pillars.Max =
424 		MAX(m->u.Classic.Pillars.Min, m->u.Classic.Pillars.Max);
425 	return EDITOR_RESULT_CHANGED;
426 }
MissionChangePillarMax(void * data,int d)427 static EditorResult MissionChangePillarMax(void *data, int d)
428 {
429 	Campaign *co = data;
430 	Mission *m = CampaignGetCurrentMission(co);
431 	m->u.Classic.Pillars.Max = CLAMP(m->u.Classic.Pillars.Max + d, 1, 50);
432 	m->u.Classic.Pillars.Min =
433 		MIN(m->u.Classic.Pillars.Min, m->u.Classic.Pillars.Max);
434 	return EDITOR_RESULT_CHANGED;
435 }
436 
CreateClassicMapObjs(struct vec2i pos,Campaign * co)437 UIObject *CreateClassicMapObjs(struct vec2i pos, Campaign *co)
438 {
439 	const int th = FontH();
440 	UIObject *c = UIObjectCreate(UITYPE_NONE, 0, svec2i_zero(), svec2i_zero());
441 	UIObject *o =
442 		UIObjectCreate(UITYPE_LABEL, 0, svec2i_zero(), svec2i(50, th));
443 	const int x = pos.x;
444 	// Check whether the map type matches, and set visibility
445 	c->CheckVisible = MissionCheckTypeFunc;
446 	c->Data = co;
447 
448 	UIObject *o2 = CreateCampaignSeedObj(pos, co);
449 	UIObjectAddChild(c, o2);
450 
451 	pos.x += o2->Size.x;
452 	o2 = UIObjectCopy(o);
453 	o2->u.LabelFunc = MissionGetWallCountStr;
454 	o2->Data = co;
455 	o2->ChangeFunc = MissionChangeWallCount;
456 	o2->Pos = pos;
457 	UIObjectAddChild(c, o2);
458 	pos.x += o2->Size.x;
459 	o2 = UIObjectCopy(o);
460 	o2->u.LabelFunc = MissionGetWallLengthStr;
461 	o2->Data = co;
462 	o2->ChangeFunc = MissionChangeWallLength;
463 	o2->Pos = pos;
464 	UIObjectAddChild(c, o2);
465 	pos.x += o2->Size.x;
466 	o2 = UIObjectCopy(o);
467 	o2->u.LabelFunc = MissionGetCorridorWidthStr;
468 	o2->Data = co;
469 	o2->ChangeFunc = MissionChangeCorridorWidth;
470 	o2->Pos = pos;
471 	o2->Size.x = 60;
472 	UIObjectAddChild(c, o2);
473 
474 	pos.x = x;
475 	pos.y += th;
476 	o2 = UIObjectCopy(o);
477 	o2->u.LabelFunc = MissionGetRoomCountStr;
478 	o2->Data = co;
479 	o2->ChangeFunc = MissionChangeRoomCount;
480 	o2->Pos = pos;
481 	UIObjectAddChild(c, o2);
482 	pos.x += o2->Size.x;
483 	o2 = UIObjectCopy(o);
484 	o2->u.LabelFunc = MissionGetRoomMinStr;
485 	o2->Data = co;
486 	o2->ChangeFunc = MissionChangeRoomMin;
487 	o2->Pos = pos;
488 	UIObjectAddChild(c, o2);
489 	pos.x += o2->Size.x;
490 	o2 = UIObjectCopy(o);
491 	o2->u.LabelFunc = MissionGetRoomMaxStr;
492 	o2->Data = co;
493 	o2->ChangeFunc = MissionChangeRoomMax;
494 	o2->Pos = pos;
495 	UIObjectAddChild(c, o2);
496 	pos.x += o2->Size.x;
497 	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, svec2i(60, th));
498 	o2->u.CustomDrawFunc = MissionDrawEdgeRooms;
499 	o2->Data = co;
500 	o2->ChangeFunc = MissionChangeEdgeRooms;
501 	UIObjectAddChild(c, o2);
502 	pos.x += o2->Size.x;
503 	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, svec2i(60, th));
504 	o2->u.CustomDrawFunc = MissionDrawRoomsOverlap;
505 	o2->Data = co;
506 	o2->ChangeFunc = MissionChangeRoomsOverlap;
507 	UIObjectAddChild(c, o2);
508 
509 	pos.x = x;
510 	pos.y += th;
511 	o2 = UIObjectCopy(o);
512 	o2->u.LabelFunc = MissionGetRoomWallCountStr;
513 	o2->Data = co;
514 	o2->ChangeFunc = MissionChangeRoomWallCount;
515 	o2->Pos = pos;
516 	UIObjectAddChild(c, o2);
517 	pos.x += o2->Size.x;
518 	o2 = UIObjectCopy(o);
519 	o2->u.LabelFunc = MissionGetRoomWallLenStr;
520 	o2->Data = co;
521 	o2->ChangeFunc = MissionChangeRoomWallLen;
522 	o2->Pos = pos;
523 	o2->Size.x = 60;
524 	UIObjectAddChild(c, o2);
525 	pos.x += o2->Size.x;
526 	o2 = UIObjectCopy(o);
527 	o2->u.LabelFunc = MissionGetRoomWallPadStr;
528 	o2->Data = co;
529 	o2->ChangeFunc = MissionChangeRoomWallPad;
530 	o2->Pos = pos;
531 	o2->Size.x = 60;
532 	UIObjectAddChild(c, o2);
533 
534 	pos.x = x;
535 	pos.y += th;
536 	o2 = UIObjectCopy(o);
537 	o2->u.LabelFunc = MissionGetSquareCountStr;
538 	o2->Data = co;
539 	o2->ChangeFunc = MissionChangeSquareCount;
540 	o2->Pos = pos;
541 	UIObjectAddChild(c, o2);
542 	pos.x += o2->Size.x;
543 	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, o->Size);
544 	o2->u.CustomDrawFunc = MissionDrawExitEnabled;
545 	o2->Data = co;
546 	o2->ChangeFunc = MissionChangeExitEnabled;
547 	o2->Pos = pos;
548 	UIObjectAddChild(c, o2);
549 
550 	pos.x = x;
551 	pos.y += th;
552 	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, o->Size);
553 	o2->u.CustomDrawFunc = MissionDrawDoorEnabled;
554 	o2->Data = co;
555 	o2->ChangeFunc = MissionChangeDoorEnabled;
556 	o2->Pos = pos;
557 	UIObjectAddChild(c, o2);
558 	pos.x += o2->Size.x;
559 	o2 = UIObjectCopy(o);
560 	o2->u.LabelFunc = MissionGetDoorMinStr;
561 	o2->Data = co;
562 	o2->ChangeFunc = MissionChangeDoorMin;
563 	o2->Pos = pos;
564 	UIObjectAddChild(c, o2);
565 	pos.x += o2->Size.x;
566 	o2 = UIObjectCopy(o);
567 	o2->u.LabelFunc = MissionGetDoorMaxStr;
568 	o2->Data = co;
569 	o2->ChangeFunc = MissionChangeDoorMax;
570 	o2->Pos = pos;
571 	UIObjectAddChild(c, o2);
572 	pos.x += o2->Size.x;
573 	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, o->Size);
574 	o2->u.CustomDrawFunc = MissionDrawDoorRandomPos;
575 	o2->Data = co;
576 	o2->ChangeFunc = MissionChangeDoorRandomPos;
577 	o2->Pos = pos;
578 	UIObjectAddChild(c, o2);
579 
580 	pos.x = x;
581 	pos.y += th;
582 	o2 = UIObjectCopy(o);
583 	o2->u.LabelFunc = MissionGetPillarCountStr;
584 	o2->Data = co;
585 	o2->ChangeFunc = MissionChangePillarCount;
586 	o2->Pos = pos;
587 	UIObjectAddChild(c, o2);
588 	pos.x += o2->Size.x;
589 	o2 = UIObjectCopy(o);
590 	o2->u.LabelFunc = MissionGetPillarMinStr;
591 	o2->Data = co;
592 	o2->ChangeFunc = MissionChangePillarMin;
593 	o2->Pos = pos;
594 	UIObjectAddChild(c, o2);
595 	pos.x += o2->Size.x;
596 	o2 = UIObjectCopy(o);
597 	o2->u.LabelFunc = MissionGetPillarMaxStr;
598 	o2->Data = co;
599 	o2->ChangeFunc = MissionChangePillarMax;
600 	o2->Pos = pos;
601 	UIObjectAddChild(c, o2);
602 
603 	UIObjectDestroy(o);
604 	return c;
605 }
606