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