view urogue/monsters.c @ 260:b80e1bf4eaec

UltraRogue: don't overwrite the savefile name when restoring.
author John "Elwin" Edwards
date Thu, 09 Feb 2017 20:13:25 -0500
parents c495a4f288c6
children 0250220d8cdd
line wrap: on
line source

/*
    monsters.c - File with various monster functions in it
 
    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
    All rights reserved.

    Based on "Advanced Rogue"
    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
    All rights reserved.

    Based on "Rogue: Exploring the Dungeons of Doom"
    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
    All rights reserved.

    See the file LICENSE.TXT for full copyright and licensing information.
*/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "rogue.h"

/*
    summon_monster()
        Summon a monster.
*/

struct linked_list *
summon_monster(int type, int familiar, int print_message)
{
    struct linked_list  *mp;
    struct thing    *tp;
    int   monster;

    if (familiar && !is_wearing(R_WIZARD) && off(player, CANSUMMON))
    {
        msg("Only spellcasters can summon familiars!");
        return(NULL);
    }

    if (type == 0)    /* Random monster modified by level */
    {
        int ndice = min(pstats.s_lvl, (nummonst - NUMSUMMON) / 8);

        monster = min(nummonst, roll(ndice, pstats.s_charisma));
        
		/*
         * if a familiar exists, and it is higher in level, make it
         * again 
         */

        if (fam_ptr != NULL) 
		{
            struct thing   *fp = THINGPTR(fam_ptr);

            monster = max(fp->t_index, monster);
        }
	}
    else
        monster = type;

    turn_on(player, SUMMONING);

    mp = creat_mons(&player, monster, NOMESSAGE);

    if (!mp)
    {
        msg("Summon failed.");
        turn_off(player, SUMMONING);
        return(NULL);
    }

    if (print_message == MESSAGE)
    {
        msg("A %s appears out of nowhere!", monsters[monster].m_name);

        if (familiar)
            msg("I am here to serve %s.", whoami);
        else
        {
            msg("My goodness, are you Yendor?");
            ++mons_summoned;
            debug("%d monsters now summoned.", mons_summoned);
        }
    }

    tp = THINGPTR(mp);
    turn_on(*tp, ISCHARMED);    /* Summoned monsters are always charmed */

    if (familiar)
    {
        int i;
        static const unsigned long fam_on[]= {ISREGEN,CANSHOOT,CANWIELD,HASARMOR,ISFAMILIAR,0};
        static const unsigned long fam_off[]={ISMEAN, ISHUH, ISINVIS,
                    CANSURPRISE, NOMOVE,
                    ISSLOW, ISSHADOW, ISGREED, ISFAST,
                    CANFLY, ISFLEE, 0};

        for (i = 0; fam_on[i]; i++)
            turn_on(*tp, fam_on[i]);

        for (i = 0; fam_off[i]; i++)
            turn_off(*tp, fam_off[i]);

        if (fam_ptr != NULL)    /* Get rid of old familiar */
        {
            struct thing    *fp = THINGPTR(fam_ptr);
            struct linked_list  *fpack = fp->t_pack;
            struct linked_list  *item;

            if (fpack != NULL)  /* Transfer pack */
            {
                if (tp->t_pack == NULL)
                    tp->t_pack = fpack;
                else
                {
                    for(item=tp->t_pack; item->l_next != NULL; item=next(item))
                        ;   /* find last item in list */

                    item->l_next = fpack;
                    fpack->l_prev = item;
                }
            }

            fpack = NULL;
            killed(NULL, fam_ptr, NOMESSAGE, NOPOINTS);
        }

        fam_ptr = mp;
        fam_type = monster;

        /* improve their abilities a bit */

        tp->t_stats.s_hpt += roll(2, pstats.s_lvl);
        tp->t_stats.s_lvl += roll(2, (pstats.s_lvl / 4) + 1);
        tp->t_stats.s_arm -= roll(2, (pstats.s_lvl / 4) + 1);
        tp->t_stats.s_str += roll(2, (pstats.s_lvl / 4) + 1);
        tp->t_stats.s_intel += roll(2, (pstats.s_lvl / 4) + 1);
        tp->t_stats.s_wisdom += roll(2, (pstats.s_lvl / 4) + 1);
        tp->t_stats.s_dext += roll(2, (pstats.s_lvl / 4) + 1);
        tp->t_stats.s_const += roll(2, (pstats.s_lvl / 4) + 1);
        tp->t_stats.s_charisma += roll(2, (pstats.s_lvl / 4) + 1);
		
		/* some monsters do no damage by default */
		
		if (strcmp(tp->t_stats.s_dmg, "0d0") == 0)
            tp->t_stats.s_dmg = "1d8";
			
        tp->maxstats = tp->t_stats; /* structure assignment */
    }

    turn_off(player, SUMMONING);

    return(mp);
}

/*
     randmonster()
        wander - wandering monster allowed
        grab - a throne room monster allowed
*/

int
randmonster(int wander, int grab)
{
    int mons_number, cur_level, range, i;

    /* Do we want a merchant? */

    if (wander == WANDER && monsters[nummonst].m_wander && rnd(5000) < 3)
        return(nummonst);

    cur_level = level;
    range = 4 * NLEVMONS;
    i = 0;

    do
    {
        if (i++ > range * 10)   /* just in case all have be genocided */
        {
            i = 0;

            if (--cur_level <= 0)
                fatal("Rogue could not find a monster to make");
        }

        mons_number = NLEVMONS * (cur_level - 1) +
            (rnd(range) - (range - 1 - NLEVMONS));

        if (mons_number < 1)
            mons_number = rnd(NLEVMONS) + 1;
        else if (mons_number > nummonst - NUMSUMMON - 1)
        {
            if (grab == GRAB)
                mons_number = rnd(range + NUMSUMMON) +
                    (nummonst - 1) -
                    (range + NUMSUMMON - 1);
            else if (mons_number > nummonst - 1)
                mons_number = rnd(range) +
                (nummonst - NUMSUMMON - 1) -
                (range - 1);
        }
    }
    while (wander == WANDER ? !monsters[mons_number].m_wander ||
        !monsters[mons_number].m_normal :
        !monsters[mons_number].m_normal);

    return((short)mons_number);
}

/*
    new_monster()
        Pick a new monster and add it to the list
*/

void
new_monster(struct linked_list *item, int type, coord *cp, int max_monster)
{
    struct thing    *tp;
    struct monster  *mp;
    char    *ip, *hitp;
    int   i, min_intel, max_intel;
    int   num_dice, num_sides = 8, num_extra = 0;
    int eff_charisma = pstats.s_charisma;
    int eff_intel = pstats.s_intel;

    attach(mlist, item);
    tp = THINGPTR(item);
    tp->t_index = type;
    tp->t_wasshot = FALSE;
    tp->t_type = monsters[type].m_appear;
    tp->t_ctype = C_MONSTER;
    tp->t_no_move = 0;
    tp->t_doorgoal = -1;
    tp->t_pos = *cp;
    tp->t_oldpos = *cp;
    tp->t_oldch = CCHAR( mvwinch(cw, cp->y, cp->x) );
    mvwaddch(mw, cp->y, cp->x, tp->t_type);
    mp = &monsters[tp->t_index];

    /* Figure out monster's hit points */

    hitp = mp->m_stats.s_hpt;
    num_dice = atoi(hitp);

    if ((hitp = strchr(hitp, 'd')) != NULL)
    {
        num_sides = atoi(++hitp);

        if ((hitp = strchr(hitp, '+')) != NULL)
            num_extra = atoi(++hitp);
    }

    if (max_monster == MAXSTATS)
        tp->t_stats.s_hpt = num_dice * num_sides + num_extra;
    else
        tp->t_stats.s_hpt = roll(num_dice, num_sides) + num_extra;

    tp->t_stats.s_lvl = mp->m_stats.s_lvl;
    tp->t_stats.s_arm = mp->m_stats.s_arm;
    tp->t_stats.s_dmg = mp->m_stats.s_dmg;
    tp->t_stats.s_exp = mp->m_stats.s_exp + mp->m_add_exp * tp->t_stats.s_hpt;
    tp->t_stats.s_str = mp->m_stats.s_str;

    if (max_level > 30)
    {
        tp->t_stats.s_hpt += roll(4, (max_level - 60) * 2);
        tp->t_stats.s_lvl += roll(4, (max_level - 60) / 8);
        tp->t_stats.s_arm -= roll(2, (max_level - 60) / 8);
        tp->t_stats.s_str += roll(2, (max_level - 60) / 12);
        tp->t_stats.s_exp += roll(4, (max_level - 60) * 2) * mp->m_add_exp;
    }

    /*
     * just initailize others values to something reasonable for now
     * maybe someday will *really* put these in monster table
     */

    tp->t_stats.s_wisdom = 8 + rnd(4);
    tp->t_stats.s_dext = 8 + rnd(4);
    tp->t_stats.s_const = 8 + rnd(4);
    tp->t_stats.s_charisma = 8 + rnd(4);

    if (max_level > 45)
        tp->t_stats.s_dext += roll(2, (max_level - 50) / 8);

    /* Set the initial flags */

    for (i = 0; i < 16; i++)
        tp->t_flags[i] = 0;

    for (i = 0; i < 16; i++)
        turn_on(*tp, mp->m_flags[i]);

    /* suprising monsters don't always surprise you */

    if (!max_monster && on(*tp, CANSURPRISE) && rnd(100) < 20)
        turn_off(*tp, CANSURPRISE);

    /* If this monster is unique, genocide it */

    if (on(*tp, ISUNIQUE))
        mp->m_normal = FALSE;

    /* gods automatically get special abilities */

    if (on(*tp, ISGOD))
    {
        turn_on(*tp, CANFRIGHTEN);
        turn_on(*tp, CANCAST);
        turn_on(*tp, CANFLY);
        turn_on(*tp, CANBARGAIN);
        turn_on(*tp, ISLARGE);
        turn_on(*tp, CANTELEPORT);
        turn_on(*tp, CANSPEAK);
        turn_on(*tp, CANDARKEN);
        turn_on(*tp, CANSEE);
        turn_on(*tp, CANLIGHT);
        turn_on(*tp, BMAGICHIT);
    }

    tp->t_turn = TRUE;
    tp->t_pack = NULL;

    /* Figure intelligence */

    min_intel = atoi(mp->m_intel);

    if ((ip = (char *) strchr(mp->m_intel, '-')) == NULL)
        tp->t_stats.s_intel = min_intel;
    else
    {
        max_intel = atoi(++ip);

        if (max_monster)
            tp->t_stats.s_intel = max_intel;
        else
            tp->t_stats.s_intel = min_intel + rnd(max_intel - min_intel);
    }

    tp->t_stats.s_power = (rnd(tp->t_stats.s_lvl / 5) + 1) * tp->t_stats.s_intel;

    tp->maxstats = tp->t_stats; /* structure assignment */

    /* If the monster can shoot, it may have a weapon */

    if (on(*tp, CANSHOOT) && (max_monster || rnd(9) < 6))
    {
        struct linked_list  *thrower_item, *missile_item;
        struct object *thrower, *a_missile;

        thrower_item = new_item(sizeof *thrower);
        thrower = OBJPTR(thrower_item);
        carried_weapon(tp, thrower);

        missile_item = new_item(sizeof *a_missile);
        a_missile = OBJPTR(missile_item);
        carried_weapon(tp, a_missile);

        /* The monster may use a crossbow, sling, footbow, or an arrow */
        /* Take racial preferences into account */

        if ((strcmp(mp->m_name, "elf") == 0) ||
            (strcmp(mp->m_name, "noldor elf") == 0))
        {
            thrower->o_which = BOW;

            if (rnd(5) == 0)
                a_missile->o_which = SILVERARROW;
            else
                a_missile->o_which = ARROW;
        }
        else if ((strcmp(mp->m_name, "dwarf") == 0) ||
                (strcmp(mp->m_name, "kazad dwarf") == 0))
        {
            thrower->o_which = CROSSBOW;
            a_missile->o_which = BOLT;
        }
        else if (on(*tp, ISSMALL))
        {
            switch (rnd(3))
            {
                case 0:
                    thrower->o_which = SLING;
                    a_missile->o_which = BULLET;
                    break;
                default:
                    thrower->o_which = SLING;
                    a_missile->o_which = ROCK;
            }
        }
        else if (on(*tp, ISLARGE))
        {
            switch (rnd(4))
            {
                case 0:
                    thrower->o_which = CROSSBOW;
                    a_missile->o_which = BOLT;
                    break;

                case 1:
                    thrower->o_which = FOOTBOW;
                    a_missile->o_which = FBBOLT;
                    break;

                default:
                    thrower->o_which = BOW;

                    if (rnd(5) == 0)
                        a_missile->o_which = FLAMEARROW;
                    else
                        a_missile->o_which = ARROW;

                    break;
            }
        }
        else
        {
            switch (rnd(6))
            {
                case 1:
                    thrower->o_which = SLING;
                    a_missile->o_which = ROCK;
                    break;

                case 2:
                    thrower->o_which = CROSSBOW;
                    a_missile->o_which = BOLT;
                    break;

                case 3:
                    thrower->o_which = FOOTBOW;
                    a_missile->o_which = FBBOLT;
                    break;

                case 4:
                    thrower->o_which = BOW;
                    a_missile->o_which = ARROW;
                    break;

                default:
                    thrower->o_which = SLING;
                    a_missile->o_which = BULLET;
                    break;
            }
        }

        init_weapon(thrower, thrower->o_which);
        init_weapon(a_missile, a_missile->o_which);

        attach(tp->t_pack, thrower_item);
        attach(tp->t_pack, missile_item);
    }

    /* monsters that wield weapons */

    if (on(*tp, CANWIELD))
    {
        if (max_monster || rnd(3))
        {
            struct linked_list  *wield_item;
            struct object   *wielded;

            wield_item = new_item(sizeof *wielded);
            wielded = OBJPTR(wield_item);
            carried_weapon(tp, wielded);

            i = rnd(CLAYMORE - CLUB) + rnd(2 * tp->t_stats.s_lvl);
            i = min(i, CLAYMORE);
            wielded->o_which = i;
            init_weapon(wielded, wielded->o_which);

            /* Is it too heavy? */

            if (itemweight(wielded) > 8 * tp->t_stats.s_str)
                discard(wield_item);
            else
                attach(tp->t_pack, wield_item);
        }
    }

    if (is_wearing(R_AGGR))
        chase_it(cp, &player);
    else
    {
        turn_off(*tp, ISRUN);

        if (on(*tp, ISFLEE) && (rnd(4) == 0))
            turn_off(*tp, ISFLEE);

        if (rnd(luck) == 0)
            switch (player.t_ctype)
            {
                case C_MAGICIAN:
                case C_ILLUSION:
                    eff_intel = 2 * pstats.s_intel;
                    break;
                case C_DRUID:
                    eff_intel = 2 * pstats.s_intel;
                case C_RANGER:
                    eff_charisma = 2 * pstats.s_charisma;
                    break;
                case C_ASSASIN:
                case C_THIEF:
                case C_NINJA:
                    eff_charisma = pstats.s_charisma / 2;
                    break;
            }

        /* LOWFRIENDLY monsters might be friendly */

        i = roll(1,100);

        if (i == 0 || (on(*tp, LOWFRIENDLY) && i < eff_charisma) ||
            (on(*tp, MEDFRIENDLY) && i < 3 * eff_charisma) ||
            (on(*tp, HIGHFRIENDLY) && i < 5 * eff_charisma))
        {
            turn_on(*tp, ISFRIENDLY);
            turn_off(*tp, ISMEAN);
        }

        i = roll(1,100);

        if (i == 0 || (on(*tp, LOWCAST) && i < eff_intel) ||
            (on(*tp, MEDCAST) && i < 3 * eff_intel) ||
            (on(*tp, HIGHCAST) && i < 5 * eff_intel))
        {
            turn_on(*tp, CANCAST);
        }

        if (on(*tp, ISDISGUISE))
        {
            char    mch = 0;

            if (tp->t_pack != NULL)
                mch = (OBJPTR(tp->t_pack))->o_type;
            else
                switch (rnd(level > arts[0].ar_level ? 10 : 9))
                {
                    case 0: mch = GOLD;     break;
                    case 1: mch = POTION;   break;
                    case 2: mch = SCROLL;   break;
                    case 3: mch = FOOD;     break;
                    case 4: mch = WEAPON;   break;
                    case 5: mch = ARMOR;    break;
                    case 6: mch = RING;     break;
                    case 7: mch = STICK;    break;
                    case 8: mch = monsters[randmonster(NOWANDER, NOGRAB)].m_appear;
                                break;
                    case 9: mch = ARTIFACT; break;
                }

            tp->t_disguise = mch;
        }
    }
}

/*
    wanderer()
        A wandering monster has awakened and is headed for the player
*/

void
wanderer(void)
{
    int i, cnt = 0;
    struct room *hr = roomin(hero);
    struct linked_list  *item;
    struct thing    *tp;
    coord   cp;
    char    *loc;
    int which;

    /* Find a place for it -- avoid the player's room */

    do
    {
        do
        {
            cnt++;
            i = rnd_room();
        }
        while (!(hr != &rooms[i] || levtype == MAZELEV
               || levtype == THRONE || cnt > 5000));

        rnd_pos(&rooms[i], &cp);
    }
    while(!step_ok(cp.y, cp.x, NOMONST, NULL));

    /* Create a new wandering monster */

    item = new_item(sizeof *tp);
    which = randmonster(TRUE, FALSE);
    new_monster(item, which, &cp, FALSE);

    tp = THINGPTR(item);
    tp->t_pos = cp;     /* Assign the position to the monster */

    chase_it(&tp->t_pos, &player);

    i = rnd(7);

    if (on(*tp, ISSWARM) && i < 5)
        cnt = roll(2, 4);
    else if (on(*tp, ISFLOCK) && i < 5)
        cnt = roll(1, 4);
    else
        cnt = 0;

    for (i = 1; i <= cnt; i++)
    {
        struct linked_list  *ip = creat_mons(tp, which, NOMESSAGE);

        if (ip != NULL)
        {
            struct thing    *mp = THINGPTR(ip);

            if (on(*tp, ISFRIENDLY))
                turn_on(*mp, ISFRIENDLY);
            else
                turn_off(*mp, ISFRIENDLY);
        }
    }

    if (cnt > 0)
    {
        if (on(*tp, LOWCAST) || on(*tp, MEDCAST) || on(*tp, HIGHCAST))
            turn_on(*tp, CANCAST);

        tp->t_stats.s_hpt += roll(2, 8);
        tp->t_stats.s_lvl += roll(2, 3);
        tp->t_stats.s_arm -= roll(1, 6);
        tp->t_stats.s_str += roll(2, 3);
        tp->t_stats.s_intel += roll(2, 3);
        tp->t_stats.s_exp += roll(2, 8) * monsters[which].m_add_exp;
    }

    i = DISTANCE(cp, hero);

    if (i < 20)
        loc = "very close to you";
    else if (i < 400)
        loc = "nearby";
    else
        loc = "in the distance";

    if (wizard)
        msg("Started a wandering %s.", monsters[tp->t_index].m_name);
    else if (on(*tp, ISUNDEAD) && (player.t_ctype == C_CLERIC ||
            player.t_ctype == C_PALADIN || is_wearing(R_PIETY)))
        msg("You sense a new ungodly monster %s.", loc);
    else if (on(player, CANHEAR) || (player.t_ctype == C_THIEF &&
            rnd(20) == 0))
        msg("You hear a new %s moving %s.",
            monsters[tp->t_index].m_name, loc);
    else if (on(player, CANSCENT) || (player.t_ctype == C_THIEF &&
            rnd(20) == 0))
        msg("You smell a new %s %s.", monsters[tp->t_index].m_name,
            loc);
}

/*
    wake_monster
	
        what to do when the hero steps next to a monster
*/

struct linked_list *
wake_monster(int y, int x)
{
    struct thing    *tp;
    struct linked_list  *it;
    struct room *trp;
    char    *mname;

    if ((it = find_mons(y, x)) == NULL)
    {
        debug("Can't find monster in show.");
        return(NULL);
    }

    tp = THINGPTR(it);

    if ((good_monster(*tp)) || on(player, SUMMONING))
    {
        chase_it(&tp->t_pos, &player);
        turn_off(*tp, ISINVIS);
        turn_off(*tp, CANSURPRISE);
        return(it);
    }

    trp = roomin(tp->t_pos);   /* Current room for monster */
    mname = monsters[tp->t_index].m_name;

    /* Let greedy ones guard gold */

    if (on(*tp, ISGREED) && off(*tp, ISRUN))
        if ((trp != NULL) && (lvl_obj != NULL))
        {
            struct linked_list  *item;
            struct object   *cur;

            for (item = lvl_obj; item != NULL; item = next(item))
            {
                cur = OBJPTR(item);

                if ((cur->o_type == GOLD) &&
                    (roomin(cur->o_pos) == trp))
                {
                    /* Run to the gold */
                    tp->t_horde = cur;
                    turn_on(*tp, ISRUN);
                    turn_off(*tp, ISDISGUISE);
                    tp->t_ischasing = FALSE;
                    /* Make it worth protecting */
                    cur->o_count += roll(2, 3) * GOLDCALC;
                    break;
                }
            }
        }

    /*
     * Every time he sees mean monster, it might start chasing him unique
     * monsters always do
     */

    if (  (on(*tp, ISUNIQUE)) ||
          ( (rnd(100) > 33) &&
            on(*tp, ISMEAN) &&
            off(*tp, ISHELD) &&
            off(*tp, ISRUN) &&
            !is_stealth(&player) &&
            (off(player, ISINVIS) || on(*tp, CANSEE))
          )
       )
    {
        chase_it(&tp->t_pos, &player);
    }

    /* Handle gaze attacks */

    if (on(*tp, ISRUN) && cansee(tp->t_pos.y, tp->t_pos.x) &&
            off(player, ISINVIS))
    {
        if (on(*tp, CANHUH))    /* Confusion */
        {
            if (on(player, CANREFLECT))
            {
                msg("You reflect the bewildering stare of the %s.", mname);

                if (save_throw(VS_MAGIC, tp))
                {
                    msg("The %s is confused!", mname);
                    turn_on(*tp, ISHUH);
                }
                else
                    msg("The %s staggers for a moment.", mname);
            }
            else if (save(VS_MAGIC))
            {
                msg("You feel dizzy for a moment, but it quickly passes.");

                if (rnd(100) < 67)
                    turn_off(*tp, CANHUH);
            }
            else if (off(player, ISCLEAR))
            {
                if (off(player, ISHUH))
                {
                    light_fuse(FUSE_UNCONFUSE, 0, rnd(20) + HUHDURATION, AFTER);
                    msg("The %s's gaze has confused you.", mname);
                    turn_on(player, ISHUH);
                }
                else
                    lengthen_fuse(FUSE_UNCONFUSE, rnd(20) + HUHDURATION);
            }
        }

        if (on(*tp, CANSNORE))      /* Sleep */
        {
            if (on(player, CANREFLECT))
            {
                msg("You reflect the lethargic glance of the %s", mname);

                if (save_throw(VS_PARALYZATION, tp))
                {
                    msg("The %s falls asleep!", mname);
                    tp->t_no_move += SLEEPTIME;
                }
            }
            else if (no_command == 0 && !save(VS_PARALYZATION))
            {
                if (is_wearing(R_ALERT))
                    msg("You feel slightly drowsy for a moment.");
                else
                {
                    msg("The %s's gaze puts you to sleep.", mname);
                    no_command = SLEEPTIME;

                    if (rnd(100) < 50)
                        turn_off(*tp, CANSNORE);
                }
            }
        }

        if (on(*tp, CANFRIGHTEN))   /* Fear */
        {
            turn_off(*tp, CANFRIGHTEN);

            if (on(player, CANREFLECT))
            {
                msg("The %s sees its reflection. ", mname);

                if (save_throw(VS_MAGIC,tp))
                {
                    msg("The %s is terrified by its reflection!", mname);
                    turn_on(*tp, ISFLEE);
                }
            }
            else
            {
                if (!save(VS_WAND) && !(on(player, ISFLEE) &&
                       (player.t_chasee==tp)))
                {
                    if ((player.t_ctype != C_PALADIN) &&
                        off(player, SUPERHERO))
                    {
                        turn_on(player, ISFLEE);
                        player.t_ischasing = FALSE;
                        player.t_chasee    = tp;
                        msg("The sight of the %s terrifies you.", mname);
                    }
                    else
                        msg("My, the %s looks ugly.", mname);
                }
            }
        }

        if (on(*tp, LOOKSLOW))     /* Slow */
        {
            turn_off(*tp, LOOKSLOW);

            if (on(player, CANREFLECT))
            {
                msg("You reflect the mournful glare of the %s.", mname);