Wikia

Wikihack

Source:Objnam.c

2,032pages on
this wiki
Talk0

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

The job of this particular source code file is to give the name of an object as a string. A read will reveal much about how NetHack discloses the identity of objects and how it uses the fields from the struct defined in obj.h. This file also handles putting articles (a, an, the) in front of names, making names plural, and interpreting wishes.

Top of file Edit

1.    /*	SCCS Id: @(#)objnam.c	3.4	2003/12/04	*/
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.    /* "an uncursed greased partly eaten guardian naga hatchling [corpse]" */
8.    #define PREFIX	80	/* (56) */
9.    #define SCHAR_LIM 127
10.   #define NUMOBUF 12
11.   

NetHack employs two unusual ways to manipulate strings in C. It will put some object names (like "corpse") PREFIX characters into a buffer so that it can add prefixes (like "an uncursed greased partly eaten guardian naga hatchling") with the strprepend function. Meanwhile, it statically allocates NUMOBUF buffers of SCHAR_LIM characters each and makes those buffers available to the nextobuf function.

12.   STATIC_DCL char *FDECL(strprepend,(char *,const char *));
13.   #ifdef OVLB
14.   static boolean FDECL(wishymatch, (const char *,const char *,BOOLEAN_P));
15.   #endif
16.   static char *NDECL(nextobuf);
17.   static void FDECL(add_erosion_words, (struct obj *, char *));
18.   

struct Jitem Edit

19.   struct Jitem {
20.   	int item;
21.   	const char *name;
22.   };
23.   

This struct is used for the #Japanese_items array; it associates an object (as identified in onames.h with its Japanese name. For some reason, 3.4.3 has the GemStone macro definition between this struct Jitem definition and the Japanese_items array.

GemStone Edit

24.   /* true for gems/rocks that should have " stone" appended to their names */
25.   #define GemStone(typ)	(typ == FLINT ||				\
26.   			 (objects[typ].oc_material == GEMSTONE &&	\
27.   			  (typ != DILITHIUM_CRYSTAL && typ != RUBY &&	\
28.   			   typ != DIAMOND && typ != SAPPHIRE &&		\
29.   			   typ != BLACK_OPAL && 	\
30.   			   typ != EMERALD && typ != OPAL)))
31.   

The gems as defined at objects.c#line887 do not contain the word "stone" in their names. The GemStone macro takes an object type arguement and returns true for the flint stone and all valuable gems except dilithium crystals, diamonds, black opals, and emeralds, thus indicating that NetHack should add the word stone to make phrases like garnet stone. NetHack also adds the word to the unidentified gray stone.

Japanese_items Edit

32.   #ifndef OVLB
33.   
34.   STATIC_DCL struct Jitem Japanese_items[];
35.   
36.   #else /* OVLB */
37.   
38.   STATIC_OVL struct Jitem Japanese_items[] = {
39.   	{ SHORT_SWORD, "wakizashi" },
40.   	{ BROADSWORD, "ninja-to" },
41.   	{ FLAIL, "nunchaku" },
42.   	{ GLAIVE, "naginata" },
43.   	{ LOCK_PICK, "osaku" },
44.   	{ WOODEN_HARP, "koto" },
45.   	{ KNIFE, "shito" },
46.   	{ PLATE_MAIL, "tanko" },
47.   	{ HELMET, "kabuto" },
48.   	{ LEATHER_GLOVES, "yugake" },
49.   	{ FOOD_RATION, "gunyoki" },
50.   	{ POT_BOOZE, "sake" },
51.   	{0, "" }
52.   };
53.   
54.   #endif /* OVLB */

The array Japanese_items (of #struct Jitem) that maps certain objects to their Japanese names. Samurai see these names instead of the usual names ("short sword", "broadsword", ... "booze").

55.   
56.   STATIC_DCL const char *FDECL(Japanese_item_name,(int i));
57.   

The declaration for the Japanese_item_name function is not with the other functions but instead below the declaration of the Japanese_items array.

strprepend Edit

58.   #ifdef OVL1
59.   
60.   STATIC_OVL char *
61.   strprepend(s,pref)
62.   register char *s;
63.   register const char *pref;
64.   {

This function strprepend does prepend a prefix (such as "3 cursed") to a string (such as "potions of blindness"), then returns a pointer to the new string. It must be only used if there are PREFIX bytes available in memory before the start of the string. So you cannot use this to prepend to any string, but only to strings allocated with that extra space. Any attempt to prepend more than one prefix might cause this function to crash.

65.   	register int i = (int)strlen(pref);

The function first uses strlen to get the length of the prefix, and stores this as int i.

66.   
67.   	if(i > PREFIX) {
68.   		impossible("PREFIX too short (for %d).", i);
69.   		return(s);
70.   	}

Then it does check to make sure that the prefix is not larger than PREFIX. This catches when a programmer needs to increase PREFIX.

71.   	s -= i;

The pointer s now moves backward to the beginning of where the prefix would be prepended.

72.   	(void) strncpy(s, pref, i);	/* do not copy trailing 0 */

Exactly i characters are copied from the prefix to where the pointer s is; this correctly prepends the prefix to the string. Note that strncpy terminates s with the trailing 0 if and only if pref has less than i characters; this is often the source of bugs (and is why *BSD has strlcpy). The call for strprepend is a rare case of strncpy is used correctly but does not terminate the string. The comment "/* do not copy trailing 0 */" is a reminder that this use of strncpy is correct.

73.   	return(s);
74.   }
75.   
76.   #endif /* OVL1 */

At the end, strprepend returns the new pointer to the string including its prefix. The original string pointer passed to strprepend is no longer correct if you want to use the prefix.

nextobuf Edit

77.   #ifdef OVLB
78.   
79.   /* manage a pool of BUFSZ buffers, so callers don't have to */
80.   static char *
81.   nextobuf()
82.   {

The nextobuf function is another unusual tactic in managing memory for strings. Instead of dynamically allocating and freeing buffers, the nextobuf ("next open buffer") function instead returns the next buffer in a group of statically allocated buffers.

83.   	static char NEARDATA bufs[NUMOBUF][BUFSZ];

The bufs array contains the buffers (allocated adjacent to themselves in a two dimensional array). Notice how the buffers are "static", which means that they are stored between calls to nextobuf. (Otherwise each call to nextobuf would create its own buffers on the stack, and deallocate them when nextobuf returned, thus making the buffers useless.)

84.   	static int bufidx = 0;

The int bufidx is also static, and used so that nextobuf remembers which buffer is next. Initially, when the operating system loads NetHack, this value is 0, referring to the very first buffer in the bufs array.

85.   
86.   	bufidx = (bufidx + 1) % NUMOBUF;

Each call to the function increments bufidx. The effect of "% NUMOBUF" is to begin recycling buffers after we have used them all. Because bufidx started at 0, the very first call to nextobuf after NetHack starts will return the buffer at index 1. The next calls use buffers 2, 3, ..., NUMOBUF - 1. The buffer at index 0 is the last buffer used before we begin recycling.

87.   	return bufs[bufidx];
88.   }
89.   

The function returns a pointer to the bufidx buffer.

Compared to dynamic allocation, these few lines of C have some advantages:

  • You do not have to worry about freeing each buffer after you use it. You can just forget about the buffers and wait for them to be recycled.
  • There is a slight decrease in running time. Recycling buffers is slightly faster than freeing them and allocating new ones later. Also, with all buffers allocated together in memory (at program startup, before anyone worries about fragmentation), you are guaranteed to have some locality if you write code that uses multiple buffers.

There are enough disadvantages that nextobuf is not a universal replacement for dynamic allocation:

  • You have to be careful in objnam.c not to call nextobuf too many times and use too many buffers, because it will start recycling buffers before you finish using them. You can only use the NUMOBUF newest buffers.
  • This does not work if you need a buffer larger than BUFSZ.
  • If you increase NUMOBUF and BUFSZ to very large then you start wasting space. (So use nextobuf for NetHack object naming, not for large databases.)

This nextobuf function works well because objects in NetHack can only have names that are so long (for they should fit in the inventory screen on an 80x24 terminal), and the code is relatively linear and does not loop through the creation of many buffers.

Yet many programmers would have just dynamically allocated buffers instead of using a solution such as this.

obj_typename Edit

90.   char *
91.   obj_typename(otyp)
92.   register int otyp;
93.   {

The goal of the obj_typename function is to return type names such as "amethyst stone (violet)", "wand called cancellation (balsa)", "ring of warning (topaz)". The name does not include information not known to the player; an unidentified scroll or spellbook could be "scroll (THARR)" or "spellbook (wrinkled)". The information is only about a particular type of object, and never includes details about a particular object such as counts, BUC statuses, enchantments, or charges. Thus the type is singular, never plural.

For example, a call to otyp(SILVER_DAGGER) returns only "silver dagger". A call to otyp(ELVEN_DAGGER) apparently returns either "elven dagger" or "runed dagger", but not "elven dagger (runed dagger)", because descriptions are only appended for certain classes of objects.

The parameter otyp must be an array index into the global "objects" array. (One can find such indices in the generated file onames.h.) The result is returned in a temporary "nextobuf" buffer, so if you are not using it quickly, then you should copy it to another buffer.

94.   	char *buf = nextobuf();
95.   	register struct objclass *ocl = &objects[otyp];
96.   	register const char *actualn = OBJ_NAME(*ocl);
97.   	register const char *dn = OBJ_DESCR(*ocl);
98.   	register const char *un = ocl->oc_uname;
99.   	register int nn = ocl->oc_name_known;
100.  

The code declares several local variables:

char *buf This is a buffer in which the result will appear.
struct objclass *ocl This is &objects[otyp], a pointer into the data structure that describes this type of object. It contains the info from objects.c and some other information, like whether or not the player has identified this type of object.
const char *actualn This is a buffer containing the actual name of the object, as defined in objects.c. Note that this does not include wording such as "spellbook of" or "wand of". Examples of actual names are "orcish arrow", "levitation boots", "adornment" (for the ring), "protection" (for the ring, and also for the spellbook), "extra healing" (for the potion or the spellbook), "undead turning" (for the wand). However, amulets do include the word amulet in the actual name, for example: "amulet of ESP", "amulet versus poison" and "Amulet of Yendor".
const char *dn This buffer contains the object description, such as "crude arrow", "snow boots", or for magic items, adjectives such as "wooden", "jade", "shiny" for rings, "milky", "bubbly", "clear" for potions. For scrolls, this is a label like "DAIYEN FOOELS" or "GARVEN DEH" (or "stamped" or "unlabeled"). This obj_typename function will sometimes use these descriptions, but it will not prefix any adjectives. So it might return "crude arrow" or "scroll labeled GARVEN DEH", but it returns "ring", not "shiny ring".
const char *un This is a name set with the #name command when you use it to name types of objects. For example, if you have a "scroll called identify named cursed", then this is "identify".
int nn This acts as a flag to determine whether the player has identified this type of item, that is, whether the player knows the actual name instead of the description. Does the player yet know that crude arrows are orcish arrows, that certain conical hats are dunce caps, that in the current game scrolls labeled READ ME are stinking cloud?
101.  	if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp))
102.  		actualn = Japanese_item_name(otyp);

If you are a Samurai and a Japanese item name exists for the item (as determined by the Japanese_item_name function at #line2740), then the code replaces the actual name with the Japanese version.

103.  	switch(ocl->oc_class) {

After the declarations, the code switches on the class of item. Each case copies something appropriate into the buffer at buf. Some of these cases break to some final code at #line151, while others immediately return the contents of the buffer. The cases are:

case COIN_CLASS for coins $ #line104
case POTION_CLASS for potions ! #line107
case SCROLL_CLASS for scrolls ? #line110
case WAND_CLASS for wands / #line113
case SPBOOK_CLASS for spellbooks + #line116
case RING_CLASS for rings = #line119
case AMULET_CLASS for amulets " #line122
default for all other items #line132
104.  	case COIN_CLASS:
105.  		Strcpy(buf, "coin");
106.  		break;

The file objects.c defines only one type of coin, so case COIN_CLASS only runs for gold coins. The code copies the word "coin" into the buffer; it does not include the "gold" adjective. It then breaks to #line151.

107.  	case POTION_CLASS:
108.  		Strcpy(buf, "potion");
109.  		break;
110.  	case SCROLL_CLASS:
111.  		Strcpy(buf, "scroll");
112.  		break;
113.  	case WAND_CLASS:
114.  		Strcpy(buf, "wand");
115.  		break;
116.  	case SPBOOK_CLASS:
117.  		Strcpy(buf, "spellbook");
118.  		break;
119.  	case RING_CLASS:
120.  		Strcpy(buf, "ring");
121.  		break;

The cases for potions, scrolls, wands, spellbooks, and ring exactly identical to the case for coins, except that the word copied into the buffer is "potion", "scroll", "wand", "spellbook", "ring". The code breaks to #line151 so that it can later append type information to make strings like "potion of enlightenment", "wand called stop bugs".

122.  	case AMULET_CLASS:
123.  		if(nn)
124.  			Strcpy(buf,actualn);

In case AMULET_CLASS, if this type of amulet is known (flag nn is true), then the code copies the actual string such as "amulet of strangulation" or "amulet versus poison" into the buffer. Remember, unlike with the previous cases (ranging from coins to rings), the actual names of amulets include the word "amulet" where appropriate.

125.  		else
126.  			Strcpy(buf,"amulet");

If the amulet is unknown, the code just uses the string "amulet" without the descriptive prefix.

127.  		if(un)
128.  			Sprintf(eos(buf)," called %s",un);

If the amulet has a #name un, then code appends "called %s" where %s is the name, for example "amulet called unknown" or "amulet of strangulation called harmful".

129.  		if(dn)
130.  			Sprintf(eos(buf)," (%s)",dn);

If the amulet has a description dn, it is appended in parenthesees, as in "amulet called unknown (triangular)" or "amulet of ESP (concave)".

For both #names and descriptions, the code does nothing if the pointer is null. (At present, all of the amulets in objects.c do have descriptions, so the second check is strictly unnecessary.) The same four lines appending #names and descriptions appear many more times in this obj_typename function, and used to append #names and descriptions to all types of objects. (Some of those objects do lack descriptions.)

131.  		return(buf);

For amulets, the name is returned immediately; the code does not break to #line151.

132.  	default:

The default case handles all other types of objects, such as armor, tools, and gems. Gems and amulets must be handled specially, because unidentified amulets must be called "amulet", and most gems must be called "stone" or "gem" as appropriate. However, while amulets have their own separate case above, gems are handled with if statements in the default case.

133.  		if(nn) {
134.  			Strcpy(buf, actualn);
135.  			if (GemStone(otyp))
136.  				Strcat(buf, " stone");
137.  			if(un)
138.  				Sprintf(eos(buf), " called %s", un);
139.  			if(dn)
140.  				Sprintf(eos(buf), " (%s)", dn);

The default case opens with an if block for items identified by the player. For these items, the actual name is known to the player, so the code copies actualn into buf. Line 135 calls the GemStone macro of #line24 to test if line 136 should append the word "stone". The four lines from 137 to 140 append the #name and description, as lines 127 to 130 did for amulets.

141.  		} else {
142.  			Strcpy(buf, dn ? dn : actualn);

The default case has an interesting else block. For an unidentified object, if it has a description (such as "crude arrow") then the code uses the description, otherwise it uses the actual name. Thus obvious objects (ranging from the "dart" to "dwarvish mithril-coat", from the "tinning kit" to the "pancake" without a description use their actual name without requiring the player to identify them somehow.

Examples of descriptions include "lamp" (which might be a oil lamp or magic lamp), "conical hat" (which might be a cornuthaum or dunce cap), "riding boots" (which is a random type of boots), and many others.

143.  			if(ocl->oc_class == GEM_CLASS)
144.  				Strcat(buf, (ocl->oc_material == MINERAL) ?
145.  						" stone" : " gem");

The code appends the word "stone" or "gem" to all unidentified gems (belonging to GEM_CLASS). The effect here is that obvious minerals obtain the word "stone", yielding a "gray stone", while all other objects obtain the word "gem" (for example, "violet gem"), thus making it ambiguous whether the unidentified thing is a valuable stone or a worthless piece of glass.

146.  			if(un)
147.  				Sprintf(eos(buf), " called %s", un);

Interestingly, lines 146 and 147 append the #name un, but nothing tries to append the description dn. Thus, identifying an object (that is not a coin, potion, scroll, wand, spellbook, ring, or amulet) causes the actual name to completely mask the description for the purposes of the obj_typename function.

148.  		}
149.  		return(buf);
150.  	}

Line 149 closes the default case by returning buf immediately and not continuing to line 151.

151.  	/* here for ring/scroll/potion/wand */

The cases that break from the switch statement (instead of returning) cause the code starting at line 151 to run. This code runs for coins, potions, scrolls, wands, spellbooks, and rings only. By now, buf includes a lone word like "potion", regardless of what the player knows about this potion.

152.  	if(nn) {
153.  	    if (ocl->oc_unique)
154.  		Strcpy(buf, actualn); /* avoid spellbook of Book of the Dead */
155.  	    else
156.  		Sprintf(eos(buf), " of %s", actualn);
157.  	}

The if block on lines 152 to 157 intervene if the player has identified this type of item. For a unique item, the name is completely replaced with the actual name. (In all these classes, the Book of the Dead is the only unique item.) Otherwise, code appends the actual name in an "of" clause. This produces strings like "potion of restore ability", "spellbook of identify", in effect "type of actual name". Interestingly, for coins this produces the string "coin of gold piece".

158.  	if(un)
159.  		Sprintf(eos(buf), " called %s", un);
160.  	if(dn)
161.  		Sprintf(eos(buf), " (%s)", dn);
162.  	return(buf);
163.  }
164.  

Lines 158 to 161 then append the #name and description, if any, and line 162 finally returns the string.

simple_typename Edit

165.  /* less verbose result than obj_typename(); either the actual name
166.     or the description (but not both); user-assigned name is ignored */
167.  char *
168.  simple_typename(otyp)
169.  int otyp;
170.  {
171.      char *bufp, *pp, *save_uname = objects[otyp].oc_uname;
172.  
173.      objects[otyp].oc_uname = 0;		/* suppress any name given by user */
174.      bufp = obj_typename(otyp);
175.      objects[otyp].oc_uname = save_uname;
176.      if ((pp = strstri(bufp, " (")) != 0)
177.  	*pp = '\0';		/* strip the appended description */
178.      return bufp;
179.  }
180.  

The simple_typename function calls obj_typename and removes any "called" clause (from the #name) command and removes any appended description, so "wand called cancellation (balsa)" becomes "wand". Actually, it temporarily sets objects[otyp].oc_uname, pretending that the user never used #name to call that type of object.

There must be a simpler way of coding obj_typename and simple_typename than this! No one has any incentive to code it, but one could cause that "called" clauses and appended descriptions are appended when wanted, not stripped when unwanted.

obj_is_pname Edit

181.  boolean
182.  obj_is_pname(obj)
183.  register struct obj *obj;
184.  {
185.      return((boolean)(obj->dknown && obj->known && obj->onamelth &&
186.  		     /* Since there aren't any objects which are both
187.  		        artifacts and unique, the last check is redundant. */
188.  		     obj->oartifact && !objects[obj->otyp].oc_unique));
189.  }
190.  

In NetHack, an artifact is simply an object bearing a certain #name, for example that elven dagger named Sting or that luckstone named Heart of Ahriman. This gives rise to quirks such as the naming artifacts bug. Now there are situations in which the game refers to Ogresmasher as "Ogremasher", not "war hammer named Ogresmasher", because Ogresmasher does something extra that other war hammers do not do.

The obj_is_pname tests if NetHack can refer to an object by just its #name. This function should return TRUE for Ogresmasher, but FALSE for typical objects such as the red potion named cursed, long sword named Newtbane, or mace named Ogresmasher. It also returns FALSE if the player has not yet identified the object. This is why you find or receive a "war hammer named Ogresmasher"; it only becomes the "the blessed +0 rustproof Ogremasher" after you identify it. Unless you unfamiliar with artifacts in general, the fact that the war hammer named Ogresmasher already has a #name, unless you found it on a bones level, reveals plainly that the object is an artifact, as does being blasted (if you happen to discover it while polymorphed into an ogre), so in practice the obj_is_pname function only has a cosmetic effect in inventory screens and messages.

Now consider what happens if while exploring the dungeon, Random Number God favors you that you encounter the Eye of the Aethiopica sits on a floor a few squares away from you. (The Eye is a quest artifact, so this could only happen on a bones level.) In order for obj_is_pname to return TRUE, you must know the object's description in addition to its identity. Normally, you can know the description simply by moving onto the square with the amulet; thus it might be an "oval amulet" or a "triangular amulet" (or an "amulet of ESP" if you know that type). However, if you were blind, then obj->dknown will never be set and obj_is_pname will return FALSE; thus NetHack does not mention that it is the Eye. (Being blasted, then noticing the energy regeneration might give a hint!) Having seen the amulet, but having not identified it, obj_is_pname returns FALSE. You want to identify it (directly or indirectly, assuming you ignore the naming artifacts bug), thus causing obj_is_pname to return TRUE; imagine being tricked by someone who left an "amulet of strangulation named Eye of the Aethiopica" in a bones pile!

distant_name Edit

191.  /* Give the name of an object seen at a distance.  Unlike xname/doname,
192.   * we don't want to set dknown if it's not set already.  The kludge used is
193.   * to temporarily set Blind so that xname() skips the dknown setting.  This
194.   * assumes that we don't want to do this too often; if this function becomes
195.   * frequently used, it'd probably be better to pass a parameter to xname()
196.   * or doname() instead.
197.   */
198.  char *
199.  distant_name(obj, func)
200.  register struct obj *obj;
201.  char *FDECL((*func), (OBJ_P));
202.  {
203.  	char *str;
204.  
205.  	long save_Blinded = Blinded;
206.  	Blinded = 1;
207.  	str = (*func)(obj);
208.  	Blinded = save_Blinded;
209.  	return str;
210.  }
211.  

fruitname Edit

212.  /* convert player specified fruit name into corresponding fruit juice name
213.     ("slice of pizza" -> "pizza juice" rather than "slice of pizza juice") */
214.  char *
215.  fruitname(juice)
216.  boolean juice;	/* whether or not to append " juice" to the name */
217.  {
218.      char *buf = nextobuf();
219.      const char *fruit_nam = strstri(pl_fruit, " of ");
220.  
221.      if (fruit_nam)
222.  	fruit_nam += 4;		/* skip past " of " */
223.      else
224.  	fruit_nam = pl_fruit;	/* use it as is */
225.  
226.      Sprintf(buf, "%s%s", makesingular(fruit_nam), juice ? " juice" : "");
227.      return buf;
228.  }
229.  
230.  #endif /* OVLB */

xname Edit

231.  #ifdef OVL1
232.  
233.  char *
234.  xname(obj)
235.  register struct obj *obj;
236.  {
237.  	register char *buf;
238.  	register int typ = obj->otyp;
239.  	register struct objclass *ocl = &objects[typ];
240.  	register int nn = ocl->oc_name_known;
241.  	register const char *actualn = OBJ_NAME(*ocl);
242.  	register const char *dn = OBJ_DESCR(*ocl);
243.  	register const char *un = ocl->oc_uname;
244.  
245.  	buf = nextobuf() + PREFIX;	/* leave room for "17 -3 " */
246.  	if (Role_if(PM_SAMURAI) && Japanese_item_name(typ))
247.  		actualn = Japanese_item_name(typ);
248.  
249.  	buf[0] = '\0';
250.  	/*
251.  	 * clean up known when it's tied to oc_name_known, eg after AD_DRIN
252.  	 * This is only required for unique objects since the article
253.  	 * printed for the object is tied to the combination of the two
254.  	 * and printing the wrong article gives away information.
255.  	 */
256.  	if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0;
257.  	if (!Blind) obj->dknown = TRUE;
258.  	if (Role_if(PM_PRIEST)) obj->bknown = TRUE;
259.  	if (obj_is_pname(obj))
260.  	    goto nameit;
261.  	switch (obj->oclass) {
262.  	    case AMULET_CLASS:
263.  		if (!obj->dknown)
264.  			Strcpy(buf, "amulet");
265.  		else if (typ == AMULET_OF_YENDOR ||
266.  			 typ == FAKE_AMULET_OF_YENDOR)
267.  			/* each must be identified individually */
268.  			Strcpy(buf, obj->known ? actualn : dn);
269.  		else if (nn)
270.  			Strcpy(buf, actualn);
271.  		else if (un)
272.  			Sprintf(buf,"amulet called %s", un);
273.  		else
274.  			Sprintf(buf,"%s amulet", dn);
275.  		break;
276.  	    case WEAPON_CLASS:
277.  		if (is_poisonable(obj) && obj->opoisoned)
278.  			Strcpy(buf, "poisoned ");
279.  	    case VENOM_CLASS:
280.  	    case TOOL_CLASS:
281.  		if (typ == LENSES)
282.  			Strcpy(buf, "pair of ");
283.  
284.  		if (!obj->dknown)
285.  			Strcat(buf, dn ? dn : actualn);
286.  		else if (nn)
287.  			Strcat(buf, actualn);
288.  		else if (un) {
289.  			Strcat(buf, dn ? dn : actualn);
290.  			Strcat(buf, " called ");
291.  			Strcat(buf, un);
292.  		} else
293.  			Strcat(buf, dn ? dn : actualn);
294.  		/* If we use an() here we'd have to remember never to use */
295.  		/* it whenever calling doname() or xname(). */
296.  		if (typ == FIGURINE)
297.  		    Sprintf(eos(buf), " of a%s %s",
298.  			index(vowels,*(mons[obj->corpsenm].mname)) ? "n" : "",
299.  			mons[obj->corpsenm].mname);
300.  		break;
301.  	    case ARMOR_CLASS:
302.  		/* depends on order of the dragon scales objects */
303.  		if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) {
304.  			Sprintf(buf, "set of %s", actualn);
305.  			break;
306.  		}
307.  		if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of ");
308.  
309.  		if(obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD
310.  				&& !obj->dknown) {
311.  			Strcpy(buf, "shield");
312.  			break;
313.  		}
314.  		if(obj->otyp == SHIELD_OF_REFLECTION && !obj->dknown) {
315.  			Strcpy(buf, "smooth shield");
316.  			break;
317.  		}
318.  
319.  		if(nn)	Strcat(buf, actualn);
320.  		else if(un) {
321.  			if(is_boots(obj))
322.  				Strcat(buf,"boots");
323.  			else if(is_gloves(obj))
324.  				Strcat(buf,"gloves");
325.  			else if(is_cloak(obj))
326.  				Strcpy(buf,"cloak");
327.  			else if(is_helmet(obj))
328.  				Strcpy(buf,"helmet");
329.  			else if(is_shield(obj))
330.  				Strcpy(buf,"shield");
331.  			else
332.  				Strcpy(buf,"armor");
333.  			Strcat(buf, " called ");
334.  			Strcat(buf, un);
335.  		} else	Strcat(buf, dn);
336.  		break;
337.  	    case FOOD_CLASS:
338.  		if (typ == SLIME_MOLD) {
339.  			register struct fruit *f;
340.  
341.  			for(f=ffruit; f; f = f->nextf) {
342.  				if(f->fid == obj->spe) {
343.  					Strcpy(buf, f->fname);
344.  					break;
345.  				}
346.  			}
347.  			if (!f) impossible("Bad fruit #%d?", obj->spe);
348.  			break;
349.  		}
350.  
351.  		Strcpy(buf, actualn);
352.  		if (typ == TIN && obj->known) {
353.  		    if(obj->spe > 0)
354.  			Strcat(buf, " of spinach");
355.  		    else if (obj->corpsenm == NON_PM)
356.  		        Strcpy(buf, "empty tin");
357.  		    else if (vegetarian(&mons[obj->corpsenm]))
358.  			Sprintf(eos(buf), " of %s", mons[obj->corpsenm].mname);
359.  		    else
360.  			Sprintf(eos(buf), " of %s meat", mons[obj->corpsenm].mname);
361.  		}
362.  		break;
363.  	    case COIN_CLASS:
364.  	    case CHAIN_CLASS:
365.  		Strcpy(buf, actualn);
366.  		break;
367.  	    case ROCK_CLASS:
368.  		if (typ == STATUE)
369.  		    Sprintf(buf, "%s%s of %s%s",
370.  			(Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC)) ? "historic " : "" ,
371.  			actualn,
372.  			type_is_pname(&mons[obj->corpsenm]) ? "" :
373.  			  (mons[obj->corpsenm].geno & G_UNIQ) ? "the " :
374.  			    (index(vowels,*(mons[obj->corpsenm].mname)) ?
375.  								"an " : "a "),
376.  			mons[obj->corpsenm].mname);
377.  		else Strcpy(buf, actualn);
378.  		break;
379.  	    case BALL_CLASS:
380.  		Sprintf(buf, "%sheavy iron ball",
381.  			(obj->owt > ocl->oc_weight) ? "very " : "");
382.  		break;
383.  	    case POTION_CLASS:
384.  		if (obj->dknown && obj->odiluted)
385.  			Strcpy(buf, "diluted ");
386.  		if(nn || un || !obj->dknown) {
387.  			Strcat(buf, "potion");
388.  			if(!obj->dknown) break;
389.  			if(nn) {
390.  			    Strcat(buf, " of ");
391.  			    if (typ == POT_WATER &&
392.  				obj->bknown && (obj->blessed || obj->cursed)) {
393.  				Strcat(buf, obj->blessed ? "holy " : "unholy ");
394.  			    }
395.  			    Strcat(buf, actualn);
396.  			} else {
397.  				Strcat(buf, " called ");
398.  				Strcat(buf, un);
399.  			}
400.  		} else {
401.  			Strcat(buf, dn);
402.  			Strcat(buf, " potion");
403.  		}
404.  		break;
405.  	case SCROLL_CLASS:
406.  		Strcpy(buf, "scroll");
407.  		if(!obj->dknown) break;
408.  		if(nn) {
409.  			Strcat(buf, " of ");
410.  			Strcat(buf, actualn);
411.  		} else if(un) {
412.  			Strcat(buf, " called ");
413.  			Strcat(buf, un);
414.  		} else if (ocl->oc_magic) {
415.  			Strcat(buf, " labeled ");
416.  			Strcat(buf, dn);
417.  		} else {
418.  			Strcpy(buf, dn);
419.  			Strcat(buf, " scroll");
420.  		}
421.  		break;
422.  	case WAND_CLASS:
423.  		if(!obj->dknown)
424.  			Strcpy(buf, "wand");
425.  		else if(nn)
426.  			Sprintf(buf, "wand of %s", actualn);
427.  		else if(un)
428.  			Sprintf(buf, "wand called %s", un);
429.  		else
430.  			Sprintf(buf, "%s wand", dn);
431.  		break;
432.  	case SPBOOK_CLASS:
433.  		if (!obj->dknown) {
434.  			Strcpy(buf, "spellbook");
435.  		} else if (nn) {
436.  			if (typ != SPE_BOOK_OF_THE_DEAD)
437.  			    Strcpy(buf, "spellbook of ");
438.  			Strcat(buf, actualn);
439.  		} else if (un) {
440.  			Sprintf(buf, "spellbook called %s", un);
441.  		} else
442.  			Sprintf(buf, "%s spellbook", dn);
443.  		break;
444.  	case RING_CLASS:
445.  		if(!obj->dknown)
446.  			Strcpy(buf, "ring");
447.  		else if(nn)
448.  			Sprintf(buf, "ring of %s", actualn);
449.  		else if(un)
450.  			Sprintf(buf, "ring called %s", un);
451.  		else
452.  			Sprintf(buf, "%s ring", dn);
453.  		break;
454.  	case GEM_CLASS:
455.  	    {
456.  		const char *rock =
457.  			    (ocl->oc_material == MINERAL) ? "stone" : "gem";
458.  		if (!obj->dknown) {
459.  		    Strcpy(buf, rock);
460.  		} else if (!nn) {
461.  		    if (un) Sprintf(buf,"%s called %s", rock, un);
462.  		    else Sprintf(buf, "%s %s", dn, rock);
463.  		} else {
464.  		    Strcpy(buf, actualn);
465.  		    if (GemStone(typ)) Strcat(buf, " stone");
466.  		}
467.  		break;
468.  	    }
469.  	default:
470.  		Sprintf(buf,"glorkum %d %d %d", obj->oclass, typ, obj->spe);
471.  	}
472.  	if (obj->quan != 1L) Strcpy(buf, makeplural(buf));
473.  
474.  	if (obj->onamelth && obj->dknown) {
475.  		Strcat(buf, " named ");
476.  nameit:
477.  		Strcat(buf, ONAME(obj));
478.  	}
479.  
480.  	if (!strncmpi(buf, "the ", 4)) buf += 4;
481.  	return(buf);
482.  }
483.  

xname() returns the full name of object obj, considering whether hero has identified or named it, or whether hero is Samurai, etc.

mshot_xname Edit

484.  /* xname() output augmented for multishot missile feedback */
485.  char *
486.  mshot_xname(obj)
487.  struct obj *obj;
488.  {
489.      char tmpbuf[BUFSZ];
490.      char *onm = xname(obj);
491.  
492.      if (m_shot.n > 1 && m_shot.o == obj->otyp) {
493.  	/* copy xname's result so that we can reuse its return buffer */
494.  	Strcpy(tmpbuf, onm);
495.  	/* "the Nth arrow"; value will eventually be passed to an() or
496.  	   The(), both of which correctly handle this "the " prefix */
497.  	Sprintf(onm, "the %d%s %s", m_shot.i, ordin(m_shot.i), tmpbuf);
498.      }
499.  
500.      return onm;
501.  }
502.  
503.  #endif /* OVL1 */
504.  #ifdef OVL0
505.  
506.  /* used for naming "the unique_item" instead of "a unique_item" */
507.  boolean
508.  the_unique_obj(obj)
509.  register struct obj *obj;
510.  {
511.      if (!obj->dknown)
512.  	return FALSE;
513.      else if (obj->otyp == FAKE_AMULET_OF_YENDOR && !obj->known)
514.  	return TRUE;		/* lie */
515.      else
516.  	return (boolean)(objects[obj->otyp].oc_unique &&
517.  			 (obj->known || obj->otyp == AMULET_OF_YENDOR));
518.  }
519.  

add_erosion_words Edit

520.  static void
521.  add_erosion_words(obj,prefix)
522.  struct obj *obj;
523.  char *prefix;
524.  {
525.  	boolean iscrys = (obj->otyp == CRYSKNIFE);
526.  
527.  
528.  	if (!is_damageable(obj) && !iscrys) return;
529.  
530.  	/* The only cases where any of these bits do double duty are for
531.  	 * rotted food and diluted potions, which are all not is_damageable().
532.  	 */
533.  	if (obj->oeroded && !iscrys) {
534.  		switch (obj->oeroded) {
535.  			case 2:	Strcat(prefix, "very "); break;
536.  			case 3:	Strcat(prefix, "thoroughly "); break;
537.  		}			
538.  		Strcat(prefix, is_rustprone(obj) ? "rusty " : "burnt ");
539.  	}
540.  	if (obj->oeroded2 && !iscrys) {
541.  		switch (obj->oeroded2) {
542.  			case 2:	Strcat(prefix, "very "); break;
543.  			case 3:	Strcat(prefix, "thoroughly "); break;
544.  		}			
545.  		Strcat(prefix, is_corrodeable(obj) ? "corroded " :
546.  			"rotted ");
547.  	}
548.  	if (obj->rknown && obj->oerodeproof)
549.  		Strcat(prefix,
550.  		       iscrys ? "fixed " :
551.  		       is_rustprone(obj) ? "rustproof " :
552.  		       is_corrodeable(obj) ? "corrodeproof " :	/* "stainless"? */
553.  		       is_flammable(obj) ? "fireproof " : "");
554.  }
555.  

add_erosion_words() adds erosion-related words like "rusty thoroughly corroded " or "fireproof " to the prefix.

doname Edit

556.  char *
557.  doname(obj)
558.  register struct obj *obj;
559.  {
560.  	boolean ispoisoned = FALSE;
561.  	char prefix[PREFIX];
562.  	char tmpbuf[PREFIX+1];
563.  	/* when we have to add something at the start of prefix instead of the
564.  	 * end (Strcat is used on the end)
565.  	 */
566.  	register char *bp = xname(obj);
567.  
568.  	/* When using xname, we want "poisoned arrow", and when using
569.  	 * doname, we want "poisoned +0 arrow".  This kludge is about the only
570.  	 * way to do it, at least until someone overhauls xname() and doname(),
571.  	 * combining both into one function taking a parameter.
572.  	 */
573.  	/* must check opoisoned--someone can have a weirdly-named fruit */
574.  	if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) {
575.  		bp += 9;
576.  		ispoisoned = TRUE;
577.  	}
578.  
579.  	if(obj->quan != 1L)
580.  		Sprintf(prefix, "%ld ", obj->quan);
581.  	else if (obj_is_pname(obj) || the_unique_obj(obj)) {
582.  		if (!strncmpi(bp, "the ", 4))
583.  		    bp += 4;
584.  		Strcpy(prefix, "the ");
585.  	} else
586.  		Strcpy(prefix, "a ");
587.  
588.  #ifdef INVISIBLE_OBJECTS
589.  	if (obj->oinvis) Strcat(prefix,"invisible ");
590.  #endif
591.  
592.  	if (obj->bknown &&
593.  	    obj->oclass != COIN_CLASS &&
594.  	    (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
595.  		|| (!obj->cursed && !obj->blessed))) {
596.  	    /* allow 'blessed clear potion' if we don't know it's holy water;
597.  	     * always allow "uncursed potion of water"
598.  	     */
599.  	    if (obj->cursed)
600.  		Strcat(prefix, "cursed ");
601.  	    else if (obj->blessed)
602.  		Strcat(prefix, "blessed ");
603.  	    else if ((!obj->known || !objects[obj->otyp].oc_charged ||
604.  		      (obj->oclass == ARMOR_CLASS ||
605.  		       obj->oclass == RING_CLASS))
606.  		/* For most items with charges or +/-, if you know how many
607.  		 * charges are left or what the +/- is, then you must have
608.  		 * totally identified the item, so "uncursed" is unneccesary,
609.  		 * because an identified object not described as "blessed" or
610.  		 * "cursed" must be uncursed.
611.  		 *
612.  		 * If the charges or +/- is not known, "uncursed" must be
613.  		 * printed to avoid ambiguity between an item whose curse
614.  		 * status is unknown, and an item known to be uncursed.
615.  		 */
616.  #ifdef MAIL
617.  			&& obj->otyp != SCR_MAIL
618.  #endif
619.  			&& obj->otyp != FAKE_AMULET_OF_YENDOR
620.  			&& obj->otyp != AMULET_OF_YENDOR
621.  			&& !Role_if(PM_PRIEST))
622.  		Strcat(prefix, "uncursed ");
623.  	}
624.  
625.  	if (obj->greased) Strcat(prefix, "greased ");
626.  
627.  	switch(obj->oclass) {
628.  	case AMULET_CLASS:
629.  		if(obj->owornmask & W_AMUL)
630.  			Strcat(bp, " (being worn)");
631.  		break;
632.  	case WEAPON_CLASS:
633.  		if(ispoisoned)
634.  			Strcat(prefix, "poisoned ");
635.  plus:
636.  		add_erosion_words(obj, prefix);
637.  		if(obj->known) {
638.  			Strcat(prefix, sitoa(obj->spe));
639.  			Strcat(prefix, " ");
640.  		}
641.  		break;
642.  	case ARMOR_CLASS:
643.  		if(obj->owornmask & W_ARMOR)
644.  			Strcat(bp, (obj == uskin) ? " (embedded in your skin)" :
645.  				" (being worn)");
646.  		goto plus;
647.  	case TOOL_CLASS:
648.  		/* weptools already get this done when we go to the +n code */
649.  		if (!is_weptool(obj))
650.  		    add_erosion_words(obj, prefix);
651.  		if(obj->owornmask & (W_TOOL /* blindfold */
652.  #ifdef STEED
653.  				| W_SADDLE
654.  #endif
655.  				)) {
656.  			Strcat(bp, " (being worn)");
657.  			break;
658.  		}
659.  		if (obj->otyp == LEASH && obj->leashmon != 0) {
660.  			Strcat(bp, " (in use)");
661.  			break;
662.  		}
663.  		if (is_weptool(obj))
664.  			goto plus;
665.  		if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
666.  			if (!obj->spe)
667.  			    Strcpy(tmpbuf, "no");
668.  			else
669.  			    Sprintf(tmpbuf, "%d", obj->spe);
670.  			Sprintf(eos(bp), " (%s candle%s%s)",
671.  				tmpbuf, plur(obj->spe),
672.  				!obj->lamplit ? " attached" : ", lit");
673.  			break;
674.  		} else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
675.  			obj->otyp == BRASS_LANTERN || Is_candle(obj)) {
676.  			if (Is_candle(obj) &&
677.  			    obj->age < 20L * (long)objects[obj->otyp].oc_cost)
678.  				Strcat(prefix, "partly used ");
679.  			if(obj->lamplit)
680.  				Strcat(bp, " (lit)");
681.  			break;
682.  		}
683.  		if(objects[obj->otyp].oc_charged)
684.  		    goto charges;
685.  		break;
686.  	case WAND_CLASS:
687.  		add_erosion_words(obj, prefix);
688.  charges:
689.  		if(obj->known)
690.  		    Sprintf(eos(bp), " (%d:%d)", (int)obj->recharged, obj->spe);
691.  		break;
692.  	case POTION_CLASS:
693.  		if (obj->otyp == POT_OIL && obj->lamplit)
694.  		    Strcat(bp, " (lit)");
695.  		break;
696.  	case RING_CLASS:
697.  		add_erosion_words(obj, prefix);
698.  ring:
699.  		if(obj->owornmask & W_RINGR) Strcat(bp, " (on right ");
700.  		if(obj->owornmask & W_RINGL) Strcat(bp, " (on left ");
701.  		if(obj->owornmask & W_RING) {
702.  		    Strcat(bp, body_part(HAND));
703.  		    Strcat(bp, ")");
704.  		}
705.  		if(obj->known && objects[obj->otyp].oc_charged) {
706.  			Strcat(prefix, sitoa(obj->spe));
707.  			Strcat(prefix, " ");
708.  		}
709.  		break;
710.  	case FOOD_CLASS:
711.  		if (obj->oeaten)
712.  		    Strcat(prefix, "partly eaten ");
713.  		if (obj->otyp == CORPSE) {
714.  		    if (mons[obj->corpsenm].geno & G_UNIQ) {
715.  			Sprintf(prefix, "%s%s ",
716.  				(type_is_pname(&mons[obj->corpsenm]) ?
717.  					"" : "the "),
718.  				s_suffix(mons[obj->corpsenm].mname));
719.  			if (obj->oeaten) Strcat(prefix, "partly eaten ");
720.  		    } else {
721.  			Strcat(prefix, mons[obj->corpsenm].mname);
722.  			Strcat(prefix, " ");
723.  		    }
724.  		} else if (obj->otyp == EGG) {
725.  #if 0	/* corpses don't tell if they're stale either */
726.  		    if (obj->known && stale_egg(obj))
727.  			Strcat(prefix, "stale ");
728.  #endif
729.  		    if (obj->corpsenm >= LOW_PM &&
730.  			    (obj->known ||
731.  			    mvitals[obj->corpsenm].mvflags & MV_KNOWS_EGG)) {
732.  			Strcat(prefix, mons[obj->corpsenm].mname);
733.  			Strcat(prefix, " ");
734.  			if (obj->spe)
735.  			    Strcat(bp, " (laid by you)");
736.  		    }
737.  		}
738.  		if (obj->otyp == MEAT_RING) goto ring;
739.  		break;
740.  	case BALL_CLASS:
741.  	case CHAIN_CLASS:
742.  		add_erosion_words(obj, prefix);
743.  		if(obj->owornmask & W_BALL)
744.  			Strcat(bp, " (chained to you)");
745.  			break;
746.  	}
747.  
748.  	if((obj->owornmask & W_WEP) && !mrg_to_wielded) {
749.  		if (obj->quan != 1L) {
750.  			Strcat(bp, " (wielded)");
751.  		} else {
752.  			const char *hand_s = body_part(HAND);
753.  
754.  			if (bimanual(obj)) hand_s = makeplural(hand_s);
755.  			Sprintf(eos(bp), " (weapon in %s)", hand_s);
756.  		}
757.  	}
758.  	if(obj->owornmask & W_SWAPWEP) {
759.  		if (u.twoweap)
760.  			Sprintf(eos(bp), " (wielded in other %s)",
761.  				body_part(HAND));
762.  		else
763.  			Strcat(bp, " (alternate weapon; not wielded)");
764.  	}
765.  	if(obj->owornmask & W_QUIVER) Strcat(bp, " (in quiver)");
766.  	if(obj->unpaid) {
767.  		xchar ox, oy; 
768.  		long quotedprice = unpaid_cost(obj);
769.  		struct monst *shkp = (struct monst *)0;
770.  
771.  		if (Has_contents(obj) &&
772.  		    get_obj_location(obj, &ox, &oy, BURIED_TOO|CONTAINED_TOO) &&
773.  		    costly_spot(ox, oy) &&
774.  		    (shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE))))
775.  			quotedprice += contained_cost(obj, shkp, 0L, FALSE, TRUE);
776.  		Sprintf(eos(bp), " (unpaid, %ld %s)",
777.  			quotedprice, currency(quotedprice));
778.  	}
779.  	if (!strncmp(prefix, "a ", 2) &&
780.  			index(vowels, *(prefix+2) ? *(prefix+2) : *bp)
781.  			&& (*(prefix+2) || (strncmp(bp, "uranium", 7)
782.  				&& strncmp(bp, "unicorn", 7)
783.  				&& strncmp(bp, "eucalyptus", 10)))) {
784.  		Strcpy(tmpbuf, prefix);
785.  		Strcpy(prefix, "an ");
786.  		Strcpy(prefix+3, tmpbuf+2);
787.  	}
788.  	bp = strprepend(bp, prefix);
789.  	return(bp);
790.  }
791.  
792.  #endif /* OVL0 */

not_fully_identified Edit

793.  #ifdef OVLB
794.  
795.  /* used from invent.c */
796.  boolean
797.  not_fully_identified(otmp)
798.  register struct obj *otmp;
799.  {
800.  #ifdef GOLDOBJ
801.      /* gold doesn't have any interesting attributes [yet?] */
802.      if (otmp->oclass == COIN_CLASS) return FALSE;	/* always fully ID'd */
803.  #endif
804.      /* check fundamental ID hallmarks first */
805.      if (!otmp->known || !otmp->dknown ||
806.  #ifdef MAIL
807.  	    (!otmp->bknown && otmp->otyp != SCR_MAIL) ||
808.  #else
809.  	    !otmp->bknown ||
810.  #endif
811.  	    !objects[otmp->otyp].oc_name_known)	/* ?redundant? */
812.  	return TRUE;
813.      if (otmp->oartifact && undiscovered_artifact(otmp->oartifact))
814.  	return TRUE;
815.      /* otmp->rknown is the only item of interest if we reach here */
816.         /*
817.  	*  Note:  if a revision ever allows scrolls to become fireproof or
818.  	*  rings to become shockproof, this checking will need to be revised.
819.  	*  `rknown' ID only matters if xname() will provide the info about it.
820.  	*/
821.      if (otmp->rknown || (otmp->oclass != ARMOR_CLASS &&
822.  			 otmp->oclass != WEAPON_CLASS &&
823.  			 !is_weptool(otmp) &&		    /* (redunant) */
824.  			 otmp->oclass != BALL_CLASS))	    /* (useless) */
825.  	return FALSE;
826.      else	/* lack of `rknown' only matters for vulnerable objects */
827.  	return (boolean)(is_rustprone(otmp) ||
828.  			 is_corrodeable(otmp) ||
829.  			 is_flammable(otmp));
830.  }
831.  

corpse_xname Edit

832.  char *
833.  corpse_xname(otmp, ignore_oquan)
834.  struct obj *otmp;
835.  boolean ignore_oquan;	/* to force singular */
836.  {
837.  	char *nambuf = nextobuf();
838.  
839.  	Sprintf(nambuf, "%s corpse", mons[otmp->corpsenm].mname);
840.  
841.  	if (ignore_oquan || otmp->quan < 2)
842.  	    return nambuf;
843.  	else
844.  	    return makeplural(nambuf);
845.  }
846.  

cxname Edit

847.  /* xname, unless it's a corpse, then corpse_xname(obj, FALSE) */
848.  char *
849.  cxname(obj)
850.  struct obj *obj;
851.  {
852.  	if (obj->otyp == CORPSE)
853.  	    return corpse_xname(obj, FALSE);
854.  	return xname(obj);
855.  }
856.  

killer_xname Edit

857.  /* treat an object as fully ID'd when it might be used as reason for death */
858.  char *
859.  killer_xname(obj)
860.  struct obj *obj;
861.  {
862.      struct obj save_obj;
863.      unsigned save_ocknown;
864.      char *buf, *save_ocuname;
865.  
866.      /* remember original settings for core of the object;
867.         oname and oattached extensions don't matter here--since they
868.         aren't modified they don't need to be saved and restored */
869.      save_obj = *obj;
870.      /* killer name should be more specific than general xname; however, exact
871.         info like blessed/cursed and rustproof makes things be too verbose */
872.      obj->known = obj->dknown = 1;
873.      obj->bknown = obj->rknown = obj->greased = 0;
874.      /* if character is a priest[ess], bknown will get toggled back on */
875.      obj->blessed = obj->cursed = 0;
876.      /* "killed by poisoned <obj>" would be misleading when poison is
877.         not the cause of death and "poisoned by poisoned <obj>" would
878.         be redundant when it is, so suppress "poisoned" prefix */
879.      obj->opoisoned = 0;
880.      /* strip user-supplied name; artifacts keep theirs */
881.      if (!obj->oartifact) obj->onamelth = 0;
882.      /* temporarily identify the type of object */
883.      save_ocknown = objects[obj->otyp].oc_name_known;
884.      objects[obj->otyp].oc_name_known = 1;
885.      save_ocuname = objects[obj->otyp].oc_uname;
886.      objects[obj->otyp].oc_uname = 0;	/* avoid "foo called bar" */
887.  
888.      buf = xname(obj);
889.      if (obj->quan == 1L) buf = obj_is_pname(obj) ? the(buf) : an(buf);
890.  
891.      objects[obj->otyp].oc_name_known = save_ocknown;
892.      objects[obj->otyp].oc_uname = save_ocuname;
893.      *obj = save_obj;	/* restore object's core settings */
894.  
895.      return buf;
896.  }
897.  

singular Edit

898.  /*
899.   * Used if only one of a collection of objects is named (e.g. in eat.c).
900.   */
901.  const char *
902.  singular(otmp, func)
903.  register struct obj *otmp;
904.  char *FDECL((*func), (OBJ_P));
905.  {
906.  	long savequan;
907.  	char *nam;
908.  
909.  	/* Note: using xname for corpses will not give the monster type */
910.  	if (otmp->otyp == CORPSE && func == xname)
911.  		return corpse_xname(otmp, TRUE);
912.  
913.  	savequan = otmp->quan;
914.  	otmp->quan = 1L;
915.  	nam = (*func)(otmp);
916.  	otmp->quan = savequan;
917.  	return nam;
918.  }
919.  

an Edit

an() takes a string and returns it prefixed with either "an " or "a ".

920.  char *
921.  an(str)
922.  register const char *str;
923.  {
924.  	char *buf = nextobuf();
925.  
926.  	buf[0] = '\0';
927.  
928.  	if (strncmpi(str, "the ", 4) &&
929.  	    strcmp(str, "molten lava") &&
930.  	    strcmp(str, "iron bars") &&
931.  	    strcmp(str, "ice")) {
932.  		if (index(vowels, *str) &&
933.  		    strncmp(str, "one-", 4) &&
934.  		    strncmp(str, "useful", 6) &&
935.  		    strncmp(str, "unicorn", 7) &&
936.  		    strncmp(str, "uranium", 7) &&
937.  		    strncmp(str, "eucalyptus", 10))
938.  			Strcpy(buf, "an ");
939.  		else
940.  			Strcpy(buf, "a ");
941.  	}
942.  
943.  	Strcat(buf, str);
944.  	return buf;
945.  }
946.  

An Edit

947.  char *
948.  An(str)
949.  const char *str;
950.  {
951.  	register char *tmp = an(str);
952.  	*tmp = highc(*tmp);
953.  	return tmp;
954.  }
955.  

the Edit

956.  /*
957.   * Prepend "the" if necessary; assumes str is a subject derived from xname.
958.   * Use type_is_pname() for monster names, not the().  the() is idempotent.
959.   */
960.  char *
961.  the(str)
962.  const char *str;
963.  {
964.  	char *buf = nextobuf();
965.  	boolean insert_the = FALSE;
966.  
967.  	if (!strncmpi(str, "the ", 4)) {
968.  	    buf[0] = lowc(*str);
969.  	    Strcpy(&buf[1], str+1);
970.  	    return buf;
971.  	} else if (*str < 'A' || *str > 'Z') {
972.  	    /* not a proper name, needs an article */
973.  	    insert_the = TRUE;
974.  	} else {
975.  	    /* Probably a proper name, might not need an article */
976.  	    register char *tmp, *named, *called;
977.  	    int l;
978.  
979.  	    /* some objects have capitalized adjectives in their names */
980.  	    if(((tmp = rindex(str, ' ')) || (tmp = rindex(str, '-'))) &&
981.  	       (tmp[1] < 'A' || tmp[1] > 'Z'))
982.  		insert_the = TRUE;
983.  	    else if (tmp && index(str, ' ') < tmp) {	/* has spaces */
984.  		/* it needs an article if the name contains "of" */
985.  		tmp = strstri(str, " of ");
986.  		named = strstri(str, " named ");
987.  		called = strstri(str, " called ");
988.  		if (called && (!named || called < named)) named = called;
989.  
990.  		if (tmp && (!named || tmp < named))	/* found an "of" */
991.  		    insert_the = TRUE;
992.  		/* stupid special case: lacks "of" but needs "the" */
993.  		else if (!named && (l = strlen(str)) >= 31 &&
994.  		      !strcmp(&str[l - 31], "Platinum Yendorian Express Card"))
995.  		    insert_the = TRUE;
996.  	    }
997.  	}
998.  	if (insert_the)
999.  	    Strcpy(buf, "the ");
1000. 	else
1001. 	    buf[0] = '\0';
1002. 	Strcat(buf, str);
1003. 
1004. 	return buf;
1005. }
1006. 

The Edit

1007. char *
1008. The(str)
1009. const char *str;
1010. {
1011.     register char *tmp = the(str);
1012.     *tmp = highc(*tmp);
1013.     return tmp;
1014. }
1015. 

The() returns the string str prepended with "The ".

aobjname Edit

1016. /* returns "count cxname(otmp)" or just cxname(otmp) if count == 1 */
1017. char *
1018. aobjnam(otmp,verb)
1019. register struct obj *otmp;
1020. register const char *verb;
1021. {
1022. 	register char *bp = cxname(otmp);
1023. 	char prefix[PREFIX];
1024. 
1025. 	if(otmp->quan != 1L) {
1026. 		Sprintf(prefix, "%ld ", otmp->quan);
1027. 		bp = strprepend(bp, prefix);
1028. 	}
1029. 
1030. 	if(verb) {
1031. 	    Strcat(bp, " ");
1032. 	    Strcat(bp, otense(otmp, verb));
1033. 	}
1034. 	return(bp);
1035. }
1036. 

Tobjnam Edit

1037. /* like aobjnam, but prepend "The", not count, and use xname */
1038. char *
1039. Tobjnam(otmp, verb)
1040. register struct obj *otmp;
1041. register const char *verb;
1042. {
1043. 	char *bp = The(xname(otmp));
1044. 
1045. 	if(verb) {
1046. 	    Strcat(bp, " ");
1047. 	    Strcat(bp, otense(otmp, verb));
1048. 	}
1049. 	return(bp);
1050. }
1051. 

otense Edit

1052. /* return form of the verb (input plural) if xname(otmp) were the subject */
1053. char *
1054. otense(otmp, verb)
1055. register struct obj *otmp;
1056. register const char *verb;
1057. {
1058. 	char *buf;
1059. 
1060. 	/*
1061. 	 * verb is given in plural (without trailing s).  Return as input
1062. 	 * if the result of xname(otmp) would be plural.  Don't bother
1063. 	 * recomputing xname(otmp) at this time.
1064. 	 */
1065. 	if (!is_plural(otmp))
1066. 	    return vtense((char *)0, verb);
1067. 
1068. 	buf = nextobuf();
1069. 	Strcpy(buf, verb);
1070. 	return buf;
1071. }
1072. 


1073. /* various singular words that vtense would otherwise categorize as plural */
1074. static const char * const special_subjs[] = {
1075. 	"erinys",
1076. 	"manes",		/* this one is ambiguous */
1077. 	"Cyclops",
1078. 	"Hippocrates",
1079. 	"Pelias",
1080. 	"aklys",
1081. 	"amnesia",
1082. 	"paralysis",
1083. 	0
1084. };
1085. 

vtense Edit

1086. /* return form of the verb (input plural) for present tense 3rd person subj */
1087. char *
1088. vtense(subj, verb)
1089. register const char *subj;
1090. register const char *verb;
1091. {
1092. 	char *buf = nextobuf();
1093. 	int len, ltmp;
1094. 	const char *sp, *spot;
1095. 	const char * const *spec;
1096. 
1097. 	/*
1098. 	 * verb is given in plural (without trailing s).  Return as input
1099. 	 * if subj appears to be plural.  Add special cases as necessary.
1100. 	 * Many hard cases can already be handled by using otense() instead.
1101. 	 * If this gets much bigger, consider decomposing makeplural.
1102. 	 * Note: monster names are not expected here (except before corpse).
1103. 	 *
1104. 	 * special case: allow null sobj to get the singular 3rd person
1105. 	 * present tense form so we don't duplicate this code elsewhere.
1106. 	 */
1107. 	if (subj) {
1108. 	    if (!strncmpi(subj, "a ", 2) || !strncmpi(subj, "an ", 3))
1109. 		goto sing;
1110. 	    spot = (const char *)0;
1111. 	    for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) {
1112. 		if (!strncmp(sp, " of ", 4) ||
1113. 		    !strncmp(sp, " from ", 6) ||
1114. 		    !strncmp(sp, " called ", 8) ||
1115. 		    !strncmp(sp, " named ", 7) ||
1116. 		    !strncmp(sp, " labeled ", 9)) {
1117. 		    if (sp != subj) spot = sp - 1;
1118. 		    break;
1119. 		}
1120. 	    }
1121. 	    len = (int) strlen(subj);
1122. 	    if (!spot) spot = subj + len - 1;
1123. 
1124. 	    /*
1125. 	     * plural: anything that ends in 's', but not '*us' or '*ss'.
1126. 	     * Guess at a few other special cases that makeplural creates.
1127. 	     */
1128. 	    if ((*spot == 's' && spot != subj &&
1129. 			(*(spot-1) != 'u' && *(spot-1) != 's')) ||
1130. 		((spot - subj) >= 4 && !strncmp(spot-3, "eeth", 4)) ||
1131. 		((spot - subj) >= 3 && !strncmp(spot-3, "feet", 4)) ||
1132. 		((spot - subj) >= 2 && !strncmp(spot-1, "ia", 2)) ||
1133. 		((spot - subj) >= 2 && !strncmp(spot-1, "ae", 2))) {
1134. 		/* check for special cases to avoid false matches */
1135. 		len = (int)(spot - subj) + 1;
1136. 		for (spec = special_subjs; *spec; spec++) {
1137. 		    ltmp = strlen(*spec);
1138. 		    if (len == ltmp && !strncmpi(*spec, subj, len)) goto sing;
1139. 		    /* also check for <prefix><space><special_subj>
1140. 		       to catch things like "the invisible erinys" */
1141. 		    if (len > ltmp && *(spot - ltmp) == ' ' &&
1142. 			   !strncmpi(*spec, spot - ltmp + 1, ltmp)) goto sing;
1143. 		}
1144. 
1145. 		return strcpy(buf, verb);
1146. 	    }
1147. 	    /*
1148. 	     * 3rd person plural doesn't end in telltale 's';
1149. 	     * 2nd person singular behaves as if plural.
1150. 	     */
1151. 	    if (!strcmpi(subj, "they") || !strcmpi(subj, "you"))
1152. 		return strcpy(buf, verb);
1153. 	}
1154. 
1155.  sing:
1156. 	len = strlen(verb);
1157. 	spot = verb + len - 1;
1158. 
1159. 	if (!strcmp(verb, "are"))
1160. 	    Strcpy(buf, "is");
1161. 	else if (!strcmp(verb, "have"))
1162. 	    Strcpy(buf, "has");
1163. 	else if (index("zxs", *spot) ||
1164. 		 (len >= 2 && *spot=='h' && index("cs", *(spot-1))) ||
1165. 		 (len == 2 && *spot == 'o')) {
1166. 	    /* Ends in z, x, s, ch, sh; add an "es" */
1167. 	    Strcpy(buf, verb);
1168. 	    Strcat(buf, "es");
1169. 	} else if (*spot == 'y' && (!index(vowels, *(spot-1)))) {
1170. 	    /* like "y" case in makeplural */
1171. 	    Strcpy(buf, verb);
1172. 	    Strcpy(buf + len - 1, "ies");
1173. 	} else {
1174. 	    Strcpy(buf, verb);
1175. 	    Strcat(buf, "s");
1176. 	}
1177. 
1178. 	return buf;
1179. }
1180. 

Doname2 Edit

1181. /* capitalized variant of doname() */
1182. char *
1183. Doname2(obj)
1184. register struct obj *obj;
1185. {
1186. 	register char *s = doname(obj);
1187. 
1188. 	*s = highc(*s);
1189. 	return(s);
1190. }
1191. 

yname Edit

1192. /* returns "your xname(obj)" or "Foobar's xname(obj)" or "the xname(obj)" */
1193. char *
1194. yname(obj)
1195. struct obj *obj;
1196. {
1197. 	char *outbuf = nextobuf();
1198. 	char *s = shk_your(outbuf, obj);	/* assert( s == outbuf ); */
1199. 	int space_left = BUFSZ - strlen(s) - sizeof " ";
1200. 
1201. 	return strncat(strcat(s, " "), cxname(obj), space_left);
1202. }
1203. 

Yname2 Edit

1204. /* capitalized variant of yname() */
1205. char *
1206. Yname2(obj)
1207. struct obj *obj;
1208. {
1209. 	char *s = yname(obj);
1210. 
1211. 	*s = highc(*s);
1212. 	return s;
1213. }
1214. 

ysimple_name Edit

1215. /* returns "your simple_typename(obj->otyp)"
1216.  * or "Foobar's simple_typename(obj->otyp)"
1217.  * or "the simple_typename(obj-otyp)"
1218.  */
1219. char *
1220. ysimple_name(obj)
1221. struct obj *obj;
1222. {
1223. 	char *outbuf = nextobuf();
1224. 	char *s = shk_your(outbuf, obj);	/* assert( s == outbuf ); */
1225. 	int space_left = BUFSZ - strlen(s) - sizeof " ";
1226. 
1227. 	return strncat(strcat(s, " "), simple_typename(obj->otyp), space_left);
1228. }
1229. 
1230. /* capitalized variant of ysimple_name() */
1231. char *
1232. Ysimple_name2(obj)
1233. struct obj *obj;
1234. {
1235. 	char *s = ysimple_name(obj);
1236. 
1237. 	*s = highc(*s);
1238. 	return s;
1239. }
1240. 
1241. static const char *wrp[] = {
1242. 	"wand", "ring", "potion", "scroll", "gem", "amulet",
1243. 	"spellbook", "spell book",
1244. 	/* for non-specific wishes */
1245. 	"weapon", "armor", "armour", "tool", "food", "comestible",
1246. };
1247. static const char wrpsym[] = {
1248. 	WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, GEM_CLASS,
1249. 	AMULET_CLASS, SPBOOK_CLASS, SPBOOK_CLASS,
1250. 	WEAPON_CLASS, ARMOR_CLASS, ARMOR_CLASS, TOOL_CLASS, FOOD_CLASS,
1251. 	FOOD_CLASS
1252. };
1253. 
1254. #endif /* OVLB */
1255. #ifdef OVL0
1256. 
1257. /* Plural routine; chiefly used for user-defined fruits.  We have to try to
1258.  * account for everything reasonable the player has; something unreasonable
1259.  * can still break the code.  However, it's still a lot more accurate than
1260.  * "just add an s at the end", which Rogue uses...
1261.  *
1262.  * Also used for plural monster names ("Wiped out all homunculi.")
1263.  * and body parts.
1264.  *
1265.  * Also misused by muse.c to convert 1st person present verbs to 2nd person.
1266.  */

makeplural Edit

makeplural() takes one string parameter and returns a plural of that string. This should be able to handle every string given to it.

1267. char *
1268. makeplural(oldstr)
1269. const char *oldstr;
1270. {
1271. 	/* Note: cannot use strcmpi here -- it'd give MATZot, CAVEMeN,... */
1272. 	register char *spot;
1273. 	char *str = nextobuf();
1274. 	const char *excess = (char *)0;
1275. 	int len;
1276. 
1277. 	while (*oldstr==' ') oldstr++;
1278. 	if (!oldstr || !*oldstr) {
1279. 		impossible("plural of null?");
1280. 		Strcpy(str, "s");
1281. 		return str;
1282. 	}
1283. 	Strcpy(str, oldstr);
1284. 
1285. 	/*
1286. 	 * Skip changing "pair of" to "pairs of".  According to Webster, usual
1287. 	 * English usage is use pairs for humans, e.g. 3 pairs of dancers,
1288. 	 * and pair for objects and non-humans, e.g. 3 pair of boots.  We don't
1289. 	 * refer to pairs of humans in this game so just skip to the bottom.
1290. 	 */
1291. 	if (!strncmp(str, "pair of ", 8))
1292. 		goto bottom;
1293. 
1294. 	/* Search for common compounds, ex. lump of royal jelly */
1295. 	for(spot=str; *spot; spot++) {
1296. 		if (!strncmp(spot, " of ", 4)
1297. 				|| !strncmp(spot, " labeled ", 9)
1298. 				|| !strncmp(spot, " called ", 8)
1299. 				|| !strncmp(spot, " named ", 7)
1300. 				|| !strcmp(spot, " above") /* lurkers above */
1301. 				|| !strncmp(spot, " versus ", 8)
1302. 				|| !strncmp(spot, " from ", 6)
1303. 				|| !strncmp(spot, " in ", 4)
1304. 				|| !strncmp(spot, " on ", 4)
1305. 				|| !strncmp(spot, " a la ", 6)
1306. 				|| !strncmp(spot, " with", 5)	/* " with "? */
1307. 				|| !strncmp(spot, " de ", 4)
1308. 				|| !strncmp(spot, " d'", 3)
1309. 				|| !strncmp(spot, " du ", 4)) {
1310. 			excess = oldstr + (int) (spot - str);
1311. 			*spot = 0;
1312. 			break;
1313. 		}
1314. 	}
1315. 	spot--;
1316. 	while (*spot==' ') spot--; /* Strip blanks from end */
1317. 	*(spot+1) = 0;
1318. 	/* Now spot is the last character of the string */
1319. 
1320. 	len = strlen(str);
1321. 
1322. 	/* Single letters */
1323. 	if (len==1 || !letter(*spot)) {
1324. 		Strcpy(spot+1, "'s");
1325. 		goto bottom;
1326. 	}
1327. 
1328. 	/* Same singular and plural; mostly Japanese words except for "manes" */
1329. 	if ((len == 2 && !strcmp(str, "ya")) ||
1330. 	    (len >= 2 && !strcmp(spot-1, "ai")) || /* samurai, Uruk-hai */
1331. 	    (len >= 3 && !strcmp(spot-2, " ya")) ||
1332. 	    (len >= 4 &&
1333. 	     (!strcmp(spot-3, "fish") || !strcmp(spot-3, "tuna") ||
1334. 	      !strcmp(spot-3, "deer") || !strcmp(spot-3, "yaki"))) ||
1335. 	    (len >= 5 && (!strcmp(spot-4, "sheep") ||
1336. 			!strcmp(spot-4, "ninja") ||
1337. 			!strcmp(spot-4, "ronin") ||
1338. 			!strcmp(spot-4, "shito") ||
1339. 			!strcmp(spot-7, "shuriken") ||
1340. 			!strcmp(spot-4, "tengu") ||
1341. 			!strcmp(spot-4, "manes"))) ||
1342. 	    (len >= 6 && !strcmp(spot-5, "ki-rin")) ||
1343. 	    (len >= 7 && !strcmp(spot-6, "gunyoki")))
1344. 		goto bottom;
1345. 
1346. 	/* man/men ("Wiped out all cavemen.") */
1347. 	if (len >= 3 && !strcmp(spot-2, "man") &&
1348. 			(len<6 || strcmp(spot-5, "shaman")) &&
1349. 			(len<5 || strcmp(spot-4, "human"))) {
1350. 		*(spot-1) = 'e';
1351. 		goto bottom;
1352. 	}
1353. 
1354. 	/* tooth/teeth */
1355. 	if (len >= 5 && !strcmp(spot-4, "tooth")) {
1356. 		Strcpy(spot-3, "eeth");
1357. 		goto bottom;
1358. 	}
1359. 
1360. 	/* knife/knives, etc... */
1361. 	if (!strcmp(spot-1, "fe")) {
1362. 		Strcpy(spot-1, "ves");
1363. 		goto bottom;
1364. 	} else if (*spot == 'f') {
1365. 		if (index("lr", *(spot-1)) || index(vowels, *(spot-1))) {
1366. 			Strcpy(spot, "ves");
1367. 			goto bottom;
1368. 		} else if (len >= 5 && !strncmp(spot-4, "staf", 4)) {
1369. 			Strcpy(spot-1, "ves");
1370. 			goto bottom;
1371. 		}
1372. 	}
1373. 
1374. 	/* foot/feet (body part) */
1375. 	if (len >= 4 && !strcmp(spot-3, "foot")) {
1376. 		Strcpy(spot-2, "eet");
1377. 		goto bottom;
1378. 	}
1379. 
1380. 	/* ium/ia (mycelia, baluchitheria) */
1381. 	if (len >= 3 && !strcmp(spot-2, "ium")) {
1382. 		*(spot--) = (char)0;
1383. 		*spot = 'a';
1384. 		goto bottom;
1385. 	}
1386. 
1387. 	/* algae, larvae, hyphae (another fungus part) */
1388. 	if ((len >= 4 && !strcmp(spot-3, "alga")) ||
1389. 	    (len >= 5 &&
1390. 	     (!strcmp(spot-4, "hypha") || !strcmp(spot-4, "larva")))) {
1391. 		Strcpy(spot, "ae");
1392. 		goto bottom;
1393. 	}
1394. 
1395. 	/* fungus/fungi, homunculus/homunculi, but buses, lotuses, wumpuses */
1396. 	if (len > 3 && !strcmp(spot-1, "us") &&
1397. 	    (len < 5 || (strcmp(spot-4, "lotus") &&
1398. 			 (len < 6 || strcmp(spot-5, "wumpus"))))) {
1399. 		*(spot--) = (char)0;
1400. 		*spot = 'i';
1401. 		goto bottom;
1402. 	}
1403. 
1404. 	/* vortex/vortices */
1405. 	if (len >= 6 && !strcmp(spot-3, "rtex")) {
1406. 		Strcpy(spot-1, "ices");
1407. 		goto bottom;
1408. 	}
1409. 
1410. 	/* djinni/djinn (note: also efreeti/efreet) */
1411. 	if (len >= 6 && !strcmp(spot-5, "djinni")) {
1412. 		*spot = (char)0;
1413. 		goto bottom;
1414. 	}
1415. 
1416. 	/* mumak/mumakil */
1417. 	if (len >= 5 && !strcmp(spot-4, "mumak")) {
1418. 		Strcpy(spot+1, "il");
1419. 		goto bottom;
1420. 	}
1421. 
1422. 	/* sis/ses (nemesis) */
1423. 	if (len >= 3 && !strcmp(spot-2, "sis")) {
1424. 		*(spot-1) = 'e';
1425. 		goto bottom;
1426. 	}
1427. 
1428. 	/* erinys/erinyes */
1429. 	if (len >= 6 && !strcmp(spot-5, "erinys")) {
1430. 		Strcpy(spot, "es");
1431. 		goto bottom;
1432. 	}
1433. 
1434. 	/* mouse/mice,louse/lice (not a monster, but possible in food names) */
1435. 	if (len >= 5 && !strcmp(spot-3, "ouse") && index("MmLl", *(spot-4))) {
1436. 		Strcpy(spot-3, "ice");
1437. 		goto bottom;
1438. 	}
1439. 
1440. 	/* matzoh/matzot, possible food name */
1441. 	if (len >= 6 && (!strcmp(spot-5, "matzoh")
1442. 					|| !strcmp(spot-5, "matzah"))) {
1443. 		Strcpy(spot-1, "ot");
1444. 		goto bottom;
1445. 	}
1446. 	if (len >= 5 && (!strcmp(spot-4, "matzo")
1447. 					|| !strcmp(spot-5, "matza"))) {
1448. 		Strcpy(spot, "ot");
1449. 		goto bottom;
1450. 	}
1451. 
1452. 	/* child/children (for wise guys who give their food funny names) */
1453. 	if (len >= 5 && !strcmp(spot-4, "child")) {
1454. 		Strcpy(spot, "dren");
1455. 		goto bottom;
1456. 	}
1457. 
1458. 	/* note: -eau/-eaux (gateau, bordeau...) */
1459. 	/* note: ox/oxen, VAX/VAXen, goose/geese */
1460. 
1461. 	/* Ends in z, x, s, ch, sh; add an "es" */
1462. 	if (index("zxs", *spot)
1463. 			|| (len >= 2 && *spot=='h' && index("cs", *(spot-1)))
1464. 	/* Kludge to get "tomatoes" and "potatoes" right */
1465. 			|| (len >= 4 && !strcmp(spot-2, "ato"))) {
1466. 		Strcpy(spot+1, "es");
1467. 		goto bottom;
1468. 	}
1469. 
1470. 	/* Ends in y preceded by consonant (note: also "qu") change to "ies" */
1471. 	if (*spot == 'y' &&
1472. 	    (!index(vowels, *(spot-1)))) {
1473. 		Strcpy(spot, "ies");
1474. 		goto bottom;
1475. 	}
1476. 
1477. 	/* Default: append an 's' */
1478. 	Strcpy(spot+1, "s");
1479. 
1480. bottom:	if (excess) Strcpy(eos(str), excess);
1481. 	return str;
1482. }
1483. 
1484. #endif /* OVL0 */
1485. 

struct o_range Edit

1486. struct o_range {
1487. 	const char *name, oclass;
1488. 	int  f_o_range, l_o_range;
1489. };
1490. 
1491. #ifndef OVLB
1492. 
1493. STATIC_DCL const struct o_range o_ranges[];
1494. 
1495. #else /* OVLB */
1496. 
1497. /* wishable subranges of objects */
1498. STATIC_OVL NEARDATA const struct o_range o_ranges[] = {
1499. 	{ "bag",	TOOL_CLASS,   SACK,	      BAG_OF_TRICKS },
1500. 	{ "lamp",	TOOL_CLASS,   OIL_LAMP,	      MAGIC_LAMP },
1501. 	{ "candle",	TOOL_CLASS,   TALLOW_CANDLE,  WAX_CANDLE },
1502. 	{ "horn",	TOOL_CLASS,   TOOLED_HORN,    HORN_OF_PLENTY },
1503. 	{ "shield",	ARMOR_CLASS,  SMALL_SHIELD,   SHIELD_OF_REFLECTION },
1504. 	{ "helm",	ARMOR_CLASS,  ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY },
1505. 	{ "gloves",	ARMOR_CLASS,  LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
1506. 	{ "gauntlets",	ARMOR_CLASS,  LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
1507. 	{ "boots",	ARMOR_CLASS,  LOW_BOOTS,      LEVITATION_BOOTS },
1508. 	{ "shoes",	ARMOR_CLASS,  LOW_BOOTS,      IRON_SHOES },
1509. 	{ "cloak",	ARMOR_CLASS,  MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT },
1510. #ifdef TOURIST
1511. 	{ "shirt",	ARMOR_CLASS,  HAWAIIAN_SHIRT, T_SHIRT },
1512. #endif
1513. 	{ "dragon scales",
1514. 			ARMOR_CLASS,  GRAY_DRAGON_SCALES, YELLOW_DRAGON_SCALES },
1515. 	{ "dragon scale mail",
1516. 			ARMOR_CLASS,  GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL },
1517. 	{ "sword",	WEAPON_CLASS, SHORT_SWORD,    KATANA },
1518. #ifdef WIZARD
1519. 	{ "venom",	VENOM_CLASS,  BLINDING_VENOM, ACID_VENOM },
1520. #endif
1521. 	{ "gray stone",	GEM_CLASS,    LUCKSTONE,      FLINT },
1522. 	{ "grey stone",	GEM_CLASS,    LUCKSTONE,      FLINT },
1523. };
1524. 
1525. #define BSTRCMP(base,ptr,string) ((ptr) < base || strcmp((ptr),string))
1526. #define BSTRCMPI(base,ptr,string) ((ptr) < base || strcmpi((ptr),string))
1527. #define BSTRNCMP(base,ptr,string,num) ((ptr)<base || strncmp((ptr),string,num))
1528. #define BSTRNCMPI(base,ptr,string,num) ((ptr)<base||strncmpi((ptr),string,num))
1529. 

makesingular Edit

1530. /*
1531.  * Singularize a string the user typed in; this helps reduce the complexity
1532.  * of readobjnam, and is also used in pager.c to singularize the string
1533.  * for which help is sought.
1534.  */
1535. char *
1536. makesingular(oldstr)
1537. const char *oldstr;
1538. {
1539. 	register char *p, *bp;
1540. 	char *str = nextobuf();
1541. 
1542. 	if (!oldstr || !*oldstr) {
1543. 		impossible("singular of null?");
1544. 		str[0] = 0;
1545. 		return str;
1546. 	}
1547. 	Strcpy(str, oldstr);
1548. 	bp = str;
1549. 
1550. 	while (*bp == ' ') bp++;
1551. 	/* find "cloves of garlic", "worthless pieces of blue glass" */
1552. 	if ((p = strstri(bp, "s of ")) != 0) {
1553. 	    /* but don't singularize "gauntlets", "boots", "Eyes of the.." */
1554. 	    if (BSTRNCMPI(bp, p-3, "Eye", 3) &&
1555. 		BSTRNCMP(bp, p-4, "boot", 4) &&
1556. 		BSTRNCMP(bp, p-8, "gauntlet", 8))
1557. 		while ((*p = *(p+1)) != 0) p++;
1558. 	    return bp;
1559. 	}
1560. 
1561. 	/* remove -s or -es (boxes) or -ies (rubies) */
1562. 	p = eos(bp);
1563. 	if (p >= bp+1 && p[-1] == 's') {
1564. 		if (p >= bp+2 && p[-2] == 'e') {
1565. 			if (p >= bp+3 && p[-3] == 'i') {
1566. 				if(!BSTRCMP(bp, p-7, "cookies") ||
1567. 				   !BSTRCMP(bp, p-4, "pies"))
1568. 					goto mins;
1569. 				Strcpy(p-3, "y");
1570. 				return bp;
1571. 			}
1572. 
1573. 			/* note: cloves / knives from clove / knife */
1574. 			if(!BSTRCMP(bp, p-6, "knives")) {
1575. 				Strcpy(p-3, "fe");
1576. 				return bp;
1577. 			}
1578. 			if(!BSTRCMP(bp, p-6, "staves")) {
1579. 				Strcpy(p-3, "ff");
1580. 				return bp;
1581. 			}
1582. 			if (!BSTRCMPI(bp, p-6, "leaves")) {
1583. 				Strcpy(p-3, "f");
1584. 				return bp;
1585. 			}
1586. 			if (!BSTRCMP(bp, p-8, "vortices")) {
1587. 				Strcpy(p-4, "ex");
1588. 				return bp;
1589. 			}
1590. 
1591. 			/* note: nurses, axes but boxes */
1592. 			if (!BSTRCMP(bp, p-5, "boxes") ||
1593. 			    !BSTRCMP(bp, p-4, "ches")) {
1594. 				p[-2] = '\0';
1595. 				return bp;
1596. 			}
1597. 
1598. 			if (!BSTRCMP(bp, p-6, "gloves") ||
1599. 			    !BSTRCMP(bp, p-6, "lenses") ||
1600. 			    !BSTRCMP(bp, p-5, "shoes") ||
1601. 			    !BSTRCMP(bp, p-6, "scales"))
1602. 				return bp;
1603. 
1604. 		} else if (!BSTRCMP(bp, p-5, "boots") ||
1605. 			   !BSTRCMP(bp, p-9, "gauntlets") ||
1606. 			   !BSTRCMP(bp, p-6, "tricks") ||
1607. 			   !BSTRCMP(bp, p-9, "paralysis") ||
1608. 			   !BSTRCMP(bp, p-5, "glass") ||
1609. 			   !BSTRCMP(bp, p-4, "ness") ||
1610. 			   !BSTRCMP(bp, p-14, "shape changers") ||
1611. 			   !BSTRCMP(bp, p-15, "detect monsters") ||
1612. 			   !BSTRCMPI(bp, p-11, "Aesculapius") || /* staff */
1613. 			   !BSTRCMP(bp, p-10, "eucalyptus") ||
1614. #ifdef WIZARD
1615. 			   !BSTRCMP(bp, p-9, "iron bars") ||
1616. #endif
1617. 			   !BSTRCMP(bp, p-5, "aklys") ||
1618. 			   !BSTRCMP(bp, p-6, "fungus"))
1619. 				return bp;
1620. 	mins:
1621. 		p[-1] = '\0';
1622. 
1623. 	} else {
1624. 
1625. 		if(!BSTRCMP(bp, p-5, "teeth")) {
1626. 			Strcpy(p-5, "tooth");
1627. 			return bp;
1628. 		}
1629. 
1630. 		if (!BSTRCMP(bp, p-5, "fungi")) {
1631. 			Strcpy(p-5, "fungus");
1632. 			return bp;
1633. 		}
1634. 
1635. 		/* here we cannot find the plural suffix */
1636. 	}
1637. 	return bp;
1638. }
1639. 

wishymatch Edit

1640. /* compare user string against object name string using fuzzy matching */
1641. static boolean
1642. wishymatch(u_str, o_str, retry_inverted)
1643. const char *u_str;	/* from user, so might be variant spelling */
1644. const char *o_str;	/* from objects[], so is in canonical form */
1645. boolean retry_inverted;	/* optional extra "of" handling */
1646. {
1647. 	/* special case: wizards can wish for traps.  The object is "beartrap"
1648. 	 * and the trap is "bear trap", so to let wizards wish for both we
1649. 	 * must not fuzzymatch.
1650. 	 */
1651. #ifdef WIZARD
1652. 	if (wizard && !strcmp(o_str, "beartrap"))
1653. 	    return !strncmpi(o_str, u_str, 8);
1654. #endif
1655. 
1656. 	/* ignore spaces & hyphens and upper/lower case when comparing */
1657. 	if (fuzzymatch(u_str, o_str, " -", TRUE)) return TRUE;
1658. 
1659. 	if (retry_inverted) {
1660. 	    const char *u_of, *o_of;
1661. 	    char *p, buf[BUFSZ];
1662. 
1663. 	    /* when just one of the strings is in the form "foo of bar",
1664. 	       convert it into "bar foo" and perform another comparison */
1665. 	    u_of = strstri(u_str, " of ");
1666. 	    o_of = strstri(o_str, " of ");
1667. 	    if (u_of && !o_of) {
1668. 		Strcpy(buf, u_of + 4);
1669. 		p = eos(strcat(buf, " "));
1670. 		while (u_str < u_of) *p++ = *u_str++;
1671. 		*p = '\0';
1672. 		return fuzzymatch(buf, o_str, " -", TRUE);
1673. 	    } else if (o_of && !u_of) {
1674. 		Strcpy(buf, o_of + 4);
1675. 		p = eos(strcat(buf, " "));
1676. 		while (o_str < o_of) *p++ = *o_str++;
1677. 		*p = '\0';
1678. 		return fuzzymatch(u_str, buf, " -", TRUE);
1679. 	    }
1680. 	}
1681. 
1682. 	/* [note: if something like "elven speed boots" ever gets added, these
1683. 	   special cases should be changed to call wishymatch() recursively in
1684. 	   order to get the "of" inversion handling] */
1685. 	if (!strncmp(o_str, "dwarvish ", 9)) {
1686. 	    if (!strncmpi(u_str, "dwarven ", 8))
1687. 		return fuzzymatch(u_str + 8, o_str + 9, " -", TRUE);
1688. 	} else if (!strncmp(o_str, "elven ", 6)) {
1689. 	    if (!strncmpi(u_str, "elvish ", 7))
1690. 		return fuzzymatch(u_str + 7, o_str + 6, " -", TRUE);
1691. 	    else if (!strncmpi(u_str, "elfin ", 6))
1692. 		return fuzzymatch(u_str + 6, o_str + 6, " -", TRUE);
1693. 	} else if (!strcmp(o_str, "aluminum")) {
1694. 		/* this special case doesn't really fit anywhere else... */
1695. 		/* (note that " wand" will have been stripped off by now) */
1696. 	    if (!strcmpi(u_str, "aluminium"))
1697. 		return fuzzymatch(u_str + 9, o_str + 8, " -", TRUE);
1698. 	}
1699. 
1700. 	return FALSE;
1701. }
1702. 

struct alt_spellings Edit

1703. /* alternate spellings; if the difference is only the presence or
1704.    absence of spaces and/or hyphens (such as "pickaxe" vs "pick axe"
1705.    vs "pick-axe") then there is no need for inclusion in this list;
1706.    likewise for ``"of" inversions ("boots of speed" vs "speed boots") */
1707. struct alt_spellings {
1708. 	const char *sp;
1709. 	int ob;
1710. } spellings[] = {
1711. 	{ "pickax", PICK_AXE },
1712. 	{ "whip", BULLWHIP },
1713. 	{ "saber", SILVER_SABER },
1714. 	{ "silver sabre", SILVER_SABER },
1715. 	{ "smooth shield", SHIELD_OF_REFLECTION },
1716. 	{ "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL },
1717. 	{ "grey dragon scales", GRAY_DRAGON_SCALES },
1718. 	{ "enchant armour", SCR_ENCHANT_ARMOR },
1719. 	{ "destroy armour", SCR_DESTROY_ARMOR },
1720. 	{ "scroll of enchant armour", SCR_ENCHANT_ARMOR },
1721. 	{ "scroll of destroy armour", SCR_DESTROY_ARMOR },
1722. 	{ "leather armour", LEATHER_ARMOR },
1723. 	{ "studded leather armour", STUDDED_LEATHER_ARMOR },
1724. 	{ "iron ball", HEAVY_IRON_BALL },
1725. 	{ "lantern", BRASS_LANTERN },
1726. 	{ "mattock", DWARVISH_MATTOCK },
1727. 	{ "amulet of poison resistance", AMULET_VERSUS_POISON },
1728. 	{ "stone", ROCK },
1729. #ifdef TOURIST
1730. 	{ "camera", EXPENSIVE_CAMERA },
1731. 	{ "tee shirt", T_SHIRT },
1732. #endif
1733. 	{ "can", TIN },
1734. 	{ "can opener", TIN_OPENER },
1735. 	{ "kelp", KELP_FROND },
1736. 	{ "eucalyptus", EUCALYPTUS_LEAF },
1737. 	{ "grapple", GRAPPLING_HOOK },
1738. 	{ (const char *)0, 0 },
1739. };
1740. 

readobjnam Edit

1741. /*
1742.  * Return something wished for.  Specifying a null pointer for
1743.  * the user request string results in a random object.  Otherwise,
1744.  * if asking explicitly for "nothing" (or "nil") return no_wish;
1745.  * if not an object return &zeroobj; if an error (no matching object),
1746.  * return null.
1747.  * If from_user is false, we're reading from the wizkit, nothing was typed in.
1748.  */
1749. struct obj *
1750. readobjnam(bp, no_wish, from_user)
1751. register char *bp;
1752. struct obj *no_wish;
1753. boolean from_user;
1754. {
1755. 	register char *p;
1756. 	register int i;
1757. 	register struct obj *otmp;
1758. 	int cnt, spe, spesgn, typ, very, rechrg;
1759. 	int blessed, uncursed, iscursed, ispoisoned, isgreased;
1760. 	int eroded, eroded2, erodeproof;
1761. #ifdef INVISIBLE_OBJECTS
1762. 	int isinvisible;
1763. #endif
1764. 	int halfeaten, mntmp, contents;
1765. 	int islit, unlabeled, ishistoric, isdiluted;
1766. 	struct fruit *f;
1767. 	int ftype = current_fruit;
1768. 	char fruitbuf[BUFSZ];
1769. 	/* Fruits may not mess up the ability to wish for real objects (since
1770. 	 * you can leave a fruit in a bones file and it will be added to
1771. 	 * another person's game), so they must be checked for last, after
1772. 	 * stripping all the possible prefixes and seeing if there's a real
1773. 	 * name in there.  So we have to save the full original name.  However,
1774. 	 * it's still possible to do things like "uncursed burnt Alaska",
1775. 	 * or worse yet, "2 burned 5 course meals", so we need to loop to
1776. 	 * strip off the prefixes again, this time stripping only the ones
1777. 	 * possible on food.
1778. 	 * We could get even more detailed so as to allow food names with
1779. 	 * prefixes that _are_ possible on food, so you could wish for
1780. 	 * "2 3 alarm chilis".  Currently this isn't allowed; options.c
1781. 	 * automatically sticks 'candied' in front of such names.
1782. 	 */
1783. 
1784. 	char oclass;
1785. 	char *un, *dn, *actualn;
1786. 	const char *name=0;
1787. 
1788. 	cnt = spe = spesgn = typ = very = rechrg =
1789. 		blessed = uncursed = iscursed =
1790. #ifdef INVISIBLE_OBJECTS
1791. 		isinvisible =
1792. #endif
1793. 		ispoisoned = isgreased = eroded = eroded2 = erodeproof =
1794. 		halfeaten = islit = unlabeled = ishistoric = isdiluted = 0;
1795. 	mntmp = NON_PM;
1796. #define UNDEFINED 0
1797. #define EMPTY 1
1798. #define SPINACH 2
1799. 	contents = UNDEFINED;
1800. 	oclass = 0;
1801. 	actualn = dn = un = 0;
1802. 
1803. 	if (!bp) goto any;
1804. 	/* first, remove extra whitespace they may have typed */
1805. 	(void)mungspaces(bp);
1806. 	/* allow wishing for "nothing" to preserve wishless conduct...
1807. 	   [now requires "wand of nothing" if that's what was really wanted] */
1808. 	if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil") ||
1809. 	    !strcmpi(bp, "none")) return no_wish;
1810. 	/* save the [nearly] unmodified choice string */
1811. 	Strcpy(fruitbuf, bp);
1812. 
1813. 	for(;;) {
1814. 		register int l;
1815. 
1816. 		if (!bp || !*bp) goto any;
1817. 		if (!strncmpi(bp, "an ", l=3) ||
1818. 		    !strncmpi(bp, "a ", l=2)) {
1819. 			cnt = 1;
1820. 		} else if (!strncmpi(bp, "the ", l=4)) {
1821. 			;	/* just increment `bp' by `l' below */
1822. 		} else if (!cnt && digit(*bp) && strcmp(bp, "0")) {
1823. 			cnt = atoi(bp);
1824. 			while(digit(*bp)) bp++;
1825. 			while(*bp == ' ') bp++;
1826. 			l = 0;
1827. 		} else if (*bp == '+' || *bp == '-') {
1828. 			spesgn = (*bp++ == '+') ? 1 : -1;
1829. 			spe = atoi(bp);
1830. 			while(digit(*bp)) bp++;
1831. 			while(*bp == ' ') bp++;
1832. 			l = 0;
1833. 		} else if (!strncmpi(bp, "blessed ", l=8) ||
1834. 			   !strncmpi(bp, "holy ", l=5)) {
1835. 			blessed = 1;
1836. 		} else if (!strncmpi(bp, "cursed ", l=7) ||
1837. 			   !strncmpi(bp, "unholy ", l=7)) {
1838. 			iscursed = 1;
1839. 		} else if (!strncmpi(bp, "uncursed ", l=9)) {
1840. 			uncursed = 1;
1841. #ifdef INVISIBLE_OBJECTS
1842. 		} else if (!strncmpi(bp, "invisible ", l=10)) {
1843. 			isinvisible = 1;
1844. #endif
1845. 		} else if (!strncmpi(bp, "rustproof ", l=10) ||
1846. 			   !strncmpi(bp, "erodeproof ", l=11) ||
1847. 			   !strncmpi(bp, "corrodeproof ", l=13) ||
1848. 			   !strncmpi(bp, "fixed ", l=6) ||
1849. 			   !strncmpi(bp, "fireproof ", l=10) ||
1850. 			   !strncmpi(bp, "rotproof ", l=9)) {
1851. 			erodeproof = 1;
1852. 		} else if (!strncmpi(bp,"lit ", l=4) ||
1853. 			   !strncmpi(bp,"burning ", l=8)) {
1854. 			islit = 1;
1855. 		} else if (!strncmpi(bp,"unlit ", l=6) ||
1856. 			   !strncmpi(bp,"extinguished ", l=13)) {
1857. 			islit = 0;
1858. 		/* "unlabeled" and "blank" are synonymous */
1859. 		} else if (!strncmpi(bp,"unlabeled ", l=10) ||
1860. 			   !strncmpi(bp,"unlabelled ", l=11) ||
1861. 			   !strncmpi(bp,"blank ", l=6)) {
1862. 			unlabeled = 1;
1863. 		} else if(!strncmpi(bp, "poisoned ",l=9)
1864. #ifdef WIZARD
1865. 			  || (wizard && !strncmpi(bp, "trapped ",l=8))
1866. #endif
1867. 			  ) {
1868. 			ispoisoned=1;
1869. 		} else if(!strncmpi(bp, "greased ",l=8)) {
1870. 			isgreased=1;
1871. 		} else if (!strncmpi(bp, "very ", l=5)) {
1872. 			/* very rusted very heavy iron ball */
1873. 			very = 1;
1874. 		} else if (!strncmpi(bp, "thoroughly ", l=11)) {
1875. 			very = 2;
1876. 		} else if (!strncmpi(bp, "rusty ", l=6) ||
1877. 			   !strncmpi(bp, "rusted ", l=7) ||
1878. 			   !strncmpi(bp, "burnt ", l=6) ||
1879. 			   !strncmpi(bp, "burned ", l=7)) {
1880. 			eroded = 1 + very;
1881. 			very = 0;
1882. 		} else if (!strncmpi(bp, "corroded ", l=9) ||
1883. 			   !strncmpi(bp, "rotted ", l=7)) {
1884. 			eroded2 = 1 + very;
1885. 			very = 0;
1886. 		} else if (!strncmpi(bp, "partly eaten ", l=13)) {
1887. 			halfeaten = 1;
1888. 		} else if (!strncmpi(bp, "historic ", l=9)) {
1889. 			ishistoric = 1;
1890. 		} else if (!strncmpi(bp, "diluted ", l=8)) {
1891. 			isdiluted = 1;
1892. 		} else if(!strncmpi(bp, "empty ", l=6)) {
1893. 			contents = EMPTY;
1894. 		} else break;
1895. 		bp += l;
1896. 	}
1897. 	if(!cnt) cnt = 1;		/* %% what with "gems" etc. ? */
1898. 	if (strlen(bp) > 1) {
1899. 	    if ((p = rindex(bp, '(')) != 0) {
1900. 		if (p > bp && p[-1] == ' ') p[-1] = 0;
1901. 		else *p = 0;
1902. 		p++;
1903. 		if (!strcmpi(p, "lit)")) {
1904. 		    islit = 1;
1905. 		} else {
1906. 		    spe = atoi(p);
1907. 		    while (digit(*p)) p++;
1908. 		    if (*p == ':') {
1909. 			p++;
1910. 			rechrg = spe;
1911. 			spe = atoi(p);
1912. 			while (digit(*p)) p++;
1913. 		    }
1914. 		    if (*p != ')') {
1915. 			spe = rechrg = 0;
1916. 		    } else {
1917. 			spesgn = 1;
1918. 			p++;
1919. 			if (*p) Strcat(bp, p);
1920. 		    }
1921. 		}
1922. 	    }
1923. 	}
1924. /*
1925.    otmp->spe is type schar; so we don't want spe to be any bigger or smaller.
1926.    also, spe should always be positive  -- some cheaters may try to confuse
1927.    atoi()
1928. */
1929. 	if (spe < 0) {
1930. 		spesgn = -1;	/* cheaters get what they deserve */
1931. 		spe = abs(spe);
1932. 	}
1933. 	if (spe > SCHAR_LIM)
1934. 		spe = SCHAR_LIM;
1935. 	if (rechrg < 0 || rechrg > 7) rechrg = 7;	/* recharge_limit */
1936. 
1937. 	/* now we have the actual name, as delivered by xname, say
1938. 		green potions called whisky
1939. 		scrolls labeled "QWERTY"
1940. 		egg
1941. 		fortune cookies
1942. 		very heavy iron ball named hoei
1943. 		wand of wishing
1944. 		elven cloak
1945. 	*/
1946. 	if ((p = strstri(bp, " named ")) != 0) {
1947. 		*p = 0;
1948. 		name = p+7;
1949. 	}
1950. 	if ((p = strstri(bp, " called ")) != 0) {
1951. 		*p = 0;
1952. 		un = p+8;
1953. 		/* "helmet called telepathy" is not "helmet" (a specific type)
1954. 		 * "shield called reflection" is not "shield" (a general type)
1955. 		 */
1956. 		for(i = 0; i < SIZE(o_ranges); i++)
1957. 		    if(!strcmpi(bp, o_ranges[i].name)) {
1958. 			oclass = o_ranges[i].oclass;
1959. 			goto srch;
1960. 		    }
1961. 	}
1962. 	if ((p = strstri(bp, " labeled ")) != 0) {
1963. 		*p = 0;
1964. 		dn = p+9;
1965. 	} else if ((p = strstri(bp, " labelled ")) != 0) {
1966. 		*p = 0;
1967. 		dn = p+10;
1968. 	}
1969. 	if ((p = strstri(bp, " of spinach")) != 0) {
1970. 		*p = 0;
1971. 		contents = SPINACH;
1972. 	}
1973. 
1974. 	/*
1975. 	Skip over "pair of ", "pairs of", "set of" and "sets of".
1976. 
1977. 	Accept "3 pair of boots" as well as "3 pairs of boots". It is valid
1978. 	English either way.  See makeplural() for more on pair/pairs.
1979. 
1980. 	We should only double count if the object in question is not
1981. 	refered to as a "pair of".  E.g. We should double if the player
1982. 	types "pair of spears", but not if the player types "pair of
1983. 	lenses".  Luckily (?) all objects that are refered to as pairs
1984. 	-- boots, gloves, and lenses -- are also not mergable, so cnt is
1985. 	ignored anyway.
1986. 	*/
1987. 	if(!strncmpi(bp, "pair of ",8)) {
1988. 		bp += 8;
1989. 		cnt *= 2;
1990. 	} else if(cnt > 1 && !strncmpi(bp, "pairs of ",9)) {
1991. 		bp += 9;
1992. 		cnt *= 2;
1993. 	} else if (!strncmpi(bp, "set of ",7)) {
1994. 		bp += 7;
1995. 	} else if (!strncmpi(bp, "sets of ",8)) {
1996. 		bp += 8;
1997. 	}
1998. 
1999. 	/*
2000. 	 * Find corpse type using "of" (figurine of an orc, tin of orc meat)
2001. 	 * Don't check if it's a wand or spellbook.
2002. 	 * (avoid "wand/finger of death" confusion).
2003. 	 */
2004. 	if (!strstri(bp, "wand ")
2005. 	 && !strstri(bp, "spellbook ")
2006. 	 && !strstri(bp, "finger ")) {
2007. 	    if ((p = strstri(bp, " of ")) != 0
2008. 		&& (mntmp = name_to_mon(p+4)) >= LOW_PM)
2009. 		*p = 0;
2010. 	}
2011. 	/* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */
2012. 	if (strncmpi(bp, "samurai sword", 13)) /* not the "samurai" monster! */
2013. 	if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */
2014. 	if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */
2015. 	if (strncmpi(bp, "master key", 10)) /* not the "master" rank */
2016. 	if (strncmpi(bp, "magenta", 7)) /* not the "mage" rank */
2017. 	if (mntmp < LOW_PM && strlen(bp) > 2 &&
2018. 	    (mntmp = name_to_mon(bp)) >= LOW_PM) {
2019. 		int mntmptoo, mntmplen;	/* double check for rank title */
2020. 		char *obp = bp;
2021. 		mntmptoo = title_to_mon(bp, (int *)0, &mntmplen);
2022. 		bp += mntmp != mntmptoo ? (int)strlen(mons[mntmp].mname) : mntmplen;
2023. 		if (*bp == ' ') bp++;
2024. 		else if (!strncmpi(bp, "s ", 2)) bp += 2;
2025. 		else if (!strncmpi(bp, "es ", 3)) bp += 3;
2026. 		else if (!*bp && !actualn && !dn && !un && !oclass) {
2027. 		    /* no referent; they don't really mean a monster type */
2028. 		    bp = obp;
2029. 		    mntmp = NON_PM;
2030. 		}
2031. 	}
2032. 
2033. 	/* first change to singular if necessary */
2034. 	if (*bp) {
2035. 		char *sng = makesingular(bp);
2036. 		if (strcmp(bp, sng)) {
2037. 			if (cnt == 1) cnt = 2;
2038. 			Strcpy(bp, sng);
2039. 		}
2040. 	}
2041. 
2042. 	/* Alternate spellings (pick-ax, silver sabre, &c) */
2043.     {
2044. 	struct alt_spellings *as = spellings;
2045. 
2046. 	while (as->sp) {
2047. 		if (fuzzymatch(bp, as->sp, " -", TRUE)) {
2048. 			typ = as->ob;
2049. 			goto typfnd;
2050. 		}
2051. 		as++;
2052. 	}
2053. 	/* can't use spellings list for this one due to shuffling */
2054. 	if (!strncmpi(bp, "grey spell", 10))
2055. 		*(bp + 2) = 'a';
2056.     }
2057. 
2058. 	/* dragon scales - assumes order of dragons */
2059. 	if(!strcmpi(bp, "scales") &&
2060. 			mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON) {
2061. 		typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON;
2062. 		mntmp = NON_PM;	/* no monster */
2063. 		goto typfnd;
2064. 	}
2065. 
2066. 	p = eos(bp);
2067. 	if(!BSTRCMPI(bp, p-10, "holy water")) {
2068. 		typ = POT_WATER;
2069. 		if ((p-bp) >= 12 && *(p-12) == 'u')
2070. 			iscursed = 1; /* unholy water */
2071. 		else blessed = 1;
2072. 		goto typfnd;
2073. 	}
2074. 	if(unlabeled && !BSTRCMPI(bp, p-6, "scroll")) {
2075. 		typ = SCR_BLANK_PAPER;
2076. 		goto typfnd;
2077. 	}
2078. 	if(unlabeled && !BSTRCMPI(bp, p-9, "spellbook")) {
2079. 		typ = SPE_BLANK_PAPER;
2080. 		goto typfnd;
2081. 	}
2082. 	/*
2083. 	 * NOTE: Gold pieces are handled as objects nowadays, and therefore
2084. 	 * this section should probably be reconsidered as well as the entire
2085. 	 * gold/money concept.  Maybe we want to add other monetary units as
2086. 	 * well in the future. (TH)
2087. 	 */
2088. 	if(!BSTRCMPI(bp, p-10, "gold piece") || !BSTRCMPI(bp, p-7, "zorkmid") ||
2089. 	   !strcmpi(bp, "gold") || !strcmpi(bp, "money") ||
2090. 	   !strcmpi(bp, "coin") || *bp == GOLD_SYM) {
2091. 			if (cnt > 5000
2092. #ifdef WIZARD
2093. 					&& !wizard
2094. #endif
2095. 						) cnt=5000;
2096. 		if (cnt < 1) cnt=1;
2097. #ifndef GOLDOBJ
2098. 		if (from_user)
2099. 		    pline("%d gold piece%s.", cnt, plur(cnt));
2100. 		u.ugold += cnt;
2101. 		flags.botl=1;
2102. 		return (&zeroobj);
2103. #else
2104.                 otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
2105. 		otmp->quan = cnt;
2106.                 otmp->owt = weight(otmp);
2107. 		flags.botl=1;
2108. 		return (otmp);
2109. #endif
2110. 	}
2111. 	if (strlen(bp) == 1 &&
2112. 	   (i = def_char_to_objclass(*bp)) < MAXOCLASSES && i > ILLOBJ_CLASS
2113. #ifdef WIZARD
2114. 	    && (wizard || i != VENOM_CLASS)
2115. #else
2116. 	    && i != VENOM_CLASS
2117. #endif
2118. 	    ) {
2119. 		oclass = i;
2120. 		goto any;
2121. 	}
2122. 
2123. 	/* Search for class names: XXXXX potion, scroll of XXXXX.  Avoid */
2124. 	/* false hits on, e.g., rings for "ring mail". */
2125. 	if(strncmpi(bp, "enchant ", 8) &&
2126. 	   strncmpi(bp, "destroy ", 8) &&
2127. 	   strncmpi(bp, "food detection", 14) &&
2128. 	   strncmpi(bp, "ring mail", 9) &&
2129. 	   strncmpi(bp, "studded leather arm", 19) &&
2130. 	   strncmpi(bp, "leather arm", 11) &&
2131. 	   strncmpi(bp, "tooled horn", 11) &&
2132. 	   strncmpi(bp, "food ration", 11) &&
2133. 	   strncmpi(bp, "meat ring", 9)
2134. 	)
2135. 	for (i = 0; i < (int)(sizeof wrpsym); i++) {
2136. 		register int j = strlen(wrp[i]);
2137. 		if(!strncmpi(bp, wrp[i], j)){
2138. 			oclass = wrpsym[i];
2139. 			if(oclass != AMULET_CLASS) {
2140. 			    bp += j;
2141. 			    if(!strncmpi(bp, " of ", 4)) actualn = bp+4;
2142. 			    /* else if(*bp) ?? */
2143. 			} else
2144. 			    actualn = bp;
2145. 			goto srch;
2146. 		}
2147. 		if(!BSTRCMPI(bp, p-j, wrp[i])){
2148. 			oclass = wrpsym[i];
2149. 			p -= j;
2150. 			*p = 0;
2151. 			if(p > bp && p[-1] == ' ') p[-1] = 0;
2152. 			actualn = dn = bp;
2153. 			goto srch;
2154. 		}
2155. 	}
2156. 
2157. 	/* "grey stone" check must be before general "stone" */
2158. 	for (i = 0; i < SIZE(o_ranges); i++)
2159. 	    if(!strcmpi(bp, o_ranges[i].name)) {
2160. 		typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range);
2161. 		goto typfnd;
2162. 	    }
2163. 
2164. 	if (!BSTRCMPI(bp, p-6, " stone")) {
2165. 		p[-6] = 0;
2166. 		oclass = GEM_CLASS;
2167. 		dn = actualn = bp;
2168. 		goto srch;
2169. 	} else if (!strcmpi(bp, "looking glass")) {
2170. 		;	/* avoid false hit on "* glass" */
2171. 	} else if (!BSTRCMPI(bp, p-6, " glass") || !strcmpi(bp, "glass")) {
2172. 		register char *g = bp;
2173. 		if (strstri(g, "broken")) return (struct obj *)0;
2174. 		if (!strncmpi(g, "worthless ", 10)) g += 10;
2175. 		if (!strncmpi(g, "piece of ", 9)) g += 9;
2176. 		if (!strncmpi(g, "colored ", 8)) g += 8;
2177. 		else if (!strncmpi(g, "coloured ", 9)) g += 9;
2178. 		if (!strcmpi(g, "glass")) {	/* choose random color */
2179. 			/* 9 different kinds */
2180. 			typ = LAST_GEM + rnd(9);
2181. 			if (objects[typ].oc_class == GEM_CLASS) goto typfnd;
2182. 			else typ = 0;	/* somebody changed objects[]? punt */
2183. 		} else {		/* try to construct canonical form */
2184. 			char tbuf[BUFSZ];
2185. 			Strcpy(tbuf, "worthless piece of ");
2186. 			Strcat(tbuf, g);  /* assume it starts with the color */
2187. 			Strcpy(bp, tbuf);
2188. 		}
2189. 	}
2190. 
2191. 	actualn = bp;
2192. 	if (!dn) dn = actualn; /* ex. "skull cap" */
2193. srch:
2194. 	/* check real names of gems first */
2195. 	if(!oclass && actualn) {
2196. 	    for(i = bases[GEM_CLASS]; i <= LAST_GEM; i++) {
2197. 		register const char *zn;
2198. 
2199. 		if((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) {
2200. 		    typ = i;
2201. 		    goto typfnd;
2202. 		}
2203. 	    }
2204. 	}
2205. 	i = oclass ? bases[(int)oclass] : 1;
2206. 	while(i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass)){
2207. 		register const char *zn;
2208. 
2209. 		if (actualn && (zn = OBJ_NAME(objects[i])) != 0 &&
2210. 			    wishymatch(actualn, zn, TRUE)) {
2211. 			typ = i;
2212. 			goto typfnd;
2213. 		}
2214. 		if (dn && (zn = OBJ_DESCR(objects[i])) != 0 &&
2215. 			    wishymatch(dn, zn, FALSE)) {
2216. 			/* don't match extra descriptions (w/o real name) */
2217. 			if (!OBJ_NAME(objects[i])) return (struct obj *)0;
2218. 			typ = i;
2219. 			goto typfnd;
2220. 		}
2221. 		if (un && (zn = objects[i].oc_uname) != 0 &&
2222. 			    wishymatch(un, zn, FALSE)) {
2223. 			typ = i;
2224. 			goto typfnd;
2225. 		}
2226. 		i++;
2227. 	}
2228. 	if (actualn) {
2229. 		struct Jitem *j = Japanese_items;
2230. 		while(j->item) {
2231. 			if (actualn && !strcmpi(actualn, j->name)) {
2232. 				typ = j->item;
2233. 				goto typfnd;
2234. 			}
2235. 			j++;
2236. 		}
2237. 	}
2238. 	if (!strcmpi(bp, "spinach")) {
2239. 		contents = SPINACH;
2240. 		typ = TIN;
2241. 		goto typfnd;
2242. 	}
2243. 	/* Note: not strncmpi.  2 fruits, one capital, one not, are possible. */
2244. 	{
2245. 	    char *fp;
2246. 	    int l, cntf;
2247. 	    int blessedf, iscursedf, uncursedf, halfeatenf;
2248. 
2249. 	    blessedf = iscursedf = uncursedf = halfeatenf = 0;
2250. 	    cntf = 0;
2251. 
2252. 	    fp = fruitbuf;
2253. 	    for(;;) {
2254. 		if (!fp || !*fp) break;
2255. 		if (!strncmpi(fp, "an ", l=3) ||
2256. 		    !strncmpi(fp, "a ", l=2)) {
2257. 			cntf = 1;
2258. 		} else if (!cntf && digit(*fp)) {
2259. 			cntf = atoi(fp);
2260. 			while(digit(*fp)) fp++;
2261. 			while(*fp == ' ') fp++;
2262. 			l = 0;
2263. 		} else if (!strncmpi(fp, "blessed ", l=8)) {
2264. 			blessedf = 1;
2265. 		} else if (!strncmpi(fp, "cursed ", l=7)) {
2266. 			iscursedf = 1;
2267. 		} else if (!strncmpi(fp, "uncursed ", l=9)) {
2268. 			uncursedf = 1;
2269. 		} else if (!strncmpi(fp, "partly eaten ", l=13)) {
2270. 			halfeatenf = 1;
2271. 		} else break;
2272. 		fp += l;
2273. 	    }
2274. 
2275. 	    for(f=ffruit; f; f = f->nextf) {
2276. 		char *f1 = f->fname, *f2 = makeplural(f->fname);
2277. 
2278. 		if(!strncmp(fp, f1, strlen(f1)) ||
2279. 					!strncmp(fp, f2, strlen(f2))) {
2280. 			typ = SLIME_MOLD;
2281. 			blessed = blessedf;
2282. 			iscursed = iscursedf;
2283. 			uncursed = uncursedf;
2284. 			halfeaten = halfeatenf;
2285. 			cnt = cntf;
2286. 			ftype = f->fid;
2287. 			goto typfnd;
2288. 		}
2289. 	    }
2290. 	}
2291. 
2292. 	if(!oclass && actualn) {
2293. 	    short objtyp;
2294. 
2295. 	    /* Perhaps it's an artifact specified by name, not type */
2296. 	    name = artifact_name(actualn, &objtyp);
2297. 	    if(name) {
2298. 		typ = objtyp;
2299. 		goto typfnd;
2300. 	    }
2301. 	}
2302. #ifdef WIZARD
2303. 	/* Let wizards wish for traps --KAA */
2304. 	/* must come after objects check so wizards can still wish for
2305. 	 * trap objects like beartraps
2306. 	 */
2307. 	if (wizard && from_user) {
2308. 		int trap;
2309. 
2310. 		for (trap = NO_TRAP+1; trap < TRAPNUM; trap++) {
2311. 			const char *tname;
2312. 
2313. 			tname = defsyms[trap_to_defsym(trap)].explanation;
2314. 			if (!strncmpi(tname, bp, strlen(tname))) {
2315. 				/* avoid stupid mistakes */
2316. 				if((trap == TRAPDOOR || trap == HOLE)
2317. 				      && !Can_fall_thru(&u.uz)) trap = ROCKTRAP;
2318. 				(void) maketrap(u.ux, u.uy, trap);
2319. 				pline("%s.", An(tname));
2320. 				return(&zeroobj);
2321. 			}
2322. 		}
2323. 		/* or some other dungeon features -dlc */
2324. 		p = eos(bp);
2325. 		if(!BSTRCMP(bp, p-8, "fountain")) {
2326. 			levl[u.ux][u.uy].typ = FOUNTAIN;
2327. 			level.flags.nfountains++;
2328. 			if(!strncmpi(bp, "magic ", 6))
2329. 				levl[u.ux][u.uy].blessedftn = 1;
2330. 			pline("A %sfountain.",
2331. 			      levl[u.ux][u.uy].blessedftn ? "magic " : "");
2332. 			newsym(u.ux, u.uy);
2333. 			return(&zeroobj);
2334. 		}
2335. 		if(!BSTRCMP(bp, p-6, "throne")) {
2336. 			levl[u.ux][u.uy].typ = THRONE;
2337. 			pline("A throne.");
2338. 			newsym(u.ux, u.uy);
2339. 			return(&zeroobj);
2340. 		}
2341. # ifdef SINKS
2342. 		if(!BSTRCMP(bp, p-4, "sink")) {
2343. 			levl[u.ux][u.uy].typ = SINK;
2344. 			level.flags.nsinks++;
2345. 			pline("A sink.");
2346. 			newsym(u.ux, u.uy);
2347. 			return &zeroobj;
2348. 		}
2349. # endif
2350. 		if(!BSTRCMP(bp, p-4, "pool")) {
2351. 			levl[u.ux][u.uy].typ = POOL;
2352. 			del_engr_at(u.ux, u.uy);
2353. 			pline("A pool.");
2354. 			/* Must manually make kelp! */
2355. 			water_damage(level.objects[u.ux][u.uy], FALSE, TRUE);
2356. 			newsym(u.ux, u.uy);
2357. 			return &zeroobj;
2358. 		}
2359. 		if (!BSTRCMP(bp, p-4, "lava")) {  /* also matches "molten lava" */
2360. 			levl[u.ux][u.uy].typ = LAVAPOOL;
2361. 			del_engr_at(u.ux, u.uy);
2362. 			pline("A pool of molten lava.");
2363. 			if (!(Levitation || Flying)) (void) lava_effects();
2364. 			newsym(u.ux, u.uy);
2365. 			return &zeroobj;
2366. 		}
2367. 
2368. 		if(!BSTRCMP(bp, p-5, "altar")) {
2369. 		    aligntyp al;
2370. 
2371. 		    levl[u.ux][u.uy].typ = ALTAR;
2372. 		    if(!strncmpi(bp, "chaotic ", 8))
2373. 			al = A_CHAOTIC;
2374. 		    else if(!strncmpi(bp, "neutral ", 8))
2375. 			al = A_NEUTRAL;
2376. 		    else if(!strncmpi(bp, "lawful ", 7))
2377. 			al = A_LAWFUL;
2378. 		    else if(!strncmpi(bp, "unaligned ", 10))
2379. 			al = A_NONE;
2380. 		    else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
2381. 			al = (!rn2(6)) ? A_NONE : rn2((int)A_LAWFUL+2) - 1;
2382. 		    levl[u.ux][u.uy].altarmask = Align2amask( al );
2383. 		    pline("%s altar.", An(align_str(al)));
2384. 		    newsym(u.ux, u.uy);
2385. 		    return(&zeroobj);
2386. 		}
2387. 
2388. 		if(!BSTRCMP(bp, p-5, "grave") || !BSTRCMP(bp, p-9, "headstone")) {
2389. 		    make_grave(u.ux, u.uy, (char *) 0);
2390. 		    pline("A grave.");
2391. 		    newsym(u.ux, u.uy);
2392. 		    return(&zeroobj);
2393. 		}
2394. 
2395. 		if(!BSTRCMP(bp, p-4, "tree")) {
2396. 		    levl[u.ux][u.uy].typ = TREE;
2397. 		    pline("A tree.");
2398. 		    newsym(u.ux, u.uy);
2399. 		    block_point(u.ux, u.uy);
2400. 		    return &zeroobj;
2401. 		}
2402. 
2403. 		if(!BSTRCMP(bp, p-4, "bars")) {
2404. 		    levl[u.ux][u.uy].typ = IRONBARS;
2405. 		    pline("Iron bars.");
2406. 		    newsym(u.ux, u.uy);
2407. 		    return &zeroobj;
2408. 		}
2409. 	}
2410. #endif
2411. 	if(!oclass) return((struct obj *)0);
2412. any:
2413. 	if(!oclass) oclass = wrpsym[rn2((int)sizeof(wrpsym))];
2414. typfnd:
2415. 	if (typ) oclass = objects[typ].oc_class;
2416. 
2417. 	/* check for some objects that are not allowed */
2418. 	if (typ && objects[typ].oc_unique) {
2419. #ifdef WIZARD
2420. 	    if (wizard)
2421. 		;	/* allow unique objects */
2422. 	    else
2423. #endif
2424. 	    switch (typ) {
2425. 		case AMULET_OF_YENDOR:
2426. 		    typ = FAKE_AMULET_OF_YENDOR;
2427. 		    break;
2428. 		case CANDELABRUM_OF_INVOCATION:
2429. 		    typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE);
2430. 		    break;
2431. 		case BELL_OF_OPENING:
2432. 		    typ = BELL;
2433. 		    break;
2434. 		case SPE_BOOK_OF_THE_DEAD:
2435. 		    typ = SPE_BLANK_PAPER;
2436. 		    break;
2437. 	    }
2438. 	}
2439. 
2440. 	/* catch any other non-wishable objects */
2441. 	if (objects[typ].oc_nowish
2442. #ifdef WIZARD
2443. 	    && !wizard
2444. #endif
2445. 	    )
2446. 	    return((struct obj *)0);
2447. 
2448. 	/* convert magic lamps to regular lamps before lighting them or setting
2449. 	   the charges */
2450. 	if (typ == MAGIC_LAMP
2451. #ifdef WIZARD
2452. 				&& !wizard
2453. #endif
2454. 						)
2455. 	    typ = OIL_LAMP;
2456. 
2457. 	if(typ) {
2458. 		otmp = mksobj(typ, TRUE, FALSE);
2459. 	} else {
2460. 		otmp = mkobj(oclass, FALSE);
2461. 		if (otmp) typ = otmp->otyp;
2462. 	}
2463. 
2464. 	if (islit &&
2465. 		(typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN ||
2466. 		 Is_candle(otmp) || typ == POT_OIL)) {
2467. 	    place_object(otmp, u.ux, u.uy);  /* make it viable light source */
2468. 	    begin_burn(otmp, FALSE);
2469. 	    obj_extract_self(otmp);	 /* now release it for caller's use */
2470. 	}
2471. 
2472. 	if(cnt > 0 && objects[typ].oc_merge && oclass != SPBOOK_CLASS &&
2473. 		(cnt < rnd(6) ||
2474. #ifdef WIZARD
2475. 		wizard ||
2476. #endif
2477. 		 (cnt <= 7 && Is_candle(otmp)) ||
2478. 		 (cnt <= 20 &&
2479. 		  ((oclass == WEAPON_CLASS && is_ammo(otmp))
2480. 				|| typ == ROCK || is_missile(otmp)))))
2481. 			otmp->quan = (long) cnt;
2482. 
2483. #ifdef WIZARD
2484. 	if (oclass == VENOM_CLASS) otmp->spe = 1;
2485. #endif
2486. 
2487. 	if (spesgn == 0) spe = otmp->spe;
2488. #ifdef WIZARD
2489. 	else if (wizard) /* no alteration to spe */ ;
2490. #endif
2491. 	else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS ||
2492. 		 is_weptool(otmp) ||
2493. 			(oclass==RING_CLASS && objects[typ].oc_charged)) {
2494. 		if(spe > rnd(5) && spe > otmp->spe) spe = 0;
2495. 		if(spe > 2 && Luck < 0) spesgn = -1;
2496. 	} else {
2497. 		if (oclass == WAND_CLASS) {
2498. 			if (spe > 1 && spesgn == -1) spe = 1;
2499. 		} else {
2500. 			if (spe > 0 && spesgn == -1) spe = 0;
2501. 		}
2502. 		if (spe > otmp->spe) spe = otmp->spe;
2503. 	}
2504. 
2505. 	if (spesgn == -1) spe = -spe;
2506. 
2507. 	/* set otmp->spe.  This may, or may not, use spe... */
2508. 	switch (typ) {
2509. 		case TIN: if (contents==EMPTY) {
2510. 				otmp->corpsenm = NON_PM;
2511. 				otmp->spe = 0;
2512. 			} else if (contents==SPINACH) {
2513. 				otmp->corpsenm = NON_PM;
2514. 				otmp->spe = 1;
2515. 			}
2516. 			break;
2517. 		case SLIME_MOLD: otmp->spe = ftype;
2518. 			/* Fall through */
2519. 		case SKELETON_KEY: case CHEST: case LARGE_BOX:
2520. 		case HEAVY_IRON_BALL: case IRON_CHAIN: case STATUE:
2521. 			/* otmp->cobj already done in mksobj() */
2522. 				break;
2523. #ifdef MAIL
2524. 		case SCR_MAIL: otmp->spe = 1; break;
2525. #endif
2526. 		case WAN_WISHING:
2527. #ifdef WIZARD
2528. 			if (!wizard) {
2529. #endif
2530. 				otmp->spe = (rn2(10) ? -1 : 0);
2531. 				break;
2532. #ifdef WIZARD
2533. 			}
2534. 			/* fall through, if wizard */
2535. #endif
2536. 		default: otmp->spe = spe;
2537. 	}
2538. 
2539. 	/* set otmp->corpsenm or dragon scale [mail] */
2540. 	if (mntmp >= LOW_PM) {
2541. 		if (mntmp == PM_LONG_WORM_TAIL) mntmp = PM_LONG_WORM;
2542. 
2543. 		switch (typ) {
2544. 		case TIN:
2545. 			otmp->spe = 0; /* No spinach */
2546. 			if (dead_species(mntmp, FALSE)) {
2547. 			    otmp->corpsenm = NON_PM;	/* it's empty */
2548. 			} else if (!(mons[mntmp].geno & G_UNIQ) &&
2549. 				   !(mvitals[mntmp].mvflags & G_NOCORPSE) &&
2550. 				   mons[mntmp].cnutrit != 0) {
2551. 			    otmp->corpsenm = mntmp;
2552. 			}
2553. 			break;
2554. 		case CORPSE:
2555. 			if (!(mons[mntmp].geno & G_UNIQ) &&
2556. 				   !(mvitals[mntmp].mvflags & G_NOCORPSE)) {
2557. 			    /* beware of random troll or lizard corpse,
2558. 			       or of ordinary one being forced to such */
2559. 			    if (otmp->timed) obj_stop_timers(otmp);
2560. 			    if (mons[mntmp].msound == MS_GUARDIAN)
2561. 			    	otmp->corpsenm = genus(mntmp,1);
2562. 			    else
2563. 				otmp->corpsenm = mntmp;
2564. 			    start_corpse_timeout(otmp);
2565. 			}
2566. 			break;
2567. 		case FIGURINE:
2568. 			if (!(mons[mntmp].geno & G_UNIQ)
2569. 			    && !is_human(&mons[mntmp])
2570. #ifdef MAIL
2571. 			    && mntmp != PM_MAIL_DAEMON
2572. #endif
2573. 							)
2574. 				otmp->corpsenm = mntmp;
2575. 			break;
2576. 		case EGG:
2577. 			mntmp = can_be_hatched(mntmp);
2578. 			if (mntmp != NON_PM) {
2579. 			    otmp->corpsenm = mntmp;
2580. 			    if (!dead_species(mntmp, TRUE))
2581. 				attach_egg_hatch_timeout(otmp);
2582. 			    else
2583. 				kill_egg(otmp);
2584. 			}
2585. 			break;
2586. 		case STATUE: otmp->corpsenm = mntmp;
2587. 			if (Has_contents(otmp) && verysmall(&mons[mntmp]))
2588. 			    delete_contents(otmp);	/* no spellbook */
2589. 			otmp->spe = ishistoric ? STATUE_HISTORIC : 0;
2590. 			break;
2591. 		case SCALE_MAIL:
2592. 			/* Dragon mail - depends on the order of objects */
2593. 			/*		 & dragons.			 */
2594. 			if (mntmp >= PM_GRAY_DRAGON &&
2595. 						mntmp <= PM_YELLOW_DRAGON)
2596. 			    otmp->otyp = GRAY_DRAGON_SCALE_MAIL +
2597. 						    mntmp - PM_GRAY_DRAGON;
2598. 			break;
2599. 		}
2600. 	}
2601. 
2602. 	/* set blessed/cursed -- setting the fields directly is safe
2603. 	 * since weight() is called below and addinv() will take care
2604. 	 * of luck */
2605. 	if (iscursed) {
2606. 		curse(otmp);
2607. 	} else if (uncursed) {
2608. 		otmp->blessed = 0;
2609. 		otmp->cursed = (Luck < 0
2610. #ifdef WIZARD
2611. 					 && !wizard
2612. #endif
2613. 							);
2614. 	} else if (blessed) {
2615. 		otmp->blessed = (Luck >= 0
2616. #ifdef WIZARD
2617. 					 || wizard
2618. #endif
2619. 							);
2620. 		otmp->cursed = (Luck < 0
2621. #ifdef WIZARD
2622. 					 && !wizard
2623. #endif
2624. 							);
2625. 	} else if (spesgn < 0) {
2626. 		curse(otmp);
2627. 	}
2628. 
2629. #ifdef INVISIBLE_OBJECTS
2630. 	if (isinvisible) otmp->oinvis = 1;
2631. #endif
2632. 
2633. 	/* set eroded */
2634. 	if (is_damageable(otmp) || otmp->otyp == CRYSKNIFE) {
2635. 	    if (eroded && (is_flammable(otmp) || is_rustprone(otmp)))
2636. 		    otmp->oeroded = eroded;
2637. 	    if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp)))
2638. 		    otmp->oeroded2 = eroded2;
2639. 
2640. 	    /* set erodeproof */
2641. 	    if (erodeproof && !eroded && !eroded2)
2642. 		    otmp->oerodeproof = (Luck >= 0
2643. #ifdef WIZARD
2644. 					     || wizard
2645. #endif
2646. 					);
2647. 	}
2648. 
2649. 	/* set otmp->recharged */
2650. 	if (oclass == WAND_CLASS) {
2651. 	    /* prevent wishing abuse */
2652. 	    if (otmp->otyp == WAN_WISHING
2653. #ifdef WIZARD
2654. 		    && !wizard
2655. #endif
2656. 		) rechrg = 1;
2657. 	    otmp->recharged = (unsigned)rechrg;
2658. 	}
2659. 
2660. 	/* set poisoned */
2661. 	if (ispoisoned) {
2662. 	    if (is_poisonable(otmp))
2663. 		otmp->opoisoned = (Luck >= 0);
2664. 	    else if (Is_box(otmp) || typ == TIN)
2665. 		otmp->otrapped = 1;
2666. 	    else if (oclass == FOOD_CLASS)
2667. 		/* try to taint by making it as old as possible */
2668. 		otmp->age = 1L;
2669. 	}
2670. 
2671. 	if (isgreased) otmp->greased = 1;
2672. 
2673. 	if (isdiluted && otmp->oclass == POTION_CLASS &&
2674. 			otmp->otyp != POT_WATER)
2675. 		otmp->odiluted = 1;
2676. 
2677. 	if (name) {
2678. 		const char *aname;
2679. 		short objtyp;
2680. 
2681. 		/* an artifact name might need capitalization fixing */
2682. 		aname = artifact_name(name, &objtyp);
2683. 		if (aname && objtyp == otmp->otyp) name = aname;
2684. 
2685. 		otmp = oname(otmp, name);
2686. 		if (otmp->oartifact) {
2687. 			otmp->quan = 1L;
2688. 			u.uconduct.wisharti++;	/* KMH, conduct */
2689. 		}
2690. 	}
2691. 
2692. 	/* more wishing abuse: don't allow wishing for certain artifacts */
2693. 	/* and make them pay; charge them for the wish anyway! */
2694. 	if ((is_quest_artifact(otmp) ||
2695. 	     (otmp->oartifact && rn2(nartifact_exist()) > 1))
2696. #ifdef WIZARD
2697. 	    && !wizard
2698. #endif
2699. 	    ) {
2700. 	    artifact_exists(otmp, ONAME(otmp), FALSE);
2701. 	    obfree(otmp, (struct obj *) 0);
2702. 	    otmp = &zeroobj;
2703. 	    pline("For a moment, you feel %s in your %s, but it disappears!",
2704. 		  something,
2705. 		  makeplural(body_part(HAND)));
2706. 	}
2707. 
2708. 	if (halfeaten && otmp->oclass == FOOD_CLASS) {
2709. 		if (otmp->otyp == CORPSE)
2710. 			otmp->oeaten = mons[otmp->corpsenm].cnutrit;
2711. 		else otmp->oeaten = objects[otmp->otyp].oc_nutrition;
2712. 		/* (do this adjustment before setting up object's weight) */
2713. 		consume_oeaten(otmp, 1);
2714. 	}
2715. 	otmp->owt = weight(otmp);
2716. 	if (very && otmp->otyp == HEAVY_IRON_BALL) otmp->owt += 160;
2717. 
2718. 	return(otmp);
2719. }
2720. 
2721. int
2722. rnd_class(first,last)
2723. int first,last;
2724. {
2725. 	int i, x, sum=0;
2726. 
2727. 	if (first == last)
2728. 	    return (first);
2729. 	for(i=first; i<=last; i++)
2730. 		sum += objects[i].oc_prob;
2731. 	if (!sum) /* all zero */
2732. 		return first + rn2(last-first+1);
2733. 	x = rnd(sum);
2734. 	for(i=first; i<=last; i++)
2735. 		if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0)
2736. 			return i;
2737. 	return 0;
2738. }
2739. 

Japanese_item_name Edit

2740. STATIC_OVL const char *
2741. Japanese_item_name(i)
2742. int i;
2743. {
2744. 	struct Jitem *j = Japanese_items;
2745. 
2746. 	while(j->item) {
2747. 		if (i == j->item)
2748. 			return j->name;
2749. 		j++;
2750. 	}
2751. 	return (const char *)0;
2752. }
2753. 

cloak_simple_name Edit

2754. const char *
2755. cloak_simple_name(cloak)
2756. struct obj *cloak;
2757. {
2758.     if (cloak) {
2759. 	switch (cloak->otyp) {
2760. 	case ROBE:
2761. 	    return "robe";
2762. 	case MUMMY_WRAPPING:
2763. 	    return "wrapping";
2764. 	case ALCHEMY_SMOCK:
2765. 	    return (objects[cloak->otyp].oc_name_known &&
2766. 			cloak->dknown) ? "smock" : "apron";
2767. 	default:
2768. 	    break;
2769. 	}
2770.     }
2771.     return "cloak";
2772. }
2773. 

mimic_obj_name Edit

2774. const char *
2775. mimic_obj_name(mtmp)
2776. struct monst *mtmp;
2777. {
2778. 	if (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance != STRANGE_OBJECT) {
2779. 		int idx = objects[mtmp->mappearance].oc_descr_idx;
2780. 		if (mtmp->mappearance == GOLD_PIECE) return "gold";
2781. 		return obj_descr[idx].oc_name;
2782. 	}
2783. 	return "whatcha-may-callit";
2784. }
2785. #endif /* OVLB */
2786. 
2787. /*objnam.c*/

Around Wikia's network

Random Wiki