472 lines
9.5 KiB
C
472 lines
9.5 KiB
C
/*
|
|
* Routines to deal with the pack
|
|
*
|
|
* @(#)pack.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"
|
|
|
|
/*
|
|
* 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
|
|
* getting it off the ground.
|
|
*/
|
|
bool
|
|
add_pack(struct linked_list *item, bool silent)
|
|
{
|
|
reg struct linked_list *ip, *lp;
|
|
reg struct object *obj, *op = NULL;
|
|
bool from_floor;
|
|
char delchar;
|
|
|
|
if (player.t_room == NULL)
|
|
delchar = PASSAGE;
|
|
else
|
|
delchar = FLOOR;
|
|
if (item == NULL) {
|
|
from_floor = TRUE;
|
|
if ((item = find_obj(hero.y, hero.x)) == NULL) {
|
|
mpos = 0;
|
|
msg("That object must have been an illusion.");
|
|
mvaddch(hero.y, hero.x, delchar);
|
|
return FALSE;
|
|
}
|
|
/*
|
|
* Check for scare monster scrolls
|
|
*/
|
|
obj = OBJPTR(item);
|
|
if (obj->o_type == SCROLL && obj->o_which == S_SCARE) {
|
|
if (o_on(obj,ISFOUND)) {
|
|
msg("The scroll turns to dust as you pick it up.");
|
|
detach(lvl_obj, item);
|
|
discard(item);
|
|
mvaddch(hero.y, hero.x, delchar);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
from_floor = FALSE;
|
|
obj = OBJPTR(item);
|
|
/*
|
|
* See if this guy can carry any more weight
|
|
*/
|
|
if (itemweight(obj) + him->s_pack > him->s_carry) {
|
|
msg("You can't carry that %s.", obj->o_typname);
|
|
return FALSE;
|
|
}
|
|
/*
|
|
* Check if there is room
|
|
*/
|
|
if (packvol + obj->o_vol > V_PACK) {
|
|
msg("That %s won't fit in your pack.", obj->o_typname);
|
|
return FALSE;
|
|
}
|
|
if (from_floor) {
|
|
detach(lvl_obj, item);
|
|
mvaddch(hero.y, hero.x, delchar);
|
|
}
|
|
item->l_prev = NULL;
|
|
item->l_next = NULL;
|
|
setoflg(obj, ISFOUND);
|
|
/*
|
|
* start looking thru pack to find the start of items
|
|
* with the same type.
|
|
*/
|
|
lp = pack;
|
|
for (ip = pack; ip != NULL; ip = next(ip)) {
|
|
op = OBJPTR(ip);
|
|
/*
|
|
* If we find a matching type then quit.
|
|
*/
|
|
if (op->o_type == obj->o_type)
|
|
break;
|
|
if (next(ip) != NULL)
|
|
lp = next(lp); /* update "previous" entry */
|
|
}
|
|
/*
|
|
* If the pack was empty, just stick the item in it.
|
|
*/
|
|
if (pack == NULL) {
|
|
pack = item;
|
|
item->l_prev = NULL;
|
|
}
|
|
/*
|
|
* If we looked thru the pack, but could not find an
|
|
* item of the same type, then stick it at the end,
|
|
* unless it was food, then put it in front.
|
|
*/
|
|
else if (ip == NULL) {
|
|
if (obj->o_type == FOOD) { /* insert food at front */
|
|
item->l_next = pack;
|
|
pack->l_prev = item;
|
|
pack = item;
|
|
item->l_prev = NULL;
|
|
}
|
|
else { /* insert other stuff at back */
|
|
lp->l_next = item;
|
|
item->l_prev = lp;
|
|
}
|
|
}
|
|
/*
|
|
* Here, we found at least one item of the same type.
|
|
* Look thru these items to see if there is one of the
|
|
* same group. If so, increment the count and throw the
|
|
* new item away. If not, stick it at the end of the
|
|
* items with the same type. Also keep all similar
|
|
* objects near each other, like all identify scrolls, etc.
|
|
*/
|
|
else {
|
|
struct linked_list **save;
|
|
|
|
while (ip != NULL && op->o_type == obj->o_type) {
|
|
if (op->o_group == obj->o_group) {
|
|
if (op->o_flags == obj->o_flags) {
|
|
op->o_count++;
|
|
discard(item);
|
|
item = ip;
|
|
goto picked_up;
|
|
}
|
|
else {
|
|
goto around;
|
|
}
|
|
}
|
|
if (op->o_which == obj->o_which) {
|
|
if (obj->o_type == FOOD)
|
|
ip = next(ip);
|
|
break;
|
|
}
|
|
around:
|
|
ip = next(ip);
|
|
if (ip != NULL) {
|
|
op = OBJPTR(ip);
|
|
lp = next(lp);
|
|
}
|
|
}
|
|
/*
|
|
* If inserting into last of group at end of pack,
|
|
* just tack on the end.
|
|
*/
|
|
if (ip == NULL) {
|
|
lp->l_next = item;
|
|
item->l_prev = lp;
|
|
}
|
|
/*
|
|
* Insert into the last of a group of objects
|
|
* not at the end of the pack.
|
|
*/
|
|
else {
|
|
save = &((ip->l_prev)->l_next);
|
|
item->l_next = ip;
|
|
item->l_prev = ip->l_prev;
|
|
ip->l_prev = item;
|
|
*save = item;
|
|
}
|
|
}
|
|
picked_up:
|
|
obj = OBJPTR(item);
|
|
if (!silent)
|
|
msg("%s (%c)",inv_name(obj,FALSE),pack_char(obj));
|
|
if (obj->o_type == AMULET)
|
|
amulet = TRUE;
|
|
updpack(); /* new pack weight & volume */
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* inventory:
|
|
* Show what items are in a specific list
|
|
*/
|
|
bool
|
|
inventory(struct linked_list *list, int type)
|
|
{
|
|
reg struct linked_list *pc;
|
|
reg struct object *obj;
|
|
reg char ch;
|
|
reg int cnt;
|
|
|
|
if (list == NULL) { /* empty list */
|
|
msg(type == 0 ? "Empty handed." : "Nothing appropriate.");
|
|
return FALSE;
|
|
}
|
|
else if (next(list) == NULL) { /* only 1 item in list */
|
|
obj = OBJPTR(list);
|
|
msg("a) %s", inv_name(obj, FALSE));
|
|
return TRUE;
|
|
}
|
|
cnt = 0;
|
|
wclear(hw);
|
|
for (ch = 'a', pc = list; pc != NULL; pc = next(pc), ch = npch(ch)) {
|
|
obj = OBJPTR(pc);
|
|
wprintw(hw,"%c) %s\n\r",ch,inv_name(obj, FALSE));
|
|
if (++cnt > LINES - 2 && next(pc) != NULL) {
|
|
dbotline(hw, morestr);
|
|
cnt = 0;
|
|
wclear(hw);
|
|
}
|
|
}
|
|
dbotline(hw,spacemsg);
|
|
restscr(cw);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* pick_up:
|
|
* Add something to characters pack.
|
|
*/
|
|
void
|
|
pick_up(char ch)
|
|
{
|
|
nochange = FALSE;
|
|
switch(ch) {
|
|
case GOLD:
|
|
money();
|
|
when ARMOR:
|
|
case POTION:
|
|
case FOOD:
|
|
case WEAPON:
|
|
case SCROLL:
|
|
case AMULET:
|
|
case RING:
|
|
case STICK:
|
|
add_pack(NULL, FALSE);
|
|
otherwise:
|
|
msg("That item is ethereal !!!");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* picky_inven:
|
|
* Allow player to inventory a single item
|
|
*/
|
|
void
|
|
picky_inven(void)
|
|
{
|
|
reg struct linked_list *item;
|
|
reg char ch, mch;
|
|
|
|
if (pack == NULL)
|
|
msg("You aren't carrying anything.");
|
|
else if (next(pack) == NULL)
|
|
msg("a) %s", inv_name(OBJPTR(pack), FALSE));
|
|
else {
|
|
msg("Item: ");
|
|
mpos = 0;
|
|
if ((mch = readchar()) == ESCAPE) {
|
|
msg("");
|
|
return;
|
|
}
|
|
for (ch='a',item=pack; item != NULL; item=next(item),ch=npch(ch))
|
|
if (ch == mch) {
|
|
msg("%c) %s",ch,inv_name(OBJPTR(item), FALSE));
|
|
return;
|
|
}
|
|
if (ch == 'A')
|
|
ch = 'z';
|
|
else
|
|
ch -= 1;
|
|
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)
|
|
{
|
|
reg struct linked_list *obj, *pit, *savepit = NULL;
|
|
struct object *pob;
|
|
int ch, och, anr, cnt;
|
|
|
|
if (pack == NULL) {
|
|
msg("You aren't carrying anything.");
|
|
return NULL;
|
|
}
|
|
if (type != WEAPON && (type != 0 || next(pack) == NULL)) {
|
|
/*
|
|
* see if we have any of the type requested
|
|
*/
|
|
pit = pack;
|
|
anr = 0;
|
|
for (ch = 'a'; pit != NULL; pit = next(pit), ch = npch(ch)) {
|
|
pob = OBJPTR(pit);
|
|
if (type == pob->o_type || type == 0) {
|
|
++anr;
|
|
savepit = pit; /* save in case of only 1 */
|
|
}
|
|
}
|
|
if (anr == 0) {
|
|
msg("Nothing to %s",purpose);
|
|
after = FALSE;
|
|
return NULL;
|
|
}
|
|
else if (anr == 1) { /* only found one of 'em */
|
|
do {
|
|
struct object *opb;
|
|
|
|
opb = OBJPTR(savepit);
|
|
msg("%s what (* for the item)?",purpose);
|
|
och = readchar();
|
|
if (och == '*') {
|
|
mpos = 0;
|
|
msg("%c) %s",pack_char(opb),inv_name(opb,FALSE));
|
|
continue;
|
|
}
|
|
if (och == ESCAPE) {
|
|
msg("");
|
|
after = FALSE;
|
|
return NULL;
|
|
}
|
|
if (isalpha(och) && och != pack_char(opb)) {
|
|
mpos = 0;
|
|
msg("You can't %s that !!", purpose);
|
|
after = FALSE;
|
|
return NULL;
|
|
}
|
|
} while(!isalpha(och));
|
|
mpos = 0;
|
|
return savepit; /* return this item */
|
|
}
|
|
}
|
|
for (;;) {
|
|
msg("%s what? (* for list): ",purpose);
|
|
ch = readchar();
|
|
mpos = 0;
|
|
if (ch == ESCAPE) { /* abort if escape hit */
|
|
after = FALSE;
|
|
msg(""); /* clear display */
|
|
return NULL;
|
|
}
|
|
if (ch == '*') {
|
|
wclear(hw);
|
|
pit = pack; /* point to pack */
|
|
cnt = 0;
|
|
for (ch='a'; pit != NULL; pit=next(pit), ch=npch(ch)) {
|
|
pob = OBJPTR(pit);
|
|
if (type == 0 || type == pob->o_type) {
|
|
wprintw(hw,"%c) %s\n\r",ch,inv_name(pob,FALSE));
|
|
if (++cnt > LINES - 2 && next(pit) != NULL) {
|
|
cnt = 0;
|
|
dbotline(hw, morestr);
|
|
wclear(hw);
|
|
}
|
|
}
|
|
}
|
|
wmove(hw, LINES - 1,0);
|
|
wprintw(hw,"%s what? ",purpose);
|
|
draw(hw); /* write screen */
|
|
anr = FALSE;
|
|
do {
|
|
ch = readchar();
|
|
if (isalpha(ch) || ch == ESCAPE)
|
|
anr = TRUE;
|
|
} while(!anr); /* do till we got it right */
|
|
restscr(cw); /* redraw orig screen */
|
|
if (ch == ESCAPE) {
|
|
after = FALSE;
|
|
msg(""); /* clear top line */
|
|
return NULL; /* all done if abort */
|
|
}
|
|
/* ch has item to get from pack */
|
|
}
|
|
for (obj=pack,och='a';obj!=NULL;obj=next(obj),och=npch(och))
|
|
if (ch == och)
|
|
break;
|
|
if (obj == NULL) {
|
|
if (och == 'A')
|
|
och = 'z';
|
|
else
|
|
och -= 1;
|
|
msg("Please specify a letter between 'a' and '%c'",och);
|
|
continue;
|
|
}
|
|
else
|
|
return obj;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* pack_char:
|
|
* Get the character of a particular item in the pack
|
|
*/
|
|
char
|
|
pack_char(struct object *obj)
|
|
{
|
|
reg struct linked_list *item;
|
|
reg char c;
|
|
|
|
c = 'a';
|
|
for (item = pack; item != NULL; item = next(item))
|
|
if (OBJPTR(item) == obj)
|
|
return c;
|
|
else
|
|
c = npch(c);
|
|
return '%';
|
|
}
|
|
|
|
/*
|
|
* idenpack:
|
|
* Identify all the items in the pack
|
|
*/
|
|
void
|
|
idenpack(void)
|
|
{
|
|
reg struct linked_list *pc;
|
|
|
|
for (pc = pack ; pc != NULL ; pc = next(pc))
|
|
whatis(pc);
|
|
}
|
|
|
|
|
|
/*
|
|
* del_pack:
|
|
* Take something out of the hero's pack
|
|
*/
|
|
void
|
|
del_pack(struct linked_list *what)
|
|
{
|
|
reg struct object *op;
|
|
|
|
op = OBJPTR(what);
|
|
cur_null(op); /* check for current stuff */
|
|
if (op->o_count > 1) {
|
|
op->o_count--;
|
|
}
|
|
else {
|
|
detach(pack,what);
|
|
discard(what);
|
|
}
|
|
updpack();
|
|
}
|
|
|
|
/*
|
|
* cur_null:
|
|
* This updates cur_weapon etc for dropping things
|
|
*/
|
|
void
|
|
cur_null(struct object *op)
|
|
{
|
|
if (op == cur_weapon)
|
|
cur_weapon = NULL;
|
|
else if (op == cur_armor)
|
|
cur_armor = NULL;
|
|
else if (op == cur_ring[LEFT])
|
|
cur_ring[LEFT] = NULL;
|
|
else if (op == cur_ring[RIGHT])
|
|
cur_ring[RIGHT] = NULL;
|
|
}
|