From 604ed1302dc1969a67e4c73d87ccec0110b984a0 Mon Sep 17 00:00:00 2001 From: copperwater Date: Sun, 12 Jan 2020 16:09:12 -0500 Subject: [PATCH 1/2] Add the Grudge Patch: monsters with natural enmity will fight each other This ultimately derives from Nephi's Grudge Patch back in the 3.4.3 era, plus some updates from SpliceHack and xNetHack. Its primary purpose is to make the dungeon a richer, more interesting place by providing more opportunities for natural monster-to-monster interactions. All of the code necessary to support monster battling was already in place; this merely adds more monster pairs to mm_aggression. Monsters that will fight each other are: - Quest guardians and hostile non-guardians - Angels and demons - Elves and orcs - Hobbits and Nazguls Monsters with a one-sided grudge (where the defending monster may counterattack, but won't use its own turns to retaliate aggressively) are: - Baby purple worms against shriekers (purple worms already had this) - Ravens against floating eyes - Spiders against insects (x and a) - Bats against flying insects - Cats against rats - Woodchucks against the Oracle Pets will never attack other pets, even if they would normally be hostile to each other. --- include/mondata.h | 4 +++ src/mon.c | 77 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/include/mondata.h b/include/mondata.h index e84a09272f..ad766b300a 100644 --- a/include/mondata.h +++ b/include/mondata.h @@ -113,6 +113,10 @@ #define is_bird(ptr) ((ptr)->mlet == S_BAT && !is_bat(ptr)) #define is_giant(ptr) (((ptr)->mflags2 & M2_GIANT) != 0L) #define is_golem(ptr) ((ptr)->mlet == S_GOLEM) +#define is_rat(ptr) \ + (((ptr) == &mons[PM_SEWER_RAT]) || ((ptr) == &mons[PM_GIANT_RAT]) || \ + ((ptr) == &mons[PM_RABID_RAT]) || ((ptr) == &mons[PM_WERERAT]) || \ + ((ptr) == &mons[PM_HUMAN_WERERAT])) #define is_domestic(ptr) (((ptr)->mflags2 & M2_DOMESTIC) != 0L) #define is_demon(ptr) (((ptr)->mflags2 & M2_DEMON) != 0L) #define is_mercenary(ptr) (((ptr)->mflags2 & M2_MERC) != 0L) diff --git a/src/mon.c b/src/mon.c index 6fd50d7f75..2f0c2cafab 100644 --- a/src/mon.c +++ b/src/mon.c @@ -24,6 +24,7 @@ static boolean FDECL(isspecmon, (struct monst *)); static boolean FDECL(validspecmon, (struct monst *, int)); static struct permonst *FDECL(accept_newcham_form, (struct monst *, int)); static struct obj *FDECL(make_corpse, (struct monst *, unsigned)); +static long FDECL(mm_2way_aggression, (struct monst *, struct monst *)); static void FDECL(m_detach, (struct monst *, struct permonst *)); static void FDECL(lifesaved_monster, (struct monst *)); static void FDECL(migrate_mon, (struct monst *, XCHAR_P, XCHAR_P)); @@ -1545,6 +1546,39 @@ long flag; return cnt; } +/* Part of mm_aggression that represents two-way aggression. To avoid having to + * code each case twice, this function contains those cases that ought to + * happen twice, and mm_aggression will call it twice. */ +static long +mm_2way_aggression(magr, mdef) +struct monst *magr, *mdef; +{ + struct permonst *ma = magr->data; + struct permonst *md = mdef->data; + /* Since the quest guardians are under siege, it makes sense to have + them fight hostiles. (But we don't want the quest leader to be in + danger.) + NOTE: But don't let still-peaceful guardians fight hostile guardians if + the hero manages to annoy one of them! */ + if (ma->msound==MS_GUARDIAN && mdef->mpeaceful==FALSE + && !(md->msound == MS_GUARDIAN)) + return ALLOW_M|ALLOW_TM; + + /* elves vs. orcs */ + if(is_elf(ma) && is_orc(md)) + return ALLOW_M|ALLOW_TM; + + /* angels vs. demons */ + if (ma->mlet==S_ANGEL && is_demon(md)) + return ALLOW_M|ALLOW_TM; + + /* hobbits vs Nazguls */ + if (ma == &mons[PM_HOBBIT] && md == &mons[PM_NAZGUL]) + return ALLOW_M|ALLOW_TM; + + return 0; +} + /* Monster against monster special attacks; for the specified monster combinations, this allows one monster to attack another adjacent one in the absence of Conflict. There is no provision for targetting @@ -1555,15 +1589,46 @@ mm_aggression(magr, mdef) struct monst *magr, /* monster that is currently deciding where to move */ *mdef; /* another monster which is next to it */ { + struct permonst *ma, *md; + ma = magr->data; + md = mdef->data; + + /* Don't allow pets to fight each other. */ + if (magr->mtame && mdef->mtame) + return 0; + /* supposedly purple worms are attracted to shrieking because they like to eat shriekers, so attack the latter when feasible */ - if (magr->data == &mons[PM_PURPLE_WORM] - && mdef->data == &mons[PM_SHRIEKER]) + if ((ma == &mons[PM_PURPLE_WORM] || ma == &mons[PM_BABY_PURPLE_WORM]) + && md == &mons[PM_SHRIEKER]) return ALLOW_M | ALLOW_TM; - /* Various other combinations such as dog vs cat, cat vs rat, and - elf vs orc have been suggested. For the time being we don't - support those. */ - return 0L; + + /* Put one-way aggressions below here, and two-way aggressions in + * mm_2way_aggression. */ + + /* woodchucks vs. The Oracle (she has a passive retaliation) */ + if (ma == &mons[PM_WOODCHUCK] && md == &mons[PM_ORACLE]) + return ALLOW_M|ALLOW_TM; + + /* ravens like eyes */ + if (ma == &mons[PM_RAVEN] && md == &mons[PM_FLOATING_EYE]) + return ALLOW_M|ALLOW_TM; + + /* insect-eating bugs vs insects */ + if (ma->mlet == S_SPIDER && (md->mlet == S_ANT || md->mlet == S_XAN)) + return ALLOW_M|ALLOW_TM; + + /* bats vs flying insects */ + if (is_bat(ma) && (md->mlet == S_ANT || md->mlet == S_XAN) && + (md->mflags1 & M1_FLY)) + return ALLOW_M|ALLOW_TM; + + /* cats vs rats */ + if (ma->mlet == S_FELINE && is_rat(md)) + return ALLOW_M|ALLOW_TM; + + /* now test all two-way aggressions both ways */ + return (mm_2way_aggression(magr, mdef) | mm_2way_aggression(mdef, magr)); } /* Monster displacing another monster out of the way */ From 3ef5ea30b5d8a2bee57fb53035703236ceb1db4a Mon Sep 17 00:00:00 2001 From: copperwater Date: Wed, 20 Feb 2019 08:47:07 -0500 Subject: [PATCH 2/2] Lift restriction on pets fighting grudged monsters of too high level Under previous rules, a pet would respect its level checks and not attack a monster it grudged, whereas the monster had no such restriction and would attack the pet with impunity, until either the hero got it away or the pet died. Make it so that if a pet grudges a monster, it will not balk at it being too high of a level. Also fix a case in which a pet at less than 25% health would not attack a monster it grudges, which has the same problem that the grudged monster will continue to attack it freely. --- include/extern.h | 1 + src/dogmove.c | 2 +- src/mon.c | 3 +-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/extern.h b/include/extern.h index 6df34ea711..2f75d45910 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1433,6 +1433,7 @@ E int FDECL(curr_mon_load, (struct monst *)); E int FDECL(max_mon_load, (struct monst *)); E int FDECL(can_carry, (struct monst *, struct obj *)); E int FDECL(mfndpos, (struct monst *, coord *, long *, long)); +E long FDECL(mm_aggression, (struct monst *, struct monst *)); E boolean FDECL(monnear, (struct monst *, int, int)); E void NDECL(dmonsfree); E void FDECL(elemental_clog, (struct monst *)); diff --git a/src/dogmove.c b/src/dogmove.c index a70c9c70ab..3d226d24f8 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -1015,7 +1015,7 @@ int after; /* this is extra fast monster movement */ || ((mtmp->mhp * 4 < mtmp->mhpmax || mtmp2->data->msound == MS_GUARDIAN || mtmp2->data->msound == MS_LEADER) && mtmp2->mpeaceful - && !Conflict) + && !(mm_aggression(mtmp, mtmp2) & ALLOW_M) && !Conflict) || (touch_petrifies(mtmp2->data) && !resists_ston(mtmp))) continue; diff --git a/src/mon.c b/src/mon.c index 2f0c2cafab..21ebf907f7 100644 --- a/src/mon.c +++ b/src/mon.c @@ -15,7 +15,6 @@ static void FDECL(sanity_check_single_mon, (struct monst *, BOOLEAN_P, const char *)); static boolean FDECL(restrap, (struct monst *)); -static long FDECL(mm_aggression, (struct monst *, struct monst *)); static long FDECL(mm_displacement, (struct monst *, struct monst *)); static int NDECL(pick_animal); static void FDECL(kill_eggs, (struct obj *)); @@ -1584,7 +1583,7 @@ struct monst *magr, *mdef; in the absence of Conflict. There is no provision for targetting other monsters; just hand to hand fighting when they happen to be next to each other. */ -static long +long mm_aggression(magr, mdef) struct monst *magr, /* monster that is currently deciding where to move */ *mdef; /* another monster which is next to it */