From f930a12fba63e77d63b7a266d517f7ea038cd464 Mon Sep 17 00:00:00 2001 From: Michael Meyer Date: Tue, 21 Nov 2023 12:14:59 -0500 Subject: [PATCH] Make erinyes scale with alignment abuse Consistent with their mythological role of punishing those who had violated societal taboos -- oathbreakers, hosts who attacked their guests, etc -- erinyes scale with the cumulative amount of alignment abuse the hero has committed over the course of the game. This is tracked separately from the alignment record, and cannot be cleared by the hero improving her favor with her god via "good deeds" as the normal alignment record can. Erinyes will gain abilities, levels, and attacks as the hero's alignment abuse worsens. They will also aggravate monsters when near the hero. --- include/align.h | 1 + include/extern.h | 1 + include/monsters.h | 6 ++++-- src/attrib.c | 6 ++++++ src/makemon.c | 2 ++ src/mon.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ src/monmove.c | 4 ++++ src/restore.c | 1 + 8 files changed, 68 insertions(+), 2 deletions(-) diff --git a/include/align.h b/include/align.h index 5375db4cd..ae8b7c4cb 100644 --- a/include/align.h +++ b/include/align.h @@ -10,6 +10,7 @@ typedef schar aligntyp; /* basic alignment type */ typedef struct align { /* alignment & record */ aligntyp type; int record; + unsigned abuse; } align; /* bounds for "record" -- respect initial alignments of 10 */ diff --git a/include/extern.h b/include/extern.h index 588a83be4..17efeecbe 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1759,6 +1759,7 @@ extern void copy_mextra(struct monst *, struct monst *); extern void dealloc_mextra(struct monst *); extern boolean usmellmon(struct permonst *); extern void mimic_hit_msg(struct monst *, short); +extern void adj_erinys(unsigned); /* ### mondata.c ### */ diff --git a/include/monsters.h b/include/monsters.h index a34c662c8..b1bb58edb 100644 --- a/include/monsters.h +++ b/include/monsters.h @@ -2492,12 +2492,14 @@ and spelled this way */ MON("erinys", S_DEMON, LVL(7, 12, 2, 30, 10), (G_HELL | G_NOCORPSE | G_SGROUP | 2), + /* erinys attacks (among other things) are variable depending on your + alignment abuse, can be increased from here by adj_erinys(mon.c) */ A(ATTK(AT_WEAP, AD_DRST, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SILENT, MZ_HUMAN), MR_FIRE | MR_POISON, 0, M1_HUMANOID | M1_POIS, - M2_NOPOLY | M2_DEMON | M2_STALK | M2_HOSTILE | M2_STRONG | M2_NASTY - | M2_FEMALE | M2_COLLECT, + M2_NOPOLY | M2_DEMON | M2_STALK | M2_STRONG | M2_NASTY | M2_FEMALE + | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 10, CLR_RED, ERINYS), MON("barbed devil", S_DEMON, LVL(8, 12, 0, 35, 8), (G_HELL | G_NOCORPSE | G_SGROUP | 2), diff --git a/src/attrib.c b/src/attrib.c index 7b278f864..2bcc6cade 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -1219,8 +1219,14 @@ adjalign(int n) int newalign = u.ualign.record + n; if (n < 0) { + unsigned newabuse = u.ualign.abuse - n; + if (newalign < u.ualign.record) u.ualign.record = newalign; + if (newabuse > u.ualign.abuse) { + u.ualign.abuse = newabuse; + adj_erinys(newabuse); + } } else if (newalign > u.ualign.record) { u.ualign.record = newalign; if (u.ualign.record > ALIGNLIM) diff --git a/src/makemon.c b/src/makemon.c index 92e2282f4..b28d03f8d 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -2129,6 +2129,8 @@ peace_minded(register struct permonst *ptr) return TRUE; if (ptr->msound == MS_NEMESIS) return FALSE; + if (ptr == &mons[PM_ERINYS]) + return !u.ualign.abuse; if (race_peaceful(ptr)) return TRUE; diff --git a/src/mon.c b/src/mon.c index ef5c63519..96c112e6f 100644 --- a/src/mon.c +++ b/src/mon.c @@ -5462,4 +5462,53 @@ check_gear_next_turn(struct monst *mon) { mon->misc_worn_check |= I_SPECIAL; } + +/* make erinyes more dangerous based on your alignment abuse */ +void +adj_erinys(unsigned abuse) +{ + struct permonst *pm = &mons[PM_ERINYS]; + + if (abuse > 5L) { + pm->mflags1 |= M1_SEE_INVIS; + } + if (abuse > 10L) { + pm->mflags1 |= M1_AMPHIBIOUS; + } + if (abuse > 15L) { + pm->mflags1 |= M1_FLY; + } + if (abuse > 20L) { + /* more powerful attack */ + pm->mattk[0].damn = 3; + } + if (abuse > 25L) { + pm->mflags1 |= M1_REGEN; + } + if (abuse > 30L) { + pm->mflags1 |= M1_TPORT_CNTRL; + } + if (abuse > 35L) { + /* second attack */ + pm->mattk[1].aatyp = AT_WEAP; + pm->mattk[1].adtyp = AD_DRST; + pm->mattk[1].damn = 3; + pm->mattk[1].damd = 4; + } + if (abuse > 40L) { + pm->mflags1 |= M1_TPORT; + } + if (abuse > 50L) { + /* third (spellcasting) attack */ + pm->mattk[2].aatyp = AT_MAGC; + pm->mattk[2].adtyp = AD_SPEL; + pm->mattk[2].damn = 3; + pm->mattk[2].damd = 4; + } + + /* also adjust level and difficulty */ + pm->mlevel = min(7 + u.ualign.abuse, 50); + pm->difficulty = min(10 + (u.ualign.abuse / 3), 25); +} + /*mon.c*/ diff --git a/src/monmove.c b/src/monmove.c index 63a7ee7f5..48b346401 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -639,6 +639,10 @@ dochug(register struct monst* mtmp) return 0; } + /* Erinyes will inform surrounding monsters of your crimes */ + if (mdat == &mons[PM_ERINYS] && !mtmp->mpeaceful && m_canseeu(mtmp)) + aggravate(); + /* Shriekers and Medusa have irregular abilities which must be checked every turn. These abilities do not cost a turn when used. */ diff --git a/src/restore.c b/src/restore.c index 2b5a8fccb..b2a487c3c 100644 --- a/src/restore.c +++ b/src/restore.c @@ -692,6 +692,7 @@ restgamestate(NHFILE *nhfp) /* must come after all mons & objs are restored */ relink_timers(FALSE); relink_light_sources(FALSE); + adj_erinys(u.ualign.abuse); /* inventory display is now viable */ iflags.perm_invent = defer_perm_invent; return TRUE;