public static void HandleSellItemOpcode(ref PacketReader packet, ref WorldSession session) { Log.outDebug("WORLD: Received CMSG_SELL_ITEM"); ulong vendorguid = packet.ReadUInt64(); ulong itemguid = packet.ReadUInt64(); uint count = packet.ReadUInt32(); if (itemguid == 0) { return; } var pl = session.GetPlayer(); Creature creature = pl.GetNPCIfCanInteractWith(vendorguid, NPCFlags.Vendor); if (creature == null) { Log.outDebug("WORLD: HandleSellItemOpcode - Unit (GUID: {0}) not found or you can not interact with him.", ObjectGuid.GuidLowPart(vendorguid)); pl.SendSellError(SellResult.CantFindVendor, null, itemguid); return; } // remove fake death //if (pl.HasUnitState(UNIT_STATE_DIED)) //GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); Item pItem = pl.GetItemByGuid(itemguid); if (pItem != null) { // prevent sell not owner item if (pl.GetGUID() != pItem.GetOwnerGUID()) { pl.SendSellError(SellResult.CantSellItem, creature, itemguid); return; } // prevent sell non empty bag by drag-and-drop at vendor's item list if (pItem.IsNotEmptyBag()) { pl.SendSellError(SellResult.CantSellItem, creature, itemguid); return; } // prevent sell currently looted item //if (pl.GetLootGUID() == pItem.GetGUID()) { //pl.SendSellError(SellResult.CantSellItem, creature, itemguid); //return; } // prevent selling item for sellprice when the item is still refundable // this probably happens when right clicking a refundable item, the client sends both // CMSG_SELL_ITEM and CMSG_REFUND_ITEM (unverified) if (pItem.HasFlag(ItemFields.Flags, ItemFlags.Refundable)) { return; // Therefore, no feedback to client } // special case at auto sell (sell all) if (count == 0) { count = pItem.GetStackCount(); } else { // prevent sell more items that exist in stack (possible only not from client) if (count > pItem.GetStackCount()) { pl.SendSellError(SellResult.CantSellItem, creature, itemguid); return; } } ItemTemplate pProto = pItem.GetTemplate(); if (pProto != null) { if (pProto.SellPrice > 0) { if (count < pItem.GetStackCount()) // need split items { Item pNewItem = pItem.CloneItem(count, pl); if (pNewItem == null) { Log.outError("WORLD: HandleSellItemOpcode - could not create clone of item {0}; count = {1}", pItem.GetEntry(), count); pl.SendSellError(SellResult.CantSellItem, creature, itemguid); return; } pItem.SetStackCount(pItem.GetStackCount() - count); //pl.ItemRemovedQuestCheck(pItem.GetEntry(), count); if (pl.IsInWorld) { pItem.SendUpdateToPlayer(pl); } pItem.SetState(ItemUpdateState.Changed, pl); pl.AddItemToBuyBackSlot(pNewItem); if (pl.IsInWorld) { pNewItem.SendUpdateToPlayer(pl); } } else { //pl.ItemRemovedQuestCheck(pItem.GetEntry(), pItem.GetStackCount()); pl.RemoveItem(pItem.GetBagSlot(), pItem.GetSlot(), true); pItem.RemoveFromUpdateQueueOf(pl); pl.AddItemToBuyBackSlot(pItem); } uint money = pProto.SellPrice * count; pl.ModifyMoney(money); //pl.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money); } else { pl.SendSellError(SellResult.CantSellItem, creature, itemguid); } return; } } pl.SendSellError(SellResult.CantSellItem, creature, itemguid); return; }
public static void HandleTrainerList(ref PacketReader packet, ref WorldSession session) { ulong guid = packet.ReadUInt64(); string str = ObjMgr.GetCypherString(CypherStrings.NpcTrainerHello); Creature unit = session.GetPlayer().GetNPCIfCanInteractWith(guid, NPCFlags.Trainer); if (unit == null) { Log.outDebug("WORLD: SendTrainerList - Unit (GUID: {0}) not found or you can not interact with him.", ObjectGuid.GuidLowPart(guid)); return; } // remove fake death //if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) //GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); // trainer list loaded at check; if (!unit.isTrainerOf(session.GetPlayer(), true)) { return; } CreatureTemplate ci = unit.GetCreatureTemplate(); if (ci == null) { Log.outDebug("WORLD: SendTrainerList - (GUID: {0}) NO CREATUREINFO!", ObjectGuid.GuidLowPart(guid)); return; } TrainerSpellData trainer_spells = unit.GetTrainerSpells(); if (trainer_spells == null) { Log.outDebug("WORLD: SendTrainerList - Training spells not found for creature (GUID: {0} Entry: {1})", ObjectGuid.GuidLowPart(guid), unit.GetEntry()); return; } PacketWriter data = new PacketWriter(Opcodes.SMSG_TrainerList); data.WriteUInt64(guid); data.WriteUInt32(trainer_spells.trainerType); data.WriteUInt32(133); int count_pos = data.wpos(); data.WriteUInt32(trainer_spells.spellList.Count); // reputation discount float fDiscountMod = session.GetPlayer().GetReputationPriceDiscount(unit); bool can_learn_primary_prof = session.GetPlayer().GetFreePrimaryProfessionPoints() > 0; uint count = 0; foreach (var spell in trainer_spells.spellList.Values) { bool valid = true; bool primary_prof_first_rank = false; for (var i = 0; i < 3; ++i) { if (spell.learnedSpell[i] == 0) { continue; } if (!session.GetPlayer().IsSpellFitByClassAndRace(spell.learnedSpell[i])) { valid = false; break; } SpellInfo spellentry = SpellMgr.GetSpellInfo(spell.learnedSpell[i]); if (spellentry.IsPrimaryProfessionFirstRank()) { primary_prof_first_rank = true; } } if (!valid) { continue; } TrainerSpellState state = session.GetPlayer().GetTrainerSpellState(spell); data.WriteUInt32(spell.spellId); // learned spell (or cast-spell in profession case) data.WriteUInt8((byte)(state == TrainerSpellState.GreenDisabled ? TrainerSpellState.Green : state)); data.WriteUInt32((uint)Math.Floor(spell.spellCost * fDiscountMod)); data.WriteUInt8((byte)spell.reqLevel); data.WriteUInt32(spell.reqSkill); data.WriteUInt32(spell.reqSkillValue); //prev + req or req + 0 var maxReq = 0; for (var i = 0; i < 3; ++i) { if (spell.learnedSpell[i] == 0) { continue; } uint prevSpellId = SpellMgr.GetPrevSpellInChain(spell.learnedSpell[i]); if (prevSpellId != 0) { data.WriteUInt32(prevSpellId); maxReq++; } if (maxReq == 2) { break; } //SpellsRequiringSpellMapBounds spellsRequired = sSpellMgr->GetSpellsRequiredForSpellBounds(tSpell->learnedSpell[i]); //for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2) { //data.WriteUInt32(itr2->second); //++maxReq; } //if (maxReq == 2) //break; } while (maxReq < 2) { data.WriteUInt32(0); maxReq++; } data.WriteInt32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0); count++; } data.WriteCString(str); data.Replace <uint>(count_pos, count); session.Send(data); }
public static void HandleGossipHello(ref PacketReader packet, ref WorldSession session) { Log.outDebug("WORLD: Received CMSG_GOSSIP_HELLO"); ulong guid = packet.ReadUInt64(); Creature unit = session.GetPlayer().GetNPCIfCanInteractWith(guid, NPCFlags.Gossip); if (unit == null) { Log.outDebug("WORLD: HandleGossipHelloOpcode - Unit (GUID: {0}) not found or you can not interact with him.", ObjectGuid.GuidLowPart(guid)); return; } // set faction visible if needed FactionTemplateEntry factionTemplateEntry = DBCStorage.FactionTemplateStorage.LookupByKey(unit.getFaction()); if (factionTemplateEntry != null) { session.GetPlayer().GetReputationMgr().SetVisible(factionTemplateEntry); } //GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); //if (unit.isArmorer() || unit.isCivilian() || unit.isQuestGiver() || unit.isServiceProvider() || unit.isGuard()) //unit.StopMoving(); // If spiritguide, no need for gossip menu, just put player into resurrect queue //if (unit.isSpiritGuide()) { //Battleground* bg = _player->GetBattleground(); //if (bg) { //bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID()); //sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID()); //return; } } //if (!sScriptMgr->OnGossipHello(_player, unit)) { // _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID()); //_player->PrepareGossipMenu(unit, unit->GetCreatureTemplate()->GossipMenuId, true); //_player->SendPreparedGossip(unit); } //unit.AI()->sGossipHello(_player); }
static void SendListInventory(ulong vendorGuid, ref WorldSession session) { Log.outDebug("WORLD: Sent SMSG_LIST_INVENTORY"); Player pl = session.GetPlayer(); Creature vendor = pl.GetNPCIfCanInteractWith(vendorGuid, NPCFlags.Vendor); if (vendor == null) { Log.outDebug("WORLD: SendListInventory - Unit (GUID: %u) not found or you can not interact with him.", ObjectGuid.GuidLowPart(vendorGuid)); session.GetPlayer().SendSellError(SellResult.CantFindVendor, null, 0); return; } // remove fake death //if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) //GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); // Stop the npc if moving //if (vendor.HasUnitState(UNIT_STATE_MOVING)) //vendor->StopMoving(); VendorItemData vendorItems = vendor.GetVendorItems(); int rawItemCount = vendorItems != null?vendorItems.GetItemCount() : 0; List <bool> enablers = new List <bool>(); PacketWriter itemsData = new PacketWriter(); float discountMod = session.GetPlayer().GetReputationPriceDiscount(vendor); ushort count = 0; for (ushort slot = 0; slot < rawItemCount; ++slot) { VendorItem vendorItem = vendorItems.GetItem(slot); if (vendorItem == null) { continue; } if (vendorItem.Type == (byte)ItemVendorType.Item) { ItemTemplate itemTemplate = ObjMgr.GetItemTemplate(vendorItem.item); if (itemTemplate == null) { continue; } uint leftInStock = vendorItem.maxcount == 0 ? 0xFFFFFFFF : vendor.GetVendorItemCurrentCount(vendorItem); if (!pl.isGameMaster()) // ignore conditions if GM on { // Respect allowed class if (!Convert.ToBoolean(itemTemplate.AllowableClass & pl.getClassMask()) && itemTemplate.Bonding == ItemBondingType.PickedUp) { continue; } // Only display items in vendor lists for the team the player is on if ((Convert.ToBoolean(itemTemplate.Flags2 & ItemFlags2.HordeOnly) && pl.GetTeam() == Team.Alliance) || (Convert.ToBoolean(itemTemplate.Flags2 & ItemFlags2.AllianceOnly) && pl.GetTeam() == Team.Horde)) { continue; } // Items sold out are not displayed in list if (leftInStock == 0) { continue; } } int price = vendorItem.IsGoldRequired(itemTemplate) ? (int)(Math.Floor(itemTemplate.BuyPrice * discountMod)) : 0; //int priceMod = pl.GetTotalAuraModifier(SPELL_AURA_MOD_VENDOR_ITEMS_PRICES) //if (priceMod != 0) //price -= CalculatePctN(price, priceMod); itemsData.WriteUInt32(count++ + 1); // client expects counting to start at 1 itemsData.WriteUInt32(itemTemplate.MaxDurability); if (vendorItem.ExtendedCost != 0) { enablers.Add(false); itemsData.WriteUInt32(vendorItem.ExtendedCost); } else { enablers.Add(true); } enablers.Add(true); // unk bit itemsData.WriteUInt32(vendorItem.item); itemsData.WriteUInt32(vendorItem.Type); // 1 is items, 2 is currency itemsData.WriteUInt32(price); itemsData.WriteUInt32(itemTemplate.DisplayInfoID); // if (!unk "enabler") data << uint32(something); itemsData.WriteUInt32(leftInStock); itemsData.WriteUInt32(itemTemplate.BuyCount); } else if (vendorItem.Type == (byte)ItemVendorType.Currency) { CurrencyTypesEntry currencyTemplate = DBCStorage.CurrencyTypesStorage.LookupByKey(vendorItem.item); if (currencyTemplate == null) { continue; } if (vendorItem.ExtendedCost == 0) { continue; // there's no price defined for currencies, only extendedcost is used } uint precision = (uint)(Convert.ToBoolean(currencyTemplate.Flags & (uint)CurrencyFlags.HighPrecision) ? 100 : 1); itemsData.WriteUInt32(count++ + 1); // client expects counting to start at 1 itemsData.WriteUInt32(0); // max durability if (vendorItem.ExtendedCost != 0) { enablers.Add(false); itemsData.WriteUInt32(vendorItem.ExtendedCost); } else { enablers.Add(true); } enablers.Add(true); // unk bit itemsData.WriteUInt32(vendorItem.item); itemsData.WriteUInt32(vendorItem.Type); // 1 is items, 2 is currency itemsData.WriteUInt32(0); // price, only seen currency types that have Extended cost itemsData.WriteUInt32(0); // displayId // if (!unk "enabler") data << uint32(something); itemsData.WriteInt32(-1); itemsData.WriteUInt32(vendorItem.maxcount * precision); } // else error } ObjectGuid guid = new ObjectGuid(vendorGuid); PacketWriter data = new PacketWriter(Opcodes.SMSG_ListInventory); data.WriteBit(guid[1]); data.WriteBit(guid[0]); data.WriteBits(count, 21); // item count data.WriteBit(guid[3]); data.WriteBit(guid[6]); data.WriteBit(guid[5]); data.WriteBit(guid[2]); data.WriteBit(guid[7]); foreach (var itr in enablers) { data.WriteBit(itr); } data.WriteBit(guid[4]); data.BitFlush(); data.WriteBytes(itemsData); data.WriteByteSeq(guid[5]); data.WriteByteSeq(guid[4]); data.WriteByteSeq(guid[1]); data.WriteByteSeq(guid[0]); data.WriteByteSeq(guid[6]); data.WriteUInt8(count == 0); // unk byte, item count 0: 1, item count != 0: 0 or some "random" value below 300 data.WriteByteSeq(guid[2]); data.WriteByteSeq(guid[3]); data.WriteByteSeq(guid[7]); session.Send(data); }
public bool LoadFromDB(ulong guid, ulong owner_guid, uint itemEntry) { // 0 1 2 3 4 5 6 7 8 SQLResult result = DB.Characters.Select("SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, " + //9 10 "playedTime, text FROM item_instance WHERE guid = {0}", guid); if (result.Count == 0) { return(false); } // create item before any checks for store correct guid // and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB CreateGuid(guid, 0, HighGuidType.Item); SetEntry(itemEntry); SetObjectScale(1.0f); ItemTemplate proto = GetTemplate(); if (proto == null) { return(false); } // set owner (not if item is only loaded for gbank/auction/mail if (owner_guid != 0) { SetOwnerGUID(owner_guid); } bool need_save = false; SetValue <ulong>(ItemFields.Creator, MakeNewGuid(result.Read <uint>(0, 0), 0, HighGuidType.Player)); SetValue <ulong>(ItemFields.GiftCreator, MakeNewGuid(result.Read <uint>(0, 1), 0, HighGuidType.Player)); ulong blah = GetPackGUID(); ulong vlah = GetGUID(); ulong bl = ObjectGuid.GuidLowPart(vlah); SetStackCount(result.Read <uint>(0, 2)); uint duration = result.Read <uint>(0, 3); SetValue <uint>(ItemFields.Expiration, duration); // update duration if need, and remove if not need if (proto.Duration != duration) { SetValue <uint>(ItemFields.Expiration, proto.Duration); need_save = true; } //Tokens tokens(fields[4].GetString(), ' ', MAX_ITEM_PROTO_SPELLS); //if (tokens.size() == MAX_ITEM_PROTO_SPELLS) //for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) //SetSpellCharges(i, atoi(tokens[i])); SetValue <uint>(ItemFields.Flags, result.Read <uint>(0, 5)); // Remove bind flag for items vs NO_BIND set if (IsSoulBound() && proto.Bonding == ItemBondingType.None) { ApplyModFlag(ItemFields.Flags, ItemFieldFlags.Soulbound, false); need_save = true; } string enchants = result.Read <string>(0, 6); LoadIntoDataField(enchants, (uint)ItemFields.Enchantment, (uint)EnchantmentSlot.MAX_ENCHANTMENT_SLOT * (uint)EnchantmentOffset.Max); SetValue <int>(ItemFields.RandomPropertiesID, result.Read <int>(0, 7)); // recalculate suffix factor if (GetItemRandomPropertyId() < 0) { UpdateItemSuffixFactor(); } uint durability = result.Read <uint>(0, 8); SetValue <uint>(ItemFields.Durability, durability); // update max durability (and durability) if need SetValue <uint>(ItemFields.MaxDurability, proto.MaxDurability); if (durability > proto.MaxDurability) { SetValue <uint>(ItemFields.Durability, proto.MaxDurability); need_save = true; } SetValue <uint>(ItemFields.CreatePlayedTime, result.Read <uint>(0, 9)); SetText(result.Read <string>(0, 10)); if (need_save) // normal item changed state set not work at loading { PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.CHAR_UPD_ITEM_INSTANCE_ON_LOAD); stmt.AddValue(0, GetValue <uint>(ItemFields.Expiration)); stmt.AddValue(1, GetValue <uint>(ItemFields.Flags)); stmt.AddValue(2, GetValue <uint>(ItemFields.Durability)); stmt.AddValue(3, guid); DB.Characters.Execute(stmt); } return(true); }
//DB public void SaveToDB() { PreparedStatement stmt; uint guid = GetGUIDLow(); switch (uState) { case ItemUpdateState.New: case ItemUpdateState.Changed: { byte index = 0; stmt = DB.Characters.GetPreparedStatement(uState == ItemUpdateState.New ? CharStatements.CHAR_REP_ITEM_INSTANCE : CharStatements.CHAR_UPD_ITEM_INSTANCE); stmt.AddValue(index, GetEntry()); stmt.AddValue(++index, ObjectGuid.GuidLowPart(GetOwnerGUID())); stmt.AddValue(++index, ObjectGuid.GuidLowPart(GetValue <ulong>(ItemFields.Creator))); stmt.AddValue(++index, ObjectGuid.GuidLowPart(GetValue <ulong>(ItemFields.GiftCreator))); stmt.AddValue(++index, GetStackCount()); stmt.AddValue(++index, GetValue <uint>(ItemFields.Expiration)); StringBuilder ss = new StringBuilder(); for (byte i = 0; i < ItemConst.MaxSpells; ++i) { ss.AppendFormat("{0} ", GetSpellCharges(i)); } stmt.AddValue(++index, ss.ToString()); stmt.AddValue(++index, GetValue <uint>(ItemFields.Flags)); ss.Clear(); for (var i = 0; i < (int)EnchantmentSlot.MAX_ENCHANTMENT_SLOT; ++i) { ss.AppendFormat("{0} ", GetEnchantmentId((EnchantmentSlot)i)); ss.AppendFormat("{0} ", GetEnchantmentDuration((EnchantmentSlot)i)); ss.AppendFormat("{0} ", GetEnchantmentCharges((EnchantmentSlot)i)); } stmt.AddValue(++index, ss.ToString()); stmt.AddValue(++index, GetItemRandomPropertyId()); stmt.AddValue(++index, GetValue <uint>(ItemFields.Durability)); stmt.AddValue(++index, GetValue <uint>(ItemFields.CreatePlayedTime)); stmt.AddValue(++index, m_text); stmt.AddValue(++index, guid); DB.Characters.Execute(stmt); if ((uState == ItemUpdateState.Changed) && HasFlag(ItemFields.Flags, ItemFieldFlags.Wrapped)) { stmt = DB.Characters.GetPreparedStatement(CharStatements.CHAR_UPD_GIFT_OWNER); stmt.AddValue(0, ObjectGuid.GuidLowPart(GetOwnerGUID())); stmt.AddValue(1, guid); DB.Characters.Execute(stmt); } break; } case ItemUpdateState.Removed: { stmt = DB.Characters.GetPreparedStatement(CharStatements.CHAR_DEL_ITEM_INSTANCE); stmt.AddValue(0, guid); DB.Characters.Execute(stmt); if (HasFlag(ItemFields.Flags, ItemFieldFlags.Wrapped)) { stmt = DB.Characters.GetPreparedStatement(CharStatements.CHAR_DEL_GIFT); stmt.AddValue(0, guid); DB.Characters.Execute(stmt); } return; } case ItemUpdateState.Unchanged: break; } SetState(ItemUpdateState.Unchanged); }
public void RemoveFromUpdateQueueOf(Player player) { if (!IsInUpdateQueue()) { return; } //ASSERT(player != NULL) if (player.GetGUID() != GetOwnerGUID()) { Log.outError("Item->RemoveFromUpdateQueueOf - Owner's guid ({0}) and player's guid ({1}) don't match!", ObjectGuid.GuidLowPart(GetOwnerGUID()), player.GetGUIDLow()); return; } if (player.m_itemUpdateQueueBlocked) { return; } player.ItemUpdateQueue[uQueuePos] = null; uQueuePos = -1; }
public static void HandleAttackSwingOpcode(ref PacketReader packet, ref WorldSession session) { ulong guid = packet.ReadUInt64(); Log.outDebug("WORLD: Recvd CMSG_ATTACKSWING Message guidlow:{0} guidhigh:{1}", ObjectGuid.GuidLowPart(guid), ObjectGuid.GuidHiPart(guid)); var pl = session.GetPlayer(); Unit pEnemy = Cypher.ObjMgr.GetUnit(pl, guid); if (pEnemy == null) { // stop attack state at client SendAttackStop(null, pl); return; } //if (!pl.IsValidAttackTarget(pEnemy)) { // stop attack state at client //SendAttackStop(pEnemy, pl); //return; } //! Client explicitly checks the following before sending CMSG_ATTACKSWING packet, //! so we'll place the same check here. Note that it might be possible to reuse this snippet //! in other places as well. //if (Vehicle* vehicle = _player->GetVehicle()) { //VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(_player); //ASSERT(seat); //if (!(seat->m_flags & VEHICLE_SEAT_FLAG_CAN_ATTACK)) { //SendAttackStop(pEnemy); //return; } } pl.Attack(pEnemy, true); }