Home | History | Annotate | Line # | Download | only in rogue
hit.c revision 1.3
      1 /*	$NetBSD: hit.c,v 1.3 1995/04/22 10:27:30 cgd 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 #ifndef lint
     40 #if 0
     41 static char sccsid[] = "@(#)hit.c	8.1 (Berkeley) 5/31/93";
     42 #else
     43 static char rcsid[] = "$NetBSD: hit.c,v 1.3 1995/04/22 10:27:30 cgd Exp $";
     44 #endif
     45 #endif /* not lint */
     46 
     47 /*
     48  * hit.c
     49  *
     50  * This source herein may be modified and/or distributed by anybody who
     51  * so desires, with the following restrictions:
     52  *    1.)  No portion of this notice shall be removed.
     53  *    2.)  Credit shall not be taken for the creation of this source.
     54  *    3.)  This code is not to be traded, sold, or used for personal
     55  *         gain or profit.
     56  *
     57  */
     58 
     59 #include "rogue.h"
     60 
     61 object *fight_monster = 0;
     62 char hit_message[80] = "";
     63 
     64 extern short halluc, blind, cur_level;
     65 extern short add_strength, ring_exp, r_rings;
     66 extern boolean being_held, interrupted, wizard, con_mon;
     67 
     68 mon_hit(monster)
     69 register object *monster;
     70 {
     71 	short damage, hit_chance;
     72 	char *mn;
     73 	float minus;
     74 
     75 	if (fight_monster && (monster != fight_monster)) {
     76 		fight_monster = 0;
     77 	}
     78 	monster->trow = NO_ROOM;
     79 	if (cur_level >= (AMULET_LEVEL * 2)) {
     80 		hit_chance = 100;
     81 	} else {
     82 		hit_chance = monster->m_hit_chance;
     83 		hit_chance -= (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
     84 	}
     85 	if (wizard) {
     86 		hit_chance /= 2;
     87 	}
     88 	if (!fight_monster) {
     89 		interrupted = 1;
     90 	}
     91 	mn = mon_name(monster);
     92 
     93 	if (!rand_percent(hit_chance)) {
     94 		if (!fight_monster) {
     95 			sprintf(hit_message + strlen(hit_message), "the %s misses", mn);
     96 			message(hit_message, 1);
     97 			hit_message[0] = 0;
     98 		}
     99 		return;
    100 	}
    101 	if (!fight_monster) {
    102 		sprintf(hit_message + strlen(hit_message), "the %s hit", mn);
    103 		message(hit_message, 1);
    104 		hit_message[0] = 0;
    105 	}
    106 	if (!(monster->m_flags & STATIONARY)) {
    107 		damage = get_damage(monster->m_damage, 1);
    108 		if (cur_level >= (AMULET_LEVEL * 2)) {
    109 			minus = (float) ((AMULET_LEVEL * 2) - cur_level);
    110 		} else {
    111 			minus = (float) get_armor_class(rogue.armor) * 3.00;
    112 			minus = minus/100.00 * (float) damage;
    113 		}
    114 		damage -= (short) minus;
    115 	} else {
    116 		damage = monster->stationary_damage++;
    117 	}
    118 	if (wizard) {
    119 		damage /= 3;
    120 	}
    121 	if (damage > 0) {
    122 		rogue_damage(damage, monster, 0);
    123 	}
    124 	if (monster->m_flags & SPECIAL_HIT) {
    125 		special_hit(monster);
    126 	}
    127 }
    128 
    129 rogue_hit(monster, force_hit)
    130 register 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 rogue_damage(d, monster, other)
    168 short d;
    169 object *monster;
    170 short other;
    171 {
    172 	if (d >= rogue.hp_current) {
    173 		rogue.hp_current = 0;
    174 		print_stats(STAT_HP);
    175 		killed_by(monster, other);
    176 	}
    177 	if (d > 0) {
    178 		rogue.hp_current -= d;
    179 		print_stats(STAT_HP);
    180 	}
    181 }
    182 
    183 get_damage(ds, r)
    184 char *ds;
    185 boolean r;
    186 {
    187 	register i = 0, j, n, d, total = 0;
    188 
    189 	while (ds[i]) {
    190 		n = get_number(ds+i);
    191 		while (ds[i++] != 'd') ;
    192 		d = get_number(ds+i);
    193 		while ((ds[i] != '/') && ds[i]) i++;
    194 
    195 		for (j = 0; j < n; j++) {
    196 			if (r) {
    197 				total += get_rand(1, d);
    198 			} else {
    199 				total += d;
    200 			}
    201 		}
    202 		if (ds[i] == '/') {
    203 			i++;
    204 		}
    205 	}
    206 	return(total);
    207 }
    208 
    209 get_w_damage(obj)
    210 object *obj;
    211 {
    212 	char new_damage[12];
    213 	register to_hit, damage;
    214 	register i = 0;
    215 
    216 	if ((!obj) || (obj->what_is != WEAPON)) {
    217 		return(-1);
    218 	}
    219 	to_hit = get_number(obj->damage) + obj->hit_enchant;
    220 	while (obj->damage[i++] != 'd') ;
    221 	damage = get_number(obj->damage + i) + obj->d_enchant;
    222 
    223 	sprintf(new_damage, "%dd%d", to_hit, damage);
    224 
    225 	return(get_damage(new_damage, 1));
    226 }
    227 
    228 get_number(s)
    229 register char *s;
    230 {
    231 	register i = 0;
    232 	register total = 0;
    233 
    234 	while ((s[i] >= '0') && (s[i] <= '9')) {
    235 		total = (10 * total) + (s[i] - '0');
    236 		i++;
    237 	}
    238 	return(total);
    239 }
    240 
    241 long
    242 lget_number(s)
    243 char *s;
    244 {
    245 	short i = 0;
    246 	long total = 0;
    247 
    248 	while ((s[i] >= '0') && (s[i] <= '9')) {
    249 		total = (10 * total) + (s[i] - '0');
    250 		i++;
    251 	}
    252 	return(total);
    253 }
    254 
    255 to_hit(obj)
    256 object *obj;
    257 {
    258 	if (!obj) {
    259 		return(1);
    260 	}
    261 	return(get_number(obj->damage) + obj->hit_enchant);
    262 }
    263 
    264 damage_for_strength()
    265 {
    266 	short strength;
    267 
    268 	strength = rogue.str_current + add_strength;
    269 
    270 	if (strength <= 6) {
    271 		return(strength-5);
    272 	}
    273 	if (strength <= 14) {
    274 		return(1);
    275 	}
    276 	if (strength <= 17) {
    277 		return(3);
    278 	}
    279 	if (strength <= 18) {
    280 		return(4);
    281 	}
    282 	if (strength <= 20) {
    283 		return(5);
    284 	}
    285 	if (strength <= 21) {
    286 		return(6);
    287 	}
    288 	if (strength <= 30) {
    289 		return(7);
    290 	}
    291 	return(8);
    292 }
    293 
    294 mon_damage(monster, damage)
    295 object *monster;
    296 short damage;
    297 {
    298 	char *mn;
    299 	short row, col;
    300 
    301 	monster->hp_to_kill -= damage;
    302 
    303 	if (monster->hp_to_kill <= 0) {
    304 		row = monster->row;
    305 		col = monster->col;
    306 		dungeon[row][col] &= ~MONSTER;
    307 		mvaddch(row, col, (int) get_dungeon_char(row, col));
    308 
    309 		fight_monster = 0;
    310 		cough_up(monster);
    311 		mn = mon_name(monster);
    312 		sprintf(hit_message+strlen(hit_message), "defeated the %s", mn);
    313 		message(hit_message, 1);
    314 		hit_message[0] = 0;
    315 		add_exp(monster->kill_exp, 1);
    316 		take_from_pack(monster, &level_monsters);
    317 
    318 		if (monster->m_flags & HOLDS) {
    319 			being_held = 0;
    320 		}
    321 		free_object(monster);
    322 		return(0);
    323 	}
    324 	return(1);
    325 }
    326 
    327 fight(to_the_death)
    328 boolean to_the_death;
    329 {
    330 	short ch, c, d;
    331 	short row, col;
    332 	boolean first_miss = 1;
    333 	short possible_damage;
    334 	object *monster;
    335 
    336 	while (!is_direction(ch = rgetchar(), &d)) {
    337 		sound_bell();
    338 		if (first_miss) {
    339 			message("direction?", 0);
    340 			first_miss = 0;
    341 		}
    342 	}
    343 	check_message();
    344 	if (ch == CANCEL) {
    345 		return;
    346 	}
    347 	row = rogue.row; col = rogue.col;
    348 	get_dir_rc(d, &row, &col, 0);
    349 
    350 	c = mvinch(row, col);
    351 	if (((c < 'A') || (c > 'Z')) ||
    352 		(!can_move(rogue.row, rogue.col, row, col))) {
    353 		message("I see no monster there", 0);
    354 		return;
    355 	}
    356 	if (!(fight_monster = object_at(&level_monsters, row, col))) {
    357 		return;
    358 	}
    359 	if (!(fight_monster->m_flags & STATIONARY)) {
    360 		possible_damage = ((get_damage(fight_monster->m_damage, 0) * 2) / 3);
    361 	} else {
    362 		possible_damage = fight_monster->stationary_damage - 1;
    363 	}
    364 	while (fight_monster) {
    365 		(void) one_move_rogue(ch, 0);
    366 		if (((!to_the_death) && (rogue.hp_current <= possible_damage)) ||
    367 			interrupted || (!(dungeon[row][col] & MONSTER))) {
    368 			fight_monster = 0;
    369 		} else {
    370 			monster = object_at(&level_monsters, row, col);
    371 			if (monster != fight_monster) {
    372 				fight_monster = 0;
    373 			}
    374 		}
    375 	}
    376 }
    377 
    378 get_dir_rc(dir, row, col, allow_off_screen)
    379 short dir;
    380 short *row, *col;
    381 short allow_off_screen;
    382 {
    383 	switch(dir) {
    384 	case LEFT:
    385 		if (allow_off_screen || (*col > 0)) {
    386 			(*col)--;
    387 		}
    388 		break;
    389 	case DOWN:
    390 		if (allow_off_screen || (*row < (DROWS-2))) {
    391 			(*row)++;
    392 		}
    393 		break;
    394 	case UPWARD:
    395 		if (allow_off_screen || (*row > MIN_ROW)) {
    396 			(*row)--;
    397 		}
    398 		break;
    399 	case RIGHT:
    400 		if (allow_off_screen || (*col < (DCOLS-1))) {
    401 			(*col)++;
    402 		}
    403 		break;
    404 	case UPLEFT:
    405 		if (allow_off_screen || ((*row > MIN_ROW) && (*col > 0))) {
    406 			(*row)--;
    407 			(*col)--;
    408 		}
    409 		break;
    410 	case UPRIGHT:
    411 		if (allow_off_screen || ((*row > MIN_ROW) && (*col < (DCOLS-1)))) {
    412 			(*row)--;
    413 			(*col)++;
    414 		}
    415 		break;
    416 	case DOWNRIGHT:
    417 		if (allow_off_screen || ((*row < (DROWS-2)) && (*col < (DCOLS-1)))) {
    418 			(*row)++;
    419 			(*col)++;
    420 		}
    421 		break;
    422 	case DOWNLEFT:
    423 		if (allow_off_screen || ((*row < (DROWS-2)) && (*col > 0))) {
    424 			(*row)++;
    425 			(*col)--;
    426 		}
    427 		break;
    428 	}
    429 }
    430 
    431 get_hit_chance(weapon)
    432 object *weapon;
    433 {
    434 	short hit_chance;
    435 
    436 	hit_chance = 40;
    437 	hit_chance += 3 * to_hit(weapon);
    438 	hit_chance += (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
    439 	return(hit_chance);
    440 }
    441 
    442 get_weapon_damage(weapon)
    443 object *weapon;
    444 {
    445 	short damage;
    446 
    447 	damage = get_w_damage(weapon);
    448 	damage += damage_for_strength();
    449 	damage += ((((rogue.exp + ring_exp) - r_rings) + 1) / 2);
    450 	return(damage);
    451 }
    452 
    453 s_con_mon(monster)
    454 object *monster;
    455 {
    456 	if (con_mon) {
    457 		monster->m_flags |= CONFUSED;
    458 		monster->moves_confused += get_rand(12, 22);
    459 		message("the monster appears confused", 0);
    460 		con_mon = 0;
    461 	}
    462 }
    463