mirror of https://github.com/nealey/rogue
487 lines
8.4 KiB
C
487 lines
8.4 KiB
C
#include <curses.h>
|
|
#include <ctype.h>
|
|
#include "netprot.h"
|
|
|
|
/*
|
|
* Routines to deal with the pack
|
|
*
|
|
* @(#)packet.c 4.40 (Berkeley) 02/05/99
|
|
*/
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
THING *op, *lp;
|
|
bool from_floor;
|
|
|
|
from_floor = FALSE;
|
|
if (obj == NULL)
|
|
{
|
|
if ((obj = find_obj(Hero.y, Hero.x)) == NULL)
|
|
return;
|
|
from_floor = TRUE;
|
|
}
|
|
|
|
/*
|
|
* 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_ch());
|
|
chat(Hero.y, Hero.x) = (Proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
|
|
discard(obj);
|
|
msg("the scroll turns to dust as you pick it up");
|
|
return;
|
|
}
|
|
|
|
if (Pack == NULL)
|
|
{
|
|
Pack = obj;
|
|
obj->o_packch = pack_char();
|
|
Inpack++;
|
|
}
|
|
else
|
|
{
|
|
lp = NULL;
|
|
for (op = Pack; op != NULL; op = next(op))
|
|
{
|
|
if (op->o_type != obj->o_type)
|
|
lp = op;
|
|
else
|
|
{
|
|
while (op->o_type == obj->o_type && op->o_which != obj->o_which)
|
|
{
|
|
lp = op;
|
|
if (next(op) == NULL)
|
|
break;
|
|
else
|
|
op = next(op);
|
|
}
|
|
if (op->o_type == obj->o_type && op->o_which == obj->o_which)
|
|
if (ISMULT(op->o_type))
|
|
{
|
|
if (!pack_room(from_floor, obj))
|
|
return;
|
|
op->o_count++;
|
|
dump_it:
|
|
discard(obj);
|
|
obj = op;
|
|
lp = NULL;
|
|
goto out;
|
|
}
|
|
else if (obj->o_group)
|
|
{
|
|
lp = op;
|
|
while (op->o_type == obj->o_type
|
|
&& op->o_which == obj->o_which
|
|
&& op->o_group != obj->o_group)
|
|
{
|
|
lp = op;
|
|
if (next(op) == NULL)
|
|
break;
|
|
else
|
|
op = next(op);
|
|
}
|
|
if (op->o_type == obj->o_type
|
|
&& op->o_which == obj->o_which
|
|
&& op->o_group == obj->o_group)
|
|
{
|
|
op->o_count += obj->o_count;
|
|
Inpack--;
|
|
if (!pack_room(from_floor, obj))
|
|
return;
|
|
goto dump_it;
|
|
}
|
|
}
|
|
else
|
|
lp = op;
|
|
out:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (lp != NULL)
|
|
if (!pack_room(from_floor, obj))
|
|
return;
|
|
else
|
|
{
|
|
obj->o_packch = pack_char();
|
|
next(obj) = next(lp);
|
|
prev(obj) = lp;
|
|
if (next(lp) != NULL)
|
|
prev(next(lp)) = obj;
|
|
next(lp) = obj;
|
|
}
|
|
}
|
|
|
|
obj->o_flags |= ISFOUND;
|
|
|
|
/*
|
|
* If this was the object of something's desire, that monster will
|
|
* get mad and run at the hero.
|
|
*/
|
|
for (op = Mlist; op != NULL; op = next(op))
|
|
if (op->t_dest = &obj->o_pos)
|
|
op->t_dest = &Hero;
|
|
|
|
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), obj->o_packch);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* pack_room:
|
|
* See if there's room in the pack. If not, print out an
|
|
* appropriate message
|
|
*/
|
|
bool
|
|
pack_room(bool from_floor, THING *obj)
|
|
{
|
|
if (++Inpack > MAXPACK)
|
|
{
|
|
if (!Terse)
|
|
addmsg("there's ");
|
|
addmsg("no room");
|
|
if (!Terse)
|
|
addmsg(" in your pack");
|
|
endmsg();
|
|
if (from_floor)
|
|
move_msg(obj);
|
|
Inpack = MAXPACK;
|
|
return FALSE;
|
|
}
|
|
|
|
if (from_floor)
|
|
{
|
|
detach(Lvl_obj, obj);
|
|
mvaddch(Hero.y, Hero.x, floor_ch());
|
|
chat(Hero.y, Hero.x) = (Proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* leave_pack:
|
|
* Take an item out of the pack
|
|
*/
|
|
THING *
|
|
leave_pack(THING *obj, bool newobj, bool all)
|
|
{
|
|
THING *nobj;
|
|
|
|
Inpack--;
|
|
nobj = obj;
|
|
if (obj->o_count > 1 && !all)
|
|
{
|
|
Last_pick = obj;
|
|
obj->o_count--;
|
|
if (obj->o_group)
|
|
Inpack++;
|
|
if (newobj)
|
|
{
|
|
nobj = new_item();
|
|
*nobj = *obj;
|
|
next(nobj) = NULL;
|
|
prev(nobj) = NULL;
|
|
nobj->o_count = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Last_pick = NULL;
|
|
Pack_used[obj->o_packch - 'a'] = FALSE;
|
|
detach(Pack, obj);
|
|
}
|
|
return nobj;
|
|
}
|
|
|
|
/*
|
|
* pack_char:
|
|
* Return the next unused pack character.
|
|
*/
|
|
char
|
|
pack_char(void)
|
|
{
|
|
bool *bp;
|
|
|
|
for (bp = Pack_used; *bp; bp++)
|
|
continue;
|
|
*bp = TRUE;
|
|
return (bp - Pack_used) + 'a';
|
|
}
|
|
|
|
/*
|
|
* inventory:
|
|
* List what is in the pack. Return TRUE if there is something of
|
|
* the given type.
|
|
*/
|
|
bool
|
|
inventory(THING *list, int type)
|
|
{
|
|
static char inv_temp[MAXSTR];
|
|
|
|
N_objs = 0;
|
|
for (; list != NULL; list = next(list))
|
|
{
|
|
if (type && type != list->o_type && !(type == CALLABLE &&
|
|
list->o_type != FOOD && list->o_type != AMULET) &&
|
|
!(type == R_OR_S && (list->o_type == RING || list->o_type == STICK)))
|
|
continue;
|
|
N_objs++;
|
|
#ifdef MASTER
|
|
if (!list->o_packch)
|
|
strcpy(inv_temp, "%s");
|
|
else
|
|
#endif
|
|
sprintf(inv_temp, "%c) %%s", list->o_packch);
|
|
Msg_esc = TRUE;
|
|
if (add_line(inv_temp, inv_name(list, FALSE)) == ESCAPE)
|
|
{
|
|
Msg_esc = FALSE;
|
|
msg("");
|
|
return TRUE;
|
|
}
|
|
Msg_esc = 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)
|
|
{
|
|
THING *obj;
|
|
|
|
if (on(Player, ISLEVIT))
|
|
return;
|
|
|
|
obj = find_obj(Hero.y, Hero.x);
|
|
if (Move_on)
|
|
move_msg(obj);
|
|
else
|
|
switch (ch)
|
|
{
|
|
case GOLD:
|
|
if (obj == NULL)
|
|
return;
|
|
money(obj->o_goldval);
|
|
detach(Lvl_obj, obj);
|
|
discard(obj);
|
|
Proom->r_goldval = 0;
|
|
break;
|
|
default:
|
|
#ifdef MASTER
|
|
debug("Where did you pick a '%s' up???", unctrl(ch));
|
|
#endif
|
|
case ARMOR:
|
|
case POTION:
|
|
case FOOD:
|
|
case WEAPON:
|
|
case SCROLL:
|
|
case AMULET:
|
|
case RING:
|
|
case STICK:
|
|
add_pack((THING *) NULL, FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* move_msg:
|
|
* Print out the message if you are just moving onto an object
|
|
*/
|
|
void
|
|
move_msg(THING *obj)
|
|
{
|
|
if (!Terse)
|
|
addmsg("you ");
|
|
msg("moved onto %s", inv_name(obj, TRUE));
|
|
}
|
|
|
|
/*
|
|
* picky_inven:
|
|
* Allow player to inventory a single item
|
|
*/
|
|
void
|
|
picky_inven(void)
|
|
{
|
|
THING *obj;
|
|
char 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 (obj = Pack; obj != NULL; obj = next(obj))
|
|
if (mch == obj->o_packch)
|
|
{
|
|
msg("%c) %s", mch, inv_name(obj, FALSE));
|
|
return;
|
|
}
|
|
msg("'%s' not in pack", unctrl(mch));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* get_item:
|
|
* Pick something out of a pack for a purpose
|
|
*/
|
|
THING *
|
|
get_item(char *purpose, int type)
|
|
{
|
|
THING *obj;
|
|
char ch;
|
|
|
|
if (Pack == NULL)
|
|
msg("you aren't carrying anything");
|
|
else if (Again)
|
|
if (Last_pick)
|
|
return Last_pick;
|
|
else
|
|
msg("you ran out");
|
|
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)
|
|
{
|
|
reset_last();
|
|
After = FALSE;
|
|
msg("");
|
|
return NULL;
|
|
}
|
|
N_objs = 1; /* normal case: person types one char */
|
|
if (ch == '*')
|
|
{
|
|
Mpos = 0;
|
|
if (inventory(Pack, type) == 0)
|
|
{
|
|
After = FALSE;
|
|
return NULL;
|
|
}
|
|
continue;
|
|
}
|
|
for (obj = Pack; obj != NULL; obj = next(obj))
|
|
if (obj->o_packch == ch)
|
|
break;
|
|
if (obj == NULL)
|
|
{
|
|
msg("that's not a valid item");
|
|
continue;
|
|
}
|
|
else
|
|
return obj;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* money:
|
|
* Add or subtract gold from the pack
|
|
*/
|
|
void
|
|
money(int value)
|
|
{
|
|
Purse += value;
|
|
mvaddch(Hero.y, Hero.x, floor_ch());
|
|
chat(Hero.y, Hero.x) = (Proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
|
|
if (value > 0)
|
|
{
|
|
if (!Terse)
|
|
addmsg("you found ");
|
|
msg("%d gold pieces", value);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* floor_ch:
|
|
* Return the appropriate floor character for her room
|
|
*/
|
|
char
|
|
floor_ch(void)
|
|
{
|
|
if (Proom->r_flags & ISGONE)
|
|
return PASSAGE;
|
|
return (show_floor() ? FLOOR : ' ');
|
|
}
|
|
|
|
/*
|
|
* floor_at:
|
|
* Return the character at hero's position, taking See_floor
|
|
* into account
|
|
*/
|
|
char
|
|
floor_at(void)
|
|
{
|
|
char ch;
|
|
|
|
ch = chat(Hero.y, Hero.x);
|
|
if (ch == FLOOR)
|
|
ch = floor_ch();
|
|
return ch;
|
|
}
|
|
|
|
/*
|
|
* reset_last:
|
|
* Reset the last command when the current one is aborted
|
|
*/
|
|
void
|
|
reset_last(void)
|
|
{
|
|
Last_comm = L_last_comm;
|
|
Last_dir = L_last_dir;
|
|
Last_pick = L_last_pick;
|
|
}
|