From 5eb262c76429b1bd30f935d9dbfda07844d686be Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Thu, 25 Jan 2024 21:00:06 -0500
Subject: [PATCH 01/21] Add difficulty to .tab data

---
 src/allmain.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/allmain.c b/src/allmain.c
index 9e3b90066..df058321c 100644
--- a/src/allmain.c
+++ b/src/allmain.c
@@ -3830,7 +3830,7 @@ printDPR(){
 	struct attack *attk;
 	rfile = fopen_datafile("MonDPR.tab", "w", SCOREPREFIX);
 	if (rfile) {
-		Sprintf(pbuf,"Number\tName\tclass\taverage\tmax\tper-hit avg\tper-hit max\tspeed\talignment\tunique?\n");
+		Sprintf(pbuf,"Number\tName\tclass\tdifficulty\taverage\tmax\tper-hit avg\tper-hit max\tspeed\talignment\tunique?\n");
 		fprintf(rfile, "%s", pbuf);
 		fflush(rfile);
 		for(j=0;j<NUMMONS;j++){
@@ -3856,7 +3856,7 @@ printDPR(){
 						maxperhit = attk->damn * attk->damd;
 				}
 			}
-			Sprintf(pbuf,"%d\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%s\n", j, mons[j].mname, mons[j].mlet,avdm, mdm, avgperhit, maxperhit, mons[j].mmove,ptr->maligntyp,(mons[j].geno&G_UNIQ) ? "unique":"");
+			Sprintf(pbuf,"%d\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%s\n", j, mons[j].mname, mons[j].mlet,monstr[j],avdm, mdm, avgperhit, maxperhit, mons[j].mmove,ptr->maligntyp,(mons[j].geno&G_UNIQ) ? "unique":"");
 			fprintf(rfile, "%s", pbuf);
 			fflush(rfile);
 		}

From 1d4107393428c57c850bfcd759a0d242d7ecb2c9 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Mon, 29 Jan 2024 13:31:05 -0500
Subject: [PATCH 02/21] Show "Held" status on status (Noisytoot)

---
 src/botl.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/botl.c b/src/botl.c
index 8a0f3b19d..13fffeb05 100644
--- a/src/botl.c
+++ b/src/botl.c
@@ -590,6 +590,12 @@ do_statuseffects(char *newbot2, boolean terminal_output, int abbrev, int statusl
   if(FaintingFits)
     status_effect("Faint", "Fnt", "Fnt");
 /** Less important **/
+  if(u.ustuck) {
+    if(sticks(&youmonst) && !u.uswallow)
+      status_effect("UHold", "UHld", "UHd");
+    else
+      status_effect("Held", "Hld", "Hd");
+  }
   if(Levitation)
     status_effect("Lev", "Lev", "Lv");
   /* flying and levitation are mutually exclusive */

From e0e9227a1bb37f343a3bb5e78e649630170c4c56 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Mon, 29 Jan 2024 13:32:18 -0500
Subject: [PATCH 03/21] Inspection bugfix: Do not show artifact stats unless
 the item is known

Sub artifact = 0 otherwise
---
 src/invent.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/invent.c b/src/invent.c
index d27861558..ae0582189 100644
--- a/src/invent.c
+++ b/src/invent.c
@@ -2655,7 +2655,9 @@ winid *datawin;
 	if (obj)
 	{
 		otyp = obj->otyp;
-		oartifact = obj->oartifact;
+		if(obj->known)
+			oartifact = obj->oartifact;
+		else oartifact = 0;
 	}
 	struct objclass oc = objects[otyp];
 	char olet = oc.oc_class;

From 2447873710decd174db3cbd54c5d2d69a97be8a4 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Mon, 29 Jan 2024 18:27:35 -0500
Subject: [PATCH 04/21] Bugfix: Be more restrictive when handing out necromancy
 faction

Should still be limited to orcs and undead, not any hostile monster that happens to generate (and DEFINITELY not hostile elves).
---
 src/makemon.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/makemon.c b/src/makemon.c
index 66cd783ed..a388970b6 100644
--- a/src/makemon.c
+++ b/src/makemon.c
@@ -13240,9 +13240,7 @@ struct monst * mon;
 		|| (mon->mtyp == PM_STAR_ELF && Role_if(PM_MADMAN))
 	)
 		out_faction = YELLOW_FACTION;
-	else if(In_quest(&u.uz) && urole.neminum == PM_NECROMANCER && !peaceful)
-		out_faction = NECROMANCY_FACTION;
-	else if(In_mordor_quest(&u.uz) && !peaceful)
+	else if((In_mordor_quest(&u.uz) || (In_quest(&u.uz) && urole.neminum == PM_NECROMANCER)) && (is_orc(mon->data) || is_undead(mon->data)))
 		out_faction = NECROMANCY_FACTION;
 	else if(Is_knox(&u.uz)
 		|| Is_sanctum(&u.uz)

From f9b4913e7d9538ce2ffd565279dee51e699f7f4d Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Mon, 29 Jan 2024 18:28:18 -0500
Subject: [PATCH 05/21] Bugfix: Don't re-set throne room factions if already
 used.

Affects lethe manse thonerooms (yendorian vs. illsensine)
---
 src/mkroom.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/mkroom.c b/src/mkroom.c
index b6f6d20d7..1d6c06884 100644
--- a/src/mkroom.c
+++ b/src/mkroom.c
@@ -7131,7 +7131,8 @@ struct mkroom *sroom;
 							set_curhouse(mon->mfaction);
 						}
 						//Note: court monsters are always part of rodney's forces.
-						set_faction(mon, YENDORIAN_FACTION);
+						if(!mon->mfaction)
+							set_faction(mon, YENDORIAN_FACTION);
 						if(mon->mpeaceful){
 							mon->mpeaceful = 0;
 							set_malign(mon);
@@ -7212,7 +7213,8 @@ struct mkroom *sroom;
 				}
 				if (type==COURT) {
 					//Note: court monsters are always part of rodney's forces, even if they are angels.
-					set_faction(mon, YENDORIAN_FACTION);
+					if(!mon->mfaction)
+						set_faction(mon, YENDORIAN_FACTION);
 					if(mon->mpeaceful){
 						mon->mpeaceful = 0;
 						set_malign(mon);

From fdcf5dac558c37ff518182215e0719ece22329b9 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Mon, 29 Jan 2024 18:31:21 -0500
Subject: [PATCH 06/21] Witches are wierdly light

- So, logically--
- If she weighs the same as a duck...
- she's made of wood.
- And therefore?
- A witch!
---
 src/monst.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/monst.c b/src/monst.c
index 8435cb969..a8ee36b93 100644
--- a/src/monst.c
+++ b/src/monst.c
@@ -9197,7 +9197,7 @@ is a red right hand
 	LVL(10, 12, 45, 0),  (G_DEPTHS|3),
 	DEF(SPE_AC(4)),
 	A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MMGC, AD_CLRC, 1, 6)),
-	SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), MR_MAGIC, 0,
+	SIZ(WT_HUMAN/2, 400, MS_HUMANOID, MZ_HUMAN), MR_MAGIC, 0,
 	MM_FLY /*MM*/, MT_OMNIVORE|MT_COLLECT|MT_MAGIC /*MT*/, MF_LEVEL_30 /*MF*/,
 	MB_HUMANOID|MB_STRONG|MB_FEMALE /*MB*/, MG_NOWISH|MG_NOPOLY|MG_INFRAVISIBLE|MG_NOSPELLCOOLDOWN /*MG*/,
 	MA_HUMAN /*MA*/,  MV_NORMAL /*MV*/, 0 /*MW*/, CLR_BLACK),
@@ -9205,7 +9205,7 @@ is a red right hand
 	LVL(20, 16, 60, 0), (G_NOGEN),
 	DEF(SPE_AC(8), SPE_DR(4)),
 	A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_CLRC, 2, 6)),
-	SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), MR_MAGIC, 0,
+	SIZ(WT_HUMAN/10, 400, MS_HUMANOID, MZ_HUMAN), MR_MAGIC, 0,
 	MM_FLY /*MM*/, MT_CLOSE|MT_OMNIVORE|MT_COLLECT|MT_MAGIC /*MT*/, 0 /*MF*/,
 	MB_HUMANOID|MB_FEMALE|MB_STRONG /*MB*/, MG_NOWISH|MG_NOTAME|MG_NOPOLY|MG_INFRAVISIBLE|MG_LORD|MG_NOSPELLCOOLDOWN /*MG*/,
 	MA_HUMAN /*MA*/,  MV_NORMAL /*MV*/, 0 /*MW*/, CLR_MAGENTA),

From ecfc62216ce7504c49a33f0023a0d5c3519e3b3a Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Fri, 2 Feb 2024 16:46:01 -0500
Subject: [PATCH 07/21] Change MAD_FORGETFUL effects

Removed: level-drain and amnesia on double-trigger.

Added:
-Lose up to 666 xp (scaled by insanity % squared)
-for each skill, lose 1 point of practice if madness is rolled.

-If practice dips below the required level for a skill, de-train the skill (refunding any skill points)
-If xp dips below the required level for your xp level, drain a level (only 1 level is drained at a time, and XP is reset to 1 less than max for the level. So only one level will be drained per turn.)
--666xp is far less than the number required for the highest levels, so a 30th level PC will be at limited risk from this effect.
---
 include/extern.h |  2 ++
 src/allmain.c    | 13 ++++++-------
 src/exper.c      | 16 ++++++++++++++++
 src/weapon.c     | 35 +++++++++++++++++++++++++++++++++++
 4 files changed, 59 insertions(+), 7 deletions(-)

diff --git a/include/extern.h b/include/extern.h
index a18fd515e..8961454f0 100644
--- a/include/extern.h
+++ b/include/extern.h
@@ -954,6 +954,7 @@ E long FDECL(newuexp, (int));
 E int FDECL(experience, (struct monst *,int));
 E int FDECL(ptrexperience, (struct permonst *));
 E void FDECL(more_experienced, (int,int));
+E void FDECL(lose_experience, (int));
 E void FDECL(losexp, (const char *,BOOLEAN_P,BOOLEAN_P,BOOLEAN_P));
 E void NDECL(newexplevel);
 E void NDECL(binderup);
@@ -3266,6 +3267,7 @@ E void FDECL(restrict_weapon_skill, (int));
 E void FDECL(expert_weapon_skill, (int));
 E void FDECL(skilled_weapon_skill, (int));
 E void FDECL(use_skill, (int,int));
+E void FDECL(lose_skill, (int,int));
 E void FDECL(add_weapon_skill, (int));
 E void FDECL(lose_weapon_skill, (int));
 E int FDECL(weapon_type, (struct obj *));
diff --git a/src/allmain.c b/src/allmain.c
index df058321c..16ac6f9ec 100644
--- a/src/allmain.c
+++ b/src/allmain.c
@@ -2437,15 +2437,14 @@ karemade:
 				if(moves%5 && roll_madness(MAD_SPIRAL))
 					change_usanity(-1, FALSE);
 			}
-			//Mind dissolution double trigger: lose 1d4 levels
-			if(u.ulevel > 1 && roll_madness(MAD_FORGETFUL) && roll_madness(MAD_FORGETFUL)){
+			//Mind dissolution xp loss
+			if(u.ulevel > 1 && u.umadness&MAD_FORGETFUL && !BlockableClearThoughts){
 				int i;
-				int pre_drain = u.ulevel;
-				for(i = rn2(4); i > 0 && u.ulevel > 2; i--){
-					losexp("mind dissolution",FALSE,TRUE,TRUE);
+				lose_experience(666*NightmareAware_Insanity*NightmareAware_Insanity/(100*100));
+				for(i = 1; i < P_NUM_SKILLS; i++){
+					if(roll_madness(MAD_FORGETFUL))
+						lose_skill(i,1);
 				}
-				losexp("mind dissolution",TRUE,TRUE,TRUE);
-				forget((pre_drain - u.ulevel) * 100/(pre_drain)); //drain some proportion of your memory
 			}
 			
 			if(mad_turn(MAD_HOST)){
diff --git a/src/exper.c b/src/exper.c
index c6d71e74b..bf883acf0 100644
--- a/src/exper.c
+++ b/src/exper.c
@@ -213,6 +213,22 @@ more_experienced(exp, rexp)
 		flags.beginner = 0;
 }
 
+void
+lose_experience(exp)
+	register int exp;
+{
+	if(!exp)
+		return;
+	u.uexp = max(u.uexp - exp, 0);
+	if(exp
+#ifdef SCORE_ON_BOTL
+	   || flags.showscore
+#endif
+	   ) flags.botl = 1;
+	if (u.ulevel > 1 && u.uexp < newuexp(u.ulevel-1))
+	    losexp("lost experience",FALSE,FALSE,FALSE);
+}
+
 void
 losexp(drainer,verbose,force,expdrain)		/* e.g., hit by drain life attack */
 const char *drainer;	/* cause of death, if drain should be fatal */
diff --git a/src/weapon.c b/src/weapon.c
index e189e5846..487aa2e9c 100644
--- a/src/weapon.c
+++ b/src/weapon.c
@@ -3351,6 +3351,41 @@ int degree;
     }
 }
 
+void
+lose_skill(skill,degree)
+int skill;
+int degree;
+{
+	if(skill < 0) skill *= -1;
+	
+    if (skill == P_NONE)
+		return;
+
+	if(P_ADVANCE(skill) > degree)
+		P_ADVANCE(skill)-=degree;
+	else P_ADVANCE(skill) = 0;
+
+	boolean try_reduce = TRUE; //Don't get stuck in an infinite loop if skill's default value is > P_UNSKILLED
+	while(OLD_P_SKILL(skill) > P_UNSKILLED
+	 && P_ADVANCE(skill) < practice_needed_to_advance(OLD_P_SKILL(skill)-1)
+	 && try_reduce
+	) {
+		try_reduce = FALSE;
+		for(int i = u.skills_advanced-1; i >= 0; i--){
+			if(skill == u.skill_record[i]){
+				try_reduce = TRUE;
+				OLD_P_SKILL(skill)--;
+				u.weapon_slots += slots_required(skill);
+				for(int j = i+1; j < u.skills_advanced; j++, i++){
+					u.skill_record[i] = u.skill_record[j];
+				}
+				u.skills_advanced--;
+				break; //End outer skill-finding loop
+			}
+		}
+	}
+}
+
 void
 add_weapon_skill(n)
 int n;	/* number of slots to gain; normally one */

From 267844962ff8cc902a27b6a48f423029e4034f8a Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sat, 3 Feb 2024 19:49:16 -0500
Subject: [PATCH 08/21] Amalgamated Skies pt 2: upgrades

Mantras: Permanent upgrades learned from the Sky Reflected/Amalgamated Skies. Read via #invoke.
Tracked via a avar field on the Sky Reflected
-Anger (<8 wis, wis+int > 21, Insantiy > 75): Magic missile spells use d8s instead of d6s
-Steel (wis + int > 23): enchantment+1 bonus to-hit, +1 AC, pets get +1 to hit and +1 AC. Pets get +1 level on saves.
-Will (wis + int > 27): Upgrade protection spell: Take 1/2 spell damage when active (stacks with half spell damage). Pets get +10 MR.
-Eye (wis + int > 29): Upgrade invisibility: Monsters must save vs. spells when trying to sense you if you're invisible
-Power (wis + int > 31): Upgrade 25 Str while wielding a "Sky" artifact. Pets get +8 damage.
-Balance (wis + int > 34): Upgrade protection spell: Deals 8 damage to all surounding enemies when struck in melee.
-Patience (wis + int > 37): Pet xp threshold improved by 8. Force bolt deals +10d12 damage at 30th level.
-Focus (wis + int > 40): Boosts "Crit" chance with Gith Silver Sword weapons (up to +3 at 96 sanity)

Fighting styles ("Mental Edges"): Fighting styles employable with the Silver Sky/Amalgamated Skies. The PC must be at least 14th level for most styles. Adjust via #style.
-Penetrate (<50 San, level 14+): Up to 50% minium die rolls (stacks with great weapon fighting)
-Cold (<50 San, level 14+, 9+ insight): Up to +6d6 cold and 3d9 unholy
-Defense (>50 San, level 14+): Applies up to 5+spe to your AC, Applies up to 3+spe/2 to pet AC and DR
-Antimagic (>50 San, level 14+): Sets target cooldown, may cancel target
-Resonant (>50 San, level 30, 81+ insight): Boosts "Crit" effects with Gith Silver Sword weapons, speeding and encouraging pets and slowing and discouraging nearby enemies. Pets get up to +8 damage.
---
 include/artifact.h |  19 +++++
 include/extern.h   |   4 ++
 src/artifact.c     | 171 ++++++++++++++++++++++++++++++++++++++++++---
 src/attrib.c       |  73 +++++++++++++++++++
 src/cmd.c          | 104 ++++++++++++++++++++++++++-
 src/do_wear.c      |  10 +++
 src/makemon.c      |  17 +++--
 src/mon.c          |   4 ++
 src/weapon.c       |  28 ++++++--
 src/worn.c         |  43 ++++++++++++
 src/xhity.c        |  19 +++++
 src/zap.c          |  16 ++++-
 12 files changed, 484 insertions(+), 24 deletions(-)

diff --git a/include/artifact.h b/include/artifact.h
index f3409ee77..386e1a16c 100644
--- a/include/artifact.h
+++ b/include/artifact.h
@@ -313,12 +313,31 @@ struct artinstance{
 #define	IPROP_BRANCHPORT	0x00000020L
 #define	IPROP_REFLECT	0x00000040L
 #define	ALL_IPROP		(0x0000000FL|IPROP_LEVELPORTIPROP_BRANCHPORT|IPROP_REFLECT)
+#define ZerthUpgrades avar1
+#define	ZPROP_WRATH		0x00000001L
+#define	ZPROP_STEEL		0x00000002L
+#define	ZPROP_WILL		0x00000004L
+#define	ZPROP_VILQUAR	0x00000008L
+#define	ZPROP_POWER		0x00000010L
+#define	ZPROP_BALANCE	0x00000020L
+#define	ZPROP_PATIENCE	0x00000040L
+#define	ZPROP_FOCUS		0x00000080L
+
 	long avar2;
 #define SnSd2 avar2
 #define RoSPflights avar2
 #define RRSlunar avar2
 #define PlagueDoOnHit avar2
 #define IbiteFavor avar2
+#define GithStyle avar2
+#define	GSTYLE_PENETRATE	1
+#define	GSTYLE_COLD			2
+#define	GSTYLE_DEFENSE		3
+#define	GSTYLE_ANTIMAGIC	4
+#define	GSTYLE_RESONANT		5
+#define FIRST_GSTYLE		GSTYLE_PENETRATE
+#define LAST_GSTYLE			GSTYLE_RESONANT
+
 	long avar3;
 #define SnSd3 avar3
 #define IbiteBoons avar3
diff --git a/include/extern.h b/include/extern.h
index 8961454f0..c0a3f540a 100644
--- a/include/extern.h
+++ b/include/extern.h
@@ -238,11 +238,14 @@ E void FDECL(adjalign, (int));
 E void FDECL(unSetFightingForm, (int));
 E void FDECL(setFightingForm, (int));
 E boolean FDECL(activeFightingForm, (int));
+E boolean FDECL(activeMentalEdge, (int));
 E boolean FDECL(selectedFightingForm, (int));
 E int FDECL(getFightingFormSkill, (int));
+E const char * FDECL(nameOfMentalEdge, (int));
 E const char * FDECL(nameOfFightingForm, (int));
 E void NDECL(validateLightsaberForm);
 E boolean FDECL(blockedFightingForm, (int));
+E boolean FDECL(blockedMentalEdge, (int));
 E int NDECL(uhp);
 E int NDECL(uhpmax);
 E void NDECL(check_brainlessness);
@@ -290,6 +293,7 @@ E void FDECL(bot3str, (char *, boolean, int));
 
 
 E char NDECL(randomkey);
+E int NDECL(doGithForm);
 #ifdef USE_TRAMPOLI
 E int NDECL(doextcmd);
 E int NDECL(domonability);
diff --git a/src/artifact.c b/src/artifact.c
index 7620a36cc..e1739f885 100644
--- a/src/artifact.c
+++ b/src/artifact.c
@@ -3194,7 +3194,7 @@ struct obj *otmp;
 struct monst *mon;
 boolean youagr;
 {
-	register const struct artifact *weap = get_artifact(otmp);
+	const struct artifact *weap = get_artifact(otmp);
 	int bonus = 0;
 	/* no need for an extra check for `NO_ATTK' because this will
 	   always return 0 for any artifact which has that attribute */
@@ -3206,6 +3206,9 @@ boolean youagr;
 	}
 	if(youagr && Role_if(PM_BARD)) //legend lore
 		bonus += 5;
+
+	if(weap && (weap->inv_prop == GITH_ART || weap->inv_prop == ZERTH_ART || weap->inv_prop == AMALGUM_ART) && (artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_STEEL))
+		bonus += otmp->spe+1;
 	
 	if(youagr && Role_if(PM_PRIEST)) return bonus + weap->accuracy; //priests always get the maximum to-hit bonus.
 	
@@ -3438,6 +3441,26 @@ winid tmpwin;		/* supplied by dodiscover() */
 
 #ifdef OVLB
 
+boolean
+near_yourteam(mon)
+struct monst *mon;
+{
+	struct monst *mnear;
+	for(int x = mon->mx-1; x < mon->mx+2; x++){
+		for(int y = mon->my-1; y < mon->my+2; y++){
+			if(!isok(x,y))
+				continue;
+			mnear = m_u_at(x, y);
+			if(!mnear)
+				continue;
+			if(mnear == &youmonst)
+				return TRUE;
+			if(mnear->mtame)
+				return TRUE;
+		}
+	}
+	return FALSE;
+}
 
 	/*
 	 * Magicbane's intrinsic magic is incompatible with normal
@@ -4273,6 +4296,7 @@ int * truedmgptr;
 	struct permonst * pd = (youdef ? youracedata : mdef->data);
 	int original_plusdmgptr = *plusdmgptr;
 	int original_truedmgptr = *truedmgptr;
+	const struct artifact *oart = get_artifact(otmp);
 	
 	if(!Fire_res(mdef)){
 		if(check_oprop(otmp, OPROP_FIREW))
@@ -4514,13 +4538,33 @@ int * truedmgptr;
 			*truedmgptr += d(2, 12);
 	}
 	if(check_oprop(otmp, OPROP_GSSDW)){
-		int power = youagr ? u.uinsight : magr ? magr->m_lev : 0;
+		int power = youagr ? min(u.uinsight, u.usanity) : magr ? magr->m_lev : 0;
 		//"Crit" chance
 		if(power > 0){
 			int multiplier = power >= 50 ? 3 : power >= 25 ? 2 : 1; 
-			int chance = power >= 50 ? 5 : power >= 25 ? 10 : 20; 
-			if(!rn2(chance))
-			*truedmgptr += multiplier*basedmg;
+			int chance = power >= 50 ? 4 : power >= 25 ? 3 : 2;
+			if(u.usanity > 80 &&(oart->inv_prop == GITH_ART || oart->inv_prop == ZERTH_ART || oart->inv_prop == AMALGUM_ART) && artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_FOCUS)
+				chance += (u.usanity-81)/5;//0, 1, 2, or 3 starting at 81, 86, 91, 96
+			if(rn2(20) < chance){
+				*truedmgptr += multiplier*basedmg;
+				if(otmp->oartifact){
+					const struct artifact *weap = get_artifact(otmp);
+					if((weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART) && activeMentalEdge(GSTYLE_RESONANT)){
+						for(struct monst *tmon = fmon; tmon; tmon = tmon->nmon){
+							if(DEADMONSTER(tmon))
+								continue;
+							if(tmon->mtame){
+								tmon->movement += 12;
+								tmon->encouraged += u.usanity < 50 ? 0 : u.usanity < 75 ? 2 : u.usanity < 90 ? 5 : 8;
+							}
+							else if(near_yourteam(tmon)){
+								tmon->movement -= 12;
+								tmon->encouraged -= u.usanity < 50 ? 0 : u.usanity < 75 ? 2 : u.usanity < 90 ? 5 : 8;
+							}
+						}
+					}
+				}
+			}
 		}
 		//Bonus psychic damage (More reliable than regular psychic damage)
 		if(youdef || !mindless_mon(mdef)){
@@ -7160,6 +7204,38 @@ boolean printmessages; /* print generic elemental damage messages */
 			}
 		}
 	}
+
+	if(youagr && otmp->oartifact){
+		const struct artifact *weap = get_artifact(otmp);
+		if((weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART)){
+			if(activeMentalEdge(GSTYLE_COLD)){
+				if(!Cold_res(mdef))
+					(*truedmgptr) += u.usanity > 50 ? 0 : u.usanity > 25 ? d(2,6) : u.usanity > 10 ? d(4,6) : d(6,6);
+				if(hates_unholy_mon(mdef))
+					(*truedmgptr) += u.usanity > 50 ? 0 : u.usanity > 25 ? d(1,9) : u.usanity > 10 ? d(2,9) : d(3,9);
+			}
+			if(activeMentalEdge(GSTYLE_ANTIMAGIC)){
+				int major_chance = u.usanity < 50 ? 0 : u.usanity < 75 ? 1 : u.usanity < 90 ? 2 : 5;
+				if(youdef){
+					if(u.uen > 0){
+						u.uen -= u.usanity/10;
+						flags.botl = 1;
+					}
+					if(rn2(20) < major_chance){
+						if(u.uen > 0){
+							u.uen = max(u.uen-400, 0);
+							flags.botl = 1;
+						}
+					}
+				}
+				else {
+					mdef->mspec_used += rnd(u.usanity/10);
+					if(rn2(20) < major_chance)
+						set_mcan(mdef, TRUE);
+				}
+			}
+		}
+	}
 	
 	if(otmp->oartifact == ART_ESSCOOAHLIPBOOURRR){
 		if(artinstance[otmp->oartifact].Esscoo_mid == mdef->m_id)
@@ -7811,6 +7887,83 @@ static NEARDATA const char invoke_types[] = { ALL_CLASSES, 0 };
 		/* #invoke: an "ugly check" filters out most objects */
 
 
+void
+zerth_mantras()
+{
+	pline("There are mantras wound around the grip.");
+	//Reign of Anger (MM)
+	if(ACURR(A_WIS) < 8 && ACURR(A_WIS)+ACURR(A_INT) > 21 && Insanity > 75 && !(artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_WRATH)){
+		// Modifies MM spell, +1 damage per die (implemented as +2 faces)
+		You("decipher a new mantra!");
+		pline("\"Greed and hates, pains and joys, jealousies and doubts. All of these fed on each other and the minds of the People were divided. In their division, the People were punished.\"");
+		artinstance[ART_SKY_REFLECTED].ZerthUpgrades |= ZPROP_WRATH;
+		more_experienced(300, 0);
+		newexplevel();
+	}
+	//Scripture of Steel (+1 to-hit and +1 to pet saves)
+	else if(ACURR(A_WIS)+ACURR(A_INT) > 23 && !(artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_STEEL)){
+		You("decipher a new mantra!");
+		pline("\"*Know* that flesh cannot mark steel. *Know* that steel may mark flesh.\"");
+		artinstance[ART_SKY_REFLECTED].ZerthUpgrades |= ZPROP_STEEL;
+		more_experienced(600, 0);
+		newexplevel();
+	}
+	//Submerge the Will (Protection + Saves)
+	else if(ACURR(A_WIS)+ACURR(A_INT) > 27 && !(artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_WILL)){
+		// Modifies protection spell, grants half magic damage while active, pets get +10 mr
+		You("decipher a new mantra!");
+		pline("\"Lashed upon the Pillars, Zerthimon moved his mind to a place where pain could not reach, leaving his body behind.\"");
+		artinstance[ART_SKY_REFLECTED].ZerthUpgrades |= ZPROP_WILL;
+		more_experienced(900, 0);
+		newexplevel();
+	}
+	//Vilquar's Eye (Blindness)
+	else if(ACURR(A_WIS)+ACURR(A_INT) > 29 && !(artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_VILQUAR)){
+		// Modifies invis effects, monsters must roll vs. resist to see you
+		You("decipher a new mantra!");
+		pline("\"Vilquar's eye was filled only with the reward he had been promised. He would see what he wished to see.\"");
+		artinstance[ART_SKY_REFLECTED].ZerthUpgrades |= ZPROP_VILQUAR;
+		more_experienced(1500, 0);
+		newexplevel();
+	}
+	//Power of One (Strength)
+	else if(ACURR(A_WIS)+ACURR(A_INT) > 31 && !(artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_POWER)){
+		// Grants 25 str while wielded, bonus damage for pets
+		You("decipher a new mantra!");
+		pline("\"The strength of her *knowing* was so great, that all those that walked her path came to *know* themselves.\"");
+		artinstance[ART_SKY_REFLECTED].ZerthUpgrades |= ZPROP_POWER;
+		more_experienced(3000, 0);
+		newexplevel();
+	}
+	//Balance in All Things
+	else if(ACURR(A_WIS)+ACURR(A_INT) > 34 && !(artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_BALANCE)){
+		// Modifies protection spell, monsters take damage when attacking
+		You("decipher a new mantra!");
+		pline("\"From the Separation of the People, came the *knowing* of Two Skies. From the *knowing* of Two Skies came the realization that hurting others, hurts oneself.\"");
+		artinstance[ART_SKY_REFLECTED].ZerthUpgrades |= ZPROP_BALANCE;
+		more_experienced(5000, 0);
+		newexplevel();
+	}
+	//Missile of Patience
+	else if(ACURR(A_WIS)+ACURR(A_INT) > 37 && !(artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_PATIENCE)){
+		// Modifies Force Bolt
+		You("decipher a new mantra!");
+		pline("\"*Know* that the Rising of the People against the *illithid* was a thing built upon many turnings.\"");
+		artinstance[ART_SKY_REFLECTED].ZerthUpgrades |= ZPROP_PATIENCE;
+		more_experienced(8000, 0);
+		newexplevel();
+	}
+	//Zerthimon's Focus
+	else if(ACURR(A_WIS)+ACURR(A_INT) > 40 && !(artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_FOCUS)){
+		// Modifies "crit" chance, proportional to sanity
+		You("decipher a new mantra!");
+		pline("\"A divided mind is one that does not *know* itself. When it is divided, it cleaves the body in two. When one has a single purpose, the body is strengthened. In *knowing* the self, grow strong.\"");
+		artinstance[ART_SKY_REFLECTED].ZerthUpgrades |= ZPROP_FOCUS;
+		more_experienced(16000, 0);
+		newexplevel();
+	}
+}
+
 int
 ibite_upgrade_menu(obj)
 struct obj *obj;
@@ -11384,11 +11537,11 @@ arti_invoke(obj)
 			}
 		}break;
 		case GITH_ART:{
+			doGithForm();
 		}break;
+		case AMALGUM_ART:
 		case ZERTH_ART:{
-			pline("There are mantras wound around the grip.");
-		}break;
-		case AMALGUM_ART:{
+			zerth_mantras();
 		}break;
 		case MORGOTH:{
 			int base_otyp = find_good_iring();
@@ -14102,7 +14255,7 @@ struct obj **opptr;
 				obfree(amalgam, (struct obj *)0);	/* get rid of the useless non-artifact */
 			return MOVE_CANCELLED;
 		}
-		pline("%s and %s melt and disolve into each-other!", The(xname(sky1)), the(xname(sky2)));
+		pline("%s and %s melt and dissolve into each-other!", The(xname(sky1)), the(xname(sky2)));
 		//merge stats
 		amalgam->spe = max(sky1->spe, sky2->spe);
 		for(int prop = 1; prop < MAX_OPROP; prop++){
diff --git a/src/attrib.c b/src/attrib.c
index b05aa7e1d..5de671eec 100644
--- a/src/attrib.c
+++ b/src/attrib.c
@@ -7,6 +7,7 @@
 #include <limits.h>
 #include "math.h"
 #include "hack.h"
+#include "artifact.h"
 
 /* #define DEBUG */	/* uncomment for debugging info */
 
@@ -1233,6 +1234,10 @@ struct monst *mon;
 	struct obj *armh = (is_player ? uarmh : which_armor(mon, W_ARMH));
 	struct obj *wep = (is_player ? uwep : MON_WEP(mon));
 	struct obj *swapwep = (is_player ? uswapwep : MON_SWEP(mon));
+    const struct artifact *oart = (struct artifact *) 0;
+	if(wep){
+		oart = get_artifact(wep);
+	}
 	
 	int tmp;
 	if(is_player){
@@ -1299,6 +1304,7 @@ struct monst *mon;
 		if ((armg && (armg->otyp == GAUNTLETS_OF_POWER || (armg->otyp == IMPERIAL_ELVEN_GAUNTLETS && check_imp_mod(armg, IEA_GOPOWER)))) || 
 			(wep &&((wep->oartifact == ART_SCEPTRE_OF_MIGHT) || 
 					 (wep->oartifact == ART_PEN_OF_THE_VOID && wep->ovar1&SEAL_YMIR && mvitals[PM_ACERERAK].died > 0) ||
+					 (oart && (oart->inv_prop == GITH_ART || oart->inv_prop == ZERTH_ART || oart->inv_prop == AMALGUM_ART) && artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_POWER) ||
 					 (wep->oartifact == ART_STORMBRINGER) ||
 					 (wep->oartifact == ART_OGRESMASHER)
 			)) ||
@@ -1946,6 +1952,13 @@ int fform;
 	return (selectedFightingForm(fform) && !blockedFightingForm(fform));
 }
 
+boolean
+activeMentalEdge(fform)
+int fform;
+{
+	return (artinstance[ART_SILVER_SKY].GithStyle == fform && !blockedMentalEdge(fform));
+}
+
 boolean
 selectedFightingForm(fform)
 int fform;
@@ -2021,6 +2034,7 @@ int fform;
 	}
 	return P_NONE; //Never reached
 }
+
 const char *
 nameOfFightingForm(fform)
 int fform;
@@ -2047,6 +2061,23 @@ int fform;
 	return "None";
 }
 
+const char *
+nameOfMentalEdge(edge)
+int edge;
+{
+	switch (edge)
+	{
+		case GSTYLE_PENETRATE: return "Penetrating Edge of Hatred";
+		case GSTYLE_COLD:  return "Cold Edge of Wrath";
+		case GSTYLE_DEFENSE:   return "Defensive Edge of Leadership";
+		case GSTYLE_ANTIMAGIC:    return "Anti-magic Edge of Serenity";
+		case GSTYLE_RESONANT:  return "Resonant Edge of Fellowship";
+		default:
+			impossible("bad gstyle %d", edge);
+	}
+	return "None";
+}
+
 void
 validateLightsaberForm()
 {
@@ -2107,6 +2138,48 @@ int fform;
 	return FALSE;
 }
 
+boolean
+blockedMentalEdge(edge)
+int edge;
+{
+	boolean ok = FALSE;
+    const struct artifact *oart = (struct artifact *) 0;
+	if(uwep){
+		oart = get_artifact(uwep);
+		if(oart && (oart->inv_prop == GITH_ART || oart->inv_prop == AMALGUM_ART))
+			ok = TRUE;
+	}
+	if(uswapwep){
+		oart = get_artifact(uswapwep);
+		if(oart && (oart->inv_prop == GITH_ART || oart->inv_prop == AMALGUM_ART))
+			ok = TRUE;
+	}
+	if(!ok)
+		return TRUE;
+
+	switch(edge){
+		case GSTYLE_PENETRATE:
+			return u.usanity > 50 || u.ulevel < 14;
+		break;
+		case GSTYLE_COLD:
+			return u.usanity > 50 || u.ulevel < 14 || u.uinsight < 9;
+		break;
+		case GSTYLE_DEFENSE:
+			return u.usanity < 50 || u.ulevel < 14;
+		break;
+		case GSTYLE_ANTIMAGIC:
+			return u.usanity < 50 || u.ulevel < 14;
+		break;
+		case GSTYLE_RESONANT:
+			return u.usanity < 50 || u.ulevel < 30 || u.uinsight < 81;
+		break;
+		default:
+			impossible("Attempting to get blockage of mental edge number %d?", edge);
+		break;
+	}
+	return TRUE; // Should never be reached
+}
+
 #endif /* OVL2 */
 
 /** Returns the hitpoints of your current form. */
diff --git a/src/cmd.c b/src/cmd.c
index c86e7f504..524b7cbdc 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -5,6 +5,7 @@
 #include <ctype.h>
 
 #include "hack.h"
+#include "artifact.h"
 #include "lev.h"
 #include "func_tab.h"
 /* #define DEBUG */	/* uncomment for debugging */
@@ -1158,7 +1159,8 @@ int doEldritchKniForm()
 	return MOVE_CANCELLED;
 }
 
-int doKnightForm()
+int
+doKnightForm()
 {
 	winid tmpwin;
 	int n, how, i;
@@ -1246,6 +1248,7 @@ int doKnightForm()
 		return MOVE_CANCELLED;
 	} else if ((selected[0].item.a_int == FFORM_HALF_SWORD || activeFightingForm(FFORM_HALF_SWORD)) &&
 				(!freehand() || (uwep && uwep->otyp == LONG_SWORD && welded(uwep)))){
+		free(selected);
 		pline("You need a free hand to adjust your grip!");
 		return MOVE_CANCELLED;
 	} else if (selected[0].item.a_int == FFORM_KNI_ELDRITCH){
@@ -1262,6 +1265,85 @@ int doKnightForm()
 	}
 }
 
+int
+doGithForm()
+{
+	winid tmpwin;
+	int n, how, i;
+	char buf[BUFSZ];
+	char incntlet = 'a';
+	menu_item *selected;
+	anything any;
+	int curskill;
+	char* block_reason;
+
+	tmpwin = create_nhwindow(NHW_MENU);
+	start_menu(tmpwin);
+	any.a_void = 0;		/* zero out all bits */
+
+	Sprintf(buf, "Known Mental Edges");
+	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED);
+
+
+	for (i = FIRST_GSTYLE; i <= LAST_GSTYLE; i++) {
+		if (i == GSTYLE_RESONANT && (u.ulevel < 30 || u.uinsight < 81))
+			continue;
+		if (i == GSTYLE_COLD && u.uinsight < 9)
+			continue;
+
+		/* knight forms are shown if unskilled but not restricted, since training involves starting from unskilled */
+		boolean active = artinstance[ART_SILVER_SKY].GithStyle == i;
+		boolean blocked = blockedMentalEdge(i);
+
+		Strcpy(buf, nameOfMentalEdge(i));
+		Strcat(buf, " (");
+
+		if (i == GSTYLE_PENETRATE)
+			block_reason = "lack of hate";
+		else if (i == GSTYLE_COLD)
+			block_reason = "lack of wrath";
+		else
+			block_reason = "lack of mental discipline";
+
+		if (active && blocked){
+			Strcat(buf, "selected; blocked by ");
+			Strcat(buf, block_reason);
+		}
+		else if (active)
+			Strcat(buf, "active");
+		else if (blocked){
+			Strcat(buf, "blocked by ");
+			Strcat(buf, block_reason);
+		}
+		else
+			Strcat(buf, "ready");
+		Strcat(buf, ")");
+
+		any.a_int = i;	/* must be non-zero */
+		add_menu(tmpwin, NO_GLYPH, &any,
+			incntlet, 0, ATR_NONE, buf,
+			MENU_UNSELECTED);
+		incntlet = (incntlet != 'z') ? (incntlet+1) : 'A';
+	}
+	end_menu(tmpwin, "Choose preferred mental edge:");
+
+	how = PICK_ONE;
+	n = select_menu(tmpwin, how, &selected);
+	destroy_nhwindow(tmpwin);
+
+	if(n <= 0){
+		return MOVE_CANCELLED;
+	} else if (artinstance[ART_SILVER_SKY].GithStyle == selected[0].item.a_int) {
+		artinstance[ART_SILVER_SKY].GithStyle = 0;
+		free(selected);
+		return MOVE_INSTANT;
+	} else {
+		artinstance[ART_SILVER_SKY].GithStyle = selected[0].item.a_int;
+		free(selected);
+		return MOVE_INSTANT;
+	}
+}
+
 #define MONK_FORMS			0x001L
 #define LIGHTSABER_FORMS	0x002L
 #define KNIGHT_FORMS		0x004L
@@ -1270,6 +1352,7 @@ int doKnightForm()
 #define AVOID_GRABATTK		0x020L
 #define AVOID_ENGLATTK		0x040L
 #define AVOID_UNSAFETOUCH	0x080L
+#define GITH_FORMS			0x100L
 
 
 int
@@ -1342,6 +1425,19 @@ hasfightingforms(){
 		}
 	}
 	
+	if(u.ulevel >= 14){
+		if(uwep && uwep->oartifact){
+			const struct artifact *weap = get_artifact(uwep);
+			if(weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART)
+				formmask |= GITH_FORMS;
+		}
+		if(uswapwep && uswapwep->oartifact){
+			const struct artifact *weap = get_artifact(uswapwep);
+			if(weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART)
+				formmask |= GITH_FORMS;
+		}
+	}
+
 	/* next, forms trained are shown, even if inapplicable at the moment*/
 	for (i = FIRST_LS_FFORM; i <= LAST_LS_FFORM; i++) {
 		if (FightingFormSkillLevel(i) >= P_BASIC)
@@ -1386,6 +1482,10 @@ dofightingform()
 		any.a_int = 3;
 		add_menu(tmpwin, NO_GLYPH, &any, 'k', 0, ATR_NONE, "Select Knightly Forms", MENU_UNSELECTED);
 	}
+	if (formmask & GITH_FORMS) {
+		any.a_int = 9;
+		add_menu(tmpwin, NO_GLYPH, &any, 'h', 0, ATR_NONE, "Select Mental Edge", MENU_UNSELECTED);
+	}
 	if (formmask & AVOID_PASSIVES) {
 		any.a_int = 4;
 		if (!u.uavoid_passives) Strcpy(buf, "Only make passive-safe attacks");
@@ -1457,6 +1557,8 @@ dofightingform()
 		case 8:
 			u.uavoid_unsafetouch = !u.uavoid_unsafetouch;
 			return MOVE_INSTANT;
+		case 9:
+			return doGithForm();
 		default:
 			impossible("unknown fighting form set %d", n);
 			return MOVE_CANCELLED;
diff --git a/src/do_wear.c b/src/do_wear.c
index ff3eb85d9..18c1ee420 100644
--- a/src/do_wear.c
+++ b/src/do_wear.c
@@ -2714,6 +2714,16 @@ find_ac()
 			else
 				uac -= 1+(uwep->spe)/2;
 		}
+		const struct artifact *weap = get_artifact(uwep);
+		if(weap && (weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART) && activeMentalEdge(GSTYLE_DEFENSE)){
+			uac -= u.usanity < 50 ? 0 : u.usanity < 75 ? max(uwep->spe,0) : u.usanity < 90 ? 2+max(uwep->spe,0) : 5+max(uwep->spe,0);
+		}
+	}
+	if(uswapwep){
+		const struct artifact *weap = get_artifact(uswapwep);
+		if(weap && (weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART) && activeMentalEdge(GSTYLE_DEFENSE)){
+			uac -= u.usanity < 50 ? 0 : u.usanity < 75 ? max(uswapwep->spe/2,0) : u.usanity < 90 ? 1+max(uswapwep->spe/2,0) : 3+max(uswapwep->spe/2,0);
+		}
 	}
 	if(Race_if(PM_HALF_DRAGON)){
 		//Some half dragons are more humanoid
diff --git a/src/makemon.c b/src/makemon.c
index a388970b6..03b1e332a 100644
--- a/src/makemon.c
+++ b/src/makemon.c
@@ -4,6 +4,7 @@
 
 #include <math.h>
 #include "hack.h"
+#include "artifact.h"
 
 #ifdef REINCARNATION
 #include <ctype.h>
@@ -16159,12 +16160,16 @@ struct monst *mtmp, *victim;
 			// max_increase = max((hp_threshold + 1) - mtmp->mhpmax, 0);
 	    // cur_increase = (max_increase > 0) ? rn2(max_increase)+1 : 0;
 		int xp_threshold = victim->m_lev + d(2,5);
-		if(mtmp->mtyp == PM_TWIN_SIBLING && mtmp->m_lev < u.ulevel)
-			xp_threshold = mtmp->m_lev + 1;
-		if(Role_if(PM_HEALER))
-			xp_threshold += heal_mlevel_bonus();
-		if(uring_art(ART_LOMYA))
-			xp_threshold += lev_lomya();
+		if(mtmp->mtame){
+			if(mtmp->mtyp == PM_TWIN_SIBLING && mtmp->m_lev < u.ulevel)
+				xp_threshold = mtmp->m_lev + 1;
+			if(Role_if(PM_HEALER))
+				xp_threshold += heal_mlevel_bonus();
+			if(uring_art(ART_LOMYA))
+				xp_threshold += lev_lomya();
+			if(artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_PATIENCE)
+				xp_threshold += 8;
+		}
 		if(has_sunflask(mtmp->mtyp) && mtmp->mvar_flask_charges < MAX_FLASK_CHARGES(mtmp) && !rn2(6+mtmp->mvar_flask_charges)){
 			if(canseemon(mtmp))
 				pline("Warm light shines on %s", mon_nam(mtmp));
diff --git a/src/mon.c b/src/mon.c
index e13d51ab3..d5563faf6 100644
--- a/src/mon.c
+++ b/src/mon.c
@@ -2975,6 +2975,10 @@ struct monst *looker;
 	if(distmin(looker->mx,looker->my,u.ux,u.uy) <= 1 && !rn2(8))
 		return TRUE;
 	
+	if(Invis && (artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_VILQUAR) && !resist(looker, '\0', 0, NOTELL)){
+		return FALSE;
+	}
+
 	/* Note: the player is never mindless */
 	/* R'lyehian psyichic sight, see minds, blocked by water */
 	if(rlyehiansight(looker->data)
diff --git a/src/weapon.c b/src/weapon.c
index 487aa2e9c..c562bc013 100644
--- a/src/weapon.c
+++ b/src/weapon.c
@@ -539,6 +539,12 @@ struct monst *magr;
 		} else if (magr == &youmonst && activeFightingForm(FFORM_GREAT_WEP) && (bimanual(obj, youracedata) || bimanual_mod(obj, &youmonst) > 1)) {
 			ignore_rolls = max(0, FightingFormSkillLevel(FFORM_GREAT_WEP) - 1); // 0-3 for unskilled-expert
 		}
+		
+		if(magr == &youmonst && obj->oartifact){
+			const struct artifact *weap = get_artifact(obj);
+			if((weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART) && activeMentalEdge(GSTYLE_PENETRATE))
+				ignore_rolls += u.usanity > 50 ? 0 : u.usanity > 25 ? 1 : u.usanity > 10 ? 2 : 3;
+		}
 
 		if (otyp == HEAVY_IRON_BALL) {
 			int wt = (int)objects[HEAVY_IRON_BALL].oc_weight;
@@ -1057,28 +1063,38 @@ boolean youdef;
 	/* determine function to use */
 	if (!wdie->exploding && !wdie->lucky) {
 		/* standard dice */
-		tmp += d(n, x-igrolls);
+		if(x-igrolls > 1)
+			tmp += d(n, x-igrolls);
 		tmp += n*igrolls;
 	}
 	else if (wdie->exploding && !wdie->lucky) {
 		/* exploding non-lucky dice */
 		/* great weapon fighting is a LARGE buff to these. possibly too strong */
-		tmp += exploding_d(n, x-igrolls, wdie->explode_amt);
+		if(x-igrolls > 1)
+			tmp += exploding_d(n, x-igrolls, wdie->explode_amt);
+		else igrolls = 2*x;
+
 		tmp += n*igrolls;
 	}
 	else if (!wdie->exploding && wdie->lucky) {
 		/* lucky non-exploding dice */
 		int i;
-		for (i = n; i; i--)
-		{
-			tmp += youdef ? (rnl(x-igrolls) + igrolls + 1) : (x - rnl(x-igrolls));
+		if(x-igrolls > 1){
+			for (i = n; i; i--)
+			{
+				tmp += youdef ? (rnl(x-igrolls) + igrolls + 1) : (x - rnl(x-igrolls));
+			}
 		}
+		else tmp += n*igrolls;
 	}
 	else if (wdie->exploding && wdie->lucky) {
 		/* EXTEMELY POTENT exploding lucky dice */
 		/* going to be honest - no CLUE what the distr with GWF turned on does,
 		 * but if you manage to get that, it's probably stupid or deserved */
-		tmp += (youdef ? unlucky_exploding_d : lucky_exploding_d)(n, x-igrolls, wdie->explode_amt);
+		if(x-igrolls > 1)
+			tmp += (youdef ? unlucky_exploding_d : lucky_exploding_d)(n, x-igrolls, wdie->explode_amt);
+		else igrolls = 10*x; //I think this is impossible, since this would be a Gith sword plus Fluorite Octet
+
 		tmp += n*igrolls;
 	}
 	return tmp;
diff --git a/src/worn.c b/src/worn.c
index 93137c80a..9861a8384 100644
--- a/src/worn.c
+++ b/src/worn.c
@@ -817,6 +817,21 @@ struct monst *mon;
 
 		if(uring_art(ART_NARYA) && def_narya())
 			base -= sgn(def_narya())*rnd(abs(def_narya()));
+
+		if(uwep){
+			const struct artifact *weap = get_artifact(uwep);
+			if(weap && (weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART) && activeMentalEdge(GSTYLE_DEFENSE)){
+				base -= u.usanity < 50 ? 0 : u.usanity < 75 ? max(uwep->spe/2,0) : u.usanity < 90 ? 1+max(uwep->spe/2,0) : 3+max(uwep->spe/2,0);
+			}
+		}
+		if(uswapwep){
+			const struct artifact *weap = get_artifact(uswapwep);
+			if(weap && (weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART) && activeMentalEdge(GSTYLE_DEFENSE)){
+				base -= u.usanity < 50 ? 0 : u.usanity < 75 ? max(uswapwep->spe/2,0) : u.usanity < 90 ? 1+max(uswapwep->spe/2,0) : 3+max(uswapwep->spe/2,0);
+			}
+		}
+		if(artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_STEEL)
+			base -= 1;
 	}
 
 	monwep = MON_WEP(mon);
@@ -1040,6 +1055,21 @@ struct monst *mon;
 
 		if(uring_art(ART_NARYA))
 			base -= def_narya();
+
+		if(uwep){
+			const struct artifact *weap = get_artifact(uwep);
+			if(weap && (weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART) && activeMentalEdge(GSTYLE_DEFENSE)){
+				base -= u.usanity < 50 ? 0 : u.usanity < 75 ? max(uwep->spe/2,0) : u.usanity < 90 ? 1+max(uwep->spe/2,0) : 3+max(uwep->spe/2,0);
+			}
+		}
+		if(uswapwep){
+			const struct artifact *weap = get_artifact(uswapwep);
+			if(weap && (weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART) && activeMentalEdge(GSTYLE_DEFENSE)){
+				base -= u.usanity < 50 ? 0 : u.usanity < 75 ? max(uswapwep->spe/2,0) : u.usanity < 90 ? 1+max(uswapwep->spe/2,0) : 3+max(uswapwep->spe/2,0);
+			}
+		}
+		if(artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_STEEL)
+			base -= 1;
 	}
 	
 	if(mon->mtyp == PM_HOD_SEPHIRAH){
@@ -1171,6 +1201,19 @@ struct monst *mon;
 
 		if(uring_art(ART_LOMYA))
 			base += def_lomya();
+
+		if(uwep){
+			const struct artifact *weap = get_artifact(uwep);
+			if(weap && (weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART) && activeMentalEdge(GSTYLE_DEFENSE)){
+				base += u.usanity < 50 ? 0 : u.usanity < 75 ? max(uwep->spe/2,0) : u.usanity < 90 ? 1+max(uwep->spe/2,0) : 3+max(uwep->spe/2,0);
+			}
+		}
+		if(uswapwep){
+			const struct artifact *weap = get_artifact(uswapwep);
+			if(weap && (weap->inv_prop == GITH_ART || weap->inv_prop == AMALGUM_ART) && activeMentalEdge(GSTYLE_DEFENSE)){
+				base += u.usanity < 50 ? 0 : u.usanity < 75 ? max(uswapwep->spe/2,0) : u.usanity < 90 ? 1+max(uswapwep->spe/2,0) : 3+max(uswapwep->spe/2,0);
+			}
+		}
 	}
 	if(is_alabaster_mummy(mon->data) && mon->mvar_syllable == SYLLABLE_OF_SPIRIT__VAUL)
 		base += 10;
diff --git a/src/xhity.c b/src/xhity.c
index ff22e8edd..1d4f279b4 100644
--- a/src/xhity.c
+++ b/src/xhity.c
@@ -1200,6 +1200,15 @@ int tary;
 		/* make per-attack counterattacks */
 		if (dopassive_local) {
 			dopassive = TRUE;
+			if(youdef && (result&MM_HIT) && u.uspellprot && artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_BALANCE){
+				struct monst *mon;
+				for(int i = 0; i < 8; i++){
+					if(isok(x(mdef)+xdir[i], y(mdef)+ydir[i]) && (mon = m_at(x(mdef)+xdir[i], y(mdef)+ydir[i])) && !DEADMONSTER(mon) && !mon->mpeaceful)
+						xdamagey(mdef, mon, (struct attack *) 0, 8);
+				}
+				if(DEADMONSTER(magr))
+					result |= MM_AGR_DIED;
+			}
 			result = xpassivey(magr, mdef, attk, otmp, vis, result, pd, FALSE);
 		}
 
@@ -3620,6 +3629,8 @@ int *shield_margin;
 				bons_acc += beastmastery();
 				if (uarm && uarm->oartifact == ART_BEASTMASTER_S_DUSTER && is_animal(magr->data))
 					bons_acc += beastmastery(); // double for the beastmaster's duster
+				if(artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_STEEL)
+					bons_acc += 1;
 			}
 			/* Bard */
 			if(!(youdef && Nightmare && u.umadness&MAD_RAGE))
@@ -14821,6 +14832,10 @@ int vis;						/* True if action is at all visible to the player */
 			if(magr->mtame){
 				if(uring_art(ART_NARYA))
 					bonsdmg += narya();
+				if(!youdef && (artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_POWER))
+					bonsdmg += 8;
+				if(!youdef && activeMentalEdge(GSTYLE_RESONANT))
+					bonsdmg += u.usanity < 50 ? 0 : u.usanity < 75 ? 2 : u.usanity < 90 ? 5 : 8;
 			}
 		}
 		/* Singing Sword -- only works when the player is wielding it >_> */
@@ -18978,6 +18993,10 @@ boolean magical;
 		else
 			dmg = (dmg + 1) / 2;
 	}
+	if (mdef == &youmonst && u.uspellprot){
+		if(magical && artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_WILL)
+			dmg = (dmg + 1) / 2;
+	}
 	/* Priests of Asmodeus */
 	if(mdef != &youmonst && flags.spriest_level && is_demon(mdef->data) && is_lawful_mon(mdef) && !mdef->mpeaceful)
 		dmg = (dmg + 1) / 2;
diff --git a/src/zap.c b/src/zap.c
index 6ad5400fa..8634a51b8 100644
--- a/src/zap.c
+++ b/src/zap.c
@@ -3,6 +3,7 @@
 /* NetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
+#include "artifact.h"
 
 #include "xhity.h"
 
@@ -265,8 +266,12 @@ struct obj *otmp;
 		} else if (u.uswallow || otyp == WAN_STRIKING || rnd(20) < 10 + find_mac(mtmp) + 2*P_SKILL(otyp == SPE_FORCE_BOLT ? P_ATTACK_SPELL : P_WAND_POWER)) {
 			if(otyp == WAN_STRIKING || otyp == ROD_OF_FORCE) dmg = d(wand_damage_die(P_SKILL(P_WAND_POWER))-4,12);
 			else dmg = d(fblt_damage_die(P_SKILL(P_ATTACK_SPELL)),12);
-			if (!flags.mon_moving && otyp == SPE_FORCE_BOLT && (uwep && uwep->oartifact == ART_ANNULUS && uwep->otyp == CHAKRAM))
-				dmg += d((u.ulevel+1)/2, 12);
+			if (!flags.mon_moving && otyp == SPE_FORCE_BOLT){
+				if(uwep && uwep->oartifact == ART_ANNULUS && uwep->otyp == CHAKRAM)
+					dmg += d((u.ulevel+1)/2, 12);
+				if(u.ulevel == 30 && (artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_PATIENCE))
+					dmg += d(10, 12);
+			}
 			if(dbldam) dmg *= 2;
 			if(!flags.mon_moving && Double_spell_size) dmg *= 1.5;
 			if (otyp == SPE_FORCE_BOLT){
@@ -3393,6 +3398,8 @@ register struct	obj	*obj;
 			switch (otyp) {
 			case SPE_MAGIC_MISSILE:
 				zapdat.single_target = TRUE;
+				if(otyp == SPE_MAGIC_MISSILE && (artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_WRATH))
+					zapdat.damd += 2;
 				break;
 			case SPE_FIREBALL:
 				zapdat.explosive = TRUE;
@@ -5654,6 +5661,9 @@ int damage, tell;
 	if (dlev > 50) dlev = 50;
 	else if (dlev < 1) dlev = 1;
 	
+	if(mtmp->mtame && artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_STEEL)
+		dlev += 1;
+
 	int mons_mr = mtmp->data->mr;
 	if(mtmp->mcan){
 		if(mtmp->mtyp == PM_ALIDER)
@@ -5661,6 +5671,8 @@ int damage, tell;
 		else
 			mons_mr /= 2;
 	}
+	if(mtmp->mtame && artinstance[ART_SKY_REFLECTED].ZerthUpgrades&ZPROP_WILL)
+		mons_mr += 10;
 
 	if(mtmp->mtyp == PM_CHOKHMAH_SEPHIRAH) dlev+=u.chokhmah;
 	resisted = rn2(100 + alev - dlev) < mons_mr;

From 5a47ac36512558148f3560edc17a40b98bc7f9a3 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sat, 3 Feb 2024 19:59:13 -0500
Subject: [PATCH 09/21] Another inheritor pass

Added:
Dragonlance: Unbreakable lance that gives reflection and is still occasionally useful late game vs. dragons.

Golden Sword of Y'ha-Talla: Instight weapon, plus poison is most useful early game.

Silver Sky and Sky Reflected: Various upgrades unlock as the game progresses, and the base arts aren't all that great.

Helping Hand: Untrapping, stealth, warning, and searching most useful early game. Curse-proof-ness most useful late game.

Blade Singer's Saber: Insight weapon, not that great early game

Removed:
Lifehunt Scythe: Already a first gift for a bunch of half dragon roles.
---
 include/artilist.h | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/include/artilist.h b/include/artilist.h
index db425db4a..8f3b5e25a 100644
--- a/include/artilist.h
+++ b/include/artilist.h
@@ -229,7 +229,7 @@ A("Claideamh",			LONG_SWORD,						(const char *)0,
 /* also makes a handy weapon for knights, since it can't break */
 A("Dragonlance",		LANCE,							(const char *)0,
 	5000L, DRAGON_HIDE, MZ_DEFAULT, WT_DEFAULT,
-	A_NONE, NON_PM, NON_PM, TIER_D, (ARTG_GIFT),
+	A_NONE, NON_PM, NON_PM, TIER_D, (ARTG_GIFT|ARTG_INHER),
 	MONS(vsMA(MA_DRAGON | MA_REPTILIAN)),
 	ATTK(AD_PHYS, 10, 20), (ARTA_HATES|ARTA_CANCEL),
 	PROPS(REFLECTING), NOFLAG,
@@ -519,7 +519,7 @@ A("Fuma-itto no Ken",	BROADSWORD,						(const char *)0,
 
 A("The Golden Sword of Y'ha-Talla",			SCIMITAR,	"scorpion-bladed %s",
 	3000L, GOLD, MZ_DEFAULT, WT_SPECIAL,
-	A_NONE, NON_PM, NON_PM, TIER_B, (ARTG_GIFT),
+	A_NONE, NON_PM, NON_PM, TIER_B, (ARTG_GIFT|ARTG_INHER),
 	NO_MONS(),
 	ATTK(AD_DRST, 5, 0), (ARTA_POIS),
 	PROPS(POISON_RES), NOFLAG,
@@ -718,7 +718,7 @@ A("The Lance of Longinus",		SPEAR,					(const char *)0,
 
 A("The Silver Sky",		LONG_SWORD,					(const char *)0,
 	1500L, SILVER, MZ_MEDIUM, WT_DEFAULT,
-	A_NONE, NON_PM, PM_GITHYANKI_PIRATE, TIER_B, (NOFLAG),
+	A_NONE, NON_PM, PM_GITHYANKI_PIRATE, TIER_B, (ARTG_INHER),
 	NO_MONS(),
 	ATTK(AD_PHYS, 1, 12), (ARTA_VORPAL),
 	PROPS(ANTIMAGIC), NOFLAG,
@@ -728,7 +728,7 @@ A("The Silver Sky",		LONG_SWORD,					(const char *)0,
 
 A("The Sky Reflected",		BROADSWORD,					(const char *)0,
 	1500L, MERCURIAL, MZ_MEDIUM, WT_DEFAULT,
-	A_NONE, NON_PM, PM_GITHYANKI_PIRATE, TIER_B, (ARTG_NAME|ARTG_NOGEN),
+	A_NONE, NON_PM, PM_GITHYANKI_PIRATE, TIER_B, (ARTG_NAME|ARTG_NOGEN|ARTG_INHER),
 	NO_MONS(),
 	ATTK(AD_PHYS, 8, 1), NOFLAG,
 	PROPS(REFLECTING), NOFLAG,
@@ -780,7 +780,7 @@ A("Release from Care",	SCYTHE,							(const char *)0,
 /* uses STR and DEX scaling, +16 max */
 A("The Lifehunt Scythe",SCYTHE,							(const char *)0,
 	4000L, DRAGON_HIDE, MZ_LARGE, WT_DEFAULT,
-	A_CHAOTIC, NON_PM, NON_PM, TIER_B, (ARTG_GIFT|ARTG_INHER),
+	A_CHAOTIC, NON_PM, NON_PM, TIER_B, (ARTG_GIFT),
 	NO_MONS(),
 	ATTK(AD_PHYS, 6, 6), (ARTA_HATES|ARTA_VORPAL), /* damage only applies vs living or undead monsters */
 	PROPS(DRAIN_RES, STEALTH), NOFLAG,
@@ -856,7 +856,7 @@ A("The Garnet Rod",		UNIVERSAL_KEY,					"garnet-tipped rod",
 /* also protects vs curses while carried */
 A("Helping Hand",		GRAPPLING_HOOK,					(const char *)0,
 	2000L, MT_DEFAULT, MZ_DEFAULT, WT_DEFAULT,
-	A_LAWFUL, NON_PM, NON_PM, TIER_A, (NOFLAG),
+	A_LAWFUL, NON_PM, NON_PM, TIER_A, (ARTG_INHER),
 	NO_MONS(),
 	NO_ATTK(), NOFLAG,
 	PROPS(STEALTH, WARNING, SEARCHING), (ARTP_SEEK),
@@ -867,7 +867,7 @@ A("Helping Hand",		GRAPPLING_HOOK,					(const char *)0,
 /*Needs encyc entry*/
 A("The Blade Singer's Saber",		RAKUYO,				(const char *)0,
 	1500L, SILVER, MZ_DEFAULT, WT_DEFAULT,
-	A_NONE, NON_PM, NON_PM, TIER_A, (ARTG_GIFT),
+	A_NONE, NON_PM, NON_PM, TIER_A, (ARTG_GIFT|ARTG_INHER),
 	NO_MONS(),
 	ATTK(AD_PHYS, 8, 8), (ARTA_HASTE),
 	PROPS(), NOFLAG,

From d26ce625862ff4c3dd0f9bee94836cb9b3236784 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sat, 3 Feb 2024 20:34:20 -0500
Subject: [PATCH 10/21] Avenger should always have the holy and unholy oprops.

Move them from makemon to do_name
---
 src/do_name.c | 5 +++++
 src/makemon.c | 2 --
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/do_name.c b/src/do_name.c
index 7513b00fd..256a3dc2c 100644
--- a/src/do_name.c
+++ b/src/do_name.c
@@ -713,6 +713,11 @@ const char *name;
 		if (obj->oartifact == ART_IBITE_ARM)
 			add_oprop(obj, OPROP_CCLAW);
 		
+		if (obj->oartifact == ART_AVENGER){
+			add_oprop(obj, OPROP_HOLYW);
+			add_oprop(obj, OPROP_UNHYW);
+		}
+		
 		/* property */
 		if (obj->oartifact == ART_AMALGAMATED_SKIES || obj->oartifact == ART_SILVER_SKY)
 			add_oprop(obj, OPROP_GSSDW);
diff --git a/src/makemon.c b/src/makemon.c
index 03b1e332a..dedec970b 100644
--- a/src/makemon.c
+++ b/src/makemon.c
@@ -3908,8 +3908,6 @@ boolean greatequip;
 			if(otmp->spe < 3) otmp->spe = 3;
 			set_material_gm(otmp, IRON);
 			otmp = oname(otmp, artiname(ART_AVENGER));
-			add_oprop(otmp, OPROP_HOLYW);
-			add_oprop(otmp, OPROP_UNHYW);
 			fix_object(otmp);
 			(void) mpickobj(mtmp, otmp);
 			(void) mongets(mtmp, HELMET, mkobjflags);

From ce81dcb146795ffb0ccc6740445faab26661d86b Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sat, 3 Feb 2024 20:35:51 -0500
Subject: [PATCH 11/21] Weapons and Armor in lolth's vaults should also typical
 be erodeproof

---
 src/mkroom.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/mkroom.c b/src/mkroom.c
index 1d6c06884..537c49689 100644
--- a/src/mkroom.c
+++ b/src/mkroom.c
@@ -532,6 +532,8 @@ mklolthvaultitem()
 			if(otmp->oclass == WEAPON_CLASS || is_weptool(otmp) || otmp->oclass == ARMOR_CLASS)
 				otmp->spe = max_ints(d(2,3), otmp->spe);
 		}
+		if((otmp->oclass == WEAPON_CLASS || is_weptool(otmp) || otmp->oclass == ARMOR_CLASS) && rn2(5))
+			otmp->oerodeproof = TRUE;
 	} while (--try_limit > 0 &&
 	  !(objects[otmp->otyp].oc_magic || otmp->oartifact || !check_oprop(otmp, OPROP_NONE) || Is_container(otmp)));
 

From 14d2d361316cd56497e7cefc701783b2dd5dd690 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sat, 3 Feb 2024 20:36:10 -0500
Subject: [PATCH 12/21] Bugfix: Silver Starlight needs an instrument set

---
 src/music.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/music.c b/src/music.c
index d7b0c3b60..9f8c6b933 100644
--- a/src/music.c
+++ b/src/music.c
@@ -1922,6 +1922,9 @@ struct obj *instr;
     boolean ok;
 
 	instr_otyp = instr->otyp;
+
+	if(instr->oartifact == ART_SILVER_STARLIGHT) instr_otyp = MAGIC_FLUTE;
+
 	if(instr_otyp == MAGIC_HARP) instr_otyp = HARP;
 	else if(instr_otyp == MAGIC_FLUTE) instr_otyp = FLUTE;
 	else if(instr_otyp == FIRE_HORN) instr_otyp = TOOLED_HORN;

From d343cd9beb3f62224e7303cd004d623e2f51a797 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sat, 3 Feb 2024 20:37:57 -0500
Subject: [PATCH 13/21] Priests are only coaligned if their alignment matches
 and their god (if any) matches

---
 src/priest.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/priest.c b/src/priest.c
index 81bab6356..3f50044d3 100644
--- a/src/priest.c
+++ b/src/priest.c
@@ -394,7 +394,7 @@ boolean
 p_coaligned(priest)
 struct monst *priest;
 {
-	return((boolean)(u.ualign.type == ((int)EPRI(priest)->shralign)));
+	return((boolean)(u.ualign.type == ((int)EPRI(priest)->shralign) && (!(EPRI(priest)->godnum) || u.ugodbase[UGOD_CURRENT] == EPRI(priest)->godnum)));
 }
 
 STATIC_OVL boolean

From d6fa7ba456bccfc7a1b5cbc51c3cda7a9321cc83 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sat, 3 Feb 2024 20:45:14 -0500
Subject: [PATCH 14/21] Bugfix: Insight weapons shouldn't pierce walls

Check for line of sight.
---
 src/projectile.c   |  6 ++++++
 src/xhityhelpers.c | 20 +++++++++++++++++++-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/src/projectile.c b/src/projectile.c
index 705c4eb74..7e2c21527 100644
--- a/src/projectile.c
+++ b/src/projectile.c
@@ -776,6 +776,12 @@ int y;							/* */
 	struct rm *room = &levl[x][y];
 	boolean shopdoor = FALSE, shopwall = FALSE;
 
+	if(youagr && !couldsee(x,y))
+		return;
+
+	if(!youagr && !clear_path(x(magr), y(magr), x, y))
+		return;
+
 	/* Doors (but not artifact doors) */
 	if ((closed_door(x, y) || room->typ == SDOOR) &&
 		!artifact_door(x, y)) 
diff --git a/src/xhityhelpers.c b/src/xhityhelpers.c
index ea316d267..4ee3a74e9 100644
--- a/src/xhityhelpers.c
+++ b/src/xhityhelpers.c
@@ -2566,6 +2566,7 @@ struct attack * attk;
 								(struct monst *)0;
 		if (mdef2 
 			&& (!DEADMONSTER(mdef2))
+			&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 			&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 				(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 				(youagr && !mdef2->mpeaceful))
@@ -2597,6 +2598,7 @@ struct attack * attk;
 									(struct monst *)0;
 			if (mdef2 
 				&& (!DEADMONSTER(mdef2))
+				&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 				&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 					(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 					(youagr && !mdef2->mpeaceful))
@@ -2625,6 +2627,7 @@ struct attack * attk;
 									(struct monst *)0;
 			if (mdef2 
 				&& (!DEADMONSTER(mdef2))
+				&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 				&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 					(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 					(youagr && !mdef2->mpeaceful))
@@ -2681,6 +2684,7 @@ struct attack * attk;
 								(struct monst *)0;
 		if (mdef2 
 			&& (!DEADMONSTER(mdef2))
+			&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 			&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 				(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 				(youagr && !mdef2->mpeaceful))
@@ -2707,6 +2711,7 @@ struct attack * attk;
 									(struct monst *)0;
 			if (mdef2 
 				&& (!DEADMONSTER(mdef2))
+				&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 				&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 					(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 					(youagr && !mdef2->mpeaceful))
@@ -2732,6 +2737,7 @@ struct attack * attk;
 									(struct monst *)0;
 			if (mdef2 
 				&& (!DEADMONSTER(mdef2))
+				&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 				&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 					(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 					(youagr && !mdef2->mpeaceful))
@@ -2759,6 +2765,7 @@ struct attack * attk;
 									(struct monst *)0;
 			if (mdef2 
 				&& (!DEADMONSTER(mdef2))
+				&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 				&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 					(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 					(youagr && !mdef2->mpeaceful))
@@ -2784,6 +2791,7 @@ struct attack * attk;
 									(struct monst *)0;
 			if (mdef2 
 				&& (!DEADMONSTER(mdef2))
+				&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 				&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 					(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 					(youagr && !mdef2->mpeaceful))
@@ -2815,6 +2823,7 @@ struct attack * attk;
 									(struct monst *)0;
 			if (mdef2 
 				&& (!DEADMONSTER(mdef2))
+				&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 				&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 					(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 					(youagr && !mdef2->mpeaceful))
@@ -2845,6 +2854,7 @@ struct attack * attk;
 									(struct monst *)0;
 			if (mdef2 
 				&& (!DEADMONSTER(mdef2))
+				&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 				&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 					(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 					(youagr && !mdef2->mpeaceful))
@@ -2897,6 +2907,7 @@ struct attack * attk;
 								(struct monst *)0;
 		if (mdef2 
 			&& (!DEADMONSTER(mdef2))
+			&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 			&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 				(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 				(youagr && !mdef2->mpeaceful))
@@ -2911,7 +2922,9 @@ struct attack * attk;
 			/* handle MM_AGR_DIED and MM_AGR_STOP by adding them to the overall result, ignore other outcomes */
 			result |= subresult&(MM_AGR_DIED|MM_AGR_STOP);
 		}
-		if(u.uinsight >= 40){
+		if(u.uinsight >= 40
+		  && ((youagr) ? couldsee(tarx + dx, tary + dy) : clear_path(magr->mx, magr->my, tarx + dx, tary + dy))
+		){
 			explode(tarx + dx, tary + dy, AD_FIRE, -1, d(6,6), EXPL_FIERY, 1);
 		}
 	}
@@ -2988,6 +3001,7 @@ struct attack * attk;
 								(struct monst *)0;
 		if (mdef2 
 			&& (!DEADMONSTER(mdef2))
+			&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 			&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 				(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 				(youagr && !mdef2->mpeaceful))
@@ -3043,6 +3057,7 @@ struct attack * attk;
 								(struct monst *)0;
 		if (mdef2 
 			&& (!DEADMONSTER(mdef2))
+			&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 			&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 				(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 				(youagr && !mdef2->mpeaceful))
@@ -3067,6 +3082,7 @@ struct attack * attk;
 								(struct monst *)0;
 		if (mdef2 
 			&& (!DEADMONSTER(mdef2))
+			&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 			&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 				(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 				(youagr && !mdef2->mpeaceful))
@@ -3120,6 +3136,7 @@ struct attack * attk;
 								(struct monst *)0;
 		if (mdef2 
 			&& (!DEADMONSTER(mdef2))
+			&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 			&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 				(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 				(youagr && !mdef2->mpeaceful))
@@ -3144,6 +3161,7 @@ struct attack * attk;
 								(struct monst *)0;
 		if (mdef2 
 			&& (!DEADMONSTER(mdef2))
+			&& ((youagr || mdef2 == &youmonst) ? couldsee(mdef2->mx,mdef2->my) : clear_path(magr->mx, magr->my, mdef2->mx, mdef2->my))
 			&& ((!youagr && mdef2 != &youmonst && mdef2->mpeaceful != magr->mpeaceful) ||
 				(!youagr && mdef2 == &youmonst && !magr->mpeaceful) ||
 				(youagr && !mdef2->mpeaceful))

From bb21eed508d8b31b1964a31abb3432a2d2d90154 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sat, 3 Feb 2024 20:50:15 -0500
Subject: [PATCH 15/21] Reduce cult san costs from 1/2 favor to 1/5 favor.

Maybe even 1/10th is correct. I tried it at 1/10 on local and it seemed a bit too little, but that was after the main cult sac fest.
---
 src/potion.c | 2 +-
 src/pray.c   | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/potion.c b/src/potion.c
index 8dca3cdb3..b878c1893 100644
--- a/src/potion.c
+++ b/src/potion.c
@@ -1181,7 +1181,7 @@ as_extra_healing:
 		exercise(A_STR, TRUE);
 		exercise(A_CON, TRUE);
 		//Makes you crazy
-		change_usanity(-1*rnd(20), FALSE);
+		change_usanity(-1*rnd(10), FALSE);
 		u.umadness |= MAD_GOAT_RIDDEN;
 		lift_veil();
 		break;
diff --git a/src/pray.c b/src/pray.c
index 866f44a3b..9c5c9d8c8 100644
--- a/src/pray.c
+++ b/src/pray.c
@@ -3624,7 +3624,7 @@ commune_with_goat()
 	}
 
 	u.shubbie_credit -= cost;
-	change_usanity(-cost/2, TRUE);
+	change_usanity(-(cost+4)/5, TRUE);
 	
 	return MOVE_STANDARD;
 }
@@ -3955,7 +3955,7 @@ commune_with_silver_flame()
 		pline("The silver light recedes.");
 
 	u.silver_credit -= cost;
-	change_usanity(-cost/2, TRUE);
+	change_usanity(-(cost+4)/5, TRUE);
 	
 	return MOVE_STANDARD;
 }
@@ -4173,7 +4173,7 @@ commune_with_yog()
 			s_suffix(yogname)
 			);
 		/* taxes sanity! (a tiny bit) */
-		change_usanity(-6, TRUE);
+		change_usanity(-1, TRUE);
 		return MOVE_STANDARD;
 	}
 
@@ -4321,7 +4321,7 @@ commune_with_yog()
 	}
 
 	u.yog_sothoth_credit -= cost;
-	change_usanity(-cost/2, TRUE);
+	change_usanity(-(cost+4)/5, TRUE);
 	
 	return MOVE_STANDARD;
 }

From 3faf30a63a76925f4c1f9abaac9d58776699c5ae Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sat, 3 Feb 2024 20:51:21 -0500
Subject: [PATCH 16/21] Altar conversions don't anger priests if the gods are
 friendly

---
 src/pray.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/pray.c b/src/pray.c
index 9c5c9d8c8..f11a74d30 100644
--- a/src/pray.c
+++ b/src/pray.c
@@ -2140,10 +2140,10 @@ dosacrifice()
 					if(u.ulevel > 20) summon_god_minion(altargod, FALSE);
 					if(u.ulevel >= 14) summon_god_minion(altargod, FALSE);
 					(void) summon_god_minion(altargod, TRUE);
+					/* anger priest; test handles bones files */
+					if((pri = findpriest(temple_occupied(u.urooms))) && !p_coaligned(pri))
+						angry_priest();
 				}
-				/* anger priest; test handles bones files */
-				if((pri = findpriest(temple_occupied(u.urooms))) && !p_coaligned(pri))
-					angry_priest();
 			} else {
 				pline("Unluckily, you feel the power of %s decrease.", u_gname());
 				change_luck(-1);

From fa91e04560aadfe57e2ffcbec9a085f0d36218d8 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sat, 3 Feb 2024 20:51:37 -0500
Subject: [PATCH 17/21] Spelling

---
 src/sounds.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/sounds.c b/src/sounds.c
index 570c67696..f73e6d95c 100644
--- a/src/sounds.c
+++ b/src/sounds.c
@@ -17,7 +17,7 @@
 #define 	SANCTIFY_WEP	4
 
 #define		NURSE_FULL_HEAL			1
-#define		NURSE_TRANQUIZIZERS		2
+#define		NURSE_TRANQUILIZERS		2
 #define		NURSE_RESTORE_ABILITY	3
 #define		NURSE_FIX_MORGUL		4
 #define		NURSE_FIX_SICKNESS		5
@@ -6580,8 +6580,8 @@ donursemenu()
 		MENU_UNSELECTED);
 	incntlet++;
 	if(u.usanity < 100){
-		Sprintf(buf, "Something for my nerves ($%d)", nurseprices[NURSE_TRANQUIZIZERS]);
-		any.a_int = NURSE_TRANQUIZIZERS;	/* must be non-zero */
+		Sprintf(buf, "Something for my nerves ($%d)", nurseprices[NURSE_TRANQUILIZERS]);
+		any.a_int = NURSE_TRANQUILIZERS;	/* must be non-zero */
 		add_menu(tmpwin, NO_GLYPH, &any,
 			incntlet, 0, ATR_NONE, buf,
 			MENU_UNSELECTED);
@@ -6674,7 +6674,7 @@ struct monst *nurse;
 #else
 		gold = money_cnt(invent);
 #endif
-	if(service == NURSE_FULL_HEAL || service == NURSE_TRANQUIZIZERS){
+	if(service == NURSE_FULL_HEAL || service == NURSE_TRANQUILIZERS){
 		char inbuf[BUFSZ];
 		getlin("How many courses?", inbuf);
 		if (*inbuf == '\033') count = 1;
@@ -6703,7 +6703,7 @@ struct monst *nurse;
 			pline("%s doses you with healing medicine.", Monnam(nurse));
 			healup(400*count, 8*count, FALSE, TRUE);
 		break;
-		case NURSE_TRANQUIZIZERS:
+		case NURSE_TRANQUILIZERS:
 			pline("%s doses you with tranquilizers.", Monnam(nurse));
 			if(Sleep_resistance || Free_action)
 				You("yawn.");

From b886fa446ce2274ec5c48f2801fc52ece84f4c33 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sun, 4 Feb 2024 15:25:46 -0500
Subject: [PATCH 18/21] Slightly buff Sode no Shirayuki: third dance eventually
 repairs sword to +7

---
 src/artifact.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/artifact.c b/src/artifact.c
index e1739f885..203066367 100644
--- a/src/artifact.c
+++ b/src/artifact.c
@@ -8855,6 +8855,7 @@ arti_invoke(obj)
 					obj->oeroded = 0;
 					obj->oeroded2= 0;
 					if(obj->spe < 3) obj->spe = 3;
+					if(obj->spe < u.ulevel/4) obj->spe = u.ulevel/4; //0 to 7
 					artinstance[obj->oartifact].SnSd3duration = monstermoves + (long) u.ulevel + obj->spe;
 				}
 			}

From 01dc5512a6d0b9edb1ad2d69cf77de9a59cba86b Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sun, 4 Feb 2024 15:27:34 -0500
Subject: [PATCH 19/21] Nerf Resonant Edge

Pet encouragement bonus does not stack (was trivially stacking to several hundred bonus damage)

Enemies roll to resist speed penalty (was stun-locking demon lords)
---
 src/artifact.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/artifact.c b/src/artifact.c
index 203066367..401960105 100644
--- a/src/artifact.c
+++ b/src/artifact.c
@@ -4555,11 +4555,12 @@ int * truedmgptr;
 								continue;
 							if(tmon->mtame){
 								tmon->movement += 12;
-								tmon->encouraged += u.usanity < 50 ? 0 : u.usanity < 75 ? 2 : u.usanity < 90 ? 5 : 8;
+								tmon->encouraged = max_ints(u.usanity < 50 ? 0 : u.usanity < 75 ? 2 : u.usanity < 90 ? 5 : 8, tmon->encouraged);
 							}
 							else if(near_yourteam(tmon)){
-								tmon->movement -= 12;
-								tmon->encouraged -= u.usanity < 50 ? 0 : u.usanity < 75 ? 2 : u.usanity < 90 ? 5 : 8;
+								if(!resist(tmon, '\0', 0, NOTELL))
+									tmon->movement -= 12;
+								tmon->encouraged = min_ints(u.usanity < 50 ? 0 : u.usanity < 75 ? -2 : u.usanity < 90 ? -5 : -8, tmon->encouraged);
 							}
 						}
 					}

From dccd935a0ce3cce6d175d441ca2df1ae37193237 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sun, 4 Feb 2024 17:53:24 -0500
Subject: [PATCH 20/21] Inheritor changes:

No longer consumes first artifact wish.

Inheritors other than Convicts and Madmen count as being 10 levels deeper in the dungeon.

Inheritors gain reduced XP while "beginners"
-Convicts and Madmen gain 1/2 normal XP
-Others gain 1/10th normal XP (they do not power-level with the tougher monsters)

Start with around 20% fewer stat points.

Only archeologists, convicts, knights, madmen, noblemen, pirates, rogues, samurai, tourists, and valkyries can be inheritors.
-Convicts and madmen have their artifacts in their quests, and reduced penalties.
---
 src/dungeon.c         |  3 +++
 src/exper.c           | 10 ++++++++++
 src/u_init.c          | 27 ++++++++++++++++++++++-----
 src/zap.c             |  2 +-
 win/curses/cursinit.c | 11 +++++++++--
 win/tty/wintty.c      | 11 +++++++++--
 6 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/src/dungeon.c b/src/dungeon.c
index b439648cf..02128ab96 100644
--- a/src/dungeon.c
+++ b/src/dungeon.c
@@ -1915,6 +1915,9 @@ level_difficulty()
 		else
 			dpth = ((int) depth(&u.uz));
 	
+	if(flags.descendant && !Role_if(PM_CONVICT) && !Role_if(PM_MADMAN))
+		dpth += 10;
+
 	return max(1, dpth);
 }
 
diff --git a/src/exper.c b/src/exper.c
index bf883acf0..29a433cb2 100644
--- a/src/exper.c
+++ b/src/exper.c
@@ -194,6 +194,16 @@ more_experienced(exp, rexp)
 		exp *= 1.3;
 		rexp *= 1.3;
 	}
+	if(flags.descendant && flags.beginner){
+		if(Role_if(PM_CONVICT) || Role_if(PM_MADMAN)){
+			exp = (exp+1)/2;
+			rexp = (rexp+1)/2;
+		}
+		else {
+			exp = (exp+9)/10;
+			rexp = (rexp+9)/10;
+		}
+	}
 	if(u.ulevel < u.ulevelmax){
 		//if you have lost levels to level drain, gain XP at 5x rate.
 		//if you are about to regain the last drained level, gain at least the base xp total
diff --git a/src/u_init.c b/src/u_init.c
index 5892b0d82..c39fef6cf 100644
--- a/src/u_init.c
+++ b/src/u_init.c
@@ -2756,14 +2756,31 @@ u_init()
 		else
 			init_attr(55);
 	} else if(Race_if(PM_ORC)){
-		init_attr(55);
+		if(flags.descendant)
+			init_attr(45);
+		else
+			init_attr(55);
 	} else if (Race_if(PM_ANDROID)){
-		init_attr(95);
+		if(flags.descendant)
+			init_attr(75);
+		else
+			init_attr(95);
 	} else if (Role_if(PM_VALKYRIE)){
-		init_attr(85);
+		if(flags.descendant)
+			init_attr(70);
+		else
+			init_attr(85);
 	} else if (Race_if(PM_ELF)){
-		init_attr(80);
-	} else init_attr(75);	/* init attribute values */
+		if(flags.descendant)
+			init_attr(65);
+		else
+			init_attr(80);
+	} else {
+		if(flags.descendant)
+			init_attr(60);
+		else
+			init_attr(75);	/* init attribute values */
+	}
 	find_ac();				/* get initial ac value */
 	max_rank_sz();			/* set max str size for class ranks */
 /*
diff --git a/src/zap.c b/src/zap.c
index 8634a51b8..db6686a92 100644
--- a/src/zap.c
+++ b/src/zap.c
@@ -5724,7 +5724,7 @@ allow_artwish()
 {
 	int n = 1;
 	
-	n -= flags.descendant; 			// 'used' their first on their inheritance
+	// n -= flags.descendant; 			// 'used' their first on their inheritance
 	// n += u.uevent.qcalled;		// reaching the main dungeon branch of the quest
 	//if(u.ulevel >= 7) n++;		// enough levels to be intimidating to marids/djinni
 	n += (u.uevent.utook_castle & ARTWISH_EARNED);	// sitting on the castle throne
diff --git a/win/curses/cursinit.c b/win/curses/cursinit.c
index c22792923..6e4dd0c46 100644
--- a/win/curses/cursinit.c
+++ b/win/curses/cursinit.c
@@ -842,13 +842,20 @@ curses_choose_character()
 
 	/* Select descendant status, if necessary */
     if (flags.descendant < 0){
-		if (flags.descendant == ROLE_RANDOM || flags.randomall) {
+		if (flags.descendant == ROLE_RANDOM || flags.randomall
+			|| !(flags.initrole < 0 || roles[flags.initrole].malenum == PM_ARCHEOLOGIST || roles[flags.initrole].malenum == PM_CONVICT
+				 || roles[flags.initrole].malenum == PM_KNIGHT || roles[flags.initrole].malenum == PM_MADMAN
+				 || roles[flags.initrole].malenum == PM_NOBLEMAN || roles[flags.initrole].malenum == PM_PIRATE
+				 || roles[flags.initrole].malenum == PM_ROGUE || roles[flags.initrole].malenum == PM_SAMURAI
+				 || roles[flags.initrole].malenum == PM_TOURIST || flags.initrole == PM_VALKYRIE
+				)
+		) {
            flags.descendant = 0; // never randomly roll descendant
         } else {
             /* Always 2 options - yn */
             choices = (const char **) alloc(sizeof (char *) * (3));
             pickmap = (int *) alloc(sizeof (int) * (3));
-			char * terms[] = {"Inherit from a past adventurer (start with an heirloom artifact, consuming an artifact wish)",
+			char * terms[] = {"Inherit from a past adventurer (start with an heirloom artifact but low stats and dangerous foes)",
 								"No past inheritance", '\0'};
 
             for (i = 0; i < 2; i++) {
diff --git a/win/tty/wintty.c b/win/tty/wintty.c
index 9ff9f5b3e..fa97d124d 100644
--- a/win/tty/wintty.c
+++ b/win/tty/wintty.c
@@ -707,7 +707,14 @@ give_up:	/* Quit */
 
 	/* Select descendant status, if necessary */
 	if (flags.descendant < 0) {
-	    if (pick4u == 'y' || flags.descendant == ROLE_RANDOM || flags.randomall) {
+	    if (pick4u == 'y' || flags.descendant == ROLE_RANDOM || flags.randomall
+			|| !(flags.initrole < 0 || roles[flags.initrole].malenum == PM_ARCHEOLOGIST || roles[flags.initrole].malenum == PM_CONVICT
+				 || roles[flags.initrole].malenum == PM_KNIGHT || roles[flags.initrole].malenum == PM_MADMAN
+				 || roles[flags.initrole].malenum == PM_NOBLEMAN || roles[flags.initrole].malenum == PM_PIRATE
+				 || roles[flags.initrole].malenum == PM_ROGUE || roles[flags.initrole].malenum == PM_SAMURAI
+				 || roles[flags.initrole].malenum == PM_TOURIST || flags.initrole == PM_VALKYRIE
+				)
+		) {
 			flags.descendant = 0; // never randomly roll descendant
 	    } else {	/* pick4u == 'n' */
 		tty_clear_nhwindow(BASE_WINDOW);
@@ -718,7 +725,7 @@ give_up:	/* Quit */
 
 		any.a_int = 2;
 		add_menu(win, NO_GLYPH, &any , 'y', 0, ATR_NONE,
-			"Inherit from a past adventurer (start with an heirloom artifact, consuming an artifact wish)", MENU_UNSELECTED);
+			"Inherit from a past adventurer (start with an heirloom artifact but low stats and dangerous foes)", MENU_UNSELECTED);
 
 		any.a_int = 1;
 		add_menu(win, NO_GLYPH, &any , 'n', 0, ATR_NONE, "No past inheritance", MENU_UNSELECTED);

From 91b244e7ed4ee1ea681aa922f5ebef700462b970 Mon Sep 17 00:00:00 2001
From: chris <ohmygod.stopitwiththis.com>
Date: Sun, 4 Feb 2024 17:54:22 -0500
Subject: [PATCH 21/21] Nerf magic cancellation 3

Drop from 98% effectiveness to 90% effectiveness
---
 src/xhity.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/xhity.c b/src/xhity.c
index 1d4f279b4..0c954bd58 100644
--- a/src/xhity.c
+++ b/src/xhity.c
@@ -4469,7 +4469,7 @@ boolean ranged;
 	 *	armor's special magic protection.  Otherwise just use !mtmp->mcan.
 	 */
 	armpro = magic_negation(mdef);
-	armuncancel = ((rn2(3) >= armpro) || !rn2(50));
+	armuncancel = ((rn2(3) >= armpro) || !rn2(10));
 	/* hack: elemental gaze attacks call this function with their AT_GAZE; we want that to ignore armor cancellation */
 	if (attk->aatyp == AT_GAZE || attk->aatyp == AT_WDGZ)
 		armuncancel = TRUE;