xref: /csrg-svn/games/rogue/zap.c (revision 60842)
132689Sbostic /*
2*60842Sbostic  * Copyright (c) 1988, 1993
3*60842Sbostic  *	The Regents of the University of California.  All rights reserved.
436704Sbostic  *
536704Sbostic  * This code is derived from software contributed to Berkeley by
636704Sbostic  * Timothy C. Stoehr.
736704Sbostic  *
842604Sbostic  * %sccs.include.redist.c%
936704Sbostic  */
1036704Sbostic 
1136704Sbostic #ifndef lint
12*60842Sbostic static char sccsid[] = "@(#)zap.c	8.1 (Berkeley) 05/31/93";
1336704Sbostic #endif /* not lint */
1436704Sbostic 
1536704Sbostic /*
1632689Sbostic  * zap.c
1732689Sbostic  *
1832689Sbostic  * This source herein may be modified and/or distributed by anybody who
1932689Sbostic  * so desires, with the following restrictions:
2032689Sbostic  *    1.)  No portion of this notice shall be removed.
2132689Sbostic  *    2.)  Credit shall not be taken for the creation of this source.
2232689Sbostic  *    3.)  This code is not to be traded, sold, or used for personal
2332689Sbostic  *         gain or profit.
2432689Sbostic  *
2532689Sbostic  */
2632689Sbostic 
2732689Sbostic #include "rogue.h"
2832689Sbostic 
2932689Sbostic boolean wizard = 0;
3032689Sbostic 
3132689Sbostic extern boolean being_held, score_only, detect_monster;
3232689Sbostic extern short cur_room;
3332689Sbostic 
zapp()3432689Sbostic zapp()
3532689Sbostic {
3632689Sbostic 	short wch;
3732689Sbostic 	boolean first_miss = 1;
3832689Sbostic 	object *wand;
3932689Sbostic 	short dir, d, row, col;
4032689Sbostic 	object *monster;
4132689Sbostic 
4232689Sbostic 	while (!is_direction(dir = rgetchar(), &d)) {
4332689Sbostic 		sound_bell();
4432689Sbostic 		if (first_miss) {
4532689Sbostic 			message("direction? ", 0);
4632689Sbostic 			first_miss = 0;
4732689Sbostic 		}
4832689Sbostic 	}
4932689Sbostic 	check_message();
5032689Sbostic 	if (dir == CANCEL) {
5132689Sbostic 		return;
5232689Sbostic 	}
5332689Sbostic 	if ((wch = pack_letter("zap with what?", WAND)) == CANCEL) {
5432689Sbostic 		return;
5532689Sbostic 	}
5632689Sbostic 	check_message();
5732689Sbostic 
5832689Sbostic 	if (!(wand = get_letter_object(wch))) {
5932689Sbostic 		message("no such item.", 0);
6032689Sbostic 		return;
6132689Sbostic 	}
6232689Sbostic 	if (wand->what_is != WAND) {
6332689Sbostic 		message("you can't zap with that", 0);
6432689Sbostic 		return;
6532689Sbostic 	}
6632689Sbostic 	if (wand->class <= 0) {
6732689Sbostic 		message("nothing happens", 0);
6832689Sbostic 	} else {
6932689Sbostic 		wand->class--;
7032689Sbostic 		row = rogue.row; col = rogue.col;
7132689Sbostic 		if ((wand->which_kind == COLD) || (wand->which_kind == FIRE)) {
7232689Sbostic 			bounce((short) wand->which_kind, d, row, col, 0);
7332689Sbostic 		} else {
7432689Sbostic 			monster = get_zapped_monster(d, &row, &col);
7532689Sbostic 			if (wand->which_kind == DRAIN_LIFE) {
7632689Sbostic 				wdrain_life(monster);
7732689Sbostic 			} else if (monster) {
7832689Sbostic 				wake_up(monster);
7932689Sbostic 				s_con_mon(monster);
8032689Sbostic 				zap_monster(monster, wand->which_kind);
8132689Sbostic 				relight();
8232689Sbostic 			}
8332689Sbostic 		}
8432689Sbostic 	}
8532689Sbostic 	(void) reg_move();
8632689Sbostic }
8732689Sbostic 
8832689Sbostic object *
get_zapped_monster(dir,row,col)8932689Sbostic get_zapped_monster(dir, row, col)
9032689Sbostic short dir;
9132689Sbostic short *row, *col;
9232689Sbostic {
9332689Sbostic 	short orow, ocol;
9432689Sbostic 
9532689Sbostic 	for (;;) {
9632689Sbostic 		orow = *row; ocol = *col;
9732689Sbostic 		get_dir_rc(dir, row, col, 0);
9832689Sbostic 		if (((*row == orow) && (*col == ocol)) ||
9932689Sbostic 		   (dungeon[*row][*col] & (HORWALL | VERTWALL)) ||
10032689Sbostic 		   (dungeon[*row][*col] == NOTHING)) {
10132689Sbostic 			return(0);
10232689Sbostic 		}
10332689Sbostic 		if (dungeon[*row][*col] & MONSTER) {
10432689Sbostic 			if (!imitating(*row, *col)) {
10532689Sbostic 				return(object_at(&level_monsters, *row, *col));
10632689Sbostic 			}
10732689Sbostic 		}
10832689Sbostic 	}
10932689Sbostic }
11032689Sbostic 
zap_monster(monster,kind)11132689Sbostic zap_monster(monster, kind)
11232689Sbostic object *monster;
11332689Sbostic unsigned short kind;
11432689Sbostic {
11532689Sbostic 	short row, col;
11632689Sbostic 	object *nm;
11732689Sbostic 	short tc;
11832689Sbostic 
11932689Sbostic 	row = monster->row;
12032689Sbostic 	col = monster->col;
12132689Sbostic 
12232689Sbostic 	switch(kind) {
12332689Sbostic 	case SLOW_MONSTER:
12432689Sbostic 		if (monster->m_flags & HASTED) {
12532689Sbostic 			monster->m_flags &= (~HASTED);
12632689Sbostic 		} else {
12732689Sbostic 			monster->slowed_toggle = 0;
12832689Sbostic 			monster->m_flags |= SLOWED;
12932689Sbostic 		}
13032689Sbostic 		break;
13132689Sbostic 	case HASTE_MONSTER:
13232689Sbostic 		if (monster->m_flags & SLOWED) {
13332689Sbostic 			monster->m_flags &= (~SLOWED);
13432689Sbostic 		} else {
13532689Sbostic 			monster->m_flags |= HASTED;
13632689Sbostic 		}
13732689Sbostic 		break;
13832689Sbostic 	case TELE_AWAY:
13932689Sbostic 		tele_away(monster);
14032689Sbostic 		break;
14132689Sbostic 	case INVISIBILITY:
14232689Sbostic 		monster->m_flags |= INVISIBLE;
14332689Sbostic 		break;
14432689Sbostic 	case POLYMORPH:
14532689Sbostic 		if (monster->m_flags & HOLDS) {
14632689Sbostic 			being_held = 0;
14732689Sbostic 		}
14832689Sbostic 		nm = monster->next_monster;
14932689Sbostic 		tc = monster->trail_char;
15032689Sbostic 		(void) gr_monster(monster, get_rand(0, MONSTERS-1));
15132689Sbostic 		monster->row = row;
15232689Sbostic 		monster->col = col;
15332689Sbostic 		monster->next_monster = nm;
15432689Sbostic 		monster->trail_char = tc;
15532689Sbostic 		if (!(monster->m_flags & IMITATES)) {
15632689Sbostic 			wake_up(monster);
15732689Sbostic 		}
15832689Sbostic 		break;
15932689Sbostic 	case MAGIC_MISSILE:
16032689Sbostic 		rogue_hit(monster, 1);
16132689Sbostic 		break;
16232689Sbostic 	case CANCELLATION:
16332689Sbostic 		if (monster->m_flags & HOLDS) {
16432689Sbostic 			being_held = 0;
16532689Sbostic 		}
16632689Sbostic 		if (monster->m_flags & STEALS_ITEM) {
16732689Sbostic 			monster->drop_percent = 0;
16832689Sbostic 		}
16932689Sbostic 		monster->m_flags &= (~(FLIES | FLITS | SPECIAL_HIT | INVISIBLE |
17032689Sbostic 			FLAMES | IMITATES | CONFUSES | SEEKS_GOLD | HOLDS));
17132689Sbostic 		break;
17232689Sbostic 	case DO_NOTHING:
17332689Sbostic 		message("nothing happens", 0);
17432689Sbostic 		break;
17532689Sbostic 	}
17632689Sbostic }
17732689Sbostic 
tele_away(monster)17832689Sbostic tele_away(monster)
17932689Sbostic object *monster;
18032689Sbostic {
18132689Sbostic 	short row, col;
18232689Sbostic 
18332689Sbostic 	if (monster->m_flags & HOLDS) {
18432689Sbostic 		being_held = 0;
18532689Sbostic 	}
18632689Sbostic 	gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
18732689Sbostic 	mvaddch(monster->row, monster->col, monster->trail_char);
18832689Sbostic 	dungeon[monster->row][monster->col] &= ~MONSTER;
18932689Sbostic 	monster->row = row; monster->col = col;
19032689Sbostic 	dungeon[row][col] |= MONSTER;
19132689Sbostic 	monster->trail_char = mvinch(row, col);
19232689Sbostic 	if (detect_monster || rogue_can_see(row, col)) {
19332689Sbostic 		mvaddch(row, col, gmc(monster));
19432689Sbostic 	}
19532689Sbostic }
19632689Sbostic 
wizardize()19732689Sbostic wizardize()
19832689Sbostic {
19932689Sbostic 	char buf[100];
20032689Sbostic 
20132689Sbostic 	if (wizard) {
20232689Sbostic 		wizard = 0;
20332689Sbostic 		message("not wizard anymore", 0);
20432689Sbostic 	} else {
20532689Sbostic 		if (get_input_line("wizard's password:", "", buf, "", 0, 0)) {
20632689Sbostic 			(void) xxx(1);
20732689Sbostic 			xxxx(buf, strlen(buf));
20832689Sbostic 			if (!strncmp(buf, "\247\104\126\272\115\243\027", 7)) {
20932689Sbostic 				wizard = 1;
21032689Sbostic 				score_only = 1;
21132689Sbostic 				message("Welcome, mighty wizard!", 0);
21232689Sbostic 			} else {
21332689Sbostic 				message("sorry", 0);
21432689Sbostic 			}
21532689Sbostic 		}
21632689Sbostic 	}
21732689Sbostic }
21832689Sbostic 
wdrain_life(monster)21932689Sbostic wdrain_life(monster)
22032689Sbostic object *monster;
22132689Sbostic {
22232689Sbostic 	short hp;
22332689Sbostic 	object *lmon, *nm;
22432689Sbostic 
22532689Sbostic 	hp = rogue.hp_current / 3;
22632689Sbostic 	rogue.hp_current = (rogue.hp_current + 1) / 2;
22732689Sbostic 
22832689Sbostic 	if (cur_room >= 0) {
22932689Sbostic 		lmon = level_monsters.next_monster;
23032689Sbostic 		while (lmon) {
23132689Sbostic 			nm = lmon->next_monster;
23232689Sbostic 			if (get_room_number(lmon->row, lmon->col) == cur_room) {
23332689Sbostic 				wake_up(lmon);
23432689Sbostic 				(void) mon_damage(lmon, hp);
23532689Sbostic 			}
23632689Sbostic 			lmon = nm;
23732689Sbostic 		}
23832689Sbostic 	} else {
23932689Sbostic 		if (monster) {
24032689Sbostic 			wake_up(monster);
24132689Sbostic 			(void) mon_damage(monster, hp);
24232689Sbostic 		}
24332689Sbostic 	}
24432689Sbostic 	print_stats(STAT_HP);
24532689Sbostic 	relight();
24632689Sbostic }
24732689Sbostic 
bounce(ball,dir,row,col,r)24832689Sbostic bounce(ball, dir, row, col, r)
24932689Sbostic short ball, dir, row, col, r;
25032689Sbostic {
25132689Sbostic 	short orow, ocol;
25232689Sbostic 	char buf[DCOLS], *s;
25332689Sbostic 	short i, ch, new_dir = -1, damage;
25432689Sbostic 	static short btime;
25532689Sbostic 
25632689Sbostic 	if (++r == 1) {
25732689Sbostic 		btime = get_rand(3, 6);
25832689Sbostic 	} else if (r > btime) {
25932689Sbostic 		return;
26032689Sbostic 	}
26132689Sbostic 
26232689Sbostic 	if (ball == FIRE) {
26332689Sbostic 		s = "fire";
26432689Sbostic 	} else {
26532689Sbostic 		s = "ice";
26632689Sbostic 	}
26732689Sbostic 	if (r > 1) {
26832689Sbostic 		sprintf(buf, "the %s bounces", s);
26932689Sbostic 		message(buf, 0);
27032689Sbostic 	}
27132689Sbostic 	orow = row;
27232689Sbostic 	ocol = col;
27332689Sbostic 	do {
27432689Sbostic 		ch = mvinch(orow, ocol);
27532689Sbostic 		standout();
27632689Sbostic 		mvaddch(orow, ocol, ch);
27732689Sbostic 		get_dir_rc(dir, &orow, &ocol, 1);
27832689Sbostic 	} while (!(	(ocol <= 0) ||
27932689Sbostic 				(ocol >= DCOLS-1) ||
28032689Sbostic 				(dungeon[orow][ocol] == NOTHING) ||
28132689Sbostic 				(dungeon[orow][ocol] & MONSTER) ||
28232689Sbostic 				(dungeon[orow][ocol] & (HORWALL | VERTWALL)) ||
28332689Sbostic 				((orow == rogue.row) && (ocol == rogue.col))));
28432689Sbostic 	standend();
28532689Sbostic 	refresh();
28632689Sbostic 	do {
28732689Sbostic 		orow = row;
28832689Sbostic 		ocol = col;
28932689Sbostic 		ch = mvinch(row, col);
29032689Sbostic 		mvaddch(row, col, ch);
29132689Sbostic 		get_dir_rc(dir, &row, &col, 1);
29232689Sbostic 	} while (!(	(col <= 0) ||
29332689Sbostic 				(col >= DCOLS-1) ||
29432689Sbostic 				(dungeon[row][col] == NOTHING) ||
29532689Sbostic 				(dungeon[row][col] & MONSTER) ||
29632689Sbostic 				(dungeon[row][col] & (HORWALL | VERTWALL)) ||
29732689Sbostic 				((row == rogue.row) && (col == rogue.col))));
29832689Sbostic 
29932689Sbostic 	if (dungeon[row][col] & MONSTER) {
30032689Sbostic 		object *monster;
30132689Sbostic 
30232689Sbostic 		monster = object_at(&level_monsters, row, col);
30332689Sbostic 
30432689Sbostic 		wake_up(monster);
30532689Sbostic 		if (rand_percent(33)) {
30632689Sbostic 			sprintf(buf, "the %s misses the %s", s, mon_name(monster));
30732689Sbostic 			message(buf, 0);
30832689Sbostic 			goto ND;
30932689Sbostic 		}
31032689Sbostic 		if (ball == FIRE) {
31132689Sbostic 			if (!(monster->m_flags & RUSTS)) {
31232689Sbostic 				if (monster->m_flags & FREEZES) {
31332689Sbostic 					damage = monster->hp_to_kill;
31432689Sbostic 				} else if (monster->m_flags & FLAMES) {
31532689Sbostic 					damage = (monster->hp_to_kill / 10) + 1;
31632689Sbostic 				} else {
31732689Sbostic 					damage = get_rand((rogue.hp_current / 3), rogue.hp_max);
31832689Sbostic 				}
31932689Sbostic 			} else {
32032689Sbostic 				damage = (monster->hp_to_kill / 2) + 1;
32132689Sbostic 			}
32232689Sbostic 			sprintf(buf, "the %s hits the %s", s, mon_name(monster));
32332689Sbostic 			message(buf, 0);
32432689Sbostic 			(void) mon_damage(monster, damage);
32532689Sbostic 		} else {
32632689Sbostic 			damage = -1;
32732689Sbostic 			if (!(monster->m_flags & FREEZES)) {
32832689Sbostic 				if (rand_percent(33)) {
32932689Sbostic 					message("the monster is frozen", 0);
33032689Sbostic 					monster->m_flags |= (ASLEEP | NAPPING);
33132689Sbostic 					monster->nap_length = get_rand(3, 6);
33232689Sbostic 				} else {
33332689Sbostic 					damage = rogue.hp_current / 4;
33432689Sbostic 				}
33532689Sbostic 			} else {
33632689Sbostic 				damage = -2;
33732689Sbostic 			}
33832689Sbostic 			if (damage != -1) {
33932689Sbostic 				sprintf(buf, "the %s hits the %s", s, mon_name(monster));
34032689Sbostic 				message(buf, 0);
34132689Sbostic 				(void) mon_damage(monster, damage);
34232689Sbostic 			}
34332689Sbostic 		}
34432689Sbostic 	} else if ((row == rogue.row) && (col == rogue.col)) {
34532689Sbostic 		if (rand_percent(10 + (3 * get_armor_class(rogue.armor)))) {
34632689Sbostic 			sprintf(buf, "the %s misses", s);
34732689Sbostic 			message(buf, 0);
34832689Sbostic 			goto ND;
34932689Sbostic 		} else {
35032689Sbostic 			damage = get_rand(3, (3 * rogue.exp));
35132689Sbostic 			if (ball == FIRE) {
35232689Sbostic 				damage = (damage * 3) / 2;
35332689Sbostic 				damage -= get_armor_class(rogue.armor);
35432689Sbostic 			}
35532689Sbostic 			sprintf(buf, "the %s hits", s);
35632689Sbostic 			rogue_damage(damage, (object *) 0,
35732689Sbostic 					((ball == FIRE) ? KFIRE : HYPOTHERMIA));
35832689Sbostic 			message(buf, 0);
35932689Sbostic 		}
36032689Sbostic 	} else {
36132689Sbostic 		short nrow, ncol;
36232689Sbostic 
36332689Sbostic ND:		for (i = 0; i < 10; i++) {
36432689Sbostic 			dir = get_rand(0, DIRS-1);
36532689Sbostic 			nrow = orow;
36632689Sbostic 			ncol = ocol;
36732689Sbostic 			get_dir_rc(dir, &nrow, &ncol, 1);
36832689Sbostic 			if (((ncol >= 0) && (ncol <= DCOLS-1)) &&
36932689Sbostic 				(dungeon[nrow][ncol] != NOTHING) &&
37032689Sbostic 				(!(dungeon[nrow][ncol] & (VERTWALL | HORWALL)))) {
37132689Sbostic 				new_dir = dir;
37232689Sbostic 				break;
37332689Sbostic 			}
37432689Sbostic 		}
37532689Sbostic 		if (new_dir != -1) {
37632689Sbostic 			bounce(ball, new_dir, orow, ocol, r);
37732689Sbostic 		}
37832689Sbostic 	}
37932689Sbostic }
380