Example #1
0
/* 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;
}
Example #2
0
/* 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;
}
Example #3
0
/* 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;
}