2019-09-19 22:42:45 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
|
|
Copyright (C) 2019 Nuke.YKT
|
|
|
|
|
|
|
|
This file is part of NBlood.
|
|
|
|
|
|
|
|
NBlood is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License version 2
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
2019-09-21 18:59:54 +00:00
|
|
|
|
|
|
|
#include "ns.h" // Must come before everything else!
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
#include "build.h"
|
|
|
|
#include "common_game.h"
|
2020-07-25 16:48:26 +00:00
|
|
|
#include "zstring.h"
|
2019-11-02 21:10:53 +00:00
|
|
|
#include "m_crc32.h"
|
2020-01-11 11:54:58 +00:00
|
|
|
#include "md4.h"
|
2020-09-06 10:44:58 +00:00
|
|
|
#include "automap.h"
|
2020-10-28 23:08:06 +00:00
|
|
|
#include "raze_sound.h"
|
2021-03-19 19:40:44 +00:00
|
|
|
#include "gamefuncs.h"
|
2021-05-02 22:04:36 +00:00
|
|
|
#include "hw_sections.h"
|
2021-05-03 15:48:35 +00:00
|
|
|
#include "sectorgeometry.h"
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2020-12-09 14:56:32 +00:00
|
|
|
#include "blood.h"
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2019-09-22 06:39:22 +00:00
|
|
|
BEGIN_BLD_NS
|
|
|
|
|
2020-12-02 11:46:44 +00:00
|
|
|
DBloodActor bloodActors[kMaxSprites];
|
|
|
|
|
|
|
|
|
2020-05-22 16:28:03 +00:00
|
|
|
bool gModernMap = false;
|
2021-11-19 19:50:02 +00:00
|
|
|
unsigned int gStatCount[kMaxStatus + 1];
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
int gVisibility;
|
|
|
|
|
|
|
|
void dbCrypt(char *pPtr, int nLength, int nKey)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < nLength; i++)
|
|
|
|
{
|
|
|
|
pPtr[i] = pPtr[i] ^ nKey;
|
|
|
|
nKey++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InsertSpriteSect(int nSprite, int nSector)
|
|
|
|
{
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(nSprite >= 0 && nSprite < kMaxSprites);
|
2021-11-09 08:06:54 +00:00
|
|
|
assert(validSectorIndex(nSector));
|
2019-09-19 22:42:45 +00:00
|
|
|
int nOther = headspritesect[nSector];
|
|
|
|
if (nOther >= 0)
|
|
|
|
{
|
|
|
|
prevspritesect[nSprite] = prevspritesect[nOther];
|
|
|
|
nextspritesect[nSprite] = -1;
|
|
|
|
nextspritesect[prevspritesect[nOther]] = nSprite;
|
|
|
|
prevspritesect[nOther] = nSprite;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
prevspritesect[nSprite] = nSprite;
|
|
|
|
nextspritesect[nSprite] = -1;
|
|
|
|
headspritesect[nSector] = nSprite;
|
|
|
|
}
|
|
|
|
sprite[nSprite].sectnum = nSector;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveSpriteSect(int nSprite)
|
|
|
|
{
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(nSprite >= 0 && nSprite < kMaxSprites);
|
2019-09-19 22:42:45 +00:00
|
|
|
int nSector = sprite[nSprite].sectnum;
|
2021-11-09 08:06:54 +00:00
|
|
|
assert(validSectorIndex(nSector));
|
2019-09-19 22:42:45 +00:00
|
|
|
int nOther = nextspritesect[nSprite];
|
|
|
|
if (nOther < 0)
|
|
|
|
{
|
|
|
|
nOther = headspritesect[nSector];
|
|
|
|
}
|
|
|
|
prevspritesect[nOther] = prevspritesect[nSprite];
|
|
|
|
if (headspritesect[nSector] != nSprite)
|
|
|
|
{
|
|
|
|
nextspritesect[prevspritesect[nSprite]] = nextspritesect[nSprite];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
headspritesect[nSector] = nextspritesect[nSprite];
|
|
|
|
}
|
2020-10-13 17:43:45 +00:00
|
|
|
sprite[nSprite].sectnum = MAXSECTORS;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InsertSpriteStat(int nSprite, int nStat)
|
|
|
|
{
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(nSprite >= 0 && nSprite < kMaxSprites);
|
|
|
|
assert(nStat >= 0 && nStat <= kMaxStatus);
|
2019-09-19 22:42:45 +00:00
|
|
|
int nOther = headspritestat[nStat];
|
|
|
|
if (nOther >= 0)
|
|
|
|
{
|
|
|
|
prevspritestat[nSprite] = prevspritestat[nOther];
|
|
|
|
nextspritestat[nSprite] = -1;
|
|
|
|
nextspritestat[prevspritestat[nOther]] = nSprite;
|
|
|
|
prevspritestat[nOther] = nSprite;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
prevspritestat[nSprite] = nSprite;
|
|
|
|
nextspritestat[nSprite] = -1;
|
|
|
|
headspritestat[nStat] = nSprite;
|
|
|
|
}
|
|
|
|
sprite[nSprite].statnum = nStat;
|
|
|
|
gStatCount[nStat]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveSpriteStat(int nSprite)
|
|
|
|
{
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(nSprite >= 0 && nSprite < kMaxSprites);
|
2019-09-19 22:42:45 +00:00
|
|
|
int nStat = sprite[nSprite].statnum;
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(nStat >= 0 && nStat <= kMaxStatus);
|
2019-09-19 22:42:45 +00:00
|
|
|
int nOther = nextspritestat[nSprite];
|
|
|
|
if (nOther < 0)
|
|
|
|
{
|
|
|
|
nOther = headspritestat[nStat];
|
|
|
|
}
|
|
|
|
prevspritestat[nOther] = prevspritestat[nSprite];
|
|
|
|
if (headspritestat[nStat] != nSprite)
|
|
|
|
{
|
|
|
|
nextspritestat[prevspritestat[nSprite]] = nextspritestat[nSprite];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
headspritestat[nStat] = nextspritestat[nSprite];
|
|
|
|
}
|
2020-10-13 17:43:45 +00:00
|
|
|
sprite[nSprite].statnum = MAXSTATUS;
|
2019-09-19 22:42:45 +00:00
|
|
|
gStatCount[nStat]--;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qinitspritelists(void) // Replace
|
|
|
|
{
|
2021-11-20 23:03:56 +00:00
|
|
|
for (int i = 0; i <= MAXSECTORS; i++)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
headspritesect[i] = -1;
|
|
|
|
}
|
2021-11-16 17:15:56 +00:00
|
|
|
for (int i = 0; i <= kMaxStatus; i++)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
headspritestat[i] = -1;
|
|
|
|
}
|
2021-11-16 17:15:56 +00:00
|
|
|
for (int i = 0; i < kMaxSprites; i++)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
sprite[i].sectnum = -1;
|
|
|
|
InsertSpriteStat(i, kMaxStatus);
|
|
|
|
}
|
|
|
|
memset(gStatCount, 0, sizeof(gStatCount));
|
2019-06-29 12:24:23 +00:00
|
|
|
Numsprites = 0;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
2021-09-05 08:09:59 +00:00
|
|
|
DBloodActor* InsertSprite(int nSector, int nStat)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
int nSprite = headspritestat[kMaxStatus];
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(nSprite < kMaxSprites);
|
2019-09-19 22:42:45 +00:00
|
|
|
if (nSprite < 0)
|
|
|
|
{
|
2021-09-05 08:09:59 +00:00
|
|
|
I_Error("Out of sprites!"); // we cannot deal with this - and most of the calling code never checks...
|
|
|
|
return nullptr;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
RemoveSpriteStat(nSprite);
|
2021-08-27 15:04:34 +00:00
|
|
|
DBloodActor* actor = &bloodActors[nSprite];
|
2021-09-05 07:59:10 +00:00
|
|
|
actor->Clear();
|
2021-08-27 15:04:34 +00:00
|
|
|
spritetype *pSprite = &actor->s();
|
|
|
|
memset(pSprite, 0, sizeof(spritetype));
|
2019-09-19 22:42:45 +00:00
|
|
|
InsertSpriteStat(nSprite, nStat);
|
|
|
|
InsertSpriteSect(nSprite, nSector);
|
|
|
|
pSprite->cstat = 128;
|
|
|
|
pSprite->clipdist = 32;
|
|
|
|
pSprite->xrepeat = pSprite->yrepeat = 64;
|
2021-08-29 21:10:19 +00:00
|
|
|
actor->SetOwner(nullptr);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2019-06-29 12:24:23 +00:00
|
|
|
Numsprites++;
|
|
|
|
|
2021-03-26 14:06:14 +00:00
|
|
|
sprite[nSprite].time = leveltimer++;
|
2021-09-05 08:09:59 +00:00
|
|
|
return actor;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int DeleteSprite(int nSprite)
|
|
|
|
{
|
2020-10-28 23:08:06 +00:00
|
|
|
FVector3 pos = GetSoundPos(&sprite[nSprite].pos);
|
|
|
|
soundEngine->RelinkSound(SOURCE_Actor, &sprite[nSprite], nullptr, &pos);
|
|
|
|
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus);
|
2019-09-19 22:42:45 +00:00
|
|
|
RemoveSpriteStat(nSprite);
|
2021-11-09 08:06:54 +00:00
|
|
|
assert(validSectorIndex(sprite[nSprite].sectnum));
|
2019-09-19 22:42:45 +00:00
|
|
|
RemoveSpriteSect(nSprite);
|
|
|
|
InsertSpriteStat(nSprite, kMaxStatus);
|
2021-08-28 08:38:36 +00:00
|
|
|
#ifdef NOONE_EXTENSIONS
|
|
|
|
for (auto& ctrl : gPlayerCtrl) if (ctrl.qavScene.initiator == &bloodActors[nSprite]) ctrl.qavScene.initiator = nullptr;
|
|
|
|
#endif
|
2019-06-29 12:24:23 +00:00
|
|
|
Numsprites--;
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
return nSprite;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ChangeSpriteSect(int nSprite, int nSector)
|
|
|
|
{
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(nSprite >= 0 && nSprite < kMaxSprites);
|
2021-11-09 08:06:54 +00:00
|
|
|
assert(validSectorIndex(nSector));
|
|
|
|
assert(validSectorIndex(sprite[nSprite].sectnum));
|
2019-09-19 22:42:45 +00:00
|
|
|
RemoveSpriteSect(nSprite);
|
|
|
|
InsertSpriteSect(nSprite, nSector);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qchangespritesect(short nSprite, short nSector)
|
|
|
|
{
|
|
|
|
return ChangeSpriteSect(nSprite, nSector);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ChangeSpriteStat(int nSprite, int nStatus)
|
|
|
|
{
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(nSprite >= 0 && nSprite < kMaxSprites);
|
|
|
|
assert(nStatus >= 0 && nStatus < kMaxStatus);
|
|
|
|
assert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus);
|
2021-11-09 08:06:54 +00:00
|
|
|
assert(validSectorIndex(sprite[nSprite].sectnum));
|
2019-09-19 22:42:45 +00:00
|
|
|
RemoveSpriteStat(nSprite);
|
|
|
|
InsertSpriteStat(nSprite, nStatus);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-11-19 19:50:02 +00:00
|
|
|
void InitFreeList(unsigned short* pList, int nCount)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
for (int i = 1; i < nCount; i++)
|
|
|
|
{
|
2021-11-19 19:50:02 +00:00
|
|
|
pList[i] = i - 1;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
pList[0] = nCount - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void dbInit(void)
|
|
|
|
{
|
|
|
|
initspritelists();
|
|
|
|
for (int i = 0; i < kMaxSprites; i++)
|
|
|
|
{
|
|
|
|
sprite[i].cstat = 128;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PropagateMarkerReferences(void)
|
|
|
|
{
|
2021-09-04 17:44:19 +00:00
|
|
|
BloodStatIterator it(kStatMarker);
|
|
|
|
while (auto actor = it.Next())
|
|
|
|
{
|
|
|
|
switch (actor->s().type)
|
|
|
|
{
|
2019-10-11 21:59:39 +00:00
|
|
|
case kMarkerOff:
|
|
|
|
case kMarkerAxis:
|
2021-09-04 17:44:19 +00:00
|
|
|
case kMarkerWarpDest:
|
|
|
|
{
|
|
|
|
int nOwner = actor->s().owner;
|
|
|
|
if (nOwner >= 0 && nOwner < numsectors)
|
|
|
|
{
|
2021-11-19 19:25:16 +00:00
|
|
|
if (sector[nOwner].hasX())
|
2021-09-04 17:44:19 +00:00
|
|
|
{
|
2021-11-19 19:25:16 +00:00
|
|
|
sector[nOwner].xs().marker0 = actor;
|
2019-10-11 21:59:39 +00:00
|
|
|
continue;
|
|
|
|
}
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2021-09-04 17:44:19 +00:00
|
|
|
case kMarkerOn:
|
|
|
|
{
|
|
|
|
int nOwner = actor->s().owner;
|
|
|
|
if (nOwner >= 0 && nOwner < numsectors)
|
|
|
|
{
|
2021-11-19 19:25:16 +00:00
|
|
|
if (sector[nOwner].hasX())
|
2021-09-04 17:44:19 +00:00
|
|
|
{
|
2021-11-19 19:25:16 +00:00
|
|
|
sector[nOwner].xs().marker1 = actor;
|
2019-10-11 21:59:39 +00:00
|
|
|
continue;
|
|
|
|
}
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2019-10-11 21:59:39 +00:00
|
|
|
|
2021-09-04 17:44:19 +00:00
|
|
|
DeleteSprite(actor);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-22 15:47:08 +00:00
|
|
|
bool drawtile2048, encrypted;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
|
|
MAPHEADER2 byte_19AE44;
|
|
|
|
|
|
|
|
unsigned int dbReadMapCRC(const char *pPath)
|
|
|
|
{
|
2020-11-22 15:47:08 +00:00
|
|
|
encrypted = 0;
|
2019-09-30 17:08:35 +00:00
|
|
|
|
2020-07-25 16:48:26 +00:00
|
|
|
FString mapname = pPath;
|
|
|
|
DefaultExtension(mapname, ".map");
|
|
|
|
auto fr = fileSystem.OpenFileReader(mapname);
|
2019-09-30 17:08:35 +00:00
|
|
|
|
2020-07-25 16:48:26 +00:00
|
|
|
if (!fr.isOpen())
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("Error opening map file %s", pPath);
|
2019-09-30 17:08:35 +00:00
|
|
|
return -1;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-09-30 17:08:35 +00:00
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
MAPSIGNATURE header;
|
2020-07-25 16:48:26 +00:00
|
|
|
fr.Read(&header, 6);
|
2019-09-19 22:42:45 +00:00
|
|
|
if (memcmp(header.signature, "BLM\x1a", 4))
|
|
|
|
{
|
2020-07-27 22:01:16 +00:00
|
|
|
I_Error("%s: Map file corrupted.", mapname.GetChars());
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-07-25 16:48:26 +00:00
|
|
|
int ver = LittleShort(header.version);
|
|
|
|
if ((ver & 0xff00) == 0x600)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
}
|
2020-07-25 16:48:26 +00:00
|
|
|
else if ((ver & 0xff00) == 0x700)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-11-22 15:47:08 +00:00
|
|
|
encrypted = 1;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-07-27 22:01:16 +00:00
|
|
|
I_Error("%s: Map file is wrong version.", mapname.GetChars());
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-07-25 16:48:26 +00:00
|
|
|
fr.Seek(-4, FileReader::SeekEnd);
|
|
|
|
return fr.ReadInt32();
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
2020-11-22 15:47:08 +00:00
|
|
|
int gMapRev, gMattId, gSkyCount;
|
2019-09-19 22:42:45 +00:00
|
|
|
//char byte_19AE44[128];
|
2019-06-29 15:37:04 +00:00
|
|
|
const int nXSectorSize = 60;
|
|
|
|
const int nXSpriteSize = 56;
|
|
|
|
const int nXWallSize = 24;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2020-10-03 16:35:47 +00:00
|
|
|
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
// This is the on-disk format. Only Blood still needs this for its retarded encryption that has to read this in as a block so that it can be decoded.
|
|
|
|
// Keep it local so that the engine's sprite type is no longer limited by file format restrictions.
|
|
|
|
struct spritetypedisk
|
|
|
|
{
|
|
|
|
int32_t x, y, z;
|
|
|
|
uint16_t cstat;
|
|
|
|
int16_t picnum;
|
|
|
|
int8_t shade;
|
|
|
|
uint8_t pal, clipdist, detail;
|
|
|
|
uint8_t xrepeat, yrepeat;
|
|
|
|
int8_t xoffset, yoffset;
|
|
|
|
int16_t sectnum, statnum;
|
|
|
|
int16_t ang, owner;
|
|
|
|
int16_t index, yvel, inittype;
|
|
|
|
int16_t type;
|
|
|
|
int16_t hitag;
|
|
|
|
int16_t extra;
|
|
|
|
};
|
2020-10-11 18:57:20 +00:00
|
|
|
|
|
|
|
struct sectortypedisk
|
|
|
|
{
|
|
|
|
int16_t wallptr, wallnum;
|
|
|
|
int32_t ceilingz, floorz;
|
|
|
|
uint16_t ceilingstat, floorstat;
|
|
|
|
int16_t ceilingpicnum, ceilingheinum;
|
|
|
|
int8_t ceilingshade;
|
|
|
|
uint8_t ceilingpal, ceilingxpanning, ceilingypanning;
|
|
|
|
int16_t floorpicnum, floorheinum;
|
|
|
|
int8_t floorshade;
|
|
|
|
uint8_t floorpal, floorxpanning, floorypanning;
|
|
|
|
uint8_t visibility, fogpal;
|
|
|
|
int16_t type;
|
|
|
|
int16_t hitag;
|
|
|
|
int16_t extra;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct walltypedisk
|
|
|
|
{
|
|
|
|
int32_t x, y;
|
|
|
|
int16_t point2, nextwall, nextsector;
|
|
|
|
uint16_t cstat;
|
|
|
|
int16_t picnum, overpicnum;
|
|
|
|
int8_t shade;
|
|
|
|
uint8_t pal, xrepeat, yrepeat, xpanning, ypanning;
|
|
|
|
int16_t type;
|
|
|
|
int16_t hitag;
|
|
|
|
int16_t extra;
|
|
|
|
};
|
|
|
|
|
2020-10-03 16:35:47 +00:00
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
|
|
|
2021-11-19 19:50:02 +00:00
|
|
|
void dbLoadMap(const char* pPath, int* pX, int* pY, int* pZ, short* pAngle, int* pSector, unsigned int* pCRC)
|
|
|
|
{
|
2019-12-29 15:35:51 +00:00
|
|
|
int16_t tpskyoff[256];
|
2020-09-06 08:59:45 +00:00
|
|
|
ClearAutomap();
|
2021-11-19 19:50:02 +00:00
|
|
|
#ifdef NOONE_EXTENSIONS
|
2019-11-08 19:57:01 +00:00
|
|
|
gModernMap = false;
|
2021-11-19 19:50:02 +00:00
|
|
|
#endif
|
2019-11-08 19:57:01 +00:00
|
|
|
|
2021-08-28 08:38:36 +00:00
|
|
|
#ifdef NOONE_EXTENSIONS
|
|
|
|
for (auto& ctrl : gPlayerCtrl) ctrl.qavScene.initiator = nullptr;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
#ifdef USE_OPENGL
|
2021-03-15 18:39:58 +00:00
|
|
|
Polymost::Polymost_prepare_loadboard();
|
2019-09-19 22:42:45 +00:00
|
|
|
#endif
|
2019-09-22 08:16:16 +00:00
|
|
|
|
2020-07-25 16:48:26 +00:00
|
|
|
FString mapname = pPath;
|
|
|
|
DefaultExtension(mapname, ".map");
|
|
|
|
auto fr = fileSystem.OpenFileReader(mapname);
|
2019-09-30 17:08:35 +00:00
|
|
|
|
2020-07-25 16:48:26 +00:00
|
|
|
if (!fr.isOpen())
|
2019-06-28 16:03:47 +00:00
|
|
|
{
|
2020-10-11 18:57:20 +00:00
|
|
|
I_Error("Error opening map file %s", mapname.GetChars());
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
MAPSIGNATURE header;
|
2020-07-25 16:48:26 +00:00
|
|
|
fr.Read(&header, 6);
|
2019-09-19 22:42:45 +00:00
|
|
|
if (memcmp(header.signature, "BLM\x1a", 4))
|
|
|
|
{
|
2020-10-11 18:57:20 +00:00
|
|
|
I_Error("%s: Map file corrupted", mapname.GetChars());
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-11-22 15:47:08 +00:00
|
|
|
encrypted = 0;
|
2020-07-25 16:48:26 +00:00
|
|
|
if ((LittleShort(header.version) & 0xff00) == 0x700) {
|
2020-11-22 15:47:08 +00:00
|
|
|
encrypted = 1;
|
2021-11-19 19:50:02 +00:00
|
|
|
|
|
|
|
#ifdef NOONE_EXTENSIONS
|
2020-01-26 11:19:01 +00:00
|
|
|
// indicate if the map requires modern features to work properly
|
2019-10-11 21:59:39 +00:00
|
|
|
// for maps wich created in PMAPEDIT BETA13 or higher versions. Since only minor version changed,
|
|
|
|
// the map is still can be loaded with vanilla BLOOD / MAPEDIT and should work in other ports too.
|
|
|
|
if ((header.version & 0x00ff) == 0x001) gModernMap = true;
|
2021-11-19 19:50:02 +00:00
|
|
|
#endif
|
2019-10-11 21:59:39 +00:00
|
|
|
|
2021-11-19 19:50:02 +00:00
|
|
|
}
|
|
|
|
else {
|
2020-10-11 18:57:20 +00:00
|
|
|
I_Error("%s: Map file is wrong version", mapname.GetChars());
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-10-11 21:59:39 +00:00
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
MAPHEADER mapHeader;
|
2021-11-19 19:50:02 +00:00
|
|
|
fr.Read(&mapHeader, 37/* sizeof(mapHeader)*/);
|
2020-11-21 21:25:26 +00:00
|
|
|
if (mapHeader.mattid != 0 && mapHeader.mattid != 0x7474614d && mapHeader.mattid != 0x4d617474) {
|
2019-09-19 22:42:45 +00:00
|
|
|
dbCrypt((char*)&mapHeader, sizeof(mapHeader), 0x7474614d);
|
|
|
|
}
|
2019-10-11 21:59:39 +00:00
|
|
|
|
2020-11-21 21:25:26 +00:00
|
|
|
mapHeader.x = LittleLong(mapHeader.x);
|
|
|
|
mapHeader.y = LittleLong(mapHeader.y);
|
|
|
|
mapHeader.z = LittleLong(mapHeader.z);
|
|
|
|
mapHeader.ang = LittleShort(mapHeader.ang);
|
|
|
|
mapHeader.sect = LittleShort(mapHeader.sect);
|
|
|
|
mapHeader.pskybits = LittleShort(mapHeader.pskybits);
|
|
|
|
mapHeader.visibility = LittleLong(mapHeader.visibility);
|
|
|
|
mapHeader.mattid = LittleLong(mapHeader.mattid);
|
|
|
|
mapHeader.revision = LittleLong(mapHeader.revision);
|
|
|
|
mapHeader.numsectors = LittleShort(mapHeader.numsectors);
|
|
|
|
mapHeader.numwalls = LittleShort(mapHeader.numwalls);
|
|
|
|
mapHeader.numsprites = LittleShort(mapHeader.numsprites);
|
|
|
|
|
|
|
|
*pX = mapHeader.x;
|
|
|
|
*pY = mapHeader.y;
|
|
|
|
*pZ = mapHeader.z;
|
|
|
|
*pAngle = mapHeader.ang;
|
|
|
|
*pSector = mapHeader.sect;
|
|
|
|
gVisibility = g_visibility = mapHeader.visibility;
|
2020-11-22 15:47:08 +00:00
|
|
|
gMattId = mapHeader.mattid;
|
|
|
|
if (encrypted)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-11-21 21:25:26 +00:00
|
|
|
if (mapHeader.mattid == 0x7474614d || mapHeader.mattid == 0x4d617474)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-11-22 15:47:08 +00:00
|
|
|
drawtile2048 = 1;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-11-21 21:25:26 +00:00
|
|
|
else if (!mapHeader.mattid)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-11-22 15:47:08 +00:00
|
|
|
drawtile2048 = 0;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-10-11 18:57:20 +00:00
|
|
|
I_Error("%s: Corrupted Map file", mapname.GetChars());
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-21 21:25:26 +00:00
|
|
|
else if (mapHeader.mattid)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-10-11 18:57:20 +00:00
|
|
|
I_Error("%s: Corrupted Map file", mapname.GetChars());
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-11-21 21:25:26 +00:00
|
|
|
parallaxtype = mapHeader.parallax;
|
|
|
|
gMapRev = mapHeader.revision;
|
|
|
|
numsectors = mapHeader.numsectors;
|
|
|
|
numwalls = mapHeader.numwalls;
|
2021-11-15 23:30:01 +00:00
|
|
|
allocateMapArrays(mapHeader.numsprites);
|
2021-11-21 17:19:47 +00:00
|
|
|
#if 1 // bad, bad hack, just for making Polymost happy...
|
|
|
|
PolymostAllocFakeSector();
|
|
|
|
#endif
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
dbInit();
|
2020-11-22 15:47:08 +00:00
|
|
|
if (encrypted)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-07-25 16:48:26 +00:00
|
|
|
fr.Read(&byte_19AE44, 128);
|
2019-09-19 22:42:45 +00:00
|
|
|
dbCrypt((char*)&byte_19AE44, 128, numwalls);
|
2020-08-03 17:09:57 +00:00
|
|
|
|
2020-11-21 22:40:08 +00:00
|
|
|
byte_19AE44.numxsprites = LittleLong(byte_19AE44.numxsprites);
|
|
|
|
byte_19AE44.numxwalls = LittleLong(byte_19AE44.numxwalls);
|
|
|
|
byte_19AE44.numxsectors = LittleLong(byte_19AE44.numxsectors);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memset(&byte_19AE44, 0, 128);
|
|
|
|
}
|
2021-11-19 19:50:02 +00:00
|
|
|
gSkyCount = 1 << mapHeader.pskybits;
|
|
|
|
fr.Read(tpskyoff, gSkyCount * sizeof(tpskyoff[0]));
|
2020-11-22 15:47:08 +00:00
|
|
|
if (encrypted)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2021-11-19 19:50:02 +00:00
|
|
|
dbCrypt((char*)tpskyoff, gSkyCount * sizeof(tpskyoff[0]), gSkyCount * 2);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-07-14 22:06:19 +00:00
|
|
|
|
|
|
|
psky_t* pSky = tileSetupSky(DEFAULTPSKY);
|
|
|
|
pSky->horizfrac = 65536;
|
2020-11-21 21:25:26 +00:00
|
|
|
pSky->lognumtiles = mapHeader.pskybits;
|
2019-09-19 22:42:45 +00:00
|
|
|
for (int i = 0; i < ClipHigh(gSkyCount, MAXPSKYTILES); i++)
|
|
|
|
{
|
2020-08-03 17:09:57 +00:00
|
|
|
pSky->tileofs[i] = LittleShort(tpskyoff[i]);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-07-14 22:06:19 +00:00
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
for (int i = 0; i < numsectors; i++)
|
|
|
|
{
|
2021-11-19 19:50:02 +00:00
|
|
|
sectortype* pSector = §or[i];
|
2020-10-11 18:57:20 +00:00
|
|
|
sectortypedisk load;
|
|
|
|
fr.Read(&load, sizeof(sectortypedisk));
|
2020-11-22 15:47:08 +00:00
|
|
|
if (encrypted)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2021-11-19 19:50:02 +00:00
|
|
|
dbCrypt((char*)&load, sizeof(sectortypedisk), gMapRev * sizeof(sectortypedisk));
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-10-11 18:57:20 +00:00
|
|
|
pSector->wallptr = LittleShort(load.wallptr);
|
|
|
|
pSector->wallnum = LittleShort(load.wallnum);
|
|
|
|
pSector->ceilingz = LittleLong(load.ceilingz);
|
|
|
|
pSector->floorz = LittleLong(load.floorz);
|
|
|
|
pSector->ceilingstat = LittleShort(load.ceilingstat);
|
|
|
|
pSector->floorstat = LittleShort(load.floorstat);
|
|
|
|
pSector->ceilingpicnum = LittleShort(load.ceilingpicnum);
|
|
|
|
pSector->ceilingheinum = LittleShort(load.ceilingheinum);
|
|
|
|
pSector->floorpicnum = LittleShort(load.floorpicnum);
|
|
|
|
pSector->floorheinum = LittleShort(load.floorheinum);
|
|
|
|
pSector->type = LittleShort(load.type);
|
|
|
|
pSector->hitag = LittleShort(load.hitag);
|
|
|
|
pSector->extra = LittleShort(load.extra);
|
|
|
|
pSector->ceilingshade = load.ceilingshade;
|
|
|
|
pSector->ceilingpal = load.ceilingpal;
|
2020-11-25 19:52:06 +00:00
|
|
|
pSector->ceilingxpan_ = load.ceilingxpanning;
|
|
|
|
pSector->ceilingypan_ = load.ceilingypanning;
|
2020-10-11 18:57:20 +00:00
|
|
|
pSector->floorshade = load.floorshade;
|
|
|
|
pSector->floorpal = load.floorpal;
|
2020-11-25 19:52:06 +00:00
|
|
|
pSector->floorxpan_ = load.floorxpanning;
|
|
|
|
pSector->floorypan_ = load.floorypanning;
|
2020-10-11 18:57:20 +00:00
|
|
|
pSector->visibility = load.visibility;
|
2021-11-20 18:10:02 +00:00
|
|
|
pSector->slopewallofs = load.fogpal;
|
2021-04-04 18:35:38 +00:00
|
|
|
pSector->dirty = 255;
|
|
|
|
pSector->exflags = 0;
|
2019-09-19 22:42:45 +00:00
|
|
|
pSector->fogpal = 0;
|
2020-10-11 18:57:20 +00:00
|
|
|
|
2021-11-20 18:22:30 +00:00
|
|
|
if (pSector->extra > 0)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
char pBuffer[nXSectorSize];
|
2021-11-20 18:22:30 +00:00
|
|
|
pSector->allocX();
|
|
|
|
XSECTOR* pXSector = &pSector->xs();
|
2019-09-19 22:42:45 +00:00
|
|
|
int nCount;
|
2020-11-22 15:47:08 +00:00
|
|
|
if (!encrypted)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
nCount = nXSectorSize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-11-21 22:40:08 +00:00
|
|
|
nCount = byte_19AE44.numxsectors;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(nCount <= nXSectorSize);
|
2020-07-25 16:48:26 +00:00
|
|
|
fr.Read(pBuffer, nCount);
|
2019-09-19 22:42:45 +00:00
|
|
|
BitReader bitReader(pBuffer, nCount);
|
2021-11-19 16:29:49 +00:00
|
|
|
/*pXSector->reference =*/ bitReader.readSigned(14);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->state = bitReader.readUnsigned(1);
|
|
|
|
pXSector->busy = bitReader.readUnsigned(17);
|
|
|
|
pXSector->data = bitReader.readUnsigned(16);
|
|
|
|
pXSector->txID = bitReader.readUnsigned(10);
|
2019-10-25 20:53:41 +00:00
|
|
|
pXSector->busyWaveA = bitReader.readUnsigned(3);
|
|
|
|
pXSector->busyWaveB = bitReader.readUnsigned(3);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->rxID = bitReader.readUnsigned(10);
|
|
|
|
pXSector->command = bitReader.readUnsigned(8);
|
|
|
|
pXSector->triggerOn = bitReader.readUnsigned(1);
|
|
|
|
pXSector->triggerOff = bitReader.readUnsigned(1);
|
|
|
|
pXSector->busyTimeA = bitReader.readUnsigned(12);
|
|
|
|
pXSector->waitTimeA = bitReader.readUnsigned(12);
|
2019-10-25 20:53:41 +00:00
|
|
|
pXSector->restState = bitReader.readUnsigned(1);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->interruptable = bitReader.readUnsigned(1);
|
|
|
|
pXSector->amplitude = bitReader.readSigned(8);
|
|
|
|
pXSector->freq = bitReader.readUnsigned(8);
|
2019-10-25 20:53:41 +00:00
|
|
|
pXSector->reTriggerA = bitReader.readUnsigned(1);
|
|
|
|
pXSector->reTriggerB = bitReader.readUnsigned(1);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->phase = bitReader.readUnsigned(8);
|
|
|
|
pXSector->wave = bitReader.readUnsigned(4);
|
|
|
|
pXSector->shadeAlways = bitReader.readUnsigned(1);
|
|
|
|
pXSector->shadeFloor = bitReader.readUnsigned(1);
|
|
|
|
pXSector->shadeCeiling = bitReader.readUnsigned(1);
|
|
|
|
pXSector->shadeWalls = bitReader.readUnsigned(1);
|
|
|
|
pXSector->shade = bitReader.readSigned(8);
|
|
|
|
pXSector->panAlways = bitReader.readUnsigned(1);
|
|
|
|
pXSector->panFloor = bitReader.readUnsigned(1);
|
|
|
|
pXSector->panCeiling = bitReader.readUnsigned(1);
|
|
|
|
pXSector->Drag = bitReader.readUnsigned(1);
|
|
|
|
pXSector->Underwater = bitReader.readUnsigned(1);
|
|
|
|
pXSector->Depth = bitReader.readUnsigned(3);
|
|
|
|
pXSector->panVel = bitReader.readUnsigned(8);
|
|
|
|
pXSector->panAngle = bitReader.readUnsigned(11);
|
2021-05-03 22:03:01 +00:00
|
|
|
pXSector->unused1 = bitReader.readUnsigned(1);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->decoupled = bitReader.readUnsigned(1);
|
|
|
|
pXSector->triggerOnce = bitReader.readUnsigned(1);
|
2019-10-11 21:59:39 +00:00
|
|
|
pXSector->isTriggered = bitReader.readUnsigned(1);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->Key = bitReader.readUnsigned(3);
|
|
|
|
pXSector->Push = bitReader.readUnsigned(1);
|
|
|
|
pXSector->Vector = bitReader.readUnsigned(1);
|
|
|
|
pXSector->Reserved = bitReader.readUnsigned(1);
|
|
|
|
pXSector->Enter = bitReader.readUnsigned(1);
|
|
|
|
pXSector->Exit = bitReader.readUnsigned(1);
|
|
|
|
pXSector->Wallpush = bitReader.readUnsigned(1);
|
|
|
|
pXSector->color = bitReader.readUnsigned(1);
|
2021-05-03 22:03:01 +00:00
|
|
|
/*pXSector->unused2 =*/ bitReader.readUnsigned(1);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->busyTimeB = bitReader.readUnsigned(12);
|
|
|
|
pXSector->waitTimeB = bitReader.readUnsigned(12);
|
2019-10-11 21:59:39 +00:00
|
|
|
pXSector->stopOn = bitReader.readUnsigned(1);
|
|
|
|
pXSector->stopOff = bitReader.readUnsigned(1);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->ceilpal = bitReader.readUnsigned(4);
|
2019-10-25 20:53:41 +00:00
|
|
|
pXSector->offCeilZ = bitReader.readSigned(32);
|
|
|
|
pXSector->onCeilZ = bitReader.readSigned(32);
|
|
|
|
pXSector->offFloorZ = bitReader.readSigned(32);
|
|
|
|
pXSector->onFloorZ = bitReader.readSigned(32);
|
2021-09-04 17:44:19 +00:00
|
|
|
/*pXSector->marker0 =*/ bitReader.readUnsigned(16);
|
|
|
|
/*pXSector->marker1 =*/ bitReader.readUnsigned(16);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->Crush = bitReader.readUnsigned(1);
|
2020-11-25 19:52:06 +00:00
|
|
|
pSector->ceilingxpan_ += bitReader.readUnsigned(8) / 256.f;
|
|
|
|
pSector->ceilingypan_ += bitReader.readUnsigned(8) / 256.f;
|
|
|
|
pSector->floorxpan_ += bitReader.readUnsigned(8) / 256.f;
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->damageType = bitReader.readUnsigned(3);
|
|
|
|
pXSector->floorpal = bitReader.readUnsigned(4);
|
2021-03-03 12:26:58 +00:00
|
|
|
pSector->floorypan_ += bitReader.readUnsigned(8) / 256.f;
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->locked = bitReader.readUnsigned(1);
|
|
|
|
pXSector->windVel = bitReader.readUnsigned(10);
|
|
|
|
pXSector->windAng = bitReader.readUnsigned(11);
|
|
|
|
pXSector->windAlways = bitReader.readUnsigned(1);
|
2019-10-25 20:53:41 +00:00
|
|
|
pXSector->dudeLockout = bitReader.readUnsigned(1);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->bobTheta = bitReader.readUnsigned(11);
|
|
|
|
pXSector->bobZRange = bitReader.readUnsigned(5);
|
|
|
|
pXSector->bobSpeed = bitReader.readSigned(12);
|
|
|
|
pXSector->bobAlways = bitReader.readUnsigned(1);
|
|
|
|
pXSector->bobFloor = bitReader.readUnsigned(1);
|
|
|
|
pXSector->bobCeiling = bitReader.readUnsigned(1);
|
|
|
|
pXSector->bobRotate = bitReader.readUnsigned(1);
|
2021-11-19 18:04:11 +00:00
|
|
|
pXSector->busy = IntToFixed(pXSector->state);
|
2019-10-07 19:29:52 +00:00
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < numwalls; i++)
|
|
|
|
{
|
2021-11-19 19:50:02 +00:00
|
|
|
walltype* pWall = &wall[i];
|
2020-10-11 18:57:20 +00:00
|
|
|
walltypedisk load;
|
|
|
|
fr.Read(&load, sizeof(walltypedisk));
|
2020-11-22 15:47:08 +00:00
|
|
|
if (encrypted)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2021-11-19 19:50:02 +00:00
|
|
|
dbCrypt((char*)&load, sizeof(walltypedisk), (gMapRev * sizeof(sectortypedisk)) | 0x7474614d);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-10-11 18:57:20 +00:00
|
|
|
pWall->x = LittleLong(load.x);
|
|
|
|
pWall->y = LittleLong(load.y);
|
|
|
|
pWall->point2 = LittleShort(load.point2);
|
|
|
|
pWall->nextwall = LittleShort(load.nextwall);
|
|
|
|
pWall->nextsector = LittleShort(load.nextsector);
|
|
|
|
pWall->cstat = LittleShort(load.cstat);
|
|
|
|
pWall->picnum = LittleShort(load.picnum);
|
|
|
|
pWall->overpicnum = LittleShort(load.overpicnum);
|
|
|
|
pWall->type = LittleShort(load.type);
|
|
|
|
pWall->hitag = LittleShort(load.hitag);
|
|
|
|
pWall->extra = LittleShort(load.extra);
|
|
|
|
pWall->shade = load.shade;
|
|
|
|
pWall->pal = load.pal;
|
|
|
|
pWall->xrepeat = load.xrepeat;
|
2020-11-26 07:38:59 +00:00
|
|
|
pWall->xpan_ = load.xpanning;
|
2020-10-11 18:57:20 +00:00
|
|
|
pWall->yrepeat = load.yrepeat;
|
2020-11-26 07:38:59 +00:00
|
|
|
pWall->ypan_ = load.ypanning;
|
2020-10-11 18:57:20 +00:00
|
|
|
|
2021-11-20 16:01:59 +00:00
|
|
|
if (pWall->extra > 0)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
char pBuffer[nXWallSize];
|
2021-11-20 16:01:59 +00:00
|
|
|
pWall->allocX();
|
|
|
|
XWALL* pXWall = &pWall->xw();
|
2019-09-19 22:42:45 +00:00
|
|
|
int nCount;
|
2020-11-22 15:47:08 +00:00
|
|
|
if (!encrypted)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
nCount = nXWallSize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-11-21 22:40:08 +00:00
|
|
|
nCount = byte_19AE44.numxwalls;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(nCount <= nXWallSize);
|
2020-07-25 16:48:26 +00:00
|
|
|
fr.Read(pBuffer, nCount);
|
2019-09-19 22:42:45 +00:00
|
|
|
BitReader bitReader(pBuffer, nCount);
|
2021-11-19 15:59:37 +00:00
|
|
|
/*pXWall->reference =*/ bitReader.readSigned(14);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXWall->state = bitReader.readUnsigned(1);
|
|
|
|
pXWall->busy = bitReader.readUnsigned(17);
|
|
|
|
pXWall->data = bitReader.readSigned(16);
|
|
|
|
pXWall->txID = bitReader.readUnsigned(10);
|
2020-10-13 18:21:47 +00:00
|
|
|
bitReader.readUnsigned(6);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXWall->rxID = bitReader.readUnsigned(10);
|
|
|
|
pXWall->command = bitReader.readUnsigned(8);
|
|
|
|
pXWall->triggerOn = bitReader.readUnsigned(1);
|
|
|
|
pXWall->triggerOff = bitReader.readUnsigned(1);
|
|
|
|
pXWall->busyTime = bitReader.readUnsigned(12);
|
|
|
|
pXWall->waitTime = bitReader.readUnsigned(12);
|
|
|
|
pXWall->restState = bitReader.readUnsigned(1);
|
|
|
|
pXWall->interruptable = bitReader.readUnsigned(1);
|
|
|
|
pXWall->panAlways = bitReader.readUnsigned(1);
|
|
|
|
pXWall->panXVel = bitReader.readSigned(8);
|
|
|
|
pXWall->panYVel = bitReader.readSigned(8);
|
|
|
|
pXWall->decoupled = bitReader.readUnsigned(1);
|
|
|
|
pXWall->triggerOnce = bitReader.readUnsigned(1);
|
|
|
|
pXWall->isTriggered = bitReader.readUnsigned(1);
|
|
|
|
pXWall->key = bitReader.readUnsigned(3);
|
|
|
|
pXWall->triggerPush = bitReader.readUnsigned(1);
|
|
|
|
pXWall->triggerVector = bitReader.readUnsigned(1);
|
2019-09-21 11:02:17 +00:00
|
|
|
pXWall->triggerTouch = bitReader.readUnsigned(1);
|
2020-10-13 18:21:47 +00:00
|
|
|
bitReader.readUnsigned(2);
|
2020-11-26 07:38:59 +00:00
|
|
|
pWall->xpan_ += bitReader.readUnsigned(8) / 256.f;
|
|
|
|
pWall->ypan_ += bitReader.readUnsigned(8) / 256.f;
|
2019-09-19 22:42:45 +00:00
|
|
|
pXWall->locked = bitReader.readUnsigned(1);
|
|
|
|
pXWall->dudeLockout = bitReader.readUnsigned(1);
|
2020-10-13 18:21:47 +00:00
|
|
|
bitReader.readUnsigned(4);
|
|
|
|
bitReader.readUnsigned(32);
|
2021-11-19 16:29:49 +00:00
|
|
|
pXWall->busy = IntToFixed(pXWall->state);
|
2019-10-07 19:29:52 +00:00
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
initspritelists();
|
2021-10-24 07:11:43 +00:00
|
|
|
leveltimer = mapHeader.numsprites;
|
2020-11-21 21:25:26 +00:00
|
|
|
for (int i = 0; i < mapHeader.numsprites; i++)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
RemoveSpriteStat(i);
|
2020-10-03 16:35:47 +00:00
|
|
|
spritetypedisk load;
|
2021-09-05 08:09:59 +00:00
|
|
|
auto actor = &bloodActors[i];
|
|
|
|
actor->Clear();
|
2021-11-19 19:50:02 +00:00
|
|
|
spritetype* pSprite = &actor->s();
|
2020-10-03 16:35:47 +00:00
|
|
|
fr.Read(&load, sizeof(spritetypedisk)); // load into an intermediate buffer so that spritetype is no longer bound by file formats.
|
2020-11-22 15:47:08 +00:00
|
|
|
if (encrypted) // What were these people thinking? :(
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2021-11-19 19:50:02 +00:00
|
|
|
dbCrypt((char*)&load, sizeof(spritetypedisk), (gMapRev * sizeof(spritetypedisk)) | 0x7474614d);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-08-03 17:09:57 +00:00
|
|
|
|
2020-10-02 20:14:01 +00:00
|
|
|
pSprite->x = LittleLong(load.x);
|
|
|
|
pSprite->y = LittleLong(load.y);
|
|
|
|
pSprite->z = LittleLong(load.z);
|
|
|
|
pSprite->cstat = LittleShort(load.cstat);
|
|
|
|
pSprite->picnum = LittleShort(load.picnum);
|
|
|
|
pSprite->sectnum = LittleShort(load.sectnum);
|
|
|
|
pSprite->statnum = LittleShort(load.statnum);
|
|
|
|
pSprite->ang = LittleShort(load.ang);
|
|
|
|
pSprite->owner = LittleShort(load.owner);
|
2021-09-05 09:45:36 +00:00
|
|
|
pSprite->xvel = LittleShort(load.index);
|
2020-10-02 20:14:01 +00:00
|
|
|
pSprite->yvel = LittleShort(load.yvel);
|
|
|
|
pSprite->inittype = LittleShort(load.inittype);
|
|
|
|
pSprite->type = LittleShort(load.type);
|
|
|
|
pSprite->flags = LittleShort(load.hitag);
|
|
|
|
pSprite->extra = LittleShort(load.extra);
|
2020-10-03 16:35:47 +00:00
|
|
|
pSprite->pal = load.pal;
|
|
|
|
pSprite->clipdist = load.clipdist;
|
|
|
|
pSprite->xrepeat = load.xrepeat;
|
|
|
|
pSprite->yrepeat = load.yrepeat;
|
|
|
|
pSprite->xoffset = load.xoffset;
|
|
|
|
pSprite->yoffset = load.yoffset;
|
|
|
|
pSprite->detail = load.detail;
|
2020-10-24 17:11:58 +00:00
|
|
|
pSprite->shade = load.shade;
|
2020-10-02 20:14:01 +00:00
|
|
|
pSprite->blend = 0;
|
2021-10-24 07:11:43 +00:00
|
|
|
pSprite->time = i;
|
2021-11-09 22:50:02 +00:00
|
|
|
ValidateSprite(*pSprite);
|
2020-08-03 17:09:57 +00:00
|
|
|
|
2021-09-05 07:59:10 +00:00
|
|
|
InsertSpriteSect(i, pSprite->sectnum);
|
|
|
|
InsertSpriteStat(i, pSprite->statnum);
|
2019-06-29 12:24:23 +00:00
|
|
|
Numsprites++;
|
2021-09-05 07:59:10 +00:00
|
|
|
if (pSprite->extra > 0)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
char pBuffer[nXSpriteSize];
|
2021-09-05 08:09:59 +00:00
|
|
|
actor->addX();
|
2021-11-19 19:50:02 +00:00
|
|
|
XSPRITE* pXSprite = &actor->x();
|
2019-09-19 22:42:45 +00:00
|
|
|
int nCount;
|
2020-11-22 15:47:08 +00:00
|
|
|
if (!encrypted)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
nCount = nXSpriteSize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-11-21 22:40:08 +00:00
|
|
|
nCount = byte_19AE44.numxsprites;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(nCount <= nXSpriteSize);
|
2020-07-25 16:48:26 +00:00
|
|
|
fr.Read(pBuffer, nCount);
|
2019-09-19 22:42:45 +00:00
|
|
|
BitReader bitReader(pBuffer, nCount);
|
2021-09-05 07:35:44 +00:00
|
|
|
/*pXSprite->reference =*/ bitReader.readSigned(14);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSprite->state = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->busy = bitReader.readUnsigned(17);
|
|
|
|
pXSprite->txID = bitReader.readUnsigned(10);
|
|
|
|
pXSprite->rxID = bitReader.readUnsigned(10);
|
|
|
|
pXSprite->command = bitReader.readUnsigned(8);
|
|
|
|
pXSprite->triggerOn = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->triggerOff = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->wave = bitReader.readUnsigned(2);
|
|
|
|
pXSprite->busyTime = bitReader.readUnsigned(12);
|
|
|
|
pXSprite->waitTime = bitReader.readUnsigned(12);
|
|
|
|
pXSprite->restState = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->Interrutable = bitReader.readUnsigned(1);
|
2021-05-03 22:22:35 +00:00
|
|
|
pXSprite->unused1 = bitReader.readUnsigned(2);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSprite->respawnPending = bitReader.readUnsigned(2);
|
2021-05-03 22:03:01 +00:00
|
|
|
pXSprite->unused2 = bitReader.readUnsigned(1);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSprite->lT = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->dropMsg = bitReader.readUnsigned(8);
|
|
|
|
pXSprite->Decoupled = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->triggerOnce = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->isTriggered = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->key = bitReader.readUnsigned(3);
|
|
|
|
pXSprite->Push = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->Vector = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->Impact = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->Pickup = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->Touch = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->Sight = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->Proximity = bitReader.readUnsigned(1);
|
2021-07-19 21:15:26 +00:00
|
|
|
pXSprite->unused3 = bitReader.readUnsigned(2);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSprite->lSkill = bitReader.readUnsigned(5);
|
|
|
|
pXSprite->lS = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->lB = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->lC = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->DudeLockout = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->data1 = bitReader.readSigned(16);
|
|
|
|
pXSprite->data2 = bitReader.readSigned(16);
|
|
|
|
pXSprite->data3 = bitReader.readSigned(16);
|
|
|
|
pXSprite->goalAng = bitReader.readUnsigned(11);
|
|
|
|
pXSprite->dodgeDir = bitReader.readSigned(2);
|
|
|
|
pXSprite->locked = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->medium = bitReader.readUnsigned(2);
|
|
|
|
pXSprite->respawn = bitReader.readUnsigned(2);
|
|
|
|
pXSprite->data4 = bitReader.readUnsigned(16);
|
2021-07-19 21:15:26 +00:00
|
|
|
pXSprite->unused4 = bitReader.readUnsigned(6);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSprite->lockMsg = bitReader.readUnsigned(8);
|
|
|
|
pXSprite->health = bitReader.readUnsigned(12);
|
|
|
|
pXSprite->dudeDeaf = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->dudeAmbush = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->dudeGuard = bitReader.readUnsigned(1);
|
|
|
|
pXSprite->dudeFlag4 = bitReader.readUnsigned(1);
|
2021-09-05 09:45:36 +00:00
|
|
|
/*pXSprite->target_i = */ bitReader.readSigned(16);
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSprite->targetX = bitReader.readSigned(32);
|
|
|
|
pXSprite->targetY = bitReader.readSigned(32);
|
|
|
|
pXSprite->targetZ = bitReader.readSigned(32);
|
|
|
|
pXSprite->burnTime = bitReader.readUnsigned(16);
|
|
|
|
pXSprite->burnSource = bitReader.readSigned(16);
|
|
|
|
pXSprite->height = bitReader.readUnsigned(16);
|
|
|
|
pXSprite->stateTimer = bitReader.readUnsigned(16);
|
|
|
|
pXSprite->aiState = NULL;
|
|
|
|
bitReader.skipBits(32);
|
2021-09-05 07:35:44 +00:00
|
|
|
pXSprite->busy = IntToFixed(pXSprite->state);
|
2020-11-22 15:47:08 +00:00
|
|
|
if (!encrypted) {
|
2021-09-05 07:35:44 +00:00
|
|
|
pXSprite->lT |= pXSprite->lB;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-10-07 19:29:52 +00:00
|
|
|
|
2021-11-19 19:50:02 +00:00
|
|
|
#ifdef NOONE_EXTENSIONS
|
2020-01-26 11:19:01 +00:00
|
|
|
// indicate if the map requires modern features to work properly
|
2019-10-07 19:29:52 +00:00
|
|
|
// for maps wich created in different editors (include vanilla MAPEDIT) or in PMAPEDIT version below than BETA13
|
2019-11-08 19:57:01 +00:00
|
|
|
if (!gModernMap && pXSprite->rxID == kChannelMapModernize && pXSprite->rxID == pXSprite->txID && pXSprite->command == kCmdModernFeaturesEnable)
|
2019-10-07 19:29:52 +00:00
|
|
|
gModernMap = true;
|
2021-11-19 19:50:02 +00:00
|
|
|
#endif
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
if ((sprite[i].cstat & 0x30) == 0x30)
|
|
|
|
{
|
|
|
|
sprite[i].cstat &= ~0x30;
|
|
|
|
}
|
|
|
|
}
|
2021-11-19 19:50:02 +00:00
|
|
|
unsigned int nCRC = fr.ReadUInt32();
|
2020-08-03 17:09:57 +00:00
|
|
|
|
2020-07-25 16:48:26 +00:00
|
|
|
fr.Seek(0, FileReader::SeekSet);
|
|
|
|
auto buffer = fr.Read();
|
2021-04-17 08:14:03 +00:00
|
|
|
uint8_t md4[16];
|
2021-03-07 08:39:16 +00:00
|
|
|
md4once(buffer.Data(), buffer.Size(), md4);
|
|
|
|
G_LoadMapHack(mapname, md4);
|
2020-09-13 11:01:44 +00:00
|
|
|
|
2021-11-19 19:50:02 +00:00
|
|
|
if (CalcCRC32(buffer.Data(), buffer.Size() - 4) != nCRC)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-10-11 18:57:20 +00:00
|
|
|
I_Error("%s: Map File does not match CRC", mapname.GetChars());
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-06-28 16:03:47 +00:00
|
|
|
if (pCRC)
|
|
|
|
*pCRC = nCRC;
|
2019-09-19 22:42:45 +00:00
|
|
|
PropagateMarkerReferences();
|
2020-11-22 15:47:08 +00:00
|
|
|
if (encrypted)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-11-22 15:47:08 +00:00
|
|
|
if (gMattId == 0x7474614d || gMattId == 0x4d617474)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-11-22 15:47:08 +00:00
|
|
|
drawtile2048 = 1;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2020-11-22 15:47:08 +00:00
|
|
|
else if (!gMattId)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-11-22 15:47:08 +00:00
|
|
|
drawtile2048 = 0;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-10-11 18:57:20 +00:00
|
|
|
I_Error("%s: Corrupted Map file", mapname.GetChars());
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-22 15:47:08 +00:00
|
|
|
else if (gMattId != 0)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2020-10-11 18:57:20 +00:00
|
|
|
I_Error("%s: Corrupted Map file", mapname.GetChars());
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((header.version & 0xff00) == 0x600)
|
|
|
|
{
|
2021-11-19 19:50:02 +00:00
|
|
|
switch (header.version & 0xff)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
for (int i = 0; i < numsectors; i++)
|
|
|
|
{
|
2021-11-19 19:50:02 +00:00
|
|
|
sectortype* pSector = §or[i];
|
2021-11-20 18:22:30 +00:00
|
|
|
if (pSector->hasX())
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2021-11-20 18:22:30 +00:00
|
|
|
XSECTOR* pXSector = &pSector->xs();
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->busyTimeB = pXSector->busyTimeA;
|
|
|
|
if (pXSector->busyTimeA > 0)
|
|
|
|
{
|
2019-10-25 20:53:41 +00:00
|
|
|
if (!pXSector->restState)
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2019-10-25 20:53:41 +00:00
|
|
|
pXSector->reTriggerA = 1;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pXSector->waitTimeB = pXSector->busyTimeA;
|
|
|
|
pXSector->waitTimeA = 0;
|
2019-10-25 20:53:41 +00:00
|
|
|
pXSector->reTriggerB = 1;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-14 11:05:24 +00:00
|
|
|
[[fallthrough]];
|
2019-09-19 22:42:45 +00:00
|
|
|
case 1:
|
|
|
|
for (int i = 0; i < numsectors; i++)
|
|
|
|
{
|
2021-11-19 19:50:02 +00:00
|
|
|
sectortype* pSector = §or[i];
|
2021-11-20 18:22:30 +00:00
|
|
|
if (pSector->hasX())
|
2019-09-19 22:42:45 +00:00
|
|
|
{
|
2021-11-20 18:22:30 +00:00
|
|
|
XSECTOR* pXSector = &pSector->xs();
|
2019-09-19 22:42:45 +00:00
|
|
|
pXSector->freq >>= 1;
|
|
|
|
}
|
|
|
|
}
|
2021-12-14 11:05:24 +00:00
|
|
|
[[fallthrough]];
|
2019-09-19 22:42:45 +00:00
|
|
|
case 2:
|
|
|
|
for (int i = 0; i < kMaxSprites; i++)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
break;
|
2021-11-19 19:50:02 +00:00
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
2019-06-28 16:03:47 +00:00
|
|
|
|
2021-03-19 19:40:44 +00:00
|
|
|
setWallSectors();
|
2021-05-02 22:04:36 +00:00
|
|
|
hw_BuildSections();
|
2021-05-03 15:48:35 +00:00
|
|
|
sectorGeometry.SetSize(numsections);
|
2021-11-20 22:42:01 +00:00
|
|
|
wallbackup = wall;
|
2021-11-20 22:20:43 +00:00
|
|
|
sectorbackup = sector;
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
2019-06-29 15:37:04 +00:00
|
|
|
|
2019-09-22 06:39:22 +00:00
|
|
|
|
|
|
|
END_BLD_NS
|
2020-10-11 18:57:20 +00:00
|
|
|
|
|
|
|
// only used by the backup loader.
|
2021-11-16 17:20:24 +00:00
|
|
|
void qloadboard(const char* filename, char flags, vec3_t* dapos, int16_t* daang, int* dacursectnum)
|
2020-10-11 18:57:20 +00:00
|
|
|
{
|
2021-11-16 17:20:24 +00:00
|
|
|
Blood::dbLoadMap(filename, &dapos->x, &dapos->y, &dapos->z, daang, dacursectnum, NULL);
|
2020-10-11 18:57:20 +00:00
|
|
|
Blood::dbInit(); // clean up immediately.
|
|
|
|
}
|
2021-11-20 16:35:41 +00:00
|
|
|
|