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)
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
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)
}
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()
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()
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)
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)
}
}
ModUtil.OnModsActivated();
ModUtil.LoadTypeFallback();
BaseModManager.isInitialized = true;
yield return new WaitForEndOfFrame();
onComplete?.Invoke();ModUtil
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 bool IsAdded<T>() where T : Quest
{
if (IsStarted<T>())
if (IsStarted<T>() || GetPhase<T>() == 999)
{
return true;
}SourcePref
public static SourcePref ReadFromIni(string path)
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 gotGaragara
{
get
{
return bits[2];
}
set
{
bits[2] = value;
}
}
[OnSerializing]
private void _OnSerializing(StreamingContext context)
{private void _OnDeserialized(StreamingContext context)
[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)
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)
});
}
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)
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)
}
}
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)
{
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));
} 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) 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)
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, delegateTaskPoint
public override IEnumerable<Status> Run()
{
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
}
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)
{
p.TrySetAct("actWarhorn", delegate
{
SE.Play("warhorn");
Msg.Say("warhorn");
EClass.game.survival.StartRaid();
return true;
});public override void TrySetAct(ActPlan p)
{
p.TrySetAct("actWarhornRaid", delegate
{
SE.Play("warhorn");
Msg.Say("warhorn");
EClass._zone.events.Add(new ZoneEventRaid());
return true;
});TraitDemitas
{
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
{
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
{
get
{
if (!base.owner.IsPCFaction)
if (!base.owner.IsPCFaction || EClass.game.IsSurvival)
{
return ShopType.Plat;
}TraitSpotBiome
using System.Collections.Generic;
using System.Collections.Generic;
public class TraitSpotBiome : TraitSpot
{
public override int radius => 6;public class TraitSpotBiome : TraitSpot
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
{
get
{
if (!(EClass._zone is Zone_LittleGarden))
if (!(EClass._zone is Zone_LittleGarden) && !EClass.game.IsSurvival)
{
return ShopType.None;
}TreasureType
BossNefia,
BossQuest,
Map,
RandomChest
RandomChest,
SurvivalRaid
}Zone
public Card AddCardSplinkle(Card t, Point center, int radius = 4)
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
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
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()
{
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()
}
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
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;
}
}
}