1 /*
2 	C-Dogs SDL
3 	A port of the legendary (and fun) action/arcade cdogs.
4 	Copyright (c) 2016-2017, 2020 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_cave.h"
29 
30 #include <cdogs/events.h>
31 #include <cdogs/font.h>
32 
33 #include "editor_ui_common.h"
34 
35 MISSION_CHECK_TYPE_FUNC(MAPTYPE_CAVE)
36 
37 static const char *MissionGetFillPercentStr(UIObject *o, void *data);
38 static EditorResult MissionChangeFillPercent(void *data, int d);
39 static const char *MissionGetRepeatStr(UIObject *o, void *data);
40 static EditorResult MissionChangeRepeat(void *data, int d);
41 static const char *MissionGetR1Str(UIObject *o, void *data);
42 static EditorResult MissionChangeR1(void *data, int d);
43 static const char *MissionGetR2Str(UIObject *o, void *data);
44 static EditorResult MissionChangeR2(void *data, int d);
45 static const char *MissionGetCorridorWidthStr(UIObject *o, void *data);
46 static EditorResult MissionChangeCorridorWidth(void *data, int d);
47 static const char *MissionGetRoomCountStr(UIObject *o, void *data);
48 static EditorResult MissionChangeRoomCount(void *data, int d);
49 static const char *MissionGetRoomMinStr(UIObject *o, void *data);
50 static EditorResult MissionChangeRoomMin(void *data, int d);
51 static const char *MissionGetRoomMaxStr(UIObject *o, void *data);
52 static EditorResult MissionChangeRoomMax(void *data, int d);
53 static void MissionDrawRoomsOverlap(
54 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data);
55 static EditorResult MissionChangeRoomsOverlap(void *data, int d);
56 static const char *MissionGetRoomWallCountStr(UIObject *o, void *data);
57 static EditorResult MissionChangeRoomWallCount(void *data, int d);
58 static const char *MissionGetRoomWallLenStr(UIObject *o, void *data);
59 static EditorResult MissionChangeRoomWallLen(void *data, int d);
60 static const char *MissionGetRoomWallPadStr(UIObject *o, void *data);
61 static EditorResult MissionChangeRoomWallPad(void *data, int d);
62 static const char *MissionGetSquareCountStr(UIObject *o, void *data);
63 static EditorResult MissionChangeSquareCount(void *data, int d);
64 static void MissionDrawExitEnabled(
65 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data);
66 static void MissionDrawDoorEnabled(
67 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data);
68 static EditorResult MissionChangeExitEnabled(void *data, int d);
69 static EditorResult MissionChangeDoorEnabled(void *data, int d);
CreateCaveMapObjs(struct vec2i pos,Campaign * co)70 UIObject *CreateCaveMapObjs(struct vec2i pos, Campaign *co)
71 {
72 	const int th = FontH();
73 	UIObject *c = UIObjectCreate(UITYPE_NONE, 0, svec2i_zero(), svec2i_zero());
74 	UIObject *o =
75 		UIObjectCreate(UITYPE_LABEL, 0, svec2i_zero(), svec2i(50, th));
76 	const int x = pos.x;
77 	// Check whether the map type matches, and set visibility
78 	c->CheckVisible = MissionCheckTypeFunc;
79 	c->Data = co;
80 
81 	UIObject *o2 = CreateCampaignSeedObj(pos, co);
82 	UIObjectAddChild(c, o2);
83 
84 	pos.x += o2->Size.x;
85 	o2 = UIObjectCopy(o);
86 	o2->u.LabelFunc = MissionGetFillPercentStr;
87 	o2->Data = co;
88 	o2->ChangeFunc = MissionChangeFillPercent;
89 	o2->Pos = pos;
90 	UIObjectAddChild(c, o2);
91 	pos.x += o2->Size.x;
92 	o2 = UIObjectCopy(o);
93 	o2->u.LabelFunc = MissionGetRepeatStr;
94 	o2->Data = co;
95 	o2->ChangeFunc = MissionChangeRepeat;
96 	o2->Pos = pos;
97 	UIObjectAddChild(c, o2);
98 
99 	pos.x = x;
100 	pos.y += th;
101 	o2 = UIObjectCopy(o);
102 	o2->u.LabelFunc = MissionGetR1Str;
103 	o2->Data = co;
104 	o2->ChangeFunc = MissionChangeR1;
105 	o2->Pos = pos;
106 	UIObjectAddChild(c, o2);
107 	pos.x += o2->Size.x;
108 	o2 = UIObjectCopy(o);
109 	o2->u.LabelFunc = MissionGetR2Str;
110 	o2->Data = co;
111 	o2->ChangeFunc = MissionChangeR2;
112 	o2->Pos = pos;
113 	UIObjectAddChild(c, o2);
114 	pos.x += o2->Size.x;
115 	o2 = UIObjectCopy(o);
116 	o2->u.LabelFunc = MissionGetCorridorWidthStr;
117 	o2->Data = co;
118 	o2->ChangeFunc = MissionChangeCorridorWidth;
119 	o2->Pos = pos;
120 	o2->Size.x = 60;
121 	UIObjectAddChild(c, o2);
122 
123 	pos.x = x;
124 	pos.y += th;
125 	o2 = UIObjectCopy(o);
126 	o2->u.LabelFunc = MissionGetRoomCountStr;
127 	o2->Data = co;
128 	o2->ChangeFunc = MissionChangeRoomCount;
129 	o2->Pos = pos;
130 	UIObjectAddChild(c, o2);
131 	pos.x += o2->Size.x;
132 	o2 = UIObjectCopy(o);
133 	o2->u.LabelFunc = MissionGetRoomMinStr;
134 	o2->Data = co;
135 	o2->ChangeFunc = MissionChangeRoomMin;
136 	o2->Pos = pos;
137 	UIObjectAddChild(c, o2);
138 	pos.x += o2->Size.x;
139 	o2 = UIObjectCopy(o);
140 	o2->u.LabelFunc = MissionGetRoomMaxStr;
141 	o2->Data = co;
142 	o2->ChangeFunc = MissionChangeRoomMax;
143 	o2->Pos = pos;
144 	UIObjectAddChild(c, o2);
145 	pos.x += o2->Size.x;
146 	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, svec2i(60, th));
147 	o2->u.CustomDrawFunc = MissionDrawRoomsOverlap;
148 	o2->Data = co;
149 	o2->ChangeFunc = MissionChangeRoomsOverlap;
150 	UIObjectAddChild(c, o2);
151 
152 	pos.x = x;
153 	pos.y += th;
154 	o2 = UIObjectCopy(o);
155 	o2->u.LabelFunc = MissionGetRoomWallCountStr;
156 	o2->Data = co;
157 	o2->ChangeFunc = MissionChangeRoomWallCount;
158 	o2->Pos = pos;
159 	UIObjectAddChild(c, o2);
160 	pos.x += o2->Size.x;
161 	o2 = UIObjectCopy(o);
162 	o2->u.LabelFunc = MissionGetRoomWallLenStr;
163 	o2->Data = co;
164 	o2->ChangeFunc = MissionChangeRoomWallLen;
165 	o2->Pos = pos;
166 	o2->Size.x = 60;
167 	UIObjectAddChild(c, o2);
168 	pos.x += o2->Size.x;
169 	o2 = UIObjectCopy(o);
170 	o2->u.LabelFunc = MissionGetRoomWallPadStr;
171 	o2->Data = co;
172 	o2->ChangeFunc = MissionChangeRoomWallPad;
173 	o2->Pos = pos;
174 	o2->Size.x = 60;
175 	UIObjectAddChild(c, o2);
176 
177 	pos.x = x;
178 	pos.y += th;
179 	o2 = UIObjectCopy(o);
180 	o2->u.LabelFunc = MissionGetSquareCountStr;
181 	o2->Data = co;
182 	o2->ChangeFunc = MissionChangeSquareCount;
183 	o2->Pos = pos;
184 	UIObjectAddChild(c, o2);
185 	pos.x += o2->Size.x;
186 	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, o->Size);
187 	o2->u.CustomDrawFunc = MissionDrawExitEnabled;
188 	o2->Data = co;
189 	o2->ChangeFunc = MissionChangeExitEnabled;
190 	o2->Pos = pos;
191 	UIObjectAddChild(c, o2);
192 
193 	pos.x = x;
194 	pos.y += th;
195 	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, o->Size);
196 	o2->u.CustomDrawFunc = MissionDrawDoorEnabled;
197 	o2->Data = co;
198 	o2->ChangeFunc = MissionChangeDoorEnabled;
199 	o2->Pos = pos;
200 	UIObjectAddChild(c, o2);
201 
202 	UIObjectDestroy(o);
203 	return c;
204 }
MissionGetFillPercentStr(UIObject * o,void * data)205 static const char *MissionGetFillPercentStr(UIObject *o, void *data)
206 {
207 	UNUSED(o);
208 	Campaign *co = data;
209 	const Mission *m = CampaignGetCurrentMission(co);
210 	if (m == NULL)
211 		return NULL;
212 	static char s[128];
213 	sprintf(s, "Fill: %d%%", m->u.Cave.FillPercent);
214 	return s;
215 }
MissionChangeFillPercent(void * data,int d)216 static EditorResult MissionChangeFillPercent(void *data, int d)
217 {
218 	Campaign *co = data;
219 	Mission *m = CampaignGetCurrentMission(co);
220 	if (gEventHandlers.keyboard.modState & KMOD_SHIFT)
221 	{
222 		d *= 10;
223 	}
224 	m->u.Cave.FillPercent = CLAMP(m->u.Cave.FillPercent + d, 0, 100);
225 	return EDITOR_RESULT_CHANGED;
226 }
MissionGetRepeatStr(UIObject * o,void * data)227 static const char *MissionGetRepeatStr(UIObject *o, void *data)
228 {
229 	UNUSED(o);
230 	Campaign *co = data;
231 	const Mission *m = CampaignGetCurrentMission(co);
232 	if (m == NULL)
233 		return NULL;
234 	static char s[128];
235 	sprintf(s, "Repeat: %d", m->u.Cave.Repeat);
236 	return s;
237 }
MissionChangeRepeat(void * data,int d)238 static EditorResult MissionChangeRepeat(void *data, int d)
239 {
240 	Campaign *co = data;
241 	Mission *m = CampaignGetCurrentMission(co);
242 	m->u.Cave.Repeat = CLAMP(m->u.Cave.Repeat + d, 0, 10);
243 	return EDITOR_RESULT_CHANGED;
244 }
MissionGetR1Str(UIObject * o,void * data)245 static const char *MissionGetR1Str(UIObject *o, void *data)
246 {
247 	UNUSED(o);
248 	Campaign *co = data;
249 	const Mission *m = CampaignGetCurrentMission(co);
250 	if (m == NULL)
251 		return NULL;
252 	static char s[128];
253 	sprintf(s, "R1: %d", m->u.Cave.R1);
254 	return s;
255 }
MissionChangeR1(void * data,int d)256 static EditorResult MissionChangeR1(void *data, int d)
257 {
258 	Campaign *co = data;
259 	Mission *m = CampaignGetCurrentMission(co);
260 	m->u.Cave.R1 = CLAMP(m->u.Cave.R1 + d, 0, 8);
261 	return EDITOR_RESULT_CHANGED;
262 }
MissionGetR2Str(UIObject * o,void * data)263 static const char *MissionGetR2Str(UIObject *o, void *data)
264 {
265 	UNUSED(o);
266 	Campaign *co = data;
267 	const Mission *m = CampaignGetCurrentMission(co);
268 	if (m == NULL)
269 		return NULL;
270 	static char s[128];
271 	sprintf(s, "R2: %d", m->u.Cave.R2);
272 	return s;
273 }
MissionChangeR2(void * data,int d)274 static EditorResult MissionChangeR2(void *data, int d)
275 {
276 	Campaign *co = data;
277 	Mission *m = CampaignGetCurrentMission(co);
278 	m->u.Cave.R2 = CLAMP(m->u.Cave.R2 + d, -1, 25);
279 	return EDITOR_RESULT_CHANGED;
280 }
MissionGetCorridorWidthStr(UIObject * o,void * data)281 static const char *MissionGetCorridorWidthStr(UIObject *o, void *data)
282 {
283 	UNUSED(o);
284 	Campaign *co = data;
285 	const Mission *m = CampaignGetCurrentMission(co);
286 	if (m == NULL)
287 		return NULL;
288 	static char s[128];
289 	sprintf(s, "CorridorWidth: %d", m->u.Cave.CorridorWidth);
290 	return s;
291 }
MissionChangeCorridorWidth(void * data,int d)292 static EditorResult MissionChangeCorridorWidth(void *data, int d)
293 {
294 	Campaign *co = data;
295 	Mission *m = CampaignGetCurrentMission(co);
296 	m->u.Cave.CorridorWidth = CLAMP(m->u.Cave.CorridorWidth + d, 1, 5);
297 	return EDITOR_RESULT_CHANGED;
298 }
MissionGetRoomCountStr(UIObject * o,void * data)299 static const char *MissionGetRoomCountStr(UIObject *o, void *data)
300 {
301 	static char s[128];
302 	UNUSED(o);
303 	Campaign *co = data;
304 	if (!CampaignGetCurrentMission(co))
305 		return NULL;
306 	sprintf(s, "Rooms: %d", CampaignGetCurrentMission(co)->u.Cave.Rooms.Count);
307 	return s;
308 }
MissionGetRoomMinStr(UIObject * o,void * data)309 static const char *MissionGetRoomMinStr(UIObject *o, void *data)
310 {
311 	static char s[128];
312 	UNUSED(o);
313 	Campaign *co = data;
314 	if (!CampaignGetCurrentMission(co))
315 		return NULL;
316 	sprintf(s, "RoomMin: %d", CampaignGetCurrentMission(co)->u.Cave.Rooms.Min);
317 	return s;
318 }
MissionGetRoomMaxStr(UIObject * o,void * data)319 static const char *MissionGetRoomMaxStr(UIObject *o, void *data)
320 {
321 	static char s[128];
322 	UNUSED(o);
323 	Campaign *co = data;
324 	if (!CampaignGetCurrentMission(co))
325 		return NULL;
326 	sprintf(s, "RoomMax: %d", CampaignGetCurrentMission(co)->u.Cave.Rooms.Max);
327 	return s;
328 }
MissionChangeRoomCount(void * data,int d)329 static EditorResult MissionChangeRoomCount(void *data, int d)
330 {
331 	Campaign *co = data;
332 	CampaignGetCurrentMission(co)->u.Cave.Rooms.Count =
333 		CLAMP(CampaignGetCurrentMission(co)->u.Cave.Rooms.Count + d, 0, 100);
334 	return EDITOR_RESULT_CHANGED;
335 }
MissionChangeRoomMin(void * data,int d)336 static EditorResult MissionChangeRoomMin(void *data, int d)
337 {
338 	Campaign *co = data;
339 	Mission *m = CampaignGetCurrentMission(co);
340 	m->u.Cave.Rooms.Min = CLAMP(m->u.Cave.Rooms.Min + d, 5, 50);
341 	m->u.Cave.Rooms.Max = MAX(m->u.Cave.Rooms.Min, m->u.Cave.Rooms.Max);
342 	return EDITOR_RESULT_CHANGED;
343 }
MissionChangeRoomMax(void * data,int d)344 static EditorResult MissionChangeRoomMax(void *data, int d)
345 {
346 	Campaign *co = data;
347 	Mission *m = CampaignGetCurrentMission(co);
348 	m->u.Cave.Rooms.Max = CLAMP(m->u.Cave.Rooms.Max + d, 5, 50);
349 	m->u.Cave.Rooms.Min =
350 		MIN(m->u.Cave.Rooms.Min, m->u.Cave.Rooms.Max);
351 	return EDITOR_RESULT_CHANGED;
352 }
MissionDrawRoomsOverlap(UIObject * o,GraphicsDevice * g,struct vec2i pos,void * data)353 static void MissionDrawRoomsOverlap(
354 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data)
355 {
356 	UNUSED(o);
357 	UNUSED(g);
358 	UNUSED(pos);
359 	Campaign *co = data;
360 	if (!CampaignGetCurrentMission(co))
361 		return;
362 	DisplayFlag(
363 		svec2i_add(pos, o->Pos), "Room overlap",
364 		CampaignGetCurrentMission(co)->u.Cave.Rooms.Overlap,
365 		UIObjectIsHighlighted(o));
366 }
MissionChangeRoomsOverlap(void * data,int d)367 static EditorResult MissionChangeRoomsOverlap(void *data, int d)
368 {
369 	UNUSED(d);
370 	Campaign *co = data;
371 	CampaignGetCurrentMission(co)->u.Cave.Rooms.Overlap =
372 		!CampaignGetCurrentMission(co)->u.Cave.Rooms.Overlap;
373 	return EDITOR_RESULT_CHANGED;
374 }
MissionGetRoomWallCountStr(UIObject * o,void * data)375 static const char *MissionGetRoomWallCountStr(UIObject *o, void *data)
376 {
377 	static char s[128];
378 	UNUSED(o);
379 	Campaign *co = data;
380 	if (!CampaignGetCurrentMission(co))
381 		return NULL;
382 	sprintf(
383 		s, "RoomWalls: %d", CampaignGetCurrentMission(co)->u.Cave.Rooms.Walls);
384 	return s;
385 }
MissionGetRoomWallLenStr(UIObject * o,void * data)386 static const char *MissionGetRoomWallLenStr(UIObject *o, void *data)
387 {
388 	static char s[128];
389 	UNUSED(o);
390 	Campaign *co = data;
391 	if (!CampaignGetCurrentMission(co))
392 		return NULL;
393 	sprintf(
394 		s, "RoomWallLen: %d",
395 		CampaignGetCurrentMission(co)->u.Cave.Rooms.WallLength);
396 	return s;
397 }
MissionGetRoomWallPadStr(UIObject * o,void * data)398 static const char *MissionGetRoomWallPadStr(UIObject *o, void *data)
399 {
400 	static char s[128];
401 	UNUSED(o);
402 	Campaign *co = data;
403 	if (!CampaignGetCurrentMission(co))
404 		return NULL;
405 	sprintf(
406 		s, "RoomWallPad: %d",
407 		CampaignGetCurrentMission(co)->u.Cave.Rooms.WallPad);
408 	return s;
409 }
MissionChangeRoomWallCount(void * data,int d)410 static EditorResult MissionChangeRoomWallCount(void *data, int d)
411 {
412 	Campaign *co = data;
413 	Mission *m = CampaignGetCurrentMission(co);
414 	m->u.Cave.Rooms.Walls = CLAMP(m->u.Cave.Rooms.Walls + d, 0, 50);
415 	return EDITOR_RESULT_CHANGED;
416 }
MissionChangeRoomWallLen(void * data,int d)417 static EditorResult MissionChangeRoomWallLen(void *data, int d)
418 {
419 	Campaign *co = data;
420 	Mission *m = CampaignGetCurrentMission(co);
421 	m->u.Cave.Rooms.WallLength = CLAMP(m->u.Cave.Rooms.WallLength + d, 1, 50);
422 	return EDITOR_RESULT_CHANGED;
423 }
MissionChangeRoomWallPad(void * data,int d)424 static EditorResult MissionChangeRoomWallPad(void *data, int d)
425 {
426 	Campaign *co = data;
427 	Mission *m = CampaignGetCurrentMission(co);
428 	m->u.Cave.Rooms.WallPad = CLAMP(m->u.Cave.Rooms.WallPad + d, 1, 10);
429 	return EDITOR_RESULT_CHANGED;
430 }
MissionGetSquareCountStr(UIObject * o,void * data)431 static const char *MissionGetSquareCountStr(UIObject *o, void *data)
432 {
433 	static char s[128];
434 	UNUSED(o);
435 	Campaign *co = data;
436 	if (!CampaignGetCurrentMission(co))
437 		return NULL;
438 	sprintf(s, "Sqr: %d", CampaignGetCurrentMission(co)->u.Cave.Squares);
439 	return s;
440 }
MissionChangeSquareCount(void * data,int d)441 static EditorResult MissionChangeSquareCount(void *data, int d)
442 {
443 	Campaign *co = data;
444 	CampaignGetCurrentMission(co)->u.Cave.Squares =
445 		CLAMP(CampaignGetCurrentMission(co)->u.Cave.Squares + d, 0, 100);
446 	return EDITOR_RESULT_CHANGED;
447 }
MissionDrawExitEnabled(UIObject * o,GraphicsDevice * g,struct vec2i pos,void * data)448 static void MissionDrawExitEnabled(
449 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data)
450 {
451 	UNUSED(o);
452 	UNUSED(g);
453 	Campaign *co = data;
454 	if (!CampaignGetCurrentMission(co))
455 		return;
456 	DisplayFlag(
457 		svec2i_add(pos, o->Pos), "Exit",
458 		CampaignGetCurrentMission(co)->u.Cave.ExitEnabled,
459 		UIObjectIsHighlighted(o));
460 }
MissionDrawDoorEnabled(UIObject * o,GraphicsDevice * g,struct vec2i pos,void * data)461 static void MissionDrawDoorEnabled(
462 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data)
463 {
464 	UNUSED(o);
465 	UNUSED(g);
466 	Campaign *co = data;
467 	if (!CampaignGetCurrentMission(co))
468 		return;
469 	DisplayFlag(
470 		svec2i_add(pos, o->Pos), "Doors",
471 		CampaignGetCurrentMission(co)->u.Cave.DoorsEnabled,
472 		UIObjectIsHighlighted(o));
473 }
MissionChangeExitEnabled(void * data,int d)474 static EditorResult MissionChangeExitEnabled(void *data, int d)
475 {
476 	UNUSED(d);
477 	Campaign *co = data;
478 	Mission *m = CampaignGetCurrentMission(co);
479 	m->u.Cave.ExitEnabled = !m->u.Cave.ExitEnabled;
480 	return EDITOR_RESULT_CHANGED;
481 }
MissionChangeDoorEnabled(void * data,int d)482 static EditorResult MissionChangeDoorEnabled(void *data, int d)
483 {
484 	UNUSED(d);
485 	Campaign *co = data;
486 	Mission *m = CampaignGetCurrentMission(co);
487 	m->u.Cave.DoorsEnabled = !m->u.Cave.DoorsEnabled;
488 	return EDITOR_RESULT_CHANGED;
489 }
490