diff srogue/sticks.c @ 36:2128c7dc8a40

Import Super-Rogue 9.0 from the Roguelike Restoration Project (r1490)
author elwin
date Thu, 25 Nov 2010 12:21:41 +0000
parents
children 94a0d9dd5ce1
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/srogue/sticks.c	Thu Nov 25 12:21:41 2010 +0000
@@ -0,0 +1,592 @@
+/*
+ * Functions to deal with the various sticks one
+ * might find while wandering around the dungeon.
+ *
+ * @(#)sticks.c	9.0	(rdk)	 7/17/84
+ *
+ * Super-Rogue
+ * Copyright (C) 1984 Robert D. Kindelberger
+ * 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 <ctype.h>
+#include "rogue.h"
+#include "rogue.ext"
+
+/*
+ * fix_stick:
+ *	Init a stick for the hero
+ */
+fix_stick(cur)
+struct object *cur;
+{
+	struct rod *rd;
+
+	cur->o_type = STICK;
+	cur->o_charges = 4 + rnd(5);
+	strcpy(cur->o_hurldmg, "1d1");
+	rd = &ws_stuff[cur->o_which];
+	cur->o_weight = rd->ws_wght;
+	cur->o_vol = rd->ws_vol;
+	if (strcmp(rd->ws_type, "staff") == 0) {
+		strcpy(cur->o_damage, "2d3");
+		cur->o_charges += rnd(5) + 3;
+	}
+	else {
+		strcpy(cur->o_damage, "1d1");
+	}
+	switch (cur->o_which) {
+		case WS_HIT:
+			if(rnd(100) < 15) {
+				cur->o_hplus = 9;
+				cur->o_dplus = 9;
+				strcpy(cur->o_damage,"3d8");
+			}
+			else {
+				cur->o_hplus = 3;
+				cur->o_dplus = 3;
+				strcpy(cur->o_damage,"1d8");
+			}
+		when WS_LIGHT:
+			cur->o_charges += 7 + rnd(9);
+	}
+}
+
+/*
+ * do_zap:
+ *	Zap a stick at something
+ */
+do_zap(gotdir)
+bool gotdir;
+{
+	reg struct linked_list *item;
+	reg struct object *obj;
+	reg struct thing *tp;
+	reg int y, x, wh;
+	struct room *rp;
+	bool bless, curse;
+	int better = 0;
+
+	if ((item = get_item("zap with", STICK)) == NULL)
+		return;
+	obj = OBJPTR(item);
+	wh = obj->o_which;
+	bless = o_on(obj, ISBLESS);
+	curse = o_on(obj, ISCURSED);
+	if (obj->o_type != STICK) {
+		msg("You can't zap with that!");
+		after = FALSE;
+		return;
+	}
+	if (obj->o_charges == 0) {
+		msg("Nothing happens.");
+		return;
+	}
+	if (!gotdir)
+	do {
+		delta.y = rnd(3) - 1;
+		delta.x = rnd(3) - 1;
+	} while (delta.y == 0 && delta.x == 0);
+	rp = player.t_room;
+	if (bless)
+		better = 3;
+	else if (curse)
+		better = -3;
+	switch (wh) {
+	case WS_SAPLIFE:
+		if (!bless) {
+			if (him->s_hpt > 1)
+			him->s_hpt /= 2;	/* zap half his hit points */
+		}
+	when WS_CURE:
+		if (!curse) {
+			ws_know[WS_CURE] = TRUE;
+			heal_self(6, FALSE);
+			unconfuse(FALSE);
+			notslow(FALSE);
+			sight(FALSE);
+		}
+	when WS_PYRO:
+		if (!bless) {
+			msg("The rod explodes !!!");
+			chg_hpt(-roll(6,6), FALSE, K_ROD);
+			ws_know[WS_PYRO] = TRUE;
+			del_pack(item);		/* throw it away */
+		}
+	when WS_HUNGER:
+		if (!bless) {
+			struct linked_list *ip;
+			struct object *lb;
+
+			food_left /= 3;
+			if ((ip = pack) != NULL) {
+				lb = OBJPTR(ip);
+				if (lb->o_type == FOOD) {
+					if ((lb->o_count -= roll(1,4)) < 1)
+						del_pack(ip);
+				}
+			}
+		}
+	when WS_PARZ:
+	case WS_MREG:
+	case WS_MDEG:
+	case WS_ANNIH: {
+		struct linked_list *mitem;
+		struct thing *it;
+		reg int i,j;
+
+		for (i = hero.y - 3; i <= hero.y + 3; i++) {
+			for (j = hero.x - 3; j <= hero.x + 3; j++) {
+				if (!cordok(i, j))
+					continue;
+				if (isalpha(mvwinch(mw,i,j))) {
+					mitem = find_mons(i, j);
+					if (mitem == NULL)
+						continue;
+					it = THINGPTR(mitem);
+					switch(wh) {
+						case WS_ANNIH:
+							if (!curse)
+								killed(mitem,FALSE);
+						when WS_MREG:
+							if (!bless)
+								it->t_stats.s_hpt *= 2;
+						when WS_MDEG:
+							if (!curse) {
+								it->t_stats.s_hpt /= 2;
+								if (it->t_stats.s_hpt < 2)
+									killed(mitem,FALSE);
+							}
+						when WS_PARZ:
+							if (!curse) {
+								it->t_flags |= ISPARA;
+								it->t_flags &= ~ISRUN;
+							}
+						}
+					}
+				}
+			}
+		}
+	when WS_LIGHT:
+		if (!curse) {
+			ws_know[WS_LIGHT] = TRUE;
+			if (rp == NULL)
+				msg("The corridor glows and then fades.");
+			else {
+				msg("The room is lit.");
+				rp->r_flags &= ~ISDARK;
+				light(&hero);
+				mvwaddch(cw, hero.y, hero.x, PLAYER);
+			}
+		}
+	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)
+		 */
+		if (him->s_hpt < 2) {
+			msg("You are too weak to use it.");
+			return;
+		}
+		else if (!curse) {
+			if (rp == NULL)
+				drain(hero.y-1, hero.y+1, hero.x-1, hero.x+1);
+			else
+				drain(rp->r_pos.y, rp->r_pos.y+rp->r_max.y,
+				  rp->r_pos.x, rp->r_pos.x+rp->r_max.x);
+		}
+	when WS_POLYM:
+	case WS_TELAWAY:
+	case WS_TELTO:
+	case WS_CANCEL:
+	case WS_MINVIS:
+	{
+		reg char monster, oldch;
+
+		y = hero.y;
+		x = hero.x;
+		do {
+			y += delta.y;
+			x += delta.x;
+		} while (step_ok(winat(y, x)));
+		if (isalpha(monster = mvwinch(mw, y, x))) {
+			int omonst;
+
+			if (wh != WS_MINVIS)
+				unhold(monster);
+			item = find_mons(y, x);
+			if (item == NULL)
+				break;
+			tp = THINGPTR(item);
+			omonst = tp->t_indx;
+			if (wh == WS_POLYM && !curse) {
+				detach(mlist, item);
+				discard(item);
+				oldch = tp->t_oldch;
+				delta.y = y;
+				delta.x = x;
+				monster = rnd_mon(FALSE, TRUE);
+				item = new_monster(monster, &delta, FALSE);
+				if (!(tp->t_flags & ISRUN))
+					runto(&delta, &hero);
+				if (isalpha(mvwinch(cw, y, x)))
+					mvwaddch(cw, y, x, monsters[monster].m_show);
+				tp->t_oldch = oldch;
+				ws_know[WS_POLYM] |= (monster != omonst);
+			}
+			else if (wh == WS_MINVIS && !bless) {
+				tp->t_flags |= ISINVIS;
+				mvwaddch(cw,y,x,tp->t_oldch);	/* hide em */
+				runto(&tp->t_pos, &hero);
+			}
+			else if (wh == WS_CANCEL && !curse) {
+				tp->t_flags |= ISCANC;
+				tp->t_flags &= ~ISINVIS;
+			}
+			else {
+				if (wh == WS_TELAWAY) {
+					if (curse)
+						break;
+					tp->t_pos = *rnd_pos(&rooms[rnd_room()]);
+				}
+				else {					/* WS_TELTO */
+					if (bless)
+						break;
+					tp->t_pos.y = hero.y + delta.y;
+					tp->t_pos.x = hero.x + delta.x;
+				}
+				if (isalpha(mvwinch(cw, y, x)))
+					mvwaddch(cw, y, x, tp->t_oldch);
+				tp->t_dest = &hero;
+				tp->t_flags |= ISRUN;
+				mvwaddch(mw, y, x, ' ');
+				mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, monster);
+				tp->t_oldch = mvwinch(cw,tp->t_pos.y,tp->t_pos.x);
+			}
+		}
+	}
+	when WS_MISSILE:
+	{
+		struct coord *whe;
+		static struct object bolt = {
+			{0, 0}, "", "6d6", "", '*', 0, 0, 1000, 0, 0, 0, 0, 0, 0,
+		};
+
+		if (curse)
+			strcpy(bolt.o_hurldmg,"3d3");
+		else if (bless)
+			strcpy(bolt.o_hurldmg,"9d9");
+		ws_know[WS_MISSILE] = TRUE;
+		do_motion(&bolt, delta.y, delta.x);
+		whe = &bolt.o_pos;
+		if (isalpha(mvwinch(mw, whe->y, whe->x))) {
+			struct linked_list *it;
+
+			runto(whe, &hero);
+			it = find_mons(whe->y, whe->x);
+			if (it != NULL) {
+				if (!save_throw(VS_MAGIC + better, THINGPTR(it))) {
+					hit_monster(whe, &bolt);
+					break;
+				}
+			}
+		}
+		msg("Missle vanishes.");
+	}
+	when WS_NOP:
+		msg("Your %s flickers momentarily and then fades",
+			ws_stuff[wh].ws_type);
+	when WS_HIT: {
+		char ch;
+
+		delta.y += hero.y;
+		delta.x += hero.x;
+		ch = winat(delta.y, delta.x);
+		if (curse) {				/* decrease for cursed */
+			strcpy(obj->o_damage,"1d1");
+			obj->o_hplus = obj->o_dplus = 0;
+		}
+		else if (bless) {			/* increase for blessed */
+			strcpy(obj->o_damage,"5d8");
+			obj->o_hplus = obj->o_dplus = 12;
+		}
+		if (isalpha(ch))
+			fight(&delta, obj, FALSE);
+	}
+	when WS_HASTE_M:
+	case WS_CONFMON:
+	case WS_SLOW_M:
+	case WS_MOREMON: {
+		reg int m1,m2;
+		struct coord mp;
+		struct linked_list *titem;
+
+		y = hero.y;
+		x = hero.x;
+		do {
+			y += delta.y;
+			x += delta.x;
+		} while (step_ok(winat(y, x)));
+		if (isalpha(mvwinch(mw, y, x))) {
+			item = find_mons(y, x);
+			if (item == NULL)
+				break;
+			tp = THINGPTR(item);
+			if (wh == WS_HASTE_M && !bless) {			/* haste it */
+				if (on(*tp, ISSLOW))
+					tp->t_flags &= ~ISSLOW;
+				else
+					tp->t_flags |= ISHASTE;
+			}
+			else if (wh == WS_CONFMON && !curse) {		/* confuse it */
+				tp->t_flags |= ISHUH;
+				if (pl_on(ISHELD) && tp->t_type == 'd')
+					player.t_flags &= ~ISHELD;
+			}
+			else if (wh == WS_SLOW_M && !curse) {		/* slow it */
+				if (on(*tp, ISHASTE))
+					tp->t_flags &= ~ISHASTE;
+				else
+					tp->t_flags |= ISSLOW;
+				tp->t_turn = TRUE;
+			}
+			else if (!bless) {	/* WS_MOREMON: multiply it */
+				char ch;
+				struct thing *th;
+
+				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 (hero.x == m1 && hero.y == m2)
+							continue;
+						ch = winat(m2,m1);
+						if (step_ok(ch)) {
+							mp.x = m1;			/* create it */
+							mp.y = m2;
+							titem = new_monster(tp->t_indx, &mp, FALSE);
+							th = THINGPTR(titem);
+							th->t_flags |= ISMEAN;
+							runto(&mp, &hero);
+						}
+					}
+				}
+			}
+			delta.y = y;
+			delta.x = x;
+			runto(&delta, &hero);
+		}
+	}
+	when WS_ELECT:
+	case WS_FIRE:
+	case WS_COLD: {
+		reg char dirch, ch, *name;
+		reg bool bounced, used;
+		int boingcnt, boltlen;
+		struct coord pos;
+		struct coord spotpos[BOLT_LENGTH * 2];
+		static struct object bolt =	{
+			{0, 0}, "", "6d6", "", '*', 0, 0, 1000, 0, 0, 0, 0, 0, 0,
+		};
+
+		boltlen = BOLT_LENGTH;
+		if (curse) {
+			strcpy(bolt.o_hurldmg,"3d3");
+			boltlen -= 3;
+		}
+		else if (bless) {
+			strcpy(bolt.o_hurldmg,"9d9");
+			boltlen += 3;
+		}
+		switch (delta.y + delta.x) {
+			case 0: dirch = '/';
+			when 1: case -1: dirch = (delta.y == 0 ? '-' : '|');
+			when 2: case -2: dirch = '\\';
+		}
+		pos = hero;
+		bounced = FALSE;
+		boingcnt = 0;
+		used = FALSE;
+		if (wh == WS_ELECT)
+			name = "bolt";
+		else if (wh == WS_FIRE)
+			name = "flame";
+		else
+			name = "ice";
+		for (y = 0; y < boltlen && !used; y++) {
+			ch = winat(pos.y, pos.x);
+			spotpos[y] = pos;
+			switch (ch) {
+				case SECRETDOOR:
+				case '|':
+				case '-':
+				case ' ':
+					bounced = TRUE;
+					if (++boingcnt > 6) 
+						used = TRUE;	/* only so many bounces */
+					delta.y = -delta.y;
+					delta.x = -delta.x;
+					y--;
+					msg("The bolt bounces");
+					break;
+				default:
+					if (isalpha(ch)) {
+						struct linked_list *it;
+
+						it = find_mons(pos.y, pos.x);
+						runto(&pos, &hero);
+						if (it != NULL) {
+							if (!save_throw(VS_MAGIC+better,THINGPTR(it))) {
+								bolt.o_pos = pos;
+								hit_monster(&pos, &bolt);
+								used = TRUE;
+							}
+							else if(ch != 'M' || show(pos.y,pos.x)=='M') {
+								msg("%s misses", name);
+							}
+						}
+					}
+					else if(bounced && pos.y==hero.y && pos.x==hero.x) {
+						bounced = FALSE;
+						if (!save(VS_MAGIC + better)) {
+							msg("The %s hits you.", name);
+							chg_hpt(-roll(6, 6),FALSE,K_BOLT);
+							used = TRUE;
+						}
+						else
+							msg("The %s whizzes by you.", name);
+					}
+					mvwaddch(cw, pos.y, pos.x, dirch);
+					draw(cw);
+				}
+				pos.y += delta.y;
+				pos.x += delta.x;
+			}
+			for (x = 0; x < y; x++)
+				mvwaddch(cw, spotpos[x].y, spotpos[x].x,
+				  show(spotpos[x].y, spotpos[x].x));
+			ws_know[wh] = TRUE;
+		}
+	when WS_ANTIM: {
+		reg int m1, m2, x1, y1;
+		struct linked_list *ll;
+		struct thing *lt;
+		int ch, radius;
+
+		y1 = hero.y;
+		x1 = hero.x;
+		do {
+			y1 += delta.y;
+			x1 += delta.x;
+			ch = winat(y1, x1);
+		} while (ch == PASSAGE || ch == FLOOR);
+		if (curse)
+			radius = 2;
+		else if (bless)
+			radius = 0;
+		else
+			radius = 1;
+		for (m1 = x1 - radius; m1 <= x1 + radius; m1++) {
+			for (m2 = y1 - radius; m2 <= y1 + radius; m2++) {
+				if (!cordok(m2, m1))
+					continue;
+				ch = winat(m2, m1);
+				if (m1 == hero.x && m2 == hero.y)
+					continue;
+				if (ch == ' ')
+					continue;
+				ll = find_obj(m2,m1);
+				if (ll != NULL) {
+					detach(lvl_obj,ll);
+					discard(ll);
+				}
+				ll = find_mons(m2,m1);
+				if (ll != NULL) {
+					lt = THINGPTR(ll);
+					him->s_exp += lt->t_stats.s_exp;
+					unhold(lt->t_type);
+					/*
+					 * throw away anything that the monster
+					 * was carrying in its pack
+					 */
+					free_list(lt->t_pack);
+					detach(mlist,ll);
+					discard(ll);
+					mvwaddch(mw,m2,m1,' ');
+				}
+				mvaddch(m2,m1,' ');
+				mvwaddch(cw,m2,m1,' ');
+			}
+		}
+		touchwin(cw);
+		touchwin(mw);
+		check_level();
+	}
+	otherwise:
+		msg("What a bizarre schtick!");
+	}
+	obj->o_charges--;
+}
+
+/*
+ * drain:
+ *	Do drain hit points from player stick
+ */
+drain(ymin, ymax, xmin, xmax)
+int ymin, ymax, xmin, xmax;
+{
+	reg int i, j, cnt;
+	reg struct thing *ick;
+	reg struct linked_list *item;
+
+	/*
+	 * First count how many things we need to spread the hit points among
+	 */
+	cnt = 0;
+	for (i = ymin; i <= ymax; i++)
+		for (j = xmin; j <= xmax; j++)
+			if (isalpha(mvwinch(mw, i, j)))
+				cnt++;
+	if (cnt == 0) {
+		msg("You have a tingling feeling.");
+		return;
+	}
+	cnt = him->s_hpt / cnt;
+	him->s_hpt /= 2;
+	/*
+	 * Now zot all of the monsters
+	 */
+	for (i = ymin; i <= ymax; i++) {
+		for (j = xmin; j <= xmax; j++) {
+			if(isalpha(mvwinch(mw, i, j))) {
+				item = find_mons(i, j);
+				if (item == NULL)
+					continue;
+				ick = THINGPTR(item);
+				if ((ick->t_stats.s_hpt -= cnt) < 1)
+					killed(item,cansee(i,j) && !(ick->t_flags & ISINVIS));
+			}
+		}
+	}
+}
+
+/*
+ * charge_str:
+ *	Return number of charges left in a stick
+ */
+char *
+charge_str(obj)
+struct object *obj;
+{
+	static char buf[20];
+
+	buf[0] = '\0';
+	if (o_on(obj,ISKNOW) || o_on(obj,ISPOST))
+		sprintf(buf, " [%d]", obj->o_charges);
+	return buf;
+}