Blindfold removal fix
[slashemextended.git] / src / dothrow.c
blob3f76d1fd824cff6d872478ec38a2dc2b9ad4771d
1 /* SCCS Id: @(#)dothrow.c 3.4 2003/12/04 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* Contains code for 't' (throw) */
7 #include "hack.h"
8 #include "edog.h"
10 STATIC_DCL int throw_obj(struct obj *, int, int);
11 STATIC_DCL void autoquiver(void);
12 STATIC_DCL int gem_accept(struct monst *, struct obj *);
13 STATIC_DCL void tmiss(struct obj *, struct monst *);
14 STATIC_DCL int throw_gold(struct obj *);
15 STATIC_DCL void check_shop_obj(struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P);
16 STATIC_DCL void breakobj(struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P,BOOLEAN_P);
17 STATIC_DCL void breakmsg(struct obj *,BOOLEAN_P);
18 STATIC_DCL boolean toss_up(struct obj *, BOOLEAN_P);
19 STATIC_DCL boolean throwing_weapon(struct obj *);
20 STATIC_DCL void sho_obj_return_to_u(struct obj *obj);
21 STATIC_DCL boolean mhurtle_step(void *,int,int);
22 static void autoquiver(void); /* KMH -- automatically fill quiver */
25 static NEARDATA const char toss_objs[] =
26 { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, WEAPON_CLASS, 0 };
27 /* different default choices when wielding a sling (gold must be included) */
28 static NEARDATA const char bullets[] =
29 { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, GEM_CLASS, 0 };
31 struct obj *thrownobj = 0; /* tracks an object until it lands */
33 extern boolean notonhead; /* for long worms */
35 #define THROW_UWEP 1
36 #define THROW_USWAPWEP 2
38 /* Split this object off from its slot */
40 struct obj *
41 splitoneoff(pobj)
42 struct obj **pobj;
44 struct obj *obj = *pobj;
45 struct obj *otmp = (struct obj *)0;
46 if (obj == uquiver) {
47 if (obj->quan > 1L)
48 setuqwep(otmp = splitobj(obj, 1L));
49 else
50 setuqwep((struct obj *)0);
51 } else if (obj == uswapwep) {
52 if (obj->quan > 1L)
53 setuswapwep(otmp = splitobj(obj, 1L), FALSE);
54 else
55 setuswapwep((struct obj *)0, FALSE);
56 } else if (obj == uwep) {
57 if (obj->quan > 1L)
58 setworn(otmp = splitobj(obj, 1L), W_WEP);
59 /* not setuwep; do not change unweapon */
60 else {
61 setuwep((struct obj *)0, FALSE, TRUE);
62 if (uwep) return (struct obj *)0; /* unwielded, died, rewielded */
64 } else if (obj->quan > 1L)
65 otmp = splitobj(obj, 1L);
66 *pobj = otmp;
67 return obj;
70 /* Throw the selected object, asking for direction */
71 STATIC_OVL int
72 throw_obj(obj, shotlimit, thrown)
73 register struct obj *obj;
74 int shotlimit;
75 int thrown;
77 struct obj *otmp;
78 struct obj *launcher;
79 int multishot = (Race_if(PM_CLOCKWORK_AUTOMATON) && !Upolyd) ? rnd(3) : Race_if(PM_MANSTER) ? rnd(2) : Race_if(PM_MONGUNG) ? rnd(2) : Race_if(PM_HAXOR) ? rno(2) : 1;
80 boolean fullmultishot = FALSE; /* depends on missile weapons skill --Amy */
81 boolean reallyfullmultishot = FALSE;
82 int angeramount; /* for blade anger technique */
84 if (RngeMultishot) multishot++;
85 if (Race_if(PM_SPARD)) multishot += rnd(4);
86 if (uarmf && uarmf->oartifact == ART_ZERO_SUIT) multishot += 1;
87 if (uarmh && uarmh->oartifact == ART_VIRUS_ATTACK) multishot += 1;
88 if (uarmh && uarmh->oartifact == ART_SURFACE_TO_AIR_SITE) multishot += 1;
89 if (uwep && uwep->oartifact == ART_LASER_PALADIN) multishot += 1;
90 if (uarmg && uarmg->oartifact == ART_WHINY_MARY) multishot += rnd(5);
91 if (uwep && uwep->oartifact == ART_GUNS_IN_MY_HEAD) multishot += 1;
93 if (Double_attack || (uwep && uwep->oartifact == ART_MELISSA_S_PEACEBRINGER && !u.twoweap) || (uwep && uwep->oartifact == ART_CRUSHING_IMPACT && !u.twoweap) ) multishot += rn2(multishot + 1);
94 if (Quad_attack) multishot += rn2(multishot * 3 + 1);
96 if ((long)multishot > obj->quan && (long)multishot > 1) multishot = (int)obj->quan;
98 if ((shotlimit > 0) && (multishot > shotlimit)) multishot = shotlimit;
100 schar skill;
101 long wep_mask;
102 boolean twoweap;
104 multi = 0; /* reset; it's been used up */
106 if (thrown == 1 && uwep && ammo_and_launcher(obj, uwep))
107 launcher = uwep;
108 else if (thrown == 2 && uswapwep && ammo_and_launcher(obj, uswapwep))
109 launcher = uswapwep;
110 else if (thrown == 666) { /* inbuilt pistol boots */
111 if (uarmf && itemhasappearance(uarmf, APP_PISTOL_BOOTS) ) launcher = uarmf;
113 else launcher = (struct obj *)0;
115 /* ask "in what direction?" */
116 #ifndef GOLDOBJ
117 if (!getdir((char *)0)) {
118 if (obj->oclass == COIN_CLASS) {
119 u.ugold += obj->quan;
120 flags.botl = 1;
121 dealloc_obj(obj);
123 return(0);
126 if(obj->oclass == COIN_CLASS) return(throw_gold(obj));
127 #else
128 if (!getdir((char *)0)) {
129 /* obj might need to be merged back into the singular gold object */
130 freeinv(obj);
131 addinv(obj);
132 return(0);
136 Throwing money is usually for getting rid of it when
137 a leprechaun approaches, or for bribing an oncoming
138 angry monster. So throw the whole object.
140 If the money is in quiver, throw one coin at a time,
141 possibly using a sling.
143 if(obj->oclass == COIN_CLASS && obj != uquiver) return(throw_gold(obj));
144 #endif
146 if(!canletgo(obj,"throw"))
147 return(0);
149 if(obj == uwep && welded(obj)) {
150 weldmsg(obj);
151 return(1);
154 if (obj->oartifact == ART_MJOLLNIR && obj != uwep) {
155 pline("%s must be wielded before it can be thrown.",
156 The(xname(obj)));
157 return(0);
159 if (obj->oartifact == ART_OTHER_MJOLLNIR && obj != uwep) {
160 pline("%s must be wielded before it can be thrown.",
161 The(xname(obj)));
162 return(0);
164 /* Since it's almost impossible to get 25 strength in slex, valkyries can simply throw Mjollnir at all times --Amy */
165 if ((obj->oartifact == ART_MJOLLNIR && !Role_if(PM_VALKYRIE) && !Role_if(PM_VANILLA_VALK) && ACURR(A_STR) < STR19(25))
166 || (obj->otyp == BOULDER && !throws_rocks(youmonst.data) && !(uarmg && uarmg->oartifact == ART_MOUNTAIN_FISTS) )) {
167 pline("It's too heavy.");
168 return(1);
170 if ((obj->oartifact == ART_OTHER_MJOLLNIR && !Role_if(PM_VALKYRIE) && !Role_if(PM_VANILLA_VALK) && ACURR(A_STR) < STR19(25))
171 || (obj->otyp == BOULDER && !throws_rocks(youmonst.data) && !(uarmg && uarmg->oartifact == ART_MOUNTAIN_FISTS) )) {
172 pline("It's too heavy.");
173 return(1);
175 if(!u.dx && !u.dy && !u.dz) {
176 You("cannot throw an object at yourself.");
177 return(0);
179 u_wipe_engr(2);
180 if ( (!uarmg || FingerlessGloves) && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) && (obj->otyp == CORPSE &&
181 touch_petrifies(&mons[obj->corpsenm]))) {
182 You("throw the %s corpse with your bare %s.",
183 mons[obj->corpsenm].mname, body_part(HAND));
184 sprintf(killer_buf, "throwing a petrifying corpse");
185 instapetrify(killer_buf);
187 if ( (!uarmg || FingerlessGloves) && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) && (obj->otyp == PETRIFYIUM_BAR)) {
188 You("throw the bar with your bare %s.", body_part(HAND));
189 sprintf(killer_buf, "a thrown petrifyium bar");
190 instapetrify(killer_buf);
192 if ( (!uarmg || FingerlessGloves) && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) && (obj->otyp == PETRIFYIUM_BRA)) {
193 You("throw the bra with your bare %s.", body_part(HAND));
194 sprintf(killer_buf, "a thrown petrifyium bra");
195 instapetrify(killer_buf);
197 if ( (!uarmg || FingerlessGloves) && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) && (obj->otyp == EGG &&
198 touch_petrifies(&mons[obj->corpsenm]) && obj->corpsenm != PM_PLAYERMON)) {
199 You("throw the %s egg with your bare %s.",
200 mons[obj->corpsenm].mname, body_part(HAND));
201 sprintf(killer_buf, "throwing a petrifying egg");
202 instapetrify(killer_buf);
204 if (welded(obj)) {
205 weldmsg(obj);
206 return 1;
209 /* Multishot calculations
211 skill = objects[obj->otyp].oc_skill;
212 if (( (ammo_and_launcher(obj, uwep) && !(uwep && uwep->otyp == LASERXBOW && !uwep->lamplit) && !(uwep && uwep->otyp == KLIUSLING && !uwep->lamplit) ) || skill == P_DAGGER || skill == P_KNIFE || skill == P_BOOMERANG || skill == -P_BOOMERANG || skill == P_VENOM || skill == -P_VENOM ||
213 skill == -P_DART || skill == -P_SHURIKEN || skill == P_SPEAR || skill == P_JAVELIN) &&
214 !( (Confusion && !Conf_resist) || (Stunned && !Stun_resist) )) {
215 /* Bonus if the player is proficient in this weapon... */
217 if (!(PlayerCannotUseSkills)) {
219 switch (P_SKILL(weapon_type(obj))) {
220 default: break; /* No bonus */
221 case P_SKILLED: multishot++; break;
222 case P_EXPERT: multishot += 2; break;
223 case P_MASTER: multishot += 3; break; /* this might be implemented --Amy */
224 case P_GRAND_MASTER: multishot += 4; break;
225 case P_SUPREME_MASTER: multishot += 5; break;
230 /* ...or is using a good weapon... */
231 /* Elven Craftsmanship makes for light, quick bows */
232 if (obj->otyp == ELVEN_ARROW && !obj->cursed && !rn2(3)) multishot++;
233 if (launcher && launcher->otyp == ELVEN_BOW &&
234 !launcher->cursed && !rn2(3))
235 multishot++;
237 if (launcher && launcher->oartifact == ART_MULTISHOTTEMSO && launcher->lamplit && !(PlayerCannotUseSkills)) {
238 switch (P_SKILL(P_DJEM_SO)) {
239 default: break; /* No bonus */
240 case P_BASIC: multishot++; break;
241 case P_SKILLED: multishot += 2; break;
242 case P_EXPERT: multishot += 3; break;
243 case P_MASTER: multishot += 4; break;
244 case P_GRAND_MASTER: multishot += 5; break;
245 case P_SUPREME_MASTER: multishot += 6; break;
249 if (launcher && launcher->oartifact == ART_CANNONDANCER && !(PlayerCannotUseSkills)) {
250 switch (P_SKILL(P_FIREARM)) {
251 default: break; /* No bonus */
252 case P_BASIC: multishot += 1; break;
253 case P_SKILLED: multishot += rnd(2); break;
254 case P_EXPERT: multishot += rnd(3); break;
255 case P_MASTER: multishot += rnd(4); break;
256 case P_GRAND_MASTER: multishot += rnd(5); break;
257 case P_SUPREME_MASTER: multishot += rnd(6); break;
261 if (launcher && launcher->oartifact == ART_EXPERIMENTAL_MIRV) {
262 multishot += 7;
263 fullmultishot = TRUE;
264 reallyfullmultishot = TRUE;
267 if (launcher && launcher->otyp == WILDHILD_BOW && obj->otyp == ODOR_SHOT) multishot++;
268 if (launcher && launcher->otyp == COMPOST_BOW && obj->otyp == FORBIDDEN_ARROW) multishot++;
270 if (launcher && launcher->oartifact == ART_TEAM_FORTRESS_GL && obj->otyp == FRAG_GRENADE) multishot += 5;
271 if (launcher && launcher->oartifact == ART_TEAM_FORTRESS_GL && obj->otyp == GAS_GRENADE) multishot += 5;
273 if (launcher && launcher->oartifact == ART_MEASURE_SKILLING) multishot++;
274 if (launcher && launcher->oartifact == ART_SKILLED_THROUGHLOAD) multishot++;
275 if (launcher && launcher->oartifact == ART_LINCOLN_S_REPEATER) multishot++;
276 if (launcher && launcher->oartifact == ART_AR_ARMALYTE) multishot++;
277 if (launcher && launcher->oartifact == ART_LOUD_SHITTER) multishot += rn1(2, 2);
278 if (launcher && launcher->oartifact == ART_CLACKINDRA) multishot += 3;
279 if (launcher && launcher->oartifact == ART_UZ_I) multishot += rnd(3);
280 if (launcher && launcher->oartifact == ART_HEAVY_CROSSBOW_OF_ETERNITY) multishot += 2;
281 if (launcher && obj && obj->oartifact == ART_FUCK_THE_SERVER) multishot += 2;
283 if (uarmf && uarmf->oartifact == ART_FRENCHYPOSS && uarmf->blessed && launcher && objects[launcher->otyp].oc_skill == P_FIREARM) multishot++;
285 if (uarms && uarms->oartifact == ART_MISSING_LETTER_D && launcher && objects[launcher->otyp].oc_skill == P_SLING) multishot += 2;
287 if (launcher && launcher->oartifact == ART_NOCK_GUN && (launcher->invoketimer <= monstermoves) ) {
288 int artitimeout = rnz(2000);
289 if (!rn2(5)) artitimeout = rnz(20000); /* squeaking does not help here, as it's not an actual invoke --Amy */
290 multishot += 6;
291 launcher->invoketimer = (monstermoves + artitimeout);
294 if (obj && obj->oartifact == ART_WIWIU_) multishot += rnd(3);
295 if (obj && obj->oartifact == ART_LEAD_SYRINGE) multishot += 2;
296 if (obj && obj->otyp == RAPID_DART) multishot += 2;
297 if (obj && obj->otyp == NINJA_STAR) multishot += 3;
298 if (obj && obj->otyp == FLAMETHROWER) multishot += 4;
299 if (obj && obj->oartifact == ART_POEPOEPOEPOEOEU_) multishot += 4;
300 if (obj && obj->oartifact == ART_MRLS) multishot += 1;
301 if (obj && obj->oartifact == ART_FRIGHT_PRAWN) multishot += 1;
302 if (obj && obj->oartifact == ART_WASHINGTON_S_CAPPER) multishot += 1;
303 if (uarmh && uarmh->oartifact == ART_GIVE_THE_BONUS_STUFF) multishot += 1;
305 if (obj && obj->oartifact == ART_CAPAUER && !PlayerCannotUseSkills) {
306 if (P_MAX_SKILL(P_SHURIKEN) == P_SUPREME_MASTER) {
307 switch (P_SKILL(P_SHURIKEN)) {
308 case P_GRAND_MASTER: multishot += 1; break;
309 case P_MASTER: multishot += 2; break;
310 case P_EXPERT: multishot += 3; break;
312 } else if (P_MAX_SKILL(P_SHURIKEN) == P_GRAND_MASTER) {
313 switch (P_SKILL(P_SHURIKEN)) {
314 case P_MASTER: multishot += 1; break;
315 case P_EXPERT: multishot += 2; break;
317 } else if (P_MAX_SKILL(P_SHURIKEN) == P_MASTER) {
318 switch (P_SKILL(P_SHURIKEN)) {
319 case P_EXPERT: multishot += 1; break;
325 if (Race_if(PM_AZTPOK) && launcher && objects[launcher->otyp].oc_skill == P_FIREARM) multishot += rnd(2);
326 if (Race_if(PM_TURMENE) && launcher && objects[launcher->otyp].oc_skill == P_FIREARM) multishot += rnd(3);
328 if (uamul && uamul->oartifact == ART_PURPLE_ARBALEST && launcher && objects[launcher->otyp].oc_skill == P_CROSSBOW) multishot++;
329 if (uamul && uamul->oartifact == ART_PURPLE_ARBALEST) multishot++;
331 if (uimplant && uimplant->oartifact == ART_BIUUU_ && launcher && objects[launcher->otyp].oc_skill == P_CROSSBOW) multishot++;
332 if (powerfulimplants() && uimplant && uimplant->oartifact == ART_BIUUU_ && launcher && objects[launcher->otyp].oc_skill == P_BOW) multishot++;
333 if (uarmh && uarmh->oartifact == ART_HELM_OF_THE_ARCANE_ARCHER && launcher && objects[launcher->otyp].oc_skill == P_BOW) multishot++;
335 if (launcher && objects[launcher->otyp].oc_skill == P_FIREARM && !(PlayerCannotUseSkills) && P_SKILL(P_SQUEAKING) >= P_MASTER && P_SKILL(P_GUN_CONTROL) >= P_MASTER && Upolyd) {
336 multishot++;
337 if (P_SKILL(P_SQUEAKING) >= P_GRAND_MASTER && P_SKILL(P_GUN_CONTROL) >= P_GRAND_MASTER) multishot++;
338 if (P_SKILL(P_SQUEAKING) >= P_SUPREME_MASTER && P_SKILL(P_GUN_CONTROL) >= P_SUPREME_MASTER) multishot++;
341 if (launcher && launcher->otyp == CATAPULT && (!obj || obj->otyp != ROCK)) multishot += rnd(5);
342 if (launcher && launcher->otyp == CATAPULT && obj && obj->otyp == ROCK) multishot += rno(5);
343 if (launcher && launcher->oartifact == ART_DRIVE_BY && u.usteed) {
344 multishot += 2;
345 if (u.ugallop) multishot++;
347 if (launcher && launcher->oartifact == ART_BROWNING) multishot += rnd(5);
349 if ((uwep && uwep->oartifact == ART_SPEERTHROW) && (skill == P_SPEAR) ) {
350 multishot += 2;
351 if (Race_if(PM_AZTPOK) || Race_if(PM_MAYMES)) multishot++;
354 if (uwep && uwep->oartifact == ART_POWCHARGE) multishot++;
356 if (launcher && (launcher->otyp == RIFLE || launcher->otyp == SNIPER_RIFLE || launcher->otyp == HUNTING_RIFLE || launcher->otyp == PROCESS_CARD) && uarmc && itemhasappearance(uarmc, APP_RIFLING_POWER_CLOAK) ) multishot += rnd(2);
358 if (launcher && launcher->otyp == HYDRA_BOW) multishot += 2;
359 if (launcher && launcher->otyp == DEMON_CROSSBOW && launcher->altmode == WP_MODE_AUTO) multishot += 4;
360 if (launcher && launcher->otyp == WILDHILD_BOW) multishot += 2;
362 if (launcher && launcher->oartifact == ART_STREAMSHOOTER) multishot += 1;
364 if (launcher && launcher->oartifact == ART_SNIPEGIANT) multishot += 1;
365 if (launcher && launcher->oartifact == ART_DOLE__EM_ALL_OUT) multishot += 2;
367 if (launcher && launcher->oartifact == ART_MAXIMUM_LAUNCH_POWER) multishot += rnd(2);
369 if (launcher && launcher->oartifact == ART_WINSETT_S_BIG_DADDY) multishot += rnd(2);
371 if (launcher && launcher->oartifact == ART_TUNA_CANNON) multishot += 1;
373 if (launcher && launcher->oartifact == ART_FOEOEOEOEOEOEOE) multishot += rnd(3);
375 if (!PlayerCannotUseSkills && skill == P_SLING && ((uarm && uarm->oartifact == ART_LU_NONNAME) || Role_if(PM_HEDDERJEDI)) ) {
376 if (u.kliuskill >= 20) multishot++;
377 if (u.kliuskill >= 160) multishot++;
378 if (u.kliuskill >= 540) multishot++;
379 if (u.kliuskill >= 1280) multishot++;
380 if (u.kliuskill >= 2500) multishot++;
381 if (u.kliuskill >= 4320) multishot++;
384 if (Role_if(PM_TOSSER) && obj && objects[obj->otyp].oc_skill == P_JAVELIN) multishot += 1;
385 if (Role_if(PM_MILL_SWALLOWER) && obj && (objects[obj->otyp].oc_skill == P_CROSSBOW || objects[obj->otyp].oc_skill == -P_CROSSBOW)) multishot += 1;
387 if (uarmg && uarmg->oartifact == ART_PEEPING_GROOVE && launcher && (launcher->otyp == SHOTGUN || launcher->otyp == PAPER_SHOTGUN || launcher->otyp == SAWED_OFF_SHOTGUN || launcher->otyp == AUTO_SHOTGUN)) multishot += rnd(7);
389 if (uarmc && uarmc->oartifact == ART_PALEOLITHIC_ELBOW_CONTRACT && launcher && objects[launcher->otyp].oc_skill == P_BOW) multishot += 5;
391 if (uamul && uamul->oartifact == ART_WILDWEST_LAW && launcher && objects[launcher->otyp].oc_skill == P_FIREARM) multishot += 1;
393 /* 1/3 of object enchantment */
394 if (launcher && launcher->spe > 1)
395 multishot += (long) rounddiv(launcher->spe,3);
397 /* ...or is using a special weapon for their role... */
398 switch (Role_switch) {
399 case PM_RANGER:
400 multishot++;
401 break;
402 case PM_ROGUE:
403 if (skill == P_DAGGER) multishot++;
404 break;
405 case PM_RINGSEEKER:
406 if (skill == P_SLING) multishot++;
407 break;
408 case PM_ROCKER:
409 if (skill == P_SLING) {multishot++;
411 if (!(PlayerCannotUseSkills)) {
413 if (P_SKILL(weapon_type(obj)) >= P_SKILLED) multishot++;
414 if (P_SKILL(weapon_type(obj)) >= P_EXPERT) multishot++;
415 if (P_SKILL(weapon_type(obj)) >= P_MASTER) multishot++;
416 if (P_SKILL(weapon_type(obj)) >= P_GRAND_MASTER) multishot++;
417 if (P_SKILL(weapon_type(obj)) >= P_SUPREME_MASTER) multishot++;
421 break;
422 case PM_ELPH: /* elf role --Amy */
423 multishot++;
424 if (obj->otyp == ELVEN_ARROW && launcher &&
425 launcher->otyp == ELVEN_BOW) multishot++;
426 break;
427 case PM_TWELPH: /* dark elf role --Amy */
428 multishot++;
429 if (obj->otyp == DARK_ELVEN_ARROW && launcher &&
430 launcher->otyp == DARK_ELVEN_BOW) multishot++;
431 break;
432 case PM_SAMURAI:
433 if (obj->otyp == YA && launcher && launcher->otyp == YUMI) multishot++;
434 if (obj->otyp == FAR_EAST_ARROW && launcher && launcher->otyp == YUMI) multishot++;
435 break;
436 default:
437 break; /* No bonus */
439 /* ...or using their race's special bow */
440 switch (Race_switch) {
441 case PM_ELF:
442 case PM_PLAYER_MYRKALFR:
443 if (obj->otyp == ELVEN_ARROW && launcher &&
444 launcher->otyp == ELVEN_BOW) multishot++;
445 break;
446 case PM_PLAYABLE_NEANDERTHAL:
447 if (skill == P_SLING) multishot++;
448 break;
449 case PM_INKA:
450 if (launcher && launcher->otyp == INKA_SLING && ammo_and_launcher(obj, launcher) ) multishot += 2;
451 break;
452 case PM_ORC:
453 if (obj->otyp == ORCISH_ARROW && uwep &&
454 uwep->otyp == ORCISH_BOW) multishot++;
455 break;
456 case PM_HOBBIT: /* slings are retarded weapons according to Jacob Black, so a little bonus is in order... --Amy */
457 if (skill == P_SLING) multishot++;
458 break;
459 default:
460 break; /* No bonus */
463 if (!(PlayerCannotUseSkills)) {
465 switch (P_SKILL(P_MISSILE_WEAPONS)) {
466 /* These fallthroughs are intentional --Amy */
467 case P_SUPREME_MASTER:
468 if ((skill == P_DAGGER || skill == P_KNIFE || skill == P_SPEAR ) && !rn2(5)) multishot++;
469 if (skill == P_JAVELIN && !rn2(3)) multishot++;
470 if ((skill == P_DART || skill == P_SHURIKEN || skill == P_BOOMERANG || skill == -P_DART || skill == -P_SHURIKEN || skill == -P_BOOMERANG || skill == P_VENOM || skill == -P_VENOM ) && !rn2(4)) multishot++;
471 case P_GRAND_MASTER:
472 if ((skill == P_DAGGER || skill == P_KNIFE || skill == P_SPEAR ) && !rn2(5)) multishot++;
473 if (skill == P_JAVELIN && !rn2(3)) multishot++;
474 if ((skill == P_DART || skill == P_SHURIKEN || skill == P_BOOMERANG || skill == -P_DART || skill == -P_SHURIKEN || skill == -P_BOOMERANG || skill == P_VENOM || skill == -P_VENOM ) && !rn2(4)) multishot++;
475 case P_MASTER:
476 if ((skill == P_DAGGER || skill == P_KNIFE || skill == P_SPEAR ) && !rn2(5)) multishot++;
477 if (skill == P_JAVELIN && !rn2(3)) multishot++;
478 if ((skill == P_DART || skill == P_SHURIKEN || skill == P_BOOMERANG || skill == -P_DART || skill == -P_SHURIKEN || skill == -P_BOOMERANG || skill == P_VENOM || skill == -P_VENOM ) && !rn2(4)) multishot++;
479 case P_EXPERT:
480 if ((skill == P_DAGGER || skill == P_KNIFE || skill == P_SPEAR ) && !rn2(5)) multishot++;
481 if (skill == P_JAVELIN && !rn2(3)) multishot++;
482 if ((skill == P_DART || skill == P_SHURIKEN || skill == P_BOOMERANG || skill == -P_DART || skill == -P_SHURIKEN || skill == -P_BOOMERANG || skill == P_VENOM || skill == -P_VENOM ) && !rn2(4)) multishot++;
483 case P_SKILLED:
484 if ((skill == P_DAGGER || skill == P_KNIFE || skill == P_SPEAR ) && !rn2(5)) multishot++;
485 if (skill == P_JAVELIN && !rn2(3)) multishot++;
486 if ((skill == P_DART || skill == P_SHURIKEN || skill == P_BOOMERANG || skill == -P_DART || skill == -P_SHURIKEN || skill == -P_BOOMERANG || skill == P_VENOM || skill == -P_VENOM ) && !rn2(4)) multishot++;
487 case P_BASIC:
488 if ((skill == P_DAGGER || skill == P_KNIFE || skill == P_SPEAR ) && !rn2(5)) multishot++;
489 if (skill == P_JAVELIN && !rn2(3)) multishot++;
490 if ((skill == P_DART || skill == P_SHURIKEN || skill == P_BOOMERANG || skill == -P_DART || skill == -P_SHURIKEN || skill == -P_BOOMERANG || skill == P_VENOM || skill == -P_VENOM ) && !rn2(4)) multishot++;
491 default: break;
495 if ((long)multishot > obj->quan) multishot = (int)obj->quan;
497 if (multishot > 0)
498 multishot = rnd(multishot); /* Some randomness */
499 else multishot = 1;
501 /* Tech: Flurry */
502 if ( (objects[obj->otyp].oc_skill == -P_BOW || objects[obj->otyp].oc_skill == -P_CROSSBOW || objects[obj->otyp].oc_skill == -P_SLING) && tech_inuse(T_FLURRY)) {
503 multishot += 1; multishot += rnd(multishot); /* Let'em rip! Extra bonus added by Amy. */
505 /* more than usual == volley */
506 if (((shotlimit <= 0) || (shotlimit >= multishot)) &&
507 (obj->quan >= multishot))
508 You("let fly a volley of %s!", xname(obj));
511 if ( (objects[obj->otyp].oc_skill == -P_DAGGER || objects[obj->otyp].oc_skill == P_DAGGER || objects[obj->otyp].oc_skill == -P_DART || objects[obj->otyp].oc_skill == P_DART || objects[obj->otyp].oc_skill == -P_SHURIKEN || objects[obj->otyp].oc_skill == P_SHURIKEN || objects[obj->otyp].oc_skill == -P_BOOMERANG || objects[obj->otyp].oc_skill == P_BOOMERANG || objects[obj->otyp].oc_skill == -P_VENOM || objects[obj->otyp].oc_skill == P_VENOM || objects[obj->otyp].oc_skill == -P_KNIFE || objects[obj->otyp].oc_skill == P_KNIFE || objects[obj->otyp].oc_skill == -P_SPEAR || objects[obj->otyp].oc_skill == P_SPEAR || objects[obj->otyp].oc_skill == -P_JAVELIN || objects[obj->otyp].oc_skill == P_JAVELIN) && uarmf && uarmf->oartifact == ART_H__S_GANGSTER_KICKS) {
512 multishot += 1;
515 if ( (objects[obj->otyp].oc_skill == -P_DAGGER || objects[obj->otyp].oc_skill == P_DAGGER || objects[obj->otyp].oc_skill == -P_DART || objects[obj->otyp].oc_skill == P_DART || objects[obj->otyp].oc_skill == -P_SHURIKEN || objects[obj->otyp].oc_skill == P_SHURIKEN || objects[obj->otyp].oc_skill == -P_BOOMERANG || objects[obj->otyp].oc_skill == P_BOOMERANG || objects[obj->otyp].oc_skill == -P_VENOM || objects[obj->otyp].oc_skill == P_VENOM || objects[obj->otyp].oc_skill == -P_KNIFE || objects[obj->otyp].oc_skill == P_KNIFE || objects[obj->otyp].oc_skill == -P_SPEAR || objects[obj->otyp].oc_skill == P_SPEAR || objects[obj->otyp].oc_skill == -P_JAVELIN || objects[obj->otyp].oc_skill == P_JAVELIN) && tech_inuse(T_DOUBLE_THROWNAGE)) {
516 multishot += 1; multishot += rnd(multishot); /* Let'em rip! Extra bonus added by Amy. */
518 /* more than usual == volley */
519 if (((shotlimit <= 0) || (shotlimit >= multishot)) &&
520 (obj->quan >= multishot))
521 You("throw a hail of %s!", xname(obj));
524 if (launcher && launcher->oartifact == ART_ARROW_RAIN && (launcher->invoketimer <= monstermoves) ) {
525 int artitimeout = rnz(2000);
526 if (!rn2(5)) artitimeout = rnz(20000); /* squeaking does not help here, as it's not an actual invoke --Amy */
527 multishot += 8;
528 fullmultishot = TRUE;
529 reallyfullmultishot = TRUE;
530 launcher->invoketimer = (monstermoves + artitimeout);
533 if (launcher && launcher->otyp == PISTOL_PAIR) multishot *= 2;
535 /* Shotlimit controls your rate of fire */
536 if ((shotlimit > 0) && (multishot > shotlimit)) multishot = shotlimit;
538 if (uarm && uarm->oartifact == ART_POWASPEL) {
539 multishot -= rnd(2);
540 if (multishot < 1) multishot = 1;
543 if (launcher && launcher->oartifact == ART_DESERT_EAGLE) {
544 multishot--;
545 if (multishot < 1) multishot = 1;
547 if (launcher && launcher->oartifact == ART_LEONE_M__GUAGE_SUPER) {
548 multishot -= 2;
549 if (multishot < 1) multishot = 1;
551 if (launcher && launcher->otyp == BLADE_BOW) {
552 multishot -= 2;
553 if (multishot < 1) multishot = 1;
555 if (obj && obj->otyp == HEAVY_SPEAR) {
556 multishot -= 2;
557 if (multishot < 1) multishot = 1;
559 if (obj && obj->otyp == SUPERHEAVY_SPEAR) {
560 multishot -= 3;
561 if (multishot < 1) multishot = 1;
563 if (launcher && launcher->oartifact == ART_MOSIN_NAGANT) {
564 multishot -= 3;
565 if (multishot < 1) multishot = 1;
567 if (launcher && launcher->oartifact == ART_BOW_OF_SKADI) {
568 multishot -= rnd(2);
569 if (multishot < 1) multishot = 1;
571 if (launcher && launcher->otyp == SHOVEL) {
572 multishot--;
573 if (multishot < 1) multishot = 1;
575 if (launcher && launcher->oartifact == ART_OZYZEVPDWTVP) {
576 multishot--;
577 if (multishot < 1) multishot = 1;
579 if (uarmc && uarmc->oartifact == ART_OLD_PERSON_TALK) {
580 multishot /= 2;
581 if (multishot < 1) multishot = 1;
583 if (uarms && uarms->otyp == COMPLETE_BLOCKAGE_SHIELD) {
584 multishot /= 2;
585 multishot--;
586 if (multishot < 1) multishot = 1;
589 /* Rate of fire is intrinsic to the weapon - cannot be user selected
590 * except via altmode
591 * Only for valid launchers
592 * (currently oc_rof conflicts with wsdam)
594 if (launcher && is_launcher(launcher))
596 if (objects[(launcher->otyp)].oc_rof && launcher->oartifact != ART_EXPERIMENTAL_MIRV)
597 multishot += (objects[(launcher->otyp)].oc_rof - 1);
598 if (launcher->altmode == WP_MODE_SINGLE)
599 /* weapons switchable b/w full/semi auto */
600 multishot = 1;
601 else if (launcher->altmode == WP_MODE_BURST)
602 multishot = ((multishot > 3) ? (multishot / 3) : 1);
603 /* else it is auto == no change */
605 if (objects[(launcher->otyp)].oc_rof) {
606 if (launcher->altmode == WP_MODE_AUTO && obj->quan < objects[(launcher->otyp)].oc_rof) {
607 pline("You do not have enough ammo to fire that weapon in full-auto mode!");
608 return(0);
609 } else if (launcher->altmode == WP_MODE_BURST && obj->quan < (objects[(launcher->otyp)].oc_rof / 3) ) {
610 pline("You do not have enough ammo to fire that weapon in burst-fire mode!");
611 return(0);
616 if ((long)multishot > obj->quan) multishot = (int)obj->quan;
619 if (multishot < 1) multishot = 1;
621 if (objects[obj->otyp].oc_skill == -P_CROSSBOW && launcher && launcher->otyp != DEMON_CROSSBOW && multishot > 1) multishot = rnd(multishot);
623 if (launcher && launcher->oartifact == ART_DOLORES__WINNING_STRAT) {
624 if (multishot > 2) multishot = 2;
627 if (launcher && launcher->oartifact == ART_GAT_FROM_HELL) {
628 int drainhp = multishot;
629 while (drainhp > 0) {
630 drainhp--;
631 if (u.uhpmax > 1) {
632 u.uhpmax--;
633 if (u.uhp > u.uhpmax) u.uhp = u.uhpmax;
634 } else {
635 u.youaredead = 1;
636 pline("Unfortunately you didn't have enough health to power this dangerous weapon.");
637 killer_format = KILLED_BY;
638 killer = "firing the gat from hell";
639 done(DIED);
640 u.youaredead = 0;
643 pline("%d points of health have been drained!", multishot);
644 flags.botl = TRUE;
647 if (launcher && launcher->oartifact == ART_UPGRADED_LEMURE) {
648 int verisiertnumber = multishot * 100;
649 u.uprops[VERISIERTEFFECT].intrinsic += verisiertnumber;
652 if (launcher && launcher->oartifact == ART_POST_OFFICE_COURSE) {
653 int postofficenumber = multishot;
654 adjalign(-postofficenumber);
655 u.alignlim -= postofficenumber;
658 if (launcher && (launcher->otyp == SUBMACHINE_GUN || launcher->otyp == LEAD_UNLOADER || launcher->otyp == ASSAULT_RIFLE || launcher->otyp == STORM_RIFLE || launcher->otyp == KALASHNIKOV || launcher->otyp == AUTO_SHOTGUN ) && launcher->altmode == WP_MODE_AUTO && !bulletator_allowed(1)) {
659 if (launcher->otyp == SUBMACHINE_GUN) {
660 u.bulletatorwantedlevel += 1;
661 u.bulletatortimer += 100;
662 if (P_MAX_SKILL(P_FIREARM) == P_ISRESTRICTED && P_MAX_SKILL(P_GUN_CONTROL) == P_ISRESTRICTED) u.bulletatortimer += 300;
664 if (launcher->otyp == LEAD_UNLOADER) {
665 u.bulletatorwantedlevel += 1;
666 u.bulletatortimer += 100;
667 if (P_MAX_SKILL(P_FIREARM) == P_ISRESTRICTED && P_MAX_SKILL(P_GUN_CONTROL) == P_ISRESTRICTED) u.bulletatortimer += 300;
669 if (launcher->otyp == ASSAULT_RIFLE) {
670 u.bulletatorwantedlevel += 3;
671 u.bulletatortimer += 300;
672 if (P_MAX_SKILL(P_FIREARM) == P_ISRESTRICTED && P_MAX_SKILL(P_GUN_CONTROL) == P_ISRESTRICTED) u.bulletatortimer += 1000;
674 if (launcher->otyp == STORM_RIFLE) {
675 u.bulletatorwantedlevel += 3;
676 u.bulletatortimer += 300;
677 if (P_MAX_SKILL(P_FIREARM) == P_ISRESTRICTED && P_MAX_SKILL(P_GUN_CONTROL) == P_ISRESTRICTED) u.bulletatortimer += 1000;
679 if (launcher->otyp == AUTO_SHOTGUN) {
680 u.bulletatorwantedlevel += 1;
681 u.bulletatortimer += 100;
682 if (P_MAX_SKILL(P_FIREARM) == P_ISRESTRICTED && P_MAX_SKILL(P_GUN_CONTROL) == P_ISRESTRICTED) u.bulletatortimer += 1000;
684 if (launcher->otyp == KALASHNIKOV) {
685 u.bulletatorwantedlevel += 4;
686 u.bulletatortimer += 400;
687 if (P_MAX_SKILL(P_FIREARM) == P_ISRESTRICTED && P_MAX_SKILL(P_GUN_CONTROL) == P_ISRESTRICTED) u.bulletatortimer += 2000;
689 if (!u.bulletatorgun) {
690 pline("You're not allowed to use automatic firearms. Bulletators have been alerted.");
691 u.bulletatorgun = TRUE;
694 if (launcher && (launcher->otyp == ARM_BLASTER || launcher->otyp == HEAVY_MACHINE_GUN || launcher->otyp == BFG ) && !bulletator_allowed(1)) {
695 if (launcher->otyp == ARM_BLASTER) {
696 u.bulletatorwantedlevel += 5;
697 u.bulletatortimer += 500;
698 if (P_MAX_SKILL(P_FIREARM) == P_ISRESTRICTED && P_MAX_SKILL(P_GUN_CONTROL) == P_ISRESTRICTED) u.bulletatortimer += 1500;
700 if (launcher->otyp == HEAVY_MACHINE_GUN) {
701 u.bulletatorwantedlevel += 10;
702 u.bulletatortimer += 1000;
703 if (P_MAX_SKILL(P_FIREARM) == P_ISRESTRICTED && P_MAX_SKILL(P_GUN_CONTROL) == P_ISRESTRICTED) u.bulletatortimer += 5000;
705 if (launcher->otyp == BFG) {
706 u.bulletatorwantedlevel += 10;
707 u.bulletatortimer += 1000;
708 if (P_MAX_SKILL(P_FIREARM) == P_ISRESTRICTED && P_MAX_SKILL(P_GUN_CONTROL) == P_ISRESTRICTED) u.bulletatortimer += 5000;
710 if (!u.bulletatorgun) {
711 pline("You're not allowed to use automatic firearms. Bulletators have been alerted.");
712 u.bulletatorgun = TRUE;
715 if (launcher && launcher->otyp == DEMON_CROSSBOW && launcher->altmode == WP_MODE_AUTO && !bulletator_allowed(3)) {
716 if (!rn2(2)) {
717 u.bulletatorwantedlevel += 1;
718 u.bulletatortimer += 100;
720 if (!u.bulletatorxbow) {
721 pline("You're not allowed to use the demon crossbow. Bulletators have been alerted.");
722 u.bulletatorxbow = TRUE;
725 if (launcher && launcher->otyp == HYDRA_BOW && !bulletator_allowed(2)) {
726 if (!rn2(5)) {
727 u.bulletatorwantedlevel += 1;
728 u.bulletatortimer += 100;
730 if (!u.bulletatorbow) {
731 pline("You're not allowed to use the hydra bow. Bulletators have been alerted.");
732 u.bulletatorbow = TRUE;
736 if (launcher && launcher->otyp == CATAPULT && !bulletator_allowed(4)) {
737 if (!rn2(2)) {
738 u.bulletatorwantedlevel += 1;
739 u.bulletatortimer += 100;
741 if (!u.bulletatorsling) {
742 pline("You're not allowed to use the catapult. Bulletators have been alerted.");
743 u.bulletatorsling = TRUE;
747 if (obj && obj->otyp == FLAMETHROWER && !bulletator_allowed(5)) {
748 if (!rn2(3)) {
749 u.bulletatorwantedlevel += 1;
750 u.bulletatortimer += 100;
752 if (!u.bulletatorjavelin) {
753 pline("You're not allowed to use the flamethrower. Bulletators have been alerted.");
754 u.bulletatorjavelin = TRUE;
758 if (launcher && launcher->otyp == DEMON_CROSSBOW && !rn2(100)) {
759 int attempts = 0;
760 register struct permonst *ptrZ;
762 if (Aggravate_monster) {
763 u.aggravation = 1;
764 reset_rndmonst(NON_PM);
767 newbossO:
768 do {
769 ptrZ = rndmonst();
770 attempts++;
771 if (attempts && (attempts % 10000 == 0)) u.mondiffhack++;
772 if (!rn2(2000)) reset_rndmonst(NON_PM);
774 } while ( (!ptrZ || (ptrZ && !is_demon(ptrZ))) && attempts < 50000);
776 if (ptrZ && is_demon(ptrZ)) {
777 (void) makemon(ptrZ, u.ux, u.uy, MM_ANGRY|MM_FRENZIED);
778 pline("A demon suddenly appears from nowhere!");
779 } else if (rn2(50)) {
780 attempts = 0;
781 goto newbossO;
784 u.mondiffhack = 0;
785 u.aggravation = 0;
788 if (launcher && launcher->otyp == DEMON_CROSSBOW && !rn2(100)) {
789 int tryct = 0;
790 int x, y;
791 boolean canbeinawall = FALSE;
792 if (!rn2(Passes_walls ? 5 : 25)) canbeinawall = TRUE;
794 for (tryct = 0; tryct < 2000; tryct++) {
795 x = rn1(COLNO-3,2);
796 y = rn2(ROWNO);
798 if (isok(x, y) && ((levl[x][y].typ > DBWALL) || canbeinawall) && !(t_at(x, y)) ) {
799 (void) maketrap(x, y, rndtrap(), 100, FALSE);
800 break;
806 if (launcher && launcher->otyp == DEMON_CROSSBOW && !rn2(100)) {
807 badeffect();
808 pline_The("demon crossbow malfunctioned!");
809 return(1);
812 /* nerf multishot --Amy */
814 if (!reallyfullmultishot) fullmultishot = 0;
815 if (tech_inuse(T_FLURRY) && rn2(3)) fullmultishot = 1;
816 if (tech_inuse(T_DOUBLE_THROWNAGE) && rn2(3)) fullmultishot = 1;
818 if (!(PlayerCannotUseSkills)) {
820 switch (P_SKILL(P_MISSILE_WEAPONS)) {
821 default: break;
822 case P_SKILLED: if (!rn2(8)) fullmultishot = 1; break;
823 case P_EXPERT: if (!rn2(6)) fullmultishot = 1; break;
824 case P_MASTER: if (!rn2(4)) fullmultishot = 1; break;
825 case P_GRAND_MASTER: if (!rn2(2)) fullmultishot = 1; break;
826 case P_SUPREME_MASTER: fullmultishot = 1; break;
830 if ((multishot > 3) && !fullmultishot && !(launcher && launcher->oartifact == ART_STREAMSHOOTER) && !(objects[obj->otyp].oc_skill == -P_FIREARM) && !(objects[obj->otyp].oc_skill == P_FIREARM) ) multishot = 2 + rno(multishot - 2);
832 if (multishot > 1 && isfriday && !rn2(3)) multishot = rnd(multishot);
834 if (obj && obj->otyp == JUMPING_FLAMER) multishot = 1;
835 if (launcher && launcher->oartifact == ART_TSCHUEUU) multishot = 1;
837 m_shot.s = (ammo_and_launcher(obj, uwep) && !(uwep && uwep->otyp == LASERXBOW && !uwep->lamplit) && !(uwep && uwep->otyp == KLIUSLING && !uwep->lamplit) ) ? TRUE : FALSE;
838 /* give a message if shooting more than one, or if player
839 attempted to specify a count */
840 if (multishot > 1 || shotlimit > 0) {
841 /* "You shoot N arrows." or "You throw N daggers." */
842 You("%s %d %s.",
843 m_shot.s ? "shoot" : "throw",
844 multishot, /* (might be 1 if player gave shotlimit) */
845 (multishot == 1) ? singular(obj, xname) : xname(obj));
848 if (obj && obj->oartifact == ART_POWERED_BY_HUNGER) {
849 morehungry(multishot * 50);
852 if (obj && uwep && ammo_and_launcher(obj,uwep) && uwep->oartifact == ART_BUG_BAZOOKA) {
853 (void) makemon(mkclass(S_XAN,0), 0, 0, MM_ANGRY);
854 (void) makemon(mkclass(S_ANT,0), 0, 0, MM_ANGRY);
857 if (launcher && launcher->oartifact == ART_TSCHUEUU) youmonst.movement += 6;
859 if (launcher && launcher->oartifact == ART_NOZZLE_CHANGE) {
860 if (launcher->altmode == WP_MODE_AUTO) launcher->altmode = WP_MODE_SINGLE;
861 else launcher->altmode = WP_MODE_AUTO;
865 if (launcher && launcher->oartifact == ART_SHENA_S_PANTY && !rn2(100)) {
866 TimeStopped += rn1(2,2);
867 pline((Role_if(PM_SAMURAI) || Role_if(PM_NINJA)) ? "Jikan ga teishi shimashita." : "Time has stopped.");
870 if (launcher && launcher->oartifact == ART_SCENTFUL_PANTY && !rn2(100)) {
871 TimeStopped += rn1(2,2);
872 pline((Role_if(PM_SAMURAI) || Role_if(PM_NINJA)) ? "Jikan ga teishi shimashita." : "Time has stopped.");
875 if (launcher && launcher->oartifact == ART_SPEW_THE_BOW) {
876 buzz(10, rnd(4), u.ux, u.uy, u.dx, u.dy);
879 if (tech_inuse(T_GREEN_MISSILE) && obj && obj->oclass == VENOM_CLASS) {
880 int melteestrength = 1;
881 if (techlevX(get_tech_no(T_GREEN_MISSILE)) > 9) melteestrength += (techlevX(get_tech_no(T_GREEN_MISSILE)) / 10);
882 buzz(16, melteestrength, u.ux, u.uy, u.dx, u.dy);
885 if (obj && obj->oartifact == ART_ACTUAL_FLAME && u.uen >= 5) {
886 u.uen -= 5;
887 flags.botl = TRUE;
888 buzz(1, 1, u.ux, u.uy, u.dx, u.dy); /* 1, not 11, or it'll explode! */
891 if (tech_inuse(T_BLADE_ANGER) && (objects[obj->otyp].oc_skill == -P_SHURIKEN || objects[obj->otyp].oc_skill == P_SHURIKEN ) ) {
892 struct obj *pseudo;
893 pseudo = mksobj(SPE_BLADE_ANGER, FALSE, 2, FALSE);
894 if (!pseudo) goto bladeangerdone;
895 if (pseudo->otyp == GOLD_PIECE) pseudo->otyp = SPE_BLADE_ANGER; /* minimalist fix */
896 pseudo->blessed = pseudo->cursed = 0;
897 pseudo->quan = 20L; /* do not let useup get it */
898 pseudo->spe = obj->spe;
899 angeramount = multishot;
901 /* we have to clone the entire remaining function because of eternal bugs...
902 * defining pseudo in the function leads to obfree throwing an error if you didn't use blade anger,
903 * and pseudo isn't used in any other way (yet), so let's do it like this --Amy */
905 wep_mask = obj->owornmask;
906 m_shot.o = obj->otyp;
907 m_shot.n = multishot;
908 for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
909 twoweap = u.twoweap;
910 /* split this object off from its slot if necessary */
911 if (obj->quan > 1L) {
912 otmp = splitobj(obj, 1L);
913 } else {
914 otmp = obj;
915 if (otmp->owornmask)
916 remove_worn_item(otmp, FALSE);
918 freeinv(otmp);
919 throwit(otmp, wep_mask, twoweap, thrown);
921 m_shot.n = m_shot.i = 0;
922 m_shot.o = STRANGE_OBJECT;
923 m_shot.s = FALSE;
925 /* now do blade anger damage (it usually has a higher range than the thrown shuriken) */
926 if (u.uen < 10) pline("Not enough mana for blade anger.");
927 while (pseudo && angeramount >= 1) {
928 if (u.uen >= 10) {
929 u.uen -= 10;
930 flags.botl = TRUE;
931 weffects(pseudo);
933 angeramount--;
935 if (pseudo) obfree(pseudo, (struct obj *)0); /* now, get rid of it */
936 return 1;
940 if ((tech_inuse(T_BEAMSWORD) || (obj && obj->oartifact == ART_LINK_S_MASTER_SWORD)) && is_lightsaber(obj) && obj->lamplit ) {
941 if (obj && obj->oartifact == ART_LINK_S_MASTER_SWORD) u.linkmasterswordhack = 1;
942 struct obj *pseudo;
943 pseudo = mksobj(SPE_BEAMSWORD, FALSE, 2, FALSE);
944 if (!pseudo) goto bladeangerdone;
945 if (pseudo->otyp == GOLD_PIECE) pseudo->otyp = SPE_BEAMSWORD; /* minimalist fix */
946 pseudo->blessed = pseudo->cursed = 0;
947 pseudo->quan = 20L; /* do not let useup get it */
948 pseudo->spe = obj->spe;
950 /* we have to clone the entire remaining function because of eternal bugs...
951 * defining pseudo in the function leads to obfree throwing an error if you didn't use blade anger,
952 * and pseudo isn't used in any other way (yet), so let's do it like this --Amy */
954 wep_mask = obj->owornmask;
955 m_shot.o = obj->otyp;
956 m_shot.n = multishot;
957 for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
958 twoweap = u.twoweap;
959 /* split this object off from its slot if necessary */
960 if (obj->quan > 1L) {
961 otmp = splitobj(obj, 1L);
962 } else {
963 otmp = obj;
964 if (otmp->owornmask)
965 remove_worn_item(otmp, FALSE);
967 freeinv(otmp);
968 throwit(otmp, wep_mask, twoweap, thrown);
970 m_shot.n = m_shot.i = 0;
971 m_shot.o = STRANGE_OBJECT;
972 m_shot.s = FALSE;
974 /* now do beamsword damage (it usually has a higher range than the thrown lightsaber) */
975 weffects(pseudo);
977 if (pseudo) obfree(pseudo, (struct obj *)0); /* now, get rid of it */
978 return 1;
982 bladeangerdone:
984 wep_mask = obj->owornmask;
985 m_shot.o = obj->otyp;
986 m_shot.n = multishot;
987 for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
989 int savechance = 0;
991 if (!(PlayerCannotUseSkills)) {
992 switch (P_SKILL(P_MISSILE_WEAPONS)) {
994 case P_BASIC: savechance = 1; break;
995 case P_SKILLED: savechance = 2; break;
996 case P_EXPERT: savechance = 3; break;
997 case P_MASTER: savechance = 4; break;
998 case P_GRAND_MASTER:savechance = 5; break;
999 case P_SUPREME_MASTER:savechance = 6; break;
1000 default: savechance += 0; break;
1004 if (!obj) { /* uh-oh */
1005 You("suddenly ran out of ammo for your ranged attack!");
1006 m_shot.n = m_shot.i = 0;
1007 m_shot.o = STRANGE_OBJECT;
1008 m_shot.s = FALSE;
1009 return 1;
1012 /* melee weapons dull when used repeatedly, so firing a launcher should do the same --Amy */
1013 if (uwep && ammo_and_launcher(obj, uwep) && weaponwilldull(uwep) && (rnd(7) > savechance) && !issoviet) {
1014 if (uwep->greased) {
1015 uwep->greased--;
1016 pline("Your weapon loses its grease.");
1017 } else {
1018 uwep->spe--;
1019 pline("Your weapon dulls.");
1020 u.cnd_weapondull++;
1023 if (uswapwep && ammo_and_launcher(obj, uswapwep) && weaponwilldull(uswapwep) && (rnd(7) > savechance) && !issoviet) {
1024 if (uswapwep->greased) {
1025 uswapwep->greased--;
1026 pline("Your weapon loses its grease.");
1027 } else {
1028 uswapwep->spe--;
1029 pline("Your weapon dulls.");
1030 u.cnd_weapondull++;
1034 if (uwep && uwep->oartifact == ART_LOUD_SHITTER && ammo_and_launcher(obj, uwep)) {
1035 wake_nearby();
1037 if (uswapwep && uswapwep->oartifact == ART_LOUD_SHITTER && ammo_and_launcher(obj, uswapwep)) {
1038 wake_nearby();
1041 twoweap = u.twoweap;
1042 /* split this object off from its slot if necessary */
1043 if (obj->quan > 1L) {
1044 otmp = splitobj(obj, 1L);
1045 } else {
1046 otmp = obj;
1047 if (otmp->owornmask)
1048 remove_worn_item(otmp, FALSE);
1050 freeinv(otmp);
1051 throwit(otmp, wep_mask, twoweap, thrown);
1052 if (autismweaponcheck(ART_PSG) || autismweaponcheck(ART_BORKED_PARA)) {
1053 pushplayer(FALSE);
1056 m_shot.n = m_shot.i = 0;
1057 m_shot.o = STRANGE_OBJECT;
1058 m_shot.s = FALSE;
1060 return 1;
1066 dothrow()
1068 register struct obj *obj;
1069 int oldmulti = multi, result, shotlimit;
1070 char *oldsave_cm = save_cm;
1071 struct trap *trap;
1074 * Since some characters shoot multiple missiles at one time,
1075 * allow user to specify a count prefix for 'f' or or select
1076 * a number of items in the item selection for 't' to limit
1077 * number of items thrown (to avoid possibly hitting something
1078 * behind target after killing it, or perhaps to conserve ammo).
1080 * Nethack 3.3.0 uses prefixes for all - should this revert to that?
1082 * Prior to 3.3.0, command ``3t'' meant ``t(shoot) t(shoot) t(shoot)''
1083 * and took 3 turns. Now it means ``t(shoot at most 3 missiles)''.
1086 if (trap = t_at(u.ux, u.uy)) {
1087 if (trap->ttyp == VIVISECTION_TRAP) {
1088 You("are in vivisection, and therefore unable to use a ranged attack!");
1089 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1090 return 0;
1094 if (u.rangedreload) {
1095 You("have to reload, which is gonna take %d more turns!", u.rangedreload);
1096 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1097 return 0;
1100 if (u.twoweap && uarms) {
1101 You("are way too busy with your two weapons and shield.");
1102 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1103 return 0;
1106 if (notake(youmonst.data) && !Race_if(PM_TRANSFORMER) ) {
1107 You("are physically incapable of throwing anything.");
1108 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1110 if (yn("But you can try to throw anyway. Okay?") == 'y') {
1111 if (rn2(3) && !polyskillchance()) {
1112 morehungry(10);
1113 pline("The darn thing doesn't seem to fly very far.");
1114 if (!rn2(20)) badeffect();
1115 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1116 return 1;
1119 else {return(0);}
1122 if(check_capacity((char *)0)) return(0);
1123 obj = getobj(uslinging() ? bullets : toss_objs, "throw");
1124 /* it is also possible to throw food */
1125 /* (or jewels, or iron balls... ) */
1127 if (!obj) return(0);
1129 #ifdef MAIL
1130 if (obj->otyp == SCR_MAIL) {
1131 You("try to cheat, but it fails.");
1132 if (Is_airlevel(&u.uz)) pline("Stop being a wiseguy and play the game properly already! :-P");
1133 return(0);
1135 #endif
1137 if (EpviProblemActive && obj && (objects[obj->otyp].oc_minlvl > (u.ulevel + u.xtralevelmult - 1) ) ) {
1138 verbalize("I cannot use that yet.");
1139 return(0);
1142 /* kludge to work around parse()'s pre-decrement of 'multi' */
1143 shotlimit = (multi || save_cm) ? multi + 1 : 0;
1145 result = throw_obj(obj, shotlimit, THROW_UWEP);
1148 * [ALI] Bug fix: Temporary paralysis (eg., from hurtle) cancels
1149 * any count for the throw command.
1151 if (multi >= 0)
1152 multi = oldmulti;
1153 save_cm = oldsave_cm;
1154 return (result);
1158 /* KMH -- automatically fill quiver */
1159 /* Suggested by Jeffrey Bay <jbay@convex.hp.com> */
1160 static void
1161 autoquiver()
1163 struct obj *otmp, *oammo = 0, *omissile = 0, *omisc = 0, *altammo = 0;
1165 if (uquiver)
1166 return;
1168 /* Scan through the inventory */
1169 for (otmp = invent; otmp; otmp = otmp->nobj) {
1170 if (otmp->owornmask || otmp->oartifact || !otmp->dknown) {
1171 ; /* Skip it */
1172 } else if (otmp->otyp == ROCK ||
1173 /* seen rocks or known flint or known glass */
1174 (objects[otmp->otyp].oc_name_known &&
1175 otmp->otyp == FLINT) ||
1176 (objects[otmp->otyp].oc_name_known &&
1177 otmp->oclass == GEM_CLASS &&
1178 objects[otmp->otyp].oc_material == MT_GLASS)) {
1179 if (uslinging())
1180 oammo = otmp;
1181 else if (ammo_and_launcher(otmp, uswapwep))
1182 altammo = otmp;
1183 else if (!omisc)
1184 omisc = otmp;
1185 } else if (otmp->oclass == GEM_CLASS) {
1186 ; /* skip non-rock gems--they're ammo but
1187 player has to select them explicitly */
1188 } else if (is_ammo(otmp)) {
1189 if (ammo_and_launcher(otmp, uwep))
1190 /* Ammo matched with launcher (bow and arrow, crossbow and bolt) */
1191 oammo = otmp;
1192 else if (ammo_and_launcher(otmp, uswapwep))
1193 altammo = otmp;
1194 else
1195 /* Mismatched ammo (no better than an ordinary weapon) */
1196 omisc = otmp;
1197 } else if (is_missile(otmp)) {
1198 /* Missile (dart, shuriken, etc.) */
1199 omissile = otmp;
1200 } else if (otmp->oclass == WEAPON_CLASS && throwing_weapon(otmp)) {
1201 /* Ordinary weapon */
1202 if (objects[otmp->otyp].oc_skill == P_DAGGER
1203 && !omissile)
1204 omissile = otmp;
1205 else
1206 omisc = otmp;
1210 /* Pick the best choice */
1211 if (oammo)
1212 setuqwep(oammo);
1213 else if (omissile)
1214 setuqwep(omissile);
1215 else if (altammo)
1216 setuqwep(altammo);
1217 else if (omisc)
1218 setuqwep(omisc);
1220 return;
1224 dofire()
1226 int result, shotlimit;
1227 struct trap *trap;
1229 if (trap = t_at(u.ux, u.uy)) {
1230 if (trap->ttyp == VIVISECTION_TRAP) {
1231 You("are in vivisection, and therefore unable to use a ranged attack!");
1232 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1233 return 0;
1237 if (u.twoweap && uarms) {
1238 You("are way too busy with your two weapons and shield.");
1239 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1240 return 0;
1243 if (u.rangedreload) {
1244 You("have to reload, which is gonna take %d more turns!", u.rangedreload);
1245 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1246 return 0;
1249 if (notake(youmonst.data) && !Race_if(PM_TRANSFORMER) ) {
1250 You("are physically incapable of doing that.");
1251 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1253 if (yn("But you can try to fire anyway. Okay?") == 'y') {
1254 if (rn2(3) && !polyskillchance()) {
1255 morehungry(10);
1256 pline("The darn thing doesn't seem to fly very far.");
1257 if (!rn2(20)) badeffect();
1258 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1259 return 1;
1262 else {return(0);}
1265 #ifdef MAIL
1266 if (uquiver && uquiver->otyp == SCR_MAIL) {
1267 You("try to cheat, but it fails.");
1268 if (Is_airlevel(&u.uz)) pline("Stop being a wiseguy and play the game properly already! :-P");
1269 return(0);
1271 #endif
1273 if (EpviProblemActive && uquiver && (objects[uquiver->otyp].oc_minlvl > (u.ulevel + u.xtralevelmult - 1) ) ) {
1274 verbalize("I cannot use that yet.");
1275 return(0);
1278 if(check_capacity((char *)0)) return(0);
1279 if (!uquiver) {
1280 if (!flags.autoquiver) {
1281 /* Don't automatically fill the quiver */
1282 You("have no ammunition readied!");
1283 if (iflags.quiver_fired)
1284 dowieldquiver(); /* quiver_fired */
1285 if (!uquiver)
1286 return(dothrow());
1288 else { /* quiver_fired */
1289 autoquiver();
1290 if (!uquiver) {
1291 You("have nothing appropriate for your quiver!");
1292 return(dothrow());
1293 } else {
1294 You("fill your quiver:");
1295 prinv((char *)0, uquiver, 0L);
1297 } /* quiver_fired */
1301 * Since some characters shoot multiple missiles at one time,
1302 * allow user to specify a count prefix for 'f' or 't' to limit
1303 * number of items thrown (to avoid possibly hitting something
1304 * behind target after killing it, or perhaps to conserve ammo).
1306 * The number specified can never increase the number of missiles.
1307 * Using ``5f'' when the shooting skill (plus RNG) dictates launch
1308 * of 3 projectiles will result in 3 being shot, not 5.
1310 /* kludge to work around parse()'s pre-decrement of `multi' */
1311 shotlimit = (multi || save_cm) ? multi + 1 : 0;
1312 multi = 0; /* reset; it's been used up */
1314 if (u.twoweap) {
1315 if (!can_twoweapon()) untwoweapon();
1316 else if (ammo_and_launcher(uquiver,uwep)
1317 && ammo_and_launcher(uquiver, uswapwep)){
1318 result = throw_obj(uquiver, shotlimit, THROW_UWEP);
1319 if ((result == 1) && uquiver)
1320 result += throw_obj(uquiver, shotlimit, THROW_USWAPWEP);
1321 if (result > 1) result--;
1322 return(result);
1325 result = (throw_obj(uquiver, shotlimit, THROW_UWEP));
1327 return result;
1332 * Object hits floor at hero's feet. Called from drop() and throwit().
1334 void
1335 hitfloor(obj)
1336 register struct obj *obj;
1338 if (IS_SOFT(levl[u.ux][u.uy].typ) || u.uinwater) {
1339 dropy(obj);
1340 return;
1342 if (IS_ALTAR(levl[u.ux][u.uy].typ))
1343 doaltarobj(obj);
1344 else
1345 pline("%s hit%s the %s.", Doname2(obj),
1346 (obj->quan == 1L) ? "s" : "", surface(u.ux,u.uy));
1347 /* waaaaaaaaaaay too big a penalty to lose ALL potions unconditionally --Amy */
1348 if (!rn2(obj->oerodeproof ? 100 : 20)) {
1349 if (hero_breaks(obj, u.ux, u.uy, TRUE)) return;
1351 if (ship_object(obj, u.ux, u.uy, FALSE)) return;
1352 dropy(obj);
1353 if (!u.uswallow) container_impact_dmg(obj);
1357 * Walk a path from src_cc to dest_cc, calling a proc for each location
1358 * except the starting one. If the proc returns FALSE, stop walking
1359 * and return FALSE. If stopped early, dest_cc will be the location
1360 * before the failed callback.
1362 boolean
1363 walk_path(src_cc, dest_cc, check_proc, arg)
1364 coord *src_cc;
1365 coord *dest_cc;
1366 boolean (*check_proc)(void *, int, int);
1367 void * arg;
1369 int x, y, dx, dy, x_change, y_change, err, i, prev_x, prev_y;
1370 boolean keep_going = TRUE;
1372 /* Use Bresenham's Line Algorithm to walk from src to dest */
1373 dx = dest_cc->x - src_cc->x;
1374 dy = dest_cc->y - src_cc->y;
1375 prev_x = x = src_cc->x;
1376 prev_y = y = src_cc->y;
1378 if (dx < 0) {
1379 x_change = -1;
1380 dx = -dx;
1381 } else
1382 x_change = 1;
1383 if (dy < 0) {
1384 y_change = -1;
1385 dy = -dy;
1386 } else
1387 y_change = 1;
1389 i = err = 0;
1390 if (dx < dy) {
1391 while (i++ < dy) {
1392 prev_x = x;
1393 prev_y = y;
1394 y += y_change;
1395 err += dx;
1396 if (err >= dy) {
1397 x += x_change;
1398 err -= dy;
1400 /* check for early exit condition */
1401 if (!(keep_going = (*check_proc)(arg, x, y)))
1402 break;
1404 } else {
1405 while (i++ < dx) {
1406 prev_x = x;
1407 prev_y = y;
1408 x += x_change;
1409 err += dy;
1410 if (err >= dx) {
1411 y += y_change;
1412 err -= dx;
1414 /* check for early exit condition */
1415 if (!(keep_going = (*check_proc)(arg, x, y)))
1416 break;
1420 if (keep_going)
1421 return TRUE; /* successful */
1423 dest_cc->x = prev_x;
1424 dest_cc->y = prev_y;
1425 return FALSE;
1429 * Single step for the hero flying through the air from jumping, flying,
1430 * etc. Called from hurtle() and jump() via walk_path(). We expect the
1431 * argument to be a pointer to an integer -- the range -- which is
1432 * used in the calculation of points off if we hit something.
1434 * Bumping into monsters won't cause damage but will wake them and make
1435 * them angry. Auto-pickup isn't done, since you don't have control over
1436 * your movements at the time.
1438 * Possible additions/changes:
1439 * o really attack monster if we hit one
1440 * o set stunned if we hit a wall or door
1441 * o reset nomul when we stop
1442 * o creepy feeling if pass through monster (if ever implemented...)
1443 * o bounce off walls
1444 * o let jumps go over boulders
1446 boolean
1447 hurtle_step(arg, x, y)
1448 void * arg;
1449 int x, y;
1451 int ox, oy, *range = (int *)arg;
1452 struct obj *obj;
1453 struct monst *mon;
1454 boolean may_pass = TRUE;
1455 struct trap *ttmp;
1457 if (!isok(x,y)) {
1458 You_feel("the spirits holding you back.");
1459 return FALSE;
1460 } else if (!in_out_region(x, y)) {
1461 return FALSE;
1462 } else if (*range == 0) {
1463 return FALSE; /* previous step wants to stop now */
1466 if (!Passes_walls || !(may_pass = may_passwall(x, y))) {
1467 if (IS_ROCK(levl[x][y].typ) || closed_door(x,y)) {
1468 const char *s;
1470 pline("Ouch!");
1471 if (IS_TREE(levl[x][y].typ))
1472 s = "bumping into a tree";
1473 else if (IS_ROCK(levl[x][y].typ))
1474 s = "bumping into a wall";
1475 else
1476 s = "bumping into a door";
1477 losehp(rnd(2+*range), s, KILLED_BY);
1478 return FALSE;
1480 if (levl[x][y].typ == IRONBARS) {
1481 You("crash into some iron bars. Ouch!");
1482 losehp(rnd(2+*range), "crashing into iron bars", KILLED_BY);
1483 return FALSE;
1485 if ((obj = sobj_at(BOULDER,x,y)) != 0) {
1486 You("bump into a %s. Ouch!", xname(obj));
1487 losehp(rnd(2+*range), "bumping into a boulder", KILLED_BY);
1488 return FALSE;
1490 if (!may_pass) {
1491 /* did we hit a no-dig non-wall position? */
1492 You("smack into something!");
1493 losehp(rnd(2+*range), "touching the edge of the universe", KILLED_BY);
1494 return FALSE;
1496 if ((u.ux - x) && (u.uy - y) &&
1497 bad_rock(&youmonst,u.ux,y) && bad_rock(&youmonst,x,u.uy)) {
1498 boolean too_much = (invent && (inv_weight() + weight_cap() > 5000));
1499 /* Move at a diagonal. */
1500 if (bigmonst(youmonst.data) || too_much) {
1501 You("%sget forcefully wedged into a crevice.",
1502 too_much ? "and all your belongings " : "");
1503 losehp(rnd(2+*range), "wedging into a narrow crevice", KILLED_BY);
1504 return FALSE;
1509 if ((mon = m_at(x, y)) != 0) {
1510 You("bump into %s.", a_monnam(mon));
1511 wakeup(mon);
1512 return FALSE;
1514 if ((u.ux - x) && (u.uy - y) &&
1515 bad_rock(&youmonst, u.ux, y) && bad_rock(&youmonst, x, u.uy)) {
1516 /* Move at a diagonal. */
1517 if (In_sokoban(&u.uz)) {
1518 You("come to an abrupt halt!");
1519 return FALSE;
1523 ox = u.ux;
1524 oy = u.uy;
1525 u.ux = x;
1526 u.uy = y;
1527 newsym(ox, oy); /* update old position */
1528 vision_recalc(1); /* update for new position */
1529 flush_screen(1);
1530 /* FIXME:
1531 * Each trap should really trigger on the recoil if
1532 * it would trigger during normal movement. However,
1533 * not all the possible side-effects of this are
1534 * tested [as of 3.4.0] so we trigger those that
1535 * we have tested, and offer a message for the
1536 * ones that we have not yet tested.
1538 if ((ttmp = t_at(x, y)) != 0) {
1539 if (ttmp->ttyp == MAGIC_PORTAL) {
1540 dotrap(ttmp,0);
1541 return FALSE;
1542 } else if (ttmp->ttyp == FIRE_TRAP) {
1543 dotrap(ttmp,0);
1544 } else if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT || ttmp->ttyp == GIANT_CHASM || ttmp->ttyp == SHIT_PIT || ttmp->ttyp == MANA_PIT || ttmp->ttyp == ANOXIC_PIT || ttmp->ttyp == HYPOXIC_PIT || ttmp->ttyp == ACID_PIT || ttmp->ttyp == SHAFT_TRAP || ttmp->ttyp == CURRENT_SHAFT ||
1545 ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR) &&
1546 In_sokoban(&u.uz)) {
1547 /* Air currents overcome the recoil */
1548 dotrap(ttmp,0);
1549 *range = 0;
1550 return TRUE;
1551 } else {
1552 if (ttmp->tseen)
1553 You("pass right over %s %s.",
1554 (ttmp->ttyp == ARROW_TRAP) ? "an" : "a",
1555 defsyms[trap_to_defsym(ttmp->ttyp)].explanation);
1558 if (--*range < 0) /* make sure our range never goes negative */
1559 *range = 0;
1560 if (*range != 0)
1561 delay_output();
1562 return TRUE;
1565 STATIC_OVL boolean
1566 mhurtle_step(arg, x, y)
1567 void * arg;
1568 int x, y;
1570 struct monst *mon = (struct monst *)arg;
1572 /* TODO: Treat walls, doors, iron bars, pools, lava, etc. specially
1573 * rather than just stopping before.
1575 if (goodpos(x, y, mon, 0) && m_in_out_region(mon, x, y)) {
1576 remove_monster(mon->mx, mon->my);
1577 newsym(mon->mx, mon->my);
1578 place_monster(mon, x, y);
1579 newsym(mon->mx, mon->my);
1580 set_apparxy(mon);
1581 (void) mintrap(mon);
1582 return TRUE;
1584 return FALSE;
1588 * The player moves through the air for a few squares as a result of
1589 * throwing or kicking something.
1591 * dx and dy should be the direction of the hurtle, not of the original
1592 * kick or throw and be only.
1594 void
1595 hurtle(dx, dy, range, verbose)
1596 int dx, dy, range;
1597 boolean verbose;
1599 coord uc, cc;
1601 /* The chain is stretched vertically, so you shouldn't be able to move
1602 * very far diagonally. The premise that you should be able to move one
1603 * spot leads to calculations that allow you to only move one spot away
1604 * from the ball, if you are levitating over the ball, or one spot
1605 * towards the ball, if you are at the end of the chain. Rather than
1606 * bother with all of that, assume that there is no slack in the chain
1607 * for diagonal movement, give the player a message and return.
1609 if(Punished && !carried(uball)) {
1610 You_feel("a tug from the iron ball.");
1611 nomul(0, 0, FALSE);
1612 return;
1613 } else if (u.utrap) {
1614 You("are anchored by the %s.",
1615 u.utraptype == TT_WEB ? "web" : u.utraptype == TT_GLUE ? "glue" : u.utraptype == TT_LAVA ? "lava" :
1616 u.utraptype == TT_INFLOOR ? surface(u.ux,u.uy) : "trap");
1617 nomul(0, 0, FALSE);
1618 return;
1621 /* make sure dx and dy are [-1,0,1] */
1622 dx = sgn(dx);
1623 dy = sgn(dy);
1625 if(!range || (!dx && !dy) || u.ustuck) return; /* paranoia */
1627 nomul(-range, "moving through the air", TRUE);
1628 nomovemsg = 0;
1629 if (verbose)
1630 You("%s in the opposite direction.", range > 1 ? "hurtle" : "float");
1631 /* if we're in the midst of shooting multiple projectiles, stop */
1632 if (m_shot.i < m_shot.n) {
1633 /* last message before hurtling was "you shoot N arrows" */
1634 You("stop %sing after the first %s.",
1635 m_shot.s ? "shoot" : "throw", m_shot.s ? "shot" : "toss");
1636 m_shot.n = m_shot.i; /* make current shot be the last */
1639 /* This used to give sokoban penalties but you can't actually bypass anything so the penalty is removed --Amy */
1640 /* Soviet Russia comment is in apply.c */
1642 if (issoviet && In_sokoban(&u.uz)) {
1643 change_luck(-1);
1644 pline("Teper' vy teryayete ochko udachi KHAR KHAR. Eto deystviye ne pomoglo vam reshit' golovolomki, no my takiye elitnyye.");
1645 if (evilfriday) u.ugangr++;
1648 uc.x = u.ux;
1649 uc.y = u.uy;
1650 /* this setting of cc is only correct if dx and dy are [-1,0,1] only */
1651 cc.x = u.ux + (dx * range);
1652 cc.y = u.uy + (dy * range);
1653 (void) walk_path(&uc, &cc, hurtle_step, (void *)&range);
1654 teleds(cc.x, cc.y, FALSE);
1657 /* Move a monster through the air for a few squares.
1659 void
1660 mhurtle(mon, dx, dy, range)
1661 struct monst *mon;
1662 int dx, dy, range;
1664 coord mc, cc;
1666 /* At the very least, debilitate the monster */
1667 mon->movement = 0;
1668 mon->mstun = 1;
1670 /* Is the monster stuck or too heavy to push?
1671 * (very large monsters have too much inertia, even floaters and flyers)
1673 if (mon->data->msize >= MZ_HUGE || mon == u.ustuck || mon->mtrapped)
1674 return;
1676 /* Make sure dx and dy are [-1,0,1] */
1677 dx = sgn(dx);
1678 dy = sgn(dy);
1679 if(!range || (!dx && !dy)) return; /* paranoia */
1681 /* Send the monster along the path */
1682 mc.x = mon->mx;
1683 mc.y = mon->my;
1684 cc.x = mon->mx + (dx * range);
1685 cc.y = mon->my + (dy * range);
1686 (void) walk_path(&mc, &cc, mhurtle_step, (void *)mon);
1687 return;
1690 STATIC_OVL void
1691 check_shop_obj(obj, x, y, broken)
1692 register struct obj *obj;
1693 register xchar x, y;
1694 register boolean broken;
1696 struct monst *shkp = shop_keeper(*u.ushops);
1698 if(!shkp) return;
1700 if(broken) {
1701 if (obj->unpaid) {
1702 (void)stolen_value(obj, u.ux, u.uy,
1703 (boolean)shkp->mpeaceful, FALSE, TRUE);
1704 subfrombill(obj, shkp);
1706 obj->no_charge = 1;
1707 return;
1710 if (!costly_spot(x, y) || *in_rooms(x, y, SHOPBASE) != *u.ushops) {
1711 /* thrown out of a shop or into a different shop */
1712 if (obj->unpaid) {
1713 (void)stolen_value(obj, u.ux, u.uy,
1714 (boolean)shkp->mpeaceful, FALSE, FALSE);
1715 subfrombill(obj, shkp);
1717 } else {
1718 if (costly_spot(u.ux, u.uy) && costly_spot(x, y)) {
1719 if(obj->unpaid) subfrombill(obj, shkp);
1720 else if(!(x == shkp->mx && y == shkp->my))
1721 sellobj(obj, x, y);
1727 * Hero tosses an object upwards with appropriate consequences.
1729 * Returns FALSE if the object is gone.
1731 STATIC_OVL boolean
1732 toss_up(obj, hitsroof)
1733 struct obj *obj;
1734 boolean hitsroof;
1736 const char *almost;
1737 /* note: obj->quan == 1 */
1739 if (hitsroof) {
1740 if (breaktest(obj)) {
1741 pline("%s hits the %s.", Doname2(obj), ceiling(u.ux, u.uy));
1742 breakmsg(obj, !Blind);
1743 if (issegfaulter && obj->otyp == SEGFAULT_VENOM && !rn2(5) ) { /* segfault panic! */
1744 u.segfaultpanic = TRUE;
1745 } else if (obj->oartifact == ART_DO_NOT_THROW_ME) { /* uh-oh... you really messed up big time there. */
1746 u.segfaultpanic = TRUE;
1748 breakobj(obj, u.ux, u.uy, TRUE, TRUE);
1749 return FALSE;
1751 almost = "";
1752 } else {
1753 almost = " almost";
1755 pline("%s%s hits the %s, then falls back on top of your %s.",
1756 Doname2(obj), almost, ceiling(u.ux,u.uy), body_part(HEAD));
1758 /* object now hits you */
1760 if (obj->oclass == POTION_CLASS) {
1761 potionhit(&youmonst, obj, TRUE);
1762 } else if (breaktest(obj)) {
1763 int otyp = obj->otyp, ocorpsenm = obj->corpsenm;
1764 int blindinc;
1766 /* need to check for blindness result prior to destroying obj */
1767 blindinc = (otyp == CREAM_PIE || otyp == BLINDING_VENOM) &&
1768 /* AT_WEAP is ok here even if attack type was AT_SPIT */
1769 can_blnd(&youmonst, &youmonst, AT_WEAP, obj) ? rnd(25) : 0;
1771 breakmsg(obj, !Blind);
1772 breakobj(obj, u.ux, u.uy, TRUE, TRUE);
1773 obj = 0; /* it's now gone */
1774 switch (otyp) {
1775 case PETRIFYIUM_BAR:
1776 if (!uarmh && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) &&
1777 !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)))
1778 goto petrify;
1779 case PETRIFYIUM_BRA:
1780 if (!uarmh && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) &&
1781 !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)))
1782 goto petrify;
1783 case EGG:
1784 if (touch_petrifies(&mons[ocorpsenm]) && ocorpsenm != PM_PLAYERMON &&
1785 !uarmh && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) &&
1786 !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)))
1787 goto petrify;
1788 case CREAM_PIE:
1789 case BLINDING_VENOM:
1790 pline("You've got it all over your %s!", body_part(FACE));
1791 if (blindinc) {
1792 if (otyp == BLINDING_VENOM && !Blind)
1793 pline("It blinds you!");
1794 u.ucreamed += blindinc;
1795 make_blinded(Blinded + (long)blindinc, FALSE);
1796 if (!Blind) Your("%s", vision_clears);
1798 break;
1799 default:
1800 break;
1802 return FALSE;
1803 } else { /* neither potion nor other breaking object */
1804 boolean less_damage = uarmh && is_hardmaterial(uarmh), artimsg = FALSE;
1805 int dmg = dmgval(obj, &youmonst);
1807 if (obj->oartifact)
1808 /* need a fake die roll here; rn1(18,2) avoids 1 and 20 */
1809 artimsg = artifact_hit((struct monst *)0, &youmonst,
1810 obj, &dmg, rn1(18,2));
1812 if (!dmg) { /* probably wasn't a weapon; base damage on weight */
1813 dmg = (int) obj->owt / 100;
1814 if (dmg < 1) dmg = 1;
1815 else if (dmg > 6) dmg = 6;
1816 if (is_shade(youmonst.data) && objects[obj->otyp].oc_material != MT_SILVER && objects[obj->otyp].oc_material != MT_ARCANIUM)
1817 dmg = 0;
1819 if (dmg > 1 && less_damage) dmg = 1;
1820 if (dmg > 0) {
1821 if (increase_damage_bonus_value() > 1) dmg += rnd(increase_damage_bonus_value());
1822 else dmg += increase_damage_bonus_value();
1824 if (dmg > 0 && uarmh && uarmh->oartifact == ART_REMOTE_GAMBLE) dmg += 2;
1825 if (dmg > 0 && uarm && uarm->oartifact == ART_MOTHERFUCKER_TROPHY) dmg += 5;
1826 if (dmg > 0 && u.tiksrvzllatdown) dmg += 1;
1828 if (dmg > 0 && (uarmg && itemhasappearance(uarmg, APP_UNCANNY_GLOVES))) dmg += 1;
1829 if (dmg > 0 && (uarmg && itemhasappearance(uarmg, APP_SLAYING_GLOVES))) dmg += 1;
1831 if (dmg > 0 && uarmc && uarmc->oartifact == ART_INA_S_SORROW && u.uhunger < 0) dmg += 3;
1832 if (dmg > 0 && uwep && uwep->oartifact == ART_SPAMBAIT_FIRE) dmg += 2;
1833 if (dmg > 0 && uwep && uwep->oartifact == ART_GARY_S_RIVALRY) dmg += 2;
1834 if (dmg > 0 && uarmf && uarmf->oartifact == ART_KATI_S_IRRESISTIBLE_STILET) dmg += 2;
1835 if (dmg > 0 && uarmf && uarmf->oartifact == ART_STREET_ROCKZ) dmg += 2;
1836 if (dmg > 0 && uwep && uwep->oartifact == ART_THOR_S_STRIKE && ACURR(A_STR) >= STR19(25)) dmg += 5;
1837 if (dmg > 0 && uarmh && uarmh->oartifact == ART_IRON_HELM_OF_GORLIM) dmg += 10;
1838 if (dmg > 0 && uarmh && uarmh->oartifact == ART_SUDUNSEL) dmg += 2;
1839 if (dmg > 0 && uwep && uwep->oartifact == ART_KLOCKING_NOISE) dmg += 2;
1840 if (dmg > 0 && uarm && uarm->otyp == DARK_DRAGON_SCALES) dmg += 1;
1841 if (dmg > 0 && uarmg && uarmg->oartifact == ART_FLOEMMELFLOEMMELFLOEMMELFL) dmg += 1;
1842 if (dmg > 0 && uarm && uarm->otyp == DARK_DRAGON_SCALE_MAIL) dmg += 1;
1843 if (dmg > 0 && uarms && uarms->otyp == DARK_DRAGON_SCALE_SHIELD) dmg += 1;
1844 if (dmg > 0 && uarmg && uarmg->oartifact == ART_YES_TO_RANGED_COMBAT) dmg += rnd(6);
1845 if (dmg > 0 && uleft && uleft->oartifact == ART_BLIND_PILOT) dmg += 10;
1846 if (dmg > 0 && uright && uright->oartifact == ART_BLIND_PILOT) dmg += 10;
1847 if (dmg > 0 && uamul && uamul->oartifact == ART_NOW_YOU_HAVE_LOST) dmg += 10;
1848 if (dmg > 0 && Role_if(PM_ARCHEOLOGIST) && uamul && uamul->oartifact == ART_ARCHEOLOGIST_SONG) dmg += 2;
1849 if (dmg > 0 && uarmg && uarmg->oartifact == ART_MADELINE_S_STUPID_GIRL) dmg += 3;
1850 if (dmg > 0 && ublindf && ublindf->oartifact == ART_EYEHANDER) dmg += 5;
1851 if (dmg > 0) dmg += (Drunken_boxing && Confusion);
1852 if (dmg > 0) dmg += (StrongDrunken_boxing && Confusion);
1853 if (RngeBloodlust && dmg > 0) dmg++;
1854 if (dmg > 0 && u.boosttimer) dmg += 2;
1855 if (dmg > 0 && uarms && uarms->oartifact == ART_TEH_BASH_R) dmg += 2;
1856 if (dmg > 0 && uarmc && uarmc->oartifact == ART_DUFFDUFFDUFF) dmg += 3;
1857 if (dmg > 0 && uarmg && uarmg->oartifact == ART_RAAAAAAAARRRRRRGH) dmg += 5;
1858 if (dmg > 0 && uarmg && uarmg->oartifact == ART_SI_OH_WEE) dmg += 2;
1859 if (dmg > 0 && powerfulimplants() && uimplant && uimplant->oartifact == ART_RHEA_S_MISSING_EYESIGHT) dmg += rnd(5);
1860 if (dmg > 0 && powerfulimplants() && uimplant && uimplant->oartifact == ART_SOME_LITTLE_AID) dmg += 1;
1861 if (dmg > 0 && Race_if(PM_VIKING)) dmg += 1;
1862 if (dmg > 0 && Race_if(PM_SERB)) dmg += 1;
1863 if (dmg > 0 && Race_if(PM_RUSMOT)) dmg += 2;
1864 if (dmg > 0 && uarmg && uarmg->oartifact == ART_MAJOR_PRESENCE) dmg += 2;
1865 if (dmg > 0 && uarmf && uarmf->oartifact == ART_SNAILHUNT) dmg += 1;
1866 if (dmg > 0 && uarmf && uarmf->oartifact == ART_MAY_BRITT_S_ADULTHOOD) dmg += 1;
1867 if (dmg > 0 && uarmf && uarmf->oartifact == ART_CRASHING_YOUR_SISTER_S_WED) dmg += 2;
1868 if (dmg > 0 && uwep && uwep->oartifact == ART_SINSWORD && u.ualign.record < 0) dmg += 1;
1869 if (dmg > 0 && uwep && uwep->oartifact == ART_SINSWORD && u.ualign.record < 49) dmg += 1;
1870 if (dmg > 0 && uwep && uwep->oartifact == ART_SINSWORD && u.ualign.record < 99) dmg += 1;
1871 if (dmg > 0 && uwep && uwep->oartifact == ART_SINSWORD && u.ualign.record < 149) dmg += 1;
1872 if (dmg > 0 && uwep && uwep->oartifact == ART_SINSWORD && u.ualign.record < 199) dmg += 1;
1873 if (dmg > 0 && uwep && uwep->oartifact == ART_SINSWORD && u.ualign.record < 249) dmg += 1;
1874 if (dmg > 0 && bmwride(ART_KERSTIN_S_COWBOY_BOOST)) dmg += 2;
1875 if (dmg > 0 && Role_if(PM_OTAKU) && uarmc && itemhasappearance(uarmc, APP_FOURCHAN_CLOAK)) dmg += 1;
1876 if (dmg > 0 && Race_if(PM_RODNEYAN)) dmg += (1 + (GushLevel / 3) );
1877 if (dmg > 0 && uarmf && uarmf->oartifact == ART_PROPERTY_GRUMBLE) dmg += 8;
1878 if (dmg > 0 && uarmh && uarmh->oartifact == ART_HABIBA_S_MATRONAGE) dmg += 2;
1879 if (dmg > 0 && uarmg && uarmg->oartifact == ART_UNKNOWINGNESS_AS_A_WEAPON && !(objects[uarmg->otyp].oc_name_known)) dmg += 5;
1880 if (dmg > 0 && uwep && uwep->oartifact == ART_BUCK_SHOT && !uwep->bknown) dmg += 2;
1881 if (dmg > 0 && uwep && uwep->oartifact == ART_FALCO_S_ORB) dmg += 1;
1882 if (dmg > 0 && uarmg && uarmg->oartifact == ART_PLUS_TO_DAM) dmg += 2;
1883 if (dmg > 0 && uarm && uarm->oartifact == ART_YOU_ARE_UGLY) dmg += 1;
1884 if (dmg > 0 && uarm && uarm->oartifact == ART_THERE_GOES_SHE_TO) dmg += 4;
1885 if (dmg > 0 && uarms && uarms->oartifact == ART_RONDITSCH) dmg += 1;
1886 if (dmg > 0 && uwep && uwep->oartifact == ART_NOOBY_BONUS_STYLE && !bimanual(uwep)) dmg += 2;
1887 if (dmg > 0 && powerfulimplants() && uimplant && uimplant->oartifact == ART_NIOBE_S_ANGER) dmg += 2;
1888 if (dmg > 0 && powerfulimplants() && uimplant && uimplant->oartifact == ART_I_M_GONNA_CRUSH_YA_) dmg += 4;
1889 if (dmg > 0 && uarms && uarms->oartifact == ART_UNUSUAL_ENCH) dmg += 1;
1890 if (dmg > 0 && bmwride(ART_ZIN_BA)) dmg += 1;
1891 if (dmg > 0 && uarm && uarm->oartifact == ART_I_AM_YOUR_FALL) dmg += 2;
1892 if (dmg > 0 && uarm && uarm->oartifact == ART_ETH_ITH) dmg += 3;
1893 if (dmg > 0 && uleft && uleft->oartifact == ART_RING_OF_THROR) dmg += 2;
1894 if (dmg > 0 && uright && uright->oartifact == ART_RING_OF_THROR) dmg += 2;
1895 if (dmg > 0 && uleft && uleft->oartifact == ART_KRATSCHEM_HARD) dmg += 2;
1896 if (dmg > 0 && uright && uright->oartifact == ART_KRATSCHEM_HARD) dmg += 2;
1897 if (dmg > 0 && uleft && uleft->oartifact == ART_WILDFIST) dmg += 4;
1898 if (dmg > 0 && uright && uright->oartifact == ART_WILDFIST) dmg += 4;
1899 if (dmg > 0 && uarm && uarm->oartifact == ART_EITHER_INTELLIGENT_OR_FAIR) dmg += 2;
1900 if (dmg > 0 && uarmg && uarmg->oartifact == ART_DOCHGOGRAP) dmg += 2;
1902 if (dmg > 0 && uwep && uwep->oartifact == ART_AK_____) {
1903 if (!PlayerCannotUseSkills) {
1904 if (P_SKILL(P_FIREARM) < P_BASIC) dmg += 3;
1905 else if (P_SKILL(P_FIREARM) == P_BASIC) dmg += 2;
1906 else if (P_SKILL(P_FIREARM) == P_SKILLED) dmg += 1;
1908 if (P_SKILL(P_FIREARM) == P_MASTER) dmg -= 2;
1909 if (P_SKILL(P_FIREARM) == P_GRAND_MASTER) dmg -= 4;
1910 if (P_SKILL(P_FIREARM) == P_SUPREME_MASTER) dmg -= 6;
1912 if (dmg > 0 && u.twoweap && uswapwep && uswapwep->oartifact == ART_AK_____) {
1913 if (P_SKILL(P_FIREARM) == P_MASTER) dmg -= 2;
1914 if (P_SKILL(P_FIREARM) == P_GRAND_MASTER) dmg -= 4;
1915 if (P_SKILL(P_FIREARM) == P_SUPREME_MASTER) dmg -= 6;
1918 if (Race_if(PM_ITAQUE)) dmg -= 1;
1919 if (uwep && uwep->oartifact == ART_RIP_STRATEGY) dmg -= 5;
1920 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_RIP_STRATEGY) dmg -= 5;
1921 if (uwep && uwep->oartifact == ART_KLOBB) dmg -= 6;
1922 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_KLOBB) dmg -= 6;
1923 if (uwep && uwep->oartifact == ART_EXCALIPOOR) dmg -= 9;
1924 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_EXCALIPOOR) dmg -= 9;
1925 if (uwep && uwep->oartifact == ART_VLADSBANE) dmg -= 5;
1926 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_VLADSBANE) dmg -= 5;
1927 if (uwep && uwep->oartifact == ART_CHARGING_MADE_EASY) dmg -= 5;
1928 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_CHARGING_MADE_EASY) dmg -= 5;
1929 if (uwep && uwep->oartifact == ART_BLACK_MARK) dmg -= 1;
1930 if (uarm && uarm->oartifact == ART_POWASPEL) dmg -= 3;
1932 if (dmg < 0) dmg = 0; /* beware negative rings of increase damage */
1933 if (Half_physical_damage && (rn2(2) || (uwep && uwep->oartifact == ART_SOOTHE_)) ) dmg = (dmg + 1) / 2;
1934 if (StrongHalf_physical_damage && (rn2(2) || (uwep && uwep->oartifact == ART_SOOTHE_)) ) dmg = (dmg + 1) / 2;
1936 if (uarmh) {
1937 if (less_damage && dmg < (Upolyd ? u.mh : u.uhp)) {
1938 if (!artimsg)
1939 pline("Fortunately, you are wearing a hard helmet.");
1940 } else if (flags.verbose &&
1941 !(obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])))
1942 Your("%s does not protect you.", xname(uarmh));
1943 } else if (obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])) {
1944 if ((!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) &&
1945 !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
1946 petrify:
1947 /* killer_format = KILLED_BY;
1948 killer = "elementary physics";
1949 You("turn to stone.");
1950 if (obj) dropy(obj);
1951 done(STONING); */
1952 if (!Stoned) {
1953 if (Hallucination && rn2(10)) pline("Good thing you are already stoned.");
1954 else {
1955 You("start turning to stone.");
1956 Stoned = Race_if(PM_EROSATOR) ? 3 : 7;
1957 u.cnd_stoningcount++;
1958 delayed_killer = "elementary physics";
1961 return obj ? TRUE : FALSE;
1964 hitfloor(obj);
1965 losehp(dmg, "falling object", KILLED_BY_AN);
1967 return TRUE;
1970 /* return true for weapon meant to be thrown; excludes ammo */
1971 STATIC_OVL boolean
1972 throwing_weapon(obj)
1973 struct obj *obj;
1975 return (is_missile(obj) || is_spear(obj) ||
1976 /* daggers and knife (excludes scalpel) */
1977 (is_blade(obj) && !is_sword(obj) &&
1978 (objects[obj->otyp].oc_dir & PIERCE)) ||
1979 /* special cases [might want to add AXE] */
1980 obj->otyp == WAR_HAMMER || obj->otyp == AKLYS || obj->otyp == BLOW_AKLYS);
1983 /* the currently thrown object is returning to you (not for boomerangs) */
1984 STATIC_OVL void
1985 sho_obj_return_to_u(obj)
1986 struct obj *obj;
1988 /* might already be our location (bounced off a wall) */
1989 if (bhitpos.x != u.ux || bhitpos.y != u.uy) {
1990 int x = bhitpos.x - u.dx, y = bhitpos.y - u.dy;
1992 tmp_at(DISP_FLASH, obj_to_glyph(obj));
1993 while(x != u.ux || y != u.uy) {
1994 tmp_at(x, y);
1995 delay_output();
1996 x -= u.dx; y -= u.dy;
1998 tmp_at(DISP_END, 0);
2002 void
2003 throwit(obj, wep_mask, twoweap, thrown)
2004 struct obj *obj;
2005 long wep_mask; /* used to re-equip returning boomerang */
2006 boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
2007 int thrown;
2009 register struct monst *mon;
2010 register int range, urange;
2011 struct obj *launcher = (struct obj*) 0;
2012 boolean impaired = ( (Confusion && !Conf_resist) || (Stunned && !Stun_resist) || Blind ||
2013 Hallucination || Fumbling || Frozen || Burned || Dimmed || Numbed || Feared);
2015 if (thrown == 1) launcher = uwep;
2016 else if (thrown == 2) launcher = uswapwep;
2017 else if (thrown == 666) { /* inbuilt pistol boots */
2018 if (uarmf && itemhasappearance(uarmf, APP_PISTOL_BOOTS) ) launcher = uarmf;
2021 boolean misfire = FALSE;
2022 if (obj->cursed && !(uarmg && uarmg->otyp == GAUNTLETS_OF_TRUE_AIM) && !(uarmg && itemhasappearance(uarmg, APP_SUREFIRE_GLOVES)) ) {
2023 if (!rn2(7)) misfire = TRUE;
2025 if (obj->otyp == FLIMSY_DART) {
2026 if (!rn2(7)) misfire = TRUE;
2028 if (ACURR(A_DEX) == 1) {
2029 if (!rn2(7)) misfire = TRUE;
2031 if (is_grassland(u.ux, u.uy) && !(uarm && uarm->oartifact == ART_DORL_TSCH) && !(uarmf && itemhasappearance(uarmf, APP_GARDEN_SLIPPERS)) ) {
2032 if (!rn2(7)) misfire = TRUE;
2034 if (obj->greased) {
2035 if (!rn2(7)) misfire = TRUE;
2037 if (Race_if(PM_PLAYER_SKELETON) && !rn2(3)) {
2038 if (!rn2(7)) misfire = TRUE;
2040 if (autismweaponcheck(ART_FOEOEOEOEOEOEOE)) {
2041 if (!rn2(7)) misfire = TRUE;
2043 if (uarmg && itemhasappearance(uarmg, APP_CLUMSY_GLOVES) ) {
2044 if (!rn2(7)) misfire = TRUE;
2046 if ((obj->oartifact == ART_COMPLETELY_OFF) || (obj->oartifact == ART_FLUSCH) || (obj->oartifact == ART_STREW_ANYWHERE) || u.uprops[PROJECTILES_MISFIRE].extrinsic || ProjectilesMisfire || have_misfirestone() ) misfire = TRUE;
2048 /* KMH -- Handle Plague here */
2049 if (launcher && (launcher->oartifact == ART_PLAGUE || launcher->oartifact == ART_BOW_OF_VINDERRE || launcher->oartifact == ART_SHAKING_BOW || launcher->oartifact == ART_BIBLICAL_PLAGUE || launcher->oartifact == ART_BOW_OF_HERCULES) &&
2050 ammo_and_launcher(obj, launcher) && is_poisonable(obj))
2051 obj->opoisoned = 1;
2053 if (launcher && launcher->oartifact == ART_NOZZLE_CHANGE && ammo_and_launcher(obj, launcher))
2054 obj->opoisoned = 1; /* even if it cannot be poisoned, this is not a bug --Amy */
2056 if (uarmf && uarmf->oartifact == ART_DOUBTLY_POISON && is_poisonable(obj)) {
2057 obj->opoisoned = obj->superpoison = 1;
2060 if (obj && obj->oartifact == ART_TROPICAL_WOOD_SELECTION) obj->opoisoned = 1;
2061 if (obj && obj->oartifact == ART_DART_OF_THE_ASSASSIN) obj->opoisoned = 1;
2063 if (launcher && obj && ammo_and_launcher(obj, launcher) && obj->otyp == POISON_BOLT) obj->opoisoned = 1;
2064 if (launcher && obj && ammo_and_launcher(obj, launcher) && obj->otyp == CHROME_PELLET) obj->opoisoned = 1;
2066 obj->was_thrown = 1;
2067 if (misfire && (u.dx || u.dy) ) {
2068 boolean slipok = TRUE;
2069 if (ammo_and_launcher(obj, launcher))
2070 pline("%s!", Tobjnam(obj, "misfire"));
2071 else {
2072 /* only slip if it's greased or meant to be thrown */
2073 /* Amy edit: well, the item is cursed, so it should malfunction no matter what. See monsters throwing
2074 * cursed potions, which also causes them to slip. */
2075 /*if (obj->greased || throwing_weapon(obj))*/
2076 /* BUG: this message is grammatically incorrect if obj has
2077 a plural name; greased gloves or boots for instance. */
2078 pline("%s as you throw it!", Tobjnam(obj, "slip"));
2079 /*else slipok = FALSE;*/
2081 if (slipok) {
2082 u.dx = rn2(3)-1;
2083 u.dy = rn2(3)-1;
2084 if (!u.dx && !u.dy) u.dz = 1;
2085 impaired = TRUE;
2089 if ((u.dx || u.dy || (u.dz < 1)) &&
2090 calc_capacity((int)obj->owt) > SLT_ENCUMBER &&
2091 (Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
2092 : (u.uhp < 10 && u.uhp != u.uhpmax)) &&
2093 obj->owt > (unsigned)((Upolyd ? u.mh : u.uhp) * 2) &&
2094 !Is_airlevel(&u.uz)) {
2095 You("have so little stamina, %s drops from your grasp.",
2096 the(xname(obj)));
2097 exercise(A_CON, FALSE);
2098 u.dx = u.dy = 0;
2099 u.dz = 1;
2102 thrownobj = obj;
2104 if (launcher && launcher->oartifact == ART_LEONE_M__GUAGE_SUPER) {
2105 nomul(-2, "suffering from M3 recoil", TRUE);
2107 if (launcher && launcher->oartifact == ART_MOSIN_NAGANT) {
2108 nomul(-3, "reloading the Mosin-Nagant", TRUE);
2110 if (obj && obj->otyp == JUMPING_FLAMER) {
2111 if (u.rangedreload < 3) u.rangedreload = 3;
2114 if(u.uswallow) {
2115 mon = u.ustuck;
2116 bhitpos.x = mon->mx;
2117 bhitpos.y = mon->my;
2118 } else if(u.dz) {
2119 if (u.dz < 0 && (Role_if(PM_VALKYRIE) || Role_if(PM_VANILLA_VALK)) &&
2120 (obj->oartifact == ART_MJOLLNIR || obj->oartifact == ART_OTHER_MJOLLNIR) && !impaired) {
2121 pline("%s the %s and returns to your hand!",
2122 Tobjnam(obj, "hit"), ceiling(u.ux,u.uy));
2123 obj = addinv(obj);
2124 (void) encumber_msg();
2125 setuwep(obj, TRUE, TRUE);
2126 u.twoweap = twoweap;
2127 return;
2129 if (u.dz < 0 && (Role_if(PM_JEDI) || Role_if(PM_SHADOW_JEDI) || Role_if(PM_HEDDERJEDI) || !rn2(2)) &&
2130 is_lightsaber(obj) && obj->lamplit && !impaired &&
2131 !(PlayerCannotUseSkills) && rn2(2) &&
2132 P_SKILL(weapon_type(obj)) >= P_SKILLED) {
2133 pline("%s the %s and returns to your hand!",
2134 Tobjnam(obj, "hit"), ceiling(u.ux,u.uy));
2135 obj = addinv(obj);
2136 (void) encumber_msg();
2137 setuwep(obj, TRUE, TRUE);
2138 u.twoweap = twoweap;
2139 return;
2141 /* [ALI]
2142 * Grenades are armed but are then processed by toss_up/hitfloor
2143 * as normal.
2145 * Bullets just disappear with no message.
2147 * Rockets hit the ceiling/floor and explode.
2149 else if (is_grenade(obj)) {
2150 arm_bomb(obj, TRUE);
2151 You("yell 'Fire in the hole!'");
2152 } else if (obj->oclass == VENOM_CLASS) {
2153 check_shop_obj(obj, u.ux, u.uy, TRUE);
2154 obfree(obj, (struct obj *)0);
2155 return;
2156 } else if (is_bullet(obj) && ammo_and_launcher(obj, launcher)) {
2157 if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !Underwater
2158 && (objects[obj->otyp].oc_dir & EXPLOSION)) {
2159 pline("%s hit%s the %s and explodes in a ball of fire!",
2160 Doname2(obj), (obj->quan == 1L) ? "s" : "",
2161 u.dz < 0 ? ceiling(u.ux, u.uy) : surface(u.ux, u.uy));
2162 explode(u.ux, u.uy, ZT_SPELL(ZT_FIRE), d(3, 8),
2163 WEAPON_CLASS, EXPL_FIERY);
2165 if (obj && obj->otyp == MINI_NUKE) fatman_explosion(u.ux, u.uy, obj);
2167 check_shop_obj(obj, u.ux, u.uy, TRUE);
2168 u.cnd_gunpowderused++; /* even if bulletreuse or lead bullets allows them to be used again --Amy */
2169 if (((!(tech_inuse(T_BULLETREUSE)) || rn2(3)) && !(Race_if(PM_VIETIS) && !rn2(3)) && !(obj->oartifact == ART_REUSEME && rn2(4)) && !(uarm && uarm->oartifact == ART_MG_RATTERING && (objects[obj->otyp].w_ammotyp == WP_BULLET_MG) ) && !(obj->oartifact == ART_EVERYTHING_GREENS_SO_GREEN) && !(obj->oartifact == ART_COMBAT_PELLET && rn2(10)) && !(objects[obj->otyp].oc_material == MT_LEAD && !rn2(2))) || (uarmf && uarmf->oartifact == ART_ANACONDA_HEELS) ) {
2170 obfree(obj, (struct obj *)0);
2171 return;
2174 if (u.dz < 0 && !Is_airlevel(&u.uz) &&
2175 !Underwater && !is_crystalwater(u.ux, u.uy) && !Is_waterlevel(&u.uz)) {
2176 (void) toss_up(obj, rn2(5));
2177 } else {
2178 hitfloor(obj);
2180 thrownobj = (struct obj*)0;
2181 return;
2183 } else if( (obj->otyp == BOOMERANG || obj->otyp == ALU_BOOMERANG || obj->otyp == SILVER_CHAKRAM || obj->otyp == BATARANG || obj->otyp == DARK_BATARANG) && !Underwater) {
2184 if(Is_airlevel(&u.uz) || Levitation)
2185 hurtle(-u.dx, -u.dy, 1, TRUE);
2186 mon = boomhit(u.dx, u.dy);
2187 if(mon == &youmonst) { /* the thing was caught */
2188 exercise(A_DEX, TRUE);
2189 obj = addinv(obj);
2190 (void) encumber_msg();
2191 if (wep_mask && !(obj->owornmask & wep_mask)) {
2192 setworn(obj, wep_mask);
2193 u.twoweap = twoweap;
2195 thrownobj = (struct obj*)0;
2196 return;
2198 } else {
2199 /* note to self by Amy: urange is not the range of the thrown thing - range is!!! */
2200 urange = (int)(ACURRSTR)/2;
2202 /* balls are easy to throw or at least roll */
2203 /* also, this insures the maximum range of a ball is greater
2204 * than 1, so the effects from throwing attached balls are
2205 * actually possible
2207 if (obj->oclass == BALL_CLASS)
2208 range = urange - (int)(obj->owt/600); /* thanks to the ball's weight being 2400 now */
2209 else
2210 range = urange - (int)(obj->owt/40);
2211 if (obj == uball) {
2212 if (u.ustuck) range = 1;
2213 else if (range >= 5) range = 5;
2215 if (range < 1) range = 1;
2217 /* KMH, balance patch -- new macros */
2218 if (is_ammo(obj)) {
2219 if ( (ammo_and_launcher(obj, launcher) && !(launcher && launcher->otyp == LASERXBOW && !launcher->lamplit) && !(launcher && launcher->otyp == KLIUSLING && !launcher->lamplit) ) ) {
2220 if (is_launcher(launcher) &&
2221 objects[(launcher->otyp)].oc_range)
2222 range = objects[(launcher->otyp)].oc_range;
2223 else
2224 range++;
2225 } else if (obj->oclass != GEM_CLASS)
2226 range /= 2;
2228 if (thrown == 666) range = 15;
2230 if (uarmh && uarmh->oartifact == ART_VIRUS_ATTACK) range += 2;
2231 if (launcher && ammo_and_launcher(obj, launcher) && launcher->otyp == SNIPESLING && obj) range += 5;
2232 if (launcher && ammo_and_launcher(obj, launcher) && launcher->otyp == BLUE_BOW && obj) range += 1;
2233 if (launcher && ammo_and_launcher(obj, launcher) && launcher->oartifact == ART_TSCHUEUU && obj) range += 10;
2234 if (launcher && (ammo_and_launcher(obj, launcher) && !(launcher && launcher->otyp == LASERXBOW && !launcher->lamplit) ) && obj && obj->otyp == ETHER_BOLT) range += 2;
2235 if (obj && obj->oartifact == ART_LONG_RANGE_BALLISTICS) range += 5;
2236 if (launcher && ammo_and_launcher(obj, launcher) && obj->oartifact == ART_SNIPESNIPESNIPE) range += 5;
2237 if (obj && obj->oartifact == ART_WAY_TOO_LONG) range += 10;
2238 if (launcher && ammo_and_launcher(obj, launcher) && obj->oartifact == ART_SAY__CHESS_) range += 2;
2239 if (obj && obj->oartifact == ART_PEWWWWWWW) range += 15;
2240 if (obj && obj->oartifact == ART_WIUNEW) range += 3;
2241 if (obj && obj->oartifact == ART_KLUEUEUEU) range += 5;
2242 if (obj && obj->oartifact == ART_GEHENNA_MODE && ( (Inhell && !Race_if(PM_HERETIC) ) || flags.gehenna ) ) range += 4;
2243 if (uwep && uwep->oartifact == ART_GEHENNA_MODE && ( (Inhell && !Race_if(PM_HERETIC) ) || flags.gehenna ) ) range += 3;
2245 if (!PlayerCannotUseSkills && launcher && ammo_and_launcher(obj, launcher) && launcher->otyp == KLIUSLING && launcher->lamplit) {
2246 if (u.kliuskill >= 20) range++;
2247 if (u.kliuskill >= 160) range++;
2248 if (u.kliuskill >= 540) range++;
2249 if (u.kliuskill >= 1280) range++;
2250 if (u.kliuskill >= 2500) range++;
2251 if (u.kliuskill >= 4320) range++;
2254 if (!PlayerCannotUseSkills && obj && obj->oartifact == ART_WEDIFORCE) {
2255 switch (P_SKILL(P_WEDI)) {
2256 case P_BASIC: range += 1; break;
2257 case P_SKILLED: range += 2; break;
2258 case P_EXPERT: range += 3; break;
2259 case P_MASTER: range += 4; break;
2260 case P_GRAND_MASTER: range += 5; break;
2261 case P_SUPREME_MASTER: range += 6; break;
2262 default: break;
2266 if (Race_if(PM_ENGCHIP) && launcher && objects[launcher->otyp].oc_skill == P_BOW) range += 2;
2267 if (Race_if(PM_ENGCHIP) && launcher && objects[launcher->otyp].oc_skill == P_CROSSBOW) range += 2;
2268 if (Race_if(PM_KORONST) && launcher && objects[launcher->otyp].oc_skill == P_SLING) range += 2;
2270 if (uarmg && uarmg->oartifact == ART_BEEEEEEEANPOLE && launcher && objects[launcher->otyp].oc_skill == P_BOW) range += 5;
2271 if (uwep && uwep->oartifact == ART_SNIPER_CROSSHAIR && launcher && objects[launcher->otyp].oc_skill == P_CROSSBOW) range += 30;
2272 if ((uarmc && itemhasappearance(uarmc, APP_CYANISM_CLOAK)) && launcher && objects[launcher->otyp].oc_skill == P_SLING) range += 3;
2273 if (launcher && launcher->oartifact == ART_ITALY_SI_ES) range += 4;
2274 if (launcher && launcher->oartifact == ART_MISS_LAUNCHER) range += 2;
2275 if (launcher && launcher->oartifact == ART_ACTUALLY_USABLE_GL) range += 6;
2276 if (obj && obj->oartifact == ART_MEGATON_LOAD) range += 10;
2277 if (obj && obj->oartifact == ART_A_MILE_AND_A_HALF) range += 25;
2278 if (obj && obj->oartifact == ART_LONG_MILE) range += 5;
2279 if (obj && obj->oartifact == ART_FLAI_AWEI) range += 10;
2280 if (obj && obj->oartifact == ART_NINJINGY) range += 2;
2281 if (obj && obj->oartifact == ART_FTS) range += 10;
2282 if (obj && obj->oartifact == ART_WASHINGTON_S_CAPPER) range += 5;
2283 if (uarmu && uarmu->oartifact == ART_NOW_YOU_MADE_HER_SAD) range += 2;
2285 if (obj && obj->oartifact == ART_RACER_PROJECTILE) range *= 2;
2287 if (launcher && launcher->oartifact == ART_ENEMY_DEAD_AT_CLOSE_RANGE) range--;
2289 if (Race_if(PM_GERTEUT) && range > 5) range = 5;
2290 if (Race_if(PM_PERVERT) && range > 2) range = 2;
2291 if (launcher && launcher->otyp == SHOVEL && range > 4) range = 4;
2292 if (launcher && launcher->oartifact == ART_OZYZEVPDWTVP) range -= 2;
2294 if (range < 1) range = 1; /* fail safe */
2296 if (Is_airlevel(&u.uz) || Levitation) {
2297 /* action, reaction... */
2298 urange -= range;
2299 if(urange < 1) urange = 1;
2300 range -= urange;
2301 if(range < 1) range = 1;
2304 if (obj->otyp == BOULDER)
2305 range = 20; /* you must be giant */
2306 else if (obj->oartifact == ART_MJOLLNIR || obj->oartifact == ART_OTHER_MJOLLNIR)
2307 range = (range + 1) / 2; /* it's heavy */
2308 else if (obj == uball && u.utrap && u.utraptype == TT_INFLOOR)
2309 range = 1;
2311 if (Underwater) range = 1;
2313 if (Race_if(PM_GERTEUT) && range > 5) range = 5;
2314 if (Race_if(PM_PERVERT) && range > 2) range = 2;
2316 if (range < 1) range = 1; /* fail safe */
2318 mon = bhit(u.dx,u.dy,range,THROWN_WEAPON,
2319 (int (*)(MONST_P,OBJ_P))0,
2320 (int (*)(OBJ_P,OBJ_P))0,
2321 &obj, TRUE);
2323 /* have to do this after bhit() so u.ux & u.uy are correct */
2324 if(Is_airlevel(&u.uz) || Levitation)
2325 hurtle(-u.dx, -u.dy, urange, TRUE);
2327 if (!obj) {
2328 thrownobj = (struct obj *)0;
2329 return;
2333 if(mon) {
2334 boolean obj_gone;
2336 if (mon->isshk &&
2337 obj->where == OBJ_MINVENT && obj->ocarry == mon) {
2338 thrownobj = (struct obj*)0;
2339 return; /* alert shk caught it */
2341 (void) snuff_candle(obj);
2342 notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my);
2343 obj_gone = thitmonst(mon, obj, thrown, FALSE);
2344 /* Monster may have been tamed; this frees old mon */
2345 mon = m_at(bhitpos.x, bhitpos.y);
2347 /* [perhaps this should be moved into thitmonst or hmon] */
2348 if (mon && mon->isshk &&
2349 (!inside_shop(u.ux, u.uy) ||
2350 !index(in_rooms(mon->mx, mon->my, SHOPBASE), *u.ushops)))
2351 hot_pursuit(mon);
2353 if (obj_gone) return;
2356 /* Handle grenades or rockets */
2357 if (is_grenade(obj)) {
2358 arm_bomb(obj, TRUE);
2359 You("yell 'Fire in the hole!'");
2360 } else if (ammo_and_launcher(obj, launcher) &&
2361 (objects[obj->otyp].oc_dir & EXPLOSION)) {
2362 if (cansee(bhitpos.x,bhitpos.y))
2363 pline("%s explodes in a ball of fire!", Doname2(obj));
2364 else You_hear("an explosion");
2365 explode(bhitpos.x, bhitpos.y, ZT_SPELL(ZT_FIRE),
2366 d(3,8), WEAPON_CLASS, EXPL_FIERY);
2368 if (obj && obj->otyp == MINI_NUKE) fatman_explosion(bhitpos.x, bhitpos.y, obj);
2371 if (obj->oclass == VENOM_CLASS) {
2372 check_shop_obj(obj, bhitpos.x,bhitpos.y, TRUE);
2373 obfree(obj, (struct obj *)0);
2374 return;
2377 if (is_bullet(obj) && (ammo_and_launcher(obj, launcher) && !is_grenade(obj))) {
2378 check_shop_obj(obj, bhitpos.x,bhitpos.y, TRUE);
2379 u.cnd_gunpowderused++; /* even if bulletreuse or lead bullets allows them to be used again --Amy */
2380 if (((!(tech_inuse(T_BULLETREUSE)) || rn2(3)) && !(Race_if(PM_VIETIS) && !rn2(3)) && !(obj->oartifact == ART_REUSEME && rn2(4)) && !(uarm && uarm->oartifact == ART_MG_RATTERING && (objects[obj->otyp].w_ammotyp == WP_BULLET_MG) ) && !(obj->oartifact == ART_EVERYTHING_GREENS_SO_GREEN) && !(obj->oartifact == ART_COMBAT_PELLET && rn2(10)) && !(objects[obj->otyp].oc_material == MT_LEAD && !rn2(2))) || (uarmf && uarmf->oartifact == ART_ANACONDA_HEELS) ) {
2381 obfree(obj, (struct obj *)0);
2382 return;
2386 int djemsochance = 0;
2388 if (!PlayerCannotUseSkills) {
2389 switch (P_SKILL(P_DJEM_SO)) {
2391 case P_BASIC: djemsochance = 1; break;
2392 case P_SKILLED: djemsochance = 2; break;
2393 case P_EXPERT: djemsochance = 4; break;
2394 case P_MASTER: djemsochance = 6; break;
2395 case P_GRAND_MASTER: djemsochance = 8; break;
2396 case P_SUPREME_MASTER: djemsochance = 9; break;
2397 default: djemsochance = 0; break;
2401 /* boomerang can come back, idea from dnethack, implementation by Amy (chance is less than 100%) */
2402 int boomerangchance = 20;
2404 if (!PlayerCannotUseSkills) {
2405 switch (P_SKILL(P_BOOMERANG)) {
2407 case P_BASIC: boomerangchance = 30; break;
2408 case P_SKILLED: boomerangchance = 35; break;
2409 case P_EXPERT: boomerangchance = 40; break;
2410 case P_MASTER: boomerangchance = 50; break;
2411 case P_GRAND_MASTER: boomerangchance = 60; break;
2412 case P_SUPREME_MASTER: boomerangchance = 70; break;
2413 default: boomerangchance = 20; break;
2416 switch (P_SKILL(P_DJEM_SO)) {
2418 case P_BASIC: boomerangchance += 2; break;
2419 case P_SKILLED: boomerangchance += 4; break;
2420 case P_EXPERT: boomerangchance += 6; break;
2421 case P_MASTER: boomerangchance += 8; break;
2422 case P_GRAND_MASTER: boomerangchance += 10; break;
2423 case P_SUPREME_MASTER: boomerangchance += 12; break;
2424 default: break;
2427 if (boomerangchance > 90) boomerangchance = 90; /* shouldn't happen */
2429 if (Race_if(PM_BATMAN)) { /* his batarang usually comes back --Amy */
2430 boomerangchance += ((100 - boomerangchance) / 2);
2434 if (u.uswallow) {
2435 /* ball is not picked up by monster */
2436 if (obj != uball) (void) mpickobj(u.ustuck,obj,FALSE);
2437 } else {
2438 /* the code following might become part of dropy() */
2439 if (
2440 (obj->oartifact == ART_MJOLLNIR && Role_if(PM_VALKYRIE) && rn2(100)) ||
2441 (obj->oartifact == ART_OTHER_MJOLLNIR && Role_if(PM_VALKYRIE) && rn2(100)) ||
2442 (obj->oartifact == ART_MJOLLNIR && Role_if(PM_VANILLA_VALK) && rn2(100)) ||
2443 (obj->oartifact == ART_OTHER_MJOLLNIR && Role_if(PM_VANILLA_VALK) && rn2(100)) ||
2445 (is_lightsaber(obj) && (obj->lamplit || Role_if(PM_SHADOW_JEDI)) && (rn2(2) || (djemsochance >= rn2(11)) ) &&
2446 ( ( (Role_if(PM_JEDI) || Role_if(PM_SHADOW_JEDI) || Role_if(PM_HEDDERJEDI)) && P_SKILL(weapon_type(obj)) > P_SKILLED) || (!rn2(2) && P_SKILL(weapon_type(obj)) > P_SKILLED) || (djemsochance >= rn2(11)) ) ) ||
2448 ((objects[obj->otyp].oc_skill == P_BOOMERANG || objects[obj->otyp].oc_skill == -P_BOOMERANG) &&
2449 ((boomerangchance > rn2(100)) || (obj->oartifact && !rn2(3)) ) )
2453 boolean boomerfix = (objects[obj->otyp].oc_skill == P_BOOMERANG || objects[obj->otyp].oc_skill == -P_BOOMERANG);
2455 /* we must be wearing Gauntlets of Power to get here */
2456 /* or a Jedi with a lightsaber or a thrown boomerang */
2457 if ( (Role_if(PM_JEDI) || Role_if(PM_SHADOW_JEDI) || Role_if(PM_HEDDERJEDI)) && u.uen < 5){
2458 You("don't have enough force to call %s. You need at least 5 points of mana!", the(xname(obj)));
2459 } else {
2460 if (Role_if(PM_JEDI) || Role_if(PM_SHADOW_JEDI) || Role_if(PM_HEDDERJEDI))
2461 u.uen -= 5;
2462 if (!boomerfix) sho_obj_return_to_u(obj); /* display its flight */
2464 /* djem so just trains so damn slowly... so here's an improvement --Amy */
2465 if (is_lightsaber(obj)) {
2466 use_skill(P_DJEM_SO, 1);
2467 if (obj->otyp == PINK_LIGHTSWORD || obj->otyp == PINK_DOUBLE_LIGHTSWORD) use_skill(P_DJEM_SO, 1);
2468 if (obj->oartifact == ART_ROSH_TRAINOR) use_skill(P_DJEM_SO, 1);
2471 if (!impaired && rn2(100)) {
2472 pline("%s to your hand!", Tobjnam(obj, "return"));
2473 if (is_lightsaber(obj)) mightbooststat(A_DEX);
2474 obj = addinv(obj);
2475 (void) encumber_msg();
2476 if (!boomerfix) {
2477 setuwep(obj, TRUE, TRUE);
2478 u.twoweap = twoweap;
2479 } else {
2480 setuqwep(obj);
2482 if(cansee(bhitpos.x, bhitpos.y))
2483 newsym(bhitpos.x,bhitpos.y);
2484 } else {
2485 int dmg = rn2(2);
2486 if (!dmg) {
2487 pline(Blind ? "%s lands %s your %s." :
2488 "%s back to you, landing %s your %s.",
2489 Blind ? Something : Tobjnam(obj, "return"),
2490 Levitation ? "beneath" : "at",
2491 makeplural(body_part(FOOT)));
2492 } else {
2493 dmg += rnd(3);
2494 pline(Blind ? "%s your %s!" :
2495 "%s back toward you, hitting your %s!",
2496 Tobjnam(obj, Blind ? "hit" : "fly"),
2497 body_part(ARM));
2498 (void) artifact_hit((struct monst *)0,
2499 &youmonst, obj, &dmg, 0);
2500 losehp(dmg, xname(obj),
2501 obj_is_pname(obj) ? KILLED_BY : KILLED_BY_AN);
2503 if (ship_object(obj, u.ux, u.uy, FALSE)) {
2504 thrownobj = (struct obj*)0;
2505 return;
2507 dropy(obj);
2509 thrownobj = (struct obj*)0;
2510 return;
2514 if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ) &&
2515 breaktest(obj)) {
2516 tmp_at(DISP_FLASH, obj_to_glyph(obj));
2517 tmp_at(bhitpos.x, bhitpos.y);
2518 delay_output();
2519 tmp_at(DISP_END, 0);
2520 breakmsg(obj, cansee(bhitpos.x, bhitpos.y));
2521 if (issegfaulter && obj->otyp == SEGFAULT_VENOM && !rn2(5)) { /* segfault panic! */
2522 u.segfaultpanic = TRUE;
2523 } else if (obj->oartifact == ART_DO_NOT_THROW_ME) { /* uh-oh... you really messed up big time there. */
2524 u.segfaultpanic = TRUE;
2526 breakobj(obj, bhitpos.x, bhitpos.y, TRUE, TRUE);
2527 return;
2529 if(flooreffects(obj,bhitpos.x,bhitpos.y,"fall")) return;
2530 obj_no_longer_held(obj);
2531 if (mon && mon->isshk && is_pick(obj)) {
2532 if (cansee(bhitpos.x, bhitpos.y))
2533 pline("%s snatches up %s.",
2534 Monnam(mon), the(xname(obj)));
2535 if(*u.ushops)
2536 check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
2537 (void) mpickobj(mon, obj, FALSE); /* may merge and free obj */
2538 thrownobj = (struct obj*)0;
2539 return;
2541 (void) snuff_candle(obj);
2542 if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) {
2543 thrownobj = (struct obj*)0;
2544 return;
2546 thrownobj = (struct obj*)0;
2547 place_object(obj, bhitpos.x, bhitpos.y);
2548 if(*u.ushops && obj != uball)
2549 check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
2551 stackobj(obj);
2552 if (obj == uball)
2553 drop_ball(bhitpos.x, bhitpos.y);
2554 if (cansee(bhitpos.x, bhitpos.y))
2555 newsym(bhitpos.x,bhitpos.y);
2556 if (obj_sheds_light(obj))
2557 vision_full_recalc = 1;
2558 if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ))
2559 container_impact_dmg(obj);
2563 /* an object may hit a monster; various factors adjust the chance of hitting */
2565 omon_adj(mon, obj, mon_notices)
2566 struct monst *mon;
2567 struct obj *obj;
2568 boolean mon_notices;
2570 int tmp = 0;
2572 /* size of target affects the chance of hitting */
2573 tmp += (mon->data->msize - MZ_MEDIUM); /* -2..+5 */
2574 /* sleeping target is more likely to be hit */
2575 if (mon->msleeping) {
2576 tmp += 2;
2577 if (mon_notices) mon->msleeping = 0;
2579 /* ditto for immobilized target */
2580 if (!mon->mcanmove || !mon->data->mmove) {
2581 tmp += 4;
2582 if (mon_notices && mon->data->mmove && !rn2(mon->masleep ? 3 : 10)) {
2583 mon->mcanmove = 1;
2584 mon->masleep = 0;
2585 mon->mfrozen = 0;
2588 /* some objects are more likely to hit than others */
2589 switch (obj->otyp) {
2590 case HEAVY_IRON_BALL:
2591 if (obj != uball) tmp += 2;
2592 break;
2593 case BOULDER:
2594 tmp += 6;
2595 if (!PlayerCannotUseSkills) {
2596 switch (P_SKILL(P_BOULDER_THROWING)) {
2597 default: break;
2598 case P_BASIC: tmp += 2; break;
2599 case P_SKILLED: tmp += 4; break;
2600 case P_EXPERT: tmp += 6; break;
2601 case P_MASTER: tmp += 8; break;
2602 case P_GRAND_MASTER: tmp += 10; break;
2603 case P_SUPREME_MASTER: tmp += 12; break;
2607 break;
2608 default:
2609 if (obj->oclass == WEAPON_CLASS || obj->oclass == BALL_CLASS || obj->oclass == CHAIN_CLASS || obj->oclass == VENOM_CLASS || is_weptool(obj) || obj->oclass == GEM_CLASS)
2610 tmp += hitval(obj, mon);
2611 break;
2613 return tmp;
2616 /* thrown object misses target monster */
2617 STATIC_OVL void
2618 tmiss(obj, mon)
2619 struct obj *obj;
2620 struct monst *mon;
2622 const char *missile = mshot_xname(obj);
2624 /* If the target can't be seen or doesn't look like a valid target,
2625 avoid "the arrow misses it," or worse, "the arrows misses the mimic."
2626 An attentive player will still notice that this is different from
2627 an arrow just landing short of any target (no message in that case),
2628 so will realize that there is a valid target here anyway. */
2629 if (!canseemon(mon) || (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER))
2630 pline("%s %s.", The(missile), otense(obj, "miss"));
2631 else
2632 miss(missile, mon);
2633 if (!rn2(3)) wakeup(mon);
2635 if ( (autismweaponcheck(ART_CANNONDANCER)) && multi >= 0) {
2636 if (isstunfish) nomul(-(rnz(10)), "having missed the beat", TRUE);
2637 else nomul(-(rn1(5,5)), "having missed the beat", TRUE);
2641 return;
2644 #define quest_arti_hits_leader(obj,mon) \
2645 (obj->oartifact && is_quest_artifact(obj) && (mon->data->msound == MS_LEADER))
2648 * Object thrown by player arrives at monster's location.
2649 * Return 1 if obj has disappeared or otherwise been taken care of,
2650 * 0 if caller must take care of it.
2653 thitmonst(mon, obj, thrown, polearming)
2654 register struct monst *mon;
2655 register struct obj *obj;
2656 int thrown;
2657 boolean polearming;
2659 register int tmp; /* Base chance to hit */
2660 register int disttmp; /* distance modifier */
2661 struct obj *launcher;
2662 register struct obj *blocker = (struct obj *)0;
2663 boolean doubleshot = FALSE; /* are you dual-wielding and firing with the secondary weapon as well? */
2665 int skillpierce; /* with high skill, you can hit monsters that would normally have dodged --Amy */
2667 int otyp = obj->otyp;
2668 boolean guaranteed_hit = (u.uswallow && mon == u.ustuck && rn2(3));
2669 int dieroll = rnd(20);
2671 boolean stupidrock = 0;
2672 if (obj->otyp == ROCK) stupidrock = 1;
2674 boolean bulletate = 0;
2675 if (objects[obj->otyp].oc_skill == P_FIREARM || objects[obj->otyp].oc_skill == -P_FIREARM) bulletate = 1;
2677 boolean pieks = 0;
2678 if (objects[obj->otyp].oc_skill == P_POLEARMS) pieks = 1;
2679 if (objects[obj->otyp].oc_skill == P_LANCE) pieks = 1;
2680 if (obj->otyp == GRAPPLING_HOOK) pieks = 1;
2681 if (obj->otyp == LAJATANG) pieks = 1;
2682 if (obj->otyp == JACK_KNIFE) pieks = 1;
2683 boolean stopevading = 0;
2684 if (obj->oartifact == ART_STOP_EVADING_ME) stopevading = 1;
2686 register int shieldblockrate = 0;
2688 /* Differences from melee weapons:
2690 * Dex still gives a bonus, but strength does not.
2691 * Polymorphed players lacking attacks may still throw.
2692 * There's a base -1 to hit.
2693 * No bonuses for fleeing or stunned targets (they don't dodge
2694 * melee blows as readily, but dodging arrows is hard anyway).
2695 * Not affected by traps, etc.
2696 * Certain items which don't in themselves do damage ignore tmp.
2697 * Distance and monster size affect chance to hit.
2699 /* KMH -- added ring of increase accuracy */
2701 if (thrown == 1) launcher = uwep;
2702 else if (thrown == 2) launcher = uswapwep;
2703 else if (thrown == 666) { /* inbuilt pistol boots */
2704 if (uarmf && itemhasappearance(uarmf, APP_PISTOL_BOOTS) ) launcher = uarmf;
2706 else launcher = (struct obj *)0;
2708 if (u.twoweap && uswapwep && launcher && (uswapwep == launcher)) doubleshot = TRUE;
2710 boolean gunused = 0;
2711 if (launcher && ammo_and_launcher(obj, launcher) && objects[launcher->otyp].oc_skill == P_FIREARM) gunused = 1;
2713 tmp = -1 + ( (!rn2(3) && Luck > 0) ? rnd(Luck) : Luck) + find_mac(mon) + ((increase_accuracy_bonus_value() > 1) ? rnd(increase_accuracy_bonus_value()) : increase_accuracy_bonus_value()) +
2714 (!rn2(3) ? (maybe_polyd(rnd(youmonst.data->mlevel + 1), rnd(GushLevel))) : (maybe_polyd(youmonst.data->mlevel + 1, GushLevel)) );
2716 /* early-game bonuses to make starting characters not suck too badly --Amy */
2717 if (u.ulevel < 6) tmp += 1;
2718 if (u.ulevel < 4) tmp += 1; /* because abon() somehow doesn't get factored in */
2719 if (u.ulevel < 2) tmp += 1;
2720 if (u.ulevel < 5 && rn2(2)) tmp += 1;
2721 if (u.ulevel < 3 && rn2(2)) tmp += 1;
2723 if (GushLevel > 5) tmp += 1;
2724 if (GushLevel > 9) tmp += 1;
2725 if (GushLevel > 12) tmp += 1;
2726 if (GushLevel > 15) tmp += 1;
2727 if (GushLevel > 19) tmp += 1;
2728 if (GushLevel > 23) tmp += 1;
2729 if (GushLevel > 26) tmp += 1;
2730 if (GushLevel > 29) tmp += 1;
2732 if (!issoviet && !rn2(3)) tmp += rno(GushLevel);
2734 if (uarmh && uarmh->oartifact == ART_REMOTE_GAMBLE) tmp += 2;
2735 if (uarm && uarm->oartifact == ART_MOTHERFUCKER_TROPHY) tmp += 5;
2736 if (u.tiksrvzllatdown) tmp += 5;
2738 if (Race_if(PM_GERTEUT)) tmp += 5;
2740 if (obj && obj->otyp == LASER_FLYAXE && obj->lamplit) tmp += 5;
2741 if (obj && obj->otyp == DISKOS) tmp += 5;
2742 if (obj && obj->otyp == TOMAHAWK) tmp += 5;
2743 if (obj && obj->oartifact == ART_LONG_RANGE_BALLISTICS) tmp += 10;
2745 if (uarmh && uarmh->oartifact == ART_B_A_L_L_A_S && gunused) tmp += 3;
2747 if (uarmf && uarmf->oartifact == ART_WE_ARE__TRANNIES && gunused) tmp += rnd(10);
2749 if (uarmg && itemhasappearance(uarmg, APP_UNCANNY_GLOVES)) tmp += 1;
2750 if (uarmg && itemhasappearance(uarmg, APP_SLAYING_GLOVES)) tmp += 1;
2751 if (uarmg && itemhasappearance(uarmg, APP_SUREFIRE_GLOVES)) tmp += 2;
2752 if (uarmg && uarmg->otyp == GAUNTLETS_OF_TRUE_AIM) {
2753 tmp += 2;
2754 if (uarmg->spe > 0) tmp += uarmg->spe;
2757 if (uarmh && uarmh->oartifact == ART_IRON_HELM_OF_GORLIM) tmp += 10;
2758 if (uarmh && uarmh->oartifact == ART_SUDUNSEL) tmp += 2;
2759 if (uarm && uarm->otyp == DARK_DRAGON_SCALES) tmp += 1;
2760 if (uarm && uarm->otyp == DARK_DRAGON_SCALE_MAIL) tmp += 1;
2761 if (uarms && uarms->otyp == DARK_DRAGON_SCALE_SHIELD) tmp += 1;
2762 if (uarmg && uarmg->oartifact == ART_FLOEMMELFLOEMMELFLOEMMELFL) tmp += 1;
2763 if (uarmf && uarmf->oartifact == ART_MELISSA_S_BEAUTY) tmp += 5;
2764 if (uarmf && uarmf->oartifact == ART_MAY_BRITT_S_ADULTHOOD) tmp -= 2;
2765 if (uwep && uwep->oartifact == ART_WILD_HEAVY_SWINGS) tmp -= 10;
2766 if (uwep && uwep->oartifact == ART_RAFSCHAR_S_SUPERWEAPON) tmp += 1;
2767 if (uarmc && uarmc->oartifact == ART_ENEMIES_SHALL_LAUGH_TOO) tmp += 10;
2768 if (uimplant && uimplant->oartifact == ART_ACTUAL_PRECISION) tmp += 5;
2769 if (uimplant && uimplant->oartifact == ART_RHEA_S_MISSING_EYESIGHT) tmp -= rnd(20);
2770 if (uwep && uwep->oartifact == ART_SIGIX_BROADSWORD) tmp -= 5;
2771 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_SIGIX_BROADSWORD) tmp -= 5;
2772 if (powerfulimplants() && uimplant && uimplant->oartifact == ART_ACTUAL_PRECISION) tmp += 5;
2773 if (uleft && uleft->oartifact == ART_BLIND_PILOT) tmp -= 10;
2774 if (uright && uright->oartifact == ART_BLIND_PILOT) tmp -= 10;
2775 if (Role_if(PM_ARCHEOLOGIST) && uamul && uamul->oartifact == ART_ARCHEOLOGIST_SONG) tmp += 2;
2776 if (u.boosttimer) tmp += 5;
2777 if (ublindf && ublindf->oartifact == ART_EYEHANDER) tmp += 5;
2778 if (uarmg && uarmg->oartifact == ART_SOFT_TO_THE_TOUCH) tmp += 5;
2779 if (uwep && uwep->oartifact == ART_JUSTICE_FOR_GARLIC) tmp += 5;
2780 if (uwep && uwep->oartifact == ART_ATOMIC_MISSING) tmp -= 20;
2781 if (uarmg && uarmg->oartifact == ART_SI_OH_WEE) tmp += 2;
2782 if (uimplant && uimplant->oartifact == ART_SOME_LITTLE_AID) tmp += 1;
2783 if (uwep && uwep->oartifact == ART_RIP_STRATEGY) tmp -= 5;
2784 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_RIP_STRATEGY) tmp -= 5;
2785 if (uarmf && uarmf->oartifact == ART_CRASHING_YOUR_SISTER_S_WED) tmp -= 5;
2786 if (uarmf && uarmf->oartifact == ART_CAT_ROCKZ) tmp += 5;
2787 if (Race_if(PM_SERB)) tmp += 1;
2788 if (uarmg && uarmg->oartifact == ART_MAJOR_PRESENCE) tmp += 2;
2789 if (uwep && uwep->oartifact == ART_SINSWORD && u.ualign.record < 0) tmp += 1;
2790 if (uwep && uwep->oartifact == ART_SINSWORD && u.ualign.record < 49) tmp += 1;
2791 if (uwep && uwep->oartifact == ART_SINSWORD && u.ualign.record < 99) tmp += 1;
2792 if (uwep && uwep->oartifact == ART_SINSWORD && u.ualign.record < 149) tmp += 1;
2793 if (uwep && uwep->oartifact == ART_SINSWORD && u.ualign.record < 199) tmp += 1;
2794 if (uwep && uwep->oartifact == ART_SINSWORD && u.ualign.record < 249) tmp += 1;
2795 if (StrongBlind_resistance) tmp += rn1(5, 5);
2796 if (uarmh && uarmh->oartifact == ART_WAITING_FOR_MELEE) tmp -= 2;
2797 if (bmwride(ART_KERSTIN_S_COWBOY_BOOST)) tmp += 2;
2798 if (uwep && uwep->oartifact == ART_VLADSBANE) tmp -= 5;
2799 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_VLADSBANE) tmp -= 5;
2800 if (uwep && uwep->oartifact == ART_CHARGING_MADE_EASY) tmp -= 5;
2801 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_CHARGING_MADE_EASY) tmp -= 5;
2802 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_DUAL_MASTERY) tmp += 5;
2803 if (uwep && uwep->oartifact == ART_SPINESHOOTER) tmp += 5;
2804 if (uarmf && uarmf->oartifact == ART_PROPERTY_GRUMBLE) tmp -= 5;
2805 if (uarmg && uarmg->oartifact == ART_UNKNOWINGNESS_AS_A_WEAPON && !(objects[uarmg->otyp].oc_name_known)) tmp += 5;
2806 if (uwep && uwep->oartifact == ART_FALCO_S_ORB) tmp += 1;
2807 if (uwep && uwep->oartifact == ART_VERY_SPECIFICNESS) tmp += 1;
2808 if (uarmg && uarmg->oartifact == ART_PLUS_TO_HIT) tmp += 5;
2809 if (uarmh && uarmh->oartifact == ART_BE_THE_LITE) tmp += 1;
2810 if (uarms && uarms->oartifact == ART_RONDITSCH) tmp += 1;
2811 if (powerfulimplants() && uimplant && uimplant->oartifact == ART_NIOBE_S_ANGER) tmp += 4;
2812 if (obj && objects[obj->otyp].oc_material == MT_ADAMANTIUM) tmp += 2;
2813 if (uimplant && uimplant->oartifact == ART_I_M_GONNA_CRUSH_YA_) tmp += 4;
2814 if (bmwride(ART_ZIN_BA)) tmp += 4;
2815 if (obj && obj->oartifact == ART_BLOHIT) tmp += 10;
2816 if (obj && obj->oartifact == ART_KLUEUEUEU) tmp += 1000;
2817 if (uarm && uarm->oartifact == ART_I_AM_YOUR_FALL) tmp += 10;
2818 if (uarmg && uarmg->oartifact == ART_GET_THE_OLD_VALUES_BACK) tmp += 3;
2819 if (uleft && uleft->oartifact == ART_CERBERUS_BAND) tmp += 3;
2820 if (uright && uright->oartifact == ART_CERBERUS_BAND) tmp += 3;
2821 if (uleft && uleft->oartifact == ART_CHERRYTAPPER) tmp += 10;
2822 if (uright && uright->oartifact == ART_CHERRYTAPPER) tmp += 10;
2823 if (uarmc && uarmc->oartifact == ART_ISHITA_S_OVERWHELMING) tmp += 5;
2824 if (uarmg && uarmg->oartifact == ART_DOCHGOGRAP) tmp += 4;
2825 if (u.ulevel >= 8) tmp++;
2826 if (u.ulevel >= 16) tmp++;
2827 if (u.ulevel >= 24) tmp++;
2828 if (u.ulevel >= 30) tmp++;
2830 if (uleft && uleft->oartifact == ART_KRATSCHEM_HARD) tmp += 3;
2831 if (uright && uright->oartifact == ART_KRATSCHEM_HARD) tmp += 3;
2833 if (PlayerInWedgeHeels && !PlayerCannotUseSkills) {
2834 switch (P_SKILL(P_WEDGE_HEELS)) {
2835 default: break;
2836 case P_BASIC: tmp += 1; break;
2837 case P_SKILLED: tmp += 2; break;
2838 case P_EXPERT: tmp += 3; break;
2839 case P_MASTER: tmp += 4; break;
2840 case P_GRAND_MASTER: tmp += 5; break;
2841 case P_SUPREME_MASTER: tmp += 6; break;
2845 if (uwep && uwep->oartifact == ART_AK_____) {
2846 if (!PlayerCannotUseSkills) {
2847 if (P_SKILL(P_FIREARM) < P_BASIC) tmp += 6;
2848 else if (P_SKILL(P_FIREARM) == P_BASIC) tmp += 4;
2849 else if (P_SKILL(P_FIREARM) == P_SKILLED) tmp += 2;
2851 if (P_SKILL(P_FIREARM) == P_MASTER) tmp -= 2;
2852 if (P_SKILL(P_FIREARM) == P_GRAND_MASTER) tmp -= 4;
2853 if (P_SKILL(P_FIREARM) == P_SUPREME_MASTER) tmp -= 6;
2855 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_AK_____) {
2856 if (P_SKILL(P_FIREARM) == P_MASTER) tmp -= 2;
2857 if (P_SKILL(P_FIREARM) == P_GRAND_MASTER) tmp -= 4;
2858 if (P_SKILL(P_FIREARM) == P_SUPREME_MASTER) tmp -= 6;
2861 if (obj && obj->oartifact == ART_WASHINGTON_S_CAPPER) tmp -= 5;
2862 if (uwep && uwep->oartifact == ART_LONGLOSS) tmp -= rnd(10);
2863 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_LONGLOSS) tmp -= rnd(10);
2864 if (uwep && uwep->oartifact == ART_ENEMY_DEAD_AT_CLOSE_RANGE) tmp -= 10;
2865 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_ENEMY_DEAD_AT_CLOSE_RANGE) tmp -= 10;
2866 if (uwep && uwep->oartifact == ART_ITALY_SI_ES) tmp -= rnd(25);
2867 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_ITALY_SI_ES) tmp -= rnd(25);
2868 if (uarmc && uarmc->oartifact == ART_OLD_PERSON_TALK) tmp -= 5;
2869 if (uwep && uwep->oartifact == ART_BLACK_MARK) tmp -= 1;
2870 if (uwep && uwep->oartifact == ART_LOUD_SHITTER) tmp -= 7;
2871 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_LOUD_SHITTER) tmp -= 7;
2872 if (uwep && uwep->oartifact == ART_CHINESE_MODEL) tmp -= 5;
2873 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_CHINESE_MODEL) tmp -= 5;
2874 if (uwep && uwep->oartifact == ART_XUANLONG) tmp -= 5;
2875 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_XUANLONG) tmp -= 5;
2876 if (uarm && uarm->oartifact == ART_POWASPEL) tmp -= 3;
2877 if (uwep && uwep->oartifact == ART_UZ_I) tmp -= rnd(10);
2878 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_UZ_I) tmp -= rnd(10);
2879 if (uwep && uwep->oartifact == ART_AR_ARMALYTE) tmp -= 2;
2880 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_AR_ARMALYTE) tmp -= 2;
2881 if (u.martialstyle == MARTIALSTYLE_MUAYTHAI) tmp -= 5;
2883 if (uarm && uarm->oartifact == ART_DAMMIT_PICK_UP) tmp -= 5;
2885 if (Role_if(PM_OTAKU) && uarmc && itemhasappearance(uarmc, APP_FOURCHAN_CLOAK)) tmp += 1;
2887 if (is_grassland(u.ux, u.uy) && !(uarm && uarm->oartifact == ART_DORL_TSCH) && !(uarmf && itemhasappearance(uarmf, APP_GARDEN_SLIPPERS))) tmp -= rnd(5);
2889 if (ACURR(A_DEX) < 2) tmp -= 5;
2890 else if (ACURR(A_DEX) < 3) tmp -= 4;
2891 else if (ACURR(A_DEX) < 4) tmp -= 3;
2892 else if (ACURR(A_DEX) < 6) tmp -= 2;
2893 else if (ACURR(A_DEX) < 8) tmp -= 1;
2894 else if (ACURR(A_DEX) >= 12) tmp += (ACURR(A_DEX) - 11);
2896 if (tech_inuse(T_STEADY_HAND)) tmp += 5;
2898 if (uarmc && uarmc->oartifact == ART_ROKKO_CHAN_S_SUIT) tmp += 5;
2900 if (!issoviet && !rn2(20 - (GushLevel / 2) )) tmp += rnd(GushLevel);
2902 if (Race_if(PM_ENGCHIP) && objects[obj->otyp].oc_skill == P_BOW) tmp -= 5;
2903 if (Race_if(PM_ENGCHIP) && objects[obj->otyp].oc_skill == -P_BOW) tmp -= 5;
2904 if (Race_if(PM_ENGCHIP) && objects[obj->otyp].oc_skill == P_CROSSBOW) tmp -= 5;
2905 if (Race_if(PM_ENGCHIP) && objects[obj->otyp].oc_skill == -P_BOW) tmp -= 5;
2906 if (uwep && uwep->oartifact == ART_KLOBB) tmp -= 6;
2907 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_KLOBB) tmp -= 6;
2908 if (uwep && uwep->oartifact == ART_EXCALIPOOR) tmp -= 9;
2909 if (u.twoweap && uswapwep && uswapwep->oartifact == ART_EXCALIPOOR) tmp -= 9;
2911 if (Race_if(PM_VIETIS) && objects[obj->otyp].oc_skill != -P_FIREARM && objects[obj->otyp].oc_skill != P_FIREARM) tmp -= rnd(10);
2913 if (Race_if(PM_BOVER)) {
2914 if (uarm && is_metallic(uarm)) tmp -= rnd(3);
2915 if (uarmu && is_metallic(uarmu)) tmp -= rnd(3);
2916 if (uarmc && is_metallic(uarmc)) tmp -= rnd(3);
2917 if (uarms && is_metallic(uarms)) tmp -= rnd(3);
2918 if (uarmh && is_metallic(uarmh)) tmp -= rnd(3);
2919 if (uarmg && is_metallic(uarmg)) tmp -= rnd(3);
2920 if (uarmf && is_metallic(uarmf)) tmp -= rnd(3);
2923 /* shooters that have innate to-hit penalty for the player go here; if you're dual-wielding two launchers
2924 * that use the same type of ammo, and the secondary one has such a penalty, it's supposed to be much higher
2925 * than if it was the primary launcher, for balance purposes, since otherwise dual-wielding assault rifles
2926 * would be far better in every way than a heavy MG! --Amy
2927 * annoyingly, nozzle change (artifact lead unloader) has already changed its fire mode at this point... */
2929 inaccurateguns:
2930 if (launcher && launcher->otyp == HYDRA_BOW) tmp -= rnd(8);
2931 if (launcher && launcher->otyp == WILDHILD_BOW && !Role_if(PM_HUSSY)) tmp -= rnd(10);
2932 if (launcher && launcher->otyp == CATAPULT) {
2933 tmp -= rnd(10);
2934 if (!rn2(2)) tmp -= rnd(10);
2936 if (launcher && launcher->otyp == SUBMACHINE_GUN && launcher->altmode == WP_MODE_AUTO) tmp -= rnd(6);
2937 if (launcher && launcher->otyp == LEAD_UNLOADER && launcher->altmode == WP_MODE_AUTO) tmp -= rnd(6);
2938 if (launcher && launcher->oartifact == ART_NOZZLE_CHANGE && launcher->altmode == WP_MODE_SINGLE) tmp -= rnd(6);
2939 if (launcher && launcher->otyp == AUTO_SHOTGUN && launcher->altmode == WP_MODE_AUTO) tmp -= rnd(8);
2940 if (launcher && launcher->otyp == POWER_CROSSBOW) tmp -= rnd(8);
2941 if (launcher && launcher->otyp == PILE_BUNKER) tmp -= rnd(4);
2942 if (launcher && launcher->otyp == ASSAULT_RIFLE && (launcher->altmode == WP_MODE_AUTO || (launcher->altmode == WP_MODE_BURST && !rn2(3)) ) ) {
2943 tmp -= rnd(8);
2944 if (!rn2(3)) tmp -= rnd(5);
2946 if (launcher && launcher->otyp == STORM_RIFLE && (launcher->altmode == WP_MODE_AUTO || (launcher->altmode == WP_MODE_BURST && !rn2(3)) ) ) {
2947 tmp -= rnd(8);
2948 if (!rn2(3)) tmp -= rnd(5);
2950 if (launcher && launcher->otyp == ARM_BLASTER) {
2951 tmp -= rnd(10);
2952 if (!rn2(2)) tmp -= rnd(8);
2954 if (launcher && launcher->otyp == DEMON_CROSSBOW && launcher->altmode == WP_MODE_AUTO) {
2955 tmp -= rnd(20);
2956 if (!rn2(2)) tmp -= rnd(6);
2958 if (launcher && launcher->otyp == KALASHNIKOV && (launcher->altmode == WP_MODE_AUTO || (launcher->altmode == WP_MODE_BURST && !rn2(3)) ) ) {
2959 tmp -= rnd(9);
2960 if (!rn2(2)) tmp -= rnd(5);
2962 if (launcher && launcher->otyp == HEAVY_MACHINE_GUN) {
2963 tmp -= rnd(20);
2964 if (!rn2(2)) tmp -= rnd(10);
2965 if (!rn2(3)) tmp -= rnd(10);
2967 if (launcher && launcher->otyp == PISTOL_PAIR && P_RESTRICTED(P_TWO_WEAPON_COMBAT)) {
2968 tmp -= rnd(20);
2971 if (launcher && launcher->oartifact == ART_FN_M____PARA) tmp -= rnd(15);
2972 if (launcher && launcher->oartifact == ART_CITYKILLER_COMBAT_SHOTGUN) tmp -= rnd(10);
2973 if (launcher && launcher->oartifact == ART_COLONEL_BASTARD_S_LASER_PI) tmp -= rnd(5);
2975 if (doubleshot) {
2976 if (!rn2(2)) doubleshot = FALSE;
2977 goto inaccurateguns;
2980 if (Race_if(PM_SWIKNI)) {
2981 if (obj) {
2982 if (obj->oeroded) tmp -= ((obj->oeroded) * 2);
2983 if (obj->oeroded2) tmp -= ((obj->oeroded2) * 2);
2988 if (tech_inuse(T_UNARMED_FOCUS)) tmp -= rnd(20);
2989 if (u.martialstyle == MARTIALSTYLE_KUNGFU) tmp -= rnd(20);
2991 /* quarterback is highly skilled at shooting small round objects --Amy */
2992 if (Role_if(PM_QUARTERBACK) && objects[obj->otyp].oc_skill == -P_SLING) tmp += rn1(5, 5);
2993 if (Role_if(PM_QUARTERBACK) && objects[obj->otyp].oc_skill == P_SLING) tmp += rn1(5, 5);
2995 /* let's just add that bonus anyway. --Amy */
2996 if(mon->mstun) tmp += 2;
2997 if(mon->mflee) tmp += 2;
2998 if(mon->msleeping) tmp += 2;
2999 if(!mon->mcanmove) tmp += 4;
3001 /* Missile weapon skill: without it, you generally have a lower to-hit; with it, you eventually gain positive bonuses --Amy */
3002 tmp -= rn2(5);
3003 skillpierce = 0;
3004 if (!(PlayerCannotUseSkills)) {
3005 switch (P_SKILL(P_MISSILE_WEAPONS)) {
3006 default: break;
3007 case P_BASIC: tmp += rnd(2); skillpierce += 1; break;
3008 case P_SKILLED: tmp += rnd(3); skillpierce += 2; break;
3009 case P_EXPERT: tmp += rnd(5); skillpierce += 3; break;
3010 case P_MASTER: tmp += rnd(6); skillpierce += 4; break;
3011 case P_GRAND_MASTER: tmp += rnd(8); skillpierce += 5; break;
3012 case P_SUPREME_MASTER: tmp += rnd(10); skillpierce += 6; break;
3015 if (obj && objects[obj->otyp].oc_skill == -P_FIREARM) {
3016 switch (P_SKILL(P_GUN_CONTROL)) {
3017 default: break;
3018 case P_BASIC: tmp += rnd(2); skillpierce += 1; break;
3019 case P_SKILLED: tmp += rnd(4); skillpierce += 2; break;
3020 case P_EXPERT: tmp += rnd(6); skillpierce += 3; break;
3021 case P_MASTER: tmp += rnd(8); skillpierce += 4; break;
3022 case P_GRAND_MASTER: tmp += rnd(10); skillpierce += 5; break;
3023 case P_SUPREME_MASTER: tmp += rnd(12); skillpierce += 6; break;
3027 switch (P_SKILL(P_DJEM_SO)) {
3028 default: break;
3029 case P_BASIC: tmp += 1; break;
3030 case P_SKILLED: tmp += rnd(2); break;
3031 case P_EXPERT: tmp += rnd(3); break;
3032 case P_MASTER: tmp += rnd(4); break;
3033 case P_GRAND_MASTER: tmp += rnd(5); break;
3034 case P_SUPREME_MASTER: tmp += rnd(6); break;
3037 /* shien and djem so are both "form V" so they boost each other --Amy
3038 * reduced monster evasiveness if you've enhanced both */
3039 if (obj && is_lightsaber(obj) && (obj->lamplit || Role_if(PM_SHADOW_JEDI)) ) {
3040 if (P_SKILL(P_SHIEN) >= P_BASIC && P_SKILL(P_DJEM_SO) >= P_BASIC) skillpierce++;
3041 if (P_SKILL(P_SHIEN) >= P_SKILLED && P_SKILL(P_DJEM_SO) >= P_SKILLED) skillpierce++;
3042 if (P_SKILL(P_SHIEN) >= P_EXPERT && P_SKILL(P_DJEM_SO) >= P_EXPERT) skillpierce++;
3043 if (P_SKILL(P_SHIEN) >= P_MASTER && P_SKILL(P_DJEM_SO) >= P_MASTER) skillpierce++;
3044 if (P_SKILL(P_SHIEN) >= P_GRAND_MASTER && P_SKILL(P_DJEM_SO) >= P_GRAND_MASTER) skillpierce++;
3045 if (P_SKILL(P_SHIEN) >= P_SUPREME_MASTER && P_SKILL(P_DJEM_SO) >= P_SUPREME_MASTER) skillpierce++;
3048 /* polearms and such should get to-hit bonuses from general combat as well, because I want it :D --Amy */
3049 if (pieks) {
3051 switch (P_SKILL(P_GENERAL_COMBAT)) {
3052 default: break;
3053 case P_BASIC: tmp += 1; skillpierce += 1; break;
3054 case P_SKILLED: tmp += rnd(2); skillpierce += 2; break;
3055 case P_EXPERT: tmp += rnd(3); skillpierce += 3; break;
3056 case P_MASTER: tmp += rnd(4); skillpierce += 4; break;
3057 case P_GRAND_MASTER: tmp += rnd(5); skillpierce += 5; break;
3058 case P_SUPREME_MASTER: tmp += rnd(6); skillpierce += 6; break;
3065 if (uwep && uwep->oartifact == ART_ULTRA_ANNOYANCE && pieks) skillpierce += 5;
3067 if (stopevading) skillpierce += rnd(5);
3069 if (Race_if(PM_FRO) && objects[obj->otyp].oc_skill == P_AXE) {
3070 tmp += 5;
3073 if (Numbed) {
3074 if (tmp > 1) {
3075 tmp *= 9;
3076 tmp /= 10;
3078 tmp -= 2;
3081 if (u.tremblingamount) tmp -= rnd(u.tremblingamount);
3083 if (!rn2(20)) tmp -= 20; /* catastrophic failure on a "natural 20", similar to D&D --Amy */
3084 if (Race_if(PM_INHERITOR) && !rn2(100)) tmp -= 20;
3086 if (Role_if(PM_FAILED_EXISTENCE) && rn2(2)) tmp = -100; /* 50% chance of automiss --Amy */
3087 if (uarmc && uarmc->oartifact == ART_ARTIFICIAL_FAKE_DIFFICULTY && !rn2(6)) tmp = -100;
3089 if (obj && obj->oartifact == ART_EVASION_BREAK) goto evasionchancedone;
3091 /* certain monsters are capable of deflecting projectiles --Amy */
3093 if (!pieks && !(gunused && rn2(3)) && !(rn2(13) < skillpierce ) ) {
3095 if (verysmall(mon->data) && !rn2(4)) {
3096 tmp = -100;
3097 pline("%s avoids the projectile!", Monnam(mon));
3099 if (rathersmall(mon->data) && !(verysmall(mon->data)) && !rn2(10)) {
3100 tmp = -100;
3101 pline("%s avoids the projectile!", Monnam(mon));
3103 if (hugemonst(mon->data) && !rn2(2) && (mon->m_lev > rnd(GushLevel) ) ) {
3104 tmp = -100;
3105 pline("%s shrugs off the projectile!", Monnam(mon));
3107 if (bigmonst(mon->data) && !(hugemonst(mon->data)) && !rn2(5) && (mon->m_lev > rnd(GushLevel) ) ) {
3108 tmp = -100;
3109 pline("%s shrugs off the projectile!", Monnam(mon));
3114 /* certain traits also allow monsters to avoid getting hit */
3116 if (amorphous(mon->data) && !rn2(5) && tmp > -50 && !(rn2(20) < skillpierce ) ) {
3117 tmp = -100;
3118 pline("%s's amorphous body skillfully dodges the projectile!", Monnam(mon));
3120 if (noncorporeal(mon->data) && rn2(3) && tmp > -50 && !(rn2(40) < skillpierce ) ) {
3121 tmp = -100;
3122 pline("%s easily avoids the projectile due to being noncorporeal!", Monnam(mon));
3124 if (unsolid(mon->data) && !rn2(4) && tmp > -50 && !(rn2(20) < skillpierce ) ) {
3125 tmp = -100;
3126 pline("%s's unsolid body lets the projectile pass through harmlessly!", Monnam(mon));
3129 evasionchancedone:
3131 if (FemtrapActiveNatalia && !flags.female && spawnswithhammersandal(mon->data) && rn2(4)) {
3132 tmp = -100;
3133 pline("The projectile just passes through %s!", mon_nam(mon));
3136 if (mon->data == &mons[PM_XXXXXXXXXXXXXXXXXXXX]) {
3137 if (tmp > -100) tmp = -100;
3138 pline("The projectile just passes through %s!", mon_nam(mon));
3141 if (mon->data == &mons[PM_IDE_BY__]) {
3142 if (tmp > -100) tmp = -100;
3143 pline("The projectile just passes through %s!", mon_nam(mon));
3146 /* the elder priest uses cheats */
3147 if (swatting_monster(mon->data) && rn2(15) && tmp > -50) {
3148 tmp = -100;
3149 pline("%s swats the projectile away!", Monnam(mon));
3152 if (mon->data->msound == MS_BULLETATOR && bulletate && rn2(4)) {
3153 tmp = -100;
3154 pline("%s absorbs the projectile!", Monnam(mon));
3157 if (FemtrapActiveAnnemarie && humanoid(mon->data) && mon->female && rn2(15) && tmp > -50) {
3158 tmp = -100;
3159 pline("%s swats the projectile away!", Monnam(mon));
3162 if (ecm_monster(mon->data) && rn2(15) && tmp > -50) {
3163 tmp = -100;
3164 pline("%s uses an ECM system to divert the projectile!", Monnam(mon));
3167 if (stupidrock && tmp > -50 && !(rn2(25) < skillpierce ) ) {
3168 if (verysmall(mon->data) && !rn2(4)) {
3169 tmp = -100;
3170 pline("%s avoids the projectile!", Monnam(mon));
3172 if (rathersmall(mon->data) && !(verysmall(mon->data)) && !rn2(10)) {
3173 tmp = -100;
3174 pline("%s avoids the projectile!", Monnam(mon));
3176 if (hugemonst(mon->data) && !rn2(2) && (mon->m_lev > rnd(GushLevel) ) ) {
3177 tmp = -100;
3178 pline("%s shrugs off the projectile!", Monnam(mon));
3180 if (bigmonst(mon->data) && !(hugemonst(mon->data)) && !rn2(5) && (mon->m_lev > rnd(GushLevel) ) ) {
3181 tmp = -100;
3182 pline("%s shrugs off the projectile!", Monnam(mon));
3184 if (amorphous(mon->data) && !rn2(5) && tmp > -50) {
3185 tmp = -100;
3186 pline("%s's amorphous body skillfully dodges the projectile!", Monnam(mon));
3188 if (noncorporeal(mon->data) && rn2(3) && tmp > -50) {
3189 tmp = -100;
3190 pline("%s easily avoids the projectile due to being noncorporeal!", Monnam(mon));
3192 if (unsolid(mon->data) && !rn2(4) && tmp > -50) {
3193 tmp = -100;
3194 pline("%s's unsolid body lets the projectile pass through harmlessly!", Monnam(mon));
3199 if (MON_WEP(mon)) { /* shien monster lightsaber form */
3200 struct obj *monweapon;
3201 monweapon = MON_WEP(mon);
3202 if (monweapon) {
3203 if (is_lightsaber(monweapon) && tmp > -50 && monweapon->lamplit && (!rn2(2) || ((mon->data->geno & G_UNIQ) && !rn2(2)) ) ) {
3204 tmp = -100;
3205 pline("%s's lightsaber blocks the projectile!", Monnam(mon));
3211 if (blocker = (which_armor(mon, W_ARMS))) {
3213 shieldblockrate = shield_block_rate(blocker);
3214 shieldblockrate += 10; /* monsters can simply block better --Amy */
3216 if (blocker->otyp == ELVEN_SHIELD && is_elf(mon->data)) shieldblockrate += 5;
3217 if (blocker->otyp == URUK_HAI_SHIELD && is_orc(mon->data)) shieldblockrate += 5;
3218 if (blocker->otyp == ORCISH_SHIELD && is_orc(mon->data)) shieldblockrate += 5;
3219 if (blocker->otyp == ORCISH_GUARD_SHIELD && is_orc(mon->data)) shieldblockrate += 5;
3220 if (blocker->otyp == DWARVISH_ROUNDSHIELD && is_dwarf(mon->data)) shieldblockrate += 5;
3222 if (shieldblockrate && (blocker->spe > 0)) shieldblockrate += (blocker->spe * 2);
3223 if (blocker->blessed) shieldblockrate += 5;
3225 if (stupidrock && shieldblockrate) shieldblockrate *= 2;
3227 if (blocker->otyp == BROKEN_SHIELD) tmp = 0;
3229 if ((rnd(100) < shieldblockrate) && tmp > -50) {
3230 tmp = -100;
3231 pline("%s's shield deflects your projectile!", Monnam(mon));
3235 if (Race_if(PM_ENGCHIP) && !rn2(20) && objects[obj->otyp].oc_skill == P_BOW) tmp = -100;
3236 if (Race_if(PM_ENGCHIP) && !rn2(20) && objects[obj->otyp].oc_skill == -P_BOW) tmp = -100;
3237 if (Race_if(PM_ENGCHIP) && !rn2(20) && objects[obj->otyp].oc_skill == P_CROSSBOW) tmp = -100;
3238 if (Race_if(PM_ENGCHIP) && !rn2(20) && objects[obj->otyp].oc_skill == -P_BOW) tmp = -100;
3240 /* Modify to-hit depending on distance; but keep it sane.
3241 * Polearms get a distance penalty even when wielded; it's
3242 * hard to hit at a distance.
3245 /* Amy edit: ranged combat was way too powerful, I decided to greatly reduce to-hit at long distances.
3246 * Firearms are an exception for two reasons: one, their ammo always breaks; two, some of them (especially rifles)
3247 * are actually meant to be used at range and those that are not (e.g. shotguns) have limited range anyway.
3248 * Crossbows are a bit of a special case: they're potentially the most damaging shooter for which the ammos
3249 * can be re-used, but most types also need a pretty high enchantment value to get any serious multishot,
3250 * and they're also kind of meant to be used at long range, so their to-hit will receive a lesser nerf. */
3252 if (obj && obj->oartifact == ART_FTS) tmp += distmin(u.ux, u.uy, mon->mx, mon->my);
3254 if ( !(launcher && ammo_and_launcher(obj, launcher) && objects[launcher->otyp].oc_skill == P_FIREARM) && (!(launcher && ammo_and_launcher(obj, launcher) && objects[launcher->otyp].oc_skill == P_CROSSBOW && !rn2(2)) ) ) {
3256 disttmp = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
3257 if(disttmp < -4) disttmp = -4;
3259 if (uarmg && uarmg->oartifact == ART_SNIPE_EVERYTHING && disttmp < 0) disttmp = 0;
3261 tmp += disttmp;
3263 if ((distmin(u.ux, u.uy, mon->mx, mon->my) > 3) && !(uarmg && uarmg->oartifact == ART_SNIPE_EVERYTHING) ) {
3265 switch (distmin(u.ux, u.uy, mon->mx, mon->my)) {
3267 case 4:
3268 tmp -= rn2(2);
3269 break;
3270 case 5:
3271 tmp -= rn2(4);
3272 break;
3273 case 6:
3274 tmp -= rn2(6);
3275 break;
3276 case 7:
3277 tmp -= rn2(9);
3278 break;
3279 case 8:
3280 tmp -= rn2(12);
3281 break;
3282 case 9:
3283 tmp -= rn2(16);
3284 break;
3285 case 10:
3286 default:
3287 tmp -= rn2(20);
3288 break;
3296 /* gloves are a hinderance to proper use of bows */
3297 if (uarmg && launcher && objects[launcher->otyp].oc_skill == P_BOW) {
3298 switch (uarmg->otyp) {
3299 case GAUNTLETS_OF_POWER: /* metal */
3300 tmp -= 2;
3301 break;
3302 case GAUNTLETS_OF_FUMBLING:
3303 tmp -= 3;
3304 break;
3305 case GAUNTLETS_OF_MISFIRING:
3306 tmp -= 5;
3307 break;
3308 case GAUNTLETS_OF_PANIC:
3309 tmp -= 1;
3310 break;
3311 case GAUNTLETS_OF_FREE_ACTION:
3312 case ELVEN_GAUNTLETS:
3313 case FEMALE_GLOVES:
3314 tmp += 1;
3315 break;
3316 case GAUNTLETS_OF_TRUE_AIM:
3317 tmp += 2;
3318 break;
3319 case REGULAR_GLOVES:
3320 case GAUNTLETS_OF_SWIMMING:
3321 case GAUNTLETS_OF_DEXTERITY:
3322 break;
3323 default: /* why do we need this impossible message anyway? --Amy */
3324 /*impossible("Unknown type of gloves (%d)", uarmg->otyp);*/
3325 break;
3329 if (obj && launcher && ammo_and_launcher(obj, launcher) && launcher->otyp == LASERXBOW && launcher->lamplit && launcher->altmode) tmp += 5;
3331 /* with a lot of luggage, your agility diminishes */
3332 if (near_capacity()) tmp -= rnd(near_capacity() * 5);
3333 if (u.utrap) tmp -= 5;
3335 if (uarmg && itemhasappearance(uarmg, APP_CLUMSY_GLOVES)) tmp -= 3;
3337 if (Race_if(PM_PLAYER_SKELETON)) tmp -= rnd(u.ulevel); /* lesser nerf than melee, since you also misfire */
3339 tmp += omon_adj(mon, obj, TRUE);
3340 if (is_orc(mon->data) && maybe_polyd(is_elf(youmonst.data),
3341 Race_if(PM_ELF)))
3342 tmp++;
3343 if (guaranteed_hit) {
3344 tmp += 1000; /* Guaranteed hit */
3347 /* sleeping unicorns don't catch gems */
3348 if (obj->oclass == GEM_CLASS && is_unicorn(mon->data) && !mon->msleeping) {
3349 if (mon->mtame) {
3350 pline("%s catches and drops %s.", Monnam(mon), the(xname(obj)));
3351 return 0;
3352 } else {
3353 pline("%s catches %s.", Monnam(mon), the(xname(obj)));
3354 return gem_accept(mon, obj);
3358 /* don't make game unwinnable if naive player throws artifact
3359 at leader.... */
3360 if (quest_arti_hits_leader(obj, mon)) {
3361 /* not wakeup(), which angers non-tame monsters */
3362 mon->msleeping = 0;
3363 mon->mstrategy &= ~STRAT_WAITMASK;
3365 if (mon->mcanmove) {
3366 pline("%s catches %s.", Monnam(mon), the(xname(obj)));
3367 if (mon->mpeaceful) {
3368 boolean next2u = monnear(mon, u.ux, u.uy);
3370 finish_quest(obj); /* acknowledge quest completion */
3371 pline("%s %s %s back to you.", Monnam(mon),
3372 (next2u ? "hands" : "tosses"), the(xname(obj)));
3373 if (!next2u) sho_obj_return_to_u(obj);
3374 obj = addinv(obj); /* back into your inventory */
3375 (void) encumber_msg();
3376 } else {
3377 /* angry leader caught it and isn't returning it */
3378 (void) mpickobj(mon, obj, FALSE);
3380 return 1; /* caller doesn't need to place it */
3382 return(0);
3385 if (!polearming && befriend_with_obj(mon->data, obj)) goto befriended;
3387 if (obj->oclass == WEAPON_CLASS || obj->oclass == BALL_CLASS || obj->oclass == CHAIN_CLASS || obj->oclass == VENOM_CLASS || is_weptool(obj) || obj->oartifact == ART_KLUEUEUEU ||
3388 obj->oclass == GEM_CLASS) {
3389 if (is_ammo(obj)) {
3390 if (!ammo_and_launcher(obj, launcher)) {
3391 tmp -= 4;
3392 } else {
3393 if (!InvertedState) {
3394 tmp += launcher->spe - greatest_erosionX(launcher);
3395 } else {
3396 tmp -= abs(launcher->spe);
3397 tmp -= greatest_erosionX(launcher);
3399 tmp += weapon_hit_bonus(launcher);
3400 if (launcher->oartifact) tmp += spec_abon(launcher, mon);
3402 * Elves and Samurais are highly trained w/bows,
3403 * especially their own special types of bow.
3404 * Polymorphing won't make you a bow expert.
3406 if ((Race_if(PM_ELF) || Race_if(PM_PLAYER_MYRKALFR) || Race_if(PM_DROW) ||
3407 Role_if(PM_SAMURAI) || Role_if(PM_ELPH) || Role_if(PM_TWELPH)) &&
3408 (!Upolyd || your_race(youmonst.data)) &&
3409 objects[launcher->otyp].oc_skill == P_BOW) {
3410 tmp++;
3411 if ((Race_if(PM_ELF) || Race_if(PM_PLAYER_MYRKALFR)) && launcher->otyp == ELVEN_BOW)
3412 tmp++;
3413 /*else */if (Race_if(PM_DROW) && launcher->otyp == DARK_ELVEN_BOW)
3414 tmp++;
3415 /*else */if (Role_if(PM_ELPH) && launcher->otyp == ELVEN_BOW)
3416 tmp++;
3417 /*else */if (Role_if(PM_TWELPH) && launcher->otyp == DARK_ELVEN_BOW)
3418 tmp++;
3419 /*else */if (Role_if(PM_SAMURAI) && launcher->otyp == YUMI)
3420 tmp++;
3423 } else {
3424 if (otyp == BOOMERANG || otyp == ALU_BOOMERANG || otyp == SILVER_CHAKRAM || otyp == BATARANG || otyp == DARK_BATARANG) /* arbitrary */
3425 tmp += 4;
3426 else if (throwing_weapon(obj)) /* meant to be thrown */
3427 tmp += 2;
3428 else /* not meant to be thrown */
3429 tmp -= 2;
3430 /* we know we're dealing with a weapon or weptool handled
3431 by WEAPON_SKILLS once ammo objects have been excluded */
3432 tmp += weapon_hit_bonus(obj);
3434 #ifdef DEBUG
3435 pline("(%i/20)", tmp);
3436 #endif
3438 if (tmp >= dieroll) {
3439 ranged_thorns(mon);
3440 if (hmon(mon,obj,thrown?thrown:3,dieroll)) { /* mon still alive */
3441 (void) cutworm(mon, bhitpos.x, bhitpos.y, obj);
3443 exercise(A_DEX, TRUE);
3445 if (obj && obj->otyp == LASER_POLE) {
3446 u.uvaapadturns++;
3447 if (u.uvaapadturns >= 4) {
3448 u.uvaapadturns = 0;
3449 use_skill(P_VAAPAD, 1);
3453 if (obj && obj->otyp == LASER_CHAIN && !bimanual(obj) && !uarms && !u.twoweap) {
3454 u.umakashiturns++;
3455 if (u.umakashiturns >= 4) {
3456 u.umakashiturns = 0;
3457 use_skill(P_MAKASHI, 1);
3461 /* Detonate bolts shot by Hellfire */
3462 if (ammo_and_launcher(obj, launcher) &&
3463 (launcher->oartifact == ART_HELLFIRE || launcher->oartifact == ART_EVERCONSUMING_HELLFIRE || obj->oartifact == ART_BAKUHATSU_SEI_MISAIRU || launcher->oartifact == ART_UNIDENTIFIED_HELLCAST || launcher->oartifact == ART_SEVENTH_SCRIPTURE)) {
3464 if (cansee(bhitpos.x,bhitpos.y))
3465 pline("%s explodes in a ball of fire!", Doname2(obj));
3466 else You_hear("an explosion");
3467 explode(bhitpos.x, bhitpos.y, ZT_SPELL(ZT_FIRE),
3468 d(2,6), WEAPON_CLASS, EXPL_FIERY);
3471 /* projectiles other than magic stones
3472 * sometimes disappear when thrown
3473 * WAC - Spoon always disappears after doing damage
3475 if (((objects[otyp].oc_skill < P_NONE &&
3476 objects[otyp].oc_skill > -P_BOOMERANG) ||
3477 ( objects[otyp].oc_skill == P_DAGGER && ((obj->spe < 1) || (obj->spe > 0 && (!rn2(obj->spe + 1) || !rn2(obj->spe + 1))) ) && (!obj->oartifact || !rn2(1000)) ) ||
3478 ( objects[otyp].oc_skill == P_KNIFE && ((obj->spe < 1) || (obj->spe > 0 && (!rn2(obj->spe + 1) || !rn2(obj->spe + 1))) ) && (!obj->oartifact || !rn2(1000)) ) ||
3479 ( objects[otyp].oc_skill == P_SPEAR && ((obj->spe < 1) || (obj->spe > 0 && (!rn2(obj->spe + 1) || !rn2(obj->spe + 1) || !rn2(obj->spe + 1))) ) && (!obj->oartifact || !rn2(1000)) ) ||
3480 ( objects[otyp].oc_skill == P_JAVELIN && ((obj->spe < 1) || (obj->spe > 0 && !rn2(obj->spe + 1)) ) && (!obj->oartifact || !rn2(1000)) ) ||
3482 /* low chance for daggers, knives and spears to disappear --Amy */
3483 (obj->oclass == GEM_CLASS &&
3484 (!objects[otyp].oc_magic || !rn2(5) ))) /* also low chance for loadstones etc. to disappear */
3485 || (obj->oartifact == ART_HOUCHOU)
3486 /* WAC catch Hellfire */
3487 || (launcher && (launcher->oartifact == ART_HELLFIRE || launcher->oartifact == ART_EVERCONSUMING_HELLFIRE || obj->oartifact == ART_BAKUHATSU_SEI_MISAIRU || launcher->oartifact == ART_UNIDENTIFIED_HELLCAST || launcher->oartifact == ART_SEVENTH_SCRIPTURE)
3488 && is_ammo(obj) && ammo_and_launcher(obj, launcher))
3490 /* we were breaking 2/3 of everything unconditionally.
3491 * we still don't want anything to survive unconditionally,
3492 * but we need ammo to stay around longer on average.
3494 int broken, chance;
3495 chance = greatest_erosionX(obj) - obj->spe; /* base chance increased --Amy */
3496 chance -= rnd(2);
3497 if (chance > 1) {
3498 if (chance == 3) chance = 2;
3499 else if (chance == 4) chance = 3;
3500 else if (chance == 5) chance = 3;
3501 else if (chance > 5) chance /= 2;
3502 broken = rn2(chance);
3503 } else {/* continue to survive longer with better enchantment --Amy */
3504 chance = 3 + obj->spe - greatest_erosionX(obj);
3505 if (chance > 3) chance = 2 + rno(chance - 2);
3506 if (chance < 2) chance = 2; /* fail safe */
3507 if (Race_if(PM_MONGUNG)) chance *= 2;
3508 broken = !rn2(chance);
3510 if ( objects[otyp].oc_skill == P_DAGGER )
3511 broken = !rn2(Race_if(PM_MONGUNG) ? 80 : 40);
3512 if ( objects[otyp].oc_skill == P_SPEAR )
3513 broken = !rn2(Race_if(PM_MONGUNG) ? 150 : 75);
3514 if ( objects[otyp].oc_skill == P_KNIFE )
3515 broken = !rn2(Race_if(PM_MONGUNG) ? 160 : 80);
3516 if ( objects[otyp].oc_skill == P_JAVELIN )
3517 broken = !rn2(Race_if(PM_MONGUNG) ? 2400 : 1200);
3518 if (obj->blessed && !rnl(6))
3519 broken = 0;
3520 /* also save uncursed ones sometimes --Amy */
3521 if (!obj->blessed && !obj->cursed && !rn2(3) && !rnl(6))
3522 broken = 0;
3524 if (!(PlayerCannotUseSkills)) {
3525 switch (P_SKILL(P_MISSILE_WEAPONS)) {
3526 default: break;
3527 case P_BASIC: if (rn2(10) < 1) broken = 0; break;
3528 case P_SKILLED: if (rn2(10) < 2) broken = 0; break;
3529 case P_EXPERT: if (rn2(10) < 3) broken = 0; break;
3530 case P_MASTER: if (rn2(10) < 4) broken = 0; break;
3531 case P_GRAND_MASTER: if (rn2(10) < 5) broken = 0; break;
3532 case P_SUPREME_MASTER: if (rn2(10) < 6) broken = 0; break;
3536 /* allow skill to save ammo --Amy */
3538 if (!(PlayerCannotUseSkills)) {
3540 if (objects[otyp].oc_skill == -P_BOW && (P_SKILL(P_BOW) >= P_BASIC) && rn2(P_SKILL(P_BOW)) )
3541 broken = 0;
3542 if (objects[otyp].oc_skill == -P_CROSSBOW && (P_SKILL(P_CROSSBOW) >= P_BASIC) && rn2(P_SKILL(P_CROSSBOW)) )
3543 broken = 0;
3544 if (objects[otyp].oc_skill == -P_SLING && (P_SKILL(P_SLING) >= P_BASIC) && rn2(P_SKILL(P_SLING)) )
3545 broken = 0;
3546 if (objects[otyp].oc_skill == -P_DART && (P_SKILL(P_DART) >= P_BASIC) && rn2(P_SKILL(P_DART)) )
3547 broken = 0;
3548 if (objects[otyp].oc_skill == -P_SHURIKEN && (P_SKILL(P_SHURIKEN) >= P_BASIC) && rn2(P_SKILL(P_SHURIKEN)) )
3549 broken = 0;
3550 if (objects[otyp].oc_skill == P_DAGGER && (P_SKILL(P_DAGGER) >= P_BASIC) && rn2(P_SKILL(P_DAGGER)) )
3551 broken = 0;
3552 if (objects[otyp].oc_skill == P_SPEAR && (P_SKILL(P_SPEAR) >= P_BASIC) && rn2(P_SKILL(P_SPEAR)) )
3553 broken = 0;
3554 if (objects[otyp].oc_skill == P_JAVELIN && (P_SKILL(P_JAVELIN) >= P_BASIC) && rn2(P_SKILL(P_JAVELIN)) )
3555 broken = 0;
3556 if (objects[otyp].oc_skill == P_KNIFE && (P_SKILL(P_KNIFE) >= P_BASIC) && rn2(P_SKILL(P_KNIFE)) )
3557 broken = 0;
3561 if (objects[otyp].oc_skill == -P_BOW && uarm && uarm->oartifact == ART_WOODSTOCK && broken && !rn2(2))
3562 broken = 0;
3563 if (objects[otyp].oc_skill == -P_SLING && uarms && uarms->oartifact == ART_MISSING_LETTER_D && broken && rn2(4))
3564 broken = 0;
3565 if (objects[otyp].oc_material == MT_MINERAL && uarm && uarm->oartifact == ART_QUARRY && broken && !rn2(2))
3566 broken = 0;
3567 if (uarmc && uarmc->oartifact == ART_ARABELLA_S_WEAPON_STORAGE && broken && !rn2(2))
3568 broken = 0;
3569 if (Race_if(PM_MACTHEIST) && objects[otyp].oc_skill == P_SLING && broken && !rn2(2))
3570 broken = 0;
3571 if (Race_if(PM_MACTHEIST) && objects[otyp].oc_skill == -P_SLING && broken && !rn2(2))
3572 broken = 0;
3574 if (obj->oartifact == ART_USE_A_LOT) {
3575 if (rn2(10)) broken = 0;
3577 if (obj->oartifact == ART_WIUNEW) {
3578 if (rn2(10)) broken = 0;
3580 if (obj->oartifact == ART_BE_CONSERVED) {
3581 if (rn2(10)) broken = 0;
3584 if (objects[otyp].oc_material == MT_BAMBOO && broken && !rn2(4)) broken = 0;
3586 if (objects[otyp].oc_material == MT_LEAD && broken && !rn2(4)) broken = 0;
3587 if (otyp == DART_OF_DISINTEGRATION && rn2(10) ) broken = 1;
3589 /* Due to segfaults and stuff when trying to make this work in other functions, I'm just deciding that
3590 * any thoroughly eroded stuff you throw will generally be destroyed much more often. --Amy */
3591 if ((obj->oeroded == MAX_ERODE || obj->oeroded2 == MAX_ERODE) && !rn2(25) && !hard_to_destruct(obj)) broken = 1;
3593 /* artifact that sets the mulching rate to exactly 10%, regardless of other calculations */
3594 if (obj->oartifact == ART_ACTUALLY_THE_MATTER_COMES_) {
3595 if (!rn2(10)) broken = 1;
3596 else broken = 0;
3599 /* mulch nastytrap: ammo breaks unconditionally no matter what --Amy */
3600 if (MulchBug || u.uprops[MULCH_BUG].extrinsic || have_mulchstone() || autismweaponcheck(ART_PIN_EM_ONCE) ) broken = 1;
3602 if (broken) {
3603 if (*u.ushops)
3604 check_shop_obj(obj, bhitpos.x,bhitpos.y, TRUE);
3606 * Thrown grenades and explosive ammo used with the
3607 * relevant launcher explode rather than simply
3608 * breaking.
3610 if ((thrown == 1 || thrown == 2) && is_grenade(obj)) {
3611 grenade_explode(obj, bhitpos.x, bhitpos.y, TRUE, 0);
3612 } else if (ammo_and_launcher(obj, launcher) && (objects[obj->otyp].oc_dir & EXPLOSION)) {
3613 if (cansee(bhitpos.x,bhitpos.y))
3614 pline("%s explodes in a ball of fire!", Doname2(obj));
3615 else You_hear("an explosion"); /* Amy note: we do not add an exclamation mark here on purpose */
3617 explode(bhitpos.x, bhitpos.y, ZT_SPELL(ZT_FIRE), d(3,8), WEAPON_CLASS, EXPL_FIERY);
3618 u.cnd_gunpowderused++;
3620 if (obj && obj->otyp == MINI_NUKE) fatman_explosion(bhitpos.x, bhitpos.y, obj);
3622 obfree(obj, (struct obj *)0);
3623 } else {
3624 obfree(obj, (struct obj *)0);
3625 u.cnd_ammomulched++; /* known problem: bullets can also run this code --Amy */
3626 if (RngeMulchingDisplay || (uarm && uarm->oartifact == ART_SEE_THE_MULCH_STATE) ) Your("projectile has mulched.");
3628 return 1;
3631 /* ceramic stuff dulls in melee, but we want ceramic missiles to dull too --Amy */
3632 if (obj && objects[obj->otyp].oc_material == MT_CERAMIC && !rn2(10) && obj->spe > -10) {
3633 obj->spe--;
3636 if (obj && obj->oartifact == ART_CHA_SHATTER && !rn2(3) && obj->spe > -20) {
3637 obj->spe--;
3640 passive_obj(mon, obj, (struct attack *)0);
3641 } else {
3642 tmiss(obj, mon);
3645 } else if (otyp == HEAVY_IRON_BALL) {
3646 exercise(A_STR, TRUE);
3647 if (tmp >= dieroll) {
3648 int was_swallowed = guaranteed_hit;
3650 exercise(A_DEX, TRUE);
3651 ranged_thorns(mon);
3652 if (!hmon(mon,obj,thrown?thrown:3,dieroll)) { /* mon killed */
3653 if (was_swallowed && !u.uswallow && obj == uball)
3654 return 1; /* already did placebc() */
3656 } else {
3657 tmiss(obj, mon);
3660 } else if (otyp == BOULDER) {
3661 exercise(A_STR, TRUE);
3662 if (tmp >= dieroll) {
3663 exercise(A_DEX, TRUE);
3664 ranged_thorns(mon);
3665 (void) hmon(mon, obj, thrown ? thrown : 3, dieroll);
3667 if (obj) {
3668 int bouldersplinterchance = 10;
3669 if (obj->oartifact) bouldersplinterchance *= 10;
3670 if (obj->cursed) bouldersplinterchance /= 2;
3671 if (obj->blessed) bouldersplinterchance *= 3;
3673 if (!PlayerCannotUseSkills) {
3674 switch (P_SKILL(P_BOULDER_THROWING)) {
3675 default: break;
3676 case P_BASIC: bouldersplinterchance *= 6; bouldersplinterchance /= 5; break;
3677 case P_SKILLED: bouldersplinterchance *= 7; bouldersplinterchance /= 5; break;
3678 case P_EXPERT: bouldersplinterchance *= 8; bouldersplinterchance /= 5; break;
3679 case P_MASTER: bouldersplinterchance *= 9; bouldersplinterchance /= 5; break;
3680 case P_GRAND_MASTER: bouldersplinterchance *= 10; bouldersplinterchance /= 5; break;
3681 case P_SUPREME_MASTER: bouldersplinterchance *= 11; bouldersplinterchance /= 5; break;
3685 if (!rn2(bouldersplinterchance)) {
3686 pline_The("boulder shatters into fragments!");
3687 fracture_rock(obj);
3691 } else {
3692 tmiss(obj, mon);
3695 } else if ((otyp == EGG || otyp == CREAM_PIE) &&
3696 (guaranteed_hit || ACURR(A_DEX) > rnd(25) || (tmp >= rnd(20) && !PlayersRaysAreInaccurate) )) { /* F this stupidity. Sorry. --Amy */
3698 ranged_thorns(mon);
3699 (void) hmon(mon, obj, thrown?thrown:3,dieroll);
3700 if (issegfaulter && otyp == SEGFAULT_VENOM && !rn2(5)) { /* segfault panic! */
3701 u.segfaultpanic = TRUE;
3702 } else if (obj->oartifact == ART_DO_NOT_THROW_ME) { /* uh-oh... you really messed up big time there. */
3703 u.segfaultpanic = TRUE;
3706 return 1; /* hmon used it up */
3708 } else if (obj->oclass == POTION_CLASS &&
3709 (guaranteed_hit || ACURR(A_DEX) > rnd(25) || (tmp >= rnd(20) && !PlayersRaysAreInaccurate) )) { /* The damn things missed way too often. */
3710 ranged_thorns(mon);
3711 potionhit(mon, obj, TRUE);
3712 return 1;
3714 } else if (!polearming && (befriend_with_obj(mon->data, obj) || (obj->oclass == FOOD_CLASS && mon->egotype_domestic) || (otyp == KELP_FROND && mon->egotype_petty) || (mon->mtame && dogfood(mon, obj) <= ACCFOOD)) ) {
3715 befriended:
3717 if (tamedog(mon, obj, FALSE)) return 1; /* obj is gone */
3718 else {
3719 /* not tmiss(), which angers non-tame monsters */
3720 miss(xname(obj), mon);
3721 mon->msleeping = 0;
3722 mon->mstrategy &= ~STRAT_WAITMASK;
3724 } else if (guaranteed_hit) {
3725 /* this assumes that guaranteed_hit is due to swallowing */
3726 wakeup(mon);
3727 ranged_thorns(mon);
3728 if (obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm]) && !rn2(4)) {
3729 if (is_animal(u.ustuck->data)) {
3730 minstapetrify(u.ustuck, TRUE);
3731 /* Don't leave a cockatrice corpse available in a statue */
3732 if (!u.uswallow) {
3733 delobj(obj);
3734 return 1;
3738 pline("%s into %s %s.",
3739 Tobjnam(obj, "vanish"), s_suffix(mon_nam(mon)),
3740 is_animal(u.ustuck->data) ? "entrails" : "currents");
3741 } else {
3742 tmiss(obj, mon);
3744 return 0;
3747 STATIC_OVL int
3748 gem_accept(mon, obj)
3749 register struct monst *mon;
3750 register struct obj *obj;
3752 char buf[BUFSZ];
3753 boolean is_buddy = sgn(mon->data->maligntyp) == sgn(u.ualign.type);
3754 if (mon->data == &mons[PM_MOLOCH_ALIGNED_UNICORN]) is_buddy = FALSE;
3755 boolean is_gem = objects[obj->otyp].oc_material == MT_GEMSTONE;
3756 int ret = 0;
3757 static NEARDATA const char nogood[] = " is not interested in your junk.";
3758 static NEARDATA const char acceptgift[] = " accepts your gift.";
3759 static NEARDATA const char maybeluck[] = " hesitatingly";
3760 static NEARDATA const char noluck[] = " graciously";
3761 static NEARDATA const char addluck[] = " gratefully";
3763 strcpy(buf,Monnam(mon));
3764 if (!mon->mfrenzied) {
3765 mon->mpeaceful = 1;
3766 mon->mavenge = 0;
3769 /* Luck boosts used to be way too high. Thus I lowered them. --Amy */
3771 /* object properly identified */
3772 if(obj->dknown && objects[obj->otyp].oc_name_known) {
3773 if(is_gem) {
3774 if(is_buddy) {
3775 strcat(buf,addluck);
3776 if (!rn2(isfriday ? 10 : issoviet ? 2 : 3)) change_luck(issoviet ? 4 : rnd(4) );
3777 if (issoviet) pline("Vy, bezuslovno, povezlo, potomu chto eta igra yavlyayetsya nesbalansirovannym, kak chert!");
3778 } else {
3779 strcat(buf,maybeluck);
3780 if (!rn2(isfriday ? 10 : issoviet ? 3 : 5)) change_luck(issoviet ? 2 : rnd(2) );
3781 if (issoviet) pline("Kto-to reshil, chto vy dolzhny poluchit' tonny udachi besplatno!");
3783 } else {
3784 strcat(buf,nogood);
3785 goto nopick;
3787 /* making guesses */
3788 } else if(obj->onamelth || objects[obj->otyp].oc_uname) {
3789 if(is_gem) {
3790 if(is_buddy) {
3791 strcat(buf,addluck);
3792 if (!rn2(isfriday ? 10 : issoviet ? 2 : 3)) change_luck(issoviet ? 2 : rnd(2) );
3793 if (issoviet) pline("Vy, bezuslovno, povezlo, potomu chto eta igra yavlyayetsya nesbalansirovannym, kak chert!");
3794 } else {
3795 strcat(buf,maybeluck);
3796 if (!rn2(isfriday ? 10 : issoviet ? 3 : 5)) change_luck(issoviet ? 2 : rnd(2) );
3797 if (issoviet) pline("Kto-to reshil, chto vy dolzhny poluchit' tonny udachi besplatno!");
3799 } else {
3800 strcat(buf,nogood);
3801 goto nopick;
3803 /* value completely unknown to @ */
3804 } else {
3805 if(is_gem) {
3806 if(is_buddy) {
3807 strcat(buf,addluck);
3808 if (!rn2(isfriday ? 10 : issoviet ? 2 : 3)) change_luck(1);
3809 } else {
3810 strcat(buf,maybeluck);
3811 if (!rn2(isfriday ? 10 : issoviet ? 3 : 5)) change_luck(1);
3813 } else {
3814 strcat(buf,noluck);
3817 strcat(buf,acceptgift);
3818 if(*u.ushops) check_shop_obj(obj, mon->mx, mon->my, TRUE);
3819 if (!issoviet && rn2(2)) (void) mpickobj(mon, obj, FALSE); /* may merge and free obj */
3820 else obfree(obj, (struct obj *)0); /* definitely frees obj, nerf by Amy */
3821 ret = 1;
3823 nopick:
3824 if(!Blind) pline("%s", buf);
3825 if (!tele_restrict(mon)) (void) rloc(mon, FALSE);
3826 return(ret);
3830 * Comments about the restructuring of the old breaks() routine.
3832 * There are now three distinct phases to object breaking:
3833 * breaktest() - which makes the check/decision about whether the
3834 * object is going to break.
3835 * breakmsg() - which outputs a message about the breakage,
3836 * appropriate for that particular object. Should
3837 * only be called after a positve breaktest().
3838 * on the object and, if it going to be called,
3839 * it must be called before calling breakobj().
3840 * Calling breakmsg() is optional.
3841 * breakobj() - which actually does the breakage and the side-effects
3842 * of breaking that particular object. This should
3843 * only be called after a positive breaktest() on the
3844 * object.
3846 * Each of the above routines is currently static to this source module.
3847 * There are two routines callable from outside this source module which
3848 * perform the routines above in the correct sequence.
3850 * hero_breaks() - called when an object is to be broken as a result
3851 * of something that the hero has done. (throwing it,
3852 * kicking it, etc.)
3853 * breaks() - called when an object is to be broken for some
3854 * reason other than the hero doing something to it.
3858 * The hero causes breakage of an object (throwing, dropping it, etc.)
3859 * Return 0 if the object didn't break, 1 if the object broke.
3862 hero_breaks(obj, x, y, from_invent)
3863 struct obj *obj;
3864 xchar x, y; /* object location (ox, oy may not be right) */
3865 boolean from_invent; /* thrown or dropped by player; maybe on shop bill */
3867 boolean in_view = !Blind;
3868 if (!breaktest(obj)) return 0;
3869 breakmsg(obj, in_view);
3870 breakobj(obj, x, y, TRUE, from_invent);
3871 return 1;
3875 * The object is going to break for a reason other than the hero doing
3876 * something to it.
3877 * Return 0 if the object doesn't break, 1 if the object broke.
3880 breaks(obj, x, y)
3881 struct obj *obj;
3882 xchar x, y; /* object location (ox, oy may not be right) */
3884 boolean in_view = Blind ? FALSE : cansee(x, y);
3886 if (!breaktest(obj)) return 0;
3887 breakmsg(obj, in_view);
3888 breakobj(obj, x, y, FALSE, FALSE);
3889 return 1;
3893 * Unconditionally break an object. Assumes all resistance checks
3894 * and break messages have been delivered prior to getting here.
3896 STATIC_OVL void
3897 breakobj(obj, x, y, hero_caused, from_invent)
3898 struct obj *obj;
3899 xchar x, y; /* object location (ox, oy may not be right) */
3900 boolean hero_caused; /* is this the hero's fault? */
3901 boolean from_invent;
3903 if (itemhasappearance(obj, APP_POTION_RESERVATROL) && isok(x, y)) {
3904 (void) create_gas_cloud(x, y, 3+bcsign(obj), 8+4*bcsign(obj));
3905 You("smell chemicals.");
3907 if (itemhasappearance(obj, APP_POTION_NITROGLYCERIN) && isok(x, y)) {
3908 struct obj *dynamite;
3909 dynamite = mksobj_at(STICK_OF_DYNAMITE, x, y, TRUE, FALSE, FALSE);
3910 if (dynamite) {
3911 if (dynamite->otyp != STICK_OF_DYNAMITE) delobj(dynamite);
3912 else {
3913 dynamite->dynamitekaboom = 1;
3914 dynamite->quan = 1;
3915 dynamite->owt = weight(dynamite);
3916 attach_bomb_blow_timeout(dynamite, 0, 0);
3917 run_timers();
3923 int am;
3924 if (IS_ALTAR(levl[x][y].typ))
3925 am = levl[x][y].altarmask & AM_MASK;
3926 else
3927 am = AM_NONE;
3928 switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
3929 case MIRROR:
3930 if (hero_caused)
3931 change_luck(-2);
3932 break;
3933 case POT_WATER: /* really, all potions */
3934 if (obj->otyp == POT_OIL && obj->lamplit) {
3935 splatter_burning_oil(x,y);
3936 } else if ((obj->otyp == POT_VAMPIRE_BLOOD ||
3937 obj->otyp == POT_BLOOD) &&
3938 am != AM_CHAOTIC &&
3939 am != AM_NONE) {
3940 /* ALI: If blood is spilt on a lawful or
3941 * neutral altar the effect is similar to
3942 * human sacrifice. There's no effect on
3943 * chaotic or unaligned altars since it is
3944 * not sufficient to summon a demon.
3946 if (hero_caused) {
3947 /* Regardless of your race/alignment etc.
3948 * Lawful and neutral gods really _dont_
3949 * like vampire or (presumed) human blood
3950 * on their altars.
3952 pline("You'll regret this infamous offense!");
3953 exercise(A_WIS, FALSE);
3955 /* curse the lawful/neutral altar */
3956 pline_The("altar is stained with blood.");
3957 if (PlayerHearsSoundEffects) pline(issoviet ? "Vy nechisto yeretikom, pravoslavnaya tserkov' progonit vas!" : "Klatsch.");
3958 if (!Is_astralevel(&u.uz))
3959 levl[x][y].altarmask = AM_CHAOTIC;
3960 angry_priest();
3961 } else if (distu(x,y) <= 2) {
3962 if (!breathless(youmonst.data) || haseyes(youmonst.data)) {
3963 if (obj->otyp != POT_WATER) {
3964 if (!breathless(youmonst.data))
3965 /* [what about "familiar odor" when known?] */
3966 You("smell a peculiar odor...");
3967 else {
3968 int numeyes = eyecount(youmonst.data);
3969 Your("%s water%s.",
3970 (numeyes == 1) ? body_part(EYE) :
3971 makeplural(body_part(EYE)),
3972 (numeyes == 1) ? "s" : "");
3975 potionbreathe(obj);
3978 /* monster breathing isn't handled... [yet?] */
3979 break;
3980 case EGG:
3981 /* breaking your own eggs is bad luck */
3982 if (hero_caused && obj->spe && obj->corpsenm >= LOW_PM)
3983 change_luck((schar) -min(obj->quan, 5L));
3984 break;
3986 if (hero_caused) {
3987 if (from_invent) {
3988 if (*u.ushops)
3989 check_shop_obj(obj, x, y, TRUE);
3990 } else if (!obj->no_charge && costly_spot(x, y)) {
3991 /* it is assumed that the obj is a floor-object */
3992 char *o_shop = in_rooms(x, y, SHOPBASE);
3993 struct monst *shkp = shop_keeper(*o_shop);
3995 if (shkp) { /* (implies *o_shop != '\0') */
3996 static NEARDATA long lastmovetime = 0L;
3997 static NEARDATA boolean peaceful_shk = FALSE;
3998 /* We want to base shk actions on her peacefulness
3999 at start of this turn, so that "simultaneous"
4000 multiple breakage isn't drastically worse than
4001 single breakage. (ought to be done via ESHK) */
4002 if (moves != lastmovetime)
4003 peaceful_shk = shkp->mpeaceful;
4004 if (stolen_value(obj, x, y, peaceful_shk, FALSE, TRUE) > 0L &&
4005 (*o_shop != u.ushops[0] || !inside_shop(u.ux, u.uy)) &&
4006 moves != lastmovetime) make_angry_shk(shkp, x, y);
4007 lastmovetime = moves;
4011 if (obj == uball) unpunish();
4012 if (obj == uchain) unpunish();
4013 delobj(obj);
4017 * Check to see if obj is going to break, but don't actually break it.
4018 * Return 0 if the object isn't going to break, 1 if it is.
4019 * Amy edit: artifacts no longer completely immune, muahahahaha!
4020 * also, if the item is vitric, artifact versions should have a considerable chance of breaking too
4022 boolean
4023 breaktest(obj)
4024 struct obj *obj;
4026 if (is_vitric(obj)) {
4027 if (obj_resists(obj, 1, 33)) return 0;
4028 } else {
4029 if (obj_resists(obj, 1, 99)) return 0;
4031 if ((objects[obj->otyp].oc_material == MT_GLASS || objects[obj->otyp].oc_material == MT_OBSIDIAN || is_vitric(obj)) && (!obj->oartifact || is_vitric(obj) || !rn2(10)) &&
4032 obj->oclass != GEM_CLASS)
4033 return 1;
4034 switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
4035 case EXPENSIVE_CAMERA:
4036 case POT_WATER: /* really, all potions */
4037 case EGG:
4038 case CREAM_PIE:
4039 case MELON:
4040 case ACID_VENOM:
4041 case TAIL_SPIKES:
4042 case BLINDING_VENOM:
4043 case SEGFAULT_VENOM:
4044 case FAERIE_FLOSS_RHING:
4045 return 1;
4046 default:
4047 return 0;
4051 STATIC_OVL void
4052 breakmsg(obj, in_view)
4053 struct obj *obj;
4054 boolean in_view;
4056 const char *to_pieces;
4058 to_pieces = "";
4059 switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
4060 default: /* glass or crystal wand */
4061 if (obj->oclass != WAND_CLASS)
4062 /*impossible("breaking odd object?");*/
4063 pline(FunnyHallu ? "Shards, lots of shards!" : "An odd object broke!"); /*quartz rings for example*/
4064 case CRYSTAL_PLATE_MAIL:
4065 case LENSES:
4066 case MIRROR:
4067 case CRYSTAL_BALL:
4068 case ORB_OF_CHARGING:
4069 case ORB_OF_ENCHANTMENT:
4070 case ORB_OF_DESTRUCTION:
4071 case EXPENSIVE_CAMERA:
4072 to_pieces = " into a thousand pieces";
4073 /*FALLTHRU*/
4074 case POT_WATER: /* really, all potions */
4075 if (!in_view)
4076 You_hear("%s shatter!", something);
4077 else
4078 pline("%s shatter%s%s!", Doname2(obj),
4079 (obj->quan==1) ? "s" : "", to_pieces);
4080 break;
4081 case EGG:
4082 case MELON:
4083 pline("Splat!");
4084 break;
4085 case CREAM_PIE:
4086 if (in_view) pline("What a mess!");
4087 break;
4088 case ACID_VENOM:
4089 case TAIL_SPIKES:
4090 case BLINDING_VENOM:
4091 case SEGFAULT_VENOM:
4092 case FAERIE_FLOSS_RHING:
4093 pline("Splash!");
4094 break;
4098 STATIC_OVL int
4099 throw_gold(obj)
4100 struct obj *obj;
4102 int range, odx, ody;
4103 #ifndef GOLDOBJ
4104 long zorks = obj->quan;
4105 #endif
4106 register struct monst *mon;
4108 if(!u.dx && !u.dy && !u.dz) {
4109 #ifndef GOLDOBJ
4110 u.ugold += obj->quan;
4111 flags.botl = 1;
4112 dealloc_obj(obj);
4113 #endif
4114 You("cannot throw gold at yourself.");
4115 return(0);
4117 #ifdef GOLDOBJ
4118 freeinv(obj);
4119 #endif
4120 if(u.uswallow) {
4121 pline(is_animal(u.ustuck->data) ?
4122 "%s in the %s's entrails." : "%s into %s.",
4123 #ifndef GOLDOBJ
4124 "The gold disappears", mon_nam(u.ustuck));
4125 u.ustuck->mgold += zorks;
4126 dealloc_obj(obj);
4127 #else
4128 "The money disappears", mon_nam(u.ustuck));
4129 add_to_minv(u.ustuck, obj);
4130 #endif
4131 return(1);
4134 if(u.dz) {
4135 if (u.dz < 0 && !Is_airlevel(&u.uz) &&
4136 !Underwater && !Is_waterlevel(&u.uz)) {
4137 pline_The("gold hits the %s, then falls back on top of your %s.",
4138 ceiling(u.ux,u.uy), body_part(HEAD));
4139 /* some self damage? */
4140 if(uarmh) pline("Fortunately, you are wearing a helmet!");
4142 bhitpos.x = u.ux;
4143 bhitpos.y = u.uy;
4144 } else {
4145 /* consistent with range for normal objects */
4146 range = (int)((ACURRSTR)/2 - obj->owt/40);
4148 /* see if the gold has a place to move into */
4149 odx = u.ux + u.dx;
4150 ody = u.uy + u.dy;
4151 if(!ZAP_POS(levl[odx][ody].typ) || closed_door(odx, ody)) {
4152 bhitpos.x = u.ux;
4153 bhitpos.y = u.uy;
4154 } else {
4155 mon = bhit(u.dx, u.dy, range, THROWN_WEAPON,
4156 (int (*)(MONST_P,OBJ_P))0,
4157 (int (*)(OBJ_P,OBJ_P))0,
4158 &obj, FALSE);
4159 if (!obj)
4160 return 1;
4161 if(mon) {
4162 if (ghitm(mon, obj)) /* was it caught? */
4163 return 1;
4164 } else {
4165 if(ship_object(obj, bhitpos.x, bhitpos.y, FALSE))
4166 return 1;
4171 if(flooreffects(obj,bhitpos.x,bhitpos.y,"fall")) return(1);
4172 if(u.dz > 0)
4173 pline_The("gold hits the %s.", surface(bhitpos.x,bhitpos.y));
4174 place_object(obj,bhitpos.x,bhitpos.y);
4175 if(*u.ushops) sellobj(obj, bhitpos.x, bhitpos.y);
4176 stackobj(obj);
4177 newsym(bhitpos.x,bhitpos.y);
4178 return(1);
4181 /*dothrow.c*/