4 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6 * This software may be copied and distributed for educational, research,
7 * and not for profit purposes provided that this copyright and statement
8 * are included in all such copies. Other copyrights may also apply.
16 * Critical blow. All hits that do 95% of total possible damage,
17 * and which also do at least 20 damage, or, sometimes, N damage.
18 * This is used only to determine "cuts" and "stuns".
20 static int monster_critical(int dice
, int sides
, int dam
)
23 int total
= dice
* sides
;
25 /* Must do at least 95% of perfect */
26 if (dam
< total
* 19 / 20) return (0);
28 /* Weak blows rarely work */
29 if ((dam
< 20) && (rand_int(100) >= dam
)) return (0);
32 if (dam
== total
) max
++;
37 while (rand_int(100) < 2) max
++;
41 if (dam
> 45) return (6 + max
);
42 if (dam
> 33) return (5 + max
);
43 if (dam
> 25) return (4 + max
);
44 if (dam
> 18) return (3 + max
);
45 if (dam
> 11) return (2 + max
);
54 * Determine if a monster attack against the player succeeds.
56 static bool check_hit(int power
, int level
)
60 /* Calculate the "attack quality" */
61 chance
= (power
+ (level
* 3));
64 ac
= p_ptr
->ac
+ p_ptr
->to_a
;
66 /* Check if the player was hit */
67 return test_hit(chance
, ac
, TRUE
);
71 #define MAX_DESC_INSULT 8
75 * Hack -- possible "insult" messages
77 static cptr desc_insult
[MAX_DESC_INSULT
] =
80 "insults your mother!",
81 "gives you the finger!",
85 "makes obscene gestures!",
90 #define MAX_DESC_MOAN 8
94 * Hack -- possible "insult" messages
96 static cptr desc_moan
[MAX_DESC_MOAN
] =
98 "wants his mushrooms back.",
99 "tells you to get off his land.",
100 "looks for his dogs. ",
101 "says 'Did you kill my Fang?' ",
102 "asks 'Do you want to buy any mushrooms?' ",
103 "seems sad about something.",
104 "asks if you have seen his dogs.",
105 "mumbles something about mushrooms."
110 * Attack the player via physical attacks.
112 bool make_attack_normal(int m_idx
)
114 monster_type
*m_ptr
= &mon_list
[m_idx
];
116 monster_race
*r_ptr
= &r_info
[m_ptr
->r_idx
];
118 monster_lore
*l_ptr
= &l_list
[m_ptr
->r_idx
];
122 int i
, k
, tmp
, ac
, rlev
;
140 /* Not allowed to attack */
141 if (r_ptr
->flags1
& (RF1_NEVER_BLOW
)) return (FALSE
);
145 ac
= p_ptr
->ac
+ p_ptr
->to_a
;
147 /* Extract the effective monster level */
148 rlev
= ((r_ptr
->level
>= 1) ? r_ptr
->level
: 1);
151 /* Get the monster name (or "it") */
152 monster_desc(m_name
, sizeof(m_name
), m_ptr
, 0);
154 /* Get the "died from" information (i.e. "a kobold") */
155 monster_desc(ddesc
, sizeof(ddesc
), m_ptr
, 0x88);
158 /* Assume no blink */
161 /* Scan through all blows */
162 for (ap_cnt
= 0; ap_cnt
< MONSTER_BLOW_MAX
; ap_cnt
++)
164 bool visible
= FALSE
;
165 bool obvious
= FALSE
;
166 bool do_break
= FALSE
;
173 /* Extract the attack infomation */
174 int effect
= r_ptr
->blow
[ap_cnt
].effect
;
175 int method
= r_ptr
->blow
[ap_cnt
].method
;
176 int d_dice
= r_ptr
->blow
[ap_cnt
].d_dice
;
177 int d_side
= r_ptr
->blow
[ap_cnt
].d_side
;
180 /* Hack -- no more attacks */
184 /* Handle "leaving" */
185 if (p_ptr
->leaving
) break;
188 /* Extract visibility (before blink) */
189 if (m_ptr
->ml
) visible
= TRUE
;
193 /* Extract the attack "power" */
196 case RBE_HURT
: power
= 60; break;
197 case RBE_POISON
: power
= 5; break;
198 case RBE_UN_BONUS
: power
= 20; break;
199 case RBE_UN_POWER
: power
= 15; break;
200 case RBE_EAT_GOLD
: power
= 5; break;
201 case RBE_EAT_ITEM
: power
= 5; break;
202 case RBE_EAT_FOOD
: power
= 5; break;
203 case RBE_EAT_LITE
: power
= 5; break;
204 case RBE_ACID
: power
= 0; break;
205 case RBE_ELEC
: power
= 10; break;
206 case RBE_FIRE
: power
= 10; break;
207 case RBE_COLD
: power
= 10; break;
208 case RBE_BLIND
: power
= 2; break;
209 case RBE_CONFUSE
: power
= 10; break;
210 case RBE_TERRIFY
: power
= 10; break;
211 case RBE_PARALYZE
: power
= 2; break;
212 case RBE_LOSE_STR
: power
= 0; break;
213 case RBE_LOSE_DEX
: power
= 0; break;
214 case RBE_LOSE_CON
: power
= 0; break;
215 case RBE_LOSE_INT
: power
= 0; break;
216 case RBE_LOSE_WIS
: power
= 0; break;
217 case RBE_LOSE_CHR
: power
= 0; break;
218 case RBE_LOSE_ALL
: power
= 2; break;
219 case RBE_SHATTER
: power
= 60; break;
220 case RBE_EXP_10
: power
= 5; break;
221 case RBE_EXP_20
: power
= 5; break;
222 case RBE_EXP_40
: power
= 5; break;
223 case RBE_EXP_80
: power
= 5; break;
224 case RBE_HALLU
: power
= 10; break;
228 /* Monster hits player */
229 if (!effect
|| check_hit(power
, rlev
))
231 /* Always disturbing */
235 /* Hack -- Apply "protection from evil" */
236 if ((p_ptr
->timed
[TMD_PROTEVIL
] > 0) &&
237 (r_ptr
->flags3
& (RF3_EVIL
)) &&
238 (p_ptr
->lev
>= rlev
) &&
239 ((rand_int(100) + p_ptr
->lev
) > 50))
241 /* Remember the Evil-ness */
244 l_ptr
->flags3
|= (RF3_EVIL
);
248 msg_format("%^s is repelled.", m_name
);
250 /* Hack -- Next attack */
255 /* Assume no cut or stun */
256 do_cut
= do_stun
= 0;
258 /* Assume no sound */
259 sound_msg
= MSG_GENERIC
;
261 /* Describe the attack method */
267 do_cut
= do_stun
= 1;
268 sound_msg
= MSG_MON_HIT
;
274 act
= "touches you.";
275 sound_msg
= MSG_MON_TOUCH
;
281 act
= "punches you.";
283 sound_msg
= MSG_MON_PUNCH
;
291 sound_msg
= MSG_MON_KICK
;
299 sound_msg
= MSG_MON_CLAW
;
307 sound_msg
= MSG_MON_BITE
;
314 sound_msg
= MSG_MON_STING
;
328 sound_msg
= MSG_MON_BUTT
;
334 act
= "crushes you.";
336 sound_msg
= MSG_MON_CRUSH
;
342 act
= "engulfs you.";
343 sound_msg
= MSG_MON_ENGULF
;
355 act
= "crawls on you.";
356 sound_msg
= MSG_MON_CRAWL
;
362 act
= "drools on you.";
363 sound_msg
= MSG_MON_DROOL
;
369 act
= "spits on you.";
370 sound_msg
= MSG_MON_SPIT
;
376 act
= "XXX3's on you.";
382 act
= "gazes at you.";
383 sound_msg
= MSG_MON_GAZE
;
389 act
= "wails at you.";
390 sound_msg
= MSG_MON_WAIL
;
396 act
= "releases spores at you.";
397 sound_msg
= MSG_MON_SPORE
;
403 act
= "projects XXX4's at you.";
409 act
= "begs you for money.";
410 sound_msg
= MSG_MON_BEG
;
416 act
= desc_insult
[rand_int(MAX_DESC_INSULT
)];
417 sound_msg
= MSG_MON_INSULT
;
423 act
= desc_moan
[rand_int(MAX_DESC_MOAN
)];
424 sound_msg
= MSG_MON_MOAN
;
436 if (act
) message_format(sound_msg
, 0, "%^s %s", m_name
, act
);
439 /* Hack -- assume all attacks are obvious */
442 /* Roll out the damage */
443 damage
= damroll(d_dice
, d_side
);
445 /* Apply appropriate damage */
450 /* Hack -- Assume obvious */
453 /* Hack -- No damage */
464 /* Hack -- Player armor reduces total damage */
465 damage
-= (damage
* ((ac
< 150) ? ac
: 150) / 250);
468 take_hit(damage
, ddesc
);
476 take_hit(damage
, ddesc
);
478 /* Take "poison" effect */
479 if (!(p_ptr
->resist_pois
|| p_ptr
->timed
[TMD_OPP_POIS
]))
481 if (inc_timed(TMD_POISONED
, randint(rlev
) + 5))
487 /* Learn about the player */
488 update_smart_learn(m_idx
, DRS_RES_POIS
);
496 take_hit(damage
, ddesc
);
498 /* Allow complete resist */
499 if (!p_ptr
->resist_disen
)
501 /* Apply disenchantment */
502 if (apply_disenchant(0)) obvious
= TRUE
;
505 /* Learn about the player */
506 update_smart_learn(m_idx
, DRS_RES_DISEN
);
516 take_hit(damage
, ddesc
);
519 for (k
= 0; k
< 10; k
++)
522 i
= rand_int(INVEN_PACK
);
524 /* Obtain the item */
525 o_ptr
= &inventory
[i
];
527 /* Skip non-objects */
528 if (!o_ptr
->k_idx
) continue;
530 /* Drain charged wands/staves */
531 if ((o_ptr
->tval
== TV_STAFF
) ||
532 (o_ptr
->tval
== TV_WAND
))
537 drained
= o_ptr
->pval
;
546 int heal
= rlev
* drained
;
548 msg_print("Energy drains from your pack!");
552 /* Don't heal more than max hp */
553 heal
= MIN(heal
, m_ptr
->maxhp
- m_ptr
->hp
);
558 /* Redraw (later) if needed */
559 if (p_ptr
->health_who
== m_idx
)
560 p_ptr
->redraw
|= (PR_HEALTH
);
562 /* Combine / Reorder the pack */
563 p_ptr
->notice
|= (PN_COMBINE
| PN_REORDER
);
566 p_ptr
->window
|= (PW_INVEN
);
568 /* Affect only a single inventory slot */
579 take_hit(damage
, ddesc
);
584 /* Saving throw (unless paralyzed) based on dex and level */
585 if (!p_ptr
->timed
[TMD_PARALYZED
] &&
586 (rand_int(100) < (adj_dex_safe
[p_ptr
->stat_ind
[A_DEX
]] +
589 /* Saving throw message */
590 msg_print("You quickly protect your money pouch!");
592 /* Occasional blink anyway */
593 if (rand_int(3)) blinked
= TRUE
;
599 gold
= (p_ptr
->au
/ 10) + randint(25);
600 if (gold
< 2) gold
= 2;
601 if (gold
> 5000) gold
= (p_ptr
->au
/ 20) + randint(3000);
602 if (gold
> p_ptr
->au
) gold
= p_ptr
->au
;
606 msg_print("Nothing was stolen.");
610 msg_print("Your purse feels lighter.");
611 msg_format("%ld coins were stolen!", (long)gold
);
615 msg_print("Your purse feels lighter.");
616 msg_print("All of your coins were stolen!");
620 p_ptr
->redraw
|= (PR_GOLD
);
623 p_ptr
->window
|= (PW_PLAYER_0
| PW_PLAYER_1
);
635 take_hit(damage
, ddesc
);
637 /* Saving throw (unless paralyzed) based on dex and level */
638 if (!p_ptr
->timed
[TMD_PARALYZED
] &&
639 (rand_int(100) < (adj_dex_safe
[p_ptr
->stat_ind
[A_DEX
]] +
642 /* Saving throw message */
643 msg_print("You grab hold of your backpack!");
645 /* Occasional "blink" anyway */
656 for (k
= 0; k
< 10; k
++)
659 object_type object_type_body
;
662 i
= rand_int(INVEN_PACK
);
664 /* Obtain the item */
665 o_ptr
= &inventory
[i
];
667 /* Skip non-objects */
668 if (!o_ptr
->k_idx
) continue;
671 if (artifact_p(o_ptr
)) continue;
673 /* Get a description */
674 object_desc(o_name
, sizeof(o_name
), o_ptr
, FALSE
, 3);
677 msg_format("%sour %s (%c) was stolen!",
678 ((o_ptr
->number
> 1) ? "One of y" : "Y"),
679 o_name
, index_to_label(i
));
681 /* Get local object */
682 i_ptr
= &object_type_body
;
684 /* Obtain local object */
685 object_copy(i_ptr
, o_ptr
);
690 /* Hack -- If a rod, staff, or wand, allocate total
691 * maximum timeouts or charges between those
692 * stolen and those missed. -LM-
694 distribute_charges(o_ptr
, i_ptr
, 1);
696 /* Carry the object */
697 (void)monster_carry(m_idx
, i_ptr
);
699 /* Steal the items */
700 inven_item_increase(i
, -1);
701 inven_item_optimize(i
);
719 take_hit(damage
, ddesc
);
721 /* Steal some food */
722 for (k
= 0; k
< 10; k
++)
724 /* Pick an item from the pack */
725 i
= rand_int(INVEN_PACK
);
728 o_ptr
= &inventory
[i
];
730 /* Skip non-objects */
731 if (!o_ptr
->k_idx
) continue;
733 /* Skip non-food objects */
734 if (o_ptr
->tval
!= TV_FOOD
) continue;
736 /* Get a description */
737 object_desc(o_name
, sizeof(o_name
), o_ptr
, FALSE
, 0);
740 msg_format("%sour %s (%c) was eaten!",
741 ((o_ptr
->number
> 1) ? "One of y" : "Y"),
742 o_name
, index_to_label(i
));
744 /* Steal the items */
745 inven_item_increase(i
, -1);
746 inven_item_optimize(i
);
763 take_hit(damage
, ddesc
);
765 /* Get the lite, and its flags */
766 o_ptr
= &inventory
[INVEN_LITE
];
767 object_flags(o_ptr
, &f1
, &f2
, &f3
);
769 /* Drain fuel where applicable */
770 if (!(f3
& TR3_NO_FUEL
) && (o_ptr
->timeout
> 0))
773 o_ptr
->timeout
-= (250 + randint(250));
774 if (o_ptr
->timeout
< 1) o_ptr
->timeout
= 1;
777 if (!p_ptr
->timed
[TMD_BLIND
])
779 msg_print("Your light dims.");
784 p_ptr
->window
|= (PW_EQUIP
);
796 msg_print("You are covered in acid!");
799 acid_dam(damage
, ddesc
);
801 /* Learn about the player */
802 update_smart_learn(m_idx
, DRS_RES_ACID
);
813 msg_print("You are struck by electricity!");
815 /* Take damage (special) */
816 elec_dam(damage
, ddesc
);
818 /* Learn about the player */
819 update_smart_learn(m_idx
, DRS_RES_ELEC
);
830 msg_print("You are enveloped in flames!");
832 /* Take damage (special) */
833 fire_dam(damage
, ddesc
);
835 /* Learn about the player */
836 update_smart_learn(m_idx
, DRS_RES_FIRE
);
847 msg_print("You are covered with frost!");
849 /* Take damage (special) */
850 cold_dam(damage
, ddesc
);
852 /* Learn about the player */
853 update_smart_learn(m_idx
, DRS_RES_COLD
);
861 take_hit(damage
, ddesc
);
863 /* Increase "blind" */
864 if (!p_ptr
->resist_blind
)
866 if (inc_timed(TMD_BLIND
, 10 + randint(rlev
)))
872 /* Learn about the player */
873 update_smart_learn(m_idx
, DRS_RES_BLIND
);
881 take_hit(damage
, ddesc
);
883 /* Increase "confused" */
884 if (!p_ptr
->resist_confu
)
886 if (inc_timed(TMD_CONFUSED
, 3 + randint(rlev
)))
892 /* Learn about the player */
893 update_smart_learn(m_idx
, DRS_RES_CONFU
);
901 take_hit(damage
, ddesc
);
903 /* Increase "afraid" */
904 if (p_ptr
->resist_fear
)
906 msg_print("You stand your ground!");
909 else if (rand_int(100) < p_ptr
->skills
[SKILL_SAV
])
911 msg_print("You stand your ground!");
916 if (inc_timed(TMD_AFRAID
, 3 + randint(rlev
)))
922 /* Learn about the player */
923 update_smart_learn(m_idx
, DRS_RES_FEAR
);
930 /* Hack -- Prevent perma-paralysis via damage */
931 if (p_ptr
->timed
[TMD_PARALYZED
] && (damage
< 1)) damage
= 1;
934 take_hit(damage
, ddesc
);
936 /* Increase "paralyzed" */
939 msg_print("You are unaffected!");
942 else if (rand_int(100) < p_ptr
->skills
[SKILL_SAV
])
944 msg_print("You resist the effects!");
949 if (inc_timed(TMD_PARALYZED
, 3 + randint(rlev
)))
955 /* Learn about the player */
956 update_smart_learn(m_idx
, DRS_FREE
);
964 take_hit(damage
, ddesc
);
967 if (do_dec_stat(A_STR
)) obvious
= TRUE
;
975 take_hit(damage
, ddesc
);
978 if (do_dec_stat(A_INT
)) obvious
= TRUE
;
986 take_hit(damage
, ddesc
);
989 if (do_dec_stat(A_WIS
)) obvious
= TRUE
;
997 take_hit(damage
, ddesc
);
1000 if (do_dec_stat(A_DEX
)) obvious
= TRUE
;
1008 take_hit(damage
, ddesc
);
1011 if (do_dec_stat(A_CON
)) obvious
= TRUE
;
1019 take_hit(damage
, ddesc
);
1022 if (do_dec_stat(A_CHR
)) obvious
= TRUE
;
1030 take_hit(damage
, ddesc
);
1032 /* Damage (stats) */
1033 if (do_dec_stat(A_STR
)) obvious
= TRUE
;
1034 if (do_dec_stat(A_DEX
)) obvious
= TRUE
;
1035 if (do_dec_stat(A_CON
)) obvious
= TRUE
;
1036 if (do_dec_stat(A_INT
)) obvious
= TRUE
;
1037 if (do_dec_stat(A_WIS
)) obvious
= TRUE
;
1038 if (do_dec_stat(A_CHR
)) obvious
= TRUE
;
1048 /* Hack -- Reduce damage based on the player armor class */
1049 damage
-= (damage
* ((ac
< 150) ? ac
: 150) / 250);
1052 take_hit(damage
, ddesc
);
1054 /* Radius 8 earthquake centered at the monster */
1057 int px_old
= p_ptr
->px
;
1058 int py_old
= p_ptr
->py
;
1060 earthquake(m_ptr
->fy
, m_ptr
->fx
, 8);
1062 /* Stop the blows if the player is pushed away */
1063 if ((px_old
!= p_ptr
->px
) ||
1064 (py_old
!= p_ptr
->py
))
1076 take_hit(damage
, ddesc
);
1078 if (p_ptr
->hold_life
&& (rand_int(100) < 95))
1080 msg_print("You keep hold of your life force!");
1084 s32b d
= damroll(10, 6) + (p_ptr
->exp
/100) * MON_DRAIN_LIFE
;
1085 if (p_ptr
->hold_life
)
1087 msg_print("You feel your life slipping away!");
1092 msg_print("You feel your life draining away!");
1105 take_hit(damage
, ddesc
);
1107 if (p_ptr
->hold_life
&& (rand_int(100) < 90))
1109 msg_print("You keep hold of your life force!");
1113 s32b d
= damroll(20, 6) + (p_ptr
->exp
/ 100) * MON_DRAIN_LIFE
;
1115 if (p_ptr
->hold_life
)
1117 msg_print("You feel your life slipping away!");
1122 msg_print("You feel your life draining away!");
1135 take_hit(damage
, ddesc
);
1137 if (p_ptr
->hold_life
&& (rand_int(100) < 75))
1139 msg_print("You keep hold of your life force!");
1143 s32b d
= damroll(40, 6) + (p_ptr
->exp
/ 100) * MON_DRAIN_LIFE
;
1145 if (p_ptr
->hold_life
)
1147 msg_print("You feel your life slipping away!");
1152 msg_print("You feel your life draining away!");
1165 take_hit(damage
, ddesc
);
1167 if (p_ptr
->hold_life
&& (rand_int(100) < 50))
1169 msg_print("You keep hold of your life force!");
1173 s32b d
= damroll(80, 6) + (p_ptr
->exp
/ 100) * MON_DRAIN_LIFE
;
1175 if (p_ptr
->hold_life
)
1177 msg_print("You feel your life slipping away!");
1182 msg_print("You feel your life draining away!");
1192 take_hit(damage
, ddesc
);
1194 /* Increase "image" */
1195 if (!p_ptr
->resist_chaos
)
1197 if (inc_timed(TMD_IMAGE
, 3 + randint(rlev
/ 2)))
1203 /* Learn about the player */
1204 update_smart_learn(m_idx
, DRS_RES_CHAOS
);
1211 /* Hack -- only one of cut or stun */
1212 if (do_cut
&& do_stun
)
1215 if (rand_int(100) < 50)
1232 /* Critical hit (zero if non-critical) */
1233 tmp
= monster_critical(d_dice
, d_side
, damage
);
1235 /* Roll for damage */
1238 case 0: k
= 0; break;
1239 case 1: k
= randint(5); break;
1240 case 2: k
= randint(5) + 5; break;
1241 case 3: k
= randint(20) + 20; break;
1242 case 4: k
= randint(50) + 50; break;
1243 case 5: k
= randint(100) + 100; break;
1244 case 6: k
= 300; break;
1245 default: k
= 500; break;
1249 if (k
) (void)inc_timed(TMD_CUT
, k
);
1257 /* Critical hit (zero if non-critical) */
1258 tmp
= monster_critical(d_dice
, d_side
, damage
);
1260 /* Roll for damage */
1263 case 0: k
= 0; break;
1264 case 1: k
= randint(5); break;
1265 case 2: k
= randint(10) + 10; break;
1266 case 3: k
= randint(20) + 20; break;
1267 case 4: k
= randint(30) + 30; break;
1268 case 5: k
= randint(40) + 40; break;
1269 case 6: k
= 100; break;
1270 default: k
= 200; break;
1273 /* Apply the stun */
1274 if (k
) (void)inc_timed(TMD_STUN
, k
);
1278 /* Monster missed player */
1281 /* Analyze failed attacks */
1297 /* Visible monsters */
1304 msg_format("%^s misses you.", m_name
);
1312 /* Analyze "visible" monsters only */
1315 /* Count "obvious" attacks (and ones that cause damage) */
1316 if (obvious
|| damage
|| (l_ptr
->blows
[ap_cnt
] > 10))
1318 /* Count attacks of this type */
1319 if (l_ptr
->blows
[ap_cnt
] < MAX_UCHAR
)
1321 l_ptr
->blows
[ap_cnt
]++;
1326 /* Skip the other blows if necessary */
1327 if (do_break
) break;
1334 msg_print("There is a puff of smoke!");
1335 teleport_away(m_idx
, MAX_SIGHT
* 2 + 5);
1339 /* Always notice cause of death */
1340 if (p_ptr
->is_dead
&& (l_ptr
->deaths
< MAX_SHORT
))
1346 /* Assume we attacked */