using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using Bifrost.Cooked;
using Bifrost.ShopGroup;
using CrowbarShop;
using HarmonyLib;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using Mimic;
using Mimic.Actors;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyTitle("CrowbarShop")]
[assembly: AssemblyProduct("CrowbarShop")]
[assembly: AssemblyCompany("dsh")]
[assembly: MelonInfo(typeof(Core), "CrowbarShop", "0.1.0", "dsh", null)]
[assembly: MelonGame("ReLUGames", "MIMESIS")]
[assembly: HarmonyDontPatchAll]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace CrowbarShop
{
public sealed class Core : MelonMod
{
private float _timer;
public override void OnInitializeMelon()
{
ModPreferences.Initialize();
ApplyPatches();
MelonLogger.Msg("[CrowbarShop] loaded");
}
private void ApplyPatches()
{
int num = 0;
Type[] types = typeof(Core).Assembly.GetTypes();
foreach (Type type in types)
{
if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).Any())
{
try
{
((MelonBase)this).HarmonyInstance.PatchAll(type);
num++;
}
catch (Exception arg)
{
MelonLogger.Error($"[CrowbarShop] 补丁 {type.Name} 应用失败:{arg}");
}
}
}
MelonLogger.Msg($"[CrowbarShop] Harmony 补丁:{num} 个类,{((MelonBase)this).HarmonyInstance.GetPatchedMethods().Count()} 个方法。");
}
public override void OnUpdate()
{
if (!((Object)(object)Hub.s == (Object)null))
{
_timer += Time.unscaledDeltaTime;
if (!(_timer < 1f))
{
_timer = 0f;
ShopGroupInjector.EnsureInjected();
CrowbarUnlock.Apply();
CrowbarCombatTuning.Apply();
}
}
}
}
[HarmonyPatch(typeof(MaintenanceScene), "Start")]
internal static class MaintenanceSceneStartPatch
{
private static void Prefix(MaintenanceScene __instance)
{
try
{
ShopGroupInjector.EnsureInjected();
CrowbarUnlock.Apply();
CrowbarCombatTuning.Apply();
VendingMachineSpawner.Spawn(__instance);
}
catch (Exception arg)
{
MelonLogger.Error($"[CrowbarShop] 放置撬棒售货机失败:{arg}");
}
}
}
internal static class CrowbarCombatTuning
{
private static bool _applied;
internal static void Apply()
{
if (!_applied)
{
ExcelDataManager excelDataManager = ShopGroupInjector.GetExcelDataManager();
if (excelDataManager != null)
{
_applied = true;
ApplySequence(excelDataManager);
ApplyDamage(excelDataManager);
ApplyCooldown(excelDataManager);
}
}
}
private static void ApplySequence(ExcelDataManager excel)
{
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
SkillSequenceInfo val = default(SkillSequenceInfo);
if (!excel.SkillSequenceInfoDict.TryGetValue(18006, ref val) || val == null)
{
MelonLogger.Warning($"[CrowbarShop] 找不到技能序列 {18006}。");
return;
}
try
{
if (ModPreferences.HitFeedback)
{
SetField(typeof(SkillSequenceInfo), val, "SkillTagetEffectId", 40007);
AbnormalInfo val2 = default(AbnormalInfo);
if (excel.AbnormalDict.TryGetValue(18006, ref val2) && val2 != null)
{
Enumerator<int, IAbnormalElementInfo> enumerator = val2.ElementList.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
IAbnormalElementInfo value = enumerator.Current.Value;
if (value != null && value.SkillTargetEffectId == 40008)
{
SetField(typeof(IAbnormalElementInfo), value, "SkillTargetEffectId", 0);
}
}
}
finally
{
((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
}
}
}
SetField(typeof(SkillSequenceInfo), val, "MutableValue", -ModPreferences.EffectiveDamage);
if (ModPreferences.HitStun && !val.AbnormalMasterIDs.Contains(20001))
{
val.AbnormalMasterIDs = val.AbnormalMasterIDs.Add(20001);
}
MelonLogger.Msg($"[CrowbarShop] 撬棍序列 {18006}:伤害 {ModPreferences.EffectiveDamage}({ModPreferences.Damage}×{ModPreferences.DamageMultiplier},走 ActiveAttack 结算),冷却 {ModPreferences.EffectiveCooldownMs}ms,反馈 {40007},硬直 {ModPreferences.HitStun}");
}
catch (Exception ex)
{
MelonLogger.Warning("[CrowbarShop] 调整撬棍序列失败:" + ex.Message);
}
}
private static void ApplyDamage(ExcelDataManager excel)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Invalid comparison between Unknown and I4
AbnormalInfo val = default(AbnormalInfo);
if (!excel.AbnormalDict.TryGetValue(18006, ref val) || val == null)
{
return;
}
try
{
Enumerator<int, IAbnormalElementInfo> enumerator = val.ElementList.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
IAbnormalElementInfo value = enumerator.Current.Value;
AbnormalStatsElementInfo val2 = (AbnormalStatsElementInfo)(object)((value is AbnormalStatsElementInfo) ? value : null);
if (val2 != null && (int)val2.MutableStatType == 1)
{
SetField(typeof(AbnormalStatsElementInfo), val2, "Value", 0L);
}
}
}
finally
{
((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
}
}
catch (Exception ex)
{
MelonLogger.Warning("[CrowbarShop] 调整撬棍伤害失败:" + ex.Message);
}
}
private static void ApplyCooldown(ExcelDataManager excel)
{
SkillInfo val = default(SkillInfo);
if (!excel.SkillInfoDict.TryGetValue(10806, ref val) || val == null)
{
return;
}
try
{
SetField(typeof(SkillInfo), val, "Cooltime", ModPreferences.EffectiveCooldownMs);
}
catch (Exception ex)
{
MelonLogger.Warning("[CrowbarShop] 调整撬棍冷却失败:" + ex.Message);
}
}
private static void SetField(Type type, object instance, string name, object value)
{
FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field == null)
{
MelonLogger.Warning("[CrowbarShop] 找不到字段 " + type.Name + "." + name + "。");
}
else
{
field.SetValue(instance, value);
}
}
}
internal sealed class CrowbarDisplay : MonoBehaviour
{
private static readonly FieldInfo? ItemRootField = AccessTools.Field(typeof(VendingMachineLevelObject), "vendingMachineItemRoot");
private static readonly FieldInfo? VanillaRootField = AccessTools.Field(typeof(VendingMachineLevelObject), "vendingMachineVanillaRoot");
private Transform? _itemRoot;
private Transform? _vanillaRoot;
private GameObject? _item;
private float _timer;
internal static void Attach(VendingMachineLevelObject machine)
{
try
{
CrowbarDisplay crowbarDisplay = ((Component)machine).gameObject.AddComponent<CrowbarDisplay>();
ref Transform? itemRoot = ref crowbarDisplay._itemRoot;
object? obj = ItemRootField?.GetValue(machine);
itemRoot = (Transform?)((obj is Transform) ? obj : null);
ref Transform? vanillaRoot = ref crowbarDisplay._vanillaRoot;
object? obj2 = VanillaRootField?.GetValue(machine);
vanillaRoot = (Transform?)((obj2 is Transform) ? obj2 : null);
if ((Object)(object)crowbarDisplay._itemRoot == (Object)null)
{
MelonLogger.Warning("[CrowbarShop] 找不到 vendingMachineItemRoot,陈列物品可能显示不正确。");
}
}
catch (Exception ex)
{
MelonLogger.Warning("[CrowbarShop] 挂载陈列显示失败:" + ex.Message);
}
}
private void Update()
{
_timer += Time.unscaledDeltaTime;
if (_timer < 0.25f)
{
return;
}
_timer = 0f;
if ((Object)(object)_itemRoot == (Object)null)
{
return;
}
if ((Object)(object)_vanillaRoot != (Object)null && ((Component)_vanillaRoot).gameObject.activeSelf)
{
((Component)_vanillaRoot).gameObject.SetActive(false);
}
if ((Object)(object)_item != (Object)null)
{
return;
}
GameMainBase main = Hub.Main;
if ((Object)(object)main == (Object)null)
{
return;
}
try
{
_item = main.TrySpawnItemObject(2900, _itemRoot).Item2;
if ((Object)(object)_item != (Object)null)
{
ModPreferences.Log("[CrowbarShop] 陈列物品已生成:" + ((Object)_item).name);
}
}
catch (Exception ex)
{
MelonLogger.Warning("[CrowbarShop] 陈列物品生成失败:" + ex.Message);
}
}
}
internal static class CrowbarUnlock
{
private static bool _applied;
internal static void Apply()
{
if (_applied || !ModPreferences.UnlockCrowbar)
{
return;
}
ExcelDataManager excelDataManager = ShopGroupInjector.GetExcelDataManager();
if (excelDataManager == null)
{
return;
}
ItemMasterInfo itemInfo = excelDataManager.GetItemInfo(2900);
if (itemInfo == null)
{
return;
}
_applied = true;
try
{
FieldInfo field = typeof(ItemMasterInfo).GetField("ForbidChange", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field == null)
{
MelonLogger.Warning("[CrowbarShop] 找不到 ItemMasterInfo.ForbidChange 字段,改用捡取补丁兜底。");
return;
}
field.SetValue(itemInfo, false);
MelonLogger.Msg($"[CrowbarShop] 已解除撬棒 ForbidChange(当前值 {field.GetValue(itemInfo)})");
}
catch (Exception ex)
{
MelonLogger.Warning("[CrowbarShop] 改写 ForbidChange 失败:" + ex.Message + "(使用捡取补丁兜底)");
}
}
}
internal static class Constants
{
internal const int CrowbarMasterId = 2900;
internal const int ShopGroupId = 990001;
internal const int CrowbarSkillId = 10806;
internal const int CrowbarSequenceId = 18006;
internal const int CrowbarAbnormalId = 18006;
internal const int HitEffectFrom = 40008;
internal const int HitEffectTo = 40007;
internal const int HitStunAbnormalId = 20001;
internal const string RoomAnchors = "bg_Maintenance=Vending machine_electricflyswatter,-1.8,0,0; bg_Maintenance_b_a=Vending machine_flash,-1.8,0,0; bg_Maintenance_c=Vending machine_electricflyswatter,-1.8,0,0";
internal const string RoomPositions = "bg_Maintenance_d=-13.88,0,29.39,180";
internal const float DefaultOffsetX = 1.8f;
internal const float ItemYOffset = 0.2f;
internal const float ItemXRotation = 60f;
internal const float ItemScale = 1.5f;
}
internal static class ModPreferences
{
private const string CategoryId = "CrowbarShop";
private const string CategoryDisplayName = "CrowbarShop";
private static MelonPreferences_Category? _category;
private static MelonPreferences_Entry<bool>? _enabled;
private static MelonPreferences_Entry<bool>? _verbose;
private static MelonPreferences_Entry<int>? _price;
private static MelonPreferences_Entry<int>? _damage;
private static MelonPreferences_Entry<float>? _damageMultiplier;
private static MelonPreferences_Entry<int>? _attackCooldownMs;
private static MelonPreferences_Entry<float>? _cooldownMultiplier;
private static MelonPreferences_Entry<bool>? _hitFeedback;
private static MelonPreferences_Entry<bool>? _hitStun;
private static MelonPreferences_Entry<bool>? _unlockCrowbar;
private static MelonPreferences_Entry<string>? _monsterDamageMultipliers;
private static MelonPreferences_Entry<string>? _placement;
internal static bool Enabled => Entry(ref _enabled).Value;
internal static bool Verbose => Entry(ref _verbose).Value;
internal static int Price => Math.Max(0, Entry(ref _price).Value);
internal static int Damage => Math.Max(1, Entry(ref _damage).Value);
internal static float DamageMultiplier => Mathf.Clamp(Entry(ref _damageMultiplier).Value, 0.01f, 100f);
internal static int AttackCooldownMs => Math.Max(50, Entry(ref _attackCooldownMs).Value);
internal static float CooldownMultiplier => Mathf.Clamp(Entry(ref _cooldownMultiplier).Value, 0.05f, 100f);
internal static bool HitFeedback => Entry(ref _hitFeedback).Value;
internal static bool HitStun => Entry(ref _hitStun).Value;
internal static bool UnlockCrowbar => Entry(ref _unlockCrowbar).Value;
internal static string MonsterDamageMultipliers => Entry(ref _monsterDamageMultipliers).Value;
internal static string Placement => Entry(ref _placement).Value;
internal static int EffectiveDamage => Math.Max(1, (int)Math.Round((float)Damage * DamageMultiplier));
internal static int EffectiveCooldownMs => Math.Max(50, (int)Math.Round((float)AttackCooldownMs * CooldownMultiplier));
internal static void Initialize()
{
if (_category == null)
{
_category = MelonPreferences.CreateCategory("CrowbarShop", "CrowbarShop");
_enabled = CreateEntry("Enabled", defaultValue: true, "Enabled", "Add a crowbar vending machine and crowbar combat tweaks.");
_verbose = CreateEntry("Verbose", defaultValue: false, "Verbose logging", "Log injections, placement and damage calculations.");
_price = CreateEntry("Price", 488, "Crowbar price", "Price shown on the vending machine.");
_damage = CreateEntry("Damage", 90, "Crowbar damage", "Base HP damage per crowbar hit.");
_damageMultiplier = CreateEntry("DamageMultiplier", 0.6f, "Damage multiplier", "Final damage = Damage x DamageMultiplier.");
_attackCooldownMs = CreateEntry("AttackCooldownMs", 850, "Attack cooldown (ms)", "Base crowbar swing cooldown in milliseconds.");
_cooldownMultiplier = CreateEntry("CooldownMultiplier", 1f, "Cooldown multiplier", "Final cooldown = AttackCooldownMs x CooldownMultiplier.");
_hitFeedback = CreateEntry("HitFeedback", defaultValue: true, "Hit sound / effect", "Play the teddy bat hit sound and VFX on every crowbar hit.");
_hitStun = CreateEntry("HitStun", defaultValue: true, "Hit stun", "Add the teddy bat flinch abnormal to crowbar hits.");
_unlockCrowbar = CreateEntry("UnlockCrowbar", defaultValue: true, "Unlock crowbar restriction", "Remove the 'put this item down first' restriction while holding the crowbar.");
_monsterDamageMultipliers = CreateEntry("MonsterDamageMultipliers", "", "Per-monster damage multipliers", "Format: mimic=1.5; HeavyD=0.5. Match by MonsterData name. Default 1.0.");
_placement = CreateEntry("Placement", "NextToExisting", "Placement mode (NextToExisting / ReplaceExisting)", "NextToExisting clones an existing vending machine next to the anchor; ReplaceExisting changes an existing machine instead.");
}
}
internal static void Log(string message)
{
if (Verbose)
{
MelonLogger.Msg(message);
}
}
internal static float GetMonsterDamageMultiplier(string? monsterName)
{
string monsterDamageMultipliers = MonsterDamageMultipliers;
if (string.IsNullOrWhiteSpace(monsterDamageMultipliers) || string.IsNullOrEmpty(monsterName))
{
return 1f;
}
string[] array = monsterDamageMultipliers.Split(';');
for (int i = 0; i < array.Length; i++)
{
string[] array2 = array[i].Split('=');
if (array2.Length == 2 && string.Equals(array2[0].Trim(), monsterName, StringComparison.OrdinalIgnoreCase) && float.TryParse(array2[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
{
return Mathf.Clamp(result, 0f, 100f);
}
}
return 1f;
}
private static MelonPreferences_Entry<T> Entry<T>(ref MelonPreferences_Entry<T>? field)
{
if (field == null)
{
throw new InvalidOperationException("ModPreferences.Initialize() must run first.");
}
return field;
}
private static MelonPreferences_Entry<T> CreateEntry<T>(string identifier, T defaultValue, string displayName, string? description = null)
{
if (_category == null)
{
throw new InvalidOperationException("Preference category not initialized.");
}
return _category.CreateEntry<T>(identifier, defaultValue, displayName, description, false, false, (ValueValidator)null, (string)null);
}
}
[HarmonyPatch(typeof(LootingLevelObject), "CanGrap")]
internal static class CanGrapPatch
{
private static bool Prefix(ProtoActor protoActor, ref bool __result)
{
if (!ModPreferences.UnlockCrowbar)
{
return true;
}
try
{
InventoryItem val = ((protoActor != null) ? protoActor.GetSelectedInventoryItem() : null);
if (((val != null) ? val.MasterInfo : null) != null && val.MasterInfo.MasterID == 2900)
{
__result = true;
return false;
}
}
catch
{
}
return true;
}
}
internal static class ShopGroupInjector
{
private static bool _injected;
internal static bool EnsureInjected()
{
//IL_001b: 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_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Expected O, but got Unknown
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Expected O, but got Unknown
if (_injected)
{
return true;
}
ExcelDataManager excelDataManager = GetExcelDataManager();
if (excelDataManager == null)
{
return false;
}
try
{
int num = 990001;
ShopGroup_MasterData val = new ShopGroup_MasterData
{
id = num,
item_masterid = 2900,
item_price = ModPreferences.Price
};
val.ShopGroup_rateval.Add(new ShopGroup_rate
{
item_rate = 10000,
discount_ratio = 0
});
ImmutableDictionary<int, ShopGroup_MasterData> val2 = excelDataManager.ShopGroupDict.SetItem(num, val);
MethodInfo methodInfo = typeof(ExcelDataManager).GetProperty("ShopGroupDict", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetSetMethod(nonPublic: true);
if (methodInfo == null)
{
MelonLogger.Error("[CrowbarShop] ExcelDataManager.ShopGroupDict 不可写,无法注入商店组。");
return false;
}
methodInfo.Invoke(excelDataManager, new object[1] { val2 });
_injected = true;
MelonLogger.Msg($"[CrowbarShop] 商店组 {num}:物品 {2900},价格 {ModPreferences.Price}");
return true;
}
catch (Exception arg)
{
MelonLogger.Error($"[CrowbarShop] 注入商店组失败:{arg}");
return false;
}
}
internal static ExcelDataManager? GetExcelDataManager()
{
Hub s = Hub.s;
if ((Object)(object)s == (Object)null)
{
return null;
}
object obj = null;
try
{
obj = AccessTools.Property(typeof(Hub), "dataman")?.GetValue(s);
}
catch
{
}
if (obj == null)
{
try
{
obj = AccessTools.Field(typeof(Hub), "<dataman>k__BackingField")?.GetValue(s);
}
catch
{
}
}
object obj4 = ((obj is DataManager) ? obj : null);
if (obj4 == null)
{
return null;
}
return ((DataManager)obj4).ExcelDataManager;
}
}
internal static class VendingMachineSpawner
{
private const string MachineObjectName = "CrowbarShopMachine";
private static readonly FieldInfo? RoomRootField = AccessTools.Field(typeof(MaintenanceScene), "maintenanceRoomRoot");
private static readonly FieldInfo? ItemRootField = AccessTools.Field(typeof(VendingMachineLevelObject), "vendingMachineItemRoot");
private static GameObject? _template;
private static string _templateLevelObjectName = string.Empty;
internal static void Spawn(MaintenanceScene scene)
{
//IL_01a1: 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_01b1: Unknown result type (might be due to invalid IL or missing references)
//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Unknown result type (might be due to invalid IL or missing references)
//IL_0141: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0153: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
if (!ModPreferences.Enabled || (Object)(object)scene == (Object)null || !ShopGroupInjector.EnsureInjected())
{
return;
}
object? obj = RoomRootField?.GetValue(scene);
Transform val = (Transform)((obj is Transform) ? obj : null);
if ((Object)(object)val == (Object)null)
{
MelonLogger.Warning("[CrowbarShop] 找不到 maintenanceRoomRoot,跳过。");
return;
}
VendingMachineLevelObject[] componentsInChildren = ((Component)val).GetComponentsInChildren<VendingMachineLevelObject>(true);
if (componentsInChildren == null || componentsInChildren.Length == 0)
{
SpawnWithoutAnchor(val);
return;
}
if (ModPreferences.Verbose)
{
MelonLogger.Msg($"[CrowbarShop] 房间 '{((Object)val).name}':{componentsInChildren.Length} 台售货机");
}
if (string.Equals(ModPreferences.Placement, "ReplaceExisting", StringComparison.OrdinalIgnoreCase))
{
VendingMachineLevelObject val2 = PickAnchor(componentsInChildren);
if (!((Object)(object)val2 == (Object)null))
{
val2.shopGroupID = 990001;
MelonLogger.Msg($"[CrowbarShop] 已把 '{((Object)val2).name}' 改为撬棒售货机(组 {990001},价格 {ModPreferences.Price})");
}
return;
}
if ((Object)(object)val.Find("CrowbarShopMachine") != (Object)null)
{
ModPreferences.Log("[CrowbarShop] 撬棒售货机已存在,跳过。");
return;
}
VendingMachineLevelObject val3 = PickAnchor(componentsInChildren);
if (!((Object)(object)val3 == (Object)null))
{
string levelObjectName = ((LevelObject)val3).levelObjectName;
GameObject val4 = Object.Instantiate<GameObject>(((Component)val3).gameObject, val, true);
((Object)val4).name = "CrowbarShopMachine";
if (TryGetRoomAnchor(val, out Transform anchor, out Vector3 offset, out float yaw))
{
Quaternion rotation = anchor.rotation;
val4.transform.SetPositionAndRotation(anchor.position + rotation * offset, rotation * Quaternion.Euler(0f, yaw, 0f));
}
else
{
Vector3 val5 = default(Vector3);
((Vector3)(ref val5))..ctor(1.8f, 0f, 0f);
val4.transform.SetPositionAndRotation(((Component)val3).transform.position + ((Component)val3).transform.rotation * val5, ((Component)val3).transform.rotation);
}
ConfigureMachine(val4, ((Object)val3).name, levelObjectName);
CacheTemplate(((Component)val3).gameObject);
}
}
private static void ConfigureMachine(GameObject clone, string anchorName, string? levelObjectName)
{
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
VendingMachineLevelObject component = clone.GetComponent<VendingMachineLevelObject>();
if ((Object)(object)component == (Object)null)
{
Object.Destroy((Object)(object)clone);
MelonLogger.Warning("[CrowbarShop] 克隆出来的物体上没有 VendingMachineLevelObject,已销毁。");
return;
}
component.shopGroupID = 990001;
((LevelObject)component).levelObjectName = "CrowbarShopMachine";
if (!string.IsNullOrEmpty(levelObjectName) && levelObjectName != "CrowbarShopMachine")
{
RewriteStateActions(component, levelObjectName, "CrowbarShopMachine");
}
object? obj = ItemRootField?.GetValue(component);
Transform val = (Transform)((obj is Transform) ? obj : null);
if (val != null)
{
val.localPosition += Vector3.up * 0.2f;
val.eulerAngles = new Vector3(60f, 0f, 0f);
val.localScale = Vector3.one * 1.5f;
}
CrowbarDisplay.Attach(component);
MelonLogger.Msg($"[CrowbarShop] 在 '{anchorName}' 旁边放置撬棒售货机:pos={clone.transform.position},价格 {ModPreferences.Price}");
}
private static void RewriteStateActions(VendingMachineLevelObject machine, string oldName, string newName)
{
int num = 0;
foreach (Dictionary<int, StateActionInfo> value in ((LevelObject)machine).StateActionsMap.Values)
{
foreach (StateActionInfo value2 in value.Values)
{
if (!string.IsNullOrEmpty(value2.action) && value2.action.Contains(oldName))
{
value2.action = value2.action.Replace(oldName, newName);
num++;
}
if (!string.IsNullOrEmpty(value2.condition) && value2.condition.Contains(oldName))
{
value2.condition = value2.condition.Replace(oldName, newName);
}
}
}
MelonLogger.Msg($"[CrowbarShop] state action 名字重写:'{oldName}' -> '{newName}'({num} 条)");
}
private static VendingMachineLevelObject? PickAnchor(VendingMachineLevelObject[] machines)
{
return ((IEnumerable<VendingMachineLevelObject>)machines).LastOrDefault((Func<VendingMachineLevelObject, bool>)((VendingMachineLevelObject machine) => (Object)(object)machine != (Object)null));
}
private static void CacheTemplate(GameObject source)
{
if ((Object)(object)_template != (Object)null || (Object)(object)source == (Object)null)
{
return;
}
try
{
GameObject obj = Object.Instantiate<GameObject>(source);
((Object)obj).name = "CrowbarShopTemplate";
obj.SetActive(false);
Object.DontDestroyOnLoad((Object)(object)obj);
_template = obj;
_templateLevelObjectName = ((LevelObject)(source.GetComponent<VendingMachineLevelObject>()?)).levelObjectName ?? string.Empty;
ModPreferences.Log("[CrowbarShop] 已缓存售货机模板。");
}
catch (Exception ex)
{
MelonLogger.Warning("[CrowbarShop] 缓存售货机模板失败:" + ex.Message);
}
}
private static void SpawnWithoutAnchor(Transform roomRoot)
{
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)roomRoot.Find("CrowbarShopMachine") != (Object)null)
{
return;
}
if (!TryGetRoomPosition(((Object)roomRoot).name, out var position, out var yaw))
{
MelonLogger.Warning("[CrowbarShop] 房间 '" + ((Object)roomRoot).name + "' 里没有售货机,且没有预置坐标,跳过。");
return;
}
if ((Object)(object)_template == (Object)null)
{
MelonLogger.Warning("[CrowbarShop] 房间 '" + ((Object)roomRoot).name + "' 需要模板,但还没有缓存(请先进一次有售货机的房间)。");
return;
}
try
{
GameObject obj = Object.Instantiate<GameObject>(_template, roomRoot, true);
((Object)obj).name = "CrowbarShopMachine";
obj.SetActive(true);
obj.transform.SetPositionAndRotation(position, Quaternion.Euler(0f, yaw, 0f));
ConfigureMachine(obj, ((Object)roomRoot).name, _templateLevelObjectName);
}
catch (Exception arg)
{
MelonLogger.Error($"[CrowbarShop] 用模板放置失败:{arg}");
}
}
private static bool TryGetRoomAnchor(Transform roomRoot, out Transform anchor, out Vector3 offset, out float yaw)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
anchor = null;
offset = Vector3.zero;
yaw = 0f;
string[] array = "bg_Maintenance=Vending machine_electricflyswatter,-1.8,0,0; bg_Maintenance_b_a=Vending machine_flash,-1.8,0,0; bg_Maintenance_c=Vending machine_electricflyswatter,-1.8,0,0".Split(';');
foreach (string obj in array)
{
string[] array2 = obj.Split('=');
if (array2.Length == 2 && string.Equals(array2[0].Trim(), ((Object)roomRoot).name, StringComparison.OrdinalIgnoreCase))
{
string[] array3 = array2[1].Split(',');
if (array3.Length < 4)
{
return false;
}
string targetName = array3[0].Trim();
if (!TryParseNumbers(string.Join(",", array3.Skip(1)), out offset, out yaw))
{
return false;
}
Transform[] componentsInChildren = ((Component)roomRoot).GetComponentsInChildren<Transform>(true);
Transform val = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => string.Equals(((Object)t).name, targetName, StringComparison.OrdinalIgnoreCase))) ?? ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name.IndexOf(targetName, StringComparison.OrdinalIgnoreCase) >= 0));
if ((Object)(object)val == (Object)null)
{
return false;
}
anchor = val;
return true;
}
}
return false;
}
private static bool TryGetRoomPosition(string roomName, out Vector3 position, out float yaw)
{
//IL_0001: 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)
position = Vector3.zero;
yaw = 0f;
string[] array = "bg_Maintenance_d=-13.88,0,29.39,180".Split(';');
for (int i = 0; i < array.Length; i++)
{
string[] array2 = array[i].Split('=');
if (array2.Length == 2 && string.Equals(array2[0].Trim(), roomName, StringComparison.OrdinalIgnoreCase))
{
return TryParseNumbers(array2[1], out position, out yaw);
}
}
return false;
}
private static bool TryParseNumbers(string text, out Vector3 offset, out float yaw)
{
//IL_0001: 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_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
offset = Vector3.zero;
yaw = 0f;
string[] array = (from v in text.Split(',')
select v.Trim() into v
where v.Length > 0
select v).ToArray();
if (array.Length < 3)
{
return false;
}
float[] array2 = new float[array.Length];
for (int num = 0; num < array.Length; num++)
{
if (!float.TryParse(array[num], NumberStyles.Float, CultureInfo.InvariantCulture, out array2[num]))
{
return false;
}
}
offset = new Vector3(array2[0], array2[1], array2[2]);
yaw = ((array2.Length >= 4) ? array2[3] : 0f);
return true;
}
}
}
namespace CrowbarShop.Patches
{
[HarmonyPatch(typeof(AbnormalController), "ApplyAbnormalInternal")]
internal static class CrowbarCasterPatch
{
private static void Prefix(AbnormalController __instance, ref int casterObjectID, AbnormalInfo? info)
{
if (info == null || info.MasterID != 18006)
{
return;
}
try
{
VCreature victim = __instance.Self;
IVroom val = ((VActor)(victim?)).VRoom;
if (victim == null || val == null || val.FindActorByObjectID(casterObjectID) is VPlayer)
{
return;
}
VPlayer nearest = null;
float best = float.MaxValue;
val.IterateAllPlayer((Action<VPlayer>)delegate(VPlayer player)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
if (player != null && ((VActor)player).IsAliveStatus())
{
float num = Vector3.Distance(((VActor)player).PositionVector, ((VActor)victim).PositionVector);
if (num < best)
{
best = num;
nearest = player;
}
}
});
if (nearest != null && !(best > 6f))
{
MelonLogger.Msg($"[CrowbarShop] 撬棍伤害来源修正:caster {casterObjectID} -> {((VActor)nearest).ObjectID}({best:0.##}m)");
casterObjectID = ((VActor)nearest).ObjectID;
}
}
catch (Exception ex)
{
MelonLogger.Warning("[CrowbarShop] 修正撬棍伤害来源失败:" + ex.Message);
}
}
}
[HarmonyPatch(typeof(VWorldCombatUtil), "CalculateDamage")]
internal static class MonsterDamagePatch
{
private static void Postfix(VCreature? victim, int skillSeqMasterID, ref DamageAttribute __result)
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Expected O, but got Unknown
if (__result == null || victim == null || skillSeqMasterID != 18006)
{
return;
}
try
{
if (!(victim is VPlayer))
{
CreatureAIInfo creatureAIData = victim.GetCreatureAIData();
float monsterDamageMultiplier = ModPreferences.GetMonsterDamageMultiplier((creatureAIData != null) ? creatureAIData.Name : null);
if (!(Math.Abs(monsterDamageMultiplier - 1f) < 0.001f))
{
__result = new DamageAttribute((long)Math.Round((double)__result.Damage * (double)monsterDamageMultiplier), __result.GroggyValue, __result.Critical);
CreatureAIInfo creatureAIData2 = victim.GetCreatureAIData();
ModPreferences.Log($"[CrowbarShop] 怪物 {((creatureAIData2 != null) ? creatureAIData2.Name : null)} 伤害倍率 {monsterDamageMultiplier}:最终 {__result.Damage}");
}
}
}
catch (Exception ex)
{
MelonLogger.Warning("[CrowbarShop] 怪物伤害倍率处理失败:" + ex.Message);
}
}
}
}