2016-05-03 17:55:04 +02:00
|
|
|
|
#include "dungeonman.h"
|
2016-05-15 15:53:00 +02:00
|
|
|
|
#include "gfx.h"
|
2016-05-03 17:55:04 +02:00
|
|
|
|
#include "common/file.h"
|
2016-05-07 20:53:35 +02:00
|
|
|
|
#include "common/memstream.h"
|
|
|
|
|
|
2016-05-03 17:55:04 +02:00
|
|
|
|
|
|
|
|
|
|
2016-05-07 20:53:35 +02:00
|
|
|
|
using namespace DM;
|
|
|
|
|
|
2016-05-22 00:32:53 +02:00
|
|
|
|
|
|
|
|
|
|
2016-05-15 15:53:00 +02:00
|
|
|
|
CreatureInfo gCreatureInfo[kCreatureTypeCount] = { // @ G0243_as_Graphic559_CreatureInfo
|
|
|
|
|
/* { CreatureAspectIndex, AttackSoundOrdinal, Attributes, GraphicInfo,
|
|
|
|
|
MovementTicks, AttackTicks, Defense, BaseHealth, Attack, PoisonAttack,
|
|
|
|
|
Dexterity, Ranges, Properties, Resistances, AnimationTicks, WoundProbabilities, AttackType } */
|
|
|
|
|
{0, 4, 0x0482, 0x623D, 8, 20, 55, 150, 150, 240, 55, 0x1153, 0x299B, 0x0876, 0x0254, 0xFD40, 4},
|
|
|
|
|
{1, 0, 0x0480, 0xA625, 15, 32, 20, 110, 80, 15, 20, 0x3132, 0x33A9, 0x0E42, 0x0384, 0xFC41, 3},
|
|
|
|
|
{2, 6, 0x0510, 0x6198, 3, 5, 50, 10, 10, 0, 110, 0x1376, 0x710A, 0x0235, 0x0222, 0xFD20, 0},
|
|
|
|
|
{3, 0, 0x04B4, 0xB225, 10, 21, 30, 40, 58, 0, 80, 0x320A, 0x96AA, 0x0B3C, 0x0113, 0xF910, 5},
|
|
|
|
|
{4, 1, 0x0701, 0xA3B8, 9, 8, 45, 101, 90, 0, 65, 0x1554, 0x58FF, 0x0A34, 0x0143, 0xFE93, 4},
|
|
|
|
|
{5, 0, 0x0581, 0x539D, 20, 18, 100, 60, 30, 0, 30, 0x1232, 0x4338, 0x0583, 0x0265, 0xFFD6, 3},
|
|
|
|
|
{6, 3, 0x070C, 0x0020, 120, 10, 5, 165, 5, 0, 5, 0x1111, 0x10F1, 0x0764, 0x02F2, 0xFC84, 6},
|
|
|
|
|
{7, 7, 0x0300, 0x0220, 185, 15, 170, 50, 40, 5, 10, 0x1463, 0x25C4, 0x06E3, 0x01F4, 0xFD93, 4}, /* Atari ST: AttackSoundOrdinal = 0 */
|
|
|
|
|
{8, 2, 0x1864, 0x5225, 11, 16, 15, 30, 55, 0, 80, 0x1423, 0x4664, 0x0FC8, 0x0116, 0xFB30, 6},
|
|
|
|
|
{9, 10, 0x0282, 0x71B8, 21, 14, 240, 120, 219, 0, 35, 0x1023, 0x3BFF, 0x0FF7, 0x04F3, 0xF920, 3}, /* Atari ST: AttackSoundOrdinal = 7 */
|
|
|
|
|
{10, 2, 0x1480, 0x11B8, 17, 12, 25, 33, 20, 0, 40, 0x1224, 0x5497, 0x0F15, 0x0483, 0xFB20, 3},
|
|
|
|
|
{11, 0, 0x18C6, 0x0225, 255, 8, 45, 80, 105, 0, 60, 0x1314, 0x55A5, 0x0FF9, 0x0114, 0xFD95, 1},
|
|
|
|
|
{12, 11, 0x1280, 0x6038, 7, 7, 22, 20, 22, 0, 80, 0x1013, 0x6596, 0x0F63, 0x0132, 0xFA30, 4}, /* Atari ST: AttackSoundOrdinal = 8 */
|
|
|
|
|
{13, 9, 0x14A2, 0xB23D, 5, 10, 42, 39, 90, 100, 88, 0x1343, 0x5734, 0x0638, 0x0112, 0xFA30, 4}, /* Atari ST: AttackSoundOrdinal = 0 */
|
|
|
|
|
{14, 0, 0x05B8, 0x1638, 10, 20, 47, 44, 75, 0, 90, 0x4335, 0xD952, 0x035B, 0x0664, 0xFD60, 5},
|
|
|
|
|
{15, 5, 0x0381, 0x523D, 18, 19, 72, 70, 45, 35, 35, 0x1AA1, 0x15AB, 0x0B93, 0x0253, 0xFFC5, 4},
|
|
|
|
|
{16, 10, 0x0680, 0xA038, 13, 8, 28, 20, 25, 0, 41, 0x1343, 0x2148, 0x0321, 0x0332, 0xFC30, 3}, /* Atari ST: AttackSoundOrdinal = 7 */
|
|
|
|
|
{17, 0, 0x04A0, 0xF23D, 1, 16, 180, 8, 28, 20, 150, 0x1432, 0x19FD, 0x0004, 0x0112, 0xF710, 4},
|
|
|
|
|
{18, 11, 0x0280, 0xA3BD, 14, 6, 140, 60, 105, 0, 70, 0x1005, 0x7AFF, 0x0FFA, 0x0143, 0xFA30, 4}, /* Atari ST: AttackSoundOrdinal = 8 */
|
|
|
|
|
{19, 0, 0x0060, 0xE23D, 5, 18, 15, 33, 61, 0, 65, 0x3258, 0xAC77, 0x0F56, 0x0117, 0xFC40, 5},
|
|
|
|
|
{20, 8, 0x10DE, 0x0225, 25, 25, 75, 144, 66, 0, 50, 0x1381, 0x7679, 0x0EA7, 0x0345, 0xFD93, 3}, /* Atari ST: AttackSoundOrdinal = 0 */
|
|
|
|
|
{21, 3, 0x0082, 0xA3BD, 7, 15, 33, 77, 130, 0, 60, 0x1592, 0x696A, 0x0859, 0x0224, 0xFC30, 4},
|
|
|
|
|
{22, 0, 0x1480, 0x53BD, 10, 14, 68, 100, 100, 0, 75, 0x4344, 0xBDF9, 0x0A5D, 0x0124, 0xF920, 3},
|
|
|
|
|
{23, 0, 0x38AA, 0x0038, 12, 22, 255, 180, 210, 0, 130, 0x6369, 0xFF37, 0x0FBF, 0x0564, 0xFB52, 5},
|
|
|
|
|
{24, 1, 0x068A, 0x97BD, 13, 28, 110, 255, 255, 0, 70, 0x3645, 0xBF7C, 0x06CD, 0x0445, 0xFC30, 4}, /* Atari ST Version 1.0 1987-12-08 1987-12-11: Ranges = 0x2645 */
|
|
|
|
|
{25, 0, 0x38AA, 0x0000, 12, 22, 255, 180, 210, 0, 130, 0x6369, 0xFF37, 0x0FBF, 0x0564, 0xFB52, 5},
|
|
|
|
|
{26, 0, 0x38AA, 0x0000, 12, 22, 255, 180, 210, 0, 130, 0x6369, 0xFF37, 0x0FBF, 0x0564, 0xFB52, 5}};
|
|
|
|
|
|
|
|
|
|
int16 DM::ordinalToIndex(int16 val) { return val - 1; }
|
|
|
|
|
int16 DM::indexToOrdinal(int16 val) { return val + 1; }
|
|
|
|
|
|
2016-05-07 20:53:35 +02:00
|
|
|
|
|
2016-05-13 00:54:01 +02:00
|
|
|
|
void DungeonMan::mapCoordsAfterRelMovement(direction dir, int16 stepsForward, int16 stepsRight, int16 &posX, int16 &posY) {
|
2016-05-07 20:53:35 +02:00
|
|
|
|
posX += dirIntoStepCountEast[dir] * stepsForward;
|
|
|
|
|
posY += dirIntoStepCountNorth[dir] * stepsForward;
|
|
|
|
|
turnDirRight(dir);
|
|
|
|
|
posX += dirIntoStepCountEast[dir] * stepsRight;
|
|
|
|
|
posY += dirIntoStepCountNorth[dir] * stepsRight;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-03 23:47:04 +02:00
|
|
|
|
DungeonMan::DungeonMan(DMEngine *dmEngine) : _vm(dmEngine), _rawDunFileData(NULL), _maps(NULL), _rawMapData(NULL) {
|
|
|
|
|
_dunData.columCount = 0;
|
|
|
|
|
_dunData.eventMaximumCount = 0;
|
|
|
|
|
|
|
|
|
|
_dunData.mapsFirstColumnIndex = nullptr;
|
|
|
|
|
_dunData.columnsCumulativeSquareThingCount = nullptr;
|
|
|
|
|
_dunData.squareFirstThings = nullptr;
|
|
|
|
|
_dunData.textData = nullptr;
|
|
|
|
|
_dunData.mapData = nullptr;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
|
_dunData.thingsData[i] = nullptr;
|
|
|
|
|
|
|
|
|
|
_currMap.partyDir = kDirNorth;
|
|
|
|
|
_currMap.partyPosX = 0;
|
|
|
|
|
_currMap.partyPosY = 0;
|
|
|
|
|
_currMap.currPartyMapIndex = 0;
|
|
|
|
|
_currMap.index = 0;
|
|
|
|
|
_currMap.width = 0;
|
|
|
|
|
_currMap.height = 0;
|
|
|
|
|
|
|
|
|
|
_currMap.data = nullptr;
|
|
|
|
|
_currMap.map = nullptr;
|
|
|
|
|
_currMap.colCumulativeSquareFirstThingCount = nullptr;
|
|
|
|
|
|
|
|
|
|
_messages.newGame = true;
|
|
|
|
|
_messages.restartGameRequest = false;
|
|
|
|
|
|
|
|
|
|
_rawDunFileDataSize = 0;
|
|
|
|
|
_rawDunFileData = nullptr;
|
|
|
|
|
|
|
|
|
|
_fileHeader.dungeonId = 0;
|
|
|
|
|
_fileHeader.ornamentRandomSeed = 0;
|
|
|
|
|
_fileHeader.rawMapDataSize = 0;
|
|
|
|
|
_fileHeader.mapCount = 0;
|
|
|
|
|
_fileHeader.textDataWordCount = 0;
|
|
|
|
|
_fileHeader.partyStartDir = kDirNorth;
|
|
|
|
|
_fileHeader.partyStartPosX = 0;
|
|
|
|
|
_fileHeader.partyStartPosY = 0;
|
|
|
|
|
_fileHeader.squareFirstThingCount = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
|
_fileHeader.thingCounts[i] = 0;
|
|
|
|
|
|
|
|
|
|
_maps = nullptr;
|
|
|
|
|
_rawMapData = nullptr;
|
|
|
|
|
|
|
|
|
|
_currMapInscriptionWallOrnIndex = 0;
|
|
|
|
|
_isFacingAlcove = false;
|
|
|
|
|
_isFacingViAltar = false;
|
|
|
|
|
_isFacingFountain = false;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
|
for (int j = 0; j < 6; j++)
|
|
|
|
|
_dungeonViewClickableBoxes[j][i] = 0;
|
|
|
|
|
}
|
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-15 15:53:00 +02:00
|
|
|
|
for (uint16 i = 0; i < 16; ++i) {
|
|
|
|
|
if (_dunData.thingsData[i])
|
|
|
|
|
delete[] _dunData.thingsData[i][0];
|
|
|
|
|
delete[] _dunData.thingsData[i];
|
|
|
|
|
}
|
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();
|
2016-05-17 22:56:14 +02:00
|
|
|
|
delete[] _rawDunFileData;
|
2016-05-07 20:53:35 +02:00
|
|
|
|
_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
|
|
|
|
|
|
2016-05-15 15:53:00 +02:00
|
|
|
|
// this is the number of uint16s the data has to be stored, not the lenght of the data in dungeon.dat!
|
|
|
|
|
unsigned char gThingDataWordCount[16] = {
|
|
|
|
|
2, /* Door */
|
|
|
|
|
3, /* Teleporter */
|
|
|
|
|
2, /* Text String */
|
|
|
|
|
4, /* Sensor */
|
|
|
|
|
9, /* Group */
|
|
|
|
|
2, /* Weapon */
|
|
|
|
|
2, /* Armour */
|
|
|
|
|
2, /* Scroll */
|
|
|
|
|
2, /* Potion */
|
|
|
|
|
4, /* Container */
|
|
|
|
|
2, /* Junk */
|
2016-05-07 20:53:35 +02:00
|
|
|
|
0, /* Unused */
|
|
|
|
|
0, /* Unused */
|
|
|
|
|
0, /* Unused */
|
2016-05-15 15:53:00 +02:00
|
|
|
|
5, /* Projectile */
|
|
|
|
|
2 /* Explosion */
|
2016-05-07 20:53:35 +02:00
|
|
|
|
}; // @ G0235_auc_Graphic559_ThingDataByteCount
|
|
|
|
|
|
2016-05-15 15:53:00 +02:00
|
|
|
|
const Thing Thing::thingNone(0);
|
|
|
|
|
const Thing Thing::thingEndOfList(0xFFFE);
|
2016-05-07 20:53:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
2016-05-17 22:56:14 +02:00
|
|
|
|
delete[] _maps;
|
2016-05-07 20:53:35 +02:00
|
|
|
|
_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;
|
2016-05-15 15:53:00 +02:00
|
|
|
|
_maps[i].wallSet = (WallSet)((tmp >> 4) & 0xF);
|
|
|
|
|
_maps[i].floorSet = (FloorSet)(tmp & 0xF);
|
2016-05-07 20:53:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: ??? is this - begin
|
2016-05-17 22:56:14 +02:00
|
|
|
|
delete[] _dunData.mapsFirstColumnIndex;
|
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
|
|
|
|
|
|
2016-05-16 13:37:52 +02:00
|
|
|
|
|
|
|
|
|
uint32 actualSquareFirstThingCount = _fileHeader.squareFirstThingCount;
|
2016-05-07 20:53:35 +02:00
|
|
|
|
if (_messages.newGame) // TODO: what purpose does this serve?
|
|
|
|
|
_fileHeader.squareFirstThingCount += 300;
|
|
|
|
|
|
|
|
|
|
// TODO: ??? is this - begin
|
2016-05-17 22:56:14 +02:00
|
|
|
|
delete[] _dunData.columnsCumulativeSquareThingCount;
|
2016-05-07 21:59:59 +02:00
|
|
|
|
_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
|
2016-05-17 22:56:14 +02:00
|
|
|
|
delete[] _dunData.squareFirstThings;
|
2016-05-07 20:53:35 +02:00
|
|
|
|
_dunData.squareFirstThings = new Thing[_fileHeader.squareFirstThingCount];
|
2016-05-16 13:37:52 +02:00
|
|
|
|
for (uint16 i = 0; i < actualSquareFirstThingCount; ++i)
|
2016-05-12 23:19:36 +02:00
|
|
|
|
_dunData.squareFirstThings[i].set(dunDataStream.readUint16BE());
|
2016-05-07 20:53:35 +02:00
|
|
|
|
if (_messages.newGame)
|
|
|
|
|
for (uint16 i = 0; i < 300; ++i)
|
2016-05-16 13:37:52 +02:00
|
|
|
|
_dunData.squareFirstThings[actualSquareFirstThingCount + i] = Thing::thingNone;
|
2016-05-07 20:53:35 +02:00
|
|
|
|
|
|
|
|
|
// TODO: ??? is this - end
|
|
|
|
|
|
|
|
|
|
// load text data
|
2016-05-17 22:56:14 +02:00
|
|
|
|
delete[] _dunData.textData;
|
2016-05-07 21:59:59 +02:00
|
|
|
|
_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;
|
|
|
|
|
|
|
|
|
|
|
2016-05-15 15:53:00 +02:00
|
|
|
|
// load things
|
|
|
|
|
for (uint16 thingType = kDoorThingType; thingType < kThingTypeTotal; ++thingType) {
|
|
|
|
|
uint16 thingCount = _fileHeader.thingCounts[thingType];
|
|
|
|
|
if (_messages.newGame) {
|
2016-05-16 13:37:52 +02:00
|
|
|
|
_fileHeader.thingCounts[thingType] = MIN((thingType == kExplosionThingType) ? 768 : 1024, thingCount + gAdditionalThingCounts[thingType]);
|
2016-05-15 15:53:00 +02:00
|
|
|
|
}
|
|
|
|
|
uint16 thingStoreWordCount = gThingDataWordCount[thingType];
|
2016-05-16 13:37:52 +02:00
|
|
|
|
|
2016-05-17 23:09:56 +02:00
|
|
|
|
if (thingStoreWordCount == 0)
|
|
|
|
|
continue;
|
2016-05-15 15:53:00 +02:00
|
|
|
|
|
|
|
|
|
if (_dunData.thingsData[thingType]) {
|
|
|
|
|
delete[] _dunData.thingsData[thingType][0];
|
|
|
|
|
delete[] _dunData.thingsData[thingType];
|
|
|
|
|
}
|
2016-05-16 13:37:52 +02:00
|
|
|
|
_dunData.thingsData[thingType] = new uint16*[_fileHeader.thingCounts[thingType]];
|
|
|
|
|
_dunData.thingsData[thingType][0] = new uint16[_fileHeader.thingCounts[thingType] * thingStoreWordCount];
|
|
|
|
|
for (uint16 i = 0; i < _fileHeader.thingCounts[thingType]; ++i)
|
2016-05-15 15:53:00 +02:00
|
|
|
|
_dunData.thingsData[thingType][i] = _dunData.thingsData[thingType][0] + i * thingStoreWordCount;
|
|
|
|
|
|
|
|
|
|
if (thingType == kGroupThingType) {
|
|
|
|
|
for (uint16 i = 0; i < thingCount; ++i)
|
|
|
|
|
for (uint16 j = 0; j < thingStoreWordCount; ++j) {
|
|
|
|
|
if (j == 2 || j == 3)
|
|
|
|
|
_dunData.thingsData[thingType][i][j] = dunDataStream.readByte();
|
|
|
|
|
else
|
|
|
|
|
_dunData.thingsData[thingType][i][j] = dunDataStream.readUint16BE();
|
|
|
|
|
}
|
|
|
|
|
} else if (thingType == kProjectileThingType) {
|
|
|
|
|
for (uint16 i = 0; i < thingCount; ++i) {
|
|
|
|
|
_dunData.thingsData[thingType][i][0] = dunDataStream.readUint16BE();
|
|
|
|
|
_dunData.thingsData[thingType][i][1] = dunDataStream.readUint16BE();
|
|
|
|
|
_dunData.thingsData[thingType][i][2] = dunDataStream.readByte();
|
|
|
|
|
_dunData.thingsData[thingType][i][3] = dunDataStream.readByte();
|
|
|
|
|
_dunData.thingsData[thingType][i][4] = dunDataStream.readUint16BE();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for (uint16 i = 0; i < thingCount; ++i)
|
|
|
|
|
for (uint16 j = 0; j < thingStoreWordCount; ++j)
|
|
|
|
|
_dunData.thingsData[thingType][i][j] = dunDataStream.readUint16BE();
|
|
|
|
|
}
|
2016-05-16 13:37:52 +02:00
|
|
|
|
|
|
|
|
|
if (_messages.newGame) {
|
|
|
|
|
if ((thingType == kGroupThingType) || thingType >= kProjectileThingType)
|
|
|
|
|
_dunData.eventMaximumCount += _fileHeader.thingCounts[thingType];
|
|
|
|
|
for (uint16 i = 0; i < gAdditionalThingCounts[thingType]; ++i) {
|
|
|
|
|
_dunData.thingsData[thingType][thingCount + i][0] = Thing::thingNone.toUint16();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-15 15:53:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// load map data
|
2016-05-16 13:37:52 +02:00
|
|
|
|
if (!_messages.restartGameRequest)
|
|
|
|
|
_rawMapData = _rawDunFileData + dunDataStream.pos();
|
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-17 22:56:14 +02:00
|
|
|
|
delete[] _dunData.mapData;
|
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;
|
2016-05-16 13:37:52 +02:00
|
|
|
|
for (uint16 w = 1; w <= _maps[i].width; ++w) {
|
2016-05-17 22:14:34 +02:00
|
|
|
|
square += _maps[i].height + 1;
|
2016-05-07 20:53:35 +02:00
|
|
|
|
*colFirstSquares++ = square;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-05-07 21:59:59 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DungeonMan::setCurrentMap(uint16 mapIndex) {
|
|
|
|
|
_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-07 22:48:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-05-15 15:53:00 +02:00
|
|
|
|
void DungeonMan::setCurrentMapAndPartyMap(uint16 mapIndex) {
|
|
|
|
|
setCurrentMap(mapIndex);
|
|
|
|
|
|
|
|
|
|
byte *metaMapData = _currMap.data[_currMap.width - 1] + _currMap.height;
|
|
|
|
|
_vm->_displayMan->_currMapAllowedCreatureTypes = metaMapData;
|
|
|
|
|
|
|
|
|
|
metaMapData += _currMap.map->creatureTypeCount;
|
|
|
|
|
memcpy(_vm->_displayMan->_currMapWallOrnIndices, metaMapData, _currMap.map->wallOrnCount);
|
|
|
|
|
|
|
|
|
|
metaMapData += _currMap.map->wallOrnCount;
|
|
|
|
|
memcpy(_vm->_displayMan->_currMapFloorOrnIndices, metaMapData, _currMap.map->floorOrnCount);
|
|
|
|
|
|
|
|
|
|
metaMapData += _currMap.map->wallOrnCount;
|
|
|
|
|
memcpy(_vm->_displayMan->_currMapDoorOrnIndices, metaMapData, _currMap.map->doorOrnCount);
|
|
|
|
|
|
|
|
|
|
_currMapInscriptionWallOrnIndex = _currMap.map->wallOrnCount;
|
|
|
|
|
_vm->_displayMan->_currMapWallOrnIndices[_currMapInscriptionWallOrnIndex] = kWallOrnInscription;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-13 16:13:19 +02:00
|
|
|
|
|
|
|
|
|
Square DungeonMan::getSquare(int16 mapX, int16 mapY) {
|
2016-05-07 22:48:19 +02:00
|
|
|
|
bool isInXBounds = (mapX >= 0) && (mapX < _currMap.width);
|
|
|
|
|
bool isInYBounds = (mapY >= 0) && (mapY < _currMap.height);
|
|
|
|
|
|
|
|
|
|
if (isInXBounds && isInYBounds)
|
|
|
|
|
return _currMap.data[mapX][mapY];
|
2016-05-13 00:54:01 +02:00
|
|
|
|
|
2016-05-13 16:13:19 +02:00
|
|
|
|
|
|
|
|
|
Square tmpSquare;
|
2016-05-13 00:54:01 +02:00
|
|
|
|
if (isInYBounds) {
|
2016-05-15 15:53:00 +02:00
|
|
|
|
tmpSquare.set(_currMap.data[0][mapY]);
|
2016-05-13 16:13:19 +02:00
|
|
|
|
if (mapX == -1 && (tmpSquare.getType() == kCorridorElemType || tmpSquare.getType() == kPitElemType))
|
|
|
|
|
return Square(kWallElemType).set(kWallEastRandOrnAllowed);
|
2016-05-13 00:54:01 +02:00
|
|
|
|
|
2016-05-13 16:13:19 +02:00
|
|
|
|
tmpSquare.set(_currMap.data[_currMap.width - 1][mapY]);
|
|
|
|
|
if (mapX == _currMap.width && (tmpSquare.getType() == kCorridorElemType || tmpSquare.getType() == kPitElemType))
|
|
|
|
|
return Square(kWallElemType).set(kWallWestRandOrnAllowed);
|
2016-05-13 00:54:01 +02:00
|
|
|
|
} else if (isInXBounds) {
|
2016-05-13 16:13:19 +02:00
|
|
|
|
tmpSquare.set(_currMap.data[mapX][0]);
|
|
|
|
|
if (mapY == -1 && (tmpSquare.getType() == kCorridorElemType || tmpSquare.getType() == kPitElemType))
|
|
|
|
|
return Square(kWallElemType).set(kWallSouthRandOrnAllowed);
|
2016-05-13 00:54:01 +02:00
|
|
|
|
|
2016-05-13 16:13:19 +02:00
|
|
|
|
tmpSquare.set(_currMap.data[mapX][_currMap.height - 1]);
|
|
|
|
|
if (mapY == _currMap.height && (tmpSquare.getType() == kCorridorElemType || tmpSquare.getType() == kPitElemType))
|
2016-05-13 00:54:01 +02:00
|
|
|
|
return (kWallElemType << 5) | kWallNorthRandOrnAllowed;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-13 16:13:19 +02:00
|
|
|
|
return Square(kWallElemType);
|
2016-05-07 22:48:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-05-13 16:13:19 +02:00
|
|
|
|
Square DungeonMan::getRelSquare(direction dir, int16 stepsForward, int16 stepsRight, int16 posX, int16 posY) {
|
2016-05-07 22:48:19 +02:00
|
|
|
|
mapCoordsAfterRelMovement(dir, stepsForward, stepsForward, posX, posY);
|
|
|
|
|
return getSquare(posX, posY);
|
2016-05-13 16:13:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-05-15 15:53:00 +02:00
|
|
|
|
int16 DungeonMan::getSquareFirstThingIndex(int16 mapX, int16 mapY) {
|
|
|
|
|
if (mapX < 0 || mapX >= _currMap.width || mapY < 0 || mapY >= _currMap.height || !Square(_currMap.data[mapX][mapY]).get(kThingListPresent))
|
|
|
|
|
return -1;
|
|
|
|
|
|
2016-05-15 18:59:55 +02:00
|
|
|
|
int16 y = 0;
|
2016-05-15 15:53:00 +02:00
|
|
|
|
uint16 index = _currMap.colCumulativeSquareFirstThingCount[mapX];
|
|
|
|
|
byte* square = _currMap.data[mapX];
|
|
|
|
|
while (y++ != mapY)
|
|
|
|
|
if (Square(*square++).get(kThingListPresent))
|
|
|
|
|
index++;
|
|
|
|
|
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Thing DungeonMan::getSquareFirstThing(int16 mapX, int16 mapY) {
|
|
|
|
|
int16 index = getSquareFirstThingIndex(mapX, mapY);
|
|
|
|
|
if (index == -1)
|
|
|
|
|
return Thing::thingEndOfList;
|
|
|
|
|
return _dunData.squareFirstThings[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-05-21 12:55:37 +02:00
|
|
|
|
// TODO: get rid of the GOTOs
|
|
|
|
|
void DungeonMan::setSquareAspect(uint16 *aspectArray, direction dir, int16 mapX, int16 mapY) { // complete, except where marked
|
|
|
|
|
_vm->_displayMan->_championPortraitOrdinal = 0; // BUG0_75, possible fix
|
|
|
|
|
|
2016-06-14 16:40:45 +02:00
|
|
|
|
for (uint16 i = 0; i < 5; ++i)
|
|
|
|
|
aspectArray[i] = 0;
|
|
|
|
|
|
2016-05-15 15:53:00 +02:00
|
|
|
|
Thing thing = getSquareFirstThing(mapX, mapY);
|
|
|
|
|
Square square = getSquare(mapX, mapY);
|
|
|
|
|
|
|
|
|
|
aspectArray[kElemAspect] = square.getType();
|
2016-06-04 10:11:25 +02:00
|
|
|
|
|
|
|
|
|
bool leftOrnAllowed = false;
|
|
|
|
|
bool rightOrnAllowed = false;
|
|
|
|
|
bool frontOrnAllowed = false;
|
|
|
|
|
bool squareIsFakeWall = false;
|
|
|
|
|
bool footPrintsAllowed = false;
|
2016-05-15 15:53:00 +02:00
|
|
|
|
switch (square.getType()) {
|
|
|
|
|
case kWallElemType:
|
|
|
|
|
switch (dir) {
|
|
|
|
|
case kDirNorth:
|
|
|
|
|
leftOrnAllowed = square.get(kWallEastRandOrnAllowed);
|
|
|
|
|
frontOrnAllowed = square.get(kWallSouthRandOrnAllowed);
|
|
|
|
|
rightOrnAllowed = square.get(kWallWestRandOrnAllowed);
|
|
|
|
|
break;
|
|
|
|
|
case kDirEast:
|
|
|
|
|
leftOrnAllowed = square.get(kWallSouthRandOrnAllowed);
|
|
|
|
|
frontOrnAllowed = square.get(kWallWestRandOrnAllowed);
|
|
|
|
|
rightOrnAllowed = square.get(kWallNorthRandOrnAllowed);
|
|
|
|
|
break;
|
|
|
|
|
case kDirSouth:
|
|
|
|
|
leftOrnAllowed = square.get(kWallWestRandOrnAllowed);
|
|
|
|
|
frontOrnAllowed = square.get(kWallNorthRandOrnAllowed);
|
|
|
|
|
rightOrnAllowed = square.get(kWallEastRandOrnAllowed);
|
|
|
|
|
break;
|
|
|
|
|
case kDirWest:
|
|
|
|
|
leftOrnAllowed = square.get(kWallNorthRandOrnAllowed);
|
|
|
|
|
frontOrnAllowed = square.get(kWallEastRandOrnAllowed);
|
|
|
|
|
rightOrnAllowed = square.get(kWallSouthRandOrnAllowed);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-21 12:55:37 +02:00
|
|
|
|
T0172010_ClosedFakeWall:
|
2016-05-15 15:53:00 +02:00
|
|
|
|
setSquareAspectOrnOrdinals(aspectArray, leftOrnAllowed, frontOrnAllowed, rightOrnAllowed, dir, mapX, mapY, squareIsFakeWall);
|
|
|
|
|
|
|
|
|
|
while ((thing != Thing::thingEndOfList) && (thing.getType() <= kSensorThingType)) {
|
|
|
|
|
int16 sideIndex = (thing.getCell() - dir) & 3;
|
|
|
|
|
if (sideIndex) {
|
|
|
|
|
if (thing.getType() == kTextstringType) {
|
|
|
|
|
if (TextString(getThingData(thing)).isVisible()) {
|
|
|
|
|
aspectArray[sideIndex + 1] = _currMapInscriptionWallOrnIndex + 1;
|
2016-05-21 12:55:37 +02:00
|
|
|
|
_vm->_displayMan->_inscriptionThing = thing; // BUG0_76
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Sensor sensor(getThingData(thing));
|
|
|
|
|
aspectArray[sideIndex + 1] = sensor.getOrnOrdinal();
|
|
|
|
|
if (sensor.getType() == kSensorWallChampionPortrait) {
|
|
|
|
|
_vm->_displayMan->_championPortraitOrdinal = indexToOrdinal(sensor.getData());
|
2016-05-15 15:53:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
thing = getNextThing(thing);
|
|
|
|
|
}
|
|
|
|
|
if (squareIsFakeWall && (_currMap.partyPosX != mapX) && (_currMap.partyPosY != mapY)) {
|
|
|
|
|
aspectArray[kFirstGroupOrObjectAspect] = Thing::thingEndOfList.toUint16();
|
2016-05-21 12:55:37 +02:00
|
|
|
|
return;
|
2016-05-15 15:53:00 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2016-05-21 12:55:37 +02:00
|
|
|
|
case kPitElemType:
|
2016-06-14 16:40:45 +02:00
|
|
|
|
if (square.get(kPitOpen)) {
|
2016-05-21 12:55:37 +02:00
|
|
|
|
aspectArray[kPitInvisibleAspect] = square.get(kPitInvisible);
|
2016-06-14 16:40:45 +02:00
|
|
|
|
footPrintsAllowed = square.toByte() & 1;
|
|
|
|
|
} else {
|
2016-05-21 12:55:37 +02:00
|
|
|
|
aspectArray[kElemAspect] = kCorridorElemType;
|
2016-06-14 16:40:45 +02:00
|
|
|
|
footPrintsAllowed = true;
|
|
|
|
|
}
|
2016-05-21 12:55:37 +02:00
|
|
|
|
goto T0172030_Pit;
|
|
|
|
|
case kFakeWallElemType:
|
|
|
|
|
if (!square.get(kFakeWallOpen)) {
|
|
|
|
|
aspectArray[kElemAspect] = kWallElemType;
|
|
|
|
|
leftOrnAllowed = rightOrnAllowed = frontOrnAllowed = square.get(kFakeWallRandOrnOrFootPAllowed);
|
|
|
|
|
squareIsFakeWall = true;
|
|
|
|
|
goto T0172010_ClosedFakeWall;
|
|
|
|
|
}
|
|
|
|
|
aspectArray[kWallElemType] = kCorridorElemType;
|
|
|
|
|
footPrintsAllowed = square.get(kFakeWallRandOrnOrFootPAllowed);
|
2016-06-14 16:40:45 +02:00
|
|
|
|
square = footPrintsAllowed ? 8 : 0;
|
2016-05-21 12:55:37 +02:00
|
|
|
|
// intentional fallthrough
|
|
|
|
|
case kCorridorElemType:
|
|
|
|
|
aspectArray[kFloorOrnOrdAspect] = getRandomOrnOrdinal(square.get(kCorridorRandOrnAllowed), _currMap.map->randFloorOrnCount, mapX, mapY, 30);
|
|
|
|
|
T0172029_Teleporter:
|
|
|
|
|
footPrintsAllowed = true;
|
|
|
|
|
T0172030_Pit:
|
|
|
|
|
while ((thing != Thing::thingEndOfList) && (thing.getType() <= kSensorThingType)) {
|
|
|
|
|
if (thing.getType() == kSensorThingType)
|
|
|
|
|
aspectArray[kFloorOrnOrdAspect] = Sensor(getThingData(thing)).getOrnOrdinal();
|
|
|
|
|
thing = getNextThing(thing);
|
|
|
|
|
}
|
|
|
|
|
goto T0172049_Footprints;
|
|
|
|
|
case kTeleporterElemType:
|
|
|
|
|
aspectArray[kTeleporterVisibleAspect] = square.get(kTeleporterOpen) && square.get(kTeleporterVisible);
|
|
|
|
|
goto T0172029_Teleporter;
|
|
|
|
|
case kStairsElemType:
|
|
|
|
|
aspectArray[kElemAspect] = ((square.get(kStairsNorthSouthOrient) >> 3) == isOrientedWestEast(dir)) ? kStairsSideElemType : kStairsFrontElemType;
|
|
|
|
|
aspectArray[kStairsUpAspect] = square.get(kStairsUp);
|
|
|
|
|
footPrintsAllowed = false;
|
|
|
|
|
goto T0172046_Stairs;
|
|
|
|
|
case kDoorElemType:
|
|
|
|
|
if ((square.get(kDoorNorthSouthOrient) >> 3) == isOrientedWestEast(dir)) {
|
|
|
|
|
aspectArray[kElemAspect] = kDoorSideElemType;
|
|
|
|
|
} else {
|
|
|
|
|
aspectArray[kElemAspect] = kDoorFrontElemType;
|
|
|
|
|
aspectArray[kDoorStateAspect] = square.getDoorState();
|
|
|
|
|
aspectArray[kDoorThingIndexAspect] = getSquareFirstThing(mapX, mapY).getIndex();
|
|
|
|
|
}
|
|
|
|
|
footPrintsAllowed = true;
|
|
|
|
|
T0172046_Stairs:
|
|
|
|
|
while ((thing != Thing::thingEndOfList) && (thing.getType() <= kSensorThingType))
|
|
|
|
|
thing = getNextThing(thing);
|
|
|
|
|
T0172049_Footprints:
|
2016-06-14 16:40:45 +02:00
|
|
|
|
unsigned char scentOrdinal; // see next line comment
|
2016-05-21 12:55:37 +02:00
|
|
|
|
if (footPrintsAllowed) // TODO: I skipped some party query code, must come back later and complete
|
|
|
|
|
aspectArray[kFloorOrnOrdAspect] &= kFootprintsAspect;
|
2016-05-15 15:53:00 +02:00
|
|
|
|
}
|
|
|
|
|
aspectArray[kFirstGroupOrObjectAspect] = thing.toUint16();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DungeonMan::setSquareAspectOrnOrdinals(uint16 *aspectArray, bool leftAllowed, bool frontAllowed, bool rightAllowed, direction dir,
|
|
|
|
|
int16 mapX, int16 mapY, bool isFakeWall) {
|
|
|
|
|
int16 ornCount = _currMap.map->randWallOrnCount;
|
|
|
|
|
|
|
|
|
|
turnDirRight(dir);
|
|
|
|
|
aspectArray[kRightWallOrnOrdAspect] = getRandomOrnOrdinal(leftAllowed, ornCount, mapX, ++mapY * (dir + 1), 30);
|
|
|
|
|
turnDirRight(dir);
|
|
|
|
|
aspectArray[kFrontWallOrnOrdAspect] = getRandomOrnOrdinal(frontAllowed, ornCount, mapX, ++mapY * (dir + 1), 30);
|
|
|
|
|
turnDirRight(dir);
|
|
|
|
|
aspectArray[kLeftWallOrnOrdAspect] = getRandomOrnOrdinal(rightAllowed, ornCount, mapX, ++mapY * (dir + 1), 30);
|
|
|
|
|
|
|
|
|
|
if (isFakeWall || mapX < 0 || mapX >= _currMap.width || mapY < 0 || mapY >= _currMap.height) {
|
|
|
|
|
for (uint16 i = kRightWallOrnOrdAspect; i <= kLeftWallOrnOrdAspect; ++i) {
|
|
|
|
|
if (isWallOrnAnAlcove(ordinalToIndex(aspectArray[i])))
|
|
|
|
|
aspectArray[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int16 DungeonMan::getRandomOrnOrdinal(bool allowed, int16 count, int16 mapX, int16 mapY, int16 modulo) {
|
|
|
|
|
int16 index = (((((2000 + (mapX << 5) + mapY) * 31417) >> 1)
|
|
|
|
|
+ (3000 + (_currMap.index << 6) + _currMap.width + _currMap.height) * 11
|
|
|
|
|
+ _fileHeader.ornamentRandomSeed) >> 2) % modulo;
|
|
|
|
|
if (allowed && index < count)
|
|
|
|
|
return indexToOrdinal(index);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool DungeonMan::isWallOrnAnAlcove(int16 wallOrnIndex) {
|
|
|
|
|
if (wallOrnIndex >= 0)
|
|
|
|
|
for (uint16 i = 0; i < kAlcoveOrnCount; ++i)
|
|
|
|
|
if (_vm->_displayMan->_currMapAlcoveOrnIndices[i] == wallOrnIndex)
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16 *DungeonMan::getThingData(Thing thing) {
|
|
|
|
|
return _dunData.thingsData[thing.getType()][thing.getIndex()];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Thing DungeonMan::getNextThing(Thing thing) {
|
|
|
|
|
return getThingData(thing)[0]; // :)
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-22 17:18:56 +02:00
|
|
|
|
char gMessageAndScrollEscReplacementStrings[32][8] = { // @ G0255_aac_Graphic559_MessageAndScrollEscapeReplacementStrings
|
|
|
|
|
{'x', 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { '?', 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{'y', 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { '!', 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{'T','H','E',' ', 0, 0, 0, 0},
|
|
|
|
|
{'Y','O','U',' ', 0, 0, 0, 0},
|
|
|
|
|
{'z', 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{'{', 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{'|', 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{'}', 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{'~', 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{'', 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0}};
|
|
|
|
|
char gEscReplacementCharacters[32][2] = { // @ G0256_aac_Graphic559_EscapeReplacementCharacters
|
|
|
|
|
{'a', 0},
|
|
|
|
|
{'b', 0},
|
|
|
|
|
{'c', 0},
|
|
|
|
|
{'d', 0},
|
|
|
|
|
{'e', 0},
|
|
|
|
|
{'f', 0},
|
|
|
|
|
{'g', 0},
|
|
|
|
|
{'h', 0},
|
|
|
|
|
{'i', 0},
|
|
|
|
|
{'j', 0},
|
|
|
|
|
{'k', 0},
|
|
|
|
|
{'l', 0},
|
|
|
|
|
{'m', 0},
|
|
|
|
|
{'n', 0},
|
|
|
|
|
{'o', 0},
|
|
|
|
|
{'p', 0},
|
|
|
|
|
{'q', 0},
|
|
|
|
|
{'r', 0},
|
|
|
|
|
{'s', 0},
|
|
|
|
|
{'t', 0},
|
|
|
|
|
{'u', 0},
|
|
|
|
|
{'v', 0},
|
|
|
|
|
{'w', 0},
|
|
|
|
|
{'x', 0},
|
|
|
|
|
{'0', 0},
|
|
|
|
|
{'1', 0},
|
|
|
|
|
{'2', 0},
|
|
|
|
|
{'3', 0},
|
|
|
|
|
{'4', 0},
|
|
|
|
|
{'5', 0},
|
|
|
|
|
{'6', 0},
|
|
|
|
|
{'7', 0}};
|
|
|
|
|
char gInscriptionEscReplacementStrings[32][8] = { // @ G0257_aac_Graphic559_InscriptionEscapeReplacementStrings
|
|
|
|
|
{28, 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{29, 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{19, 7, 4, 26, 0, 0, 0, 0},
|
|
|
|
|
{24, 14, 20, 26, 0, 0, 0, 0},
|
|
|
|
|
{30, 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{31, 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{32, 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{33, 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{34, 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{35, 0, 0, 0, 0, 0, 0, 0}, /* Atari ST Version 1.0 1987-12-08 1987-12-11 1.1 1.2EN 1.2GE: { 0, 0, 0, 0, 0, 0, 0, 0 }, */
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
|
{0, 0, 0, 0, 0, 0, 0, 0}};
|
|
|
|
|
|
|
|
|
|
|
2016-05-22 18:43:35 +02:00
|
|
|
|
void DungeonMan::decodeText(char *destString, Thing thing, TextType type) {
|
|
|
|
|
char sepChar;
|
|
|
|
|
TextString textString(_dunData.thingsData[kTextstringType][thing.getIndex()]);
|
|
|
|
|
if ((textString.isVisible()) || (type & kDecodeEvenIfInvisible)) {
|
|
|
|
|
type = (TextType)(type & ~kDecodeEvenIfInvisible);
|
|
|
|
|
if (type == kTextTypeMessage) {
|
|
|
|
|
*destString++ = '\n';
|
|
|
|
|
sepChar = ' ';
|
|
|
|
|
} else if (type == kTextTypeInscription) {
|
|
|
|
|
sepChar = 0x80;
|
|
|
|
|
} else {
|
|
|
|
|
sepChar = '\n';
|
|
|
|
|
}
|
|
|
|
|
uint16 codeCounter = 0;
|
|
|
|
|
int16 escChar = 0;
|
|
|
|
|
uint16 *codeWord = _dunData.textData + textString.getWordOffset();
|
2016-06-04 10:11:25 +02:00
|
|
|
|
uint16 code = 0, codes = 0;
|
|
|
|
|
char *escReplString = nullptr;
|
2016-05-22 18:43:35 +02:00
|
|
|
|
for (;;) { /*infinite loop*/
|
|
|
|
|
if (!codeCounter) {
|
|
|
|
|
codes = *codeWord++;
|
|
|
|
|
code = (codes >> 10) & 0x1F;
|
|
|
|
|
} else if (codeCounter == 1) {
|
|
|
|
|
code = (codes >> 5) & 0x1F;
|
|
|
|
|
} else {
|
|
|
|
|
code = codes & 0x1F;
|
|
|
|
|
}
|
|
|
|
|
++codeCounter;
|
|
|
|
|
codeCounter %= 3;
|
|
|
|
|
|
|
|
|
|
if (escChar) {
|
|
|
|
|
*destString = '\0';
|
|
|
|
|
if (escChar == 30) {
|
|
|
|
|
if (type != kTextTypeInscription) {
|
|
|
|
|
escReplString = gMessageAndScrollEscReplacementStrings[code];
|
|
|
|
|
} else {
|
|
|
|
|
escReplString = gInscriptionEscReplacementStrings[code];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
escReplString = gEscReplacementCharacters[code];
|
|
|
|
|
}
|
|
|
|
|
strcat(destString, escReplString);
|
|
|
|
|
destString += strlen(escReplString);
|
|
|
|
|
escChar = 0;
|
|
|
|
|
} else if (code < 28) {
|
|
|
|
|
if (type != kTextTypeInscription) {
|
|
|
|
|
if (code == 26) {
|
|
|
|
|
code = ' ';
|
|
|
|
|
} else if (code == 27) {
|
|
|
|
|
code = '.';
|
|
|
|
|
} else {
|
|
|
|
|
code += 'A';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*destString++ = code;
|
|
|
|
|
} else if (code == 28) {
|
|
|
|
|
*destString++ = sepChar;
|
|
|
|
|
} else if (code <= 30) {
|
|
|
|
|
escChar = code;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*destString = ((type == kTextTypeInscription) ? 0x81 : '\0');
|
2016-05-22 17:18:56 +02:00
|
|
|
|
}
|