git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7501 c06c8d41-db1a-0410-9941-cceddc491573
FQ7XALBL6NZAGBKKYIFHYQ7MUWIHR4TEU4TCS33EG4I3JTND5SQAC
MD2ABJ4CWOV5UKIOLQHCIA3DREZXH32MU74UU6MHETQJAX6XU4FAC
5ZKNFOMHGEVRDWZSD5JEEMOVXXXNEKQNASXVWWKNPBUYJGTNDIFQC
S74D5KQSRSDBHFN6OTSQQTLUEGNA3FZQMG7IPR5JXDUXJ3AOL2UAC
7MFGZW2K4OYHVLLCQHPCLQ7MWSD6DVJ4E32T6RW54KRE5HHGUVPQC
A4WHP5XZMXDCFMGRPS43OVHXHMU5KJBZKF4IRIO6F3KTXNHKAERQC
XUUXZ34SWMKSJCLJYPNFF6X2LDWYBGVRNL4NVUVVLHIHNDOJ74TAC
ED62QWGKBPORWVKDFOQRKJXEIWZVNGR3O4KWQBDSRNPT36AYOQYAC
JT672SIJK4BOIUAGL2WQ6NR2NF4PSWP3BT6Q4HMNRF25UN6JQ2MAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
OYTCBRC7LE44EUVRZVYTOOVKQWJ6P6YE3FXTOGUTNKEMLNWPHKSQC
NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC
W52PCSHX72WAMWKG6L4BPUBVMO6E72KYYBNKAA7554KNOTY6V7WQC
RZHJQU3Y6KKMNJKGL6P4IXBJTKWFO4YARAQSWYCETXXNSZG4BN7QC
RGHXFBNIULRVRYLBGG5JZDMYVM2E2JJ2Y5KQPMU6PUS3V26G6ZXQC
GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
W52PTX4I7TUG2LS36FJHLZ72DWCVXGUCTUIKPI3IGEYO5KWL6OVAC
BW3XFNOS6LDAQLHOZ6RXARCMKCY5JVLVDSXDSSAX4DSYM3FANQBAC
ANBVGN4RZOMY5LI4QSHOV2477FN55H353ZYLSVCPTXC7AWWSQZBAC
3PY3L3A4QRW3Z5Y7SHO4TMVOOP2VNCO27X2MX4DTOP2SADLBQUOAC
2C6B6QRTOK2ZMK2ZOF3EPSFUZTKG5B3IZXWBWIUYC4ZOVGQ2OV2QC
6ZCKL3LCJ2QYYRI6CVK7CU4VXZMIZ6RIOTFUDEM2QTM4EHKVUKMAC
FIYBXLWALQINNQTHG2KNDUUTAQAZRDDLXW2XOVSKDKBADJ3XCJ4AC
KXUQB3WNWC5IFL6VFWADEPQMMU3VV3NDI5FLA666PGOEWFYUHCLQC
WTGKEI4F7WINPHW4UMWFADYQH7VK7TNV5V7RUORBVXGFSO5SNP5AC
MI7CWKRDXHAU7PIHLXXOSFBULRGT2OOMIMOSQLMVYOUVGABIVXGAC
D6AJOTSOJNLJBBLQC2RAQOTPJJQENNBBVNRP45CZKDUHLLZLBFFQC
NH533CNPGAQGR3QSSXRKCAJHSPVSHSPSTEJXRDIRH5YPKMGMEHVAC
AYAQKTO6HOZJ44NDH5UIP6WFNB54Z5EZ4UMUISIQ67ZOIDB6OIQAC
MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC
56C44YMFHZ62GXAAOLYSLLGBVGRWXB53W2VI37Q26ZECEK2XG5SQC
6QWZDCP5HGYLTJO3WWYJJGRRT7QFY6IG64TC7TUB553Z7GAA2HIQC
TLO257LZSB6ZO36STDUEWJBO2LETXFKTFGXELA6Y4BZBVAEIIINAC
JDM27QE4HR52AYFSQE763BFF57ANOTF5MXKMO377PP5EXMN7SAOAC
WF2DSJGR6PKLGQSXEFF4ZW4EZZFGMHXPXWUYAKYBPFJH6KJKAANQC
AUXHSGS4EFOPZ6TVZYWNVOUDO7NYKUKE3HBKGQQWTALSVFOE3HAAC
CUNNC574MESEMTTONZ6YB6CJ2S5P6VA3V7Z3OODESWAK37GYOBPAC
ZVK4J5HTKFNOOIVCI62ZWEYGXEE5TYJ65DLYYZAZWTADFSXE62ZAC
QUYSD2DWCIKAAQJGI43EENAWWPA5W33UT3I5WFRSHU6FPSSXTX2AC
ZJLJGSB2XSBQU42OFQMXL3EG4CXAQGOYAU6YTV2SAWZEJIPFH2CAC
7Z37EO2GGM2DAS65DWEI5VVPRPXMGH6XHB6IADG3Q6KOITSV25MAC
QFWQG7G6KTZX3GP52K3N4BDWLMNH7A3A5ILJLXDIK6PYYLF3KO3AC
FSD7GIK3YLZXWLEH37BU6KV3IUCFGXPQL6IZ7H65YWNRBEKDBX5AC
2YSMM7QMFZOPD5NXAD2OAMDJEY5LOZO4NCYBC7UCQVANKINJRNBAC
UEI5JAVCMN7Y2SACTEZPZSNFJWOJTC55G24Q6LKQCT4XNDH5ZQIAC
34C4U6EQWERY75GZJKUCM5KVGU2OUICETS5LGZF6RMKMZT4R5SQAC
B7MSPF6X2RLGWN4M6ZZF3WSOPKGYPTTD7LIJVST7DXN27DG6JHNAC
2EUWVLBXTKBIYLS7HVCIL6R7EERHRAIVFAXQPBRKDEMH5BGFEDQQC
WLX2RQMMOMP2PYPAGJRM4VFD2WTLJTOAZZPPY3MV76FU2EGEJ54QC
IE3INS4WUXZOBVXB5VWRBYPVPXADD2U2W5H3TBTOYNWJ3EGRSGQQC
H3552BCIAVBLKAYKE4DHFLBLFW5RGRMYBMRRYHYEB5IPIJRUVU5QC
EEPNZ3SHGXQ4NKLSWHI7X2WK3LU3AR2EDZZFFDGOXQQBK5LO5OYAC
JYNLSDNQDNOBCHDPQLJP6TNOJQ2IB4V7JHBYLL6UAUCTZ7DUZAWQC
EL2ZPHAS5JGUCCBWYMSDJOQAFQLR7QKLOIWM2FYZ77ATL57G5NGAC
ZI6K4LOBYQJKSMHZ766HTJS66AL2KB6IYSBUYPETTKPOKW4ZNK7AC
XXZGTB5UAFMP2SW2WWUHCTDY5TEM7LZEPAASEXKQLT7BSLBY3OTQC
R4UPYSRDYDVGAKQAJOXVWHYDMASGKTJXTO2AVTO35ZYOJERELAKQC
VZKO4ZQNMNGUK6WY7Y4A4TIW2OA6YGREQ6V7NZCWW3DAPSWXKK7AC
OODLVVDEHPOTPPUSPKCGAEXBVGKRUX7YYGQPA6UI3RKWZVB2YKKAC
S6YHCQQOD4BLRRLJ7BX2VI7EFJGOHFNZ6M6HJBFK7DWOGMLE5BAAC
3GOS6LZ7JSSXLASCIJCMCOOMCVH2SD22TCEVUQ3YAIPB7FUFJPCQC
YWT3IVJQ2NI6S47ZLGEHIW7C6YUFHUNQ5XMU6MVYRBWE4T3ALQWQC
IDGC4LG4GCIAM4DC4WOQUB7TGTY3PHGTBF6NGMGJDS24HHJNY35QC
5JRYIJOGYDTTIBNUQFB5DUHFPLCUEBSNMTZ4T34SDNTEDGHHCPIAC
5TKGFHC6X2JYR3MVN5T2XU2VWG45V7HGEI45H3BZ4B55WPULZEFAC
VCISXSXE6WGRO6PQN7Y6IFZ7C4VFUMKQK6KGAXA6YZ5RCZIB64WAC
CI5VTLSMB2L5W5ZVKDZEJFUARGSZP2FUSTRFV3MG6U44TDDUYH5AC
ZFHVWIDJGBUGJP5XKKI26HOVFQCT5ALKYLFZANNDIJXRKIXAUMKQC
JFJU5HJKIHKW7NRJMMM3BBAEK2SZYOWU5A5O22QFKFZX6QWECFUQC
HZK3YN3SAISTDS5JI4COBYFG7YB4ABDVENXWZZEYLFA2LDI232VAC
32B6H524I6YHMCVYFWZPHP32R4BURWJHMFGLYAEWADGI45B27ZUQC
ZRJSOM6JBS4EBKBNK4UZZ74KNMLDP7N6EWMDH2NF5GSBXXPEW3SQC
ZWYVZW5QFM5I2F6BLMNDDTV7FROJUHOO3O2BCBG7WSCKMKXUEMTQC
SPVHVYFXSG2RIHX5JBNTGOL3YP5SX3CYZEGN2HUE6AQDIXD3M42AC
X2SXILGEVQERETVZAHSFJXUOP3ZHXOE3JSU37SFYYS2UYFZNWKRAC
KFM2ARORBIJ6BGX456VFW7EAVRIYBVFUV53JH63GSKNOKVPJWQ2QC
CS2XCJNU5NFVOQUDQJCRHEECDBXH7J4YL74OBJPKQ4CYPAQVQKJAC
KESFTFAMZEQMX2KFQL3WXFSFS2VCKRPLGRFVDVOLNJHO7L63LH3AC
RRADDS444JWSL4KOJKNZFAIMWMZRLFR4KZPC2MJBCJPEPINC5CPQC
IGHO5UHUXYBLIHLUMLZ672YHAYUSK4FSFX7SA42XARIKLIMCVLUAC
UBQTNLYGD3SNWMUNGWUPX7EXEGQXOXCFCPWIVWBFE7ID7DJLPFWAC
OUEUG67YNHCAEAR5TYOBG3RMJYXG6WI52OAH5SL5OHZPNFHT7R7AC
53K44NBML2QHWLZNXU5HBY2MOIXRK7ZGFQYAWZFO663TCOJKVHZAC
BNP25NWD5OXPQEPLM3YJRJCRE24DH55RZKFCZPUX5NLWGOSBIYGAC
V2SIR47DZF52SZOVRUTQKTSJ4H7LKOFK654JGGHFZQWR64CLNAUQC
ILN2K6ASDZSMEHOPJ22IZLZJUO6DDGZTKAKXM3YXG6JZZHJNLX4AC
MXOCLQAUGWLOS7AOTYZ46JZDMRL4EVRK5YN4JJUQ76GLKBOBHEVAC
R6XS2HO5QX2FJUGL5UQQRNETKCMYWTUFPHPPS5SYWK3OQA4UDUQQC
// Returns a map for which PLACE: matches the given place.
int random_map_for_place(const level_id &place, bool want_minivault)
{
if (!place.is_valid())
return (-1);
struct map_selector {
private:
enum select_type
{
PLACE,
DEPTH,
TAG
};
public:
bool accept(const map_def &md) const;
void announce(int vault) const;
bool valid() const
{
return (sel == TAG || place.is_valid());
}
for (unsigned i = 0, size = vdefs.size(); i < size; ++i)
static map_selector by_depth(const level_id &place, bool mini)
{
return map_selector(map_selector::DEPTH, place, "", mini, true);
}
static map_selector by_tag(const std::string &tag, bool mini,
bool check_depth)
// We also accept tagged levels here.
if (vdefs[i].place == place
&& vdefs[i].is_minivault() == want_minivault
&& !vdefs[i].has_tag("layout")
&& map_matches_layout_type(vdefs[i])
&& vault_unforbidden(vdefs[i]))
{
rollsize += vdefs[i].chance;
return map_selector(map_selector::TAG, level_id::current(), tag,
mini, check_depth);
}
if (rollsize && x_chance_in_y(vdefs[i].chance, rollsize))
mapindex = i;
}
private:
map_selector(select_type _typ, const level_id &_pl,
const std::string &_tag,
bool _mini, bool _check_depth)
: ignore_chance(false), preserve_dummy(false),
sel(_typ), place(_pl), tag(_tag),
mini(_mini), check_depth(_check_depth),
check_layout(sel == DEPTH && place == level_id::current())
{
if (mapindex != -1 && vdefs[mapindex].has_tag("dummy"))
mapindex = -1;
bool map_selector::accept(const map_def &mapdef) const
{
switch (sel)
{
case PLACE:
return (mapdef.place == place
&& mapdef.is_minivault() == mini
&& !mapdef.has_tag("layout")
&& map_matches_layout_type(mapdef)
&& vault_unforbidden(mapdef));
case DEPTH:
return (mapdef.is_minivault() == mini
&& !mapdef.place.is_valid()
&& mapdef.is_usable_in(place)
// Some tagged levels cannot be selected by depth. This is
// the only thing preventing Pandemonium demon vaults from
// showing up in the main dungeon.
&& !mapdef.has_tag_suffix("entry")
&& !mapdef.has_tag("pan")
&& !mapdef.has_tag("unrand")
&& !mapdef.has_tag("bazaar")
&& !mapdef.has_tag("layout")
&& (!check_layout || map_matches_layout_type(mapdef))
&& vault_unforbidden(mapdef));
case TAG:
return (mapdef.has_tag(tag) && mapdef.is_minivault() == mini
&& (!check_depth || !mapdef.has_depth()
|| mapdef.is_usable_in(place))
&& map_matches_layout_type(mapdef)
&& vault_unforbidden(mapdef));
default:
return (false);
}
}
if (mapindex != -1)
mprf(MSGCH_DIAGNOSTICS, "Found map %s for %s",
vdefs[mapindex].name.c_str(), place.describe().c_str());
if (vault != -1)
{
const char *format =
sel == PLACE? "[PLACE] Found map %s for %s" :
sel == DEPTH? "[DEPTH] Found random map %s for %s" :
"[TAG] Found map %s tagged '%s'";
mprf(MSGCH_DIAGNOSTICS, format,
vdefs[vault].name.c_str(),
sel == TAG? tag.c_str() : place.describe().c_str());
}
int random_map_in_depth(const level_id &place, bool want_minivault)
static std::string _vault_chance_tag(const map_def &map)
{
if (map.has_tag_prefix("chance_"))
{
const std::vector<std::string> tags = map.get_tags();
for (int i = 0, size = tags.size(); i < size; ++i)
{
if (tags[i].find("chance_") == 0)
return (tags[i]);
}
}
return ("");
}
static int _random_map_by_selector(const map_selector &sel)
const bool check_layout = (place == level_id::current());
typedef std::vector<unsigned> vault_indices;
// First build a list of vaults that could be used:
vault_indices eligible;
// Vaults that are eligible and have >0 chance.
vault_indices chance;
if (vdefs[i].is_minivault() == want_minivault
&& !vdefs[i].place.is_valid()
&& vdefs[i].is_usable_in(place)
// Some tagged levels cannot be selected by depth. This is
// the only thing preventing Pandemonium demon vaults from
// 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("bazaar")
&& !vdefs[i].has_tag("layout")
&& (!check_layout || map_matches_layout_type(vdefs[i]))
&& vault_unforbidden(vdefs[i]))
if (sel.accept(vdefs[i]))
rollsize += vdefs[i].chance;
if (rollsize && x_chance_in_y(vdefs[i].chance, rollsize))
mapindex = i;
if (!sel.ignore_chance && vdefs[i].chance > 0)
{
// There may be several alternatives for a portal
// vault that want to be governed by one common
// CHANCE. In this case each vault will use a
// CHANCE, and a common chance_xxx tag. Pick the
// first such vault for the chance roll. Note that
// at this point we ignore chance_priority.
const std::string tag = _vault_chance_tag(vdefs[i]);
if (chance_tags.find(tag) == chance_tags.end())
{
if (!tag.empty())
chance_tags.insert(tag);
chance.push_back(i);
}
}
else
{
eligible.push_back(i);
}
return (mapindex);
}
// Check CHANCEs.
for (vault_indices::const_iterator i = chance.begin();
i != chance.end(); ++i)
{
const map_def &map(vdefs[*i]);
if (random2(CHANCE_ROLL) < map.chance)
{
const std::string chance_tag = _vault_chance_tag(map);
// If this map has a chance_ tag, convert the search into
// a lookup for that tag.
if (!chance_tag.empty())
{
map_selector msel = map_selector::by_tag(sel.tag, sel.mini,
sel.check_depth);
msel.ignore_chance = true;
return _random_map_by_selector(msel);
}
int random_map_for_tag(const std::string &tag,
bool want_minivault,
bool check_depth)
{
int mapindex = -1;
int rollsize = 0;
mapindex = *i;
break;
}
}
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()))
&& map_matches_layout_type(vdefs[i])
&& vault_unforbidden(vdefs[i]))
for (vault_indices::const_iterator i = eligible.begin();
i != eligible.end(); ++i)
#ifdef DEBUG_DIAGNOSTICS
if (mapindex != -1)
mprf(MSGCH_DIAGNOSTICS, "Found map %s tagged '%s'",
vdefs[mapindex].name.c_str(), tag.c_str());
#endif
sel.announce(mapindex);
}
// Returns a map for which PLACE: matches the given place.
int random_map_for_place(const level_id &place, bool want_minivault)
{
return _random_map_by_selector(
map_selector::by_place(place, want_minivault));
}
int random_map_in_depth(const level_id &place, bool want_minivault)
{
return _random_map_by_selector(
map_selector::by_depth(place, want_minivault));
}
int random_map_for_tag(const std::string &tag,
bool want_minivault,
bool check_depth)
{
return _random_map_by_selector(
map_selector::by_tag(tag, want_minivault, check_depth));
if (vdefs[i].is_minivault() == wantmini
&& !vdefs[i].place.is_valid()
&& vdefs[i].is_usable_in(place)
// Some tagged levels cannot be selected by depth. This is
// the only thing preventing Pandemonium demon vaults from
// 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("bazaar"))
{
wms.push_back(
weighted_map_name( vdefs[i].name, vdefs[i].chance ) );
}
const int v = _mg_random_vault_here(place, wantmini);
if (v == -1)
map_counts["(none)"]++;
else
map_counts[vdefs[v].name]++;
}
for (map_count_t::const_iterator i = map_counts.begin();
i != map_counts.end(); ++i)
{
wms.push_back(*i);
// Base chance; this is not a percentage.
chance = 10;
// Chance of using this level. Nonzero chance should be used
// sparingly. When selecting vaults for a place, first those
// vaults with chance > 0 are considered, in the order they were
// loaded (which is arbitrary). If random2(100) < chance, the
// vault is picked, and all other vaults are ignored for that
// random selection. weight is ignored if the vault is chosen
// based on its chance.
chance = 0;
// If multiple alternative vaults have a chance, the order in which
// they're tested is based on chance_priority: higher priority vaults
// are checked first. Vaults with the same priority are tested in
// unspecified order.
chance_priority = 0;
// Weight for this map. When selecting a map, if no map with a
// nonzero chance is picked, one of the other eligible vaults is
// picked with a probability of weight / (sum of weights of all
// eligible vaults).
weight = 10;
static int dgn_chance(lua_State *ls)
{
MAP(ls, 1, map);
if (!lua_isnil(ls, 2) && !lua_isnil(ls, 3))
{
const int chance_priority = luaL_checkint(ls, 2);
const int chance = luaL_checkint(ls, 3);
if (chance < 0 || chance > CHANCE_ROLL)
luaL_argerror(ls, 2,
make_stringf("Chance must be in the range [0,%d]",
CHANCE_ROLL).c_str());
map->chance_priority = chance_priority;
map->chance = chance;
}
PLUARET(number, map->chance);
}
if (vault == -1
&& use_random_maps
&& one_chance_in(vault_chance))
if (vault == -1 && use_random_maps && can_create_vault)
"altar.des", "bazaar.des", "entry.des", "elf.des", "float.des", "hells.des",
"hive.des", "lab.des", "lair.des", "large.des", "layout.des", "mini.des",
"orc.des", "pan.des", "sewer.des", "temple.des", "vaults.des", "crypt.des",
"zot.des"
-- The dummy vaults that define global vault generation odds.
"dummy.des",
"altar.des", "bazaar.des", "entry.des", "elf.des", "float.des",
"hells.des", "hive.des", "lab.des", "lair.des", "large.des", "layout.des",
"mini.des", "orc.des", "pan.des", "sewer.des", "temple.des", "vaults.des",
"crypt.des", "zot.des"
CHANCE: (number with 10 being default)
CHANCE: <priority>:<roll> or <roll>
CHANCE allows you to control the probability that your map
is used on any given level with an absolute roll.
There are two ways to specify the CHANCE roll:
CHANCE: 500
or
CHANCE: 5%
If specified as a raw number, the chance of selecting the
vault is <number> in 10000. If specified as a percentage,
the chance of selecting the vault is <perc> * 100 in 10000.
Note that CHANCE accepts only integers, no fractions or
decimals.
For any map with alternatives, a CHANCE influences how
likely the map is to be picked instead of the alternatives.
If a map has a CHANCE, Crawl will roll a random number in
the range 1-10000, and select the map if the CHANCE is >=
the rolled random number.
If there are multiple alternative maps with CHANCE, they
will be tested in an unspecified order; the first map that
makes the CHANCE roll will be used. If you'd like to specify
an order of testing CHANCEs, specify a CHANCE with a
priority:
CHANCE: 10 : 20%
This specifies a CHANCE of 20%, with a priority of 10, which
means this vault will be checked before any other vault with
a lower priority (the default priority is 0).
If no map with a CHANCE is picked, Crawl will select a map
based on WEIGHT, ignoring vaults with a CHANCE set.
Note that the Lua equivalent for CHANCE is a two-argument
function:
: chance(<priority>, <number>)
These lines are all equivalent:
CHANCE: 5%
CHANCE: 500
CHANCE: 0 : 5%
CHANCE: 0 : 500
: chance(0, 500)
WEIGHT: (number with 10 being default)