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