/* some monsters bypass the normal rules for moving between levels or even leaving the game entirely; when that happens, prevent them from taking the Amulet or invocation tools with them */ void mdrop_special_objs (struct monst *mon) { struct obj *obj, *otmp; for (obj = mon->minvent; obj; obj = otmp) { otmp = obj->nobj; /* the Amulet, invocation tools, and Rider corpses resist even when artifacts and ordinary objects are given 0% resistance chance */ if (obj_resists(obj, 0, 0)) { obj_extract_self(obj); mdrop_obj(mon, obj, false); } } }
/* Called every turn during chest-forcing. The caller must set u.utracked[tos_lock] to the chest in question. */ static int forcelock(void) { struct monst *shkp; boolean costly; struct obj *otmp; struct obj *box = u.utracked[tos_lock]; if (!obj_with_u(box)) return reset_pick(); if (!uwep_can_force()) /* prints the messages; ensures uwep != NULL */ return reset_pick(); if (u.uoccupation_progress[tos_lock]++ >= 50 || nohands(youmonst.data)) { pline(msgc_failrandom, "You give up your attempt to force the lock."); if (!nohands(youmonst.data)) exercise(is_blade(uwep) ? A_DEX : A_STR, TRUE); return reset_pick(); } if (is_blade(uwep)) { if (rn2(1000 - (int)uwep->spe) > (992 - greatest_erosion(uwep) * 10) && !uwep->cursed && !obj_resists(uwep, 0, 99)) { /* for a +0 weapon, probability that it survives an unsuccessful attempt to force the lock is (.992)^50 = .67 */ pline(msgc_substitute, "%sour %s broke!", (uwep->quan > 1L) ? "One of y" : "Y", xname(uwep)); useup(uwep); pline_implied(msgc_failcurse, "You can't exactly force that lock now."); exercise(A_DEX, TRUE); return reset_pick(); } } else /* blunt */ wake_nearby(FALSE); /* due to hammering on the container */ if (rn2(100) >= objects[uwep->otyp].oc_wldam * 2) return 1; /* still busy */ pline(msgc_actionok, "You succeed in forcing the lock."); box->olocked = 0; box->obroken = 1; costly = (*u.ushops && costly_spot(youmonst.mx, youmonst.my)); shkp = costly ? shop_keeper(level, *u.ushops) : 0; if (!is_blade(uwep) && !rn2(3)) { long loss = 0L; pline(msgc_substitute, "In fact, you've totally destroyed %s.", the(xname(box))); /* Put the contents on ground at the hero's feet. */ while ((otmp = box->cobj) != 0) { obj_extract_self(otmp); if (!rn2(3) || otmp->oclass == POTION_CLASS) { chest_shatter_msg(otmp); if (costly) loss += stolen_value(otmp, youmonst.mx, youmonst.my, (boolean) shkp->mpeaceful, TRUE); if (otmp->quan == 1L) { obfree(otmp, NULL); continue; } useup(otmp); } if (box->otyp == ICE_BOX && otmp->otyp == CORPSE) { otmp->age = moves - otmp->age; /* actual age */ start_corpse_timeout(otmp); } place_object(otmp, level, youmonst.mx, youmonst.my); stackobj(otmp); } if (costly) loss += stolen_value(box, youmonst.mx, youmonst.my, (boolean) shkp->mpeaceful, TRUE); if (loss) pline(msgc_unpaid, "You owe %ld %s for objects destroyed.", loss, currency(loss)); delobj(box); } else { if (costly) { struct obj *cobjbak = box->cobj; box->cobj = (struct obj *)0; verbalize(msgc_unpaid, "You damage it, you bought it!"); bill_dummy_object(box); box->cobj = cobjbak; } } exercise(is_blade(uwep) ? A_DEX : A_STR, TRUE); return reset_pick(); }
/* fungi will eat even tainted food */ int dogfood(const struct monst *mon, struct obj *obj) { boolean carni = carnivorous(mon->data); boolean herbi = herbivorous(mon->data); const struct permonst *fptr = &mons[obj->corpsenm]; boolean starving; if (is_quest_artifact(obj) || obj_resists(obj, 0, 95)) return obj->cursed ? TABU : APPORT; switch (obj->oclass) { case FOOD_CLASS: if (obj->otyp == CORPSE && ((touch_petrifies(&mons[obj->corpsenm]) && !resists_ston(mon)) || is_rider(fptr))) return TABU; /* Ghouls only eat old corpses... yum! */ if (mon->data == &mons[PM_GHOUL]) return (obj->otyp == CORPSE && peek_at_iced_corpse_age(obj) + 50L <= moves) ? DOGFOOD : TABU; if (!carni && !herbi) return obj->cursed ? UNDEF : APPORT; /* a starving pet will eat almost anything */ starving = (mon->mtame && !mon->isminion && CONST_EDOG(mon)->mhpmax_penalty); switch (obj->otyp) { case TRIPE_RATION: case MEATBALL: case MEAT_RING: case MEAT_STICK: case HUGE_CHUNK_OF_MEAT: return carni ? DOGFOOD : MANFOOD; case EGG: if (touch_petrifies(&mons[obj->corpsenm]) && !resists_ston(mon)) return POISON; return carni ? CADAVER : MANFOOD; case CORPSE: if ((peek_at_iced_corpse_age(obj) + 50L <= moves && obj->corpsenm != PM_LIZARD && obj->corpsenm != PM_LICHEN && mon->data->mlet != S_FUNGUS) || (acidic(&mons[obj->corpsenm]) && !resists_acid(mon)) || (poisonous(&mons[obj->corpsenm]) && !resists_poison(mon))) return POISON; else if (vegan(fptr)) return herbi ? CADAVER : MANFOOD; else return carni ? CADAVER : MANFOOD; case CLOVE_OF_GARLIC: return (is_undead(mon->data) ? TABU : ((herbi || starving) ? ACCFOOD : MANFOOD)); case TIN: return metallivorous(mon->data) ? ACCFOOD : MANFOOD; case APPLE: case CARROT: return herbi ? DOGFOOD : starving ? ACCFOOD : MANFOOD; case BANANA: return ((mon->data->mlet == S_YETI) ? DOGFOOD : ((herbi || starving) ? ACCFOOD : MANFOOD)); case K_RATION: case C_RATION: case CRAM_RATION: case LEMBAS_WAFER: case FOOD_RATION: if (is_human(mon->data) || is_elf(mon->data) || is_dwarf(mon->data) || is_gnome(mon->data) || is_orc(mon->data)) return ACCFOOD; default: if (starving) return ACCFOOD; return (obj->otyp > SLIME_MOLD ? (carni ? ACCFOOD : MANFOOD) : (herbi ? ACCFOOD : MANFOOD)); } default: if (obj->otyp == AMULET_OF_STRANGULATION || obj->otyp == RIN_SLOW_DIGESTION) return TABU; if (hates_silver(mon->data) && objects[obj->otyp].oc_material == SILVER) return TABU; if (mon->data == &mons[PM_GELATINOUS_CUBE] && is_organic(obj)) return ACCFOOD; if (metallivorous(mon->data) && is_metallic(obj) && (is_rustprone(obj) || mon->data != &mons[PM_RUST_MONSTER])) { /* Non-rustproofed ferrous based metals are preferred. */ return (is_rustprone(obj) && !obj->oerodeproof) ? DOGFOOD : ACCFOOD; } if (!obj->cursed && obj->oclass != BALL_CLASS && obj->oclass != CHAIN_CLASS) return APPORT; /* fall into next case */ case ROCK_CLASS: return UNDEF; } }