Fandom

Wikihack

Source:Invent.c

2,034pages on
this wiki
Add New Page
Talk0

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.

Below is the full text to src/invent.c from NetHack 3.4.3. To link to a particular line, write [[invent.c#line123]], for example.

Top of file Edit

1.    /*	SCCS Id: @(#)invent.c	3.4	2003/12/02	*/
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
5.    #include "hack.h"
6.    
7.    #define NOINVSYM	'#'
8.    #define CONTAINED_SYM	'>'	/* designator for inside a container */
9.    
10.   #ifdef OVL1
11.   STATIC_DCL void NDECL(reorder_invent);
12.   STATIC_DCL boolean FDECL(mergable,(struct obj *,struct obj *));
13.   STATIC_DCL void FDECL(invdisp_nothing, (const char *,const char *));
14.   STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *));
15.   STATIC_DCL boolean FDECL(only_here, (struct obj *));
16.   #endif /* OVL1 */
17.   STATIC_DCL void FDECL(compactify,(char *));
18.   STATIC_DCL boolean FDECL(taking_off, (const char *));
19.   STATIC_DCL boolean FDECL(putting_on, (const char *));
20.   STATIC_PTR int FDECL(ckunpaid,(struct obj *));
21.   STATIC_PTR int FDECL(ckvalidcat,(struct obj *));
22.   static char FDECL(display_pickinv, (const char *,BOOLEAN_P, long *));
23.   #ifdef OVLB
24.   STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
25.   STATIC_DCL void NDECL(dounpaid);
26.   STATIC_DCL struct obj *FDECL(find_unpaid,(struct obj *,struct obj **));
27.   STATIC_DCL void FDECL(menu_identify, (int));
28.   STATIC_DCL boolean FDECL(tool_in_use, (struct obj *));
29.   #endif /* OVLB */
30.   STATIC_DCL char FDECL(obj_to_let,(struct obj *));
31.   
32.   #ifdef OVLB
33.   
34.   static int lastinvnr = 51;	/* 0 ... 51 (never saved&restored) */
35.   
36.   #ifdef WIZARD
37.   /* wizards can wish for venom, which will become an invisible inventory
38.    * item without this.  putting it in inv_order would mean venom would
39.    * suddenly become a choice for all the inventory-class commands, which
40.    * would probably cause mass confusion.  the test for inventory venom
41.    * is only WIZARD and not wizard because the wizard can leave venom lying
42.    * around on a bones level for normal players to find.
43.    */
44.   static char venom_inv[] = { VENOM_CLASS, 0 };	/* (constant) */
45.   #endif
46.   

assigninvlet Edit

47.   void
48.   assigninvlet(otmp)
49.   register struct obj *otmp;
50.   {
51.   	boolean inuse[52];
52.   	register int i;
53.   	register struct obj *obj;
54.   
55.   #ifdef GOLDOBJ
56.           /* There is only one of these in inventory... */        
57.           if (otmp->oclass == COIN_CLASS) {
58.   	    otmp->invlet = GOLD_SYM;
59.   	    return;
60.   	}
61.   #endif
62.   
63.   	for(i = 0; i < 52; i++) inuse[i] = FALSE;
64.   	for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
65.   		i = obj->invlet;
66.   		if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
67.   		if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
68.   		if(i == otmp->invlet) otmp->invlet = 0;
69.   	}
70.   	if((i = otmp->invlet) &&
71.   	    (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
72.   		return;
73.   	for(i = lastinvnr+1; i != lastinvnr; i++) {
74.   		if(i == 52) { i = -1; continue; }
75.   		if(!inuse[i]) break;
76.   	}
77.   	otmp->invlet = (inuse[i] ? NOINVSYM :
78.   			(i < 26) ? ('a'+i) : ('A'+i-26));
79.   	lastinvnr = i;
80.   }
81.   
82.   #endif /* OVLB */

reorder_invent Edit

83.   #ifdef OVL1
84.   
85.   /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
86.   #define inv_rank(o) ((o)->invlet ^ 040)
87.   
88.   /* sort the inventory; used by addinv() and doorganize() */
89.   STATIC_OVL void
90.   reorder_invent()
91.   {
92.   	struct obj *otmp, *prev, *next;
93.   	boolean need_more_sorting;
94.   
95.   	do {
96.   	    /*
97.   	     * We expect at most one item to be out of order, so this
98.   	     * isn't nearly as inefficient as it may first appear.
99.   	     */
100.  	    need_more_sorting = FALSE;
101.  	    for (otmp = invent, prev = 0; otmp; ) {
102.  		next = otmp->nobj;
103.  		if (next && inv_rank(next) < inv_rank(otmp)) {
104.  		    need_more_sorting = TRUE;
105.  		    if (prev) prev->nobj = next;
106.  		    else      invent = next;
107.  		    otmp->nobj = next->nobj;
108.  		    next->nobj = otmp;
109.  		    prev = next;
110.  		} else {
111.  		    prev = otmp;
112.  		    otmp = next;
113.  		}
114.  	    }
115.  	} while (need_more_sorting);
116.  }
117.  
118.  #undef inv_rank
119.  

merge_choice Edit

120.  /* scan a list of objects to see whether another object will merge with
121.     one of them; used in pickup.c when all 52 inventory slots are in use,
122.     to figure out whether another object could still be picked up */
123.  struct obj *
124.  merge_choice(objlist, obj)
125.  struct obj *objlist, *obj;
126.  {
127.  	struct monst *shkp;
128.  	int save_nocharge;
129.  
130.  	if (obj->otyp == SCR_SCARE_MONSTER)	/* punt on these */
131.  	    return (struct obj *)0;
132.  	/* if this is an item on the shop floor, the attributes it will
133.  	   have when carried are different from what they are now; prevent
134.  	   that from eliciting an incorrect result from mergable() */
135.  	save_nocharge = obj->no_charge;
136.  	if (objlist == invent && obj->where == OBJ_FLOOR &&
137.  		(shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) {
138.  	    if (obj->no_charge) obj->no_charge = 0;
139.  	    /* A billable object won't have its `unpaid' bit set, so would
140.  	       erroneously seem to be a candidate to merge with a similar
141.  	       ordinary object.  That's no good, because once it's really
142.  	       picked up, it won't merge after all.  It might merge with
143.  	       another unpaid object, but we can't check that here (depends
144.  	       too much upon shk's bill) and if it doesn't merge it would
145.  	       end up in the '#' overflow inventory slot, so reject it now. */
146.  	    else if (inhishop(shkp)) return (struct obj *)0;
147.  	}
148.  	while (objlist) {
149.  	    if (mergable(objlist, obj)) break;
150.  	    objlist = objlist->nobj;
151.  	}
152.  	obj->no_charge = save_nocharge;
153.  	return objlist;
154.  }
155.  

merged Edit

156.  /* merge obj with otmp and delete obj if types agree */
157.  int
158.  merged(potmp, pobj)
159.  struct obj **potmp, **pobj;
160.  {
161.  	register struct obj *otmp = *potmp, *obj = *pobj;
162.  
163.  	if(mergable(otmp, obj)) {
164.  		/* Approximate age: we do it this way because if we were to
165.  		 * do it "accurately" (merge only when ages are identical)
166.  		 * we'd wind up never merging any corpses.
167.  		 * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
168.  		 *
169.  		 * Don't do the age manipulation if lit.  We would need
170.  		 * to stop the burn on both items, then merge the age,
171.  		 * then restart the burn.
172.  		 */
173.  		if (!obj->lamplit)
174.  		    otmp->age = ((otmp->age*otmp->quan) + (obj->age*obj->quan))
175.  			    / (otmp->quan + obj->quan);
176.  
177.  		otmp->quan += obj->quan;
178.  #ifdef GOLDOBJ
179.                  /* temporary special case for gold objects!!!! */
180.  #endif
181.  		if (otmp->oclass == COIN_CLASS) otmp->owt = weight(otmp);
182.  		else otmp->owt += obj->owt;
183.  		if(!otmp->onamelth && obj->onamelth)
184.  			otmp = *potmp = oname(otmp, ONAME(obj));
185.  		obj_extract_self(obj);
186.  
187.  		/* really should merge the timeouts */
188.  		if (obj->lamplit) obj_merge_light_sources(obj, otmp);
189.  		if (obj->timed) obj_stop_timers(obj);	/* follows lights */
190.  
191.  		/* fixup for `#adjust' merging wielded darts, daggers, &c */
192.  		if (obj->owornmask && carried(otmp)) {
193.  		    long wmask = otmp->owornmask | obj->owornmask;
194.  
195.  		    /* Both the items might be worn in competing slots;
196.  		       merger preference (regardless of which is which):
197.  			 primary weapon + alternate weapon -> primary weapon;
198.  			 primary weapon + quiver -> primary weapon;
199.  			 alternate weapon + quiver -> alternate weapon.
200.  		       (Prior to 3.3.0, it was not possible for the two
201.  		       stacks to be worn in different slots and `obj'
202.  		       didn't need to be unworn when merging.) */
203.  		    if (wmask & W_WEP) wmask = W_WEP;
204.  		    else if (wmask & W_SWAPWEP) wmask = W_SWAPWEP;
205.  		    else if (wmask & W_QUIVER) wmask = W_QUIVER;
206.  		    else {
207.  			impossible("merging strangely worn items (%lx)", wmask);
208.  			wmask = otmp->owornmask;
209.  		    }
210.  		    if ((otmp->owornmask & ~wmask) != 0L) setnotworn(otmp);
211.  		    setworn(otmp, wmask);
212.  		    setnotworn(obj);
213.  		}
214.  #if 0
215.  		/* (this should not be necessary, since items
216.  		    already in a monster's inventory don't ever get
217.  		    merged into other objects [only vice versa]) */
218.  		else if (obj->owornmask && mcarried(otmp)) {
219.  		    if (obj == MON_WEP(otmp->ocarry)) {
220.  			MON_WEP(otmp->ocarry) = otmp;
221.  			otmp->owornmask = W_WEP;
222.  		    }
223.  		}
224.  #endif /*0*/
225.  
226.  		obfree(obj,otmp);	/* free(obj), bill->otmp */
227.  		return(1);
228.  	}
229.  	return 0;
230.  }
231.  

addinv_core1 Edit

232.  /*
233.  Adjust hero intrinsics as if this object was being added to the hero's
234.  inventory.  Called _before_ the object has been added to the hero's
235.  inventory.
236.  
237.  This is called when adding objects to the hero's inventory normally (via
238.  addinv) or when an object in the hero's inventory has been polymorphed
239.  in-place.
240.  
241.  It may be valid to merge this code with with addinv_core2().
242.  */
243.  void
244.  addinv_core1(obj)
245.  struct obj *obj;
246.  {
247.  	if (obj->oclass == COIN_CLASS) {
248.  #ifndef GOLDOBJ
249.  		u.ugold += obj->quan;
250.  #else
251.  		flags.botl = 1;
252.  #endif
253.  	} else if (obj->otyp == AMULET_OF_YENDOR) {
254.  		if (u.uhave.amulet) impossible("already have amulet?");
255.  		u.uhave.amulet = 1;
256.  	} else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
257.  		if (u.uhave.menorah) impossible("already have candelabrum?");
258.  		u.uhave.menorah = 1;
259.  	} else if (obj->otyp == BELL_OF_OPENING) {
260.  		if (u.uhave.bell) impossible("already have silver bell?");
261.  		u.uhave.bell = 1;
262.  	} else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
263.  		if (u.uhave.book) impossible("already have the book?");
264.  		u.uhave.book = 1;
265.  	} else if (obj->oartifact) {
266.  		if (is_quest_artifact(obj)) {
267.  		    if (u.uhave.questart)
268.  			impossible("already have quest artifact?");
269.  		    u.uhave.questart = 1;
270.  		    artitouch();
271.  		}
272.  		set_artifact_intrinsic(obj, 1, W_ART);
273.  	}
274.  }
275.  

addinv_core2 Edit

276.  /*
277.  Adjust hero intrinsics as if this object was being added to the hero's
278.  inventory.  Called _after_ the object has been added to the hero's
279.  inventory.
280.  
281.  This is called when adding objects to the hero's inventory normally (via
282.  addinv) or when an object in the hero's inventory has been polymorphed
283.  in-place.
284.  */
285.  void
286.  addinv_core2(obj)
287.  struct obj *obj;
288.  {
289.  	if (confers_luck(obj)) {
290.  		/* new luckstone must be in inventory by this point
291.  		 * for correct calculation */
292.  		set_moreluck();
293.  	}
294.  }
295.  

addinv Edit

296.  /*
297.  Add obj to the hero's inventory.  Make sure the object is "free".
298.  Adjust hero attributes as necessary.
299.  */
300.  struct obj *
301.  addinv(obj)
302.  struct obj *obj;
303.  {
304.  	struct obj *otmp, *prev;
305.  
306.  	if (obj->where != OBJ_FREE)
307.  	    panic("addinv: obj not free");
308.  	obj->no_charge = 0;	/* not meaningful for invent */
309.  
310.  	addinv_core1(obj);
311.  #ifndef GOLDOBJ
312.  	/* if handed gold, we're done */
313.  	if (obj->oclass == COIN_CLASS)
314.  	    return obj;
315.  #endif
316.  
317.  	/* merge if possible; find end of chain in the process */
318.  	for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
319.  	    if (merged(&otmp, &obj)) {
320.  		obj = otmp;
321.  		goto added;
322.  	    }
323.  	/* didn't merge, so insert into chain */
324.  	if (flags.invlet_constant || !prev) {
325.  	    if (flags.invlet_constant) assigninvlet(obj);
326.  	    obj->nobj = invent;		/* insert at beginning */
327.  	    invent = obj;
328.  	    if (flags.invlet_constant) reorder_invent();
329.  	} else {
330.  	    prev->nobj = obj;		/* insert at end */
331.  	    obj->nobj = 0;
332.  	}
333.  	obj->where = OBJ_INVENT;
334.  
335.  added:
336.  	addinv_core2(obj);
337.  	carry_obj_effects(obj);		/* carrying affects the obj */
338.  	update_inventory();
339.  	return(obj);
340.  }
341.  

carry_obj_effects Edit

342.  /*
343.   * Some objects are affected by being carried.
344.   * Make those adjustments here. Called _after_ the object
345.   * has been added to the hero's or monster's inventory,
346.   * and after hero's intrinsics have been updated.
347.   */
348.  void
349.  carry_obj_effects(obj)
350.  struct obj *obj;
351.  {
352.  	/* Cursed figurines can spontaneously transform
353.  	   when carried. */
354.  	if (obj->otyp == FIGURINE) {
355.  		if (obj->cursed
356.  	    	    && obj->corpsenm != NON_PM
357.  	    	    && !dead_species(obj->corpsenm,TRUE)) {
358.  			attach_fig_transform_timeout(obj);
359.  		    }
360.  	}
361.  }
362.  
363.  #endif /* OVL1 */

hold_another_object Edit

364.  #ifdef OVLB
365.  
366.  /* Add an item to the inventory unless we're fumbling or it refuses to be
367.   * held (via touch_artifact), and give a message.
368.   * If there aren't any free inventory slots, we'll drop it instead.
369.   * If both success and failure messages are NULL, then we're just doing the
370.   * fumbling/slot-limit checking for a silent grab.  In any case,
371.   * touch_artifact will print its own messages if they are warranted.
372.   */
373.  struct obj *
374.  hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
375.  struct obj *obj;
376.  const char *drop_fmt, *drop_arg, *hold_msg;
377.  {
378.  	char buf[BUFSZ];
379.  
380.  	if (!Blind) obj->dknown = 1;	/* maximize mergibility */
381.  	if (obj->oartifact) {
382.  	    /* place_object may change these */
383.  	    boolean crysknife = (obj->otyp == CRYSKNIFE);
384.  	    int oerode = obj->oerodeproof;
385.  	    boolean wasUpolyd = Upolyd;
386.  
387.  	    /* in case touching this object turns out to be fatal */
388.  	    place_object(obj, u.ux, u.uy);
389.  
390.  	    if (!touch_artifact(obj, &youmonst)) {
391.  		obj_extract_self(obj);	/* remove it from the floor */
392.  		dropy(obj);		/* now put it back again :-) */
393.  		return obj;
394.  	    } else if (wasUpolyd && !Upolyd) {
395.  		/* loose your grip if you revert your form */
396.  		if (drop_fmt) pline(drop_fmt, drop_arg);
397.  		obj_extract_self(obj);
398.  		dropy(obj);
399.  		return obj;
400.  	    }
401.  	    obj_extract_self(obj);
402.  	    if (crysknife) {
403.  		obj->otyp = CRYSKNIFE;
404.  		obj->oerodeproof = oerode;
405.  	    }
406.  	}
407.  	if (Fumbling) {
408.  	    if (drop_fmt) pline(drop_fmt, drop_arg);
409.  	    dropy(obj);
410.  	} else {
411.  	    long oquan = obj->quan;
412.  	    int prev_encumbr = near_capacity();	/* before addinv() */
413.  
414.  	    /* encumbrance only matters if it would now become worse
415.  	       than max( current_value, stressed ) */
416.  	    if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER;
417.  	    /* addinv() may redraw the entire inventory, overwriting
418.  	       drop_arg when it comes from something like doname() */
419.  	    if (drop_arg) drop_arg = strcpy(buf, drop_arg);
420.  
421.  	    obj = addinv(obj);
422.  	    if (inv_cnt() > 52
423.  		    || ((obj->otyp != LOADSTONE || !obj->cursed)
424.  			&& near_capacity() > prev_encumbr)) {
425.  		if (drop_fmt) pline(drop_fmt, drop_arg);
426.  		/* undo any merge which took place */
427.  		if (obj->quan > oquan) obj = splitobj(obj, oquan);
428.  		dropx(obj);
429.  	    } else {
430.  		if (flags.autoquiver && !uquiver && !obj->owornmask &&
431.  			(is_missile(obj) ||
432.  			    ammo_and_launcher(obj, uwep) ||
433.  			    ammo_and_launcher(obj, uswapwep)))
434.  		    setuqwep(obj);
435.  		if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan);
436.  	    }
437.  	}
438.  	return obj;
439.  }
440.  

useupall Edit

441.  /* useup() all of an item regardless of its quantity */
442.  void
443.  useupall(obj)
444.  struct obj *obj;
445.  {
446.  	setnotworn(obj);
447.  	freeinv(obj);
448.  	obfree(obj, (struct obj *)0);	/* deletes contents also */
449.  }
450.  

useup Edit

useup() takes one parameter, an object, and will either remove one from that pile or delete the whole object.

451.  void
452.  useup(obj)
453.  register struct obj *obj;
454.  {
455.  	/*  Note:  This works correctly for containers because they */
456.  	/*	   (containers) don't merge.			    */
457.  	if (obj->quan > 1L) {
458.  		obj->in_use = FALSE;	/* no longer in use */
459.  		obj->quan--;
460.  		obj->owt = weight(obj);
461.  		update_inventory();
462.  	} else {
463.  		useupall(obj);
464.  	}
465.  }
466.  

consume_obj_charge Edit

467.  /* use one charge from an item and possibly incur shop debt for it */
468.  void
469.  consume_obj_charge(obj, maybe_unpaid)
470.  struct obj *obj;
471.  boolean maybe_unpaid;	/* false if caller handles shop billing */
472.  {
473.  	if (maybe_unpaid) check_unpaid(obj);
474.  	obj->spe -= 1;
475.  	if (obj->known) update_inventory();
476.  }
477.  
478.  #endif /* OVLB */

freeinv_core Edit

479.  #ifdef OVL3
480.  
481.  /*
482.  Adjust hero's attributes as if this object was being removed from the
483.  hero's inventory.  This should only be called from freeinv() and
484.  where we are polymorphing an object already in the hero's inventory.
485.  
486.  Should think of a better name...
487.  */
488.  void
489.  freeinv_core(obj)
490.  struct obj *obj;
491.  {
492.  	if (obj->oclass == COIN_CLASS) {
493.  #ifndef GOLDOBJ
494.  		u.ugold -= obj->quan;
495.  		obj->in_use = FALSE;
496.  #endif
497.  		flags.botl = 1;
498.  		return;
499.  	} else if (obj->otyp == AMULET_OF_YENDOR) {
500.  		if (!u.uhave.amulet) impossible("don't have amulet?");
501.  		u.uhave.amulet = 0;
502.  	} else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
503.  		if (!u.uhave.menorah) impossible("don't have candelabrum?");
504.  		u.uhave.menorah = 0;
505.  	} else if (obj->otyp == BELL_OF_OPENING) {
506.  		if (!u.uhave.bell) impossible("don't have silver bell?");
507.  		u.uhave.bell = 0;
508.  	} else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
509.  		if (!u.uhave.book) impossible("don't have the book?");
510.  		u.uhave.book = 0;
511.  	} else if (obj->oartifact) {
512.  		if (is_quest_artifact(obj)) {
513.  		    if (!u.uhave.questart)
514.  			impossible("don't have quest artifact?");
515.  		    u.uhave.questart = 0;
516.  		}
517.  		set_artifact_intrinsic(obj, 0, W_ART);
518.  	}
519.  
520.  	if (obj->otyp == LOADSTONE) {
521.  		curse(obj);
522.  	} else if (confers_luck(obj)) {
523.  		set_moreluck();
524.  		flags.botl = 1;
525.  	} else if (obj->otyp == FIGURINE && obj->timed) {
526.  		(void) stop_timer(FIG_TRANSFORM, (genericptr_t) obj);
527.  	}
528.  }
529.  

freeinv Edit

530.  /* remove an object from the hero's inventory */
531.  void
532.  freeinv(obj)
533.  register struct obj *obj;
534.  {
535.  	extract_nobj(obj, &invent);
536.  	freeinv_core(obj);
537.  	update_inventory();
538.  }
539.  

delallobj Edit

delallobj() takes two parameters, an x,y coordinate, and removes all objects on the map at that location.

540.  void
541.  delallobj(x, y)
542.  int x, y;
543.  {
544.  	struct obj *otmp, *otmp2;
545.  
546.  	for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
547.  		if (otmp == uball)
548.  			unpunish();
549.  		/* after unpunish(), or might get deallocated chain */
550.  		otmp2 = otmp->nexthere;
551.  		if (otmp == uchain)
552.  			continue;
553.  		delobj(otmp);
554.  	}
555.  }
556.  
557.  #endif /* OVL3 */

delobj Edit

558.  #ifdef OVL2
559.  
560.  /* destroy object in fobj chain (if unpaid, it remains on the bill) */
561.  void
562.  delobj(obj)
563.  register struct obj *obj;
564.  {
565.  	boolean update_map;
566.  
567.  	if (obj->otyp == AMULET_OF_YENDOR ||
568.  			obj->otyp == CANDELABRUM_OF_INVOCATION ||
569.  			obj->otyp == BELL_OF_OPENING ||
570.  			obj->otyp == SPE_BOOK_OF_THE_DEAD) {
571.  		/* player might be doing something stupid, but we
572.  		 * can't guarantee that.  assume special artifacts
573.  		 * are indestructible via drawbridges, and exploding
574.  		 * chests, and golem creation, and ...
575.  		 */
576.  		return;
577.  	}
578.  	update_map = (obj->where == OBJ_FLOOR);
579.  	obj_extract_self(obj);
580.  	if (update_map) newsym(obj->ox, obj->oy);
581.  	obfree(obj, (struct obj *) 0);	/* frees contents also */
582.  }
583.  
584.  #endif /* OVL2 */

sobj_at Edit

sobj_at() takes three parameters, an object type macro and an x,y coordinate, and returns a pointer to an object of that type at that location, or NULL if none found there.

585.  #ifdef OVL0
586.  
587.  struct obj *
588.  sobj_at(n,x,y)
589.  register int n, x, y;
590.  {
591.  	register struct obj *otmp;
592.  
593.  	for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
594.  		if(otmp->otyp == n)
595.  		    return(otmp);
596.  	return((struct obj *)0);
597.  }
598.  
599.  #endif /* OVL0 */

carrying Edit

carrying() takes one parameter, an object type macro and returns a pointer to an object of that type hero is carrying, or NULL if no such object.

600.  #ifdef OVLB
601.  
602.  struct obj *
603.  carrying(type)
604.  register int type;
605.  {
606.  	register struct obj *otmp;
607.  
608.  	for(otmp = invent; otmp; otmp = otmp->nobj)
609.  		if(otmp->otyp == type)
610.  			return(otmp);
611.  	return((struct obj *) 0);
612.  }
613.  

currency Edit

614.  const char *
615.  currency(amount)
616.  long amount;
617.  {
618.  	if (amount == 1L) return "zorkmid";
619.  	else return "zorkmids";
620.  }
621.  

have_lizard Edit

622.  boolean
623.  have_lizard()
624.  {
625.  	register struct obj *otmp;
626.  
627.  	for(otmp = invent; otmp; otmp = otmp->nobj)
628.  		if(otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
629.  			return(TRUE);
630.  	return(FALSE);
631.  }
632.  

o_on Edit

633.  struct obj *
634.  o_on(id, objchn)
635.  unsigned int id;
636.  register struct obj *objchn;
637.  {
638.  	struct obj *temp;
639.  
640.  	while(objchn) {
641.  		if(objchn->o_id == id) return(objchn);
642.  		if (Has_contents(objchn) && (temp = o_on(id,objchn->cobj)))
643.  			return temp;
644.  		objchn = objchn->nobj;
645.  	}
646.  	return((struct obj *) 0);
647.  }
648.  

obj_here Edit

649.  boolean
650.  obj_here(obj, x, y)
651.  register struct obj *obj;
652.  int x, y;
653.  {
654.  	register struct obj *otmp;
655.  
656.  	for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
657.  		if(obj == otmp) return(TRUE);
658.  	return(FALSE);
659.  }
660.  
661.  #endif /* OVLB */

g_at Edit

662.  #ifdef OVL2
663.  
664.  struct obj *
665.  g_at(x,y)
666.  register int x, y;
667.  {
668.  	register struct obj *obj = level.objects[x][y];
669.  	while(obj) {
670.  	    if (obj->oclass == COIN_CLASS) return obj;
671.  	    obj = obj->nexthere;
672.  	}
673.  	return((struct obj *)0);
674.  }
675.  
676.  #endif /* OVL2 */

mkgoldobj Edit

677.  #ifdef OVLB
678.  #ifndef GOLDOBJ
679.  /* Make a gold object from the hero's gold. */
680.  struct obj *
681.  mkgoldobj(q)
682.  register long q;
683.  {
684.  	register struct obj *otmp;
685.  
686.  	otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
687.  	u.ugold -= q;
688.  	otmp->quan = q;
689.  	otmp->owt = weight(otmp);
690.  	flags.botl = 1;
691.  	return(otmp);
692.  }
693.  #endif
694.  #endif /* OVLB */

compactify Edit

695.  #ifdef OVL1
696.  
697.  STATIC_OVL void
698.  compactify(buf)
699.  register char *buf;
700.  /* compact a string of inventory letters by dashing runs of letters */
701.  {
702.  	register int i1 = 1, i2 = 1;
703.  	register char ilet, ilet1, ilet2;
704.  
705.  	ilet2 = buf[0];
706.  	ilet1 = buf[1];
707.  	buf[++i2] = buf[++i1];
708.  	ilet = buf[i1];
709.  	while(ilet) {
710.  		if(ilet == ilet1+1) {
711.  			if(ilet1 == ilet2+1)
712.  				buf[i2 - 1] = ilet1 = '-';
713.  			else if(ilet2 == '-') {
714.  				buf[i2 - 1] = ++ilet1;
715.  				buf[i2] = buf[++i1];
716.  				ilet = buf[i1];
717.  				continue;
718.  			}
719.  		}
720.  		ilet2 = ilet1;
721.  		ilet1 = ilet;
722.  		buf[++i2] = buf[++i1];
723.  		ilet = buf[i1];
724.  	}
725.  }
726.  

taking_off Edit

727.  /* match the prompt for either 'T' or 'R' command */
728.  STATIC_OVL boolean
729.  taking_off(action)
730.  const char *action;
731.  {
732.      return !strcmp(action, "take off") || !strcmp(action, "remove");
733.  }
734.  

putting_on Edit

735.  /* match the prompt for either 'W' or 'P' command */
736.  STATIC_OVL boolean
737.  putting_on(action)
738.  const char *action;
739.  {
740.      return !strcmp(action, "wear") || !strcmp(action, "put on");
741.  }
742.  

getobj Edit

743.  /*
744.   * getobj returns:
745.   *	struct obj *xxx:	object to do something with.
746.   *	(struct obj *) 0	error return: no object.
747.   *	&zeroobj		explicitly no object (as in w-).
748.  #ifdef GOLDOBJ
749.  !!!! test if gold can be used in unusual ways (eaten etc.)
750.  !!!! may be able to remove "usegold"
751.  #endif
752.   */
753.  struct obj *
754.  getobj(let,word)
755.  register const char *let,*word;
756.  {
757.  	register struct obj *otmp;
758.  	register char ilet;
759.  	char buf[BUFSZ], qbuf[QBUFSZ];
760.  	char lets[BUFSZ], altlets[BUFSZ], *ap;
761.  	register int foo = 0;
762.  	register char *bp = buf;
763.  	xchar allowcnt = 0;	/* 0, 1 or 2 */
764.  #ifndef GOLDOBJ
765.  	boolean allowgold = FALSE;	/* can't use gold because they don't have any */
766.  #endif
767.  	boolean usegold = FALSE;	/* can't use gold because its illegal */
768.  	boolean allowall = FALSE;
769.  	boolean allownone = FALSE;
770.  	boolean useboulder = FALSE;
771.  	xchar foox = 0;
772.  	long cnt;
773.  	boolean prezero = FALSE;
774.  	long dummymask;
775.  
776.  	if(*let == ALLOW_COUNT) let++, allowcnt = 1;
777.  #ifndef GOLDOBJ
778.  	if(*let == COIN_CLASS) let++,
779.  		usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE);
780.  #else
781.  	if(*let == COIN_CLASS) let++, usegold = TRUE;
782.  #endif
783.  
784.  	/* Equivalent of an "ugly check" for gold */
785.  	if (usegold && !strcmp(word, "eat") &&
786.  	    (!metallivorous(youmonst.data)
787.  	     || youmonst.data == &mons[PM_RUST_MONSTER]))
788.  #ifndef GOLDOBJ
789.  		usegold = allowgold = FALSE;
790.  #else
791.  		usegold = FALSE;
792.  #endif
793.  
794.  	if(*let == ALL_CLASSES) let++, allowall = TRUE;
795.  	if(*let == ALLOW_NONE) let++, allownone = TRUE;
796.  	/* "ugly check" for reading fortune cookies, part 1 */
797.  	/* The normal 'ugly check' keeps the object on the inventory list.
798.  	 * We don't want to do that for shirts/cookies, so the check for
799.  	 * them is handled a bit differently (and also requires that we set
800.  	 * allowall in the caller)
801.  	 */
802.  	if(allowall && !strcmp(word, "read")) allowall = FALSE;
803.  
804.  	/* another ugly check: show boulders (not statues) */
805.  	if(*let == WEAPON_CLASS &&
806.  	   !strcmp(word, "throw") && throws_rocks(youmonst.data))
807.  	    useboulder = TRUE;
808.  
809.  	if(allownone) *bp++ = '-';
810.  #ifndef GOLDOBJ
811.  	if(allowgold) *bp++ = def_oc_syms[COIN_CLASS];
812.  #endif
813.  	if(bp > buf && bp[-1] == '-') *bp++ = ' ';
814.  	ap = altlets;
815.  
816.  	ilet = 'a';
817.  	for (otmp = invent; otmp; otmp = otmp->nobj) {
818.  	    if (!flags.invlet_constant)
819.  #ifdef GOLDOBJ
820.  		if (otmp->invlet != GOLD_SYM) /* don't reassign this */
821.  #endif
822.  		otmp->invlet = ilet;	/* reassign() */
823.  	    if (!*let || index(let, otmp->oclass)
824.  #ifdef GOLDOBJ
825.  		|| (usegold && otmp->invlet == GOLD_SYM)
826.  #endif
827.  		|| (useboulder && otmp->otyp == BOULDER)
828.  		) {
829.  		register int otyp = otmp->otyp;
830.  		bp[foo++] = otmp->invlet;
831.  
832.  		/* ugly check: remove inappropriate things */
833.  		if ((taking_off(word) &&
834.  		    (!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))
835.  		     || (otmp==uarm && uarmc)
836.  #ifdef TOURIST
837.  		     || (otmp==uarmu && (uarm || uarmc))
838.  #endif
839.  		    ))
840.  		|| (putting_on(word) &&
841.  		     (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
842.  							/* already worn */
843.  #if 0	/* 3.4.1 -- include currently wielded weapon among the choices */
844.  		|| (!strcmp(word, "wield") &&
845.  		    (otmp->owornmask & W_WEP))
846.  #endif
847.  		|| (!strcmp(word, "ready") &&
848.  		    (otmp == uwep || (otmp == uswapwep && u.twoweap)))
849.  		    ) {
850.  			foo--;
851.  			foox++;
852.  		}
853.  
854.  		/* Second ugly check; unlike the first it won't trigger an
855.  		 * "else" in "you don't have anything else to ___".
856.  		 */
857.  		else if ((putting_on(word) &&
858.  		    ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) ||
859.  		    (otmp->oclass == TOOL_CLASS &&
860.  		     otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES)))
861.  		|| (!strcmp(word, "wield") &&
862.  		    (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
863.  		|| (!strcmp(word, "eat") && !is_edible(otmp))
864.  		|| (!strcmp(word, "sacrifice") &&
865.  		    (otyp != CORPSE &&
866.  		     otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR))
867.  		|| (!strcmp(word, "write with") &&
868.  		    (otmp->oclass == TOOL_CLASS &&
869.  		     otyp != MAGIC_MARKER && otyp != TOWEL))
870.  		|| (!strcmp(word, "tin") &&
871.  		    (otyp != CORPSE || !tinnable(otmp)))
872.  		|| (!strcmp(word, "rub") &&
873.  		    ((otmp->oclass == TOOL_CLASS &&
874.  		      otyp != OIL_LAMP && otyp != MAGIC_LAMP &&
875.  		      otyp != BRASS_LANTERN) ||
876.  		     (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
877.  		|| (!strncmp(word, "rub on the stone", 16) &&
878.  		    *let == GEM_CLASS &&	/* using known touchstone */
879.  		    otmp->dknown && objects[otyp].oc_name_known)
880.  		|| ((!strcmp(word, "use or apply") ||
881.  			!strcmp(word, "untrap with")) &&
882.  		     /* Picks, axes, pole-weapons, bullwhips */
883.  		    ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) &&
884.  		      !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) ||
885.  		     (otmp->oclass == POTION_CLASS &&
886.  		     /* only applicable potion is oil, and it will only
887.  			be offered as a choice when already discovered */
888.  		     (otyp != POT_OIL || !otmp->dknown ||
889.  		      !objects[POT_OIL].oc_name_known)) ||
890.  		     (otmp->oclass == FOOD_CLASS &&
891.  		      otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) ||
892.  		     (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
893.  		|| (!strcmp(word, "invoke") &&
894.  		    (!otmp->oartifact && !objects[otyp].oc_unique &&
895.  		     (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) &&
896.  		     otyp != CRYSTAL_BALL &&	/* #invoke synonym for apply */
897.  		   /* note: presenting the possibility of invoking non-artifact
898.  		      mirrors and/or lamps is a simply a cruel deception... */
899.  		     otyp != MIRROR && otyp != MAGIC_LAMP &&
900.  		     (otyp != OIL_LAMP ||	/* don't list known oil lamp */
901.  		      (otmp->dknown && objects[OIL_LAMP].oc_name_known))))
902.  		|| (!strcmp(word, "untrap with") &&
903.  		    (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE))
904.  		|| (!strcmp(word, "charge") && !is_chargeable(otmp))
905.  		    )
906.  			foo--;
907.  		/* ugly check for unworn armor that can't be worn */
908.  		else if (putting_on(word) && *let == ARMOR_CLASS &&
909.  			 !canwearobj(otmp, &dummymask, FALSE)) {
910.  			foo--;
911.  			allowall = TRUE;
912.  			*ap++ = otmp->invlet;
913.  		}
914.  	    } else {
915.  
916.  		/* "ugly check" for reading fortune cookies, part 2 */
917.  		if ((!strcmp(word, "read") &&
918.  		    (otmp->otyp == FORTUNE_COOKIE
919.  #ifdef TOURIST
920.  			|| otmp->otyp == T_SHIRT
921.  #endif
922.  		    )))
923.  			allowall = TRUE;
924.  	    }
925.  
926.  	    if(ilet == 'z') ilet = 'A'; else ilet++;
927.  	}
928.  	bp[foo] = 0;
929.  	if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
930.  	Strcpy(lets, bp);	/* necessary since we destroy buf */
931.  	if(foo > 5)			/* compactify string */
932.  		compactify(bp);
933.  	*ap = '\0';
934.  
935.  #ifndef GOLDOBJ
936.  	if(!foo && !allowall && !allowgold && !allownone) {
937.  #else
938.  	if(!foo && !allowall && !allownone) {
939.  #endif
940.  		You("don't have anything %sto %s.",
941.  			foox ? "else " : "", word);
942.  		return((struct obj *)0);
943.  	}
944.  	for(;;) {
945.  		cnt = 0;
946.  		if (allowcnt == 2) allowcnt = 1;  /* abort previous count */
947.  		if(!buf[0]) {
948.  			Sprintf(qbuf, "What do you want to %s? [*]", word);
949.  		} else {
950.  			Sprintf(qbuf, "What do you want to %s? [%s or ?*]",
951.  				word, buf);
952.  		}
953.  #ifdef REDO
954.  		if (in_doagain)
955.  		    ilet = readchar();
956.  		else
957.  #endif
958.  		    ilet = yn_function(qbuf, (char *)0, '\0');
959.  		if(ilet == '0') prezero = TRUE;
960.  		while(digit(ilet) && allowcnt) {
961.  #ifdef REDO
962.  			if (ilet != '?' && ilet != '*')	savech(ilet);
963.  #endif
964.  			cnt = 10*cnt + (ilet - '0');
965.  			allowcnt = 2;	/* signal presence of cnt */
966.  			ilet = readchar();
967.  		}
968.  		if(digit(ilet)) {
969.  			pline("No count allowed with this command.");
970.  			continue;
971.  		}
972.  		if(index(quitchars,ilet)) {
973.  		    if(flags.verbose)
974.  			pline(Never_mind);
975.  		    return((struct obj *)0);
976.  		}
977.  		if(ilet == '-') {
978.  			return(allownone ? &zeroobj : (struct obj *) 0);
979.  		}
980.  		if(ilet == def_oc_syms[COIN_CLASS]) {
981.  			if (!usegold) {
982.  			    if (!strncmp(word, "rub on ", 7)) {
983.  				/* the dangers of building sentences... */
984.  				You("cannot rub gold%s.", word + 3);
985.  			    } else {
986.  				You("cannot %s gold.", word);
987.  			    }
988.  			    return(struct obj *)0;
989.  #ifndef GOLDOBJ
990.  			} else if (!allowgold) {
991.  				You("are not carrying any gold.");
992.  				return(struct obj *)0;
993.  #endif
994.  			} 
995.  			if(cnt == 0 && prezero) return((struct obj *)0);
996.  			/* Historic note: early Nethack had a bug which was
997.  			 * first reported for Larn, where trying to drop 2^32-n
998.  			 * gold pieces was allowed, and did interesting things
999.  			 * to your money supply.  The LRS is the tax bureau
1000. 			 * from Larn.
1001. 			 */
1002. 			if(cnt < 0) {
1003. 	pline_The("LRS would be very interested to know you have that much.");
1004. 				return(struct obj *)0;
1005. 			}
1006. 
1007. #ifndef GOLDOBJ
1008. 			if(!(allowcnt == 2 && cnt < u.ugold))
1009. 				cnt = u.ugold;
1010. 			return(mkgoldobj(cnt));
1011. #endif
1012. 		}
1013. 		if(ilet == '?' || ilet == '*') {
1014. 		    char *allowed_choices = (ilet == '?') ? lets : (char *)0;
1015. 		    long ctmp = 0;
1016. 
1017. 		    if (ilet == '?' && !*lets && *altlets)
1018. 			allowed_choices = altlets;
1019. 		    ilet = display_pickinv(allowed_choices, TRUE,
1020. 					   allowcnt ? &ctmp : (long *)0);
1021. 		    if(!ilet) continue;
1022. 		    if (allowcnt && ctmp >= 0) {
1023. 			cnt = ctmp;
1024. 			if (!cnt) prezero = TRUE;
1025. 			allowcnt = 2;
1026. 		    }
1027. 		    if(ilet == '\033') {
1028. 			if(flags.verbose)
1029. 			    pline(Never_mind);
1030. 			return((struct obj *)0);
1031. 		    }
1032. 		    /* they typed a letter (not a space) at the prompt */
1033. 		}
1034. 		if(allowcnt == 2 && !strcmp(word,"throw")) {
1035. 		    /* permit counts for throwing gold, but don't accept
1036. 		     * counts for other things since the throw code will
1037. 		     * split off a single item anyway */
1038. #ifdef GOLDOBJ
1039. 		    if (ilet != def_oc_syms[COIN_CLASS])
1040. #endif
1041. 			allowcnt = 1;
1042. 		    if(cnt == 0 && prezero) return((struct obj *)0);
1043. 		    if(cnt > 1) {
1044. 			You("can only throw one item at a time.");
1045. 			continue;
1046. 		    }
1047. 		}
1048. #ifdef GOLDOBJ
1049. 		flags.botl = 1; /* May have changed the amount of money */
1050. #endif
1051. #ifdef REDO
1052. 		savech(ilet);
1053. #endif
1054. 		for (otmp = invent; otmp; otmp = otmp->nobj)
1055. 			if (otmp->invlet == ilet) break;
1056. 		if(!otmp) {
1057. 			You("don't have that object.");
1058. #ifdef REDO
1059. 			if (in_doagain) return((struct obj *) 0);
1060. #endif
1061. 			continue;
1062. 		} else if (cnt < 0 || otmp->quan < cnt) {
1063. 			You("don't have that many!  You have only %ld.",
1064. 			    otmp->quan);
1065. #ifdef REDO
1066. 			if (in_doagain) return((struct obj *) 0);
1067. #endif
1068. 			continue;
1069. 		}
1070. 		break;
1071. 	}
1072. 	if(!allowall && let && !index(let,otmp->oclass)
1073. #ifdef GOLDOBJ
1074. 	   && !(usegold && otmp->oclass == COIN_CLASS)
1075. #endif
1076. 	   ) {
1077. 		silly_thing(word, otmp);
1078. 		return((struct obj *)0);
1079. 	}
1080. 	if(allowcnt == 2) {	/* cnt given */
1081. 	    if(cnt == 0) return (struct obj *)0;
1082. 	    if(cnt != otmp->quan) {
1083. 		/* don't split a stack of cursed loadstones */
1084. 		if (otmp->otyp == LOADSTONE && otmp->cursed)
1085. 		    /* kludge for canletgo()'s can't-drop-this message */
1086. 		    otmp->corpsenm = (int) cnt;
1087. 		else
1088. 		    otmp = splitobj(otmp, cnt);
1089. 	    }
1090. 	}
1091. 	return(otmp);
1092. }
1093. 

silly_thing Edit

1094. void
1095. silly_thing(word, otmp)
1096. const char *word;
1097. struct obj *otmp;
1098. {
1099. 	const char *s1, *s2, *s3, *what;
1100. 	int ocls = otmp->oclass, otyp = otmp->otyp;
1101. 
1102. 	s1 = s2 = s3 = 0;
1103. 	/* check for attempted use of accessory commands ('P','R') on armor
1104. 	   and for corresponding armor commands ('W','T') on accessories */
1105. 	if (ocls == ARMOR_CLASS) {
1106. 	    if (!strcmp(word, "put on"))
1107. 		s1 = "W", s2 = "wear", s3 = "";
1108. 	    else if (!strcmp(word, "remove"))
1109. 		s1 = "T", s2 = "take", s3 = " off";
1110. 	} else if ((ocls == RING_CLASS || otyp == MEAT_RING) ||
1111. 		ocls == AMULET_CLASS ||
1112. 		(otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) {
1113. 	    if (!strcmp(word, "wear"))
1114. 		s1 = "P", s2 = "put", s3 = " on";
1115. 	    else if (!strcmp(word, "take off"))
1116. 		s1 = "R", s2 = "remove", s3 = "";
1117. 	}
1118. 	if (s1) {
1119. 	    what = "that";
1120. 	    /* quantity for armor and accessory objects is always 1,
1121. 	       but some things should be referred to as plural */
1122. 	    if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp))
1123. 		what = "those";
1124. 	    pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3);
1125. 	} else {
1126. 	    pline(silly_thing_to, word);
1127. 	}
1128. }
1129. 
1130. #endif /* OVL1 */

ckvalidcat Edit

1131. #ifdef OVLB
1132. 
1133. STATIC_PTR int
1134. ckvalidcat(otmp)
1135. register struct obj *otmp;
1136. {
1137. 	/* use allow_category() from pickup.c */
1138. 	return((int)allow_category(otmp));
1139. }
1140. 

ckunpaid Edit

1141. STATIC_PTR int
1142. ckunpaid(otmp)
1143. register struct obj *otmp;
1144. {
1145. 	return((int)(otmp->unpaid));
1146. }
1147. 

wearing_armor Edit

1148. boolean
1149. wearing_armor()
1150. {
1151. 	return((boolean)(uarm || uarmc || uarmf || uarmg || uarmh || uarms
1152. #ifdef TOURIST
1153. 		|| uarmu
1154. #endif
1155. 		));
1156. }
1157. 

is_worn Edit

1158. boolean
1159. is_worn(otmp)
1160. register struct obj *otmp;
1161. {
1162.     return((boolean)(!!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL |
1163. #ifdef STEED
1164. 			W_SADDLE |
1165. #endif
1166. 			W_WEP | W_SWAPWEP | W_QUIVER))));
1167. }
1168. 

ggetobj Edit

1169. static NEARDATA const char removeables[] =
1170. 	{ ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 };
1171. 
1172. /* interactive version of getobj - used for Drop, Identify and */
1173. /* Takeoff (A). Return the number of times fn was called successfully */
1174. /* If combo is TRUE, we just use this to get a category list */
1175. int
1176. ggetobj(word, fn, mx, combo, resultflags)
1177. const char *word;
1178. int FDECL((*fn),(OBJ_P)), mx;
1179. boolean combo;		/* combination menu flag */
1180. unsigned *resultflags;
1181. {
1182. 	int FDECL((*ckfn),(OBJ_P)) = (int FDECL((*),(OBJ_P))) 0;
1183. 	boolean FDECL((*filter),(OBJ_P)) = (boolean FDECL((*),(OBJ_P))) 0;
1184. 	boolean takeoff, ident, allflag, m_seen;
1185. 	int itemcount;
1186. #ifndef GOLDOBJ
1187. 	int oletct, iletct, allowgold, unpaid, oc_of_sym;
1188. #else
1189. 	int oletct, iletct, unpaid, oc_of_sym;
1190. #endif
1191. 	char sym, *ip, olets[MAXOCLASSES+5], ilets[MAXOCLASSES+5];
1192. 	char extra_removeables[3+1];	/* uwep,uswapwep,uquiver */
1193. 	char buf[BUFSZ], qbuf[QBUFSZ];
1194. 
1195. 	if (resultflags) *resultflags = 0;
1196. #ifndef GOLDOBJ
1197. 	allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;
1198. #endif
1199. 	takeoff = ident = allflag = m_seen = FALSE;
1200. #ifndef GOLDOBJ
1201. 	if(!invent && !allowgold){
1202. #else
1203. 	if(!invent){
1204. #endif
1205. 		You("have nothing to %s.", word);
1206. 		return(0);
1207. 	}
1208. 	add_valid_menu_class(0);	/* reset */
1209. 	if (taking_off(word)) {
1210. 	    takeoff = TRUE;
1211. 	    filter = is_worn;
1212. 	} else if (!strcmp(word, "identify")) {
1213. 	    ident = TRUE;
1214. 	    filter = not_fully_identified;
1215. 	}
1216. 
1217. 	iletct = collect_obj_classes(ilets, invent,
1218. 				     	FALSE,
1219. #ifndef GOLDOBJ
1220. 					(allowgold != 0),
1221. #endif
1222. 					filter, &itemcount);
1223. 	unpaid = count_unpaid(invent);
1224. 
1225. 	if (ident && !iletct) {
1226. 	    return -1;		/* no further identifications */
1227. 	} else if (!takeoff && (unpaid || invent)) {
1228. 	    ilets[iletct++] = ' ';
1229. 	    if (unpaid) ilets[iletct++] = 'u';
1230. 	    if (count_buc(invent, BUC_BLESSED))  ilets[iletct++] = 'B';
1231. 	    if (count_buc(invent, BUC_UNCURSED)) ilets[iletct++] = 'U';
1232. 	    if (count_buc(invent, BUC_CURSED))   ilets[iletct++] = 'C';
1233. 	    if (count_buc(invent, BUC_UNKNOWN))  ilets[iletct++] = 'X';
1234. 	    if (invent) ilets[iletct++] = 'a';
1235. 	} else if (takeoff && invent) {
1236. 	    ilets[iletct++] = ' ';
1237. 	}
1238. 	ilets[iletct++] = 'i';
1239. 	if (!combo)
1240. 	    ilets[iletct++] = 'm';	/* allow menu presentation on request */
1241. 	ilets[iletct] = '\0';
1242. 
1243. 	for (;;) {
1244. 	    Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
1245. 		    word, ilets);
1246. 	    getlin(qbuf, buf);
1247. 	    if (buf[0] == '\033') return(0);
1248. 	    if (index(buf, 'i')) {
1249. 		if (display_inventory((char *)0, TRUE) == '\033') return 0;
1250. 	    } else
1251. 		break;
1252. 	}
1253. 
1254. 	extra_removeables[0] = '\0';
1255. 	if (takeoff) {
1256. 	    /* arbitrary types of items can be placed in the weapon slots
1257. 	       [any duplicate entries in extra_removeables[] won't matter] */
1258. 	    if (uwep) (void)strkitten(extra_removeables, uwep->oclass);
1259. 	    if (uswapwep) (void)strkitten(extra_removeables, uswapwep->oclass);
1260. 	    if (uquiver) (void)strkitten(extra_removeables, uquiver->oclass);
1261. 	}
1262. 
1263. 	ip = buf;
1264. 	olets[oletct = 0] = '\0';
1265. 	while ((sym = *ip++) != '\0') {
1266. 	    if (sym == ' ') continue;
1267. 	    oc_of_sym = def_char_to_objclass(sym);
1268. 	    if (takeoff && oc_of_sym != MAXOCLASSES) {
1269. 		if (index(extra_removeables, oc_of_sym)) {
1270. 		    ;	/* skip rest of takeoff checks */
1271. 		} else if (!index(removeables, oc_of_sym)) {
1272. 		    pline("Not applicable.");
1273. 		    return 0;
1274. 		} else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
1275. 		    You("are not wearing any armor.");
1276. 		    return 0;
1277. 		} else if (oc_of_sym == WEAPON_CLASS &&
1278. 			!uwep && !uswapwep && !uquiver) {
1279. 		    You("are not wielding anything.");
1280. 		    return 0;
1281. 		} else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
1282. 		    You("are not wearing rings.");
1283. 		    return 0;
1284. 		} else if (oc_of_sym == AMULET_CLASS && !uamul) {
1285. 		    You("are not wearing an amulet.");
1286. 		    return 0;
1287. 		} else if (oc_of_sym == TOOL_CLASS && !ublindf) {
1288. 		    You("are not wearing a blindfold.");
1289. 		    return 0;
1290. 		}
1291. 	    }
1292. 
1293. 	    if (oc_of_sym == COIN_CLASS && !combo) {
1294. #ifndef GOLDOBJ
1295. 		if (allowgold == 1)
1296. 		    (*fn)(mkgoldobj(u.ugold));
1297. 		else if (!u.ugold)
1298. 		    You("have no gold.");
1299. 		allowgold = 2;
1300. #else
1301. 		flags.botl = 1;
1302. #endif
1303. 	    } else if (sym == 'a') {
1304. 		allflag = TRUE;
1305. 	    } else if (sym == 'A') {
1306. 		/* same as the default */ ;
1307. 	    } else if (sym == 'u') {
1308. 		add_valid_menu_class('u');
1309. 		ckfn = ckunpaid;
1310. 	    } else if (sym == 'B') {
1311. 	    	add_valid_menu_class('B');
1312. 	    	ckfn = ckvalidcat;
1313. 	    } else if (sym == 'U') {
1314. 	    	add_valid_menu_class('U');
1315. 	    	ckfn = ckvalidcat;
1316. 	    } else if (sym == 'C') {
1317. 	    	add_valid_menu_class('C');
1318. 		ckfn = ckvalidcat;
1319. 	    } else if (sym == 'X') {
1320. 	    	add_valid_menu_class('X');
1321. 		ckfn = ckvalidcat;
1322. 	    } else if (sym == 'm') {
1323. 		m_seen = TRUE;
1324. 	    } else if (oc_of_sym == MAXOCLASSES) {
1325. 		You("don't have any %c's.", sym);
1326. 	    } else if (oc_of_sym != VENOM_CLASS) {	/* suppress venom */
1327. 		if (!index(olets, oc_of_sym)) {
1328. 		    add_valid_menu_class(oc_of_sym);
1329. 		    olets[oletct++] = oc_of_sym;
1330. 		    olets[oletct] = 0;
1331. 		}
1332. 	    }
1333. 	}
1334. 
1335. 	if (m_seen)
1336. 	    return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
1337. 	else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag)
1338. 	    return 0;
1339. #ifndef GOLDOBJ
1340. 	else if (allowgold == 2 && !oletct)
1341. 	    return 1;	/* you dropped gold (or at least tried to) */
1342. 	else {
1343. #else
1344. 	else /*!!!! if (allowgold == 2 && !oletct)
1345. 	    !!!! return 1;	 you dropped gold (or at least tried to) 
1346.             !!!! test gold dropping
1347. 	else*/ {
1348. #endif
1349. 	    int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word); 
1350. 	    /*
1351. 	     * askchain() has already finished the job in this case
1352. 	     * so set a special flag to convey that back to the caller
1353. 	     * so that it won't continue processing.
1354. 	     * Fix for bug C331-1 reported by Irina Rempt-Drijfhout. 
1355. 	     */
1356. 	    if (combo && allflag && resultflags)
1357. 		*resultflags |= ALL_FINISHED; 
1358. 	    return cnt;
1359. 	}
1360. }
1361. 

askchain Edit

1362. /*
1363.  * Walk through the chain starting at objchn and ask for all objects
1364.  * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
1365.  * whether the action in question (i.e., fn) has to be performed.
1366.  * If allflag then no questions are asked. Max gives the max nr of
1367.  * objects to be treated. Return the number of objects treated.
1368.  */
1369. int
1370. askchain(objchn, olets, allflag, fn, ckfn, mx, word)
1371. struct obj **objchn;
1372. register int allflag, mx;
1373. register const char *olets, *word;	/* olets is an Obj Class char array */
1374. register int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P));
1375. {
1376. 	struct obj *otmp, *otmp2, *otmpo;
1377. 	register char sym, ilet;
1378. 	register int cnt = 0, dud = 0, tmp;
1379. 	boolean takeoff, nodot, ident, ininv;
1380. 	char qbuf[QBUFSZ];
1381. 
1382. 	takeoff = taking_off(word);
1383. 	ident = !strcmp(word, "identify");
1384. 	nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") ||
1385. 		 ident || takeoff);
1386. 	ininv = (*objchn == invent);
1387. 	/* Changed so the askchain is interrogated in the order specified.
1388. 	 * For example, if a person specifies =/ then first all rings will be
1389. 	 * asked about followed by all wands -dgk
1390. 	 */
1391. nextclass:
1392. 	ilet = 'a'-1;
1393. 	if (*objchn && (*objchn)->oclass == COIN_CLASS)
1394. 		ilet--;		/* extra iteration */
1395. 	for (otmp = *objchn; otmp; otmp = otmp2) {
1396. 		if(ilet == 'z') ilet = 'A'; else ilet++;
1397. 		otmp2 = otmp->nobj;
1398. 		if (olets && *olets && otmp->oclass != *olets) continue;
1399. 		if (takeoff && !is_worn(otmp)) continue;
1400. 		if (ident && !not_fully_identified(otmp)) continue;
1401. 		if (ckfn && !(*ckfn)(otmp)) continue;
1402. 		if (!allflag) {
1403. 			Strcpy(qbuf, !ininv ? doname(otmp) :
1404. 				xprname(otmp, (char *)0, ilet, !nodot, 0L, 0L));
1405. 			Strcat(qbuf, "?");
1406. 			sym = (takeoff || ident || otmp->quan < 2L) ?
1407. 				nyaq(qbuf) : nyNaq(qbuf);
1408. 		}
1409. 		else	sym = 'y';
1410. 
1411. 		otmpo = otmp;
1412. 		if (sym == '#') {
1413. 		 /* Number was entered; split the object unless it corresponds
1414. 		    to 'none' or 'all'.  2 special cases: cursed loadstones and
1415. 		    welded weapons (eg, multiple daggers) will remain as merged
1416. 		    unit; done to avoid splitting an object that won't be
1417. 		    droppable (even if we're picking up rather than dropping).
1418. 		  */
1419. 		    if (!yn_number)
1420. 			sym = 'n';
1421. 		    else {
1422. 			sym = 'y';
1423. 			if (yn_number < otmp->quan && !welded(otmp) &&
1424. 			    (!otmp->cursed || otmp->otyp != LOADSTONE)) {
1425. 			    otmp = splitobj(otmp, yn_number);
1426. 			}
1427. 		    }
1428. 		}
1429. 		switch(sym){
1430. 		case 'a':
1431. 			allflag = 1;
1432. 		case 'y':
1433. 			tmp = (*fn)(otmp);
1434. 			if(tmp < 0) {
1435. 			    if (otmp != otmpo) {
1436. 				/* split occurred, merge again */
1437. 				(void) merged(&otmpo, &otmp);
1438. 			    }
1439. 			    goto ret;
1440. 			}
1441. 			cnt += tmp;
1442. 			if(--mx == 0) goto ret;
1443. 		case 'n':
1444. 			if(nodot) dud++;
1445. 		default:
1446. 			break;
1447. 		case 'q':
1448. 			/* special case for seffects() */
1449. 			if (ident) cnt = -1;
1450. 			goto ret;
1451. 		}
1452. 	}
1453. 	if (olets && *olets && *++olets)
1454. 		goto nextclass;
1455. 	if(!takeoff && (dud || cnt)) pline("That was all.");
1456. 	else if(!dud && !cnt) pline("No applicable objects.");
1457. ret:
1458. 	return(cnt);
1459. }
1460. 
1461. 

fully_identify_obj Edit

1462. /*
1463.  *	Object identification routines:
1464.  */
1465. 
1466. /* make an object actually be identified; no display updating */
1467. void
1468. fully_identify_obj(otmp)
1469. struct obj *otmp;
1470. {
1471.     makeknown(otmp->otyp);
1472.     if (otmp->oartifact) discover_artifact((xchar)otmp->oartifact);
1473.     otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1474.     if (otmp->otyp == EGG && otmp->corpsenm != NON_PM)
1475. 	learn_egg_type(otmp->corpsenm);
1476. }
1477. 

identify Edit

1478. /* ggetobj callback routine; identify an object and give immediate feedback */
1479. int
1480. identify(otmp)
1481. struct obj *otmp;
1482. {
1483.     fully_identify_obj(otmp);
1484.     prinv((char *)0, otmp, 0L);
1485.     return 1;
1486. }
1487. 

menu_identify Edit

1488. /* menu of unidentified objects; select and identify up to id_limit of them */
1489. STATIC_OVL void
1490. menu_identify(id_limit)
1491. int id_limit;
1492. {
1493.     menu_item *pick_list;
1494.     int n, i, first = 1;
1495.     char buf[BUFSZ];
1496.     /* assumptions:  id_limit > 0 and at least one unID'd item is present */
1497. 
1498.     while (id_limit) {
1499. 	Sprintf(buf, "What would you like to identify %s?",
1500. 		first ? "first" : "next");
1501. 	n = query_objlist(buf, invent, SIGNAL_NOMENU|USE_INVLET|INVORDER_SORT,
1502. 		&pick_list, PICK_ANY, not_fully_identified);
1503. 
1504. 	if (n > 0) {
1505. 	    if (n > id_limit) n = id_limit;
1506. 	    for (i = 0; i < n; i++, id_limit--)
1507. 		(void) identify(pick_list[i].item.a_obj);
1508. 	    free((genericptr_t) pick_list);
1509. 	    mark_synch(); /* Before we loop to pop open another menu */
1510. 	} else {
1511. 	    if (n < 0) pline("That was all.");
1512. 	    id_limit = 0; /* Stop now */
1513. 	}
1514. 	first = 0;
1515.     }
1516. }
1517. 

identify_pack Edit

1518. /* dialog with user to identify a given number of items; 0 means all */
1519. void
1520. identify_pack(id_limit)
1521. int id_limit;
1522. {
1523.     struct obj *obj, *the_obj;
1524.     int n, unid_cnt;
1525. 
1526.     unid_cnt = 0;
1527.     the_obj = 0;		/* if unid_cnt ends up 1, this will be it */
1528.     for (obj = invent; obj; obj = obj->nobj)
1529. 	if (not_fully_identified(obj)) ++unid_cnt, the_obj = obj;
1530. 
1531.     if (!unid_cnt) {
1532. 	You("have already identified all of your possessions.");
1533.     } else if (!id_limit) {
1534. 	/* identify everything */
1535. 	if (unid_cnt == 1) {
1536. 	    (void) identify(the_obj);
1537. 	} else {
1538. 
1539. 	    /* TODO:  use fully_identify_obj and cornline/menu/whatever here */
1540. 	    for (obj = invent; obj; obj = obj->nobj)
1541. 		if (not_fully_identified(obj)) (void) identify(obj);
1542. 
1543. 	}
1544.     } else {
1545. 	/* identify up to `id_limit' items */
1546. 	n = 0;
1547. 	if (flags.menu_style == MENU_TRADITIONAL)
1548. 	    do {
1549. 		n = ggetobj("identify", identify, id_limit, FALSE, (unsigned *)0);
1550. 		if (n < 0) break; /* quit or no eligible items */
1551. 	    } while ((id_limit -= n) > 0);
1552. 	if (n == 0 || n < -1)
1553. 	    menu_identify(id_limit);
1554.     }
1555.     update_inventory();
1556. }
1557. 
1558. #endif /* OVLB */

obj_to_let Edit

1559. #ifdef OVL2
1560. 
1561. STATIC_OVL char
1562. obj_to_let(obj)	/* should of course only be called for things in invent */
1563. register struct obj *obj;
1564. {
1565. #ifndef GOLDOBJ
1566. 	if (obj->oclass == COIN_CLASS)
1567. 		return GOLD_SYM;
1568. #endif
1569. 	if (!flags.invlet_constant) {
1570. 		obj->invlet = NOINVSYM;
1571. 		reassign();
1572. 	}
1573. 	return obj->invlet;
1574. }
1575. 

prinv Edit

1576. /*
1577.  * Print the indicated quantity of the given object.  If quan == 0L then use
1578.  * the current quantity.
1579.  */
1580. void
1581. prinv(prefix, obj, quan)
1582. const char *prefix;
1583. register struct obj *obj;
1584. long quan;
1585. {
1586. 	if (!prefix) prefix = "";
1587. 	pline("%s%s%s",
1588. 	      prefix, *prefix ? " " : "",
1589. 	      xprname(obj, (char *)0, obj_to_let(obj), TRUE, 0L, quan));
1590. }
1591. 
1592. #endif /* OVL2 */

xprname Edit

1593. #ifdef OVL1
1594. 
1595. char *
1596. xprname(obj, txt, let, dot, cost, quan)
1597. struct obj *obj;
1598. const char *txt;	/* text to print instead of obj */
1599. char let;		/* inventory letter */
1600. boolean dot;		/* append period; (dot && cost => Iu) */
1601. long cost;		/* cost (for inventory of unpaid or expended items) */
1602. long quan;		/* if non-0, print this quantity, not obj->quan */
1603. {
1604. #ifdef LINT	/* handle static char li[BUFSZ]; */
1605.     char li[BUFSZ];
1606. #else
1607.     static char li[BUFSZ];
1608. #endif
1609.     boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
1610.     long savequan = 0;
1611. 
1612.     if (quan && obj) {
1613. 	savequan = obj->quan;
1614. 	obj->quan = quan;
1615.     }
1616. 
1617.     /*
1618.      * If let is:
1619.      *	*  Then obj == null and we are printing a total amount.
1620.      *	>  Then the object is contained and doesn't have an inventory letter.
1621.      */
1622.     if (cost != 0 || let == '*') {
1623. 	/* if dot is true, we're doing Iu, otherwise Ix */
1624. 	Sprintf(li, "%c - %-45s %6ld %s",
1625. 		(dot && use_invlet ? obj->invlet : let),
1626. 		(txt ? txt : doname(obj)), cost, currency(cost));
1627. #ifndef GOLDOBJ
1628.     } else if (obj && obj->oclass == COIN_CLASS) {
1629. 	Sprintf(li, "%ld gold piece%s%s", obj->quan, plur(obj->quan),
1630. 		(dot ? "." : ""));
1631. #endif
1632.     } else {
1633. 	/* ordinary inventory display or pickup message */
1634. 	Sprintf(li, "%c - %s%s",
1635. 		(use_invlet ? obj->invlet : let),
1636. 		(txt ? txt : doname(obj)), (dot ? "." : ""));
1637.     }
1638.     if (savequan) obj->quan = savequan;
1639. 
1640.     return li;
1641. }
1642. 
1643. #endif /* OVL1 */

ddoinv Edit

1644. #ifdef OVLB
1645. 
1646. /* the 'i' command */
1647. int
1648. ddoinv()
1649. {
1650. 	(void) display_inventory((char *)0, FALSE);
1651. 	return 0;
1652. }
1653. 

find_unpaid Edit

1654. /*
1655.  * find_unpaid()
1656.  *
1657.  * Scan the given list of objects.  If last_found is NULL, return the first
1658.  * unpaid object found.  If last_found is not NULL, then skip over unpaid
1659.  * objects until last_found is reached, then set last_found to NULL so the
1660.  * next unpaid object is returned.  This routine recursively follows
1661.  * containers.
1662.  */
1663. STATIC_OVL struct obj *
1664. find_unpaid(list, last_found)
1665.     struct obj *list, **last_found;
1666. {
1667.     struct obj *obj;
1668. 
1669.     while (list) {
1670. 	if (list->unpaid) {
1671. 	    if (*last_found) {
1672. 		/* still looking for previous unpaid object */
1673. 		if (list == *last_found)
1674. 		    *last_found = (struct obj *) 0;
1675. 	    } else
1676. 		return (*last_found = list);
1677. 	}
1678. 	if (Has_contents(list)) {
1679. 	    if ((obj = find_unpaid(list->cobj, last_found)) != 0)
1680. 		return obj;
1681. 	}
1682. 	list = list->nobj;
1683.     }
1684.     return (struct obj *) 0;
1685. }
1686. 

display_pickinv Edit

1687. /*
1688.  * Internal function used by display_inventory and getobj that can display
1689.  * inventory and return a count as well as a letter. If out_cnt is not null,
1690.  * any count returned from the menu selection is placed here.
1691.  */
1692. static char
1693. display_pickinv(lets, want_reply, out_cnt)
1694. register const char *lets;
1695. boolean want_reply;
1696. long* out_cnt;
1697. {
1698. 	struct obj *otmp;
1699. 	char ilet, ret;
1700. 	char *invlet = flags.inv_order;
1701. 	int n, classcount;
1702. 	winid win;				/* windows being used */
1703. 	static winid local_win = WIN_ERR;	/* window for partial menus */
1704. 	anything any;
1705. 	menu_item *selected;
1706. 
1707. 	/* overriden by global flag */
1708. 	if (flags.perm_invent) {
1709. 	    win = (lets && *lets) ? local_win : WIN_INVEN;
1710. 	    /* create the first time used */
1711. 	    if (win == WIN_ERR)
1712. 		win = local_win = create_nhwindow(NHW_MENU);
1713. 	} else
1714. 	    win = WIN_INVEN;
1715. 
1716. 	/*
1717. 	Exit early if no inventory -- but keep going if we are doing
1718. 	a permanent inventory update.  We need to keep going so the
1719. 	permanent inventory window updates itself to remove the last
1720. 	item(s) dropped.  One down side:  the addition of the exception
1721. 	for permanent inventory window updates _can_ pop the window
1722. 	up when it's not displayed -- even if it's empty -- because we
1723. 	don't know at this level if its up or not.  This may not be
1724. 	an issue if empty checks are done before hand and the call
1725. 	to here is short circuited away.
1726. 	*/
1727. 	if (!invent && !(flags.perm_invent && !lets && !want_reply)) {
1728. #ifndef GOLDOBJ
1729. 	    pline("Not carrying anything%s.", u.ugold ? " except gold" : "");
1730. #else
1731. 	    pline("Not carrying anything.");
1732. #endif
1733. 	    return 0;
1734. 	}
1735. 
1736. 	/* oxymoron? temporarily assign permanent inventory letters */
1737. 	if (!flags.invlet_constant) reassign();
1738. 
1739. 	if (lets && strlen(lets) == 1) {
1740. 	    /* when only one item of interest, use pline instead of menus;
1741. 	       we actually use a fake message-line menu in order to allow
1742. 	       the user to perform selection at the --More-- prompt for tty */
1743. 	    ret = '\0';
1744. 	    for (otmp = invent; otmp; otmp = otmp->nobj) {
1745. 		if (otmp->invlet == lets[0]) {
1746. 		    ret = message_menu(lets[0],
1747. 			  want_reply ? PICK_ONE : PICK_NONE,
1748. 			  xprname(otmp, (char *)0, lets[0], TRUE, 0L, 0L));
1749. 		    if (out_cnt) *out_cnt = -1L;	/* select all */
1750. 		    break;
1751. 		}
1752. 	    }
1753. 	    return ret;
1754. 	}
1755. 
1756. 	start_menu(win);
1757. nextclass:
1758. 	classcount = 0;
1759. 	any.a_void = 0;		/* set all bits to zero */
1760. 	for(otmp = invent; otmp; otmp = otmp->nobj) {
1761. 		ilet = otmp->invlet;
1762. 		if(!lets || !*lets || index(lets, ilet)) {
1763. 			if (!flags.sortpack || otmp->oclass == *invlet) {
1764. 			    if (flags.sortpack && !classcount) {
1765. 				any.a_void = 0;		/* zero */
1766. 				add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
1767. 				    let_to_name(*invlet, FALSE), MENU_UNSELECTED);
1768. 				classcount++;
1769. 			    }
1770. 			    any.a_char = ilet;
1771. 			    add_menu(win, obj_to_glyph(otmp),
1772. 					&any, ilet, 0, ATR_NONE, doname(otmp),
1773. 					MENU_UNSELECTED);
1774. 			}
1775. 		}
1776. 	}
1777. 	if (flags.sortpack) {
1778. 		if (*++invlet) goto nextclass;
1779. #ifdef WIZARD
1780. 		if (--invlet != venom_inv) {
1781. 			invlet = venom_inv;
1782. 			goto nextclass;
1783. 		}
1784. #endif
1785. 	}
1786. 	end_menu(win, (char *) 0);
1787. 
1788. 	n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
1789. 	if (n > 0) {
1790. 	    ret = selected[0].item.a_char;
1791. 	    if (out_cnt) *out_cnt = selected[0].count;
1792. 	    free((genericptr_t)selected);
1793. 	} else
1794. 	    ret = !n ? '\0' : '\033';	/* cancelled */
1795. 
1796. 	return ret;
1797. }
1798. 

display_inventory Edit

1799. /*
1800.  * If lets == NULL or "", list all objects in the inventory.  Otherwise,
1801.  * list all objects with object classes that match the order in lets.
1802.  *
1803.  * Returns the letter identifier of a selected item, or 0 if nothing
1804.  * was selected.
1805.  */
1806. char
1807. display_inventory(lets, want_reply)
1808. register const char *lets;
1809. boolean want_reply;
1810. {
1811. 	return display_pickinv(lets, want_reply, (long *)0);
1812. }
1813. 

count_unpaid Edit

1814. /*
1815.  * Returns the number of unpaid items within the given list.  This includes
1816.  * contained objects.
1817.  */
1818. int
1819. count_unpaid(list)
1820.     struct obj *list;
1821. {
1822.     int count = 0;
1823. 
1824.     while (list) {
1825. 	if (list->unpaid) count++;
1826. 	if (Has_contents(list))
1827. 	    count += count_unpaid(list->cobj);
1828. 	list = list->nobj;
1829.     }
1830.     return count;
1831. }
1832. 

count_buc Edit

1833. /*
1834.  * Returns the number of items with b/u/c/unknown within the given list.  
1835.  * This does NOT include contained objects.
1836.  */
1837. int
1838. count_buc(list, type)
1839.     struct obj *list;
1840.     int type;
1841. {
1842.     int count = 0;
1843. 
1844.     while (list) {
1845. 	if (Role_if(PM_PRIEST)) list->bknown = TRUE;
1846. 	switch(type) {
1847. 	    case BUC_BLESSED:
1848. 		if (list->oclass != COIN_CLASS && list->bknown && list->blessed)
1849. 		    count++;
1850. 		break;
1851. 	    case BUC_CURSED:
1852. 		if (list->oclass != COIN_CLASS && list->bknown && list->cursed)
1853. 		    count++;
1854. 		break;
1855. 	    case BUC_UNCURSED:
1856. 		if (list->oclass != COIN_CLASS &&
1857. 			list->bknown && !list->blessed && !list->cursed)
1858. 		    count++;
1859. 		break;
1860. 	    case BUC_UNKNOWN:
1861. 		if (list->oclass != COIN_CLASS && !list->bknown)
1862. 		    count++;
1863. 		break;
1864. 	    default:
1865. 		impossible("need count of curse status %d?", type);
1866. 		return 0;
1867. 	}
1868. 	list = list->nobj;
1869.     }
1870.     return count;
1871. }
1872. 

dounpaid Edit

1873. STATIC_OVL void
1874. dounpaid()
1875. {
1876.     winid win;
1877.     struct obj *otmp, *marker;
1878.     register char ilet;
1879.     char *invlet = flags.inv_order;
1880.     int classcount, count, num_so_far;
1881.     int save_unpaid = 0;	/* lint init */
1882.     long cost, totcost;
1883. 
1884.     count = count_unpaid(invent);
1885. 
1886.     if (count == 1) {
1887. 	marker = (struct obj *) 0;
1888. 	otmp = find_unpaid(invent, &marker);
1889. 
1890. 	/* see if the unpaid item is in the top level inventory */
1891. 	for (marker = invent; marker; marker = marker->nobj)
1892. 	    if (marker == otmp) break;
1893. 
1894. 	pline("%s", xprname(otmp, distant_name(otmp, doname),
1895. 			    marker ? otmp->invlet : CONTAINED_SYM,
1896. 			    TRUE, unpaid_cost(otmp), 0L));
1897. 	return;
1898.     }
1899. 
1900.     win = create_nhwindow(NHW_MENU);
1901.     cost = totcost = 0;
1902.     num_so_far = 0;	/* count of # printed so far */
1903.     if (!flags.invlet_constant) reassign();
1904. 
1905.     do {
1906. 	classcount = 0;
1907. 	for (otmp = invent; otmp; otmp = otmp->nobj) {
1908. 	    ilet = otmp->invlet;
1909. 	    if (otmp->unpaid) {
1910. 		if (!flags.sortpack || otmp->oclass == *invlet) {
1911. 		    if (flags.sortpack && !classcount) {
1912. 			putstr(win, 0, let_to_name(*invlet, TRUE));
1913. 			classcount++;
1914. 		    }
1915. 
1916. 		    totcost += cost = unpaid_cost(otmp);
1917. 		    /* suppress "(unpaid)" suffix */
1918. 		    save_unpaid = otmp->unpaid;
1919. 		    otmp->unpaid = 0;
1920. 		    putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
1921. 					   ilet, TRUE, cost, 0L));
1922. 		    otmp->unpaid = save_unpaid;
1923. 		    num_so_far++;
1924. 		}
1925. 	    }
1926. 	}
1927.     } while (flags.sortpack && (*++invlet));
1928. 
1929.     if (count > num_so_far) {
1930. 	/* something unpaid is contained */
1931. 	if (flags.sortpack)
1932. 	    putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE));
1933. 	/*
1934. 	 * Search through the container objects in the inventory for
1935. 	 * unpaid items.  The top level inventory items have already
1936. 	 * been listed.
1937. 	 */
1938. 	for (otmp = invent; otmp; otmp = otmp->nobj) {
1939. 	    if (Has_contents(otmp)) {
1940. 		marker = (struct obj *) 0;	/* haven't found any */
1941. 		while (find_unpaid(otmp->cobj, &marker)) {
1942. 		    totcost += cost = unpaid_cost(marker);
1943. 		    save_unpaid = marker->unpaid;
1944. 		    marker->unpaid = 0;    /* suppress "(unpaid)" suffix */
1945. 		    putstr(win, 0,
1946. 			   xprname(marker, distant_name(marker, doname),
1947. 				   CONTAINED_SYM, TRUE, cost, 0L));
1948. 		    marker->unpaid = save_unpaid;
1949. 		}
1950. 	    }
1951. 	}
1952.     }
1953. 
1954.     putstr(win, 0, "");
1955.     putstr(win, 0, xprname((struct obj *)0, "Total:", '*', FALSE, totcost, 0L));
1956.     display_nhwindow(win, FALSE);
1957.     destroy_nhwindow(win);
1958. }
1959. 
1960. 

this_type_only Edit

1961. /* query objlist callback: return TRUE if obj type matches "this_type" */
1962. static int this_type;
1963. 
1964. STATIC_OVL boolean
1965. this_type_only(obj)
1966.     struct obj *obj;
1967. {
1968.     return (obj->oclass == this_type);
1969. }
1970. 

dotypeinv Edit

1971. /* the 'I' command */
1972. int
1973. dotypeinv()
1974. {
1975. 	char c = '\0';
1976. 	int n, i = 0;
1977. 	char *extra_types, types[BUFSZ];
1978. 	int class_count, oclass, unpaid_count, itemcount;
1979. 	boolean billx = *u.ushops && doinvbill(0);
1980. 	menu_item *pick_list;
1981. 	boolean traditional = TRUE;
1982. 	const char *prompt = "What type of object do you want an inventory of?";
1983. 
1984. #ifndef GOLDOBJ
1985. 	if (!invent && !u.ugold && !billx) {
1986. #else
1987. 	if (!invent && !billx) {
1988. #endif
1989. 	    You("aren't carrying anything.");
1990. 	    return 0;
1991. 	}
1992. 	unpaid_count = count_unpaid(invent);
1993. 	if (flags.menu_style != MENU_TRADITIONAL) {
1994. 	    if (flags.menu_style == MENU_FULL ||
1995. 				flags.menu_style == MENU_PARTIAL) {
1996. 		traditional = FALSE;
1997. 		i = UNPAID_TYPES;
1998. 		if (billx) i |= BILLED_TYPES;
1999. 		n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
2000. 		if (!n) return 0;
2001. 		this_type = c = pick_list[0].item.a_int;
2002. 		free((genericptr_t) pick_list);
2003. 	    }
2004. 	}
2005. 	if (traditional) {
2006. 	    /* collect a list of classes of objects carried, for use as a prompt */
2007. 	    types[0] = 0;
2008. 	    class_count = collect_obj_classes(types, invent,
2009. 					      FALSE,
2010. #ifndef GOLDOBJ
2011. 					      (u.ugold != 0),
2012. #endif
2013. 					      (boolean FDECL((*),(OBJ_P))) 0, &itemcount);
2014. 	    if (unpaid_count) {
2015. 		Strcat(types, "u");
2016. 		class_count++;
2017. 	    }
2018. 	    if (billx) {
2019. 		Strcat(types, "x");
2020. 		class_count++;
2021. 	    }
2022. 	    /* add everything not already included; user won't see these */
2023. 	    extra_types = eos(types);
2024. 	    *extra_types++ = '\033';
2025. 	    if (!unpaid_count) *extra_types++ = 'u';
2026. 	    if (!billx) *extra_types++ = 'x';
2027. 	    *extra_types = '\0';	/* for index() */
2028. 	    for (i = 0; i < MAXOCLASSES; i++)
2029. 		if (!index(types, def_oc_syms[i])) {
2030. 		    *extra_types++ = def_oc_syms[i];
2031. 		    *extra_types = '\0';
2032. 		}
2033. 
2034. 	    if(class_count > 1) {
2035. 		c = yn_function(prompt, types, '\0');
2036. #ifdef REDO
2037. 		savech(c);
2038. #endif
2039. 		if(c == '\0') {
2040. 			clear_nhwindow(WIN_MESSAGE);
2041. 			return 0;
2042. 		}
2043. 	    } else {
2044. 		/* only one thing to itemize */
2045. 		if (unpaid_count)
2046. 		    c = 'u';
2047. 		else if (billx)
2048. 		    c = 'x';
2049. 		else
2050. 		    c = types[0];
2051. 	    }
2052. 	}
2053. 	if (c == 'x') {
2054. 	    if (billx)
2055. 		(void) doinvbill(1);
2056. 	    else
2057. 		pline("No used-up objects on your shopping bill.");
2058. 	    return 0;
2059. 	}
2060. 	if (c == 'u') {
2061. 	    if (unpaid_count)
2062. 		dounpaid();
2063. 	    else
2064. 		You("are not carrying any unpaid objects.");
2065. 	    return 0;
2066. 	}
2067. 	if (traditional) {
2068. 	    oclass = def_char_to_objclass(c); /* change to object class */
2069. 	    if (oclass == COIN_CLASS) {
2070. 		return doprgold();
2071. 	    } else if (index(types, c) > index(types, '\033')) {
2072. 		You("have no such objects.");
2073. 		return 0;
2074. 	    }
2075. 	    this_type = oclass;
2076. 	}
2077. 	if (query_objlist((char *) 0, invent,
2078. 		    (flags.invlet_constant ? USE_INVLET : 0)|INVORDER_SORT,
2079. 		    &pick_list, PICK_NONE, this_type_only) > 0)
2080. 	    free((genericptr_t)pick_list);
2081. 	return 0;
2082. }
2083. 

dfeature_at Edit

2084. /* return a string describing the dungeon feature at <x,y> if there
2085.    is one worth mentioning at that location; otherwise null */
2086. const char *
2087. dfeature_at(x, y, buf)
2088. int x, y;
2089. char *buf;
2090. {
2091. 	struct rm *lev = &levl[x][y];
2092. 	int ltyp = lev->typ, cmap = -1;
2093. 	const char *dfeature = 0;
2094. 	static char altbuf[BUFSZ];
2095. 
2096. 	if (IS_DOOR(ltyp)) {
2097. 	    switch (lev->doormask) {
2098. 	    case D_NODOOR:	cmap = S_ndoor; break;	/* "doorway" */
2099. 	    case D_ISOPEN:	cmap = S_vodoor; break;	/* "open door" */
2100. 	    case D_BROKEN:	dfeature = "broken door"; break;
2101. 	    default:	cmap = S_vcdoor; break;	/* "closed door" */
2102. 	    }
2103. 	    /* override door description for open drawbridge */
2104. 	    if (is_drawbridge_wall(x, y) >= 0)
2105. 		dfeature = "open drawbridge portcullis",  cmap = -1;
2106. 	} else if (IS_FOUNTAIN(ltyp))
2107. 	    cmap = S_fountain;				/* "fountain" */
2108. 	else if (IS_THRONE(ltyp))
2109. 	    cmap = S_throne;				/* "opulent throne" */
2110. 	else if (is_lava(x,y))
2111. 	    cmap = S_lava;				/* "molten lava" */
2112. 	else if (is_ice(x,y))
2113. 	    cmap = S_ice;				/* "ice" */
2114. 	else if (is_pool(x,y))
2115. 	    dfeature = "pool of water";
2116. #ifdef SINKS
2117. 	else if (IS_SINK(ltyp))
2118. 	    cmap = S_sink;				/* "sink" */
2119. #endif
2120. 	else if (IS_ALTAR(ltyp)) {
2121. 	    Sprintf(altbuf, "altar to %s (%s)", a_gname(),
2122. 		    align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
2123. 	    dfeature = altbuf;
2124. 	} else if ((x == xupstair && y == yupstair) ||
2125. 		 (x == sstairs.sx && y == sstairs.sy && sstairs.up))
2126. 	    cmap = S_upstair;				/* "staircase up" */
2127. 	else if ((x == xdnstair && y == ydnstair) ||
2128. 		 (x == sstairs.sx && y == sstairs.sy && !sstairs.up))
2129. 	    cmap = S_dnstair;				/* "staircase down" */
2130. 	else if (x == xupladder && y == yupladder)
2131. 	    cmap = S_upladder;				/* "ladder up" */
2132. 	else if (x == xdnladder && y == ydnladder)
2133. 	    cmap = S_dnladder;				/* "ladder down" */
2134. 	else if (ltyp == DRAWBRIDGE_DOWN)
2135. 	    cmap = S_vodbridge;			/* "lowered drawbridge" */
2136. 	else if (ltyp == DBWALL)
2137. 	    cmap = S_vcdbridge;			/* "raised drawbridge" */
2138. 	else if (IS_GRAVE(ltyp))
2139. 	    cmap = S_grave;				/* "grave" */
2140. 	else if (ltyp == TREE)
2141. 	    cmap = S_tree;				/* "tree" */
2142. 	else if (ltyp == IRONBARS)
2143. 	    dfeature = "set of iron bars";
2144. 
2145. 	if (cmap >= 0) dfeature = defsyms[cmap].explanation;
2146. 	if (dfeature) Strcpy(buf, dfeature);
2147. 	return dfeature;
2148. }
2149. 

look_here Edit

2150. /* look at what is here; if there are many objects (5 or more),
2151.    don't show them unless obj_cnt is 0 */
2152. int
2153. look_here(obj_cnt, picked_some)
2154. int obj_cnt;	/* obj_cnt > 0 implies that autopickup is in progess */
2155. boolean picked_some;
2156. {
2157. 	struct obj *otmp;
2158. 	struct trap *trap;
2159. 	const char *verb = Blind ? "feel" : "see";
2160. 	const char *dfeature = (char *)0;
2161. 	char fbuf[BUFSZ], fbuf2[BUFSZ];
2162. 	winid tmpwin;
2163. 	boolean skip_objects = (obj_cnt >= 5), felt_cockatrice = FALSE;
2164. 
2165. 	if (u.uswallow && u.ustuck) {
2166. 	    struct monst *mtmp = u.ustuck;
2167. 	    Sprintf(fbuf, "Contents of %s %s",
2168. 		s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH));
2169. 	    /* Skip "Contents of " by using fbuf index 12 */
2170. 	    You("%s to %s what is lying in %s.",
2171. 		Blind ? "try" : "look around", verb, &fbuf[12]);
2172. 	    otmp = mtmp->minvent;
2173. 	    if (otmp) {
2174. 		for ( ; otmp; otmp = otmp->nobj) {
2175. 			/* If swallower is an animal, it should have become stone but... */
2176. 			if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE);
2177. 		}
2178. 		if (Blind) Strcpy(fbuf, "You feel");
2179. 		Strcat(fbuf,":");
2180. 	    	(void) display_minventory(mtmp, MINV_ALL, fbuf);
2181. 	    } else {
2182. 		You("%s no objects here.", verb);
2183. 	    }
2184. 	    return(!!Blind);
2185. 	}
2186. 	if (!skip_objects && (trap = t_at(u.ux,u.uy)) && trap->tseen)
2187. 		There("is %s here.",
2188. 			an(defsyms[trap_to_defsym(trap->ttyp)].explanation));
2189. 
2190. 	otmp = level.objects[u.ux][u.uy];
2191. 	dfeature = dfeature_at(u.ux, u.uy, fbuf2);
2192. 	if (dfeature && !strcmp(dfeature, "pool of water") && Underwater)
2193. 		dfeature = 0;
2194. 
2195. 	if (Blind) {
2196. 		boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
2197. 		if (dfeature && !strncmp(dfeature, "altar ", 6)) {
2198. 		    /* don't say "altar" twice, dfeature has more info */
2199. 		    You("try to feel what is here.");
2200. 		} else {
2201. 		    You("try to feel what is %s%s.",
2202. 			drift ? "floating here" : "lying here on the ",
2203. 			drift ? ""		: surface(u.ux, u.uy));
2204. 		}
2205. 		if (dfeature && !drift && !strcmp(dfeature, surface(u.ux,u.uy)))
2206. 			dfeature = 0;		/* ice already identifed */
2207. 		if (!can_reach_floor()) {
2208. 			pline("But you can't reach it!");
2209. 			return(0);
2210. 		}
2211. 	}
2212. 
2213. 	if (dfeature)
2214. 		Sprintf(fbuf, "There is %s here.", an(dfeature));
2215. 
2216. 	if (!otmp || is_lava(u.ux,u.uy) || (is_pool(u.ux,u.uy) && !Underwater)) {
2217. 		if (dfeature) pline(fbuf);
2218. 		read_engr_at(u.ux, u.uy); /* Eric Backus */
2219. 		if (!skip_objects && (Blind || !dfeature))
2220. 		    You("%s no objects here.", verb);
2221. 		return(!!Blind);
2222. 	}
2223. 	/* we know there is something here */
2224. 
2225. 	if (skip_objects) {
2226. 	    if (dfeature) pline(fbuf);
2227. 	    read_engr_at(u.ux, u.uy); /* Eric Backus */
2228. 	    There("are %s%s objects here.",
2229. 		  (obj_cnt <= 10) ? "several" : "many",
2230. 		  picked_some ? " more" : "");
2231. 	} else if (!otmp->nexthere) {
2232. 	    /* only one object */
2233. 	    if (dfeature) pline(fbuf);
2234. 	    read_engr_at(u.ux, u.uy); /* Eric Backus */
2235. #ifdef INVISIBLE_OBJECTS
2236. 	    if (otmp->oinvis && !See_invisible) verb = "feel";
2237. #endif
2238. 	    You("%s here %s.", verb, doname(otmp));
2239. 	    if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE);
2240. 	} else {
2241. 	    display_nhwindow(WIN_MESSAGE, FALSE);
2242. 	    tmpwin = create_nhwindow(NHW_MENU);
2243. 	    if(dfeature) {
2244. 		putstr(tmpwin, 0, fbuf);
2245. 		putstr(tmpwin, 0, "");
2246. 	    }
2247. 	    putstr(tmpwin, 0, Blind ? "Things that you feel here:" :
2248. 				      "Things that are here:");
2249. 	    for ( ; otmp; otmp = otmp->nexthere) {
2250. 		if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
2251. 			char buf[BUFSZ];
2252. 			felt_cockatrice = TRUE;
2253. 			Strcpy(buf, doname(otmp));
2254. 			Strcat(buf, "...");
2255. 			putstr(tmpwin, 0, buf);
2256. 			break;
2257. 		}
2258. 		putstr(tmpwin, 0, doname(otmp));
2259. 	    }
2260. 	    display_nhwindow(tmpwin, TRUE);
2261. 	    destroy_nhwindow(tmpwin);
2262. 	    if (felt_cockatrice) feel_cockatrice(otmp, FALSE);
2263. 	    read_engr_at(u.ux, u.uy); /* Eric Backus */
2264. 	}
2265. 	return(!!Blind);
2266. }
2267. 

dolook Edit

2268. /* explicilty look at what is here, including all objects */
2269. int
2270. dolook()
2271. {
2272. 	return look_here(0, FALSE);
2273. }
2274. 

will_feel_cockatrice Edit

2275. boolean
2276. will_feel_cockatrice(otmp, force_touch)
2277. struct obj *otmp;
2278. boolean force_touch;
2279. {
2280. 	if ((Blind || force_touch) && !uarmg && !Stone_resistance &&
2281. 		(otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))
2282. 			return TRUE;
2283. 	return FALSE;
2284. }
2285. 

feel_cockatrice Edit

2286. void
2287. feel_cockatrice(otmp, force_touch)
2288. struct obj *otmp;
2289. boolean force_touch;
2290. {
2291. 	char kbuf[BUFSZ];
2292. 
2293. 	if (will_feel_cockatrice(otmp, force_touch)) {
2294. 	    if(poly_when_stoned(youmonst.data))
2295. 			You("touched the %s corpse with your bare %s.",
2296. 				mons[otmp->corpsenm].mname, makeplural(body_part(HAND)));
2297. 	    else
2298. 			pline("Touching the %s corpse is a fatal mistake...",
2299. 				mons[otmp->corpsenm].mname);
2300. 		Sprintf(kbuf, "%s corpse", an(mons[otmp->corpsenm].mname));
2301. 		instapetrify(kbuf);
2302. 	}
2303. }
2304. 
2305. #endif /* OVLB */

stackobj Edit

2306. #ifdef OVL1
2307. 
2308. void
2309. stackobj(obj)
2310. struct obj *obj;
2311. {
2312. 	struct obj *otmp;
2313. 
2314. 	for(otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
2315. 		if(otmp != obj && merged(&obj,&otmp))
2316. 			break;
2317. 	return;
2318. }
2319. 

mergeable Edit

2320. STATIC_OVL boolean
2321. mergable(otmp, obj)	/* returns TRUE if obj  & otmp can be merged */
2322. 	register struct obj *otmp, *obj;
2323. {
2324. 	if (obj->otyp != otmp->otyp) return FALSE;
2325. #ifdef GOLDOBJ
2326. 	/* coins of the same kind will always merge */
2327. 	if (obj->oclass == COIN_CLASS) return TRUE;
2328. #endif
2329. 	if (obj->unpaid != otmp->unpaid ||
2330. 	    obj->spe != otmp->spe || obj->dknown != otmp->dknown ||
2331. 	    (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) ||
2332. 	    obj->cursed != otmp->cursed || obj->blessed != otmp->blessed ||
2333. 	    obj->no_charge != otmp->no_charge ||
2334. 	    obj->obroken != otmp->obroken ||
2335. 	    obj->otrapped != otmp->otrapped ||
2336. 	    obj->lamplit != otmp->lamplit ||
2337. #ifdef INVISIBLE_OBJECTS
2338. 		obj->oinvis != otmp->oinvis ||
2339. #endif
2340. 	    obj->greased != otmp->greased ||
2341. 	    obj->oeroded != otmp->oeroded ||
2342. 	    obj->oeroded2 != otmp->oeroded2 ||
2343. 	    obj->bypass != otmp->bypass)
2344. 	    return(FALSE);
2345. 
2346. 	if ((obj->oclass==WEAPON_CLASS || obj->oclass==ARMOR_CLASS) &&
2347. 	    (obj->oerodeproof!=otmp->oerodeproof || obj->rknown!=otmp->rknown))
2348. 	    return FALSE;
2349. 
2350. 	if (obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten ||
2351. 					  obj->orotten != otmp->orotten))
2352. 	    return(FALSE);
2353. 
2354. 	if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
2355. 		if (obj->corpsenm != otmp->corpsenm)
2356. 				return FALSE;
2357. 	}
2358. 
2359. 	/* hatching eggs don't merge; ditto for revivable corpses */
2360. 	if ((obj->otyp == EGG && (obj->timed || otmp->timed)) ||
2361. 	    (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM &&
2362. 		is_reviver(&mons[otmp->corpsenm])))
2363. 	    return FALSE;
2364. 
2365. 	/* allow candle merging only if their ages are close */
2366. 	/* see begin_burn() for a reference for the magic "25" */
2367. 	if (Is_candle(obj) && obj->age/25 != otmp->age/25)
2368. 	    return(FALSE);
2369. 
2370. 	/* burning potions of oil never merge */
2371. 	if (obj->otyp == POT_OIL && obj->lamplit)
2372. 	    return FALSE;
2373. 
2374. 	/* don't merge surcharged item with base-cost item */
2375. 	if (obj->unpaid && !same_price(obj, otmp))
2376. 	    return FALSE;
2377. 
2378. 	/* if they have names, make sure they're the same */
2379. 	if ( (obj->onamelth != otmp->onamelth &&
2380. 		((obj->onamelth && otmp->onamelth) || obj->otyp == CORPSE)
2381. 	     ) ||
2382. 	    (obj->onamelth && otmp->onamelth &&
2383. 		    strncmp(ONAME(obj), ONAME(otmp), (int)obj->onamelth)))
2384. 		return FALSE;
2385. 
2386. 	/* for the moment, any additional information is incompatible */
2387. 	if (obj->oxlth || otmp->oxlth) return FALSE;
2388. 
2389. 	if(obj->oartifact != otmp->oartifact) return FALSE;
2390. 
2391. 	if(obj->known == otmp->known ||
2392. 		!objects[otmp->otyp].oc_uses_known) {
2393. 		return((boolean)(objects[obj->otyp].oc_merge));
2394. 	} else return(FALSE);
2395. }
2396. 

doprgold Edit

2397. int
2398. doprgold()
2399. {
2400. 	/* the messages used to refer to "carrying gold", but that didn't
2401. 	   take containers into account */
2402. #ifndef GOLDOBJ
2403. 	if(!u.ugold)
2404. 	    Your("wallet is empty.");
2405. 	else
2406. 	    Your("wallet contains %ld gold piece%s.", u.ugold, plur(u.ugold));
2407. #else
2408.         long umoney = money_cnt(invent);
2409. 	if(!umoney)
2410. 	    Your("wallet is empty.");
2411. 	else
2412. 	    Your("wallet contains %ld %s.", umoney, currency(umoney));
2413. #endif
2414. 	shopper_financial_report();
2415. 	return 0;
2416. }
2417. 
2418. #endif /* OVL1 */

doprwep Edit

2419. #ifdef OVLB
2420. 
2421. int
2422. doprwep()
2423. {
2424.     if (!uwep) {
2425. 	You("are empty %s.", body_part(HANDED));
2426.     } else {
2427. 	prinv((char *)0, uwep, 0L);
2428. 	if (u.twoweap) prinv((char *)0, uswapwep, 0L);
2429.     }
2430.     return 0;
2431. }
2432. 

doprarm Edit

2433. int
2434. doprarm()
2435. {
2436. 	if(!wearing_armor())
2437. 		You("are not wearing any armor.");
2438. 	else {
2439. #ifdef TOURIST
2440. 		char lets[8];
2441. #else
2442. 		char lets[7];
2443. #endif
2444. 		register int ct = 0;
2445. 
2446. #ifdef TOURIST
2447. 		if(uarmu) lets[ct++] = obj_to_let(uarmu);
2448. #endif
2449. 		if(uarm) lets[ct++] = obj_to_let(uarm);
2450. 		if(uarmc) lets[ct++] = obj_to_let(uarmc);
2451. 		if(uarmh) lets[ct++] = obj_to_let(uarmh);
2452. 		if(uarms) lets[ct++] = obj_to_let(uarms);
2453. 		if(uarmg) lets[ct++] = obj_to_let(uarmg);
2454. 		if(uarmf) lets[ct++] = obj_to_let(uarmf);
2455. 		lets[ct] = 0;
2456. 		(void) display_inventory(lets, FALSE);
2457. 	}
2458. 	return 0;
2459. }
2460. 

doprring Edit

2461. int
2462. doprring()
2463. {
2464. 	if(!uleft && !uright)
2465. 		You("are not wearing any rings.");
2466. 	else {
2467. 		char lets[3];
2468. 		register int ct = 0;
2469. 
2470. 		if(uleft) lets[ct++] = obj_to_let(uleft);
2471. 		if(uright) lets[ct++] = obj_to_let(uright);
2472. 		lets[ct] = 0;
2473. 		(void) display_inventory(lets, FALSE);
2474. 	}
2475. 	return 0;
2476. }
2477. 

dopramulet Edit

2478. int
2479. dopramulet()
2480. {
2481. 	if (!uamul)
2482. 		You("are not wearing an amulet.");
2483. 	else
2484. 		prinv((char *)0, uamul, 0L);
2485. 	return 0;
2486. }
2487. 

tool_in_use Edit

2488. STATIC_OVL boolean
2489. tool_in_use(obj)
2490. struct obj *obj;
2491. {
2492. 	if ((obj->owornmask & (W_TOOL
2493. #ifdef STEED
2494. 			| W_SADDLE
2495. #endif
2496. 			)) != 0L) return TRUE;
2497. 	if (obj->oclass != TOOL_CLASS) return FALSE;
2498. 	return (boolean)(obj == uwep || obj->lamplit ||
2499. 				(obj->otyp == LEASH && obj->leashmon));
2500. }
2501. 

doprtool Edit

2502. int
2503. doprtool()
2504. {
2505. 	struct obj *otmp;
2506. 	int ct = 0;
2507. 	char lets[52+1];
2508. 
2509. 	for (otmp = invent; otmp; otmp = otmp->nobj)
2510. 	    if (tool_in_use(otmp))
2511. 		lets[ct++] = obj_to_let(otmp);
2512. 	lets[ct] = '\0';
2513. 	if (!ct) You("are not using any tools.");
2514. 	else (void) display_inventory(lets, FALSE);
2515. 	return 0;
2516. }
2517. 

doprinuse Edit

2518. /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
2519.    show inventory of all currently wielded, worn, or used objects */
2520. int
2521. doprinuse()
2522. {
2523. 	struct obj *otmp;
2524. 	int ct = 0;
2525. 	char lets[52+1];
2526. 
2527. 	for (otmp = invent; otmp; otmp = otmp->nobj)
2528. 	    if (is_worn(otmp) || tool_in_use(otmp))
2529. 		lets[ct++] = obj_to_let(otmp);
2530. 	lets[ct] = '\0';
2531. 	if (!ct) You("are not wearing or wielding anything.");
2532. 	else (void) display_inventory(lets, FALSE);
2533. 	return 0;
2534. }
2535. 

useupf Edit

2536. /*
2537.  * uses up an object that's on the floor, charging for it as necessary
2538.  */
2539. void
2540. useupf(obj, numused)
2541. register struct obj *obj;
2542. long numused;
2543. {
2544. 	register struct obj *otmp;
2545. 	boolean at_u = (obj->ox == u.ux && obj->oy == u.uy);
2546. 
2547. 	/* burn_floor_paper() keeps an object pointer that it tries to
2548. 	 * useupf() multiple times, so obj must survive if plural */
2549. 	if (obj->quan > numused)
2550. 		otmp = splitobj(obj, numused);
2551. 	else
2552. 		otmp = obj;
2553. 	if(costly_spot(otmp->ox, otmp->oy)) {
2554. 	    if(index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
2555. 	        addtobill(otmp, FALSE, FALSE, FALSE);
2556. 	    else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
2557. 	}
2558. 	delobj(otmp);
2559. 	if (at_u && u.uundetected && hides_under(youmonst.data))
2560. 	    u.uundetected = OBJ_AT(u.ux, u.uy);
2561. }
2562. 
2563. #endif /* OVLB */
2564. 
2565. 

let_to_name Edit

2566. #ifdef OVL1
2567. 
2568. /*
2569.  * Conversion from a class to a string for printing.
2570.  * This must match the object class order.
2571.  */
2572. STATIC_VAR NEARDATA const char *names[] = { 0,
2573. 	"Illegal objects", "Weapons", "Armor", "Rings", "Amulets",
2574. 	"Tools", "Comestibles", "Potions", "Scrolls", "Spellbooks",
2575. 	"Wands", "Coins", "Gems", "Boulders/Statues", "Iron balls",
2576. 	"Chains", "Venoms"
2577. };
2578. 
2579. static NEARDATA const char oth_symbols[] = {
2580. 	CONTAINED_SYM,
2581. 	'\0'
2582. };
2583. 
2584. static NEARDATA const char *oth_names[] = {
2585. 	"Bagged/Boxed items"
2586. };
2587. 
2588. static NEARDATA char *invbuf = (char *)0;
2589. static NEARDATA unsigned invbufsiz = 0;
2590. 
2591. char *
2592. let_to_name(let,unpaid)
2593. char let;
2594. boolean unpaid;
2595. {
2596. 	const char *class_name;
2597. 	const char *pos;
2598. 	int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
2599. 	unsigned len;
2600. 
2601. 	if (oclass)
2602. 	    class_name = names[oclass];
2603. 	else if ((pos = index(oth_symbols, let)) != 0)
2604. 	    class_name = oth_names[pos - oth_symbols];
2605. 	else
2606. 	    class_name = names[0];
2607. 
2608. 	len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "");
2609. 	if (len > invbufsiz) {
2610. 	    if (invbuf) free((genericptr_t)invbuf);
2611. 	    invbufsiz = len + 10; /* add slop to reduce incremental realloc */
2612. 	    invbuf = (char *) alloc(invbufsiz);
2613. 	}
2614. 	if (unpaid)
2615. 	    Strcat(strcpy(invbuf, "Unpaid "), class_name);
2616. 	else
2617. 	    Strcpy(invbuf, class_name);
2618. 	return invbuf;
2619. }
2620. 

free_invbuf Edit

2621. void
2622. free_invbuf()
2623. {
2624. 	if (invbuf) free((genericptr_t)invbuf),  invbuf = (char *)0;
2625. 	invbufsiz = 0;
2626. }
2627. 
2628. #endif /* OVL1 */

reassign Edit

2629. #ifdef OVLB
2630. 
2631. void
2632. reassign()
2633. {
2634. 	register int i;
2635. 	register struct obj *obj;
2636. 
2637. 	for(obj = invent, i = 0; obj; obj = obj->nobj, i++)
2638. 		obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26);
2639. 	lastinvnr = i;
2640. }
2641. 
2642. #endif /* OVLB */

doorganize Edit

2643. #ifdef OVL1
2644. 
2645. int
2646. doorganize()	/* inventory organizer by Del Lamb */
2647. {
2648. 	struct obj *obj, *otmp;
2649. 	register int ix, cur;
2650. 	register char let;
2651. 	char alphabet[52+1], buf[52+1];
2652. 	char qbuf[QBUFSZ];
2653. 	char allowall[2];
2654. 	const char *adj_type;
2655. 
2656. 	if (!flags.invlet_constant) reassign();
2657. 	/* get a pointer to the object the user wants to organize */
2658. 	allowall[0] = ALL_CLASSES; allowall[1] = '\0';
2659. 	if (!(obj = getobj(allowall,"adjust"))) return(0);
2660. 
2661. 	/* initialize the list with all upper and lower case letters */
2662. 	for (let = 'a', ix = 0;  let <= 'z';) alphabet[ix++] = let++;
2663. 	for (let = 'A', ix = 26; let <= 'Z';) alphabet[ix++] = let++;
2664. 	alphabet[52] = 0;
2665. 
2666. 	/* blank out all the letters currently in use in the inventory */
2667. 	/* except those that will be merged with the selected object   */
2668. 	for (otmp = invent; otmp; otmp = otmp->nobj)
2669. 		if (otmp != obj && !mergable(otmp,obj)) {
2670. 			if (otmp->invlet <= 'Z')
2671. 				alphabet[(otmp->invlet) - 'A' + 26] = ' ';
2672. 			else	alphabet[(otmp->invlet) - 'a']	    = ' ';
2673. 		}
2674. 
2675. 	/* compact the list by removing all the blanks */
2676. 	for (ix = cur = 0; ix <= 52; ix++)
2677. 		if (alphabet[ix] != ' ') buf[cur++] = alphabet[ix];
2678. 
2679. 	/* and by dashing runs of letters */
2680. 	if(cur > 5) compactify(buf);
2681. 
2682. 	/* get new letter to use as inventory letter */
2683. 	for (;;) {
2684. 		Sprintf(qbuf, "Adjust letter to what [%s]?",buf);
2685. 		let = yn_function(qbuf, (char *)0, '\0');
2686. 		if(index(quitchars,let)) {
2687. 			pline(Never_mind);
2688. 			return(0);
2689. 		}
2690. 		if (let == '@' || !letter(let))
2691. 			pline("Select an inventory slot letter.");
2692. 		else
2693. 			break;
2694. 	}
2695. 
2696. 	/* change the inventory and print the resulting item */
2697. 	adj_type = "Moving:";
2698. 
2699. 	/*
2700. 	 * don't use freeinv/addinv to avoid double-touching artifacts,
2701. 	 * dousing lamps, losing luck, cursing loadstone, etc.
2702. 	 */
2703. 	extract_nobj(obj, &invent);
2704. 
2705. 	for (otmp = invent; otmp;)
2706. 		if (merged(&otmp,&obj)) {
2707. 			adj_type = "Merging:";
2708. 			obj = otmp;
2709. 			otmp = otmp->nobj;
2710. 			extract_nobj(obj, &invent);
2711. 		} else {
2712. 			if (otmp->invlet == let) {
2713. 				adj_type = "Swapping:";
2714. 				otmp->invlet = obj->invlet;
2715. 			}
2716. 			otmp = otmp->nobj;
2717. 		}
2718. 
2719. 	/* inline addinv (assuming flags.invlet_constant and !merged) */
2720. 	obj->invlet = let;
2721. 	obj->nobj = invent; /* insert at beginning */
2722. 	obj->where = OBJ_INVENT;
2723. 	invent = obj;
2724. 	reorder_invent();
2725. 
2726. 	prinv(adj_type, obj, 0L);
2727. 	update_inventory();
2728. 	return(0);
2729. }
2730. 

invdisp_nothing Edit

2731. /* common to display_minventory and display_cinventory */
2732. STATIC_OVL void
2733. invdisp_nothing(hdr, txt)
2734. const char *hdr, *txt;
2735. {
2736. 	winid win;
2737. 	anything any;
2738. 	menu_item *selected;
2739. 
2740. 	any.a_void = 0;
2741. 	win = create_nhwindow(NHW_MENU);
2742. 	start_menu(win);
2743. 	add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr, MENU_UNSELECTED);
2744. 	add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
2745. 	add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED);
2746. 	end_menu(win, (char *)0);
2747. 	if (select_menu(win, PICK_NONE, &selected) > 0)
2748. 	    free((genericptr_t)selected);
2749. 	destroy_nhwindow(win);
2750. 	return;
2751. }
2752. 

worn_wield_only Edit

2753. /* query_objlist callback: return things that could possibly be worn/wielded */
2754. STATIC_OVL boolean
2755. worn_wield_only(obj)
2756. struct obj *obj;
2757. {
2758.     return (obj->oclass == WEAPON_CLASS
2759. 		|| obj->oclass == ARMOR_CLASS
2760. 		|| obj->oclass == AMULET_CLASS
2761. 		|| obj->oclass == RING_CLASS
2762. 		|| obj->oclass == TOOL_CLASS);
2763. }
2764. 

display_minventory Edit

2765. /*
2766.  * Display a monster's inventory.
2767.  * Returns a pointer to the object from the monster's inventory selected
2768.  * or NULL if nothing was selected.
2769.  *
2770.  * By default, only worn and wielded items are displayed.  The caller
2771.  * can pick one.  Modifier flags are:
2772.  *
2773.  *	MINV_NOLET	- nothing selectable
2774.  *	MINV_ALL	- display all inventory
2775.  */
2776. struct obj *
2777. display_minventory(mon, dflags, title)
2778. register struct monst *mon;
2779. int dflags;
2780. char *title;
2781. {
2782. 	struct obj *ret;
2783. #ifndef GOLDOBJ
2784. 	struct obj m_gold;
2785. #endif
2786. 	char tmp[QBUFSZ];
2787. 	int n;
2788. 	menu_item *selected = 0;
2789. #ifndef GOLDOBJ
2790. 	int do_all = (dflags & MINV_ALL) != 0,
2791. 	    do_gold = (do_all && mon->mgold);
2792. #else
2793. 	int do_all = (dflags & MINV_ALL) != 0;
2794. #endif
2795. 
2796. 	Sprintf(tmp,"%s %s:", s_suffix(noit_Monnam(mon)),
2797. 		do_all ? "possessions" : "armament");
2798. 
2799. #ifndef GOLDOBJ
2800. 	if (do_all ? (mon->minvent || mon->mgold)
2801. #else
2802. 	if (do_all ? (mon->minvent != 0)
2803. #endif
2804. 		   : (mon->misc_worn_check || MON_WEP(mon))) {
2805. 	    /* Fool the 'weapon in hand' routine into
2806. 	     * displaying 'weapon in claw', etc. properly.
2807. 	     */
2808. 	    youmonst.data = mon->data;
2809. 
2810. #ifndef GOLDOBJ
2811. 	    if (do_gold) {
2812. 		/*
2813. 		 * Make temporary gold object and insert at the head of
2814. 		 * the mon's inventory.  We can get away with using a
2815. 		 * stack variable object because monsters don't carry
2816. 		 * gold in their inventory, so it won't merge.
2817. 		 */
2818. 		m_gold = zeroobj;
2819. 		m_gold.otyp = GOLD_PIECE;  m_gold.oclass = COIN_CLASS;
2820. 		m_gold.quan = mon->mgold;  m_gold.dknown = 1;
2821. 		m_gold.where = OBJ_FREE;
2822. 		/* we had better not merge and free this object... */
2823. 		if (add_to_minv(mon, &m_gold))
2824. 		    panic("display_minventory: static object freed.");
2825. 	    }
2826. 
2827. #endif
2828. 	    n = query_objlist(title ? title : tmp, mon->minvent, INVORDER_SORT, &selected,
2829. 			(dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE,
2830. 			do_all ? allow_all : worn_wield_only);
2831. 
2832. #ifndef GOLDOBJ
2833. 	    if (do_gold) obj_extract_self(&m_gold);
2834. #endif
2835. 
2836. 	    set_uasmon();
2837. 	} else {
2838. 	    invdisp_nothing(title ? title : tmp, "(none)");
2839. 	    n = 0;
2840. 	}
2841. 
2842. 	if (n > 0) {
2843. 	    ret = selected[0].item.a_obj;
2844. 	    free((genericptr_t)selected);
2845. #ifndef GOLDOBJ
2846. 	    /*
2847. 	     * Unfortunately, we can't return a pointer to our temporary
2848. 	     * gold object.  We'll have to work out a scheme where this
2849. 	     * can happen.  Maybe even put gold in the inventory list...
2850. 	     */
2851. 	    if (ret == &m_gold) ret = (struct obj *) 0;
2852. #endif
2853. 	} else
2854. 	    ret = (struct obj *) 0;
2855. 	return ret;
2856. }
2857. 

display_cinventory Edit

2858. /*
2859.  * Display the contents of a container in inventory style.
2860.  * Currently, this is only used for statues, via wand of probing.
2861.  */
2862. struct obj *
2863. display_cinventory(obj)
2864. register struct obj *obj;
2865. {
2866. 	struct obj *ret;
2867. 	char tmp[QBUFSZ];
2868. 	int n;
2869. 	menu_item *selected = 0;
2870. 
2871. 	Sprintf(tmp,"Contents of %s:", doname(obj));
2872. 
2873. 	if (obj->cobj) {
2874. 	    n = query_objlist(tmp, obj->cobj, INVORDER_SORT, &selected,
2875. 			    PICK_NONE, allow_all);
2876. 	} else {
2877. 	    invdisp_nothing(tmp, "(empty)");
2878. 	    n = 0;
2879. 	}
2880. 	if (n > 0) {
2881. 	    ret = selected[0].item.a_obj;
2882. 	    free((genericptr_t)selected);
2883. 	} else
2884. 	    ret = (struct obj *) 0;
2885. 	return ret;
2886. }
2887. 

only_here Edit

2888. /* query objlist callback: return TRUE if obj is at given location */
2889. static coord only;
2890. 
2891. STATIC_OVL boolean
2892. only_here(obj)
2893.     struct obj *obj;
2894. {
2895.     return (obj->ox == only.x && obj->oy == only.y);
2896. }
2897. 

display_binventory Edit

2898. /*
2899.  * Display a list of buried items in inventory style.  Return a non-zero
2900.  * value if there were items at that spot.
2901.  *
2902.  * Currently, this is only used with a wand of probing zapped downwards.
2903.  */
2904. int
2905. display_binventory(x, y, as_if_seen)
2906. int x, y;
2907. boolean as_if_seen;
2908. {
2909. 	struct obj *obj;
2910. 	menu_item *selected = 0;
2911. 	int n;
2912. 
2913. 	/* count # of objects here */
2914. 	for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
2915. 	    if (obj->ox == x && obj->oy == y) {
2916. 		if (as_if_seen) obj->dknown = 1;
2917. 		n++;
2918. 	    }
2919. 
2920. 	if (n) {
2921. 	    only.x = x;
2922. 	    only.y = y;
2923. 	    if (query_objlist("Things that are buried here:",
2924. 			      level.buriedobjlist, INVORDER_SORT,
2925. 			      &selected, PICK_NONE, only_here) > 0)
2926. 		free((genericptr_t)selected);
2927. 	    only.x = only.y = 0;
2928. 	}
2929. 	return n;
2930. }
2931. 
2932. #endif /* OVL1 */
2933. 
2934. /*invent.c*/

Also on Fandom

Random Wiki