Skip to content

EA 23.188 Stable Patch 2

August 26, 2025

24 files modified.

Important Changes

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

Zone (1)

cs
public Card AddChara(string id, int x, int z) 
public Chara AddChara(string id, int x, int z) 

ActThrow

public static EffectIRenderer Throw(Card c, Point p, Card target, Thing t, Throw

cs
		TraitMonsterBall traitMonsterBall = t.trait as TraitMonsterBall;
		if (traitMonsterBall.chara != null)
		{
			if (traitMonsterBall.IsLittleBall && !(EClass._zone is Zone_LittleGarden)) 
			if (traitMonsterBall.IsLittleBall && !(EClass._zone is Zone_LittleGarden) && !EClass.game.IsSurvival) 
			{
				break;
			}

BiomeProfile

public override bool TryCreate(Point p)

cs
		}
		p.SetObj(item.idObj);
		cell.objDir = EScriptable.rnd(8);
		if (cell.sourceObj.HasGrowth && cell.sourceObj.id != 103) 
		if (cell.sourceObj.HasGrowth && !EClass._zone.IsPCFactionOrTent && cell.sourceObj.id != 103) 
		{
			cell.growth.SetRandomStage();
		}

DramaOutcome

public void QuestCraft_Drop1()

cs
	public void QuestDefense_0()
	{
		Prologue prologue = EMono.game.Prologue;
		Card card = EMono._zone.AddChara("punk", prologue.posPunk.x, prologue.posPunk.y); 
		card.things.DestroyAll(); 
		(EMono._zone.AddThing("gallows", prologue.posPunk.x, prologue.posPunk.y).Install().trait as TraitShackle).Restrain(card); 
		Chara chara = EMono._zone.AddChara("punk", prologue.posPunk.x, prologue.posPunk.y); 
		chara.things.DestroyAll(); 
		(EMono._zone.AddThing("gallows", prologue.posPunk.x, prologue.posPunk.y).Install().trait as TraitShackle).Restrain(chara); 
		CardBlueprint.SetNormalRarity();
	}

public void QuestVernis_DropRecipe()

cs
public void QuestDefense_1()
{
	Prologue prologue = EMono.game.Prologue;
	Card tc = EMono._zone.AddChara("boar", prologue.posPunk.x + 1, prologue.posPunk.y); 
	Chara tc = EMono._zone.AddChara("boar", prologue.posPunk.x + 1, prologue.posPunk.y); 
	(EMono._zone.AddThing("gallows", prologue.posPunk.x + 1, prologue.posPunk.y).Install().trait as TraitShackle).Restrain(tc);
	EMono.player.DropReward(ThingGen.Create("stone").SetNum(20));
	EMono.player.DropReward(ThingGen.Create("330").SetNum(3), silent: true).Identify(show: false);

EloMap

public void Init(EloMapActor _actor)

cs
		if (cell == null)
		{
			Debug.Log("cell is null:" + x + "/" + y);
			continue; 
		}
		cell.zone = zone; 
		if (!zone.IsInstance) 
		else if (!zone.IsInstance) 
		{
			cell.zone = zone; 
			cell.obj = zone.icon;
		}
	}

ModManager

public IEnumerator RefreshMods(Action onComplete, bool syncMods)

cs
		}
	}
	ModUtil.OnModsActivated();
	ModUtil.LoadTypeFallback(); 
	BaseModManager.isInitialized = true;
	yield return new WaitForEndOfFrame();
	onComplete?.Invoke();

ModUtil

public static void Test()

cs

	public static void OnModsActivated()
	{
		RegisterSerializedTypeFallback("TrueArena", "ArenaWaveEvent", "ZoneEvent"); 
	} 
	public static void LoadTypeFallback() 
	{ 
		string text = "type_resolver.txt"; 
		string[] array = new string[0]; 
		if (File.Exists(CorePath.RootData + text)) 
		{ 
			array = IO.LoadTextArray(CorePath.RootData + text); 
		} 
		else
		{ 
			array = new string[2] { "TrueArena,ArenaWaveEvent,ZoneEvent", "Elin-GeneRecombinator,Elin_GeneRecombinator.IncubationSacrifice,Chara" }; 
			IO.SaveTextArray(CorePath.RootData + text, array); 
		} 
		string[] array2 = array; 
		for (int i = 0; i < array2.Length; i++) 
		{ 
			string[] array3 = array2[i].Split(','); 
			if (array3.Length >= 2) 
			{ 
				RegisterSerializedTypeFallback(array3[0], array3[1], array3[2]); 
			} 
		} 
	}

	public static void RegisterSerializedTypeFallback(string nameAssembly, string nameType, string nameFallbackType)

QuestManager

public void OnAdvanceHour()

cs

	public bool IsAdded<T>() where T : Quest
	{
		if (IsStarted<T>()) 
		if (IsStarted<T>() || GetPhase<T>() == 999) 
		{
			return true;
		}

SourcePref

public static SourcePref ReadFromIni(string path)

cs
	sourcePref.pivotY = iniData.Global["pivotY"].ToInt();
	sourcePref.shadow = iniData.Global["shadow"].ToInt();
	sourcePref.shadowX = iniData.Global["shadowX"].ToInt();
	sourcePref.shadowY = iniData.Global["shadowY"].ToInt(); 
	sourcePref.shadowRX = -sourcePref.shadowX; 
	int num2 = (sourcePref.shadowRY = iniData.Global["shadowY"].ToInt()); 
	sourcePref.shadowY = num2; 
	sourcePref.ints[3] = iniData.Global["height"].ToInt();
	sourcePref.scaleIcon = iniData.Global["scaleIcon"].ToInt();
	sourcePref.liquidMod = iniData.Global["liquidMod"].ToInt();

SurvivalManager

public bool gotTaxChest

cs
			}
		}

		public bool gotGaragara 
		{ 
			get 
			{ 
				return bits[2]; 
			} 
			set 
			{ 
				bits[2] = value; 
			} 
		} 
		[OnSerializing]
		private void _OnSerializing(StreamingContext context)
		{

private void _OnDeserialized(StreamingContext context)

cs
	[JsonProperty]
	public Flags flags = new Flags();

	[JsonProperty] 
	public List<string> listReward = new List<string>(); 
	public bool IsInRaid => GetRaidEvent() != null;

	public ZoneEventRaid GetRaidEvent()

public void MeteorThing(Point pos, string id, bool install = false)

cs
		Meteor(pos, delegate
		{
			Card card = EClass._zone.AddCard(ThingGen.Create(id), pos);
			if (card.id == "rod_wish") 
			{ 
				card.SetCharge(1); 
			} 
			if (install) 
			{ 
				card.Install(); 
			} 
		}); 
	} 
	public void MeteorThing(Point pos, Thing t, bool install = false) 
	{ 
		Meteor(pos, delegate
		{ 
			Card card = EClass._zone.AddCard(t, pos); 
			if (install)
			{
				card.Install();

public void MeteorThing(Point pos, string id, bool install = false)

cs
		});
	}

	public void RefreshRewards() 
	{ 
		if (listReward.Count <= 0) 
		{ 
			Add(new string[7] { "659", "758", "759", "806", "828", "1190", "1191" }); 
			if (flags.raidLv < 50) 
			{ 
				Add(new string[7] { "pillow_jure", "pillow_ehekatl", "pillow_opatos", "pillow_kumiromi", "pillow_lulwy", "pillow_mani", "pillow_itzpalt" }); 
			} 
			else
			{ 
				Add(new string[1] { "rod_wish" }); 
			} 
		} 
		void Add(string[] ids) 
		{ 
			foreach (string item in ids) 
			{ 
				listReward.Add(item); 
			} 
		} 
	} 
	public void OnExpandFloor(Point pos)
	{
		int i = 0;

public void OnExpandFloor(Point pos)

cs
	Check(60, delegate
	{
		EClass.pc.homeBranch.AddMemeber(EClass._zone.AddCard(CharaGen.Create("loytel"), pos.x, pos.z).Chara);
		CheckLoytelDebt(); 
	});
	Check(80, delegate
	{

void Check(int a, Action action)

cs
		}
	}

	public void CheckLoytelDebt() 
	{ 
		if (EClass.game.cards.globalCharas.Find("loytel") != null && !EClass.game.quests.IsAdded<QuestDebt>()) 
		{ 
			Quest quest = EClass.game.quests.Add("debt", "loytel"); 
			EClass.game.quests.globalList.Remove(quest); 
			EClass.game.quests.Start(quest); 
		} 
	} 
	public bool OnMineWreck(Point point)
	{
		if (EClass._zone.events.GetEvent<ZoneEventSurvival>() == null)
		{
			EClass._zone.events.Add(new ZoneEventSurvival());
		}
		CheckLoytelDebt(); 
		SourceObj.Row sourceObj = point.cell.sourceObj;
		int searchWreck = EClass.game.survival.flags.searchWreck;
		string[] array = new string[6] { "log", "rock", "branch", "bone", "grass", "vine" };
		int chanceChange = 25;
		int num = searchWreck / 50 + 3; 
		int num = searchWreck / 50 + 1; 
		if (searchWreck == 0)
		{
			Thing t2 = ThingGen.CreateParcel(null, ThingGen.Create("log").SetNum(6), ThingGen.Create("rock").SetNum(4), ThingGen.Create("resin").SetNum(2), ThingGen.Create("money2").SetNum(10), ThingGen.Create("1267"), ThingGen.CreateRod(50311, 8));

public bool OnMineWreck(Point point)

cs
	{
		return Pop(TraitSeed.MakeRandomSeed());
	}
	if (EClass.rnd(12) == 0) 
	if (EClass.rnd(12 + num / 5) == 0) 
	{
		return Pop(ThingGen.Create("money2"));
	}
	if (searchWreck > 10 && EClass.rnd(40 + num) == 0) 
	{ 
		TreasureType treasureType = ((EClass.rnd(10) == 0) ? TreasureType.BossNefia : ((EClass.rnd(10) == 0) ? TreasureType.Map : TreasureType.RandomChest)); 
		Thing t3 = ThingGen.Create(treasureType switch
		{ 
			TreasureType.Map => "chest_treasure",  
			TreasureType.BossNefia => "chest_boss",  
			_ => "chest3",  
		}); 
		ThingGen.CreateTreasureContent(t3, num, treasureType, clearContent: true); 
		MeteorThing(GetRandomPoint(), t3, install: true); 
	} 
	if (EClass.rnd(12) == 0)
	{
		Point pos = point.GetNearestPoint(allowBlock: false, allowChara: false, allowInstalled: false, ignoreCenter: true) ?? point;
		if (searchWreck < 50 || EClass.rnd(3) != 0) 
		if (searchWreck < 100 || EClass.rnd(3) != 0) 
		{
			EClass._zone.SpawnMob(pos, SpawnSetting.HomeWild(num));
		}

bool Next()

cs
		Point pos2 = point.GetNearestPoint(allowBlock: false, allowChara: false, allowInstalled: false, ignoreCenter: true) ?? point;
		if (searchWreck2 == 20)
		{
			Thing container = ThingGen.CreateParcel(null, ThingGen.CreateRecipe("container_shipping"), ThingGen.CreateRecipe("stonecutter"), ThingGen.CreateRecipe("workbench2")); 
			Meteor(pos2, delegate
			{
				EClass._zone.AddCard(ThingGen.CreateRecipe("container_shipping"), pos2); 
				EClass._zone.AddCard(container, pos2); 
			});
		}
		if (searchWreck2 > (EClass.debug.enable ? 5 : 100) && !flags.gotTaxChest)

bool Next()

cs
			MeteorThing(pos2, "chest_tax");
			flags.gotTaxChest = true;
		}
		if (searchWreck2 > (EClass.debug.enable ? 10 : 200) && !flags.gotGaragara) 
		{ 
			MeteorThing(pos2, "rolling_fortune"); 
			flags.gotGaragara = true; 
		} 
		NextObj();
		return true;
	}

public void OnUpdateRecruit(FactionBranch branch)

cs

	public void StartRaid()
	{
		SE.Play("warhorn"); 
		Msg.Say("warhorn"); 
		flags.raid = true;
		Point pos = EClass.pc.pos.GetNearestPoint(allowBlock: false, allowChara: false, allowInstalled: false, ignoreCenter: true) ?? EClass.pc.pos;
		Meteor(pos, delegate

TaskPoint

public override IEnumerable<Status> Run()

cs
		{
			AM_Adv.actCount++;
		}
		if (child != null && child.status == Status.Fail) 
		{ 
			yield return Cancel(); 
		} 
	}
	while (Loop);
}

ThingGen

public static void CreateTreasureContent(Thing t, int lv, TreasureType type, boo

cs
		}
		t.c_lockLv /= 2;
		break;
	case TreasureType.SurvivalRaid:
		t.Add("plat", EClass.rndHalf(Mathf.Min(3 + num / 10, 15))); 
		t.Add("money2", EClass.rndHalf(Mathf.Min(3 + num / 10, 10))); 
		t.Add("medal", EClass.rndHalf(8)); 
		t.Add("book_skill", 1, lv); 
		t.Add("book_skill", 1, lv); 
		t.c_lockLv /= 3; 
		break; 
	case TreasureType.RandomChest:
		flag2 = false;
		miracleChance /= 2;

TraitCoreDefense

public override void TrySetAct(ActPlan p)

cs
		{
			p.TrySetAct("actWarhorn", delegate
			{
				SE.Play("warhorn"); 
				Msg.Say("warhorn"); 
				EClass.game.survival.StartRaid();
				return true;
			});

public override void TrySetAct(ActPlan p)

cs
		{
			p.TrySetAct("actWarhornRaid", delegate
			{
				SE.Play("warhorn"); 
				Msg.Say("warhorn"); 
				EClass._zone.events.Add(new ZoneEventRaid());
				return true;
			});

TraitDemitas

public bool CanSpellwrite

cs
{
	get
	{
		if (!EClass.debug.enable) 
		if (!EClass.debug.enable && !EClass.game.quests.IsCompleted("demitas_spellwriter")) 
		{
			return EClass.game.quests.IsCompleted("demitas_spellwriter"); 
			return EClass.game.IsSurvival; 
		}
		return true;
	}

TraitKettle

public override bool CanJoinParty

cs
{
	get
	{
		if (!EClass.game.quests.IsCompleted("vernis_gold")) 
		if (!EClass.game.quests.IsCompleted("vernis_gold") && !EClass.game.IsSurvival) 
		{
			return EClass.debug.enable;
		}

TraitMerchantPlat

public override ShopType ShopType

cs
{
	get
	{
		if (!base.owner.IsPCFaction) 
		if (!base.owner.IsPCFaction || EClass.game.IsSurvival) 
		{
			return ShopType.Plat;
		}

TraitSpotBiome

using System.Collections.Generic;

cs
using System.Collections.Generic; 
public class TraitSpotBiome : TraitSpot
{
	public override int radius => 6;

public class TraitSpotBiome : TraitSpot

cs

	public override void Update()
	{
		if (EClass.rnd(5) != 0) 
		if (EClass.rnd(10) != 0 || !EClass._zone.IsPCFactionOrTent || !owner.IsInstalled) 
		{
			return;
		}
		Point randomPoint = GetRandomPoint();
		if (!randomPoint.IsSky && !randomPoint.HasObj && !randomPoint.HasBlock && !randomPoint.HasThing && randomPoint.cell.room == null) 
		if (randomPoint.IsSky || randomPoint.HasObj || randomPoint.HasBlock || randomPoint.HasThing || randomPoint.cell.room != null) 
		{
			if (EClass.rnd(5) == 0) 
			return; 
		} 
		if (EClass.game.IsSurvival) 
		{ 
			int num = 0; 
			foreach (Thing thing2 in EClass._map.props.installed.things) 
			{
				EClass._zone.SpawnMob(randomPoint); 
				if (thing2.trait is TraitSpotBiome) 
				{ 
					num++; 
				} 
			} 
			int num2 = CountNotableThing(); 
			if (EClass.rnd(num * 10) == 0) 
			{ 
				if (num2 < 2) 
				{ 
					string text = ((EClass.rnd(10) == 0) ? "statue_god" : ((EClass.rnd(2) == 0) ? "statue_power" : "altar")); 
					if (text == "altar" && EClass.rnd(20) == 0) 
					{ 
						text = ((EClass.rnd(5) == 0) ? "altar_machine" : ((EClass.rnd(3) == 0) ? "altar_fox" : ((EClass.rnd(2) == 0) ? "altar_fox2" : "altar_strife"))); 
					} 
					Thing thing = ThingGen.Create(text); 
					thing.SetPriceFix(-100); 
					EClass._zone.AddCard(thing, randomPoint).Install(); 
				} 
				if (EClass.rnd(40) == 0 && EClass._map.FindChara("big_daddy") == null) 
				{ 
					CardBlueprint.Set(new CardBlueprint
					{ 
						lv = EClass.game.survival.flags.raidLv + 10
					}); 
					Chara t = CharaGen.Create("big_daddy"); 
					EClass._zone.AddCard(t, randomPoint); 
					Msg.Say("sign_bigdaddy"); 
				} 
				return; 
			} 
		} 
		if (EClass.rnd(5) == 0) 
		{ 
			if (EClass.game.IsSurvival && EClass.game.survival.flags.raidLv < 20) 
			{ 
				EClass._zone.SpawnMob(randomPoint, SpawnSetting.HomeWild(1)); 
			}
			else
			{
				randomPoint.cell.biome.Populate(randomPoint, interior: false, 100f); 
				EClass._zone.SpawnMob(randomPoint); 
			} 
		} 
		else
		{ 
			randomPoint.cell.biome.Populate(randomPoint, interior: false, 100f); 
		} 
	} 
	public int CountNotableThing(bool tryRemove = true) 
	{ 
		int num = 0; 
		List<Thing> listRemove = new List<Thing>(); 
		foreach (Point item in ListPoints(null, onlyPassable: false)) 
		{ 
			if (!item.HasThing) 
			{ 
				continue; 
			} 
			foreach (Thing thing in item.Things) 
			{ 
				if (!thing.IsInstalled) 
				{ 
					continue; 
				} 
				if (thing.trait is TraitAltar) 
				{ 
					num++; 
					if (tryRemove && thing.c_priceFix == -100) 
					{ 
						TryRemove(thing, 4); 
					} 
				} 
				else if (thing.trait is TraitPowerStatue) 
				{ 
					num++; 
					if (tryRemove && !thing.isOn && thing.c_priceFix == -100) 
					{ 
						TryRemove(thing, 2); 
					} 
				} 
			} 
		} 
		if (tryRemove) 
		{ 
			foreach (Thing item2 in listRemove) 
			{ 
				item2.Destroy(); 
			} 
		} 
		return num; 
		void TryRemove(Thing t, int h) 
		{ 
			if (t.c_dateStockExpire == 0) 
			{ 
				t.c_dateStockExpire = EClass.world.date.GetRaw(h); 
			} 
			else if (EClass.world.date.IsExpired(t.c_dateStockExpire)) 
			{ 
				listRemove.Add(t); 
			}
		}
	}

TraitStrangeGirl

public override ShopType ShopType

cs
{
	get
	{
		if (!(EClass._zone is Zone_LittleGarden)) 
		if (!(EClass._zone is Zone_LittleGarden) && !EClass.game.IsSurvival) 
		{
			return ShopType.None;
		}

TreasureType

public enum TreasureType

cs
	BossNefia,
	BossQuest,
	Map,
	RandomChest 
	RandomChest, 
	SurvivalRaid 
}

Zone

public Card AddCardSplinkle(Card t, Point center, int radius = 4)

cs
		return AddCard(t, center);
	}

	public Card AddChara(string id, int x, int z) 
	public Chara AddChara(string id, int x, int z) 
	{
		return AddCard(CharaGen.Create(id), x, z); 
		return AddCard(CharaGen.Create(id), x, z) as Chara; 
	}

	public Card AddThing(string id, int x, int z)

ZoneEventRaid

public override void OnKill()

cs
		EClass.game.survival.flags.raidRound++;
		EClass.game.survival.flags.raidLv += 5;
		EClass.game.survival.flags.dateNextRaid = EClass.world.date.GetRaw(168);
		EClass.game.survival.RefreshRewards(); 
		Point pos = EClass.game.survival.GetRandomPoint() ?? EClass.pc.pos;
		string text = ((EClass.game.survival.flags.raidLv >= 50 && EClass.rnd(3) == 0) ? "statue_god" : ((EClass.game.survival.flags.raidLv >= 25 && EClass.rnd(2) == 0) ? "statue_power" : "altar")); 
		EClass.game.survival.MeteorThing(pos, text, install: true); 
		string item = EClass.game.survival.listReward.RandomItem(); 
		EClass.game.survival.listReward.Remove(item); 
		EClass.game.survival.MeteorThing(pos, item, install: true); 
	}
}

ZoneEventSiege

public override void OnKill()

cs
		Msg.Say("endSiege");
		SE.Play("kill_boss");
		EClass._zone.RefreshBGM();
		EClass._zone.AddCard(ThingGen.CreateTreasure("chest_boss", lv, TreasureType.BossNefia), GetSpawnPos().GetNearestPoint(allowBlock: false, allowChara: false, allowInstalled: false, ignoreCenter: true) ?? EClass.pc.pos).Install(); 
		EClass._zone.AddCard(ThingGen.CreateTreasure("chest_boss", lv, TreasureType.SurvivalRaid), GetSpawnPos().GetNearestPoint(allowBlock: false, allowChara: false, allowInstalled: false, ignoreCenter: true) ?? EClass.pc.pos).Install(); 
	}
}

ZoneEventSurvival

public override void OnTickRound()

cs
	{
		EClass._map.SetObj(cell.x, cell.z, 46);
	}
	if (EClass.player.stats.days >= 10 && !EClass.game.survival.flags.raid) 
	{ 
		EClass.game.survival.StartRaid(); 
	} 
	if (EClass.game.survival.flags.raid)
	{
		TraitVoidgate traitVoidgate = EClass._map.FindThing<TraitVoidgate>();

Zone_Nymelle

public override void OnBeforeSimulate()

cs
	}
	if (IsBossLv)
	{
		EClass._zone.AddChara("isygarad", 40, 37); 
		EClass._zone.AddChara("isygarad", 40, 37).ScaleByPrincipal(); 
		SoundManager.ForceBGM();
		LayerDrama.ActivateMain("mono", "nymelle_boss");
	}

Zone_StartSiteSky

public class Zone_StartSiteSky : Zone_StartSite

cs
	public override bool BlockBorderExit => true;

	public override string IdBiome => "Plain";
	public override bool ScaleMonsterLevel 
	{ 
		get 
		{ 
			if (EClass.game.IsSurvival) 
			{ 
				return EClass.game.survival.flags.raidLv >= 100; 
			} 
			return false; 
		} 
	} 
}