xref: /original-bsd/games/rogue/zap.c (revision 29d43723)
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  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #ifndef lint
22 static char sccsid[] = "@(#)zap.c	5.2 (Berkeley) 02/07/89";
23 #endif /* not lint */
24 
25 /*
26  * zap.c
27  *
28  * This source herein may be modified and/or distributed by anybody who
29  * so desires, with the following restrictions:
30  *    1.)  No portion of this notice shall be removed.
31  *    2.)  Credit shall not be taken for the creation of this source.
32  *    3.)  This code is not to be traded, sold, or used for personal
33  *         gain or profit.
34  *
35  */
36 
37 #include "rogue.h"
38 
39 boolean wizard = 0;
40 
41 extern boolean being_held, score_only, detect_monster;
42 extern short cur_room;
43 
44 zapp()
45 {
46 	short wch;
47 	boolean first_miss = 1;
48 	object *wand;
49 	short dir, d, row, col;
50 	object *monster;
51 
52 	while (!is_direction(dir = rgetchar(), &d)) {
53 		sound_bell();
54 		if (first_miss) {
55 			message("direction? ", 0);
56 			first_miss = 0;
57 		}
58 	}
59 	check_message();
60 	if (dir == CANCEL) {
61 		return;
62 	}
63 	if ((wch = pack_letter("zap with what?", WAND)) == CANCEL) {
64 		return;
65 	}
66 	check_message();
67 
68 	if (!(wand = get_letter_object(wch))) {
69 		message("no such item.", 0);
70 		return;
71 	}
72 	if (wand->what_is != WAND) {
73 		message("you can't zap with that", 0);
74 		return;
75 	}
76 	if (wand->class <= 0) {
77 		message("nothing happens", 0);
78 	} else {
79 		wand->class--;
80 		row = rogue.row; col = rogue.col;
81 		if ((wand->which_kind == COLD) || (wand->which_kind == FIRE)) {
82 			bounce((short) wand->which_kind, d, row, col, 0);
83 		} else {
84 			monster = get_zapped_monster(d, &row, &col);
85 			if (wand->which_kind == DRAIN_LIFE) {
86 				wdrain_life(monster);
87 			} else if (monster) {
88 				wake_up(monster);
89 				s_con_mon(monster);
90 				zap_monster(monster, wand->which_kind);
91 				relight();
92 			}
93 		}
94 	}
95 	(void) reg_move();
96 }
97 
98 object *
99 get_zapped_monster(dir, row, col)
100 short dir;
101 short *row, *col;
102 {
103 	short orow, ocol;
104 
105 	for (;;) {
106 		orow = *row; ocol = *col;
107 		get_dir_rc(dir, row, col, 0);
108 		if (((*row == orow) && (*col == ocol)) ||
109 		   (dungeon[*row][*col] & (HORWALL | VERTWALL)) ||
110 		   (dungeon[*row][*col] == NOTHING)) {
111 			return(0);
112 		}
113 		if (dungeon[*row][*col] & MONSTER) {
114 			if (!imitating(*row, *col)) {
115 				return(object_at(&level_monsters, *row, *col));
116 			}
117 		}
118 	}
119 }
120 
121 zap_monster(monster, kind)
122 object *monster;
123 unsigned short kind;
124 {
125 	short row, col;
126 	object *nm;
127 	short tc;
128 
129 	row = monster->row;
130 	col = monster->col;
131 
132 	switch(kind) {
133 	case SLOW_MONSTER:
134 		if (monster->m_flags & HASTED) {
135 			monster->m_flags &= (~HASTED);
136 		} else {
137 			monster->slowed_toggle = 0;
138 			monster->m_flags |= SLOWED;
139 		}
140 		break;
141 	case HASTE_MONSTER:
142 		if (monster->m_flags & SLOWED) {
143 			monster->m_flags &= (~SLOWED);
144 		} else {
145 			monster->m_flags |= HASTED;
146 		}
147 		break;
148 	case TELE_AWAY:
149 		tele_away(monster);
150 		break;
151 	case INVISIBILITY:
152 		monster->m_flags |= INVISIBLE;
153 		break;
154 	case POLYMORPH:
155 		if (monster->m_flags & HOLDS) {
156 			being_held = 0;
157 		}
158 		nm = monster->next_monster;
159 		tc = monster->trail_char;
160 		(void) gr_monster(monster, get_rand(0, MONSTERS-1));
161 		monster->row = row;
162 		monster->col = col;
163 		monster->next_monster = nm;
164 		monster->trail_char = tc;
165 		if (!(monster->m_flags & IMITATES)) {
166 			wake_up(monster);
167 		}
168 		break;
169 	case MAGIC_MISSILE:
170 		rogue_hit(monster, 1);
171 		break;
172 	case CANCELLATION:
173 		if (monster->m_flags & HOLDS) {
174 			being_held = 0;
175 		}
176 		if (monster->m_flags & STEALS_ITEM) {
177 			monster->drop_percent = 0;
178 		}
179 		monster->m_flags &= (~(FLIES | FLITS | SPECIAL_HIT | INVISIBLE |
180 			FLAMES | IMITATES | CONFUSES | SEEKS_GOLD | HOLDS));
181 		break;
182 	case DO_NOTHING:
183 		message("nothing happens", 0);
184 		break;
185 	}
186 }
187 
188 tele_away(monster)
189 object *monster;
190 {
191 	short row, col;
192 
193 	if (monster->m_flags & HOLDS) {
194 		being_held = 0;
195 	}
196 	gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
197 	mvaddch(monster->row, monster->col, monster->trail_char);
198 	dungeon[monster->row][monster->col] &= ~MONSTER;
199 	monster->row = row; monster->col = col;
200 	dungeon[row][col] |= MONSTER;
201 	monster->trail_char = mvinch(row, col);
202 	if (detect_monster || rogue_can_see(row, col)) {
203 		mvaddch(row, col, gmc(monster));
204 	}
205 }
206 
207 wizardize()
208 {
209 	char buf[100];
210 
211 	if (wizard) {
212 		wizard = 0;
213 		message("not wizard anymore", 0);
214 	} else {
215 		if (get_input_line("wizard's password:", "", buf, "", 0, 0)) {
216 			(void) xxx(1);
217 			xxxx(buf, strlen(buf));
218 			if (!strncmp(buf, "\247\104\126\272\115\243\027", 7)) {
219 				wizard = 1;
220 				score_only = 1;
221 				message("Welcome, mighty wizard!", 0);
222 			} else {
223 				message("sorry", 0);
224 			}
225 		}
226 	}
227 }
228 
229 wdrain_life(monster)
230 object *monster;
231 {
232 	short hp;
233 	object *lmon, *nm;
234 
235 	hp = rogue.hp_current / 3;
236 	rogue.hp_current = (rogue.hp_current + 1) / 2;
237 
238 	if (cur_room >= 0) {
239 		lmon = level_monsters.next_monster;
240 		while (lmon) {
241 			nm = lmon->next_monster;
242 			if (get_room_number(lmon->row, lmon->col) == cur_room) {
243 				wake_up(lmon);
244 				(void) mon_damage(lmon, hp);
245 			}
246 			lmon = nm;
247 		}
248 	} else {
249 		if (monster) {
250 			wake_up(monster);
251 			(void) mon_damage(monster, hp);
252 		}
253 	}
254 	print_stats(STAT_HP);
255 	relight();
256 }
257 
258 bounce(ball, dir, row, col, r)
259 short ball, dir, row, col, r;
260 {
261 	short orow, ocol;
262 	char buf[DCOLS], *s;
263 	short i, ch, new_dir = -1, damage;
264 	static short btime;
265 
266 	if (++r == 1) {
267 		btime = get_rand(3, 6);
268 	} else if (r > btime) {
269 		return;
270 	}
271 
272 	if (ball == FIRE) {
273 		s = "fire";
274 	} else {
275 		s = "ice";
276 	}
277 	if (r > 1) {
278 		sprintf(buf, "the %s bounces", s);
279 		message(buf, 0);
280 	}
281 	orow = row;
282 	ocol = col;
283 	do {
284 		ch = mvinch(orow, ocol);
285 		standout();
286 		mvaddch(orow, ocol, ch);
287 		get_dir_rc(dir, &orow, &ocol, 1);
288 	} while (!(	(ocol <= 0) ||
289 				(ocol >= DCOLS-1) ||
290 				(dungeon[orow][ocol] == NOTHING) ||
291 				(dungeon[orow][ocol] & MONSTER) ||
292 				(dungeon[orow][ocol] & (HORWALL | VERTWALL)) ||
293 				((orow == rogue.row) && (ocol == rogue.col))));
294 	standend();
295 	refresh();
296 	do {
297 		orow = row;
298 		ocol = col;
299 		ch = mvinch(row, col);
300 		mvaddch(row, col, ch);
301 		get_dir_rc(dir, &row, &col, 1);
302 	} while (!(	(col <= 0) ||
303 				(col >= DCOLS-1) ||
304 				(dungeon[row][col] == NOTHING) ||
305 				(dungeon[row][col] & MONSTER) ||
306 				(dungeon[row][col] & (HORWALL | VERTWALL)) ||
307 				((row == rogue.row) && (col == rogue.col))));
308 
309 	if (dungeon[row][col] & MONSTER) {
310 		object *monster;
311 
312 		monster = object_at(&level_monsters, row, col);
313 
314 		wake_up(monster);
315 		if (rand_percent(33)) {
316 			sprintf(buf, "the %s misses the %s", s, mon_name(monster));
317 			message(buf, 0);
318 			goto ND;
319 		}
320 		if (ball == FIRE) {
321 			if (!(monster->m_flags & RUSTS)) {
322 				if (monster->m_flags & FREEZES) {
323 					damage = monster->hp_to_kill;
324 				} else if (monster->m_flags & FLAMES) {
325 					damage = (monster->hp_to_kill / 10) + 1;
326 				} else {
327 					damage = get_rand((rogue.hp_current / 3), rogue.hp_max);
328 				}
329 			} else {
330 				damage = (monster->hp_to_kill / 2) + 1;
331 			}
332 			sprintf(buf, "the %s hits the %s", s, mon_name(monster));
333 			message(buf, 0);
334 			(void) mon_damage(monster, damage);
335 		} else {
336 			damage = -1;
337 			if (!(monster->m_flags & FREEZES)) {
338 				if (rand_percent(33)) {
339 					message("the monster is frozen", 0);
340 					monster->m_flags |= (ASLEEP | NAPPING);
341 					monster->nap_length = get_rand(3, 6);
342 				} else {
343 					damage = rogue.hp_current / 4;
344 				}
345 			} else {
346 				damage = -2;
347 			}
348 			if (damage != -1) {
349 				sprintf(buf, "the %s hits the %s", s, mon_name(monster));
350 				message(buf, 0);
351 				(void) mon_damage(monster, damage);
352 			}
353 		}
354 	} else if ((row == rogue.row) && (col == rogue.col)) {
355 		if (rand_percent(10 + (3 * get_armor_class(rogue.armor)))) {
356 			sprintf(buf, "the %s misses", s);
357 			message(buf, 0);
358 			goto ND;
359 		} else {
360 			damage = get_rand(3, (3 * rogue.exp));
361 			if (ball == FIRE) {
362 				damage = (damage * 3) / 2;
363 				damage -= get_armor_class(rogue.armor);
364 			}
365 			sprintf(buf, "the %s hits", s);
366 			rogue_damage(damage, (object *) 0,
367 					((ball == FIRE) ? KFIRE : HYPOTHERMIA));
368 			message(buf, 0);
369 		}
370 	} else {
371 		short nrow, ncol;
372 
373 ND:		for (i = 0; i < 10; i++) {
374 			dir = get_rand(0, DIRS-1);
375 			nrow = orow;
376 			ncol = ocol;
377 			get_dir_rc(dir, &nrow, &ncol, 1);
378 			if (((ncol >= 0) && (ncol <= DCOLS-1)) &&
379 				(dungeon[nrow][ncol] != NOTHING) &&
380 				(!(dungeon[nrow][ncol] & (VERTWALL | HORWALL)))) {
381 				new_dir = dir;
382 				break;
383 			}
384 		}
385 		if (new_dir != -1) {
386 			bounce(ball, new_dir, orow, ocol, r);
387 		}
388 	}
389 }
390