/*
    sticks.c - Functions to implement the various sticks one might find
    
    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.

    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 <curses.h>
#include <ctype.h>
#include <string.h>
#include "rogue.h"

void drain(int ymin, int ymax, int xmin, int xmax);

/*
 * zap a stick and see what happens
 */

void
do_zap(struct thing *zapper, struct object *obj, coord *direction, int which, 
       int flags)
{
    register struct linked_list *item = NULL;
    register struct thing *tp;
    register int y = 0, x = 0, bonus;
    struct linked_list *nitem;
    struct object *nobj;
    bool cursed, blessed, is_player = FALSE;
    char *mname = NULL;

    cursed = flags & ISCURSED;
    blessed = flags & ISBLESSED;

    if (obj && obj->o_type != RELIC) { /* all relics are chargeless */
        if (obj->o_charges < 1) {
            msg(nothing);
            return;
        }
        obj->o_charges--;
    }
    if (which == WS_WONDER) {
        switch (rnd(19)) {
            case  0: which = WS_ELECT;
            when  1: which = WS_FIRE;
            when  2: which = WS_COLD;
            when  3: which = WS_POLYMORPH;
            when  4: which = WS_MISSILE;
            when  5: which = WS_SLOW_M;
            when  6: which = WS_TELMON;
            when  7: which = WS_CANCEL;
            when  8: which = WS_CONFMON;
            when  9: which = WS_DISINTEGRATE;
            when 10: which = WS_PETRIFY;
            when 11: which = WS_PARALYZE;
            when 12: which = WS_MDEG;
            when 13: which = WS_FEAR;
            when 14: which = WS_CURING;
            when 15: which = WS_LIGHT;
            when 16: which = WS_HIT;
            when 17: which = WS_DRAIN;
            when 18: which = WS_CHARGE;
        }
        if(ws_magic[which].mi_curse>0 && rnd(100)<=ws_magic[which].mi_curse){
            cursed = TRUE;
            blessed = FALSE;
        }
    }

    tp = NULL;
    switch (which) {
        case WS_POLYMORPH:
        case WS_SLOW_M:
        case WS_TELMON:
        case WS_CANCEL:
        case WS_CONFMON:
        case WS_DISINTEGRATE:
        case WS_PETRIFY:
        case WS_PARALYZE:
        case WS_MDEG:
        case WS_FEAR:
            y = zapper->t_pos.y;
            x = zapper->t_pos.x;

            do {
                y += direction->y;
                x += direction->x;
            }
            while (shoot_ok(winat(y, x)) && !(y == hero.y && x == hero.x));

            if (y == hero.y && x == hero.x)
                is_player = TRUE;
            else if (isalpha(mvwinch(mw, y, x))) {
                item = find_mons(y, x);
                tp = THINGPTR(item);
                runto(tp, &hero);
                turn_off(*tp, CANSURPRISE);
                mname = monster_name(tp);
                is_player = FALSE;

                /* The monster may not like being shot at */
                if ((zapper == &player) &&
                    on(*tp, ISCHARMED)  &&
                    save(VS_MAGIC, tp, 0)) {
                    msg("The eyes of %s turn clear.", prname(mname, FALSE));
                    turn_off(*tp, ISCHARMED);
                    mname = monster_name(tp);
                }
            }
            else {
                /*
                 * if monster misses player because the player dodged then lessen
                 * the chances he will use the wand again since the player appears
                 * to be rather dextrous
                 */
                if (zapper != &player) 
                    zapper->t_wand = zapper->t_wand * 3 / 5;
            }
    }
    switch (which) {
        case WS_LIGHT:
            /*
             * Reddy Kilowat wand.  Light up the room
             */
            blue_light(blessed, cursed);
        when WS_DRAIN:
            /*
             * Take away 1/2 of hero's hit points, then take it away
             * evenly from the monsters in the room or next to hero
             * if he is in a passage (but leave the monsters alone
             * if the stick is cursed)
             */
            if (pstats.s_hpt < 2) {
                msg("You are too weak to use it.");
            }
            else if (cursed)
                pstats.s_hpt /= 2;
        if (pstats.s_hpt <= 0) {
            pstats.s_hpt = -1;
            msg("You drain your own life away.  --More--");
            death(D_STRENGTH);
        }
            else
                drain(hero.y-1, hero.y+1, hero.x-1, hero.x+1);

        when WS_POLYMORPH:
        {
            register char oldch;
            register struct room *rp;
            register struct linked_list *pitem;
            coord delta;

            if (tp == NULL)
                break;
            if (save(VS_MAGIC, tp, 0)) {
                msg(nothing);
                break;
            }
            rp = roomin(&tp->t_pos);
            check_residue(tp);
            delta.x = x;
            delta.y = y;
            detach(mlist, item);
            oldch = tp->t_oldch;
            pitem = tp->t_pack; /* save his pack */
            tp->t_pack = NULL;

            if (levtype == OUTSIDE) 
                new_monster(item,rnd(NUMDINOS)+NUMMONST-NUMDINOS,&delta,FALSE);
            else
                new_monster(item,rnd(NUMMONST-NUMUNIQUE-NUMDINOS-1)+1,&delta,FALSE);

            if (tp->t_pack != NULL) 
                o_free_list (tp->t_pack);
            tp->t_pack = pitem;
            if (isalpha(mvwinch(cw, y, x)))
                mvwaddch(cw, y, x, tp->t_type);
            tp->t_oldch = oldch;
            /*
             * should the room light up?
             */
            if (on(*tp, HASFIRE)) {
                if (rp) {
                    register struct linked_list *fire_item;

                    fire_item = creat_item();
                    ldata(fire_item) = (char *) tp;
                    attach(rp->r_fires, fire_item);
                    rp->r_flags |= HASFIRE;
                    if (cansee(tp->t_pos.y,tp->t_pos.x) &&
                        next(rp->r_fires) == NULL) light(&hero);
                }
            }
            runto(tp, &hero);
            msg(terse ? "A new %s!" 
                      : "You have created a new %s!",
                      monster_name(tp));
        }

        when WS_PETRIFY:
            if (tp == NULL)
                break;
            if (save(VS_MAGIC, tp, 0)) {
                msg(nothing);
                break;
            }
            check_residue(tp);
            turn_on(*tp, ISSTONE);
            turn_on(*tp, NOSTONE);
            turn_off(*tp, ISRUN);
            turn_off(*tp, ISINVIS);
            turn_off(*tp, CANSURPRISE);
            turn_off(*tp, ISDISGUISE);
            tp->t_action = A_NIL;
            tp->t_no_move = 0;
            msg("%s is turned to stone!",prname(mname, TRUE));

        when WS_TELMON:
        {
            register int rm;
            register struct room *rp;

            if (tp == NULL)
                break;
            if (save(VS_MAGIC, tp, 0)) {
                msg(nothing);
                break;
            }
            rp = NULL;
            check_residue(tp);
            tp->t_action = A_FREEZE; /* creature is disoriented */
            tp->t_no_move = 2;
            if (cursed) {       /* Teleport monster to player */
                if ((y == (hero.y + direction->y)) &&
                    (x == (hero.x + direction->x)))
                        msg(nothing);
                else {
                    tp->t_pos.y = hero.y + direction->y;
                    tp->t_pos.x = hero.x + direction->x;
                }
            }
            else if (blessed) { /* Get rid of monster */
                killed(item, FALSE, TRUE, TRUE);
                return;
            }
            else {
                register int i=0;

                do {    /* Move monster to another room */
                    rm = rnd_room();
                    rnd_pos(&rooms[rm], &tp->t_pos);
                }until(winat(tp->t_pos.y,tp->t_pos.x)==FLOOR ||i++>500);
                rp = &rooms[rm];
            }

            /* Now move the monster */
            if (isalpha(mvwinch(cw, y, x)))
                mvwaddch(cw, y, x, tp->t_oldch);
            mvwaddch(mw, y, x, ' ');
            mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type);
            if (tp->t_pos.y != y || tp->t_pos.x != x)
                tp->t_oldch = mvwinch(cw, tp->t_pos.y, tp->t_pos.x);
            /*
             * check to see if room that creature appears in should
             * light up
             */
            if (on(*tp, HASFIRE)) {
                if (rp) {
                    register struct linked_list *fire_item;

                    fire_item = creat_item();
                    ldata(fire_item) = (char *) tp;
                    attach(rp->r_fires, fire_item);
                    rp->r_flags |= HASFIRE;
                    if(cansee(tp->t_pos.y, tp->t_pos.x) && 
                       next(rp->r_fires) == NULL)
                        light(&hero);
                }
            }
        }
        when WS_CANCEL:
            if (tp == NULL)
                break;
            if (save(VS_MAGIC, tp, 0)) {
                msg(nothing);
                break;
            }
            check_residue(tp);
            tp->t_flags[0] &= CANC0MASK;
            tp->t_flags[1] &= CANC1MASK;
            tp->t_flags[2] &= CANC2MASK;
            tp->t_flags[3] &= CANC3MASK;
            tp->t_flags[4] &= CANC4MASK;
            tp->t_flags[5] &= CANC5MASK;
            tp->t_flags[6] &= CANC6MASK;
            tp->t_flags[7] &= CANC7MASK;
            tp->t_flags[8] &= CANC8MASK;
            tp->t_flags[9] &= CANC9MASK;
            tp->t_flags[10] &= CANCAMASK;
            tp->t_flags[11] &= CANCBMASK;
            tp->t_flags[12] &= CANCCMASK;
            tp->t_flags[13] &= CANCDMASK;
            tp->t_flags[14] &= CANCEMASK;
            tp->t_flags[15] &= CANCFMASK;

        when WS_MISSILE:
        {
            int dice;
            static struct object bolt =
            {
                MISSILE , {0, 0}, 0, "", "1d4 " , NULL, 0, WS_MISSILE, 50, 1
            };

            if (!obj)
                dice = zapper->t_stats.s_lvl;
            if (obj->o_type == RELIC)
                 dice = 15;
            else if (EQUAL(ws_type[which], "staff"))
                 dice = 10;
            else
                 dice = 6;
            sprintf(bolt.o_hurldmg, "%dd4", dice);
            do_motion(&bolt, direction->y, direction->x, zapper);
            if (!hit_monster(unc(bolt.o_pos), &bolt, zapper))
               msg("The missile vanishes with a puff of smoke");
        }
        when WS_HIT:
        {
            register unsigned char ch;
            struct object strike; /* don't want to change sticks attributes */

            direction->y += hero.y;
            direction->x += hero.x;
            ch = winat(direction->y, direction->x);
            if (isalpha(ch))
            {
                strike = *obj;
                strike.o_hplus  = 7;
                if (EQUAL(ws_type[which], "staff"))
                    strcpy(strike.o_damage,"3d8");
                else
                    strcpy(strike.o_damage,"2d8");
                fight(direction, &strike, FALSE);
            }
        }
        when WS_SLOW_M:
            if (is_player) {
                add_slow();
                break;
            }
            if (tp == NULL)
                break;
            if (cursed) {
                if (on(*tp, ISSLOW))
                    turn_off(*tp, ISSLOW);
                else
                    turn_on(*tp, ISHASTE);
                break;
            }
            if ((on(*tp,ISUNIQUE) && save(VS_MAGIC,tp,0)) || on(*tp,NOSLOW)) {
                msg(nothing);
                break;
            }
            else if (blessed) {
                turn_off(*tp, ISRUN);
                turn_on(*tp, ISHELD);
            }
            /*
             * always slow in case he breaks free of HOLD
             */
            if (on(*tp, ISHASTE))
                turn_off(*tp, ISHASTE);
            else
                turn_on(*tp, ISSLOW);

        when WS_CHARGE:
            if (ws_know[WS_CHARGE] != TRUE && obj)
                msg("This is a wand of charging.");
            nitem = get_item(pack, "charge", STICK, FALSE, FALSE);
            if (nitem != NULL) {
                nobj = OBJPTR(nitem);
                if ((++(nobj->o_charges) == 1) && (nobj->o_which == WS_HIT))
                    fix_stick(nobj);
                if (blessed) ++(nobj->o_charges);
                if (EQUAL(ws_type[nobj->o_which], "staff")) {
                    if (nobj->o_charges > 200) 
                        nobj->o_charges = 200;
                }
                else {
                    if (nobj->o_charges > 200)
                        nobj->o_charges = 200;
                }
            }
        when WS_ELECT:
            shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT, 
                        "lightning bolt", roll(zapper->t_stats.s_lvl,6));

        when WS_FIRE:
            shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT, 
                        "flame", roll(zapper->t_stats.s_lvl,6));

        when WS_COLD:
            shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT, 
                        "ice", roll(zapper->t_stats.s_lvl,6));

        when WS_CONFMON:
            if (cursed || is_player) { 
                if (!save(VS_WAND, &player, 0)) {
                    dsrpt_player();
                    confus_player();
                }
                else {
                    if (zapper != &player) zapper->t_wand /= 2;
                    msg(nothing);
                }
            }
            else {
                if (tp == NULL)
                    break;
                if (save(VS_MAGIC, tp, 0) || on(*tp, ISCLEAR))
                     msg(nothing);
                else
                     turn_on (*tp, ISHUH);
            }
        when WS_PARALYZE:
            if (is_player || cursed) {
                if ((obj && obj->o_type==RELIC) || !save(VS_WAND, &player, 0)){
                    player.t_no_move += 2 * movement(&player) * FREEZETIME;
                    player.t_action = A_FREEZE;
                    msg("You can't move.");
                }
                else {
                    if (zapper != &player) zapper->t_wand /= 2;
                    msg(nothing);
                }
            }
            else {
                if (tp == NULL)
                    break;
                bonus = 0;
                if (blessed) bonus = -3;
                if (((obj && obj->o_type==RELIC) || !save(VS_WAND,tp,bonus)) &&
                    off(*tp, NOPARALYZE)) {
                    tp->t_no_move += 2 * movement(tp) * FREEZETIME;
                    tp->t_action = A_FREEZE;
                }
                else {
                    msg(nothing);
                }
            }
        when WS_FEAR:
            if (is_player) {
                if (!on(player, ISFLEE)         || 
                    ISWEARING(R_HEROISM)        || 
                    save(VS_WAND, &player, 0)) {
                        msg(nothing);
                        zapper->t_wand /= 2;
                }
                else {
                    turn_on(player, ISFLEE);
                    player.t_dest = &zapper->t_pos;
                    msg("The sight of %s terrifies you.", prname(mname, FALSE));
                }
                break;
            }
            if (tp == NULL)
                break;
            bonus = 0;
            if (blessed) bonus = -3;
            if(save(VS_WAND, tp,bonus) || on(*tp,ISUNDEAD) || on(*tp,NOFEAR)){
                    msg(nothing);
                    break;
            }
            turn_on(*tp, ISFLEE);
            turn_on(*tp, WASTURNED);

            /* Stop it from attacking us */
            dsrpt_monster(tp, TRUE, cansee(tp->t_pos.y, tp->t_pos.x));

            /* 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;

        when WS_MDEG:
            if (is_player) {
                if (save(VS_WAND, &player, 0)) {
                    msg (nothing);
                    zapper->t_wand /= 2;
                    break;
                }
                pstats.s_hpt /= 2;
                if (pstats.s_hpt <= 0) {
            pstats.s_hpt = -1;
                    msg("Your life has been sucked out from you!  --More--");
                    wait_for(' ');
                    death(zapper->t_index);
                }
                else
                    msg("You feel a great drain on your system.");
            }
            if (tp == NULL)
                break;
            if (cursed) {
                 tp->t_stats.s_hpt *= 2;
                 msg("%s appears to be stronger now!", prname(mname, TRUE));
            }
            else if (on(*tp, ISUNIQUE) && save(VS_WAND, tp, 0))
                 msg (nothing);
            else {
                 tp->t_stats.s_hpt /= 2;
                 msg("%s appears to be weaker now", prname(mname, TRUE));
            }
            if (tp->t_stats.s_hpt < 1)
                 killed(item, TRUE, TRUE, TRUE);
        when WS_DISINTEGRATE:
            if (tp == NULL)
                break;
            if (cursed) {
                register int m1, m2;
                coord mp;
                struct linked_list *titem;
                char ch;
                struct thing *th;

                if (on(*tp, ISUNIQUE) || on(*tp, CANSELL)) {
                    msg (nothing);
                    break;
                }
                for (m1=tp->t_pos.x-1 ; m1 <= tp->t_pos.x+1 ; m1++) {
                    for(m2=tp->t_pos.y-1 ; m2<=tp->t_pos.y+1 ; m2++) {
                        if (m1 == hero.x && m2 == hero.y)
                            continue;
                        ch = winat(m2,m1);
                        if (shoot_ok(ch)) {
                            mp.x = m1;  /* create it */
                            mp.y = m2;
                            titem = new_item(sizeof(struct thing));
                            new_monster(titem,(short)tp->t_index,&mp,FALSE);
                            th = THINGPTR(titem);
                            turn_on (*th, ISMEAN);
                            runto(th,&hero);
                            if (on(*th, HASFIRE)) {
                                register struct room *rp;

                                rp = roomin(&th->t_pos);
                                if (rp) {
                                    register struct linked_list *fire_item;

                                    fire_item = creat_item();
                                    ldata(fire_item) = (char *) th;
                                    attach(rp->r_fires, fire_item);
                                    rp->r_flags |= HASFIRE;
                                    if (cansee(th->t_pos.y, th->t_pos.x) &&
                                        next(rp->r_fires) == NULL)
                                        light(&hero);
                                }
                            }
                        }
                    }
                }
            }
            else { /* if its a UNIQUE it might still live */
                if (on(*tp, ISUNIQUE) && save(VS_MAGIC, tp, 0)) {
                    tp->t_stats.s_hpt /= 2;
                    if (tp->t_stats.s_hpt < 1) {
                         killed(item, FALSE, TRUE, TRUE);
                         msg("You have disintegrated %s", prname(mname, FALSE));
                    }
                    else {
                        msg("%s appears wounded", prname(mname, TRUE));
                    }
                }
                else {
                    msg("You have disintegrated %s", prname(mname, FALSE));
                    killed (item, FALSE, TRUE, TRUE);
                }
            }
        when WS_CURING:
            if (cursed) {
        bool sick = FALSE;
                if (!save(VS_POISON, &player, 0)) {
                    msg("You feel extremely sick. ");
            sick = TRUE;
                    pstats.s_hpt -= (pstats.s_hpt/3)+1;
                    if (pstats.s_hpt == 0)  {
            pstats.s_hpt = -1;
            msg("You die!  --More--");
            wait_for(' ');
            death (D_POISON);
            }
                }
                if (!save(VS_WAND, &player, 0) && !ISWEARING(R_HEALTH)) {
                    turn_on(player, HASDISEASE);
                    turn_on(player, HASINFEST);
                    turn_on(player, DOROT);
                    fuse(cure_disease, NULL, roll(HEALTIME,SICKTIME), AFTER);
                    infest_dam++;
                }
        else if (sick == FALSE) msg("You feel momentarily sick");
            }
            else {
                if (on(player, HASDISEASE) || on(player, HASINFEST)) {
                    extinguish(cure_disease);
                    turn_off(player, HASINFEST);
                    infest_dam = 0;
                    cure_disease(); /* this prints message */
                }
                if (on(player, DOROT)) {
                    msg("You feel your skin returning to normal.");
                    turn_off(player, DOROT);
                }
                pstats.s_hpt += roll(pstats.s_lvl, blessed ? 9 : 6);
                if (pstats.s_hpt > max_stats.s_hpt)
                    pstats.s_hpt = max_stats.s_hpt;
                msg("You begin to feel %sbetter.", blessed ? "much " : "");
                    
            }
        otherwise:
            msg("What a bizarre schtick!");
    }
}


/*
 * drain:
 *      Do drain hit points from player shtick
 */

void
drain(int ymin, int ymax, int xmin, int xmax)
{
    register int i, j, count;
    register struct thing *ick;
    register struct linked_list *item;

    /*
     * First count how many things we need to spread the hit points among
     */
    count = 0;
    for (i = ymin; i <= ymax; i++) {
        if (i < 1 || i > lines - 3)
            continue;
        for (j = xmin; j <= xmax; j++) {
            if (j < 0 || j > cols - 1)
                continue;
            if (isalpha(mvwinch(mw, i, j)))
                count++;
        }
    }
    if (count == 0)
    {
        msg("You have a tingling feeling.");
        return;
    }
    count = pstats.s_hpt / count;
    pstats.s_hpt /= 2;
    if (pstats.s_hpt <= 0) {
    pstats.s_hpt = -1;
    msg("Aarrgghhh!!  --More--");
    wait_for(' ');
    death(D_STRENGTH);
    }
    /*
     * Now zot all of the monsters
     */
    for (i = ymin; i <= ymax; i++) {
        if (i < 1 || i > lines - 3)
            continue;
        for (j = xmin; j <= xmax; j++) {
            if (j < 0 || j > cols - 1)
                continue;
            if (isalpha(mvwinch(mw, i, j)) &&
                ((item = find_mons(i, j)) != NULL)) {
                ick = THINGPTR(item);
                if (on(*ick, ISUNIQUE) && save(VS_MAGIC, ick, 0)) 
                    ick->t_stats.s_hpt -= count / 2;
                else
                    ick->t_stats.s_hpt -= count;
                if (ick->t_stats.s_hpt < 1)
                    killed(item, 
                           cansee(i,j)&&(!on(*ick,ISINVIS)||on(player,CANSEE)),
                           TRUE, TRUE);
                else {
                    runto(ick, &hero);

                    /* 
                     * The monster may not like being shot at.  Since the
                     * shot is not aimed directly at the monster, we will
                     * give him a poorer save.
                     */
                    if (on(*ick, ISCHARMED) && save(VS_MAGIC, ick, -2)) {
                        msg("The eyes of %s turn clear.",
                            prname(monster_name(ick), FALSE));
                        turn_off(*ick, ISCHARMED);
                    }
                    if (cansee(i,j) && (!on(*ick,ISINVIS)||on(player,CANSEE)))
                            msg("%s appears wounded", 
                                prname(monster_name(ick), TRUE));
                }
            }
        }
    }
}

/*
 * initialize a stick
 */

void
fix_stick(struct object *cur)
{
    if (EQUAL(ws_type[cur->o_which], "staff")) {
        cur->o_weight = 100;
        cur->o_charges = 5 + rnd(11);
        strcpy(cur->o_damage,"3d4");
        cur->o_hplus = 1;
        cur->o_dplus = 0;
        switch (cur->o_which) {
            case WS_HIT:
                cur->o_hplus = 3;
                cur->o_dplus = 3;
                strcpy(cur->o_damage,"2d8");
            when WS_LIGHT:
                cur->o_charges = 15 + rnd(11);
            }
    }
    else {
        strcpy(cur->o_damage,"2d3");
        cur->o_weight = 75;
        cur->o_hplus = 1;
        cur->o_dplus = 0;
        cur->o_charges = 5 + rnd(11);
        switch (cur->o_which) {
            case WS_HIT:
                cur->o_hplus = 3;
                cur->o_dplus = 3;
                strcpy(cur->o_damage,"2d8");
            when WS_LIGHT:
                cur->o_charges = 15 + rnd(11);
            }
    }
    strcpy(cur->o_hurldmg,"3d3");

}

/*
 * Use the wand that our monster is wielding.
 */

void
m_use_wand(struct thing *monster)
{
    register struct object *obj;

    /* Make sure we really have it */
    if (monster->t_using) 
        obj = OBJPTR(monster->t_using);
    else {
        debug("Stick not set!");
        monster->t_action = A_NIL;
        return;
    }

    if (obj->o_type != STICK) {
        debug("Stick not selected!");
        monster->t_action = A_NIL;
        return;
    }
    /*
     * shoot the stick!
     * assume all blessed sticks are normal for now. 
     * Note that we don't get here if the wand is cursed.
     */
    msg("%s points a %s at you!", prname(monster_name(monster), TRUE),
        ws_type[obj->o_which]);
    do_zap(monster, obj, &monster->t_newpos, obj->o_which, 0);
    monster->t_wand /= 2; /* chance lowers with each use */
}

/*
 * type: type of item, NULL means stick
 * which: which item
 */
bool
need_dir(int type, int which)
{
    if (type == STICK || type == 0) {
        switch (which) {
            case WS_LIGHT:
            case WS_DRAIN: 
            case WS_CHARGE:
            case WS_CURING:
                return(FALSE);
            default:
                return(TRUE);
        }
    }
    else if (type == RELIC) {
        switch (which) {
            case MING_STAFF:
            case ASMO_ROD:
            case EMORI_CLOAK:
                return(TRUE);
            default:
                return(FALSE);
        }
    }
return (FALSE); /* hope we don't get here */
}

/*
 * let the player zap a stick and see what happens
 */

bool
player_zap(int which, int flag)
{
    register struct linked_list *item;
    register struct object *obj;

    obj = NULL;
    if (which == 0) {
        /* This is a stick.  It takes 2 movement periods to zap it */
        if (player.t_action != C_ZAP) {
            if ((item = get_item(pack,"zap with",ZAPPABLE,FALSE,FALSE)) == NULL)
                return(FALSE);

            obj = OBJPTR(item);

            if (need_dir(obj->o_type, obj->o_which)) {
                if (!get_dir(&player.t_newpos))
                    return(FALSE);
            }
            player.t_using = item;      /* Remember what it is */
            player.t_action = C_ZAP;    /* We are quaffing */
            player.t_no_move = 2 * movement(&player);
            return(TRUE);
        }

        item = player.t_using;
        /* We've waited our time, let's shoot 'em up! */
        player.t_using = NULL;
        player.t_action = A_NIL;

        obj = OBJPTR(item);

        /* Handle relics specially here */
        if (obj->o_type == RELIC) {
            switch (obj->o_which) {
                case ORCUS_WAND:
            /* msg(nothing); */
            read_scroll(S_PETRIFY, 0, FALSE);
            return(TRUE);
                when MING_STAFF:
                    which = WS_MISSILE;
                when EMORI_CLOAK:
                    which = WS_PARALYZE;
                    obj->o_charges = 0; /* one zap/day (whatever that is) */
                    fuse(cloak_charge, obj, CLOAK_TIME, AFTER);
                when ASMO_ROD:
                    switch (rnd(3)) {
                        case 0:         which = WS_ELECT;
                        when 1:         which = WS_COLD;
                        otherwise:      which = WS_FIRE;
                    }
            }
        }
        else {
            which = obj->o_which;
            ws_know[which] = TRUE;
            flag = obj->o_flags;
        }
    }
    do_zap(&player, obj, &player.t_newpos, which, flag);
    return(TRUE);
}

