1 /*- 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. 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, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)use.c 8.1 (Berkeley) 5/31/93 33 * $FreeBSD: src/games/rogue/use.c,v 1.4 1999/11/30 03:49:29 billf Exp $ 34 */ 35 36 /* 37 * use.c 38 * 39 * This source herein may be modified and/or distributed by anybody who 40 * so desires, with the following restrictions: 41 * 1.) No portion of this notice shall be removed. 42 * 2.) Credit shall not be taken for the creation of this source. 43 * 3.) This code is not to be traded, sold, or used for personal 44 * gain or profit. 45 * 46 */ 47 48 #include "rogue.h" 49 50 short halluc = 0; 51 short blind = 0; 52 short confused = 0; 53 short levitate = 0; 54 short haste_self = 0; 55 boolean see_invisible = 0; 56 short extra_hp = 0; 57 boolean detect_monster = 0; 58 boolean con_mon = 0; 59 const char *strange_feeling = "you have a strange feeling for a moment, then it passes"; 60 61 extern short bear_trap; 62 extern short cur_room; 63 extern long level_points[]; 64 extern boolean being_held; 65 extern char *fruit, *you_can_move_again; 66 extern boolean sustain_strength; 67 68 static const char *get_ench_color(void); 69 static void go_blind(void); 70 static void hold_monster(void); 71 static void idntfy(void); 72 static void potion_heal(boolean); 73 static void uncurse_all(void); 74 75 void 76 quaff(void) 77 { 78 short ch; 79 char buf[80]; 80 object *obj; 81 82 ch = pack_letter("quaff what?", POTION); 83 84 if (ch == CANCEL) { 85 return; 86 } 87 if (!(obj = get_letter_object(ch))) { 88 message("no such item.", 0); 89 return; 90 } 91 if (obj->what_is != POTION) { 92 message("you can't drink that", 0); 93 return; 94 } 95 switch(obj->which_kind) { 96 case INCREASE_STRENGTH: 97 message("you feel stronger now, what bulging muscles!", 98 0); 99 rogue.str_current++; 100 if (rogue.str_current > rogue.str_max) { 101 rogue.str_max = rogue.str_current; 102 } 103 break; 104 case RESTORE_STRENGTH: 105 rogue.str_current = rogue.str_max; 106 message("this tastes great, you feel warm all over", 0); 107 break; 108 case HEALING: 109 message("you begin to feel better", 0); 110 potion_heal(0); 111 break; 112 case EXTRA_HEALING: 113 message("you begin to feel much better", 0); 114 potion_heal(1); 115 break; 116 case POISON: 117 if (!sustain_strength) { 118 rogue.str_current -= get_rand(1, 3); 119 if (rogue.str_current < 1) { 120 rogue.str_current = 1; 121 } 122 } 123 message("you feel very sick now", 0); 124 if (halluc) { 125 unhallucinate(); 126 } 127 break; 128 case RAISE_LEVEL: 129 rogue.exp_points = level_points[rogue.exp - 1]; 130 message("you suddenly feel much more skillful", 0); 131 add_exp(1, 1); 132 break; 133 case BLINDNESS: 134 go_blind(); 135 break; 136 case HALLUCINATION: 137 message("oh wow, everything seems so cosmic", 0); 138 halluc += get_rand(500, 800); 139 break; 140 case DETECT_MONSTER: 141 show_monsters(); 142 if (!(level_monsters.next_monster)) { 143 message(strange_feeling, 0); 144 } 145 break; 146 case DETECT_OBJECTS: 147 if (level_objects.next_object) { 148 if (!blind) { 149 show_objects(); 150 } 151 } else { 152 message(strange_feeling, 0); 153 } 154 break; 155 case CONFUSION: 156 message((halluc ? "what a trippy feeling" : 157 "you feel confused"), 0); 158 cnfs(); 159 break; 160 case LEVITATION: 161 message("you start to float in the air", 0); 162 levitate += get_rand(15, 30); 163 bear_trap = being_held = 0; 164 break; 165 case HASTE_SELF: 166 message("you feel yourself moving much faster", 0); 167 haste_self += get_rand(11, 21); 168 if (!(haste_self % 2)) { 169 haste_self++; 170 } 171 break; 172 case SEE_INVISIBLE: 173 sprintf(buf, "hmm, this potion tastes like %sjuice", fruit); 174 message(buf, 0); 175 if (blind) { 176 unblind(); 177 } 178 see_invisible = 1; 179 relight(); 180 break; 181 } 182 print_stats((STAT_STRENGTH | STAT_HP)); 183 if (id_potions[obj->which_kind].id_status != CALLED) { 184 id_potions[obj->which_kind].id_status = IDENTIFIED; 185 } 186 vanish(obj, 1, &rogue.pack); 187 } 188 189 void 190 read_scroll(void) 191 { 192 short ch; 193 object *obj; 194 char msg[DCOLS]; 195 196 ch = pack_letter("read what?", SCROL); 197 198 if (ch == CANCEL) { 199 return; 200 } 201 if (!(obj = get_letter_object(ch))) { 202 message("no such item.", 0); 203 return; 204 } 205 if (obj->what_is != SCROL) { 206 message("you can't read that", 0); 207 return; 208 } 209 switch(obj->which_kind) { 210 case SCARE_MONSTER: 211 message("you hear a maniacal laughter in the distance", 212 0); 213 break; 214 case HOLD_MONSTER: 215 hold_monster(); 216 break; 217 case ENCH_WEAPON: 218 if (rogue.weapon) { 219 if (rogue.weapon->what_is == WEAPON) { 220 sprintf(msg, "your %sglow%s %sfor a moment", 221 name_of(rogue.weapon), 222 ((rogue.weapon->quantity <= 1) ? "s" : ""), 223 get_ench_color()); 224 message(msg, 0); 225 if (coin_toss()) { 226 rogue.weapon->hit_enchant++; 227 } else { 228 rogue.weapon->d_enchant++; 229 } 230 } 231 rogue.weapon->is_cursed = 0; 232 } else { 233 message("your hands tingle", 0); 234 } 235 break; 236 case ENCH_ARMOR: 237 if (rogue.armor) { 238 sprintf(msg, "your armor glows %sfor a moment", 239 get_ench_color()); 240 message(msg, 0); 241 rogue.armor->d_enchant++; 242 rogue.armor->is_cursed = 0; 243 print_stats(STAT_ARMOR); 244 } else { 245 message("your skin crawls", 0); 246 } 247 break; 248 case IDENTIFY: 249 message("this is a scroll of identify", 0); 250 obj->identified = 1; 251 id_scrolls[obj->which_kind].id_status = IDENTIFIED; 252 idntfy(); 253 break; 254 case TELEPORT: 255 tele(); 256 break; 257 case SLEEP: 258 message("you fall asleep", 0); 259 take_a_nap(); 260 break; 261 case PROTECT_ARMOR: 262 if (rogue.armor) { 263 message( "your armor is covered by a shimmering gold shield",0); 264 rogue.armor->is_protected = 1; 265 rogue.armor->is_cursed = 0; 266 } else { 267 message("your acne seems to have disappeared", 0); 268 } 269 break; 270 case REMOVE_CURSE: 271 message((!halluc) ? 272 "you feel as though someone is watching over you" : 273 "you feel in touch with the universal oneness", 0); 274 uncurse_all(); 275 break; 276 case CREATE_MONSTER: 277 create_monster(); 278 break; 279 case AGGRAVATE_MONSTER: 280 aggravate(); 281 break; 282 case MAGIC_MAPPING: 283 message("this scroll seems to have a map on it", 0); 284 draw_magic_map(); 285 break; 286 case CON_MON: 287 con_mon = 1; 288 sprintf(msg, "your hands glow %sfor a moment", get_ench_color()); 289 message(msg, 0); 290 break; 291 } 292 if (id_scrolls[obj->which_kind].id_status != CALLED) { 293 id_scrolls[obj->which_kind].id_status = IDENTIFIED; 294 } 295 vanish(obj, (obj->which_kind != SLEEP), &rogue.pack); 296 } 297 298 /* vanish() does NOT handle a quiver of weapons with more than one 299 * arrow (or whatever) in the quiver. It will only decrement the count. 300 */ 301 302 void 303 vanish(object *obj, short rm, object *pack) 304 { 305 if (obj->quantity > 1) { 306 obj->quantity--; 307 } else { 308 if (obj->in_use_flags & BEING_WIELDED) { 309 unwield(obj); 310 } else if (obj->in_use_flags & BEING_WORN) { 311 unwear(obj); 312 } else if (obj->in_use_flags & ON_EITHER_HAND) { 313 un_put_on(obj); 314 } 315 take_from_pack(obj, pack); 316 free_object(obj); 317 } 318 if (rm) { 319 reg_move(); 320 } 321 } 322 323 static void 324 potion_heal(boolean extra) 325 { 326 float ratio; 327 short add; 328 329 rogue.hp_current += rogue.exp; 330 331 ratio = ((float)rogue.hp_current) / rogue.hp_max; 332 333 if (ratio >= 1.00) { 334 rogue.hp_max += (extra ? 2 : 1); 335 extra_hp += (extra ? 2 : 1); 336 rogue.hp_current = rogue.hp_max; 337 } else if (ratio >= 0.90) { 338 rogue.hp_max += (extra ? 1 : 0); 339 extra_hp += (extra ? 1 : 0); 340 rogue.hp_current = rogue.hp_max; 341 } else { 342 if (ratio < 0.33) { 343 ratio = 0.33; 344 } 345 if (extra) { 346 ratio += ratio; 347 } 348 add = (short)(ratio * ((float)rogue.hp_max - rogue.hp_current)); 349 rogue.hp_current += add; 350 if (rogue.hp_current > rogue.hp_max) { 351 rogue.hp_current = rogue.hp_max; 352 } 353 } 354 if (blind) { 355 unblind(); 356 } 357 if (confused && extra) { 358 unconfuse(); 359 } else if (confused) { 360 confused = (confused / 2) + 1; 361 } 362 if (halluc && extra) { 363 unhallucinate(); 364 } else if (halluc) { 365 halluc = (halluc / 2) + 1; 366 } 367 } 368 369 static void 370 idntfy(void) 371 { 372 short ch; 373 object *obj; 374 struct id *id_table; 375 char desc[DCOLS]; 376 AGAIN: 377 ch = pack_letter("what would you like to identify?", ALL_OBJECTS); 378 379 if (ch == CANCEL) { 380 return; 381 } 382 if (!(obj = get_letter_object(ch))) { 383 message("no such item, try again", 0); 384 message("", 0); 385 check_message(); 386 goto AGAIN; 387 } 388 obj->identified = 1; 389 if (obj->what_is & (SCROL | POTION | WEAPON | ARMOR | WAND | RING)) { 390 id_table = get_id_table(obj); 391 id_table[obj->which_kind].id_status = IDENTIFIED; 392 } 393 get_desc(obj, desc); 394 message(desc, 0); 395 } 396 397 void 398 eat(void) 399 { 400 short ch; 401 short moves; 402 object *obj; 403 char buf[70]; 404 405 ch = pack_letter("eat what?", FOOD); 406 407 if (ch == CANCEL) { 408 return; 409 } 410 if (!(obj = get_letter_object(ch))) { 411 message("no such item.", 0); 412 return; 413 } 414 if (obj->what_is != FOOD) { 415 message("you can't eat that", 0); 416 return; 417 } 418 if ((obj->which_kind == FRUIT) || rand_percent(60)) { 419 moves = get_rand(950, 1150); 420 if (obj->which_kind == RATION) { 421 message("yum, that tasted good", 0); 422 } else { 423 sprintf(buf, "my, that was a yummy %s", fruit); 424 message(buf, 0); 425 } 426 } else { 427 moves = get_rand(750, 950); 428 message("yuk, that food tasted awful", 0); 429 add_exp(2, 1); 430 } 431 rogue.moves_left /= 3; 432 rogue.moves_left += moves; 433 hunger_str[0] = 0; 434 print_stats(STAT_HUNGER); 435 436 vanish(obj, 1, &rogue.pack); 437 } 438 439 static void 440 hold_monster(void) 441 { 442 short i, j; 443 short mcount = 0; 444 object *monster; 445 short row, col; 446 447 for (i = -2; i <= 2; i++) { 448 for (j = -2; j <= 2; j++) { 449 row = rogue.row + i; 450 col = rogue.col + j; 451 if ((row < MIN_ROW) || (row > (DROWS-2)) || (col < 0) || 452 (col > (DCOLS-1))) { 453 continue; 454 } 455 if (dungeon[row][col] & MONSTER) { 456 monster = object_at(&level_monsters, row, col); 457 monster->m_flags |= ASLEEP; 458 monster->m_flags &= (~WAKENS); 459 mcount++; 460 } 461 } 462 } 463 if (mcount == 0) { 464 message("you feel a strange sense of loss", 0); 465 } else if (mcount == 1) { 466 message("the monster freezes", 0); 467 } else { 468 message("the monsters around you freeze", 0); 469 } 470 } 471 472 void 473 tele(void) 474 { 475 mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col)); 476 477 if (cur_room >= 0) { 478 darken_room(cur_room); 479 } 480 put_player(get_room_number(rogue.row, rogue.col)); 481 being_held = 0; 482 bear_trap = 0; 483 } 484 485 void 486 hallucinate(void) 487 { 488 object *obj, *monster; 489 short ch; 490 491 if (blind) return; 492 493 obj = level_objects.next_object; 494 495 while (obj) { 496 ch = mvinch(obj->row, obj->col); 497 if (((ch < 'A') || (ch > 'Z')) && 498 ((obj->row != rogue.row) || (obj->col != rogue.col))) 499 { 500 if ((ch != ' ') && (ch != '.') && (ch != '#') && 501 (ch != '+')) 502 { 503 addch(gr_obj_char()); 504 } 505 } 506 obj = obj->next_object; 507 } 508 monster = level_monsters.next_monster; 509 510 while (monster) { 511 ch = mvinch(monster->row, monster->col); 512 if ((ch >= 'A') && (ch <= 'Z')) { 513 addch(get_rand('A', 'Z')); 514 } 515 monster = monster->next_monster; 516 } 517 } 518 519 void 520 unhallucinate(void) 521 { 522 halluc = 0; 523 relight(); 524 message("everything looks SO boring now", 1); 525 } 526 527 void 528 unblind(void) 529 { 530 blind = 0; 531 message("the veil of darkness lifts", 1); 532 relight(); 533 if (halluc) { 534 hallucinate(); 535 } 536 if (detect_monster) { 537 show_monsters(); 538 } 539 } 540 541 void 542 relight(void) 543 { 544 if (cur_room == PASSAGE) { 545 light_passage(rogue.row, rogue.col); 546 } else { 547 light_up_room(cur_room); 548 } 549 mvaddch(rogue.row, rogue.col, rogue.fchar); 550 } 551 552 void 553 take_a_nap(void) 554 { 555 short i; 556 557 i = get_rand(2, 5); 558 md_sleep(1); 559 560 while (i--) { 561 mv_mons(); 562 } 563 md_sleep(1); 564 message(you_can_move_again, 0); 565 } 566 567 static void 568 go_blind(void) 569 { 570 short i, j; 571 572 if (!blind) { 573 message("a cloak of darkness falls around you", 0); 574 } 575 blind += get_rand(500, 800); 576 577 if (detect_monster) { 578 object *monster; 579 580 monster = level_monsters.next_monster; 581 582 while (monster) { 583 mvaddch(monster->row, monster->col, monster->trail_char); 584 monster = monster->next_monster; 585 } 586 } 587 if (cur_room >= 0) { 588 for (i = rooms[cur_room].top_row + 1; 589 i < rooms[cur_room].bottom_row; i++) { 590 for (j = rooms[cur_room].left_col + 1; 591 j < rooms[cur_room].right_col; j++) { 592 mvaddch(i, j, ' '); 593 } 594 } 595 } 596 mvaddch(rogue.row, rogue.col, rogue.fchar); 597 } 598 599 static const char * 600 get_ench_color(void) 601 { 602 if (halluc) { 603 return(id_potions[get_rand(0, POTIONS-1)].title); 604 } else if (con_mon) { 605 return("red "); 606 } 607 return("blue "); 608 } 609 610 void 611 cnfs(void) 612 { 613 confused += get_rand(12, 22); 614 } 615 616 void 617 unconfuse(void) 618 { 619 char msg[80]; 620 621 confused = 0; 622 sprintf(msg, "you feel less %s now", (halluc ? "trippy" : "confused")); 623 message(msg, 1); 624 } 625 626 static void 627 uncurse_all(void) 628 { 629 object *obj; 630 631 obj = rogue.pack.next_object; 632 633 while (obj) { 634 obj->is_cursed = 0; 635 obj = obj->next_object; 636 } 637 } 638