diff rogue5/things.c @ 33:f502bf60e6e4

Import Rogue 5.4 from the Roguelike Restoration Project (r1490)
author elwin
date Mon, 24 May 2010 20:10:59 +0000
parents
children ded75a57405c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rogue5/things.c	Mon May 24 20:10:59 2010 +0000
@@ -0,0 +1,716 @@
+/*
+ * Contains functions for dealing with things like potions, scrolls,
+ * and other items.
+ *
+ * @(#)things.c	4.53 (Berkeley) 02/05/99
+ *
+ * Rogue: Exploring the Dungeons of Doom
+ * Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
+ * All rights reserved.
+ *
+ * See the file LICENSE.TXT for full copyright and licensing information.
+ */
+
+#include <stdlib.h>
+#include <curses.h>
+#include <string.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+ * inv_name:
+ *	Return the name of something as it would appear in an
+ *	inventory.
+ */
+char *
+inv_name(const THING *obj, int drop)
+{
+    char *pb;
+    struct obj_info *op;
+    const char *sp;
+    int which;
+
+    pb = prbuf;
+    which = obj->o_which;
+    switch (obj->o_type)
+    {
+        case POTION:
+	    nameit(obj, "potion", p_colors[which], &pot_info[which], nullstr);
+	when RING:
+	    nameit(obj, "ring", r_stones[which], &ring_info[which], ring_num);
+	when STICK:
+	    nameit(obj, ws_type[which], ws_made[which], &ws_info[which], charge_str);
+	when 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)];
+	    }
+	    op = &scr_info[which];
+	    if (op->oi_know)
+		sprintf(pb, "of %s", op->oi_name);
+	    else if (op->oi_guess)
+		sprintf(pb, "called %s", op->oi_guess);
+	    else
+		sprintf(pb, "titled '%s'", s_names[which]);
+	when FOOD:
+	    if (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:
+	    sp = weap_info[which].oi_name;
+	    if (obj->o_count > 1)
+		sprintf(pb, "%d ", obj->o_count);
+	    else
+		sprintf(pb, "A%s ", vowelstr(sp));
+	    pb = &prbuf[strlen(prbuf)];
+	    if (obj->o_flags & ISKNOW)
+		sprintf(pb, "%s %s", num(obj->o_hplus,obj->o_dplus,WEAPON), sp);
+	    else
+		sprintf(pb, "%s", sp);
+	    if (obj->o_count > 1)
+		strcat(pb, "s");
+	    if (obj->o_label != NULL)
+	    {
+		pb = &prbuf[strlen(prbuf)];
+		sprintf(pb, " called %s", obj->o_label);
+	    }
+	when ARMOR:
+	    sp = arm_info[which].oi_name;
+	    if (obj->o_flags & ISKNOW)
+	    {
+		sprintf(pb, "%s %s [",
+		    num(a_class[which] - obj->o_arm, 0, ARMOR), sp);
+		if (!terse)
+		    strcat(pb, "protection ");
+		pb = &prbuf[strlen(prbuf)];
+		sprintf(pb, "%d]", 10 - obj->o_arm);
+	    }
+	    else
+		sprintf(pb, "%s", sp);
+	    if (obj->o_label != NULL)
+	    {
+		pb = &prbuf[strlen(prbuf)];
+		sprintf(pb, " called %s", obj->o_label);
+	    }
+	when AMULET:
+	    strcpy(pb, "The Amulet of Yendor");
+	when GOLD:
+	    sprintf(prbuf, "%d Gold pieces", obj->o_goldval);
+#ifdef MASTER
+	otherwise:
+	    debug("Picked up something funny %s", unctrl(obj->o_type));
+	    sprintf(pb, "Something bizarre %s", unctrl(obj->o_type));
+#endif
+    }
+    if (inv_describe)
+    {
+	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((int)prbuf[0]))
+	prbuf[0] = (char) tolower(prbuf[0]);
+    else if (!drop && islower((int)*prbuf))
+	*prbuf = (char) toupper(*prbuf);
+    prbuf[MAXSTR-1] = '\0';
+    return prbuf;
+}
+
+/*
+ * drop:
+ *	Put something down
+ */
+
+void
+drop(void)
+{
+    int ch;
+    THING *obj;
+
+    ch = chat(hero.y, hero.x);
+    if (ch != FLOOR && ch != PASSAGE)
+    {
+	after = FALSE;
+	msg("there is something there already");
+	return;
+    }
+    if ((obj = get_item("drop", 0)) == NULL)
+	return;
+    if (!dropcheck(obj))
+	return;
+    obj = leave_pack(obj, TRUE, !ISMULT(obj->o_type));
+    /*
+     * Link it into the level object list
+     */
+    attach(lvl_obj, obj);
+    chat(hero.y, hero.x) = obj->o_type;
+    flat(hero.y, hero.x) |= F_DROPPED;
+    obj->o_pos = hero;
+    if (obj->o_type == AMULET)
+	amulet = FALSE;
+    msg("dropped %s", inv_name(obj, TRUE));
+}
+
+/*
+ * dropcheck:
+ *	Do special checks for dropping or unweilding|unwearing|unringing
+ */
+int
+dropcheck(const THING *obj)
+{
+    if (obj == NULL)
+	return TRUE;
+    if (obj != cur_armor && obj != cur_weapon
+	&& obj != cur_ring[LEFT] && obj != cur_ring[RIGHT])
+	    return TRUE;
+    if (obj->o_flags & ISCURSED)
+    {
+	msg("you can't.  It appears to be cursed");
+	return FALSE;
+    }
+    if (obj == cur_weapon)
+	cur_weapon = NULL;
+    else if (obj == cur_armor)
+    {
+	waste_time();
+	cur_armor = NULL;
+    }
+    else
+    {
+	cur_ring[obj == cur_ring[LEFT] ? LEFT : RIGHT] = NULL;
+	switch (obj->o_which)
+	{
+	    case R_ADDSTR:
+		chg_str(-obj->o_arm);
+		break;
+	    case R_SEEINVIS:
+		unsee();
+		extinguish(unsee);
+		break;
+	}
+    }
+    return TRUE;
+}
+
+/*
+ * new_thing:
+ *	Return a new thing
+ */
+THING *
+new_thing(void)
+{
+    THING *cur;
+    int r;
+
+    cur = new_item();
+    cur->o_hplus = 0;
+    cur->o_dplus = 0;
+    strncpy(cur->o_damage, "0x0", sizeof(cur->o_damage));
+    strncpy(cur->o_hurldmg, "0x0", sizeof(cur->o_hurldmg));
+    cur->o_arm = 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(pot_info, MAXPOTIONS);
+	when 1:
+	    cur->o_type = SCROLL;
+	    cur->o_which = pick_one(scr_info, MAXSCROLLS);
+	when 2:
+	    cur->o_type = FOOD;
+	    no_food = 0;
+	    if (rnd(10) != 0)
+		cur->o_which = 0;
+	    else
+		cur->o_which = 1;
+	when 3:
+	    init_weapon(cur, pick_one(weap_info, MAXWEAPONS));
+	    if ((r = rnd(100)) < 10)
+	    {
+		cur->o_flags |= ISCURSED;
+		cur->o_hplus -= rnd(3) + 1;
+	    }
+	    else if (r < 15)
+		cur->o_hplus += rnd(3) + 1;
+	when 4:
+	    cur->o_type = ARMOR;
+	    cur->o_which = pick_one(arm_info, MAXARMORS);
+	    cur->o_arm = a_class[cur->o_which];
+	    if ((r = rnd(100)) < 20)
+	    {
+		cur->o_flags |= ISCURSED;
+		cur->o_arm += rnd(3) + 1;
+	    }
+	    else if (r < 28)
+		cur->o_arm -= rnd(3) + 1;
+	when 5:
+	    cur->o_type = RING;
+	    cur->o_which = pick_one(ring_info, MAXRINGS);
+	    switch (cur->o_which)
+	    {
+		case R_ADDSTR:
+		case R_PROTECT:
+		case R_ADDHIT:
+		case R_ADDDAM:
+		    if ((cur->o_arm = rnd(3)) == 0)
+		    {
+			cur->o_arm = -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_info, MAXSTICKS);
+	    fix_stick(cur);
+#ifdef MASTER
+	otherwise:
+	    debug("Picked a bad kind of object");
+	    wait_for(stdscr, ' ');
+#endif
+    }
+    return cur;
+}
+
+/*
+ * pick_one:
+ *	Pick an item out of a list of nitems possible objects
+ */
+int
+pick_one(const struct obj_info *info, int nitems)
+{
+    const struct obj_info *end;
+    const struct obj_info *start;
+    int i;
+
+    start = info;
+    for (end = &info[nitems], i = rnd(100); info < end; info++)
+	if (i < info->oi_prob)
+	    break;
+    if (info == end)
+    {
+#ifdef MASTER
+	if (wizard)
+	{
+	    msg("bad pick_one: %d from %d items", i, nitems);
+	    for (info = start; info < end; info++)
+		msg("%s: %d%%", info->oi_name, info->oi_prob);
+	}
+#endif
+	info = start;
+    }
+    return (int)(info - start);
+}
+
+/*
+ * discovered:
+ *	list what the player has discovered in this game of a certain type
+ */
+static int line_cnt = 0;
+
+static int newpage = FALSE;
+
+static const char *lastfmt, *lastarg;
+
+
+void
+discovered(void)
+{
+    int ch;
+    int 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("", NULL);
+	print_disc(SCROLL);
+	add_line("", NULL);
+	print_disc(RING);
+	add_line("", NULL);
+	print_disc(STICK);
+	end_line();
+    }
+    else
+    {
+	print_disc(ch);
+	end_line();
+    }
+    msg("");
+}
+
+/*
+ * print_disc:
+ *	Print what we've discovered of type 'type'
+ */
+
+#define MAX4(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)))
+
+
+void
+print_disc(int type)
+{
+    struct obj_info *info = NULL;
+    int i, maxnum = 0, num_found;
+    THING obj;
+    int order[MAX4(MAXSCROLLS, MAXPOTIONS, MAXRINGS, MAXSTICKS)];
+
+    switch (type)
+    {
+	case SCROLL:
+	    maxnum = MAXSCROLLS;
+	    info = scr_info;
+	    break;
+	case POTION:
+	    maxnum = MAXPOTIONS;
+	    info = pot_info;
+	    break;
+	case RING:
+	    maxnum = MAXRINGS;
+	    info = ring_info;
+	    break;
+	case STICK:
+	    maxnum = MAXSTICKS;
+	    info = ws_info;
+	    break;
+    }
+    set_order(order, maxnum);
+    obj.o_count = 1;
+    obj.o_flags = 0;
+    num_found = 0;
+    for (i = 0; i < maxnum; i++)
+	if (info[order[i]].oi_know || info[order[i]].oi_guess)
+	{
+	    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), NULL);
+}
+
+/*
+ * set_order:
+ *	Set up order for list
+ */
+
+void
+set_order(int *order, int numthings)
+{
+    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 */
+int
+add_line(const char *fmt, const char *arg)
+{
+    WINDOW *tw, *sw;
+    int x, y;
+    char *prompt = "--Press space to continue--";
+    static int maxlen = -1;
+
+    if (line_cnt == 0)
+    {
+	    wclear(hw);
+	    if (inv_type == INV_SLOW)
+		mpos = 0;
+    }
+    if (inv_type == INV_SLOW)
+    {
+	if (*fmt != '\0')
+	    if (msg(fmt, arg) == ESCAPE)
+		return ESCAPE;
+	line_cnt++;
+    }
+    else
+    {
+	if (maxlen < 0)
+	    maxlen = (int) strlen(prompt);
+	if (line_cnt >= LINES - 1 || fmt == NULL)
+	{
+	    if (inv_type == INV_OVER && fmt == NULL && !newpage)
+	    {
+		msg("");
+		refresh();
+		tw = newwin(line_cnt + 1, maxlen + 2, 0, COLS - maxlen - 3);
+		sw = subwin(tw, line_cnt + 1, maxlen + 1, 0, COLS - maxlen - 2);
+                for (y = 0; y <= line_cnt; y++) 
+                { 
+                    wmove(sw, y, 0); 
+                    for (x = 0; x <= maxlen; x++) 
+                        waddch(sw, mvwinch(hw, y, x)); 
+                } 
+		wmove(tw, line_cnt, 1);
+		waddstr(tw, prompt);
+		/*
+		 * if there are lines below, use 'em
+		 */
+		if (LINES > NUMLINES)
+		{
+		    if (NUMLINES + line_cnt > LINES)
+			mvwin(tw, LINES - (line_cnt + 1), COLS - maxlen - 3);
+		    else
+			mvwin(tw, NUMLINES, 0);
+		}
+		touchwin(tw);
+		wrefresh(tw);
+		wait_for(tw, ' ');
+                if (md_hasclreol())
+		{
+		    werase(tw);
+		    leaveok(tw, TRUE);
+		    wrefresh(tw);
+		}
+		delwin(tw);
+		touchwin(stdscr);
+	    }
+	    else
+	    {
+		wmove(hw, LINES - 1, 0);
+		waddstr(hw, prompt);
+		wrefresh(hw);
+		wait_for(hw, ' ');
+		clearok(curscr, TRUE);
+		wclear(hw);
+		touchwin(stdscr);
+	    }
+	    newpage = TRUE;
+	    line_cnt = 0;
+	    maxlen = (int) strlen(prompt);
+	}
+	if (fmt != NULL && !(line_cnt == 0 && *fmt == '\0'))
+	{
+	    mvwprintw(hw, line_cnt++, 0, fmt, arg);
+	    getyx(hw, y, x);
+	    if (maxlen < x)
+		maxlen = x;
+	    lastfmt = fmt;
+	    lastarg = arg;
+	}
+    }
+    return ~ESCAPE;
+}
+
+/*
+ * end_line:
+ *	End the list of lines
+ */
+
+void
+end_line(void)
+{
+    if (inv_type != INV_SLOW)
+    {
+	if (line_cnt == 1 && !newpage)
+	{
+	    mpos = 0;
+	    msg(lastfmt, lastarg);
+	}
+	else
+	    add_line(NULL, NULL);
+    }
+    line_cnt = 0;
+    newpage = FALSE;
+}
+
+/*
+ * nothing:
+ *	Set up prbuf so that message for "nothing found" is there
+ */
+const char *
+nothing(int type)
+{
+    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;
+}
+
+/*
+ * nameit:
+ *	Give the proper name to a potion, stick, or ring
+ */
+
+void
+nameit(const THING *obj, const char *type, const char *which, const struct obj_info *op,
+    const char *(*prfunc)(const THING *))
+{
+    char *pb;
+
+    if (op->oi_know || op->oi_guess)
+    {
+	if (obj->o_count == 1)
+	    sprintf(prbuf, "A %s ", type);
+	else
+	    sprintf(prbuf, "%d %ss ", obj->o_count, type);
+	pb = &prbuf[strlen(prbuf)];
+	if (op->oi_know)
+	    sprintf(pb, "of %s%s(%s)", op->oi_name, (*prfunc)(obj), which);
+	else if (op->oi_guess)
+	    sprintf(pb, "called %s%s(%s)", op->oi_guess, (*prfunc)(obj), which);
+    }
+    else if (obj->o_count == 1)
+	sprintf(prbuf, "A%s %s %s", vowelstr(which), which, type);
+    else
+	sprintf(prbuf, "%d %s %ss", obj->o_count, which, type);
+}
+
+/*
+ * nullstr:
+ *	Return a pointer to a null-length string
+ */
+const char *
+nullstr(const THING *ignored)
+{
+    NOOP(ignored);
+    return "";
+}
+
+# ifdef	MASTER
+/*
+ * pr_list:
+ *	List possible potions, scrolls, etc. for wizard.
+ */
+
+void
+pr_list(void)
+{
+    int ch;
+
+    if (!terse)
+	addmsg("for ");
+    addmsg("what type");
+    if (!terse)
+	addmsg(" of object do you want a list");
+    msg("? ");
+    ch = readchar();
+	msg("");
+    switch (ch)
+    {
+	case POTION:
+	    pr_spec(pot_info, MAXPOTIONS);
+	when SCROLL:
+	    pr_spec(scr_info, MAXSCROLLS);
+	when RING:
+	    pr_spec(ring_info, MAXRINGS);
+	when STICK:
+	    pr_spec(ws_info, MAXSTICKS);
+	when ARMOR:
+	    pr_spec(arm_info, MAXARMORS);
+	when WEAPON:
+	    pr_spec(weap_info, MAXWEAPONS);
+	otherwise:
+	    return;
+    }
+}
+
+/*
+ * pr_spec:
+ *	Print specific list of possible items to choose from
+ */
+
+void
+pr_spec(const struct obj_info *info, int nitems)
+{
+    const struct obj_info *endp;
+    int i, lastprob;
+
+    endp = &info[nitems];
+    lastprob = 0;
+    for (i = '0'; info < endp; i++)
+    {
+	if (i == '9' + 1)
+	    i = 'a';
+	sprintf(prbuf, "%c: %%s (%d%%%%)", i, info->oi_prob - lastprob);
+	lastprob = info->oi_prob;
+	add_line(prbuf, info->oi_name);
+	info++;
+    }
+    end_line();
+}
+# endif	/* MASTER */