diff rogue4/things.c @ 12:9535a08ddc39

Import Rogue 5.2 from the Roguelike Restoration Project (r1490)
author edwarj4
date Sat, 24 Oct 2009 16:52:52 +0000
parents
children 1b73a8641b37
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rogue4/things.c	Sat Oct 24 16:52:52 2009 +0000
@@ -0,0 +1,616 @@
+/*
+ * Contains functions for dealing with things like potions, scrolls,
+ * and other items.
+ *
+ * @(#)things.c	4.26 (Berkeley) 5/18/82
+ *
+ * Rogue: Exploring the Dungeons of Doom
+ * Copyright (C) 1980, 1981, 1982 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"
+
+bool got_genocide = FALSE;
+
+/*
+ * inv_name:
+ *	Return the name of something as it would appear in an
+ *	inventory.
+ */
+char *
+inv_name(obj, drop)
+register THING *obj;
+register bool drop;
+{
+    register char *pb;
+
+    pb = prbuf;
+    switch (obj->o_type)
+    {
+	case SCROLL:
+	    if (obj->o_count == 1)
+	    {
+		strcpy(pb, "A scroll ");
+		pb = &prbuf[9];
+	    }
+	    else
+	    {
+		sprintf(pb, "%d scrolls ", obj->o_count);
+		pb = &prbuf[strlen(prbuf)];
+	    }
+	    if (s_know[obj->o_which])
+		sprintf(pb, "of %s", s_magic[obj->o_which].mi_name);
+	    else if (s_guess[obj->o_which])
+		sprintf(pb, "called %s", s_guess[obj->o_which]);
+	    else
+		sprintf(pb, "titled '%s'", s_names[obj->o_which]);
+        when POTION:
+	    if (obj->o_count == 1)
+	    {
+		strcpy(pb, "A potion ");
+		pb = &prbuf[9];
+	    }
+	    else
+	    {
+		sprintf(pb, "%d potions ", obj->o_count);
+		pb = &pb[strlen(prbuf)];
+	    }
+	    if (p_know[obj->o_which])
+		sprintf(pb, "of %s(%s)", p_magic[obj->o_which].mi_name,
+		    p_colors[obj->o_which]);
+	    else if (p_guess[obj->o_which])
+		sprintf(pb, "called %s(%s)", p_guess[obj->o_which],
+		    p_colors[obj->o_which]);
+	    else if (obj->o_count == 1)
+		sprintf(prbuf, "A%s %s potion", vowelstr(p_colors[obj->o_which]),
+		    p_colors[obj->o_which]);
+	    else
+		sprintf(prbuf, "%d %s potions", obj->o_count,
+		    p_colors[obj->o_which]);
+	when FOOD:
+	    if (obj->o_which == 1)
+		if (obj->o_count == 1)
+		    sprintf(pb, "A%s %s", vowelstr(fruit), fruit);
+		else
+		    sprintf(pb, "%d %ss", obj->o_count, fruit);
+	    else
+		if (obj->o_count == 1)
+		    strcpy(pb, "Some food");
+		else
+		    sprintf(pb, "%d rations of food", obj->o_count);
+	when WEAPON:
+	    if (obj->o_count > 1)
+		sprintf(pb, "%d ", obj->o_count);
+	    else
+		sprintf(pb, "A%s ", vowelstr(w_names[obj->o_which]));
+	    pb = &prbuf[strlen(prbuf)];
+	    if (obj->o_flags & ISKNOW)
+		sprintf(pb, "%s %s", num(obj->o_hplus, obj->o_dplus, WEAPON),
+		    w_names[obj->o_which]);
+	    else
+		sprintf(pb, "%s", w_names[obj->o_which]);
+	    if (obj->o_count > 1)
+		strcat(pb, "s");
+	when ARMOR:
+	    if (obj->o_flags & ISKNOW)
+	    {
+		sprintf(pb, "%s %s [",
+		    num(a_class[obj->o_which] - obj->o_ac, 0, ARMOR),
+		    a_names[obj->o_which]);
+		if (!terse)
+		    strcat(pb, "armor class ");
+		pb = &prbuf[strlen(prbuf)];
+		sprintf(pb, "%d]", obj->o_ac);
+	    }
+	    else
+		sprintf(pb, "%s", a_names[obj->o_which]);
+	when AMULET:
+	    strcpy(pb, "The Amulet of Yendor");
+	when STICK:
+	    sprintf(pb, "A%s %s ", vowelstr(ws_type[obj->o_which]),
+		ws_type[obj->o_which]);
+	    pb = &prbuf[strlen(prbuf)];
+	    if (ws_know[obj->o_which])
+		sprintf(pb, "of %s%s(%s)", ws_magic[obj->o_which].mi_name,
+		    charge_str(obj), ws_made[obj->o_which]);
+	    else if (ws_guess[obj->o_which])
+		sprintf(pb, "called %s(%s)", ws_guess[obj->o_which],
+		    ws_made[obj->o_which]);
+	    else
+		sprintf(pb = &prbuf[1], "%s %s %s",
+		    vowelstr(ws_made[obj->o_which]), ws_made[obj->o_which],
+		    ws_type[obj->o_which]);
+        when RING:
+	    if (r_know[obj->o_which])
+		sprintf(pb, "A%s ring of %s(%s)", ring_num(obj),
+		    r_magic[obj->o_which].mi_name, r_stones[obj->o_which]);
+	    else if (r_guess[obj->o_which])
+		sprintf(pb, "A ring called %s(%s)",
+		    r_guess[obj->o_which], r_stones[obj->o_which]);
+	    else
+		sprintf(pb, "A%s %s ring", vowelstr(r_stones[obj->o_which]),
+		    r_stones[obj->o_which]);
+	when GOLD:
+		sprintf(pb, "%d pieces of gold", obj->o_goldval);
+#ifdef WIZARD
+	otherwise:
+	    debug("Picked up something funny %s", unctrol(obj->o_type));
+	    sprintf(pb, "Something bizarre %s", unctrol(obj->o_type));
+#endif
+    }
+    if (obj == cur_armor)
+	strcat(pb, " (being worn)");
+    if (obj == cur_weapon)
+	strcat(pb, " (weapon in hand)");
+    if (obj == cur_ring[LEFT])
+	strcat(pb, " (on left hand)");
+    else if (obj == cur_ring[RIGHT])
+	strcat(pb, " (on right hand)");
+    if (drop && isupper(prbuf[0]))
+	prbuf[0] = tolower(prbuf[0]);
+    else if (!drop && islower(*prbuf))
+	*prbuf = toupper(*prbuf);
+    return prbuf;
+}
+
+/*
+ * drop:
+ *	Put something down
+ */
+drop()
+{
+    register char ch;
+    register THING *nobj, *op;
+
+    ch = chat(hero.y, hero.x);
+    if (ch != FLOOR && ch != PASSAGE)
+    {
+	after = FALSE;
+	msg("there is something there already");
+	return;
+    }
+    if ((op = get_item("drop", 0)) == NULL)
+	return;
+    if (!dropcheck(op))
+	return;
+    /*
+     * Take it out of the pack
+     */
+    if (op->o_count >= 2 && op->o_type != WEAPON)
+    {
+	op->o_count--;
+	nobj = new_item();
+	*nobj = *op;
+	nobj->o_count = 1;
+	op = nobj;
+	if (op->o_group != 0)
+		inpack++;
+    }
+    else
+	detach(pack, op);
+    inpack--;
+    /*
+     * Link it into the level object list
+     */
+    attach(lvl_obj, op);
+    chat(hero.y, hero.x) = op->o_type;
+    flat(hero.y, hero.x) |= F_DROPPED;
+    op->o_pos = hero;
+    if (op->o_type == AMULET)
+	amulet = FALSE;
+    msg("dropped %s", inv_name(op, TRUE));
+}
+
+/*
+ * dropcheck:
+ *	Do special checks for dropping or unweilding|unwearing|unringing
+ */
+dropcheck(op)
+register THING *op;
+{
+    if (op == NULL)
+	return TRUE;
+    if (op != cur_armor && op != cur_weapon
+	&& op != cur_ring[LEFT] && op != cur_ring[RIGHT])
+	    return TRUE;
+    if (op->o_flags & ISCURSED)
+    {
+	msg("you can't.  It appears to be cursed");
+	return FALSE;
+    }
+    if (op == cur_weapon)
+	cur_weapon = NULL;
+    else if (op == cur_armor)
+    {
+	waste_time();
+	cur_armor = NULL;
+    }
+    else
+    {
+	cur_ring[op == cur_ring[LEFT] ? LEFT : RIGHT] = NULL;
+	switch (op->o_which)
+	{
+	    case R_ADDSTR:
+		chg_str(-op->o_ac);
+		break;
+	    case R_SEEINVIS:
+		unsee();
+		extinguish(unsee);
+		break;
+	}
+    }
+    return TRUE;
+}
+
+/*
+ * new_thing:
+ *	Return a new thing
+ */
+THING *
+new_thing()
+{
+    register THING *cur;
+    register int j, k;
+
+    cur = new_item();
+    cur->o_hplus = cur->o_dplus = 0;
+    strcpy(cur->o_damage,"0d0");
+    strcpy(cur->o_hurldmg,"0d0");
+    cur->o_ac = 11;
+    cur->o_count = 1;
+    cur->o_group = 0;
+    cur->o_flags = 0;
+    /*
+     * Decide what kind of object it will be
+     * If we haven't had food for a while, let it be food.
+     */
+    switch (no_food > 3 ? 2 : pick_one(things, NUMTHINGS))
+    {
+	case 0:
+	    cur->o_type = POTION;
+	    cur->o_which = pick_one(p_magic, MAXPOTIONS);
+	when 1:
+	    cur->o_type = SCROLL;
+	    cur->o_which = pick_one(s_magic, MAXSCROLLS);
+	    /*
+	     * Only one genocide scroll allowed per game, so if it's
+	     * the second one, then turn it into a identify scroll
+	     */
+	    if (cur->o_which == S_GENOCIDE)
+		if (got_genocide)
+		    cur->o_which = S_IDENT;
+		else
+		    got_genocide = TRUE;
+	when 2:
+	    no_food = 0;
+	    cur->o_type = FOOD;
+	    if (rnd(10) != 0)
+		cur->o_which = 0;
+	    else
+		cur->o_which = 1;
+	when 3:
+	    cur->o_type = WEAPON;
+	    cur->o_which = rnd(MAXWEAPONS);
+	    init_weapon(cur, cur->o_which);
+	    if ((k = rnd(100)) < 10)
+	    {
+		cur->o_flags |= ISCURSED;
+		cur->o_hplus -= rnd(3) + 1;
+	    }
+	    else if (k < 15)
+		cur->o_hplus += rnd(3) + 1;
+	when 4:
+	    cur->o_type = ARMOR;
+	    for (j = 0, k = rnd(100); j < MAXARMORS; j++)
+		if (k < a_chances[j])
+		    break;
+#ifdef WIZARD
+	    if (j == MAXARMORS)
+	    {
+		debug("Picked a bad armor %d", k);
+		j = 0;
+	    }
+#endif
+	    cur->o_which = j;
+	    cur->o_ac = a_class[j];
+	    if ((k = rnd(100)) < 20)
+	    {
+		cur->o_flags |= ISCURSED;
+		cur->o_ac += rnd(3) + 1;
+	    }
+	    else if (k < 28)
+		cur->o_ac -= rnd(3) + 1;
+	when 5:
+	    cur->o_type = RING;
+	    cur->o_which = pick_one(r_magic, MAXRINGS);
+	    switch (cur->o_which)
+	    {
+		case R_ADDSTR:
+		case R_PROTECT:
+		case R_ADDHIT:
+		case R_ADDDAM:
+		    if ((cur->o_ac = rnd(3)) == 0)
+		    {
+			cur->o_ac = -1;
+			cur->o_flags |= ISCURSED;
+		    }
+		when R_AGGR:
+		case R_TELEPORT:
+		    cur->o_flags |= ISCURSED;
+	    }
+	when 6:
+	    cur->o_type = STICK;
+	    cur->o_which = pick_one(ws_magic, MAXSTICKS);
+	    fix_stick(cur);
+#ifdef WIZARD
+	otherwise:
+	    debug("Picked a bad kind of object");
+	    wait_for(' ');
+#endif
+    }
+    return cur;
+}
+
+/*
+ * pick_one:
+ *	Pick an item out of a list of nitems possible magic items
+ */
+pick_one(magic, nitems)
+register struct magic_item *magic;
+int nitems;
+{
+    register struct magic_item *end;
+    register int i;
+    register struct magic_item *start;
+
+    start = magic;
+    for (end = &magic[nitems], i = rnd(100); magic < end; magic++)
+	if (i < magic->mi_prob)
+	    break;
+    if (magic == end)
+    {
+#ifdef WIZARD
+	if (wizard)
+	{
+	    msg("bad pick_one: %d from %d items", i, nitems);
+	    for (magic = start; magic < end; magic++)
+		msg("%s: %d%%", magic->mi_name, magic->mi_prob);
+	}
+#endif
+	magic = start;
+    }
+    return magic - start;
+}
+
+/*
+ * discovered:
+ *	list what the player has discovered in this game of a certain type
+ */
+static int line_cnt = 0;
+
+static bool newpage = FALSE;
+
+static char *lastfmt, *lastarg;
+
+discovered()
+{
+    register char ch;
+    register bool disc_list;
+
+    do {
+	disc_list = FALSE;
+	if (!terse)
+	    addmsg("for ");
+	addmsg("what type");
+	if (!terse)
+	    addmsg(" of object do you want a list");
+	msg("? (* for all)");
+	ch = readchar();
+	switch (ch)
+	{
+	    case ESCAPE:
+		msg("");
+		return;
+	    case POTION:
+	    case SCROLL:
+	    case RING:
+	    case STICK:
+	    case '*':
+		disc_list = TRUE;
+		break;
+	    default:
+		if (terse)
+		    msg("Not a type");
+		else
+		    msg("Please type one of %c%c%c%c (ESCAPE to quit)", POTION, SCROLL, RING, STICK);
+	}
+    } while (!disc_list);
+    if (ch == '*')
+    {
+	print_disc(POTION);
+	add_line("");
+	print_disc(SCROLL);
+	add_line("");
+	print_disc(RING);
+	add_line("");
+	print_disc(STICK);
+	end_line();
+    }
+    else
+    {
+	print_disc(ch);
+	end_line();
+    }
+}
+
+/*
+ * print_disc:
+ *	Print what we've discovered of type 'type'
+ */
+
+#define MAX(a,b,c,d)	(a > b ? (a > c ? (a > d ? a : d) : (c > d ? c : d)) : (b > c ? (b > d ? b : d) : (c > d ? c : d)))
+
+print_disc(type)
+char type;
+{
+    register bool *know = NULL;
+    register char **guess = NULL;
+    register int i, maxnum = 0, num_found;
+    static THING obj;
+    static short order[MAX(MAXSCROLLS, MAXPOTIONS, MAXRINGS, MAXSTICKS)];
+
+    switch (type)
+    {
+	case SCROLL:
+	    maxnum = MAXSCROLLS;
+	    know = s_know;
+	    guess = s_guess;
+	    break;
+	case POTION:
+	    maxnum = MAXPOTIONS;
+	    know = p_know;
+	    guess = p_guess;
+	    break;
+	case RING:
+	    maxnum = MAXRINGS;
+	    know = r_know;
+	    guess = r_guess;
+	    break;
+	case STICK:
+	    maxnum = MAXSTICKS;
+	    know = ws_know;
+	    guess = ws_guess;
+	    break;
+    }
+    set_order(order, maxnum);
+    obj.o_count = 1;
+    obj.o_flags = 0;
+    num_found = 0;
+    for (i = 0; i < maxnum; i++)
+	if (know[order[i]] || guess[order[i]])
+	{
+	    obj.o_type = type;
+	    obj.o_which = order[i];
+	    add_line("%s", inv_name(&obj, FALSE));
+	    num_found++;
+	}
+    if (num_found == 0)
+	add_line(nothing(type));
+}
+
+/*
+ * set_order:
+ *	Set up order for list
+ */
+set_order(order, numthings)
+short *order;
+int numthings;
+{
+    register int i, r, t;
+
+    for (i = 0; i< numthings; i++)
+	order[i] = i;
+
+    for (i = numthings; i > 0; i--)
+    {
+	r = rnd(i);
+	t = order[i - 1];
+	order[i - 1] = order[r];
+	order[r] = t;
+    }
+}
+
+/*
+ * add_line:
+ *	Add a line to the list of discoveries
+ */
+/* VARARGS1 */
+add_line(fmt, arg)
+char *fmt, *arg;
+{
+    if (line_cnt == 0)
+    {
+	    wclear(hw);
+	    if (slow_invent)
+		mpos = 0;
+    }
+    if (slow_invent)
+    {
+	if (*fmt != '\0')
+	    msg(fmt, arg);
+	line_cnt++;
+    }
+    else
+    {
+	if (line_cnt >= LINES - 1 || fmt == NULL)
+	{
+	    mvwaddstr(hw, LINES - 1, 0, "--Press space to continue--");
+	    wrefresh(hw);
+	    w_wait_for(hw,' ');
+	    clearok(curscr, TRUE);
+	    wclear(hw);
+            touchwin(stdscr);
+	    newpage = TRUE;
+	    line_cnt = 0;
+	}
+	if (fmt != NULL && !(line_cnt == 0 && *fmt == '\0'))
+	{
+	    mvwprintw(hw, line_cnt++, 0, fmt, arg);
+	    lastfmt = fmt;
+	    lastarg = arg;
+	}
+    }
+}
+
+/*
+ * end_line:
+ *	End the list of lines
+ */
+end_line()
+{
+    if (!slow_invent)
+	if (line_cnt == 1 && !newpage)
+	{
+	    mpos = 0;
+	    msg(lastfmt, lastarg);
+	}
+	else
+	    add_line(NULL);
+    line_cnt = 0;
+    newpage = FALSE;
+}
+
+/*
+ * nothing:
+ *	Set up prbuf so that message for "nothing found" is there
+ */
+char *
+nothing(type)
+register char type;
+{
+    register char *sp, *tystr = NULL;
+
+    if (terse)
+	sprintf(prbuf, "Nothing");
+    else
+	sprintf(prbuf, "Haven't discovered anything");
+    if (type != '*')
+    {
+	sp = &prbuf[strlen(prbuf)];
+	switch (type)
+	{
+	    case POTION: tystr = "potion";
+	    when SCROLL: tystr = "scroll";
+	    when RING: tystr = "ring";
+	    when STICK: tystr = "stick";
+	}
+	sprintf(sp, " about any %ss", tystr);
+    }
+    return prbuf;
+}