KYRA: (LOL) - add support for loading original DOS version save files

This commit is contained in:
athrxx 2012-01-06 18:16:08 +01:00
parent a2b553a017
commit 3adc1ab467
3 changed files with 148 additions and 71 deletions

2
NEWS
View file

@ -9,6 +9,8 @@ For a more comprehensive changelog of the latest experimental code, see:
KYRA:
- Fixed bug in the original Lands of Lore GUI which made ScummVM error out
in the case the user did not have a contiguous save slot usage.
- Add support for original DOS Lands of Lore save files (also applies to save
files made with the GOG release)
SCI:
- Fixed race condition in SCI1.1 palette changes. This fixes an error in

View file

@ -54,7 +54,7 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab
header.gameID = in->readByte();
} else {
// try checking for original save header
const int descriptionSize[2] = { 30, 80 };
const int descriptionSize[3] = { 30, 80, 60 };
char descriptionBuffer[81];
bool saveOk = false;
@ -78,6 +78,16 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab
header.description = descriptionBuffer;
header.gameID = GI_KYRA3;
break;
} else if (type == MKTAG('C','D','0','4')) {
header.version = in->readUint32BE();
// We don't check the minor version, since the original doesn't do that either and it isn't required.
if (header.version != MKTAG(' ','C','D','1'))
continue;
saveOk = true;
header.description = descriptionBuffer;
header.gameID = GI_LOL;
in->seek(6, SEEK_CUR);
break;
}
}

View file

@ -27,6 +27,7 @@
#include "common/savefile.h"
#include "common/substream.h"
#include "common/memstream.h"
#include "graphics/scaler.h"
@ -44,6 +45,9 @@ Common::Error LoLEngine::loadGameState(int slot) {
return Common::kNoError;
}
if (header.originalSave)
warning("Trying to load savegame from original interpreter, while this is possible, it is not officially supported");
_screen->fadeClearSceneWindow(10);
completeDoorOperations();
_screen->fillRect(112, 0, 287, 119, 0, 0);
@ -53,38 +57,40 @@ Common::Error LoLEngine::loadGameState(int slot) {
for (int i = 0; i < 4; i++) {
LoLCharacter *c = &_characters[i];
c->flags = in.readUint16BE();
c->flags = in.readUint16();
in.read(c->name, 11);
c->raceClassSex = in.readByte();
c->id = in.readSint16BE();
c->id = in.readSint16();
c->curFaceFrame = in.readByte();
c->tempFaceFrame = in.readByte();
c->screamSfx = in.readByte();
if (header.originalSave)
in.skip(4);
for (int ii = 0; ii < 8; ii++)
c->itemsMight[ii] = in.readUint16BE();
c->itemsMight[ii] = in.readUint16();
for (int ii = 0; ii < 8; ii++)
c->protectionAgainstItems[ii] = in.readUint16BE();
c->itemProtection = in.readUint16BE();
c->hitPointsCur = in.readSint16BE();
c->hitPointsMax = in.readUint16BE();
c->magicPointsCur = in.readSint16BE();
c->magicPointsMax = in.readUint16BE();
c->protectionAgainstItems[ii] = in.readUint16();
c->itemProtection = in.readUint16();
c->hitPointsCur = in.readSint16();
c->hitPointsMax = in.readUint16();
c->magicPointsCur = in.readSint16();
c->magicPointsMax = in.readUint16();
c->field_41 = in.readByte();
c->damageSuffered = in.readUint16BE();
c->weaponHit = in.readUint16BE();
c->totalMightModifier = in.readUint16BE();
c->totalProtectionModifier = in.readUint16BE();
c->might = in.readUint16BE();
c->protection = in.readUint16BE();
c->nextAnimUpdateCountdown = in.readSint16BE();
c->damageSuffered = in.readUint16();
c->weaponHit = in.readUint16();
c->totalMightModifier = in.readUint16();
c->totalProtectionModifier = in.readUint16();
c->might = in.readUint16();
c->protection = in.readUint16();
c->nextAnimUpdateCountdown = in.readSint16();
for (int ii = 0; ii < 11; ii++)
c->items[ii] = in.readUint16BE();
c->items[ii] = in.readUint16();
for (int ii = 0; ii < 3; ii++)
c->skillLevels[ii] = in.readByte();
for (int ii = 0; ii < 3; ii++)
c->skillModifiers[ii] = in.readSByte();
for (int ii = 0; ii < 3; ii++)
c->experiencePts[ii] = in.readUint32BE();
c->experiencePts[ii] = in.readUint32();
for (int ii = 0; ii < 5; ii++)
c->characterUpdateEvents[ii] = in.readByte();
for (int ii = 0; ii < 5; ii++)
@ -96,39 +102,48 @@ Common::Error LoLEngine::loadGameState(int slot) {
}
}
in.read(_wllBuffer4, 80);
if (!header.originalSave)
in.read(_wllBuffer4, 80);
_currentBlock = in.readUint16BE();
_partyPosX = in.readUint16BE();
_partyPosY = in.readUint16BE();
_updateFlags = in.readUint16BE();
_currentBlock = in.readUint16();
_partyPosX = in.readUint16();
_partyPosY = in.readUint16();
_updateFlags = in.readUint16();
_scriptDirection = in.readByte();
_selectedSpell = in.readByte();
if (header.originalSave)
in.skip(2);
_sceneDefaultUpdate = in.readByte();
_compassBroken = in.readByte();
_drainMagic = in.readByte();
_currentDirection = in.readUint16BE();
_compassDirection = in.readUint16BE();
_currentDirection = in.readUint16();
_compassDirection = in.readUint16();
_selectedCharacter = in.readSByte();
if (header.originalSave)
in.skip(1);
_currentLevel = in.readByte();
for (int i = 0; i < 48; i++)
_inventory[i] = in.readSint16BE();
_inventoryCurItem = in.readSint16BE();
_itemInHand = in.readSint16BE();
_lastMouseRegion = in.readSint16BE();
_inventory[i] = in.readSint16();
_inventoryCurItem = in.readSint16();
_itemInHand = in.readSint16();
_lastMouseRegion = in.readSint16();
if (header.version <= 15) {
if (header.originalSave || header.version <= 15) {
uint16 flags[40];
memset(flags, 0, sizeof(flags));
if (header.version == 14) {
for (int i = 0; i < 16; i++)
flags[i] = in.readUint16BE();
flags[26] = in.readUint16BE();
flags[36] = in.readUint16BE();
} else if (header.version == 15) {
flags[i] = in.readUint16();
flags[26] = in.readUint16();
flags[36] = in.readUint16();
} else if (header.originalSave || header.version == 15) {
for (int i = 0; i < 40; i++)
flags[i] = in.readUint16BE();
flags[i] = in.readUint16();
}
memset(_flagsTable, 0, sizeof(_flagsTable));
@ -139,37 +154,56 @@ Common::Error LoLEngine::loadGameState(int slot) {
}
}
} else {
uint32 flagsSize = in.readUint32BE();
uint32 flagsSize = in.readUint32();
assert(flagsSize <= sizeof(_flagsTable));
in.read(_flagsTable, flagsSize);
}
if (header.originalSave)
in.skip(120);
for (int i = 0; i < 24; i++)
_globalScriptVars[i] = in.readUint16BE();
_globalScriptVars[i] = in.readUint16();
if (header.originalSave)
in.skip(152);
_brightness = in.readByte();
_lampOilStatus = in.readByte();
_lampEffect = in.readSByte();
_credits = in.readUint16BE();
if (header.originalSave)
in.skip(1);
_credits = in.readUint16();
for (int i = 0; i < 8; i++)
_globalScriptVars2[i] = in.readUint16BE();
_globalScriptVars2[i] = in.readUint16();
in.read(_availableSpells, 7);
_hasTempDataFlags = in.readUint32BE();
_hasTempDataFlags = in.readUint32();
uint8 *origCmp = 0;
if (header.originalSave) {
in.skip(6);
origCmp = new uint8[2496];
}
for (int i = 0; i < 400; i++) {
ItemInPlay *t = &_itemsInPlay[i];
t->nextAssignedObject = in.readUint16BE();
t->nextDrawObject = in.readUint16BE();
t->nextAssignedObject = in.readUint16();
t->nextDrawObject = in.readUint16();
t->flyingHeight = in.readByte();
t->block = in.readUint16BE();
t->x = in.readUint16BE();
t->y = in.readUint16BE();
t->block = in.readUint16();
t->x = in.readUint16();
t->y = in.readUint16();
t->level = in.readSByte();
t->itemPropertyIndex = in.readUint16BE();
t->shpCurFrame_flg = in.readUint16BE();
t->destDirection = in.readByte();
t->hitOffsX = in.readSByte();
t->hitOffsY = in.readSByte();
t->currentSubFrame = in.readByte();
t->itemPropertyIndex = in.readUint16();
t->shpCurFrame_flg = in.readUint16();
if (!header.originalSave) {
t->destDirection = in.readByte();
t->hitOffsX = in.readSByte();
t->hitOffsY = in.readSByte();
t->currentSubFrame = in.readByte();
}
}
for (int i = 0; i < 1024; i++) {
@ -179,8 +213,13 @@ Common::Error LoLEngine::loadGameState(int slot) {
}
for (int i = 0; i < 29; i++) {
if (!(_hasTempDataFlags & (1 << i)))
if (!(_hasTempDataFlags & (1 << i))) {
if (header.originalSave) {
if (in.size() - in.pos() >= 2500)
in.skip(2500);
}
continue;
}
if (_lvlTempData[i]) {
delete[] _lvlTempData[i]->wallsXorData;
@ -196,21 +235,36 @@ Common::Error LoLEngine::loadGameState(int slot) {
_lvlTempData[i]->monsters = new MonsterInPlay[30];
_lvlTempData[i]->flyingObjects = new FlyingObject[8];
LevelTempData *l = _lvlTempData[i];
uint32 next = in.pos() + 2500;
in.read(l->wallsXorData, 4096);
in.read(l->flags, 1024);
if (header.originalSave) {
in.skip(4);
in.read(origCmp, in.readUint16());
_screen->decodeFrame4(origCmp, _tempBuffer5120, 5120);
memcpy(l->wallsXorData, _tempBuffer5120, 4096);
for (int ii = 0; ii < 1024; ii++)
l->flags[ii] = _tempBuffer5120[4096 + ii];
} else {
in.read(l->wallsXorData, 4096);
for (int ii = 0; ii < 1024; ii++)
l->flags[ii] = in.readByte();
}
if (header.originalSave)
l->monsterDifficulty = in.readUint16();
for (int ii = 0; ii < 30; ii++) {
MonsterInPlay *m = &l->monsters[ii];
m->nextAssignedObject = in.readUint16BE();
m->nextDrawObject = in.readUint16BE();
m->nextAssignedObject = in.readUint16();
m->nextDrawObject = in.readUint16();
m->flyingHeight = in.readByte();
m->block = in.readUint16BE();
m->x = in.readUint16BE();
m->y = in.readUint16BE();
m->block = in.readUint16();
m->x = in.readUint16();
m->y = in.readUint16();
m->shiftStep = in.readSByte();
m->destX = in.readUint16BE();
m->destY = in.readUint16BE();
m->destX = in.readUint16();
m->destY = in.readUint16();
m->destDirection = in.readByte();
m->hitOffsX = in.readSByte();
m->hitOffsY = in.readSByte();
@ -220,15 +274,19 @@ Common::Error LoLEngine::loadGameState(int slot) {
m->id = in.readByte();
m->direction = in.readByte();
m->facing = in.readByte();
m->flags = in.readUint16BE();
m->damageReceived = in.readUint16BE();
m->hitPoints = in.readSint16BE();
m->flags = in.readUint16();
m->damageReceived = in.readUint16();
m->hitPoints = in.readSint16();
m->speedTick = in.readByte();
m->type = in.readByte();
if (header.originalSave)
in.skip(4);
m->numDistAttacks = in.readByte();
m->curDistWeapon = in.readByte();
m->distAttackTick = in.readSByte();
m->assignedItems = in.readUint16BE();
m->assignedItems = in.readUint16();
m->properties = &_monsterProperties[m->type];
in.read(m->equipmentShapes, 4);
}
@ -237,10 +295,10 @@ Common::Error LoLEngine::loadGameState(int slot) {
FlyingObject *m = &l->flyingObjects[ii];
m->enable = in.readByte();
m->objectType = in.readByte();
m->attackerId = in.readUint16BE();
m->item = in.readSint16BE();
m->x = in.readUint16BE();
m->y = in.readUint16BE();
m->attackerId = in.readUint16();
m->item = in.readSint16();
m->x = in.readUint16();
m->y = in.readUint16();
m->flyingHeight = in.readByte();
m->direction = in.readByte();
m->distance = in.readByte();
@ -249,9 +307,15 @@ Common::Error LoLEngine::loadGameState(int slot) {
m->flags = in.readByte();
m->wallFlags = in.readByte();
}
l->monsterDifficulty = in.readByte();
if (header.originalSave)
in.seek(next, SEEK_SET);
else
l->monsterDifficulty = in.readByte();
}
delete[] origCmp;
calcCharPortraitXpos();
memset(_moneyColumnHeight, 0, sizeof(_moneyColumnHeight));
int t = _credits;
@ -365,6 +429,7 @@ Common::Error LoLEngine::saveGameStateIntern(int slot, const char *saveName, con
out->writeSByte(t->level);
out->writeUint16BE(t->itemPropertyIndex);
out->writeUint16BE(t->shpCurFrame_flg);
out->writeByte(t->destDirection);
out->writeSByte(t->hitOffsX);
out->writeSByte(t->hitOffsY);