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