properly generalize the checks for item-eating monsters.
Currently, monsters' eating abilities are restricted to items (jelly types) and corpses (necrophagi, ghouls, and hungry ghosts; the last can eat corpses in some legends). It should probably be extended to harpies at some point, too.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@10628 c06c8d41-db1a-0410-9941-cceddc491573
PC6K5OQF3BWPMWTIN5JXAKHTZF453JQOELDWRUOSBZXR256FTUYQC HVF5GB6LMI4WDUXMU2UFXMOXML4B6HQWJLDZO5HE3ZESATZCGHCAC X76BZSFTVOIC6EVXDSBRPKFM227O37UC7HMONSZT6GYOBGYKFE5AC QUCSVB67V5K3B6DHP2HLM7U63GUKT6KOF3S443PXCOUPN4UIGYZQC 5WZBSOTN3CY26JNCVXUEBYFXKPNSWRPODG6XWLRHLV4T7HEICRWAC SQKDQNOTGPJG3H4YDDEYRLO6GRUZ5BTZRKKN6XS6ZVNB4BNDQDYQC AU2EFNMEXJJVYSZXWJ7UYY65OWH62AQHBAUDLUOY4M3A5GJB7CPAC J3TQJFHTYT24FMBWZ3OWA5VDLYNZ5TL2JX4UVXVUJGUGZBG4A2GQC BRYDK7XNQUU2WKPC45FHHTE3WZLNGJTCJEPDOBG4L6C6YPOP3JUQC QVG6UKV7WYZK3UO23HFHEPTCJXDSJXSOZW57MNDXDPNZGEUVBQFQC L2EFOLMGPPGYT2HDHW4FSRZ2JWPBR7Q4GAPKDKYXHD2AJ2PIODLQC YRRWJM2XOQFVNL2VGHI3EP7ACLQ4FWHAR5KH573LE7MP4NDSPA6AC FYASQYFOCCS5CBY4JA5ZREEBNOL62BRZ3OFWTCCFLRH6L5YGW7NAC CLWTLZY5ULOZKRRDA6OCTFN34GCR5L5UZZZAMQAOZZAWD6FMQZ3AC LAFEHLILTGGK6HPVUYZ5YLK5AFNPG77Q6HUE4UFAHN2EVXLWNFPAC TZ62VYV5FM6KLDDLFQHYFR4OSYUBOWUPGAX7LR376YJBQDVIPIVQC HHAQ34UDM5Z27ZJB5IWSHYD7KKGYKOZSFKUZIBZJ6GEIWG4VW6NAC Z3H73NQZ4GWOCQUAOSBV5L2DCEBGAMA5WDZ3ZO523PQANJZIRYXAC IVCUCSARYCTHNMEOOV57MJ2IWCJKDRRZECO3EE4TGES2CE4ZKU4QC CGFRVQTOR7WIV5UBRVVEVRGTGJFFHT3JNYLNHHAJLQUE2AQSW5SAC N2ULVEU2ZCF4LKHJ2H6KWGG7LCP2WHOIGLXCE3EK47ND3QWVS42QC OM34VHDXECRX5GEFXHNDGXVVSUPIAUSRQVWCSPF3RXQ5DYQLMJ5QC FW3PIRSTFPX7VNUAVASCBB7VPYJHGPRSHXC4S6RXCLSLJMGWS6QQC IXO5VNCDYDYI46Y5QWNJMD7TURKYO526CJA4TIMH5PDDAYHMK5YQC 2LLU3OUASGBZPBFLVBQRC33L4UQV6QFVNPT7LX34B3LFQ7LKE57QC WVVQONQMNXR3XQCEZOHBI2KSTXTSX2CBJNIWWD3O53KFB2VNAWEAC 4PT7GOXKXSBWAWYRV7IUFUFLS7GMND3C3ASJL7NVD5AREIGHWIHAC AFHBHRB752ORI6ALRVZLPJ4WO2VYLABP2ATTEEVWMTKSN46XZBZQC 5WVUTEZLEZEML54CKPR6GACQBYY3EMVNXMLJOREN6SSEUZGC47AQC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC NLQNXH3SVJ52CWXEV35FSSZP32VHC4QFGN3HINF4KO5GZHZMOBKQC TJ72NVTRNJKF55RTH5MRLTHHVPOJ2M5OOYEWF4UFLTO2PPPTU6PQC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC GGEB64C3QQ5PPS7GOFXULDUCRT2NZL2PMIE5UDDUJTUTLLPTDU7QC LTX72QGIPNUGWQN5ULPOMFCOPZTK7472DQY4AYX5WM3WHSUVXI5QC KAOE5HB3THUKVGFZRO5EZESHEB3Q34WUO5DFMLWIKOBF47LZTIYAC M6JQ7Z4RM3KUHVM74UNVUUUO4WV2CEW663CSHCKANVQ4PUVRIMFAC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC Y2NYY7HWFZ2LQDK3ACSLGS37F2J2IJ5LRGCIMZYXLEOSVPD3A4DAC EFWEYIB2R3DPD3JWIPU6LS6SFLPMYN7J7X4GBZR7DJWKHJ3UELSAC BQXHIR3D7LBBMUMNNZC76YZS2BDD673KRRRLPXTNXUDMHTQK2RTQC NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC CWQGOO5TNRXAXGZ57JAQ7JUPZVV2QUOOYUJAIMMPOVS4REDJB4ZAC 4UXFU3FZOCBSLDQ4S7MJKAE2H7VUHCNRDQMIY6NJ3PHYXWNGISDQC RGY2525RQH7SSGM6ZVI7CZL4WMNFZK2WRABOSIWRKQYYOU2RWN4QC LZN527GR3AULRHWIBA537RR4WSCNNYY4XSEZ6VFF7TKGYSUSBOCAC KT7JMMRJJ4LI2ZMKZSZYCMQ54A3UDHYJOYUZWFBBWRR5DDYE4EIQC Q4AG4UGLKBPH5KGVHHUPSTXQDLKDOBLQYYHYDJNNOJDZG3Y3PWXQC TGJZXTUIAKCFZQJ54ZQEBGFBVZSJCAX6AWDRSH3TP7UJRLGUM5SAC XRZPPYWPWUOM4SFNI6BHKH2UKJQNLKOV6Y7XIEPEZXE5QYRT26PAC ZGUJWUFJ4NFFJ6PGXLFGQWCWBCZHPWGWI44NJHJEVPRG5L36PADQC FSD7GIK3YLZXWLEH37BU6KV3IUCFGXPQL6IZ7H65YWNRBEKDBX5AC OMGPA2JNIW5BPBUG6LFK5M2UEB6JH6CT7MP6DH3NKFTJVVLNWWCAC KF5BNN42PTO35TBQD5CNMDXFAXHYCSQTBOOXZV7I3ML5VASUUT5AC SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC PFEJ4LMDNEKLMGRCMWQ7EIRVU4JMYGICI4G7X4WVWOROVXQCBZ7QC R22TTMI6WXWULC7ODKFF3QCB7MOTETQQ6IR4BUCUPOCQKQNCTT5AC ZVG6W2UMHJ3GHLF4ZVCUHZOOEUNJMWPURVBN2OQXKVTXYC4Z2LPQC LHUDGRLJC6O4GDPCE2Z5OONRZFSYDJMZ4YGL6AQZJPVXJ2KR5ODAC B4YYKEZVHLGRFAHEP5ATEV4MYRPGXQPWTUXGGG7ITZH3ZGV3VMBQC 5V47S4NNTHWTSAHV3YLO2VGH7JTUIYJ3GBPDN5ZM4UQALT2ZEXDQC QS3ZRS3E6KL3YJHPKYEWCWJYRBJSXD5OOYF6Y25HZVECGPJRDB5QC SYOUKIZKYUNJ7YVII2XYYZXYDXEN5I6SB7OIUIPXQMBF2K4HZFSQC 33ZMPQC6OXTESW7SRW765GRNJUEJRSYONRVZVIEUDAUEJ2PPMB4AC 2GUJEAQN5CVJOKMEZANI6QQ6JFJZGCS6TDKHTVP4NZFXVNSYZWEAC ADIVVYTV2MJ3XVRYDNBLPTAEACCNF27XZDCRVZFQEHRHPMZGNITQC 47NSOFQMBZCDIBHEAZSENFUGDSQCX3GJHFBUZ65ARDKCYIZ435LAC GASNVWKEMRKFEMHIQPMD5XRJ5PVDVSSHCFHV6HWTR6PRKRCUP4EQC BDTWKBUEAFESWE74IUU7IFK2RDZKSIBSVRZQXZLPX2RRN65TRIUQC UBJ3K77N3ESM5ZHZAND4FDTONECSSB3NUNL6QQA7ATSESSCW5QUQC BINKDWGFGUPTOA7IE5KK4ZIELGU5WC3X47MYXOWU4X43EGAC5DUAC ASH5CK6CPBKMLGGIRJ5GKTWMS5W3OBVHTL66RTYZIPFM6KFBYA3QC X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC OSGS3PH2L5CBTDVZCZS6OCFQNA4A7RMEXBYJQB7DDZBYYJW7QSSAC CG4TL4AKSN4J7CMATZFJ5N7PSDCQXLS3QYX7PZ3K67KMMBT675OQC ZMED4SUEZTGX762DHBTMAZYNJZDV7RFFKMELFSTCM4KZFX553H5AC AY3CBJCAR4XMZODH5N4DVJXXJF3B5HUKICRGO7KCTCFACAYVGN4QC T4FNOPMWYYJHJBTTY33PB43HTJPKEC46L62YERTWIX73HYZSELXQC WMHFDQKUDCUGM3R245LLVZ5NNEZSCXFDSTNMVS2O5EFUHHO7HU3AC 3WHI3KM43ZCN4ITJLFQQBQBC4OJPRS7QTBPIQ6QBCUVKRSK476SAC O7OBYGSZTPWMK3EADTZWXQ6VAEMMFEK2I4MXTCMOQJKVJMLYEB5AC MHWSAWELF3VEV52PNGAI43GK7OGF5PTYATO4O7ERZ75O7RCRKQRQC BIY3NZ7VMD2BY4PTFRWG65C7NODLQXY7CRXIOTOEHJC2NBT2QJMAC 27QXJ4J5YOSK5RDDEYJC75YA3GQLK5F4HCQRIBUYIRRUJ6BID35QC ZX2BGBBNWBF5NNDT2RXGNQYXC6RV5QIC4N4IFHK6CT6BM7NRCDLAC KZWOHH536QBWAPWROR32EOXEK5LRY6I5VHVL7HHI7GOFKCMQTCSQC JFDTUUUT6AKIGPBKGYFC7HZKGQUZOMG7EUWU4QYKSDVXXPQBBFHAC LIGJ4EFGYMNHEEC2K3SMXTXULAB2U5LCRVTGTEYJLU74KKK6OIMAC GDMMLW5HKFUFEVA7BKREZGIAHV3KAXN2I7DY55RQFHXS5NVAAZZQC LHYTGOCNDWX3CVD2HSQ6LAYC6NLKKI6ZKKNWZ5IQWP6YP5PQEVWQC VJHHPMXQDIX6YV5SO4O2ITJTQLU4YI3QQABCKSPI27L2YJ72UOCQC MQF53ID3RRGZNJRW3LUWPIU5BGA7I2RRQZR7HISKX6PVNSAG3QWAC 3HGELZU7NELOQ635HZO6IJIYLBSNCJ5VPH46IE22KA3OSLEFK7AQC 3RSGUIHINKZQ467SKRG23I7G56OV7NLS72S7FHXTZEGGL2T64UMAC GPEJOT73KMACP33IPAKFR5ROGHCOIP22VXZMQNYTGLEA2OSZUM2AC W24ORBSALASTWLBXE6F64VS3ZFK3LSBQPQVTXVUGLLODUAFWQPHAC OBRWC5CZCGCM4MTOVKMWZEAA5IPZC67MJLUXEC4V34FBDERWHQYAC RSAN6BKBL55SZRZV74QUELL5SEHKPWCLEQMYH5U5UE6HFTE5HDLAC PWY4VZVHDLYL7UVNCCOW7BM7LYK2BOGTL23P75HXUJ33MHJPEJPQC NIRBZYFEXG46J43BC5PUYGNDOL6NE2UG6RHLKSPNCYPJI5EGH5LAC 5YVMU75DJF7S6TJAFPNPVNYLSY2ZYLJTNCTKUKVEE4PJTFTIUP4AC 3LLRMOYSJ7LPXMSASNGLSR3UOVYRQENQVFCENLEFYDLKANWS5UJAC 4QRLZDW4KBFG34B3MCG4375NHFR3WKWSLWQKRMQ3OE5R26WCZBBQC UPUR43MXCLHJOHYGKGRA4XAGB4GXW4RNCGCDCB2MXJDV3DIEISIAC M7WTOF3BVX5MGA7AQZB22YEFWCSL7RLW54PQM3MTRLCKUCUZZEUAC NRYVIJKSDT2OYPLA7IXZKRKOGTMJEU76Z3DZPXZJIDXWF2ZZKXUQC MAK2SOU5NCRMJPPFU6FCQZNQITS3QVIDXVW5V5CV4M3OSUOERREAC V3PK6UP5BCJOWCMLMAR3GNYJT425FD4VIMB4G4TGCPOADHG62LMQC 35GQND22JGU5QJKBIXM5QCKY3YDF4RTHT6WXURVGIHWDR26N6TYAC AGKLT4LWLCN3JE4K72NLWJ2KWVH7QQYUT22B2YTKEJOIPVR3XITAC 54X7E52H5TIGNBO5XIP7NNK4NA7XQVHETYB2CRLKBGZVMQJZ2TQAC 6RQ5YXKQ2UQEDYE7C57IVGJH2DFVUZE2IB5UPYEWJL6LSNTYUUJAC JYEEOUYQ7ZPKOGWUV7VCORBVSOLF2UCBFBH3TR75RGOSS6PNKYUAC BMKL2AB2HBBBVAHWDYXPYZHSCO345QWOQHFSICFRN5BCYZ3UEK3AC QAUXI2U6XHSKZTLWIDBACYCHVFEKHFZSS3TMSADAJKH2TJGDYJRQC MICCXRO7MWRW7RXNA4BGSJPUFZHJMWFP5OM3OTQCH7ORCGOAQPAQC R2DQBWKIW7YUJB5SOQ7J274JIYRVX4H3ISFRPAL5RG2RVVP4G2KAC BLM2OPXHWXU7RSYQSEKOEVRVS6XRSQFLHIU73YFUDW2KVF77V5HQC 2FHNLTLN3DVVD67N4QMAQ2LO7YY4GVZWXJAOIWGCCYYGIX7UHSVQC CQKH4FU2BZOMP5VWWOH2CEWDAYOV7FV53VOFQRF7R64DCQMP73LAC NQ5X2L66MPWZTR3ANZDBQ5ISPDTJ3AGEYTFQIS437S7MOTXN7A2AC BNE3OKRCLL3BVGH7RSLHXU7E6IVDNII3GUCUDM6W4T7UCU6XQ7HQC QSPLWL6QWR5RGGORC4XJ3ICIII5JY6MLQFSD7JOI2QL664KNK5VQC OG5QJYVF3IPLPQR7ZASAIWQLAQLGVXTI7GIIVOUN2ZAXFPVFYUXAC PQYLCUBDA6P4UY7X3NLIUUKMJ5GTQTB5X64VNSQVMCFS6ONMXXOQC RKROW7KCH7MJL4PYI5RRWEPNFAWTZU6GIZVHLUWP34NDU63HELUAC NHCEH7ZFP3IFRMZMC25ZA2X5ZSS3MOCHCYLVCSVY7RTY62WX7UAQC K25HMGF5625EQYQENFEWILNFIBK5FAZYYURPJV6UPIPIRWW5FNXAC EJYK3CKIEMP4NMZUCMUYLHIBE7A3LPZOU7DUON5V7CPHY7QEKLEAC CCDQMJMMVC6MIZRZ6JSKKCMEDPUGEVVSFPJUOC5WP63J6SX35MXAC GRVGLW4QW6BMLK4E3HY7YMHFV2PWGV7BPVFMOTX5APYKCWNUELOQC 4ZP2AEI7WCXZCK2KFWGKCUMEOG4GEB5JM32YVQGH7PMTQRFS5FYQC //---------------------------------------------------------------//// handle_pickup//// Returns false if monster doesn't spend any time picking something up.////---------------------------------------------------------------static bool _handle_pickup(monsters *monster)
// XXX: This function assumes that only jellies can eat items.static bool _monster_eat_item(monsters *monster, bool monster_nearby)
// Friendly jellies won't eat (unless worshipping Jiyva).if (monster->attitude != ATT_HOSTILE && you.religion != GOD_JIYVA)return (false);
if (!_is_item_jelly_edible(*si))continue;
int hps_gained = 0;int max_eat = roll_dice( 1, 10 );int eaten = 0;bool eaten_net = false;
#if DEBUG_DIAGNOSTICS || DEBUG_EATERSmprf(MSGCH_DIAGNOSTICS,"%s eating %s", monster->name(DESC_PLAIN, true).c_str(),si->name(DESC_PLAIN).c_str());#endifint quant = si->quantity;
#if DEBUG_DIAGNOSTICS || DEBUG_EATERSmprf(MSGCH_DIAGNOSTICS,"%s eating %s", monster->name(DESC_PLAIN, true).c_str(),si->name(DESC_PLAIN).c_str());#endif
hps_gained += (quant * item_mass(*si)) / 20 + quant;eaten += quant;
int quant = si->quantity;
if (mons_is_caught(monster)&& si->base_type == OBJ_MISSILES&& si->sub_type == MI_THROWING_NET&& item_is_stationary(*si)){monster->del_ench(ENCH_HELD, true);eaten_net = true;}}else{// Shouldn't be much trouble to digest a huge pile of gold!if (quant > 500)quant = 500 + roll_dice(2, (quant - 500) / 2);
if (si->base_type != OBJ_GOLD){quant = std::min(quant, max_eat - eaten);
hps_gained += quant / 10 + 1;eaten++;}
hps_gained += (quant * item_mass(*si)) / 20 + quant;eaten += quant;
if (you.religion == GOD_JIYVA){const int quantity = si->quantity;const int value = item_value(*si) / quantity;int pg = 0;int timeout = 0;
if (mons_is_caught(monster)&& si->base_type == OBJ_MISSILES&& si->sub_type == MI_THROWING_NET&& item_is_stationary(*si))
for (int m = 0; m < quantity; ++m){if (x_chance_in_y(value / 2 + 1, 30 + you.piety / 4))
// Shouldn't be much trouble to digest a huge pile of gold!if (quant > 500)quant = 500 + roll_dice( 2, (quant - 500) / 2 );hps_gained += quant / 10 + 1;eaten++;
simple_god_message(" appreciates your sacrifice.");gain_piety(pg);
if (x_chance_in_y(value/2 + 1, 30 + you.piety/4))
simple_god_message(" alters your body.");bool success = false;const int rand = random2(100);if (rand < 40)success = mutate(RANDOM_MUTATION, true, false, true);else if (rand < 60){success = delete_mutation(RANDOM_MUTATION, true, false,true);}else{success = mutate(RANDOM_GOOD_MUTATION, true, false,true);}if (success)
if (pg > 0){simple_god_message(" appreciates your sacrifice.");gain_piety(pg);}
if (quant >= si->quantity)item_was_destroyed(*si, monster->mindex());dec_mitm_item_quantity(si.link(), quant);}if (eaten > 0){hps_gained = std::max(hps_gained, 1);hps_gained = std::min(hps_gained, 50);
if (you.piety > 80&& random2(you.piety) > 50&& one_chance_in(4)){if (you.can_safely_mutate()){simple_god_message(" alters your body.");
// This is done manually instead of using heal_monster(),// because that function doesn't work quite this way. -- bwrmonster->hit_points += hps_gained;monster->max_hit_points = std::max(monster->hit_points,monster->max_hit_points);
if (rand < 40){success = mutate(RANDOM_MUTATION, true, false,true);}else if (rand < 60){success = delete_mutation(RANDOM_MUTATION, true,false, true);}else{success = mutate(RANDOM_GOOD_MUTATION, true, false,true);}
if (eaten_net)simple_monster_message(monster, " devours the net!");
if (success){timeout = (100 + roll_dice(2, 4));you.num_gifts[you.religion]++;take_note(Note(NOTE_GOD_GIFT, you.religion));}elsempr("You feel as though nothing has changed.");}}}
_jelly_divide(monster);}return (eaten > 0);}static bool _monster_eat_corpse(monsters *monster, bool monster_nearby){if (!mons_eats_corpses(monster))return (false);int eaten = 0;
if (eaten)
// Limited growth factor here -- should 77 really be the cap? {dlb}:monster->hit_points = std::min(100, monster->hit_points);monster->max_hit_points = std::max(monster->hit_points,monster->max_hit_points);if (monster_nearby)
// This is done manually instead of using heal_monster(),// because that function doesn't work quite this way. -- bwrmonster->hit_points += hps_gained;
// Assume that eating a corpse requires butchering it.//// Use logic from misc.cc:turn_corpse_into_chunks() and// the butchery-related delays in delay.cc:stop_delay().
if (player_can_hear(monster->pos())){mprf(MSGCH_SOUND, "You hear a%s slurping noise.",monster_nearby ? "" : " distant");}
// Only fresh corpses bleed enough to colour the ground.if (!food_is_rotten(*si))bleed_onto_floor(monster->pos(), si->plus, max_chunks, true);
_jelly_divide(monster);}
eaten++;break;}return (eaten > 0);}//---------------------------------------------------------------//// handle_pickup//// Returns false if monster doesn't spend any time picking something up.////---------------------------------------------------------------static bool _handle_pickup(monsters *monster){if (mons_is_sleeping(monster) || mons_is_submerged(monster))return (false);const bool monster_nearby = mons_near(monster);
// Jellies eat doors. Yum!// (Jellies don't realize secret doors make good eating.)
// Monsters that eat items (currently only jellies) also eat doors.// However, they don't realize that secret doors make good eating.
mon_itemeat_type mons_class_itemeat(int mc){ASSERT(smc);return (smc->gmon_eat);}mon_itemeat_type mons_itemeat(const monsters *mon){if (mons_enslaved_twisted_soul(mon))return (MONEAT_NOTHING);else if (mons_enslaved_intact_soul(mon))return (mons_class_itemeat(mons_zombie_base(mon)));return (mons_class_itemeat(mon->type));}
bool monsters::eat_corpse(item_def &item, int near){if (!mons_eats_corpses(this))return (false);if (item.sub_type != CORPSE_BODY)return (false);
hit_points += 1 + random2(mons_weight(item.plus)) / 100;// Limited growth factor here -- should 77 really be the cap? {dlb}:hit_points = std::min(100, hit_points);max_hit_points = std::max(hit_points, max_hit_points);if (need_message(near)){mprf("%s eats %s.", name(DESC_CAP_THE).c_str(),item.name(DESC_NOCAP_THE).c_str());}// Assume that eating a corpse requires butchering it.//// Use logic from misc.cc:turn_corpse_into_chunks() and// the butchery-related delays in delay.cc:stop_delay().const int max_chunks = mons_weight(item.plus) / 150;// Only fresh corpses bleed enough to colour the ground.if (!food_is_rotten(item))bleed_onto_floor(pos(), item.plus, max_chunks, true);if (mons_skeleton(item.plus) && one_chance_in(3))turn_corpse_into_skeleton(item);elsedestroy_item(item.index());lose_pickup_energy();return (true);}
// habitat, speed, energy usage, use type, body sizeHT_LAND, 0, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_HUGE
// habitat, speed, energy usage, use type, eat type, body sizeHT_LAND, 0, DEFAULT_ENERGY, MONUSE_NOTHING, MONEAT_NOTHING, SIZE_HUGE