1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010-2019 EDuke32 developers and contributors
4 Copyright (C) 2019 Nuke.YKT
5
6 This file is part of NBlood.
7
8 NBlood is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License version 2
10 as published by the Free Software Foundation.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
16 See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22 //-------------------------------------------------------------------------
23 #include "build.h"
24 #include "editor.h"
25 #ifdef POLYMER
26 #include "polymer.h"
27 #endif
28 #include "compat.h"
29 #include "common_game.h"
30 #include "crc32.h"
31 #include "md4.h"
32
33 //#include "actor.h"
34 #include "globals.h"
35 #include "db.h"
36 #include "iob.h"
37 #include "eventq.h"
38 #ifdef NOONE_EXTENSIONS
39 #include "nnexts.h"
40 #endif
41
42 #ifdef NOONE_EXTENSIONS
43 bool gModernMap = false;
44 #endif // !NOONE_EXTENSIONS
45
46
47 unsigned short gStatCount[kMaxStatus + 1];
48
49 XSPRITE xsprite[kMaxXSprites];
50 XSECTOR xsector[kMaxXSectors];
51 XWALL xwall[kMaxXWalls];
52
53 SPRITEHIT gSpriteHit[kMaxXSprites];
54
55 int xvel[kMaxSprites], yvel[kMaxSprites], zvel[kMaxSprites];
56
57 #ifdef POLYMER
58 PolymerLight_t gPolymerLight[kMaxSprites];
59 #endif
60
61 char qsprite_filler[kMaxSprites], qsector_filler[kMaxSectors];
62
63 int gVisibility;
64 const char *gItemText[] = {
65 "Skull Key",
66 "Eye Key",
67 "Fire Key",
68 "Dagger Key",
69 "Spider Key",
70 "Moon Key",
71 "Key 7",
72 "Doctor's Bag",
73 "Medicine Pouch",
74 "Life Essence",
75 "Life Seed",
76 "Red Potion",
77 "Feather Fall",
78 "Limited Invisibility",
79 "INVULNERABILITY",
80 "Boots of Jumping",
81 "Raven Flight",
82 "Guns Akimbo",
83 "Diving Suit",
84 "Gas mask",
85 "Clone",
86 "Crystal Ball",
87 "Decoy",
88 "Doppleganger",
89 "Reflective shots",
90 "Beast Vision",
91 "ShadowCloak",
92 "Rage shroom",
93 "Delirium Shroom",
94 "Grow shroom",
95 "Shrink shroom",
96 "Death mask",
97 "Wine Goblet",
98 "Wine Bottle",
99 "Skull Grail",
100 "Silver Grail",
101 "Tome",
102 "Black Chest",
103 "Wooden Chest",
104 "Asbestos Armor",
105 "Basic Armor",
106 "Body Armor",
107 "Fire Armor",
108 "Spirit Armor",
109 "Super Armor",
110 "Blue Team Base",
111 "Red Team Base",
112 "Blue Flag",
113 "Red Flag",
114 "DUMMY",
115 "Level map",
116 };
117
118 const char *gAmmoText[] = {
119 "Spray can",
120 "Bundle of TNT*",
121 "Bundle of TNT",
122 "Case of TNT",
123 "Proximity Detonator",
124 "Remote Detonator",
125 "Trapped Soul",
126 "4 shotgun shells",
127 "Box of shotgun shells",
128 "A few bullets",
129 "Voodoo Doll",
130 "OBSOLETE",
131 "Full drum of bullets",
132 "Tesla Charge",
133 "OBSOLETE",
134 "OBSOLETE",
135 "Flares",
136 "OBSOLETE",
137 "OBSOLETE",
138 "Gasoline Can",
139 NULL,
140 };
141
142 const char *gWeaponText[] = {
143 "RANDOM",
144 "Sawed-off",
145 "Tommy Gun",
146 "Flare Pistol",
147 "Voodoo Doll",
148 "Tesla Cannon",
149 "Napalm Launcher",
150 "Pitchfork",
151 "Spray Can",
152 "Dynamite",
153 "Life Leech",
154 };
155
156
157
dbCrypt(char * pPtr,int nLength,int nKey)158 void dbCrypt(char *pPtr, int nLength, int nKey)
159 {
160 for (int i = 0; i < nLength; i++)
161 {
162 pPtr[i] = pPtr[i] ^ nKey;
163 nKey++;
164 }
165 }
166
167 #ifdef POLYMER
168
DeleteLight(int32_t s)169 void DeleteLight(int32_t s)
170 {
171 if (gPolymerLight[s].lightId >= 0)
172 polymer_deletelight(gPolymerLight[s].lightId);
173 gPolymerLight[s].lightId = -1;
174 gPolymerLight[s].lightptr = NULL;
175 }
176
177 #endif
178
179
InsertSpriteSect(int nSprite,int nSector)180 void InsertSpriteSect(int nSprite, int nSector)
181 {
182 dassert(nSprite >= 0 && nSprite < kMaxSprites);
183 dassert(nSector >= 0 && nSector < kMaxSectors);
184 int nOther = headspritesect[nSector];
185 if (nOther >= 0)
186 {
187 prevspritesect[nSprite] = prevspritesect[nOther];
188 nextspritesect[nSprite] = -1;
189 nextspritesect[prevspritesect[nOther]] = nSprite;
190 prevspritesect[nOther] = nSprite;
191 }
192 else
193 {
194 prevspritesect[nSprite] = nSprite;
195 nextspritesect[nSprite] = -1;
196 headspritesect[nSector] = nSprite;
197 }
198 sprite[nSprite].sectnum = nSector;
199 }
200
RemoveSpriteSect(int nSprite)201 void RemoveSpriteSect(int nSprite)
202 {
203 dassert(nSprite >= 0 && nSprite < kMaxSprites);
204 int nSector = sprite[nSprite].sectnum;
205 dassert(nSector >= 0 && nSector < kMaxSectors);
206 int nOther = nextspritesect[nSprite];
207 if (nOther < 0)
208 {
209 nOther = headspritesect[nSector];
210 }
211 prevspritesect[nOther] = prevspritesect[nSprite];
212 if (headspritesect[nSector] != nSprite)
213 {
214 nextspritesect[prevspritesect[nSprite]] = nextspritesect[nSprite];
215 }
216 else
217 {
218 headspritesect[nSector] = nextspritesect[nSprite];
219 }
220 sprite[nSprite].sectnum = -1;
221 }
222
InsertSpriteStat(int nSprite,int nStat)223 void InsertSpriteStat(int nSprite, int nStat)
224 {
225 dassert(nSprite >= 0 && nSprite < kMaxSprites);
226 dassert(nStat >= 0 && nStat <= kMaxStatus);
227 int nOther = headspritestat[nStat];
228 if (nOther >= 0)
229 {
230 prevspritestat[nSprite] = prevspritestat[nOther];
231 nextspritestat[nSprite] = -1;
232 nextspritestat[prevspritestat[nOther]] = nSprite;
233 prevspritestat[nOther] = nSprite;
234 }
235 else
236 {
237 prevspritestat[nSprite] = nSprite;
238 nextspritestat[nSprite] = -1;
239 headspritestat[nStat] = nSprite;
240 }
241 sprite[nSprite].statnum = nStat;
242 gStatCount[nStat]++;
243 }
244
RemoveSpriteStat(int nSprite)245 void RemoveSpriteStat(int nSprite)
246 {
247 dassert(nSprite >= 0 && nSprite < kMaxSprites);
248 int nStat = sprite[nSprite].statnum;
249 dassert(nStat >= 0 && nStat <= kMaxStatus);
250 int nOther = nextspritestat[nSprite];
251 if (nOther < 0)
252 {
253 nOther = headspritestat[nStat];
254 }
255 prevspritestat[nOther] = prevspritestat[nSprite];
256 if (headspritestat[nStat] != nSprite)
257 {
258 nextspritestat[prevspritestat[nSprite]] = nextspritestat[nSprite];
259 }
260 else
261 {
262 headspritestat[nStat] = nextspritestat[nSprite];
263 }
264 sprite[nSprite].statnum = kStatNothing;
265 gStatCount[nStat]--;
266 }
267
qinitspritelists(void)268 void qinitspritelists(void) // Replace
269 {
270 for (short i = 0; i <= kMaxSectors; i++)
271 {
272 headspritesect[i] = -1;
273 }
274 for (short i = 0; i <= kMaxStatus; i++)
275 {
276 headspritestat[i] = -1;
277 }
278 int const nMaxSprites = bVanilla ? 4096 : kMaxSprites;
279 for (short i = 0; i < nMaxSprites; i++)
280 {
281 sprite[i].sectnum = -1;
282 sprite[i].index = -1;
283 InsertSpriteStat(i, kMaxStatus);
284 }
285 memset(gStatCount, 0, sizeof(gStatCount));
286 Numsprites = 0;
287 }
288
InsertSprite(int nSector,int nStat)289 int InsertSprite(int nSector, int nStat)
290 {
291 int nSprite = headspritestat[kMaxStatus];
292 dassert(nSprite < kMaxSprites);
293 if (nSprite < 0)
294 {
295 return nSprite;
296 }
297 RemoveSpriteStat(nSprite);
298 spritetype *pSprite = &sprite[nSprite];
299 memset(&sprite[nSprite], 0, sizeof(spritetype));
300 InsertSpriteStat(nSprite, nStat);
301 InsertSpriteSect(nSprite, nSector);
302 pSprite->cstat = 128;
303 pSprite->clipdist = 32;
304 pSprite->xrepeat = pSprite->yrepeat = 64;
305 pSprite->owner = -1;
306 pSprite->extra = -1;
307 pSprite->index = nSprite;
308 xvel[nSprite] = yvel[nSprite] = zvel[nSprite] = 0;
309
310 #ifdef POLYMER
311 gPolymerLight[nSprite].lightId = -1;
312 #endif
313
314 Numsprites++;
315
316 return nSprite;
317 }
318
qinsertsprite(short nSector,short nStat)319 int qinsertsprite(short nSector, short nStat) // Replace
320 {
321 return InsertSprite(nSector, nStat);
322 }
323
DeleteSprite(int nSprite)324 int DeleteSprite(int nSprite)
325 {
326 #ifdef POLYMER
327 if (gPolymerLight[nSprite].lightptr != NULL && videoGetRenderMode() == REND_POLYMER)
328 DeleteLight(nSprite);
329 #endif
330 if (sprite[nSprite].extra > 0)
331 {
332 dbDeleteXSprite(sprite[nSprite].extra);
333 }
334 dassert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus);
335 RemoveSpriteStat(nSprite);
336 dassert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors);
337 RemoveSpriteSect(nSprite);
338 InsertSpriteStat(nSprite, kMaxStatus);
339
340 Numsprites--;
341
342 return nSprite;
343 }
344
qdeletesprite(short nSprite)345 int qdeletesprite(short nSprite) // Replace
346 {
347 return DeleteSprite(nSprite);
348 }
349
ChangeSpriteSect(int nSprite,int nSector)350 int ChangeSpriteSect(int nSprite, int nSector)
351 {
352 dassert(nSprite >= 0 && nSprite < kMaxSprites);
353 dassert(nSector >= 0 && nSector < kMaxSectors);
354 dassert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors);
355 RemoveSpriteSect(nSprite);
356 InsertSpriteSect(nSprite, nSector);
357 return 0;
358 }
359
qchangespritesect(short nSprite,short nSector)360 int qchangespritesect(short nSprite, short nSector)
361 {
362 return ChangeSpriteSect(nSprite, nSector);
363 }
364
ChangeSpriteStat(int nSprite,int nStatus)365 int ChangeSpriteStat(int nSprite, int nStatus)
366 {
367 dassert(nSprite >= 0 && nSprite < kMaxSprites);
368 dassert(nStatus >= 0 && nStatus < kMaxStatus);
369 dassert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus);
370 dassert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors);
371 RemoveSpriteStat(nSprite);
372 InsertSpriteStat(nSprite, nStatus);
373 return 0;
374 }
375
qchangespritestat(short nSprite,short nStatus)376 int qchangespritestat(short nSprite, short nStatus)
377 {
378 return ChangeSpriteStat(nSprite, nStatus);
379 }
380
381 unsigned short nextXSprite[kMaxXSprites];
382 unsigned short nextXWall[kMaxXWalls];
383 unsigned short nextXSector[kMaxXSectors];
384
InitFreeList(unsigned short * pList,int nCount)385 void InitFreeList(unsigned short *pList, int nCount)
386 {
387 for (int i = 1; i < nCount; i++)
388 {
389 pList[i] = i-1;
390 }
391 pList[0] = nCount - 1;
392 }
393
InsertFree(unsigned short * pList,int nIndex)394 void InsertFree(unsigned short *pList, int nIndex)
395 {
396 pList[nIndex] = pList[0];
397 pList[0] = nIndex;
398 }
399
dbInsertXSprite(int nSprite)400 unsigned short dbInsertXSprite(int nSprite)
401 {
402 int nXSprite = nextXSprite[0];
403 nextXSprite[0] = nextXSprite[nXSprite];
404 if (nXSprite == 0)
405 {
406 ThrowError("Out of free XSprites");
407 }
408 memset(&xsprite[nXSprite], 0, sizeof(XSPRITE));
409 if (!bVanilla)
410 memset(&gSpriteHit[nXSprite], 0, sizeof(SPRITEHIT));
411 xsprite[nXSprite].reference = nSprite;
412 sprite[nSprite].extra = nXSprite;
413 return nXSprite;
414 }
415
dbDeleteXSprite(int nXSprite)416 void dbDeleteXSprite(int nXSprite)
417 {
418 dassert(xsprite[nXSprite].reference >= 0);
419 dassert(sprite[xsprite[nXSprite].reference].extra == nXSprite);
420 InsertFree(nextXSprite, nXSprite);
421 sprite[xsprite[nXSprite].reference].extra = -1;
422 xsprite[nXSprite].reference = -1;
423 }
424
dbInsertXWall(int nWall)425 unsigned short dbInsertXWall(int nWall)
426 {
427 int nXWall = nextXWall[0];
428 nextXWall[0] = nextXWall[nXWall];
429 if (nXWall == 0)
430 {
431 ThrowError("Out of free XWalls");
432 }
433 memset(&xwall[nXWall], 0, sizeof(XWALL));
434 xwall[nXWall].reference = nWall;
435 wall[nWall].extra = nXWall;
436 return nXWall;
437 }
438
dbDeleteXWall(int nXWall)439 void dbDeleteXWall(int nXWall)
440 {
441 dassert(xwall[nXWall].reference >= 0);
442 InsertFree(nextXWall, nXWall);
443 wall[xwall[nXWall].reference].extra = -1;
444 xwall[nXWall].reference = -1;
445 }
446
dbInsertXSector(int nSector)447 unsigned short dbInsertXSector(int nSector)
448 {
449 int nXSector = nextXSector[0];
450 nextXSector[0] = nextXSector[nXSector];
451 if (nXSector == 0)
452 {
453 ThrowError("Out of free XSectors");
454 }
455 memset(&xsector[nXSector], 0, sizeof(XSECTOR));
456 xsector[nXSector].reference = nSector;
457 sector[nSector].extra = nXSector;
458 return nXSector;
459 }
460
dbDeleteXSector(int nXSector)461 void dbDeleteXSector(int nXSector)
462 {
463 dassert(xsector[nXSector].reference >= 0);
464 InsertFree(nextXSector, nXSector);
465 sector[xsector[nXSector].reference].extra = -1;
466 xsector[nXSector].reference = -1;
467 }
468
dbXSpriteClean(void)469 void dbXSpriteClean(void)
470 {
471 for (int i = 0; i < kMaxSprites; i++)
472 {
473 int nXSprite = sprite[i].extra;
474 if (nXSprite == 0)
475 {
476 sprite[i].extra = -1;
477 }
478 if (sprite[i].statnum < kMaxStatus && nXSprite > 0)
479 {
480 dassert(nXSprite < kMaxXSprites);
481 if (xsprite[nXSprite].reference != i)
482 {
483 int nXSprite2 = dbInsertXSprite(i);
484 memcpy(&xsprite[nXSprite2], &xsprite[nXSprite], sizeof(XSPRITE));
485 xsprite[nXSprite2].reference = i;
486 }
487 }
488 }
489 for (int i = 1; i < kMaxXSprites; i++)
490 {
491 int nSprite = xsprite[i].reference;
492 if (nSprite >= 0)
493 {
494 dassert(nSprite < kMaxSprites);
495 if (sprite[nSprite].statnum >= kMaxStatus || sprite[nSprite].extra != i)
496 {
497 InsertFree(nextXSprite, i);
498 xsprite[i].reference = -1;
499 }
500 }
501 }
502 }
503
dbXWallClean(void)504 void dbXWallClean(void)
505 {
506 for (int i = 0; i < numwalls; i++)
507 {
508 int nXWall = wall[i].extra;
509 if (nXWall == 0)
510 {
511 wall[i].extra = -1;
512 }
513 if (nXWall > 0)
514 {
515 dassert(nXWall < kMaxXWalls);
516 if (xwall[nXWall].reference == -1)
517 {
518 wall[i].extra = -1;
519 }
520 else
521 {
522 xwall[nXWall].reference = i;
523 }
524 }
525 }
526 for (int i = 0; i < numwalls; i++)
527 {
528 int nXWall = wall[i].extra;
529 if (nXWall > 0)
530 {
531 dassert(nXWall < kMaxXWalls);
532 if (xwall[nXWall].reference != i)
533 {
534 int nXWall2 = dbInsertXWall(i);
535 memcpy(&xwall[nXWall2], &xwall[nXWall], sizeof(XWALL));
536 xwall[nXWall2].reference = i;
537 }
538 }
539 }
540 for (int i = 1; i < kMaxXWalls; i++)
541 {
542 int nWall = xwall[i].reference;
543 if (nWall >= 0)
544 {
545 dassert(nWall < kMaxWalls);
546 if (nWall >= numwalls || wall[nWall].extra != i)
547 {
548 InsertFree(nextXWall, i);
549 xwall[i].reference = -1;
550 }
551 }
552 }
553 }
554
dbXSectorClean(void)555 void dbXSectorClean(void)
556 {
557
558
559 for (int i = 0; i < numsectors; i++)
560 {
561 int nXSector = sector[i].extra;
562 if (nXSector == 0)
563 {
564 sector[i].extra = -1;
565 }
566 if (nXSector > 0)
567 {
568 dassert(nXSector < kMaxXSectors);
569 if (xsector[nXSector].reference == -1)
570 {
571 sector[i].extra = -1;
572 }
573 else
574 {
575 xsector[nXSector].reference = i;
576 }
577 }
578 }
579 for (int i = 0; i < numsectors; i++)
580 {
581 int nXSector = sector[i].extra;
582 if (nXSector > 0)
583 {
584 dassert(nXSector < kMaxXSectors);
585 if (xsector[nXSector].reference != i)
586 {
587 int nXSector2 = dbInsertXSector(i);
588 memcpy(&xsector[nXSector2], &xsector[nXSector], sizeof(XSECTOR));
589 xsector[nXSector2].reference = i;
590 }
591 }
592 }
593 for (int i = 1; i < kMaxXSectors; i++)
594 {
595 int nSector = xsector[i].reference;
596 if (nSector >= 0)
597 {
598 dassert(nSector < kMaxSectors);
599 if (nSector >= numsectors || sector[nSector].extra != i)
600 {
601 InsertFree(nextXSector, i);
602 xsector[i].reference = -1;
603 }
604 }
605 }
606 }
607
dbInit(void)608 void dbInit(void)
609 {
610 InitFreeList(nextXSprite, kMaxXSprites);
611 for (int i = 1; i < kMaxXSprites; i++)
612 {
613 xsprite[i].reference = -1;
614 }
615 InitFreeList(nextXWall, kMaxXWalls);
616 for (int i = 1; i < kMaxXWalls; i++)
617 {
618 xwall[i].reference = -1;
619 }
620 InitFreeList(nextXSector, kMaxXSectors);
621 for (int i = 1; i < kMaxXSectors; i++)
622 {
623 xsector[i].reference = -1;
624 }
625 initspritelists();
626 for (int i = 0; i < kMaxSprites; i++)
627 {
628 sprite[i].cstat = 128;
629 }
630 }
631
PropagateMarkerReferences(void)632 void PropagateMarkerReferences(void)
633 {
634 int nSprite, nNextSprite;
635 for (nSprite = headspritestat[kStatMarker]; nSprite != -1; nSprite = nNextSprite) {
636
637 nNextSprite = nextspritestat[nSprite];
638
639 switch (sprite[nSprite].type) {
640 case kMarkerOff:
641 case kMarkerAxis:
642 case kMarkerWarpDest: {
643 int nOwner = sprite[nSprite].owner;
644 if (nOwner >= 0 && nOwner < numsectors) {
645 int nXSector = sector[nOwner].extra;
646 if (nXSector > 0 && nXSector < kMaxXSectors) {
647 xsector[nXSector].marker0 = nSprite;
648 continue;
649 }
650 }
651 }
652 break;
653 case kMarkerOn: {
654 int nOwner = sprite[nSprite].owner;
655 if (nOwner >= 0 && nOwner < numsectors) {
656 int nXSector = sector[nOwner].extra;
657 if (nXSector > 0 && nXSector < kMaxXSectors) {
658 xsector[nXSector].marker1 = nSprite;
659 continue;
660 }
661 }
662 }
663 break;
664 }
665
666 DeleteSprite(nSprite);
667 }
668 }
669
670 bool byte_1A76C6, byte_1A76C7, byte_1A76C8;
671
672 MAPHEADER2 byte_19AE44;
673
dbReadMapCRC(const char * pPath)674 unsigned int dbReadMapCRC(const char *pPath)
675 {
676 char name2[BMAX_PATH];
677 byte_1A76C7 = 0;
678 byte_1A76C8 = 0;
679
680 int const bakpathsearchmode = pathsearchmode;
681 pathsearchmode = 1;
682
683 Bstrncpy(name2, pPath, BMAX_PATH);
684 Bstrupr(name2);
685 DICTNODE* pNode = *gSysRes.Probe(name2, "MAP");
686 if (pNode && pNode->flags & DICT_EXTERNAL)
687 {
688 gSysRes.RemoveNode(pNode);
689 }
690 pNode = gSysRes.Lookup(pPath, "MAP");
691 if (!pNode)
692 {
693 char name2[BMAX_PATH];
694 Bstrncpy(name2, pPath, BMAX_PATH);
695 ChangeExtension(name2, "");
696 pNode = gSysRes.Lookup(name2, "MAP");
697 }
698
699 if (!pNode)
700 {
701 initprintf("Error opening map file %s", pPath);
702 pathsearchmode = bakpathsearchmode;
703 return -1;
704 }
705 char *pData = (char*)gSysRes.Lock(pNode);
706 pathsearchmode = bakpathsearchmode;
707
708 int nSize = pNode->size;
709 MAPSIGNATURE header;
710 IOBuffer(nSize, pData).Read(&header, 6);
711 #if B_BIG_ENDIAN == 1
712 header.version = B_LITTLE16(header.version);
713 #endif
714 if (memcmp(header.signature, "BLM\x1a", 4))
715 {
716 ThrowError("Map file corrupted");
717 }
718 if ((header.version & 0xff00) == 0x600)
719 {
720 }
721 else if ((header.version & 0xff00) == 0x700)
722 {
723 byte_1A76C8 = 1;
724 }
725 else
726 {
727 ThrowError("Map file is wrong version");
728 }
729 unsigned int nCRC = *(unsigned int*)(pData+nSize-4);
730 gSysRes.Unlock(pNode);
731 return nCRC;
732 }
733
734 int gMapRev, gSongId, gSkyCount;
735 //char byte_19AE44[128];
736 const int nXSectorSize = 60;
737 const int nXSpriteSize = 56;
738 const int nXWallSize = 24;
739
dbLoadMap(const char * pPath,int * pX,int * pY,int * pZ,short * pAngle,short * pSector,unsigned int * pCRC)740 int dbLoadMap(const char *pPath, int *pX, int *pY, int *pZ, short *pAngle, short *pSector, unsigned int *pCRC) {
741 char name2[BMAX_PATH]; int16_t tpskyoff[256];
742 memset(show2dsector, 0, sizeof(show2dsector));
743 memset(show2dwall, 0, sizeof(show2dwall));
744 memset(show2dsprite, 0, sizeof(show2dsprite));
745 #ifdef NOONE_EXTENSIONS
746 gModernMap = false;
747 #endif
748
749 #ifdef USE_OPENGL
750 Polymost_prepare_loadboard();
751 #endif
752
753 int const bakpathsearchmode = pathsearchmode;
754 pathsearchmode = 1;
755
756 Bstrncpy(name2, pPath, BMAX_PATH);
757 Bstrupr(name2);
758 DICTNODE* pNode = *gSysRes.Probe(name2, "MAP");
759 if (pNode && pNode->flags & DICT_EXTERNAL)
760 {
761 gSysRes.RemoveNode(pNode);
762 }
763
764 pNode = gSysRes.Lookup(pPath, "MAP");
765 if (!pNode)
766 {
767 char name2[BMAX_PATH];
768 Bstrncpy(name2, pPath, BMAX_PATH);
769 ChangeExtension(name2, "");
770 pNode = gSysRes.Lookup(name2, "MAP");
771 }
772
773 if (!pNode)
774 {
775 initprintf("Error opening map file %s", pPath);
776 pathsearchmode = bakpathsearchmode;
777 return -1;
778 }
779 char *pData = (char*)gSysRes.Lock(pNode);
780 pathsearchmode = bakpathsearchmode;
781 int nSize = pNode->size;
782 MAPSIGNATURE header;
783 IOBuffer IOBuffer1 = IOBuffer(nSize, pData);
784 IOBuffer1.Read(&header, 6);
785 #if B_BIG_ENDIAN == 1
786 header.version = B_LITTLE16(header.version);
787 #endif
788 if (memcmp(header.signature, "BLM\x1a", 4))
789 {
790 initprintf("Map file corrupted");
791 gSysRes.Unlock(pNode);
792 return -1;
793 }
794 byte_1A76C8 = 0;
795 if ((header.version & 0xff00) == 0x700) {
796 byte_1A76C8 = 1;
797
798 #ifdef NOONE_EXTENSIONS
799 // indicate if the map requires modern features to work properly
800 // for maps wich created in PMAPEDIT BETA13 or higher versions. Since only minor version changed,
801 // the map is still can be loaded with vanilla BLOOD / MAPEDIT and should work in other ports too.
802 if ((header.version & 0x00ff) == 0x001) gModernMap = true;
803 #endif
804
805 } else {
806 initprintf("Map file is wrong version");
807 gSysRes.Unlock(pNode);
808 return -1;
809 }
810
811 MAPHEADER mapHeader;
812 IOBuffer1.Read(&mapHeader,37/* sizeof(mapHeader)*/);
813 if (mapHeader.at16 != 0 && mapHeader.at16 != 0x7474614d && mapHeader.at16 != 0x4d617474) {
814 dbCrypt((char*)&mapHeader, sizeof(mapHeader), 0x7474614d);
815 byte_1A76C7 = 1;
816 }
817
818 #if B_BIG_ENDIAN == 1
819 mapHeader.at0 = B_LITTLE32(mapHeader.at0);
820 mapHeader.at4 = B_LITTLE32(mapHeader.at4);
821 mapHeader.at8 = B_LITTLE32(mapHeader.at8);
822 mapHeader.atc = B_LITTLE16(mapHeader.atc);
823 mapHeader.ate = B_LITTLE16(mapHeader.ate);
824 mapHeader.at10 = B_LITTLE16(mapHeader.at10);
825 mapHeader.at12 = B_LITTLE32(mapHeader.at12);
826 mapHeader.at16 = B_LITTLE32(mapHeader.at16);
827 mapHeader.at1b = B_LITTLE32(mapHeader.at1b);
828 mapHeader.at1f = B_LITTLE16(mapHeader.at1f);
829 mapHeader.at21 = B_LITTLE16(mapHeader.at21);
830 mapHeader.at23 = B_LITTLE16(mapHeader.at23);
831 #endif
832
833 psky_t *pSky = tileSetupSky(0);
834 pSky->horizfrac = 65536;
835
836 *pX = mapHeader.at0;
837 *pY = mapHeader.at4;
838 *pZ = mapHeader.at8;
839 *pAngle = mapHeader.atc;
840 *pSector = mapHeader.ate;
841 pSky->lognumtiles = mapHeader.at10;
842 gVisibility = g_visibility = mapHeader.at12;
843 gSongId = mapHeader.at16;
844 if (byte_1A76C8)
845 {
846 if (mapHeader.at16 == 0x7474614d || mapHeader.at16 == 0x4d617474)
847 {
848 byte_1A76C6 = 1;
849 }
850 else if (!mapHeader.at16)
851 {
852 byte_1A76C6 = 0;
853 }
854 else
855 {
856 initprintf("Corrupted Map file");
857 gSysRes.Unlock(pNode);
858 return -1;
859 }
860 }
861 else if (mapHeader.at16)
862 {
863 initprintf("Corrupted Map file");
864 gSysRes.Unlock(pNode);
865 return -1;
866 }
867 parallaxtype = mapHeader.at1a;
868 gMapRev = mapHeader.at1b;
869 numsectors = mapHeader.at1f;
870 numwalls = mapHeader.at21;
871 dbInit();
872 if (byte_1A76C8)
873 {
874 IOBuffer1.Read(&byte_19AE44, 128);
875 dbCrypt((char*)&byte_19AE44, 128, numwalls);
876 #if B_BIG_ENDIAN == 1
877 byte_19AE44.at40 = B_LITTLE32(byte_19AE44.at40);
878 byte_19AE44.at44 = B_LITTLE32(byte_19AE44.at44);
879 byte_19AE44.at48 = B_LITTLE32(byte_19AE44.at48);
880 #endif
881 }
882 else
883 {
884 memset(&byte_19AE44, 0, 128);
885 }
886 gSkyCount = 1<<pSky->lognumtiles;
887 IOBuffer1.Read(tpskyoff, gSkyCount*sizeof(tpskyoff[0]));
888 if (byte_1A76C8)
889 {
890 dbCrypt((char*)tpskyoff, gSkyCount*sizeof(tpskyoff[0]), gSkyCount*2);
891 }
892 for (int i = 0; i < ClipHigh(gSkyCount, MAXPSKYTILES); i++)
893 {
894 pSky->tileofs[i] = B_LITTLE16(tpskyoff[i]);
895 }
896 for (int i = 0; i < numsectors; i++)
897 {
898 sectortype *pSector = §or[i];
899 IOBuffer1.Read(pSector, sizeof(sectortype));
900 if (byte_1A76C8)
901 {
902 dbCrypt((char*)pSector, sizeof(sectortype), gMapRev*sizeof(sectortype));
903 }
904 #if B_BIG_ENDIAN == 1
905 pSector->wallptr = B_LITTLE16(pSector->wallptr);
906 pSector->wallnum = B_LITTLE16(pSector->wallnum);
907 pSector->ceilingz = B_LITTLE32(pSector->ceilingz);
908 pSector->floorz = B_LITTLE32(pSector->floorz);
909 pSector->ceilingstat = B_LITTLE16(pSector->ceilingstat);
910 pSector->floorstat = B_LITTLE16(pSector->floorstat);
911 pSector->ceilingpicnum = B_LITTLE16(pSector->ceilingpicnum);
912 pSector->ceilingheinum = B_LITTLE16(pSector->ceilingheinum);
913 pSector->floorpicnum = B_LITTLE16(pSector->floorpicnum);
914 pSector->floorheinum = B_LITTLE16(pSector->floorheinum);
915 pSector->type = B_LITTLE16(pSector->type);
916 pSector->hitag = B_LITTLE16(pSector->hitag);
917 pSector->extra = B_LITTLE16(pSector->extra);
918 #endif
919 qsector_filler[i] = pSector->fogpal;
920 pSector->fogpal = 0;
921 if (sector[i].extra > 0)
922 {
923 char pBuffer[nXSectorSize];
924 int nXSector = dbInsertXSector(i);
925 XSECTOR *pXSector = &xsector[nXSector];
926 memset(pXSector, 0, sizeof(XSECTOR));
927 int nCount;
928 if (!byte_1A76C8)
929 {
930 nCount = nXSectorSize;
931 }
932 else
933 {
934 nCount = byte_19AE44.at48;
935 }
936 dassert(nCount <= nXSectorSize);
937 IOBuffer1.Read(pBuffer, nCount);
938 BitReader bitReader(pBuffer, nCount);
939 pXSector->reference = bitReader.readSigned(14);
940 pXSector->state = bitReader.readUnsigned(1);
941 pXSector->busy = bitReader.readUnsigned(17);
942 pXSector->data = bitReader.readUnsigned(16);
943 pXSector->txID = bitReader.readUnsigned(10);
944 pXSector->busyWaveA = bitReader.readUnsigned(3);
945 pXSector->busyWaveB = bitReader.readUnsigned(3);
946 pXSector->rxID = bitReader.readUnsigned(10);
947 pXSector->command = bitReader.readUnsigned(8);
948 pXSector->triggerOn = bitReader.readUnsigned(1);
949 pXSector->triggerOff = bitReader.readUnsigned(1);
950 pXSector->busyTimeA = bitReader.readUnsigned(12);
951 pXSector->waitTimeA = bitReader.readUnsigned(12);
952 pXSector->restState = bitReader.readUnsigned(1);
953 pXSector->interruptable = bitReader.readUnsigned(1);
954 pXSector->amplitude = bitReader.readSigned(8);
955 pXSector->freq = bitReader.readUnsigned(8);
956 pXSector->reTriggerA = bitReader.readUnsigned(1);
957 pXSector->reTriggerB = bitReader.readUnsigned(1);
958 pXSector->phase = bitReader.readUnsigned(8);
959 pXSector->wave = bitReader.readUnsigned(4);
960 pXSector->shadeAlways = bitReader.readUnsigned(1);
961 pXSector->shadeFloor = bitReader.readUnsigned(1);
962 pXSector->shadeCeiling = bitReader.readUnsigned(1);
963 pXSector->shadeWalls = bitReader.readUnsigned(1);
964 pXSector->shade = bitReader.readSigned(8);
965 pXSector->panAlways = bitReader.readUnsigned(1);
966 pXSector->panFloor = bitReader.readUnsigned(1);
967 pXSector->panCeiling = bitReader.readUnsigned(1);
968 pXSector->Drag = bitReader.readUnsigned(1);
969 pXSector->Underwater = bitReader.readUnsigned(1);
970 pXSector->Depth = bitReader.readUnsigned(3);
971 pXSector->panVel = bitReader.readUnsigned(8);
972 pXSector->panAngle = bitReader.readUnsigned(11);
973 pXSector->unused1 = bitReader.readUnsigned(1);
974 pXSector->decoupled = bitReader.readUnsigned(1);
975 pXSector->triggerOnce = bitReader.readUnsigned(1);
976 pXSector->isTriggered = bitReader.readUnsigned(1);
977 pXSector->Key = bitReader.readUnsigned(3);
978 pXSector->Push = bitReader.readUnsigned(1);
979 pXSector->Vector = bitReader.readUnsigned(1);
980 pXSector->Reserved = bitReader.readUnsigned(1);
981 pXSector->Enter = bitReader.readUnsigned(1);
982 pXSector->Exit = bitReader.readUnsigned(1);
983 pXSector->Wallpush = bitReader.readUnsigned(1);
984 pXSector->color = bitReader.readUnsigned(1);
985 pXSector->unused2 = bitReader.readUnsigned(1);
986 pXSector->busyTimeB = bitReader.readUnsigned(12);
987 pXSector->waitTimeB = bitReader.readUnsigned(12);
988 pXSector->stopOn = bitReader.readUnsigned(1);
989 pXSector->stopOff = bitReader.readUnsigned(1);
990 pXSector->ceilpal = bitReader.readUnsigned(4);
991 pXSector->offCeilZ = bitReader.readSigned(32);
992 pXSector->onCeilZ = bitReader.readSigned(32);
993 pXSector->offFloorZ = bitReader.readSigned(32);
994 pXSector->onFloorZ = bitReader.readSigned(32);
995 pXSector->marker0 = bitReader.readUnsigned(16);
996 pXSector->marker1 = bitReader.readUnsigned(16);
997 pXSector->Crush = bitReader.readUnsigned(1);
998 pXSector->ceilXPanFrac = bitReader.readUnsigned(8);
999 pXSector->ceilYPanFrac = bitReader.readUnsigned(8);
1000 pXSector->floorXPanFrac = bitReader.readUnsigned(8);
1001 pXSector->damageType = bitReader.readUnsigned(3);
1002 pXSector->floorpal = bitReader.readUnsigned(4);
1003 pXSector->floorYPanFrac = bitReader.readUnsigned(8);
1004 pXSector->locked = bitReader.readUnsigned(1);
1005 pXSector->windVel = bitReader.readUnsigned(10);
1006 pXSector->windAng = bitReader.readUnsigned(11);
1007 pXSector->windAlways = bitReader.readUnsigned(1);
1008 pXSector->dudeLockout = bitReader.readUnsigned(1);
1009 pXSector->bobTheta = bitReader.readUnsigned(11);
1010 pXSector->bobZRange = bitReader.readUnsigned(5);
1011 pXSector->bobSpeed = bitReader.readSigned(12);
1012 pXSector->bobAlways = bitReader.readUnsigned(1);
1013 pXSector->bobFloor = bitReader.readUnsigned(1);
1014 pXSector->bobCeiling = bitReader.readUnsigned(1);
1015 pXSector->bobRotate = bitReader.readUnsigned(1);
1016 xsector[sector[i].extra].reference = i;
1017 xsector[sector[i].extra].busy = xsector[sector[i].extra].state<<16;
1018
1019 }
1020 }
1021 for (int i = 0; i < numwalls; i++)
1022 {
1023 walltype *pWall = &wall[i];
1024 IOBuffer1.Read(pWall, sizeof(walltype));
1025 if (byte_1A76C8)
1026 {
1027 dbCrypt((char*)pWall, sizeof(walltype), (gMapRev*sizeof(sectortype)) | 0x7474614d);
1028 }
1029 #if B_BIG_ENDIAN == 1
1030 pWall->x = B_LITTLE32(pWall->x);
1031 pWall->y = B_LITTLE32(pWall->y);
1032 pWall->point2 = B_LITTLE16(pWall->point2);
1033 pWall->nextwall = B_LITTLE16(pWall->nextwall);
1034 pWall->nextsector = B_LITTLE16(pWall->nextsector);
1035 pWall->cstat = B_LITTLE16(pWall->cstat);
1036 pWall->picnum = B_LITTLE16(pWall->picnum);
1037 pWall->overpicnum = B_LITTLE16(pWall->overpicnum);
1038 pWall->type = B_LITTLE16(pWall->type);
1039 pWall->hitag = B_LITTLE16(pWall->hitag);
1040 pWall->extra = B_LITTLE16(pWall->extra);
1041 #endif
1042 if (wall[i].extra > 0)
1043 {
1044 char pBuffer[nXWallSize];
1045 int nXWall = dbInsertXWall(i);
1046 XWALL *pXWall = &xwall[nXWall];
1047 memset(pXWall, 0, sizeof(XWALL));
1048 int nCount;
1049 if (!byte_1A76C8)
1050 {
1051 nCount = nXWallSize;
1052 }
1053 else
1054 {
1055 nCount = byte_19AE44.at44;
1056 }
1057 dassert(nCount <= nXWallSize);
1058 IOBuffer1.Read(pBuffer, nCount);
1059 BitReader bitReader(pBuffer, nCount);
1060 pXWall->reference = bitReader.readSigned(14);
1061 pXWall->state = bitReader.readUnsigned(1);
1062 pXWall->busy = bitReader.readUnsigned(17);
1063 pXWall->data = bitReader.readSigned(16);
1064 pXWall->txID = bitReader.readUnsigned(10);
1065 pXWall->unused1 = bitReader.readUnsigned(6);
1066 pXWall->rxID = bitReader.readUnsigned(10);
1067 pXWall->command = bitReader.readUnsigned(8);
1068 pXWall->triggerOn = bitReader.readUnsigned(1);
1069 pXWall->triggerOff = bitReader.readUnsigned(1);
1070 pXWall->busyTime = bitReader.readUnsigned(12);
1071 pXWall->waitTime = bitReader.readUnsigned(12);
1072 pXWall->restState = bitReader.readUnsigned(1);
1073 pXWall->interruptable = bitReader.readUnsigned(1);
1074 pXWall->panAlways = bitReader.readUnsigned(1);
1075 pXWall->panXVel = bitReader.readSigned(8);
1076 pXWall->panYVel = bitReader.readSigned(8);
1077 pXWall->decoupled = bitReader.readUnsigned(1);
1078 pXWall->triggerOnce = bitReader.readUnsigned(1);
1079 pXWall->isTriggered = bitReader.readUnsigned(1);
1080 pXWall->key = bitReader.readUnsigned(3);
1081 pXWall->triggerPush = bitReader.readUnsigned(1);
1082 pXWall->triggerVector = bitReader.readUnsigned(1);
1083 pXWall->triggerTouch = bitReader.readUnsigned(1);
1084 pXWall->unused2 = bitReader.readUnsigned(2);
1085 pXWall->xpanFrac = bitReader.readUnsigned(8);
1086 pXWall->ypanFrac = bitReader.readUnsigned(8);
1087 pXWall->locked = bitReader.readUnsigned(1);
1088 pXWall->dudeLockout = bitReader.readUnsigned(1);
1089 pXWall->unused3 = bitReader.readUnsigned(4);
1090 pXWall->unused4 = bitReader.readUnsigned(32);
1091 xwall[wall[i].extra].reference = i;
1092 xwall[wall[i].extra].busy = xwall[wall[i].extra].state << 16;
1093
1094 }
1095 }
1096 initspritelists();
1097 for (int i = 0; i < mapHeader.at23; i++)
1098 {
1099 RemoveSpriteStat(i);
1100 spritetype *pSprite = &sprite[i];
1101 IOBuffer1.Read(pSprite, sizeof(spritetype));
1102 if (byte_1A76C8)
1103 {
1104 dbCrypt((char*)pSprite, sizeof(spritetype), (gMapRev*sizeof(spritetype)) | 0x7474614d);
1105 }
1106 #if B_BIG_ENDIAN == 1
1107 pSprite->x = B_LITTLE32(pSprite->x);
1108 pSprite->y = B_LITTLE32(pSprite->y);
1109 pSprite->z = B_LITTLE32(pSprite->z);
1110 pSprite->cstat = B_LITTLE16(pSprite->cstat);
1111 pSprite->picnum = B_LITTLE16(pSprite->picnum);
1112 pSprite->sectnum = B_LITTLE16(pSprite->sectnum);
1113 pSprite->statnum = B_LITTLE16(pSprite->statnum);
1114 pSprite->ang = B_LITTLE16(pSprite->ang);
1115 pSprite->owner = B_LITTLE16(pSprite->owner);
1116 pSprite->index = B_LITTLE16(pSprite->index);
1117 pSprite->yvel = B_LITTLE16(pSprite->yvel);
1118 pSprite->inittype = B_LITTLE16(pSprite->inittype);
1119 pSprite->type = B_LITTLE16(pSprite->type);
1120 pSprite->flags = B_LITTLE16(pSprite->hitag);
1121 pSprite->extra = B_LITTLE16(pSprite->extra);
1122 #endif
1123 InsertSpriteSect(i, sprite[i].sectnum);
1124 InsertSpriteStat(i, sprite[i].statnum);
1125 Numsprites++;
1126 sprite[i].index = i;
1127 qsprite_filler[i] = pSprite->blend;
1128 pSprite->blend = 0;
1129 if (sprite[i].extra > 0)
1130 {
1131 char pBuffer[nXSpriteSize];
1132 int nXSprite = dbInsertXSprite(i);
1133 XSPRITE *pXSprite = &xsprite[nXSprite];
1134 memset(pXSprite, 0, sizeof(XSPRITE));
1135 int nCount;
1136 if (!byte_1A76C8)
1137 {
1138 nCount = nXSpriteSize;
1139 }
1140 else
1141 {
1142 nCount = byte_19AE44.at40;
1143 }
1144 dassert(nCount <= nXSpriteSize);
1145 IOBuffer1.Read(pBuffer, nCount);
1146 BitReader bitReader(pBuffer, nCount);
1147 pXSprite->reference = bitReader.readSigned(14);
1148 pXSprite->state = bitReader.readUnsigned(1);
1149 pXSprite->busy = bitReader.readUnsigned(17);
1150 pXSprite->txID = bitReader.readUnsigned(10);
1151 pXSprite->rxID = bitReader.readUnsigned(10);
1152 pXSprite->command = bitReader.readUnsigned(8);
1153 pXSprite->triggerOn = bitReader.readUnsigned(1);
1154 pXSprite->triggerOff = bitReader.readUnsigned(1);
1155 pXSprite->wave = bitReader.readUnsigned(2);
1156 pXSprite->busyTime = bitReader.readUnsigned(12);
1157 pXSprite->waitTime = bitReader.readUnsigned(12);
1158 pXSprite->restState = bitReader.readUnsigned(1);
1159 pXSprite->Interrutable = bitReader.readUnsigned(1);
1160 pXSprite->unused1 = bitReader.readUnsigned(2);
1161 pXSprite->respawnPending = bitReader.readUnsigned(2);
1162 pXSprite->unused2 = bitReader.readUnsigned(1);
1163 pXSprite->lT = bitReader.readUnsigned(1);
1164 pXSprite->dropMsg = bitReader.readUnsigned(8);
1165 pXSprite->Decoupled = bitReader.readUnsigned(1);
1166 pXSprite->triggerOnce = bitReader.readUnsigned(1);
1167 pXSprite->isTriggered = bitReader.readUnsigned(1);
1168 pXSprite->key = bitReader.readUnsigned(3);
1169 pXSprite->Push = bitReader.readUnsigned(1);
1170 pXSprite->Vector = bitReader.readUnsigned(1);
1171 pXSprite->Impact = bitReader.readUnsigned(1);
1172 pXSprite->Pickup = bitReader.readUnsigned(1);
1173 pXSprite->Touch = bitReader.readUnsigned(1);
1174 pXSprite->Sight = bitReader.readUnsigned(1);
1175 pXSprite->Proximity = bitReader.readUnsigned(1);
1176 pXSprite->unused3 = bitReader.readUnsigned(2);
1177 pXSprite->lSkill = bitReader.readUnsigned(5);
1178 pXSprite->lS = bitReader.readUnsigned(1);
1179 pXSprite->lB = bitReader.readUnsigned(1);
1180 pXSprite->lC = bitReader.readUnsigned(1);
1181 pXSprite->DudeLockout = bitReader.readUnsigned(1);
1182 pXSprite->data1 = bitReader.readSigned(16);
1183 pXSprite->data2 = bitReader.readSigned(16);
1184 pXSprite->data3 = bitReader.readSigned(16);
1185 pXSprite->goalAng = bitReader.readUnsigned(11);
1186 pXSprite->dodgeDir = bitReader.readSigned(2);
1187 pXSprite->locked = bitReader.readUnsigned(1);
1188 pXSprite->medium = bitReader.readUnsigned(2);
1189 pXSprite->respawn = bitReader.readUnsigned(2);
1190 pXSprite->data4 = bitReader.readUnsigned(16);
1191 pXSprite->unused4 = bitReader.readUnsigned(6);
1192 pXSprite->lockMsg = bitReader.readUnsigned(8);
1193 pXSprite->health = bitReader.readUnsigned(12);
1194 pXSprite->dudeDeaf = bitReader.readUnsigned(1);
1195 pXSprite->dudeAmbush = bitReader.readUnsigned(1);
1196 pXSprite->dudeGuard = bitReader.readUnsigned(1);
1197 pXSprite->dudeFlag4 = bitReader.readUnsigned(1);
1198 pXSprite->target = bitReader.readSigned(16);
1199 pXSprite->targetX = bitReader.readSigned(32);
1200 pXSprite->targetY = bitReader.readSigned(32);
1201 pXSprite->targetZ = bitReader.readSigned(32);
1202 pXSprite->burnTime = bitReader.readUnsigned(16);
1203 pXSprite->burnSource = bitReader.readSigned(16);
1204 pXSprite->height = bitReader.readUnsigned(16);
1205 pXSprite->stateTimer = bitReader.readUnsigned(16);
1206 pXSprite->aiState = NULL;
1207 bitReader.skipBits(32);
1208 xsprite[sprite[i].extra].reference = i;
1209 xsprite[sprite[i].extra].busy = xsprite[sprite[i].extra].state << 16;
1210 if (!byte_1A76C8) {
1211 xsprite[sprite[i].extra].lT |= xsprite[sprite[i].extra].lB;
1212 }
1213
1214 #ifdef NOONE_EXTENSIONS
1215 // indicate if the map requires modern features to work properly
1216 // for maps wich created in different editors (include vanilla MAPEDIT) or in PMAPEDIT version below than BETA13
1217 if (!gModernMap && pXSprite->rxID == kChannelMapModernize && pXSprite->rxID == pXSprite->txID && pXSprite->command == kCmdModernFeaturesEnable)
1218 gModernMap = true;
1219 #endif
1220 }
1221 #if 0
1222 if ((sprite[i].cstat & 0x30) == 0x30)
1223 {
1224 sprite[i].cstat &= ~0x30;
1225 }
1226 #endif
1227 }
1228 unsigned int nCRC;
1229 IOBuffer1.Read(&nCRC, 4);
1230 #if B_BIG_ENDIAN == 1
1231 nCRC = B_LITTLE32(nCRC);
1232 #endif
1233 md4once((unsigned char*)pData, nSize, g_loadedMapHack.md4);
1234 if (Bcrc32(pData, nSize-4, 0) != nCRC)
1235 {
1236 initprintf("Map File does not match CRC");
1237 gSysRes.Unlock(pNode);
1238 return -1;
1239 }
1240 if (pCRC)
1241 *pCRC = nCRC;
1242 gSysRes.Unlock(pNode);
1243 PropagateMarkerReferences();
1244 if (byte_1A76C8)
1245 {
1246 if (gSongId == 0x7474614d || gSongId == 0x4d617474)
1247 {
1248 byte_1A76C6 = 1;
1249 }
1250 else if (!gSongId)
1251 {
1252 byte_1A76C6 = 0;
1253 }
1254 else
1255 {
1256 initprintf("Corrupted Map file");
1257 gSysRes.Unlock(pNode);
1258 return -1;
1259 }
1260 }
1261 else if (gSongId != 0)
1262 {
1263 initprintf("Corrupted Map file");
1264 gSysRes.Unlock(pNode);
1265 return -1;
1266 }
1267
1268 #ifdef POLYMER
1269 if (videoGetRenderMode() == REND_POLYMER)
1270 polymer_loadboard();
1271 #endif
1272
1273 if ((header.version & 0xff00) == 0x600)
1274 {
1275 switch (header.version&0xff)
1276 {
1277 case 0:
1278 for (int i = 0; i < numsectors; i++)
1279 {
1280 sectortype *pSector = §or[i];
1281 if (pSector->extra > 0)
1282 {
1283 XSECTOR *pXSector = &xsector[pSector->extra];
1284 pXSector->busyTimeB = pXSector->busyTimeA;
1285 if (pXSector->busyTimeA > 0)
1286 {
1287 if (!pXSector->restState)
1288 {
1289 pXSector->reTriggerA = 1;
1290 }
1291 else
1292 {
1293 pXSector->waitTimeB = pXSector->busyTimeA;
1294 pXSector->waitTimeA = 0;
1295 pXSector->reTriggerB = 1;
1296 }
1297 }
1298 }
1299 }
1300 fallthrough__;
1301 case 1:
1302 for (int i = 0; i < numsectors; i++)
1303 {
1304 sectortype *pSector = §or[i];
1305 if (pSector->extra > 0)
1306 {
1307 XSECTOR *pXSector = &xsector[pSector->extra];
1308 pXSector->freq >>= 1;
1309 }
1310 }
1311 fallthrough__;
1312 case 2:
1313 for (int i = 0; i < kMaxSprites; i++)
1314 {
1315 }
1316 break;
1317
1318 }
1319 }
1320
1321 #ifdef YAX_ENABLE
1322 yax_update((header.version & 0xff00) > 0x700 ? 0 : 1);
1323 if (editstatus)
1324 yax_updategrays(*pZ);
1325 #endif
1326
1327 g_loadedMapVersion = 7;
1328
1329 return 0;
1330 }
1331
dbSaveMap(const char * pPath,int nX,int nY,int nZ,short nAngle,short nSector)1332 int dbSaveMap(const char *pPath, int nX, int nY, int nZ, short nAngle, short nSector)
1333 {
1334 char sMapExt[BMAX_PATH];
1335 char sBakExt[BMAX_PATH];
1336 int16_t tpskyoff[256];
1337 int nSpriteNum;
1338 psky_t *pSky = tileSetupSky(0);
1339 gSkyCount = 1<<pSky->lognumtiles;
1340 gMapRev++;
1341 nSpriteNum = 0;
1342 strcpy(sMapExt, pPath);
1343 ChangeExtension(sMapExt, ".MAP");
1344 int nSize = sizeof(MAPSIGNATURE)+sizeof(MAPHEADER);
1345 if (byte_1A76C8)
1346 {
1347 nSize += sizeof(MAPHEADER2);
1348 }
1349 for (int i = 0; i < gSkyCount; i++)
1350 tpskyoff[i] = pSky->tileofs[i];
1351 nSize += gSkyCount*sizeof(tpskyoff[0]);
1352 nSize += sizeof(sectortype)*numsectors;
1353 for (int i = 0; i < numsectors; i++)
1354 {
1355 if (sector[i].extra > 0)
1356 {
1357 nSize += nXSectorSize;
1358 }
1359 }
1360 nSize += sizeof(walltype)*numwalls;
1361 for (int i = 0; i < numwalls; i++)
1362 {
1363 if (wall[i].extra > 0)
1364 {
1365 nSize += nXWallSize;
1366 }
1367 }
1368 for (int i = 0; i < kMaxSprites; i++)
1369 {
1370 if (sprite[i].statnum < kMaxStatus)
1371 {
1372 nSpriteNum++;
1373 if (sprite[i].extra > 0)
1374 {
1375 nSize += nXSpriteSize;
1376 }
1377 }
1378 }
1379 nSize += sizeof(spritetype)*nSpriteNum;
1380 nSize += 4;
1381 char *pData = (char*)Xmalloc(nSize);
1382 IOBuffer IOBuffer1 = IOBuffer(nSize, pData);
1383 MAPSIGNATURE header;
1384 memcpy(&header, "BLM\x1a", 4);
1385 if (byte_1A76C8)
1386 {
1387 header.version = 0x700;
1388 byte_1A76C7 = 1;
1389 }
1390 else
1391 {
1392 header.version = 0x603;
1393 byte_1A76C7 = 0;
1394 }
1395 IOBuffer1.Write(&header, sizeof(header));
1396 MAPHEADER mapheader;
1397 mapheader.at0 = B_LITTLE32(nX);
1398 mapheader.at4 = B_LITTLE32(nY);
1399 mapheader.at8 = B_LITTLE32(nZ);
1400 mapheader.atc = B_LITTLE16(nAngle);
1401 mapheader.ate = B_LITTLE16(nSector);
1402 mapheader.at10 = B_LITTLE16(pSky->lognumtiles);
1403 mapheader.at12 = B_LITTLE32(gVisibility);
1404 if (byte_1A76C6)
1405 {
1406 gSongId = 0x7474614d;
1407 }
1408 else
1409 {
1410 gSongId = 0;
1411 }
1412 mapheader.at16 = B_LITTLE32(gSongId);
1413 mapheader.at1a = parallaxtype;
1414 mapheader.at1b = gMapRev;
1415 mapheader.at1f = B_LITTLE16(numsectors);
1416 mapheader.at21 = B_LITTLE16(numwalls);
1417 mapheader.at23 = B_LITTLE16(nSpriteNum);
1418 if (byte_1A76C7)
1419 {
1420 dbCrypt((char*)&mapheader, sizeof(MAPHEADER), 'ttaM');
1421 }
1422 IOBuffer1.Write(&mapheader, sizeof(MAPHEADER));
1423 if (byte_1A76C8)
1424 {
1425 Bstrcpy(byte_19AE44.at0, AppProperName);
1426 byte_19AE44.at48 = nXSectorSize;
1427 byte_19AE44.at44 = nXWallSize;
1428 byte_19AE44.at40 = nXSpriteSize;
1429 dbCrypt((char*)&byte_19AE44, sizeof(MAPHEADER2), numwalls);
1430 IOBuffer1.Write(&byte_19AE44, sizeof(MAPHEADER2));
1431 dbCrypt((char*)&byte_19AE44, sizeof(MAPHEADER2), numwalls);
1432 }
1433 if (byte_1A76C8)
1434 {
1435 dbCrypt((char*)tpskyoff, gSkyCount*sizeof(tpskyoff[0]), gSkyCount*sizeof(tpskyoff[0]));
1436 }
1437 IOBuffer1.Write(tpskyoff, gSkyCount*sizeof(tpskyoff[0]));
1438 if (byte_1A76C8)
1439 {
1440 dbCrypt((char*)tpskyoff, gSkyCount*sizeof(tpskyoff[0]), gSkyCount*sizeof(tpskyoff[0]));
1441 }
1442 for (int i = 0; i < numsectors; i++)
1443 {
1444 if (byte_1A76C8)
1445 {
1446 dbCrypt((char*)§or[i], sizeof(sectortype), gMapRev*sizeof(sectortype));
1447 }
1448 IOBuffer1.Write(§or[i], sizeof(sectortype));
1449 if (byte_1A76C8)
1450 {
1451 dbCrypt((char*)§or[i], sizeof(sectortype), gMapRev*sizeof(sectortype));
1452 }
1453 if (sector[i].extra > 0)
1454 {
1455 char pBuffer[nXSectorSize];
1456 BitWriter bitWriter(pBuffer, nXSectorSize);
1457 XSECTOR* pXSector = &xsector[sector[i].extra];
1458 bitWriter.write(pXSector->reference, 14);
1459 bitWriter.write(pXSector->state, 1);
1460 bitWriter.write(pXSector->busy, 17);
1461 bitWriter.write(pXSector->data, 16);
1462 bitWriter.write(pXSector->txID, 10);
1463 bitWriter.write(pXSector->busyWaveA, 3);
1464 bitWriter.write(pXSector->busyWaveB, 3);
1465 bitWriter.write(pXSector->rxID, 10);
1466 bitWriter.write(pXSector->command, 8);
1467 bitWriter.write(pXSector->triggerOn, 1);
1468 bitWriter.write(pXSector->triggerOff, 1);
1469 bitWriter.write(pXSector->busyTimeA, 12);
1470 bitWriter.write(pXSector->waitTimeA, 12);
1471 bitWriter.write(pXSector->restState, 1);
1472 bitWriter.write(pXSector->interruptable, 1);
1473 bitWriter.write(pXSector->amplitude, 8);
1474 bitWriter.write(pXSector->freq, 8);
1475 bitWriter.write(pXSector->reTriggerA, 1);
1476 bitWriter.write(pXSector->reTriggerB, 1);
1477 bitWriter.write(pXSector->phase, 8);
1478 bitWriter.write(pXSector->wave, 4);
1479 bitWriter.write(pXSector->shadeAlways, 1);
1480 bitWriter.write(pXSector->shadeFloor, 1);
1481 bitWriter.write(pXSector->shadeCeiling, 1);
1482 bitWriter.write(pXSector->shadeWalls, 1);
1483 bitWriter.write(pXSector->shade, 8);
1484 bitWriter.write(pXSector->panAlways, 1);
1485 bitWriter.write(pXSector->panFloor, 1);
1486 bitWriter.write(pXSector->panCeiling, 1);
1487 bitWriter.write(pXSector->Drag, 1);
1488 bitWriter.write(pXSector->Underwater, 1);
1489 bitWriter.write(pXSector->Depth, 3);
1490 bitWriter.write(pXSector->panVel, 8);
1491 bitWriter.write(pXSector->panAngle, 11);
1492 bitWriter.write(pXSector->unused1, 1);
1493 bitWriter.write(pXSector->decoupled, 1);
1494 bitWriter.write(pXSector->triggerOnce, 1);
1495 bitWriter.write(pXSector->isTriggered, 1);
1496 bitWriter.write(pXSector->Key, 3);
1497 bitWriter.write(pXSector->Push, 1);
1498 bitWriter.write(pXSector->Vector, 1);
1499 bitWriter.write(pXSector->Reserved, 1);
1500 bitWriter.write(pXSector->Enter, 1);
1501 bitWriter.write(pXSector->Exit, 1);
1502 bitWriter.write(pXSector->Wallpush, 1);
1503 bitWriter.write(pXSector->color, 1);
1504 bitWriter.write(pXSector->unused2, 1);
1505 bitWriter.write(pXSector->busyTimeB, 12);
1506 bitWriter.write(pXSector->waitTimeB, 12);
1507 bitWriter.write(pXSector->stopOn, 1);
1508 bitWriter.write(pXSector->stopOff, 1);
1509 bitWriter.write(pXSector->ceilpal, 4);
1510 bitWriter.write(pXSector->offCeilZ, 32);
1511 bitWriter.write(pXSector->onCeilZ, 32);
1512 bitWriter.write(pXSector->offFloorZ, 32);
1513 bitWriter.write(pXSector->onFloorZ, 32);
1514 bitWriter.write(pXSector->marker0, 16);
1515 bitWriter.write(pXSector->marker1, 16);
1516 bitWriter.write(pXSector->Crush, 1);
1517 bitWriter.write(pXSector->ceilXPanFrac, 8);
1518 bitWriter.write(pXSector->ceilYPanFrac, 8);
1519 bitWriter.write(pXSector->floorXPanFrac, 8);
1520 bitWriter.write(pXSector->damageType, 3);
1521 bitWriter.write(pXSector->floorpal, 4);
1522 bitWriter.write(pXSector->floorYPanFrac, 8);
1523 bitWriter.write(pXSector->locked, 1);
1524 bitWriter.write(pXSector->windVel, 10);
1525 bitWriter.write(pXSector->windAng, 11);
1526 bitWriter.write(pXSector->windAlways, 1);
1527 bitWriter.write(pXSector->dudeLockout, 1);
1528 bitWriter.write(pXSector->bobTheta, 11);
1529 bitWriter.write(pXSector->bobZRange, 5);
1530 bitWriter.write(pXSector->bobSpeed, 12);
1531 bitWriter.write(pXSector->bobAlways, 1);
1532 bitWriter.write(pXSector->bobFloor, 1);
1533 bitWriter.write(pXSector->bobCeiling, 1);
1534 bitWriter.write(pXSector->bobRotate, 1);
1535 IOBuffer1.Write(pBuffer, nXSectorSize);
1536 }
1537 }
1538 for (int i = 0; i < numwalls; i++)
1539 {
1540 if (byte_1A76C8)
1541 {
1542 dbCrypt((char*)&wall[i], sizeof(walltype), gMapRev*sizeof(sectortype) | 0x7474614d);
1543 }
1544 IOBuffer1.Write(&wall[i], sizeof(walltype));
1545 if (byte_1A76C8)
1546 {
1547 dbCrypt((char*)&wall[i], sizeof(walltype), gMapRev*sizeof(sectortype) | 0x7474614d);
1548 }
1549 if (wall[i].extra > 0)
1550 {
1551 char pBuffer[nXWallSize];
1552 BitWriter bitWriter(pBuffer, nXWallSize);
1553 XWALL* pXWall = &xwall[wall[i].extra];
1554 bitWriter.write(pXWall->reference, 14);
1555 bitWriter.write(pXWall->state, 1);
1556 bitWriter.write(pXWall->busy, 17);
1557 bitWriter.write(pXWall->data, 16);
1558 bitWriter.write(pXWall->txID, 10);
1559 bitWriter.write(pXWall->unused1, 6);
1560 bitWriter.write(pXWall->rxID, 10);
1561 bitWriter.write(pXWall->command, 8);
1562 bitWriter.write(pXWall->triggerOn, 1);
1563 bitWriter.write(pXWall->triggerOff, 1);
1564 bitWriter.write(pXWall->busyTime, 12);
1565 bitWriter.write(pXWall->waitTime, 12);
1566 bitWriter.write(pXWall->restState, 1);
1567 bitWriter.write(pXWall->interruptable, 1);
1568 bitWriter.write(pXWall->panAlways, 1);
1569 bitWriter.write(pXWall->panXVel, 8);
1570 bitWriter.write(pXWall->panYVel, 8);
1571 bitWriter.write(pXWall->decoupled, 1);
1572 bitWriter.write(pXWall->triggerOnce, 1);
1573 bitWriter.write(pXWall->isTriggered, 1);
1574 bitWriter.write(pXWall->key, 3);
1575 bitWriter.write(pXWall->triggerPush, 1);
1576 bitWriter.write(pXWall->triggerVector, 1);
1577 bitWriter.write(pXWall->triggerTouch, 1);
1578 bitWriter.write(pXWall->unused2, 2);
1579 bitWriter.write(pXWall->xpanFrac, 8);
1580 bitWriter.write(pXWall->ypanFrac, 8);
1581 bitWriter.write(pXWall->locked, 1);
1582 bitWriter.write(pXWall->dudeLockout, 1);
1583 bitWriter.write(pXWall->unused3, 4);
1584 bitWriter.write(pXWall->unused4, 32);
1585 IOBuffer1.Write(pBuffer, nXWallSize);
1586 }
1587 }
1588 for (int i = 0; i < kMaxSprites; i++)
1589 {
1590 if (sprite[i].statnum < kMaxStatus)
1591 {
1592 if (byte_1A76C8)
1593 {
1594 dbCrypt((char*)&sprite[i], sizeof(spritetype), gMapRev*sizeof(spritetype) | 'ttaM');
1595 }
1596 IOBuffer1.Write(&sprite[i], sizeof(spritetype));
1597 if (byte_1A76C8)
1598 {
1599 dbCrypt((char*)&sprite[i], sizeof(spritetype), gMapRev*sizeof(spritetype) | 'ttaM');
1600 }
1601 if (sprite[i].extra > 0)
1602 {
1603 char pBuffer[nXSpriteSize];
1604 BitWriter bitWriter(pBuffer, nXSpriteSize);
1605 XSPRITE* pXSprite = &xsprite[sprite[i].extra];
1606 bitWriter.write(pXSprite->reference, 14);
1607 bitWriter.write(pXSprite->state, 1);
1608 bitWriter.write(pXSprite->busy, 17);
1609 bitWriter.write(pXSprite->txID, 10);
1610 bitWriter.write(pXSprite->rxID, 10);
1611 bitWriter.write(pXSprite->command, 8);
1612 bitWriter.write(pXSprite->triggerOn, 1);
1613 bitWriter.write(pXSprite->triggerOff, 1);
1614 bitWriter.write(pXSprite->wave, 2);
1615 bitWriter.write(pXSprite->busyTime, 12);
1616 bitWriter.write(pXSprite->waitTime, 12);
1617 bitWriter.write(pXSprite->restState, 1);
1618 bitWriter.write(pXSprite->Interrutable, 1);
1619 bitWriter.write(pXSprite->unused1, 2);
1620 bitWriter.write(pXSprite->respawnPending, 2);
1621 bitWriter.write(pXSprite->unused2, 1);
1622 bitWriter.write(pXSprite->lT, 1);
1623 bitWriter.write(pXSprite->dropMsg, 8);
1624 bitWriter.write(pXSprite->Decoupled, 1);
1625 bitWriter.write(pXSprite->triggerOnce, 1);
1626 bitWriter.write(pXSprite->isTriggered, 1);
1627 bitWriter.write(pXSprite->key, 3);
1628 bitWriter.write(pXSprite->Push, 1);
1629 bitWriter.write(pXSprite->Vector, 1);
1630 bitWriter.write(pXSprite->Impact, 1);
1631 bitWriter.write(pXSprite->Pickup, 1);
1632 bitWriter.write(pXSprite->Touch, 1);
1633 bitWriter.write(pXSprite->Sight, 1);
1634 bitWriter.write(pXSprite->Proximity, 1);
1635 bitWriter.write(pXSprite->unused3, 2);
1636 bitWriter.write(pXSprite->lSkill, 5);
1637 bitWriter.write(pXSprite->lS, 1);
1638 bitWriter.write(pXSprite->lB, 1);
1639 bitWriter.write(pXSprite->lC, 1);
1640 bitWriter.write(pXSprite->DudeLockout, 1);
1641 bitWriter.write(pXSprite->data1, 16);
1642 bitWriter.write(pXSprite->data2, 16);
1643 bitWriter.write(pXSprite->data3, 16);
1644 bitWriter.write(pXSprite->goalAng, 11);
1645 bitWriter.write(pXSprite->dodgeDir, 2);
1646 bitWriter.write(pXSprite->locked, 1);
1647 bitWriter.write(pXSprite->medium, 2);
1648 bitWriter.write(pXSprite->respawn, 2);
1649 bitWriter.write(pXSprite->data4, 16);
1650 bitWriter.write(pXSprite->unused4, 6);
1651 bitWriter.write(pXSprite->lockMsg, 8);
1652 bitWriter.write(pXSprite->health, 12);
1653 bitWriter.write(pXSprite->dudeDeaf, 1);
1654 bitWriter.write(pXSprite->dudeAmbush, 1);
1655 bitWriter.write(pXSprite->dudeGuard, 1);
1656 bitWriter.write(pXSprite->dudeFlag4, 1);
1657 bitWriter.write(pXSprite->target, 16);
1658 bitWriter.write(pXSprite->targetX, 32);
1659 bitWriter.write(pXSprite->targetY, 32);
1660 bitWriter.write(pXSprite->targetZ, 32);
1661 bitWriter.write(pXSprite->burnTime, 16);
1662 bitWriter.write(pXSprite->burnSource, 16);
1663 bitWriter.write(pXSprite->height, 16);
1664 bitWriter.write(pXSprite->stateTimer, 16);
1665 IOBuffer1.Write(pBuffer, nXSpriteSize);
1666 }
1667 }
1668 }
1669 unsigned int nCRC = Bcrc32(pData, nSize-4, 0);
1670 IOBuffer1.Write(&nCRC, 4);
1671 int nHandle = Bopen(sMapExt, BO_BINARY|BO_TRUNC|BO_CREAT|BO_WRONLY, BS_IREAD|BS_IWRITE);
1672 if (nHandle == -1)
1673 {
1674 initprintf("Couldn't open \"%s\" for writing: %s\n", sMapExt, strerror(errno));
1675 Bfree(pData);
1676 return -1;
1677 }
1678 if (Bwrite(nHandle, pData, nSize) != nSize)
1679 {
1680 initprintf("Couldn't write to \"%s\": %s\n", sMapExt, strerror(errno));
1681 Bclose(nHandle);
1682 Bfree(pData);
1683 return -1;
1684 }
1685 Bclose(nHandle);
1686 Bfree(pData);
1687 return 0;
1688 #if 0
1689 char *pExt = strchr(sMapExt, '.');
1690 if (pExt)
1691 {
1692 *pExt = 0;
1693 }
1694 gSysRes.AddExternalResource(sMapExt, "MAP", nSize);
1695 DICTNODE *hMap = gSysRes.Lookup(sMapExt, "MAP");
1696 dassert(hMap != NULL);
1697 #endif
1698 }
1699
qloadboard(const char * filename,char flags,vec3_t * dapos,int16_t * daang,int16_t * dacursectnum)1700 int32_t qloadboard(const char* filename, char flags, vec3_t* dapos, int16_t* daang, int16_t* dacursectnum)
1701 {
1702 // NUKE-TODO: implement flags, see mapedit.cpp
1703 return dbLoadMap(filename, &dapos->x, &dapos->y, &dapos->z, (short*)daang, (short*)dacursectnum, NULL);
1704 }
1705
qsaveboard(const char * filename,const vec3_t * dapos,int16_t daang,int16_t dacursectnum)1706 int32_t qsaveboard(const char* filename, const vec3_t* dapos, int16_t daang, int16_t dacursectnum)
1707 {
1708 // NUKE-TODO: see mapedit.cpp
1709 byte_1A76C6 = byte_1A76C8 = byte_1A76C7 = 1;
1710 return dbSaveMap(filename, dapos->x, dapos->y, dapos->z, daang, dacursectnum);
1711 }
1712