scummvm/engines/glk/comprehend/comprehend.cpp
2022-12-25 16:31:57 +01:00

297 lines
7.8 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 "glk/comprehend/comprehend.h"
#include "glk/comprehend/debugger.h"
#include "glk/comprehend/draw_surface.h"
#include "glk/comprehend/game.h"
#include "glk/comprehend/game_cc.h"
#include "glk/comprehend/game_data.h"
#include "glk/comprehend/game_oo.h"
#include "glk/comprehend/game_tm.h"
#include "glk/comprehend/game_tr1.h"
#include "glk/comprehend/game_tr2.h"
#include "glk/comprehend/pics.h"
#include "glk/quetzal.h"
#include "common/config-manager.h"
#include "common/ustr.h"
#include "engines/util.h"
namespace Glk {
namespace Comprehend {
// Even with no ScummVM scaling, internally we do a 2x scaling to
// render on a 640x480 window, to allow for better looking text
#define SCALE_FACTOR 2
Comprehend *g_comprehend;
Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
_topWindow(nullptr), _bottomWindow(nullptr), _roomDescWindow(nullptr),
_drawSurface(nullptr), _game(nullptr), _pics(nullptr), _saveSlot(-1),
_graphicsEnabled(true), _drawFlags(0), _disableSaves(false) {
g_comprehend = this;
}
Comprehend::~Comprehend() {
delete _drawSurface;
delete _game;
SearchMan.remove("Pics"); // This also deletes it
g_comprehend = nullptr;
}
void Comprehend::initGraphicsMode() {
Graphics::PixelFormat pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
initGraphics(640, 400, &pixelFormat);
}
void Comprehend::createConfiguration() {
GlkAPI::createConfiguration();
switchToWhiteOnBlack();
}
void Comprehend::runGame() {
initialize();
// Lookup game
createGame();
_game->loadGame();
_game->playGame();
deinitialize();
}
void Comprehend::initialize() {
_bottomWindow = (TextBufferWindow *)glk_window_open(nullptr, 0, 0, wintype_TextBuffer, 1);
glk_set_window(_bottomWindow);
showGraphics();
_topWindow->fillRect(0, Rect(0, 0, _topWindow->_w, _topWindow->_h));
// Initialize drawing surface, and the archive that abstracts
// the room and item graphics as as individual files
_drawSurface = new DrawSurface();
_pics = new Pics();
SearchMan.add("Pics", _pics, 99, true);
// Check for savegame to load
_saveSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
}
void Comprehend::deinitialize() {
glk_window_close(_topWindow);
glk_window_close(_bottomWindow);
glk_window_close(_roomDescWindow);
}
void Comprehend::createDebugger() {
setDebugger(new Debugger());
}
void Comprehend::createGame() {
if (_gameDescription._gameId == "crimsoncrown")
_game = new CrimsonCrownGame();
else if (_gameDescription._gameId == "ootopos")
_game = new OOToposGame();
else if (_gameDescription._gameId == "talisman")
_game = new TalismanGame();
else if (_gameDescription._gameId == "transylvania")
_game = new TransylvaniaGame1();
else if (_gameDescription._gameId == "transylvaniav2")
_game = new TransylvaniaGame2();
else
error("Unknown game");
}
void Comprehend::print(const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
Common::String msg = Common::String::vformat(fmt, argp);
va_end(argp);
glk_put_string_stream(glk_window_get_stream(_bottomWindow), msg.c_str());
}
void Comprehend::print_u32_internal(const Common::U32String *fmt, ...) {
Common::U32String outputMsg;
va_list argp;
va_start(argp, fmt);
Common::U32String::vformat(fmt->begin(), fmt->end(), outputMsg, argp);
va_end(argp);
glk_put_string_stream_uni(glk_window_get_stream(_bottomWindow), outputMsg.u32_str());
}
void Comprehend::printRoomDesc(const Common::String &desc) {
if (_roomDescWindow) {
glk_window_clear(_roomDescWindow);
// Get the grid width and do a word wrap
uint width;
glk_window_get_size(_roomDescWindow, &width, nullptr);
Common::String str = desc;
str.wordWrap(width - 2);
str += '\n';
// Display the room description
while (!str.empty()) {
size_t idx = str.findFirstOf('\n');
Common::String line = Common::String::format(" %s", Common::String(str.c_str(), str.c_str() + idx + 1).c_str());
glk_put_string_stream(glk_window_get_stream(_roomDescWindow), line.c_str());
str = Common::String(str.c_str() + idx + 1);
}
}
}
void Comprehend::readLine(char *buffer, size_t maxLen) {
event_t ev;
glk_request_line_event(_bottomWindow, buffer, maxLen - 1, 0);
for (;;) {
glk_select(&ev);
if (ev.type == evtype_Quit) {
glk_cancel_line_event(_bottomWindow, &ev);
return;
} else if (ev.type == evtype_LineInput)
break;
}
buffer[ev.val1] = 0;
debug(1, "\n> %s", buffer);
}
int Comprehend::readChar() {
glk_request_char_event(_bottomWindow);
setDisableSaves(true);
event_t ev;
while (ev.type != evtype_CharInput) {
glk_select(&ev);
if (ev.type == evtype_Quit) {
glk_cancel_char_event(_bottomWindow);
return -1;
}
}
setDisableSaves(false);
return ev.val1;
}
Common::Error Comprehend::readSaveData(Common::SeekableReadStream *rs) {
Common::Serializer s(rs, nullptr);
_game->synchronizeSave(s);
_game->_updateFlags = UPDATE_ALL;
if (isInputLineActive()) {
// Restored game using GMM, so update grpahics and print room description
g_comprehend->print("\n");
_game->update();
g_comprehend->print("> ");
}
return Common::kNoError;
}
Common::Error Comprehend::writeGameData(Common::WriteStream *ws) {
Common::Serializer s(nullptr, ws);
_game->synchronizeSave(s);
return Common::kNoError;
}
bool Comprehend::loadLauncherSavegameIfNeeded() {
if (_saveSlot != -1) {
return loadGameState(_saveSlot).getCode() == Common::kNoError;
}
return false;
}
void Comprehend::drawPicture(uint pictureNum) {
if (_topWindow) {
// Clear the picture cache before each drawing in OO-Topos. Wearing the goggles
// can producing different versions of the same scene, so we can't cache it
if (_gameDescription._gameId == "ootopos")
_pictures->clear();
glk_image_draw_scaled(_topWindow, pictureNum,
20 * SCALE_FACTOR, 0, G_RENDER_WIDTH * SCALE_FACTOR, G_RENDER_HEIGHT * SCALE_FACTOR);
}
}
void Comprehend::drawLocationPicture(int pictureNum, bool clearBg) {
drawPicture(pictureNum + (clearBg ? LOCATIONS_OFFSET : LOCATIONS_NO_BG_OFFSET));
}
void Comprehend::drawItemPicture(int pictureNum) {
drawPicture(pictureNum + ITEMS_OFFSET);
}
void Comprehend::clearScreen(bool isBright) {
drawPicture(isBright ? BRIGHT_ROOM : DARK_ROOM);
}
bool Comprehend::toggleGraphics() {
if (_topWindow) {
// Remove the picture window
glk_window_close(_topWindow);
_topWindow = nullptr;
_graphicsEnabled = false;
// Add the room description window
_roomDescWindow = (TextGridWindow *)glk_window_open(_bottomWindow,
winmethod_Above | winmethod_Fixed, 5, wintype_TextGrid, 1);
return false;
} else {
glk_window_close(_roomDescWindow);
_roomDescWindow = nullptr;
// Create the window again
showGraphics();
return true;
}
}
void Comprehend::showGraphics() {
if (!_topWindow) {
_topWindow = (GraphicsWindow *)glk_window_open(_bottomWindow,
winmethod_Above | winmethod_Fixed,
160 * SCALE_FACTOR, wintype_Graphics, 2);
_graphicsEnabled = true;
}
}
bool Comprehend::isInputLineActive() const {
return _bottomWindow->_lineRequest || _bottomWindow->_lineRequestUni;
}
} // namespace Comprehend
} // namespace Glk