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