xref: /netbsd/games/rogue/inventory.c (revision bf9ec67e)
1 /*	$NetBSD: inventory.c,v 1.6 1998/11/10 13:01:32 hubertf Exp $	*/
2 
3 /*
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Timothy C. Stoehr.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)inventory.c	8.1 (Berkeley) 5/31/93";
43 #else
44 __RCSID("$NetBSD: inventory.c,v 1.6 1998/11/10 13:01:32 hubertf Exp $");
45 #endif
46 #endif /* not lint */
47 
48 /*
49  * inventory.c
50  *
51  * This source herein may be modified and/or distributed by anybody who
52  * so desires, with the following restrictions:
53  *    1.)  No portion of this notice shall be removed.
54  *    2.)  Credit shall not be taken for the creation of this source.
55  *    3.)  This code is not to be traded, sold, or used for personal
56  *         gain or profit.
57  *
58  */
59 
60 #include "rogue.h"
61 
62 boolean is_wood[WANDS];
63 const char *press_space = " --press space to continue--";
64 
65 const char *const wand_materials[WAND_MATERIALS] = {
66 	"steel ",
67 	"bronze ",
68 	"gold ",
69 	"silver ",
70 	"copper ",
71 	"nickel ",
72 	"cobalt ",
73 	"tin ",
74 	"iron ",
75 	"magnesium ",
76 	"chrome ",
77 	"carbon ",
78 	"platinum ",
79 	"silicon ",
80 	"titanium ",
81 
82 	"teak ",
83 	"oak ",
84 	"cherry ",
85 	"birch ",
86 	"pine ",
87 	"cedar ",
88 	"redwood ",
89 	"balsa ",
90 	"ivory ",
91 	"walnut ",
92 	"maple ",
93 	"mahogany ",
94 	"elm ",
95 	"palm ",
96 	"wooden "
97 };
98 
99 const char *const gems[GEMS] = {
100 	"diamond ",
101 	"stibotantalite ",
102 	"lapi-lazuli ",
103 	"ruby ",
104 	"emerald ",
105 	"sapphire ",
106 	"amethyst ",
107 	"quartz ",
108 	"tiger-eye ",
109 	"opal ",
110 	"agate ",
111 	"turquoise ",
112 	"pearl ",
113 	"garnet "
114 };
115 
116 const char *const syllables[MAXSYLLABLES] = {
117 	"blech ",
118 	"foo ",
119 	"barf ",
120 	"rech ",
121 	"bar ",
122 	"blech ",
123 	"quo ",
124 	"bloto ",
125 	"oh ",
126 	"caca ",
127 	"blorp ",
128 	"erp ",
129 	"festr ",
130 	"rot ",
131 	"slie ",
132 	"snorf ",
133 	"iky ",
134 	"yuky ",
135 	"ooze ",
136 	"ah ",
137 	"bahl ",
138 	"zep ",
139 	"druhl ",
140 	"flem ",
141 	"behil ",
142 	"arek ",
143 	"mep ",
144 	"zihr ",
145 	"grit ",
146 	"kona ",
147 	"kini ",
148 	"ichi ",
149 	"tims ",
150 	"ogr ",
151 	"oo ",
152 	"ighr ",
153 	"coph ",
154 	"swerr ",
155 	"mihln ",
156 	"poxi "
157 };
158 
159 #define COMS 48
160 
161 struct id_com_s {
162 	short com_char;
163 	const char *com_desc;
164 };
165 
166 const struct id_com_s com_id_tab[COMS] = {
167 	{'?',	"?       prints help"},
168 	{'r',	"r       read scroll"},
169 	{'/',	"/       identify object"},
170 	{'e',	"e       eat food"},
171 	{'h',	"h       left "},
172 	{'w',	"w       wield a weapon"},
173 	{'j',	"j       down"},
174 	{'W',	"W       wear armor"},
175 	{'k',	"k       up"},
176 	{'T',	"T       take armor off"},
177 	{'l',	"l       right"},
178 	{'P',	"P       put on ring"},
179 	{'y',	"y       up & left"},
180 	{'R',	"R       remove ring"},
181 	{'u',	"u       up & right"},
182 	{'d',	"d       drop object"},
183 	{'b',	"b       down & left"},
184 	{'c',	"c       call object"},
185 	{'n',	"n       down & right"},
186 	{'\0',	"<SHIFT><dir>: run that way"},
187 	{')',	")       print current weapon"},
188 	{'\0',	"<CTRL><dir>: run till adjacent"},
189 	{']',	"]       print current armor"},
190 	{'f',	"f<dir>  fight till death or near death"},
191 	{'=',	"=       print current rings"},
192 	{'t',	"t<dir>  throw something"},
193 	{'\001',	"^A      print Hp-raise average"},
194 	{'m',	"m<dir>  move onto without picking up"},
195 	{'z',	"z<dir>  zap a wand in a direction"},
196 	{'o',	"o       examine/set options"},
197 	{'^',	"^<dir>  identify trap type"},
198 	{'\022',	"^R      redraw screen"},
199 	{'&',	"&       save screen into 'rogue.screen'"},
200 	{'s',	"s       search for trap/secret door"},
201 	{'\020',	"^P      repeat last message"},
202 	{'>',	">       go down a staircase"},
203 	{'\033',	"^[      cancel command"},
204 	{'<',	"<       go up a staircase"},
205 	{'S',	"S       save game"},
206 	{'.',	".       rest for a turn"},
207 	{'Q',	"Q       quit"},
208 	{',',	",       pick something up"},
209 	{'!',	"!       shell escape"},
210 	{'i',	"i       inventory"},
211 	{'F',	"F<dir>  fight till either of you dies"},
212 	{'I',	"I       inventory single item"},
213 	{'v',	"v       print version number"},
214 	{'q',	"q       quaff potion" }
215 };
216 
217 void
218 inventory(pack, mask)
219 	const object *pack;
220 	unsigned short mask;
221 {
222 	object *obj;
223 	short i = 0, j, maxlen = 0, n;
224 	char descs[MAX_PACK_COUNT+1][DCOLS];
225 	short row, col;
226 
227 	obj = pack->next_object;
228 
229 	if (!obj) {
230 		message("your pack is empty", 0);
231 		return;
232 	}
233 	while (obj) {
234 		if (obj->what_is & mask) {
235 			descs[i][0] = ' ';
236 			descs[i][1] = obj->ichar;
237 			descs[i][2] = ((obj->what_is & ARMOR) && obj->is_protected)
238 				? '}' : ')';
239 			descs[i][3] = ' ';
240 			get_desc(obj, descs[i]+4);
241 			if ((n = strlen(descs[i])) > maxlen) {
242 				maxlen = n;
243 			}
244 		i++;
245 		}
246 		obj = obj->next_object;
247 	}
248 	(void) strcpy(descs[i++], press_space);
249 	if (maxlen < 27) maxlen = 27;
250 	col = DCOLS - (maxlen + 2);
251 
252 	for (row = 0; ((row < i) && (row < DROWS)); row++) {
253 		if (row > 0) {
254 			for (j = col; j < DCOLS; j++) {
255 				descs[row-1][j-col] = mvinch(row, j);
256 			}
257 			descs[row-1][j-col] = 0;
258 		}
259 		mvaddstr(row, col, descs[row]);
260 		clrtoeol();
261 	}
262 	refresh();
263 	wait_for_ack();
264 
265 	move(0, 0);
266 	clrtoeol();
267 
268 	for (j = 1; ((j < i) && (j < DROWS)); j++) {
269 		mvaddstr(j, col, descs[j-1]);
270 	}
271 }
272 
273 void
274 id_com()
275 {
276 	int ch = 0;
277 	short i, j, k;
278 
279 	while (ch != CANCEL) {
280 		check_message();
281 		message("Character you want help for (* for all):", 0);
282 
283 		refresh();
284 		ch = getchar();
285 
286 		switch(ch) {
287 		case LIST:
288 			{
289 				char save[(((COMS / 2) + (COMS % 2)) + 1)][DCOLS];
290 				short rows = (((COMS / 2) + (COMS % 2)) + 1);
291 				boolean need_two_screens = FALSE;
292 
293 				if (rows > LINES) {
294 					need_two_screens = 1;
295 					rows = LINES;
296 				}
297 				k = 0;
298 
299 				for (i = 0; i < rows; i++) {
300 					for (j = 0; j < DCOLS; j++) {
301 						save[i][j] = mvinch(i, j);
302 					}
303 				}
304 MORE:
305 				for (i = 0; i < rows; i++) {
306 					move(i, 0);
307 					clrtoeol();
308 				}
309 				for (i = 0; i < (rows-1); i++) {
310 					if (i < (LINES-1)) {
311 						if (((i + i) < COMS) && ((i+i+k) < COMS)) {
312 							mvaddstr(i, 0, com_id_tab[i+i+k].com_desc);
313 						}
314 						if (((i + i + 1) < COMS) && ((i+i+k+1) < COMS)) {
315 							mvaddstr(i, (DCOLS/2),
316 										com_id_tab[i+i+k+1].com_desc);
317 						}
318 					}
319 				}
320 				mvaddstr(rows - 1, 0, need_two_screens ? more : press_space);
321 				refresh();
322 				wait_for_ack();
323 
324 				if (need_two_screens) {
325 					k += ((rows-1) * 2);
326 					need_two_screens = 0;
327 					goto MORE;
328 				}
329 				for (i = 0; i < rows; i++) {
330 					move(i, 0);
331 					for (j = 0; j < DCOLS; j++) {
332 						addch(save[i][j]);
333 					}
334 				}
335 			}
336 			break;
337 		default:
338 			if (!pr_com_id(ch)) {
339 				if (!pr_motion_char(ch)) {
340 					check_message();
341 					message("unknown character", 0);
342 				}
343 			}
344 			ch = CANCEL;
345 			break;
346 		}
347 	}
348 }
349 
350 int
351 pr_com_id(ch)
352 	int ch;
353 {
354 	int i;
355 
356 	if (!get_com_id(&i, ch)) {
357 		return(0);
358 	}
359 	check_message();
360 	message(com_id_tab[i].com_desc, 0);
361 	return(1);
362 }
363 
364 int
365 get_com_id(index, ch)
366 	int *index;
367 	short ch;
368 {
369 	short i;
370 
371 	for (i = 0; i < COMS; i++) {
372 		if (com_id_tab[i].com_char == ch) {
373 			*index = i;
374 			return(1);
375 		}
376 	}
377 	return(0);
378 }
379 
380 int
381 pr_motion_char(ch)
382 	int ch;
383 {
384 	if (	(ch == 'J') ||
385 			(ch == 'K') ||
386 			(ch == 'L') ||
387 			(ch == 'H') ||
388 			(ch == 'Y') ||
389 			(ch == 'U') ||
390 			(ch == 'N') ||
391 			(ch == 'B') ||
392 			(ch == '\012') ||
393 			(ch == '\013') ||
394 			(ch == '\010') ||
395 			(ch == '\014') ||
396 			(ch == '\025') ||
397 			(ch == '\031') ||
398 			(ch == '\016') ||
399 			(ch == '\002')) {
400 		char until[18], buf[DCOLS];
401 		int n;
402 
403 		if (ch <= '\031') {
404 			ch += 96;
405 			(void) strcpy(until, "until adjascent");
406 		} else {
407 			ch += 32;
408 			until[0] = '\0';
409 		}
410 		(void) get_com_id(&n, ch);
411 		sprintf(buf, "run %s %s", com_id_tab[n].com_desc + 8, until);
412 		check_message();
413 		message(buf, 0);
414 		return(1);
415 	} else {
416 		return(0);
417 	}
418 }
419 
420 void
421 mix_colors()
422 {
423 	short i, j, k;
424 	char *t;
425 
426 	for (i = 0; i <= 32; i++) {
427 		j = get_rand(0, (POTIONS - 1));
428 		k = get_rand(0, (POTIONS - 1));
429 		t = id_potions[j].title;
430 		id_potions[j].title = id_potions[k].title;
431 		id_potions[k].title = t;
432 	}
433 }
434 
435 void
436 make_scroll_titles()
437 {
438 	short i, j, n;
439 	short sylls, s;
440 
441 	for (i = 0; i < SCROLS; i++) {
442 		sylls = get_rand(2, 5);
443 		(void) strcpy(id_scrolls[i].title, "'");
444 
445 		for (j = 0; j < sylls; j++) {
446 			s = get_rand(1, (MAXSYLLABLES-1));
447 			(void) strcat(id_scrolls[i].title, syllables[s]);
448 		}
449 		n = strlen(id_scrolls[i].title);
450 		(void) strcpy(id_scrolls[i].title+(n-1), "' ");
451 	}
452 }
453 
454 void
455 get_desc(obj, desc)
456 	const object *obj;
457 	char *desc;
458 {
459 	const char *item_name;
460 	struct id *id_table;
461 	char more_info[32];
462 	short i;
463 
464 	if (obj->what_is == AMULET) {
465 		(void) strcpy(desc, "the amulet of Yendor ");
466 		return;
467 	}
468 	item_name = name_of(obj);
469 
470 	if (obj->what_is == GOLD) {
471 		sprintf(desc, "%d pieces of gold", obj->quantity);
472 		return;
473 	}
474 
475 	if (obj->what_is != ARMOR) {
476 		if (obj->quantity == 1) {
477 			(void) strcpy(desc, "a ");
478 		} else {
479 			sprintf(desc, "%d ", obj->quantity);
480 		}
481 	}
482 	if (obj->what_is == FOOD) {
483 		if (obj->which_kind == RATION) {
484 			if (obj->quantity > 1) {
485 				sprintf(desc, "%d rations of ", obj->quantity);
486 			} else {
487 				(void) strcpy(desc, "some ");
488 			}
489 		} else {
490 			(void) strcpy(desc, "a ");
491 		}
492 		(void) strcat(desc, item_name);
493 		goto ANA;
494 	}
495 	id_table = get_id_table(obj);
496 
497 	if (wizard) {
498 		goto ID;
499 	}
500 	if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
501 		goto CHECK;
502 	}
503 
504 	switch(id_table[obj->which_kind].id_status) {
505 	case UNIDENTIFIED:
506 CHECK:
507 		switch(obj->what_is) {
508 		case SCROL:
509 			(void) strcat(desc, item_name);
510 			(void) strcat(desc, "entitled: ");
511 			(void) strcat(desc, id_table[obj->which_kind].title);
512 			break;
513 		case POTION:
514 			(void) strcat(desc, id_table[obj->which_kind].title);
515 			(void) strcat(desc, item_name);
516 			break;
517 		case WAND:
518 		case RING:
519 			if (obj->identified ||
520 			(id_table[obj->which_kind].id_status == IDENTIFIED)) {
521 				goto ID;
522 			}
523 			if (id_table[obj->which_kind].id_status == CALLED) {
524 				goto CALL;
525 			}
526 			(void) strcat(desc, id_table[obj->which_kind].title);
527 			(void) strcat(desc, item_name);
528 			break;
529 		case ARMOR:
530 			if (obj->identified) {
531 				goto ID;
532 			}
533 			(void) strcpy(desc, id_table[obj->which_kind].title);
534 			break;
535 		case WEAPON:
536 			if (obj->identified) {
537 				goto ID;
538 			}
539 			(void) strcat(desc, name_of(obj));
540 			break;
541 		}
542 		break;
543 	case CALLED:
544 CALL:	switch(obj->what_is) {
545 		case SCROL:
546 		case POTION:
547 		case WAND:
548 		case RING:
549 			(void) strcat(desc, item_name);
550 			(void) strcat(desc, "called ");
551 			(void) strcat(desc, id_table[obj->which_kind].title);
552 			break;
553 		}
554 		break;
555 	case IDENTIFIED:
556 ID:		switch(obj->what_is) {
557 		case SCROL:
558 		case POTION:
559 			(void) strcat(desc, item_name);
560 			(void) strcat(desc, id_table[obj->which_kind].real);
561 			break;
562 		case RING:
563 			if (wizard || obj->identified) {
564 				if ((obj->which_kind == DEXTERITY) ||
565 					(obj->which_kind == ADD_STRENGTH)) {
566 					sprintf(more_info, "%s%d ", ((obj->class > 0) ? "+" : ""),
567 						obj->class);
568 					(void) strcat(desc, more_info);
569 				}
570 			}
571 			(void) strcat(desc, item_name);
572 			(void) strcat(desc, id_table[obj->which_kind].real);
573 			break;
574 		case WAND:
575 			(void) strcat(desc, item_name);
576 			(void) strcat(desc, id_table[obj->which_kind].real);
577 			if (wizard || obj->identified) {
578 				sprintf(more_info, "[%d]", obj->class);
579 				(void) strcat(desc, more_info);
580 			}
581 			break;
582 		case ARMOR:
583 			sprintf(desc, "%s%d ", ((obj->d_enchant >= 0) ? "+" : ""),
584 			obj->d_enchant);
585 			(void) strcat(desc, id_table[obj->which_kind].title);
586 			sprintf(more_info, "[%d] ", get_armor_class(obj));
587 			(void) strcat(desc, more_info);
588 			break;
589 		case WEAPON:
590 			sprintf(desc+strlen(desc), "%s%d,%s%d ",
591 			((obj->hit_enchant >= 0) ? "+" : ""), obj->hit_enchant,
592 			((obj->d_enchant >= 0) ? "+" : ""), obj->d_enchant);
593 			(void) strcat(desc, name_of(obj));
594 			break;
595 		}
596 		break;
597 	}
598 ANA:
599 	if (!strncmp(desc, "a ", 2)) {
600 		if (is_vowel(desc[2])) {
601 			for (i = strlen(desc) + 1; i > 1; i--) {
602 				desc[i] = desc[i-1];
603 			}
604 			desc[1] = 'n';
605 		}
606 	}
607 	if (obj->in_use_flags & BEING_WIELDED) {
608 		(void) strcat(desc, "in hand");
609 	} else if (obj->in_use_flags & BEING_WORN) {
610 		(void) strcat(desc, "being worn");
611 	} else if (obj->in_use_flags & ON_LEFT_HAND) {
612 		(void) strcat(desc, "on left hand");
613 	} else if (obj->in_use_flags & ON_RIGHT_HAND) {
614 		(void) strcat(desc, "on right hand");
615 	}
616 }
617 
618 void
619 get_wand_and_ring_materials()
620 {
621 	short i, j;
622 	boolean used[WAND_MATERIALS];
623 
624 	for (i = 0; i < WAND_MATERIALS; i++) {
625 		used[i] = 0;
626 	}
627 	for (i = 0; i < WANDS; i++) {
628 		do {
629 			j = get_rand(0, WAND_MATERIALS-1);
630 		} while (used[j]);
631 		used[j] = 1;
632 		(void) strcpy(id_wands[i].title, wand_materials[j]);
633 		is_wood[i] = (j > MAX_METAL);
634 	}
635 	for (i = 0; i < GEMS; i++) {
636 		used[i] = 0;
637 	}
638 	for (i = 0; i < RINGS; i++) {
639 		do {
640 			j = get_rand(0, GEMS-1);
641 		} while (used[j]);
642 		used[j] = 1;
643 		(void) strcpy(id_rings[i].title, gems[j]);
644 	}
645 }
646 
647 void
648 single_inv(ichar)
649 	short ichar;
650 {
651 	short ch;
652 	char desc[DCOLS];
653 	object *obj;
654 
655 	ch = ichar ? ichar : pack_letter("inventory what?", ALL_OBJECTS);
656 
657 	if (ch == CANCEL) {
658 		return;
659 	}
660 	if (!(obj = get_letter_object(ch))) {
661 		message("no such item.", 0);
662 		return;
663 	}
664 	desc[0] = ch;
665 	desc[1] = ((obj->what_is & ARMOR) && obj->is_protected) ? '}' : ')';
666 	desc[2] = ' ';
667 	desc[3] = 0;
668 	get_desc(obj, desc+3);
669 	message(desc, 0);
670 }
671 
672 struct id *
673 get_id_table(obj)
674 	const object *obj;
675 {
676 	switch(obj->what_is) {
677 	case SCROL:
678 		return(id_scrolls);
679 	case POTION:
680 		return(id_potions);
681 	case WAND:
682 		return(id_wands);
683 	case RING:
684 		return(id_rings);
685 	case WEAPON:
686 		return(id_weapons);
687 	case ARMOR:
688 		return(id_armors);
689 	}
690 	return((struct id *) 0);
691 }
692 
693 void
694 inv_armor_weapon(is_weapon)
695 	boolean is_weapon;
696 {
697 	if (is_weapon) {
698 		if (rogue.weapon) {
699 			single_inv(rogue.weapon->ichar);
700 		} else {
701 			message("not wielding anything", 0);
702 		}
703 	} else {
704 		if (rogue.armor) {
705 			single_inv(rogue.armor->ichar);
706 		} else {
707 			message("not wearing anything", 0);
708 		}
709 	}
710 }
711 
712 void
713 id_type()
714 {
715 	const char *id;
716 	int ch;
717 	char buf[DCOLS];
718 
719 	message("what do you want identified?", 0);
720 
721 	ch = rgetchar();
722 
723 	if ((ch >= 'A') && (ch <= 'Z')) {
724 		id = m_names[ch-'A'];
725 	} else if (ch < 32) {
726 		check_message();
727 		return;
728 	} else {
729 		switch(ch) {
730 		case '@':
731 			id = "you";
732 			break;
733 		case '%':
734 			id = "staircase";
735 			break;
736 		case '^':
737 			id = "trap";
738 			break;
739 		case '+':
740 			id = "door";
741 			break;
742 		case '-':
743 		case '|':
744 			id = "wall of a room";
745 			break;
746 		case '.':
747 			id = "floor";
748 			break;
749 		case '#':
750 			id = "passage";
751 			break;
752 		case ' ':
753 			id = "solid rock";
754 			break;
755 		case '=':
756 			id = "ring";
757 			break;
758 		case '?':
759 			id = "scroll";
760 			break;
761 		case '!':
762 			id = "potion";
763 			break;
764 		case '/':
765 			id = "wand or staff";
766 			break;
767 		case ')':
768 			id = "weapon";
769 			break;
770 		case ']':
771 			id = "armor";
772 			break;
773 		case '*':
774 			id = "gold";
775 			break;
776 		case ':':
777 			id = "food";
778 			break;
779 		case ',':
780 			id = "the Amulet of Yendor";
781 			break;
782 		default:
783 			id = "unknown character";
784 			break;
785 		}
786 	}
787 	check_message();
788 	sprintf(buf, "'%c': %s", ch, id);
789 	message(buf, 0);
790 }
791