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