From a5fc17f0b190953b2f7d65da9b1de92e4a953fd6 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Tue, 26 Jul 2016 20:07:45 +0600 Subject: WAGE: Add saveGameState() sketch Copy-pasted from asvitkine/wage-engine (on java). I've managed filling in some values, the others are 0 for now. --- engines/wage/saveload.cpp | 192 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 engines/wage/saveload.cpp (limited to 'engines/wage/saveload.cpp') diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp new file mode 100644 index 0000000000..ea3ae34048 --- /dev/null +++ b/engines/wage/saveload.cpp @@ -0,0 +1,192 @@ +/* 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. + * + */ + +#include "common/file.h" +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/config-manager.h" +#include "common/savefile.h" +#include "common/system.h" +#include "common/textconsole.h" +#include "common/translation.h" + +#include "gui/saveload.h" + +#include "graphics/thumbnail.h" +#include "graphics/surface.h" + +#include "wage/wage.h" +#include "wage/world.h" +#include "wage/entities.h" + +#define SAVEGAME_CURRENT_VERSION 1 + +// +// Version 0 (ScummVM): first ScummVM version +// + +namespace Wage { + +static const uint32 AGIflag = MKTAG('W', 'A', 'G', 'E'); + +int WageEngine::saveGame(const Common::String &fileName, const Common::String &descriptionString) { + Common::OutSaveFile *out; + int result = 0; + + debug(9, "WageEngine::saveGame(%s, %s)", fileName.c_str(), descriptionString.c_str()); + if (!(out = _saveFileMan->openForSaving(fileName))) { + warning("Can't create file '%s', game not saved", fileName.c_str()); + return -1; + } else { + debug(9, "Successfully opened %s for writing", fileName.c_str()); + } + + out->writeUint32BE(AGIflag); + + // Write description of saved game, limited to WAGE_SAVEDGAME_DESCRIPTION_LEN characters + terminating NUL + const int WAGE_SAVEDGAME_DESCRIPTION_LEN = 127; + char description[WAGE_SAVEDGAME_DESCRIPTION_LEN + 1]; + + memset(description, 0, sizeof(description)); + strncpy(description, descriptionString.c_str(), WAGE_SAVEDGAME_DESCRIPTION_LEN); + assert(WAGE_SAVEDGAME_DESCRIPTION_LEN + 1 == 128); // safety + out->write(description, 128); + + out->writeByte(SAVEGAME_CURRENT_VERSION); + debug(9, "Writing save game version (%d)", SAVEGAME_CURRENT_VERSION); + + // Thumbnail + Graphics::saveThumbnail(*out); + + // Counters + out->writeSint16LE(_world->_scenes.size()); //numScenes + out->writeSint16LE(_world->_chrs.size()); //numChars + out->writeSint16LE(_world->_objs.size()); //numObjs + + // Hex Offsets + out->writeSint32LE(0); //state.getChrsHexOffset() + out->writeSint32LE(0); //state.getObjsHexOffset() + + // Unique 8-byte World Signature + out->writeSint32LE(0); //8-byte ints? seriously? + + // More Counters + out->writeSint32LE(_world->_player->_context._visits); //visitNum + out->writeSint32LE(0); //state.getLoopNum() + out->writeSint32LE(_world->_player->_context._kills); //killNum + + // Hex offset to player character + out->writeSint32LE(0); //state.getPlayerHexOffset() + + // character in this scene? + out->writeSint32LE(0); //state.getPresCharHexOffset() + + // Hex offset to current scene + out->writeSint32LE(0); //state.getCurSceneHexOffset() + + // wearing a helmet? + out->writeSint32LE(0); //hex offset for <_world->_player->_armor[Chr::ChrArmorType::HEAD_ARMOR]> //state.getHelmetIndex() + + // holding a shield? + out->writeSint32LE(0); //hex offset for <_world->_player->_armor[Chr::ChrArmorType::SHIELD_ARMOR]> //state.getShieldIndex() + + // wearing chest armor? + out->writeSint32LE(0); //hex offset for <_world->_player->_armor[Chr::ChrArmorType::BODY_ARMOR]> //state.getChestArmIndex() + + // wearing spiritual armor? + out->writeSint32LE(0); //hex offset for <_world->_player->_armor[Chr::ChrArmorType::MAGIC_ARMOR]> //state.getSprtArmIndex() + + // TODO: + out->writeSint16LE(0xffff); // ???? - always FFFF + out->writeSint16LE(0xffff); // ???? - always FFFF + out->writeSint16LE(0xffff); // ???? - always FFFF + out->writeSint16LE(0xffff); // ???? - always FFFF + + // did a character just escape? + out->writeSint32LE(0); //state.getRunCharHexOffset() + + // players experience points + out->writeSint32LE(_world->_player->_context._experience); + + out->writeSint16LE(0); //state.getAim() + out->writeSint16LE(0); //state.getOpponentAim() + + // TODO: + out->writeSint16LE(0x0000); // always 0 + out->writeSint16LE(0x0000); // always 0 + out->writeSint16LE(0x0000); // always 0 + + // Base character stats + out->writeByte(_world->_player->_physicalStrength); //state.getBasePhysStr() + out->writeByte(_world->_player->_physicalHp); //state.getBasePhysHp() + out->writeByte(_world->_player->_naturalArmor); //state.getBasePhysArm() + out->writeByte(_world->_player->_physicalAccuracy); //state.getBasePhysAcc() + out->writeByte(_world->_player->_spiritualStength); //state.getBaseSprtStr() + out->writeByte(_world->_player->_spiritialHp); //state.getBaseSprtHp() + out->writeByte(_world->_player->_resistanceToMagic); //state.getBaseSprtArm() + out->writeByte(_world->_player->_spiritualAccuracy); //state.getBaseSprtAcc() + out->writeByte(_world->_player->_runningSpeed); //state.getBaseRunSpeed() + + // TODO: + out->writeByte(0x0A); // ???? - always seems to be 0x0A + + /* + // write user vars + for (short var : state.getUserVars()) + out->->writeSint16LE(var); + + // write updated info for all scenes + out.write(state.getSceneData()); + + // write updated info for all characters + out.write(state.getChrData()); + + // write updated info for all objects + out.write(state.getObjData()); + */ + + out->finalize(); + if (out->err()) { + warning("Can't write file '%s'. (Disk full?)", fileName.c_str()); + result = -1; + } else + debug(9, "Saved game %s in file %s", descriptionString.c_str(), fileName.c_str()); + + delete out; + return result; +} + +Common::String WageEngine::getSavegameFilename(int16 slotId) const { + Common::String saveLoadSlot = _targetName; + saveLoadSlot += Common::String::format(".%.3d", slotId); + return saveLoadSlot; +} + +Common::Error WageEngine::saveGameState(int slot, const Common::String &description) { + Common::String saveLoadSlot = getSavegameFilename(slot); + if (saveGame(saveLoadSlot, description) == 0) + return Common::kNoError; + else + return Common::kUnknownError; +} + +} // End of namespace Agi -- cgit v1.2.3 From fe1f5352aaccd0253b22e5add14ff395e3370953 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Wed, 27 Jul 2016 12:36:41 +0600 Subject: WAGE: Refine WageEngine::saveGame() More values are saved now, yet some are still not found. --- engines/wage/saveload.cpp | 185 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 151 insertions(+), 34 deletions(-) (limited to 'engines/wage/saveload.cpp') diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp index ea3ae34048..71321628a8 100644 --- a/engines/wage/saveload.cpp +++ b/engines/wage/saveload.cpp @@ -18,6 +18,31 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * */ #include "common/file.h" @@ -48,6 +73,30 @@ namespace Wage { static const uint32 AGIflag = MKTAG('W', 'A', 'G', 'E'); +//TODO: make sure these are calculated right: (we add flag, description, etc) +#define VARS_INDEX 0x005E +#define SCENES_INDEX 0x0232 + +#define SCENE_SIZE 0x0010 +#define CHR_SIZE 0x0016 +#define OBJ_SIZE 0x0010 + +#define GET_HEX_OFFSET(ptr, baseOffset, entrySize) ((ptr) == nullptr ? -1 : ((baseOffset) + (entrySize) * (ptr)->_index)) +#define GET_HEX_CHR_OFFSET(ptr) GET_HEX_OFFSET((ptr), chrsHexOffset, CHR_SIZE) +#define GET_HEX_OBJ_OFFSET(ptr) GET_HEX_OFFSET((ptr), objsHexOffset, OBJ_SIZE) +#define GET_HEX_SCENE_OFFSET(ptr) ((ptr) == nullptr ? -1 : (SCENES_INDEX + getSceneIndex(_world->_player->_currentScene) * SCENE_SIZE)) + +int WageEngine::getSceneIndex(Scene *scene) const { + assert(scene); + Common::Array<Scene *> &orderedScenes = _world->_orderedScenes; + for (uint32 i = 0; i < orderedScenes.size(); ++i) { + if (orderedScenes[i] == scene) return i; + } + + warning("Scene's index not found"); + return -1; +} + int WageEngine::saveGame(const Common::String &fileName, const Common::String &descriptionString) { Common::OutSaveFile *out; int result = 0; @@ -83,37 +132,42 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d out->writeSint16LE(_world->_objs.size()); //numObjs // Hex Offsets - out->writeSint32LE(0); //state.getChrsHexOffset() - out->writeSint32LE(0); //state.getObjsHexOffset() + int chrsHexOffset = SCENES_INDEX + _world->_scenes.size() * SCENE_SIZE; //chrs start after scenes + int objsHexOffset = chrsHexOffset + _world->_chrs.size() * CHR_SIZE; //objs start after chrs + out->writeSint32LE(chrsHexOffset); + out->writeSint32LE(objsHexOffset); // Unique 8-byte World Signature - out->writeSint32LE(0); //8-byte ints? seriously? + out->writeSint32LE(0); //TODO: 8-byte ints? seriously? + + Chr *player = _world->_player; + Context &playerContext = player->_context; // More Counters - out->writeSint32LE(_world->_player->_context._visits); //visitNum - out->writeSint32LE(0); //state.getLoopNum() - out->writeSint32LE(_world->_player->_context._kills); //killNum + out->writeSint32LE(playerContext._visits); //visitNum + out->writeSint32LE(0); //TODO: state.getLoopNum() + out->writeSint32LE(playerContext._kills); //killNum // Hex offset to player character - out->writeSint32LE(0); //state.getPlayerHexOffset() + out->writeSint32LE(GET_HEX_CHR_OFFSET(player)); //getPlayerHexOffset() == getHexOffsetForChr(player) // character in this scene? - out->writeSint32LE(0); //state.getPresCharHexOffset() + out->writeSint32LE(GET_HEX_CHR_OFFSET(_monster)); //getPresCharHexOffset() == getHexOffsetForChr(monster) // Hex offset to current scene - out->writeSint32LE(0); //state.getCurSceneHexOffset() + out->writeSint32LE(GET_HEX_SCENE_OFFSET(player->_currentScene)); //getCurSceneHexOffset() // wearing a helmet? - out->writeSint32LE(0); //hex offset for <_world->_player->_armor[Chr::ChrArmorType::HEAD_ARMOR]> //state.getHelmetIndex() + out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::ChrArmorType::HEAD_ARMOR])); //helmetIndex // holding a shield? - out->writeSint32LE(0); //hex offset for <_world->_player->_armor[Chr::ChrArmorType::SHIELD_ARMOR]> //state.getShieldIndex() + out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::ChrArmorType::SHIELD_ARMOR])); //shieldIndex // wearing chest armor? - out->writeSint32LE(0); //hex offset for <_world->_player->_armor[Chr::ChrArmorType::BODY_ARMOR]> //state.getChestArmIndex() + out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::ChrArmorType::BODY_ARMOR])); //chestArmIndex // wearing spiritual armor? - out->writeSint32LE(0); //hex offset for <_world->_player->_armor[Chr::ChrArmorType::MAGIC_ARMOR]> //state.getSprtArmIndex() + out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::ChrArmorType::MAGIC_ARMOR])); //sprtArmIndex // TODO: out->writeSint16LE(0xffff); // ???? - always FFFF @@ -122,13 +176,13 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d out->writeSint16LE(0xffff); // ???? - always FFFF // did a character just escape? - out->writeSint32LE(0); //state.getRunCharHexOffset() + out->writeSint32LE(GET_HEX_CHR_OFFSET(_running)); //getRunCharHexOffset() == getHexOffsetForChr(running) // players experience points - out->writeSint32LE(_world->_player->_context._experience); + out->writeSint32LE(playerContext._experience); - out->writeSint16LE(0); //state.getAim() - out->writeSint16LE(0); //state.getOpponentAim() + out->writeSint16LE(0); //TODO: state.getAim() + out->writeSint16LE(0); //TODO: state.getOpponentAim() // TODO: out->writeSint16LE(0x0000); // always 0 @@ -136,33 +190,96 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d out->writeSint16LE(0x0000); // always 0 // Base character stats - out->writeByte(_world->_player->_physicalStrength); //state.getBasePhysStr() - out->writeByte(_world->_player->_physicalHp); //state.getBasePhysHp() - out->writeByte(_world->_player->_naturalArmor); //state.getBasePhysArm() - out->writeByte(_world->_player->_physicalAccuracy); //state.getBasePhysAcc() - out->writeByte(_world->_player->_spiritualStength); //state.getBaseSprtStr() - out->writeByte(_world->_player->_spiritialHp); //state.getBaseSprtHp() - out->writeByte(_world->_player->_resistanceToMagic); //state.getBaseSprtArm() - out->writeByte(_world->_player->_spiritualAccuracy); //state.getBaseSprtAcc() - out->writeByte(_world->_player->_runningSpeed); //state.getBaseRunSpeed() + // TODO: are these *base* btw? looks like we don't want to save *current* stats + out->writeByte(player->_physicalStrength); //state.getBasePhysStr() + out->writeByte(player->_physicalHp); //state.getBasePhysHp() + out->writeByte(player->_naturalArmor); //state.getBasePhysArm() + out->writeByte(player->_physicalAccuracy); //state.getBasePhysAcc() + out->writeByte(player->_spiritualStength); //state.getBaseSprtStr() + out->writeByte(player->_spiritialHp); //state.getBaseSprtHp() + out->writeByte(player->_resistanceToMagic); //state.getBaseSprtArm() + out->writeByte(player->_spiritualAccuracy); //state.getBaseSprtAcc() + out->writeByte(player->_runningSpeed); //state.getBaseRunSpeed() // TODO: out->writeByte(0x0A); // ???? - always seems to be 0x0A - /* // write user vars - for (short var : state.getUserVars()) - out->->writeSint16LE(var); - + for (uint32 i = 0; i < 26 * 9; ++i) + out->writeSint16LE(playerContext._userVariables[i]); + // write updated info for all scenes - out.write(state.getSceneData()); + Common::Array<Scene *> &orderedScenes = _world->_orderedScenes; + for (uint32 i = 0; i < orderedScenes.size(); ++i) { + Scene *scene = orderedScenes[i]; + if (scene != _world->_storageScene) { + out->writeSint16LE(0); //TODO: scene.resourceId + out->writeSint16LE(scene->_worldY); + out->writeSint16LE(scene->_worldX); + out->writeByte(scene->_blocked[NORTH] ? 0x01 : 0x00); + out->writeByte(scene->_blocked[SOUTH] ? 0x01 : 0x00); + out->writeByte(scene->_blocked[EAST] ? 0x01 : 0x00); + out->writeByte(scene->_blocked[WEST] ? 0x01 : 0x00); + out->writeSint16LE(scene->_soundFrequency); + out->writeByte(scene->_soundType); + // the following two bytes are currently unknown + out->writeByte(0); + out->writeByte(0); + out->writeByte(scene->_visited ? 0x01 : 0x00); + } + } // write updated info for all characters - out.write(state.getChrData()); + Common::Array<Chr *> &orderedChrs = _world->_orderedChrs; + for (uint32 i = 0; i < orderedChrs.size(); ++i) { + Chr *chr = orderedChrs[i]; + out->writeSint16LE(0); //TODO: chr.getResourceID() + out->writeSint16LE(0); //TODO: chr->_currentScene.getResourceID() + //TODO: here we want to write *current* stats + out->writeByte(chr->_physicalStrength); + out->writeByte(chr->_physicalHp); + out->writeByte(chr->_naturalArmor); + out->writeByte(chr->_physicalAccuracy); + out->writeByte(chr->_spiritualStength); + out->writeByte(chr->_spiritialHp); + out->writeByte(chr->_resistanceToMagic); + out->writeByte(chr->_spiritualAccuracy); + out->writeByte(chr->_runningSpeed); + out->writeByte(chr->_rejectsOffers); + out->writeByte(chr->_followsOpponent); + // bytes 16-20 are unknown + out->writeByte(0); + out->writeByte(0); + out->writeByte(0); + out->writeByte(0); + out->writeByte(0); + out->writeByte(chr->_weaponDamage1); + out->writeByte(chr->_weaponDamage2); + } // write updated info for all objects - out.write(state.getObjData()); - */ + Common::Array<Obj *> &orderedObjs = _world->_orderedObjs; + for (uint32 i = 0; i < orderedObjs.size(); ++i) { + Obj *obj = orderedObjs[i]; + Scene *location = obj->_currentScene; + Chr *owner = obj->_currentOwner; + + out->writeSint16LE(0); //TODO: obj.getResourceID() + out->writeSint16LE(0); //TODO: location == nullptr ? 0 : location.getResourceID()); + out->writeSint16LE(0); //TODO: owner == nullptr ? 0 : owner.getResourceID()); + + // bytes 7-9 are unknown (always = 0) + out->writeByte(0); + out->writeByte(0); + out->writeByte(0); + + out->writeByte(obj->_accuracy); + out->writeByte(obj->_value); + out->writeByte(obj->_type); + out->writeByte(obj->_damage); + out->writeByte(obj->_attackType); + out->writeSint16LE(obj->_numberOfUses); + } out->finalize(); if (out->err()) { -- cgit v1.2.3 From 5d804f379ce77f0dd5eb43cfa5c2d18aa2de3585 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Wed, 27 Jul 2016 17:27:18 +0600 Subject: WAGE: Refine saveGame() Base/Current stats fix + loopNum, aim, opponentAim saving. --- engines/wage/saveload.cpp | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) (limited to 'engines/wage/saveload.cpp') diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp index 71321628a8..2c4a23f2d3 100644 --- a/engines/wage/saveload.cpp +++ b/engines/wage/saveload.cpp @@ -145,7 +145,7 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d // More Counters out->writeSint32LE(playerContext._visits); //visitNum - out->writeSint32LE(0); //TODO: state.getLoopNum() + out->writeSint32LE(_loopCount); //loopNum out->writeSint32LE(playerContext._kills); //killNum // Hex offset to player character @@ -181,8 +181,8 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d // players experience points out->writeSint32LE(playerContext._experience); - out->writeSint16LE(0); //TODO: state.getAim() - out->writeSint16LE(0); //TODO: state.getOpponentAim() + out->writeSint16LE(_aim); //aim + out->writeSint16LE(_opponentAim); //opponentAim // TODO: out->writeSint16LE(0x0000); // always 0 @@ -190,16 +190,15 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d out->writeSint16LE(0x0000); // always 0 // Base character stats - // TODO: are these *base* btw? looks like we don't want to save *current* stats - out->writeByte(player->_physicalStrength); //state.getBasePhysStr() - out->writeByte(player->_physicalHp); //state.getBasePhysHp() - out->writeByte(player->_naturalArmor); //state.getBasePhysArm() - out->writeByte(player->_physicalAccuracy); //state.getBasePhysAcc() - out->writeByte(player->_spiritualStength); //state.getBaseSprtStr() - out->writeByte(player->_spiritialHp); //state.getBaseSprtHp() - out->writeByte(player->_resistanceToMagic); //state.getBaseSprtArm() - out->writeByte(player->_spiritualAccuracy); //state.getBaseSprtAcc() - out->writeByte(player->_runningSpeed); //state.getBaseRunSpeed() + out->writeByte(playerContext._statVariables[PHYS_STR_BAS]); //state.getBasePhysStr() + out->writeByte(playerContext._statVariables[PHYS_HIT_BAS]); //state.getBasePhysHp() + out->writeByte(playerContext._statVariables[PHYS_ARM_BAS]); //state.getBasePhysArm() + out->writeByte(playerContext._statVariables[PHYS_ACC_BAS]); //state.getBasePhysAcc() + out->writeByte(playerContext._statVariables[SPIR_STR_BAS]); //state.getBaseSprtStr() + out->writeByte(playerContext._statVariables[SPIR_HIT_BAS]); //state.getBaseSprtHp() + out->writeByte(playerContext._statVariables[SPIR_ARM_BAS]); //state.getBaseSprtArm() + out->writeByte(playerContext._statVariables[SPIR_ACC_BAS]); //state.getBaseSprtAcc() + out->writeByte(playerContext._statVariables[PHYS_SPE_BAS]); //state.getBaseRunSpeed() // TODO: out->writeByte(0x0A); // ???? - always seems to be 0x0A @@ -235,16 +234,16 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d Chr *chr = orderedChrs[i]; out->writeSint16LE(0); //TODO: chr.getResourceID() out->writeSint16LE(0); //TODO: chr->_currentScene.getResourceID() - //TODO: here we want to write *current* stats - out->writeByte(chr->_physicalStrength); - out->writeByte(chr->_physicalHp); - out->writeByte(chr->_naturalArmor); - out->writeByte(chr->_physicalAccuracy); - out->writeByte(chr->_spiritualStength); - out->writeByte(chr->_spiritialHp); - out->writeByte(chr->_resistanceToMagic); - out->writeByte(chr->_spiritualAccuracy); - out->writeByte(chr->_runningSpeed); + Context &chrContext = chr->_context; + out->writeByte(chrContext._statVariables[PHYS_STR_CUR]); + out->writeByte(chrContext._statVariables[PHYS_HIT_CUR]); + out->writeByte(chrContext._statVariables[PHYS_ARM_CUR]); + out->writeByte(chrContext._statVariables[PHYS_ACC_CUR]); + out->writeByte(chrContext._statVariables[SPIR_STR_CUR]); + out->writeByte(chrContext._statVariables[SPIR_HIT_CUR]); + out->writeByte(chrContext._statVariables[SPIR_ARM_CUR]); + out->writeByte(chrContext._statVariables[SPIR_ACC_CUR]); + out->writeByte(chrContext._statVariables[PHYS_SPE_CUR]); out->writeByte(chr->_rejectsOffers); out->writeByte(chr->_followsOpponent); // bytes 16-20 are unknown -- cgit v1.2.3 From 6b21b1f89365bd77494940ec918212069238cc70 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Wed, 27 Jul 2016 17:38:43 +0600 Subject: WAGE: Add World's _signature --- engines/wage/saveload.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines/wage/saveload.cpp') diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp index 2c4a23f2d3..60852551b7 100644 --- a/engines/wage/saveload.cpp +++ b/engines/wage/saveload.cpp @@ -138,7 +138,7 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d out->writeSint32LE(objsHexOffset); // Unique 8-byte World Signature - out->writeSint32LE(0); //TODO: 8-byte ints? seriously? + out->writeSint32LE(_world->_signature); //8-byte ints? seriously? (uses 4 bytes in java code too) Chr *player = _world->_player; Context &playerContext = player->_context; -- cgit v1.2.3 From 35883517994efbcef9b5eb429b3888235745dea8 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Wed, 27 Jul 2016 17:51:00 +0600 Subject: WAGE: Refine saveGame() once more _resourceId is added to entities, so saveGame() can access these ids and save them. --- engines/wage/saveload.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'engines/wage/saveload.cpp') diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp index 60852551b7..a204757543 100644 --- a/engines/wage/saveload.cpp +++ b/engines/wage/saveload.cpp @@ -212,7 +212,7 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d for (uint32 i = 0; i < orderedScenes.size(); ++i) { Scene *scene = orderedScenes[i]; if (scene != _world->_storageScene) { - out->writeSint16LE(0); //TODO: scene.resourceId + out->writeSint16LE(scene->_resourceId); out->writeSint16LE(scene->_worldY); out->writeSint16LE(scene->_worldX); out->writeByte(scene->_blocked[NORTH] ? 0x01 : 0x00); @@ -232,8 +232,8 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d Common::Array<Chr *> &orderedChrs = _world->_orderedChrs; for (uint32 i = 0; i < orderedChrs.size(); ++i) { Chr *chr = orderedChrs[i]; - out->writeSint16LE(0); //TODO: chr.getResourceID() - out->writeSint16LE(0); //TODO: chr->_currentScene.getResourceID() + out->writeSint16LE(chr->_resourceId); + out->writeSint16LE(chr->_currentScene->_resourceId); Context &chrContext = chr->_context; out->writeByte(chrContext._statVariables[PHYS_STR_CUR]); out->writeByte(chrContext._statVariables[PHYS_HIT_CUR]); @@ -263,9 +263,9 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d Scene *location = obj->_currentScene; Chr *owner = obj->_currentOwner; - out->writeSint16LE(0); //TODO: obj.getResourceID() - out->writeSint16LE(0); //TODO: location == nullptr ? 0 : location.getResourceID()); - out->writeSint16LE(0); //TODO: owner == nullptr ? 0 : owner.getResourceID()); + out->writeSint16LE(obj->_resourceId); + out->writeSint16LE(location == nullptr ? 0 : location->_resourceId); + out->writeSint16LE(owner == nullptr ? 0 : owner->_resourceId); // bytes 7-9 are unknown (always = 0) out->writeByte(0); -- cgit v1.2.3 From a4f02c73837ef46f620872d8297cdc6cbf5119dc Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Wed, 27 Jul 2016 18:06:39 +0600 Subject: WAGE: Move some code in saveGame() Now flags, version, description and thumbnail are added in the end of the file, thus making saves compatible with original ones. --- engines/wage/saveload.cpp | 49 +++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 19 deletions(-) (limited to 'engines/wage/saveload.cpp') diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp index a204757543..bc9a443aa0 100644 --- a/engines/wage/saveload.cpp +++ b/engines/wage/saveload.cpp @@ -66,12 +66,16 @@ #define SAVEGAME_CURRENT_VERSION 1 // -// Version 0 (ScummVM): first ScummVM version +// Original saves format is supported. +// ScummVM adds flags, description and thumbnail +// in the end of the file (shouldn't make saves incompatible). +// +// Version 0 (original/ScummVM): first ScummVM version // namespace Wage { -static const uint32 AGIflag = MKTAG('W', 'A', 'G', 'E'); +static const uint32 WAGEflag = MKTAG('W', 'A', 'G', 'E'); //TODO: make sure these are calculated right: (we add flag, description, etc) #define VARS_INDEX 0x005E @@ -109,23 +113,6 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d debug(9, "Successfully opened %s for writing", fileName.c_str()); } - out->writeUint32BE(AGIflag); - - // Write description of saved game, limited to WAGE_SAVEDGAME_DESCRIPTION_LEN characters + terminating NUL - const int WAGE_SAVEDGAME_DESCRIPTION_LEN = 127; - char description[WAGE_SAVEDGAME_DESCRIPTION_LEN + 1]; - - memset(description, 0, sizeof(description)); - strncpy(description, descriptionString.c_str(), WAGE_SAVEDGAME_DESCRIPTION_LEN); - assert(WAGE_SAVEDGAME_DESCRIPTION_LEN + 1 == 128); // safety - out->write(description, 128); - - out->writeByte(SAVEGAME_CURRENT_VERSION); - debug(9, "Writing save game version (%d)", SAVEGAME_CURRENT_VERSION); - - // Thumbnail - Graphics::saveThumbnail(*out); - // Counters out->writeSint16LE(_world->_scenes.size()); //numScenes out->writeSint16LE(_world->_chrs.size()); //numChars @@ -280,6 +267,30 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d out->writeSint16LE(obj->_numberOfUses); } + // the following is appended by ScummVM + out->writeUint32BE(WAGEflag); + + // Write description of saved game, limited to WAGE_SAVEDGAME_DESCRIPTION_LEN characters + terminating NUL + const int WAGE_SAVEDGAME_DESCRIPTION_LEN = 127; + char description[WAGE_SAVEDGAME_DESCRIPTION_LEN + 1]; + + memset(description, 0, sizeof(description)); + strncpy(description, descriptionString.c_str(), WAGE_SAVEDGAME_DESCRIPTION_LEN); + assert(WAGE_SAVEDGAME_DESCRIPTION_LEN + 1 == 128); // safety + out->write(description, 128); + + out->writeByte(SAVEGAME_CURRENT_VERSION); + debug(9, "Writing save game version (%d)", SAVEGAME_CURRENT_VERSION); + + // Thumbnail + Graphics::saveThumbnail(*out); + + // this one to make checking easier: + // it couldn't be added to the beginning + // and we won't be able to find it in the middle, + // so these would be the last 4 bytes of the file + out->writeUint32BE(WAGEflag); + out->finalize(); if (out->err()) { warning("Can't write file '%s'. (Disk full?)", fileName.c_str()); -- cgit v1.2.3 From 18476dc752efd9888222b2b61d30a88648486fbd Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Wed, 27 Jul 2016 21:38:10 +0600 Subject: WAGE: Add loadGame() sketch --- engines/wage/saveload.cpp | 184 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) (limited to 'engines/wage/saveload.cpp') diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp index bc9a443aa0..4b38e5be6e 100644 --- a/engines/wage/saveload.cpp +++ b/engines/wage/saveload.cpp @@ -302,6 +302,190 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d return result; } +int WageEngine::loadGame(int slotId) { + Common::InSaveFile *data; + Common::String fileName = getSavegameFilename(slotId); + + debug(9, "WageEngine::loadGame(%d)", slotId); + if (!(data = _saveFileMan->openForLoading(fileName))) { + warning("Can't open file '%s', game not loaded", fileName.c_str()); + return -1; + } else { + debug(9, "Successfully opened %s for reading", fileName.c_str()); + } + + // Counters + int numScenes = data->readSint16LE(); + int numChars = data->readSint16LE(); + int numObjs = data->readSint16LE(); + + // Hex Offsets + int chrsHexOffset = data->readSint32LE(); + int objsHexOffset = data->readSint32LE(); + + // Unique 8-byte World Signature + _world->_signature = data->readSint32LE(); + + //Chr *player = _world->_player; + //Context &playerContext = player->_context; + + // More Counters + int visitNum = data->readSint32LE(); //visitNum @ playerContext._visits + _loopCount = data->readSint32LE(); //loopNum + int killNum = data->readSint32LE(); //killNum @ playerContext._kills + + // Hex offset to player character + int playerOffset = data->readSint32LE(); + + // character in this scene? + int presCharOffset = data->readSint32LE(); + + // Hex offset to current scene + int currentSceneOffset = data->readSint32LE(); + + // wearing a helmet? + int helmetOffset = data->readSint32LE(); //helmetIndex @ player->_armor[Chr::ChrArmorType::HEAD_ARMOR] + + // holding a shield? + int shieldOffset = data->readSint32LE(); //shieldIndex @ player->_armor[Chr::ChrArmorType::SHIELD_ARMOR] + + // wearing chest armor? + int armorOffset = data->readSint32LE(); //chestArmIndex @ player->_armor[Chr::ChrArmorType::BODY_ARMOR] + + // wearing spiritual armor? + int spiritualArmorOffset = data->readSint32LE(); //sprtArmIndex @ player->_armor[Chr::ChrArmorType::MAGIC_ARMOR] + + data->readSint16LE(); // FFFF + data->readSint16LE(); // FFFF + data->readSint16LE(); // FFFF + data->readSint16LE(); // FFFF + + int runCharOffset = data->readSint32LE(); + + // players experience points + int exp = data->readSint32LE(); // @ playerContext._experience + + _aim = data->readSint16LE(); //aim + _opponentAim = data->readSint16LE(); //opponentAim + + data->readSint16LE(); // 0000 + data->readSint16LE(); // 0000 + data->readSint16LE(); // 0000 + + // Base character stats + int basePhysStr = data->readByte(); // @ playerContext._statVariables[PHYS_STR_BAS] + int basePhysHp = data->readByte(); // @ playerContext._statVariables[PHYS_HIT_BAS] + int basePhysArm = data->readByte(); // @ playerContext._statVariables[PHYS_ARM_BAS] + int basePhysAcc = data->readByte(); // @ playerContext._statVariables[PHYS_ACC_BAS] + int baseSprtStr = data->readByte(); // @ playerContext._statVariables[SPIR_STR_BAS] + int baseSprtHp = data->readByte(); // @ playerContext._statVariables[SPIR_HIT_BAS] + int baseSprtArm = data->readByte(); // @ playerContext._statVariables[SPIR_ARM_BAS] + int baseSprtAcc = data->readByte(); // @ playerContext._statVariables[SPIR_ACC_BAS] + int baseRunSpeed = data->readByte(); // @ playerContext._statVariables[PHYS_SPE_BAS] + + data->readByte(); // 0x0A? + + // write user vars + for (uint32 i = 0; i < 26 * 9; ++i) + data->readSint16LE(); // @ playerContext._userVariables[i] + + // write updated info for all scenes + for (uint32 i = 0; i < numScenes; ++i) { + data->readSint16LE(); // @ scene->_resourceId + data->readSint16LE(); // @ scene->_worldY + data->readSint16LE(); // @ scene->_worldX + data->readByte(); // @ scene->_blocked[NORTH] + data->readByte(); // @ scene->_blocked[SOUTH] + data->readByte(); // @ scene->_blocked[EAST] + data->readByte(); // @ scene->_blocked[WEST] + data->readSint16LE(); // @ scene->_soundFrequency + data->readByte(); // @ scene->_soundType + // the following two bytes are currently unknown + data->readByte(); + data->readByte(); + data->readByte(); // @ scene->_visited + } + + // write updated info for all characters + Common::Array<Chr *> &orderedChrs = _world->_orderedChrs; + for (uint32 i = 0; i < orderedChrs.size(); ++i) { + int resourceId = data->readSint16LE(); + int sceneResourceId = data->readSint16LE(); + + int strength = data->readByte(); // @ chrContext._statVariables[PHYS_STR_CUR] + int hp = data->readByte(); // @ chrContext._statVariables[PHYS_HIT_CUR] + int armor = data->readByte(); // @ chrContext._statVariables[PHYS_ARM_CUR] + int accuracy = data->readByte(); // @ chrContext._statVariables[PHYS_ACC_CUR] + int spirStrength = data->readByte(); // @ chrContext._statVariables[SPIR_STR_CUR] + int spirHp = data->readByte(); // @ chrContext._statVariables[SPIR_HIT_CUR] + int spirArmor = data->readByte(); // @ chrContext._statVariables[SPIR_ARM_CUR] + int spirAccuracy = data->readByte(); // @ chrContext._statVariables[SPIR_ACC_CUR] + int speed = data->readByte(); // @ chrContext._statVariables[PHYS_SPE_CUR] + int rejectsOffers = data->readByte(); // @ chr->_rejectsOffers + int followsOpponent = data->readByte(); // @ chr->_followsOpponent + + // bytes 16-20 are unknown + data->readByte(); + data->readByte(); + data->readByte(); + data->readByte(); + data->readByte(); + + data->readByte(); // @ chr->_weaponDamage1 + data->readByte(); // @ chr->_weaponDamage2 + } + + // write updated info for all objects + for (uint32 i = 0; i < numObjs; ++i) { + int resourceId = data->readSint16LE(); + int locationResourceId = data->readSint16LE(); + int ownerResourceId = data->readSint16LE(); + + // bytes 7-9 are unknown (always = 0) + data->readByte(); + data->readByte(); + data->readByte(); + + data->readByte(); // @ obj->_accuracy + data->readByte(); // @ obj->_value + data->readByte(); // @ obj->_type + data->readByte(); // @ obj->_damage + data->readByte(); // @ obj->_attackType + data->readSint16LE(); // @ obj->_numberOfUses + } + + // the following is appended by ScummVM + if (data->pos() < data->size()) { + int scummvmWageFlag = data->readUint32BE(); + + if (scummvmWageFlag != WAGEflag) { + warning("Extra bytes after original save's information found, but that's not ScummVM's"); + delete data; + return 0; + } + + // Write description of saved game, limited to WAGE_SAVEDGAME_DESCRIPTION_LEN characters + terminating NUL + const int WAGE_SAVEDGAME_DESCRIPTION_LEN = 127; + char description[WAGE_SAVEDGAME_DESCRIPTION_LEN + 1]; + data->read(description, 128); + if (description[WAGE_SAVEDGAME_DESCRIPTION_LEN] != 0) { + warning("Description's last byte is not '\0'"); + description[WAGE_SAVEDGAME_DESCRIPTION_LEN] = 0; + } + + int version = data->readByte(); + if (version != SAVEGAME_CURRENT_VERSION) { + warning("Reading version %d while current is %d", version, SAVEGAME_CURRENT_VERSION); + } + + // Thumbnail + Graphics::loadThumbnail(*data); + } + + delete data; + return 0; +} + Common::String WageEngine::getSavegameFilename(int16 slotId) const { Common::String saveLoadSlot = _targetName; saveLoadSlot += Common::String::format(".%.3d", slotId); -- cgit v1.2.3 From a854217bd67c0e9ac8df552064dbfcaf6fd83024 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Thu, 28 Jul 2016 15:21:14 +0600 Subject: WAGE: Refine loadGame() It now actually does the loading. --- engines/wage/saveload.cpp | 399 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 314 insertions(+), 85 deletions(-) (limited to 'engines/wage/saveload.cpp') diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp index 4b38e5be6e..654812a6b1 100644 --- a/engines/wage/saveload.cpp +++ b/engines/wage/saveload.cpp @@ -88,19 +88,86 @@ static const uint32 WAGEflag = MKTAG('W', 'A', 'G', 'E'); #define GET_HEX_OFFSET(ptr, baseOffset, entrySize) ((ptr) == nullptr ? -1 : ((baseOffset) + (entrySize) * (ptr)->_index)) #define GET_HEX_CHR_OFFSET(ptr) GET_HEX_OFFSET((ptr), chrsHexOffset, CHR_SIZE) #define GET_HEX_OBJ_OFFSET(ptr) GET_HEX_OFFSET((ptr), objsHexOffset, OBJ_SIZE) -#define GET_HEX_SCENE_OFFSET(ptr) ((ptr) == nullptr ? -1 : (SCENES_INDEX + getSceneIndex(_world->_player->_currentScene) * SCENE_SIZE)) +#define GET_HEX_SCENE_OFFSET(ptr) ((ptr) == nullptr ? -1 : \ + ((ptr) == _world->_storageScene ? 0 : (SCENES_INDEX + getSceneIndex(_world->_player->_currentScene) * SCENE_SIZE))) int WageEngine::getSceneIndex(Scene *scene) const { assert(scene); Common::Array<Scene *> &orderedScenes = _world->_orderedScenes; for (uint32 i = 0; i < orderedScenes.size(); ++i) { - if (orderedScenes[i] == scene) return i; + if (orderedScenes[i] == scene) return i-1; } warning("Scene's index not found"); return -1; } +Obj *WageEngine::getObjByOffset(int offset, int objBaseOffset) const { + int objIndex = -1; + + if (offset != 0xFFFF) { + objIndex = (offset - objBaseOffset) / CHR_SIZE; + } + + if (objIndex >= 0 && objIndex < _world->_orderedObjs.size()) { + return _world->_orderedObjs[objIndex]; + } + + return nullptr; +} + +Chr *WageEngine::getChrById(int resId) const { + Common::Array<Chr *> &orderedChrs = _world->_orderedChrs; + for (uint32 i = 0; i < orderedChrs.size(); ++i) { + if (orderedChrs[i]->_resourceId == resId) + return orderedChrs[i]; + } + + return nullptr; +} + +Chr *WageEngine::getChrByOffset(int offset, int chrBaseOffset) const { + int chrIndex = -1; + + if (offset != 0xFFFF) { + chrIndex = (offset - chrBaseOffset) / CHR_SIZE; + } + + if (chrIndex >= 0 && chrIndex < _world->_orderedChrs.size()) { + return _world->_orderedChrs[chrIndex]; + } + + return nullptr; +} + +Scene *WageEngine::getSceneById(int resId) const { + Common::Array<Scene *> &orderedScenes = _world->_orderedScenes; + for (uint32 i = 0; i < orderedScenes.size(); ++i) { + if (orderedScenes[i]->_resourceId == resId) + return orderedScenes[i]; + } + + return nullptr; +} + +Scene *WageEngine::getSceneByOffset(int offset) const { + int sceneIndex = -1; + + if (offset != 0xFFFF) { + if (offset == 0) + sceneIndex = 0; + else + sceneIndex = 1 + (offset - SCENES_INDEX) / SCENE_SIZE; + } + + if (sceneIndex >= 0 && sceneIndex < _world->_orderedScenes.size()) { + if (sceneIndex == 0) return _world->_storageScene; + return _world->_orderedScenes[sceneIndex]; + } + + return nullptr; +} + int WageEngine::saveGame(const Common::String &fileName, const Common::String &descriptionString) { Common::OutSaveFile *out; int result = 0; @@ -324,15 +391,18 @@ int WageEngine::loadGame(int slotId) { int objsHexOffset = data->readSint32LE(); // Unique 8-byte World Signature - _world->_signature = data->readSint32LE(); - - //Chr *player = _world->_player; - //Context &playerContext = player->_context; + int signature = data->readSint32LE(); + if (_world->_signature != signature) { + warning("This saved game is for a different world, please select another one"); + warning("World signature = %d, save signature = %d", _world->_signature, signature); + delete data; + return -1; + } // More Counters - int visitNum = data->readSint32LE(); //visitNum @ playerContext._visits - _loopCount = data->readSint32LE(); //loopNum - int killNum = data->readSint32LE(); //killNum @ playerContext._kills + int visitNum = data->readSint32LE(); //visitNum + int loopNum = data->readSint32LE(); //loopNum + int killNum = data->readSint32LE(); //killNum // Hex offset to player character int playerOffset = data->readSint32LE(); @@ -343,17 +413,41 @@ int WageEngine::loadGame(int slotId) { // Hex offset to current scene int currentSceneOffset = data->readSint32LE(); + // find player and current scene + Chr *player = getChrByOffset(playerOffset, chrsHexOffset); + if (player == nullptr) { + warning("Invalid Character! Aborting load."); + delete data; + return -1; + } + + Scene *currentScene = getSceneByOffset(currentSceneOffset); + if (currentScene == nullptr) { + warning("Invalid Scene! Aborting load."); + delete data; + return -1; + } + + // set player character + _world->_player = player; + + // set current scene + player->_currentScene = currentScene; + + // clear the players inventory list + player->_inventory.clear(); + // wearing a helmet? - int helmetOffset = data->readSint32LE(); //helmetIndex @ player->_armor[Chr::ChrArmorType::HEAD_ARMOR] + int helmetOffset = data->readSint32LE(); //helmetIndex // holding a shield? - int shieldOffset = data->readSint32LE(); //shieldIndex @ player->_armor[Chr::ChrArmorType::SHIELD_ARMOR] + int shieldOffset = data->readSint32LE(); //shieldIndex // wearing chest armor? - int armorOffset = data->readSint32LE(); //chestArmIndex @ player->_armor[Chr::ChrArmorType::BODY_ARMOR] + int armorOffset = data->readSint32LE(); //chestArmIndex // wearing spiritual armor? - int spiritualArmorOffset = data->readSint32LE(); //sprtArmIndex @ player->_armor[Chr::ChrArmorType::MAGIC_ARMOR] + int spiritualArmorOffset = data->readSint32LE(); //sprtArmIndex data->readSint16LE(); // FFFF data->readSint16LE(); // FFFF @@ -365,64 +459,118 @@ int WageEngine::loadGame(int slotId) { // players experience points int exp = data->readSint32LE(); // @ playerContext._experience - _aim = data->readSint16LE(); //aim - _opponentAim = data->readSint16LE(); //opponentAim + int aim = data->readSint16LE(); //aim + int opponentAim = data->readSint16LE(); //opponentAim data->readSint16LE(); // 0000 data->readSint16LE(); // 0000 data->readSint16LE(); // 0000 // Base character stats - int basePhysStr = data->readByte(); // @ playerContext._statVariables[PHYS_STR_BAS] - int basePhysHp = data->readByte(); // @ playerContext._statVariables[PHYS_HIT_BAS] - int basePhysArm = data->readByte(); // @ playerContext._statVariables[PHYS_ARM_BAS] - int basePhysAcc = data->readByte(); // @ playerContext._statVariables[PHYS_ACC_BAS] - int baseSprtStr = data->readByte(); // @ playerContext._statVariables[SPIR_STR_BAS] - int baseSprtHp = data->readByte(); // @ playerContext._statVariables[SPIR_HIT_BAS] - int baseSprtArm = data->readByte(); // @ playerContext._statVariables[SPIR_ARM_BAS] - int baseSprtAcc = data->readByte(); // @ playerContext._statVariables[SPIR_ACC_BAS] - int baseRunSpeed = data->readByte(); // @ playerContext._statVariables[PHYS_SPE_BAS] + int basePhysStr = data->readByte(); + int basePhysHp = data->readByte(); + int basePhysArm = data->readByte(); + int basePhysAcc = data->readByte(); + int baseSprtStr = data->readByte(); + int baseSprtHp = data->readByte(); + int baseSprtArm = data->readByte(); + int baseSprtAcc = data->readByte(); + int baseRunSpeed = data->readByte(); + + // set player stats + Context &playerContext = player->_context; + // I'm setting player fields also, because those are used as base values in Chr::resetState() + playerContext._statVariables[PHYS_STR_BAS] = player->_physicalStrength = basePhysStr; + playerContext._statVariables[PHYS_HIT_BAS] = player->_physicalHp = basePhysHp; + playerContext._statVariables[PHYS_ARM_BAS] = player->_naturalArmor = basePhysArm; + playerContext._statVariables[PHYS_ACC_BAS] = player->_physicalAccuracy = basePhysAcc; + playerContext._statVariables[SPIR_STR_BAS] = player->_spiritualStength = baseSprtStr; + playerContext._statVariables[SPIR_HIT_BAS] = player->_spiritialHp = baseSprtHp; + playerContext._statVariables[SPIR_ARM_BAS] = player->_resistanceToMagic = baseSprtArm; + playerContext._statVariables[SPIR_ACC_BAS] = player->_spiritualAccuracy = baseSprtAcc; + playerContext._statVariables[PHYS_SPE_BAS] = player->_runningSpeed = baseRunSpeed; + + // set visit# + playerContext._visits = visitNum; + + // set monsters killed + playerContext._kills = killNum; + + // set experience + playerContext._experience = exp; + + // if a character is present, move it to this scene + // TODO: This is done in the engine object, would it be cleaner + // to move it here? + // well, it's actually down there now, now sure if that's "cleaner" + // when it's up there or down there + + // if a character just ran away, let our engine know + // TODO: The current engine doesn't have a case for this, we + // should update it + // yep, I don't see such code anywhere in java, so not added it here data->readByte(); // 0x0A? - // write user vars - for (uint32 i = 0; i < 26 * 9; ++i) - data->readSint16LE(); // @ playerContext._userVariables[i] - - // write updated info for all scenes - for (uint32 i = 0; i < numScenes; ++i) { - data->readSint16LE(); // @ scene->_resourceId - data->readSint16LE(); // @ scene->_worldY - data->readSint16LE(); // @ scene->_worldX - data->readByte(); // @ scene->_blocked[NORTH] - data->readByte(); // @ scene->_blocked[SOUTH] - data->readByte(); // @ scene->_blocked[EAST] - data->readByte(); // @ scene->_blocked[WEST] - data->readSint16LE(); // @ scene->_soundFrequency - data->readByte(); // @ scene->_soundType - // the following two bytes are currently unknown - data->readByte(); - data->readByte(); - data->readByte(); // @ scene->_visited + // set all user variables + for (uint32 i = 0; i < 26 * 9; ++i) { + playerContext._userVariables[i] = data->readSint16LE(); } - // write updated info for all characters + // update all scene stats + Common::Array<Scene *> &orderedScenes = _world->_orderedScenes; + if (numScenes != orderedScenes.size()) { + warning("scenes number in file (%d) differs from the one in world (%d)", numScenes, orderedScenes.size()); + } + for (uint32 i = 0; i < orderedScenes.size(); ++i) { + Scene *scene = orderedScenes[i]; + if (scene == _world->_storageScene) { + scene->_chrs.clear(); + scene->_objs.clear(); + } else { + int id = data->readSint16LE(); + + if (scene->_resourceId != id) { + warning("loadGame(): updating scenes: expected %d but got %d", scene->_resourceId, id); + data->skip(14); //2,2,1,1,1,1,2,1,1,1,1 down there + continue; + } + + scene->_worldY = data->readSint16LE(); + scene->_worldX = data->readSint16LE(); + scene->_blocked[NORTH] = data->readByte() != 0; + scene->_blocked[SOUTH] = data->readByte() != 0; + scene->_blocked[EAST] = data->readByte() != 0; + scene->_blocked[WEST] = data->readByte() != 0; + scene->_soundFrequency = data->readSint16LE(); + scene->_soundType = data->readByte(); + // the following two bytes are currently unknown + data->readByte(); + data->readByte(); + scene->_visited = data->readByte() != 0; + } + } + + // update all char locations and stats Common::Array<Chr *> &orderedChrs = _world->_orderedChrs; + if (numChars != orderedChrs.size()) { + warning("characters number in file (%d) differs from the one in world (%d)", numChars, orderedChrs.size()); + } for (uint32 i = 0; i < orderedChrs.size(); ++i) { int resourceId = data->readSint16LE(); int sceneResourceId = data->readSint16LE(); - int strength = data->readByte(); // @ chrContext._statVariables[PHYS_STR_CUR] - int hp = data->readByte(); // @ chrContext._statVariables[PHYS_HIT_CUR] - int armor = data->readByte(); // @ chrContext._statVariables[PHYS_ARM_CUR] - int accuracy = data->readByte(); // @ chrContext._statVariables[PHYS_ACC_CUR] - int spirStrength = data->readByte(); // @ chrContext._statVariables[SPIR_STR_CUR] - int spirHp = data->readByte(); // @ chrContext._statVariables[SPIR_HIT_CUR] - int spirArmor = data->readByte(); // @ chrContext._statVariables[SPIR_ARM_CUR] - int spirAccuracy = data->readByte(); // @ chrContext._statVariables[SPIR_ACC_CUR] - int speed = data->readByte(); // @ chrContext._statVariables[PHYS_SPE_CUR] - int rejectsOffers = data->readByte(); // @ chr->_rejectsOffers - int followsOpponent = data->readByte(); // @ chr->_followsOpponent + int strength = data->readByte(); + int hp = data->readByte(); + int armor = data->readByte(); + int accuracy = data->readByte(); + int spirStrength = data->readByte(); + int spirHp = data->readByte(); + int spirArmor = data->readByte(); + int spirAccuracy = data->readByte(); + int speed = data->readByte(); + int rejectsOffers = data->readByte(); + int followsOpponent = data->readByte(); // bytes 16-20 are unknown data->readByte(); @@ -431,12 +579,38 @@ int WageEngine::loadGame(int slotId) { data->readByte(); data->readByte(); - data->readByte(); // @ chr->_weaponDamage1 - data->readByte(); // @ chr->_weaponDamage2 + int weaponDamage1 = data->readByte(); + int weaponDamage2 = data->readByte(); + + Chr *chr = orderedChrs[i]; + if (chr->_resourceId != resourceId) { + warning("loadGame(): updating chrs: expected %d but got %d", chr->_resourceId, resourceId); + continue; + } + + chr->_currentScene = getSceneById(sceneResourceId); + Context &chrContext = chr->_context; + chrContext._statVariables[PHYS_STR_CUR] = strength; + chrContext._statVariables[PHYS_HIT_CUR] = hp; + chrContext._statVariables[PHYS_ARM_CUR] = armor; + chrContext._statVariables[PHYS_ACC_CUR] = accuracy; + chrContext._statVariables[SPIR_STR_CUR] = spirStrength; + chrContext._statVariables[SPIR_HIT_CUR] = spirHp; + chrContext._statVariables[SPIR_ARM_CUR] = spirArmor; + chrContext._statVariables[SPIR_ACC_CUR] = spirAccuracy; + chrContext._statVariables[PHYS_SPE_CUR] = speed; + chr->_rejectsOffers = rejectsOffers; + chr->_followsOpponent = followsOpponent; + chr->_weaponDamage1 = weaponDamage1; + chr->_weaponDamage2 = weaponDamage2; } - // write updated info for all objects - for (uint32 i = 0; i < numObjs; ++i) { + // update all object locations and stats + Common::Array<Obj *> &orderedObjs = _world->_orderedObjs; + if (numObjs != orderedObjs.size()) { + warning("objects number in file (%d) differs from the one in world (%d)", numObjs, orderedObjs.size()); + } + for (uint32 i = 0; i < orderedObjs.size(); ++i) { int resourceId = data->readSint16LE(); int locationResourceId = data->readSint16LE(); int ownerResourceId = data->readSint16LE(); @@ -446,42 +620,97 @@ int WageEngine::loadGame(int slotId) { data->readByte(); data->readByte(); - data->readByte(); // @ obj->_accuracy - data->readByte(); // @ obj->_value - data->readByte(); // @ obj->_type - data->readByte(); // @ obj->_damage - data->readByte(); // @ obj->_attackType - data->readSint16LE(); // @ obj->_numberOfUses - } + int accuracy = data->readByte(); + int value = data->readByte(); + int type = data->readByte(); + int damage = data->readByte(); + int attackType= data->readByte(); + int numberOfUses = data->readSint16LE(); - // the following is appended by ScummVM - if (data->pos() < data->size()) { - int scummvmWageFlag = data->readUint32BE(); + Obj *obj = orderedObjs[i]; + if (obj->_resourceId != resourceId) { + warning("loadGame(): updating objs: expected %d but got %d", obj->_resourceId, resourceId); + continue; + } + + if (ownerResourceId != 0) { + obj->setCurrentOwner(getChrById(ownerResourceId)); + if (obj->_currentOwner == nullptr) + warning("loadGame(): updating objs: owner not found - char with id %d", ownerResourceId); + } else { + obj->setCurrentScene(getSceneById(locationResourceId)); + if (obj->_currentScene == nullptr) + warning("loadGame(): updating objs: scene with id %d not found", ownerResourceId); + } + + obj->_accuracy = accuracy; + obj->_value = value; + obj->_type = type; + obj->_damage = damage; + obj->_attackType = attackType; + obj->_numberOfUses = numberOfUses; + } - if (scummvmWageFlag != WAGEflag) { - warning("Extra bytes after original save's information found, but that's not ScummVM's"); - delete data; - return 0; + // update inventories and scene contents + for (uint32 i = 0; i < orderedObjs.size(); ++i) { + Obj *obj = orderedObjs[i]; + Chr *chr = obj->_currentOwner; + if (chr != nullptr) { + chr->_inventory.push_back(obj); + } else { + Scene *scene = obj->_currentScene; + scene->_objs.push_back(obj); } + } - // Write description of saved game, limited to WAGE_SAVEDGAME_DESCRIPTION_LEN characters + terminating NUL - const int WAGE_SAVEDGAME_DESCRIPTION_LEN = 127; - char description[WAGE_SAVEDGAME_DESCRIPTION_LEN + 1]; - data->read(description, 128); - if (description[WAGE_SAVEDGAME_DESCRIPTION_LEN] != 0) { - warning("Description's last byte is not '\0'"); - description[WAGE_SAVEDGAME_DESCRIPTION_LEN] = 0; + // update scene chrs + for (uint32 i = 0; i < orderedChrs.size(); ++i) { + Chr *chr = orderedChrs[i]; + Scene *scene = chr->_currentScene; + scene->_chrs.push_back(chr); + if (chr != player) { + wearObjs(chr); } + } - int version = data->readByte(); - if (version != SAVEGAME_CURRENT_VERSION) { - warning("Reading version %d while current is %d", version, SAVEGAME_CURRENT_VERSION); + // move all worn helmets, shields, chest armors and spiritual + // armors to player + for (int type = 0; type < Chr::ChrArmorType::NUMBER_OF_ARMOR_TYPES; ++type) { + Obj *armor; + + if (type == Chr::ChrArmorType::HEAD_ARMOR) + armor = getObjByOffset(helmetOffset, objsHexOffset); + else if (type == Chr::ChrArmorType::SHIELD_ARMOR) + armor = getObjByOffset(shieldOffset, objsHexOffset); + else if (type == Chr::ChrArmorType::BODY_ARMOR) + armor = getObjByOffset(armorOffset, objsHexOffset); + else + armor = getObjByOffset(spiritualArmorOffset, objsHexOffset); + + if (armor != nullptr) { + _world->move(armor, player); + player->_armor[type] = armor; } + } + + //TODO: make sure that armor in the inventory gets put on if we are wearing it + + _loopCount = loopNum; - // Thumbnail - Graphics::loadThumbnail(*data); + // let the engine know if there is a npc in the current scene + if (presCharOffset != 0xffff) { + _monster = getChrByOffset(presCharOffset, chrsHexOffset); } + // java engine calls clearOutput(); here + // processTurn("look", NULL); called in Wage right after this loadGame() + + // TODO: as you may see, aim, opponentAim or runCharOffset are not used anywhere + // I'm fixing the first two, as those are clearly not even mentioned anywhere + // the runCharOffset is mentioned up there as "not implemented case" + _aim = aim; + _opponentAim = opponentAim; + delete data; return 0; } -- cgit v1.2.3 From faed7c79730f13d98f7b68794293891404013b58 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Fri, 29 Jul 2016 11:35:36 +0600 Subject: WAGE: Fix Chr::ChrArmorType unknown identifier It should've been `Chr` instead. --- engines/wage/saveload.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'engines/wage/saveload.cpp') diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp index 654812a6b1..4889add4f0 100644 --- a/engines/wage/saveload.cpp +++ b/engines/wage/saveload.cpp @@ -212,16 +212,16 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d out->writeSint32LE(GET_HEX_SCENE_OFFSET(player->_currentScene)); //getCurSceneHexOffset() // wearing a helmet? - out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::ChrArmorType::HEAD_ARMOR])); //helmetIndex + out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::HEAD_ARMOR])); //helmetIndex // holding a shield? - out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::ChrArmorType::SHIELD_ARMOR])); //shieldIndex + out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::SHIELD_ARMOR])); //shieldIndex // wearing chest armor? - out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::ChrArmorType::BODY_ARMOR])); //chestArmIndex + out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::BODY_ARMOR])); //chestArmIndex // wearing spiritual armor? - out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::ChrArmorType::MAGIC_ARMOR])); //sprtArmIndex + out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::MAGIC_ARMOR])); //sprtArmIndex // TODO: out->writeSint16LE(0xffff); // ???? - always FFFF @@ -675,14 +675,14 @@ int WageEngine::loadGame(int slotId) { // move all worn helmets, shields, chest armors and spiritual // armors to player - for (int type = 0; type < Chr::ChrArmorType::NUMBER_OF_ARMOR_TYPES; ++type) { + for (int type = 0; type < Chr::NUMBER_OF_ARMOR_TYPES; ++type) { Obj *armor; - if (type == Chr::ChrArmorType::HEAD_ARMOR) + if (type == Chr::HEAD_ARMOR) armor = getObjByOffset(helmetOffset, objsHexOffset); - else if (type == Chr::ChrArmorType::SHIELD_ARMOR) + else if (type == Chr::SHIELD_ARMOR) armor = getObjByOffset(shieldOffset, objsHexOffset); - else if (type == Chr::ChrArmorType::BODY_ARMOR) + else if (type == Chr::BODY_ARMOR) armor = getObjByOffset(armorOffset, objsHexOffset); else armor = getObjByOffset(spiritualArmorOffset, objsHexOffset); -- cgit v1.2.3 From f50d9feee1e04a8ca9271b21859bda48172b7ff5 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Fri, 29 Jul 2016 17:48:23 +0600 Subject: WAGE: Make menu items show Save/Load dialog Default ScummVM Save/Load dialog shows up on click. --- engines/wage/saveload.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'engines/wage/saveload.cpp') diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp index 4889add4f0..78e8d389d3 100644 --- a/engines/wage/saveload.cpp +++ b/engines/wage/saveload.cpp @@ -721,6 +721,13 @@ Common::String WageEngine::getSavegameFilename(int16 slotId) const { return saveLoadSlot; } +Common::Error WageEngine::loadGameState(int slot) { + if (loadGame(slot) == 0) + return Common::kNoError; + else + return Common::kUnknownError; +} + Common::Error WageEngine::saveGameState(int slot, const Common::String &description) { Common::String saveLoadSlot = getSavegameFilename(slot); if (saveGame(saveLoadSlot, description) == 0) @@ -729,4 +736,35 @@ Common::Error WageEngine::saveGameState(int slot, const Common::String &descript return Common::kUnknownError; } +bool WageEngine::scummVMSaveLoadDialog(bool isSave) { + if (!isSave) { + // do loading + GUI::SaveLoadChooser dialog = GUI::SaveLoadChooser(_("Load game:"), _("Load"), false); + int slot = dialog.runModalWithCurrentTarget(); + + if (slot < 0) + return true; + + return loadGameState(slot).getCode() == Common::kNoError; + } + + // do saving + GUI::SaveLoadChooser dialog = GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); + int slot = dialog.runModalWithCurrentTarget(); + Common::String desc = dialog.getResultString(); + + if (desc.empty()) { + // create our own description for the saved game, the user didnt enter it + desc = dialog.createDefaultSaveDescription(slot); + } + + if (desc.size() > 28) + desc = Common::String(desc.c_str(), 28); + + if (slot < 0) + return true; + + return saveGameState(slot, desc).getCode() == Common::kNoError; +} + } // End of namespace Agi -- cgit v1.2.3 From ef631c9e75f09e3a2a54701c1d6bf0e2dce5b71e Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Thu, 4 Aug 2016 15:15:45 +0600 Subject: WAGE: Update saves format Offset is added in the end of the file, so ScummVM would know where to look for description, version, thumbnail information. --- engines/wage/saveload.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'engines/wage/saveload.cpp') diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp index 78e8d389d3..c3b20bdf2f 100644 --- a/engines/wage/saveload.cpp +++ b/engines/wage/saveload.cpp @@ -335,6 +335,10 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d } // the following is appended by ScummVM + int32 appendixOffset = out->pos(); + if (appendixOffset < 0) { + warning("OutSaveFile::pos() failed"); + } out->writeUint32BE(WAGEflag); // Write description of saved game, limited to WAGE_SAVEDGAME_DESCRIPTION_LEN characters + terminating NUL @@ -352,6 +356,8 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d // Thumbnail Graphics::saveThumbnail(*out); + out->writeUint32BE(appendixOffset); + // this one to make checking easier: // it couldn't be added to the beginning // and we won't be able to find it in the middle, -- cgit v1.2.3 From 78f1d707c3284365e158eb0598cdc1ef9b1c0ab6 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sat, 20 Aug 2016 23:54:07 +0200 Subject: WAGE: Fix warnings --- engines/wage/saveload.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'engines/wage/saveload.cpp') diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp index c3b20bdf2f..da10ad41c1 100644 --- a/engines/wage/saveload.cpp +++ b/engines/wage/saveload.cpp @@ -109,7 +109,7 @@ Obj *WageEngine::getObjByOffset(int offset, int objBaseOffset) const { objIndex = (offset - objBaseOffset) / CHR_SIZE; } - if (objIndex >= 0 && objIndex < _world->_orderedObjs.size()) { + if (objIndex >= 0 && (uint)objIndex < _world->_orderedObjs.size()) { return _world->_orderedObjs[objIndex]; } @@ -133,7 +133,7 @@ Chr *WageEngine::getChrByOffset(int offset, int chrBaseOffset) const { chrIndex = (offset - chrBaseOffset) / CHR_SIZE; } - if (chrIndex >= 0 && chrIndex < _world->_orderedChrs.size()) { + if (chrIndex >= 0 && (uint)chrIndex < _world->_orderedChrs.size()) { return _world->_orderedChrs[chrIndex]; } @@ -160,7 +160,7 @@ Scene *WageEngine::getSceneByOffset(int offset) const { sceneIndex = 1 + (offset - SCENES_INDEX) / SCENE_SIZE; } - if (sceneIndex >= 0 && sceneIndex < _world->_orderedScenes.size()) { + if (sceneIndex >= 0 && (uint)sceneIndex < _world->_orderedScenes.size()) { if (sceneIndex == 0) return _world->_storageScene; return _world->_orderedScenes[sceneIndex]; } @@ -224,10 +224,10 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::MAGIC_ARMOR])); //sprtArmIndex // TODO: - out->writeSint16LE(0xffff); // ???? - always FFFF - out->writeSint16LE(0xffff); // ???? - always FFFF - out->writeSint16LE(0xffff); // ???? - always FFFF - out->writeSint16LE(0xffff); // ???? - always FFFF + out->writeUint16LE(0xffff); // ???? - always FFFF + out->writeUint16LE(0xffff); // ???? - always FFFF + out->writeUint16LE(0xffff); // ???? - always FFFF + out->writeUint16LE(0xffff); // ???? - always FFFF // did a character just escape? out->writeSint32LE(GET_HEX_CHR_OFFSET(_running)); //getRunCharHexOffset() == getHexOffsetForChr(running) @@ -260,7 +260,7 @@ int WageEngine::saveGame(const Common::String &fileName, const Common::String &d // write user vars for (uint32 i = 0; i < 26 * 9; ++i) out->writeSint16LE(playerContext._userVariables[i]); - + // write updated info for all scenes Common::Array<Scene *> &orderedScenes = _world->_orderedScenes; for (uint32 i = 0; i < orderedScenes.size(); ++i) { @@ -520,12 +520,12 @@ int WageEngine::loadGame(int slotId) { // set all user variables for (uint32 i = 0; i < 26 * 9; ++i) { - playerContext._userVariables[i] = data->readSint16LE(); + playerContext._userVariables[i] = data->readSint16LE(); } // update all scene stats Common::Array<Scene *> &orderedScenes = _world->_orderedScenes; - if (numScenes != orderedScenes.size()) { + if ((uint)numScenes != orderedScenes.size()) { warning("scenes number in file (%d) differs from the one in world (%d)", numScenes, orderedScenes.size()); } for (uint32 i = 0; i < orderedScenes.size(); ++i) { @@ -559,7 +559,7 @@ int WageEngine::loadGame(int slotId) { // update all char locations and stats Common::Array<Chr *> &orderedChrs = _world->_orderedChrs; - if (numChars != orderedChrs.size()) { + if ((uint)numChars != orderedChrs.size()) { warning("characters number in file (%d) differs from the one in world (%d)", numChars, orderedChrs.size()); } for (uint32 i = 0; i < orderedChrs.size(); ++i) { @@ -613,7 +613,7 @@ int WageEngine::loadGame(int slotId) { // update all object locations and stats Common::Array<Obj *> &orderedObjs = _world->_orderedObjs; - if (numObjs != orderedObjs.size()) { + if ((uint)numObjs != orderedObjs.size()) { warning("objects number in file (%d) differs from the one in world (%d)", numObjs, orderedObjs.size()); } for (uint32 i = 0; i < orderedObjs.size(); ++i) { @@ -727,7 +727,7 @@ Common::String WageEngine::getSavegameFilename(int16 slotId) const { return saveLoadSlot; } -Common::Error WageEngine::loadGameState(int slot) { +Common::Error WageEngine::loadGameState(int slot) { if (loadGame(slot) == 0) return Common::kNoError; else -- cgit v1.2.3