xref: /dragonfly/games/rogue/use.c (revision 7bc7e232)
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