/* heal monster for time spent elsewhere */ void mon_catchup_elapsed_time(struct monst *mtmp, long nmv) { int imv = 0; /* avoid zillions of casts and lint warnings */ /* Without this, if a monster is deleted during level creation (e.g. statue trap) and the player comes to the level later, it'll have healed itself out of the "deleted" state, thoroughly confusing dmonsfree(). */ if (DEADMONSTER(mtmp)) return; if (nmv >= LARGEST_INT) /* paranoia */ imv = LARGEST_INT - 1; else imv = (int)nmv; /* might stop being afraid, blind or frozen */ /* set to 1 and allow final decrement in movemon() */ if (mtmp->mblinded) { if (imv >= (int)mtmp->mblinded) mtmp->mblinded = 1; else mtmp->mblinded -= imv; } if (mtmp->mfrozen) { if (imv >= (int)mtmp->mfrozen) mtmp->mfrozen = 1; else mtmp->mfrozen -= imv; } if (mtmp->mfleetim) { if (imv >= (int)mtmp->mfleetim) mtmp->mfleetim = 1; else mtmp->mfleetim -= imv; } /* might recover from temporary trouble */ if (mtmp->mtrapped && rn2(imv + 1) > 40 / 2) mtmp->mtrapped = 0; if (mtmp->mconf && rn2(imv + 1) > 50 / 2) mtmp->mconf = 0; if (mtmp->mstun && rn2(imv + 1) > 10 / 2) mtmp->mstun = 0; /* might finish eating or be able to use special ability again */ if (imv > mtmp->meating) mtmp->meating = 0; else mtmp->meating -= imv; if (imv > mtmp->mspec_used) mtmp->mspec_used = 0; else mtmp->mspec_used -= imv; /* reduce tameness for every 150 moves you are separated */ if (mtmp->mtame) { int wilder = (imv + 75) / 150; /* The rng_dog_untame RNG is only semi-synched, because the argument changes. This gives better results than rng_main, and we can't match exactly due to different pet-wrangling habits. Note: not msethostility; we're off-level right now. */ if (mtmp->mtame > wilder) mtmp->mtame -= wilder; /* less tame */ else if (mtmp->mtame > rn2_on_rng(wilder, rng_dog_untame)) mtmp->mtame = 0; /* untame */ else mtmp->mtame = mtmp->mpeaceful = 0; /* hostile! */ } /* check to see if it would have died as a pet; if so, go wild instead of dying the next time we call dog_move() */ if (mtmp->mtame && !mtmp->isminion && (carnivorous(mtmp->data) || herbivorous(mtmp->data))) { const struct edog *edog = CONST_EDOG(mtmp); if ((moves > edog->hungrytime + 500 && mtmp->mhp < 3) || (moves > edog->hungrytime + 750)) mtmp->mtame = mtmp->mpeaceful = 0; } if (!mtmp->mtame && mtmp->mleashed) { /* leashed monsters should always be with hero, consequently never losing any time to be accounted for later */ impossible("catching up for leashed monster?"); m_unleash(mtmp, FALSE); } /* recover lost hit points */ if (!regenerates(mtmp->data)) imv /= 20; if (mtmp->mhp + imv >= mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; else mtmp->mhp += imv; }
/* Returns an object slot mask giving all the reasons why the given player/monster might have the given property, limited by "reasons", an object slot mask (W_EQUIP, INTRINSIC, and ANY_PROPERTY are the most likely values here, but you can specify slots individually if you like). */ unsigned m_has_property(const struct monst *mon, enum youprop property, unsigned reasons, boolean even_if_blocked) { unsigned rv = 0; struct obj *otmp; /* The general case for equipment */ rv |= mworn_extrinsic(mon, property); if (mon == &youmonst) { /* Intrinsics */ if (u.uintrinsic[property] & TIMEOUT) rv |= W_MASK(os_timeout); rv |= u.uintrinsic[property] & (INTRINSIC | I_SPECIAL); /* Birth options */ if (property == BLINDED && flags.permablind) rv |= W_MASK(os_birthopt); if (property == HALLUC && flags.permahallu) rv |= W_MASK(os_birthopt); if (property == UNCHANGING && flags.polyinit_mnum != -1) rv |= W_MASK(os_birthopt); } else { /* Monster tempraries are boolean flags. TODO: Monsters with no eyes are not considered blind. This doesn't make much sense. However, changing it would be a major balance change (due to Elbereth), and so it has been left alone for now. */ if (property == BLINDED && (!mon->mcansee || mon->mblinded)) rv |= W_MASK(os_timeout); if (property == FAST && mon->mspeed == MFAST) rv |= (mon->permspeed == FAST ? W_MASK(os_polyform) : W_MASK(os_outside)); if (property == INVIS && mon->perminvis && !pm_invisible(mon->data)) rv |= W_MASK(os_outside); if (property == STUNNED && mon->mstun) rv |= W_MASK(os_timeout); if (property == CONFUSION && mon->mconf) rv |= W_MASK(os_timeout); } /* Polyform / monster intrinsic */ /* TODO: Change the monster data code into something that doesn't require a giant switch statement or ternary chain to get useful information from it. We use a ternary chain here because it cuts down on repetitive code and so is easier to read. */ if (property == FIRE_RES ? resists_fire(mon) : property == COLD_RES ? resists_cold(mon) : property == SLEEP_RES ? resists_sleep(mon) : property == DISINT_RES ? resists_disint(mon) : property == SHOCK_RES ? resists_elec(mon) : property == POISON_RES ? resists_poison(mon) : property == DRAIN_RES ? resists_drli(mon) : property == SICK_RES ? mon->data->mlet == S_FUNGUS || mon->data == &mons[PM_GHOUL] : property == ANTIMAGIC ? resists_magm(mon) : property == ACID_RES ? resists_acid(mon) : property == STONE_RES ? resists_ston(mon) : property == STUNNED ? u.umonnum == PM_STALKER || mon->data->mlet == S_BAT : property == BLINDED ? !haseyes(mon->data) : property == HALLUC ? Upolyd && dmgtype(mon->data, AD_HALU) : property == SEE_INVIS ? perceives(mon->data) : property == TELEPAT ? telepathic(mon->data) : property == INFRAVISION ? infravision(mon->data) : /* Note: This one assumes that there's no way to permanently turn visible when you're in stalker form (i.e. mummy wrappings only). */ property == INVIS ? pm_invisible(mon->data) : property == TELEPORT ? can_teleport(mon->data) : property == LEVITATION ? is_floater(mon->data) : property == FLYING ? is_flyer(mon->data) : property == SWIMMING ? is_swimmer(mon->data) : property == PASSES_WALLS ? passes_walls(mon->data) : property == REGENERATION ? regenerates(mon->data) : property == REFLECTING ? mon->data == &mons[PM_SILVER_DRAGON] : property == TELEPORT_CONTROL ? control_teleport(mon->data) : property == MAGICAL_BREATHING ? amphibious(mon->data) : 0) rv |= W_MASK(os_polyform); if (mon == &youmonst) { /* External circumstances */ if (property == BLINDED && u_helpless(hm_unconscious)) rv |= W_MASK(os_circumstance); /* Riding */ if (property == FLYING && u.usteed && is_flyer(u.usteed->data)) rv |= W_MASK(os_saddle); if (property == SWIMMING && u.usteed && is_swimmer(u.usteed->data)) rv |= W_MASK(os_saddle); } /* Overrides */ if (!even_if_blocked) { if (property == BLINDED) { for (otmp = m_minvent(mon); otmp; otmp = otmp->nobj) if (otmp->oartifact == ART_EYES_OF_THE_OVERWORLD && otmp->owornmask & W_MASK(os_tool)) rv &= (unsigned)(W_MASK(os_circumstance) | W_MASK(os_birthopt)); } if (property == WWALKING && Is_waterlevel(m_mz(mon))) rv &= (unsigned)(W_MASK(os_birthopt)); if (mworn_blocked(mon, property)) rv &= (unsigned)(W_MASK(os_birthopt)); } return rv & reasons; }
/* heal monster for time spent elsewhere */ void mon_catchup_elapsed_time(struct monst *mtmp, long nmv) { int imv = 0; /* avoid zillions of casts and lint warnings */ if (nmv >= LARGEST_INT) /* paranoia */ imv = LARGEST_INT - 1; else imv = (int)nmv; /* might stop being afraid, blind or frozen */ /* set to 1 and allow final decrement in movemon() */ if (mtmp->mblinded) { if (imv >= (int) mtmp->mblinded) mtmp->mblinded = 1; else mtmp->mblinded -= imv; } if (mtmp->mfrozen) { if (imv >= (int) mtmp->mfrozen) mtmp->mfrozen = 1; else mtmp->mfrozen -= imv; } if (mtmp->mfleetim) { if (imv >= (int) mtmp->mfleetim) mtmp->mfleetim = 1; else mtmp->mfleetim -= imv; } /* might recover from temporary trouble */ if (mtmp->mtrapped && rn2(imv + 1) > 40/2) mtmp->mtrapped = 0; if (mtmp->mconf && rn2(imv + 1) > 50/2) mtmp->mconf = 0; if (mtmp->mstun && rn2(imv + 1) > 10/2) mtmp->mstun = 0; /* might finish eating or be able to use special ability again */ if (imv > mtmp->meating) mtmp->meating = 0; else mtmp->meating -= imv; if (imv > mtmp->mspec_used) mtmp->mspec_used = 0; else mtmp->mspec_used -= imv; /* reduce tameness for every 150 moves you are separated */ if (mtmp->mtame) { int wilder = (imv + 75) / 150; if (mtmp->mtame > wilder) mtmp->mtame -= wilder; /* less tame */ else if (mtmp->mtame > rn2(wilder)) mtmp->mtame = 0; /* untame */ else mtmp->mtame = mtmp->mpeaceful = 0; /* hostile! */ } /* check to see if it would have died as a pet; if so, go wild instead * of dying the next time we call dog_move() */ if (mtmp->mtame && !mtmp->isminion && (carnivorous(mtmp->data) || herbivorous(mtmp->data))) { struct edog *edog = EDOG(mtmp); if ((moves > edog->hungrytime + 500 && mtmp->mhp < 3) || (moves > edog->hungrytime + 750)) mtmp->mtame = mtmp->mpeaceful = 0; } if (!mtmp->mtame && mtmp->mleashed) { /* leashed monsters should always be with hero, consequently never losing any time to be accounted for later */ impossible("catching up for leashed monster?"); m_unleash(mtmp, FALSE); } /* recover lost hit points */ if (!regenerates(mtmp->data)) imv /= 20; if (mtmp->mhp + imv >= mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; else mtmp->mhp += imv; }