PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/engines/queen/queen.cpp

http://github.com/scummvm/scummvm
C++ | 384 lines | 301 code | 50 blank | 33 comment | 71 complexity | 9b63f6a1ac2f5f25c2032616c02a3d45 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0
  1. /* ScummVM - Graphic Adventure Engine
  2. *
  3. * ScummVM is the legal property of its developers, whose names
  4. * are too numerous to list here. Please refer to the COPYRIGHT
  5. * file distributed with this source distribution.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. *
  21. */
  22. #include "base/plugins.h"
  23. #include "common/config-manager.h"
  24. #include "common/events.h"
  25. #include "common/file.h"
  26. #include "common/fs.h"
  27. #include "common/savefile.h"
  28. #include "common/system.h"
  29. #include "common/textconsole.h"
  30. #include "engines/util.h"
  31. #include "queen/queen.h"
  32. #include "queen/bankman.h"
  33. #include "queen/command.h"
  34. #include "queen/cutaway.h"
  35. #include "queen/debug.h"
  36. #include "queen/display.h"
  37. #include "queen/graphics.h"
  38. #include "queen/grid.h"
  39. #include "queen/input.h"
  40. #include "queen/logic.h"
  41. #include "queen/resource.h"
  42. #include "queen/sound.h"
  43. #include "queen/talk.h"
  44. #include "queen/walk.h"
  45. namespace Queen {
  46. QueenEngine::QueenEngine(OSystem *syst)
  47. : Engine(syst), _bam(nullptr), _bankMan(nullptr), _command(nullptr), _debugger(nullptr),
  48. _display(nullptr), _graphics(nullptr), _grid(nullptr), _input(nullptr), _logic(nullptr),
  49. _sound(nullptr), _resource(nullptr), _walk(nullptr), _gameStarted(false),
  50. randomizer("queen") {
  51. }
  52. QueenEngine::~QueenEngine() {
  53. delete _bam;
  54. delete _resource;
  55. delete _bankMan;
  56. delete _command;
  57. delete _display;
  58. delete _graphics;
  59. delete _grid;
  60. delete _input;
  61. delete _logic;
  62. delete _sound;
  63. delete _walk;
  64. //_debugger is deleted by Engine
  65. }
  66. void QueenEngine::registerDefaultSettings() {
  67. ConfMan.registerDefault("talkspeed", Logic::DEFAULT_TALK_SPEED);
  68. ConfMan.registerDefault("subtitles", true);
  69. _subtitles = true;
  70. }
  71. void QueenEngine::checkOptionSettings() {
  72. // check talkspeed value
  73. if (_talkSpeed < MIN_TEXT_SPEED) {
  74. _talkSpeed = MIN_TEXT_SPEED;
  75. } else if (_talkSpeed > MAX_TEXT_SPEED) {
  76. _talkSpeed = MAX_TEXT_SPEED;
  77. }
  78. // demo and interview versions don't have speech at all
  79. if (_sound->speechOn() && (_resource->isDemo() || _resource->isInterview())) {
  80. _sound->speechToggle(false);
  81. }
  82. // ensure text is always on when voice is off
  83. if (!_sound->speechOn()) {
  84. _subtitles = true;
  85. }
  86. }
  87. void QueenEngine::syncSoundSettings() {
  88. Engine::syncSoundSettings();
  89. readOptionSettings();
  90. }
  91. void QueenEngine::readOptionSettings() {
  92. bool mute = false;
  93. if (ConfMan.hasKey("mute"))
  94. mute = ConfMan.getBool("mute");
  95. _sound->setVolume(ConfMan.getInt("music_volume"));
  96. _sound->musicToggle(!(mute || ConfMan.getBool("music_mute")));
  97. _sound->sfxToggle(!(mute || ConfMan.getBool("sfx_mute")));
  98. _sound->speechToggle(!(mute || ConfMan.getBool("speech_mute")));
  99. _talkSpeed = (ConfMan.getInt("talkspeed") * (MAX_TEXT_SPEED - MIN_TEXT_SPEED) + 255 / 2) / 255 + MIN_TEXT_SPEED;
  100. _subtitles = ConfMan.getBool("subtitles");
  101. checkOptionSettings();
  102. }
  103. void QueenEngine::writeOptionSettings() {
  104. ConfMan.setInt("music_volume", _sound->getVolume());
  105. ConfMan.setBool("music_mute", !_sound->musicOn());
  106. ConfMan.setBool("sfx_mute", !_sound->sfxOn());
  107. ConfMan.setInt("talkspeed", ((_talkSpeed - MIN_TEXT_SPEED) * 255 + (MAX_TEXT_SPEED - MIN_TEXT_SPEED) / 2) / (MAX_TEXT_SPEED - MIN_TEXT_SPEED));
  108. ConfMan.setBool("speech_mute", !_sound->speechOn());
  109. ConfMan.setBool("subtitles", _subtitles);
  110. ConfMan.flushToDisk();
  111. }
  112. void QueenEngine::update(bool checkPlayerInput) {
  113. _graphics->update(_logic->currentRoom());
  114. _logic->update();
  115. int frameDelay = (_lastUpdateTime + Input::DELAY_NORMAL - _system->getMillis());
  116. if (frameDelay <= 0) {
  117. frameDelay = 1;
  118. }
  119. _input->delay(frameDelay);
  120. _lastUpdateTime = _system->getMillis();
  121. if (!_resource->isInterview()) {
  122. _display->palCustomScroll(_logic->currentRoom());
  123. }
  124. BobSlot *joe = _graphics->bob(0);
  125. _display->update(joe->active, joe->x, joe->y);
  126. _input->checkKeys();
  127. if (canLoadOrSave()) {
  128. if (_input->quickSave()) {
  129. _input->quickSaveReset();
  130. saveGameState(SLOT_QUICKSAVE, "Quicksave");
  131. }
  132. if (_input->quickLoad()) {
  133. _input->quickLoadReset();
  134. loadGameState(SLOT_QUICKSAVE);
  135. }
  136. }
  137. if (!_input->cutawayRunning()) {
  138. if (checkPlayerInput) {
  139. _command->updatePlayer();
  140. }
  141. if (_input->idleTime() >= Input::DELAY_SCREEN_BLANKER) {
  142. _display->blankScreen();
  143. }
  144. }
  145. _sound->updateMusic();
  146. }
  147. bool QueenEngine::canLoadOrSave() const {
  148. return !_input->cutawayRunning() && !(_resource->isDemo() || _resource->isInterview()) && _gameStarted;
  149. }
  150. bool QueenEngine::canLoadGameStateCurrently() {
  151. return canLoadOrSave();
  152. }
  153. bool QueenEngine::canSaveGameStateCurrently() {
  154. return canLoadOrSave();
  155. }
  156. Common::Error QueenEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
  157. debug(3, "Saving game to slot %d", slot);
  158. char name[20];
  159. Common::Error err = Common::kNoError;
  160. makeGameStateName(slot, name);
  161. Common::OutSaveFile *file = _saveFileMan->openForSaving(name);
  162. if (file) {
  163. // save data
  164. byte *saveData = new byte[SAVESTATE_MAX_SIZE];
  165. byte *p = saveData;
  166. _bam->saveState(p);
  167. _grid->saveState(p);
  168. _logic->saveState(p);
  169. _sound->saveState(p);
  170. uint32 dataSize = p - saveData;
  171. assert(dataSize < SAVESTATE_MAX_SIZE);
  172. // write header
  173. file->writeUint32BE('SCVM');
  174. file->writeUint32BE(SAVESTATE_CUR_VER);
  175. file->writeUint32BE(0);
  176. file->writeUint32BE(dataSize);
  177. char description[32];
  178. Common::strlcpy(description, desc.c_str(), sizeof(description));
  179. file->write(description, sizeof(description));
  180. // write save data
  181. file->write(saveData, dataSize);
  182. file->finalize();
  183. // check for errors
  184. if (file->err()) {
  185. warning("Can't write file '%s'. (Disk full?)", name);
  186. err = Common::kWritingFailed;
  187. }
  188. delete[] saveData;
  189. delete file;
  190. } else {
  191. warning("Can't create file '%s', game not saved", name);
  192. err = Common::kCreatingFileFailed;
  193. }
  194. return err;
  195. }
  196. Common::Error QueenEngine::loadGameState(int slot) {
  197. debug(3, "Loading game from slot %d", slot);
  198. Common::Error err = Common::kNoError;
  199. GameStateHeader header;
  200. Common::InSaveFile *file = readGameStateHeader(slot, &header);
  201. if (file && header.dataSize != 0) {
  202. byte *saveData = new byte[header.dataSize];
  203. byte *p = saveData;
  204. if (file->read(saveData, header.dataSize) != header.dataSize) {
  205. warning("Error reading savegame file");
  206. err = Common::kReadingFailed;
  207. } else {
  208. _bam->loadState(header.version, p);
  209. _grid->loadState(header.version, p);
  210. _logic->loadState(header.version, p);
  211. _sound->loadState(header.version, p);
  212. if (header.dataSize != (uint32)(p - saveData)) {
  213. warning("Corrupted savegame file");
  214. err = Common::kReadingFailed; // FIXME
  215. } else {
  216. _logic->setupRestoredGame();
  217. }
  218. }
  219. delete[] saveData;
  220. delete file;
  221. } else {
  222. err = Common::kReadingFailed;
  223. }
  224. return err;
  225. }
  226. Common::InSaveFile *QueenEngine::readGameStateHeader(int slot, GameStateHeader *gsh) {
  227. char name[20];
  228. makeGameStateName(slot, name);
  229. Common::InSaveFile *file = _saveFileMan->openForLoading(name);
  230. if (file && file->readUint32BE() == MKTAG('S','C','V','M')) {
  231. gsh->version = file->readUint32BE();
  232. gsh->flags = file->readUint32BE();
  233. gsh->dataSize = file->readUint32BE();
  234. file->read(gsh->description, sizeof(gsh->description));
  235. } else {
  236. memset(gsh, 0, sizeof(GameStateHeader));
  237. }
  238. return file;
  239. }
  240. Common::String QueenEngine::getSaveStateName(int slot) const {
  241. if (slot == SLOT_LISTPREFIX) {
  242. return "queen.s??";
  243. } else if (slot == SLOT_AUTOSAVE) {
  244. slot = getAutosaveSlot();
  245. }
  246. assert(slot >= 0);
  247. return Common::String::format("queen.s%02d", slot);
  248. }
  249. void QueenEngine::makeGameStateName(int slot, char *buf) const {
  250. Common::String name = getSaveStateName(slot);
  251. strcpy(buf, name.c_str());
  252. }
  253. int QueenEngine::getGameStateSlot(const char *filename) const {
  254. int i = -1;
  255. const char *slot = strrchr(filename, '.');
  256. if (slot && (slot[1] == 's' || slot[1] == 'S')) {
  257. i = atoi(slot + 2);
  258. }
  259. return i;
  260. }
  261. void QueenEngine::findGameStateDescriptions(char descriptions[100][32]) {
  262. char prefix[20];
  263. makeGameStateName(SLOT_LISTPREFIX, prefix);
  264. Common::StringArray filenames = _saveFileMan->listSavefiles(prefix);
  265. for (Common::StringArray::const_iterator it = filenames.begin(); it != filenames.end(); ++it) {
  266. int i = getGameStateSlot(it->c_str());
  267. if (i >= 0 && i < SAVESTATE_MAX_NUM) {
  268. GameStateHeader header;
  269. Common::InSaveFile *f = readGameStateHeader(i, &header);
  270. strcpy(descriptions[i], header.description);
  271. delete f;
  272. }
  273. }
  274. }
  275. bool Queen::QueenEngine::hasFeature(EngineFeature f) const {
  276. return
  277. (f == kSupportsRTL) ||
  278. (f == kSupportsLoadingDuringRuntime) ||
  279. (f == kSupportsSavingDuringRuntime) ||
  280. (f == kSupportsSubtitleOptions);
  281. }
  282. Common::Error QueenEngine::run() {
  283. initGraphics(GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT);
  284. _resource = new Resource();
  285. _bam = new BamScene(this);
  286. _bankMan = new BankManager(_resource);
  287. _command = new Command(this);
  288. _debugger = new Debugger(this);
  289. setDebugger(_debugger);
  290. _display = new Display(this, _system);
  291. _graphics = new Graphics(this);
  292. _grid = new Grid(this);
  293. _input = new Input(_resource->getLanguage(), _system);
  294. if (_resource->isDemo()) {
  295. _logic = new LogicDemo(this);
  296. } else if (_resource->isInterview()) {
  297. _logic = new LogicInterview(this);
  298. } else {
  299. _logic = new LogicGame(this);
  300. }
  301. _sound = Sound::makeSoundInstance(_mixer, this, _resource->getCompression());
  302. _walk = new Walk(this);
  303. //_talkspeedScale = (MAX_TEXT_SPEED - MIN_TEXT_SPEED) / 255.0;
  304. registerDefaultSettings();
  305. // Setup mixer
  306. syncSoundSettings();
  307. _logic->start();
  308. if (ConfMan.hasKey("save_slot") && canLoadOrSave()) {
  309. loadGameState(ConfMan.getInt("save_slot"));
  310. }
  311. while (!shouldQuit()) {
  312. if (_logic->newRoom() > 0) {
  313. _logic->update();
  314. _logic->oldRoom(_logic->currentRoom());
  315. _logic->currentRoom(_logic->newRoom());
  316. _logic->changeRoom();
  317. _display->fullscreen(false);
  318. // From this point onwards it is safe to use the load/save
  319. // menu, so consider game to be 'started'
  320. _gameStarted = true;
  321. if (_logic->currentRoom() == _logic->newRoom()) {
  322. _logic->newRoom(0);
  323. }
  324. } else if (_logic->joeWalk() == JWM_EXECUTE) {
  325. _logic->joeWalk(JWM_NORMAL);
  326. _command->executeCurrentAction();
  327. } else {
  328. _logic->joeWalk(JWM_NORMAL);
  329. update(true);
  330. }
  331. }
  332. return Common::kNoError;
  333. }
  334. } // End of namespace Queen