1 /* SCCS Id: @(#)mthrowu.c 3.4 2003/05/09 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 STATIC_DCL
int drop_throw(struct monst
*, struct obj
*,BOOLEAN_P
,int,int);
9 #define URETREATING(x,y) (distmin(u.ux,u.uy,x,y) > distmin(u.ux0,u.uy0,x,y))
11 #define POLE_LIM 8 /* How far monsters can use pole-weapons */
15 const char *breathwep
[];
20 * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
22 NEARDATA
const char *breathwep
[] = {
27 "a disintegration blast",
35 NEARDATA
const char *hallubreathwep
[] = {"fragments", "fire", "frost", "sleep gas", "a disintegration blast", "lightning", "poison gas", "acid", "light", "strange breath #9", "sizzle", "nexus", "slaying", "vomit", "nausea", "repetition", "nether", "chaos", "confusion", "smoke", "--More-- You have died. DYWYPI?", "darkness", "sound", "gravity", "vibration", "penetration", "spitballs", "fart gas", "stinking gas", "slow gas", "rainbows", "air", "balloons", "nitrogen", "chloroform", "prussic acid", "ozone", "spill", "litter", "garbage", "trash", "heat", "cold", "ice", "water", "earth", "hell", "sky", "astral", "stars", "asterisks", "exclamation marks!!!", "feathers", "springs", "fog", "dew", "snow", "drugs", "rock'n'roll", "smog", "sludge", "waste", "temperature", "humidity", "vortices", "clouds", "a psionic blast", "cotton candy", "butterflies", "asteroids", "beads", "bubbles", "champagne", "coins", "crumbs", "dark matter", "dust specks", "emoticons", "emotions", "entropy", "corona viri", "flowers", "foam", "gamma rays", "gelatin", "gemstones", "ghosts", "glass shards", "glitter", "good vibes", "gravel", "gravy", "grawlixes", "holy light", "hornets", "hot air", "hyphens", "hypnosis", "infrared", "insects", "laser beams", "leaves", "lightening", "logic gates", "magma", "marbles", "mathematics", "megabytes", "metal shavings", "metapatterns", "meteors", "mist", "mud", "music", "nanites", "needles", "noise", "nostalgia", "oil", "paint", "photons", "pixels", "plasma", "polarity", "powder", "powerups", "prismatic light", "pure logic", "purple", "radio waves", "rock music", "rocket fuel", "rope", "sadness", "salt", "sand", "scrolls", "smileys", "snowflakes", "sparkles", "specularity", "spores", "steam", "tetrahedrons", "text", "the past", "tornadoes", "toxic waste", "ultraviolet light", "viruses", "waveforms", "wind", "X-rays", "zorkmids", "shoes", "high heels", "hail", "etherwind", "game over", "taunts", "wouwou taunts", "conversion sermon", "perfume", "gramar cheker", "venom", "anti-teleportation fields", "perish songs", "a kick in the nuts", "cuddle", "cloth", "wheels", "dictators", "nasty traps", "crosses", "NHK-fire", "BFG ammo", "green flames", "carbon monoxide", "icicles", "error messages", "segfaults", "queefing gas", "menstruational liquid", "some icky bodily fluid", "pus", "necrosis",
40 /* hero is hit by something other than a monster */
42 thitu(tlev
, dam
, obj
, name
)
45 const char *name
; /* if null, then format `obj' */
47 const char *onm
, *knm
;
52 boolean is_thrown_weapon
;
53 boolean is_bulletammo
;
54 int kprefix
= KILLED_BY_AN
;
55 char onmbuf
[BUFSZ
], knmbuf
[BUFSZ
];
57 int shieldblockrate
= 0;
58 int saberblockrate
= 0;
61 int columnarevasion
= 0;
65 if (u
.twoweap
&& uswapwep
&& (uswapwep
->oartifact
== ART_BLOCKPARRY
|| uswapwep
->otyp
== PARRY_DAGGER
|| uswapwep
->otyp
== PARRY_SWORD
) ) {
67 if (uswapwep
->spe
> 0) shieldblockrate
+= (uswapwep
->spe
* 2);
68 if (!(PlayerCannotUseSkills
)) {
69 switch (P_SKILL(P_TWO_WEAPON_COMBAT
)) {
70 case P_BASIC
: shieldblockrate
+= 2; break;
71 case P_SKILLED
: shieldblockrate
+= 4; break;
72 case P_EXPERT
: shieldblockrate
+= 6; break;
73 case P_MASTER
: shieldblockrate
+= 8; break;
74 case P_GRAND_MASTER
: shieldblockrate
+= 10; break;
75 case P_SUPREME_MASTER
: shieldblockrate
+= 12; break;
81 if (u
.twoweap
&& uswapwep
&& uswapwep
->oartifact
== ART_TOTAL_PARRY_GAUCHE
) {
84 if (u
.twoweap
&& uwep
&& uswapwep
&& (tech_inuse(T_WEAPON_BLOCKER
)) ) {
85 shieldblockrate
+= 25;
87 if (u
.martialstyle
== MARTIALSTYLE_TAEKWONDO
&& !uwep
&& !uarms
&& (!u
.twoweap
|| !uswapwep
) ) {
89 if (!(PlayerCannotUseSkills
)) {
90 switch (P_SKILL(P_MARTIAL_ARTS
)) {
91 case P_BASIC
: shieldblockrate
+= 5; break;
92 case P_SKILLED
: shieldblockrate
+= 10; break;
93 case P_EXPERT
: shieldblockrate
+= 13; break;
94 case P_MASTER
: shieldblockrate
+= 16; break;
95 case P_GRAND_MASTER
: shieldblockrate
+= 20; break;
96 case P_SUPREME_MASTER
: shieldblockrate
+= 25; break;
102 if (u
.martialstyle
== MARTIALSTYLE_BOJUTSU
&& uwep
&& weapon_type(uwep
) == P_QUARTERSTAFF
) {
103 shieldblockrate
= 25;
104 if (uwep
->spe
> 0) shieldblockrate
+= (uwep
->spe
* 2);
105 if (!(PlayerCannotUseSkills
)) {
106 switch (P_SKILL(P_QUARTERSTAFF
)) {
107 case P_BASIC
: shieldblockrate
+= 2; break;
108 case P_SKILLED
: shieldblockrate
+= 4; break;
109 case P_EXPERT
: shieldblockrate
+= 6; break;
110 case P_MASTER
: shieldblockrate
+= 8; break;
111 case P_GRAND_MASTER
: shieldblockrate
+= 10; break;
112 case P_SUPREME_MASTER
: shieldblockrate
+= 12; break;
119 shieldblockrate
= shield_block_rate(uarms
);
120 if (uarms
->otyp
== ELVEN_SHIELD
) {
121 if (Race_if(PM_ELF
) || Race_if(PM_PLAYER_MYRKALFR
) || Race_if(PM_DROW
) || Role_if(PM_ELPH
) || Role_if(PM_TWELPH
)) shieldblockrate
+= 5;
124 if (uarms
->otyp
== URUK_HAI_SHIELD
|| uarms
->otyp
== ORCISH_SHIELD
|| uarms
->otyp
== ORCISH_GUARD_SHIELD
) {
125 if (Race_if(PM_ORC
)) shieldblockrate
+= 5;
127 if (uarms
->otyp
== DWARVISH_ROUNDSHIELD
) {
128 if (Race_if(PM_DWARF
)) shieldblockrate
+= 5;
129 if (Role_if(PM_MIDGET
)) shieldblockrate
+= 5;
132 if (!(PlayerCannotUseSkills
)) {
133 switch (P_SKILL(P_SHIELD
)) {
134 case P_BASIC
: shieldblockrate
+= 2; break;
135 case P_SKILLED
: shieldblockrate
+= 4; break;
136 case P_EXPERT
: shieldblockrate
+= 6; break;
137 case P_MASTER
: shieldblockrate
+= 8; break;
138 case P_GRAND_MASTER
: shieldblockrate
+= 10; break;
139 case P_SUPREME_MASTER
: shieldblockrate
+= 12; break;
144 if (uarms
->oartifact
== ART_LURTZ_S_WALL
) shieldblockrate
+= 20;
145 if (uarm
&& uarm
->oartifact
== ART_MOEBIUS_ARMOR
) shieldblockrate
+= 10;
146 if (uarms
->oartifact
== ART_I_M_GETTING_HUNGRY
) shieldblockrate
+= 20;
147 if (uarms
->oartifact
== ART_WHANG_CLINK_CLONK
) shieldblockrate
+= 10;
148 if (uarms
->oartifact
== ART_BLOCKBETTER
) shieldblockrate
+= 5;
149 if (uarms
->oartifact
== ART_VITALITY_STORM
) shieldblockrate
+= 2;
150 if (uarms
->oartifact
== ART_SUPER_SKELLIE
) shieldblockrate
+= 10;
151 if (uarms
->oartifact
== ART_WHO_CARES_ABOUT_A_LITTLE_R
) shieldblockrate
+= 15;
152 if (uarms
->oartifact
== ART_LOOK_HOW_IT_BLOCKS
) shieldblockrate
+= 20;
153 if (uarms
->oartifact
== ART_BLOCKING_EXTREME
) shieldblockrate
+= 10;
154 if (uarms
->oartifact
== ART_TSCHINGFIRM
) shieldblockrate
+= 10;
155 if (uarms
->oartifact
== ART_CUTTING_THROUGH
) shieldblockrate
+= 5;
156 if (uarms
->oartifact
== ART_LITTLE_PROTECTER
) shieldblockrate
+= 5;
157 if (uwep
&& uwep
->oartifact
== ART_VEST_REPLACEMENT
) shieldblockrate
+= 10;
158 if (uwep
&& uwep
->oartifact
== ART_THOSE_LAZY_PROGRAMMERS
) shieldblockrate
+= 10;
159 if (Race_if(PM_MACTHEIST
)) shieldblockrate
+= 10;
161 if (u
.holyshield
) shieldblockrate
+= (3 + spell_damage_bonus(SPE_HOLY_SHIELD
));
163 if (uarms
->spe
> 0) shieldblockrate
+= (uarms
->spe
* 2);
165 if (uarms
->cursed
) shieldblockrate
/= 2;
166 if (uarms
->blessed
) shieldblockrate
+= 5;
168 if (uarms
->spe
< 0) shieldblockrate
+= (uarms
->spe
* 2);
170 if (uarm
&& uarm
->oartifact
== ART_WOODSTOCK
) shieldblockrate
+= 5;
171 if (uwep
&& uwep
->oartifact
== ART_HOLD_IT_OUT
) shieldblockrate
+= 20;
172 if (uwep
&& uwep
->oartifact
== ART_SECANTED
) shieldblockrate
+= 5;
173 if (uarm
&& uarm
->oartifact
== ART_FARTHER_INTO_THE_JUNGLE
) shieldblockrate
+= 10;
174 if (uwep
&& uwep
->oartifact
== ART_BIMMSELIMMELIMM
) shieldblockrate
+= 10;
175 if (Numbed
) shieldblockrate
-= 10;
177 if (tlev
> 10) shieldblockrate
-= (rn2(tlev
- 9));
179 if (!PlayerCannotUseSkills
) {
180 switch (P_SKILL(P_SHIEN
)) {
181 case P_BASIC
: shieldblockrate
+= 1; break;
182 case P_SKILLED
: shieldblockrate
+= 2; break;
183 case P_EXPERT
: shieldblockrate
+= 3; break;
184 case P_MASTER
: shieldblockrate
+= 4; break;
185 case P_GRAND_MASTER
: shieldblockrate
+= 5; break;
186 case P_SUPREME_MASTER
: shieldblockrate
+= 6; break;
190 if (Conflict
&& shieldblockrate
> 0) {
191 shieldblockrate
*= 2;
192 shieldblockrate
/= 3;
194 if (StrongConflict
&& shieldblockrate
> 0) {
195 shieldblockrate
*= 2;
196 shieldblockrate
/= 3;
199 if (Role_if(PM_DANCER
)) shieldblockrate
/= 2;
201 if (uarms
&& uarms
->oartifact
== ART_THERMO_NUCLEAR_CHAMBER
) shieldblockrate
= 0;
202 if (uarms
&& uarms
->oartifact
== ART_SUPER_ENERGY_LINES
) shieldblockrate
= 0;
203 if (uarms
&& uarms
->otyp
== BROKEN_SHIELD
) shieldblockrate
= 0;
205 if (shieldblockrate
< 0) shieldblockrate
= 0;
207 /* If you're berserk, you cannot block at all. We will still show your actual chance to block in enlightenment,
208 so this line should not be copied over to cmd.c --Amy */
209 if (u
.berserktime
) shieldblockrate
= 0;
210 if (uarmf
&& uarmf
->otyp
== CATWALK_SANDALS
) shieldblockrate
= 0;
215 if (!obj
) panic("thitu: name & obj both null?");
216 name
= strcpy(onmbuf
,
217 (obj
->quan
> 1L) ? doname(obj
) : mshot_xname(obj
));
218 knm
= strcpy(knmbuf
, killer_xname(obj
));
219 kprefix
= KILLED_BY
; /* killer_name supplies "an" if warranted */
222 /* [perhaps ought to check for plural here to] */
223 if (!strncmpi(name
, "the ", 4) ||
224 !strncmpi(name
, "an ", 3) ||
225 !strncmpi(name
, "a ", 2)) kprefix
= KILLED_BY
;
227 onm
= (obj
&& obj_is_pname(obj
)) ? the(name
) :
228 (obj
&& obj
->quan
> 1L) ? name
: an(name
);
229 is_acid
= (obj
&& obj
->otyp
== ACID_VENOM
);
230 is_tailspike
= (obj
&& obj
->otyp
== TAIL_SPIKES
);
231 is_egg
= (obj
&& obj
->otyp
== EGG
);
232 is_polearm
= (obj
&& (objects
[obj
->otyp
].oc_skill
== P_POLEARMS
|| objects
[obj
->otyp
].oc_skill
== P_LANCE
|| objects
[obj
->otyp
].oc_skill
== P_GRINDER
|| obj
->otyp
== AKLYS
|| obj
->otyp
== BLOW_AKLYS
|| obj
->otyp
== REACH_TRIDENT
|| obj
->otyp
== SPINED_BALL
|| obj
->otyp
== CHAIN_AND_SICKLE
|| obj
->otyp
== LAJATANG
|| obj
->otyp
== LASER_CHAIN
));
233 is_thrown_weapon
= (obj
&& (objects
[obj
->otyp
].oc_skill
== P_DART
|| objects
[obj
->otyp
].oc_skill
== P_SHURIKEN
|| objects
[obj
->otyp
].oc_skill
== -P_DART
|| objects
[obj
->otyp
].oc_skill
== -P_SHURIKEN
) );
234 is_bulletammo
= (obj
&& obj
->otyp
>= PISTOL_BULLET
&& obj
->otyp
<= GAS_GRENADE
);
236 if (is_bulletammo
) extrachance
= 1;
237 else if (is_acid
|| is_tailspike
|| is_egg
|| is_polearm
|| (obj
&& obj
->oclass
== VENOM_CLASS
) ) extrachance
= 10;
238 else if (is_thrown_weapon
) extrachance
= 3;
239 else extrachance
= 2;
241 if (uwep
&& is_lightsaber(uwep
) && uwep
->lamplit
) {
243 if (!PlayerCannotUseSkills
) {
244 switch (P_SKILL(P_SHIEN
)) {
246 case P_BASIC
: saberblockrate
+= 10; break;
247 case P_SKILLED
: saberblockrate
+= 20; break;
248 case P_EXPERT
: saberblockrate
+= 30; break;
249 case P_MASTER
: saberblockrate
+= 40; break;
250 case P_GRAND_MASTER
: saberblockrate
+= 50; break;
251 case P_SUPREME_MASTER
: saberblockrate
+= 60; break;
252 default: saberblockrate
+= 0; break;
255 /* shien and djem so are both "form V" so they boost each other --Amy
256 * bonus to lightsaber blocking chance if you've enhanced both */
257 if (P_SKILL(P_SHIEN
) >= P_BASIC
&& P_SKILL(P_DJEM_SO
) >= P_BASIC
) saberblockrate
++;
258 if (P_SKILL(P_SHIEN
) >= P_SKILLED
&& P_SKILL(P_DJEM_SO
) >= P_SKILLED
) saberblockrate
++;
259 if (P_SKILL(P_SHIEN
) >= P_EXPERT
&& P_SKILL(P_DJEM_SO
) >= P_EXPERT
) saberblockrate
++;
260 if (P_SKILL(P_SHIEN
) >= P_MASTER
&& P_SKILL(P_DJEM_SO
) >= P_MASTER
) saberblockrate
++;
261 if (P_SKILL(P_SHIEN
) >= P_GRAND_MASTER
&& P_SKILL(P_DJEM_SO
) >= P_GRAND_MASTER
) saberblockrate
++;
262 if (P_SKILL(P_SHIEN
) >= P_SUPREME_MASTER
&& P_SKILL(P_DJEM_SO
) >= P_SUPREME_MASTER
) saberblockrate
++;
265 if (P_SKILL(weapon_type(uwep
)) >= P_SKILLED
&& !(PlayerCannotUseSkills
) ) {
266 saberblockrate
+= 30;
267 if (Role_if(PM_JEDI
)) {
268 saberblockrate
+= ((100 - saberblockrate
) / 2);
270 if (Role_if(PM_SHADOW_JEDI
)) {
271 saberblockrate
+= ((100 - saberblockrate
) / 2);
273 if (Role_if(PM_HEDDERJEDI
)) {
274 saberblockrate
+= ((100 - saberblockrate
) / 2);
276 if (Race_if(PM_BORG
)) {
277 saberblockrate
+= ((100 - saberblockrate
) / 5);
281 if (tlev
> 10) saberblockrate
-= (rn3(tlev
- 9));
285 if (PlayerInColumnarHeels
) {
288 if (!PlayerCannotUseSkills
) {
289 switch (P_SKILL(P_HIGH_HEELS
)) {
291 case P_BASIC
: columnarevasion
+= 5; break;
292 case P_SKILLED
: columnarevasion
+= 10; break;
293 case P_EXPERT
: columnarevasion
+= 15; break;
294 case P_MASTER
: columnarevasion
+= 20; break;
295 case P_GRAND_MASTER
: columnarevasion
+= 25; break;
296 case P_SUPREME_MASTER
: columnarevasion
+= 30; break;
297 default: columnarevasion
+= 0; break;
304 if (uwep
&& is_lightsaber(uwep
) && !uwep
->lamplit
&& Role_if(PM_SHADOW_JEDI
)) {
306 if (!PlayerCannotUseSkills
) {
307 switch (P_SKILL(P_SHIEN
)) {
309 case P_BASIC
: saberblockrate
+= 1; break;
310 case P_SKILLED
: saberblockrate
+= 2; break;
311 case P_EXPERT
: saberblockrate
+= 3; break;
312 case P_MASTER
: saberblockrate
+= 4; break;
313 case P_GRAND_MASTER
: saberblockrate
+= 5; break;
314 case P_SUPREME_MASTER
: saberblockrate
+= 6; break;
315 default: saberblockrate
+= 0; break;
319 if (tlev
> 10) saberblockrate
-= (rn3(tlev
- 9));
323 /* don't let the player become completely impervious --Amy */
324 if (shieldblockrate
> 75) shieldblockrate
= 75;
325 if (saberblockrate
> 95) saberblockrate
= 95;
327 if((u
.uac
+ tlev
<= rnd(20)) && (!rn2(StrongConflict
? 5 : Conflict
? 4 : 3))) {
328 if(Blind
|| !flags
.verbose
) pline("It misses.");
329 else You("are almost hit by %s.", onm
);
331 } else if ( (u
.uac
< 0) && (!rn2(StrongConflict
? 4 : Conflict
? 3 : 2)) && !rn2(extrachance
) && (rnd(100) < (-(u
.uac
))) ) {
332 /* more negative AC means a higher chance to deflect projectiles with armor --Amy */
333 if(Blind
|| !flags
.verbose
) pline("Your armor deflects a projectile.");
334 else You("deflect %s with your armor.", onm
);
337 if (u
.ubodyarmorturns
>= 5) {
338 u
.ubodyarmorturns
= 0;
339 use_skill(P_BODY_ARMOR
, 1);
344 } else if (uarms
&& uarms
->oartifact
== ART_HAVENER
&& rn2(2) && obj
&& (objects
[obj
->otyp
].oc_skill
== -P_BOW
|| objects
[obj
->otyp
].oc_skill
== P_BOW
) ) {
348 } else if (!rn2(extrachance
) && (rnd(100) < shieldblockrate
) ) {
350 if (u
.martialstyle
== MARTIALSTYLE_TAEKWONDO
&& !uwep
&& !uarms
&& (!u
.twoweap
|| !uswapwep
)) {
352 Your("fists block a projectile.");
353 use_skill(P_MARTIAL_ARTS
, 1);
355 } else if (u
.martialstyle
== MARTIALSTYLE_BOJUTSU
&& uwep
&& weapon_type(uwep
) == P_QUARTERSTAFF
) {
357 Your("quarterstaff blocks a projectile.");
358 use_skill(P_QUARTERSTAFF
, 1);
360 } else if (u
.twoweap
&& uwep
&& uswapwep
&& (tech_inuse(T_WEAPON_BLOCKER
) ) ) {
362 Your("weapons block a projectile.");
363 if (evilfriday
&& multi
>= 0) nomul(-2, "blocking with both weapons", TRUE
);
364 use_skill(P_TWO_WEAPON_COMBAT
, 1);
366 } else if (u
.twoweap
&& uswapwep
&& (uswapwep
->oartifact
== ART_BLOCKPARRY
|| uswapwep
->oartifact
== ART_TOTAL_PARRY_GAUCHE
|| uswapwep
->otyp
== PARRY_DAGGER
|| uswapwep
->otyp
== PARRY_SWORD
) ) {
368 Your("parrying weapon blocks a projectile.");
369 use_skill(P_TWO_WEAPON_COMBAT
, 1);
374 /* a good shield allows you to block projectiles --Amy */
375 if(Blind
|| !flags
.verbose
) pline("You block a projectile with your shield.");
376 else You("block %s with your shield.", onm
);
377 use_skill(P_SHIELD
, 1);
378 if (uarms
&& uarms
->oartifact
== ART_SHIENSIDE
) use_skill(P_SHIEN
, 1);
379 if (uarms
&& uarms
->oartifact
== ART_SPICKAR
&& uarms
->invoketimer
<= monstermoves
) {
380 int artitimeout
= rnz(2000);
381 if (!rn2(5)) artitimeout
= rnz(20000);
382 int mmstrength
= (GushLevel
/ 3);
383 if (mmstrength
< 1) mmstrength
= 1;
384 /* squeaking does not help here, as it's not an actual invoke --Amy */
385 uarms
->invoketimer
= (monstermoves
+ artitimeout
);
387 Your("shield fires a magic missile!");
389 buzz(20,mmstrength
,u
.ux
,u
.uy
,u
.dx
,u
.dy
); /* 20 = magic missile */
392 if (uarms
&& uarms
->oartifact
== ART_KLUUSCH
) {
395 if (u
.mh
> u
.mhmax
) u
.mh
= u
.mhmax
;
398 if (u
.uhp
> u
.uhpmax
) u
.uhp
= u
.uhpmax
;
402 if (uwep
&& uwep
->oartifact
== ART_BIMMSELIMMELIMM
&& !rn2(50) && uarms
&& uarms
->spe
> -20) {
404 pline("Bimmselimmelimm! Splinters of your shield are flying everywhere!");
408 if (u
.ubodyarmorturns
>= 5) {
409 u
.ubodyarmorturns
= 0;
410 use_skill(P_BODY_ARMOR
, 1);
417 } else if (uwep
&& is_lightsaber(uwep
) && (3 > rnd(extrachance
)) && (uwep
->lamplit
|| Role_if(PM_SHADOW_JEDI
)) && (saberblockrate
> rn2(100))) {
419 /* dodge missiles, even when blind; see "A new hope" for blindness reference */
420 You("dodge %s with %s.", onm
, yname(uwep
));
421 use_skill(P_SHIEN
, rnd(4)); /* would take forever to train otherwise --Amy */
423 if (tech_inuse(T_ABSORBER_SHIELD
) && uwep
&& is_lightsaber(uwep
) && uwep
->lamplit
) {
424 pline("Energy surges into the lightsaber as the projectile is blocked.");
426 if (uwep
->otyp
== ORANGE_LIGHTSABER
) uwep
->age
+= (25 * rnd(2));
427 if (uwep
->oartifact
== ART_DESANN_S_WRATH
) uwep
->age
+= (25 * rnd(2));
432 } else if (uarmc
&& uarmc
->oartifact
== ART_DOEDOEDOEDOEDOEDOEDOE_TEST
&& rn2(3)) {
434 if(Blind
|| !flags
.verbose
) You("are not hit by the missile.");
435 else You("are not hit by %s.", onm
);
438 } else if (uarmf
&& uarmf
->oartifact
== ART_YELLY
&& !rn2(2)) {
440 if(Blind
|| !flags
.verbose
) You("skillfully evade a projectile.");
441 else You("skillfully evade %s.", onm
);
444 } else if (uarm
&& uarm
->oartifact
== ART_BACKOBLOK
&& !rn2(2)) {
446 if(Blind
|| !flags
.verbose
) You("skillfully evade a projectile.");
447 else You("skillfully evade %s.", onm
);
450 } else if (powerfulimplants() && (!rn2(extrachance
) || !rn2(extrachance
) || !rn2(extrachance
)) && uimplant
&& uimplant
->oartifact
== ART_GYMNASTIC_LOVE
&& !rn2(3)) {
452 if(Blind
|| !flags
.verbose
) You("skillfully evade a projectile.");
453 else You("skillfully evade %s.", onm
);
456 } else if (uimplant
&& uimplant
->oartifact
== ART_IRON_OF_INNERMOST_JOY
&& rnd(10) < ( ((moves
% 13) > 9) ? 6 : (powerfulimplants()) ? 11 : 10) ) {
457 if(Blind
|| !flags
.verbose
) You("skillfully evade a projectile.");
458 else You("skillfully evade %s.", onm
);
461 } else if (uarm
&& uarm
->oartifact
== ART_IS_ONLY_OWWE
&& !rn2(10)) {
462 if(Blind
|| !flags
.verbose
) You("skillfully evade a projectile.");
463 else You("skillfully evade %s.", onm
);
466 } else if (uarm
&& uarm
->oartifact
== ART_BULLETSTOPPER
&& !rn2(2) && obj
&& is_bullet(obj
) ) {
467 pline_The("armor deflects the shot.");
470 } else if (uarmc
&& itemhasappearance(uarmc
, APP_KEVLAR_CLOAK
) && !rn2(10)) {
471 pline_The("kevlar cloak deflects the projectile.");
474 } else if (uarmc
&& uarmc
->otyp
== KEVLAR_VEST
&& !rn2(5)) {
475 pline_The("kevlar vest deflects the projectile.");
476 makeknown(KEVLAR_VEST
);
479 } else if (uarm
&& uarm
->otyp
== BULLETPROOF_VEST
&& !rn2(3) ) {
480 pline_The("bulletproof vest deflects the projectile.");
483 } else if (uarmf
&& uarmf
->otyp
== FLECHETTE_BOOTS
&& !rn2(5) ) {
484 if(Blind
|| !flags
.verbose
) You("sidestep a projectile.");
485 else You("sidestep %s.", onm
);
488 } else if (Race_if(PM_CUPID
) && !rn2(5)) {
490 if(Blind
|| !flags
.verbose
) You("sidestep a projectile.");
491 else You("sidestep %s.", onm
);
494 } else if (uarmf
&& uarmf
->oartifact
== ART_FIND_THE_COMBAT_STANCE
&& !rn2(5)) {
496 if(Blind
|| !flags
.verbose
) You("sidestep a projectile.");
497 else You("sidestep %s.", onm
);
500 } else if (columnarevasion
> rnd(100)) {
501 if(Blind
|| !flags
.verbose
) You("skillfully evade a projectile.");
502 else You("skillfully evade %s.", onm
);
505 } else if (uwep
&& uwep
->oartifact
== ART_SYLVIE_S_INVENTION
&& rn2(3)) {
507 if(Blind
|| !flags
.verbose
) You("skillfully evade a projectile.");
508 else You("skillfully evade %s.", onm
);
511 } else if (tech_inuse(T_FORCE_FIELD
) && rn2(4)) {
513 if(Blind
|| !flags
.verbose
) pline("Your force field causes a projectile to miss you.");
514 else pline("Your force field causes %s to miss you.", onm
);
517 } else if (Race_if(PM_PLAYER_ATLANTEAN
) && rn2(2)) {
519 if(Blind
|| !flags
.verbose
) pline("Your force field causes a projectile to miss you.");
520 else pline("Your force field causes %s to miss you.", onm
);
523 } else if (Race_if(PM_PLAYER_DYNAMO
) && !rn2(3)) {
525 if(Blind
|| !flags
.verbose
) pline("You absorb a projectile.");
526 else pline("You absorb %s.", onm
);
527 healup(rnd(u
.ulevel
), 0, FALSE
, FALSE
);
530 } else if (!rn2(extrachance
) && rnd(30) < (2 + (GushLevel
/ 2) ) ) {
532 /* depending on your character level, you may be able to dodge --Amy */
533 if(Blind
|| !flags
.verbose
) pline("You dodge a projectile.");
534 else You("dodge %s.", onm
);
538 if(Blind
|| !flags
.verbose
) You("are hit!");
539 else You("are hit by %s%s", onm
, exclam(dam
));
541 if (obj
&& obj
->otyp
== YITH_TENTACLE
) {
542 increasesanity(rnz(monster_difficulty() + 1));
544 if (obj
&& obj
->otyp
== NASTYPOLE
&& !rn2(10)) {
548 if (obj
&& obj
->otyp
== PETRIFYIUM_BAR
) {
549 if ((!Stone_resistance
|| (!IntStone_resistance
&& !rn2(20)) ) &&
550 !(poly_when_stoned(youmonst
.data
) && polymon(PM_STONE_GOLEM
))) {
552 if (Hallucination
&& rn2(10)) pline("Thankfully you are already stoned.");
554 Stoned
= Race_if(PM_EROSATOR
) ? 3 : 7;
555 u
.cnd_stoningcount
++;
556 pline("You start turning to stone!");
559 sprintf(killer_buf
, "petrifyium bar");
560 delayed_killer
= killer_buf
;
565 if (obj
&& obj
->otyp
== DISINTEGRATION_BAR
) {
567 if ((!Disint_resistance
|| !rn2(StrongDisint_resistance
? 1000 : 100) || (evilfriday
&& (uarms
|| uarmc
|| uarm
|| uarmu
)) ) && !rn2(10)) {
568 You_feel("like you're falling apart!");
571 /* destroy shield; other possessions are safe */
572 if (!(EDisint_resistance
& W_ARMS
) && !(itemsurvivedestruction(uarms
, 12)) ) (void) destroy_arm(uarms
);
574 /* destroy cloak; other possessions are safe */
575 if (!(EDisint_resistance
& W_ARMC
) && !(itemsurvivedestruction(uarmc
, 12)) ) (void) destroy_arm(uarmc
);
578 if (!(EDisint_resistance
& W_ARM
) && !(itemsurvivedestruction(uarm
, 12)) ) (void) destroy_arm(uarm
);
581 if (!(EDisint_resistance
& W_ARMU
) && !(itemsurvivedestruction(uarmu
, 12)) ) (void) destroy_arm(uarmu
);
585 if (u
.uhp
> u
.uhpmax
) u
.uhp
= u
.uhpmax
;
586 losehp(rnz(100 + level_difficulty()), "click click click click click you died", KILLED_BY
);
599 if (obj
&& objects
[obj
->otyp
].oc_material
== MT_SILVER
&& (hates_silver(youmonst
.data
) || (uarmf
&& uarmf
->oartifact
== ART_IRIS_S_HIDDEN_ALLERGY
) || (uarmh
&& uarmh
->oartifact
== ART_IRIS_S_SECRET_VULNERABILIT
) || (uarmc
&& uarmc
->oartifact
== ART_IRIS_S_UNREVEALED_LOVE
) || (uarmg
&& uarmg
->oartifact
== ART_IRIS_S_FAVORED_MATERIAL
) || autismweaponcheck(ART_PORKMAN_S_BALLS_OF_STEEL
) ) ) {
601 pline_The("silver sears your flesh!");
602 exercise(A_CON
, FALSE
);
604 if (obj
&& objects
[obj
->otyp
].oc_material
== MT_COPPER
&& hates_copper(youmonst
.data
)) {
606 pline_The("copper decomposes you!");
607 exercise(A_CON
, FALSE
);
609 if (obj
&& objects
[obj
->otyp
].oc_material
== MT_MERCURIAL
&& !rn2(10) && !Poison_resistance
) {
611 pline_The("mercury poisons you!");
612 exercise(A_CON
, FALSE
);
614 if (obj
&& objects
[obj
->otyp
].oc_material
== MT_PLATINUM
&& (hates_platinum(youmonst
.data
) || u
.contamination
>= 1000) ) {
616 pline_The("platinum smashes you!");
617 exercise(A_CON
, FALSE
);
619 if (obj
&& obj
->cursed
&& (hates_cursed(youmonst
.data
) || youmonst
.data
->mlet
== S_ANGEL
|| Race_if(PM_HUMANOID_ANGEL
))) {
621 if (obj
->hvycurse
) dam
+= 4;
622 if (obj
->prmcurse
) dam
+= 7;
623 if (obj
->bbrcurse
) dam
+= 15;
624 if (obj
->evilcurse
) dam
+= 15;
625 if (obj
->morgcurse
) dam
+= 15;
626 pline("An unholy aura blasts you!");
627 exercise(A_CON
, FALSE
);
629 if (obj
&& objects
[obj
->otyp
].oc_material
== MT_VIVA
&& hates_viva(youmonst
.data
)) {
631 pline_The("irradiation severely hurts you!");
632 exercise(A_CON
, FALSE
);
634 if (obj
&& objects
[obj
->otyp
].oc_material
== MT_INKA
) {
636 pline_The("inka string hurts you!");
637 exercise(A_CON
, FALSE
);
639 if (obj
&& obj
->otyp
== ODOR_SHOT
) {
641 pline("You inhale the horrific odor!");
642 if (tlev
< 1) increasesanity(rnz(5));
643 else increasesanity(rnz(tlev
* 5));
644 exercise(A_CON
, FALSE
);
647 if (obj
&& objects
[obj
->otyp
].oc_skill
== P_POLEARMS
&& (u
.usteed
|| youmonst
.data
->mlet
== S_CENTAUR
|| youmonst
.data
->mlet
== S_UNICORN
) || (!Upolyd
&& Race_if(PM_PLAYER_UNICORN
)) || (!Upolyd
&& Race_if(PM_HUMANOID_CENTAUR
)) || (!Upolyd
&& Race_if(PM_THUNDERLORD
)) ) {
649 if (u
.usteed
&& !rn2(25)) {
650 if (!mayfalloffsteed()) {
651 pline("The polearm lifts you out of your saddle!");
652 dismount_steed(DISMOUNT_FELL
);
658 if (uarmf
&& uarmf
->oartifact
== ART_STAR_SOLES
) enchrequired
= 1;
659 if (uarmf
&& uarmf
->oartifact
== ART_SHE_REALLY_LIKES_IT
) enchrequired
= 1;
660 if (uarmf
&& uarmf
->oartifact
== ART_HERSAY_PRICE
) enchrequired
= 1;
661 if (Race_if(PM_PLAYER_SKELETON
)) enchrequired
= 2;
662 if (uarmf
&& uarmf
->oartifact
== ART_PHANTO_S_RETARDEDNESS
) enchrequired
= 4;
664 if (obj
&& obj
->spe
> enchhave
) enchhave
= obj
->spe
;
665 if (obj
&& obj
->oartifact
== ART_MAGICBANE
&& enchhave
< 4) enchhave
= 4;
666 if (obj
&& is_lightsaber(obj
) && enchhave
< 4) enchhave
= 4;
667 if (obj
&& obj
->opoisoned
&& enchhave
< 4) enchhave
= 4;
668 if (obj
&& obj
->oartifact
) enchhave
+= 2;
670 if (is_acid
&& ((Acid_resistance
&& (StrongAcid_resistance
|| rn2(10))) ) || AcidImmunity
) {
671 pline("It doesn't seem to hurt you.");
672 if (Stoned
) fix_petrification();
673 } else if ((enchrequired
> 0) && rn2(3) && (enchhave
< enchrequired
) ) {
674 pline("The attack doesn't seem to harm you.");
677 if (is_acid
) {pline("It burns!");
678 if (tlev
> 0) dam
+= rnd(tlev
);
679 if (Stoned
) fix_petrification();
681 else if (is_tailspike
&& (tlev
> 0) ) dam
+= rnd(tlev
* 2);
682 else if (is_polearm
&& !rn2(2) && (tlev
> 10) ) dam
+= rnd(tlev
- 10);
683 else if (!is_bulletammo
&& (tlev
> 10) && !rn2(3)) dam
+= rnd(tlev
- 10);
685 if (Half_physical_damage
&& (rn2(2) || (uwep
&& uwep
->oartifact
== ART_SOOTHE_
)) ) dam
= (dam
+1) / 2;
686 if (StrongHalf_physical_damage
&& (rn2(2) || (uwep
&& uwep
->oartifact
== ART_SOOTHE_
)) ) dam
= (dam
+1) / 2;
688 if (dam
&& u
.uac
< /*-1*/0) { /* AC protects against this damage now, at least a bit --Amy */
692 int effectiveac
= (-(u
.uac
));
695 if (effectiveac
< 1) effectiveac
= 1;
697 if (effectiveac
> (issoviet
? 100 : 120)) {
698 if (issoviet
) effectiveac
-= rn3(effectiveac
- 99);
699 else effectiveac
-= rn3(effectiveac
- 119);
701 if (effectiveac
> (issoviet
? 60 : 80)) {
702 if (issoviet
) effectiveac
-= rn3(effectiveac
- 59);
703 else effectiveac
-= rn3(effectiveac
- 79);
705 if (effectiveac
> (issoviet
? 20 : 40)) {
706 if (issoviet
) effectiveac
-= rn2(effectiveac
- 19);
707 else effectiveac
-= rn2(effectiveac
- 39);
710 tempval
= rnd((effectiveac
/ (issoviet
? 5 : 4)) + 1);
711 if (tempval
< 1) tempval
= 1;
712 if (tempval
> (issoviet
? 20 : 50)) tempval
= (issoviet
? 20 : 50); /* max limit increased --Amy */
716 if (dam
< 1) dam
= 1;
719 if (dam
> 1 && tempval
> 0) {
720 dam
*= (100 - rnd(tempval
));
723 if (dam
< 1) dam
= 1;
728 if (dam
>= 2 && GushLevel
> rnd(100)) dam
= (dam
+1) / 2;
730 losehp(dam
, knm
, kprefix
);
731 exercise(A_STR
, FALSE
);
734 if (obj
&& (objects
[obj
->otyp
].oc_skill
== P_SHURIKEN
|| objects
[obj
->otyp
].oc_skill
== -P_SHURIKEN
) && dam
> 0) {
739 /* evil patch: antimatter bullets will damage the player's inventory --Amy */
740 if (obj
&& obj
->otyp
== ANTIMATTER_PISTOL_BULLET
) {
741 antimatter_damage(invent
, FALSE
, FALSE
);
743 if (obj
&& obj
->otyp
== ANTIMATTER_FIVE_SEVEN_BULLET
) {
744 antimatter_damage(invent
, FALSE
, FALSE
);
746 if (obj
&& obj
->otyp
== ANTIMATTER_SMG_BULLET
) {
747 antimatter_damage(invent
, FALSE
, FALSE
);
749 if (obj
&& obj
->otyp
== ANTIMATTER_MG_BULLET
) {
750 antimatter_damage(invent
, FALSE
, FALSE
);
752 if (obj
&& obj
->otyp
== ANTIMATTER_SNIPER_BULLET
) {
753 antimatter_damage(invent
, FALSE
, FALSE
);
755 if (obj
&& obj
->otyp
== ANTIMATTER_RIFLE_BULLET
) {
756 antimatter_damage(invent
, FALSE
, FALSE
);
758 if (obj
&& obj
->otyp
== ANTIMATTER_ASSAULT_RIFLE_BULLE
) {
759 antimatter_damage(invent
, FALSE
, FALSE
);
762 /* evil patch: darts of disintegration can disintegrate the player
763 * only have a 10% chance of actually doing so, because otherwise it would be really unbalanced --Amy */
764 if (obj
&& obj
->otyp
== DART_OF_DISINTEGRATION
) {
765 if ((!Disint_resistance
|| !rn2(StrongDisint_resistance
? 1000 : 100) || (evilfriday
&& (uarms
|| uarmc
|| uarm
|| uarmu
)) ) && !rn2(10)) {
766 You_feel("like you're falling apart!");
769 /* destroy shield; other possessions are safe */
770 if (!(EDisint_resistance
& W_ARMS
) && !(itemsurvivedestruction(uarms
, 12)) ) (void) destroy_arm(uarms
);
772 /* destroy cloak; other possessions are safe */
773 if (!(EDisint_resistance
& W_ARMC
) && !(itemsurvivedestruction(uarmc
, 12)) ) (void) destroy_arm(uarmc
);
776 if (!(EDisint_resistance
& W_ARM
) && !(itemsurvivedestruction(uarm
, 12)) ) (void) destroy_arm(uarm
);
779 if (!(EDisint_resistance
& W_ARMU
) && !(itemsurvivedestruction(uarmu
, 12)) ) (void) destroy_arm(uarmu
);
783 if (u
.uhp
> u
.uhpmax
) u
.uhp
= u
.uhpmax
;
784 losehp(rnz(100 + level_difficulty()), "click click click click click you died", KILLED_BY
);
796 if (obj
&& obj
->oartifact
== ART_SIEGFRIED_S_DEATHBOLT
) {
797 if ((!Disint_resistance
|| !rn2(StrongDisint_resistance
? 1000 : 100) || (evilfriday
&& (uarms
|| uarmc
|| uarm
|| uarmu
)) ) ) {
798 You_feel("like you're falling apart!");
801 /* destroy shield; other possessions are safe */
802 if (!(EDisint_resistance
& W_ARMS
) && !(itemsurvivedestruction(uarms
, 12)) ) (void) destroy_arm(uarms
);
804 /* destroy cloak; other possessions are safe */
805 if (!(EDisint_resistance
& W_ARMC
) && !(itemsurvivedestruction(uarmc
, 12)) ) (void) destroy_arm(uarmc
);
808 if (!(EDisint_resistance
& W_ARM
) && !(itemsurvivedestruction(uarm
, 12)) ) (void) destroy_arm(uarm
);
811 if (!(EDisint_resistance
& W_ARMU
) && !(itemsurvivedestruction(uarmu
, 12)) ) (void) destroy_arm(uarmu
);
815 if (u
.uhp
> u
.uhpmax
) u
.uhp
= u
.uhpmax
;
816 losehp(rnz(100 + level_difficulty()), "Siegfried's murderous crossbow", KILLED_BY
);
828 if (obj
&& obj
->otyp
== FLAMETHROWER
) {
829 if (FireImmunity
|| (Fire_resistance
&& rn2(StrongFire_resistance
? 20 : 5)) ) {
830 pline_The("fire doesn't seem to harm you.");
832 losehp(rnd(6), "being flamethrowered", KILLED_BY
);
836 if (obj
&& objects
[obj
->otyp
].oc_skill
== P_GRINDER
) {
838 losehp(rnd(10), "grinding", KILLED_BY
);
845 /* Be sure this corresponds with what happens to player-thrown objects in
846 * dothrow.c (for consistency). --KAA
847 * Returns 0 if object still exists (not destroyed).
851 drop_throw(mon
, obj
, ohit
, x
, y
)
852 register struct monst
*mon
;
853 register struct obj
*obj
;
857 struct obj
*mwep
= (struct obj
*) 0;
864 if (mon
) mwep
= MON_WEP(mon
);
866 if (issegfaulter
) { /* used to cause segfault panics but that's just malicious... cause fake segfault instead --Amy */
867 if (obj
->oclass
== VENOM_CLASS
) {
868 if (obj
->otyp
== SEGFAULT_VENOM
&& !rn2(5) ) {
869 u
.segfaultpanic
= TRUE
;
874 if ((obj
->otyp
== CREAM_PIE
|| obj
->oclass
== VENOM_CLASS
||
875 /* WAC added Spoon throw code */
876 (obj
->oartifact
== ART_HOUCHOU
) ||
877 /* WAC -- assume monsters don't throw without
878 using the right propellor */
879 (is_bullet(obj
) && !(objects
[obj
->otyp
].oc_material
== MT_LEAD
&& !rn2(2))) ||
880 (ohit
&& obj
->otyp
== EGG
)))
882 else if (ohit
&& (is_multigen(obj
) || obj
->otyp
== ROCK
)) {
884 /* copying over the dothrow.c code, because it makes no sense for blessed +10 ammo to break 2 out of 3 times --Amy */
885 chance
= greatest_erosionX(obj
) - obj
->spe
;
889 if (chance
== 3) chance
= 2;
890 else if (chance
== 4) chance
= 3;
891 else if (chance
== 5) chance
= 3;
892 else if (chance
> 5) chance
/= 2;
893 create
= !rn2(chance
);
895 chance
= 3 + obj
->spe
- greatest_erosionX(obj
);
896 if (chance
> 3) chance
= 2 + rno(chance
- 2);
897 if (chance
< 2) chance
= 2; /* fail safe */
898 if (Race_if(PM_MONGUNG
)) chance
*= 2;
900 create
= rn2(chance
);
903 if (obj
->blessed
&& !rnl(6))
905 if (!obj
->blessed
&& !obj
->cursed
&& !rn2(3) && !rnl(6))
908 if (!(PlayerCannotUseSkills
)) {
909 switch (P_SKILL(P_MISSILE_WEAPONS
)) {
911 case P_BASIC
: if (rn2(10) < 1) create
= 1; break;
912 case P_SKILLED
: if (rn2(10) < 2) create
= 1; break;
913 case P_EXPERT
: if (rn2(10) < 3) create
= 1; break;
914 case P_MASTER
: if (rn2(10) < 4) create
= 1; break;
915 case P_GRAND_MASTER
: if (rn2(10) < 5) create
= 1; break;
916 case P_SUPREME_MASTER
: if (rn2(10) < 6) create
= 1; break;
920 if (!(PlayerCannotUseSkills
)) {
922 if (objects
[obj
->otyp
].oc_skill
== -P_BOW
&& (P_SKILL(P_BOW
) >= P_BASIC
) && rn2(P_SKILL(P_BOW
)) )
924 if (objects
[obj
->otyp
].oc_skill
== -P_CROSSBOW
&& (P_SKILL(P_CROSSBOW
) >= P_BASIC
) && rn2(P_SKILL(P_CROSSBOW
)) )
926 if (objects
[obj
->otyp
].oc_skill
== -P_SLING
&& (P_SKILL(P_SLING
) >= P_BASIC
) && rn2(P_SKILL(P_SLING
)) )
928 if (objects
[obj
->otyp
].oc_skill
== -P_DART
&& (P_SKILL(P_DART
) >= P_BASIC
) && rn2(P_SKILL(P_DART
)) )
930 if (objects
[obj
->otyp
].oc_skill
== -P_SHURIKEN
&& (P_SKILL(P_SHURIKEN
) >= P_BASIC
) && rn2(P_SKILL(P_SHURIKEN
)) )
935 if (objects
[obj
->otyp
].oc_skill
== -P_BOW
&& uarm
&& uarm
->oartifact
== ART_WOODSTOCK
&& !create
&& !rn2(2))
937 if (objects
[obj
->otyp
].oc_material
== MT_MINERAL
&& uarm
&& uarm
->oartifact
== ART_QUARRY
&& !create
&& !rn2(2))
939 if (uarmc
&& uarmc
->oartifact
== ART_ARABELLA_S_WEAPON_STORAGE
&& !create
&& !rn2(2))
941 if (Race_if(PM_MACTHEIST
) && objects
[obj
->otyp
].oc_skill
== P_SLING
&& !create
&& !rn2(2))
943 if (Race_if(PM_MACTHEIST
) && objects
[obj
->otyp
].oc_skill
== -P_SLING
&& !create
&& !rn2(2))
946 if (objects
[obj
->otyp
].oc_material
== MT_LEAD
&& !create
&& !rn2(4)) create
= 1;
947 if (objects
[obj
->otyp
].oc_material
== MT_BAMBOO
&& !create
&& !rn2(4)) create
= 1;
948 if (obj
->otyp
== DART_OF_DISINTEGRATION
&& rn2(10)) create
= 0;
952 if (obj
->mstartinventB
&& obj
->otyp
!= ROCKET
&& obj
->otyp
!= MINI_NUKE
&& !is_grenade(obj
) && !(obj
->oartifact
) && !(obj
->fakeartifact
&& timebasedlowerchance() && rn2(4) ) && (!rn2(4) || (rn2(100) < u
.equipmentremovechance
) || !timebasedlowerchance() ) ) create
= 0;
953 if (obj
->mstartinventC
&& obj
->otyp
!= ROCKET
&& obj
->otyp
!= MINI_NUKE
&& !is_grenade(obj
) && !(obj
->oartifact
) && !(obj
->fakeartifact
&& !rn2(10)) && rn2(10)) create
= 0;
954 if (obj
->mstartinventE
&& obj
->otyp
!= ROCKET
&& obj
->otyp
!= MINI_NUKE
&& !is_grenade(obj
) && !(obj
->oartifact
) && !(obj
->fakeartifact
&& !rn2(20)) && rn2(20)) create
= 0;
955 if (obj
->mstartinventD
&& obj
->otyp
!= ROCKET
&& obj
->otyp
!= MINI_NUKE
&& !is_grenade(obj
) && !(obj
->oartifact
) && !(obj
->fakeartifact
&& !rn2(4)) && rn2(4)) create
= 0;
956 if (obj
->mstartinventX
&& obj
->otyp
!= ROCKET
&& obj
->otyp
!= MINI_NUKE
&& !is_grenade(obj
)) create
= 0;
958 /* Detonate rockets */
959 if (is_grenade(obj
)) {
961 if (rn2(5)) verbalize("Fire in the hole!");
962 else if (rn2(3)) verbalize("Fire in the ass hole!");
963 else if (rn2(2)) verbalize("Fire in your ass hole %s!", playeraliasname
);
964 else verbalize("Here is a grenade four you!"); /* sic */
967 create
= 1; /* Don't destroy */
968 arm_bomb(obj
, FALSE
);
970 grenade_explode(obj
, bhitpos
.x
, bhitpos
.y
, FALSE
, 0);
971 obj
= (struct obj
*)0;
973 } else if (objects
[obj
->otyp
].oc_dir
& EXPLOSION
) {
974 if (cansee(bhitpos
.x
,bhitpos
.y
))
975 pline("%s explodes in a ball of fire!", Doname2(obj
));
976 else You_hear("an explosion");
977 explode(bhitpos
.x
, bhitpos
.y
, -ZT_SPELL(ZT_FIRE
), d(3,8),
978 WEAPON_CLASS
, EXPL_FIERY
);
980 if (obj
&& obj
->otyp
== MINI_NUKE
) fatman_explosion(bhitpos
.x
, bhitpos
.y
, obj
);
984 /* D: Detonate crossbow bolts from Hellfire if they hit */
985 if (ohit
&& mwep
&& (mwep
->oartifact
== ART_HELLFIRE
|| mwep
->oartifact
== ART_EVERCONSUMING_HELLFIRE
|| (obj
&& obj
->oartifact
== ART_BAKUHATSU_SEI_MISAIRU
) || mwep
->oartifact
== ART_UNIDENTIFIED_HELLCAST
|| mwep
->oartifact
== ART_SEVENTH_SCRIPTURE
)
986 && is_ammo(obj
) && ammo_and_launcher(obj
, mwep
)) {
988 if (cansee(bhitpos
.x
,bhitpos
.y
))
989 pline("%s explodes in a ball of fire!", Doname2(obj
));
991 You_hear("an explosion");
993 explode(bhitpos
.x
, bhitpos
.y
, -ZT_SPELL(ZT_FIRE
),
994 d(2,6), WEAPON_CLASS
, EXPL_FIERY
);
996 /* D: Exploding bolts will be destroyed */
1000 if (create
&& !((mtmp
= m_at(x
, y
)) && (mtmp
->mtrapped
) &&
1001 (t
= t_at(x
, y
)) && ((t
->ttyp
== PIT
) || (t
->ttyp
== SHIT_PIT
) || (t
->ttyp
== MANA_PIT
) || (t
->ttyp
== ANOXIC_PIT
) || (t
->ttyp
== HYPOXIC_PIT
) || (t
->ttyp
== GIANT_CHASM
) || (t
->ttyp
== ACID_PIT
) ||
1002 (t
->ttyp
== SPIKED_PIT
)))) {
1004 obj
->mstartinventB
= 0;
1005 obj
->mstartinventC
= 0;
1006 obj
->mstartinventD
= 0;
1007 obj
->mstartinventE
= 0;
1008 if (obj
->mstartinventX
) u
.itemcleanupneeded
= TRUE
;
1010 if (down_gate(x
, y
) != -1)
1011 objgone
= ship_object(obj
, x
, y
, FALSE
);
1013 if (!flooreffects(obj
,x
,y
,"fall")) { /* don't double-dip on damage */
1014 place_object(obj
, x
, y
);
1016 if (!mtmp
&& x
== u
.ux
&& y
== u
.uy
)
1019 passive_obj(mtmp
, obj
, (struct attack
*)0);
1021 /* evil patch idea: monsters shooting nasty gray stones cause them to end up in your pack --Amy */
1022 if (obj
&& x
== u
.ux
&& y
== u
.uy
&& is_nastygraystone(obj
)) {
1023 pline("%s lands in your knapsack!", Doname2(obj
));
1024 (void) pickup_object(obj
, obj
->quan
, TRUE
, TRUE
);
1025 } else if (obj
&& x
== u
.ux
&& y
== u
.uy
&& is_feminismstone(obj
)) {
1026 pline("%s stays in your inventory, and you get a bad feeling about it.", Doname2(obj
));
1027 (void) pickup_object(obj
, obj
->quan
, TRUE
, TRUE
);
1028 } else stackobj(obj
);
1033 } else if (obj
) obfree(obj
, (struct obj
*) 0);
1041 /* an object launched by someone/thing other than player attacks a monster;
1042 return 1 if the object has stopped moving (hit or its range used up) */
1044 ohitmon(mon
, mtmp
, otmp
, range
, verbose
)
1045 struct monst
*mon
; /* monster thrower (if applicable) */
1046 struct monst
*mtmp
; /* accidental target */
1047 struct obj
*otmp
; /* missile; might be destroyed by drop_throw */
1048 int range
; /* how much farther will object travel if it misses */
1049 /* Use -1 to signify to keep going even after hit, */
1050 /* unless its gone (used for rolling_boulder_traps) */
1051 boolean verbose
; /* give message(s) even when you can't see what happened */
1054 boolean vis
, ismimic
;
1056 register struct obj
*blocker
= (struct obj
*)0;
1057 int shieldblockrate
= 0;
1059 ismimic
= mtmp
->m_ap_type
&& mtmp
->m_ap_type
!= M_AP_MONSTER
;
1060 vis
= cansee(bhitpos
.x
, bhitpos
.y
);
1062 tmp
= 5 + find_mac(mtmp
) + omon_adj(mtmp
, otmp
, FALSE
);
1064 /* Amy edit: if a pet is the target and the monster is high-level, add to-hit to make sure it can actually hit */
1065 if (mtmp
->mtame
&& mon
) {
1066 int armordifferential
= 0;
1067 if (mon
->m_lev
> 0) armordifferential
+= mon
->m_lev
;
1068 if (mtmp
->m_lev
> mon
->m_lev
) armordifferential
-= (mtmp
->m_lev
- mon
->m_lev
);
1069 if (armordifferential
< 0) armordifferential
= 0; /* fail safe */
1070 tmp
+= armordifferential
;
1071 if (otmp
&& otmp
->oclass
== VENOM_CLASS
) tmp
+= 10;
1073 if (verysmall(mtmp
->data
) && !rn2(8)) {
1075 if (vis
) pline("%s avoids a projectile.", Monnam(mtmp
));
1077 if (!range
) { /* Last position; object drops */
1078 (void) drop_throw(mon
, otmp
, 0, mtmp
->mx
, mtmp
->my
);
1081 } else if (rathersmall(mtmp
->data
) && !verysmall(mtmp
->data
) && !rn2(20)) {
1083 if (vis
) pline("%s avoids a projectile.", Monnam(mtmp
));
1085 if (!range
) { /* Last position; object drops */
1086 (void) drop_throw(mon
, otmp
, 0, mtmp
->mx
, mtmp
->my
);
1089 } else if (hugemonst(mtmp
->data
) && !rn2(8)) {
1091 if (vis
) pline("%s shrugs off a projectile.", Monnam(mtmp
));
1093 if (!range
) { /* Last position; object drops */
1094 (void) drop_throw(mon
, otmp
, 0, mtmp
->mx
, mtmp
->my
);
1097 } else if (bigmonst(mtmp
->data
) && !hugemonst(mtmp
->data
) && !rn2(15)) {
1099 if (vis
) pline("%s shrugs off a projectile.", Monnam(mtmp
));
1101 if (!range
) { /* Last position; object drops */
1102 (void) drop_throw(mon
, otmp
, 0, mtmp
->mx
, mtmp
->my
);
1105 } else if (amorphous(mtmp
->data
) && !rn2(10)) {
1107 if (vis
) pline("%s's amorphous body skillfully dodges a projectile.", Monnam(mtmp
));
1109 if (!range
) { /* Last position; object drops */
1110 (void) drop_throw(mon
, otmp
, 0, mtmp
->mx
, mtmp
->my
);
1113 } else if (noncorporeal(mtmp
->data
) && !rn2(2)) {
1115 if (vis
) pline("%s avoids a projectile due to being noncorporeal.", Monnam(mtmp
));
1117 if (!range
) { /* Last position; object drops */
1118 (void) drop_throw(mon
, otmp
, 0, mtmp
->mx
, mtmp
->my
);
1121 } else if (unsolid(mtmp
->data
) && !rn2(8)) {
1123 if (vis
) pline("%s's unsolid body lets a projectile pass through harmlessly.", Monnam(mtmp
));
1125 if (!range
) { /* Last position; object drops */
1126 (void) drop_throw(mon
, otmp
, 0, mtmp
->mx
, mtmp
->my
);
1129 } else if (ecm_monster(mtmp
->data
)) { /* will never be hit by monsters' ranged attacks */
1131 pline("%s uses an ECM system to divert a projectile.", Monnam(mtmp
));
1133 if (!range
) { /* Last position; object drops */
1134 (void) drop_throw(mon
, otmp
, 0, mtmp
->mx
, mtmp
->my
);
1137 } else if (swatting_monster(mtmp
->data
)) { /* will never be hit by monsters' ranged attacks */
1139 pline("%s swats a projectile away.", Monnam(mtmp
));
1141 if (!range
) { /* Last position; object drops */
1142 (void) drop_throw(mon
, otmp
, 0, mtmp
->mx
, mtmp
->my
);
1145 } else if (mtmp
->data
== &mons
[PM_XXXXXXXXXXXXXXXXXXXX
] || mtmp
->data
== &mons
[PM_IDE_BY__
]) { /* will never be hit by monsters' ranged attacks */
1147 pline("%s swats a projectile away.", Monnam(mtmp
));
1149 if (!range
) { /* Last position; object drops */
1150 (void) drop_throw(mon
, otmp
, 0, mtmp
->mx
, mtmp
->my
);
1153 } else if (blocker
= (which_armor(mtmp
, W_ARMS
))) {
1155 shieldblockrate
= shield_block_rate(blocker
);
1156 shieldblockrate
+= 10; /* monsters can simply block better --Amy */
1158 if (blocker
->otyp
== ELVEN_SHIELD
&& is_elf(mtmp
->data
)) shieldblockrate
+= 5;
1159 if (blocker
->otyp
== URUK_HAI_SHIELD
&& is_orc(mtmp
->data
)) shieldblockrate
+= 5;
1160 if (blocker
->otyp
== ORCISH_SHIELD
&& is_orc(mtmp
->data
)) shieldblockrate
+= 5;
1161 if (blocker
->otyp
== ORCISH_GUARD_SHIELD
&& is_orc(mtmp
->data
)) shieldblockrate
+= 5;
1162 if (blocker
->otyp
== DWARVISH_ROUNDSHIELD
&& is_dwarf(mtmp
->data
)) shieldblockrate
+= 5;
1164 if (shieldblockrate
&& (blocker
->spe
> 0)) shieldblockrate
+= (blocker
->spe
* 2);
1165 if (blocker
->blessed
) shieldblockrate
+= 5;
1167 if (shieldblockrate
> 75) shieldblockrate
= 75;
1169 if (blocker
->otyp
== BROKEN_SHIELD
) shieldblockrate
= 0;
1171 if (rnd(100) < shieldblockrate
) {
1173 pline("%s's shield blocks a projectile.", Monnam(mtmp
));
1175 if (!range
) { /* Last position; object drops */
1176 (void) drop_throw(mon
, otmp
, 0, mtmp
->mx
, mtmp
->my
);
1180 else goto blockingdone
;
1183 if (tmp
< rnd(20)) {
1185 if (vis
) miss(distant_name(otmp
, mshot_xname
), mtmp
);
1186 else if (verbose
) pline("It is missed.");
1188 if (!range
) { /* Last position; object drops */
1189 (void) drop_throw(mon
, otmp
, 0, mtmp
->mx
, mtmp
->my
);
1192 } else if (otmp
->oclass
== POTION_CLASS
) {
1193 if (ismimic
) seemimic(mtmp
);
1194 mtmp
->msleeping
= 0;
1195 if (vis
) otmp
->dknown
= 1;
1196 potionhit(mtmp
, otmp
, FALSE
);
1197 if (mon
&& !DEADMONSTER(mon
) && !DEADMONSTER(mtmp
) &&
1198 mtmp
->movement
>= NORMAL_SPEED
&& rn2(4)) {
1200 mtmp
->movement
-= NORMAL_SPEED
;
1201 mattackm(mtmp
, mon
);
1205 damage
= dmgval(otmp
, mtmp
);
1206 if (mtmp
->mtame
&& mon
) {
1207 if (mon
->m_lev
>= 5) damage
+= ((mon
->m_lev
- 4) / 2);
1208 if (otmp
->otyp
== TAIL_SPIKES
) damage
+= rnd((mon
->m_lev
* 2) + 30);
1209 if (otmp
->otyp
== DART_OF_DISINTEGRATION
) damage
+= rnd(50);
1210 if (otmp
->otyp
== DISINTEGRATION_BAR
) damage
+= rnd(50);
1211 if (otmp
->otyp
== NASTYPOLE
) damage
+= rnd(10);
1212 if (otmp
->otyp
== PETRIFYIUM_BAR
&& !rn2(4)) damage
+= rnd(200);
1213 if (otmp
&& objects
[otmp
->otyp
].oc_skill
== P_GRINDER
) damage
+= rnd(10);
1215 if (otmp
->otyp
== SPOON
) {
1216 pline("The spoon flashes brightly as it hits %s.",
1217 the(mon_nam(mtmp
)));
1220 if (otmp
->otyp
== ACID_VENOM
&& resists_acid(mtmp
) && !player_will_pierce_resistance())
1222 if (ismimic
) seemimic(mtmp
);
1223 mtmp
->msleeping
= 0;
1224 if (vis
) hit(distant_name(otmp
,mshot_xname
), mtmp
, exclam(damage
));
1225 else if (verbose
) pline("%s is hit%s", Monnam(mtmp
), exclam(damage
));
1227 if (otmp
->opoisoned
) {
1228 if (resists_poison(mtmp
) && !player_will_pierce_resistance()) {
1229 if (vis
) pline_The("poison doesn't seem to affect %s.",
1232 if (rn2(150) || resists_poison(mtmp
)) {
1233 damage
+= rnd(mtmp
->mtame
? 15 : 6);
1235 if (vis
) pline_The("poison was deadly...");
1240 if (objects
[otmp
->otyp
].oc_material
== MT_SILVER
&&
1241 hates_silver(mtmp
->data
)) {
1242 if (vis
) pline_The("silver sears %s flesh!",
1243 s_suffix(mon_nam(mtmp
)));
1244 else if (verbose
) pline("Its flesh is seared!");
1246 if (objects
[otmp
->otyp
].oc_material
== MT_VIVA
&& hates_viva(mtmp
->data
)) {
1247 if (verbose
) pline("It is irradiated!");
1249 if (objects
[otmp
->otyp
].oc_material
== MT_COPPER
&& hates_copper(mtmp
->data
)) {
1250 if (verbose
) pline("It is decomposed!");
1252 if (objects
[otmp
->otyp
].oc_material
== MT_PLATINUM
&& hates_platinum(mtmp
->data
)) {
1253 if (verbose
) pline("It is smashed!");
1255 if (otmp
->cursed
&& hates_cursed(mtmp
->data
)) {
1256 if (verbose
) pline("It is blasted by darkness!");
1258 if (objects
[otmp
->otyp
].oc_material
== MT_INKA
&& hates_inka(mtmp
->data
)) {
1259 if (verbose
) pline("It is hurt!");
1261 if (otmp
->otyp
== ODOR_SHOT
&& hates_odor(mtmp
->data
)) {
1262 if (verbose
) pline("It is beguiled!");
1264 if (otmp
->otyp
== ACID_VENOM
&& cansee(mtmp
->mx
,mtmp
->my
)) {
1265 if (resists_acid(mtmp
) && !player_will_pierce_resistance()) {
1267 pline("%s is unaffected.", Monnam(mtmp
));
1270 if (vis
) pline_The("acid burns %s!", mon_nam(mtmp
));
1271 else if (verbose
) pline("It is burned!");
1274 mtmp
->mhp
-= damage
;
1275 if (mtmp
->mhp
< 1) {
1277 pline("%s is %s!", Monnam(mtmp
),
1278 (nonliving(mtmp
->data
) || !canspotmon(mtmp
))
1279 ? "destroyed" : "killed");
1280 /* don't blame hero for unknown rolling boulder trap */
1281 if (!flags
.mon_moving
&&
1282 (otmp
->otyp
!= BOULDER
|| range
>= 0 || !otmp
->otrapped
))
1286 if (mtmp
->mhp
> 0) monster_pain(mtmp
);
1288 if (can_blnd((struct monst
*)0, mtmp
,
1289 (uchar
)(otmp
->otyp
== BLINDING_VENOM
? AT_SPIT
: AT_WEAP
),
1291 if (vis
&& mtmp
->mcansee
)
1292 pline("%s is blinded by %s.", Monnam(mtmp
), the(xname(otmp
)));
1294 tmp
= (int)mtmp
->mblinded
+ rnd(25) + 20;
1295 if (tmp
> 127) tmp
= 127;
1296 mtmp
->mblinded
= tmp
;
1299 if (mon
&& !DEADMONSTER(mon
) && !DEADMONSTER(mtmp
) &&
1300 mtmp
->movement
>= NORMAL_SPEED
&& rn2(4)) {
1302 mtmp
->movement
-= NORMAL_SPEED
;
1303 mattackm(mtmp
, mon
);
1306 objgone
= drop_throw(mon
, otmp
, 1, bhitpos
.x
, bhitpos
.y
);
1307 if (!objgone
&& range
== -1) { /* special case */
1308 obj_extract_self(otmp
); /* free it for motion again */
1317 m_throw(mon
, x
, y
, dx
, dy
, range
, obj
)
1318 register struct monst
*mon
;
1319 register int x
,y
,dx
,dy
,range
; /* direction and range */
1320 register struct obj
*obj
;
1322 register struct monst
*mtmp
;
1323 struct obj
*singleobj
, *mwep
;
1324 char sym
= obj
->oclass
;
1325 int hitu
, blindinc
= 0;
1331 if (DEADMONSTER(mon
)) return;
1333 if (obj
->quan
== 1L) {
1335 * Remove object from minvent. This cannot be done later on;
1336 * what if the player dies before then, leaving the monster
1337 * with 0 daggers? (This caused the infamous 2^32-1 orcish
1340 * VENOM is not in minvent - it should already be OBJ_FREE.
1341 * The extract below does nothing.
1344 /* not possibly_unwield, which checks the object's */
1345 /* location, not its existence */
1346 if (MON_WEP(mon
) == obj
) {
1347 setmnotwielded(mon
,obj
);
1350 obj_extract_self(obj
);
1352 obj
= (struct obj
*) 0;
1354 singleobj
= splitobj(obj
, 1L);
1355 obj_extract_self(singleobj
);
1358 singleobj
->owornmask
= 0; /* threw one of multiple weapons in hand? */
1360 if (mon
) mwep
= MON_WEP(mon
);
1361 else mwep
= (struct obj
*) 0;
1363 /* D: Special launcher effects */
1364 if (mwep
&& is_ammo(singleobj
) && ammo_and_launcher(singleobj
, mwep
)) {
1365 if ((mwep
->oartifact
== ART_PLAGUE
|| mwep
->oartifact
== ART_BOW_OF_VINDERRE
|| mwep
->oartifact
== ART_SHAKING_BOW
|| mwep
->oartifact
== ART_BIBLICAL_PLAGUE
|| mwep
->oartifact
== ART_BOW_OF_HERCULES
) && is_poisonable(singleobj
))
1366 singleobj
->opoisoned
= 1;
1368 /* D: Hellfire is handled in drop_throw */
1371 if (mwep
&& singleobj
&& ammo_and_launcher(singleobj
, mwep
) && is_ammo(singleobj
) && singleobj
->otyp
== POISON_BOLT
) {
1372 singleobj
->opoisoned
= 1;
1375 if (mwep
&& singleobj
&& ammo_and_launcher(singleobj
, mwep
) && is_ammo(singleobj
) && singleobj
->otyp
== CHROME_PELLET
) {
1376 singleobj
->opoisoned
= 1;
1380 if (singleobj
->cursed
&& (dx
|| dy
) && !rn2(7)) {
1381 if(canseemon(mon
) && flags
.verbose
) {
1382 if(is_ammo(singleobj
))
1383 pline("%s misfires!", Monnam(mon
));
1385 pline("%s as %s throws it!",
1386 Tobjnam(singleobj
, "slip"), mon_nam(mon
));
1390 /* check validity of new direction */
1392 (void) drop_throw(mon
, singleobj
, 0, bhitpos
.x
, bhitpos
.y
);
1397 /* pre-check for doors, walls and boundaries.
1398 Also need to pre-check for bars regardless of direction;
1399 the random chance for small objects hitting bars is
1400 skipped when reaching them at point blank range */
1401 if (!isok(bhitpos
.x
+dx
,bhitpos
.y
+dy
)
1402 || (IS_ROCK(levl
[bhitpos
.x
+dx
][bhitpos
.y
+dy
].typ
) && !IS_FARMLAND(levl
[bhitpos
.x
+dx
][bhitpos
.y
+dy
].typ
) )
1403 || IS_WATERTUNNEL(levl
[bhitpos
.x
+dx
][bhitpos
.y
+dy
].typ
)
1404 || closed_door(bhitpos
.x
+dx
, bhitpos
.y
+dy
)
1405 || (levl
[bhitpos
.x
+ dx
][bhitpos
.y
+ dy
].typ
== IRONBARS
&&
1406 hits_bars(&singleobj
, bhitpos
.x
, bhitpos
.y
, 0, 0))) {
1408 if (!isok(bhitpos
.x
+dx
,bhitpos
.y
+dy
) || !((u
.ux
== bhitpos
.x
+dx
) && (u
.uy
== bhitpos
.y
+dy
)) ) {
1409 (void) drop_throw(mon
, singleobj
, 0, bhitpos
.x
, bhitpos
.y
);
1414 /* Note: drop_throw may destroy singleobj. Since obj must be destroyed
1415 * early to avoid the dagger bug, anyone who modifies this code should
1416 * be careful not to use either one after it's been freed.
1418 if (sym
) tmp_at(DISP_FLASH
, obj_to_glyph(singleobj
));
1419 while(range
-- > 0) { /* Actually the loop is always exited by break */
1423 if (!singleobj
) { /* destroyed by hits_bars, bug discovered by amateurhour --Amy */
1424 pline("Some thin air brushes you!");
1428 if ((mtmp
= m_at(bhitpos
.x
, bhitpos
.y
)) != 0) {
1429 if (ohitmon(mon
, mtmp
, singleobj
, range
, TRUE
))
1431 } else if (bhitpos
.x
== u
.ux
&& bhitpos
.y
== u
.uy
) {
1432 if (multi
) nomul(0, 0, FALSE
);
1434 if (singleobj
->oclass
== GEM_CLASS
&&
1435 singleobj
->otyp
<= LAST_GEM
+9 /* 9 glass colors */
1436 && is_unicorn(youmonst
.data
)) {
1437 if (singleobj
->otyp
> LAST_GEM
) {
1438 You("catch the %s.", xname(singleobj
));
1439 You("are not interested in %s junk.",
1440 s_suffix(mon_nam(mon
)));
1441 makeknown(singleobj
->otyp
);
1444 You("accept %s gift in the spirit in which it was intended.",
1445 s_suffix(mon_nam(mon
)));
1446 (void)hold_another_object(singleobj
,
1447 "You catch, but drop, %s.", xname(singleobj
),
1452 if (singleobj
->oclass
== POTION_CLASS
) {
1453 if (!Blind
) singleobj
->dknown
= 1;
1454 potionhit(&youmonst
, singleobj
, FALSE
);
1457 switch(singleobj
->otyp
) {
1460 if (!touch_petrifies(&mons
[singleobj
->corpsenm
])) {
1461 impossible("monster throwing egg type %d",
1462 singleobj
->corpsenm
);
1468 case BLINDING_VENOM
:
1469 hitu
= thitu(8 + (mon
->m_lev
/ 2), 0, singleobj
, (char *)0);
1473 tmpwpndmg
= dmgval(singleobj
, &youmonst
);
1474 if (tmpwpndmg
> 0) {
1475 if (mon
->m_lev
< 2 && u
.urmaxlvlUP
< 4) tmpwpndmg
/= 2;
1476 if (mon
->m_lev
== 2 && u
.urmaxlvlUP
< 4) {
1480 if (mon
->m_lev
== 3 && u
.urmaxlvlUP
< 4) {
1484 if (mon
->m_lev
== 4 && u
.urmaxlvlUP
< 4) {
1488 if (tmpwpndmg
< 1) tmpwpndmg
= 1; /* fail safe */
1492 if (singleobj
->otyp
== BOULDER
&& !rn2(2)) dam
+= (2 * (mon
->m_lev
));
1494 if (singleobj
->otyp
== BOULDER
&& (mon
->data
== &mons
[PM_BOULDER_FART
] || mon
->data
== &mons
[PM_FIRM_BOULDER_FART
])) {
1495 pline("%s produces %s farting noises with %s %s butt.", Monnam(mon
), !rn2(2) ? "loud" : "disgusting", mhis(mon
), mon
->female
? "sexy" : "ugly");
1496 u
.cnd_fartingcount
++;
1497 if (Role_if(PM_CLIMACTERIAL
)) climtrainsqueaking(1);
1498 if (Role_if(PM_BUTT_LOVER
) && !rn2(20)) buttlovertrigger();
1499 if (Role_if(PM_SOCIAL_JUSTICE_WARRIOR
)) sjwtrigger();
1500 if (!extralongsqueak()) badeffect();
1503 hitv
= 3 - distmin(u
.ux
,u
.uy
, mon
->mx
,mon
->my
);
1504 if (hitv
< -4) hitv
= -4;
1505 if (is_elf(mon
->data
) &&
1506 objects
[singleobj
->otyp
].oc_skill
== P_BOW
) {
1509 MON_WEP(mon
)->otyp
== ELVEN_BOW
)
1511 if(singleobj
->otyp
== ELVEN_ARROW
) dam
++;
1513 if (bigmonst(youmonst
.data
)) hitv
++;
1514 /* high-level monsters sometimes deal extra damage --Amy */
1515 if (mon
->m_lev
>= 10 && !rn2(2)) {
1516 hitv
+= 8 + singleobj
->spe
+ ((mon
->m_lev
- 9) / 2);
1518 hitv
+= 8 + singleobj
->spe
;
1520 if (dam
< 1) dam
= 1;
1521 if (mon
&& mon
->data
== &mons
[PM_UTIMA_DESTROYER_OF_XEREN
]) dam
+= rnd(100);
1522 hitu
= thitu(hitv
, dam
, singleobj
, (char *)0);
1524 if (hitu
&& singleobj
->opoisoned
) {
1525 char onmbuf
[BUFSZ
], knmbuf
[BUFSZ
];
1527 strcpy(onmbuf
, xname(singleobj
));
1528 strcpy(knmbuf
, killer_xname(singleobj
));
1529 poisoned(onmbuf
, A_STR
, knmbuf
, -10);
1532 can_blnd((struct monst
*)0, &youmonst
,
1533 (uchar
)(singleobj
->otyp
== BLINDING_VENOM
?
1534 AT_SPIT
: AT_WEAP
), singleobj
)) {
1536 if(singleobj
->otyp
== CREAM_PIE
) {
1537 if(!Blind
) pline("Yecch! You've been creamed.");
1538 else pline("There's %s sticky all over your %s.",
1541 } else if(singleobj
->otyp
== BLINDING_VENOM
) {
1542 int num_eyes
= eyecount(youmonst
.data
);
1543 /* venom in the eyes */
1544 if(!Blind
) pline_The("venom blinds you.");
1545 else Your("%s sting%s.",
1546 (num_eyes
== 1) ? body_part(EYE
) :
1547 makeplural(body_part(EYE
)),
1548 (num_eyes
== 1) ? "s" : "");
1551 if (hitu
&& singleobj
->otyp
== FAERIE_FLOSS_RHING
) {
1552 losexp("a sweet ring of faerie floss", TRUE
, FALSE
);
1553 } /* This ignores level-drain resistance (not a bug). --Amy */
1555 if (hitu
&& singleobj
->otyp
== COLLUSION_KNIFE
&& !(Race_if(PM_PLAYER_NIBELUNG
) && rn2(5))) {
1556 pline("Collusion!");
1559 if (hitu
&& singleobj
->oartifact
== ART_CRUCIFIX_OF_THE_MAD_KING
&& !(Race_if(PM_PLAYER_NIBELUNG
) && rn2(5))) {
1560 pline("Collusion!");
1563 if (hitu
&& singleobj
->oartifact
== ART_BURGLED_NIGHT_SCYTHE
&& !(Race_if(PM_PLAYER_NIBELUNG
) && rn2(5))) {
1564 pline("Collusion!");
1567 if (hitu
&& singleobj
->oartifact
== ART_DARK_CLAYMORE
&& !(Race_if(PM_PLAYER_NIBELUNG
) && rn2(5))) {
1568 pline("Collusion!");
1571 if (hitu
&& singleobj
->otyp
== DARKNESS_CLUB
&& !(Race_if(PM_PLAYER_NIBELUNG
) && rn2(5))) {
1572 pline("Collusion!");
1575 if (hitu
&& singleobj
->otyp
== JUMPING_FLAMER
) {
1576 (void) burnarmor(&youmonst
);
1577 if (isevilvariant
|| !rn2(Race_if(PM_SEA_ELF
) ? 1 : issoviet
? 2 : 5)) destroy_item(SCROLL_CLASS
, AD_FIRE
);
1578 if (isevilvariant
|| !rn2(Race_if(PM_SEA_ELF
) ? 1 : issoviet
? 2 : 5)) destroy_item(SPBOOK_CLASS
, AD_FIRE
);
1579 if (isevilvariant
|| !rn2(Race_if(PM_SEA_ELF
) ? 1 : issoviet
? 2 : 5)) destroy_item(POTION_CLASS
, AD_FIRE
);
1581 if (hitu
&& singleobj
->otyp
== FLAMETHROWER
) {
1582 (void) burnarmor(&youmonst
);
1583 if (isevilvariant
|| !rn2(Race_if(PM_SEA_ELF
) ? 1 : issoviet
? 2 : 5)) destroy_item(SCROLL_CLASS
, AD_FIRE
);
1584 if (isevilvariant
|| !rn2(Race_if(PM_SEA_ELF
) ? 1 : issoviet
? 2 : 5)) destroy_item(SPBOOK_CLASS
, AD_FIRE
);
1585 if (isevilvariant
|| !rn2(Race_if(PM_SEA_ELF
) ? 1 : issoviet
? 2 : 5)) destroy_item(POTION_CLASS
, AD_FIRE
);
1587 if (hitu
&& singleobj
->otyp
== YITH_TENTACLE
) {
1588 increasesanity(rnz(monster_difficulty() + 1));
1590 if (hitu
&& singleobj
->otyp
== NASTYPOLE
&& !rn2(10)) {
1593 if (hitu
&& singleobj
->otyp
== DISINTEGRATION_BAR
) {
1594 if ((!Disint_resistance
|| !rn2(StrongDisint_resistance
? 1000 : 100) || (evilfriday
&& (uarms
|| uarmc
|| uarm
|| uarmu
)) ) && !rn2(10)) {
1595 You_feel("like you're falling apart!");
1598 /* destroy shield; other possessions are safe */
1599 if (!(EDisint_resistance
& W_ARMS
) && !(itemsurvivedestruction(uarms
, 12)) ) (void) destroy_arm(uarms
);
1601 /* destroy cloak; other possessions are safe */
1602 if (!(EDisint_resistance
& W_ARMC
) && !(itemsurvivedestruction(uarmc
, 12)) ) (void) destroy_arm(uarmc
);
1605 if (!(EDisint_resistance
& W_ARM
) && !(itemsurvivedestruction(uarm
, 12)) ) (void) destroy_arm(uarm
);
1608 if (!(EDisint_resistance
& W_ARMU
) && !(itemsurvivedestruction(uarmu
, 12)) ) (void) destroy_arm(uarmu
);
1610 if (u
.uhpmax
> 20) {
1611 u
.uhpmax
-= rnd(20);
1612 if (u
.uhp
> u
.uhpmax
) u
.uhp
= u
.uhpmax
;
1613 losehp(rnz(100 + level_difficulty()), "click click click click click you died", KILLED_BY
);
1624 if (hitu
&& singleobj
->otyp
== PETRIFYIUM_BAR
) {
1625 if ((!Stone_resistance
|| (!IntStone_resistance
&& !rn2(20)) ) &&
1626 !(poly_when_stoned(youmonst
.data
) && polymon(PM_STONE_GOLEM
))) {
1628 if (Hallucination
&& rn2(10)) pline("Thankfully you are already stoned.");
1630 Stoned
= Race_if(PM_EROSATOR
) ? 3 : 7;
1631 u
.cnd_stoningcount
++;
1632 pline("You start turning to stone!");
1635 sprintf(killer_buf
, "petrifyium bar");
1636 delayed_killer
= killer_buf
;
1641 if (hitu
&& singleobj
->otyp
== EGG
) {
1642 if ((!Stone_resistance
|| (!IntStone_resistance
&& !rn2(20)) ) && !(poly_when_stoned(youmonst
.data
) && polymon(PM_STONE_GOLEM
))) {
1643 if (Hallucination
&& rn2(10)) pline("Thankfully you are already stoned.");
1644 else if (Stoned
) pline("You are already stoned.");
1646 You("start turning to stone!");
1647 Stoned
= Race_if(PM_EROSATOR
) ? 3 : 7;
1648 u
.cnd_stoningcount
++;
1649 delayed_killer
= "thrown petrifying egg";
1654 if (hitu
|| !range
) {
1655 (void) drop_throw(mon
, singleobj
, hitu
, u
.ux
, u
.uy
);
1659 if (!range
/* reached end of path */
1660 /* missile hits edge of screen */
1661 || !isok(bhitpos
.x
+dx
,bhitpos
.y
+dy
)
1662 /* missile hits the wall */
1663 || (IS_ROCK(levl
[bhitpos
.x
+dx
][bhitpos
.y
+dy
].typ
) && !IS_FARMLAND(levl
[bhitpos
.x
+dx
][bhitpos
.y
+dy
].typ
))
1664 /* missile hit closed door */
1665 || closed_door(bhitpos
.x
+dx
, bhitpos
.y
+dy
)
1666 /* missile might hit bars */
1667 || (levl
[bhitpos
.x
+dx
][bhitpos
.y
+dy
].typ
== IRONBARS
&&
1668 hits_bars(&singleobj
, bhitpos
.x
, bhitpos
.y
, !rn2(5), 0))
1669 /* Thrown objects "sink" */
1670 || IS_SINK(levl
[bhitpos
.x
][bhitpos
.y
].typ
)
1671 || IS_WATERTUNNEL(levl
[bhitpos
.x
][bhitpos
.y
].typ
)
1674 if (!range
|| IS_SINK(levl
[bhitpos
.x
][bhitpos
.y
].typ
) || IS_WATERTUNNEL(levl
[bhitpos
.x
][bhitpos
.y
].typ
) || !isok(bhitpos
.x
+dx
,bhitpos
.y
+dy
) || !((u
.ux
== bhitpos
.x
+dx
) && (u
.uy
== bhitpos
.y
+dy
)) ) {
1675 if (singleobj
) /* hits_bars might have destroyed it */
1676 (void) drop_throw(mon
, singleobj
, 0, bhitpos
.x
, bhitpos
.y
);
1681 tmp_at(bhitpos
.x
, bhitpos
.y
);
1684 tmp_at(bhitpos
.x
, bhitpos
.y
);
1686 tmp_at(DISP_END
, 0);
1689 u
.ucreamed
+= blindinc
;
1690 make_blinded(Blinded
+ (long)blindinc
, FALSE
);
1691 if (!Blind
) Your("%s", vision_clears
);
1698 /* Remove an item from the monster's inventory and destroy it. */
1704 if (obj
->quan
> 1L) {
1706 obj
->owt
= weight(obj
);
1708 obj_extract_self(obj
);
1709 possibly_unwield(mon
, FALSE
);
1710 if (obj
->owornmask
) {
1711 mon
->misc_worn_check
&= ~(obj
->owornmask
);
1712 update_mon_intrinsics(mon
, obj
, FALSE
, FALSE
);
1714 obfree(obj
, (struct obj
*) 0);
1721 /* monster attempts ranged weapon attack against player */
1726 if (DEADMONSTER(mtmp
)) return;
1728 struct obj
*otmp
, *mwep
;
1735 int polelimit
= POLE_LIM
;
1738 if (mtmp
->data
== &mons
[PM_MECHTNED
]) return;
1739 if (mtmp
->data
== &mons
[PM_IMPALAZON
]) return;
1740 if (mtmp
->data
== &mons
[PM_MYSTERY_WOMAN
]) return;
1741 if (mtmp
->data
== &mons
[PM_SILVER_LADY_PUMP
]) return;
1742 if (uarm
&& uarm
->oartifact
== ART_RANGED_REDUCER
&& !rn2(3)) return;
1744 /* Rearranged beginning so monsters can use polearms not in a line */
1745 if (mtmp
->weapon_check
== NEED_WEAPON
|| !MON_WEP(mtmp
)) {
1746 mtmp
->weapon_check
= NEED_RANGED_WEAPON
;
1747 /* mon_wield_item resets weapon_check as appropriate */
1748 if(mon_wield_item(mtmp
) != 0) return;
1752 otmp
= select_rwep(mtmp
, FALSE
);
1755 if ((MON_WEP(mtmp
) == otmp
) && is_applypole(otmp
)) {
1758 if (otmp
->otyp
== NOOB_POLLAX
|| otmp
->otyp
== GREAT_POLLAX
) polelimit
+= 5;
1759 if (otmp
->otyp
== YITH_TENTACLE
) polelimit
+= 2;
1760 if (otmp
->otyp
== POLE_LANTERN
) polelimit
+= 10;
1761 if (otmp
->otyp
== NASTYPOLE
) polelimit
+= 8;
1762 if (otmp
->oartifact
== ART_ETHER_PENETRATOR
) polelimit
+= 5;
1763 if (otmp
->oartifact
== ART_FUURKER
) polelimit
+= 6;
1764 if (otmp
->otyp
== WOODEN_BAR
) polelimit
+= 7;
1765 if (otmp
->oartifact
== ART_OVERLONG_STICK
) polelimit
+= 12;
1766 /* monsters cheat and ignore the increased minimum range :P */
1768 if (dist2(mtmp
->mx
, mtmp
->my
, mtmp
->mux
, mtmp
->muy
) > polelimit
||
1769 !couldsee(mtmp
->mx
, mtmp
->my
))
1770 return; /* Out of range, or intervening wall */
1772 if (canseemon(mtmp
)) {
1774 pline("%s thrusts %s.", Monnam(mtmp
),
1775 obj_is_pname(otmp
) ? the(onm
) : an(onm
));
1778 tmpwpndmg
= dmgval(otmp
, &youmonst
);
1779 if (tmpwpndmg
> 0) {
1780 if (mtmp
->m_lev
< 2 && u
.urmaxlvlUP
< 4) tmpwpndmg
/= 2;
1781 if (mtmp
->m_lev
== 2 && u
.urmaxlvlUP
< 4) {
1785 if (mtmp
->m_lev
== 3 && u
.urmaxlvlUP
< 4) {
1789 if (mtmp
->m_lev
== 4 && u
.urmaxlvlUP
< 4) {
1793 if (tmpwpndmg
< 1) tmpwpndmg
= 1; /* fail safe */
1797 hitv
= 3 - distmin(u
.ux
,u
.uy
, mtmp
->mx
,mtmp
->my
);
1798 if (hitv
< -4) hitv
= -4;
1799 if (bigmonst(youmonst
.data
)) hitv
++;
1800 hitv
+= 8 + otmp
->spe
;
1801 if (dam
< 1) dam
= 1;
1802 if (mtmp
->m_lev
>= 3) dam
+= rnd(mtmp
->m_lev
/ 3);
1804 (void) thitu(hitv
, dam
, otmp
, (char *)0);
1811 /* If you are coming toward the monster, the monster
1812 * should try to soften you up with missiles. If you are
1813 * going away, you are probably hurt or running. Give
1814 * chase, but if you are getting too far away, throw.
1816 /* WAC Catch this since rn2(0) is illegal */
1817 chance
= (BOLT_LIM
- distmin(x
,y
,mtmp
->mux
,mtmp
->muy
) > 0) ?
1818 BOLT_LIM
- distmin(x
,y
,mtmp
->mux
,mtmp
->muy
) : 1;
1819 if (!lined_upB(mtmp
) || (URETREATING(x
,y
) && rn2(chance
)))
1822 skill
= objects
[otmp
->otyp
].oc_skill
;
1823 mwep
= MON_WEP(mtmp
); /* wielded weapon */
1825 if (!(elongation_monster(mtmp
->data
) || ElongationBug
|| u
.uprops
[ELONGATION_BUG
].extrinsic
|| have_elongatedstone()) && mwep
&& ammo_and_launcher(otmp
, mwep
) && objects
[mwep
->otyp
].oc_range
&&
1826 dist2(mtmp
->mx
, mtmp
->my
, mtmp
->mux
, mtmp
->muy
) >
1827 objects
[mwep
->otyp
].oc_range
* objects
[mwep
->otyp
].oc_range
)
1828 return; /* Out of range */
1830 if (!(elongation_monster(mtmp
->data
) || ElongationBug
|| u
.uprops
[ELONGATION_BUG
].extrinsic
|| have_elongatedstone())
1831 && (uarm
&& uarm
->oartifact
== ART_SLOW_MISSILES
) && (dist2(mtmp
->mx
, mtmp
->my
, mtmp
->mux
, mtmp
->muy
) > (BOLT_LIM
*BOLT_LIM
)) )
1832 return; /* Out of range */
1834 /* monsters were throwing darts way across the map, that is, distances of 70+ squares.
1835 * This was obviously not intended; they should just be able to fire sniper rifles at their actual range. --Amy */
1836 if (!(elongation_monster(mtmp
->data
) || ElongationBug
|| u
.uprops
[ELONGATION_BUG
].extrinsic
|| have_elongatedstone()) && !(mwep
&& ammo_and_launcher(otmp
, mwep
) && objects
[mwep
->otyp
].oc_range
) && dist2(mtmp
->mx
, mtmp
->my
, mtmp
->mux
, mtmp
->muy
) > ((BOLT_LIM
+ strongmonst(mtmp
->data
) ) * (BOLT_LIM
+ strongmonst(mtmp
->data
) )) ) return;
1838 /* Multishot calculations */
1840 if (((mwep
&& ammo_and_launcher(otmp
, mwep
)) || skill
== P_DAGGER
|| skill
== P_KNIFE
|| skill
== P_BOOMERANG
|| skill
== -P_BOOMERANG
||
1841 skill
== -P_DART
|| skill
== -P_SHURIKEN
|| skill
== P_SPEAR
|| skill
== P_JAVELIN
) && !mtmp
->mconf
) {
1842 /* Assumes lords are skilled, princes are expert */
1843 if (is_prince(mtmp
->data
)) multishot
+= 2;
1844 else if (is_lord(mtmp
->data
)) multishot
++;
1846 if (MonsterMultishotBug
|| u
.uprops
[MONSTER_MULTISHOT_EFFECT
].extrinsic
|| have_monstermultishotstone()) {
1847 int multishotbonus
= (mtmp
->m_lev
/ 3);
1848 if (multishotbonus
< 1) multishotbonus
= 1; /* fail safe */
1849 multishotbonus
= rno(multishotbonus
);
1850 multishot
+= multishotbonus
;
1853 /* strong, nasty or high-level monsters can also shoot more --Amy */
1854 if (mtmp
->m_lev
>= 10 && strongmonst(mtmp
->data
) && !rn2(3)) multishot
++;
1855 if (mtmp
->m_lev
>= 10 && strongmonst(mtmp
->data
) && !rn2(9)) multishot
++;
1856 if (mtmp
->m_lev
>= 10 && strongmonst(mtmp
->data
) && !rn2(27)) multishot
++;
1858 if (mtmp
->m_lev
>= 10 && extra_nasty(mtmp
->data
) && !rn2(2)) multishot
++;
1859 if (mtmp
->m_lev
>= 10 && extra_nasty(mtmp
->data
) && !rn2(4)) multishot
++;
1860 if (mtmp
->m_lev
>= 10 && extra_nasty(mtmp
->data
) && !rn2(8)) multishot
++;
1862 if (mtmp
->m_lev
>= 10 && mtmp
->m_lev
< 20) multishot
+= 1;
1863 if (mtmp
->m_lev
>= 20 && mtmp
->m_lev
< 30) multishot
+= rnd(2);
1864 if (mtmp
->m_lev
>= 30 && mtmp
->m_lev
< 40) multishot
+= rnd(3);
1865 if (mtmp
->m_lev
>= 40 && mtmp
->m_lev
< 50) multishot
+= rnd(4);
1866 if (mtmp
->m_lev
>= 50 && mtmp
->m_lev
< 60) multishot
+= rnd(5);
1867 if (mtmp
->m_lev
>= 60 && mtmp
->m_lev
< 70) multishot
+= rnd(6);
1868 if (mtmp
->m_lev
>= 70 && mtmp
->m_lev
< 80) multishot
+= rnd(7);
1869 if (mtmp
->m_lev
>= 80 && mtmp
->m_lev
< 90) multishot
+= rnd(8);
1870 if (mtmp
->m_lev
>= 90 && mtmp
->m_lev
< 100) multishot
+= rnd(9);
1871 if (mtmp
->m_lev
>= 100) multishot
+= rnd(10);
1873 /* Elven Craftsmanship makes for light, quick bows */
1874 if (otmp
->otyp
== ELVEN_ARROW
&& !otmp
->cursed
)
1876 if (mwep
&& mwep
->otyp
== ELVEN_BOW
&& !mwep
->cursed
) multishot
++;
1878 if (mwep
&& mwep
->otyp
== WILDHILD_BOW
&& otmp
->otyp
== ODOR_SHOT
) multishot
++;
1879 if (mwep
&& mwep
->otyp
== COMPOST_BOW
&& otmp
->otyp
== FORBIDDEN_ARROW
) multishot
++;
1881 if (mwep
&& mwep
->otyp
== CATAPULT
) multishot
+= rnd(5);
1883 if (mwep
&& mwep
->otyp
== HYDRA_BOW
) multishot
+= 2;
1884 if (mwep
&& mwep
->otyp
== DEMON_CROSSBOW
) multishot
+= 4;
1885 if (mwep
&& mwep
->otyp
== WILDHILD_BOW
) multishot
+= 2;
1887 if (mwep
&& is_lightsaber(mwep
) && mwep
->lamplit
) { /* djem so monster lightsaber form */
1889 if (mtmp
->data
->geno
& G_UNIQ
) multishot
+= 1;
1892 if (otmp
&& otmp
->otyp
== RAPID_DART
) multishot
+= 2;
1893 if (otmp
&& otmp
->otyp
== NINJA_STAR
) multishot
+= 3;
1894 if (otmp
&& otmp
->otyp
== FLAMETHROWER
) multishot
+= 4;
1896 /* 1/3 of object enchantment */
1897 if (mwep
&& mwep
->spe
> 1)
1898 multishot
+= rounddiv(mwep
->spe
, 3);
1899 /* Some randomness */
1901 multishot
= rnd(multishot
);
1902 if (mwep
&& objects
[mwep
->otyp
].oc_rof
&& is_launcher(mwep
))
1903 multishot
+= objects
[mwep
->otyp
].oc_rof
;
1905 switch (monsndx(mtmp
->data
)) {
1907 case PM_IBERIAN_SOLDIER
:
1910 case PM_BLUE_ARCHER
:
1915 case PM_GATLING_ARCHER
:
1918 case PM_PELLET_ARCHER
:
1920 case PM_SHOTGUN_HORROR
:
1921 case PM_SHOTGUN_TERROR
:
1922 case PM_KOBOLD_PEPPERMASTER
:
1931 if (otmp
->otyp
== ELVEN_ARROW
&& mwep
&& mwep
->otyp
== ELVEN_BOW
) multishot
++;
1934 if (skill
== P_DAGGER
) multishot
++;
1937 if (skill
== P_JAVELIN
) multishot
++;
1940 case PM_NINJA_GAIDEN
:
1942 if (otmp
->otyp
== YA
&& mwep
&& mwep
->otyp
== YUMI
) multishot
++;
1943 if (otmp
->otyp
== FAR_EAST_ARROW
&& mwep
&& mwep
->otyp
== YUMI
) multishot
++;
1949 if ((is_elf(mtmp
->data
) &&
1950 otmp
->otyp
== ELVEN_ARROW
&&
1951 mwep
&& mwep
->otyp
== ELVEN_BOW
) ||
1952 (is_orc(mtmp
->data
) &&
1953 otmp
->otyp
== ORCISH_ARROW
&&
1954 mwep
&& mwep
->otyp
== ORCISH_BOW
))
1957 if (mwep
&& mwep
->otyp
== PISTOL_PAIR
) multishot
*= 2;
1959 /* weaker monsters shouldn't spam you with thousands of arrows --Amy */
1960 if (!rn2(2) && !strongmonst(mtmp
->data
) && !extra_nasty(mtmp
->data
) && !(mtmp
->data
->geno
& G_UNIQ
) && multishot
> 1) multishot
-= rnd(multishot
/ 2);
1962 if ((long)multishot
> otmp
->quan
) multishot
= (int)otmp
->quan
;
1964 /* we don't want monsters to throw their entire stack of daggers if that's what they use in melee --Amy
1965 * also they shouldn't fire the last from a stack of artifact ammo, because they can melee with it */
1966 if ((long)multishot
== otmp
->quan
&& (multishot
> 1) && ((otmp
== MON_WEP(mtmp
)) || (otmp
->oartifact
&& !(otmp
->oartifact
== ART_SIEGFRIED_S_DEATHBOLT
)) ) ) {
1968 if (multishot
< 1) multishot
= 1; /* shouldn't happen */
1971 if (multishot
< 1) multishot
= 1;
1972 /* else multishot = rnd(multishot); */
1975 if (canseemon(mtmp
)) {
1978 if (multishot
> 1) {
1979 /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
1980 xname()'s result will already be pluralized */
1981 sprintf(onmbuf
, "%d %s", multishot
, xname(otmp
));
1985 onm
= singular(otmp
, xname
);
1986 onm
= obj_is_pname(otmp
) ? the(onm
) : an(onm
);
1988 m_shot
.s
= (mwep
&& ammo_and_launcher(otmp
,mwep
)) ? TRUE
: FALSE
;
1989 pline("%s %s %s!", Monnam(mtmp
),
1990 m_shot
.s
? is_bullet(otmp
) ? "fires" : "shoots" : "throws",
1992 m_shot
.o
= otmp
->otyp
;
1995 m_shot
.s
= (mwep
&& ammo_and_launcher(otmp
,mwep
)) ? TRUE
: FALSE
;
1997 if (flags
.soundok
&& !issoviet
) {
1999 /* at least tell the player that something's happening, instead of stupidly stopping input while the off-screen
2000 * projectile is flying (which can make the player think the game hangs when the projectile was fired from
2001 * far away, since it may delay output for several seconds while nothing apparently happens) --Amy */
2002 if (multishot
> 1) {
2003 if (is_bullet(otmp
)) You_hear("several gunshots.");
2004 else if (m_shot
.s
) You_hear("rapid shooting sounds.");
2005 else You_hear("multiple flinging sounds.");
2007 if (is_bullet(otmp
)) You_hear("the sound of gunfire.");
2008 else if (m_shot
.s
) You_hear("a shooting sound.");
2009 else You_hear("a flinging sound.");
2012 m_shot
.o
= STRANGE_OBJECT
; /* don't give multishot feedback */
2015 m_shot
.n
= multishot
;
2016 for (m_shot
.i
= 1; m_shot
.i
<= m_shot
.n
; m_shot
.i
++)
2017 m_throw(mtmp
, mtmp
->mx
, mtmp
->my
, sgn(tbx
), sgn(tby
),
2018 distmin(mtmp
->mx
, mtmp
->my
, mtmp
->mux
, mtmp
->muy
), otmp
);
2019 m_shot
.n
= m_shot
.i
= 0;
2020 m_shot
.o
= STRANGE_OBJECT
;
2030 spitmu(mtmp
, mattk
) /* monster spits substance at you */
2031 register struct monst
*mtmp
;
2032 register struct attack
*mattk
;
2034 register struct obj
*otmp
;
2036 if (DEADMONSTER(mtmp
)) return 0;
2041 pline("A dry rattle comes from %s throat.",
2042 s_suffix(mon_nam(mtmp
)));
2045 if(lined_up(mtmp
)) {
2046 if (issegfaulter
&& rn2(10)) {
2047 otmp
= mksobj(SEGFAULT_VENOM
, TRUE
, FALSE
, FALSE
);
2048 } else switch (mattk
->adtyp
) {
2051 otmp
= mksobj(BLINDING_VENOM
, TRUE
, FALSE
, FALSE
);
2054 otmp
= mksobj(FAERIE_FLOSS_RHING
, TRUE
, FALSE
, FALSE
);
2057 otmp
= mksobj(SEGFAULT_VENOM
, TRUE
, FALSE
, FALSE
);
2060 otmp
= mksobj(TAIL_SPIKES
, TRUE
, FALSE
, FALSE
);
2063 pline("bad attack type in spitmu");
2066 otmp
= mksobj(ACID_VENOM
, TRUE
, FALSE
, FALSE
);
2069 if (!otmp
) return 0;
2071 otmp
->owt
= weight(otmp
);
2073 if(!rn2(BOLT_LIM
-distmin(mtmp
->mx
,mtmp
->my
,mtmp
->mux
,mtmp
->muy
))) {
2074 if (canseemon(mtmp
))
2075 pline("%s spits venom!", Monnam(mtmp
));
2076 else if (flags
.soundok
&& !issoviet
) You_hear("a spitting sound.");
2077 m_throw(mtmp
, mtmp
->mx
, mtmp
->my
, sgn(tbx
), sgn(tby
),
2078 distmin(mtmp
->mx
,mtmp
->my
,mtmp
->mux
,mtmp
->muy
), otmp
);
2090 breamu(mtmp
, mattk
) /* monster breathes at you (ranged) */
2091 register struct monst
*mtmp
;
2092 register struct attack
*mattk
;
2094 if (DEADMONSTER(mtmp
)) return 0;
2096 /* if new breath types are added, change AD_ACID to max type */
2097 int typ
= (mattk
->adtyp
== AD_RBRE
) ? rnd(AD_SPC2
) : mattk
->adtyp
;
2099 if (typ
< AD_MAGM
|| typ
> AD_SPC2
) typ
= rnd(AD_SPC2
); /* for shambling horrors etc. --Amy */
2101 if(lined_up(mtmp
)) {
2106 pline("%s coughs.", Monnam(mtmp
));
2108 You_hear("a cough.");
2112 if(!mtmp
->mspec_used
&& rn2(3)) {
2114 if((typ
>= AD_MAGM
) && (typ
<= AD_SPC2
)) {
2116 /* angband has the infamous "it breathes" deaths --Amy */
2118 if (isangbander
&& rn2(2) && (rnd( (int)mattk
->damn
* 6) > u
.uhp
)) {
2122 pline("It breathes"); /* The following --More-- prompt is forced and shall not be disabled --Amy */
2123 display_nhwindow(WIN_MESSAGE
, TRUE
); /* --More-- */
2124 pline("You have died.");
2126 killer_format
= KILLED_BY_AN
;
2127 killer
= "fatal breath attack";
2135 if (isangbander
&& rn2(2) && (rnd( (int)mattk
->damd
* 6) > u
.uhp
)) {
2139 pline("It breathes");
2140 display_nhwindow(WIN_MESSAGE
, TRUE
); /* --More-- */
2141 pline("You have died.");
2143 killer_format
= KILLED_BY_AN
;
2144 killer
= "fatal breath attack";
2152 /* In Soviet Russia, no player may ever know anything. Whether it's a dragon breathing at you,
2153 * a gnome trying to shoot you with his crossbow, or a cobra spitting venom... "if you can't see it,
2154 * it doesn't exist". Or rather, "if there was no message about it in SLASH'EM then there may not be one
2155 * here either". Yes, it's unbelievable, but that's what they are thinking. --Amy */
2158 pline("%s breathes %s!", Monnam(mtmp
),
2159 FunnyHallu
? hallubreathwep
[rn2(SIZE(hallubreathwep
))] : breathwep
[typ
-1]);
2160 else if (flags
.soundok
&& !issoviet
) {
2161 if (isangbander
) pline("It breathes.");
2162 else You_hear("an exhaling sound.");
2164 if (mtmp
->data
== &mons
[PM_AUTO_AIM_CHEATAH
]) u
.uprops
[DEAC_REFLECTING
].intrinsic
+= 5;
2166 if (flags
.moreforced
&& !MessagesSuppressed
) display_nhwindow(WIN_MESSAGE
, TRUE
); /* --More-- */
2167 buzz((int) (-20 - (typ
-1)), (rn2(2) ? (int)mattk
->damn
: (int)mattk
->damd
),
2168 mtmp
->mx
, mtmp
->my
, sgn(tbx
), sgn(tby
));
2170 /* breath runs out sometimes. Also, give monster some
2171 * cunning; don't breath if the player fell asleep.
2174 mtmp
->mspec_used
= 10+rn2(20);
2175 if(typ
== AD_SLEE
&& !Sleep_resistance
)
2176 mtmp
->mspec_used
+= rnd(20);
2177 } else pline("Breath weapon %d used", typ
-1);
2184 /* WAC for doorbusting ONLY (at this point in time) No checks */
2186 breamspot(mtmp
, mattk
, ax
, ay
)
2187 register struct monst
*mtmp
;
2188 register struct attack
*mattk
;
2191 /* if new breath types are added, change AD_ACID to max type */
2192 int typ
= (mattk
->adtyp
== AD_RBRE
) ? rnd(AD_SPC2
) : mattk
->adtyp
;
2194 if (DEADMONSTER(mtmp
)) return 0;
2196 if((typ
>= AD_MAGM
) && (typ
<= AD_SPC2
)) {
2198 pline("%s breathes %s!", Monnam(mtmp
),
2199 FunnyHallu
? hallubreathwep
[rn2(SIZE(hallubreathwep
))] : breathwep
[typ
-1]);
2200 if (flags
.moreforced
&& !MessagesSuppressed
) display_nhwindow(WIN_MESSAGE
, TRUE
); /* --More-- */
2201 /* Do the door first - monster is ON TOP so call direct */
2202 zap_over_floor(mtmp
->mx
, mtmp
->my
, (int) (-20 - (typ
-1)), NULL
);
2203 buzz((int) (-20 - (typ
-1)), (rn2(2) ? (int)mattk
->damn
: (int)mattk
->damd
),
2204 mtmp
->mx
, mtmp
->my
, ax
, ay
);
2206 /* breath runs out sometimes. */
2208 mtmp
->mspec_used
= 10+rn2(20);
2209 } else impossible("Breath weapon %d used", typ
-1);
2215 linedup(ax
, ay
, bx
, by
, special
)
2216 register xchar ax
, ay
, bx
, by
;
2217 boolean special
; /* for monsters that can shoot from infinite distance --Amy */
2220 tbx
= ax
- bx
; /* These two values are set for use */
2221 tby
= ay
- by
; /* after successful return. */
2223 /* sometimes displacement makes a monster think that you're at its
2224 own location; prevent it from throwing and zapping in that case */
2225 if (!tbx
&& !tby
) return FALSE
;
2227 if ((!tbx
|| !tby
|| abs(tbx
) == abs(tby
)) /* straight line or diagonal */
2228 && distmin(tbx
, tby
, 0, 0) < ((special
|| ElongationBug
|| u
.uprops
[ELONGATION_BUG
].extrinsic
|| have_elongatedstone()) ? 100 : EnglandMode
? 10 : BOLT_LIM
) ) {
2229 if ((ax
== u
.ux
&& ay
== u
.uy
) ? (boolean
) couldsee(bx
, by
) : clear_path(ax
, ay
, bx
, by
))
2231 /* don't have line of sight, but might still be lined up
2232 if that lack of sight is due solely to boulders */
2233 dx
= sgn(ax
- bx
), dy
= sgn(ay
- by
);
2235 /* <bx,by> is guaranteed to eventually converge with <ax,ay> */
2237 if ((IS_ROCK(levl
[bx
][by
].typ
) && !IS_FARMLAND(levl
[bx
][by
].typ
)) || IS_WATERTUNNEL(levl
[bx
][by
].typ
) || closed_door(bx
, by
))
2239 } while (bx
!= ax
|| by
!= ay
);
2240 /* reached target position without encountering obstacle */
2244 /*if((!tbx || !tby || abs(tbx) == abs(tby))*/ /* straight line or diagonal */
2245 /* && distmin(tbx, tby, 0, 0) < ((ElongationBug || u.uprops[ELONGATION_BUG].extrinsic || have_elongatedstone()) ? 100 : EnglandMode ? 10 : BOLT_LIM)) {
2246 if(ax == u.ux && ay == u.uy) return((boolean)(couldsee(bx,by)));
2247 else if(clear_path(ax,ay,bx,by)) return TRUE;
2253 linedupB(ax
, ay
, bx
, by
) /* without the distance check --Amy */
2254 register xchar ax
, ay
, bx
, by
;
2257 tbx
= ax
- bx
; /* These two values are set for use */
2258 tby
= ay
- by
; /* after successful return. */
2260 /* sometimes displacement makes a monster think that you're at its
2261 own location; prevent it from throwing and zapping in that case */
2262 if (!tbx
&& !tby
) return FALSE
;
2264 if ((!tbx
|| !tby
|| abs(tbx
) == abs(tby
)) /* straight line or diagonal */
2266 if ((ax
== u
.ux
&& ay
== u
.uy
) ? (boolean
) couldsee(bx
, by
) : clear_path(ax
, ay
, bx
, by
))
2268 /* don't have line of sight, but might still be lined up
2269 if that lack of sight is due solely to boulders */
2270 dx
= sgn(ax
- bx
), dy
= sgn(ay
- by
);
2272 /* <bx,by> is guaranteed to eventually converge with <ax,ay> */
2274 if ((IS_ROCK(levl
[bx
][by
].typ
) && !IS_FARMLAND(levl
[bx
][by
].typ
)) || IS_WATERTUNNEL(levl
[bx
][by
].typ
) || closed_door(bx
, by
))
2276 } while (bx
!= ax
|| by
!= ay
);
2277 /* reached target position without encountering obstacle */
2281 /*if((!tbx || !tby || abs(tbx) == abs(tby)))*/ /* straight line or diagonal */
2283 if(ax == u.ux && ay == u.uy) return((boolean)(couldsee(bx,by)));
2284 else if(clear_path(ax,ay,bx,by)) return TRUE;
2290 lined_up(mtmp
) /* is mtmp in position to use ranged attack? */
2291 register struct monst
*mtmp
;
2293 return(linedup(mtmp
->mux
,mtmp
->muy
,mtmp
->mx
,mtmp
->my
, (elongation_monster(mtmp
->data
)) ));
2297 lined_upB(mtmp
) /* is mtmp in position to use ranged attack? */
2298 register struct monst
*mtmp
;
2300 return(linedupB(mtmp
->mux
,mtmp
->muy
,mtmp
->mx
,mtmp
->my
));
2306 /* Check if a monster is carrying a particular item.
2309 m_carrying(mtmp
, type
)
2313 register struct obj
*otmp
;
2315 for(otmp
= mtmp
->minvent
; otmp
; otmp
= otmp
->nobj
)
2316 if(otmp
->otyp
== type
)
2318 return((struct obj
*) 0);
2321 /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
2323 hits_bars(obj_p
, x
, y
, always_hit
, whodidit
)
2324 struct obj
**obj_p
; /* *obj_p will be set to NULL if object breaks */
2326 int always_hit
; /* caller can force a hit for items which would fit through */
2327 int whodidit
; /* 1==hero, 0=other, -1==just check whether it'll pass thru */
2329 struct obj
*otmp
= *obj_p
;
2330 int obj_type
= otmp
->otyp
;
2331 boolean hits
= always_hit
;
2334 switch (otmp
->oclass
) {
2337 int oskill
= objects
[obj_type
].oc_skill
;
2339 hits
= (oskill
!= -P_BOW
&& oskill
!= -P_CROSSBOW
&&
2340 oskill
!= -P_DART
&& oskill
!= -P_SHURIKEN
&&
2341 (oskill
!= -P_FIREARM
|| obj_type
== ROCKET
|| obj_type
== MINI_NUKE
) &&
2342 oskill
!= P_SPEAR
&& oskill
!= P_JAVELIN
&&
2343 oskill
!= P_KNIFE
); /* but not dagger */
2347 hits
= (objects
[obj_type
].oc_armcat
!= ARM_GLOVES
);
2350 hits
= (obj_type
!= SKELETON_KEY
&&
2351 obj_type
!= SECRET_KEY
&&
2352 obj_type
!= LOCK_PICK
&&
2353 obj_type
!= HAIRCLIP
&&
2354 obj_type
!= CREDIT_CARD
&&
2355 obj_type
!= DATA_CHIP
&&
2356 obj_type
!= TALLOW_CANDLE
&&
2357 obj_type
!= WAX_CANDLE
&&
2358 obj_type
!= JAPAN_WAX_CANDLE
&&
2359 obj_type
!= OIL_CANDLE
&&
2360 obj_type
!= UNAFFECTED_CANDLE
&&
2361 obj_type
!= SPECIFIC_CANDLE
&&
2362 obj_type
!= __CANDLE
&&
2363 obj_type
!= NATURAL_CANDLE
&&
2364 obj_type
!= UNSPECIFIED_CANDLE
&&
2365 obj_type
!= GENERAL_CANDLE
&&
2366 obj_type
!= LENSES
&&
2367 obj_type
!= RADIOGLASSES
&&
2368 obj_type
!= SHIELD_PATE_GLASSES
&&
2369 obj_type
!= BOSS_VISOR
&&
2370 obj_type
!= NIGHT_VISION_GOGGLES
&&
2371 obj_type
!= TIN_WHISTLE
&&
2372 obj_type
!= GRASS_WHISTLE
&&
2373 obj_type
!= MAGIC_WHISTLE
);
2375 case ROCK_CLASS
: /* includes boulder */
2376 if (obj_type
!= STATUE
||
2377 mons
[otmp
->corpsenm
].msize
> MZ_TINY
) hits
= TRUE
;
2380 if (obj_type
== CORPSE
&&
2381 mons
[otmp
->corpsenm
].msize
> MZ_TINY
) hits
= TRUE
;
2383 hits
= (obj_type
== MEAT_STICK
||
2384 obj_type
== HUGE_CHUNK_OF_MEAT
);
2396 if (hits
&& whodidit
!= -1) {
2397 if (whodidit
? hero_breaks(otmp
, x
, y
, FALSE
) : breaks(otmp
, x
, y
))
2398 *obj_p
= otmp
= 0; /* object is now gone */
2399 /* breakage makes its own noises */
2400 else if (obj_type
== BOULDER
|| obj_type
== HEAVY_IRON_BALL
)
2402 else if (otmp
->oclass
== COIN_CLASS
||
2403 objects
[obj_type
].oc_material
== MT_GOLD
||
2404 objects
[obj_type
].oc_material
== MT_SILVER
)
2413 /* Find a target for a ranged attack. From dnethack (thanks Chris_ANG). Here in SLEX, it's meant to be specifically for
2414 * hostile monsters attacking your pets at range. */
2416 mfind_target(mtmp
, force_linedup
)
2418 boolean force_linedup
;
2420 if (DEADMONSTER(mtmp
)) return (struct monst
*)0;
2422 int dir
, origdir
= -1;
2423 int x
, y
, dx
, dy
, tbx
, tby
;
2427 struct monst
*mat
, *mret
= (struct monst
*)0, *oldmret
= (struct monst
*)0;
2428 struct monst
*mtmp2
;
2430 if (mtmp
->mpeaceful
|| mtmp
->mtame
) return 0;
2432 /* things that shouldn't attack pets go here --Amy */
2433 if (mtmp
->data
== &mons
[PM_MOLDOUX__THE_DEFENCELESS_MOLD
]) return 0;
2434 if (mtmp
->isshk
|| mtmp
->isgd
|| mtmp
->ispriest
|| mtmp
->data
->mlet
== S_TROVE
) return 0;
2436 struct obj
*mrwep
= select_rwep(mtmp
, TRUE
); /* may use polearm even when far from the player --Amy */
2438 for (mtmp2
= fmon
; mtmp2
; mtmp2
= mtmp2
->nmon
) {
2439 if(mtmp
== mtmp2
) continue;
2440 if (mtmp2
&& u
.usteed
&& mtmp2
== u
.usteed
) continue; /* steeds are fragile enough already... --Amy */
2441 if (mtmp2
->mtame
&& (mlined_up(mtmp
, mtmp2
, FALSE
) || attacktype(mtmp
->data
, AT_GAZE
) || attacktype(mtmp
->data
, AT_WEAP
)) &&
2442 ((attacktype(mtmp
->data
, AT_GAZE
) && !mtmp
->mcan
)
2443 || (attacktype(mtmp
->data
, AT_MAGC
) && !mtmp
->mcan
&& distmin(mtmp2
->mx
,mtmp2
->my
,mtmp
->mx
,mtmp
->my
) < BOLT_LIM
)
2444 || (attacktype(mtmp
->data
, AT_WEAP
) && mrwep
&& distmin(mtmp2
->mx
,mtmp2
->my
,mtmp
->mx
,mtmp
->my
) < BOLT_LIM
)
2445 || (attacktype(mtmp
->data
, AT_BREA
) && !mtmp
->mcan
&& distmin(mtmp2
->mx
,mtmp2
->my
,mtmp
->mx
,mtmp
->my
) < BOLT_LIM
)
2446 || (attacktype(mtmp
->data
, AT_BEAM
) && distmin(mtmp2
->mx
,mtmp2
->my
,mtmp
->mx
,mtmp
->my
) < BOLT_LIM
)
2447 || (attacktype(mtmp
->data
, AT_SPIT
) && !mtmp
->mcan
&& distmin(mtmp2
->mx
,mtmp2
->my
,mtmp
->mx
,mtmp
->my
) < BOLT_LIM
)) )
2451 if (PethateEffect
|| u
.uprops
[PETHATE_EFFECT
].extrinsic
|| have_pethatestone()) mret
= mtmp2
;
2453 if ((!rn2((mtmp2
->m_lev
> 40) ? 3 : (mtmp2
->m_lev
> 30) ? 5 : (mtmp2
->m_lev
> 20) ? 10 : 20) && !(u
.usteed
&& mtmp2
== u
.usteed
&& !rn2(10)) && (!rn2(5) || mtmp2
->mcanmove
) && (!rn2(5) || (mtmp2
->mhpmax
> 5 && mtmp2
->mhp
> (mtmp2
->mhpmax
/ 5) )) && (mtmp2
->m_lev
> rn2(6)) && (u
.petattackenemies
>= 0) && ((mtmp
->m_lev
- mtmp2
->m_lev
) < (2 + rn2(5)) ) ) || attacktype(mtmp2
->data
, AT_EXPL
) || mtmp
->mfrenzied
) mret
= mtmp2
;
2458 if (mret
!= (struct monst
*)0) {
2460 if(!mlined_up(mtmp
, mret
, FALSE
) && !attacktype(mtmp
->data
, AT_GAZE
) && !attacktype(mtmp
->data
, AT_WEAP
)) {
2465 /* Nothing lined up? */
2467 return (struct monst
*)0;
2471 mlined_up(mtmp
, mdef
, breath
) /* From dnethack: is mtmp in position to use ranged attack? */
2472 register struct monst
*mtmp
;
2473 register struct monst
*mdef
;
2474 register boolean breath
;
2478 if (DEADMONSTER(mtmp
)) return 0;
2479 if (DEADMONSTER(mdef
)) return 0;
2481 boolean lined_up
= linedup(mdef
->mx
,mdef
->my
,mtmp
->mx
,mtmp
->my
, FALSE
);
2483 int dx
= sgn(mdef
->mx
- mtmp
->mx
),
2484 dy
= sgn(mdef
->my
- mtmp
->my
);
2486 int x
= mtmp
->mx
, y
= mtmp
->my
;
2488 int i
= 10; /* arbitrary */
2490 /* No special checks if confused - can't tell friend from foe */
2491 if (!lined_up
|| mtmp
->mconf
|| !mtmp
->mtame
) return lined_up
;
2493 /* Check for friendlies in the line of fire. */
2494 for (; !breath
|| i
> 0; --i
)
2498 if (!isok(x
, y
)) break;
2500 if (x
== u
.ux
&& y
== u
.uy
)
2506 if (!breath
&& mat
== mdef
) return lined_up
;
2508 /* Don't hit friendlies - since this is used by hostile monsters, other hostile monsters == friendly */
2509 if (!mat
->mtame
&& !mat
->mpeaceful
) return FALSE
;