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