diff --git a/doc/fixes35.0 b/doc/fixes35.0 index f8431ba08..b0657a706 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -200,6 +200,8 @@ artifacts which subsequently evade your grasp/control after already being hero with lycanthropy is vulnerable to silver in human form as well as beast changing alignment or shape triggers a check for equipment evading hero's grasp passive fire effects can damage attackers weapons +wielded bow shouldn't affect outcome of kicked arrows +ranged polearm hit can divide puddings and can use confuse monster effect Platform- and/or Interface-Specific Fixes diff --git a/include/hack.h b/include/hack.h index cb895aed8..ae3ec1a80 100644 --- a/include/hack.h +++ b/include/hack.h @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)hack.h 3.5 2007/02/21 */ +/* SCCS Id: @(#)hack.h 3.5 2007/03/24 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -129,6 +129,13 @@ NEARDATA extern coord bhitpos; /* place where throw or zap hits or stops */ #define FLASHED_LIGHT 3 #define INVIS_BEAM 4 +/* attack mode for hmon() */ +#define HMON_MELEE 0 /* hand-to-hand */ +#define HMON_THROWN 1 /* normal ranged (or spitting while poly'd) */ +#define HMON_KICKED 2 /* alternate ranged */ +#define HMON_APPLIED 3 /* polearm, treated as ranged */ +#define HMON_DRAGGED 4 /* attached iron ball, pulled into mon */ + #define MATCH_WARN_OF_MON(mon) (Warn_of_mon && \ ((context.warntype.obj && \ (context.warntype.obj & (mon)->data->mflags2)) || \ diff --git a/src/ball.c b/src/ball.c index 7bc7b743b..e78110ff2 100644 --- a/src/ball.c +++ b/src/ball.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)ball.c 3.5 2003/02/03 */ +/* SCCS Id: @(#)ball.c 3.5 2007/03/24 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -585,7 +585,7 @@ drag: tmp = -2 + Luck + find_mac(victim); tmp += omon_adj(victim, uball, TRUE); if (tmp >= rnd(20)) - (void) hmon(victim,uball,1); + (void) hmon(victim, uball, HMON_DRAGGED); else miss(xname(uball), victim); diff --git a/src/dothrow.c b/src/dothrow.c index c2b0e832f..0a5922467 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)dothrow.c 3.5 2007/01/10 */ +/* SCCS Id: @(#)dothrow.c 3.5 2007/03/23 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -27,6 +27,7 @@ static NEARDATA const char bullets[] = struct obj *thrownobj = 0; /* tracks an object until it lands */ +extern struct obj *kickobj; /* from dokick.c */ extern boolean notonhead; /* for long worms */ @@ -1225,23 +1226,28 @@ boolean maybe_wakeup; } #define quest_arti_hits_leader(obj,mon) \ - (obj->oartifact && is_quest_artifact(obj) && (mon->data->msound == MS_LEADER)) + (obj->oartifact && is_quest_artifact(obj) && \ + mon->m_id == quest_status.leader_m_id) /* * Object thrown by player arrives at monster's location. * Return 1 if obj has disappeared or otherwise been taken care of, * 0 if caller must take care of it. + * Also used for kicked objects and for polearms/grapnel applied at range. */ int thitmonst(mon, obj) register struct monst *mon; -register struct obj *obj; +register struct obj *obj; /* thrownobj or kickobj or uwep */ { register int tmp; /* Base chance to hit */ register int disttmp; /* distance modifier */ - int otyp = obj->otyp; + int otyp = obj->otyp, hmode; boolean guaranteed_hit = (u.uswallow && mon == u.ustuck); + hmode = (obj == uwep) ? HMON_APPLIED : + (obj == kickobj) ? HMON_KICKED : HMON_THROWN; + /* Differences from melee weapons: * * Dex still gives a bonus, but strength does not. @@ -1287,8 +1293,8 @@ register struct obj *obj; } tmp += omon_adj(mon, obj, TRUE); - if (is_orc(mon->data) && maybe_polyd(is_elf(youmonst.data), - Race_if(PM_ELF))) + if (is_orc(mon->data) && + maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF))) tmp++; if (guaranteed_hit) { tmp += 1000; /* Guaranteed hit */ @@ -1308,8 +1314,9 @@ register struct obj *obj; } /* don't make game unwinnable if naive player throws artifact - at leader.... */ - if (quest_arti_hits_leader(obj, mon)) { + at leader... (kicked artifact is ok too; HMON_APPLIED could + occur if quest artifact polearm or grapnel ever gets added) */ + if (hmode != HMON_APPLIED && quest_arti_hits_leader(obj, mon)) { /* not wakeup(), which angers non-tame monsters */ mon->msleeping = 0; mon->mstrategy &= ~STRAT_WAITMASK; @@ -1336,7 +1343,10 @@ register struct obj *obj; if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || obj->oclass == GEM_CLASS) { - if (is_ammo(obj)) { + if (hmode == HMON_KICKED) { + /* throwing adjustments and weapon skill bonus don't apply */ + tmp -= (is_ammo(obj) ? 5 : 3); + } else if (is_ammo(obj)) { if (!ammo_and_launcher(obj, uwep)) { tmp -= 4; } else { @@ -1358,12 +1368,12 @@ register struct obj *obj; tmp++; } } - } else { + } else { /* thrown non-ammo or applied polearm/grapnel */ if (otyp == BOOMERANG) /* arbitrary */ tmp += 4; else if (throwing_weapon(obj)) /* meant to be thrown */ tmp += 2; - else /* not meant to be thrown */ + else if (obj == thrownobj) /* not meant to be thrown */ tmp -= 2; /* we know we're dealing with a weapon or weptool handled by WEAPON_SKILLS once ammo objects have been excluded */ @@ -1371,7 +1381,7 @@ register struct obj *obj; } if (tmp >= rnd(20)) { - if (hmon(mon,obj,1)) { /* mon still alive */ + if (hmon(mon, obj, hmode)) { /* mon still alive */ cutworm(mon, bhitpos.x, bhitpos.y, obj); } exercise(A_DEX, TRUE); @@ -1411,7 +1421,7 @@ register struct obj *obj; int was_swallowed = guaranteed_hit; exercise(A_DEX, TRUE); - if (!hmon(mon,obj,1)) { /* mon killed */ + if (!hmon(mon, obj, hmode)) { /* mon killed */ if (was_swallowed && !u.uswallow && obj == uball) return 1; /* already did placebc() */ } @@ -1423,7 +1433,7 @@ register struct obj *obj; exercise(A_STR, TRUE); if (tmp >= rnd(20)) { exercise(A_DEX, TRUE); - (void) hmon(mon,obj,1); + (void) hmon(mon, obj, hmode); } else { tmiss(obj, mon, TRUE); } @@ -1431,7 +1441,7 @@ register struct obj *obj; } else if ((otyp == EGG || otyp == CREAM_PIE || otyp == BLINDING_VENOM || otyp == ACID_VENOM) && (guaranteed_hit || ACURR(A_DEX) > rnd(25))) { - (void) hmon(mon, obj, 1); + (void) hmon(mon, obj, hmode); return 1; /* hmon used it up */ } else if (obj->oclass == POTION_CLASS && diff --git a/src/uhitm.c b/src/uhitm.c index c63e38b9b..18eb479de 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -453,7 +453,7 @@ struct attack *uattk; /* we hit the monster; be careful: it might die or be knocked into a different location */ notonhead = (mon->mx != x || mon->my != y); - malive = hmon(mon, weapon, 0); + malive = hmon(mon, weapon, HMON_MELEE); if (malive) { /* monster still alive */ if(!rn2(25) && mon->mhp < mon->mhpmax/2 @@ -514,7 +514,7 @@ boolean /* general "damage monster" routine */ hmon(mon, obj, thrown) /* return TRUE if mon still alive */ struct monst *mon; struct obj *obj; -int thrown; +int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */ { boolean result, anger_guards; @@ -533,7 +533,7 @@ STATIC_OVL boolean hmon_hitmon(mon, obj, thrown) struct monst *mon; struct obj *obj; -int thrown; +int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */ { int tmp; struct permonst *mdat = mon->data; @@ -605,7 +605,8 @@ int thrown; #endif is_pole(obj)) || /* or throw a missile without the proper bow... */ - (is_ammo(obj) && !ammo_and_launcher(obj, uwep))) { + (is_ammo(obj) && (thrown != HMON_THROWN || + !ammo_and_launcher(obj, uwep)))) { /* then do only 1-2 points of damage */ if (mdat == &mons[PM_SHADE] && obj->otyp != SILVER_ARROW) tmp = 0; @@ -690,7 +691,8 @@ int thrown; if (jousting) valid_weapon_attack = TRUE; } #endif - if (thrown && (is_ammo(obj) || is_missile(obj))) { + if (thrown == HMON_THROWN && + (is_ammo(obj) || is_missile(obj))) { if (ammo_and_launcher(obj, uwep)) { /* Elves and Samurai do extra damage using * their bows&arrows; they're highly trained. @@ -924,7 +926,8 @@ int thrown; /* If you throw using a propellor, you don't get a strength * bonus but you do get an increase-damage bonus. */ - if(!thrown || !obj || !uwep || !ammo_and_launcher(obj, uwep)) + if (thrown != HMON_THROWN || !obj || !uwep || + !ammo_and_launcher(obj, uwep)) tmp += dbon(); } @@ -1027,11 +1030,15 @@ int thrown; abuse_dog(mon); monflee(mon, 10 * rnd(tmp), FALSE, FALSE); } - if((mdat == &mons[PM_BLACK_PUDDING] || mdat == &mons[PM_BROWN_PUDDING]) - && obj && obj == uwep - && objects[obj->otyp].oc_material == IRON - && mon->mhp > 1 && !thrown && !mon->mcan - /* && !destroyed -- guaranteed by mhp > 1 */ ) { + if ((mdat == &mons[PM_BLACK_PUDDING] || + mdat == &mons[PM_BROWN_PUDDING]) && + /* pudding is alive and healthy enough to split */ + mon->mhp > 1 && !mon->mcan && + /* iron weapon using melee or polearm hit */ + obj && obj == uwep && + objects[obj->otyp].oc_material == IRON && + (thrown == HMON_MELEE || + (thrown == HMON_APPLIED && is_pole(obj)))) { if (clone_mon(mon, 0, 0)) { pline("%s divides as you hit it!", Monnam(mon)); hittxt = TRUE; @@ -1085,7 +1092,8 @@ int thrown; } else if (destroyed) { if (!already_killed) killed(mon); /* takes care of most messages */ - } else if(u.umconf && !thrown) { + } else if (u.umconf && + (thrown == HMON_MELEE || thrown == HMON_APPLIED)) { nohandglow(mon); if (!mon->mconf && !resist(mon, SPBOOK_CLASS, 0, NOTELL)) { mon->mconf = 1;