ULTIMA1: In progress implementing the Grocery dialog

This commit is contained in:
dreammaster 2020-01-21 07:23:44 +00:00 committed by Paul Gilbert
parent 0b5dd81634
commit 601699c040
14 changed files with 239 additions and 45 deletions

View File

@ -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 \

View File

@ -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

View File

@ -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);

View File

@ -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::Person *>(_widgets.findByClass(Widgets::MerchantArmor::type()));
case 56:
case 57:
return dynamic_cast<Widgets::Person *>(_widgets.findByClass(Widgets::MerchantGrocer::type()));
case 58:
case 59:
return dynamic_cast<Widgets::Person *>(_widgets.findByClass(Widgets::MerchantWeapons::type()));
case 60:
return dynamic_cast<Widgets::Person *>(_widgets.findByClass(Widgets::MerchantMagic::type()));
case 61:
return dynamic_cast<Widgets::Person *>(_widgets.findByClass(Widgets::MerchantTavern::type()));
case 62:
return dynamic_cast<Widgets::Person *>(_widgets.findByClass(
dynamic_cast<MapCity *>(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();

View File

@ -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
*/

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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