diff arogue5/sticks.c @ 63:0ed67132cf10

Import Advanced Rogue 5.8 from the Roguelike Restoration Project (r1490)
author elwin
date Thu, 09 Aug 2012 22:58:48 +0000
parents
children c49f7927b0fa
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arogue5/sticks.c	Thu Aug 09 22:58:48 2012 +0000
@@ -0,0 +1,1076 @@
+/*
+ * Functions to implement the various sticks one might find
+ * while wandering around the dungeon.
+ *
+ * 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(gotdir, which, flag)
+bool gotdir;
+int which;
+int flag;
+{
+    register struct linked_list *item;
+    register struct object *obj = NULL;
+    register struct thing *tp;
+    register int y, x;
+    struct linked_list *nitem;
+    struct object *nobj;
+    bool cursed, blessed, is_stick;
+
+    blessed = FALSE;
+    cursed = FALSE;
+    is_stick = FALSE;
+
+    if (which == 0) {
+	if ((item = get_item(pack, "zap with", ZAPPABLE)) == NULL)
+	    return(FALSE);
+	obj = OBJPTR(item);
+
+	/* Handle relics specially here */
+	if (obj->o_type == RELIC) {
+	    switch (obj->o_which) {
+		case ORCUS_WAND:
+		    msg(nothing);
+		    return(TRUE);
+		when MING_STAFF:
+		    which = WS_MISSILE;
+		when ASMO_ROD:
+		    switch (rnd(3)) {
+			case 0:
+			    which = WS_ELECT;
+			when 1:
+			    which = WS_COLD;
+			otherwise:
+			    which = WS_FIRE;
+		    }
+	    }
+	    cursed = FALSE;
+	    blessed = FALSE;
+	}
+	else {
+	    which = obj->o_which;
+	    ws_know[which] = TRUE;
+	    cursed = (obj->o_flags & ISCURSED) != 0;
+	    blessed = (obj->o_flags & ISBLESSED) != 0;
+	    is_stick = TRUE;
+	}
+    }
+    else {
+	cursed = flag & ISCURSED;
+	blessed = flag & ISBLESSED;
+    }
+    switch (which) {	/* no direction for these */
+	case WS_LIGHT:
+	case WS_DRAIN:
+	case WS_CHARGE:
+	case WS_CURING:
+	    break;
+
+	default:
+	    if (!get_dir())
+		return(FALSE);
+	    if (!gotdir) {
+		do {
+		    delta.y = rnd(3) - 1;
+		    delta.x = rnd(3) - 1;
+		} while (delta.y == 0 && delta.x == 0);
+	    }
+    }
+
+    if (is_stick) {
+	if (obj->o_charges < 1) {
+	    msg(nothing);
+	    return(TRUE);
+	}
+	obj->o_charges--;
+    }
+    if (which == WS_WONDER) {
+	switch (rnd(14)) {
+	    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;
+	}
+	if(ws_magic[which].mi_curse>0 && rnd(100)<=ws_magic[which].mi_curse){
+	    cursed = TRUE;
+	    blessed = FALSE;
+	}
+    }
+
+    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.");
+		return(TRUE);
+	    }
+	    if (cursed)
+		pstats.s_hpt /= 2;
+	    else
+		drain(hero.y-1, hero.y+1, hero.x-1, hero.x+1);
+	when WS_POLYMORPH:
+	case WS_TELMON:
+	case WS_CANCEL:
+	{
+	    register char monster, oldch;
+	    register int rm;
+
+	    y = hero.y;
+	    x = hero.x;
+	    while (shoot_ok(winat(y, x))) {
+		y += delta.y;
+		x += delta.x;
+	    }
+	    if (isalpha(monster = CCHAR( mvwinch(mw, y, x) ))) {
+		register struct room *rp;
+
+		item = find_mons(y, x);
+		tp = THINGPTR(item);
+		/* if the monster gets the saving throw, leave the case */
+		if (save(VS_MAGIC, tp, 0)) {
+		    msg(nothing);
+		    break;
+		}
+
+		/* Unhold player */
+		if (on(*tp, DIDHOLD)) {
+		    turn_off(*tp, DIDHOLD);
+		    if (--hold_count == 0) turn_off(player, ISHELD);
+		}
+		/* unsuffocate player */
+		if (on(*tp, DIDSUFFOCATE)) {
+		    turn_off(*tp, DIDSUFFOCATE);
+		    extinguish(suffocate);
+		}
+		rp = roomin(&tp->t_pos);
+		/*
+		 * check to see if room should go dark
+		 */
+		if (on(*tp, HASFIRE)) {
+		    if (rp != NULL) {
+			register struct linked_list *fire_item;
+
+			for (fire_item = rp->r_fires; fire_item != NULL;
+			     fire_item = next(fire_item)) {
+			    if (THINGPTR(fire_item) == tp) {
+				detach(rp->r_fires, fire_item);
+				destroy_item(fire_item);
+				if (rp->r_fires == NULL) {
+				    rp->r_flags &= ~HASFIRE;
+				    if(cansee(tp->t_pos.y,tp->t_pos.x))
+					light(&hero);
+				}
+				break;
+			    }
+			}
+		    }
+		}
+
+		if (which == WS_POLYMORPH) {
+		    register struct linked_list *pitem;
+
+		    delta.x = x;
+		    delta.y = y;
+		    detach(mlist, item);
+		    oldch = tp->t_oldch;
+		    pitem = tp->t_pack; /* save his pack */
+		    tp->t_pack = NULL;
+		    new_monster(item,rnd(NUMMONST-NUMUNIQUE-1)+1,&delta,FALSE);
+		    if (tp->t_pack != NULL) 
+			o_free_list (tp->t_pack);
+		    tp->t_pack = pitem;
+		    monster = tp->t_type;
+		    if (isalpha(mvwinch(cw, y, x)))
+			mvwaddch(cw, y, x, monster);
+		    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);
+			}
+		    }
+		    msg(terse ? "A new %s!" : "You have created a new %s!",
+			monsters[tp->t_index].m_name);
+		}
+		else if (which == WS_CANCEL) {
+		    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[4] &= CANC5MASK;
+		}
+		else { /* A teleport stick */
+		    if (cursed) {	/* Teleport monster to player */
+			if ((y == (hero.y + delta.y)) &&
+			    (x == (hero.x + delta.x)))
+				msg(nothing);
+			else {
+			    tp->t_pos.y = hero.y + delta.y;
+			    tp->t_pos.x = hero.x + delta.x;
+			}
+		    }
+		    else if (blessed) {	/* Get rid of monster */
+			killed(item, FALSE, TRUE);
+			return(TRUE);
+		    }
+		    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);
+		    turn_off(*tp, ISDISGUISE);
+		    mvwaddch(mw, y, x, ' ');
+		    mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, monster);
+		    if (tp->t_pos.y != y || tp->t_pos.x != x)
+			tp->t_oldch = CCHAR( 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)) {
+			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);
+	    }
+	}
+	when WS_MISSILE:
+	{
+	    static struct object bolt =
+	    {
+		MISSILE , {0, 0}, "", 0, "", "1d4 " , NULL, 0, WS_MISSILE, 50, 1
+	    };
+
+	    sprintf(bolt.o_hurldmg, "%dd4", pstats.s_lvl);
+	    do_motion(&bolt, delta.y, delta.x, &player);
+	    if (!hit_monster(unc(bolt.o_pos), &bolt, &player))
+	       msg("The missile vanishes with a puff of smoke");
+	}
+	when WS_HIT:
+	{
+	    register char ch;
+	    struct object strike; /* don't want to change sticks attributes */
+
+	    delta.y += hero.y;
+	    delta.x += hero.x;
+	    ch = CCHAR( winat(delta.y, delta.x) );
+	    if (isalpha(ch))
+	    {
+		strike = *obj;
+		strike.o_hplus  = 6;
+		if (EQUAL(ws_type[which], "staff"))
+		    strcpy(strike.o_damage,"3d8");
+		else
+		    strcpy(strike.o_damage,"2d8");
+		fight(&delta, &strike, FALSE);
+	    }
+	}
+	case WS_SLOW_M:
+	    y = hero.y;
+	    x = hero.x;
+	    while (shoot_ok(winat(y, x))) {
+		y += delta.y;
+		x += delta.x;
+	    }
+	    if (isalpha(mvwinch(mw, y, x))) {
+		item = find_mons(y, x);
+		tp = THINGPTR(item);
+		runto(tp, &hero);
+		if (on(*tp, ISUNIQUE) && save(VS_MAGIC, tp, 0))
+		    msg(nothing);
+		else if (on(*tp, NOSLOW))
+		    msg(nothing);
+		else if (cursed) {
+		    if (on(*tp, ISSLOW))
+			turn_off(*tp, ISSLOW);
+		    else
+			turn_on(*tp, ISHASTE);
+		}
+		else if (blessed) {
+		    turn_off(*tp, ISRUN);
+		    turn_on(*tp, ISHELD);
+		    return(TRUE);
+		}
+		else {
+		    if (on(*tp, ISHASTE))
+			turn_off(*tp, ISHASTE);
+		    else
+			turn_on(*tp, ISSLOW);
+		    tp->t_turn = TRUE;
+		}
+	    }
+	when WS_CHARGE:
+	    if (ws_know[WS_CHARGE] != TRUE && is_stick)
+		msg("This is a wand of charging.");
+	    if ((nitem = get_item(pack, "charge", STICK)) != NULL) {
+		nobj = OBJPTR(nitem);
+	        if ((++(nobj->o_charges) == 1) && (nobj->o_which == WS_HIT))
+		    fix_stick(nobj);
+	        if (EQUAL(ws_type[nobj->o_which], "staff")) {
+		    if (nobj->o_charges > 100) 
+		        nobj->o_charges = 100;
+		}
+	        else {
+		    if (nobj->o_charges > 50)
+		        nobj->o_charges = 50;
+		}
+	    }
+	when WS_ELECT:
+	case WS_FIRE:
+	case WS_COLD:
+	    {
+		char *name;
+
+		if (which == WS_ELECT)
+		    name = "lightning bolt";
+		else if (which == WS_FIRE)
+		    name = "flame";
+		else
+		    name = "ice";
+
+		shoot_bolt(	&player, hero, 
+				delta, TRUE, D_BOLT, 
+				name, roll(pstats.s_lvl,6));
+	    }
+	when WS_PETRIFY: {
+	    reg int m1, m2, x1, y1;
+	    reg char ch;
+	    reg struct linked_list *ll;
+	    reg struct thing *lt;
+
+	    y1 = hero.y;
+	    x1 = hero.x;
+	    do {
+		y1 += delta.y;
+		x1 += delta.x;
+		ch = CCHAR( winat(y1,x1) );
+	    } while (ch == PASSAGE || ch == FLOOR);
+	    for (m1 = x1 - 1 ; m1 <= x1 + 1 ; m1++) {
+		for(m2 = y1 - 1 ; m2 <= y1 + 1 ; m2++) {
+		    ch = CCHAR( winat(m2,m1) );
+		    if (m1 == hero.x && m2 == hero.y)
+			continue;
+		    if (ch != ' ') {
+			ll = find_obj(m2,m1);
+			if (ll != NULL) {
+			    detach(lvl_obj,ll);
+			    o_discard(ll);
+			}
+			ll = find_mons(m2,m1);
+			if (ll != NULL) {
+			    lt = THINGPTR(ll);
+			    if (on(*lt, ISUNIQUE)) 
+			        monsters[lt->t_index].m_normal = TRUE;
+			    check_residue(lt);
+			    detach(mlist,ll);
+			    t_discard(ll);
+			    mvwaddch(mw,m2,m1,' ');
+			}
+			mvaddch(m2,m1,' ');
+			mvwaddch(cw,m2,m1,' ');
+		    }
+		}
+	    }
+	    touchwin(cw);
+	    touchwin(mw);
+	}
+	when WS_CONFMON:
+	    if (cursed) {
+		if (off(player, ISCLEAR)) {
+		    if (on(player, ISHUH))
+			lengthen(unconfuse, rnd(20)+HUHDURATION);
+		    else {
+			turn_on(player, ISHUH);
+			fuse(unconfuse,0,rnd(20)+HUHDURATION,AFTER);
+			msg("Wait, what's going on here. Huh? What? Who?");
+		    }
+		}
+		else msg("You feel dizzy for a moment, but it quickly passes.");
+	    }
+	    else {
+		y = hero.y;
+		x = hero.x;
+		while (shoot_ok(winat(y, x)))
+		{
+		    y += delta.y;
+		    x += delta.x;
+		}
+		if (isalpha(mvwinch(mw, y, x)))
+		{
+		    item = find_mons(y, x);
+		    tp = THINGPTR(item);
+		    if (save(VS_MAGIC, tp, 0) || on(*tp, ISCLEAR))
+			 msg(nothing);
+		    else
+			 turn_on (*tp, ISHUH);
+		    runto(tp, &hero);
+		}
+	    }
+	when WS_PARALYZE:
+	    if (cursed) {
+		no_command += FREEZETIME;
+		msg("You can't move.");
+	    }
+	    else {
+		y = hero.y;
+		x = hero.x;
+		while (shoot_ok(winat(y, x)))
+		{
+		    y += delta.y;
+		    x += delta.x;
+		}
+		if (isalpha(mvwinch(mw, y, x)))
+		{
+		    item = find_mons(y, x);
+		    tp = THINGPTR(item);
+		    if (save(VS_WAND, tp, 0) || on(*tp, NOPARALYZE))
+			msg(nothing);
+		    else {
+			tp->t_no_move = FREEZETIME;
+		    }
+		    runto(tp, &hero);
+		}
+	    }
+	    when WS_FEAR:
+		y = hero.y;
+		x = hero.x;
+		while (shoot_ok(winat(y, x)))
+		{
+		    y += delta.y;
+		    x += delta.x;
+		}
+		if (isalpha(mvwinch(mw, y, x)))
+		{
+		    item = find_mons(y, x);
+		    tp = THINGPTR(item);
+		    runto(tp, &hero);
+		    if (save(VS_WAND, tp, 0) || 
+			on(*tp, ISUNDEAD)    || 
+			on(*tp, NOFEAR))
+			    msg(nothing);
+		    else {
+			turn_on(*tp, ISFLEE);
+			turn_on(*tp, WASTURNED);
+
+			/* 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);
+		    }
+		}
+	when WS_MDEG:
+	    y = hero.y;
+	    x = hero.x;
+	    while (shoot_ok(winat(y, x)))
+	    {
+		y += delta.y;
+		x += delta.x;
+	    }
+	    if (isalpha(mvwinch(mw, y, x)))
+	    {
+		item = find_mons(y, x);
+		tp = THINGPTR(item);
+		if (cursed) {
+		     tp->t_stats.s_hpt *= 2;
+		     msg("The %s appears to be stronger now!", 
+			monsters[tp->t_index].m_name);
+		}
+		else if (on(*tp, ISUNIQUE) && save(VS_WAND, tp, 0))
+		     msg (nothing);
+		else {
+		     tp->t_stats.s_hpt /= 2;
+		     msg("The %s appears to be weaker now", 
+			monsters[tp->t_index].m_name);
+		}
+		runto(tp, &hero);
+	        if (tp->t_stats.s_hpt < 1)
+		     killed(item, TRUE, TRUE);
+	    }
+	when WS_DISINTEGRATE:
+	    y = hero.y;
+	    x = hero.x;
+	    while (shoot_ok(winat(y, x))) {
+		y += delta.y;
+		x += delta.x;
+	    }
+	    if (isalpha(mvwinch(mw, y, x))) {
+		item = find_mons(y, x);
+		tp = THINGPTR(item);
+		turn_on (*tp, ISMEAN);
+		runto(tp, &hero);
+		if (cursed) {
+		    register int m1, m2;
+		    coord mp;
+		    struct linked_list *titem;
+		    char ch;
+		    struct thing *th;
+
+		    if (on(*tp, ISUNIQUE)) {
+			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++) {
+			    ch = CCHAR( winat(m2,m1) );
+			    if (shoot_ok(ch) && ch != PLAYER) {
+				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 */
+		    tp = THINGPTR(item);
+		    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);
+			     msg("You have disintegrated the %s", 
+				    monsters[tp->t_index].m_name);
+			}
+			else {
+			    msg("The %s appears wounded",
+				monsters[tp->t_index].m_name);
+			}
+		    }
+		    else {
+			msg("You have disintegrated the %s", 
+				monsters[tp->t_index].m_name);
+			killed (item, FALSE, TRUE);
+		    }
+		}
+	    }
+	when WS_CURING:
+	    ws_know[WS_CURING] = TRUE;
+	    if (cursed) {
+		if (!save(VS_POISON, &player, 0)) {
+		    msg("You feel extremely sick now");
+		    pstats.s_hpt /=2;
+		    if (pstats.s_hpt == 0) 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, 0, roll(HEALTIME,SICKTIME), AFTER);
+		    infest_dam++;
+		}
+		else msg("You fell momentarily sick");
+	    }
+	    else {
+		if (on(player, HASDISEASE)) {
+		    extinguish(cure_disease);
+		    cure_disease();
+		    msg(terse ? "You feel yourself improving."
+			      : "You begin to feel yourself improving again.");
+		}
+		if (on(player, HASINFEST)) {
+		    turn_off(player, HASINFEST);
+		    infest_dam = 0;
+		    msg(terse ? "You feel yourself improving."
+			      : "You begin to feel yourself improving again.");
+		}
+		if (on(player, DOROT)) {
+		    msg("You feel your skin returning to normal.");
+		    turn_off(player, DOROT);
+		}
+		pstats.s_hpt += roll(pstats.s_lvl, blessed ? 6 : 4);
+		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!");
+    }
+    return(TRUE);
+}
+
+