diff --git a/devtools/create_mm/files/mm1/strings_en.yml b/devtools/create_mm/files/mm1/strings_en.yml index 8e023f56e69..44588866149 100644 --- a/devtools/create_mm/files/mm1/strings_en.yml +++ b/devtools/create_mm/files/mm1/strings_en.yml @@ -1301,3 +1301,23 @@ maps: door: "A GOLDEN DOOR REPELS YOU!" alamar1: "SUSPENDED IN A FORCEFIELD IS THE BODY\nOF A MAN ENCLOSED IN AN IRON SUIT.\nTELEPATHIC COMMUNICATION:""I AM THE TRUE\nKING ALAMAR, IMPRISONED BY A DEMONIC\nALIEN BEING! CONFRONT HIM WITH THIS EYE\nOF GOROS AND YOU SHALL SEE HIS TRUE\nSELF." alamar2: "THE FATE OF THE REALM IS AT STAKE.""" + + map35: + exit: "EXIT CASTLE, (Y/N)?" + guards: "CASTLE GUARDS EXCLAIM\n""NO MERCHANTS PASS! BEGONE PEASANTS.""" + quests: + 0: "FIND THE ANCIENT RUINS IN THE\nQUIVERING FOREST" + 1: "VISIT BLITHES PEAK, AND REPORT" + 2: "THE PEOPLE OF THE DESERT HAVE MUCH TO\nTRADE,BRING ME A SAMPLE OF THEIR GOODS" + 3: "FIND THE SHRINE OF OKZAR IN THE\nCAVES BELOW DUSK" + 4: "FIND THE FABLED FOUNTAIN IN DRAGADUNE" + 5: "SOLVE THE RIDDLE OF THE RUBY" + 6: "DEFEAT THE STRONGHOLD\nIN THE ENCHANTED FOREST" + inspectron1: "LORD INSPECTRON SPEAKS:\n" + inspectron2: """YOUR SERVICES ARE NEEDED!"" ACCEPT (Y/N)?" + inspectron3: """RETURN NOT UNTIL THY QUEST IS COMPLETE""" + inspectron4: """SORRY, BUT SINCE YOU ARE CURRENTLY\nQUESTED, I CAN'T ENGAGE YOUR SERVICES.""" + inspectron5: "WELL DONE, QUEST COMPLETE! +%d EXP" + message: "ETCHED IN SILVER, MESSAGE A READS:\nATIS-19-31UD54AEUPI1" + slide: "A SLIDE!" + vault: "EMPTY VAULT, ALARM!" diff --git a/engines/mm/mm1/data/character.h b/engines/mm/mm1/data/character.h index 3602c402da4..1b918957399 100644 --- a/engines/mm/mm1/data/character.h +++ b/engines/mm/mm1/data/character.h @@ -107,7 +107,11 @@ enum CharFlags5 { CHARFLAG5_1 = 1, CHARFLAG5_2 = 2, CHARFLAG5_4 = 4, - CHARFLAG5_8 = 8 + CHARFLAG5_8 = 8, + CHARFLAG5_10 = 0x10, + CHARFLAG5_20 = 0x20, + CHARFLAG5_40 = 0x40, + CHARFLAG5_80 = 0x80 }; enum CharFlags7 { diff --git a/engines/mm/mm1/data/items.h b/engines/mm/mm1/data/items.h index 92fabf97d45..cac89e6e726 100644 --- a/engines/mm/mm1/data/items.h +++ b/engines/mm/mm1/data/items.h @@ -34,6 +34,7 @@ namespace MM1 { enum ItemId { VELLUM_SCROLL_ID = 231, RUBY_WHISTLE_ID = 232, + MERCHANTS_PASS_ID = 234, CORAL_KEY_ID = 236, BRONZE_KEY_ID = 237, SILVER_KEY_ID = 238, diff --git a/engines/mm/mm1/maps/map.cpp b/engines/mm/mm1/maps/map.cpp index 29c5580dca0..b7404b70f9b 100644 --- a/engines/mm/mm1/maps/map.cpp +++ b/engines/mm/mm1/maps/map.cpp @@ -108,6 +108,10 @@ void Map::updateGame() { g_events->send("Game", GameMessage("UPDATE")); } +void Map::redrawGame() { + g_events->findView("Game")->redraw(); +} + } // namespace Maps } // namespace MM1 } // namespace MM diff --git a/engines/mm/mm1/maps/map.h b/engines/mm/mm1/maps/map.h index 91d7599e0d2..725f9af4f1b 100644 --- a/engines/mm/mm1/maps/map.h +++ b/engines/mm/mm1/maps/map.h @@ -187,6 +187,11 @@ public: * Updates the game display */ static void updateGame(); + + /** + * Redraw the game display + */ + static void redrawGame(); }; } // namespace Maps diff --git a/engines/mm/mm1/maps/map18.cpp b/engines/mm/mm1/maps/map18.cpp index e9458c6415d..4f45f5742f0 100644 --- a/engines/mm/mm1/maps/map18.cpp +++ b/engines/mm/mm1/maps/map18.cpp @@ -71,7 +71,7 @@ void Map18::special01() { _data[VAL1] = 0; } else { - g_events->findView("Game")->redraw(); + redrawGame(); send(SoundMessage( STRING["maps.map18.blackridge_south"], [](const Common::KeyState &ks) { @@ -97,7 +97,7 @@ void Map18::special02() { _data[VAL2] = 0; } else { - g_events->findView("Game")->redraw(); + redrawGame(); send(SoundMessage( STRING["maps.map18.blackridge_north"], [](const Common::KeyState &ks) { diff --git a/engines/mm/mm1/maps/map35.cpp b/engines/mm/mm1/maps/map35.cpp index f246850eb2f..06443cd9b73 100644 --- a/engines/mm/mm1/maps/map35.cpp +++ b/engines/mm/mm1/maps/map35.cpp @@ -29,6 +29,17 @@ namespace MM { namespace MM1 { namespace Maps { +#define VAL1 29 +#define VAL2 47 + +static const byte MATCH_ITEMS[7] = { + 0, 0,241, 0, 0, 0, 0 +}; +static const byte MATCH_FLAGS[7] = { + CHARFLAG5_1, CHARFLAG5_2, CHARFLAG5_4, CHARFLAG5_8, + CHARFLAG5_10, CHARFLAG5_20, CHARFLAG5_40 +}; + void Map35::special() { // Scan for special actions on the map cell for (uint i = 0; i < 11; ++i) { @@ -55,27 +66,109 @@ void Map35::special00() { } void Map35::special01() { + send(SoundMessage( + STRING["maps.map35.exit"], + []() { + g_maps->_mapPos = Common::Point(14, 10); + g_maps->changeMap(0xa00, 2); + } + )); } void Map35::special02() { + send(SoundMessage(STRING["maps.map35.slide"])); + g_maps->_mapPos = Common::Point(14, 9); + g_maps->changeMap(0xa00, 2); } void Map35::special03() { + send(SoundMessage(STRING["maps.map35.message"])); } void Map35::special04() { + if (!g_globals->_party.hasItem(MERCHANTS_PASS_ID)) { + send(SoundMessage(STRING["maps.map35.merchants"])); + g_maps->_mapPos.y++; + updateGame(); + } } void Map35::special05() { + updateFlags(); + warning("TODO: drawMonster"); + g_events->addView("Inspectron"); } void Map35::special06() { + g_maps->clearSpecial(); + g_globals->_treasure[8] = 30; + g_events->addAction(KEYBIND_SEARCH); } void Map35::special07() { + send(SoundMessage(STRING["maps.map35.vault"])); + _data[VAL1] = 30; + _data[VAL2] = 7; } void Map35::special09() { + g_maps->clearSpecial(); + g_globals->_treasure[8] = 50; + special07(); +} + +void Map35::updateFlags() { + for (uint i = 0; i < g_globals->_party.size(); ++i) { + Character &c = g_globals->_party[i]; + int counte = c._equipped.size(); + int count = counte + c._backpack.size(); + for (int itemIdx = 0; itemIdx < count; ++itemIdx) { + byte itemId = (itemIdx < counte) ? + c._equipped[itemIdx]._id : c._backpack[itemIdx - counte]._id; + + // Scan list of items to match against + for (int arrIdx = 0; arrIdx < 7; ++arrIdx) { + if (itemId == MATCH_ITEMS[arrIdx]) { + c._flags[5] |= MATCH_FLAGS[arrIdx]; + break; + } + } + } + } +} + +void Map35::acceptQuest() { + Character &leader = g_globals->_party[0]; + byte flags = leader._flags[8]; + + // Find quest that hasn't been done yet + int questNum; + for (questNum = 8; flags && questNum < 15; ++questNum, flags >>= 1) { + if (!(flags & 1)) + break; + } + if (questNum == 15) { + for (uint i = 0; i < g_globals->_party.size(); ++i) { + Character &c = g_globals->_party[i]; + c._flags[8] = CHARFLAG8_80; + c._flags[5] = CHARFLAG5_80; + } + } + + // Assign the quest to all party characters + for (uint i = 0; i < g_globals->_party.size(); ++i) { + Character &c = g_globals->_party[i]; + c._quest = questNum; + } + + // Draw the scene + g_maps->_mapPos.y++; + redrawGame(); +} + +bool Map35::matchQuest(Common::String &line) { + // TODO + return false; } } // namespace Maps diff --git a/engines/mm/mm1/maps/map35.h b/engines/mm/mm1/maps/map35.h index 1064706fe39..8eeb634d80c 100644 --- a/engines/mm/mm1/maps/map35.h +++ b/engines/mm/mm1/maps/map35.h @@ -40,6 +40,7 @@ private: void special06(); void special07(); void special09(); + void updateFlags(); const SpecialFn SPECIAL_FN[11] = { &Map35::special00, @@ -61,6 +62,17 @@ public: * Handles all special stuff that happens on the map */ void special() override; + + /** + * Accepts a quest from Inspectron + */ + void acceptQuest(); + + /** + * Does a check for the party's current quest is one + * of Inspectron's, and if it's complete + */ + bool matchQuest(Common::String &line); }; } // namespace Maps diff --git a/engines/mm/mm1/maps/map_desert.cpp b/engines/mm/mm1/maps/map_desert.cpp index 7ec410cfc35..91e4c83d7d8 100644 --- a/engines/mm/mm1/maps/map_desert.cpp +++ b/engines/mm/mm1/maps/map_desert.cpp @@ -29,8 +29,6 @@ namespace MM1 { namespace Maps { void MapDesert::desert() { - Game::Encounter &enc = g_globals->_encounters; - SoundMessage msg; msg._lines.push_back(Line(0, 1, STRING["maps.desert.its_hot"])); diff --git a/engines/mm/mm1/views/dialogs.h b/engines/mm/mm1/views/dialogs.h index fda980c2dcf..11b38948ef2 100644 --- a/engines/mm/mm1/views/dialogs.h +++ b/engines/mm/mm1/views/dialogs.h @@ -47,6 +47,7 @@ #include "mm/mm1/views/maps/arrested.h" #include "mm/mm1/views/maps/chess.h" #include "mm/mm1/views/maps/ice_princess.h" +#include "mm/mm1/views/maps/inspectron.h" #include "mm/mm1/views/maps/lion.h" #include "mm/mm1/views/maps/prisoners.h" #include "mm/mm1/views/maps/resistances.h" @@ -96,6 +97,7 @@ private: Views::Maps::DemonPrisoner _demonPrisoner; Views::Maps::ManPrisoner _manPrisoner; Views::Maps::IcePrincess _icePrincess; + Views::Maps::Inspectron _inspectron; Views::Maps::Lion _lion; Views::Maps::Resistances _resistances; Views::Maps::Trivia _trivia; diff --git a/engines/mm/mm1/views/maps/inspectron.cpp b/engines/mm/mm1/views/maps/inspectron.cpp new file mode 100644 index 00000000000..40e4416f717 --- /dev/null +++ b/engines/mm/mm1/views/maps/inspectron.cpp @@ -0,0 +1,97 @@ +/* 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 . + * + */ + +#include "mm/mm1/views/maps/inspectron.h" +#include "mm/mm1/maps/map35.h" +#include "mm/mm1/globals.h" + +namespace MM { +namespace MM1 { +namespace Views { +namespace Maps { + +#define VAL1 123 +#define ANSWER_OFFSET 167 + +Inspectron::Inspectron() : TextView("Inspectron") { + _bounds = getLineBounds(20, 24); +} + +bool Inspectron::msgFocus(const FocusMessage &msg) { + _canAccept = !g_globals->_party[0]._quest; + return TextView::msgFocus(msg); +} + +void Inspectron::draw() { + MM1::Maps::Map35 &map = *static_cast(g_maps->_currentMap); + clearSurface(); + + if (_canAccept) { + send(SoundMessage( + 0, 1, STRING["maps.map35.inspectron1"], + 0, 2, STRING["maps.map35.inspectron2"] + )); + } else { + int questNum = g_globals->_party[0]._quest; + Common::String line; + + if (questNum < 8 || questNum > 14 || !map.matchQuest(line)) + line = STRING["maps.map35.inspectron4"]; + + g_maps->_mapPos.y++; + map.redrawGame(); + + clearSurface(); + send(SoundMessage( + 0, 1, STRING["maps.map35.inspectron1"], + 0, 2, line + )); + close(); + } +} + +bool Inspectron::msgKeypress(const KeypressMessage &msg) { + MM1::Maps::Map35 &map = *static_cast(g_maps->_currentMap); + + if (_canAccept) { + if (msg.keycode == Common::KEYCODE_y) { + map.acceptQuest(); + + clearSurface(); + writeString(0, 1, STRING["maps.map35.inspectron1"]); + writeString(0, 2, STRING[Common::String::format( + "maps.map35.quests.%d", + g_globals->_party[0]._quest)]); + close(); + + } else if (msg.keycode == Common::KEYCODE_n) { + close(); + map.redrawGame(); + } + } + + return true; +} + +} // namespace Maps +} // namespace Views +} // namespace MM1 +} // namespace MM diff --git a/engines/mm/mm1/views/maps/inspectron.h b/engines/mm/mm1/views/maps/inspectron.h new file mode 100644 index 00000000000..257d863e691 --- /dev/null +++ b/engines/mm/mm1/views/maps/inspectron.h @@ -0,0 +1,49 @@ +/* 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 . + * + */ + +#ifndef MM1_VIEWS_MAPS_INSPECTRON_H +#define MM1_VIEWS_MAPS_INSPECTRON_H + +#include "mm/mm1/views/text_view.h" + +namespace MM { +namespace MM1 { +namespace Views { +namespace Maps { + +class Inspectron : public TextView { +private: + bool _canAccept; +public: + Inspectron(); + virtual ~Inspectron() {} + + bool msgFocus(const FocusMessage &msg) override; + void draw() override; + bool msgKeypress(const KeypressMessage &msg) override; +}; + +} // namespace Maps +} // namespace Views +} // namespace MM1 +} // namespace MM + +#endif diff --git a/engines/mm/module.mk b/engines/mm/module.mk index a4d003f0ae4..f173c5e38cd 100644 --- a/engines/mm/module.mk +++ b/engines/mm/module.mk @@ -58,6 +58,7 @@ MODULE_OBJS := \ mm1/views/maps/giant.o \ mm1/views/maps/gypsy.o \ mm1/views/maps/ice_princess.o \ + mm1/views/maps/inspectron.o \ mm1/views/maps/lion.o \ mm1/views/maps/prisoners.o \ mm1/views/maps/resistances.o \