TWINE: started to implement saving and loading as well as player name entering

This commit is contained in:
Martin Gerhardy 2020-10-26 00:13:54 +01:00
parent 64ce952c74
commit 71921f241c
14 changed files with 283 additions and 141 deletions

View File

@ -53,6 +53,7 @@ bool TwinEConsole::doChangeScene(int argc, const char **argv) {
bool TwinEConsole::doGiveAllItems(int argc, const char **argv) {
for (int32 i = 0; i < NUM_INVENTORY_ITEMS; ++i) {
_engine->_gameState->gameFlags[i] = 1;
_engine->_gameState->inventoryFlags[i] = 1;
}
int amount = 10;
if (argc > 1) {

View File

@ -71,7 +71,7 @@ void DebugGrid::changeGrid() {
if (_engine->_input->toggleActionIfActive(TwinEActionType::NextRoom)) {
_engine->_scene->currentSceneIdx++;
if (_engine->_scene->currentSceneIdx >= LBA1SceneId::SceneIdMax) {
_engine->_scene->currentSceneIdx = 0;
_engine->_scene->currentSceneIdx = LBA1SceneId::Citadel_Island_Prison;
}
_engine->_scene->needChangeScene = _engine->_scene->currentSceneIdx;
_engine->_redraw->reqBgRedraw = true;
@ -80,7 +80,7 @@ void DebugGrid::changeGrid() {
// Press down - less X positions
if (_engine->_input->toggleActionIfActive(TwinEActionType::PreviousRoom)) {
_engine->_scene->currentSceneIdx--;
if (_engine->_scene->currentSceneIdx < 0) {
if (_engine->_scene->currentSceneIdx < LBA1SceneId::Citadel_Island_Prison) {
_engine->_scene->currentSceneIdx = LBA1SceneId::SceneIdMax - 1;
}
_engine->_scene->needChangeScene = _engine->_scene->currentSceneIdx;

View File

@ -169,19 +169,16 @@ void GameState::initEngineVars() {
_engine->_actor->previousHeroBehaviour = kNormal;
}
bool GameState::loadGame() {
Common::File file;
// TODO: the filename must be handled properly
if (!file.open(SAVE_DIR "S9999.LBA")) {
warning("Could not load the gamestate");
bool GameState::loadGame(Common::InSaveFile* file) {
if (file == nullptr) {
return false;
}
file.skip(1); // skip save game id
file->skip(1); // skip save game id
int playerNameIdx = 0;
do {
const byte c = file.readByte();
const byte c = file->readByte();
if (c == '\0') {
break;
}
@ -193,94 +190,87 @@ bool GameState::loadGame() {
} while (true);
playerName[playerNameIdx] = '\0';
byte numGameFlags = file.readByte();
byte numGameFlags = file->readByte();
if (numGameFlags != NUM_GAME_FLAGS) {
warning("Failed to load gameflags");
return false;
}
file.read(gameFlags, numGameFlags);
_engine->_scene->needChangeScene = file.readByte(); // scene index
gameChapter = file.readByte();
file->read(gameFlags, numGameFlags);
_engine->_scene->needChangeScene = file->readByte(); // scene index
gameChapter = file->readByte();
_engine->_actor->heroBehaviour = (HeroBehaviourType)file.readByte();
_engine->_actor->heroBehaviour = (HeroBehaviourType)file->readByte();
_engine->_actor->previousHeroBehaviour = _engine->_actor->heroBehaviour;
_engine->_scene->sceneHero->life = file.readByte();
inventoryNumKashes = file.readSint16LE();
magicLevelIdx = file.readByte();
inventoryMagicPoints = file.readByte();
inventoryNumLeafsBox = file.readByte();
_engine->_scene->newHeroX = file.readSint16LE();
_engine->_scene->newHeroY = file.readSint16LE();
_engine->_scene->newHeroZ = file.readSint16LE();
_engine->_scene->sceneHero->angle = file.readSint16LE();
_engine->_scene->sceneHero->life = file->readByte();
inventoryNumKashes = file->readSint16LE();
magicLevelIdx = file->readByte();
inventoryMagicPoints = file->readByte();
inventoryNumLeafsBox = file->readByte();
_engine->_scene->newHeroX = file->readSint16LE();
_engine->_scene->newHeroY = file->readSint16LE();
_engine->_scene->newHeroZ = file->readSint16LE();
_engine->_scene->sceneHero->angle = file->readSint16LE();
_engine->_actor->previousHeroAngle = _engine->_scene->sceneHero->angle;
_engine->_scene->sceneHero->body = file.readByte();
_engine->_scene->sceneHero->body = file->readByte();
const byte numHolemapFlags = file.readByte(); // number of holomap locations, always 150
const byte numHolemapFlags = file->readByte(); // number of holomap locations, always 150
if (numHolemapFlags != ARRAYSIZE(holomapFlags)) {
warning("Failed to load holomapflags");
return false;
}
file.read(holomapFlags, numHolemapFlags);
file->read(holomapFlags, numHolemapFlags);
inventoryNumGas = file.readByte();
inventoryNumGas = file->readByte();
const byte numInventoryFlags = file.readByte(); // number of used inventory items, always 28
const byte numInventoryFlags = file->readByte(); // number of used inventory items, always 28
if (numInventoryFlags != NUM_INVENTORY_ITEMS) {
warning("Failed to load inventoryFlags");
return false;
}
file.read(inventoryFlags, numInventoryFlags);
file->read(inventoryFlags, numInventoryFlags);
inventoryNumLeafs = file.readByte();
usingSabre = file.readByte();
inventoryNumLeafs = file->readByte();
usingSabre = file->readByte();
_engine->_scene->currentSceneIdx = -1;
_engine->_scene->heroPositionType = ScenePositionType::kReborn;
return true;
}
bool GameState::saveGame() {
Common::DumpFile file;
// TODO: the filename must be handled properly
if (!file.open(SAVE_DIR "S9999.LBA")) {
warning("Could not save the game");
return false;
}
bool GameState::saveGame(Common::OutSaveFile* file) {
// TODO: the player name must be handled properly
Common::strlcpy(playerName, "TwinEngineSave", sizeof(playerName));
file.writeByte(0x03);
file.writeString(playerName);
file.writeByte(NUM_GAME_FLAGS);
file.write(gameFlags, sizeof(gameFlags));
file.writeByte(_engine->_scene->currentSceneIdx);
file.writeByte(gameChapter);
file.writeByte(_engine->_actor->heroBehaviour);
file.writeByte(_engine->_scene->sceneHero->life);
file.writeSint16LE(inventoryNumKashes);
file.writeByte(magicLevelIdx);
file.writeByte(inventoryMagicPoints);
file.writeByte(inventoryNumLeafsBox);
file.writeSint16LE(_engine->_scene->newHeroX);
file.writeSint16LE(_engine->_scene->newHeroY);
file.writeSint16LE(_engine->_scene->newHeroZ);
file.writeSint16LE(_engine->_scene->sceneHero->angle);
file.writeByte(_engine->_scene->sceneHero->body);
file->writeByte(0x03);
file->writeString(playerName);
file->writeByte(NUM_GAME_FLAGS);
file->write(gameFlags, sizeof(gameFlags));
file->writeByte(_engine->_scene->currentSceneIdx);
file->writeByte(gameChapter);
file->writeByte(_engine->_actor->heroBehaviour);
file->writeByte(_engine->_scene->sceneHero->life);
file->writeSint16LE(inventoryNumKashes);
file->writeByte(magicLevelIdx);
file->writeByte(inventoryMagicPoints);
file->writeByte(inventoryNumLeafsBox);
file->writeSint16LE(_engine->_scene->newHeroX);
file->writeSint16LE(_engine->_scene->newHeroY);
file->writeSint16LE(_engine->_scene->newHeroZ);
file->writeSint16LE(_engine->_scene->sceneHero->angle);
file->writeByte(_engine->_scene->sceneHero->body);
// number of holomap locations
file.writeByte(ARRAYSIZE(holomapFlags));
file.write(holomapFlags, sizeof(holomapFlags));
file->writeByte(ARRAYSIZE(holomapFlags));
file->write(holomapFlags, sizeof(holomapFlags));
file.writeByte(inventoryNumGas);
file->writeByte(inventoryNumGas);
// number of inventory items
file.writeByte(ARRAYSIZE(inventoryFlags));
file.write(inventoryFlags, sizeof(inventoryFlags));
file->writeByte(ARRAYSIZE(inventoryFlags));
file->write(inventoryFlags, sizeof(inventoryFlags));
file.writeByte(inventoryNumLeafs);
file.writeByte(usingSabre);
file->writeByte(inventoryNumLeafs);
file->writeByte(usingSabre);
return true;
}

View File

@ -23,6 +23,7 @@
#ifndef TWINE_GAMESTATE_H
#define TWINE_GAMESTATE_H
#include "common/savefile.h"
#include "common/scummsys.h"
#include "twine/actor.h"
@ -119,8 +120,8 @@ public:
void processFoundItem(int32 item);
bool loadGame();
bool saveGame();
bool loadGame(Common::InSaveFile* file);
bool saveGame(Common::OutSaveFile* file);
void processGameChoices(int32 choiceIdx);

View File

@ -142,6 +142,31 @@ void Input::enableKeyMap(const char *id) {
debug("enable keymap %s", id);
}
uint8 Input::processCustomEngineEventStart(const Common::Event &event) {
if (!_engine->cfgfile.Debug) {
switch (event.customType) {
case TwinEActionType::NextRoom:
case TwinEActionType::PreviousRoom:
case TwinEActionType::ApplyCellingGrid:
case TwinEActionType::IncreaseCellingGridIndex:
case TwinEActionType::DecreaseCellingGridIndex:
break;
default:
actionStates[event.customType] = 1 + event.kbdRepeat;
return twineactions[event.customType].localKey;
}
} else {
actionStates[event.customType] = 1 + event.kbdRepeat;
return twineactions[event.customType].localKey;
}
return 0;
}
uint8 Input::processCustomEngineEventEnd(const Common::Event &event) {
actionStates[event.customType] = 0;
return twineactions[event.customType].localKey;
}
void Input::readKeys() {
skippedKey = 0;
@ -150,27 +175,10 @@ void Input::readKeys() {
uint8 localKey = 0;
switch (event.type) {
case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
actionStates[event.customType] = 0;
localKey = twineactions[event.customType].localKey;
localKey = processCustomEngineEventEnd(event);
break;
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
if (!_engine->cfgfile.Debug) {
switch (event.customType) {
case TwinEActionType::NextRoom:
case TwinEActionType::PreviousRoom:
case TwinEActionType::ApplyCellingGrid:
case TwinEActionType::IncreaseCellingGridIndex:
case TwinEActionType::DecreaseCellingGridIndex:
break;
default:
localKey = twineactions[event.customType].localKey;
actionStates[event.customType] = 1 + event.kbdRepeat;
break;
}
} else {
localKey = twineactions[event.customType].localKey;
actionStates[event.customType] = 1 + event.kbdRepeat;
}
localKey = processCustomEngineEventStart(event);
break;
case Common::EVENT_LBUTTONDOWN:
leftMouse = 1;

View File

@ -23,6 +23,7 @@
#ifndef TWINE_KEYBOARD_H
#define TWINE_KEYBOARD_H
#include "common/events.h"
#include "common/keyboard.h"
#include "common/scummsys.h"
#include "common/util.h"
@ -219,6 +220,8 @@ public:
void getMousePositions(MouseStatusStruct *mouseData);
void readKeys();
uint8 processCustomEngineEventStart(const Common::Event& event);
uint8 processCustomEngineEventEnd(const Common::Event& event);
};
inline const Common::String Input::currentKeyMap() const {

View File

@ -443,9 +443,6 @@ void Menu::drawButton(const int16 *menuSettings, bool hover) {
currentButton++;
topHeight += 56; // increase button top height
// slow down the CPU
_engine->_system->delayMillis(1);
} while (currentButton < maxButton);
}
@ -571,6 +568,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
// draw plasma effect for the current selected button
drawButton(menuSettings, true);
// TODO: update volume settings
_engine->_system->delayMillis(10);
} while (!_engine->_input->toggleActionIfActive(TwinEActionType::UIEnter));
currentButton = *(menuSettings + MenuSettings_FirstButton + currentButton * 2); // get current browsed button

View File

@ -21,7 +21,9 @@
*/
#include "twine/menuoptions.h"
#include "common/keyboard.h"
#include "common/system.h"
#include "common/util.h"
#include "twine/flamovies.h"
#include "twine/gamestate.h"
#include "twine/input.h"
@ -41,6 +43,9 @@ namespace TwinE {
/** Main menu enter players name */
#define MAINMENU_ENTERPLAYERNAME 42
#define ONSCREENKEYBOARD_WIDTH 14
#define ONSCREENKEYBOARD_HEIGHT 5
static const char allowedCharIndex[] = " ABCDEFGHIJKLM.NOPQRSTUVWXYZ-abcdefghijklm?nopqrstuvwxyz!0123456789\040\b\r\0";
void MenuOptions::newGame() {
@ -113,10 +118,10 @@ void MenuOptions::showCredits() {
_engine->setPalette(_engine->_screens->paletteRGBA);
}
void MenuOptions::drawSelectableCharacter(int32 x, int32 y, int32 arg) {
void MenuOptions::drawSelectableCharacter(int32 x, int32 y, bool selected) {
char buffer[2];
buffer[0] = allowedCharIndex[y + x * 14];
buffer[0] = allowedCharIndex[y + x * ONSCREENKEYBOARD_WIDTH];
buffer[1] = '\0';
const int32 centerX = y * 45 + 25;
@ -126,7 +131,7 @@ void MenuOptions::drawSelectableCharacter(int32 x, int32 y, int32 arg) {
const int32 centerY = x * 56 + 200;
const int32 bottom = x * 56 + 200 + 25;
if (arg != 0) {
if (selected) {
_engine->_interface->drawSplittedBox(left, top, right, bottom, 91);
} else {
_engine->_interface->blitBox(left, top, right, bottom, (const int8 *)_engine->workVideoBuffer.getPixels(), left, top, (int8 *)_engine->frontVideoBuffer.getPixels());
@ -142,9 +147,9 @@ void MenuOptions::drawSelectableCharacter(int32 x, int32 y, int32 arg) {
}
void MenuOptions::drawSelectableCharacters() {
for (int8 x = 0; x < 5; x++) {
for (int8 y = 0; y < 14; y++) {
drawSelectableCharacter(x, y, 0);
for (int8 x = 0; x < ONSCREENKEYBOARD_HEIGHT; x++) {
for (int8 y = 0; y < ONSCREENKEYBOARD_WIDTH; y++) {
drawSelectableCharacter(x, y, _onScreenKeyboardY == x && _onScreenKeyboardX == y);
}
}
}
@ -154,7 +159,7 @@ void MenuOptions::drawPlayerName(int32 centerx, int32 top, int32 type) {
const int left = _engine->_text->dialTextBoxLeft;
const int right = _engine->_text->dialTextBoxRight;
if (type == 1) {
_engine->_menu->processPlasmaEffect(left, top, right, 1);
_engine->_menu->processPlasmaEffect(left, top, right, 32);
}
const int bottom = _engine->_text->dialTextBoxBottom;
@ -167,54 +172,120 @@ void MenuOptions::drawPlayerName(int32 centerx, int32 top, int32 type) {
// TODO: _engine->copyBlockPhys(left, top, right, bottom);
}
int32 MenuOptions::enterPlayerName(int32 textIdx) {
bool MenuOptions::enterPlayerName(int32 textIdx) {
_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
_engine->flip();
playerName[0] = '\0'; // TODO: read from settings?
while (1) {
_engine->_text->initTextBank(0);
char buffer[256];
_engine->_text->getMenuText(textIdx, buffer, sizeof(buffer));
_engine->_text->setFontColor(15);
const int halfScreenWidth = (SCREEN_WIDTH / 2);
_engine->_text->drawText(halfScreenWidth - (_engine->_text->getTextSize(buffer) / 2), 20, buffer);
_engine->copyBlockPhys(0, 0, SCREEN_WIDTH - 1, 99);
drawPlayerName(halfScreenWidth, 100, 1);
drawSelectableCharacters();
_engine->flip();
_engine->_text->initTextBank(0);
char buffer[256];
_engine->_text->getMenuText(textIdx, buffer, sizeof(buffer));
_engine->_text->setFontColor(15);
const int halfScreenWidth = (SCREEN_WIDTH / 2);
_engine->_text->drawText(halfScreenWidth - (_engine->_text->getTextSize(buffer) / 2), 20, buffer);
_engine->copyBlockPhys(0, 0, SCREEN_WIDTH - 1, 99);
_engine->flip();
// we don't want custom events here - as we are entering the player name
ScopedKeyMapperDisable scopedKeyMapperDisable;
for (;;) {
Common::Event event;
while (g_system->getEventManager()->pollEvent(event)) {
if (event.type == Common::EVENT_KEYDOWN) {
if (event.kbd.keycode == Common::KEYCODE_KP_ENTER || event.kbd.keycode == Common::KEYCODE_RETURN) {
return 1;
for (;;) {
Common::Event event;
while (g_system->getEventManager()->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
_engine->_input->processCustomEngineEventEnd(event);
break;
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
_engine->_input->processCustomEngineEventStart(event);
if (_engine->_input->toggleActionIfActive(TwinEActionType::UIEnter)) {
if (_onScreenKeyboardLeaveViaOkButton) {
if (_onScreenKeyboardX == ONSCREENKEYBOARD_WIDTH - 1 && _onScreenKeyboardY == ONSCREENKEYBOARD_HEIGHT - 1) {
return true;
}
const size_t size = strlen(playerName);
if (_onScreenKeyboardX == ONSCREENKEYBOARD_WIDTH - 2 && _onScreenKeyboardY == ONSCREENKEYBOARD_HEIGHT - 1) {
if (size >= 1) {
playerName[size - 1] = '\0';
}
continue;
}
const char chr = allowedCharIndex[_onScreenKeyboardX + _onScreenKeyboardY * ONSCREENKEYBOARD_WIDTH];
playerName[size] = chr;
playerName[size + 1] = '\0';
if (size + 1 >= sizeof(playerName) - 1) {
return true;
}
continue;
}
const size_t size = strlen(playerName);
if (size >= sizeof(playerName) - 1) {
return 1;
return true;
}
if (_engine->_input->toggleActionIfActive(TwinEActionType::UIAbort)) {
return false;
}
if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft)) {
--_onScreenKeyboardX;
if (_onScreenKeyboardX < 0) {
_onScreenKeyboardX = ONSCREENKEYBOARD_WIDTH - 1;
}
_onScreenKeyboardLeaveViaOkButton = true;
} else if (_engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
++_onScreenKeyboardX;
if (_onScreenKeyboardX >= ONSCREENKEYBOARD_WIDTH) {
_onScreenKeyboardX = 0;
}
_onScreenKeyboardLeaveViaOkButton = true;
}
if (_engine->_input->toggleActionIfActive(TwinEActionType::UIUp)) {
--_onScreenKeyboardY;
if (_onScreenKeyboardY < 0) {
_onScreenKeyboardY = ONSCREENKEYBOARD_HEIGHT - 1;
}
_onScreenKeyboardLeaveViaOkButton = true;
} else if (_engine->_input->toggleActionIfActive(TwinEActionType::UIDown)) {
++_onScreenKeyboardY;
if (_onScreenKeyboardY >= ONSCREENKEYBOARD_HEIGHT) {
_onScreenKeyboardY = 0;
}
_onScreenKeyboardLeaveViaOkButton = true;
}
break;
case Common::EVENT_KEYDOWN: {
const size_t size = strlen(playerName);
if (!Common::isPrint(event.kbd.ascii)) {
if (event.kbd.keycode == Common::KEYCODE_BACKSPACE) {
if (size >= 1) {
playerName[size - 1] = '\0';
_onScreenKeyboardLeaveViaOkButton = false;
}
}
continue;
}
if (size >= sizeof(playerName) - 1) {
return true;
}
if (strchr(allowedCharIndex, event.kbd.ascii)) {
playerName[size] = event.kbd.ascii;
playerName[size + 1] = '\0';
debug("name: %s", playerName);
drawPlayerName(halfScreenWidth, 100, 1);
_engine->flip();
_onScreenKeyboardLeaveViaOkButton = false;
}
}
if (_engine->shouldQuit()) {
_engine->flip();
break;
}
_engine->_system->delayMillis(1);
};
default:
break;
}
}
if (_engine->shouldQuit()) {
break;
}
_engine->_system->delayMillis(10);
drawPlayerName(halfScreenWidth, 100, 1);
drawSelectableCharacters();
}
return 1;
return false;
}
void MenuOptions::newGameMenu() {
// TODO: process players name
if (enterPlayerName(MAINMENU_ENTERPLAYERNAME)) {
_engine->_gameState->initEngineVars();
newGame();
@ -225,16 +296,41 @@ void MenuOptions::newGameMenu() {
}
}
int MenuOptions::chooseSave(int textIdx) {
if (!_engine->hasSavedSlots()) {
return -1;
}
_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
_engine->flip();
do {
// TODO: assemble menu with save slots and make then loadable.
_engine->_text->initTextBank(0);
char buffer[256];
_engine->_text->getMenuText(textIdx, buffer, sizeof(buffer));
_engine->_text->setFontColor(15);
const int halfScreenWidth = (SCREEN_WIDTH / 2);
_engine->_text->drawText(halfScreenWidth - (_engine->_text->getTextSize(buffer) / 2), 20, buffer);
_engine->copyBlockPhys(0, 0, SCREEN_WIDTH - 1, 99);
_engine->flip();
if (_engine->shouldQuit()) {
break;
}
_engine->_system->delayMillis(1);
} while (_engine->_input->toggleAbortAction());
return 0;
}
void MenuOptions::continueGameMenu() {
//TODO: get list of saved games
//if(chooseSave(MAINMENU_CONTINUEGAME))
{
const int slot = chooseSave(MAINMENU_CONTINUEGAME);
if (slot >= 0) {
_engine->_gameState->initEngineVars();
_engine->_gameState->loadGame();
_engine->loadSaveSlot(slot);
if (_engine->_scene->newHeroX == -1) {
_engine->_scene->heroPositionType = ScenePositionType::kNoPosition;
}
if (_engine->_gameState->gameChapter == 0 && _engine->_scene->currentSceneIdx == 0) {
if (_engine->_gameState->gameChapter == 0 && _engine->_scene->currentSceneIdx == LBA1SceneId::Citadel_Island_Prison) {
newGame();
} else {
_engine->_text->newGameVar5 = 0;

View File

@ -32,12 +32,17 @@ class MenuOptions {
private:
TwinEEngine *_engine;
int32 enterPlayerName(int32 textIdx);
int _onScreenKeyboardX = 0;
int _onScreenKeyboardY = 0;
bool _onScreenKeyboardLeaveViaOkButton = false;
bool enterPlayerName(int32 textIdx);
void drawSelectableCharacters();
void drawPlayerName(int32 centerx, int32 top, int32 type);
void drawSelectableCharacter(int32 x, int32 y, int32 arg);
void drawSelectableCharacter(int32 x, int32 y, bool selected);
void showCredits();
void newGame();
int chooseSave(int textIdx);
public:
MenuOptions(TwinEEngine *engine) : _engine(engine) {}

View File

@ -304,7 +304,7 @@ void Scene::changeScene() {
if (previousSceneIdx != needChangeScene) {
_engine->_actor->previousHeroBehaviour = _engine->_actor->heroBehaviour;
_engine->_actor->previousHeroAngle = sceneHero->angle;
_engine->_gameState->saveGame();
_engine->autoSave();
}
_engine->_actor->restartHeroScene();

View File

@ -248,8 +248,8 @@ public:
uint8 *currentScene = nullptr;
int32 needChangeScene = LBA1SceneId::Citadel_Island_Prison;
int32 currentSceneIdx = 0;
int32 previousSceneIdx = 0;
int32 currentSceneIdx = LBA1SceneId::Citadel_Island_Prison;
int32 previousSceneIdx = LBA1SceneId::Citadel_Island_Prison;
uint8 *spriteShadowPtr = nullptr;
uint8 *spriteBoundingBoxPtr = nullptr;

View File

@ -1396,11 +1396,11 @@ static int32 lTHE_END(TwinEEngine *engine, int32 actorIdx, ActorStruct *actor) {
engine->_gameState->inventoryNumLeafs = 0;
engine->_scene->sceneHero->life = 50;
engine->_gameState->inventoryMagicPoints = 80;
engine->_scene->currentSceneIdx = 113;
engine->_scene->currentSceneIdx = LBA1SceneId::Polar_Island_Final_Battle;
engine->_actor->heroBehaviour = engine->_actor->previousHeroBehaviour;
engine->_scene->newHeroX = -1;
engine->_scene->sceneHero->angle = engine->_actor->previousHeroAngle;
engine->_gameState->saveGame();
engine->autoSave();
return 1; // break;
}

View File

@ -26,11 +26,14 @@
#include "common/error.h"
#include "common/events.h"
#include "common/keyboard.h"
#include "common/savefile.h"
#include "common/str.h"
#include "common/stream.h"
#include "common/system.h"
#include "common/textconsole.h"
#include "common/translation.h"
#include "engines/util.h"
#include "engines/metaengine.h"
#include "graphics/managed_surface.h"
#include "graphics/palette.h"
#include "graphics/pixelformat.h"
@ -167,6 +170,36 @@ bool TwinEEngine::hasFeature(EngineFeature f) const {
return false;
}
bool TwinEEngine::hasSavedSlots() {
Common::SaveFileManager *saveFileMan = getSaveFileManager();
const Common::String pattern(getMetaEngine().getSavegameFilePattern(_targetName.c_str()));
return !saveFileMan->listSavefiles(pattern).empty();
}
void TwinEEngine::wipeSaveSlot(int slot) {
Common::SaveFileManager *saveFileMan = getSaveFileManager();
const Common::String& saveFile = getMetaEngine().getSavegameFile(slot, _targetName.c_str());
saveFileMan->removeSavefile(saveFile);
}
bool TwinEEngine::loadSaveSlot(int slot) {
Common::SaveFileManager *saveFileMan = getSaveFileManager();
const Common::String& saveFile = getMetaEngine().getSavegameFile(slot, _targetName.c_str());
Common::InSaveFile* file = saveFileMan->openForLoading(saveFile);
return _gameState->loadGame(file);
}
bool TwinEEngine::saveSlot(int slot) {
Common::SaveFileManager *saveFileMan = getSaveFileManager();
const Common::String& saveFile = getMetaEngine().getSavegameFile(slot, _targetName.c_str());
Common::OutSaveFile* file = saveFileMan->openForSaving(saveFile);
return _gameState->saveGame(file);
}
void TwinEEngine::autoSave() {
// TODO:
}
void TwinEEngine::allocVideoMemory() {
const Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8();
workVideoBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, format);
@ -362,7 +395,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
unfreezeTime();
_redraw->redrawEngineActions(1);
freezeTime();
_gameState->saveGame(); // auto save game
autoSave();
quitGame = 0;
unfreezeTime();
return 0;
@ -705,7 +738,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
_scene->currentSceneIdx = _scene->previousSceneIdx;
}
_gameState->saveGame();
autoSave();
_gameState->processGameoverAnimation();
quitGame = 0;
return 0;

View File

@ -30,6 +30,7 @@
#include "graphics/managed_surface.h"
#include "graphics/pixelformat.h"
#include "graphics/surface.h"
#include "metaengine.h"
#include "twine/actor.h"
#include "twine/input.h"
#include "twine/detection.h"
@ -167,6 +168,12 @@ public:
Common::Error run() override;
bool hasFeature(EngineFeature f) const override;
void wipeSaveSlot(int slot);
bool hasSavedSlots();
bool loadSaveSlot(int slot);
bool saveSlot(int slot);
void autoSave();
bool isLBA1() const { return _gameType == TwineGameType::GType_LBA; };
bool isLBA2() const { return _gameType == TwineGameType::GType_LBA2; };