using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using GlobalSettings;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace HKSilksong_Randomizer
{
[BepInPlugin("com.yourname.mysilksongmod", "HKSilksong_Randomizer", "0.5.5")]
public class HKS_Randomizer : BaseUnityPlugin
{
private class PickupMessage
{
public string Text;
public float Time;
public PickupMessage(string t, float time)
{
Text = t;
Time = time;
}
}
[CompilerGenerated]
private sealed class <CheckAndApplyMaskShardsIfReset>d__38 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public HKS_Randomizer <>4__this;
private int <tries>5__1;
private PlayerData <pd>5__2;
private int <shards>5__3;
private int <expectedHealthUpgrades>5__4;
private int <expectedHeartPieces>5__5;
private int <expectedMaxHealth>5__6;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <CheckAndApplyMaskShardsIfReset>d__38(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<pd>5__2 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<tries>5__1 = 300;
goto IL_0051;
case 1:
<>1__state = -1;
goto IL_0051;
case 2:
{
<>1__state = -1;
<pd>5__2 = PlayerData.instance;
if (<pd>5__2.maxHealth == 5 && <pd>5__2.heartPieces == 0 && upgradesGivenCount.TryGetValue("Mask Shard", out <shards>5__3) && <shards>5__3 > 0)
{
<expectedHealthUpgrades>5__4 = <shards>5__3 / 4;
<expectedHeartPieces>5__5 = <shards>5__3 % 4;
<expectedMaxHealth>5__6 = 5 + <expectedHealthUpgrades>5__4;
<pd>5__2.maxHealth = <expectedMaxHealth>5__6;
<pd>5__2.maxHealthBase = <expectedMaxHealth>5__6;
<pd>5__2.health = Mathf.Min(<pd>5__2.health, <pd>5__2.maxHealth);
<pd>5__2.heartPieces = <expectedHeartPieces>5__5;
ToolItemManager.SendEquippedChangedEvent(true);
Log.LogInfo((object)$"[MASK PERSIST] Detected reset stats (5/0), reapplied {<shards>5__3} mask shards: maxHealth={<pd>5__2.maxHealth}, heartPieces={<pd>5__2.heartPieces}");
}
return false;
}
IL_0051:
if (PlayerData.instance == null && <tries>5__1-- > 0)
{
<>2__current = null;
<>1__state = 1;
return true;
}
if (PlayerData.instance == null)
{
return false;
}
<>2__current = (object)new WaitForSeconds(0.5f);
<>1__state = 2;
return true;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <RefreshSilkUI>d__53 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public HKS_Randomizer <>4__this;
private SilkSpool <silkSpool>5__1;
private Exception <e>5__2;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <RefreshSilkUI>d__53(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<silkSpool>5__1 = null;
<e>5__2 = null;
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = null;
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
try
{
<silkSpool>5__1 = SilkSpool.Instance ?? GameCameras.instance?.silkSpool;
if ((Object)(object)<silkSpool>5__1 != (Object)null)
{
<silkSpool>5__1.DrawSpool();
Log.LogInfo((object)"Refreshed silk spool HUD (delayed)");
}
else
{
Log.LogWarning((object)"SilkSpool instance not found - silk UI may not refresh");
}
<silkSpool>5__1 = null;
}
catch (Exception ex)
{
<e>5__2 = ex;
Log.LogError((object)("Error refreshing silk UI: " + <e>5__2.Message));
}
return false;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
private static ManualLogSource Log;
private static CollectableItem[] memorizedCollectables;
private static ToolItem[] memorizedTools;
private static ToolCrest[] memorizedCrests;
internal static ShopOwner[] memorizedShopOwners;
private static string[] availablePowerups = new string[7] { "hasDoubleJump", "hasChargeSlash", "hasSuperJump", "hasWalljump", "hasBrolly", "hasDash", "hasNeedolin" };
private static string[] availableMaps = new string[28]
{
"HasMossGrottoMap", "HasWildsMap", "HasBoneforestMap", "HasDocksMap", "HasGreymoorMap", "HasBellhartMap", "HasShellwoodMap", "HasCrawlMap", "HasHuntersNestMap", "HasJudgeStepsMap",
"HasDustpensMap", "HasSlabMap", "HasPeakMap", "HasCitadelUnderstoreMap", "HasCoralMap", "HasSwampMap", "HasCloverMap", "HasAbyssMap", "HasHangMap", "HasSongGateMap",
"HasHallsMap", "HasWardMap", "HasCogMap", "HasLibraryMap", "HasCradleMap", "HasArboriumMap", "HasAqueductMap", "HasWeavehomeMap"
};
private static Dictionary<string, int> availableUpgrades = new Dictionary<string, int>
{
{ "Mask Shard", 20 },
{ "Spool Fragment", 18 },
{ "Silk Heart", 3 }
};
private static Dictionary<string, int> upgradesGivenCount = new Dictionary<string, int>();
public static bool itemsMemorized = false;
private static HashSet<string> givenItems = new HashSet<string>();
private static List<string> givenItemsInOrder = new List<string>();
private static string givenItemsFilePath;
private static string randomizedShopsFilePath;
internal static Dictionary<string, List<(string itemName, int originalCost)>> randomizedShops = new Dictionary<string, List<(string, int)>>();
internal static Dictionary<string, int> shopItemPool = new Dictionary<string, int>();
private static Dictionary<string, int> bulkItemQuantities = new Dictionary<string, int>
{
{ "Song Pilgrim Cloak", 99 },
{ "Enemy Morsel Speared", 99 },
{ "Pins", 99 },
{ "Shell Flower", 99 },
{ "Enemy Morsel Seared", 99 },
{ "Roach Corpse Item", 99 },
{ "Enemy Morsel Shredded", 99 },
{ "Fine Pin", 99 },
{ "Pilgrim Rag", 99 },
{ "Rock Roller Item", 99 },
{ "Common Spine", 99 },
{ "Crow Feather", 99 },
{ "Silver Bellclapper", 99 },
{ "Plasmium Blood", 99 },
{ "Plasmium", 99 },
{ "Simple Key", 4 },
{ "Rosary_Set_Large", 5 },
{ "Cog Heart Pieces", 3 },
{ "Rosary_Set_Huge_White", 5 },
{ "Crest Socket Unlocker", 20 },
{ "Tool Pouch&Kit Inv", 8 },
{ "Shard Pouch", 4 },
{ "Pale_Oil", 4 },
{ "Rosary_Set_Frayed", 5 },
{ "Rosary_Set_Small", 5 },
{ "Rosary_Set_Medium", 5 },
{ "Tool Metal", 8 },
{ "Silk Grub", 10 },
{ "Slab Key", 1 },
{ "R Seal chit", 4 },
{ "R Weaver Totem", 3 },
{ "R Bone Record", 4 },
{ "R Weaver Record", 3 },
{ "R Ancient Egg", 1 },
{ "R Psalm Cylinder", 5 },
{ "R Librarian Melody Cylinder", 1 },
{ "Silk Snare", 1 },
{ "Snare Soul Swamp Bug", 1 }
};
private static Dictionary<string, int> bulkItemGivenCount = new Dictionary<string, int>();
private static Dictionary<string, int> bulkItemFailedAttempts = new Dictionary<string, int>();
private static Dictionary<string, int> bulkItemPityThreshold = new Dictionary<string, int>
{
{ "Common Spine", 9 },
{ "Pilgrim Rag", 14 },
{ "Rock Roller Item", 19 },
{ "Slab Key", 23 },
{ "Silver Bellclapper", 24 },
{ "Shell Flower", 27 },
{ "Crow Feather", 29 },
{ "Simple Key", 31 },
{ "Roach Corpse Item", 33 },
{ "Plasmium", 35 },
{ "Fine Pin", 41 },
{ "R Librarian Melody Cylinder", 44 },
{ "Song Pilgrim Cloak", 47 },
{ "Enemy Morsel Speared", 49 },
{ "Enemy Morsel Shredded", 54 },
{ "Enemy Morsel Seared", 59 },
{ "White Key", 64 },
{ "Snare Soul Swamp Bug", 67 },
{ "Silk Snare", 70 },
{ "Plasmium Blood", 71 }
};
private List<PickupMessage> _recentPickupMessages = new List<PickupMessage>();
private const int kMaxPickupMessages = 10;
private const float kPickupMessageDuration = 10f;
public static HKS_Randomizer Instance { get; private set; }
private void ShowInGamePickup(string text)
{
try
{
_recentPickupMessages.Add(new PickupMessage(text, Time.time));
if (_recentPickupMessages.Count > 10)
{
_recentPickupMessages.RemoveAt(0);
}
}
catch
{
}
}
private void SyncCrossCategoryOnGive(int givenItemType, string name)
{
try
{
if (givenItemType == 0 && memorizedTools != null && memorizedTools.Any((ToolItem t) => (Object)(object)t != (Object)null && t.name == name) && !givenItems.Contains("ToolItem: " + name))
{
givenItems.Add("ToolItem: " + name);
givenItemsInOrder.Add("ToolItem: " + name);
Log.LogInfo((object)("Sync: marked ToolItem '" + name + "' as given because collectable was given"));
}
if (givenItemType == 1 && memorizedCollectables != null && memorizedCollectables.Any((CollectableItem c) => (Object)(object)c != (Object)null && ((Object)c).name == name) && !givenItems.Contains("CollectableItem: " + name))
{
givenItems.Add("CollectableItem: " + name);
givenItemsInOrder.Add("CollectableItem: " + name);
Log.LogInfo((object)("Sync: marked CollectableItem '" + name + "' as given because Tool was given"));
}
}
catch (Exception ex)
{
Log.LogError((object)("Error in SyncCrossCategoryOnGive for '" + name + "': " + ex.Message));
}
}
private void OnGUI()
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Expected O, but got Unknown
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Expected O, but got Unknown
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_0200: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_0130: Expected O, but got Unknown
//IL_019c: Unknown result type (might be due to invalid IL or missing references)
//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
try
{
if (_recentPickupMessages == null || _recentPickupMessages.Count == 0)
{
return;
}
int num = 420;
int num2 = 12;
float num3 = num2;
GUIStyle val = new GUIStyle(GUI.skin.box);
GUIStyle val2 = new GUIStyle(GUI.skin.label);
val2.fontSize = 20;
val2.fontStyle = (FontStyle)1;
val2.alignment = (TextAnchor)5;
val2.normal.textColor = Color.white;
val2.wordWrap = true;
val2.richText = true;
Color color = GUI.color;
Color color2 = default(Color);
((Color)(ref color2))..ctor(0f, 0f, 0f, 0.45f);
Color color3 = default(Color);
((Color)(ref color3))..ctor(0f, 0f, 0f, 0.75f);
Rect val4 = default(Rect);
Rect val5 = default(Rect);
Rect val6 = default(Rect);
for (int num4 = _recentPickupMessages.Count - 1; num4 >= 0; num4--)
{
PickupMessage pickupMessage = _recentPickupMessages[num4];
if (Time.time - pickupMessage.Time > 10f)
{
_recentPickupMessages.RemoveAt(num4);
}
else
{
GUIContent val3 = new GUIContent(pickupMessage.Text);
float num5 = val2.CalcHeight(val3, (float)num);
float num6 = 8f;
((Rect)(ref val4))..ctor((float)(Screen.width - num - num2 - 8), num3 - 6f, (float)(num + 16), num5 + num6);
((Rect)(ref val5))..ctor((float)(Screen.width - num - num2 + 1), num3 + 1f, (float)num, num5);
((Rect)(ref val6))..ctor((float)(Screen.width - num - num2), num3, (float)num, num5);
GUI.color = color2;
GUI.Box(val4, GUIContent.none, val);
GUI.color = color3;
GUI.Label(val5, val3, val2);
GUI.color = Color.white;
GUI.Label(val6, val3, val2);
num3 += num5 + 8f;
}
}
GUI.color = color;
}
catch
{
}
}
private bool CheckForPityItems(ref int itemType, ref string selectedName)
{
try
{
foreach (KeyValuePair<string, int> item in bulkItemPityThreshold)
{
string key = item.Key;
int value = item.Value;
if (!bulkItemQuantities.ContainsKey(key))
{
continue;
}
int num = (bulkItemGivenCount.ContainsKey(key) ? bulkItemGivenCount[key] : 0);
if (num >= bulkItemQuantities[key])
{
continue;
}
int num2 = (bulkItemFailedAttempts.ContainsKey(key) ? bulkItemFailedAttempts[key] : 0);
if (num2 >= value)
{
Log.LogInfo((object)$"Pity timer activated! Forcing {key} after {num2 + 1} attempts");
int num3 = DetermineItemType(key);
if (num3 != -1)
{
itemType = num3;
selectedName = key;
bulkItemFailedAttempts[key] = 0;
return true;
}
Log.LogWarning((object)("Could not determine type for pity item: " + key));
}
}
return false;
}
catch (Exception ex)
{
Log.LogError((object)("Error in pity timer check: " + ex.Message));
return false;
}
}
private int DetermineItemType(string itemName)
{
try
{
if (memorizedCollectables != null)
{
CollectableItem[] array = memorizedCollectables;
foreach (CollectableItem val in array)
{
if ((Object)(object)val != (Object)null && ((Object)val).name == itemName)
{
return 0;
}
}
}
if (memorizedTools != null)
{
ToolItem[] array2 = memorizedTools;
foreach (ToolItem val2 in array2)
{
if ((Object)(object)val2 != (Object)null && val2.name == itemName)
{
return 1;
}
}
}
if (memorizedCrests != null)
{
ToolCrest[] array3 = memorizedCrests;
foreach (ToolCrest val3 in array3)
{
if ((Object)(object)val3 != (Object)null && val3.name == itemName)
{
return 2;
}
}
}
return -1;
}
catch (Exception ex)
{
Log.LogError((object)("Error determining item type for " + itemName + ": " + ex.Message));
return -1;
}
}
private void UpdateFailedAttempts(int itemType, string selectedName)
{
try
{
foreach (KeyValuePair<string, int> item in bulkItemPityThreshold)
{
string key = item.Key;
if (!(selectedName == key) && bulkItemQuantities.ContainsKey(key))
{
int num = (bulkItemGivenCount.ContainsKey(key) ? bulkItemGivenCount[key] : 0);
if (num < bulkItemQuantities[key])
{
int num2 = (bulkItemFailedAttempts.ContainsKey(key) ? bulkItemFailedAttempts[key] : 0);
bulkItemFailedAttempts[key] = num2 + 1;
}
}
}
}
catch (Exception ex)
{
Log.LogError((object)("Error updating failed attempts: " + ex.Message));
}
}
private void Testing()
{
}
private void Awake()
{
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Expected O, but got Unknown
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
Log.LogInfo((object)"HKS Rando Awake()");
string text = Path.Combine(Paths.GameRootPath, "SilksongRandomizerData");
if (!Directory.Exists(text))
{
Directory.CreateDirectory(text);
}
givenItemsFilePath = Path.Combine(text, "given_items.txt");
randomizedShopsFilePath = Path.Combine(text, "randomized_shops.txt");
LoadGivenItems();
LoadRandomizedShops();
LoadShopItemPool();
Harmony val = new Harmony("com.yourname.mysilksongmod");
val.PatchAll();
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
((MonoBehaviour)this).StartCoroutine(CheckAndApplyMaskShardsIfReset());
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
[IteratorStateMachine(typeof(<CheckAndApplyMaskShardsIfReset>d__38))]
private IEnumerator CheckAndApplyMaskShardsIfReset()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <CheckAndApplyMaskShardsIfReset>d__38(0)
{
<>4__this = this
};
}
private void Update()
{
try
{
if (Input.GetKeyDown((KeyCode)288))
{
Log.LogInfo((object)"F7 pressed - Getting random item!");
GetRandomItem();
}
if (Input.GetKeyDown((KeyCode)289))
{
Log.LogInfo((object)"F8 pressed - Memorizing items and toggling crest!");
if (!itemsMemorized)
{
MemorizeAllItems();
}
ToggleCloaklessHunterCrest();
}
if (Input.GetKeyDown((KeyCode)290))
{
Log.LogInfo((object)"F9 pressed - Toggling silk soar crest!");
ToggleSilkSoar();
}
}
catch (Exception ex)
{
Log.LogError((object)("Error in Update(): " + ex.Message));
}
}
private void getRelicWithSameName(string relicDisplayName)
{
if (memorizedCollectables == null)
{
Log.LogWarning((object)"getRelicWithSameName: no memorizedCollectables");
return;
}
Log.LogInfo((object)("getRelicWithSameName: searching for '" + relicDisplayName + "'"));
CollectableItem[] array = memorizedCollectables;
foreach (CollectableItem val in array)
{
CollectableItemRelicType val2 = (CollectableItemRelicType)(object)((val is CollectableItemRelicType) ? val : null);
if (val2 == null || val2.Relics == null)
{
continue;
}
foreach (CollectableRelic relic in val2.Relics)
{
if ((Object)(object)relic == (Object)null)
{
continue;
}
try
{
if (!relic.IsInInventory && relic.DisplayName == relicDisplayName)
{
((SavedItem)relic).Get(true);
Log.LogInfo((object)("getRelicWithSameName: gave " + (relic.DisplayName ?? ((Object)relic).name)));
return;
}
}
catch (Exception ex)
{
Log.LogWarning((object)("getRelicWithSameName: inspect/give failed for '" + (((relic != null) ? ((Object)relic).name : null) ?? "<null>") + "': " + ex.Message));
}
}
}
givenItems.Add("CollectableItem: " + relicDisplayName);
givenItemsInOrder.Add("CollectableItem: " + relicDisplayName);
}
public void MemorizeAllItems()
{
try
{
memorizedCollectables = (CollectableItem[])(((object)Resources.FindObjectsOfTypeAll<CollectableItem>()?.Where((CollectableItem item) => (Object)(object)item != (Object)null && !string.IsNullOrEmpty(((Object)item).name)).ToArray()) ?? ((object)new CollectableItem[0]));
memorizedTools = (ToolItem[])(((object)Resources.FindObjectsOfTypeAll<ToolItem>()?.Where((ToolItem tool) => (Object)(object)tool != (Object)null && !string.IsNullOrEmpty(tool.name)).ToArray()) ?? ((object)new ToolItem[0]));
memorizedCrests = (ToolCrest[])(((object)Resources.FindObjectsOfTypeAll<ToolCrest>()?.Where((ToolCrest crest) => (Object)(object)crest != (Object)null && !string.IsNullOrEmpty(crest.name)).ToArray()) ?? ((object)new ToolCrest[0]));
memorizedShopOwners = (ShopOwner[])(((object)Resources.FindObjectsOfTypeAll<ShopOwner>()?.Where((ShopOwner owner) => (Object)(object)owner != (Object)null && ((ShopOwnerBase)owner).Stock != null && ((ShopOwnerBase)owner).Stock.Length != 0).ToArray()) ?? ((object)new ShopOwner[0]));
itemsMemorized = true;
ManualLogSource log = Log;
object[] array = new object[5];
CollectableItem[] array2 = memorizedCollectables;
array[0] = ((array2 != null) ? array2.Length : 0);
ToolItem[] array3 = memorizedTools;
array[1] = ((array3 != null) ? array3.Length : 0);
ToolCrest[] array4 = memorizedCrests;
array[2] = ((array4 != null) ? array4.Length : 0);
ShopOwner[] array5 = memorizedShopOwners;
array[3] = ((array5 != null) ? array5.Length : 0);
string[] array6 = availablePowerups;
array[4] = ((array6 != null) ? array6.Length : 0);
log.LogInfo((object)string.Format("Memorized {0} CollectableItems, {1} ToolItems, {2} ToolCrests, {3} ShopOwners, {4} powerups", array));
}
catch (Exception ex)
{
Log.LogError((object)("Error memorizing items: " + ex.Message));
itemsMemorized = false;
}
}
public void GetRandomItem()
{
try
{
if (!itemsMemorized)
{
MemorizeAllItems();
if (!itemsMemorized)
{
Log.LogError((object)"Failed to memorize items!");
return;
}
}
if (memorizedCollectables == null || memorizedTools == null || memorizedCrests == null)
{
Log.LogError((object)"Item arrays are null! Try pressing F8 again.");
return;
}
if (memorizedCollectables.Length == 0 && memorizedTools.Length == 0 && memorizedCrests.Length == 0)
{
Log.LogWarning((object)"No items found in memorized arrays! Giving currency instead.");
CurrencyManager.AddCurrency(100, (CurrencyType)0, true);
CurrencyManager.AddCurrency(100, (CurrencyType)1, true);
ShowInGamePickup("Text not intended to be shown");
return;
}
List<string> list = new List<string>();
List<string> list2 = new List<string>();
List<string> list3 = new List<string>();
List<string> list4 = new List<string>();
List<string> list5 = new List<string>();
Log.LogInfo((object)"=== BUILDING ITEM POOL ===");
Log.LogInfo((object)$"bulkItemGivenCount has {bulkItemGivenCount.Count} entries:");
foreach (KeyValuePair<string, int> item in bulkItemGivenCount)
{
Log.LogInfo((object)$" {item.Key}: {item.Value} given");
}
CollectableItem[] array = memorizedCollectables;
foreach (CollectableItem val in array)
{
if (!((Object)(object)val != (Object)null))
{
continue;
}
if (bulkItemQuantities.ContainsKey(((Object)val).name))
{
int num = (bulkItemGivenCount.ContainsKey(((Object)val).name) ? bulkItemGivenCount[((Object)val).name] : 0);
int num2 = bulkItemQuantities[((Object)val).name] - num;
Log.LogInfo((object)$"[BULK CHECK] {((Object)val).name}: maxQty={bulkItemQuantities[((Object)val).name]}, givenCount={num}, remaining={num2}");
if (num2 <= 0)
{
continue;
}
int num3 = bulkItemQuantities[((Object)val).name];
if (num3 >= 50)
{
list.Add(((Object)val).name);
Log.LogInfo((object)$"[BULK DEBUG] {((Object)val).name}: maxQty={num3}, given={num}, remaining={num2}, added 1x (bulk>=50)");
continue;
}
for (int j = 0; j < num2; j++)
{
list.Add(((Object)val).name);
}
Log.LogInfo((object)$"[BULK DEBUG] {((Object)val).name}: maxQty={num3}, given={num}, remaining={num2}, added {num2}x (remaining*5)");
}
else if (!givenItems.Contains("CollectableItem: " + ((Object)val).name))
{
list.Add(((Object)val).name);
}
}
ToolItem[] array2 = memorizedTools;
foreach (ToolItem val2 in array2)
{
if ((Object)(object)val2 != (Object)null && !givenItems.Contains("ToolItem: " + val2.name))
{
list2.Add(val2.name);
}
}
ToolCrest[] array3 = memorizedCrests;
foreach (ToolCrest val3 in array3)
{
if ((Object)(object)val3 != (Object)null && !givenItems.Contains("ToolCrest: " + val3.name))
{
list3.Add(val3.name);
}
}
string[] array4 = availablePowerups;
foreach (string text in array4)
{
if (!givenItems.Contains("Powerup: " + text))
{
PlayerData instance = PlayerData.instance;
if (instance != null && !instance.GetBool(text))
{
list4.Add(text);
}
}
}
string[] array5 = availableMaps;
foreach (string text2 in array5)
{
if (!givenItems.Contains("Map: " + text2))
{
PlayerData instance2 = PlayerData.instance;
if (instance2 != null && !instance2.GetBool(text2))
{
list5.Add(text2);
}
}
}
List<string> list6 = new List<string>();
foreach (KeyValuePair<string, int> availableUpgrade in availableUpgrades)
{
string key = availableUpgrade.Key;
int value = availableUpgrade.Value;
int num4 = (upgradesGivenCount.ContainsKey(key) ? upgradesGivenCount[key] : 0);
if (num4 < value)
{
int num5 = value - num4;
int num6 = Mathf.Min(num5, 41);
for (int num7 = 0; num7 < num6; num7++)
{
list6.Add(key);
}
}
}
if (list.Count + list2.Count + list3.Count + list4.Count + list5.Count + list6.Count == 0)
{
CurrencyManager.AddCurrency(100, (CurrencyType)0, true);
CurrencyManager.AddCurrency(100, (CurrencyType)1, true);
Log.LogInfo((object)"All items given! Added 100 rosaries and 100 shards!");
ShowInGamePickup("Got all items! Here's some currency instead.");
return;
}
List<(int, string)> list7 = new List<(int, string)>();
foreach (string item2 in list)
{
list7.Add((0, item2));
}
foreach (string item3 in list2)
{
list7.Add((1, item3));
}
foreach (string item4 in list3)
{
list7.Add((2, item4));
}
foreach (string item5 in list4)
{
list7.Add((3, item5));
}
foreach (string item6 in list5)
{
list7.Add((4, item6));
}
foreach (string item7 in list6)
{
list7.Add((5, item7));
}
if (list7.Count == 0)
{
Log.LogWarning((object)"No available items found! This should not happen after totalAvailable check.");
CurrencyManager.AddCurrency(50, (CurrencyType)0, true);
CurrencyManager.AddCurrency(50, (CurrencyType)1, true);
Log.LogInfo((object)"Added 50 rosaries and 50 shards as fallback!");
ShowInGamePickup("Got all items! Here's some currency instead. Also this text isn't really supposed to be seen but it is what it is");
return;
}
int itemType = -1;
string selectedName = "";
if (!CheckForPityItems(ref itemType, ref selectedName))
{
(itemType, selectedName) = list7[Random.Range(0, list7.Count)];
}
UpdateFailedAttempts(itemType, selectedName);
switch (itemType)
{
case 0:
{
string collectableName = selectedName;
if (collectableName == "Invalid Item Template" || collectableName == "Blue Goop Jar" || collectableName == "Dock Demo Key")
{
Log.LogInfo((object)("Got CollectableItem: " + collectableName + " - giving currency instead!"));
CurrencyManager.AddCurrency(200, (CurrencyType)0, true);
CurrencyManager.AddCurrency(200, (CurrencyType)1, true);
Log.LogInfo((object)("Added 200 rosaries and 200 shards for " + collectableName + "."));
ShowInGamePickup("You found " + collectableName + "!\n not sure what that is...\n but here's some currency instead.");
givenItems.Add("CollectableItem: " + collectableName);
givenItemsInOrder.Add("CollectableItem: " + collectableName);
SaveGivenItems();
break;
}
CollectableItem val6 = memorizedCollectables?.FirstOrDefault((Func<CollectableItem, bool>)((CollectableItem item) => (Object)(object)item != (Object)null && ((Object)item).name == collectableName));
if ((Object)(object)val6 != (Object)null)
{
if (collectableName == "Quill")
{
PlayerData instance8 = PlayerData.instance;
instance8.hasQuill = true;
instance8.QuillState = 3;
givenItems.Add("CollectableItem: " + collectableName);
givenItemsInOrder.Add("CollectableItem: " + collectableName);
SaveGivenItems();
Log.LogInfo((object)"Gave Quill!");
ShowInGamePickup("Quill");
GetRandomItem();
break;
}
if (collectableName == "Tool Pouch&Kit Inv")
{
PlayerData instance9 = PlayerData.instance;
if (instance9 != null)
{
string text9;
if (Random.Range(0, 2) == 0)
{
instance9.ToolPouchUpgrades++;
text9 = "Tool Pouch";
Log.LogInfo((object)$"Gave Tool Pouch upgrade! Total: {instance9.ToolPouchUpgrades}");
}
else
{
instance9.ToolKitUpgrades++;
text9 = "Tool Kit";
Log.LogInfo((object)$"Gave Tool Kit upgrade! Total: {instance9.ToolKitUpgrades}");
}
int num10 = bulkItemQuantities[collectableName];
int num11 = (bulkItemGivenCount.ContainsKey(collectableName) ? bulkItemGivenCount[collectableName] : 0);
bulkItemGivenCount[collectableName] = num11 + 1;
givenItemsInOrder.Add($"BULK: {collectableName}: {bulkItemGivenCount[collectableName]}/{num10}");
SaveGivenItems();
ShowInGamePickup(text9);
Log.LogInfo((object)$"[BULK UPDATE] Updated bulkItemGivenCount[{collectableName}] = {bulkItemGivenCount[collectableName]}");
}
break;
}
if (bulkItemQuantities.ContainsKey(collectableName))
{
int num12 = bulkItemQuantities[collectableName];
if (num12 >= 50)
{
val6.Collect(num12, true);
bulkItemGivenCount[collectableName] = num12;
givenItemsInOrder.Add($"BULK: {collectableName}: {num12}");
Log.LogInfo((object)$"Gave bulk CollectableItem: {collectableName} x{num12}");
ShowInGamePickup($"{collectableName} x {num12}");
}
else
{
if (((object)val6).GetType() == typeof(CollectableItemRelicType))
{
getRelicWithSameName(val6.GetDisplayName((ReadSource)4));
ShowInGamePickup(val6.GetDisplayName((ReadSource)4) ?? "");
}
else if (((Object)val6).name == "Slab Key")
{
PlayerData instance10 = PlayerData.instance;
instance10.HasSlabKeyA = true;
instance10.HasSlabKeyB = true;
instance10.HasSlabKeyC = true;
Log.LogInfo((object)"Gave Slab Key - all three keys granted!");
ShowInGamePickup("A slab key sneaked into your pocket!");
GetRandomItem();
}
else
{
val6.Collect(1, true);
ShowInGamePickup(collectableName ?? "");
}
int num13 = (bulkItemGivenCount.ContainsKey(collectableName) ? bulkItemGivenCount[collectableName] : 0);
bulkItemGivenCount[collectableName] = num13 + 1;
givenItemsInOrder.Add($"BULK: {collectableName}: {bulkItemGivenCount[collectableName]}/{num12}");
Log.LogInfo((object)$"Gave CollectableItem: {collectableName} ({bulkItemGivenCount[collectableName]}/{num12})");
Log.LogInfo((object)$"[BULK UPDATE] Updated bulkItemGivenCount[{collectableName}] = {bulkItemGivenCount[collectableName]}");
}
}
else
{
val6.Collect(1, true);
givenItems.Add("CollectableItem: " + collectableName);
givenItemsInOrder.Add("CollectableItem: " + collectableName);
Log.LogInfo((object)$"Gave new CollectableItem: {collectableName} ({givenItems.Count} total given)");
ShowInGamePickup(collectableName ?? "");
}
SaveGivenItems();
}
else
{
Log.LogWarning((object)("Could not find CollectableItem: " + collectableName + " in memorized items! Giving currency instead."));
CurrencyManager.AddCurrency(100, (CurrencyType)0, true);
Log.LogInfo((object)"Added 100 rosaries as fallback for missing collectable item.");
ShowInGamePickup("Didn't find this item: " + collectableName + ", how are you seeing this? Here's some rosaries instead.");
}
break;
}
case 1:
{
string toolName = selectedName;
ToolItem val4 = memorizedTools?.FirstOrDefault((Func<ToolItem, bool>)((ToolItem item) => (Object)(object)item != (Object)null && item.name == toolName));
if ((Object)(object)val4 != (Object)null)
{
((SavedItem)val4).Get(true);
givenItems.Add("ToolItem: " + toolName);
givenItemsInOrder.Add("ToolItem: " + toolName);
SaveGivenItems();
Log.LogInfo((object)$"Gave new ToolItem: {toolName} ({givenItems.Count} total given)");
ShowInGamePickup(toolName ?? "");
}
else
{
Log.LogWarning((object)("Could not find ToolItem: " + toolName + " in memorized items! Giving currency instead."));
CurrencyManager.AddCurrency(25, (CurrencyType)1, true);
Log.LogInfo((object)"Added 25 shards as fallback for missing tool item.");
ShowInGamePickup("Didn't find this item: " + toolName + ", how are you seeing this? Here's some rosaries instead.");
}
break;
}
case 2:
{
string crestName = selectedName;
if (crestName == "Hunter")
{
Log.LogInfo((object)"Got ToolCrest: Hunter - giving currency instead!");
CurrencyManager.AddCurrency(150, (CurrencyType)0, true);
CurrencyManager.AddCurrency(150, (CurrencyType)1, true);
Log.LogInfo((object)"Added 150 rosaries and 150 shards for Hunter crest.");
givenItems.Add("ToolCrest: " + crestName);
givenItemsInOrder.Add("ToolCrest: " + crestName);
ShowInGamePickup("You found Hunter's crest!\n Oh wait, you already have that...\n Here's some currency instead.");
break;
}
ToolCrest val5 = memorizedCrests?.FirstOrDefault((Func<ToolCrest, bool>)((ToolCrest item) => (Object)(object)item != (Object)null && item.name == crestName));
if ((Object)(object)val5 != (Object)null)
{
val5.Unlock();
try
{
ToolItemManager.SetEquippedCrest(crestName);
Log.LogInfo((object)("Equipped ToolCrest: " + crestName));
AutoRest();
}
catch (Exception ex)
{
Log.LogWarning((object)("Could not equip crest " + crestName + ": " + ex.Message));
}
givenItems.Add("ToolCrest: " + crestName);
givenItemsInOrder.Add("ToolCrest: " + crestName);
ShowInGamePickup(crestName ?? "");
if (crestName == "Cursed")
{
PlayerData instance7 = PlayerData.instance;
if (instance7 != null)
{
instance7.SetBool("IsAnyCursed", true);
Log.LogInfo((object)"Set IsAnyCursed to true due to Cursed ToolCrest!");
}
}
ToolCrest cloaklessCrest = Gameplay.CloaklessCrest;
if ((Object)(object)cloaklessCrest != (Object)null && crestName == "cloakless")
{
Log.LogInfo((object)"Got Cloakless crest - triggering crest toggle!");
ToggleCloaklessHunterCrest();
}
SaveGivenItems();
Log.LogInfo((object)$"Gave and equipped new ToolCrest: {crestName} ({givenItems.Count} total given)");
}
else
{
Log.LogWarning((object)("Could not find ToolCrest: " + crestName + " in memorized items! Giving currency instead."));
CurrencyManager.AddCurrency(100, (CurrencyType)0, true);
CurrencyManager.AddCurrency(100, (CurrencyType)1, true);
Log.LogInfo((object)"Added 100 rosaries and 100 shards as fallback for missing crest.");
ShowInGamePickup("Could not find ToolCrest: " + crestName + ", you're not supposed to see this text, oh well. Here's some currency instead.");
}
break;
}
case 3:
{
string text7 = selectedName;
PlayerData instance6 = PlayerData.instance;
if (instance6 != null)
{
instance6.SetBool(text7, true);
givenItems.Add("Powerup: " + text7);
givenItemsInOrder.Add("Powerup: " + text7);
SaveGivenItems();
Log.LogInfo((object)$"Gave new Powerup: {text7} ({givenItems.Count} total given)");
string text8 = text7.Replace("has", "").Replace("_", " ").Trim();
ShowInGamePickup(text8 ?? "");
Log.LogInfo((object)("You now have the " + text7 + " ability!"));
}
else
{
Log.LogWarning((object)"PlayerData not available for powerup! Giving currency instead.");
CurrencyManager.AddCurrency(100, (CurrencyType)0, true);
Log.LogInfo((object)"Added 100 rosaries as fallback for powerup.");
ShowInGamePickup("Powerup " + text7 + " not found? Here's some rosaries instead.");
}
break;
}
case 4:
{
string text4 = selectedName;
PlayerData instance5 = PlayerData.instance;
if (instance5 != null)
{
if (instance5.GetBool(text4))
{
Log.LogInfo((object)("Player already has map " + text4 + "! Rerolling for new item..."));
string text5 = text4.Replace("Has", "").Replace("_", " ").Trim();
ShowInGamePickup("You already have " + text5 + "!\nRerolling for new item...");
GetRandomItem();
}
else
{
instance5.SetBool(text4, true);
givenItems.Add("Map: " + text4);
givenItemsInOrder.Add("Map: " + text4);
SaveGivenItems();
Log.LogInfo((object)$"Gave map flag: {text4} ({givenItems.Count} total given)");
string text6 = text4.Replace("Has", "").Replace("_", " ").Trim();
ShowInGamePickup(text6 ?? "");
}
}
else
{
Log.LogWarning((object)("PlayerData not available for map " + text4 + "! Giving currency instead."));
CurrencyManager.AddCurrency(100, (CurrencyType)0, true);
ShowInGamePickup("Map " + text4 + " not found? Here's some rosaries instead.");
}
break;
}
case 5:
{
string text3 = selectedName;
PlayerData instance3 = PlayerData.instance;
HeroController instance4 = HeroController.instance;
if (instance3 == null || (Object)(object)instance4 == (Object)null)
{
Log.LogWarning((object)"PlayerData or HeroController not available for upgrade!");
CurrencyManager.AddCurrency(50, (CurrencyType)0, true);
ShowInGamePickup("Upgrade failed! Here's some currency.");
break;
}
int num8 = (upgradesGivenCount.ContainsKey(text3) ? upgradesGivenCount[text3] : 0);
upgradesGivenCount[text3] = num8 + 1;
int num9 = availableUpgrades[text3];
givenItemsInOrder.Add($"UPGRADE: {text3}: {upgradesGivenCount[text3]}/{num9}");
switch (text3)
{
case "Mask Shard":
instance3.heartPieces++;
if (instance3.heartPieces % 4 == 0)
{
instance3.maxHealth++;
instance3.health = instance3.maxHealth;
instance3.heartPieces = 0;
Log.LogInfo((object)$"Mask Shard collected! Total shards given: {upgradesGivenCount[text3]}/20. HEALTH UPGRADE! New max: {instance3.maxHealth}");
ShowInGamePickup($"Mask Shard ({upgradesGivenCount[text3]}/20)\nMax Health Increased!\n0/4 pieces");
ToolItemManager.SendEquippedChangedEvent(true);
}
else
{
Log.LogInfo((object)$"Mask Shard collected! Pieces: {instance3.heartPieces}/4. Total given: {upgradesGivenCount[text3]}/20");
ShowInGamePickup($"Mask Shard ({upgradesGivenCount[text3]}/20)\n{instance3.heartPieces}/4 pieces");
}
break;
case "Spool Fragment":
instance3.silkSpoolParts++;
if (instance3.silkSpoolParts % 2 == 0)
{
instance3.IsSilkSpoolBroken = false;
instance4.AddToMaxSilk(1);
instance4.MaxRegenSilkInstant();
instance3.silkSpoolParts = 0;
Log.LogInfo((object)$"Spool Fragment collected! Total fragments given: {upgradesGivenCount[text3]}/18. SILK UPGRADE! New max: {instance3.silkMax}");
ShowInGamePickup($"Spool Fragment ({upgradesGivenCount[text3]}/18)\nMax Silk Increased!\n0/2 pieces");
((MonoBehaviour)this).StartCoroutine(RefreshSilkUI());
}
else
{
Log.LogInfo((object)$"Spool Fragment collected! Parts: {instance3.silkSpoolParts}/2. Total given: {upgradesGivenCount[text3]}/18");
ShowInGamePickup($"Spool Fragment ({upgradesGivenCount[text3]}/18)\n{instance3.silkSpoolParts}/2 pieces");
}
break;
case "Silk Heart":
instance3.silkRegenMax++;
instance3.HasSeenSilkHearts = true;
Log.LogInfo((object)$"Silk Heart collected! Total: {upgradesGivenCount[text3]}/3. Silk regen max: {instance3.silkRegenMax}");
ShowInGamePickup($"Silk Heart ({upgradesGivenCount[text3]}/3)\nSilk Regen Increased!");
ToolItemManager.SendEquippedChangedEvent(true);
break;
}
SaveGivenItems();
break;
}
}
}
catch (Exception ex2)
{
Log.LogError((object)("Error giving random item: " + ex2.Message));
}
}
private void LoadGivenItems()
{
try
{
if (File.Exists(givenItemsFilePath))
{
string[] array = File.ReadAllLines(givenItemsFilePath);
givenItems.Clear();
bulkItemGivenCount.Clear();
bulkItemFailedAttempts.Clear();
upgradesGivenCount.Clear();
givenItemsInOrder.Clear();
for (int num = array.Length - 1; num >= 0; num--)
{
string text = array[num];
if (!string.IsNullOrWhiteSpace(text))
{
string text2 = text.Trim();
givenItemsInOrder.Add(text2);
if (text2.StartsWith("BULK: "))
{
string[] array2 = text2.Split(new string[1] { ": " }, StringSplitOptions.None);
if (array2.Length >= 3)
{
string key = array2[1];
string text3 = array2[2];
int result2;
if (text3.Contains("/"))
{
string[] array3 = text3.Split(new char[1] { '/' });
if (array3.Length == 2 && int.TryParse(array3[0], out var result))
{
bulkItemGivenCount[key] = result;
}
}
else if (int.TryParse(text3, out result2))
{
bulkItemGivenCount[key] = result2;
}
}
}
else if (text2.StartsWith("PITY: "))
{
string[] array4 = text2.Split(new string[1] { ": " }, StringSplitOptions.None);
if (array4.Length >= 3)
{
string key2 = array4[1];
string text4 = array4[2];
if (text4.Contains("/"))
{
string[] array5 = text4.Split(new char[1] { '/' });
if (array5.Length >= 1 && int.TryParse(array5[0], out var result3))
{
bulkItemFailedAttempts[key2] = result3;
}
}
}
}
else if (text2.StartsWith("FAILED: "))
{
string[] array6 = text2.Split(new string[1] { ": " }, StringSplitOptions.None);
if (array6.Length >= 3)
{
string key3 = array6[1];
if (int.TryParse(array6[2], out var result4))
{
bulkItemFailedAttempts[key3] = result4;
}
}
}
else if (text2.StartsWith("UPGRADE: "))
{
string[] array7 = text2.Split(new string[1] { ": " }, StringSplitOptions.None);
if (array7.Length >= 3)
{
string key4 = array7[1];
string text5 = array7[2];
int result6;
if (text5.Contains("/"))
{
string[] array8 = text5.Split(new char[1] { '/' });
if (array8.Length == 2 && int.TryParse(array8[0], out var result5))
{
upgradesGivenCount[key4] = result5;
}
}
else if (int.TryParse(text5, out result6))
{
upgradesGivenCount[key4] = result6;
}
}
}
else
{
givenItems.Add(text2);
}
}
}
Log.LogInfo((object)$"Loaded {givenItems.Count} previously given items, {bulkItemGivenCount.Count} bulk counters, {upgradesGivenCount.Count} upgrades, and {bulkItemFailedAttempts.Count} pity timers from file");
}
else
{
Log.LogInfo((object)"No previous given items file found - starting fresh");
}
}
catch (Exception ex)
{
Log.LogError((object)("Error loading given items: " + ex.Message));
}
}
private void LoadRandomizedShops()
{
try
{
randomizedShops.Clear();
if (!File.Exists(randomizedShopsFilePath))
{
Log.LogInfo((object)"No randomized_shops.txt file found, starting fresh");
return;
}
string[] array = File.ReadAllLines(randomizedShopsFilePath);
string[] array2 = array;
foreach (string text in array2)
{
if (string.IsNullOrWhiteSpace(text))
{
continue;
}
string text2 = text.Trim();
int num = text2.IndexOf('=');
if (num >= 0)
{
string key = text2.Substring(0, num);
string text3 = text2.Substring(num + 1);
string[] array3 = text3.Split(new char[1] { '|' }, StringSplitOptions.None);
List<(string, int)> list = new List<(string, int)>();
string[] array4 = array3;
foreach (string text4 in array4)
{
if (string.IsNullOrEmpty(text4))
{
list.Add(("", 0));
continue;
}
int num2 = text4.LastIndexOf(':');
if (num2 >= 0)
{
string item = text4.Substring(0, num2);
string s = text4.Substring(num2 + 1);
if (int.TryParse(s, out var result))
{
list.Add((item, result));
continue;
}
Log.LogWarning((object)("Invalid cost format in shop data: '" + text4 + "'"));
list.Add((item, 0));
}
else
{
list.Add((text4, 0));
}
}
randomizedShops[key] = list;
}
else
{
randomizedShops[text2] = null;
}
}
Log.LogInfo((object)$"Loaded {randomizedShops.Count} randomized shops from file (per-shop assignments: {randomizedShops.Values.Count((List<(string itemName, int originalCost)> v) => v != null)})");
}
catch (Exception ex)
{
Log.LogError((object)("Error loading randomized shops: " + ex.Message));
}
}
private void SaveGivenItems()
{
try
{
try
{
if (givenItemsInOrder != null && givenItemsInOrder.Count > 0)
{
string text = givenItemsInOrder[givenItemsInOrder.Count - 1];
int num = -1;
string text2 = null;
if (text.StartsWith("CollectableItem: "))
{
num = 0;
text2 = text.Substring("CollectableItem: ".Length);
}
else if (text.StartsWith("ToolItem: "))
{
num = 1;
text2 = text.Substring("ToolItem: ".Length);
}
else if (text.StartsWith("ToolCrest: "))
{
num = 2;
text2 = text.Substring("ToolCrest: ".Length);
}
else if (text.StartsWith("Powerup: "))
{
num = 3;
text2 = text.Substring("Powerup: ".Length);
}
else if (text.StartsWith("BULK: "))
{
string[] array = text.Split(new string[1] { ": " }, StringSplitOptions.None);
if (array.Length >= 2)
{
num = 0;
text2 = array[1];
}
}
if (num != -1 && !string.IsNullOrEmpty(text2))
{
SyncCrossCategoryOnGive(num, text2);
}
}
}
catch (Exception ex)
{
Log.LogError((object)("Error syncing cross-category after save: " + ex.Message));
}
List<string> list = new List<string>();
List<string> collection = (from line in givenItemsInOrder.AsEnumerable().Reverse()
where !line.StartsWith("=== PITY TIMER STATUS ===") && !line.Trim().Equals("")
select line).ToList();
list.AddRange(collection);
if (bulkItemFailedAttempts.Count > 0)
{
list.Add("");
list.Add("=== PITY TIMER STATUS ===");
foreach (KeyValuePair<string, int> item in bulkItemFailedAttempts.OrderBy((KeyValuePair<string, int> x) => x.Key))
{
if (item.Value > 0 && bulkItemPityThreshold.ContainsKey(item.Key))
{
int num2 = bulkItemPityThreshold[item.Key];
int num3 = num2 - item.Value + 1;
list.Add($"PITY: {item.Key}: {item.Value}/{num2} failed ({num3} more attempts until guaranteed)");
}
}
}
File.WriteAllLines(givenItemsFilePath, list);
Log.LogInfo((object)$"Saved {givenItems.Count} given items, {bulkItemGivenCount.Count} bulk counters, and {bulkItemFailedAttempts.Count} pity timers to file");
}
catch (Exception ex2)
{
Log.LogError((object)("Error saving given items: " + ex2.Message));
}
}
internal void SaveRandomizedShops()
{
try
{
List<string> list = new List<string>();
foreach (KeyValuePair<string, List<(string, int)>> randomizedShop in randomizedShops)
{
if (randomizedShop.Value == null)
{
list.Add(randomizedShop.Key);
continue;
}
string[] value = randomizedShop.Value.Select<(string, int), string>(((string itemName, int originalCost) tuple) => string.IsNullOrEmpty(tuple.itemName) ? "" : $"{tuple.itemName}:{tuple.originalCost}").ToArray();
list.Add(randomizedShop.Key + "=" + string.Join("|", value));
}
File.WriteAllLines(randomizedShopsFilePath, list);
Log.LogInfo((object)$"Saved {randomizedShops.Count} randomized shops (with assignments: {list.Count((string l) => Enumerable.Contains(l, '='))})");
}
catch (Exception ex)
{
Log.LogError((object)("Failed to save randomized shops: " + ex.Message));
}
}
internal void SaveShopItemPool()
{
try
{
List<string> list = new List<string>();
foreach (KeyValuePair<string, int> item in shopItemPool)
{
list.Add($"{item.Key}:{item.Value}");
}
string path = Path.Combine(Path.GetDirectoryName(randomizedShopsFilePath), "shop_item_pool.txt");
File.WriteAllLines(path, list);
Log.LogInfo((object)$"Saved shop item pool with {shopItemPool.Count} entries");
}
catch (Exception ex)
{
Log.LogError((object)("Failed to save shop item pool: " + ex.Message));
}
}
internal void LoadShopItemPool()
{
try
{
string path = Path.Combine(Path.GetDirectoryName(randomizedShopsFilePath), "shop_item_pool.txt");
if (!File.Exists(path))
{
Log.LogInfo((object)"No shop item pool file found, starting with empty pool");
return;
}
string[] array = File.ReadAllLines(path);
shopItemPool.Clear();
string[] array2 = array;
foreach (string text in array2)
{
if (string.IsNullOrWhiteSpace(text))
{
continue;
}
string[] array3 = text.Split(new char[1] { ':' });
if (array3.Length == 2)
{
string key = array3[0];
if (int.TryParse(array3[1], out var result))
{
shopItemPool[key] = result;
}
}
}
Log.LogInfo((object)$"Loaded shop item pool with {shopItemPool.Count} entries");
}
catch (Exception ex)
{
Log.LogError((object)("Failed to load shop item pool: " + ex.Message));
}
}
internal static List<CollectableItem> GetAvailableCollectablesForShops()
{
List<CollectableItem> list = new List<CollectableItem>();
if (memorizedCollectables == null)
{
return list;
}
CollectableItem[] array = memorizedCollectables;
foreach (CollectableItem val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
string name = ((Object)val).name;
switch (name)
{
case "Invalid Item Template":
case "Blue Goop Jar":
case "Dock Demo Key":
continue;
}
if (name == "Tool Pouch&Kit Inv")
{
continue;
}
switch (name)
{
case "R Seal chit":
case "R Weaver Totem":
case "R Bone Record":
case "R Weaver Record":
case "R Ancient Egg":
case "R Psalm Cylinder":
case "R Librarian Melody Cylinder":
continue;
}
if (name == "Pins" || bulkItemPityThreshold.ContainsKey(name))
{
continue;
}
if (bulkItemQuantities.ContainsKey(name))
{
int num = bulkItemQuantities[name];
if (num < 50)
{
int num2 = (shopItemPool.ContainsKey(name) ? shopItemPool[name] : 0);
int num3 = num - num2;
for (int j = 0; j < Mathf.Min(num3, 20); j++)
{
list.Add(val);
}
}
}
else if (!shopItemPool.ContainsKey(name) || shopItemPool[name] == 0)
{
list.Add(val);
}
}
return list;
}
private void ToggleCloaklessHunterCrest()
{
try
{
PlayerData instance = PlayerData.instance;
if (instance == null)
{
Log.LogWarning((object)"PlayerData not available!");
return;
}
string currentCrestID = instance.CurrentCrestID;
Log.LogInfo((object)("Current crest: " + (currentCrestID ?? "none")));
ToolCrest cloaklessCrest = Gameplay.CloaklessCrest;
bool flag = (Object)(object)cloaklessCrest != (Object)null && currentCrestID == cloaklessCrest.name;
bool flag2 = currentCrestID == "Cursed";
if (flag || flag2)
{
if (memorizedCrests != null)
{
ToolCrest val = ((IEnumerable<ToolCrest>)memorizedCrests).FirstOrDefault((Func<ToolCrest, bool>)((ToolCrest c) => (Object)(object)c != (Object)null && c.name == "Hunter"));
if ((Object)(object)val != (Object)null)
{
val.Unlock();
ToolItemManager.SetEquippedCrest(val.name);
string text = (flag ? "cloakless" : "cursed");
Log.LogInfo((object)("Switched from " + text + " to Hunter crest: " + val.name));
AutoRest();
}
else
{
Log.LogWarning((object)"Hunter crest not found in memorized crests!");
}
}
else
{
Log.LogWarning((object)"Crests not memorized yet! Press F7 first.");
}
}
else if ((Object)(object)cloaklessCrest != (Object)null)
{
cloaklessCrest.Unlock();
ToolItemManager.SetEquippedCrest(cloaklessCrest.name);
Log.LogInfo((object)("Switched to cloakless crest: " + cloaklessCrest.name));
AutoRest();
}
else
{
Log.LogWarning((object)"CloaklessCrest not found!");
}
}
catch (Exception ex)
{
Log.LogError((object)("Error toggling crest: " + ex.Message));
}
}
private void ToggleSilkSoar()
{
try
{
PlayerData instance = PlayerData.instance;
if (instance == null)
{
Log.LogWarning((object)"PlayerData not available!");
}
else if (instance.GetBool("hasSuperJump"))
{
instance.SetBool("hasSuperJump", false);
Log.LogInfo((object)"Disabled Silk Soar ability");
}
else
{
instance.SetBool("hasSuperJump", true);
Log.LogInfo((object)"Enabled Silk Soar ability");
}
}
catch (Exception ex)
{
Log.LogError((object)("Error toggling Silk Soar: " + ex.Message));
}
}
public static void AutoRest()
{
try
{
bool flag = ToolItemManager.TryReplenishTools(true, (ReplenishMethod)0);
Log.LogInfo((object)(flag ? "Auto-rested! Tools replenished." : "Auto-rest complete (no replenishment needed)."));
}
catch (Exception ex)
{
Log.LogError((object)("Error during auto-rest: " + ex.Message));
}
}
[IteratorStateMachine(typeof(<RefreshSilkUI>d__53))]
private IEnumerator RefreshSilkUI()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <RefreshSilkUI>d__53(0)
{
<>4__this = this
};
}
}
[HarmonyPatch(typeof(ShopMenuStock), "BuildItemList")]
public static class ShopMenuStock_BuildItemList_Patch
{
private static ManualLogSource Log = Logger.CreateLogSource("ShopRandomizer");
[HarmonyPrefix]
public static void Prefix(ShopMenuStock __instance)
{
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_042e: Unknown result type (might be due to invalid IL or missing references)
//IL_0435: Expected I4, but got Unknown
try
{
if (!HKS_Randomizer.itemsMemorized)
{
Log.LogInfo((object)"[SHOP] Items not memorized yet, memorizing now...");
HKS_Randomizer.Instance?.MemorizeAllItems();
if (!HKS_Randomizer.itemsMemorized)
{
Log.LogError((object)"[SHOP] Failed to memorize items, cannot randomize shops");
return;
}
}
ShopOwner[] array = Resources.FindObjectsOfTypeAll<ShopOwner>();
Log.LogInfo((object)$"[SHOP] Found {array.Length} ShopOwners in scene");
ShopOwner[] array2 = array;
foreach (ShopOwner val in array2)
{
if ((Object)(object)val == (Object)null || ((ShopOwnerBase)val).Stock == null || ((ShopOwnerBase)val).Stock.Length == 0)
{
continue;
}
object obj;
if (!((Object)((Component)val).gameObject).name.Contains("Mapper"))
{
Scene activeScene = SceneManager.GetActiveScene();
obj = ((Scene)(ref activeScene)).name + "_" + ((Object)((Component)val).gameObject).name;
}
else
{
obj = "Mapper";
}
string text = (string)obj;
if (HKS_Randomizer.randomizedShops.ContainsKey(text))
{
List<(string, int)> list = HKS_Randomizer.randomizedShops[text];
if (list != null && list.Count == ((ShopOwnerBase)val).Stock.Length)
{
Log.LogInfo((object)("[SHOP LOAD] Reapplying saved assignments to " + text));
for (int j = 0; j < ((ShopOwnerBase)val).Stock.Length; j++)
{
ShopItem val2 = ((ShopOwnerBase)val).Stock[j];
if ((Object)(object)val2 == (Object)null)
{
continue;
}
var (itemName, num) = list[j];
if (string.IsNullOrEmpty(itemName))
{
FieldInfo field = typeof(ShopItem).GetField("cost", BindingFlags.Instance | BindingFlags.NonPublic);
if (field != null)
{
int num2 = (int)field.GetValue(val2);
int num3 = Mathf.Max(1, num2 / 2);
field.SetValue(val2, num3);
}
continue;
}
CollectableItem[] array3 = typeof(HKS_Randomizer).GetField("memorizedCollectables", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as CollectableItem[];
CollectableItem val3 = null;
if (array3 != null)
{
val3 = Array.Find(array3, (CollectableItem c) => (Object)(object)c != (Object)null && ((Object)c).name == itemName);
}
if ((Object)(object)val3 != (Object)null)
{
FieldInfo field2 = typeof(ShopItem).GetField("savedItem", BindingFlags.Instance | BindingFlags.NonPublic);
if (field2 != null)
{
field2.SetValue(val2, val3);
FieldInfo field3 = typeof(ShopItem).GetField("cost", BindingFlags.Instance | BindingFlags.NonPublic);
if (field3 != null)
{
int num4 = Mathf.Max(1, num / 2);
field3.SetValue(val2, num4);
Log.LogInfo((object)$"[SHOP LOAD] Slot {j}: {itemName} (original: {num}, halved: {num4})");
}
}
}
else
{
Log.LogWarning((object)$"[SHOP LOAD] Slot {j}: Could not find item '{itemName}'");
}
}
Log.LogInfo((object)("[SHOP LOAD] " + text + " assignments reapplied"));
continue;
}
Log.LogWarning((object)("[SHOP] " + text + " has invalid/mismatched assignments, re-randomizing"));
}
Log.LogInfo((object)$"[SHOP] Randomizing shop: {text} with {((ShopOwnerBase)val).Stock.Length} slots");
List<CollectableItem> availableCollectablesForShops = HKS_Randomizer.GetAvailableCollectablesForShops();
int num5 = 0;
List<(string, int)> list2 = new List<(string, int)>(new(string, int)[((ShopOwnerBase)val).Stock.Length]);
for (int k = 0; k < ((ShopOwnerBase)val).Stock.Length; k++)
{
ShopItem val4 = ((ShopOwnerBase)val).Stock[k];
if ((Object)(object)val4 == (Object)null)
{
continue;
}
int num6 = (int)val4.GetTypeFlags();
if (num6 == 0 || num6 == 1)
{
if (availableCollectablesForShops.Count == 0)
{
Log.LogWarning((object)"[SHOP] Pool exhausted");
break;
}
int index = Random.Range(0, availableCollectablesForShops.Count);
CollectableItem val5 = availableCollectablesForShops[index];
availableCollectablesForShops.RemoveAt(index);
FieldInfo field4 = typeof(ShopItem).GetField("savedItem", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo field5 = typeof(ShopItem).GetField("cost", BindingFlags.Instance | BindingFlags.NonPublic);
if (field4 != null && field5 != null)
{
field4.SetValue(val4, val5);
int num7 = (int)field5.GetValue(val4);
int num8 = Mathf.Max(1, num7 / 2);
field5.SetValue(val4, num8);
string name = ((Object)val5).name;
int num9 = (HKS_Randomizer.shopItemPool.ContainsKey(name) ? HKS_Randomizer.shopItemPool[name] : 0);
HKS_Randomizer.shopItemPool[name] = num9 + 1;
Log.LogInfo((object)$"[SHOP] Slot {k}: {name} (pool: {num9 + 1}, cost: {num8})");
list2[k] = (name, num7);
num5++;
}
}
else
{
FieldInfo field6 = typeof(ShopItem).GetField("cost", BindingFlags.Instance | BindingFlags.NonPublic);
if (field6 != null)
{
int num10 = (int)field6.GetValue(val4);
int num11 = Mathf.Max(1, num10 / 2);
field6.SetValue(val4, num11);
list2[k] = ("", 0);
}
}
}
Log.LogInfo((object)$"[SHOP SAVE] {text} complete: {num5} items replaced");
HKS_Randomizer.randomizedShops[text] = list2;
((object)HKS_Randomizer.Instance).GetType().GetMethod("SaveRandomizedShops", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(HKS_Randomizer.Instance, null);
((object)HKS_Randomizer.Instance).GetType().GetMethod("SaveShopItemPool", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(HKS_Randomizer.Instance, null);
}
}
catch (Exception ex)
{
Log.LogError((object)("[SHOP] Error in BuildItemList patch: " + ex.Message + "\n" + ex.StackTrace));
}
}
}
[HarmonyPatch(typeof(CollectableItemPickup), "Invoke")]
public static class CollectableItemPickup_DoPickup_Patch
{
[HarmonyPatch(typeof(SavedItem), "TryGet")]
public static class SavedItem_TryGet_Patch
{
private static ManualLogSource Log = Logger.CreateLogSource("InstantPickupPatches");
private static bool hasInitialized = false;
[HarmonyPrefix]
public static bool Prefix(SavedItem __instance, ref bool __result, bool breakIfAtMax, bool showPopup)
{
HKS_Randomizer hKS_Randomizer = Object.FindFirstObjectByType<HKS_Randomizer>();
if ((Object)(object)hKS_Randomizer != (Object)null)
{
if (!hasInitialized)
{
Log.LogInfo((object)"First walking pickup - automatically initializing items");
hKS_Randomizer.MemorizeAllItems();
hasInitialized = true;
if (HKS_Randomizer.itemsMemorized)
{
hKS_Randomizer.GetRandomItem();
}
}
else if (HKS_Randomizer.itemsMemorized)
{
hKS_Randomizer.GetRandomItem();
}
}
if (__instance is CollectableItem)
{
__result = true;
return false;
}
return true;
}
}
private static ManualLogSource patchLog = Logger.CreateLogSource("PickupPatches");
}
}