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