2016-05-03 17:55:04 +02:00
|
|
|
#include "dungeonman.h"
|
|
|
|
#include "common/file.h"
|
2016-05-07 20:53:35 +02:00
|
|
|
#include "common/memstream.h"
|
|
|
|
|
2016-05-03 17:55:04 +02:00
|
|
|
|
|
|
|
|
|
|
|
namespace DM {
|
2016-05-07 20:53:35 +02:00
|
|
|
// TODO: refactor direction into a class
|
|
|
|
int8 dirIntoStepCountEast[4] = {0 /* North */, 1 /* East */, 0 /* West */, -1 /* South */};
|
|
|
|
int8 dirIntoStepCountNorth[4] = {-1 /* North */, 0 /* East */, 1 /* West */, 0 /* South */};
|
|
|
|
|
|
|
|
void turnDirRight(direction &dir) { dir = (direction)((dir + 1) & 3); }
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
using namespace DM;
|
|
|
|
|
|
|
|
|
|
|
|
void DungeonMan::mapCoordsAfterRelMovement(direction dir, uint16 stepsForward, uint16 stepsRight, uint16 &posX, uint16 &posY) {
|
|
|
|
posX += dirIntoStepCountEast[dir] * stepsForward;
|
|
|
|
posY += dirIntoStepCountNorth[dir] * stepsForward;
|
|
|
|
turnDirRight(dir);
|
|
|
|
posX += dirIntoStepCountEast[dir] * stepsRight;
|
|
|
|
posY += dirIntoStepCountNorth[dir] * stepsRight;
|
|
|
|
}
|
|
|
|
|
|
|
|
DungeonMan::DungeonMan(DMEngine *dmEngine) : _vm(dmEngine), _rawDunFileData(NULL), _maps(NULL), _rawMapData(NULL) {}
|
2016-05-04 11:23:52 +02:00
|
|
|
|
|
|
|
DungeonMan::~DungeonMan() {
|
2016-05-07 20:53:35 +02:00
|
|
|
delete[] _rawDunFileData;
|
|
|
|
delete[] _maps;
|
2016-05-07 21:59:59 +02:00
|
|
|
delete[] _dunData.mapsFirstColumnIndex;
|
|
|
|
delete[] _dunData.columnsCumulativeSquareThingCount;
|
2016-05-07 20:53:35 +02:00
|
|
|
delete[] _dunData.squareFirstThings;
|
2016-05-07 21:59:59 +02:00
|
|
|
delete[] _dunData.textData;
|
|
|
|
delete[] _dunData.mapData;
|
2016-05-04 11:23:52 +02:00
|
|
|
}
|
|
|
|
|
2016-05-07 20:53:35 +02:00
|
|
|
void DungeonMan::decompressDungeonFile() {
|
2016-05-03 17:55:04 +02:00
|
|
|
Common::File f;
|
|
|
|
f.open("Dungeon.dat");
|
|
|
|
if (f.readUint16BE() == 0x8104) {
|
2016-05-07 20:53:35 +02:00
|
|
|
_rawDunFileDataSize = f.readUint32BE();
|
|
|
|
if (_rawDunFileData) delete[] _rawDunFileData;
|
|
|
|
_rawDunFileData = new byte[_rawDunFileDataSize];
|
2016-05-03 17:55:04 +02:00
|
|
|
f.readUint16BE();
|
|
|
|
byte common[4];
|
|
|
|
for (uint16 i = 0; i < 4; ++i)
|
|
|
|
common[i] = f.readByte();
|
|
|
|
byte lessCommon[16];
|
|
|
|
for (uint16 i = 0; i < 16; ++i)
|
|
|
|
lessCommon[i] = f.readByte();
|
|
|
|
|
|
|
|
// start unpacking
|
|
|
|
uint32 uncompIndex = 0;
|
|
|
|
uint8 bitsUsedInWord = 0;
|
|
|
|
uint16 wordBuff = f.readUint16BE();
|
|
|
|
uint8 bitsLeftInByte = 8;
|
|
|
|
byte byteBuff = f.readByte();
|
2016-05-07 20:53:35 +02:00
|
|
|
while (uncompIndex < _rawDunFileDataSize) {
|
2016-05-03 17:55:04 +02:00
|
|
|
while (bitsUsedInWord != 0) {
|
|
|
|
uint8 shiftVal;
|
|
|
|
if (f.eos()) {
|
|
|
|
shiftVal = bitsUsedInWord;
|
|
|
|
wordBuff <<= shiftVal;
|
|
|
|
} else {
|
|
|
|
shiftVal = MIN(bitsLeftInByte, bitsUsedInWord);
|
|
|
|
wordBuff <<= shiftVal;
|
|
|
|
wordBuff |= (byteBuff >> (8 - shiftVal));
|
|
|
|
byteBuff <<= shiftVal;
|
|
|
|
bitsLeftInByte -= shiftVal;
|
|
|
|
if (!bitsLeftInByte) {
|
|
|
|
byteBuff = f.readByte();
|
|
|
|
bitsLeftInByte = 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bitsUsedInWord -= shiftVal;
|
|
|
|
}
|
|
|
|
if (((wordBuff >> 15) & 1) == 0) {
|
2016-05-07 20:53:35 +02:00
|
|
|
_rawDunFileData[uncompIndex++] = common[(wordBuff >> 13) & 3];
|
2016-05-03 17:55:04 +02:00
|
|
|
bitsUsedInWord += 3;
|
|
|
|
} else if (((wordBuff >> 14) & 3) == 2) {
|
2016-05-07 20:53:35 +02:00
|
|
|
_rawDunFileData[uncompIndex++] = lessCommon[(wordBuff >> 10) & 15];
|
2016-05-03 17:55:04 +02:00
|
|
|
bitsUsedInWord += 6;
|
|
|
|
} else if (((wordBuff >> 14) & 3) == 3) {
|
2016-05-07 20:53:35 +02:00
|
|
|
_rawDunFileData[uncompIndex++] = (wordBuff >> 6) & 255;
|
2016-05-03 17:55:04 +02:00
|
|
|
bitsUsedInWord += 10;
|
|
|
|
}
|
|
|
|
}
|
2016-05-07 20:53:35 +02:00
|
|
|
} else {
|
|
|
|
// TODO: if the dungeon is uncompressed, read it here
|
2016-05-03 17:55:04 +02:00
|
|
|
}
|
|
|
|
f.close();
|
|
|
|
}
|
|
|
|
|
2016-05-07 20:53:35 +02:00
|
|
|
|
|
|
|
uint8 gAdditionalThingCounts[16] = {
|
|
|
|
0, /* Door */
|
|
|
|
0, /* Teleporter */
|
|
|
|
0, /* Text String */
|
|
|
|
0, /* Sensor */
|
|
|
|
75, /* Group */
|
|
|
|
100, /* Weapon */
|
|
|
|
120, /* Armour */
|
|
|
|
0, /* Scroll */
|
|
|
|
5, /* Potion */
|
|
|
|
0, /* Container */
|
|
|
|
140, /* Junk */
|
|
|
|
0, /* Unused */
|
|
|
|
0, /* Unused */
|
|
|
|
0, /* Unused */
|
|
|
|
60, /* Projectile */
|
|
|
|
50 /* Explosion */
|
|
|
|
}; // @ G0236_auc_Graphic559_AdditionalThingCounts
|
|
|
|
|
|
|
|
// TODO: refactor THINGS into classes
|
|
|
|
unsigned char gThingDataByteCount[16] = {
|
|
|
|
4, /* Door */
|
|
|
|
6, /* Teleporter */
|
|
|
|
4, /* Text String */
|
|
|
|
8, /* Sensor */
|
|
|
|
16, /* Group */
|
|
|
|
4, /* Weapon */
|
|
|
|
4, /* Armour */
|
|
|
|
4, /* Scroll */
|
|
|
|
4, /* Potion */
|
|
|
|
8, /* Container */
|
|
|
|
4, /* Junk */
|
|
|
|
0, /* Unused */
|
|
|
|
0, /* Unused */
|
|
|
|
0, /* Unused */
|
|
|
|
8, /* Projectile */
|
|
|
|
4 /* Explosion */
|
|
|
|
}; // @ G0235_auc_Graphic559_ThingDataByteCount
|
|
|
|
|
|
|
|
const Thing Thing::specThingNone(0, 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
void DungeonMan::loadDungeonFile() {
|
|
|
|
if (_messages.newGame)
|
|
|
|
decompressDungeonFile();
|
|
|
|
|
|
|
|
Common::MemoryReadStream dunDataStream(_rawDunFileData, _fileHeader.rawMapDataSize, DisposeAfterUse::NO);
|
|
|
|
|
|
|
|
// initialize _fileHeader
|
|
|
|
_fileHeader.dungeonId = _fileHeader.ornamentRandomSeed = dunDataStream.readUint16BE();
|
|
|
|
_fileHeader.rawMapDataSize = dunDataStream.readUint16BE();
|
|
|
|
_fileHeader.mapCount = dunDataStream.readByte();
|
|
|
|
dunDataStream.readByte(); // discard 1 byte
|
|
|
|
_fileHeader.textDataWordCount = dunDataStream.readUint16BE();
|
|
|
|
uint16 partyPosition = dunDataStream.readUint16BE();
|
|
|
|
_fileHeader.partyStartDir = (direction)((partyPosition >> 10) & 3);
|
|
|
|
_fileHeader.partyStartPosY = (partyPosition >> 5) & 0x1F;
|
|
|
|
_fileHeader.partyStartPosX = (partyPosition >> 0) & 0x1F;
|
|
|
|
_fileHeader.squareFirstThingCount = dunDataStream.readUint16BE();
|
|
|
|
for (uint16 i = 0; i < kThingTypeTotal; ++i)
|
|
|
|
_fileHeader.thingCounts[i] = dunDataStream.readUint16BE();
|
|
|
|
|
|
|
|
// init party position and mapindex
|
|
|
|
if (_messages.newGame) {
|
2016-05-07 21:59:59 +02:00
|
|
|
_currMap.partyDir = _fileHeader.partyStartDir;
|
|
|
|
_currMap.partyPosX = _fileHeader.partyStartPosX;
|
|
|
|
_currMap.partyPosY = _fileHeader.partyStartPosY;
|
|
|
|
_currMap.currPartyMapIndex = 0;
|
2016-05-07 20:53:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// load map data
|
|
|
|
if (_maps) delete[] _maps;
|
|
|
|
|
|
|
|
_maps = new Map[_fileHeader.mapCount];
|
|
|
|
for (uint16 i = 0; i < _fileHeader.mapCount; ++i) {
|
|
|
|
_maps[i].rawDunDataOffset = dunDataStream.readUint16BE();
|
|
|
|
dunDataStream.readUint32BE(); // discard 4 bytes
|
|
|
|
_maps[i].offsetMapX = dunDataStream.readByte();
|
|
|
|
_maps[i].offsetMapY = dunDataStream.readByte();
|
|
|
|
|
|
|
|
uint16 tmp = dunDataStream.readUint16BE();
|
|
|
|
_maps[i].height = tmp >> 11;
|
|
|
|
_maps[i].width = (tmp >> 6) & 0x1F;
|
|
|
|
_maps[i].level = tmp & 0x1F; // Only used in DMII
|
|
|
|
|
|
|
|
tmp = dunDataStream.readUint16BE();
|
|
|
|
_maps[i].randFloorOrnCount = tmp >> 12;
|
|
|
|
_maps[i].floorOrnCount = (tmp >> 8) & 0xF;
|
|
|
|
_maps[i].randWallOrnCount = (tmp >> 4) & 0xF;
|
|
|
|
_maps[i].wallOrnCount = tmp & 0xF;
|
|
|
|
|
|
|
|
tmp = dunDataStream.readUint16BE();
|
|
|
|
_maps[i].difficulty = tmp >> 12;
|
|
|
|
_maps[i].creatureTypeCount = (tmp >> 4) & 0xF;
|
|
|
|
_maps[i].doorOrnCount = tmp & 0xF;
|
|
|
|
|
|
|
|
tmp = dunDataStream.readUint16BE();
|
|
|
|
_maps[i].doorSet1 = (tmp >> 12) & 0xF;
|
|
|
|
_maps[i].doorSet0 = (tmp >> 8) & 0xF;
|
|
|
|
_maps[i].wallSet = (tmp >> 4) & 0xF;
|
|
|
|
_maps[i].floorSet = tmp & 0xF;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: ??? is this - begin
|
2016-05-07 21:59:59 +02:00
|
|
|
if (_dunData.mapsFirstColumnIndex) delete[] _dunData.mapsFirstColumnIndex;
|
2016-05-07 20:53:35 +02:00
|
|
|
|
2016-05-07 21:59:59 +02:00
|
|
|
_dunData.mapsFirstColumnIndex = new uint16[_fileHeader.mapCount];
|
2016-05-07 20:53:35 +02:00
|
|
|
uint16 columCount = 0;
|
|
|
|
for (uint16 i = 0; i < _fileHeader.mapCount; ++i) {
|
2016-05-07 21:59:59 +02:00
|
|
|
_dunData.mapsFirstColumnIndex[i] = columCount;
|
2016-05-07 20:53:35 +02:00
|
|
|
columCount += _maps[i].width + 1;
|
|
|
|
}
|
2016-05-07 21:59:59 +02:00
|
|
|
_dunData.columCount = columCount;
|
2016-05-07 20:53:35 +02:00
|
|
|
// TODO: ??? is this - end
|
|
|
|
|
|
|
|
if (_messages.newGame) // TODO: what purpose does this serve?
|
|
|
|
_fileHeader.squareFirstThingCount += 300;
|
|
|
|
|
|
|
|
// TODO: ??? is this - begin
|
2016-05-07 21:59:59 +02:00
|
|
|
if (_dunData.columnsCumulativeSquareThingCount)
|
|
|
|
delete[] _dunData.columnsCumulativeSquareThingCount;
|
|
|
|
_dunData.columnsCumulativeSquareThingCount = new uint16[columCount];
|
2016-05-07 20:53:35 +02:00
|
|
|
for (uint16 i = 0; i < columCount; ++i)
|
2016-05-07 21:59:59 +02:00
|
|
|
_dunData.columnsCumulativeSquareThingCount[i] = dunDataStream.readUint16BE();
|
2016-05-07 20:53:35 +02:00
|
|
|
// TODO: ??? is this - end
|
|
|
|
|
|
|
|
// TODO: ??? is this - begin
|
|
|
|
if (_dunData.squareFirstThings)
|
|
|
|
delete[] _dunData.squareFirstThings;
|
|
|
|
_dunData.squareFirstThings = new Thing[_fileHeader.squareFirstThingCount];
|
|
|
|
for (uint16 i = 0; i < _fileHeader.squareFirstThingCount; ++i) {
|
|
|
|
uint16 tmp = dunDataStream.readUint16BE();
|
|
|
|
_dunData.squareFirstThings[i].cell = tmp >> 14;
|
|
|
|
_dunData.squareFirstThings[i].type = (tmp >> 10) & 0xF;
|
|
|
|
_dunData.squareFirstThings[i].index = tmp & 0x1FF;
|
|
|
|
}
|
|
|
|
if (_messages.newGame)
|
|
|
|
for (uint16 i = 0; i < 300; ++i)
|
|
|
|
_dunData.squareFirstThings[i] = Thing::specThingNone;
|
|
|
|
|
|
|
|
// TODO: ??? is this - end
|
|
|
|
|
|
|
|
// load text data
|
2016-05-07 21:59:59 +02:00
|
|
|
if (_dunData.textData)
|
|
|
|
delete[] _dunData.textData;
|
|
|
|
_dunData.textData = new uint16[_fileHeader.textDataWordCount];
|
2016-05-07 20:53:35 +02:00
|
|
|
for (uint16 i = 0; i < _fileHeader.textDataWordCount; ++i)
|
2016-05-07 21:59:59 +02:00
|
|
|
_dunData.textData[i] = dunDataStream.readUint16BE();
|
2016-05-07 20:53:35 +02:00
|
|
|
|
|
|
|
// TODO: ??? what this
|
|
|
|
if (_messages.newGame)
|
|
|
|
_dunData.eventMaximumCount = 100;
|
|
|
|
|
|
|
|
// load 'Things'
|
|
|
|
// TODO: implement load things
|
|
|
|
// this is a temporary workaround to seek to raw map data
|
|
|
|
for (uint16 i = 0; i < kThingTypeTotal; ++i)
|
|
|
|
dunDataStream.skip(_fileHeader.thingCounts[i] * gThingDataByteCount[i]);
|
|
|
|
|
|
|
|
_rawMapData = _rawDunFileData + dunDataStream.pos();
|
|
|
|
|
2016-05-07 21:59:59 +02:00
|
|
|
if (_dunData.mapData) delete[] _dunData.mapData;
|
2016-05-07 20:53:35 +02:00
|
|
|
|
2016-05-07 21:59:59 +02:00
|
|
|
if (!_messages.restartGameRequest) {
|
2016-05-07 20:53:35 +02:00
|
|
|
uint8 mapCount = _fileHeader.mapCount;
|
2016-05-07 21:59:59 +02:00
|
|
|
_dunData.mapData = new byte**[_dunData.columCount + mapCount];
|
|
|
|
byte **colFirstSquares = (byte**)_dunData.mapData + mapCount;
|
2016-05-07 20:53:35 +02:00
|
|
|
for (uint8 i = 0; i < mapCount; ++i) {
|
2016-05-07 21:59:59 +02:00
|
|
|
_dunData.mapData[i] = colFirstSquares;
|
2016-05-07 20:53:35 +02:00
|
|
|
byte *square = _rawMapData + _maps[i].rawDunDataOffset;
|
|
|
|
*colFirstSquares++ = square;
|
|
|
|
for (uint16 w = 0; w <= _maps[i].width; ++w) {
|
|
|
|
square += _maps[w].height + 1;
|
|
|
|
*colFirstSquares++ = square;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-05-07 21:59:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void DungeonMan::setCurrentMap(uint16 mapIndex) {
|
|
|
|
if (_currMap.index == mapIndex)
|
|
|
|
return;
|
|
|
|
|
|
|
|
_currMap.index = mapIndex;
|
|
|
|
_currMap.data = _dunData.mapData[mapIndex];
|
|
|
|
_currMap.map = _maps + mapIndex;
|
|
|
|
_currMap.width = _maps[mapIndex].width + 1;
|
|
|
|
_currMap.height = _maps[mapIndex].height + 1;
|
|
|
|
_currMap.colCumulativeSquareFirstThingCount
|
|
|
|
= &_dunData.columnsCumulativeSquareThingCount[_dunData.mapsFirstColumnIndex[mapIndex]];
|
2016-05-03 17:55:04 +02:00
|
|
|
}
|