1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: files.cpp
5 	Desc: contains code for file i/o
6 
7 	Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
8 	See LICENSE for details.
9 
10 -------------------------------------------------------------------------------*/
11 
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <dirent.h>
15 
16 #include <fstream>
17 #include <list>
18 #include <string>
19 
20 #include "main.hpp"
21 #include "files.hpp"
22 #include "sound.hpp"
23 #include "entity.hpp"
24 #include "book.hpp"
25 #include "menu.hpp"
26 #include "items.hpp"
27 #include "interface/interface.hpp"
28 #include "mod_tools.hpp"
29 
30 std::vector<int> gamemods_modelsListModifiedIndexes;
31 std::vector<std::pair<SDL_Surface**, std::string>> systemResourceImagesToReload;
32 std::unordered_map<std::string, int> mapHashes =
33 {
34 	{ "start.lmp", 126469 },
35 	{ "mine.lmp", 85780 },
36 	{ "mine00.lmp", 13234 },
37 	{ "mine01.lmp", 11830 },
38 	{ "mine02.lmp", 6249 },
39 	{ "mine03.lmp", 6098 },
40 	{ "mine04.lmp", 7120 },
41 	{ "mine05.lmp", 8076 },
42 	{ "mine06.lmp", 18001 },
43 	{ "mine07.lmp", 19587 },
44 	{ "mine08.lmp", 5241 },
45 	{ "mine09.lmp", 18992 },
46 	{ "mine10.lmp", 24825 },
47 	{ "mine11.lmp", 13415 },
48 	{ "mine12.lmp", 12253 },
49 	{ "mine13.lmp", 10261 },
50 	{ "mine14.lmp", 15502 },
51 	{ "mine15.lmp", 9930 },
52 	{ "mine16.lmp", 13337 },
53 	{ "mine17.lmp", 11360 },
54 	{ "mine18.lmp", 10841 },
55 	{ "mine19.lmp", 4695 },
56 	{ "mine20.lmp", 5250 },
57 	{ "mine21.lmp", 6005 },
58 	{ "mine22.lmp", 5940 },
59 	{ "mine23.lmp", 6022 },
60 	{ "mine24.lmp", 8775 },
61 	{ "mine25.lmp", 2509 },
62 	{ "mine26.lmp", 1852 },
63 	{ "mine27.lmp", 1909 },
64 	{ "mine28.lmp", 1966 },
65 	{ "mine29.lmp", 2189 },
66 	{ "mine30.lmp", 36103 },
67 	{ "mine31.lmp", 20880 },
68 	{ "mine32.lmp", 10381 },
69 	{ "mine33.lmp", 13668 },
70 	{ "minetoswamp.lmp", 35867 },
71 	{ "minesecret.lmp", 12174 },
72 	{ "gnomishmines.lmp", 571896 },
73 	{ "minetown.lmp", 1401309 },
74 	{ "swamp.lmp", 13542615 },
75 	{ "swamp00.lmp", 14599 },
76 	{ "swamp01.lmp", 6780 },
77 	{ "swamp02.lmp", 27059 },
78 	{ "swamp03.lmp", 17148 },
79 	{ "swamp04.lmp", 26450 },
80 	{ "swamp05.lmp", 13262 },
81 	{ "swamp06.lmp", 16320 },
82 	{ "swamp07.lmp", 100108 },
83 	{ "swamp08.lmp", 8690 },
84 	{ "swamp09.lmp", 7540 },
85 	{ "swamp10.lmp", 19205 },
86 	{ "swamp11.lmp", 52707 },
87 	{ "swamp12.lmp", 88446 },
88 	{ "swamp13.lmp", 12936 },
89 	{ "swamp14.lmp", 14215 },
90 	{ "swamp15.lmp", 1092 },
91 	{ "swamp16.lmp", 3977 },
92 	{ "swamp17.lmp", 11776 },
93 	{ "swamp18.lmp", 1484 },
94 	{ "swamp19.lmp", 6366 },
95 	{ "swamp20.lmp", 8541 },
96 	{ "swamp21.lmp", 9036 },
97 	{ "swamp22.lmp", 15810 },
98 	{ "swamp23.lmp", 151549 },
99 	{ "swamp24.lmp", 16155 },
100 	{ "swamp25.lmp", 9710 },
101 	{ "swamp26.lmp", 41369 },
102 	{ "swamp27.lmp", 49462 },
103 	{ "swamp28.lmp", 1223 },
104 	{ "swamp29.lmp", 1136 },
105 	{ "swamp30.lmp", 43685 },
106 	{ "swamp31.lmp", 27215 },
107 	{ "swamp32.lmp", 13342 },
108 	{ "swamptolabyrinth.lmp", 63062 },
109 	{ "swampsecret.lmp", 11316 },
110 	{ "temple.lmp", 1756474 },
111 	{ "greatcastle.lmp", 551758 },
112 	{ "labyrinth.lmp", 219311 },
113 	{ "labyrinth00.lmp", 12194 },
114 	{ "labyrinth01.lmp", 4079 },
115 	{ "labyrinth02.lmp", 472 },
116 	{ "labyrinth03.lmp", 24615 },
117 	{ "labyrinth04.lmp", 8421 },
118 	{ "labyrinth05.lmp", 5742 },
119 	{ "labyrinth06.lmp", 4296 },
120 	{ "labyrinth07.lmp", 4297 },
121 	{ "labyrinth08.lmp", 4389 },
122 	{ "labyrinth09.lmp", 9494 },
123 	{ "labyrinth10.lmp", 10304 },
124 	{ "labyrinth11.lmp", 89828 },
125 	{ "labyrinth12.lmp", 39775 },
126 	{ "labyrinth13.lmp", 9162 },
127 	{ "labyrinth14.lmp", 40743 },
128 	{ "labyrinth15.lmp", 35557 },
129 	{ "labyrinth16.lmp", 12319 },
130 	{ "labyrinth17.lmp", 11146 },
131 	{ "labyrinth18.lmp", 6437 },
132 	{ "labyrinth19.lmp", 7273 },
133 	{ "labyrinth20.lmp", 10027 },
134 	{ "labyrinth21.lmp", 6939 },
135 	{ "labyrinth22.lmp", 5829 },
136 	{ "labyrinth23.lmp", 13042 },
137 	{ "labyrinth24.lmp", 14902 },
138 	{ "labyrinth25.lmp", 6399 },
139 	{ "labyrinth26.lmp", 1913 },
140 	{ "labyrinth27.lmp", 1916 },
141 	{ "labyrinth28.lmp", 1755 },
142 	{ "labyrinth29.lmp", 5155 },
143 	{ "labyrinth30.lmp", 21119 },
144 	{ "labyrinth31.lmp", 28195 },
145 	{ "labyrinth32.lmp", 28071 },
146 	{ "labyrinthtoruins.lmp", 36433 },
147 	{ "labyrinthsecret.lmp", 26508 },
148 	{ "sokoban.lmp", 122455 },
149 	{ "minotaur.lmp", 484073 },
150 	{ "ruins.lmp", 11472 },
151 	{ "ruins00.lmp", 6373 },
152 	{ "ruins01.lmp", 2301 },
153 	{ "ruins02.lmp", 2295 },
154 	{ "ruins03.lmp", 18465 },
155 	{ "ruins04.lmp", 11113 },
156 	{ "ruins05.lmp", 16194 },
157 	{ "ruins06.lmp", 1890 },
158 	{ "ruins07.lmp", 2486 },
159 	{ "ruins08.lmp", 4682 },
160 	{ "ruins09.lmp", 4704 },
161 	{ "ruins10.lmp", 10987 },
162 	{ "ruins11.lmp", 13490 },
163 	{ "ruins12.lmp", 6662 },
164 	{ "ruins13.lmp", 26335 },
165 	{ "ruins14.lmp", 766 },
166 	{ "ruins15.lmp", 772 },
167 	{ "ruins16.lmp", 4681 },
168 	{ "ruins17.lmp", 1848 },
169 	{ "ruins18.lmp", 9066 },
170 	{ "ruins19.lmp", 6897 },
171 	{ "ruins20.lmp", 40374 },
172 	{ "ruins21.lmp", 10664 },
173 	{ "ruins22.lmp", 11523 },
174 	{ "ruins23.lmp", 88 },
175 	{ "ruins24.lmp", 36565 },
176 	{ "ruins25.lmp", 1218 },
177 	{ "ruins26.lmp", 72992 },
178 	{ "ruins27.lmp", 1430 },
179 	{ "ruins28.lmp", 244 },
180 	{ "ruins29.lmp", 13673 },
181 	{ "ruins30.lmp", 39050 },
182 	{ "ruins31.lmp", 46626 },
183 	{ "ruins32.lmp", 32243 },
184 	{ "ruins33.lmp", 1597 },
185 	{ "ruins34.lmp", 381 },
186 	{ "ruinssecret.lmp", 66694 },
187 	{ "mysticlibrary.lmp", 55745 },
188 	{ "boss.lmp", 588024 },
189 	{ "underworld.lmp", 187740 },
190 	{ "underworld00.lmp", 20100 },
191 	{ "underworld01.lmp", 31871 },
192 	{ "underworld02.lmp", 9820 },
193 	{ "underworld03.lmp", 1687 },
194 	{ "underworld04.lmp", 5941 },
195 	{ "underworld05.lmp", 8743 },
196 	{ "underworld06.lmp", 11131 },
197 	{ "underworld07.lmp", 14844 },
198 	{ "underworld08.lmp", 11533 },
199 	{ "underworld09.lmp", 40231 },
200 	{ "underworld10.lmp", 218726 },
201 	{ "underworld11.lmp", 43090 },
202 	{ "underworld12.lmp", 13684 },
203 	{ "underworld13.lmp", 13664 },
204 	{ "underworld14.lmp", 43872 },
205 	{ "underworld15.lmp", 486983 },
206 	{ "underworld16.lmp", 2122 },
207 	{ "underworld17.lmp", 33907 },
208 	{ "underworld18.lmp", 48642 },
209 	{ "underworld19.lmp", 75679 },
210 	{ "underworld20.lmp", 89314 },
211 	{ "underworld21.lmp", 79585 },
212 	{ "underworld22.lmp", 76361 },
213 	{ "underworld23.lmp", 6463 },
214 	{ "underworld24.lmp", 9343 },
215 	{ "underworld25.lmp", 88248 },
216 	{ "underworld26.lmp", 3298 },
217 	{ "underworld27.lmp", 56635 },
218 	{ "underworld28.lmp", 12961 },
219 	{ "underworld29.lmp", 12473 },
220 	{ "hell.lmp", 145792 },
221 	{ "hell00.lmp", 43314 },
222 	{ "hell01.lmp", 15404 },
223 	{ "hell02.lmp", 17388 },
224 	{ "hell03.lmp", 23065 },
225 	{ "hell04.lmp", 2222 },
226 	{ "hell05.lmp", 3790 },
227 	{ "hell06.lmp", 2270 },
228 	{ "hell07.lmp", 3790 },
229 	{ "hell08.lmp", 10844 },
230 	{ "hell09.lmp", 11219 },
231 	{ "hell10.lmp", 19144 },
232 	{ "hell11.lmp", 4066 },
233 	{ "hell12.lmp", 20327 },
234 	{ "hell13.lmp", 3600 },
235 	{ "hell14.lmp", 28891 },
236 	{ "hell15.lmp", 99289 },
237 	{ "hell16.lmp", 357141 },
238 	{ "hell17.lmp", 14157 },
239 	{ "hell18.lmp", 14717 },
240 	{ "hell19.lmp", 5471 },
241 	{ "hell20.lmp", 15568 },
242 	{ "hell21.lmp", 8218 },
243 	{ "hell22.lmp", 14855 },
244 	{ "hell23.lmp", 8685 },
245 	{ "hell24.lmp", 61443 },
246 	{ "hell25.lmp", 53518 },
247 	{ "hell26.lmp", 4116 },
248 	{ "hell27.lmp", 2333 },
249 	{ "hell28.lmp", 1329 },
250 	{ "hell29.lmp", 36832 },
251 	{ "hellboss.lmp", 835271 },
252 	{ "hamlet.lmp", 8681527 },
253 	{ "caves.lmp", 1065461 },
254 	{ "caves00.lmp", 70935 },
255 	{ "caves01.lmp", 13350 },
256 	{ "caves02.lmp", 6995 },
257 	{ "caves03.lmp", 11883 },
258 	{ "caves04.lmp", 15294 },
259 	{ "caves05.lmp", 10359 },
260 	{ "caves06.lmp", 8376 },
261 	{ "caves07.lmp", 9198 },
262 	{ "caves08.lmp", 6873 },
263 	{ "caves09.lmp", 102879 },
264 	{ "caves10.lmp", 28899 },
265 	{ "caves11.lmp", 35066 },
266 	{ "caves12.lmp", 39802 },
267 	{ "caves13.lmp", 45478 },
268 	{ "caves14.lmp", 37757 },
269 	{ "caves15.lmp", 26887 },
270 	{ "caves16.lmp", 233992 },
271 	{ "caves17.lmp", 31734 },
272 	{ "caves18.lmp", 36806 },
273 	{ "caves19.lmp", 25878 },
274 	{ "caves20.lmp", 117281 },
275 	{ "caves21.lmp", 16169 },
276 	{ "caves22.lmp", 26212 },
277 	{ "caves23.lmp", 35367 },
278 	{ "caves24.lmp", 80159 },
279 	{ "caves25.lmp", 19691 },
280 	{ "caves26.lmp", 41694 },
281 	{ "caves27.lmp", 10622 },
282 	{ "caves28.lmp", 8712 },
283 	{ "caves01a.lmp", 5 },
284 	{ "caves01b.lmp", 898 },
285 	{ "caves01c.lmp", 1238 },
286 	{ "caves01d.lmp", 709 },
287 	{ "caves01e.lmp", 5 },
288 	{ "caves01f.lmp", 955 },
289 	{ "caves09a.lmp", 2836 },
290 	{ "caves09b.lmp", 6462 },
291 	{ "caves09c.lmp", 8822 },
292 	{ "caves09d.lmp", 9722 },
293 	{ "caves09e.lmp", 6727 },
294 	{ "caves13a.lmp", 1855 },
295 	{ "caves13b.lmp", 1678 },
296 	{ "caves13c.lmp", 6637 },
297 	{ "caves13d.lmp", 3017 },
298 	{ "caves13e.lmp", 2892 },
299 	{ "caves24a.lmp", 159828 },
300 	{ "caves24b.lmp", 170175 },
301 	{ "caves24c.lmp", 169732 },
302 	{ "caves24d.lmp", 391561 },
303 	{ "cavestocitadel.lmp", 215724 },
304 	{ "cavessecret.lmp", 198959 },
305 	{ "caveslair.lmp", 4602584 },
306 	{ "citadel.lmp", 729069 },
307 	{ "citadel00.lmp", 23997 },
308 	{ "citadel01.lmp", 30094 },
309 	{ "citadel02.lmp", 20605 },
310 	{ "citadel03.lmp", 23292 },
311 	{ "citadel04.lmp", 23377 },
312 	{ "citadel05.lmp", 24208 },
313 	{ "citadel06.lmp", 22342 },
314 	{ "citadel07.lmp", 24158 },
315 	{ "citadel08.lmp", 23917 },
316 	{ "citadel09.lmp", 31320 },
317 	{ "citadel10.lmp", 31323 },
318 	{ "citadel11.lmp", 31330 },
319 	{ "citadel12.lmp", 31330 },
320 	{ "citadel13.lmp", 62357 },
321 	{ "citadel14.lmp", 121487 },
322 	{ "citadel15.lmp", 62368 },
323 	{ "citadel16.lmp", 55383 },
324 	{ "citadel17.lmp", 111086 },
325 	{ "citadel01a.lmp", 2025 },
326 	{ "citadel01b.lmp", 2224 },
327 	{ "citadel01c.lmp", 2025 },
328 	{ "citadel01d.lmp", 2377 },
329 	{ "citadel01e.lmp", 582 },
330 	{ "citadel01f.lmp", 204 },
331 	{ "citadel01g.lmp", 6 },
332 	{ "citadel02a.lmp", 4 },
333 	{ "citadel02b.lmp", 4 },
334 	{ "citadel02c.lmp", 4 },
335 	{ "citadel02d.lmp", 4 },
336 	{ "citadel02e.lmp", 4 },
337 	{ "citadel02f.lmp", 4 },
338 	{ "citadel02g.lmp", 4 },
339 	{ "citadel09a.lmp", 4930 },
340 	{ "citadel09b.lmp", 6181 },
341 	{ "citadel09c.lmp", 5270 },
342 	{ "citadel10a.lmp", 4930 },
343 	{ "citadel10b.lmp", 8900 },
344 	{ "citadel10c.lmp", 6072 },
345 	{ "citadel11a.lmp", 4930 },
346 	{ "citadel11b.lmp", 7722 },
347 	{ "citadel11c.lmp", 4860 },
348 	{ "citadel11d.lmp", 4179 },
349 	{ "citadel12a.lmp", 4930 },
350 	{ "citadel12b.lmp", 5874 },
351 	{ "citadel12c.lmp", 6072 },
352 	{ "citadel13a.lmp", 21969 },
353 	{ "citadel13b.lmp", 12526 },
354 	{ "citadel14a.lmp", 171089 },
355 	{ "citadel14b.lmp", 42457 },
356 	{ "citadel14c.lmp", 43306 },
357 	{ "citadel15a.lmp", 9038 },
358 	{ "citadel15b.lmp", 12010 },
359 	{ "citadel16a.lmp", 11376 },
360 	{ "citadel16b.lmp", 6314 },
361 	{ "citadel17a.lmp", 7279 },
362 	{ "citadel17b.lmp", 1729 },
363 	{ "citadel17c.lmp", 4197 },
364 	{ "citadel17d.lmp", 8339 },
365 	{ "citadel18.lmp", 31650 },
366 	{ "citadel19.lmp", 11786 },
367 	{ "citadel20.lmp", 11905 },
368 	{ "citadel21.lmp", 59257 },
369 	{ "citadelsecret.lmp", 104229 },
370 	{ "bramscastle.lmp", 2995692 },
371 	{ "sanctum.lmp", 5630316 },
372 	{ "shop00.lmp", 7106 },
373 	{ "shop02.lmp", 11805 },
374 	{ "shop01.lmp", 11521 },
375 	{ "shop03.lmp", 11396 },
376 	{ "shopcitadel.lmp", 25021 },
377 	{ "warpzone.lmp", 3133088 },
378 	{ "tutorial_hub.lmp", -1 },
379 	{ "tutorial1.lmp", -1 },
380 	{ "tutorial2.lmp", -1 },
381 	{ "tutorial3.lmp", -1 },
382 	{ "tutorial4.lmp", -1 },
383 	{ "tutorial5.lmp", -1 },
384 	{ "tutorial6.lmp", -1 },
385 	{ "tutorial7.lmp", -1 },
386 	{ "tutorial8.lmp", -1 },
387 	{ "tutorial9.lmp", -1 },
388 	{ "tutorial10.lmp", -1 }
389 };
390 
391 const std::vector<std::string> officialLevelsTxtOrder =
392 {
393 	"start",
394 	"mine",
395 	"mine",
396 	"mine",
397 	"mine",
398 	"minetoswamp",
399 	"swamp",
400 	"swamp",
401 	"swamp",
402 	"swamp",
403 	"swamptolabyrinth",
404 	"labyrinth",
405 	"labyrinth",
406 	"labyrinth",
407 	"labyrinth",
408 	"labyrinthtoruins",
409 	"ruins",
410 	"ruins",
411 	"ruins",
412 	"ruins",
413 	"boss",
414 	"hell",
415 	"hell",
416 	"hell",
417 	"hellboss",
418 	"hamlet",
419 	"caves",
420 	"caves",
421 	"caves",
422 	"caves",
423 	"cavestocitadel",
424 	"citadel",
425 	"citadel",
426 	"citadel",
427 	"citadel",
428 	"sanctum"
429 };
430 
431 const std::vector<std::string> officialSecretlevelsTxtOrder =
432 {
433 	"warpzone",
434 	"warpzone",
435 	"warpzone",
436 	"gnomishmines",
437 	"minetown",
438 	"warpzone",
439 	"underworld",
440 	"underworld",
441 	"temple",
442 	"greatcastle",
443 	"warpzone",
444 	"warpzone",
445 	"sokoban",
446 	"warpzone",
447 	"minotaur",
448 	"warpzone",
449 	"warpzone",
450 	"mysticlibrary",
451 	"warpzone",
452 	"underworld",
453 	"underworld",
454 	"warpzone",
455 	"warpzone",
456 	"warpzone",
457 	"boss",
458 	"warpzone",
459 	"warpzone",
460 	"warpzone",
461 	"warpzone",
462 	"caveslair",
463 	"warpzone",
464 	"warpzone",
465 	"warpzone",
466 	"warpzone",
467 	"bramscastle",
468 	"warpzone",
469 	"warpzone",
470 	"warpzone"
471 };
472 
473 /*-------------------------------------------------------------------------------
474 
475 	glLoadTexture
476 
477 	Binds the given image to an opengl texture name
478 
479 -------------------------------------------------------------------------------*/
480 
glLoadTexture(SDL_Surface * image,int texnum)481 void glLoadTexture(SDL_Surface* image, int texnum)
482 {
483 	SDL_LockSurface(image);
484 	glEnable(GL_TEXTURE_2D);
485 	glBindTexture(GL_TEXTURE_2D, texid[texnum]);
486 	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
487 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
488 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
489 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
490 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
491 	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
492 	//#ifdef APPLE
493 	//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image->w, image->h, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, image->pixels);
494 	//#else
495 	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
496 	//#endif
497 	SDL_UnlockSurface(image);
498 }
499 
500 
completePath(char * dest,const char * const filename,const char * base)501 bool completePath(char *dest, const char * const filename, const char *base) {
502 	if (!(filename && filename[0])) {
503 		return false;
504 	}
505 
506 	// Already absolute
507 	if (filename[0] == '/') {
508 		strncpy(dest, filename, PATH_MAX);
509 		return true;
510 	}
511 
512 #ifdef WINDOWS
513 	// Already absolute (drive letter in path)
514 	if ( filename[1] == ':' ) {
515 		strncpy(dest, filename, PATH_MAX);
516 		return true;
517 	}
518 #endif
519 
520 	snprintf(dest, PATH_MAX, "%s/%s", base, filename);
521 	return true;
522 }
523 
openDataFile(const char * const filename,const char * const mode)524 FILE* openDataFile(const char * const filename, const char * const mode) {
525 	char path[PATH_MAX];
526 	completePath(path, filename);
527 	FILE * result = fopen(path, mode);
528 	if (!result) {
529 		printlog("Could not open '%s': %s", path, strerror(errno));
530 	}
531 	return result;
532 }
533 
openDataDir(const char * const name)534 DIR* openDataDir(const char * const name) {
535 	char path[PATH_MAX];
536 	completePath(path, name);
537 	DIR * result = opendir(path);
538 	if (!result) {
539 		printlog("Could not open '%s': %s", path, strerror(errno));
540 	}
541 	return result;
542 }
543 
544 
dataPathExists(const char * const path)545 bool dataPathExists(const char * const path) {
546 	char full_path[PATH_MAX];
547 	completePath(full_path, path);
548 	return access(full_path, F_OK) != -1;
549 }
550 
openLogFile()551 void openLogFile() {
552 	char path[PATH_MAX];
553 	completePath(path, "log.txt", outputdir);
554 
555 	logfile = freopen(path, "wb" /*or "wt"*/, stderr);
556 }
557 
558 
559 /*-------------------------------------------------------------------------------
560 
561 	loadImage
562 
563 	Loads the image specified in filename, binds it to an opengl texture name,
564 	and returns the image as an SDL_Surface
565 
566 -------------------------------------------------------------------------------*/
567 
loadImage(char const * const filename)568 SDL_Surface* loadImage(char const * const filename)
569 {
570 	char full_path[PATH_MAX];
571 	completePath(full_path, filename);
572 	SDL_Surface* originalSurface;
573 
574 	if ( imgref >= MAXTEXTURES )
575 	{
576 		printlog("critical error! No more room in allsurfaces[], MAXTEXTURES reached.\n");
577 		printlog("aborting...\n");
578 		exit(1);
579 	}
580 	if ( (originalSurface = IMG_Load(full_path)) == NULL )
581 	{
582 		printlog("error: failed to load image '%s'\n", full_path);
583 		exit(1); // critical error
584 		return NULL;
585 	}
586 
587 	// translate the original surface to an RGBA surface
588 	//int w = pow(2, ceil( log(std::max(originalSurface->w,originalSurface->h))/log(2) ) ); // round up to the nearest power of two
589 	SDL_Surface* newSurface = SDL_CreateRGBSurface(0, originalSurface->w, originalSurface->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
590 	SDL_BlitSurface(originalSurface, NULL, newSurface, NULL); // blit onto a purely RGBA Surface
591 
592 	// load the new surface as a GL texture
593 	allsurfaces[imgref] = newSurface;
594 	allsurfaces[imgref]->refcount = imgref + 1;
595 	glLoadTexture(allsurfaces[imgref], imgref);
596 
597 	// free the translated surface
598 	SDL_FreeSurface(originalSurface);
599 
600 	imgref++;
601 	return allsurfaces[imgref - 1];
602 }
603 
604 /*-------------------------------------------------------------------------------
605 
606 	loadVoxel
607 
608 	Loads a voxel model from the given filename
609 
610 -------------------------------------------------------------------------------*/
611 
loadVoxel(char * filename)612 voxel_t* loadVoxel(char* filename)
613 {
614 	//char filename2[1024];
615 	FILE* file;
616 	voxel_t* model;
617 
618 	if (filename != NULL)
619 	{
620 		//bool has_ext = strstr(filename, ".vox") == NULL;
621 		//snprintf(filename2, 1024, "%s%s", filename, has_ext ? "" : ".vox");
622 		std::string filenamePath = PHYSFS_getRealDir(filename);
623 		filenamePath.append(PHYSFS_getDirSeparator()).append(filename);
624 
625 		if ((file = openDataFile(filenamePath.c_str(), "rb")) == NULL)
626 		{
627 			return NULL;
628 		}
629 		model = (voxel_t*) malloc(sizeof(voxel_t));
630 		model->sizex = 0;
631 		fread(&model->sizex, sizeof(Sint32), 1, file);
632 		model->sizey = 0;
633 		fread(&model->sizey, sizeof(Sint32), 1, file);
634 		model->sizez = 0;
635 		fread(&model->sizez, sizeof(Sint32), 1, file);
636 		model->data = (Uint8*) malloc(sizeof(Uint8) * model->sizex * model->sizey * model->sizez);
637 		memset(model->data, 0, sizeof(Uint8)*model->sizex * model->sizey * model->sizez);
638 		fread(model->data, sizeof(Uint8), model->sizex * model->sizey * model->sizez, file);
639 		fread(&model->palette, sizeof(Uint8), 256 * 3, file);
640 		int c;
641 		for ( c = 0; c < 256; c++ )
642 		{
643 			model->palette[c][0] = model->palette[c][0] << 2;
644 			model->palette[c][1] = model->palette[c][1] << 2;
645 			model->palette[c][2] = model->palette[c][2] << 2;
646 		}
647 		fclose(file);
648 
649 		return model;
650 	}
651 	else
652 	{
653 		return NULL;
654 	}
655 }
656 
657 /*-------------------------------------------------------------------------------
658 
659 	loadMap
660 
661 	Loads a map from the given filename
662 
663 -------------------------------------------------------------------------------*/
664 
loadMap(const char * filename2,map_t * destmap,list_t * entlist,list_t * creatureList,int * checkMapHash)665 int loadMap(const char* filename2, map_t* destmap, list_t* entlist, list_t* creatureList, int *checkMapHash)
666 {
667 	FILE* fp;
668 	char valid_data[16];
669 	Uint32 numentities;
670 	Uint32 c;
671 	Sint32 x, y;
672 	Entity* entity;
673 	Sint32 sprite;
674 	Stat* myStats;
675 	Stat* dummyStats;
676 	sex_t s;
677 	int editorVersion = 0;
678 	char filename[1024];
679 	int mapHashData = 0;
680 	if ( checkMapHash )
681 	{
682 		*checkMapHash = 0;
683 	}
684 
685 	char oldmapname[64];
686 	strcpy(oldmapname, map.name);
687 
688 	printlog("LoadMap %s", filename2);
689 
690 	if (! (filename2 && filename2[0]))
691 	{
692 		printlog("map filename empty or null");
693 		return -1;
694 	}
695 
696 	if ( !PHYSFS_isInit() )
697 	{
698 		strcpy(filename, "maps/");
699 		strcat(filename, filename2);
700 	}
701 	else
702 	{
703 		strcpy(filename, filename2);
704 	}
705 
706 
707 	// add extension if missing
708 	if ( strstr(filename, ".lmp") == nullptr )
709 	{
710 		strcat(filename, ".lmp");
711 	}
712 
713 	// load the file!
714 	if ((fp = openDataFile(filename, "rb")) == nullptr)
715 	{
716 		printlog("warning: failed to open file '%s' for map loading!\n", filename);
717 		if ( destmap == &map && game )
718 		{
719 			printlog("error: main map failed to load, aborting.\n");
720 			mainloop = 0;
721 		}
722 		return -1;
723 	}
724 
725 	// read map version number
726 	fread(valid_data, sizeof(char), strlen("BARONY LMPV2.0"), fp);
727 	if ( strncmp(valid_data, "BARONY LMPV2.6", strlen("BARONY LMPV2.0")) == 0 )
728 	{
729 		// V2.6 version of editor - player starts/doors/gates
730 		editorVersion = 26;
731 	}
732 	else if ( strncmp(valid_data, "BARONY LMPV2.5", strlen("BARONY LMPV2.0")) == 0 )
733 	{
734 		// V2.5 version of editor - scripting
735 		editorVersion = 25;
736 	}
737 	else if ( strncmp(valid_data, "BARONY LMPV2.4", strlen("BARONY LMPV2.0")) == 0 )
738 	{
739 		// V2.4 version of editor - boulder trap properties
740 		editorVersion = 24;
741 	}
742 	else if ( strncmp(valid_data, "BARONY LMPV2.3", strlen("BARONY LMPV2.0")) == 0 )
743 	{
744 		// V2.3 version of editor - map flags
745 		editorVersion = 23;
746 	}
747 	else if ( strncmp(valid_data, "BARONY LMPV2.2", strlen("BARONY LMPV2.0")) == 0 )
748 	{
749 		// V2.2 version of editor - submaps
750 		editorVersion = 22;
751 	}
752 	else if ( strncmp(valid_data, "BARONY LMPV2.1", strlen("BARONY LMPV2.0")) == 0 )
753 	{
754 		// V2.1 version of editor - skybox
755 		editorVersion = 21;
756 	}
757 	else if ( strncmp(valid_data, "BARONY LMPV2.0", strlen("BARONY LMPV2.0")) == 0 )
758 	{
759 		// V2.0 version of editor
760 		editorVersion = 2;
761 	}
762 	else
763 	{
764 		rewind(fp);
765 		fread(valid_data, sizeof(char), strlen("BARONY"), fp);
766 		if ( strncmp(valid_data, "BARONY", strlen("BARONY")) == 0 )
767 		{
768 			// V1.0 version of editor
769 			editorVersion = 1;
770 		}
771 		else
772 		{
773 			printlog("warning: file '%s' is an invalid map file.\n", filename);
774 			fclose(fp);
775 			if ( destmap == &map && game )
776 			{
777 				printlog("error: main map failed to load, aborting.\n");
778 				mainloop = 0;
779 			}
780 			return -1;
781 		}
782 	}
783 
784 	list_FreeAll(entlist);
785 	if ( destmap == &map )
786 	{
787 		// remove old lights
788 		list_FreeAll(&light_l);
789 	}
790 	if ( destmap->tiles != NULL )
791 	{
792 		free(destmap->tiles);
793 	}
794 	fread(destmap->name, sizeof(char), 32, fp); // map name
795 	fread(destmap->author, sizeof(char), 32, fp); // map author
796 	fread(&destmap->width, sizeof(Uint32), 1, fp); // map width
797 	fread(&destmap->height, sizeof(Uint32), 1, fp); // map height
798 
799 	mapHashData += destmap->width + destmap->height;
800 
801 	// map skybox
802 	if ( editorVersion == 1 || editorVersion == 2 )
803 	{
804 		if ( strncmp(destmap->name, "Hell", 4) == 0 )
805 		{
806 			destmap->skybox = 77;
807 		}
808 		else
809 		{
810 			destmap->skybox = 0;
811 		}
812 	}
813 	else
814 	{
815 		fread(&destmap->skybox, sizeof(Uint32), 1, fp); // map skybox
816 	}
817 
818 	// misc map flags
819 	if ( editorVersion == 1 || editorVersion == 2 || editorVersion == 21 || editorVersion == 22 )
820 	{
821 		for ( c = 0; c < MAPFLAGS; c++ )
822 		{
823 			destmap->flags[c] = 0;
824 		}
825 	}
826 	else
827 	{
828 		fread(destmap->flags, sizeof(Sint32), MAPFLAGS, fp); // map flags
829 	}
830 	destmap->tiles = (Sint32*) malloc(sizeof(Sint32) * destmap->width * destmap->height * MAPLAYERS);
831 	fread(destmap->tiles, sizeof(Sint32), destmap->width * destmap->height * MAPLAYERS, fp);
832 	fread(&numentities, sizeof(Uint32), 1, fp); // number of entities on the map
833 
834 	for ( c = 0; c < destmap->width * destmap->height * MAPLAYERS; ++c )
835 	{
836 		mapHashData += destmap->tiles[c];
837 	}
838 
839 	for (c = 0; c < numentities; c++)
840 	{
841 		fread(&sprite, sizeof(Sint32), 1, fp);
842 		entity = newEntity(sprite, 0, entlist, nullptr); //TODO: Figure out when we need to assign an entity to the global monster list. And do it!
843 		switch( editorVersion )
844 		{	case 1:
845 				// V1.0 of editor version
846 			switch ( checkSpriteType(sprite) )
847 			{
848 				case 1:
849 				case 2:
850 				case 3:
851 				case 4:
852 				case 5:
853 				case 6:
854 				case 7:
855 					setSpriteAttributes(entity, nullptr, nullptr);
856 					break;
857 				default:
858 					break;
859 			}
860 				break;
861 			case 2:
862 			case 21:
863 			case 22:
864 			case 23:
865 			case 24:
866 			case 25:
867 			case 26:
868 				// V2.0+ of editor version
869 				switch ( checkSpriteType(sprite) )
870 				{
871 					case 1:
872 						if ( multiplayer != CLIENT )
873 						{
874 							// need to give the entity its list stuff.
875 							// create an empty first node for traversal purposes
876 							node_t* node2 = list_AddNodeFirst(&entity->children);
877 							node2->element = NULL;
878 							node2->deconstructor = &emptyDeconstructor;
879 
880 							myStats = new Stat(entity->sprite);
881 							node2 = list_AddNodeLast(&entity->children);
882 							node2->element = myStats;
883 							//					node2->deconstructor = &myStats->~Stat;
884 							node2->size = sizeof(myStats);
885 
886 							sex_t dummyVar = MALE;
887 							// we don't actually embed the sex from the editor
888 							// advance the fp since we read in 0 always.
889 							// otherwise it would overwrite the value of a handplaced succubus or a certain icey lich.
890 							// certainly were a lot of male adventurers locked in cells...
891 							fread(&dummyVar, sizeof(sex_t), 1, fp);
892 							fread(&myStats->name, sizeof(char[128]), 1, fp);
893 							fread(&myStats->HP, sizeof(Sint32), 1, fp);
894 							fread(&myStats->MAXHP, sizeof(Sint32), 1, fp);
895 							fread(&myStats->OLDHP, sizeof(Sint32), 1, fp);
896 							fread(&myStats->MP, sizeof(Sint32), 1, fp);
897 							fread(&myStats->MAXMP, sizeof(Sint32), 1, fp);
898 							fread(&myStats->STR, sizeof(Sint32), 1, fp);
899 							fread(&myStats->DEX, sizeof(Sint32), 1, fp);
900 							fread(&myStats->CON, sizeof(Sint32), 1, fp);
901 							fread(&myStats->INT, sizeof(Sint32), 1, fp);
902 							fread(&myStats->PER, sizeof(Sint32), 1, fp);
903 							fread(&myStats->CHR, sizeof(Sint32), 1, fp);
904 							fread(&myStats->LVL, sizeof(Sint32), 1, fp);
905 							fread(&myStats->GOLD, sizeof(Sint32), 1, fp);
906 
907 							fread(&myStats->RANDOM_MAXHP, sizeof(Sint32), 1, fp);
908 							fread(&myStats->RANDOM_HP, sizeof(Sint32), 1, fp);
909 							fread(&myStats->RANDOM_MAXMP, sizeof(Sint32), 1, fp);
910 							fread(&myStats->RANDOM_MP, sizeof(Sint32), 1, fp);
911 							fread(&myStats->RANDOM_STR, sizeof(Sint32), 1, fp);
912 							fread(&myStats->RANDOM_CON, sizeof(Sint32), 1, fp);
913 							fread(&myStats->RANDOM_DEX, sizeof(Sint32), 1, fp);
914 							fread(&myStats->RANDOM_INT, sizeof(Sint32), 1, fp);
915 							fread(&myStats->RANDOM_PER, sizeof(Sint32), 1, fp);
916 							fread(&myStats->RANDOM_CHR, sizeof(Sint32), 1, fp);
917 							fread(&myStats->RANDOM_LVL, sizeof(Sint32), 1, fp);
918 							fread(&myStats->RANDOM_GOLD, sizeof(Sint32), 1, fp);
919 
920 							if ( editorVersion >= 22 )
921 							{
922 								fread(&myStats->EDITOR_ITEMS, sizeof(Sint32), ITEM_SLOT_NUM, fp);
923 							}
924 							else
925 							{
926 								// read old map formats
927 								fread(&myStats->EDITOR_ITEMS, sizeof(Sint32), 96, fp);
928 							}
929 							fread(&myStats->MISC_FLAGS, sizeof(Sint32), 32, fp);
930 						}
931 						//Read dummy values to move fp for the client
932 						else
933 						{
934 							dummyStats = new Stat(entity->sprite);
935 							fread(&dummyStats->sex, sizeof(sex_t), 1, fp);
936 							fread(&dummyStats->name, sizeof(char[128]), 1, fp);
937 							fread(&dummyStats->HP, sizeof(Sint32), 1, fp);
938 							fread(&dummyStats->MAXHP, sizeof(Sint32), 1, fp);
939 							fread(&dummyStats->OLDHP, sizeof(Sint32), 1, fp);
940 							fread(&dummyStats->MP, sizeof(Sint32), 1, fp);
941 							fread(&dummyStats->MAXMP, sizeof(Sint32), 1, fp);
942 							fread(&dummyStats->STR, sizeof(Sint32), 1, fp);
943 							fread(&dummyStats->DEX, sizeof(Sint32), 1, fp);
944 							fread(&dummyStats->CON, sizeof(Sint32), 1, fp);
945 							fread(&dummyStats->INT, sizeof(Sint32), 1, fp);
946 							fread(&dummyStats->PER, sizeof(Sint32), 1, fp);
947 							fread(&dummyStats->CHR, sizeof(Sint32), 1, fp);
948 							fread(&dummyStats->LVL, sizeof(Sint32), 1, fp);
949 							fread(&dummyStats->GOLD, sizeof(Sint32), 1, fp);
950 
951 							fread(&dummyStats->RANDOM_MAXHP, sizeof(Sint32), 1, fp);
952 							fread(&dummyStats->RANDOM_HP, sizeof(Sint32), 1, fp);
953 							fread(&dummyStats->RANDOM_MAXMP, sizeof(Sint32), 1, fp);
954 							fread(&dummyStats->RANDOM_MP, sizeof(Sint32), 1, fp);
955 							fread(&dummyStats->RANDOM_STR, sizeof(Sint32), 1, fp);
956 							fread(&dummyStats->RANDOM_CON, sizeof(Sint32), 1, fp);
957 							fread(&dummyStats->RANDOM_DEX, sizeof(Sint32), 1, fp);
958 							fread(&dummyStats->RANDOM_INT, sizeof(Sint32), 1, fp);
959 							fread(&dummyStats->RANDOM_PER, sizeof(Sint32), 1, fp);
960 							fread(&dummyStats->RANDOM_CHR, sizeof(Sint32), 1, fp);
961 							fread(&dummyStats->RANDOM_LVL, sizeof(Sint32), 1, fp);
962 							fread(&dummyStats->RANDOM_GOLD, sizeof(Sint32), 1, fp);
963 
964 							if ( editorVersion >= 22 )
965 							{
966 								fread(&dummyStats->EDITOR_ITEMS, sizeof(Sint32), ITEM_SLOT_NUM, fp);
967 							}
968 							else
969 							{
970 								fread(&dummyStats->EDITOR_ITEMS, sizeof(Sint32), 96, fp);
971 							}
972 							fread(&dummyStats->MISC_FLAGS, sizeof(Sint32), 32, fp);
973 							delete dummyStats;
974 						}
975 						break;
976 					case 2:
977 						fread(&entity->yaw, sizeof(real_t), 1, fp);
978 						fread(&entity->skill[9], sizeof(Sint32), 1, fp);
979 						fread(&entity->chestLocked, sizeof(Sint32), 1, fp);
980 						break;
981 					case 3:
982 						fread(&entity->skill[10], sizeof(Sint32), 1, fp);
983 						fread(&entity->skill[11], sizeof(Sint32), 1, fp);
984 						fread(&entity->skill[12], sizeof(Sint32), 1, fp);
985 						fread(&entity->skill[13], sizeof(Sint32), 1, fp);
986 						fread(&entity->skill[15], sizeof(Sint32), 1, fp);
987 						if ( editorVersion >= 22 )
988 						{
989 							fread(&entity->skill[16], sizeof(Sint32), 1, fp);
990 						}
991 						break;
992 					case 4:
993 						fread(&entity->skill[0], sizeof(Sint32), 1, fp);
994 						fread(&entity->skill[1], sizeof(Sint32), 1, fp);
995 						fread(&entity->skill[2], sizeof(Sint32), 1, fp);
996 						fread(&entity->skill[3], sizeof(Sint32), 1, fp);
997 						fread(&entity->skill[4], sizeof(Sint32), 1, fp);
998 						fread(&entity->skill[5], sizeof(Sint32), 1, fp);
999 						break;
1000 					case 5:
1001 						fread(&entity->yaw, sizeof(real_t), 1, fp);
1002 						fread(&entity->crystalNumElectricityNodes, sizeof(Sint32), 1, fp);
1003 						fread(&entity->crystalTurnReverse, sizeof(Sint32), 1, fp);
1004 						fread(&entity->crystalSpellToActivate, sizeof(Sint32), 1, fp);
1005 						break;
1006 					case 6:
1007 						fread(&entity->leverTimerTicks, sizeof(Sint32), 1, fp);
1008 						break;
1009 					case 7:
1010 						if ( editorVersion >= 24 )
1011 						{
1012 							fread(&entity->boulderTrapRefireAmount, sizeof(Sint32), 1, fp);
1013 							fread(&entity->boulderTrapRefireDelay, sizeof(Sint32), 1, fp);
1014 							fread(&entity->boulderTrapPreDelay, sizeof(Sint32), 1, fp);
1015 						}
1016 						else
1017 						{
1018 							setSpriteAttributes(entity, nullptr, nullptr);
1019 						}
1020 						break;
1021 					case 8:
1022 						fread(&entity->pedestalOrbType, sizeof(Sint32), 1, fp);
1023 						fread(&entity->pedestalHasOrb, sizeof(Sint32), 1, fp);
1024 						fread(&entity->pedestalInvertedPower, sizeof(Sint32), 1, fp);
1025 						fread(&entity->pedestalInGround, sizeof(Sint32), 1, fp);
1026 						fread(&entity->pedestalLockOrb, sizeof(Sint32), 1, fp);
1027 						break;
1028 					case 9:
1029 						fread(&entity->teleporterX, sizeof(Sint32), 1, fp);
1030 						fread(&entity->teleporterY, sizeof(Sint32), 1, fp);
1031 						fread(&entity->teleporterType, sizeof(Sint32), 1, fp);
1032 						break;
1033 					case 10:
1034 						fread(&entity->ceilingTileModel, sizeof(Sint32), 1, fp);
1035 						break;
1036 					case 11:
1037 						fread(&entity->spellTrapType, sizeof(Sint32), 1, fp);
1038 						fread(&entity->spellTrapRefire, sizeof(Sint32), 1, fp);
1039 						fread(&entity->spellTrapLatchPower, sizeof(Sint32), 1, fp);
1040 						fread(&entity->spellTrapFloorTile, sizeof(Sint32), 1, fp);
1041 						fread(&entity->spellTrapRefireRate, sizeof(Sint32), 1, fp);
1042 						break;
1043 					case 12:
1044 						if ( entity->sprite == 60 ) // chair
1045 						{
1046 							if ( editorVersion >= 25 )
1047 							{
1048 								fread(&entity->furnitureDir, sizeof(Sint32), 1, fp);
1049 							}
1050 							else
1051 							{
1052 								// don't read data, set default.
1053 								setSpriteAttributes(entity, nullptr, nullptr);
1054 							}
1055 						}
1056 						else
1057 						{
1058 							fread(&entity->furnitureDir, sizeof(Sint32), 1, fp);
1059 						}
1060 						break;
1061 					case 13:
1062 						fread(&entity->floorDecorationModel, sizeof(Sint32), 1, fp);
1063 						fread(&entity->floorDecorationRotation, sizeof(Sint32), 1, fp);
1064 						fread(&entity->floorDecorationHeightOffset, sizeof(Sint32), 1, fp);
1065 						if ( editorVersion >= 25 )
1066 						{
1067 							fread(&entity->floorDecorationXOffset, sizeof(Sint32), 1, fp);
1068 							fread(&entity->floorDecorationYOffset, sizeof(Sint32), 1, fp);
1069 							for ( int i = 8; i < 60; ++i )
1070 							{
1071 								fread(&entity->skill[i], sizeof(Sint32), 1, fp);
1072 							}
1073 						}
1074 						break;
1075 					case 14:
1076 						fread(&entity->soundSourceToPlay, sizeof(Sint32), 1, fp);
1077 						fread(&entity->soundSourceVolume, sizeof(Sint32), 1, fp);
1078 						fread(&entity->soundSourceLatchOn, sizeof(Sint32), 1, fp);
1079 						fread(&entity->soundSourceDelay, sizeof(Sint32), 1, fp);
1080 						fread(&entity->soundSourceOrigin, sizeof(Sint32), 1, fp);
1081 						break;
1082 					case 15:
1083 						fread(&entity->lightSourceAlwaysOn, sizeof(Sint32), 1, fp);
1084 						fread(&entity->lightSourceBrightness, sizeof(Sint32), 1, fp);
1085 						fread(&entity->lightSourceInvertPower, sizeof(Sint32), 1, fp);
1086 						fread(&entity->lightSourceLatchOn, sizeof(Sint32), 1, fp);
1087 						fread(&entity->lightSourceRadius, sizeof(Sint32), 1, fp);
1088 						fread(&entity->lightSourceFlicker, sizeof(Sint32), 1, fp);
1089 						fread(&entity->lightSourceDelay, sizeof(Sint32), 1, fp);
1090 						break;
1091 					case 16:
1092 					{
1093 						fread(&entity->textSourceColorRGB, sizeof(Sint32), 1, fp);
1094 						fread(&entity->textSourceVariables4W, sizeof(Sint32), 1, fp);
1095 						fread(&entity->textSourceDelay, sizeof(Sint32), 1, fp);
1096 						fread(&entity->textSourceIsScript, sizeof(Sint32), 1, fp);
1097 						for ( int i = 4; i < 60; ++i )
1098 						{
1099 							fread(&entity->skill[i], sizeof(Sint32), 1, fp);
1100 						}
1101 						break;
1102 					}
1103 					case 17:
1104 						fread(&entity->signalInputDirection, sizeof(Sint32), 1, fp);
1105 						fread(&entity->signalActivateDelay, sizeof(Sint32), 1, fp);
1106 						fread(&entity->signalTimerInterval, sizeof(Sint32), 1, fp);
1107 						fread(&entity->signalTimerRepeatCount, sizeof(Sint32), 1, fp);
1108 						fread(&entity->signalTimerLatchInput, sizeof(Sint32), 1, fp);
1109 						break;
1110 					case 18:
1111 						fread(&entity->portalCustomSprite, sizeof(Sint32), 1, fp);
1112 						fread(&entity->portalCustomSpriteAnimationFrames, sizeof(Sint32), 1, fp);
1113 						fread(&entity->portalCustomZOffset, sizeof(Sint32), 1, fp);
1114 						fread(&entity->portalCustomLevelsToJump, sizeof(Sint32), 1, fp);
1115 						fread(&entity->portalNotSecret, sizeof(Sint32), 1, fp);
1116 						fread(&entity->portalCustomRequiresPower, sizeof(Sint32), 1, fp);
1117 						for ( int i = 11; i <= 18; ++i )
1118 						{
1119 							fread(&entity->skill[i], sizeof(Sint32), 1, fp);
1120 						}
1121 						break;
1122 					case 19:
1123 						if ( editorVersion >= 25 )
1124 						{
1125 							fread(&entity->furnitureDir, sizeof(Sint32), 1, fp);
1126 							fread(&entity->furnitureTableSpawnChairs, sizeof(Sint32), 1, fp);
1127 							fread(&entity->furnitureTableRandomItemChance, sizeof(Sint32), 1, fp);
1128 						}
1129 						else
1130 						{
1131 							// don't read data, set default.
1132 							setSpriteAttributes(entity, nullptr, nullptr);
1133 						}
1134 						break;
1135 					case 20:
1136 						fread(&entity->skill[11], sizeof(Sint32), 1, fp);
1137 						fread(&entity->skill[12], sizeof(Sint32), 1, fp);
1138 						fread(&entity->skill[15], sizeof(Sint32), 1, fp);
1139 						for ( int i = 40; i <= 52; ++i )
1140 						{
1141 							fread(&entity->skill[i], sizeof(Sint32), 1, fp);
1142 						}
1143 						break;
1144 					case 21:
1145 						if ( editorVersion >= 26 )
1146 						{
1147 							fread(&entity->doorForceLockedUnlocked, sizeof(Sint32), 1, fp);
1148 							fread(&entity->doorDisableLockpicks, sizeof(Sint32), 1, fp);
1149 							fread(&entity->doorDisableOpening, sizeof(Sint32), 1, fp);
1150 						}
1151 						break;
1152 					case 22:
1153 						if ( editorVersion >= 26 )
1154 						{
1155 							fread(&entity->gateDisableOpening, sizeof(Sint32), 1, fp);
1156 						}
1157 						break;
1158 					case 23:
1159 						if ( editorVersion >= 26 )
1160 						{
1161 							fread(&entity->playerStartDir, sizeof(Sint32), 1, fp);
1162 						}
1163 						break;
1164 					default:
1165 						break;
1166 				}
1167 				break;
1168 			default:
1169 				break;
1170 		}
1171 		if ( entity->behavior == actMonster || entity->behavior == actPlayer )
1172 		{
1173 			entity->addToCreatureList(creatureList);
1174 		}
1175 
1176 		fread(&x, sizeof(Sint32), 1, fp);
1177 		fread(&y, sizeof(Sint32), 1, fp);
1178 		entity->x = x;
1179 		entity->y = y;
1180 		mapHashData += (sprite * c);
1181 	}
1182 
1183 	fclose(fp);
1184 
1185 	if ( destmap == &map )
1186 	{
1187 		nummonsters = 0;
1188 		minotaurlevel = 0;
1189 
1190 #if defined (USE_FMOD) || defined(USE_OPENAL)
1191 		if ( strcmp(oldmapname, map.name) )
1192 		{
1193 			if ( gameModeManager.getMode() == GameModeManager_t::GAME_MODE_DEFAULT )
1194 			{
1195 				levelmusicplaying = false;
1196 			}
1197 		}
1198 #endif
1199 
1200 		// create new lightmap
1201 		if ( lightmap != NULL )
1202 		{
1203 			free(lightmap);
1204 		}
1205 		if ( lightmapSmoothed )
1206 		{
1207 			free(lightmapSmoothed);
1208 		}
1209 
1210 		lightmap = (int*) malloc(sizeof(Sint32) * destmap->width * destmap->height);
1211 		lightmapSmoothed = (int*)malloc(sizeof(Sint32) * destmap->width * destmap->height);
1212 		if ( strncmp(map.name, "Hell", 4) )
1213 		{
1214 			for (c = 0; c < destmap->width * destmap->height; c++ )
1215 			{
1216 				lightmap[c] = 0;
1217 				lightmapSmoothed[c] = 0;
1218 			}
1219 		}
1220 		else
1221 		{
1222 			for (c = 0; c < destmap->width * destmap->height; c++ )
1223 			{
1224 				lightmap[c] = 32;
1225 				lightmapSmoothed[c] = 32;
1226 			}
1227 		}
1228 
1229 
1230 		// create a new vismap
1231 		if (vismap != NULL)
1232 		{
1233 			free(vismap);
1234 		}
1235 		vismap = (bool*) calloc(destmap->width * destmap->height, sizeof(bool));
1236 
1237 		// reset minimap
1238 		for ( x = 0; x < MINIMAP_MAX_DIMENSION; x++ )
1239 		{
1240 			for ( y = 0; y < MINIMAP_MAX_DIMENSION; y++ )
1241 			{
1242 				minimap[y][x] = 0;
1243 			}
1244 		}
1245 
1246 		// reset cameras
1247 		for (int c = 0; c < MAXPLAYERS; ++c) {
1248 			auto& camera = cameras[c];
1249 			if ( game )
1250 			{
1251 				camera.x = -32;
1252 				camera.y = -32;
1253 				camera.z = 0;
1254 				camera.ang = 3 * PI / 2;
1255 				camera.vang = 0;
1256 			}
1257 			else
1258 			{
1259 				camera.x = 2;
1260 				camera.y = 2;
1261 				camera.z = 0;
1262 				camera.ang = 0;
1263 				camera.vang = 0;
1264 			}
1265 		}
1266 
1267 		// shoparea
1268 		if ( shoparea )
1269 		{
1270 			free(shoparea);
1271 		}
1272 		shoparea = (bool*) malloc(sizeof(bool) * destmap->width * destmap->height);
1273 		for ( x = 0; x < destmap->width; x++ )
1274 			for ( y = 0; y < destmap->height; y++ )
1275 			{
1276 				shoparea[y + x * destmap->height] = false;
1277 			}
1278 	}
1279 
1280 	for ( c = 0; c < 512; c++ )
1281 	{
1282 		keystatus[c] = 0;
1283 	}
1284 
1285 
1286 	if ( checkMapHash != nullptr )
1287 	{
1288 		std::string mapShortName = filename2;
1289 		size_t found = mapShortName.rfind("/");
1290 		if ( found != std::string::npos )
1291 		{
1292 			mapShortName = mapShortName.substr(found + 1);
1293 			std::unordered_map<std::string, int>::iterator it;
1294 			it = mapHashes.find(mapShortName);
1295 			if ( it != mapHashes.end() && ((*it).second == mapHashData || (*it).second == -1) )
1296 			{
1297 				//printlog("MAP HASH SUCCESS");
1298 				*checkMapHash = 1;
1299 			}
1300 			else
1301 			{
1302 				printlog("Notice: Unable to verify map %s hash %d.", filename2, mapHashData);
1303 				*checkMapHash = 0;
1304 			}
1305 		}
1306 		else
1307 		{
1308 			size_t found2 = mapShortName.rfind("\\");
1309 			if ( found2 != std::string::npos )
1310 			{
1311 				mapShortName = mapShortName.substr(found2 + 1);
1312 				std::unordered_map<std::string, int>::iterator it;
1313 				it = mapHashes.find(mapShortName);
1314 				if ( it != mapHashes.end() && ((*it).second == mapHashData || (*it).second == -1) )
1315 				{
1316 					//printlog("MAP HASH SUCCESS");
1317 					*checkMapHash = 1;
1318 				}
1319 				else
1320 				{
1321 					printlog("Notice: Unable to verify map %s hash %d.", filename2, mapHashData);
1322 					*checkMapHash = 0;
1323 				}
1324 			}
1325 		}
1326 	}
1327 
1328 	return numentities;
1329 }
1330 
1331 /*-------------------------------------------------------------------------------
1332 
1333 	saveMap
1334 
1335 	Saves a map to the given filename
1336 
1337 -------------------------------------------------------------------------------*/
1338 
saveMap(const char * filename2)1339 int saveMap(const char* filename2)
1340 {
1341 	FILE* fp;
1342 	Uint32 numentities = 0;
1343 	node_t* node;
1344 	Entity* entity;
1345 	char filename[256];
1346 	Sint32 x, y;
1347 	Stat* myStats;
1348 
1349 	if ( filename2 != NULL && strcmp(filename2, "") )
1350 	{
1351 		if ( !PHYSFS_isInit() )
1352 		{
1353 			strcpy(filename, "maps/");
1354 			strcat(filename, filename2);
1355 		}
1356 		else
1357 		{
1358 			strcpy(filename, filename2);
1359 		}
1360 
1361 		if ( strstr(filename, ".lmp") == NULL )
1362 		{
1363 			strcat(filename, ".lmp");
1364 		}
1365 
1366 		if ((fp = openDataFile(filename, "wb")) == NULL)
1367 		{
1368 			printlog("warning: failed to open file '%s' for map saving!\n", filename);
1369 			return 1;
1370 		}
1371 
1372 		fwrite("BARONY LMPV2.6", sizeof(char), strlen("BARONY LMPV2.0"), fp); // magic code
1373 		fwrite(map.name, sizeof(char), 32, fp); // map filename
1374 		fwrite(map.author, sizeof(char), 32, fp); // map author
1375 		fwrite(&map.width, sizeof(Uint32), 1, fp); // map width
1376 		fwrite(&map.height, sizeof(Uint32), 1, fp); // map height
1377 		fwrite(&map.skybox, sizeof(Uint32), 1, fp); // map skybox
1378 		fwrite(map.flags, sizeof(Sint32), MAPFLAGS, fp); // map flags
1379 		fwrite(map.tiles, sizeof(Sint32), map.width * map.height * MAPLAYERS, fp);
1380 		for (node = map.entities->first; node != nullptr; node = node->next)
1381 		{
1382 			++numentities;
1383 		}
1384 		fwrite(&numentities, sizeof(Uint32), 1, fp); // number of entities on the map
1385 		for (node = map.entities->first; node != nullptr; node = node->next)
1386 		{
1387 			entity = (Entity*) node->element;
1388 			fwrite(&entity->sprite, sizeof(Sint32), 1, fp);
1389 
1390 			switch ( checkSpriteType(entity->sprite) )
1391 			{
1392 				case 1:
1393 					// monsters
1394 					myStats = entity->getStats();
1395 					fwrite(&myStats->sex, sizeof(sex_t), 1, fp);
1396 					fwrite(&myStats->name, sizeof(char[128]), 1, fp);
1397 					fwrite(&myStats->HP, sizeof(Sint32), 1, fp);
1398 					fwrite(&myStats->MAXHP, sizeof(Sint32), 1, fp);
1399 					fwrite(&myStats->OLDHP, sizeof(Sint32), 1, fp);
1400 					fwrite(&myStats->MP, sizeof(Sint32), 1, fp);
1401 					fwrite(&myStats->MAXMP, sizeof(Sint32), 1, fp);
1402 					fwrite(&myStats->STR, sizeof(Sint32), 1, fp);
1403 					fwrite(&myStats->DEX, sizeof(Sint32), 1, fp);
1404 					fwrite(&myStats->CON, sizeof(Sint32), 1, fp);
1405 					fwrite(&myStats->INT, sizeof(Sint32), 1, fp);
1406 					fwrite(&myStats->PER, sizeof(Sint32), 1, fp);
1407 					fwrite(&myStats->CHR, sizeof(Sint32), 1, fp);
1408 					fwrite(&myStats->LVL, sizeof(Sint32), 1, fp);
1409 					fwrite(&myStats->GOLD, sizeof(Sint32), 1, fp);
1410 
1411 					fwrite(&myStats->RANDOM_MAXHP, sizeof(Sint32), 1, fp);
1412 					fwrite(&myStats->RANDOM_HP, sizeof(Sint32), 1, fp);
1413 					fwrite(&myStats->RANDOM_MAXMP, sizeof(Sint32), 1, fp);
1414 					fwrite(&myStats->RANDOM_MP, sizeof(Sint32), 1, fp);
1415 					fwrite(&myStats->RANDOM_STR, sizeof(Sint32), 1, fp);
1416 					fwrite(&myStats->RANDOM_CON, sizeof(Sint32), 1, fp);
1417 					fwrite(&myStats->RANDOM_DEX, sizeof(Sint32), 1, fp);
1418 					fwrite(&myStats->RANDOM_INT, sizeof(Sint32), 1, fp);
1419 					fwrite(&myStats->RANDOM_PER, sizeof(Sint32), 1, fp);
1420 					fwrite(&myStats->RANDOM_CHR, sizeof(Sint32), 1, fp);
1421 					fwrite(&myStats->RANDOM_LVL, sizeof(Sint32), 1, fp);
1422 					fwrite(&myStats->RANDOM_GOLD, sizeof(Sint32), 1, fp);
1423 
1424 					fwrite(&myStats->EDITOR_ITEMS, sizeof(Sint32), ITEM_SLOT_NUM, fp);
1425 					fwrite(&myStats->MISC_FLAGS, sizeof(Sint32), 32, fp);
1426 					break;
1427 				case 2:
1428 					// chests
1429 					fwrite(&entity->yaw, sizeof(real_t), 1, fp);
1430 					fwrite(&entity->skill[9], sizeof(Sint32), 1, fp);
1431 					fwrite(&entity->chestLocked, sizeof(Sint32), 1, fp);
1432 					break;
1433 				case 3:
1434 					// items
1435 					fwrite(&entity->skill[10], sizeof(Sint32), 1, fp);
1436 					fwrite(&entity->skill[11], sizeof(Sint32), 1, fp);
1437 					fwrite(&entity->skill[12], sizeof(Sint32), 1, fp);
1438 					fwrite(&entity->skill[13], sizeof(Sint32), 1, fp);
1439 					fwrite(&entity->skill[15], sizeof(Sint32), 1, fp);
1440 					fwrite(&entity->skill[16], sizeof(Sint32), 1, fp);
1441 					break;
1442 				case 4:
1443 					fwrite(&entity->skill[0], sizeof(Sint32), 1, fp);
1444 					fwrite(&entity->skill[1], sizeof(Sint32), 1, fp);
1445 					fwrite(&entity->skill[2], sizeof(Sint32), 1, fp);
1446 					fwrite(&entity->skill[3], sizeof(Sint32), 1, fp);
1447 					fwrite(&entity->skill[4], sizeof(Sint32), 1, fp);
1448 					fwrite(&entity->skill[5], sizeof(Sint32), 1, fp);
1449 					break;
1450 				case 5:
1451 					fwrite(&entity->yaw, sizeof(real_t), 1, fp);
1452 					fwrite(&entity->crystalNumElectricityNodes, sizeof(Sint32), 1, fp);
1453 					fwrite(&entity->crystalTurnReverse, sizeof(Sint32), 1, fp);
1454 					fwrite(&entity->crystalSpellToActivate, sizeof(Sint32), 1, fp);
1455 					break;
1456 				case 6:
1457 					fwrite(&entity->leverTimerTicks, sizeof(Sint32), 1, fp);
1458 					break;
1459 				case 7:
1460 					fwrite(&entity->boulderTrapRefireAmount, sizeof(Sint32), 1, fp);
1461 					fwrite(&entity->boulderTrapRefireDelay, sizeof(Sint32), 1, fp);
1462 					fwrite(&entity->boulderTrapPreDelay, sizeof(Sint32), 1, fp);
1463 					break;
1464 				case 8:
1465 					fwrite(&entity->pedestalOrbType, sizeof(Sint32), 1, fp);
1466 					fwrite(&entity->pedestalHasOrb, sizeof(Sint32), 1, fp);
1467 					fwrite(&entity->pedestalInvertedPower, sizeof(Sint32), 1, fp);
1468 					fwrite(&entity->pedestalInGround, sizeof(Sint32), 1, fp);
1469 					fwrite(&entity->pedestalLockOrb, sizeof(Sint32), 1, fp);
1470 					break;
1471 				case 9:
1472 					fwrite(&entity->teleporterX, sizeof(Sint32), 1, fp);
1473 					fwrite(&entity->teleporterY, sizeof(Sint32), 1, fp);
1474 					fwrite(&entity->teleporterType, sizeof(Sint32), 1, fp);
1475 					break;
1476 				case 10:
1477 					fwrite(&entity->ceilingTileModel, sizeof(Sint32), 1, fp);
1478 					break;
1479 				case 11:
1480 					fwrite(&entity->spellTrapType, sizeof(Sint32), 1, fp);
1481 					fwrite(&entity->spellTrapRefire, sizeof(Sint32), 1, fp);
1482 					fwrite(&entity->spellTrapLatchPower, sizeof(Sint32), 1, fp);
1483 					fwrite(&entity->spellTrapFloorTile, sizeof(Sint32), 1, fp);
1484 					fwrite(&entity->spellTrapRefireRate, sizeof(Sint32), 1, fp);
1485 					break;
1486 				case 12:
1487 					fwrite(&entity->furnitureDir, sizeof(Sint32), 1, fp);
1488 					break;
1489 				case 13:
1490 					fwrite(&entity->floorDecorationModel, sizeof(Sint32), 1, fp);
1491 					fwrite(&entity->floorDecorationRotation, sizeof(Sint32), 1, fp);
1492 					fwrite(&entity->floorDecorationHeightOffset, sizeof(Sint32), 1, fp);
1493 					fwrite(&entity->floorDecorationXOffset, sizeof(Sint32), 1, fp);
1494 					fwrite(&entity->floorDecorationYOffset, sizeof(Sint32), 1, fp);
1495 					for ( int i = 8; i < 60; ++i )
1496 					{
1497 						fwrite(&entity->skill[i], sizeof(Sint32), 1, fp);
1498 					}
1499 					break;
1500 				case 14:
1501 					fwrite(&entity->soundSourceToPlay, sizeof(Sint32), 1, fp);
1502 					fwrite(&entity->soundSourceVolume, sizeof(Sint32), 1, fp);
1503 					fwrite(&entity->soundSourceLatchOn, sizeof(Sint32), 1, fp);
1504 					fwrite(&entity->soundSourceDelay, sizeof(Sint32), 1, fp);
1505 					fwrite(&entity->soundSourceOrigin, sizeof(Sint32), 1, fp);
1506 					break;
1507 				case 15:
1508 					fwrite(&entity->lightSourceAlwaysOn, sizeof(Sint32), 1, fp);
1509 					fwrite(&entity->lightSourceBrightness, sizeof(Sint32), 1, fp);
1510 					fwrite(&entity->lightSourceInvertPower, sizeof(Sint32), 1, fp);
1511 					fwrite(&entity->lightSourceLatchOn, sizeof(Sint32), 1, fp);
1512 					fwrite(&entity->lightSourceRadius, sizeof(Sint32), 1, fp);
1513 					fwrite(&entity->lightSourceFlicker, sizeof(Sint32), 1, fp);
1514 					fwrite(&entity->lightSourceDelay, sizeof(Sint32), 1, fp);
1515 					break;
1516 				case 16:
1517 				{
1518 					fwrite(&entity->textSourceColorRGB, sizeof(Sint32), 1, fp);
1519 					fwrite(&entity->textSourceVariables4W, sizeof(Sint32), 1, fp);
1520 					fwrite(&entity->textSourceDelay, sizeof(Sint32), 1, fp);
1521 					fwrite(&entity->textSourceIsScript, sizeof(Sint32), 1, fp);
1522 					for ( int i = 4; i < 60; ++i )
1523 					{
1524 						fwrite(&entity->skill[i], sizeof(Sint32), 1, fp);
1525 					}
1526 					break;
1527 				}
1528 				case 17:
1529 					fwrite(&entity->signalInputDirection, sizeof(Sint32), 1, fp);
1530 					fwrite(&entity->signalActivateDelay, sizeof(Sint32), 1, fp);
1531 					fwrite(&entity->signalTimerInterval, sizeof(Sint32), 1, fp);
1532 					fwrite(&entity->signalTimerRepeatCount, sizeof(Sint32), 1, fp);
1533 					fwrite(&entity->signalTimerLatchInput, sizeof(Sint32), 1, fp);
1534 					break;
1535 				case 18:
1536 					fwrite(&entity->portalCustomSprite, sizeof(Sint32), 1, fp);
1537 					fwrite(&entity->portalCustomSpriteAnimationFrames, sizeof(Sint32), 1, fp);
1538 					fwrite(&entity->portalCustomZOffset, sizeof(Sint32), 1, fp);
1539 					fwrite(&entity->portalCustomLevelsToJump, sizeof(Sint32), 1, fp);
1540 					fwrite(&entity->portalNotSecret, sizeof(Sint32), 1, fp);
1541 					fwrite(&entity->portalCustomRequiresPower, sizeof(Sint32), 1, fp);
1542 					for ( int i = 11; i <= 18; ++i )
1543 					{
1544 						fwrite(&entity->skill[i], sizeof(Sint32), 1, fp);
1545 					}
1546 					break;
1547 				case 19:
1548 					fwrite(&entity->furnitureDir, sizeof(Sint32), 1, fp);
1549 					fwrite(&entity->furnitureTableSpawnChairs, sizeof(Sint32), 1, fp);
1550 					fwrite(&entity->furnitureTableRandomItemChance, sizeof(Sint32), 1, fp);
1551 					break;
1552 				case 20:
1553 					fwrite(&entity->skill[11], sizeof(Sint32), 1, fp);
1554 					fwrite(&entity->skill[12], sizeof(Sint32), 1, fp);
1555 					fwrite(&entity->skill[15], sizeof(Sint32), 1, fp);
1556 					for ( int i = 40; i <= 52; ++i )
1557 					{
1558 						fwrite(&entity->skill[i], sizeof(Sint32), 1, fp);
1559 					}
1560 					break;
1561 				case 21:
1562 					fwrite(&entity->doorForceLockedUnlocked, sizeof(Sint32), 1, fp);
1563 					fwrite(&entity->doorDisableLockpicks, sizeof(Sint32), 1, fp);
1564 					fwrite(&entity->doorDisableOpening, sizeof(Sint32), 1, fp);
1565 					break;
1566 				case 22:
1567 					fwrite(&entity->gateDisableOpening, sizeof(Sint32), 1, fp);
1568 					break;
1569 				case 23:
1570 					fwrite(&entity->playerStartDir, sizeof(Sint32), 1, fp);
1571 					break;
1572 				default:
1573 					break;
1574 			}
1575 
1576 			x = entity->x;
1577 			y = entity->y;
1578 			fwrite(&x, sizeof(Sint32), 1, fp);
1579 			fwrite(&y, sizeof(Sint32), 1, fp);
1580 		}
1581 		fclose(fp);
1582 		return 0;
1583 	}
1584 	else
1585 	{
1586 		return 1;
1587 	}
1588 }
1589 
1590 /*-------------------------------------------------------------------------------
1591 
1592 	readFile
1593 
1594 	Simply reads the contents of an entire file into a char array
1595 
1596 -------------------------------------------------------------------------------*/
1597 
readFile(char * filename)1598 char* readFile(char* filename)
1599 {
1600 	char* file_contents = NULL;
1601 	long input_file_size;
1602 	FILE* input_file = openDataFile(filename, "rb");
1603 	if (!input_file) {
1604 		printlog("Open failed: %s", strerror(errno));
1605 		goto out_input_file;
1606 	}
1607 
1608 	if (fseek(input_file, 0, SEEK_END) != 0) {
1609 		printlog("Seek failed");
1610 		goto out_input_file;
1611 	}
1612 
1613 	if ((input_file_size = ftell(input_file)) == -1) {
1614 		printlog("ftell failed");
1615 		goto out_input_file;
1616 	}
1617 
1618 	if (input_file_size > (1<<30)) {
1619 		printlog("Unreasonable size: %ld", input_file_size);
1620 		goto out_input_file;
1621 	}
1622 
1623 	rewind(input_file);
1624 	file_contents = static_cast<char*>(malloc((input_file_size + 1) * sizeof(char)));
1625 	fread(file_contents, sizeof(char), input_file_size, input_file);
1626 	file_contents[input_file_size] = 0;
1627 
1628 out_input_file:
1629 	fclose(input_file);
1630 	return file_contents;
1631 }
1632 
1633 /*-------------------------------------------------------------------------------
1634 
1635 	directoryContents
1636 
1637 	Stores the contents of a directory in a list
1638 
1639 -------------------------------------------------------------------------------*/
1640 
directoryContents(const char * directory,bool includeSubdirectory,bool includeFiles)1641 std::list<std::string> directoryContents(const char* directory, bool includeSubdirectory, bool includeFiles)
1642 {
1643 	std::list<std::string> list;
1644 	char fullPath[PATH_MAX];
1645 	completePath(fullPath, directory);
1646 	DIR* dir = opendir(fullPath);
1647 	struct dirent* entry = NULL;
1648 
1649 	if ( !dir )
1650 	{
1651 		printlog( "[directoryContents()] Failed to open directory \"%s\".\n", directory);
1652 		return list;
1653 	}
1654 
1655 	struct stat cur;
1656 	char curPath[PATH_MAX];
1657 	while ((entry = readdir(dir)) != NULL)
1658 	{
1659 		strcpy(curPath, fullPath);
1660 		strcat(curPath, entry->d_name);
1661 
1662 		if (stat(curPath, &cur) != 0)
1663 		{
1664 			continue;
1665 		}
1666 		if ( includeFiles )
1667 		{
1668 			if ((cur.st_mode & S_IFMT) == S_IFREG)
1669 			{
1670 				list.push_back(entry->d_name);
1671 			}
1672 		}
1673 		if ( includeSubdirectory )
1674 		{
1675 			if ((cur.st_mode & S_IFMT) == S_IFDIR)
1676 			{
1677 				list.push_back(entry->d_name);
1678 			}
1679 		}
1680 	}
1681 
1682 	closedir(dir);
1683 
1684 	return list;
1685 }
1686 
getLinesFromDataFile(std::string filename)1687 std::vector<std::string> getLinesFromDataFile(std::string filename)
1688 {
1689 	std::vector<std::string> lines;
1690 	std::string filepath(datadir);
1691 	filepath += "/";
1692 	filepath += filename;
1693 	std::ifstream file(filepath);
1694 	if ( !file )
1695 	{
1696 		std::ifstream file(filename); // check absolute path.
1697 		if ( !file)
1698 		{
1699 			printlog("Error: Failed to open file \"%s\"", filename.c_str());
1700 			return lines;
1701 		}
1702 		else
1703 		{
1704 			std::string line;
1705 			while ( std::getline(file, line) )
1706 			{
1707 				if ( !line.empty() )
1708 				{
1709 					lines.push_back(line);
1710 				}
1711 			}
1712 			file.close();
1713 		}
1714 	}
1715 	else
1716 	{
1717 		std::string line;
1718 		while ( std::getline(file, line) )
1719 		{
1720 			if ( !line.empty() )
1721 			{
1722 				lines.push_back(line);
1723 			}
1724 		}
1725 		file.close();
1726 	}
1727 
1728 	return lines;
1729 }
1730 
physfsLoadMapFile(int levelToLoad,Uint32 seed,bool useRandSeed,int * checkMapHash)1731 int physfsLoadMapFile(int levelToLoad, Uint32 seed, bool useRandSeed, int* checkMapHash)
1732 {
1733 	std::string mapsDirectory; // store the full file path here.
1734 	std::string line = "";
1735 	if ( loadCustomNextMap.compare("") != 0 )
1736 	{
1737 		line = "map: " + loadCustomNextMap;
1738 		loadCustomNextMap = "";
1739 	}
1740 	else
1741 	{
1742 		if ( !secretlevel )
1743 		{
1744 			mapsDirectory = PHYSFS_getRealDir(LEVELSFILE);
1745 			mapsDirectory.append(PHYSFS_getDirSeparator()).append(LEVELSFILE);
1746 		}
1747 		else
1748 		{
1749 			mapsDirectory = PHYSFS_getRealDir(SECRETLEVELSFILE);
1750 			mapsDirectory.append(PHYSFS_getDirSeparator()).append(SECRETLEVELSFILE);
1751 		}
1752 		printlog("Maps directory: %s", mapsDirectory.c_str());
1753 		std::vector<std::string> levelsList = getLinesFromDataFile(mapsDirectory);
1754 		line = levelsList.front();
1755 		int levelsCounted = 0;
1756 		if ( levelToLoad > 0 ) // if level == 0, then load up the first map.
1757 		{
1758 			for ( std::vector<std::string>::const_iterator i = levelsList.begin(); i != levelsList.end() && levelsCounted <= levelToLoad; ++i )
1759 			{
1760 				// process i, iterate through all the map levels until currentlevel.
1761 				line = *i;
1762 				if ( line[0] == '\n' )
1763 				{
1764 					continue;
1765 				}
1766 				++levelsCounted;
1767 			}
1768 		}
1769 	}
1770 	std::size_t found = line.find(' ');
1771 	char tempstr[1024];
1772 	if ( found != std::string::npos )
1773 	{
1774 		std::string mapType = line.substr(0, found);
1775 		std::string mapName;
1776 		mapName = line.substr(found + 1, line.find('\n'));
1777 		std::size_t carriageReturn = mapName.find('\r');
1778 		if ( carriageReturn != std::string::npos )
1779 		{
1780 			mapName.erase(carriageReturn);
1781 			printlog("%s", mapName.c_str());
1782 		}
1783 		if ( mapType.compare("map:") == 0 )
1784 		{
1785 			strncpy(tempstr, mapName.c_str(), mapName.length());
1786 			tempstr[mapName.length()] = '\0';
1787 			mapName = physfsFormatMapName(tempstr);
1788 			if ( checkMapHash )
1789 			{
1790 				return loadMap(mapName.c_str(), &map, map.entities, map.creatures, checkMapHash);
1791 			}
1792 			else
1793 			{
1794 				return loadMap(mapName.c_str(), &map, map.entities, map.creatures);
1795 			}
1796 		}
1797 		else if ( mapType.compare("gen:") == 0 )
1798 		{
1799 			std::size_t secretChanceFound = mapName.find(" secret%: ");
1800 			std::size_t darkmapChanceFound = mapName.find(" darkmap%: ");
1801 			std::size_t minotaurChanceFound = mapName.find(" minotaur%: ");
1802 			std::size_t disableNormalExitFound = mapName.find(" noexit");
1803 			std::string parameterStr = "";
1804 			std::tuple<int, int, int, int> mapParameters = std::make_tuple(-1, -1, -1, 0);
1805 			if ( secretChanceFound != std::string::npos )
1806 			{
1807 				// found a percentage for secret levels to spawn.
1808 				parameterStr = mapName.substr(secretChanceFound + strlen(" secret%: "));
1809 				parameterStr = parameterStr.substr(0, parameterStr.find_first_of(" \0"));
1810 				std::get<LEVELPARAM_CHANCE_SECRET>(mapParameters) = std::stoi(parameterStr);
1811 				if ( std::get<LEVELPARAM_CHANCE_SECRET>(mapParameters) < 0 || std::get<LEVELPARAM_CHANCE_SECRET>(mapParameters) > 100 )
1812 				{
1813 					std::get<LEVELPARAM_CHANCE_SECRET>(mapParameters) = -1;
1814 				}
1815 			}
1816 			if ( darkmapChanceFound != std::string::npos )
1817 			{
1818 				// found a percentage for secret levels to spawn.
1819 				parameterStr = mapName.substr(darkmapChanceFound + strlen(" darkmap%: "));
1820 				parameterStr = parameterStr.substr(0, parameterStr.find_first_of(" \0"));
1821 				std::get<LEVELPARAM_CHANCE_DARKNESS>(mapParameters) = std::stoi(parameterStr);
1822 				if ( std::get<LEVELPARAM_CHANCE_DARKNESS>(mapParameters) < 0 || std::get<LEVELPARAM_CHANCE_DARKNESS>(mapParameters) > 100 )
1823 				{
1824 					std::get<LEVELPARAM_CHANCE_DARKNESS>(mapParameters) = -1;
1825 				}
1826 			}
1827 			if ( minotaurChanceFound != std::string::npos )
1828 			{
1829 				// found a percentage for secret levels to spawn.
1830 				parameterStr = mapName.substr(minotaurChanceFound + strlen(" minotaur%: "));
1831 				parameterStr = parameterStr.substr(0, parameterStr.find_first_of(" \0"));
1832 				std::get<LEVELPARAM_CHANCE_MINOTAUR>(mapParameters) = std::stoi(parameterStr);
1833 				if ( std::get<LEVELPARAM_CHANCE_MINOTAUR>(mapParameters) < 0 || std::get<LEVELPARAM_CHANCE_MINOTAUR>(mapParameters) > 100 )
1834 				{
1835 					std::get<LEVELPARAM_CHANCE_MINOTAUR>(mapParameters) = -1;
1836 				}
1837 			}
1838 			if ( disableNormalExitFound != std::string::npos )
1839 			{
1840 				std::get<LEVELPARAM_DISABLE_NORMAL_EXIT>(mapParameters) = 1;
1841 			}
1842 			mapName = mapName.substr(0, mapName.find_first_of(" \0"));
1843 
1844 			strncpy(tempstr, mapName.c_str(), mapName.length());
1845 			tempstr[mapName.length()] = '\0';
1846 			if ( useRandSeed )
1847 			{
1848 				return generateDungeon(tempstr, rand(), mapParameters);
1849 			}
1850 			else
1851 			{
1852 				return generateDungeon(tempstr, seed, mapParameters);
1853 			}
1854 		}
1855 		//printlog("%s", mapName.c_str());
1856 	}
1857 	return 0;
1858 }
1859 
physfsGetFileNamesInDirectory(const char * dir)1860 std::list<std::string> physfsGetFileNamesInDirectory(const char* dir)
1861 {
1862 	std::list<std::string> filenames;
1863 	char **rc = PHYSFS_enumerateFiles(dir);
1864 	if ( *rc == NULL )
1865 	{
1866 		printlog("[PhysFS]: Error: Failed to enumerate filenames in directory '%s'", dir);
1867 		return filenames;
1868 	}
1869 	char **i;
1870 	std::string file;
1871 	for ( i = rc; *i != NULL; i++ )
1872 	{
1873 		file = *i;
1874 		//printlog(" * We've got [%s].\n", file.c_str());
1875 		filenames.push_back(file);
1876 	}
1877 	PHYSFS_freeList(rc);
1878 	return filenames;
1879 }
1880 
physfsFormatMapName(char const * const levelfilename)1881 std::string physfsFormatMapName(char const * const levelfilename)
1882 {
1883 	std::string fullMapPath;
1884 	std::string mapFileName = "maps/";
1885 	mapFileName.append(levelfilename);
1886 	if ( mapFileName.find(".lmp") == std::string::npos )
1887 	{
1888 		mapFileName.append(".lmp");
1889 	}
1890 	//printlog("format map name: %s", mapFileName.c_str());
1891 	if ( PHYSFS_getRealDir(mapFileName.c_str()) != NULL )
1892 	{
1893 		//printlog("format map name: %s", mapFileName.c_str());
1894 		fullMapPath = PHYSFS_getRealDir(mapFileName.c_str());
1895 		fullMapPath.append(PHYSFS_getDirSeparator()).append(mapFileName);
1896 	}
1897 	return fullMapPath;
1898 }
1899 
physfsSearchModelsToUpdate()1900 bool physfsSearchModelsToUpdate()
1901 {
1902 	std::string modelsDirectory = PHYSFS_getRealDir("models/models.txt");
1903 	modelsDirectory.append(PHYSFS_getDirSeparator()).append("models/models.txt");
1904 	FILE* fp = openDataFile(modelsDirectory.c_str(), "r");
1905 	char name[128];
1906 
1907 	for ( int c = 0; !feof(fp); c++ )
1908 	{
1909 		fscanf(fp, "%s", name);
1910 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
1911 		{
1912 			break;
1913 		}
1914 
1915 		if ( PHYSFS_getRealDir(name) != NULL )
1916 		{
1917 			std::string modelRealDir = PHYSFS_getRealDir(name);
1918 			if ( modelRealDir.compare("./") != 0 )
1919 			{
1920 				fclose(fp);
1921 				return true;
1922 			}
1923 		}
1924 	}
1925 	fclose(fp);
1926 	return false;
1927 }
1928 
physfsModelIndexUpdate(int & start,int & end,bool freePreviousModels)1929 bool physfsModelIndexUpdate(int &start, int &end, bool freePreviousModels)
1930 {
1931 	std::string modelsDirectory = PHYSFS_getRealDir("models/models.txt");
1932 	char modelName[128];
1933 	int startnum = 0;
1934 	int endnum = nummodels;
1935 	modelsDirectory.append(PHYSFS_getDirSeparator()).append("models/models.txt");
1936 	FILE *fp = openDataFile(modelsDirectory.c_str(), "r");
1937 	for ( int c = 0; !feof(fp); c++ )
1938 	{
1939 		fscanf(fp, "%s", modelName);
1940 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
1941 		{
1942 			break;
1943 		}
1944 
1945 		bool modelHasBeenModified = false;
1946 		// has this model index been modified?
1947 		std::vector<int>::iterator it = gamemods_modelsListModifiedIndexes.end();
1948 		if ( !gamemods_modelsListModifiedIndexes.empty() )
1949 		{
1950 			it = std::find(gamemods_modelsListModifiedIndexes.begin(),
1951 				gamemods_modelsListModifiedIndexes.end(), c);
1952 			if ( it != gamemods_modelsListModifiedIndexes.end() )
1953 			{
1954 				modelHasBeenModified = true; // found the model in the vector.
1955 			}
1956 		}
1957 
1958 		std::string modelPath = PHYSFS_getRealDir(modelName);
1959 		if ( modelHasBeenModified || modelPath.compare("./") != 0 )
1960 		{
1961 			if ( !modelHasBeenModified )
1962 			{
1963 				// add this model index to say we've modified it as the base dir is not default.
1964 				gamemods_modelsListModifiedIndexes.push_back(c);
1965 			}
1966 			else
1967 			{
1968 				if ( modelPath.compare("./") == 0 )
1969 				{
1970 					// model returned to base directory, remove from the modified index list.
1971 					gamemods_modelsListModifiedIndexes.erase(it);
1972 				}
1973 			}
1974 
1975 			if ( c < nummodels )
1976 			{
1977 				if ( models[c] != NULL )
1978 				{
1979 					if ( models[c]->data )
1980 					{
1981 						free(models[c]->data);
1982 					}
1983 					free(models[c]);
1984 				}
1985 			}
1986 			else
1987 			{
1988 				printlog("[PhysFS]: WARNING: Loading a new model: %d outside normal nummodels: %d range - Need special handling case to free model after use", c, nummodels);
1989 			}
1990 			models[c] = loadVoxel(modelName);
1991 
1992 			// this index is not found in the normal models folder.
1993 			// store the lowest found model number inside startnum.
1994 			if ( startnum == 0 || c < startnum )
1995 			{
1996 				startnum = c;
1997 			}
1998 
1999 			// store the higher end model num in endnum.
2000 			if ( endnum == nummodels )
2001 			{
2002 				endnum = c + 1;
2003 			}
2004 			else if ( c + 1 > endnum )
2005 			{
2006 				endnum = c + 1;
2007 			}
2008 		}
2009 	}
2010 	if ( startnum == endnum )
2011 	{
2012 		endnum = std::min(static_cast<int>(nummodels), endnum + 1); // if both indices are the same, then models won't load.
2013 	}
2014 	printlog("[PhysFS]: Models file not in default directory... reloading models from index %d to %d\n", startnum, endnum);
2015 	start = startnum;
2016 	end = endnum;
2017 
2018 	// now free polymodels as we'll be loading them up later.
2019 	if ( freePreviousModels )
2020 	{
2021 		for ( int c = std::max(1, start); c < end && c < nummodels; ++c )
2022 		{
2023 			// cannot free index 0 - null object
2024 			if ( polymodels[c].faces )
2025 			{
2026 				free(polymodels[c].faces);
2027 			}
2028 			if ( polymodels[c].vbo )
2029 			{
2030 				SDL_glDeleteBuffers(1, &polymodels[c].vbo);
2031 			}
2032 			if ( polymodels[c].colors )
2033 			{
2034 				SDL_glDeleteBuffers(1, &polymodels[c].colors);
2035 			}
2036 			if ( polymodels[c].va )
2037 			{
2038 				SDL_glDeleteVertexArrays(1, &polymodels[c].va);
2039 			}
2040 			if ( polymodels[c].colors_shifted )
2041 			{
2042 				SDL_glDeleteBuffers(1, &polymodels[c].colors_shifted);
2043 			}
2044 		}
2045 	}
2046 
2047 	fclose(fp);
2048 	return true;
2049 }
2050 
physfsSearchSoundsToUpdate()2051 bool physfsSearchSoundsToUpdate()
2052 {
2053 	if ( no_sound )
2054 	{
2055 		return false;
2056 	}
2057 	std::string soundsDirectory = PHYSFS_getRealDir("sound/sounds.txt");
2058 	if ( soundsDirectory.compare("./") != 0 )
2059 	{
2060 		return true;
2061 	}
2062 	soundsDirectory.append(PHYSFS_getDirSeparator()).append("sound/sounds.txt");
2063 	FILE* fp = openDataFile(soundsDirectory.c_str(), "r");
2064 	char name[128];
2065 
2066 	for ( int c = 0; !feof(fp); c++ )
2067 	{
2068 		fscanf(fp, "%s", name);
2069 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
2070 		{
2071 			break;
2072 		}
2073 
2074 		if ( PHYSFS_getRealDir(name) != NULL )
2075 		{
2076 			std::string soundRealDir = PHYSFS_getRealDir(name);
2077 			if ( soundRealDir.compare("./") != 0 )
2078 			{
2079 				fclose(fp);
2080 				return true;
2081 			}
2082 		}
2083 	}
2084 	fclose(fp);
2085 	return false;
2086 }
2087 
physfsReloadSounds(bool reloadAll)2088 void physfsReloadSounds(bool reloadAll)
2089 {
2090 	if ( no_sound )
2091 	{
2092 		return;
2093 	}
2094 	std::string soundsDirectory = PHYSFS_getRealDir("sound/sounds.txt");
2095 	soundsDirectory.append(PHYSFS_getDirSeparator()).append("sound/sounds.txt");
2096 	FILE* fp = openDataFile(soundsDirectory.c_str(), "r");
2097 	char name[128];
2098 
2099 	printlog("freeing sounds and loading modded sounds...\n");
2100 	if ( reloadAll )
2101 	{
2102 #ifdef SOUND
2103 		if ( sounds != NULL )
2104 		{
2105 			for ( int c = 0; c < numsounds; c++ )
2106 			{
2107 				if ( sounds[c] != NULL )
2108 				{
2109 #ifdef USE_FMOD
2110 					FMOD_Sound_Release(sounds[c]);    //Free the sound in FMOD
2111 #endif
2112 #ifdef USE_OPENAL
2113 					OPENAL_Sound_Release(sounds[c]); //Free the sound in OPENAL
2114 #endif
2115 				}
2116 			}
2117 		}
2118 #endif
2119 	}
2120 
2121 	for ( int c = 0; !feof(fp); c++ )
2122 	{
2123 		fscanf(fp, "%s", name);
2124 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
2125 		{
2126 			break;
2127 		}
2128 
2129 		if ( PHYSFS_getRealDir(name) != NULL )
2130 		{
2131 			std::string soundRealDir = PHYSFS_getRealDir(name);
2132 			if ( reloadAll || soundRealDir.compare("./") != 0 )
2133 			{
2134 				std::string soundFile = soundRealDir;
2135 				soundFile.append(PHYSFS_getDirSeparator()).append(name);
2136 #ifdef USE_FMOD
2137 				if ( !reloadAll )
2138 				{
2139 					FMOD_Sound_Release(sounds[c]);
2140 				}
2141 				fmod_result = FMOD_System_CreateSound(fmod_system, soundFile.c_str(), (FMOD_MODE)(FMOD_SOFTWARE | FMOD_3D), NULL, &sounds[c]);
2142 				if ( FMODErrorCheck() )
2143 				{
2144 					printlog("warning: failed to load '%s' listed at line %d in sounds.txt\n", name, c + 1);
2145 				}
2146 #endif
2147 #ifdef USE_OPENAL
2148 				if ( !reloadAll )
2149 				{
2150 					OPENAL_Sound_Release(sounds[c]);
2151 				}
2152 				OPENAL_CreateSound(soundFile.c_str(), true, &sounds[c]);
2153 #endif
2154 			}
2155 		}
2156 	}
2157 	fclose(fp);
2158 }
2159 
physfsSearchSpritesToUpdate()2160 bool physfsSearchSpritesToUpdate()
2161 {
2162 	std::string spritesDirectory = PHYSFS_getRealDir("images/sprites.txt");
2163 	spritesDirectory.append(PHYSFS_getDirSeparator()).append("images/sprites.txt");
2164 	FILE* fp = openDataFile(spritesDirectory.c_str(), "r");
2165 	char name[128];
2166 
2167 	for ( int c = 0; !feof(fp); c++ )
2168 	{
2169 		fscanf(fp, "%s", name);
2170 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
2171 		{
2172 			break;
2173 		}
2174 
2175 		if ( PHYSFS_getRealDir(name) != NULL )
2176 		{
2177 			std::string spritesRealDir = PHYSFS_getRealDir(name);
2178 			if ( spritesRealDir.compare("./") != 0 )
2179 			{
2180 				fclose(fp);
2181 				printlog("[PhysFS]: Found modified sprite in sprites/ directory, reloading all sprites...");
2182 				return true;
2183 			}
2184 		}
2185 	}
2186 	fclose(fp);
2187 	return false;
2188 }
2189 
physfsReloadSprites(bool reloadAll)2190 void physfsReloadSprites(bool reloadAll)
2191 {
2192 	std::string spritesDirectory = PHYSFS_getRealDir("images/sprites.txt");
2193 	spritesDirectory.append(PHYSFS_getDirSeparator()).append("images/sprites.txt");
2194 	printlog("[PhysFS]: Loading sprites from directory %s...\n", spritesDirectory.c_str());
2195 	FILE* fp = openDataFile(spritesDirectory.c_str(), "r");
2196 	char name[128];
2197 
2198 	for ( int c = 0; !feof(fp); c++ )
2199 	{
2200 		fscanf(fp, "%s", name);
2201 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
2202 		{
2203 			break;
2204 		}
2205 		if ( PHYSFS_getRealDir(name) != NULL )
2206 		{
2207 			std::string spritesRealDir = PHYSFS_getRealDir(name);
2208 			if ( reloadAll || spritesRealDir.compare("./") != 0 )
2209 			{
2210 				std::string spriteFile = spritesRealDir;
2211 				spriteFile.append(PHYSFS_getDirSeparator()).append(name);
2212 				if ( sprites[c] )
2213 				{
2214 					SDL_FreeSurface(sprites[c]);
2215 				}
2216 				char fullname[128];
2217 				strncpy(fullname, spriteFile.c_str(), 127);
2218 				sprites[c] = loadImage(fullname);
2219 				if ( sprites[c] != NULL )
2220 				{
2221 				}
2222 				else
2223 				{
2224 					printlog("warning: failed to load '%s' listed at line %d in %s\n", name, c + 1, spritesDirectory.c_str());
2225 					if ( c == 0 )
2226 					{
2227 						printlog("sprite 0 cannot be NULL!\n");
2228 						fclose(fp);
2229 						return;
2230 					}
2231 				}
2232 			}
2233 		}
2234 	}
2235 	fclose(fp);
2236 }
2237 
physfsSearchTilesToUpdate()2238 bool physfsSearchTilesToUpdate()
2239 {
2240 	std::string tilesDirectory = PHYSFS_getRealDir("images/tiles.txt");
2241 	tilesDirectory.append(PHYSFS_getDirSeparator()).append("images/tiles.txt");
2242 	FILE* fp = openDataFile(tilesDirectory.c_str(), "r");
2243 	char name[128];
2244 
2245 	for ( int c = 0; !feof(fp); c++ )
2246 	{
2247 		fscanf(fp, "%s", name);
2248 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
2249 		{
2250 			break;
2251 		}
2252 
2253 		if ( PHYSFS_getRealDir(name) != NULL )
2254 		{
2255 			std::string tileRealDir = PHYSFS_getRealDir(name);
2256 			if ( tileRealDir.compare("./") != 0 )
2257 			{
2258 				fclose(fp);
2259 				printlog("[PhysFS]: Found modified tile in tiles/ directory, reloading all tiles...");
2260 				return true;
2261 			}
2262 		}
2263 	}
2264 	fclose(fp);
2265 	return false;
2266 }
2267 
physfsReloadTiles(bool reloadAll)2268 void physfsReloadTiles(bool reloadAll)
2269 {
2270 	std::string tilesDirectory = PHYSFS_getRealDir("images/tiles.txt");
2271 	tilesDirectory.append(PHYSFS_getDirSeparator()).append("images/tiles.txt");
2272 	printlog("[PhysFS]: Loading tiles from directory %s...\n", tilesDirectory.c_str());
2273 	FILE* fp = openDataFile(tilesDirectory.c_str(), "r");
2274 	char name[128];
2275 
2276 	for ( int c = 0; !feof(fp); c++ )
2277 	{
2278 		fscanf(fp, "%s", name);
2279 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
2280 		{
2281 			break;
2282 		}
2283 		if ( PHYSFS_getRealDir(name) != NULL )
2284 		{
2285 			std::string tileRealDir = PHYSFS_getRealDir(name);
2286 			if ( reloadAll || tileRealDir.compare("./") != 0 )
2287 			{
2288 				std::string tileFile = tileRealDir;
2289 				tileFile.append(PHYSFS_getDirSeparator()).append(name);
2290 				if ( tiles[c] )
2291 				{
2292 					SDL_FreeSurface(tiles[c]);
2293 				}
2294 				char fullname[128];
2295 				strncpy(fullname, tileFile.c_str(), 127);
2296 				tiles[c] = loadImage(fullname);
2297 				animatedtiles[c] = false;
2298 				lavatiles[c] = false;
2299 				swimmingtiles[c] = false;
2300 				if ( tiles[c] != NULL )
2301 				{
2302 					size_t found = tileFile.find(".png");
2303 					if ( found != string::npos && found != 0 )
2304 					{
2305 						if ( tileFile.at(found - 1) >= '0' && tileFile.at(found - 1) <= '9' )
2306 						{
2307 							// animated tiles if the tile name ends in a number 0-9.
2308 							animatedtiles[c] = true;
2309 						}
2310 					}
2311 					if ( strstr(name, "Lava") || strstr(name, "lava") )
2312 					{
2313 						lavatiles[c] = true;
2314 					}
2315 					if ( strstr(name, "Water") || strstr(name, "water") || strstr(name, "swimtile") || strstr(name, "Swimtile") )
2316 					{
2317 						swimmingtiles[c] = true;
2318 					}
2319 				}
2320 				else
2321 				{
2322 					printlog("warning: failed to load '%s' listed at line %d in %s\n", name, c + 1, tilesDirectory.c_str());
2323 					if ( c == 0 )
2324 					{
2325 						printlog("tile 0 cannot be NULL!\n");
2326 						fclose(fp);
2327 						return;
2328 					}
2329 				}
2330 			}
2331 		}
2332 	}
2333 	fclose(fp);
2334 }
2335 
physfsIsMapLevelListModded()2336 bool physfsIsMapLevelListModded()
2337 {
2338 	std::string mapsDirectory = PHYSFS_getRealDir(LEVELSFILE);
2339 	if ( mapsDirectory.compare("./") != 0 )
2340 	{
2341 		//return true;
2342 	}
2343 	mapsDirectory.append(PHYSFS_getDirSeparator()).append(LEVELSFILE);
2344 
2345 	std::vector<std::string> levelsList = getLinesFromDataFile(mapsDirectory);
2346 	if ( levelsList.empty() )
2347 	{
2348 		return false;
2349 	}
2350 	std::string line = levelsList.front();
2351 	int levelsCounted = 0;
2352 	for ( std::vector<std::string>::const_iterator i = levelsList.begin(); i != levelsList.end(); ++i )
2353 	{
2354 		// process i, iterate through all the map levels until currentlevel.
2355 		line = *i;
2356 		if ( line[0] == '\n' )
2357 		{
2358 			continue;
2359 		}
2360 		std::size_t found = line.find(' ');
2361 		char tempstr[1024];
2362 		if ( found != std::string::npos )
2363 		{
2364 			std::string mapType = line.substr(0, found);
2365 			std::string mapName;
2366 			mapName = line.substr(found + 1, line.find('\n'));
2367 			std::size_t carriageReturn = mapName.find('\r');
2368 			if ( carriageReturn != std::string::npos )
2369 			{
2370 				mapName.erase(carriageReturn);
2371 			}
2372 			mapName = mapName.substr(0, mapName.find_first_of(" \0"));
2373 			if ( mapName.compare(officialLevelsTxtOrder.at(levelsCounted)) != 0 )
2374 			{
2375 				return true;
2376 			}
2377 			mapName = "maps/" + mapName + ".lmp";
2378 			//printlog("%s", mapName.c_str());
2379 			if ( PHYSFS_getRealDir(mapName.c_str()) != NULL )
2380 			{
2381 				mapsDirectory = PHYSFS_getRealDir(mapName.c_str());
2382 				if ( mapsDirectory.compare("./") != 0 )
2383 				{
2384 					return true;
2385 				}
2386 			}
2387 		}
2388 		++levelsCounted;
2389 	}
2390 
2391 	mapsDirectory = PHYSFS_getRealDir(SECRETLEVELSFILE);
2392 	if ( mapsDirectory.compare("./") != 0 )
2393 	{
2394 		//return true;
2395 	}
2396 	mapsDirectory.append(PHYSFS_getDirSeparator()).append(SECRETLEVELSFILE);
2397 
2398 	levelsList = getLinesFromDataFile(mapsDirectory);
2399 	if ( levelsList.empty() )
2400 	{
2401 		return false;
2402 	}
2403 	line = levelsList.front();
2404 	levelsCounted = 0;
2405 	for ( std::vector<std::string>::const_iterator i = levelsList.begin(); i != levelsList.end(); ++i )
2406 	{
2407 		// process i, iterate through all the map levels until currentlevel.
2408 		line = *i;
2409 		if ( line[0] == '\n' )
2410 		{
2411 			continue;
2412 		}
2413 		std::size_t found = line.find(' ');
2414 		char tempstr[1024];
2415 		if ( found != std::string::npos )
2416 		{
2417 			std::string mapType = line.substr(0, found);
2418 			std::string mapName;
2419 			mapName = line.substr(found + 1, line.find('\n'));
2420 			std::size_t carriageReturn = mapName.find('\r');
2421 			if ( carriageReturn != std::string::npos )
2422 			{
2423 				mapName.erase(carriageReturn);
2424 			}
2425 			mapName = mapName.substr(0, mapName.find_first_of(" \0"));
2426 			if ( mapName.compare(officialSecretlevelsTxtOrder.at(levelsCounted)) != 0 )
2427 			{
2428 				return true;
2429 			}
2430 			mapName = "maps/" + mapName + ".lmp";
2431 			//printlog("%s", mapName.c_str());
2432 			if ( PHYSFS_getRealDir(mapName.c_str()) != NULL )
2433 			{
2434 				mapsDirectory = PHYSFS_getRealDir(mapName.c_str());
2435 				if ( mapsDirectory.compare("./") != 0 )
2436 				{
2437 					return true;
2438 				}
2439 			}
2440 		}
2441 		++levelsCounted;
2442 	}
2443 	return false;
2444 }
2445 
physfsSearchItemSpritesToUpdate()2446 bool physfsSearchItemSpritesToUpdate()
2447 {
2448 	for ( int c = 0; c < NUMITEMS; ++c )
2449 	{
2450 		for ( int x = 0; x < list_Size(&items[c].images); x++ )
2451 		{
2452 			node_t* node = list_Node(&items[c].images, x);
2453 			string_t* string = (string_t*)node->element;
2454 			std::string itemImgDir;
2455 			if ( PHYSFS_getRealDir(string->data) != NULL )
2456 			{
2457 				itemImgDir = PHYSFS_getRealDir(string->data);
2458 				if ( itemImgDir.compare("./") != 0 )
2459 				{
2460 					printlog("[PhysFS]: Found modified item sprite in items/items.txt file, reloading all item sprites...");
2461 					return true;
2462 				}
2463 			}
2464 		}
2465 	}
2466 	return false;
2467 }
2468 
physfsReloadItemSprites(bool reloadAll)2469 void physfsReloadItemSprites(bool reloadAll)
2470 {
2471 	for ( int c = 0; c < NUMITEMS; ++c )
2472 	{
2473 		bool reloadImg = reloadAll;
2474 		if ( !reloadAll )
2475 		{
2476 			for ( int x = 0; x < list_Size(&items[c].images); x++ )
2477 			{
2478 				node_t* node = list_Node(&items[c].images, x);
2479 				string_t* string = (string_t*)node->element;
2480 				std::string itemImgDir;
2481 				if ( PHYSFS_getRealDir(string->data) != NULL )
2482 				{
2483 					itemImgDir = PHYSFS_getRealDir(string->data);
2484 					if ( itemImgDir.compare("./") != 0 )
2485 					{
2486 						reloadImg = true;
2487 					}
2488 				}
2489 			}
2490 		}
2491 		if ( reloadImg )
2492 		{
2493 			// free the image data.
2494 			//list_FreeAll(&items[c].images);
2495 			node_t* node, *nextnode;
2496 			for ( node = items[c].surfaces.first; node != NULL; node = nextnode )
2497 			{
2498 				nextnode = node->next;
2499 				SDL_Surface** surface = (SDL_Surface**)node->element;
2500 				if ( surface )
2501 				{
2502 					if ( *surface )
2503 					{
2504 						SDL_FreeSurface(*surface);
2505 					}
2506 				}
2507 			}
2508 			list_FreeAll(&items[c].surfaces);
2509 
2510 			// now reload the image data.
2511 			for ( int x = 0; x < list_Size(&items[c].images); x++ )
2512 			{
2513 				SDL_Surface** surface = (SDL_Surface**)malloc(sizeof(SDL_Surface*));
2514 				node_t* node = list_AddNodeLast(&items[c].surfaces);
2515 				node->element = surface;
2516 				node->deconstructor = &defaultDeconstructor;
2517 				node->size = sizeof(SDL_Surface*);
2518 
2519 				node_t* node2 = list_Node(&items[c].images, x);
2520 				string_t* string = (string_t*)node2->element;
2521 				std::string itemImgDir;
2522 				if ( PHYSFS_getRealDir(string->data) != NULL )
2523 				{
2524 					itemImgDir = PHYSFS_getRealDir(string->data);
2525 					itemImgDir.append(PHYSFS_getDirSeparator()).append(string->data);
2526 				}
2527 				else
2528 				{
2529 					itemImgDir = string->data;
2530 				}
2531 				char imgFileChar[256];
2532 				strncpy(imgFileChar, itemImgDir.c_str(), 255);
2533 				*surface = loadImage(imgFileChar);
2534 			}
2535 		}
2536 	}
2537 }
2538 
physfsSearchItemsTxtToUpdate()2539 bool physfsSearchItemsTxtToUpdate()
2540 {
2541 	std::string itemsTxtDirectory = PHYSFS_getRealDir("items/items.txt");
2542 	if ( itemsTxtDirectory.compare("./") != 0 )
2543 	{
2544 		printlog("[PhysFS]: Found modified items/items.txt file, reloading all item information...");
2545 		return true;
2546 	}
2547 	return false;
2548 }
2549 
physfsSearchItemsGlobalTxtToUpdate()2550 bool physfsSearchItemsGlobalTxtToUpdate()
2551 {
2552 	std::string itemsTxtDirectory = PHYSFS_getRealDir("items/items_global.txt");
2553 	if ( itemsTxtDirectory.compare("./") != 0 )
2554 	{
2555 		printlog("[PhysFS]: Found modified items/items_global.txt file, reloading item spawn levels...");
2556 		return true;
2557 	}
2558 	return false;
2559 }
2560 
physfsReloadItemsTxt()2561 void physfsReloadItemsTxt()
2562 {
2563 	std::string itemsTxtDirectory = PHYSFS_getRealDir("items/items.txt");
2564 	itemsTxtDirectory.append(PHYSFS_getDirSeparator()).append("items/items.txt");
2565 	FILE* fp = openDataFile(itemsTxtDirectory.c_str(), "r");
2566 	char buffer[128];
2567 
2568 	for ( int c = 0; !feof(fp) && c < NUMITEMS; ++c )
2569 	{
2570 		//if ( c > ARTIFACT_BOW )
2571 		//{
2572 		//	int newItems = c - ARTIFACT_BOW - 1;
2573 		//	items[c].name_identified = language[2200 + newItems * 2];
2574 		//	items[c].name_unidentified = language[2201 + newItems * 2];
2575 		//}
2576 		//else
2577 		//{
2578 		//	items[c].name_identified = language[1545 + c * 2];
2579 		//	items[c].name_unidentified = language[1546 + c * 2];
2580 		//}
2581 		fscanf(fp, "%d", &items[c].index);
2582 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
2583 		{
2584 			break;
2585 		}
2586 		fscanf(fp, "%d", &items[c].fpindex);
2587 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
2588 		{
2589 			break;
2590 		}
2591 		fscanf(fp, "%d", &items[c].variations);
2592 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
2593 		{
2594 			break;
2595 		}
2596 		fscanf(fp, "%s", buffer);
2597 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
2598 		{
2599 			break;
2600 		}
2601 		if ( !strcmp(buffer, "WEAPON") )
2602 		{
2603 			items[c].category = WEAPON;
2604 		}
2605 		else if ( !strcmp(buffer, "ARMOR") )
2606 		{
2607 			items[c].category = ARMOR;
2608 		}
2609 		else if ( !strcmp(buffer, "AMULET") )
2610 		{
2611 			items[c].category = AMULET;
2612 		}
2613 		else if ( !strcmp(buffer, "POTION") )
2614 		{
2615 			items[c].category = POTION;
2616 		}
2617 		else if ( !strcmp(buffer, "SCROLL") )
2618 		{
2619 			items[c].category = SCROLL;
2620 		}
2621 		else if ( !strcmp(buffer, "MAGICSTAFF") )
2622 		{
2623 			items[c].category = MAGICSTAFF;
2624 		}
2625 		else if ( !strcmp(buffer, "RING") )
2626 		{
2627 			items[c].category = RING;
2628 		}
2629 		else if ( !strcmp(buffer, "SPELLBOOK") )
2630 		{
2631 			items[c].category = SPELLBOOK;
2632 		}
2633 		else if ( !strcmp(buffer, "TOOL") )
2634 		{
2635 			items[c].category = TOOL;
2636 		}
2637 		else if ( !strcmp(buffer, "FOOD") )
2638 		{
2639 			items[c].category = FOOD;
2640 		}
2641 		else if ( !strcmp(buffer, "BOOK") )
2642 		{
2643 			items[c].category = BOOK;
2644 		}
2645 		else if ( !strcmp(buffer, "THROWN") )
2646 		{
2647 			items[c].category = THROWN;
2648 		}
2649 		else if ( !strcmp(buffer, "SPELL_CAT") )
2650 		{
2651 			items[c].category = SPELL_CAT;
2652 		}
2653 		else
2654 		{
2655 			items[c].category = GEM;
2656 		}
2657 		fscanf(fp, "%d", &items[c].weight);
2658 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
2659 		{
2660 			break;
2661 		}
2662 		fscanf(fp, "%d", &items[c].value);
2663 		while ( fgetc(fp) != '\n' ) if ( feof(fp) )
2664 		{
2665 			break;
2666 		}
2667 
2668 		list_FreeAll(&items[c].images);
2669 
2670 		while ( 1 )
2671 		{
2672 			string_t* string = (string_t*)malloc(sizeof(string_t));
2673 			string->data = (char*)malloc(sizeof(char) * 64);
2674 			string->lines = 1;
2675 
2676 			node_t* node = list_AddNodeLast(&items[c].images);
2677 			node->element = string;
2678 			node->deconstructor = &stringDeconstructor;
2679 			node->size = sizeof(string_t);
2680 			string->node = node;
2681 
2682 			int x = 0;
2683 			bool fileend = false;
2684 			while ( (string->data[x] = fgetc(fp)) != '\n' )
2685 			{
2686 				if ( feof(fp) )
2687 				{
2688 					fileend = true;
2689 					break;
2690 				}
2691 				x++;
2692 			}
2693 			if ( x == 0 || fileend )
2694 			{
2695 				list_RemoveNode(node);
2696 				break;
2697 			}
2698 			string->data[x] = 0;
2699 		}
2700 	}
2701 
2702 	fclose(fp);
2703 }
2704 
physfsSearchMonsterLimbFilesToUpdate()2705 bool physfsSearchMonsterLimbFilesToUpdate()
2706 {
2707 	bool requiresUpdate = false;
2708 	for ( int c = 1; c < NUMMONSTERS; c++ )
2709 	{
2710 		char filename[256];
2711 		strcpy(filename, "models/creatures/");
2712 		strcat(filename, monstertypename[c]);
2713 		strcat(filename, "/limbs.txt");
2714 		if ( PHYSFS_getRealDir(filename) == NULL ) // some monsters don't have limbs.
2715 		{
2716 			continue;
2717 		}
2718 		std::string limbsDir = PHYSFS_getRealDir(filename);
2719 		if ( limbsDir.compare("./") != 0 )
2720 		{
2721 			printlog("[PhysFS]: Found modified limbs.txt file for monster %s, reloading all limb information...", monstertypename[c]);
2722 			requiresUpdate = true;
2723 		}
2724 	}
2725 	return requiresUpdate;
2726 }
2727 
physfsReloadMonsterLimbFiles()2728 void physfsReloadMonsterLimbFiles()
2729 {
2730 	int x;
2731 	FILE* fp;
2732 	for ( int c = 1; c < NUMMONSTERS; c++ )
2733 	{
2734 		// initialize all offsets to zero
2735 		for ( x = 0; x < 20; x++ )
2736 		{
2737 			limbs[c][x][0] = 0;
2738 			limbs[c][x][1] = 0;
2739 			limbs[c][x][2] = 0;
2740 		}
2741 
2742 		// open file
2743 		char filename[256];
2744 		strcpy(filename, "models/creatures/");
2745 		strcat(filename, monstertypename[c]);
2746 		strcat(filename, "/limbs.txt");
2747 		if ( PHYSFS_getRealDir(filename) == NULL ) // some monsters don't have limbs
2748 		{
2749 			continue;
2750 		}
2751 		std::string limbsDir = PHYSFS_getRealDir(filename);
2752 		limbsDir.append(PHYSFS_getDirSeparator()).append(filename);
2753 		if ( (fp = openDataFile(limbsDir.c_str(), "r")) == NULL )
2754 		{
2755 			continue;
2756 		}
2757 
2758 		// read file
2759 		int line;
2760 		for ( line = 1; feof(fp) == 0; line++ )
2761 		{
2762 			char data[256];
2763 			int limb = 20;
2764 			int dummy;
2765 
2766 			// read line from file
2767 			fgets(data, 256, fp);
2768 
2769 			// skip blank and comment lines
2770 			if ( data[0] == '\n' || data[0] == '\r' || data[0] == '#' )
2771 			{
2772 				continue;
2773 			}
2774 
2775 			// process line
2776 			if ( sscanf(data, "%d", &limb) != 1 || limb >= 20 || limb < 0 )
2777 			{
2778 				printlog("warning: syntax error in '%s':%d\n invalid limb index!\n", limbsDir.c_str(), line);
2779 				continue;
2780 			}
2781 			if ( sscanf(data, "%d %f %f %f\n", &dummy, &limbs[c][limb][0], &limbs[c][limb][1], &limbs[c][limb][2]) != 4 )
2782 			{
2783 				printlog("warning: syntax error in '%s':%d\n invalid limb offsets!\n", limbsDir.c_str(), line);
2784 				continue;
2785 			}
2786 		}
2787 		// close file
2788 		fclose(fp);
2789 	}
2790 }
2791 
physfsSearchSystemImagesToUpdate()2792 bool physfsSearchSystemImagesToUpdate()
2793 {
2794 	bool requireReload = false;
2795 	systemResourceImagesToReload.clear();
2796 
2797 	for ( std::vector<std::pair<SDL_Surface**, std::string>>::const_iterator it = systemResourceImages.begin(); it != systemResourceImages.end(); ++it )
2798 	{
2799 		std::pair<SDL_Surface**, std::string> line = *it;
2800 		std::string imgFile = line.second;
2801 		if ( PHYSFS_getRealDir(imgFile.c_str()) != NULL)
2802 		{
2803 			std::string imgDir = PHYSFS_getRealDir(imgFile.c_str());
2804 			if ( imgDir.compare("./") != 0 )
2805 			{
2806 				printlog("[PhysFS]: Found modified %s file, reloading system image...", imgFile.c_str());
2807 				requireReload = true;
2808 				systemResourceImagesToReload.push_back(line);
2809 			}
2810 		}
2811 	}
2812 	return requireReload;
2813 }
2814 
physfsReloadSystemImages()2815 void physfsReloadSystemImages()
2816 {
2817 	if ( !systemResourceImagesToReload.empty() )
2818 	{
2819 		for ( std::vector<std::pair<SDL_Surface**, std::string>>::const_iterator it = systemResourceImagesToReload.begin(); it != systemResourceImagesToReload.end(); ++it )
2820 		{
2821 			std::pair<SDL_Surface**, std::string> line = *it;
2822 			if ( *(line.first) ) // SDL_Surface* pointer exists
2823 			{
2824 				// load a new image, getting the VFS system location.
2825 				std::string filepath = PHYSFS_getRealDir(line.second.c_str());
2826 				filepath.append(PHYSFS_getDirSeparator()).append(line.second);
2827 
2828 				char filepathChar[1024];
2829 				strncpy(filepathChar, filepath.c_str(), 1023);
2830 
2831 				SDL_FreeSurface(*(line.first));
2832 				*(line.first) = loadImage(filepathChar);
2833 
2834 				if ( !(*(line.first)))
2835 				{
2836 					printlog("[PhysFS]: Error: Failed to reload %s!", filepath.c_str());
2837 				}
2838 			}
2839 		}
2840 	}
2841 }
2842