using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using RoR2;
using UnityEngine;
using UnityEngine.AddressableAssets;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.3.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 Local.Enemy.Variety
{
internal class Override : MonoBehaviour
{
internal Type value;
internal static void Set(CombatDirector director, Type value)
{
Override @override = ((Component)director).GetComponent<Override>();
if (value == Type.None)
{
if (!Object.op_Implicit((Object)(object)@override))
{
return;
}
Object.Destroy((Object)(object)@override);
}
else if (@override == null)
{
@override = ((Component)director).gameObject.AddComponent<Override>();
}
Console.WriteLine($"Set override to '{value}' for \"{((Object)director).name}\".");
@override.value = value;
}
internal static Type Get(CombatDirector director)
{
Override @override = default(Override);
if (!((Component)director).TryGetComponent<Override>(ref @override))
{
return Type.None;
}
return @override.value;
}
public static void Clear(CombatDirector director)
{
ref bool hasStartedWave = ref director.hasStartedWave;
if (hasStartedWave)
{
Set(director, Type.None);
}
hasStartedWave = false;
}
}
internal enum Type
{
None,
Scene,
Boss,
Shrine,
Card
}
internal class Hook
{
[HarmonyPatch(typeof(CombatDirector), "Simulate")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> TriggerWaveStart(IEnumerable<CodeInstruction> IL)
{
System.Type typeFromHandle = typeof(CombatDirector);
FieldInfo indicator = typeFromHandle.GetField("hasStartedWave", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
FieldInfo configuration = typeFromHandle.GetField("shouldSpawnOneWave");
foreach (CodeInstruction instruction in IL)
{
yield return instruction;
if (CodeInstructionExtensions.LoadsField(instruction, configuration, false))
{
yield return new CodeInstruction(OpCodes.Pop, (object)null);
yield return new CodeInstruction(OpCodes.Ldc_I4_1, (object)null);
}
else if (CodeInstructionExtensions.LoadsField(instruction, indicator, false))
{
yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
yield return new CodeInstruction(OpCodes.Ldfld, (object)configuration);
yield return new CodeInstruction(OpCodes.And, (object)null);
yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
yield return new CodeInstruction(OpCodes.Call, (object)typeof(Override).GetMethod("Clear"));
}
}
}
[HarmonyPatch(typeof(CombatDirector), "SpendAllCreditsOnMapSpawns")]
[HarmonyPrefix]
private static void PopulateScene(CombatDirector __instance)
{
__instance.hasStartedWave = true;
Override.Set(__instance, Type.Scene);
}
[HarmonyPatch(typeof(CombatDirector), "SpendAllCreditsOnMapSpawns")]
[HarmonyPostfix]
private static void EndScene(CombatDirector __instance)
{
Override.Clear(__instance);
}
[HarmonyPatch(typeof(CombatDirector), "SetNextSpawnAsBoss")]
[HarmonyPrefix]
private static void SetBoss(CombatDirector __instance)
{
Override.Set(__instance, Type.Boss);
}
[HarmonyPatch(typeof(CombatDirector), "CombatShrineActivation")]
[HarmonyPostfix]
private static void CombatShrine(CombatDirector __instance)
{
Override.Set(__instance, Type.Shrine);
}
[HarmonyPatch(typeof(CombatDirector), "OverrideCurrentMonsterCard")]
[HarmonyPrefix]
private static void OverrideMonsterCard(CombatDirector __instance)
{
Override.Set(__instance, Type.Card);
}
}
[BepInPlugin("local.enemy.variety", "EnemyVariety", "0.3.0")]
internal class Plugin : BaseUnityPlugin
{
public const string version = "0.3.0";
public const string identifier = "local.enemy.variety";
private static ConfigEntry<bool> scene;
private static ConfigEntry<bool> boss;
private static ConfigEntry<bool> combat;
private static ConfigEntry<float> horde;
protected async void Awake()
{
boss = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Apply to Teleporter Boss", true, "If enabled, multiple types of bosses may appear for the teleporter event.");
horde = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Horde of Many", 5f, new ConfigDescription("Percent chance for a different type of monster to be chosen instead.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
scene = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Scene Director", true, "This determines if expensive enemies are favored during initialization.");
combat = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Shrine of Combat", true, "Whether those summoned by this interactable should be affected.");
Harmony.CreateAndPatchAll(typeof(Plugin), (string)null);
Harmony.CreateAndPatchAll(typeof(Hook), (string)null);
GameObject val = await Addressables.LoadAssetAsync<GameObject>((object)"RoR2/DLC2/ShrineHalcyonite.prefab").Task;
if (Object.op_Implicit((Object)(object)val))
{
CombatDirector[] componentsInChildren = val.GetComponentsInChildren<CombatDirector>();
for (int i = 0; i < componentsInChildren.Length; i++)
{
((Behaviour)componentsInChildren[i]).enabled = false;
}
}
}
[HarmonyPatch(typeof(CombatDirector), "AttemptSpawnOnTarget")]
[HarmonyPrefix]
private static void ResetMonsterCard(CombatDirector __instance)
{
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_016a: Unknown result type (might be due to invalid IL or missing references)
//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
WeightedSelection<DirectorCard> finalMonsterCardsSelection = __instance.finalMonsterCardsSelection;
if (finalMonsterCardsSelection == null || !__instance.resetMonsterCardIfFailed)
{
return;
}
DirectorCard currentMonsterCard = __instance.currentMonsterCard;
Xoroshiro128Plus rng = __instance.rng;
bool? flag = null;
switch (Override.Get(__instance))
{
case Type.Scene:
{
SceneDef currentSceneDef = SceneCatalog.currentSceneDef;
if (!scene.Value || !(currentSceneDef?.stageOrder <= Run.stagesPerLoop))
{
return;
}
break;
}
case Type.Boss:
if (!boss.Value)
{
return;
}
if (__instance.hasStartedWave)
{
flag = false;
if (currentMonsterCard == null || !currentMonsterCard.IsBoss())
{
return;
}
}
else
{
flag = rng.nextNormalizedFloat < horde.Value / 100f;
if (currentMonsterCard != null && currentMonsterCard.IsBoss() != flag)
{
return;
}
}
break;
case Type.Shrine:
if (!combat.Value)
{
return;
}
break;
case Type.Card:
return;
}
int spawnCountInCurrentWave = __instance.spawnCountInCurrentWave;
int num = 0;
if (currentMonsterCard != null)
{
num = currentMonsterCard.cost;
}
else if (!flag.HasValue)
{
return;
}
WeightedSelection<DirectorCard> val = new WeightedSelection<DirectorCard>(finalMonsterCardsSelection.Count);
float monsterCredit = __instance.monsterCredit;
float val2 = Math.Min(800f, monsterCredit);
for (int i = 0; i < finalMonsterCardsSelection.Count; i++)
{
ChoiceInfo<DirectorCard> choice = finalMonsterCardsSelection.GetChoice(i);
currentMonsterCard = choice.value;
if ((currentMonsterCard.cost <= num || !((float)currentMonsterCard.cost > monsterCredit)) && currentMonsterCard.IsAvailable())
{
if (!flag.HasValue)
{
choice.weight *= Math.Min(currentMonsterCard.cost, val2);
}
else if (currentMonsterCard.IsBoss() == flag)
{
continue;
}
val.AddChoice(choice);
}
}
if (val.Count > 0)
{
currentMonsterCard = val.Evaluate(rng.nextNormalizedFloat);
__instance.PrepareNewMonsterWave(currentMonsterCard);
__instance.spawnCountInCurrentWave = spawnCountInCurrentWave;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Chat), "SendBroadcastChat", new System.Type[] { typeof(ChatMessageBase) })]
private static void ChangeMessage(ChatMessageBase message)
{
SubjectFormatChatMessage val = (SubjectFormatChatMessage)(object)((message is SubjectFormatChatMessage) ? message : null);
if (val != null)
{
bool? flag = val.paramTokens?.Any();
if (flag.HasValue && flag.GetValueOrDefault() && combat.Value && ((SubjectChatMessage)val).baseToken == "SHRINE_COMBAT_USE_MESSAGE")
{
val.paramTokens[0] = Language.GetString("LOGBOOK_CATEGORY_MONSTER").ToLower();
}
}
}
[HarmonyPatch(typeof(BossGroup), "UpdateBossMemories")]
[HarmonyPostfix]
private static void UpdateTitle(BossGroup __instance)
{
if (!boss.Value)
{
return;
}
Dictionary<(string, string), float> dictionary = new Dictionary<(string, string), float>();
float num = 0f;
for (int i = 0; i < __instance.bossMemoryCount; i++)
{
CharacterBody cachedBody = __instance.bossMemories[i].cachedBody;
if (!Object.op_Implicit((Object)(object)cachedBody))
{
continue;
}
HealthComponent healthComponent = cachedBody.healthComponent;
if (!(((healthComponent != null) ? new bool?(healthComponent.alive) : null) ?? true))
{
continue;
}
string bestBodyName = Util.GetBestBodyName(((Component)cachedBody).gameObject);
string text = cachedBody.GetSubtitle();
(string, string) key = (bestBodyName, text);
if (!dictionary.ContainsKey(key))
{
dictionary[key] = 0f;
}
dictionary[key] += healthComponent.combinedHealth + healthComponent.missingCombinedHealth * 4f;
if (dictionary[key] > num)
{
num = dictionary[key];
if (string.IsNullOrEmpty(text))
{
text = Language.GetString("NULL_SUBTITLE");
}
__instance.bestObservedName = bestBodyName;
__instance.bestObservedSubtitle = "<sprite name=\"CloudLeft\" tint=1> " + text + " <sprite name=\"CloudRight\" tint=1>";
}
}
}
[HarmonyPatch(typeof(CombatDirector), "SpendAllCreditsOnMapSpawns")]
[HarmonyILManipulator]
private static void SkipReroll(ILContext context)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Expected O, but got Unknown
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
ILCursor val = new ILCursor(context);
MethodInfo method = typeof(CombatDirector).GetMethod("PrepareNewMonsterWave", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
{
(Instruction i) => ILPatternMatchingExt.MatchCall(i, (MethodBase)method)
}))
{
ILLabel val2 = val.MarkLabel();
ILLabel val3 = default(ILLabel);
if (val.TryGotoPrev((MoveType)2, new Func<Instruction, bool>[1]
{
(Instruction i) => ILPatternMatchingExt.MatchBr(i, ref val3)
}))
{
val.MoveAfterLabels();
val.EmitDelegate<Func<bool>>((Func<bool>)(() => scene.Value));
val.Emit(OpCodes.Brtrue, (object)val2);
return;
}
}
Console.WriteLine("Failed to patch scene combat director.");
}
}
internal static class Extension
{
internal static bool IsBoss(this DirectorCard card)
{
SpawnCard spawnCard = card.spawnCard;
CharacterSpawnCard val = (CharacterSpawnCard)(object)((spawnCard is CharacterSpawnCard) ? spawnCard : null);
if (val == null || val.forbiddenAsBoss)
{
return false;
}
return ((SpawnCard)val).prefab.GetComponent<CharacterMaster>().bodyPrefab.GetComponent<CharacterBody>().isChampion;
}
}
}