Annotation of early-roguelike/rogue5/things.c, Revision 1.1.1.1
1.1 rubenllo 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: }
394:
395: /*
396: * print_disc:
397: * Print what we've discovered of type 'type'
398: */
399:
400: #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)))
401:
402:
403: void
404: print_disc(int type)
405: {
406: struct obj_info *info = NULL;
407: int i, maxnum = 0, num_found;
408: THING obj;
409: int order[MAX4(MAXSCROLLS, MAXPOTIONS, MAXRINGS, MAXSTICKS)];
410:
411: switch (type)
412: {
413: case SCROLL:
414: maxnum = MAXSCROLLS;
415: info = scr_info;
416: break;
417: case POTION:
418: maxnum = MAXPOTIONS;
419: info = pot_info;
420: break;
421: case RING:
422: maxnum = MAXRINGS;
423: info = ring_info;
424: break;
425: case STICK:
426: maxnum = MAXSTICKS;
427: info = ws_info;
428: break;
429: }
430: set_order(order, maxnum);
431: obj.o_count = 1;
432: obj.o_flags = 0;
433: num_found = 0;
434: for (i = 0; i < maxnum; i++)
435: if (info[order[i]].oi_know || info[order[i]].oi_guess)
436: {
437: obj.o_type = type;
438: obj.o_which = order[i];
439: add_line("%s", inv_name(&obj, FALSE));
440: num_found++;
441: }
442: if (num_found == 0)
443: add_line(nothing(type), NULL);
444: }
445:
446: /*
447: * set_order:
448: * Set up order for list
449: */
450:
451: void
452: set_order(int *order, int numthings)
453: {
454: int i, r, t;
455:
456: for (i = 0; i< numthings; i++)
457: order[i] = i;
458:
459: for (i = numthings; i > 0; i--)
460: {
461: r = rnd(i);
462: t = order[i - 1];
463: order[i - 1] = order[r];
464: order[r] = t;
465: }
466: }
467:
468: /*
469: * add_line:
470: * Add a line to the list of discoveries
471: */
472: /* VARARGS1 */
473: int
474: add_line(const char *fmt, const char *arg)
475: {
476: WINDOW *tw, *sw;
477: int x, y;
478: char *prompt = "--Press space to continue--";
479: static int maxlen = -1;
480:
481: if (line_cnt == 0)
482: {
483: wclear(hw);
484: if (inv_type == INV_SLOW)
485: mpos = 0;
486: }
487: if (inv_type == INV_SLOW)
488: {
489: if (fmt != NULL && *fmt != '\0')
490: if (msg(fmt, arg) == ESCAPE)
491: return ESCAPE;
492: line_cnt++;
493: }
494: else
495: {
496: if (maxlen < 0)
497: maxlen = (int) strlen(prompt);
498: if (line_cnt >= LINES - 1 || fmt == NULL)
499: {
500: if (inv_type == INV_OVER && fmt == NULL && !newpage)
501: {
502: msg("");
503: refresh();
504: tw = newwin(line_cnt + 1, maxlen + 2, 0, COLS - maxlen - 3);
505: sw = subwin(tw, line_cnt + 1, maxlen + 1, 0, COLS - maxlen - 2);
506: for (y = 0; y <= line_cnt; y++)
507: {
508: wmove(sw, y, 0);
509: for (x = 0; x <= maxlen; x++)
510: waddch(sw, mvwinch(hw, y, x));
511: }
512: wmove(tw, line_cnt, 1);
513: waddstr(tw, prompt);
514: /*
515: * if there are lines below, use 'em
516: */
517: if (LINES > NUMLINES)
518: {
519: if (NUMLINES + line_cnt > LINES)
520: mvwin(tw, LINES - (line_cnt + 1), COLS - maxlen - 3);
521: else
522: mvwin(tw, NUMLINES, 0);
523: }
524: touchwin(tw);
525: wrefresh(tw);
526: wait_for(tw, ' ');
527: if (md_hasclreol())
528: {
529: werase(tw);
530: leaveok(tw, TRUE);
531: wrefresh(tw);
532: }
533: delwin(tw);
534: touchwin(stdscr);
535: }
536: else
537: {
538: wmove(hw, LINES - 1, 0);
539: waddstr(hw, prompt);
540: wrefresh(hw);
541: wait_for(hw, ' ');
542: clearok(curscr, TRUE);
543: wclear(hw);
544: touchwin(stdscr);
545: }
546: newpage = TRUE;
547: line_cnt = 0;
548: maxlen = (int) strlen(prompt);
549: }
550: if (fmt != NULL && !(line_cnt == 0 && *fmt == '\0'))
551: {
552: mvwprintw(hw, line_cnt++, 0, fmt, arg);
553: getyx(hw, y, x);
554: if (maxlen < x)
555: maxlen = x;
556: lastfmt = fmt;
557: lastarg = arg;
558: }
559: }
560: return ~ESCAPE;
561: }
562:
563: /*
564: * end_line:
565: * End the list of lines
566: */
567:
568: void
569: end_line(void)
570: {
571: if (inv_type != INV_SLOW)
572: {
573: if (line_cnt == 1 && !newpage)
574: {
575: mpos = 0;
576: msg(lastfmt, lastarg);
577: }
578: else
579: {
580: add_line(NULL, NULL);
581: msg("");
582: }
583: }
584: line_cnt = 0;
585: newpage = FALSE;
586: }
587:
588: /*
589: * nothing:
590: * Set up prbuf so that message for "nothing found" is there
591: */
592: const char *
593: nothing(int type)
594: {
595: char *sp, *tystr = NULL;
596:
597: if (terse)
598: sprintf(prbuf, "Nothing");
599: else
600: sprintf(prbuf, "Haven't discovered anything");
601: if (type != '*')
602: {
603: sp = &prbuf[strlen(prbuf)];
604: switch (type)
605: {
606: case POTION: tystr = "potion";
607: when SCROLL: tystr = "scroll";
608: when RING: tystr = "ring";
609: when STICK: tystr = "stick";
610: }
611: sprintf(sp, " about any %ss", tystr);
612: }
613: return prbuf;
614: }
615:
616: /*
617: * nameit:
618: * Give the proper name to a potion, stick, or ring
619: */
620:
621: void
622: nameit(const THING *obj, const char *type, const char *which, const struct obj_info *op,
623: const char *(*prfunc)(const THING *))
624: {
625: char *pb;
626:
627: if (op->oi_know || op->oi_guess)
628: {
629: if (obj->o_count == 1)
630: sprintf(prbuf, "A %s ", type);
631: else
632: sprintf(prbuf, "%d %ss ", obj->o_count, type);
633: pb = &prbuf[strlen(prbuf)];
634: if (op->oi_know)
635: sprintf(pb, "of %s%s(%s)", op->oi_name, (*prfunc)(obj), which);
636: else if (op->oi_guess)
637: sprintf(pb, "called %s%s(%s)", op->oi_guess, (*prfunc)(obj), which);
638: }
639: else if (obj->o_count == 1)
640: sprintf(prbuf, "A%s %s %s", vowelstr(which), which, type);
641: else
642: sprintf(prbuf, "%d %s %ss", obj->o_count, which, type);
643: }
644:
645: /*
646: * nullstr:
647: * Return a pointer to a null-length string
648: */
649: const char *
650: nullstr(const THING *ignored)
651: {
652: NOOP(ignored);
653: return "";
654: }
655:
656: # ifdef MASTER
657: /*
658: * pr_list:
659: * List possible potions, scrolls, etc. for wizard.
660: */
661:
662: void
663: pr_list(void)
664: {
665: int ch;
666:
667: if (!terse)
668: addmsg("for ");
669: addmsg("what type");
670: if (!terse)
671: addmsg(" of object do you want a list");
672: msg("? ");
673: ch = readchar();
674: msg("");
675: switch (ch)
676: {
677: case POTION:
678: pr_spec(pot_info, MAXPOTIONS);
679: when SCROLL:
680: pr_spec(scr_info, MAXSCROLLS);
681: when RING:
682: pr_spec(ring_info, MAXRINGS);
683: when STICK:
684: pr_spec(ws_info, MAXSTICKS);
685: when ARMOR:
686: pr_spec(arm_info, MAXARMORS);
687: when WEAPON:
688: pr_spec(weap_info, MAXWEAPONS);
689: otherwise:
690: return;
691: }
692: }
693:
694: /*
695: * pr_spec:
696: * Print specific list of possible items to choose from
697: */
698:
699: void
700: pr_spec(const struct obj_info *info, int nitems)
701: {
702: const struct obj_info *endp;
703: int i, lastprob;
704:
705: endp = &info[nitems];
706: lastprob = 0;
707: for (i = '0'; info < endp; i++)
708: {
709: if (i == '9' + 1)
710: i = 'a';
711: sprintf(prbuf, "%c: %%s (%d%%%%)", i, info->oi_prob - lastprob);
712: lastprob = info->oi_prob;
713: add_line(prbuf, info->oi_name);
714: info++;
715: }
716: end_line();
717: }
718: # endif /* MASTER */
CVSweb