diff options
Diffstat (limited to 'engines/kyra')
-rw-r--r-- | engines/kyra/lol.cpp | 14 | ||||
-rw-r--r-- | engines/kyra/lol.h | 5 | ||||
-rw-r--r-- | engines/kyra/module.mk | 1 | ||||
-rw-r--r-- | engines/kyra/saveload_lol.cpp | 430 | ||||
-rw-r--r-- | engines/kyra/script_lol.cpp | 11 | ||||
-rw-r--r-- | engines/kyra/staticres.cpp | 8 |
6 files changed, 459 insertions, 10 deletions
diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index 3dd143fe4f..920a79a3cb 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -152,6 +152,7 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _blockDrawingBuffer = 0; _sceneWindowBuffer = 0; memset(_doorShapes, 0, sizeof(_doorShapes)); + memset(_characterFaceShapes, 0, sizeof(_characterFaceShapes)); _lampEffect = _brightness = _lampOilStatus = 0; _lampStatusSuspended = false; @@ -389,6 +390,11 @@ LoLEngine::~LoLEngine() { } } + for (int i = 0; i < 3; i++) { + for (int ii = 0; ii < 40; ii++) + delete[] _characterFaceShapes[ii][i]; + } + delete[] _healOverlay; delete[] _defaultLegendData; @@ -1104,8 +1110,10 @@ void LoLEngine::loadCharFaceShapes(int charNum, int id) { _screen->loadBitmap(file, 3, 3, 0); const uint8 *p = _screen->getCPagePtr(3); - for (int i = 0; i < 40; i++) + for (int i = 0; i < 40; i++) { + delete[] _characterFaceShapes[i][charNum]; _characterFaceShapes[i][charNum] = _screen->makeShapeCopy(p, i); + } } void LoLEngine::updatePortraitSpeechAnim() { @@ -3808,8 +3816,8 @@ void LoLEngine::generateTempData() { char filename[13]; snprintf(filename, sizeof(filename), "LEVEL%d.CMZ", _currentLevel); - _screen->loadBitmap(filename, 3, 3, 0); - const uint8 *p = _screen->getCPagePtr(2); + _screen->loadBitmap(filename, 15, 15, 0); + const uint8 *p = _screen->getCPagePtr(14); uint16 len = READ_LE_UINT16(p + 4); p += 6; diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h index 4a6ab6b0ab..5bb5d02a7d 100644 --- a/engines/kyra/lol.h +++ b/engines/kyra/lol.h @@ -682,6 +682,7 @@ private: int olol_suspendMonster(EMCState *script); int olol_triggerEventOnMouseButtonRelease(EMCState *script); int olol_printWindowText(EMCState *script); + int olol_updateBlockAnimations2(EMCState *script); int olol_checkPartyForItemType(EMCState *script); int olol_setUnkDoorVar(EMCState *script); int olol_resetTimDialogueState(EMCState *script); @@ -1346,8 +1347,8 @@ private: bool lineIsPassable(int, int) { return false; } // save - Common::Error loadGameState(int slot) { return Common::kNoError; } - Common::Error saveGameState(int slot, const char *saveName, const Graphics::Surface *thumbnail) { return Common::kNoError; } + Common::Error loadGameState(int slot); + Common::Error saveGameState(int slot, const char *saveName, const Graphics::Surface *thumbnail); void generateTempData(); LevelTempData *_lvlTempData[28]; diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk index 37d3307751..ac28d741ca 100644 --- a/engines/kyra/module.mk +++ b/engines/kyra/module.mk @@ -25,6 +25,7 @@ MODULE_OBJS := \ resource_intern.o \ saveload.o \ saveload_lok.o \ + saveload_lol.o \ saveload_hof.o \ saveload_mr.o \ scene_v1.o \ diff --git a/engines/kyra/saveload_lol.cpp b/engines/kyra/saveload_lol.cpp new file mode 100644 index 0000000000..bacd367b93 --- /dev/null +++ b/engines/kyra/saveload_lol.cpp @@ -0,0 +1,430 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/savefile.h" +#include "common/system.h" + +#include "kyra/lol.h" +#include "kyra/screen_lol.h" +#include "kyra/resource.h" + +namespace Kyra { + +Common::Error LoLEngine::loadGameState(int slot) { + debugC(9, kDebugLevelMain, "LoLEngine::loadGameState(%d)", slot); + + const uint16 *cdf[] = { _charDefsMan, _charDefsWoman, _charDefsKieran, _charDefsMan, _charDefsAkshel }; + + const char *fileName = getSavegameFilename(slot); + + SaveHeader header; + Common::InSaveFile *saveFile = openSaveForReading(fileName, header); + if (!saveFile) { + _txt->printMessage(2, getLangString(0x425d)); + return Common::kNoError; + } + + _screen->fadeClearSceneWindow(10); + completeDoorOperations(); + _screen->fillRect(112, 0, 287, 119, 0, 0); + _screen->updateScreen(); + + Common::SeekableSubReadStreamEndian in(saveFile, saveFile->pos(), saveFile->size(), !header.originalSave, true); + + for (int i = 0; i < 4; i++) { + LoLCharacter *c = &_characters[i]; + c->flags = in.readUint16BE(); + in.read(c->name, 11); + c->raceClassSex = in.readByte(); + c->id = in.readSint16BE(); + c->curFaceFrame = in.readByte(); + c->defaultFaceFrame = in.readByte(); + c->screamSfx = in.readByte(); + for (int ii = 0; ii < 8; ii++) + c->itemsMight[ii] = in.readUint16BE(); + 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->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(); + for (int ii = 0; ii < 11; ii++) + c->items[ii] = in.readUint16BE(); + for (int ii = 0; ii < 3; ii++) + c->skillLevels[ii] = in.readByte(); + for (int ii = 0; ii < 3; ii++) + c->skillModifiers[ii] = in.readByte(); + for (int ii = 0; ii < 3; ii++) + c->experiencePts[ii] = in.readUint32BE(); + for (int ii = 0; ii < 5; ii++) + c->characterUpdateEvents[ii] = in.readByte(); + for (int ii = 0; ii < 5; ii++) + c->characterUpdateDelay[ii] = in.readByte(); + + if (c->flags & 1) { + loadCharFaceShapes(i, c->id); + c->defaultModifiers = cdf[c->raceClassSex]; + } + } + + in.read(_wllBuffer4, 80); + + _currentBlock = in.readUint16BE(); + _partyPosX = in.readUint16BE(); + _partyPosY = in.readUint16BE(); + _updateFlags = in.readUint16BE(); + _scriptDirection = in.readByte(); + _selectedSpell = in.readByte(); + _sceneDefaultUpdate = in.readByte(); + _compassBroken = in.readByte(); + _drainMagic = in.readByte(); + _currentDirection = in.readUint16BE(); + _compassDirection = in.readUint16BE(); + _selectedCharacter = in.readSByte(); + _currentLevel = in.readByte(); + for (int i = 0; i < 48; i++) + _inventory[i] = in.readUint16BE(); + _inventoryCurItem = in.readSint16BE(); + _itemInHand = in.readSint16BE(); + _lastMouseRegion = in.readSint16BE(); + for (int i = 0; i < 16; i++) + _gameFlags[i] = in.readUint16BE(); + _freezeStateFlags = in.readUint16BE(); + _unkFlag = in.readUint16BE(); + for (int i = 0; i < 24; i++) + _globalScriptVars[i] = in.readUint16BE(); + _brightness = in.readByte(); + _lampOilStatus = in.readByte(); + _lampEffect = in.readByte(); + _credits = in.readUint16BE(); + for (int i = 0; i < 8; i++) + _globalScriptVars2[i] = in.readUint16BE(); + in.read(_availableSpells, 7); + _hasTempDataFlags = in.readUint32BE(); + + for (int i = 0; i < 400; i++) { + ItemInPlay *t = &_itemsInPlay[i]; + t->nextAssignedObject = in.readUint16BE(); + t->nextDrawObject = in.readUint16BE(); + t->flyingHeight = in.readByte(); + t->block = in.readUint16BE(); + t->x = in.readUint16BE(); + t->y = in.readUint16BE(); + 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(); + } + + for (int i = 0; i < 1024; i++) { + LevelBlockProperty *l = &_levelBlockProperties[i]; + l->assignedObjects = l->drawObjects = 0; + l->direction = 5; + } + + for (int i = 0; i < 28; i++) { + if (!(_hasTempDataFlags & (1 << i))) + continue; + + if (_lvlTempData[i]) { + delete[] _lvlTempData[i]->wallsXorData; + delete[] _lvlTempData[i]->flags; + delete[] _lvlTempData[i]->monsters; + delete[] _lvlTempData[i]->flyingObjects; + delete _lvlTempData[i]; + } + + _lvlTempData[i] = new LevelTempData; + _lvlTempData[i]->wallsXorData = new uint8[4096]; + _lvlTempData[i]->flags = new uint8[1024]; + _lvlTempData[i]->monsters = new MonsterInPlay[30]; + _lvlTempData[i]->flyingObjects = new FlyingObject[8]; + LevelTempData *l = _lvlTempData[i]; + + in.read(l->wallsXorData, 4096); + in.read(l->flags, 1024); + + for (int ii = 0; ii < 30; ii++) { + MonsterInPlay *m = &l->monsters[ii]; + m->nextAssignedObject = in.readUint16BE(); + m->nextDrawObject = in.readUint16BE(); + m->flyingHeight = in.readByte(); + m->block = in.readUint16BE(); + m->x = in.readUint16BE(); + m->y = in.readUint16BE(); + m->shiftStep = in.readSByte(); + m->destX = in.readUint16BE(); + m->destY = in.readUint16BE(); + m->destDirection = in.readByte(); + m->hitOffsX = in.readSByte(); + m->hitOffsY = in.readSByte(); + m->currentSubFrame = in.readByte(); + m->mode = in.readByte(); + m->fightCurTick = in.readSByte(); + 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->speedTick = in.readByte(); + m->type = in.readByte(); + m->numDistAttacks = in.readByte(); + m->curDistWeapon = in.readByte(); + m->distAttackTick = in.readSByte(); + m->assignedItems = in.readUint16BE(); + m->properties = &_monsterProperties[m->type]; + in.read(m->field_2A, 4); + } + + for (int ii = 0; ii < 8; ii++) { + FlyingObject *m = &l->flyingObjects[ii]; + m->enable = in.readByte(); + m->objectType = in.readByte(); + m->attackerId = in.readUint16BE(); + m->item = in.readUint16BE(); + m->x = in.readUint16BE(); + m->y = in.readUint16BE(); + m->flyingHeight = in.readByte(); + m->direction = in.readByte(); + m->distance = in.readByte(); + m->field_D = in.readSByte(); + m->c = in.readByte(); + m->flags = in.readByte(); + m->wallFlags = in.readByte(); + } + l->monsterDifficulty = in.readByte(); + } + + calcCharPortraitXpos(); + memset(_moneyColumnHeight, 0, sizeof(_moneyColumnHeight)); + int t = _credits; + _credits = 0; + giveCredits(t, 0); + setHandItem(_itemInHand); + loadLevel(_currentLevel); + gui_drawPlayField(); + timerSpecialCharacterUpdate(0); + _unkFlag |= 0x800; + + return Common::kNoError; +} + +Common::Error LoLEngine::saveGameState(int slot, const char *saveName, const Graphics::Surface *thumbnail) { + debugC(9, kDebugLevelMain, "LoLEngine::saveGameState(%d, '%s', %p)", slot, saveName, (const void *)thumbnail); + + const char *fileName = getSavegameFilename(slot); + + Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumbnail); + if (!out) + return _saveFileMan->getError(); + + completeDoorOperations(); + generateTempData(); + + for (int i = 0; i < 4; i++) { + LoLCharacter *c = &_characters[i]; + out->writeUint16BE(c->flags); + out->write(c->name, 11); + out->writeByte(c->raceClassSex); + out->writeSint16BE(c->id); + out->writeByte(c->curFaceFrame); + out->writeByte(c->defaultFaceFrame); + out->writeByte(c->screamSfx); + for (int ii = 0; ii < 8; ii++) + out->writeUint16BE(c->itemsMight[ii]); + for (int ii = 0; ii < 8; ii++) + out->writeUint16BE(c->protectionAgainstItems[ii]); + out->writeUint16BE(c->itemProtection); + out->writeSint16BE(c->hitPointsCur); + out->writeUint16BE(c->hitPointsMax); + out->writeSint16BE(c->magicPointsCur); + out->writeUint16BE(c->magicPointsMax); + out->writeByte(c->field_41); + out->writeUint16BE(c->damageSuffered); + out->writeUint16BE(c->weaponHit); + out->writeUint16BE(c->totalMightModifier); + out->writeUint16BE(c->totalProtectionModifier); + out->writeUint16BE(c->might); + out->writeUint16BE(c->protection); + out->writeSint16BE(c->nextAnimUpdateCountdown); + for (int ii = 0; ii < 11; ii++) + out->writeUint16BE(c->items[ii]); + for (int ii = 0; ii < 3; ii++) + out->writeByte(c->skillLevels[ii]); + for (int ii = 0; ii < 3; ii++) + out->writeByte(c->skillModifiers[ii]); + for (int ii = 0; ii < 3; ii++) + out->writeUint32BE(c->experiencePts[ii]); + for (int ii = 0; ii < 5; ii++) + out->writeByte(c->characterUpdateEvents[ii]); + for (int ii = 0; ii < 5; ii++) + out->writeByte(c->characterUpdateDelay[ii]); + } + + out->write(_wllBuffer4, 80); + + out->writeUint16BE(_currentBlock); + out->writeUint16BE(_partyPosX); + out->writeUint16BE(_partyPosY); + out->writeUint16BE(_updateFlags); + out->writeByte(_scriptDirection); + out->writeByte(_selectedSpell); + out->writeByte(_sceneDefaultUpdate); + out->writeByte(_compassBroken); + out->writeByte(_drainMagic); + out->writeUint16BE(_currentDirection); + out->writeUint16BE(_compassDirection); + out->writeSByte(_selectedCharacter); + out->writeByte(_currentLevel); + for (int i = 0; i < 48; i++) + out->writeUint16BE(_inventory[i]); + out->writeSint16BE(_inventoryCurItem); + out->writeSint16BE(_itemInHand); + out->writeSint16BE(_lastMouseRegion); + for (int i = 0; i < 16; i++) + out->writeUint16BE(_gameFlags[i]); + out->writeUint16BE(_freezeStateFlags); + out->writeUint16BE(_unkFlag); + for (int i = 0; i < 24; i++) + out->writeUint16BE(_globalScriptVars[i]); + out->writeByte(_brightness); + out->writeByte(_lampOilStatus); + out->writeByte(_lampEffect); + out->writeUint16BE(_credits); + for (int i = 0; i < 8; i++) + out->writeUint16BE(_globalScriptVars2[i]); + out->write(_availableSpells, 7); + out->writeUint32BE(_hasTempDataFlags); + + resetItems(0); + + for (int i = 0; i < 400; i++) { + ItemInPlay *t = &_itemsInPlay[i]; + out->writeUint16BE(t->nextAssignedObject); + out->writeUint16BE(t->nextDrawObject); + out->writeByte(t->flyingHeight); + out->writeUint16BE(t->block); + out->writeUint16BE(t->x); + out->writeUint16BE(t->y); + 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); + out->writeByte(t->currentSubFrame); + } + + addLevelItems(); + + for (int i = 0; i < 28; i++) { + LevelTempData *l = _lvlTempData[i]; + if (!l || !(_hasTempDataFlags & (1 << i))) + continue; + + out->write(l->wallsXorData, 4096); + out->write(l->flags, 1024); + + for (int ii = 0; ii < 30; ii++) { + MonsterInPlay *m = &l->monsters[ii]; + out->writeUint16BE(m->nextAssignedObject); + out->writeUint16BE(m->nextDrawObject); + out->writeByte(m->flyingHeight); + out->writeUint16BE(m->block); + out->writeUint16BE(m->x); + out->writeUint16BE(m->y); + out->writeSByte(m->shiftStep); + out->writeUint16BE(m->destX); + out->writeUint16BE(m->destY); + out->writeByte(m->destDirection); + out->writeSByte(m->hitOffsX); + out->writeSByte(m->hitOffsY); + out->writeByte(m->currentSubFrame); + out->writeByte(m->mode); + out->writeSByte(m->fightCurTick); + out->writeByte(m->id); + out->writeByte(m->direction); + out->writeByte(m->facing); + out->writeUint16BE(m->flags); + out->writeUint16BE(m->damageReceived); + out->writeSint16BE(m->hitPoints); + out->writeByte(m->speedTick); + out->writeByte(m->type); + out->writeByte(m->numDistAttacks); + out->writeByte(m->curDistWeapon); + out->writeSByte(m->distAttackTick); + out->writeUint16BE(m->assignedItems); + out->write(m->field_2A, 4); + } + + for (int ii = 0; ii < 8; ii++) { + FlyingObject *m = &l->flyingObjects[ii]; + out->writeByte(m->enable); + out->writeByte(m->objectType); + out->writeUint16BE(m->attackerId); + out->writeUint16BE(m->item); + out->writeUint16BE(m->x); + out->writeUint16BE(m->y); + out->writeByte(m->flyingHeight); + out->writeByte(m->direction); + out->writeByte(m->distance); + out->writeSByte(m->field_D); + out->writeByte(m->c); + out->writeByte(m->flags); + out->writeByte(m->wallFlags); + } + out->writeByte(l->monsterDifficulty); + } + + out->finalize(); + + // check for errors + if (out->err()) { + warning("Can't write file '%s'. (Disk full?)", fileName); + return Common::kUnknownError; + } else { + debugC(1, kDebugLevelMain, "Saved game '%s.'", saveName); + } + + delete out; + return Common::kNoError; +} + +} // end of namespace Kyra + diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp index f1d5b6b3ab..957aedf47c 100644 --- a/engines/kyra/script_lol.cpp +++ b/engines/kyra/script_lol.cpp @@ -1585,6 +1585,15 @@ int LoLEngine::olol_printWindowText(EMCState *script) { return 1; } +int LoLEngine::olol_updateBlockAnimations2(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_updateBlockAnimations2(%p) (%d, %d, %d, %d, ...)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3)); + int numFrames = stackPos(3); + assert (numFrames <= 97); + int curFrame = stackPos(2) % numFrames; + setWallType(stackPos(0), stackPos(1), stackPos(4 + curFrame)); + return 0; +} + int LoLEngine::olol_checkPartyForItemType(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkPartyForItemType(%p) (%d, %d, %d))", (const void *)script, stackPos(0), stackPos(1), stackPos(2)); int p = stackPos(1); @@ -2315,7 +2324,7 @@ void LoLEngine::setupOpcodeTable() { OpcodeUnImpl(); // 0x84 - OpcodeUnImpl(); + Opcode(olol_updateBlockAnimations2); Opcode(olol_checkPartyForItemType); Opcode(olol_setUnkDoorVar); Opcode(olol_resetTimDialogueState); diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index a0c6afd1fa..c4e193f87f 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1003,10 +1003,10 @@ bool StaticResource::loadCharData(const char *filename, void *&ptr, int &size) { for (int ii = 0; ii < 8; ii++) t->protectionAgainstItems[ii] = file->readUint16LE(); t->itemProtection = file->readUint16LE(); - t->hitPointsCur = file->readSint16LE();; - t->hitPointsMax = file->readUint16LE();; - t->magicPointsCur = file->readSint16LE();; - t->magicPointsMax = file->readUint16LE();; + t->hitPointsCur = file->readSint16LE(); + t->hitPointsMax = file->readUint16LE(); + t->magicPointsCur = file->readSint16LE(); + t->magicPointsMax = file->readUint16LE(); t->field_41 = file->readByte(); t->damageSuffered = file->readUint16LE(); t->weaponHit = file->readUint16LE(); |