/// <summary> /// Verify all conditions to pickup a dropped item. /// </summary> /// <param name="droppedItem">The dropped item.</param> private void PickUpDroppedItem(IItemEntity droppedItem) { // TODO: check if drop belongs to a party. if (droppedItem.Drop.HasOwner && droppedItem.Drop.Owner != _player) { _textPacketFactory.SendDefinedText(_player, DefineText.TID_GAME_PRIORITYITEMPER, $"\"{droppedItem.Object.Name}\""); return; } if (droppedItem.Drop.IsGold) { int droppedGoldAmount = droppedItem.Drop.Item.Quantity; if (_playerDataSystem.IncreaseGold(_player, droppedGoldAmount)) { _textPacketFactory.SendDefinedText(_player, DefineText.TID_GAME_REAPMONEY, droppedGoldAmount.ToString("###,###,###,###"), _player.PlayerData.Gold.ToString("###,###,###,###")); } } else { _inventorySystem.CreateItem(_player, droppedItem.Drop.Item, droppedItem.Drop.Item.Quantity); _textPacketFactory.SendDefinedText(_player, DefineText.TID_GAME_REAPITEM, $"\"{droppedItem.Object.Name}\""); } _moverPacketFactory.SendMotion(_player, ObjectMessageType.OBJMSG_PICKUP); droppedItem.Delete(); }
/// <inheritdoc /> public void ChangeFace(IPlayerEntity player, uint objectId, uint faceId, bool useCoupon) { if (!useCoupon) { if (player.PlayerData.Gold < _worldServerConfiguration.Customization.ChangeFaceCost) { _textPacketFactory.SendDefinedText(player, DefineText.TID_GAME_LACKMONEY); } else { player.VisualAppearance.FaceId = (int)faceId; _playerDataSystem.DecreaseGold(player, (int)_worldServerConfiguration.Customization.ChangeFaceCost); _customizationPacketFactory.SendChangeFace(player, faceId); } } else { Item couponItem = player.Inventory.GetItemById(DefineItem.II_SYS_SYS_SCR_FACEOFFFREE); if (couponItem == null) { _textPacketFactory.SendDefinedText(player, DefineText.TID_GAME_WARNNING_COUPON); return; } _inventorySystem.DeleteItem(player, couponItem, 1); _customizationPacketFactory.SendChangeFace(player, faceId); } }
public void UseFoodItem(IPlayerEntity player, Item foodItemToUse) { foreach (KeyValuePair <DefineAttributes, int> parameter in foodItemToUse.Data.Params) { if (parameter.Key == DefineAttributes.HP || parameter.Key == DefineAttributes.MP || parameter.Key == DefineAttributes.FP) { int currentPoints = player.Attributes[parameter.Key]; int maxPoints = PlayerHelper.GetMaxPoints(player, parameter.Key); int itemMaxRecovery = foodItemToUse.Data.AbilityMin; if (parameter.Value >= 0) { if (currentPoints >= itemMaxRecovery) { float limitedRecovery = parameter.Value * 0.3f; if (currentPoints + limitedRecovery > maxPoints) { currentPoints = maxPoints; } else { switch (parameter.Key) { case DefineAttributes.HP: _textPacketFactory.SendDefinedText(player, DefineText.TID_GAME_LIMITHP); break; case DefineAttributes.MP: _textPacketFactory.SendDefinedText(player, DefineText.TID_GAME_LIMITMP); break; case DefineAttributes.FP: _textPacketFactory.SendDefinedText(player, DefineText.TID_GAME_LIMITFP); break; } currentPoints += (int)limitedRecovery; } } else { currentPoints = Math.Min(currentPoints + parameter.Value, maxPoints); } } PlayerHelper.SetPoints(player, parameter.Key, currentPoints); _moverPacketFactory.SendUpdateAttributes(player, parameter.Key, player.Attributes[parameter.Key]); } else { // TODO: food triggers a skill. _logger.LogWarning($"Activating a skill throught food."); _textPacketFactory.SendFeatureNotImplemented(player, "skill with food"); } } DecreaseItem(player, foodItemToUse); }
/// <inheritdoc /> public void BuyItem(IPlayerEntity player, NpcShopItemInfo shopItemInfo, int quantity) { var npc = player.FindEntity <INpcEntity>(x => x.Object.Name == player.PlayerData.CurrentShopName); if (npc == null) { _logger.LogError($"ShopSystem: Cannot find NPC: {player.PlayerData.CurrentShopName}"); return; } if (!npc.NpcData.HasShop) { _logger.LogError($"ShopSystem: NPC {npc.Object.Name} doesn't have a shop."); return; } if (shopItemInfo.Tab < 0 || shopItemInfo.Tab >= ShopData.DefaultTabCount) { _logger.LogError($"Attempt to buy an item from {npc.Object.Name} shop tab that is out of range."); return; } ItemContainerComponent shopTab = npc.Shop.ElementAt(shopItemInfo.Tab); if (shopItemInfo.Slot < 0 || shopItemInfo.Slot > shopTab.MaxCapacity - 1) { _logger.LogError($"ShopSystem: Item slot index was out of tab bounds. Slot: {shopItemInfo.Slot}"); return; } Item shopItem = shopTab.GetItemAtSlot(shopItemInfo.Slot); if (shopItem.Id != shopItemInfo.ItemId) { _logger.LogError($"ShopSystem: Shop item id doens't match the item id that {player.Object.Name} is trying to buy."); return; } if (player.PlayerData.Gold < shopItem.Data.Cost) { _logger.LogTrace($"ShopSystem: {player.Object.Name} doens't have enough gold to buy item {shopItem.Data.Name} at {shopItem.Data.Cost}."); _textPacketFactory.SendDefinedText(player, DefineText.TID_GAME_LACKMONEY); return; } int itemsCreatedCount = _inventorySystem.CreateItem(player, shopItem, quantity); if (itemsCreatedCount > 0) { _playerDataSystem.DecreaseGold(player, shopItem.Data.Cost * itemsCreatedCount); } }
/// <inheritdoc /> public void PutItem(IPlayerEntity player, int itemUniqueId, int quantity, int itemType, int destinationSlot) { _logger.LogTrace($"Player '{player.Object.Name}' is putting item with unique id '{itemUniqueId}' to trade slot '{destinationSlot}'."); ThrowIfPlayerTrade(player, isTrading: false); IPlayerEntity target = GetTargetEntity(player, player.Trade.TargetId); try { ThrowIfPlayerTrade(target, isTrading: false); } catch (InvalidOperationException) { CancelTradeAndRefund(player); CancelTradeAndRefund(target); throw; } if (player.Trade.State != TradeComponent.TradeState.Item || target.Trade.State != TradeComponent.TradeState.Item) { _tradePacketFactory.SendTradePutError(player); return; } Item inventoryItem = player.Inventory.GetItemAtIndex(itemUniqueId); if (inventoryItem == null) { throw new ArgumentNullException($"Cannot find item with unique id '{itemUniqueId}' in '{player.Object.Name}' inventory.');"); } if (!IsTradeItemValid(player, inventoryItem, out DefineText errorText)) { _textPacketFactory.SendDefinedText(player, errorText); } int tradingQuantity = Math.Min(quantity, inventoryItem.Quantity); if (!player.Trade.Items.IsSlotAvailable(destinationSlot)) { _logger.LogTrace($"Destination slot '{destinationSlot}' is not available for player '{player.Object.Name}'"); return; } inventoryItem.ExtraUsed = tradingQuantity; player.Trade.Items.SetItemAtIndex(inventoryItem.Clone(), destinationSlot); player.Trade.ItemCount++; _tradePacketFactory.SendTradePut(player, trader: player, (byte)destinationSlot, (byte)itemType, (byte)inventoryItem.UniqueId, (short)tradingQuantity); _tradePacketFactory.SendTradePut(target, trader: player, (byte)destinationSlot, (byte)itemType, (byte)inventoryItem.UniqueId, (short)tradingQuantity); }
/// <inheritdoc /> public bool IncreaseGold(IPlayerEntity player, int goldAmount) { // We cast player gold to long because otherwise it would use Int32 arithmetic and would overflow long gold = (long)player.PlayerData.Gold + goldAmount; if (gold > int.MaxValue || gold < 0) // Check gold overflow { _textPacketFactory.SendDefinedText(player, DefineText.TID_GAME_TOOMANYMONEY_USE_PERIN); return(false); } else { player.PlayerData.Gold = (int)gold; _moverPacketFactory.SendUpdateAttributes(player, DefineAttributes.GOLD, player.PlayerData.Gold); } return(true); }
/// <inheritdoc /> public void Execute(IPlayerEntity player, object[] parameters) { _logger.LogTrace($"{player.Object.Name} wants to create an item"); if (parameters.Length <= 0) { throw new ArgumentException($"Create item command must have at least one parameter.", nameof(parameters)); } if (!player.Inventory.HasAvailableSlots()) { _textPacketFactory.SendDefinedText(player, DefineText.TID_GAME_LACKSPACE); return; } int quantity = parameters.Length >= 2 ? Convert.ToInt32(parameters[1]) : 1; byte refine = parameters.Length >= 3 ? Convert.ToByte(parameters[2]) : (byte)0; ElementType element = parameters.Length >= 4 ? (ElementType)Enum.Parse(typeof(ElementType), parameters[3].ToString(), true) : default; byte elementRefine = parameters.Length >= 5 ? Convert.ToByte(parameters[4]) : (byte)0; string itemInput = parameters[0].ToString(); Item itemToCreate; if (!int.TryParse(itemInput, out int itemId)) { itemToCreate = _itemFactory.CreateItem(itemInput, refine, element, elementRefine, player.PlayerData.Id); } else { itemToCreate = _itemFactory.CreateItem(itemId, refine, element, elementRefine, player.PlayerData.Id); } if (itemToCreate != null) { _inventorySystem.CreateItem(player, itemToCreate, quantity, player.PlayerData.Id); } }
/// <inheritdoc /> public void UpdateSkills(IPlayerEntity player, IReadOnlyDictionary <int, int> skillsToUpdate) { int requiredSkillPoints = 0; foreach (KeyValuePair <int, int> skill in skillsToUpdate) { int skillId = skill.Key; int skillLevel = skill.Value; SkillInfo playerSkill = player.SkillTree.GetSkill(skillId); if (playerSkill == null) { _textPacketFactory.SendDefinedText(player, DefineText.TID_RESKILLPOINT_ERROR); _logger.LogError($"Cannot find skill with id '{skillId}' for player '{player}'."); return; } if (playerSkill.Level == skillLevel) { // Skill hasn't change continue; } if (player.Object.Level < playerSkill.Data.RequiredLevel) { _textPacketFactory.SendDefinedText(player, DefineText.TID_RESKILLPOINT_ERROR); _logger.LogError($"Cannot update skill with '{skillId}' for player '{player}'. Player need to be level '{playerSkill.Data.RequiredLevel}' to learn this skill."); return; } if (!CheckRequiredSkill(playerSkill.Data.RequiredSkillId1, playerSkill.Data.RequiredSkillLevel1, skillsToUpdate)) { SkillData requiredSkill1 = _gameResources.Skills[playerSkill.Data.RequiredSkillId1]; _textPacketFactory.SendDefinedText(player, DefineText.TID_RESKILLPOINT_ERROR); _logger.LogError($"Cannot update skill with '{skillId}' for player '{player}'. Skill '{requiredSkill1.Name}' must be at least Lv.{requiredSkill1.RequiredSkillLevel1}"); return; } if (!CheckRequiredSkill(playerSkill.Data.RequiredSkillId2, playerSkill.Data.RequiredSkillLevel2, skillsToUpdate)) { SkillData requiredSkill2 = _gameResources.Skills[playerSkill.Data.RequiredSkillId2]; _textPacketFactory.SendDefinedText(player, DefineText.TID_RESKILLPOINT_ERROR); _logger.LogError($"Cannot update skill with '{skillId}' for player '{player}'. Skill '{requiredSkill2.Name}' must be at least Lv.{requiredSkill2.RequiredSkillLevel1}"); return; } if (skillLevel < 0 || skillLevel < playerSkill.Level || skillLevel > playerSkill.Data.MaxLevel) { _textPacketFactory.SendDefinedText(player, DefineText.TID_RESKILLPOINT_ERROR); _logger.LogError($"Cannot update skill with '{skillId}' for player '{player}'. The skill level is out of bounds."); return; } if (!SkillPointUsage.TryGetValue(playerSkill.Data.JobType, out int requiredSkillPointAmount)) { _textPacketFactory.SendDefinedText(player, DefineText.TID_RESKILLPOINT_ERROR); _logger.LogError($"Cannot update skill with '{skillId}' for player '{player}'. Cannot find required skill point for job type '{playerSkill.Data.JobType}'."); return; } requiredSkillPoints += (skillLevel - playerSkill.Level) * requiredSkillPointAmount; } if (player.Statistics.SkillPoints < requiredSkillPoints) { _logger.LogError($"Cannot update skills for player '{player}'. Not enough skill points."); _textPacketFactory.SendDefinedText(player, DefineText.TID_RESKILLPOINT_ERROR); return; } player.Statistics.SkillPoints -= (ushort)requiredSkillPoints; foreach (KeyValuePair <int, int> skill in skillsToUpdate) { int skillId = skill.Key; int skillLevel = skill.Value; player.SkillTree.SetSkillLevel(skillId, skillLevel); } _specialEffectPacketFactory.SendSpecialEffect(player, DefineSpecialEffects.XI_SYS_EXCHAN01, false); _skillPacketFactory.SendSkillTreeUpdate(player); }
/// <inheritdoc /> public int CreateItem(IPlayerEntity player, ItemDescriptor item, int quantity, int creatorId = -1, bool sendToPlayer = true) { int createdAmount = 0; if (item.Data.IsStackable) { for (var i = 0; i < InventoryContainerComponent.InventorySize; i++) { Item inventoryItem = player.Inventory.GetItemAtIndex(i); if (inventoryItem?.Id == item.Id) { if (inventoryItem.Quantity + quantity > item.Data.PackMax) { int boughtQuantity = inventoryItem.Data.PackMax - inventoryItem.Quantity; createdAmount = boughtQuantity; quantity -= boughtQuantity; inventoryItem.Quantity = inventoryItem.Data.PackMax; } else { createdAmount = quantity; inventoryItem.Quantity += quantity; quantity = 0; } if (sendToPlayer) { _inventoryPacketFactory.SendItemUpdate(player, UpdateItemType.UI_NUM, inventoryItem.UniqueId, inventoryItem.Quantity); } } } if (quantity > 0) { int availableSlot = player.Inventory.GetAvailableSlot(); if (availableSlot == -1) { _textPacketFactory.SendDefinedText(player, DefineText.TID_GAME_LACKSPACE); } else { Item newItem = _itemFactory.CreateItem(item.Id, item.Refine, item.Element, item.ElementRefine, creatorId); if (newItem == null) { throw new ArgumentNullException(nameof(newItem)); } newItem.Quantity = quantity; newItem.Slot = availableSlot; player.Inventory.SetItemAtSlot(newItem, availableSlot); if (sendToPlayer) { _inventoryPacketFactory.SendItemCreation(player, newItem); } createdAmount += quantity; } } } else { while (quantity > 0) { int availableSlot = player.Inventory.GetAvailableSlot(); if (availableSlot == -1) { _textPacketFactory.SendDefinedText(player, DefineText.TID_GAME_LACKSPACE); break; } Item newItem = _itemFactory.CreateItem(item.Id, item.Refine, item.Element, item.ElementRefine, creatorId); if (newItem == null) { throw new ArgumentNullException(nameof(newItem)); } newItem.Quantity = 1; newItem.Slot = availableSlot; player.Inventory.SetItemAtSlot(newItem, availableSlot); if (sendToPlayer) { _inventoryPacketFactory.SendItemCreation(player, newItem); } createdAmount++; quantity--; } } return(createdAmount); }