using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak.Afflictions;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("youxia173")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.4.0")]
[assembly: AssemblyInformationalVersion("1.2.4")]
[assembly: AssemblyProduct("CampfireFaerieAura")]
[assembly: AssemblyTitle("youxia173.CampfireFaerieAura")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.4.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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;
}
}
[CompilerGenerated]
[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 CampfireFaerieAura
{
internal static class AuraHeal
{
private const float TeammateHealInterval = 0.1f;
private const float PetrifyMinChunk = 0.01f;
private const float StoveBuffRefreshInterval = 2f;
private static float _teammateHealAcc;
private static float _petrifyLocalAcc;
private static float _petrifyRpcAcc;
private static float _stoveBuffLastApplied;
private static readonly Affliction_NoHunger StoveCampfireBuff = new Affliction_NoHunger
{
totalTime = 3f
};
internal static readonly STATUSTYPE[] HealTypes;
public static bool ShouldSkipSelfHealAsClient()
{
if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
{
return HostAuraSync.HostIsProvidingTeammateAura();
}
return false;
}
private static float GetStatusAmount(CharacterAfflictions aff, STATUSTYPE type)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Invalid comparison between Unknown and I4
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
if ((int)type == 13)
{
CharacterData val = aff.character?.data;
if (!((Object)(object)val != (Object)null))
{
return 0f;
}
return (float)val.petrifyAmount / 100f;
}
return aff.GetCurrentStatus(type);
}
private static float TakePetrifyChunk(ref float acc, float add)
{
if (add <= 0f)
{
return 0f;
}
acc += add;
if (acc < 0.01f)
{
return 0f;
}
float num = Mathf.Floor(acc * 100f) / 100f;
acc -= num;
return num;
}
public static void HealLocal(CharacterAfflictions? aff, float dt, bool applyModCold)
{
//IL_0017: 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)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Invalid comparison between Unknown and I4
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: 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_005f: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)aff == (Object)null)
{
return;
}
STATUSTYPE[] healTypes = HealTypes;
foreach (STATUSTYPE val in healTypes)
{
float healAmount = Plugin.GetHealAmount(val, dt, applyModCold);
if (healAmount <= 0f)
{
continue;
}
if ((int)val == 13)
{
if (GetStatusAmount(aff, val) <= 0f)
{
_petrifyLocalAcc = 0f;
continue;
}
float num = TakePetrifyChunk(ref _petrifyLocalAcc, healAmount);
if (num > 0f)
{
aff.SubtractStatus(val, num, false, false);
}
}
else if (!(GetStatusAmount(aff, val) <= 0f))
{
aff.SubtractStatus(val, healAmount, false, false);
}
}
}
public static void ApplyAura(IEnumerable<Character> inRangeCharacters, float dt, bool applyModCold, bool restoreExtraStamina = false)
{
if (dt <= 0f)
{
return;
}
Character localCharacter = Character.localCharacter;
bool flag = ShouldSkipSelfHealAsClient();
foreach (Character inRangeCharacter in inRangeCharacters)
{
if (!((Object)(object)inRangeCharacter == (Object)null) && !((Object)(object)inRangeCharacter.data == (Object)null) && !inRangeCharacter.data.dead && (Object)(object)inRangeCharacter == (Object)(object)localCharacter)
{
if (!flag)
{
HealLocal(inRangeCharacter.refs?.afflictions, dt, applyModCold);
}
if (restoreExtraStamina)
{
RestoreLocalExtraStamina(localCharacter, dt);
}
}
}
if (!HostAuraSync.IsProvidingTeammateAura() || !PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient)
{
return;
}
_teammateHealAcc += dt;
if (_teammateHealAcc < 0.1f)
{
return;
}
float teammateHealAcc = _teammateHealAcc;
_teammateHealAcc = 0f;
float[] array = BuildHealDeltas(teammateHealAcc, applyModCold);
if (array == null)
{
return;
}
foreach (Character inRangeCharacter2 in inRangeCharacters)
{
if (!((Object)(object)inRangeCharacter2 == (Object)null) && !((Object)(object)inRangeCharacter2 == (Object)(object)localCharacter) && !((Object)(object)inRangeCharacter2.data == (Object)null) && !inRangeCharacter2.data.dead)
{
CharacterAfflictions val = inRangeCharacter2.refs?.afflictions;
if (!((Object)(object)val == (Object)null) && !((Object)(object)((MonoBehaviourPun)val).photonView == (Object)null))
{
((MonoBehaviourPun)val).photonView.RPC("RPC_ApplyStatusesFromFloatArray", (RpcTarget)0, new object[1] { array });
}
}
}
}
private static void RestoreLocalExtraStamina(Character? local, float dt)
{
if ((Object)(object)local == (Object)null || !local.IsLocal || !Plugin.RestoreExtraStamina.Value)
{
return;
}
float num = Plugin.ExtraStaminaPerSecond.Value * dt;
if (num <= 0f)
{
return;
}
float num2 = 1f - (float)local.data.petrifyAmount * 0.01f;
float num3 = Mathf.Clamp(Plugin.ExtraStaminaCap.Value, 0f, 1f);
float num4 = Mathf.Min(num2, num3);
float extraStamina = local.data.extraStamina;
if (extraStamina >= num4 - 0.0001f)
{
return;
}
num = Mathf.Min(num, num4 - extraStamina);
if (!(num <= 0f))
{
local.AddExtraStamina(num);
if ((Object)(object)GUIManager.instance?.bar != (Object)null)
{
GUIManager.instance.bar.ChangeBar();
}
}
}
private static float[]? BuildHealDeltas(float dt, bool applyModCold)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected I4, but got Unknown
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Invalid comparison between Unknown and I4
float[] array = new float[CharacterAfflictions.NumStatusTypes];
bool flag = false;
STATUSTYPE[] healTypes = HealTypes;
foreach (STATUSTYPE val in healTypes)
{
float healAmount = Plugin.GetHealAmount(val, dt, applyModCold);
if (healAmount <= 0f)
{
continue;
}
int num = (int)val;
if (num < 0 || num >= array.Length)
{
continue;
}
if ((int)val == 13)
{
float num2 = TakePetrifyChunk(ref _petrifyRpcAcc, healAmount);
if (!(num2 <= 0f))
{
array[num] = 0f - num2;
flag = true;
}
}
else
{
array[num] = 0f - healAmount;
flag = true;
}
}
if (!flag)
{
return null;
}
return array;
}
public static bool IsPortableStoveColdEmitter(StatusEmitter emitter)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Invalid comparison between Unknown and I4
if ((Object)(object)emitter == (Object)null)
{
return false;
}
if ((int)emitter.statusType != 2)
{
return false;
}
if (emitter.amount >= 0f)
{
return false;
}
Transform val = ((Component)emitter).transform;
while ((Object)(object)val != (Object)null)
{
string name = ((Object)val).name;
if (name.IndexOf("PortableStove", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("PortableStovetop", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Portable Stove", StringComparison.OrdinalIgnoreCase) >= 0)
{
return true;
}
val = val.parent;
}
return false;
}
public static bool IsPortableStoveFireLit(StatusEmitter emitter)
{
if ((Object)(object)emitter == (Object)null)
{
return false;
}
Campfire componentInParent = ((Component)emitter).GetComponentInParent<Campfire>();
if ((Object)(object)componentInParent != (Object)null)
{
if (!componentInParent.Lit)
{
return false;
}
if ((Object)(object)componentInParent.enableWhenLit != (Object)null && !componentInParent.enableWhenLit.activeInHierarchy)
{
return false;
}
return true;
}
return ((Behaviour)emitter).isActiveAndEnabled;
}
public static void RefreshStoveCampfireIconForLocal(bool localInStoveRange)
{
if (!Plugin.ShowCampfireIconOnStove.Value || !localInStoveRange)
{
return;
}
CharacterAfflictions val = Character.localCharacter?.refs?.afflictions;
if (!((Object)(object)val == (Object)null))
{
float totalTime = Mathf.Max(1f, Plugin.PortableStoveBuffDuration.Value);
((Affliction)StoveCampfireBuff).totalTime = totalTime;
if (val.canGetHungry || Time.time - _stoveBuffLastApplied > 2f)
{
val.AddAffliction((Affliction)(object)StoveCampfireBuff, false);
_stoveBuffLastApplied = Time.time;
}
}
}
public static void ClearStoveCampfireIconForLocal()
{
Character localCharacter = Character.localCharacter;
CharacterAfflictions val = localCharacter?.refs?.afflictions;
if (!((Object)(object)val == (Object)null) && !((Object)(object)localCharacter == (Object)null) && !IsLocalNearLitCampfire(localCharacter))
{
if (!val.canGetHungry)
{
val.RemoveAffliction((AfflictionType)21);
}
_stoveBuffLastApplied = 0f;
}
}
private static bool IsLocalNearLitCampfire(Character local)
{
if ((Object)(object)local == (Object)null)
{
return false;
}
if (!(AccessTools.Field(typeof(Campfire), "ALL_CAMPFIRES")?.GetValue(null) is List<Campfire> list))
{
return false;
}
foreach (Campfire item in list)
{
if (!((Object)(object)item == (Object)null) && item.Lit)
{
List<Character> list2 = item.PlayerCharactersInRadius(item.moraleBoostRadius);
if (list2 != null && list2.Contains(local))
{
return true;
}
}
}
return false;
}
static AuraHeal()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Expected O, but got Unknown
STATUSTYPE[] array = new STATUSTYPE[9];
RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
HealTypes = (STATUSTYPE[])(object)array;
}
}
internal static class HostAuraSync
{
public const string RoomPropertyKey = "yx173_CFA_HTA";
private static bool? _lastSyncedProviding;
public static bool IsProvidingTeammateAura()
{
if (Plugin.Enabled.Value)
{
return Plugin.AffectTeammatesAsHost.Value;
}
return false;
}
public static void SyncIfHost()
{
//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_005a: Expected O, but got Unknown
//IL_005b: Expected O, but got Unknown
if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient)
{
if (!PhotonNetwork.InRoom)
{
_lastSyncedProviding = null;
}
return;
}
bool flag = IsProvidingTeammateAura();
if (_lastSyncedProviding != flag)
{
Hashtable val = new Hashtable();
((Dictionary<object, object>)val).Add((object)"yx173_CFA_HTA", (object)flag);
Hashtable val2 = val;
PhotonNetwork.CurrentRoom.SetCustomProperties(val2, (Hashtable)null, (WebFlags)null);
_lastSyncedProviding = flag;
Plugin.Log.LogInfo((object)$"已同步主机队友光环状态到房间: {flag}");
}
}
public static bool HostIsProvidingTeammateAura()
{
if (!PhotonNetwork.InRoom)
{
return false;
}
Room currentRoom = PhotonNetwork.CurrentRoom;
if (((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties : null) == null)
{
return false;
}
if (((Dictionary<object, object>)(object)((RoomInfo)currentRoom).CustomProperties).TryGetValue((object)"yx173_CFA_HTA", out object value) && value is bool)
{
return (bool)value;
}
return false;
}
public static void ResetLocalCache()
{
_lastSyncedProviding = null;
}
}
[HarmonyPatch(typeof(Campfire), "ApplyCampfireProtection")]
internal static class Campfire_ApplyCampfireProtection_Patch
{
[HarmonyPostfix]
private static void Postfix(Campfire __instance)
{
if (!Plugin.Enabled.Value || (Object)(object)__instance == (Object)null || !__instance.Lit)
{
return;
}
float deltaTime = Time.deltaTime;
if (!(deltaTime <= 0f))
{
List<Character> list = __instance.PlayerCharactersInRadius(__instance.moraleBoostRadius);
if (list != null && list.Count != 0)
{
AuraHeal.ApplyAura(list, deltaTime, applyModCold: true, restoreExtraStamina: true);
}
}
}
}
[HarmonyPatch(typeof(StatusEmitter), "Update")]
internal static class StatusEmitter_Update_Patch
{
[HarmonyPostfix]
private static void Postfix(StatusEmitter __instance)
{
if (Plugin.Enabled.Value && Plugin.EnablePortableStove.Value && !((Object)(object)__instance == (Object)null) && ((Behaviour)__instance).isActiveAndEnabled && !__instance.emitterDisabledByWind && AuraHeal.IsPortableStoveColdEmitter(__instance) && AuraHeal.IsPortableStoveFireLit(__instance))
{
StoveAuraTracker.NotifyLitEmitter(__instance);
}
}
}
[BepInPlugin("youxia173.CampfireFaerieAura", "CampfireFaerieAura", "1.2.4")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Log;
public static ConfigEntry<bool> Enabled;
public static ConfigEntry<bool> AffectTeammatesAsHost;
public static ConfigEntry<bool> EnablePortableStove;
public static ConfigEntry<bool> HealHot;
public static ConfigEntry<bool> HealCold;
public static ConfigEntry<bool> HealPoison;
public static ConfigEntry<bool> HealDrowsy;
public static ConfigEntry<bool> HealInjury;
public static ConfigEntry<bool> HealSpores;
public static ConfigEntry<bool> HealHunger;
public static ConfigEntry<bool> HealPetrify;
public static ConfigEntry<bool> HealCurse;
public static ConfigEntry<bool> RestoreExtraStamina;
public static ConfigEntry<bool> ShowCampfireIconOnStove;
public static ConfigEntry<float> PortableStoveBuffDuration;
public static ConfigEntry<float> HotPerSecond;
public static ConfigEntry<float> ColdPerSecond;
public static ConfigEntry<float> PoisonPerSecond;
public static ConfigEntry<float> DrowsyPerSecond;
public static ConfigEntry<float> InjuryPerSecond;
public static ConfigEntry<float> SporesPerSecond;
public static ConfigEntry<float> HungerRestorePerSecond;
public static ConfigEntry<float> PetrifyPerSecond;
public static ConfigEntry<float> CursePerSecond;
public static ConfigEntry<float> ExtraStaminaPerSecond;
public static ConfigEntry<float> ExtraStaminaCap;
private Harmony? _harmony;
private void Awake()
{
//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0203: Expected O, but got Unknown
//IL_0236: Unknown result type (might be due to invalid IL or missing references)
//IL_0240: Expected O, but got Unknown
//IL_0273: Unknown result type (might be due to invalid IL or missing references)
//IL_027d: Expected O, but got Unknown
//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
//IL_02ba: Expected O, but got Unknown
//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
//IL_02f7: Expected O, but got Unknown
//IL_032a: Unknown result type (might be due to invalid IL or missing references)
//IL_0334: Expected O, but got Unknown
//IL_0367: Unknown result type (might be due to invalid IL or missing references)
//IL_0371: Expected O, but got Unknown
//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
//IL_03ae: Expected O, but got Unknown
//IL_03e1: Unknown result type (might be due to invalid IL or missing references)
//IL_03eb: Expected O, but got Unknown
//IL_041e: Unknown result type (might be due to invalid IL or missing references)
//IL_0428: Expected O, but got Unknown
//IL_045b: Unknown result type (might be due to invalid IL or missing references)
//IL_0465: Expected O, but got Unknown
//IL_0498: Unknown result type (might be due to invalid IL or missing references)
//IL_04a2: Expected O, but got Unknown
//IL_04ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0509: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "总开关。关闭后完全不生效(含主机队友光环)。 / Master switch. When off, the mod does nothing (including host teammate aura).");
AffectTeammatesAsHost = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AffectTeammatesAsHost", false, "仅主机:篝火/便携炉范围内队友也享受疗愈(队友可不装本模组)。写入房间属性;装了本模组的客机会跳过自疗避免双倍。 / Host only: also heal teammates in campfire/stove range (they need not install this mod). Writes a room property; clients with this mod skip self-heal to avoid double healing.");
EnablePortableStove = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnablePortableStove", true, "便携炉范围内也套用本模组疗愈。寒冷仍只走原版炉子(不叠加模组减寒);篝火寒冷用 HealCold / ColdPerSecond。 / Apply mod heals near portable stoves. Cold still uses vanilla stove only (no mod cold stack); campfire cold uses HealCold / ColdPerSecond.");
HealHot = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealHot", false, "是否疗愈灼热。 / Heal Hot.");
HealCold = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealCold", true, "是否疗愈寒冷(仅篝火;便携炉用原版)。 / Heal Cold (campfire only; stove uses vanilla).");
HealPoison = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealPoison", true, "是否疗愈中毒。 / Heal Poison.");
HealDrowsy = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealDrowsy", true, "是否疗愈昏睡。 / Heal Drowsy.");
HealInjury = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealInjury", true, "是否疗愈受伤。 / Heal Injury.");
HealSpores = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealSpores", true, "是否疗愈孢子。 / Heal Spores.");
HealHunger = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealHunger", true, "是否降低饥饿(恢复饱食)。 / Reduce Hunger (restore satiety).");
HealPetrify = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealPetrify", true, "是否疗愈石化。 / Heal Petrify.");
HealCurse = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealCurse", true, "是否疗愈诅咒。 / Heal Curse.");
RestoreExtraStamina = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "RestoreExtraStamina", true, "篝火/便携炉范围内是否缓慢恢复额外体力条(便携炉还需 EnablePortableStove)。 / Slowly restore bonus/extra stamina near lit campfire or portable stove (stove also needs EnablePortableStove).");
ShowCampfireIconOnStove = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "ShowCampfireIconOnStove", true, "便携炉疗愈生效时点亮体力条篝火图标(与原版篝火相同)。 / Light the stamina-bar campfire icon while portable-stove aura is active.");
PortableStoveBuffDuration = ((BaseUnityPlugin)this).Config.Bind<float>("General", "PortableStoveBuffDuration", 5f, new ConfigDescription("便携炉熄灭后,若仍站在炉旁(原减寒范围),模组疗愈与图标再持续的秒数。炉子燃烧期间不受此限制;不影响原版减寒。0 = 熄灭立刻结束。 / Seconds our stove heal+icon continues after the stove extinguishes while still in cold-emitter range. Unlimited while the stove is lit; does not affect vanilla cold. 0 = end immediately on extinguish.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>()));
HotPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "HotPerSecond", 0.005f, new ConfigDescription("每秒减少的状态量(0~1)。例如 0.005 ≈ 每秒 0.5%。0 = 关闭。默认约仙子提灯的 1/5。 / Status removed per second (0~1). e.g. 0.005 ≈ 0.5%/s. 0 = off. Default ~1/5 of Faerie lantern.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
ColdPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "ColdPerSecond", 0.05f, new ConfigDescription("每秒减少的寒冷(0~1)。原版便携炉约 0.05/秒。0 = 关闭。 / Cold removed per second (0~1). Vanilla stove is about 0.05/s. 0 = off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
PoisonPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "PoisonPerSecond", 0.005f, new ConfigDescription("每秒减少的状态量(0~1)。例如 0.005 ≈ 每秒 0.5%。0 = 关闭。默认约仙子提灯的 1/5。 / Status removed per second (0~1). e.g. 0.005 ≈ 0.5%/s. 0 = off. Default ~1/5 of Faerie lantern.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
DrowsyPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "DrowsyPerSecond", 0.01f, new ConfigDescription("每秒减少的状态量(0~1)。例如 0.005 ≈ 每秒 0.5%。0 = 关闭。默认约仙子提灯的 1/5。 / Status removed per second (0~1). e.g. 0.005 ≈ 0.5%/s. 0 = off. Default ~1/5 of Faerie lantern.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
InjuryPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "InjuryPerSecond", 0.005f, new ConfigDescription("每秒减少的状态量(0~1)。例如 0.005 ≈ 每秒 0.5%。0 = 关闭。默认约仙子提灯的 1/5。 / Status removed per second (0~1). e.g. 0.005 ≈ 0.5%/s. 0 = off. Default ~1/5 of Faerie lantern.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
SporesPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "SporesPerSecond", 0.005f, new ConfigDescription("每秒减少的状态量(0~1)。例如 0.005 ≈ 每秒 0.5%。0 = 关闭。默认约仙子提灯的 1/5。 / Status removed per second (0~1). e.g. 0.005 ≈ 0.5%/s. 0 = off. Default ~1/5 of Faerie lantern.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
HungerRestorePerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "HungerPerSecond", 0.005f, new ConfigDescription("每秒减少的饥饿。篝火原版只会暂停饥饿上涨;此项会主动降低 Hunger。 / Hunger reduced per second. Vanilla campfire only pauses hunger gain; this actively lowers it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
PetrifyPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "PetrifyPerSecond", 0.005f, new ConfigDescription("每秒减少的石化(0~1)。引擎按 1% 步进取整,需累计到 ≥0.01。 / Petrify removed per second (0~1). Engine floors to 1% steps; accumulates until >= 0.01.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
CursePerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "CursePerSecond", 0.005f, new ConfigDescription("每秒减少的诅咒(0~1)。默认与石化相同。 / Curse removed per second (0~1). Default same as Petrify.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
ExtraStaminaPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "ExtraStaminaPerSecond", 0.01f, new ConfigDescription("篝火/便携炉旁每秒增加的额外体力(0~1)。0.01 ≈ 每秒 1%。0 = 关闭。 / Extra stamina gained per second near campfire/stove (0~1). 0.01 ≈ 1%/s. 0 = off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
ExtraStaminaCap = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "ExtraStaminaCap", 0.5f, new ConfigDescription("本模组恢复额外体力的上限(0~1)。默认 0.5 = 最多回满到 50%;已高于上限则不再回。仍受石化对额外体力上限的限制。 / Cap for mod-restored extra stamina (0~1). Default 0.5 = stop at 50%. Won't restore if already above. Still limited by petrify.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
Enabled.SettingChanged += delegate
{
HostAuraSync.ResetLocalCache();
};
AffectTeammatesAsHost.SettingChanged += delegate
{
HostAuraSync.ResetLocalCache();
};
_harmony = new Harmony("youxia173.CampfireFaerieAura");
_harmony.PatchAll();
Log.LogInfo((object)("CampfireFaerieAura v1.2.4 by youxia173 loaded. " + $"Enabled={Enabled.Value} AffectTeammatesAsHost={AffectTeammatesAsHost.Value}"));
}
private void Update()
{
HostAuraSync.SyncIfHost();
StoveAuraTracker.Tick(Time.deltaTime);
}
private void OnDestroy()
{
Harmony? harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
public static float GetHealAmount(STATUSTYPE type, float dt, bool applyModCold = true)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Expected I4, but got Unknown
if (dt <= 0f)
{
return 0f;
}
switch ((int)type)
{
case 8:
if (!HealHot.Value)
{
return 0f;
}
return HotPerSecond.Value * dt;
case 2:
if (!applyModCold || !HealCold.Value)
{
return 0f;
}
return ColdPerSecond.Value * dt;
case 3:
if (!HealPoison.Value)
{
return 0f;
}
return PoisonPerSecond.Value * dt;
case 6:
if (!HealDrowsy.Value)
{
return 0f;
}
return DrowsyPerSecond.Value * dt;
case 0:
if (!HealInjury.Value)
{
return 0f;
}
return InjuryPerSecond.Value * dt;
case 10:
if (!HealSpores.Value)
{
return 0f;
}
return SporesPerSecond.Value * dt;
case 1:
if (!HealHunger.Value)
{
return 0f;
}
return HungerRestorePerSecond.Value * dt;
case 13:
if (!HealPetrify.Value)
{
return 0f;
}
return PetrifyPerSecond.Value * dt;
case 5:
if (!HealCurse.Value)
{
return 0f;
}
return CursePerSecond.Value * dt;
default:
return 0f;
}
}
}
internal static class StoveAuraTracker
{
private sealed class StoveState
{
public StatusEmitter? Emitter;
public Vector3 LastPos;
public float Range;
public bool WasLit;
public float ExtinguishedAt = -1f;
public bool LingerActive;
}
private static readonly Dictionary<int, StoveState> _stoves = new Dictionary<int, StoveState>();
private static bool _iconForcedOff;
public static void NotifyLitEmitter(StatusEmitter emitter)
{
//IL_0040: 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)
if (!((Object)(object)emitter == (Object)null))
{
int instanceID = ((Object)emitter).GetInstanceID();
if (!_stoves.TryGetValue(instanceID, out StoveState value))
{
value = new StoveState();
_stoves[instanceID] = value;
}
value.Emitter = emitter;
value.LastPos = ((Component)emitter).transform.position;
value.Range = emitter.radius + emitter.outerFade;
value.WasLit = true;
value.ExtinguishedAt = -1f;
value.LingerActive = false;
}
}
public static void Tick(float dt)
{
//IL_00a4: 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)
if (!Plugin.Enabled.Value || !Plugin.EnablePortableStove.Value)
{
if (_stoves.Count > 0)
{
ClearAllAndExtinguishIcon();
}
}
else
{
if (dt <= 0f)
{
return;
}
float num = Mathf.Max(0f, Plugin.PortableStoveBuffDuration.Value);
Character localCharacter = Character.localCharacter;
bool flag = false;
List<int> list = new List<int>();
foreach (KeyValuePair<int, StoveState> stofe in _stoves)
{
StoveState value = stofe.Value;
bool flag2 = IsEmitterLit(value);
if (flag2)
{
if ((Object)(object)value.Emitter != (Object)null)
{
value.LastPos = ((Component)value.Emitter).transform.position;
value.Range = value.Emitter.radius + value.Emitter.outerFade;
}
value.WasLit = true;
value.ExtinguishedAt = -1f;
value.LingerActive = false;
}
else if (value.WasLit)
{
value.WasLit = false;
if (!((Object)(object)localCharacter != (Object)null) || !IsNear(localCharacter, value) || !(num > 0f))
{
list.Add(stofe.Key);
continue;
}
value.ExtinguishedAt = Time.time;
value.LingerActive = true;
}
else
{
if (!value.LingerActive)
{
list.Add(stofe.Key);
continue;
}
if (Time.time - value.ExtinguishedAt >= num || (Object)(object)localCharacter == (Object)null || !IsNear(localCharacter, value))
{
list.Add(stofe.Key);
continue;
}
}
if (!flag2 && !value.LingerActive)
{
list.Add(stofe.Key);
continue;
}
List<Character> list2 = CollectInRange(value);
if (list2.Count == 0)
{
if (value.LingerActive)
{
list.Add(stofe.Key);
}
continue;
}
AuraHeal.ApplyAura(list2, dt, applyModCold: false, restoreExtraStamina: true);
if ((Object)(object)localCharacter != (Object)null && list2.Contains(localCharacter))
{
flag = true;
}
}
foreach (int item in list)
{
_stoves.Remove(item);
}
if (flag)
{
_iconForcedOff = false;
AuraHeal.RefreshStoveCampfireIconForLocal(localInStoveRange: true);
}
else if (!_iconForcedOff)
{
AuraHeal.ClearStoveCampfireIconForLocal();
_iconForcedOff = true;
}
}
}
private static bool IsEmitterLit(StoveState state)
{
StatusEmitter emitter = state.Emitter;
if ((Object)(object)emitter == (Object)null)
{
return false;
}
if (!Object.op_Implicit((Object)(object)emitter))
{
state.Emitter = null;
return false;
}
if (emitter.emitterDisabledByWind)
{
return false;
}
if (!AuraHeal.IsPortableStoveColdEmitter(emitter))
{
return false;
}
if (!AuraHeal.IsPortableStoveFireLit(emitter))
{
return false;
}
return true;
}
private static bool IsNear(Character c, StoveState state)
{
//IL_0024: 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)
if ((Object)(object)c?.data == (Object)null || c.data.dead)
{
return false;
}
return Vector3.Distance(state.LastPos, c.Center) <= state.Range;
}
private static List<Character> CollectInRange(StoveState state)
{
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
List<Character> list = new List<Character>();
foreach (Character allPlayerCharacter in PlayerHandler.GetAllPlayerCharacters())
{
if (!((Object)(object)allPlayerCharacter == (Object)null) && !((Object)(object)allPlayerCharacter.data == (Object)null) && !allPlayerCharacter.data.dead && !(Vector3.Distance(state.LastPos, allPlayerCharacter.Center) > state.Range))
{
list.Add(allPlayerCharacter);
}
}
return list;
}
private static void ClearAllAndExtinguishIcon()
{
_stoves.Clear();
AuraHeal.ClearStoveCampfireIconForLocal();
_iconForcedOff = true;
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "youxia173.CampfireFaerieAura";
public const string PLUGIN_NAME = "CampfireFaerieAura";
public const string PLUGIN_VERSION = "1.2.4";
}
}