public override void Update()
        {
            if (!World.Initialized ||
                AIManager.IsBusy())
            {
                return;
            }

            CalculateColoniesThatRequireMonsters();

            maxTimePerTick.Reset();
            maxTimePerTick.Start();

            while (coloniesRequiringZombies.Count > 0 && maxTimePerTick.Elapsed.TotalMilliseconds < variables.MSPerTick)
            {
                int i = 0;

                while (i < coloniesRequiringZombies.Count && maxTimePerTick.Elapsed.TotalMilliseconds < variables.MSPerTick)
                {
                    var    tuple  = coloniesRequiringZombies[i];
                    Colony colony = tuple.item1;
                    Banner banner = tuple.item2;

                    IDifficultySetting difficulty = colony.Owner.DifficultySetting;
                    float cooldown = difficulty.GetZombieSpawnCooldown(colony);

                    if (SpawnForBanner(banner, difficulty, colony, cooldown, null))
                    {
                        double nextZombieSpawn = NextZombieSpawnTimes.GetValueOrDefault(colony, 0.0) + cooldown;
                        NextZombieSpawnTimes[colony] = nextZombieSpawn;

                        if (nextZombieSpawn > Pipliz.Time.SecondsSinceStartDoubleThisFrame)
                        {
                            coloniesRequiringZombies.RemoveAt(i);
                        }
                    }
                    else if (colony.InSiegeMode)
                    {
                        coloniesRequiringZombies.RemoveAt(i); // only test getting out of siege mode once per time
                    }
                }
            }

            maxTimePerTick.Stop();
        }
        public void CalculateColoniesThatRequireMonsters()
        {
            int bannerCount = BannerTracker.GetCount();

            coloniesRequiringZombies.Clear();

            for (int i = 0; i < bannerCount; i++)
            {
                Banner banner;

                if (!BannerTracker.TryGetAtIndex(i, out banner) || !banner.KeyLocation.IsValid)
                {
                    continue;
                }

                Colony colony = Colony.Get(banner.Owner);

                if (colony.FollowerCount == 0)
                {
                    colony.OnZombieSpawn(true);
                    continue;
                }

                var ps = PlayerState.GetPlayerState(banner.Owner);
                IDifficultySetting difficultyColony = colony.Owner.DifficultySetting;

                if (!MonsterManager.BossActive)
                {
                    if (!ps.MonstersEnabled || !difficultyColony.ShouldSpawnZombies(colony))
                    {
                        colony.OnZombieSpawn(true);
                        continue;
                    }
                }

                double nextZombieSpawnTime = NextZombieSpawnTimes.GetValueOrDefault(colony, 0.0);

                if (nextZombieSpawnTime > Pipliz.Time.SecondsSinceStartDoubleThisFrame)
                {
                    continue;
                }

                if (colony.InSiegeMode)
                {
                    if (Pipliz.Time.SecondsSinceStartDoubleThisFrame - colony.LastSiegeModeSpawn < siegeModeCooldown)
                    {
                        continue;
                    }
                    else
                    {
                        colony.LastSiegeModeSpawn = Pipliz.Time.SecondsSinceStartDoubleThisFrame;
                    }
                }

                // lagging behind, or no cooldown set: teleport to current time
                if (Pipliz.Time.SecondsSinceStartDoubleThisFrame - nextZombieSpawnTime > MONSTERS_DELAY_THRESHOLD_SECONDS)
                {
                    NextZombieSpawnTimes[colony] = Pipliz.Time.SecondsSinceStartDoubleThisFrame;
                }

                coloniesRequiringZombies.Add(TupleStruct.Create(colony, banner));
            }
        }