Neale Pickett
·
2011-10-13
rcopy.c
1/*
2 * Contains functions for dealing with things like potions, scrolls,
3 * and other items.
4 *
5 * @(#)rcopy.c 4.53 (Berkeley) 02/05/99
6 */
7
8#include <curses.h>
9#ifdef attron
10#include <term.h>
11#endif attron
12#include <ctype.h>
13#include "netprot.h"
14
15/*
16 * inv_name:
17 * Return the name of something as it would appear in an
18 * inventory.
19 */
20char *
21inv_name(THING *obj, bool drop)
22{
23 char *pb;
24 struct obj_info *op;
25 char *sp;
26 int which;
27
28 pb = Prbuf;
29 which = obj->o_which;
30 switch (obj->o_type)
31 {
32 when POTION:
33 nameit(obj, "potion", P_colors[which], &Pot_info[which], nullstr);
34 when RING:
35 nameit(obj, "ring", R_stones[which], &Ring_info[which], ring_num);
36 when STICK:
37 nameit(obj, Ws_type[which], Ws_made[which], &Ws_info[which], charge_str);
38 when SCROLL:
39 if (obj->o_count == 1)
40 {
41 strcpy(pb, "A scroll ");
42 pb = &Prbuf[9];
43 }
44 else
45 {
46 sprintf(pb, "%d scrolls ", obj->o_count);
47 pb = &Prbuf[strlen(Prbuf)];
48 }
49 op = &Scr_info[which];
50 if (op->oi_know)
51 sprintf(pb, "of %s", op->oi_name);
52 else if (op->oi_guess)
53 sprintf(pb, "called %s", op->oi_guess);
54 else
55 sprintf(pb, "titled '%s'", S_names[which]);
56 when FOOD:
57 if (which == 1)
58 if (obj->o_count == 1)
59 sprintf(pb, "A%s %s", vowelstr(Fruit), Fruit);
60 else
61 sprintf(pb, "%d %ss", obj->o_count, Fruit);
62 else
63 if (obj->o_count == 1)
64 strcpy(pb, "Some food");
65 else
66 sprintf(pb, "%d rations of food", obj->o_count);
67 when WEAPON:
68 sp = Weap_info[which].oi_name;
69 if (obj->o_count > 1)
70 sprintf(pb, "%d ", obj->o_count);
71 else
72 sprintf(pb, "A%s ", vowelstr(sp));
73 pb = &Prbuf[strlen(Prbuf)];
74 if (obj->o_flags & ISKNOW)
75 sprintf(pb, "%s %s", num(obj->o_hplus,obj->o_dplus,WEAPON), sp);
76 else
77 sprintf(pb, "%s", sp);
78 if (obj->o_count > 1)
79 strcat(pb, "s");
80 if (obj->o_label != NULL)
81 {
82 pb = &Prbuf[strlen(Prbuf)];
83 sprintf(pb, " called %s", obj->o_label);
84 }
85 when ARMOR:
86 sp = Arm_info[which].oi_name;
87 if (obj->o_flags & ISKNOW)
88 {
89 sprintf(pb, "%s %s [",
90 num(A_class[which] - obj->o_arm, 0, ARMOR), sp);
91 if (!Terse)
92 strcat(pb, "protection ");
93 pb = &Prbuf[strlen(Prbuf)];
94 sprintf(pb, "%d]", 10 - obj->o_arm);
95 }
96 else
97 sprintf(pb, "%s", sp);
98 if (obj->o_label != NULL)
99 {
100 pb = &Prbuf[strlen(Prbuf)];
101 sprintf(pb, " called %s", obj->o_label);
102 }
103 when AMULET:
104 strcpy(pb, "The Amulet of Yendor");
105 when GOLD:
106 sprintf(Prbuf, "%d Gold pieces", obj->o_goldval);
107#ifdef MASTER
108 otherwise:
109 debug("Picked up something funny %s", unctrl(obj->o_type));
110 sprintf(pb, "Something bizarre %s", unctrl(obj->o_type));
111#endif
112 }
113 if (Inv_describe)
114 {
115 if (obj == Cur_armor)
116 strcat(pb, " (being worn)");
117 if (obj == Cur_weapon)
118 strcat(pb, " (weapon in hand)");
119 if (obj == Cur_ring[LEFT])
120 strcat(pb, " (on left hand)");
121 else if (obj == Cur_ring[RIGHT])
122 strcat(pb, " (on right hand)");
123 }
124 if (drop && isupper(Prbuf[0]))
125 Prbuf[0] = tolower(Prbuf[0]);
126 else if (!drop && islower(*Prbuf))
127 *Prbuf = toupper(*Prbuf);
128 Prbuf[MAXSTR-1] = '\0';
129 return Prbuf;
130}
131
132/*
133 * drop:
134 * Put something down
135 */
136void
137drop(void)
138{
139 char ch;
140 THING *obj;
141
142 ch = chat(Hero.y, Hero.x);
143 if (ch != FLOOR && ch != PASSAGE)
144 {
145 After = FALSE;
146 msg("there is something there already");
147 return;
148 }
149 if ((obj = get_item("drop", 0)) == NULL)
150 return;
151 if (!dropcheck(obj))
152 return;
153 obj = leave_pack(obj, TRUE, !ISMULT(obj->o_type));
154 /*
155 * Link it into the level object list
156 */
157 attach(Lvl_obj, obj);
158 chat(Hero.y, Hero.x) = obj->o_type;
159 flat(Hero.y, Hero.x) |= F_DROPPED;
160 obj->o_pos = Hero;
161 if (obj->o_type == AMULET)
162 Amulet = FALSE;
163 msg("dropped %s", inv_name(obj, TRUE));
164}
165
166/*
167 * dropcheck:
168 * Do special checks for dropping or unweilding|unwearing|unringing
169 */
170bool
171dropcheck(THING *obj)
172{
173 if (obj == NULL)
174 return TRUE;
175 if (obj != Cur_armor && obj != Cur_weapon
176 && obj != Cur_ring[LEFT] && obj != Cur_ring[RIGHT])
177 return TRUE;
178 if (obj->o_flags & ISCURSED)
179 {
180 msg("you can't. It appears to be cursed");
181 return FALSE;
182 }
183 if (obj == Cur_weapon)
184 Cur_weapon = NULL;
185 else if (obj == Cur_armor)
186 {
187 waste_time();
188 Cur_armor = NULL;
189 }
190 else
191 {
192 Cur_ring[obj == Cur_ring[LEFT] ? LEFT : RIGHT] = NULL;
193 switch (obj->o_which)
194 {
195 case R_ADDSTR:
196 chg_str(-obj->o_arm);
197 break;
198 case R_SEEINVIS:
199 unsee();
200 extinguish(unsee);
201 break;
202 }
203 }
204 return TRUE;
205}
206
207/*
208 * new_thing:
209 * Return a new thing
210 */
211THING *
212new_thing(void)
213{
214 THING *cur;
215 int r;
216
217 cur = new_item();
218 cur->o_hplus = 0;
219 cur->o_dplus = 0;
220 cur->o_damage = cur->o_hurldmg = "0x0";
221 cur->o_arm = 11;
222 cur->o_count = 1;
223 cur->o_group = 0;
224 cur->o_flags = 0;
225 /*
226 * Decide what kind of object it will be
227 * If we haven't had food for a while, let it be food.
228 */
229 switch (No_food > 3 ? 2 : pick_one(Things, NUMTHINGS))
230 {
231 when 0:
232 cur->o_type = POTION;
233 cur->o_which = pick_one(Pot_info, MAXPOTIONS);
234 when 1:
235 cur->o_type = SCROLL;
236 cur->o_which = pick_one(Scr_info, MAXSCROLLS);
237 when 2:
238 cur->o_type = FOOD;
239 No_food = 0;
240 if (rnd(10) != 0)
241 cur->o_which = 0;
242 else
243 cur->o_which = 1;
244 when 3:
245 init_weapon(cur, pick_one(Weap_info, MAXWEAPONS));
246 if ((r = rnd(100)) < 10)
247 {
248 cur->o_flags |= ISCURSED;
249 cur->o_hplus -= rnd(3) + 1;
250 }
251 else if (r < 15)
252 cur->o_hplus += rnd(3) + 1;
253 when 4:
254 cur->o_type = ARMOR;
255 cur->o_which = pick_one(Arm_info, MAXARMORS);
256 cur->o_arm = A_class[cur->o_which];
257 if ((r = rnd(100)) < 20)
258 {
259 cur->o_flags |= ISCURSED;
260 cur->o_arm += rnd(3) + 1;
261 }
262 else if (r < 28)
263 cur->o_arm -= rnd(3) + 1;
264 when 5:
265 cur->o_type = RING;
266 cur->o_which = pick_one(Ring_info, MAXRINGS);
267 switch (cur->o_which)
268 {
269 when R_ADDSTR:
270 case R_PROTECT:
271 case R_ADDHIT:
272 case R_ADDDAM:
273 if ((cur->o_arm = rnd(3)) == 0)
274 {
275 cur->o_arm = -1;
276 cur->o_flags |= ISCURSED;
277 }
278 when R_AGGR:
279 case R_TELEPORT:
280 cur->o_flags |= ISCURSED;
281 }
282 when 6:
283 cur->o_type = STICK;
284 cur->o_which = pick_one(Ws_info, MAXSTICKS);
285 fix_stick(cur);
286#ifdef MASTER
287 otherwise:
288 debug("Picked a bad kind of object");
289 wait_for(' ');
290#endif
291 }
292 return cur;
293}
294
295/*
296 * pick_one:
297 * Pick an item out of a list of nitems possible objects
298 */
299int
300pick_one(struct obj_info *info, int nitems)
301{
302 struct obj_info *end;
303 struct obj_info *start;
304 int i;
305
306 start = info;
307 for (end = &info[nitems], i = rnd(100); info < end; info++)
308 if (i < info->oi_prob)
309 break;
310 if (info == end)
311 {
312#ifdef MASTER
313 if (Wizard)
314 {
315 msg("bad pick_one: %d from %d items", i, nitems);
316 for (info = start; info < end; info++)
317 msg("%s: %d%%", info->oi_name, info->oi_prob);
318 }
319#endif
320 info = start;
321 }
322 return info - start;
323}
324
325/*
326 * discovered:
327 * list what the player has discovered in this game of a certain type
328 */
329static int Line_cnt = 0;
330
331static bool Newpage = FALSE;
332
333static char *Lastfmt, *Lastarg;
334
335void
336discovered(void)
337{
338 char ch;
339 bool disc_list;
340
341 do {
342 disc_list = FALSE;
343 if (!Terse)
344 addmsg("for ");
345 addmsg("what type");
346 if (!Terse)
347 addmsg(" of object do you want a list");
348 msg("? (* for all)");
349 ch = readchar();
350 switch (ch)
351 {
352 case ESCAPE:
353 msg("");
354 return;
355 case POTION:
356 case SCROLL:
357 case RING:
358 case STICK:
359 case '*':
360 disc_list = TRUE;
361 break;
362 default:
363 if (Terse)
364 msg("Not a type");
365 else
366 msg("Please type one of %c%c%c%c (ESCAPE to quit)", POTION, SCROLL, RING, STICK);
367 }
368 } while (!disc_list);
369 if (ch == '*')
370 {
371 print_disc(POTION);
372 add_line("", NULL);
373 print_disc(SCROLL);
374 add_line("", NULL);
375 print_disc(RING);
376 add_line("", NULL);
377 print_disc(STICK);
378 end_line();
379 }
380 else
381 {
382 print_disc(ch);
383 end_line();
384 }
385}
386
387/*
388 * print_disc:
389 * Print what we've discovered of type 'type'
390 */
391
392#define MAX4(a,b,c,d) (a > b ? (a > c ? (a > d ? a : d) : (c > d ? c : d)) : (b > c ? (b > d ? b : d) : (c > d ? c : d)))
393
394void
395print_disc(char type)
396{
397 struct obj_info *info;
398 int i, maxnum, num_found;
399 static THING obj;
400 static short order[MAX4(MAXSCROLLS, MAXPOTIONS, MAXRINGS, MAXSTICKS)];
401
402 switch (type)
403 {
404 case SCROLL:
405 maxnum = MAXSCROLLS;
406 info = Scr_info;
407 break;
408 case POTION:
409 maxnum = MAXPOTIONS;
410 info = Pot_info;
411 break;
412 case RING:
413 maxnum = MAXRINGS;
414 info = Ring_info;
415 break;
416 case STICK:
417 maxnum = MAXSTICKS;
418 info = Ws_info;
419 break;
420 }
421 set_order(order, maxnum);
422 obj.o_count = 1;
423 obj.o_flags = 0;
424 num_found = 0;
425 for (i = 0; i < maxnum; i++)
426 if (info[order[i]].oi_know || info[order[i]].oi_guess)
427 {
428 obj.o_type = type;
429 obj.o_which = order[i];
430 add_line("%s", inv_name(&obj, FALSE));
431 num_found++;
432 }
433 if (num_found == 0)
434 add_line(nothing(type), NULL);
435}
436
437/*
438 * set_order:
439 * Set up order for list
440 */
441void
442set_order(short *order, int numthings)
443{
444 int i, r, t;
445
446 for (i = 0; i< numthings; i++)
447 order[i] = i;
448
449 for (i = numthings; i > 0; i--)
450 {
451 r = rnd(i);
452 t = order[i - 1];
453 order[i - 1] = order[r];
454 order[r] = t;
455 }
456}
457
458/*
459 * add_line:
460 * Add a line to the list of discoveries
461 */
462/* VARARGS1 */
463char
464add_line(char *fmt, char *arg)
465{
466 WINDOW *tw, *sw;
467 int x, y;
468 char *prompt = "--Press space to continue--";
469 static int maxlen = -1;
470
471 if (Line_cnt == 0)
472 {
473 wclear(Hw);
474 if (Inv_type == INV_SLOW)
475 Mpos = 0;
476 }
477 if (Inv_type == INV_SLOW)
478 {
479 if (*fmt != '\0')
480 if (msg(fmt, arg) == ESCAPE)
481 return ESCAPE;
482 Line_cnt++;
483 }
484 else
485 {
486 if (maxlen < 0)
487 maxlen = strlen(prompt);
488 if (Line_cnt >= LINES - 1 || fmt == NULL)
489 {
490 if (Inv_type == INV_OVER && fmt == NULL && !Newpage)
491 {
492 msg("");
493 refresh();
494 tw = newwin(Line_cnt + 1, maxlen + 2, 0, COLS - maxlen - 3);
495 sw = subwin(tw, Line_cnt + 1, maxlen + 1, 0, COLS - maxlen - 2);
496 for (y = 0; y <= Line_cnt; y++)
497 {
498 wmove(sw, y, 0);
499 for (x = 0; x <= maxlen; x++)
500 waddch(sw, mvwinch(Hw, y, x));
501 }
502 wmove(tw, Line_cnt, 1);
503 waddstr(tw, prompt);
504 /*
505 * if there are lines below, use 'em
506 */
507 if (LINES > NUMLINES)
508 if (NUMLINES + Line_cnt > LINES)
509 mvwin(tw, LINES - (Line_cnt + 1), COLS - maxlen - 3);
510 else
511 mvwin(tw, NUMLINES, 0);
512 touchwin(tw);
513 wrefresh(tw);
514 wait_for(' ');
515#ifndef attron
516 if (CE)
517#else attron
518 if (clr_eol)
519#endif attron
520 {
521 werase(tw);
522 leaveok(tw, TRUE);
523 wrefresh(tw);
524 }
525 delwin(tw);
526 touchwin(stdscr);
527 }
528 else
529 {
530 wmove(Hw, LINES - 1, 0);
531 waddstr(Hw, prompt);
532 wrefresh(Hw);
533 wait_for(' ');
534 clearok(curscr, TRUE);
535 wclear(Hw);
536#ifdef attron
537 touchwin(stdscr);
538#endif attron
539 }
540 Newpage = TRUE;
541 Line_cnt = 0;
542 maxlen = strlen(prompt);
543 }
544 if (fmt != NULL && !(Line_cnt == 0 && *fmt == '\0'))
545 {
546 mvwprintw(Hw, Line_cnt++, 0, fmt, arg);
547 getyx(Hw, y, x);
548 if (maxlen < x)
549 maxlen = x;
550 Lastfmt = fmt;
551 Lastarg = arg;
552 }
553 }
554 return ~ESCAPE;
555}
556
557/*
558 * end_line:
559 * End the list of lines
560 */
561void
562end_line(void)
563{
564 if (Inv_type != INV_SLOW)
565 if (Line_cnt == 1 && !Newpage)
566 {
567 Mpos = 0;
568 msg(Lastfmt, Lastarg);
569 }
570 else
571 add_line((char *) NULL, NULL);
572 Line_cnt = 0;
573 Newpage = FALSE;
574}
575
576/*
577 * nothing:
578 * Set up Prbuf so that message for "nothing found" is there
579 */
580char *
581nothing(char type)
582{
583 char *sp, *tystr;
584
585 if (Terse)
586 sprintf(Prbuf, "Nothing");
587 else
588 sprintf(Prbuf, "Haven't discovered anything");
589 if (type != '*')
590 {
591 sp = &Prbuf[strlen(Prbuf)];
592 switch (type)
593 {
594 when POTION: tystr = "potion";
595 when SCROLL: tystr = "scroll";
596 when RING: tystr = "ring";
597 when STICK: tystr = "stick";
598 }
599 sprintf(sp, " about any %ss", tystr);
600 }
601 return Prbuf;
602}
603
604/*
605 * nameit:
606 * Give the proper name to a potion, stick, or ring
607 */
608void
609nameit(THING *obj, char *type, char *which, struct obj_info *op,
610 char *(*prfunc)(THING *))
611{
612 char *pb;
613
614 if (op->oi_know || op->oi_guess)
615 {
616 if (obj->o_count == 1)
617 sprintf(Prbuf, "A %s ", type);
618 else
619 sprintf(Prbuf, "%d %ss ", obj->o_count, type);
620 pb = &Prbuf[strlen(Prbuf)];
621 if (op->oi_know)
622 sprintf(pb, "of %s%s(%s)", op->oi_name, (*prfunc)(obj), which);
623 else if (op->oi_guess)
624 sprintf(pb, "called %s%s(%s)", op->oi_guess, (*prfunc)(obj), which);
625 }
626 else if (obj->o_count == 1)
627 sprintf(Prbuf, "A%s %s %s", vowelstr(which), which, type);
628 else
629 sprintf(Prbuf, "%d %s %ss", obj->o_count, which, type);
630}
631
632/*
633 * nullstr:
634 * Return a pointer to a null-length string
635 */
636char *
637nullstr(THING *ignored)
638{
639 return "";
640}
641
642# ifdef MASTER
643/*
644 * pr_list:
645 * List possible potions, scrolls, etc. for wizard.
646 */
647void
648pr_list(void)
649{
650 int ch;
651
652 if (!Terse)
653 addmsg("for ");
654 addmsg("what type");
655 if (!Terse)
656 addmsg(" of object do you want a list");
657 msg("? ");
658 ch = readchar();
659 switch (ch)
660 {
661 when POTION:
662 pr_spec(Pot_info, MAXPOTIONS);
663 when SCROLL:
664 pr_spec(Scr_info, MAXSCROLLS);
665 when RING:
666 pr_spec(Ring_info, MAXRINGS);
667 when STICK:
668 pr_spec(Ws_info, MAXSTICKS);
669 when ARMOR:
670 pr_spec(Arm_info, MAXARMORS);
671 when WEAPON:
672 pr_spec(Weap_info, MAXWEAPONS);
673 otherwise:
674 return;
675 }
676}
677
678/*
679 * pr_spec:
680 * Print specific list of possible items to choose from
681 */
682void
683pr_spec(struct obj_info *info, int nitems)
684{
685 struct obj_info *endp;
686 int i, lastprob;
687
688 endp = &info[nitems];
689 lastprob = 0;
690 for (i = '0'; info < endp; i++)
691 {
692 if (i == '9' + 1)
693 i = 'a';
694 sprintf(Prbuf, "%c: %%s (%d%%%%)", i, info->oi_prob - lastprob);
695 lastprob = info->oi_prob;
696 add_line(Prbuf, info->oi_name);
697 info++;
698 }
699 end_line();
700}
701# endif MASTER