From 9e59977c79ae92ce6cf94d9ca025efc85023d1d3 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 1 Jun 2021 17:14:50 -0700 Subject: [PATCH] fix pull request #521 - valk+warrior alignment Valkyrie player monster was set to be chaotic even though valk hero is lawful by default and can also be neutral but not chaotic. Change it to be lawful. Warrior quest monsters attending leader were also chaotic; change to lawful to match revised valk. If hero is a neutral valk then both the player monster and warriors get changed to neutral at start of game (and stay that way even if hero changes alignment). The leader defaults to neutral but gets changed to lawful for lawful valk hero. Attentdant quest monsters with the healer leader were lawful but if they gain enough experience they get promoted to healer, so make them neutral like the latter. I've added some miscellaneous comments and done a small amount of reformatting. Comment about alignment changing in bones applies to all roles that can be played with different alignments, not just to valkyries. It isn't new; I just thought that it ought to be mentioned somewhere. Fixes #521 --- doc/fixes37.0 | 2 ++ src/monst.c | 88 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 63 insertions(+), 27 deletions(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index f3b1e3754..eb60b59df 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -537,6 +537,8 @@ allow killing your quest leader to open the quest give King Arthur Excalibur when moving the cursor to examine the map, have '^' move to next trap even if that trap is displayed with some other symbol (web, vibrating square) +change valkyrie and warrior (valk quest) monsters from chaotic to lawful +change attendant (healer quest) monster from lawful to neutral Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/monst.c b/src/monst.c index 4f837d1b3..1755e3072 100644 --- a/src/monst.c +++ b/src/monst.c @@ -15,6 +15,8 @@ #define WT_ELF 800 #define WT_DRAGON 4500 +/* caveat: in other source files, C('X') is used to convert 'X' into '^X' but + here is it used to make color values be conditionally present or absent */ #ifdef C #undef C #endif @@ -38,27 +40,46 @@ * sounds made (MS_* defines), physical size (MZ_* defines), * resistances, resistances conferred (both MR_* defines), * 3 * flag bitmaps (M1_*, M2_*, and M3_* defines respectively), - * difficulty, symbol color (C(x) macro) + * difficulty, symbol color (C(x) macro). * - * For AT_BREA attacks, '# sides' is ignored; 6 is used for most - * damage types, 25 for sleep, not applicable for death or poison. + * The difficulty was generated in separate array monstr[] with + * values calculated by makedefs, but has been moved into mons[] + * since it rarely changes. If a new monster is added or an old + * one undergoes significant change, 'makedefs -m' can be used to + * create a dummy monstr.c containing the calculated difficulty + * (of everything in mons[], not just any new or changed ones), + * then the value(s) can be plugged in here and monstr.c deleted. + * [Note that some monsters might warrant manually calculated + * difficulty, on a case by case basis, instead of blindly using + * the default value produced by makedefs. Or fix the algoritm + * used by makedefs to generate a more appropriate value....] + * + * TODO: difficulty is closely releated to level; its field ought + * to be moved sooner in the permonst struct so that it can become + * part of LVL() instead of remaining an orphan near the end. */ -#define MON(nam, sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, col) \ - { \ - {(const char *) 0, (const char *) 0, nam}, \ - sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, C(col) \ +#define MON(nam, \ + sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, col) \ + { \ + { (const char *) 0, (const char *) 0, nam }, \ + sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, C(col) \ } -#define MON3(namm, namf, namn, sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, col) \ - { \ - {namm, namf, namn}, \ - sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, C(col) \ +#define MON3(namm, namf, namn, \ + sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, col) \ + { \ + { namm, namf, namn }, \ + sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, C(col) \ } -/* LVL() and SIZ() collect several fields to cut down on number of args - * for MON() +/* LVL() and SIZ() collect several fields to cut down on number of args for + * MON()/MON3(). Some pre-processors limit function-like macros to 15 + * parameters (possibly only pre-ANSI ones these days). */ #define LVL(lvl, mov, ac, mr, aln) lvl, mov, ac, mr, aln #define SIZ(wt, nut, snd, siz) wt, nut, snd, siz -/* ATTK() and A() are to avoid braces and commas within args to MON() */ +/* ATTK() and A() are to avoid braces and commas within args to MON(). + * For AT_BREA attacks, '# sides' is ignored; 6 is used for most + * damage types, 25 for sleep, not applicable for death or poison. + */ #define ATTK(at, ad, n, d) \ { \ at, ad, n, d \ @@ -438,10 +459,11 @@ NEARDATA struct permonst mons_init[] = { M2_NOPOLY | M2_DWARF | M2_STRONG | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 4, CLR_RED), MON("bugbear", S_HUMANOID, LVL(3, 9, 5, 0, -6), (G_GENO | 1), - A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, - NO_ATTK), - SIZ(1250, 250, MS_GROWL, MZ_LARGE), 0, 0, M1_HUMANOID | M1_OMNIVORE, - M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 5, CLR_BROWN), + A(ATTK(AT_WEAP, AD_PHYS, 2, 4), + NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), + SIZ(1250, 250, MS_GROWL, MZ_LARGE), 0, 0, + M1_HUMANOID | M1_OMNIVORE, M2_STRONG | M2_COLLECT, + M3_INFRAVISIBLE | M3_INFRAVISION, 5, CLR_BROWN), MON3("dwarf lord", "dwarf lady", "dwarf leader", S_HUMANOID, LVL(4, 6, 10, 10, 5), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, @@ -2837,7 +2859,12 @@ struct permonst _mons2[] = { M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, 12, HI_DOMESTIC), - MON("valkyrie", S_HUMAN, LVL(10, 12, 10, 1, -1), G_NOGEN, + /* valk is lawful by default; player valk can be neutral, in which case + role_init() will change this monster and 'warrior' to be neutral too; + if a neutral valk leaves a bones file containing neutral warriors, + the latter will magically turn lawful if encountered by a lawful valk + or any non-valk (for bones on the dungeon side of the portal) */ + MON("valkyrie", S_HUMAN, LVL(10, 12, 10, 1, 1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), MR_COLD, 0, @@ -2909,8 +2936,8 @@ struct permonst _mons2[] = { | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, 22, HI_LORD), MON("King Arthur", S_HUMAN, LVL(20, 15, 0, 90, 20), (G_NOGEN | G_UNIQ), - A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10), NO_ATTK, - NO_ATTK, NO_ATTK, NO_ATTK), + A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10), + NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE @@ -2956,8 +2983,8 @@ struct permonst _mons2[] = { | M2_JEWELS | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, 24, HI_LORD), MON("Lord Sato", S_HUMAN, LVL(20, 15, 0, 90, 20), (G_NOGEN | G_UNIQ), - A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10), NO_ATTK, - NO_ATTK, NO_ATTK, NO_ATTK), + A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10), + NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE @@ -2971,9 +2998,11 @@ struct permonst _mons2[] = { M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, 22, HI_DOMESTIC), + /* for a valkyrie hero, Norn's alignment will be changed to match hero's + starting alignment */ MON("Norn", S_HUMAN, LVL(20, 15, 0, 90, 0), (G_NOGEN | G_UNIQ), - A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10), NO_ATTK, - NO_ATTK, NO_ATTK, NO_ATTK), + A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10), + NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1800, 550, MS_LEADER, MZ_HUGE), MR_COLD, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_FEMALE @@ -3165,7 +3194,9 @@ struct permonst _mons2[] = { M2_NOPOLY | M2_ELF | M2_PEACEFUL | M2_COLLECT, M3_INFRAVISION | M3_INFRAVISIBLE, 7, HI_DOMESTIC), #endif - MON("attendant", S_HUMAN, LVL(5, 12, 10, 10, 3), G_NOGEN, + /* attendants used to lawful but have been changed to netural because + grow_up() promotes them to healer and the latter is always neutral */ + MON("attendant", S_HUMAN, LVL(5, 12, 10, 10, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), MR_POISON, 0, @@ -3228,7 +3259,10 @@ struct permonst _mons2[] = { M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT | M2_MAGIC, M3_INFRAVISIBLE, 8, HI_DOMESTIC), - MON("warrior", S_HUMAN, LVL(5, 12, 10, 10, -1), G_NOGEN, + /* warriors used to be chaotic but have been changed to lawful because + grow_up() promotes them to valkyrie; for a valkyrie hero, they might + be changed to neutral at game start; see the valkyrie comment above */ + MON("warrior", S_HUMAN, LVL(5, 12, 10, 10, 1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), 0, 0,