using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("DoubleDamageMod")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DoubleDamageMod")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("65218193-4214-430d-a58c-f83b343cd02f")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
public class CloneMarker : MonoBehaviour
{
private GameObject original;
private HealthManager originalHealth;
private HealthManager cloneHealth;
private bool startBattleTriggered = false;
public Action StartBattleEvent;
public void CopyState(GameObject original, HealthManager healthManager, bool isSharedHPEnabled, EnemyType enemyType)
{
this.original = original;
originalHealth = healthManager;
if (((Object)((Component)healthManager).gameObject).name.Contains("Roachkeeper Chef Tiny"))
{
return;
}
SongGolemFix();
DeleteMossBerry();
if (enemyType == EnemyType.Arena)
{
BattleSceneFix();
if (!DoubleEnemiesMod.EnableSharedHPUnsafeMode.Value)
{
return;
}
}
cloneHealth = ((Component)this).GetComponent<HealthManager>();
if ((Object)(object)cloneHealth == (Object)null)
{
HealthManager[] componentsInChildren = ((Component)this).GetComponentsInChildren<HealthManager>();
componentsInChildren = componentsInChildren.OrderBy((HealthManager c) => ((Object)c).name).ToArray();
HealthManager[] componentsInChildren2 = original.GetComponentsInChildren<HealthManager>();
componentsInChildren2 = componentsInChildren2.OrderBy((HealthManager c) => ((Object)c).name).ToArray();
if (componentsInChildren2.Length != componentsInChildren.Length)
{
DoubleEnemiesMod.Log($"[{((Object)((Component)this).gameObject).name}] Non equal amount of Healthcomponents ({componentsInChildren2.Length},{componentsInChildren.Length})");
return;
}
if (componentsInChildren2.Length > 2 && !DoubleEnemiesMod.EnableSharedHPUnsafeMode.Value)
{
DoubleEnemiesMod.Log($"[{((Object)((Component)this).gameObject).name}] stopped linking objects due to too high object counts causing instability: {componentsInChildren2.Length}");
return;
}
for (int i = 0; i < componentsInChildren2.Length; i++)
{
SyncPair(componentsInChildren2[i], componentsInChildren[i], isSharedHPEnabled);
}
}
else
{
SyncPair(originalHealth, cloneHealth, isSharedHPEnabled);
}
}
private void SyncPair(HealthManager _originalHealth, HealthManager _cloneHealth, bool isSharedHPEnabled)
{
if (!((Object)((Component)_cloneHealth).gameObject).name.Contains(((Object)((Component)_originalHealth).gameObject).name))
{
DoubleEnemiesMod.Log("[" + ((Object)((Component)_originalHealth).gameObject).name + "] " + ((Object)((Component)_originalHealth).gameObject).name + " and " + ((Object)((Component)_cloneHealth).gameObject).name + " do not share a name");
}
else
{
DoubleEnemiesMod.Log("[" + ((Object)((Component)this).gameObject).name + "] Pairing " + ((Object)((Component)_originalHealth).gameObject).name + " with " + ((Object)((Component)_cloneHealth).gameObject).name);
CloneSync cloneSync = ((Component)_cloneHealth).gameObject.AddComponent<CloneSync>();
cloneSync.Init(this, _originalHealth, _cloneHealth, isSharedHPEnabled);
}
}
private void SongGolemFix()
{
if (!((Object)original).name.Contains("song_golem"))
{
return;
}
DamageHero[] array = Resources.FindObjectsOfTypeAll<DamageHero>();
foreach (DamageHero val in array)
{
if (((Object)((Component)val).gameObject).name == "Lava Rock Damager")
{
Object.DestroyImmediate((Object)(object)val);
DoubleEnemiesMod.Log("Destroyed Rock Damager");
}
}
}
public void LastJudgeFix()
{
if (!((Object)originalHealth).name.Contains("Last Judge"))
{
return;
}
string[] array = new string[4] { "Great Gate", "Gate L", "Gate Quest Ender", "Gate Open Trigger" };
string[] array2 = array;
foreach (string text in array2)
{
Transform val = ((Component)this).gameObject.transform.Find(text);
if ((Object)(object)val != (Object)null)
{
DoubleEnemiesMod.Log("LastJudgeFix: Found '" + text + "', destroying...");
Object.Destroy((Object)(object)((Component)val).gameObject);
}
else
{
DoubleEnemiesMod.Log("LastJudgeFix: Could not find '" + text + "' on " + ((Object)((Component)this).gameObject).name);
}
}
}
private void BattleSceneFix()
{
//IL_001d: 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)
BattleScene component = ((Component)this).GetComponent<BattleScene>();
if (!((Object)(object)component != (Object)null))
{
return;
}
Scene scene = ((Component)this).gameObject.scene;
if (((Scene)(ref scene)).name.Contains("Memory_Coral_Tower"))
{
DoubleEnemiesMod.Log("Coral Tower detected");
component.StartBattle();
return;
}
CloneMarker component2 = original.GetComponent<CloneMarker>();
if ((Object)(object)component2 != (Object)null)
{
component2.LinkBattleScene(this);
component2.StartBattleEvent = (Action)Delegate.Combine(component2.StartBattleEvent, new Action(StartBattle));
DoubleEnemiesMod.Log("Connected to original BattleScene");
}
else
{
DoubleEnemiesMod.Log("original BattleScene has no marker");
}
}
public void LinkBattleScene(CloneMarker clone)
{
BattleScene component = ((Component)this).GetComponent<BattleScene>();
if ((Object)(object)component != (Object)null)
{
clone.StartBattleEvent = (Action)Delegate.Combine(clone.StartBattleEvent, new Action(clone.StartBattle));
}
else
{
DoubleEnemiesMod.Log("BattleScene link failed on object " + ((Object)((Component)this).gameObject).name);
}
}
public void StartBattle()
{
BattleScene component = ((Component)this).GetComponent<BattleScene>();
if (!startBattleTriggered)
{
startBattleTriggered = true;
component.StartBattle();
}
}
private void DeleteMossBerry()
{
if (!((Object)((Component)this).gameObject).name.Contains("Aspid Collector"))
{
return;
}
string[] array = new string[2] { "Mossberry Pickup", "Berry Sprite" };
string[] array2 = array;
foreach (string text in array2)
{
Transform val = ((Component)this).gameObject.transform.Find(text);
if ((Object)(object)val != (Object)null)
{
DoubleEnemiesMod.Log("DeleteMossberry: Found '" + text + "', destroying...");
Object.Destroy((Object)(object)((Component)val).gameObject);
}
else
{
DoubleEnemiesMod.Log("DeleteMossberry: Could not find '" + text + "' on " + ((Object)((Component)this).gameObject).name);
}
}
}
private void LogAllComponents()
{
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Expected O, but got Unknown
DoubleEnemiesMod.Log("--- Components on " + ((Object)((Component)this).gameObject).name + " ---");
Component[] components = ((Component)this).gameObject.GetComponents<Component>();
Component[] array = components;
foreach (Component val in array)
{
if ((Object)(object)val != (Object)null)
{
DoubleEnemiesMod.Log(((object)val).GetType().Name);
}
else
{
DoubleEnemiesMod.Log("Missing (null) Component found!");
}
}
foreach (Transform item in ((Component)this).transform)
{
Transform val2 = item;
DoubleEnemiesMod.Log("[" + ((Object)((Component)this).gameObject).name + "] has child: " + ((Object)((Component)val2).gameObject).name);
components = ((Component)val2).GetComponents<Component>();
DoubleEnemiesMod.Log("--- Components on " + ((Object)val2).name + " ---");
Component[] array2 = components;
foreach (Component val3 in array2)
{
if ((Object)(object)val3 != (Object)null)
{
DoubleEnemiesMod.Log(((object)val3).GetType().Name);
}
else
{
DoubleEnemiesMod.Log("Missing (null) Component found!");
}
}
}
}
private static string GetFullPath(GameObject obj)
{
string text = ((Object)obj).name;
Transform parent = obj.transform.parent;
while ((Object)(object)parent != (Object)null)
{
text = ((Object)parent).name + "/" + text;
parent = parent.parent;
}
return text;
}
}
public class CloneSync : MonoBehaviour
{
private CloneMarker marker;
private HealthManager originalHealth;
private HealthManager cloneHealth;
private PlayMakerFSM originalFSM;
private PlayMakerFSM cloneFSM;
private bool isSynced = false;
private string lastLoggedState = "";
public void Init(CloneMarker marker, HealthManager originalHealth, HealthManager cloneHealth, bool isSharedHPEnabled)
{
this.marker = marker;
this.originalHealth = originalHealth;
this.cloneHealth = cloneHealth;
originalFSM = ((Component)originalHealth).GetComponent<PlayMakerFSM>();
cloneFSM = ((Component)cloneHealth).GetComponent<PlayMakerFSM>();
if ((Object)(object)originalFSM == (Object)null || (Object)(object)cloneFSM == (Object)null)
{
isSynced = true;
}
if (isSharedHPEnabled)
{
SharedHPManager.Connect(originalHealth, cloneHealth);
if (((Object)((Component)this).gameObject).name.Contains("Last Judge"))
{
cloneHealth.TookDamage += OnLastJudgeDamaged;
}
}
}
private void LateUpdate()
{
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
if (isSynced)
{
return;
}
string activeStateName = originalFSM.Fsm.ActiveStateName;
cloneFSM.SetState(activeStateName);
((Component)this).transform.position = ((Component)originalHealth).transform.position;
if (activeStateName == null)
{
return;
}
if (activeStateName != lastLoggedState)
{
DoubleEnemiesMod.Log("[" + ((Object)((Component)this).gameObject).name + "] Current state: " + activeStateName);
lastLoggedState = activeStateName;
}
bool flag = false;
string[] syncStates = StringLists.SyncStates;
foreach (string text in syncStates)
{
if (text == activeStateName)
{
flag = true;
}
}
if (!flag)
{
isSynced = true;
DoubleEnemiesMod.Log("[" + ((Object)((Component)this).gameObject).name + "] Stopped syncing: " + activeStateName);
}
}
private void OnLastJudgeDamaged()
{
marker.LastJudgeFix();
cloneHealth.TookDamage -= OnLastJudgeDamaged;
}
}
[BepInPlugin("com.adwamogus.skdoubleenemiesmod", "Silksong Double Enemies Mod", "0.7.3")]
public class DoubleEnemiesMod : BaseUnityPlugin
{
[CompilerGenerated]
private sealed class <DelayedScanWisps>d__10 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public Scene scene;
public DoubleEnemiesMod <>4__this;
private GameObject[] <>s__1;
private int <>s__2;
private GameObject <root>5__3;
private GameObject <clone>5__4;
private GameObject <clone>5__5;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <DelayedScanWisps>d__10(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>s__1 = null;
<root>5__3 = null;
<clone>5__4 = null;
<clone>5__5 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Expected O, but got Unknown
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_0175: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = (object)new WaitForSeconds(0.1f);
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
<>s__1 = ((Scene)(ref scene)).GetRootGameObjects();
for (<>s__2 = 0; <>s__2 < <>s__1.Length; <>s__2++)
{
<root>5__3 = <>s__1[<>s__2];
if (((Object)<root>5__3).name.Contains("Wisp Flame Lantern") && EnableEnemies.Value)
{
Log("[Clone] Cloning " + ((Object)<root>5__3).name + " in " + ((Scene)(ref scene)).name);
<clone>5__4 = Object.Instantiate<GameObject>(<root>5__3, <root>5__3.transform.position, <root>5__3.transform.rotation, <root>5__3.transform.parent);
<clone>5__4 = null;
}
if (((Object)<root>5__3).name.Contains("Boss Scene") && EnableBosses.Value)
{
Log("[Clone] Cloning " + ((Object)<root>5__3).name + " in " + ((Scene)(ref scene)).name);
<clone>5__5 = Object.Instantiate<GameObject>(<root>5__3, <root>5__3.transform.position, <root>5__3.transform.rotation, <root>5__3.transform.parent);
<clone>5__5 = null;
}
<root>5__3 = null;
}
<>s__1 = null;
return false;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
public static ConfigEntry<int> Multiplier;
public static ConfigEntry<bool> debugLog;
public static ConfigEntry<bool> EnableEnemies;
public static ConfigEntry<bool> EnableArenas;
public static ConfigEntry<bool> EnableBosses;
public static ConfigEntry<bool> EnableSharedHP;
public static ConfigEntry<bool> EnableSharedHPUnsafeMode;
private static ManualLogSource logger;
private void Awake()
{
logger = ((BaseUnityPlugin)this).Logger;
Multiplier = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Multiplier", 2, "Enemy * Multiplier = the amount of enemies spawned");
debugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLog", false, "For development");
EnableEnemies = ((BaseUnityPlugin)this).Config.Bind<bool>("Control", "Enable Enemies", true, "Enables cloning of all normal enemies.");
EnableArenas = ((BaseUnityPlugin)this).Config.Bind<bool>("Control", "Enable Arenas", true, "Enables cloning of all arenas.");
EnableBosses = ((BaseUnityPlugin)this).Config.Bind<bool>("Control", "Enable Bosses", true, "Enables cloning of all bosses.");
EnableSharedHP = ((BaseUnityPlugin)this).Config.Bind<bool>("Control", "Enable Shared HP", true, "Multiplies boss hp with the Multiplier and shares all damage between bosses. Supported bosses will now die at the same time.");
EnableSharedHPUnsafeMode = ((BaseUnityPlugin)this).Config.Bind<bool>("Control", "Enable Shared HP unsafe mode", false, "Removes saveguards for SharedHP. This forces the system to accept arenas and any amount of enemies as a valid target. Turning this on may result in unexpected behaviour of certain bosses/arenas.");
((BaseUnityPlugin)this).Logger.LogInfo((object)"Double Enemies Mod loaded");
Harmony.CreateAndPatchAll(typeof(DoubleEnemiesMod), (string)null);
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
if (((Scene)(ref scene)).name.Contains("Wisp") || ((Scene)(ref scene)).name.Contains("Belltown_08"))
{
((MonoBehaviour)this).StartCoroutine(DelayedScanWisps(scene));
}
}
[IteratorStateMachine(typeof(<DelayedScanWisps>d__10))]
private IEnumerator DelayedScanWisps(Scene scene)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <DelayedScanWisps>d__10(0)
{
<>4__this = this,
scene = scene
};
}
public static void Log(string msg)
{
if (debugLog.Value)
{
if (logger != null)
{
logger.LogInfo((object)msg);
}
else
{
Logger.CreateLogSource("DoubleEnemiesMod").LogInfo((object)msg);
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(HealthManager), "Start")]
private static void OnHealthManagerEnabled(HealthManager __instance)
{
if (!((Object)(object)__instance == (Object)null) && Multiplier.Value > 1)
{
TryDuplicateInstance(__instance);
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(BattleScene), "StartBattle")]
private static void OnBattleStart(BattleScene __instance)
{
Log("[BattleScenePatcher] BattleScene start detected");
CloneMarker component = ((Component)__instance).GetComponent<CloneMarker>();
if ((Object)(object)component != (Object)null)
{
component.StartBattleEvent();
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(HealthManager), "Die", new Type[]
{
typeof(float?),
typeof(AttackTypes),
typeof(NailElements),
typeof(GameObject),
typeof(bool),
typeof(float),
typeof(bool),
typeof(bool)
})]
private static void OnHealthManagerDie(HealthManager __instance)
{
Log($"[{((Object)((Component)__instance).gameObject).name}] HealthManagerDie: {__instance.isDead}, {__instance.hp}");
SharedHPID component = ((Component)__instance).GetComponent<SharedHPID>();
if ((Object)(object)component != (Object)null)
{
SharedHPManager.ReportDeath(__instance, component.ID);
}
}
private static void TryDuplicateInstance(HealthManager healthManager)
{
//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_00ce: 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)
try
{
GameObject gameObject = ((Component)healthManager).gameObject;
if ((Object)(object)gameObject.GetComponent<CloneMarker>() != (Object)null || (Object)(object)gameObject.GetComponentInParent<CloneMarker>() != (Object)null)
{
return;
}
string[] blacklist = StringLists.Blacklist;
Scene scene;
foreach (string value in blacklist)
{
if (((Object)gameObject).name.Contains(value))
{
string[] obj = new string[6]
{
"[Blacklist] Skipped: ",
((Object)gameObject).name,
" (",
((Object)gameObject).name,
") in scene ",
null
};
scene = gameObject.scene;
obj[5] = ((Scene)(ref scene)).name;
Log(string.Concat(obj));
return;
}
}
bool flag = true;
string[] blacklistedScenes = StringLists.BlacklistedScenes;
foreach (string value2 in blacklistedScenes)
{
scene = gameObject.scene;
if (((Scene)(ref scene)).name.Contains(value2))
{
flag = false;
Log("[Blacklist] " + ((Object)gameObject).name + " is in a blacklisted scene. Skipping parent scans");
}
}
if (flag)
{
Transform val = gameObject.transform;
while ((Object)(object)val != (Object)null)
{
string name = ((Object)((Component)val).gameObject).name;
Log("[" + ((Object)gameObject).name + "] Parent name: " + name);
string[] parentKeywords = StringLists.ParentKeywords;
foreach (string value3 in parentKeywords)
{
if (name.Contains(value3))
{
if ((Object)(object)((Component)val).GetComponent<CloneMarker>() == (Object)null)
{
CloneObject(((Component)val).gameObject, healthManager);
}
else
{
Log("[" + ((Object)gameObject).name + "] Parent was already cloned");
}
return;
}
}
val = val.parent;
}
}
CloneObject(gameObject, healthManager);
}
catch (Exception arg)
{
GameObject gameObject2 = ((Component)healthManager).gameObject;
Log($"[Error] Error while duplicating {((gameObject2 != null) ? ((Object)gameObject2).name : null)}: {arg}");
}
}
private static void CloneObject(GameObject gameObject, HealthManager healthManager)
{
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
EnemyType enemyType = GetEnemyType(((Object)gameObject).name);
if (CheckEnemyEnabled(enemyType, ((Object)gameObject).name))
{
bool isSharedHPEnabled = false;
if (EnableSharedHP.Value && enemyType == EnemyType.Boss)
{
isSharedHPEnabled = true;
}
if (EnableSharedHP.Value && EnableSharedHPUnsafeMode.Value && enemyType == EnemyType.Arena)
{
isSharedHPEnabled = true;
}
CloneMarker cloneMarker = gameObject.AddComponent<CloneMarker>();
for (int i = 0; i < Multiplier.Value - 1; i++)
{
GameObject val = Object.Instantiate<GameObject>(gameObject, gameObject.transform.position, gameObject.transform.rotation, gameObject.transform.parent);
((Object)val).name = ((Object)val).name + "DECLONE";
CloneMarker component = val.GetComponent<CloneMarker>();
component.CopyState(gameObject, healthManager, isSharedHPEnabled, enemyType);
string[] obj = new string[6]
{
"[Clone] ",
((Object)gameObject).name,
" -> ",
((Object)val).name,
" in scene ",
null
};
Scene scene = gameObject.gameObject.scene;
obj[5] = ((Scene)(ref scene)).name;
Log(string.Concat(obj));
}
}
}
private static bool CheckEnemyEnabled(EnemyType type, string gameObjectName)
{
switch (type)
{
case EnemyType.Enemy:
if (EnableEnemies.Value)
{
return true;
}
Log("[" + gameObjectName + "] was not cloned due to config settings (Enemy)");
return false;
case EnemyType.Arena:
if (EnableArenas.Value)
{
return true;
}
Log("[" + gameObjectName + "] was not cloned due to config settings (Arena)");
return false;
case EnemyType.Boss:
if (EnableBosses.Value)
{
return true;
}
Log("[" + gameObjectName + "] was not cloned due to config settings (Boss)");
return false;
default:
Log("$[{gameObjectName}] Invalid enemy type exception");
return false;
}
}
public static EnemyType GetEnemyType(string gameObjectName)
{
string[] arenaFilterKeywords = StringLists.ArenaFilterKeywords;
foreach (string value in arenaFilterKeywords)
{
if (gameObjectName.Contains(value))
{
return EnemyType.Arena;
}
}
string[] bossFilterKeywords = StringLists.BossFilterKeywords;
foreach (string value2 in bossFilterKeywords)
{
if (gameObjectName.Contains(value2))
{
return EnemyType.Boss;
}
}
return EnemyType.Enemy;
}
}
public static class StringLists
{
public static readonly string[] Blacklist = new string[3] { "Crystal Drifter", "Zap Core Enemy", "Music Box Bell" };
public static readonly string[] BlacklistedScenes = new string[5] { "Shellwood_18", "Shadow_18", "Dust_Chef", "Bone_18", "Bone_East_08_boss_beastfly" };
public static readonly string[] SyncStates = new string[23]
{
"Pause", "Dormant", "Zoom Down", "Spear Spawn Pause", "Burst Out", "Fly In", "Jump Away Air", "Burst Out?", "Spawn Antic", "Spawn",
"BG Dance", "Challenge Pause", "Battle Roar Antic", "Battle Roar", "Battle Roar End", "Battle Dance", "Init", "Ready", "Wall", "Ambush Ready",
"Pointing", "Arena Start", "Roar"
};
public static readonly string[] ParentKeywords = new string[8] { "Dancer Control", "Boss Scene", "Battle Scene", "Muckmen Control", "song_golem", "First Weaver", "Silk Boss", "Lace Boss2 New" };
public static readonly string[] BossFilterKeywords = new string[12]
{
"Dancer Control", "Boss Scene", "Splinter Queen", "song_golem", "Vampire Gnat Boss", "First Weaver", "Silk Boss", "Lace Boss2 New", "Swamp Shaman", "Roachkeeper Chef",
"Bone Flyer Giant", "Lost Lace Boss"
};
public static readonly string[] ArenaFilterKeywords = new string[1] { "Battle Scene" };
}
public enum EnemyType
{
Enemy,
Arena,
Boss
}
public static class SharedHPManager
{
public static Dictionary<int, SharedHPInstance> SharedHpInstances = new Dictionary<int, SharedHPInstance>();
private static int id = 0;
public static void Connect(HealthManager original, HealthManager clone)
{
SharedHPID sharedHPID = ((Component)original).GetComponent<SharedHPID>();
if ((Object)(object)sharedHPID == (Object)null)
{
int key = id;
id++;
SharedHpInstances.Add(key, new SharedHPInstance(original));
sharedHPID = AddSharedHPID(original, key);
DoubleEnemiesMod.Log("[SharedHPManager] Created new SharedHPInstance (" + ((Object)((Component)original).gameObject).name + ")");
}
SharedHpInstances[sharedHPID.ID].AddToList(clone);
AddSharedHPID(clone, sharedHPID.ID);
}
public static void Clear()
{
if (!Extensions.IsNullOrEmpty<KeyValuePair<int, SharedHPInstance>>((ICollection<KeyValuePair<int, SharedHPInstance>>)SharedHpInstances))
{
DoubleEnemiesMod.Log("[SharedHPManager] Cleared all SharedHPInstances");
SharedHpInstances.Clear();
}
}
public static SharedHPID AddSharedHPID(HealthManager healthManager, int id)
{
SharedHPID sharedHPID = ((Component)healthManager).gameObject.AddComponent<SharedHPID>();
sharedHPID.ID = id;
return sharedHPID;
}
public static void ReportDeath(HealthManager healthManager, int id)
{
if (IsDead(healthManager.hp))
{
SharedHpInstances[id].DeathSync();
}
}
public static bool IsDead(int currentHP)
{
if (currentHP <= 0 || currentHP == 99999)
{
return true;
}
return false;
}
}
public class SharedHPInstance
{
private List<HealthManager> hpComponents;
private float residualDamage = 0f;
private string name;
public SharedHPInstance(HealthManager original)
{
name = ((Object)((Component)original).gameObject).name;
hpComponents = new List<HealthManager>();
AddToList(original);
}
public void AddToList(HealthManager healthManager)
{
hpComponents.Add(healthManager);
healthManager.TookDamage += Update;
}
public void Update()
{
DoubleEnemiesMod.Log("[SharedHpInstance/" + name + "] Triggered update");
if (hpComponents.Count != DoubleEnemiesMod.Multiplier.Value)
{
DoubleEnemiesMod.Log($"[SharedHpInstance/{name}] The incorrect amount of enemies are registered ({hpComponents.Count})");
}
else
{
DistributeHP();
}
}
private void DistributeHP()
{
float num = 0f - residualDamage;
foreach (HealthManager hpComponent in hpComponents)
{
num += (float)hpComponent.hp;
}
float num2 = num / (float)DoubleEnemiesMod.Multiplier.Value;
int num3 = Mathf.CeilToInt(num2);
residualDamage = ((float)num3 - num2) * (float)DoubleEnemiesMod.Multiplier.Value;
foreach (HealthManager hpComponent2 in hpComponents)
{
hpComponent2.ApplyExtraDamage(hpComponent2.hp - num3);
}
DoubleEnemiesMod.Log($"[SharedHpInstance/{name}] HP distributed: targetHP/{num3}, residualDamage/{residualDamage}");
}
public void DeathSync()
{
//IL_002e: 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_0054: 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)
foreach (HealthManager hpComponent in hpComponents)
{
if (!SharedHPManager.IsDead(hpComponent.hp))
{
DamageTagInstance val = default(DamageTagInstance);
val.isHeroDamage = true;
val.amount = hpComponent.hp;
val.specialDamageType = (SpecialDamageTypes)0;
val.nailElements = (NailElements)0;
hpComponent.ApplyTagDamage(val);
DoubleEnemiesMod.Log("[Death Sync/" + name + "] killed " + ((Object)((Component)hpComponent).gameObject).name);
}
}
}
}
public class SharedHPID : MonoBehaviour
{
public int ID;
}