summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/shopping.cc
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source/shopping.cc')
-rw-r--r--crawl-ref/source/shopping.cc230
1 files changed, 182 insertions, 48 deletions
diff --git a/crawl-ref/source/shopping.cc b/crawl-ref/source/shopping.cc
index a169778b4a..01044a58e0 100644
--- a/crawl-ref/source/shopping.cc
+++ b/crawl-ref/source/shopping.cc
@@ -44,7 +44,7 @@
#include "view.h"
static void _in_a_shop(int shopidx);
-static void _purchase( int shop, int item_got, int cost, bool id);
+static bool _purchase( int shop, int item_got, int cost, bool id);
static void _shop_print( const char *shoppy, int line )
{
@@ -139,7 +139,7 @@ static std::vector<int> _shop_get_stock(int shopidx)
static int _shop_get_item_value(const item_def& item, int greed, bool id)
{
int result = (greed * item_value(item, id) / 10);
- if ( you.duration[DUR_BARGAIN] ) // 20% discount
+ if (you.duration[DUR_BARGAIN]) // 20% discount
{
result *= 8;
result /= 10;
@@ -152,7 +152,9 @@ static int _shop_get_item_value(const item_def& item, int greed, bool id)
}
static std::string _shop_print_stock( const std::vector<int>& stock,
- const shop_struct& shop )
+ const std::vector<bool>& selected,
+ const shop_struct& shop,
+ int total_cost )
{
ShopInfo &si = StashTrack.get_shop(shop.x, shop.y);
const bool id = shoptype_identifies_stock(shop.type);
@@ -168,19 +170,65 @@ static std::string _shop_print_stock( const std::vector<int>& stock,
if (can_afford)
purchasable += c;
- textcolor( can_afford ? LIGHTGREEN : LIGHTRED );
- cprintf("%c - ", c);
+ // Colour stock as follows:
+ // * lightred, if you can't buy all you selected.
+ // * lightgreen, if this item is purchasable along with your selections
+ // * red, if this item is not purchasable even by itself.
+ // * yellow, if this item would be purchasable if you deselected
+ // something else.
+
+ // Is this too complicated?
+
+ if (total_cost > you.gold && selected[i])
+ textcolor(LIGHTRED);
+ else if (gp_value <= you.gold - total_cost || selected[i] && can_afford)
+ textcolor(LIGHTGREEN);
+ else if (!can_afford)
+ textcolor(RED);
+ else
+ textcolor(YELLOW);
+
+ if (selected[i])
+ cprintf("%c + ", c);
+ else
+ cprintf("%c - ", c);
- textcolor((i % 2) ? LIGHTGREY : WHITE);
+ textcolor(i % 2 ? LIGHTGREY : WHITE);
cprintf("%-56s%5d gold",
mitm[stock[i]].name(DESC_NOCAP_A, false, id).c_str(),
gp_value);
+
si.add_item(mitm[stock[i]], gp_value);
}
textcolor(LIGHTGREY);
- return purchasable;
+
+ return (purchasable);
}
+
+/*
+ Rather than prompting for each individual item, I think it should be
+like multi-pickup, in that pressing a letter only "selects" an item
+(changing the '-' next to its name to a '+').
+
+New, suggested shopping keys:
+* letter keys [a-t] (de)select item
+* Enter buys (with prompt)
+* ? toggles examination mode (where letter keys view items)
+* \ shows discovered items
+* * lists inventory
+* x exits (also Esc)
+
+For the ? key, the text should read:
+[?] switch to examination mode
+[?] switch to selection mode
+
+Display selected items in yellow.
+Use red/green letters to indicated availability as now. Update these as
+items are (de)selected.
+List funds: "You now have 119 gold pieces. After the purchase, you will
+have 24 gold pieces."
+*/
static void _in_a_shop( int shopidx )
{
const shop_struct& shop = env.shop[shopidx];
@@ -191,15 +239,25 @@ static void _in_a_shop( int shopidx )
const std::string hello = "Welcome to " + shop_name(shop.x, shop.y) + "!";
bool first = true;
+ int total_cost = 0;
const bool id_stock = shoptype_identifies_stock(shop.type);
-
- while ( true )
+ std::vector<bool> selected;
+ while (true)
{
StashTrack.get_shop(shop.x, shop.y).reset();
std::vector<int> stock = _shop_get_stock(shopidx);
+ // Deselect all.
+ if (stock.size() != selected.size())
+ {
+ total_cost = 0;
+ selected.resize(stock.size());
+ for (unsigned int i = 0; i < selected.size(); ++i)
+ selected[i] = false;
+ }
+
clrscr();
if (stock.empty())
{
@@ -208,12 +266,40 @@ static void _in_a_shop( int shopidx )
return;
}
- const std::string purchasable = _shop_print_stock(stock, shop);
+ const std::string purchasable = _shop_print_stock(stock, selected, shop,
+ total_cost);
_list_shop_keys(purchasable);
- snprintf( info, INFO_SIZE, "You have %d gold piece%s.", you.gold,
- (you.gold == 1) ? "" : "s" );
- textcolor(YELLOW);
+ if (!total_cost)
+ {
+ snprintf( info, INFO_SIZE, "You have %d gold piece%s.", you.gold,
+ (you.gold == 1) ? "" : "s" );
+
+ textcolor(YELLOW);
+ }
+ else if (total_cost > you.gold)
+ {
+ snprintf( info, INFO_SIZE, "You now have %d gold piece%s. "
+ "You are short %d gold piece%s for the purchase.",
+ you.gold,
+ (you.gold == 1) ? "" : "s",
+ total_cost - you.gold,
+ (total_cost - you.gold == 1) ? "" : "s" );
+
+ textcolor(LIGHTRED);
+ }
+ else
+ {
+ snprintf( info, INFO_SIZE, "You now have %d gold piece%s. "
+ "After the purchase, you will have %d gold piece%s.",
+ you.gold,
+ (you.gold == 1) ? "" : "s",
+ you.gold - total_cost,
+ (you.gold - total_cost == 1) ? "" : "s" );
+
+ textcolor(YELLOW);
+ }
+
_shop_print(info, 0);
if (first)
@@ -236,10 +322,81 @@ static void _in_a_shop( int shopidx )
int ft = get_ch();
- if ( ft == '\\' )
+ if (ft == '\\')
check_item_knowledge();
else if (ft == 'x' || ft == ESCAPE)
break;
+ else if (ft == '\r')
+ {
+ // Do purchase.
+ if (total_cost > you.gold)
+ {
+ _shop_print("I'm sorry, you don't seem to have enough money.", 1);
+ _shop_more();
+ }
+ else if (!total_cost)
+ continue;
+ else
+ {
+ textcolor(channel_to_colour(MSGCH_PROMPT));
+ snprintf(info, INFO_SIZE, "Purchase for %d gold? (y/n) ",
+ total_cost);
+ _shop_print(info, 1);
+
+ if ( yesno(NULL, true, 'n', false, false, true) )
+ {
+ std::vector<std::string> purchases;
+ int num_items = 0, outside_items = 0, quant;
+ for (int i = selected.size() - 1; i >= 0; --i)
+ {
+ if (selected[i])
+ {
+ item_def& item = mitm[stock[i]];
+ purchases.push_back(item.name(DESC_NOCAP_A));
+
+ quant = item.quantity;
+ num_items += quant;
+
+ const int gp_value = _shop_get_item_value(item,
+ shop.greed, id_stock);
+ if (!_purchase(shopidx, stock[i], gp_value,
+ id_stock))
+ {
+ // The purchased item didn't fit into your
+ // knapsack.
+ outside_items += quant;
+ }
+ }
+ }
+
+ // Hack to make sure the lines are empty for the mpr().
+ for (int i = 0; i < 5; i++)
+ _shop_print("\n", i);
+
+ // This is so that note_messages can be used to note items
+ // being bought, and also so you can use message history
+ // to review what you bought.
+ // FIXME: If you buy several items of the same type
+ // they are not merged in the listing.
+ mprf("You bought %s for a total of %d gold piece%s.",
+ comma_separated_line(purchases.begin(),
+ purchases.end(),
+ ", and ", ", ").c_str(),
+ total_cost,
+ total_cost > 1 ? "s" : "");
+
+ if (outside_items)
+ {
+ mprf( "I'll put %s outside for you.",
+ num_items == 1 ? "it" :
+ num_items == outside_items ? "them"
+ : "part of them" );
+ }
+ }
+ }
+ _shop_more();
+ continue;
+ }
else if (ft == 'v')
{
textcolor(CYAN);
@@ -250,9 +407,7 @@ static void _in_a_shop( int shopidx )
ft = get_ch();
if (!isalpha(ft))
- {
is_ok = false;
- }
else
{
ft = tolower(ft) - 'a';
@@ -303,23 +458,13 @@ static void _in_a_shop( int shopidx )
}
item_def& item = mitm[stock[ft]];
-
const int gp_value = _shop_get_item_value(item, shop.greed, id_stock);
- if (gp_value > you.gold)
- {
- _shop_print("I'm sorry, you don't seem to have enough money.", 1);
- _shop_more();
- }
- else
- {
- textcolor(channel_to_colour(MSGCH_PROMPT));
- snprintf(info, INFO_SIZE, "Purchase %s (%d gold)? (y/n) ",
- item.name(DESC_NOCAP_A).c_str(), gp_value);
- _shop_print(info, 1);
- if ( yesno(NULL, true, 'n', false, false, true) )
- _purchase( shopidx, stock[ft], gp_value, id_stock );
- }
+ selected[ft] = !selected[ft];
+ if (selected[ft])
+ total_cost += gp_value;
+ else
+ total_cost -= gp_value;
}
}
}
@@ -331,7 +476,7 @@ bool shoptype_identifies_stock(shop_type type)
&& type != SHOP_GENERAL_ANTIQUE);
}
-static void _purchase( int shop, int item_got, int cost, bool id )
+static bool _purchase( int shop, int item_got, int cost, bool id )
{
you.gold -= cost;
@@ -339,13 +484,7 @@ static void _purchase( int shop, int item_got, int cost, bool id )
origin_purchased(item);
- // This is so that note_messages can be used to note items being
- // bought, and also so you can use message history to review
- // what you bought.
- mprf("You bought %s.", item.name(DESC_NOCAP_A, false, id).c_str());
- mesclr();
-
- if ( id )
+ if (id)
{
// Identify the item and its type.
// This also takes the ID note if necessary.
@@ -354,22 +493,16 @@ static void _purchase( int shop, int item_got, int cost, bool id )
}
const int quant = item.quantity;
- // note that item will be invalidated if num == item.quantity
+ // Note that item will be invalidated if num == item.quantity.
const int num = move_item_to_player( item_got, item.quantity, true );
// Shopkeepers will now place goods you can't carry outside the shop.
if (num < quant)
{
- snprintf( info, INFO_SIZE, "I'll put %s outside for you.",
- (quant == 1) ? "it" :
- (num > 0) ? "the rest"
- : "these" );
-
- _shop_print(info, 1);
- _shop_more();
-
move_item_to_grid( &item_got, env.shop[shop].x, env.shop[shop].y );
+ return (false);
}
+ return (true);
}
// This probably still needs some work. Rings used to be the only
@@ -1502,6 +1635,7 @@ unsigned int item_value( item_def item, bool ident )
return (valued);
} // end item_value()
+
void shop()
{
int i;