public static Banner GetClosestBanner(Players.Player p, Vector3Int currentPos) { Banner closest = null; float distance = float.MaxValue; var banners = BannerTracker.GetBanners(); for (int i = 0; i < banners.Count; i++) { var banner = banners.GetValueAtIndex(i); if (banner.Owner == p) { var bannerDistance = Vector3.Distance(currentPos.Vector, banner.KeyLocation.Vector); if (closest == null) { closest = banner; distance = bannerDistance; } else { if (bannerDistance < distance) { closest = banner; distance = bannerDistance; } } } } return(closest); }
public void Update() { if (!World.Initialized || AIManager.IsBusy()) { return; } WorldSettings wsettings = ServerManager.WorldSettings; bool toSpawnZombies = wsettings.ZombiesEnabled && (TimeCycle.ShouldSpawnMonsters || wsettings.MonstersDayTime); int monsterMultiplier = wsettings.MonstersDoubled ? 2 : 1; double timeSinceStart = Pipliz.Time.SecondsSinceStartDouble; var banners = BannerTracker.GetBanners(); for (int i = 0; i < banners.Count; i++) { Banner banner = banners.GetValueAtIndex(i); if (banner == null || !banner.KeyLocation.IsValid) { continue; } Colony colony = Colony.Get(banner.Owner); if (toSpawnZombies) { float zombiesMax = GetMaxZombieCount(colony.FollowerCount) * monsterMultiplier; if (zombiesMax > 0f) { if (MonsterTracker.MonstersPerPlayer(banner.Owner) < zombiesMax) { if (colony.InSiegeMode) { if (timeSinceStart - colony.LastSiegeModeSpawn < siegeModeCooldown) { continue; } else { colony.LastSiegeModeSpawn = timeSinceStart; } } SpawnZombie(colony, banner, GetMosterType(colony.FollowerCount, zombiesMax)); } } else { colony.OnZombieSpawn(true); } } else { colony.OnZombieSpawn(true); } } }
public override void OnResearchComplete(ScienceManagerPlayer manager, EResearchCompletionReason reason) { manager.Player.GetTempValues(true).Set("pipliz.bannersaferadius", 100); if (reason == EResearchCompletionReason.ProgressCompleted) { BannerTracker.SendPacket(manager.Player); } }
public static AIColony AddColony(Banner banner) { AIColony newAiColony = new AIColony(banner.Owner); BannerTracker.Add(banner.KeyLocation, BuiltinBlocks.Banner, banner.Owner); Instance.Colonies.Add(newAiColony); return(newAiColony); }
public override Vector3Int GetJobLocation() { var currentPos = usedNPC.Position; if (_playerState.CallToArmsEnabled && _weapon != null) { _target = MonsterTracker.Find(currentPos, _weapon.range, _weapon.shootDamage); if (_target != null) { return(currentPos); } _target = MonsterTracker.Find(currentPos, CALL_RAD, _weapon.shootDamage); if (_target != null) { var ranged = _weapon.range - 5; if (ranged < 0) { ranged = 1; } position = new Vector3Int(_target.Position).Add(ranged, 0, ranged); position = AIManager.ClosestPosition(position, currentPos); if (!AIManager.CanStandAt(position)) { _tmpVals.Set(COOLDOWN_KEY, _weapon.cooldownMissingItem); _waitingFor++; } else { return(position); } } else { _tmpVals.Set(COOLDOWN_KEY, _weapon.cooldownMissingItem); _waitingFor++; } } if (_waitingFor > 10) { var banner = BannerTracker.GetClosest(usedNPC.Colony.Owner, currentPos); if (banner != null) { return(banner.KeyLocation); } } return(currentPos); }
public static bool OnTryChangeBlockUser(ModLoader.OnTryChangeBlockUserData userData) { Players.Player requestedBy = userData.requestedBy; Vector3Int position = userData.VoxelToChange; Vector3Int spawn = TerrainGenerator.GetSpawnLocation(); int ox = position.x - spawn.x; int oz = position.z - spawn.z; if (((ox >= 0 && ox <= SpawnProtectionRangeXPos) || (ox < 0 && ox >= -SpawnProtectionRangeXNeg)) && ((oz >= 0 && oz <= SpawnProtectionRangeZPos) || (oz < 0 && oz >= -SpawnProtectionRangeZNeg))) { if (!PermissionsManager.HasPermission(requestedBy, PERMISSION_SPAWN_CHANGE)) { Chat.Send(requestedBy, "<color=red>You don't have permission to change the spawn area!</color>"); // TODO add counter and report to admins or auto-kick return(false); } } else { Banner homeBanner = BannerTracker.Get(requestedBy); if (homeBanner != null) { Vector3Int homeBannerLocation = homeBanner.KeyLocation; if (System.Math.Abs(homeBannerLocation.x - position.x) <= BannerProtectionRangeX && System.Math.Abs(homeBannerLocation.z - position.z) <= BannerProtectionRangeZ) { return(true); } } int checkRangeX = BannerProtectionRangeX; int checkRangeZ = BannerProtectionRangeZ; if (userData.typeToBuild == BlockTypes.Builtin.BuiltinBlocks.Banner) { checkRangeX *= 2; checkRangeZ *= 2; } foreach (Banner b in BannerTracker.GetBanners()) { Vector3Int bannerLocation = b.KeyLocation; if (System.Math.Abs(bannerLocation.x - position.x) <= checkRangeX && System.Math.Abs(bannerLocation.z - position.z) <= checkRangeZ) { if (b.Owner != requestedBy && !PermissionsManager.HasPermission(requestedBy, PERMISSION_BANNER_PREFIX + b.Owner.ID.steamID)) { Chat.Send(requestedBy, "<color=red>You don't have permission to change this area!</color>"); return(false); } break; } } } return(true); }
public static void AfterNetworkSetup() { new Thread(() => { Thread.CurrentThread.IsBackground = true; Log.Write("Started kingdom spawner thread"); while (true) { Thread.Sleep(DelayBetweenPlacingAttempts); try { if (KingdomsTracker.Count < MaxNumberOfKingdoms) { for (int c = 0; c < NumOfSpotsToCheckPerAttempt; c++) { var kingdomPosition = GetRandomSpot(MaxRangeFromSpawn); var farmSize = 1 + Pipliz.Random.Next(NpcFarmBuilder.MAX_SIZE); var npcKingdom = NpcFarm.Create(kingdomPosition, farmSize); var closestBanner = BannerTracker.GetClosest(kingdomPosition, MinDistanceToBanners); if (closestBanner == null) { LoadChunksBlocking(npcKingdom.GetPrimaryChunkPositions()); if (npcKingdom.IsAreaClear()) { LoadChunksBlocking(npcKingdom.GetTotalChunkPositions()); npcKingdom.InitNew(); if (KingdomsTracker.Count >= MaxNumberOfKingdoms) { Log.Write($"Reached maximum number ({MaxNumberOfKingdoms}) of kingdoms"); } break; } try { currentlyUsedChunksLock.EnterWriteLock(); currentlyUsedChunks.Clear(); } finally { if (currentlyUsedChunksLock.IsWriteLockHeld) { currentlyUsedChunksLock.ExitWriteLock(); } } } Thread.Sleep(DelayBetweenSpotChecks); } } } catch (Exception exception) { Log.WriteError($"Exception in kingdom update thread; {exception.Message}"); } } }).Start(); }
protected override bool RunCommand(Players.Player ply, string[] args, NetworkID target) { if (PermissionsManager.CheckAndWarnPermission(ply, "locate")) { var player = Players.GetPlayer(target); var banner = (from b in BannerTracker.GetBanners() where b.Owner == player select b).FirstOrDefault(); Chat.sendSilent(ply, banner != null ? $"{player.Name} has a banner at x:{banner.KeyLocation.x} y:{banner.KeyLocation.y} z:{banner.KeyLocation.z}" : $"{player.Name} doesn't have a banner", Chat.ChatColour.magenta); } return(true); }
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)); } }
public static bool EvaluateSettlers(Players.Player p) { var update = false; if (p.IsConnected) { var colony = Colony.Get(p); var state = PlayerState.GetPlayerState(p); if (state.NextGenTime == 0) { state.NextGenTime = Time.SecondsSinceStartDouble + Random.Next(8, 16 - Pipliz.Math.RoundToInt(p.GetTempValues(true) .GetOrDefault(PandaResearch.GetResearchKey(PandaResearch.TimeBetween), 0f))) * TimeCycle .SecondsPerHour; } if (Time.SecondsSinceStartDouble > state.NextGenTime && colony.FollowerCount >= MAX_BUYABLE) { var chance = p.GetTempValues(true) .GetOrDefault(PandaResearch.GetResearchKey(PandaResearch.SettlerChance), 0f) + state.Difficulty.AdditionalChance; chance += SettlerEvaluation.SpawnChance(p, colony, state); var rand = Random.NextFloat(); if (chance > rand) { var addCount = Math.Floor(state.MaxPerSpawn * chance); // if we lost alot of colonists add extra to help build back up. if (colony.FollowerCount < state.HighestColonistCount) { var diff = state.HighestColonistCount - colony.FollowerCount; addCount += Math.Floor(diff * .25); } try { var skillChance = p.GetTempValues(true) .GetOrDefault(PandaResearch.GetResearchKey(PandaResearch.SkilledLaborer), 0f); var numbSkilled = 0; rand = Random.NextFloat(); try { if (skillChance > rand) { numbSkilled = state.Rand.Next(1, 2 + Pipliz.Math.RoundToInt(p.GetTempValues(true) .GetOrDefault(PandaResearch.GetResearchKey(PandaResearch.NumberSkilledLaborer), 0f))); } } catch (Exception ex) { PandaLogger.Log("NumberSkilledLaborer"); PandaLogger.LogError(ex); } if (addCount > 0) { if (addCount > 30) { addCount = 30; } var reason = string.Format(SettlerReasoning.GetSettleReason(), addCount); if (numbSkilled > 0) { if (numbSkilled == 1) { reason += string.Format(" {0} of them is skilled!", numbSkilled); } else { reason += string.Format(" {0} of them are skilled!", numbSkilled); } } PandaChat.Send(p, reason, ChatColor.magenta); var playerPos = new Vector3Int(p.Position); for (var i = 0; i < addCount; i++) { var newGuy = new NPCBase(NPCType.GetByKeyNameOrDefault("pipliz.laborer"), BannerTracker.GetClosest(p, playerPos).KeyLocation.Vector, colony); SettlerInventory.GetSettlerInventory(newGuy); newGuy.GetTempValues().Set(ISSETTLER, true); if (i <= numbSkilled) { var npcTemp = newGuy.GetTempValues(true); npcTemp.Set(GameLoader.ALL_SKILLS, state.Rand.Next(1, 10) * 0.002f); } update = true; ModLoader.TriggerCallbacks(ModLoader.EModCallbackType.OnNPCRecruited, newGuy); } } } catch (Exception ex) { PandaLogger.Log("SkilledLaborer"); PandaLogger.LogError(ex); } if (colony.FollowerCount > state.HighestColonistCount) { state.HighestColonistCount = colony.FollowerCount; } } state.NextGenTime = Time.SecondsSinceStartDouble + Random.Next(8, 16 - Pipliz.Math.RoundToInt(p.GetTempValues(true) .GetOrDefault(PandaResearch.GetResearchKey(PandaResearch.TimeBetween), 0f))) * TimeCycle .SecondsPerHour; colony.SendUpdate(); } } return(update); }
public static MonsterSpawner.ESpawnResult TryGetSpawnLocation(Banner primaryBanner, float maxSpawnWalkDistance, out Vector3Int positionFinal) { Vector3Int bannerPos = primaryBanner.KeyLocation; var bannerList = BannerTracker.GetBanners(); int safeRadius = primaryBanner.SafeRadius; int spawnRadius = Pipliz.Math.RoundToInt(Pipliz.Math.Min(maxSpawnWalkDistance, primaryBanner.MaxSpawnRadius)); positionFinal = Vector3Int.invalidPos; for (int spawnTry = 0; spawnTry < MAX_TRIES; spawnTry++) { Vector3Int possiblePosition; Vector3Int dif; while (true) { possiblePosition.x = bannerPos.x + Pipliz.Random.Next(-spawnRadius, spawnRadius); possiblePosition.z = bannerPos.z + Pipliz.Random.Next(-spawnRadius, spawnRadius); possiblePosition.y = Pipliz.Math.RoundToInt(TerrainGenerator.UsedGenerator.GetHeight(possiblePosition.x, possiblePosition.z)); dif = bannerPos - possiblePosition; if (dif.MaxPartAbs > safeRadius && Pipliz.Math.Abs(dif.x) + Pipliz.Math.Abs(dif.z) < spawnRadius) { break; } } for (int idxBanner = 0; idxBanner < bannerList.Count; idxBanner++) { var otherBanner = bannerList.GetValueAtIndex(idxBanner); Colony otherColony = Colony.Get(otherBanner.Owner); if (otherColony.FollowerCount > 0 && (otherBanner.KeyLocation - possiblePosition).MaxPartAbs <= otherBanner.SafeRadius) { goto NEXT_TRY; } } if (!AIManager.Loaded(possiblePosition)) { return(MonsterSpawner.ESpawnResult.NotLoaded); } for (int idxOffset = 0; idxOffset < offsets.Length; idxOffset++) { Vector3Int positionAITest = possiblePosition.Add(0, offsets[idxOffset], 0); if (AIManager.CanStandAt(positionAITest)) { positionFinal = positionAITest; return(MonsterSpawner.ESpawnResult.Success); } } NEXT_TRY: continue; } return(MonsterSpawner.ESpawnResult.Fail); }
private ITrackableBlock GetScoutBanner() { return(BannerTracker.Get(GetColonyOwner())); }
public override void OnNPCAtJob(ref NPCBase.NPCState state) { state.SetCooldown(2); getScoutChunkManager().RemoveDoublePositions(); if (Activity == ScoutActivity.Scouting) { getScoutChunkManager().RegisterPositionScouted(currentDestination.ToChunk()); } if (Activity == ScoutActivity.Walking) { SetActivity(ScoutActivity.Scouting); Vector3Int positionToScout = NPC.Position; getScoutChunkManager().RegisterPositionScouted(positionToScout); state.SetCooldown(2); } //WriteLog("OnNPCAtJob"); if (!StockedUp) { StockedUp = true; SetActivity(ScoutActivity.Scouting); } var commenceBaseBuild = false; if (!IsOutsideMinimumRange(NPC.Position, BannerTracker.Get(GetColonyOwner()))) { return; } //Check the surrounding area and calculate its average flatness, to determine if it's suitable for a base var suitability = calculateAreaSuitability(); switch (suitability) { case Suitability.None: break; case Suitability.Bad: break; case Suitability.Decent: break; case Suitability.Good: WriteLog("Suitable location found for new base."); commenceBaseBuild = true; break; case Suitability.Excellent: break; default: Log.WriteWarning("Invalid Area Suitability received: {0}", suitability); break; } //Only actually build base if the area is suitable enough if (commenceBaseBuild) { PrepareBase(); } }
protected override void ReconsiderDecision() { switch (decision.GoalType) { case ZombieGoal.Banner: if ((!decision.IsValid || decision.PathDistance > MinDistanceToReconsiderBanner) && (ConsiderPlayerTarget(ref decision) || ConsiderNPCTarget(ref decision))) { return; } if (!BannerTracker.Contains(decision.GoalLocation)) { var closest = BannerTracker.GetClosest(originalGoal, position); if (closest != null && AIManager.ZombiePathFinder.TryFindPath(position, closest.KeyLocation, out var path, 2000000000) == EPathFindingResult.Success) { decision.Clear(); decision = new ZombieDecision(this, path); return; } SetCooldown(3.0); } break; case ZombieGoal.NPC: if (!decision.IsValid || decision.PathDistance > MinDistanceToReconsiderNPC) { if (ConsiderPlayerTarget(ref decision)) { return; } NPCBase nPCBase; if (NPCTracker.TryGetNear(position.Vector, MaxRadiusToNPCToConsider, out nPCBase)) { if (decision.IsGoingTo(nPCBase) && IsMovingTargetPathOkay(nPCBase.Position)) { decision.Reconsidered(); return; } if (AIManager.ZombiePathFinder.TryFindPath(position, nPCBase.Position, out var path2, decision.PathDistance / 2) == EPathFindingResult.Success) { decision.Clear(); decision = new ZombieDecision(this, nPCBase, path2); } } if (ConsiderBannerTarget(ref decision)) { return; } } break; case ZombieGoal.Player: if (Players.FindClosestAlive(position.Vector, out var player, out var num)) { if (decision.IsGoingTo(player) && IsMovingTargetPathOkay(player.VoxelPosition)) { decision.Reconsidered(); return; } if (num < MaxSqrdRadiusToPlayerToConsider && AIManager.CanStandAt(player.VoxelPosition) && AIManager.ZombiePathFinder.TryFindPath(position, player.VoxelPosition, out var path3, 2000000000) == EPathFindingResult.Success) { decision.Clear(); decision = new ZombieDecision(this, player, path3); } } if (ConsiderNPCTarget(ref decision) || ConsiderBannerTarget(ref decision)) { return; } break; default: if (ConsiderPlayerTarget(ref decision) || ConsiderNPCTarget(ref decision) || ConsiderBannerTarget(ref decision)) { return; } break; } decision.Reconsidered(); }
public static void EvaluateBanners() { if (!GameLoader.WorldLoaded) { return; } _bannerCounts.Clear(); var banners = BannerTracker.GetCount(); if (banners > 0) { for (var i = 0; i < banners; i++) { if (BannerTracker.TryGetAtIndex(i, out var banner)) { if (!_bannerCounts.ContainsKey(banner.Owner)) { _bannerCounts.Add(banner.Owner, 1); } else { _bannerCounts[banner.Owner]++; } } } } foreach (var p in _bannerCounts) { var ps = PlayerState.GetPlayerState(p.Key); if (ps == null) { continue; } var numberOfBanners = p.Key.GetTempValues(true) .GetOrDefault(PandaResearch.GetLevelKey(PandaResearch.Settlement), 0) + 1; var inv = Inventory.GetInventory(p.Key); var sockBanner = Stockpile.GetStockPile(p.Key).AmountContained(BuiltinBlocks.Banner); var inventoryBanners = 0; if (inv != null) { foreach (var item in inv.Items) { if (item.Type == BuiltinBlocks.Banner) { inventoryBanners = item.Amount; } } } var totalBanners = p.Value + sockBanner + inventoryBanners; #if Debug PandaLogger.Log($"Number of research banners: {numberOfBanners}"); PandaLogger.Log($"Number of banners: {p.Value}"); PandaLogger.Log($"Number of stockpile banners: {sockBanner}"); PandaLogger.Log($"Number of Inventory banners: {inventoryBanners}"); PandaLogger.Log($"Total banners: {totalBanners}"); PandaLogger.Log($"Add Banner: {totalBanners < numberOfBanners}"); #endif if (totalBanners < numberOfBanners) { if (!Inventory.GetInventory(p.Key).TryAdd(BuiltinBlocks.Banner)) { Stockpile.GetStockPile(p.Key).Add(BuiltinBlocks.Banner); } } } }
public static void OnUpdate() { if (!World.Initialized || AIManager.IsBusy()) { return; } var secondsSinceStartDouble = Time.SecondsSinceStartDouble; if (_nextUpdateTime < secondsSinceStartDouble) { IMonster m = null; foreach (var monster in GetAllMonsters()) { if (m == null || Vector3.Distance(monster.Value.Position, m.Position) > 15 && Random.NextBool()) { m = monster.Value; ServerManager.SendAudio(monster.Value.Position, GameLoader.NAMESPACE + ".ZombieAudio"); } } _nextUpdateTime = secondsSinceStartDouble + 5; } IPandaBoss bossType = null; if (World.Initialized && !AIManager.IsBusy()) { if (!BossActive && _nextBossUpdateTime <= secondsSinceStartDouble) { BossActive = true; bossType = GetMonsterType(); if (Players.CountConnected != 0) { PandaLogger.Log(ChatColor.yellow, $"Boss Active! Boss is: {bossType.Name}"); } } if (BossActive) { var turnOffBoss = true; var worldSettings = ServerManager.WorldSettings; Dictionary <PlayerState, List <Banner> > banners = new Dictionary <PlayerState, List <Banner> >(); var spawnBanners = new List <Banner>(); for (var i = 0; i < BannerTracker.GetCount(); i++) { if (BannerTracker.TryGetAtIndex(i, out var newBanner)) { var bps = PlayerState.GetPlayerState(newBanner.Owner); if (!banners.ContainsKey(bps)) { banners.Add(bps, new List <Banner>()); } banners[bps].Add(newBanner); } } foreach (var bkvp in banners) { if (bkvp.Value.Count > 1) { var next = Pipliz.Random.Next(bkvp.Value.Count); spawnBanners.Add(bkvp.Value[next]); } else if (bkvp.Value.Count == 1) { spawnBanners.Add(bkvp.Value[0]); } } foreach (var bannerGoal in spawnBanners) { var ps = PlayerState.GetPlayerState(bannerGoal.Owner); var colony = Colony.Get(ps.Player); if (ps.BossesEnabled && ps.Player.IsConnected && colony.FollowerCount > Configuration.GetorDefault("MinColonistsCountForBosses", 15)) { if (bossType != null && !_spawnedBosses.ContainsKey(ps)) { Vector3Int positionFinal; switch (MonsterSpawner.TryGetSpawnLocation(bannerGoal, 500f, out positionFinal)) { case MonsterSpawner.ESpawnResult.Success: if (AIManager.ZombiePathFinder.TryFindPath(positionFinal, bannerGoal.KeyLocation, out var path, 2000000000) == EPathFindingResult.Success) { var pandaboss = bossType.GetNewBoss(path, ps.Player); _spawnedBosses.Add(ps, pandaboss); BossSpawned?.Invoke(MonsterTracker.MonsterSpawner, new BossSpawnedEvent(ps, pandaboss)); ModLoader.TriggerCallbacks <IMonster>(ModLoader.EModCallbackType.OnMonsterSpawned, pandaboss); MonsterTracker.Add(pandaboss); colony.OnZombieSpawn(true); ps.FaiedBossSpawns = 0; PandaChat.Send(ps.Player, $"[{pandaboss.Name}] {pandaboss.AnnouncementText}", ChatColor.red); if (!string.IsNullOrEmpty(pandaboss.AnnouncementAudio)) { ServerManager.SendAudio(ps.Player.Position, pandaboss.AnnouncementAudio); } } break; case MonsterSpawner.ESpawnResult.NotLoaded: case MonsterSpawner.ESpawnResult.Impossible: colony.OnZombieSpawn(true); break; case MonsterSpawner.ESpawnResult.Fail: CantSpawnBoss(ps, colony); break; } if (_spawnedBosses.ContainsKey(ps) && _spawnedBosses[ps].IsValid && _spawnedBosses[ps].CurrentHealth > 0) { if (ps.Player.GetTempValues(true).GetOrDefault("BossIndicator", 0) < Time.SecondsSinceStartInt) { Indicator.SendIconIndicatorNear(new Vector3Int(_spawnedBosses[ps].Position), _spawnedBosses[ps].ID, new IndicatorState(1, GameLoader.Poisoned_Icon, false, false)); ps.Player.GetTempValues(true) .Set("BossIndicator", Time.SecondsSinceStartInt + 1); } turnOffBoss = false; } } } if (turnOffBoss) { if (Players.CountConnected != 0 && _spawnedBosses.Count != 0) { PandaLogger.Log(ChatColor.yellow, $"All bosses cleared!"); var boss = _spawnedBosses.FirstOrDefault().Value; PandaChat.SendToAll($"[{boss.Name}] {boss.DeathText}", ChatColor.red); } BossActive = false; _spawnedBosses.Clear(); GetNextBossSpawnTime(); } } } } }