comparison xrogue/fight.c @ 133:e6179860cb76

Import XRogue 8.0 from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 21 Apr 2015 08:55:20 -0400
parents
children 856017d63519
comparison
equal deleted inserted replaced
124:d10fc4a065ac 133:e6179860cb76
1 /*
2 fight.c - All the fighting gets done here
3
4 XRogue: Expeditions into the Dungeons of Doom
5 Copyright (C) 1991 Robert Pietkivitch
6 All rights reserved.
7
8 Based on "Advanced Rogue"
9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
10 All rights reserved.
11
12 Based on "Rogue: Exploring the Dungeons of Doom"
13 Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
14 All rights reserved.
15
16 See the file LICENSE.TXT for full copyright and licensing information.
17 */
18
19 #include <curses.h>
20 #include <ctype.h>
21 #include <string.h>
22 #include "rogue.h"
23
24 #define CONF_DAMAGE -1
25 #define PARAL_DAMAGE -2
26 #define DEST_DAMAGE -3
27 #define DRAIN_DAMAGE -4
28
29 int killed_chance = 0; /* cumulative chance for goodies to loose it */
30
31 /*
32 * returns true if player has a any chance to hit the monster
33 */
34
35 player_can_hit(tp, weap)
36 register struct thing *tp;
37 register struct object *weap;
38 {
39 if (off(*tp, CMAGICHIT) && off(*tp, BMAGICHIT) && off(*tp, MAGICHIT))
40 return(TRUE);
41 if (weap && weap->o_type == RELIC)
42 return(TRUE);
43 if (on(*tp, CMAGICHIT) && weap && (weap->o_hplus>2 || weap->o_dplus>2))
44 return(TRUE);
45 if (on(*tp, BMAGICHIT) && weap && (weap->o_hplus>1 || weap->o_dplus>1))
46 return(TRUE);
47 if (on(*tp, MAGICHIT) && weap && (weap->o_hplus>0 || weap->o_dplus>0))
48 return(TRUE);
49 if (player.t_ctype == C_MONK) {
50 if (on(*tp, CMAGICHIT) && pstats.s_lvl > 15)
51 return(TRUE);
52 if (on(*tp, BMAGICHIT) && pstats.s_lvl > 10)
53 return(TRUE);
54 if (on(*tp, MAGICHIT) && pstats.s_lvl > 5)
55 return(TRUE);
56 }
57 return(FALSE);
58 }
59
60 /*
61 * fight:
62 * The player attacks the monster.
63 */
64
65 fight(mp, weap, thrown)
66 register coord *mp;
67 struct object *weap;
68 bool thrown;
69 {
70 register struct thing *tp;
71 register struct linked_list *item;
72 register bool did_hit = TRUE;
73 bool see_def, back_stab = FALSE;
74 register char *mname;
75
76 /*
77 * Find the monster we want to fight
78 */
79 if ((item = find_mons(mp->y, mp->x)) == NULL) {
80 return(FALSE); /* must have killed him already */
81 }
82 tp = THINGPTR(item);
83
84 /*
85 * Since we are fighting, things are not quiet so no healing takes
86 * place. The -1 also tells us that we are in a fight.
87 */
88 player.t_quiet = -1;
89 tp->t_quiet = -1;
90
91 see_def = ((off(*tp, ISINVIS) || on(player, CANSEE)) &&
92 (off(*tp, ISSHADOW) || on(player, CANSEE)) &&
93 (!thrown || cansee(unc(tp->t_pos))));
94
95 mname = see_def ? monster_name(tp) : "something";
96
97 /*
98 * if its in the wall, we can't hit it
99 */
100 if (on(*tp, ISINWALL) && off(player, CANINWALL))
101 return(FALSE);
102
103 if (on(*tp, ISSTONE)) {
104 killed(item, FALSE, FALSE, FALSE);
105 if (see_def)
106 msg("%s shatters into a million pieces!", prname(mname, TRUE));
107 count = 0;
108 return (TRUE);
109 }
110 /*
111 * Let him know it was really a mimic (if it was one).
112 */
113 if (on(*tp, ISDISGUISE) && (tp->t_type != tp->t_disguise) &&
114 off(player, ISBLIND))
115 {
116 if (see_def) {
117 msg("Wait! That's a %s!", mname);
118 turn_off(*tp, ISDISGUISE);
119 }
120 did_hit = thrown;
121 }
122 if (on(*tp, CANSURPRISE) && off(player, ISBLIND) && !ISWEARING(R_ALERT)) {
123 if (see_def) {
124 msg("Wait! There's a %s!", mname);
125 turn_off(*tp, CANSURPRISE);
126 }
127 did_hit = thrown;
128 }
129
130 /*
131 * if he's a thief or assassin and the creature is asleep then he gets
132 * a chance for a backstab
133 */
134 if ((player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN) &&
135 !thrown &&
136 !on(*tp, NOSTAB) &&
137 !invisible(tp) &&
138 (!on(*tp, ISRUN) || on(*tp, ISHELD) || tp->t_action == A_FREEZE))
139 back_stab = TRUE;
140
141 /*
142 * assassins get an assassination chance, if it fails then its normal
143 * damage
144 */
145 if (back_stab && player.t_ctype == C_ASSASSIN) {
146 int chance;
147
148 chance = 50 + (pstats.s_lvl - tp->t_stats.s_lvl) * 5;
149 if (cur_weapon && (cur_weapon->o_flags & ISPOISON))
150 chance += 20;
151 if (roll(1,100) > chance || on(*tp, ISUNIQUE))
152 back_stab = FALSE;
153 }
154
155 runto(tp, &hero);
156
157 /* Let the monster know that the player has missiles! */
158 if (thrown) tp->t_wasshot = TRUE;
159
160 if (did_hit)
161 {
162
163 did_hit = FALSE;
164 if (!can_blink(tp) &&
165 player_can_hit(tp, weap) &&
166 roll_em(&player, tp, weap, thrown, cur_weapon, back_stab))
167 {
168 did_hit = TRUE;
169
170 if (on(*tp, NOMETAL) && weap != NULL &&
171 weap->o_type != RELIC && weap->o_flags & ISMETAL) {
172 msg("Your %s passes right through %s!",
173 weaps[weap->o_which].w_name, prname(mname, FALSE));
174 }
175 else if (weap != NULL && weap->o_type == MISSILE && on(*tp, CARRYBAMULET)) {
176 msg("The magic missile has no effect on %s. ",
177 prname(mname, FALSE));
178 }
179 else {
180 hit(thrown ? (struct object *)NULL : weap,
181 TRUE, see_def,
182 thrown ? weap_name(weap) : NULL,
183 mname, back_stab, thrown, terse);
184
185 /* See if there are any special effects */
186 if (effect(&player, tp, weap, thrown, TRUE, see_def) != 0)
187 killed(item, FALSE, FALSE, TRUE);
188
189 /*
190 * Merchants just disappear if hit
191 */
192 else if (on(*tp, CANSELL)) {
193 if (see_def)
194 msg("%s disappears with his wares in a flash! ",
195 prname(mname, FALSE));
196 killed(item, FALSE, FALSE, FALSE);
197 }
198
199 else if (tp->t_stats.s_hpt <= 0)
200 killed(item, TRUE, TRUE, TRUE);
201
202 else {
203 /* If the victim was charmed, it now gets a saving throw! */
204 if (on(*tp, ISCHARMED) && save(VS_MAGIC, tp, 0)) {
205 msg("The eyes of %s turn clear.", prname(mname, FALSE));
206 turn_off(*tp, ISCHARMED);
207 }
208
209 dsrpt_monster(tp, FALSE, see_def); /* Disrupt a spell? */
210 }
211 }
212 }
213 else {
214 miss(thrown ? (struct object *)NULL : weap,
215 TRUE, see_def,
216 thrown ? weap_name(weap) : (char *)NULL,
217 mname, thrown, terse);
218 }
219 }
220 count = 0;
221 return did_hit;
222 }
223
224 /*
225 * attack:
226 * The monster attacks the player
227 */
228
229 attack(mp, weapon, thrown)
230 register struct thing *mp;
231 register struct object *weapon;
232 bool thrown;
233 {
234 register char *mname;
235 register bool see_att, did_hit = FALSE;
236 register struct object *wielded; /* The wielded weapon */
237 struct linked_list *get_wield; /* Linked list header for wielded */
238
239 /*
240 * Since this is an attack, stop running and any healing that was
241 * going on at the time. The -1 also tells us that we're fighting.
242 */
243 running = FALSE;
244 player.t_quiet = -1;
245 mp->t_quiet = -1;
246
247 if (on(*mp, ISDISGUISE) && off(player, ISBLIND))
248 turn_off(*mp, ISDISGUISE);
249
250 see_att = ((off(*mp, ISINVIS) || on(player, CANSEE)) &&
251 (off(*mp, ISSHADOW) || on(player, CANSEE)) &&
252 (!thrown || cansee(unc(mp->t_pos))));
253
254 mname = see_att ? monster_name(mp) : "something";
255
256 /*
257 * Try to find a weapon to wield. Wield_weap will return a
258 * projector if weapon is a projectile (eg. bow for arrow).
259 * If weapon is NULL, it will try to find a suitable weapon.
260 */
261 get_wield = wield_weap(weapon, mp);
262 if (get_wield) wielded = OBJPTR(get_wield);
263 else wielded = NULL;
264
265 /* If we aren't wielding a weapon, wield what we found (could be NULL) */
266 if (weapon == NULL) weapon = wielded;
267
268 if (roll_em(mp, &player, weapon, thrown, wielded, FALSE)) {
269 int death_type; /* From one of the effects of getting hit */
270
271 did_hit = TRUE;
272
273 if (weapon != NULL && weapon->o_type == MISSILE && cur_relic[STONEBONES_AMULET]) {
274 hit(weapon, see_att, TRUE, mname, (char *)NULL, FALSE, thrown, terse);
275 msg("Your amulet absorbs the magic missile. ");
276 }
277 else {
278 hit(weapon, see_att, TRUE, mname, (char *)NULL, FALSE, thrown, terse);
279 dsrpt_player(); /* see if we disrupted some activity */
280 if (pstats.s_hpt <= 0)
281 death(mp->t_index); /* Bye bye life ... */
282 death_type = effect(mp, &player, weapon, thrown, see_att, TRUE);
283 if (death_type != 0) {
284 pstats.s_hpt = -1;
285 death(death_type);
286 }
287 }
288
289 }
290 else {
291 /* If the thing was trying to surprise, no good */
292 if (on(*mp, CANSURPRISE)) turn_off(*mp, CANSURPRISE);
293
294 /* If it couldn't surprise, let's tell the player. */
295 else miss(weapon, see_att, TRUE, mname, (char *)NULL, thrown, terse);
296 }
297 if (fight_flush) flushinp();
298 count = 0;
299 status(FALSE);
300 return(did_hit);
301 }
302
303 /*
304 * swing:
305 * returns true if the swing hits
306 */
307
308 swing(class, at_lvl, op_arm, wplus)
309 short class;
310 int at_lvl, op_arm, wplus;
311 {
312 register int res = rnd(20)+1;
313 register int need;
314
315 need = char_class[class].base -
316 char_class[class].factor *
317 ((min(at_lvl, char_class[class].max_lvl) -
318 char_class[class].offset)/char_class[class].range) +
319 (10 - op_arm);
320 if (need > 20 && need <= 25) need = 20;
321
322 return (res+wplus >= need);
323 }
324
325 /*
326 * roll_em:
327 * Roll several attacks
328 */
329
330 roll_em(att_er, def_er, weap, hurl, cur_weapon, back_stab)
331 struct thing *att_er, *def_er;
332 struct object *weap;
333 bool hurl;
334 struct object *cur_weapon;
335 bool back_stab;
336 {
337 register struct stats *att, *def;
338 register char *cp = NULL;
339 register int ndice, nsides, nplus, def_arm;
340 char dmgbuf[20];
341 bool did_hit = FALSE;
342 int prop_hplus, prop_dplus;
343 int vampiric_damage;
344
345 /* Get statistics */
346 att = &att_er->t_stats;
347 def = &def_er->t_stats;
348
349 prop_hplus = prop_dplus = 0;
350 if (weap == NULL) {
351 /*
352 * monks damage grows with level
353 */
354 if (att == &pstats && player.t_ctype == C_MONK) {
355 sprintf(dmgbuf, "%dd4", att->s_lvl/3+2);
356 cp = dmgbuf;
357 }
358 else
359 cp = att->s_dmg;
360 }
361 else if (weap->o_type == RELIC) {
362 switch (weap->o_which) {
363 case MUSTY_DAGGER: