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