diff xrogue/sticks.c @ 133:e6179860cb76

Import XRogue 8.0 from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 21 Apr 2015 08:55:20 -0400
parents
children ce0cf824c192
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xrogue/sticks.c	Tue Apr 21 08:55:20 2015 -0400
@@ -0,0 +1,896 @@
+/*
+    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 "rogue.h"
+
+/*
+ * zap a stick and see what happens
+ */
+
+do_zap(zapper, obj, direction, which, flags)
+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);
+                }
+                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)  {