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