using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using CatAPI;
using CustomAchievements;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[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 ArtanisAchievement
{
internal static class Achievements
{
internal const int PrecisionDrone = 5102;
internal const int AttackDrone = 5103;
internal const int Corvette = 5111;
internal const int Destroyer = 5112;
internal const int ShieldTarget = 20000;
internal const int LossTarget = 152;
internal const int BurstKillTarget = 50;
internal static Achievement ActivatingShields;
internal static Achievement WellDone;
internal static Achievement WellFought;
internal static Achievement BattleTurned;
internal static Achievement CouldNotHold;
internal static Achievement GreatLosses;
internal static Achievement MustRegroup;
internal static Achievement EmbraceGlory;
internal static void Register()
{
AchievementMod mod = AchievementRegistry.RegisterMod("https://github.com/cat-yummi-dspmod/DSP-ArtanisAchievement", AchText.En("Artanis Achievement").ZhCN("荣耀贩子"));
ActivatingShields = Add(mod, "activating-shields", AchText.En("Activating shields!").ZhCN("激活护盾!"), AchText.En("Icarus regenerates 20,000 shield within 10 seconds.").ZhCN("伊卡洛斯10秒内恢复20000点护盾值。"), 20000L);
WellDone = Add(mod, "well-done", AchText.En("You have done well.").ZhCN("大家做得很好"), AchText.En("Wipe out a Dark Fog space assault without touching the controls.").ZhCN("伊卡洛斯在没有任何操作的前提下,全灭一次太空黑雾的攻击。"), 1L);
WellFought = Add(mod, "well-fought", AchText.En("Well fought.").ZhCN("漂亮的一仗"), AchText.En("Destroy a Dark Fog space core with no save loaded and no ship lost in the last 5 minutes.").ZhCN("在5分钟内没有读档且没有损失舰船的情况下,消灭一个太空黑雾核心。"), 1L);
BattleTurned = Add(mod, "battle-turned", AchText.En("The battle has turned against my warriors.").ZhCN("战局对我们的战士太不利了"), AchText.En("Lose 152 Precision Drones within 5 minutes.").ZhCN("5分钟内阵亡152个精准无人机。"), 152L);
CouldNotHold = Add(mod, "could-not-hold", AchText.En("My warriors could not hold.").ZhCN("我的战士们坚持不住了"), AchText.En("Lose 152 Attack Drones within 5 minutes.").ZhCN("5分钟内阵亡152个攻击无人机。"), 152L);
GreatLosses = Add(mod, "great-losses", AchText.En("My forces have suffered great loss.").ZhCN("我的部队损失惨重"), AchText.En("Lose 152 Corvettes within 5 minutes.").ZhCN("5分钟内阵亡152个护卫舰。"), 152L);
MustRegroup = Add(mod, "must-regroup", AchText.En("I must regroup my forces.").ZhCN("我得重新集结部队"), AchText.En("Lose 152 Destroyers within 5 minutes.").ZhCN("5分钟内阵亡152个驱逐舰。"), 152L);
EmbraceGlory = Add(mod, "embrace-glory", AchText.En("We embrace the glory of battle.").ZhCN("拥抱战斗的荣耀"), AchText.En("Destroy 50 or more Dark Fog units with a single Energy Shell Burst.").ZhCN("用能量盾爆破一次性消灭50个以上黑雾单位。"), 50L);
}
private static Achievement Add(AchievementMod mod, string key, AchText name, AchText description, long target = 1L)
{
AchIcon val = AchIcon.FromEmbeddedPng(typeof(Achievements).Assembly, "ArtanisAchievement.icons." + key + ".png");
return mod.Register(key, name, description, target, val, false);
}
internal static Achievement ForFighter(int protoId)
{
return (Achievement)(protoId switch
{
5102 => BattleTurned,
5103 => CouldNotHold,
5111 => GreatLosses,
5112 => MustRegroup,
_ => null,
});
}
}
internal sealed class AssaultWatch
{
internal readonly long StartTick;
internal bool Failed;
internal int Killed;
private readonly HashSet<int> units = new HashSet<int>();
private readonly List<int> gone = new List<int>();
internal bool WipedOut
{
get
{
if (!Failed && Killed > 0)
{
return units.Count == 0;
}
return false;
}
}
internal AssaultWatch(long startTick)
{
StartTick = startTick;
}
internal void Scan(SpaceSector sector, EnemyDFHiveSystem hive)
{
EnemyData[] enemyPool = sector.enemyPool;
EnemyUnitComponent[] array = hive.units?.buffer;
if (enemyPool == null)
{
return;
}
if (array != null)
{
int cursor = hive.units.cursor;
for (int i = 1; i < cursor && i < array.Length; i++)
{
if (array[i].id == i)
{
int enemyId = array[i].enemyId;
if (IsAssaulting(enemyPool, enemyId))
{
units.Add(enemyId);
}
}
}
}
gone.Clear();
foreach (int unit in units)
{
if (!IsAssaulting(enemyPool, unit))
{
gone.Add(unit);
}
}
foreach (int item in gone)
{
units.Remove(item);
if (CombatEvents.TakeKilledAssaultUnit(item))
{
Killed++;
}
else
{
Failed = true;
}
}
}
private static bool IsAssaulting(EnemyData[] pool, int enemyId)
{
if (enemyId > 0 && enemyId < pool.Length && pool[enemyId].id == enemyId)
{
return ((EnemyData)(ref pool[enemyId])).isAssaultingUnit;
}
return false;
}
}
internal static class CombatEvents
{
internal struct ShieldGain
{
public long Tick;
public long Energy;
}
private static readonly object sync = new object();
private static readonly Dictionary<int, Queue<long>> fighterLosses = new Dictionary<int, Queue<long>>
{
{
5102,
new Queue<long>()
},
{
5103,
new Queue<long>()
},
{
5111,
new Queue<long>()
},
{
5112,
new Queue<long>()
}
};
private static readonly Queue<ShieldGain> shieldGains = new Queue<ShieldGain>();
private static readonly List<int> coreKillStars = new List<int>();
private static readonly HashSet<int> killedAssaultUnits = new HashSet<int>();
private static long lastMechaShipLossTick = long.MinValue;
private const long BurstWindow = 75L;
private static long burstStartTick = long.MinValue;
private static int burstKills;
internal static int BurstKills
{
get
{
lock (sync)
{
return burstKills;
}
}
}
internal static long LastMechaShipLossTick
{
get
{
lock (sync)
{
return lastMechaShipLossTick;
}
}
}
internal static void Reset()
{
lock (sync)
{
foreach (Queue<long> value in fighterLosses.Values)
{
value.Clear();
}
shieldGains.Clear();
coreKillStars.Clear();
killedAssaultUnits.Clear();
lastMechaShipLossTick = long.MinValue;
burstStartTick = long.MinValue;
burstKills = 0;
}
}
internal static void OnShieldBurst()
{
long gameTick = GameMain.gameTick;
lock (sync)
{
burstStartTick = gameTick;
burstKills = 0;
}
}
internal static void OnMechaKill()
{
long gameTick = GameMain.gameTick;
lock (sync)
{
if (burstStartTick != long.MinValue && gameTick >= burstStartTick && gameTick <= burstStartTick + 75)
{
burstKills++;
}
}
}
internal static void OnFighterLost(int protoId, bool mechaSpaceShip)
{
long gameTick = GameMain.gameTick;
lock (sync)
{
if (fighterLosses.TryGetValue(protoId, out var value))
{
value.Enqueue(gameTick);
}
if (mechaSpaceShip)
{
lastMechaShipLossTick = gameTick;
}
}
}
internal static void OnShieldGain(long energy)
{
long gameTick = GameMain.gameTick;
lock (sync)
{
shieldGains.Enqueue(new ShieldGain
{
Tick = gameTick,
Energy = energy
});
}
}
internal static void OnCoreKilled(int starId)
{
lock (sync)
{
coreKillStars.Add(starId);
}
}
internal static void OnAssaultUnitKilled(int enemyId)
{
lock (sync)
{
killedAssaultUnits.Add(enemyId);
}
}
internal static int FighterLossesSince(int protoId, long fromTick)
{
lock (sync)
{
Queue<long> queue = fighterLosses[protoId];
while (queue.Count > 0 && queue.Peek() < fromTick)
{
queue.Dequeue();
}
return queue.Count;
}
}
internal static long ShieldEnergySince(long fromTick)
{
lock (sync)
{
while (shieldGains.Count > 0 && shieldGains.Peek().Tick < fromTick)
{
shieldGains.Dequeue();
}
long num = 0L;
foreach (ShieldGain shieldGain in shieldGains)
{
num += shieldGain.Energy;
}
return num;
}
}
internal static List<int> TakeCoreKills()
{
lock (sync)
{
List<int> result = new List<int>(coreKillStars);
coreKillStars.Clear();
return result;
}
}
internal static bool TakeKilledAssaultUnit(int enemyId)
{
lock (sync)
{
return killedAssaultUnits.Remove(enemyId);
}
}
internal static void ClearKilledAssaultUnits()
{
lock (sync)
{
killedAssaultUnits.Clear();
}
}
}
[HarmonyPatch]
internal static class CombatHooks
{
[HarmonyPrefix]
[HarmonyPatch(typeof(SpaceSector), "KillCraftFinal")]
[Guard("8d331b6d165290d0")]
public static void SpaceSector_KillCraftFinal_Prefix(SpaceSector __instance, int craftId)
{
RecordFighterLoss(__instance.craftPool, craftId);
}
[HarmonyPrefix]
[HarmonyPatch(typeof(PlanetFactory), "KillCraftFinally")]
[Guard("4438112e7d007854")]
public static void PlanetFactory_KillCraftFinally_Prefix(PlanetFactory __instance, int craftId)
{
RecordFighterLoss(__instance.craftPool, craftId);
}
[HarmonyPrefix]
[HarmonyPatch(typeof(SpaceSector), "KillEnemyFinal")]
[Guard("cb31108bc5305076")]
public static void SpaceSector_KillEnemyFinal_Prefix(SpaceSector __instance, int enemyId, ref CombatStat combatStat)
{
RecordMechaKill(__instance.enemyPool, enemyId, ref combatStat);
EnemyData[] enemyPool = __instance.enemyPool;
if (enemyId <= 0 || enemyPool == null || enemyId >= enemyPool.Length)
{
return;
}
ref EnemyData reference = ref enemyPool[enemyId];
if (reference.id == enemyId)
{
if (((EnemyData)(ref reference)).isAssaultingUnit)
{
CombatEvents.OnAssaultUnitKilled(enemyId);
}
if (reference.dfSCoreId > 0)
{
CombatEvents.OnCoreKilled((__instance.GetHiveByAstroId(reference.originAstroId)?.starData?.id).GetValueOrDefault());
}
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(PlanetFactory), "KillEnemyFinally")]
[Guard("e83f0731e4b18ba0")]
public static void PlanetFactory_KillEnemyFinally_Prefix(PlanetFactory __instance, int enemyId, ref CombatStat combatStat)
{
RecordMechaKill(__instance.enemyPool, enemyId, ref combatStat);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(PlayerAction_Combat), "ShieldBurst")]
[Guard("9442e06fa083a721")]
public static void PlayerAction_Combat_ShieldBurst_Postfix(PlayerAction_Combat __instance)
{
if (((PlayerAction)__instance).player != null && ((PlayerAction)__instance).player == GameMain.mainPlayer)
{
CombatEvents.OnShieldBurst();
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Mecha), "UpdateCombatStats")]
[Guard("e0c3d2d8aa654f22")]
public static void Mecha_UpdateCombatStats_Prefix(Mecha __instance, out long __state)
{
__state = __instance.energyShieldEnergy;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Mecha), "UpdateCombatStats")]
[Guard("e0c3d2d8aa654f22")]
public static void Mecha_UpdateCombatStats_Postfix(Mecha __instance, long __state)
{
long num = __instance.energyShieldEnergy - __state;
if (num > 0 && __instance.player != null && __instance.player == GameMain.mainPlayer)
{
CombatEvents.OnShieldGain(num);
}
}
private static void RecordMechaKill(EnemyData[] pool, int enemyId, ref CombatStat combatStat)
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Invalid comparison between Unknown and I4
if (enemyId > 0 && pool != null && enemyId < pool.Length && pool[enemyId].id == enemyId && (int)combatStat.lastCaster.type == 15 && combatStat.lastCaster.id == 1)
{
CombatEvents.OnMechaKill();
}
}
private static void RecordFighterLoss(CraftData[] pool, int craftId)
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Invalid comparison between Unknown and I4
if (craftId <= 0 || pool == null || craftId >= pool.Length)
{
return;
}
ref CraftData reference = ref pool[craftId];
if (reference.id != craftId || reference.unitId <= 0 || (int)reference.prototype != 5)
{
return;
}
int owner = reference.owner;
if (owner > 0 && owner < pool.Length)
{
int owner2 = pool[owner].owner;
if (owner2 != 0)
{
CombatEvents.OnFighterLost(reference.protoId, owner2 < 0 && reference.isSpace);
}
}
}
}
internal static class PatchCheck
{
private struct Hook
{
public MethodBase Target;
public string Name;
public string Affects;
}
internal static void Report(Harmony harmony)
{
List<Hook> list = new List<Hook>
{
new Hook
{
Target = AccessTools.Method(typeof(SpaceSector), "KillCraftFinal", (Type[])null, (Type[])null),
Name = "SpaceSector.KillCraftFinal",
Affects = "My forces have suffered great loss, I must regroup my forces, Well fought"
},
new Hook
{
Target = AccessTools.Method(typeof(PlanetFactory), "KillCraftFinally", (Type[])null, (Type[])null),
Name = "PlanetFactory.KillCraftFinally",
Affects = "The battle has turned against my warriors, My warriors could not hold"
},
new Hook
{
Target = AccessTools.Method(typeof(SpaceSector), "KillEnemyFinal", (Type[])null, (Type[])null),
Name = "SpaceSector.KillEnemyFinal",
Affects = "You have done well, Well fought, We embrace the glory of battle"
},
new Hook
{
Target = AccessTools.Method(typeof(PlanetFactory), "KillEnemyFinally", (Type[])null, (Type[])null),
Name = "PlanetFactory.KillEnemyFinally",
Affects = "We embrace the glory of battle"
},
new Hook
{
Target = AccessTools.Method(typeof(PlayerAction_Combat), "ShieldBurst", (Type[])null, (Type[])null),
Name = "PlayerAction_Combat.ShieldBurst",
Affects = "We embrace the glory of battle"
},
new Hook
{
Target = AccessTools.Method(typeof(Mecha), "UpdateCombatStats", (Type[])null, (Type[])null),
Name = "Mecha.UpdateCombatStats",
Affects = "Activating shields!"
}
};
int num = 0;
foreach (Hook item in list)
{
Patches val = ((item.Target == null) ? null : Harmony.GetPatchInfo(item.Target));
if (val != null && val.Owners.Contains(harmony.Id))
{
num++;
Plugin.Log.LogInfo((object)(" hooked " + item.Name));
}
else
{
Plugin.Log.LogWarning((object)(" NOT hooked " + item.Name + " -> these achievements will not progress: " + item.Affects));
}
}
Plugin.Log.LogInfo((object)$"Combat hooks: {num}/{list.Count} applied");
}
}
[BepInPlugin("com.yummi.dsp.artanisachievement", "Artanis Achievement", "0.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "com.yummi.dsp.artanisachievement";
public const string PluginName = "Artanis Achievement";
public const string PluginVersion = "0.0.0";
public const string GitHubUrl = "https://github.com/cat-yummi-dspmod/DSP-ArtanisAchievement";
private static readonly Harmony harmony = new Harmony("com.yummi.dsp.artanisachievement");
internal static ManualLogSource Log;
private bool trackerFailed;
private void Awake()
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Achievements.Register();
Harness.PatchAll(harmony, typeof(CombatHooks), new PatchOptions
{
ModName = "Artanis Achievement"
});
PatchCheck.Report(harmony);
Log.LogInfo((object)"Artanis Achievement v0.0.0 loaded");
}
private void Update()
{
if (trackerFailed)
{
return;
}
try
{
Tracker.Update();
}
catch (Exception ex)
{
trackerFailed = true;
Log.LogError((object)("Achievement tracking stopped after an error: " + ex));
Harness.Report((NoticeLevel)2, "Artanis Achievement", "成就判定出错,已停止,详情见日志", "Achievement tracking failed and stopped; see the log", (string)null, (string)null);
}
}
private void OnDestroy()
{
harmony.UnpatchSelf();
}
}
internal static class Tracker
{
private const long ShieldWindow = 600L;
private const long LossWindow = 18000L;
private const long ScanInterval = 10L;
private const int FreshWaveTicks = 300;
private static readonly int[] fighterTypes = new int[4] { 5102, 5103, 5111, 5112 };
private static readonly Dictionary<EnemyDFHiveSystem, AssaultWatch> watches = new Dictionary<EnemyDFHiveSystem, AssaultWatch>();
private static readonly HashSet<EnemyDFHiveSystem> joinedLate = new HashSet<EnemyDFHiveSystem>();
private static readonly HashSet<EnemyDFHiveSystem> seen = new HashSet<EnemyDFHiveSystem>();
private static readonly List<EnemyDFHiveSystem> leftBehind = new List<EnemyDFHiveSystem>();
private static GameData trackedGame;
private static long trackingStartTick;
private static long nextScanTick;
private static long lastInputTick;
private static long lastTick;
internal static void Update()
{
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
GameData data = GameMain.data;
if (!GameMain.isRunning || DSPGame.IsMenuDemo || data == null || GameMain.mainPlayer == null)
{
trackedGame = null;
return;
}
long gameTick = GameMain.gameTick;
if (data != trackedGame || gameTick < lastTick)
{
StartTracking(data);
}
lastTick = gameTick;
if (Input.anyKey || Input.mouseScrollDelta != Vector2.zero)
{
lastInputTick = gameTick;
}
if (gameTick >= nextScanTick)
{
nextScanTick = gameTick + 10;
CheckShield(gameTick);
CheckLosses(gameTick);
Raise(Achievements.EmbraceGlory, CombatEvents.BurstKills);
CheckCoreKills(gameTick);
CheckAssaults(gameTick, data);
}
}
private static void StartTracking(GameData data)
{
trackedGame = data;
trackingStartTick = GameMain.gameTick;
nextScanTick = 0L;
lastInputTick = long.MinValue;
watches.Clear();
joinedLate.Clear();
CombatEvents.Reset();
bool isSandboxMode = data.gameDesc.isSandboxMode;
Plugin.Log.LogInfo((object)(isSandboxMode ? "Game started in sandbox mode; achievements will not progress" : $"Tracking achievements for this game (combat mode: {data.gameDesc.isCombatMode})"));
}
private static void Raise(Achievement achievement, long value)
{
if (achievement != null && achievement.CanProgress && value > achievement.Progress)
{
achievement.SetProgress(value);
}
}
private static void CheckShield(long now)
{
long num = CombatEvents.ShieldEnergySince(now - 600);
long energyShieldEnergyRate = GameMain.mainPlayer.mecha.energyShieldEnergyRate;
if (energyShieldEnergyRate > 0)
{
Raise(Achievements.ActivatingShields, num / (energyShieldEnergyRate * 100));
}
}
private static void CheckLosses(long now)
{
int[] array = fighterTypes;
foreach (int protoId in array)
{
Raise(Achievements.ForFighter(protoId), CombatEvents.FighterLossesSince(protoId, now - 18000));
}
}
private static void CheckCoreKills(long now)
{
List<int> list = CombatEvents.TakeCoreKills();
if (list.Count != 0 && !Achievements.WellFought.Unlocked)
{
StarData localStar = GameMain.localStar;
bool flag = now - trackingStartTick >= 18000 && CombatEvents.LastMechaShipLossTick < now - 18000;
if (localStar != null && flag && HasSpaceFleetOut(GameMain.mainPlayer.mecha) && list.Contains(localStar.id))
{
Achievements.WellFought.Unlock();
}
}
}
private static bool HasSpaceFleetOut(Mecha mecha)
{
CombatModuleComponent spaceCombatModule = mecha.spaceCombatModule;
if (spaceCombatModule == null || !spaceCombatModule.moduleEnabled || spaceCombatModule.moduleFleets == null)
{
return false;
}
for (int i = 0; i < spaceCombatModule.fleetCount && i < spaceCombatModule.moduleFleets.Length; i++)
{
if (spaceCombatModule.moduleFleets[i].fleetId > 0)
{
return true;
}
}
return false;
}
private static void CheckAssaults(long now, GameData data)
{
SpaceSector spaceSector = data.spaceSector;
StarData localStar = GameMain.localStar;
Player mainPlayer = GameMain.mainPlayer;
seen.Clear();
if (spaceSector?.dfHives != null && localStar != null && localStar.index >= 0 && localStar.index < spaceSector.dfHives.Length)
{
for (EnemyDFHiveSystem val = spaceSector.dfHives[localStar.index]; val != null; val = val.nextSibling)
{
seen.Add(val);
watches.TryGetValue(val, out var value);
if (val.evolve.waveTicks > 0)
{
if (value == null && !joinedLate.Contains(val))
{
if (val.evolve.waveTicks <= 300)
{
value = new AssaultWatch(now);
watches[val] = value;
}
else
{
joinedLate.Add(val);
}
}
if (value != null)
{
Judge(value, mainPlayer);
value.Scan(spaceSector, val);
}
}
else
{
joinedLate.Remove(val);
if (value != null)
{
Finish(val, value, spaceSector, mainPlayer);
}
}
}
}
leftBehind.Clear();
foreach (EnemyDFHiveSystem key in watches.Keys)
{
if (!seen.Contains(key))
{
leftBehind.Add(key);
}
}
foreach (EnemyDFHiveSystem item in leftBehind)
{
AssaultWatch assaultWatch = watches[item];
if (item.starData != localStar)
{
assaultWatch.Failed = true;
}
Finish(item, assaultWatch, spaceSector, mainPlayer);
}
joinedLate.RemoveWhere((EnemyDFHiveSystem h) => !seen.Contains(h));
if (watches.Count == 0)
{
CombatEvents.ClearKilledAssaultUnits();
}
}
private static void Judge(AssaultWatch watch, Player player)
{
if (lastInputTick >= watch.StartTick || !player.isAlive)
{
watch.Failed = true;
}
}
private static void Finish(EnemyDFHiveSystem hive, AssaultWatch watch, SpaceSector sector, Player player)
{
watches.Remove(hive);
Judge(watch, player);
if (!watch.Failed && sector != null)
{
watch.Scan(sector, hive);
}
if (watch.WipedOut)
{
Achievements.WellDone.Unlock();
}
}
}
}