1 /* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */
2 /* inv.c */
3 /* functions having to do with player item inventory */
4 
5 #ifdef MSDOS_SUPPORTED_ANTIQUE
6 # include "curses.h"
7 #else
8 # ifdef AMIGA
9 #  include <curses210.h>
10 # else
11 #  ifdef __FreeBSD__
12 #   include <ncurses.h>
13 #  else
14 #   include <curses.h>
15 #  endif
16 # endif
17 #endif
18 
19 #include "glob.h"
20 
21 /* drops money, heh heh */
drop_money()22 void drop_money()
23 {
24   pob money;
25 
26   /* WDT HACK!  Let me guess -- this is yet another memory leak, right? */
27   money = detach_money();
28   if (money != NULL) {
29     if (Current_Environment == E_CITY) {
30       print1("As soon as the money leaves your hand,");
31       print2("a horde of scrofulous beggars snatch it up and are gone!");
32     }
33     else drop_at(Player.x,Player.y,money);
34   }
35   else setgamestatus(SKIP_MONSTERS);
36 }
37 
38 
39 
40 /* returns some money from player back into "money" item.
41    for giving and dropping money */
detach_money()42 pob detach_money()
43 {
44   long c;
45   pob cash=NULL;
46   c = get_money(Player.cash);
47   if (c != ABORT) {
48     Player.cash -= c;
49     cash = ((pob) checkmalloc(sizeof(objtype)));
50     make_cash(cash,difficulty());
51     cash->basevalue = c;
52   }
53   return(cash);
54 }
55 
56 
57 /* gets a legal amount of money or ABORT */
get_money(limit)58 long get_money(limit)
59 long limit;
60 {
61   long c;
62   print1("How much? ");
63   c = parsenum();
64   if (c > limit) {
65     print3("Forget it, buddy.");
66     return(ABORT);
67   }
68   else return(c);
69 }
70 
71 
72 
73 /* pick up from some location x,y */
74 /* Lift entire itemlist off ground, pass it to inventory control, which
75    may drop things back onto the now null ground */
pickup_at(x,y)76 void pickup_at(x,y)
77 int x,y;
78 {
79   int quit = FALSE;
80   char response;
81   pol ol = Level->site[x][y].things;
82   pol temp;
83 
84   resetgamestatus(FAST_MOVE);
85 
86   Level->site[x][y].things = NULL;
87 
88   while (ol != NULL) {
89     if (! quit) {
90       clearmsg1();
91       print1("Pick up: ");
92       nprint1(itemid(ol->thing));
93       nprint1(" [ynq]: ");
94       response = ynq1();
95       quit = (response == 'q');
96     }
97     if (response == 'y') gain_item(ol->thing);
98     else drop_at(x,y,ol->thing);
99     temp = ol;
100     ol = ol->next;
101     temp->thing = NULL;
102     temp->next = NULL;
103     free((char *) temp);
104   }
105 }
106 
107 
108 /* WDT -- convert from a char (keypress) to an item index in
109  * player inventory */
110 /* Item identifiers, in this case the letters of the alphabet minus
111  * any letters already used for commands.  Yes, there are more here
112  * than could be needed, but I don't want to short myself for later.
113  */
114 signed char inventory_keymap[] = "-abcfghimnoqruvwyz";
key_to_index(key)115 int key_to_index(key)
116 signed char key;
117 {
118   int i;
119   assert( MAXITEMS>0 ); /* must have room for an item, or this loop will
120                          * die! */
121 
122   for (i=0; i<MAXITEMS; i++) {
123     if (key == inventory_keymap[i])
124       return (signed char)i;
125   }
126   return O_UP_IN_AIR;
127 }
128 
index_to_key(index)129 signed char index_to_key(index)
130 signed int index;
131 {
132   if ( index < MAXITEMS )
133     return inventory_keymap[index];
134   else return '-';
135 }
136 
137 
138 /* criteria for being able to put some item in some slot */
139 /* WDT -- why on earth does the 'slottable' function print stuff???? */
aux_slottable(o,slot)140 int aux_slottable(o,slot)
141 pob o;
142 int slot;
143 {
144   int ok = TRUE;
145   if (o == NULL) ok = FALSE;
146   else if (slot == O_ARMOR) {
147     if (o->objchar != ARMOR) {
148       ok = FALSE;
149     }
150   }
151   else if (slot == O_SHIELD) {
152     if (o->objchar != SHIELD) {
153       ok = FALSE;
154     }
155   }
156   else if (slot == O_BOOTS) {
157     if (o->objchar != BOOTS) {
158       ok = FALSE;
159     }
160   }
161   else if (slot == O_CLOAK) {
162     if (o->objchar != CLOAK) {
163       ok = FALSE;
164     }
165   }
166   else if (slot >= O_RING1) {
167     if (o->objchar != RING) {
168       ok = FALSE;
169     }
170   }
171   return(ok);
172 }
173 
174 /* put all of o on objlist at x,y on Level->depth */
175 /* Not necessarily dropped by character; just dropped... */
drop_at(x,y,o)176 void drop_at(x,y,o)
177 int x,y;
178 pob o;
179 {
180   pol tmp;
181   pob cpy;
182 
183   if (Current_Environment != E_COUNTRYSIDE) {
184     if ((Level->site[x][y].locchar != VOID_CHAR) &&
185 	(Level->site[x][y].locchar != ABYSS)) {
186       cpy = ((pob) checkmalloc(sizeof(objtype)));
187       tmp = ((pol) checkmalloc(sizeof(oltype)));
188       *cpy = *o;
189       cpy->used = FALSE;
190       tmp->thing = cpy;
191       tmp->next = Level->site[x][y].things;
192       Level->site[x][y].things = tmp;
193     }
194     else if (Level->site[x][y].p_locf == L_VOID_STATION)
195       setgamestatus(PREPARED_VOID);
196   }
197 }
198 
199 /* put n of o on objlist at x,y on Level->depth */
p_drop_at(x,y,n,o)200 void p_drop_at(x,y,n,o)
201 int x,y;
202 int n;
203 pob o;
204 {
205   pol tmp;
206   if (Current_Environment != E_COUNTRYSIDE)
207     if ((Level->site[x][y].locchar != VOID_CHAR) &&
208 	(Level->site[x][y].locchar != ABYSS)) {
209       tmp = ((pol) checkmalloc(sizeof(oltype)));
210       tmp->thing = ((pob) checkmalloc(sizeof(objtype)));
211       *(tmp->thing) = *o;
212       tmp->thing->used = FALSE;
213       tmp->thing->number = n;
214       print2("Dropped ");
215       nprint2(itemid(tmp->thing));
216       morewait();
217       tmp->next = Level->site[x][y].things;
218       Level->site[x][y].things = tmp;
219     }
220     else if (Level->site[x][y].p_locf == L_VOID_STATION)
221       setgamestatus(PREPARED_VOID);
222 }
223 
224 
225 /* returns a string for identified items */
itemid(obj)226 char *itemid(obj)
227 pob obj;
228 {
229   char tstr[80];
230   if (obj->objchar==CASH){
231     strcpy(Str4,obj->truename);
232     return(Str4);
233   }
234   else {
235     if (Objects[obj->id].known > obj->known)
236       obj->known = Objects[obj->id].known;
237 
238     setnumstr(obj,tstr);
239     strcpy(Str4,tstr);
240     if (obj->known == 0)
241       strcat(Str4,obj->objstr);
242     else if (obj->known == 1) {
243       if (obj->id == ARTIFACTID + 8 || obj->id == ARTIFACTID + 20 ||
244 	obj->id == ARTIFACTID + 21)
245 	strcat(Str4, "the ");
246       strcat(Str4,obj->truename);
247     }
248     else {
249       if (obj->id == ARTIFACTID + 8 || obj->id == ARTIFACTID + 20 ||
250 	obj->id == ARTIFACTID + 21)
251 	strcat(Str4, "the ");
252       if (obj->usef == I_NOTHING && Objects[obj->id].usef != I_NOTHING)
253 	strcat(Str4, "disenchanted ");
254       if (obj->blessing < 0) {
255 	strcat(Str4, "cursed ");
256 	strcat(Str4, obj->cursestr);
257       }
258       else if (obj->blessing > 0) {
259 	strcat(Str4, "blessed ");
260 	strcat(Str4, obj->truename);
261       }
262       else strcat(Str4,obj->truename);
263       if (obj->number > 1) strcat(Str4,"s");
264       switch (obj->objchar) {
265       case STICK:
266         setchargestr(obj,tstr);
267 	strcat(Str4,tstr);
268 	break;
269       case MISSILEWEAPON:
270       case ARMOR:
271       case RING:
272       case SHIELD:
273       case WEAPON:
274 	setplustr(obj,tstr);
275 	strcat(Str4, tstr);
276 	break;
277       default: strcat(Str4,""); break;
278       }
279     }
280     return(Str4);
281   }
282 }
283 
cashstr()284 char *cashstr()
285 {
286   if (difficulty() < 3) return("copper pieces");
287   else if (difficulty() < 5) return("silver pieces");
288   else if (difficulty() < 7) return("gold pieces");
289   else if (difficulty() < 8) return("semiprecious gems");
290   else if (difficulty() < 9) return("mithril pieces");
291   else if (difficulty() < 10) return("precious gems");
292   else return("orichalc pieces");
293 }
294 
295 /* return an object's plus as a string */
setplustr(obj,pstr)296 void setplustr(obj,pstr)
297 pob obj;
298 char *pstr;
299 {
300   pstr[0] = ' ';
301   pstr[1] = (obj->plus < 0 ? '-' : '+' );
302   if (abs(obj->plus) < 10) {
303     pstr[2] = '0' + abs(obj->plus);
304     pstr[3] = 0;
305   }
306   else {
307     pstr[2] = '0' + abs(obj->plus / 10);
308     pstr[3] = '0' + abs(obj->plus % 10);
309     pstr[4] = 0;
310   }
311 }
312 
313 /* return an object's number as a string */
setnumstr(obj,nstr)314 void setnumstr(obj,nstr)
315 pob obj;
316 char *nstr;
317 {
318   if (obj->number < 2)
319     nstr[0] = 0;
320   else if (obj->number < 10) {
321     nstr[0] = '0' + obj->number;
322     nstr[1] = 'x';
323     nstr[2] = ' ';
324     nstr[3] = 0;
325   }
326   else if (obj->number < 41) {
327     nstr[0] = '0' + ((int)(obj->number / 10));
328     nstr[1] = '0' + (obj->number % 10);
329     nstr[2] = 'x';
330     nstr[3] = ' ';
331     nstr[4] = 0;
332   }
333   else strcpy(nstr,"lots of ");
334 }
335 
336 
337 
338 
339 /* return object with charges */
setchargestr(obj,cstr)340 void setchargestr(obj,cstr)
341 pob obj;
342 char *cstr;
343 {
344   cstr[0] = ' ';
345   cstr[1] = '[';
346   if (obj->charge < 0) {
347     cstr[2]='d';
348     cstr[3]='e';
349     cstr[4]='a';
350     cstr[5]='d';
351     cstr[6]=']';
352     cstr[7]=0;
353   }
354   else if (obj->charge < 10) {
355     cstr[2] = '0' + obj->charge;
356     cstr[3] = ']';
357     cstr[4] = 0;
358   }
359   else {
360     cstr[2] = '0' + ((int)(obj->charge / 10));
361     cstr[3] = '0' + (obj->charge % 10);
362     cstr[4] = ']';
363     cstr[5] = 0;
364   }
365 }
366 
367 
give_money(m)368 void give_money(m)
369 struct monster *m;
370 {
371   pob cash;
372 
373   cash = detach_money();
374   if (cash == NULL)
375     setgamestatus(SKIP_MONSTERS);
376   else givemonster(m,cash);
377 }
378 
379 
380 
givemonster(m,o)381 void givemonster(m,o)
382 struct monster *m;
383 struct object *o;
384 {
385   /* special case -- give gem to LawBringer */
386   if ((m->id == LAWBRINGER) && (o->id == ARTIFACTID+21)) {
387     clearmsg();
388     print1("The LawBringer accepts the gem reverently.");
389     print2("He raises it above his head, where it bursts into lambent flame!");
390     morewait();
391     print1("You are bathed in a shimmering golden light.");
392     print2("You feel embedded in an infinite matrix of ordered energy.");
393     morewait();
394     if (Imprisonment > 0)
395       Imprisonment = 0;
396     if (Player.rank[ORDER] == -1) {
397       print2("You have been forgiven. You feel like a Paladin....");
398       Player.rank[ORDER] = 1;
399     }
400     Player.alignment += 200;
401     Player.pow = Player.maxpow = Player.pow * 2;
402     gain_experience(2000);
403     setgamestatus(GAVE_STARGEM);
404     /* WDT HACK!!!  Where else would this ever get freed?? */
405     free(o);
406   }
407   else {
408     if (m->uniqueness == COMMON) {
409       strcpy(Str3,"The ");
410       strcat(Str3,m->monstring);
411     }
412     else strcpy(Str3,m->monstring);
413 
414     if (m_statusp(m,GREEDY) || m_statusp(m,NEEDY)) {
415       m_pickup(m,o);
416       strcat(Str3," takes your gift");
417       print1(Str3);
418       Player.alignment++;
419       if (m_statusp(m,GREEDY) && (true_item_value(o) < (long) m->level*100))
420       nprint1("...but does not appear satisfied.");
421       else if (m_statusp(m,NEEDY) &&
422 	       (true_item_value(o) < (long) Level->depth*Level->depth))
423 	nprint1("...and looks chasteningly at you.");
424       else {
425 	nprint1("...and seems happy with it.");
426 	m_status_reset(m,HOSTILE);
427 	m_status_reset(m,GREEDY);
428 	m_status_reset(m,NEEDY);
429       }
430     }
431     else if (m_statusp(m,HUNGRY)) {
432 
433       if (((m->id == HORSE) && (o->id == FOODID+15)) || /* grain */
434 	  ((m->id != HORSE) &&
435 	   ((o->usef == I_FOOD) || (o->usef == I_POISON_FOOD)))) {
436 	strcat(Str3," wolfs down your food ... ");
437 	print1(Str3);
438 	m_status_reset(m,HUNGRY);
439 	m_status_reset(m,HOSTILE);
440 	if  (o->usef == I_POISON_FOOD) {
441 	  Player.alignment -= 2;
442 	  nprint1("...and chokes on the poisoned ration!");
443 	  morewait();
444 	  m_status_set(m,HOSTILE);
445 	  m_damage(m,100,POISON);
446 	}
447 	else nprint1("...and now seems satiated.");
448 	morewait();
449 	free((char *)o);
450       }
451       else {
452 	strcat(Str3," spurns your offering and leaves it on the ground.");
453 	print1(Str3);
454 	drop_at(m->x,m->y,o);
455       }
456     }
457     else {
458       strcat(Str3," doesn't care for your offering and drops it.");
459       print1(Str3);
460       drop_at(m->x,m->y,o);
461     }
462   }
463 }
464 
465 
466 
467 
468 /* will clear all, not just one of an object. */
conform_lost_object(obj)469 void conform_lost_object(obj)
470 pob obj;
471 {
472   if (obj != NULL) conform_lost_objects(obj->number,obj);
473 }
474 
475 
476 
477 /* removes n of object from inventory; frees object if appropriate. */
478 
dispose_lost_objects(n,obj)479 void dispose_lost_objects(n,obj)
480 int n;
481 pob obj;
482 {
483   int i,conformed=FALSE,subtracted=FALSE;
484 
485   if (obj == NULL)
486     return;
487   for(i=0;i<MAXITEMS;i++)
488     if (Player.possessions[i] == obj) {
489       if (! subtracted) {
490 	obj->number -= n;
491 	subtracted = TRUE;
492       }
493       if (obj->number < 1) {
494 	if (!conformed) {
495 	  conform_unused_object(obj);
496 	  conformed = TRUE;
497 	}
498 	Player.possessions[i] = NULL;
499       }
500     }
501   if (obj->number < 1)
502     free((char *) obj);
503 }
504 
505 
506 
507 
508 /* removes n of object from inventory without freeing object.
509    Removes all instances of pointer (might be 2 handed weapon, etc) */
conform_lost_objects(n,obj)510 void conform_lost_objects(n,obj)
511 int n;
512 pob obj;
513 {
514   int i,conformed=FALSE,subtracted=FALSE;
515   if (obj != NULL) for(i=0;i<MAXITEMS;i++)
516     if (Player.possessions[i] == obj) {
517       if (! subtracted) {
518 	obj->number -= n;
519 	subtracted = TRUE;
520       }
521       if (obj->number < 1) {
522 	if (!conformed) {
523 	  conform_unused_object(obj);
524 	  conformed = TRUE;
525 	}
526 	Player.possessions[i] = NULL;
527       }
528     }
529 }
530 
531 
532 /* clears unused possession */
conform_unused_object(obj)533 void conform_unused_object(obj)
534 pob obj;
535 {
536   if (obj->used) {
537     obj->used = FALSE;
538     item_use(obj);
539   }
540   calc_melee();
541 }
542 
543 
544 /* select an item from inventory */
545 /* if itype is NULL_ITEM, any kind of item is acceptable.
546    if itype is CASH, any kind of item or '$' (cash) is acceptable.
547    if itype is FOOD, CORPSE or FOOD is acceptable, but only FOOD is
548 listed in the possibilities.
549    if itype is any other object type (eg SCROLL, POTION, etc.), only
550 that type of item is acceptable or is listed */
551 
getitem(itype)552 int getitem(itype)
553 Symbol itype;
554 {
555   char invstr[64];
556   char key;
557   int i,k=0,ok=FALSE,drewmenu=FALSE,found=FALSE;
558 
559   found = ((itype == NULL_ITEM) || ((itype == CASH) && (Player.cash > 0)));
560   invstr[0]=0;
561   for(i=1;i<MAXITEMS;i++)
562     if (Player.possessions[i] != NULL)
563       if ((itype == NULL_ITEM) ||
564 	  (itype == CASH) ||
565 	  (Player.possessions[i]->objchar == itype) ||
566 	  ((itype == FOOD) && (Player.possessions[i]->objchar == CORPSE))) {
567 	   found = TRUE;
568 	   invstr[k++] = index_to_key(i);
569 	   invstr[k] = 0;
570 	 }
571   if ((itype == CASH) && found) {
572     invstr[k++] = '$';
573     invstr[k] = 0;
574   }
575   if (! found) {
576     print3("Nothing appropriate.");
577     return(ABORT);
578   }
579   else {
580     print2("Select an item [");
581     nprint2(invstr);
582     nprint2(",?] ");
583     while (! ok) {
584       key = (char) mcigetc();
585       if (key == '?') {
586 	drewmenu = TRUE;
587 	for (i=1;i<MAXITEMS;i++)
588 	  if (Player.possessions[i] != NULL)
589 	    if ((itype == NULL_ITEM) ||
590 		(itype == CASH) ||
591 		(Player.possessions[i]->objchar == itype) ||
592 		((itype == FOOD) &&
593 		 (Player.possessions[i]->objchar == CORPSE)))
594 	      display_inventory_slot(i,FALSE);
595       }
596       else if (key == ESCAPE) ok = TRUE;
597       else if (key == (CASH&0xff)) {
598 	if (itype == CASH) ok = TRUE;
599 	else {
600 	  print3("You cannot select cash now.");
601 	  ok = FALSE;
602 	}
603       }
604       else if ( !strmem(key,invstr) || key_to_index(key)==(signed char)-1 )
605 	print3("Nope! Try again [? for inventory, ESCAPE to quit]:");
606       else ok = TRUE;
607     }
608     if (drewmenu) xredraw();
609     if (key == ESCAPE) return(ABORT);
610     else if (key == (CASH&0xff)) return(CASHVALUE);
611     else return key_to_index(key);
612   }
613 }
614 
615 
616 /* true if the numerical index based on 'a' == 1 turns out to be either
617 out of the range of the possessions array or a null item */
badobject(slotchar)618 int badobject(slotchar)
619 char slotchar;
620 {
621   int slot = slotchar + 1 - 'a';
622   if ((slot<1) || (slot >= MAXITEMS)) return(TRUE);
623   else return(Player.possessions[slot] == NULL);
624 }
625 
626 
627 #ifndef MSDOS_SUPPORTED_ANTIQUE
628 /* this takes the numerical index directly for the same effect as badobject*/
baditem(slotnum)629 int baditem(slotnum)
630 int slotnum;
631 {
632   if ((slotnum<1) || (slotnum >= MAXITEMS)) return(TRUE);
633   else return(Player.possessions[slotnum] == NULL);
634 }
635 #endif
636 
637 
638 
639 /* formerly add_item_to_pack */
gain_item(o)640 void gain_item(o)
641 struct object *o;
642 {
643   if (o->uniqueness == UNIQUE_MADE)
644     Objects[o->id].uniqueness = UNIQUE_TAKEN;
645   if (o->objchar == CASH) {
646     print2("You gained some cash.");
647     Player.cash += o->basevalue;
648     free((char *)o);
649     dataprint();
650   }
651   else if (optionp(PACKADD)) {
652     if (! get_to_pack(o)) {
653       Player.possessions[O_UP_IN_AIR] = o;
654       do_inventory_control();
655     }
656   }
657   else {
658     Player.possessions[O_UP_IN_AIR] = o;
659     do_inventory_control();
660   }
661 }
662 
663 /* inserts the item at the start of the pack array */
push_pack(o)664 void push_pack(o)
665 pob o;
666 {
667   int i;
668   for (i = Player.packptr; i > 0; i--)
669     Player.pack[i] = Player.pack[i-1];
670   Player.pack[0] = o;
671   Player.packptr++;
672 }
673 
674 /* Adds item to pack list */
add_to_pack(o)675 void add_to_pack(o)
676 pob o;
677 {
678   if (Player.packptr >= MAXPACK) {
679     print3("Your pack is full. The item drops to the ground.");
680     drop_at(Player.x,Player.y,o);
681   }
682   else {
683     push_pack(o);
684     print3("Putting item in pack.");
685   }
686 }
687 
688 /* Adds item to pack list, maybe going into inventory mode if pack is full */
get_to_pack(o)689 int get_to_pack(o)
690 pob o;
691 {
692   if (Player.packptr >= MAXPACK) {
693     print3("Your pack is full.");
694     morewait();
695     return(FALSE);
696   }
697   else {
698     push_pack(o);
699     print3("Putting item in pack.");
700     return(TRUE);
701   }
702 }
703 
pack_item_cost(index)704 int pack_item_cost(index)
705 {
706   int cost;
707   if (index > 20) {
708     cost = 17;
709   }
710   else if (index > 15) {
711     cost = 7;
712   }
713   else cost = 2;
714   return cost;
715 }
716 
717 /* WDT -- 'response' must be an index into the pack. */
use_pack_item(response,slot)718 int use_pack_item(response,slot)
719 int response,slot;
720 {
721   pob item; int i;
722   i = pack_item_cost(response);
723   if (i > 10) {
724     print1("You begin to rummage through your pack.");
725     morewait();
726   }
727   if (i > 5) {
728     print1("You search your pack for the item.");
729     morewait();
730   }
731   print1("You take the item from your pack.");
732   morewait();
733   Command_Duration += i;
734   item = Player.possessions[slot] = Player.pack[response];
735   for(i=response;i<Player.packptr-1;i++)
736       Player.pack[i] = Player.pack[i+1];
737   Player.pack[--Player.packptr] = NULL;
738 
739   if ((slot == O_READY_HAND || slot == O_WEAPON_HAND) &&
740       twohandedp(item->id))
741   {
742     if (Player.possessions[O_READY_HAND] == NULL)
743         Player.possessions[O_READY_HAND] = item;
744     if (Player.possessions[O_WEAPON_HAND] == NULL)
745         Player.possessions[O_WEAPON_HAND] = item;
746   }
747   if (item_useable(item,slot)) {
748     item->used = TRUE;
749     item_use(item);
750     morewait();
751     if (item->number > 1) pack_extra_items(item);
752   }
753 }
754 
755 /* WDT HACK!  This ought to be in scr.c, along with its companion.  However,
756  * right now it's only used in the function directly below. */
aux_display_pack(start_item,slot)757 int aux_display_pack(start_item,slot)
758 int start_item,slot;
759 {
760   int i=start_item, items;
761   char *depth_string;
762   if (Player.packptr < 1) print3("Pack is empty.");
763   else if (Player.packptr <= start_item) print3("You see the leather at the bottom of the pack.");
764   else {
765     menuclear();
766     items = 0;
767     for(i=start_item;i<Player.packptr && items<ScreenLength-5;i++) {
768       if ( aux_slottable(Player.pack[i],slot) ) {
769 	if (pack_item_cost(i) > 10)
770           depth_string = "**";
771         else if (pack_item_cost(i) > 5)
772           depth_string = "* ";
773         else depth_string = "  ";
774         sprintf(Str1, "  %c: %s %s\n", i + 'a', depth_string,
775 		itemid(Player.pack[i]));
776 	if (items == 0)
777 	  menuprint("Items in Pack:\n");
778         menuprint(Str1);
779         items++;
780       }
781     }
782     if (items == 0)
783       menuprint("You see nothing useful for that slot in the pack.");
784     else {
785       menuprint("\n*: Takes some time to reach; **: buried very deeply.");
786     }
787     showmenu();
788   }
789   return i;
790 }
791 
792 /* takes something from pack, puts to slot,
793 or to 'up-in-air', one of which at least must be empty */
aux_take_from_pack(slot)794 int aux_take_from_pack(slot)
795 int slot;
796 {
797   char response,pack_item, last_item;
798   int i,quit = FALSE,ok=TRUE;
799   if (Player.possessions[slot] != NULL)
800     slot = O_UP_IN_AIR;
801   if (Player.possessions[slot] != NULL)
802     print3("slot is not empty!");
803   else if (Player.packptr < 1)
804     print3("Pack is empty!");
805   else {
806     pack_item = 0;
807     do {
808       ok = TRUE;
809       last_item = aux_display_pack(pack_item,slot);
810       if (last_item == Player.packptr && pack_item == 0 )
811         print1("Enter pack slot letter or ESCAPE to quit.");
812       else if (last_item == Player.packptr)
813         print1("Enter pack slot letter, - to go back, or ESCAPE to quit.");
814       else if (pack_item == 0)
815         print1("Enter pack slot letter, + to see more, or ESCAPE to quit.");
816       else
817         print1("Enter pack slot letter, + or - to see more, or ESCAPE to quit.");
818       response = mcigetc();
819       if (response == '?') {
820 	/* WDT HACK -- display some help instead. */
821         print1("Help not implemented (sorry).");
822 	morewait();
823 	ok = FALSE;
824       }
825       else if (response == ESCAPE) quit = TRUE;
826       else if (response == '+') {
827 	if (last_item < Player.packptr)
828 	  pack_item = last_item;
829         ok = FALSE;
830       }
831       else if (response == '-') {
832 	/* WDT HACK: this _should_ make us page up.  Sadly,
833 	 * I have no way of calculating how much I'll be paging up.
834 	 * This is fixable, but I have no idea how much work... */
835         pack_item = 0;
836 	ok = FALSE;
837       }
838       else{
839 	ok = ((response >= 'a') && (response < 'a'+Player.packptr));
840 	if (ok) ok = slottable(Player.pack[response-'a'],slot);
841       }
842     } while (! ok);
843     if (! quit) {
844       use_pack_item(response - 'a',slot);
845     }
846   }
847   display_possessions();
848   return slot;
849 }
850 
851 /* takes something from pack, puts to slot,
852 or to 'up-in-air', one of which at least must be empty */
aux_top_take_from_pack(slot,display)853 int aux_top_take_from_pack(slot,display)
854 int slot,display;
855 {
856   char response;
857   int i,quit = FALSE,ok=TRUE,displayed=FALSE;
858   pob item;
859   if (Player.possessions[slot] != NULL)
860     slot = O_UP_IN_AIR;
861   if (Player.possessions[slot] != NULL)
862     print3("slot is not empty!");
863   else if (Player.packptr == 0)
864     print3("Pack is empty!");
865   else {
866     do {
867       ok = TRUE;
868       print1("Enter pack slot letter, or ? to show pack, or ESCAPE to quit.");
869       response = mcigetc();
870       if (response == '?') {
871 	display_pack();
872 	displayed = TRUE;
873 	ok = FALSE;
874       }
875       else if (response == ESCAPE) quit = TRUE;
876       else{
877 	ok = ((response >= 'a') && (response < 'a'+Player.packptr));
878 	if (ok) ok = slottable(Player.pack[response-'a'],slot);
879       }
880     } while (! ok);
881     if (! quit) use_pack_item(response - 'a',slot);
882   }
883   if (displayed) {
884     if (display)
885       display_possessions();
886     else
887       xredraw();
888   }
889   return slot;
890 }
891 
take_from_pack(slot,display)892 int take_from_pack(slot,display)
893 int slot,display;
894 {
895   if (optionp(TOPINV)) aux_top_take_from_pack(slot,display);
896   else aux_take_from_pack(slot);
897 }
898 
899 
900 #ifndef MSDOS_SUPPORTED_ANTIQUE
901 /* General interface to inventory */
item_inventory(topline)902 void item_inventory(topline)
903 int topline;
904 {
905   if (topline) {
906     display_possessions();
907     inventory_control();
908   }
909   else top_inventory_control();
910 }
911 #endif
912 
913 
do_inventory_control()914 void do_inventory_control()
915 {
916   if (optionp(TOPINV)) top_inventory_control();
917   else {
918     menuclear();
919     display_possessions();
920     inventory_control();
921   }
922 }
923 
924 /* inventory_control assumes a few setup things have been done,
925    like displaying the slots, loading the O_UP_IN_AIR item, etc.
926 
927    Each action uses up a little time. If only inspection actions
928    are taken, no time is used up. */
929 
930 
inventory_control()931 void inventory_control()
932 {
933   int slot = 0,done=FALSE;
934   int response;
935   char letter;
936 #ifdef MSDOS_SUPPORTED_ANTIQUE
937   int simple = 0;
938 #endif
939   clearmsg3();
940   checkclear();
941   print1("Action [d,e,l,p,s,t,x,>,<,?,ESCAPE]:");
942   show_inventory_slot(slot,FALSE);
943   display_inventory_slot(O_UP_IN_AIR,FALSE);
944   do {
945     move_slot(slot,slot,MAXITEMS);
946     response = mcigetc();
947 
948     switch(response) {
949     case 12:
950     case 18: /* ^l, ^r */
951       display_possessions();
952       break;
953     case 'd':
954       if (Player.possessions[O_UP_IN_AIR] != NULL)
955       {
956 	drop_from_slot(O_UP_IN_AIR);
957 	display_inventory_slot(O_UP_IN_AIR, FALSE);
958       }
959       else if (Player.possessions[slot] != NULL)
960       {
961 	drop_from_slot(slot);
962 	show_inventory_slot(slot, FALSE);
963       }
964       else print3("Nothing in selected slot!");
965       Command_Duration++;
966       break;
967     case 'l':
968       Str1[0] = '\0';
969       if (Player.possessions[slot] != NULL) {
970 	if (!strcmp(itemid(Player.possessions[slot]),
971 	  Player.possessions[slot]->objstr))
972 	  print3("You notice nothing new about it.");
973 	else {
974 	  if (Player.possessions[slot]->uniqueness == COMMON)
975 	    strcat(Str1, "Your ");
976 	  strcat(Str1, itemid(Player.possessions[slot]));
977 	  if (Player.possessions[slot]->objchar == BOOTS)
978 	    strcat(Str1, " look like ");
979 	  else {
980 	    strcat(Str1, " looks like a");
981 	    letter = Player.possessions[slot]->objstr[0];
982 	    if (letter == 'a' || letter == 'A' || letter == 'e' ||
983 	      letter == 'E' || letter == 'i' || letter == 'I' ||
984 	      letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U')
985 	      strcat(Str1, "n ");
986 	    else
987 	      strcat(Str1, " ");
988 	  }
989 	  strcat(Str1, Player.possessions[slot]->objstr);
990 	  print3(Str1);
991 	}
992       }
993       else print3("Nothing in selected slot!");
994       break;
995     case 'p':
996       if (Player.possessions[slot] != NULL)
997       {
998 	put_to_pack(slot);
999 	show_inventory_slot(slot, FALSE);
1000       }
1001       Command_Duration+=5;
1002       break;
1003     case 's':
1004       display_pack();
1005       morewait();
1006       display_possessions();
1007       Command_Duration+=5;
1008       break;
1009     case 't':
1010       show_inventory_slot(take_from_pack(slot,TRUE), FALSE);
1011       Command_Duration+=5;
1012       break;
1013     case 'e':
1014       switch_to_slot(slot);
1015       show_inventory_slot(O_UP_IN_AIR,FALSE);
1016       show_inventory_slot(slot,FALSE);
1017       Command_Duration+=2;
1018       break;
1019     case '\n':
1020     case 'x':
1021       switch_to_slot(slot);
1022       show_inventory_slot(O_UP_IN_AIR,FALSE);
1023       show_inventory_slot(slot,FALSE);
1024       Command_Duration+=2;
1025       done = (Player.possessions[O_UP_IN_AIR] == NULL);
1026       break;
1027     case 'j':
1028     case '>':
1029     case '2':
1030 #if defined(KEY_DOWN)
1031     case KEY_DOWN:
1032 #endif
1033       slot = move_slot(slot,slot+1,MAXITEMS);
1034       break;
1035     case 'k':
1036     case '<':
1037     case '8':
1038 #if defined(KEY_UP)
1039     case KEY_UP:
1040 #endif
1041       slot = move_slot(slot,slot-1,MAXITEMS);
1042       break;
1043 #ifdef KEY_HOME
1044     case KEY_HOME:
1045 #endif
1046     case '-':
1047       slot = move_slot(slot,0,MAXITEMS);
1048       break;
1049 #ifdef KEY_LL
1050     case KEY_LL:
1051 #endif
1052     case '+':
1053       slot = move_slot(slot,MAXITEMS-1,MAXITEMS);
1054       break;
1055     case '?':
1056       menuclear();
1057       menuprint("d:\tDrop up-in-air or current item\n");
1058       menuprint("e:\tExchange current slot with up-in-air slot\n");
1059       menuprint("l:\tLook at current item\n");
1060       menuprint("p:\tPut up-in-air or current item in pack\n");
1061       menuprint("s:\tShow contents of pack\n");
1062       menuprint("t:\tTake something from pack into the\n\tcurrent or up-in-air slot\n");
1063       menuprint("x:\tAs 'e', but exit if up-in-air slot finishes empty\n");
1064       menuprint(">:\tMove down one slot/item\n");
1065       menuprint("<:\tMove up one slot/item\n");
1066       menuprint("?:\tDisplay help (this message + help file)\n");
1067       menuprint("ESCAPE:\texit\n");
1068       showmenu();
1069       clearmsg();
1070       print1("Display full help? (y/n)");
1071       if (ynq1() == 'y')
1072 	  inv_help();
1073       display_possessions();
1074       break;
1075     case ESCAPE:
1076       if (Player.possessions[O_UP_IN_AIR] != NULL) {
1077 	drop_at(Player.x,Player.y,Player.possessions[O_UP_IN_AIR]);
1078 	Player.possessions[O_UP_IN_AIR] = NULL;
1079 	print3("Object 'up in air' dropped.");
1080       }
1081       done = TRUE;
1082       break;
1083     default:
1084       if (key_to_index(response) > 0) {
1085         slot = move_slot(slot,key_to_index(response),MAXITEMS);
1086         if (Player.possessions[slot] == NULL
1087             &&
1088             Player.possessions[O_UP_IN_AIR] == NULL) {
1089           show_inventory_slot(take_from_pack(slot,TRUE), FALSE);
1090           Command_Duration+=5;
1091         }
1092         else {
1093           switch_to_slot(slot);
1094           show_inventory_slot(slot,FALSE);
1095 	  slot = O_UP_IN_AIR;
1096           show_inventory_slot(slot,FALSE);
1097           Command_Duration+=2;
1098         }
1099       }
1100     }
1101     calc_melee();
1102   } while (! done);
1103   xredraw();
1104 }
1105 
1106 
1107 
1108 
1109 
1110 
1111 
1112 /* same as inventory_control, but only uses msg window for i/o*/
1113 
1114 
top_inventory_control()1115 void top_inventory_control()
1116 {
1117   int slot = 0,done=FALSE,usedmenu=FALSE;
1118   char response, letter;
1119   clearmsg3();
1120   do {
1121     clearmsg1();
1122     print1("Action [d,e,l,p,s,t,x,~,?,ESCAPE]:");
1123     print2("'Up in air': ");
1124     if (Player.possessions[O_UP_IN_AIR] == NULL) nprint2("NOTHING");
1125     else nprint2(itemid(Player.possessions[O_UP_IN_AIR]));
1126     response = (char) mcigetc();
1127 
1128     switch(response) {
1129     case 'd':
1130       if (Player.possessions[O_UP_IN_AIR] != NULL)
1131 	drop_from_slot(O_UP_IN_AIR);
1132       else {
1133 	slot = get_inventory_slot();
1134 	if (Player.possessions[slot] != NULL)
1135 	  drop_from_slot(slot);
1136 	else print3("Nothing in selected slot!");
1137       }
1138       Command_Duration++;
1139       break;
1140     case 'l':
1141       Str1[0] = '\0';
1142       slot = get_inventory_slot();
1143       if (Player.possessions[slot] != NULL) {
1144 	if (!strcmp(itemid(Player.possessions[slot]),
1145 	  Player.possessions[slot]->objstr))
1146 	  print3("You notice nothing new about it.");
1147 	else {
1148 	  if (Player.possessions[slot]->uniqueness == COMMON)
1149 	    strcat(Str1, "Your ");
1150 	  strcat(Str1, itemid(Player.possessions[slot]));
1151 	  if (Player.possessions[slot]->objchar == BOOTS)
1152 	    strcat(Str1, " look like ");
1153 	  else {
1154 	    strcat(Str1, " looks like a");
1155 	    letter = Player.possessions[slot]->objstr[0];
1156 	    if (letter == 'a' || letter == 'A' || letter == 'e' ||
1157 	      letter == 'E' || letter == 'i' || letter == 'I' ||
1158 	      letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U')
1159 	      strcat(Str1, "n ");
1160 	    else
1161 	      strcat(Str1, " ");
1162 	  }
1163 	  strcat(Str1, Player.possessions[slot]->objstr);
1164 	  print3(Str1);
1165 	}
1166       }
1167       else print3("Nothing in selected slot!");
1168       break;
1169     case 'p':
1170       if (Player.possessions[O_UP_IN_AIR] == NULL)
1171 	slot = get_inventory_slot();
1172       else slot = O_UP_IN_AIR;
1173       put_to_pack(slot);
1174       Command_Duration+=5;
1175       break;
1176     case 's':
1177       display_pack();
1178       usedmenu = TRUE;
1179       Command_Duration+=5;
1180       break;
1181     case 't':
1182       slot = get_inventory_slot();
1183       (void) take_from_pack(slot,FALSE);
1184       Command_Duration+=5;
1185       break;
1186     case 'e':
1187       slot = get_inventory_slot();
1188       if ( slot == O_UP_IN_AIR ) break;
1189       switch_to_slot(slot);
1190       Command_Duration+=2;
1191       break;
1192     case 'x':
1193       slot = get_inventory_slot();
1194       if ( slot == O_UP_IN_AIR ) break;
1195       switch_to_slot(slot);
1196       Command_Duration+=2;
1197       done = (Player.possessions[O_UP_IN_AIR] == NULL);
1198       break;
1199     case '~':
1200       display_possessions();
1201       inventory_control();
1202       usedmenu = TRUE;
1203       done = TRUE;
1204       break;
1205     case '?':
1206       menuclear();
1207       menuprint("d:\tDrop an item\n");
1208       menuprint("e:\tExchange a slot with up-in-air slot\n");
1209       menuprint("l:\tLook at an item\n");
1210       menuprint("p:\tPut an item in pack\n");
1211       menuprint("s:\tShow contents of pack\n");
1212       menuprint("t:\tTake something from pack into a slot\n");
1213       menuprint("x:\tAs 'e', above, exit if up-in-air slot finishes empty\n");
1214       menuprint("~:\tEnter full-screen inventory mode\n");
1215       menuprint("?:\tDisplay help (this message + help file)\n");
1216       menuprint("ESCAPE:\texit\n");
1217       showmenu();
1218       clearmsg();
1219       print1("Display full help? (y/n)");
1220       if (ynq1() == 'y')
1221 	  inv_help();
1222       usedmenu=TRUE;
1223       break;
1224     case ESCAPE:
1225       if (Player.possessions[O_UP_IN_AIR] != NULL) {
1226 	drop_at(Player.x,Player.y,Player.possessions[O_UP_IN_AIR]);
1227 	Player.possessions[O_UP_IN_AIR] = NULL;
1228 	print3("Object 'up in air' dropped.");
1229       }
1230       done = TRUE;
1231       break;
1232     }
1233     calc_melee();
1234   } while (! done);
1235   if (usedmenu)
1236     xredraw();
1237 }
1238 
1239 
1240 
1241 /* Let the user select a slot. */
get_inventory_slot()1242 int get_inventory_slot()
1243 {
1244   signed char response;
1245   do {
1246     clearmsg1();
1247     print1("Which inventory slot ['-'='up-in-air' slot]?");
1248     response = (signed char)mcigetc();
1249     if ( response == ESCAPE || response == '-' )
1250       return O_UP_IN_AIR;
1251     else response = key_to_index(response);
1252   } while (response != O_UP_IN_AIR);
1253   return response;
1254 }
1255 
1256 
1257 /* returns some number between 0 and o->number */
get_item_number(o)1258 int get_item_number(o)
1259 pob o;
1260 {
1261   int n=0;
1262   if (o->number == 1)
1263     return 1;
1264   do {
1265     clearmsg();
1266     print1("How many? -- max ");
1267     mnumprint(o->number);
1268     nprint1(" :");
1269     n = (int) parsenum();
1270     if (n>o->number) print3("Too many!");
1271     else if (n<1) n = 0;
1272   } while (n > o->number);
1273   if (n < 1) n = 0;
1274   return(n);
1275 }
1276 
drop_from_slot(slot)1277 void drop_from_slot(slot)
1278 int slot;
1279 {
1280   int n,waitflag;
1281   if (Player.possessions[slot] != NULL) {
1282     if(cursed(Player.possessions[slot]) == TRUE + TRUE)
1283       print3("It sticks to your fingers!");
1284     else {
1285       n = get_item_number(Player.possessions[slot]);
1286       if (n > 0) {
1287 	p_drop_at(Player.x,Player.y,n,Player.possessions[slot]);
1288 	waitflag = (Player.possessions[slot]->used &&
1289 		    (Player.possessions[slot]->number == n));
1290 	conform_lost_objects(n,Player.possessions[slot]);
1291 	if (waitflag) morewait();
1292       }
1293       else print3("Didn't drop anything.");
1294     }
1295   }
1296   else print3("Didn't drop anything.");
1297 }
1298 
1299 
put_to_pack(slot)1300 void put_to_pack(slot)
1301 int slot;
1302 {
1303   int waitflag,num = 1;
1304   pob temp,oslot = Player.possessions[slot];
1305   if (oslot == NULL)
1306     print3("Slot is empty!");
1307   else if (cursed(oslot) == TRUE+TRUE)
1308     print3("Item is cursed!");
1309   else {
1310     num = get_item_number(oslot);
1311     if (num > 0) {
1312       temp = split_item(num,oslot);
1313       waitflag = (oslot->used && (oslot->number == num));
1314       conform_lost_objects(num,oslot);
1315       if (waitflag) morewait();
1316       add_to_pack(temp);
1317     }
1318   }
1319 }
1320 
1321 
1322 /* splits num off of item to make newitem which is returned */
1323 /* something else (conform_lost_objects) has to reduce the actual
1324    number value of item and Player.itemweight */
split_item(num,item)1325 pob split_item(num,item)
1326 int num;
1327 pob item;
1328 {
1329   pob newitem=NULL;
1330   if (item != NULL) {
1331     newitem = ((pob) checkmalloc(sizeof(objtype)));
1332     *newitem = *item;
1333     if (num <= item->number)
1334       newitem->number = num;
1335     /* else num > item->number, so return newitem with number = item->number */
1336     newitem->used = FALSE;	/* whether the original item was used or not */
1337   }
1338   return(newitem);
1339 }
1340 
1341 
1342 
1343 /* Trades contents of "up in air" slot with selected slot. One or both
1344 may be null. If both slots are 'objequal' merges two groups into one
1345 in the selected slot. If one slot is null and the number of the other
1346 is greater than one, requests how many to move. */
1347 
switch_to_slot(slot)1348 void switch_to_slot(slot)
1349 int slot;
1350 {
1351   pob oslot = Player.possessions[slot];
1352   pob oair = Player.possessions[O_UP_IN_AIR];
1353   pob otemp = NULL;
1354   int slotnull,airnull,num=1,trade=FALSE,put=FALSE,take=FALSE,merge=FALSE;
1355   int s2h=FALSE,a2h=FALSE;
1356 
1357   /* ie, is cursed and in use */
1358   if (slot == O_UP_IN_AIR)
1359     print3("This action makes no sense!");
1360   else if (cursed(oslot)==TRUE+TRUE)
1361     print3("The object in that slot is cursed -- you can't get rid of it!");
1362   else {
1363 
1364     slotnull = (oslot == NULL);
1365     airnull = (oair == NULL);
1366 
1367     if  (!slotnull)
1368       s2h = (Player.possessions[O_READY_HAND] ==
1369 	     Player.possessions[O_WEAPON_HAND]);
1370 
1371     if (! airnull)
1372       a2h = (twohandedp(oair->id) &&
1373 	     ((slot == O_READY_HAND) || (slot == O_WEAPON_HAND)));
1374 
1375 
1376     /* figure out which action to take */
1377 
1378     /* merge if both are same kind of object */
1379     merge = objequal(oslot,oair);
1380 
1381     take = ((!merge) && (!slotnull) && airnull);
1382 
1383     put = ((!merge) && slotnull && (!airnull) && slottable(oair,slot));
1384 
1385     trade = ((!merge) && (!slotnull) && (!airnull) && slottable(oair,slot));
1386 
1387     if (merge) merge_item(slot);
1388 
1389     else if (put) {
1390 
1391       /* deal with a 2-handed weapon */
1392       if (a2h) {
1393 	if (Player.possessions[O_READY_HAND] == NULL)
1394 	  Player.possessions[O_READY_HAND] = oair;
1395 	if (Player.possessions[O_WEAPON_HAND] == NULL)
1396 	  Player.possessions[O_WEAPON_HAND] = oair;
1397       }
1398       else Player.possessions[slot] = oair;
1399       Player.possessions[O_UP_IN_AIR] = NULL;
1400       if (item_useable(oair,slot)) {
1401 	oair->used = TRUE;
1402 	item_use(oair);
1403 	morewait();
1404 	if (oair->number > 1) pack_extra_items(oair);
1405       }
1406       Player.possessions[O_UP_IN_AIR] = NULL;
1407     }
1408 
1409     else if (take) {
1410       num = get_item_number(oslot);
1411       if (num > 0) {
1412 	otemp = split_item(num,oslot);
1413 	dispose_lost_objects(num,oslot);
1414 	Player.possessions[O_UP_IN_AIR] = otemp;
1415       }
1416       if (s2h) {
1417         if (Player.possessions[O_READY_HAND] == oslot)
1418           Player.possessions[O_READY_HAND] = NULL;
1419         if (Player.possessions[O_WEAPON_HAND] == oslot)
1420           Player.possessions[O_WEAPON_HAND] = NULL;
1421       }
1422     }
1423 
1424     else if (trade) {
1425 
1426       /* first remove item from slot */
1427       num = oslot->number;
1428       conform_lost_objects(oslot->number,oslot);
1429       oslot->number = num;
1430 
1431       Player.possessions[O_UP_IN_AIR] = oslot;
1432 
1433       Player.possessions[slot] = oair;
1434 
1435       if (s2h) {
1436         if (Player.possessions[O_READY_HAND] == oslot)
1437           Player.possessions[O_READY_HAND] = NULL;
1438         if (Player.possessions[O_WEAPON_HAND] == oslot)
1439           Player.possessions[O_WEAPON_HAND] = NULL;
1440       }
1441 
1442       if (a2h) {
1443 	if (Player.possessions[O_READY_HAND] == NULL)
1444 	  Player.possessions[O_READY_HAND] = oair;
1445 	if (Player.possessions[O_WEAPON_HAND] == NULL)
1446 	  Player.possessions[O_WEAPON_HAND] = oair;
1447       }
1448 
1449       if (item_useable(oair,slot)) {
1450 	oair->used = TRUE;
1451 	item_use(oair);
1452 	morewait();
1453 	if (oair->number > 1) pack_extra_items(oair);
1454       }
1455     }
1456   }
1457 }
1458 
1459 
1460 
1461 
1462 /* merges the up-in-air items into the selected items */
1463 
merge_item(slot)1464 void merge_item(slot)
1465 int slot;
1466 {
1467   Player.possessions[slot]->number +=
1468     Player.possessions[O_UP_IN_AIR]->number;
1469   Player.possessions[O_UP_IN_AIR] = NULL;
1470 }
1471 
1472 
1473 /* are two objects equal except for their number field? */
1474 /* returns false if either object is null */
objequal(o,p)1475 int objequal(o,p)
1476 struct object *o,*p;
1477 {
1478   if ((o == NULL) || (p == NULL)) return(FALSE);
1479   else return(
1480 	 (o->id == p->id) &&
1481 	 (o->plus == p->plus) &&
1482 	 (o->charge == 0) &&
1483 	 (p->charge == 0) &&
1484 	 (o->dmg == p->dmg) &&
1485 	 (o->hit == p->hit) &&
1486 	 (o->aux == p->aux) &&
1487 	 (o->known == p->known) &&
1488 	 (o->blessing == p->blessing) &&
1489 	 (o->usef == p->usef)
1490 	 );
1491 
1492 }
1493 
1494 /* criteria for being able to put some item in some slot */
slottable(o,slot)1495 int slottable(o,slot)
1496 pob o;
1497 int slot;
1498 {
1499   int ok = TRUE;
1500   if (o == NULL) ok = FALSE;
1501   else if (slot == O_ARMOR) {
1502     if (o->objchar != ARMOR) {
1503       print3("Only armor can go in the armor slot!");
1504       ok = FALSE;
1505     }
1506   }
1507   else if (slot == O_SHIELD) {
1508     if (o->objchar != SHIELD) {
1509       print3("Only a shield can go in the shield slot!");
1510       ok = FALSE;
1511     }
1512   }
1513   else if (slot == O_BOOTS) {
1514     if (o->objchar != BOOTS) {
1515       print3("Only boots can go in the boots slot!");
1516       ok = FALSE;
1517     }
1518   }
1519   else if (slot == O_CLOAK) {
1520     if (o->objchar != CLOAK) {
1521       print3("Only a cloak can go in the cloak slot!");
1522       ok = FALSE;
1523     }
1524   }
1525   else if (slot >= O_RING1) {
1526     if (o->objchar != RING) {
1527       print3("Only a ring can go in a ring slot!");
1528       ok = FALSE;
1529     }
1530   }
1531   return(ok);
1532 }
1533 
1534 
1535 /* ->;WDT HACK: this is bad factoring.  I want to use this, but it's
1536  * printing SILLY stuff out. */
1537 /* whether or not an item o can be used in a slot. Assumes o can in
1538    fact be placed in the slot. */
item_useable(o,slot)1539 int item_useable(o,slot)
1540 pob o;
1541 int slot;
1542 {
1543   /* don't have to check the object in the first if since only armor
1544   can go in armor slot, cloak in cloak slot, etc */
1545 
1546   if ((slot == O_ARMOR) ||
1547       (slot == O_CLOAK) ||
1548       (slot == O_SHIELD) ||
1549       (slot == O_BOOTS) ||
1550       (slot >= O_RING1))
1551     return(TRUE);
1552 
1553   /* weapon is useable if it is put in weapon hand or if it is two-handed
1554      and put in either hand when the other also holds the weapon */
1555 
1556   else if ((o->objchar == WEAPON) ||
1557 	   (o->objchar == MISSILEWEAPON)) {
1558     if (twohandedp(o->id) &&
1559 	((slot==O_READY_HAND)||(slot==O_WEAPON_HAND))) {
1560       if (Player.possessions[O_READY_HAND] ==
1561 	  Player.possessions[O_WEAPON_HAND]) {
1562 	print1("You heft the weapon and find you must use both hands.");
1563 	morewait();
1564 	return(TRUE);
1565       }
1566       else {
1567 	print1("This weapon is two-handed, so at the moment, ");
1568 	print2("you are just lugging it around....");
1569 	morewait();
1570 	return(FALSE);
1571       }
1572     }
1573     else return(slot == O_WEAPON_HAND);
1574   }
1575   else return(FALSE);
1576 }
1577 
1578 
1579 
1580 
1581 
1582 
1583 
1584 
1585 /* returns FALSE if not cursed, TRUE if cursed but not used,
1586    TRUE + TRUE if cursed and used */
cursed(obj)1587 int cursed(obj)
1588 pob obj;
1589 {
1590   return((obj == NULL) ?
1591 	 FALSE :
1592 	 ((obj->blessing < 0) ?
1593 	  (obj->used == TRUE) + TRUE :
1594 	  FALSE));
1595 }
1596 
1597 
1598 
1599 
1600 /* returns true if item with id and charge is found in pack or in
1601    inventory slot. charge is used to differentiate
1602    corpses instead of aux, which is their food value. */
find_item(o,id,chargeval)1603 int find_item(o,id,chargeval)
1604 int id,chargeval;
1605 pob *o;
1606 {
1607   int i,found=FALSE;
1608   *o=NULL;
1609   for(i=1;((i<MAXITEMS)&&(! found));i++)
1610     if (Player.possessions[i] != NULL)
1611       if ((Player.possessions[i]->id == id) &&
1612 	  ((chargeval == -1) ||
1613 	   (Player.possessions[i]->charge == chargeval))) {
1614 	*o = Player.possessions[i];
1615 	found = TRUE;
1616       }
1617   if (! found)
1618     for(i=0;((i<Player.packptr)&&(! found));i++)
1619       if (Player.pack[i] != NULL)
1620 	if ((Player.pack[i]->id == id) &&
1621 	    ((chargeval == -1) ||
1622 	     (Player.pack[i]->charge == chargeval))) {
1623 	  *o = Player.pack[i];
1624 	  found = TRUE;
1625 	}
1626   return(found);
1627 }
1628 
1629 
1630 
1631 /* returns true if item with id and charge is found in pack or in
1632    inventory slot. Destroys item. charge is used to differentiate
1633    corpses instead of aux, which is their food value. */
find_and_remove_item(id,chargeval)1634 int find_and_remove_item(id,chargeval)
1635 int id,chargeval;
1636 {
1637   int i,found=FALSE;
1638   pob o=NULL;
1639 
1640   for(i=1;((i<MAXITEMS)&&(! found));i++)
1641     if (Player.possessions[i] != NULL)
1642       if ((Player.possessions[i]->id == id) &&
1643 	  ((chargeval == -1) ||
1644 	   (Player.possessions[i]->charge == chargeval))) {
1645 	o = Player.possessions[i];
1646 	conform_lost_objects(1, o);
1647 	found = TRUE;
1648       }
1649   if (! found) for(i=0;((i<Player.packptr)&&(! found));i++)
1650     if (Player.pack[i] != NULL)
1651       if ((Player.pack[i]->id == id) &&
1652 	  ((chargeval == -1) ||
1653 	   (Player.pack[i]->charge == chargeval))) {
1654 	Player.pack[i]->number--;
1655 	if (Player.pack[i]->number == 0) {
1656 	  free((char *)Player.pack[i]);
1657 	  Player.pack[i] = NULL;
1658 	}
1659 	found = TRUE;
1660       }
1661   fixpack();
1662   return(found);
1663 }
1664 
1665 
1666 
1667 
lose_all_items()1668 void lose_all_items()
1669 {
1670   int i;
1671   print1("You notice that you are completely devoid of all possessions.");
1672   morewait();
1673   for(i=0;i<MAXITEMS;i++)
1674     if (Player.possessions[i] != NULL) {
1675       dispose_lost_objects(Player.possessions[i]->number,
1676 			   Player.possessions[i]);
1677       Player.possessions[i] = NULL;
1678     }
1679   for(i=0;i<MAXPACK;i++) {
1680     if (Player.pack[i] != NULL)
1681       free((char *) Player.pack[i]);
1682     Player.pack[i] = NULL;
1683   }
1684   Player.packptr = 0;
1685   calc_melee();
1686   morewait();
1687 }
1688 
1689 
1690 /* prevents people from wielding 3 short swords, etc. */
pack_extra_items(item)1691 void pack_extra_items(item)
1692 pob item;
1693 {
1694   pob extra=((pob) checkmalloc(sizeof(objtype)));
1695   *extra = *item;
1696   extra->number = item->number-1;
1697   extra->used = FALSE;
1698   item->number = 1;
1699   if (Player.packptr < MAXPACK) {
1700     print3("Putting extra items back in pack.");
1701     morewait();
1702     push_pack(extra);
1703   }
1704   else if (Player.possessions[O_UP_IN_AIR] == NULL) {
1705     print3("Extra copies of item are 'up in the air'");
1706     Player.possessions[O_UP_IN_AIR] = extra;
1707   }
1708   else {
1709     print3("No room for extra copies of item -- dropping them.");
1710     drop_at(Player.x,Player.y,extra);
1711   }
1712   calc_melee();
1713 }
1714 
1715 
1716 /* makes sure Player.pack is OK, (used after sale from pack) */
fixpack()1717 void fixpack()
1718 {
1719   pob tpack[MAXPACK];
1720   int i,tctr=0;
1721   for(i=0;i<MAXPACK;i++) tpack[i] = NULL;
1722   for(i=0;i<MAXPACK;i++)
1723     if (Player.pack[i]!=NULL)
1724       tpack[tctr++] = Player.pack[i];
1725   for(i=0;i<MAXPACK;i++)
1726     Player.pack[i]=tpack[i];
1727   Player.packptr = tctr;
1728 }
1729 
1730 
1731 /* show slots, with appropriate additional displays if two-handed weapons */
1732 /* are involved */
show_inventory_slot(slotnum,topline)1733 void show_inventory_slot(slotnum,topline)
1734 int slotnum;
1735 int topline;
1736 {
1737   if (!topline)
1738     if (Player.possessions[O_READY_HAND] == Player.possessions[O_WEAPON_HAND] &&
1739       (slotnum == O_READY_HAND || slotnum == O_WEAPON_HAND))
1740     {
1741       display_inventory_slot(O_READY_HAND, topline);
1742       display_inventory_slot(O_WEAPON_HAND, topline);
1743     }
1744     else if (slotnum == O_UP_IN_AIR && Player.possessions[O_UP_IN_AIR] &&
1745       twohandedp(Player.possessions[O_UP_IN_AIR]->id))
1746     {
1747       display_inventory_slot(O_READY_HAND, topline);
1748       display_inventory_slot(O_WEAPON_HAND, topline);
1749       display_inventory_slot(slotnum, topline);
1750     }
1751     else
1752       display_inventory_slot(slotnum, topline);
1753   else
1754     display_inventory_slot(slotnum, topline);
1755 }
1756