view rogue4/pack.c @ 245:e7aab31362af

Rogue V[345], Super-Rogue: Fix violet fungi/venus flytraps. Violet fungi (renamed venus flytraps in Rogue V5) do an increasing amount of damage each time they hit. If they miss, you still suffer the same number of HP. This worked by keeping a counter and printing new damage strings into monsters[5].m_stats.s_dmg, which is the "prototype" of that particular monster. Each individual monster has its own damage string. Apparently these were once char *, pointing to the same string as the prototype. When the s_dmg member was changed to be an internal char array, changing the prototype's damage string no longer had any effect on actual monsters. As a result, flytraps did no damage on a hit, or only one point in V5. The mechanism for doing damage on a miss continued to work. This has been fixed by overwriting the individual monster's damage string instead of the prototype's. It is now no longer necessary to reset the damage string when the flytrap is killed. The method for resetting it when the hero teleports away had to be modified. Comments referencing the long-unused xstr have been removed.
author John "Elwin" Edwards
date Sun, 01 May 2016 19:39:56 -0400
parents 1b73a8641b37
children e52a8a7ad4c5
line wrap: on
line source

/*
 * Routines to deal with the pack
 *
 * @(#)pack.c	4.15 (Berkeley) 4/6/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 "rogue.h"

void money(int value);

/*
 * update_mdest:
 *	Called after picking up an object, before discarding it.
 *	If this was the object of something's desire, that monster will
 *	get mad and run at the hero
 */
void
update_mdest(THING *obj)
{
    register THING *mp;

    for (mp = mlist; mp != NULL; mp = next(mp))
	if (mp->t_dest == &obj->o_pos)
     mp->t_dest = &hero;
}

/*
 * add_pack:
 *	Pick up an object and add it to the pack.  If the argument is
 *	non-null use it as the linked_list pointer instead of gettting
 *	it off the ground.
 */
void
add_pack(THING *obj, bool silent)
{
    register THING *op, *lp = NULL;
    register bool exact, from_floor;
    register char floor;
    int discarded = 0;

    if (obj == NULL)
    {
	from_floor = TRUE;
	if ((obj = find_obj(hero.y, hero.x)) == NULL)
	    return;
    }
    else
	from_floor = FALSE;
    /*
     * Link it into the pack.  Search the pack for a object of similar type
     * if there isn't one, stuff it at the beginning, if there is, look for one
     * that is exactly the same and just increment the count if there is.
     * it  that.  Food is always put at the beginning for ease of access, but
     * is not ordered so that you can't tell good food from bad.  First check
     * to see if there is something in thr same group and if there is then
     * increment the count.
     */
/*    floor = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR; */
    if (proom) floor = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
    else floor = FLOOR;
    if (obj->o_group)
    {
	for (op = pack; op != NULL; op = next(op))
	{
	    if (op->o_group == obj->o_group)
	    {
		/*
		 * Put it in the pack and notify the user
		 */
		op->o_count++;
		if (from_floor)
		{
		    detach(lvl_obj, obj);
		    mvaddch(hero.y, hero.x, floor);
		    chat(hero.y, hero.x) = floor;
		}
		update_mdest(obj);
		discard(obj);
		obj = op;
		discarded = 1;
		goto picked_up;
	    }
	}
    }
    /*
     * Check if there is room
     */
    if (inpack == MAXPACK-1)
    {
	msg("you can't carry anything else");
	return;
    }
    /*
     * Check for and deal with scare monster scrolls
     */
    if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
	if (obj->o_flags & ISFOUND)
	{
	    detach(lvl_obj, obj);
	    mvaddch(hero.y, hero.x, floor);
	    chat(hero.y, hero.x) = floor;
	    msg("the scroll turns to dust as you pick it up");
	    return;
	}
	else
	    obj->o_flags |= ISFOUND;

    inpack++;
    if (from_floor)
    {
	detach(lvl_obj, obj);
	mvaddch(hero.y, hero.x, floor);
	chat(hero.y, hero.x) = floor;
    }
    /*
     * Search for an object of the same type
     */
    exact = FALSE;
    for (op = pack; op != NULL; op = next(op))
	if (obj->o_type == op->o_type)
	    break;
    if (op == NULL)
    {
	/*
	 * Put it at the end of the pack since it is a new type
	 */
	for (op = pack; op != NULL; op = next(op))
	{
	    if (op->o_type != FOOD)
		break;
	    lp = op;
	}
    }
    else
    {
	/*
	 * Search for an object which is exactly the same
	 */
	while (op->o_type == obj->o_type)
	{
	    if (op->o_which == obj->o_which)
	    {
		exact = TRUE;
		break;
	    }
	    lp = op;
	    if ((op = next(op)) == NULL)
		break;
	}
    }
    if (op == NULL)
    {
	/*
	 * Didn't find an exact match, just stick it here
	 */
	if (pack == NULL)
	    pack = obj;
	else
	{
	    lp->l_next = obj;
	    obj->l_prev = lp;
	    obj->l_next = NULL;
	}
    }
    else
    {
	/*
	 * If we found an exact match.  If it is a potion, food, or a 
	 * scroll, increase the count, otherwise put it with its clones.
	 */
	if (exact && ISMULT(obj->o_type))
	{
	    op->o_count++;
	    update_mdest(obj);
	    discard(obj);
	    obj = op;
	    discarded = 1;
	    goto picked_up;
	}
	if ((obj->l_prev = prev(op)) != NULL)
	    obj->l_prev->l_next = obj;
	else
	    pack = obj;
	obj->l_next = op;
	op->l_prev = obj;
    }
picked_up:
    /*
     * If this was the object of something's desire, that monster will
     * get mad and run at the hero
     */
    if (!discarded)
        update_mdest(obj);

    if (obj->o_type == AMULET)
	amulet = TRUE;
    /*
     * Notify the user
     */
    if (!silent)
    {
	if (!terse)
	    addmsg("you now have ");
	msg("%s (%c)", inv_name(obj, !terse), pack_char(obj));
    }
}

/*
 * inventory:
 *	List what is in the pack
 */
bool
inventory(THING *list, int type)
{
    register char ch;
    register int n_objs;
    char inv_temp[MAXSTR];

    n_objs = 0;
    for (ch = 'a'; list != NULL; ch++, list = next(list))
    {
	if (type && type != list->o_type && !(type == CALLABLE &&
	    (list->o_type == SCROLL || list->o_type == POTION ||
	     list->o_type == RING || list->o_type == STICK)))
		continue;
	n_objs++;
	sprintf(inv_temp, "%c) %%s", ch);
	add_line(inv_temp, inv_name(list, FALSE));
    }
    if (n_objs == 0)
    {
	if (terse)
	    msg(type == 0 ? "empty handed" :
			    "nothing appropriate");
	else
	    msg(type == 0 ? "you are empty handed" :
			    "you don't have anything appropriate");
	return FALSE;
    }
    end_line();
    return TRUE;
}

/*
 * pick_up:
 *	Add something to characters pack.
 */
void
pick_up(char ch)
{
    register THING *obj, *mp;

    switch (ch)
    {
	case GOLD:
	    if ((obj = find_obj(hero.y, hero.x)) == NULL)
		return;
	    money(obj->o_goldval);
	    detach(lvl_obj, obj);
	    update_mdest(obj);
	    discard(obj);
	    proom->r_goldval = 0;
	    break;
	default:
#ifdef WIZARD
	    debug("Where did you pick a '%s' up???", unctrol(ch));
#endif
	case ARMOR:
	case POTION:
	case FOOD:
	case WEAPON:
	case SCROLL:	
	case AMULET:
	case RING:
	case STICK:
	    add_pack(NULL, FALSE);
	    break;
    }
}

/*
 * picky_inven:
 *	Allow player to inventory a single item
 */
void
picky_inven(void)
{
    register THING *obj;
    register char ch, mch;

    if (pack == NULL)
	msg("you aren't carrying anything");
    else if (next(pack) == NULL)
	msg("a) %s", inv_name(pack, FALSE));
    else
    {
	msg(terse ? "item: " : "which item do you wish to inventory: ");
	mpos = 0;
	if ((mch = readchar()) == ESCAPE)
	{
	    msg("");
	    return;
	}
	for (ch = 'a', obj = pack; obj != NULL; obj = next(obj), ch++)
	    if (ch == mch)
	    {
		msg("%c) %s",ch,inv_name(obj, FALSE));
		return;
	    }
	if (!terse)
	    msg("'%s' not in pack", unctrol(mch));
	msg("range is 'a' to '%c'", --ch);
    }
}

/*
 * get_item:
 *	Pick something out of a pack for a purpose
 */
THING *
get_item(char *purpose, int type)
{
    register THING *obj;
    register char ch, och;

    if (pack == NULL)
	msg("you aren't carrying anything");
    else
    {
	for (;;)
	{
	    if (!terse)
		addmsg("which object do you want to ");
	    addmsg(purpose);
	    if (terse)
		addmsg(" what");
	    msg("? (* for list): ");
	    ch = readchar();
	    mpos = 0;
	    /*
	     * Give the poor player a chance to abort the command
	     */
	    if (ch == ESCAPE || ch == CTRL('G'))
	    {
		after = FALSE;
		msg("");
		return NULL;
	    }
	    if (ch == '*')
	    {
		mpos = 0;
		if (inventory(pack, type) == 0)
		{
		    after = FALSE;
		    return NULL;
		}
		continue;
	    }
	    for (obj = pack, och = 'a'; obj != NULL; obj = next(obj), och++)
		if (ch == och)
		    break;
	    if (obj == NULL)
	    {
		msg("please specify a letter between 'a' and '%c'", och-1);
		continue;
	    }
	    else 
		return obj;
	}
    }
    return NULL;
}

/*
 * pack_char:
 *	Return which character would address a pack object
 */
char
pack_char(THING *obj)
{
    register THING *item;
    register char c;

    c = 'a';
    for (item = pack; item != NULL; item = next(item))
	if (item == obj)
	    return c;
	else
	    c++;
    return '?';
}

/*
 * money:
 *	Add or subtract gold from the pack
 */
void
money(int value)
{
    register char floor;

    floor = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
    purse += value;
    mvaddch(hero.y, hero.x, floor);
    chat(hero.y, hero.x) = floor;
    if (value > 0)
    {
	if (!terse)
	    addmsg("you found ");
	msg("%d gold pieces", value);
    }
}