diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk index 561236884f8..05d84b549b7 100644 --- a/engines/ultima/module.mk +++ b/engines/ultima/module.mk @@ -86,6 +86,7 @@ MODULE_OBJS += \ ultima1/spells/prayer.o \ ultima1/spells/spell.o \ ultima1/spells/steal.o \ + ultima1/u1dialogs/buy_sell_dialog.o \ ultima1/u1dialogs/combat.o \ ultima1/u1dialogs/dialog.o \ ultima1/u1dialogs/drop.o \ diff --git a/engines/ultima/ultima1/core/resources.cpp b/engines/ultima/ultima1/core/resources.cpp index 06b357f7f2c..8be99b20e40 100644 --- a/engines/ultima/ultima1/core/resources.cpp +++ b/engines/ultima/ultima1/core/resources.cpp @@ -614,6 +614,8 @@ const char *const SRC_GROCERY_NAMES[8] = { }; const char *const SRC_BUY_SELL = "-Buy, Sell: "; +const char *const SRC_BUY = "-Buy: "; +const char *const SRC_SELL = "-Sell: "; const char *const SRC_NOTHING = "nothing"; const char *const SRC_NONE = "none"; const char *const SRC_NOTHING_HERE = " - nothing here!"; @@ -661,6 +663,15 @@ const char *const SRC_GROCERY_PACKS3 = "wish to purchase?"; const char *const SRC_GROCERY_PACKS_FOOD = "%d packs food"; const char *const SRC_GROCERY_FIND_PACKS = "Thou dost find %d bags of food!"; +const char *const SRC_WITH_KING = " with king"; +const char *const SRC_HE_IS_NOT_HERE = "He is not here!"; +const char *const SRC_HE_REJECTS_OFFER = "He rejects thine offer!"; +const char *const SRC_KING_TEXT[11] = { + "Dost thou offer pence or service: ", "neither", "pence", "service", "How much? ", + "none", "Thou hast not that much!", "In return I give unto thee %u hit points", + "Thou art on a quest for me already!", "Go now and kill a", "Go forth and find a" +}; + /*-------------------------------------------------------------------*/ GameResources::GameResources() : LocalResourceFile("ULTIMA1/DATA") { @@ -737,6 +748,8 @@ GameResources::GameResources(Shared::Resources *resManager) : LocalResourceFile( CAUGHT = SRC_CAUGHT; NONE_WILL_TALK = SRC_NONE_WILL_TALK; BUY_SELL = SRC_BUY_SELL; + BUY = SRC_BUY; + SELL = SRC_SELL; NOTHING = SRC_NOTHING; NONE = SRC_NONE; NOTHING_HERE = SRC_NOTHING_HERE; @@ -784,6 +797,11 @@ GameResources::GameResources(Shared::Resources *resManager) : LocalResourceFile( GROCERY_PACKS3 = SRC_GROCERY_PACKS3; GROCERY_PACKS_FOOD = SRC_GROCERY_PACKS_FOOD; GROCERY_FIND_PACKS = SRC_GROCERY_FIND_PACKS; + + WITH_KING = SRC_WITH_KING; + HE_IS_NOT_HERE = SRC_HE_IS_NOT_HERE; + HE_REJECTS_OFFER = SRC_HE_REJECTS_OFFER; + Common::copy(&SRC_KING_TEXT[0], &SRC_KING_TEXT[11], KING_TEXT); } void GameResources::synchronize() { @@ -857,6 +875,8 @@ void GameResources::synchronize() { syncString(CAUGHT); syncString(NONE_WILL_TALK); syncString(BUY_SELL); + syncString(BUY); + syncString(SELL); syncString(NOTHING); syncString(NONE); syncString(NOTHING_HERE); @@ -904,6 +924,11 @@ void GameResources::synchronize() { syncString(GROCERY_PACKS3); syncString(GROCERY_PACKS_FOOD); syncString(GROCERY_FIND_PACKS); + + syncString(WITH_KING); + syncString(HE_IS_NOT_HERE); + syncString(HE_REJECTS_OFFER); + syncStrings(KING_TEXT, 11); } } // End of namespace Ultima1 diff --git a/engines/ultima/ultima1/core/resources.h b/engines/ultima/ultima1/core/resources.h index ede21613300..3513976b209 100644 --- a/engines/ultima/ultima1/core/resources.h +++ b/engines/ultima/ultima1/core/resources.h @@ -106,6 +106,8 @@ public: const char *CAUGHT; const char *NONE_WILL_TALK; const char *BUY_SELL; + const char *BUY; + const char *SELL; const char *NOTHING; const char *NONE; const char *NOTHING_HERE; @@ -153,6 +155,12 @@ public: const char *GROCERY_PACKS3; const char *GROCERY_PACKS_FOOD; const char *GROCERY_FIND_PACKS; + + const char *WITH_KING; + const char *HE_IS_NOT_HERE; + const char *HE_REJECTS_OFFER; + const char *KING_TEXT[11]; + public: GameResources(); GameResources(Shared::Resources *resManager); diff --git a/engines/ultima/ultima1/maps/map_city_castle.cpp b/engines/ultima/ultima1/maps/map_city_castle.cpp index 99c0e0b7e6c..bee62780b2a 100644 --- a/engines/ultima/ultima1/maps/map_city_castle.cpp +++ b/engines/ultima/ultima1/maps/map_city_castle.cpp @@ -179,6 +179,39 @@ Widgets::Merchant *MapCityCastle::getStealMerchant() { } } +Widgets::Person *MapCityCastle::getTalkPerson() { + U1MapTile tile; + getTileAt(getPosition(), &tile); + + switch (tile._tileId) { + case 54: + case 55: + return dynamic_cast(_widgets.findByClass(Widgets::MerchantArmor::type())); + + case 56: + case 57: + return dynamic_cast(_widgets.findByClass(Widgets::MerchantGrocer::type())); + + case 58: + case 59: + return dynamic_cast(_widgets.findByClass(Widgets::MerchantWeapons::type())); + + case 60: + return dynamic_cast(_widgets.findByClass(Widgets::MerchantMagic::type())); + + case 61: + return dynamic_cast(_widgets.findByClass(Widgets::MerchantTavern::type())); + + case 62: + return dynamic_cast(_widgets.findByClass( + dynamic_cast(this) ? Widgets::MerchantTransport::type() : Widgets::King::type() )); + + default: + return nullptr; + } + +} + void MapCityCastle::cast() { addInfoMsg(Common::String::format(" -- %s", _game->_res->NO_EFFECT)); _game->playFX(6); @@ -301,6 +334,15 @@ void MapCity::get() { _game->playFX(1); } +void MapCity::talk() { + if (_guardsHostile) { + addInfoMsg(_game->_res->NONE_WILL_TALK); + + } + + // TODO +} + void MapCity::unlock() { addInfoMsg(_game->_res->WHAT); _game->playFX(1); @@ -371,6 +413,18 @@ void MapCastle::get() { } } +void MapCastle::talk() { + addInfoMsg(_game->_res->WITH_KING); + Widgets::Person *person = getTalkPerson(); + + if (person) { + person->talk(); + } else { + addInfoMsg(_game->_res->HE_IS_NOT_HERE); + _game->endOfTurn(); + } +} + void MapCastle::unlock() { U1MapTile tile; Point pt = getPosition(); diff --git a/engines/ultima/ultima1/maps/map_city_castle.h b/engines/ultima/ultima1/maps/map_city_castle.h index 633b05b1b87..c074425d4f8 100644 --- a/engines/ultima/ultima1/maps/map_city_castle.h +++ b/engines/ultima/ultima1/maps/map_city_castle.h @@ -28,6 +28,7 @@ namespace Ultima { namespace Ultima1 { namespace Widgets { + class Person; class Merchant; } @@ -57,6 +58,11 @@ protected: * Get a merchant for a given steal-type tile */ Widgets::Merchant *getStealMerchant(); + + /** + * Get a person to talk to based on the tile the player is on + */ + Widgets::Person *getTalkPerson(); public: bool _guardsHostile; // Flag for whether guards are hostile public: @@ -152,6 +158,11 @@ public: */ virtual void get() override; + /** + * Do a talk action + */ + virtual void talk() override; + /** * Do an unlock action */ @@ -193,6 +204,11 @@ public: */ virtual void get() override; + /** + * Do a talk action + */ + virtual void talk() override; + /** * Do an unlock action */ diff --git a/engines/ultima/ultima1/u1dialogs/buy_sell_dialog.cpp b/engines/ultima/ultima1/u1dialogs/buy_sell_dialog.cpp index 2445aeb8d72..fe1f3777bde 100644 --- a/engines/ultima/ultima1/u1dialogs/buy_sell_dialog.cpp +++ b/engines/ultima/ultima1/u1dialogs/buy_sell_dialog.cpp @@ -20,34 +20,60 @@ * */ -#include "ultima/games/ultima1/u1dialogs/buy_sell_dialog.h" -#include "ultima/gfx/visual_surface.h" -#include "ultima/games/ultima1/game.h" -#include "ultima/games/ultima1/core/resources.h" -#include "ultima/games/ultima1/maps/map.h" +#include "ultima/ultima1/u1dialogs/buy_sell_dialog.h" +#include "ultima/shared/gfx/visual_surface.h" +#include "ultima/ultima1/game.h" +#include "ultima/ultima1/core/resources.h" +#include "ultima/ultima1/maps/map.h" namespace Ultima { namespace Ultima1 { namespace U1Dialogs { -BuySellDialog::BuySellDialog(Ultima1Game *game, BuySell buySell, const Common::String &title) : Dialog(game), - _buySell(buySell), _title(title) { - assert(buySell == BUY || buySell == SOLD); +BEGIN_MESSAGE_MAP(BuySellDialog, Dialog) + ON_MESSAGE(CharacterInputMsg) +END_MESSAGE_MAP() + +BuySellDialog::BuySellDialog(Ultima1Game *game, const Common::String &title) : + Dialog(game), _mode(SELECT), _title(title), _charInput(game) { _bounds = Rect(31, 23, 287, 127); } void BuySellDialog::draw() { Dialog::draw(); - Gfx::VisualSurface s = getSurface(); - - // Draw the background and frame - s.clear(); - s.frameRect(Rect(3, 3, _bounds.width() - 3, _bounds.height() - 3), getGame()->_borderColor); + Shared::Gfx::VisualSurface s = getSurface(); - // Draw the title - s.writeString(_title, Point((_bounds.width() - _title.size() * 8) / 2, 9)); + if (_mode != SELECT) { + // Draw the background and frame + s.clear(); + s.frameRect(Rect(3, 3, _bounds.width() - 3, _bounds.height() - 3), getGame()->_borderColor); - switch (_buySell) { + // Draw the title + s.writeString(_title, Point((_bounds.width() - _title.size() * 8) / 2, 9)); + } + + // Clear part of the bottom info text line + s.fillRect(TextRect(8, 24, 28, 24), _game->_bgColor); + + switch (_mode) { + case SELECT: { + // Display the buy/sell text and prompt for input + s.writeString(_game->_res->BUY_SELL, TextPoint(8, 24)); + _charInput.show(TextPoint(20, 24), _game->_textColor, this); + break; + } + case BUY: { + // Display the buy/sell text and prompt for input + s.writeString(_game->_res->BUY, TextPoint(8, 24)); + _charInput.show(TextPoint(15, 24), _game->_textColor, this); + break; + } + case SELL: { + // Display the buy/sell text and prompt for input + s.writeString(_game->_res->SELL, TextPoint(8, 24)); + _charInput.show(TextPoint(15, 24), _game->_textColor, this); + break; + } case SOLD: s.writeString(getGame()->_res->SOLD, TextPoint(14, 5)); break; @@ -61,14 +87,32 @@ void BuySellDialog::draw() { } } -void BuySellDialog::showSold() { - _buySell = SOLD; +void BuySellDialog::setMode(BuySell mode) { + _mode = mode; setDirty(); } -void BuySellDialog::cantAfford() { - _buySell = CANT_AFFORD; - setDirty(); +bool BuySellDialog::CharacterInputMsg(CCharacterInputMsg &msg) { + switch (_mode) { + case SELECT: + if (msg._keyState.keycode == Common::KEYCODE_b) + setMode(BUY); + else if (msg._keyState.keycode == Common::KEYCODE_s) + setMode(SELL); + else + nothing(); + break; + + default: + break; + } + + return true; +} + +void BuySellDialog::nothing() { + addInfoMsg(Common::String::format(" %s", _game->_res->NOTHING)); + hide(); } } // End of namespace U1Dialogs diff --git a/engines/ultima/ultima1/u1dialogs/buy_sell_dialog.h b/engines/ultima/ultima1/u1dialogs/buy_sell_dialog.h index 90c89908324..3988cba6b76 100644 --- a/engines/ultima/ultima1/u1dialogs/buy_sell_dialog.h +++ b/engines/ultima/ultima1/u1dialogs/buy_sell_dialog.h @@ -24,40 +24,59 @@ #define ULTIMA_ULTIMA1_U1DIALOGS_BUY_SELL_DIALOG_H #include "ultima/ultima1/u1dialogs/dialog.h" +#include "ultima/shared/gfx/character_input.h" namespace Ultima { namespace Ultima1 { namespace U1Dialogs { -enum BuySell { BUY, SELL, SOLD, CANT_AFFORD }; +enum BuySell { SELECT, BUY, SELL, SOLD, CANT_AFFORD }; + +using Shared::CCharacterInputMsg; /** * Secondary base class for dialogs that have display for buying and selling */ class BuySellDialog : public Dialog { + DECLARE_MESSAGE_MAP; + virtual bool CharacterInputMsg(CCharacterInputMsg &msg); +private: + Shared::Gfx::CharacterInput _charInput; protected: - BuySell _buySell; + BuySell _mode; Common::String _title; -public: +protected: /** * Constructor */ - BuySellDialog(Ultima1Game *game, BuySell buySell, const Common::String &title); + BuySellDialog(Ultima1Game *game, const Common::String &title); + + /** + * Nothing selected + */ + void nothing(); + + /** + * Set the mode + */ + void setMode(BuySell mode); + + /** + * Switches the dialog to displaying sold + */ + void showSold() { setMode(SOLD); } + + /** + * Switches the dialog to displaying a can't afford message + */ + void cantAfford() { setMode(CANT_AFFORD); } +public: + CLASSDEF; /** * Draws the visual item on the screen */ virtual void draw(); - - /** - * Switches the dialog to displaying sold - */ - void showSold(); - - /** - * Switches the dialog to displaying a can't afford message - */ - void cantAfford(); }; } // End of namespace U1Dialogs diff --git a/engines/ultima/ultima1/u1dialogs/grocery.cpp b/engines/ultima/ultima1/u1dialogs/grocery.cpp index 746761d9563..d9a77d0ecb7 100644 --- a/engines/ultima/ultima1/u1dialogs/grocery.cpp +++ b/engines/ultima/ultima1/u1dialogs/grocery.cpp @@ -31,9 +31,9 @@ namespace U1Dialogs { EMPTY_MESSAGE_MAP(Grocery, BuySellDialog); -Grocery::Grocery(Ultima1Game *game, BuySell buySell, int groceryNum, uint costPerPack) : - BuySellDialog(game, buySell, game->_res->GROCERY_NAMES[groceryNum]) { - assert(buySell == SELL || costPerPack > 0); +Grocery::Grocery(Ultima1Game *game, int groceryNum) : BuySellDialog(game, game->_res->GROCERY_NAMES[groceryNum]) { + Shared::Character &c = *game->_party; + _costPerPack = 5 - c._intelligence / 20; } void Grocery::draw() { @@ -41,15 +41,15 @@ void Grocery::draw() { Shared::Gfx::VisualSurface s = getSurface(); Ultima1Game *game = getGame(); - switch (_buySell) { + switch (_mode) { case BUY: - s.writeString(game->_res->GROCERY_PACKS1, TextPoint(5, 5)); - s.writeString(game->_res->GROCERY_PACKS2, TextPoint(5, 5)); - s.writeString(game->_res->GROCERY_PACKS3, TextPoint(5, 5)); + s.writeString(game->_res->GROCERY_PACKS1, TextPoint(5, 8)); + s.writeString(game->_res->GROCERY_PACKS2, TextPoint(8, 9)); + s.writeString(game->_res->GROCERY_PACKS3, TextPoint(15, 10)); break; case SELL: - s.writeString(game->_res->GROCERY_SELL, TextPoint(5, 5)); + s.writeString(game->_res->GROCERY_SELL, TextPoint(9, 8)); break; default: diff --git a/engines/ultima/ultima1/u1dialogs/grocery.h b/engines/ultima/ultima1/u1dialogs/grocery.h index 50fbb244421..9ee0810201b 100644 --- a/engines/ultima/ultima1/u1dialogs/grocery.h +++ b/engines/ultima/ultima1/u1dialogs/grocery.h @@ -42,7 +42,7 @@ public: /** * Constructor */ - Grocery(Ultima1Game *game, BuySell buySell, int groceryNum, uint costPerPack = 0); + Grocery(Ultima1Game *game, int groceryNum); /** * Draws the visual item on the screen diff --git a/engines/ultima/ultima1/u1gfx/view_game.cpp b/engines/ultima/ultima1/u1gfx/view_game.cpp index c3607043f03..50dd6e3ff3c 100644 --- a/engines/ultima/ultima1/u1gfx/view_game.cpp +++ b/engines/ultima/ultima1/u1gfx/view_game.cpp @@ -52,7 +52,7 @@ MAP_ACTION_END_TURN(Inform, 8, inform) MAP_ACTION_END_TURN(Climb, 10, climb) MAP_ACTION_END_TURN(Open, 14, open) MAP_ACTION_END_TURN(Steal, 18, steal) -MAP_ACTION_END_TURN(Transact, 19, talk) +MAP_ACTION(Transact, 19, talk) MAP_ACTION_END_TURN(Unlock, 20, unlock) MAP_ACTION_END_TURN(ViewChange, 21, view) MAP_ACTION_END_TURN(ExitTransport, 23, disembark) diff --git a/engines/ultima/ultima1/widgets/king.cpp b/engines/ultima/ultima1/widgets/king.cpp index 25d6fb3f8a0..c35ea8065db 100644 --- a/engines/ultima/ultima1/widgets/king.cpp +++ b/engines/ultima/ultima1/widgets/king.cpp @@ -22,6 +22,7 @@ #include "ultima/ultima1/widgets/king.h" #include "ultima/ultima1/maps/map_city_castle.h" +#include "ultima/ultima1/core/resources.h" namespace Ultima { namespace Ultima1 { @@ -37,6 +38,16 @@ bool King::subtractHitPoints(uint amount) { return map->isLordBritishCastle() ? false : Person::subtractHitPoints(amount); } +void King::talk() { + if (areGuardsHostile()) { + addInfoMsg(_game->_res->HE_REJECTS_OFFER); + _game->endOfTurn(); + + } else { + // TODO + } +} + } // End of namespace Widgets } // End of namespace Ultima1 } // End of namespace Ultima diff --git a/engines/ultima/ultima1/widgets/king.h b/engines/ultima/ultima1/widgets/king.h index fc3a2e83567..633072be1eb 100644 --- a/engines/ultima/ultima1/widgets/king.h +++ b/engines/ultima/ultima1/widgets/king.h @@ -58,6 +58,11 @@ public: * @returns Returns true if kills the creature */ virtual bool subtractHitPoints(uint amount) override; + + /** + * Do a talk action + */ + virtual void talk() override; }; } // End of namespace Widgets diff --git a/engines/ultima/ultima1/widgets/merchant_grocer.cpp b/engines/ultima/ultima1/widgets/merchant_grocer.cpp index fa0be79cdb2..8829ee3931b 100644 --- a/engines/ultima/ultima1/widgets/merchant_grocer.cpp +++ b/engines/ultima/ultima1/widgets/merchant_grocer.cpp @@ -23,6 +23,7 @@ #include "ultima/ultima1/widgets/merchant_grocer.h" #include "ultima/ultima1/maps/map_city_castle.h" #include "ultima/ultima1/core/resources.h" +#include "ultima/ultima1/u1dialogs/grocery.h" namespace Ultima { namespace Ultima1 { @@ -56,6 +57,11 @@ void MerchantGrocer::findFood(bool checkStealing) { } } +void MerchantGrocer::talk() { + U1Dialogs::Grocery *grocery = new U1Dialogs::Grocery(_game, _map->getMapIndex()); + grocery->show(); +} + } // End of namespace Widgets } // End of namespace Ultima1 } // End of namespace Ultima diff --git a/engines/ultima/ultima1/widgets/merchant_grocer.h b/engines/ultima/ultima1/widgets/merchant_grocer.h index 96ffa55492c..68a9b8df58f 100644 --- a/engines/ultima/ultima1/widgets/merchant_grocer.h +++ b/engines/ultima/ultima1/widgets/merchant_grocer.h @@ -70,6 +70,11 @@ public: * Does the steal action */ virtual void steal() override; + + /** + * Talk to an NPC + */ + virtual void talk() override; }; } // End of namespace Widgets