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