1 /*
2 	C-Dogs SDL
3 	A port of the legendary (and fun) action/arcade cdogs.
4 	Copyright (c) 2018-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 "tile_class.h"
29 
30 #include "door.h"
31 #include "log.h"
32 #include "pics.h"
33 #include "sys_config.h"
34 
35 
36 TileClasses gTileClasses;
37 TileClass gTileFloor = {
38 	"tile", NULL, NULL, NULL, { 255, 255, 255, 255 }, { 255, 255, 255, 255 },
39 	true, false, false, false, TILE_CLASS_FLOOR,
40 };
41 TileClass gTileRoom = {
42 	"tile", NULL, NULL, NULL, { 255, 255, 255, 255 }, { 255, 255, 255, 255 },
43 	true, false, false, true, TILE_CLASS_FLOOR,
44 };
45 TileClass gTileWall = {
46 	"wall", NULL, NULL, NULL, { 255, 255, 255, 255 }, { 255, 255, 255, 255 },
47 	false, true, true, false, TILE_CLASS_WALL,
48 };
49 TileClass gTileNothing = {
50 	NULL, NULL, NULL, NULL, { 255, 255, 255, 255 }, { 255, 255, 255, 255 },
51 	false, false, false, false, TILE_CLASS_NOTHING,
52 };
53 TileClass gTileExit = {
54 	"exits", NULL, NULL, NULL, { 255, 255, 255, 255 }, { 255, 255, 255, 255 },
55 	true, false, false, false, TILE_CLASS_FLOOR,
56 };
57 TileClass gTileDoor = {
58 	"door", NULL, NULL, NULL, { 255, 255, 255, 255 }, { 255, 255, 255, 255 },
59 	false, true, true, true, TILE_CLASS_DOOR,
60 };
61 
TileClassTypeStr(const TileClassType t)62 const char *TileClassTypeStr(const TileClassType t)
63 {
64 	switch (t)
65 	{
66 		T2S(TILE_CLASS_FLOOR, "Floor");
67 		T2S(TILE_CLASS_WALL, "Wall");
68 		T2S(TILE_CLASS_DOOR, "Door");
69 	default:
70 		return "";
71 	}
72 }
StrTileClassType(const char * s)73 TileClassType StrTileClassType(const char *s)
74 {
75 	S2T(TILE_CLASS_FLOOR, "Floor");
76 	S2T(TILE_CLASS_WALL, "Wall");
77 	S2T(TILE_CLASS_DOOR, "Door");
78 	S2T(TILE_CLASS_NOTHING, "");
79 	CASSERT(false, "unknown tile class type");
80 	return TILE_CLASS_NOTHING;
81 }
82 
TileClassesInit(TileClasses * c)83 void TileClassesInit(TileClasses *c)
84 {
85 	c->classes = hashmap_new();
86 	c->customClasses = hashmap_new();
87 }
TileClassesClearCustom(TileClasses * c)88 void TileClassesClearCustom(TileClasses *c)
89 {
90 	TileClassesTerminate(c);
91 	TileClassesInit(c);
92 }
TileClassesTerminate(TileClasses * c)93 void TileClassesTerminate(TileClasses *c)
94 {
95 	hashmap_destroy(c->classes, TileClassDestroy);
96 	hashmap_destroy(c->customClasses, TileClassDestroy);
97 }
TileClassDestroy(any_t data)98 void TileClassDestroy(any_t data)
99 {
100 	TileClass *tc = data;
101 	TileClassTerminate(tc);
102 	CFREE(tc);
103 }
TileClassTerminate(TileClass * tc)104 void TileClassTerminate(TileClass *tc)
105 {
106 	if (tc->Type == TILE_CLASS_NOTHING)
107 	{
108 		return;
109 	}
110 	CFREE(tc->Name);
111 	CFREE(tc->Style);
112 	CFREE(tc->StyleType);
113 }
114 
TileClassBaseStyleType(const TileClassType type)115 const char *TileClassBaseStyleType(const TileClassType type)
116 {
117 	switch (type)
118 	{
119 	case TILE_CLASS_FLOOR:
120 		return "normal";
121 	case TILE_CLASS_WALL:
122 		return "o";
123 	case TILE_CLASS_DOOR:
124 		return "normal_h";
125 	default:
126 		return "";
127 	}
128 }
129 
TileClassCopy(TileClass * dst,const TileClass * src)130 void TileClassCopy(TileClass *dst, const TileClass *src)
131 {
132 	memcpy(dst, src, sizeof *dst);
133 	if (src->Name) CSTRDUP(dst->Name, src->Name);
134 	if (src->Style) CSTRDUP(dst->Style, src->Style);
135 	if (src->StyleType) CSTRDUP(dst->StyleType, TileClassBaseStyleType(src->Type));
136 }
StrTileClass(const char * name)137 const TileClass *StrTileClass(const char *name)
138 {
139 	if (name == NULL || strlen(name) == 0)
140 	{
141 		return &gTileNothing;
142 	}
143 	LOG(LM_MAIN, LL_TRACE, "get tile class %s", name);
144 	TileClass *t;
145 	int error = hashmap_get(gTileClasses.customClasses, name, (any_t *)&t);
146 	if (error == MAP_OK)
147 	{
148 		return t;
149 	}
150 	error = hashmap_get(gTileClasses.classes, name, (any_t *)&t);
151 	if (error == MAP_OK)
152 	{
153 		return t;
154 	}
155 	LOG(LM_MAIN, LL_ERROR, "failed to get tile class %s: %d",
156 		name, error);
157 	return &gTileNothing;
158 }
159 
TileClassInit(TileClass * t,PicManager * pm,const TileClass * base,const char * style,const char * type,const color_t mask,const color_t maskAlt)160 void TileClassInit(
161 	TileClass *t, PicManager *pm, const TileClass *base,
162 	const char *style, const char *type,
163 	const color_t mask, const color_t maskAlt)
164 {
165 	memcpy(t, base, sizeof *t);
166 	if (base->Name) CSTRDUP(t->Name, base->Name);
167 	if (style) CSTRDUP(t->Style, style);
168 	if (type && strlen(type))
169 	{
170 		CSTRDUP(t->StyleType, type);
171 	}
172 	t->Mask = mask;
173 	t->MaskAlt = maskAlt;
174 	TileClassReloadPic(t, pm);
175 }
TileClassInitDefault(TileClass * t,PicManager * pm,const TileClass * base,const char * forceStyle,const color_t * forceMask)176 void TileClassInitDefault(
177 	TileClass *t, PicManager *pm, const TileClass *base,
178 	const char *forceStyle, const color_t *forceMask)
179 {
180 	const char *style = IntFloorStyle(0);
181 	color_t mask = colorBattleshipGrey;
182 	color_t maskAlt = colorOfficeGreen;
183 	switch (base->Type)
184 	{
185 	case TILE_CLASS_FLOOR:
186 		break;
187 	case TILE_CLASS_WALL:
188 		style = IntWallStyle(0);
189 		mask = colorGravel;
190 		break;
191 	case TILE_CLASS_DOOR:
192 		style = IntDoorStyle(0);
193 		mask = colorWhite;
194 		break;
195 	case TILE_CLASS_NOTHING:
196 		break;
197 	default:
198 		CASSERT(false, "unknown tile class");
199 		break;
200 	}
201 	if (forceStyle != NULL)
202 	{
203 		style = forceStyle;
204 	}
205 	if (forceMask != NULL)
206 	{
207 		mask = *forceMask;
208 	}
209 	TileClassInit(
210 		t, pm, base, style, TileClassBaseStyleType(base->Type),
211 		mask, maskAlt);
212 }
TileClassReloadPic(TileClass * t,PicManager * pm)213 void TileClassReloadPic(TileClass *t, PicManager *pm)
214 {
215 	if (t->Name != NULL && strlen(t->Name) != 0)
216 	{
217 		// Generate the pic in case it doesn't exist
218 		PicManagerGenerateMaskedStylePic(
219 			pm, t->Name, t->Style, t->StyleType, t->Mask, t->MaskAlt, false);
220 		t->Pic = TileClassGetPic(pm, t);
221 		CASSERT(t->Pic != NULL, "cannot find tile pic");
222 	}
223 }
TileClassesGetMaskedTile(const TileClass * baseClass,const char * style,const char * type,const color_t mask,const color_t maskAlt)224 const TileClass *TileClassesGetMaskedTile(
225 	const TileClass *baseClass, const char *style, const char *type,
226 	const color_t mask, const color_t maskAlt)
227 {
228 	char buf[256];
229 	TileClassGetName(buf, baseClass, style, type, mask, maskAlt);
230 	return StrTileClass(buf);
231 }
TileClassesAdd(TileClasses * c,PicManager * pm,const TileClass * baseClass,const char * style,const char * type,const color_t mask,const color_t maskAlt)232 TileClass *TileClassesAdd(
233 	TileClasses *c, PicManager *pm, const TileClass *baseClass,
234 	const char *style, const char *type,
235 	const color_t mask, const color_t maskAlt)
236 {
237 	TileClass *t;
238 	CMALLOC(t, sizeof *t);
239 	TileClassInit(t, pm, baseClass, style, type, mask, maskAlt);
240 
241 	char buf[CDOGS_PATH_MAX];
242 	TileClassGetName(buf, t, style, type, mask, maskAlt);
243 	const int error = hashmap_put(c->customClasses, buf, t);
244 	if (error != MAP_OK)
245 	{
246 		LOG(LM_MAIN, LL_ERROR, "failed to add tile class %s: %d", buf, error);
247 		TileClassDestroy(t);
248 		return NULL;
249 	}
250 	LOG(LM_MAIN, LL_DEBUG, "add tile class %s", buf);
251 	return t;
252 }
TileClassGetName(char * buf,const TileClass * base,const char * style,const char * type,const color_t mask,const color_t maskAlt)253 void TileClassGetName(
254 	char *buf, const TileClass *base, const char *style, const char *type,
255 	const color_t mask, const color_t maskAlt)
256 {
257 	char maskName[COLOR_STR_BUF];
258 	ColorStr(maskName, mask);
259 	char maskAltName[COLOR_STR_BUF];
260 	ColorStr(maskAltName, maskAlt);
261 	sprintf(
262 		buf, "%s%s/%s/%s/%s/%s",
263 		TileClassTypeStr(base->Type), base->IsRoom ? "room" : "",
264 		style, type, maskName, maskAltName);
265 }
TileClassGetBaseName(char * buf,const TileClass * tc)266 void TileClassGetBaseName(char *buf, const TileClass *tc)
267 {
268 	TileClassGetName(
269 		buf, tc, tc->Style, TileClassBaseStyleType(tc->Type),
270 		tc->Mask, tc->MaskAlt);
271 }
TileClassGetPic(const PicManager * pm,const TileClass * tc)272 const Pic *TileClassGetPic(const PicManager *pm, const TileClass *tc)
273 {
274 	char buf[CDOGS_PATH_MAX];
275 	char maskName[COLOR_STR_BUF];
276 	ColorStr(maskName, tc->Mask);
277 	char maskAltName[COLOR_STR_BUF];
278 	ColorStr(maskAltName, tc->MaskAlt);
279 	sprintf(
280 		buf, "%s/%s/%s/%s/%s",
281 		tc->Name, tc->Style, tc->StyleType, maskName, maskAltName);
282 	const Pic *pic = PicManagerGetPic(pm, buf);
283 	return pic;
284 }
285 
TileClassesGetExit(TileClasses * c,PicManager * pm,const char * style,const bool isShadow)286 const TileClass *TileClassesGetExit(
287 	TileClasses *c, PicManager *pm, const char *style, const bool isShadow)
288 {
289 	char buf[256];
290 	const char *type = isShadow ? "shadow" : "normal";
291 	TileClassGetName(buf, &gTileExit, style, type, colorWhite, colorWhite);
292 	const TileClass *t = StrTileClass(buf);
293 	if (t != &gTileNothing)
294 	{
295 		return t;
296 	}
297 
298 	// tile class not found; create it
299 	PicManagerGenerateMaskedStylePic(
300 		pm, "exits", style, type, colorWhite, colorWhite, true);
301 	return TileClassesAdd(
302 		c, pm, &gTileExit, style, type, colorWhite, colorWhite);
303 }
304