1: /* 2: * object.c 3: * 4: * This source herein may be modified and/or distributed by anybody who 5: * so desires, with the following restrictions: 6: * 1.) No portion of this notice shall be removed. 7: * 2.) Credit shall not be taken for the creation of this source. 8: * 3.) This code is not to be traded, sold, or used for personal 9: * gain or profit. 10: * 11: */ 12: 13: #ifndef lint 14: static char sccsid[] = "@(#)object.c 5.1 (Berkeley) 11/25/87"; 15: #endif /* not lint */ 16: 17: #include "rogue.h" 18: 19: object level_objects; 20: unsigned short dungeon[DROWS][DCOLS]; 21: short foods = 0; 22: object *free_list = (object *) 0; 23: char *fruit = (char *) 0; 24: 25: fighter rogue = { 26: INIT_AW, /* armor, weapon */ 27: INIT_RINGS, /* rings */ 28: INIT_HP, /* Hp current,max */ 29: INIT_STR, /* Str current,max */ 30: INIT_PACK, /* pack */ 31: INIT_GOLD, /* gold */ 32: INIT_EXP, /* exp level,points */ 33: 0, 0, /* row, col */ 34: INIT_CHAR, /* char */ 35: INIT_MOVES /* moves */ 36: }; 37: 38: struct id id_potions[POTIONS] = { 39: {100, "blue \0 ", "of increase strength ", 0}, 40: {250, "red \0 ", "of restore strength ", 0}, 41: {100, "green \0 ", "of healing ", 0}, 42: {200, "grey \0 ", "of extra healing ", 0}, 43: {10, "brown \0 ", "of poison ", 0}, 44: {300, "clear \0 ", "of raise level ", 0}, 45: {10, "pink \0 ", "of blindness ", 0}, 46: {25, "white \0 ", "of hallucination ", 0}, 47: {100, "purple \0 ", "of detect monster ", 0}, 48: {100, "black \0 ", "of detect things ", 0}, 49: {10, "yellow \0 ", "of confusion ", 0}, 50: {80, "plaid \0 ", "of levitation ", 0}, 51: {150, "burgundy \0 ", "of haste self ", 0}, 52: {145, "beige \0 ", "of see invisible ", 0} 53: }; 54: 55: struct id id_scrolls[SCROLS] = { 56: {505, " ", "of protect armor ", 0}, 57: {200, " ", "of hold monster ", 0}, 58: {235, " ", "of enchant weapon ", 0}, 59: {235, " ", "of enchant armor ", 0}, 60: {175, " ", "of identify ", 0}, 61: {190, " ", "of teleportation ", 0}, 62: {25, " ", "of sleep ", 0}, 63: {610, " ", "of scare monster ", 0}, 64: {210, " ", "of remove curse ", 0}, 65: {80, " ", "of create monster ",0}, 66: {25, " ", "of aggravate monster ",0}, 67: {180, " ", "of magic mapping ", 0}, 68: {90, " ", "of confuse monster ", 0} 69: }; 70: 71: struct id id_weapons[WEAPONS] = { 72: {150, "short bow ", "", 0}, 73: {8, "darts ", "", 0}, 74: {15, "arrows ", "", 0}, 75: {27, "daggers ", "", 0}, 76: {35, "shurikens ", "", 0}, 77: {360, "mace ", "", 0}, 78: {470, "long sword ", "", 0}, 79: {580, "two-handed sword ", "", 0} 80: }; 81: 82: struct id id_armors[ARMORS] = { 83: {300, "leather armor ", "", (UNIDENTIFIED)}, 84: {300, "ring mail ", "", (UNIDENTIFIED)}, 85: {400, "scale mail ", "", (UNIDENTIFIED)}, 86: {500, "chain mail ", "", (UNIDENTIFIED)}, 87: {600, "banded mail ", "", (UNIDENTIFIED)}, 88: {600, "splint mail ", "", (UNIDENTIFIED)}, 89: {700, "plate mail ", "", (UNIDENTIFIED)} 90: }; 91: 92: struct id id_wands[WANDS] = { 93: {25, " ", "of teleport away ",0}, 94: {50, " ", "of slow monster ", 0}, 95: {8, " ", "of invisibility ",0}, 96: {55, " ", "of polymorph ",0}, 97: {2, " ", "of haste monster ",0}, 98: {20, " ", "of magic missile ",0}, 99: {20, " ", "of cancellation ",0}, 100: {0, " ", "of do nothing ",0}, 101: {35, " ", "of drain life ",0}, 102: {20, " ", "of cold ",0}, 103: {20, " ", "of fire ",0} 104: }; 105: 106: struct id id_rings[RINGS] = { 107: {250, " ", "of stealth ",0}, 108: {100, " ", "of teleportation ", 0}, 109: {255, " ", "of regeneration ",0}, 110: {295, " ", "of slow digestion ",0}, 111: {200, " ", "of add strength ",0}, 112: {250, " ", "of sustain strength ",0}, 113: {250, " ", "of dexterity ",0}, 114: {25, " ", "of adornment ",0}, 115: {300, " ", "of see invisible ",0}, 116: {290, " ", "of maintain armor ",0}, 117: {270, " ", "of searching ",0}, 118: }; 119: 120: extern short cur_level, max_level; 121: extern short party_room; 122: extern char *error_file; 123: extern boolean is_wood[]; 124: 125: put_objects() 126: { 127: short i, n; 128: object *obj; 129: 130: if (cur_level < max_level) { 131: return; 132: } 133: n = coin_toss() ? get_rand(2, 4) : get_rand(3, 5); 134: while (rand_percent(33)) { 135: n++; 136: } 137: if (party_room != NO_ROOM) { 138: make_party(); 139: } 140: for (i = 0; i < n; i++) { 141: obj = gr_object(); 142: rand_place(obj); 143: } 144: put_gold(); 145: } 146: 147: put_gold() 148: { 149: short i, j; 150: short row,col; 151: boolean is_maze, is_room; 152: 153: for (i = 0; i < MAXROOMS; i++) { 154: is_maze = (rooms[i].is_room & R_MAZE) ? 1 : 0; 155: is_room = (rooms[i].is_room & R_ROOM) ? 1 : 0; 156: 157: if (!(is_room || is_maze)) { 158: continue; 159: } 160: if (is_maze || rand_percent(GOLD_PERCENT)) { 161: for (j = 0; j < 50; j++) { 162: row = get_rand(rooms[i].top_row+1, 163: rooms[i].bottom_row-1); 164: col = get_rand(rooms[i].left_col+1, 165: rooms[i].right_col-1); 166: if ((dungeon[row][col] == FLOOR) || 167: (dungeon[row][col] == TUNNEL)) { 168: plant_gold(row, col, is_maze); 169: break; 170: } 171: } 172: } 173: } 174: } 175: 176: plant_gold(row, col, is_maze) 177: short row, col; 178: boolean is_maze; 179: { 180: object *obj; 181: 182: obj = alloc_object(); 183: obj->row = row; obj->col = col; 184: obj->what_is = GOLD; 185: obj->quantity = get_rand((2 * cur_level), (16 * cur_level)); 186: if (is_maze) { 187: obj->quantity += obj->quantity / 2; 188: } 189: dungeon[row][col] |= OBJECT; 190: (void) add_to_pack(obj, &level_objects, 0); 191: } 192: 193: place_at(obj, row, col) 194: object *obj; 195: { 196: obj->row = row; 197: obj->col = col; 198: dungeon[row][col] |= OBJECT; 199: (void) add_to_pack(obj, &level_objects, 0); 200: } 201: 202: object * 203: object_at(pack, row, col) 204: register object *pack; 205: short row, col; 206: { 207: object *obj = (object *) 0; 208: 209: if (dungeon[row][col] & (MONSTER | OBJECT)) { 210: obj = pack->next_object; 211: 212: while (obj && ((obj->row != row) || (obj->col != col))) { 213: obj = obj->next_object; 214: } 215: if (!obj) { 216: message("object_at(): inconsistent", 1); 217: } 218: } 219: return(obj); 220: } 221: 222: object * 223: get_letter_object(ch) 224: { 225: object *obj; 226: 227: obj = rogue.pack.next_object; 228: 229: while (obj && (obj->ichar != ch)) { 230: obj = obj->next_object; 231: } 232: return(obj); 233: } 234: 235: free_stuff(objlist) 236: object *objlist; 237: { 238: object *obj; 239: 240: while (objlist->next_object) { 241: obj = objlist->next_object; 242: objlist->next_object = 243: objlist->next_object->next_object; 244: free_object(obj); 245: } 246: } 247: 248: char * 249: name_of(obj) 250: object *obj; 251: { 252: char *retstring; 253: 254: switch(obj->what_is) { 255: case SCROL: 256: retstring = obj->quantity > 1 ? "scrolls " : "scroll "; 257: break; 258: case POTION: 259: retstring = obj->quantity > 1 ? "potions " : "potion "; 260: break; 261: case FOOD: 262: if (obj->which_kind == RATION) { 263: retstring = "food "; 264: } else { 265: retstring = fruit; 266: } 267: break; 268: case WAND: 269: retstring = is_wood[obj->which_kind] ? "staff " : "wand "; 270: break; 271: case WEAPON: 272: switch(obj->which_kind) { 273: case DART: 274: retstring=obj->quantity > 1 ? "darts " : "dart "; 275: break; 276: case ARROW: 277: retstring=obj->quantity > 1 ? "arrows " : "arrow "; 278: break; 279: case DAGGER: 280: retstring=obj->quantity > 1 ? "daggers " : "dagger "; 281: break; 282: case SHURIKEN: 283: retstring=obj->quantity > 1?"shurikens ":"shuriken "; 284: break; 285: default: 286: retstring = id_weapons[obj->which_kind].title; 287: } 288: break; 289: case ARMOR: 290: retstring = "armor "; 291: break; 292: case RING: 293: retstring = "ring "; 294: break; 295: case AMULET: 296: retstring = "amulet "; 297: break; 298: default: 299: retstring = "unknown "; 300: break; 301: } 302: return(retstring); 303: } 304: 305: object * 306: gr_object() 307: { 308: object *obj; 309: 310: obj = alloc_object(); 311: 312: if (foods < (cur_level / 3)) { 313: obj->what_is = FOOD; 314: foods++; 315: } else { 316: obj->what_is = gr_what_is(); 317: } 318: switch(obj->what_is) { 319: case SCROL: 320: gr_scroll(obj); 321: break; 322: case POTION: 323: gr_potion(obj); 324: break; 325: case WEAPON: 326: gr_weapon(obj, 1); 327: break; 328: case ARMOR: 329: gr_armor(obj); 330: break; 331: case WAND: 332: gr_wand(obj); 333: break; 334: case FOOD: 335: get_food(obj, 0); 336: break; 337: case RING: 338: gr_ring(obj, 1); 339: break; 340: } 341: return(obj); 342: } 343: 344: unsigned short 345: gr_what_is() 346: { 347: short percent; 348: unsigned short what_is; 349: 350: percent = get_rand(1, 91); 351: 352: if (percent <= 30) { 353: what_is = SCROL; 354: } else if (percent <= 60) { 355: what_is = POTION; 356: } else if (percent <= 64) { 357: what_is = WAND; 358: } else if (percent <= 74) { 359: what_is = WEAPON; 360: } else if (percent <= 83) { 361: what_is = ARMOR; 362: } else if (percent <= 88) { 363: what_is = FOOD; 364: } else { 365: what_is = RING; 366: } 367: return(what_is); 368: } 369: 370: gr_scroll(obj) 371: object *obj; 372: { 373: short percent; 374: 375: percent = get_rand(0, 91); 376: 377: obj->what_is = SCROL; 378: 379: if (percent <= 5) { 380: obj->which_kind = PROTECT_ARMOR; 381: } else if (percent <= 10) { 382: obj->which_kind = HOLD_MONSTER; 383: } else if (percent <= 20) { 384: obj->which_kind = CREATE_MONSTER; 385: } else if (percent <= 35) { 386: obj->which_kind = IDENTIFY; 387: } else if (percent <= 43) { 388: obj->which_kind = TELEPORT; 389: } else if (percent <= 50) { 390: obj->which_kind = SLEEP; 391: } else if (percent <= 55) { 392: obj->which_kind = SCARE_MONSTER; 393: } else if (percent <= 64) { 394: obj->which_kind = REMOVE_CURSE; 395: } else if (percent <= 69) { 396: obj->which_kind = ENCH_ARMOR; 397: } else if (percent <= 74) { 398: obj->which_kind = ENCH_WEAPON; 399: } else if (percent <= 80) { 400: obj->which_kind = AGGRAVATE_MONSTER; 401: } else if (percent <= 86) { 402: obj->which_kind = CON_MON; 403: } else { 404: obj->which_kind = MAGIC_MAPPING; 405: } 406: } 407: 408: gr_potion(obj) 409: object *obj; 410: { 411: short percent; 412: 413: percent = get_rand(1, 118); 414: 415: obj->what_is = POTION; 416: 417: if (percent <= 5) { 418: obj->which_kind = RAISE_LEVEL; 419: } else if (percent <= 15) { 420: obj->which_kind = DETECT_OBJECTS; 421: } else if (percent <= 25) { 422: obj->which_kind = DETECT_MONSTER; 423: } else if (percent <= 35) { 424: obj->which_kind = INCREASE_STRENGTH; 425: } else if (percent <= 45) { 426: obj->which_kind = RESTORE_STRENGTH; 427: } else if (percent <= 55) { 428: obj->which_kind = HEALING; 429: } else if (percent <= 65) { 430: obj->which_kind = EXTRA_HEALING; 431: } else if (percent <= 75) { 432: obj->which_kind = BLINDNESS; 433: } else if (percent <= 85) { 434: obj->which_kind = HALLUCINATION; 435: } else if (percent <= 95) { 436: obj->which_kind = CONFUSION; 437: } else if (percent <= 105) { 438: obj->which_kind = POISON; 439: } else if (percent <= 110) { 440: obj->which_kind = LEVITATION; 441: } else if (percent <= 114) { 442: obj->which_kind = HASTE_SELF; 443: } else { 444: obj->which_kind = SEE_INVISIBLE; 445: } 446: } 447: 448: gr_weapon(obj, assign_wk) 449: object *obj; 450: int assign_wk; 451: { 452: short percent; 453: short i; 454: short blessing, increment; 455: 456: obj->what_is = WEAPON; 457: if (assign_wk) { 458: obj->which_kind = get_rand(0, (WEAPONS - 1)); 459: } 460: if ((obj->which_kind == ARROW) || (obj->which_kind == DAGGER) || 461: (obj->which_kind == SHURIKEN) | (obj->which_kind == DART)) { 462: obj->quantity = get_rand(3, 15); 463: obj->quiver = get_rand(0, 126); 464: } else { 465: obj->quantity = 1; 466: } 467: obj->hit_enchant = obj->d_enchant = 0; 468: 469: percent = get_rand(1, 96); 470: blessing = get_rand(1, 3); 471: 472: if (percent <= 16) { 473: increment = 1; 474: } else if (percent <= 32) { 475: increment = -1; 476: obj->is_cursed = 1; 477: } 478: if (percent <= 32) { 479: for (i = 0; i < blessing; i++) { 480: if (coin_toss()) { 481: obj->hit_enchant += increment; 482: } else { 483: obj->d_enchant += increment; 484: } 485: } 486: } 487: switch(obj->which_kind) { 488: case BOW: 489: case DART: 490: obj->damage = "1d1"; 491: break; 492: case ARROW: 493: obj->damage = "1d2"; 494: break; 495: case DAGGER: 496: obj->damage = "1d3"; 497: break; 498: case SHURIKEN: 499: obj->damage = "1d4"; 500: break; 501: case MACE: 502: obj->damage = "2d3"; 503: break; 504: case LONG_SWORD: 505: obj->damage = "3d4"; 506: break; 507: case TWO_HANDED_SWORD: 508: obj->damage = "4d5"; 509: break; 510: } 511: } 512: 513: gr_armor(obj) 514: object *obj; 515: { 516: short percent; 517: short blessing; 518: 519: obj->what_is = ARMOR; 520: obj->which_kind = get_rand(0, (ARMORS - 1)); 521: obj->class = obj->which_kind + 2; 522: if ((obj->which_kind == PLATE) || (obj->which_kind == SPLINT)) { 523: obj->class--; 524: } 525: obj->is_protected = 0; 526: obj->d_enchant = 0; 527: 528: percent = get_rand(1, 100); 529: blessing = get_rand(1, 3); 530: 531: if (percent <= 16) { 532: obj->is_cursed = 1; 533: obj->d_enchant -= blessing; 534: } else if (percent <= 33) { 535: obj->d_enchant += blessing; 536: } 537: } 538: 539: gr_wand(obj) 540: object *obj; 541: { 542: obj->what_is = WAND; 543: obj->which_kind = get_rand(0, (WANDS - 1)); 544: obj->class = get_rand(3, 7); 545: } 546: 547: get_food(obj, force_ration) 548: object *obj; 549: boolean force_ration; 550: { 551: obj->what_is = FOOD; 552: 553: if (force_ration || rand_percent(80)) { 554: obj->which_kind = RATION; 555: } else { 556: obj->which_kind = FRUIT; 557: } 558: } 559: 560: put_stairs() 561: { 562: short row, col; 563: 564: gr_row_col(&row, &col, (FLOOR | TUNNEL)); 565: dungeon[row][col] |= STAIRS; 566: } 567: 568: get_armor_class(obj) 569: object *obj; 570: { 571: if (obj) { 572: return(obj->class + obj->d_enchant); 573: } 574: return(0); 575: } 576: 577: object * 578: alloc_object() 579: { 580: object *obj; 581: 582: if (free_list) { 583: obj = free_list; 584: free_list = free_list->next_object; 585: } else if (!(obj = (object *) md_malloc(sizeof(object)))) { 586: message("cannot allocate object, saving game", 0); 587: save_into_file(error_file); 588: } 589: obj->quantity = 1; 590: obj->ichar = 'L'; 591: obj->picked_up = obj->is_cursed = 0; 592: obj->in_use_flags = NOT_USED; 593: obj->identified = UNIDENTIFIED; 594: obj->damage = "1d1"; 595: return(obj); 596: } 597: 598: free_object(obj) 599: object *obj; 600: { 601: obj->next_object = free_list; 602: free_list = obj; 603: } 604: 605: make_party() 606: { 607: short n; 608: 609: party_room = gr_room(); 610: 611: n = rand_percent(99) ? party_objects(party_room) : 11; 612: if (rand_percent(99)) { 613: party_monsters(party_room, n); 614: } 615: } 616: 617: show_objects() 618: { 619: object *obj; 620: short mc, rc, row, col; 621: object *monster; 622: 623: obj = level_objects.next_object; 624: 625: while (obj) { 626: row = obj->row; 627: col = obj->col; 628: 629: rc = get_mask_char(obj->what_is); 630: 631: if (dungeon[row][col] & MONSTER) { 632: if (monster = object_at(&level_monsters, row, col)) { 633: monster->trail_char = rc; 634: } 635: } 636: mc = mvinch(row, col); 637: if (((mc < 'A') || (mc > 'Z')) && 638: ((row != rogue.row) || (col != rogue.col))) { 639: mvaddch(row, col, rc); 640: } 641: obj = obj->next_object; 642: } 643: 644: monster = level_monsters.next_object; 645: 646: while (monster) { 647: if (monster->m_flags & IMITATES) { 648: mvaddch(monster->row, monster->col, (int) monster->disguise); 649: } 650: monster = monster->next_monster; 651: } 652: } 653: 654: put_amulet() 655: { 656: object *obj; 657: 658: obj = alloc_object(); 659: obj->what_is = AMULET; 660: rand_place(obj); 661: } 662: 663: rand_place(obj) 664: object *obj; 665: { 666: short row, col; 667: 668: gr_row_col(&row, &col, (FLOOR | TUNNEL)); 669: place_at(obj, row, col); 670: } 671: 672: c_object_for_wizard() 673: { 674: short ch, max, wk; 675: object *obj; 676: char buf[80]; 677: 678: if (pack_count((object *) 0) >= MAX_PACK_COUNT) { 679: message("pack full", 0); 680: return; 681: } 682: message("type of object?", 0); 683: 684: while (r_index("!?:)]=/,\033", (ch = rgetchar()), 0) == -1) { 685: sound_bell(); 686: } 687: check_message(); 688: 689: if (ch == '\033') { 690: return; 691: } 692: obj = alloc_object(); 693: 694: switch(ch) { 695: case '!': 696: obj->what_is = POTION; 697: max = POTIONS - 1; 698: break; 699: case '?': 700: obj->what_is = SCROL; 701: max = SCROLS - 1; 702: break; 703: case ',': 704: obj->what_is = AMULET; 705: break; 706: case ':': 707: get_food(obj, 0); 708: break; 709: case ')': 710: gr_weapon(obj, 0); 711: max = WEAPONS - 1; 712: break; 713: case ']': 714: gr_armor(obj); 715: max = ARMORS - 1; 716: break; 717: case '/': 718: gr_wand(obj); 719: max = WANDS - 1; 720: break; 721: case '=': 722: max = RINGS - 1; 723: obj->what_is = RING; 724: break; 725: } 726: if ((ch != ',') && (ch != ':')) { 727: GIL: 728: if (get_input_line("which kind?", "", buf, "", 0, 1)) { 729: wk = get_number(buf); 730: if ((wk >= 0) && (wk <= max)) { 731: obj->which_kind = (unsigned short) wk; 732: if (obj->what_is == RING) { 733: gr_ring(obj, 0); 734: } 735: } else { 736: sound_bell(); 737: goto GIL; 738: } 739: } else { 740: free_object(obj); 741: return; 742: } 743: } 744: get_desc(obj, buf); 745: message(buf, 0); 746: (void) add_to_pack(obj, &rogue.pack, 1); 747: }