/* * Start a corpse decay or revive timer. * This takes the age of the corpse into consideration as of 3.4.0. */ void start_corpse_timeout(struct obj *body) { long when; /* rot away when this old */ long corpse_age; /* age of corpse */ int rot_adjust; short action; #define TAINT_AGE (50L) /* age when corpses go bad */ #define TROLL_REVIVE_CHANCE 37 /* 1/37 chance for 50 turns ~ 75% chance */ #define ROT_AGE (250L) /* age when corpses rot away */ /* lizards and lichen don't rot or revive */ if (body->corpsenm == PM_LIZARD || body->corpsenm == PM_LICHEN) return; action = ROT_CORPSE; /* default action: rot away */ rot_adjust = in_mklev ? 25 : 10; /* give some variation */ corpse_age = monstermoves - body->age; if (corpse_age > ROT_AGE) when = rot_adjust; else when = ROT_AGE - corpse_age; when += (long)(rnz(rot_adjust) - rot_adjust); if (is_rider(&mons[body->corpsenm])) { /* * Riders always revive. They have a 1/3 chance per turn * of reviving after 12 turns. Always revive by 500. */ action = REVIVE_MON; for (when = 12L; when < 500L; when++) if (!rn2(3)) break; } else if (mons[body->corpsenm].mlet == S_TROLL && !body->norevive) { long age; struct monst *mtmp = get_mtraits(body, FALSE); if (mtmp && !mtmp->mcan) { for (age = 2; age <= TAINT_AGE; age++) if (!rn2(TROLL_REVIVE_CHANCE)) { /* troll revives */ action = REVIVE_MON; when = age; break; } } } if (body->norevive) body->norevive = 0; (void) start_timer(when, TIMER_OBJECT, action, (genericptr_t)body); }
void rloco(struct obj *obj) { xchar tx, ty, otx, oty; boolean restricted_fall; int try_limit = 4000; if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) { if (revive_corpse(obj)) return; } obj_extract_self(obj); otx = obj->ox; oty = obj->oy; restricted_fall = (otx == 0 && level->dndest.lx); do { tx = rn1(COLNO-3,2); ty = rn2(ROWNO); if (!--try_limit) break; } while (!goodpos(level, tx, ty, NULL, 0) || /* bug: this lacks provision for handling the Wizard's tower */ (restricted_fall && (!within_bounded_area(tx, ty, level->dndest.lx, level->dndest.ly, level->dndest.hx, level->dndest.hy) || (level->dndest.nlx && within_bounded_area(tx, ty, level->dndest.nlx, level->dndest.nly, level->dndest.nhx, level->dndest.nhy))))); if (flooreffects(obj, tx, ty, "fall")) { return; } else if (otx == 0 && oty == 0) { ; /* fell through a trap door; no update of old loc needed */ } else { if (costly_spot(otx, oty) && (!costly_spot(tx, ty) || !strchr(in_rooms(level, tx, ty, 0), *in_rooms(level, otx, oty, 0)))) { if (costly_spot(u.ux, u.uy) && strchr(u.urooms, *in_rooms(level, otx, oty, 0))) addtobill(obj, FALSE, FALSE, FALSE); else stolen_value(obj, otx, oty, FALSE, FALSE); } newsym(otx, oty); /* update old location */ } place_object(obj, level, tx, ty); newsym(tx, ty); }
/* you teleport a monster (via wand, spell, or poly'd q.mechanic attack); return false iff the attempt fails */ boolean u_teleport_mon(struct monst *mtmp, boolean give_feedback) { coord cc; if (mtmp->ispriest && *in_rooms(level, mtmp->mx, mtmp->my, TEMPLE)) { if (give_feedback) pline("%s resists your magic!", Monnam(mtmp)); return FALSE; } else if (level->flags.noteleport && u.uswallow && mtmp == u.ustuck) { if (give_feedback) pline("You are no longer inside %s!", mon_nam(mtmp)); unstuck(mtmp); rloc(mtmp, FALSE); } else if (is_rider(mtmp->data) && rn2(13) && enexto(&cc, level, u.ux, u.uy, mtmp->data)) rloc_to(mtmp, cc.x, cc.y); else rloc(mtmp, FALSE); return TRUE; }
boolean in_your_sanctuary(struct monst *mon, /* if non-null, <mx,my> overrides <x,y> */ xchar x, xchar y) { char roomno; struct monst *priest; if (mon) { if (is_minion(mon->data) || is_rider(mon->data)) return FALSE; x = mon->mx, y = mon->my; } if (u.ualign.record <= ALGN_SINNED) /* sinned or worse */ return FALSE; if ((roomno = temple_occupied(u.urooms)) == 0 || roomno != *in_rooms(level, x, y, TEMPLE)) return FALSE; if ((priest = findpriest(roomno)) == 0) return FALSE; return (boolean) (has_shrine(priest) && p_coaligned(priest) && priest->mpeaceful); }
void rloco(struct obj *obj) { int tx, ty, otx, oty; otx = obj->ox; oty = obj->oy; if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) { if (revive_corpse(obj)) return; } obj_extract_self(obj); rloco_pos(level, obj, &tx, &ty); if (flooreffects(obj, tx, ty, "fall")) { return; } else if (otx == 0 && oty == 0) { ; /* fell through a trap door; no update of old loc needed */ } else { if (costly_spot(otx, oty) && (!costly_spot(tx, ty) || !strchr(in_rooms(level, tx, ty, 0), *in_rooms(level, otx, oty, 0)))) { if (costly_spot(u.ux, u.uy) && strchr(u.urooms, *in_rooms(level, otx, oty, 0))) addtobill(obj, FALSE, FALSE, FALSE); else stolen_value(obj, otx, oty, FALSE, FALSE); } newsym(otx, oty); /* update old location */ } place_object(obj, level, tx, ty); newsym(tx, ty); }
/* 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; } }