Home | History | Annotate | Line # | Download | only in rogue
hit.c revision 1.9
      1 /*	$NetBSD: hit.c,v 1.9 2008/01/14 00:23:51 dholland Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Timothy C. Stoehr.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 #ifndef lint
     37 #if 0
     38 static char sccsid[] = "@(#)hit.c	8.1 (Berkeley) 5/31/93";
     39 #else
     40 __RCSID("$NetBSD: hit.c,v 1.9 2008/01/14 00:23:51 dholland Exp $");
     41 #endif
     42 #endif /* not lint */
     43 
     44 /*
     45  * hit.c
     46  *
     47  * This source herein may be modified and/or distributed by anybody who
     48  * so desires, with the following restrictions:
     49  *    1.)  No portion of this notice shall be removed.
     50  *    2.)  Credit shall not be taken for the creation of this source.
     51  *    3.)  This code is not to be traded, sold, or used for personal
     52  *         gain or profit.
     53  *
     54  */
     55 
     56 #include "rogue.h"
     57 
     58 object *fight_monster = 0;
     59 char hit_message[HIT_MESSAGE_SIZE] = "";
     60 
     61 void
     62 mon_hit(monster)
     63 	object *monster;
     64 {
     65 	short damage, hit_chance;
     66 	const char *mn;
     67 	float minus;
     68 
     69 	if (fight_monster && (monster != fight_monster)) {
     70 		fight_monster = 0;
     71 	}
     72 	monster->trow = NO_ROOM;
     73 	if (cur_level >= (AMULET_LEVEL * 2)) {
     74 		hit_chance = 100;
     75 	} else {
     76 		hit_chance = monster->m_hit_chance;
     77 		hit_chance -= (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
     78 	}
     79 	if (wizard) {
     80 		hit_chance /= 2;
     81 	}
     82 	if (!fight_monster) {
     83 		interrupted = 1;
     84 	}
     85 	mn = mon_name(monster);
     86 
     87 	if (!rand_percent(hit_chance)) {
     88 		if (!fight_monster) {
     89 			messagef(1, "%sthe %s misses", hit_message, mn);
     90 			hit_message[0] = 0;
     91 		}
     92 		return;
     93 	}
     94 	if (!fight_monster) {
     95 		messagef(1, "%sthe %s hit", hit_message, mn);
     96 		hit_message[0] = 0;
     97 	}
     98 	if (!(monster->m_flags & STATIONARY)) {
     99 		damage = get_damage(monster->m_damage, 1);
    100 		if (cur_level >= (AMULET_LEVEL * 2)) {
    101 			minus = (float)((AMULET_LEVEL * 2) - cur_level);
    102 		} else {
    103 			minus = (float)get_armor_class(rogue.armor) * 3.00;
    104 			minus = minus/100.00 * (float)damage;
    105 		}
    106 		damage -= (short)minus;
    107 	} else {
    108 		damage = monster->stationary_damage++;
    109 	}
    110 	if (wizard) {
    111 		damage /= 3;
    112 	}
    113 	if (damage > 0) {
    114 		rogue_damage(damage, monster, 0);
    115 	}
    116 	if (monster->m_flags & SPECIAL_HIT) {
    117 		special_hit(monster);
    118 	}
    119 }
    120 
    121 void
    122 rogue_hit(monster, force_hit)
    123 	object *monster;
    124 	boolean force_hit;
    125 {
    126 	short damage, hit_chance;
    127 
    128 	if (monster) {
    129 		if (check_imitator(monster)) {
    130 			return;
    131 		}
    132 		hit_chance = force_hit ? 100 : get_hit_chance(rogue.weapon);
    133 
    134 		if (wizard) {
    135 			hit_chance *= 2;
    136 		}
    137 		if (!rand_percent(hit_chance)) {
    138 			if (!fight_monster) {
    139 				(void)strlcpy(hit_message, "you miss  ",
    140 					       sizeof(hit_message));
    141 			}
    142 			goto RET;
    143 		}
    144 		damage = get_weapon_damage(rogue.weapon);
    145 		if (wizard) {
    146 			damage *= 3;
    147 		}
    148 		if (con_mon) {
    149 			s_con_mon(monster);
    150 		}
    151 		if (mon_damage(monster, damage)) {	/* still alive? */
    152 			if (!fight_monster) {
    153 				(void)strlcpy(hit_message, "you hit  ",
    154 					       sizeof(hit_message));
    155 			}
    156 		}
    157 RET:	check_gold_seeker(monster);
    158 		wake_up(monster);
    159 	}
    160 }
    161 
    162 void
    163 rogue_damage(d, monster, other)
    164 	short d;
    165 	object *monster;
    166 	short other;
    167 {
    168 	if (d >= rogue.hp_current) {
    169 		rogue.hp_current = 0;
    170 		print_stats(STAT_HP);
    171 		killed_by(monster, other);
    172 	}
    173 	if (d > 0) {
    174 		rogue.hp_current -= d;
    175 		print_stats(STAT_HP);
    176 	}
    177 }
    178 
    179 int
    180 get_damage(ds, r)
    181 	const char *ds;
    182 	boolean r;
    183 {
    184 	int i = 0, j, n, d, total = 0;
    185 
    186 	while (ds[i]) {
    187 		n = get_number(ds+i);
    188 		while ((ds[i] != 'd') && ds[i]) {
    189 			i++;
    190 		}
    191 		if (ds[i] == 'd') {
    192 			i++;
    193 		}
    194 
    195 		d = get_number(ds+i);
    196 		while ((ds[i] != '/') && ds[i]) {
    197 			i++;
    198 		}
    199 		if (ds[i] == '/') {
    200 			i++;
    201 		}
    202 
    203 		for (j = 0; j < n; j++) {
    204 			if (r) {
    205 				total += get_rand(1, d);
    206 			} else {
    207 				total += d;
    208 			}
    209 		}
    210 	}
    211 	return(total);
    212 }
    213 
    214 int
    215 get_w_damage(obj)
    216 	const object *obj;
    217 {
    218 	char new_damage[32];
    219 	int tmp_to_hit, tmp_damage;
    220 	int i = 0;
    221 
    222 	if ((!obj) || (obj->what_is != WEAPON)) {
    223 		return(-1);
    224 	}
    225 	tmp_to_hit = get_number(obj->damage) + obj->hit_enchant;
    226 	while ((obj->damage[i] != 'd') && obj->damage[i]) {
    227 		i++;
    228 	}
    229 	if (obj->damage[i] == 'd') {
    230 		i++;
    231 	}
    232 	tmp_damage = get_number(obj->damage + i) + obj->d_enchant;
    233 
    234 	snprintf(new_damage, sizeof(new_damage), "%dd%d",
    235 		tmp_to_hit, tmp_damage);
    236 
    237 	return(get_damage(new_damage, 1));
    238 }
    239 
    240 int
    241 get_number(s)
    242 	const char *s;
    243 {
    244 	int i = 0;
    245 	int total = 0;
    246 
    247 	while ((s[i] >= '0') && (s[i] <= '9')) {
    248 		total = (10 * total) + (s[i] - '0');
    249 		i++;
    250 	}
    251 	return(total);
    252 }
    253 
    254 long
    255 lget_number(s)
    256 	const char *s;
    257 {
    258 	short i = 0;
    259 	long total = 0;
    260 
    261 	while ((s[i] >= '0') && (s[i] <= '9')) {
    262 		total = (10 * total) + (s[i] - '0');
    263 		i++;
    264 	}
    265 	return(total);
    266 }
    267 
    268 int
    269 to_hit(obj)
    270 	const object *obj;
    271 {
    272 	if (!obj) {
    273 		return(1);
    274 	}
    275 	return(get_number(obj->damage) + obj->hit_enchant);
    276 }
    277 
    278 int
    279 damage_for_strength()
    280 {
    281 	short strength;
    282 
    283 	strength = rogue.str_current + add_strength;
    284 
    285 	if (strength <= 6) {
    286 		return(strength-5);
    287 	}
    288 	if (strength <= 14) {
    289 		return(1);
    290 	}
    291 	if (strength <= 17) {
    292 		return(3);
    293 	}
    294 	if (strength <= 18) {
    295 		return(4);
    296 	}
    297 	if (strength <= 20) {
    298 		return(5);
    299 	}
    300 	if (strength <= 21) {
    301 		return(6);
    302 	}
    303 	if (strength <= 30) {
    304 		return(7);
    305 	}
    306 	return(8);
    307 }
    308 
    309 int
    310 mon_damage(monster, damage)
    311 	object *monster;
    312 	short damage;
    313 {
    314 	const char *mn;
    315 	short row, col;
    316 
    317 	monster->hp_to_kill -= damage;
    318 
    319 	if (monster->hp_to_kill <= 0) {
    320 		row = monster->row;
    321 		col = monster->col;
    322 		dungeon[row][col] &= ~MONSTER;
    323 		mvaddch(row, col, (int)get_dungeon_char(row, col));
    324 
    325 		fight_monster = 0;
    326 		cough_up(monster);
    327 		mn = mon_name(monster);
    328 		messagef(1, "%sdefeated the %s", hit_message, mn);
    329 		hit_message[0] = 0;
    330 		add_exp(monster->kill_exp, 1);
    331 		take_from_pack(monster, &level_monsters);
    332 
    333 		if (monster->m_flags & HOLDS) {
    334 			being_held = 0;
    335 		}
    336 		free_object(monster);
    337 		return(0);
    338 	}
    339 	return(1);
    340 }
    341 
    342 void
    343 fight(to_the_death)
    344 	boolean to_the_death;
    345 {
    346 	short ch, c, d;
    347 	short row, col;
    348 	boolean first_miss = 1;
    349 	short possible_damage;
    350 	object *monster;
    351 
    352 	ch = 0;
    353 	while (!is_direction(ch = rgetchar(), &d)) {
    354 		sound_bell();
    355 		if (first_miss) {
    356 			messagef(0, "direction?");
    357 			first_miss = 0;
    358 		}
    359 	}
    360 	check_message();
    361 	if (ch == CANCEL) {
    362 		return;
    363 	}
    364 	row = rogue.row; col = rogue.col;
    365 	get_dir_rc(d, &row, &col, 0);
    366 
    367 	c = mvinch(row, col);
    368 	if (((c < 'A') || (c > 'Z')) ||
    369 		(!can_move(rogue.row, rogue.col, row, col))) {
    370 		messagef(0, "I see no monster there");
    371 		return;
    372 	}
    373 	if (!(fight_monster = object_at(&level_monsters, row, col))) {
    374 		return;
    375 	}
    376 	if (!(fight_monster->m_flags & STATIONARY)) {
    377 		possible_damage = ((get_damage(fight_monster->m_damage, 0) * 2) / 3);
    378 	} else {
    379 		possible_damage = fight_monster->stationary_damage - 1;
    380 	}
    381 	while (fight_monster) {
    382 		(void)one_move_rogue(ch, 0);
    383 		if (((!to_the_death) && (rogue.hp_current <= possible_damage)) ||
    384 			interrupted || (!(dungeon[row][col] & MONSTER))) {
    385 			fight_monster = 0;
    386 		} else {
    387 			monster = object_at(&level_monsters, row, col);
    388 			if (monster != fight_monster) {
    389 				fight_monster = 0;
    390 			}
    391 		}
    392 	}
    393 }
    394 
    395 void
    396 get_dir_rc(dir, row, col, allow_off_screen)
    397 	short dir;
    398 	short *row, *col;
    399 	short allow_off_screen;
    400 {
    401 	switch(dir) {
    402 	case LEFT:
    403 		if (allow_off_screen || (*col > 0)) {
    404 			(*col)--;
    405 		}
    406 		break;
    407 	case DOWN:
    408 		if (allow_off_screen || (*row < (DROWS-2))) {
    409 			(*row)++;
    410 		}
    411 		break;
    412 	case UPWARD:
    413 		if (allow_off_screen || (*row > MIN_ROW)) {
    414 			(*row)--;
    415 		}
    416 		break;
    417 	case RIGHT:
    418 		if (allow_off_screen || (*col < (DCOLS-1))) {
    419 			(*col)++;
    420 		}
    421 		break;
    422 	case UPLEFT:
    423 		if (allow_off_screen || ((*row > MIN_ROW) && (*col > 0))) {
    424 			(*row)--;
    425 			(*col)--;
    426 		}
    427 		break;
    428 	case UPRIGHT:
    429 		if (allow_off_screen || ((*row > MIN_ROW) && (*col < (DCOLS-1)))) {
    430 			(*row)--;
    431 			(*col)++;
    432 		}
    433 		break;
    434 	case DOWNRIGHT:
    435 		if (allow_off_screen || ((*row < (DROWS-2)) && (*col < (DCOLS-1)))) {
    436 			(*row)++;
    437 			(*col)++;
    438 		}
    439 		break;
    440 	case DOWNLEFT:
    441 		if (allow_off_screen || ((*row < (DROWS-2)) && (*col > 0))) {
    442 			(*row)++;
    443 			(*col)--;
    444 		}
    445 		break;
    446 	}
    447 }
    448 
    449 int
    450 get_hit_chance(weapon)
    451 	const object *weapon;
    452 {
    453 	short hit_chance;
    454 
    455 	hit_chance = 40;
    456 	hit_chance += 3 * to_hit(weapon);
    457 	hit_chance += (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
    458 	return(hit_chance);
    459 }
    460 
    461 int
    462 get_weapon_damage(weapon)
    463 	const object *weapon;
    464 {
    465 	short damage;
    466 
    467 	damage = get_w_damage(weapon);
    468 	damage += damage_for_strength();
    469 	damage += ((((rogue.exp + ring_exp) - r_rings) + 1) / 2);
    470 	return(damage);
    471 }
    472 
    473 void
    474 s_con_mon(monster)
    475 	object *monster;
    476 {
    477 	if (con_mon) {
    478 		monster->m_flags |= CONFUSED;
    479 		monster->moves_confused += get_rand(12, 22);
    480 		messagef(0, "the monster appears confused");
    481 		con_mon = 0;
    482 	}
    483 }
    484