/* * File: stash.h * Summary: Classes tracking player stashes * Written by: Darshan Shaligram */ #ifndef STASH_H #define STASH_H #include "shopping.h" #include #include #include #include #include "externs.h" #include "player.h" class input_history; class reader; class writer; class StashMenu; // Stash definitions void stash_init_new_level(); enum STASH_TRACK_MODES { STM_NONE, // Stashes are not tracked STM_EXPLICIT, // Only explicitly marked stashes are tracked STM_DROPPED, // Dropped items and explicitly marked stashes are // tracked STM_ALL // All seen items are tracked }; struct stash_search_result; class Stash { public: Stash(int xp = -1, int yp = -1); static bool is_boring_feature(dungeon_feature_type feat); static void filter(object_class_type base_type, unsigned char sub_type); static void filter(const std::string &filt); static std::string stash_item_name(const item_def &item); void update(); void save(writer&) const; void load(reader&); std::string description() const; std::string feature_description() const; std::vector get_items() const; bool show_menu(const level_pos &place, bool can_travel) const; // Returns true if this Stash contains items that are eligible for // autopickup. bool pickup_eligible() const; // Returns true if this Stash is unverified (a visit by the character will // verify the stash). bool unverified() const; bool matches_search(const std::string &prefix, const base_pattern &search, stash_search_result &res) const; void write(std::ostream &os, int refx = 0, int refy = 0, std::string place = "", bool identify = false) const; bool empty() const { return enabled && items.empty() && feat == DNGN_FLOOR; } bool isAt(int xp, int yp) const { return x == xp && y == yp; } int abs_pos() const { return abspos; } int getX() const { return x; } int getY() const { return y; } bool is_verified() const { return verified; } bool enabled; // If false, this Stash will neither track // items nor dump itself. Disabled stashes are // also never removed from the level's map of // stashes. private: void _update_corpses(long rot_time); void add_item(const item_def &item, bool add_to_front = false); private: bool verified; // Is this correct to the best of our knowledge? unsigned char x, y; int abspos; dungeon_feature_type feat; trap_type trap; std::vector items; /* * If true (the default), the stash-tracker is a lot more likely to consider * squares that the player is not standing on as correctly-verified. This * will lead to cleaner dumps, but the chance of stashes not accurately * reflecting what's in the dungeon also increases. */ static bool aggressive_verify; static std::vector filters; static bool are_items_same(const item_def &, const item_def &); static bool is_filtered(const item_def &item); friend class LevelStashes; friend class ST_ItemIterator; }; class ShopInfo { public: ShopInfo(int xp, int yp); bool matches_search(const std::string &prefix, const base_pattern &search, stash_search_result &res) const; std::string description() const; void save(writer&) const; void load(reader&); bool show_menu(const level_pos &place, bool can_travel) const; bool is_visited() const { return items.size() || visited; } void write(std::ostream &os, bool identify = false) const; void reset() { items.clear(); visited = true; } void set_name(const std::string& s) { name = s; } void add_item(const item_def &item, unsigned price); bool isAt(int xp, int yp) const { return x == xp && y == yp; } // Messy! struct shop_item { item_def item; unsigned price; }; private: int x, y; std::string name; int shoptype; // Set true if the player has visited this shop bool visited; std::vector items; std::string shop_item_name(const shop_item &si) const; std::string shop_item_desc(const shop_item &si) const; void describe_shop_item(const shop_item &si) const; void fill_out_menu(StashMenu &menu, const level_pos &place) const; friend class ST_ItemIterator; }; struct stash_search_result { // Where's this thingummy of interest. level_pos pos; // Number of levels the player must cross to reach the level the stash/shop // is on. int player_distance; // Number of items in the stash that match the search. int matches; // Count of items stacks in the stash that matched. This will be the same as // matches if each matching stack's quantity is 1. int count; // Text that describes this search result - usually the name of // the first matching item in the stash or the name of the shop. std::string match; // The stash or shop in question. Both can be null if this is a feature. const Stash *stash; const ShopInfo *shop; stash_search_result() : pos(), player_distance(0), matches(0), count(0), match(), stash(NULL), shop(NULL) { } bool operator < (const stash_search_result &ssr) const { return (player_distance < ssr.player_distance || (player_distance == ssr.player_distance && matches > ssr.matches)); } }; extern std::ostream &operator << (std::ostream &, const Stash &); class LevelStashes { public: LevelStashes(); Stash *find_stash(int x = -1, int y = -1); const Stash *find_stash(int x = -1, int y = -1) const; ShopInfo &get_shop(int x, int y); const ShopInfo *find_shop(int x, int y) const; level_id where() const; void get_matching_stashes(const base_pattern &search, std::vector &results) const; // Update stash at (x,y) on current level, defaulting to player's current // location if no parameters are supplied. bool update_stash(int x = -1, int y = -1); // Returns true if the square at (x,y) contains potentially interesting // swag that merits a personal visit (for EXPLORE_GREEDY). bool needs_visit(int x, int y) const; bool needs_visit(const coord_def& c) const { return needs_visit(c.x, c.y); } bool shop_needs_visit(int x, int y) const; bool shop_needs_visit(const coord_def& c) const { return shop_needs_visit(c.x, c.y); } // Add stash at (x,y), or player's current location if no parameters are // supplied void add_stash(int x = -1, int y = -1); // Mark square (x,y) as not stashworthy. The player's current location is // used if no parameters are supplied. void no_stash(int x = -1, int y = -1); void kill_stash(const Stash &s); void save(writer&) const; void load(reader&); void write(std::ostream &os, bool identify = false) const; std::string level_name() const; std::string short_level_name() const; int stash_count() const { return m_stashes.size() + m_shops.size(); } int visible_stash_count() const { return _num_enabled_stashes() + m_shops.size(); } bool is_current() const; private: int _num_enabled_stashes() const; void _update_corpses(long rot_time); private: typedef std::map stashes_t; typedef std::vector shops_t; // which level level_id m_place; stashes_t m_stashes; shops_t m_shops; friend class StashTracker; friend class ST_ItemIterator; }; extern std::ostream &operator << (std::ostream &, const LevelStashes &); class StashTracker { public: static bool is_level_untrackable() { return you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS; } StashTracker() : levels(), last_corpse_update(0.0) { } void search_stashes(); LevelStashes &get_current_level(); LevelStashes *find_current_level(); LevelStashes *find_level(const level_id &pos); ShopInfo &get_shop(int x, int y) { return get_current_level().get_shop(x, y); } ShopInfo &get_shop(const coord_def& p) { return get_shop(p.x, p.y); } void remove_level(const level_id &which = level_id::current()); enum stash_update_mode { ST_PASSIVE, // Maintain existing stashes only. ST_AGGRESSIVE // Create stashes for each square containing // objects, even if those squares were not // previously marked as stashes. }; void update_corpses(); void update_visible_stashes(StashTracker::stash_update_mode = ST_PASSIVE); // Update stash at (x,y) on current level, defaulting to player's current // location if no parameters are supplied, return true if a stash was // updated. bool update_stash(int x = -1, int y = -1); // Add stash at (x,y), or player's current location if no parameters are // supplied void add_stash(int x = -1, int y = -1, bool verbose = false); // Mark square (x,y) as not stashworthy. The player's current location is // used if no parameters are supplied. void no_stash(int x = -1, int y = -1); void save(writer&) const; void load(reader&); void write(std::ostream &os, bool identify = false) const; void dump(const char *filename, bool identify = false) const; private: void get_matching_stashes(const base_pattern &search, std::vector &results) const; bool display_search_results(std::vector &results, const char* sort_style); void show_stash_search_prompt(); private: typedef std::map stash_levels_t; stash_levels_t levels; double last_corpse_update; friend class ST_ItemIterator; }; class ST_ItemIterator { public: ST_ItemIterator(); const ST_ItemIterator& operator ++ (); ST_ItemIterator operator ++ (int); operator bool() const; const item_def& operator *() const; const item_def* operator->() const; const level_id &place(); const ShopInfo* shop(); const unsigned price(); private: level_id m_place; const item_def* m_item; unsigned m_price; const ShopInfo* m_shop; StashTracker::stash_levels_t::const_iterator m_stash_level_it; LevelStashes::stashes_t::const_iterator m_stash_it; LevelStashes::shops_t::const_iterator m_shop_it; std::vector::const_iterator m_stash_item_it; std::vector::const_iterator m_shop_item_it; private: void new_level(); }; extern StashTracker StashTrack; void maybe_update_stashes(); bool is_stash(int x, int y); inline bool is_stash( const coord_def& p ) { return is_stash(p.x, p.y); } std::string get_stash_desc(int x, int y); void describe_stash(int x, int y); std::vector item_list_in_stash( coord_def pos ); std::string userdef_annotate_item(const char *s, const item_def *item, bool exclusive = false); #define STASH_LUA_SEARCH_ANNOTATE "ch_stash_search_annotate_item" #define STASH_LUA_DUMP_ANNOTATE "ch_stash_dump_annotate_item" #define STASH_LUA_VIEW_ANNOTATE "ch_stash_view_annotate_item" #endif