xref: /csrg-svn/games/rogue/spec_hit.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[] = "@(#)spec_hit.c	8.1 (Berkeley) 05/31/93";
1336704Sbostic #endif /* not lint */
1436704Sbostic 
1536704Sbostic /*
1632689Sbostic  * special_hit.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 short less_hp = 0;
3032689Sbostic boolean being_held;
3132689Sbostic 
3232689Sbostic extern short cur_level, max_level, blind, levitate, ring_exp;
3332689Sbostic extern long level_points[];
3432689Sbostic extern boolean detect_monster, mon_disappeared;
3532689Sbostic extern boolean sustain_strength, maintain_armor;
3632689Sbostic extern char *you_can_move_again;
3732689Sbostic 
special_hit(monster)3832689Sbostic special_hit(monster)
3932689Sbostic object *monster;
4032689Sbostic {
4132689Sbostic 	if ((monster->m_flags & CONFUSED) && rand_percent(66)) {
4232689Sbostic 		return;
4332689Sbostic 	}
4432689Sbostic 	if (monster->m_flags & RUSTS) {
4532689Sbostic 		rust(monster);
4632689Sbostic 	}
4732689Sbostic 	if ((monster->m_flags & HOLDS) && !levitate) {
4832689Sbostic 		being_held = 1;
4932689Sbostic 	}
5032689Sbostic 	if (monster->m_flags & FREEZES) {
5132689Sbostic 		freeze(monster);
5232689Sbostic 	}
5332689Sbostic 	if (monster->m_flags & STINGS) {
5432689Sbostic 		sting(monster);
5532689Sbostic 	}
5632689Sbostic 	if (monster->m_flags & DRAINS_LIFE) {
5732689Sbostic 		drain_life();
5832689Sbostic 	}
5932689Sbostic 	if (monster->m_flags & DROPS_LEVEL) {
6032689Sbostic 		drop_level();
6132689Sbostic 	}
6232689Sbostic 	if (monster->m_flags & STEALS_GOLD) {
6332689Sbostic 		steal_gold(monster);
6432689Sbostic 	} else if (monster->m_flags & STEALS_ITEM) {
6532689Sbostic 		steal_item(monster);
6632689Sbostic 	}
6732689Sbostic }
6832689Sbostic 
rust(monster)6932689Sbostic rust(monster)
7032689Sbostic object *monster;
7132689Sbostic {
7232689Sbostic 	if ((!rogue.armor) || (get_armor_class(rogue.armor) <= 1) ||
7332689Sbostic 		(rogue.armor->which_kind == LEATHER)) {
7432689Sbostic 		return;
7532689Sbostic 	}
7632689Sbostic 	if ((rogue.armor->is_protected) || maintain_armor) {
7732689Sbostic 		if (monster && (!(monster->m_flags & RUST_VANISHED))) {
7832689Sbostic 			message("the rust vanishes instantly", 0);
7932689Sbostic 			monster->m_flags |= RUST_VANISHED;
8032689Sbostic 		}
8132689Sbostic 	} else {
8232689Sbostic 		rogue.armor->d_enchant--;
8332689Sbostic 		message("your armor weakens", 0);
8432689Sbostic 		print_stats(STAT_ARMOR);
8532689Sbostic 	}
8632689Sbostic }
8732689Sbostic 
freeze(monster)8832689Sbostic freeze(monster)
8932689Sbostic object *monster;
9032689Sbostic {
9132689Sbostic 	short freeze_percent = 99;
9232689Sbostic 	short i, n;
9332689Sbostic 
9432689Sbostic 	if (rand_percent(12)) {
9532689Sbostic 		return;
9632689Sbostic 	}
9732689Sbostic 	freeze_percent -= (rogue.str_current+(rogue.str_current / 2));
9832689Sbostic 	freeze_percent -= ((rogue.exp + ring_exp) * 4);
9932689Sbostic 	freeze_percent -= (get_armor_class(rogue.armor) * 5);
10032689Sbostic 	freeze_percent -= (rogue.hp_max / 3);
10132689Sbostic 
10232689Sbostic 	if (freeze_percent > 10) {
10332689Sbostic 		monster->m_flags |= FREEZING_ROGUE;
10432689Sbostic 		message("you are frozen", 1);
10532689Sbostic 
10632689Sbostic 		n = get_rand(4, 8);
10732689Sbostic 		for (i = 0; i < n; i++) {
10832689Sbostic 			mv_mons();
10932689Sbostic 		}
11032689Sbostic 		if (rand_percent(freeze_percent)) {
11132689Sbostic 			for (i = 0; i < 50; i++) {
11232689Sbostic 				mv_mons();
11332689Sbostic 			}
11432689Sbostic 			killed_by((object *)0, HYPOTHERMIA);
11532689Sbostic 		}
11632689Sbostic 		message(you_can_move_again, 1);
11732689Sbostic 		monster->m_flags &= (~FREEZING_ROGUE);
11832689Sbostic 	}
11932689Sbostic }
12032689Sbostic 
steal_gold(monster)12132689Sbostic steal_gold(monster)
12232689Sbostic object *monster;
12332689Sbostic {
12432689Sbostic 	int amount;
12532689Sbostic 
12632689Sbostic 	if ((rogue.gold <= 0) || rand_percent(10)) {
12732689Sbostic 		return;
12832689Sbostic 	}
12932689Sbostic 
13032689Sbostic 	amount = get_rand((cur_level * 10), (cur_level * 30));
13132689Sbostic 
13232689Sbostic 	if (amount > rogue.gold) {
13332689Sbostic 		amount = rogue.gold;
13432689Sbostic 	}
13532689Sbostic 	rogue.gold -= amount;
13632689Sbostic 	message("your purse feels lighter", 0);
13732689Sbostic 	print_stats(STAT_GOLD);
13832689Sbostic 	disappear(monster);
13932689Sbostic }
14032689Sbostic 
steal_item(monster)14132689Sbostic steal_item(monster)
14232689Sbostic object *monster;
14332689Sbostic {
14432689Sbostic 	object *obj;
14532689Sbostic 	short i, n, t;
14632689Sbostic 	char desc[80];
14732689Sbostic 	boolean has_something = 0;
14832689Sbostic 
14932689Sbostic 	if (rand_percent(15)) {
15032689Sbostic 		return;
15132689Sbostic 	}
15232689Sbostic 	obj = rogue.pack.next_object;
15332689Sbostic 
15432689Sbostic 	if (!obj) {
15532689Sbostic 		goto DSPR;
15632689Sbostic 	}
15732689Sbostic 	while (obj) {
15832689Sbostic 		if (!(obj->in_use_flags & BEING_USED)) {
15932689Sbostic 			has_something = 1;
16032689Sbostic 			break;
16132689Sbostic 		}
16232689Sbostic 		obj = obj->next_object;
16332689Sbostic 	}
16432689Sbostic 	if (!has_something) {
16532689Sbostic 		goto DSPR;
16632689Sbostic 	}
16732689Sbostic 	n = get_rand(0, MAX_PACK_COUNT);
16832689Sbostic 	obj = rogue.pack.next_object;
16932689Sbostic 
17032689Sbostic 	for (i = 0; i <= n; i++) {
17132689Sbostic 		obj = obj->next_object;
17232689Sbostic 		while ((!obj) || (obj->in_use_flags & BEING_USED)) {
17332689Sbostic 			if (!obj) {
17432689Sbostic 				obj = rogue.pack.next_object;
17532689Sbostic 			} else {
17632689Sbostic 				obj = obj->next_object;
17732689Sbostic 			}
17832689Sbostic 		}
17932689Sbostic 	}
18032689Sbostic 	(void) strcpy(desc, "she stole ");
18132689Sbostic 	if (obj->what_is != WEAPON) {
18232689Sbostic 		t = obj->quantity;
18332689Sbostic 		obj->quantity = 1;
18432689Sbostic 	}
18532689Sbostic 	get_desc(obj, desc+10);
18632689Sbostic 	message(desc, 0);
18732689Sbostic 
18832689Sbostic 	obj->quantity = ((obj->what_is != WEAPON) ? t : 1);
18932689Sbostic 
19032689Sbostic 	vanish(obj, 0, &rogue.pack);
19132689Sbostic DSPR:
19232689Sbostic 	disappear(monster);
19332689Sbostic }
19432689Sbostic 
disappear(monster)19532689Sbostic disappear(monster)
19632689Sbostic object *monster;
19732689Sbostic {
19832689Sbostic 	short row, col;
19932689Sbostic 
20032689Sbostic 	row = monster->row;
20132689Sbostic 	col = monster->col;
20232689Sbostic 
20332689Sbostic 	dungeon[row][col] &= ~MONSTER;
20432689Sbostic 	if (rogue_can_see(row, col)) {
20532689Sbostic 		mvaddch(row, col, get_dungeon_char(row, col));
20632689Sbostic 	}
20732689Sbostic 	take_from_pack(monster, &level_monsters);
20832689Sbostic 	free_object(monster);
20932689Sbostic 	mon_disappeared = 1;
21032689Sbostic }
21132689Sbostic 
cough_up(monster)21232689Sbostic cough_up(monster)
21332689Sbostic object *monster;
21432689Sbostic {
21532689Sbostic 	object *obj;
21632689Sbostic 	short row, col, i, n;
21732689Sbostic 
21832689Sbostic 	if (cur_level < max_level) {
21932689Sbostic 		return;
22032689Sbostic 	}
22132689Sbostic 
22232689Sbostic 	if (monster->m_flags & STEALS_GOLD) {
22332689Sbostic 		obj = alloc_object();
22432689Sbostic 		obj->what_is = GOLD;
22532689Sbostic 		obj->quantity = get_rand((cur_level * 15), (cur_level * 30));
22632689Sbostic 	} else {
22732689Sbostic 		if (!rand_percent((int) monster->drop_percent)) {
22832689Sbostic 			return;
22932689Sbostic 		}
23032689Sbostic 		obj = gr_object();
23132689Sbostic 	}
23232689Sbostic 	row = monster->row;
23332689Sbostic 	col = monster->col;
23432689Sbostic 
23532689Sbostic 	for (n = 0; n <= 5; n++) {
23632689Sbostic 		for (i = -n; i <= n; i++) {
23732689Sbostic 			if (try_to_cough(row+n, col+i, obj)) {
23832689Sbostic 				return;
23932689Sbostic 			}
24032689Sbostic 			if (try_to_cough(row-n, col+i, obj)) {
24132689Sbostic 				return;
24232689Sbostic 			}
24332689Sbostic 		}
24432689Sbostic 		for (i = -n; i <= n; i++) {
24532689Sbostic 			if (try_to_cough(row+i, col-n, obj)) {
24632689Sbostic 				return;
24732689Sbostic 			}
24832689Sbostic 			if (try_to_cough(row+i, col+n, obj)) {
24932689Sbostic 				return;
25032689Sbostic 			}
25132689Sbostic 		}
25232689Sbostic 	}
25332689Sbostic 	free_object(obj);
25432689Sbostic }
25532689Sbostic 
try_to_cough(row,col,obj)25632689Sbostic try_to_cough(row, col, obj)
25732689Sbostic short row, col;
25832689Sbostic object *obj;
25932689Sbostic {
26032689Sbostic 	if ((row < MIN_ROW) || (row > (DROWS-2)) || (col < 0) || (col>(DCOLS-1))) {
26132689Sbostic 		return(0);
26232689Sbostic 	}
26332689Sbostic 	if ((!(dungeon[row][col] & (OBJECT | STAIRS | TRAP))) &&
26432689Sbostic 		(dungeon[row][col] & (TUNNEL | FLOOR | DOOR))) {
26532689Sbostic 		place_at(obj, row, col);
26632689Sbostic 		if (((row != rogue.row) || (col != rogue.col)) &&
26732689Sbostic 			(!(dungeon[row][col] & MONSTER))) {
26832689Sbostic 			mvaddch(row, col, get_dungeon_char(row, col));
26932689Sbostic 		}
27032689Sbostic 		return(1);
27132689Sbostic 	}
27232689Sbostic 	return(0);
27332689Sbostic }
27432689Sbostic 
seek_gold(monster)27532689Sbostic seek_gold(monster)
27632689Sbostic object *monster;
27732689Sbostic {
27832689Sbostic 	short i, j, rn, s;
27932689Sbostic 
28032689Sbostic 	if ((rn = get_room_number(monster->row, monster->col)) < 0) {
28132689Sbostic 		return(0);
28232689Sbostic 	}
28332689Sbostic 	for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
28432689Sbostic 		for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
28532689Sbostic 			if ((gold_at(i, j)) && !(dungeon[i][j] & MONSTER)) {
28632689Sbostic 				monster->m_flags |= CAN_FLIT;
28732689Sbostic 				s = mon_can_go(monster, i, j);
28832689Sbostic 				monster->m_flags &= (~CAN_FLIT);
28932689Sbostic 				if (s) {
29032689Sbostic 					move_mon_to(monster, i, j);
29132689Sbostic 					monster->m_flags |= ASLEEP;
29232689Sbostic 					monster->m_flags &= (~(WAKENS | SEEKS_GOLD));
29332689Sbostic 					return(1);
29432689Sbostic 				}
29532689Sbostic 				monster->m_flags &= (~SEEKS_GOLD);
29632689Sbostic 				monster->m_flags |= CAN_FLIT;
29732689Sbostic 				mv_1_monster(monster, i, j);
29832689Sbostic 				monster->m_flags &= (~CAN_FLIT);
29932689Sbostic 				monster->m_flags |= SEEKS_GOLD;
30032689Sbostic 				return(1);
30132689Sbostic 			}
30232689Sbostic 		}
30332689Sbostic 	}
30432689Sbostic 	return(0);
30532689Sbostic }
30632689Sbostic 
gold_at(row,col)30732689Sbostic gold_at(row, col)
30832689Sbostic short row, col;
30932689Sbostic {
31032689Sbostic 	if (dungeon[row][col] & OBJECT) {
31132689Sbostic 		object *obj;
31232689Sbostic 
31332689Sbostic 		if ((obj = object_at(&level_objects, row, col)) &&
31432689Sbostic 				(obj->what_is == GOLD)) {
31532689Sbostic 			return(1);
31632689Sbostic 		}
31732689Sbostic 	}
31832689Sbostic 	return(0);
31932689Sbostic }
32032689Sbostic 
check_gold_seeker(monster)32132689Sbostic check_gold_seeker(monster)
32232689Sbostic object *monster;
32332689Sbostic {
32432689Sbostic 	monster->m_flags &= (~SEEKS_GOLD);
32532689Sbostic }
32632689Sbostic 
check_imitator(monster)32732689Sbostic check_imitator(monster)
32832689Sbostic object *monster;
32932689Sbostic {
33032689Sbostic 	char msg[80];
33132689Sbostic 
33232689Sbostic 	if (monster->m_flags & IMITATES) {
33332689Sbostic 		wake_up(monster);
33432689Sbostic 		if (!blind) {
33532689Sbostic 			mvaddch(monster->row, monster->col,
33632689Sbostic 					get_dungeon_char(monster->row, monster->col));
33732689Sbostic 			check_message();
33832689Sbostic 			sprintf(msg, "wait, that's a %s!", mon_name(monster));
33932689Sbostic 			message(msg, 1);
34032689Sbostic 		}
34132689Sbostic 		return(1);
34232689Sbostic 	}
34332689Sbostic 	return(0);
34432689Sbostic }
34532689Sbostic 
imitating(row,col)34632689Sbostic imitating(row, col)
34732689Sbostic register short row, col;
34832689Sbostic {
34932689Sbostic 	if (dungeon[row][col] & MONSTER) {
35032689Sbostic 		object *object_at(), *monster;
35132689Sbostic 
35232689Sbostic 		if (monster = object_at(&level_monsters, row, col)) {
35332689Sbostic 			if (monster->m_flags & IMITATES) {
35432689Sbostic 				return(1);
35532689Sbostic 			}
35632689Sbostic 		}
35732689Sbostic 	}
35832689Sbostic 	return(0);
35932689Sbostic }
36032689Sbostic 
sting(monster)36132689Sbostic sting(monster)
36232689Sbostic object *monster;
36332689Sbostic {
36432689Sbostic 	short sting_chance = 35;
36532689Sbostic 	char msg[80];
36632689Sbostic 
36732689Sbostic 	if ((rogue.str_current <= 3) || sustain_strength) {
36832689Sbostic 		return;
36932689Sbostic 	}
37032689Sbostic 	sting_chance += (6 * (6 - get_armor_class(rogue.armor)));
37132689Sbostic 
37232689Sbostic 	if ((rogue.exp + ring_exp) > 8) {
37332689Sbostic 		sting_chance -= (6 * ((rogue.exp + ring_exp) - 8));
37432689Sbostic 	}
37532689Sbostic 	if (rand_percent(sting_chance)) {
37632689Sbostic 		sprintf(msg, "the %s's bite has weakened you",
37732689Sbostic 		mon_name(monster));
37832689Sbostic 		message(msg, 0);
37932689Sbostic 		rogue.str_current--;
38032689Sbostic 		print_stats(STAT_STRENGTH);
38132689Sbostic 	}
38232689Sbostic }
38332689Sbostic 
drop_level()38432689Sbostic drop_level()
38532689Sbostic {
38632689Sbostic 	int hp;
38732689Sbostic 
38832689Sbostic 	if (rand_percent(80) || (rogue.exp <= 5)) {
38932689Sbostic 		return;
39032689Sbostic 	}
39132689Sbostic 	rogue.exp_points = level_points[rogue.exp-2] - get_rand(9, 29);
39232689Sbostic 	rogue.exp -= 2;
39332689Sbostic 	hp = hp_raise();
39432689Sbostic 	if ((rogue.hp_current -= hp) <= 0) {
39532689Sbostic 		rogue.hp_current = 1;
39632689Sbostic 	}
39732689Sbostic 	if ((rogue.hp_max -= hp) <= 0) {
39832689Sbostic 		rogue.hp_max = 1;
39932689Sbostic 	}
40032689Sbostic 	add_exp(1, 0);
40132689Sbostic }
40232689Sbostic 
drain_life()40332689Sbostic drain_life()
40432689Sbostic {
40532689Sbostic 	short n;
40632689Sbostic 
40732689Sbostic 	if (rand_percent(60) || (rogue.hp_max <= 30) || (rogue.hp_current < 10)) {
40832689Sbostic 		return;
40932689Sbostic 	}
41032689Sbostic 	n = get_rand(1, 3);		/* 1 Hp, 2 Str, 3 both */
41132689Sbostic 
41232689Sbostic 	if ((n != 2) || (!sustain_strength)) {
41332689Sbostic 		message("you feel weaker", 0);
41432689Sbostic 	}
41532689Sbostic 	if (n != 2) {
41632689Sbostic 		rogue.hp_max--;
41732689Sbostic 		rogue.hp_current--;
41832689Sbostic 		less_hp++;
41932689Sbostic 	}
42032689Sbostic 	if (n != 1) {
42132689Sbostic 		if ((rogue.str_current > 3) && (!sustain_strength)) {
42232689Sbostic 			rogue.str_current--;
42332689Sbostic 			if (coin_toss()) {
42432689Sbostic 				rogue.str_max--;
42532689Sbostic 			}
42632689Sbostic 		}
42732689Sbostic 	}
42832689Sbostic 	print_stats((STAT_STRENGTH | STAT_HP));
42932689Sbostic }
43032689Sbostic 
m_confuse(monster)43132689Sbostic m_confuse(monster)
43232689Sbostic object *monster;
43332689Sbostic {
43432689Sbostic 	char msg[80];
43532689Sbostic 
43632689Sbostic 	if (!rogue_can_see(monster->row, monster->col)) {
43732689Sbostic 		return(0);
43832689Sbostic 	}
43932689Sbostic 	if (rand_percent(45)) {
44032689Sbostic 		monster->m_flags &= (~CONFUSES);	/* will not confuse the rogue */
44132689Sbostic 		return(0);
44232689Sbostic 	}
44332689Sbostic 	if (rand_percent(55)) {
44432689Sbostic 		monster->m_flags &= (~CONFUSES);
44532689Sbostic 		sprintf(msg, "the gaze of the %s has confused you", mon_name(monster));
44632689Sbostic 		message(msg, 1);
44732689Sbostic 		cnfs();
44832689Sbostic 		return(1);
44932689Sbostic 	}
45032689Sbostic 	return(0);
45132689Sbostic }
45232689Sbostic 
flame_broil(monster)45332689Sbostic flame_broil(monster)
45432689Sbostic object *monster;
45532689Sbostic {
45632689Sbostic 	short row, col, dir;
45732689Sbostic 
45832689Sbostic 	if ((!mon_sees(monster, rogue.row, rogue.col)) || coin_toss()) {
45932689Sbostic 		return(0);
46032689Sbostic 	}
46132689Sbostic 	row = rogue.row - monster->row;
46232689Sbostic 	col = rogue.col - monster->col;
46332689Sbostic 	if (row < 0) {
46432689Sbostic 		row = -row;
46532689Sbostic 	}
46632689Sbostic 	if (col < 0) {
46732689Sbostic 		col = -col;
46832689Sbostic 	}
46932689Sbostic 	if (((row != 0) && (col != 0) && (row != col)) ||
47032689Sbostic 		((row > 7) || (col > 7))) {
47132689Sbostic 		return(0);
47232689Sbostic 	}
47332689Sbostic 	dir = get_dir(monster->row, monster->col, row, col);
47432689Sbostic 	bounce(FIRE, dir, monster->row, monster->col, 0);
47532689Sbostic 
47632689Sbostic 	return(1);
47732689Sbostic }
47832689Sbostic 
get_dir(srow,scol,drow,dcol)47932689Sbostic get_dir(srow, scol, drow, dcol)
48032689Sbostic short srow, scol, drow, dcol;
48132689Sbostic {
48232689Sbostic 	if (srow == drow) {
48332689Sbostic 		if (scol < dcol) {
48432689Sbostic 			return(RIGHT);
48532689Sbostic 		} else {
48632689Sbostic 			return(LEFT);
48732689Sbostic 		}
48832689Sbostic 	}
48932689Sbostic 	if (scol == dcol) {
49032689Sbostic 		if (srow < drow) {
49132689Sbostic 			return(DOWN);
49232689Sbostic 		} else {
49332689Sbostic 			return(UPWARD);
49432689Sbostic 		}
49532689Sbostic 	}
49632689Sbostic 	if ((srow > drow) && (scol > dcol)) {
49732689Sbostic 		return(UPLEFT);
49832689Sbostic 	}
49932689Sbostic 	if ((srow < drow) && (scol < dcol)) {
50032689Sbostic 		return(DOWNRIGHT);
50132689Sbostic 	}
50232689Sbostic 	if ((srow < drow) && (scol > dcol)) {
50332689Sbostic 		return(DOWNLEFT);
50432689Sbostic 	}
50532689Sbostic 	/*if ((srow > drow) && (scol < dcol)) {*/
50632689Sbostic 		return(UPRIGHT);
50732689Sbostic 	/*}*/
50832689Sbostic }
509