hit.c revision 1.10 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