/* 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/search.h" #include "mm/mm1/views/trap.h" #include "mm/mm1/globals.h" #include "mm/mm1/sound.h" namespace MM { namespace MM1 { namespace Views { Search::Search() : TextView("Search") { _bounds = getLineBounds(20, 24); } bool Search::msgGame(const GameMessage &msg) { if (msg._name != "SHOW") return false; bool hasStuff = g_globals->_treasure.present(); if (hasStuff) { // Focus view to show what was found open(); } else { // Otherwise send an info message to say nothing was found Common::String line = STRING["dialogs.search.search"] + STRING["dialogs.search.nothing"]; send(InfoMessage(0, 1, line)); } return true; } bool Search::msgFocus(const FocusMessage &msg) { _bounds = getLineBounds(20, 24); _lineNum = 0; if (dynamic_cast(msg._priorView) != nullptr) { // Returning from trap display if (g_globals->_party.checkPartyDead()) return true; getTreasure(); } else { _mode = INITIAL; } return true; } void Search::draw() { Common::String line; if (_mode != GET_ITEMS) clearSurface(); switch (_mode) { case INITIAL: Sound::sound(SOUND_2); line = STRING["dialogs.search.search"] + STRING["dialogs.search.you_found"]; writeString(0, 1, line); delaySeconds(2); break; case OPTIONS: writeString(1, 1, STRING["dialogs.search.options"]); writeString(20, 1, STRING["dialogs.search.options1"]); writeString(20, 2, STRING["dialogs.search.options2"]); writeString(20, 3, STRING["dialogs.search.options3"]); escToGoBack(0, 3); break; case GET_TREASURE: drawTreasure(); break; case GET_ITEMS: // This may be called up to three times, for each item drawItem(); break; case WHO_WILL_TRY: { line = Common::String::format( STRING["dialogs.misc.who_will_try"].c_str(), '0' + g_globals->_party.size() ); writeString(10, 1, line); break; } default: break; } } bool Search::msgKeypress(const KeypressMessage &msg) { if (endDelay()) return true; switch (_mode) { case INITIAL: endDelay(); break; case OPTIONS: switch (msg.keycode) { case Common::KEYCODE_1: openContainer(); break; case Common::KEYCODE_2: findRemoveTrap(); break; case Common::KEYCODE_3: detectMagicTrap(); break; default: break; } break; case RESPONSE: endDelay(); break; case WHO_WILL_TRY: if (msg.keycode >= Common::KEYCODE_1 && msg.keycode <= (Common::KEYCODE_0 + (int)g_globals->_party.size())) { // Character selected g_globals->_currCharacter = &g_globals->_party[ msg.keycode - Common::KEYCODE_1]; if ((g_globals->_currCharacter->_condition & (BAD_CONDITION | DEAD | STONE | ASLEEP)) != 0) { clearSurface(); writeString(3, 2, STRING["dialogs.search.check_condition"]); delaySeconds(4); } else { switch (_optionMode) { case OMODE_OPEN: openContainer2(); break; case OMODE_REMOVE_TRAP: findRemoveTrap2(); break; case OMODE_DETECT: detectMagicTrap2(); break; } } } break; case GET_TREASURE: break; default: break; } return true; } bool Search::msgAction(const ActionMessage &msg) { if (endDelay()) return true; if (msg._action == KEYBIND_ESCAPE) { switch (_mode) { case OPTIONS: close(); break; case WHO_WILL_TRY: _mode = OPTIONS; draw(); break; default: break; } return true; } return true; } void Search::timeout() { switch (_mode) { case INITIAL: { Maps::Map &map = *g_maps->_currentMap; _val1 = MIN(g_globals->_treasure._container * 8 + map[Maps::MAP_TRAP_THRESHOLD], 255); if (!g_globals->_treasure._trapType) { g_globals->_treasure._trapType = (getRandomNumber(100) < _val1) ? 1 : 2; } // Show the name of the container type in the game view send("View", HeaderMessage( STRING[Common::String::format("dialogs.search.containers.%d", g_globals->_treasure._container)] )); // Display a graphic for the container type int gfxNum = g_globals->_treasure._container < WOODEN_BOX ? 4 : 2; send("View", DrawGraphicMessage(gfxNum + 65)); _mode = OPTIONS; draw(); break; } case RESPONSE: _mode = OPTIONS; draw(); break; case WHO_WILL_TRY: draw(); break; case GET_TREASURE: _mode = GET_ITEMS; draw(); break; case GET_ITEMS: draw(); break; case GET_ITEMS_DONE: close(); break; default: break; } } void Search::openContainer() { _optionMode = OMODE_OPEN; if (whoWillTry()) openContainer2(); } void Search::openContainer2() { if (g_globals->_treasure._trapType == 1) { Maps::Map &map = *g_maps->_currentMap; int thresold = map[Maps::MAP_TRAP_THRESHOLD] + g_globals->_treasure._container; if (getRandomNumber(thresold + 5) < thresold) { g_events->send("Trap", GameMessage("TRAP")); return; } } getTreasure(); } void Search::findRemoveTrap() { _optionMode = OMODE_REMOVE_TRAP; if (whoWillTry()) findRemoveTrap2(); } void Search::findRemoveTrap2() { Character &c = *g_globals->_currCharacter; if (g_globals->_treasure._trapType == 1) { byte val = c._trapCtr; if (getRandomNumber(val >= 100 ? val + 5 : 100) >= val) { // Triggered a trap g_events->send("Trap", GameMessage("TRAP")); return; } } } void Search::detectMagicTrap() { _optionMode = OMODE_DETECT; if (whoWillTry()) detectMagicTrap2(); } void Search::detectMagicTrap2() { Character &c = *g_globals->_currCharacter; _mode = RESPONSE; if (c._class == PALADIN || c._class == CLERIC) { Sound::sound(SOUND_2); clearSurface(); writeString(6, 2, STRING["dialogs.search.bad_class"]); delaySeconds(4); } else if (c._sp == 0) { Sound::sound(SOUND_2); clearSurface(); writeString(6, 2, STRING["dialogs.search.no_sp"]); delaySeconds(4); } else { c._sp._current--; char magic = g_globals->_treasure.hasItems() || g_globals->_treasure.getGems() ? 'Y' : 'N'; char trapped = g_globals->_treasure._trapType == 1 ? 'Y' : 'N'; clearSurface(); writeString(5, 1, Common::String::format( STRING["dialogs.search.magic_trap"].c_str(), magic, trapped)); delaySeconds(8); } } bool Search::whoWillTry() { if (g_globals->_party.size() == 1) { g_globals->_currCharacter = &g_globals->_party[0]; return true; } else { // Switch to mode to ask which character to use _mode = WHO_WILL_TRY; draw(); return false; } } void Search::getTreasure() { _mode = GET_TREASURE; _bounds = getLineBounds(17, 24); // Display a graphic for the container type int gfxNum = g_globals->_treasure._container < WOODEN_BOX ? 3 : 1; send("View", DrawGraphicMessage(gfxNum + 65)); redraw(); } void Search::drawTreasure() { writeString(15, 0, STRING["dialogs.search.it_opens"]); // Split up the gold across the party uint32 goldPerPerson = g_globals->_treasure.getGold() / g_globals->_party.size(); g_globals->_treasure.setGold(0); for (uint i = 0; i < g_globals->_party.size(); ++i) { Character &c = g_globals->_party[i]; uint32 newGold = c._gold + goldPerPerson; if (newGold < c._gold) // As unlikely as it is to overflow 32-bits newGold = 0xffffffff; c._gold = newGold; } writeString(0, 2, Common::String::format( STRING["dialogs.search.each_share"].c_str(), goldPerPerson)); g_globals->_treasure.setGold(0); // Assign any gems to a random person int gems = g_globals->_treasure.getGems(); g_globals->_treasure.setGems(0); _lineNum = 3; if (gems) { // Choose a random recipient uint charNum = getRandomNumber(g_globals->_party.size()) - 1; Character &c = g_globals->_party[charNum]; writeString(0, _lineNum++, Common::String::format( STRING["dialogs.search.found_gems"].c_str(), c._name, gems)); c._gems = MIN((int)c._gems + gems, 0xffff); } Sound::sound2(SOUND_5); delaySeconds(2); } void Search::drawItem() { Treasure &treasure = g_globals->_treasure; int itemId = treasure.removeItem(); _lineNum = 0; // Iterate through any treasure items if (itemId != 0) { // Find a person with free backpack space for the item for (uint i = 0; i < g_globals->_party.size(); ++i) { Character &c = g_globals->_party[i]; // Check if character has backpack space if (c._backpack.full()) continue; Item *item = g_globals->_items.getItem(itemId); c._backpack.add(itemId, item->_maxCharges); // Add line for found item writeString(0, _lineNum++, Common::String::format( STRING["dialogs.search.found_item"].c_str(), c._name, item->_name.c_str() )); if (treasure.hasItems()) { delaySeconds(2); return; } else { // Finished final item, so go down below to switch to items done break; } } } // At this point we've either displayed the up to 3 item // lines (in addition to gold and/or gems), or the party's // backpacks were completely full up. Wait for 7 seconds _mode = GET_ITEMS_DONE; delaySeconds(7); } } // namespace Views } // namespace MM1 } // namespace MM