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