comparison rogue5/things.c @ 33:f502bf60e6e4

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