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