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 
MISSION_CHECK_TYPE_FUNC(MAPTYPE_INTERIOR)36 MISSION_CHECK_TYPE_FUNC(MAPTYPE_INTERIOR)
37 static const char *MissionGetCorridorWidthStr(UIObject *o, void *data)
38 {
39 	static char s[128];
40 	UNUSED(o);
41 	Campaign *co = data;
42 	if (!CampaignGetCurrentMission(co))
43 		return NULL;
44 	sprintf(
45 		s, "CorridorWidth: %d",
46 		CampaignGetCurrentMission(co)->u.Interior.CorridorWidth);
47 	return s;
48 }
MissionGetRoomMinStr(UIObject * o,void * data)49 static const char *MissionGetRoomMinStr(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(
57 		s, "RoomMin: %d", CampaignGetCurrentMission(co)->u.Interior.Rooms.Min);
58 	return s;
59 }
MissionGetRoomMaxStr(UIObject * o,void * data)60 static const char *MissionGetRoomMaxStr(UIObject *o, void *data)
61 {
62 	static char s[128];
63 	UNUSED(o);
64 	Campaign *co = data;
65 	if (!CampaignGetCurrentMission(co))
66 		return NULL;
67 	sprintf(s, "RoomMax: %d", CampaignGetCurrentMission(co)->u.Interior.Rooms.Max);
68 	return s;
69 }
MissionDrawExitEnabled(UIObject * o,GraphicsDevice * g,struct vec2i pos,void * data)70 static void MissionDrawExitEnabled(
71 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data)
72 {
73 	UNUSED(o);
74 	UNUSED(g);
75 	Campaign *co = data;
76 	if (!CampaignGetCurrentMission(co))
77 		return;
78 	DisplayFlag(
79 		svec2i_add(pos, o->Pos), "Exit",
80 		CampaignGetCurrentMission(co)->u.Interior.ExitEnabled,
81 		UIObjectIsHighlighted(o));
82 }
MissionGetRoomWallCountStr(UIObject * o,void * data)83 static const char *MissionGetRoomWallCountStr(UIObject *o, void *data)
84 {
85 	static char s[128];
86 	UNUSED(o);
87 	Campaign *co = data;
88 	if (!CampaignGetCurrentMission(co))
89 		return NULL;
90 	sprintf(
91 		s, "RoomWalls: %d", CampaignGetCurrentMission(co)->u.Interior.Rooms.Walls);
92 	return s;
93 }
MissionGetRoomWallLenStr(UIObject * o,void * data)94 static const char *MissionGetRoomWallLenStr(UIObject *o, void *data)
95 {
96 	static char s[128];
97 	UNUSED(o);
98 	Campaign *co = data;
99 	if (!CampaignGetCurrentMission(co))
100 		return NULL;
101 	sprintf(
102 		s, "RoomWallLen: %d",
103 		CampaignGetCurrentMission(co)->u.Interior.Rooms.WallLength);
104 	return s;
105 }
MissionGetRoomWallPadStr(UIObject * o,void * data)106 static const char *MissionGetRoomWallPadStr(UIObject *o, void *data)
107 {
108 	static char s[128];
109 	UNUSED(o);
110 	Campaign *co = data;
111 	if (!CampaignGetCurrentMission(co))
112 		return NULL;
113 	sprintf(
114 		s, "RoomWallPad: %d",
115 		CampaignGetCurrentMission(co)->u.Interior.Rooms.WallPad);
116 	return s;
117 }
MissionDrawDoorEnabled(UIObject * o,GraphicsDevice * g,struct vec2i pos,void * data)118 static void MissionDrawDoorEnabled(
119 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data)
120 {
121 	UNUSED(o);
122 	UNUSED(g);
123 	Campaign *co = data;
124 	Mission *m = CampaignGetCurrentMission(co);
125 	if (!m)
126 		return;
127 	DisplayFlag(
128 		svec2i_add(pos, o->Pos), "Doors",
129 		m->u.Interior.Doors.Enabled,
130 		UIObjectIsHighlighted(o));
131 }
MissionGetDoorMinStr(UIObject * o,void * data)132 static const char *MissionGetDoorMinStr(UIObject *o, void *data)
133 {
134 	static char s[128];
135 	UNUSED(o);
136 	Campaign *co = data;
137 	if (!CampaignGetCurrentMission(co))
138 		return NULL;
139 	sprintf(
140 		s, "DoorMin: %d", CampaignGetCurrentMission(co)->u.Interior.Doors.Min);
141 	return s;
142 }
MissionGetDoorMaxStr(UIObject * o,void * data)143 static const char *MissionGetDoorMaxStr(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, "DoorMax: %d", CampaignGetCurrentMission(co)->u.Interior.Doors.Max);
152 	return s;
153 }
MissionDrawDoorRandomPos(UIObject * o,GraphicsDevice * g,struct vec2i pos,void * data)154 static void MissionDrawDoorRandomPos(
155 	UIObject *o, GraphicsDevice *g, struct vec2i pos, void *data)
156 {
157 	UNUSED(o);
158 	UNUSED(g);
159 	Campaign *co = data;
160 	Mission *m = CampaignGetCurrentMission(co);
161 	if (!m)
162 		return;
163 	DisplayFlag(
164 		svec2i_add(pos, o->Pos), "DoorRandomPos",
165 		m->u.Interior.Doors.RandomPos,
166 		UIObjectIsHighlighted(o));
167 }
MissionGetPillarCountStr(UIObject * o,void * data)168 static const char *MissionGetPillarCountStr(UIObject *o, void *data)
169 {
170 	static char s[128];
171 	UNUSED(o);
172 	Campaign *co = data;
173 	if (!CampaignGetCurrentMission(co))
174 		return NULL;
175 	sprintf(
176 		s, "Pillars: %d",
177 		CampaignGetCurrentMission(co)->u.Interior.Pillars.Count);
178 	return s;
179 }
180 
MissionChangeCorridorWidth(void * data,int d)181 static EditorResult MissionChangeCorridorWidth(void *data, int d)
182 {
183 	Campaign *co = data;
184 	CampaignGetCurrentMission(co)->u.Interior.CorridorWidth = CLAMP(
185 		CampaignGetCurrentMission(co)->u.Interior.CorridorWidth + d, 1, 5);
186 	return EDITOR_RESULT_CHANGED;
187 }
MissionChangeRoomMin(void * data,int d)188 static EditorResult MissionChangeRoomMin(void *data, int d)
189 {
190 	Campaign *co = data;
191 	Mission *m = CampaignGetCurrentMission(co);
192 	m->u.Interior.Rooms.Min = CLAMP(m->u.Interior.Rooms.Min + d, 5, 25);
193 	m->u.Interior.Rooms.Max =
194 		MAX(m->u.Interior.Rooms.Min * 2, m->u.Interior.Rooms.Max);
195 	return EDITOR_RESULT_CHANGED;
196 }
MissionChangeRoomMax(void * data,int d)197 static EditorResult MissionChangeRoomMax(void *data, int d)
198 {
199 	Campaign *co = data;
200 	Mission *m = CampaignGetCurrentMission(co);
201 	m->u.Interior.Rooms.Max = CLAMP(m->u.Interior.Rooms.Max + d, 10, 50);
202 	m->u.Interior.Rooms.Min =
203 		MIN(m->u.Interior.Rooms.Min, m->u.Interior.Rooms.Max / 2);
204 	return EDITOR_RESULT_CHANGED;
205 }
MissionChangeExitEnabled(void * data,int d)206 static EditorResult MissionChangeExitEnabled(void *data, int d)
207 {
208 	UNUSED(d);
209 	Campaign *co = data;
210 	Mission *m = CampaignGetCurrentMission(co);
211 	m->u.Interior.ExitEnabled = !m->u.Interior.ExitEnabled;
212 	return EDITOR_RESULT_CHANGED;
213 }
MissionChangeRoomWallCount(void * data,int d)214 static EditorResult MissionChangeRoomWallCount(void *data, int d)
215 {
216 	Campaign *co = data;
217 	Mission *m = CampaignGetCurrentMission(co);
218 	m->u.Interior.Rooms.Walls = CLAMP(m->u.Interior.Rooms.Walls + d, 0, 50);
219 	return EDITOR_RESULT_CHANGED;
220 }
MissionChangeRoomWallLen(void * data,int d)221 static EditorResult MissionChangeRoomWallLen(void *data, int d)
222 {
223 	Campaign *co = data;
224 	Mission *m = CampaignGetCurrentMission(co);
225 	m->u.Interior.Rooms.WallLength = CLAMP(m->u.Interior.Rooms.WallLength + d, 1, 50);
226 	return EDITOR_RESULT_CHANGED;
227 }
MissionChangeRoomWallPad(void * data,int d)228 static EditorResult MissionChangeRoomWallPad(void *data, int d)
229 {
230 	Campaign *co = data;
231 	Mission *m = CampaignGetCurrentMission(co);
232 	m->u.Interior.Rooms.WallPad = CLAMP(m->u.Interior.Rooms.WallPad + d, 1, 10);
233 	return EDITOR_RESULT_CHANGED;
234 }
MissionChangeDoorEnabled(void * data,int d)235 static EditorResult MissionChangeDoorEnabled(void *data, int d)
236 {
237 	UNUSED(d);
238 	Campaign *co = data;
239 	Mission *m = CampaignGetCurrentMission(co);
240 	m->u.Interior.Doors.Enabled = !m->u.Interior.Doors.Enabled;
241 	return EDITOR_RESULT_CHANGED;
242 }
MissionChangeDoorMin(void * data,int d)243 static EditorResult MissionChangeDoorMin(void *data, int d)
244 {
245 	Campaign *co = data;
246 	Mission *m = CampaignGetCurrentMission(co);
247 	m->u.Interior.Doors.Min = CLAMP(m->u.Interior.Doors.Min + d, 1, 6);
248 	m->u.Interior.Doors.Max =
249 		MAX(m->u.Interior.Doors.Min, m->u.Interior.Doors.Max);
250 	return EDITOR_RESULT_CHANGED;
251 }
MissionChangeDoorMax(void * data,int d)252 static EditorResult MissionChangeDoorMax(void *data, int d)
253 {
254 	Campaign *co = data;
255 	Mission *m = CampaignGetCurrentMission(co);
256 	m->u.Interior.Doors.Max = CLAMP(m->u.Interior.Doors.Max + d, 1, 6);
257 	m->u.Interior.Doors.Min =
258 		MIN(m->u.Interior.Doors.Min, m->u.Interior.Doors.Max);
259 	return EDITOR_RESULT_CHANGED;
260 }
MissionChangeDoorRandomPos(void * data,int d)261 static EditorResult MissionChangeDoorRandomPos(void *data, int d)
262 {
263 	UNUSED(d);
264 	Campaign *co = data;
265 	Mission *m = CampaignGetCurrentMission(co);
266 	m->u.Interior.Doors.RandomPos = !m->u.Interior.Doors.RandomPos;
267 	return EDITOR_RESULT_CHANGED;
268 }
MissionChangePillarCount(void * data,int d)269 static EditorResult MissionChangePillarCount(void *data, int d)
270 {
271 	Campaign *co = data;
272 	Mission *m = CampaignGetCurrentMission(co);
273 	m->u.Interior.Pillars.Count = CLAMP(m->u.Interior.Pillars.Count + d, 0, 50);
274 	return EDITOR_RESULT_CHANGED;
275 }
276 
CreateInteriorMapObjs(struct vec2i pos,Campaign * co)277 UIObject *CreateInteriorMapObjs(struct vec2i pos, Campaign *co)
278 {
279 	const int th = FontH();
280 	UIObject *c = UIObjectCreate(UITYPE_NONE, 0, svec2i_zero(), svec2i_zero());
281 	UIObject *o =
282 		UIObjectCreate(UITYPE_LABEL, 0, svec2i_zero(), svec2i(50, th));
283 	const int x = pos.x;
284 	// Check whether the map type matches, and set visibility
285 	c->CheckVisible = MissionCheckTypeFunc;
286 	c->Data = co;
287 
288 	UIObject *o2 = CreateCampaignSeedObj(pos, co);
289 	UIObjectAddChild(c, o2);
290 
291 	pos.x += o2->Size.x;
292 	o2 = UIObjectCopy(o);
293 	o2->u.LabelFunc = MissionGetCorridorWidthStr;
294 	o2->Data = co;
295 	o2->ChangeFunc = MissionChangeCorridorWidth;
296 	o2->Pos = pos;
297 	o2->Size.x = 60;
298 	UIObjectAddChild(c, o2);
299 
300 	pos.x = x;
301 	pos.y += th;
302 	o2 = UIObjectCopy(o);
303 	o2->u.LabelFunc = MissionGetRoomMinStr;
304 	o2->Data = co;
305 	o2->ChangeFunc = MissionChangeRoomMin;
306 	o2->Pos = pos;
307 	UIObjectAddChild(c, o2);
308 	pos.x += o2->Size.x;
309 	o2 = UIObjectCopy(o);
310 	o2->u.LabelFunc = MissionGetRoomMaxStr;
311 	o2->Data = co;
312 	o2->ChangeFunc = MissionChangeRoomMax;
313 	o2->Pos = pos;
314 	UIObjectAddChild(c, o2);
315 
316 	pos.x = x;
317 	pos.y += th;
318 	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, o->Size);
319 	o2->u.CustomDrawFunc = MissionDrawExitEnabled;
320 	o2->Data = co;
321 	o2->ChangeFunc = MissionChangeExitEnabled;
322 	o2->Pos = pos;
323 	UIObjectAddChild(c, o2);
324 
325 	pos.x = x;
326 	pos.y += th;
327 	o2 = UIObjectCopy(o);
328 	o2->u.LabelFunc = MissionGetRoomWallCountStr;
329 	o2->Data = co;
330 	o2->ChangeFunc = MissionChangeRoomWallCount;
331 	o2->Pos = pos;
332 	UIObjectAddChild(c, o2);
333 	pos.x += o2->Size.x;
334 	o2 = UIObjectCopy(o);
335 	o2->u.LabelFunc = MissionGetRoomWallLenStr;
336 	o2->Data = co;
337 	o2->ChangeFunc = MissionChangeRoomWallLen;
338 	o2->Pos = pos;
339 	o2->Size.x = 60;
340 	UIObjectAddChild(c, o2);
341 	pos.x += o2->Size.x;
342 	o2 = UIObjectCopy(o);
343 	o2->u.LabelFunc = MissionGetRoomWallPadStr;
344 	o2->Data = co;
345 	o2->ChangeFunc = MissionChangeRoomWallPad;
346 	o2->Pos = pos;
347 	o2->Size.x = 60;
348 	UIObjectAddChild(c, o2);
349 
350 	pos.x = x;
351 	pos.y += th;
352 	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, o->Size);
353 	o2->u.CustomDrawFunc = MissionDrawDoorEnabled;
354 	o2->Data = co;
355 	o2->ChangeFunc = MissionChangeDoorEnabled;
356 	o2->Pos = pos;
357 	UIObjectAddChild(c, o2);
358 	pos.x += o2->Size.x;
359 	o2 = UIObjectCopy(o);
360 	o2->u.LabelFunc = MissionGetDoorMinStr;
361 	o2->Data = co;
362 	o2->ChangeFunc = MissionChangeDoorMin;
363 	o2->Pos = pos;
364 	UIObjectAddChild(c, o2);
365 	pos.x += o2->Size.x;
366 	o2 = UIObjectCopy(o);
367 	o2->u.LabelFunc = MissionGetDoorMaxStr;
368 	o2->Data = co;
369 	o2->ChangeFunc = MissionChangeDoorMax;
370 	o2->Pos = pos;
371 	UIObjectAddChild(c, o2);
372 	pos.x += o2->Size.x;
373 	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, o->Size);
374 	o2->u.CustomDrawFunc = MissionDrawDoorRandomPos;
375 	o2->Data = co;
376 	o2->ChangeFunc = MissionChangeDoorRandomPos;
377 	o2->Pos = pos;
378 	UIObjectAddChild(c, o2);
379 
380 	pos.x = x;
381 	pos.y += th;
382 	o2 = UIObjectCopy(o);
383 	o2->u.LabelFunc = MissionGetPillarCountStr;
384 	o2->Data = co;
385 	o2->ChangeFunc = MissionChangePillarCount;
386 	o2->Pos = pos;
387 	UIObjectAddChild(c, o2);
388 
389 	UIObjectDestroy(o);
390 	return c;
391 }
392