Exemple #1
0
        public void TakeLoot(Player plr)
        {
            Character character = CharMgr.GetCharacter(plr.CharacterId, false);

            var bagExists = LootBags.ContainsKey(character.CharacterId);

            if (bagExists)
            {
                var bag = LootBags[character.CharacterId];

                foreach (var talisman in bag.Value)
                {
                    // Adding bag to the player
                    ItemResult result = plr.ItmInterface.CreateItem(bag.Key, 1, bag.Value, 0, 0, false);

                    if (result == ItemResult.RESULT_OK)
                    {
                        LootBags.Remove(plr.CharacterId);
                    }
                    else if (result == ItemResult.RESULT_MAX_BAG)
                    {
                        plr.SendLocalizeString("", ChatLogFilters.CHATLOGFILTERS_LOOT,
                                               Localized_text.TEXT_OVERAGE_CANT_LOOT);
                    }
                }

                //ItemResult result = plr.ItmInterface.CreateItem(bag.Key, 1, items.talisman,
                //    items.primary_dye, items.secondary_dye, false);
            }
        }
Exemple #2
0
        protected override void SetDeath(Unit killer)
        {
            // reset add list
            // AddDictionary = new List<Creature>();

            base.SetDeath(killer);

            if (Instance != null)
            {
                Instance.OnBossDeath(InstanceGroupSpawnId, this);

                // remove barriages from this instance
                Instance.RemoveInstanceObjectOnBossDeath(BossId);
            }

            // handle torch of lileath on horgulul death
            if (this is SimpleHorgulul horgulul)
            {
                foreach (Player plr in horgulul.GetPlayersInRange(300, false))
                {
                    var character = CharMgr.GetCharacter(plr.CharacterId, false);
                    if (character == null)
                    {
                        continue;
                    }
                    if (!CharMgr.GetItemsForCharacter(character).Any(x => x.Entry == 11435))
                    {
                        plr.ItmInterface.CreateItem(11435, 1);
                    }
                }
            }

            EvtInterface.AddEvent(ApplyDelayedLockout, 40000, 1);
        }
Exemple #3
0
        public static bool MailItem(uint characterId, uint itemId, ushort count)
        {
            var character = CharMgr.GetCharacter(characterId, true);

            if (character == null)
            {
                return(false);
            }
            var characterName = character?.Name;

            Character_mail mail = new Character_mail
            {
                Guid              = CharMgr.GenerateMailGuid(),
                CharacterId       = characterId, //CharacterId
                SenderName        = "Ikthaleon",
                ReceiverName      = characterName,
                SendDate          = (uint)TCPManager.GetTimeStamp(),
                Title             = "",
                Content           = "",
                Money             = 0,
                Opened            = false,
                CharacterIdSender = 283
            };

            MailItem item = new MailItem(itemId, count);

            if (item != null)
            {
                mail.Items.Add(item);
                CharMgr.AddMail(mail);
            }

            return(true);
        }
Exemple #4
0
        /// <summary>
        /// Seach a player's inventory by name <name>
        /// </summary>
        /// <param name="plr">Player that initiated the command</param>
        /// <param name="values">List of command arguments (after command name)</param>
        /// <returns>True if command was correctly handled, false if operation was canceled</returns>
        public static bool SearchInventory(Player plr, ref List <string> values)
        {
            var target = plr.CbtInterface.GetCurrentTarget();
            var filter = String.Empty;

            if (target == null)
            {
                plr.SendClientMessage($"SEARCH INVENTORY: No target selected.");
            }
            else
            {
                var character = CharMgr.GetCharacter((target as Player).CharacterId, false);
                if (character == null)
                {
                    plr.SendClientMessage($"SEARCH INVENTORY: The player {(target as Player).Name} in question does not exist.");
                    return(true);
                }
                var characterItemList = CharMgr.GetItemsForCharacter(character);
                var itemList          = new List <Item_Info>();

                if (values.Count > 0)
                {
                    // First argument is a wildcard filter.
                    filter = values[0];
                }

                foreach (CharacterItem itm in characterItemList)
                {
                    if (itm != null)
                    {
                        itemList.Add(ItemService.GetItem_Info(itm.Entry));
                    }
                }

                itemList.OrderBy(x => x.Name);

                foreach (Item_Info proto in itemList)
                {
                    if (!String.IsNullOrEmpty(filter))
                    {
                        if (proto.Name.ToLower().Contains(filter.ToLower()))
                        {
                            plr.SendMessage(0, "", $"[{proto.Entry}] {proto.Name} ", ChatLogFilters.CHATLOGFILTERS_EMOTE);
                        }
                    }
                    else
                    {
                        plr.SendMessage(0, "", $"[{proto.Entry}] {proto.Name} ", ChatLogFilters.CHATLOGFILTERS_EMOTE);
                    }
                }
            }



            return(true);
        }
        /// <summary>
        /// Sets offline/online players coordinates in database (player_name byte byte ZoneID , uint WorldX, uint WorldY, uint WorldZ)
        /// </summary>
        /// <param name="plr">Player that initiated the command</param>
        /// <param name="values">List of command arguments (after command name)</param>
        /// <returns>True if command was correctly handled, false if operation was canceled</returns>
        public static bool TeleportSet(Player plr, ref List <string> values)
        {
            string playerName = GetString(ref values);
            int    zoneID     = GetZoneId(plr, ref values);

            if (zoneID == -1)
            {
                return(false);
            }
            int worldX = GetInt(ref values);
            int worldY = GetInt(ref values);
            int worldZ = GetInt(ref values);

            Zone_Info zone = ZoneService.GetZone_Info((ushort)zoneID);

            if (zone == null)
            {
                zone = ZoneService._Zone_Info[0];
            }

            var existingChar = CharMgr.GetCharacter(Player.AsCharacterName(playerName), false);

            if (existingChar == null)
            {
                plr.SendClientMessage("Player with name '" + values[0] + "' not found.", ChatLogFilters.CHATLOGFILTERS_USER_ERROR);
                return(true);
            }

            var player = Player.GetPlayer(playerName);

            GMCommandLog log = new GMCommandLog
            {
                PlayerName = plr.Name,
                AccountId  = (uint)plr.Client._Account.AccountId,
                Command    = "TELEPORT offline player '" + existingChar.Name + "' TO " + zoneID + " " + worldX + " " + worldY,
                Date       = DateTime.Now
            };

            CharMgr.Database.AddObject(log);

            if (player != null)
            {
                player.Teleport((ushort)zoneID, (uint)worldX, (uint)worldY, (ushort)worldZ, 0);
            }

            existingChar.Value.WorldX   = worldX;
            existingChar.Value.WorldY   = worldY;
            existingChar.Value.WorldZ   = worldZ;
            existingChar.Value.ZoneId   = zone.ZoneId;
            existingChar.Value.RegionId = zone.Region;

            CharMgr.Database.SaveObject(existingChar.Value);
            CharMgr.Database.ForceSave();

            return(true);
        }
Exemple #6
0
        // Called by Destroy of Object
        public override void Dispose()
        {
            if (IsDisposed)
            {
                return;
            }

            try
            {
                foreach (var lootBag in LootBags)
                {
                    var character     = CharMgr.GetCharacter(lootBag.Key, false);
                    var characterName = character?.Name;

                    // Forced to have some value here.
                    if (Content == null)
                    {
                        Content = "mail";
                    }
                    if (String.IsNullOrEmpty(Content))
                    {
                        Content = "mail";
                    }

                    Character_mail mail = new Character_mail
                    {
                        Guid         = CharMgr.GenerateMailGuid(),
                        CharacterId  = lootBag.Key, //CharacterId
                        SenderName   = SenderName,
                        ReceiverName = characterName,
                        SendDate     = (uint)TCPManager.GetTimeStamp(),
                        Title        = Title,
                        Content      = Content,
                        Money        = 0,
                        Opened       = false
                    };

                    mail.CharacterIdSender = lootBag.Key;
                    MailItem item = new MailItem((uint)lootBag.Value.Key.Entry, lootBag.Value.Value, 0, 0, (ushort)lootBag.Value.Value.Count);
                    if (item != null)
                    {
                        mail.Items.Add(item);
                        CharMgr.AddMail(mail);
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error("LootChest", $"Failed to mail loot. {ex.Message} {ex.StackTrace}");
            }



            base.Dispose();
        }
Exemple #7
0
        public static void SendCOD(string receiverName, Player sender, uint amount)
        {
            Character receiver = CharMgr.GetCharacter(receiverName, false);

            // Sender may have deleted character, oh well. No one gets the money.
            if (receiver == null)
            {
                return;
            }

            sender.MlInterface.SendMail(receiver, "COD Payment", "Here is your COD payment", amount, false);
        }
        /// <summary>
        /// Changes the renown rank of a player (string playerName, int RenownRank)
        /// </summary>
        /// <param name="plr">Player that initiated the command</param>
        /// <param name="values">List of command arguments (after command name)</param>
        /// <returns>True if command was correctly handled, false if operation was canceled</returns>
        public static bool ModifyRenown(Player plr, ref List <string> values)
        {
            string playerName = GetString(ref values);

            int renownLevel = GetInt(ref values);

            Player    target = Player.GetPlayer(playerName);
            Character chara  = CharMgr.GetCharacter(playerName, false);

            if (chara == null)
            {
                plr.SendClientMessage($"MODIFY RENOWN: The player {playerName} in question does not exist.");
                return(true);
            }

            int desiredRenownRank = renownLevel > 0 ? renownLevel : Math.Max(1, chara.Value.RenownRank + renownLevel);

            desiredRenownRank = Math.Min(100, desiredRenownRank);

            if (target != null)
            {
                target.SetRenownLevel((byte)desiredRenownRank);
            }
            else
            {
                chara.Value.Renown     = 0;
                chara.Value.RenownRank = (byte)desiredRenownRank;
                CharMgr.Database.SaveObject(chara.Value);
            }

            if (target != plr)
            {
                plr.SendClientMessage($"MODIFY RENOWN: {playerName}'s renown rank is now {chara.Value.RenownRank}.");
            }

            GMCommandLog log = new GMCommandLog
            {
                PlayerName = plr.Name,
                AccountId  = (uint)plr.Client._Account.AccountId,
                Command    = renownLevel > 0 ? $"SET {playerName}'S RENOWN TO {renownLevel}" : $"REDUCED {playerName}'S RENOWN BY {-renownLevel}",
                Date       = DateTime.Now
            };

            CharMgr.Database.AddObject(log);

            return(true);
        }
Exemple #9
0
        public void TakeLoot(Player plr)
        {
            Character chara = CharMgr.GetCharacter(plr.CharacterId, false);

            MailItem items = GenerateBag(chara.CharacterId);

            ItemResult result = plr.ItmInterface.CreateItem(ItemService.GetItem_Info(items.id), 1, items.talisman, items.primary_dye, items.secondary_dye, false);

            if (result == ItemResult.RESULT_OK)
            {
                _lootBags.Remove(plr.CharacterId);
            }
            else if (result == ItemResult.RESULT_MAX_BAG)
            {
                plr.SendLocalizeString("", ChatLogFilters.CHATLOGFILTERS_LOOT, Localized_text.TEXT_OVERAGE_CANT_LOOT);
            }
        }
        /// <summary>
        /// Removes or returns an expired mail.
        /// </summary>
        private static void MailExpired(Character_mail mail)
        {
            if (mail.AuctionType != 0 || (mail.Money == 0 && mail.Items.Count == 0))
            {
                CharMgr.DeleteMail(mail);
                return;
            }

            Character receiver = CharMgr.GetCharacter(mail.SenderName, false);

            if (receiver != null)
            {
                ReturnMail(mail);
            }
            else
            {
                CharMgr.DeleteMail(mail);
            }
        }
        /// <summary>
        /// Returns an expired mail to its sender.
        /// </summary>
        private static MailResult ReturnMail(Character_mail mail)
        {
            // Can't return auction mail.
            if (mail.AuctionType != 0)
            {
                return(MailResult.TEXT_MAIL_RESULT11);
            }

            Character receiver = CharMgr.GetCharacter(mail.SenderName, false);

            // No one to return mail to.
            if (receiver == null)
            {
                return(MailResult.TEXT_MAIL_RESULT11);
            }

            // If mail is COD, remove the COD requirement and remove the money.
            if (mail.Cr)
            {
                mail.Cr    = false;
                mail.Money = 0;
            }

            CharMgr.DeleteMail(mail);

            Character_mail returnMail = new Character_mail
            {
                // Sender -> Reciever, Reciever -> Sender
                Guid              = CharMgr.GenerateMailGuid(),
                CharacterId       = mail.CharacterIdSender,
                CharacterIdSender = mail.CharacterId,
                SenderName        = mail.ReceiverName,
                ReceiverName      = mail.SenderName,
                Content           = "Your mail expired and has been returned to you.",
                ReadDate          = 0,
                SendDate          = (uint)TCPManager.GetTimeStamp(),
                Opened            = false
            };

            CharMgr.AddMail(returnMail);

            return(MailResult.TEXT_MAIL_UNK);
        }
Exemple #12
0
        public static void F_RENAME_CHARACTER(BaseClient client, PacketIn packet)
        {
            GameClient cclient = client as GameClient;

            packet.Skip(3);

            string OldName = packet.GetString(24);
            string NewName = packet.GetString(24);

            //Log.Success("F_RENAME_CHARACTER", "Renaming '" + OldName + "' to '" + NewName + "'");

            if (NewName.Length > 2 && !CharMgr.NameIsUsed(NewName))
            {
                Character Char = CharMgr.GetCharacter(Player.AsCharacterName(OldName), false);

                if (Char == null || Char.AccountId != cclient._Account.AccountId)
                {
                    Log.Error("CharacterRename", "Hack: Tried to rename character which account doesn't own");
                    cclient.Disconnect("Null or unowned character in F_RENAME_CHARACTER");
                    return;
                }

                Char.Name = NewName;
                CharMgr.Database.SaveObject(Char);

                // Wrong response? Perhaps needs to send F_REQUEST_CHAR_RESPONSE again.
                PacketOut Out = new PacketOut((byte)Opcodes.F_SEND_CHARACTER_RESPONSE);
                Out.WritePascalString(cclient._Account.Username);
                cclient.SendPacket(Out);
            }
            else
            {
                // Wrong response?
                PacketOut Out = new PacketOut((byte)Opcodes.F_SEND_CHARACTER_ERROR);
                Out.WritePascalString(cclient._Account.Username);
                cclient.SendPacket(Out);
            }
        }
Exemple #13
0
        public static void LoadAuctions()
        {
            Log.Debug("WorldMgr", "Loading auctions...");

            Auctions = CharMgr.Database.SelectAllObjects <Common.Auction>() as List <Common.Auction>;
            int count = 0;

            if (Auctions != null)
            {
                foreach (Common.Auction auct in Auctions)
                {
                    auct.Seller = CharMgr.GetCharacter(auct.SellerId, false);

                    if (auct.AuctionId > MAX_AUCTION_GUID)
                    {
                        MAX_AUCTION_GUID = auct.AuctionId;
                    }
                    count++;
                }
            }


            Log.Success("LoadAuctions", "Loaded " + count + " Auctions");
        }
        public void AddFriend(string name)
        {
            if (name.Length <= 0 || name.Equals(_player.Name, StringComparison.OrdinalIgnoreCase))
            {
                _player.SendLocalizeString("", ChatLogFilters.CHATLOGFILTERS_USER_ERROR, Localized_text.TEXT_SN_FRIENDSLIST_ERR_ADD_SELF);
                return;
            }

            string charName    = Player.AsCharacterName(name);
            uint   characterId = CharMgr.GetCharacterId(charName);

            // Character didn't exist
            if (characterId == 0)
            {
                _player.SendLocalizeString("", ChatLogFilters.CHATLOGFILTERS_USER_ERROR, Localized_text.TEXT_SN_LISTS_ERR_PLAYER_NOT_FOUND);
                return;
            }

            // Lift any ignore when friending someone
            if (HasIgnore(characterId))
            {
                RemoveIgnore(characterId, name);
            }

            // Check for existing friend
            lock (_friendCharacterIds)
            {
                if (_friendCharacterIds.ContainsKey(characterId))
                {
                    _player.SendLocalizeString("", ChatLogFilters.CHATLOGFILTERS_USER_ERROR, Localized_text.TEXT_SN_FRIENDSLIST_ERR_EXISTS);
                    return;
                }
            }

            // Players may not add a GM as a friend unless the GM friended them first
            Character charInfo = CharMgr.GetCharacter(characterId, false);

            if (charInfo != null && _player.GmLevel == 1)
            {
                Account acct = Program.AcctMgr.GetAccountById(charInfo.AccountId);

                if (acct != null && acct.GmLevel > 1)
                {
                    lock (charInfo.Socials)
                    {
                        if (!charInfo.Socials.Any(soc => soc.DistCharacterId == _player.Info.CharacterId && soc.Friend == 1))
                        {
                            _player.SendClientMessage("To prevent abuse of the Friends list for staff harassment, you may not friend staff members unless they friend you first.", ChatLogFilters.CHATLOGFILTERS_CSR_TELL_RECEIVE);
                            return;
                        }
                    }
                }
            }

            Character_social social = new Character_social
            {
                CharacterId     = _player.Info.CharacterId,
                DistName        = charName,
                DistCharacterId = characterId,
                Friend          = 1,
                Ignore          = 0
            };

            CharMgr.Database.AddObject(social);
            _player.Info.Socials.Add(social);

            lock (_friendCharacterIds)
                _friendCharacterIds.Add(characterId, social);

            //CharMgr.Database.ForceSave();

            SendSocialList(social, SocialListType.SOCIAL_FRIEND);
            _player.SendLocalizeString(charName, ChatLogFilters.CHATLOGFILTERS_SAY, Localized_text.TEXT_SN_FRIENDSLIST_ADD_SUCCESS);

            Player distPlayer = Player.GetPlayer(name);

            if (distPlayer != null)
            {
                distPlayer.SendLocalizeString(_player.Name, ChatLogFilters.CHATLOGFILTERS_SAY, Localized_text.TEXT_X_FRIENDED_YOU);
                SendFriend(distPlayer, true);
            }
        }
Exemple #15
0
        internal void TickContribution(long curTimeSeconds)
        {
            foreach (KeyValuePair <uint, ContributionInfo> kV in PlayerContributions)
            {
                var x = kV.Value;
                if (kV.Value.ActiveTimeEnd > curTimeSeconds)
                {
                    kV.Value.BaseContribution += (uint)(125 * _tier * RENOWN_CONTRIBUTION_FACTOR);
                }

                else if (curTimeSeconds - kV.Value.ActiveTimeEnd > CONTRIB_ELAPSE_INTERVAL)
                {
                    _toRemove.Add(kV);
                }
            }

            if (_toRemove.Count > 0)
            {
                Item_Info medallionInfo = ItemService.GetItem_Info((uint)(208399 + _tier));

                uint rpCap = (uint)(_tier * 7000);

                uint maxContrib = GetMaxContribution(PlayerContributions);

                foreach (var kVr in _toRemove)
                {
                    // Convert contribution to XP/RP based on current loss rates.
                    float contributionFactor = Math.Min(1f, kVr.Value.BaseContribution / (maxContrib * 0.7f));

                    uint   rp             = (uint)(Math.Min(rpCap, maxContrib * 1.5f * LoserShare * contributionFactor));
                    uint   xp             = rp * 5;
                    ushort medallionCount = (ushort)Math.Min(12, rp / (450 * _tier));

                    Player player = Player.GetPlayer(kVr.Key);

                    if (player != null)
                    {
                        player.SendClientMessage("You have received a reward for your contributions to a recent battle.", ChatLogFilters.CHATLOGFILTERS_RVR);

                        if (player.Region == _region)
                        {
                            player.AddXp(xp, false, false);
                            player.AddRenown(rp, false);

                            if (medallionCount > 0 && player.ItmInterface.CreateItem(medallionInfo, medallionCount) == ItemResult.RESULT_OK)
                            {
                                player.SendLocalizeString(new[] { medallionInfo.Name, medallionCount.ToString() }, ChatLogFilters.CHATLOGFILTERS_LOOT, Localized_text.TEXT_YOU_RECEIVE_ITEM_X);
                            }
                        }

                        else
                        {
                            player.AddPendingXP(xp);
                            player.AddPendingRenown(rp);

                            if (medallionCount > 0)

                            {
                                Character_mail medallionMail = new Character_mail
                                {
                                    Guid              = CharMgr.GenerateMailGuid(),
                                    CharacterId       = player.CharacterId,
                                    CharacterIdSender = player.CharacterId,
                                    SenderName        = player.Name,
                                    ReceiverName      = player.Name,
                                    SendDate          = (uint)TCPManager.GetTimeStamp(),
                                    Title             = "Medallion Reward",
                                    Content           = "You've received a medallion reward for your participation in a recent battle.",
                                    Money             = 0,
                                    Opened            = false
                                };
                                medallionMail.Items.Add(new MailItem(medallionInfo.Entry, medallionCount));
                                CharMgr.AddMail(medallionMail);
                            }
                        }
                    }

                    else
                    {
                        Character chara = CharMgr.GetCharacter(kVr.Key, false);

                        if (chara != null && chara.Value != null)
                        {
                            chara.Value.PendingXp     += xp;
                            chara.Value.PendingRenown += rp;

                            CharMgr.Database.SaveObject(chara.Value);

                            if (medallionCount > 0)
                            {
                                Character_mail medallionMail = new Character_mail
                                {
                                    Guid              = CharMgr.GenerateMailGuid(),
                                    CharacterId       = chara.CharacterId,
                                    CharacterIdSender = chara.CharacterId,
                                    SenderName        = chara.Name,
                                    ReceiverName      = chara.Name,
                                    SendDate          = (uint)TCPManager.GetTimeStamp(),
                                    Title             = "Medallion Reward",
                                    Content           = "You've received a medallion reward for your participation in a recent battle.",
                                    Money             = 0,
                                    Opened            = false
                                };
                                medallionMail.Items.Add(new MailItem(medallionInfo.Entry, medallionCount));
                                CharMgr.AddMail(medallionMail);
                            }
                        }
                    }

                    PlayerContributions.Remove(kVr.Key);
                }
                _toRemove.Clear();
            }
        }
Exemple #16
0
        /// <summary>
        /// Rewards players based on their contribution, converting it to XP, RP, Influence and Medallions.
        /// </summary>
        internal void HandleLockReward(Realms realm, float winnerRewardScale, string lockMessage, int zoneId, int tier)
        {
            /*
             * Some general notes on this.
             *
             * The ticker, if kicked consistently by a player during the course of one hour, will grant contribution which converts to 3000 RP over 60 minutes.
             * Rewards are based on a player's contribution performance relative to the best player on their realm.
             * The RP from a lock cannot exceed Tier * 5000, and by extension, the XP cannot exceed Tier * 15000,
             * the Influence cannot exceed Tier * 500 and there can be no more than 6 medallions issued.
             *
             * The rewards are scaled by the proximity of a zone to the enemy fortress.
             *
             * The rewards are also scaled by the relative Campaign scaler, which cripples rewards for players
             * refusing to fight in the most hotly contested zone.
             *
             * For the losing side, the reward is also scaled by the % of rewards, linked to the Victory Point pool.
             *
             * To receive the max losing reward, the top contributor on the losing realm must have contribution greater than 1/3 of the top attacker contribution.
             */

            string zoneName;

            if (zoneId == 0)
            {
                zoneName = _region.ZonesInfo[0].Name + " and " + _region.ZonesInfo[1].Name;
            }
            else
            {
                zoneName = ZoneService.GetZone_Info((ushort)zoneId).Name;
            }


            uint   xpCap  = (uint)(tier * 19000);
            uint   rpCap  = (uint)(tier * 10000);
            ushort infCap = (ushort)(tier * 2000);

            #region Init winner rewards
            Dictionary <uint, ContributionInfo> winnerContrib = GetContributorsFromRealm(realm);

            uint winMaxContrib = GetMaxContribution(winnerContrib);
            //Log.Info(zoneName, $"Winner contributor count : {winnerContrib.Count} Max contribution: {winMaxContrib}");

            uint   winRP             = (uint)(winMaxContrib * 1.5 * winnerRewardScale * BattleFrontConstants.LOCK_REWARD_SCALER);
            uint   winXP             = winRP * 4;
            ushort winInf            = (ushort)(winRP * 0.25f);
            ushort winMedallionCount = (ushort)Math.Min(20, winRP / (450 * tier));

            //Log.Info(zoneName, $"Lock XP: {winXP} RP: {winRP} Inf: {winInf} Medals: {winMedallionCount}");

            #endregion

            #region Init loser rewards

            Dictionary <uint, ContributionInfo> loserContrib = GetContributorsFromRealm(realm == Realms.REALMS_REALM_ORDER ? Realms.REALMS_REALM_DESTRUCTION : Realms.REALMS_REALM_ORDER);

            uint loserMaxContrib = GetMaxContribution(loserContrib);

            //Log.Info(zoneName, $"Loser contributor count : {loserContrib.Count} Max contribution: {loserMaxContrib}");

            uint   lossRP             = (uint)(winRP * LoserShare * Math.Min(1f, (loserMaxContrib * 3) / (float)winMaxContrib));
            uint   lossXP             = lossRP * 5;
            ushort lossInf            = (ushort)(lossRP * 0.35f);
            ushort lossMedallionCount = (ushort)Math.Min(15, winMedallionCount * LoserShare);

            //Log.Info(zoneName, $"Lock XP: {lossXP} RP: {lossRP} Inf: {lossInf} Medallions: {lossMedallionCount}");

            #endregion

            Item_Info medallionInfo = ItemService.GetItem_Info((uint)(208399 + tier));
            Item_Info T3Token       = ItemService.GetItem_Info(2165);
            Item_Info T4Token       = ItemService.GetItem_Info(2166);

            ushort tokenCount = 2;

            foreach (var kV in PlayerContributions)
            {
                Player plr = Player.GetPlayer(kV.Key);

                Character chara = plr != null ? plr.Info : CharMgr.GetCharacter(kV.Key, false);

                if (chara == null)
                {
                    continue;
                }

                if (plr != null)
                {
                    plr.SendLocalizeString(lockMessage, ChatLogFilters.CHATLOGFILTERS_RVR, Localized_text.CHAT_TAG_DEFAULT);
                    plr.SendLocalizeString(lockMessage, realm == Realms.REALMS_REALM_ORDER ? ChatLogFilters.CHATLOGFILTERS_C_ORDER_RVR_MESSAGE : ChatLogFilters.CHATLOGFILTERS_C_DESTRUCTION_RVR_MESSAGE, Localized_text.CHAT_TAG_DEFAULT);
                    // AAO multiplier needs to be multiplied with 20 to get the AAO that player sees.
                    // AAO mult is the global value for the server to grab the difference in size of the teams while AAOBonus is the players individual bonus
                    int aaoBuff = Convert.ToInt32(plr.AAOBonus);
                    if (aaoBuff < 0.1)
                    {
                        tokenCount = 1;
                    }
                    if (aaoBuff >= 2)
                    {
                        tokenCount = 3;
                    }
                    if (aaoBuff >= 3)
                    {
                        tokenCount = 4;
                    }
                    if (aaoBuff >= 4)
                    {
                        tokenCount = 5;
                    }
                }

                ContributionInfo contrib = kV.Value;

                if (chara.Realm == (int)realm)
                {
                    if (winRP == 0)
                    {
                        continue;
                    }

                    float contributionFactor = Math.Min(1f, contrib.BaseContribution / (winMaxContrib * 0.7f));

                    string contributionDesc;

                    if (contributionFactor > 0.75f)
                    {
                        contributionDesc = "valiant";
                    }
                    else if (contributionFactor > 0.5f)
                    {
                        contributionDesc = "stalwart";
                    }
                    else if (contributionFactor > 0.25f)
                    {
                        contributionDesc = "modest";
                    }
                    else
                    {
                        contributionDesc = "small";
                    }

                    plr?.SendClientMessage($"Your realm has captured {zoneName}, and you have been rewarded for your {contributionDesc} effort!", ChatLogFilters.CHATLOGFILTERS_RVR);

                    if (plr != null)
                    {
                        if (plr.Region == _region)
                        {
                            plr.AddXp(Math.Min(xpCap, (uint)(winXP * contributionFactor)), false, false);
                            if (plr.AAOBonus > 1)
                            {
                                plr.AddRenown(Math.Min(rpCap, (uint)(winRP * contributionFactor + (tokenCount * 100))), false, RewardType.ZoneKeepCapture, zoneName);
                                if (plr.CurrentArea != null)
                                {
                                    ushort influenceId = realm == Realms.REALMS_REALM_ORDER ? (ushort)plr.CurrentArea.OrderInfluenceId : (ushort)plr.CurrentArea.DestroInfluenceId;
                                    plr.AddInfluence(influenceId, Math.Min(infCap, (ushort)(winInf * contributionFactor + (tokenCount * 100))));
                                }
                            }
                            else
                            {
                                plr.AddRenown(Math.Min(rpCap, (uint)(winRP * contributionFactor)), false, RewardType.ZoneKeepCapture, zoneName);
                                if (plr.CurrentArea != null)
                                {
                                    ushort influenceId = realm == Realms.REALMS_REALM_ORDER ? (ushort)plr.CurrentArea.OrderInfluenceId : (ushort)plr.CurrentArea.DestroInfluenceId;
                                    plr.AddInfluence(influenceId, Math.Min(infCap, (ushort)(winInf * contributionFactor)));
                                }
                            }
                        }

                        else
                        {
                            plr.AddPendingXP(Math.Min(xpCap, (uint)(winXP * contributionFactor)));
                            plr.AddPendingRenown(Math.Min(rpCap, (uint)(winRP * contributionFactor)));
                        }
                    }

                    else if (chara.Value != null)
                    {
                        chara.Value.PendingXp     += Math.Min(xpCap, (uint)(winXP * contributionFactor));
                        chara.Value.PendingRenown += Math.Min(rpCap, (uint)(winRP * contributionFactor));
                        CharMgr.Database.SaveObject(chara.Value);
                    }

                    ushort resultantCount = (ushort)(winMedallionCount * contributionFactor);

                    /*
                     * if (plr != null && plr.AAOBonus > 1 && plr.Region == Region)
                     * {
                     *  resultantCount = Convert.ToUInt16(resultantCount * ((AgainstAllOddsMult * 20)/100));
                     * }
                     */
                    if (contributionFactor > 0 && plr != null)
                    {
                        if ((tier == 2 || tier == 3) && plr.ItmInterface.CreateItem(T3Token, tokenCount) == ItemResult.RESULT_OK)
                        {
                            plr.SendLocalizeString(new[] { T3Token.Name, tokenCount.ToString() }, ChatLogFilters.CHATLOGFILTERS_LOOT, Localized_text.TEXT_YOU_RECEIVE_ITEM_X);
                        }
                        if (tier == 4 && plr.ItmInterface.CreateItem(T4Token, tokenCount) == ItemResult.RESULT_OK)
                        {
                            plr.SendLocalizeString(new[] { T4Token.Name, tokenCount.ToString() }, ChatLogFilters.CHATLOGFILTERS_LOOT, Localized_text.TEXT_YOU_RECEIVE_ITEM_X);
                        }
                    }

                    if (resultantCount > 0)
                    {
                        if (plr != null && plr.Region == _region && plr.ItmInterface.CreateItem(medallionInfo, resultantCount) == ItemResult.RESULT_OK)
                        {
                            plr.SendLocalizeString(new[] { medallionInfo.Name, resultantCount.ToString() }, ChatLogFilters.CHATLOGFILTERS_LOOT, Localized_text.TEXT_YOU_RECEIVE_ITEM_X);
                        }

                        else
                        {
                            Character_mail medallionMail = new Character_mail
                            {
                                Guid              = CharMgr.GenerateMailGuid(),
                                CharacterId       = chara.CharacterId,
                                CharacterIdSender = chara.CharacterId,
                                SenderName        = chara.Name,
                                ReceiverName      = chara.Name,
                                SendDate          = (uint)TCPManager.GetTimeStamp(),
                                Title             = "Medallion Reward",
                                Content           = "You've received a medallion reward for your realm's victory in a recent battle in which you were a participant.",
                                Money             = 0,
                                Opened            = false
                            };
                            medallionMail.Items.Add(new MailItem(medallionInfo.Entry, resultantCount));
                            if (tier == 2 || tier == 3)
                            {
                                medallionMail.Items.Add(new MailItem(T3Token.Entry, tokenCount));
                            }
                            if (tier == 4)
                            {
                                medallionMail.Items.Add(new MailItem(T4Token.Entry, tokenCount));
                            }
                            CharMgr.AddMail(medallionMail);
                        }
                    }
                }

                else
                {
                    if (lossRP == 0)
                    {
                        continue;
                    }

                    float scaleFactor = Math.Min(1f, contrib.BaseContribution / (loserMaxContrib * 0.7f));

                    string contributionDesc;

                    if (scaleFactor > 0.75f)
                    {
                        contributionDesc = "valiant";
                    }
                    else if (scaleFactor > 0.5f)
                    {
                        contributionDesc = "stalwart";
                    }
                    else if (scaleFactor > 0.25f)
                    {
                        contributionDesc = "modest";
                    }
                    else
                    {
                        contributionDesc = "small";
                    }

                    plr?.SendClientMessage($"Though your realm lost {zoneName}, you have been rewarded for your {contributionDesc} effort in defense.", ChatLogFilters.CHATLOGFILTERS_RVR);

                    if (plr != null)
                    {
                        if (plr.Region == _region)
                        {
                            plr.AddXp((uint)Math.Min(xpCap * 0.9f, lossXP * scaleFactor), false, false);
                            if (plr.AAOBonus > 1)
                            {
                                plr.AddRenown((uint)Math.Min(rpCap * 0.9f, lossRP * scaleFactor + (tokenCount * 100)), false, RewardType.ObjectiveDefense, zoneName);
                                if (plr.CurrentArea != null)
                                {
                                    ushort influenceId = realm == Realms.REALMS_REALM_ORDER ? (ushort)plr.CurrentArea.OrderInfluenceId : (ushort)plr.CurrentArea.DestroInfluenceId;
                                    plr.AddInfluence(influenceId, (ushort)Math.Min(infCap * 0.9f, lossInf * scaleFactor + (tokenCount * 100)));
                                }
                            }
                            else
                            {
                                plr.AddRenown((uint)Math.Min(rpCap * 0.9f, lossRP * scaleFactor), false, RewardType.ObjectiveDefense, zoneName);
                                if (plr.CurrentArea != null)
                                {
                                    ushort influenceId = realm == Realms.REALMS_REALM_ORDER ? (ushort)plr.CurrentArea.OrderInfluenceId : (ushort)plr.CurrentArea.DestroInfluenceId;
                                    plr.AddInfluence(influenceId, (ushort)Math.Min(infCap * 0.9f, lossInf * scaleFactor));
                                }
                            }
                        }

                        else
                        {
                            plr.AddPendingXP((uint)Math.Min(xpCap * 0.9f, lossXP * scaleFactor));
                            plr.AddPendingRenown((uint)Math.Min(rpCap * 0.9f, lossRP * scaleFactor));
                        }
                    }

                    else if (chara.Value != null)
                    {
                        chara.Value.PendingXp     += (uint)Math.Min(xpCap * 0.9f, lossXP * scaleFactor);
                        chara.Value.PendingRenown += (uint)Math.Min(rpCap * 0.9f, lossRP * scaleFactor);
                        CharMgr.Database.SaveObject(chara.Value);
                    }

                    ushort resultantCount = (ushort)(lossMedallionCount * scaleFactor);

                    /*
                     * if (plr != null && plr.AAOBonus > 1 && plr.Region == Region)
                     * {
                     *  resultantCount = Convert.ToUInt16(resultantCount * ((AgainstAllOddsMult * 20)/100));
                     * }
                     */
                    if (scaleFactor > 0 && plr != null)
                    {
                        if ((tier == 2 || tier == 3) && plr.ItmInterface.CreateItem(T3Token, tokenCount) == ItemResult.RESULT_OK)
                        {
                            plr.SendLocalizeString(new[] { T3Token.Name, tokenCount.ToString() }, ChatLogFilters.CHATLOGFILTERS_LOOT, Localized_text.TEXT_YOU_RECEIVE_ITEM_X);
                        }
                        if (tier == 4 && plr.ItmInterface.CreateItem(T4Token, tokenCount) == ItemResult.RESULT_OK)
                        {
                            plr.SendLocalizeString(new[] { T4Token.Name, tokenCount.ToString() }, ChatLogFilters.CHATLOGFILTERS_LOOT, Localized_text.TEXT_YOU_RECEIVE_ITEM_X);
                        }
                    }
                    if (resultantCount > 0)
                    {
                        if (plr != null && plr.Region == _region && plr.ItmInterface.CreateItem(medallionInfo, resultantCount) == ItemResult.RESULT_OK)
                        {
                            plr.SendLocalizeString(new[] { medallionInfo.Name, resultantCount.ToString() }, ChatLogFilters.CHATLOGFILTERS_LOOT, Localized_text.TEXT_YOU_RECEIVE_ITEM_X);
                        }
                        else
                        {
                            Character_mail medallionMail = new Character_mail
                            {
                                Guid              = CharMgr.GenerateMailGuid(),
                                CharacterId       = chara.CharacterId,
                                CharacterIdSender = chara.CharacterId,
                                SenderName        = chara.Name,
                                ReceiverName      = chara.Name,
                                SendDate          = (uint)TCPManager.GetTimeStamp(),
                                Title             = "Medallion Reward",
                                Content           = "You've received a medallion reward for your participation in a recent battle.",
                                Money             = 0,
                                Opened            = false
                            };
                            medallionMail.Items.Add(new MailItem(medallionInfo.Entry, resultantCount));
                            if (tier == 2 || tier == 3)
                            {
                                medallionMail.Items.Add(new MailItem(T3Token.Entry, tokenCount));
                            }
                            if (tier == 4)
                            {
                                medallionMail.Items.Add(new MailItem(T4Token.Entry, tokenCount));
                            }
                            CharMgr.AddMail(medallionMail);
                        }
                    }
                }
            }

            PlayerContributions.Clear();
        }
        public void SendPacketMail(PacketIn packet)
        {
            Player plr = GetPlayer();

            if (plr == null)
            {
                return;
            }

            if (_nextSend >= TCPManager.GetTimeStamp())
            {
                SendResult(MailResult.TEXT_MAIL_RESULT6);
                return;
            }

            // Recipient read
            packet.Skip(1);
            byte   nameSize = packet.GetUint8();
            string name     = packet.GetString(nameSize);



            // Subject (client is limited to send 30 chars but its probably a ushort anyway)
            ushort subjectSize = ByteSwap.Swap(packet.GetUint16());
            string subject     = packet.GetString(subjectSize);

            // Message
            ushort messageSize = ByteSwap.Swap(packet.GetUint16());
            string message     = packet.GetString(messageSize);

            // Money
            uint money = ByteSwap.Swap(packet.GetUint32());

            // COD?
            byte cr = packet.GetUint8();

            // Item
            byte itemsToSendCount = packet.GetUint8();

            var isBlackMarket = ((name.ToLower() == "black market") || (name.ToLower() == "blackmarket"));

            List <ushort> itemSlots = new List <ushort>();
            var           itemList  = new List <Item>();

            for (byte i = 0; i < itemsToSendCount; ++i)
            {
                ushort itemSlot = ByteSwap.Swap(packet.GetUint16());
                packet.Skip(2);

                Item item = plr.ItmInterface.GetItemInSlot(itemSlot);
                if (item == null || item.Info == null)
                {
                    SendResult(MailResult.TEXT_MAIL_RESULT16);
                    return;
                }

                // Allow black market items to be sent in mail
                if (!isBlackMarket)
                {
                    if (item.BoundtoPlayer || item.Info.Bind == 1)
                    {
                        SendResult(MailResult.TEXT_MAIL_RESULT9);
                        return;
                    }
                }

                itemSlots.Add(itemSlot);
                itemList.Add(item);
            }

            if (isBlackMarket)
            {
                _logger.Debug($"Sending mail to the BLACK MARKET. Number items {itemsToSendCount}");

                // Ensure that what is being sent is a warlord item
                if (itemsToSendCount == 0)
                {
                    SendResult(MailResult.TEXT_MAIL_RESULT9);
                    return;
                }

                var blackMarketManager = new BlackMarketManager();

                // Sending multiple items.
                foreach (var item in itemList)
                {
                    if (blackMarketManager.IsItemOnBlackMarket(item.Info.Entry))
                    {
                        _logger.Info($"Sending {item.Info.Name} ({item.Info.Entry}) to BlackMarket");
                        blackMarketManager.SendBlackMarketReward(plr, item.Info.Entry);
                        plr.SendClientMessage($"Trusting to your luck, you have sent {string.Join(",", itemList.Select(x => x.Info.Name))} to the Black Market, hoping for just recompense.");
                        _logger.Debug($"Email Sent.");
                        plr.ItmInterface.RemoveItems(item.Info.Entry, 1);
                        _logger.Info($"Removed {item.Info.Name} ({item.Info.Entry}) from {plr.Name}");
                        plr.SendClientMessage($"A suspicious looking package has arrived in your mail.", ChatLogFilters.CHATLOGFILTERS_LOOT);
                    }
                    else
                    {
                        _logger.Debug($"{MailResult.TEXT_MAIL_RESULT9}");
                        return;
                    }
                }

                SendResult(MailResult.TEXT_MAIL_RESULT4);
            }
            else
            {
                Character receiver = CharMgr.GetCharacter(Player.AsCharacterName(name), false);

                if (receiver == null || receiver.Realm != (byte)plr.Realm)
                {
                    SendResult(MailResult.TEXT_MAIL_RESULT7);
                    return;
                }
                if (receiver.Name == plr.Name) // You cannot mail yourself
                {
                    plr.SendLocalizeString("", ChatLogFilters.CHATLOGFILTERS_USER_ERROR, Localized_text.TEXT_PLAYER_CANT_MAIL_YOURSELF);
                    return;
                }
                if ((cr == 0 && !plr.HasMoney(money)) || !plr.RemoveMoney((cr == 0 ? money : 0) + MAIL_PRICE))
                {
                    SendResult(MailResult.TEXT_MAIL_RESULT8);
                    return;
                }

                SendMail(receiver, subject, message, money, cr == 1, itemSlots);

                _logger.Info($"Sending mail {subject} to {receiver.Name} from {plr.Name}. Money={money}, Item Count={itemSlots.Count}");
                foreach (var itemSlot in itemSlots)
                {
                    _logger.Info($"Item : {itemSlot}");
                }
            }
        }
        /// <summary>
        /// Lists all tickets that are open
        /// </summary>
        /// <param name="plr"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static bool ListTickets(Player plr, ref List <string> values)
        {
            foreach (Bug_report report in CharMgr._report)
            {
                string assignee = "nobody";
                if (report.Assigned != null)
                {
                    assignee = report.Assigned;
                }

                string subtype = "0";

                if (report.ReportType == "General")
                {
                    subtype = "1";
                }

                else if (report.ReportType == "Harassment")
                {
                    subtype = "2";
                }

                else if (report.ReportType == "Zone Disruption")
                {
                    subtype = "3";
                }

                else if (report.ReportType == "XP or Renown Farming")
                {
                    subtype = "4";
                }

                else if (report.ReportType == "Speed Hacking")
                {
                    subtype = "5";
                }

                else if (report.ReportType == "Macroing")
                {
                    subtype = "6";
                }

                else if (report.ReportType == "Kill Stealing")
                {
                    subtype = "7";
                }

                else if (report.ReportType == "Cross Realming")
                {
                    subtype = "8";
                }


                /*  How the category work
                 *  report.type     report.category     what it means
                 *      3               18              Goldseller
                 *      0               1               Stuck in world
                 *      0               2               Missing Character
                 *      0               3               Missing Item
                 *      2               4               Violation report, it also have a subtype defined in report.reporttype
                 *      1               5               Naming Violation
                 *      0               6               Character Issues
                 *      0               19              Paid Item Issues
                 *      0               20              Paid Character Transfer
                 *      0               21              Paid Namechange
                 *      0               7               PQ Issue
                 *      0               8               SC Issue
                 *      0               10              Monster Issue
                 *      0               9               BattlefieldObjective and Keep Issue
                 *      0               11              Quest and Quest Item Issue
                 *      0               12              Combat Issue
                 *      0               13              TOK Issue
                 *      0               14              Mail Issue
                 *      0               15              AH Issue
                 *      0               16              Interface Issue
                 *      0               17              Tradeskill Issue
                 *      THIS IS THE END OF GM TICKETS, HERE BUGREPORTS START
                 *      4               6               Bugreport: Other
                 *      4               1               Bugreport: Art
                 *      4               5               Bugreport: Item
                 *      4               0               Bugreport: Character
                 *      4               2               Bugrepoort: Monster
                 *      4               3               Bugreport: Crash
                 *      4               4               Bugreport: Quest and PQ
                 *      THIS IS THE END OF BUGREPORTS, HERE FEEDBACK STARTS
                 *      5               7               Feedback: Cities
                 *      5               8               Feedback: TOK
                 *      5               9               Feedback: Quests and PQ
                 *      5               10              Feedback: Career
                 *      5               11              Feedback: Combat
                 *      5               12              Feedback: Tradeskill
                 *      5               13              Feedback: UI
                 *      5               14              Feedback: Constructive Criticism
                 *      5               15              Feedback: Positive Feedback
                 * */

                string field = "0";
                if (report.FieldSting != "")
                {
                    field = report.FieldSting.ToString();
                }

                long time = report.Time - TCPManager.GetTimeStamp();

                //0 means that the character has been deleted
                string name = "0";
                //0 means that the ticket is older then when we added accountid to the tickets or that it was not sent for whatever reason into the ticket.
                string account = "0";
                if (CharMgr.GetCharacter(report.CharacterId, false) != null)
                {
                    if (report.AccountId != 0)
                    {
                        if (CharMgr.GetCharacter(report.CharacterId, false).AccountId == report.AccountId)
                        {
                            name    = CharMgr.GetCharacter(report.CharacterId, false).Name;
                            account = Program.AcctMgr.GetAccountById((int)report.AccountId).Username;
                        }
                    }
                }

                if (CharMgr.GetCharacter(report.CharacterId, false) == null && report.AccountId != 0)
                {
                    account = Program.AcctMgr.GetAccountById((int)report.AccountId).Username;
                }


                //for whatever reason ^ cannot be sent to the client, it will break the rest of the string.
                string Message = report.Message;
                if (Message.Contains("^"))
                {
                    Message = Message.Replace('^', ' ');
                }

                plr.SendClientMessage("TICKET_REPORT:" + report.ObjectId + ";" + name + ";" + report.Type + ";" + report.Category + ";" + subtype + ";" + field + ";" + assignee + ";" + Message + ";" + time + ";" + account, SystemData.ChatLogFilters.CHATLOGFILTERS_CHANNEL_9);
            }
            plr.SendClientMessage("TICKET_END", SystemData.ChatLogFilters.CHATLOGFILTERS_CHANNEL_9);
            return(true);
        }
        /// <summary>
        /// To answer and close a ticket (answer will be sent as an ingame mail)
        /// </summary>
        /// <param name="plr"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static bool Answer(Player plr, ref List <string> values)
        {
            if (values.Count < 2)
            {
                plr.SendClientMessage("Usage: .ticket answer <bugtrackerID> <message>");
                return(true);
            }

            string reportID = GetString(ref values);
            string message  = GetTotalString(ref values).Trim();

            if (string.IsNullOrEmpty(message))
            {
                plr.SendClientMessage("you need to specify a message to send");
                return(true);
            }

            if (string.IsNullOrEmpty(reportID))
            {
                plr.SendClientMessage("you need to specify the ticketID");
                return(true);
            }

            Bug_report report = CharMgr.GetReport(reportID);

            if (report == null)
            {
                plr.SendClientMessage("The Specified report does not exist");
                return(true);
            }

            if (report.Assigned != plr.Client._Account.Username)
            {
                plr.SendClientMessage("You cannot answer a ticket not assigned to you(username), assign it to yourself first if you want to answer this ticket");
                return(true);
            }

            if (CharMgr.GetCharacter(report.CharacterId, false) == null)
            {
                plr.SendClientMessage("The player who created this ticket is deleted or has not logged in for over the preload period, as such we cannot send a mail to the character.");
                return(true);
            }

            else
            {
                plr.SendClientMessage("You have answered ticket: " + reportID);

                GMCommandLog log = new GMCommandLog
                {
                    PlayerName = plr.Client._Account.Username,
                    AccountId  = (uint)plr.Client._Account.AccountId,
                    Command    = $"Answered Ticket: {reportID} from characterID: {report.CharacterId}. Containing message: {report.Message} {report.FieldSting} with the following reply: {message}",
                    Date       = DateTime.Now
                };

                Character      chara      = CharMgr.GetCharacter(report.CharacterId, false);
                Character_mail ticketMail = new Character_mail
                {
                    Guid              = CharMgr.GenerateMailGuid(),
                    CharacterId       = chara.CharacterId,
                    CharacterIdSender = chara.CharacterId,
                    SenderName        = chara.Name,
                    ReceiverName      = chara.Name,
                    SendDate          = (uint)TCPManager.GetTimeStamp(),
                    Title             = "Answered Ticket",
                    Content           = $"Your ticket has been answered by: {report.Assigned} with the following message: \n \n {message}",
                    Money             = 0,
                    Opened            = false
                };

                CharMgr.AddMail(ticketMail);
                CharMgr.Database.AddObject(log);

                lock (CharMgr._report)
                {
                    CharMgr._report.Remove(report);
                    CharMgr.Database.DeleteObject(report);
                    CharMgr.Database.ForceSave();
                }
                return(true);
            }
        }
        /// <summary>
        /// Changes players name
        /// </summary>
        /// <param name="plr">Player that initiated the command</param>
        /// <param name="values">List of command arguments (after command name)</param>
        /// <returns>True if command was correctly handled, false if operation was canceled</returns>
        public static bool ModifyPlayerName(Player plr, ref List <string> values)
        {
            if (values.Count < 2)
            {
                plr.SendClientMessage("Usage: .modify playername old_player_name new_player_name");
                return(true);
            }

            var charToRename = CharMgr.GetCharacter(Player.AsCharacterName(values[0]), false);

            if (charToRename == null)
            {
                plr.SendClientMessage("Player with name '" + values[0] + "' not found.", ChatLogFilters.CHATLOGFILTERS_USER_ERROR);
                return(true);
            }

            var existingChar = CharMgr.GetCharacter(Player.AsCharacterName(values[1]), false);

            if (existingChar != null)
            {
                plr.SendClientMessage("Player with name '" + existingChar.Name + "' already exists.", ChatLogFilters.CHATLOGFILTERS_USER_ERROR);
                return(true);
            }

            if (values[1].Length < 3)
            {
                plr.SendClientMessage("Player name must be at least 3 characters long.", ChatLogFilters.CHATLOGFILTERS_USER_ERROR);
                return(true);
            }

            if (!values[1].All(c => char.IsLetter(c) && c <= 0x7A))
            {
                plr.SendClientMessage("Player names may not contain special characters.", ChatLogFilters.CHATLOGFILTERS_USER_ERROR);
                return(true);
            }

            string newName = values[1][0].ToString().ToUpper() + values[1].ToLower().Substring(1);


            CharMgr.UpdateCharacterName(charToRename, newName);

            var player = Player.GetPlayer(values[0]);

            LogSanction(player.Info.AccountId, plr, "GM issued Name Change", "", $"From {charToRename.Name} to {newName}");

            GMCommandLog log = new GMCommandLog
            {
                PlayerName = plr.Name,
                AccountId  = (uint)plr.Client._Account.AccountId,
                Command    = "Changed player name FROM " + values[0] + " TO " + charToRename.Name,
                Date       = DateTime.Now
            };

            CharMgr.Database.AddObject(log);

            if (player != null)
            {
                player.Name = charToRename.Name;
                player.Quit(false, false);
            }

            plr.SendClientMessage(log.Command);
            return(true);
        }