예제 #1
0
        public void HandleSalvaging(List <uint> salvageItems)
        {
            var salvageBags    = new List <WorldObject>();
            var salvageResults = new SalvageResults();

            foreach (var itemGuid in salvageItems)
            {
                var item = GetInventoryItem(itemGuid);
                if (item == null)
                {
                    log.Debug($"[CRAFTING] {Name}.HandleSalvaging({itemGuid:X8}): couldn't find inventory item");
                    continue;
                }

                if (item.MaterialType == null)
                {
                    log.Warn($"{Name}.HandleSalvaging({item.Name}): no material type");
                    continue;
                }

                if (IsTrading && ItemsInTradeWindow.Contains(item.Guid))
                {
                    SendWeenieError(WeenieError.YouCannotSalvageItemsInTrading);
                    continue;
                }

                if (item.Workmanship == null || item.Retained)
                {
                    continue;
                }

                AddSalvage(salvageBags, item, salvageResults);

                // can any salvagable items be stacked?
                TryConsumeFromInventoryWithNetworking(item);
            }

            // add salvage bags
            foreach (var salvageBag in salvageBags)
            {
                TryCreateInInventoryWithNetworking(salvageBag);
            }

            // send network messages
            if (!SquelchManager.Squelches.Contains(this, ChatMessageType.Salvaging))
            {
                foreach (var kvp in salvageResults.GetMessages())
                {
                    Session.Network.EnqueueSend(new GameEventSalvageOperationsResult(Session, kvp.Key, kvp.Value));
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Handles the 'GameAction 0x36 - UseItem' network message
        /// when player double clicks an item
        /// </summary>
        public void HandleActionUseItem(uint itemGuid)
        {
            if (PKLogout)
            {
                SendUseDoneEvent(WeenieError.YouHaveBeenInPKBattleTooRecently);
                return;
            }

            StopExistingMoveToChains();

            var item = FindObject(itemGuid, SearchLocations.MyInventory | SearchLocations.MyEquippedItems | SearchLocations.Landblock);

            if (IsTrading && ItemsInTradeWindow.Contains(item.Guid))
            {
                SendUseDoneEvent(WeenieError.TradeItemBeingTraded);
                //SendWeenieError(WeenieError.TradeItemBeingTraded);
                return;
            }

            if (item != null)
            {
                if (item.CurrentLandblock != null && !item.Visibility && item.Guid != LastOpenedContainerId)
                {
                    if (IsBusy)
                    {
                        SendUseDoneEvent(WeenieError.YoureTooBusy);
                        return;
                    }

                    CreateMoveToChain(item, (success) => TryUseItem(item, success));
                }
                else
                {
                    TryUseItem(item);
                }
            }
            else
            {
                log.Debug($"{Name}.HandleActionUseItem({itemGuid:X8}): couldn't find object");
                SendUseDoneEvent();
            }
        }
예제 #3
0
        /// <summary>
        /// Handles the 'GameAction 0x35 - UseWithTarget' network message
        /// when player double clicks an inventory item resulting in a target indicator
        /// and then clicks another item
        /// </summary>
        public void HandleActionUseWithTarget(uint sourceObjectGuid, uint targetObjectGuid)
        {
            if (PKLogout)
            {
                SendUseDoneEvent(WeenieError.YouHaveBeenInPKBattleTooRecently);
                return;
            }

            StopExistingMoveToChains();

            // source item is always in our possession
            var sourceItem = FindObject(sourceObjectGuid, SearchLocations.MyInventory | SearchLocations.MyEquippedItems, out _, out _, out var sourceItemIsEquipped);

            if (sourceItem == null)
            {
                log.Warn($"{Name}.HandleActionUseWithTarget({sourceObjectGuid:X8}, {targetObjectGuid:X8}): couldn't find {sourceObjectGuid:X8}");
                SendUseDoneEvent();
                return;
            }

            // handle casters with built-in spells
            if (sourceItemIsEquipped)
            {
                if (sourceItem.SpellDID != null)
                {
                    // check activation requirements
                    var result = sourceItem.CheckUseRequirements(this);
                    if (!result.Success)
                    {
                        if (result.Message != null)
                        {
                            Session.Network.EnqueueSend(result.Message);
                        }

                        SendUseDoneEvent();
                    }
                    else
                    {
                        HandleActionCastTargetedSpell(targetObjectGuid, sourceItem.SpellDID ?? 0, true);
                    }
                }
                else
                {
                    SendUseDoneEvent();
                }

                return;
            }

            // Resolve the guid to an object that is either in our possession or on the Landblock
            var target = FindObject(targetObjectGuid, SearchLocations.MyInventory | SearchLocations.MyEquippedItems | SearchLocations.Landblock);

            if (target == null)
            {
                log.Warn($"{Name}.HandleActionUseWithTarget({sourceObjectGuid:X8}, {targetObjectGuid:X8}): couldn't find {targetObjectGuid:X8}");
                SendUseDoneEvent();
                return;
            }

            if (IsTrading)
            {
                if (ItemsInTradeWindow.Contains(sourceItem.Guid))
                {
                    SendUseDoneEvent(WeenieError.TradeItemBeingTraded);
                    //SendWeenieError(WeenieError.TradeItemBeingTraded);
                    return;
                }
                if (ItemsInTradeWindow.Contains(target.Guid))
                {
                    SendUseDoneEvent(WeenieError.TradeItemBeingTraded);
                    //SendWeenieError(WeenieError.TradeItemBeingTraded);
                    return;
                }
            }

            // re-verify client checks
            if (((sourceItem.TargetType ?? ItemType.None) & target.ItemType) == ItemType.None)
            {
                // ItemHolder::TargetCompatibleWithObject
                SendTransientError($"Cannot use the {sourceItem.Name} with the {target.Name}");
                SendUseDoneEvent();
                return;
            }

            sourceItem.HandleActionUseOnTarget(this, target);
        }
예제 #4
0
        /// <summary>
        /// Client Calls this when Sell is clicked.
        /// </summary>
        public void HandleActionSellItem(List <ItemProfile> itemprofiles, uint vendorGuid)
        {
            if (IsBusy)
            {
                SendUseDoneEvent(WeenieError.YoureTooBusy);
                return;
            }

            var vendor = CurrentLandblock?.GetObject(vendorGuid) as Vendor;

            if (vendor == null)
            {
                SendUseDoneEvent(WeenieError.NoObject);
                return;
            }

            itemprofiles = VerifySellItems(itemprofiles, vendor);

            var allPossessions = GetAllPossessions();

            var sellList = new List <WorldObject>();

            var acceptedItemTypes = (ItemType)(vendor.MerchandiseItemTypes ?? 0);

            foreach (ItemProfile profile in itemprofiles)
            {
                var item = allPossessions.FirstOrDefault(i => i.Guid.Full == profile.ObjectGuid);

                if (item == null)
                {
                    continue;
                }

                if ((acceptedItemTypes & item.ItemType) == 0 || !item.IsSellable || item.Retained)
                {
                    var itemName = (item.StackSize ?? 1) > 1 ? item.GetPluralName() : item.Name;
                    Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, $"The {itemName} is unsellable.")); // retail message did not include item name, leaving in that for now.

                    continue;
                }

                if (item.Value < 1)
                {
                    var itemName = (item.StackSize ?? 1) > 1 ? item.GetPluralName() : item.Name;
                    Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, $"The {itemName} has no value and cannot be sold.")); // retail message did not include item name, leaving in that for now.

                    continue;
                }

                if (IsTrading && ItemsInTradeWindow.Contains(item.Guid))
                {
                    var itemName = (item.StackSize ?? 1) > 1 ? item.GetPluralName() : item.Name;
                    Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, $"You cannot sell that! The {itemName} is currently being traded.")); // custom message?

                    continue;
                }

                sellList.Add(item);
            }

            if (sellList.Count == 0)
            {
                Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, Guid.Full));
                SendUseDoneEvent(WeenieError.None);
                return;
            }

            var payoutCoinAmount = vendor.CalculatePayoutCoinAmount(sellList);

            if (payoutCoinAmount < 0)
            {
                Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, "Transaction failed."));
                log.Warn($"{Name} (0x({Guid}) tried to sell something to {vendor.Name} (0x{vendor.Guid}) resulting in a payout of {payoutCoinAmount} pyreals.");
                Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, Guid.Full));
                SendUseDoneEvent();
                return;
            }

            var playerFreeInventorySlots = GetFreeInventorySlots();
            var playerAvailableBurden    = GetAvailableBurden();

            var numberOfCoinStacksToCreate = PreCheckItem(coinStackWeenieClassId, payoutCoinAmount, 0, GetFreeInventorySlots(), GetAvailableBurden(), out var totalEncumburanceOfCoinStacks, out _);

            var playerDoesNotHaveEnoughPackSpace      = playerFreeInventorySlots < numberOfCoinStacksToCreate;
            var playerDoesNotHaveEnoughBurdenCapacity = playerAvailableBurden < totalEncumburanceOfCoinStacks;

            if (playerDoesNotHaveEnoughPackSpace || playerDoesNotHaveEnoughBurdenCapacity)
            {
                if (playerDoesNotHaveEnoughBurdenCapacity)
                {
                    Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, "You are too encumbered to sell that!"));
                }
                else // if (playerDoesNotHaveEnoughPackSpace)
                {
                    Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, "You do not have enough free pack space to sell that!"));
                }
                Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, Guid.Full));
                SendUseDoneEvent();
                return;
            }

            var payoutCoinStacks = CreatePayoutCoinStacks(payoutCoinAmount);

            // Make sure we have enough pack space for the payout
            if (GetFreeInventorySlots() + sellList.Count - payoutCoinStacks.Count < 0)
            {
                Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, "Not enough inventory space!")); // TODO: find retail messages
                Session.Network.EnqueueSend(new GameEventInventoryServerSaveFailed(Session, Guid.Full));

                foreach (var item in payoutCoinStacks)
                {
                    item.Destroy();
                }

                SendUseDoneEvent(WeenieError.FullInventoryLocation);
                return;
            }

            // Remove the items we're selling from our inventory
            foreach (var item in sellList)
            {
                if (TryRemoveFromInventoryWithNetworking(item.Guid, out _, RemoveFromInventoryAction.SellItem) || TryDequipObjectWithNetworking(item.Guid, out _, DequipObjectAction.SellItem))
                {
                    Session.Network.EnqueueSend(new GameEventItemServerSaysContainId(Session, item, vendor));
                }
                else
                {
                    log.WarnFormat("Item 0x{0:X8}:{1} for player {2} not found in HandleActionSellItem.", item.Guid.Full, item.Name, Name); // This shouldn't happen
                }
            }

            // Send the list of items to the vendor to complete the transaction
            vendor.ProcessItemsForPurchase(this, sellList);

            // Add the payout to inventory
            foreach (var item in payoutCoinStacks)
            {
                if (!TryCreateInInventoryWithNetworking(item)) // This shouldn't happen
                {
                    log.WarnFormat("Payout 0x{0:X8}:{1} for player {2} failed to add to inventory HandleActionSellItem.", item.Guid.Full, item.Name, Name);
                    item.Destroy();
                }
            }

            UpdateCoinValue(false);

            Session.Network.EnqueueSend(new GameMessageSound(Guid, Sound.PickUpItem));

            SendUseDoneEvent();
        }
예제 #5
0
        /// <summary>
        /// Handles the 'GameAction 0x35 - UseWithTarget' network message
        /// when player double clicks an inventory item resulting in a target indicator
        /// and then clicks another item
        /// </summary>
        public void HandleActionUseWithTarget(uint sourceObjectGuid, uint targetObjectGuid)
        {
            if (PKLogout)
            {
                SendUseDoneEvent(WeenieError.YouHaveBeenInPKBattleTooRecently);
                return;
            }

            StopExistingMoveToChains();

            // source item is always in our possession
            var sourceItem = FindObject(sourceObjectGuid, SearchLocations.MyInventory | SearchLocations.MyEquippedItems, out _, out _, out var sourceItemIsEquipped);

            if (sourceItem == null)
            {
                log.Warn($"{Name}.HandleActionUseWithTarget({sourceObjectGuid:X8}, {targetObjectGuid:X8}): couldn't find {sourceObjectGuid:X8}");
                SendUseDoneEvent();
                return;
            }

            // handle casters with built-in spells
            if (sourceItemIsEquipped)
            {
                if (sourceItem.SpellDID != null)
                {
                    // check activation requirements
                    var result = sourceItem.CheckUseRequirements(this);
                    if (!result.Success)
                    {
                        if (result.Message != null)
                        {
                            Session.Network.EnqueueSend(result.Message);
                        }

                        SendUseDoneEvent();
                    }
                    else
                    {
                        HandleActionCastTargetedSpell(targetObjectGuid, sourceItem.SpellDID ?? 0, true);
                    }
                }
                else
                {
                    SendUseDoneEvent();
                }

                return;
            }

            // Resolve the guid to an object that is either in our possession or on the Landblock
            var target = FindObject(targetObjectGuid, SearchLocations.MyInventory | SearchLocations.MyEquippedItems | SearchLocations.Landblock);

            if (target == null)
            {
                log.Warn($"{Name}.HandleActionUseWithTarget({sourceObjectGuid:X8}, {targetObjectGuid:X8}): couldn't find {targetObjectGuid:X8}");
                SendUseDoneEvent();
                return;
            }

            if (IsTrading)
            {
                if (ItemsInTradeWindow.Contains(sourceItem.Guid))
                {
                    SendUseDoneEvent(WeenieError.TradeItemBeingTraded);
                    //SendWeenieError(WeenieError.TradeItemBeingTraded);
                    return;
                }
                if (ItemsInTradeWindow.Contains(target.Guid))
                {
                    SendUseDoneEvent(WeenieError.TradeItemBeingTraded);
                    //SendWeenieError(WeenieError.TradeItemBeingTraded);
                    return;
                }
            }

            // re-verify client checks
            if (((sourceItem.TargetType ?? ItemType.None) & target.ItemType) == ItemType.None)
            {
                // ItemHolder::TargetCompatibleWithObject
                SendTransientError($"Cannot use the {sourceItem.Name} with the {target.Name}");
                SendUseDoneEvent();
                return;
            }

            if (target.CurrentLandblock != null && target != this)
            {
                // todo: verify target can be used remotely
                // move RecipeManager.VerifyUse logic into base Player_Use
                // this was avoided because i didn't want to deal with the ramifications of random items missing the correct ItemUseable flags,
                // and because there are still some ItemUseable flags with missing logic we haven't quite figured out yet

                if (IsBusy)
                {
                    SendUseDoneEvent(WeenieError.YoureTooBusy);
                    return;
                }

                CreateMoveToChain(target, (success) =>
                {
                    if (success)
                    {
                        sourceItem.HandleActionUseOnTarget(this, target);
                    }
                    else
                    {
                        SendUseDoneEvent();
                    }
                });
            }
            else
            {
                sourceItem.HandleActionUseOnTarget(this, target);
            }
        }