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