using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using HarmonyLib;
using MelonLoader;
using PersistentHeroes;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: HarmonyDontPatchAll]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: MelonGame(null, "Backpack Hero")]
[assembly: MelonInfo(typeof(Mod), "Persistent Heroes", "0.1.4", "Kospa", null)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace PersistentHeroes;
internal static class BackpackService
{
private static Transform Root()
{
if (!Object.op_Implicit((Object)(object)LevelUpManager.main) || !Object.op_Implicit((Object)(object)LevelUpManager.main.gridParent))
{
throw new InvalidOperationException("Нет LevelUpManager.gridParent.");
}
return LevelUpManager.main.gridParent;
}
private static List<GridSquare> Cells(Transform root)
{
return (from c in ((Component)root).GetComponentsInChildren<GridSquare>(false)
where (Object)(object)((Component)c).transform.parent == (Object)(object)root && !c.isPouch && !Object.op_Implicit((Object)(object)((Component)c).GetComponentInParent<GridBlock>())
select c).ToList();
}
internal static ProgressState Capture(Player player)
{
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
LevelUpManager main = LevelUpManager.main;
if (!Object.op_Implicit((Object)(object)main) || main.levelingUp || !Object.op_Implicit((Object)(object)GameManager.main) || !Object.op_Implicit((Object)(object)player.chosenCharacter))
{
throw new InvalidOperationException("Рюкзак не готов к сохранению либо идёт расширение.");
}
ProgressState progressState = new ProgressState();
progressState.Level = player.level;
progressState.Experience = player.experience;
progressState.Spaces = main.spacesSaved;
progressState.Gold = GameManager.main.goldAmount;
ProgressState progressState2 = progressState;
foreach (GridSquare item in Cells(Root()))
{
Vector3 localPosition = ((Component)item).transform.localPosition;
int num = Mathf.RoundToInt(localPosition.x);
int num2 = Mathf.RoundToInt(localPosition.y);
if (Mathf.Abs((float)num - localPosition.x) > 0.01f || Mathf.Abs((float)num2 - localPosition.y) > 0.01f)
{
throw new InvalidDataException("Ячейка вне целочисленной сетки: " + localPosition);
}
progressState2.Cells.Add(new CellState
{
X = num,
Y = num2,
Runic = item.isRunic
});
}
foreach (GameObject chosenBlockPrefab in main.chosenBlockPrefabs)
{
if (!Object.op_Implicit((Object)(object)chosenBlockPrefab))
{
throw new InvalidDataException("Пустая ссылка chosenBlockPrefabs.");
}
progressState2.Blocks.Add(((Object)chosenBlockPrefab).name);
}
progressState2.Validate();
if (progressState2.Level >= player.chosenCharacter.levelUps.Count)
{
throw new InvalidDataException("Уровень вне таблицы героя: " + progressState2.Level);
}
return progressState2;
}
internal static void Restore(Player player, ProgressState state)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
//IL_0259: Unknown result type (might be due to invalid IL or missing references)
state.Validate();
Transform val = Root();
LevelUpManager main = LevelUpManager.main;
GameObject val2 = (GameObject)AccessTools.Field(typeof(Player), "gridPrefab").GetValue(player);
if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val2.GetComponent<GridSquare>()) || !Object.op_Implicit((Object)(object)player.chosenCharacter) || state.Level >= player.chosenCharacter.levelUps.Count)
{
throw new InvalidDataException("Нет префаба GridSquare или уровень несовместим с героем.");
}
List<GameObject> list = new List<GameObject>();
foreach (string name in state.Blocks)
{
List<GameObject> gridBlockPrefabs = main.gridBlockPrefabs;
Predicate<GameObject> match = (GameObject p) => Object.op_Implicit((Object)(object)p) && ((Object)p).name == name;
GameObject val3 = gridBlockPrefabs.Find(match);
if (!Object.op_Implicit((Object)(object)val3))
{
throw new InvalidDataException("Не найден блок расширения: " + name);
}
list.Add(val3);
}
Transform[] array = ((IEnumerable)val).Cast<Transform>().ToArray();
foreach (Transform val4 in array)
{
((Component)val4).gameObject.SetActive(false);
val4.SetParent((Transform)null);
Object.Destroy((Object)(object)((Component)val4).gameObject);
}
foreach (CellState cell in state.Cells)
{
GameObject val5 = Object.Instantiate<GameObject>(val2, val);
val5.transform.localPosition = new Vector3((float)cell.X, (float)cell.Y, 0f);
GridSquare component = val5.GetComponent<GridSquare>();
component.isRunic = cell.Runic;
component.containsItem = false;
component.itemCountsAsEmpty = false;
component.isPouch = false;
component.itemPouch = null;
component.SetColor();
component.GetGridObject();
GridObject component2 = val5.GetComponent<GridObject>();
component2.type = (Type)1;
}
player.level = state.Level;
player.experience = state.Experience;
main.spacesSaved = state.Spaces;
main.chosenBlockPrefabs = list;
GameManager.main.goldAmount = state.Gold;
GameManager.main.ChangeGold(0);
player.AddExperience(0, ((Component)player).transform.position);
ModularBackpack.SetAllBackpackSprites();
main.ResizeAllBackpacks();
MelonCoroutines.Start(ValidateAfterStart(player, val, state));
}
private static IEnumerator ValidateAfterStart(Player player, Transform root, ProgressState state)
{
yield return null;
yield return (object)new WaitForEndOfFrame();
int frame = 0;
while (true)
{
if (frame < 180)
{
if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)root))
{
break;
}
bool valid;
try
{
List<GridSquare> list = Cells(root);
foreach (GridSquare item in list)
{
item.GetGridObject();
((Component)item).GetComponent<GridObject>().SnapToGrid();
}
HashSet<string> hashSet = new HashSet<string>(list.Select((GridSquare c) => Mathf.RoundToInt(((Component)c).transform.localPosition.x) + ":" + Mathf.RoundToInt(((Component)c).transform.localPosition.y)));
valid = list.Count == state.Cells.Count && hashSet.SetEquals(state.Cells.Select((CellState c) => c.Key)) && list.All((GridSquare c) => ((Component)c).GetComponent<GridObject>().gridPositions.Count > 0);
if (valid)
{
List<Vector2Int> list2 = list.SelectMany((GridSquare c) => ((Component)c).GetComponent<GridObject>().gridPositions).ToList();
valid = list2.Distinct().Count() == list2.Count;
}
}
catch (Exception error)
{
Mod.RestoreFailed = true;
Mod.Error("Проверка логической сетки", error);
break;
}
if (valid)
{
if (Object.op_Implicit((Object)(object)PocketManager.main))
{
PocketManager.main.DeterminePockets();
}
MelonLogger.Msg(string.Concat("Восстановлено и проверено: слот=", Singleton.Instance.storyModeSlot, ", герой=", Singleton.Instance.character, ", ячеек=", state.Cells.Count, ", уровень=", state.Level, ", опыт=", state.Experience, ", золото=", state.Gold));
break;
}
yield return null;
frame++;
continue;
}
Mod.RestoreFailed = true;
Mod.Notice("Сетка рюкзака не прошла проверку: ожидалось " + state.Cells.Count + " ячеек. Не продолжайте вылазку; пришлите журнал.");
break;
}
}
}
internal static class DeparturePreparation
{
private static RunTypeSelector selector;
private static OverworldInventory window;
private static bool approved;
private static bool allowSave;
internal static void Reset()
{
PreparationUi.Release();
selector = null;
window = null;
approved = false;
allowSave = false;
}
internal static bool IsApproved(RunTypeSelector value)
{
if (approved)
{
return (Object)(object)selector == (Object)(object)value;
}
return false;
}
internal static bool BeforeSave(RunTypeSelector value)
{
if (allowSave && IsApproved(value))
{
allowSave = false;
return true;
}
Begin(value);
return false;
}
internal static void Begin(RunTypeSelector value)
{
if (Mod.Departing || approved || (Object.op_Implicit((Object)(object)window) && ((Component)window).gameObject.activeInHierarchy))
{
return;
}
if (!Object.op_Implicit((Object)(object)value.selectedRunTypeButton) || !value.selectedRunTypeButton.UnlockedRunType())
{
throw new InvalidOperationException("Задание недоступно.");
}
selector = value;
try
{
window = LoadoutService.OpenPicker();
if (!Object.op_Implicit((Object)(object)window))
{
throw new InvalidOperationException("Игра не создала окно склада.");
}
PreparationUi.Create(window, Confirm, Cancel);
LoadoutService.RefreshSummary();
}
catch
{
Reset();
try
{
Overworld_InventoryManager.main.HideInventory();
}
catch (Exception error)
{
Mod.Error("Закрытие склада после ошибки подготовки", error);
}
throw;
}
}
private static void Confirm()
{
if (approved || Mod.Departing || !Object.op_Implicit((Object)(object)window) || !((Component)window).gameObject.activeInHierarchy)
{
return;
}
try
{
if (!Mod.Eligible())
{
throw new InvalidOperationException("Задание больше не поддерживает выбор снаряжения.");
}
LoadoutService.ValidateSelection(selector);
approved = true;
Overworld_InventoryManager.main.HideInventory();
window = null;
allowSave = true;
MelonLogger.Msg("Снаряжение подтверждено; " + Mod.Context());
selector.SaveOverworldAndGoAdventuring();
}
catch (Exception ex)
{
Reset();
Mod.Error("Подтверждение снаряжения", ex);
Mod.Notice("Отправка отменена: " + ex.Message);
}
}
private static void Cancel()
{
if (!approved)
{
Overworld_InventoryManager.main.HideInventory();
}
}
internal static void OnInventoryRemoved()
{
if (!approved && !LoadoutService.BuildingPicker && Object.op_Implicit((Object)(object)selector))
{
Reset();
MelonLogger.Msg("Выбор снаряжения закрыт. Отправка отменена, склад не изменён.");
}
}
}
[HarmonyPatch(typeof(RunTypeSelector), "SaveOverworldAndGoAdventuring")]
internal static class PreparationPatch
{
private static bool Prefix(RunTypeSelector __instance)
{
if (!Mod.Eligible())
{
return true;
}
try
{
return DeparturePreparation.BeforeSave(__instance);
}
catch (Exception ex)
{
DeparturePreparation.Reset();
Mod.Error("Подготовка вылазки", ex);
Mod.Notice("Не удалось открыть снаряжение: " + ex.Message);
return false;
}
}
}
[HarmonyPatch(typeof(Overworld_InventoryManager), "RemoveAllInventories")]
internal static class PreparationClosePatch
{
private static void Prefix()
{
DeparturePreparation.OnInventoryRemoved();
}
}
internal static class LoadoutService
{
private static readonly LoadoutSelection selection = new LoadoutSelection();
private static readonly List<GameObject> pending = new List<GameObject>();
private static readonly List<GameObject> pendingCarvings = new List<GameObject>();
private static Missions mission;
private static CharacterName hero;
private static int slot;
private static OverworldInventory picker;
private static bool buildingPicker;
private static readonly Dictionary<string, int> pageCopies = new Dictionary<string, int>();
private static readonly Dictionary<Overworld_InventoryItemButton, int> cardCopies = new Dictionary<Overworld_InventoryItemButton, int>();
internal static bool BuildingPicker => buildingPicker;
internal static void Clear()
{
selection.Clear();
pending.Clear();
pendingCarvings.Clear();
mission = null;
picker = null;
cardCopies.Clear();
pageCopies.Clear();
DeparturePreparation.Reset();
}
private static List<string> Stock()
{
return ((IEnumerable<string>)MetaProgressSaveManager.main.storedItems).Select((Func<string, string>)Item2.GetDisplayName).ToList();
}
internal static void AddControl(RunTypeButton source)
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
selection.Clear();
picker = null;
DeparturePreparation.Reset();
mission = source.mission;
hero = Singleton.Instance.character;
slot = Singleton.Instance.storyModeSlot;
}
private static void UpdateHeading()
{
PreparationUi.UpdateCount(selection.Count);
}
internal static OverworldInventory OpenPicker()
{
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Expected O, but got Unknown
try
{
if (Mod.Departing || !Mod.Eligible())
{
throw new InvalidOperationException("Сейчас нельзя выбрать снаряжение.");
}
if ((Object)(object)Singleton.Instance.mission != (Object)(object)mission || Singleton.Instance.character != hero || Singleton.Instance.storyModeSlot != slot)
{
selection.Clear();
mission = Singleton.Instance.mission;
hero = Singleton.Instance.character;
slot = Singleton.Instance.storyModeSlot;
}
buildingPicker = true;
picker = (OverworldInventory)AccessTools.Method(typeof(Overworld_InventoryManager), "ShowInventory", (Type[])null, (Type[])null).Invoke(Overworld_InventoryManager.main, new object[1] { (object)(ClickAction)0 });
MelonLogger.Msg("Открыт выбор снаряжения; " + Mod.Context());
return picker;
}
finally
{
buildingPicker = false;
}
}
internal static void RefreshSummary()
{
UpdateHeading();
}
internal static void ValidateSelection(RunTypeSelector selector)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)selector) || !Object.op_Implicit((Object)(object)selector.selectedRunTypeButton) || !selector.selectedRunTypeButton.UnlockedRunType())
{
throw new InvalidOperationException("Задание недоступно.");
}
if ((Object)(object)mission != (Object)(object)Singleton.Instance.mission || hero != Singleton.Instance.character || slot != Singleton.Instance.storyModeSlot)
{
throw new InvalidOperationException("Изменились герой, слот или задание. Выберите снаряжение заново.");
}
selection.Remaining(Stock());
}
internal static bool IsPickerButton(Overworld_InventoryItemButton button)
{
if (!buildingPicker)
{
if (Object.op_Implicit((Object)(object)picker))
{
return (Object)(object)((Component)button).GetComponentInParent<OverworldInventory>() == (Object)(object)picker;
}
return false;
}
return true;
}
internal static void BeginPage(OverworldInventory inventory, int startingNumber)
{
if (!buildingPicker && (Object)(object)inventory != (Object)(object)picker)
{
return;
}
cardCopies.Clear();
pageCopies.Clear();
List<string> list = (List<string>)AccessTools.Field(typeof(OverworldInventory), "originOfItems").GetValue(inventory);
if (list == null)
{
throw new InvalidOperationException("Нет списка предметов страницы склада.");
}
foreach (string item in list.Take(startingNumber))
{
string displayName = Item2.GetDisplayName(item);
pageCopies.TryGetValue(displayName, out var value);
pageCopies[displayName] = value + 1;
}
}
internal static void ConfigureButton(Overworld_InventoryItemButton itemButton)
{
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Expected O, but got Unknown
if (!IsPickerButton(itemButton) || !Object.op_Implicit((Object)(object)itemButton.item))
{
return;
}
if (!cardCopies.ContainsKey(itemButton))
{
string displayName = Item2.GetDisplayName(((Object)itemButton.item).name);
pageCopies.TryGetValue(displayName, out var value);
cardCopies.Add(itemButton, value);
pageCopies[displayName] = value + 1;
}
itemButton.draggable = false;
Button component = ((Component)itemButton).GetComponent<Button>();
if (!Object.op_Implicit((Object)(object)component))
{
throw new InvalidOperationException("У предмета нет Button: " + ((Object)itemButton).name);
}
((UnityEventBase)component.onClick).RemoveAllListeners();
((UnityEvent)component.onClick).AddListener((UnityAction)delegate
{
try
{
if (!Mod.Departing)
{
if (!CanTake(itemButton.item))
{
Mod.Notice("Предмет уникален или недоступен выбранному герою: " + Item2.GetDisplayName(((Object)itemButton.item).name));
}
else
{
if (!cardCopies.TryGetValue(itemButton, out var value2))
{
throw new InvalidOperationException("Карточка склада устарела.");
}
selection.Toggle(Item2.GetDisplayName(((Object)itemButton.item).name), value2, Stock());
MelonLogger.Msg("Снаряжение: предмет=" + Item2.GetDisplayName(((Object)itemButton.item).name) + ", выбрано=" + selection.Get(Item2.GetDisplayName(((Object)itemButton.item).name)) + ", всего=" + selection.Count);
UpdateHeading();
if (Object.op_Implicit((Object)(object)picker))
{
Overworld_InventoryItemButton[] componentsInChildren = ((Component)picker).GetComponentsInChildren<Overworld_InventoryItemButton>();
foreach (Overworld_InventoryItemButton button in componentsInChildren)
{
UpdateLabel(button);
}
}
}
}
}
catch (Exception error)
{
Mod.Error("Выбор предмета", error);
Mod.Notice("Склад изменился. Закройте выбор и проверьте снаряжение.");
}
});
UpdateLabel(itemButton);
}
private static void UpdateLabel(Overworld_InventoryItemButton button)
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Expected O, but got Unknown
if (Object.op_Implicit((Object)(object)button.item) && cardCopies.TryGetValue(button, out var value))
{
string displayName = Item2.GetDisplayName(((Object)button.item).name);
TextMeshProUGUI val = (TextMeshProUGUI)AccessTools.Field(typeof(Overworld_InventoryItemButton), "itemNameText").GetValue(button);
if (!Object.op_Implicit((Object)(object)val))
{
throw new InvalidOperationException("Нет текста карточки снаряжения: " + displayName);
}
((TMP_Text)val).text = LangaugeManager.main.GetTextByKey(displayName);
SelectionMarkerUi.Refresh(button, selection.Contains(displayName, value));
}
}
private static bool CanTake(Item2 item)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Invalid comparison between Unknown and I4
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)item) || (int)item.oneOfAKindType == 2)
{
return false;
}
if (item.validForCharacters == null)
{
Debug.LogWarning((object)("[PersistentHeroes] Нет validForCharacters у предмета " + ((Object)item).name + "; герой=" + Singleton.Instance.character));
return false;
}
if (item.validForCharacters.Count != 0 && !item.validForCharacters.Contains((CharacterName)0))
{
return item.validForCharacters.Contains(Singleton.Instance.character);
}
return true;
}
internal static void Depart(RunTypeSelector selector)
{
if (Mod.Departing)
{
return;
}
if (!Object.op_Implicit((Object)(object)SceneLoader.main) || SceneLoader.main.IsLoading())
{
throw new InvalidOperationException("Переход между сценами уже выполняется.");
}
ValidateSelection(selector);
MetaProgressSaveManager main = MetaProgressSaveManager.main;
List<string> list = main.storedItems.ToList();
selection.Remaining(Stock());
List<string> list2 = list.ToList();
List<GameObject> list3 = new List<GameObject>();
foreach (string key in selection.Selected())
{
Predicate<string> match = (string x) => Item2.GetDisplayName(x) == key;
int num = list2.FindIndex(match);
if (num < 0)
{
throw new InvalidOperationException("На складе больше нет: " + key);
}
Item2 item2ByName = DebugItemManager.main.GetItem2ByName(key);
if (!CanTake(item2ByName))
{
throw new InvalidOperationException("Предмет недоступен для вылазки: " + key);
}
list3.Add(((Component)item2ByName).gameObject);
list2.RemoveAt(num);
}
Mod.Departing = true;
try
{
main.storedItems = list2;
SaveStockAndVerify(main, list2);
}
catch
{
main.storedItems = list;
try
{
SaveStockAndVerify(main, list);
}
catch (Exception error)
{
Mod.Error("Не удалось записать возврат снаряжения после ошибки сохранения", error);
}
Mod.Departing = false;
throw;
}
pending.Clear();
pending.AddRange(list3);
Singleton.Instance.otherPrefabObjectsToSpawn.Clear();
Singleton.Instance.loadSave = false;
Singleton.Instance.doTutorial = false;
MelonLogger.Msg("Отправка: слот=" + Singleton.Instance.storyModeSlot + ", предметов=" + pending.Count + ", на складе=" + list2.Count);
try
{
SceneLoader.main.LoadScene("Game", (LoadSceneMode)0, (SceneLoaderPredicate)null, (Action)null);
selection.Clear();
}
catch
{
pending.Clear();
main.storedItems = list;
Mod.Departing = false;
SaveStockAndVerify(main, list);
throw;
}
}
private static void SaveStockAndVerify(MetaProgressSaveManager meta, List<string> expected)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Expected O, but got Unknown
meta.SaveAll();
ES3Settings val = (ES3Settings)AccessTools.Field(typeof(MetaProgressSaveManager), "settings").GetValue(meta);
byte[] first = ES3.DecryptBytes(File.ReadAllBytes(val.path), (string)null);
if (!first.SequenceEqual(ES3.LoadRawBytes(val)))
{
throw new IOException("Записанные данные склада отличаются от кэша: " + val.path);
}
List<string> first2 = ES3.Load<List<string>>("storedItems", val);
if (!first2.SequenceEqual(expected))
{
throw new IOException("Склад на диске не совпадает с выбранным снаряжением: " + val.path);
}
}
internal static void Spawn()
{
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
if (!Mod.Supported())
{
return;
}
if (Singleton.Instance.loadSave)
{
pending.Clear();
pendingCarvings.Clear();
}
else
{
if (pending.Count == 0)
{
return;
}
GameObject[] array = pending.ToArray();
pending.Clear();
GameObject[] array2 = array;
foreach (GameObject val in array2)
{
if (!Object.op_Implicit((Object)(object)val))
{
throw new InvalidOperationException("Потерян префаб выбранного снаряжения.");
}
if (Object.op_Implicit((Object)(object)val.GetComponent<Carving>()))
{
pendingCarvings.Add(val);
}
else
{
Object.Instantiate<GameObject>(val, Vector3.zero, Quaternion.identity);
}
}
MelonLogger.Msg("Выдано снаряжение: " + array.Length + " предметов. Повторная выдача заблокирована.");
}
}
internal static void SpawnCarvings(Tote deck)
{
if (!Singleton.Instance.loadSave && pendingCarvings.Count != 0)
{
GameObject[] array = pendingCarvings.ToArray();
pendingCarvings.Clear();
GameObject[] array2 = array;
foreach (GameObject val in array2)
{
deck.AddCarvingToDeck(val);
}
MelonLogger.Msg("В стартовую колоду передано резных фигурок: " + array.Length);
}
}
}
[HarmonyPatch(typeof(RunTypeButton), "SetRunType")]
internal static class MissionUiPatch
{
private static void Prefix(RunTypeButton __instance, out List<RunProperty> __state)
{
__state = null;
if (Mod.Supported() && Object.op_Implicit((Object)(object)__instance.mission) && !__instance.mission.runProperties.Exists((RunProperty p) => (int)p.type == 42 || (int)p.type == 45 || (int)p.type == 56 || (int)p.type == 28))
{
__state = __instance.mission.runProperties;
__instance.mission.runProperties = __state.Where((RunProperty p) => (int)p.type != 58).ToList();
}
}
private static void Postfix(RunTypeButton __instance, List<RunProperty> __state)
{
if (__state == null)
{
return;
}
__instance.mission.runProperties = __state;
try
{
LoadoutService.AddControl(__instance);
}
catch (Exception error)
{
Mod.Error("Создание выбора снаряжения", error);
Mod.Notice("Не удалось создать выбор снаряжения.");
}
}
private static Exception Finalizer(RunTypeButton __instance, List<RunProperty> __state, Exception __exception)
{
if (__state != null && Object.op_Implicit((Object)(object)__instance.mission))
{
__instance.mission.runProperties = __state;
}
return __exception;
}
}
[HarmonyPatch(typeof(Overworld_InventoryItemButton), "SetupAction")]
internal static class PickerButtonPatch
{
private static void Postfix(Overworld_InventoryItemButton __instance)
{
try
{
LoadoutService.ConfigureButton(__instance);
}
catch (Exception error)
{
Mod.Error("Настройка кнопки предмета", error);
}
}
}
[HarmonyPatch(typeof(OverworldInventory), "Setup")]
internal static class PickerStockPatch
{
private static void Prefix(ref List<string> originOfItems)
{
if (LoadoutService.BuildingPicker)
{
originOfItems = new List<string>(originOfItems);
}
}
}
[HarmonyPatch(typeof(OverworldInventory), "SetupItemsForInventory")]
internal static class PickerPagePatch
{
private static void Prefix(OverworldInventory __instance, int startingNumber)
{
LoadoutService.BeginPage(__instance, startingNumber);
}
}
[HarmonyPatch(typeof(Overworld_InventoryItemButton), "RightClick")]
internal static class PickerContextPatch
{
private static bool Prefix(Overworld_InventoryItemButton __instance)
{
return !LoadoutService.IsPickerButton(__instance);
}
}
[HarmonyPatch(typeof(RunTypeSelector), "GoAdventuring2")]
internal static class DeparturePatch
{
private static bool Prefix(RunTypeSelector __instance)
{
if (!Mod.Eligible())
{
return true;
}
try
{
if (!DeparturePreparation.IsApproved(__instance))
{
DeparturePreparation.Begin(__instance);
return false;
}
LoadoutService.Depart(__instance);
DeparturePreparation.Reset();
}
catch (Exception ex)
{
DeparturePreparation.Reset();
Mod.Error("Отправка отменена", ex);
Mod.Notice("Отправка отменена: " + ex.Message);
}
return false;
}
}
[HarmonyPatch(typeof(RunTypeManager), "CreateStarterItems")]
internal static class StarterPatch
{
private static void Postfix()
{
try
{
LoadoutService.Spawn();
}
catch (Exception error)
{
Mod.Error("Выдача снаряжения", error);
Mod.Notice("Не удалось выдать всё снаряжение. Пришлите журнал мода.");
}
}
}
[HarmonyPatch(typeof(Tote), "SpawnTote")]
internal static class StarterDeckPatch
{
private static void Prefix(Tote __instance)
{
try
{
LoadoutService.SpawnCarvings(__instance);
}
catch (Exception error)
{
Mod.Error("Подготовка колоды", error);
Mod.Notice("Не удалось подготовить колоду. Пришлите журнал мода.");
}
}
}
public sealed class Mod : MelonMod
{
internal static ProgressStore Store;
internal static bool RestoreFailed;
internal static Player RestoredPlayer;
internal static bool Departing;
public override void OnInitializeMelon()
{
Store = new ProgressStore(Path.Combine(Application.persistentDataPath, "PersistentHeroesV2"));
try
{
((MelonBase)this).HarmonyInstance.PatchAll(typeof(Mod).Assembly);
MelonLogger.Msg("Persistent Heroes 0.1.4: сюжетный режим, все герои. Победа — сохранить, смерть — сброс, выход — без изменений.");
MelonLogger.Msg("Папка прогресса: " + Path.Combine(Application.persistentDataPath, "PersistentHeroesV2"));
string text = Path.Combine(Environment.CurrentDirectory, "UserData", "PersistentHeroes");
if (Directory.Exists(text))
{
Notice("Обнаружены старые данные " + text + ". Они не импортируются: результат вылазок в старом формате неизвестен.");
}
}
catch (Exception error)
{
((MelonBase)this).HarmonyInstance.UnpatchSelf();
Error("Подключение мода отменено: несовместимый API игры", error);
}
}
public override void OnSceneWasLoaded(int buildIndex, string sceneName)
{
if (sceneName == "Game")
{
RestoreFailed = false;
RestoredPlayer = null;
Departing = false;
}
if (sceneName == "Overworld" || sceneName == "MainMenu")
{
LoadoutService.Clear();
Departing = false;
}
}
internal static bool Supported()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
if (Object.op_Implicit((Object)(object)Singleton.Instance) && Singleton.Instance.storyMode && (int)Singleton.Instance.character != 0)
{
return Singleton.Instance.storyModeSlot >= 0;
}
return false;
}
internal static bool Eligible()
{
return EligibilityReason(Object.op_Implicit((Object)(object)Singleton.Instance) ? Singleton.Instance.mission : null, victory: false) == null;
}
internal static string EligibilityReason(Missions mission, bool victory)
{
if (Object.op_Implicit((Object)(object)mission) && mission.runProperties == null)
{
return "у задания отсутствует список правил: " + ((Object)mission).name;
}
return ProgressPolicy.BlockReason(Supported(), Object.op_Implicit((Object)(object)mission), Object.op_Implicit((Object)(object)mission) && mission.runProperties.Exists((RunProperty p) => (int)p.type == 56), Object.op_Implicit((Object)(object)mission) && mission.runProperties.Exists((RunProperty p) => (int)p.type == 28), Object.op_Implicit((Object)(object)mission) && mission.runProperties.Exists((RunProperty p) => (int)p.type == 42), Object.op_Implicit((Object)(object)mission) && mission.runProperties.Exists((RunProperty p) => (int)p.type == 45), victory);
}
internal static string Context()
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)Singleton.Instance))
{
return "Singleton отсутствует";
}
return string.Concat("слот=", Singleton.Instance.storyModeSlot, ", герой=", Singleton.Instance.character, ", задание=", Object.op_Implicit((Object)(object)Singleton.Instance.mission) ? ((Object)Singleton.Instance.mission).name : "отсутствует");
}
internal static void Error(string operation, Exception error)
{
string text = Context();
MelonLogger.Error(operation + "; " + text + ": " + error);
Debug.LogError((object)("[PersistentHeroes] " + operation + "; " + text + ": " + error));
}
internal static void Notice(string text)
{
MelonLogger.Warning(text);
Debug.LogWarning((object)("[PersistentHeroes] " + text));
if (Object.op_Implicit((Object)(object)PopUpManager.main))
{
PopUpManager.main.CreatePopUp(text);
}
}
}
[HarmonyPatch(typeof(Player), "SetBagSize")]
internal static class BagPatch
{
private static bool Prefix(Player __instance)
{
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
string text = Mod.EligibilityReason(Object.op_Implicit((Object)(object)Singleton.Instance) ? Singleton.Instance.mission : null, victory: false);
if (text != null || Singleton.Instance.loadSave || Singleton.Instance.doTutorial)
{
MelonLogger.Msg("Восстановление пропущено: " + (text ?? (Singleton.Instance.loadSave ? "продолжение сохранённой вылазки" : "активное обучение")) + "; " + Mod.Context());
return true;
}
if ((Object)(object)Mod.RestoredPlayer == (Object)(object)__instance)
{
return false;
}
try
{
ProgressState progressState = Mod.Store.Load(Singleton.Instance.storyModeSlot, ((object)Singleton.Instance.character).ToString());
if (progressState == null || progressState.Dead)
{
MelonLogger.Msg("Обычный старт: " + ((progressState == null) ? "ещё нет сохранённой победы" : "прогресс сброшен после смерти или удаления слота") + "; " + Mod.Context());
return true;
}
BackpackService.Restore(__instance, progressState);
Mod.RestoredPlayer = __instance;
return false;
}
catch (Exception error)
{
Mod.RestoreFailed = true;
Mod.Error("Не удалось восстановить рюкзак", error);
Mod.Notice("Не удалось восстановить прогресс. Не продолжайте вылазку; пришлите журнал мода. Старое состояние не будет перезаписано победой.");
return true;
}
}
}
[HarmonyPatch(typeof(MetaProgressSaveManager), "CompleteMission")]
internal static class VictoryPatch
{
private static void Postfix(Missions m)
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
string text = Mod.EligibilityReason(m, victory: true);
if (text != null || !Object.op_Implicit((Object)(object)Player.main) || Mod.RestoreFailed)
{
Mod.Notice("Сохранение победы пропущено: " + (text ?? ((!Object.op_Implicit((Object)(object)Player.main)) ? "нет Player" : "сетка ранее не прошла проверку")) + "; " + Mod.Context());
return;
}
try
{
ProgressState progressState = BackpackService.Capture(Player.main);
Mod.Store.Save(Singleton.Instance.storyModeSlot, ((object)Singleton.Instance.character).ToString(), progressState);
MelonLogger.Msg("Победа: слот=" + Singleton.Instance.storyModeSlot + ", уровень=" + progressState.Level + ", опыт=" + progressState.Experience + ", золото=" + progressState.Gold + ", ячеек=" + progressState.Cells.Count + ", свободных расширений=" + progressState.Spaces);
}
catch (Exception error)
{
Mod.Error("Не удалось сохранить победу", error);
Mod.Notice("Прогресс победы не сохранён. Пришлите журнал мода.");
}
}
}
[HarmonyPatch(typeof(MetaProgressSaveManager), "SaveLastRun")]
internal static class OutcomePatch
{
private static void Postfix(Result result)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Invalid comparison between Unknown and I4
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Invalid comparison between Unknown and I4
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
if (!Mod.Supported())
{
return;
}
if ((int)result == 3)
{
MelonLogger.Msg("Добровольный выход: постоянный прогресс не изменён.");
}
if ((int)result != 2)
{
return;
}
try
{
Mod.Store.Reset(Singleton.Instance.storyModeSlot, ((object)Singleton.Instance.character).ToString());
LoadStoryGame.DeleteStoryRunSave(Singleton.Instance.storyModeSlot);
MelonLogger.Msg(string.Concat("Смерть: прогресс ", Singleton.Instance.character, " сброшен в слоте ", Singleton.Instance.storyModeSlot));
}
catch (Exception error)
{
Mod.Error("Не удалось записать полный сброс после смерти", error);
Mod.Notice("Сброс после смерти не записан. Не начинайте новую вылазку; пришлите журнал.");
}
}
}
[HarmonyPatch(typeof(SaveAnItemOnLoss), "SaveItem")]
internal static class DeathItemPatch
{
private static bool Prefix()
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Invalid comparison between Unknown and I4
if (!Mod.Supported() || !Object.op_Implicit((Object)(object)MetaProgressSaveManager.main) || MetaProgressSaveManager.main.lastRun == null || (int)MetaProgressSaveManager.main.lastRun.result != 2)
{
return true;
}
MelonLogger.Msg("Смерть: возврат предмета отключён правилом полной потери.");
return false;
}
}
[HarmonyPatch(typeof(SaveAnItemOnLoss), "GetItem")]
internal static class DeathItemSelectionPatch
{
private static bool Prefix()
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Invalid comparison between Unknown and I4
if (!Mod.Supported() || !Object.op_Implicit((Object)(object)MetaProgressSaveManager.main) || MetaProgressSaveManager.main.lastRun == null || (int)MetaProgressSaveManager.main.lastRun.result != 2)
{
return true;
}
Mod.Notice("При смерти теряется всё снаряжение вылазки. Предметы, оставленные на городском складе, сохраняются.");
return false;
}
}
[HarmonyPatch(typeof(LoadStoryGame), "DeleteStorySaveFile")]
internal static class DeleteSlotPatch
{
private static void Postfix(int slotNumber)
{
try
{
Mod.Store.ResetSlot(slotNumber);
}
catch (Exception error)
{
Mod.Error("Не удалось очистить прогресс удалённого слота " + slotNumber, error);
}
}
}
internal static class PreparationUi
{
private static ReplacementText summary;
private static readonly List<GameObject> hiddenCloseButtons = new List<GameObject>();
internal static void Release()
{
foreach (GameObject hiddenCloseButton in hiddenCloseButtons)
{
if (Object.op_Implicit((Object)(object)hiddenCloseButton))
{
hiddenCloseButton.SetActive(true);
}
}
hiddenCloseButtons.Clear();
summary = null;
}
internal static void Create(OverworldInventory inventory, Action confirm, Action cancel)
{
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Expected O, but got Unknown
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
//IL_018b: Unknown result type (might be due to invalid IL or missing references)
//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
//IL_0242: Unknown result type (might be due to invalid IL or missing references)
//IL_0247: Unknown result type (might be due to invalid IL or missing references)
//IL_0284: Unknown result type (might be due to invalid IL or missing references)
//IL_029d: Unknown result type (might be due to invalid IL or missing references)
//IL_0259: Unknown result type (might be due to invalid IL or missing references)
//IL_025e: Unknown result type (might be due to invalid IL or missing references)
Button[] array = Object.FindObjectsOfType<Button>();
foreach (Button val in array)
{
for (int j = 0; j < ((UnityEventBase)val.onClick).GetPersistentEventCount(); j++)
{
if (((UnityEventBase)val.onClick).GetPersistentTarget(j) == (Object)(object)Overworld_InventoryManager.main && ((UnityEventBase)val.onClick).GetPersistentMethodName(j) == "HideInventory")
{
hiddenCloseButtons.Add(((Component)val).gameObject);
((Component)val).gameObject.SetActive(false);
break;
}
}
}
if (hiddenCloseButtons.Count == 0)
{
Debug.LogWarning((object)"[PersistentHeroes] Не найдена штатная кнопка HideInventory для замены на экране снаряжения.");
}
TextMeshProUGUI componentInChildren = ((Component)inventory).GetComponentInChildren<TextMeshProUGUI>(true);
ScrollRect componentInChildren2 = ((Component)inventory).GetComponentInChildren<ScrollRect>(true);
if (!Object.op_Implicit((Object)(object)componentInChildren) || !Object.op_Implicit((Object)(object)((TMP_Text)componentInChildren).font) || !Object.op_Implicit((Object)(object)componentInChildren2))
{
throw new InvalidOperationException("У склада отсутствует шрифт или область прокрутки: " + ((Object)inventory).name);
}
RectTransform val2 = (RectTransform)((Component)componentInChildren2).transform;
val2.offsetMin += new Vector2(0f, 190f);
RectTransform val3 = Rect("PersistentHeroesPreparation", ((Component)inventory).transform, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(40f, 80f), new Vector2(-40f, 260f));
((Component)val3).gameObject.AddComponent<LayoutElement>().ignoreLayout = true;
((Graphic)((Component)val3).gameObject.AddComponent<Image>()).color = new Color(0.12f, 0.09f, 0.07f, 0.98f);
TextMeshProUGUI text = Text((Transform)(object)val3, ((TMP_Text)componentInChildren).font, "", new Vector2(12f, 86f), new Vector2(-12f, -6f));
summary = Localize(text, "items");
AddButton((Transform)(object)val3, ((TMP_Text)componentInChildren).font, "b9", right: false, cancel);
AddButton((Transform)(object)val3, ((TMP_Text)componentInChildren).font, "b8", right: true, confirm);
LangaugeManager.main.SetFont((Transform)(object)val3);
TextMeshProUGUI[] componentsInChildren = ((Component)val3).GetComponentsInChildren<TextMeshProUGUI>();
foreach (TextMeshProUGUI val4 in componentsInChildren)
{
((TMP_Text)val4).lineSpacing = 0f;
}
Canvas.ForceUpdateCanvases();
Rect rect = val3.rect;
if (!(((Rect)(ref rect)).width < 400f))
{
Rect rect2 = val2.rect;
if (!(((Rect)(ref rect2)).height <= 0f))
{
return;
}
}
throw new InvalidOperationException(string.Concat("Недостаточно места для снаряжения: панель=", val3.rect, ", прокрутка=", val2.rect));
}
internal static void UpdateCount(int count)
{
if (Object.op_Implicit((Object)(object)summary))
{
summary.nonKeySuffix = ": " + count;
summary.ReplaceText();
}
}
private static ReplacementText Localize(TextMeshProUGUI text, string key)
{
ReplacementText val = ((Component)text).gameObject.AddComponent<ReplacementText>();
val.key = key;
val.ReplaceText();
return val;
}
private static RectTransform Rect(string name, Transform parent, Vector2 min, Vector2 max, Vector2 low, Vector2 high)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Expected O, but got Unknown
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
RectTransform val2 = (RectTransform)val.transform;
((Transform)val2).SetParent(parent, false);
val2.anchorMin = min;
val2.anchorMax = max;
val2.offsetMin = low;
val2.offsetMax = high;
return val2;
}
private static TextMeshProUGUI Text(Transform parent, TMP_FontAsset font, string value, Vector2 low, Vector2 high)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
RectTransform val = Rect("Label", parent, Vector2.zero, Vector2.one, low, high);
TextMeshProUGUI val2 = ((Component)val).gameObject.AddComponent<TextMeshProUGUI>();
((TMP_Text)val2).font = font;
((TMP_Text)val2).text = value;
((TMP_Text)val2).fontSize = 32f;
((TMP_Text)val2).alignment = (TextAlignmentOptions)514;
((Graphic)val2).raycastTarget = false;
((TMP_Text)val2).enableAutoSizing = true;
((TMP_Text)val2).fontSizeMin = 20f;
((TMP_Text)val2).fontSizeMax = 32f;
return val2;
}
private static void AddButton(Transform parent, TMP_FontAsset font, string label, bool right, Action action)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Expected O, but got Unknown
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
RectTransform val = Rect(right ? "Confirm" : "Cancel", parent, new Vector2(right ? 0.5f : 0f, 0f), new Vector2(right ? 1f : 0.5f, 0f), new Vector2(12f, 12f), new Vector2(-12f, 78f));
Image val2 = ((Component)val).gameObject.AddComponent<Image>();
((Graphic)val2).color = (right ? new Color(0.19f, 0.4f, 0.25f) : new Color(0.36f, 0.27f, 0.19f));
Button val3 = ((Component)val).gameObject.AddComponent<Button>();
((Selectable)val3).targetGraphic = (Graphic)(object)val2;
((UnityEvent)val3.onClick).AddListener((UnityAction)delegate
{
action();
});
Localize(Text((Transform)(object)val, font, "", new Vector2(10f, 4f), new Vector2(-10f, -4f)), label);
}
}
internal static class ProgressPolicy
{
public static string BlockReason(bool supported, bool hasMission, bool disabled, bool puzzle, bool tutorial, bool intro, bool victory)
{
if (!supported)
{
return "не выбран сюжетный слот и герой";
}
if (!hasMission)
{
return "нет выбранного задания";
}
if (disabled)
{
return "метапрогресс отключён правилами задания";
}
if (puzzle)
{
return "задание-головоломка";
}
if (!victory && (tutorial || intro))
{
return "старт обучения или сюжетного вступления";
}
return null;
}
}
internal sealed class CellState
{
public int X;
public int Y;
public bool Runic;
public string Key => X + ":" + Y;
}
internal sealed class ProgressState
{
public int Level = -1;
public int Experience;
public int Spaces;
public int Gold;
public bool Dead;
public List<CellState> Cells = new List<CellState>();
public List<string> Blocks = new List<string>();
public void Validate()
{
if (Level < -1 || Level > 1000 || Experience < 0 || Spaces < 0 || Spaces > 1024 || Gold < 0)
{
throw new InvalidDataException("Некорректные значения прогресса.");
}
if (!Dead)
{
if (Cells.Count == 0 || Cells.Count > 1024 || Cells.Select((CellState c) => c.Key).Distinct().Count() != Cells.Count)
{
throw new InvalidDataException("Пустая сетка, слишком много ячеек или повтор координат.");
}
if (Cells.Any((CellState c) => Math.Abs((long)c.X) > 100 || Math.Abs((long)c.Y) > 100) || Blocks.Count > 64)
{
throw new InvalidDataException("Недопустимые координаты или список блоков рюкзака.");
}
}
}
}
internal sealed class ProgressStore
{
private readonly string root;
public ProgressStore(string root)
{
this.root = root;
}
public string PathFor(int slot, string hero)
{
if (slot < 0 || string.IsNullOrEmpty(hero) || hero.Any((char c) => !char.IsLetterOrDigit(c)))
{
throw new InvalidDataException("Некорректный слот или идентификатор героя.");
}
return Path.Combine(root, "slot" + slot + "_" + hero + ".ph2");
}
public ProgressState Load(int slot, string hero)
{
string text = PathFor(slot, hero);
if (!File.Exists(text))
{
return null;
}
using FileStream fileStream = File.OpenRead(text);
using BinaryReader binaryReader = new BinaryReader(fileStream);
if (binaryReader.ReadString() != "PH02" || binaryReader.ReadInt32() != 1)
{
throw new InvalidDataException("Неподдерживаемый формат прогресса: " + text);
}
ProgressState progressState = new ProgressState();
progressState.Dead = binaryReader.ReadBoolean();
progressState.Level = binaryReader.ReadInt32();
progressState.Experience = binaryReader.ReadInt32();
progressState.Spaces = binaryReader.ReadInt32();
progressState.Gold = binaryReader.ReadInt32();
ProgressState progressState2 = progressState;
int num = binaryReader.ReadInt32();
if (num < 0 || num > 1024)
{
throw new InvalidDataException("Некорректное число ячеек.");
}
for (int i = 0; i < num; i++)
{
progressState2.Cells.Add(new CellState
{
X = binaryReader.ReadInt32(),
Y = binaryReader.ReadInt32(),
Runic = binaryReader.ReadBoolean()
});
}
num = binaryReader.ReadInt32();
if (num < 0 || num > 64)
{
throw new InvalidDataException("Некорректное число блоков.");
}
for (int j = 0; j < num; j++)
{
progressState2.Blocks.Add(binaryReader.ReadString());
}
if (fileStream.Position != fileStream.Length)
{
throw new InvalidDataException("Лишние данные в файле прогресса.");
}
progressState2.Validate();
return progressState2;
}
public void Save(int slot, string hero, ProgressState state)
{
state.Validate();
string text = PathFor(slot, hero);
Directory.CreateDirectory(root);
string text2 = text + ".tmp";
using (FileStream fileStream = new FileStream(text2, FileMode.Create, FileAccess.Write, FileShare.None))
{
using BinaryWriter binaryWriter = new BinaryWriter(fileStream);
binaryWriter.Write("PH02");
binaryWriter.Write(1);
binaryWriter.Write(state.Dead);
binaryWriter.Write(state.Level);
binaryWriter.Write(state.Experience);
binaryWriter.Write(state.Spaces);
binaryWriter.Write(state.Gold);
binaryWriter.Write(state.Cells.Count);
foreach (CellState cell in state.Cells)
{
binaryWriter.Write(cell.X);
binaryWriter.Write(cell.Y);
binaryWriter.Write(cell.Runic);
}
binaryWriter.Write(state.Blocks.Count);
foreach (string block in state.Blocks)
{
binaryWriter.Write(block);
}
binaryWriter.Flush();
fileStream.Flush(flushToDisk: true);
}
if (File.Exists(text))
{
File.Replace(text2, text, null);
}
else
{
File.Move(text2, text);
}
}
public void Reset(int slot, string hero)
{
Save(slot, hero, new ProgressState
{
Dead = true
});
}
public void ResetSlot(int slot)
{
if (slot < 0)
{
throw new InvalidDataException("Некорректный слот.");
}
if (Directory.Exists(root))
{
string text = "slot" + slot + "_";
string[] files = Directory.GetFiles(root, text + "*.ph2");
foreach (string path in files)
{
Reset(slot, Path.GetFileNameWithoutExtension(path).Substring(text.Length));
}
}
}
}
internal sealed class LoadoutSelection
{
private readonly Dictionary<string, HashSet<int>> copies = new Dictionary<string, HashSet<int>>(StringComparer.Ordinal);
public int Count => copies.Values.Sum((HashSet<int> x) => x.Count);
public int Get(string key)
{
if (!copies.TryGetValue(key, out var value))
{
return 0;
}
return value.Count;
}
public bool Contains(string key, int copy)
{
if (copies.TryGetValue(key, out var value))
{
return value.Contains(copy);
}
return false;
}
public void Clear()
{
copies.Clear();
}
public void Toggle(string key, int copy, IList<string> stock)
{
if (copy < 0 || copy >= stock.Count((string x) => x == key))
{
throw new InvalidOperationException("На складе нет экземпляра: " + key + ", номер=" + copy);
}
if (!copies.TryGetValue(key, out var value))
{
value = new HashSet<int>();
copies.Add(key, value);
}
if (!value.Add(copy))
{
value.Remove(copy);
}
if (value.Count == 0)
{
copies.Remove(key);
}
}
public List<string> Selected()
{
return copies.SelectMany((KeyValuePair<string, HashSet<int>> pair) => Enumerable.Repeat(pair.Key, pair.Value.Count)).ToList();
}
public List<string> Remaining(IList<string> normalizedStock)
{
foreach (KeyValuePair<string, HashSet<int>> pair in copies)
{
KeyValuePair<string, HashSet<int>> keyValuePair = pair;
if (keyValuePair.Value.Any((int copy) => copy >= normalizedStock.Count(delegate(string x)
{
KeyValuePair<string, HashSet<int>> keyValuePair3 = pair;
return x == keyValuePair3.Key;
})))
{
KeyValuePair<string, HashSet<int>> keyValuePair2 = pair;
throw new InvalidOperationException("Состав склада изменился: " + keyValuePair2.Key);
}
}
List<string> list = normalizedStock.ToList();
foreach (string item in Selected())
{
if (!list.Remove(item))
{
throw new InvalidOperationException("Состав склада изменился: " + item);
}
}
return list;
}
}
[HarmonyPatch(typeof(GameManager), "EndBattle")]
internal static class RewardLabelPatch
{
private static void Prefix(GameManager __instance)
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Expected O, but got Unknown
if (Object.op_Implicit((Object)(object)GameFlowManager.main) && GameFlowManager.main.combatEndedAbruptly)
{
return;
}
try
{
GameObject val = (GameObject)AccessTools.Field(typeof(GameManager), "afterBattleButton").GetValue(__instance);
TextMeshProUGUI val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponentInChildren<TextMeshProUGUI>(true) : null);
if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)LangaugeManager.main))
{
throw new InvalidOperationException("Не найдена кнопка награды или менеджер перевода.");
}
((TMP_Text)val2).text = LangaugeManager.main.GetTextByKey("gm14");
}
catch (Exception error)
{
Mod.Error("Перевод кнопки награды, ключ=gm14", error);
}
}
}
internal static class SelectionMarkerUi
{
private const string MarkerName = "PersistentHeroesSelection";
private static readonly Color SelectedColor = new Color(0.3f, 0.91f, 0.53f, 1f);
internal static void Refresh(Overworld_InventoryItemButton card, bool selected)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//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_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: Unknown result type (might be due to invalid IL or missing references)
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
Transform val = ((Component)card).transform.Find("PersistentHeroesSelection");
if (!Object.op_Implicit((Object)(object)val))
{
RectTransform val2 = Rect("PersistentHeroesSelection", ((Component)card).transform, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
((Component)val2).gameObject.AddComponent<LayoutElement>().ignoreLayout = true;
Edge((Transform)(object)val2, "Left", Vector2.zero, new Vector2(0f, 1f), Vector2.zero, new Vector2(5f, 0f));
Edge((Transform)(object)val2, "Right", new Vector2(1f, 0f), Vector2.one, new Vector2(-5f, 0f), Vector2.zero);
Edge((Transform)(object)val2, "Bottom", Vector2.zero, new Vector2(1f, 0f), Vector2.zero, new Vector2(0f, 5f));
Edge((Transform)(object)val2, "Top", new Vector2(0f, 1f), Vector2.one, new Vector2(0f, -5f), Vector2.zero);
val = (Transform)(object)val2;
}
((Component)val).gameObject.SetActive(selected);
val.SetAsLastSibling();
}
private static void Edge(Transform parent, string name, Vector2 min, Vector2 max, Vector2 low, Vector2 high)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
Image val = ((Component)Rect(name, parent, min, max, low, high)).gameObject.AddComponent<Image>();
((Graphic)val).color = SelectedColor;
((Graphic)val).raycastTarget = false;
}
private static RectTransform Rect(string name, Transform parent, Vector2 min, Vector2 max, Vector2 low, Vector2 high)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Expected O, but got Unknown
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) }).transform;
((Transform)val).SetParent(parent, false);
val.anchorMin = min;
val.anchorMax = max;
val.offsetMin = low;
val.offsetMax = high;
return val;
}
}