using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Burst2Flame;
using Burst2Flame.Observable;
using HarmonyLib;
using MapMaker;
using Microsoft.CodeAnalysis;
using ModNet;
using Steamworks;
using Steamworks.Data;
using StolenRealmModAPI;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[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("WaveDefense")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+e541341b423e7e02f062bf9975ad907cb3f30935")]
[assembly: AssemblyProduct("WaveDefense")]
[assembly: AssemblyTitle("WaveDefense")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[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 WaveDefense
{
internal static class Factions
{
private static readonly List<EnemyType> WaveTypes = new List<EnemyType>
{
(EnemyType)0,
(EnemyType)1,
(EnemyType)2,
(EnemyType)4
};
internal static bool RollingWaveOne;
private static readonly List<EnemyType> BossType = new List<EnemyType> { (EnemyType)3 };
internal static bool On
{
get
{
if (Plugin.Enabled.Value && Plugin.AnyFaction.Value)
{
if (!RollingWaveOne)
{
return Waves.Active;
}
return true;
}
return false;
}
}
internal static List<EnemyGroup> All(int level)
{
GlobalSettings gs = GlobalSettingsManager.instance.globalSettings;
return (from EnemyGroup g in Enum.GetValues(typeof(EnemyGroup))
where (int)g != 72 && (gs.GetEnemyPool(g, level, WaveTypes)?.Count ?? 0) > 0
select g).ToList();
}
internal static List<CharacterInfo> AllBosses(int level)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Invalid comparison between Unknown and I4
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
GlobalSettings globalSettings = GlobalSettingsManager.instance.globalSettings;
List<CharacterInfo> list = new List<CharacterInfo>();
foreach (EnemyGroup value in Enum.GetValues(typeof(EnemyGroup)))
{
if ((int)value != 72)
{
list.AddRange(globalSettings.GetEnemyPool(value, level, BossType) ?? new List<CharacterInfo>());
}
}
return list.Where((CharacterInfo i) => (Object)(object)i != (Object)null).Distinct().ToList();
}
}
[HarmonyPatch(typeof(GlobalSettings), "GetPossibleEnemyGroups")]
internal static class AnyFactionPatch
{
private static void Postfix(int level, ref List<EnemyGroup> __result)
{
if (!Factions.On)
{
return;
}
try
{
List<EnemyGroup> list = Factions.All(level);
if (list.Count > 0)
{
__result = list;
}
}
catch (Exception ex)
{
Plugin.ModLog.LogWarning((object)("Wave Defense: every faction: " + ex.Message + "; the map's own factions instead"));
}
}
}
[HarmonyPatch]
internal static class TeamAlivePatch
{
private static MethodBase TargetMethod()
{
return AccessTools.Method(AccessTools.TypeByName("Burst2Flame.Observable.Generated.RootObservable"), "IsTeamAlive", (Type[])null, (Type[])null) ?? AccessTools.Method(typeof(Root), "IsTeamAlive", (Type[])null, (Type[])null);
}
private static void Postfix(int teamIndex, ref bool __result)
{
__result = Waves.TeamAlive(teamIndex, __result);
}
}
[HarmonyPatch(typeof(GameLogic), "Update")]
internal static class TickPatch
{
private static void Prefix()
{
Waves.Tick();
}
}
[HarmonyPatch]
internal static class GameCompletePatch
{
private static MethodBase TargetMethod()
{
return AccessTools.Method(AccessTools.TypeByName("Burst2Flame.Observable.Generated.RootObservable"), "SendGameCompleteFromServer", (Type[])null, (Type[])null) ?? AccessTools.Method(typeof(Root), "SendGameCompleteFromServer", (Type[])null, (Type[])null);
}
private static void Prefix(int winningTeamIndex)
{
if (Waves.Active)
{
Waves.Stop(Waves.EndReason ?? ((winningTeamIndex == 0) ? "battle won" : "battle lost"));
}
}
}
[HarmonyPatch(typeof(GUIManager), "ChangeBattleTopText")]
internal static class TopTextPatch
{
private static void Prefix(ref string text)
{
if (Waves.OnField > 0 && text != null && !text.Contains("Wave"))
{
text = text + " · Wave " + Titles.Roman(Waves.OnField);
}
}
}
[HarmonyPatch(typeof(PostBattleManager), "OpenPostBattleMenu")]
internal static class ResultsTitlePatch
{
private static void Prefix(bool victory)
{
try
{
Titles.OnResults(victory);
}
catch (Exception ex)
{
Plugin.ModLog.LogWarning((object)("Wave Defense: results title: " + ex.Message));
}
}
}
[HarmonyPatch(typeof(MainMenu), "Start")]
internal static class MainMenuPatch
{
private static void Postfix(MainMenu __instance)
{
try
{
WaveMenu.Add(__instance);
}
catch (Exception arg)
{
Plugin.ModLog.LogWarning((object)$"Wave Defense: menu button: {arg}");
}
}
}
[HarmonyPatch(typeof(MainMenu), "ChooseNormalMode")]
internal static class NormalModePatch
{
private static void Prefix()
{
if (!WaveMode.Entering)
{
WaveMode.Forget("Campaign chosen");
}
}
}
[HarmonyPatch(typeof(MainMenu), "ChooseRoguelikeMode")]
internal static class RoguelikeModePatch
{
private static void Prefix()
{
WaveMode.Forget("Roguelike chosen");
}
}
[HarmonyPatch(typeof(MainMenu), "StartSinglePlayer", new Type[] { })]
internal static class StartSinglePlayerPatch
{
private static bool Prefix(MainMenu __instance)
{
if (!WaveMode.Chosen)
{
return true;
}
__instance.StartSinglePlayer(false);
return false;
}
}
[HarmonyPatch(typeof(MainMenu), "HostMultiplayerIP", new Type[] { })]
internal static class HostIPPatch
{
private static bool Prefix(MainMenu __instance)
{
if (!WaveMode.Chosen)
{
return true;
}
__instance.HostMultiplayerIP(false);
return false;
}
}
[HarmonyPatch(typeof(MainMenu), "HostMultiplayerPlayFab", new Type[] { })]
internal static class HostSteamPatch
{
private static bool Prefix(MainMenu __instance)
{
if (!WaveMode.Chosen)
{
return true;
}
__instance.HostMultiplayerPlayFab(false);
return false;
}
}
[HarmonyPatch]
internal static class CharacterTilePatch
{
private static MethodBase TargetMethod()
{
return AccessTools.GetDeclaredMethods(typeof(CharacterChoiceManager)).FirstOrDefault((MethodInfo m) => m.Name.StartsWith("<ExecuteRefreshCharacters>") && m.ReturnType == typeof(bool) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(Character));
}
private static void Postfix(Character __0, ref bool __result)
{
if (__result && WaveMode.Chosen && !WaveMode.Qualifies(__0))
{
__result = false;
}
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class CharacterCountPatch
{
private static void Postfix(ref List<Character> __result)
{
if (WaveMode.Chosen && __result != null)
{
__result = __result.Where(WaveMode.Qualifies).ToList();
}
}
}
[HarmonyPatch(typeof(CharacterChoiceManager), "OpenCharacterChoiceManager")]
internal static class GuestScreenPatch
{
private static void Prefix()
{
NetworkingManager instance = NetworkingManager.Instance;
if (!((Object)(object)instance == (Object)null) && !instance.IsServer && !instance.IsPlayingAsSinglePlayer && WaveNet.LobbySaysSo())
{
WaveMode.JoinHost("the host's Steam lobby says so");
}
}
}
[HarmonyPatch(typeof(CharacterChoiceManager), "AcceptButtonPressed")]
internal static class AcceptPatch
{
private static bool Prefix()
{
if (!WaveMode.Chosen)
{
return true;
}
List<string> list = (from c in NetworkingManager.Instance.PartyCharactersUnaccepted?.Where((Character c) => c != null && c.Owned && !WaveMode.Qualifies(c))
select c.CharacterName).ToList();
if (list == null || list.Count == 0)
{
return true;
}
ConfirmWindow.Instance.ShowPopupMessage("Wave Defense", "Only level 30 campaign heroes can play Wave Defense. Take " + string.Join(", ", list) + " out of the party.");
return false;
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class GameLevelPatch
{
private static void Postfix(ref int __result)
{
if (WaveMode.Chosen && (Object)(object)QuestManager.instance != (Object)null && QuestManager.instance.CurrentQuest != null)
{
__result = GlobalSettingsManager.instance.globalSettings.MaxLevel;
}
}
}
[HarmonyPatch]
internal static class QuestSavePatch
{
private static IEnumerable<MethodBase> TargetMethods()
{
foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeof(GlobalSaveData)))
{
if (declaredMethod.Name == "SaveQuestState" || declaredMethod.Name == "SaveCampaignQuest" || declaredMethod.Name == "ClearCurrentGameModeQuestData")
{
yield return declaredMethod;
}
}
}
private static bool Prefix(MethodBase __originalMethod)
{
if (!WaveMode.Chosen)
{
return true;
}
Plugin.ModLog.LogInfo((object)("Wave Defense: quest save skipped (" + __originalMethod.Name + ")"));
return false;
}
}
[BepInPlugin("com.helvetica.wavedefense", "Wave Defense", "0.9.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : StolenRealmMod
{
private sealed class Runner : MonoBehaviour
{
private string _lastError;
private void Update()
{
try
{
WaveMenu.Tick();
WaveMenu.TickCharacterScreen();
WaveMode.Tick();
}
catch (Exception ex)
{
if (!(ex.Message == _lastError))
{
_lastError = ex.Message;
ModLog.LogWarning((object)$"Wave Defense: {ex}");
}
}
}
}
public const string PluginGuid = "com.helvetica.wavedefense";
public const string PluginName = "Wave Defense";
public const string PluginVersion = "0.9.1";
internal static ManualLogSource ModLog;
internal static ConfigEntry<bool> Enabled;
internal static ConfigEntry<bool> AnyFaction;
internal static ConfigEntry<bool> AnyBoss;
private static Runner _runner;
public static void DevUnload()
{
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
WaveNet.Unload();
try
{
Waves.Stop("hot reload");
}
catch (Exception arg)
{
Debug.LogWarning((object)$"[WaveDefense] stop: {arg}");
}
try
{
WaveMenu.Remove();
}
catch (Exception arg2)
{
Debug.LogWarning((object)$"[WaveDefense] menu: {arg2}");
}
if ((Object)(object)_runner != (Object)null)
{
Object.Destroy((Object)(object)((Component)_runner).gameObject);
}
new Harmony("com.helvetica.wavedefense").UnpatchSelf();
Debug.Log((object)"[WaveDefense] Unloaded for a hot reload.");
}
protected override void OnModLoaded()
{
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Expected O, but got Unknown
ModLog = ((BaseUnityPlugin)this).Logger;
Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turn Wave Defense on or off.");
AnyFaction = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AnyFaction", true, "Waves come from every enemy faction in the game, whatever the arena's terrain. Off: only the arena's own region's factions (Freewind Forest). The host's setting decides.");
AnyBoss = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AnyBoss", true, "Every 5th wave's Boss can be any Boss in the game, whatever faction the wave is. Off: one of the wave's own faction (else the region's), and no dragon on wave 5. The host's setting decides.");
if (Chainloader.PluginInfos.ContainsKey("com.helvetica.modnet"))
{
WaveNet.Init();
}
GameObject val = new GameObject("WaveDefense")
{
hideFlags = (HideFlags)61
};
Object.DontDestroyOnLoad((Object)val);
_runner = val.AddComponent<Runner>();
if ((Object)(object)MainMenu.Instance != (Object)null)
{
WaveMenu.Add(MainMenu.Instance);
}
((BaseUnityPlugin)this).Logger.LogInfo((object)"Wave Defense v0.9.1 loaded.");
}
}
public static class Records
{
public sealed class Hero
{
public string Guid;
public string Name;
}
public sealed class Result
{
public int Wave;
public int Killed;
public string Why;
public readonly List<string> Lines = new List<string>();
}
public const string FileName = "WaveDefenseRecords.txt";
public static Result Last { get; private set; }
public static string FilePath => Path.Combine(FileSystem.persistentDataPath, "WaveDefenseRecords.txt");
internal static List<Hero> Party()
{
return (from c in NetworkingManager.Instance.MyPartyCharacters.ToList()
where c != null && !string.IsNullOrEmpty(c.Guid)
select new Hero
{
Guid = c.Guid,
Name = c.CharacterName
}).ToList();
}
public static int Best(string guid)
{
if (guid == null || !Load().TryGetValue(guid, out var value))
{
return 0;
}
return value.Key;
}
internal static Result Note(int wave, int killed, string why, List<Hero> heroes)
{
Result result = new Result
{
Wave = wave,
Killed = killed,
Why = why
};
Dictionary<string, KeyValuePair<int, string>> dictionary = Load();
foreach (Hero item in heroes ?? new List<Hero>())
{
KeyValuePair<int, string> value;
int num = (dictionary.TryGetValue(item.Guid, out value) ? value.Key : 0);
if (wave > num)
{
dictionary[item.Guid] = new KeyValuePair<int, string>(wave, item.Name);
result.Lines.Add((num > 0) ? $"{item.Name}: wave {wave}, a new best (was {num})" : $"{item.Name}: wave {wave}, a first record");
}
else
{
result.Lines.Add($"{item.Name}: best wave {num}");
}
}
try
{
Save(dictionary);
}
catch (Exception ex)
{
Plugin.ModLog.LogWarning((object)("Wave Defense: couldn't save the records (" + FilePath + "): " + ex.Message));
}
Plugin.ModLog.LogInfo((object)("Wave Defense: records: " + string.Join("; ", result.Lines)));
return Last = result;
}
private static Dictionary<string, KeyValuePair<int, string>> Load()
{
Dictionary<string, KeyValuePair<int, string>> dictionary = new Dictionary<string, KeyValuePair<int, string>>();
if (!File.Exists(FilePath))
{
return dictionary;
}
string[] array = File.ReadAllLines(FilePath);
for (int i = 0; i < array.Length; i++)
{
string[] array2 = array[i].Split('\t');
if (array2.Length >= 2 && array2[0].Length > 0 && int.TryParse(array2[1], out var result))
{
dictionary[array2[0]] = new KeyValuePair<int, string>(result, (array2.Length > 2) ? array2[2] : "");
}
}
return dictionary;
}
private static void Save(Dictionary<string, KeyValuePair<int, string>> all)
{
IEnumerable<string> contents = from e in all
orderby e.Value.Key descending
select $"{e.Key}\t{e.Value.Key}\t{e.Value.Value.Replace('\t', ' ').Replace('\n', ' ')}";
File.WriteAllLines(FilePath, contents);
}
}
internal static class Shrines
{
private static readonly FieldRef<GameLogic, List<HexCell>> UsedHexes = AccessTools.FieldRefAccess<GameLogic, List<HexCell>>("usedHexes");
private static readonly FieldRef<GameLogic, List<HexCell>> ShrineHexes = AccessTools.FieldRefAccess<GameLogic, List<HexCell>>("shrineHexes");
internal static bool Due;
internal static List<Character> OnField()
{
NetworkingManager instance = NetworkingManager.Instance;
Root val = ((instance == null) ? null : ((Observer<Root>)(object)instance.NetworkManager)?.Root);
if (val == null)
{
return new List<Character>();
}
return val.CharactersInBattle.Where((Character c) => c != null && (int)c.CharacterType == 1 && !c.IsDead && c.SummonMaster == null).ToList();
}
internal static int Clear()
{
Root root = ((Observer<Root>)(object)NetworkingManager.Instance.NetworkManager).Root;
GameLogic instance = GameLogic.instance;
List<Character> list = OnField();
foreach (Character s in list)
{
try
{
foreach (GroundEffect item in instance.GroundEffects.Where((GroundEffect g) => g != null && g.Source == s).ToList())
{
instance.RemoveGroundEffect(item);
}
}
catch (Exception ex)
{
Plugin.ModLog.LogWarning((object)("Wave Defense: couldn't remove shrine " + s.CharacterName + "'s aura: " + ex.Message));
}
try
{
root.RemoveCharacterFromGame(s, true);
}
catch (Exception ex2)
{
Plugin.ModLog.LogWarning((object)("Wave Defense: couldn't remove shrine " + s.CharacterName + ": " + ex2.Message));
}
}
return list.Count;
}
internal static int Raise()
{
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: 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)
GameLogic instance = GameLogic.instance;
MapFile current = MapBuilder.Current;
if ((Object)(object)instance == (Object)null || current == null || !MapBuilder.Ready)
{
return 0;
}
HashSet<HexCell> spots = new HashSet<HexCell>(from s in current.party.Concat(current.enemies)
select MapBuilder.Cell(s.q, s.r) into c
where (Object)(object)c != (Object)null
select c);
List<HexCell> list = MapBuilder.Cells.Where((HexCell c) => (Object)(object)c != (Object)null && c.IsValid && c.IsWalkable && c.IsEmpty && !spots.Contains(c)).ToList();
if (list.Count == 0)
{
return 0;
}
UsedHexes.Invoke(instance)?.Clear();
ShrineHexes.Invoke(instance)?.Clear();
Game instance2 = Game.Instance;
TerrainType result;
TerrainType val = (Enum.TryParse<TerrainType>(current.terrain, out result) ? result : instance2.CurrentRoomTerrainType);
((MonoBehaviour)instance).StartCoroutine(instance.SpawnShrines(HexCellManager.instance, val, instance2.CurrentRoomTimeOfDay, list, new Random(), true));
int num = Mathf.CeilToInt((float)list.Count / GlobalSettingsManager.instance.globalSettings.shrinePerNumWalkable);
Plugin.ModLog.LogInfo((object)$"Wave Defense: raising up to {num} shrines on {list.Count} free hexes.");
return num;
}
internal static void Renew()
{
int num = Clear();
Plugin.ModLog.LogInfo((object)$"Wave Defense: the boss wave is over: {num} shrines removed.");
Raise();
}
internal static string Status()
{
return string.Join(", ", from s in OnField()
select s.CharacterName + " at " + MapBuilder.Where((object)s.Cell));
}
}
internal static class Titles
{
internal const string Gold = "#FFE4AC";
internal const string Red = "#FF8C83";
private const float Speed = 0.75f;
private const float Lift = 30f;
private static GameObject _shown;
private static string _victoryText;
internal static string Roman(int n)
{
if (n <= 0 || n >= 4000)
{
return n.ToString();
}
int[] array = new int[13]
{
1000, 900, 500, 400, 100, 90, 50, 40, 10, 9,
5, 4, 1
};
string[] array2 = new string[13]
{
"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX",
"V", "IV", "I"
};
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < array.Length; i++)
{
while (n >= array[i])
{
stringBuilder.Append(array2[i]);
n -= array[i];
}
}
return stringBuilder.ToString();
}
private static string Big(string word)
{
if (word.Length != 0)
{
return "<size=120>" + word.Substring(0, 1) + "</size>" + word.Substring(1).ToUpperInvariant();
}
return word;
}
internal static string WaveTitle(int wave, string boss)
{
return Big("Wave") + " <size=120>" + Roman(wave) + "</size>" + (string.IsNullOrEmpty(boss) ? "" : ("\n<size=56><color=#FF8C83>" + boss.ToUpperInvariant() + "</color></size>"));
}
internal static string EndTitle(int wave, bool fell)
{
if (!fell)
{
return Big("Survived") + "\n<size=44>WAVE " + Roman(wave) + "</size>";
}
return Big("Fallen") + "\n<size=44>ON WAVE " + Roman(wave) + "</size>";
}
private static GameObject Template()
{
if ((Object)(object)PostBattleManager.Instance == (Object)null)
{
PostBattleManager.LoadInstanceReference();
}
Animation val = (((Object)(object)PostBattleManager.Instance != (Object)null) ? PostBattleManager.Instance.VictoryAnim : null);
if (!((Object)(object)val != (Object)null))
{
return null;
}
return ((Component)val).gameObject;
}
internal static void Show(string text)
{
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Expected O, but got Unknown
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Expected O, but got Unknown
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: 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)
//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)
//IL_0087: 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_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_016c: Unknown result type (might be due to invalid IL or missing references)
//IL_0180: Unknown result type (might be due to invalid IL or missing references)
try
{
GameObject val = Template();
GUIManager instance = GUIManager.instance;
if ((Object)(object)val == (Object)null || (Object)(object)instance == (Object)null)
{
Waves.Banner(StripTags(text));
return;
}
HideShown();
GameObject val2 = new GameObject("Wave Defense Title", new Type[1] { typeof(RectTransform) });
RectTransform val3 = (RectTransform)val2.transform;
((Transform)val3).SetParent(((Component)instance).transform, false);
Vector2 val4 = (val3.pivot = new Vector2(0.5f, 0.5f));
Vector2 anchorMin = (val3.anchorMax = val4);
val3.anchorMin = anchorMin;
val3.sizeDelta = Vector2.zero;
((Transform)val3).localScale = Vector3.one * 1.2f;
float y = ((RectTransform)val.transform).anchoredPosition.y;
val3.anchoredPosition = new Vector2(0f, 30f - y * 1.2f);
((Transform)val3).SetAsLastSibling();
Canvas obj = val2.AddComponent<Canvas>();
obj.overrideSorting = true;
obj.sortingOrder = 30000;
CanvasGroup obj2 = val2.AddComponent<CanvasGroup>();
obj2.blocksRaycasts = false;
obj2.interactable = false;
GameObject val7 = Object.Instantiate<GameObject>(val, (Transform)(object)val3, false);
Text[] componentsInChildren = val7.GetComponentsInChildren<Text>(true);
foreach (Text obj3 in componentsInChildren)
{
obj3.text = text;
obj3.verticalOverflow = (VerticalWrapMode)1;
((Graphic)obj3).raycastTarget = false;
Shadow obj4 = ((Component)obj3).gameObject.AddComponent<Shadow>();
obj4.effectColor = new Color(0f, 0f, 0f, 0.75f);
obj4.effectDistance = new Vector2(3f, -3f);
}
val7.SetActive(true);
Animation component = val7.GetComponent<Animation>();
float num = 3f;
if ((Object)(object)component != (Object)null && (Object)(object)component.clip != (Object)null)
{
component[((Object)component.clip).name].speed = 0.75f;
component.Play(((Object)component.clip).name);
num = component.clip.length / 0.75f;
}
Object.Destroy((Object)(object)val2, num + 0.1f);
_shown = val2;
}
catch (Exception ex)
{
Plugin.ModLog.LogWarning((object)("Wave Defense: title failed: " + ex.Message));
Waves.Banner(StripTags(text));
}
}
internal static void HideShown()
{
if ((Object)(object)_shown != (Object)null)
{
Object.Destroy((Object)(object)_shown);
}
_shown = null;
}
internal static void OnResults(bool victory)
{
HideShown();
GameObject val = Template();
Text val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInChildren<Text>(true) : null);
if (!((Object)(object)val2 == (Object)null))
{
if (_victoryText == null)
{
_victoryText = val2.text;
}
string text = Waves.TakeEndTitle();
val2.verticalOverflow = (VerticalWrapMode)1;
val2.text = ((victory && text != null) ? text : _victoryText);
if (victory && text != null)
{
Plugin.ModLog.LogInfo((object)("Wave Defense: results title '" + StripTags(text) + "'"));
}
}
}
private static string StripTags(string s)
{
return Regex.Replace(s, "<[^>]+>", "").Replace("\n", " ");
}
}
public static class WaveMenu
{
private sealed class Entry
{
public GameObject Page;
public Button Button;
public TextMeshProUGUI Text;
public GameObject Reason;
public Color TextColor;
}
public const string ButtonName = "Button (Wave Defense)";
public const string Label = "Wave Defense";
public const string Why = "Needs a level 30 campaign hero";
private static readonly List<Entry> Entries = new List<Entry>();
private static bool _onFirstPage;
private static float _nextCheck;
private static bool _qualifies;
private static bool _hidCreate;
public static void Add(MainMenu menu)
{
//IL_0206: Unknown result type (might be due to invalid IL or missing references)
//IL_0210: Expected O, but got Unknown
//IL_021e: Unknown result type (might be due to invalid IL or missing references)
//IL_0228: Expected O, but got Unknown
//IL_0293: Unknown result type (might be due to invalid IL or missing references)
//IL_028a: Unknown result type (might be due to invalid IL or missing references)
//IL_0298: Unknown result type (might be due to invalid IL or missing references)
Entries.RemoveAll((Entry e) => (Object)(object)e.Button == (Object)null);
GameObject[] array = (GameObject[])(object)new GameObject[3] { menu.gameModeControlsSinglePlayer, menu.gameModeControlsOnline, menu.gameModeControlsIP };
foreach (GameObject val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
Transform val2 = val.transform.Find("Buttons");
if ((Object)(object)val2 == (Object)null)
{
Plugin.ModLog.LogWarning((object)("Wave Defense: menu page " + ((Object)val).name + " has no Buttons group"));
}
else
{
if ((Object)(object)val2.Find("Button (Wave Defense)") != (Object)null)
{
continue;
}
List<Button> source = (from t in Enumerable.Range(0, val2.childCount).Select((Func<int, Transform>)val2.GetChild)
select ((Component)t).GetComponent<Button>() into b
where (Object)(object)b != (Object)null
select b).ToList();
Button campaign = ((IEnumerable<Button>)source).FirstOrDefault((Func<Button, bool>)((Button b) => FirstHandler(b) == "ChooseNormalMode"));
Button val3 = ((IEnumerable<Button>)source).FirstOrDefault((Func<Button, bool>)((Button b) => FirstHandler(b) == "ChooseRoguelikeMode"));
if ((Object)(object)campaign == (Object)null)
{
Plugin.ModLog.LogWarning((object)("Wave Defense: no Campaign button on " + ((Object)val).name));
continue;
}
GameObject val4 = Object.Instantiate<GameObject>(((Component)campaign).gameObject, val2);
((Object)val4).name = "Button (Wave Defense)";
val4.transform.SetSiblingIndex(((Component)(((Object)(object)val3 != (Object)null) ? val3 : campaign)).transform.GetSiblingIndex() + 1);
Button component = val4.GetComponent<Button>();
component.onClick = new ButtonClickedEvent();
((UnityEvent)component.onClick).AddListener((UnityAction)delegate
{
Enter(campaign);
});
TextMeshProUGUI componentInChildren = val4.GetComponentInChildren<TextMeshProUGUI>(true);
TextMeshProUGUI[] componentsInChildren = val4.GetComponentsInChildren<TextMeshProUGUI>(true);
for (int num2 = 0; num2 < componentsInChildren.Length; num2++)
{
((TMP_Text)componentsInChildren[num2]).text = "Wave Defense";
}
Entries.Add(new Entry
{
Page = val,
Button = component,
Text = componentInChildren,
TextColor = (((Object)(object)componentInChildren != (Object)null) ? ((Graphic)componentInChildren).color : Color.white),
Reason = (((Object)(object)componentInChildren != (Object)null) ? AddReason(val4, componentInChildren) : null)
});
}
}
Plugin.ModLog.LogInfo((object)$"Wave Defense: button added to {Entries.Count} menu page(s)");
}
public static void Remove()
{
foreach (Entry entry in Entries)
{
if (!((Object)(object)entry.Button == (Object)null))
{
GameObject gameObject = ((Component)entry.Button).gameObject;
((Object)gameObject).name = ((Object)gameObject).name + " (removed)";
gameObject.SetActive(false);
Object.Destroy((Object)(object)gameObject);
}
}
Entries.Clear();
}
private static GameObject AddReason(GameObject button, TextMeshProUGUI label)
{
//IL_0022: 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_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
GameObject obj = Object.Instantiate<GameObject>(((Component)label).gameObject, button.transform);
((Object)obj).name = "Wave Defense Reason";
RectTransform val = (RectTransform)obj.transform;
val.anchorMin = new Vector2(0f, 0f);
val.anchorMax = new Vector2(1f, 0f);
val.pivot = new Vector2(0.5f, 1f);
val.anchoredPosition = new Vector2(0f, -2f);
val.sizeDelta = new Vector2(60f, 24f);
TextMeshProUGUI component = obj.GetComponent<TextMeshProUGUI>();
((TMP_Text)component).enableAutoSizing = false;
((TMP_Text)component).fontSize = Mathf.Max(12f, ((TMP_Text)label).fontSize * 0.5f);
((TMP_Text)component).alignment = (TextAlignmentOptions)258;
((Graphic)component).raycastTarget = false;
((Graphic)component).color = new Color(1f, 0.85f, 0.6f, 0.9f);
((TMP_Text)component).text = "Needs a level 30 campaign hero";
obj.SetActive(false);
return obj;
}
private static string FirstHandler(Button b)
{
if (((UnityEventBase)b.onClick).GetPersistentEventCount() <= 0)
{
return null;
}
return ((UnityEventBase)b.onClick).GetPersistentMethodName(0);
}
private static void Enter(Button campaign)
{
if (!Plugin.Enabled.Value || !WaveMode.AnyQualifies())
{
return;
}
WaveMode.Choose();
WaveMode.Entering = true;
try
{
((UnityEvent)campaign.onClick).Invoke();
}
catch (Exception arg)
{
Plugin.ModLog.LogWarning((object)$"Wave Defense: the menu step failed: {arg}");
}
finally
{
WaveMode.Entering = false;
}
}
internal static void Tick()
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Invalid comparison between Unknown and I4
//IL_016c: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
MainMenu instance = MainMenu.Instance;
int num;
int num2;
if ((Object)(object)instance != (Object)null && (Object)(object)GUIManager.instance != (Object)null)
{
num = (((int)GUIManager.instance.CurrentGuiState == 5) ? 1 : 0);
if (num != 0 && (Object)(object)instance.mainControls != (Object)null)
{
num2 = (instance.mainControls.activeInHierarchy ? 1 : 0);
if (num2 != 0 && !_onFirstPage)
{
WaveMode.Forget("back on the main menu");
}
goto IL_005f;
}
}
else
{
num = 0;
}
num2 = 0;
goto IL_005f;
IL_005f:
_onFirstPage = (byte)num2 != 0;
if (num == 0 || Entries.Count == 0)
{
return;
}
if (Time.realtimeSinceStartup >= _nextCheck)
{
_qualifies = WaveMode.AnyQualifies();
_nextCheck = Time.realtimeSinceStartup + 1f;
}
bool value = Plugin.Enabled.Value;
foreach (Entry entry in Entries)
{
if (!((Object)(object)entry.Button == (Object)null) && entry.Page.activeInHierarchy)
{
if (((Component)entry.Button).gameObject.activeSelf != value)
{
((Component)entry.Button).gameObject.SetActive(value);
}
if (((Selectable)entry.Button).interactable != _qualifies)
{
((Selectable)entry.Button).interactable = _qualifies;
}
if ((Object)(object)entry.Text != (Object)null)
{
((Graphic)entry.Text).color = (Color)(_qualifies ? entry.TextColor : new Color(entry.TextColor.r, entry.TextColor.g, entry.TextColor.b, 0.4f));
}
if ((Object)(object)entry.Reason != (Object)null && entry.Reason.activeSelf == _qualifies)
{
entry.Reason.SetActive(!_qualifies);
}
}
}
}
internal static void TickCharacterScreen()
{
CharacterChoiceManager instance = CharacterChoiceManager.Instance;
if ((Object)(object)instance == (Object)null || (Object)(object)instance.createCharacterBtn == (Object)null)
{
return;
}
GameObject gameObject = ((Component)instance.createCharacterBtn).gameObject;
if (WaveMode.Chosen && CharacterChoiceManager.IsNotNullAndIsActive)
{
if (gameObject.activeSelf)
{
gameObject.SetActive(false);
_hidCreate = true;
}
}
else if (_hidCreate)
{
_hidCreate = false;
gameObject.SetActive(true);
}
}
}
public static class WaveMode
{
public enum Step
{
Off,
ToTown,
ToIsland,
InArena,
Over,
Guest
}
[CompilerGenerated]
private static class <>O
{
public static Func<Character, bool> <0>__Qualifies;
public static ConfirmAction <1>__Leave;
}
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static Func<Character, bool> <>9__18_0;
public static Func<Character, string> <>9__18_1;
public static Func<Character, bool> <>9__33_0;
public static Func<Character, string> <>9__33_1;
public static ConfirmAction <>9__33_2;
internal bool <WarnGuest>b__18_0(Character c)
{
if (c != null)
{
return !Qualifies(c);
}
return false;
}
internal string <WarnGuest>b__18_1(Character c)
{
return c.CharacterName;
}
internal bool <TownPrompt>b__33_0(Character c)
{
return c != null;
}
internal string <TownPrompt>b__33_1(Character c)
{
if (!Qualifies(c))
{
return c.CharacterName + " (not a level 30 campaign hero)";
}
return c.CharacterName;
}
internal void <TownPrompt>b__33_2()
{
_promptUp = false;
_startAsked = true;
}
}
internal static bool Entering;
private static bool _busy;
private static bool _resultsShown;
private static bool _left;
private static bool _startPressed;
private static bool _startAsked;
private static bool _promptUp;
private static bool _warned;
private static string _promptText;
private static float _promptAt;
public static bool Chosen { get; private set; }
public static Step Phase { get; private set; }
public static string ArenaPath => Path.Combine(ModFolder, "maps", "arena.json");
private static string ModFolder
{
get
{
string location = typeof(WaveMode).Assembly.Location;
if (string.IsNullOrEmpty(location) && Chainloader.PluginInfos.TryGetValue("com.helvetica.wavedefense", out var value))
{
location = value.Location;
}
return Path.GetDirectoryName(location);
}
}
public static bool Qualifies(Character c)
{
if (c != null && !c.IsDeleted && !c.IsRoguelikeCharacter && !c.HardcoreDeath)
{
return c.IsMaxLevel;
}
return false;
}
public static bool AnyQualifies()
{
return (((Object)(object)GameLogic.instance != (Object)null) ? GameLogic.instance.AllMyCharacters : null)?.Any(Qualifies) ?? false;
}
internal static void Choose()
{
Chosen = true;
Phase = Step.ToTown;
_resultsShown = (_left = (_startPressed = (_startAsked = (_promptUp = (_warned = false)))));
_promptText = null;
Plugin.ModLog.LogInfo((object)"Wave Defense: chosen on the main menu");
}
internal static void JoinHost(string how)
{
if (!Chosen || (Phase != Step.Guest && Phase != Step.Over))
{
Chosen = true;
Phase = Step.Guest;
_resultsShown = (_left = (_warned = false));
Plugin.ModLog.LogInfo((object)("Wave Defense: joined a Wave Defense game (" + how + ")"));
}
WarnGuest();
}
private static void WarnGuest()
{
if (!_warned && !((Object)(object)ConfirmWindow.Instance == (Object)null) && !((Component)ConfirmWindow.Instance).gameObject.activeInHierarchy)
{
NetworkingManager instance = NetworkingManager.Instance;
List<string> list = (from c in ((instance == null) ? null : instance.MyPartyCharacters?.ToList())?.Where((Character c) => c != null && !Qualifies(c))
select c.CharacterName).ToList();
if (list != null && list.Count != 0)
{
_warned = true;
Plugin.ModLog.LogInfo((object)("Wave Defense: told this player that " + string.Join(", ", list) + " can't play"));
ConfirmWindow.Instance.ShowPopupMessage("Wave Defense", "This game is Wave Defense: only level 30 campaign heroes can play, not " + string.Join(", ", list) + ". Go back to the main menu and join again with one who can.");
}
}
}
internal static void GuestRunOver()
{
Phase = Step.Over;
_resultsShown = false;
}
internal static void HostLeft()
{
if (Chosen && !_left)
{
Plugin.ModLog.LogInfo((object)"Wave Defense: the host went back to the main menu");
Leave();
}
}
internal static void Forget(string why)
{
if (Chosen)
{
Chosen = false;
Phase = Step.Off;
if (Waves.Armed || Waves.Active)
{
Waves.Stop(why);
}
Waves.ClearShown();
Plugin.ModLog.LogInfo((object)("Wave Defense: mode off (" + why + ")"));
}
}
internal static void Tick()
{
//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_0052: 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: Invalid comparison between Unknown and I4
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Invalid comparison between Unknown and I4
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Invalid comparison between Unknown and I4
if (!Chosen || _busy || !Plugin.Enabled.Value)
{
return;
}
NetworkingManager instance = NetworkingManager.Instance;
if ((Object)(object)instance == (Object)null || (Object)(object)GUIManager.instance == (Object)null || Loading())
{
return;
}
GUIState currentGuiState = GUIManager.instance.CurrentGuiState;
if (!instance.IsServer)
{
GuestTick(currentGuiState);
return;
}
if (!instance.IsPlayingAsSinglePlayer)
{
WaveNet.Advertise();
}
if (Phase == Step.ToTown && (int)currentGuiState == 4 && (Object)(object)LoadableUIWindow<QuestSelectManager>.Instance != (Object)null)
{
if (!WaveNet.Multiplayer || _startPressed)
{
Run(StartQuest(), "quest start");
}
else
{
TownPrompt();
}
}
else if (Phase == Step.ToIsland && (int)currentGuiState == 3 && IslandReady() && MapBattle.CannotStart() == null)
{
Run(EnterArena(), "arena start");
}
else if (Phase == Step.InArena && !Waves.Armed && !Waves.Active && !MapBattle.Active && (int)currentGuiState == 3)
{
Phase = Step.Over;
Plugin.ModLog.LogInfo((object)("Wave Defense: the run is over (" + Waves.LastResult + "); the party is back on the island"));
ShowResults();
}
else if (Phase == Step.Over && _resultsShown && !_left && !ResultsOpen())
{
Leave();
}
}
private static void GuestTick(GUIState state)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Invalid comparison between Unknown and I4
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Invalid comparison between Unknown and I4
if (Phase == Step.Guest && (int)state == 4)
{
WarnGuest();
}
if (Phase == Step.Over && !_left)
{
if (!_resultsShown && (int)state == 3 && !Waves.InFight() && !ResultsOpen())
{
ShowResults();
}
else if (_resultsShown && !ResultsOpen())
{
Leave();
}
}
}
private static void TownPrompt()
{
//IL_0147: 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_0152: Expected O, but got Unknown
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
//IL_016b: Unknown result type (might be due to invalid IL or missing references)
//IL_0171: Expected O, but got Unknown
ConfirmWindow instance = ConfirmWindow.Instance;
if ((Object)(object)instance == (Object)null)
{
return;
}
if (_startAsked)
{
_startAsked = false;
string text = WaveNet.CannotStart();
if (text == null)
{
_startPressed = true;
Plugin.ModLog.LogInfo((object)"Wave Defense: the host starts the run");
}
else
{
Plugin.ModLog.LogInfo((object)("Wave Defense: can't start yet: " + text));
instance.ShowPopupMessage("Wave Defense", text);
}
return;
}
bool activeInHierarchy = ((Component)instance).gameObject.activeInHierarchy;
if (activeInHierarchy && !_promptUp)
{
return;
}
if (!activeInHierarchy && _promptUp)
{
_promptUp = false;
_promptAt = Time.unscaledTime + 2f;
return;
}
string text2 = string.Join(", ", from c in NetworkingManager.Instance.PartyCharacters
where c != null
select (!Qualifies(c)) ? (c.CharacterName + " (not a level 30 campaign hero)") : c.CharacterName);
string text3 = "Wait in town until everyone has joined with a level 30 campaign hero, then start the run.\n\nHeroes here: " + text2;
if ((activeInHierarchy && text3 == _promptText) || (!activeInHierarchy && Time.unscaledTime < _promptAt))
{
return;
}
_promptText = text3;
_promptUp = true;
object obj = <>O.<1>__Leave;
if (obj == null)
{
ConfirmAction val = Leave;
<>O.<1>__Leave = val;
obj = (object)val;
}
object obj2 = <>c.<>9__33_2;
if (obj2 == null)
{
ConfirmAction val2 = delegate
{
_promptUp = false;
_startAsked = true;
};
<>c.<>9__33_2 = val2;
obj2 = (object)val2;
}
instance.ShowConfirmMessage("Wave Defense", text3, (ConfirmAction)obj, (ConfirmAction)obj2, "Start", "Main Menu", (List<GameObject>)null, (List<GameObject>)null);
}
private static void ShowResults()
{
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Expected O, but got Unknown
_left = false;
ConfirmWindow instance = ConfirmWindow.Instance;
if ((Object)(object)instance == (Object)null)
{
Leave();
return;
}
Records.Result last = Records.Last;
string text = ((last == null) ? ("Run over: " + Waves.LastResult + ".") : ((last.Why == "the party fell") ? $"The party fell on wave {last.Wave}." : $"The run ended on wave {last.Wave} ({last.Why})."));
string text2 = ((last == null) ? "" : string.Format("\n{0} {1} defeated\n\n{2}", last.Killed, (last.Killed == 1) ? "enemy" : "enemies", string.Join("\n", last.Lines)));
string text3 = text + text2;
object obj = <>O.<1>__Leave;
if (obj == null)
{
ConfirmAction val = Leave;
<>O.<1>__Leave = val;
obj = (object)val;
}
instance.ShowConfirmMessage("Wave Defense", text3, (ConfirmAction)null, (ConfirmAction)obj, "Main Menu", (string)null, (List<GameObject>)null, (List<GameObject>)null);
_resultsShown = true;
}
private static bool ResultsOpen()
{
ConfirmWindow instance = ConfirmWindow.Instance;
if ((Object)(object)instance != (Object)null)
{
return ((Component)instance).gameObject.activeInHierarchy;
}
return false;
}
private static void Leave()
{
if (!_left)
{
_left = true;
_resultsShown = (_promptUp = false);
NetworkingManager instance = NetworkingManager.Instance;
if (instance.IsServer && WaveNet.Multiplayer)
{
WaveNet.SendLeave();
Plugin.ModLog.LogInfo((object)"Wave Defense: back to the main menu, the other players first");
Plugin.Run(LeaveSoon(), "Wave Defense leave", true);
}
else
{
Plugin.ModLog.LogInfo((object)"Wave Defense: back to the main menu");
instance.ExitToMainMenu();
}
}
}
private static IEnumerator LeaveSoon()
{
yield return (object)new WaitForSecondsRealtime(1.5f);
NetworkingManager.Instance.ExitToMainMenu();
}
private static IEnumerator StartQuest()
{
QuestSelectManager qsm = LoadableUIWindow<QuestSelectManager>.Instance;
qsm.Initialize();
((UIWindow)qsm).OpenWindow();
qsm.UpdateQuestNodes();
float until = Time.realtimeSinceStartup + 10f;
QuestNode target = null;
while ((Object)(object)target == (Object)null)
{
target = ((IEnumerable<QuestNode>)(((object)qsm.QuestNodes) ?? ((object)new QuestNode[0]))).FirstOrDefault((Func<QuestNode, bool>)((QuestNode n) => (Object)(object)n != (Object)null && ((int)n.questNodeType == 0 || (int)n.questNodeType == 2) && Navigable(qsm, n) && n.CurrentQuestInstance != null));
if ((Object)(object)target != (Object)null)
{
break;
}
if (Time.realtimeSinceStartup > until)
{
Plugin.ModLog.LogWarning((object)"Wave Defense: no quest to start from town; the run can't begin");
Phase = Step.Over;
yield break;
}
yield return null;
}
qsm.SelectQuestNode(target);
while (Loading())
{
yield return null;
}
Phase = Step.ToIsland;
qsm.ActivateSelectedQuestNode();
Plugin.ModLog.LogInfo((object)("Wave Defense: quest '" + ((Object)target).name + "' started, the arena is next to its island"));
}
private static IEnumerator EnterArena()
{
Phase = Step.InArena;
if (!File.Exists(ArenaPath))
{
throw new FileNotFoundException("the arena map is missing: " + ArenaPath);
}
Waves.Arm();
Plugin.ModLog.LogInfo((object)("Wave Defense: building the arena (" + ArenaPath + ")"));
BattleInfo battle = GlobalSettingsManager.instance.globalSettings.testBattle;
int level = battle.mLvl;
battle.mLvl = Waves.LevelOf(1);
Factions.RollingWaveOne = true;
try
{
IEnumerator fight = MapBattle.Fight(ArenaPath, false, false);
while (fight.MoveNext())
{
yield return fight.Current;
}
}
finally
{
battle.mLvl = level;
Factions.RollingWaveOne = false;
}
}
private static bool Navigable(QuestSelectManager qsm, QuestNode n)
{
try
{
return qsm.CanNavigateToQuestNode(n);
}
catch
{
return false;
}
}
private static bool IslandReady()
{
PortalManager instance = PortalManager.Instance;
if ((Object)(object)instance != (Object)null && (Object)(object)instance.CurrentIsland != (Object)null && instance.CompletedIslandGeneration)
{
return !instance.OpeningIsland;
}
return false;
}
private static bool Loading()
{
LoadingScreen instance = LoadingScreen.Instance;
if ((Object)(object)instance != (Object)null)
{
if (!instance.MainFadeActive)
{
return instance.IsLoading;
}
return true;
}
return false;
}
private static void Run(IEnumerator routine, string what)
{
_busy = true;
Plugin.Run(Guard(routine, what), "Wave Defense " + what, true);
}
private static IEnumerator Guard(IEnumerator routine, string what)
{
try
{
while (true)
{
object current;
try
{
if (!routine.MoveNext())
{
break;
}
current = routine.Current;
}
catch (Exception arg)
{
Plugin.ModLog.LogWarning((object)$"Wave Defense: {what} failed: {arg}");
Phase = Step.Over;
if (Waves.Armed)
{
Waves.Stop(what + " failed");
}
break;
}
yield return current;
}
}
finally
{
_busy = false;
}
}
}
public static class WaveNet
{
private static class Bridge
{
internal static bool Ready => ModNetApi.Ready;
internal static void Hook()
{
ModNetApi.Register("wavedefense", (Action<NetMessage>)delegate(NetMessage m)
{
Handle(m.Payload);
});
ModNetApi.BecameReady += Announce;
ModNetApi.PlayerHello += delegate
{
Announce();
};
}
internal static bool Send(string payload)
{
return ModNetApi.Send("wavedefense", payload, (Character)null);
}
internal static List<string> WithoutTheMod()
{
return (from p in ModNetApi.Players
where !p.IsMe && !p.Has("com.helvetica.wavedefense", "0.9.1")
select p.Name).ToList();
}
}
public const string Channel = "wavedefense";
private const string LobbyKey = "srm_wavedefense";
private static bool _unloaded;
private static float _nextAdvert;
private static ulong _advertised;
public static bool Available { get; private set; }
public static bool Multiplayer
{
get
{
NetworkingManager instance = NetworkingManager.Instance;
if ((Object)(object)instance != (Object)null)
{
return !instance.IsPlayingAsSinglePlayer;
}
return false;
}
}
private static bool IsHost
{
get
{
if ((Object)(object)NetworkingManager.Instance != (Object)null)
{
return NetworkingManager.Instance.IsServer;
}
return false;
}
}
internal static void Init()
{
Available = true;
Bridge.Hook();
}
internal static void Unload()
{
_unloaded = true;
}
internal static void SendMode()
{
Send("mode|0.9.1");
}
internal static void SendWave(int n, string boss)
{
Send(string.Format("wave|{0}|{1}", n, (boss ?? "").Replace('|', '/')));
}
internal static void SendLeave()
{
Send("leave");
}
internal static void SendEnd(int wave, int killed, string why, IEnumerable<Character> removed)
{
IEnumerable<string> values = from s in (removed ?? Enumerable.Empty<Character>()).Select(NameOf)
where s != null
select s;
Send(string.Format("end|{0}|{1}|{2}|{3}", wave, killed, (why ?? "").Replace('|', '/'), string.Join(",", values)));
}
private static void Send(string payload)
{
if (Available && Multiplayer && IsHost && !Bridge.Send(payload))
{
Plugin.ModLog.LogWarning((object)("Wave Defense: couldn't send '" + payload + "' (ModNet not ready?)"));
}
}
private static void Announce()
{
if (!_unloaded && IsHost && WaveMode.Chosen)
{
SendMode();
}
}
internal static string CannotStart()
{
if (!Multiplayer)
{
return null;
}
if (!Available)
{
return "Wave Defense needs ModNet to be played with others.";
}
if (!Bridge.Ready)
{
return "Multiplayer isn't ready yet: wait a few seconds.";
}
List<string> list = Bridge.WithoutTheMod();
if (list.Count > 0)
{
return "Not everyone is ready: " + string.Join(", ", list) + " (still joining, or without Wave Defense 0.9.1).";
}
List<string> list2 = (from c in NetworkingManager.Instance.PartyCharacters
where c != null && !WaveMode.Qualifies(c)
select c.CharacterName).ToList();
if (list2.Count > 0)
{
return "Only level 30 campaign heroes can play Wave Defense, not " + string.Join(", ", list2) + ".";
}
return null;
}
internal static void Advertise()
{
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: 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)
if (Time.unscaledTime < _nextAdvert)
{
return;
}
_nextAdvert = Time.unscaledTime + 1f;
try
{
SteamManager instance = SteamManager.instance;
Lobby? val = (((Object)(object)instance != (Object)null) ? instance.CurrentLobby : ((Lobby?)null));
if (!val.HasValue || !IsHost || !SteamClient.IsValid)
{
_advertised = 0uL;
return;
}
Lobby value = val.Value;
if (((Lobby)(ref value)).Id.Value != _advertised && ((Lobby)(ref value)).IsOwnedBy(SteamClient.SteamId) && ((Lobby)(ref value)).SetData("srm_wavedefense", "1"))
{
_advertised = ((Lobby)(ref value)).Id.Value;
Plugin.ModLog.LogInfo((object)"Wave Defense: the Steam lobby says this game is Wave Defense");
}
}
catch (Exception ex)
{
_advertised = 0uL;
Plugin.ModLog.LogWarning((object)("Wave Defense: lobby: " + ex.Message));
}
}
internal static bool LobbySaysSo()
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
try
{
SteamManager instance = SteamManager.instance;
Lobby? val = (((Object)(object)instance != (Object)null) ? instance.CurrentLobby : ((Lobby?)null));
int result;
if (val.HasValue)
{
Lobby value = val.Value;
result = ((((Lobby)(ref value)).GetData("srm_wavedefense") == "1") ? 1 : 0);
}
else
{
result = 0;
}
return (byte)result != 0;
}
catch
{
return false;
}
}
private static void Handle(string payload)
{
if (_unloaded || IsHost || string.IsNullOrEmpty(payload))
{
return;
}
string[] array = payload.Split('|');
switch (array[0])
{
case "mode":
WaveMode.JoinHost("the host runs " + ((array.Length > 1) ? array[1] : "?"));
break;
case "wave":
{
if (array.Length > 1 && int.TryParse(array[1], out var result3))
{
WaveMode.JoinHost("a wave began");
Waves.ShowWave(result3, (array.Length > 2) ? array[2] : null);
}
break;
}
case "end":
{
if (array.Length > 3 && int.TryParse(array[1], out var result) && int.TryParse(array[2], out var result2))
{
int num = ((array.Length > 4) ? FlagRemoved(array[4]) : 0);
Plugin.ModLog.LogInfo((object)($"Wave Defense: the host says the run is over ({array[3]}): wave {result}, {result2} killed, " + $"{num} enemies removed without rewards"));
WaveMode.JoinHost("the run ended");
Waves.EndShown(result, array[3]);
try
{
Records.Note(result, result2, array[3], Records.Party());
}
catch (Exception arg)
{
Plugin.ModLog.LogWarning((object)$"Wave Defense: records: {arg}");
}
WaveMode.GuestRunOver();
}
break;
}
case "leave":
WaveMode.HostLeft();
break;
}
}
private static string NameOf(Character c)
{
NetworkingManager instance = NetworkingManager.Instance;
object obj;
if (instance == null)
{
obj = null;
}
else
{
NetworkManager networkManager = instance.NetworkManager;
if (networkManager == null)
{
obj = null;
}
else
{
Root root = ((Observer<Root>)(object)networkManager).Root;
obj = ((root != null) ? root.AllCharacters : null);
}
}
ObservableList<Character> val = (ObservableList<Character>)obj;
int num = ((val != null && c != null) ? val.IndexOf(c) : (-1));
if (num < 0)
{
return null;
}
string text = c.CharacterInfoGuidString ?? "";
return $"{num}:{((text.Length > 8) ? text.Substring(0, 8) : text)}";
}
private static int FlagRemoved(string ids)
{
NetworkingManager instance = NetworkingManager.Instance;
object obj;
if (instance == null)
{
obj = null;
}
else
{
NetworkManager networkManager = instance.NetworkManager;
if (networkManager == null)
{
obj = null;
}
else
{
Root root = ((Observer<Root>)(object)networkManager).Root;
obj = ((root != null) ? root.AllCharacters : null);
}
}
ObservableList<Character> val = (ObservableList<Character>)obj;
if (val == null || string.IsNullOrEmpty(ids))
{
return 0;
}
int num = 0;
string[] array = ids.Split(',');
for (int i = 0; i < array.Length; i++)
{
string[] array2 = array[i].Split(':');
if (array2.Length == 2 && int.TryParse(array2[0], out var result) && result >= 0 && result < val.Count)
{
Character val2 = val[result];
if (val2 != null && (val2.CharacterInfoGuidString ?? "").StartsWith(array2[1]))
{
val2.DespawnedNoRewards = true;
num++;
}
}
}
return num;
}
}
public static class Waves
{
internal const float PointsGrowth = 0.15f;
internal const int LevelStep = 2;
internal const float MixChance = 0.5f;
internal const int MaxAlive = 24;
internal const int BossEvery = 5;
internal const int LateBossLevel = 20;
private static int _shown;
private const float CloseDelay = 1f;
private static float _closeAt;
private static readonly List<Character> Foes = new List<Character>();
private static CharacterInfo _lastBoss;
private static List<Records.Hero> _heroes = new List<Records.Hero>();
private static float _beganAt;
private static string _endTitle;
public static bool Armed { get; private set; }
public static bool Active { get; private set; }
public static bool Ending { get; private set; }
public static int Wave { get; private set; }
public static int Killed { get; private set; }
public static string LastResult { get; private set; } = "";
public static string EndReason { get; private set; }
public static int OnField
{
get
{
if (!Active)
{
return _shown;
}
return Wave;
}
}
public static string Arm()
{
Armed = true;
return "armed: the next battle is a wave defense run";
}
public static string Begin()
{
if (!NetworkingManager.Instance.IsServer)
{
return "only the host runs the waves";
}
if (!InFight())
{
return "no battle on";
}
if (!MapBuilder.Ready || MapBuilder.Current == null || MapBuilder.Current.enemies.Length == 0)
{
return "the battle isn't on a MapMaker map with enemy spots";
}
Armed = false;
Active = true;
Ending = false;
Wave = 1;
Killed = 0;
Foes.Clear();
LastResult = "";
EndReason = null;
_heroes = Records.Party();
_beganAt = Time.unscaledTime;
_endTitle = null;
Shrines.Due = true;
Plugin.ModLog.LogInfo((object)("Wave Defense: run begins on '" + MapBuilder.Current.name + "', wave 1 is the map's fight " + $"({LivingEnemies().Count} enemies)."));
Titles.Show(Titles.WaveTitle(1, null));
WaveNet.SendWave(1, null);
return "wave 1";
}
public static string Stop(string why)
{
if (!Active && !Armed)
{
return "no run";
}
if (Active)
{
Plugin.ModLog.LogInfo((object)$"Wave Defense: run over ({why}): wave {Wave} reached, {Killed} enemies killed.");
if (why != "hot reload")
{
try
{
Records.Note(Wave, Killed, why, _heroes);
}
catch (Exception arg)
{
Plugin.ModLog.LogWarning((object)$"Wave Defense: records: {arg}");
}
}
}
Armed = false;
Active = false;
Ending = false;
Shrines.Due = false;
Foes.Clear();
return LastResult = $"wave {Wave} reached, {Killed} killed ({why})";
}
public static string Status()
{
return $"armed={Armed} active={Active} ending={Ending} wave={Wave} killed={Killed} alive={LivingEnemies().Count} last='{LastResult}' " + "shrines=[" + Shrines.Status() + "]";
}
public static int LevelOf(int wave)
{
return GlobalSettingsManager.instance.globalSettings.MaxLevel + (wave - 1) / 2;
}
private static string PartyState()
{
IEnumerable<string> values = from c in NetworkingManager.Instance.PartyCharacters
where c != null
select $"{c.CharacterName} {Mathf.RoundToInt(c.Health)}/{Mathf.RoundToInt(c.MaxHealth)} HP " + $"{Mathf.RoundToInt(c.Mana)}/{Mathf.RoundToInt(c.MaxMana)} mana";
Root val = ((Observer<Root>)(object)NetworkingManager.Instance.NetworkManager)?.Root;
return string.Format("{0} s, turn {1}: {2}", Mathf.RoundToInt(Time.unscaledTime - _beganAt), (val != null) ? val.TurnNumber : 0, string.Join("; ", values));
}
public static int PointsOf(int wave)
{
GlobalSettings globalSettings = GlobalSettingsManager.instance.globalSettings;
float num = globalSettings.GeneratedBattlePointTotal;
return Mathf.RoundToInt(num * (1f + 0.15f * (float)(wave - 1)) + num * (float)GameLogic.instance.CurrentDifficulty.AdditionalBattlePointsPerc / 100f + (float)(Math.Max(0, NetworkingManager.Instance.PartyCharacters.Count - 1) * globalSettings.AdditionalBattlePointsPerPlayer));
}
internal static void Tick()
{
if (Armed && !Active && InFight() && NetworkingManager.Instance.IsServer && MapBattle.Active)
{
Begin();
}
if (Shrines.Due && Active && !Ending && InFight() && !((Observer<Root>)(object)NetworkingManager.Instance.NetworkManager).Root.SpawnPlacementActive)
{
Shrines.Due = false;
try
{
Shrines.Raise();
}
catch (Exception arg)
{
Plugin.ModLog.LogWarning((object)$"Wave Defense: shrines: {arg}");
}
}
}
internal static bool TeamAlive(int team, bool real)
{
if (!Active || !InFight())
{
return real;
}
switch (team)
{
case 0:
if (Ending)
{
return true;
}
if (!real)
{
BeginEnding();
}
return true;
case 1:
if (Ending)
{
return Time.unscaledTime < _closeAt;
}
if (real)
{
return true;
}
CountDead();
if (SpawnWave(Wave + 1))
{
return true;
}
Plugin.ModLog.LogWarning((object)$"Wave Defense: wave {Wave + 1} couldn't be spawned; the run ends on wave {Wave}.");
Ending = true;
EndReason = $"wave {Wave} cleared, no wave {Wave + 1} could be raised";
LastResult = $"cleared wave {Wave}";
_endTitle = Titles.EndTitle(Wave, fell: false);
_closeAt = 0f;
WaveNet.SendEnd(Wave, Killed, EndReason, null);
return false;
default:
return real;
}
}
private static void BeginEnding()
{
Ending = true;
EndReason = "the party fell";
List<Character> list = LivingEnemies();
CountDead();
LastResult = $"fell on wave {Wave}";
_endTitle = Titles.EndTitle(Wave, fell: true);
Plugin.ModLog.LogInfo((object)($"Wave Defense: the party fell on wave {Wave} ({Killed} killed) after {PartyState()}; " + $"{list.Count} enemies left standing are removed and the battle closes as won."));
WaveNet.SendEnd(Wave, Killed, EndReason, list);
_closeAt = Time.unscaledTime + (WaveNet.Multiplayer ? 1f : 0f);
foreach (Character item in list)
{
try
{
item.DespawnedNoRewards = true;
item.Kill();
}
catch (Exception ex)
{
Plugin.ModLog.LogWarning((object)("Wave Defense: couldn't remove " + item.CharacterName + ": " + ex.Message));
}
}
Banner("Fallen on wave " + Titles.Roman(Wave));
}
private static bool SpawnWave(int n)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: 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_0047: 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_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0380: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: Unknown result type (might be due to invalid IL or missing references)
//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
GlobalSettings globalSettings = GlobalSettingsManager.instance.globalSettings;
Game instance = Game.Instance;
MapFile current = MapBuilder.Current;
int maxLevel = globalSettings.MaxLevel;
int num = LevelOf(n);
int num2 = PointsOf(n);
TerrainType result;
TerrainType val = (Enum.TryParse<TerrainType>(current.terrain, out result) ? result : instance.CurrentRoomTerrainType);
List<EnemyGroup> possibleEnemyGroups = globalSettings.GetPossibleEnemyGroups(val, instance.CurrentRoomTimeOfDay, maxLevel);
if (possibleEnemyGroups == null || possibleEnemyGroups.Count == 0)
{
Plugin.ModLog.LogWarning((object)$"Wave Defense: no enemy factions for {val}");
return false;
}
List<EnemyGroup> list = possibleEnemyGroups.OrderBy((EnemyGroup _) => Random.value).ToList();
bool flag = n >= 3 && list.Count > 1 && Random.value < 0.5f;
List<EnemyGroup> list2 = list.Take((!flag) ? 1 : 2).ToList();
CharacterInfo val2 = ((n % 5 == 0) ? BossFor(list2[0], val, maxLevel, n == 5) : null);
int num3 = (((Object)(object)val2 != (Object)null) ? Math.Max(0, num2 - Mathf.RoundToInt(val2.EnemyBasePointValue)) : num2);
List<CharacterInfo> list3 = new List<CharacterInfo>();
foreach (EnemyGroup item in list2)
{
list3.AddRange(GameLogic.GetEnemiesByGroupAndPoints(new List<EnemyGroup> { item }, flag ? ((float)num3 / 2f) : ((float)num3), maxLevel));
}
if ((Object)(object)val2 != (Object)null)
{
list3.Insert(0, val2);
}
else if (n % 5 == 0)
{
List<CharacterInfo> enemiesByGroupAndPoints = GameLogic.GetEnemiesByGroupAndPoints(new List<EnemyGroup> { list2[0] }, (float)num2, maxLevel, new List<EnemyType>
{
(EnemyType)2,
(EnemyType)4
});
list3.InsertRange(0, enemiesByGroupAndPoints.OrderBy((CharacterInfo _) => Random.value).Take(1 + n / 10));
}
int num4 = 24 - LivingEnemies().Count;
if (list3.Count > num4)
{
list3 = list3.Take(Math.Max(0, num4)).ToList();
}
if (list3.Count == 0)
{
return false;
}
List<HexCell> list4 = (from s in current.enemies
select MapBuilder.Cell(s.q, s.r) into _
where (Object)(object)_ != (Object)null
orderby Random.value
select _).ToList();
HashSet<HexCell> hashSet = new HashSet<HexCell>();
List<string> list5 = new List<string>();
Character val3 = null;
int num5 = 0;
foreach (CharacterInfo item2 in list3)
{
HexCell val4 = null;
int num6 = 0;
while (num6 < list4.Count && (Object)(object)val4 == (Object)null)
{
HexCell val5 = list4[num5 % list4.Count];
if (val5.Player == null && !hashSet.Contains(val5))
{
val4 = val5;
}
else
{
HexCell validEmptyNeighbor = val5.ValidEmptyNeighbor;
if (validEmptyNeighbor != null && !hashSet.Contains(validEmptyNeighbor))
{
val4 = validEmptyNeighbor;
}
}
num6++;
num5++;
}
if ((Object)(object)val4 == (Object)null)
{
break;
}
hashSet.Add(val4);
try
{
Character val6 = GameLogic.instance.CreateAI(item2, 1, num, item2.enemyType, val4, "", (QuestAIType)0, false, true, (Vector3?)null);
if (val6 != null)
{
Foes.Add(val6);
if ((Object)(object)item2 == (Object)(object)val2)
{
val3 = val6;
}
list5.Add(((Object)item2).name + " at " + MapBuilder.Where((object)val4));
}
}
catch (Exception ex)
{
Plugin.ModLog.LogWarning((object)("Wave Defense: couldn't spawn " + ((Object)item2).name + ": " + ex.Message));
}
}
if (list5.Count == 0)
{
return false;
}
Plugin.ModLog.LogInfo((object)$"Wave Defense: wave {n - 1} cleared after {PartyState()}");
Wave = n;
string text = ((val3 != null) ? val3.CharacterName : null);
if (val3 != null)
{
_lastBoss = val2;
}
Plugin.ModLog.LogInfo((object)(string.Format("Wave Defense: wave {0} (level {1}, {2} points, {3}", n, num, num2, string.Join(" + ", list2)) + ((val3 != null) ? $", boss {text} ({val3.MaxHealth} HP) + {num3} points" : ((n % 5 == 0) ? ", no boss: elites" : "")) + "): " + string.Format("{0} enemies: {1}", list5.Count, string.Join("; ", list5))));
if ((n - 1) % 5 == 0)
{
try
{
Shrines.Renew();
}
catch (Exception arg)
{
Plugin.ModLog.LogWarning((object)$"Wave Defense: shrines: {arg}");
}
}
ShowWave(n, text);
WaveNet.SendWave(n, text);
return true;
}
internal static CharacterInfo BossFor(EnemyGroup group, TerrainType terrain, int top, bool first)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: 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)
GlobalSettings globalSettings = GlobalSettingsManager.instance.globalSettings;
Func<IEnumerable<CharacterInfo>, List<CharacterInfo>> func = (IEnumerable<CharacterInfo> enumerable) => (enumerable ?? Enumerable.Empty<CharacterInfo>()).Where((CharacterInfo i) => (Object)(object)i != (Object)null && (!first || i.MinLevel < 20)).ToList();
List<CharacterInfo> list = (Plugin.AnyBoss.Value ? Factions.AllBosses(top) : new List<CharacterInfo>());
if (list.Count == 0)
{
list = func(globalSettings.GetEnemyPool(group, top, new List<EnemyType> { (EnemyType)3 }));
}
if (list.Count == 0)
{
list = func(globalSettings.GetPossibleBossCharacters(terrain, Game.Instance.CurrentRoomTimeOfDay, top));
}
List<CharacterInfo> list2 = list.Where((CharacterInfo i) => (Object)(object)i != (Object)(object)_lastBoss).ToList();
if (list2.Count == 0)
{
list2 = list;
}
if (list2.Count != 0)
{
return list2[Random.Range(0, list2.Count)];
}
return null;
}
internal static void ShowWave(int n, string boss)
{
if (!Active)
{
_shown = n;
}
Titles.Show(Titles.WaveTitle(n, boss));
}
internal static void ClearShown()
{
_shown = 0;
_endTitle = null;
}
internal static void EndShown(int wave, string why)
{
_shown = 0;
LastResult = $"wave {wave} reached ({why})";
bool flag = why == "the party fell";
_endTitle = Titles.EndTitle(wave, flag);
if (flag)
{
Banner("Fallen on wave " + Titles.Roman(wave));
}
}
internal static string TakeEndTitle()
{
string endTitle = _endTitle;
_endTitle = null;
return endTitle;
}
private static void CountDead()
{
Killed = ((Observer<Root>)(object)NetworkingManager.Instance.NetworkManager).Root.CharactersInBattle.Count((Character c) => c != null && c.TeamIndex == 1 && c.IsDead && !c.DespawnedNoRewards);
}
private static List<Character> LivingEnemies()
{
NetworkingManager instance = NetworkingManager.Instance;
Root val = ((instance == null) ? null : ((Observer<Root>)(object)instance.NetworkManager)?.Root);
if (val == null)
{
return new List<Character>();
}
return val.CharactersInBattle.Where((Character c) => c != null && c.TeamIndex == 1 && !c.IsDead).ToList();
}
internal static bool InFight()
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Invalid comparison between Unknown and I4
if ((Object)(object)GameLogic.instance != (Object)null && GameLogic.instance.GameStarted && (Object)(object)GUIManager.instance != (Object)null)
{
return (int)GUIManager.instance.CurrentGuiState == 2;
}
return false;
}
internal static void Banner(string text)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
GUIManager instance = GUIManager.instance;
if ((Object)(object)instance == (Object)null)
{
return;
}
try
{
instance.ChangeBattleTopText(text, instance.TopBattleTextActiveBG, ColorUtility.ToHtmlStringRGBA(Color.white));
}
catch (Exception ex)
{
Plugin.ModLog.LogWarning((object)("Wave Defense: banner failed: " + ex.Message));
}
}
}
}