Esempio n. 1
0
        private void HouseCmd(CommandArgs args)
        {
            var parameters        = args.Parameters;
            var player            = args.Player;
            var playerGroupConfig = Config.Instance.GetGroupConfig(player.Group.Name);

            var subcommand = parameters.Count > 0 ? parameters[0] : "";

            if (subcommand.Equals("1", StringComparison.OrdinalIgnoreCase))
            {
                player.AwaitingTempPoint = 1;
                player.SendInfoMessage("Hit a block to set the first point.");
            }
            else if (subcommand.Equals("2", StringComparison.OrdinalIgnoreCase))
            {
                player.AwaitingTempPoint = 2;
                player.SendInfoMessage("Hit a block to set the second point.");
            }
            else if (subcommand.Equals("allow", StringComparison.OrdinalIgnoreCase))
            {
                if (parameters.Count != 2)
                {
                    player.SendErrorMessage($"Syntax: {Commands.Specifier}house allow <player-name>");
                    return;
                }

                var session = GetOrCreateSession(player);
                if (session.CurrentHouse == null)
                {
                    player.SendErrorMessage("You aren't currently in a house.");
                    return;
                }

                var house = session.CurrentHouse;
                if (player.User?.Name != house.OwnerName && !player.HasPermission("housing.house.admin"))
                {
                    player.SendErrorMessage(
                        $"You can't allow users for {house.OwnerName}'s [c/{Color.MediumPurple.Hex3()}:{house}] house.");
                    return;
                }

                var inputPlayerName = parameters[1];
                var players         = TShock.Utils.FindPlayer(inputPlayerName);
                if (players.Count > 1)
                {
                    player.SendErrorMessage($"Multiple players matched '{inputPlayerName}':");
                    TShock.Utils.SendMultipleMatchError(player, players);
                    return;
                }
                if (players.Count == 0)
                {
                    player.SendErrorMessage($"Invalid player '{inputPlayerName}'.");
                    return;
                }

                var otherPlayer = players[0];
                if (otherPlayer.User == null)
                {
                    player.SendErrorMessage($"{otherPlayer.Name} is not logged in.");
                    return;
                }

                house.AllowedUsernames.Add(otherPlayer.User.Name);
                database.Update(house);
                player.SendSuccessMessage(
                    $"Allowed {otherPlayer.Name} to modify " +
                    $"{(house.OwnerName == player.User?.Name ? "your" : house.OwnerName + "'s")} " +
                    $"[c/{Color.MediumPurple.Hex3()}:{house}] house.");
            }
            else if (subcommand.Equals("buy", StringComparison.OrdinalIgnoreCase))
            {
                if (parameters.Count != 2)
                {
                    player.SendErrorMessage($"Syntax: {Commands.Specifier}house buy <house-name>");
                    return;
                }

                var inputHouseName = parameters[1];
                var session        = GetOrCreateSession(player);
                if (session.CurrentHouse == null)
                {
                    var plot = TShock.Regions.InAreaRegion(player.TileX, player.TileY)
                               .FirstOrDefault(r => r.Name.StartsWith("__Plot"));
                    if (plot == null)
                    {
                        player.SendErrorMessage("You aren't currently in a house or plot.");
                        return;
                    }

                    player.TempPoints[0] = new Point(plot.Area.X, plot.Area.Y);
                    player.TempPoints[1] = new Point(plot.Area.Right - 1, plot.Area.Bottom - 1);
                    HouseCmd(new CommandArgs("", player, new List <string> {
                        "set", inputHouseName
                    }));
                    return;
                }

                var house = session.CurrentHouse;
                if (!house.ForSale || house.OwnerName == player.User?.Name)
                {
                    player.SendErrorMessage("You cannot purchase this house.");
                    return;
                }

                if (!BankingPlugin.Instance.Bank.CurrencyManager.TryFindCurrencyFromString(house.SalePrice, out var saleCurrency))
                {
                    player.SendErrorMessage("The House's list price is in an unknown currency format. Please contact the owner.");
                    return;
                }

                var currencyConverter = saleCurrency.GetCurrencyConverter();
                if (!currencyConverter.TryParse(house.SalePrice, out var purchaseCost))
                {
                    player.SendErrorMessage("The House's list price is in an invalid currency format. Please contact the owner.");
                    return;
                }

                var salesTax  = Math.Round((decimal)playerGroupConfig.TaxRate * purchaseCost);
                var totalCost = purchaseCost + salesTax;

                var purchaseCostString = currencyConverter.ToString(purchaseCost);
                var salesTaxString     = currencyConverter.ToString(salesTax);
                var totalCostString    = currencyConverter.ToString(totalCost);

                player.SendInfoMessage(
                    $"Purchasing {house.OwnerName}'s house [c/{Color.MediumPurple.Hex3()}:{house}] will cost " +
                    $"[c/{Color.OrangeRed.Hex3()}:{purchaseCostString}], with a sales tax of [c/{Color.OrangeRed.Hex3()}:{salesTaxString}].");
                player.SendInfoMessage("Do you wish to proceed? Use /yes or /no.");
                player.AddResponse("yes", args2 =>
                {
                    player.AwaitingResponse.Remove("no");
                    var account = BankingPlugin.Instance.GetBankAccount(player.Name, saleCurrency.InternalName);

                    if (account == null || account.Balance < totalCost)
                    {
                        player.SendErrorMessage(
                            $"You do not have enough of a balance to purchase {house.OwnerName}'s " +
                            $"[c/{Color.MediumPurple.Hex3()}:{house}] house.");
                        return;
                    }
                    if (!house.ForSale)
                    {
                        player.SendErrorMessage("Unfortunately, the house was purchased while waiting.");
                        return;
                    }
                    house.ForSale = false;

                    if (purchaseCost > 0)
                    {
                        var account2 = BankingPlugin.Instance.GetBankAccount(house.OwnerName, saleCurrency.InternalName);
                        account.TryTransferTo(account2, purchaseCost);
                    }
                    if (salesTax > 0)
                    {
                        TaxService.PayTax(account, salesTax);
                    }

                    database.Remove(house);
                    database.AddHouse(player, inputHouseName, house.Rectangle.X, house.Rectangle.Y,
                                      house.Rectangle.Right - 1, house.Rectangle.Bottom - 1);
                    player.SendInfoMessage(
                        $"Purchased {house.OwnerName}'s house [c/{Color.MediumPurple.Hex3()}:{house}] for " +
                        $"[c/{Color.OrangeRed.Hex3()}:{totalCostString}].");

                    var player2 = TShock.Players.Where(p => p?.Active == true)
                                  .FirstOrDefault(p => p.User?.Name == house.OwnerName);
                    player2?.SendInfoMessage(
                        $"{player.Name} purchased your house [c/{Color.MediumPurple.Hex3()}:{house}] for " +
                        $"[c/{Color.OrangeRed.Hex3()}:{totalCostString}].");
                });
                player.AddResponse("no", args2 =>
                {
                    player.AwaitingResponse.Remove("yes");
                    player.SendInfoMessage("Canceled purchase.");
                });
            }
            else if (subcommand.Equals("disallow", StringComparison.OrdinalIgnoreCase))
            {
                if (parameters.Count != 2)
                {
                    player.SendErrorMessage($"Syntax: {Commands.Specifier}house disallow <username>");
                    return;
                }

                var session = GetOrCreateSession(player);
                if (session.CurrentHouse == null)
                {
                    player.SendErrorMessage("You aren't currently in a house.");
                    return;
                }

                var house = session.CurrentHouse;
                if (player.User?.Name != house.OwnerName && !player.HasPermission("housing.house.admin"))
                {
                    player.SendErrorMessage(
                        $"You can't disallow users for {house.OwnerName}'s [c/{Color.MediumPurple.Hex3()}:{house}] house.");
                    return;
                }

                var inputUsername = parameters[1];
                house.AllowedUsernames.Remove(inputUsername);
                database.Update(house);
                player.SendSuccessMessage(
                    $"Disallowed {inputUsername} from modifying " +
                    $"{(house.OwnerName == player.User?.Name ? "your house" : house.OwnerName + "'s house")} " +
                    $"[c/{Color.MediumPurple.Hex3()}:{house}].");
            }
            else if (subcommand.Equals("info", StringComparison.OrdinalIgnoreCase))
            {
                var session = GetOrCreateSession(player);
                if (session.CurrentHouse == null)
                {
                    player.SendErrorMessage("You aren't currently in a house.");
                    return;
                }

                var house = session.CurrentHouse;
                player.SendInfoMessage($"Owner: {house.OwnerName}, Name: {house.Name}");
                if (player.User?.Name == house.OwnerName || player.HasPermission("housing.house.admin"))
                {
                    var ownerConfig = house.GetGroupConfig();                    //because a player other than the owner maybe running this command.

                    player.SendInfoMessage($"Debt: [c/{Color.OrangeRed.Hex3()}:{house.Debt}]");
                    var isStore = database.GetShops().Any(s => house.Rectangle.Contains(s.Rectangle));
                    var taxRate = isStore ? ownerConfig.StoreTaxRate : ownerConfig.TaxRate;
                    var taxCost = (decimal)Math.Round(house.Area * taxRate);
                    player.SendInfoMessage(
                        $"Tax cost: [c/{Color.OrangeRed.Hex3()}:{taxCost}], Last taxed: {house.LastTaxed}");
                    player.SendInfoMessage($"Allowed users: {string.Join(", ", house.AllowedUsernames)}");
                }
            }
            else if (subcommand.Equals("remove", StringComparison.OrdinalIgnoreCase))
            {
                var session = GetOrCreateSession(player);
                if (session.CurrentHouse == null)
                {
                    player.SendErrorMessage("You aren't currently in a house.");
                    return;
                }

                var house = session.CurrentHouse;
                if (player.User?.Name != house.OwnerName && !player.HasPermission("housing.house.admin"))
                {
                    player.SendErrorMessage(
                        $"You can't remove {house.OwnerName}'s [c/{Color.MediumPurple.Hex3()}:{house}] house.");
                    return;
                }

                database.Remove(house);
                player.SendSuccessMessage(
                    $"Removed {(house.OwnerName == player.User?.Name ? "your" : house.OwnerName + "'s")} " +
                    $"[c/{Color.MediumPurple.Hex3()}:{house}] house.");
            }
            else if (subcommand.Equals("sell", StringComparison.OrdinalIgnoreCase))
            {
                if (parameters.Count != 2)
                {
                    player.SendErrorMessage($"Syntax: {Commands.Specifier}house sell <price>");
                    return;
                }

                var session = GetOrCreateSession(player);
                if (session.CurrentHouse == null)
                {
                    player.SendErrorMessage("You aren't currently in a house.");
                    return;
                }

                var house = session.CurrentHouse;
                if (player.User?.Name != house.OwnerName && !player.HasPermission("housing.house.admin"))
                {
                    player.SendErrorMessage(
                        $"You can't sell {house.OwnerName}'s [c/{Color.MediumPurple.Hex3()}:{house}] house.");
                    return;
                }

                var inputPrice = parameters[1];
                if (!BankingPlugin.Instance.Bank.CurrencyManager.TryFindCurrencyFromString(inputPrice, out var saleCurrency))
                {
                    player.SendErrorMessage($"Invalid price '{inputPrice}'. No currency supports this format.");
                    return;
                }

                var parsed = saleCurrency.GetCurrencyConverter().TryParse(inputPrice, out var price);
                if (parsed && price > 0m)
                {
                    house.ForSale   = true;
                    house.SalePrice = saleCurrency.GetCurrencyConverter().ToString(price);                    //we use the converter.ToString() so
                    //so that the SalePrice uses the largest units available.
                    database.Update(house);
                    player.SendSuccessMessage(
                        $"Selling {(house.OwnerName == player.User?.Name ? "your" : house.OwnerName + "'s")} " +
                        $"[c/{Color.MediumPurple.Hex3()}:{house}] house for [c/{Color.OrangeRed.Hex3()}:{house.SalePrice}].");
                }
                else
                {
                    player.SendErrorMessage($"Invalid price '{inputPrice}'.");
                    return;
                }
            }
            else if (subcommand.Equals("set", StringComparison.OrdinalIgnoreCase))
            {
                if (parameters.Count != 2)
                {
                    player.SendErrorMessage($"Syntax: {Commands.Specifier}house set <house-name>");
                    return;
                }

                if (player.TempPoints.Any(p => p == Point.Zero))
                {
                    player.SendErrorMessage("Not all points have been set.");
                    return;
                }

                var point1         = player.TempPoints[0];
                var point2         = player.TempPoints[1];
                var inputHouseName = parameters[1];
                var x  = Math.Min(point1.X, point2.X);
                var y  = Math.Min(point1.Y, point2.Y);
                var x2 = Math.Max(point1.X, point2.X);
                var y2 = Math.Max(point1.Y, point2.Y);
                if (database.GetHouses().Count(h => h.OwnerName == player.User?.Name) >= playerGroupConfig.MaxHouses)
                {
                    player.SendErrorMessage($"You have too many houses. Maximum allowed is {playerGroupConfig.MaxHouses}.");
                    return;
                }

                var area = (x2 - x + 1) * (y2 - y + 1);
                if (area < playerGroupConfig.MinHouseSize)
                {
                    player.SendErrorMessage($"Your house is too small. Minimum area is {playerGroupConfig.MinHouseSize}.");
                    return;
                }
                if (area > playerGroupConfig.MaxHouseSize)
                {
                    player.SendErrorMessage($"Your house is too large. Maximum area is {playerGroupConfig.MaxHouseSize}.");
                    return;
                }

                var rectangle = new Rectangle(x, y, x2 - x + 1, y2 - y + 1);
                if (database.GetHouses().Any(h => h.Rectangle.Intersects(rectangle)))
                {
                    player.SendErrorMessage("Your house must not intersect any other houses.");
                    return;
                }
                if (Config.Instance.RequireAdminRegions && TShock.Regions.ListAllRegions(Main.worldID.ToString()).All(
                        r => !r.Name.StartsWith("__Plot") || !r.Area.Contains(rectangle)))
                {
                    player.SendErrorMessage("Your house must lie entirely on a plot.");
                }

                player.TempPoints[0] = Point.Zero;
                player.TempPoints[1] = Point.Zero;
                var purchaseCost = (decimal)Math.Round(rectangle.Width * rectangle.Height * playerGroupConfig.PurchaseRate);
                if (purchaseCost > 0)
                {
                    var taxCost = (decimal)Math.Round(rectangle.Width * rectangle.Height * playerGroupConfig.TaxRate);
                    player.SendInfoMessage(
                        $"Purchasing this house will require [c/{Color.OrangeRed.Hex3()}:{purchaseCost.ToMoneyString()}].");
                    player.SendInfoMessage(
                        $"The tax for this house will be [c/{Color.OrangeRed.Hex3()}:{taxCost.ToMoneyString()}].");
                    player.SendInfoMessage("Do you wish to proceed? Use /yes or /no.");
                    player.AddResponse("yes", args2 =>
                    {
                        player.AwaitingResponse.Remove("no");

                        var account = BankingPlugin.Instance.GetBankAccount(player);
                        if (account == null || account.Balance < purchaseCost)
                        {
                            player.SendErrorMessage("You do not have enough of a balance to purchase the house.");
                            return;
                        }

                        account.TryTransferTo(BankingPlugin.Instance.GetWorldAccount(), purchaseCost);

                        var house = database.AddHouse(player, inputHouseName, x, y, x2, y2);
                        player.SendSuccessMessage($"Purchased house [c/{Color.MediumPurple.Hex3()}:{house}] for " +
                                                  $"[c/{Color.OrangeRed.Hex3()}:{purchaseCost.ToMoneyString()}].");
                    });
                    player.AddResponse("no", args2 =>
                    {
                        player.AwaitingResponse.Remove("yes");
                        player.SendInfoMessage("Canceled purchase.");
                    });
                }
                else
                {
                    var house = database.AddHouse(player, inputHouseName, x, y, x2, y2);
                    player.SendSuccessMessage($"Added house [c/{Color.MediumPurple.Hex3()}:{house}].");
                }
            }
            else
            {
                player.SendErrorMessage($"Syntax: {Commands.Specifier}house 1/2");
                player.SendErrorMessage($"Syntax: {Commands.Specifier}house allow <player-name>");
                player.SendErrorMessage($"Syntax: {Commands.Specifier}house buy <house-name>");
                player.SendErrorMessage($"Syntax: {Commands.Specifier}house disallow <username>");
                player.SendErrorMessage($"Syntax: {Commands.Specifier}house info");
                player.SendErrorMessage($"Syntax: {Commands.Specifier}house remove");
                player.SendErrorMessage($"Syntax: {Commands.Specifier}house sell <price>");
                player.SendErrorMessage($"Syntax: {Commands.Specifier}house set <house-name>");
            }
        }