public TradingStationLotInfo(TradingStationLot lot)
 {
     this.ProtoItem      = lot.ProtoItem;
     this.State          = lot.State;
     this.LotQuantity    = lot.LotQuantity;
     this.CountAvailable = lot.CountAvailable;
     this.PriceCoinShiny = lot.PriceCoinShiny;
     this.PriceCoinPenny = lot.PriceCoinPenny;
 }
예제 #2
0
        public static void ServerInitialize(IStaticWorldObject tradingStation)
        {
            if (!(tradingStation.ProtoStaticWorldObject is IProtoObjectTradingStation protoTradingStation))
            {
                throw new Exception($"Not an {typeof(IProtoObjectTradingStation).FullName}: {tradingStation}");
            }

            TradingStationsMapMarksSystem.ServerTryAddMark(tradingStation);

            var privateState = GetPrivateState(tradingStation);
            var publicState  = GetPublicState(tradingStation);

            if (privateState.StockItemsContainer == null)
            {
                privateState.StockItemsContainer = ServerItems.CreateContainer(tradingStation,
                                                                               protoTradingStation
                                                                               .StockItemsContainerSlotsCount);
            }
            else
            {
                ServerItems.SetSlotsCount(privateState.StockItemsContainer,
                                          protoTradingStation.StockItemsContainerSlotsCount);
            }

            var lots = publicState.Lots;

            if (lots == null)
            {
                publicState.Lots =
                    lots         = new NetworkSyncList <TradingStationLot>(capacity: protoTradingStation.LotsCount);
            }

            // ensure that the lots count is not exceeded
            while (lots.Count > protoTradingStation.LotsCount)
            {
                lots.RemoveAt(protoTradingStation.LotsCount - 1);
            }

            for (var i = 0; i < protoTradingStation.LotsCount; i++)
            {
                if (lots.Count <= i)
                {
                    lots.Add(new TradingStationLot());
                }
                else if (lots[i] == null)
                {
                    lots[i] = new TradingStationLot();
                }
            }

            ServerRefreshTradingStationLots(tradingStation,
                                            privateState,
                                            publicState);
        }
예제 #3
0
        private static void ClientShowErrorNotification(
            TradingStationLot lot,
            TradingResult error,
            bool isPlayerBuying)
        {
            var message = error.GetDescription();

            if (error == TradingResult.ErrorNotEnoughMoneyOnPlayer)
            {
                // calculate how many coins are needed
                var  character    = Client.Characters.CurrentPlayerCharacter;
                long deficitShiny = 0,
                     deficitPenny = 0;

                if (lot.PriceCoinShiny > 0)
                {
                    deficitShiny = lot.PriceCoinShiny
                                   - character.CountItemsOfType(ProtoItemCoinShiny.Value);
                }

                if (lot.PriceCoinPenny > 0)
                {
                    deficitPenny = lot.PriceCoinPenny
                                   - character.CountItemsOfType(ProtoItemCoinPenny.Value);
                }

                if (deficitShiny > 0 ||
                    deficitPenny > 0)
                {
                    if (deficitShiny > 0)
                    {
                        // ReSharper disable once CanExtractXamlLocalizableStringCSharp
                        message += "[br]"
                                   + string.Format(NotificationNeedMoreShinyCoins, deficitShiny);
                    }

                    if (deficitPenny > 0)
                    {
                        // ReSharper disable once CanExtractXamlLocalizableStringCSharp
                        message += "[br]"
                                   + string.Format(NotificationNeedMorePennyCoins, deficitPenny);
                    }
                }
            }

            NotificationSystem.ClientShowNotification(
                isPlayerBuying
                    ? NotiticationCannotBuy_Title
                    : NotiticationCannotSell_Title,
                message,
                NotificationColor.Bad,
                icon: lot.ProtoItem.Icon);
        }
        private static void ClientShowErrorNotification(
            TradingStationLot lot,
            TradingResult error,
            bool isPlayerBuying)
        {
            var message = error.GetDescription();

            if (error == TradingResult.ErrorNotEnoughMoneyOnPlayer)
            {
                // calculate how many coins are needed
                long shinyNotEnough = 0, pennyNotEnough = 0;
                if (lot.PriceCoinShiny > 0)
                {
                    shinyNotEnough = lot.PriceCoinShiny
                                     - Client.Characters.CurrentPlayerCharacter.CountItemsOfType(
                        ProtoItemCoinShiny.Value);
                }

                if (lot.PriceCoinPenny > 0)
                {
                    pennyNotEnough = lot.PriceCoinPenny
                                     - Client.Characters.CurrentPlayerCharacter.CountItemsOfType(
                        ProtoItemCoinPenny.Value);
                }

                if (shinyNotEnough > 0 ||
                    pennyNotEnough > 0)
                {
                    if (shinyNotEnough > 0)
                    {
                        message += Environment.NewLine
                                   + string.Format(NotificationNeedMoreShinyCoins, shinyNotEnough);
                    }

                    if (pennyNotEnough > 0)
                    {
                        message += Environment.NewLine
                                   + string.Format(NotificationNeedMorePennyCoins, pennyNotEnough);
                    }
                }
            }

            NotificationSystem.ClientShowNotification(
                isPlayerBuying
                    ? NotiticationCannotBuy_Title
                    : NotiticationCannotSell_Title,
                message,
                NotificationColor.Bad,
                icon: lot.ProtoItem.Icon);
        }
예제 #5
0
        public ViewModelTradingStationLot(
            TradingStationLot lot,
            Action <TradingStationLot, ViewModelTradingStationLotEditor> callbackSaveHandler = null)
        {
            this.lot = lot;
            this.callbackSaveHandler = callbackSaveHandler;

            this.lot.ClientSubscribe(_ => _.ProtoItem,
                                     _ =>
            {
                this.NotifyPropertyChanged(nameof(this.ProtoItem));
                this.NotifyPropertyChanged(nameof(this.Icon));
            },
                                     this);

            this.lot.ClientSubscribe(_ => _.ItemOnSale,
                                     _ =>
            {
                this.NotifyPropertyChanged(nameof(this.ItemOnSaleInstance));
                this.NotifyPropertyChanged(nameof(this.Icon));
                this.RefreshOverlayControls();
            },
                                     this);

            this.RefreshOverlayControls();

            this.lot.ClientSubscribe(_ => _.LotQuantity,
                                     _ => this.NotifyPropertyChanged(nameof(this.LotQuantity)),
                                     this);

            this.lot.ClientSubscribe(_ => _.PriceCoinPenny,
                                     _ => this.NotifyPropertyChanged(nameof(this.PriceCoinPenny)),
                                     this);

            this.lot.ClientSubscribe(_ => _.PriceCoinShiny,
                                     _ => this.NotifyPropertyChanged(nameof(this.PriceCoinShiny)),
                                     this);

            this.lot.ClientSubscribe(_ => _.State,
                                     _ =>
            {
                this.NotifyPropertyChanged(nameof(this.IsAvailable));
                this.NotifyPropertyChanged(nameof(this.IsEnabled));
                this.NotifyPropertyChanged(nameof(this.ProblemText));
            },
                                     this);

            handItemsContainer.StateHashChanged += this.HandItemsContainerItemsChanged;
        }
예제 #6
0
 private static void ClientShowSuccessNotification(
     TradingStationLot lot,
     bool isPlayerBuying)
 {
     Client.Audio.PlayOneShot(new SoundResource("UI/Notifications/ItemTradeSuccess"));
     NotificationSystem.ClientShowNotification(
         title: isPlayerBuying
                    ? NotificationBoughtTitle
                    : NotificationSoldTitle,
         // ReSharper disable once CanExtractXamlLocalizableStringCSharp
         message: $"{lot.ProtoItem.Name} ({lot.LotQuantity}).",
         color: NotificationColor.Good,
         icon: lot.ProtoItem.Icon,
         playSound: false);
 }
예제 #7
0
        public ViewModelTradingStationLotEditor(TradingStationLot lot, Action callbackSave, Action callbackCancel)
        {
            this.lot            = lot;
            this.callbackCancel = callbackCancel;
            this.callbackSave   = callbackSave;

            this.selectedProtoItem = lot.ProtoItem;
            this.PriceCoinShiny    = lot.PriceCoinShiny;
            this.PriceCoinPenny    = lot.PriceCoinPenny;
            this.LotQuantity       = Math.Max((ushort)1, lot.LotQuantity);

            // no need to order as the ordering is applied later
            this.allItemsList      = Api.FindProtoEntities <IProtoItem>().ToList();
            this.existingItemsList = this.GetExistingItemsList();

            this.RefreshLists();
        }
예제 #8
0
        public static void ClientSendTradingLotModification(
            TradingStationLot lot,
            IProtoItem protoItem,
            ushort lotQuantity,
            ushort priceCoinPenny,
            ushort priceCoinShiny)
        {
            var tradingStation = lot.GameObject as IStaticWorldObject;
            var publicState    = GetPublicState(tradingStation);
            var lotIndex       = publicState.Lots.IndexOf(lot);

            Instance.CallServer(
                _ => _.ServerRemote_SetTradingLot(tradingStation,
                                                  (byte)lotIndex,
                                                  protoItem,
                                                  lotQuantity,
                                                  priceCoinPenny,
                                                  priceCoinShiny));
        }
예제 #9
0
        public static async void ClientRequestExecuteTrade(
            IStaticWorldObject tradingStation,
            TradingStationLot lot,
            bool isPlayerBuying)
        {
            var mode = isPlayerBuying
                           ? TradingStationMode.StationSelling
                           : TradingStationMode.StationBuying;

            if (!Instance.SharedValidateCanTrade(tradingStation,
                                                 lot,
                                                 mode,
                                                 Client.Characters.CurrentPlayerCharacter,
                                                 out var checkResult))
            {
                ClientShowErrorNotification(lot, checkResult, isPlayerBuying);
                return;
            }

            var publicState = GetPublicState(tradingStation);
            var lotIndex    = publicState.Lots.IndexOf(lot);

            checkResult = await Instance.CallServer(
                _ => _.ServerRemote_ExecuteTrade(tradingStation,
                                                 (byte)lotIndex,
                                                 mode));

            if (checkResult != TradingResult.Success)
            {
                ClientShowErrorNotification(lot, checkResult, isPlayerBuying);
            }
            else
            {
                ClientShowSuccessNotification(lot, isPlayerBuying);
            }
        }
예제 #10
0
        public ViewModelTradingStationLotEditor(
            TradingStationLot lot,
            Action callbackSave,
            Action callbackCancel)
        {
            this.lot             = lot;
            this.IsStationBuying = ProtoObjectTradingStation.GetPublicState(
                (IStaticWorldObject)lot.GameObject).Mode
                                   == TradingStationMode.StationBuying;
            this.callbackCancel = callbackCancel;
            this.callbackSave   = callbackSave;

            this.selectedProtoItem = lot.ProtoItem;
            this.PriceCoinShiny    = lot.PriceCoinShiny;
            this.PriceCoinPenny    = lot.PriceCoinPenny;
            this.LotQuantity       = Math.Max((ushort)1, lot.LotQuantity);
            this.MinQualityPercent = lot.MinQualityPercent;

            // no need to order as the ordering is applied later
            this.allItemsList      = Api.FindProtoEntities <IProtoItem>().ToList();
            this.existingItemsList = this.GetExistingItemsList();

            this.RefreshLists();
        }
예제 #11
0
        private bool SharedValidateCanTrade(
            IStaticWorldObject tradingStation,
            TradingStationLot lot,
            TradingStationMode mode,
            ICharacter character,
            out TradingResult error)
        {
            var protoTradingStation = tradingStation.ProtoStaticWorldObject;

            var publicState = GetPublicState(tradingStation);

            if (publicState.Mode != mode)
            {
                throw new Exception("Trading station has different trading mode");
            }

            if (!protoTradingStation
                .SharedCanInteract(character, tradingStation, writeToLog: false))
            {
                error = TradingResult.ErrorCannotInteract;
                return(false);
            }

            var lots = publicState.Lots;

            var isLotFound = false;

            foreach (var otherLot in lots)
            {
                if (otherLot == lot)
                {
                    // found lot
                    isLotFound = true;
                    break;
                }
            }

            if (!isLotFound)
            {
                error = TradingResult.ErrorLotNotFound;
                return(false);
            }

            if (lot.State == TradingStationLotState.Disabled)
            {
                error = TradingResult.ErrorLotNotActive;
                return(false);
            }

            if (mode == TradingStationMode.StationBuying)
            {
                // ensure that the character has required item count to sell
                if (lot.LotQuantity > character.CountItemsOfType(lot.ProtoItem))
                {
                    error = TradingResult.ErrorNotEnoughItemsOnPlayer;
                    return(false);
                }

                if (IsServer)
                {
                    // ensure station has enough money to pay for these items
                    var tradingStationItemsContainer = GetPrivateState(tradingStation).StockItemsContainer;
                    if (!tradingStationItemsContainer.ContainsItemsOfType(
                            ProtoItemCoinPenny.Value,
                            requiredCount: lot.PriceCoinPenny) ||
                        !tradingStationItemsContainer.ContainsItemsOfType(
                            ProtoItemCoinShiny.Value,
                            requiredCount: lot.PriceCoinShiny))
                    {
                        error = TradingResult.ErrorNotEnoughMoneyOnStation;
                        return(false);
                    }
                }
            }
            else // if station selling
            {
                if (lot.CountAvailable == 0)
                {
                    error = TradingResult.ErrorNotEnoughItemsOnStation;
                    return(false);
                }

                // ensure player has enough money to pay for these items
                if (!character.ContainsItemsOfType(
                        ProtoItemCoinPenny.Value,
                        requiredCount: lot.PriceCoinPenny) ||
                    !character.ContainsItemsOfType(
                        ProtoItemCoinShiny.Value,
                        requiredCount: lot.PriceCoinShiny))
                {
                    error = TradingResult.ErrorNotEnoughMoneyOnPlayer;
                    return(false);
                }
            }

            // no error
            error = TradingResult.Success;
            return(true);
        }
예제 #12
0
        private static TradingResult ServerExecuteTrade(
            TradingStationLot lot,
            IItemsContainerProvider sellerContainers,
            IItemsContainerProvider buyerContainers,
            bool isPlayerBuying)
        {
            // find items to buy by other party
            if (!SharedTryFindItemsOfType(sellerContainers, lot.ProtoItem, lot.LotQuantity, out var itemsToSell))
            {
                return(isPlayerBuying
                           ? TradingResult.ErrorNotEnoughItemsOnStation
                           : TradingResult.ErrorNotEnoughItemsOnPlayer);
            }

            // try to find money to pay to other party
            var countCoinPenny = (uint)lot.PriceCoinPenny;
            var countCoinShiny = (uint)lot.PriceCoinShiny;

            if (!SharedTryFindItemsOfType(buyerContainers,
                                          ProtoItemCoinPenny.Value,
                                          countCoinPenny,
                                          out _) ||
                !SharedTryFindItemsOfType(buyerContainers,
                                          ProtoItemCoinShiny.Value,
                                          countCoinShiny,
                                          out _))
            {
                return(isPlayerBuying
                           ? TradingResult.ErrorNotEnoughMoneyOnStation
                           : TradingResult.ErrorNotEnoughMoneyOnPlayer);
            }

            // ensure there is enough space to store the sold items
            if (!ServerItems.CanCreateItem(buyerContainers, lot.ProtoItem, lot.LotQuantity))
            {
                return(isPlayerBuying
                           ? TradingResult.ErrorNotEnoughSpaceOnPlayerForPurchasedItem
                           : TradingResult.ErrorNotEnoughSpaceOnStationForSoldItem);
            }

            // try create money in the source containers
            var sourceContainerResult = new CreateItemResult()
            {
                IsEverythingCreated = true
            };

            if (lot.PriceCoinPenny > 0)
            {
                sourceContainerResult.MergeWith(
                    ServerItems.CreateItem(ProtoItemCoinPenny.Value,
                                           sellerContainers,
                                           countCoinPenny));
            }

            if (lot.PriceCoinShiny > 0)
            {
                sourceContainerResult.MergeWith(
                    ServerItems.CreateItem(ProtoItemCoinShiny.Value,
                                           sellerContainers,
                                           countCoinShiny));
            }

            if (!sourceContainerResult.IsEverythingCreated)
            {
                sourceContainerResult.Rollback();
                // TODO: check this
                return(isPlayerBuying
                           ? TradingResult.ErrorNotEnoughSpaceOnStationForSoldItem
                           : TradingResult.ErrorNotEnoughSpaceOnPlayerForPurchasedItem);
            }

            // try moving (bought) items
            var itemsCountToDestroyRemains = (int)lot.LotQuantity;

            foreach (var item in itemsToSell)
            {
                if (itemsCountToDestroyRemains <= 0)
                {
                    break;
                }

                ServerItems.MoveOrSwapItem(item,
                                           buyerContainers,
                                           out var movedCount,
                                           countToMove: (ushort)itemsCountToDestroyRemains);
                itemsCountToDestroyRemains -= movedCount;
            }

            if (itemsCountToDestroyRemains > 0)
            {
                // should be impossible
                Logger.Error(
                    "Cannot move all sold items! But we've verified that the sellerContainers have them all...");
            }

            if (countCoinPenny > 0)
            {
                ServerItems.DestroyItemsOfType(buyerContainers, ProtoItemCoinPenny.Value, countCoinPenny, out _);
            }

            if (countCoinShiny > 0)
            {
                ServerItems.DestroyItemsOfType(buyerContainers, ProtoItemCoinShiny.Value, countCoinShiny, out _);
            }

            Logger.Important($"Successfully completed trading transaction: {lot}");
            return(TradingResult.Success);
        }
 public WindowTradingStationLotEditor(TradingStationLot lot)
 {
     this.lot = lot;
 }