Vampires' drinking habits.
Allow other channels than MSGCH_TUTORIAL to use formatted strings and use it to send a coloured string through the butcher prompt, thus visibly setting off dangerous corpses. I'd like normal corpses (no patterns in food_colouring.txt matching) not to be highlighted at all, but they're currently shown in lightgrey, that will have to be improved.
Fix Vampire mutation screen displaying poison resistance wrongly.
Add a new option force_more_message whose syntax is copied from travel_stop_message. Any message containing a regex within this listing will enforce a -More- prompt. By default, it's only enabled for "You start to lose your buoyoncy."
Tweak the messages for Kenku flying to fix 1823833.
Make Xom be amused at players teleporting in a labyrinth or when becoming (Near) Starving while in a labyrinth and with little food at their disposal.
Yes, it's one of those "Something for everyone" commits. :D
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@5416 c06c8d41-db1a-0410-9941-cceddc491573
57E4T664CXRFPVW2BZBYI33UIHFS4PSEZURZYPSYSZK5DRLJJ5CQC
VSP2UVEASZS7NATQOC6C73SGVLLVVLFEPFSQKYGBM4I4D3HFE77QC
ZPYW5XKEOCWWBR2RSIKRLKAHI3KQJNYWM4PBV5LFYWSL4RWL2HOQC
SBTVKHKZRMVDBYLGQNMZMJXPAYJG43UWBBD7HQJWIPN3BMMHUBJAC
4DGRUR65VRRSNJH33DNNC5IWLDXEYF4MDE5CPNYQE7DPLQOC5THQC
IOMV4CS3PJA6VO3NYB6T45OTXQ5QYP6LT4JOCSLPKP22HWZ3FFKQC
RX6575DZOHRUXQUZH34YZGPZJF4STUPLBQDIVTINA2L6LVCKRIGQC
QTFUA7DXD2QGKBXT7S5Z7RDHZ7BYFYWZOZPOTP5ZBR3PMKH257NQC
6I5DGAACRD7U5HAN3EEKPL7MPZXEVGUNJU5REFL4Q2SRZJ5WKDDAC
KZQCE332EGX6EOALDW5QKS7CBYORFCOOM7UYE3B2U5PCOIKTMWYQC
5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC
UM2LNJ6FBISGASDHAZZPJEHTXRW4HPQZUTJPMZQ5PGWZOQEQB6RAC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
EFWEYIB2R3DPD3JWIPU6LS6SFLPMYN7J7X4GBZR7DJWKHJ3UELSAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
VOXLOCDUHOAFIKRTSISYMOA2QFY3TSHQGR7BKGGQ2VZ5BUUKUQYAC
HMC247EGUJ3Q25DQ3VKUCIGLIO4SZORFQQWAPAF6S2WLQY3WU5TQC
UET576SVCGS2TXEDRTO7BUTOTLJ77MYHIVZJCDWGH2BAXYMKG6DAC
YV5KGOLCV7DBD6P4ARYQDLVO4AAH7NDJPF6PNASLQSRAKJRVO4YAC
JJULXW764V5C2HJKZNWQAEWB6QM5YZADD7ZCE35LYTBFEM6PMYCAC
ENOQQ6DEA6ECRNTBGYYNK7G3DFEILMKQBNKP4SUQIZW2L6HWVR7QC
W6EWE6VIRP6OTSSTG3ZZEBN72OIKK6D3AEIP3OWX3HMJBA52SZSAC
J7KCPTGASQNRAKVKQ5FCXZ75E75PK7I2BB6MFSI3COWU6HRKTWSAC
QHAYBZTRPVJMK55WXT3F63CNRSAEVN3CQAAG42GCJTONLXQLNNNQC
YDDLIMYVR5YEORQ6YXEG3M4O26M3XIZ6OCXQTHEVLKTAAJP3FI5AC
AVCMVFA3MKCXHO6H44UK5KJNIHTGQV7UA7GYXM26VI6TXXU5ZN6QC
RC5SAVDRSD6X75HG3SEEFC444LXYMHASQFLOJMH6D6VTYHBQAJEQC
IMC2HA2YWCU7SLGGVQQVUEUIST4ILSOEAUYXNZAW2PJZ475GXLDAC
WCK6TM2ZD56WSOK6SMMKBYAYGG4OUCTILLMVVLMB4QO5I5S2IVNAC
264FLET5STFALEWUDOEFCR273Y5CY2WZDHL56WHZUAQ635RUN6MAC
7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC
BW3XFNOS6LDAQLHOZ6RXARCMKCY5JVLVDSXDSSAX4DSYM3FANQBAC
6HQB2N6N75R2RGKJFWRUN7WAC2PNGWQFXTII5DTRLTHZ2BOTMTVAC
2B4AQJIATJ4E7RFN6OTQITZNDBAPQ2VWWXLBCVYSORAFG2GIIDNQC
YZ3BCKFW4PTYDL5EG2PW52KKRHPWCYPSXYH7TJAINF3335N2XCHAC
GCIZIUXO5TYROKDUYB3HAY7H7MRDTJNM7HR7DGSH7KXDIZC2LCDAC
5B5DP5S6A6LQMKZYVLQAEMHQZWFWYDHPCKQGRNSCNNYIBQYZ6BIQC
ID2OZJTHFXL74RVUCS3JCMDQEUHAXCQFZU7235VU6IEVAAUWD2FAC
BFZZ7DFLZM4WNHQOKWDJENZOLMXH3UPHZ437BMISYJ3VSO2Y57WQC
GL6SGPBZQPJBVGPOASYVCTAFXS7RNARR6Y5WZMIO5YCTB7ZJY4KAC
7FUHFAXXCAL5TZ3MGUVMWH44637Z7WYJOM5Y5P6K6YPO22TNLDJQC
XX62GOJVDP352L4BH7MELNYXHMZNA6VAGF7B6RWWOSULX7VJR5YAC
TOKBONNNPTP2CIEHMMR4QAJZTXYETS55OGGDA6FY6NIMNDYMWJDAC
JYCMD6WMNHXA53K4LLKVTNX6PLRLU25F6J2TYMPQXM2ENAE66NIAC
IHOKNI4O7EEW4UBMKHP6XOZNEIQSW4AYOT4O3JXUIXNNR553IQAQC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
CVC5FFFLGVRR3KPYDNB6RF4FNACV3LI3HPSR4MCUNZ4C3FSQYBDAC
3D6NWJ44UYHLZMD3BOQIWXJUEGITAVCHK6Z2WWDQONVQC4HSBRXQC
NGW2XPEX2XRK3CYC37DNUZSSB5IQLECMKRB6NX257I2X3G35LMPAC
M2HMYLYYXSP5XGX6MCI77IT6UW5K4YSEUJWHPQPYXVSW5L36BJ2AC
RQR4PTMGQLTRWLYRU3KXIIDGND7FBORESJWMWFVD3WYU5SISZXAAC
ASLW3Z5PAVZSWJEMMMVZT226P44EKSAD47QS72JIFJESAI3RPN3AC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
O6ZMFKDI3XO2SWPNEYHIPYFDWJR4TVDP5BAATK6LVCVETQID6E7AC
ARVJY7XPMCHI4IAQMD2VUWTAXQLCRNVSM2MK3YT4S4WHQYFTLEMAC
GKA3ZGZ2P6F22FDNSYNQDMCS3N7HNZD5QCOSQ6VJRAU2K5U4YYTQC
JCWJWGMQIKQGSSFJUQRKNIWW3HBOJSHYDTOPPE5BWOJTIJTDYUTAC
U6Q43EFKHJIDBBWN6RUTOYRHHX4IT73OPBR4CWIOKUDGTCYQE5PAC
QXD3HX6QQ37PW6HVKIIKGFLO2ACROLUGKK66KFX7ED6SO4FDXB2AC
YOZHWGKGPWZGHQYNMMBHNGDO2UEVIHPOR6UF3SEZPIYWVMBGWBOAC
TFNFP2YQA4EOVE4VIXBEQSGACZSXHWIQ2T4TIPQ46R2MJW2C4B5AC
5S3CAGZSAQC3CYFPM5TQFPHW5IE2OZRVFJMICQZXHBZRGKFMNPRQC
MLZSEZWNNZMSIDQNAAIOJJR4K7VSVJICL5SAGHD3ROM7SYDVZABAC
CWTKS62IFZYYR3HGPDP5LW5C53CRWVAD6AAEOV4BSWNW52BCQH3QC
TMFNNWBMIPWM2FDC7I5R2RUKWNBS3GD3DX6VN452VYRPC3GU2HCQC
TRCCLE5RJ4VJULBOWOI2WC3RJU7WTEGS7RRQTDQL6W5UU246LKTQC
KBNY5FWKTEAKABFCLPC3QFKFSVZKAGXINPCIFV6WDSWFO4VCKNTAC
FXVDNB6MAAOSEP37HP7CIPPXNS7FDECN3GCRMT5UFFCKLHIL6IVAC
TDAVD56MGLFSMJLPLSYLEVW7MBRMT7V5BNII4TRWVDIHH47CD2OAC
THEWZBBFONK266AMYIIFQ4SFGZMTMU62ZO2Y43UMCDD6DDBSDYKAC
F2ZJ55CL3T66DFM34BQWCJNHIT4XJFCGTWTA5KESV6NHWFLTGUYAC
RVST2QHYJ757ZHK4AUJ5NGPDZ44AD6RVFVXYPKQIBJXZBDNUCHXQC
WL5WZXFJ6TONUQRSHUY4GQ5USU47ILWNN5X2JDQZO4CRJJZSRQIAC
EOMCPVNQLX3IMLC46EAO67DPBH5KEG2FQTPBLGU62HIRWA3UQ7XQC
EHSY6DVGUMI6C67WKET3GDJVLWJWGYBYQONNDK5JVT7BCTHBEZVAC
// like yesno(), but returns 0 for no, 1 for yes, and -1 for quit
// alt_yes and alt_yes2 allow up to two synonyms for 'Y'
// Like yesno(), but returns 0 for no, 1 for yes, and -1 for quit.
// alt_yes and alt_yes2 allow up to two synonyms for 'Y'.
// FIXME: This function is shaping up to be a monster. Help!
if (randtele && player_in_a_dangerous_place()
&& you.level_type != LEVEL_ABYSS)
// Teleporting in a labyrinth is also funny, but only for non-minotaurs.
if (randtele
&& (you.level_type == LEVEL_LABYRINTH && you.species != SP_MINOTAUR
|| you.level_type != LEVEL_ABYSS && player_in_a_dangerous_place()))
return;
}
std::string help = inf;
if (help.find("</") != std::string::npos)
{
std::string col = colour_to_str(channel_to_colour(channel));
if (!col.empty())
help = "<" + col + ">" + help + "</" + col + ">";
// Handing over to the experts...
formatted_mpr(formatted_string::parse_string(help), channel);
// checks whether a given message contains patterns relevant for
// notes, stop_running or sounds and handles these cases
// Checks whether a given message contains patterns relevant for
// notes, stop_running or sounds and handles these cases.
// message playback explicitly only handles colors for
// the tutorial channel... guess we'll store bare strings
// for the rest, then.
if (channel == MSGCH_TUTORIAL)
mpr_store_messages(fs.to_colour_string(), channel, param);
else
mpr_store_messages(unformatted, channel, param);
for (unsigned f = 0; f < Options.force_more_message.size(); ++f)
{
if (Options.force_more_message[f].is_filtered(channel, st_nocolor))
{
more();
New_Message_Count = 0;
// One more() is quite enough, thank you!
break;
}
}
mpr_store_messages(fs.to_colour_string(), channel, param);
// for tutorial texts (for now, used for debugging)
// allow formatted output of tagged messages
if (Store_Message[ line ].channel == MSGCH_TUTORIAL)
// Allow formatted output of tagged messages.
formatted_string fs = formatted_string::parse_string(text, true);
int curcol = 1;
for ( unsigned int j = 0; j < fs.ops.size(); ++j )
switch ( fs.ops[j].type )
{
case FSOP_COLOUR:
colour = fs.ops[j].x;
break;
case FSOP_TEXT:
textcolor( colour );
cgotoxy(curcol, wherey(), GOTO_CRT);
cprintf(fs.ops[j].text.c_str());
curcol += multibyte_strlen(fs.ops[j].text);
break;
case FSOP_CURSOR:
break;
}
case FSOP_COLOUR:
colour = fs.ops[j].x;
break;
case FSOP_TEXT:
textcolor( colour );
cgotoxy(curcol, wherey(), GOTO_CRT);
cprintf(fs.ops[j].text.c_str());
curcol += multibyte_strlen(fs.ops[j].text);
break;
case FSOP_CURSOR:
break;
else
#if DEBUG_DIAGNOSTICS
cprintf( "%d: %s", line, text.c_str() );
#else
cprintf( "%s", text.c_str() );
#endif
message_filter( fragments[i] ) );
}
}
else if (key == "force_more_message")
{
std::vector<std::string> fragments = split_string(",", field);
for (int i = 0, count = fragments.size(); i < count; ++i)
{
if (fragments[i].length() == 0)
continue;
std::string::size_type pos = fragments[i].find(":");
if (pos && pos != std::string::npos)
{
std::string prefix = fragments[i].substr(0, pos);
int channel = str_to_channel( prefix );
if (channel != -1 || prefix == "any")
{
std::string s = fragments[i].substr( pos + 1 );
trim_string( s );
force_more_message.push_back(
message_filter( channel, s ) );
continue;
}
}
force_more_message.push_back(
text << "If you dropped the " << noun << " in your pack on solid "
<< "ground then you could " << verb << " " << pronoun << ".";
text << "If you dropped the " << noun << " in your pack "
<< "then you could " << verb << " " << pronoun << ".";
std::string corpse_name = mitm[o].name(DESC_NOCAP_A);
const bool sacrifice = (you.duration[DUR_PRAYER]
&& god_likes_butchery(you.religion));
// We don't need to check for undead because
// * Mummies can't eat
// * Ghouls relish the bad things
// * Vampires won't bottle bad corpses
if (!sacrifice && !you.is_undead)
{
// Don't bother colouring if it's only for sacrificing.
std::string cprf = menu_colour_item_prefix(mitm[o]);
std::string colour = "";
std::string colour_off = "";
int col = menu_colour(corpse_name, cprf, "pickup");
if (col != LIGHTGRAY)
colour = colour_to_str( col );
if (!colour.empty())
{
// Order is important here.
colour_off = "</" + colour + ">";
colour = "<" + colour + ">";
corpse_name = colour + corpse_name + colour_off;
}
}
(!can_bottle_blood_from_corpse(mitm[o].plus)
|| you.duration[DUR_PRAYER]
&& god_likes_butchery(you.religion)) ? "Butcher"
: "Bottle",
mitm[o].name(DESC_NOCAP_A).c_str());
(sacrifice
|| !can_bottle_blood_from_corpse(mitm[o].plus)) ?
"Butcher" : "Bottle",
corpse_name.c_str());
static bool _player_has_enough_food()
{
int food_value = 0;
item_def item;
for (unsigned slot = 0; slot < ENDOFPACK; ++slot)
{
item = you.inv[slot];
if (!is_valid_item(item))
continue;
if (!can_ingest(item.base_type, item.sub_type, true, true, false))
continue;
if (food_is_rotten(item) && !player_mutation_level(MUT_SAPROVOROUS))
continue;
if (is_poisonous(item))
continue;
if (is_mutagenic(item))
continue;
if (causes_rot(item) && you.species != SP_GHOUL)
continue;
// Vampires can only drain corpses.
if (you.species == SP_VAMPIRE)
food_value += 3;
else
{
if (item.base_type != OBJ_FOOD)
continue;
switch (item.sub_type)
{
case FOOD_CHUNK:
if (!player_mutation_level(MUT_HERBIVOROUS))
food_value += 2 * item.quantity;
break;
case FOOD_MEAT_RATION:
if (!player_mutation_level(MUT_HERBIVOROUS))
food_value += 3 * item.quantity;
break;
case FOOD_BREAD_RATION:
if (!player_mutation_level(MUT_CARNIVOROUS))
food_value += 3 * item.quantity;
break;
default:
// Only count snacks if we really like them
if (is_preferred_food(item))
food_value += item.quantity;
break;
}
}
}
// You have "enough" food if you have, e.g.
// 1 meat ration + 1 chunk, or 2 chunks for carnivores, or
// 5 items of fruit, or 1 bread ration and 2 fruit items as a herbivore.
return (food_value > 5);
}
// Now you can only turn levitation off if you have an
// activatable item. Potions and miscast effects will
// have to time out (this makes the miscast effect actually
// a bit annoying). -- bwr
_add_talent(talents, you.duration[DUR_LEVITATION] ?
ABIL_EVOKE_STOP_LEVITATING : ABIL_EVOKE_LEVITATE,
check_confused);
// Has no effect on permanently flying Kenku.
if (!you.permanent_levitation() && you.flight_mode() != FL_FLY)
{
// Now you can only turn levitation off if you have an
// activatable item. Potions and miscast effects will
// have to time out (this makes the miscast effect actually
// a bit annoying). -- bwr
_add_talent(talents, you.duration[DUR_LEVITATION] ?
ABIL_EVOKE_STOP_LEVITATING : ABIL_EVOKE_LEVITATE,
check_confused);
}
travel_stop_message, runrest_ignore_message,
runrest_ignore_poison, runrest_ignore_monster,
trapwalk_safe_hp, trap_prompt, rest_wait_both
travel_stop_message, force_more_message,
runrest_ignore_message, runrest_ignore_poison,
runrest_ignore_monster, trapwalk_safe_hp,
trap_prompt, rest_wait_both