1774 lines
44 KiB
C
1774 lines
44 KiB
C
/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */
|
|
/* inv.c */
|
|
/* functions having to do with player item inventory */
|
|
|
|
#ifdef MSDOS_SUPPORTED_ANTIQUE
|
|
# include "curses.h"
|
|
#else
|
|
# ifdef AMIGA
|
|
# include <curses210.h>
|
|
# elif defined(USE_OPCURSES)
|
|
# include "../opcurses/curses.h"
|
|
# else
|
|
# include <curses.h>
|
|
# endif
|
|
#endif
|
|
|
|
#include "glob.h"
|
|
|
|
static void inv_display_munge(void);
|
|
static void inv_display_refresh(void);
|
|
|
|
|
|
/* drops money, heh heh */
|
|
void drop_money(void)
|
|
{
|
|
pob money;
|
|
|
|
money = detach_money(0);
|
|
if (money != NULL) {
|
|
if (Current_Environment == E_CITY) {
|
|
print1("As soon as the money leaves your hand,");
|
|
print2("a horde of scrofulous beggars snatch it up and are gone!");
|
|
free( money );
|
|
}
|
|
else drop_at(Player.x,Player.y,money);
|
|
}
|
|
else setgamestatus(SKIP_MONSTERS);
|
|
}
|
|
|
|
|
|
/* returns some money from player back into "money" item.
|
|
for giving and dropping money */
|
|
pob detach_money(long howmuch)
|
|
/* if howmuch == 0, ask the player. otherwise, just get howmuch. */
|
|
{
|
|
long c;
|
|
pob cash=NULL;
|
|
if ( howmuch == 0 )
|
|
c = get_money(Player.cash);
|
|
else
|
|
c = howmuch;
|
|
if (c != ABORT) {
|
|
Player.cash -= c;
|
|
cash = ((pob) checkmalloc(sizeof(objtype)));
|
|
make_cash(cash,difficulty());
|
|
cash->basevalue = c;
|
|
}
|
|
return(cash);
|
|
}
|
|
|
|
|
|
/* gets a legal amount of money or ABORT */
|
|
long get_money(long limit)
|
|
{
|
|
long c;
|
|
c = parsenum("How much money? ");
|
|
if (c > limit) {
|
|
print3("Forget it, buddy.");
|
|
return(ABORT);
|
|
}
|
|
else return(c);
|
|
}
|
|
|
|
|
|
|
|
/* pick up from some location x,y */
|
|
/* Lift entire itemlist off ground, pass it to inventory control, which
|
|
may drop things back onto the now null ground */
|
|
void pickup_at (int x, int y)
|
|
{
|
|
char response;
|
|
|
|
pol ol;
|
|
pol temp;
|
|
|
|
resetgamestatus(FAST_MOVE);
|
|
|
|
ol = Level->site[x][y].things;
|
|
Level->site[x][y].things = 0;
|
|
|
|
while (ol != 0)
|
|
{
|
|
clearmsg1();
|
|
response = cinema_ynq(strjoin("Pick up: ", itemid(ol->thing)));
|
|
if ('q' == response)
|
|
break;
|
|
|
|
if (response == 'y')
|
|
gain_item(ol->thing);
|
|
else
|
|
drop_at(x,y,ol->thing);
|
|
|
|
temp = ol;
|
|
ol = ol->next;
|
|
temp->next = 0;
|
|
temp->thing = 0;
|
|
free(temp);
|
|
}
|
|
|
|
while (ol != 0)
|
|
{
|
|
temp = ol;
|
|
ol = ol->next;
|
|
temp->next = 0;
|
|
temp->thing = 0;
|
|
free(temp);
|
|
}
|
|
}
|
|
|
|
/* WDT -- convert from a char (keypress) to an item index in
|
|
* player inventory */
|
|
/* Item identifiers, in this case the letters of the alphabet minus
|
|
* any letters already used for commands. Yes, there are more here
|
|
* than could be needed, but I don't want to short myself for later.
|
|
*/
|
|
signed char inventory_keymap[] = "-abcfghimnoqruvwyz";
|
|
int key_to_index(signed char key)
|
|
{
|
|
int i;
|
|
assert( MAXITEMS>0 ); /* must have room for an item, or this loop will
|
|
* die! */
|
|
|
|
for (i=0; i<MAXITEMS; i++) {
|
|
if (key == inventory_keymap[i])
|
|
return (signed char)i;
|
|
}
|
|
return O_UP_IN_AIR;
|
|
}
|
|
|
|
signed char index_to_key(signed int index)
|
|
{
|
|
if ( index < MAXITEMS )
|
|
return inventory_keymap[index];
|
|
else return '-';
|
|
}
|
|
|
|
|
|
/* criteria for being able to put some item in some slot */
|
|
/* WDT -- why on earth does the 'slottable' function print stuff???? */
|
|
int aux_slottable(pob o, int slot)
|
|
{
|
|
int ok = TRUE;
|
|
if (o == NULL) ok = FALSE;
|
|
else if (slot == O_ARMOR) {
|
|
if (o->objchar != ARMOR) {
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
else if (slot == O_SHIELD) {
|
|
if (o->objchar != SHIELD) {
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
else if (slot == O_BOOTS) {
|
|
if (o->objchar != BOOTS) {
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
else if (slot == O_CLOAK) {
|
|
if (o->objchar != CLOAK) {
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
else if (slot >= O_RING1) {
|
|
if (o->objchar != RING) {
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
return(ok);
|
|
}
|
|
|
|
/* put all of o on objlist at x,y on Level->depth */
|
|
/* Not necessarily dropped by character; just dropped... */
|
|
void drop_at(int x, int y, pob o)
|
|
{
|
|
pol tmp;
|
|
pob cpy;
|
|
|
|
if (Current_Environment != E_COUNTRYSIDE) {
|
|
if ((Level->site[x][y].locchar != VOID_CHAR) &&
|
|
(Level->site[x][y].locchar != ABYSS)) {
|
|
cpy = copy_obj( o );
|
|
tmp = ((pol) checkmalloc(sizeof(oltype)));
|
|
cpy->used = FALSE;
|
|
tmp->thing = cpy;
|
|
tmp->next = Level->site[x][y].things;
|
|
Level->site[x][y].things = tmp;
|
|
}
|
|
else if (Level->site[x][y].p_locf == L_VOID_STATION)
|
|
setgamestatus(PREPARED_VOID);
|
|
}
|
|
}
|
|
|
|
/* put n of o on objlist at x,y on Level->depth */
|
|
void p_drop_at(int x, int y, int n, pob o)
|
|
{
|
|
pol tmp;
|
|
if (Current_Environment != E_COUNTRYSIDE) {
|
|
if ((Level->site[x][y].locchar != VOID_CHAR) &&
|
|
(Level->site[x][y].locchar != ABYSS)) {
|
|
tmp = ((pol) checkmalloc(sizeof(oltype)));
|
|
tmp->thing = copy_obj( o );
|
|
tmp->thing->used = FALSE;
|
|
tmp->thing->number = n;
|
|
print2("Dropped ");
|
|
nprint2(itemid(tmp->thing));
|
|
morewait();
|
|
tmp->next = Level->site[x][y].things;
|
|
Level->site[x][y].things = tmp;
|
|
}
|
|
else if (Level->site[x][y].p_locf == L_VOID_STATION)
|
|
setgamestatus(PREPARED_VOID);
|
|
}
|
|
}
|
|
|
|
|
|
/* returns a string for identified items */
|
|
char *itemid(pob obj)
|
|
{
|
|
char tstr[80];
|
|
if (obj->objchar==CASH){
|
|
strcpy(Str4,obj->truename);
|
|
return(Str4);
|
|
}
|
|
else {
|
|
if (Objects[obj->id].known > obj->known)
|
|
obj->known = Objects[obj->id].known;
|
|
|
|
setnumstr(obj,tstr);
|
|
strcpy(Str4,tstr);
|
|
if (obj->known == 0)
|
|
strcat(Str4,obj->objstr);
|
|
else if (obj->known == 1) {
|
|
if (obj->id == OB_YENDOR || obj->id == OB_KARNAK ||
|
|
obj->id == OB_STARGEM )
|
|
strcat(Str4, "the ");
|
|
strcat(Str4,obj->truename);
|
|
}
|
|
else {
|
|
if (obj->id == OB_YENDOR || obj->id == OB_KARNAK ||
|
|
obj->id == OB_STARGEM )
|
|
strcat(Str4, "the ");
|
|
if (obj->usef == I_NOTHING && Objects[obj->id].usef != I_NOTHING)
|
|
strcat(Str4, "disenchanted ");
|
|
if (obj->blessing < 0) {
|
|
strcat(Str4, "cursed ");
|
|
strcat(Str4, obj->cursestr);
|
|
}
|
|
else if (obj->blessing > 0) {
|
|
strcat(Str4, "blessed ");
|
|
strcat(Str4, obj->truename);
|
|
}
|
|
else strcat(Str4,obj->truename);
|
|
if (obj->number > 1) strcat(Str4,"s");
|
|
switch (obj->objchar) {
|
|
case STICK:
|
|
setchargestr(obj,tstr);
|
|
strcat(Str4,tstr);
|
|
break;
|
|
case MISSILEWEAPON:
|
|
case ARMOR:
|
|
case RING:
|
|
case SHIELD:
|
|
case WEAPON:
|
|
setplustr(obj,tstr);
|
|
strcat(Str4, tstr);
|
|
break;
|
|
default: strcat(Str4,""); break;
|
|
}
|
|
}
|
|
return(Str4);
|
|
}
|
|
}
|
|
|
|
char *cashstr(void)
|
|
{
|
|
if (difficulty() < 3) return("copper pieces");
|
|
else if (difficulty() < 5) return("silver pieces");
|
|
else if (difficulty() < 7) return("gold pieces");
|
|
else if (difficulty() < 8) return("semiprecious gems");
|
|
else if (difficulty() < 9) return("mithril pieces");
|
|
else if (difficulty() < 10) return("precious gems");
|
|
else return("orichalc pieces");
|
|
}
|
|
|
|
/* return an object's plus as a string */
|
|
void setplustr(pob obj, char *pstr)
|
|
{
|
|
pstr[0] = ' ';
|
|
pstr[1] = (obj->plus < 0 ? '-' : '+' );
|
|
if (abs(obj->plus) < 10) {
|
|
pstr[2] = '0' + abs(obj->plus);
|
|
pstr[3] = 0;
|
|
}
|
|
else {
|
|
pstr[2] = '0' + abs(obj->plus / 10);
|
|
pstr[3] = '0' + abs(obj->plus % 10);
|
|
pstr[4] = 0;
|
|
}
|
|
}
|
|
|
|
/* return an object's number as a string */
|
|
void setnumstr(pob obj, char *nstr)
|
|
{
|
|
if (obj->number < 2)
|
|
nstr[0] = 0;
|
|
else if (obj->number < 10) {
|
|
nstr[0] = '0' + obj->number;
|
|
nstr[1] = 'x';
|
|
nstr[2] = ' ';
|
|
nstr[3] = 0;
|
|
}
|
|
else if (obj->number < 41) {
|
|
nstr[0] = '0' + ((int)(obj->number / 10));
|
|
nstr[1] = '0' + (obj->number % 10);
|
|
nstr[2] = 'x';
|
|
nstr[3] = ' ';
|
|
nstr[4] = 0;
|
|
}
|
|
else strcpy(nstr,"lots of ");
|
|
}
|
|
|
|
|
|
/* return object with charges */
|
|
void setchargestr(pob obj, char *cstr)
|
|
{
|
|
cstr[0] = ' ';
|
|
cstr[1] = '[';
|
|
if (obj->charge < 0) {
|
|
cstr[2]='d';
|
|
cstr[3]='e';
|
|
cstr[4]='a';
|
|
cstr[5]='d';
|
|
cstr[6]=']';
|
|
cstr[7]=0;
|
|
}
|
|
else if (obj->charge < 10) {
|
|
cstr[2] = '0' + obj->charge;
|
|
cstr[3] = ']';
|
|
cstr[4] = 0;
|
|
}
|
|
else {
|
|
cstr[2] = '0' + ((int)(obj->charge / 10));
|
|
cstr[3] = '0' + (obj->charge % 10);
|
|
cstr[4] = ']';
|
|
cstr[5] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void give_money(struct monster *m)
|
|
{
|
|
pob cash;
|
|
|
|
cash = detach_money(0);
|
|
if (cash == NULL)
|
|
setgamestatus(SKIP_MONSTERS);
|
|
else givemonster(m,cash);
|
|
}
|
|
|
|
|
|
void lawbringer_gets_gem(pmt m, pob o)
|
|
{
|
|
clearmsg();
|
|
print1("The LawBringer accepts the gem reverently.");
|
|
print2("He raises it above his head, where it bursts into lambent flame!");
|
|
morewait();
|
|
print1("You are bathed in a shimmering golden light.");
|
|
print2("You feel embedded in an infinite matrix of ordered energy.");
|
|
morewait();
|
|
if (Imprisonment > 0)
|
|
Imprisonment = 0;
|
|
if (Player.rank[ORDER] == -1) {
|
|
print2("You have been forgiven. You feel like a Paladin....");
|
|
Player.rank[ORDER] = 1;
|
|
}
|
|
Player.alignment += 200;
|
|
Player.pow = Player.maxpow = Player.pow * 2;
|
|
gain_experience(2000);
|
|
setgamestatus(GAVE_STARGEM);
|
|
/* WDT HACK!!! Where else would this ever get freed?? */
|
|
free_obj(o, TRUE);
|
|
}
|
|
|
|
void givemonster(pmt m, pob o)
|
|
{
|
|
/* special case -- give gem to LawBringer */
|
|
if ((m->id == LAWBRINGER) && (o->id == OB_STARGEM))
|
|
lawbringer_gets_gem(m,o);
|
|
else {
|
|
if (m->uniqueness == COMMON) {
|
|
strcpy(Str3,"The ");
|
|
strcat(Str3,m->monstring);
|
|
}
|
|
else strcpy(Str3,m->monstring);
|
|
|
|
if (m_statusp(m,GREEDY) || m_statusp(m,NEEDY)) {
|
|
m_pickup(m,o);
|
|
strcat(Str3," takes your gift");
|
|
print1(Str3);
|
|
Player.alignment++;
|
|
if (m_statusp(m,GREEDY) && (true_item_value(o) < (long) m->level*100))
|
|
nprint1("...but does not appear satisfied.");
|
|
else if (m_statusp(m,NEEDY) &&
|
|
(true_item_value(o) < (long) Level->depth*Level->depth))
|
|
nprint1("...and looks chasteningly at you.");
|
|
else {
|
|
nprint1("...and seems happy with it.");
|
|
m_status_reset(m,HOSTILE);
|
|
m_status_reset(m,GREEDY);
|
|
m_status_reset(m,NEEDY);
|
|
}
|
|
}
|
|
else if (m_statusp(m,HUNGRY)) {
|
|
|
|
if (((m->id == HORSE) && (o->id == OB_GRAIN)) || /* grain */
|
|
((m->id != HORSE) &&
|
|
((o->usef == I_FOOD) || (o->usef == I_POISON_FOOD)))) {
|
|
strcat(Str3," wolfs down your food ... ");
|
|
print1(Str3);
|
|
m_status_reset(m,HUNGRY);
|
|
m_status_reset(m,HOSTILE);
|
|
if (o->usef == I_POISON_FOOD) {
|
|
Player.alignment -= 2;
|
|
nprint1("...and chokes on the poisoned ration!");
|
|
morewait();
|
|
m_status_set(m,HOSTILE);
|
|
m_damage(m,100,POISON);
|
|
}
|
|
else nprint1("...and now seems satiated.");
|
|
morewait();
|
|
free_obj(o, TRUE);
|
|
}
|
|
else {
|
|
strcat(Str3," spurns your offering and leaves it on the ground.");
|
|
print1(Str3);
|
|
drop_at(m->x,m->y,o);
|
|
}
|
|
}
|
|
else {
|
|
strcat(Str3," doesn't care for your offering and drops it.");
|
|
print1(Str3);
|
|
drop_at(m->x,m->y,o);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* will clear all, not just one of an object. */
|
|
void conform_lost_object(pob obj)
|
|
{
|
|
if (obj != NULL) conform_lost_objects(obj->number,obj);
|
|
}
|
|
|
|
|
|
|
|
/* removes n of object from inventory; frees object if appropriate. */
|
|
|
|
void dispose_lost_objects(int n, pob obj)
|
|
{
|
|
int i,conformed=FALSE,subtracted=FALSE;
|
|
|
|
if (obj == NULL)
|
|
return;
|
|
for(i=0;i<MAXITEMS;i++)
|
|
if (Player.possessions[i] == obj) {
|
|
if (! subtracted) {
|
|
obj->number -= n;
|
|
subtracted = TRUE;
|
|
}
|
|
if (obj->number < 1) {
|
|
if (!conformed) {
|
|
conform_unused_object(obj);
|
|
conformed = TRUE;
|
|
}
|
|
Player.possessions[i] = NULL;
|
|
}
|
|
}
|
|
if (obj->number < 1)
|
|
free_obj( obj, TRUE );
|
|
}
|
|
|
|
|
|
/* removes n of object from inventory without freeing object.
|
|
Removes all instances of pointer (might be 2 handed weapon, etc) */
|
|
void conform_lost_objects(int n, pob obj)
|
|
{
|
|
int i,conformed=FALSE,subtracted=FALSE;
|
|
if (obj != NULL) for(i=0;i<MAXITEMS;i++)
|
|
if (Player.possessions[i] == obj) {
|
|
if (! subtracted) {
|
|
obj->number -= n;
|
|
subtracted = TRUE;
|
|
}
|
|
if (obj->number < 1) {
|
|
if (!conformed) {
|
|
conform_unused_object(obj);
|
|
conformed = TRUE;
|
|
}
|
|
Player.possessions[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* clears unused possession */
|
|
void conform_unused_object(pob obj)
|
|
{
|
|
if (obj->used) {
|
|
obj->used = FALSE;
|
|
item_use(obj);
|
|
inv_display_munge();
|
|
}
|
|
calc_melee();
|
|
}
|
|
|
|
|
|
/* select an item from inventory */
|
|
/* if itype is NULL_ITEM, any kind of item is acceptable.
|
|
if itype is CASH, any kind of item or '$' (cash) is acceptable.
|
|
if itype is FOOD, CORPSE or FOOD is acceptable, but only FOOD is
|
|
listed in the possibilities.
|
|
if itype is any other object type (eg SCROLL, POTION, etc.), only
|
|
that type of item is acceptable or is listed */
|
|
|
|
int item_is_selectable (Symbol itype, struct object * item)
|
|
{
|
|
if (!item) return FALSE;
|
|
|
|
if (CASH == itype) return TRUE;
|
|
if (NULL_ITEM == itype) return TRUE;
|
|
if (item->objchar == itype) return TRUE;
|
|
if (FOOD == itype && CORPSE == item->objchar) return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
int getitem (Symbol itype)
|
|
{
|
|
return getitem_prompt(0, itype);
|
|
}
|
|
|
|
int getitem_prompt (char * prompt, Symbol itype)
|
|
{
|
|
char key;
|
|
char *line3;
|
|
char invstr[64];
|
|
char selectstr[80];
|
|
int i, k;
|
|
int again;
|
|
int found = FALSE;
|
|
int drewmenu = FALSE;
|
|
|
|
found = ((itype == NULL_ITEM) || ((itype == CASH) && (Player.cash > 0)));
|
|
|
|
/* build invstr, which lists all valid selections that the user can make */
|
|
invstr[0] = 0;
|
|
|
|
k = 0;
|
|
for(i = 1; i < MAXITEMS; ++i)
|
|
{
|
|
if (item_is_selectable(itype, Player.possessions[i]))
|
|
{
|
|
found = TRUE;
|
|
invstr[k++] = index_to_key(i);
|
|
invstr[k] = 0;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
print3("Nothing appropriate.");
|
|
return ABORT;
|
|
}
|
|
|
|
if (itype == CASH)
|
|
{
|
|
invstr[k++] = CASH & 0xff;
|
|
invstr[k] = 0;
|
|
}
|
|
|
|
/* gotta let the user see what everything means... */
|
|
invstr[k++] = '?';
|
|
invstr[k] = 0;
|
|
|
|
line3 = NULL;
|
|
|
|
/* build prompt... */
|
|
selectstr[0] = 0;
|
|
if (prompt) strcpy(selectstr, prompt);
|
|
strcat(selectstr, "Select an item. (");
|
|
|
|
i = 0;
|
|
k = strlen(selectstr);
|
|
while (TRUE)
|
|
{
|
|
if ('?' == invstr[i]) break;
|
|
selectstr[k++] = invstr[i++];
|
|
selectstr[k++] = ',';
|
|
if (k > 75) break;
|
|
}
|
|
|
|
selectstr[k-1] = ')';
|
|
selectstr[k] = 0;
|
|
|
|
/* get input from the user */
|
|
do
|
|
{
|
|
again = FALSE;
|
|
|
|
key = cinema_interact(invstr, selectstr, " ? to display items", line3);
|
|
line3 = NULL;
|
|
|
|
if ('?' == key)
|
|
{
|
|
again = TRUE;
|
|
drewmenu = TRUE;
|
|
for (i = 1; i < MAXITEMS; ++i)
|
|
{
|
|
if (item_is_selectable(itype, Player.possessions[i]))
|
|
display_inventory_slot(i, FALSE);
|
|
}
|
|
}
|
|
else if ((CASH & 0xff) == key && (CASH != itype))
|
|
{
|
|
again = TRUE;
|
|
line3 = "You cannot select cash now.";
|
|
}
|
|
}
|
|
while (again);
|
|
|
|
if (drewmenu) xredraw();
|
|
if (-1 == key) return ABORT; /* cinema_interact() returns -1 for ESC */
|
|
if ((CASH & 0xff) == key) return CASHVALUE;
|
|
|
|
return key_to_index(key);
|
|
}
|
|
|
|
|
|
/* true if the numerical index based on 'a' == 1 turns out to be either
|
|
out of the range of the possessions array or a null item */
|
|
int badobject(char slotchar)
|
|
{
|
|
int slot = slotchar + 1 - 'a';
|
|
if ((slot<1) || (slot >= MAXITEMS)) return(TRUE);
|
|
else return(Player.possessions[slot] == NULL);
|
|
}
|
|
|
|
|
|
#ifndef MSDOS_SUPPORTED_ANTIQUE
|
|
/* this takes the numerical index directly for the same effect as badobject*/
|
|
int baditem(int slotnum)
|
|
{
|
|
if ((slotnum<1) || (slotnum >= MAXITEMS)) return(TRUE);
|
|
else return(Player.possessions[slotnum] == NULL);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
/* formerly add_item_to_pack */
|
|
void gain_item(pob o)
|
|
{
|
|
if (o->uniqueness == UNIQUE_MADE)
|
|
Objects[o->id].uniqueness = UNIQUE_TAKEN;
|
|
if (o->objchar == CASH) {
|
|
print2("You gained some cash.");
|
|
Player.cash += o->basevalue;
|
|
free_obj(o,TRUE);
|
|
dataprint();
|
|
}
|
|
else if (optionp(PACKADD)) {
|
|
if (! get_to_pack(o)) {
|
|
Player.possessions[O_UP_IN_AIR] = o;
|
|
do_inventory_control();
|
|
}
|
|
}
|
|
else {
|
|
Player.possessions[O_UP_IN_AIR] = o;
|
|
do_inventory_control();
|
|
}
|
|
}
|
|
|
|
/* tosses the item into the pack, making it the first reachable item */
|
|
void push_pack(pob o)
|
|
{
|
|
int i;
|
|
for (i = Player.packptr; i > 0; i--)
|
|
Player.pack[i] = Player.pack[i-1];
|
|
Player.pack[0] = o;
|
|
Player.packptr++;
|
|
}
|
|
|
|
/* Adds item to pack list */
|
|
void add_to_pack(pob o)
|
|
{
|
|
if (Player.packptr >= MAXPACK) {
|
|
print3("Your pack is full. The item drops to the ground.");
|
|
drop_at(Player.x,Player.y,o);
|
|
}
|
|
else {
|
|
push_pack(o);
|
|
print3("Putting item in pack.");
|
|
}
|
|
}
|
|
|
|
/* Adds item to pack list, maybe going into inventory mode if pack is full */
|
|
int get_to_pack(pob o)
|
|
{
|
|
if (Player.packptr >= MAXPACK) {
|
|
print3("Your pack is full.");
|
|
morewait();
|
|
return(FALSE);
|
|
}
|
|
else {
|
|
push_pack(o);
|
|
print3("Putting item in pack.");
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
int pack_item_cost(int index)
|
|
{
|
|
int cost;
|
|
if (index > 20) {
|
|
cost = 17;
|
|
}
|
|
else if (index > 15) {
|
|
cost = 7;
|
|
}
|
|
else cost = 2;
|
|
return cost;
|
|
}
|
|
|
|
/* WDT -- 'response' must be an index into the pack. */
|
|
void use_pack_item(int response, int slot)
|
|
{
|
|
pob item; int i;
|
|
i = pack_item_cost(response);
|
|
if (i > 10) {
|
|
cinema_scene("You begin to rummage through your pack.",NULL,NULL);
|
|
}
|
|
if (i > 5) {
|
|
cinema_scene("You search your pack for the item.",NULL,NULL);
|
|
}
|
|
print3("You take the item from your pack.");
|
|
morewait();
|
|
Command_Duration += i;
|
|
item = Player.possessions[slot] = Player.pack[response];
|
|
for(i=response;i<Player.packptr-1;i++)
|
|
Player.pack[i] = Player.pack[i+1];
|
|
Player.pack[--Player.packptr] = NULL;
|
|
|
|
if ((slot == O_READY_HAND || slot == O_WEAPON_HAND) &&
|
|
twohandedp(item->id))
|
|
{
|
|
if (Player.possessions[O_READY_HAND] == NULL)
|
|
Player.possessions[O_READY_HAND] = item;
|
|
if (Player.possessions[O_WEAPON_HAND] == NULL)
|
|
Player.possessions[O_WEAPON_HAND] = item;
|
|
}
|
|
if (item_useable(item,slot)) {
|
|
item->used = TRUE;
|
|
item_use(item);
|
|
inv_display_munge();
|
|
morewait();
|
|
if (item->number > 1) pack_extra_items(item);
|
|
}
|
|
}
|
|
|
|
/* WDT HACK! This ought to be in scr.c, along with its companion. However,
|
|
* right now it's only used in the function directly below. */
|
|
int aux_display_pack(int start_item, int slot)
|
|
{
|
|
int i=start_item, items;
|
|
char *depth_string;
|
|
|
|
menuclear();
|
|
#if 0
|
|
/* WDT: I decided to remove these lines, since the purpose of this routine
|
|
* is to generate a pack menu, not update the message line. This is
|
|
* especially important now that I'm making the inventory system use the
|
|
* new 'Cinema' message box (which will stop the message corruption
|
|
* problems that were epidemic). */
|
|
if (Player.packptr < 1) print3("Pack is empty.");
|
|
else if (Player.packptr <= start_item) print3("You see the leather at the bottom of the pack.");
|
|
#else
|
|
/* These cases are not terribly important, but they can happen. */
|
|
if (Player.packptr < 1 || Player.packptr <= start_item)
|
|
return start_item;
|
|
#endif
|
|
else
|
|
{
|
|
items = 0;
|
|
for(i=start_item;i<Player.packptr && items<ScreenLength-5;i++) {
|
|
if ( aux_slottable(Player.pack[i],slot) ) {
|
|
if (pack_item_cost(i) > 10)
|
|
depth_string = "**";
|
|
else if (pack_item_cost(i) > 5)
|
|
depth_string = "* ";
|
|
else depth_string = " ";
|
|
sprintf(Str1, " %c: %s %s\n", i + 'a', depth_string,
|
|
itemid(Player.pack[i]));
|
|
if (items == 0)
|
|
menuprint("Items in Pack:\n");
|
|
menuprint(Str1);
|
|
items++;
|
|
}
|
|
}
|
|
if (items == 0)
|
|
menuprint("You see nothing useful for that slot in the pack.");
|
|
else {
|
|
menuprint("\n*: Takes some time to reach; **: buried very deeply.");
|
|
}
|
|
showmenu();
|
|
}
|
|
return i;
|
|
}
|
|
|
|
/* takes something from pack, puts to slot,
|
|
* or to 'up-in-air', one of which at least must be empty */
|
|
int aux_take_from_pack(int slot)
|
|
{
|
|
char response,pack_item, last_item;
|
|
int quit = FALSE,ok=TRUE;
|
|
if (Player.possessions[slot] != NULL)
|
|
slot = O_UP_IN_AIR;
|
|
if (Player.possessions[slot] != NULL)
|
|
print3("slot is not empty!");
|
|
else if (Player.packptr < 1)
|
|
print3("Pack is empty!");
|
|
else {
|
|
pack_item = 0;
|
|
do {
|
|
ok = TRUE;
|
|
last_item = aux_display_pack(pack_item,slot);
|
|
if (last_item == Player.packptr && pack_item == 0 )
|
|
print1("Enter pack slot letter or ESCAPE to quit.");
|
|
else if (last_item == Player.packptr)
|
|
print1("Enter pack slot letter, - to go back, or ESCAPE to quit.");
|
|
else if (pack_item == 0)
|
|
print1("Enter pack slot letter, + to see more, or ESCAPE to quit.");
|
|
else
|
|
print1("Enter pack slot letter, + or - to see more, or ESCAPE to quit.");
|
|
response = mcigetc();
|
|
if (response == '?') {
|
|
/* WDT HACK -- display some help instead. */
|
|
print1("Help not implemented (sorry).");
|
|
morewait();
|
|
ok = FALSE;
|
|
}
|
|
else if (response == ESCAPE) quit = TRUE;
|
|
else if (response == '+') {
|
|
if (last_item < Player.packptr)
|
|
pack_item = last_item;
|
|
ok = FALSE;
|
|
}
|
|
else if (response == '-') {
|
|
/* WDT HACK: this _should_ make us page up. Sadly,
|
|
* I have no way of calculating how much I'll be paging up.
|
|
* This is fixable, but I have no idea how much work... As
|
|
* a hack, I'm just returning to the first page of the listing.
|
|
*/
|
|
pack_item = 0;
|
|
ok = FALSE;
|
|
}
|
|
else{
|
|
ok = ((response >= 'a') && (response < 'a'+Player.packptr));
|
|
if (ok) ok = slottable(Player.pack[response-'a'],slot);
|
|
}
|
|
} while (! ok);
|
|
if (! quit) {
|
|
use_pack_item(response - 'a',slot);
|
|
}
|
|
}
|
|
|
|
inv_display_munge();
|
|
|
|
return slot;
|
|
}
|
|
|
|
/* takes something from pack, puts to slot,
|
|
or to 'up-in-air', one of which at least must be empty */
|
|
int aux_top_take_from_pack(int slot, int display)
|
|
{
|
|
char response;
|
|
int quit = FALSE,ok=TRUE;
|
|
|
|
if (Player.possessions[slot] != NULL)
|
|
slot = O_UP_IN_AIR;
|
|
if (Player.possessions[slot] != NULL)
|
|
print3("slot is not empty!");
|
|
else if (Player.packptr == 0)
|
|
print3("Pack is empty!");
|
|
else {
|
|
do {
|
|
ok = TRUE;
|
|
print1("Enter pack slot letter, or ? to show pack, or ESCAPE to quit.");
|
|
response = mcigetc();
|
|
if (response == '?') {
|
|
display_pack();
|
|
inv_display_munge();
|
|
ok = FALSE;
|
|
}
|
|
else if (response == ESCAPE) quit = TRUE;
|
|
else{
|
|
ok = ((response >= 'a') && (response < 'a'+Player.packptr));
|
|
if (ok) ok = slottable(Player.pack[response-'a'],slot);
|
|
}
|
|
} while (! ok);
|
|
if (! quit) use_pack_item(response - 'a',slot);
|
|
}
|
|
return slot;
|
|
}
|
|
|
|
int take_from_pack(int slot, int display)
|
|
{
|
|
if (optionp(TOPINV)) return aux_top_take_from_pack(slot,display);
|
|
else return aux_take_from_pack(slot);
|
|
}
|
|
|
|
|
|
#ifndef MSDOS_SUPPORTED_ANTIQUE
|
|
/* General interface to inventory */
|
|
void item_inventory(int topline)
|
|
{
|
|
if (topline) {
|
|
display_possessions();
|
|
inventory_control();
|
|
}
|
|
else top_inventory_control();
|
|
}
|
|
#endif
|
|
|
|
|
|
void do_inventory_control(void)
|
|
{
|
|
if (optionp(TOPINV)) top_inventory_control();
|
|
else {
|
|
menuclear();
|
|
display_possessions();
|
|
inventory_control();
|
|
}
|
|
}
|
|
|
|
/* inventory_control assumes a few setup things have been done,
|
|
* like loading the O_UP_IN_AIR item, etc.
|
|
* Each action uses up a little time. If only inspection actions
|
|
* are taken, no time is used up. */
|
|
void inventory_control(void)
|
|
{
|
|
int slot = O_UP_IN_AIR,done=FALSE;
|
|
int response;
|
|
char letter;
|
|
#ifdef MSDOS_SUPPORTED_ANTIQUE
|
|
int simple = 0;
|
|
#endif
|
|
/* Start out assuming that we'll need to redraw. */
|
|
inv_display_munge();
|
|
clearmsg3();
|
|
|
|
do {
|
|
checkclear();
|
|
print1("Action [d,e,l,p,s,t,x,>,<,?,ESCAPE]:");
|
|
inv_display_refresh();
|
|
|
|
show_inventory_slot(slot,FALSE);
|
|
display_inventory_slot(O_UP_IN_AIR,FALSE);
|
|
move_slot(slot,slot,MAXITEMS);
|
|
response = mcigetc();
|
|
|
|
switch(response) {
|
|
case 12:
|
|
case 18: /* ^l, ^r */
|
|
display_possessions();
|
|
break;
|
|
case 'd':
|
|
if (Player.possessions[O_UP_IN_AIR] != NULL)
|
|
{
|
|
drop_from_slot(O_UP_IN_AIR);
|
|
display_inventory_slot(O_UP_IN_AIR, FALSE);
|
|
}
|
|
else if (Player.possessions[slot] != NULL)
|
|
{
|
|
drop_from_slot(slot);
|
|
show_inventory_slot(slot, FALSE);
|
|
}
|
|
else print3("Nothing in selected slot!");
|
|
Command_Duration++;
|
|
break;
|
|
case 'l':
|
|
Str1[0] = '\0';
|
|
if (Player.possessions[slot] != NULL) {
|
|
if (!strcmp(itemid(Player.possessions[slot]),
|
|
Player.possessions[slot]->objstr))
|
|
print3("You notice nothing new about it.");
|
|
else {
|
|
if (Player.possessions[slot]->uniqueness == COMMON)
|
|
strcat(Str1, "Your ");
|
|
strcat(Str1, itemid(Player.possessions[slot]));
|
|
if (Player.possessions[slot]->objchar == BOOTS)
|
|
strcat(Str1, " look like ");
|
|
else {
|
|
strcat(Str1, " looks like a");
|
|
letter = Player.possessions[slot]->objstr[0];
|
|
if (letter == 'a' || letter == 'A' || letter == 'e' ||
|
|
letter == 'E' || letter == 'i' || letter == 'I' ||
|
|
letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U')
|
|
strcat(Str1, "n ");
|
|
else
|
|
strcat(Str1, " ");
|
|
}
|
|
strcat(Str1, Player.possessions[slot]->objstr);
|
|
print3(Str1);
|
|
}
|
|
}
|
|
else print3("Nothing in selected slot!");
|
|
break;
|
|
case 'p':
|
|
if (Player.possessions[slot] != NULL)
|
|
{
|
|
put_to_pack(slot);
|
|
show_inventory_slot(slot, FALSE);
|
|
}
|
|
Command_Duration+=5;
|
|
break;
|
|
case 's':
|
|
display_pack();
|
|
morewait();
|
|
inv_display_munge();
|
|
Command_Duration+=5;
|
|
break;
|
|
case 't':
|
|
show_inventory_slot(take_from_pack(slot,TRUE), FALSE);
|
|
Command_Duration+=5;
|
|
break;
|
|
case 'e':
|
|
switch_to_slot(slot);
|
|
show_inventory_slot(O_UP_IN_AIR,FALSE);
|
|
show_inventory_slot(slot,FALSE);
|
|
Command_Duration+=2;
|
|
break;
|
|
case '\n':
|
|
case 'x':
|
|
switch_to_slot(slot);
|
|
show_inventory_slot(O_UP_IN_AIR,FALSE);
|
|
show_inventory_slot(slot,FALSE);
|
|
Command_Duration+=2;
|
|
done = (Player.possessions[O_UP_IN_AIR] == NULL);
|
|
break;
|
|
case 'j':
|
|
case '>':
|
|
case '2':
|
|
#if defined(KEY_DOWN)
|
|
case KEY_DOWN:
|
|
#endif
|
|
slot = move_slot(slot,slot+1,MAXITEMS);
|
|
break;
|
|
case 'k':
|
|
case '<':
|
|
case '8':
|
|
#if defined(KEY_UP)
|
|
case KEY_UP:
|
|
#endif
|
|
slot = move_slot(slot,slot-1,MAXITEMS);
|
|
break;
|
|
#ifdef KEY_HOME
|
|
case KEY_HOME:
|
|
#endif
|
|
case '-':
|
|
slot = move_slot(slot,0,MAXITEMS);
|
|
break;
|
|
#ifdef KEY_LL
|
|
case KEY_LL:
|
|
#endif
|
|
case '+':
|
|
slot = move_slot(slot,MAXITEMS-1,MAXITEMS);
|
|
break;
|
|
case '?':
|
|
menuclear();
|
|
menuprint("d:\tDrop up-in-air or current item\n");
|
|
menuprint("e:\tExchange current slot with up-in-air slot\n");
|
|
menuprint("l:\tLook at current item\n");
|
|
menuprint("p:\tPut up-in-air or current item in pack\n");
|
|
menuprint("s:\tShow contents of pack\n");
|
|
menuprint("t:\tTake something from pack into the\n\tcurrent or up-in-air slot\n");
|
|
menuprint("x:\tAs 'e', but exit if up-in-air slot finishes empty\n");
|
|
menuprint(">:\tMove down one slot/item\n");
|
|
menuprint("<:\tMove up one slot/item\n");
|
|
menuprint("?:\tDisplay help (this message + help file)\n");
|
|
menuprint("ESCAPE:\texit\n");
|
|
showmenu();
|
|
clearmsg();
|
|
print1("Display full help? (y/n)");
|
|
if (ynq1() == 'y')
|
|
inv_help();
|
|
inv_display_munge();
|
|
break;
|
|
case ESCAPE:
|
|
if (Player.possessions[O_UP_IN_AIR] != NULL) {
|
|
drop_at(Player.x,Player.y,Player.possessions[O_UP_IN_AIR]);
|
|
Player.possessions[O_UP_IN_AIR] = NULL;
|
|
print3("Object 'up in air' dropped.");
|
|
}
|
|
done = TRUE;
|
|
break;
|
|
default:
|
|
if (key_to_index(response) > 0) {
|
|
slot = move_slot(slot,key_to_index(response),MAXITEMS);
|
|
if (Player.possessions[slot] == NULL
|
|
&&
|
|
Player.possessions[O_UP_IN_AIR] == NULL) {
|
|
show_inventory_slot(take_from_pack(slot,TRUE), FALSE);
|
|
Command_Duration+=5;
|
|
}
|
|
else {
|
|
switch_to_slot(slot);
|
|
show_inventory_slot(slot,FALSE);
|
|
slot = O_UP_IN_AIR;
|
|
show_inventory_slot(slot,FALSE);
|
|
Command_Duration+=2;
|
|
}
|
|
}
|
|
}
|
|
calc_melee();
|
|
} while (! done);
|
|
xredraw();
|
|
}
|
|
|
|
|
|
/* Make it clear that the inventory window mmust be redrawn. */
|
|
static int inv_must_redraw;
|
|
static void inv_display_munge(void)
|
|
{
|
|
inv_must_redraw = TRUE;
|
|
}
|
|
|
|
static void inv_display_refresh(void)
|
|
{
|
|
if ( inv_must_redraw )
|
|
display_possessions();
|
|
inv_must_redraw = FALSE;
|
|
}
|
|
|
|
|
|
/* same as inventory_control, but only uses msg window for i/o*/
|
|
|
|
|
|
void top_inventory_control(void)
|
|
{
|
|
int slot = 0,done=FALSE,usedmenu=FALSE;
|
|
char response, letter;
|
|
clearmsg3();
|
|
do {
|
|
clearmsg1();
|
|
print1("Action [d,e,l,p,s,t,x,~,?,ESCAPE]:");
|
|
print2("'Up in air': ");
|
|
if (Player.possessions[O_UP_IN_AIR] == NULL) nprint2("NOTHING");
|
|
else nprint2(itemid(Player.possessions[O_UP_IN_AIR]));
|
|
response = (char) mcigetc();
|
|
|
|
switch(response) {
|
|
case 'd':
|
|
if (Player.possessions[O_UP_IN_AIR] != NULL)
|
|
drop_from_slot(O_UP_IN_AIR);
|
|
else {
|
|
slot = get_inventory_slot();
|
|
if (Player.possessions[slot] != NULL)
|
|
drop_from_slot(slot);
|
|
else print3("Nothing in selected slot!");
|
|
}
|
|
Command_Duration++;
|
|
break;
|
|
case 'l':
|
|
Str1[0] = '\0';
|
|
slot = get_inventory_slot();
|
|
if (Player.possessions[slot] != NULL) {
|
|
if (!strcmp(itemid(Player.possessions[slot]),
|
|
Player.possessions[slot]->objstr))
|
|
print3("You notice nothing new about it.");
|
|
else {
|
|
if (Player.possessions[slot]->uniqueness == COMMON)
|
|
strcat(Str1, "Your ");
|
|
strcat(Str1, itemid(Player.possessions[slot]));
|
|
if (Player.possessions[slot]->objchar == BOOTS)
|
|
strcat(Str1, " look like ");
|
|
else {
|
|
strcat(Str1, " looks like a");
|
|
letter = Player.possessions[slot]->objstr[0];
|
|
if (letter == 'a' || letter == 'A' || letter == 'e' ||
|
|
letter == 'E' || letter == 'i' || letter == 'I' ||
|
|
letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U')
|
|
strcat(Str1, "n ");
|
|
else
|
|
strcat(Str1, " ");
|
|
}
|
|
strcat(Str1, Player.possessions[slot]->objstr);
|
|
print3(Str1);
|
|
}
|
|
}
|
|
else print3("Nothing in selected slot!");
|
|
break;
|
|
case 'p':
|
|
if (Player.possessions[O_UP_IN_AIR] == NULL)
|
|
slot = get_inventory_slot();
|
|
else slot = O_UP_IN_AIR;
|
|
put_to_pack(slot);
|
|
Command_Duration+=5;
|
|
break;
|
|
case 's':
|
|
display_pack();
|
|
usedmenu = TRUE;
|
|
Command_Duration+=5;
|
|
break;
|
|
case 't':
|
|
slot = get_inventory_slot();
|
|
(void) take_from_pack(slot,FALSE);
|
|
Command_Duration+=5;
|
|
break;
|
|
case 'e':
|
|
slot = get_inventory_slot();
|
|
if ( slot == O_UP_IN_AIR ) break;
|
|
switch_to_slot(slot);
|
|
Command_Duration+=2;
|
|
break;
|
|
case 'x':
|
|
slot = get_inventory_slot();
|
|
if ( slot == O_UP_IN_AIR ) break;
|
|
switch_to_slot(slot);
|
|
Command_Duration+=2;
|
|
done = (Player.possessions[O_UP_IN_AIR] == NULL);
|
|
break;
|
|
case '~':
|
|
display_possessions();
|
|
inventory_control();
|
|
usedmenu = TRUE;
|
|
done = TRUE;
|
|
break;
|
|
case '?':
|
|
menuclear();
|
|
menuprint("d:\tDrop an item\n");
|
|
menuprint("e:\tExchange a slot with up-in-air slot\n");
|
|
menuprint("l:\tLook at an item\n");
|
|
menuprint("p:\tPut an item in pack\n");
|
|
menuprint("s:\tShow contents of pack\n");
|
|
menuprint("t:\tTake something from pack into a slot\n");
|
|
menuprint("x:\tAs 'e', above, exit if up-in-air slot finishes empty\n");
|
|
menuprint("~:\tEnter full-screen inventory mode\n");
|
|
menuprint("?:\tDisplay help (this message + help file)\n");
|
|
menuprint("ESCAPE:\texit\n");
|
|
showmenu();
|
|
clearmsg();
|
|
print1("Display full help? (y/n)");
|
|
if (ynq1() == 'y')
|
|
inv_help();
|
|
usedmenu=TRUE;
|
|
break;
|
|
case ESCAPE:
|
|
if (Player.possessions[O_UP_IN_AIR] != NULL) {
|
|
drop_at(Player.x,Player.y,Player.possessions[O_UP_IN_AIR]);
|
|
Player.possessions[O_UP_IN_AIR] = NULL;
|
|
print3("Object 'up in air' dropped.");
|
|
}
|
|
done = TRUE;
|
|
break;
|
|
}
|
|
calc_melee();
|
|
} while (! done);
|
|
if (usedmenu)
|
|
xredraw();
|
|
}
|
|
|
|
|
|
|
|
/* Let the user select a slot. */
|
|
int get_inventory_slot(void)
|
|
{
|
|
signed char response;
|
|
do {
|
|
clearmsg1();
|
|
print1("Which inventory slot ['-'='up-in-air' slot]?");
|
|
response = (signed char)mcigetc();
|
|
if ( response == ESCAPE || response == '-' )
|
|
return O_UP_IN_AIR;
|
|
else response = key_to_index(response);
|
|
} while (response != O_UP_IN_AIR);
|
|
return response;
|
|
}
|
|
|
|
|
|
/* returns some number between 0 and o->number */
|
|
int get_item_number(pob o)
|
|
{
|
|
int n=0;
|
|
if (o->number == 1)
|
|
return 1;
|
|
do {
|
|
clearmsg();
|
|
print1("How many? -- max ");
|
|
mnumprint(o->number);
|
|
nprint1(" :");
|
|
n = (int) parsenum("");
|
|
if (n>o->number) print3("Too many!");
|
|
else if (n<1) n = 0;
|
|
} while (n > o->number);
|
|
if (n < 1) n = 0;
|
|
return(n);
|
|
}
|
|
|
|
void drop_from_slot(int slot)
|
|
{
|
|
int n,waitflag;
|
|
if (Player.possessions[slot] != NULL) {
|
|
if(cursed(Player.possessions[slot]) == TRUE + TRUE)
|
|
print3("It sticks to your fingers!");
|
|
else {
|
|
n = get_item_number(Player.possessions[slot]);
|
|
if (n > 0) {
|
|
p_drop_at(Player.x,Player.y,n,Player.possessions[slot]);
|
|
waitflag = (Player.possessions[slot]->used &&
|
|
(Player.possessions[slot]->number == n));
|
|
conform_lost_objects(n,Player.possessions[slot]);
|
|
if (waitflag) morewait();
|
|
}
|
|
else print3("Didn't drop anything.");
|
|
}
|
|
}
|
|
else print3("Didn't drop anything.");
|
|
}
|
|
|
|
|
|
void put_to_pack(int slot)
|
|
{
|
|
int waitflag,num = 1;
|
|
pob temp,oslot = Player.possessions[slot];
|
|
if (oslot == NULL)
|
|
print3("Slot is empty!");
|
|
else if (cursed(oslot) == TRUE+TRUE)
|
|
print3("Item is cursed!");
|
|
else {
|
|
num = get_item_number(oslot);
|
|
if (num > 0) {
|
|
temp = split_item(num,oslot);
|
|
waitflag = (oslot->used && (oslot->number == num));
|
|
conform_lost_objects(num,oslot);
|
|
if (waitflag) morewait();
|
|
add_to_pack(temp);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* splits num off of item to make newitem which is returned */
|
|
/* something else (conform_lost_objects) has to reduce the actual
|
|
number value of item and Player.itemweight */
|
|
pob split_item(int num, pob item)
|
|
{
|
|
pob newitem=NULL;
|
|
if (item != NULL) {
|
|
newitem = copy_obj( item );
|
|
if (num <= item->number)
|
|
newitem->number = num;
|
|
/* else num > item->number, so return newitem with number = item->number */
|
|
newitem->used = FALSE; /* whether the original item was used or not */
|
|
}
|
|
return(newitem);
|
|
}
|
|
|
|
|
|
|
|
/* Trades contents of "up in air" slot with selected slot. One or both
|
|
may be null. If both slots are 'objequal' merges two groups into one
|
|
in the selected slot. If one slot is null and the number of the other
|
|
is greater than one, requests how many to move. */
|
|
|
|
void switch_to_slot(int slot)
|
|
{
|
|
pob oslot = Player.possessions[slot];
|
|
pob oair = Player.possessions[O_UP_IN_AIR];
|
|
pob otemp = NULL;
|
|
int slotnull,airnull,num=1,trade=FALSE,put=FALSE,take=FALSE,merge=FALSE;
|
|
int s2h=FALSE,a2h=FALSE;
|
|
|
|
/* ie, is cursed and in use */
|
|
if (slot == O_UP_IN_AIR)
|
|
print3("This action makes no sense!");
|
|
else if (cursed(oslot)==TRUE+TRUE) /* WDT: this is SICK!!!! TRUE doesn't
|
|
* add. */
|
|
print3("The object in that slot is cursed -- you can't get rid of it!");
|
|
else {
|
|
|
|
slotnull = (oslot == NULL);
|
|
airnull = (oair == NULL);
|
|
|
|
if (!slotnull)
|
|
s2h = (Player.possessions[O_READY_HAND] ==
|
|
Player.possessions[O_WEAPON_HAND]);
|
|
|
|
if (! airnull)
|
|
a2h = (twohandedp(oair->id) &&
|
|
((slot == O_READY_HAND) || (slot == O_WEAPON_HAND)));
|
|
|
|
|
|
/* figure out which action to take */
|
|
|
|
/* merge if both are same kind of object */
|
|
merge = objequal(oslot,oair);
|
|
|
|
take = ((!merge) && (!slotnull) && airnull);
|
|
|
|
put = ((!merge) && slotnull && (!airnull) && slottable(oair,slot));
|
|
|
|
trade = ((!merge) && (!slotnull) && (!airnull) && slottable(oair,slot));
|
|
|
|
if (merge) merge_item(slot);
|
|
|
|
else if (put) {
|
|
|
|
/* deal with a 2-handed weapon */
|
|
if (a2h) {
|
|
if (Player.possessions[O_READY_HAND] == NULL)
|
|
Player.possessions[O_READY_HAND] = oair;
|
|
if (Player.possessions[O_WEAPON_HAND] == NULL)
|
|
Player.possessions[O_WEAPON_HAND] = oair;
|
|
}
|
|
else Player.possessions[slot] = oair;
|
|
Player.possessions[O_UP_IN_AIR] = NULL;
|
|
if (item_useable(oair,slot)) {
|
|
oair->used = TRUE;
|
|
item_use(oair);
|
|
inv_display_munge();
|
|
morewait();
|
|
if (oair->number > 1) pack_extra_items(oair);
|
|
}
|
|
Player.possessions[O_UP_IN_AIR] = NULL;
|
|
}
|
|
|
|
else if (take) {
|
|
num = get_item_number(oslot);
|
|
if (num > 0) {
|
|
otemp = split_item(num,oslot);
|
|
dispose_lost_objects(num,oslot);
|
|
Player.possessions[O_UP_IN_AIR] = otemp;
|
|
}
|
|
if (s2h) {
|
|
if (Player.possessions[O_READY_HAND] == oslot)
|
|
Player.possessions[O_READY_HAND] = NULL;
|
|
if (Player.possessions[O_WEAPON_HAND] == oslot)
|
|
Player.possessions[O_WEAPON_HAND] = NULL;
|
|
}
|
|
}
|
|
|
|
else if (trade) {
|
|
|
|
/* first remove item from slot */
|
|
num = oslot->number;
|
|
conform_lost_objects(oslot->number,oslot);
|
|
oslot->number = num;
|
|
|
|
Player.possessions[O_UP_IN_AIR] = oslot;
|
|
|
|
Player.possessions[slot] = oair;
|
|
|
|
if (s2h) {
|
|
if (Player.possessions[O_READY_HAND] == oslot)
|
|
Player.possessions[O_READY_HAND] = NULL;
|
|
if (Player.possessions[O_WEAPON_HAND] == oslot)
|
|
Player.possessions[O_WEAPON_HAND] = NULL;
|
|
}
|
|
|
|
if (a2h) {
|
|
if (Player.possessions[O_READY_HAND] == NULL)
|
|
Player.possessions[O_READY_HAND] = oair;
|
|
if (Player.possessions[O_WEAPON_HAND] == NULL)
|
|
Player.possessions[O_WEAPON_HAND] = oair;
|
|
}
|
|
|
|
if (item_useable(oair,slot)) {
|
|
oair->used = TRUE;
|
|
item_use(oair);
|
|
inv_display_munge();
|
|
morewait();
|
|
if (oair->number > 1) pack_extra_items(oair);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/* merges the up-in-air items into the selected items */
|
|
|
|
void merge_item(int slot)
|
|
{
|
|
Player.possessions[slot]->number +=
|
|
Player.possessions[O_UP_IN_AIR]->number;
|
|
Player.possessions[O_UP_IN_AIR] = NULL;
|
|
}
|
|
|
|
|
|
/* are two objects equal except for their number field? */
|
|
/* returns false if either object is null */
|
|
int objequal(pob o, pob p)
|
|
{
|
|
if ((o == NULL) || (p == NULL)) return(FALSE);
|
|
else return(
|
|
(o->id == p->id) &&
|
|
/* DAG won't match corpses because they use charge for monster id, */
|
|
/* except for hornets which have mid == 0, so will stack. Prevent this. */
|
|
(o->id != CORPSEID) &&
|
|
(o->plus == p->plus) &&
|
|
(o->charge == 0) &&
|
|
(p->charge == 0) &&
|
|
(o->dmg == p->dmg) &&
|
|
(o->hit == p->hit) &&
|
|
(o->aux == p->aux) &&
|
|
(o->known == p->known) &&
|
|
(o->blessing == p->blessing) &&
|
|
(o->usef == p->usef) &&
|
|
(o->objstr == p->objstr )
|
|
);
|
|
|
|
}
|
|
|
|
/* criteria for being able to put some item in some slot */
|
|
int slottable(pob o, int slot)
|
|
{
|
|
int ok = TRUE;
|
|
if (o == NULL) ok = FALSE;
|
|
else if (slot == O_ARMOR) {
|
|
if (o->objchar != ARMOR) {
|
|
print3("Only armor can go in the armor slot!");
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
else if (slot == O_SHIELD) {
|
|
if (o->objchar != SHIELD) {
|
|
print3("Only a shield can go in the shield slot!");
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
else if (slot == O_BOOTS) {
|
|
if (o->objchar != BOOTS) {
|
|
print3("Only boots can go in the boots slot!");
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
else if (slot == O_CLOAK) {
|
|
if (o->objchar != CLOAK) {
|
|
print3("Only a cloak can go in the cloak slot!");
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
else if (slot >= O_RING1) {
|
|
if (o->objchar != RING) {
|
|
print3("Only a ring can go in a ring slot!");
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
return(ok);
|
|
}
|
|
|
|
|
|
/* whether or not an item o can be used in a slot. Assumes o can in
|
|
fact be placed in the slot. */
|
|
int item_useable(pob o, int slot)
|
|
{
|
|
/* don't have to check the object in the first if since only armor
|
|
can go in armor slot, cloak in cloak slot, etc */
|
|
|
|
if ((slot == O_ARMOR) ||
|
|
(slot == O_CLOAK) ||
|
|
(slot == O_SHIELD) ||
|
|
(slot == O_BOOTS) ||
|
|
(slot >= O_RING1))
|
|
return(TRUE);
|
|
|
|
/* weapon is useable if it is put in weapon hand or if it is two-handed
|
|
and put in either hand when the other also holds the weapon */
|
|
|
|
else if ((o->objchar == WEAPON) ||
|
|
(o->objchar == MISSILEWEAPON)) {
|
|
if (twohandedp(o->id) &&
|
|
((slot==O_READY_HAND)||(slot==O_WEAPON_HAND))) {
|
|
if (Player.possessions[O_READY_HAND] ==
|
|
Player.possessions[O_WEAPON_HAND]) {
|
|
print1("You heft the weapon and find you must use both hands.");
|
|
morewait();
|
|
return(TRUE);
|
|
}
|
|
else {
|
|
print1("This weapon is two-handed, so at the moment, ");
|
|
print2("you are just lugging it around....");
|
|
morewait();
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else return(slot == O_WEAPON_HAND);
|
|
}
|
|
else return(FALSE);
|
|
}
|
|
|
|
|
|
/* returns FALSE if not cursed, TRUE if cursed but not used,
|
|
TRUE + TRUE if cursed and used */
|
|
int cursed(pob obj)
|
|
{
|
|
return((obj == NULL) ?
|
|
FALSE :
|
|
((obj->blessing < 0) ?
|
|
(obj->used == TRUE) + TRUE :
|
|
FALSE));
|
|
}
|
|
|
|
|
|
/* returns true if item with id and charge is found in pack or in
|
|
inventory slot. charge is used to differentiate
|
|
corpses instead of aux, which is their food value. */
|
|
int find_item(pob *o, int id, int chargeval)
|
|
{
|
|
int i,found=FALSE;
|
|
*o=NULL;
|
|
for(i=1;((i<MAXITEMS)&&(! found));i++)
|
|
if (Player.possessions[i] != NULL)
|
|
if ((Player.possessions[i]->id == id) &&
|
|
((chargeval == -1) ||
|
|
(Player.possessions[i]->charge == chargeval))) {
|
|
*o = Player.possessions[i];
|
|
found = TRUE;
|
|
}
|
|
if (! found)
|
|
for(i=0;((i<Player.packptr)&&(! found));i++)
|
|
if (Player.pack[i] != NULL)
|
|
if ((Player.pack[i]->id == id) &&
|
|
((chargeval == -1) ||
|
|
(Player.pack[i]->charge == chargeval))) {
|
|
*o = Player.pack[i];
|
|
found = TRUE;
|
|
}
|
|
return(found);
|
|
}
|
|
|
|
|
|
/* returns true if item with id and charge is found in pack or in
|
|
inventory slot. Destroys item. charge is used to differentiate
|
|
corpses instead of aux, which is their food value. */
|
|
int find_and_remove_item(int id, int chargeval)
|
|
{
|
|
int i,found=FALSE;
|
|
pob o=NULL;
|
|
|
|
for(i=1;((i<MAXITEMS)&&(! found));i++)
|
|
if (Player.possessions[i] != NULL)
|
|
if ((Player.possessions[i]->id == id) &&
|
|
((chargeval == -1) ||
|
|
(Player.possessions[i]->charge == chargeval))) {
|
|
o = Player.possessions[i];
|
|
conform_lost_objects(1, o);
|
|
found = TRUE;
|
|
}
|
|
if (! found) for(i=0;((i<Player.packptr)&&(! found));i++)
|
|
if (Player.pack[i] != NULL)
|
|
if ((Player.pack[i]->id == id) &&
|
|
((chargeval == -1) ||
|
|
(Player.pack[i]->charge == chargeval))) {
|
|
Player.pack[i]->number--;
|
|
if (Player.pack[i]->number == 0) {
|
|
free_obj( Player.pack[i], TRUE );
|
|
Player.pack[i] = NULL;
|
|
}
|
|
found = TRUE;
|
|
}
|
|
fixpack();
|
|
return(found);
|
|
}
|
|
|
|
|
|
void lose_all_items(void)
|
|
{
|
|
int i;
|
|
print1("You notice that you are completely devoid of all possessions.");
|
|
morewait();
|
|
for(i=0;i<MAXITEMS;i++)
|
|
if (Player.possessions[i] != NULL) {
|
|
dispose_lost_objects(Player.possessions[i]->number,
|
|
Player.possessions[i]);
|
|
Player.possessions[i] = NULL;
|
|
}
|
|
for(i=0;i<MAXPACK;i++) {
|
|
if (Player.pack[i] != NULL)
|
|
free_obj( Player.pack[i], TRUE );
|
|
Player.pack[i] = NULL;
|
|
}
|
|
Player.packptr = 0;
|
|
calc_melee();
|
|
morewait();
|
|
}
|
|
|
|
|
|
/* prevents people from wielding 3 short swords, etc. */
|
|
void pack_extra_items(pob item)
|
|
{
|
|
pob extra=copy_obj( item );
|
|
extra->number = item->number-1;
|
|
extra->used = FALSE;
|
|
item->number = 1;
|
|
if (Player.packptr < MAXPACK) {
|
|
print3("Putting extra items back in pack.");
|
|
morewait();
|
|
push_pack(extra);
|
|
}
|
|
else if (Player.possessions[O_UP_IN_AIR] == NULL) {
|
|
print3("Extra copies of item are 'up in the air'");
|
|
Player.possessions[O_UP_IN_AIR] = extra;
|
|
}
|
|
else {
|
|
print3("No room for extra copies of item -- dropping them.");
|
|
drop_at(Player.x,Player.y,extra);
|
|
}
|
|
calc_melee();
|
|
}
|
|
|
|
|
|
/* makes sure Player.pack is OK, (used after sale from pack) */
|
|
void fixpack(void)
|
|
{
|
|
pob tpack[MAXPACK];
|
|
int i,tctr=0;
|
|
for(i=0;i<MAXPACK;i++) tpack[i] = NULL;
|
|
for(i=0;i<MAXPACK;i++)
|
|
if (Player.pack[i]!=NULL)
|
|
tpack[tctr++] = Player.pack[i];
|
|
for(i=0;i<MAXPACK;i++)
|
|
Player.pack[i]=tpack[i];
|
|
Player.packptr = tctr;
|
|
}
|
|
|
|
|
|
/* show slots, with appropriate additional displays if two-handed weapons */
|
|
/* are involved */
|
|
void show_inventory_slot(int slotnum, int topline)
|
|
{
|
|
if (!topline)
|
|
if (Player.possessions[O_READY_HAND] == Player.possessions[O_WEAPON_HAND] &&
|
|
(slotnum == O_READY_HAND || slotnum == O_WEAPON_HAND))
|
|
{
|
|
display_inventory_slot(O_READY_HAND, topline);
|
|
display_inventory_slot(O_WEAPON_HAND, topline);
|
|
}
|
|
else if (slotnum == O_UP_IN_AIR && Player.possessions[O_UP_IN_AIR] &&
|
|
twohandedp(Player.possessions[O_UP_IN_AIR]->id))
|
|
{
|
|
display_inventory_slot(O_READY_HAND, topline);
|
|
display_inventory_slot(O_WEAPON_HAND, topline);
|
|
display_inventory_slot(slotnum, topline);
|
|
}
|
|
else
|
|
display_inventory_slot(slotnum, topline);
|
|
else
|
|
display_inventory_slot(slotnum, topline);
|
|
}
|