From 13ff565a6770bfe54631977c54167e4e3bd78e54 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 21 Jan 2024 11:58:44 -0800 Subject: [PATCH] github issue #1201 - Forcefighting webs Issue reported by Umbire: suggestion to always destroy adjacent webs via 'F' if wielding Sting or Fire Brand. Sting already did that; this adds Fire Brand. This also augments the #untrap command when wielding either of those, or any other blade. And rephrases successful untrap message "You remove {the or your} {bear trap or webbing} from Fido." to "You extract Fido from {the or your} {bear trap or web}." since the trap remains intact. Forcefight and #untrap against webs ought to be reconciled to remove [some of] their differences and/or share code. But not by me... Closes #1201 --- include/extern.h | 1 + src/artifact.c | 5 ++-- src/hack.c | 7 +++--- src/trap.c | 63 ++++++++++++++++++++++++++++++++++++------------ 4 files changed, 54 insertions(+), 22 deletions(-) diff --git a/include/extern.h b/include/extern.h index a1c5f2add..67544d1b1 100644 --- a/include/extern.h +++ b/include/extern.h @@ -144,6 +144,7 @@ extern boolean confers_luck(struct obj *) NONNULLPTRS; extern boolean arti_reflects(struct obj *); extern boolean shade_glare(struct obj *) NONNULLPTRS; extern boolean restrict_name(struct obj *, const char *) NONNULLPTRS; +extern boolean attacks(int, struct obj *); extern boolean defends(int, struct obj *); extern boolean defends_when_carried(int, struct obj *); extern boolean protects(struct obj *, boolean); diff --git a/src/artifact.c b/src/artifact.c index fc3a62774..ae8908582 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -70,7 +70,6 @@ static xint16 artidisco[NROFARTIFACTS]; static const struct arti_info zero_artiexist = {0}; /* all bits zero */ static void hack_artifacts(void); -static boolean attacks(int, struct obj *); /* handle some special cases; must be called after u_init() */ static void @@ -536,7 +535,7 @@ restrict_name(struct obj *otmp, const char *name) return FALSE; } -static boolean +boolean attacks(int adtyp, struct obj *otmp) { const struct artifact *weap; @@ -549,7 +548,7 @@ attacks(int adtyp, struct obj *otmp) boolean defends(int adtyp, struct obj *otmp) { - struct artifact *weap; + const struct artifact *weap; if (!otmp) return FALSE; diff --git a/src/hack.c b/src/hack.c index 63050ef55..8ed03de79 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1915,10 +1915,11 @@ domove_fight_web(coordxy x, coordxy y) chance to succeed rather than maybe make two tries */ roll = rn2(uwep ? 20 : (45 - 5 * wskill_minus_2)); - if (uwep && u_wield_art(ART_STING)) { + if (uwep && (u_wield_art(ART_STING) + || (uwep->oartifact && attacks(AD_FIRE, uwep)))) { /* guaranteed success */ - pline("%s cuts through the web!", - bare_artifactname(uwep)); + pline("%s %s through the web!", bare_artifactname(uwep), + u_wield_art(ART_STING) ? "cuts" : "burns"); /* is_blade() includes daggers (which are classified as PIERCE) but doesn't include axes and slashing polearms */ diff --git a/src/trap.c b/src/trap.c index 414e9184a..3338f2e61 100644 --- a/src/trap.c +++ b/src/trap.c @@ -5010,7 +5010,8 @@ could_untrap(boolean verbosely, boolean check_floor) return 1; } -/* Probability of disabling a trap. Helge Hafting */ +/* Probability of disabling a trap. Helge Hafting; + Returns 0 for success, non-0 for failure. */ static int untrap_prob( struct trap *ttmp) /* must not be Null */ @@ -5018,8 +5019,25 @@ untrap_prob( int chance = 3; /* non-spiders are less adept at dealing with webs */ - if (ttmp->ttyp == WEB && !webmaker(gy.youmonst.data)) - chance = 7; /* 3.7: used to be 30 */ + if (ttmp->ttyp == WEB) { + /* this assumes that all fiery artifacts are blades; no need to + make it more complicated unless/until that changes */ + struct obj *wep = (uwep && is_blade(uwep)) ? uwep + : (uswapwep && u.twoweap && is_blade(uswapwep)) + ? uswapwep : NULL; + + /* FIXME? Forcefight of adjacent web works with bare-handed and + martial arts but #untrap of same resorts to !webmaker() chance */ + if (wep && !m_at(ttmp->tx, ttmp->ty)) { + /* primary or secondary weapon is a blade (which includes + daggers but not axes or bladed polearms) */ + if (u_wield_art(ART_STING) || attacks(AD_FIRE, wep)) + chance = 1; + /* else chance stays 3 */ + } else if (!webmaker(gy.youmonst.data)) { + chance = 7; /* 3.7: used to be 30 */ + } + } if (Confusion || Hallucination) chance++; if (Blind) @@ -5040,6 +5058,8 @@ untrap_prob( chance--; } else if (Role_if(PM_RANGER) && chance > 1) chance--; + if (chance < 1) + chance = 1; return rn2(chance); } @@ -5230,10 +5250,13 @@ reward_untrap(struct trap* ttmp, struct monst* mtmp) } } +/* Help a monster out of a bear trap or web, or if no monster is + present, disarm a bear trap or destroy a web. Helge Hafting */ static int -disarm_holdingtrap(struct trap* ttmp) /* Helge Hafting */ +disarm_holdingtrap(struct trap *ttmp) { struct monst *mtmp; + const char *which = the_your[ttmp->madeby_u]; int fails = try_disarm(ttmp, FALSE); if (fails < 2) @@ -5245,18 +5268,26 @@ disarm_holdingtrap(struct trap* ttmp) /* Helge Hafting */ There's no need for a cockatrice test, only the trap is touched */ if ((mtmp = m_at(ttmp->tx, ttmp->ty)) != 0) { mtmp->mtrapped = 0; - You("remove %s %s from %s.", the_your[ttmp->madeby_u], - (ttmp->ttyp == BEAR_TRAP) ? "bear trap" : "webbing", - mon_nam(mtmp)); + You("extract %s from %s %s.", mon_nam(mtmp), + which, (ttmp->ttyp == BEAR_TRAP) ? "bear trap" : "web"); reward_untrap(ttmp, mtmp); - } else { - if (ttmp->ttyp == BEAR_TRAP) { - You("disarm %s bear trap.", the_your[ttmp->madeby_u]); - cnv_trap_obj(BEARTRAP, 1, ttmp, FALSE); - } else /* if (ttmp->ttyp == WEB) */ { - You("succeed in removing %s web.", the_your[ttmp->madeby_u]); - deltrap(ttmp); - } + } else if (ttmp->ttyp == BEAR_TRAP) { + You("disarm %s bear trap.", which); + cnv_trap_obj(BEARTRAP, 1, ttmp, FALSE); + } else if (ttmp->ttyp == WEB) { + struct obj *wep = (uwep && is_blade(uwep)) ? uwep + : (uswapwep && u.twoweap && is_blade(uswapwep)) + ? uswapwep : NULL; + + if (wep && wep->oartifact + && (u_wield_art(ART_STING) || attacks(AD_FIRE, wep))) + pline("%s %s through %s web!", bare_artifactname(uwep), + u_wield_art(ART_STING) ? "cuts" : "burns", which); + else if (wep) + You("cut through %s web.", which); + else + You("succeed in removing %s web.", which); + deltrap(ttmp); } newsym(u.ux + u.dx, u.uy + u.dy); return 1; @@ -5395,7 +5426,7 @@ help_monster_out( return 1; /* Will our hero succeed? */ - if ((uprob = untrap_prob(ttmp)) && !helpless(mtmp)) { + if ((uprob = untrap_prob(ttmp)) != 0 && !helpless(mtmp)) { You("try to reach out your %s, but %s backs away skeptically.", makeplural(body_part(ARM)), mon_nam(mtmp)); return 1;