Ejemplo n.º 1
0
        private StringBuilder GetOnlineInfo(ShPlayer target)
        {
            var sb = new StringBuilder();

            sb
            .Append("ID: ").AppendLine(target.ID.ToString())
            .Append("SteamID64: ").AppendLine(target.steamID.ToString())
            .Append("Username: "******" (Sanitized)")
            .Append("Health: ").AppendLine(target.health.ToString())
            .Append("BankBalance: ").AppendLine(target.svPlayer.bankBalance.ToString())
            .Append("Position: ").AppendLine(target.GetPosition().ToString())
            .Append("Rotation: ").AppendLine(target.GetRotation().ToString())
            .Append("Stats: ").AppendLine(string.Join("\n    - ", target.stats))
            .Append("Expecting more info? Type '/info ").Append(target.steamID.ToString()).AppendLine("'.");
            return(sb);
        }
Ejemplo n.º 2
0
 public void OnCommandInvoke(ShPlayer player, string Skin, ShPlayer target = null)
 {
     if (target != player && !player.svPlayer.HasPermission(Core.Instance.Info.GroupNamespace + ".changeothersskin"))
     {
         player.svPlayer.Send(SvSendType.Self, Channel.Unsequenced, ClPacket.GameMessage, "You can only change your skin");
         return;
     }
     target = target ?? player;
     if (player.manager.skinPrefabs.FirstOrDefault(x => x.name.ToLower() == Skin.ToLower()) == null)
     {
         player.svPlayer.Send(SvSendType.Self, Channel.Unsequenced, ClPacket.GameMessage, "Skin not found");
         return;
     }
     target.GetExtendedPlayerPs().Skin = player.manager.skinPrefabs.FirstOrDefault(x => x.name.ToLower() == Skin.ToLower()).name;
     target.svPlayer.Send(SvSendType.Self, Channel.Unsequenced, ClPacket.GameMessage, "Reconnect to apply new skin.");
 }
Ejemplo n.º 3
0
        public void OnJailCriminal(ShPlayer player, ShPlayer criminal)
        {
            if (player.svPlayer.job.info.shared.groupIndex == GroupIndex.LawEnforcement)
            {
                int fine = criminal.svPlayer.SvGoToJail();

                if (fine > 0)
                {
                    player.svPlayer.job.OnJailCriminal(criminal, fine);
                }
                else
                {
                    player.svPlayer.SendGameMessage("Confirm criminal is cuffed and has crimes");
                }
            }
        }
Ejemplo n.º 4
0
 public void Invoke(ShPlayer player, ShPlayer target = null)
 {
     target = target ?? player;
     if (target.svPlayer.job.info.upgrades.Length == 0) // Check if Target's Job even has Ranks
     {
         player.TS("promoted_no_ranks", target.username.CleanerMessage());
         return;
     }
     if (target.rank == target.svPlayer.job.info.upgrades.Length - 1) // Check if Target is max rank
     {
         player.TS("promoted_max_rank", target.username.CleanerMessage());
         return;
     }
     target.svPlayer.Reward(Util.maxExperience - target.experience + 1, 0);
     player.TS("promoted", target.username.CleanerMessage(), (target.rank + 1).ToString());
 }
Ejemplo n.º 5
0
        public void OnDisplayName(ShPlayer player, string username)
        {
            player.username = username;

            if (player.isHuman)
            {
                player.svPlayer.tagname = player.svPlayer.PrimaryGroup?.Tag ?? string.Empty;
            }
            else
            {
                player.svPlayer.tagname = string.Empty;
            }

            // &f to reset back to white after any tag colors
            player.displayName = $"{player.svPlayer.tagname}&f{player.username}";
        }
Ejemplo n.º 6
0
        public static bool Run(ShPlayer shPlayer, float time)
        {
            if (shPlayer.IsDead())
            {
                return(false);
            }
            var jailSpawn = shPlayer.manager.jail.transform;

            shPlayer.svPlayer.SvSetJob(shPlayer.jobs[2], true, false);
            shPlayer.svPlayer.ResetAndSavePosition(jailSpawn.position, jailSpawn.rotation, 0);
            shPlayer.StartCoroutine(shPlayer.svPlayer.JailTimer(time));
            shPlayer.svPlayer.SvClearCrimes();
            shPlayer.RemoveItemsJail();
            shPlayer.svPlayer.Send(SvSendType.Self, Channel.Reliable, ClPacket.ShowTimer, time);
            return(true);
        }
Ejemplo n.º 7
0
        public void RequestAdd(int sourceID, string itemName)
        {
            if (!requestItems.Contains(itemName))
            {
                Debug.LogError("[SVR] Item not valid: " + itemName);
                return;
            }

            ShItem item = SceneManager.Instance.GetEntity <ShItem>(itemName);

            if (!item)
            {
                Debug.LogError("[SVR] Item not found: " + itemName);
                return;
            }

            ShPlayer requester = EntityCollections.FindByID <ShPlayer>(sourceID);

            if (!requester)
            {
                Debug.LogError("[SVR] Requester not found");
                return;
            }

            if (requester.HasItem(item.index))
            {
                requester.svPlayer.SendGameMessage("Already own item");
            }
            else if (requester.MyMoneyCount < item.value)
            {
                requester.svPlayer.SendGameMessage("Not enough money");
            }
            else if (requests.ContainsKey(requester.username))
            {
                requester.svPlayer.SendGameMessage("Previous request still pending");
            }
            else
            {
                requests[requester.username] = itemName;
                requester.svPlayer.SendGameMessage("Request successfully sent");
                ShPlayer mayor = info.members.FirstOrDefault();
                if (mayor)
                {
                    mayor.svPlayer.SendGameMessage(requester.username + " requesting a " + item.itemName);
                }
            }
        }
Ejemplo n.º 8
0
 public void Invoke(ShPlayer player, ShPlayer target, int amount = 1)
 {
     if (amount <= 0)
     {
         player.TS("pay_error_negative");
         return;
     }
     if (player.MyMoneyCount < amount)
     {
         player.TS("you_dont_own", amount.ToString());
         return;
     }
     player.TransferMoney(DeltaInv.RemoveFromMe, amount, true);
     target.TransferMoney(DeltaInv.AddToMe, amount, true);
     player.TS("paid_to", amount.ToString(), target.username);
     target.TS("received_from", amount.ToString(), player.username);
 }
Ejemplo n.º 9
0
        public static string FormatMessage(ShPlayer player, string message)
        {
            var formatGroup = player.svPlayer.Groups.FirstOrDefault(group => group.CustomData.Data.ContainsKey("bpe:format"));

            if (formatGroup != null && formatGroup.CustomData.TryFetchCustomData("bpe:format", out string formatter))
            {
                try
                {
                    return(string.Format(new CustomFormatter(), formatter.ParseColorCodes(), player.ID, player.username.SanitizeString(), message));
                }
                catch (Exception err)
                {
                    Core.Instance.Logger.LogException(err);
                }
            }
            return($"{player.username}: {message.SanitizeString()}");
        }
Ejemplo n.º 10
0
        public override void OnEmployeeAction(ShPlayer target, string actionID)
        {
            List <LabelID> options = new List <LabelID>();

            foreach (string s in requestItems)
            {
                ShItem item = SceneManager.Instance.GetEntity <ShItem>(s.GetPrefabIndex());

                if (item)
                {
                    options.Add(new LabelID(item.itemName + ": $" + item.value, s));
                }
            }

            // Negative playerID means job action is called on the employer with that ID, not self
            target.svPlayer.SendOptionMenu("Items", -player.ID, itemMenu, options.ToArray(), new LabelID[] { new LabelID("Request", string.Empty) });
        }
Ejemplo n.º 11
0
        public void Invoke(ShPlayer player, ShPlayer target, int warnId)
        {
            if (warnId < 1)
            {
                player.TS("warn_remove_error_null_or_negative", warnId.ToString());
                return;
            }
            var warns = target.GetWarns();

            if (warns.Count < warnId)
            {
                player.TS("warn_remove_error_notExistant", warnId.ToString());
                return;
            }
            player.TS("player_warn_removed", warns[warnId - 1].ToString(player));
            target.RemoveWarn(warnId - 1);
        }
Ejemplo n.º 12
0
        public static string FormatMessage(ShPlayer player, string message, string formatKey = "format")
        {
            var formatGroup = player.svPlayer.Groups.FirstOrDefault(group => group.Value.CustomData.Data.ContainsKey($"{Core.Instance.Info.GroupNamespace}:{formatKey}"));

            if (formatGroup.Value != null && formatGroup.Value.CustomData.TryFetchCustomData($"{Core.Instance.Info.GroupNamespace}:{formatKey}", out string formatter))
            {
                try
                {
                    return(string.Format(new CustomFormatter(), formatter, player.ID, player.username, message));
                }
                catch (Exception err)
                {
                    Core.Instance.Logger.LogException(err);
                }
            }
            return($"{player.username}: {message.CleanerMessage()}");
        }
Ejemplo n.º 13
0
        public void OnLocalChatMessage(ShPlayer player, string message)
        {
            if (player.manager.svManager.chatted.OverLimit(player))
            {
                return;
            }

            message = message.CleanMessage();
            Debug.Log($"[CHAT] {player.username}:{message}");

            if (CommandHandler.OnEvent(player, message)) // 'true' if message starts with command prefix
            {
                return;
            }

            player.manager.svManager.chatted.Add(player);
            player.svPlayer.Send(SvSendType.LocalOthers, Channel.Unsequenced, ClPacket.LocalChatMessage, player.ID, message);
        }
Ejemplo n.º 14
0
        public void Invoke(ShPlayer player, string message)
        {
            var ePlayer = player.GetExtendedPlayer();

            if (ePlayer.ReplyToUser == null)
            {
                player.TS("no_user_found_or_offline");
                return;
            }
            var eTarget = ePlayer.ReplyToUser.GetExtendedPlayer();

            if (eTarget.CurrentChat == Chat.Disabled)
            {
                player.SendChatMessage($"{player.T("user_has_chat_disabled")} {player.T("message_not_sent")}");
                return;
            }
            player.GetExtendedPlayer().SendPmMessage(eTarget, message);
        }
Ejemplo n.º 15
0
        public void Invoke(ShPlayer player, string targetStr)
        {
            StringBuilder sb;

            if (EntityCollections.TryGetPlayerByNameOrId(targetStr, out ShPlayer target))
            {
                sb = GetOnlineInfo(target);
            }
            else
            {
                sb = GetOfflineInfo(player, targetStr);
            }
            if (sb == null)
            {
                return;
            }

            // TODO: send as server info or CEF (pref server info to limit footprint)
        }
Ejemplo n.º 16
0
        public override void OnEmployeeAction(ShPlayer target, string actionID)
        {
            List <LabelID> options = new List <LabelID>();

            foreach (ShPlayer p in EntityCollections.Humans)
            {
                if (bounties.TryGetValue(p.username, out var bountyTime))
                {
                    options.Add(new LabelID($"{p.username}: {bountyLimitHours - (Util.CurrentTime - bountyTime).Hours} Hours", p.username));
                }
                else
                {
                    options.Add(new LabelID($"{p.username}:  Available", p.username));
                }
            }

            // Negative playerID means job action is called on the employer with that ID, not self
            target.svPlayer.SendOptionMenu("Players", -player.ID, playersMenu, options.ToArray(), new LabelID[] { new LabelID($"Place Bounty ${placeCost}", place), new LabelID($"Cancel Bounty ${cancelCost}", cancel) });
        }
Ejemplo n.º 17
0
        public void Invoke(ShPlayer player, string warp)
        {
            var obj = Core.Instance.WarpHandler.List.FirstOrDefault(x => x.Name == warp);

            if (obj == null)
            {
                player.TS("expFileHandler_error_notFound", player.T(Core.Instance.WarpHandler.Name), warp);
                return;
            }
            if (!player.svPlayer.HasPermission($"{Core.Instance.Info.GroupNamespace}.{Core.Instance.WarpHandler.Name}.{warp}"))
            {
                player.TS("expFileHandler_error_noPermission", player.T(Core.Instance.WarpHandler.Name), warp);
                return;
            }
            if (obj.Disabled)
            {
                player.TS("expFileHandler_error_disabled", player.T(Core.Instance.WarpHandler.Name), warp);
                return;
            }
            if (player.HasCooldown(Core.Instance.WarpHandler.Name, warp))
            {
                player.TS("expFileHandler_error_cooldown", player.T(Core.Instance.WarpHandler.Name), player.GetCooldown(Core.Instance.WarpHandler.Name, warp).ToString());
                return;
            }
            if (obj.Price > 0)
            {
                if (player.MyMoneyCount() < obj.Price)
                {
                    player.TS("expFileHandler_error_price", player.T(Core.Instance.WarpHandler.Name), obj.Price.ToString(), player.MyMoneyCount().ToString());
                    return;
                }
                player.TransferMoney(DeltaInv.RemoveFromMe, obj.Price, true);
            }
            player.GetExtendedPlayer().ResetAndSavePosition(obj.Position.SerializableVector3.ToVector3(), obj.SerializableQuaternion.ToQuaternion(), obj.Position.PlaceIndex);
            if (obj.Delay > 0)
            {
                player.AddCooldown(Core.Instance.WarpHandler.Name, warp, obj.Delay);
            }
            player.SendChatMessage(
                player.T(Core.Instance.WarpHandler.Name + "_teleported", warp) +
                (obj.Price > 0 ? player.T(Core.Instance.WarpHandler.Name + "_telported_Price", obj.Price.ToString()) : "") +
                (obj.Delay > 0 ? player.T(Core.Instance.WarpHandler.Name + "_telported_Delay", obj.Delay.ToString()) : ""));
        }
Ejemplo n.º 18
0
        public override void ResetJobAI()
        {
            ShPlayer target = player.svPlayer.spawner;

            if (target && target.IsOutside && target.svPlayer.job is Gangster &&
                target.svPlayer.job != this && player.DistanceSqr(target) <= Util.visibleRangeSqr)
            {
                ShTerritory territory = target.svPlayer.GetTerritory;
                if (territory && territory.ownerIndex == info.shared.jobIndex && territory.attackerIndex != Util.InvalidByte)
                {
                    player.svPlayer.targetEntity = target;
                    if (player.svPlayer.SetState(StateIndex.Attack))
                    {
                        return;
                    }
                }
            }
            base.ResetJobAI();
        }
Ejemplo n.º 19
0
        public void Invoke(ShPlayer player, string kit)
        {
            var obj = Core.Instance.KitHandler.List.FirstOrDefault(x => x.Name == kit);

            if (obj == null)
            {
                player.TS("expFileHandler_error_notFound", player.T(Core.Instance.KitHandler.Name), kit);
                return;
            }
            if (!player.svPlayer.HasPermission($"{Core.Instance.Info.GroupNamespace}.{Core.Instance.KitHandler.Name}.{kit}"))
            {
                player.TS("expFileHandler_error_noPermission", player.T(Core.Instance.KitHandler.Name), kit);
                return;
            }
            if (obj.Disabled)
            {
                player.TS("expFileHandler_error_disabled", player.T(Core.Instance.KitHandler.Name), kit);
                return;
            }
            if (player.HasCooldown(Core.Instance.KitHandler.Name, kit))
            {
                player.TS("expFileHandler_error_cooldown", player.T(Core.Instance.KitHandler.Name), player.GetCooldown(Core.Instance.KitHandler.Name, kit).ToString());
                return;
            }
            if (obj.Price > 0)
            {
                if (player.MyMoneyCount() < obj.Price)
                {
                    player.TS("expFileHandler_error_price", player.T(Core.Instance.KitHandler.Name), obj.Price.ToString(), player.MyMoneyCount().ToString());
                    return;
                }
                player.TransferMoney(DeltaInv.RemoveFromMe, obj.Price, true);
            }
            obj.GiveItems(player);
            if (obj.Delay > 0)
            {
                player.AddCooldown(Core.Instance.KitHandler.Name, kit, obj.Delay);
            }
            player.SendChatMessage(
                player.T(Core.Instance.KitHandler.Name + "_received", kit) +
                (obj.Price > 0 ? player.T(Core.Instance.KitHandler.Name + "_received_Price", obj.Price.ToString()) : "") +
                (obj.Delay > 0 ? player.T(Core.Instance.KitHandler.Name + "_received_Delay", obj.Delay.ToString()) : ""));
        }
Ejemplo n.º 20
0
        public void ButtonPush(ShEntity target, ShPlayer caller)
        {
            if (voidRunning)
            {
                caller.svPlayer.SendGameMessage("Do not challenge the void");
                return;
            }

            const int cost = 500;

            if (caller.MyMoneyCount < cost)
            {
                caller.svPlayer.SendGameMessage("Not enough cash");
                return;
            }

            caller.TransferMoney(DeltaInv.RemoveFromMe, cost);

            target.StartCoroutine(EnterTheVoid(target.svEntity.svManager));
        }
Ejemplo n.º 21
0
        public void OnRespawn(ShPlayer player)
        {
            if (player.isHuman)
            {
                var newSpawn = player.svPlayer.svManager.spawnLocations.GetRandom().transform;
                player.svPlayer.originalPosition = newSpawn.position;
                player.svPlayer.originalRotation = newSpawn.rotation;
                player.svPlayer.originalParent   = newSpawn.parent;
            }

            base.OnRespawn(player);

            if (player.isHuman)
            {
                // Back to spectate self on Respawn
                player.svPlayer.SvSpectate(player);
            }

            player.svPlayer.SvForceEquipable(player.manager.hands.index);
        }
Ejemplo n.º 22
0
Archivo: Info.cs Proyecto: ggggg/Core
        public void Invoke(ShPlayer player, string targetStr)
        {
            StringBuilder sb;
            var           target = Core.Instance.SvManager.database.Users.FindById(targetStr);

            if (target != null)
            {
                sb = GetOfflineInfo(target);
            }
            else if (EntityCollections.TryGetPlayerByNameOrID(targetStr, out ShPlayer shPlayer))
            {
                sb = GetOnlineInfo(shPlayer);
            }
            else
            {
                player.SendChatMessage($"No account found with the id '{targetStr}'.");
                return;
            }
            player.svPlayer.Send(SvSendType.Self, Channel.Reliable, ClPacket.ServerInfo, sb.ToString());
        }
Ejemplo n.º 23
0
        public void Invoke(ShPlayer player, string text = "")
        {
            var ePlayer = player.GetExtendedPlayer();

            if (string.IsNullOrWhiteSpace(text))
            {
                if (ePlayer.CurrentChat == Enums.Chat.StaffChat)
                {
                    ePlayer.CurrentChat = Enums.Chat.Global;
                    player.TS("staff_chat_disabled");
                }
                else
                {
                    ePlayer.CurrentChat = Enums.Chat.StaffChat;
                    player.TS("staff_chat_enabled");
                }
                return;
            }
            ChatUtils.SendStaffChatMessage(player, text);
        }
Ejemplo n.º 24
0
        public void OnAcceptRequest(ShPlayer player, ShPlayer requester)
        {
            var requestItem = player.RequestGet(requester);

            if (requestItem == null)
            {
                return;
            }

            if (!requester.svPlayer.BuyRequestItem(requestItem))
            {
                requester.svPlayer.Send(SvSendType.Self, Channel.Unsequenced, ClPacket.GameMessage, "No funds for license");
            }
            else
            {
                player.TransferMoney(DeltaInv.AddToMe, requestItem.item.value, true);
            }

            player.RequestRemove(requester);
        }
Ejemplo n.º 25
0
        protected void OnRemoveItemsDeath(ShPlayer player)
        {
            // -- BPE EXTEND
            if (BPEssentials.Core.Instance.Settings.General.KeepAllItemsOnDeath)
            {
                return;
            }
            // BPE EXTEND --

            // Allows players to keep items/rewards from job ranks
            foreach (InventoryItem myItem in player.myItems.Values.ToArray())
            {
                // -- BPE EXTEND
                if (BPEssentials.Core.Instance.Settings.General.KeptItemsOnDeath.Contains(myItem.item.index))
                {
                    continue;
                }
                // BPE EXTEND --

                int extra = myItem.count;
                if (player.job.info.rankItems.Length > player.rank)
                {
                    for (int rankIndex = player.rank; rankIndex >= 0; rankIndex--)
                    {
                        foreach (InventoryItem i in player.job.info.rankItems[rankIndex].items)
                        {
                            if (myItem.item.index == i.item.index)
                            {
                                extra = Mathf.Max(0, myItem.count - i.count);
                            }
                        }
                    }
                }

                // Remove everything except legal items currently worn
                if (extra > 0 && (myItem.item.illegal || !(myItem.item is ShWearable w) || player.curWearables[(int)w.type].index != w.index))
                {
                    player.TransferItem(DeltaInv.RemoveFromMe, myItem.item.index, extra, true);
                }
            }
        }
Ejemplo n.º 26
0
        public void OnEnterDoor(ShPlayer player, ShDoor door, ShPlayer sender, bool forceEnter)
        {
            if (!forceEnter)
            {
                if (player.IsRestrained)
                {
                    player.svPlayer.SendGameMessage("You are restrained");
                    return;
                }

                if (door.svDoor.key && !player.HasItem(door.svDoor.key))
                {
                    player.svPlayer.SendGameMessage("Need " + door.svDoor.key.itemName + " to enter");
                    return;
                }

                if (!player.InActionRange(door))
                {
                    return;
                }
            }

            ShMountable baseEntity;

            if (player.curMount is ShPlayer mountPlayer)
            {
                baseEntity = mountPlayer;
            }
            else
            {
                baseEntity = player;
                if (player.curMount)
                {
                    player.svPlayer.SvDismount();
                }
            }

            if (door is ShApartment apartment && sender.ownedApartments.TryGetValue(apartment, out var place))
            {
                baseEntity.svMountable.SvRelocate(place.mainDoor.spawnPoint, place.mTransform);
            }
Ejemplo n.º 27
0
        public void OnSellApartment(ShPlayer player, ShApartment apartment)
        {
            if (!Utility.trySell.Limit(player))
            {
                player.svPlayer.SendGameMessage("Are you sure? Sell again to confirm..");
                return;
            }

            if (player.ownedApartments.TryGetValue(apartment, out var place))
            {
                if (player.GetPlace == place)
                {
                    player.svPlayer.SvEnterDoor(place.mainDoor.ID, player, true);
                }

                player.TransferMoney(DeltaInv.AddToMe, apartment.value / 2);

                player.svPlayer.Send(SvSendType.Self, Channel.Reliable, ClPacket.SellApartment, apartment.ID);
                player.svPlayer.CleanupApartment(place);
            }
        }
Ejemplo n.º 28
0
        public void OnEvent(ShPlayer player)
        {
            if (player.GetExtendedPlayerPs().Skin != null)
            {
                int skin = MonoBehaviourSingleton <SceneManager> .Instance.entityCollection.FirstOrDefault(x => x.Value.name == player.GetExtendedPlayerPs().Skin).Key;

                Core.Instance.Logger.Log(skin.ToString());
                string accId = player.username;
                Core.Instance.PlayerHandler.Remove(player.ID);
                Core.Instance.SvManager.StartCoroutine(MethodTimer(2, delegate()
                {
                    Core.Instance.SvManager.TryGetUserData(accId, out var user);
                    user.Character.SkinIndex = skin;
                    Core.Instance.SvManager.database.Users.Upsert(user);
                }));
            }
            else
            {
                Core.Instance.PlayerHandler.Remove(player.ID);
            }
        }
Ejemplo n.º 29
0
        public void Invoke(ShPlayer player, string kit, int price = 0, int delay = 0)
        {
            if (delay < 0)
            {
                player.TS("delay_error_negative");
                return;
            }
            if (price < 0)
            {
                price = 0;
                foreach (var item in player.myItems.Values)
                {
                    price += item.count * item.currentValue;
                }
                player.TS("kit_price_automatically_calculated", price);
            }
            var file = Path.Combine(Core.Instance.Paths.KitsFolder, $"{kit}.json");

            if (File.Exists(file))
            {
                player.TS("expFileHandler_create_error_alreadyExists", player.T(Core.Instance.KitHandler.Name), kit);
                return;
            }
            var obj = new KitHandler.JsonModel
            {
                Delay = Math.Max(0, delay),
                Price = Math.Max(0, price),
                Name  = kit,
            };

            foreach (var item in player.myItems.Values)
            {
                obj.Items.Add(new KitHandler.KitsItem {
                    Amount = item.count, Id = item.item.index
                });
            }
            Core.Instance.KitHandler.CreateNew(obj, kit);
            player.TS("kitCreate_created", kit, price.ToString(), delay.ToString());
        }
Ejemplo n.º 30
0
        public void OnSecurityPanel(ShPlayer player, ShApartment apartment)
        {
            List <LabelID> options = new List <LabelID>();

            options.Add(new LabelID("Enter Passcode", enterPasscode));
            options.Add(new LabelID("Set Passcode", setPasscode));
            options.Add(new LabelID("Clear Passcode", clearPasscode));
            options.Add(new LabelID("Hack Panel", hackPanel));

            string title = "&7Security Panel";

            if (player.ownedApartments.TryGetValue(apartment, out var apartmentPlace))
            {
                title += ": Level " + apartmentPlace.svSecurity.ToPercent();
                if (apartmentPlace.svSecurity < securityCutoff)
                {
                    options.Add(new LabelID($"Upgrade Security (Cost: ${SecurityUpgradeCost(apartmentPlace.svSecurity).ToString()})", upgradeSecurity));
                }
            }

            player.svPlayer.SendOptionMenu(title, apartment.ID, securityPanel, options.ToArray(), new LabelID[] { new LabelID("Select", string.Empty) });
        }