xref: /original-bsd/games/rogue/hit.c (revision a4d3ae46)
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 #ifndef lint
14 static char sccsid[] = "@(#)hit.c	5.1 (Berkeley) 11/25/87";
15 #endif /* not lint */
16 
17 #include "rogue.h"
18 
19 object *fight_monster = 0;
20 char hit_message[80] = "";
21 
22 extern short halluc, blind, cur_level;
23 extern short add_strength, ring_exp, r_rings;
24 extern boolean being_held, interrupted, wizard, con_mon;
25 
26 mon_hit(monster)
27 register object *monster;
28 {
29 	short damage, hit_chance;
30 	char *mn;
31 	float 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 (!rand_percent(hit_chance)) {
52 		if (!fight_monster) {
53 			sprintf(hit_message + strlen(hit_message), "the %s misses", mn);
54 			message(hit_message, 1);
55 			hit_message[0] = 0;
56 		}
57 		return;
58 	}
59 	if (!fight_monster) {
60 		sprintf(hit_message + strlen(hit_message), "the %s hit", mn);
61 		message(hit_message, 1);
62 		hit_message[0] = 0;
63 	}
64 	if (!(monster->m_flags & STATIONARY)) {
65 		damage = get_damage(monster->m_damage, 1);
66 		if (cur_level >= (AMULET_LEVEL * 2)) {
67 			minus = (float) ((AMULET_LEVEL * 2) - cur_level);
68 		} else {
69 			minus = (float) get_armor_class(rogue.armor) * 3.00;
70 			minus = minus/100.00 * (float) damage;
71 		}
72 		damage -= (short) minus;
73 	} else {
74 		damage = monster->stationary_damage++;
75 	}
76 	if (wizard) {
77 		damage /= 3;
78 	}
79 	if (damage > 0) {
80 		rogue_damage(damage, monster, 0);
81 	}
82 	if (monster->m_flags & SPECIAL_HIT) {
83 		special_hit(monster);
84 	}
85 }
86 
87 rogue_hit(monster, force_hit)
88 register object *monster;
89 boolean force_hit;
90 {
91 	short damage, hit_chance;
92 
93 	if (monster) {
94 		if (check_imitator(monster)) {
95 			return;
96 		}
97 		hit_chance = force_hit ? 100 : get_hit_chance(rogue.weapon);
98 
99 		if (wizard) {
100 			hit_chance *= 2;
101 		}
102 		if (!rand_percent(hit_chance)) {
103 			if (!fight_monster) {
104 				(void) strcpy(hit_message, "you miss  ");
105 			}
106 			goto RET;
107 		}
108 		damage = get_weapon_damage(rogue.weapon);
109 		if (wizard) {
110 			damage *= 3;
111 		}
112 		if (con_mon) {
113 			s_con_mon(monster);
114 		}
115 		if (mon_damage(monster, damage)) {	/* still alive? */
116 			if (!fight_monster) {
117 				(void) strcpy(hit_message, "you hit  ");
118 			}
119 		}
120 RET:	check_gold_seeker(monster);
121 		wake_up(monster);
122 	}
123 }
124 
125 rogue_damage(d, monster, other)
126 short d;
127 object *monster;
128 short other;
129 {
130 	if (d >= rogue.hp_current) {
131 		rogue.hp_current = 0;
132 		print_stats(STAT_HP);
133 		killed_by(monster, other);
134 	}
135 	if (d > 0) {
136 		rogue.hp_current -= d;
137 		print_stats(STAT_HP);
138 	}
139 }
140 
141 get_damage(ds, r)
142 char *ds;
143 boolean r;
144 {
145 	register i = 0, j, n, d, total = 0;
146 
147 	while (ds[i]) {
148 		n = get_number(ds+i);
149 		while (ds[i++] != 'd') ;
150 		d = get_number(ds+i);
151 		while ((ds[i] != '/') && ds[i]) i++;
152 
153 		for (j = 0; j < n; j++) {
154 			if (r) {
155 				total += get_rand(1, d);
156 			} else {
157 				total += d;
158 			}
159 		}
160 		if (ds[i] == '/') {
161 			i++;
162 		}
163 	}
164 	return(total);
165 }
166 
167 get_w_damage(obj)
168 object *obj;
169 {
170 	char new_damage[12];
171 	register to_hit, damage;
172 	register i = 0;
173 
174 	if ((!obj) || (obj->what_is != WEAPON)) {
175 		return(-1);
176 	}
177 	to_hit = get_number(obj->damage) + obj->hit_enchant;
178 	while (obj->damage[i++] != 'd') ;
179 	damage = get_number(obj->damage + i) + obj->d_enchant;
180 
181 	sprintf(new_damage, "%dd%d", to_hit, damage);
182 
183 	return(get_damage(new_damage, 1));
184 }
185 
186 get_number(s)
187 register char *s;
188 {
189 	register i = 0;
190 	register total = 0;
191 
192 	while ((s[i] >= '0') && (s[i] <= '9')) {
193 		total = (10 * total) + (s[i] - '0');
194 		i++;
195 	}
196 	return(total);
197 }
198 
199 long
200 lget_number(s)
201 char *s;
202 {
203 	short i = 0;
204 	long total = 0;
205 
206 	while ((s[i] >= '0') && (s[i] <= '9')) {
207 		total = (10 * total) + (s[i] - '0');
208 		i++;
209 	}
210 	return(total);
211 }
212 
213 to_hit(obj)
214 object *obj;
215 {
216 	if (!obj) {
217 		return(1);
218 	}
219 	return(get_number(obj->damage) + obj->hit_enchant);
220 }
221 
222 damage_for_strength()
223 {
224 	short strength;
225 
226 	strength = rogue.str_current + add_strength;
227 
228 	if (strength <= 6) {
229 		return(strength-5);
230 	}
231 	if (strength <= 14) {
232 		return(1);
233 	}
234 	if (strength <= 17) {
235 		return(3);
236 	}
237 	if (strength <= 18) {
238 		return(4);
239 	}
240 	if (strength <= 20) {
241 		return(5);
242 	}
243 	if (strength <= 21) {
244 		return(6);
245 	}
246 	if (strength <= 30) {
247 		return(7);
248 	}
249 	return(8);
250 }
251 
252 mon_damage(monster, damage)
253 object *monster;
254 short damage;
255 {
256 	char *mn;
257 	short row, col;
258 
259 	monster->hp_to_kill -= damage;
260 
261 	if (monster->hp_to_kill <= 0) {
262 		row = monster->row;
263 		col = monster->col;
264 		dungeon[row][col] &= ~MONSTER;
265 		mvaddch(row, col, (int) get_dungeon_char(row, col));
266 
267 		fight_monster = 0;
268 		cough_up(monster);
269 		mn = mon_name(monster);
270 		sprintf(hit_message+strlen(hit_message), "defeated the %s", mn);
271 		message(hit_message, 1);
272 		hit_message[0] = 0;
273 		add_exp(monster->kill_exp, 1);
274 		take_from_pack(monster, &level_monsters);
275 
276 		if (monster->m_flags & HOLDS) {
277 			being_held = 0;
278 		}
279 		free_object(monster);
280 		return(0);
281 	}
282 	return(1);
283 }
284 
285 fight(to_the_death)
286 boolean to_the_death;
287 {
288 	short ch, c, d;
289 	short row, col;
290 	boolean first_miss = 1;
291 	short possible_damage;
292 	object *monster;
293 
294 	while (!is_direction(ch = rgetchar(), &d)) {
295 		sound_bell();
296 		if (first_miss) {
297 			message("direction?", 0);
298 			first_miss = 0;
299 		}
300 	}
301 	check_message();
302 	if (ch == CANCEL) {
303 		return;
304 	}
305 	row = rogue.row; col = rogue.col;
306 	get_dir_rc(d, &row, &col, 0);
307 
308 	c = mvinch(row, col);
309 	if (((c < 'A') || (c > 'Z')) ||
310 		(!can_move(rogue.row, rogue.col, row, col))) {
311 		message("I see no monster there", 0);
312 		return;
313 	}
314 	if (!(fight_monster = object_at(&level_monsters, row, col))) {
315 		return;
316 	}
317 	if (!(fight_monster->m_flags & STATIONARY)) {
318 		possible_damage = ((get_damage(fight_monster->m_damage, 0) * 2) / 3);
319 	} else {
320 		possible_damage = fight_monster->stationary_damage - 1;
321 	}
322 	while (fight_monster) {
323 		(void) one_move_rogue(ch, 0);
324 		if (((!to_the_death) && (rogue.hp_current <= possible_damage)) ||
325 			interrupted || (!(dungeon[row][col] & MONSTER))) {
326 			fight_monster = 0;
327 		} else {
328 			monster = object_at(&level_monsters, row, col);
329 			if (monster != fight_monster) {
330 				fight_monster = 0;
331 			}
332 		}
333 	}
334 }
335 
336 get_dir_rc(dir, row, col, allow_off_screen)
337 short dir;
338 short *row, *col;
339 short allow_off_screen;
340 {
341 	switch(dir) {
342 	case LEFT:
343 		if (allow_off_screen || (*col > 0)) {
344 			(*col)--;
345 		}
346 		break;
347 	case DOWN:
348 		if (allow_off_screen || (*row < (DROWS-2))) {
349 			(*row)++;
350 		}
351 		break;
352 	case UPWARD:
353 		if (allow_off_screen || (*row > MIN_ROW)) {
354 			(*row)--;
355 		}
356 		break;
357 	case RIGHT:
358 		if (allow_off_screen || (*col < (DCOLS-1))) {
359 			(*col)++;
360 		}
361 		break;
362 	case UPLEFT:
363 		if (allow_off_screen || ((*row > MIN_ROW) && (*col > 0))) {
364 			(*row)--;
365 			(*col)--;
366 		}
367 		break;
368 	case UPRIGHT:
369 		if (allow_off_screen || ((*row > MIN_ROW) && (*col < (DCOLS-1)))) {
370 			(*row)--;
371 			(*col)++;
372 		}
373 		break;
374 	case DOWNRIGHT:
375 		if (allow_off_screen || ((*row < (DROWS-2)) && (*col < (DCOLS-1)))) {
376 			(*row)++;
377 			(*col)++;
378 		}
379 		break;
380 	case DOWNLEFT:
381 		if (allow_off_screen || ((*row < (DROWS-2)) && (*col > 0))) {
382 			(*row)++;
383 			(*col)--;
384 		}
385 		break;
386 	}
387 }
388 
389 get_hit_chance(weapon)
390 object *weapon;
391 {
392 	short hit_chance;
393 
394 	hit_chance = 40;
395 	hit_chance += 3 * to_hit(weapon);
396 	hit_chance += (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
397 	return(hit_chance);
398 }
399 
400 get_weapon_damage(weapon)
401 object *weapon;
402 {
403 	short damage;
404 
405 	damage = get_w_damage(weapon);
406 	damage += damage_for_strength();
407 	damage += ((((rogue.exp + ring_exp) - r_rings) + 1) / 2);
408 	return(damage);
409 }
410 
411 s_con_mon(monster)
412 object *monster;
413 {
414 	if (con_mon) {
415 		monster->m_flags |= CONFUSED;
416 		monster->moves_confused += get_rand(12, 22);
417 		message("the monster appears confused", 0);
418 		con_mon = 0;
419 	}
420 }
421