mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-13 15:40:57 +00:00
291 lines
7.3 KiB
C++
291 lines
7.3 KiB
C++
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/scummsys.h"
|
|
#include "common/config-manager.h"
|
|
#include "common/debug-channels.h"
|
|
#include "common/events.h"
|
|
#include "common/system.h"
|
|
#include "common/savefile.h"
|
|
#include "engines/util.h"
|
|
#include "graphics/palette.h"
|
|
#include "m4/m4.h"
|
|
#include "m4/adv_r/adv_control.h"
|
|
#include "m4/adv_r/adv_file.h"
|
|
#include "m4/adv_r/conv_io.h"
|
|
#include "m4/gui/hotkeys.h"
|
|
#include "m4/platform/sound/digi.h"
|
|
#include "m4/platform/sound/midi.h"
|
|
#include "m4/detection.h"
|
|
#include "m4/console.h"
|
|
#include "m4/metaengine.h"
|
|
#include "m4/core/param.h"
|
|
|
|
namespace M4 {
|
|
|
|
#define SAVEGAME_VERSION 1
|
|
|
|
M4Engine *g_engine;
|
|
|
|
M4Engine::M4Engine(OSystem *syst, const M4GameDescription *gameDesc) : Engine(syst),
|
|
_gameDescription(gameDesc), _randomSource("M4") {
|
|
g_engine = this;
|
|
}
|
|
|
|
M4Engine::~M4Engine() {
|
|
delete _screen;
|
|
}
|
|
|
|
uint32 M4Engine::getFeatures() const {
|
|
return _gameDescription->desc.flags;
|
|
}
|
|
|
|
Common::String M4Engine::getGameId() const {
|
|
return _gameDescription->desc.gameId;
|
|
}
|
|
|
|
int M4Engine::getGameType() const {
|
|
return _gameDescription->gameType;
|
|
}
|
|
|
|
Common::Language M4Engine::getLanguage() const {
|
|
return _gameDescription->desc.language;
|
|
}
|
|
|
|
|
|
Common::Error M4Engine::run() {
|
|
// Initialize 320x200 paletted graphics mode
|
|
initGraphics(640, 480);
|
|
|
|
// Instantiate globals and setup
|
|
Vars *vars = createVars();
|
|
|
|
if (vars->init()) {
|
|
// Set the console
|
|
setupConsole();
|
|
|
|
// Check for launcher savegame to load
|
|
_useOriginalSaveLoad = ConfMan.getBool("original_menus");
|
|
if (ConfMan.hasKey("save_slot")) {
|
|
_G(kernel).restore_slot = ConfMan.getInt("save_slot");
|
|
_G(game).previous_room = KERNEL_RESTORING_GAME;
|
|
}
|
|
|
|
// Run game here
|
|
m4_inflight();
|
|
}
|
|
|
|
delete vars;
|
|
return Common::kNoError;
|
|
}
|
|
|
|
#define KEEP_PLAYING (_G(kernel).going && !shouldQuit())
|
|
|
|
void M4Engine::m4_inflight() {
|
|
g_vars->getHotkeys()->add_hot_keys();
|
|
_G(kernel).going = true;
|
|
|
|
while (KEEP_PLAYING) {
|
|
if (_G(game).previous_room == KERNEL_RESTORING_GAME) {
|
|
midi_stop();
|
|
kernel_load_game(_G(kernel).restore_slot);
|
|
}
|
|
|
|
// Start up next section
|
|
_G(between_rooms) = true;
|
|
global_section_constructor(); // Sets the active section
|
|
_G(kernel).going = kernel_section_startup();
|
|
section_init();
|
|
|
|
while (_G(game).new_section == _G(game).section_id && KEEP_PLAYING) {
|
|
m4SceneLoad();
|
|
m4RunScene();
|
|
m4EndScene();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool M4Engine::canLoadGameStateCurrently(Common::U32String *msg) {
|
|
return g_vars && INTERFACE_VISIBLE && player_commands_allowed();
|
|
}
|
|
|
|
bool M4Engine::canSaveGameStateCurrently(Common::U32String *msg) {
|
|
return g_vars && INTERFACE_VISIBLE && player_commands_allowed();
|
|
}
|
|
|
|
void M4Engine::showSaveScreen() {
|
|
saveGameDialog();
|
|
}
|
|
|
|
void M4Engine::showLoadScreen(bool fromMainMenu) {
|
|
loadGameDialog();
|
|
}
|
|
|
|
Common::Error M4Engine::loadGameState(int slot) {
|
|
// Don't load savegame immediately, just set the slot for the engine's
|
|
// kernel to take care of in the outer game loop
|
|
_G(kernel).restore_slot = slot;
|
|
_G(game).new_room = KERNEL_RESTORING_GAME;
|
|
_G(game).new_section = KERNEL_RESTORING_GAME;
|
|
_G(game).previous_room = KERNEL_RESTORING_GAME;
|
|
|
|
return Common::kNoError;
|
|
}
|
|
|
|
Common::Error M4Engine::loadGameStateDoIt(int slot) {
|
|
Common::InSaveFile *save = getOriginalSave(slot);
|
|
|
|
if (save) {
|
|
// Skip original description
|
|
int descSize = save->readUint32LE();
|
|
save->seek(descSize + 45, SEEK_CUR);
|
|
|
|
int thumbSize = save->readUint32LE();
|
|
save->seek(thumbSize, SEEK_CUR);
|
|
|
|
// We're now at data section, handle it
|
|
Common::Serializer s(save, nullptr);
|
|
s.setVersion(1);
|
|
Common::Error result = syncGame(s);
|
|
|
|
delete save;
|
|
|
|
return result;
|
|
|
|
} else {
|
|
return Engine::loadGameState(slot);
|
|
}
|
|
}
|
|
|
|
Common::InSaveFile *M4Engine::getOriginalSave(int slot) const {
|
|
Common::InSaveFile *save = g_system->getSavefileManager()->openForLoading(
|
|
getSaveStateName(slot));
|
|
char name[16];
|
|
|
|
if (save) {
|
|
if (save->seek(-44, SEEK_END) && save->read(name, 7) == 7 &&
|
|
!strncmp(name, "MIRROR", 7)) {
|
|
save->seek(0);
|
|
return save;
|
|
} else if (save->seek(-44, SEEK_END) && save->read(name, 7) == 7 &&
|
|
!strncmp(name, "FAUCET ", 7)) {
|
|
save->seek(0);
|
|
return save;
|
|
}
|
|
|
|
delete save;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
Common::Error M4Engine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
|
|
stream->writeByte(SAVEGAME_VERSION);
|
|
|
|
Common::Serializer s(nullptr, stream);
|
|
return syncGame(s);
|
|
}
|
|
|
|
Common::Error M4Engine::loadGameStream(Common::SeekableReadStream *stream) {
|
|
byte version = stream->readByte();
|
|
if (version > SAVEGAME_VERSION)
|
|
error("Tried to load unsupported savegame version");
|
|
|
|
Common::Serializer s(stream, nullptr);
|
|
s.setVersion(version);
|
|
return syncGame(s);
|
|
}
|
|
|
|
Common::Error M4Engine::syncGame(Common::Serializer &s) {
|
|
if (s.isSaving())
|
|
_G(kernel).pause = false;
|
|
|
|
// To match the original, we sync a set of fields from kernel and game
|
|
if (getGameType() == GType_Riddle)
|
|
s.syncAsByte(_G(kernel).going);
|
|
|
|
s.syncAsByte(_G(kernel).pause);
|
|
for (int i = 0; i < KERNEL_SCRATCH_SIZE; ++i)
|
|
s.syncAsUint32LE(_G(kernel).scratch[i]);
|
|
|
|
s.syncAsByte(_G(kernel).unused);
|
|
s.syncAsSint16LE(_G(kernel).last_save);
|
|
s.syncAsSint16LE(_G(game).room_id);
|
|
s.syncAsSint16LE(_G(game).new_room);
|
|
s.syncAsSint16LE(_G(game).previous_section);
|
|
s.syncAsSint16LE(_G(game).section_id);
|
|
s.syncAsSint16LE(_G(game).new_section);
|
|
s.syncAsSint16LE(_G(game).previous_room);
|
|
|
|
if (getGameType() == GType_Riddle) {
|
|
// TODO: Determinate if the extra fields need to be synced
|
|
s.skip(22);
|
|
|
|
} else {
|
|
s.syncAsByte(_G(kernel).restore_game);
|
|
s.syncAsSint32LE(_G(game).digi_overall_volume_percent);
|
|
s.syncAsSint32LE(_G(game).midi_overall_volume_percent);
|
|
s.syncAsByte(_G(kernel).camera_pan_instant);
|
|
}
|
|
|
|
_G(player).syncGame(s);
|
|
|
|
_G(player_info).syncGame(s);
|
|
|
|
syncFlags(s);
|
|
|
|
player_been_sync(s);
|
|
|
|
_G(conversations).syncGame(s);
|
|
_G(inventory)->syncGame(s);
|
|
|
|
if (s.isLoading()) {
|
|
// set up variables so everyone knows we've teleported
|
|
_G(kernel).restore_game = true;
|
|
_G(between_rooms) = true;
|
|
_G(game).previous_room = KERNEL_RESTORING_GAME;
|
|
|
|
digi_set_overall_volume(_G(game).digi_overall_volume_percent);
|
|
midi_set_overall_volume(_G(game).midi_overall_volume_percent);
|
|
}
|
|
|
|
return Common::kNoError;
|
|
}
|
|
|
|
bool M4Engine::autosaveExists() const {
|
|
Common::String slotName = getSaveStateName(getAutosaveSlot());
|
|
Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(slotName);
|
|
bool result = saveFile != nullptr;
|
|
delete saveFile;
|
|
|
|
return result;
|
|
}
|
|
|
|
SaveStateList M4Engine::listSaves() const {
|
|
return getMetaEngine()->listSaves(_targetName.c_str());
|
|
}
|
|
|
|
bool M4Engine::savesExist() const {
|
|
return !listSaves().empty();
|
|
}
|
|
|
|
} // End of namespace M4
|