/// <summary> /// Runs equipment updates if necessary. /// </summary> /// <param name="item"></param> /// <param name="source"></param> /// <param name="target"></param> private void CheckEquipMoved(Item item, Pocket source, Pocket target) { if (source.IsEquip()) { Send.EquipmentMoved(_creature, source); } if (target.IsEquip()) { Send.EquipmentChanged(_creature, item); } // Send stat update when moving equipment if (source.IsEquip() || target.IsEquip()) { this.UpdateEquipStats(); } }
/// <summary> /// Runs equipment updates if necessary. /// </summary> /// <param name="item"></param> /// <param name="source"></param> /// <param name="target"></param> private void CheckEquipMoved(Item item, Pocket source, Pocket target) { if (source.IsEquip()) { Send.EquipmentMoved(_creature, source); } if (target.IsEquip()) { Send.EquipmentChanged(_creature, item); } // Send stat update when moving equipment if (source.IsEquip() || target.IsEquip()) { Send.StatUpdate(_creature, StatUpdateType.Private, Stat.AttackMinBaseMod, Stat.AttackMaxBaseMod, Stat.InjuryMinBaseMod, Stat.InjuryMaxBaseMod, Stat.BalanceBaseMod, Stat.CriticalBaseMod, Stat.DefenseBaseMod, Stat.ProtectionBaseMod ); } }
protected virtual void EquipItem(Pocket pocket, uint itemClass, uint color1 = 0, uint color2 = 0, uint color3 = 0) { if (!pocket.IsEquip()) return; var item = new MabiItem(itemClass); item.Info.ColorA = color1; item.Info.ColorB = color2; item.Info.ColorC = color3; //var inPocket = this.Creature.GetItemInPocket(slot); //if (inPocket != null) // this.Creature.Items.Remove(inPocket); this.Creature.Inventory.ForceAdd(item, pocket); Send.EquipmentChanged(this.Creature, item); }
/// <summary> /// Adds item to NPC's inventory. /// </summary> /// <param name="pocket"></param> /// <param name="itemId"></param> /// <param name="color1"></param> /// <param name="color2"></param> /// <param name="color3"></param> /// <param name="state">For robes and helmets</param> protected void EquipItem(Pocket pocket, int itemId, uint color1 = 0, uint color2 = 0, uint color3 = 0, ItemState state = ItemState.Up) { if (this.NPC == null) throw new InvalidOperationException("NPC's race has to be set first."); if (!pocket.IsEquip()) { Log.Error("Pocket '{0}' is not for equipment ({1})", pocket, this.GetType().Name); return; } if (!AuraData.ItemDb.Exists(itemId)) { Log.Error("Unknown item '{0}' ({1})", itemId, this.GetType().Name); return; } var item = new Item(itemId); item.Info.Pocket = pocket; item.Info.Color1 = color1; item.Info.Color2 = color2; item.Info.Color3 = color3; item.Info.State = (byte)state; this.NPC.Inventory.InitAdd(item); }
/// <summary> /// Runs equipment updates if necessary. /// </summary> /// <param name="item"></param> /// <param name="source"></param> /// <param name="target"></param> private void CheckEquipMoved(Item item, Pocket source, Pocket target) { if (source.IsEquip()) Send.EquipmentMoved(_creature, source); if (target.IsEquip()) Send.EquipmentChanged(_creature, item); // Send stat update when moving equipment if (source.IsEquip() || target.IsEquip()) { Send.StatUpdate(_creature, StatUpdateType.Private, Stat.AttackMinBaseMod, Stat.AttackMaxBaseMod, Stat.WAttackMinBaseMod, Stat.WAttackMaxBaseMod, Stat.BalanceBaseMod, Stat.CriticalBaseMod, Stat.DefenseBaseMod, Stat.ProtectionBaseMod ); } }
/// <summary> /// Runs equipment updates if necessary. /// </summary> /// <param name="item"></param> /// <param name="source"></param> /// <param name="target"></param> private void CheckEquipMoved(Item item, Pocket source, Pocket target) { if (source.IsEquip()) Send.EquipmentMoved(_creature, source); if (target.IsEquip()) Send.EquipmentChanged(_creature, item); // Send stat update when moving equipment if (source.IsEquip() || target.IsEquip()) this.UpdateEquipStats(); }
/// <summary> /// Moving item between char and pet, used from handler. /// </summary> /// <param name="pet">Always the pet</param> /// <param name="item"></param> /// <param name="other">The "other" creature, player when taking out, pet when putting in.</param> /// <param name="target"></param> /// <param name="targetX"></param> /// <param name="targetY"></param> /// <returns></returns> public bool MovePet(Creature pet, Item item, Creature other, Pocket target, int targetX, int targetY) { if (!this.Has(target) || !other.Inventory.Has(target)) return false; var source = item.Info.Pocket; var amount = item.Info.Amount; // We have to copy the item to get a new id, otherwise there could // be collisions when saving, because the moved item is still in // the inventory of the pet/character (from the pov of the db). // http://dev.mabinoger.com/forum/index.php/topic/804-pet-inventory/ var newItem = new Item(item); Item collidingItem = null; lock (_pockets) { if (!other.Inventory._pockets[target].TryAdd(newItem, (byte)targetX, (byte)targetY, out collidingItem)) return false; // If amount differs (item was added to stack) if (collidingItem != null && newItem.Info.Amount != amount) { Send.ItemAmount(other, collidingItem); // Left overs, update if (newItem.Info.Amount > 0) { item.Info.Amount = newItem.Info.Amount; Send.ItemAmount(_creature, item); } // All in, remove from cursor. else { _pockets[item.Info.Pocket].Remove(item); Send.ItemRemove(_creature, item); } } else { // Remove the item from the source pocket _pockets[source].Remove(item); Send.ItemRemove(_creature, item, source); if (collidingItem != null) { // Remove colliding item Send.ItemRemove(other, collidingItem, target); var collidingItemCopy = new Item(collidingItem); // Toss it in, it should be the cursor. _pockets[source].Add(collidingItemCopy); Send.ItemNew(_creature, collidingItemCopy); } Send.ItemNew(other, newItem); Send.ItemMoveInfo(_creature, item, source, collidingItem); } } // Check movement pet.Inventory.CheckLeftHand(item, source, target); pet.Inventory.CheckRightHand(item, source, target); // Equip handling if (target.IsEquip()) { pet.Inventory.UpdateEquipReferences(); pet.Inventory.OnEquip(item); if (collidingItem != null) pet.Inventory.OnUnequip(collidingItem); pet.Inventory.UpdateEquipStats(); Send.EquipmentChanged(pet, newItem); } else if (source.IsEquip()) { pet.Inventory.UpdateEquipReferences(); pet.Inventory.OnUnequip(item); pet.Inventory.UpdateEquipStats(); Send.EquipmentMoved(pet, source); } return true; }
// Handlers // ------------------------------------------------------------------ /// <summary> /// Used from MoveItem handler. /// </summary> /// <remarks> /// The item is the one that's interacted with, the one picked up /// when taking it, the one being put into a packet when it's one /// the cursor. Colliding items switch places with it. /// </remarks> /// <param name="item">Item to move</param> /// <param name="target">Pocket to move it to</param> /// <param name="targetX"></param> /// <param name="targetY"></param> /// <returns></returns> public bool Move(Item item, Pocket target, byte targetX, byte targetY) { if (!this.Has(target)) return false; var source = item.Info.Pocket; var amount = item.Info.Amount; Item collidingItem = null; var collidingItemTarget = source; lock (_pockets) { // Hotfix for #200, ctrl+click-equipping. // If an item is moved from the inventory to a filled equip // slot, but there's not enough space in the source pocket // for the colliding item, it would vanish, because the Add // failed. ("Toss it in, it should be the cursor.") // // The following code tries to prevent that, by explicitly // checking if this is a ctrl+click-equip move, and whether // the potentially colliding item fits into the inventory. // // Is there a better way to solve this? Maybe a more // generalized one? *Without* reverting the move on fail? if (source != Pocket.Cursor && target.IsEquip()) { //Log.Debug("Inv2EqMove: {0} -> {1}", source, target); if ((collidingItem = _pockets[target].GetItemAt(0, 0)) != null) { var success = false; // Cursor will work by default, as it will be // empty after moving the new item out of it. if (source == Pocket.Cursor) { success = true; collidingItemTarget = Pocket.Cursor; } // Try main inv if (!success) { if (_pockets.ContainsKey(Pocket.Inventory)) { success = _pockets[Pocket.Inventory].HasSpace(collidingItem); collidingItemTarget = Pocket.Inventory; } } // VIP inv if (!success) { if (_pockets.ContainsKey(Pocket.VIPInventory)) { success = _pockets[Pocket.VIPInventory].HasSpace(collidingItem); collidingItemTarget = Pocket.VIPInventory; } } // Try bags if (_creature.Client.Account.PremiumServices.CanUseBags) { for (var i = Pocket.ItemBags; i <= Pocket.ItemBagsMax && !success; ++i) { if (_pockets.ContainsKey(i)) { success = _pockets[i].HasSpace(collidingItem); collidingItemTarget = i; } } } if (!success) { Send.Notice(_creature, Localization.Get("There is no room in your inventory.")); return false; } } } if (!_pockets[target].TryAdd(item, targetX, targetY, out collidingItem)) return false; // If amount differs (item was added to stack) if (collidingItem != null && (item.Info.Amount != amount || (item.Info.Amount == 0 && item.Data.Type != ItemType.Sac))) { Send.ItemAmount(_creature, collidingItem); // Left overs or sac, update if (item.Info.Amount > 0 || item.Data.Type == ItemType.Sac) { Send.ItemAmount(_creature, item); } // All in, remove from cursor. else { _pockets[item.Info.Pocket].Remove(item); Send.ItemRemove(_creature, item); } } else { // Remove the item from the source pocket _pockets[source].Remove(item); if (collidingItem != null) { // Move colliding item into the pocket ascertained to // be free in the beginning. if (!_pockets[collidingItemTarget].Add(collidingItem)) { // Should never happen, as it was checked above. Log.Error("CreatureInventory: Inv2EqMove error? Please report. {0} -> {1}", source, target); } } Send.ItemMoveInfo(_creature, item, source, collidingItem); } } // Inform about temp moves (items in temp don't count for quest objectives?) if (source == Pocket.Temporary && target == Pocket.Cursor) { this.OnItemEntersInventory(item); ChannelServer.Instance.Events.OnPlayerReceivesItem(_creature, item.Info.Id, item.Info.Amount); } // Check movement this.CheckLeftHand(item, source, target); this.CheckRightHand(item, source, target); // Equip handling if (target.IsEquip()) { this.UpdateEquipReferences(); this.OnEquip(item); if (collidingItem != null) this.OnUnequip(collidingItem); this.UpdateEquipStats(); Send.EquipmentChanged(_creature, item); } else if (source.IsEquip()) { this.UpdateEquipReferences(); this.OnUnequip(item); this.UpdateEquipStats(); Send.EquipmentMoved(_creature, source); } // Update trade window if (target == Pocket.Trade) { if (collidingItem != null) _creature.Temp.ActiveTrade.RemoveItem(_creature, collidingItem); _creature.Temp.ActiveTrade.AddItem(_creature, item); } if (source == Pocket.Trade) _creature.Temp.ActiveTrade.RemoveItem(_creature, item); // Update entrustment window if (target >= Pocket.EntrustmentItem1 && target <= Pocket.EntrustmentReward) { if (collidingItem != null) _creature.Temp.ActiveEntrustment.RemoveItem(collidingItem, target); _creature.Temp.ActiveEntrustment.AddItem(item, target); } if (source >= Pocket.EntrustmentItem1 && source <= Pocket.EntrustmentReward) _creature.Temp.ActiveEntrustment.RemoveItem(item, source); return true; }
// TODO: Add central "Add" method that all others use, for central stuff // like adding bag pockets. This wil require a GetFreePosition // method in the pockets. /// <summary> /// Tries to add item to pocket. Returns false if the pocket /// doesn't exist or there was no space. /// </summary> public bool Add(Item item, Pocket pocket) { var success = false; lock (_pockets) { if (!_pockets.ContainsKey(pocket)) return success; success = _pockets[pocket].Add(item); } if (success) { this.PrepareBags(item); Send.ItemNew(_creature, item); if (_creature.IsPlayer && pocket != Pocket.Temporary) { this.OnItemEntersInventory(item); // Notify everybody about receiving the item. ChannelServer.Instance.Events.OnPlayerReceivesItem(_creature, item.Info.Id, item.Amount); // If item was a sac, we have to notify the server about // receiving its *contents* as well. if (item.Data.StackType == StackType.Sac) ChannelServer.Instance.Events.OnPlayerReceivesItem(_creature, item.Data.StackItemId, item.Info.Amount); } if (pocket.IsEquip()) { this.UpdateEquipReferences(); this.OnEquip(item); this.UpdateEquipStats(); if (_creature.Region != Region.Limbo) Send.EquipmentChanged(_creature, item); } } return success; }
/// <summary> /// Sends EquipmentMoved and EquipmentChanged, if necessary. /// </summary> /// <param name="item"></param> /// <param name="source"></param> /// <param name="target"></param> private void CheckEquipMoved(MabiItem item, Pocket source, Pocket target) { if (source.IsEquip()) Send.EquipmentMoved(_creature, source); if (target.IsEquip()) { Send.EquipmentChanged(_creature, item); // TODO: Equip/Unequip item scripts switch (item.Info.Class) { // Umbrella Skill case 41021: case 41022: case 41023: case 41025: case 41026: case 41027: case 41061: case 41062: case 41063: if (!_creature.Skills.Has(SkillConst.Umbrella)) _creature.Skills.Give(SkillConst.Umbrella, SkillRank.Novice); break; // Spread Wings case 19138: case 19139: case 19140: case 19141: case 19142: case 19143: case 19157: case 19158: case 19159: if (!_creature.Skills.Has(SkillConst.SpreadWings)) _creature.Skills.Give(SkillConst.SpreadWings, SkillRank.Novice); break; } } }
/// <summary> /// Adds item to NPC's inventory. /// </summary> /// <param name="pocket"></param> /// <param name="itemId"></param> /// <param name="color1"></param> /// <param name="color2"></param> /// <param name="color3"></param> /// <param name="state">For robes and helmets</param> protected void EquipItem(Pocket pocket, int itemId, uint color1 = 0, uint color2 = 0, uint color3 = 0, ItemState state = ItemState.Up) { if (!pocket.IsEquip()) { Log.Error("Pocket '{0}' is not for equipment ({1})", pocket, this.ScriptFilePath); return; } if (!AuraData.ItemDb.Exists(itemId)) { Log.Error("Unknown item '{0}' ({1})", itemId, this.ScriptFilePath); return; } var item = new Item(itemId); item.Info.Pocket = pocket; item.Info.Color1 = color1; item.Info.Color2 = color2; item.Info.Color3 = color3; item.Info.State = (byte)state; this.NPC.Inventory.InitAdd(item); }