From ab679653017c1d661572cf34a62bf5ddf7c1304e Mon Sep 17 00:00:00 2001 From: dshaligram Date: Thu, 19 Jul 2007 12:31:32 +0000 Subject: Added elf arrival vaults (Eino). Tweaked dungeon builder so you always land on { on level 1 of a branch (using a map marker to identify which stair was a {). Maps with the "uniq" tag will be used only once in a game. Maps with a "uniq_foo" tag will be used only once, and will also prevent any other maps tagged "uniq_foo" from being used thereafter. Breaks saves. Oklob plants should not receive stab brands, fixed. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1897 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/dat/elf.des | 86 ++++++++++++++++++++++++++++++++++++++ crawl-ref/source/direct.cc | 3 +- crawl-ref/source/dungeon.cc | 98 +++++++++++++++++++++++++++++++------------- crawl-ref/source/externs.h | 3 ++ crawl-ref/source/files.cc | 4 +- crawl-ref/source/maps.cc | 28 +++++++++++-- crawl-ref/source/maps.h | 2 +- crawl-ref/source/mon-util.cc | 20 +++++---- crawl-ref/source/mon-util.h | 1 + crawl-ref/source/tags.cc | 52 +++++++++++++++++------ crawl-ref/source/tags.h | 7 ++-- 11 files changed, 243 insertions(+), 61 deletions(-) (limited to 'crawl-ref') diff --git a/crawl-ref/source/dat/elf.des b/crawl-ref/source/dat/elf.des index 46900c87e4..b1d692f674 100644 --- a/crawl-ref/source/dat/elf.des +++ b/crawl-ref/source/dat/elf.des @@ -3,6 +3,92 @@ # Elven Halls. ############################################################################## +############################################################################## +# Elf:1 arrival vaults +# +# The concept: +# There are no entry vaults for the Elven Halls. Instead, there is a "border +# check" vault on the other side, in the Elf:1 level. Note that elves and orcs +# are not necessarily at war or have big enmities against each other. It's +# just a border check. +# +# The intention: +# I (Eino here, hi!) lost a lot of characters trying to do the Halls right +# after the Mines until I realized the Halls are significantly harder. A +# welcoming party on the other side will hopefully warn the player about this. +# +# Honor this intention. Lots of space between the monsters and the stairs, so +# the players have many turns to realize their mistake. Note that designing +# can be a challenge with the eight space LOS. What might make the player +# realize it's better to flee: facing a nasty summon, taking a few hits from +# conjurations.. they might engage melee opponents, at which point it's quite +# difficult to flee. Please keep that in mind. Note also, that a corridor is +# usually easier for the player than an open space. +# +# This is an instance where an entry (arrival) vault really does benefit from +# having monsters, even a nasty bunch. However, don't go overboard trying to +# make it really hard. And try to make it seem like a plausible border guard. +# +############################################################################## + +############################################################################## +# Dummy Elf arrival vault + +NAME: elf_arrival_dummy +TAGS: dummy +PLACE: Elf:1 +CHANCE: 50 +ORIENT: float +MAP +{ +ENDMAP + +############################################################################## +# Elf arrival vault: corridor one (with the hidden toll cashbox) + +NAME: elf_arrival_001 +PLACE: Elf:1 +ORIENT: float +SHUFFLE: asd/v$= +SHUFFLE: fgh/v$= +SUBST: a = v, s = v, d = v, f = v, g = v, h = v +MONS: deep elf soldier, deep elf mage, deep elf conjurer / deep elf priest / deep elf fighter +MONS: deep elf summoner / deep elf knight w:2 +MAP + aaa + asa +vvvvvvvvvvvvvvvvvvvvdv +v...vvvvv..12..3.....@ +v.{........v12..v.4..v +v...vvvvv..12..3.....@ +vvvvvvvvvvvvvvvvvvvvhv + fgf + fff +ENDMAP + +############################################################################## +# Elf arrival vault: open area + +NAME: elf_arrival_002 +PLACE: Elf:1 +ORIENT: float +FLAGS: no_rotate +MONS: deep elf soldier, deep elf mage, deep elf conjurer / deep elf priest / deep elf fighter +MONS: deep elf summoner / deep elf knight w:2 +MAP +xxxxx@xxx@xxx@xxxxx +xxxx...........xxxx +xx....G.3.3.G....xx +x...1.........1...x +x.G...2..4..2...G.x +x.................x +x.......G.G.......x +x.................x +x.....G.....G.....x +xx.1.....{.....1.xx +xxxx...........xxxx +xxxxxxxxxxxxxxxxxxx +ENDMAP ############################################################################ # elf_hall diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc index 798a1f25bb..b2c3382803 100644 --- a/crawl-ref/source/direct.cc +++ b/crawl-ref/source/direct.cc @@ -1569,8 +1569,7 @@ static void describe_cell(int mx, int my) if (mons_is_mimic( menv[i].type )) mimic_item = true; - else if (!mons_class_flag(menv[i].type, M_NO_EXP_GAIN) - && !mons_is_statue(menv[i].type)) + else if (mons_behaviour_perceptible(&menv[i])) { if (menv[i].behaviour == BEH_SLEEP) { diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index a93c75773f..f46559ba58 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -205,6 +205,7 @@ static int dgn_random_map_for_place(bool wantmini); // ALTAR FUNCTIONS static dungeon_feature_type pick_an_altar(); static void place_altar(); +static void place_altars(); typedef std::list coord_list; @@ -222,35 +223,14 @@ static bool use_random_maps = true; static bool dgn_check_connectivity = false; static int dgn_zones = 0; -static void place_altars() -{ - // No altars before level 5. - if (you.your_level < 4) - return; - - if ( you.level_type == LEVEL_DUNGEON ) - { - int prob = your_branch().altar_chance; - while (prob) - { - if (random2(100) >= prob) - break; - -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Placing an altar"); -#endif - place_altar(); - // Reduce the chance and try to place another. - prob /= 5; - } - } -} - /********************************************************************** * builder() - kickoff for the dungeon generator. *********************************************************************/ bool builder(int level_number, int level_type) { + const std::set uniq_tags = you.uniq_map_tags; + const std::set uniq_names = you.uniq_map_names; + // N tries to build the level, after which we bail with a capital B. int tries = 20; while (tries-- > 0) @@ -277,6 +257,9 @@ bool builder(int level_number, int level_type) if (!dgn_level_vetoed && valid_dungeon_level(level_number, level_type)) return (true); + + you.uniq_map_tags = uniq_tags; + you.uniq_map_names = uniq_names; } if (!crawl_state.map_stat_gen) @@ -289,6 +272,20 @@ bool builder(int level_number, int level_type) return (false); } +static void dgn_register_vault(const map_def &map) +{ + if (map.has_tag("uniq")) + you.uniq_map_names.insert(map.name); + + std::vector tags = split_string(" ", map.tags); + for (int t = 0, ntags = tags.size(); t < ntags; ++t) + { + const std::string &tag = tags[t]; + if (tag.find("uniq_") == 0) + you.uniq_map_tags.insert(tag); + } +} + static inline bool dgn_grid_is_passable(dungeon_feature_type grid) { // Rock wall check is superfluous, but is the most common case. @@ -410,8 +407,10 @@ static void mask_vault(const vault_placement &place, unsigned mask) dgn_map_mask[x][y] |= mask; } -static void apply_place_masks(const vault_placement &place) +static void register_place(const vault_placement &place) { + dgn_register_vault(place.map); + mask_vault(place, MMT_VAULT | MMT_NO_DOOR); if (place.map.has_tag("no_monster_gen")) mask_vault(place, MMT_NO_MONS); @@ -621,11 +620,18 @@ static void fixup_branch_stairs() player_branch_depth() == 1 && you.level_type == LEVEL_DUNGEON ) { + const dungeon_feature_type exit = your_branch().exit_stairs; for (int x = 1; x < GXM; x++) for (int y = 1; y < GYM; y++) if (grd[x][y] >= DNGN_STONE_STAIRS_UP_I && grd[x][y] <= DNGN_ROCK_STAIRS_UP) - grd[x][y] = your_branch().exit_stairs; + { + if (grd[x][y] == DNGN_STONE_STAIRS_UP_I) + env.add_marker( + new map_feature_marker(coord_def(x,y), + grd[x][y])); + grd[x][y] = exit; + } } // bottom level of branch - replaces down stairs with up ladders: @@ -2883,7 +2889,7 @@ static bool build_minivaults(int level_number, int force_vault, mapgen_report_map_use(place.map); #endif - apply_place_masks(place); + register_place(place); // these two are throwaways: int num_runes = 0; @@ -3304,7 +3310,7 @@ static bool build_vaults(int level_number, int force_vault, int rune_subst, } } - apply_place_masks(place); + register_place(place); if (gluggy == MAP_FLOAT && target_connections.empty()) pick_float_exits(place, target_connections); @@ -4228,6 +4234,30 @@ static dungeon_feature_type pick_an_altar() return (altar_type); } // end pick_an_altar() +static void place_altars() +{ + // No altars before level 5. + if (you.your_level < 4) + return; + + if ( you.level_type == LEVEL_DUNGEON ) + { + int prob = your_branch().altar_chance; + while (prob) + { + if (random2(100) >= prob) + break; + +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Placing an altar"); +#endif + place_altar(); + // Reduce the chance and try to place another. + prob /= 5; + } + } +} + static void place_altar() { for ( int numtry = 0; numtry < 5000; ++numtry ) @@ -6433,6 +6463,11 @@ static coord_def dgn_find_closest_to_stone_stairs() coord_def dgn_find_nearby_stair(int stair_to_find, bool find_closest) { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Placing PC on %s", + dungeon_feature_name( + static_cast(stair_to_find))); +#endif if (stair_to_find == DNGN_ROCK_STAIRS_UP || stair_to_find == DNGN_ROCK_STAIRS_DOWN) { @@ -6445,6 +6480,8 @@ coord_def dgn_find_nearby_stair(int stair_to_find, bool find_closest) int basex = you.x_pos; int basey = you.y_pos; + const bool branch_exit = stair_to_find == your_branch().exit_stairs; + // check for illegal starting point if ( !in_bounds(basex, basey) ) { @@ -6478,7 +6515,10 @@ coord_def dgn_find_nearby_stair(int stair_to_find, bool find_closest) const int dist = (xpos-basex)*(xpos-basex) + (ypos-basey)*(ypos-basey); - if (grd[xpos][ypos] == stair_to_find) + if (grd[xpos][ypos] == stair_to_find + && (!branch_exit + || env.find_marker(coord_def(xpos, ypos), + MAT_FEATURE))) { found++; if (find_closest) diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 81965334bd..7f9653ef4c 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -786,6 +786,9 @@ public: FixedVector spell_letter_table; // ref to spell by slot FixedVector ability_letter_table; // ref to abil by enum + std::set uniq_map_tags; + std::set uniq_map_names; + public: player(); void init(); diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index 6da990e5b8..ad8baf87c1 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -1478,14 +1478,14 @@ void writeString(FILE* file, const std::string &s, int cap) int length = s.length(); if (length > cap) length = cap; - writeShort(file, length); + writeLong(file, length); if (length) write2(file, s.c_str(), length); } std::string readString(FILE *file, int cap) { - short length = readShort(file); + const int length = readLong(file); if (length > 0) { if (length <= cap) diff --git a/crawl-ref/source/maps.cc b/crawl-ref/source/maps.cc index 8d5845bde2..e8a1514296 100644 --- a/crawl-ref/source/maps.cc +++ b/crawl-ref/source/maps.cc @@ -283,6 +283,22 @@ static int apply_vault_definition( /////////////////////////////////////////////////////////////////////////// // Map lookups +template +static bool map_has_no_tags(const map_def &map, I begin, I end) +{ + for ( ; begin != end; ++begin) + if (map.has_tag(*begin)) + return (false); + return (true); +} + +static bool vault_unforbidden(const map_def &map) +{ + return (you.uniq_map_names.find(map.name) == you.uniq_map_names.end() + && map_has_no_tags(map, you.uniq_map_tags.begin(), + you.uniq_map_tags.end())); +} + // Returns a map for which PLACE: matches the given place. int random_map_for_place(const level_id &place, bool want_minivault) { @@ -296,7 +312,8 @@ int random_map_for_place(const level_id &place, bool want_minivault) { // We also accept tagged levels here. if (vdefs[i].place == place - && vdefs[i].is_minivault() == want_minivault) + && vdefs[i].is_minivault() == want_minivault + && vault_unforbidden(vdefs[i])) { rollsize += vdefs[i].chance; @@ -305,6 +322,9 @@ int random_map_for_place(const level_id &place, bool want_minivault) } } + if (mapindex != -1 && vdefs[mapindex].has_tag("dummy")) + mapindex = -1; + #ifdef DEBUG_DIAGNOSTICS if (mapindex != -1) mprf(MSGCH_DIAGNOSTICS, "Found map %s for %s", @@ -328,7 +348,8 @@ int random_map_in_depth(const level_id &place, bool want_minivault) // showing up in the main dungeon. && !vdefs[i].has_tag_suffix("entry") && !vdefs[i].has_tag("pan") - && !vdefs[i].has_tag("unrand")) + && !vdefs[i].has_tag("unrand") + && vault_unforbidden(vdefs[i])) { rollsize += vdefs[i].chance; @@ -353,7 +374,8 @@ int random_map_for_tag(const std::string &tag, { if (vdefs[i].has_tag(tag) && vdefs[i].is_minivault() == want_minivault && (!check_depth || !vdefs[i].has_depth() - || vdefs[i].is_usable_in(level_id::current()))) + || vdefs[i].is_usable_in(level_id::current())) + && vault_unforbidden(vdefs[i])) { rollsize += vdefs[i].chance; diff --git a/crawl-ref/source/maps.h b/crawl-ref/source/maps.h index eb97a67926..2e3eb244e7 100644 --- a/crawl-ref/source/maps.h +++ b/crawl-ref/source/maps.h @@ -64,6 +64,6 @@ extern depth_ranges lc_default_depths; extern dlua_chunk lc_global_prelude; extern bool lc_run_global_prelude; -const int MAP_CACHE_VERSION = 1005; +const int MAP_CACHE_VERSION = 1006; #endif diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 7fb476eadb..5a8842e967 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -312,6 +312,14 @@ bool mons_is_stationary(const monsters *mons) return (mons_class_is_stationary(mons->type)); } +bool mons_behaviour_perceptible(const monsters *mons) +{ + return (!mons_class_flag(mons->type, M_NO_EXP_GAIN) + && !mons_is_mimic(mons->type) + && !mons_is_statue(mons->type) + && mons->type != MONS_OKLOB_PLANT); +} + bool mons_is_icy(const monsters *mons) { return (mons_is_icy(mons->type)); @@ -1667,18 +1675,14 @@ bool mons_is_known_mimic(const monsters *m) bool mons_looks_stabbable(const monsters *m) { - return (!mons_class_flag(m->type, M_NO_EXP_GAIN) - && !mons_is_mimic(m->type) - && !mons_is_statue(m->type) - && !mons_friendly(m) - && mons_is_sleeping(m)); + return (mons_behaviour_perceptible(m) + && !mons_friendly(m) + && mons_is_sleeping(m)); } bool mons_looks_distracted(const monsters *m) { - return (!mons_class_flag(m->type, M_NO_EXP_GAIN) - && !mons_is_mimic(m->type) - && !mons_is_statue(m->type) + return (mons_behaviour_perceptible(m) && !mons_friendly(m) && ((m->foe != MHITYOU && !mons_is_batty(m)) || mons_is_confused(m) diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h index 4f5ef174e9..ecf33d7683 100644 --- a/crawl-ref/source/mon-util.h +++ b/crawl-ref/source/mon-util.h @@ -326,6 +326,7 @@ bool mons_aligned(int m1, int m2); * *********************************************************************** */ bool mons_friendly(const monsters *m); +bool mons_behaviour_perceptible(const monsters *mons); bool mons_is_confused(const monsters *m); bool mons_is_fleeing(const monsters *m); bool mons_is_sleeping(const monsters *m); diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 8ae971b5a2..8b38c9f764 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -129,9 +129,9 @@ static void unmarshall_monster(tagHeader &th, monsters &m); static void marshall_item(tagHeader &th, const item_def &item); static void unmarshall_item(tagHeader &th, item_def &item); -template +template static void marshall_iterator(struct tagHeader &th, T_iter beg, T_iter end, - void (*T_marshall)(struct tagHeader&, const T&)); + T_marshal marshal); template static void unmarshall_vector(struct tagHeader& th, std::vector& vec, T (*T_unmarshall)(struct tagHeader&)); @@ -236,9 +236,9 @@ void marshallMap(struct tagHeader &th, const std::map& data, } } -template +template static void marshall_iterator(struct tagHeader &th, T_iter beg, T_iter end, - void (*T_marshall)(struct tagHeader&, const T&)) + T_marshall_t T_marshall) { marshallLong(th, std::distance(beg, end)); while ( beg != end ) @@ -258,6 +258,16 @@ static void unmarshall_vector(struct tagHeader& th, std::vector& vec, vec.push_back( T_unmarshall(th) ); } +template +static void unmarshall_container(tagHeader &th, T_container &container, + T_inserter inserter, T_unmarshall unmarshal) +{ + container.clear(); + const long num_to_read = unmarshallLong(th); + for (long i = 0; i < num_to_read; ++i) + (container.*inserter)(unmarshal(th)); +} + void marshall_level_id( tagHeader& th, const level_id& id ) { marshallByte(th, id.branch ); @@ -348,22 +358,22 @@ float unmarshallFloat(struct tagHeader &th) } // string -- marshall length & string data -void marshallString(struct tagHeader &th, const char *data, int maxSize) +void marshallString(struct tagHeader &th, const std::string &data, int maxSize) { - // allow for very long strings. - short len = strlen(data); + // allow for very long strings (well, up to 32K). + int len = data.length(); if (maxSize > 0 && len > maxSize) len = maxSize; marshallShort(th, len); // put in the actual string -- we'll null terminate on // unmarshall. - memcpy(&tagBuffer[th.offset], data, len); + memcpy(&tagBuffer[th.offset], data.c_str(), len); th.offset += len; } // string -- unmarshall length & string data -void unmarshallString(struct tagHeader &th, char *data, int maxSize) +void unmarshallCString(struct tagHeader &th, char *data, int maxSize) { // get length short len = unmarshallShort(th); @@ -387,7 +397,7 @@ std::string unmarshallString(tagHeader &th, int maxSize) if (!buffer) return (""); *buffer = 0; - unmarshallString(th, buffer, maxSize); + unmarshallCString(th, buffer, maxSize); const std::string res = buffer; delete [] buffer; @@ -942,6 +952,11 @@ static void tag_construct_you_dungeon(struct tagHeader &th) marshall_level_pos, marshall_as_long); marshallMap(th, portals_present, marshall_level_pos, marshall_as_long); + + marshall_iterator(th, you.uniq_map_tags.begin(), you.uniq_map_tags.end(), + marshallString); + marshall_iterator(th, you.uniq_map_names.begin(), you.uniq_map_names.end(), + marshallString); } static void marshall_follower(tagHeader &th, const follower &f) @@ -998,7 +1013,7 @@ static void tag_read_you(struct tagHeader &th, char minorVersion) char count_c; short count_s; - unmarshallString(th, you.your_name, 30); + unmarshallCString(th, you.your_name, 30); you.religion = static_cast(unmarshallByte(th)); you.piety = unmarshallByte(th); @@ -1056,7 +1071,7 @@ static void tag_read_you(struct tagHeader &th, char minorVersion) const int y = unmarshallShort(th); you.moveto(x, y); - unmarshallString(th, you.class_name, 30); + unmarshallCString(th, you.class_name, 30); you.burden = unmarshallShort(th); @@ -1139,7 +1154,7 @@ static void tag_read_you(struct tagHeader &th, char minorVersion) you.wizard = (bool) unmarshallByte(th); // time of character creation - unmarshallString( th, buff, 20 ); + unmarshallCString( th, buff, 20 ); you.birth_time = parse_date_string( buff ); you.real_time = unmarshallLong(th); @@ -1284,6 +1299,17 @@ static void tag_read_you_dungeon(struct tagHeader &th) unmarshall_level_pos, unmarshall_long_as); unmarshallMap(th, portals_present, unmarshall_level_pos, unmarshall_long_as); + + typedef std::set string_set; + typedef std::pair ssipair; + unmarshall_container(th, you.uniq_map_tags, + (ssipair (string_set::*)(const std::string &)) + &string_set::insert, + unmarshallString); + unmarshall_container(th, you.uniq_map_names, + (ssipair (string_set::*)(const std::string &)) + &string_set::insert, + unmarshallString); } static void tag_read_lost_monsters(tagHeader &th, int minorVersion) diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h index 154cdef1ad..ebc61c6d4d 100644 --- a/crawl-ref/source/tags.h +++ b/crawl-ref/source/tags.h @@ -39,7 +39,8 @@ void marshallShort(struct tagHeader &th, short data); void marshallLong(struct tagHeader &th, long data); void marshallFloat(struct tagHeader &th, float data); void marshallBoolean(struct tagHeader &th, bool data); -void marshallString(struct tagHeader &th, const char *data, int maxSize = 0); +void marshallString(struct tagHeader &th, const std::string &data, + int maxSize = 0); void marshallCoord(tagHeader &th, const coord_def &c); // last updated 22jan2001 {gdl} @@ -51,8 +52,8 @@ short unmarshallShort(struct tagHeader &th); long unmarshallLong(struct tagHeader &th); float unmarshallFloat(struct tagHeader &th); bool unmarshallBoolean(struct tagHeader &th); -void unmarshallString(struct tagHeader &th, char *data, int maxSize); -std::string unmarshallString(tagHeader &th, int maxSize); +void unmarshallCString(struct tagHeader &th, char *data, int maxSize); +std::string unmarshallString(tagHeader &th, int maxSize = 1000); void unmarshallCoord(tagHeader &th, coord_def &c); std::string make_date_string( time_t in_date ); -- cgit v1.2.3-54-g00ecf