1 /* $NetBSD: use.c,v 1.10 2009/08/12 08:44:45 dholland 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
38 static char sccsid[] = "@(#)use.c 8.1 (Berkeley) 5/31/93";
39 #else
40 __RCSID("$NetBSD: use.c,v 1.10 2009/08/12 08:44:45 dholland 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
58 short halluc = 0;
59 short blind = 0;
60 short confused = 0;
61 short levitate = 0;
62 short haste_self = 0;
63 boolean see_invisible = 0;
64 short extra_hp = 0;
65 boolean detect_monster = 0;
66 boolean con_mon = 0;
67
68 static const char strange_feeling[] =
69 "you have a strange feeling for a moment, then it passes";
70
71 static const char *get_ench_color(void);
72 static void go_blind(void);
73 static void hold_monster(void);
74 static void idntfy(void);
75 static void potion_heal(int);
76 static void uncurse_all(void);
77
78 void
quaff(void)79 quaff(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
190 void
read_scroll(void)191 read_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
299 void
vanish(object * obj,short rm,object * pack)300 vanish(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
320 static void
potion_heal(int extra)321 potion_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
366 static void
idntfy(void)367 idntfy(void)
368 {
369 short ch;
370 object *obj;
371 struct id *id_table;
372 char desc[DCOLS];
373 AGAIN:
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
394 void
eat(void)395 eat(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
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 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
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 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
510 void
unhallucinate(void)511 unhallucinate(void)
512 {
513 halluc = 0;
514 relight();
515 messagef(1, "everything looks SO boring now");
516 }
517
518 void
unblind(void)519 unblind(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
532 void
relight(void)533 relight(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
543 void
take_a_nap(void)544 take_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
558 static void
go_blind(void)559 go_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
590 static const char *
get_ench_color(void)591 get_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
601 void
cnfs(void)602 cnfs(void)
603 {
604 confused += get_rand(12, 22);
605 }
606
607 void
unconfuse(void)608 unconfuse(void)
609 {
610 confused = 0;
611 messagef(1, "you feel less %s now", (halluc ? "trippy" : "confused"));
612 }
613
614 static void
uncurse_all(void)615 uncurse_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