private static void OnLocalTransitionEntered()
        {
            GlobalLog.Info("[CombatAreaCache] Resetting unwalkable flags on all cached objects.");

            var cache = Current;

            foreach (var item in cache.Items)
            {
                item.Unwalkable = false;
            }
            foreach (var monster in cache.Monsters)
            {
                monster.Unwalkable = false;
            }
            foreach (var chest in cache.Chests)
            {
                chest.Unwalkable = false;
            }
            foreach (var specialChest in cache.SpecialChests)
            {
                specialChest.Unwalkable = false;
            }
            foreach (var strongbox in cache.Strongboxes)
            {
                strongbox.Unwalkable = false;
            }
            foreach (var shrine in cache.Shrines)
            {
                shrine.Unwalkable = false;
            }
            foreach (var transition in cache.AreaTransitions)
            {
                transition.Unwalkable = false;
            }
        }
        private static void DoorScan(IncursionData data)
        {
            foreach (var door in IncursionDoors)
            {
                var targetable = door.IsTargetable;
                var id         = door.Id;
                var index      = data.Doors.FindIndex(d => d.Id == id);

                if (index >= 0)
                {
                    if (!targetable)
                    {
                        GlobalLog.Info($"[HandleIncursionTask] Removing opened {door.WalkablePosition()}");
                        data.Doors.RemoveAt(index);
                    }
                }
                else
                {
                    if (targetable)
                    {
                        var pos = door.WalkablePosition();
                        GlobalLog.Warn($"[HandleIncursionTask] Registering {pos}");
                        data.Doors.Add(new CachedObject(id, pos));
                    }
                }
            }
        }
示例#3
0
        public MessageResult Message(Loki.Bot.Message message)
        {
            var id = message.Id;

            if (id == Events.Messages.ItemStashedEvent)
            {
                var itemName = message.GetInput <CachedItem>()?.Name;

                if (!_hasWhiteSextants && itemName == CurrencyNames.SextantApprentice)
                {
                    GlobalLog.Info("[SextantTask] Apprentice Sextant has been stashed. Now marking them as available.");
                    _hasWhiteSextants = true;
                    return(MessageResult.Processed);
                }
                if (!_hasYellowSextants && itemName == CurrencyNames.SextantJourneyman)
                {
                    GlobalLog.Info("[SextantTask] Journeyman Sextant has been stashed. Now marking them as available.");
                    _hasYellowSextants = true;
                    return(MessageResult.Processed);
                }
                if (!_hasRedSextants && itemName == CurrencyNames.SextantMaster)
                {
                    GlobalLog.Info("[SextantTask] Master Sextant has been stashed. Now marking them as available.");
                    _hasRedSextants = true;
                    return(MessageResult.Processed);
                }
                return(MessageResult.Unprocessed);
            }
            if (id == Events.Messages.CombatAreaChanged)
            {
                ResetErrors();
                return(MessageResult.Processed);
            }
            return(MessageResult.Unprocessed);
        }
示例#4
0
        public override void OnStashing(CachedItem item)
        {
            if (_tabWithGcpSet != null || item.Type.ItemType != ItemTypes.Gem || item.Quality < 1)
            {
                return;
            }

            var qualities = GemQualitiesInCurrentTab;

            if (qualities.Count == 0)
            {
                return;
            }

            var finder = new GemSetFinder(qualities);

            _gcpSet = finder.BestSet;

            if (_gcpSet != null)
            {
                GlobalLog.Info($"[OnQGemStash] Found gem set for gcp recipe {_gcpSet}");
                _tabWithGcpSet = LokiPoe.InGameState.StashUi.TabControl.CurrentTabName;
            }
            else
            {
                GlobalLog.Info("[OnQGemStash] Gem set for gcp recipe was not found.");
            }
        }
示例#5
0
        public MessageResult Message(Message message)
        {
            var id = message.Id;

            if (id == MapBot.Messages.NewMapEntered)
            {
                GlobalLog.Info("[SpecialObjectTask] Reset.");

                Reset(message.GetInput <string>());

                if (_enabled)
                {
                    GlobalLog.Info("[SpecialObjectTask] Enabled.");
                }

                return(MessageResult.Processed);
            }
            if (id == ComplexExplorer.LocalTransitionEnteredMessage)
            {
                GlobalLog.Info("[SpecialObjectTask] Resetting unwalkable flags.");
                foreach (var speacialObj in Objects)
                {
                    speacialObj.Unwalkable = false;
                }
                return(MessageResult.Processed);
            }
            return(MessageResult.Unprocessed);
        }
示例#6
0
        public MessageResult Message(Message message)
        {
            var id = message.Id;

            if (id == MapBot.Messages.NewMapEntered)
            {
                GlobalLog.Info("[KillBossTask] Reset.");
                var areaName = message.GetInput <string>();
                _bossesKilled    = 0;
                _currentTarget   = null;
                BossKilled       = false;
                _multiPhaseBoss  = false;
                _teleportingBoss = false;
                CachedBosses.Clear();
                SetBossSelector(areaName);
                SetPriorityBossName(areaName);
                SetBossRange(areaName);

                if (areaName == MapNames.VaultsOfAtziri)
                {
                    BossKilled = true;
                    GlobalLog.Info($"[KillBossTask] BossKilled is set to true ({areaName})");
                    return(MessageResult.Processed);
                }

                if (areaName == MapNames.MineralPools ||
                    areaName == MapNames.Palace ||
                    areaName == MapNames.Basilica ||
                    areaName == MapNames.MaelstromOfChaos)
                {
                    _multiPhaseBoss = true;
                    GlobalLog.Info($"[KillBossTask] MultiPhaseBoss is set to true ({areaName})");
                    return(MessageResult.Processed);
                }

                if (areaName == MapNames.Pen ||
                    areaName == MapNames.Pier ||
                    areaName == MapNames.Shrine ||
                    areaName == MapNames.DesertSpring ||
                    areaName == MapNames.Summit ||
                    areaName == MapNames.DarkForest ||
                    areaName == MapNames.PutridCloister)
                {
                    _teleportingBoss = true;
                    GlobalLog.Info($"[KillBossTask] TeleportingBoss is set to true ({areaName})");
                    return(MessageResult.Processed);
                }
                return(MessageResult.Processed);
            }
            if (id == ComplexExplorer.LocalTransitionEnteredMessage)
            {
                GlobalLog.Info("[KillBossTask] Resetting unwalkable flags.");
                foreach (var cachedBoss in CachedBosses)
                {
                    cachedBoss.Unwalkable = false;
                }
                return(MessageResult.Processed);
            }
            return(MessageResult.Unprocessed);
        }
        public MessageResult Message(Message message)
        {
            var id = message.Id;

            if (id == MapBot.Messages.NewMapEntered)
            {
                GlobalLog.Info("[ProximityTriggerTask] Reset.");

                Reset(message.GetInput <string>());

                if (_triggerMetadata != null)
                {
                    GlobalLog.Info("[ProximityTriggerTask] Enabled.");
                }

                return(MessageResult.Processed);
            }
            if (id == ComplexExplorer.LocalTransitionEnteredMessage)
            {
                if (_trigger != null)
                {
                    GlobalLog.Info("[ProximityTriggerTask] Resetting unwalkable flag.");
                    _trigger.Unwalkable = false;
                }
                return(MessageResult.Processed);
            }
            return(MessageResult.Unprocessed);
        }
        public override async Task Execute()
        {
            CurrencyToBuy.Sort((c1, c2) => ExchangePriority[c1.Name].CompareTo(ExchangePriority[c2.Name]));

            var currency = CurrencyToBuy[0];

            GlobalLog.Info($"[VendorTask] Now going to buy {currency.Amount} {currency.Name}.");

            if (!CanBuyInCurrentArea(currency.Name))
            {
                var exchangeArea = GetExchangeArea();
                if (exchangeArea == null)
                {
                    GlobalLog.Warn($"[VendorTask] Cannot exchange \"{currency.Name}\" in current area and Act 3 has not been opened yet.");
                    ResetData();
                    return;
                }
                if (!await PlayerAction.TakeWaypoint(exchangeArea))
                {
                    ReportError();
                    return;
                }
            }

            if (!await CurrencyPurchase(currency))
            {
                ReportError();
            }
        }
示例#9
0
        public static MapData LoadFromJson(string path)
        {
            var data = new MapData();

            if (!File.Exists(path))
            {
                return(data);
            }

            var json = File.ReadAllText(path);

            if (string.IsNullOrWhiteSpace(json))
            {
                GlobalLog.Info("[MapManager] Fail to load stash data from json. File is empty.");
                return(data);
            }
            int[] jsonCounts;
            try
            {
                jsonCounts = JsonConvert.DeserializeObject <int[]>(json);
            }
            catch (Exception)
            {
                GlobalLog.Info("[MapManager] Fail to load stash data from json. Exception during json deserialization.");
                return(data);
            }
            if (jsonCounts == null)
            {
                GlobalLog.Info("[MapManager] Fail to load stash data from json. Json deserealizer returned null.");
                return(data);
            }
            Array.Copy(jsonCounts, data._counts, data._counts.Length);
            return(data);
        }
示例#10
0
        public void Log()
        {
            var sb = new StringBuilder("[FlaskInfo] Flags: ");

            foreach (var p in GetType().GetFields())
            {
                if (p.FieldType != typeof(bool))
                {
                    continue;
                }

                var value = (bool)p.GetValue(this);
                if (value)
                {
                    sb.Append($"{p.Name}, ");
                }
            }

            sb.Length -= 2;
            sb.Append('.');
            GlobalLog.Info(sb.ToString());

            foreach (var flask in TriggerFlasks)
            {
                foreach (var trigger in flask.Triggers)
                {
                    GlobalLog.Info($"[{flask.Name}] {trigger}.");
                }
            }
        }
示例#11
0
        private static void Reset(string areaName)
        {
            _triggerMetadata = null;
            _trigger         = null;
            _waitCount       = 0;

            if (MapData.Current.IgnoredBossroom)
            {
                GlobalLog.Info("[TransitionTriggerTask] Skipping this task because bossroom is ignored.");
                return;
            }

            if (areaName == MapNames.Academy ||
                areaName == MapNames.Museum ||
                areaName == MapNames.Scriptorium)
            {
                _triggerMetadata = "Metadata/QuestObjects/Library/HiddenDoorTrigger";
                return;
            }
            if (areaName == MapNames.Necropolis)
            {
                _triggerMetadata = "Metadata/Chests/Sarcophagi/sarcophagus_door";
                return;
            }
            if (areaName == MapNames.WastePool)
            {
                _triggerMetadata = "Metadata/QuestObjects/Sewers/SewersGrate";
            }
        }
示例#12
0
        public async Task <bool> Run()
        {
            if (!World.CurrentArea.IsMap)
            {
                return(false);
            }

            await Coroutines.FinishCurrentAction();

            var maxPulses = MaxPulses;

            if (_pulse < maxPulses)
            {
                ++_pulse;
                GlobalLog.Info($"[FinishMapTask] Final pulse {_pulse}/{maxPulses}");
                await Wait.SleepSafe(500);

                return(true);
            }

            GlobalLog.Warn("[FinishMapTask] Now leaving current map.");

            if (!await PlayerAction.TpToTown())
            {
                ErrorManager.ReportError();
                return(true);
            }

            MapBot.IsOnRun = false;
            Statistics.Instance.OnMapFinish();
            GlobalLog.Info("[MapBot] MapFinished event.");
            Utility.BroadcastMessage(this, MapBot.Messages.MapFinished);
            return(true);
        }
示例#13
0
 private CombatAreaCache(uint hash)
 {
     GlobalLog.Info($"[CombatAreaCache] Creating cache for \"{World.CurrentArea.Name}\" (hash: {hash})");
     Hash            = hash;
     WorldArea       = World.CurrentArea;
     Explorer        = new ComplexExplorer();
     _lastAccessTime = Stopwatch.StartNew();
 }
示例#14
0
 private static void OnItemEvaluatorRefresh(object sender, ItemEvaluatorRefreshedEventArgs args)
 {
     if (Caches.TryGetValue(LokiPoe.LocalData.AreaHash, out var cache))
     {
         GlobalLog.Info("[CombatAreaCache] Clearing processed items.");
         cache._processedItems.Clear();
     }
 }
示例#15
0
        private static async Task <bool> TakeGcpSets()
        {
            if (!await Inventories.OpenStashTab(_tabWithGcpSet))
            {
                return(false);
            }

            while (true)
            {
                if (_gcpSet == null)
                {
                    var qualities = GemQualitiesInCurrentTab;
                    if (qualities.Count == 0)
                    {
                        GlobalLog.Info($"[TakeGcpSets] No quality gems were found in \"{_tabWithGcpSet}\" tab.");
                        _tabWithGcpSet = null;
                        return(true);
                    }

                    var finder = new GemSetFinder(qualities);
                    _gcpSet = finder.BestSet;

                    if (_gcpSet == null)
                    {
                        GlobalLog.Info($"[TakeGcpSets] No more gem sets for gcp recipe were found in \"{_tabWithGcpSet}\" tab.");
                        _tabWithGcpSet = null;
                        return(true);
                    }
                }

                if (!_gcpSet.CanFit)
                {
                    GlobalLog.Warn("[TakeGcpSets] Not enough inventory space for current gcp set.");
                    _gcpSet = null;
                    return(true);
                }

                GlobalLog.Warn($"[TakeGcpSets] Now taking gcp set {_gcpSet}");

                foreach (int q in _gcpSet.Qualities)
                {
                    var gem = StashGems.FirstOrDefault(g => QGemFitsForSelling(g) && g.Quality == q);
                    if (gem == null)
                    {
                        GlobalLog.Error($"[TakeGcpSets] Unexpected error. Fail to find gem with quality {q} as a part of {_gcpSet} gcp set.");
                        _tabWithGcpSet = null;
                        _gcpSet        = null;
                        return(false);
                    }

                    if (!await Inventories.FastMoveFromStashTab(gem.LocationTopLeft))
                    {
                        return(false);
                    }
                }
                _gcpSet = null;
            }
        }
示例#16
0
        private static async Task <bool> ExchangeCard(Vector2i cardPos)
        {
            if (!ExchangeUi.IsOpened)
            {
                if (!await OpenExchangeUi())
                {
                    return(false);
                }
            }

            var card = LokiPoe.InGameState.InventoryUi.InventoryControl_Main.Inventory.FindItemByPos(cardPos);

            if (card == null)
            {
                GlobalLog.Error($"[ExchangeCard] Fail to find item at {cardPos}.");
                return(false);
            }

            var cardName = card.Name;

            GlobalLog.Info($"[ExchangeCard] Now exchanging \"{cardName}\".");

            if (!await Inventories.FastMoveFromInventory(cardPos))
            {
                return(false);
            }

            if (!await Wait.For(() => ExchangeUiItem != null, "divination card appear in ExchangeUi"))
            {
                return(false);
            }

            // similar to Map Device UI, sometimes Activate button needs extra time to become clickable.
            await Wait.SleepSafe(200);

            var id = ExchangeUiItem.LocalId;

            var activated = ExchangeUi.Activate();

            if (activated != LokiPoe.InGameState.ActivateResult.None)
            {
                GlobalLog.Error($"[ExchangeCard] Fail to activate the ExchangeUi. Error: \"{activated}\".");
                return(false);
            }

            if (!await Wait.For(() =>
            {
                var item = ExchangeUiItem;
                return(item != null && item.LocalId != id);
            }, "divination card exchanging"))
            {
                return(false);
            }

            WriteToLog(cardName, ExchangeUiItem);
            return(true);
        }
示例#17
0
 public static bool AddSettingsProvider(string ownerId, Func <ExplorationSettings> getSettings, ProviderPriority priority)
 {
     if (!SettingsProviders.Exists(s => s.OwnerId == ownerId))
     {
         SettingsProviders.Add(new SettingsProvider(ownerId, getSettings, priority));
         GlobalLog.Info($"[ComplexExplorer] {ownerId} settings provider has been added.");
         return(true);
     }
     return(false);
 }
示例#18
0
        private static void RemoveOldCaches()
        {
            var toRemove = Caches.Where(c => c.Value._lastAccessTime.Elapsed > Lifetime).Select(c => c.Value).ToList();

            foreach (var cache in toRemove)
            {
                GlobalLog.Info($"[CombatAreaCache] Removing cache for \"{cache.WorldArea.Name}\" (hash: {cache.Hash}). Last accessed {(int) cache._lastAccessTime.Elapsed.TotalMinutes} minutes ago.");
                Caches.Remove(cache.Hash);
            }
        }
示例#19
0
        public override async Task Execute()
        {
            var area = GetCardExchangeArea();

            if (area == null)
            {
                GlobalLog.Warn("[VendorTask] Divination card exchange is not possible because this character has no access to Highgate and we are not in hideout.");
                ResetData();
                return;
            }

            if (_itemLeftInExchangeUi)
            {
                GlobalLog.Warn("[VendorTask] Item was left in ExchangeUi. Now going to take it.");

                if (!area.IsCurrentArea)
                {
                    if (!await PlayerAction.TakeWaypoint(area))
                    {
                        ReportError();
                        return;
                    }
                }

                if (!await TakeItemFromExchangeUi())
                {
                    ReportError();
                }

                return;
            }

            GlobalLog.Info("[VendorTask] Now going to exchange divination cards.");

            if (!await TakeCards())
            {
                ReportError();
                return;
            }

            if (!area.IsCurrentArea)
            {
                if (!await PlayerAction.TakeWaypoint(area))
                {
                    ReportError();
                    return;
                }
            }

            if (!await ExchangeCards())
            {
                ReportError();
            }
        }
示例#20
0
 public MessageResult Message(Message message)
 {
     if (message.Id == MapBot.Messages.NewMapEntered)
     {
         GlobalLog.Info("[EnterTrialTask] Reset.");
         _trial   = null;
         _enabled = true;
         return(MessageResult.Processed);
     }
     return(MessageResult.Unprocessed);
 }
示例#21
0
 public void Log()
 {
     GlobalLog.Info($"[ChaosRecipe] Weapons: {GetItemCount(RecipeItemType.Weapon)}");
     GlobalLog.Info($"[ChaosRecipe] Body armors: {GetItemCount(RecipeItemType.BodyArmor)}");
     GlobalLog.Info($"[ChaosRecipe] Helmets: {GetItemCount(RecipeItemType.Helmet)}");
     GlobalLog.Info($"[ChaosRecipe] Boots: {GetItemCount(RecipeItemType.Boots)}");
     GlobalLog.Info($"[ChaosRecipe] Gloves: {GetItemCount(RecipeItemType.Gloves)}");
     GlobalLog.Info($"[ChaosRecipe] Belts: {GetItemCount(RecipeItemType.Belt)}");
     GlobalLog.Info($"[ChaosRecipe] Amulets: {GetItemCount(RecipeItemType.Amulet)}");
     GlobalLog.Info($"[ChaosRecipe] Rings: {GetItemCount(RecipeItemType.Ring)}");
 }
示例#22
0
        public static bool RemoveSettingsProvider(string ownerId)
        {
            var index = SettingsProviders.FindIndex(s => s.OwnerId == ownerId);

            if (index >= 0)
            {
                SettingsProviders.RemoveAt(index);
                GlobalLog.Info($"[ComplexExplorer] {ownerId} settings provider has been removed.");
                return(true);
            }
            return(false);
        }
示例#23
0
        private static async Task <bool> ExchangeCards()
        {
            var cardPositions = Inventories.InventoryItems
                                .Where(ItemIsCardSet)
                                .Select(c => c.LocationTopLeft)
                                .ToList();

            if (cardPositions.Count == 0)
            {
                GlobalLog.Error("[ExchangeCards] Fail to find any complete divination set in inventory.");
                return(false);
            }

            cardPositions.Sort(Position.Comparer.Instance);

            GlobalLog.Info($"[ExchangeCards] Now going to exchange {cardPositions.Count} divination card sets.");

            if (!ExchangeUi.IsOpened)
            {
                if (!await OpenExchangeUi())
                {
                    return(false);
                }
            }
            if (ExchangeUiItem != null)
            {
                if (!await TakeItemFromExchangeUi())
                {
                    return(false);
                }
            }
            foreach (var cardPos in cardPositions)
            {
                if (_itemLeftInExchangeUi)
                {
                    break;
                }

                if (!await ExchangeCard(cardPos))
                {
                    return(false);
                }

                if (!await TakeItemFromExchangeUi())
                {
                    return(false);
                }
            }
            return(true);
        }
示例#24
0
 private static ExplorationSettings ProvideSettings()
 {
     foreach (var provider in SettingsProviders.OrderBy(p => p.Priority))
     {
         var settings = provider.GetSettings();
         if (settings != null)
         {
             GlobalLog.Info($"[ComplexExplorer] Exploration settings provided by {provider.OwnerId}.");
             return(settings);
         }
     }
     GlobalLog.Info("[ComplexExplorer] Exploration settings was not provided. Using default.");
     return(new ExplorationSettings());
 }
示例#25
0
        private static async Task Click()
        {
            StuckDetection.Reset();
            await Wait.LatencySleep();

            var target = LokiPoe.InGameState.CurrentTarget;

            if (target != null)
            {
                GlobalLog.Info($"[HandleBlockingChestsTask] \"{target.Name}\" ({target.Id}) is under the cursor. Now clicking on it.");
                LokiPoe.Input.PressLMB();
                await Coroutines.FinishCurrentAction(false);
            }
        }
示例#26
0
        public MessageResult Message(Message message)
        {
            if (message.Id == MapBot.Messages.NewMapEntered)
            {
                _range = -1;

                var areaName = message.GetInput <string>();
                if (areaName == MapNames.MaoKun)
                {
                    MapData.Current.TrackMob = true;
                    GlobalLog.Info("[MapExplorationTask] Monster Tracking is hard enabled for this map.");
                }
                return(MessageResult.Processed);
            }
            return(MessageResult.Unprocessed);
        }
示例#27
0
        public static async Task <bool> RerollRare(Vector2i mapPos)
        {
            while (true)
            {
                var map = InventoryUi.InventoryControl_Main.Inventory.FindItemByPos(mapPos);
                if (map == null)
                {
                    GlobalLog.Error($"[RerollRare] Fail to find a map at {mapPos}.");
                    return(false);
                }
                var rarity = map.RarityLite();
                if (rarity != Rarity.Rare)
                {
                    GlobalLog.Error($"[TakeMapTask] RerollRare is called on {rarity} map.");
                    return(false);
                }

                var affix = map.GetBannedAffix();

                if (affix == null)
                {
                    return(true);
                }

                GlobalLog.Info($"[RerollRare] Rerolling banned \"{affix}\" affix.");

                if (Settings.RerollMethod == RareReroll.Chaos)
                {
                    if (!await ApplyOrb(mapPos, CurrencyNames.Chaos))
                    {
                        return(false);
                    }
                }
                else
                {
                    if (!await ApplyOrb(mapPos, CurrencyNames.Scouring))
                    {
                        return(false);
                    }

                    if (!await ApplyOrb(mapPos, CurrencyNames.Alchemy))
                    {
                        return(false);
                    }
                }
            }
        }
示例#28
0
        public MessageResult Message(Message message)
        {
            if (message.Id == MapBot.Messages.NewMapEntered)
            {
                GlobalLog.Info("[TransitionTriggerTask] Reset.");

                Reset(message.GetInput <string>());

                if (_triggerMetadata != null)
                {
                    GlobalLog.Info("[TransitionTriggerTask] Enabled.");
                }

                return(MessageResult.Processed);
            }
            return(MessageResult.Unprocessed);
        }
示例#29
0
        public static async Task <bool> InitializeMaxSextants()
        {
            if (!await OpenAtlasUi())
            {
                return(false);
            }

            _maxSextants = LokiPoe.InGameState.AtlasUi.MaxSextants;
            GlobalLog.Info($"[SextantTask] MaxSextants: {_maxSextants}");

            if (!await CloseAtlasUi())
            {
                return(false);
            }

            return(true);
        }
示例#30
0
        private static void SetBossSelector(string areaName)
        {
            if (areaName == MapNames.Precinct)
            {
                GlobalLog.Info("[KillBossTask] This map has a group of Rogue Exiles as map bosses.");
                _isMapBoss = m => m.Rarity == Rarity.Unique && m.Metadata.Contains("MapBoss");
                return;
            }
            if (areaName == MapNames.Courthouse)
            {
                GlobalLog.Info("[KillBossTask] This map has a group of dark Rogue Exiles as map bosses.");
                _isMapBoss = m => m.Rarity == Rarity.Unique && m.Metadata.EndsWith("Kitava") && m.Metadata.Contains("/Exiles/");
                return;
            }
            if (areaName == MapNames.InfestedValley)
            {
                GlobalLog.Info("[KillBossTask] Nests have to be killed to activate boss on this map.");
                _isMapBoss = m => m.IsMapBoss || m.Name == "Gorulis' Nest";
                return;
            }
            if (areaName == MapNames.Siege)
            {
                GlobalLog.Info("[KillBossTask] Totems must be killed to remove boss immunity on this map.");
                _isMapBoss = m => m.IsMapBoss || m.Name == "Tukohama's Protection";
                return;
            }
            if (areaName == MapNames.WhakawairuaTuahu)
            {
                GlobalLog.Info("[KillBossTask] This map has Shade of a player as one of the map bosses.");
                _isMapBoss = m => m.IsMapBoss || (m.Rarity == Rarity.Unique && m.Metadata.Contains("DarkExile"));
                return;
            }

            if (areaName == MapNames.Shipyard ||
                areaName == MapNames.Lighthouse ||
                areaName == MapNames.Iceberg ||
                areaName == MapNames.AcidLakes)
            {
                GlobalLog.Info("[KillBossTask] This map has a Warband leader as a map boss.");
                _isMapBoss = m => m.Rarity == Rarity.Unique && m.ExplicitAffixes.Any(a => a.InternalName == "MonsterWbLeader");
                return;
            }

            _isMapBoss = DefaultBossSelector;
        }