Annotation of early-roguelike/rogue5/things.c, Revision 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