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