view xrogue/player.c @ 204:4b1999ac91cf

Permit not defining score and log files.
author John "Elwin" Edwards
date Thu, 13 Aug 2015 07:47:01 -0400
parents ce0cf824c192
children f54901b9c39b
line wrap: on
line source

/*
    player.c - functions for dealing with special player abilities

    XRogue: Expeditions into the Dungeons of Doom
    Copyright (C) 1991 Robert Pietkivitch
    All rights reserved.
    
    Based on "Advanced Rogue"
    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
    All rights reserved.

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

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

/*
 * affect:
 *      cleric affecting undead
 */

affect()
{
    register struct linked_list *item;
    register struct thing *tp;
    register char *mname;
    bool see;
    coord new_pos;
    int lvl;

    if (!(player.t_ctype == C_CLERIC  ||
          (player.t_ctype == C_PALADIN && pstats.s_lvl > 4) ||
          cur_relic[HEIL_ANKH] != 0)) {
        msg("You cannot affect undead.");
        return;
    }

    new_pos.y = hero.y + player.t_newpos.y;
    new_pos.x = hero.x + player.t_newpos.x;

    if (cansee(new_pos.y, new_pos.x)) see = TRUE;
    else see = FALSE;

    /* Anything there? */
    if (new_pos.y < 0 || new_pos.y > lines-3 ||
        new_pos.x < 0 || new_pos.x > cols-1 ||
        mvwinch(mw, new_pos.y, new_pos.x) == ' ') {
        msg("Nothing to affect.");
        return;
    }

    if ((item = find_mons(new_pos.y, new_pos.x)) == 0) {
        debug("Affect what @ %d,%d?", new_pos.y, new_pos.x);
        return;
    }
    tp = THINGPTR(item);
    mname = monster_name(tp);

    if (on(player, ISINVIS) && off(*tp, CANSEE)) {
        msg("%s%s cannot see you", see ? "The " : "It",
            see ? mname : "");
        return;
    }

    if (off(*tp, TURNABLE) || on(*tp, WASTURNED)) 
        goto annoy;
    turn_off(*tp, TURNABLE);

    lvl = pstats.s_lvl;
    if (player.t_ctype == C_PALADIN && cur_relic[HEIL_ANKH] == 0) {
        lvl -= 4;
    }
    /* Can cleric kill it? */
    if (lvl >= 3 * tp->t_stats.s_lvl) {
        unsigned long test;      /* For overflow check */

        msg("You have destroyed %s%s.", see ? "the " : "it", see ? mname : "");
        test = pstats.s_exp + tp->t_stats.s_exp;

        /* Be sure there is no overflow before increasing experience */
        if (test > pstats.s_exp) pstats.s_exp = test;
        killed(item, FALSE, TRUE, TRUE);
        check_level();
        return;
    }

    /* Can cleric turn it? */
    if (rnd(100) + 1 >
         (100 * ((2 * tp->t_stats.s_lvl) - lvl)) / lvl) {
        unsigned long test;      /* Overflow test */

        /* Make the monster flee */
        turn_on(*tp, WASTURNED);        /* No more fleeing after this */
        turn_on(*tp, ISFLEE);
        runto(tp, &hero);

        /* Disrupt it */
        dsrpt_monster(tp, TRUE, TRUE);

        /* Let player know */
        msg("You have turned %s%s.", see ? "the " : "it", see ? mname : "");

        /* get points for turning monster -- but check overflow first */
        test = pstats.s_exp + tp->t_stats.s_exp/2;
        if (test > pstats.s_exp) pstats.s_exp = test;
        check_level();

        /* If monster was suffocating, stop it */
        if (on(*tp, DIDSUFFOCATE)) {
            turn_off(*tp, DIDSUFFOCATE);
            extinguish(suffocate);
        }

        /* If monster held us, stop it */
        if (on(*tp, DIDHOLD) && (--hold_count == 0))
                turn_off(player, ISHELD);
        turn_off(*tp, DIDHOLD);

        /* It is okay to turn tail */
        tp->t_oldpos = tp->t_pos;

        return;
    }

    /* Otherwise -- no go */
annoy:
    if (see && tp->t_stats.s_intel > 16)
        msg("%s laughs at you...", prname(mname, TRUE));
    else
        msg("You do not affect %s%s.", see ? "the " : "it", see ? mname : "");

    /* Annoy monster */
   if (off(*tp, ISFLEE)) runto(tp, &hero);
}

/* 
 * the cleric asks his deity for a spell
 */

pray()
{
    register int num_prayers, prayer_ability, which_prayer;

    which_prayer = num_prayers = prayer_ability =  0;

    if (player.t_ctype != C_CLERIC  && player.t_ctype != C_PALADIN &&
        cur_relic[HEIL_ANKH] == 0) {
            msg("You are not permitted to pray.");
            return;
    }
    if (cur_misc[WEAR_CLOAK] != NULL &&
        cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) {
        msg("You can't seem to pray!");
        return;
    }

    prayer_ability = pstats.s_lvl * pstats.s_wisdom - 5;
    if (player.t_ctype != C_CLERIC)
        prayer_ability /= 2;

    if (cur_relic[HEIL_ANKH]) prayer_ability += 75;

    if (player.t_action != C_PRAY) {
        num_prayers = 0;

        /* Get the number of avilable prayers */
        if (pstats.s_wisdom > 16) 
            num_prayers += pstats.s_wisdom - 16;

        num_prayers += pstats.s_lvl;
        if (cur_relic[HEIL_ANKH])
            num_prayers += pstats.s_wisdom - 18;

        if (player.t_ctype != C_CLERIC) 
            num_prayers /= 2;

        if (num_prayers > MAXPRAYERS) 
            num_prayers = MAXPRAYERS;
        if (num_prayers < 1) {
            msg("You are not permitted to pray yet.");
            return;
        }

        /* Prompt for prayer */
        if (pick_spell( cleric_spells, 
                        prayer_ability, 
                        num_prayers, 
                        pray_time,
                        "offer",
                        "prayer"))
            player.t_action = C_PRAY;

        return;
    }

    /* We've waited our required praying time. */
    which_prayer = player.t_selection;
    player.t_selection = 0;
    player.t_action = A_NIL;

    if (cleric_spells[which_prayer].s_cost + pray_time > prayer_ability) {
        msg("Your prayer fails.");
        return;
    }

    msg("Your prayer has been granted. ");

    if (cleric_spells[which_prayer].s_type == TYP_POTION)
        quaff(          cleric_spells[which_prayer].s_which,
                        NULL,
                        cleric_spells[which_prayer].s_flag,
                        FALSE);
    else if (cleric_spells[which_prayer].s_type == TYP_SCROLL)
        read_scroll(    cleric_spells[which_prayer].s_which,
                        cleric_spells[which_prayer].s_flag,
                        FALSE);
    else if (cleric_spells[which_prayer].s_type == TYP_STICK) {
         if (!player_zap(cleric_spells[which_prayer].s_which,
                         cleric_spells[which_prayer].s_flag)) {
             after = FALSE;
             return;
         }
    }
    pray_time += cleric_spells[which_prayer].s_cost;
}

/*
 * the magician is going to try and cast a spell
 */

cast()
{
    register int spell_ability, which_spell, num_spells;

    if (player.t_ctype != C_MAGICIAN && player.t_ctype != C_RANGER) {
        msg("You are not permitted to cast spells.");
        return;
    }
    if (cur_misc[WEAR_CLOAK] != NULL &&
        cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) {
        msg("You can't seem to cast spells!");
        return;
    }
    spell_ability = pstats.s_lvl * pstats.s_intel - 5;
    if (player.t_ctype != C_MAGICIAN)
        spell_ability /= 2;

    if (player.t_action != C_CAST) {
        /* 
         * Get the number of avilable spells 
         */
        num_spells = 0;
        if (pstats.s_intel > 16) 
            num_spells += pstats.s_intel - 16;

        num_spells += pstats.s_lvl;
        if (player.t_ctype != C_MAGICIAN) 
            num_spells /= 2;
        if (num_spells > MAXSPELLS)
            num_spells = MAXSPELLS;
        if (num_spells < 1) {
            msg("You are not allowed to cast spells yet.");
            return;
        }

    /* prompt for spell */
        if (pick_spell( magic_spells, 
                        spell_ability, 
                        num_spells, 
                        spell_power,
                        "cast",
                        "spell"))
            player.t_action = C_CAST;
        return;
    }

    /* We've waited our required casting time. */
    which_spell = player.t_selection;
    player.t_selection = 0;
    player.t_action = A_NIL;

    if ((spell_power + magic_spells[which_spell].s_cost) > spell_ability) {
        msg("Your attempt fails.");
        return;
    }

    msg("Your spell is successful. ");

    if (magic_spells[which_spell].s_type == TYP_POTION)
        quaff(  magic_spells[which_spell].s_which,
                NULL,
                magic_spells[which_spell].s_flag,
                FALSE);
    else if (magic_spells[which_spell].s_type == TYP_SCROLL)
        read_scroll(    magic_spells[which_spell].s_which,
                        magic_spells[which_spell].s_flag,
                        FALSE);
    else if (magic_spells[which_spell].s_type == TYP_STICK) {
         if (!player_zap(magic_spells[which_spell].s_which,
                         magic_spells[which_spell].s_flag)) {
             after = FALSE;
             return;
         }
    }
    spell_power += magic_spells[which_spell].s_cost;
}

/* 
 * the druid asks his deity for a spell
 */

chant()
{
    register int num_chants, chant_ability, which_chant;

    which_chant = num_chants = chant_ability = 0;

    if (player.t_ctype != C_DRUID && player.t_ctype != C_MONK) {
        msg("You are not permitted to chant.");
        return;
    }
    if (cur_misc[WEAR_CLOAK] != NULL &&
        cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) {
        msg("You can't seem to chant!");
        return;
    }
    chant_ability = pstats.s_lvl * pstats.s_wisdom - 5;
    if (player.t_ctype != C_DRUID)
        chant_ability /= 2;

    if (player.t_action != C_CHANT) {
        num_chants = 0;

        /* Get the number of avilable chants */
        if (pstats.s_wisdom > 16) 
            num_chants += pstats.s_wisdom - 16;

        num_chants += pstats.s_lvl;

        if (player.t_ctype != C_DRUID) 
            num_chants /= 2;

        if (num_chants > MAXCHANTS) 
            num_chants = MAXCHANTS;

        if (num_chants < 1) {
            msg("You are not permitted to chant yet.");
            return;
        }

        /* Prompt for chant */
        if (pick_spell( druid_spells, 
                        chant_ability, 
                        num_chants, 
                        chant_time,
                        "sing",
                        "chant"))
            player.t_action = C_CHANT;

        return;
    }

    /* We've waited our required chanting time. */
    which_chant = player.t_selection;
    player.t_selection = 0;
    player.t_action = A_NIL;

    if (druid_spells[which_chant].s_cost + chant_time > chant_ability) {
        msg("Your chant fails.");
        return;
    }

    msg("Your chant has been granted. ");

    if (druid_spells[which_chant].s_type == TYP_POTION)
        quaff(          druid_spells[which_chant].s_which,
                        NULL,
                        druid_spells[which_chant].s_flag,
                        FALSE);
    else if (druid_spells[which_chant].s_type == TYP_SCROLL)
        read_scroll(    druid_spells[which_chant].s_which,
                        druid_spells[which_chant].s_flag,
                        FALSE);
    else if (druid_spells[which_chant].s_type == TYP_STICK) {
         if (!player_zap(druid_spells[which_chant].s_which,
                         druid_spells[which_chant].s_flag)) {
             after = FALSE;
             return;
         }
    }
    chant_time += druid_spells[which_chant].s_cost;
}

/* Constitution bonus */

const_bonus()   /* Hit point adjustment for changing levels */
{
    register int bonus;
    if (pstats.s_const > 9 && pstats.s_const < 18) 
        bonus = 0;
    else if (pstats.s_const >= 18 && pstats.s_const < 20) 
        bonus = 1;
    else if (pstats.s_const >= 20 && pstats.s_const < 26) 
        bonus = 2;
    else if (pstats.s_const >= 26 && pstats.s_const < 36) 
        bonus = 3;
    else if (pstats.s_const >= 36) 
        bonus = 4;
    else if (pstats.s_const > 7) 
        bonus = -1;
    else
        bonus = -2;
    switch(player.t_ctype) {
        case C_FIGHTER:         bonus = min(bonus, 11);
        when C_RANGER:          bonus = min(bonus,  9);
        when C_PALADIN:         bonus = min(bonus,  9);
        when C_MAGICIAN:        bonus = min(bonus,  8);
        when C_CLERIC:          bonus = min(bonus,  8);
        when C_THIEF:           bonus = min(bonus, 10);
        when C_ASSASSIN:        bonus = min(bonus, 10);
        when C_DRUID:           bonus = min(bonus,  8);
        when C_MONK:            bonus = min(bonus,  9);
        otherwise:              bonus = min(bonus,  7);
    }
    return(bonus);
}

/*
 * Give away slime-molds to monsters.  If monster is friendly, 
 * it will give you a "regular" food ration in return.  You have
 * to give a slime-mold to Alteran (a unique monster) in order to 
 * get the special "Card of Alteran" quest item.  There's no other
 * way to get this artifact and remain alive.
 */

give(th)
register struct thing *th;
{
    /*
     * Find any monster within one space of you
     */
    struct linked_list *ll;
    struct object *lb;
    register int x,y;
    register struct linked_list *mon = NULL;
    bool gotone = FALSE;

    if (levtype != POSTLEV) {  /* no monsters at trading post  */
        for (x = hero.x-1; x <= hero.x+1; x++) {
            for (y = hero.y-1; y <= hero.y+1; y++) {
                if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1)
                    continue;
                if (isalpha(mvwinch(mw, y, x))) {
                    if ((mon = find_mons(y, x)) != NULL) {
                        gotone = TRUE;  /* found a monster to give away to */
                        th = THINGPTR(mon);
                    }
                }
            }
        }
    }
    if (gotone) {
        if ((ll=get_item(pack, "give away", ALL, FALSE, FALSE)) != NULL) {
            lb = OBJPTR(ll);
            mpos = 0;
            switch(lb->o_type) {
                case FOOD:
                    switch (lb->o_which) {
                        case E_SLIMEMOLD:   /* only slime-molds for now */
                if (on(*th, CANSELL)) {  /* quartermaster */
                msg("%s laughs at you. ");
                return;
                }
                if ((on(*th, ISFRIENDLY) || off(*th, ISMEAN)) &&
                off(*th, ISUNIQUE) && off(*th, CANSELL)) {
                turn_on(*th, ISRUN); /* we want him awake */
                                msg("%s accepts and promptly eats your gift of food.  --More--", prname(monster_name(th), TRUE));
                wait_for(' ');
                    del_pack(ll); /* delete slime-mold */
                          /* and add a food ration */
                create_obj(FALSE, FOOD, E_RATION);
                msg("%s gives you food in return and nods off to sleep. ", prname(monster_name(th), TRUE));
                turn_off(*th, ISRUN); /* put him to sleep */
                return;
                }
                else if (on(*th, CARRYCARD) && on(*th, ISUNIQUE)) {
                /* Now you get the Card of Alteran */
                msg("%s gives you a strange rectangular card. --More--", prname(monster_name(th), TRUE));
                wait_for(' ');
                    del_pack(ll); /* get rid of slime-mold */
                create_obj(FALSE, RELIC, ALTERAN_CARD);
                msg("%s bids you farewell. ", prname(monster_name(th), TRUE));
                killed(mon, FALSE, FALSE, FALSE);
                return;
                }
                else if (on(*th, ISUNIQUE) && off(*th, ISMEAN)) {
                /* Dragons */
                msg("%s is set free by your generosity. ", prname(monster_name(th), TRUE));
                    del_pack(ll);  /* get rid of it */
                /* just let him roam around */
                turn_on(*th, ISRUN);
                if (on(*th, ISFLEE)) turn_off(*th, ISFLEE);
                runto(th, &player);
                th->t_action = A_NIL;
                return;
                }
                else if (on(*th, ISRUN) && off(*th, ISUNIQUE)) {
                /* if NOT sleeping and not a unique */
                switch (rnd(2)) {
                    case 0: msg("%s ignores you. ", prname(monster_name(th), TRUE));
                    when 1: {
                    msg("%s nips at your hand. ", prname(monster_name(th), TRUE));
                    if (rnd(100) < 10) { 
                                del_pack(ll); /* delete it */
                        if (off(*th, ISMEAN)) {
                        msg("The slime-mold makes %s sleepy. ", prname(monster_name(th), TRUE));
                        /* put him to sleep */
                        turn_off(*th, ISRUN);
                        return;
                        }
                        else {  
                        switch (rnd(2)) {
                            case 0: msg("%s's eyes roll back. ", prname(monster_name(th), TRUE));
                                when 1: msg("%s becomes wanderlust. ", prname(monster_name(th), TRUE));
                        }
                        /* just let him roam around */
                            turn_on(*th, ISRUN);
                        if (on(*th, ISFLEE))
                                        turn_off(*th, ISFLEE);
                        runto(th, &player);
                        th->t_action = A_NIL;
                        return;
                        }
                    }
                    }
                }
                }
                else {
                msg("%s's mouth waters. ", prname(monster_name(th), TRUE));
                /* this wakes him up */
                if (off(*th, ISUNIQUE)) turn_on(*th, ISRUN);
                return;
                }
                otherwise:
                switch (rnd(3)) {  /* mention food (hint hint) */
                    case 0: msg("You cannot give away the %s! ", foods[lb->o_which].mi_name);
                    when 1: msg("The %s looks rancid! ", foods[lb->o_which].mi_name);
                    when 2: msg("You change your mind. ");
                }
                return;
                    }
            otherwise:
            switch (rnd(3)) {  /* do not mention other items */
                    case 0: msg("You feel foolish. ");
                    when 1: msg("You change your mind. ");
                    when 2: msg("%s ignores you. ", prname(monster_name(th), TRUE));
            }

        return;
            }
        }
    }
    else msg("Your efforts are futile. ");
    return;
}

/*
 * Frighten a monster.  Useful for the 'good' characters.
 */

fright(th)
register struct thing *th;
{
    /*
     * Find any monster within one space of you
     */
    register int x,y;
    register struct linked_list *mon;
    bool gotone = FALSE;

    if (levtype != POSTLEV) {  /* no monsters at trading post  */
        for (x = hero.x-1; x <= hero.x+1; x++) {
            for (y = hero.y-1; y <= hero.y+1; y++) {
                if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1)
                    continue;
                if (isalpha(mvwinch(mw, y, x))) {
                    if ((mon = find_mons(y, x)) != NULL) {
                        gotone = TRUE;  /* found a monster to give away to */
                        th = THINGPTR(mon);
                    }
                }
            }
        }
    }
    if (gotone) {  /* If 'good' character or is wearing a ring of fear */
        if (player.t_ctype == C_RANGER || player.t_ctype == C_PALADIN ||
            player.t_ctype == C_MONK   || ISWEARING(R_FEAR) != 0) { 

            player.t_action = A_NIL;
            player.t_no_move = movement(&player);
            switch (player.t_ctype) {
                case C_FIGHTER:   /* loss of strength */
                    pstats.s_str--;
                    if (pstats.s_str < 3) pstats.s_str = 3;
                when C_RANGER:    /* loss of charisma */
        case C_PALADIN:
                    pstats.s_charisma--;
                    if (pstats.s_charisma < 3) pstats.s_charisma = 3;
                when C_CLERIC:    /* loss of wisdom */
        case C_DRUID:
                    pstats.s_wisdom--;
                    if (pstats.s_wisdom < 3) pstats.s_wisdom = 3;
                when C_MAGICIAN:  /* loss of wisdom intelligence */
            pstats.s_intel--;
                    if (pstats.s_intel < 3) pstats.s_intel = 3;
                when C_THIEF:     /* loss of dexterity */
                case C_ASSASSIN:
                    pstats.s_dext--;
                    if (pstats.s_dext < 3) pstats.s_dext = 3;
                when C_MONK:      /* loss of constitution */
                    pstats.s_const--;
                    if (pstats.s_const < 3) pstats.s_const = 3;
                otherwise:        /* this msg can induce great fear */
                    msg("You miss. ");
        }

        /* Cause a panic.  Good thru level 16. */
            if (level < 17) { 
        msg("You wave your arms and yell! ");
                do_panic(th->t_index);
                pstats.s_hpt -= (pstats.s_hpt/2)+1;
        if (pstats.s_hpt < 25) msg("You heart quivers... ");
                if (pstats.s_hpt < 1) {
            msg("Your heart stops!!  --More--");
            wait_for(' ');
            pstats.s_hpt = -1;
            death(D_FRIGHT);
        }
            return;
        }
        else {
        /* He can't do it after level 16 */
        switch (rnd(20)) { 
            case 0: case 2:
            msg("You stamp your foot!! ");
            when 4: case 8:
            msg("%s laughs at you! ",prname(monster_name(th),TRUE));
            when 10: case 12:
            msg("You forget what you are doing? ");
                otherwise:
                msg(nothing);
        }
            return;
        }
    }
        else {
        switch (rnd(25)) {
        case 0: case 2: case 4:
        msg("You motion angrily! ");
        when 6: case 8: case 10:
        msg("You can't frighten anything. ");
        when 12: case 14: case 16:
        msg("Your puff up your face. ");
        otherwise:
        msg(nothing);
        }
    return;
    }
    }
    else {
    msg("There is nothing to fear but fear itself. ");
    return;
    }
}

/* Routines for thieves */

/*
 * gsense: Sense gold
 */

gsense()
{
    /* Thief & assassin can do this, but fighter & ranger can later */
    if (player.t_ctype == C_THIEF     || player.t_ctype == C_ASSASSIN ||
        ((player.t_ctype == C_FIGHTER || player.t_ctype == C_RANGER)  &&
    pstats.s_lvl >= 12)) {
          read_scroll(S_GFIND, NULL, FALSE);
    }
    else msg("You seem to have no gold sense.");
    return;
}

/*
 * xsense: Sense traps
 */

xsense()
{
    /* Only thief can do this, but assassin, fighter, & monk can later */
    if (player.t_ctype == C_THIEF   || ((player.t_ctype == C_ASSASSIN ||
    player.t_ctype == C_FIGHTER || player.t_ctype == C_MONK)      &&
    pstats.s_lvl >= 14)) {
        read_scroll(S_FINDTRAPS, NULL, FALSE);
    }
    else msg("You seem not to be able to sense traps.");
    return;
}

/*
 * steal:
 *      Steal in direction given in delta
 */

steal()
{
    register struct linked_list *item;
    register struct thing *tp;
    register char *mname;
    coord new_pos;
    int thief_bonus = -50;
    bool isinvisible = FALSE;


    /* let the fighter steal after level 15 */
    if (player.t_ctype == C_FIGHTER && pstats.s_lvl < 15) {
        msg(nothing);
        return;
    }
    else if (player.t_ctype != C_THIEF    &&
        player.t_ctype  != C_ASSASSIN &&
            player.t_ctype  != C_FIGHTER) {
            msg("Only thieves and assassins can steal.");
            return;
    }
    if (on(player, ISBLIND)) {
        msg("You can't see anything.");
        return;
    }

    new_pos.y = hero.y + player.t_newpos.y;
    new_pos.x = hero.x + player.t_newpos.x;

    /* Anything there? */
    if (new_pos.y < 0 || new_pos.y > lines-3 ||
        new_pos.x < 0 || new_pos.x > cols-1 ||
        mvwinch(mw, new_pos.y, new_pos.x) == ' ') {
        msg("Nothing to steal from.");
        return;
    }

    if ((item = find_mons(new_pos.y, new_pos.x)) == NULL)
        debug("Steal from what @ %d,%d?", new_pos.y, new_pos.x);
    tp = THINGPTR(item);
    if (on(*tp, ISSTONE)) {
        msg ("You can't steal from stone!");
        return;
    }

    if (on(*tp, ISFLEE)) {
        msg("You can't get your hand in anywhere! ");
        return;
    }

    isinvisible = invisible(tp);
    if (isinvisible) mname = "creature";
    else mname = monster_name(tp);

    /* Can player steal something unnoticed? */
    if (player.t_ctype == C_THIEF)    thief_bonus = 9;
    if (player.t_ctype == C_ASSASSIN) thief_bonus = 6;
    if (player.t_ctype == C_FIGHTER)  thief_bonus = 3;
    if (on(*tp, ISUNIQUE)) thief_bonus -= 15;
    if (isinvisible) thief_bonus -= 20;
    if (on(*tp, ISINWALL) && off(player, CANINWALL)) thief_bonus -= 50;

    if (on(*tp, ISHELD) || tp->t_action == A_FREEZE ||
        rnd(100) <
        (thief_bonus + 2*dex_compute() + 5*pstats.s_lvl -
         5*(tp->t_stats.s_lvl - 3))) {
        register struct linked_list *s_item, *pack_ptr;
        int count = 0;
        unsigned long test;      /* Overflow check */

        s_item = NULL;  /* Start stolen goods out as nothing */

        /* Find a good item to take */
        for (pack_ptr=tp->t_pack; pack_ptr != NULL; pack_ptr=next(pack_ptr))
            if ((OBJPTR(pack_ptr))->o_type != RELIC &&
                pack_ptr != tp->t_using &&  /* Monster can't be using it */
                rnd(++count) == 0)
                s_item = pack_ptr;

        /* 
         * Find anything?
         */
        if (s_item == NULL) {