/*
* Routines to deal with the pack
*
* @(#)pack.c 3.6 (Berkeley) 6/15/81
*
* 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"
/*
* 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(struct linked_list *item, int silent)
{
struct linked_list *ip, *lp = NULL;
struct object *obj, *op = NULL;
int exact, from_floor;
if (item == NULL)
{
from_floor = TRUE;
if ((item = find_obj(hero.y, hero.x)) == NULL)
return;
}
else
from_floor = FALSE;
obj = (struct object *) ldata(item);
/*
* 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.
*/
if (obj->o_group)
{
for (ip = pack; ip != NULL; ip = next(ip))
{
op = (struct object *) ldata(ip);
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, item);
mvaddch(hero.y, hero.x,
(roomin(&hero) == NULL ? PASSAGE : FLOOR));
}
discard(item);
item = ip;
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)
{
msg("The scroll turns to dust as you pick it up.");
detach(lvl_obj, item);
mvaddch(hero.y, hero.x, FLOOR);
return;
}
else
obj->o_flags |= ISFOUND;
inpack++;
if (from_floor)
{
detach(lvl_obj, item);
mvaddch(hero.y, hero.x, (roomin(&hero) == NULL ? PASSAGE : FLOOR));
}
/*
* Search for an object of the same type
*/
exact = FALSE;
for (ip = pack; ip != NULL; ip = next(ip))
{
op = (struct object *) ldata(ip);
if (obj->o_type == op->o_type)
break;
}
if (ip == NULL)
{
/*
* Put it at the end of the pack since it is a new type
*/
for (ip = pack; ip != NULL; ip = next(ip))
{
op = (struct object *) ldata(ip);
if (op->o_type != FOOD)
break;
lp = ip;
}
}
else
{
/*
* Search for an object which is exactly the same
*/
while (ip != NULL && op->o_type == obj->o_type)
{
if (op->o_which == obj->o_which)
{
exact = TRUE;
break;
}
lp = ip;
if ((ip = next(ip)) == NULL)
break;
op = (struct object *) ldata(ip);
}
}
if (ip == NULL)
{
/*
* Didn't find an exact match, just stick it here
*/
if (pack == NULL)
pack = item;
else
{
lp->l_next = item;
item->l_prev = lp;
item->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++;
discard(item);
item = ip;
goto picked_up;
}
if ((item->l_prev = prev(ip)) != NULL)
item->l_prev->l_next = item;
else
pack = item;
item->l_next = ip;
ip->l_prev = item;
}
picked_up:
/*
* Notify the user
*/
obj = (struct object *) ldata(item);
if (notify && !silent)
{
if (!terse)
addmsg("You now have ");
msg("%s (%c)", inv_name(obj, !terse), pack_char(obj));
}
if (obj->o_type == AMULET)
amulet = TRUE;
}
/*
* inventory:
* list what is in the pack
*/
int
inventory(struct linked_list *list, int type)
{
struct object *obj;
int ch;
int n_objs;
char inv_temp[80];
n_objs = 0;
for (ch = 'a'; list != NULL; ch++, list = next(list))
{
obj = (struct object *) ldata(list);
if (type && type != obj->o_type && !(type == CALLABLE &&
(obj->o_type == SCROLL || obj->o_type == POTION ||
obj->o_type == RING || obj->o_type == STICK)))
continue;
switch (n_objs++)
{
/*
* For the first thing in the inventory, just save the string
* in case there is only one.
*/
case 0:
sprintf(inv_temp, "%c) %s", ch, inv_name(obj, FALSE));
break;
/*
* If there is more than one, clear the screen, print the
* saved message and fall through to ...
*/
case 1:
if (slow_invent)
msg(inv_temp);
else
{
wclear(hw);
waddstr(hw, inv_temp);
waddch(hw, '\n');
}
/*
* Print the line for this object
*/
default:
if (slow_invent)
msg("%c) %s", ch, inv_name(obj, FALSE));
else
wprintw(hw, "%c) %s\n", ch, inv_name(obj, 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;
}
if (n_objs == 1)
{
msg(inv_temp);
return TRUE;
}
if (!slow_invent)
{
mvwaddstr(hw, LINES-1, 0, "--Press space to continue--");
draw(hw);
wait_for(hw,' ');
clearok(cw, TRUE);
touchwin(cw);
}
return TRUE;
}
/*
* pick_up:
* Add something to characters pack.
*/
void
pick_up(int ch)
{
switch(ch)
{
case GOLD:
money();
break;
default:
debug("Where did you pick that up???");
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()
{
struct linked_list *item;
int ch, mch;
if (pack == NULL)
msg("You aren't carrying anything");
else if (next(pack) == NULL)
msg("a) %s", inv_name((struct object *) ldata(pack), FALSE));
else
{
msg(terse ? "Item: " : "Which item do you wish to inventory: ");
mpos = 0;
if ((mch = readchar(cw)) == ESCAPE)
{
msg("");
return;
}
for (ch = 'a', item = pack; item != NULL; item = next(item), ch++)
if (ch == mch)
{
msg("%c) %s",ch,inv_name((struct object *) ldata(item), FALSE));
return;
}
if (!terse)
msg("'%s' not in pack", unctrl(mch));
msg("Range is 'a' to '%c'", --ch);
}
}
/*
* get_item:
* pick something out of a pack for a purpose
*/
struct linked_list *
get_item(char *purpose, int type)
{
struct linked_list *obj;
int 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(cw);
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;
}
int
pack_char(struct object *obj)
{
struct linked_list *item;
int c;
c = 'a';
for (item = pack; item != NULL; item = next(item))
if ((struct object *) ldata(item) == obj)
return c;
else
c++;
return 'z';
}