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