1 /*
2  * hit.c
3  *
4  * This source herein may be modified and/or distributed by anybody who
5  * so desires, with the following restrictions:
6  *    1.)  No portion of this notice shall be removed.
7  *    2.)  Credit shall not be taken for the creation of this source.
8  *    3.)  This code is not to be traded, sold, or used for personal
9  *         gain or profit.
10  *
11  */
12 
13 #include "rogue.h"
14 
15 extern char *nick_name;
16 object *fight_monster = 0;
17 char hit_message[80] = "";
18 
19 extern short halluc, blind, cur_level;
20 extern short add_strength, ring_exp, r_rings;
21 extern boolean being_held, interrupted, wizard;
22 
23 void
mon_hit(monster,other,flame)24 mon_hit(monster, other, flame)
25 register object *monster;
26 char *other;
27 boolean flame;
28 {
29 	short damage, hit_chance;
30 	char *mn;
31 	long minus;
32 
33 	if (fight_monster && (monster != fight_monster)) {
34 		fight_monster = 0;
35 	}
36 	monster->trow = NO_ROOM;
37 	if (cur_level >= (AMULET_LEVEL * 2)) {
38 		hit_chance = 100;
39 	} else {
40 		hit_chance = monster->m_hit_chance;
41 		hit_chance -= (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
42 	}
43 	if (wizard) {
44 		hit_chance /= 2;
45 	}
46 	if (!fight_monster) {
47 		interrupted = 1;
48 	}
49 	mn = mon_name(monster);
50 
51 	if (other) {
52 		hit_chance -= ((rogue.exp + ring_exp) - r_rings);
53 	}
54 
55 	if (!rand_percent(hit_chance)) {
56 		if (!fight_monster) {
57 			sprintf(hit_message + strlen(hit_message),
58 			mesg[18], (other ? other: mn));
59 			message(hit_message, 1);
60 			hit_message[0] = 0;
61 		}
62 		return;
63 	}
64 	if (!fight_monster) {
65 		sprintf(hit_message + strlen(hit_message),
66 		mesg[19], (other? other:mn), (other? mesg[20]:mesg[21]));
67 		message(hit_message, 1);
68 		hit_message[0] = 0;
69 	}
70 	if (!(monster->m_flags & STATIONARY)) {
71 		damage = get_damage(monster->m_damage, 1);
72 		if (other) {
73 			if (flame) {
74 				if ((damage -= get_armor_class(rogue.armor)) < 0) {
75 					damage = 1;
76 				}
77 			}
78 		}
79 		if (cur_level >= (AMULET_LEVEL * 2)) {
80 			minus = (long) ((AMULET_LEVEL * 2) - cur_level);
81 		} else {
82 			minus = (long) (get_armor_class(rogue.armor) * 3);
83 			minus = minus * (long)damage / 100L;
84 		}
85 		damage -= (short) minus;
86 	} else {
87 		damage = monster->stationary_damage++;
88 	}
89 	if (wizard) {
90 		damage /= 3;
91 	}
92 	if (damage > 0) {
93 		rogue_damage(damage, monster);
94 	}
95 	if (monster->m_flags & SPECIAL_HIT) {
96 		special_hit(monster);
97 	}
98 }
99 
100 void
rogue_hit(monster,force_hit)101 rogue_hit(monster, force_hit)
102 register object *monster;
103 boolean force_hit;
104 {
105 	short damage, hit_chance;
106 
107 	if (monster) {
108 		if (check_imitator(monster)) {
109 			return;
110 		}
111 		hit_chance = force_hit ? 100 : get_hit_chance(rogue.weapon);
112 
113 		if (wizard) {
114 			hit_chance *= 2;
115 		}
116 		if (!rand_percent(hit_chance)) {
117 			if (!fight_monster) {
118 				sprintf(hit_message, mesg[22],
119 					nick_name);
120 			}
121 			goto RET;
122 		}
123 		damage = get_weapon_damage(rogue.weapon);
124 		if (wizard) {
125 			damage *= 3;
126 		}
127 		if (mon_damage(monster, damage)) {	/* still alive? */
128 			if (!fight_monster) {
129 				sprintf(hit_message, mesg[23],
130 				nick_name);
131 			}
132 		}
133 RET:	check_gold_seeker(monster);
134 		wake_up(monster);
135 	}
136 }
137 
rogue_damage(d,monster)138 rogue_damage(d, monster)
139 short d;
140 object *monster;
141 {
142 	if (d >= rogue.hp_current) {
143 		rogue.hp_current = 0;
144 		print_stats(STAT_HP);
145 		killed_by(monster, 0);
146 	}
147 	rogue.hp_current -= d;
148 	print_stats(STAT_HP);
149 }
150 
get_damage(ds,r)151 get_damage(ds, r)
152 char *ds;
153 boolean r;
154 {
155 	register i = 0, j, n, d, total = 0;
156 
157 	while (ds[i]) {
158 		n = get_number(ds+i);
159 		while (ds[i++] != 'd') ;
160 		d = get_number(ds+i);
161 		while ((ds[i] != '/') && ds[i]) i++;
162 
163 		for (j = 0; j < n; j++) {
164 			if (r) {
165 				total += get_rand(1, d);
166 			} else {
167 				total += d;
168 			}
169 		}
170 		if (ds[i] == '/') {
171 			i++;
172 		}
173 	}
174 	return(total);
175 }
176 
get_w_damage(obj)177 get_w_damage(obj)
178 object *obj;
179 {
180 	char new_damage[12];
181 	register to_hit, damage;
182 	register i = 0;
183 
184 	if ((!obj) || (obj->what_is != WEAPON)) {
185 		return(-1);
186 	}
187 	to_hit = get_number(obj->damage) + obj->hit_enchant;
188 	while (obj->damage[i++] != 'd') ;
189 	damage = get_number(obj->damage + i) + obj->d_enchant;
190 
191 	sprintf(new_damage, "%dd%d", to_hit, damage);
192 
193 	return(get_damage(new_damage, 1));
194 }
195 
get_number(s)196 get_number(s)
197 register char *s;
198 {
199 	register int total = 0;
200 
201 	while (*s >= '0' && *s <= '9') {
202 		total = (10 * total) + (*s++ - '0');
203 	}
204 	return(total);
205 }
206 
207 long
lget_number(s)208 lget_number(s)
209 register char *s;
210 {
211 	register long total = 0;
212 
213 	while (*s >= '0' && *s <= '9') {
214 		total = (10 * total) + (*s++ - '0');
215 	}
216 	return(total);
217 }
218 
to_hit(obj)219 to_hit(obj)
220 object *obj;
221 {
222 	if (!obj) {
223 		return(1);
224 	}
225 	return(get_number(obj->damage) + obj->hit_enchant);
226 }
227 
damage_for_strength()228 damage_for_strength()
229 {
230 	short strength;
231 	int i;
232 	static short sa[] = { 14, 17, 18, 20, 21, 30, 9999 };
233 	static short ra[] = {  1,  3,  4,  5,  6,  7,    8 };
234 
235 	strength = rogue.str_current + add_strength;
236 	if (strength <= 6) {
237 		return(strength-5);
238 	}
239 	i = 0;
240 	for (;;) {
241 		if (strength <= sa[i])
242 			return (int)ra[i];
243 		i++;
244 	}
245 }
246 
mon_damage(monster,damage)247 mon_damage(monster, damage)
248 object *monster;
249 {
250 	char *mn;
251 	short row, col;
252 
253 	monster->hp_to_kill -= damage;
254 
255 	if (monster->hp_to_kill <= 0) {
256 		row = monster->row;
257 		col = monster->col;
258 		dungeon[row][col] &= ~MONSTER;
259 		mvaddch(row, col, colored(get_dungeon_char(row, col)));
260 
261 		fight_monster = 0;
262 		cough_up(monster);
263 		mn = mon_name(monster);
264 		sprintf(hit_message+strlen(hit_message),
265 			mesg[24], mn);
266 		message(hit_message, 1);
267 		hit_message[0] = 0;
268 		add_exp(monster->kill_exp, 1);
269 		take_from_pack(monster, &level_monsters);
270 
271 		if (monster->m_flags & HOLDS) {
272 			being_held = 0;
273 		}
274 		free_object(monster);
275 		return(0);
276 	}
277 	return(1);
278 }
279 
280 void
fight(to_the_death)281 fight(to_the_death)
282 boolean to_the_death;
283 {
284 	short ch, c;
285 	short row, col;
286 	short possible_damage;
287 	object *monster;
288 
289 	ch = get_direction();
290 	if (ch == CANCEL) {
291 		return;
292 	}
293 	row = rogue.row; col = rogue.col;
294 	get_dir_rc(ch, &row, &col, 0);
295 
296 	c = mvinch(row, col);
297 	if (((c < 'A') || (c > 'Z')) ||
298 		(!can_move(rogue.row, rogue.col, row, col))) {
299 		message(mesg[25], 0);
300 		return;
301 	}
302 	if (!(fight_monster = object_at(&level_monsters, row, col))) {
303 		return;
304 	}
305 	if (!(fight_monster->m_flags & STATIONARY)) {
306 		possible_damage = ((get_damage(fight_monster->m_damage, 0) * 2) / 3);
307 	} else {
308 		possible_damage = fight_monster->stationary_damage - 1;
309 	}
310 	while (fight_monster) {
311 		(void) one_move_rogue(ch, 0);
312 		if (((!to_the_death) && (rogue.hp_current <= possible_damage)) ||
313 			interrupted || (!(dungeon[row][col] & MONSTER))) {
314 			fight_monster = 0;
315 		} else {
316 			monster = object_at(&level_monsters, row, col);
317 			if (monster != fight_monster) {
318 				fight_monster = 0;
319 			}
320 		}
321 	}
322 }
323 
get_dir_rc(dir,row,col,allow_off_screen)324 get_dir_rc(dir, row, col, allow_off_screen)
325 short dir;
326 short *row, *col;
327 short allow_off_screen;
328 {
329 	switch(dir) {
330 	case 'h':
331 		if (allow_off_screen || (*col > 0)) {
332 			(*col)--;
333 		}
334 		break;
335 	case 'j':
336 		if (allow_off_screen || (*row < (DROWS-2))) {
337 			(*row)++;
338 		}
339 		break;
340 	case 'k':
341 		if (allow_off_screen || (*row > MIN_ROW)) {
342 			(*row)--;
343 		}
344 		break;
345 	case 'l':
346 		if (allow_off_screen || (*col < (DCOLS-1))) {
347 			(*col)++;
348 		}
349 		break;
350 	case 'y':
351 		if (allow_off_screen || ((*row > MIN_ROW) && (*col > 0))) {
352 			(*row)--;
353 			(*col)--;
354 		}
355 		break;
356 	case 'u':
357 		if (allow_off_screen || ((*row > MIN_ROW) && (*col < (DCOLS-1)))) {
358 			(*row)--;
359 			(*col)++;
360 		}
361 		break;
362 	case 'n':
363 		if (allow_off_screen || ((*row < (DROWS-2)) && (*col < (DCOLS-1)))) {
364 			(*row)++;
365 			(*col)++;
366 		}
367 		break;
368 	case 'b':
369 		if (allow_off_screen || ((*row < (DROWS-2)) && (*col > 0))) {
370 			(*row)++;
371 			(*col)--;
372 		}
373 		break;
374 	}
375 }
376 
get_hit_chance(weapon)377 get_hit_chance(weapon)
378 object *weapon;
379 {
380 	short hit_chance;
381 
382 	hit_chance = 40 + 3 * to_hit(weapon);
383 	hit_chance += (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
384 	return(hit_chance);
385 }
386 
get_weapon_damage(weapon)387 get_weapon_damage(weapon)
388 object *weapon;
389 {
390 	short damage;
391 
392 	damage = get_w_damage(weapon) + damage_for_strength();
393 	damage += ((((rogue.exp + ring_exp) - r_rings) + 1) / 2);
394 	return(damage);
395 }
396