monsters, terrain (named altars, traps, shops) and items all on the same square.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1028 c06c8d41-db1a-0410-9941-cceddc491573
JDM27QE4HR52AYFSQE763BFF57ANOTF5MXKMO377PP5EXMN7SAOAC 7VVRO5HMNNOXVRLBLJUCHUJP6MDIRMC2BWCO7MWH4OLQRM3LMTMQC JQFQX7IWSJ4TYWVUVXAFMCPSAN67PRMNECDQI5WMON2JFMQVVUEQC JR2RAQ523LOWNDYJNK6AZVKI6WVMI622PIV72XWOVZYPXPUKSQWAC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC 34C4U6EQWERY75GZJKUCM5KVGU2OUICETS5LGZF6RMKMZT4R5SQAC WKTZHLOJ65WSK6FR5MF7RWGSMZ22T2D6LHB66FV3IPGXIBLYHHNAC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC ZP2KE7A2LE7Z2S7AC45WE4CXDSEVDTWIMV2EM4IBUKXYJIDU6R7QC A3CO4KBFTFU3ZSHWRY2OPPX3MMTFV7OUCZGL7Q4Y2FU7JO4AP7MAC MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC 5E7K2S4F4QDZC5UH3JVMYQ5SFJIKIATZII4EJL7IOT66ZBJ5GUPQC KCHX2F3JFEWOZT3WMJVZAAQUU2QSZ5Q7RDCD7WUJ7VE65J52JFUQC 5P64LHKJKGKIO3FUV63KFQ2OHZ5RNRV7WXS25OHXVNYYFZAVGLMAC 7YSKYUNV34XIWRTJUHJV4QMQRTXXYDIXM5AZSPSDPAYDW4B4PU6QC KRN7O2VJTLPT5KLUEMNGNYDSVHB3LYWONSREU2GOUXRMM3J6REYQC C52GDIYN6W4WNYL2QV7L7OKFBVLPFSBQAEBCX44PAXCZ5H7JXCJQC SVUM62ARSXH6RUBFRWS6KAQC7PTNTMGSV2GPZJQQJ4GNEML2HBVQC LY6WZIBS6CVHJQJGFPTFGA74PGXM4MJ7GDDPGRK73E4RCXOVNUIQC kmons : KMONS { }| KMONS STRING{std::string err = lc_map.add_key_mons($2);if (!err.empty())yyerror(make_stringf("Bad arg to KMONS: '%s' (%s)",$2, err.c_str()).c_str());}kitem : KITEM { }| KITEM STRING{std::string err = lc_map.add_key_item($2);if (!err.empty())yyerror(make_stringf("Bad arg to KITEM: '%s' (%s)",$2, err.c_str()).c_str());}
}}static const char *shop_types[] = {"weapon","armour","antique weapon","antique armour","antiques","jewellery","wand","book","food","distillery","scroll","general"};int str_to_shoptype(const std::string &s){if (s == "random")return (SHOP_RANDOM);for (unsigned i = 0; i < sizeof(shop_types) / sizeof (*shop_types); ++i){if (s == shop_types[i])return (i);
};struct feature_spec{int genweight;int feat;int shop;int trap;int glyph;feature_spec(int f, int wt = 10): genweight(wt), feat(f), shop(-1),trap(-1), glyph(-1){ }feature_spec() : genweight(0), feat(0), shop(-1), trap(-1), glyph(-1) { }};typedef std::vector<feature_spec> feature_spec_list;struct feature_slot{feature_spec_list feats;bool fix_slot;feature_slot();feature_spec get_feat();};struct keyed_mapspec{public:feature_slot feat;item_list item;mons_list mons;public:keyed_mapspec();std::string set_feat(const std::string &s, bool fix);std::string set_mons(const std::string &s, bool fix);std::string set_item(const std::string &s, bool fix);feature_spec get_feat();mons_spec get_mons();item_spec get_item();private:std::string err;private:void parse_features(const std::string &);feature_spec_list parse_feature(const std::string &s);feature_spec parse_shop(std::string s, int weight);feature_spec parse_trap(std::string s, int weight);
}static std::string split_key_item(const std::string &s,int *key,int *separator,std::string *arg){std::string::size_typenorm = s.find("="),fixe = s.find(":");const std::string::size_type sep = norm < fixe? norm : fixe;if (sep == std::string::npos)return ("malformed declaration - must use = or :");std::string what_to_subst = trimmed_string(s.substr(0, sep));std::string substitute = trimmed_string(s.substr(sep + 1));if (what_to_subst.length() != 1)return make_stringf("selector '%s' must be exactly one character",what_to_subst.c_str());*key = what_to_subst[0];*arg = substitute;*separator = s[sep];return ("");
std::string::size_typenorm = s.find("="),fixe = s.find(":");const std::string::size_type sep = norm < fixe? norm : fixe;if (sep == std::string::npos)return ("malformed SUBST declaration - must use = or :");
int sep = 0;int key = 0;std::string substitute;
const bool fixed = (sep == fixe);std::string what_to_subst = trimmed_string(sub.substr(0, sep));std::string substitute = trimmed_string(sub.substr(sep + 1));if (what_to_subst.length() != 1)return make_stringf("selector '%s' must be exactly one character",what_to_subst.c_str());
std::string err = split_key_item(sub, &key, &sep, &substitute);if (!err.empty())return (err);
keyed_mapspec *map_def::mapspec_for_key(int key){keyed_specs::iterator i = keyspecs.find(key);return i != keyspecs.end()? &i->second : NULL;}std::string map_def::add_key_field(const std::string &s,std::string (keyed_mapspec::*set_field)(const std::string &s, bool fixed)){int key = 0;int separator = 0;std::string arg;std::string err = split_key_item(s, &key, &separator, &arg);if (!err.empty())return (err);keyed_mapspec &km = keyspecs[key];return ((km.*set_field)(arg, separator == ':'));}std::string map_def::add_key_item(const std::string &s){return add_key_field(s, &keyed_mapspec::set_item);}std::string map_def::add_key_feat(const std::string &s){return add_key_field(s, &keyed_mapspec::set_feat);}std::string map_def::add_key_mons(const std::string &s){return add_key_field(s, &keyed_mapspec::set_mons);}
//////////////////////////////////////////////////////////////////////////// keyed_mapspeckeyed_mapspec::keyed_mapspec(): feat(), item(), mons(){}std::string keyed_mapspec::set_feat(const std::string &s, bool fix){err.clear();parse_features(s);feat.fix_slot = fix;return (err);}void keyed_mapspec::parse_features(const std::string &s){feat.feats.clear();std::vector<std::string> specs = split_string("/", s);for (int i = 0, size = specs.size(); i < size; ++i){const std::string &spec = specs[i];feature_spec_list feats = parse_feature(spec);if (!err.empty())return;feat.feats.insert( feat.feats.end(),feats.begin(),feats.end() );}}feature_spec keyed_mapspec::parse_trap(std::string s, int weight){strip_tag(s, "trap");trim_string(s);lowercase(s);const int trap = str_to_trap(s);if (trap == -1)err = make_stringf("bad trap name: '%s'", s.c_str());feature_spec fspec(-1, weight);fspec.trap = trap;return (fspec);}feature_spec keyed_mapspec::parse_shop(std::string s, int weight){strip_tag(s, "shop");trim_string(s);lowercase(s);const int shop = str_to_shoptype(s);if (shop == -1)err = make_stringf("bad shop type: '%s'", s.c_str());feature_spec fspec(-1, weight);fspec.shop = shop;return (fspec);}feature_spec_list keyed_mapspec::parse_feature(const std::string &str){std::string s = str;int weight = strip_number_tag(s, "weight:");if (weight == TAG_UNFOUND || weight <= 0)weight = 10;trim_string(s);feature_spec_list list;if (s.length() == 1){feature_spec fsp(-1, weight);fsp.glyph = s[0];list.push_back( fsp );return (list);}if (s.find("trap") != std::string::npos){list.push_back( parse_trap(s, weight) );return (list);}if (s.find("shop") != std::string::npos|| s.find("store") != std::string::npos){list.push_back( parse_shop(s, weight) );return (list);}std::vector<dungeon_feature_type> feats = features_by_desc(s);for (int i = 0, size = feats.size(); i < size; ++i)list.push_back( feature_spec(feats[i], weight) );if (feats.empty())err = make_stringf("no features matching \"%s\"",str.c_str());return (list);}std::string keyed_mapspec::set_mons(const std::string &s, bool fix){err.clear();mons.clear();return (mons.add_mons(s, fix));}std::string keyed_mapspec::set_item(const std::string &s, bool fix){err.clear();item.clear();return (item.add_item(s, fix));}feature_spec keyed_mapspec::get_feat(){return feat.get_feat();}mons_spec keyed_mapspec::get_mons(){return (mons.size()? mons.get_monster(0) : mons_spec(-1));}item_spec keyed_mapspec::get_item(){if (item.size())return item.get_item(0);item_spec spec;spec.base_type = OBJ_UNASSIGNED;return (spec);}//////////////////////////////////////////////////////////////////////////// feature_slotfeature_slot::feature_slot() : feats(), fix_slot(false){}feature_spec feature_slot::get_feat(){int tweight = 0;feature_spec chosen_feat = feature_spec(DNGN_FLOOR);for (int i = 0, size = feats.size(); i < size; ++i){const feature_spec &feat = feats[i];if (random2(tweight += feat.genweight) < feat.genweight)chosen_feat = feat;}if (fix_slot){feats.clear();feats.push_back( chosen_feat );}return (chosen_feat);}
static void dngn_place_item_explicit(const item_spec &spec,int x, int y, int level){// Dummy object?if (spec.base_type == OBJ_UNASSIGNED)return;if (spec.level >= 0)level = spec.level;const int item_made =items( spec.allow_uniques, spec.base_type, spec.sub_type, true,level, spec.race );if (item_made != NON_ITEM && item_made != -1){mitm[item_made].x = x;mitm[item_made].y = y;}}
// Dummy object?if (spec.base_type == OBJ_UNASSIGNED)return;if (spec.level >= 0)level = spec.level;const int item_made =items( spec.allow_uniques, spec.base_type, spec.sub_type, true,level, spec.race );if (item_made != NON_ITEM)
static void dngn_make_monster(const mons_spec &monster_type_thing,int monster_level,int vx, int vy){if (monster_type_thing.mid != -1)
mitm[item_made].x = x;mitm[item_made].y = y;
const int mid = monster_type_thing.mid;int not_used;if (mid != RANDOM_MONSTER && mid < NUM_MONSTERS){const int habitat = monster_habitat(mid);if (habitat != DNGN_FLOOR)grd[vx][vy] = habitat;}place_monster( not_used, mid, monster_level,monster_type_thing.generate_awake?BEH_WANDER : BEH_SLEEP,MHITNOT, true, vx, vy, false );
keyed_mapspec *mapsp = following? NULL : place.map.mapspec_for_key(vgrid);if (mapsp){const feature_spec f = mapsp->get_feat();if (f.feat >= 0){grd[vx][vy] = f.feat;vgrid = -1;}else if (f.glyph >= 0){altar_count = vault_grid( place, level_number, vx, vy,altar_count, acq_item_class,f.glyph, targets, num_runes,rune_subst, true );}else if (f.shop >= 0)place_spec_shop(level_number, vx, vy, f.shop);else if (f.trap >= 0){const int trap =f.trap == TRAP_INDEPTH? random_trap_for_level(level_number): f.trap;place_specific_trap(vx, vy, trap);}elsegrd[vx][vy] = DNGN_FLOOR;
if (monster_type_thing.mid != -1){const int mid = monster_type_thing.mid;if (mid != RANDOM_MONSTER && mid < NUM_MONSTERS){const int habitat = monster_habitat(mid);if (habitat != DNGN_FLOOR)grd[vx][vy] = habitat;}place_monster( not_used, mid, monster_level,monster_type_thing.generate_awake?BEH_WANDER : BEH_SLEEP,MHITNOT, true, vx, vy, false );}
dngn_make_monster(monster_type_thing, monster_level,vx, vy);
}int str_to_trap(const std::string &s){ASSERT(NUM_TRAPS == sizeof(trap_names) / sizeof(*trap_names));if (s == "random")return (TRAP_RANDOM);else if (s == "suitable")return (TRAP_INDEPTH);for (int i = 0; i < NUM_TRAPS; ++i){if (trap_names[i] == s)return (i);}return (-1);
for (unsigned i = 0; i < sizeof(shop_types) / sizeof (*shop_types); ++i){if (strstr(requested_shop, shop_types[i])){new_shop_type = i;break;}}
std::string s = replace_all_of(requested_shop, "*", "");new_shop_type = str_to_shoptype(s);
## KFEAT:# -----# The KFEAT: directive allows you to specify a placeholder symbol that is# replaced with another symbol, named feature, trap, or shop. Eg.:## KFEAT: Z = C / needle trap / antique armour shop / altar of Zin## Replaces occurrences of Z with C (random altar), a needle trap, an# antique armour shop, or an altar of Zin. Different instances of Z may# receive different replacements. To force a single replacement for all Z,# use:## KFEAT: Z : C / needle trap / antique armour shop## You'll notice that 'Z' is the symbol of the Orb of Zot. Kxxx directives# allow you to assign arbitrary definitions to any symbol.## The placeholder used by KFEAT can be shared by KITEM and KMONS. See below.# If the placeholder is shared, all defined Kxxxx operations for the# placeholder are performed.## KMONS:# -----# KMONS: allows you to specify a placeholder symbol that indicates the# position of a monster (or monsters).## KMONS: ? = orc priest / deep elf priest
# Using KMONS: allows you to exceed the 7 slot limit for monsters. It is also# useful if you want to place a monster on a non-floor square (used in# association with a KFEAT:). Eg:## KFEAT: Z = W# KMONS: Z = rat## (Places a rat on a shallow water square for all occurrences of Z.)## KITEM:# -----# KITEM: places the specified item at all occurrences of the placeholder. It# can be combined with KFEAT and KMONS for the same placeholder. Eg:## KITEM: ? = potion of healing / potion of restore abilities##
## KFEAT:# -----# The KFEAT: directive allows you to specify a placeholder symbol that is# replaced with another symbol, named feature, trap, or shop. Eg.:## KFEAT: Z = C / needle trap / antique armour shop / altar of Zin## Replaces occurrences of Z with C (random altar), a needle trap, an# antique armour shop, or an altar of Zin. Different instances of Z may# receive different replacements. To force a single replacement for all Z,# use:## KFEAT: Z : C / needle trap / antique armour shop## You'll notice that 'Z' is the symbol of the Orb of Zot. Kxxx directives# allow you to assign arbitrary definitions to any symbol.## The placeholder used by KFEAT can be shared by KITEM and KMONS. See below.# If the placeholder is shared, all defined Kxxxx operations for the# placeholder are performed.## KMONS:# -----# KMONS: allows you to specify a placeholder symbol that indicates the# position of a monster (or monsters).## KMONS: ? = orc priest / deep elf priest## Using KMONS: allows you to exceed the 7 slot limit for monsters. It is also# useful if you want to place a monster on a non-floor square (used in# association with a KFEAT:). Eg:## KFEAT: Z = W# KMONS: Z = rat## (Places a rat on a shallow water square for all occurrences of Z.)## KITEM:# -----# KITEM: places the specified item at all occurrences of the placeholder. It# can be combined with KFEAT and KMONS for the same placeholder. Eg:## KITEM: ? = potion of healing / potion of restore abilities#