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