From 347de79bb259037e5ed24acf2b7274374ec410a8 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Tue, 8 Dec 2020 19:49:59 -0800 Subject: [PATCH] GLK: COMPREHEND: Partial support for Transylvania v2 --- engines/glk/comprehend/comprehend.cpp | 9 +- engines/glk/comprehend/detection_tables.h | 3 + engines/glk/comprehend/game_data.cpp | 1 + .../comprehend/{game_tr.cpp => game_tr1.cpp} | 22 +- .../glk/comprehend/{game_tr.h => game_tr1.h} | 10 +- engines/glk/comprehend/game_tr2.cpp | 282 ++++++++++++++++++ engines/glk/comprehend/game_tr2.h | 55 ++++ engines/glk/module.mk | 3 +- 8 files changed, 365 insertions(+), 20 deletions(-) rename engines/glk/comprehend/{game_tr.cpp => game_tr1.cpp} (91%) rename engines/glk/comprehend/{game_tr.h => game_tr1.h} (90%) create mode 100644 engines/glk/comprehend/game_tr2.cpp create mode 100644 engines/glk/comprehend/game_tr2.h diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp index 66787734abe..09ad9b2e4f5 100644 --- a/engines/glk/comprehend/comprehend.cpp +++ b/engines/glk/comprehend/comprehend.cpp @@ -28,7 +28,8 @@ #include "glk/comprehend/game_data.h" #include "glk/comprehend/game_oo.h" #include "glk/comprehend/game_tm.h" -#include "glk/comprehend/game_tr.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" @@ -113,8 +114,10 @@ void Comprehend::createGame() { _game = new OOToposGame(); else if (_gameDescription._gameId == "talisman") _game = new TalismanGame(); - else if (_gameDescription._gameId == "transylvania") - _game = new TransylvaniaGame(); + else if (_gameDescription._gameId == "transylvania" && _gameDescription._filename.equalsIgnoreCase("tr.gda")) + _game = new TransylvaniaGame1(); + else if (_gameDescription._gameId == "transylvania" && _gameDescription._filename.equalsIgnoreCase("g0")) + _game = new TransylvaniaGame2(); else error("Unknown game"); } diff --git a/engines/glk/comprehend/detection_tables.h b/engines/glk/comprehend/detection_tables.h index 28d90faf2e1..2364eef4b57 100644 --- a/engines/glk/comprehend/detection_tables.h +++ b/engines/glk/comprehend/detection_tables.h @@ -50,6 +50,9 @@ const ComprehendDetectionEntry COMPREHEND_GAMES[] = { {"talisman", "g0", "35770d4815e610b5252e3fcd9f11def3"}, #endif {"transylvania", "tr.gda", "22e08633eea02ceee49b909dfd982d22"}, +#ifndef RELEASE_BUILD + {"transylvania", "g0", "384cbf0cd50888310fd33574e6baf880"}, +#endif {nullptr, nullptr, nullptr} }; diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp index d155d16a311..1d77a5a4e0b 100644 --- a/engines/glk/comprehend/game_data.cpp +++ b/engines/glk/comprehend/game_data.cpp @@ -551,6 +551,7 @@ void GameData::parse_header(FileBuffer *fb) { _magicWord = (uint16)(-0x5a00 + 0x4); break; + case 0x8bc3: /* Transylvania v2 */ case 0x93f0: /* OO-Topos */ case 0xa429: /* Talisman */ _comprehendVersion = 2; diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr1.cpp similarity index 91% rename from engines/glk/comprehend/game_tr.cpp rename to engines/glk/comprehend/game_tr1.cpp index 818ca14a697..21419c4dbb9 100644 --- a/engines/glk/comprehend/game_tr.cpp +++ b/engines/glk/comprehend/game_tr1.cpp @@ -22,7 +22,7 @@ #include "glk/comprehend/comprehend.h" #include "glk/comprehend/game_data.h" -#include "glk/comprehend/game_tr.h" +#include "glk/comprehend/game_tr1.h" #include "glk/comprehend/pics.h" namespace Glk { @@ -56,11 +56,11 @@ struct TransylvaniaMonster { }; -const TransylvaniaMonster TransylvaniaGame::WEREWOLF = { +const TransylvaniaMonster TransylvaniaGame1::WEREWOLF = { ITEM_WEREWOLF, 7, ROOMFLAG_WEREWOLF, 10, 190 }; -const TransylvaniaMonster TransylvaniaGame::VAMPIRE = { +const TransylvaniaMonster TransylvaniaGame1::VAMPIRE = { ITEM_VAMPIRE, 5, ROOMFLAG_VAMPIRE, 0, 200 }; @@ -69,7 +69,7 @@ static const GameStrings TR_STRINGS = { }; -TransylvaniaGame::TransylvaniaGame() : ComprehendGameV1(), +TransylvaniaGame1::TransylvaniaGame1() : ComprehendGameV1(), _miceReleased(false) { _gameDataFile = "tr.gda"; @@ -91,7 +91,7 @@ TransylvaniaGame::TransylvaniaGame() : ComprehendGameV1(), _gameStrings = &TR_STRINGS; } -bool TransylvaniaGame::updateMonster(const TransylvaniaMonster *monsterInfo) { +bool TransylvaniaGame1::updateMonster(const TransylvaniaMonster *monsterInfo) { Item *monster; Room *room; uint16 turn_count; @@ -126,12 +126,12 @@ bool TransylvaniaGame::updateMonster(const TransylvaniaMonster *monsterInfo) { return true; } -bool TransylvaniaGame::isMonsterInRoom(const TransylvaniaMonster *monsterInfo) { +bool TransylvaniaGame1::isMonsterInRoom(const TransylvaniaMonster *monsterInfo) { Item *monster = get_item(monsterInfo->_object); return monster->_room == _currentRoom; } -int TransylvaniaGame::roomIsSpecial(unsigned room_index, +int TransylvaniaGame1::roomIsSpecial(unsigned room_index, unsigned *roomDescString) { Room *room = &_rooms[room_index]; @@ -144,7 +144,7 @@ int TransylvaniaGame::roomIsSpecial(unsigned room_index, return ROOM_IS_NORMAL; } -void TransylvaniaGame::beforeTurn() { +void TransylvaniaGame1::beforeTurn() { Room *room; if (!isMonsterInRoom(&WEREWOLF) && !isMonsterInRoom(&VAMPIRE)) { @@ -191,7 +191,7 @@ done: ComprehendGameV1::beforeTurn(); } -void TransylvaniaGame::synchronizeSave(Common::Serializer &s) { +void TransylvaniaGame1::synchronizeSave(Common::Serializer &s) { ComprehendGame::synchronizeSave(s); s.syncAsByte(_miceReleased); @@ -200,7 +200,7 @@ void TransylvaniaGame::synchronizeSave(Common::Serializer &s) { get_item(ITEM_VAMPIRE)->_room = 0xff; } -void TransylvaniaGame::handleSpecialOpcode(uint8 operand) { +void TransylvaniaGame1::handleSpecialOpcode(uint8 operand) { switch (operand) { case 1: // Mice have been released @@ -259,7 +259,7 @@ void TransylvaniaGame::handleSpecialOpcode(uint8 operand) { if (g_comprehend->shouldQuit()) return; \ } while (strlen(buffer) == 0) -void TransylvaniaGame::beforeGame() { +void TransylvaniaGame1::beforeGame() { char buffer[128]; g_comprehend->setDisableSaves(true); diff --git a/engines/glk/comprehend/game_tr.h b/engines/glk/comprehend/game_tr1.h similarity index 90% rename from engines/glk/comprehend/game_tr.h rename to engines/glk/comprehend/game_tr1.h index 076d697aa92..3a765965bd7 100644 --- a/engines/glk/comprehend/game_tr.h +++ b/engines/glk/comprehend/game_tr1.h @@ -20,8 +20,8 @@ * */ -#ifndef GLK_COMPREHEND_GAME_TR_H -#define GLK_COMPREHEND_GAME_TR_H +#ifndef GLK_COMPREHEND_GAME_TR1_H +#define GLK_COMPREHEND_GAME_TR1_H #include "glk/comprehend/game_opcodes.h" @@ -30,7 +30,7 @@ namespace Comprehend { struct TransylvaniaMonster; -class TransylvaniaGame : public ComprehendGameV1 { +class TransylvaniaGame1 : public ComprehendGameV1 { private: static const TransylvaniaMonster WEREWOLF; static const TransylvaniaMonster VAMPIRE; @@ -39,8 +39,8 @@ private: bool updateMonster(const TransylvaniaMonster *monsterInfo); bool isMonsterInRoom(const TransylvaniaMonster *monsterInfo); public: - TransylvaniaGame(); - ~TransylvaniaGame() override {} + TransylvaniaGame1(); + ~TransylvaniaGame1() override {} void beforeGame() override; void beforeTurn() override; diff --git a/engines/glk/comprehend/game_tr2.cpp b/engines/glk/comprehend/game_tr2.cpp new file mode 100644 index 00000000000..5f29ca49613 --- /dev/null +++ b/engines/glk/comprehend/game_tr2.cpp @@ -0,0 +1,282 @@ +/* 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 "glk/comprehend/comprehend.h" +#include "glk/comprehend/game_data.h" +#include "glk/comprehend/game_tr2.h" +#include "glk/comprehend/pics.h" + +namespace Glk { +namespace Comprehend { + +enum RoomId { + ROOM_CLAY_HUT = 7, + ROOM_FIELD = 26 +}; + +enum RoomFlag { + ROOMFLAG_FOREST = 1 << 0, + ROOMFLAG_WEREWOLF = 1 << 6, + ROOMFLAG_VAMPIRE = 1 << 7 +}; + +enum ItemId { + ITEM_GOBLIN = 9, + ITEM_SILVER_BULLET = 21, + ITEM_BLACK_CAT = 23, + ITEM_WEREWOLF = 33, + ITEM_VAMPIRE = 38 +}; + +struct TransylvaniaMonster { + uint8 _object; + uint8 _deadFlag; + uint _roomAllowFlag; + uint _minTurnsBefore; + uint _randomness; +}; + + +const TransylvaniaMonster TransylvaniaGame2::WEREWOLF = { + ITEM_WEREWOLF, 7, ROOMFLAG_WEREWOLF, 10, 190 +}; + +const TransylvaniaMonster TransylvaniaGame2::VAMPIRE = { + ITEM_VAMPIRE, 5, ROOMFLAG_VAMPIRE, 0, 200 +}; + +static const GameStrings TR_STRINGS = { + EXTRA_STRING_TABLE(0x8a) +}; + + +TransylvaniaGame2::TransylvaniaGame2() : ComprehendGameV2(), + _miceReleased(false) { + _gameDataFile = "g0"; + + _locationGraphicFiles.push_back("RA"); + _locationGraphicFiles.push_back("RB"); + _locationGraphicFiles.push_back("RC"); + _itemGraphicFiles.push_back("OA"); + _itemGraphicFiles.push_back("OB"); + _itemGraphicFiles.push_back("OC"); + + _titleGraphicFile = "t0"; + _gameStrings = &TR_STRINGS; +} + +bool TransylvaniaGame2::updateMonster(const TransylvaniaMonster *monsterInfo) { + Item *monster; + Room *room; + uint16 turn_count; + + room = &_rooms[_currentRoom]; + if (!(room->_flags & monsterInfo->_roomAllowFlag)) + return false; + + turn_count = _variables[VAR_TURN_COUNT]; + monster = get_item(monsterInfo->_object); + + if (monster->_room == _currentRoom) { + // The monster is in the current room - leave it there + return true; + } + + if (!_flags[monsterInfo->_deadFlag] && + turn_count > monsterInfo->_minTurnsBefore) { + /* + * The monster is alive and allowed to move to the current + * room. Randomly decide whether on not to. If not, move + * it back to limbo. + */ + if (getRandomNumber(255) > monsterInfo->_randomness) { + move_object(monster, _currentRoom); + _variables[15] = turn_count + 1; + } else { + move_object(monster, ROOM_NOWHERE); + } + } + + return true; +} + +bool TransylvaniaGame2::isMonsterInRoom(const TransylvaniaMonster *monsterInfo) { + Item *monster = get_item(monsterInfo->_object); + return monster->_room == _currentRoom; +} + +int TransylvaniaGame2::roomIsSpecial(unsigned room_index, + unsigned *roomDescString) { + Room *room = &_rooms[room_index]; + + if (room_index == 0x28) { + if (roomDescString) + *roomDescString = room->_stringDesc; + return ROOM_IS_DARK; + } + + return ROOM_IS_NORMAL; +} + +void TransylvaniaGame2::beforeTurn() { + Room *room; + + if (!isMonsterInRoom(&WEREWOLF) && !isMonsterInRoom(&VAMPIRE)) { + if (_currentRoom == ROOM_CLAY_HUT) { + Item *blackCat = get_item(ITEM_BLACK_CAT); + if (blackCat->_room == _currentRoom && getRandomNumber(255) >= 128) + console_println(_strings[109].c_str()); + goto done; + + } else if (_currentRoom == ROOM_FIELD) { + Item *goblin = get_item(ITEM_GOBLIN); + if (goblin->_room == _currentRoom) + console_println(_strings[94 + getRandomNumber(3)].c_str()); + goto done; + + } + } + + if (updateMonster(&WEREWOLF) || updateMonster(&VAMPIRE)) + goto done; + + room = &_rooms[_currentRoom]; + if ((room->_flags & ROOMFLAG_FOREST) && (_variables[VAR_TURN_COUNT] % 255) >= 4 + && getRandomNumber(255) < 40) { + int stringNum = _miceReleased ? 108 : 107; + console_println(_strings[stringNum].c_str()); + + // Until the mice are released, an eagle moves player to a random room + if (!_miceReleased) { + // Get new room to get moved to + int roomNum = getRandomNumber(3) + 1; + if (roomNum == _currentRoom) + roomNum += 15; + + move_to(roomNum); + + // Make sure Werwolf and Vampire aren't present + get_item(ITEM_WEREWOLF)->_room = 0xff; + get_item(ITEM_VAMPIRE)->_room = 0xff; + } + } + +done: + ComprehendGameV2::beforeTurn(); +} + +void TransylvaniaGame2::synchronizeSave(Common::Serializer &s) { + ComprehendGame::synchronizeSave(s); + s.syncAsByte(_miceReleased); + + // As a post-step, ensure the vampire and werewolf aren't present + get_item(ITEM_WEREWOLF)->_room = 0xff; + get_item(ITEM_VAMPIRE)->_room = 0xff; +} + +void TransylvaniaGame2::handleSpecialOpcode(uint8 operand) { + switch (operand) { + case 1: + // Mice have been released + _miceReleased = true; + break; + + case 2: + // Gun is fired. Drop the bullet in a random room + get_item(ITEM_SILVER_BULLET)->_room = getRandomNumber(7) + 1; + _updateFlags |= UPDATE_GRAPHICS; + break; + + case 3: + case 4: + // Game over - failure + console_println(_strings2[138].c_str()); + game_restart(); + break; + + case 5: + // Won the game + g_comprehend->showGraphics(); + g_comprehend->drawLocationPicture(40); + game_restart(); + break; + + case 6: + game_save(); + break; + + case 7: + game_restore(); + break; + + case 8: + // Restart game + game_restart(); + break; + + case 9: + // Show the Zin screen in reponse to doing + // 'sing some enchanted evening' in his cabin. + g_comprehend->showGraphics(); + g_comprehend->drawLocationPicture(41); + console_get_key(); + _updateFlags |= UPDATE_GRAPHICS; + break; + + default: + break; + } +} + +#define READ_LINE do { \ + g_comprehend->readLine(buffer, sizeof(buffer)); \ + if (g_comprehend->shouldQuit()) return; \ + } while (strlen(buffer) == 0) + +void TransylvaniaGame2::beforeGame() { + char buffer[128]; + g_comprehend->setDisableSaves(true); + + // Draw the title + g_comprehend->drawPicture(TITLE_IMAGE); + + // Print game information + console_println("Story and graphics by Antonio Antiochia."); + console_println("IBM version by Jeffrey A. Jay. Copyright 1987 POLARWARE, Inc."); + g_comprehend->readChar(); + + // Welcome to Transylvania - sign your name + console_println(_strings[0x20].c_str()); + READ_LINE; + + // The player's name is stored in word 0 + _replaceWords[0] = Common::String(buffer); + + // And your next of kin - This isn't stored by the game + console_println(_strings[0x21].c_str()); + READ_LINE; + + g_comprehend->setDisableSaves(false); +} + +} // namespace Comprehend +} // namespace Glk diff --git a/engines/glk/comprehend/game_tr2.h b/engines/glk/comprehend/game_tr2.h new file mode 100644 index 00000000000..309d7551de0 --- /dev/null +++ b/engines/glk/comprehend/game_tr2.h @@ -0,0 +1,55 @@ +/* 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. + * + */ + +#ifndef GLK_COMPREHEND_GAME_TR2_H +#define GLK_COMPREHEND_GAME_TR2_H + +#include "glk/comprehend/game_opcodes.h" + +namespace Glk { +namespace Comprehend { + +struct TransylvaniaMonster; + +class TransylvaniaGame2 : public ComprehendGameV2 { +private: + static const TransylvaniaMonster WEREWOLF; + static const TransylvaniaMonster VAMPIRE; + bool _miceReleased; + + bool updateMonster(const TransylvaniaMonster *monsterInfo); + bool isMonsterInRoom(const TransylvaniaMonster *monsterInfo); +public: + TransylvaniaGame2(); + ~TransylvaniaGame2() override {} + + void beforeGame() override; + void beforeTurn() override; + void synchronizeSave(Common::Serializer &s) override; + int roomIsSpecial(unsigned room_index, unsigned *roomDescString) override; + void handleSpecialOpcode(uint8 operand) override; +}; + +} // namespace Comprehend +} // namespace Glk + +#endif diff --git a/engines/glk/module.mk b/engines/glk/module.mk index 56c538c3694..cab4fac4aa0 100644 --- a/engines/glk/module.mk +++ b/engines/glk/module.mk @@ -174,7 +174,8 @@ MODULE_OBJS := \ comprehend/game_oo.o \ comprehend/game_opcodes.o \ comprehend/game_tm.o \ - comprehend/game_tr.o \ + comprehend/game_tr1.o \ + comprehend/game_tr2.o \ comprehend/pics.o \ glulx/accel.o \ glulx/exec.o \