EA 23.315 Nightly โ
June 10, 2026
43 files modified. 26 new files created.
Important Changes โ
Possible breaking changes. Click the filename to view the chunk.
Card (1) โ
public string StripTalkSpeiclaCharacters(string text)
public string StripTalkSpecialCharacters(string text) Chara (1) โ
public bool CanDuplicate()
public bool CanDuplicate(DuplicateCondition con = DuplicateCondition.Default) CustomMerchantStock (1) โ
public static CustomMerchantStock CreateFromId(string stockId, ModPackage owner)
public static CustomMerchantStock CreateFromId(string stockId, ModPackage owner = null) DramaManager (1) โ
public static Dictionary<string, ExcelData> dictCache = new Dictionary<string, ExcelData>();
public static Dictionary<string, ExcelData> dictCache = new Dictionary<string, ExcelData>(PathComparer.Default); FEAT (1) โ
public List<string> Apply(int a, ElementContainer owner, bool hint = false)
public virtual List<string> Apply(int a, ElementContainer owner, bool hint = false) ModUtil (4) โ
public static void LogModError(string message, SourceData.BaseRow row = null)
public static void LogModError(string message, SourceData.BaseRow row) public static void LogModError(string message, FileInfo file = null)
public static void LogModError(string message, FileInfo file) public static void LogModError(string message, DirectoryInfo dir = null)
public static void LogModError(string message, DirectoryInfo dir) public static Sprite AppendSpriteSheet(string id, int resizeWidth = 0, int resizeHeight = 0, string pattern = "@")
public static void RegisterElinEventAttributes() ReligionMachine (1) โ
public override void OnReforge(Thing t)
public override bool IsIgnoreReforge(Thing t) ReligionWind (1) โ
public override void OnReforge(Thing t)
public override bool IsIgnoreReforge(Thing t) AI_Idle โ
public override IEnumerable<Status> Run()
}
case "spider_queen":
{
if (EClass.rnd(20) != 0 || !owner.CanDuplicate() || EClass._zone.IsUserZone)
if (EClass.rnd(20) != 0 || !owner.CanDuplicate(DuplicateCondition.SpiderEgg) || EClass._zone.IsUserZone)
{
break;
}public override IEnumerable<Status> Run()
}
case "mech_scarab":
{
if (EClass.rnd(20) != 0 || !owner.CanDuplicate() || EClass._zone.IsUserZone)
if (EClass.rnd(20) != 0 || !owner.CanDuplicate(DuplicateCondition.Scarab) || EClass._zone.IsUserZone)
{
break;
}ActEffect โ
void AddCon<T>(int rate, int power) where T : Condition
switch (id)
{
case EffectId.Duplicate:
{
Point randomPoint = CC.pos.GetRandomPoint(2, requireLos: false, allowChara: false, allowBlocked: false, 200);
if (randomPoint == null || randomPoint.Equals(CC.pos) || !randomPoint.IsValid || !CC.CanDuplicate())
{
CC.Say("split_fail", CC);
return;
}
Chara t2 = CC.Duplicate();
EClass._zone.AddCard(t2, randomPoint);
CC.Say("split", CC);
CC.TryDuplicate();
break;
}
case EffectId.Escape:
if (CC.IsPCFaction || (EClass._zone.Boss == CC && EClass.rnd(30) != 0))
{void AddCon<T>(int rate, int power) where T : Condition
case EffectId.ThrowPotion:
if (!CC.pos.Equals(TC.pos))
{
Thing t3 = ThingGen.Create(new string[6] { "330", "331", "334", "335", "336", "1142" }.RandomItem());
ActThrow.Throw(CC, TC.pos, t3, ThrowMethod.Punish, 0.7f);
Thing t2 = ThingGen.Create(new string[6] { "330", "331", "334", "335", "336", "1142" }.RandomItem());
ActThrow.Throw(CC, TC.pos, t2, ThrowMethod.Punish, 0.7f);
}
break;
case EffectId.StripBlessing:public static bool Wish(string s, string name, int power, BlessedState state)
Msg.thirdPerson1.Set(EClass.pc);
string netMsg = GameLang.Parse("wish".langGame(), thirdPerson: true, name, s);
List<WishItem> list = new List<WishItem>();
int wishLv = 10 + power / 4;
int wishValue = 5000 + power * 50;
long wishLv = 10 + power / 4;
int wishValue = MathEx.ClampToInt(5000 + (long)power * 50L);
if (state >= BlessedState.Blessed)
{
wishLv = wishLv * 150 / 100;public static bool Wish(string s, string name, int power, BlessedState state)
{
CardBlueprint.SetRarity(Rarity.Legendary);
}
Thing thing = ThingGen.Create(r.id, -1, wishLv);
Thing thing = ThingGen.Create(r.id, -1, MathEx.ClampToInt(wishLv));
int num = 1;
int price = thing.GetPrice(CurrencyType.Money, sell: false, PriceType.Tourism);
bool flag2 = thing.trait is TraitDeed || thing.rarity >= Rarity.Artifact || thing.source._origin == "artifact_summon";AttackProcess โ
public void PlayRangedAnime(int numFire, float delay = 0f)
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")];
CustomGunEffectData customData = data as CustomGunEffectData;
bool isPCC = CC.IsPCC && CC.renderer.hasActor;
Vector2 firePos = (isPCC ? new Vector2(data.firePos.x * (float)((CC.renderer.actor.currentDir != 0 && CC.renderer.actor.currentDir != 1) ? 1 : (-1)), data.firePos.y) : Vector2.zero);
Chara _CC = CC;public void PlayRangedAnime(int numFire, float delay = 0f)
Color effColor = Color.white;
if (isCane)
{
IEnumerable<Element> enumerable = toolRange.owner.elements.dict.Values.Where((Element e) => e.source.categorySub == "eleAttack");
if (enumerable.Count() > 0)
Element element = toolRange.owner.elements.dict.Values.Where((Element e) => e.source.categorySub == "eleAttack").RandomItem();
if (element != null)
{
Element element = enumerable.RandomItem();
effColor = EClass.Colors.elementColors[element.source.alias];
effColor = EClass.Colors.elementColors.TryGetValue(element.source.alias, "eleFire");
}
if (!string.IsNullOrEmpty(customData?.caneColor))
{
Color color = customData.caneColor.ToColor();
effColor = (customData.caneColorBlend ? Color.Lerp(effColor, color, 0.5f) : color);
}
}
bool isLaser = toolRange is TraitToolRangeGunEnergy || (customData?.forceLaser ?? false);
bool isRail = isLaser && (weapon.id == "gun_rail" || (customData?.forceRail ?? false));
for (int i = 0; i < numFire; i++)
{
TweenUtil.Delay((float)i * data.delay + delay, delegate
{
if (EClass.core.IsGameStarted && _CC.IsAliveInCurrentZone && _zone == _CC.currentZone)
{
Vector3 fromV = (_CC.isSynced ? _CC.renderer.position : _CC.pos.Position());
switch (_weapon.id)
{
case "gun_rail":public void PlayRangedAnime(int numFire, float delay = 0f)
_CC.PlayEffect("laser").GetComponent<SpriteBasedLaser>().Play(_TP.PositionCenter());
break;
case "gun_laser_assault":
Effect.Get("ranged_laser")._Play(_CC.pos, _CC.isSynced ? _CC.renderer.position : _CC.pos.Position(), 0f, _TP, data.sprite);
Effect.Get("ranged_laser")._Play(_CC.pos, fromV, 0f, _TP, data.sprite);
break;
default:
{
Effect effect = Effect.Get("ranged_arrow")._Play(_CC.pos, _CC.isSynced ? _CC.renderer.position : _CC.pos.Position(), 0f, _TP, data.sprite);
if (isCane)
if (isLaser)
{
effect.sr.color = effColor;
string id = (isRail ? "laser_rail" : "laser");
_CC.PlayEffect(id).GetComponent<SpriteBasedLaser>().Play(_TP.PositionCenter());
}
else
{
Effect effect = Effect.Get("ranged_arrow")._Play(_CC.pos, fromV, 0f, _TP, data.sprite);
if (isCane)
{
effect.sr.color = effColor;
}
}
break;
}
}
if (data.eject)
{
if (!ignoreSound)
{
_CC.PlaySound("bullet_drop");
_CC.PlaySound(customData?.idSoundEject.IsEmpty("bullet_drop"));
}
_CC.PlayEffect("bullet").Emit(1);
}CMOD โ
public const string PriceCalcOverride = "price_calc_override";
public const string DisableBarterChoice = "disable_barter_choice";
public const string IsCustomContent = "custom_content";
public const string IsCustomCwlContent = "cwl_tags_applied";Card โ
public void SetBool(string id, bool enable)
public int GetInt(string id, int? defaultInt = null)
{
return GetInt(id.GetHashCode(), defaultInt);
int @int = GetInt(id.GetHashCode(), defaultInt);
if (!IsPC)
{
return @int;
}
return EClass.player.dialogFlags.GetValueOrDefault(id, @int);
}
public void AddInt(string id, int value)
{
AddInt(id.GetHashCode(), value);
if (IsPC)
{
EClass.player.dialogFlags[id] = GetInt(id.GetHashCode());
}
}
public void SetInt(string id, int value = 0)
{
SetInt(id.GetHashCode(), value);
if (IsPC)
{
EClass.player.dialogFlags[id] = value;
}
}
public string GetStr(string id, string defaultStr = null)public void TalkRaw(string text, string ref1 = null, string ref2 = null, bool fo
text = text.Replace("#2", ref2);
}
HostRenderer.Say(ApplyNewLine(text));
text = StripTalkSpeiclaCharacters(text);
text = StripTalkSpecialCharacters(text);
bool flag = text.StartsWith("*");
Msg.SetColor(text.StartsWith("(") ? Msg.colors.Thinking : (flag ? Msg.colors.Ono : Msg.colors.Talk));
if (!flag)public void TalkRaw(string text, string ref1 = null, string ref2 = null, bool fo
Msg.Say(text.Replace("&", ""));
}
public string StripTalkSpeiclaCharacters(string text)
public string StripTalkSpecialCharacters(string text)
{
switch (text[0])
{Chara โ
public void Refresh(bool calledRecursive = false)
}
}
public bool CanDuplicate()
public bool CanDuplicate(DuplicateCondition con = DuplicateCondition.Default)
{
if (EClass._zone.IsRegion || HasCondition<ConPoison>() || HasCondition<ConConfuse>() || HasCondition<ConDim>() || HasCondition<ConParalyze>() || HasCondition<ConSleep>() || HasCondition<ConBurning>() || HasCondition<ConFreeze>() || HasCondition<ConMiasma>() || corruption >= 100)
if (EClass._zone.IsRegion)
{
return false;
} {
return false;
}
string text = id;
if (!(text == "mech_scarab"))
if (corruption >= 100)
{
if (text == "spider_queen" && (pos.cell.light > 0 || pos.IsSunLit))
return false;
}
if (con != DuplicateCondition.Water && (HasCondition<ConPoison>() || HasCondition<ConConfuse>() || HasCondition<ConDim>() || HasCondition<ConParalyze>() || HasCondition<ConSleep>() || HasCondition<ConBurning>() || HasCondition<ConFreeze>() || HasCondition<ConMiasma>()))
{
return false;
}
switch (con)
{
case DuplicateCondition.Scarab:
if (isSynced || pos.cell.light > 0 || (!EClass._map.IsIndoor && !pos.cell.HasRoof && !EClass.world.date.IsNight))
{
return false;
}
break;
case DuplicateCondition.SpiderEgg:
if (pos.cell.light > 0 || pos.IsSunLit)
{
return false;
}
break;
}
else if (isSynced || pos.cell.light > 0 || (!EClass._map.IsIndoor && !pos.cell.HasRoof && !EClass.world.date.IsNight))
return true;
}
public Chara TryDuplicate(DuplicateCondition con = DuplicateCondition.Default, Point dest = null)
{
if (dest == null)
{
return false;
dest = pos;
}
return true;
dest = dest.GetRandomPoint(2, requireLos: false, allowChara: false, allowBlocked: false, 200);
if (dest == null || dest.Equals(pos) || !dest.IsValid || !CanDuplicate(con))
{
Say("split_fail", this);
return null;
}
Chara chara = Duplicate();
EClass._zone.AddCard(chara, dest);
Say("split", this);
return chara;
}
public Chara Duplicate()public void Stumble(int mtp = 100)
{
bool flag = EClass._map.FindThing((Thing t) => t.IsInstalled && t.pos.Equals(EClass.pc.pos) && t.trait is TraitStairsUp) != null;
Say(flag ? "dmgBurdenStairs" : "dmgBurdenFallDown", this);
int num = MaxHP;
long num = MaxHP;
if (Evalue(1421) > 0)
{
num = mana.max;
}
int num2 = (num * (base.ChildrenWeight * 100 / WeightLimit) / (flag ? 100 : 200) + 1) * mtp / 100;
long num2 = (num * (base.ChildrenWeight * 100 / WeightLimit) / (flag ? 100 : 200) + 1) * mtp / 100;
if (base.hp <= 0)
{
num2 *= 2;public void ApplyRace(bool remove = false)
}
body.RefreshBodyParts();
elements.ApplyElementMap(base.uid, SourceValueType.Chara, race.elementMap, base.DefaultLV, remove, applyFeat: true);
if (!remove)
if (remove)
{
if (race.id == "bike" && id != "bike_cub")
{
SetFeat(1423, (id == "chara" || id == "player") ? 10 : (1 + EClass.rnd(10)));
}
if (race.id == "horse" && EClass.rnd(5) == 0)
if (HasElement(1423))
{
SetFeat(1423, 1 + EClass.rnd(5));
SetFeat(1423, 0);
}
return;
}
bool flag = id == "chara" || id == "player";
if (race.id == "bike" && id != "bike_cub")
{
SetFeat(1423, flag ? 10 : (1 + EClass.rnd(10)));
}
if (id == "moa")
{
SetFeat(1423, flag ? 7 : (1 + EClass.rnd(7)));
}
if (race.id == "horse" && EClass.rnd(5) == 0)
{
SetFeat(1423, flag ? 5 : (1 + EClass.rnd(5)));
}
}public string TalkTopic(string topic = "calm")
{
return null;
}
string text = "_bracketTalk".lang();
HashSet<string> obj = new HashSet<string>
{
"_bracketTalk".lang(),
"\"",
"โ",
"ใ"
};
bool flag = topicText.StartsWith("*");
bool flag2 = topicText.StartsWith("(");
bool flag3 = topicText.StartsWith(text) || (topicText.Length > 0 && topicText[0] == text[0]) || topicText[0] == 'โ';
bool flag3 = obj.Any(topicText.StartsWith);
topicText = ApplyTone(topicText);
topicText = topicText.Replace("~", "*");
topicText = topicText.Replace('~', '*');
Msg.SetColor(flag2 ? Msg.colors.Thinking : (flag3 ? Msg.colors.Talk : Msg.colors.Ono));
Msg.Say(StripTalkSpeiclaCharacters(topicText.Replace("&", "")));
Msg.Say(StripTalkSpecialCharacters(topicText.Replace("&", "")));
if (topic == "dead")
{
EClass.ui.popGame.PopText(ApplyNewLine(topicText.StripBrackets()), null, "PopTextDead", default(Color), pos.Position() + EClass.setting.render.tc.textPosDead);public void RerollHobby(bool extraSlotChance = true)
string[] hobbies = source.hobbies;
foreach (string text in hobbies)
{
if (EClass.sources.hobbies.alias.ContainsKey(text))
if (EClass.sources.hobbies.alias.TryGetValue(text.Trim(), out var value))
{
AddHobby(EClass.sources.hobbies.alias[text].id);
AddHobby(value.id);
continue;
}
ModUtil.LogModError("source chara row '" + source.id + "' has invalid hobby '" + text + "'", source);public void RerollHobby(bool extraSlotChance = true)
string[] hobbies = source.works;
foreach (string text2 in hobbies)
{
if (EClass.sources.hobbies.alias.ContainsKey(text2))
if (EClass.sources.hobbies.alias.TryGetValue(text2.Trim(), out var value2))
{
AddWork(EClass.sources.hobbies.alias[text2].id);
AddWork(value2.id);
continue;
}
ModUtil.LogModError("source chara row '" + source.id + "' has invalid work '" + text2 + "'", source);CharaAbility โ
}
else if (!EClass.sources.elements.alias.ContainsKey(text2) || !ACT.dict.ContainsKey(text2))
{
if (EClass.sources.elements.fuzzyAlias.TryGetValue(text2, out var value) && ACT.dict.ContainsKey(value))
if (EClass.sources.elements.fuzzyAlias.TryGetValue(text2.Trim(), out var value) && ACT.dict.ContainsKey(value))
{
list[num] = text.Replace(text2, value);
}ConWet โ
public override void OnStart()
{
if (!EClass._zone.IsRegion && owner.HasElement(1254))
if (!EClass._zone.IsRegion && owner.HasElement(1254) && owner.pos.ListCharasInNeighbor((Chara c) => c.HasElement(1254)).Count < 5)
{
Point randomPoint = owner.pos.GetRandomPoint(2, requireLos: false, allowChara: false, allowBlocked: false, 200);
if (randomPoint != null && !randomPoint.Equals(BaseStats.CC.pos) && randomPoint.IsValid)
{
Chara t = owner.Duplicate();
EClass._zone.AddCard(t, randomPoint);
owner.Say("split", owner);
}
owner.TryDuplicate(DuplicateCondition.Water);
}
}
}ContentConfigOther โ
public class ContentConfigOther : ContentConfig
{
public UIButton toggleSyncMod;
public UIButton toggleNoCensor;
public UIButton toggleRunBackground;public class ContentConfigOther : ContentConfig
public UIButton buttonBackerCode;
public UIButton buttonWallPaper;
public UIButton toggleSyncMod;
public UIButton toggleDisableMods;
public UIButton buttonWallPaper;
public UIButton toggleExceptionPopup;
public UIDropdown ddSnap;public override void OnInstantiate()
{
base.config.other.disableMods = on;
});
toggleExceptionPopup.SetToggle(base.config.other.exceptionPopup, delegate(bool on)
{
base.config.other.exceptionPopup = on;
});
toggleNoCensor.SetToggle(base.config.other.noCensor, delegate(bool on)
{
base.config.other.noCensor = on;+ContextMenuProxy โ
File Created
using System;
using System.Collections.Generic;
public class ContextMenuProxy
{
public readonly List<ContextMenuProxy> children = new List<ContextMenuProxy>();
public Action onClick;
public bool isMenu;
public string DisplayName { get; }
public string MenuEntry { get; }
public ContextMenuProxy(string displayName, string menuEntry)
{
DisplayName = displayName;
MenuEntry = menuEntry;
}
}Core โ
public static int GetElement(string id)
{
if (sourceElement.fuzzyAlias.TryGetValue(id, out var value2))
{
Debug.Log("#element lookup: " + id + " -> " + value2);
Debug.Log("#element lookup: '" + id + "' -> '" + value2 + "'");
value = sourceElement.alias[value2];
}
else
{
Debug.LogWarning("#element not found: " + id);
Debug.LogWarning("#element not found: '" + id + "'");
value = sourceElement.rows[0];
}
}CoreConfig โ
public bool showTestOptions;
public string idMainWidgetTheme;
public string idSubWidgetTheme;
public bool syncMods;
public bool disableMods;
public string idMainWidgetTheme;
public string idSubWidgetTheme;
public bool exceptionPopup;
}
[Serializable]CoreDebug โ
public static string Reset_LoytelDebt()
return "Quest Reset!";
}
[ConsoleCommand("")]
public static string Fix_Awning()
{
foreach (Thing thing in EClass._map.things)
{
if (thing.id == "ash3")
{
thing.id = "awning ";
thing.source = EClass.sources.things.map[thing.id];
thing._CreateRenderer();
}
}
return "Fixed!";
}
[ConsoleCommand("")]
public static string Fix_RemoveDuplicateUnique()
{CustomBiographyContent โ
public class CustomBiographyContent : CustomFileContent
{
private const int FallbackWordKey = -100;
private static int _lastWordKey;
private static int _lastWordKey = -101;
public string background;public class CustomBiographyContent : CustomFileContent
public string favFood;
private int[] _tempLangKey = new int[4];
private bool _initialized;
public static CustomBiographyContent CreateFromId(string biographyId, ModPackage owner = null)
{
var (fileInfo, eMod) = PackageIterator.GetFilesEx("Data/bio_" + biographyId + ".json").LastOrDefault();public override void OnSetLang(string lang)
public void RefreshCharaBio(Chara chara)
{
Load();
if (_initialized)
{
return;
}
Biography bio = chara.bio;
bio.birthDay = birthDay;
bio.birthMonth = birthMonth;
bio.birthYear = birthYear;
if (birthDay != 0)
{
bio.birthDay = birthDay;
}
if (birthMonth != 0)
{
bio.birthMonth = birthMonth;
}
if (birthYear != 0)
{
bio.birthYear = birthYear;
}
Dictionary<int, LangWord.Row> langWord = EClass.sources.langWord.map;
if (!langWord.ContainsKey(-100))
{
_lastWordKey = -100;
SetTempWord("");
Dictionary<int, LangWord.Row> dictionary = langWord;
LangWord.Row obj = new LangWord.Row
{
id = -100
};
LangWord.Row row = obj;
dictionary[-100] = obj;
row.name = (row.name_JP = (row.name_L = ""));
}
if (!birthPlace.IsEmpty())
{
bio.idHome = SetTempWord(birthPlace);
bio.idHome = SetTempWord(birthPlace, 0);
}
if (!birthLocation.IsEmpty())
{
bio.idLoc = SetTempWord(birthLocation);
bio.idLoc = SetTempWord(birthLocation, 1);
}
if (!dad.IsEmpty())
{
bio.idAdvDad = -100;
bio.idDad = SetTempWord(dad);
bio.idDad = SetTempWord(dad, 2);
}
if (!mom.IsEmpty())
{
bio.idAdvMom = -100;
bio.idMom = SetTempWord(mom);
bio.idMom = SetTempWord(mom, 3);
}
if (!likeThing.IsEmpty() && EClass.sources.things.map.ContainsKey(likeThing))
if (!likeThing.IsEmpty() && EClass.sources.cards.map.ContainsKey(likeThing))
{
bio.idLike = likeThing;
}
if (!likeHobby.IsEmpty() && Core.GetElement(likeHobby) != EClass.sources.elements.rows[0].id)
if (!likeHobby.IsEmpty())
{
bio.idHobby = -100;
int element = Core.GetElement(likeHobby);
if (element != EClass.sources.elements.rows[0].id)
{
bio.idHobby = element;
}
}
int SetTempWord(string text)
_initialized = true;
int SetTempWord(string text, int tempIndex)
{
while (langWord.ContainsKey(_lastWordKey))
int num = _tempLangKey[tempIndex];
if (num == 0 || !langWord.ContainsKey(num))
{
_lastWordKey--;
while (langWord.ContainsKey(_lastWordKey))
{
_lastWordKey--;
}
num = _lastWordKey;
}
Dictionary<int, LangWord.Row> dictionary = langWord;
int lastWordKey = _lastWordKey;
LangWord.Row obj = new LangWord.Row
LangWord.Row row3 = (langWord[num] = new LangWord.Row
{
id = _lastWordKey
};
LangWord.Row row = obj;
dictionary[lastWordKey] = obj;
row.name = (row.name_JP = (row.name_L = text));
return _lastWordKey;
id = num
});
row3.name = (row3.name_JP = (row3.name_L = text));
return _tempLangKey[tempIndex] = num;
}
}protected override void LoadContent()
likeHobby = customBiographyContent.likeHobby;
favCategory = customBiographyContent.favCategory;
favFood = customBiographyContent.favFood;
_initialized = false;
}
}CustomCharaContent โ
public static SpawnType GetSpawnTypeFromTrait(string trait)
public void OnCharaCreated(Chara chara)
{
if (chara.GetBool("custom_content") || chara.GetBool("cwl_tags_applied") || chara.id != base.SourceId)
if (chara.GetBool("custom_content") || chara.id != base.SourceId)
{
return;
}public void OnCharaCreated(Chara chara)
int value3 = value2;
chara.SetInt(id3, value3);
}
if (chara.GetBool("cwl_tags_applied"))
{
return;
}
if (things.Count > 0 || equipments.Count > 0)
{
chara.RemoveThings();public override void OnGameLoad(GameIOContext context)
{
if (num2 != 1)
{
goto IL_01d5;
goto IL_01cf;
}
if (IsAdventurer)
{
goto IL_017e;
goto IL_0178;
}
}
else if (IsAdventurer)
{
ModUtil.LogModError("adventurer '" + base.SourceId + "' has spawned more than once", base.Owner);
Debug.LogWarning("#mod-content adventurer '" + base.SourceId + "' has spawned more than once");
return;
}
if (num == 0)
{
goto IL_017e;
goto IL_0178;
}
goto IL_01d5;
IL_017e:
Debug.Log("#mod-content skipping existing character '" + base.SourceId + "', " + $"{count} at {string.Join('/', list2.Select((Chara c) => c.currentZone.ZoneFullName))}");
goto IL_01cf;
IL_0178:
Debug.Log("#mod-content skipping existing character '" + base.SourceId + "', " + $"{count} at {string.Join(',', list2.Select((Chara c) => c.currentZone?.ZoneFullName))}");
return;
IL_01d5:
IL_01cf:
for (int i = 0; i < num; i++)
{
Zone z2 = list[i];+CustomDramaExpansion โ
File Created
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using UnityEngine;
public class CustomDramaExpansion : EClass
{
private static readonly Dictionary<string, DramaActionParser> _actionParsers = new Dictionary<string, DramaActionParser>(StringComparer.OrdinalIgnoreCase);
private static readonly Dictionary<string, DramaInvokeDetail> _invokes = new Dictionary<string, DramaInvokeDetail>(StringComparer.OrdinalIgnoreCase);
internal static readonly Regex _expressionRegex = new Regex("^\\s*(?<f>\\w+)\\s*(?:\\(\\s*(?<p>.*)\\s*\\))?\\s*$", RegexOptions.Compiled);
public static bool ParseAction(string action, DramaManager dm, Dictionary<string, string> line)
{
if (_actionParsers.TryGetValue(action, out var value))
{
return value(dm, line);
}
return false;
}
public static void AddDramaActionParser(string action, DramaActionParser parser)
{
_actionParsers[action] = SafeInvoke;
Debug.Log("#drama added new action parser '" + action + "' from '" + parser.Method.TryToString() + "'");
bool SafeInvoke(DramaManager dm, Dictionary<string, string> line)
{
try
{
return parser(dm, line);
}
catch (Exception ex)
{
ModUtil.LogModError("exception while parsing drama action '" + action + "'\n" + ex.Message, parser.Method.DeclaringType);
Debug.LogException(ex);
}
return false;
}
}
public static void AddDramaInvokeMethod(string name, MethodInfo method, string contract = null)
{
_invokes[name] = new DramaInvokeDetail(method, contract);
}
public static void AddDramaInvokeMethod(string name, DramaInvokeFunc func, string contract = null)
{
AddDramaInvokeMethod(name, func.Method, contract);
}
internal static (DramaInvokeDetail invoke, string[] parameters) BuildInvokeExpression(string expression)
{
(string, string[]) tuple = ParseInvokeExpression(expression);
if (!tuple.Item1.IsEmpty() && _invokes.TryGetValue(tuple.Item1, out var value))
{
return (invoke: value, parameters: tuple.Item2);
}
if (expression.Length <= 1)
{
return (invoke: new DramaInvokeDetail(null), parameters: Array.Empty<string>());
}
return expression[0] switch
{
'!' => BuildInvokeExpression("not(" + expression[1..] + ")"),
'&' => BuildInvokeExpression("and(" + expression[1..] + ")"),
'?' => BuildInvokeExpression("or(" + expression[1..] + ")"),
_ => (invoke: new DramaInvokeDetail(null), parameters: Array.Empty<string>()),
};
}
internal static (string funcName, string[] parameters) ParseInvokeExpression(string expression)
{
if (expression.IsEmpty())
{
return (funcName: "", parameters: Array.Empty<string>());
}
Match match = _expressionRegex.Match(expression);
return (funcName: match.Groups["f"].Value, parameters: SplitParams(match.Groups["p"].Value));
static string[] SplitParams(string args)
{
if (args.IsEmpty())
{
return Array.Empty<string>();
}
List<string> list = new List<string>();
int num = 0;
int num2 = 0;
char c = '\0';
for (int i = 0; i < args.Length; i++)
{
char c2 = args[i];
if (c != 0)
{
if (c2 == c)
{
c = '\0';
}
}
else
{
switch (c2)
{
case '"':
case '\'':
c = c2;
break;
case '(':
num++;
break;
case ')':
num--;
break;
case ',':
if (num == 0)
{
string s2 = args[num2..i].Trim();
s2 = Unquote(s2);
list.Add(s2);
num2 = i + 1;
}
break;
}
}
}
if (num2 < args.Length)
{
string text = args[num2..].Trim();
if (text.Length > 0)
{
list.Add(Unquote(text));
}
}
return list.ToArray();
}
static string Unquote(string s)
{
if (s.Length >= 2 && ((s[0] == '"' && s[^1] == '"') || (s[0] == '\'' && s[^1] == '\'')))
{
return s[1..^1];
}
return s;
}
}
[ElinDramaActionParser("i*")]
[ElinDramaActionParser("invoke*")]
internal static bool DefaultDramaInvokeExtActionParser(DramaManager dm, Dictionary<string, string> line)
{
string text = line["param"].Trim().RemoveNewline();
if (text.StartsWith("//"))
{
return true;
}
var (invoke, parameters) = BuildInvokeExpression(text);
if (invoke.Method == null)
{
ModUtil.LogModError("invalid drama invoke* expression '" + text + "'", new FileInfo(dm.path));
return true;
}
string jump = line["jump"];
if (!jump.IsEmpty())
{
dm.AddEvent(new DramaEventMethod(null)
{
jumpFunc = () => (!invoke.SafeInvoke(dm, line, parameters)) ? "" : jump
});
return true;
}
dm.AddEvent(new DramaEventMethod(delegate
{
invoke.SafeInvoke(dm, line, parameters);
}));
return true;
}
[ElinDramaActionParser("eval")]
internal static bool DefaultDramaEvalActionParser(DramaManager dm, Dictionary<string, string> line)
{
string expr = line["param"];
if (expr.IsEmpty())
{
return true;
}
EScriptSubmission submission = EScriptSubmission.Create(dm.setup.book);
EDramaScriptState state = new EDramaScriptState
{
dm = dm,
line = line
};
string jump = line["jump"];
bool flag = !jump.IsEmpty();
bool flag2 = !line["id"].IsEmpty();
if (!flag && flag2)
{
Dictionary<string, string> item = new Dictionary<string, string>(line)
{
["action"] = "",
["param"] = ""
};
dm.ParseLine(item);
dm.lastTalk.activeCondition = delegate
{
object obj2 = DeferredCompileAndRun();
return obj2 is bool && (bool)obj2;
};
return true;
}
if (flag)
{
dm.AddEvent(new DramaEventMethod(null)
{
jumpFunc = delegate
{
object obj = DeferredCompileAndRun();
if (obj is string result)
{
return result;
}
return (obj is bool && !(bool)obj) ? "" : jump;
}
});
return true;
}
dm.AddEvent(new DramaEventMethod(delegate
{
DeferredCompileAndRun();
}));
return true;
object DeferredCompileAndRun()
{
if (expr.StartsWith("<<<"))
{
string text = expr[3..].Trim();
string path = Path.Combine(Path.GetDirectoryName(dm.path), text);
if (!File.Exists(path))
{
throw new FileNotFoundException(text);
}
expr = File.ReadAllText(path);
}
return submission.Compile<EDramaScriptState>(expr)?.Invoke(state);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ElinDramaActionInvoke("nodiscard,passthrough")]
public static bool eval(DramaManager dm, Dictionary<string, string> line, params string[] parameters)
{
string text = string.Join(',', parameters);
if (text.IsEmpty())
{
return false;
}
EScriptSubmission eScriptSubmission = EScriptSubmission.Create(dm.setup.book);
EDramaScriptState arg = new EDramaScriptState
{
dm = dm,
line = line
};
if (text.StartsWith("<<<"))
{
string text2 = text[3..].Trim();
string path = Path.Combine(Path.GetDirectoryName(dm.path), text2);
if (!File.Exists(path))
{
throw new FileNotFoundException(text2);
}
text = File.ReadAllText(path);
}
object obj = eScriptSubmission.Compile<EDramaScriptState>(text)?.Invoke(arg);
if (obj is bool)
{
return (bool)obj;
}
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ElinDramaActionInvoke("nodiscard")]
public static bool and(DramaManager dm, Dictionary<string, string> line, params string[] parameters)
{
return parameters.All(delegate(string expr)
{
var (dramaInvokeDetail, parameters2) = BuildInvokeExpression(expr);
return dramaInvokeDetail.SafeInvoke(dm, line, parameters2);
});
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ElinDramaActionInvoke("nodiscard")]
public static bool or(DramaManager dm, Dictionary<string, string> line, params string[] parameters)
{
return parameters.Any(delegate(string expr)
{
var (dramaInvokeDetail, parameters2) = BuildInvokeExpression(expr);
return dramaInvokeDetail.SafeInvoke(dm, line, parameters2);
});
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ElinDramaActionInvoke("nodiscard")]
public static bool not(DramaManager dm, Dictionary<string, string> line, params string[] parameters)
{
return parameters.All(delegate(string expr)
{
var (dramaInvokeDetail, parameters2) = BuildInvokeExpression(expr);
return !dramaInvokeDetail.SafeInvoke(dm, line, parameters2);
});
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ElinDramaActionInvoke(null)]
public static bool console_cmd(DramaManager dm, Dictionary<string, string> line, params string[] parameters)
{
string.Join(' ', parameters).EvaluateAsCommand();
return true;
}
[ElinDramaActionInvoke(null)]
public static bool add_item(DramaManager dm, Dictionary<string, string> line, string itemId, string materialAlias = "wood", int lv = -1, int count = 1)
{
Chara chara = dm.GetChara(line["actor"]);
SourceMaterial.Row row = EClass.sources.materials.alias.TryGetValue(materialAlias, "wood");
Thing t = ThingGen.Create(itemId, row.id, lv).SetNum(count);
chara.Pick(t);
return true;
}
[ElinDramaActionInvoke(null)]
public static bool apply_condition(DramaManager dm, Dictionary<string, string> line, string conditionAlias, int power = 100)
{
dm.GetChara(line["actor"]).AddCondition(conditionAlias, power, force: true);
return true;
}
[ElinDramaActionInvoke(null)]
public static bool equip_item(DramaManager dm, Dictionary<string, string> line, string itemId)
{
dm.GetChara(line["actor"]).body.Equip(ThingGen.Create(itemId));
return true;
}
[ElinDramaActionInvoke(null)]
public static bool destroy_item(DramaManager dm, Dictionary<string, string> line, string itemId, int count = -1)
{
List<Thing> list = dm.GetChara(line["actor"]).things.List((Thing t) => t.id == itemId);
if (count < 0)
{
foreach (Thing item in list)
{
item.Destroy();
}
}
else
{
count = Math.Max(count, 0);
foreach (Thing item2 in list)
{
if (count == 0)
{
break;
}
if (item2.Num >= count)
{
item2.ModNum(-count);
continue;
}
count -= item2.Num;
item2.Destroy();
}
}
return true;
}
[ElinDramaActionInvoke(null)]
public static bool remove_condition(DramaManager dm, Dictionary<string, string> line, string conditionAlias)
{
foreach (Condition item in dm.GetChara(line["actor"]).conditions.ToList())
{
if (item.source.alias == conditionAlias)
{
item.Kill();
}
}
return true;
}
[ElinDramaActionInvoke(null)]
public static bool join_faith(DramaManager dm, Dictionary<string, string> line, string religionId = "")
{
Chara chara = dm.GetChara(line["actor"]);
if (religionId.IsEmpty())
{
chara.faith?.LeaveFaith(chara, EClass.game.religions.Eyth, Religion.ConvertType.Default);
}
else
{
EClass.game.religions.Find(religionId)?.JoinFaith(chara);
}
return true;
}
[ElinDramaActionInvoke(null)]
public static bool join_party(DramaManager dm, Dictionary<string, string> line)
{
Chara chara = dm.GetChara(line["actor"]);
EClass.Sound.Play("good");
chara.MakeAlly();
return true;
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_affinity(DramaManager dm, Dictionary<string, string> line, DramaValueExpression expr)
{
Chara chara = dm.GetChara(line["actor"]);
return expr.Compare(chara._affinity);
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_condition(DramaManager dm, Dictionary<string, string> line, string conditionAlias, DramaValueExpression expr = null)
{
if (expr == null)
{
expr = ">=1";
}
foreach (Condition condition in dm.GetChara(line["actor"]).conditions)
{
if (condition.source.alias == conditionAlias)
{
return expr.Compare(condition.value);
}
}
return false;
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_currency(DramaManager dm, Dictionary<string, string> line, string currencyId, DramaValueExpression expr)
{
Chara chara = dm.GetChara(line["actor"]);
return expr.Compare(chara.GetCurrency(currencyId));
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_element(DramaManager dm, Dictionary<string, string> line, string elementAlias, DramaValueExpression expr)
{
Chara chara = dm.GetChara(line["actor"]);
if (chara.HasElement(elementAlias))
{
return expr.Compare(chara.Evalue(elementAlias));
}
return false;
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_faith(DramaManager dm, Dictionary<string, string> line, string religionId, DramaValueExpression expr = null)
{
if (expr == null)
{
expr = ">=0";
}
Religion faith = dm.GetChara(line["actor"]).faith;
if (faith.id == religionId)
{
return expr.Compare(faith.giftRank);
}
return false;
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_fame(DramaManager dm, Dictionary<string, string> line, DramaValueExpression expr)
{
return expr.Compare(EClass.player.fame);
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_flag(DramaManager dm, Dictionary<string, string> line, string flagKey, DramaValueExpression expr = null)
{
if (expr == null)
{
expr = ">=1";
}
Chara chara = dm.GetChara(line["actor"]);
return expr.Compare(chara.GetInt(flagKey));
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_has_item(DramaManager dm, Dictionary<string, string> line, string itemId, DramaValueExpression expr = null)
{
if (expr == null)
{
expr = ">=1";
}
Chara chara = dm.GetChara(line["actor"]);
return expr.Compare(chara.things.List((Thing t) => t.id == itemId).Count);
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_hostility(DramaManager dm, Dictionary<string, string> line, string expression)
{
Chara chara = dm.GetChara(line["actor"]);
Match match = Regex.Match(expression, "^(?<op>>=|<=|>|<|=|!=|==)?(?<h>.+)$");
if (!match.Success)
{
throw new ArgumentException("invalid expression " + expression);
}
string value = match.Groups["op"].Value;
if (!Enum.TryParse<Hostility>(match.Groups["h"].Value, ignoreCase: true, out var result))
{
throw new ArgumentException("invalid hostility " + match.Groups["h"].Value);
}
return new DramaValueExpression($"{value}{result:D}").Compare(chara._cints[4]);
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_in_party(DramaManager dm, Dictionary<string, string> line, bool isInParty = true)
{
return dm.GetChara(line["actor"]).IsPCParty == isInParty;
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_keyitem(DramaManager dm, Dictionary<string, string> line, string keyitemId, DramaValueExpression expr = null)
{
if (expr == null)
{
expr = ">0";
}
if (EClass.sources.keyItems.alias.TryGetValue(keyitemId, out var value) && EClass.player.keyItems.TryGetValue(value.id, out var value2))
{
return expr.Compare(value2);
}
return false;
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_lv(DramaManager dm, Dictionary<string, string> line, DramaValueExpression expr)
{
Chara chara = dm.GetChara(line["actor"]);
return expr.Compare(chara.LV);
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_race(DramaManager dm, Dictionary<string, string> line, string raceId)
{
return dm.GetChara(line["actor"]).race.id == raceId;
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_tag(DramaManager dm, Dictionary<string, string> line, string tag)
{
return dm.GetChara(line["actor"]).source.tag.Contains(tag);
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_zone(DramaManager dm, Dictionary<string, string> line, string zoneId, int zoneLv = 99999)
{
Zone currentZone = dm.GetChara(line["actor"]).currentZone;
if (currentZone == null)
{
return false;
}
if (currentZone.id == zoneId)
{
if (zoneLv != 99999)
{
return currentZone.lv == zoneLv;
}
return true;
}
return false;
}
[ElinDramaActionInvoke("nodiscard")]
public static bool if_zone_2(DramaManager dm, Dictionary<string, string> line, string zoneFullName)
{
Zone currentZone = dm.GetChara(line["actor"]).currentZone;
Zone zone = ModUtil.FindZoneByFullName(zoneFullName);
return currentZone == zone;
}
[ElinDramaActionInvoke(null)]
public static bool mod_affinity(DramaManager dm, Dictionary<string, string> line, DramaValueExpression expr)
{
Chara chara = dm.GetChara(line["actor"]);
chara.ModAffinity(EClass.pc, expr.Diff(chara._affinity));
return true;
}
[ElinDramaActionInvoke(null)]
public static bool mod_currency(DramaManager dm, Dictionary<string, string> line, string currencyId, DramaValueExpression expr)
{
Chara chara = dm.GetChara(line["actor"]);
int currency = chara.GetCurrency(currencyId);
chara.ModCurrency(expr.Diff(currency), currencyId);
return true;
}
[ElinDramaActionInvoke(null)]
public static bool mod_element(DramaManager dm, Dictionary<string, string> line, string elementAlias, int value = 1, int potential = 100)
{
Chara chara = dm.GetChara(line["actor"]);
Element orCreateElement = chara.elements.GetOrCreateElement(elementAlias);
if (orCreateElement != null)
{
if (orCreateElement is Feat)
{
chara.SetFeat(orCreateElement.id, value, msg: true);
}
else
{
chara.elements.SetBase(orCreateElement.id, value, potential);
}
}
return true;
}
[ElinDramaActionInvoke(null)]
public static bool mod_element_exp(DramaManager dm, Dictionary<string, string> line, string elementAlias, DramaValueExpression expr)
{
Chara chara = dm.GetChara(line["actor"]);
Element orCreateElement = chara.elements.GetOrCreateElement(elementAlias);
if (orCreateElement == null)
{
return true;
}
chara.ModExp(orCreateElement.id, expr.Diff(orCreateElement.vExp));
return true;
}
[ElinDramaActionInvoke(null)]
public static bool mod_fame(DramaManager dm, Dictionary<string, string> line, DramaValueExpression expr)
{
EClass.player.ModFame(expr.Diff(EClass.player.fame));
return true;
}
[ElinDramaActionInvoke(null)]
public static bool mod_flag(DramaManager dm, Dictionary<string, string> line, string flagKey, DramaValueExpression expr = null)
{
if (expr == null)
{
expr = "=1";
}
Chara chara = dm.GetChara(line["actor"]);
chara.SetInt(flagKey, expr.ModOrSet(chara.GetInt(flagKey)));
return true;
}
[ElinDramaActionInvoke("nodiscard")]
public static bool mod_keyitem(DramaManager dm, Dictionary<string, string> line, string keyitemId, DramaValueExpression expr = null)
{
if (!EClass.sources.keyItems.alias.TryGetValue(keyitemId, out var value))
{
return false;
}
if (expr == null)
{
expr = "=1";
}
Dictionary<int, int> keyItems = EClass.player.keyItems;
keyItems.TryAdd(value.id, 0);
int num = keyItems[value.id];
int num2 = expr.ModOrSet(keyItems[value.id]);
if (num < num2)
{
SE.Play("keyitem");
Msg.Say("get_keyItem", value.GetName());
}
else if (num > num2)
{
SE.Play("keyitem_lose");
Msg.Say("lose_keyItem", value.GetName());
}
keyItems[value.id] = num2;
return true;
}
[ElinDramaActionInvoke(null)]
public static bool move_next_to(DramaManager dm, Dictionary<string, string> line, string charaId)
{
Chara chara = dm.GetChara(line["actor"]);
Chara chara2 = dm.GetChara(charaId);
if (chara2 == null)
{
return false;
}
Point nearestPoint = chara2.pos.GetNearestPoint(allowBlock: false, allowChara: false, allowInstalled: true, ignoreCenter: true);
chara.TryMove(nearestPoint, allowDestroyPath: false);
return true;
}
[ElinDramaActionInvoke(null)]
public static bool move_tile(DramaManager dm, Dictionary<string, string> line, int xOffset, int yOffset)
{
Chara chara = dm.GetChara(line["actor"]);
Point newPoint = chara.pos + new Point(xOffset, yOffset);
chara.TryMove(newPoint, allowDestroyPath: false);
return true;
}
[ElinDramaActionInvoke(null)]
public static bool move_to(DramaManager dm, Dictionary<string, string> line, int x, int y)
{
Chara chara = dm.GetChara(line["actor"]);
Point newPoint = new Point(x, y);
chara.TryMove(newPoint, allowDestroyPath: false);
return true;
}
[ElinDramaActionInvoke("nodiscard")]
public static bool move_zone(DramaManager dm, Dictionary<string, string> line, string zoneId, int zoneLv = 99999)
{
Chara chara = dm.GetChara(line["actor"]);
if (zoneLv == 99999)
{
zoneLv = 0;
}
Zone zone = ModUtil.FindZoneByFullName($"{zoneId}@{zoneLv}");
if (zone == null)
{
return false;
}
chara.MoveZone(zone, new ZoneTransition
{
state = ZoneTransition.EnterState.RandomVisit
});
return true;
}
[ElinDramaActionInvoke("nodiscard")]
public static bool move_zone_2(DramaManager dm, Dictionary<string, string> line, string zoneFullName)
{
Chara chara = dm.GetChara(line["actor"]);
Zone zone = ModUtil.FindZoneByFullName(zoneFullName);
if (zone == null)
{
return false;
}
chara.MoveZone(zone, new ZoneTransition
{
state = ZoneTransition.EnterState.RandomVisit
});
return true;
}
[ElinDramaActionInvoke(null)]
public static bool play_anime(DramaManager dm, Dictionary<string, string> line, AnimeID animeId)
{
dm.GetChara(line["actor"]).PlayAnime(animeId, force: true);
return true;
}
[ElinDramaActionInvoke(null)]
public static bool play_effect(DramaManager dm, Dictionary<string, string> line, string effectId)
{
dm.GetChara(line["actor"]).PlayEffect(effectId);
return true;
}
[ElinDramaActionInvoke(null)]
public static bool play_effect_at(DramaManager dm, Dictionary<string, string> line, string effectId, int x, int y)
{
Effect.Get(effectId)?.Play(new Point(x, y));
return true;
}
[ElinDramaActionInvoke(null)]
public static bool play_emote(DramaManager dm, Dictionary<string, string> line, Emo emote, float duration = 1f)
{
dm.GetChara(line["actor"]).ShowEmo(emote, duration, skipSame: false);
return true;
}
[ElinDramaActionInvoke(null)]
public static bool play_screen_effect(DramaManager dm, Dictionary<string, string> line, string effectId)
{
ScreenEffect.Play(effectId);
return true;
}
[ElinDramaActionInvoke(null)]
public static bool pop_text(DramaManager dm, Dictionary<string, string> line, string langText)
{
dm.GetChara(line["actor"]).HostRenderer.Say(langText.lang());
return true;
}
[ElinDramaActionInvoke(null)]
public static bool set_portrait(DramaManager dm, Dictionary<string, string> line, string portraitId = null)
{
Person person = dm.GetPerson(line["actor"]);
if (person == null)
{
return false;
}
string text = person.chara?.GetIdPortrait();
if (!portraitId.IsEmpty())
{
string text2 = person.id.IsEmpty(person.chara?.id);
HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
hashSet.Add("UN_" + text2 + "_" + text + ".png");
hashSet.Add(text + ".png");
hashSet.Add(text2 + "_" + text + ".png");
string text3 = hashSet.FirstOrDefault(Portrait.allIds.Contains);
if (text3 != null)
{
text = text3[..^4];
}
}
person.idPortrait = text;
return true;
}
[ElinDramaActionInvoke(null)]
public static bool set_portrait_override(DramaManager dm, Dictionary<string, string> line, string portraitId = null)
{
dm.GetChara(line["actor"]).SetPortraitOverride(portraitId);
return true;
}
[ElinDramaActionInvoke(null)]
public static bool set_sprite(DramaManager dm, Dictionary<string, string> line, string spriteId = null)
{
dm.GetChara(line["actor"]).SetSpriteOverride(spriteId);
return true;
}
[ElinDramaActionInvoke("nodiscard")]
public static bool show_book(DramaManager dm, Dictionary<string, string> line, string bookEntry)
{
if (BookList.dict == null)
{
BookList.Init();
}
string[] array = bookEntry.Split('/');
string text = array[0];
string text2 = array[1];
if (text2.EndsWith(".txt"))
{
text2 = text2[..^4];
}
if (!BookList.dict.TryGetValue(text, out var value) || !value.TryGetValue(text2, out var value2))
{
return false;
}
bool flag = text == "Scroll";
EClass.ui.AddLayer<LayerHelp>(flag ? "LayerParchment" : "LayerBook").book.Show((flag ? "Scroll/" : "Book/") + value2.id, null, value2.title, value2);
return true;
}
}+CustomDramaExpansionHelper โ
File Created
using System.Collections.Generic;
using System.Linq;
public static class CustomDramaExpansionHelper
{
public static void AddTempTalk(this DramaManager dm, string text, string actor = "tg", string? jump = null)
{
if (jump == null || dm.sequence.steps.ContainsKey(jump))
{
DramaEventTalk item = new DramaEventTalk
{
idActor = actor,
idJump = jump,
text = text,
temp = true,
sequence = dm.sequence
};
dm.sequence.tempEvents.Add(item);
}
}
public static void Goto(this DramaManager dm, string step)
{
if (dm.sequence.steps.ContainsKey(step))
{
dm.sequence.Play(step);
}
}
public static void InjectUniqueRumor(this DramaManager dm, Chara chara = null)
{
if (chara == null)
{
chara = dm.tg.chara;
}
if (chara == null)
{
return;
}
DramaCustomSequence cs = new DramaCustomSequence();
bool flag = chara.IsHumanSpeak || EClass.pc.HasElement(1640);
if ((!chara.IsUnique && !cs.HasTopic("unique", chara.id)) || !flag)
{
return;
}
dm.CustomEvent(dm.sequence.Exit);
DramaChoice choice = new DramaChoice("letsTalk".lang(), dm.sequence.steps.Last().Key.IsEmpty(dm.setup.step));
dm.lastTalk.choices.Add(choice);
dm._choices.Add(choice);
string rumor = (chara.IsPCParty ? chara.GetTalkText("sup") : cs.GetRumor(chara));
choice.SetOnClick(delegate
{
dm.sequence.firstTalk.funcText = () => rumor;
List<Hobby> list = chara.ListHobbies();
Hobby hobby = ((list.Count > 0) ? list[0] : null);
if (EClass.rnd(20) == 0 || EClass.debug.showFav)
{
if (EClass.rnd(2) == 0 || hobby == null)
{
GameLang.refDrama1 = chara.GetFavCat().GetName().ToLower();
GameLang.refDrama2 = chara.GetFavFood().GetName();
rumor = cs.GetText(chara, "general", "talk_fav");
chara.knowFav = true;
}
else
{
GameLang.refDrama1 = hobby.Name.ToLower();
rumor = cs.GetText(chara, "general", "talk_hobby");
}
}
else
{
rumor = cs.GetRumor(chara);
}
chara.affinity.OnTalkRumor();
choice.forceHighlight = true;
}).SetCondition(() => chara.interest > 0);
}
}CustomFileContent โ
{
LoadContent();
}
catch (Exception message)
catch (Exception exception)
{
ModUtil.LogModError("exception while loading file '" + base.ContentId + "'", base.Owner);
Debug.LogError(message);
Debug.LogException(exception);
}
finally
{+CustomGunEffectData โ
File Created
using Newtonsoft.Json;
using UnityEngine;
[JsonObject(MemberSerialization.OptOut)]
public class CustomGunEffectData : GameSetting.EffectData
{
public bool forceLaser;
public bool forceRail;
public string caneColor;
public bool caneColorBlend;
public string idSprite = "ranged_gun";
public string idSoundEject = "bullet_drop";
public GameSetting.EffectData CreateEffectData()
{
return new CustomGunEffectData
{
sprite = (ModUtil.LoadSprite(idSprite) ?? Resources.Load<Sprite>("Media/Effect/General/" + idSprite)),
eject = eject,
firePos = firePos,
num = num,
delay = delay,
idEffect = idEffect,
idSound = idSound
};
}
public static CustomGunEffectData CreateFromId(string id)
{
if (!EClass.setting.effect.guns.TryGetValue(id, out var value))
{
return null;
}
return new CustomGunEffectData
{
num = value.num,
delay = value.delay,
idEffect = value.idEffect,
idSound = value.idSound,
idSprite = (value.sprite ? value.sprite.name : ""),
eject = value.eject,
firePos = value.firePos
};
}
}+CustomGunEffectSetting โ
File Created
using System.Collections.Generic;
using System.IO;
public class CustomGunEffectSetting : CustomFileContent
{
public Dictionary<string, CustomGunEffectData> items;
public static CustomGunEffectSetting CreateFromFile(FileInfo file, ModPackage owner = null)
{
if (owner == null)
{
owner = ModUtil.FindFileProviderPackage(file);
}
return new CustomGunEffectSetting
{
ContentId = "GunEffect/" + owner.id,
Owner = owner,
File = file
};
}
protected override void LoadContent()
{
Dictionary<string, CustomGunEffectData> dictionary = IO.LoadFile<Dictionary<string, CustomGunEffectData>>(base.File.FullName, compress: false, GameIOContext.Settings);
items = dictionary;
}
public override string ToString()
{
return $"{base.ContentId}/items({items.Count})";
}
}CustomMerchantStock โ
public List<Thing> Generate(Card owner)
catch (Exception ex)
{
ModUtil.LogModError("can't create stock item '" + item2.ContentId + "'\n" + ex.Message, base.Owner);
Debug.LogError(ex);
Debug.LogException(ex);
}
}
return list;
}
public static CustomMerchantStock CreateFromId(string stockId, ModPackage owner)
public static CustomMerchantStock CreateFromId(string stockId, ModPackage owner = null)
{
var (fileInfo, eMod) = PackageIterator.GetFilesEx("Data/stock_" + stockId + ".json").LastOrDefault();
if (fileInfo == null)CustomReligionContent โ
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;public class CustomReligionContent : CustomSourceContent
public List<string> artifacts = new List<string>();
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue(true)]
public bool canJoin = true;
public bool isMinorGod; catch (Exception ex)
{
ModUtil.LogModError("exception while loading religion data '" + fileInfo.ShortPath() + "'\n" + ex.Message, package);
Debug.LogError(ex);
Debug.LogException(ex);
}
}
LoadDeprecatedCwlSpec();static void LoadDeprecatedCwlSpec()
catch (Exception ex2)
{
ModUtil.LogModError("exception while loading '" + fileInfo2.ShortPath() + "'\n" + ex2.Message, package2);
Debug.LogError(ex2);
Debug.LogException(ex2);
}
}
filesEx2 = PackageIterator.GetFilesEx("Data/religion_offerings.json");static void LoadDeprecatedCwlSpec()
catch (Exception ex3)
{
ModUtil.LogModError("exception while loading '" + fileInfo3.ShortPath() + "'\n" + ex3.Message, package3);
Debug.LogError(ex3);
Debug.LogException(ex3);
}
}
}internal static void LoadReligionData(GameIOContext context)
{
if (EClass.game.religions.dictAll.TryGetValue(key, out var value))
{
Debug.Log($"#mod-content loading {religionCustom2.content}");
Debug.Log("#mod-content loading Religion/" + value.id);
value.mood = religionCustom2.mood;
value.relation = religionCustom2.relation;
value.giftRank = religionCustom2.giftRank;CustomThingContent โ
using System.Collections.Generic;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using Newtonsoft.Json; [JsonConverter(typeof(StringEnumConverter))]
public Rarity rarity;
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue(true)]
public bool restock = true;
public List<string> sockets = new List<string>();CustomZoneContent โ
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using UnityEngine;public class CustomZoneContent : CustomSourceContent
{
public string parent;
public bool autoSpawn;
public override string SourceType => "SourceZone";
public static CustomZoneContent CreateFromRow(SourceZone.Row r, ModPackage owner = null)
{
List<string> list = r.tag.Where((string t) => t.StartsWith("add")).ToList();
if (list.Count == 0)
{
return null;
}
if (owner == null)
{
owner = ModUtil.FindSourceRowPackage(r);public static CustomZoneContent CreateFromRow(SourceZone.Row r, ModPackage owner
SourceId = r.id,
Owner = owner
};
foreach (string item in list)
string[] tag = r.tag;
for (int i = 0; i < tag.Length; i++)
{
var (text, str, _) = CustomSourceContent.GetParams(item);
var (text, str, _) = CustomSourceContent.GetParams(tag[i]);
if (text == "addMap")
{
customZoneContent.parent = str.IsEmpty(r.parent.IsEmpty("ntyris"));
customZoneContent.autoSpawn = true;
}
}
return customZoneContent;public static CustomZoneContent CreateFromRow(SourceZone.Row r, ModPackage owner
public override void OnGameLoad(GameIOContext context)
{
if (!autoSpawn || parent == null)
{
return;
}
Debug.Log($"#mod-content loading {this}");
if (EClass.game.spatials.Find(base.SourceId) != null)
{Dice โ
public static Dice Create(Element ele, Card c)
public static Dice Create(string id, int power, Card c = null, Act act = null)
{
if (!EClass.sources.calc.map.ContainsKey(id))
if (!EClass.sources.calc.map.TryGetValue(id, out var value) && (string.IsNullOrEmpty(act?.ID) || !EClass.sources.calc.map.TryGetValue(act.ID, out value)))
{
Debug.Log(id);
return null;
}
SourceCalc.Row row = EClass.sources.calc.map[id];
int power2 = power;
int ele = power / 10;
if (act != null)public static Dice Create(string id, int power, Card c = null, Act act = null)
}
try
{
return new Dice(Mathf.Max(1, row.num.Calc(power2, ele)), Mathf.Max(1, row.sides.Calc(power2, ele)), row.bonus.Calc(power2, ele), c);
return new Dice(Mathf.Max(1, value.num.Calc(power2, ele)), Mathf.Max(1, value.sides.Calc(power2, ele)), value.bonus.Calc(power2, ele), c);
}
catch
{+DramaActionParser โ
File Created
using System.Collections.Generic;
public delegate bool DramaActionParser(DramaManager dm, Dictionary<string, string> line);DramaActor โ
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
public class DramaActor : EMonoprivate void SetChoice(DramaChoice item, int index)
}
if (!idAction.IsEmpty())
{
typeof(DramaOutcome).GetMethod(sequence.id + "_" + idAction).Invoke(sequence.manager.outcome, PARAMS);
if (DramaOutcome.idJump != null)
MethodInfo method = typeof(DramaOutcome).GetMethod(sequence.id + "_" + idAction);
if (method != null)
{
sequence.Play(DramaOutcome.idJump);
return;
method.Invoke(sequence.manager.outcome, PARAMS);
if (DramaOutcome.idJump != null)
{
sequence.Play(DramaOutcome.idJump);
return;
}
}
}
if (item.onClick != null)DramaCustomSequence โ
}
if (c.trait.ShopType != 0)
{
Choice2(c.trait.TextNextRestock, "_buy").DisableSound();
if (!c.GetBool("disable_barter_choice"))
{
Choice2(c.trait.TextNextRestock, "_buy").DisableSound();
}
if (c.trait is TraitMerchantTravel && !c.IsPCFactionOrMinion)
{
Choice2("daRob", "_rob"); {
if (EClass.pc.HasElement(1232) || EClass.pc.HasElement(1291))
{
goto IL_094a;
goto IL_095c;
}
num2 = EClass.pc.HasCondition<StanceMama>();
} }
if (num2)
{
goto IL_094a;
goto IL_095c;
}
goto IL_095b;
goto IL_096d;
}
if (c.isDrunk || c.HasElement(1275) || EClass.debug.enable)
{
Choice2(flag2 ? "daBird" : "daTail", "_tail");
}
}
goto IL_0d74;
IL_099a:
Choice2("daBaby", "_baby");
goto IL_09ab;
IL_094a:
goto IL_0d86;
IL_095c:
Choice2("daMama", "_mama");
goto IL_095b;
IL_09ab:
goto IL_096d;
IL_09bd:
if (c.trait.CanRevive)
{
Choice2("daRevive", "_revive").DisableSound(); {
Choice2("daBlessing", "_blessing");
}
goto IL_0d74;
IL_0d74:
goto IL_0d86;
IL_09ac:
Choice2("daBaby", "_baby");
goto IL_09bd;
IL_096d:
ConTransmuteHuman condition2 = c.GetCondition<ConTransmuteHuman>();
bool num3;
if (condition2 == null)
{
if (c.HasElement(1232))
{
goto IL_09ac;
}
num3 = c.HasElement(1291);
}
else
{
num3 = condition2.IsBaby;
}
if (num3)
{
goto IL_09ac;
}
goto IL_09bd;
IL_0d86:
if (c.IsHomeMember())
{
if (c.IsMaid) End();
Step("_end");
End();
return;
IL_095b:
ConTransmuteHuman condition2 = c.GetCondition<ConTransmuteHuman>();
bool num3;
if (condition2 == null)
{
if (c.HasElement(1232))
{
goto IL_099a;
}
num3 = c.HasElement(1291);
}
else
{
num3 = condition2.IsBaby;
}
if (num3)
{
goto IL_099a;
}
goto IL_09ab;
void BackChill()
{
Method(RumorChill, null, StepDefault);DramaEvent โ
using System;
public class DramaEvent : EClass
{
public int progress;public class DramaEvent : EClass
public DramaSequence sequence;
public Func<bool> activeCondition;
public DramaActor actor => sequence.GetActor(idActor);
public DramaManager manager => sequence.manager; {
progress = 0;
}
public virtual bool CanPlay()
{
if (activeCondition != null)
{
return activeCondition();
}
return true;
}
}+DramaInvokeDetail โ
File Created
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq.Expressions;
using System.Reflection;
using UnityEngine;
public class DramaInvokeDetail
{
private Func<DramaManager, Dictionary<string, string>, string[], bool> _compiled;
private static readonly MethodInfo _stringIsNullOrEmpty = typeof(string).GetMethod("IsNullOrEmpty", new Type[1] { typeof(string) });
private static readonly ConstructorInfo _argumentException = typeof(ArgumentException).GetConstructor(new Type[1] { typeof(string) });
public MethodInfo Method { get; }
public string Contract { get; }
public bool NoDiscard => Contract.Contains("nodiscard");
public bool ParamPassthrough => Contract.Contains("passthrough");
public DramaInvokeDetail(MethodInfo method, string contract = null)
{
Method = method;
Contract = contract;
ValidateSignature();
}
private void ValidateSignature()
{
if (!(Method == null))
{
if (Method.ContainsGenericParameters)
{
throw new NotSupportedException("#drama action cannot contain generic parameters");
}
if (!Method.IsStatic)
{
throw new NotSupportedException("#drama action must be static");
}
ParameterInfo[] parameters = Method.GetParameters();
if (parameters.Length < 2 || parameters[0].ParameterType != typeof(DramaManager) || parameters[1].ParameterType != typeof(Dictionary<string, string>) || Method.ReturnType != typeof(bool))
{
throw new ArgumentException("#drama action parameters must start with 'DramaManager dm, Dictionary<string, string>' and returns 'bool'");
}
}
}
private Func<DramaManager, Dictionary<string, string>, string[], bool> BuildDelegate()
{
ParameterInfo[] parameters = Method.GetParameters();
ParameterExpression parameterExpression = Expression.Parameter(typeof(DramaManager), "dm");
ParameterExpression parameterExpression2 = Expression.Parameter(typeof(Dictionary<string, string>), "line");
ParameterExpression parameterExpression3 = Expression.Parameter(typeof(string[]), "parameters");
List<Expression> list = new List<Expression> { parameterExpression, parameterExpression2 };
if (parameters.Length == 3 && parameters[2].ParameterType == typeof(string[]))
{
list.Add(parameterExpression3);
}
else if (parameters.Length > 2)
{
for (int i = 2; i < parameters.Length; i++)
{
ParameterInfo parameter = parameters[i];
int num = i - 2;
Expression expr = Expression.Condition(Expression.LessThan(Expression.Constant(num), Expression.ArrayLength(parameterExpression3)), Expression.ArrayIndex(parameterExpression3, Expression.Constant(num)), Expression.Constant(null, typeof(string)));
list.Add(CreateConvertExpression(expr, parameter));
}
}
return Expression.Lambda<Func<DramaManager, Dictionary<string, string>, string[], bool>>(Expression.Call(null, Method, list), new ParameterExpression[3] { parameterExpression, parameterExpression2, parameterExpression3 }).Compile();
}
private static Expression CreateConvertExpression(Expression expr, ParameterInfo parameter)
{
Type parameterType = parameter.ParameterType;
bool isOptional = parameter.IsOptional;
object defaultValue = parameter.DefaultValue;
string text = $"required action parameter #{parameter.Position - 2} '{parameter.Name}'";
if (parameterType == typeof(string))
{
MethodCallExpression test = Expression.Call(_stringIsNullOrEmpty, expr);
if (isOptional)
{
ConstantExpression ifTrue = Expression.Constant(defaultValue, typeof(string));
return Expression.Condition(test, ifTrue, expr);
}
string value = "#drama " + text + " cannot be empty";
UnaryExpression ifTrue2 = Expression.Throw(Expression.New(_argumentException, Expression.Constant(value)), typeof(string));
return Expression.Condition(test, ifTrue2, expr);
}
MethodInfo tryParseMethod = GetTryParseMethod(parameterType);
if (tryParseMethod == null)
{
throw new NotSupportedException("#drama type '" + parameterType.Name + "' does not have a public static TryParse method");
}
ParameterExpression parameterExpression = Expression.Variable(parameterType, "parsed");
Expression test2 = Expression.Call(tryParseMethod, expr, parameterExpression);
Expression expression;
if (isOptional)
{
expression = Expression.Constant(defaultValue, parameterType);
}
else
{
string value2 = "#drama can't parse " + text + " to type '" + parameterType.Name + "'";
expression = Expression.Throw(Expression.New(_argumentException, Expression.Constant(value2)), parameterType);
}
ConditionalExpression conditionalExpression = Expression.Condition(Expression.Call(_stringIsNullOrEmpty, expr), expression, Expression.Condition(test2, parameterExpression, expression));
return Expression.Block(new ParameterExpression[1] { parameterExpression }, conditionalExpression);
}
private static MethodInfo GetTryParseMethod(Type type)
{
if (type.IsEnum)
{
MethodInfo method = typeof(Enum).GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
{
typeof(string),
type.MakeByRefType()
}, null);
if (method != null)
{
return method.MakeGenericMethod(type);
}
}
return type.GetMethod("TryParse", new Type[2]
{
typeof(string),
type.MakeByRefType()
});
}
public bool SafeInvoke(DramaManager dm, Dictionary<string, string> line, params string[] parameters)
{
if (Method == null)
{
return true;
}
try
{
if (_compiled == null)
{
_compiled = BuildDelegate();
}
return _compiled(dm, line, parameters);
}
catch (Exception ex)
{
ModUtil.LogModError("exception while invoking drama action '" + Method.TryToString() + "'\n" + ex.Message, new FileInfo(dm.path));
Debug.LogException(ex);
return false;
}
}
}+DramaInvokeFunc โ
File Created
using System.Collections.Generic;
public delegate bool DramaInvokeFunc(DramaManager dm, Dictionary<string, string> line, params string[] parameters);DramaManager โ
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using DG.Tweening;
using UnityEngine;public class DramaManager : EMono
public float creditSpeed;
[NonSerialized]
public string path;
private string lastIF;
private string lastIF2;public class DramaManager : EMono
private string textReplace;
public static Dictionary<string, ExcelData> dictCache = new Dictionary<string, ExcelData>();
public static Dictionary<string, ExcelData> dictCache = new Dictionary<string, ExcelData>(PathComparer.Default);
public bool keepAmbientBGM => !bgmChanged;
public EScriptSubmission Scripting => EScriptSubmission.Create(setup.book);
public DramaActor tgActor => sequence.GetActor("tg");
private void Update()
{
if (sequence != null)
try
{
sequence?.OnUpdate();
}
catch (Exception ex)
{
sequence.OnUpdate();
layer.Close();
ModUtil.LogModError("error during drama play\n" + ex.GetType().Name + ": " + ex.Message, new FileInfo(path));
Debug.LogException(ex);
}
} sequence.AddActor("tg", tg);
}
sequence.AddActor("pc", new Person(EMono.pc));
string text = PackageIterator.GetFiles("Dialog/Drama/" + setup.book + ".xlsx").LastOrDefault()?.FullName ?? (CorePath.DramaData + setup.book + ".xlsx");
string text = PackageIterator.GetFiles("Dialog/Drama/" + setup.book + ".xlsx").LastOrDefault()?.FullName;
ExcelData excelData = dictCache.TryGetValue(text);
if (excelData != null && excelData.IsModified())
{ excelData = new ExcelData();
}
excelData.maxEmptyRows = 10;
excelData.path = text;
path = (excelData.path = text ?? (CorePath.DramaData + setup.book + ".xlsx"));
List<Dictionary<string, string>> list = excelData.BuildList(setup.sheet);
if (!Lang.isBuiltin && dictLocalize.Count == 0)
dictCache[excelData.path] = excelData;
string key = text ?? (CorePath.DramaDataLocal + setup.book + ".xlsx");
if (!File.Exists(key))
{
key = excelData.path;
}
ExcelData excelData2 = dictCache.TryGetValue(key);
if (excelData2 != excelData)
{
if (excelData2 != null && excelData2.IsModified())
{
excelData2 = null;
}
if (excelData2 == null)
{
excelData2 = new ExcelData();
}
excelData2.maxEmptyRows = 10;
excelData2.path = key;
dictCache[excelData2.path] = excelData2;
}
dictLocalize.Clear();
string[] array = new string[3]
{
"text_" + Lang.langCode,
"text",
"text_EN"
};
foreach (Dictionary<string, string> item in excelData2.BuildList(setup.sheet))
{
foreach (Dictionary<string, string> item in new ExcelData
string text2 = item["id"];
if (text2.IsEmpty())
{
maxEmptyRows = 10,
path = (PackageIterator.GetFiles("Dialog/Drama/" + setup.book + ".xlsx").LastOrDefault()?.FullName ?? (CorePath.DramaDataLocal + setup.book + ".xlsx"))
}.BuildList(setup.sheet))
continue;
}
string value = null;
string[] array2 = array;
foreach (string key2 in array2)
{
string text2 = item["id"];
if (!text2.IsEmpty())
if (item.TryGetValue(key2, out value) && !value.IsEmpty())
{
string text3 = item.TryGetValue("text_" + Lang.langCode) ?? item["text"];
if (!dictLocalize.TryAdd(text2, text3))
{
string text4 = dictLocalize[text2];
dictLocalize[text2] = ("[DUPLICATE ID '" + text2 + "']\n").TagColor(Color.red) + text4;
Debug.LogError("#drama duplicate id '" + text2 + "' at " + text + "\n" + text4 + " -> " + text3);
}
break;
}
}
if (value == null)
{
value = "[ID '" + text2 + "'] <empty text>";
}
if (!dictLocalize.TryAdd(text2, value))
{
string text3 = dictLocalize[text2];
dictLocalize[text2] = ("[DUPLICATE ID '" + text2 + "']\n").TagColor(Color.red) + text3;
Debug.LogWarning("#drama duplicate id '" + text2 + "' at " + path + "\n" + text3 + " -> " + value);
}
}
dictCache[text] = excelData;
idDefault = setup.step;
lastTalk = null;
enableTone = (customEventsAdded = (idDefaultPassed = false));
countLine = 0;
for (int i = 0; i < list.Count; i++)
for (int j = 0; j < list.Count; j++)
{
ParseLine(list[i]);
try
{
ParseLine(list[j]);
}
catch (Exception exception)
{
Debug.LogException(exception);
}
countLine++;
}
AddCustomEvents();public void AddCustomEvents(string idCustom = "Resident")
public void ParseLine(Dictionary<string, string> item)
{
string[] array = (item.ContainsKey("action") ? item["action"].Split('/') : null);
string action = ((array != null) ? array[0] : null);
string text2 = (item.ContainsKey("step") ? item["step"] : null);
string text2 = item.TryGetValue("step");
if (text2 == "//")
{
return;public void ParseLine(Dictionary<string, string> item)
{
idDefaultPassed = true;
}
string actor = (item.ContainsKey("actor") ? item["actor"] : "#1");
string[] p = (item.ContainsKey("param") ? item["param"].Split(',') : new string[0]);
string[] array = item.TryGetValue("action")?.Split('/');
string action = array.TryGet(0, returnNull: true);
string actor = item.GetValueOrDefault("actor", "#1");
string[] p = item.TryGetValue("param")?.Split(',') ?? Array.Empty<string>();
string p2 = ((p.Length != 0) ? p[0] : "");
string p3 = ((p.Length > 1) ? p[1] : "");
string p4 = ((p.Length > 2) ? p[2] : "");
float.TryParse(p2, out var p0f);
float.TryParse(p3, out var result);
bool flag = !item["text_JP"].IsEmpty();
item.TryGetValue("text_JP");
string text = null;
if (flag)
string text = item.TryGetValue("text_JP");
bool flag = !text.IsEmpty();
string id = item["id"];
if (!id.IsEmpty())
{
if (!Lang.isBuiltin)
{
string key = item["id"];
if (dictLocalize.ContainsKey(key))
{
text = dictLocalize[key];
}
else
{
text = item.TryGetValue("text_EN");
}
}
else
{
text = item["text_" + Lang.langCode];
}
text = dictLocalize.TryGetValue(id);
flag = !text.IsEmpty();
}
if (flag && text.StartsWith("$") && tg != null && tg.hasChara)
{
string text3 = text.Split(' ')[0];
text = text.Replace(text3, tg.chara.GetTalkText(text3.Remove(0, 1)));
text = text.Replace(text3, tg.chara.GetTalkText(text3[1..]));
}
string jump = (item.ContainsKey("jump") ? item["jump"] : null);
string text4 = (item.ContainsKey("if") ? item["if"] : null);
string iF = (item.ContainsKey("if2") ? item["if2"] : null);
string cHECK = (item.ContainsKey("check") ? item["check"] : null);
string jump = item.TryGetValue("jump");
string text4 = item.TryGetValue("if");
string iF = item.TryGetValue("if2");
string cHECK = item.TryGetValue("check");
bool flag2 = false;
if (text2 != null && !sequence.steps.ContainsKey(text2) && action != "choice" && action != "cancel")
if (!text2.IsEmpty() && !sequence.steps.ContainsKey(text2) && action != "choice" && action != "cancel")
{
sequence.steps.Add(text2, sequence.events.Count);
}public void ParseLine(Dictionary<string, string> item)
{
if (action == "reload")
{
string id = "flag" + countLine;
sequence.AddStep(id);
string id2 = "flag" + countLine;
sequence.AddStep(id2);
}
return;
}public void ParseLine(Dictionary<string, string> item)
}
break;
case "choice":
if (!CheckIF(text4) || !CheckIF(iF))
{
break;
}
{
if (array.Length > 1)
{
switch (array[1])public void ParseLine(Dictionary<string, string> item)
}
}
flag2 = true;
lastTalk.AddChoice(new DramaChoice(text, jump, p2, cHECK, text4));
DramaChoice dramaChoice = new DramaChoice(text, jump, p2, cHECK, text4);
lastTalk.AddChoice(dramaChoice);
var (invoke, invokeP) = CustomDramaExpansion.BuildInvokeExpression(item.TryGetValue("param"));
if (invoke.Method != null)
{
dramaChoice.idAction = "";
dramaChoice.SetCondition(() => invoke.SafeInvoke(this, item, invokeP));
}
break;
}
case "addTempActor":
{
Person person = new Person(actor);public void ParseLine(Dictionary<string, string> item)
else
{
imageBG.enabled = true;
imageBG.sprite = Resources.Load<Sprite>("Media/Graphics/Image/Drama/" + p2);
imageBG.sprite = Resources.Load<Sprite>("Media/Graphics/Image/Drama/" + p2) ?? ModUtil.LoadSprite(p2);
}
});
break;public void ParseLine(Dictionary<string, string> item)
else
{
dialog.imageBgAdv.enabled = true;
dialog.imageBgAdv.sprite = Resources.Load<Sprite>("Media/Graphics/Image/Drama/" + p2);
dialog.imageBgAdv.sprite = Resources.Load<Sprite>("Media/Graphics/Image/Drama/" + p2) ?? ModUtil.LoadSprite(p2);
}
});
break;public void ParseLine(Dictionary<string, string> item)
});
break;
default:
{
EVENT.ElinDramaParseActionEventArgs elinDramaParseActionEventArgs = new EVENT.ElinDramaParseActionEventArgs
{
dm = this,
line = item
};
elinDramaParseActionEventArgs.SetData(action);
BaseModManager.PublishEvent("elin.drama.parse_action", elinDramaParseActionEventArgs);
if (elinDramaParseActionEventArgs.IsUsed)
if (CustomDramaExpansion.ParseAction(action, this, item))
{
return;
}public void ParseLine(Dictionary<string, string> item)
text = textReplace;
textReplace = null;
}
if (text.StartsWith("#eval"))
{
string script = text[5..].Trim();
if (!EScript.IsScriptingAvailable)
{
return ("[ID '" + id + "'] <scripting is disabled>").TagColor(Color.red);
}
Func<EDramaScriptState, object> func = Scripting.Compile<EDramaScriptState>(script);
EDramaScriptState arg = new EDramaScriptState
{
dm = this,
line = item
};
text = func(arg).TryToString("[ID '" + id + "'] <scripting returns no text>");
}
if (tg != null && (actor == "tg" || actor.IsEmpty()))
{
text = (enableTone ? tg.ApplyTone(text) : text);public void ParseLine(Dictionary<string, string> item)
})) as DramaEventTalk;
lastTalk.center = p2 == "center";
break;
}
case "new":
case "saveBGM":
case "checkAffinity":public void ParseLine(Dictionary<string, string> item)
}
}
public Chara GetChara(string id)
{
return GetPerson(id)?.chara;
}
public Person GetPerson(string id)
{
return GetActor(id)?.owner;
}
public DramaActor GetActor(string id)
{
return sequence.GetActor(id);DramaSequence โ
public DramaActor GetActor(string id)
{
if (actors.ContainsKey(id))
if (actors.TryGetValue(id, out var value))
{
return actors[id];
return value;
}
if (EClass.sources.persons.map.ContainsKey(id))
{public DramaActor GetActor(string id)
return AddActor(id, new Person(chara));
}
}
if (EClass.sources.charas.map.TryGetValue(id, out var value2))
{
Person person = new Person(id)
{
name = value2.GetName()
};
if (Portrait.allIds.Contains(person.id))
{
person.idPortrait = "UN_" + id;
}
return AddActor(id, person);
}
if (actors.Count <= 0)
{
return GetActor("narrator");public T GetEvent<T>(string idStep) where T : DramaEvent
public DramaActor AddActor(string id, Person person)
{
if (actors.ContainsKey(id))
if (actors.TryGetValue(id, out var value))
{
return actors[id];
return value;
}
DramaActor dramaActor = Util.Instantiate(manager.moldActor, manager.actorPos);
dramaActor.Init(this, id, person);
actors.Add(id, dramaActor);
return dramaActor;
value = Util.Instantiate(manager.moldActor, manager.actorPos);
value.Init(this, id, person);
actors.Add(id, value);
return value;
}
public void AddStep(string id) }
Play(text);
}
else if (currentEvent.Play())
else if (!currentEvent.CanPlay() || currentEvent.Play())
{
PlayNext();
}+DramaValueExpression โ
File Created
using System.Text.RegularExpressions;
using UnityEngine;
public class DramaValueExpression
{
private static readonly Regex _listSyntaxRegex = new Regex("^(?<op>>=|<=|==|!=|--|\\+\\+|[><=+\\-*/x])?(?<number>.*)$", RegexOptions.Compiled);
public string Expression { get; }
public string Op { get; }
public string Rhs { get; }
public DramaValueExpression(string expression)
{
Expression = expression.Trim();
Match match = _listSyntaxRegex.Match(Expression);
Op = match.Groups["op"].Value;
Rhs = match.Groups["number"].Value;
}
public static bool TryParse(string expression, out DramaValueExpression valueExpr)
{
valueExpr = new DramaValueExpression(expression);
return true;
}
public static implicit operator DramaValueExpression(string expr)
{
return new DramaValueExpression(expr);
}
public static implicit operator string(DramaValueExpression expr)
{
return expr.Expression;
}
public int Calc(int lhs)
{
if (Expression.IsEmpty())
{
return lhs;
}
if (!$"{lhs} {Expression}".TryEvaluateAsCalc(out int result, (object)null))
{
return lhs;
}
return result;
}
public float Calc(float lhs)
{
if (Expression.IsEmpty())
{
return lhs;
}
if (!$"{lhs} {Expression}".TryEvaluateAsCalc(out float result, (object)null))
{
return lhs;
}
return result;
}
public float Diff(float lhs)
{
return ModOrSet(lhs) - lhs;
}
public int Diff(int lhs)
{
return ModOrSet(lhs) - lhs;
}
public float ModOrSet(float lhs)
{
if (Expression.IsEmpty())
{
return lhs;
}
string op = Op;
if (!(op == "++"))
{
if (op == "--")
{
return lhs - 1f;
}
if (!float.TryParse(Rhs, out var result))
{
return lhs;
}
switch (Op)
{
case "+":
return lhs + result;
case "-":
return lhs - result;
case "*":
case "x":
return lhs * result;
case "/":
return lhs / result;
case "=":
case "==":
return result;
case "":
return result;
default:
return lhs;
}
}
return lhs + 1f;
}
public int ModOrSet(int lhs)
{
if (Expression.IsEmpty())
{
return lhs;
}
string op = Op;
if (!(op == "++"))
{
if (op == "--")
{
return lhs - 1;
}
if (!int.TryParse(Rhs, out var result))
{
return lhs;
}
switch (Op)
{
case "+":
return lhs + result;
case "-":
return lhs - result;
case "*":
case "x":
return lhs * result;
case "/":
return lhs / result;
case "=":
case "==":
return result;
case "":
return result;
default:
return lhs;
}
}
return lhs + 1;
}
public bool Compare(float lhs)
{
if (Expression.IsEmpty())
{
return false;
}
if (Op == "")
{
if (float.TryParse(Rhs, out var result))
{
return Mathf.Approximately(lhs, result);
}
return false;
}
if (!float.TryParse(Rhs, out var result2))
{
return false;
}
switch (Op)
{
case ">":
return lhs > result2;
case "<":
return lhs < result2;
case "=":
case "==":
return Mathf.Approximately(lhs, result2);
case ">=":
return lhs >= result2;
case "<=":
return lhs <= result2;
case "!=":
return !Mathf.Approximately(lhs, result2);
default:
return false;
}
}
public bool Compare(int lhs)
{
if (Expression.IsEmpty())
{
return false;
}
if (Op == "")
{
if (int.TryParse(Rhs, out var result))
{
return lhs == result;
}
return false;
}
if (!int.TryParse(Rhs, out var result2))
{
return false;
}
switch (Op)
{
case ">":
return lhs > result2;
case "<":
return lhs < result2;
case "=":
case "==":
return lhs == result2;
case ">=":
return lhs >= result2;
case "<=":
return lhs <= result2;
case "!=":
return lhs != result2;
default:
return false;
}
}
}+DuplicateCondition โ
File Created
public enum DuplicateCondition
{
Default,
Scarab,
SpiderEgg,
Water
}+EDramaScriptState โ
File Created
using System.Collections.Generic;
public class EDramaScriptState : EScriptState
{
public DramaManager dm;
public Dictionary<string, string> line;
public Chara pc => EClass.pc;
public Chara tg => dm.GetActor("tg").owner.chara;
public string text
{
get
{
return line["text"];
}
set
{
line["text"] = value;
}
}
}+ElinActPerformAttribute โ
File Created
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method)]
public sealed class ElinActPerformAttribute : ElinEventBaseAttribute
{
public override void Register(MethodInfo method)
{
Action<Act> handler = method.CreateDelegate<Action<Act>>();
BaseModManager.SubscribeEvent("elin.act_performed", handler);
}
}+ElinCharaOnCreateAttribute โ
File Created
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method)]
public sealed class ElinCharaOnCreateAttribute : ElinEventBaseAttribute
{
public override void Register(MethodInfo method)
{
Action<Chara> handler = method.CreateDelegate<Action<Chara>>();
BaseModManager.SubscribeEvent("elin.chara_created", handler);
}
}+ElinContextMenuEntryAttribute โ
File Created
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method)]
public sealed class ElinContextMenuEntryAttribute : ElinEventBaseAttribute
{
public string DisplayName { get; }
public string MenuEntry { get; }
public ElinContextMenuEntryAttribute(string langEntry, string langDisplay = "")
{
MenuEntry = langEntry.lang();
DisplayName = langDisplay.IsEmpty(MenuEntry.Split('/')[^1]).lang();
}
public override void Register(MethodInfo method)
{
ModUtil.AddContextMenuEntry(method.CreateDelegate<Action>(), MenuEntry, DisplayName);
}
}+ElinDramaActionInvokeAttribute โ
File Created
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method)]
public sealed class ElinDramaActionInvokeAttribute : ElinEventBaseAttribute
{
public string Contract { get; }
public ElinDramaActionInvokeAttribute(string contract = null)
{
Contract = contract;
}
public override void Register(MethodInfo method)
{
CustomDramaExpansion.AddDramaInvokeMethod(method.Name, method, Contract);
}
}+ElinDramaActionParserAttribute โ
File Created
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class ElinDramaActionParserAttribute : ElinEventBaseAttribute
{
public string DramaAction { get; }
public ElinDramaActionParserAttribute(string action)
{
if (action.IsEmpty())
{
throw new ArgumentNullException("action");
}
DramaAction = action;
}
public override void Register(MethodInfo method)
{
DramaActionParser parser = method.CreateDelegate<DramaActionParser>();
CustomDramaExpansion.AddDramaActionParser(DramaAction, parser);
}
}+ElinEventBaseAttribute โ
File Created
using System;
using System.Reflection;
public abstract class ElinEventBaseAttribute : Attribute
{
public virtual void Register(MethodInfo method)
{
}
public virtual void Register(PropertyInfo property)
{
}
}+ElinGameIOEventAttribute โ
File Created
using System;
[AttributeUsage(AttributeTargets.Method)]
public abstract class ElinGameIOEventAttribute : ElinEventBaseAttribute
{
}+ElinGameIOPropertyAttribute โ
File Created
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using UnityEngine;
[AttributeUsage(AttributeTargets.Property)]
public class ElinGameIOPropertyAttribute : ElinGameIOEventAttribute
{
private static bool _registered;
private static readonly Dictionary<string, (PropertyInfo property, Func<object> getter, Action<object> setter)> _contextVars = new Dictionary<string, (PropertyInfo, Func<object>, Action<object>)>();
public string ChunkName { get; }
public ElinGameIOPropertyAttribute(string chunkName)
{
ChunkName = chunkName;
}
public override void Register(PropertyInfo property)
{
if (!_registered)
{
BaseModManager.SubscribeEvent<GameIOContext>("elin.game.post_load", LoadGameIOProperty);
BaseModManager.SubscribeEvent<GameIOContext>("elin.game.post_save", SaveGameIOProperty);
_registered = true;
}
MethodInfo getMethod = property.GetMethod;
MethodInfo setMethod = property.SetMethod;
if (!(getMethod == null) && !(setMethod == null) && setMethod.IsStatic)
{
Func<object> item = getMethod.CreateDelegate<Func<object>>();
Action<object> item2 = CreateSetterDelegate(setMethod);
Type declaringType = property.DeclaringType;
_contextVars[declaringType.FullName + ":" + ChunkName] = (property, item, item2);
}
}
private static Action<object> CreateSetterDelegate(MethodInfo method)
{
Type parameterType = method.GetParameters()[0].ParameterType;
ParameterExpression parameterExpression = Expression.Parameter(typeof(object), "obj");
UnaryExpression arg = Expression.Convert(parameterExpression, parameterType);
return Expression.Lambda<Action<object>>(Expression.Call(method, arg), new ParameterExpression[1] { parameterExpression }).Compile();
}
private static void LoadGameIOProperty(GameIOContext context)
{
if (!context.Load<Dictionary<string, object>>("context_vars", out var data))
{
data = new Dictionary<string, object>();
}
KeyValuePair<string, (PropertyInfo, Func<object>, Action<object>)>[] array = _contextVars.ToArray();
foreach (KeyValuePair<string, (PropertyInfo, Func<object>, Action<object>)> keyValuePair in array)
{
keyValuePair.Deconstruct(out var key, out var value);
(PropertyInfo, Func<object>, Action<object>) tuple = value;
string text = key;
var (propertyInfo, _, action) = tuple;
try
{
string key2 = propertyInfo.DeclaringType.FullName + ":" + text;
object valueOrDefault = data.GetValueOrDefault(key2);
action(valueOrDefault);
}
catch (Exception arg)
{
Debug.LogError($"#io failed to populate context var {text}\n{arg}");
_contextVars.Remove(text);
}
}
}
private static void SaveGameIOProperty(GameIOContext context)
{
Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
KeyValuePair<string, (PropertyInfo, Func<object>, Action<object>)>[] array = _contextVars.ToArray();
foreach (KeyValuePair<string, (PropertyInfo, Func<object>, Action<object>)> keyValuePair in array)
{
keyValuePair.Deconstruct(out var key, out var value);
(PropertyInfo, Func<object>, Action<object>) tuple = value;
string text = key;
var (propertyInfo, func, _) = tuple;
try
{
object value2 = func();
string key2 = propertyInfo.DeclaringType.FullName + ":" + text;
dictionary[key2] = value2;
}
catch (Exception arg)
{
Debug.LogError($"#io failed to save context var {text}\n{arg}");
_contextVars.Remove(text);
}
}
context.Save("context_vars", dictionary);
}
}+ElinPostLoadAttribute โ
File Created
using System;
using System.Reflection;
public sealed class ElinPostLoadAttribute : ElinGameIOEventAttribute
{
public override void Register(MethodInfo method)
{
Action<GameIOContext> handler = method.CreateDelegate<Action<GameIOContext>>();
BaseModManager.SubscribeEvent("elin.game.start_new", handler);
BaseModManager.SubscribeEvent("elin.game.post_load", handler);
}
}+ElinPostSaveAttribute โ
File Created
using System;
using System.Reflection;
public sealed class ElinPostSaveAttribute : ElinGameIOEventAttribute
{
public override void Register(MethodInfo method)
{
Action<GameIOContext> handler = method.CreateDelegate<Action<GameIOContext>>();
BaseModManager.SubscribeEvent("elin.game.post_save", handler);
}
}+ElinPostSceneInitAttribute โ
File Created
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method)]
public sealed class ElinPostSceneInitAttribute : ElinEventBaseAttribute
{
public override void Register(MethodInfo method)
{
Action<Scene.Mode> handler = method.CreateDelegate<Action<Scene.Mode>>();
BaseModManager.SubscribeEvent("elin.scene.post_init", handler);
}
}+ElinPreLoadAttribute โ
File Created
using System;
using System.Reflection;
public sealed class ElinPreLoadAttribute : ElinGameIOEventAttribute
{
public override void Register(MethodInfo method)
{
Action<GameIOContext> handler = method.CreateDelegate<Action<GameIOContext>>();
BaseModManager.SubscribeEvent("elin.game.pre_load", handler);
}
}+ElinPreSaveAttribute โ
File Created
using System;
using System.Reflection;
public sealed class ElinPreSaveAttribute : ElinGameIOEventAttribute
{
public override void Register(MethodInfo method)
{
Action<GameIOContext> handler = method.CreateDelegate<Action<GameIOContext>>();
BaseModManager.SubscribeEvent("elin.game.pre_save", handler);
}
}+ElinPreSceneInitAttribute โ
File Created
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method)]
public sealed class ElinPreSceneInitAttribute : ElinEventBaseAttribute
{
public override void Register(MethodInfo method)
{
Action<Scene.Mode> handler = method.CreateDelegate<Action<Scene.Mode>>();
BaseModManager.SubscribeEvent("elin.scene.pre_init", handler);
}
}+ElinThingOnCreateAttribute โ
File Created
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method)]
public sealed class ElinThingOnCreateAttribute : ElinEventBaseAttribute
{
public override void Register(MethodInfo method)
{
Action<Thing> handler = method.CreateDelegate<Action<Thing>>();
BaseModManager.SubscribeEvent("elin.thing_created", handler);
}
}FACTION โ
public static Faction Create(SourceFaction.Row r)
{
Faction faction = ClassCache.Create<Faction>(r.type, "Elin");
faction.id = r.id;
faction.Init();
return faction;
Faction obj = ClassCache.Create<Faction>(r.type, "Elin") ?? new Faction();
obj.id = r.id;
obj.Init();
return obj;
}
public void Init()FEAT โ
public override void WritePurchaseReq(UINote n, int lv = -1)
}
}
public List<string> Apply(int a, ElementContainer owner, bool hint = false)
public virtual List<string> Apply(int a, ElementContainer owner, bool hint = false)
{
if (hint)
{HotItemContext โ
public static void Show(string id, Vector3 pos)
{
Util.ShowExplorer(CorePath.custom + "Portrait");
});
if (ModUtil.contextMenuProxies.Count > 0)
{
UIContextMenu parent2 = i.AddChild("mod");
foreach (ContextMenuProxy contextMenuProxy in ModUtil.contextMenuProxies)
{
PopulateMenu(parent2, contextMenuProxy);
}
}
i.AddSeparator();
i.AddButton("help", delegate
{ EClass.scene.camSupport.tiltShift.blurArea = 0.1f * b;
}, 0f, 150f, isInt: true, hideOther: false);
}
static void PopulateMenu(UIContextMenu parent, ContextMenuProxy proxy)
{
if (proxy.isMenu)
{
UIContextMenu parent3 = parent.AddChild(proxy.DisplayName);
{
foreach (ContextMenuProxy child in proxy.children)
{
PopulateMenu(parent3, child);
}
return;
}
}
parent.AddButton(proxy.DisplayName, proxy.onClick);
}
static void Toggle(ref bool flag)
{
flag = !flag;ModManager โ
public class ModManager : ModManagerCore
public List<FileInfo> replaceFiles = new List<FileInfo>();
private Action ImportModGodTalks;
public static List<string> ListChainLoad => BaseModManager.listChainLoad;
public static DirectoryInfo DirWorkshop => Instance.dirWorkshop;public override void Init(string path, string defaultPackage = "_Elona")
Core.SaveElinIni(elinIni);
}
}
if (!dirWorkshop.Exists)
if ((!(dirWorkshop?.Exists)) ?? true)
{
dirWorkshop = null;
}ModUtil โ
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using Newtonsoft.Json;
using ReflexCLI;
using ReflexCLI.Attributes;
using UnityEngine;
using UnityEngine.Networking;
private static readonly List<Func<string, object, int>> _customCalcEvaluator = new List<Func<string, object, int>>();
private static readonly HashSet<Type> _checkedAttributedTypes = new HashSet<Type>();
private static readonly Dictionary<string, Texture2D> _cachedTextures = new Dictionary<string, Texture2D>();
private static Effect _rodTemplate;
public static SourceImporter sourceImporter = new SourceImporter(SourceMapping);
public static readonly List<ContextMenuProxy> contextMenuProxies = new List<ContextMenuProxy>();
public static IReadOnlyDictionary<string, SourceData> SourceMapping => (from f in typeof(SourceManager).GetFields()
where typeof(SourceData).IsAssignableFrom(f.FieldType)
select f).ToDictionary((FieldInfo f) => f.FieldType.Name, (FieldInfo f) => f.GetValue(EClass.sources) as SourceData);public static void RegisterSerializedTypeFallback(string nameAssembly, string na
public static void LogModError(string message, BaseModPackage package = null)
{
string text = "#mod/" + package?.id + "\n" + message;
string text = "#mod/" + package?.title + " (" + package?.id + ")\n" + message;
UnityEngine.Debug.LogWarning(text.RemoveAllTags());
if ((package?.isInPackages ?? false) || Application.isEditor)
{public static void LogModError(string message, BaseModPackage package = null)
}
}
public static void LogModError(string message, SourceData.BaseRow row = null)
public static void LogModError(string message, SourceData.BaseRow row)
{
LogModError(message, FindSourceRowPackage(row));
}
public static void LogModError(string message, FileInfo file = null)
public static void LogModError(string message, Type type)
{
LogModError(message, FindFileProviderPackage(new FileInfo(type.Assembly.Location)));
}
public static void LogModError(string message, FileInfo file)
{
LogModError(message, FindFileProviderPackage(file));
}
public static void LogModError(string message, DirectoryInfo dir = null)
public static void LogModError(string message, DirectoryInfo dir)
{
LogModError(message, FindDirectoryProviderPackage(dir));
}public static ModPackage GetModPackage(string modId)
public static ModPackage FindFileProviderPackage(FileInfo file)
{
string path = file.FullName.NormalizePath();
return ModManager.Instance.packages.LastOrDefault((BaseModPackage p) => path.StartsWith(p.dirInfo.FullName)) as ModPackage;
return ModManager.Instance.packages.LastOrDefault((BaseModPackage p) => path.StartsWith(p.dirInfo.FullName.NormalizePath())) as ModPackage;
}
public static ModPackage FindDirectoryProviderPackage(DirectoryInfo dir)
{
string path = dir.FullName.NormalizePath();
return ModManager.Instance.packages.LastOrDefault((BaseModPackage p) => path.StartsWith(p.dirInfo.FullName)) as ModPackage;
return ModManager.Instance.packages.LastOrDefault((BaseModPackage p) => path.StartsWith(p.dirInfo.FullName.NormalizePath())) as ModPackage;
}
public static ModPackage FindSourceRowPackage(SourceData.BaseRow row)
public static void OnModsActivated()
{
_cachedTextures.Clear();
_customContent.Clear();
CommandRegistry.assemblies.Add(typeof(EScript).Assembly);
SoundManager.current.soundLoaders.Add(LoadSoundData);
UIBook.topicLoaders.Add(LoadTopicFiles);
BookList.booklistLoaders.Add(LoadBookList);
Lang.excelDialogLoaders.Add(LoadExcelDialog);
BaseModManager.SubscribeEvent<GameIOContext>("elin.game.post_load", OnPostLoadInit);
BaseModManager.SubscribeEvent<GameIOContext>("elin.game.start_new", OnPostLoadInit);
BaseModManager.SubscribeEvent<GameIOContext>("elin.game.post_save", OnPostSaveInit);
LoadEffectTemplate();
DynamicAsset<Effect>.assetLoaders.Add(LoadEffect);
BaseModManager.SubscribeEvent<string>("elin.source.lang_set", OnSetLang);
BaseModManager.SubscribeEvent<Chara>("elin.chara_created", OnCharaCreated);
BaseModManager.SubscribeEvent<Thing>("elin.thing_created", OnThingCreated);
BaseModManager.SubscribeEvent<List<Religion>>("elin.religion_importing", OnReligionImporting);
BaseModManager.SubscribeEvent<Act>("elin.act_performed", OnActPerformed);
BaseModManager.SubscribeEvent("elin.source.importing", OnSourceImporting);
BaseModManager.SubscribeEvent("elin.source.imported", OnSourceImported);
BaseModManager.PublishEvent("elin.mods.activated");
RegisterElinEventAttributes();
CoroutineHelper.Deferred(RegisterElinEventAttributes);
}
private static void OnSourceImporting()
{
if (ModManagerCore.enableSheetLoading)
{
ImportAllModSourceSheets();
}
ImportAllModSourceSheets();
}
private static void OnSourceImported()private static void OnSourceImported()
catch (Exception ex)
{
LogModError("exception while generating custom source profiles\n" + ex.Message, activatedUserMod);
UnityEngine.Debug.LogError(ex);
UnityEngine.Debug.LogException(ex);
}
}
ImportAllGunEffectSettings();
CustomReligionContent.managed.Clear();
foreach (CustomReligionContent item2 in _customContent.Values.OfType<CustomReligionContent>())
{
item2.RegisterCustomReligion();
}
CustomReligionContent.Init();
SourceCache.FinalizeCache();
SourceCache.InvalidateCacheBlobs();
SourceCache.ClearDetail();
if (EClass.core.launchArgs.Contains("EXPORTSOURCE"))
{
string text = CorePath.rootExe + "/SourceExport/" + EClass.core.version.GetText();
ExportAllSourceDataCsv(text);
UnityEngine.Debug.Log("#source exported current version to " + text);
}
}
[ElinPreLoad]
private static void OnPreLoadInit(GameIOContext context)
{
}
[ElinPostLoad]
private static void OnPostLoadInit(GameIOContext context)
{
EClass.player.knownBGMs.RemoveWhere((int id) => !EClass.core.refs.dictBGM.ContainsKey(id));void LoadCustomContent<T>() where T : class, ICustomContent
catch (Exception ex2)
{
LogModError("exception while loading custom content '" + item.ContentId + "'\n" + ex2.Message, item.Owner);
UnityEngine.Debug.LogError(ex2);
UnityEngine.Debug.LogException(ex2);
}
}
} catch (Exception ex)
{
LogModError("exception while loading custom content '" + item2.ContentId + "'\n" + ex.Message, item2.Owner);
UnityEngine.Debug.LogError(ex);
UnityEngine.Debug.LogException(ex);
}
}
}
}
[ElinPreSave]
private static void OnPreSaveInit(GameIOContext context)
{
}
[ElinPostSave]
private static void OnPostSaveInit(GameIOContext context)
{
CustomReligionContent.SaveReligionData(context);private static void OnPostSaveInit(GameIOContext context)
catch (Exception ex)
{
LogModError("exception while saving custom content '" + value.ContentId + "'\n" + ex.Message, value.Owner);
UnityEngine.Debug.LogError(ex);
UnityEngine.Debug.LogException(ex);
}
}
}private static void OnReligionImporting(List<Religion> list)
list.AddRange(CustomReligionContent.GetCustomReligions());
}
[ElinCharaOnCreate]
private static void OnCharaCreated(Chara chara)
{
if (TryGetContent<CustomCharaContent>("Chara/" + chara.id, out var content))private static void OnCharaCreated(Chara chara)
}
}
[ElinThingOnCreate]
private static void OnThingCreated(Thing thing)
{
if (TryGetContent<CustomThingContent>("Thing/" + thing.id, out var content))private static void OnThingCreated(Thing thing)
}
}
[ElinActPerform]
private static void OnActPerformed(Act act)
{
if (act.HasTag("godAbility"))private static void OnSetLang(string lang)
PackageIterator.ClearCache();
PackageIterator.RebuildAllMappings(lang);
SourceLocalization.SetLang(lang);
if (ModManagerCore.generateLocalizations)
foreach (EMod activatedUserMod in ModManager.Instance.ActivatedUserMods)
{
foreach (EMod activatedUserMod in ModManager.Instance.ActivatedUserMods)
if (activatedUserMod.IsSourceLocalizable && (activatedUserMod.isInPackages || Application.isEditor))
{
if (activatedUserMod.IsSourceLocalizable && (activatedUserMod.isInPackages || Application.isEditor))
{
activatedUserMod.UpdateSourceLocalizationFile(lang);
}
activatedUserMod.UpdateSourceLocalizationFile(lang);
}
ModManagerCore.generateLocalizations = false;
}
foreach (string item in LoadGodTalk())
{
MOD.listGodTalk.Add(new ExcelData(item));
}
foreach (string item2 in LoadCharaTalk())
{
MOD.listTalk.Add(new ExcelData(item2));
}
foreach (string item3 in LoadCharaTone())
{
MOD.tones.Add(new ExcelData(item3));
}
BookList.dict = null;
BottleMessageList.list = null;
Lang.excelDialog = null;
foreach (CustomFileContent item2 in _customContent.Values.OfType<CustomFileContent>())
foreach (CustomFileContent item4 in _customContent.Values.OfType<CustomFileContent>())
{
item2.OnSetLang(lang);
item4.OnSetLang(lang);
}
}public static bool HasContent(string contentId)
public static void AddContent(ICustomContent content)
{
UnityEngine.Debug.Log(_customContent.Remove(content.ContentId, out var value) ? ("#mod-content override '" + content.ContentId + "' '" + value.Owner.id + "' -> '" + content.Owner.id + "'") : ("#mod-content added '" + content.ContentId + "' from '" + content.Owner.id + "'"));
UnityEngine.Debug.Log(_customContent.Remove(content.ContentId, out var value) ? ("#mod-content override '" + content.ContentId + "' from '" + value.Owner.id + "' to '" + content.Owner.id + "'") : ("#mod-content added '" + content.ContentId + "' from '" + content.Owner.id + "'"));
_customContent[content.ContentId] = content;
}public static List<Thing> GenerateMerchantStock(Card owner, string stockId = nul
return list;
}
public static Sprite AppendSpriteSheet(string id, int resizeWidth = 0, int resizeHeight = 0, string pattern = "@")
public static void RegisterElinEventAttributes()
{
Dictionary<string, string> dictModItems = SpriteReplacer.dictModItems;
if (!dictModItems.TryGetValue(id, out var value) && pattern != "")
{
value = dictModItems.Where((KeyValuePair<string, string> kv) => kv.Key.StartsWith(pattern)).FirstOrDefault((KeyValuePair<string, string> kv) => id.StartsWith(kv.Key[pattern.Length..])).Value;
}
string spritePath = value;
string name = id;
Sprite sprite = LoadSprite(spritePath, null, name, resizeWidth, resizeHeight);
if (sprite == null)
{
return null;
}
if (SpriteSheet.dict.TryGetValue(id, out var value2) && value2.texture.width == sprite.texture.width && value2.texture.height == sprite.texture.height)
ClassCache.modTypes.Add(typeof(ModUtil));
ClassCache.modTypes.Add(typeof(CustomDramaExpansion));
foreach (var item3 in ClassCache.modTypes.Except(_checkedAttributedTypes).MembersWith<ElinEventBaseAttribute>())
{
return value2;
MemberInfo item = item3.member;
ElinEventBaseAttribute[] item2 = item3.attrs;
foreach (ElinEventBaseAttribute elinEventBaseAttribute in item2)
{
try
{
if (!(item is PropertyInfo property))
{
if (item is MethodInfo method)
{
elinEventBaseAttribute.Register(method);
}
}
else
{
elinEventBaseAttribute.Register(property);
}
}
catch (Exception ex)
{
LogModError("exception while registering attribute '" + elinEventBaseAttribute.GetType().Name + "' from '" + item.TryToString() + "'\n" + ex.Message, item.DeclaringType);
UnityEngine.Debug.LogException(ex);
}
}
}
return SpriteSheet.dict[sprite.name] = sprite;
_checkedAttributedTypes.UnionWith(ClassCache.modTypes);
}
public static List<string> LoadBookList()public static List<string> LoadBookList()
foreach (DirectoryInfo directoryInfo in directories)
{
list.AddRange(Directory.GetDirectories(directoryInfo.FullName));
UnityEngine.Debug.Log("#book list loaded " + directoryInfo.ShortPath());
UnityEngine.Debug.Log("#mod-content loaded book list " + directoryInfo.ShortPath());
}
return list;
}public static List<string> LoadTopicFiles()
foreach (FileInfo fileInfo in files)
{
list.AddRange(IO.LoadTextArray(fileInfo.FullName));
UnityEngine.Debug.Log("#book topic loaded " + fileInfo.ShortPath());
UnityEngine.Debug.Log("#mod-content loaded book topics " + fileInfo.ShortPath());
}
return list;
}public static List<string> LoadExcelDialog()
foreach (FileInfo fileInfo in files)
{
list.Add(fileInfo.FullName);
UnityEngine.Debug.Log("#dialog loaded " + fileInfo.ShortPath());
UnityEngine.Debug.Log("#mod-content loaded dialog " + fileInfo.ShortPath());
}
return list;
}
public static List<string> LoadCharaTalk()
{
List<string> list = new List<string>();
FileInfo[] files = PackageIterator.GetFiles("Data/chara_talk.xlsx");
foreach (FileInfo fileInfo in files)
{
list.Add(fileInfo.FullName);
UnityEngine.Debug.Log("#mod-content loaded chara tone " + fileInfo.ShortPath());
}
return list;
}
public static List<string> LoadCharaTone()
{
List<string> list = new List<string>();
FileInfo[] files = PackageIterator.GetFiles("Data/chara_tone.xlsx");
foreach (FileInfo fileInfo in files)
{
list.Add(fileInfo.FullName);
UnityEngine.Debug.Log("#mod-content loaded chara talk " + fileInfo.ShortPath());
}
return list;
}public static Sprite LoadSprite(string spritePath, Vector2? pivot = null, string
}
catch (Exception arg)
{
UnityEngine.Debug.LogError($"#sprite failed to load {spritePath.ShortPath()}\n{arg}");
UnityEngine.Debug.LogError($"#mod-content failed to load sprite {spritePath.ShortPath()}\n{arg}");
return null;
}
Texture2D texture2D2 = _cachedTextures[text];public static Sprite LoadSprite(string spritePath, Vector2? pivot = null, string
return sprite;
}
public static Sprite AppendSpriteSheet(string id, int resizeWidth = 0, int resizeHeight = 0, string pattern = "@")
{
Dictionary<string, string> dictModItems = SpriteReplacer.dictModItems;
if (!dictModItems.TryGetValue(id, out var value) && pattern != "")
{
value = dictModItems.Where((KeyValuePair<string, string> kv) => kv.Key.StartsWith(pattern)).FirstOrDefault((KeyValuePair<string, string> kv) => id.StartsWith(kv.Key[pattern.Length..])).Value;
}
string spritePath = value;
string name = id;
Sprite sprite = LoadSprite(spritePath, null, name, resizeWidth, resizeHeight);
if (sprite == null)
{
return null;
}
if (SpriteSheet.dict.TryGetValue(id, out var value2) && value2.texture.width == sprite.texture.width && value2.texture.height == sprite.texture.height)
{
return value2;
}
return SpriteSheet.dict[sprite.name] = sprite;
}
public static List<string> LoadGodTalk()
{
List<string> list = new List<string>();public static List<string> LoadGodTalk()
foreach (FileInfo fileInfo in files)
{
list.Add(fileInfo.FullName);
UnityEngine.Debug.Log("#god-talk loaded " + fileInfo.ShortPath());
UnityEngine.Debug.Log("#mod-content loaded god talk " + fileInfo.ShortPath());
}
return list;
}
public static Dictionary<string, CustomGunEffectData> LoadGunEffects()
{
Dictionary<string, CustomGunEffectData> dictionary = new Dictionary<string, CustomGunEffectData>();
(FileInfo, EMod)[] filesEx = PackageIterator.GetFilesEx("Data/EffectSetting.guns.json");
for (int i = 0; i < filesEx.Length; i++)
{
(FileInfo, EMod) tuple = filesEx[i];
FileInfo item = tuple.Item1;
EMod item2 = tuple.Item2;
CustomGunEffectSetting customGunEffectSetting = CustomGunEffectSetting.CreateFromFile(item, item2 as ModPackage);
_customContent[customGunEffectSetting.ContentId] = customGunEffectSetting;
}
foreach (CustomGunEffectSetting item3 in _customContent.Values.OfType<CustomGunEffectSetting>())
{
item3.Load();
dictionary.Merge(item3.items);
UnityEngine.Debug.Log($"#mod-content loaded {item3}");
}
return dictionary;
}
public static void ImportAllGunEffectSettings()
{
foreach (KeyValuePair<string, CustomGunEffectData> item in LoadGunEffects())
{
item.Deconstruct(out var key, out var value);
string key2 = key;
GameSetting.EffectData value2 = value.CreateEffectData();
EClass.setting.effect.guns[key2] = value2;
}
}
public static string ExportAllGunEffectSettings()
{
UD_String_EffectData guns = EClass.setting.effect.guns;
string text = CorePath.rootExe + "/guns.json";
Dictionary<string, CustomGunEffectData> dictionary = new Dictionary<string, CustomGunEffectData>();
foreach (string key in guns.Keys)
{
CustomGunEffectData value = CustomGunEffectData.CreateFromId(key);
dictionary[key] = value;
}
File.WriteAllText(text, JsonConvert.SerializeObject(dictionary, Formatting.Indented, GameIOContext.Settings));
return $"dumped {dictionary.Count} guns data to {text}";
}
private static Effect LoadEffect(string id)
{
if (id.IsEmpty())
{
return null;
}
if (!_rodTemplate)
{
return null;
}
string effectId = id.Split('/')[^1];
Sprite sprite = LoadSprite(effectId);
if (!sprite)
{
return null;
}
Effect effect = UnityEngine.Object.Instantiate(_rodTemplate);
effect.name = effectId;
effect.sprites = Slice().ToArray();
UnityEngine.Object.DontDestroyOnLoad(effect);
UnityEngine.Debug.Log("#mod-content loaded custom effect '" + effectId + "'");
return effect;
IEnumerable<Sprite> Slice()
{
int height = (int)sprite.rect.height;
float frames = sprite.rect.width / (float)height;
if (frames != 0f)
{
int i = 0;
while ((float)i < frames)
{
Sprite sprite2 = Sprite.Create(rect: new Rect(i * height, 0f, height, height), texture: sprite.texture, pivot: new Vector2(0.5f, 0.5f * (128f / (float)height)), pixelsPerUnit: 100f, extrude: 0u, meshType: SpriteMeshType.FullRect);
sprite2.name = $"{effectId}{i:D4}";
yield return sprite2;
int num = i + 1;
i = num;
}
}
}
}
private static void LoadEffectTemplate()
{
_rodTemplate = Resources.Load<Effect>("Media/Effect/General/rod");
if (!_rodTemplate)
{
UnityEngine.Debug.LogWarning("#mod-content cannot initialize rod effect template");
}
}
public static SerializableSoundData GetSoundMeta(string soundPath)
{
string path = Path.ChangeExtension(soundPath, ".json");public static void ImportModSourceSheets(string modId)
list.Add(sourceSheet.FullName);
}
sourceImporter.ImportFilesCached(list);
if (ModManagerCore.enableSheetCaching)
{
SourceCache.FinalizeCache();
}
SourceCache.InvalidateCacheBlobs();
SourceCache.ClearDetail();
UnityEngine.Debug.Log("#source finished importing workbooks from " + modId);
}
catch (Exception exception)public static void ImportAllModSourceSheets()
}
}
sourceImporter.ImportFilesCached(list);
if (ModManagerCore.enableSheetCaching)
{
SourceCache.FinalizeCache();
}
SourceCache.InvalidateCacheBlobs();
SourceCache.ClearDetail();
}
catch (Exception message)
catch (Exception exception)
{
UnityEngine.Debug.LogError(message);
UnityEngine.Debug.LogException(exception);
}
UnityEngine.Debug.Log("#source finished importing workbooks");
}public static string ExportSourceDataCsv(string sourceData, string delimiter = "
return "";
}
IReadOnlyDictionary<string, string> typeMapping = sourceData2.GetTypeMapping();
IReadOnlyDictionary<string, int> rowMapping = sourceData2.GetRowMapping();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine(string.Join(delimiter, rowMapping.Keys));
stringBuilder.AppendLine(string.Join(delimiter, rowMapping.Keys.Select((string k) => typeMapping[k])));
(string, string)[] array = (from kv in rowMapping
(string, string)[] array = (from kv in sourceData2.GetRowMapping()
orderby kv.Value
select (Key: kv.Key, typeMapping[kv.Key])).ToArray();
select (column: kv.Key, type: typeMapping[kv.Key])).ToArray();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine(string.Join(delimiter, array.Select(((string column, string type) p) => p.column)));
stringBuilder.AppendLine(string.Join(delimiter, array.Select(((string column, string type) p) => p.type)));
SourceData.BaseRow[] array2 = sourceData2.ExportRows();
foreach (SourceData.BaseRow baseRow in array2)
{ enumerable = obj as IEnumerable;
if (enumerable != null)
{
goto IL_0221;
goto IL_024a;
}
}
else if (item2 == "element_id") if (!(item2 == "elements"))
{
enumerable = (IEnumerable)obj;
goto IL_0221;
goto IL_024a;
}
List<string> list2 = new List<string>();
for (int l = 0; l < array4.Length - 1; l += 2)
for (int k = 0; k < array4.Length - 1; k += 2)
{
string alias = EClass.sources.elements.map[array4[l]].alias;
string text = array4[l + 1].ToString();
string alias = EClass.sources.elements.map[array4[k]].alias;
string text = array4[k + 1].ToString();
list2.Add(alias + "/" + text);
}
string item4 = string.Join(',', list2);
list.Add(item4);
continue;
IL_0221:
IL_024a:
string item5 = string.Join(',', enumerable.OfType<object>());
list.Add(item5);
}
stringBuilder.AppendLine(string.Join(delimiter, list.Select((string f) => "\"" + f.RemoveNewline() + "\"")));
IEnumerable<string> values = list.Select(delegate(string f)
{
string text2 = f.Replace("\r", "").Replace("\n", "\\n").Replace("\"", "\"\"");
return (!text2.IsEmpty()) ? ("\"" + text2 + "\"") : "";
});
stringBuilder.AppendLine(string.Join(delimiter, values));
}
return stringBuilder.ToString();
}public static void ExportAllSourceDataJson(string dir)
File.WriteAllText(Path.Combine(dir, key + ".json"), ExportSourceDataJson(key));
}
}
public static void AddContextMenuEntry(Action onClick, string menuEntry, string displayName = "")
{
if (onClick == null || menuEntry.IsEmpty())
{
return;
}
string[] array = menuEntry.Split('/', StringSplitOptions.RemoveEmptyEntries);
List<ContextMenuProxy> children = contextMenuProxies;
for (int i = 0; i < array.Length; i++)
{
bool flag = i < array.Length - 1;
string part = array[i];
ContextMenuProxy contextMenuProxy = children.Find((ContextMenuProxy p) => p.MenuEntry == part);
if (contextMenuProxy == null)
{
contextMenuProxy = new ContextMenuProxy(part, flag ? part : displayName)
{
onClick = ((i == array.Length - 1 && flag) ? null : new Action(SafeInvoke)),
isMenu = flag
};
children.Add(contextMenuProxy);
}
else if (contextMenuProxy.isMenu != flag)
{
UnityEngine.Debug.LogWarning("#mod-content attempt to add context menu entry with same name but different types\n" + part + " -> " + (contextMenuProxy.isMenu ? "submenu" : "button"));
return;
}
children = contextMenuProxy.children;
}
UnityEngine.Debug.Log("#mod-content added context menu entry '" + menuEntry + "' from '" + onClick.Method.TryToString() + "'");
void SafeInvoke()
{
try
{
onClick();
}
catch (Exception exception)
{
UnityEngine.Debug.LogException(exception);
}
}
}
public static void RemoveContextMenuEntry(string entry)
{
string[] array = entry.Split('/', StringSplitOptions.RemoveEmptyEntries);
if (array.Length == 0)
{
return;
}
List<ContextMenuProxy> children = contextMenuProxies;
ContextMenuProxy contextMenuProxy = null;
List<ContextMenuProxy> list = null;
string[] array2 = array;
foreach (string part in array2)
{
contextMenuProxy = children.Find((ContextMenuProxy p) => p.MenuEntry == part);
if (contextMenuProxy == null)
{
return;
}
list = children;
children = contextMenuProxy.children;
}
list?.Remove(contextMenuProxy);
}
}Point โ
public override string ToString()
return "(" + x + " / " + z + ")";
}
public static Point operator +(Point lhs, Point rhs)
{
return new Point(lhs.x + rhs.x, lhs.z + rhs.z);
}
public void Set(Vector3 v)
{
v.x -= 0.64f;Props โ
weight -= t.Num;
all.Remove(t);
things.Remove(t.Thing);
cardMap[t.id].Remove(t);
cardMap.TryGetValue(t.id)?.Remove(t);
if (t.sourceCard.origin != null)
{
cardMap[t.sourceCard.origin.id].Remove(t);
cardMap.TryGetValue(t.sourceCard.origin.id)?.Remove(t);
}
categoryMap[t.category.id].Remove(t);
if (!t.Thing.source.workTag.IsEmpty())QuestDeliver โ
public class QuestDeliver : QuestDestZone
public virtual bool ConsumeGoods => false;
public SourceThing.Row sourceThing => EClass.sources.things.map[idThing.IsEmpty("generator_snowman")];
public SourceThing.Row sourceThing => EClass.sources.things.map.TryGetValue(idThing.IsEmpty("generator_snowman"), "generator_snowman");
public override string NameDeliver => sourceThing.GetName();public virtual bool IsDestThing(Thing t)
if (t.c_altName.IsEmpty())
{
string name = sourceThing.GetName();
if (t.source.GetName() == name || t.GetName(NameStyle.Simple, 1) == name)
try
{
return true;
if (t.source.GetName() == name || t.GetName(NameStyle.Simple, 1) == name)
{
return true;
}
}
catch
{
return false;
}
}
}RecipeCard โ
public override void Build(TaskBuild task)
}
else
{
card = ThingGen.Create(idCard, -1, Mathf.Max(EClass._zone.DangerLv, EClass.pc.LV));
CardBlueprint.Set(new CardBlueprint
{
rarity = Rarity.Normal,
isCraft = true
});
card = ThingGen.Create(idCard);
if (!card.IsUnique)
{
card.ChangeMaterial(GetMainMaterial());RecipeManager โ
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using UnityEngine;public static void Create(RenderRow row, string type, string suffix = "")
list.Add(recipeSource);
dict[recipeSource.id] = recipeSource;
_ = row.components;
Recipe.Create(recipeSource).BuildIngredientList();
try
{
Recipe.Create(recipeSource).BuildIngredientList();
}
catch (Exception ex)
{
list.Remove(recipeSource);
dict.Remove(recipeSource.id);
Debug.LogWarning($"Failed to create recipe '{row.RecipeID}' '{type}{suffix}'\n{ex}");
}
}
public static RecipeSource Get(string id)Religion โ
public virtual bool TryGetGift()
public virtual void OnReforge(Thing t)
{
t.c_idDeity = id;
if (IsIgnoreReforge(t))
{
return;
}
foreach (Element value in t.elements.dict.Values)
{
if (IsFaithElement(value))
int num = value.id;
if ((uint)(num - 64) > 3u && IsFaithElement(value))
{
value.vExp = -1;
}
}
}
public virtual bool IsIgnoreReforge(Thing t)
{
return false;
}
public virtual bool IsValidArtifact(string id)
{
return false;ReligionMachine โ
public class ReligionMachine : Religion
{
public override string id => "machine";
public override void OnReforge(Thing t)
public override bool IsIgnoreReforge(Thing t)
{
t.c_idDeity = id;
if (t.id == "gun_mani")
{
return;
}
foreach (Element value in t.elements.dict.Values)
{
if (IsFaithElement(value))
{
value.vExp = -1;
}
}
return t.id == "gun_mani";
}
public override bool IsValidArtifact(string id)ReligionWind โ
public class ReligionWind : Religion
{
public override string id => "wind";
public override void OnReforge(Thing t)
public override bool IsIgnoreReforge(Thing t)
{
t.c_idDeity = id;
if (t.id == "windbow")
{
return;
}
foreach (Element value in t.elements.dict.Values)
{
if (IsFaithElement(value))
{
value.vExp = -1;
}
}
return t.id == "windbow";
}
public override bool IsValidArtifact(string id)SourceManager โ
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine; keyItems.Init();
ACT.Init();
TimeTable.Init();
List<SourceElement.Row> listAttackElements = Element.ListAttackElements;
listAttackElements.Clear();
for (int j = 910; j < 927; j++)
{
listAttackElements.Add(EMono.sources.elements.map[j]);
}
Element.ListAttackElements.Clear();
Element.ListAttackElements.AddRange(EMono.sources.elements.rows.Where((SourceElement.Row r) => r.categorySub == "eleAttack"));
BaseModManager.PublishEvent("elin.source.imported");
}SourceMaterial โ
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class SourceMaterial : SourceDataInt<SourceMaterial.Row>public override void OnImportData(SourceData data)
public void Init()
{
MatColors matColors = Core.Instance.Colors.matColors.TryGetValue(alias);
HashSet<string> hashSet = new HashSet<string>(tag) { alias };
if (matColors == null)
{
matColors = new MatColors();
string[] array = tag;
for (int i = 0; i < array.Length; i++)
foreach (string item in hashSet)
{
var (text, s, _) = CustomSourceContent.GetParams(array[i]);
var (text, s, _) = CustomSourceContent.GetParams(item);
switch (text)
{
case "addCol_Main": }
matColor = matColors.main;
altColor = matColors.alt;
tag = hashSet.ToArray();
SetTiles();
}TCUI โ
public override void OnDraw(ref Vector3 pos)
lastPos = _pos;
Vector3 position = Camera.main.WorldToScreenPoint(_pos);
position.z = 0f;
position += FixPos * EMono.screen.Zoom;
Vector3 vector = FixPos;
if (render.hasActor && !render.actor.isPCC && (bool)render.actor && (bool)render.actor.sr.sprite)
{
float num = 128f / render.actor.sr.sprite.rect.height;
int pivotY = render.owner.Pref.pivotY;
vector = FixPos + new Vector3(0f, num * ((float)pivotY - 48f), 0f);
}
position += vector * EMono.screen.Zoom;
_rect.position = position;
}
});TraitAdventurerCustom โ
public class TraitAdventurerCustom : TraitAdventurerBacker
public class TraitAdventurerCustom : TraitAdventurerBacker
{
public override Adv_Type AdvType => Adv_Type.Adv_Custom;
public override ShopType ShopType => ShopType.CustomContent;
}Zone_Tent โ
public override bool IsUnderwater => elements.Has(3606);
public override int DangerLv => 1;
public override ZoneTransition.EnterState RegionEnterState => ZoneTransition.EnterState.Bottom;
public override void OnBeforeDeactivate()