xref: /csrg-svn/games/rogue/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  *
842591Sbostic  * %sccs.include.redist.c%
936704Sbostic  */
1036704Sbostic 
1136704Sbostic #ifndef lint
12*60842Sbostic static char sccsid[] = "@(#)hit.c	8.1 (Berkeley) 05/31/93";
1336704Sbostic #endif /* not lint */
1436704Sbostic 
1536704Sbostic /*
1632689Sbostic  * 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 object *fight_monster = 0;
3032689Sbostic char hit_message[80] = "";
3132689Sbostic 
3232689Sbostic extern short halluc, blind, cur_level;
3332689Sbostic extern short add_strength, ring_exp, r_rings;
3432689Sbostic extern boolean being_held, interrupted, wizard, con_mon;
3532689Sbostic 
mon_hit(monster)3632689Sbostic mon_hit(monster)
3732689Sbostic register object *monster;
3832689Sbostic {
3932689Sbostic 	short damage, hit_chance;
4032689Sbostic 	char *mn;
4132689Sbostic 	float minus;
4232689Sbostic 
4332689Sbostic 	if (fight_monster && (monster != fight_monster)) {
4432689Sbostic 		fight_monster = 0;
4532689Sbostic 	}
4632689Sbostic 	monster->trow = NO_ROOM;
4732689Sbostic 	if (cur_level >= (AMULET_LEVEL * 2)) {
4832689Sbostic 		hit_chance = 100;
4932689Sbostic 	} else {
5032689Sbostic 		hit_chance = monster->m_hit_chance;
5132689Sbostic 		hit_chance -= (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
5232689Sbostic 	}
5332689Sbostic 	if (wizard) {
5432689Sbostic 		hit_chance /= 2;
5532689Sbostic 	}
5632689Sbostic 	if (!fight_monster) {
5732689Sbostic 		interrupted = 1;
5832689Sbostic 	}
5932689Sbostic 	mn = mon_name(monster);
6032689Sbostic 
6132689Sbostic 	if (!rand_percent(hit_chance)) {
6232689Sbostic 		if (!fight_monster) {
6332689Sbostic 			sprintf(hit_message + strlen(hit_message), "the %s misses", mn);
6432689Sbostic 			message(hit_message, 1);
6532689Sbostic 			hit_message[0] = 0;
6632689Sbostic 		}
6732689Sbostic 		return;
6832689Sbostic 	}
6932689Sbostic 	if (!fight_monster) {
7032689Sbostic 		sprintf(hit_message + strlen(hit_message), "the %s hit", mn);
7132689Sbostic 		message(hit_message, 1);
7232689Sbostic 		hit_message[0] = 0;
7332689Sbostic 	}
7432689Sbostic 	if (!(monster->m_flags & STATIONARY)) {
7532689Sbostic 		damage = get_damage(monster->m_damage, 1);
7632689Sbostic 		if (cur_level >= (AMULET_LEVEL * 2)) {
7732689Sbostic 			minus = (float) ((AMULET_LEVEL * 2) - cur_level);
7832689Sbostic 		} else {
7932689Sbostic 			minus = (float) get_armor_class(rogue.armor) * 3.00;
8032689Sbostic 			minus = minus/100.00 * (float) damage;
8132689Sbostic 		}
8232689Sbostic 		damage -= (short) minus;
8332689Sbostic 	} else {
8432689Sbostic 		damage = monster->stationary_damage++;
8532689Sbostic 	}
8632689Sbostic 	if (wizard) {
8732689Sbostic 		damage /= 3;
8832689Sbostic 	}
8932689Sbostic 	if (damage > 0) {
9032689Sbostic 		rogue_damage(damage, monster, 0);
9132689Sbostic 	}
9232689Sbostic 	if (monster->m_flags & SPECIAL_HIT) {
9332689Sbostic 		special_hit(monster);
9432689Sbostic 	}
9532689Sbostic }
9632689Sbostic 
rogue_hit(monster,force_hit)9732689Sbostic rogue_hit(monster, force_hit)
9832689Sbostic register object *monster;
9932689Sbostic boolean force_hit;
10032689Sbostic {
10132689Sbostic 	short damage, hit_chance;
10232689Sbostic 
10332689Sbostic 	if (monster) {
10432689Sbostic 		if (check_imitator(monster)) {
10532689Sbostic 			return;
10632689Sbostic 		}
10732689Sbostic 		hit_chance = force_hit ? 100 : get_hit_chance(rogue.weapon);
10832689Sbostic 
10932689Sbostic 		if (wizard) {
11032689Sbostic 			hit_chance *= 2;
11132689Sbostic 		}
11232689Sbostic 		if (!rand_percent(hit_chance)) {
11332689Sbostic 			if (!fight_monster) {
11432689Sbostic 				(void) strcpy(hit_message, "you miss  ");
11532689Sbostic 			}
11632689Sbostic 			goto RET;
11732689Sbostic 		}
11832689Sbostic 		damage = get_weapon_damage(rogue.weapon);
11932689Sbostic 		if (wizard) {
12032689Sbostic 			damage *= 3;
12132689Sbostic 		}
12232689Sbostic 		if (con_mon) {
12332689Sbostic 			s_con_mon(monster);
12432689Sbostic 		}
12532689Sbostic 		if (mon_damage(monster, damage)) {	/* still alive? */
12632689Sbostic 			if (!fight_monster) {
12732689Sbostic 				(void) strcpy(hit_message, "you hit  ");
12832689Sbostic 			}
12932689Sbostic 		}
13032689Sbostic RET:	check_gold_seeker(monster);
13132689Sbostic 		wake_up(monster);
13232689Sbostic 	}
13332689Sbostic }
13432689Sbostic 
rogue_damage(d,monster,other)13532689Sbostic rogue_damage(d, monster, other)
13632689Sbostic short d;
13732689Sbostic object *monster;
13832689Sbostic short other;
13932689Sbostic {
14032689Sbostic 	if (d >= rogue.hp_current) {
14132689Sbostic 		rogue.hp_current = 0;
14232689Sbostic 		print_stats(STAT_HP);
14332689Sbostic 		killed_by(monster, other);
14432689Sbostic 	}
14532689Sbostic 	if (d > 0) {
14632689Sbostic 		rogue.hp_current -= d;
14732689Sbostic 		print_stats(STAT_HP);
14832689Sbostic 	}
14932689Sbostic }
15032689Sbostic 
get_damage(ds,r)15132689Sbostic get_damage(ds, r)
15232689Sbostic char *ds;
15332689Sbostic boolean r;
15432689Sbostic {
15532689Sbostic 	register i = 0, j, n, d, total = 0;
15632689Sbostic 
15732689Sbostic 	while (ds[i]) {
15832689Sbostic 		n = get_number(ds+i);
15932689Sbostic 		while (ds[i++] != 'd') ;
16032689Sbostic 		d = get_number(ds+i);
16132689Sbostic 		while ((ds[i] != '/') && ds[i]) i++;
16232689Sbostic 
16332689Sbostic 		for (j = 0; j < n; j++) {
16432689Sbostic 			if (r) {
16532689Sbostic 				total += get_rand(1, d);
16632689Sbostic 			} else {
16732689Sbostic 				total += d;
16832689Sbostic 			}
16932689Sbostic 		}
17032689Sbostic 		if (ds[i] == '/') {
17132689Sbostic 			i++;
17232689Sbostic 		}
17332689Sbostic 	}
17432689Sbostic 	return(total);
17532689Sbostic }
17632689Sbostic 
get_w_damage(obj)17732689Sbostic get_w_damage(obj)
17832689Sbostic object *obj;
17932689Sbostic {
18032689Sbostic 	char new_damage[12];
18132689Sbostic 	register to_hit, damage;
18232689Sbostic 	register i = 0;
18332689Sbostic 
18432689Sbostic 	if ((!obj) || (obj->what_is != WEAPON)) {
18532689Sbostic 		return(-1);
18632689Sbostic 	}
18732689Sbostic 	to_hit = get_number(obj->damage) + obj->hit_enchant;
18832689Sbostic 	while (obj->damage[i++] != 'd') ;
18932689Sbostic 	damage = get_number(obj->damage + i) + obj->d_enchant;
19032689Sbostic 
19132689Sbostic 	sprintf(new_damage, "%dd%d", to_hit, damage);
19232689Sbostic 
19332689Sbostic 	return(get_damage(new_damage, 1));
19432689Sbostic }
19532689Sbostic 
get_number(s)19632689Sbostic get_number(s)
19732689Sbostic register char *s;
19832689Sbostic {
19932689Sbostic 	register i = 0;
20032689Sbostic 	register total = 0;
20132689Sbostic 
20232689Sbostic 	while ((s[i] >= '0') && (s[i] <= '9')) {
20332689Sbostic 		total = (10 * total) + (s[i] - '0');
20432689Sbostic 		i++;
20532689Sbostic 	}
20632689Sbostic 	return(total);
20732689Sbostic }
20832689Sbostic 
20932689Sbostic long
lget_number(s)21032689Sbostic lget_number(s)
21132689Sbostic char *s;
21232689Sbostic {
21332689Sbostic 	short i = 0;
21432689Sbostic 	long total = 0;
21532689Sbostic 
21632689Sbostic 	while ((s[i] >= '0') && (s[i] <= '9')) {
21732689Sbostic 		total = (10 * total) + (s[i] - '0');
21832689Sbostic 		i++;
21932689Sbostic 	}
22032689Sbostic 	return(total);
22132689Sbostic }
22232689Sbostic 
to_hit(obj)22332689Sbostic to_hit(obj)
22432689Sbostic object *obj;
22532689Sbostic {
22632689Sbostic 	if (!obj) {
22732689Sbostic 		return(1);
22832689Sbostic 	}
22932689Sbostic 	return(get_number(obj->damage) + obj->hit_enchant);
23032689Sbostic }
23132689Sbostic 
damage_for_strength()23232689Sbostic damage_for_strength()
23332689Sbostic {
23432689Sbostic 	short strength;
23532689Sbostic 
23632689Sbostic 	strength = rogue.str_current + add_strength;
23732689Sbostic 
23832689Sbostic 	if (strength <= 6) {
23932689Sbostic 		return(strength-5);
24032689Sbostic 	}
24132689Sbostic 	if (strength <= 14) {
24232689Sbostic 		return(1);
24332689Sbostic 	}
24432689Sbostic 	if (strength <= 17) {
24532689Sbostic 		return(3);
24632689Sbostic 	}
24732689Sbostic 	if (strength <= 18) {
24832689Sbostic 		return(4);
24932689Sbostic 	}
25032689Sbostic 	if (strength <= 20) {
25132689Sbostic 		return(5);
25232689Sbostic 	}
25332689Sbostic 	if (strength <= 21) {
25432689Sbostic 		return(6);
25532689Sbostic 	}
25632689Sbostic 	if (strength <= 30) {
25732689Sbostic 		return(7);
25832689Sbostic 	}
25932689Sbostic 	return(8);
26032689Sbostic }
26132689Sbostic 
mon_damage(monster,damage)26232689Sbostic mon_damage(monster, damage)
26332689Sbostic object *monster;
26432689Sbostic short damage;
26532689Sbostic {
26632689Sbostic 	char *mn;
26732689Sbostic 	short row, col;
26832689Sbostic 
26932689Sbostic 	monster->hp_to_kill -= damage;
27032689Sbostic 
27132689Sbostic 	if (monster->hp_to_kill <= 0) {
27232689Sbostic 		row = monster->row;
27332689Sbostic 		col = monster->col;
27432689Sbostic 		dungeon[row][col] &= ~MONSTER;
27532689Sbostic 		mvaddch(row, col, (int) get_dungeon_char(row, col));
27632689Sbostic 
27732689Sbostic 		fight_monster = 0;
27832689Sbostic 		cough_up(monster);
27932689Sbostic 		mn = mon_name(monster);
28032689Sbostic 		sprintf(hit_message+strlen(hit_message), "defeated the %s", mn);
28132689Sbostic 		message(hit_message, 1);
28232689Sbostic 		hit_message[0] = 0;
28332689Sbostic 		add_exp(monster->kill_exp, 1);
28432689Sbostic 		take_from_pack(monster, &level_monsters);
28532689Sbostic 
28632689Sbostic 		if (monster->m_flags & HOLDS) {
28732689Sbostic 			being_held = 0;
28832689Sbostic 		}
28932689Sbostic 		free_object(monster);
29032689Sbostic 		return(0);
29132689Sbostic 	}
29232689Sbostic 	return(1);
29332689Sbostic }
29432689Sbostic 
fight(to_the_death)29532689Sbostic fight(to_the_death)
29632689Sbostic boolean to_the_death;
29732689Sbostic {
29832689Sbostic 	short ch, c, d;
29932689Sbostic 	short row, col;
30032689Sbostic 	boolean first_miss = 1;
30132689Sbostic 	short possible_damage;
30232689Sbostic 	object *monster;
30332689Sbostic 
30432689Sbostic 	while (!is_direction(ch = rgetchar(), &d)) {
30532689Sbostic 		sound_bell();
30632689Sbostic 		if (first_miss) {
30732689Sbostic 			message("direction?", 0);
30832689Sbostic 			first_miss = 0;
30932689Sbostic 		}
31032689Sbostic 	}
31132689Sbostic 	check_message();
31232689Sbostic 	if (ch == CANCEL) {
31332689Sbostic 		return;
31432689Sbostic 	}
31532689Sbostic 	row = rogue.row; col = rogue.col;
31632689Sbostic 	get_dir_rc(d, &row, &col, 0);
31732689Sbostic 
31832689Sbostic 	c = mvinch(row, col);
31932689Sbostic 	if (((c < 'A') || (c > 'Z')) ||
32032689Sbostic 		(!can_move(rogue.row, rogue.col, row, col))) {
32132689Sbostic 		message("I see no monster there", 0);
32232689Sbostic 		return;
32332689Sbostic 	}
32432689Sbostic 	if (!(fight_monster = object_at(&level_monsters, row, col))) {
32532689Sbostic 		return;
32632689Sbostic 	}
32732689Sbostic 	if (!(fight_monster->m_flags & STATIONARY)) {
32832689Sbostic 		possible_damage = ((get_damage(fight_monster->m_damage, 0) * 2) / 3);
32932689Sbostic 	} else {
33032689Sbostic 		possible_damage = fight_monster->stationary_damage - 1;
33132689Sbostic 	}
33232689Sbostic 	while (fight_monster) {
33332689Sbostic 		(void) one_move_rogue(ch, 0);
33432689Sbostic 		if (((!to_the_death) && (rogue.hp_current <= possible_damage)) ||
33532689Sbostic 			interrupted || (!(dungeon[row][col] & MONSTER))) {
33632689Sbostic 			fight_monster = 0;
33732689Sbostic 		} else {
33832689Sbostic 			monster = object_at(&level_monsters, row, col);
33932689Sbostic 			if (monster != fight_monster) {
34032689Sbostic 				fight_monster = 0;
34132689Sbostic 			}
34232689Sbostic 		}
34332689Sbostic 	}
34432689Sbostic }
34532689Sbostic 
get_dir_rc(dir,row,col,allow_off_screen)34632689Sbostic get_dir_rc(dir, row, col, allow_off_screen)
34732689Sbostic short dir;
34832689Sbostic short *row, *col;
34932689Sbostic short allow_off_screen;
35032689Sbostic {
35132689Sbostic 	switch(dir) {
35232689Sbostic 	case LEFT:
35332689Sbostic 		if (allow_off_screen || (*col > 0)) {
35432689Sbostic 			(*col)--;
35532689Sbostic 		}
35632689Sbostic 		break;
35732689Sbostic 	case DOWN:
35832689Sbostic 		if (allow_off_screen || (*row < (DROWS-2))) {
35932689Sbostic 			(*row)++;
36032689Sbostic 		}
36132689Sbostic 		break;
36232689Sbostic 	case UPWARD:
36332689Sbostic 		if (allow_off_screen || (*row > MIN_ROW)) {
36432689Sbostic 			(*row)--;
36532689Sbostic 		}
36632689Sbostic 		break;
36732689Sbostic 	case RIGHT:
36832689Sbostic 		if (allow_off_screen || (*col < (DCOLS-1))) {
36932689Sbostic 			(*col)++;
37032689Sbostic 		}
37132689Sbostic 		break;
37232689Sbostic 	case UPLEFT:
37332689Sbostic 		if (allow_off_screen || ((*row > MIN_ROW) && (*col > 0))) {
37432689Sbostic 			(*row)--;
37532689Sbostic 			(*col)--;
37632689Sbostic 		}
37732689Sbostic 		break;
37832689Sbostic 	case UPRIGHT:
37932689Sbostic 		if (allow_off_screen || ((*row > MIN_ROW) && (*col < (DCOLS-1)))) {
38032689Sbostic 			(*row)--;
38132689Sbostic 			(*col)++;
38232689Sbostic 		}
38332689Sbostic 		break;
38432689Sbostic 	case DOWNRIGHT:
38532689Sbostic 		if (allow_off_screen || ((*row < (DROWS-2)) && (*col < (DCOLS-1)))) {
38632689Sbostic 			(*row)++;
38732689Sbostic 			(*col)++;
38832689Sbostic 		}
38932689Sbostic 		break;
39032689Sbostic 	case DOWNLEFT:
39132689Sbostic 		if (allow_off_screen || ((*row < (DROWS-2)) && (*col > 0))) {
39232689Sbostic 			(*row)++;
39332689Sbostic 			(*col)--;
39432689Sbostic 		}
39532689Sbostic 		break;
39632689Sbostic 	}
39732689Sbostic }
39832689Sbostic 
get_hit_chance(weapon)39932689Sbostic get_hit_chance(weapon)
40032689Sbostic object *weapon;
40132689Sbostic {
40232689Sbostic 	short hit_chance;
40332689Sbostic 
40432689Sbostic 	hit_chance = 40;
40532689Sbostic 	hit_chance += 3 * to_hit(weapon);
40632689Sbostic 	hit_chance += (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
40732689Sbostic 	return(hit_chance);
40832689Sbostic }
40932689Sbostic 
get_weapon_damage(weapon)41032689Sbostic get_weapon_damage(weapon)
41132689Sbostic object *weapon;
41232689Sbostic {
41332689Sbostic 	short damage;
41432689Sbostic 
41532689Sbostic 	damage = get_w_damage(weapon);
41632689Sbostic 	damage += damage_for_strength();
41732689Sbostic 	damage += ((((rogue.exp + ring_exp) - r_rings) + 1) / 2);
41832689Sbostic 	return(damage);
41932689Sbostic }
42032689Sbostic 
s_con_mon(monster)42132689Sbostic s_con_mon(monster)
42232689Sbostic object *monster;
42332689Sbostic {
42432689Sbostic 	if (con_mon) {
42532689Sbostic 		monster->m_flags |= CONFUSED;
42632689Sbostic 		monster->moves_confused += get_rand(12, 22);
42732689Sbostic 		message("the monster appears confused", 0);
42832689Sbostic 		con_mon = 0;
42932689Sbostic 	}
43032689Sbostic }
431