db.cpp
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 "config.h" 35 #include "globals.h" 36 #include "blood.h" 37 #include "db.h" 38 #include "iob.h" 39 #include "eventq.h" 40 #include "levels.h" 41 #ifdef NOONE_EXTENSIONS 42 #include "nnexts.h" 43 #include "view.h" 44 #endif 45 46 #define kMapHeaderNew 0x7474614D // 'ttaM' signature 47 #define kMapHeaderOld 0x4D617474 // 'Matt' signature 48 49 #ifdef NOONE_EXTENSIONS 50 uint8_t gModernMap = false; 51 #endif // !NOONE_EXTENSIONS 52 53 54 unsigned short gStatCount[kMaxStatus + 1]; 55 56 XSPRITE xsprite[kMaxXSprites]; 57 XSECTOR xsector[kMaxXSectors]; 58 XWALL xwall[kMaxXWalls]; 59 60 SPRITEHIT gSpriteHit[kMaxXSprites]; 61 62 int xvel[kMaxSprites], yvel[kMaxSprites], zvel[kMaxSprites]; 63 64 #ifdef POLYMER 65 PolymerLight_t gPolymerLight[kMaxSprites]; 66 #endif 67 68 char qsprite_filler[kMaxSprites], qsector_filler[kMaxSectors]; 69 70 int gVisibility; 71 const char *gItemText[] = { 72 "Skull Key", 73 "Eye Key", 74 "Fire Key", 75 "Dagger Key", 76 "Spider Key", 77 "Moon Key", 78 "Key 7", 79 "Doctor's Bag", 80 "Medicine Pouch", 81 "Life Essence", 82 "Life Seed", 83 "Red Potion", 84 "Feather Fall", 85 "Limited Invisibility", 86 "INVULNERABILITY", 87 "Boots of Jumping", 88 "Raven Flight", 89 "Guns Akimbo", 90 "Diving Suit", 91 "Gas mask", 92 "Clone", 93 "Crystal Ball", 94 "Decoy", 95 "Doppleganger", 96 "Reflective shots", 97 "Beast Vision", 98 "ShadowCloak", 99 "Rage shroom", 100 "Delirium Shroom", 101 "Grow shroom", 102 "Shrink shroom", 103 "Death mask", 104 "Wine Goblet", 105 "Wine Bottle", 106 "Skull Grail", 107 "Silver Grail", 108 "Tome", 109 "Black Chest", 110 "Wooden Chest", 111 "Asbestos Armor", 112 "Basic Armor", 113 "Body Armor", 114 "Fire Armor", 115 "Spirit Armor", 116 "Super Armor", 117 "Blue Team Base", 118 "Red Team Base", 119 "Blue Flag", 120 "Red Flag", 121 "DUMMY", 122 "Level map", 123 }; 124 125 const char *gAmmoText[] = { 126 "Spray can", 127 "Bundle of TNT*", 128 "Bundle of TNT", 129 "Case of TNT", 130 "Proximity Detonator", 131 "Remote Detonator", 132 "Trapped Soul", 133 "4 shotgun shells", 134 "Box of shotgun shells", 135 "A few bullets", 136 "Voodoo Doll", 137 "OBSOLETE", 138 "Full drum of bullets", 139 "Tesla Charge", 140 "OBSOLETE", 141 "OBSOLETE", 142 "Flares", 143 "OBSOLETE", 144 "OBSOLETE", 145 "Gasoline Can", 146 NULL, 147 }; 148 149 const char *gWeaponText[] = { 150 "RANDOM", 151 "Sawed-off", 152 "Tommy Gun", 153 "Flare Pistol", 154 "Voodoo Doll", 155 "Tesla Cannon", 156 "Napalm Launcher", 157 "Pitchfork", 158 "Spray Can", 159 "Dynamite", 160 "Life Leech", 161 }; 162 163 164 165 uint32_t XSPRITE::CalcChecksum(void) 166 { 167 // This was originally written to calculate the checksum 168 // the way OUWB v1.21 does. Therefore, certain bits may 169 // be skipped or calculated in a different order. 170 uint32_t sum = 0; 171 sum += (reference&16383) | ((state&1)<<14) | ((busy&131071)<<15); 172 sum += (txID&1023) | ((rxID&1023)<<10) | ((command&255)<<20) | 173 ((triggerOn&1)<<28) | ((triggerOff&1)<<29) | ((wave&3)<<30); 174 sum += (busyTime&4095) | ((waitTime&4095)<<12) | 175 ((restState&1)<<24) | ((Interrutable&1)<<25) | 176 ((unused1&3)<<26) | ((respawnPending&3)<<28) | 177 ((unused2&1)<<30) | ((lT&1)<<31); 178 sum += (dropMsg&255) | ((Decoupled&1)<<8) | 179 ((triggerOnce&1)<<9) | ((isTriggered&1)<<10) | 180 ((key&7)<<11) | ((Push&1)<<14) | ((Vector&1)<<15) | 181 ((Impact&1)<<16) | ((Pickup&1)<<17) | ((Touch&1)<<18) | 182 ((Sight&1)<<19) | ((Proximity&1)<<20) | 183 ((unused3&3)<<21) | ((lSkill&31)<<23) | 184 ((lS&1)<<28) | ((lB&1)<<29) | ((lC&1)<<30) | ((DudeLockout&1)<<31); 185 sum += (data1&65535) | ((data2&65535)<<16); 186 sum += (data3&65535) | ((goalAng&2047)<<16) | ((dodgeDir&3)<<27) | 187 ((locked&1)<<29) | ((medium&3)<<30); 188 sum += (respawn&3) | ((data4&65535)<<2) | 189 ((unused4&63)<<18) | ((lockMsg&255)<<24); 190 sum += (health&4095) | ((dudeDeaf&1)<<12) | ((dudeAmbush&1)<<13) | 191 ((dudeGuard&1)<<14) | ((dudeFlag4&1)<<15) | ((target&65535)<<16); 192 sum += targetX&0xFFFFFFFF; 193 sum += targetY&0xFFFFFFFF; 194 sum += targetZ&0xFFFFFFFF; 195 sum += (burnTime&65535) | ((burnSource&65535)<<16); 196 sum += (height&65535) | ((stateTimer&65535)<<16); 197 // aiState is a state pointer. Exact pointer values depend on exe layout. 198 // For player sprites, it is apparently always set to 0. 199 sum += aiState ? (((uintptr_t)aiState)&0xFFFFFFFF) : 0; 200 return sum; 201 } 202 203 void dbCrypt(char *pPtr, int nLength, int nKey) 204 { 205 for (int i = 0; i < nLength; i++) 206 { 207 pPtr[i] = pPtr[i] ^ nKey; 208 nKey++; 209 } 210 } 211 212 #ifdef POLYMER 213 214 void DeleteLight(int32_t s) 215 { 216 if (gPolymerLight[s].lightId >= 0) 217 polymer_deletelight(gPolymerLight[s].lightId); 218 gPolymerLight[s].lightId = -1; 219 gPolymerLight[s].lightptr = NULL; 220 } 221 222 #endif 223 224 225 void InsertSpriteSect(int nSprite, int nSector) 226 { 227 dassert(nSprite >= 0 && nSprite < kMaxSprites); 228 dassert(nSector >= 0 && nSector < kMaxSectors); 229 int nOther = headspritesect[nSector]; 230 if (nOther >= 0) 231 { 232 prevspritesect[nSprite] = prevspritesect[nOther]; 233 nextspritesect[nSprite] = -1; 234 nextspritesect[prevspritesect[nOther]] = nSprite; 235 prevspritesect[nOther] = nSprite; 236 } 237 else 238 { 239 prevspritesect[nSprite] = nSprite; 240 nextspritesect[nSprite] = -1; 241 headspritesect[nSector] = nSprite; 242 } 243 sprite[nSprite].sectnum = nSector; 244 } 245 246 void RemoveSpriteSect(int nSprite) 247 { 248 dassert(nSprite >= 0 && nSprite < kMaxSprites); 249 int nSector = sprite[nSprite].sectnum; 250 dassert(nSector >= 0 && nSector < kMaxSectors); 251 int nOther = nextspritesect[nSprite]; 252 if (nOther < 0) 253 { 254 nOther = headspritesect[nSector]; 255 } 256 prevspritesect[nOther] = prevspritesect[nSprite]; 257 if (headspritesect[nSector] != nSprite) 258 { 259 nextspritesect[prevspritesect[nSprite]] = nextspritesect[nSprite]; 260 } 261 else 262 { 263 headspritesect[nSector] = nextspritesect[nSprite]; 264 } 265 sprite[nSprite].sectnum = -1; 266 } 267 268 void InsertSpriteStat(int nSprite, int nStat) 269 { 270 dassert(nSprite >= 0 && nSprite < kMaxSprites); 271 dassert(nStat >= 0 && nStat <= kMaxStatus); 272 int nOther = headspritestat[nStat]; 273 if (nOther >= 0) 274 { 275 prevspritestat[nSprite] = prevspritestat[nOther]; 276 nextspritestat[nSprite] = -1; 277 nextspritestat[prevspritestat[nOther]] = nSprite; 278 prevspritestat[nOther] = nSprite; 279 } 280 else 281 { 282 prevspritestat[nSprite] = nSprite; 283 nextspritestat[nSprite] = -1; 284 headspritestat[nStat] = nSprite; 285 } 286 sprite[nSprite].statnum = nStat; 287 gStatCount[nStat]++; 288 } 289 290 void RemoveSpriteStat(int nSprite) 291 { 292 dassert(nSprite >= 0 && nSprite < kMaxSprites); 293 int nStat = sprite[nSprite].statnum; 294 dassert(nStat >= 0 && nStat <= kMaxStatus); 295 int nOther = nextspritestat[nSprite]; 296 if (nOther < 0) 297 { 298 nOther = headspritestat[nStat]; 299 } 300 prevspritestat[nOther] = prevspritestat[nSprite]; 301 if (headspritestat[nStat] != nSprite) 302 { 303 nextspritestat[prevspritestat[nSprite]] = nextspritestat[nSprite]; 304 } 305 else 306 { 307 headspritestat[nStat] = nextspritestat[nSprite]; 308 } 309 sprite[nSprite].statnum = kStatNothing; 310 gStatCount[nStat]--; 311 } 312 313 void qinitspritelists(void) // Replace 314 { 315 for (short i = 0; i <= kMaxSectors; i++) 316 { 317 headspritesect[i] = -1; 318 } 319 for (short i = 0; i <= kMaxStatus; i++) 320 { 321 headspritestat[i] = -1; 322 } 323 int const nMaxSprites = VanillaMode() ? 4096 : kMaxSprites; 324 for (short i = 0; i < nMaxSprites; i++) 325 { 326 sprite[i].sectnum = -1; 327 sprite[i].index = -1; 328 InsertSpriteStat(i, kMaxStatus); 329 } 330 memset(gStatCount, 0, sizeof(gStatCount)); 331 Numsprites = 0; 332 } 333 334 int InsertSprite(int nSector, int nStat) 335 { 336 int nSprite = headspritestat[kMaxStatus]; 337 dassert(nSprite < kMaxSprites); 338 if (nSprite < 0) 339 { 340 return nSprite; 341 } 342 RemoveSpriteStat(nSprite); 343 spritetype *pSprite = &sprite[nSprite]; 344 memset(&sprite[nSprite], 0, sizeof(spritetype)); 345 InsertSpriteStat(nSprite, nStat); 346 InsertSpriteSect(nSprite, nSector); 347 pSprite->cstat = 128; 348 pSprite->clipdist = 32; 349 pSprite->xrepeat = pSprite->yrepeat = 64; 350 pSprite->owner = -1; 351 pSprite->extra = -1; 352 pSprite->index = nSprite; 353 xvel[nSprite] = yvel[nSprite] = zvel[nSprite] = 0; 354 qsprite_filler[nSprite] = 0; 355 356 #ifdef POLYMER 357 gPolymerLight[nSprite].lightId = -1; 358 #endif 359 360 Numsprites++; 361 362 return nSprite; 363 } 364 365 int qinsertsprite(short nSector, short nStat) // Replace 366 { 367 return InsertSprite(nSector, nStat); 368 } 369 370 int DeleteSprite(int nSprite) 371 { 372 #ifdef POLYMER 373 if (gPolymerLight[nSprite].lightptr != NULL && videoGetRenderMode() == REND_POLYMER) 374 DeleteLight(nSprite); 375 #endif 376 if (sprite[nSprite].extra > 0) 377 { 378 dbDeleteXSprite(sprite[nSprite].extra); 379 } 380 dassert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus); 381 RemoveSpriteStat(nSprite); 382 dassert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors); 383 RemoveSpriteSect(nSprite); 384 InsertSpriteStat(nSprite, kMaxStatus); 385 386 Numsprites--; 387 388 return nSprite; 389 } 390 391 int qdeletesprite(short nSprite) // Replace 392 { 393 return DeleteSprite(nSprite); 394 } 395 396 int ChangeSpriteSect(int nSprite, int nSector) 397 { 398 dassert(nSprite >= 0 && nSprite < kMaxSprites); 399 dassert(nSector >= 0 && nSector < kMaxSectors); 400 dassert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors); 401 RemoveSpriteSect(nSprite); 402 InsertSpriteSect(nSprite, nSector); 403 return 0; 404 } 405 406 int qchangespritesect(short nSprite, short nSector) 407 { 408 return ChangeSpriteSect(nSprite, nSector); 409 } 410 411 int ChangeSpriteStat(int nSprite, int nStatus) 412 { 413 dassert(nSprite >= 0 && nSprite < kMaxSprites); 414 dassert(nStatus >= 0 && nStatus < kMaxStatus); 415 dassert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus); 416 dassert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors); 417 RemoveSpriteStat(nSprite); 418 InsertSpriteStat(nSprite, nStatus); 419 return 0; 420 } 421 422 int qchangespritestat(short nSprite, short nStatus) 423 { 424 return ChangeSpriteStat(nSprite, nStatus); 425 } 426 427 unsigned short nextXSprite[kMaxXSprites]; 428 unsigned short nextXWall[kMaxXWalls]; 429 unsigned short nextXSector[kMaxXSectors]; 430 431 void InitFreeList(unsigned short *pList, int nCount) 432 { 433 for (int i = 1; i < nCount; i++) 434 { 435 pList[i] = i-1; 436 } 437 pList[0] = nCount - 1; 438 } 439 440 void InsertFree(unsigned short *pList, int nIndex) 441 { 442 pList[nIndex] = pList[0]; 443 pList[0] = nIndex; 444 } 445 446 unsigned short dbInsertXSprite(int nSprite) 447 { 448 int nXSprite = nextXSprite[0]; 449 nextXSprite[0] = nextXSprite[nXSprite]; 450 if (nXSprite == 0) 451 { 452 ThrowError("Out of free XSprites"); 453 } 454 memset(&xsprite[nXSprite], 0, sizeof(XSPRITE)); 455 #if 0 // this intentionally causes demos to desync like dos (eg: playing BLOOD002.DEM after finishing BLOOD001.DEM) - for notblood we'll disable it 456 if (!VanillaMode()) 457 #endif 458 memset(&gSpriteHit[nXSprite], 0, sizeof(SPRITEHIT)); 459 xsprite[nXSprite].reference = nSprite; 460 sprite[nSprite].extra = nXSprite; 461 return nXSprite; 462 } 463 464 void dbDeleteXSprite(int nXSprite) 465 { 466 dassert(xsprite[nXSprite].reference >= 0); 467 dassert(sprite[xsprite[nXSprite].reference].extra == nXSprite); 468 InsertFree(nextXSprite, nXSprite); 469 sprite[xsprite[nXSprite].reference].extra = -1; 470 xsprite[nXSprite].reference = -1; 471 } 472 473 unsigned short dbInsertXWall(int nWall) 474 { 475 int nXWall = nextXWall[0]; 476 nextXWall[0] = nextXWall[nXWall]; 477 if (nXWall == 0) 478 { 479 ThrowError("Out of free XWalls"); 480 } 481 memset(&xwall[nXWall], 0, sizeof(XWALL)); 482 xwall[nXWall].reference = nWall; 483 wall[nWall].extra = nXWall; 484 return nXWall; 485 } 486 487 void dbDeleteXWall(int nXWall) 488 { 489 dassert(xwall[nXWall].reference >= 0); 490 InsertFree(nextXWall, nXWall); 491 wall[xwall[nXWall].reference].extra = -1; 492 xwall[nXWall].reference = -1; 493 } 494 495 unsigned short dbInsertXSector(int nSector) 496 { 497 int nXSector = nextXSector[0]; 498 nextXSector[0] = nextXSector[nXSector]; 499 if (nXSector == 0) 500 { 501 ThrowError("Out of free XSectors"); 502 } 503 memset(&xsector[nXSector], 0, sizeof(XSECTOR)); 504 xsector[nXSector].reference = nSector; 505 sector[nSector].extra = nXSector; 506 return nXSector; 507 } 508 509 void dbDeleteXSector(int nXSector) 510 { 511 dassert(xsector[nXSector].reference >= 0); 512 InsertFree(nextXSector, nXSector); 513 sector[xsector[nXSector].reference].extra = -1; 514 xsector[nXSector].reference = -1; 515 } 516 517 void dbXSpriteClean(void) 518 { 519 for (int i = 0; i < kMaxSprites; i++) 520 { 521 int nXSprite = sprite[i].extra; 522 if (nXSprite == 0) 523 { 524 sprite[i].extra = -1; 525 } 526 if (sprite[i].statnum < kMaxStatus && nXSprite > 0) 527 { 528 dassert(nXSprite < kMaxXSprites); 529 if (xsprite[nXSprite].reference != i) 530 { 531 int nXSprite2 = dbInsertXSprite(i); 532 memcpy(&xsprite[nXSprite2], &xsprite[nXSprite], sizeof(XSPRITE)); 533 xsprite[nXSprite2].reference = i; 534 } 535 } 536 } 537 for (int i = 1; i < kMaxXSprites; i++) 538 { 539 int nSprite = xsprite[i].reference; 540 if (nSprite >= 0) 541 { 542 dassert(nSprite < kMaxSprites); 543 if (sprite[nSprite].statnum >= kMaxStatus || sprite[nSprite].extra != i) 544 { 545 InsertFree(nextXSprite, i); 546 xsprite[i].reference = -1; 547 } 548 } 549 } 550 } 551 552 void dbXWallClean(void) 553 { 554 for (int i = 0; i < numwalls; i++) 555 { 556 int nXWall = wall[i].extra; 557 if (nXWall == 0) 558 { 559 wall[i].extra = -1; 560 } 561 if (nXWall > 0) 562 { 563 dassert(nXWall < kMaxXWalls); 564 if (xwall[nXWall].reference == -1) 565 { 566 wall[i].extra = -1; 567 } 568 else 569 { 570 xwall[nXWall].reference = i; 571 } 572 } 573 } 574 for (int i = 0; i < numwalls; i++) 575 { 576 int nXWall = wall[i].extra; 577 if (nXWall > 0) 578 { 579 dassert(nXWall < kMaxXWalls); 580 if (xwall[nXWall].reference != i) 581 { 582 int nXWall2 = dbInsertXWall(i); 583 memcpy(&xwall[nXWall2], &xwall[nXWall], sizeof(XWALL)); 584 xwall[nXWall2].reference = i; 585 } 586 } 587 } 588 for (int i = 1; i < kMaxXWalls; i++) 589 { 590 int nWall = xwall[i].reference; 591 if (nWall >= 0) 592 { 593 dassert(nWall < kMaxWalls); 594 if (nWall >= numwalls || wall[nWall].extra != i) 595 { 596 InsertFree(nextXWall, i); 597 xwall[i].reference = -1; 598 } 599 } 600 } 601 } 602 603 void dbXSectorClean(void) 604 { 605 606 607 for (int i = 0; i < numsectors; i++) 608 { 609 int nXSector = sector[i].extra; 610 if (nXSector == 0) 611 { 612 sector[i].extra = -1; 613 } 614 if (nXSector > 0) 615 { 616 dassert(nXSector < kMaxXSectors); 617 if (xsector[nXSector].reference == -1) 618 { 619 sector[i].extra = -1; 620 } 621 else 622 { 623 xsector[nXSector].reference = i; 624 } 625 } 626 } 627 for (int i = 0; i < numsectors; i++) 628 { 629 int nXSector = sector[i].extra; 630 if (nXSector > 0) 631 { 632 dassert(nXSector < kMaxXSectors); 633 if (xsector[nXSector].reference != i) 634 { 635 int nXSector2 = dbInsertXSector(i); 636 memcpy(&xsector[nXSector2], &xsector[nXSector], sizeof(XSECTOR)); 637 xsector[nXSector2].reference = i; 638 } 639 } 640 } 641 for (int i = 1; i < kMaxXSectors; i++) 642 { 643 int nSector = xsector[i].reference; 644 if (nSector >= 0) 645 { 646 dassert(nSector < kMaxSectors); 647 if (nSector >= numsectors || sector[nSector].extra != i) 648 { 649 InsertFree(nextXSector, i); 650 xsector[i].reference = -1; 651 } 652 } 653 } 654 } 655 656 void dbInit(void) 657 { 658 InitFreeList(nextXSprite, kMaxXSprites); 659 for (int i = 1; i < kMaxXSprites; i++) 660 { 661 xsprite[i].reference = -1; 662 } 663 InitFreeList(nextXWall, kMaxXWalls); 664 for (int i = 1; i < kMaxXWalls; i++) 665 { 666 xwall[i].reference = -1; 667 } 668 InitFreeList(nextXSector, kMaxXSectors); 669 for (int i = 1; i < kMaxXSectors; i++) 670 { 671 xsector[i].reference = -1; 672 } 673 initspritelists(); 674 for (int i = 0; i < kMaxSprites; i++) 675 { 676 sprite[i].cstat = 128; 677 } 678 } 679 680 void PropagateMarkerReferences(void) 681 { 682 int nSprite, nNextSprite; 683 for (nSprite = headspritestat[kStatMarker]; nSprite != -1; nSprite = nNextSprite) { 684 685 nNextSprite = nextspritestat[nSprite]; 686 687 switch (sprite[nSprite].type) { 688 case kMarkerOff: 689 case kMarkerAxis: 690 case kMarkerWarpDest: { 691 int nOwner = sprite[nSprite].owner; 692 if (nOwner >= 0 && nOwner < numsectors) { 693 int nXSector = sector[nOwner].extra; 694 if (nXSector > 0 && nXSector < kMaxXSectors) { 695 xsector[nXSector].marker0 = nSprite; 696 continue; 697 } 698 } 699 } 700 break; 701 case kMarkerOn: { 702 int nOwner = sprite[nSprite].owner; 703 if (nOwner >= 0 && nOwner < numsectors) { 704 int nXSector = sector[nOwner].extra; 705 if (nXSector > 0 && nXSector < kMaxXSectors) { 706 xsector[nXSector].marker1 = nSprite; 707 continue; 708 } 709 } 710 } 711 break; 712 } 713 714 DeleteSprite(nSprite); 715 } 716 } 717 718 char dbIsBannedSpriteType(int nType) 719 { 720 const unsigned int nBannedType = gGameOptions.uSpriteBannedFlags; 721 if (nBannedType == BANNED_NONE) // no monsters banned, return 722 return 0; 723 char bBanned = 0; 724 725 // monsters 726 if (!bBanned && (nBannedType&BANNED_BATS)) 727 bBanned = nType == kDudeBat; 728 if (!bBanned && (nBannedType&BANNED_RATS)) 729 bBanned = nType == kDudeRat; 730 if (!bBanned && (nBannedType&BANNED_FISH)) 731 bBanned = (nType == kDudeGillBeast) || (nType == kDudeBoneEel); 732 if (!bBanned && (nBannedType&BANNED_HANDS)) 733 bBanned = nType == kDudeHand; 734 if (!bBanned && (nBannedType&BANNED_GHOSTS)) 735 bBanned = nType == kDudePhantasm; 736 if (!bBanned && (nBannedType&BANNED_SPIDERS)) 737 bBanned = (nType == kDudeSpiderBrown) || (nType == kDudeSpiderRed) || (nType == kDudeSpiderBlack); 738 if (!bBanned && (nBannedType&BANNED_TCALEBS)) 739 bBanned = nType == kDudeTinyCaleb; 740 if (!bBanned && (nBannedType&BANNED_HHOUNDS)) 741 bBanned = nType == kDudeHellHound; 742 743 // weapons 744 if (!bBanned && (nBannedType&BANNED_FLARE)) 745 bBanned = (nType == kItemWeaponFlarePistol) || (nType == kItemAmmoFlares); 746 if (!bBanned && (nBannedType&BANNED_SHOTGUN)) 747 bBanned = (nType == kItemWeaponSawedoff) || (nType == kItemAmmoSawedoffFew) || (nType == kItemAmmoSawedoffBox); 748 if (!bBanned && (nBannedType&BANNED_TOMMYGUN)) 749 bBanned = (nType == kItemWeaponTommygun) || (nType == kItemAmmoTommygunFew) || (nType == kItemAmmoTommygunDrum); 750 if (!bBanned && (nBannedType&BANNED_NAPALM)) 751 bBanned = (nType == kItemWeaponNapalmLauncher) || (nType == kItemAmmoGasolineCan); 752 if (!bBanned && (nBannedType&BANNED_TNT)) 753 bBanned = (nType == kItemWeaponTNT) || (nType == kItemAmmoTNTBundle) || (nType == kItemAmmoTNTBox); 754 if (!bBanned && (nBannedType&BANNED_SPRAYCAN)) 755 bBanned = (nType == kItemWeaponSprayCan) || (nType == kItemAmmoSprayCan); 756 if (!bBanned && (nBannedType&BANNED_TESLA)) 757 bBanned = (nType == kItemWeaponTeslaCannon) || (nType == kItemAmmoTeslaCharge); 758 if (!bBanned && (nBannedType&BANNED_LIFELEECH)) 759 bBanned = (nType == kItemWeaponLifeLeech) || (nType == kItemAmmoTrappedSoul); 760 if (!bBanned && (nBannedType&BANNED_VOODOO)) 761 bBanned = (nType == kItemWeaponVoodooDoll) || (nType == kItemAmmoVoodooDoll); 762 if (!bBanned && (nBannedType&BANNED_PROXY)) 763 bBanned = nType == kItemAmmoProxBombBundle; 764 if (!bBanned && (nBannedType&BANNED_REMOTE)) 765 bBanned = nType == kItemAmmoRemoteBombBundle; 766 767 // items 768 if (!bBanned && (nBannedType&BANNED_MEDKIT)) 769 bBanned = nType == kItemHealthDoctorBag; 770 if (!bBanned && (nBannedType&BANNED_LIFEESSENCE)) // life essence, and other misc healing items 771 bBanned = (nType == kItemHealthMedPouch) || (nType == kItemHealthLifeEssense) || (nType == kItemHealthRedPotion); 772 if (!bBanned && (nBannedType&BANNED_LIFESEED)) 773 bBanned = nType == kItemHealthLifeSeed; 774 if (!bBanned && (nBannedType&BANNED_SUPERARMOR)) 775 bBanned = nType == kItemArmorSuper; 776 if (!bBanned && (nBannedType&BANNED_CRYSTALBALL)) 777 bBanned = nType == kItemCrystalBall; 778 779 // powerups 780 if (!bBanned && (nBannedType&BANNED_JUMPBOOTS)) 781 bBanned = nType == kItemJumpBoots; 782 if (!bBanned && (nBannedType&BANNED_CLOAK)) 783 bBanned = nType == kItemShadowCloak; 784 if (!bBanned && (nBannedType&BANNED_DEATHMASK)) 785 bBanned = nType == kItemDeathMask; 786 if (!bBanned && (nBannedType&BANNED_AKIMBO)) 787 bBanned = nType == kItemTwoGuns; 788 if (!bBanned && (nBannedType&BANNED_REFLECT)) 789 bBanned = nType == kItemReflectShots; 790 791 return bBanned; 792 } 793 794 char dbIsBannedSprite(spritetype *pSprite, XSPRITE* pXSprite) 795 { 796 if (gGameOptions.uSpriteBannedFlags == BANNED_NONE) // no sprites banned, return 797 return 0; 798 const char bRemove = dbIsBannedSpriteType(pSprite->type); 799 if (bRemove && IsDudeSprite(pSprite) && pXSprite) 800 { 801 if (pXSprite->key > 0) // drop key 802 actDropObject(pSprite, kItemKeyBase + (pXSprite->key - 1)); 803 if (pXSprite->dropMsg > 0) // drop item 804 actDropObject(pSprite, pXSprite->dropMsg); 805 } 806 return bRemove; 807 } 808 809 static uint32_t curRandomizerSeed = 0; 810 static uint32_t curRandomizerSeedDudes = 0; 811 static uint32_t curRandomizerSeedThings = 0; 812 813 inline int dbRandomizerRNG(const int range) 814 { 815 curRandomizerSeed = (214013 * curRandomizerSeed + 2531011); 816 return mulscale15(((curRandomizerSeed >> 16) & 0x7FFF), range); 817 } 818 819 inline int dbRandomizerRNGDudes(const int range) 820 { 821 curRandomizerSeedDudes = (214013 * curRandomizerSeedDudes + 2531011); 822 return mulscale15(((curRandomizerSeedDudes >> 16) & 0x7FFF), range); 823 } 824 825 inline int dbRandomizerRNGThings(const int range) 826 { 827 curRandomizerSeedThings = (214013 * curRandomizerSeedThings + 2531011); 828 return mulscale15(((curRandomizerSeedThings >> 16) & 0x7FFF), range); 829 } 830 831 void dbRandomizerModeInit(void) 832 { 833 // if adding a new seed cheat, ensure that you do the following: 834 // - add the new entry to the switch statement in dbRandomizerMode() 835 // - updating range cheat range for dbRandomizerModeScale() 836 const char randomizerCheats[][sizeof(gzRandomizerSeed)] = 837 { 838 "AAAAAAAA", // phantoms only 839 "BUTCHERS", // butchers only 840 "SOULSEEK", // hands only 841 "EPISODE6", // cultists only 842 "GARGOYLE", // gargoyles only 843 "FLAMEDOG", // hell hounds only 844 "CAPYBARA", // rats only 845 "HURTSCAN", // shotgun/tommy gun cultists only 846 "HUGEFISH", // gill beasts only 847 "SHOCKING", // tesla cultists only 848 "CRUONITA", // boss types only 849 "BILLYRAY", // shotgun cultists only 850 "WEED420!", // cultists only but they're green (and make you dizzy on damage) 851 "BRAAAINS", // zombies only 852 "OKBOOMER", // tnt cultists only 853 "OKZOOMER", // tnt/tesla cultists only 854 "SNEAKYFU", // prone shotgun/tommy gun cultists only 855 }; 856 857 const uint32_t defaultSeed = 0xCA1EB666; 858 gGameOptions.nRandomizerCheat = -1; 859 if (gGameOptions.szRandomizerSeed[0] == '\0') // if seed is empty, generate a new one 860 { 861 if (gGameOptions.nGameType != kGameTypeSinglePlayer) // if in multiplayer, use a failsafe seed 862 curRandomizerSeed = defaultSeed; 863 else // in single-player 864 curRandomizerSeed = QRandom2(defaultSeed); 865 curRandomizerSeedThings = curRandomizerSeedDudes = curRandomizerSeed; 866 return; 867 } 868 869 for (int curCheat = 0; curCheat < (int)ARRAY_SSIZE(randomizerCheats); curCheat++) // compare seed against any cheat seed entries 870 { 871 for (int i = 0; i < (int)sizeof(gzRandomizerSeed); i++) 872 { 873 const char charSeed = toupper(gGameOptions.szRandomizerSeed[i]); 874 const char charSeedCheat = toupper(randomizerCheats[curCheat][i]); 875 if (charSeed != charSeedCheat) // if encountered a non-matching character, stop and check next entry 876 { 877 gGameOptions.nRandomizerCheat = -1; 878 break; 879 } 880 else if ((charSeedCheat == '\0') || ((i+1) == (int)sizeof(gzRandomizerSeed))) // if matched cheat seed completely and reached end of string 881 { 882 gGameOptions.nRandomizerCheat = curCheat; // set to seed cheat index 883 break; 884 } 885 } 886 if (gGameOptions.nRandomizerCheat != -1) // if found a match, stop searching 887 break; 888 } 889 890 if ((gGameOptions.nRandomizerCheat != -1) && (gGameOptions.nGameType == kGameTypeSinglePlayer)) // if seed cheat is active and in single-player 891 curRandomizerSeed = qrand(); // always re-roll random seed when cheat seed mode is active 892 else 893 curRandomizerSeed = defaultSeed; // reset seed 894 for (int i = 0; i < (int)sizeof(gGameOptions.szRandomizerSeed); i++) // shitty seed system, but if it works for the N64's CIC then who am I to judge 895 { 896 if (gGameOptions.szRandomizerSeed[i] == '\0') 897 break; 898 curRandomizerSeed += ~(toupper(gGameOptions.szRandomizerSeed[i])); 899 } 900 curRandomizerSeedThings = curRandomizerSeedDudes = curRandomizerSeed; 901 } 902 903 void dbRandomizerMode(spritetype *pSprite) 904 { 905 if (pSprite == NULL) // invalid sprite, don't bother processing 906 return; 907 if (!spriRangeIsFine(pSprite->index)) 908 return; 909 910 if ((gGameOptions.nRandomizerMode >= 2) && (pSprite->type == kItemBeastVision)) // always replace beast vision if pickups or enemies+pickups mode 911 { 912 const int pickupsrngtype[] = {kItemArmorBasic, kItemArmorBody, kItemArmorFire, kItemWeaponFlarePistol, kItemWeaponSawedoff, kItemWeaponTommygun, kItemAmmoTNTBox, kItemAmmoSawedoffBox, kItemAmmoTommygunDrum}; 913 const int pickupsrngpicnum[] = {2628, 2586, 2578, 524, 559, 558, 809, 812, 817}; 914 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 915 pSprite->type = pickupsrngtype[rng]; 916 pSprite->picnum = pickupsrngpicnum[rng]; 917 if ((pSprite->type < kThingBase) || (pSprite->type >= kThingMax)) // update sprite type 918 changespritestat(pSprite->index, kStatItem); 919 } 920 921 if ((gGameOptions.nRandomizerMode & 1) && (gGameOptions.nRandomizerCheat != -1)) // if enemies or enemies+weapons mode, and seed cheat is active, replace enemy 922 { 923 const int type = pSprite->type; 924 #ifdef NOONE_EXTENSIONS 925 if (type == kDudeModernCustom) // ignore custom dude types 926 return; 927 #endif 928 if ((type >= kDudeCultistTommy) && (type <= kDudeBurningBeast) && !(type >= kDudePlayer1 && type <= kDudePlayer8) && (type != kDudeCultistReserved) && (type != kDudeBeast) && (type != kDudeCultistBeast) && (type != kDudeGargoyleStone) && (type != kDudeTchernobog) && (type != kDudeCerberusTwoHead) && (type != kDudeCerberusOneHead) && (type != kDudeSpiderMother)) // filter problematic enemy types 929 { 930 pSprite->flags |= kPhysGravity; 931 switch (gGameOptions.nRandomizerCheat) // replace enemy according to cheat type 932 { 933 case 0: // "AAAAAAAA" - phantoms only 934 pSprite->type = kDudePhantasm; 935 break; 936 case 1: // "BUTCHERS" - butchers only 937 pSprite->type = kDudeZombieButcher; 938 break; 939 case 2: // "SOULSEEK" - hands only 940 pSprite->type = kDudeHand; 941 break; 942 case 3: // "EPISODE6" - cultists only 943 { 944 const int enemiesrng[] = {kDudeCultistTommy, kDudeCultistShotgun, kDudeCultistTommyProne, kDudeCultistShotgunProne, kDudeCultistTesla, kDudeCultistTNT}; 945 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 946 break; 947 } 948 case 4: // "GARGOYLE" - gargoyles only 949 pSprite->type = dbRandomizerRNGDudes(20) ? kDudeGargoyleFlesh : kDudeGargoyleStone; 950 pSprite->flags &= ~kPhysGravity; 951 break; 952 case 5: // "FLAMEDOG" - hell hounds only 953 pSprite->type = dbRandomizerRNGDudes(20) ? kDudeHellHound : kDudeCerberusOneHead; 954 break; 955 case 6: // "CAPYBARA" - rats only 956 pSprite->type = kDudeRat; 957 break; 958 case 7: // "HURTSCAN" - shotgun/tommy gun cultists only 959 { 960 const int enemiesrng[] = {kDudeCultistTommy, kDudeCultistShotgun, kDudeCultistTommyProne, kDudeCultistShotgunProne}; 961 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 962 break; 963 } 964 case 8: // "HUGEFISH" - gill beasts only 965 pSprite->type = kDudeGillBeast; 966 break; 967 case 9: // "SHOCKING" - tesla cultists only 968 pSprite->type = kDudeCultistTesla; 969 break; 970 case 10: // "CRUONITA" - boss types only 971 { 972 const int enemiesrng[] = {kDudeCultistBeast, kDudeTchernobog, kDudeCerberusTwoHead, kDudeSpiderMother, kDudeGargoyleStone}; 973 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 974 break; 975 } 976 case 11: // "BILLYRAY" - shotgun cultists only 977 { 978 const int enemiesrng[] = {kDudeCultistShotgun, kDudeCultistShotgunProne}; 979 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 980 break; 981 } 982 case 12: // "WEED420!" - cultists only but they're green (and make you dizzy on damage) 983 { 984 const int enemiesrng[] = {kDudeCultistShotgun, kDudeCultistShotgunProne, kDudeCultistTNT}; 985 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 986 pSprite->pal = 4; // DUDE WEED XDDD 420 bro 987 break; 988 } 989 case 13: // "BRAAAINS" - zombies only 990 pSprite->type = kDudeZombieAxeNormal; 991 break; 992 case 14: // "OKBOOMER" - tnt cultists only 993 pSprite->type = kDudeCultistTNT; 994 break; 995 case 15: // "OKZOOMER" - tnt/tesla cultists only 996 { 997 const int enemiesrng[] = {kDudeCultistTesla, kDudeCultistTNT}; 998 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 999 break; 1000 } 1001 case 16: // "SNEAKYFU" - prone shotgun/tommy gun cultists only 1002 { 1003 const int enemiesrng[] = {kDudeCultistShotgunProne, kDudeCultistTommyProne}; 1004 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1005 break; 1006 } 1007 default: // unknown cheat id, don't do anything 1008 { 1009 static char bShownError = 0; 1010 if (!bShownError) // only show once per session 1011 LOG_F(WARNING, "Error invalid cheat seed %s (%d)\nAdd seed cheat effect to func dbRandomizerMode()", gGameOptions.szRandomizerSeed, gGameOptions.nRandomizerCheat); 1012 bShownError = 1; 1013 break; 1014 } 1015 } 1016 if (gGameOptions.nRandomizerCheat != 12) 1017 pSprite->pal = 0; 1018 pSprite->cstat &= ~CSTAT_SPRITE_YFLIP; 1019 return; 1020 } 1021 } 1022 1023 if (!dbRandomizerRNG(5)) return; 1024 1025 if (gGameOptions.nRandomizerMode & 1) // if enemies or enemies+weapons mode, randomize enemy 1026 { 1027 switch (pSprite->type) 1028 { 1029 case kDudeInnocent: 1030 { 1031 const int enemiesrng[] = {kDudeBat, kDudeRat, kDudeZombieAxeNormal, kDudeGillBeast, kDudeHand, kDudeCultistShotgunProne}; 1032 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1033 break; 1034 } 1035 case kDudeBat: 1036 { 1037 const int enemiesrng[] = {kDudeRat, kDudeZombieAxeLaying, kDudeHand, kDudeInnocent, kDudeCultistTNT, kDudePhantasm}; 1038 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1039 pSprite->cstat &= ~CSTAT_SPRITE_YFLIP; 1040 break; 1041 } 1042 case kDudeRat: 1043 { 1044 const int enemiesrng[] = {kDudeBat, kDudeZombieAxeBuried, kDudeHand, kDudeTinyCaleb, kDudeSpiderBrown, kDudeSpiderRed}; 1045 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1046 break; 1047 } 1048 case kDudeZombieAxeBuried: 1049 { 1050 const int enemiesrng[] = {kDudeSpiderRed, kDudeZombieAxeLaying, kDudeGillBeast, kDudeZombieButcher, kDudeCultistShotgun, kDudeCultistTommy, kDudeCultistTNT}; 1051 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1052 break; 1053 } 1054 case kDudeZombieAxeLaying: 1055 { 1056 const int enemiesrng[] = {kDudeSpiderRed, kDudeZombieAxeBuried, kDudeGillBeast, kDudeZombieButcher, kDudeCultistShotgunProne, kDudeCultistTNT}; 1057 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1058 break; 1059 } 1060 case kDudeZombieAxeNormal: 1061 { 1062 const int enemiesrng[] = {kDudeZombieAxeBuried, kDudeZombieAxeLaying, kDudeGillBeast, kDudeZombieButcher, kDudeCultistShotgun, kDudeCultistTommy, kDudeTinyCaleb, kDudeCultistTNT}; 1063 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1064 break; 1065 } 1066 case kDudeBoneEel: 1067 { 1068 const int enemiesrng[] = {kDudeZombieAxeNormal, kDudeGillBeast, kDudeHand, kDudeCultistShotgunProne, kDudeInnocent, kDudeCultistTNT}; 1069 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1070 break; 1071 } 1072 case kDudeGillBeast: 1073 { 1074 const int enemiesrng[] = {kDudeZombieAxeNormal, kDudeZombieAxeLaying, kDudeZombieButcher, kDudeCultistShotgun, kDudeCultistTommy, kDudeCultistTNT, kDudeGargoyleFlesh, kDudeCultistShotgunProne, kDudeCultistTesla}; 1075 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1076 break; 1077 } 1078 case kDudeZombieButcher: 1079 { 1080 const int enemiesrng[] = {kDudeZombieAxeNormal, kDudeZombieAxeLaying, kDudeGillBeast, kDudeCultistShotgun, kDudeCultistTommy, kDudeCultistTNT, kDudeGargoyleFlesh, kDudePhantasm, kDudeCultistShotgunProne, kDudeHellHound, kDudeCultistTommyProne, kDudeCultistTesla}; 1081 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1082 break; 1083 } 1084 case kDudeSpiderBrown: 1085 case kDudeSpiderRed: 1086 { 1087 const int enemiesrng[] = {kDudeHand, kDudeTinyCaleb, kDudeCultistTNT, kDudeHellHound, kDudeCultistTommyProne, kDudeCultistShotgunProne}; 1088 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1089 break; 1090 } 1091 case kDudeSpiderBlack: 1092 { 1093 const int enemiesrng[] = {kDudeCultistTNT, kDudeGargoyleFlesh, kDudeCultistShotgunProne, kDudeHellHound, kDudeCultistTommyProne, kDudeCultistTesla, kDudeSpiderMother}; 1094 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1095 break; 1096 } 1097 case kDudePhantasm: 1098 { 1099 const int enemiesrng[] = {kDudeBat, kDudeHellHound, kDudeZombieButcher, kDudeCultistTNT, kDudeCultistTommyProne, kDudeGillBeast}; 1100 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1101 break; 1102 } 1103 case kDudeHand: 1104 case kDudeTinyCaleb: 1105 { 1106 const int enemiesrng[] = {kDudeSpiderBrown, kDudeSpiderRed, kDudeCultistTNT, kDudePhantasm, kDudeHellHound, kDudeCultistTommyProne, kDudeCultistShotgunProne, kDudeGillBeast, kDudeZombieAxeLaying}; 1107 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1108 break; 1109 } 1110 case kDudeTentacleGreen: 1111 case kDudeTentacleFire: 1112 { 1113 const int enemiesrng[] = {kDudePodFire, kDudePodGreen, kDudeCultistShotgunProne, kDudeCultistTommyProne, kDudeZombieAxeBuried}; 1114 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1115 break; 1116 } 1117 case kDudeCultistShotgun: 1118 case kDudeCultistTommy: 1119 { 1120 const int enemiesrng[] = {kDudeInnocent, kDudeZombieAxeBuried, kDudeZombieAxeNormal, kDudeGillBeast, kDudeCultistTesla, kDudeCultistTNT, kDudeCultistShotgun, kDudeCultistShotgunProne, kDudeCultistTommyProne}; 1121 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1122 break; 1123 } 1124 case kDudeCultistShotgunProne: 1125 case kDudeCultistTommyProne: 1126 { 1127 const int enemiesrng[] = {kDudeGillBeast, kDudeZombieAxeLaying, kDudeSpiderBlack, kDudeCultistShotgun, kDudeCultistTommy, kDudeCultistTNT, kDudeHellHound, kDudeCultistTesla}; 1128 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1129 break; 1130 } 1131 case kDudeCultistTNT: 1132 { 1133 const int enemiesrng[] = {kDudeZombieAxeNormal, kDudeGillBeast, kDudeZombieAxeLaying, kDudeCultistTommy, kDudeCultistShotgunProne, kDudeHellHound, kDudeCultistTommyProne, kDudeCultistTesla}; 1134 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1135 break; 1136 } 1137 case kDudeGargoyleFlesh: 1138 { 1139 const int enemiesrng[] = {kDudeBat, kDudeCultistTNT, kDudeHellHound, kDudeCultistTommyProne, kDudeCultistTesla}; 1140 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1141 break; 1142 } 1143 case kDudeHellHound: 1144 { 1145 const int enemiesrng[] = {kDudeCultistTNT, kDudeCultistTommyProne, kDudeCultistTesla, kDudeGargoyleFlesh}; 1146 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1147 break; 1148 } 1149 case kDudeCultistTesla: 1150 { 1151 const int enemiesrng[] = {kDudeCultistTesla, kDudeCultistTesla, kDudeCultistTesla, kDudeGargoyleStone, kDudeCerberusOneHead, kDudeCultistTommyProne, kDudeCultistTNT}; 1152 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1153 break; 1154 } 1155 case kDudeCerberusOneHead: 1156 case kDudeCerberusTwoHead: 1157 { 1158 const int enemiesrng[] = {kDudeCerberusTwoHead, kDudeGargoyleStone, kDudeTchernobog, kDudeHellHound, kDudeBeast}; 1159 pSprite->type = enemiesrng[dbRandomizerRNGDudes(ARRAY_SSIZE(enemiesrng))]; 1160 break; 1161 } 1162 default: 1163 break; 1164 } 1165 if (pSprite->type == kDudeGargoyleFlesh || pSprite->type == kDudeGargoyleStone || pSprite->type == kDudeBat) // set the correct flags needed for flying enemies 1166 pSprite->flags &= ~kPhysGravity; 1167 else 1168 pSprite->flags |= kPhysGravity; 1169 pSprite->pal = 0; 1170 } 1171 if (gGameOptions.nRandomizerMode >= 2) // if pickups or enemies+pickups mode, randomize pickup 1172 { 1173 const int nPicnumOrig = pSprite->picnum; 1174 int nTopOrig, nBottomOrig; 1175 GetSpriteExtents(pSprite, &nTopOrig, &nBottomOrig); 1176 1177 switch (pSprite->type) 1178 { 1179 case kItemWeaponFlarePistol: 1180 { 1181 const int pickupsrngtype[] = {kItemAmmoSprayCan, kItemWeaponTommygun, kItemWeaponTNT, kItemHealthLifeEssense}; 1182 const int pickupsrngpicnum[] = {618, 558, 589, 2169}; 1183 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1184 pSprite->type = pickupsrngtype[rng]; 1185 pSprite->picnum = pickupsrngpicnum[rng]; 1186 break; 1187 } 1188 case kItemWeaponSawedoff: 1189 { 1190 const int pickupsrngtype[] = {kItemWeaponTommygun, kItemAmmoSprayCan, kItemAmmoTNTBox}; 1191 const int pickupsrngpicnum[] = {558, 618, 809}; 1192 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1193 pSprite->type = pickupsrngtype[rng]; 1194 pSprite->picnum = pickupsrngpicnum[rng]; 1195 break; 1196 } 1197 case kItemWeaponTommygun: 1198 { 1199 const int pickupsrngtype[] = {kItemWeaponSawedoff, kItemWeaponFlarePistol, kItemAmmoTNTBox}; 1200 const int pickupsrngpicnum[] = {559, 524, 809}; 1201 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1202 pSprite->type = pickupsrngtype[rng]; 1203 pSprite->picnum = pickupsrngpicnum[rng]; 1204 break; 1205 } 1206 case kItemAmmoTNTBox: 1207 { 1208 const int pickupsrngtype[] = {kItemAmmoSprayCan, kItemAmmoRemoteBombBundle, kItemAmmoTNTBox}; 1209 const int pickupsrngpicnum[] = {618, 810, 809}; 1210 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1211 pSprite->type = pickupsrngtype[rng]; 1212 pSprite->picnum = pickupsrngpicnum[rng]; 1213 break; 1214 } 1215 case kItemWeaponTNT: 1216 case kItemAmmoTNTBundle: 1217 case kItemAmmoProxBombBundle: 1218 case kItemAmmoRemoteBombBundle: 1219 { 1220 const int pickupsrngtype[] = {kItemAmmoSprayCan, kItemAmmoSawedoffFew, kItemAmmoTommygunFew}; 1221 const int pickupsrngpicnum[] = {618, 619, 813}; 1222 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1223 pSprite->type = pickupsrngtype[rng]; 1224 pSprite->picnum = pickupsrngpicnum[rng]; 1225 break; 1226 } 1227 case kItemWeaponSprayCan: 1228 { 1229 const int pickupsrngtype[] = {kItemWeaponSawedoff, kItemAmmoTommygunFew}; 1230 const int pickupsrngpicnum[] = {559, 813}; 1231 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1232 pSprite->type = pickupsrngtype[rng]; 1233 pSprite->picnum = pickupsrngpicnum[rng]; 1234 break; 1235 } 1236 case kItemWeaponVoodooDoll: 1237 case kItemAmmoTrappedSoul: 1238 { 1239 const int pickupsrngtype[] = {kItemWeaponLifeLeech, kItemWeaponNapalmLauncher, kItemWeaponSawedoff, kItemHealthLifeSeed, kItemTwoGuns, kItemReflectShots, kItemWeaponTeslaCannon}; 1240 const int pickupsrngpicnum[] = {800, 526, 559, 2433, 829, 2428, 539}; 1241 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1242 pSprite->type = pickupsrngtype[rng]; 1243 pSprite->picnum = pickupsrngpicnum[rng]; 1244 break; 1245 } 1246 case kItemWeaponTeslaCannon: 1247 { 1248 const int pickupsrngtype[] = {kItemWeaponTommygun, kItemHealthLifeSeed, kItemShadowCloak, kItemReflectShots, kItemWeaponVoodooDoll}; 1249 const int pickupsrngpicnum[] = {558, 2433, 896, 2428, 525}; 1250 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1251 pSprite->type = pickupsrngtype[rng]; 1252 pSprite->picnum = pickupsrngpicnum[rng]; 1253 break; 1254 } 1255 case kItemWeaponNapalmLauncher: 1256 case kItemWeaponLifeLeech: 1257 case kItemArmorSuper: 1258 { 1259 const int pickupsrngtype[] = {kItemTwoGuns, kItemReflectShots, kItemWeaponVoodooDoll}; 1260 const int pickupsrngpicnum[] = {829, 2428, 525}; 1261 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1262 pSprite->type = pickupsrngtype[rng]; 1263 pSprite->picnum = pickupsrngpicnum[rng]; 1264 break; 1265 } 1266 case kItemHealthDoctorBag: 1267 { 1268 const int pickupsrngtype[] = {kItemHealthLifeEssense, kItemHealthLifeSeed, kItemAmmoSawedoffBox, kItemWeaponTeslaCannon}; 1269 const int pickupsrngpicnum[] = {2169, 2433, 812, 539}; 1270 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1271 pSprite->type = pickupsrngtype[rng]; 1272 pSprite->picnum = pickupsrngpicnum[rng]; 1273 break; 1274 } 1275 case kItemAmmoFlares: 1276 { 1277 const int pickupsrngtype[] = {kItemAmmoSprayCan, kItemAmmoRemoteBombBundle, kItemAmmoTNTBundle, kItemAmmoSprayCan, kItemAmmoTNTBox, kItemAmmoGasolineCan}; 1278 const int pickupsrngpicnum[] = {618, 810, 589, 618, 809, 801}; 1279 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1280 pSprite->type = pickupsrngtype[rng]; 1281 pSprite->picnum = pickupsrngpicnum[rng]; 1282 break; 1283 } 1284 case kItemAmmoSawedoffBox: 1285 { 1286 const int pickupsrngtype[] = {kItemAmmoTeslaCharge, kItemWeaponSawedoff, kItemAmmoSawedoffBox}; 1287 const int pickupsrngpicnum[] = {548, 559, 812}; 1288 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1289 pSprite->type = pickupsrngtype[rng]; 1290 pSprite->picnum = pickupsrngpicnum[rng]; 1291 break; 1292 } 1293 case kItemAmmoSawedoffFew: 1294 { 1295 const int pickupsrngtype[] = {kItemAmmoRemoteBombBundle, kItemAmmoTeslaCharge, kItemAmmoTommygunDrum}; 1296 const int pickupsrngpicnum[] = {810, 548, 817}; 1297 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1298 pSprite->type = pickupsrngtype[rng]; 1299 pSprite->picnum = pickupsrngpicnum[rng]; 1300 break; 1301 } 1302 case kItemAmmoTommygunFew: 1303 { 1304 const int pickupsrngtype[] = {kItemAmmoRemoteBombBundle, kItemAmmoTNTBundle, kItemAmmoSawedoffFew}; 1305 const int pickupsrngpicnum[] = {810, 589, 619}; 1306 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1307 pSprite->type = pickupsrngtype[rng]; 1308 pSprite->picnum = pickupsrngpicnum[rng]; 1309 break; 1310 } 1311 case kItemArmorBasic: 1312 case kItemArmorBody: 1313 case kItemArmorFire: 1314 case kItemArmorSpirit: 1315 { 1316 const int pickupsrngtype[] = {kItemArmorBasic, kItemArmorBody, kItemArmorFire, kItemArmorSpirit, kItemArmorSuper, kItemHealthLifeEssense, kItemHealthLifeSeed, kItemTwoGuns, kItemReflectShots, kItemShadowCloak, kItemHealthDoctorBag}; 1317 const int pickupsrngpicnum[] = {2628, 2586, 2578, 2602, 2594, 2169, 2433, 829, 2428, 896, 519}; 1318 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1319 pSprite->type = pickupsrngtype[rng]; 1320 pSprite->picnum = pickupsrngpicnum[rng]; 1321 break; 1322 } 1323 case kItemTwoGuns: 1324 case kItemReflectShots: 1325 { 1326 const int pickupsrngtype[] = {kItemTwoGuns, kItemReflectShots}; 1327 const int pickupsrngpicnum[] = {829, 2428}; 1328 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1329 pSprite->type = pickupsrngtype[rng]; 1330 pSprite->picnum = pickupsrngpicnum[rng]; 1331 break; 1332 } 1333 case kThingObjectGib: // generic breakable objects 1334 { 1335 if (pSprite->statnum != kStatThing) // unexpected type, don't replace 1336 break; 1337 if (xspriRangeIsFine(pSprite->extra)) 1338 { 1339 XSPRITE *pXSprite = &xsprite[pSprite->extra]; 1340 if (pXSprite->key > 0) // sprite has key attached, don't replace 1341 break; 1342 if (pXSprite->dropMsg > 0) // item has item attached, don't replace 1343 break; 1344 } 1345 switch (pSprite->picnum) 1346 { 1347 case 520: // skull cup 1348 case 521: // wine glass (half-empty) 1349 case 574: // wine glass (empty) 1350 case 759: // wine bottle 1351 { 1352 const int pickupsrngtype[] = {kItemAmmoSawedoffFew, kItemAmmoTommygunFew, kItemAmmoTNTBundle}; 1353 const int pickupsrngpicnum[] = {619, 813, 589}; 1354 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1355 pSprite->type = pickupsrngtype[rng]; 1356 pSprite->picnum = pickupsrngpicnum[rng]; 1357 changespritestat(pSprite->index, kStatItem); 1358 break; 1359 } 1360 case 605: // glass bottle 1361 case 606: // glass bottle 1362 case 616: // glass jug 1363 { 1364 const int pickupsrngtype[] = {kItemAmmoSawedoffFew, kItemAmmoTommygunFew, kItemAmmoTommygunDrum, kItemAmmoSawedoffBox, kItemAmmoTNTBox}; 1365 const int pickupsrngpicnum[] = {619, 813, 817, 812, 809}; 1366 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1367 pSprite->type = pickupsrngtype[rng]; 1368 pSprite->picnum = pickupsrngpicnum[rng]; 1369 changespritestat(pSprite->index, kStatItem); 1370 break; 1371 } 1372 case 834: // montana jar 1373 case 75: // brain in jar 1374 case 76: // brain in jar 1375 { 1376 if (dbRandomizerRNGThings(2)) // lower chance of replacing object 1377 break; 1378 const int pickupsrngtype[] = {kItemHealthLifeEssense, kItemAmmoTommygunDrum, kItemAmmoSawedoffBox, kItemAmmoTNTBox}; 1379 const int pickupsrngpicnum[] = {2169, 817, 812, 809}; 1380 const int rng = dbRandomizerRNGThings(ARRAY_SSIZE(pickupsrngtype)); 1381 pSprite->type = pickupsrngtype[rng]; 1382 pSprite->picnum = pickupsrngpicnum[rng]; 1383 changespritestat(pSprite->index, kStatItem); 1384 break; 1385 } 1386 case 563: // zombie barrel 1387 case 201: // toxic waste 1388 { 1389 if (dbRandomizerRNGThings(5)) // lower chance of replacing object 1390 break; 1391 pSprite->type = kThingTNTBarrel; // replace with tnt barrel 1392 pSprite->picnum = 907; 1393 changespritestat(pSprite->index, kStatThing); 1394 break; 1395 } 1396 default: 1397 break; 1398 } 1399 } 1400 default: 1401 break; 1402 } 1403 1404 if (pSprite->picnum != nPicnumOrig) // if changed sprite type and picnum, readjust position 1405 { 1406 int top, bottom; 1407 GetSpriteExtents(pSprite, &top, &bottom); 1408 if (bottom >= nBottomOrig) 1409 pSprite->z -= bottom - nBottomOrig; 1410 } 1411 } 1412 } 1413 1414 void dbRandomizerModeScale(spritetype *pSprite, XSPRITE* pXSprite) 1415 { 1416 const bool bRandomCheatActive = ((gGameOptions.nGameType != kGameTypeSinglePlayer || gRandomizerScaleMode) && (gGameOptions.nRandomizerCheat >= 0) && (gGameOptions.nRandomizerCheat <= 15)) || (gGameOptions.nGameType == kGameTypeSinglePlayer && gRandomizerScaleMode == 2); // only randomize enemy sizes if seed cheats 0-15 are active 1417 if (!bRandomCheatActive) 1418 return; 1419 if (!pXSprite->scale && !dbRandomizerRNGDudes(3)) { // randomly change enemy scale (only if enemy does not have scale set already) 1420 switch (pSprite->type) { // make enemies randomly huge 1421 case kDudeRat: 1422 pXSprite->scale = ClipRange(dbRandomizerRNGDudes(2048-128)+128, 128, 2048); 1423 break; 1424 case kDudeHand: 1425 pXSprite->scale = ClipRange(dbRandomizerRNGDudes(1024-128)+128, 128, 1024); 1426 break; 1427 case kDudeHellHound: 1428 pXSprite->scale = ClipRange(dbRandomizerRNGDudes(512-128)+128, 128, 512); 1429 break; 1430 case kDudeCultistBeast: // boss types 1431 case kDudeTchernobog: 1432 case kDudeCerberusTwoHead: 1433 case kDudeCerberusOneHead: 1434 case kDudeSpiderMother: 1435 case kDudeGargoyleStone: 1436 pXSprite->scale = ClipRange(dbRandomizerRNGDudes(512-32)+32, 32, 512); 1437 break; 1438 case kDudeGargoyleFlesh: 1439 pXSprite->scale = ClipRange(dbRandomizerRNGDudes(512-32)+32, 32, 512); 1440 break; 1441 case kDudeCultistShotgun: // regular enemies 1442 case kDudeCultistTommy: 1443 case kDudeCultistTommyProne: 1444 case kDudeCultistShotgunProne: 1445 pXSprite->scale = ClipRange(dbRandomizerRNGDudes(384-128)+128, 128, 384); 1446 break; 1447 case kDudeCultistTNT: 1448 pXSprite->scale = ClipRange(dbRandomizerRNGDudes(384-96)+96, 96, 256); 1449 break; 1450 case kDudeZombieButcher: 1451 case kDudeGillBeast: 1452 pXSprite->scale = ClipRange(dbRandomizerRNGDudes(384-64)+64, 64, 384); 1453 break; 1454 default: 1455 break; 1456 } 1457 } 1458 } 1459 1460 inline int dbShuffleEnemyList(spritetype **pSpriteList = NULL) 1461 { 1462 int nSprites = 0; 1463 for (int i = headspritestat[kStatDude]; i >= 0; i = nextspritestat[i]) 1464 { 1465 const int type = sprite[i].type; 1466 if (!((type >= kDudeBase) && (type < kDudeVanillaMax))) // not an enemy sprite, skip 1467 continue; 1468 switch (type) // filter problematic enemy types 1469 { 1470 case kDudeBurningBeast: 1471 case kDudeBurningInnocent: 1472 case kDudeBurningCultist: 1473 case kDudeBurningZombieAxe: 1474 case kDudeBurningZombieButcher: 1475 case kDudeBurningTinyCaleb: 1476 case kDudeCultistReserved: 1477 case kDudeBeast: 1478 case kDudeCultistBeast: 1479 case kDudeGargoyleStone: 1480 case kDudeTchernobog: 1481 case kDudeCerberusTwoHead: 1482 case kDudeCerberusOneHead: 1483 case kDudeSpiderMother: 1484 case kDudeBoneEel: 1485 case kDudePlayer1: 1486 case kDudePlayer2: 1487 case kDudePlayer3: 1488 case kDudePlayer4: 1489 case kDudePlayer5: 1490 case kDudePlayer6: 1491 case kDudePlayer7: 1492 case kDudePlayer8: 1493 continue; 1494 default: 1495 break; 1496 } 1497 if (pSpriteList) 1498 pSpriteList[nSprites] = &sprite[i]; 1499 nSprites++; 1500 } 1501 return nSprites; 1502 } 1503 1504 void dbShuffleEnemy(void) 1505 { 1506 int nSprites = dbShuffleEnemyList(); // get total enemies to shuffle 1507 if (nSprites < 2) // only two enemies in the level, abort 1508 return; 1509 1510 nSprites = ClipRange(nSprites, 0, kMaxSprites-1); 1511 spritetype **pSprite = (spritetype **)Bmalloc((nSprites+1) * sizeof(spritetype)); 1512 if (!pSprite) 1513 return; 1514 dbShuffleEnemyList(pSprite); // assign sprites to pointer array 1515 1516 for (int i = 0; i < nSprites; i++) // shuffle enemies 1517 { 1518 int j = qrand() % nSprites; 1519 if (i == j) 1520 { 1521 j = qrand() % nSprites; // re-roll 1522 if (i == j) // bah! just our luck... 1523 continue; 1524 } 1525 1526 const int16_t tempType = pSprite[j]->type; 1527 pSprite[j]->type = pSprite[i]->type; 1528 pSprite[i]->type = tempType; 1529 1530 const int16_t tempPicnum = pSprite[j]->picnum; 1531 pSprite[j]->picnum = pSprite[i]->picnum; 1532 pSprite[i]->picnum = tempPicnum; 1533 1534 const uint8_t tempPal = pSprite[j]->pal; 1535 pSprite[j]->pal = pSprite[i]->pal; 1536 pSprite[i]->pal = tempPal; 1537 1538 const uint16_t tempCstat = pSprite[j]->cstat; 1539 pSprite[j]->cstat = pSprite[i]->cstat; 1540 pSprite[i]->cstat = tempCstat; 1541 1542 const int16_t tempAng = pSprite[j]->ang; 1543 pSprite[j]->ang = pSprite[i]->ang; 1544 pSprite[i]->ang = tempAng; 1545 1546 const int16_t tempOwner = pSprite[j]->owner; 1547 pSprite[j]->owner = pSprite[i]->owner; 1548 pSprite[i]->owner = tempOwner; 1549 1550 const int16_t tempInittype = pSprite[j]->inittype; 1551 pSprite[j]->inittype = pSprite[i]->inittype; 1552 pSprite[i]->inittype = tempInittype; 1553 } 1554 Bfree(pSprite); 1555 } 1556 1557 bool byte_1A76C6, byte_1A76C7, byte_1A76C8; 1558 1559 MAPHEADER2 byte_19AE44; 1560 1561 unsigned int dbReadMapCRC(const char *pPath) 1562 { 1563 char name2[BMAX_PATH]; 1564 byte_1A76C7 = 0; 1565 byte_1A76C8 = 0; 1566 1567 int const bakpathsearchmode = pathsearchmode; 1568 pathsearchmode = 1; 1569 1570 Bstrncpy(name2, pPath, BMAX_PATH); 1571 Bstrupr(name2); 1572 DICTNODE* pNode = *gSysRes.Probe(name2, "MAP"); 1573 if (pNode && pNode->flags & DICT_EXTERNAL) 1574 { 1575 gSysRes.RemoveNode(pNode); 1576 } 1577 pNode = gSysRes.Lookup(pPath, "MAP"); 1578 if (!pNode) 1579 { 1580 char name2[BMAX_PATH]; 1581 Bstrncpy(name2, pPath, BMAX_PATH); 1582 ChangeExtension(name2, ""); 1583 pNode = gSysRes.Lookup(name2, "MAP"); 1584 } 1585 1586 if (!pNode) 1587 { 1588 LOG_F(ERROR, "Error opening map file %s", pPath); 1589 pathsearchmode = bakpathsearchmode; 1590 return -1; 1591 } 1592 char *pData = (char*)gSysRes.Lock(pNode); 1593 pathsearchmode = bakpathsearchmode; 1594 1595 int nSize = pNode->size; 1596 MAPSIGNATURE header; 1597 IOBuffer(nSize, pData).Read(&header, 6); 1598 #if B_BIG_ENDIAN == 1 1599 header.version = B_LITTLE16(header.version); 1600 #endif 1601 if (memcmp(header.signature, "BLM\x1a", 4)) 1602 { 1603 ThrowError("Map file corrupted"); 1604 } 1605 if ((header.version & 0xff00) == 0x600) 1606 { 1607 } 1608 else if ((header.version & 0xff00) == 0x700) 1609 { 1610 byte_1A76C8 = 1; 1611 } 1612 else 1613 { 1614 ThrowError("Map file is wrong version"); 1615 } 1616 unsigned int nCRC = *(unsigned int*)(pData+nSize-4); 1617 gSysRes.Unlock(pNode); 1618 return nCRC; 1619 } 1620 1621 int gMapRev, gSongId, gSkyCount; 1622 //char byte_19AE44[128]; 1623 const int nXSectorSize = 60; 1624 const int nXSpriteSize = 56; 1625 const int nXWallSize = 24; 1626 1627 int dbLoadMap(const char *pPath, int *pX, int *pY, int *pZ, short *pAngle, short *pSector, unsigned int *pCRC) { 1628 char name2[BMAX_PATH]; int16_t tpskyoff[256]; 1629 1630 memset(show2dsector,0,sizeof(show2dsector)); 1631 memset(show2dwall,0,sizeof(show2dwall)); 1632 memset(show2dsprite,0,sizeof(show2dsprite)); 1633 memset(spriteext,0,kMaxSprites*sizeof(spriteext_t)); 1634 1635 memset(xvel,0,sizeof(xvel)); 1636 memset(yvel,0,sizeof(yvel)); 1637 memset(zvel,0,sizeof(zvel)); 1638 memset(xsprite,0,kMaxXSprites*sizeof(XSPRITE)); 1639 memset(sprite,0,kMaxSprites*sizeof(spritetype)); 1640 1641 memset(qsprite_filler,0,sizeof(qsprite_filler)); 1642 memset(qsector_filler,0,sizeof(qsector_filler)); 1643 1644 #ifdef NOONE_EXTENSIONS 1645 gModernMap = false; 1646 #endif 1647 1648 #ifdef USE_OPENGL 1649 Polymost_prepare_loadboard(); 1650 #endif 1651 1652 int const bakpathsearchmode = pathsearchmode; 1653 pathsearchmode = 1; 1654 1655 Bstrncpy(name2, pPath, BMAX_PATH); 1656 Bstrupr(name2); 1657 DICTNODE* pNode = *gSysRes.Probe(name2, "MAP"); 1658 if (pNode && pNode->flags & DICT_EXTERNAL) 1659 { 1660 gSysRes.RemoveNode(pNode); 1661 } 1662 1663 pNode = gSysRes.Lookup(pPath, "MAP"); 1664 if (!pNode) 1665 { 1666 char name2[BMAX_PATH]; 1667 Bstrncpy(name2, pPath, BMAX_PATH); 1668 ChangeExtension(name2, ""); 1669 pNode = gSysRes.Lookup(name2, "MAP"); 1670 } 1671 1672 if (!pNode) 1673 { 1674 LOG_F(ERROR, "Error opening map file %s", pPath); 1675 pathsearchmode = bakpathsearchmode; 1676 return -1; 1677 } 1678 char *pData = (char*)gSysRes.Lock(pNode); 1679 pathsearchmode = bakpathsearchmode; 1680 int nSize = pNode->size; 1681 MAPSIGNATURE header; 1682 IOBuffer IOBuffer1 = IOBuffer(nSize, pData); 1683 IOBuffer1.Read(&header, 6); 1684 #if B_BIG_ENDIAN == 1 1685 header.version = B_LITTLE16(header.version); 1686 #endif 1687 if (memcmp(header.signature, "BLM\x1a", 4)) 1688 { 1689 LOG_F(ERROR, "Map file corrupted"); 1690 gSysRes.Unlock(pNode); 1691 return -1; 1692 } 1693 byte_1A76C8 = 0; 1694 if ((header.version & 0xff00) == 0x700) { 1695 byte_1A76C8 = 1; 1696 1697 #ifdef NOONE_EXTENSIONS 1698 // indicate if the map requires modern features to work properly 1699 // for maps wich created in PMAPEDIT BETA13 or higher versions. Since only minor version changed, 1700 // the map is still can be loaded with vanilla BLOOD / MAPEDIT and should work in other ports too. 1701 int tmp = (header.version & 0x00ff); 1702 1703 // get the modern features revision 1704 switch (tmp) { 1705 case 0x001: 1706 gModernMap = 1; 1707 break; 1708 case 0x002: 1709 gModernMap = 2; 1710 break; 1711 } 1712 #endif 1713 1714 } else { 1715 LOG_F(ERROR, "Map file is wrong version"); 1716 gSysRes.Unlock(pNode); 1717 return -1; 1718 } 1719 1720 MAPHEADER mapHeader; 1721 IOBuffer1.Read(&mapHeader,37/* sizeof(mapHeader)*/); 1722 if (mapHeader.at16 != 0 && mapHeader.at16 != kMapHeaderNew && mapHeader.at16 != kMapHeaderOld) { 1723 dbCrypt((char*)&mapHeader, sizeof(mapHeader), kMapHeaderNew); 1724 byte_1A76C7 = 1; 1725 } 1726 1727 #if B_BIG_ENDIAN == 1 1728 mapHeader.at0 = B_LITTLE32(mapHeader.at0); 1729 mapHeader.at4 = B_LITTLE32(mapHeader.at4); 1730 mapHeader.at8 = B_LITTLE32(mapHeader.at8); 1731 mapHeader.atc = B_LITTLE16(mapHeader.atc); 1732 mapHeader.ate = B_LITTLE16(mapHeader.ate); 1733 mapHeader.at10 = B_LITTLE16(mapHeader.at10); 1734 mapHeader.at12 = B_LITTLE32(mapHeader.at12); 1735 mapHeader.at16 = B_LITTLE32(mapHeader.at16); 1736 mapHeader.at1b = B_LITTLE32(mapHeader.at1b); 1737 mapHeader.at1f = B_LITTLE16(mapHeader.at1f); 1738 mapHeader.at21 = B_LITTLE16(mapHeader.at21); 1739 mapHeader.at23 = B_LITTLE16(mapHeader.at23); 1740 #endif 1741 1742 psky_t *pSky = tileSetupSky(0); 1743 pSky->horizfrac = 65536; 1744 1745 *pX = mapHeader.at0; 1746 *pY = mapHeader.at4; 1747 *pZ = mapHeader.at8; 1748 *pAngle = mapHeader.atc; 1749 *pSector = mapHeader.ate; 1750 pSky->lognumtiles = mapHeader.at10; 1751 gVisibility = g_visibility = mapHeader.at12; 1752 gSongId = mapHeader.at16; 1753 if (byte_1A76C8) 1754 { 1755 if (mapHeader.at16 == kMapHeaderNew || mapHeader.at16 == kMapHeaderOld) 1756 { 1757 byte_1A76C6 = 1; 1758 } 1759 else if (!mapHeader.at16) 1760 { 1761 byte_1A76C6 = 0; 1762 } 1763 else 1764 { 1765 LOG_F(ERROR, "Corrupted Map file"); 1766 gSysRes.Unlock(pNode); 1767 return -1; 1768 } 1769 } 1770 else if (mapHeader.at16) 1771 { 1772 LOG_F(ERROR, "Corrupted Map file"); 1773 gSysRes.Unlock(pNode); 1774 return -1; 1775 } 1776 parallaxtype = mapHeader.at1a; 1777 gMapRev = mapHeader.at1b; 1778 numsectors = mapHeader.at1f; 1779 numwalls = mapHeader.at21; 1780 dbInit(); 1781 if (gGameOptions.nRandomizerMode && !VanillaMode()) 1782 { 1783 dbRandomizerModeInit(); // seed enemy/pickup randomizer 1784 } 1785 if (byte_1A76C8) 1786 { 1787 IOBuffer1.Read(&byte_19AE44, 128); 1788 dbCrypt((char*)&byte_19AE44, 128, numwalls); 1789 #if B_BIG_ENDIAN == 1 1790 byte_19AE44.at40 = B_LITTLE32(byte_19AE44.at40); 1791 byte_19AE44.at44 = B_LITTLE32(byte_19AE44.at44); 1792 byte_19AE44.at48 = B_LITTLE32(byte_19AE44.at48); 1793 #endif 1794 } 1795 else 1796 { 1797 memset(&byte_19AE44, 0, 128); 1798 } 1799 gSkyCount = 1<<pSky->lognumtiles; 1800 IOBuffer1.Read(tpskyoff, gSkyCount*sizeof(tpskyoff[0])); 1801 if (byte_1A76C8) 1802 { 1803 dbCrypt((char*)tpskyoff, gSkyCount*sizeof(tpskyoff[0]), gSkyCount*2); 1804 } 1805 for (int i = 0; i < ClipHigh(gSkyCount, MAXPSKYTILES); i++) 1806 { 1807 pSky->tileofs[i] = B_LITTLE16(tpskyoff[i]); 1808 } 1809 for (int i = 0; i < numsectors; i++) 1810 { 1811 sectortype *pSector = §or[i]; 1812 IOBuffer1.Read(pSector, sizeof(sectortype)); 1813 if (byte_1A76C8) 1814 { 1815 dbCrypt((char*)pSector, sizeof(sectortype), gMapRev*sizeof(sectortype)); 1816 } 1817 #if B_BIG_ENDIAN == 1 1818 pSector->wallptr = B_LITTLE16(pSector->wallptr); 1819 pSector->wallnum = B_LITTLE16(pSector->wallnum); 1820 pSector->ceilingz = B_LITTLE32(pSector->ceilingz); 1821 pSector->floorz = B_LITTLE32(pSector->floorz); 1822 pSector->ceilingstat = B_LITTLE16(pSector->ceilingstat); 1823 pSector->floorstat = B_LITTLE16(pSector->floorstat); 1824 pSector->ceilingpicnum = B_LITTLE16(pSector->ceilingpicnum); 1825 pSector->ceilingheinum = B_LITTLE16(pSector->ceilingheinum); 1826 pSector->floorpicnum = B_LITTLE16(pSector->floorpicnum); 1827 pSector->floorheinum = B_LITTLE16(pSector->floorheinum); 1828 pSector->type = B_LITTLE16(pSector->type); 1829 pSector->hitag = B_LITTLE16(pSector->hitag); 1830 pSector->extra = B_LITTLE16(pSector->extra); 1831 #endif 1832 qsector_filler[i] = pSector->fogpal; 1833 pSector->fogpal = 0; 1834 if (sector[i].extra > 0) 1835 { 1836 char pBuffer[nXSectorSize]; 1837 int nXSector = dbInsertXSector(i); 1838 XSECTOR *pXSector = &xsector[nXSector]; 1839 memset(pXSector, 0, sizeof(XSECTOR)); 1840 int nCount; 1841 if (!byte_1A76C8) 1842 { 1843 nCount = nXSectorSize; 1844 } 1845 else 1846 { 1847 nCount = byte_19AE44.at48; 1848 } 1849 dassert(nCount <= nXSectorSize); 1850 IOBuffer1.Read(pBuffer, nCount); 1851 BitReader bitReader(pBuffer, nCount); 1852 pXSector->reference = bitReader.readSigned(14); 1853 pXSector->state = bitReader.readUnsigned(1); 1854 pXSector->busy = bitReader.readUnsigned(17); 1855 pXSector->data = bitReader.readUnsigned(16); 1856 pXSector->txID = bitReader.readUnsigned(10); 1857 pXSector->busyWaveA = bitReader.readUnsigned(3); 1858 pXSector->busyWaveB = bitReader.readUnsigned(3); 1859 pXSector->rxID = bitReader.readUnsigned(10); 1860 pXSector->command = bitReader.readUnsigned(8); 1861 pXSector->triggerOn = bitReader.readUnsigned(1); 1862 pXSector->triggerOff = bitReader.readUnsigned(1); 1863 pXSector->busyTimeA = bitReader.readUnsigned(12); 1864 pXSector->waitTimeA = bitReader.readUnsigned(12); 1865 pXSector->restState = bitReader.readUnsigned(1); 1866 pXSector->interruptable = bitReader.readUnsigned(1); 1867 pXSector->amplitude = bitReader.readSigned(8); 1868 pXSector->freq = bitReader.readUnsigned(8); 1869 pXSector->reTriggerA = bitReader.readUnsigned(1); 1870 pXSector->reTriggerB = bitReader.readUnsigned(1); 1871 pXSector->phase = bitReader.readUnsigned(8); 1872 pXSector->wave = bitReader.readUnsigned(4); 1873 pXSector->shadeAlways = bitReader.readUnsigned(1); 1874 pXSector->shadeFloor = bitReader.readUnsigned(1); 1875 pXSector->shadeCeiling = bitReader.readUnsigned(1); 1876 pXSector->shadeWalls = bitReader.readUnsigned(1); 1877 pXSector->shade = bitReader.readSigned(8); 1878 pXSector->panAlways = bitReader.readUnsigned(1); 1879 pXSector->panFloor = bitReader.readUnsigned(1); 1880 pXSector->panCeiling = bitReader.readUnsigned(1); 1881 pXSector->Drag = bitReader.readUnsigned(1); 1882 pXSector->Underwater = bitReader.readUnsigned(1); 1883 pXSector->Depth = bitReader.readUnsigned(3); 1884 pXSector->panVel = bitReader.readUnsigned(8); 1885 pXSector->panAngle = bitReader.readUnsigned(11); 1886 pXSector->unused1 = bitReader.readUnsigned(1); 1887 pXSector->decoupled = bitReader.readUnsigned(1); 1888 pXSector->triggerOnce = bitReader.readUnsigned(1); 1889 pXSector->isTriggered = bitReader.readUnsigned(1); 1890 pXSector->Key = bitReader.readUnsigned(3); 1891 pXSector->Push = bitReader.readUnsigned(1); 1892 pXSector->Vector = bitReader.readUnsigned(1); 1893 pXSector->Reserved = bitReader.readUnsigned(1); 1894 pXSector->Enter = bitReader.readUnsigned(1); 1895 pXSector->Exit = bitReader.readUnsigned(1); 1896 pXSector->Wallpush = bitReader.readUnsigned(1); 1897 pXSector->color = bitReader.readUnsigned(1); 1898 pXSector->unused2 = bitReader.readUnsigned(1); 1899 pXSector->busyTimeB = bitReader.readUnsigned(12); 1900 pXSector->waitTimeB = bitReader.readUnsigned(12); 1901 pXSector->stopOn = bitReader.readUnsigned(1); 1902 pXSector->stopOff = bitReader.readUnsigned(1); 1903 pXSector->ceilpal = bitReader.readUnsigned(4); 1904 pXSector->offCeilZ = bitReader.readSigned(32); 1905 pXSector->onCeilZ = bitReader.readSigned(32); 1906 pXSector->offFloorZ = bitReader.readSigned(32); 1907 pXSector->onFloorZ = bitReader.readSigned(32); 1908 pXSector->marker0 = bitReader.readUnsigned(16); 1909 pXSector->marker1 = bitReader.readUnsigned(16); 1910 pXSector->Crush = bitReader.readUnsigned(1); 1911 pXSector->ceilXPanFrac = bitReader.readUnsigned(8); 1912 pXSector->ceilYPanFrac = bitReader.readUnsigned(8); 1913 pXSector->floorXPanFrac = bitReader.readUnsigned(8); 1914 pXSector->damageType = bitReader.readUnsigned(3); 1915 pXSector->floorpal = bitReader.readUnsigned(4); 1916 pXSector->floorYPanFrac = bitReader.readUnsigned(8); 1917 pXSector->locked = bitReader.readUnsigned(1); 1918 pXSector->windVel = bitReader.readUnsigned(10); 1919 pXSector->windAng = bitReader.readUnsigned(11); 1920 pXSector->windAlways = bitReader.readUnsigned(1); 1921 pXSector->dudeLockout = bitReader.readUnsigned(1); 1922 pXSector->bobTheta = bitReader.readUnsigned(11); 1923 pXSector->bobZRange = bitReader.readUnsigned(5); 1924 pXSector->bobSpeed = bitReader.readSigned(12); 1925 pXSector->bobAlways = bitReader.readUnsigned(1); 1926 pXSector->bobFloor = bitReader.readUnsigned(1); 1927 pXSector->bobCeiling = bitReader.readUnsigned(1); 1928 pXSector->bobRotate = bitReader.readUnsigned(1); 1929 xsector[sector[i].extra].reference = i; 1930 xsector[sector[i].extra].busy = xsector[sector[i].extra].state<<16; 1931 1932 } 1933 } 1934 for (int i = 0; i < numwalls; i++) 1935 { 1936 walltype *pWall = &wall[i]; 1937 IOBuffer1.Read(pWall, sizeof(walltype)); 1938 if (byte_1A76C8) 1939 { 1940 dbCrypt((char*)pWall, sizeof(walltype), (gMapRev*sizeof(sectortype)) | kMapHeaderNew); 1941 } 1942 #if B_BIG_ENDIAN == 1 1943 pWall->x = B_LITTLE32(pWall->x); 1944 pWall->y = B_LITTLE32(pWall->y); 1945 pWall->point2 = B_LITTLE16(pWall->point2); 1946 pWall->nextwall = B_LITTLE16(pWall->nextwall); 1947 pWall->nextsector = B_LITTLE16(pWall->nextsector); 1948 pWall->cstat = B_LITTLE16(pWall->cstat); 1949 pWall->picnum = B_LITTLE16(pWall->picnum); 1950 pWall->overpicnum = B_LITTLE16(pWall->overpicnum); 1951 pWall->type = B_LITTLE16(pWall->type); 1952 pWall->hitag = B_LITTLE16(pWall->hitag); 1953 pWall->extra = B_LITTLE16(pWall->extra); 1954 #endif 1955 if (wall[i].extra > 0) 1956 { 1957 char pBuffer[nXWallSize]; 1958 int nXWall = dbInsertXWall(i); 1959 XWALL *pXWall = &xwall[nXWall]; 1960 memset(pXWall, 0, sizeof(XWALL)); 1961 int nCount; 1962 if (!byte_1A76C8) 1963 { 1964 nCount = nXWallSize; 1965 } 1966 else 1967 { 1968 nCount = byte_19AE44.at44; 1969 } 1970 dassert(nCount <= nXWallSize); 1971 IOBuffer1.Read(pBuffer, nCount); 1972 BitReader bitReader(pBuffer, nCount); 1973 pXWall->reference = bitReader.readSigned(14); 1974 pXWall->state = bitReader.readUnsigned(1); 1975 pXWall->busy = bitReader.readUnsigned(17); 1976 pXWall->data = bitReader.readSigned(16); 1977 pXWall->txID = bitReader.readUnsigned(10); 1978 pXWall->unused1 = bitReader.readUnsigned(6); 1979 pXWall->rxID = bitReader.readUnsigned(10); 1980 pXWall->command = bitReader.readUnsigned(8); 1981 pXWall->triggerOn = bitReader.readUnsigned(1); 1982 pXWall->triggerOff = bitReader.readUnsigned(1); 1983 pXWall->busyTime = bitReader.readUnsigned(12); 1984 pXWall->waitTime = bitReader.readUnsigned(12); 1985 pXWall->restState = bitReader.readUnsigned(1); 1986 pXWall->interruptable = bitReader.readUnsigned(1); 1987 pXWall->panAlways = bitReader.readUnsigned(1); 1988 pXWall->panXVel = bitReader.readSigned(8); 1989 pXWall->panYVel = bitReader.readSigned(8); 1990 pXWall->decoupled = bitReader.readUnsigned(1); 1991 pXWall->triggerOnce = bitReader.readUnsigned(1); 1992 pXWall->isTriggered = bitReader.readUnsigned(1); 1993 pXWall->key = bitReader.readUnsigned(3); 1994 pXWall->triggerPush = bitReader.readUnsigned(1); 1995 pXWall->triggerVector = bitReader.readUnsigned(1); 1996 pXWall->triggerTouch = bitReader.readUnsigned(1); 1997 pXWall->unused2 = bitReader.readUnsigned(2); 1998 pXWall->xpanFrac = bitReader.readUnsigned(8); 1999 pXWall->ypanFrac = bitReader.readUnsigned(8); 2000 pXWall->locked = bitReader.readUnsigned(1); 2001 pXWall->dudeLockout = bitReader.readUnsigned(1); 2002 pXWall->unused3 = bitReader.readUnsigned(4); 2003 pXWall->unused4 = bitReader.readUnsigned(32); 2004 xwall[wall[i].extra].reference = i; 2005 xwall[wall[i].extra].busy = xwall[wall[i].extra].state << 16; 2006 2007 } 2008 } 2009 initspritelists(); 2010 for (int i = 0; i < mapHeader.at23; i++) 2011 { 2012 RemoveSpriteStat(i); 2013 spritetype *pSprite = &sprite[i]; 2014 IOBuffer1.Read(pSprite, sizeof(spritetype)); 2015 if (byte_1A76C8) 2016 { 2017 dbCrypt((char*)pSprite, sizeof(spritetype), (gMapRev*sizeof(spritetype)) | kMapHeaderNew); 2018 } 2019 #if B_BIG_ENDIAN == 1 2020 pSprite->x = B_LITTLE32(pSprite->x); 2021 pSprite->y = B_LITTLE32(pSprite->y); 2022 pSprite->z = B_LITTLE32(pSprite->z); 2023 pSprite->cstat = B_LITTLE16(pSprite->cstat); 2024 pSprite->picnum = B_LITTLE16(pSprite->picnum); 2025 pSprite->sectnum = B_LITTLE16(pSprite->sectnum); 2026 pSprite->statnum = B_LITTLE16(pSprite->statnum); 2027 pSprite->ang = B_LITTLE16(pSprite->ang); 2028 pSprite->owner = B_LITTLE16(pSprite->owner); 2029 pSprite->index = B_LITTLE16(pSprite->index); 2030 pSprite->yvel = B_LITTLE16(pSprite->yvel); 2031 pSprite->inittype = B_LITTLE16(pSprite->inittype); 2032 pSprite->type = B_LITTLE16(pSprite->type); 2033 pSprite->flags = B_LITTLE16(pSprite->hitag); 2034 pSprite->extra = B_LITTLE16(pSprite->extra); 2035 #endif 2036 InsertSpriteSect(i, sprite[i].sectnum); 2037 InsertSpriteStat(i, sprite[i].statnum); 2038 Numsprites++; 2039 sprite[i].index = i; 2040 qsprite_filler[i] = pSprite->blend; 2041 pSprite->blend = 0; 2042 if (sprite[i].extra > 0) 2043 { 2044 char pBuffer[nXSpriteSize]; 2045 int nXSprite = dbInsertXSprite(i); 2046 XSPRITE *pXSprite = &xsprite[nXSprite]; 2047 memset(pXSprite, 0, sizeof(XSPRITE)); 2048 int nCount; 2049 if (!byte_1A76C8) 2050 { 2051 nCount = nXSpriteSize; 2052 } 2053 else 2054 { 2055 nCount = byte_19AE44.at40; 2056 } 2057 dassert(nCount <= nXSpriteSize); 2058 IOBuffer1.Read(pBuffer, nCount); 2059 BitReader bitReader(pBuffer, nCount); 2060 pXSprite->reference = bitReader.readSigned(14); 2061 pXSprite->state = bitReader.readUnsigned(1); 2062 pXSprite->busy = bitReader.readUnsigned(17); 2063 pXSprite->txID = bitReader.readUnsigned(10); 2064 pXSprite->rxID = bitReader.readUnsigned(10); 2065 pXSprite->command = bitReader.readUnsigned(8); 2066 pXSprite->triggerOn = bitReader.readUnsigned(1); 2067 pXSprite->triggerOff = bitReader.readUnsigned(1); 2068 pXSprite->wave = bitReader.readUnsigned(2); 2069 pXSprite->busyTime = bitReader.readUnsigned(12); 2070 pXSprite->waitTime = bitReader.readUnsigned(12); 2071 pXSprite->restState = bitReader.readUnsigned(1); 2072 pXSprite->Interrutable = bitReader.readUnsigned(1); 2073 pXSprite->unused1 = bitReader.readUnsigned(2); 2074 pXSprite->respawnPending = bitReader.readUnsigned(2); 2075 pXSprite->unused2 = bitReader.readUnsigned(1); 2076 pXSprite->lT = bitReader.readUnsigned(1); 2077 pXSprite->dropMsg = bitReader.readUnsigned(8); 2078 pXSprite->Decoupled = bitReader.readUnsigned(1); 2079 pXSprite->triggerOnce = bitReader.readUnsigned(1); 2080 pXSprite->isTriggered = bitReader.readUnsigned(1); 2081 pXSprite->key = bitReader.readUnsigned(3); 2082 pXSprite->Push = bitReader.readUnsigned(1); 2083 pXSprite->Vector = bitReader.readUnsigned(1); 2084 pXSprite->Impact = bitReader.readUnsigned(1); 2085 pXSprite->Pickup = bitReader.readUnsigned(1); 2086 pXSprite->Touch = bitReader.readUnsigned(1); 2087 pXSprite->Sight = bitReader.readUnsigned(1); 2088 pXSprite->Proximity = bitReader.readUnsigned(1); 2089 pXSprite->unused3 = bitReader.readUnsigned(2); 2090 pXSprite->lSkill = bitReader.readUnsigned(5); 2091 pXSprite->lS = bitReader.readUnsigned(1); 2092 pXSprite->lB = bitReader.readUnsigned(1); 2093 pXSprite->lC = bitReader.readUnsigned(1); 2094 pXSprite->DudeLockout = bitReader.readUnsigned(1); 2095 pXSprite->data1 = bitReader.readSigned(16); 2096 pXSprite->data2 = bitReader.readSigned(16); 2097 pXSprite->data3 = bitReader.readSigned(16); 2098 pXSprite->goalAng = bitReader.readUnsigned(11); 2099 pXSprite->dodgeDir = bitReader.readSigned(2); 2100 pXSprite->locked = bitReader.readUnsigned(1); 2101 pXSprite->medium = bitReader.readUnsigned(2); 2102 pXSprite->respawn = bitReader.readUnsigned(2); 2103 pXSprite->data4 = bitReader.readUnsigned(16); 2104 pXSprite->unused4 = bitReader.readUnsigned(6); 2105 pXSprite->lockMsg = bitReader.readUnsigned(8); 2106 pXSprite->health = bitReader.readUnsigned(12); 2107 pXSprite->dudeDeaf = bitReader.readUnsigned(1); 2108 pXSprite->dudeAmbush = bitReader.readUnsigned(1); 2109 pXSprite->dudeGuard = bitReader.readUnsigned(1); 2110 pXSprite->dudeFlag4 = bitReader.readUnsigned(1); 2111 pXSprite->target = bitReader.readSigned(16); 2112 pXSprite->targetX = bitReader.readSigned(32); 2113 pXSprite->targetY = bitReader.readSigned(32); 2114 pXSprite->targetZ = bitReader.readSigned(32); 2115 pXSprite->burnTime = bitReader.readUnsigned(16); 2116 pXSprite->burnSource = bitReader.readSigned(16); 2117 pXSprite->height = bitReader.readUnsigned(16); 2118 pXSprite->stateTimer = bitReader.readUnsigned(16); 2119 pXSprite->aiState = NULL; 2120 bitReader.skipBits(32); 2121 xsprite[sprite[i].extra].reference = i; 2122 xsprite[sprite[i].extra].busy = xsprite[sprite[i].extra].state << 16; 2123 if (!byte_1A76C8) { 2124 xsprite[sprite[i].extra].lT = xsprite[sprite[i].extra].lB; 2125 } 2126 2127 #ifdef NOONE_EXTENSIONS 2128 // indicate if the map requires modern features to work properly 2129 // for maps wich created in different editors (include vanilla MAPEDIT) or in PMAPEDIT version below than BETA13 2130 if (!gModernMap && pXSprite->rxID == pXSprite->txID && pXSprite->command == kCmdModernFeaturesEnable) 2131 { 2132 // get the modern features revision 2133 switch (pXSprite->txID) { 2134 case kChannelMapModernRev1: 2135 gModernMap = 1; 2136 break; 2137 case kChannelMapModernRev2: 2138 gModernMap = 2; 2139 break; 2140 } 2141 } 2142 #endif 2143 } 2144 #if 0 2145 if ((sprite[i].cstat & 0x30) == 0x30) 2146 { 2147 sprite[i].cstat &= ~0x30; 2148 } 2149 #endif 2150 } 2151 unsigned int nCRC; 2152 IOBuffer1.Read(&nCRC, 4); 2153 #if B_BIG_ENDIAN == 1 2154 nCRC = B_LITTLE32(nCRC); 2155 #endif 2156 md4once((unsigned char*)pData, nSize, g_loadedMapHack.md4); 2157 if (Bcrc32(pData, nSize-4, 0) != nCRC) 2158 { 2159 LOG_F(ERROR, "Map File does not match CRC"); 2160 gSysRes.Unlock(pNode); 2161 return -1; 2162 } 2163 if (pCRC) 2164 *pCRC = nCRC; 2165 gSysRes.Unlock(pNode); 2166 PropagateMarkerReferences(); 2167 if (byte_1A76C8) 2168 { 2169 if (gSongId == kMapHeaderNew || gSongId == kMapHeaderOld) 2170 { 2171 byte_1A76C6 = 1; 2172 } 2173 else if (!gSongId) 2174 { 2175 byte_1A76C6 = 0; 2176 } 2177 else 2178 { 2179 LOG_F(ERROR, "Corrupted Map file"); 2180 return -1; 2181 } 2182 } 2183 else if (gSongId != 0) 2184 { 2185 LOG_F(ERROR, "Corrupted Map file"); 2186 return -1; 2187 } 2188 2189 #ifdef NOONE_EXTENSIONS 2190 if (VanillaMode() && gModernMap) 2191 { 2192 viewSetMessage("Warning: Modern levels are not compatible with vanilla mode"); 2193 viewSetMessage("Please disable vanilla mode and restart level"); 2194 } 2195 #endif 2196 2197 #ifdef POLYMER 2198 if (videoGetRenderMode() == REND_POLYMER) 2199 polymer_loadboard(); 2200 #endif 2201 2202 if ((header.version & 0xff00) == 0x600) 2203 { 2204 switch (header.version&0xff) 2205 { 2206 case 0: 2207 for (int i = 0; i < numsectors; i++) 2208 { 2209 sectortype *pSector = §or[i]; 2210 if (pSector->extra > 0) 2211 { 2212 XSECTOR *pXSector = &xsector[pSector->extra]; 2213 pXSector->busyTimeB = pXSector->busyTimeA; 2214 if (pXSector->busyTimeA > 0) 2215 { 2216 if (!pXSector->restState) 2217 { 2218 pXSector->reTriggerA = 1; 2219 } 2220 else 2221 { 2222 pXSector->waitTimeB = pXSector->busyTimeA; 2223 pXSector->waitTimeA = 0; 2224 pXSector->reTriggerB = 1; 2225 } 2226 } 2227 } 2228 } 2229 fallthrough__; 2230 case 1: 2231 for (int i = 0; i < numsectors; i++) 2232 { 2233 sectortype *pSector = §or[i]; 2234 if (pSector->extra > 0) 2235 { 2236 XSECTOR *pXSector = &xsector[pSector->extra]; 2237 pXSector->freq >>= 1; 2238 } 2239 } 2240 fallthrough__; 2241 case 2: 2242 for (int i = 0; i < kMaxSprites; i++) 2243 { 2244 } 2245 break; 2246 2247 } 2248 } 2249 2250 #ifdef YAX_ENABLE 2251 yax_update((header.version & 0xff00) > 0x700 ? 0 : 1); 2252 if (editstatus) 2253 yax_updategrays(*pZ); 2254 #endif 2255 2256 calc_sector_reachability(); 2257 2258 g_loadedMapVersion = 7; 2259 2260 return 0; 2261 } 2262 2263 int dbSaveMap(const char *pPath, int nX, int nY, int nZ, short nAngle, short nSector) 2264 { 2265 char sMapExt[BMAX_PATH]; 2266 //char sBakExt[BMAX_PATH]; 2267 int16_t tpskyoff[256]; 2268 int nSpriteNum; 2269 psky_t *pSky = tileSetupSky(0); 2270 gSkyCount = 1<<pSky->lognumtiles; 2271 gMapRev++; 2272 nSpriteNum = 0; 2273 strcpy(sMapExt, pPath); 2274 ChangeExtension(sMapExt, ".MAP"); 2275 int nSize = sizeof(MAPSIGNATURE)+sizeof(MAPHEADER); 2276 if (byte_1A76C8) 2277 { 2278 nSize += sizeof(MAPHEADER2); 2279 } 2280 for (int i = 0; i < gSkyCount; i++) 2281 tpskyoff[i] = pSky->tileofs[i]; 2282 nSize += gSkyCount*sizeof(tpskyoff[0]); 2283 nSize += sizeof(sectortype)*numsectors; 2284 for (int i = 0; i < numsectors; i++) 2285 { 2286 if (sector[i].extra > 0) 2287 { 2288 nSize += nXSectorSize; 2289 } 2290 } 2291 nSize += sizeof(walltype)*numwalls; 2292 for (int i = 0; i < numwalls; i++) 2293 { 2294 if (wall[i].extra > 0) 2295 { 2296 nSize += nXWallSize; 2297 } 2298 } 2299 for (int i = 0; i < kMaxSprites; i++) 2300 { 2301 if (sprite[i].statnum < kMaxStatus) 2302 { 2303 nSpriteNum++; 2304 if (sprite[i].extra > 0) 2305 { 2306 nSize += nXSpriteSize; 2307 } 2308 } 2309 } 2310 nSize += sizeof(spritetype)*nSpriteNum; 2311 nSize += 4; 2312 char *pData = (char*)Xmalloc(nSize); 2313 IOBuffer IOBuffer1 = IOBuffer(nSize, pData); 2314 MAPSIGNATURE header; 2315 memcpy(&header, "BLM\x1a", 4); 2316 if (byte_1A76C8) 2317 { 2318 header.version = 0x700; 2319 byte_1A76C7 = 1; 2320 } 2321 else 2322 { 2323 header.version = 0x603; 2324 byte_1A76C7 = 0; 2325 } 2326 IOBuffer1.Write(&header, sizeof(header)); 2327 MAPHEADER mapheader; 2328 mapheader.at0 = B_LITTLE32(nX); 2329 mapheader.at4 = B_LITTLE32(nY); 2330 mapheader.at8 = B_LITTLE32(nZ); 2331 mapheader.atc = B_LITTLE16(nAngle); 2332 mapheader.ate = B_LITTLE16(nSector); 2333 mapheader.at10 = B_LITTLE16(pSky->lognumtiles); 2334 mapheader.at12 = B_LITTLE32(gVisibility); 2335 if (byte_1A76C6) 2336 { 2337 gSongId = kMapHeaderNew; 2338 } 2339 else 2340 { 2341 gSongId = 0; 2342 } 2343 mapheader.at16 = B_LITTLE32(gSongId); 2344 mapheader.at1a = parallaxtype; 2345 mapheader.at1b = gMapRev; 2346 mapheader.at1f = B_LITTLE16(numsectors); 2347 mapheader.at21 = B_LITTLE16(numwalls); 2348 mapheader.at23 = B_LITTLE16(nSpriteNum); 2349 if (byte_1A76C7) 2350 { 2351 dbCrypt((char*)&mapheader, sizeof(MAPHEADER), kMapHeaderNew); 2352 } 2353 IOBuffer1.Write(&mapheader, sizeof(MAPHEADER)); 2354 if (byte_1A76C8) 2355 { 2356 Bstrcpy(byte_19AE44.at0, AppProperName); 2357 byte_19AE44.at48 = nXSectorSize; 2358 byte_19AE44.at44 = nXWallSize; 2359 byte_19AE44.at40 = nXSpriteSize; 2360 dbCrypt((char*)&byte_19AE44, sizeof(MAPHEADER2), numwalls); 2361 IOBuffer1.Write(&byte_19AE44, sizeof(MAPHEADER2)); 2362 dbCrypt((char*)&byte_19AE44, sizeof(MAPHEADER2), numwalls); 2363 } 2364 if (byte_1A76C8) 2365 { 2366 dbCrypt((char*)tpskyoff, gSkyCount*sizeof(tpskyoff[0]), gSkyCount*sizeof(tpskyoff[0])); 2367 } 2368 IOBuffer1.Write(tpskyoff, gSkyCount*sizeof(tpskyoff[0])); 2369 if (byte_1A76C8) 2370 { 2371 dbCrypt((char*)tpskyoff, gSkyCount*sizeof(tpskyoff[0]), gSkyCount*sizeof(tpskyoff[0])); 2372 } 2373 for (int i = 0; i < numsectors; i++) 2374 { 2375 if (byte_1A76C8) 2376 { 2377 dbCrypt((char*)§or[i], sizeof(sectortype), gMapRev*sizeof(sectortype)); 2378 } 2379 IOBuffer1.Write(§or[i], sizeof(sectortype)); 2380 if (byte_1A76C8) 2381 { 2382 dbCrypt((char*)§or[i], sizeof(sectortype), gMapRev*sizeof(sectortype)); 2383 } 2384 if (sector[i].extra > 0) 2385 { 2386 char pBuffer[nXSectorSize]; 2387 BitWriter bitWriter(pBuffer, nXSectorSize); 2388 XSECTOR* pXSector = &xsector[sector[i].extra]; 2389 bitWriter.write(pXSector->reference, 14); 2390 bitWriter.write(pXSector->state, 1); 2391 bitWriter.write(pXSector->busy, 17); 2392 bitWriter.write(pXSector->data, 16); 2393 bitWriter.write(pXSector->txID, 10); 2394 bitWriter.write(pXSector->busyWaveA, 3); 2395 bitWriter.write(pXSector->busyWaveB, 3); 2396 bitWriter.write(pXSector->rxID, 10); 2397 bitWriter.write(pXSector->command, 8); 2398 bitWriter.write(pXSector->triggerOn, 1); 2399 bitWriter.write(pXSector->triggerOff, 1); 2400 bitWriter.write(pXSector->busyTimeA, 12); 2401 bitWriter.write(pXSector->waitTimeA, 12); 2402 bitWriter.write(pXSector->restState, 1); 2403 bitWriter.write(pXSector->interruptable, 1); 2404 bitWriter.write(pXSector->amplitude, 8); 2405 bitWriter.write(pXSector->freq, 8); 2406 bitWriter.write(pXSector->reTriggerA, 1); 2407 bitWriter.write(pXSector->reTriggerB, 1); 2408 bitWriter.write(pXSector->phase, 8); 2409 bitWriter.write(pXSector->wave, 4); 2410 bitWriter.write(pXSector->shadeAlways, 1); 2411 bitWriter.write(pXSector->shadeFloor, 1); 2412 bitWriter.write(pXSector->shadeCeiling, 1); 2413 bitWriter.write(pXSector->shadeWalls, 1); 2414 bitWriter.write(pXSector->shade, 8); 2415 bitWriter.write(pXSector->panAlways, 1); 2416 bitWriter.write(pXSector->panFloor, 1); 2417 bitWriter.write(pXSector->panCeiling, 1); 2418 bitWriter.write(pXSector->Drag, 1); 2419 bitWriter.write(pXSector->Underwater, 1); 2420 bitWriter.write(pXSector->Depth, 3); 2421 bitWriter.write(pXSector->panVel, 8); 2422 bitWriter.write(pXSector->panAngle, 11); 2423 bitWriter.write(pXSector->unused1, 1); 2424 bitWriter.write(pXSector->decoupled, 1); 2425 bitWriter.write(pXSector->triggerOnce, 1); 2426 bitWriter.write(pXSector->isTriggered, 1); 2427 bitWriter.write(pXSector->Key, 3); 2428 bitWriter.write(pXSector->Push, 1); 2429 bitWriter.write(pXSector->Vector, 1); 2430 bitWriter.write(pXSector->Reserved, 1); 2431 bitWriter.write(pXSector->Enter, 1); 2432 bitWriter.write(pXSector->Exit, 1); 2433 bitWriter.write(pXSector->Wallpush, 1); 2434 bitWriter.write(pXSector->color, 1); 2435 bitWriter.write(pXSector->unused2, 1); 2436 bitWriter.write(pXSector->busyTimeB, 12); 2437 bitWriter.write(pXSector->waitTimeB, 12); 2438 bitWriter.write(pXSector->stopOn, 1); 2439 bitWriter.write(pXSector->stopOff, 1); 2440 bitWriter.write(pXSector->ceilpal, 4); 2441 bitWriter.write(pXSector->offCeilZ, 32); 2442 bitWriter.write(pXSector->onCeilZ, 32); 2443 bitWriter.write(pXSector->offFloorZ, 32); 2444 bitWriter.write(pXSector->onFloorZ, 32); 2445 bitWriter.write(pXSector->marker0, 16); 2446 bitWriter.write(pXSector->marker1, 16); 2447 bitWriter.write(pXSector->Crush, 1); 2448 bitWriter.write(pXSector->ceilXPanFrac, 8); 2449 bitWriter.write(pXSector->ceilYPanFrac, 8); 2450 bitWriter.write(pXSector->floorXPanFrac, 8); 2451 bitWriter.write(pXSector->damageType, 3); 2452 bitWriter.write(pXSector->floorpal, 4); 2453 bitWriter.write(pXSector->floorYPanFrac, 8); 2454 bitWriter.write(pXSector->locked, 1); 2455 bitWriter.write(pXSector->windVel, 10); 2456 bitWriter.write(pXSector->windAng, 11); 2457 bitWriter.write(pXSector->windAlways, 1); 2458 bitWriter.write(pXSector->dudeLockout, 1); 2459 bitWriter.write(pXSector->bobTheta, 11); 2460 bitWriter.write(pXSector->bobZRange, 5); 2461 bitWriter.write(pXSector->bobSpeed, 12); 2462 bitWriter.write(pXSector->bobAlways, 1); 2463 bitWriter.write(pXSector->bobFloor, 1); 2464 bitWriter.write(pXSector->bobCeiling, 1); 2465 bitWriter.write(pXSector->bobRotate, 1); 2466 IOBuffer1.Write(pBuffer, nXSectorSize); 2467 } 2468 } 2469 for (int i = 0; i < numwalls; i++) 2470 { 2471 if (byte_1A76C8) 2472 { 2473 dbCrypt((char*)&wall[i], sizeof(walltype), gMapRev*sizeof(sectortype) | kMapHeaderNew); 2474 } 2475 IOBuffer1.Write(&wall[i], sizeof(walltype)); 2476 if (byte_1A76C8) 2477 { 2478 dbCrypt((char*)&wall[i], sizeof(walltype), gMapRev*sizeof(sectortype) | kMapHeaderNew); 2479 } 2480 if (wall[i].extra > 0) 2481 { 2482 char pBuffer[nXWallSize]; 2483 BitWriter bitWriter(pBuffer, nXWallSize); 2484 XWALL* pXWall = &xwall[wall[i].extra]; 2485 bitWriter.write(pXWall->reference, 14); 2486 bitWriter.write(pXWall->state, 1); 2487 bitWriter.write(pXWall->busy, 17); 2488 bitWriter.write(pXWall->data, 16); 2489 bitWriter.write(pXWall->txID, 10); 2490 bitWriter.write(pXWall->unused1, 6); 2491 bitWriter.write(pXWall->rxID, 10); 2492 bitWriter.write(pXWall->command, 8); 2493 bitWriter.write(pXWall->triggerOn, 1); 2494 bitWriter.write(pXWall->triggerOff, 1); 2495 bitWriter.write(pXWall->busyTime, 12); 2496 bitWriter.write(pXWall->waitTime, 12); 2497 bitWriter.write(pXWall->restState, 1); 2498 bitWriter.write(pXWall->interruptable, 1); 2499 bitWriter.write(pXWall->panAlways, 1); 2500 bitWriter.write(pXWall->panXVel, 8); 2501 bitWriter.write(pXWall->panYVel, 8); 2502 bitWriter.write(pXWall->decoupled, 1); 2503 bitWriter.write(pXWall->triggerOnce, 1); 2504 bitWriter.write(pXWall->isTriggered, 1); 2505 bitWriter.write(pXWall->key, 3); 2506 bitWriter.write(pXWall->triggerPush, 1); 2507 bitWriter.write(pXWall->triggerVector, 1); 2508 bitWriter.write(pXWall->triggerTouch, 1); 2509 bitWriter.write(pXWall->unused2, 2); 2510 bitWriter.write(pXWall->xpanFrac, 8); 2511 bitWriter.write(pXWall->ypanFrac, 8); 2512 bitWriter.write(pXWall->locked, 1); 2513 bitWriter.write(pXWall->dudeLockout, 1); 2514 bitWriter.write(pXWall->unused3, 4); 2515 bitWriter.write(pXWall->unused4, 32); 2516 IOBuffer1.Write(pBuffer, nXWallSize); 2517 } 2518 } 2519 for (int i = 0; i < kMaxSprites; i++) 2520 { 2521 if (sprite[i].statnum < kMaxStatus) 2522 { 2523 if (byte_1A76C8) 2524 { 2525 dbCrypt((char*)&sprite[i], sizeof(spritetype), gMapRev*sizeof(spritetype) | kMapHeaderNew); 2526 } 2527 IOBuffer1.Write(&sprite[i], sizeof(spritetype)); 2528 if (byte_1A76C8) 2529 { 2530 dbCrypt((char*)&sprite[i], sizeof(spritetype), gMapRev*sizeof(spritetype) | kMapHeaderNew); 2531 } 2532 if (sprite[i].extra > 0) 2533 { 2534 char pBuffer[nXSpriteSize]; 2535 BitWriter bitWriter(pBuffer, nXSpriteSize); 2536 XSPRITE* pXSprite = &xsprite[sprite[i].extra]; 2537 bitWriter.write(pXSprite->reference, 14); 2538 bitWriter.write(pXSprite->state, 1); 2539 bitWriter.write(pXSprite->busy, 17); 2540 bitWriter.write(pXSprite->txID, 10); 2541 bitWriter.write(pXSprite->rxID, 10); 2542 bitWriter.write(pXSprite->command, 8); 2543 bitWriter.write(pXSprite->triggerOn, 1); 2544 bitWriter.write(pXSprite->triggerOff, 1); 2545 bitWriter.write(pXSprite->wave, 2); 2546 bitWriter.write(pXSprite->busyTime, 12); 2547 bitWriter.write(pXSprite->waitTime, 12); 2548 bitWriter.write(pXSprite->restState, 1); 2549 bitWriter.write(pXSprite->Interrutable, 1); 2550 bitWriter.write(pXSprite->unused1, 2); 2551 bitWriter.write(pXSprite->respawnPending, 2); 2552 bitWriter.write(pXSprite->unused2, 1); 2553 bitWriter.write(pXSprite->lT, 1); 2554 bitWriter.write(pXSprite->dropMsg, 8); 2555 bitWriter.write(pXSprite->Decoupled, 1); 2556 bitWriter.write(pXSprite->triggerOnce, 1); 2557 bitWriter.write(pXSprite->isTriggered, 1); 2558 bitWriter.write(pXSprite->key, 3); 2559 bitWriter.write(pXSprite->Push, 1); 2560 bitWriter.write(pXSprite->Vector, 1); 2561 bitWriter.write(pXSprite->Impact, 1); 2562 bitWriter.write(pXSprite->Pickup, 1); 2563 bitWriter.write(pXSprite->Touch, 1); 2564 bitWriter.write(pXSprite->Sight, 1); 2565 bitWriter.write(pXSprite->Proximity, 1); 2566 bitWriter.write(pXSprite->unused3, 2); 2567 bitWriter.write(pXSprite->lSkill, 5); 2568 bitWriter.write(pXSprite->lS, 1); 2569 bitWriter.write(pXSprite->lB, 1); 2570 bitWriter.write(pXSprite->lC, 1); 2571 bitWriter.write(pXSprite->DudeLockout, 1); 2572 bitWriter.write(pXSprite->data1, 16); 2573 bitWriter.write(pXSprite->data2, 16); 2574 bitWriter.write(pXSprite->data3, 16); 2575 bitWriter.write(pXSprite->goalAng, 11); 2576 bitWriter.write(pXSprite->dodgeDir, 2); 2577 bitWriter.write(pXSprite->locked, 1); 2578 bitWriter.write(pXSprite->medium, 2); 2579 bitWriter.write(pXSprite->respawn, 2); 2580 bitWriter.write(pXSprite->data4, 16); 2581 bitWriter.write(pXSprite->unused4, 6); 2582 bitWriter.write(pXSprite->lockMsg, 8); 2583 bitWriter.write(pXSprite->health, 12); 2584 bitWriter.write(pXSprite->dudeDeaf, 1); 2585 bitWriter.write(pXSprite->dudeAmbush, 1); 2586 bitWriter.write(pXSprite->dudeGuard, 1); 2587 bitWriter.write(pXSprite->dudeFlag4, 1); 2588 bitWriter.write(pXSprite->target, 16); 2589 bitWriter.write(pXSprite->targetX, 32); 2590 bitWriter.write(pXSprite->targetY, 32); 2591 bitWriter.write(pXSprite->targetZ, 32); 2592 bitWriter.write(pXSprite->burnTime, 16); 2593 bitWriter.write(pXSprite->burnSource, 16); 2594 bitWriter.write(pXSprite->height, 16); 2595 bitWriter.write(pXSprite->stateTimer, 16); 2596 IOBuffer1.Write(pBuffer, nXSpriteSize); 2597 } 2598 } 2599 } 2600 unsigned int nCRC = Bcrc32(pData, nSize-4, 0); 2601 IOBuffer1.Write(&nCRC, 4); 2602 int nHandle = Bopen(sMapExt, BO_BINARY|BO_TRUNC|BO_CREAT|BO_WRONLY, BS_IREAD|BS_IWRITE); 2603 if (nHandle == -1) 2604 { 2605 LOG_F(ERROR, "Couldn't open \"%s\" for writing: %s", sMapExt, strerror(errno)); 2606 Xfree(pData); 2607 return -1; 2608 } 2609 if (Bwrite(nHandle, pData, nSize) != nSize) 2610 { 2611 LOG_F(ERROR, "Couldn't write to \"%s\": %s", sMapExt, strerror(errno)); 2612 Bclose(nHandle); 2613 Xfree(pData); 2614 return -1; 2615 } 2616 Bclose(nHandle); 2617 Xfree(pData); 2618 return 0; 2619 #if 0 2620 char *pExt = strchr(sMapExt, '.'); 2621 if (pExt) 2622 { 2623 *pExt = 0; 2624 } 2625 gSysRes.AddExternalResource(sMapExt, "MAP", nSize); 2626 DICTNODE *hMap = gSysRes.Lookup(sMapExt, "MAP"); 2627 dassert(hMap != NULL); 2628 #endif 2629 } 2630 2631 int32_t qloadboard(const char* filename, char flags, vec3_t* dapos, int16_t* daang, int16_t* dacursectnum) 2632 { 2633 // NUKE-TODO: implement flags, see mapedit.cpp 2634 UNREFERENCED_PARAMETER(flags); 2635 return dbLoadMap(filename, &dapos->x, &dapos->y, &dapos->z, (short*)daang, (short*)dacursectnum, NULL); 2636 } 2637 2638 int32_t qsaveboard(const char* filename, const vec3_t* dapos, int16_t daang, int16_t dacursectnum) 2639 { 2640 // NUKE-TODO: see mapedit.cpp 2641 byte_1A76C6 = byte_1A76C8 = byte_1A76C7 = 1; 2642 return dbSaveMap(filename, dapos->x, dapos->y, dapos->z, daang, dacursectnum); 2643 }