1 /* source/desc.c: handle object descriptions, mostly string handling code
2 
3    Copyright (c) 1989-94 James E. Wilson, Robert A. Koeneke
4 
5    This software may be copied and distributed for educational, research, and
6    not for profit purposes provided that this copyright and statement are
7    included in all such copies. */
8 
9 #ifdef __TURBOC__
10 #include	<stdio.h>
11 #include	<stdlib.h>
12 #endif /* __TURBOC__ */
13 
14 #include "config.h"
15 #include "constant.h"
16 #include "types.h"
17 #include "externs.h"
18 
19 #ifdef USG
20 #ifndef ATARIST_MWC
21 #include <string.h>
22 #endif
23 #else
24 #include <strings.h>
25 #endif
26 
27 #if defined(LINT_ARGS)
28 static void unsample(struct inven_type *);
29 #else
30 static void unsample();
31 #endif
32 
33 #ifdef ATARIST_TC
34 /* Include this to get prototypes for standard library functions.  */
35 #include <stdlib.h>
36 #endif
37 
38 char titles[MAX_TITLES][10];
39 
40 /* Object descriptor routines					*/
41 
is_a_vowel(ch)42 int is_a_vowel(ch)
43 char ch;
44 {
45   switch(ch)
46     {
47     case 'a': case 'e': case 'i': case 'o': case 'u':
48     case 'A': case 'E': case 'I': case 'O': case 'U':
49       return(TRUE);
50     default:
51       return(FALSE);
52     }
53 }
54 
55 /* Initialize all Potions, wands, staves, scrolls, etc.	*/
magic_init()56 void magic_init()
57 {
58   register int h, i, j, k;
59   register char *tmp;
60   vtype string;
61 
62   set_seed(randes_seed);
63 
64   /* The first 3 entries for colors are fixed, (slime & apple juice, water) */
65   for (i = 3; i < MAX_COLORS; i++)
66     {
67       j = randint(MAX_COLORS - 3) + 2;
68       tmp = colors[i];
69       colors[i] = colors[j];
70       colors[j] = tmp;
71     }
72   for (i = 0; i < MAX_WOODS; i++)
73     {
74       j = randint(MAX_WOODS) - 1;
75       tmp = woods[i];
76       woods[i] = woods[j];
77       woods[j] = tmp;
78     }
79   for (i = 0; i < MAX_METALS; i++)
80     {
81       j = randint(MAX_METALS) - 1;
82       tmp = metals[i];
83       metals[i] = metals[j];
84       metals[j] = tmp;
85     }
86   for (i = 0; i < MAX_ROCKS; i++)
87     {
88       j = randint(MAX_ROCKS) - 1;
89       tmp = rocks[i];
90       rocks[i] = rocks[j];
91       rocks[j] = tmp;
92     }
93   for (i = 0; i < MAX_AMULETS; i++)
94     {
95       j = randint(MAX_AMULETS) - 1;
96       tmp = amulets[i];
97       amulets[i] = amulets[j];
98       amulets[j] = tmp;
99     }
100   for (i = 0; i < MAX_MUSH; i++)
101     {
102       j = randint(MAX_MUSH) - 1;
103       tmp = mushrooms[i];
104       mushrooms[i] = mushrooms[j];
105       mushrooms[j] = tmp;
106     }
107   for (h = 0; h < MAX_TITLES; h++)
108     {
109       string[0] = '\0';
110       k = randint(2) + 1;
111       for (i = 0; i < k; i++)
112 	{
113 	  for (j = randint(2); j > 0; j--)
114 	    (void) strcat(string, syllables[randint(MAX_SYLLABLES) - 1]);
115 	  if (i < k-1)
116 	    (void) strcat(string, " ");
117 	}
118       if (string[8] == ' ')
119 	string[8] = '\0';
120       else
121 	string[9] = '\0';
122       (void) strcpy(titles[h], string);
123     }
124   reset_seed();
125 }
126 
object_offset(t_ptr)127 int16 object_offset(t_ptr)
128 inven_type *t_ptr;
129 {
130   switch (t_ptr->tval)
131     {
132     case TV_AMULET:	return(0);
133     case TV_RING:	return(1);
134     case TV_STAFF:	return(2);
135     case TV_WAND:	return(3);
136     case TV_SCROLL1:
137     case TV_SCROLL2:	return(4);
138     case TV_POTION1:
139     case TV_POTION2:	return(5);
140     case TV_FOOD:
141       if ((t_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1)) < MAX_MUSH)
142 	return(6);
143       return(-1);
144     default:  return(-1);
145     }
146 }
147 
148 /* Remove "Secret" symbol for identity of object			*/
known1(i_ptr)149 void known1(i_ptr)
150 inven_type *i_ptr;
151 {
152   int16 offset;
153   int8u indexx;
154 
155   if ((offset = object_offset(i_ptr)) < 0)
156     return;
157   offset <<= 6;
158   indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1);
159   object_ident[offset + indexx] |= OD_KNOWN1;
160   /* clear the tried flag, since it is now known */
161   object_ident[offset + indexx] &= ~OD_TRIED;
162 }
163 
known1_p(i_ptr)164 int known1_p(i_ptr)
165 inven_type *i_ptr;
166 {
167   int16 offset;
168   int8u indexx;
169 
170   /* Items which don't have a 'color' are always known1, so that they can
171      be carried in order in the inventory.  */
172   if ((offset = object_offset(i_ptr)) < 0)
173     return OD_KNOWN1;
174   if (store_bought_p(i_ptr))
175     return OD_KNOWN1;
176   offset <<= 6;
177   indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1);
178   return(object_ident[offset + indexx] & OD_KNOWN1);
179 }
180 
181 /* Remove "Secret" symbol for identity of plusses			*/
known2(i_ptr)182 void known2(i_ptr)
183 inven_type *i_ptr;
184 {
185   unsample(i_ptr);
186   i_ptr->ident |= ID_KNOWN2;
187 }
188 
known2_p(i_ptr)189 int known2_p(i_ptr)
190 inven_type *i_ptr;
191 {
192   return (i_ptr->ident & ID_KNOWN2);
193 }
194 
clear_known2(i_ptr)195 void clear_known2(i_ptr)
196 inven_type *i_ptr;
197 {
198   i_ptr->ident &= ~ID_KNOWN2;
199 }
200 
clear_empty(i_ptr)201 void clear_empty(i_ptr)
202 inven_type *i_ptr;
203 {
204   i_ptr->ident &= ~ID_EMPTY;
205 }
206 
store_bought(i_ptr)207 void store_bought(i_ptr)
208 inven_type *i_ptr;
209 {
210   i_ptr->ident |= ID_STOREBOUGHT;
211   known2(i_ptr);
212 }
213 
store_bought_p(i_ptr)214 int store_bought_p(i_ptr)
215 inven_type *i_ptr;
216 {
217   return (i_ptr->ident & ID_STOREBOUGHT);
218 }
219 
220 /*	Remove an automatically generated inscription.	-CJS- */
unsample(i_ptr)221 static void unsample(i_ptr)
222 inven_type *i_ptr;
223 {
224   int16 offset;
225   int8u indexx;
226 
227   /* used to clear ID_DAMD flag, but I think it should remain set */
228   i_ptr->ident &= ~(ID_MAGIK|ID_EMPTY);
229   if ((offset = object_offset(i_ptr)) < 0)
230     return;
231   offset <<= 6;
232   indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1);
233   object_ident[offset + indexx] &= ~OD_TRIED;
234 }
235 
236 /* unquote() is no longer needed */
237 
238 /* Somethings been sampled -CJS- */
sample(i_ptr)239 void sample (i_ptr)
240 inven_type *i_ptr;
241 {
242   int16 offset;
243   int8u indexx;
244 
245   if ((offset = object_offset(i_ptr)) < 0)
246     return;
247   offset <<= 6;
248   indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1);
249   object_ident[offset + indexx] |= OD_TRIED;
250 }
251 
252 /* Somethings been identified					*/
253 /* extra complexity by CJS so that it can merge store/dungeon objects
254    when appropriate */
identify(item)255 void identify(item)
256 int *item;
257 {
258   register int i, x1, x2;
259   int j;
260   register inven_type *i_ptr, *t_ptr;
261 #ifdef ATARIST_MWC
262   int32u holder;
263 #endif
264 
265   i_ptr = &inventory[*item];
266 
267 #ifdef ATARIST_MWC
268   if (i_ptr->flags & (holder = TR_CURSED))
269 #else
270   if (i_ptr->flags & TR_CURSED)
271 #endif
272     add_inscribe(i_ptr, ID_DAMD);
273 
274   if (!known1_p(i_ptr))
275     {
276       known1(i_ptr);
277       x1 = i_ptr->tval;
278       x2 = i_ptr->subval;
279       if (x2 < ITEM_SINGLE_STACK_MIN || x2 >= ITEM_GROUP_MIN)
280 	/* no merging possible */
281 	;
282       else
283 	for (i = 0; i < inven_ctr; i++)
284 	  {
285 	    t_ptr = &inventory[i];
286 	    if (t_ptr->tval == x1 && t_ptr->subval == x2 && i != *item
287 		&& ((int)t_ptr->number + (int)i_ptr->number < 256))
288 	      {
289 		/* make *item the smaller number */
290 		if (*item > i)
291 		  {
292 		    j = *item; *item = i; i = j;
293 		  }
294 	  msg_print ("You combine similar objects from the shop and dungeon.");
295 
296 		inventory[*item].number += inventory[i].number;
297 		inven_ctr--;
298 		for (j = i; j < inven_ctr; j++)
299 		  inventory[j] = inventory[j+1];
300 		invcopy(&inventory[j], OBJ_NOTHING);
301 	      }
302 	  }
303     }
304 }
305 
306 /* If an object has lost magical properties,
307  * remove the appropriate portion of the name.	       -CJS-
308  */
unmagic_name(i_ptr)309 void unmagic_name(i_ptr)
310 inven_type *i_ptr;
311 {
312   i_ptr->name2 = SN_NULL;
313 }
314 
315 /* defines for p1_use, determine how the p1 field is printed */
316 #define IGNORED  0
317 #define CHARGES  1
318 #define PLUSSES  2
319 #define LIGHT    3
320 #define FLAGS    4
321 #define Z_PLUSSES 5
322 
323 /* Returns a description of item for inventory			*/
324 /* pref indicates that there should be an article added (prefix) */
325 /* note that since out_val can easily exceed 80 characters, objdes must
326    always be called with a bigvtype as the first paramter */
objdes(out_val,i_ptr,pref)327 void objdes(out_val, i_ptr, pref)
328 char *out_val;
329 register inven_type *i_ptr;
330 int pref;
331 {
332   /* base name, modifier string*/
333   register char *basenm, *modstr;
334   bigvtype tmp_val;
335   vtype tmp_str, damstr;
336   int indexx, p1_use, modify, append_name, tmp;
337 
338   indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1);
339   basenm = object_list[i_ptr->index].name;
340   modstr = CNIL;
341   damstr[0] = '\0';
342   p1_use = IGNORED;
343   modify = (known1_p(i_ptr) ? FALSE : TRUE);
344   append_name = FALSE;
345   switch(i_ptr->tval)
346     {
347     case  TV_MISC:
348     case  TV_CHEST:
349       break;
350     case  TV_SLING_AMMO:
351     case  TV_BOLT:
352     case  TV_ARROW:
353       (void) sprintf(damstr, " (%dd%d)", i_ptr->damage[0], i_ptr->damage[1]);
354       break;
355     case  TV_LIGHT:
356       p1_use = LIGHT;
357       break;
358     case  TV_SPIKE:
359       break;
360     case  TV_BOW:
361       if (i_ptr->p1 == 1 || i_ptr->p1 == 2)
362 	tmp = 2;
363       else if (i_ptr->p1 == 3 || i_ptr->p1 == 5)
364 	tmp = 3;
365       else if (i_ptr->p1 == 4 || i_ptr->p1 == 6)
366 	tmp = 4;
367       else
368 	tmp = -1;
369       (void) sprintf (damstr, " (x%d)", tmp);
370       break;
371     case  TV_HAFTED:
372     case  TV_POLEARM:
373     case  TV_SWORD:
374       (void) sprintf(damstr, " (%dd%d)", i_ptr->damage[0], i_ptr->damage[1]);
375       p1_use = FLAGS;
376       break;
377     case  TV_DIGGING:
378       p1_use = Z_PLUSSES;
379       (void) sprintf(damstr, " (%dd%d)", i_ptr->damage[0], i_ptr->damage[1]);
380       break;
381     case  TV_BOOTS:
382     case  TV_GLOVES:
383     case  TV_CLOAK:
384     case  TV_HELM:
385     case  TV_SHIELD:
386     case  TV_HARD_ARMOR:
387     case  TV_SOFT_ARMOR:
388       break;
389     case  TV_AMULET:
390       if (modify)
391 	{
392 	  basenm = "& %s Amulet";
393 	  modstr = amulets[indexx];
394 	}
395       else
396 	{
397 	  basenm = "& Amulet";
398 	  append_name = TRUE;
399 	}
400       p1_use = PLUSSES;
401       break;
402     case  TV_RING:
403       if (modify)
404 	{
405 	  basenm = "& %s Ring";
406 	  modstr = rocks[indexx];
407 	}
408       else
409 	{
410 	  basenm = "& Ring";
411 	  append_name = TRUE;
412 	}
413       p1_use = PLUSSES;
414       break;
415     case  TV_STAFF:
416       if (modify)
417 	{
418 	  basenm = "& %s Staff";
419 	  modstr = woods[indexx];
420 	}
421       else
422 	{
423 	  basenm = "& Staff";
424 	  append_name = TRUE;
425 	}
426       p1_use = CHARGES;
427       break;
428     case  TV_WAND:
429       if (modify)
430 	{
431 	  basenm = "& %s Wand";
432 	  modstr = metals[indexx];
433 	}
434       else
435 	{
436 	  basenm = "& Wand";
437 	  append_name = TRUE;
438 	}
439       p1_use = CHARGES;
440       break;
441     case  TV_SCROLL1:
442     case  TV_SCROLL2:
443       if (modify)
444 	{
445 	  basenm =  "& Scroll~ titled \"%s\"";
446 	  modstr = titles[indexx];
447 	}
448       else
449 	{
450 	  basenm = "& Scroll~";
451 	  append_name = TRUE;
452 	}
453       break;
454     case  TV_POTION1:
455     case  TV_POTION2:
456       if (modify)
457 	{
458 	  basenm = "& %s Potion~";
459 	  modstr = colors[indexx];
460 	}
461       else
462 	{
463 	  basenm = "& Potion~";
464 	  append_name = TRUE;
465 	}
466       break;
467     case  TV_FLASK:
468       break;
469     case  TV_FOOD:
470       if (modify)
471 	{
472 	  if (indexx <= 15)
473 	    basenm = "& %s Mushroom~";
474 	  else if (indexx <= 20)
475 	    basenm = "& Hairy %s Mold~";
476 	  if (indexx <= 20)
477 	    modstr = mushrooms[indexx];
478 	}
479       else
480 	{
481 	  append_name = TRUE;
482 	  if (indexx <= 15)
483 	    basenm = "& Mushroom~";
484 	  else if (indexx <= 20)
485 	    basenm = "& Hairy Mold~";
486 	  else
487 	    /* Ordinary food does not have a name appended.  */
488 	    append_name = FALSE;
489 	}
490       break;
491     case  TV_MAGIC_BOOK:
492       modstr = basenm;
493       basenm = "& Book~ of Magic Spells %s";
494       break;
495     case  TV_PRAYER_BOOK:
496       modstr = basenm;
497       basenm = "& Holy Book~ of Prayers %s";
498       break;
499     case TV_OPEN_DOOR:
500     case TV_CLOSED_DOOR:
501     case TV_SECRET_DOOR:
502     case TV_RUBBLE:
503       break;
504     case TV_GOLD:
505     case TV_INVIS_TRAP:
506     case TV_VIS_TRAP:
507     case TV_UP_STAIR:
508     case TV_DOWN_STAIR:
509       (void) strcpy(out_val, object_list[i_ptr->index].name);
510       (void) strcat(out_val, ".");
511       return;
512     case TV_STORE_DOOR:
513       (void) sprintf(out_val, "the entrance to the %s.",
514 		     object_list[i_ptr->index].name);
515       return;
516     default:
517       (void) strcpy(out_val, "Error in objdes()");
518       return;
519     }
520   if (modstr != CNIL)
521     (void) sprintf(tmp_val, basenm, modstr);
522   else
523     (void) strcpy(tmp_val, basenm);
524   if (append_name)
525     {
526       (void) strcat(tmp_val, " of ");
527       (void) strcat(tmp_val, object_list[i_ptr->index].name);
528     }
529   if (i_ptr->number != 1)
530     {
531       insert_str(tmp_val, "ch~", "ches");
532       insert_str(tmp_val, "~", "s");
533     }
534   else
535     insert_str(tmp_val, "~", CNIL);
536   if (!pref)
537     {
538       if (!strncmp("some", tmp_val, 4))
539 	(void) strcpy(out_val, &tmp_val[5]);
540       else if (tmp_val[0] == '&')
541 	/* eliminate the '& ' at the beginning */
542 	(void) strcpy(out_val, &tmp_val[2]);
543       else
544 	(void) strcpy(out_val, tmp_val);
545     }
546   else
547     {
548       if (i_ptr->name2 != SN_NULL && known2_p(i_ptr))
549 	{
550 	  (void) strcat(tmp_val, " ");
551 	  (void) strcat(tmp_val, special_names[i_ptr->name2]);
552 	}
553       if (damstr[0] != '\0')
554 	(void) strcat(tmp_val, damstr);
555       if (known2_p(i_ptr))
556 	{
557 	  /* originally used %+d, but several machines don't support it */
558 	  if (i_ptr->ident & ID_SHOW_HITDAM)
559 	    (void) sprintf(tmp_str, " (%c%d,%c%d)",
560 			   (i_ptr->tohit < 0) ? '-' : '+', abs(i_ptr->tohit),
561 			   (i_ptr->todam < 0) ? '-' : '+', abs(i_ptr->todam));
562 	  else if (i_ptr->tohit != 0)
563 	    (void) sprintf(tmp_str, " (%c%d)",
564 			   (i_ptr->tohit < 0) ? '-' : '+', abs(i_ptr->tohit));
565 	  else if (i_ptr->todam != 0)
566 	    (void) sprintf(tmp_str, " (%c%d)",
567 			   (i_ptr->todam < 0) ? '-' : '+', abs(i_ptr->todam));
568 	  else
569 	    tmp_str[0] = '\0';
570 	  (void) strcat(tmp_val, tmp_str);
571 	}
572       /* Crowns have a zero base AC, so make a special test for them. */
573       if (i_ptr->ac != 0 || (i_ptr->tval == TV_HELM))
574 	{
575 	  (void) sprintf(tmp_str, " [%d", i_ptr->ac);
576 	  (void) strcat(tmp_val, tmp_str);
577 	  if (known2_p(i_ptr))
578 	    {
579 	      /* originally used %+d, but several machines don't support it */
580 	      (void) sprintf(tmp_str, ",%c%d",
581 			     (i_ptr->toac < 0) ? '-' : '+', abs(i_ptr->toac));
582 	      (void) strcat(tmp_val, tmp_str);
583 	    }
584 	  (void) strcat(tmp_val, "]");
585 	}
586       else if ((i_ptr->toac != 0) && known2_p(i_ptr))
587 	{
588 	  /* originally used %+d, but several machines don't support it */
589 	  (void) sprintf(tmp_str, " [%c%d]",
590 			 (i_ptr->toac < 0) ? '-' : '+', abs(i_ptr->toac));
591 	  (void) strcat(tmp_val, tmp_str);
592 	}
593 
594       /* override defaults, check for p1 flags in the ident field */
595       if (i_ptr->ident & ID_NOSHOW_P1)
596 	p1_use = IGNORED;
597       else if (i_ptr->ident & ID_SHOW_P1)
598 	p1_use = Z_PLUSSES;
599       tmp_str[0] = '\0';
600       if (p1_use == LIGHT)
601 	(void) sprintf(tmp_str, " with %d turns of light", i_ptr->p1);
602       else if (p1_use == IGNORED)
603 	;
604       else if (known2_p(i_ptr))
605 	{
606 	  if (p1_use == Z_PLUSSES)
607 	  /* originally used %+d, but several machines don't support it */
608 	    (void) sprintf(tmp_str, " (%c%d)",
609 			   (i_ptr->p1 < 0) ? '-' : '+', abs(i_ptr->p1));
610 	  else if (p1_use == CHARGES)
611 	    (void) sprintf(tmp_str, " (%d charges)", i_ptr->p1);
612 	  else if (i_ptr->p1 != 0)
613 	    {
614 	      if (p1_use == PLUSSES)
615 	        (void) sprintf(tmp_str, " (%c%d)",
616 			       (i_ptr->p1 < 0) ? '-' : '+', abs(i_ptr->p1));
617 	      else if (p1_use == FLAGS)
618 		{
619 		  if (i_ptr->flags & TR_STR)
620 		    (void) sprintf(tmp_str, " (%c%d to STR)",
621 				   (i_ptr->p1 < 0) ? '-' : '+',abs(i_ptr->p1));
622 		  else if (i_ptr->flags & TR_STEALTH)
623 		    (void) sprintf(tmp_str, " (%c%d to stealth)",
624 				   (i_ptr->p1 < 0) ? '-' : '+',abs(i_ptr->p1));
625 		}
626 	    }
627 	}
628       (void) strcat(tmp_val, tmp_str);
629 
630       /* ampersand is always the first character */
631       if (tmp_val[0] == '&')
632 	{
633 	  /* use &tmp_val[1], so that & does not appear in output */
634 	  if (i_ptr->number > 1)
635 	    (void) sprintf(out_val, "%d%s", (int)i_ptr->number, &tmp_val[1]);
636 	  else if (i_ptr->number < 1)
637 	    (void) sprintf(out_val, "%s%s", "no more", &tmp_val[1]);
638 	  else if (is_a_vowel(tmp_val[2]))
639 	    (void) sprintf(out_val, "an%s", &tmp_val[1]);
640 	  else
641 	    (void) sprintf(out_val, "a%s", &tmp_val[1]);
642 	}
643       /* handle 'no more' case specially */
644       else if (i_ptr->number < 1)
645 	{
646 	  /* check for "some" at start */
647 	  if (!strncmp("some", tmp_val, 4))
648 	    (void) sprintf(out_val, "no more %s", &tmp_val[5]);
649 	  /* here if no article */
650 	  else
651 	    (void) sprintf(out_val, "no more %s", tmp_val);
652 	}
653       else
654 	(void) strcpy(out_val, tmp_val);
655 
656       tmp_str[0] = '\0';
657       if ((indexx = object_offset(i_ptr)) >= 0)
658 	{
659 	  indexx = (indexx <<= 6) +
660 	    (i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1));
661 	  /* don't print tried string for store bought items */
662 	  if ((object_ident[indexx] & OD_TRIED) && !store_bought_p(i_ptr))
663 	    (void) strcat(tmp_str, "tried ");
664 	}
665       if (i_ptr->ident & (ID_MAGIK|ID_EMPTY|ID_DAMD))
666 	{
667 	  if (i_ptr->ident & ID_MAGIK)
668 	    (void) strcat(tmp_str, "magik ");
669 	  if (i_ptr->ident & ID_EMPTY)
670 	    (void) strcat(tmp_str, "empty ");
671 	  if (i_ptr->ident & ID_DAMD)
672 	    (void) strcat(tmp_str, "damned ");
673 	}
674       if (i_ptr->inscrip[0] != '\0')
675 	(void) strcat(tmp_str, i_ptr->inscrip);
676       else if ((indexx = strlen(tmp_str)) > 0)
677 	  /* remove the extra blank at the end */
678 	  tmp_str[indexx-1] = '\0';
679       if (tmp_str[0])
680 	{
681 	  (void) sprintf(tmp_val, " {%s}", tmp_str);
682 	  (void) strcat(out_val, tmp_val);
683 	}
684       (void) strcat(out_val, ".");
685     }
686 }
687 
invcopy(to,from_index)688 void invcopy(to, from_index)
689 register inven_type *to;
690 int from_index;
691 {
692   register treasure_type *from;
693 
694   from = &object_list[from_index];
695   to->index	= from_index;
696   to->name2     = SN_NULL;
697   to->inscrip[0] = '\0';
698   to->flags     = from->flags;
699   to->tval      = from->tval;
700   to->tchar     = from->tchar;
701   to->p1        = from->p1;
702   to->cost	= from->cost;
703   to->subval    = from->subval;
704   to->number    = from->number;
705   to->weight    = from->weight;
706   to->tohit     = from->tohit;
707   to->todam     = from->todam;
708   to->ac        = from->ac;
709   to->toac      = from->toac;
710   to->damage[0] = from->damage[0];
711   to->damage[1] = from->damage[1];
712   to->level     = from->level;
713   to->ident	= 0;
714 }
715 
716 
717 /* Describe number of remaining charges.		-RAK-	*/
desc_charges(item_val)718 void desc_charges(item_val)
719 int item_val;
720 {
721   register int rem_num;
722   vtype out_val;
723 
724   if (known2_p(&inventory[item_val]))
725     {
726       rem_num = inventory[item_val].p1;
727       (void) sprintf(out_val, "You have %d charges remaining.", rem_num);
728       msg_print(out_val);
729     }
730 }
731 
732 
733 /* Describe amount of item remaining.			-RAK-	*/
desc_remain(item_val)734 void desc_remain(item_val)
735 int item_val;
736 {
737   bigvtype out_val, tmp_str;
738   register inven_type *i_ptr;
739 
740   i_ptr = &inventory[item_val];
741   i_ptr->number--;
742   objdes(tmp_str, i_ptr, TRUE);
743   i_ptr->number++;
744   /* the string already has a dot at the end. */
745   (void) sprintf(out_val, "You have %s", tmp_str);
746   msg_print(out_val);
747 }
748