scummvm/engines/queen/queen.cpp
Colin Snover 432fd522d2 ENGINES: Remove default1x scaler flag
This flag is removed for a few reasons:

* Engines universally set this flag to true for widths > 320,
  which made it redundant everywhere;
* This flag functioned primarily as a "force 1x scaler" flag,
  since its behaviour was almost completely undocumented and users
  would need to figure out that they'd need an explicit non-default
  scaler set to get a scaler to operate at widths > 320;
* (Most importantly) engines should not be in the business of
  deciding how the backend may choose to render its virtual screen.
  The choice of rendering behaviour belongs to the user, and the
  backend, in that order.

A nearby future commit restores the default1x scaler behaviour in
the SDL backend code for the moment, but in the future it is my
hope that there will be a better configuration UI to allow users
to specify how they want scaling to work for high resolutions.
2017-10-07 12:30:29 -05:00

387 lines
10 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 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 "base/plugins.h"
#include "common/config-manager.h"
#include "common/events.h"
#include "common/file.h"
#include "common/fs.h"
#include "common/savefile.h"
#include "common/system.h"
#include "common/textconsole.h"
#include "engines/util.h"
#include "queen/queen.h"
#include "queen/bankman.h"
#include "queen/command.h"
#include "queen/cutaway.h"
#include "queen/debug.h"
#include "queen/display.h"
#include "queen/graphics.h"
#include "queen/grid.h"
#include "queen/input.h"
#include "queen/logic.h"
#include "queen/resource.h"
#include "queen/sound.h"
#include "queen/talk.h"
#include "queen/walk.h"
namespace Queen {
QueenEngine::QueenEngine(OSystem *syst)
: Engine(syst), _debugger(0), randomizer("queen") {
}
QueenEngine::~QueenEngine() {
delete _bam;
delete _resource;
delete _bankMan;
delete _command;
delete _debugger;
delete _display;
delete _graphics;
delete _grid;
delete _input;
delete _logic;
delete _sound;
delete _walk;
}
void QueenEngine::registerDefaultSettings() {
ConfMan.registerDefault("talkspeed", Logic::DEFAULT_TALK_SPEED);
ConfMan.registerDefault("subtitles", true);
_subtitles = true;
}
void QueenEngine::checkOptionSettings() {
// check talkspeed value
if (_talkSpeed < MIN_TEXT_SPEED) {
_talkSpeed = MIN_TEXT_SPEED;
} else if (_talkSpeed > MAX_TEXT_SPEED) {
_talkSpeed = MAX_TEXT_SPEED;
}
// demo and interview versions don't have speech at all
if (_sound->speechOn() && (_resource->isDemo() || _resource->isInterview())) {
_sound->speechToggle(false);
}
// ensure text is always on when voice is off
if (!_sound->speechOn()) {
_subtitles = true;
}
}
void QueenEngine::syncSoundSettings() {
Engine::syncSoundSettings();
readOptionSettings();
}
void QueenEngine::readOptionSettings() {
bool mute = false;
if (ConfMan.hasKey("mute"))
mute = ConfMan.getBool("mute");
_sound->setVolume(ConfMan.getInt("music_volume"));
_sound->musicToggle(!(mute || ConfMan.getBool("music_mute")));
_sound->sfxToggle(!(mute || ConfMan.getBool("sfx_mute")));
_sound->speechToggle(!(mute || ConfMan.getBool("speech_mute")));
_talkSpeed = (ConfMan.getInt("talkspeed") * (MAX_TEXT_SPEED - MIN_TEXT_SPEED) + 255 / 2) / 255 + MIN_TEXT_SPEED;
_subtitles = ConfMan.getBool("subtitles");
checkOptionSettings();
}
void QueenEngine::writeOptionSettings() {
ConfMan.setInt("music_volume", _sound->getVolume());
ConfMan.setBool("music_mute", !_sound->musicOn());
ConfMan.setBool("sfx_mute", !_sound->sfxOn());
ConfMan.setInt("talkspeed", ((_talkSpeed - MIN_TEXT_SPEED) * 255 + (MAX_TEXT_SPEED - MIN_TEXT_SPEED) / 2) / (MAX_TEXT_SPEED - MIN_TEXT_SPEED));
ConfMan.setBool("speech_mute", !_sound->speechOn());
ConfMan.setBool("subtitles", _subtitles);
ConfMan.flushToDisk();
}
void QueenEngine::update(bool checkPlayerInput) {
_debugger->onFrame();
_graphics->update(_logic->currentRoom());
_logic->update();
int frameDelay = (_lastUpdateTime + Input::DELAY_NORMAL - _system->getMillis());
if (frameDelay <= 0) {
frameDelay = 1;
}
_input->delay(frameDelay);
_lastUpdateTime = _system->getMillis();
if (!_resource->isInterview()) {
_display->palCustomScroll(_logic->currentRoom());
}
BobSlot *joe = _graphics->bob(0);
_display->update(joe->active, joe->x, joe->y);
_input->checkKeys();
if (_input->debugger()) {
_input->debuggerReset();
_debugger->attach();
}
if (canLoadOrSave()) {
if (_input->quickSave()) {
_input->quickSaveReset();
saveGameState(SLOT_QUICKSAVE, "Quicksave");
}
if (_input->quickLoad()) {
_input->quickLoadReset();
loadGameState(SLOT_QUICKSAVE);
}
if (shouldPerformAutoSave(_lastSaveTime)) {
saveGameState(SLOT_AUTOSAVE, "Autosave");
_lastSaveTime = _system->getMillis();
}
}
if (!_input->cutawayRunning()) {
if (checkPlayerInput) {
_command->updatePlayer();
}
if (_input->idleTime() >= Input::DELAY_SCREEN_BLANKER) {
_display->blankScreen();
}
}
_sound->updateMusic();
}
bool QueenEngine::canLoadOrSave() const {
return !_input->cutawayRunning() && !(_resource->isDemo() || _resource->isInterview());
}
bool QueenEngine::canLoadGameStateCurrently() {
return canLoadOrSave();
}
bool QueenEngine::canSaveGameStateCurrently() {
return canLoadOrSave();
}
Common::Error QueenEngine::saveGameState(int slot, const Common::String &desc) {
debug(3, "Saving game to slot %d", slot);
char name[20];
Common::Error err = Common::kNoError;
makeGameStateName(slot, name);
Common::OutSaveFile *file = _saveFileMan->openForSaving(name);
if (file) {
// save data
byte *saveData = new byte[SAVESTATE_MAX_SIZE];
byte *p = saveData;
_bam->saveState(p);
_grid->saveState(p);
_logic->saveState(p);
_sound->saveState(p);
uint32 dataSize = p - saveData;
assert(dataSize < SAVESTATE_MAX_SIZE);
// write header
file->writeUint32BE('SCVM');
file->writeUint32BE(SAVESTATE_CUR_VER);
file->writeUint32BE(0);
file->writeUint32BE(dataSize);
char description[32];
Common::strlcpy(description, desc.c_str(), sizeof(description));
file->write(description, sizeof(description));
// write save data
file->write(saveData, dataSize);
file->finalize();
// check for errors
if (file->err()) {
warning("Can't write file '%s'. (Disk full?)", name);
err = Common::kWritingFailed;
}
delete[] saveData;
delete file;
} else {
warning("Can't create file '%s', game not saved", name);
err = Common::kCreatingFileFailed;
}
return err;
}
Common::Error QueenEngine::loadGameState(int slot) {
debug(3, "Loading game from slot %d", slot);
Common::Error err = Common::kNoError;
GameStateHeader header;
Common::InSaveFile *file = readGameStateHeader(slot, &header);
if (file && header.dataSize != 0) {
byte *saveData = new byte[header.dataSize];
byte *p = saveData;
if (file->read(saveData, header.dataSize) != header.dataSize) {
warning("Error reading savegame file");
err = Common::kReadingFailed;
} else {
_bam->loadState(header.version, p);
_grid->loadState(header.version, p);
_logic->loadState(header.version, p);
_sound->loadState(header.version, p);
if (header.dataSize != (uint32)(p - saveData)) {
warning("Corrupted savegame file");
err = Common::kReadingFailed; // FIXME
} else {
_logic->setupRestoredGame();
}
}
delete[] saveData;
delete file;
} else {
err = Common::kReadingFailed;
}
return err;
}
Common::InSaveFile *QueenEngine::readGameStateHeader(int slot, GameStateHeader *gsh) {
char name[20];
makeGameStateName(slot, name);
Common::InSaveFile *file = _saveFileMan->openForLoading(name);
if (file && file->readUint32BE() == MKTAG('S','C','V','M')) {
gsh->version = file->readUint32BE();
gsh->flags = file->readUint32BE();
gsh->dataSize = file->readUint32BE();
file->read(gsh->description, sizeof(gsh->description));
} else {
memset(gsh, 0, sizeof(GameStateHeader));
}
return file;
}
void QueenEngine::makeGameStateName(int slot, char *buf) const {
if (slot == SLOT_LISTPREFIX) {
strcpy(buf, "queen.s??");
} else if (slot == SLOT_AUTOSAVE) {
strcpy(buf, "queen.asd");
} else {
assert(slot >= 0);
sprintf(buf, "queen.s%02d", slot);
}
}
int QueenEngine::getGameStateSlot(const char *filename) const {
int i = -1;
const char *slot = strrchr(filename, '.');
if (slot && (slot[1] == 's' || slot[1] == 'S')) {
i = atoi(slot + 2);
}
return i;
}
void QueenEngine::findGameStateDescriptions(char descriptions[100][32]) {
char prefix[20];
makeGameStateName(SLOT_LISTPREFIX, prefix);
Common::StringArray filenames = _saveFileMan->listSavefiles(prefix);
for (Common::StringArray::const_iterator it = filenames.begin(); it != filenames.end(); ++it) {
int i = getGameStateSlot(it->c_str());
if (i >= 0 && i < SAVESTATE_MAX_NUM) {
GameStateHeader header;
Common::InSaveFile *f = readGameStateHeader(i, &header);
strcpy(descriptions[i], header.description);
delete f;
}
}
}
GUI::Debugger *QueenEngine::getDebugger() {
return _debugger;
}
bool Queen::QueenEngine::hasFeature(EngineFeature f) const {
return
(f == kSupportsRTL) ||
(f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime) ||
(f == kSupportsSubtitleOptions);
}
Common::Error QueenEngine::run() {
initGraphics(GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT);
_resource = new Resource();
_bam = new BamScene(this);
_bankMan = new BankManager(_resource);
_command = new Command(this);
_debugger = new Debugger(this);
_display = new Display(this, _system);
_graphics = new Graphics(this);
_grid = new Grid(this);
_input = new Input(_resource->getLanguage(), _system);
if (_resource->isDemo()) {
_logic = new LogicDemo(this);
} else if (_resource->isInterview()) {
_logic = new LogicInterview(this);
} else {
_logic = new LogicGame(this);
}
_sound = Sound::makeSoundInstance(_mixer, this, _resource->getCompression());
_walk = new Walk(this);
//_talkspeedScale = (MAX_TEXT_SPEED - MIN_TEXT_SPEED) / 255.0;
registerDefaultSettings();
// Setup mixer
syncSoundSettings();
_logic->start();
if (ConfMan.hasKey("save_slot") && canLoadOrSave()) {
loadGameState(ConfMan.getInt("save_slot"));
}
_lastSaveTime = _lastUpdateTime = _system->getMillis();
while (!shouldQuit()) {
if (_logic->newRoom() > 0) {
_logic->update();
_logic->oldRoom(_logic->currentRoom());
_logic->currentRoom(_logic->newRoom());
_logic->changeRoom();
_display->fullscreen(false);
if (_logic->currentRoom() == _logic->newRoom()) {
_logic->newRoom(0);
}
} else if (_logic->joeWalk() == JWM_EXECUTE) {
_logic->joeWalk(JWM_NORMAL);
_command->executeCurrentAction();
} else {
_logic->joeWalk(JWM_NORMAL);
update(true);
}
}
return Common::kNoError;
}
} // End of namespace Queen