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