summaryrefslogtreecommitdiffstats
path: root/stone_soup/crawl-ref/source/stash.cc
diff options
context:
space:
mode:
Diffstat (limited to 'stone_soup/crawl-ref/source/stash.cc')
-rw-r--r--stone_soup/crawl-ref/source/stash.cc1607
1 files changed, 0 insertions, 1607 deletions
diff --git a/stone_soup/crawl-ref/source/stash.cc b/stone_soup/crawl-ref/source/stash.cc
deleted file mode 100644
index dbdfef440d..0000000000
--- a/stone_soup/crawl-ref/source/stash.cc
+++ /dev/null
@@ -1,1607 +0,0 @@
-/*
- * File: stash.cc
- * Summary: Classes tracking player stashes
- * Written by: Darshan Shaligram
- */
-
-#include "AppHdr.h"
-#include "chardump.h"
-#include "clua.h"
-#include "describe.h"
-#include "itemname.h"
-#include "itemprop.h"
-#include "files.h"
-#include "invent.h"
-#include "items.h"
-#include "Kills.h"
-#include "libutil.h"
-#include "menu.h"
-#include "shopping.h"
-#include "spl-book.h"
-#include "stash.h"
-#include "stuff.h"
-#include "tags.h"
-#include "travel.h"
-
-#include <cctype>
-#include <cstdio>
-#include <fstream>
-#include <algorithm>
-
-#ifdef STASH_TRACKING
-
-#define ST_MAJOR_VER ((unsigned char) 4)
-#define ST_MINOR_VER ((unsigned char) 4)
-
-#define LUA_SEARCH_ANNOTATE "ch_stash_search_annotate_item"
-#define LUA_DUMP_ANNOTATE "ch_stash_dump_annotate_item"
-#define LUA_VIEW_ANNOTATE "ch_stash_view_annotate_item"
-
-std::string short_place_name(level_id id)
-{
- return short_place_name(
- get_packed_place(id.branch, id.depth, LEVEL_DUNGEON));
-}
-
-std::string userdef_annotate_item(const char *s, const item_def *item,
- bool exclusive)
-{
-#ifdef CLUA_BINDINGS
- if (exclusive)
- lua_set_exclusive_item(item);
- std::string ann;
- clua.callfn(s, "u>s", item, &ann);
- if (exclusive)
- lua_set_exclusive_item(NULL);
- return (ann);
-
-#else
- return ("");
-#endif
-}
-
-std::string stash_annotate_item(const char *s,
- const item_def *item,
- bool exclusive = false)
-{
- std::string text = userdef_annotate_item(s, item, exclusive);
- if ( (item->base_type == OBJ_BOOKS &&
- item_type_known(*item) &&
- item->sub_type != BOOK_MANUAL &&
- item->sub_type != BOOK_DESTRUCTION)
- || count_staff_spells(*item, true) > 1 )
- {
- formatted_string fs;
- item_def dup = *item;
- spellbook_contents( dup,
- item->base_type == OBJ_BOOKS?
- RBOOK_READ_SPELL
- : RBOOK_USE_STAFF,
- &fs );
- text += EOL;
- text += fs.tostring(2, -2);
- }
- return text;
-}
-
-bool is_stash(int x, int y)
-{
- LevelStashes *ls = stashes.find_current_level();
- if (ls)
- {
- Stash *s = ls->find_stash(x, y);
- return s && s->enabled;
- }
- return false;
-}
-
-void describe_stash(int x, int y)
-{
- LevelStashes *ls = stashes.find_current_level();
- if (ls)
- {
- Stash *s = ls->find_stash(x, y);
- if (s)
- {
- std::string desc = "[Stash: "
- + s->description() + "]";
- mpr(desc.c_str());
- }
- }
-}
-
-static void fully_identify_item(item_def *item)
-{
- if (!item || !is_valid_item(*item))
- return;
-
- set_ident_flags( *item, ISFLAG_IDENT_MASK );
- if (item->base_type != OBJ_WEAPONS)
- set_ident_type( item->base_type,
- item->sub_type,
- ID_KNOWN_TYPE );
-}
-
-static void save_item(FILE *file, const item_def &item)
-{
- writeByte(file, item.base_type);
- writeByte(file, item.sub_type);
- writeShort(file, item.plus);
- writeShort(file, item.plus2);
- writeLong(file, item.special);
- writeShort(file, item.quantity);
- writeByte(file, item.colour);
- writeLong(file, item.flags);
-}
-
-static void load_item(FILE *file, item_def &item)
-{
- item.base_type = readByte(file);
- item.sub_type = readByte(file);
- item.plus = readShort(file);
- item.plus2 = readShort(file);
- item.special = readLong(file);
- item.quantity = readShort(file);
- item.colour = readByte(file);
- item.flags = readLong(file);
-}
-
-bool Stash::aggressive_verify = true;
-std::vector<item_def> Stash::filters;
-
-Stash::Stash(int xp, int yp) : enabled(true), items()
-{
- // First, fix what square we're interested in
- if (xp == -1)
- {
- xp = you.x_pos;
- yp = you.y_pos;
- }
- x = (unsigned char) xp;
- y = (unsigned char) yp;
- abspos = GXM * (int) y + x;
-
- update();
-}
-
-bool Stash::are_items_same(const item_def &a, const item_def &b)
-{
- return a.base_type == b.base_type &&
- a.sub_type == b.sub_type &&
- a.plus == b.plus &&
- a.plus2 == b.plus2 &&
- a.special == b.special &&
- a.colour == b.colour &&
- a.flags == b.flags &&
- a.quantity == b.quantity;
-}
-
-void Stash::filter(const std::string &str)
-{
- std::string base = str;
-
- base.erase(base.find_last_not_of(" \n\t") + 1);
- base.erase(0, base.find_first_not_of(" \n\t"));
-
- unsigned char subc = 255;
- std::string::size_type cpos = base.find(":", 0);
- if (cpos != std::string::npos)
- {
- std::string subs = base.substr(cpos + 1);
- subc = atoi(subs.c_str());
-
- base = base.substr(0, cpos);
- }
-
- unsigned char basec = atoi(base.c_str());
- filter(basec, subc);
-}
-
-void Stash::filter(unsigned char base, unsigned char sub)
-{
- item_def item;
- item.base_type = base;
- item.sub_type = sub;
-
- filters.push_back(item);
-}
-
-bool Stash::is_filtered(const item_def &item)
-{
- for (int i = 0, count = filters.size(); i < count; ++i)
- {
- const item_def &filter = filters[i];
- if (item.base_type == filter.base_type &&
- (filter.sub_type == 255 ||
- item.sub_type == filter.sub_type))
- return true;
- }
- return false;
-}
-
-void Stash::update()
-{
- int objl = igrd[x][y];
- // If this is your position, you know what's on this square
- if (x == you.x_pos && y == you.y_pos)
- {
- // Zap existing items
- items.clear();
-
- // Now, grab all items on that square and fill our vector
- while (objl != NON_ITEM)
- {
- if (!is_filtered(mitm[objl]))
- items.push_back(mitm[objl]);
- objl = mitm[objl].link;
- }
-
- verified = true;
- }
- // If this is not your position, the only thing we can do is verify that
- // what the player sees on the square is the first item in this vector.
- else
- {
- if (objl == NON_ITEM)
- {
- items.clear();
- verified = true;
- return ;
- }
-
- // There's something on this square. Take a squint at it.
- item_def &item = mitm[objl];
-
- if (item.link == NON_ITEM) items.clear();
-
- // We knew of nothing on this square, so we'll assume this is the
- // only item here, but mark it as unverified unless we can see nothing
- // under the item.
- if (items.size() == 0)
- {
- if (!is_filtered(item))
- items.push_back(item);
- verified = (item.link == NON_ITEM);
- return ;
- }
-
- // There's more than one item in this pile. As long as the top item is
- // not filtered, we can check to see if it matches what we think the
- // top item is.
-
- if (is_filtered(item)) return;
-
- item_def &first = items[0];
- // Compare these items
- if (!are_items_same(first, item))
- {
- if (aggressive_verify)
- {
- // See if 'item' matches any of the items we have. If it does,
- // we'll just make that the first item and leave 'verified'
- // unchanged.
-
- // Start from 1 because we've already checked items[0]
- for (int i = 1, count = items.size(); i < count; ++i)
- {
- if (are_items_same(items[i], item))
- {
- // Found it. Swap it to the front of the vector.
- item_def temp = items[i];
- items[i] = items[0];
- items[0] = temp;
-
- // We don't set verified to true. If this stash was
- // already unverified, it remains so.
- return;
- }
- }
- }
-
- // If this is unverified, forget last item on stack. This isn't
- // terribly clever, but it prevents the vector swelling forever.
- if (!verified) items.pop_back();
-
- // Items are different. We'll put this item in the front of our
- // vector, and mark this as unverified
- items.insert(items.begin(), item);
- verified = false;
- }
- }
-}
-
-// Returns the item name for a given item, with any appropriate
-// stash-tracking pre/suffixes.
-std::string Stash::stash_item_name(const item_def &item)
-{
- char buf[ITEMNAME_SIZE];
-
- if (item.base_type == OBJ_GOLD)
- snprintf(buf, sizeof buf, "%d gold piece%s", item.quantity,
- (item.quantity > 1? "s" : ""));
- else
- item_name(item, DESC_NOCAP_A, buf, false);
-
- return buf;
-}
-
-class StashMenu : public Menu
-{
-public:
- StashMenu() : Menu(MF_SINGLESELECT), can_travel(false) { }
-public:
- bool can_travel;
-protected:
- void draw_title();
- bool process_key(int key);
-};
-
-void StashMenu::draw_title()
-{
- if (title)
- {
- gotoxy(1, 1);
- textcolor(title->colour);
- cprintf(title->text.c_str());
- if (title->quantity)
- cprintf(", %d item%s", title->quantity,
- title->quantity == 1? "" : "s");
- cprintf(")");
- if (can_travel)
- cprintf(" [ENTER - travel]");
- }
-}
-
-bool StashMenu::process_key(int key)
-{
- if (key == CK_ENTER)
- {
- // Travel activates.
- lastch = 1;
- return false;
- }
- return Menu::process_key(key);
-}
-
-static void stash_menu_fixup(MenuEntry *me)
-{
- const item_def *item = static_cast<const item_def *>( me->data );
- if (item->base_type == OBJ_GOLD)
- {
- me->quantity = 0;
- me->colour = DARKGREY;
- }
-}
-
-bool Stash::show_menu(const std::string &prefix, bool can_travel) const
-{
- StashMenu menu;
-
- MenuEntry *mtitle = new MenuEntry(" Stash (" + prefix);
- menu.can_travel = can_travel;
- mtitle->colour = WHITE;
- mtitle->quantity = items.size();
- menu.set_title(mtitle);
-
- populate_item_menu(&menu, items, stash_menu_fixup);
- std::vector<MenuEntry*> sel;
- while (true)
- {
- sel = menu.show();
- if (menu.getkey() == 1)
- return true;
-
- if (sel.size() != 1)
- break;
-
- const item_def *item =
- static_cast<const item_def *>( sel[0]->data );
- describe_item(*item);
- }
- return false;
-}
-
-std::string Stash::description() const
-{
- if (!enabled || items.empty())
- return ("");
-
- const item_def &item = items[0];
- std::string desc = stash_item_name(item);
-
- size_t sz = items.size();
- if (sz > 1)
- {
- char additionals[50];
- snprintf(additionals, sizeof additionals, " (+%lu)", (unsigned long) (sz - 1));
- desc += additionals;
- }
- return (desc);
-}
-
-bool Stash::matches_search(const std::string &prefix,
- const base_pattern &search,
- stash_search_result &res) const
-{
- if (!enabled || items.empty()) return false;
-
- for (unsigned i = 0; i < items.size(); ++i)
- {
- const item_def &item = items[i];
- std::string s = stash_item_name(item);
- std::string ann = stash_annotate_item(
- LUA_SEARCH_ANNOTATE, &item);
- if (search.matches(prefix + " " + ann + s))
- {
- if (!res.count++)
- res.match = s;
- res.matches += item.quantity;
- continue;
- }
-
- if (is_dumpable_artifact(item, Options.verbose_dump))
- {
- std::string desc = munge_description(get_item_description(item,
- Options.verbose_dump,
- true ));
- if (search.matches(desc))
- {
- if (!res.count++)
- res.match = s;
- res.matches += item.quantity;
- }
- }
- }
- if (res.matches)
- {
- res.stash = this;
- res.pos.x = x;
- res.pos.y = y;
- }
-
- return !!res.matches;
-}
-
-void Stash::write(std::ostream &os,
- int refx, int refy,
- std::string place,
- bool identify)
- const
-{
- if (!enabled || (items.size() == 0 && verified)) return;
- os << "(" << ((int) x - refx) << ", " << ((int) y - refy)
- << (place.length()? ", " + place : "")
- << ")"
- << std::endl;
-
- char buf[ITEMNAME_SIZE];
- for (int i = 0; i < (int) items.size(); ++i)
- {
- item_def item = items[i];
-
- if (identify)
- fully_identify_item(&item);
-
- std::string s = stash_item_name(item);
- strncpy(buf, s.c_str(), sizeof buf);
-
- std::string ann = userdef_annotate_item(
- LUA_DUMP_ANNOTATE, &item);
-
- if (!ann.empty())
- {
- trim_string(ann);
- ann = " " + ann;
- }
-
- os << " " << buf
- << (!ann.empty()? ann : std::string())
- << (!verified && (items.size() > 1 || i)? " (still there?)" : "")
- << std::endl;
-
- if (is_dumpable_artifact(item, Options.verbose_dump))
- {
- std::string desc = munge_description(get_item_description(item,
- Options.verbose_dump,
- true ));
- // Kill leading and trailing whitespace
- desc.erase(desc.find_last_not_of(" \n\t") + 1);
- desc.erase(0, desc.find_first_not_of(" \n\t"));
- // If string is not-empty, pad out to a neat indent
- if (desc.length())
- {
- // Walk backwards and prepend indenting spaces to \n characters
- for (int j = desc.length() - 1; j >= 0; --j)
- if (desc[j] == '\n')
- desc.insert(j + 1, " ");
- os << " " << desc << std::endl;
- }
- }
- }
-
- if (items.size() <= 1 && !verified)
- os << " (unseen)" << std::endl;
-}
-
-void Stash::save(FILE *file) const
-{
- // How many items on this square?
- writeShort(file, (short) items.size());
-
- writeByte(file, x);
- writeByte(file, y);
-
- // Note: Enabled save value is inverted logic, so that it defaults to true
- writeByte(file,
- (unsigned char) ((verified? 1 : 0) | (!enabled? 2 : 0)) );
-
- // And dump the items individually. We don't bother saving fields we're
- // not interested in (and don't anticipate being interested in).
- for (unsigned i = 0; i < items.size(); ++i)
- save_item(file, items[i]);
-}
-
-void Stash::load(FILE *file)
-{
- // How many items?
- int count = readShort(file);
-
- x = readByte(file);
- y = readByte(file);
-
- unsigned char flags = readByte(file);
- verified = (flags & 1) != 0;
-
- // Note: Enabled save value is inverted so it defaults to true.
- enabled = (flags & 2) == 0;
-
- abspos = GXM * (int) y + x;
-
- // Zap out item vector, in case it's in use (however unlikely)
- items.clear();
- // Read in the items
- for (int i = 0; i < count; ++i)
- {
- item_def item;
- load_item(file, item);
-
- items.push_back(item);
- }
-}
-
-std::ostream &operator << (std::ostream &os, const Stash &s)
-{
- s.write(os);
- return os;
-}
-
-ShopInfo::ShopInfo(int xp, int yp) : x(xp), y(yp), name(), shoptype(-1),
- visited(false), items()
-{
- // Most of our initialization will be done externally; this class is really
- // a mildly glorified struct.
- const shop_struct *sh = get_shop(x, y);
- if (sh)
- shoptype = sh->type;
-}
-
-ShopInfo::ShopId::ShopId(int stype) : shoptype(stype), id()
-{
- shop_init_id_type( shoptype, id );
-}
-
-ShopInfo::ShopId::~ShopId()
-{
- shop_uninit_id_type( shoptype, id );
-}
-
-void ShopInfo::add_item(const item_def &sitem, unsigned price)
-{
- shop_item it;
- it.item = sitem;
- it.price = price;
- items.push_back(it);
-}
-
-std::string ShopInfo::shop_item_name(const shop_item &si) const
-{
- char shopitem[ITEMNAME_SIZE * 2];
- std::string itemname = Stash::stash_item_name(si.item);
- snprintf(shopitem, sizeof shopitem, "%s (%u gold)",
- itemname.c_str(), si.price);
- return shopitem;
-}
-
-std::string ShopInfo::shop_item_desc(const shop_item &si) const
-{
- std::string desc;
- if (is_dumpable_artifact(si.item, Options.verbose_dump))
- {
- desc = munge_description(get_item_description(si.item,
- Options.verbose_dump,
- true));
-
- // trim leading whitespace
- std::string::size_type notwhite = desc.find_first_not_of(" \t\n");
- desc.erase(0, notwhite);
-
- // trim trailing whitespace
- notwhite = desc.find_last_not_of(" \t\n");
- desc.erase(notwhite + 1);
-
- // Walk backwards and prepend indenting spaces to \n characters
- for (int i = desc.length() - 1; i >= 0; --i)
- if (desc[i] == '\n')
- desc.insert(i + 1, " ");
- }
- return desc;
-}
-
-void ShopInfo::describe_shop_item(const shop_item &si) const
-{
- describe_item( si.item );
-}
-
-bool ShopInfo::show_menu(const std::string &place,
- bool can_travel) const
-{
- ShopId id(shoptype);
- StashMenu menu;
-
- MenuEntry *mtitle = new MenuEntry(" " + name + " (" + place);
- menu.can_travel = can_travel;
- mtitle->colour = WHITE;
- mtitle->quantity = items.size();
- menu.set_title(mtitle);
-
- menu_letter hotkey;
- if (items.empty())
- {
- MenuEntry *me = new MenuEntry(
- visited? " (Shop is empty)" : " (Shop contents are unknown)",
- MEL_ITEM,
- 0,
- 0);
- me->colour = DARKGREY;
- menu.add_entry(me);
- }
- else
- {
- for (int i = 0, count = items.size(); i < count; ++i)
- {
- MenuEntry *me = new MenuEntry(shop_item_name(items[i]),
- MEL_ITEM,
- 1,
- hotkey++);
- me->data = const_cast<shop_item *>( &items[i] );
- menu.add_entry(me);
- }
- }
-
- std::vector<MenuEntry*> sel;
- while (true)
- {
- sel = menu.show();
- if (menu.getkey() == 1)
- return true;
-
- if (sel.size() != 1)
- break;
-
- const shop_item *item =
- static_cast<const shop_item *>( sel[0]->data );
- describe_shop_item(*item);
- }
- return false;
-}
-
-std::string ShopInfo::description() const
-{
- return (name);
-}
-
-bool ShopInfo::matches_search(const std::string &prefix,
- const base_pattern &search,
- stash_search_result &res) const
-{
- if (items.empty() && visited) return false;
-
- ShopId id(shoptype);
- bool match = false;
-
- for (unsigned i = 0; i < items.size(); ++i)
- {
- std::string name = shop_item_name(items[i]);
- std::string ann = stash_annotate_item(
- LUA_SEARCH_ANNOTATE, &items[i].item, true);
-
- bool thismatch = false;
- if (search.matches(prefix + " " + ann + name))
- thismatch = true;
- else
- {
- std::string desc = shop_item_desc(items[i]);
- if (search.matches(desc))
- thismatch = true;
- }
-
- if (thismatch)
- {
- if (!res.count++)
- res.match = name;
- res.matches++;
- }
- }
-
- if (!res.matches)
- {
- std::string shoptitle = prefix + " {shop} " + name;
- if (!visited && items.empty())
- shoptitle += "*";
- if (search.matches(shoptitle))
- {
- match = true;
- res.match = name;
- }
- }
-
- if (match || res.matches)
- {
- res.shop = this;
- res.pos.x = x;
- res.pos.y = y;
- }
-
- return match || res.matches;
-}
-
-void ShopInfo::write(std::ostream &os, bool identify) const
-{
- ShopId id(shoptype);
-
- os << "[Shop] " << name << std::endl;
- if (items.size() > 0)
- {
- for (unsigned i = 0; i < items.size(); ++i)
- {
- shop_item item = items[i];
-
- if (identify)
- fully_identify_item(&item.item);
-
- os << " " << shop_item_name(item) << std::endl;
- std::string desc = shop_item_desc(item);
- if (desc.length() > 0)
- os << " " << desc << std::endl;
- }
- }
- else if (visited)
- os << " (Shop is empty)" << std::endl;
- else
- os << " (Shop contents are unknown)" << std::endl;
-}
-
-void ShopInfo::save(FILE *file) const
-{
- writeShort(file, shoptype);
-
- int mangledx = (short) x;
- if (!visited)
- mangledx |= 1024;
- writeShort(file, mangledx);
- writeShort(file, (short) y);
-
- writeShort(file, (short) items.size());
-
- writeString(file, name);
-
- for (unsigned i = 0; i < items.size(); ++i)
- {
- save_item(file, items[i].item);
- writeShort(file, (short) items[i].price );
- }
-}
-
-void ShopInfo::load(FILE *file)
-{
- shoptype = readShort(file);
-
- x = readShort(file);
- visited = !(x & 1024);
- x &= 0xFF;
-
- y = readShort(file);
-
- int itemcount = readShort(file);
-
- name = readString(file);
- for (int i = 0; i < itemcount; ++i)
- {
- shop_item item;
- load_item(file, item.item);
- item.price = (unsigned) readShort(file);
- items.push_back(item);
- }
-}
-
-std::ostream &operator << (std::ostream &os, const ShopInfo &s)
-{
- s.write(os);
- return os;
-}
-
-LevelStashes::LevelStashes()
-{
- branch = you.where_are_you;
- depth = you.your_level;
-}
-
-bool LevelStashes::operator < (const LevelStashes &lev) const
-{
- return branch < lev.branch || (branch == lev.branch && depth < lev.depth);
-}
-
-bool LevelStashes::isBelowPlayer() const
-{
- return branch > you.where_are_you
- || (branch == you.where_are_you && depth > you.your_level);
-}
-
-Stash *LevelStashes::find_stash(int x, int y)
-{
- if (x == -1 || y == -1)
- {
- x = you.x_pos;
- y = you.y_pos;
- }
- const int abspos = (GXM * y) + x;
- c_stashes::iterator st = stashes.find(abspos);
- return (st == stashes.end()? NULL : &st->second);
-}
-
-const ShopInfo *LevelStashes::find_shop(int x, int y) const
-{
- for (unsigned i = 0; i < shops.size(); ++i)
- {
- if (shops[i].isAt(x, y))
- return (&shops[i]);
- }
- return (NULL);
-}
-
-ShopInfo &LevelStashes::get_shop(int x, int y)
-{
- for (unsigned i = 0; i < shops.size(); ++i)
- {
- if (shops[i].isAt(x, y))
- return shops[i];
- }
- ShopInfo si(x, y);
- si.set_name(shop_name(x, y));
- shops.push_back(si);
- return get_shop(x, y);
-}
-
-// Updates the stash at (x,y). Returns true if there was a stash at (x,y), false
-// otherwise.
-bool LevelStashes::update_stash(int x, int y)
-{
- Stash *s = find_stash(x, y);
- if (s)
- {
- s->update();
- if (s->empty())
- kill_stash(*s);
- return true;
- }
- return false;
-}
-
-// Removes a Stash from the level.
-void LevelStashes::kill_stash(const Stash &s)
-{
- stashes.erase(s.abs_pos());
-}
-
-void LevelStashes::no_stash(int x, int y)
-{
- Stash *s = find_stash(x, y);
- bool en = false;
- if (s)
- {
- en = s->enabled = !s->enabled;
- s->update();
- if (s->empty())
- kill_stash(*s);
- }
- else
- {
- Stash newStash(x, y);
- newStash.enabled = false;
-
- stashes[ newStash.abs_pos() ] = newStash;
- }
-
- mpr(en? "I'll no longer ignore what I see on this square."
- : "Ok, I'll ignore what I see on this square.");
-}
-
-void LevelStashes::add_stash(int x, int y)
-{
- Stash *s = find_stash(x, y);
- if (s)
- {
- s->update();
- if (s->empty())
- kill_stash(*s);
- }
- else
- {
- Stash newStash(x, y);
- if (!newStash.empty())
- stashes[ newStash.abs_pos() ] = newStash;
- }
-}
-
-bool LevelStashes::isCurrent() const
-{
- return branch == you.where_are_you && depth == you.your_level;
-}
-
-bool LevelStashes::in_hell() const
-{
- return branch >= BRANCH_DIS
- && branch <= BRANCH_THE_PIT
- && branch != BRANCH_VESTIBULE_OF_HELL;
-}
-
-bool LevelStashes::in_branch(int branchid) const
-{
- return branch == branchid;
-}
-
-
-std::string LevelStashes::level_name() const
-{
- int curr_subdungeon_level = subdungeon_depth( branch, depth );
- return (branch_level_name(branch, curr_subdungeon_level));
-}
-
-std::string LevelStashes::short_level_name() const
-{
- return (short_place_name(
- get_packed_place( branch,
- subdungeon_depth( branch, depth ),
- LEVEL_DUNGEON ) ));
-}
-
-int LevelStashes::count_stashes() const
-{
- int rawcount = stashes.size();
- if (!rawcount)
- return (0);
-
- for (c_stashes::const_iterator iter = stashes.begin();
- iter != stashes.end(); iter++)
- {
- if (!iter->second.enabled)
- --rawcount;
- }
- return rawcount;
-}
-
-void LevelStashes::get_matching_stashes(
- const base_pattern &search,
- std::vector<stash_search_result> &results)
- const
-{
- level_id clid(branch, subdungeon_depth(branch, depth));
- std::string lplace = "{" + short_place_name(clid) + "}";
- for (c_stashes::const_iterator iter = stashes.begin();
- iter != stashes.end(); iter++)
- {
- if (iter->second.enabled)
- {
- stash_search_result res;
- if (iter->second.matches_search(lplace, search, res))
- {
- res.level = clid;
- results.push_back(res);
- }
- }
- }
-
- for (unsigned i = 0; i < shops.size(); ++i)
- {
- stash_search_result res;
- if (shops[i].matches_search(lplace, search, res))
- {
- res.level = clid;
- results.push_back(res);
- }
- }
-}
-
-void LevelStashes::write(std::ostream &os, bool identify) const
-{
- if (visible_stash_count() == 0) return ;
- os << level_name() << std::endl;
-
- for (unsigned i = 0; i < shops.size(); ++i)
- {
- shops[i].write(os, identify);
- }
-
- if (stashes.size())
- {
- const Stash &s = stashes.begin()->second;
- int refx = s.getX(), refy = s.getY();
- std::string level_name = short_level_name();
- for (c_stashes::const_iterator iter = stashes.begin();
- iter != stashes.end(); iter++)
- {
- iter->second.write(os, refx, refy, level_name, identify);
- }
- }
- os << std::endl;
-}
-
-void LevelStashes::save(FILE *file) const
-{
- // How many stashes on this level?
- writeShort(file, (short) stashes.size());
-
- writeByte(file, branch);
- writeShort(file, (short) depth);
-
- // And write the individual stashes
- for (c_stashes::const_iterator iter = stashes.begin();
- iter != stashes.end(); iter++)
- iter->second.save(file);
-
- writeShort(file, (short) shops.size());
- for (unsigned i = 0; i < shops.size(); ++i)
- shops[i].save(file);
-}
-
-void LevelStashes::load(FILE *file)
-{
- int size = readShort(file);
-
- branch = readByte(file);
- depth = readShort(file);
-
- stashes.clear();
- for (int i = 0; i < size; ++i)
- {
- Stash s;
- s.load(file);
- if (!s.empty())
- stashes[ s.abs_pos() ] = s;
- }
-
- shops.clear();
- int shopc = readShort(file);
- for (int i = 0; i < shopc; ++i)
- {
- ShopInfo si(0, 0);
- si.load(file);
- shops.push_back(si);
- }
-}
-
-std::ostream &operator << (std::ostream &os, const LevelStashes &ls)
-{
- ls.write(os);
- return os;
-}
-
-LevelStashes &StashTracker::get_current_level()
-{
- std::vector<LevelStashes>::iterator iter = levels.begin();
- for ( ; iter != levels.end() && !iter->isBelowPlayer(); iter++)
- {
- if (iter->isCurrent()) return *iter;
- }
- if (iter == levels.end())
- levels.push_back(LevelStashes());
- else
- levels.insert(iter, LevelStashes());
- return get_current_level();
-}
-
-LevelStashes *StashTracker::find_current_level()
-{
- std::vector<LevelStashes>::iterator iter = levels.begin();
- for ( ; iter != levels.end() && !iter->isBelowPlayer(); iter++)
- {
- if (iter->isCurrent()) return &*iter;
- }
- return NULL;
-}
-
-
-bool StashTracker::update_stash(int x, int y)
-{
- LevelStashes *lev = find_current_level();
- if (lev)
- {
- bool res = lev->update_stash(x, y);
- if (!lev->stash_count())
- remove_level(*lev);
- return res;
- }
- return false;
-}
-
-void StashTracker::remove_level(const LevelStashes &ls)
-{
- std::vector<LevelStashes>::iterator iter = levels.begin();
- for ( ; iter != levels.end(); ++iter)
- {
- if (&ls == &*iter)
- {
- levels.erase(iter);
- break ;
- }
- }
-}
-
-void StashTracker::no_stash(int x, int y)
-{
- if (is_level_untrackable())
- return ;
- LevelStashes &current = get_current_level();
- current.no_stash(x, y);
- if (!current.stash_count())
- remove_level(current);
-}
-
-void StashTracker::add_stash(int x, int y, bool verbose)
-{
- if (is_level_untrackable())
- return ;
- LevelStashes &current = get_current_level();
- current.add_stash(x, y);
-
- if (verbose)
- {
- Stash *s = current.find_stash(x, y);
- if (s && s->enabled)
- mpr("Added stash.");
- }
-
- if (!current.stash_count())
- remove_level(current);
-}
-
-void StashTracker::dump(const char *filename, bool identify) const
-{
- std::ofstream outf(filename);
- if (outf)
- {
- write(outf, identify);
- outf.close();
- }
-}
-
-void StashTracker::write(std::ostream &os, bool identify) const
-{
- os << you.your_name << std::endl << std::endl;
- if (!levels.size())
- os << " You have no stashes." << std::endl;
- else
- {
- std::vector<LevelStashes>::const_iterator iter = levels.begin();
- for ( ; iter != levels.end(); iter++)
- {
- iter->write(os, identify);
- }
- }
-}
-
-void StashTracker::save(FILE *file) const
-{
- // Write version info first - major + minor
- writeByte(file, ST_MAJOR_VER);
- writeByte(file, ST_MINOR_VER);
-
- // How many levels have we?
- writeShort(file, (short) levels.size());
-
- // And ask each level to write itself to the tag
- std::vector<LevelStashes>::const_iterator iter = levels.begin();
- for ( ; iter != levels.end(); iter++)
- iter->save(file);
-}
-
-void StashTracker::load(FILE *file)
-{
- // Check version. Compatibility isn't important, since stash-tracking
- // is non-critical.
- unsigned char major = readByte(file),
- minor = readByte(file);
- if (major != ST_MAJOR_VER || minor != ST_MINOR_VER) return ;
-
- int count = readShort(file);
-
- levels.clear();
- for (int i = 0; i < count; ++i)
- {
- LevelStashes st;
- st.load(file);
- if (st.stash_count()) levels.push_back(st);
- }
-}
-
-void StashTracker::update_visible_stashes(
- StashTracker::stash_update_mode mode)
-{
- if (is_level_untrackable())
- return ;
-
- LevelStashes *lev = find_current_level();
- for (int cy = 1; cy <= 17; ++cy)
- {
- for (int cx = 9; cx <= 25; ++cx)
- {
- int x = you.x_pos + cx - 17, y = you.y_pos + cy - 9;
- if (x < 0 || x >= GXM || y < 0 || y >= GYM)
- continue;
-
- if (!env.show[cx - 8][cy] && !(cx == 17 && cy == 9))
- continue;
-
- if ((!lev || !lev->update_stash(x, y))
- && mode == ST_AGGRESSIVE
- && igrd[x][y] != NON_ITEM)
- {
- if (!lev)
- lev = &get_current_level();
- lev->add_stash(x, y);
- }
-
- if (grd[x][y] == DNGN_ENTER_SHOP)
- get_shop(x, y);
- }
- }
-
- if (lev && !lev->stash_count())
- remove_level(*lev);
-}
-
-#define SEARCH_SPAM_THRESHOLD 400
-static std::string lastsearch;
-static input_history search_history(15);
-
-void StashTracker::search_stashes()
-{
- char prompt[200];
- if (lastsearch.length())
- snprintf(prompt, sizeof prompt,
- "Search your stashes for what item [Enter for \"%s\"]?",
- lastsearch.c_str());
- else
- snprintf(prompt, sizeof prompt,
- "Search your stashes for what item?");
-
- mpr(prompt, MSGCH_PROMPT);
- // Push the cursor down to the next line.
- mpr("", MSGCH_PROMPT);
-
- char buf[400];
- bool validline = cancelable_get_line(buf, sizeof buf, 80, &search_history);
- mesclr();
- if (!validline || (!*buf && !lastsearch.length()))
- return;
-
- std::string csearch = *buf? buf : lastsearch;
- std::vector<stash_search_result> results;
-
- base_pattern *search = NULL;
-
- text_pattern tpat( csearch, true );
- search = &tpat;
-
-#ifdef CLUA_BINDINGS
- lua_text_pattern ltpat( csearch );
-
- if (lua_text_pattern::is_lua_pattern(csearch))
- search = &ltpat;
-#endif
-
- if (!search->valid())
- {
- mpr("Your search expression is invalid.", MSGCH_PLAIN);
- return ;
- }
-
- lastsearch = csearch;
-
- get_matching_stashes(*search, results);
-
- if (results.empty())
- {
- mpr("That item is not present in any of your stashes.",
- MSGCH_PLAIN);
- return;
- }
-
- if (results.size() > SEARCH_SPAM_THRESHOLD)
- {
- mpr("Too many matches; use a more specific search.", MSGCH_PLAIN);
- return ;
- }
-
- display_search_results(results);
-}
-
-void StashTracker::get_matching_stashes(
- const base_pattern &search,
- std::vector<stash_search_result> &results)
- const
-{
- std::vector<LevelStashes>::const_iterator iter = levels.begin();
- for ( ; iter != levels.end(); iter++)
- {
- iter->get_matching_stashes(search, results);
- if (results.size() > SEARCH_SPAM_THRESHOLD)
- return;
- }
-
- level_id curr = level_id::get_current_level_id();
- for (unsigned i = 0; i < results.size(); ++i)
- {
- results[i].player_distance = level_distance(curr, results[i].level);
- }
-
- // Sort stashes so that closer stashes come first and stashes on the same
- // levels with more items come first.
- std::sort(results.begin(), results.end());
-}
-
-class StashSearchMenu : public Menu
-{
-public:
- StashSearchMenu() : Menu(), can_travel(true), meta_key(0) { }
-
-public:
- bool can_travel;
- int meta_key;
-
-protected:
- bool process_key(int key);
- void draw_title();
-};
-
-void StashSearchMenu::draw_title()
-{
- if (title)
- {
- gotoxy(1, 1);
- textcolor(title->colour);
- cprintf(" %d %s%s", title->quantity, title->text.c_str(),
- title->quantity > 1? "es" : "");
-
- if (meta_key)
- draw_title_suffix(" (x - examine stash)", false);
- else
- draw_title_suffix(" (x - go to stash; ? - examine stash)", false);
- }
-}
-
-bool StashSearchMenu::process_key(int key)
-{
- if (key == '?')
- {
- if (sel)
- sel->clear();
- meta_key = !meta_key;
- update_title();
- return true;
- }
-
- return Menu::process_key(key);
-}
-
-void StashTracker::display_search_results(
- std::vector<stash_search_result> &results)
-{
- if (results.empty())
- return;
-
- bool travelable = can_travel_interlevel();
-
- StashSearchMenu stashmenu;
- stashmenu.can_travel = travelable;
- std::string title = "matching stash";
-
- MenuEntry *mtitle = new MenuEntry(title);
- mtitle->colour = WHITE;
- // Abuse of the quantity field.
- mtitle->quantity = results.size();
- stashmenu.set_title(mtitle);
-
- menu_letter hotkey;
- for (unsigned i = 0; i < results.size(); ++i, ++hotkey)
- {
- stash_search_result &res = results[i];
- char matchtitle[ITEMNAME_SIZE];
- std::string place = short_place_name(res.level);
- if (res.matches > 1 && res.count > 1)
- {
- snprintf(matchtitle, sizeof matchtitle,
- "[%s] %s (%d)",
- place.c_str(),
- res.match.c_str(),
- res.matches);
- }
- else
- {
- snprintf(matchtitle, sizeof matchtitle,
- "[%s] %s",
- place.c_str(),
- res.match.c_str());
- }
- std::string mename = matchtitle;
-
- MenuEntry *me = new MenuEntry(mename, MEL_ITEM, 1, hotkey);
- me->data = &res;
- if (res.shop && !res.shop->is_visited())
- me->colour = CYAN;
- stashmenu.add_entry(me);
- }
-
- stashmenu.set_flags( MF_SINGLESELECT );
-
- std::vector<MenuEntry*> sel;
- while (true)
- {
- sel = stashmenu.show();
-
- if (sel.size() == 1 && stashmenu.meta_key)
- {
- stash_search_result *res =
- static_cast<stash_search_result *>(sel[0]->data);
-
- bool dotravel = false;
- if (res->shop)
- {
- dotravel = res->shop->show_menu(short_place_name(res->level),
- travelable);
- }
- else if (res->stash)
- {
- dotravel = res->stash->show_menu(short_place_name(res->level),
- travelable);
- }
-
- if (dotravel && travelable)
- {
- redraw_screen();
- level_pos lp;
- lp.id = res->level;
- lp.pos = res->pos;
- start_translevel_travel(lp);
- return ;
- }
- continue;
- }
- break;
- }
-
- redraw_screen();
- if (travelable && sel.size() == 1 && !stashmenu.meta_key)
- {
- const stash_search_result *res =
- static_cast<stash_search_result *>(sel[0]->data);
- level_pos lp;
- lp.id = res->level;
- lp.pos = res->pos;
- start_translevel_travel(lp);
- return ;
- }
-
-}
-
-// Global
-StashTracker stashes;
-
-#endif
-
-std::string branch_level_name(unsigned char branch, int sub_depth)
-{
- int ltype = sub_depth == 0xFF? branch : 0;
- if (ltype == LEVEL_PANDEMONIUM)
- return ("Pandemonium");
- else if (ltype == LEVEL_ABYSS)
- return ("The Abyss");
- else if (ltype == LEVEL_LABYRINTH)
- return ("A Labyrinth");
- else
- {
- char buf[200];
- const char *s = NULL;
- *buf = 0;
- // level_type == LEVEL_DUNGEON
- if (branch != BRANCH_VESTIBULE_OF_HELL
- && branch != BRANCH_ECUMENICAL_TEMPLE
- && branch != BRANCH_HALL_OF_BLADES)
- snprintf(buf, sizeof buf, "Level %d", sub_depth);
-
- switch (branch)
- {
- case BRANCH_MAIN_DUNGEON:
- s = " of the Dungeon";
- break;
- case BRANCH_DIS:
- s = " of Dis";
- break;
- case BRANCH_GEHENNA:
- s = " of Gehenna";
- break;
- case BRANCH_VESTIBULE_OF_HELL:
- s = "The Vestibule of Hell";
- break;
- case BRANCH_COCYTUS:
- s = " of Cocytus";
- break;
- case BRANCH_TARTARUS:
- s = " of Tartarus";
- break;
- case BRANCH_INFERNO:
- s = " of the Inferno";
- break;
- case BRANCH_THE_PIT:
- s = " of the Pit";
- break;
- case BRANCH_ORCISH_MINES:
- s = " of the Orcish Mines";
- break;
- case BRANCH_HIVE:
- s = " of the Hive";
- break;
- case BRANCH_LAIR:
- s = " of the Lair";
- break;
- case BRANCH_SLIME_PITS:
- s = " of the Slime Pits";
- break;
- case BRANCH_VAULTS:
- s = " of the Vaults";
- break;
- case BRANCH_CRYPT:
- s = " of the Crypt";
- break;
- case BRANCH_HALL_OF_BLADES:
- s = "The Hall of Blades";
- break;
- case BRANCH_HALL_OF_ZOT:
- s = " of the Realm of Zot";
- break;
- case BRANCH_ECUMENICAL_TEMPLE:
- s = "The Ecumenical Temple";
- break;
- case BRANCH_SNAKE_PIT:
- s = " of the Snake Pit";
- break;
- case BRANCH_ELVEN_HALLS:
- s = " of the Elven Halls";
- break;
- case BRANCH_TOMB:
- s = " of the Tomb";
- break;
- case BRANCH_SWAMP:
- s = " of the Swamp";
- break;
- }
- if (s)
- strncat(buf, s, sizeof(buf) - 1);
- return (buf);
- }
-}
-
-std::string branch_level_name(unsigned short packed_place)
-{
- return branch_level_name(packed_place >> 8, packed_place & 0xFF);
-}