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