From: Jude B. <boo...@us...> - 2009-11-29 08:19:18
|
via 4ce958ff4e501a3d6086a87627a172d3ebe237c0 (commit) via c6f75d72f4d5d25dddd7f1e9116c40f4224fc3c6 (commit) via 5556ce4cdeb19a2219a1f93383228d24c360c3a4 (commit) via 2af84a1dc526c634dd29f3b5f87299c8e026b110 (commit) via 0680cf8d68d7f51d7e8e2a52d03afe3e555bb8d4 (commit) via 7331ae20d3259b55b042076ccec32e046c34cf46 (commit) via a16f7fef47a16d4231b01c3d283dff75454c67cb (commit) via 2943dc2999832721dddb7a591a927e9eb2eb4976 (commit) via e44ce374c8feff8cd3a7848195e2aa851d5ff971 (commit) from d7694dcce0f20a79daee12add342f4e353cdd1da (commit) ----------------------------------------------------------------------- commit 4ce958ff4e501a3d6086a87627a172d3ebe237c0 Merge: c6f75d72f4d5d25dddd7f1e9116c40f4224fc3c6 5556ce4cdeb19a2219a1f93383228d24c360c3a4 Author: Jude Brown <boo...@us...> Date: Sun Nov 29 18:18:57 2009 +1000 Merge branch 'master' into wizlab commit c6f75d72f4d5d25dddd7f1e9116c40f4224fc3c6 Author: Jude Brown <boo...@us...> Date: Sun Nov 29 18:18:27 2009 +1000 Resolve Tukima secret door issue (dpeg). Hopefully this at least gives an indication of there being a secret treasure room. It doesn't actually tell you where to look, but it's a hint. ----------------------------------------------------------------------- Summary of changes: crawl-ref/source/dat/clua/iter.lua | 211 ++++++++++++++++++++++++---- crawl-ref/source/dat/database/monspeak.txt | 2 +- crawl-ref/source/dat/uniques.des | 24 ++-- crawl-ref/source/dat/wizlab.des | 2 +- crawl-ref/source/dungeon.cc | 18 ++- crawl-ref/source/shopping.cc | 91 +++++++----- crawl-ref/source/shopping.h | 3 + 7 files changed, 267 insertions(+), 84 deletions(-) diff --git a/crawl-ref/source/dat/clua/iter.lua b/crawl-ref/source/dat/clua/iter.lua index f9371d8..b7bf9bc 100644 --- a/crawl-ref/source/dat/clua/iter.lua +++ b/crawl-ref/source/dat/clua/iter.lua @@ -21,6 +21,31 @@ iter = {} ------------------------------------------------------------------------------ +-- generic filters for use with iterators +-- these always need to be used with 'rvi', and any filter that acts on them +-- is assumed to as well (but only return a point) +------------------------------------------------------------------------------ + +function iter.monster_filter (filter) + local function filter_fn (point) + if filter ~= nil then + if filter(point) == nil then + return nil + else + point = filter(point) + end + end + + if not dgn.in_bounds(point.x, point.y) then + return nil + end + + return dgn.mons_at(point.x, point.y) + end + return filter_fn +end + +------------------------------------------------------------------------------ -- rectangle_iterator ------------------------------------------------------------------------------ iter.rectangle_iterator = {} @@ -32,7 +57,7 @@ function iter.rectangle_iterator:_new () return m end -function iter.rectangle_iterator:new (corner1, corner2, filter) +function iter.rectangle_iterator:new (corner1, corner2, filter, rvi) if corner1 == nil or corner2 == nil then error("need two corners to a rectangle") end @@ -51,6 +76,7 @@ function iter.rectangle_iterator:new (corner1, corner2, filter) mt.cur_x = corner1.x - 1 mt.cur_y = corner1.y mt.filter = filter or nil + mt.rvi = rvi or false return mt:iter() end @@ -64,15 +90,15 @@ function iter.rectangle_iterator:next() if self.cur_y > self.max_y then point = -1 else - point = dgn.point(self.cur_x, self.cur_y) - if not self:check_filter(point) then + point = self:check_filter(dgn.point(self.cur_x, self.cur_y)) + if point == nil then point = -2 end end else self.cur_x = self.cur_x + 1 - point = dgn.point(self.cur_x, self.cur_y) - if not self:check_filter(point) then + point = self:check_filter(dgn.point(self.cur_x, self.cur_y)) + if point == nil then point = -2 end end @@ -89,12 +115,16 @@ end function iter.rectangle_iterator:check_filter(point) if self.filter ~= nil then if self.filter(point) then - return true + if self.rvi then + return self.filter(point) + else + return point + end else - return false + return nil end else - return true + return point end end @@ -102,53 +132,74 @@ function iter.rectangle_iterator:iter () return function() return self:next() end, nil, nil end -function iter.rect_iterator(top_corner, bottom_corner, filter) - return iter.rectangle_iterator:new(top_corner, bottom_corner, filter) +function iter.rect_iterator(top_corner, bottom_corner, filter, rvi) + return iter.rectangle_iterator:new(top_corner, bottom_corner, filter, rvi) +end + +function iter.mons_rect_iterator (top_corner, bottom_corner, filter) + return iter.rect_iterator(top_corner, bottom_corner, iter.monster_filter(filter), true) end ------------------------------------------------------------------------------- -- los_iterator ------------------------------------------------------------------------------- -function iter.los_iterator (ic, filter, center) +function iter.los_iterator (ic, filter, center, rvi) local y_x, y_y = you.pos() if center ~= nil then y_x, y_y = center:xy() end - local include_center = ic or false + local include_center = ic local top_corner = dgn.point(y_x - 8, y_y - 8) local bottom_corner = dgn.point(y_x + 8, y_y + 8) local function check_los (point) local _x, _y = point:xy() + local npoint = true if filter ~= nil then + if rvi then + npoint = filter(point) + end + if not filter(point) then - return false + return nil end end if y_x == _x and y_y == _y then - return include_center + if rvi and include_center then + return npoint + else + return include_center + end end if not you.see_cell(_x, _y) then - return false + return nil end - return true + if rvi then + return npoint + else + return true + end end - return iter.rect_iterator(top_corner, bottom_corner, check_los) + return iter.rect_iterator(top_corner, bottom_corner, check_los, rvi) +end + +function iter.mons_los_iterator (ic, filter, center) + return iter.los_iterator(ic, iter.monster_filter(filter), center, true) end ------------------------------------------------------------------------------- -- adjacent_iterator ------------------------------------------------------------------------------- -function iter.adjacent_iterator (ic, filter, center) +function iter.adjacent_iterator (ic, filter, center, rvi) local y_x, y_y = you.pos() if center ~= nil then @@ -157,32 +208,49 @@ function iter.adjacent_iterator (ic, filter, center) local top_corner = dgn.point(y_x - 1, y_y - 1) local bottom_corner = dgn.point(y_x + 1, y_y + 1) - local include_center = ic or false + local include_center = ic local function check_adj (point) local _x, _y = point:xy() + local npoint = nil if filter ~= nil then + if rvi then + npoint = filter(point) + end + if not filter(point) then - return false + return nil end end if y_x == _x and y_y == _y then - return include_center + if rvi and include_center then + return npoint + else + return include_center + end end - return true + if rvi then + return npoint + else + return true + end end - return iter.rect_iterator(top_corner, bottom_corner, check_adj) + return iter.rect_iterator(top_corner, bottom_corner, check_adj, rvi) +end + +function iter.mons_adjacent_iterator (ic, filter, center) + return iter.adjacent_iterator(ic, iter.monster_filter(filter), center, true) end ------------------------------------------------------------------------------- -- circle_iterator ------------------------------------------------------------------------------- -function iter.circle_iterator (radius, ic, filter, center) +function iter.circle_iterator (radius, ic, filter, center, rvi) if radius == nil then error("circle_iterator needs a radius") end @@ -193,32 +261,49 @@ function iter.circle_iterator (radius, ic, filter, center) y_x, y_y = center:xy() end - local include_center = ic or false + local include_center = ic local top_corner = dgn.point(y_x - radius, y_y - radius) local bottom_corner = dgn.point(y_x + radius, y_y + radius) local function check_dist (point) local _x, _y = point:xy() local dist = dgn.distance(y_x, y_y, _x, _y) + local npoint = nil if filter ~= nil then + if rvi then + npoint = filter(point) + end + if not filter(point) then - return false + return nil end end if y_x == _x and y_y == _y then - return include_center + if rvi and include_center then + return npoint + else + return include_center + end end if dist >= (radius * radius) + 1 then - return false + return nil end - return true + if rvi then + return npoint + else + return true + end end - return iter.rect_iterator(top_corner, bottom_corner, check_dist) + return iter.rect_iterator(top_corner, bottom_corner, check_dist, rvi) +end + +function iter.mons_circle_iterator (radius, ic, filter, center) + return iter.circle_iterator(radius, ic, iter.monster_filter(filter), center, true) end ------------------------------------------------------------------------------- @@ -319,3 +404,69 @@ function iter.subvault_iterator (e, filter) return iter.rect_iterator(top_corner, bottom_corner, check_mask) end + +------------------------------------------------------------------------------- +-- Marker iterators +-- firstly, a point iterator. It's really just a fancy ipairs(), but stateful +-- and with the ability to filter points. +------------------------------------------------------------------------------- + +iter.point_iterator = {} + +function iter.point_iterator:_new () + local m = {} + setmetatable(m, self) + self.__index = self + return m +end + +function iter.point_iterator:new (ptable, filter, rv_instead) + if ptable == nil then + error("ptable cannot be nil for point_iterator") + end + + local mt = iter.point_iterator:_new() + mt.cur_p = 0 + mt.table = ptable + mt.rvi = rv_instead or false + mt.filter = filter or nil + + return mt:iter() +end + +function iter.point_iterator:next() + local point = nil + local q = 0 + repeat + q = q + 1 + self.cur_p = self.cur_p + 1 + point = self:check_filter(self.table[self.cur_p]) + until point or q == 10 + + return point +end + +function iter.point_iterator:check_filter(point) + if self.filter ~= nil then + if self.filter(point) then + if self.rvi then + return self.filter(point) + else + return point + end + else + return nil + end + else + return point + end +end + +function iter.point_iterator:iter () + return function() return self:next() end, nil, nil +end + +-- An easier and more posh way of interfacing with find_marker_positions_by_prop. +function iter.slave_iterator (prop, value) + return iter.point_iterator:new(dgn.find_marker_positions_by_prop(prop, value)) +end diff --git a/crawl-ref/source/dat/database/monspeak.txt b/crawl-ref/source/dat/database/monspeak.txt index 6817bdf..e37df6e 100644 --- a/crawl-ref/source/dat/database/monspeak.txt +++ b/crawl-ref/source/dat/database/monspeak.txt @@ -972,7 +972,7 @@ WARN:You feel cold. @The_monster@ wails. -@The_monster@ @wails@, "What have you got that I didn't have?" +@The_monster@ @wails@, "What do you have that I didn't have?" @The_monster@ says very slowly, "There's no hope." diff --git a/crawl-ref/source/dat/uniques.des b/crawl-ref/source/dat/uniques.des index b8f8851..b93b5e2 100644 --- a/crawl-ref/source/dat/uniques.des +++ b/crawl-ref/source/dat/uniques.des @@ -548,8 +548,6 @@ ENDMAP ############################################################################### # Crazy Yiuf! Only in his cottage. -# -# XXX: Hacked around like crazy to make it less likely to split a level. NAME: uniq_crazy_yiuf_cottage DEPTH: D:2-7 WEIGHT: 100 @@ -557,15 +555,15 @@ TAGS: place_unique no_monster_gen no_item_gen MONS: Crazy Yiuf ITEM: hammer MAP - tt t@t - tttttt@t.tt - ttttt...ttt.tt -@...t..ttccccc.@ -.....t..tc...ctt -....tttt....1cttt -...ttttttc..dctt - tt.tttttccccc.@ - ttt.tttttttt.tt - ttt..@tttt.tt - ttt tt@tt + xxxxxxxxxxxxxxxx + xxtttttttxxtttxx + xxtttttttttttttx + ....t.tttccccctx +......t..tc...ctx +@....tttt....1ctx +....ttttttc..dctx + xxtttttttccccctx + xxtttttttttttttx + xxxxxttttttttxxx + xxxxxxxxxxxxxxxx ENDMAP diff --git a/crawl-ref/source/dat/wizlab.des b/crawl-ref/source/dat/wizlab.des index 96b6134..9956a14 100644 --- a/crawl-ref/source/dat/wizlab.des +++ b/crawl-ref/source/dat/wizlab.des @@ -285,7 +285,7 @@ MAP ccm.mcccLcccm.mcccRcccm.mcc ccm...mLLcccm...mcccRRm...mcc ccm..$..mcccm..?..mcccm..$..mcc - cm..$8$..mcm...M...mcm..$9$..mc + cm..$8$..m+m...M...m+m..$9$..mc ccm..$..mcccm.....mcccm..$..mcc ccm...mcc ccm...mcc ccm...mcc ccmmmcc ccmmmcc ccmmmcc diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index c0147fb..f165ee4 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -138,6 +138,7 @@ static void _place_extra_vaults(); static void _place_minivaults(const std::string &tag = "", int fewest = -1, int most = -1, bool force = false); +static int _place_uniques(int level_number, char level_type); static void _place_traps( int level_number ); static void _place_fog_machines( int level_number ); static void _prepare_swamp(); @@ -248,6 +249,9 @@ static bool _fixup_interlevel_connectivity(); map_mask dgn_Map_Mask; std::vector<vault_placement> Level_Vaults; std::vector<vault_placement> Temp_Vaults; +FixedVector<bool, NUM_MONSTERS> temp_unique_creatures; +FixedVector<unique_item_status_type, MAX_UNRANDARTS> temp_unique_items; + std::set<std::string> Level_Unique_Maps; std::set<std::string> Level_Unique_Tags; std::string dgn_Build_Method; @@ -955,6 +959,9 @@ void dgn_reset_level() Level_Unique_Maps.clear(); Level_Unique_Tags.clear(); + you.unique_creatures = temp_unique_creatures; + you.unique_items = temp_unique_items; + _portal_vault_map_name.clear(); _you_vault_list.clear(); dgn_Build_Method.clear(); @@ -1822,12 +1829,21 @@ static void _build_dungeon_level(int level_number, int level_type) return; } + // Save a copy of unique creatures in case we get vetoed. + temp_unique_creatures = you.unique_creatures; + // And unrands + temp_unique_items = you.unique_items; + // Try to place minivaults that really badly want to be placed. Still // no guarantees, seeing this is a minivault. _place_minivaults(); _place_branch_entrances( level_number, level_type ); _place_extra_vaults(); + // XXX: Moved this here from builder_monsters so that connectivity can be + // ensured + _place_uniques(level_number, level_type); + // Place shops, if appropriate. This must be protected by the connectivity // check. if (level_type == LEVEL_DUNGEON && your_branch().has_shops) @@ -3750,8 +3766,6 @@ static void _builder_monsters(int level_number, char level_type, int mon_wanted) place_monster(mg); } - _place_uniques(level_number, level_type); - if (!player_in_branch(BRANCH_CRYPT)) // No water creatures in the Crypt. _place_aquatic_monsters(level_number, level_type); else diff --git a/crawl-ref/source/shopping.cc b/crawl-ref/source/shopping.cc index 3c40e45..dd398df 100644 --- a/crawl-ref/source/shopping.cc +++ b/crawl-ref/source/shopping.cc @@ -281,6 +281,20 @@ static std::string _shop_print_stock( const std::vector<int>& stock, return (purchasable); } +static int _count_identical(const std::vector<int>& stock, + const item_def& item) +{ + int count = 0; + for (unsigned int i = 0; i < stock.size(); i++) + { + const item_def &other = mitm[stock[i]]; + + if (ShoppingList::items_are_same(item, other)) + count++; + } + return (count); +} + // Rather than prompting for each individual item, shopping now works more // like multi-pickup, in that pressing a letter only "selects" an item // (changing the '-' next to its name to a '+'). Affordability is shown @@ -338,20 +352,20 @@ static bool _in_a_shop( int shopidx, int &num_in_list ) stock = _shop_get_stock(shopidx); - // Deselect all, recompute what's in the shopping list. + in_list.clear(); + in_list.resize(stock.size(), false); + for (unsigned int i = 0; i < stock.size(); i++) + { + const item_def& item = mitm[stock[i]]; + in_list[i] = shopping_list.is_on_list(item); + } + + // If items have been bought... if (stock.size() != selected.size()) { total_cost = 0; - selected.resize(stock.size()); - for (unsigned int i = 0; i < selected.size(); ++i) - selected[i] = false; - - in_list.resize(stock.size()); - for (unsigned int i = 0; i < stock.size(); i++) - { - const item_def& item = mitm[stock[i]]; - in_list[i] = shopping_list.is_on_list(item); - } + selected.clear(); + selected.resize(stock.size(), false); } num_in_list = 0; @@ -521,9 +535,16 @@ static bool _in_a_shop( int shopidx, int &num_in_list ) { item_def& item = mitm[stock[i]]; - // Remove from shopping list. - if (in_list[i]) + // Remove from shopping list if it's unique + // (i.e., if the shop has multiple scrolls of + // identify, don't remove the other scrolls + // from the shopping list if there's any + // left). + if (in_list[i] + && _count_identical(stock, item) == 1) + { shopping_list.del_thing(item); + } const int gp_value = _shop_get_item_value(item, shop.greed, id_stock); @@ -586,9 +607,15 @@ static bool _in_a_shop( int shopidx, int &num_in_list ) // Move selected to shopping list. for (unsigned int i = 0; i < stock.size(); i++) { - if (selected[i]) + const item_def &item = mitm[stock[i]]; + if (selected[i] && !shopping_list.is_on_list(item)) { - in_list[i] = true; + // Ignore Bargaining. + const int cost = _shop_get_item_value(item, shop.greed, + id_stock, false); + + shopping_list.add_thing(item, cost); + in_list[i] = false; selected[i] = false; } } @@ -599,14 +626,17 @@ static bool _in_a_shop( int shopidx, int &num_in_list ) // Move shopping list to selected. for (unsigned int i = 0; i < stock.size(); i++) { + const item_def &item = mitm[stock[i]]; if (in_list[i]) { in_list[i] = false; selected[i] = true; - const item_def& item = mitm[stock[i]]; total_cost += _shop_get_item_value(item, shop.greed, id_stock); + + if (shopping_list.is_on_list(item)) + shopping_list.del_thing(item); } } } @@ -658,6 +688,7 @@ static bool _in_a_shop( int shopidx, int &num_in_list ) if ( _shop_yesno("Remove from shopping list? (y/N)", 'n') ) { + shopping_list.del_thing(item); in_list[key] = false; selected[key] = false; } @@ -668,6 +699,7 @@ static bool _in_a_shop( int shopidx, int &num_in_list ) if ( _shop_yesno("Remove item from shopping list and " "buy it? (Y/n)", 'y') ) { + shopping_list.del_thing(item); in_list[key] = false; // Will be toggled to true later selected[key] = false; @@ -688,27 +720,6 @@ static bool _in_a_shop( int shopidx, int &num_in_list ) } } - // Actually change shopping list. - for (unsigned int i = 0; i < stock.size(); i++) - { - const item_def& item = mitm[stock[i]]; - bool on_list = shopping_list.is_on_list(item); - - if (on_list != in_list[i]) - { - if (in_list[i]) - { - // Ignore Bargaining. - const int cost = _shop_get_item_value(item, shop.greed, - id_stock, false); - - shopping_list.add_thing(item, cost); - } - else - shopping_list.del_thing(item); - } - } - return (bought_something); } @@ -2393,6 +2404,12 @@ int ShoppingList::size() const return ( list->size() ); } +bool ShoppingList::items_are_same(const item_def& item_a, + const item_def& item_b) +{ + return (item_name_simple(item_a) == item_name_simple(item_b)); +} + void ShoppingList::move_things(const coord_def &_src, const coord_def &_dst) { if (crawl_state.map_stat_gen) diff --git a/crawl-ref/source/shopping.h b/crawl-ref/source/shopping.h index 5ff8541..ab874c7 100644 --- a/crawl-ref/source/shopping.h +++ b/crawl-ref/source/shopping.h @@ -60,6 +60,9 @@ public: int size() const; + static bool items_are_same(const item_def& item_a, + const item_def& item_b); + private: CrawlVector* list; -- Dungeon Crawl Stone Soup |