xref: /original-bsd/games/rogue/spec_hit.c (revision 2301fdfb)
1 /*
2  * special_hit.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[] = "@(#)spec_hit.c	5.1 (Berkeley) 11/25/87";
15 #endif /* not lint */
16 
17 #include "rogue.h"
18 
19 short less_hp = 0;
20 boolean being_held;
21 
22 extern short cur_level, max_level, blind, levitate, ring_exp;
23 extern long level_points[];
24 extern boolean detect_monster, mon_disappeared;
25 extern boolean sustain_strength, maintain_armor;
26 extern char *you_can_move_again;
27 
28 special_hit(monster)
29 object *monster;
30 {
31 	if ((monster->m_flags & CONFUSED) && rand_percent(66)) {
32 		return;
33 	}
34 	if (monster->m_flags & RUSTS) {
35 		rust(monster);
36 	}
37 	if ((monster->m_flags & HOLDS) && !levitate) {
38 		being_held = 1;
39 	}
40 	if (monster->m_flags & FREEZES) {
41 		freeze(monster);
42 	}
43 	if (monster->m_flags & STINGS) {
44 		sting(monster);
45 	}
46 	if (monster->m_flags & DRAINS_LIFE) {
47 		drain_life();
48 	}
49 	if (monster->m_flags & DROPS_LEVEL) {
50 		drop_level();
51 	}
52 	if (monster->m_flags & STEALS_GOLD) {
53 		steal_gold(monster);
54 	} else if (monster->m_flags & STEALS_ITEM) {
55 		steal_item(monster);
56 	}
57 }
58 
59 rust(monster)
60 object *monster;
61 {
62 	if ((!rogue.armor) || (get_armor_class(rogue.armor) <= 1) ||
63 		(rogue.armor->which_kind == LEATHER)) {
64 		return;
65 	}
66 	if ((rogue.armor->is_protected) || maintain_armor) {
67 		if (monster && (!(monster->m_flags & RUST_VANISHED))) {
68 			message("the rust vanishes instantly", 0);
69 			monster->m_flags |= RUST_VANISHED;
70 		}
71 	} else {
72 		rogue.armor->d_enchant--;
73 		message("your armor weakens", 0);
74 		print_stats(STAT_ARMOR);
75 	}
76 }
77 
78 freeze(monster)
79 object *monster;
80 {
81 	short freeze_percent = 99;
82 	short i, n;
83 
84 	if (rand_percent(12)) {
85 		return;
86 	}
87 	freeze_percent -= (rogue.str_current+(rogue.str_current / 2));
88 	freeze_percent -= ((rogue.exp + ring_exp) * 4);
89 	freeze_percent -= (get_armor_class(rogue.armor) * 5);
90 	freeze_percent -= (rogue.hp_max / 3);
91 
92 	if (freeze_percent > 10) {
93 		monster->m_flags |= FREEZING_ROGUE;
94 		message("you are frozen", 1);
95 
96 		n = get_rand(4, 8);
97 		for (i = 0; i < n; i++) {
98 			mv_mons();
99 		}
100 		if (rand_percent(freeze_percent)) {
101 			for (i = 0; i < 50; i++) {
102 				mv_mons();
103 			}
104 			killed_by((object *)0, HYPOTHERMIA);
105 		}
106 		message(you_can_move_again, 1);
107 		monster->m_flags &= (~FREEZING_ROGUE);
108 	}
109 }
110 
111 steal_gold(monster)
112 object *monster;
113 {
114 	int amount;
115 
116 	if ((rogue.gold <= 0) || rand_percent(10)) {
117 		return;
118 	}
119 
120 	amount = get_rand((cur_level * 10), (cur_level * 30));
121 
122 	if (amount > rogue.gold) {
123 		amount = rogue.gold;
124 	}
125 	rogue.gold -= amount;
126 	message("your purse feels lighter", 0);
127 	print_stats(STAT_GOLD);
128 	disappear(monster);
129 }
130 
131 steal_item(monster)
132 object *monster;
133 {
134 	object *obj;
135 	short i, n, t;
136 	char desc[80];
137 	boolean has_something = 0;
138 
139 	if (rand_percent(15)) {
140 		return;
141 	}
142 	obj = rogue.pack.next_object;
143 
144 	if (!obj) {
145 		goto DSPR;
146 	}
147 	while (obj) {
148 		if (!(obj->in_use_flags & BEING_USED)) {
149 			has_something = 1;
150 			break;
151 		}
152 		obj = obj->next_object;
153 	}
154 	if (!has_something) {
155 		goto DSPR;
156 	}
157 	n = get_rand(0, MAX_PACK_COUNT);
158 	obj = rogue.pack.next_object;
159 
160 	for (i = 0; i <= n; i++) {
161 		obj = obj->next_object;
162 		while ((!obj) || (obj->in_use_flags & BEING_USED)) {
163 			if (!obj) {
164 				obj = rogue.pack.next_object;
165 			} else {
166 				obj = obj->next_object;
167 			}
168 		}
169 	}
170 	(void) strcpy(desc, "she stole ");
171 	if (obj->what_is != WEAPON) {
172 		t = obj->quantity;
173 		obj->quantity = 1;
174 	}
175 	get_desc(obj, desc+10);
176 	message(desc, 0);
177 
178 	obj->quantity = ((obj->what_is != WEAPON) ? t : 1);
179 
180 	vanish(obj, 0, &rogue.pack);
181 DSPR:
182 	disappear(monster);
183 }
184 
185 disappear(monster)
186 object *monster;
187 {
188 	short row, col;
189 
190 	row = monster->row;
191 	col = monster->col;
192 
193 	dungeon[row][col] &= ~MONSTER;
194 	if (rogue_can_see(row, col)) {
195 		mvaddch(row, col, get_dungeon_char(row, col));
196 	}
197 	take_from_pack(monster, &level_monsters);
198 	free_object(monster);
199 	mon_disappeared = 1;
200 }
201 
202 cough_up(monster)
203 object *monster;
204 {
205 	object *obj;
206 	short row, col, i, n;
207 
208 	if (cur_level < max_level) {
209 		return;
210 	}
211 
212 	if (monster->m_flags & STEALS_GOLD) {
213 		obj = alloc_object();
214 		obj->what_is = GOLD;
215 		obj->quantity = get_rand((cur_level * 15), (cur_level * 30));
216 	} else {
217 		if (!rand_percent((int) monster->drop_percent)) {
218 			return;
219 		}
220 		obj = gr_object();
221 	}
222 	row = monster->row;
223 	col = monster->col;
224 
225 	for (n = 0; n <= 5; n++) {
226 		for (i = -n; i <= n; i++) {
227 			if (try_to_cough(row+n, col+i, obj)) {
228 				return;
229 			}
230 			if (try_to_cough(row-n, col+i, obj)) {
231 				return;
232 			}
233 		}
234 		for (i = -n; i <= n; i++) {
235 			if (try_to_cough(row+i, col-n, obj)) {
236 				return;
237 			}
238 			if (try_to_cough(row+i, col+n, obj)) {
239 				return;
240 			}
241 		}
242 	}
243 	free_object(obj);
244 }
245 
246 try_to_cough(row, col, obj)
247 short row, col;
248 object *obj;
249 {
250 	if ((row < MIN_ROW) || (row > (DROWS-2)) || (col < 0) || (col>(DCOLS-1))) {
251 		return(0);
252 	}
253 	if ((!(dungeon[row][col] & (OBJECT | STAIRS | TRAP))) &&
254 		(dungeon[row][col] & (TUNNEL | FLOOR | DOOR))) {
255 		place_at(obj, row, col);
256 		if (((row != rogue.row) || (col != rogue.col)) &&
257 			(!(dungeon[row][col] & MONSTER))) {
258 			mvaddch(row, col, get_dungeon_char(row, col));
259 		}
260 		return(1);
261 	}
262 	return(0);
263 }
264 
265 seek_gold(monster)
266 object *monster;
267 {
268 	short i, j, rn, s;
269 
270 	if ((rn = get_room_number(monster->row, monster->col)) < 0) {
271 		return(0);
272 	}
273 	for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
274 		for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
275 			if ((gold_at(i, j)) && !(dungeon[i][j] & MONSTER)) {
276 				monster->m_flags |= CAN_FLIT;
277 				s = mon_can_go(monster, i, j);
278 				monster->m_flags &= (~CAN_FLIT);
279 				if (s) {
280 					move_mon_to(monster, i, j);
281 					monster->m_flags |= ASLEEP;
282 					monster->m_flags &= (~(WAKENS | SEEKS_GOLD));
283 					return(1);
284 				}
285 				monster->m_flags &= (~SEEKS_GOLD);
286 				monster->m_flags |= CAN_FLIT;
287 				mv_1_monster(monster, i, j);
288 				monster->m_flags &= (~CAN_FLIT);
289 				monster->m_flags |= SEEKS_GOLD;
290 				return(1);
291 			}
292 		}
293 	}
294 	return(0);
295 }
296 
297 gold_at(row, col)
298 short row, col;
299 {
300 	if (dungeon[row][col] & OBJECT) {
301 		object *obj;
302 
303 		if ((obj = object_at(&level_objects, row, col)) &&
304 				(obj->what_is == GOLD)) {
305 			return(1);
306 		}
307 	}
308 	return(0);
309 }
310 
311 check_gold_seeker(monster)
312 object *monster;
313 {
314 	monster->m_flags &= (~SEEKS_GOLD);
315 }
316 
317 check_imitator(monster)
318 object *monster;
319 {
320 	char msg[80];
321 
322 	if (monster->m_flags & IMITATES) {
323 		wake_up(monster);
324 		if (!blind) {
325 			mvaddch(monster->row, monster->col,
326 					get_dungeon_char(monster->row, monster->col));
327 			check_message();
328 			sprintf(msg, "wait, that's a %s!", mon_name(monster));
329 			message(msg, 1);
330 		}
331 		return(1);
332 	}
333 	return(0);
334 }
335 
336 imitating(row, col)
337 register short row, col;
338 {
339 	if (dungeon[row][col] & MONSTER) {
340 		object *object_at(), *monster;
341 
342 		if (monster = object_at(&level_monsters, row, col)) {
343 			if (monster->m_flags & IMITATES) {
344 				return(1);
345 			}
346 		}
347 	}
348 	return(0);
349 }
350 
351 sting(monster)
352 object *monster;
353 {
354 	short sting_chance = 35;
355 	char msg[80];
356 
357 	if ((rogue.str_current <= 3) || sustain_strength) {
358 		return;
359 	}
360 	sting_chance += (6 * (6 - get_armor_class(rogue.armor)));
361 
362 	if ((rogue.exp + ring_exp) > 8) {
363 		sting_chance -= (6 * ((rogue.exp + ring_exp) - 8));
364 	}
365 	if (rand_percent(sting_chance)) {
366 		sprintf(msg, "the %s's bite has weakened you",
367 		mon_name(monster));
368 		message(msg, 0);
369 		rogue.str_current--;
370 		print_stats(STAT_STRENGTH);
371 	}
372 }
373 
374 drop_level()
375 {
376 	int hp;
377 
378 	if (rand_percent(80) || (rogue.exp <= 5)) {
379 		return;
380 	}
381 	rogue.exp_points = level_points[rogue.exp-2] - get_rand(9, 29);
382 	rogue.exp -= 2;
383 	hp = hp_raise();
384 	if ((rogue.hp_current -= hp) <= 0) {
385 		rogue.hp_current = 1;
386 	}
387 	if ((rogue.hp_max -= hp) <= 0) {
388 		rogue.hp_max = 1;
389 	}
390 	add_exp(1, 0);
391 }
392 
393 drain_life()
394 {
395 	short n;
396 
397 	if (rand_percent(60) || (rogue.hp_max <= 30) || (rogue.hp_current < 10)) {
398 		return;
399 	}
400 	n = get_rand(1, 3);		/* 1 Hp, 2 Str, 3 both */
401 
402 	if ((n != 2) || (!sustain_strength)) {
403 		message("you feel weaker", 0);
404 	}
405 	if (n != 2) {
406 		rogue.hp_max--;
407 		rogue.hp_current--;
408 		less_hp++;
409 	}
410 	if (n != 1) {
411 		if ((rogue.str_current > 3) && (!sustain_strength)) {
412 			rogue.str_current--;
413 			if (coin_toss()) {
414 				rogue.str_max--;
415 			}
416 		}
417 	}
418 	print_stats((STAT_STRENGTH | STAT_HP));
419 }
420 
421 m_confuse(monster)
422 object *monster;
423 {
424 	char msg[80];
425 
426 	if (!rogue_can_see(monster->row, monster->col)) {
427 		return(0);
428 	}
429 	if (rand_percent(45)) {
430 		monster->m_flags &= (~CONFUSES);	/* will not confuse the rogue */
431 		return(0);
432 	}
433 	if (rand_percent(55)) {
434 		monster->m_flags &= (~CONFUSES);
435 		sprintf(msg, "the gaze of the %s has confused you", mon_name(monster));
436 		message(msg, 1);
437 		cnfs();
438 		return(1);
439 	}
440 	return(0);
441 }
442 
443 flame_broil(monster)
444 object *monster;
445 {
446 	short row, col, dir;
447 
448 	if ((!mon_sees(monster, rogue.row, rogue.col)) || coin_toss()) {
449 		return(0);
450 	}
451 	row = rogue.row - monster->row;
452 	col = rogue.col - monster->col;
453 	if (row < 0) {
454 		row = -row;
455 	}
456 	if (col < 0) {
457 		col = -col;
458 	}
459 	if (((row != 0) && (col != 0) && (row != col)) ||
460 		((row > 7) || (col > 7))) {
461 		return(0);
462 	}
463 	dir = get_dir(monster->row, monster->col, row, col);
464 	bounce(FIRE, dir, monster->row, monster->col, 0);
465 
466 	return(1);
467 }
468 
469 get_dir(srow, scol, drow, dcol)
470 short srow, scol, drow, dcol;
471 {
472 	if (srow == drow) {
473 		if (scol < dcol) {
474 			return(RIGHT);
475 		} else {
476 			return(LEFT);
477 		}
478 	}
479 	if (scol == dcol) {
480 		if (srow < drow) {
481 			return(DOWN);
482 		} else {
483 			return(UPWARD);
484 		}
485 	}
486 	if ((srow > drow) && (scol > dcol)) {
487 		return(UPLEFT);
488 	}
489 	if ((srow < drow) && (scol < dcol)) {
490 		return(DOWNRIGHT);
491 	}
492 	if ((srow < drow) && (scol > dcol)) {
493 		return(DOWNLEFT);
494 	}
495 	/*if ((srow > drow) && (scol < dcol)) {*/
496 		return(UPRIGHT);
497 	/*}*/
498 }
499