using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;
[assembly: AssemblyTitle("ZombieCrisis")]
[assembly: AssemblyDescription("PEAK zombie crisis gameplay mod")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = "")]
[assembly: ComVisible(false)]
[assembly: AssemblyCompany("PeakMods")]
[assembly: AssemblyProduct("ZombieCrisis")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: CompilationRelaxations(8)]
[assembly: Guid("A04AA9C8-CDE7-4D03-9197-4D29DA4E9BB9")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ZombieCrisis;
[BepInPlugin("com.peakmods.zombiecrisis", "丧尸危机", "1.0.0")]
public sealed class ZombieCrisisPlugin : BaseUnityPlugin
{
[HarmonyPatch(typeof(MushroomZombieSpawner), "Start")]
private static class MushroomZombieSpawnerStartPatch
{
private static void Prefix(MushroomZombieSpawner __instance)
{
if ((Object)(object)_instance != (Object)null && (Object)(object)__instance != (Object)null)
{
_instance.CapturePrefab(__instance.mushroomZombiePrefab);
}
}
}
[HarmonyPatch(typeof(MushroomZombie), "Start")]
private static class MushroomZombieStartPatch
{
private static void Postfix(MushroomZombie __instance)
{
TryAttachMarker(__instance);
}
}
[HarmonyPatch(typeof(MushroomZombie), "Die")]
private static class MushroomZombieDiePatch
{
private static bool Prefix(MushroomZombie __instance)
{
return !IsCrisisZombie(__instance);
}
}
[HarmonyPatch(typeof(MushroomZombie), "set_currentState")]
private static class MushroomZombieStatePatch
{
private static bool Prefix(MushroomZombie __instance, State value)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Invalid comparison between Unknown and I4
if ((int)value == 6)
{
return !IsCrisisZombie(__instance);
}
return true;
}
}
[HarmonyPatch(typeof(MushroomZombie), "ReadyToDisable")]
private static class MushroomZombieReadyToDisablePatch
{
private static bool Prefix(MushroomZombie __instance, ref bool __result)
{
if (!IsCrisisZombie(__instance))
{
return true;
}
__result = false;
return false;
}
}
[HarmonyPatch(typeof(MushroomZombie), "DestroyZombie")]
private static class MushroomZombieDestroyPatch
{
private static bool Prefix(MushroomZombie __instance)
{
return !IsCrisisZombie(__instance);
}
}
public const string PluginGuid = "com.peakmods.zombiecrisis";
public const string PluginName = "丧尸危机";
public const string PluginVersion = "1.0.0";
internal const string NetworkMarker = "ZombieCrisis:1";
private const float MinimumSpawnRadius = 10f;
private const float MaximumSpawnRadius = 16f;
private const float GroundRayHeight = 14f;
private const float GroundRayDistance = 36f;
private const float SpawnRetryDelay = 2f;
private const float PrefabSearchInterval = 2f;
private static ZombieCrisisPlugin _instance;
private readonly List<Character> _spawnTargets = new List<Character>();
private Harmony _harmony;
private ConfigEntry<int> _zombieCount;
private ConfigEntry<float> _spawnDelay;
private ConfigEntry<float> _sprintSpeedMultiplier;
private string _zombiePrefabName;
private int _activeRunInstanceId = int.MinValue;
private int _spawnedCountForRun;
private bool _spawnCompletedForRun;
private bool _waitingForPrefabLogged;
private float _nextPrefabSearchTime;
private float _nextSpawnAttemptTime;
private void Awake()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
_instance = this;
BindConfiguration();
_harmony = new Harmony("com.peakmods.zombiecrisis");
_harmony.PatchAll(typeof(ZombieCrisisPlugin).Assembly);
((BaseUnityPlugin)this).Logger.LogInfo((object)"丧尸危机 1.0.0 已加载。丧尸将由房主按配置生成。");
}
private void BindConfiguration()
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Expected O, but got Unknown
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Expected O, but got Unknown
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Expected O, but got Unknown
_zombieCount = ((BaseUnityPlugin)this).Config.Bind<int>("丧尸危机", "丧尸数量", 5, new ConfigDescription("每轮在玩家附近生成的模组丧尸总数。设为 0 可关闭本轮生成。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), new object[0]));
_spawnDelay = ((BaseUnityPlugin)this).Config.Bind<float>("丧尸危机", "生成延迟(秒)", 30f, new ConfigDescription("从本轮攀登开始到丧尸出现的等待时间,单位为秒。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 900f), new object[0]));
_sprintSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("丧尸危机", "奔跑速度倍率", 1.5f, new ConfigDescription("模组丧尸相对于原版丧尸的奔跑速度倍率。1.0 为原版速度。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 5f), new object[0]));
}
private void Update()
{
TryFindZombiePrefab();
if (!GameHandler.IsOnIslandAndInitialized || (Object)(object)RunManager.Instance == (Object)null)
{
return;
}
int instanceID = ((Object)RunManager.Instance).GetInstanceID();
if (instanceID != _activeRunInstanceId)
{
BeginRun(instanceID);
}
if (_spawnCompletedForRun || !PhotonNetwork.IsMasterClient)
{
return;
}
int num = Mathf.Clamp(_zombieCount.Value, 0, 50);
if (num == 0)
{
_spawnCompletedForRun = true;
((BaseUnityPlugin)this).Logger.LogInfo((object)"本轮丧尸数量为 0,不生成丧尸。");
return;
}
_spawnedCountForRun = Math.Max(_spawnedCountForRun, CrisisZombieMarker.ActiveCount);
if (_spawnedCountForRun >= num)
{
_spawnCompletedForRun = true;
}
else
{
if (RunManager.Instance.TimeSinceRunStarted < Mathf.Max(0f, _spawnDelay.Value) || Time.unscaledTime < _nextSpawnAttemptTime)
{
return;
}
if (string.IsNullOrEmpty(_zombiePrefabName))
{
if (!_waitingForPrefabLogged)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)"尚未找到原版 MushroomZombie Photon 预制体,将继续等待而不会破坏本轮游戏。");
_waitingForPrefabLogged = true;
}
_nextSpawnAttemptTime = Time.unscaledTime + 2f;
return;
}
RefreshSpawnTargets();
if (_spawnTargets.Count == 0)
{
_nextSpawnAttemptTime = Time.unscaledTime + 2f;
return;
}
int count = num - _spawnedCountForRun;
int num2 = SpawnZombies(count);
_spawnedCountForRun += num2;
_nextSpawnAttemptTime = Time.unscaledTime + 2f;
if (_spawnedCountForRun >= num)
{
_spawnCompletedForRun = true;
((BaseUnityPlugin)this).Logger.LogInfo((object)("本轮丧尸危机已生成 " + _spawnedCountForRun + " 只不死丧尸。"));
}
else if (num2 == 0)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("本次未能生成丧尸,将在 " + 2f + " 秒后重试。"));
}
}
}
private void BeginRun(int runInstanceId)
{
_activeRunInstanceId = runInstanceId;
_spawnedCountForRun = CrisisZombieMarker.ActiveCount;
_spawnCompletedForRun = false;
_waitingForPrefabLogged = false;
_nextSpawnAttemptTime = 0f;
((BaseUnityPlugin)this).Logger.LogInfo((object)("新一轮丧尸危机已待命:数量=" + _zombieCount.Value + ",延迟=" + _spawnDelay.Value.ToString("0.##") + " 秒,奔跑速度倍率=" + _sprintSpeedMultiplier.Value.ToString("0.##") + "。"));
}
private void TryFindZombiePrefab()
{
if (!string.IsNullOrEmpty(_zombiePrefabName) || Time.unscaledTime < _nextPrefabSearchTime)
{
return;
}
_nextPrefabSearchTime = Time.unscaledTime + 2f;
MushroomZombieSpawner[] array = Resources.FindObjectsOfTypeAll<MushroomZombieSpawner>();
foreach (MushroomZombieSpawner val in array)
{
if ((Object)(object)val != (Object)null && (Object)(object)val.mushroomZombiePrefab != (Object)null)
{
CapturePrefab(val.mushroomZombiePrefab);
break;
}
}
}
private void CapturePrefab(MushroomZombie prefab)
{
if (!((Object)(object)prefab == (Object)null) && !((Object)(object)((Component)prefab).gameObject == (Object)null) && !string.IsNullOrEmpty(((Object)((Component)prefab).gameObject).name) && string.IsNullOrEmpty(_zombiePrefabName))
{
_zombiePrefabName = ((Object)((Component)prefab).gameObject).name;
_waitingForPrefabLogged = false;
((BaseUnityPlugin)this).Logger.LogInfo((object)("已捕获原版丧尸预制体:" + _zombiePrefabName));
}
}
private void RefreshSpawnTargets()
{
_spawnTargets.Clear();
List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
if (allPlayerCharacters == null)
{
return;
}
for (int i = 0; i < allPlayerCharacters.Count; i++)
{
Character val = allPlayerCharacters[i];
if (!((Object)(object)val == (Object)null) && val.IsPlayerControlled && !((Object)(object)val.data == (Object)null) && !val.data.dead && !val.IsGhost)
{
_spawnTargets.Add(val);
}
}
}
private int SpawnZombies(int count)
{
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
int num = 0;
float num2 = Mathf.Clamp(_sprintSpeedMultiplier.Value, 0.25f, 5f);
for (int i = 0; i < count; i++)
{
Character target = _spawnTargets[(_spawnedCountForRun + i) % _spawnTargets.Count];
FindSpawnPose(target, _spawnedCountForRun + i, out var position, out var rotation);
object[] array = new object[3] { "ZombieCrisis:1", "1.0.0", num2 };
try
{
GameObject val = PhotonNetwork.Instantiate(_zombiePrefabName, position, rotation, (byte)0, array);
MushroomZombie val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<MushroomZombie>() : null);
if ((Object)(object)val2 == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)"Photon 已创建对象,但对象上没有 MushroomZombie 组件。");
continue;
}
TryAttachMarker(val2);
num++;
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogError((object)("生成丧尸失败:" + ex));
break;
}
}
return num;
}
private static void FindSpawnPose(Character target, int index, out Vector3 position, out Quaternion rotation)
{
//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_003b: 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_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: 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_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: 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_0062: 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_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: 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_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
Vector3 center = target.Center;
float num = 51.42857f * (float)index + Random.Range(-18f, 18f);
float num2 = Random.Range(10f, 16f);
Vector3 val = Quaternion.Euler(0f, num, 0f) * Vector3.forward;
Vector3 val2 = center + val * num2 + Vector3.up * 14f;
RaycastHit val3 = default(RaycastHit);
if (Physics.Raycast(val2, Vector3.down, ref val3, 36f, -5, (QueryTriggerInteraction)1))
{
position = ((RaycastHit)(ref val3)).point + Vector3.up * 0.35f;
}
else
{
position = center + val * num2 + Vector3.up * 0.5f;
}
Vector3 val4 = center - position;
val4.y = 0f;
rotation = ((((Vector3)(ref val4)).sqrMagnitude > 0.01f) ? Quaternion.LookRotation(((Vector3)(ref val4)).normalized, Vector3.up) : Quaternion.identity);
}
internal static bool IsCrisisZombie(MushroomZombie zombie)
{
if ((Object)(object)zombie == (Object)null)
{
return false;
}
CrisisZombieMarker component = ((Component)zombie).GetComponent<CrisisZombieMarker>();
if ((Object)(object)component != (Object)null)
{
return true;
}
if (!TryReadNetworkMarker(zombie, out var speedMultiplier))
{
return false;
}
AttachMarker(zombie, speedMultiplier);
return true;
}
private static void TryAttachMarker(MushroomZombie zombie)
{
if (TryReadNetworkMarker(zombie, out var speedMultiplier))
{
AttachMarker(zombie, speedMultiplier);
}
}
private static void AttachMarker(MushroomZombie zombie, float speedMultiplier)
{
CrisisZombieMarker crisisZombieMarker = ((Component)zombie).GetComponent<CrisisZombieMarker>();
if ((Object)(object)crisisZombieMarker == (Object)null)
{
crisisZombieMarker = ((Component)zombie).gameObject.AddComponent<CrisisZombieMarker>();
}
crisisZombieMarker.Initialize(zombie, speedMultiplier);
}
private static bool TryReadNetworkMarker(MushroomZombie zombie, out float speedMultiplier)
{
speedMultiplier = 1f;
try
{
PhotonView photonView = ((MonoBehaviourPun)zombie).photonView;
object[] array = (((Object)(object)photonView != (Object)null) ? photonView.InstantiationData : null);
if (array == null || array.Length < 3 || !string.Equals(array[0] as string, "ZombieCrisis:1", StringComparison.Ordinal))
{
return false;
}
speedMultiplier = Convert.ToSingle(array[2]);
speedMultiplier = Mathf.Clamp(speedMultiplier, 0.25f, 5f);
return true;
}
catch (Exception ex)
{
if ((Object)(object)_instance != (Object)null)
{
((BaseUnityPlugin)_instance).Logger.LogWarning((object)("读取丧尸危机网络标记失败:" + ex.Message));
}
return false;
}
}
private void OnDestroy()
{
if (_harmony != null)
{
_harmony.UnpatchSelf();
}
if ((Object)(object)_instance == (Object)(object)this)
{
_instance = null;
}
}
}
internal sealed class CrisisZombieMarker : MonoBehaviour
{
private static readonly List<CrisisZombieMarker> ActiveMarkers = new List<CrisisZombieMarker>();
private static readonly int BaseColorProperty = Shader.PropertyToID("_BaseColor");
private static readonly int ColorProperty = Shader.PropertyToID("_Color");
private static readonly int EmissionColorProperty = Shader.PropertyToID("_EmissionColor");
private static readonly Color CrisisColor = new Color(0.82f, 0.035f, 0.025f, 1f);
private static readonly Color CrisisEmission = new Color(1f, 0.015f, 0.005f, 1f) * 1.4f;
private readonly HashSet<Material> _ownedMaterials = new HashSet<Material>();
private MushroomZombie _zombie;
private CharacterMovementZombie _movement;
private float _targetSprintMultiplier;
private float _nextVisualRefresh;
private int _visualRefreshesRemaining;
private bool _initialized;
internal static int ActiveCount
{
get
{
for (int num = ActiveMarkers.Count - 1; num >= 0; num--)
{
if ((Object)(object)ActiveMarkers[num] == (Object)null)
{
ActiveMarkers.RemoveAt(num);
}
}
return ActiveMarkers.Count;
}
}
internal void Initialize(MushroomZombie zombie, float speedMultiplier)
{
if (!_initialized)
{
_initialized = true;
_zombie = zombie;
_zombie.lifetime = float.PositiveInfinity;
_movement = ((Component)this).GetComponent<CharacterMovementZombie>();
if ((Object)(object)_movement != (Object)null)
{
_targetSprintMultiplier = ((CharacterMovement)_movement).sprintMultiplier * Mathf.Clamp(speedMultiplier, 0.25f, 5f);
((CharacterMovement)_movement).sprintMultiplier = _targetSprintMultiplier;
}
ActiveMarkers.Add(this);
CreateWarningLight();
ApplyCrisisAppearance();
_visualRefreshesRemaining = 3;
_nextVisualRefresh = Time.unscaledTime + 0.5f;
}
}
private void LateUpdate()
{
if (_initialized && !((Object)(object)_zombie == (Object)null))
{
_zombie.lifetime = float.PositiveInfinity;
if ((Object)(object)_movement != (Object)null && !Mathf.Approximately(((CharacterMovement)_movement).sprintMultiplier, _targetSprintMultiplier))
{
((CharacterMovement)_movement).sprintMultiplier = _targetSprintMultiplier;
}
if (_visualRefreshesRemaining > 0 && Time.unscaledTime >= _nextVisualRefresh)
{
ApplyCrisisAppearance();
_visualRefreshesRemaining--;
_nextVisualRefresh = Time.unscaledTime + 1f;
}
}
}
private void ApplyCrisisAppearance()
{
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true);
foreach (Renderer val in componentsInChildren)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
Material[] materials = val.materials;
foreach (Material val2 in materials)
{
if (!((Object)(object)val2 == (Object)null))
{
_ownedMaterials.Add(val2);
SetTint(val2, BaseColorProperty, CrisisColor);
SetTint(val2, ColorProperty, CrisisColor);
if (val2.HasProperty(EmissionColorProperty))
{
val2.EnableKeyword("_EMISSION");
val2.SetColor(EmissionColorProperty, CrisisEmission);
}
}
}
}
}
private static void SetTint(Material material, int property, Color color)
{
//IL_000c: 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)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
if (material.HasProperty(property))
{
color.a = material.GetColor(property).a;
material.SetColor(property, color);
}
}
private void CreateWarningLight()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//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)
GameObject val = new GameObject("ZombieCrisis.CrimsonGlow");
val.transform.SetParent(((Component)this).transform, false);
val.transform.localPosition = new Vector3(0f, 1.65f, 0f);
Light val2 = val.AddComponent<Light>();
val2.type = (LightType)2;
val2.color = CrisisColor;
val2.intensity = 2.2f;
val2.range = 5.5f;
val2.shadows = (LightShadows)0;
}
private void OnDestroy()
{
ActiveMarkers.Remove(this);
foreach (Material ownedMaterial in _ownedMaterials)
{
if ((Object)(object)ownedMaterial != (Object)null)
{
Object.Destroy((Object)(object)ownedMaterial);
}
}
_ownedMaterials.Clear();
}
}