Skip to content

EA 23.92 Patch 3

February 13, 2025

22 files modified. 3 new files created.

Important Changes

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

GameIO (1)

cs
public static List<GameIndex> GetGameList(string path, bool sortByName = false) 
public static List<GameIndex> GetGameList(string path, bool sortByName = false, bool includeEmptyFolder = false) 

AI_Idle

@@ -186,10 +186,14 @@ public override IEnumerable<Status> Run()

cs
		{
			if (owner.IsRestrainedResident && owner.stamina.value > owner.stamina.max / 2)
			{
				owner.SetAI(new AI_Torture
				TraitShackle traitShackle = owner.pos.FindThing<TraitShackle>(); 
				if (traitShackle != null && traitShackle.AllowTraining) 
				{
					shackle = owner.pos.FindThing<TraitShackle>() 
				}); 
					owner.SetAI(new AI_Torture
					{ 
						shackle = traitShackle 
					}); 
				} 
				yield return Restart();
			}
			if (EClass.rnd(20) == 0)

@@ -586,11 +590,15 @@ public override IEnumerable<Status> Run()

cs
	}
	if (owner.IsRestrainedResident && owner.stamina.value > owner.stamina.max / 2)
	{
		owner.SetAI(new AI_Torture
		TraitShackle traitShackle2 = owner.pos.FindThing<TraitShackle>(); 
		if (traitShackle2 != null && traitShackle2.AllowTraining) 
		{
			shackle = owner.pos.FindThing<TraitShackle>() 
		}); 
		yield return Restart(); 
			owner.SetAI(new AI_Torture
			{ 
				shackle = traitShackle2 
			}); 
			yield return Restart(); 
		} 
	}
	if (!owner.IsPCFactionOrMinion && EClass.rnd(owner.isSynced ? 50 : 2000) == 0 && owner.hostility == Hostility.Neutral && EClass.pc.party.HasElement(1563) && !owner.race.tag.Contains("animal") && EClass._zone.IsTown && !EClass._zone.IsPCFaction && !owner.HasCondition<ConIncognito>())
	{

AI_PlayMusic

@@ -382,7 +382,7 @@ void LevelSong(int a)

cs

	public void Evaluate(bool success)
	{
		if (!owner.IsPC) 
		if (owner == null || !owner.IsPC) 
		{
			return;
		}

AM_Adv

@@ -155,9 +155,9 @@ public bool IsPressing()

cs

	private float gearAngle;

	protected bool updatePlans; 
	public bool updatePlans; 

	protected bool isMoving; 
	public bool isMoving; 

	private Vector3 lastCamPos;

ActPlan

@@ -528,12 +528,16 @@ public void _Update(PointTarget target)

cs
					}
					if (c2.host != EClass.pc)
					{
						TraitShackle traitShackle = c2.pos.FindThing<TraitShackle>(); 
						if (c2.IsRestrainedResident)
						{
							TrySetAct(new AI_PracticeDummy
							if (traitShackle != null && traitShackle.AllowTraining) 
							{
								target = c2 
							}); 
								TrySetAct(new AI_PracticeDummy
								{ 
									target = c2 
								}); 
							} 
						}
						else if ((c2.IsHostile() || altAction || c2.isRestrained) && c2.IsAliveInCurrentZone)
						{

@@ -834,6 +838,7 @@ void func()

cs
					{
						_ = cc.held;
						cc.PickHeld(msg: true);
						ActionMode.AdvOrRegion.updatePlans = true; 
						return false;
					}, cc.held, CursorSystem.Inventory, 1, isHostileAct: false, localAct: false);
				}

ActRestrain

@@ -33,14 +33,17 @@ public override bool Perform()

cs
		return true;
	}
	SE.Change();
	if (!shackle.owner.IsInstalled) 
	{ 
		EClass._zone.AddCard(shackle.owner, Act.TP); 
		shackle.owner.SetPlaceState(PlaceState.installed); 
	} 
	shackle.Restrain(Act.TC, msg: true);
	EClass._zone.AddCard(shackle.owner, Act.TP); 
	shackle.owner.SetPlaceState(PlaceState.installed); 
	if (!Act.TC.IsPCFaction)
	{
		EClass.player.ModKarma(-1);
	}
	if (Act.TC.IsPCFaction && EClass._zone.IsPCFaction) 
	if (Act.TC.IsPCFaction && EClass._zone.IsPCFaction && shackle.AllowTraining) 
	{
		Act.TC.Chara?.SetAI(new AI_Torture
		{

CTAG

@@ -33,5 +33,6 @@ public enum CTAG

cs
	noWish,
	dish_bonus,
	dish_fail,
	random_color 
	random_color, 
	noRandomEnc 
}

Card

@@ -3049,7 +3049,18 @@ public void RemoveThing(Thing thing)

cs
{
	if ((GetRootCard() as Chara)?.held == thing)
	{
		(GetRootCard() as Chara).held = null; 
		Chara obj = GetRootCard() as Chara; 
		obj.held = null; 
		if (obj.IsPC) 
		{ 
			WidgetCurrentTool instance = WidgetCurrentTool.Instance; 
			if ((bool)instance && instance.selected != -1 && instance.selectedButton.card != null && instance.selectedButton.card == thing) 
			{ 
				instance.selectedButton.card = null; 
			} 
			EClass.player.RefreshCurrentHotItem(); 
			ActionMode.AdvOrRegion.updatePlans = true; 
		} 
		RecalculateFOV();
	}
	dirtyWeight = true;

@@ -4581,7 +4592,7 @@ public void SpawnLoot(Card origin)

cs
	}
	bool flag2 = Chara.race.corpse[1].ToInt() > EClass.rnd(1500) || (Chara.IsPowerful && !IsPCFaction) || EClass.debug.godFood;
	int num = 1;
	if (Chara.race.IsAnimal && EClass.rnd(EClass._zone.IsPCFaction ? 3 : 5) == 0) 
	if (!IsMinion && Chara.race.IsAnimal && EClass.rnd(EClass._zone.IsPCFaction ? 3 : 5) == 0) 
	{
		flag2 = true;
	}

@@ -4590,7 +4601,7 @@ public void SpawnLoot(Card origin)

cs
		flag2 = true;
		num = EClass.rndHalf(4 + 10 * (50 + Mathf.Max(0, (int)MathF.Sqrt(EClass.pc.Evalue(290) * 10))) / 100);
	}
	else if (origin != null && origin.HasElement(290)) 
	else if (origin != null && origin.HasElement(290) && !IsMinion) 
	{
		if (!flag2 && Chara.race.corpse[1].ToInt() > EClass.rnd(150000 / (100 + (int)Mathf.Sqrt(origin.Evalue(290)) * 5)))
		{

@@ -4809,7 +4820,7 @@ bool chance(int i)

cs
		}
		if (IsMinion)
		{
			i *= 2; 
			i *= 5; 
		}
		if (EClass.rnd(i) == 0)
		{

ContentHomeLog

@@ -24,7 +24,7 @@ public void RefreshLog()

cs
			{
				b.text1.SetColor(a.col.ToEnum<FontColor>());
			}
			b.text2.text = a.date.month + "/" + a.date.day + " " + a.date.hour + ":" + a.date.min; 
			b.text2.text = a.date.month + "/" + a.date.day + " " + ((a.date.hour < 10) ? "0" : "") + a.date.hour + ":" + ((a.date.min < 10) ? "0" : "") + a.date.min; 
		}
	};
	uIList.Clear();

Core

@@ -406,6 +406,8 @@ private void LateUpdate()

cs

	public void OnApplicationFocus(bool focus)
	{
		Resources.UnloadUnusedAssets(); 
		GC.Collect(); 
		if (config == null)
		{
			return;

FactionBranch

@@ -1199,6 +1199,17 @@ public void OnClaimZone()

cs

	public void OnUnclaimZone()
	{
		List<Element> list = owner.ListLandFeats(); 
		elements.SetBase(list[1].id, 0); 
		elements.SetBase(list[2].id, 0); 
		if (lv < 5) 
		{ 
			return; 
		} 
		foreach (Element item in list.Where((Element a) => a.HasTag("network")).ToList()) 
		{ 
			EClass.pc.faction.elements.ModBase(item.id, -item.Value); 
		} 
	}

	public void ValidateUpgradePolicies()

GameIO

@@ -283,7 +283,7 @@ public static void DeleteGame(string id, bool cloud, bool deleteBackup = true)

cs
		}
	}

	public static List<GameIndex> GetGameList(string path, bool sortByName = false) 
	public static List<GameIndex> GetGameList(string path, bool sortByName = false, bool includeEmptyFolder = false) 
	{
		List<GameIndex> list = new List<GameIndex>();
		DirectoryInfo directoryInfo = new DirectoryInfo(path);

@@ -303,9 +303,22 @@ public static List<GameIndex> GetGameList(string path, bool sortByName = false)

cs
				gameIndex.path = directoryInfo2.FullName;
				list.Add(gameIndex);
			}
			catch (Exception) 
			catch (Exception message) 
			{
				Debug.Log(message); 
				goto IL_0097; 
			}
			continue; 
		} 
		goto IL_0097; 
		IL_0097: 
		if (includeEmptyFolder && Directory.Exists(CorePath.PathBackup + directoryInfo2.Name)) 
		{ 
			GameIndex gameIndex2 = new GameIndex(); 
			gameIndex2.id = directoryInfo2.Name; 
			gameIndex2.path = directoryInfo2.FullName; 
			gameIndex2.date = (gameIndex2.real = new Date()); 
			list.Add(gameIndex2); 
		}
	}
	if (sortByName)

GameIndex

@@ -55,6 +55,18 @@ public class GameIndex : EClass

cs

	public string FormTitle => id + ": " + zoneName + "(" + factionName + ") " + RealDate;

	public bool IsCorrupted 
	{ 
		get 
		{ 
			if (zoneName == null) 
			{ 
				return pcName == null; 
			} 
			return false; 
		} 
	} 

	public GameIndex Create(Game game)
	{
		if (game != null)

LayerLoadGame

@@ -12,6 +12,8 @@ public class LayerLoadGame : ELayer

cs

	public GameObject goNoInfo;

	public GameObject goInfo2; 

	public GameObject goCloudWarn;

	public UINote note;

@@ -108,7 +110,7 @@ public void RefreshList()

cs
		windows[0].SetCaption("saveList".lang() + (cloud ? (" " + "isCloud".lang()) : ""));
	}
	pathRoot = (backup ? pathBackup : (cloud ? CorePath.RootSaveCloud : CorePath.RootSave));
	worlds = GameIO.GetGameList(pathRoot, backup); 
	worlds = GameIO.GetGameList(pathRoot, backup, !backup && !cloud); 
	goCloudWarn.SetActive(cloud && !backup);
	goInfo.SetActive(value: false);
	goNoInfo.SetActive(value: true);

@@ -151,8 +153,14 @@ public void RefreshInfo(GameIndex i)

cs
	note.AddTopic("date_real".lang(), i.RealDate);
	note.AddTopic("date_game".lang(), i.GameData);
	note.AddTopic("ID", i.id);
	bool flag = ELayer.core.version.IsSaveCompatible(i.version); 
	if (!flag) 
	bool flag = ELayer.core.version.IsSaveCompatible(i.version) && !i.IsCorrupted; 
	goInfo2.SetActive(flag); 
	if (i.IsCorrupted) 
	{ 
		note.Space(); 
		note.AddText("corrupted_folder".lang(), FontColor.Bad); 
	} 
	else if (!flag) 
	{
		note.Space();
		note.AddText("incompatible".lang(), FontColor.Bad);

LayerUploader

@@ -19,6 +19,8 @@ public class LayerUploader : ELayer

cs

	public InputField inputPassword;

	public InputField inputWelcome; 

	public IniData ini;

	public UIText textInvalidId;

@@ -31,6 +33,8 @@ public class LayerUploader : ELayer

cs

	public UIButton buttonSave;

	public UIButton toggleClearLocalCharas; 

	public int limitSec;

	public HashSet<string> invalidIds = new HashSet<string>();

@@ -49,6 +53,20 @@ public override void OnInit()

cs
		string text = ini.GetKey("pass") ?? "password";
		inputId.text = ELayer._map.custom?.id ?? "new_zone";
		inputPassword.text = text;
		if (ELayer._map.exportSetting == null) 
		{ 
			ELayer._map.exportSetting = new MapExportSetting(); 
		} 
		MapExportSetting ex = ELayer._map.exportSetting; 
		inputWelcome.text = ex.textWelcome.IsEmpty(""); 
		inputWelcome.onValueChanged.AddListener(delegate(string s) 
		{ 
			ex.textWelcome = s; 
		}); 
		toggleClearLocalCharas.SetToggle(ex.clearLocalCharas, delegate(bool on) 
		{ 
			ex.clearLocalCharas = on; 
		}); 
	}

	private void Update()

Map

@@ -69,6 +69,9 @@ public class Map : MapBounds, IPathfindGrid

cs
	[JsonProperty]
	public Dictionary<int, PlantData> plants = new Dictionary<int, PlantData>();

	[JsonProperty] 
	public MapExportSetting exportSetting; 

	public BitArray32 bits;

	public Playlist plDay;

@@ -484,11 +487,12 @@ public void Save(string path, ZoneExportData export = null, PartialMap partial =

cs
		export.serializedCards.cards.Clear();
		if (partial == null)
		{
			MapExportSetting mapExportSetting = exportSetting ?? new MapExportSetting(); 
			foreach (Chara chara2 in charas)
			{
				if (export.usermap)
				{
					if (!chara2.trait.IsUnique && !chara2.IsPC) 
					if ((!mapExportSetting.clearLocalCharas || chara2.IsPCFactionOrMinion) && !chara2.trait.IsUnique && !chara2.IsPC) 
					{
						export.serializedCards.Add(chara2);
					}

+MapExportSetting

File Created
cs
using Newtonsoft.Json;

public class MapExportSetting
{
	[JsonProperty]
	public bool clearLocalCharas;

	[JsonProperty]
	public string textWelcome;
}

MsgLog

@@ -1,4 +1,6 @@

cs
using System.Collections.Generic;
using System.Linq; 
using System.Runtime.Serialization; 
using Newtonsoft.Json;

public class MsgLog : EClass

@@ -36,6 +38,18 @@ public int maxLog

cs
		}
	}

	[OnSerializing] 
	private void OnSerializing(StreamingContext context) 
	{ 
		foreach (int item in dict.Keys.ToList()) 
		{ 
			if (item >= currentLogIndex || item <= currentLogIndex - maxLog) 
			{ 
				dict.Remove(item); 
			} 
		} 
	} 

	public void Add(Data data)
	{
		dict.Add(currentLogIndex, data);

Player

@@ -1969,13 +1969,17 @@ public void EquipTool(Thing a, bool setHotItem = true)

cs
public void RefreshCurrentHotItem()
{
	WidgetCurrentTool instance = WidgetCurrentTool.Instance;
	if (!instance) 
	{ 
		return; 
	} 
	if (currentHotItem != null)
	{
		if ((bool)instance)
		{
			instance.buttonHotItem.Refresh();
		}
		if (currentHotItem is HotItemHeld && currentHotItem.Thing != EClass.pc.held) 
		if (currentHotItem is HotItemHeld && (currentHotItem.Thing != EClass.pc.held || currentHotItem.Thing.GetRootCard() != EClass.pc)) 
		{
			currentHotItem = null;
		}

@@ -1990,7 +1994,7 @@ public void RefreshCurrentHotItem()

cs
	}
	if (currentHotItem == null)
	{
		if ((bool)instance && instance.selected != -1 && instance.selectedButton.card != null && instance.selectedButton.card.GetRootCard() == EClass.pc) 
		if ((bool)instance && instance.selected != -1 && instance.selectedButton.card != null && instance.selectedButton.card.GetRootCard() == EClass.pc && !instance.selectedButton.card.GetRootCard().isDestroyed) 
		{
			currentHotItem = instance.selectedButton.card.trait.GetHotItem();
		}

@@ -1999,6 +2003,7 @@ public void RefreshCurrentHotItem()

cs
			currentHotItem = hotItemNoItem;
		}
	}
	Debug.Log(currentHotItem); 
	if (currentHotItem != lastHotItem)
	{
		if (lastHotItem != null)

TaskDump

@@ -272,7 +272,7 @@ public List<Thing> ListThingsToPut(Thing c)

cs
	return list;
	bool ExcludeDump(Thing t)
	{
		if (t.isEquipped || t.c_isImportant || !t.trait.CanBeDropped || t.IsHotItem || t.trait is TraitToolBelt || t.trait is TraitAbility) 
		if (t.isEquipped || t.c_isImportant || t.trait.CanOnlyCarry || !t.trait.CanBeDropped || t.IsHotItem || t.trait is TraitToolBelt || t.trait is TraitAbility) 
		{
			return true;
		}

Thing

@@ -208,7 +208,7 @@ public override void OnCreate(int genLv)

cs
		{
			num = EClass.rnd(2) + 1;
		}
		if (num > 0 && !HasTag(CTAG.godArtifact)) 
		if (num > 0 && !HasTag(CTAG.godArtifact) && !HasTag(CTAG.noRandomEnc)) 
		{
			for (int i = 0; i < num; i++)
			{

+TraitCage

File Created
cs
using UnityEngine;

public class TraitCage : TraitShackle
{
	public override Vector3 GetRestrainPos => default(Vector3);
}

+TraitCageBreeding

File Created
cs
using UnityEngine;

public class TraitCageBreeding : TraitCage
{
	public override Vector3 GetRestrainPos => default(Vector3);

	public override bool AllowTraining => false;
}

TraitShackle

@@ -10,6 +10,8 @@ public class TraitShackle : Trait

cs

	public override string LangUse => "ActRestrain";

	public virtual bool AllowTraining => true; 

	public override bool CanStackTo(Thing to)
	{
		return false;

Zone

@@ -1508,44 +1508,49 @@ public void AddGlobalCharasOnActivate()

cs
		{
			Chara chara = c.parent as Chara;
			c.currentZone = chara.currentZone;
			continue; 
		}
		c.isRestrained = false; 
		if (c.isDead) 
		{ 
			continue; 
		} 
		if (c.global.transition != null) 
		else
		{
			Point pos = (c.IsPC ? spawnPosPC : (c.IsPCParty ? spawnPosPC.GetNearestPoint(allowBlock: false, allowChara: false, allowInstalled: true, ignoreCenter: true) : GetSpawnPos(c))); 
			if (c.IsPCParty && !c.IsPC) 
			if (c.isDead) 
			{
				if (c.host == EClass.pc) 
				{ 
					pos.Set(spawnPosPC); 
				} 
				else if (pos.Equals(spawnPosPC) || !PathManager.Instance.IsPathClear(spawnPosPC, pos, c, 5)) 
				continue; 
			} 
			if (c.isRestrained && c.currentZone == EClass.pc.currentZone && c.pos.FindThing<TraitShackle>() == null) 
			{ 
				c.isRestrained = false; 
			} 
			if (c.global.transition != null) 
			{ 
				Point pos = (c.IsPC ? spawnPosPC : (c.IsPCParty ? spawnPosPC.GetNearestPoint(allowBlock: false, allowChara: false, allowInstalled: true, ignoreCenter: true) : GetSpawnPos(c))); 
				if (c.IsPCParty && !c.IsPC) 
				{
					c.pos.Set(spawnPosPC); 
					if (!spawnPosPC.ForeachNearestPoint(delegate(Point p) 
					if (c.host == EClass.pc) 
					{ 
						pos.Set(spawnPosPC); 
					} 
					else if (pos.Equals(spawnPosPC) || !PathManager.Instance.IsPathClear(spawnPosPC, pos, c, 5)) 
					{
						if (PathManager.Instance.IsPathClear(spawnPosPC, p, c, 10) && !p.Equals(spawnPosPC)) 
						c.pos.Set(spawnPosPC); 
						if (!spawnPosPC.ForeachNearestPoint(delegate(Point p) 
						{
							pos.Set(p); 
							return true; 
							if (PathManager.Instance.IsPathClear(spawnPosPC, p, c, 10) && !p.Equals(spawnPosPC)) 
							{ 
								pos.Set(p); 
								return true; 
							} 
							return false; 
						}, allowBlock: false, EClass.pc.party.members.Count >= 12, allowInstalled: true, ignoreCenter: true, EClass._zone.IsRegion ? 2 : 6)) 
						{ 
							pos.Set(spawnPosPC); 
						}
						return false; 
					}, allowBlock: false, EClass.pc.party.members.Count >= 12, allowInstalled: true, ignoreCenter: true, EClass._zone.IsRegion ? 2 : 6)) 
					{ 
						pos.Set(spawnPosPC); 
					}
				}
				c.pos.Set(pos); 
				c.global.transition = null; 
			}
			c.pos.Set(pos); 
			c.global.transition = null; 
			map.charas.Add(c); 
			map.AddCardOnActivate(c); 
		}
		map.charas.Add(c); 
		map.AddCardOnActivate(c); 
	}
	foreach (Chara item in EClass.player.listSummon)
	{

@@ -2869,7 +2874,7 @@ public List<Element> ListLandFeats()

cs
	List<Element> list2 = new List<Element>();
	foreach (int landFeat in landFeats)
	{
		list2.Add(Element.Create(landFeat)); 
		list2.Add(Element.Create(landFeat, 1)); 
	}
	return list2;
}

Zone_User

@@ -19,4 +19,16 @@ public class Zone_User : Zone

cs
	public override int BaseElectricity => 1000;

	public override bool RevealRoom => true;

	public override void OnActivate() 
	{ 
		base.OnActivate(); 
		if (EClass._map.exportSetting != null && !EClass._map.exportSetting.textWelcome.IsEmpty()) 
		{ 
			WidgetMainText.Instance.NewLine(); 
			Msg.SetColor("save"); 
			Msg.SayRaw("<i>" + EClass._map.exportSetting.textWelcome + "</i>"); 
			WidgetMainText.Instance.NewLine(); 
		} 
	} 
}