Mercurial > hg > early-roguelike
comparison arogue5/fight.c @ 63:0ed67132cf10
Import Advanced Rogue 5.8 from the Roguelike Restoration Project (r1490)
author | elwin |
---|---|
date | Thu, 09 Aug 2012 22:58:48 +0000 |
parents | |
children | 56e748983fa8 |
comparison
equal
deleted
inserted
replaced
62:0ef99244acb8 | 63:0ed67132cf10 |
---|---|
1 /* | |
2 * All the fighting gets done here | |
3 * | |
4 * Advanced Rogue | |
5 * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T | |
6 * All rights reserved. | |
7 * | |
8 * Based on "Rogue: Exploring the Dungeons of Doom" | |
9 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
10 * All rights reserved. | |
11 * | |
12 * See the file LICENSE.TXT for full copyright and licensing information. | |
13 */ | |
14 | |
15 #include "curses.h" | |
16 #include <ctype.h> | |
17 #include <string.h> | |
18 #include "rogue.h" | |
19 | |
20 #define CONF_DAMAGE -1 | |
21 #define PARAL_DAMAGE -2 | |
22 #define DEST_DAMAGE -3 | |
23 | |
24 static const struct matrix att_mat[5] = { | |
25 /* Base Max_lvl, Factor, Offset, Range */ | |
26 { 10, 25, 2, 1, 2 }, | |
27 { 9, 18, 2, 1, 5 }, | |
28 { 10, 19, 2, 1, 3 }, | |
29 { 10, 21, 2, 1, 4 }, | |
30 { 7, 25, 1, 0, 2 } | |
31 }; | |
32 | |
33 /* | |
34 * fight: | |
35 * The player attacks the monster. | |
36 */ | |
37 | |
38 fight(mp, weap, thrown) | |
39 register coord *mp; | |
40 struct object *weap; | |
41 bool thrown; | |
42 { | |
43 register struct thing *tp; | |
44 register struct linked_list *item; | |
45 register bool did_hit = TRUE; | |
46 bool back_stab = FALSE; | |
47 | |
48 /* | |
49 * Find the monster we want to fight | |
50 */ | |
51 if ((item = find_mons(mp->y, mp->x)) == NULL) { | |
52 return(FALSE); /* must have killed him already */ | |
53 } | |
54 tp = THINGPTR(item); | |
55 /* | |
56 * Since we are fighting, things are not quiet so no healing takes | |
57 * place. | |
58 */ | |
59 player.t_quiet = 0; | |
60 tp->t_quiet = 0; | |
61 | |
62 /* | |
63 * if its in the wall, we can't hit it | |
64 */ | |
65 if (on(*tp, ISINWALL) && off(player, CANINWALL)) | |
66 return(FALSE); | |
67 | |
68 /* | |
69 * Let him know it was really a mimic (if it was one). | |
70 */ | |
71 if (on(*tp, ISDISGUISE) && (tp->t_type != tp->t_disguise) && | |
72 off(player, ISBLIND)) | |
73 { | |
74 msg("Wait! That's a %s!", monsters[tp->t_index].m_name); | |
75 turn_off(*tp, ISDISGUISE); | |
76 did_hit = thrown; | |
77 } | |
78 if (on(*tp, CANSURPRISE) && off(player, ISBLIND) && !ISWEARING(R_ALERT)) { | |
79 msg("Wait! There's a %s!", monsters[tp->t_index].m_name); | |
80 turn_off(*tp, CANSURPRISE); | |
81 did_hit = thrown; | |
82 } | |
83 /* | |
84 * if he's a thief and the creature is asleep then he gets a chance | |
85 * for a backstab | |
86 */ | |
87 if (player.t_ctype == C_THIEF && | |
88 (!on(*tp, ISRUN) || on(*tp, ISHELD) || tp->t_no_move > 0)&& | |
89 !on(*tp, NOSTAB)) | |
90 back_stab = TRUE; | |
91 | |
92 runto(tp, &hero); | |
93 | |
94 if (did_hit) | |
95 { | |
96 register const char *mname; | |
97 | |
98 did_hit = FALSE; | |
99 mname = (on(player, ISBLIND)) ? "it" : monsters[tp->t_index].m_name; | |
100 if (!can_blink(tp) && | |
101 ( ((weap != NULL) && (weap->o_type == RELIC)) || | |
102 ((off(*tp, MAGICHIT) || ((weap != NULL) && (weap->o_hplus > 0 || weap->o_dplus > 0)) ) && | |
103 (off(*tp, BMAGICHIT) || ((weap != NULL) && (weap->o_hplus > 1 || weap->o_dplus > 1)) ) && | |
104 (off(*tp, CMAGICHIT) || ((weap != NULL) && (weap->o_hplus > 2 || weap->o_dplus > 2)) ) ) ) | |
105 && roll_em(&player, tp, weap, thrown, cur_weapon, back_stab)) | |
106 { | |
107 did_hit = TRUE; | |
108 | |
109 if (on(*tp, NOMETAL) && weap != NULL && | |
110 weap->o_type != RELIC && weap->o_flags & ISMETAL) { | |
111 sprintf(outstring,"Your %s passes right through the %s!", | |
112 weaps[weap->o_which].w_name, mname); | |
113 msg(outstring); | |
114 } | |
115 else if (thrown) { | |
116 tp->t_wasshot = TRUE; | |
117 thunk(weap, tp, mname); | |
118 } | |
119 else | |
120 hit(weap, tp, NULL, mname, back_stab); | |
121 | |
122 /* If the player hit a rust monster, he better have a + weapon */ | |
123 if (on(*tp, CANRUST) && !thrown && (weap != NULL) && | |
124 weap->o_type != RELIC && | |
125 (weap->o_flags & ISMETAL) && | |
126 !(weap->o_flags & ISPROT) && | |
127 (weap->o_hplus < 1) && (weap->o_dplus < 1)) { | |
128 if (rnd(100) < 50) weap->o_hplus--; | |
129 else weap->o_dplus--; | |
130 msg(terse ? "Your %s weakens!" | |
131 : "Your %s appears to be weaker now!", | |
132 weaps[weap->o_which].w_name); | |
133 } | |
134 | |
135 /* If the player hit something that shrieks, wake the dungeon */ | |
136 if (on(*tp, CANSHRIEK)) { | |
137 turn_off(*tp, CANSHRIEK); | |
138 msg("The %s emits a piercing shriek.", mname); | |
139 aggravate(); | |
140 } | |
141 | |
142 /* If the player hit something that can surprise, it can't now */ | |
143 if (on(*tp, CANSURPRISE)) turn_off(*tp, CANSURPRISE); | |
144 | |
145 | |
146 /* | |
147 * Can the player confuse? | |
148 */ | |
149 if (on(player, CANHUH) && !thrown) { | |
150 msg("Your hands stop glowing red"); | |
151 msg("The %s appears confused.", mname); | |
152 turn_on(*tp, ISHUH); | |
153 turn_off(player, CANHUH); | |
154 } | |
155 /* | |
156 * does the creature explode when hit? | |
157 */ | |
158 if (on(*tp, CANEXPLODE)) | |
159 explode(tp); | |
160 | |
161 /* | |
162 * Merchants just disappear if hit | |
163 */ | |
164 if (on(*tp, CANSELL)) { | |
165 msg("The %s disappears with his wares in a flash.",mname); | |
166 killed(item, FALSE, FALSE); | |
167 } | |
168 | |
169 else if (tp->t_stats.s_hpt <= 0) | |
170 killed(item, TRUE, TRUE); | |
171 | |
172 /* If the monster is fairly intelligent and about to die, it | |
173 * may turn tail and run. | |
174 */ | |
175 else if ((tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt/10)) && | |
176 (rnd(25) < tp->t_stats.s_intel)) { | |
177 turn_on(*tp, ISFLEE); | |
178 | |
179 /* If monster was suffocating, stop it */ | |
180 if (on(*tp, DIDSUFFOCATE)) { | |
181 turn_off(*tp, DIDSUFFOCATE); | |
182 extinguish(suffocate); | |
183 } | |
184 | |
185 /* If monster held us, stop it */ | |
186 if (on(*tp, DIDHOLD) && (--hold_count == 0)) | |
187 turn_off(player, ISHELD); | |
188 turn_off(*tp, DIDHOLD); | |
189 } | |
190 } | |
191 else { | |
192 if (thrown) | |
193 bounce(weap, tp, mname); | |
194 else | |
195 miss(weap, tp, NULL, mname); | |
196 } | |
197 } | |
198 count = 0; | |
199 return did_hit; | |
200 } | |
201 | |
202 /* | |
203 * attack: | |
204 * The monster attacks the player | |
205 */ | |
206 | |
207 attack(mp, weapon, thrown) | |
208 register struct thing *mp; | |
209 register struct object *weapon; | |
210 bool thrown; | |
211 { | |
212 register const char *mname; | |
213 register bool did_hit = FALSE; | |
214 register struct object *wielded; /* The wielded weapon */ | |
215 | |
216 /* | |
217 * Since this is an attack, stop running and any healing that was | |
218 * going on at the time. | |
219 */ | |
220 running = FALSE; | |
221 player.t_quiet = 0; | |
222 mp->t_quiet = 0; | |
223 | |
224 if (on(*mp, ISDISGUISE) && off(player, ISBLIND)) | |
225 turn_off(*mp, ISDISGUISE); | |
226 mname = on(player, ISBLIND) ? "it" : monsters[mp->t_index].m_name; | |
227 | |
228 /* | |
229 * Try to find a weapon to wield. Wield_weap will return a | |
230 * projector if weapon is a projectile (eg. bow for arrow). | |
231 * If weapon is NULL, it will try to find a suitable weapon. | |
232 */ | |
233 wielded = wield_weap(weapon, mp); | |
234 if (weapon == NULL) weapon = wielded; | |
235 | |
236 if (roll_em(mp, &player, weapon, thrown, wielded, FALSE)) { | |
237 did_hit = TRUE; | |
238 | |
239 if (thrown) m_thunk(weapon, mp, mname); | |
240 else hit(weapon, mp, mname, NULL, FALSE); | |
241 | |
242 if (pstats.s_hpt <= 0) | |
243 death(mp->t_index); /* Bye bye life ... */ | |
244 | |
245 /* | |
246 * suprising monsters appear after they shoot at you | |
247 */ | |
248 if (thrown) { | |
249 if (on(*mp, CANSURPRISE)) | |
250 turn_off(*mp, CANSURPRISE); | |
251 } | |
252 if (!thrown) { | |
253 /* | |
254 * If a vampire hits, it may take half your hit points | |
255 */ | |
256 if (on(*mp, CANSUCK) && !save(VS_MAGIC, &player, 0)) { | |
257 if (pstats.s_hpt == 1) death(mp->t_index); | |
258 else { | |
259 pstats.s_hpt /= 2; | |
260 msg("You feel your life force being drawn from you."); | |
261 } | |
262 } | |
263 | |
264 /* | |
265 * Stinking monsters make player weaker (to hit) | |
266 */ | |
267 if (on(*mp, CANSTINK)) { | |
268 turn_off(*mp, CANSTINK); | |
269 if (!save(VS_POISON, &player, 0)) { | |
270 msg("The stench of the %s sickens you.", mname); | |
271 if (on(player, HASSTINK)) lengthen(unstink, STINKTIME); | |
272 else { | |
273 turn_on(player, HASSTINK); | |
274 fuse(unstink, 0, STINKTIME, AFTER); | |
275 } | |
276 } | |
277 } | |
278 | |
279 /* | |
280 * Chilling monster reduces strength each time | |
281 */ | |
282 if (on(*mp, CANCHILL)) { | |
283 if (!ISWEARING(R_SUSABILITY) && !save(VS_POISON, &player, 0)) { | |
284 msg("You cringe at the %s's chilling touch.", mname); | |
285 chg_str(-1); | |
286 if (lost_str++ == 0) | |
287 fuse(res_strength, 0, CHILLTIME, AFTER); | |
288 else lengthen(res_strength, CHILLTIME); | |
289 } | |
290 } | |
291 | |
292 /* | |
293 * itching monsters reduce dexterity (temporarily) | |
294 */ | |
295 if (on(*mp, CANITCH) && !save(VS_POISON, &player, 0)) { | |
296 msg("The claws of the %s scratch you", mname); | |
297 if(ISWEARING(R_SUSABILITY)) { | |
298 msg("The scratch has no effect"); | |
299 } | |
300 else { | |
301 turn_on(player, HASITCH); | |
302 add_dexterity(TRUE); | |
303 lost_dext++; | |
304 fuse(un_itch, 0, roll(HEALTIME,SICKTIME), AFTER); | |
305 } | |
306 } | |
307 | |
308 | |
309 /* | |
310 * If a hugging monster hits, it may SQUEEEEEEEZE | |
311 */ | |
312 if (on(*mp, CANHUG)) { | |
313 if (roll(1,20) >= 18 || roll(1,20) >= 18) { | |
314 msg("The %s squeezes you against itself.", mname); | |
315 if ((pstats.s_hpt -= roll(2,8)) <= 0) | |
316 death(mp->t_index); | |
317 } | |
318 } | |
319 | |
320 /* | |
321 * If a disease-carrying monster hits, there is a chance the | |
322 * player will catch the disease | |
323 */ | |
324 if (on(*mp, CANDISEASE) && | |
325 (rnd(pstats.s_const) < mp->t_stats.s_lvl) && | |
326 off(player, HASDISEASE)) { | |
327 if (ISWEARING(R_HEALTH)) msg("The wound heals quickly."); | |
328 else { | |
329 turn_on(player, HASDISEASE); | |
330 fuse(cure_disease, 0, roll(HEALTIME,SICKTIME), AFTER); | |
331 msg(terse ? "You have been diseased." | |
332 : "You have contracted a disease!"); | |
333 } | |
334 } | |
335 | |
336 /* | |
337 * If a rust monster hits, you lose armor | |
338 */ | |
339 if (on(*mp, CANRUST)) { | |
340 if (cur_armor != NULL && | |
341 cur_armor->o_which != LEATHER && | |
342 cur_armor->o_which != STUDDED_LEATHER && | |
343 cur_armor->o_which != PADDED_ARMOR && | |
344 !(cur_armor->o_flags & ISPROT) && | |
345 cur_armor->o_ac < pstats.s_arm+1 ) { | |
346 msg(terse ? "Your armor weakens" | |
347 : "Your armor appears to be weaker now. Oh my!"); | |
348 cur_armor->o_ac++; | |
349 } | |
350 if (cur_misc[WEAR_BRACERS] != NULL && | |
351 cur_misc[WEAR_BRACERS]->o_ac > 0 && | |
352 !(cur_misc[WEAR_BRACERS]->o_flags & ISPROT)) { | |
353 cur_misc[WEAR_BRACERS]->o_ac--; | |
354 if (cur_misc[WEAR_BRACERS]->o_ac == 0) { | |
355 register struct linked_list *item; | |
356 | |
357 for (item=pack; item!=NULL; item=next(item)) { | |
358 if (OBJPTR(item) == cur_misc[WEAR_BRACERS]) { | |
359 detach(pack, item); | |
360 o_discard(item); | |
361 break; | |
362 } | |
363 } | |
364 msg ("Your bracers crumble and fall off!"); | |
365 cur_misc[WEAR_BRACERS] = NULL; | |
366 inpack--; | |
367 } | |
368 else { | |
369 msg("Your bracers weaken!"); | |
370 } | |
371 } | |
372 } | |
373 /* | |
374 * If can dissolve and hero has leather type armor | |
375 */ | |
376 if (on(*mp, CANDISSOLVE) && cur_armor != NULL && | |
377 (cur_armor->o_which == LEATHER || | |
378 cur_armor->o_which == STUDDED_LEATHER || | |
379 cur_armor->o_which == PADDED_ARMOR) && | |
380 !(cur_armor->o_flags & ISPROT) && | |
381 cur_armor->o_ac < pstats.s_arm+1) { | |
382 msg(terse ? "Your armor dissolves" | |
383 : "Your armor appears to dissolve. Oh my!"); | |
384 cur_armor->o_ac++; | |
385 } | |
386 | |
387 /* If a surprising monster hit you, you can see it now */ | |
388 if (on(*mp, CANSURPRISE)) turn_off(*mp, CANSURPRISE); | |
389 | |
390 /* | |
391 * If an infesting monster hits you, you get a parasite or rot | |
392 */ | |
393 if (on(*mp, CANINFEST) && rnd(pstats.s_const) < mp->t_stats.s_lvl) { | |
394 if (ISWEARING(R_HEALTH)) msg("The wound quickly heals."); | |
395 else { | |
396 turn_off(*mp, CANINFEST); | |
397 msg(terse ? "You have been infested." | |
398 : "You have contracted a parasitic infestation!"); | |
399 infest_dam++; | |
400 turn_on(player, HASINFEST); | |
401 } | |
402 } | |
403 | |
404 /* | |
405 * Ants have poisonous bites | |
406 */ | |
407 if (on(*mp, CANPOISON) && !save(VS_POISON, &player, 0)) { | |
408 if (ISWEARING(R_SUSABILITY)) | |
409 msg(terse ? "Sting has no effect" | |
410 : "A sting momentarily weakens you"); | |
411 else { | |
412 chg_str(-1); | |
413 msg(terse ? "A sting has weakened you" : | |
414 "You feel a sting in your arm and now feel weaker"); | |
415 } | |
416 } | |
417 /* | |
418 * does it take wisdom away? | |
419 */ | |
420 if (on(*mp, TAKEWISDOM) && | |
421 !save(VS_MAGIC, &player, 0) && | |
422 !ISWEARING(R_SUSABILITY)) { | |
423 add_wisdom(TRUE); | |
424 } | |
425 /* | |
426 * does it take intelligence away? | |
427 */ | |
428 if (on(*mp, TAKEINTEL) && | |
429 !save(VS_MAGIC, &player, 0) && | |
430 !ISWEARING(R_SUSABILITY)) { | |
431 add_intelligence(TRUE); | |
432 } | |
433 /* | |
434 * Cause fear by touching | |
435 */ | |
436 if (on(*mp, TOUCHFEAR)) { | |
437 turn_off(*mp, TOUCHFEAR); | |
438 if (!ISWEARING(R_HEROISM) && | |
439 !save(VS_WAND, &player, 0) && | |
440 !(on(player, ISFLEE) && (player.t_dest == &mp->t_pos))) { | |
441 turn_on(player, ISFLEE); | |
442 player.t_dest = &mp->t_pos; | |
443 msg("The %s's touch terrifies you.", mname); | |
444 } | |
445 } | |
446 | |
447 /* | |
448 * make the hero dance (as in otto's irresistable dance) | |
449 */ | |
450 if (on(*mp, CANDANCE) && | |
451 !on(player, ISDANCE) && | |
452 !save(VS_MAGIC, &player, -4)) { | |
453 turn_off(*mp, CANDANCE); | |
454 turn_on(player, ISDANCE); | |
455 msg("You begin to dance uncontrollably!"); | |
456 fuse(undance, 0, roll(2,4), AFTER); | |
457 } | |
458 | |
459 /* | |
460 * Suffocating our hero | |
461 */ | |
462 if (on(*mp, CANSUFFOCATE) && (rnd(100) < 15) && | |
463 (find_slot(suffocate) == FALSE)) { | |
464 turn_on(*mp, DIDSUFFOCATE); | |
465 msg("The %s is beginning to suffocate you.", mname); | |
466 fuse(suffocate, 0, roll(4,2), AFTER); | |
467 } | |
468 | |
469 /* | |
470 * Turning to stone | |
471 */ | |
472 if (on(*mp, TOUCHSTONE)) { | |
473 turn_off(*mp, TOUCHSTONE); | |
474 if (on(player, CANINWALL)) | |
475 msg("The %s's touch has no effect.", mname); | |
476 else { | |
477 if (!save(VS_PETRIFICATION, &player, 0) && rnd(100) < 15) { | |
478 msg("Your body begins to solidify."); | |
479 msg("You are turned to stone !!! --More--"); | |
480 wait_for(cw,' '); | |
481 death(D_PETRIFY); | |
482 } | |
483 else { | |
484 msg("The %s's touch stiffens your limbs.", mname); | |
485 no_command += STONETIME; | |
486 } | |
487 } | |
488 } | |
489 | |
490 /* | |
491 * Wraiths might drain energy levels | |
492 */ | |
493 if ((on(*mp, CANDRAIN) || on(*mp, DOUBLEDRAIN)) && rnd(100) < 15) { | |
494 lower_level(mp->t_index); | |
495 if (on(*mp, DOUBLEDRAIN)) lower_level(mp->t_index); | |
496 turn_on(*mp, DIDDRAIN); | |
497 } | |
498 | |
499 /* | |
500 * Violet fungi stops the poor guy from moving | |
501 */ | |
502 if (on(*mp, CANHOLD) && off(*mp, DIDHOLD)) { | |
503 turn_on(player, ISHELD); | |
504 turn_on(*mp, DIDHOLD); | |
505 hold_count++; | |
506 } | |
507 | |
508 /* | |
509 * Sucker will suck blood and run | |
510 */ | |
511 if (on(*mp, CANDRAW)) { | |
512 turn_off(*mp, CANDRAW); | |
513 turn_on(*mp, ISFLEE); | |
514 msg("The %s sates itself with your blood.", mname); | |
515 if ((pstats.s_hpt -= 12) <= 0) death(mp->t_index); | |
516 } | |
517 | |
518 /* | |
519 * Bad smell will force a reduction in strength | |
520 */ | |
521 if (on(*mp, CANSMELL)) { | |
522 turn_off(*mp, CANSMELL); | |
523 if (save(VS_MAGIC, &player, 0) || ISWEARING(R_SUSABILITY)) | |
524 msg("You smell an unpleasant odor."); | |
525 else { | |
526 int odor_str = -(rnd(6)+1); | |
527 | |
528 msg("You are overcome by a foul odor."); | |
529 if (lost_str == 0) { | |
530 chg_str(odor_str); | |
531 fuse(res_strength, 0, SMELLTIME, AFTER); | |
532 lost_str -= odor_str; | |
533 } | |
534 else lengthen(res_strength, SMELLTIME); | |
535 } | |
536 } | |
537 | |
538 /* | |
539 * Paralyzation | |
540 */ | |
541 if (on(*mp, CANPARALYZE)) { | |
542 turn_off(*mp, CANPARALYZE); | |
543 if (!save(VS_PARALYZATION, &player, 0)) { | |
544 if (on(player, CANINWALL)) | |
545 msg("The %s's touch has no effect.", mname); | |
546 else { | |
547 msg("The %s's touch paralyzes you.", mname); | |
548 no_command += FREEZETIME; | |
549 } | |
550 } | |
551 } | |
552 | |
553 /* | |
554 * Painful wounds make you faint | |
555 */ | |
556 if (on(*mp, CANPAIN)) { | |
557 turn_off(*mp, CANPAIN); | |
558 if (!ISWEARING(R_ALERT) && !save(VS_POISON, &player, 0)) { | |
559 msg("You faint from the painful wound"); | |
560 no_command += PAINTIME; | |
561 } | |
562 } | |
563 | |
564 /* | |
565 * The monsters touch slows the hero down | |
566 */ | |
567 if (on(*mp, CANSLOW)) { | |
568 turn_off(*mp, CANSLOW); | |
569 if (!save(VS_PARALYZATION, &player, 0)) | |
570 add_slow(); | |
571 } | |
572 | |
573 /* | |
574 * Rotting | |
575 */ | |
576 if (on(*mp, CANROT)) { | |
577 if (!ISWEARING(R_HEALTH) && | |
578 !save(VS_POISON, &player, 0) && | |
579 off(player, DOROT)) { | |
580 turn_on(player, DOROT); | |
581 msg("You feel your skin starting to rot away!"); | |
582 } | |
583 } | |
584 | |
585 if (on(*mp, STEALGOLD)) { | |
586 /* | |
587 * steal some gold | |
588 */ | |
589 register long lastpurse; | |
590 register struct linked_list *item; | |
591 register struct object *obj; | |
592 | |
593 lastpurse = purse; | |
594 purse -= GOLDCALC + GOLDCALC; | |
595 if (!save(VS_MAGIC, &player, mp->t_stats.s_lvl/10)) { | |
596 if (on(*mp, ISUNIQUE)) | |
597 purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; | |
598 purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; | |
599 } | |
600 if (purse < 0) | |
601 purse = 0; | |
602 if (purse != lastpurse) { | |
603 msg("Your purse feels lighter"); | |
604 | |
605 /* Give the gold to the thief */ | |
606 for (item=mp->t_pack; item != NULL; item=next(item)) { | |
607 obj = OBJPTR(item); | |
608 if (obj->o_type == GOLD) { | |
609 obj->o_count += lastpurse - purse; | |
610 break; | |
611 } | |
612 } | |
613 | |
614 /* Did we do it? */ | |
615 if (item == NULL) { /* Then make some */ | |
616 item = new_item(sizeof *obj); | |
617 obj = OBJPTR(item); | |
618 obj->o_type = GOLD; | |
619 obj->o_count = lastpurse - purse; | |
620 obj->o_hplus = obj->o_dplus = 0; | |
621 strcpy(obj->o_damage,"0d0"); | |
622 strcpy(obj->o_hurldmg,"0d0"); | |
623 obj->o_ac = 11; | |
624 obj->contents = NULL; | |
625 obj->o_group = 0; | |
626 obj->o_flags = 0; | |
627 obj->o_mark[0] = '\0'; | |
628 obj->o_pos = mp->t_pos; | |
629 | |
630 attach(mp->t_pack, item); | |
631 } | |
632 } | |
633 | |
634 turn_on(*mp, ISFLEE); | |
635 turn_on(*mp, ISINVIS); | |
636 } | |
637 | |
638 if (on(*mp, STEALMAGIC)) { | |
639 register struct linked_list *list, *steal; | |
640 register struct object *obj; | |
641 register int nobj; | |
642 | |
643 /* | |
644 * steal a magic item, look through the pack | |
645 * and pick out one we like. | |
646 */ | |
647 steal = NULL; | |
648 for (nobj = 0, list = pack; list != NULL; list = next(list)) | |
649 { | |
650 obj = OBJPTR(list); | |
651 if (!is_current(obj) && | |
652 is_magic(obj) && | |
653 rnd(++nobj) == 0) | |
654 steal = list; | |
655 } | |
656 if (steal != NULL) | |
657 { | |
658 register struct object *obj; | |
659 struct linked_list *item; | |
660 | |
661 obj = OBJPTR(steal); | |
662 if (on(*mp, ISUNIQUE)) | |
663 monsters[mp->t_index].m_normal = TRUE; | |
664 item = find_mons(mp->t_pos.y, mp->t_pos.x); | |
665 killed(item, FALSE, FALSE); | |
666 if (obj->o_count > 1 && obj->o_group == 0) { | |
667 register int oc; | |
668 | |
669 oc = --(obj->o_count); | |
670 obj->o_count = 1; | |
671 sprintf(outstring,"The %s stole %s!", mname, inv_name(obj, TRUE)); | |
672 msg(outstring); | |
673 obj->o_count = oc; | |
674 } | |
675 else { | |
676 sprintf(outstring,"The %s stole %s!", mname, inv_name(obj, TRUE)); | |
677 msg(outstring); | |
678 detach(pack, steal); | |
679 | |
680 /* If this is a relic, clear its holding field */ | |
681 if (obj->o_type == RELIC) | |
682 cur_relic[obj->o_which] = 0; | |
683 | |
684 o_discard(steal); | |
685 inpack--; | |
686 } | |
687 updpack(FALSE); | |
688 } | |
689 } | |
690 } | |
691 } | |
692 else { | |
693 /* If the thing was trying to surprise, no good */ | |
694 if (on(*mp, CANSURPRISE)) turn_off(*mp, CANSURPRISE); | |
695 | |
696 else if (thrown) m_bounce(weapon, mp, mname); | |
697 else miss(weapon, mp, mname, NULL); | |
698 } | |
699 if (fight_flush) | |
700 md_flushinp(); | |
701 count = 0; | |
702 status(FALSE); | |
703 return(did_hit); | |
704 } | |
705 | |
706 /* | |
707 * swing: | |
708 * returns true if the swing hits | |
709 */ | |
710 | |
711 swing(class, at_lvl, op_arm, wplus) | |
712 short class; | |
713 int at_lvl, op_arm, wplus; | |
714 { | |
715 register int res = rnd(20)+1; | |
716 register int need; | |
717 | |
718 need = att_mat[class].base - | |
719 att_mat[class].factor * | |
720 ((min(at_lvl, att_mat[class].max_lvl) - | |
721 att_mat[class].offset)/att_mat[class].range) + | |
722 (10 - op_arm); | |
723 if (need > 20 && need <= 25) need = 20; | |
724 | |
725 return (res+wplus >= need); | |
726 } | |
727 | |
728 /* | |
729 * roll_em: | |
730 * Roll several attacks | |
731 */ | |
732 | |
733 roll_em(att_er, def_er, weap, hurl, cur_weapon, back_stab) | |
734 struct thing *att_er, *def_er; | |
735 struct object *weap; | |
736 bool hurl; | |
737 struct object *cur_weapon; | |
738 bool back_stab; | |
739 { | |
740 register struct stats *att, *def; | |
741 register char *cp = NULL; | |
742 register int ndice, nsides, nplus, def_arm; | |
743 bool did_hit = FALSE; | |
744 int prop_hplus, prop_dplus; | |
745 int vampiric_damage; | |
746 | |
747 /* Get statistics */ | |
748 att = &att_er->t_stats; | |
749 def = &def_er->t_stats; | |
750 | |
751 prop_hplus = prop_dplus = 0; | |
752 if (weap == NULL) | |
753 cp = att->s_dmg; | |
754 else if (hurl) { | |
755 if ((weap->o_flags&ISMISL) && cur_weapon != NULL && | |
756 cur_weapon->o_which == weap->o_launch) | |
757 { | |
758 cp = weap->o_hurldmg; | |
759 prop_hplus = cur_weapon->o_hplus; | |
760 prop_dplus = cur_weapon->o_dplus; | |
761 } | |
762 else | |
763 cp = (weap->o_flags&ISMISL ? weap->o_damage : weap->o_hurldmg); | |
764 } | |
765 else { | |
766 if (weap->o_type == RELIC) { | |
767 switch (weap->o_which) { | |
768 case MUSTY_DAGGER: cp = "1d4+1/1d4+1"; | |
769 when YEENOGHU_FLAIL: cp = "3d6/paralyze/confuse"; | |
770 when HRUGGEK_MSTAR: cp = "3d10"; | |
771 when MING_STAFF: cp = "1d8"; | |
772 when ASMO_ROD: cp = "2d8+1"; | |
773 when ORCUS_WAND: cp = "destroy"; | |
774 } | |
775 } | |
776 else cp = weap->o_damage; | |
777 /* | |
778 * Drain a staff of striking | |
779 */ | |
780 if (weap->o_type == STICK && weap->o_which == WS_HIT | |
781 && weap->o_charges == 0) | |
782 { | |
783 strcpy(weap->o_damage,"0d0"); | |
784 weap->o_hplus = weap->o_dplus = 0; | |
785 } | |
786 } | |
787 for (;;) | |
788 { | |
789 int damage; | |
790 int hplus = prop_hplus; | |
791 int dplus = prop_dplus; | |
792 | |
793 if (weap != NULL && weap->o_type == RELIC) { | |
794 switch (weap->o_which) { | |
795 case MUSTY_DAGGER: | |
796 if (att != &pstats || /* Not player or good stats */ | |
797 (str_compute() > 15 && dex_compute() > 15)) { | |
798 | |
799 hplus += 6; | |
800 dplus += 6; | |
801 | |
802 /* Give an additional strength and dex bonus */ | |
803 if (att == &pstats) { | |
804 hplus += str_plus(str_compute()) + | |
805 dext_plus(dex_compute()); | |
806 dplus += dext_plus(dex_compute()) + | |
807 add_dam(str_compute()); | |
808 } | |
809 else { | |
810 hplus += str_plus(att->s_str) + | |
811 dext_plus(att->s_dext); | |
812 dplus += dext_plus(att->s_dext) + | |
813 add_dam(att->s_str); | |
814 } | |
815 } | |
816 else { | |
817 hplus -= 3; | |
818 dplus -= 3; | |
819 } | |
820 when YEENOGHU_FLAIL: | |
821 case HRUGGEK_MSTAR: | |
822 hplus += 3; | |
823 dplus += 3; | |
824 when MING_STAFF: | |
825 hplus += 2; | |
826 dplus += 2; | |
827 } | |
828 } | |
829 else if (weap != NULL) { | |
830 hplus += weap->o_hplus; | |
831 dplus += weap->o_dplus; | |
832 } | |
833 | |
834 /* Is attacker weak? */ | |
835 if (on(*att_er, HASSTINK)) hplus -= 2; | |
836 | |
837 if (att == &pstats) /* Is the attacker the player? */ | |
838 { | |
839 hplus += hitweight(); /* adjust for encumberence */ | |
840 dplus += hung_dam(); /* adjust damage for hungry player */ | |
841 dplus += ring_value(R_ADDDAM); | |
842 } | |
843 if (back_stab || (weap && att != &pstats && on(*att_er, CANBSTAB))) | |
844 hplus += 4; /* add in pluses for backstabbing */ | |
845 | |
846 /* Get the damage */ | |
847 while (isspace(*cp)) cp++; | |
848 if (!isdigit(*cp)) { | |
849 if (strncmp(cp, "confuse", 7) == 0) ndice = CONF_DAMAGE; | |
850 else if (strncmp(cp, "paralyze", 8) == 0) ndice = PARAL_DAMAGE; | |
851 else if (strncmp(cp, "destroy", 7) == 0) ndice = DEST_DAMAGE; | |
852 else ndice = 0; | |
853 nsides = 0; | |
854 nplus = 0; | |
855 } | |
856 else { | |
857 char *oldcp; | |
858 | |
859 /* Get the number of damage dice */ | |
860 ndice = atoi(cp); | |
861 if ((cp = strchr(cp, 'd')) == NULL) | |
862 break; | |
863 | |
864 /* Skip the 'd' and get the number of sides per die */ | |
865 nsides = atoi(++cp); | |
866 | |
867 /* Check for an addition -- save old place in case none is found */ | |
868 oldcp = cp; | |
869 if ((cp = strchr(cp, '+')) != NULL) nplus = atoi(++cp); | |
870 else { | |
871 nplus = 0; | |
872 cp = oldcp; | |
873 } | |
874 } | |
875 | |
876 if (def == &pstats) { /* Monster attacks player */ | |
877 def_arm = ac_compute() - dext_prot(dex_compute()); | |
878 hplus += str_plus(att->s_str)+dext_plus(att->s_dext); | |
879 } | |
880 else { /* Player attacks monster */ | |
881 def_arm = def->s_arm - dext_prot(def->s_dext); | |
882 hplus += str_plus(str_compute())+dext_plus(dex_compute()); | |
883 } | |
884 | |
885 if (swing(att_er->t_ctype, att->s_lvl, def_arm, hplus)) { | |
886 register int proll; | |
887 | |
888 /* Take care of special effects */ | |
889 switch (ndice) { | |
890 case CONF_DAMAGE: | |
891 if (def == &pstats) { /* Monster attacks player */ | |
892 if (!save(VS_MAGIC, &player, 0) && off(player, ISCLEAR)) { | |
893 msg("You feel disoriented."); | |
894 if (find_slot(unconfuse)) | |
895 lengthen(unconfuse, rnd(8)+HUHDURATION); | |
896 else | |
897 fuse(unconfuse, 0, rnd(8)+HUHDURATION, AFTER); | |
898 turn_on(player, ISHUH); | |
899 } | |
900 else msg("You feel dizzy, but it quickly passes."); | |
901 } | |
902 /* Player hits monster */ | |
903 else if (!save(VS_MAGIC, def_er, 0) && off(*def_er, ISCLEAR)) { | |
904 msg("The artifact warms with pleasure."); | |
905 turn_on(*def_er, ISHUH); | |
906 } | |
907 did_hit = TRUE; | |
908 when PARAL_DAMAGE: | |
909 if (def == &pstats) { /* Monster attacks player */ | |
910 if (!save(VS_MAGIC, &player, 0) && off(player, CANINWALL)) { | |
911 msg("You stiffen up."); | |
912 no_command += FREEZETIME; | |
913 } | |
914 } | |
915 else if (!save(VS_MAGIC, def_er, 0)) { /* Player hits monster */ | |
916 msg("The artifact hums happily."); | |
917 turn_off(*def_er, ISRUN); | |
918 turn_on(*def_er, ISHELD); | |
919 } | |
920 did_hit = TRUE; | |
921 when DEST_DAMAGE: | |
922 if (def == &pstats) { /* Monster attacks player */ | |
923 msg("You feel a tug at your life force."); | |
924 if (!save(VS_MAGIC, &player, -4)) { | |
925 msg("The wand devours your soul."); | |
926 def->s_hpt = 0; | |
927 } | |
928 } | |
929 /* Player hits monster */ | |
930 else if (!save(VS_MAGIC, def_er, -4)) { | |
931 msg("The artifact draws energy."); | |
932 | |
933 /* Give the player half the monster's hits */ | |
934 att->s_hpt += def->s_hpt/2; | |
935 if (att->s_hpt > att_er->maxstats.s_hpt) | |
936 att->s_hpt = att_er->maxstats.s_hpt; | |
937 | |
938 /* Kill the monster */ | |
939 def->s_hpt = 0; | |
940 } | |
941 did_hit = TRUE; | |
942 otherwise: | |
943 /* Heil's ankh always gives maximum damage */ | |
944 if (att == &pstats && cur_relic[HEIL_ANKH]) | |
945 proll = ndice * nsides; | |
946 else proll = roll(ndice, nsides); | |
947 | |
948 if (ndice + nsides > 0 && proll < 1) | |
949 debug("Damage for %dd%d came out %d.", | |
950 ndice, nsides, proll); | |
951 damage = dplus + proll + nplus; | |
952 if (def == &pstats) | |
953 damage += add_dam(att->s_str); | |
954 else | |
955 damage += add_dam(str_compute()); | |
956 | |
957 /* Check for half damage monsters */ | |
958 if (on(*def_er, HALFDAMAGE)) damage /= 2; | |
959 | |
960 /* add in multipliers for backstabbing */ | |
961 if (back_stab || | |
962 (weap && att != &pstats && on(*att_er, CANBSTAB))) { | |
963 int mult = 2 + (att->s_lvl-1)/4; /* Normal multiplier */ | |
964 | |
965 if (mult > 5 && att != &pstats) | |
966 mult = 5;/*be nice with maximum of 5x for monsters*/ | |
967 if (weap->o_type == RELIC && weap->o_which == MUSTY_DAGGER) | |
968 mult++; | |
969 damage *= mult; | |
970 } | |
971 | |
972 /* Check for no-damage and division */ | |
973 if (on(*def_er, BLOWDIVIDE)) { | |
974 damage = 0; | |
975 creat_mons(def_er, def_er->t_index, FALSE); | |
976 light(&hero); | |
977 } | |
978 /* check for immunity to metal -- RELICS are always bad */ | |
979 if (on(*def_er, NOMETAL) && weap != NULL && | |
980 weap->o_type != RELIC && weap->o_flags & ISMETAL) { | |
981 damage = 0; | |
982 } | |
983 | |
984 /* | |
985 * If defender is wearing a cloak of displacement -- no damage | |
986 * the first time. (unless its a hurled magic missile) | |
987 */ | |
988 if ( ((weap == NULL) || weap->o_type != MISSILE) && | |
989 def == &pstats && | |
990 cur_misc[WEAR_CLOAK] != NULL && | |
991 cur_misc[WEAR_CLOAK]->o_which == MM_DISP && | |
992 off(*att_er, MISSEDDISP)) { | |
993 damage = 0; | |
994 did_hit = FALSE; | |
995 turn_on(*att_er, MISSEDDISP); | |
996 if (cansee(att_er->t_pos.y, att_er->t_pos.x) && | |
997 !invisible(att_er)) | |
998 msg("The %s looks amazed", | |
999 monsters[att_er->t_index].m_name); | |
1000 } | |
1001 else { | |
1002 def->s_hpt -= max(0, damage); /* Do the damage */ | |
1003 did_hit = TRUE; | |
1004 } | |
1005 | |
1006 vampiric_damage = damage; | |
1007 if (def->s_hpt < 0) /* only want REAL damage inflicted */ | |
1008 vampiric_damage += def->s_hpt; | |
1009 if (vampiric_damage < 0) | |
1010 vampiric_damage = 0; | |
1011 if (att == &pstats && ISWEARING(R_VAMPREGEN) && !hurl) { | |
1012 if ((pstats.s_hpt += vampiric_damage/2) > max_stats.s_hpt) | |
1013 pstats.s_hpt = max_stats.s_hpt; | |
1014 } | |
1015 debug ("hplus=%d dmg=%d", hplus, damage); | |
1016 } | |
1017 } | |
1018 if ((cp = strchr(cp, '/')) == NULL) | |
1019 break; | |
1020 cp++; | |
1021 } | |
1022 return did_hit; | |
1023 } | |
1024 | |
1025 /* | |
1026 * prname: | |
1027 * The print name of a combatant | |
1028 */ | |
1029 | |
1030 char * | |
1031 prname(who, upper) | |
1032 register char *who; | |
1033 bool upper; | |
1034 { | |
1035 static char tbuf[LINELEN]; | |
1036 | |
1037 *tbuf = '\0'; | |
1038 if (who == 0) | |
1039 strcpy(tbuf, "you"); | |
1040 else if (on(player, ISBLIND)) | |
1041 strcpy(tbuf, "it"); | |
1042 else | |
1043 { | |
1044 strcpy(tbuf, "the "); | |
1045 strcat(tbuf, who); | |
1046 } | |
1047 if (upper) | |
1048 *tbuf = toupper(*tbuf); | |
1049 return tbuf; | |
1050 } | |
1051 | |
1052 /* | |
1053 * hit: | |
1054 * Print a message to indicate a succesful hit | |
1055 */ | |
1056 | |
1057 hit(weapon, tp, er, ee, back_stab) | |
1058 register struct object *weapon; | |
1059 register struct thing *tp; | |
1060 register char *er, *ee; | |
1061 bool back_stab; | |
1062 { | |
1063 register char *s = NULL; | |
1064 char | |
1065 att_name[80], /* Name of attacker */ | |
1066 def_name[80];/* Name of defender */ | |
1067 bool see_monst = !invisible(tp); /* Can the player see the monster? */ | |
1068 | |
1069 /* What do we call the attacker? */ | |
1070 if (er == NULL) { /* Player is attacking */ | |
1071 strcpy(att_name, prname(er, TRUE)); | |
1072 strcpy(def_name, see_monst ? prname(ee, FALSE) : "something"); | |
1073 } | |
1074 else { | |
1075 strcpy(att_name, see_monst ? prname(er, TRUE) : "Something"); | |
1076 | |
1077 /* If the monster is using a weapon and we can see it, report it */ | |
1078 if (weapon != NULL && see_monst) { | |
1079 strcat(att_name, "'s "); | |
1080 strcat(att_name, weap_name(weapon)); | |
1081 } | |
1082 | |
1083 strcpy(def_name, prname(ee, FALSE)); | |
1084 } | |
1085 | |
1086 addmsg(att_name); | |
1087 if (terse) { | |
1088 if (back_stab) | |
1089 s = " backstab!"; | |
1090 else | |
1091 s = " hit."; | |
1092 } | |
1093 else { | |
1094 if (back_stab) | |
1095 s = (er == 0 ? " have backstabbed " : " has backstabbed "); | |
1096 else { | |
1097 switch (rnd(4)) | |
1098 { | |
1099 case 0: s = " scored an excellent hit on "; | |
1100 when 1: s = " hit "; | |
1101 when 2: s = (er == 0 ? " have injured " : " has injured "); | |
1102 when 3: s = (er == 0 ? " swing and hit " : " swings and hits "); | |
1103 } | |
1104 } | |
1105 } | |
1106 addmsg(s); | |
1107 if (!terse) | |
1108 addmsg(def_name); | |
1109 endmsg(); | |
1110 } | |
1111 | |
1112 /* | |
1113 * miss: | |
1114 * Print a message to indicate a poor swing | |
1115 */ | |
1116 | |
1117 miss(weapon, tp, er, ee) | |
1118 register struct object *weapon; | |
1119 register struct thing *tp; | |
1120 register char *er, *ee; | |
1121 { | |
1122 register char *s = NULL; | |
1123 char | |
1124 att_name[80], /* Name of attacker */ | |
1125 def_name[80];/* Name of defender */ | |
1126 bool see_monst = !invisible(tp); /* Can the player see the monster? */ | |
1127 | |
1128 /* What do we call the attacker? */ | |
1129 if (er == NULL) { /* Player is attacking */ | |
1130 strcpy(att_name, prname(er, TRUE)); | |
1131 strcpy(def_name, see_monst ? prname(ee, FALSE) : "something"); | |
1132 } | |
1133 else { | |
1134 strcpy(att_name, see_monst ? prname(er, TRUE) : "Something"); | |
1135 | |
1136 /* If the monster is using a weapon and we can see it, report it */ | |
1137 if (weapon != NULL && see_monst) { | |
1138 strcat(att_name, "'s "); | |
1139 strcat(att_name, weap_name(weapon)); | |
1140 } | |
1141 | |
1142 strcpy(def_name, prname(ee, FALSE)); | |
1143 } | |
1144 | |
1145 addmsg(att_name); | |
1146 switch (terse ? 0 : rnd(4)) | |
1147 { | |
1148 case 0: s = (er == 0 ? " miss" : " misses"); | |
1149 when 1: s = (er == 0 ? " swing and miss" : " swings and misses"); | |
1150 when 2: s = (er == 0 ? " barely miss" : " barely misses"); | |
1151 when 3: s = (er == 0 ? " don't hit" : " doesn't hit"); | |
1152 } | |
1153 addmsg(s); | |
1154 if (!terse) | |
1155 addmsg(" %s", def_name); | |
1156 endmsg(); | |
1157 } | |
1158 | |
1159 /* | |
1160 * dext_plus: | |
1161 * compute to-hit bonus for dexterity | |
1162 */ | |
1163 | |
1164 dext_plus(dexterity) | |
1165 register int dexterity; | |
1166 { | |
1167 return (dexterity > 10 ? (dexterity-13)/3 : (dexterity-10)/3); | |
1168 } | |
1169 | |
1170 | |
1171 /* | |
1172 * dext_prot: | |
1173 * compute armor class bonus for dexterity | |
1174 */ | |
1175 | |
1176 dext_prot(dexterity) | |
1177 register int dexterity; | |
1178 { | |
1179 return ((dexterity-10)/2); | |
1180 } | |
1181 /* | |
1182 * str_plus: | |
1183 * compute bonus/penalties for strength on the "to hit" roll | |
1184 */ | |
1185 | |
1186 str_plus(str) | |
1187 register short str; | |
1188 { | |
1189 return((str-10)/3); | |
1190 } | |
1191 | |
1192 /* | |
1193 * add_dam: | |
1194 * compute additional damage done for exceptionally high or low strength | |
1195 */ | |
1196 | |
1197 add_dam(str) | |
1198 register short str; | |
1199 { | |
1200 return((str-9)/2); | |
1201 } | |
1202 | |
1203 /* | |
1204 * hung_dam: | |
1205 * Calculate damage depending on players hungry state | |
1206 */ | |
1207 hung_dam() | |
1208 { | |
1209 reg int howmuch = 0; | |
1210 | |
1211 switch(hungry_state) { | |
1212 case F_OKAY: | |
1213 case F_HUNGRY: howmuch = 0; | |
1214 when F_WEAK: howmuch = -1; | |
1215 when F_FAINT: howmuch = -2; | |
1216 } | |
1217 return howmuch; | |
1218 } | |
1219 | |
1220 /* | |
1221 * thunk: | |
1222 * A missile hits a monster | |
1223 */ | |
1224 | |
1225 thunk(weap, tp, mname) | |
1226 register struct object *weap; | |
1227 register struct thing *tp; /* Defender */ | |
1228 register char *mname; | |
1229 { | |
1230 char *def_name; /* Name of defender */ | |
1231 | |
1232 /* What do we call the defender? */ | |
1233 if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp)) | |
1234 def_name = "something"; | |
1235 else def_name = prname(mname, FALSE); | |
1236 | |
1237 if (weap->o_type == WEAPON){ | |
1238 sprintf(outstring,"The %s hits %s", weaps[weap->o_which].w_name, def_name); | |
1239 msg(outstring); | |
1240 } | |
1241 else if (weap->o_type == MISSILE){ | |
1242 sprintf(outstring,"The %s hits %s",ws_magic[weap->o_which].mi_name, def_name); | |
1243 msg(outstring); | |
1244 } | |
1245 else | |
1246 msg("You hit %s.", def_name); | |
1247 } | |
1248 | |
1249 /* | |
1250 * mthunk: | |
1251 * A missile from a monster hits the player | |
1252 */ | |
1253 | |
1254 m_thunk(weap, tp, mname) | |
1255 register struct object *weap; | |
1256 register struct thing *tp; | |
1257 register char *mname; | |
1258 { | |
1259 char *att_name; /* Name of attacker */ | |
1260 | |
1261 /* What do we call the attacker? */ | |
1262 if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp)) | |
1263 att_name = "Something"; | |
1264 else att_name = prname(mname, TRUE); | |
1265 | |
1266 if (weap->o_type == WEAPON){ | |
1267 sprintf(outstring,"%s's %s hits you.", att_name, weaps[weap->o_which].w_name); | |
1268 msg(outstring); | |
1269 } | |
1270 else if (weap->o_type == MISSILE){ | |
1271 sprintf(outstring,"%s's %s hits you.", att_name, ws_magic[weap->o_which].mi_name); | |
1272 msg(outstring); | |
1273 } | |
1274 else | |
1275 msg("%s hits you.", att_name); | |
1276 } | |
1277 | |
1278 /* | |
1279 * bounce: | |
1280 * A missile misses a monster | |
1281 */ | |
1282 | |
1283 bounce(weap, tp, mname) | |
1284 register struct object *weap; | |
1285 register struct thing *tp; /* Defender */ | |
1286 register char *mname; | |
1287 { | |
1288 char *def_name; /* Name of defender */ | |
1289 | |
1290 /* What do we call the defender? */ | |
1291 if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp)) | |
1292 def_name = "something"; | |
1293 else def_name = prname(mname, FALSE); | |
1294 | |
1295 if (weap->o_type == WEAPON){ | |
1296 sprintf(outstring,"The %s misses %s",weaps[weap->o_which].w_name, def_name); | |
1297 msg(outstring); | |
1298 } | |
1299 else if (weap->o_type == MISSILE){ | |
1300 sprintf(outstring,"The %s misses %s",ws_magic[weap->o_which].mi_name, def_name); | |
1301 msg(outstring); | |
1302 } | |
1303 else | |
1304 msg("You missed %s.", def_name); | |
1305 } | |
1306 | |
1307 /* | |
1308 * m_bounce: | |
1309 A missle from a monster misses the player | |
1310 */ | |
1311 | |
1312 m_bounce(weap, tp, mname) | |
1313 register struct object *weap; | |
1314 register struct thing *tp; | |
1315 register char *mname; | |
1316 { | |
1317 char *att_name; /* Name of attacker */ | |
1318 | |
1319 /* What do we call the attacker? */ | |
1320 if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp)) | |
1321 att_name = "Something"; | |
1322 else att_name = prname(mname, TRUE); | |
1323 | |
1324 if (weap->o_type == WEAPON){ | |
1325 sprintf(outstring,"%s's %s misses you.", att_name, weaps[weap->o_which].w_name); | |
1326 msg(outstring); | |
1327 } | |
1328 else if (weap->o_type == MISSILE){ | |
1329 sprintf(outstring,"%s's %s misses you.", att_name, ws_magic[weap->o_which].mi_name); | |
1330 msg(outstring); | |
1331 } | |
1332 else | |
1333 msg("%s misses you.", att_name); | |
1334 } | |
1335 | |
1336 | |
1337 /* | |
1338 * is_magic: | |
1339 * Returns true if an object radiates magic | |
1340 */ | |
1341 | |
1342 is_magic(obj) | |
1343 register struct object *obj; | |
1344 { | |
1345 switch (obj->o_type) | |
1346 { | |
1347 case ARMOR: | |
1348 return obj->o_ac != armors[obj->o_which].a_class; | |
1349 when WEAPON: | |
1350 return obj->o_hplus != 0 || obj->o_dplus != 0; | |
1351 when POTION: | |
1352 case SCROLL: | |
1353 case STICK: | |
1354 case RING: | |
1355 case MM: | |
1356 case RELIC: | |
1357 return TRUE; | |
1358 } | |
1359 return FALSE; | |
1360 } | |
1361 | |
1362 /* | |
1363 * killed: | |
1364 * Called to put a monster to death | |
1365 */ | |
1366 | |
1367 killed(item, pr, points) | |
1368 register struct linked_list *item; | |
1369 bool pr, points; | |
1370 { | |
1371 register struct thing *tp; | |
1372 register struct linked_list *pitem, *nexti; | |
1373 const char *monst; | |
1374 | |
1375 tp = THINGPTR(item); | |
1376 | |
1377 if (pr) | |
1378 { | |
1379 addmsg(terse ? "Defeated " : "You have defeated "); | |
1380 if (on(player, ISBLIND)) | |
1381 msg("it."); | |
1382 else | |
1383 { | |
1384 if (cansee(tp->t_pos.y, tp->t_pos.x) && !invisible(tp)) | |
1385 monst = monsters[tp->t_index].m_name; | |
1386 else { | |
1387 if (terse) monst = "something"; | |
1388 else monst = "thing"; | |
1389 } | |
1390 if (!terse) | |
1391 addmsg("the "); | |
1392 msg("%s.", monst); | |
1393 } | |
1394 } | |
1395 | |
1396 /* Take care of any residual effects of the monster */ | |
1397 check_residue(tp); | |
1398 | |
1399 if (points) { | |
1400 unsigned long test; /* For overflow check */ | |
1401 | |
1402 test = pstats.s_exp + tp->t_stats.s_exp; | |
1403 | |
1404 /* Do an overflow check before increasing experience */ | |
1405 if (test > pstats.s_exp) pstats.s_exp = test; | |
1406 | |
1407 /* | |
1408 * Do adjustments if he went up a level | |
1409 */ | |
1410 check_level(TRUE); | |
1411 } | |
1412 | |
1413 /* | |
1414 * Empty the monsters pack | |
1415 */ | |
1416 pitem = tp->t_pack; | |
1417 | |
1418 /* | |
1419 * Get rid of the monster. | |
1420 */ | |
1421 mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); | |
1422 mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch); | |
1423 detach(mlist, item); | |
1424 /* | |
1425 * empty his pack | |
1426 */ | |
1427 while (pitem != NULL) | |
1428 { | |
1429 nexti = next(tp->t_pack); | |
1430 (OBJPTR(pitem))->o_pos = tp->t_pos; | |
1431 detach(tp->t_pack, pitem); | |
1432 if (points) | |
1433 fall(pitem, FALSE); | |
1434 else | |
1435 o_discard(pitem); | |
1436 pitem = nexti; | |
1437 } | |
1438 turn_on(*tp, ISDEAD); | |
1439 attach(monst_dead, item); | |
1440 } | |
1441 | |
1442 | |
1443 /* | |
1444 * Returns a pointer to the weapon the monster is wielding corresponding to | |
1445 * the given thrown weapon. If no thrown item is given, try to find any | |
1446 * decent weapon. | |
1447 */ | |
1448 | |
1449 struct object * | |
1450 wield_weap(thrown, mp) | |
1451 struct object *thrown; | |
1452 struct thing *mp; | |
1453 { | |
1454 int look_for = 0, /* The projectile weapon we are looking for */ | |
1455 new_rate, /* The rating of a prospective weapon */ | |
1456 cand_rate = -1; /* Rating of current candidate -- higher is better */ | |
1457 register struct linked_list *pitem; | |
1458 register struct object *obj, *candidate = NULL; | |
1459 | |
1460 if (thrown != NULL) { /* Using a projectile weapon */ | |
1461 switch (thrown->o_which) { | |
1462 case BOLT: look_for = CROSSBOW; /* Find the crossbow */ | |
1463 when ARROW: look_for = BOW; /* Find the bow */ | |
1464 when ROCK: look_for = SLING; /* find the sling */ | |
1465 otherwise: return(NULL); | |
1466 } | |
1467 } | |
1468 else if (off(*mp, ISUNIQUE) && off(*mp, CARRYWEAPON)) return(NULL); | |
1469 | |
1470 for (pitem=mp->t_pack; pitem; pitem=next(pitem)) { | |
1471 obj = OBJPTR(pitem); | |
1472 | |
1473 /* | |
1474 * If we have a thrown weapon, just return the first match | |
1475 * we come to. | |
1476 */ | |
1477 if (thrown != NULL && obj->o_type == WEAPON && obj->o_which == look_for) | |
1478 return(obj); | |
1479 | |
1480 /* If we have a usable RELIC, return it */ | |
1481 if (thrown == NULL && obj->o_type == RELIC) { | |
1482 switch (obj->o_which) { | |
1483 case MUSTY_DAGGER: | |
1484 case YEENOGHU_FLAIL: | |
1485 case HRUGGEK_MSTAR: | |
1486 case MING_STAFF: | |
1487 case ASMO_ROD: | |
1488 case ORCUS_WAND: | |
1489 return(obj); | |
1490 } | |
1491 } | |
1492 | |
1493 /* Otherwise if it's a usable weapon, it is a good candidate */ | |
1494 else if (thrown == NULL && obj->o_type == WEAPON) { | |
1495 switch (obj->o_which) { | |
1496 case DAGGER: | |
1497 new_rate = 0; | |
1498 when BATTLEAXE: | |
1499 new_rate = 1; | |
1500 when MACE: | |
1501 new_rate = 2; | |
1502 when SWORD: | |
1503 new_rate = 3; | |
1504 when PIKE: | |
1505 new_rate = 4; | |
1506 when HALBERD: | |
1507 case SPETUM: | |
1508 new_rate = 6; | |
1509 when BARDICHE: | |
1510 new_rate = 7; | |
1511 when TRIDENT: | |
1512 new_rate = 8; | |
1513 when BASWORD: | |
1514 new_rate = 9; | |
1515 when TWOSWORD: | |
1516 new_rate = 10; | |
1517 otherwise: | |
1518 new_rate = -1; | |
1519 } | |
1520 | |
1521 /* Only switch if this is better than the current candidate */ | |
1522 if (new_rate > cand_rate) { | |
1523 cand_rate = new_rate; | |
1524 candidate = obj; | |
1525 } | |
1526 } | |
1527 } | |
1528 | |
1529 return(candidate); | |
1530 } | |
1531 | |
1532 explode(tp) | |
1533 register struct thing *tp; | |
1534 { | |
1535 | |
1536 register int x,y, damage; | |
1537 struct linked_list *item; | |
1538 struct thing *th; | |
1539 | |
1540 msg("the %s explodes!", monsters[tp->t_index].m_name); | |
1541 /* | |
1542 * check to see if it got the hero | |
1543 */ | |
1544 if (DISTANCE(hero.x, hero.y, tp->t_pos.x, tp->t_pos.y) <= 25) { | |
1545 msg("the explosion hits you"); | |
1546 damage = roll(6,6); | |
1547 if (save(VS_WAND, &player, 0)) | |
1548 damage /= 2; | |
1549 if ((pstats.s_hpt -= damage) <= 0) | |
1550 death(tp->t_index); | |
1551 } | |
1552 | |
1553 /* | |
1554 * now check for monsters in vicinity | |
1555 */ | |
1556 for (x = tp->t_pos.x-5; x<=tp->t_pos.x+5; x++) { | |
1557 if (x < 0 || x > COLS - 1) | |
1558 continue; | |
1559 for (y = tp->t_pos.y-5; y<=tp->t_pos.y+5; y++) { | |
1560 if (y < 1 || y > LINES - 3) | |
1561 continue; | |
1562 if (isalpha(mvwinch(mw, y, x))) { | |
1563 if ((item = find_mons(y, x)) != NULL) { | |
1564 th = THINGPTR(item); | |
1565 if (th == tp) /* don't count gas spore */ | |
1566 continue; | |
1567 damage = roll(6, 6); | |
1568 if (save(VS_WAND, th, 0)) | |
1569 damage /= 2; | |
1570 if ((tp->t_stats.s_hpt -= damage) <= 0) { | |
1571 msg("the explosion kills the %s", | |
1572 monsters[th->t_index].m_name); | |
1573 killed(item, FALSE, FALSE); | |
1574 } | |
1575 } | |
1576 } | |
1577 } | |
1578 } | |
1579 } |