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