raze/source/games/blood/src/db.cpp

693 lines
26 KiB
C++
Raw Normal View History

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.
*/
//-------------------------------------------------------------------------
#include "ns.h" // Must come before everything else!
2019-09-19 22:42:45 +00:00
#include "build.h"
#include "common_game.h"
#include "zstring.h"
#include "m_crc32.h"
#include "md4.h"
2020-09-06 10:44:58 +00:00
#include "automap.h"
#include "raze_sound.h"
#include "gamefuncs.h"
#include "hw_sections.h"
2021-05-03 15:48:35 +00:00
#include "sectorgeometry.h"
2019-09-19 22:42:45 +00:00
#include "blood.h"
2019-09-19 22:42:45 +00:00
BEGIN_BLD_NS
int gSkyCount;
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
DBloodActor* InsertSprite(sectortype* pSector, int nStat)
2019-09-19 22:42:45 +00:00
{
auto act = static_cast<DBloodActor*>(::InsertActor(RUNTIME_CLASS(DBloodActor), pSector, nStat));
act->spr.cstat = CSTAT_SPRITE_YCENTER;
act->spr.clipdist = 32;
act->spr.xrepeat = act->spr.yrepeat = 64;
return act;
2019-09-19 22:42:45 +00:00
}
int DeleteSprite(DBloodActor* actor)
2019-09-19 22:42:45 +00:00
{
#ifdef NOONE_EXTENSIONS
2021-11-28 12:29:59 +00:00
for (auto& ctrl : gPlayerCtrl) if (ctrl.qavScene.initiator == actor) ctrl.qavScene.initiator = nullptr;
#endif
actor->Destroy();
2021-11-28 12:29:59 +00:00
return 0;
2019-09-19 22:42:45 +00:00
}
bool gModernMap = false;
int gVisibility;
2019-09-19 22:42:45 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void dbCrypt(char *pPtr, int nLength, int nKey)
2019-09-19 22:42:45 +00:00
{
for (int i = 0; i < nLength; i++)
{
pPtr[i] = pPtr[i] ^ nKey;
nKey++;
}
2019-09-19 22:42:45 +00:00
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2019-09-19 22:42:45 +00:00
unsigned int dbReadMapCRC(const char *pPath)
{
FString mapname = pPath;
DefaultExtension(mapname, ".map");
auto fr = fileSystem.OpenFileReader(mapname);
2019-09-30 17:08:35 +00:00
if (!fr.isOpen())
2019-09-19 22:42: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;
fr.Read(&header, 6);
2019-09-19 22:42:45 +00:00
if (memcmp(header.signature, "BLM\x1a", 4))
{
I_Error("%s: Map file corrupted.", mapname.GetChars());
2019-09-19 22:42:45 +00:00
}
int ver = LittleShort(header.version);
if ((ver & 0xff00) == 0x600)
2019-09-19 22:42:45 +00:00
{
}
else if ((ver & 0xff00) == 0x700)
2019-09-19 22:42:45 +00:00
{
}
else
{
I_Error("%s: Map file is wrong version.", mapname.GetChars());
2019-09-19 22:42:45 +00:00
}
fr.Seek(-4, FileReader::SeekEnd);
return fr.ReadInt32();
2019-09-19 22:42:45 +00:00
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void dbLoadMap(const char* pPath, int* pX, int* pY, int* pZ, short* pAngle, sectortype** ppSector, unsigned int* pCRC, BloodSpawnSpriteDef& sprites)
{
const int nXSectorSize = 60;
const int nXSpriteSize = 56;
const int nXWallSize = 24;
MAPHEADER2 xheader;
int gMapRev, gMattId;
int16_t tpskyoff[256];
2020-09-06 08:59:45 +00:00
ClearAutomap();
#ifdef NOONE_EXTENSIONS
gModernMap = false;
#endif
#ifdef NOONE_EXTENSIONS
for (auto& ctrl : gPlayerCtrl) ctrl.qavScene.initiator = nullptr;
#endif
FString mapname = pPath;
DefaultExtension(mapname, ".map");
auto fr = fileSystem.OpenFileReader(mapname);
2019-09-30 17:08:35 +00:00
if (!fr.isOpen())
{
I_Error("Error opening map file %s", mapname.GetChars());
2019-09-19 22:42:45 +00:00
}
MAPSIGNATURE header;
fr.Read(&header, 6);
2019-09-19 22:42:45 +00:00
if (memcmp(header.signature, "BLM\x1a", 4))
{
I_Error("%s: Map file corrupted", mapname.GetChars());
2019-09-19 22:42:45 +00:00
}
bool encrypted = 0;
if ((LittleShort(header.version) & 0xff00) == 0x700) {
encrypted = 1;
#ifdef NOONE_EXTENSIONS
// indicate if the map requires modern features to work properly
// 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;
#endif
}
else {
I_Error("%s: Map file is wrong version", mapname.GetChars());
2019-09-19 22:42:45 +00:00
}
2019-09-19 22:42:45 +00:00
MAPHEADER mapHeader;
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);
}
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;
gVisibility = g_visibility = mapHeader.visibility;
gMattId = mapHeader.mattid;
if (encrypted)
2019-09-19 22:42:45 +00:00
{
if (!(mapHeader.mattid == 0x7474614d || mapHeader.mattid == 0x4d617474 || !mapHeader.mattid))
2019-09-19 22:42:45 +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
{
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;
2021-12-21 09:51:41 +00:00
allocateMapArrays(mapHeader.numwalls, mapHeader.numsectors, mapHeader.numsprites);
#if 1 // bad, bad hack, just for making Polymost happy...
PolymostAllocFakeSector();
#endif
* ppSector = mapHeader.sect >= 0? &sector[mapHeader.sect] : nullptr;
if (encrypted)
2019-09-19 22:42:45 +00:00
{
fr.Read(&xheader, 128);
dbCrypt((char*)&xheader, 128, wall.Size());
xheader.numxsprites = LittleLong(xheader.numxsprites);
xheader.numxwalls = LittleLong(xheader.numxwalls);
xheader.numxsectors = LittleLong(xheader.numxsectors);
2019-09-19 22:42:45 +00:00
}
else
{
memset(&xheader, 0, 128);
2019-09-19 22:42:45 +00:00
}
gSkyCount = 1 << mapHeader.pskybits;
fr.Read(tpskyoff, gSkyCount * sizeof(tpskyoff[0]));
if (encrypted)
2019-09-19 22:42:45 +00:00
{
dbCrypt((char*)tpskyoff, gSkyCount * sizeof(tpskyoff[0]), gSkyCount * 2);
2019-09-19 22:42:45 +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++)
{
pSky->tileofs[i] = LittleShort(tpskyoff[i]);
2019-09-19 22:42:45 +00:00
}
2021-12-21 09:51:41 +00:00
for (unsigned i = 0; i < sector.Size(); i++)
2019-09-19 22:42:45 +00:00
{
sectortype* pSector = &sector[i];
sectortypedisk load;
fr.Read(&load, sizeof(sectortypedisk));
if (encrypted)
2019-09-19 22:42:45 +00:00
{
dbCrypt((char*)&load, sizeof(sectortypedisk), gMapRev * sizeof(sectortypedisk));
2019-09-19 22:42:45 +00:00
}
pSector->wallptr = LittleShort(load.wallptr);
pSector->wallnum = LittleShort(load.wallnum);
pSector->setceilingz(LittleLong(load.ceilingz), true);
pSector->setfloorz(LittleLong(load.floorz), true);
pSector->ceilingstat = ESectorFlags::FromInt(LittleShort(load.ceilingstat));
pSector->floorstat = ESectorFlags::FromInt(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;
pSector->ceilingxpan_ = load.ceilingxpanning;
pSector->ceilingypan_ = load.ceilingypanning;
pSector->floorshade = load.floorshade;
pSector->floorpal = load.floorpal;
pSector->floorxpan_ = load.floorxpanning;
pSector->floorypan_ = load.floorypanning;
pSector->visibility = load.visibility;
pSector->slopewallofs = load.fogpal;
pSector->dirty = EDirty::AllDirty;
pSector->exflags = 0;
2019-09-19 22:42:45 +00:00
pSector->fogpal = 0;
if (pSector->extra > 0)
2019-09-19 22:42:45 +00:00
{
char pBuffer[nXSectorSize];
pSector->allocX();
XSECTOR* pXSector = &pSector->xs();
2019-09-19 22:42:45 +00:00
int nCount;
if (!encrypted)
2019-09-19 22:42:45 +00:00
{
nCount = nXSectorSize;
}
else
{
nCount = xheader.numxsectors;
2019-09-19 22:42:45 +00:00
}
assert(nCount <= nXSectorSize);
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);
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);
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);
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);
pXSector->unused1 = bitReader.readUnsigned(1);
2019-09-19 22:42:45 +00:00
pXSector->decoupled = bitReader.readUnsigned(1);
pXSector->triggerOnce = bitReader.readUnsigned(1);
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);
/*pXSector->unused2 =*/ bitReader.readUnsigned(1);
2019-09-19 22:42:45 +00:00
pXSector->busyTimeB = bitReader.readUnsigned(12);
pXSector->waitTimeB = bitReader.readUnsigned(12);
pXSector->stopOn = bitReader.readUnsigned(1);
pXSector->stopOff = bitReader.readUnsigned(1);
2019-09-19 22:42:45 +00:00
pXSector->ceilpal = bitReader.readUnsigned(4);
pXSector->offCeilZ = bitReader.readSigned(32);
pXSector->onCeilZ = bitReader.readSigned(32);
pXSector->offFloorZ = bitReader.readSigned(32);
pXSector->onFloorZ = bitReader.readSigned(32);
/*pXSector->marker0 =*/ bitReader.readUnsigned(16);
/*pXSector->marker1 =*/ bitReader.readUnsigned(16);
2019-09-19 22:42:45 +00:00
pXSector->Crush = bitReader.readUnsigned(1);
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);
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);
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-09-19 22:42:45 +00:00
}
}
for (unsigned i = 0; i < wall.Size(); i++)
2019-09-19 22:42:45 +00:00
{
walltype* pWall = &wall[i];
walltypedisk load;
fr.Read(&load, sizeof(walltypedisk));
if (encrypted)
2019-09-19 22:42:45 +00:00
{
dbCrypt((char*)&load, sizeof(walltypedisk), (gMapRev * sizeof(sectortypedisk)) | 0x7474614d);
2019-09-19 22:42:45 +00:00
}
pWall->pos.X = LittleLong(load.x);
pWall->pos.Y = LittleLong(load.y);
pWall->point2 = LittleShort(load.point2);
pWall->nextwall = LittleShort(load.nextwall);
pWall->nextsector = LittleShort(load.nextsector);
2021-12-18 14:36:50 +00:00
pWall->cstat = EWallFlags::FromInt(LittleShort(load.cstat));
pWall->picnum = EWallFlags::FromInt(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;
pWall->yrepeat = load.yrepeat;
2020-11-26 07:38:59 +00:00
pWall->ypan_ = load.ypanning;
if (pWall->extra > 0)
2019-09-19 22:42:45 +00:00
{
char pBuffer[nXWallSize];
pWall->allocX();
XWALL* pXWall = &pWall->xw();
2019-09-19 22:42:45 +00:00
int nCount;
if (!encrypted)
2019-09-19 22:42:45 +00:00
{
nCount = nXWallSize;
}
else
{
nCount = xheader.numxwalls;
2019-09-19 22:42:45 +00:00
}
assert(nCount <= nXWallSize);
fr.Read(pBuffer, nCount);
2019-09-19 22:42:45 +00:00
BitReader bitReader(pBuffer, nCount);
/*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);
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);
pXWall->triggerTouch = bitReader.readUnsigned(1);
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);
bitReader.readUnsigned(4);
bitReader.readUnsigned(32);
2021-11-19 16:29:49 +00:00
pXWall->busy = IntToFixed(pXWall->state);
2019-09-19 22:42:45 +00:00
}
}
leveltimer = mapHeader.numsprites;
sprites.sprites.Resize(mapHeader.numsprites);
sprites.xspr.Resize(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
{
spritetypedisk load;
fr.Read(&load, sizeof(spritetypedisk));
if (encrypted) // What were these people thinking? :(
2019-09-19 22:42:45 +00:00
{
dbCrypt((char*)&load, sizeof(spritetypedisk), (gMapRev * sizeof(spritetypedisk)) | 0x7474614d);
2019-09-19 22:42:45 +00:00
}
auto pSprite = &sprites.sprites[i];
pSprite->clear();
pSprite->pos.X = LittleLong(load.x);
pSprite->pos.Y = LittleLong(load.y);
pSprite->pos.Z = LittleLong(load.z);
pSprite->cstat = ESpriteFlags::FromInt(LittleShort(load.cstat));
pSprite->picnum = LittleShort(load.picnum);
int secno = LittleShort(load.sectnum);
pSprite->statnum = LittleShort(load.statnum);
pSprite->ang = LittleShort(load.ang);
pSprite->owner = LittleShort(load.owner);
pSprite->xvel = LittleShort(load.index);
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);
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;
pSprite->shade = load.shade;
pSprite->blend = 0;
pSprite->time = i;
validateSprite(*pSprite, secno, i);
if (pSprite->extra > 0)
2019-09-19 22:42:45 +00:00
{
char pBuffer[nXSpriteSize];
XSPRITE* pXSprite = &sprites.xspr[i];
*pXSprite = {};
2019-09-19 22:42:45 +00:00
int nCount;
if (!encrypted)
2019-09-19 22:42:45 +00:00
{
nCount = nXSpriteSize;
}
else
{
nCount = xheader.numxsprites;
2019-09-19 22:42:45 +00:00
}
assert(nCount <= nXSpriteSize);
fr.Read(pBuffer, nCount);
2019-09-19 22:42:45 +00:00
BitReader bitReader(pBuffer, nCount);
/*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);
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);
Increase kMaxSuperXSprites from 128 to 512. Fix mirror (ROR) intialization so it won't crash if more than 1024 sectors used. Fix random item generator so items that inherits TX ID won't send command at respawn. Fix for things (400 - 433) that affected by modern physics so it won't return to vanilla physics after getting damage. Fix kTeleportTarget so teleported sprites won't stuck in floors or ceilings. Corpses won't gib as gargoyles anymore (gModernMap). kModernCondition: - remove bool comparison (condCmpb). - remove no extra comparison (condCmpne). - remove "else if" search at level start. - add global (game) conditions type. - add more conditions. - make error report a bit more informative. Add more options and damage effects for kModernSpriteDamager. Add more options for kModernMissileGen and allow to spawn projectile on TX ID sprites location. Add more options and vertical wind processing for kModernWindGen. Add more options and effects for kModernEffectGen. Allow kMarkerDudeSpawn to spawn enemies on TX ID sprites location (gModernMap). Allow kModernCustomDudeSpawn to spawn dude on TX ID sprites location. Add Screen and Aim trigger flags for sprites that can be triggered with Sight (gModernMap). Patrolling enemies: - add turn AI state. - add "return back" option for path markers. - add "turning while waiting" option for markers. - make enemies to hear some sounds assuming that player generates and hears it too. - add kModernStealthRegion type to affect current spot progress velocity. - replace AI's CanMove and aiChooseDirection to a better versions. - make flying enemies to not spin around the marker. - treat Phantasm as flying enemy! - allow to continue patrol when falling in water. Fix compile warnings Various minor fixes / cleanup.
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);
Increase kMaxSuperXSprites from 128 to 512. Fix mirror (ROR) intialization so it won't crash if more than 1024 sectors used. Fix random item generator so items that inherits TX ID won't send command at respawn. Fix for things (400 - 433) that affected by modern physics so it won't return to vanilla physics after getting damage. Fix kTeleportTarget so teleported sprites won't stuck in floors or ceilings. Corpses won't gib as gargoyles anymore (gModernMap). kModernCondition: - remove bool comparison (condCmpb). - remove no extra comparison (condCmpne). - remove "else if" search at level start. - add global (game) conditions type. - add more conditions. - make error report a bit more informative. Add more options and damage effects for kModernSpriteDamager. Add more options for kModernMissileGen and allow to spawn projectile on TX ID sprites location. Add more options and vertical wind processing for kModernWindGen. Add more options and effects for kModernEffectGen. Allow kMarkerDudeSpawn to spawn enemies on TX ID sprites location (gModernMap). Allow kModernCustomDudeSpawn to spawn dude on TX ID sprites location. Add Screen and Aim trigger flags for sprites that can be triggered with Sight (gModernMap). Patrolling enemies: - add turn AI state. - add "return back" option for path markers. - add "turning while waiting" option for markers. - make enemies to hear some sounds assuming that player generates and hears it too. - add kModernStealthRegion type to affect current spot progress velocity. - replace AI's CanMove and aiChooseDirection to a better versions. - make flying enemies to not spin around the marker. - treat Phantasm as flying enemy! - allow to continue patrol when falling in water. Fix compile warnings Various minor fixes / cleanup.
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);
/*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);
2021-11-28 12:35:35 +00:00
/*pXSprite->burnSource =*/ bitReader.readSigned(16);
2019-09-19 22:42:45 +00:00
pXSprite->height = bitReader.readUnsigned(16);
pXSprite->stateTimer = bitReader.readUnsigned(16);
pXSprite->aiState = NULL;
bitReader.skipBits(32);
pXSprite->busy = IntToFixed(pXSprite->state);
if (!encrypted) {
pXSprite->lT |= pXSprite->lB;
2019-09-19 22:42:45 +00:00
}
#ifdef NOONE_EXTENSIONS
// indicate if the map requires modern features to work properly
// for maps wich created in different editors (include vanilla MAPEDIT) or in PMAPEDIT version below than BETA13
if (!gModernMap && pXSprite->rxID == kChannelMapModernize && pXSprite->rxID == pXSprite->txID && pXSprite->command == kCmdModernFeaturesEnable)
gModernMap = true;
#endif
2019-09-19 22:42:45 +00:00
}
}
fixSectors();
unsigned int nCRC = fr.ReadUInt32();
fr.Seek(0, FileReader::SeekSet);
auto buffer = fr.Read();
uint8_t md4[16];
md4once(buffer.Data(), buffer.Size(), md4);
loadMapHack(mapname, md4, sprites);
if (CalcCRC32(buffer.Data(), buffer.Size() - 4) != nCRC)
2019-09-19 22:42:45 +00:00
{
I_Error("%s: Map File does not match CRC", mapname.GetChars());
2019-09-19 22:42:45 +00:00
}
if (pCRC)
*pCRC = nCRC;
if (encrypted)
2019-09-19 22:42:45 +00:00
{
if (!(gMattId == 0x7474614d || gMattId == 0x4d617474 || !gMattId))
2019-09-19 22:42:45 +00:00
{
I_Error("%s: Corrupted Map file", mapname.GetChars());
2019-09-19 22:42:45 +00:00
}
}
else if (gMattId != 0)
2019-09-19 22:42:45 +00:00
{
I_Error("%s: Corrupted Map file", mapname.GetChars());
2019-09-19 22:42:45 +00:00
}
if ((header.version & 0xff00) == 0x600)
{
switch (header.version & 0xff)
2019-09-19 22:42:45 +00:00
{
case 0:
for (auto& sect: sector)
2019-09-19 22:42:45 +00:00
{
sectortype* pSector = &sect;
if (pSector->hasX())
2019-09-19 22:42:45 +00:00
{
XSECTOR* pXSector = &pSector->xs();
2019-09-19 22:42:45 +00:00
pXSector->busyTimeB = pXSector->busyTimeA;
if (pXSector->busyTimeA > 0)
{
if (!pXSector->restState)
2019-09-19 22:42:45 +00:00
{
pXSector->reTriggerA = 1;
2019-09-19 22:42:45 +00:00
}
else
{
pXSector->waitTimeB = pXSector->busyTimeA;
pXSector->waitTimeA = 0;
pXSector->reTriggerB = 1;
2019-09-19 22:42:45 +00:00
}
}
}
}
[[fallthrough]];
2019-09-19 22:42:45 +00:00
case 1:
for (auto& sect: sector)
2019-09-19 22:42:45 +00:00
{
sectortype* pSector = &sect;
if (pSector->hasX())
2019-09-19 22:42:45 +00:00
{
XSECTOR* pXSector = &pSector->xs();
2019-09-19 22:42:45 +00:00
pXSector->freq >>= 1;
}
}
[[fallthrough]];
2019-09-19 22:42:45 +00:00
case 2:
break;
2019-09-19 22:42:45 +00:00
}
}
setWallSectors();
hw_CreateSections();
sectionGeometry.SetSize(sections.Size());
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
END_BLD_NS
//---------------------------------------------------------------------------
//
// only used by the backup loader.
//
//---------------------------------------------------------------------------
void qloadboard(const char* filename, char flags, vec3_t* dapos, int16_t* daang)
{
Blood::BloodSpawnSpriteDef sprites;
sectortype* sp;
2021-12-22 09:41:47 +00:00
Blood::dbLoadMap(filename, &dapos->X, &dapos->Y, &dapos->Z, daang, &sp, nullptr, sprites);
}
2021-11-20 16:35:41 +00:00