Skip to content

EA 23.121 Nightly

April 7, 2025

18 files modified. 4 new files created.

Important Changes

Possible breaking changes. Click the filename to view the chunk.

CharaAbility (1)

cs
public void BuildRandomAbilityList() 

TraitPotionRandom (1)

cs
public override void OnCreate(int lv) 

AM_FlagCell

@@ -111,13 +111,14 @@ public override void OnClickSubMenu(int a)

cs

	public override string OnSetSubMenuButton(int a, UIButton b)
	{
		if (a >= 3 && !EClass.debug.enable) 
		{ 
			return null; 
		} 
		if (a < 5)
		{
			return a.ToEnum<Mode>().ToString(); 
			Mode mode = a.ToEnum<Mode>(); 
			if (a >= 3 && mode != Mode.flagShadow) 
			{ 
				return null; 
			} 
			return mode.ToString(); 
		}
		return null;
	}

ActEffect

@@ -1371,7 +1371,7 @@ public static bool DamageEle(Card CC, EffectId id, int power, Element e, List<Po

cs
			break;
		}
		Thing thing6 = null;
		bool flag8 = actRef.n1 == "food"; 
		bool flag7 = actRef.n1 == "food"; 
		if (actRef.n1 == "money")
		{
			int currency = TC.GetCurrency();

@@ -1385,7 +1385,7 @@ public static bool DamageEle(Card CC, EffectId id, int power, Element e, List<Po

cs
		else
		{
			Func<Thing, bool> func = (Thing t) => true;
			if (flag8) 
			if (flag7) 
			{
				func = (Thing t) => t.IsFood;
			}

@@ -1567,12 +1567,12 @@ public static bool DamageEle(Card CC, EffectId id, int power, Element e, List<Po

cs
	{
		EClass.game.religions.Trickery.Talk("ability");
		bool hex2 = CC.IsHostile(TC);
		List<SourceStat.Row> list5 = EClass.sources.stats.rows.Where((SourceStat.Row con) => con.tag.Contains("random") && con.group == (hex2 ? "Debuff" : "Buff")).ToList(); 
		List<SourceStat.Row> list4 = EClass.sources.stats.rows.Where((SourceStat.Row con) => con.tag.Contains("random") && con.group == (hex2 ? "Debuff" : "Buff")).ToList(); 
		int power2 = power;
		for (int k = 0; k < 4 + EClass.rnd(2); k++)
		{
			SourceStat.Row row2 = list5.RandomItem(); 
			list5.Remove(row2); 
			SourceStat.Row row2 = list4.RandomItem(); 
			list4.Remove(row2); 
			Proc(hex2 ? EffectId.Debuff : EffectId.Buff, CC, TC, power2, new ActRef
			{
				n1 = row2.alias

@@ -1594,13 +1594,13 @@ public static bool DamageEle(Card CC, EffectId id, int power, Element e, List<Po

cs
			power = power * 2 / 3;
		}
		int a2 = power;
		int num9 = TC.WIL * (isPowerful ? 20 : 5); 
		int num8 = TC.WIL * (isPowerful ? 20 : 5); 
		ConHolyVeil condition3 = TC.GetCondition<ConHolyVeil>();
		if (condition3 != null)
		{
			num9 += condition3.power * 5; 
			num8 += condition3.power * 5; 
		}
		if (EClass.rnd(a2) < num9 / EClass.sources.stats.alias[n].hexPower && EClass.rnd(10) != 0) 
		if (EClass.rnd(a2) < num8 / EClass.sources.stats.alias[n].hexPower && EClass.rnd(10) != 0) 
		{
			TC.Say("debuff_resist", TC);
			CC.DoHostileAction(TC);

@@ -1765,13 +1765,13 @@ public static bool DamageEle(Card CC, EffectId id, int power, Element e, List<Po

cs
	case EffectId.DamageMindGreat:
	case EffectId.Weaken:
	{
		bool flag7 = id == EffectId.DamageBody || id == EffectId.DamageBodyGreat; 
		bool flag8 = id == EffectId.DamageBody || id == EffectId.DamageBodyGreat; 
		bool mind = id == EffectId.DamageMind || id == EffectId.DamageMindGreat;
		int num6 = ((id == EffectId.DamageBody || id == EffectId.DamageMind) ? 1 : (4 + EClass.rnd(4)));
		if (id == EffectId.Weaken)
		{
			flag7 = EClass.rnd(2) == 0; 
			mind = !flag7; 
			flag8 = EClass.rnd(2) == 0; 
			mind = !flag8; 
			num6 = 1;
		}
		else

@@ -1779,10 +1779,10 @@ public static bool DamageEle(Card CC, EffectId id, int power, Element e, List<Po

cs
			TC.PlayEffect("debuff");
			TC.PlaySound("debuff");
		}
		TC.Say(flag7 ? "damageBody" : "damageMind", TC); 
		TC.Say(flag8 ? "damageBody" : "damageMind", TC); 
		for (int l = 0; l < num6; l++)
		{
			TC.DamageTempElements(power, flag7, mind); 
			TC.DamageTempElements(power, flag8, mind); 
		}
		if (TC.IsPC)
		{

@@ -1827,7 +1827,6 @@ public static bool DamageEle(Card CC, EffectId id, int power, Element e, List<Po

cs
		break;
	}
	case EffectId.HealComplete:
		Dice.Create("SpHealLight", power, CC, (actRef.refThing != null) ? null : actRef.act); 
		TC.HealHPHost(9999, (actRef.refThing == null) ? HealSource.Magic : HealSource.Item);
		TC.CureHost(CureType.HealComplete, power, state);
		TC.Say("heal_heavy", TC);

@@ -1843,13 +1842,17 @@ public static bool DamageEle(Card CC, EffectId id, int power, Element e, List<Po

cs
		{
			Debug.Log(actRef.act.id);
		}
		int num8 = Dice.Create((actRef.act != null && EClass.sources.calc.map.ContainsKey(actRef.act.ID)) ? actRef.act.ID : "SpHealLight", power, CC, (actRef.refThing != null) ? null : actRef.act).Roll(); 
		int num9 = Dice.Create((actRef.act != null && EClass.sources.calc.map.ContainsKey(actRef.act.ID)) ? actRef.act.ID : "SpHealLight", power, CC, (actRef.refThing != null) ? null : actRef.act).Roll(); 
		if (actRef.refThing != null) 
		{ 
			num9 = num9 * (100 + actRef.refThing.Evalue(7500)) / 100; 
		} 
		if (flag)
		{
			TC.DamageHP(num8 / 2, 919, power); 
			TC.DamageHP(num9 / 2, 919, power); 
			break;
		}
		TC.HealHPHost(num8, (actRef.refThing == null) ? HealSource.Magic : HealSource.Item); 
		TC.HealHPHost(num9, (actRef.refThing == null) ? HealSource.Magic : HealSource.Item); 
		TC.CureHost(CureType.Heal, power, state);
		TC.Say((power >= 300) ? "heal_heavy" : "heal_light", TC);
		break;

@@ -2120,10 +2123,10 @@ public static bool DamageEle(Card CC, EffectId id, int power, Element e, List<Po

cs
		{
			power /= 4;
		}
		List<Thing> list4 = TC.things.List((Thing t) => (t.Num <= 1 && t.IsEquipmentOrRanged && !t.IsToolbelt && !t.IsLightsource && t.isEquipped) ? true : false); 
		if (list4.Count != 0) 
		List<Thing> list5 = TC.things.List((Thing t) => (t.Num <= 1 && t.IsEquipmentOrRanged && !t.IsToolbelt && !t.IsLightsource && t.isEquipped) ? true : false); 
		if (list5.Count != 0) 
		{
			Thing thing5 = list4.RandomItem(); 
			Thing thing5 = list5.RandomItem(); 
			TC.Say("acid_hit", TC);
			if (thing5.isAcidproof)
			{

ActPlan

@@ -96,6 +96,7 @@ public bool Perform(bool repeated = false)

cs
		AIAct aIAct = act as AIAct;
		if (act.IsAct)
		{
			Act.CC = EClass.pc; 
			if (act.PerformDistance != -1 && (num > act.PerformDistance || (num == 1 && !flag)))
			{
				cc.SetAIImmediate(new DynamicAIAct(act.GetText(), () => act.Perform(cc, tc, pos))

ActPray

@@ -26,25 +26,26 @@ public static bool TryPray(Chara c, bool passive = false)

cs
	if (c.faith.IsEyth)
	{
		c.Say("pray", c);
		if (passive) 
		if (passive && c.Evalue(1655) >= 2 && EClass.pc.party.members.Count > 1) 
		{
			if (c.Evalue(1655) >= 2 && EClass.pc.party.members.Count > 1) 
			foreach (Chara member in EClass.pc.party.members) 
			{
				foreach (Chara member in EClass.pc.party.members) 
				if (member != EClass.pc) 
				{
					if (member != EClass.pc) 
					{ 
						member.Say("pray2", member, member.faith.Name); 
						member.ModExp(306, 200); 
					} 
					member.Say("pray2", member, member.faith.Name); 
					member.ModExp(306, 200); 
				}
			}
		}
		else
		if (EClass.player.prayed) 
		{
			c.PlaySound("pray_ignore");
		}
		c.ModExp(306, 100); 
		else
		{ 
			EClass.player.prayed = true; 
			c.ModExp(306, 100); 
		} 
		return true;
	}
	foreach (Chara member2 in EClass.pc.party.members)

ActRanged

@@ -293,6 +293,7 @@ void Shoot(Card _tc, Point _tp)

cs
		CellEffect effect = Act.TP.cell.effect;
		if (effect != null && effect.id == 6 && EClass.rnd(2) == 0)
		{
			Prepare(); 
			AttackProcess.Current.PlayRangedAnime(numFire);
			Act.CC.PlaySound(missSound);
			Act.CC.Say("abMistOfDarkness_miss", Act.CC);

AttackProcess

@@ -337,6 +337,10 @@ public void Prepare(Chara _CC, Thing _weapon, Card _TC = null, Point _TP = null,

cs

	public void PlayRangedAnime(int numFire)
	{
		if (weapon == null) 
		{ 
			return; 
		} 
		bool isGun = toolRange is TraitToolRangeGun;
		bool isCane = toolRange is TraitToolRangeCane;
		GameSetting.EffectData data = EClass.setting.effect.guns.TryGetValue(weapon.id) ?? EClass.setting.effect.guns[isCane ? "cane" : (isGun ? "gun" : "bow")];

Biography

@@ -409,6 +409,10 @@ public void GenerateAppearance(Chara c)

cs
	{
		SourceRace.Row race = c.race;
		height = race.height + EClass.rnd(race.height / 5 + 1) - EClass.rnd(race.height / 5 + 1);
		if (c.source.tag.Contains("mini")) 
		{ 
			height /= 10; 
		} 
		weight = height * height * (EClass.rnd(6) + 18) / 10000;
	}

Card

@@ -3929,16 +3929,7 @@ public void DamageHP(int dmg, int ele, int eleP = 100, AttackSource attackSource

cs
			c.PlayEffect("blood").SetParticleColor(EClass.Colors.matColors[material.alias].main).Emit(20 + (int)(30f * ratio));
			if (EClass.core.config.test.showNumbers || isThing)
			{
				Popper popper = EClass.scene.popper.Pop(renderer.PositionCenter(), "DamageNum"); 
				Color c2 = (c.IsPC ? EClass.Colors.textColors.damagePC : (c.IsPCFaction ? EClass.Colors.textColors.damagePCParty : EClass.Colors.textColors.damage)); 
				if (e != Element.Void) 
				{ 
					c2 = EClass.Colors.elementColors.TryGetValue(e.source.alias); 
					float num16 = (c2.r + c2.g + c2.b) / 3f; 
					num16 = ((num16 > 0.5f) ? 0f : (0.6f - num16)); 
					c2 = new Color(c2.r + num16, c2.g + num16, c2.b + num16, 1f); 
				} 
				popper.SetText(dmg.ToString() ?? "", c2); 
				EClass.scene.damageTextRenderer.Add(this, c, dmg, e); 
			}
		});
	}

@@ -4121,7 +4112,7 @@ public void DamageHP(int dmg, int ele, int eleP = 100, AttackSource attackSource

cs
		if (!isDestroyed)
		{
			Die(e, origin, attackSource);
			if (trait.CanBeSmashedToDeath) 
			if (trait.CanBeSmashedToDeath && !EClass._zone.IsUserZone) 
			{
				Rand.SetSeed(uid);
				if (EClass.rnd(3) == 0 && !isCrafted && !isCopy)

@@ -6006,7 +5997,7 @@ public void Decay(int a = 10)

cs
			}
			if (IsFood)
			{
				elements.SetBase(73, -10); 
				elements.ModBase(73, -10); 
			}
		}
	}

CharaAbility

@@ -43,7 +43,10 @@ public class CharaAbility : EClass

cs
				continue;
			}
		}
		list.Add(row); 
		if (!row.tag.Contains("noRandomAbility")) 
		{ 
			list.Add(row); 
		} 
	}
	return list;
}

@@ -125,44 +128,6 @@ string ConvertID(string s)

cs
		}
	}

	public void BuildRandomAbilityList() 
	{ 
		foreach (SourceElement.Row row in EClass.sources.elements.rows) 
		{ 
			if (row.abilityType.Length == 0 || row.aliasRef == "mold") 
			{ 
				continue; 
			} 
			switch (row.id) 
			{ 
			case 5000: 
			case 5001: 
			case 5005: 
			case 5040: 
			case 5048: 
			case 6400: 
			case 6410: 
			case 8200: 
				continue; 
			} 
			if (row.idMold != 0 && !(owner.trait is TraitAdventurer)) 
			{ 
				switch (row.aliasRef) 
				{ 
				case "eleEther": 
				case "eleAcid": 
				case "eleCut": 
				case "eleImpact": 
					continue; 
				} 
			} 
			if (!row.tag.Contains("noRandomAbility")) 
			{ 
				randomAbilities.Add(row); 
			} 
		} 
	} 

	public void Add(int id, int chance, bool pt)
	{
		if (owner._listAbility == null)

ContentConfigTest

@@ -13,6 +13,8 @@ public class ContentConfigTest : ContentConfig

cs

	public UIButton toggleShowNumber;

	public UIButton toggleStackNumber; 

	public UIButton toggleAAPortrait;

	public UIButton toggleExTurn;

@@ -68,6 +70,10 @@ public override void OnInstantiate()

cs
	{
		base.config.test.showNumbers = on;
	});
	toggleStackNumber.SetToggle(base.config.test.stackNumbers, delegate(bool on) 
	{ 
		base.config.test.stackNumbers = on; 
	}); 
	toggleToolNoPick.SetToggle(base.config.test.toolNoPick, delegate(bool on)
	{
		base.config.test.toolNoPick = on;

CoreConfig

@@ -526,6 +526,8 @@ public class Test

cs

		public bool showNumbers;

		public bool stackNumbers; 

		public bool aaPortrait;

		public bool extraTurnaround;

+DamageTextRenderer

File Created
cs
using UnityEngine;

public class DamageTextRenderer : EClass
{
	public Card lastTarget;

	public Card lastAttacker;

	public Element lastElement = Element.Void;

	public int sum;

	public int num;

	public void Add(Card target, Card attacker, int dmg, Element e = null)
	{
		if (e == null)
		{
			e = Element.Void;
		}
		if (lastTarget != target || lastAttacker != attacker || lastElement.id != e.id)
		{
			Flush();
			lastTarget = target;
			lastAttacker = attacker;
			lastElement = e;
		}
		sum += dmg;
		num++;
		if (!EClass.core.config.test.stackNumbers)
		{
			Flush();
		}
	}

	public void Flush()
	{
		if (this.num != 0)
		{
			Card card = lastTarget;
			Card card2 = lastAttacker;
			Element element = lastElement;
			Popper popper = EClass.scene.popper.Pop(card.renderer.PositionCenter(), "DamageNum");
			Color c = EClass.Colors.textColors.damage;
			if (card2 != null)
			{
				c = (card2.IsPC ? EClass.Colors.textColors.damagePC : (card2.IsPCFaction ? EClass.Colors.textColors.damagePCParty : EClass.Colors.textColors.damage));
			}
			if (element != Element.Void)
			{
				c = EClass.Colors.elementColors.TryGetValue(element.source.alias);
				float num = (c.r + c.g + c.b) / 3f;
				num = ((num > 0.5f) ? 0f : (0.6f - num));
				c = new Color(c.r + num, c.g + num, c.b + num, 1f);
			}
			popper.SetText((this.num == 1) ? (sum.ToString() ?? "") : (sum + "<size=18> (x" + this.num + ")</size>"), c);
			sum = (this.num = 0);
		}
	}
}

HitSummary

@@ -93,9 +93,13 @@ public bool CanExecute()

cs
				}
			}
		}
		else if (recipe.ingredients[0].thing == null || recipe.ingredients[0].thing.Num < countValid) 
		else
		{
			return false; 
			Thing thing = recipe.ingredients[0].thing; 
			if (thing == null || recipe.ingredients[0].thing.Num < countValid / (thing.W * thing.H)) 
			{ 
				return false; 
			} 
		}
	}
	return true;

RecipeCard

@@ -223,10 +223,6 @@ public override Thing Craft(BlessedState blessed, bool sound = false, List<Thing

cs
		rarity = (flag ? Rarity.Crude : Rarity.Normal)
	});
	Thing thing = (flag3 ? ThingGen.Create(key) : ThingGen.Create(key, num, num4));
	if (thing.trait.CraftNum > 1) 
	{ 
		thing.SetNum(thing.trait.CraftNum); 
	} 
	thing.idSkin = idSkin;
	if (thing.IsEquipment && ings != null)
	{

@@ -289,6 +285,15 @@ public override Thing Craft(BlessedState blessed, bool sound = false, List<Thing

cs
		thing.SetNum(1);
		return thing;
	}
	int num5 = thing.trait.CraftNum; 
	if (crafter != null && EClass.pc.Evalue(1417) > 0 && crafter.WitchDoubleCraftChance(thing) > EClass.rnd(100)) 
	{ 
		num5 *= 2; 
	} 
	if (num5 > 1) 
	{ 
		thing.SetNum(num5); 
	} 
	if (EClass.pc.held == null || !thing.TryStackTo(EClass.pc.held.Thing))
	{
		EClass.pc.HoldCard(thing);

Scene

@@ -102,6 +102,8 @@ public enum Mode

cs

	public Material matFloorEx;

	public DamageTextRenderer damageTextRenderer = new DamageTextRenderer(); 

	public ParticleSystem psFoot;

	public ParticleSystem psSmoke;

@@ -675,6 +677,7 @@ public void OnUpdate()

cs
			EMono.ui.mouseInfo.SetText();
		}
		EMono.screen.Draw();
		damageTextRenderer.Flush(); 
		actionMode.OnAfterUpdate();
		if (EMono.player.lastTransition == null || EMono.player.simulatingZone)
		{

Thing

@@ -856,7 +856,7 @@ public override void WriteNote(UINote n, Action<UINote> onWriteNote = null, IIns

cs
			text2 = array[0] + Environment.NewLine + text3 + array[1];
		}
	}
	if (flag) 
	if (flag && !(trait is TraitPotionAlchemy)) 
	{
		text2 = recipe.GetName();
	}

+TraitAlchemyBench

File Created
cs
public class TraitAlchemyBench : TraitWorkbench
{
	public override int WitchDoubleCraftChance(Thing t)
	{
		return 100;
	}

	public override bool Contains(RecipeSource r)
	{
		return r.idFactory == "tool_alchemy";
	}
}

TraitCrafter

@@ -64,6 +64,11 @@ public enum AnimeType

cs

	public virtual int CostSP => 1;

	public virtual int WitchDoubleCraftChance(Thing t) 
	{ 
		return 0; 
	} 

	public virtual string IDReqEle(RecipeSource r)
	{
		return GetParam(1) ?? "handicraft";

TraitDrink

@@ -173,7 +173,7 @@ public override void OnDrink(Chara c)

cs
		n1 = N1,
		isPerfume = (this is TraitPerfume),
		refThing = owner.Thing,
		act = ((source != null) ? ACT.Create(source) : null) 
		act = ((source != null && source.id != 0) ? ACT.Create(source) : null) 
	});
	FoodEffect.ProcTrait(c, owner);
}

+TraitPotionAlchemy

File Created
cs
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class TraitPotionAlchemy : TraitPotionRandom
{
	public override int Power => owner.Power;

	public override void OnCrafted(Recipe recipe)
	{
		owner.refVal = 0;
		List<Element> list = owner.elements.dict.Values.Where((Element e) => e.IsTrait).ToList();
		list.Sort((Element a, Element b) => Mathf.Abs(b.Value) - Mathf.Abs(a.Value));
		int num = 0;
		foreach (Element item in list)
		{
			int num2 = item.Value / 10;
			switch (item.id)
			{
			case 750:
			case 753:
				num = ((num2 >= 6) ? 8402 : ((num2 >= 4) ? 8401 : 8400));
				break;
			case 754:
				num = 8471;
				break;
			case 755:
				num = 8470;
				break;
			case 751:
				num = 8501;
				break;
			case 752:
				num = 8791;
				break;
			case 760:
				num = 8704;
				break;
			case 756:
				num = 8506;
				break;
			}
			if (num != 0)
			{
				break;
			}
		}
		owner.refVal = num;
	}
}

TraitPotionRandom

@@ -12,12 +12,27 @@ public class TraitPotionRandom : TraitPotion

cs

	public override int Power => 200;

	public override EffectId IdEffect => source.proc[0].ToEnum<EffectId>(); 
	public override EffectId IdEffect 
	{ 
		get 
		{ 
			if (!source.proc.IsEmpty()) 
			{ 
				return source.proc[0].ToEnum<EffectId>(); 
			} 
			return EffectId.DrinkWaterDirty; 
		} 
	} 

	public override string N1 => source.proc.TryGet(1, returnNull: true);

	public override bool IsNeg => source.tag.Contains("neg");

	public override void OnCreate(int lv) 
	{ 
		TraitPotion.Create(owner, selecter.Select(lv)); 
	} 

	public override SourceElement.Row GetRefElement()
	{
		return source;

@@ -28,13 +43,21 @@ public override int GetValue()

cs
		return source.value * 120 / 100;
	}

	public override void OnCreate(int lv) 
	{ 
		TraitPotion.Create(owner, selecter.Select(lv)); 
	} 

	public override string GetName()
	{
		return Lang.TryGet("potion_" + source.alias) ?? "potion_".lang(source.GetName().ToLower()); 
		string text; 
		if (owner.refVal != 0) 
		{ 
			text = Lang.TryGet("potion_" + source.alias); 
			if (text == null) 
			{ 
				return "potion_".lang(source.GetName().ToLower()); 
			} 
		} 
		else
		{ 
			text = base.GetName(); 
		} 
		return text; 
	}
}

+TraitToolAlchemy

File Created
cs
public class TraitToolAlchemy : TraitWorkbench
{
	public override int WitchDoubleCraftChance(Thing t)
	{
		return 100;
	}
}