void WorldSession::HandleCancelTempItemEnchantmentOpcode(WorldPacket& recvData) { IC_LOG_DEBUG("network", "WORLD: CMSG_CANCEL_TEMP_ENCHANTMENT"); uint32 eslot; recvData >> eslot; // apply only to equipped item if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, eslot)) return; Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, eslot); if (!item) return; if (!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) return; GetPlayer()->ApplyEnchantment(item, TEMP_ENCHANTMENT_SLOT, false); item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT); }
void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPacket& recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CANCEL_TEMP_ENCHANTMENT"); uint32 slot; recv_data >> slot; // apply only to equipped item if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, slot)) return; Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); if (!item) return; if (!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) return; GetPlayer()->ApplyEnchantment(item, TEMP_ENCHANTMENT_SLOT, false); item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT); }
//this function inserts to WorldPacket auction's data bool AuctionEntry::BuildAuctionInfo(WorldPacket & data) const { Item *pItem = sAuctionMgr->GetAItem(item_guidlow); if (!pItem) { sLog->outError("auction to item, that doesn't exist !!!!"); return false; } data << uint32(Id); data << uint32(pItem->GetEntry()); for (uint8 i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; ++i) { data << uint32(pItem->GetEnchantmentId(EnchantmentSlot(i))); data << uint32(pItem->GetEnchantmentDuration(EnchantmentSlot(i))); data << uint32(pItem->GetEnchantmentCharges(EnchantmentSlot(i))); } for (uint8 i = 0; i < 2; ++i) { data << uint32(0); data << uint32(0); data << uint32(0); } data << int32(pItem->GetItemRandomPropertyId()); //random item property id data << uint32(pItem->GetItemSuffixFactor()); //SuffixFactor data << uint32(pItem->GetCount()); //item->count data << uint32(pItem->GetSpellCharges()); //item->charge FFFFFFF data << uint32(0); //Unknown data << uint64(owner); //Auction->owner data << uint64(startbid); //Auction->startbid (not sure if useful) data << uint64(bid ? GetAuctionOutBid() : 0); //minimal outbid data << uint64(buyout); //auction->buyout data << uint32((expire_time - time(NULL)) * IN_MILLISECONDS); //time left data << uint64(bidder); //auction->bidder current data << uint64(bid); //current bid return true; }
void WorldSession::HandleSocketOpcode(WorldPacket& recv_data) { sLog.outDebug("WORLD: CMSG_SOCKET_GEMS"); CHECK_PACKET_SIZE(recv_data,8*4); uint64 guids[4]; uint32 GemEnchants[3], OldEnchants[3]; Item *Gems[3]; bool SocketBonusActivated, SocketBonusToBeActivated; for(int i = 0; i < 4; i++) recv_data >> guids[i]; if(!guids[0]) return; //cheat -> tried to socket same gem multiple times if((guids[1] && (guids[1] == guids[2] || guids[1] == guids[3])) || (guids[2] && (guids[2] == guids[3]))) return; Item *itemTarget = _player->GetItemByGuid(guids[0]); if(!itemTarget) //missing item to socket return; //this slot is excepted when applying / removing meta gem bonus uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : NULL_SLOT; for(int i = 0; i < 3; i++) Gems[i] = guids[i + 1] ? _player->GetItemByGuid(guids[i + 1]) : NULL; GemPropertiesEntry const *GemProps[3]; for(int i = 0; i < 3; ++i) //get geminfo from dbc storage { GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetProto()->GemProperties) : NULL; } for(int i = 0; i < 3; ++i) //check for hack maybe { // tried to put gem in socket where no socket exists / tried to put normal gem in meta socket // tried to put meta gem in normal socket if( GemProps[i] && ( !itemTarget->GetProto()->Socket[i].Color || itemTarget->GetProto()->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META || itemTarget->GetProto()->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META ) ) return; } for(int i = 0; i < 3; ++i) //get new and old enchantments { GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0; OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i)); } // check unique-equipped conditions for(int i = 0; i < 3; ++i) { if (Gems[i] && (Gems[i]->GetProto()->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)) { // for equipped item check all equipment for duplicate equipped gems if(itemTarget->IsEquipped()) { if(GetPlayer()->GetItemOrItemWithGemEquipped(Gems[i]->GetEntry())) { _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE, itemTarget, NULL ); return; } } // continue check for case when attempt add 2 similar unique equipped gems in one item. for (int j = 0; j < 3; ++j) { if ((i != j) && (Gems[j]) && (Gems[i]->GetProto()->ItemId == Gems[j]->GetProto()->ItemId)) { _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL ); return; } } for (int j = 0; j < 3; ++j) { if (OldEnchants[j]) { SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]); if(!enchantEntry) continue; if ((enchantEntry->GemID == Gems[i]->GetProto()->ItemId) && (i != j)) { _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL ); return; } } } } } SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus _player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item) //if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met //remove ALL enchants for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),false); for(int i = 0; i < 3; ++i) { if(GemEnchants[i]) { itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i],0,0); if(Item* guidItem = _player->GetItemByGuid(guids[i + 1])) _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true ); } } for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),true); SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state if(SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change... { _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,false); itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetProto()->socketBonus : 0), 0, 0); _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,true); //it is not displayed, client has an inbuilt system to determine if the bonus is activated } _player->ToggleMetaGemsActive(slot, true); //turn on all metagems (except for target item) }
void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) { TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); ByteBuffer itemData(7*2 + 7*4 + 3*4 + 3*4 + 1); uint8 count = 0; for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) if (view_trade->GetItem(TradeSlots(i))) ++count; WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 4*6 + 8 + 1 + 3 + count * 70); data << uint32(0); // this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) data << uint32(0); // unk 2 data << uint64(view_trade->GetMoney()); // trader gold data << uint32(view_trade->GetSpell()); // spell casted on lowest slot item data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = next field in most cases data << uint32(0); // unk 5 data << uint8(trader_data); // 1 means traders data, 0 means own data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = prev field in most cases data.WriteBits(count, 22); for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { Item* item = view_trade->GetItem(TradeSlots(i)); if (!item) continue; ObjectGuid giftCreatorGuid = item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR); ObjectGuid creatorGuid = item->GetUInt64Value(ITEM_FIELD_CREATOR); data.WriteBit(giftCreatorGuid[7]); data.WriteBit(giftCreatorGuid[1]); bool notWrapped = data.WriteBit(!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)); data.WriteBit(giftCreatorGuid[3]); if (notWrapped) { data.WriteBit(creatorGuid[7]); data.WriteBit(creatorGuid[1]); data.WriteBit(creatorGuid[4]); data.WriteBit(creatorGuid[6]); data.WriteBit(creatorGuid[2]); data.WriteBit(creatorGuid[3]); data.WriteBit(creatorGuid[5]); data.WriteBit(item->GetTemplate()->LockID != 0); data.WriteBit(creatorGuid[0]); itemData.WriteByteSeq(creatorGuid[1]); itemData << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS /*3*/; ++enchant_slot) itemData << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); itemData << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); itemData.WriteByteSeq(creatorGuid[6]); itemData.WriteByteSeq(creatorGuid[2]); itemData.WriteByteSeq(creatorGuid[7]); itemData.WriteByteSeq(creatorGuid[4]); itemData << uint32(item->GetEnchantmentId(REFORGE_ENCHANTMENT_SLOT)); itemData << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); itemData << uint32(item->GetItemRandomPropertyId()); itemData.WriteByteSeq(creatorGuid[3]); itemData << uint32(0); // unk7 itemData.WriteByteSeq(creatorGuid[0]); itemData << uint32(item->GetSpellCharges()); itemData << uint32(item->GetItemSuffixFactor()); itemData.WriteByteSeq(creatorGuid[5]); } data.WriteBit(giftCreatorGuid[6]); data.WriteBit(giftCreatorGuid[4]); data.WriteBit(giftCreatorGuid[2]); data.WriteBit(giftCreatorGuid[0]); data.WriteBit(giftCreatorGuid[5]); itemData.WriteByteSeq(giftCreatorGuid[6]); itemData.WriteByteSeq(giftCreatorGuid[1]); itemData.WriteByteSeq(giftCreatorGuid[7]); itemData.WriteByteSeq(giftCreatorGuid[4]); itemData << uint32(item->GetTemplate()->ItemId); itemData.WriteByteSeq(giftCreatorGuid[0]); itemData << uint32(item->GetCount()); itemData.WriteByteSeq(giftCreatorGuid[5]); itemData << uint8(i); itemData.WriteByteSeq(giftCreatorGuid[2]); itemData.WriteByteSeq(giftCreatorGuid[3]); } data.FlushBits(); data.append(itemData); SendPacket(&data); }
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) { int slot = -1; bool check_adjacent_slot = true; switch (action) { case -1: // Back ShowMainMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 1: Show1HWeaponMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 2: Show2HWeaponMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 3: ShowShieldMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 4: ShowHeadMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 5: ShowShouldersMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 6: ShowCloakMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 7: ShowChestMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 8: ShowBracerMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 9: ShowGlovesMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 10: ShowBeltMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 11: ShowLegsMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 12: ShowBootsMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 13: ShowRangedMenu(player, creature); break; case GOSSIP_ACTION_INFO_DEF + 14: ShowRingsMenu(player, creature); break; // 1H weapons case ENCHANT_WEP_BLADE_WARD: case ENCHANT_WEP_BLOOD_DRAINING: case ENCHANT_WEP_AGILITY_1H: case ENCHANT_WEP_SPIRIT: case ENCHANT_WEP_BERSERKING: case ENCHANT_WEP_ACCURACY: case ENCHANT_WEP_BLACK_MAGIC: case ENCHANT_WEP_BATTLEMASTER: case ENCHANT_WEP_ICEBREAKER: case ENCHANT_WEP_LIFEWARD: case ENCHANT_WEP_TITANGUARD: case ENCHANT_WEP_POTENCY: case ENCHANT_WEP_MONGOOSE: case ENCHANT_WEP_MIGHTY_SPELL_POWER: case ENCHANT_WEP_EXECUTIONER: case ENCHANT_WEP_TITANIUM_CHAIN: // 2H weapons // case ENCHANT_WEP_BERSERKING: // case ENCHANT_WEP_MONGOOSE: // case ENCHANT_WEP_EXECUTIONER: // case ENCHANT_WEP_TITANIUM_CHAIN: case ENCHANT_WEP_GREATER_SPELL_POWER: case ENCHANT_WEP_AGILITY_2H: case ENCHANT_WEP_MASSACRE: // Runeforging case ENCHANT_WEP_CINDERGLACIER: case ENCHANT_WEP_LICHBANE: case ENCHANT_WEP_RAZORICE: case ENCHANT_WEP_SPELLBREAKING: case ENCHANT_WEP_SPELLSHATTERING: case ENCHANT_WEP_SWORDBREAKING: case ENCHANT_WEP_SWORDSHATTERING: case ENCHANT_WEP_FALLEN_CRUSADER: case ENCHANT_WEP_NERUBIAN_CARAPACE: case ENCHANT_WEP_STONESKIN_GARGOYLE: slot = EQUIPMENT_SLOT_MAINHAND; break; // Shields case ENCHANT_SHIELD_DEFENSE: case ENCHANT_SHIELD_INTELLECT: case ENCHANT_SHIELD_RESILIENCE: case ENCHANT_SHIELD_TITANIUM_PLATING: case ENCHANT_SHIELD_MAJOR_STAMINA: case ENCHANT_SHIELD_TITANIUM_SPIKE: slot = EQUIPMENT_SLOT_OFFHAND; break; // Head case ENCHANT_HEAD_BLISSFUL_MENDING: case ENCHANT_HEAD_BURNING_MYSTERIES: case ENCHANT_HEAD_DOMINANCE: case ENCHANT_HEAD_SAVAGE_GLADIATOR: case ENCHANT_HEAD_STALWART_PROTECTOR: case ENCHANT_HEAD_TORMENT: case ENCHANT_HEAD_TRIUMPH: slot = EQUIPMENT_SLOT_HEAD; break; // Shoulders case ENCHANT_SHOULDER_MASTERS_AXE: case ENCHANT_SHOULDER_MASTERS_CRAG: case ENCHANT_SHOULDER_MASTERS_PINNACLE: case ENCHANT_SHOULDER_MASTERS_STORM: case ENCHANT_SHOULDER_GREATER_AXE: case ENCHANT_SHOULDER_GREATER_CRAG: case ENCHANT_SHOULDER_GREATER_GLADIATOR: case ENCHANT_SHOULDER_GREATER_PINNACLE: case ENCHANT_SHOULDER_GREATER_STORM: case ENCHANT_SHOULDER_DOMINANCE: case ENCHANT_SHOULDER_TRIUMPH: slot = EQUIPMENT_SLOT_SHOULDERS; break; // Cloak case ENCHANT_CLOAK_DARKGLOW_EMBROIDERY: case ENCHANT_CLOAK_SWORDGUARD_EMBROIDERY: case ENCHANT_CLOAK_FLEXWEAVE_UNDERLAY: case ENCHANT_CLOAK_LIGHTWEAVE_EMBROIDERY: case ENCHANT_CLOAK_SPRINGY_ARACHNOWEAVE: case ENCHANT_CLOAK_WISDOM: case ENCHANT_CLOAK_TITANWEAVE: case ENCHANT_CLOAK_SPELL_PIERCING: case ENCHANT_CLOAK_SHADOW_ARMOR: case ENCHANT_CLOAK_MIGHTY_ARMOR: case ENCHANT_CLOAK_MAJOR_AGILITY: case ENCHANT_CLOAK_GREATER_SPEED: slot = EQUIPMENT_SLOT_BACK; break; // Chest case ENCHANT_CHEST_EXCEPTIONAL_MANA: case ENCHANT_CHEST_GREATER_MANA_RESTO: case ENCHANT_CHEST_EXCEPTIONAL_RESILIENCE: case ENCHANT_CHEST_SUPER_HEALTH: case ENCHANT_CHEST_ALL_STATS: slot = EQUIPMENT_SLOT_CHEST; break; // Bracers case ENCHANT_BRACER_GREATER_ASSAULT: case ENCHANT_BRACER_EXCEPTIONAL_INTELLECT: case ENCHANT_BRACER_MAJOR_SPIRIT: case ENCHANT_BRACER_EXPERTISE: case ENCHANT_BRACER_GREATER_STATS: case ENCHANT_BRACER_SUPERIOR_SPELLPOWER: case ENCHANT_BRACER_MAJOR_STAMINA: case ENCHANT_BRACER_FUR_LINING_AP: case ENCHANT_BRACER_FUR_LINING_STAMINA: case ENCHANT_BRACER_FUR_LINING_SP: case ENCHANT_BRACER_ARCANE_RESIST: case ENCHANT_BRACER_NATURE_RESIST: case ENCHANT_BRACER_SHADOW_RESIST: case ENCHANT_BRACER_FROST_RESIST: case ENCHANT_BRACER_FIRE_RESIST: case ENCHANT_BRACER_SOCKET_BRACER: slot = EQUIPMENT_SLOT_WRISTS; break; // Gloves case ENCHANT_GLOVES_EXPERTISE: case ENCHANT_GLOVES_PRECISION: case ENCHANT_GLOVES_GREATER_ASSAULT: case ENCHANT_GLOVES_MAJOR_AGILITY: case ENCHANT_GLOVES_EXCEPTIONAL_SPELLPOWER: case ENCHANT_GLOVES_ARMSMAN: case ENCHANT_GLOVES_SOCKET_GLOVES: case ENCHANT_GLOVES_PYROROCKET: case ENCHANT_GLOVES_HYPERSPEED_ACCELERATORS: slot = EQUIPMENT_SLOT_HANDS; break; // Belt case ENCHANT_BELT_ETERNAL_BELT_BUCKLE: case ENCHANT_BELT_FRAG_BELT: slot = EQUIPMENT_SLOT_WAIST; break; // Legs case ENCHANT_LEGS_FROSTHIDE_ARMOR: case ENCHANT_LEGS_ICESCALE_ARMOR: case ENCHANT_LEGS_EARTHEN_ARMOR: case ENCHANT_LEGS_SAPPHIRE_SPELLTHREAD : case ENCHANT_LEGS_BRILLIANT_SPELLTHREAD: slot = EQUIPMENT_SLOT_LEGS; break; // Boots case ENCHANT_BOOTS_TUSKARRS_VITALITY: case ENCHANT_BOOTS_ICEWALKER: case ENCHANT_BOOTS_GREATER_ASSAULT: case ENCHANT_BOOTS_GREATER_SPIRIT: case ENCHANT_BOOTS_GREATER_FORTITUDE: case ENCHANT_BOOTS_SUPERIOR_AGILITY: case ENCHANT_BOOTS_NITRO_BOOSTS: slot = EQUIPMENT_SLOT_FEET; break; // Rings case ENCHANT_RING_STAMINA: case ENCHANT_RING_GREATER_SPELLPOWER: case ENCHANT_RING_ASSAULT: slot = EQUIPMENT_SLOT_FINGER1; break; // Ranged weapon case ENCHANT_RANGED_HEARTSEEKER_SCOPE: case ENCHANT_RANGED_SUN_SCOPE: slot = EQUIPMENT_SLOT_RANGED; break; // Main hand case GOSSIP_ACTION_INFO_DEF + 20: slot = EQUIPMENT_SLOT_MAINHAND; action = selected_enchant; check_adjacent_slot = false; break; // Off hand case GOSSIP_ACTION_INFO_DEF + 21: slot = EQUIPMENT_SLOT_OFFHAND; action = selected_enchant; check_adjacent_slot = false; break; default: player->CLOSE_GOSSIP_MENU(); break; } if (slot > -1) { // allows for a maximum of 2 duplicates, and the // convenience of using enchant ids as gossip // userdata if (action < 0) action = -action; Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); if (!item && slot == INVTYPE_RANGEDRIGHT) item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, INVTYPE_RANGEDRIGHT); if (item && check_adjacent_slot && item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT) != 0) { switch (slot) { case EQUIPMENT_SLOT_MAINHAND: { Item* offhand = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); if (offhand) { player->PlayerTalkClass->ClearMenus(); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, item->GetTemplate()->Name1.c_str(), GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 20); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, offhand->GetTemplate()->Name1.c_str(), GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Back", GOSSIP_SENDER_MAIN, -1); player->SEND_GOSSIP_MENU(1, creature->GetGUID()); selected_enchant = action; return true; } break; } case EQUIPMENT_SLOT_FINGER1: { Item* ring2 = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_FINGER2); if (ring2) { player->PlayerTalkClass->ClearMenus(); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, item->GetTemplate()->Name1.c_str(), GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 20); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, ring2->GetTemplate()->Name1.c_str(), GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Back", GOSSIP_SENDER_MAIN, -1); player->SEND_GOSSIP_MENU(1, creature->GetGUID()); selected_enchant = action; return true; } break; } default: break; } } Enchant(player, creature, item, action); ShowMainMenu(player, creature); } return true; }
bool PlayerbotShamanAI::ChangeWeaponEnchants() { uint32 mhEnch = 0, ohEnch = 0; PlayerbotAI *ai = GetAI(); if(!ai) return false; Player *m_bot = GetPlayerBot(); if(!m_bot || m_bot->isDead()) return false; // Choose Weapon Enchant if (TALENT_RESTO) { mhEnch = EARTHLIVING_WEAPON; } else if (TALENT_ELEMENTAL){ mhEnch = FLAMETONGUE_WEAPON; } else { if (WINDFURY_WEAPON) { mhEnch = WINDFURY_WEAPON; if (m_bot->haveOffhandWeapon()) { if (LAVA_LASH) ohEnch = FLAMETONGUE_WEAPON; else ohEnch = WINDFURY_WEAPON; } } else if (FLAMETONGUE_WEAPON) { mhEnch = FLAMETONGUE_WEAPON; if (m_bot->haveOffhandWeapon()) ohEnch = FLAMETONGUE_WEAPON; } } Item* weap; uint32 enchant_id = 0; SpellEntry const *tSpell; bool castedsomething = false; if (mhEnch) { weap = m_bot->GetWeaponForAttack(BASE_ATTACK); if (weap) { tSpell = GetSpellStore()->LookupEntry(mhEnch); if (tSpell && tSpell->EffectMiscValue[0] > 0) { enchant_id = (uint32) tSpell->EffectMiscValue[0]; if (enchant_id && weap->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT) != enchant_id && sSpellItemEnchantmentStore.LookupEntry(enchant_id)) { m_bot->ApplyEnchantment(weap,TEMP_ENCHANTMENT_SLOT, false); //Remove old enchantment effect weap->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, 1800 * 1000, 0); //Add for 30 mins m_bot->ApplyEnchantment(weap, TEMP_ENCHANTMENT_SLOT, true); //Add new effect castedsomething = true; } } } } if (ohEnch) { weap = m_bot->GetWeaponForAttack(OFF_ATTACK); if (weap) { tSpell = GetSpellStore()->LookupEntry(ohEnch); if (tSpell && tSpell->EffectMiscValue[0] > 0) { enchant_id = (uint32) tSpell->EffectMiscValue[0]; if (enchant_id && weap->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT) != enchant_id && sSpellItemEnchantmentStore.LookupEntry(enchant_id)) { m_bot->ApplyEnchantment(weap,TEMP_ENCHANTMENT_SLOT, false); //Remove old enchantment effect weap->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, 1800 * 1000, 0); //Add for 30 mins m_bot->ApplyEnchantment(weap, TEMP_ENCHANTMENT_SLOT, true); //Add new effect castedsomething = true; } } } } return castedsomething; }
//called when player lists his received mails void WorldSession::HandleGetMailList(WorldPacket& recvData) { ObjectGuid mailbox; recvData >> mailbox; if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; Player* player = _player; //load players mails, and mailed items if (!player->m_mailsLoaded) player->_LoadMail(); // client can't work with packets > max int16 value const uint32 maxPacketSize = 32767; uint32 mailCount = 0; uint32 realCount = 0; // true mail count (includes any skipped mail) time_t cur_time = time(NULL); ByteBuffer mailData; WorldPacket data(SMSG_MAIL_LIST_RESULT, 200); // guess size data << uint32(0); // placeholder size_t mailCountPos = data.bitwpos(); data.WriteBits(0, 18); // placeholder for (PlayerMails::iterator itr = player->GetMailBegin(); itr != player->GetMailEnd(); ++itr) { Mail* mail = *itr; // Only first 50 mails are displayed if (mailCount >= 50) { realCount += 1; continue; } // skip deleted or not delivered (deliver delay not expired) mails if (mail->state == MAIL_STATE_DELETED || cur_time < mail->deliver_time) continue; // skip mail with more than MAX_MAIL_ITEMS items (should not occur) uint8 itemCount = mail->items.size(); if (itemCount > MAX_MAIL_ITEMS) { realCount += 1; continue; } // skip mail if the packet has become too large (should not occur) size_t nextMailSize = 6 + 1 + 8 + itemCount * (4 + 4 + 4 + 4 + 4 + MAX_INSPECTED_ENCHANTMENT_SLOT * (4 + 4 + 4) + 4 + 4 + 4 + 4 + 1 + 4) + mail->body.size() + mail->subject.size() + 4 + 4 + 8 + 4 + 8 + 4 + 4 + 1 + 4; if (data.wpos() + nextMailSize > maxPacketSize) { realCount += 1; continue; } data.WriteBit(mail->messageType != MAIL_NORMAL ? 1 : 0); data.WriteBits(mail->subject.size(), 8); data.WriteBits(mail->body.size(), 13); data.WriteBit(0); data.WriteBit(0); size_t itemCountPos = data.bitwpos(); data.WriteBits(0, 17); // placeholder data.WriteBit(1); // has guid ObjectGuid guid = mail->messageType == MAIL_NORMAL ? MAKE_NEW_GUID(mail->sender, 0, HIGHGUID_PLAYER) : 0; data << guid; uint8 trueItemCount = 0; for (uint8 i = 0; i < itemCount; i++) { Item* item = player->GetMItem(mail->items[i].item_guid); if (!item) continue; data.WriteBit(0); mailData << uint32(item->GetGUIDLow()); mailData << uint32(4); // unknown mailData << uint32(item->GetSpellCharges()); mailData << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); mailData << uint32(0); // unknown for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; j++) { mailData << uint32(item->GetEnchantmentCharges((EnchantmentSlot)j)); mailData << uint32(item->GetEnchantmentDuration((EnchantmentSlot)j)); mailData << uint32(item->GetEnchantmentId((EnchantmentSlot)j)); } mailData << uint32(item->GetItemSuffixFactor()); mailData << int32(item->GetItemRandomPropertyId()); mailData << uint32(item->GetUInt32Value(ITEM_FIELD_MAX_DURABILITY)); mailData << uint32(item->GetCount()); mailData << uint8(i); mailData << uint32(item->GetEntry()); trueItemCount++; } data.PutBits(itemCountPos, trueItemCount, 17); mailData.WriteString(mail->body); mailData << uint32(mail->messageID); mailData << guid; mailData << uint32(mail->mailTemplateId); mailData << uint64(mail->COD); mailData.WriteString(mail->subject); mailData << uint32(mail->stationery); mailData << float(float(mail->expire_time - time(NULL)) / DAY); mailData << uint64(mail->money); mailData << uint32(mail->checked); if (mail->messageType != MAIL_NORMAL) mailData << uint32(mail->sender); mailData << uint8(mail->messageType); mailData << uint32(0); // unknown realCount++; mailCount++; } data.FlushBits(); data.append(mailData); data.put<uint32>(0, realCount); data.PutBits(mailCountPos, mailCount, 18); SendPacket(&data); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); }
WorldPacket* Mailbox::BuildMailboxListingPacket() { WorldPacket* data = new WorldPacket(SMSG_MAIL_LIST_RESULT, 200); MessageMap::iterator itr; uint8 i = 0; uint32 realCount = 0; uint32 mailsCount = 0; uint32 t = (uint32)UNIXTIME; *data << uint32(0); // real mail's count *data << uint8(0); // mail's count for (itr = Messages.begin(); itr != Messages.end(); ++itr) { if (itr->second.expire_time && t > itr->second.expire_time) continue; // expired mail -> skip it if ((uint32)UNIXTIME < itr->second.delivery_time) continue; // undelivered if (mailsCount >= 50) //VLack: We could calculate message sizes instead of this, but the original code did a break at 50, so I won't fix this up if no one felt the need to do so before ;-) { realCount += 1; continue; } uint8 item_count = itr->second.items.size(); // max count is MAX_MAIL_ITEMS (12) size_t next_mail_size = 2 + 4 + 1 + (itr->second.message_type == NORMAL ? 8 : 4) + 4 * 8 + (itr->second.subject.size() + 1) + (itr->second.body.size() + 1) + 1 + item_count*(1 + 4 + 4 + MAX_INSPECTED_ENCHANTMENT_SLOT * 3 * 4 + 4 + 4 + 4 + 4 + 4 + 4 + 1); *data << uint16(next_mail_size); // Message size *data << uint32(itr->second.message_id); // Message ID *data << uint8(itr->second.message_type); // Message Type switch (itr->second.message_type) { case NORMAL: *data << uint64((itr->second.sender_guid)); break; case COD: case AUCTION: case ITEM: *data << uint32(Arcemu::Util::GUID_LOPART((itr->second.sender_guid))); break; case GAMEOBJECT: case CREATURE: *data << uint32(static_cast<uint32>((itr->second.sender_guid))); break; } *data << uint64(itr->second.cod); // COD *data << uint32(0); // Package.dbc ID ? *data << uint32(itr->second.stationery); // stationery (Stationery.dbc) *data << uint64(itr->second.money); // Gold *data << uint32(itr->second.checked_flag); // flags *data << float(float((itr->second.expire_time - uint32(UNIXTIME)) / DAY)); // Time *data << uint32(itr->second.message_id); // mail template (MailTemplate.dbc) *data << itr->second.subject; // Subject string - once 00, when mail type = 3, max 256 *data << itr->second.body; // message? max 8000 *data << uint8(item_count); // client limit is 0x10 Item* pItem; std::vector<uint32>::iterator itr2; for (uint8 i = 0; i < item_count; ++i) { pItem = objmgr.LoadItem(itr->second.items[i]); // item index (0-6?) *data << uint8(i); // item guid low? *data << uint32((pItem ? pItem->GetLowGUID() : 0)); // entry *data << uint32((pItem ? pItem->GetEntry() : 0)); for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j) { *data << uint32((pItem ? pItem->GetEnchantmentId((EnchantmentSlot)j) : 0)); *data << uint32((pItem ? pItem->GetEnchantmentDuration((EnchantmentSlot)j) : 0)); *data << uint32((pItem ? pItem->GetEnchantmentCharges((EnchantmentSlot)j) : 0)); } // can be negative *data << int32((pItem ? pItem->GetItemRandomPropertyId() : 0)); // unk *data << uint32((pItem ? pItem->GetItemRandomSuffixFactor() : 0)); // stack count *data << uint32((pItem ? pItem->GetStackCount() : 0)); // charges *data << uint32((pItem ? pItem->GetChargesLeft() : 0)); // durability *data << uint32((pItem ? pItem->GetDurabilityMax() : 0)); // durability *data << uint32((pItem ? pItem->GetDurability() : 0)); // unknown wotlk *data << uint8(0); } ++realCount; ++mailsCount; } data->put<uint32>(0, realCount); // this will display warning about undelivered mail to player if realCount > mailsCount data->put<uint8>(4, mailsCount); // set real send mails to client // do cleanup on request mail CleanupExpiredMessages(); return data; }
//called when player lists his received mails void WorldSession::HandleGetMail(WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8); uint64 mailbox; recv_data >> mailbox; //GameObject* obj = ObjectAccessor::GetGameObject(_player, mailbox); //if(!obj || !obj->IsMailBox()) // return; Player* pl = _player; //load players mails, and mailed items if(!pl->m_mailsLoaded) pl ->_LoadMail(); // client can't work with packets > max int16 value const uint32 maxPacketSize = 32767; uint32 mails_count = 0; // real send to client mails amount WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); // guess size data << uint8(0); // mail's count time_t cur_time = time(NULL); for(PlayerMails::iterator itr = pl->GetmailBegin(); itr != pl->GetmailEnd(); ++itr) { // skip deleted or not delivered (deliver delay not expired) mails if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time) continue; uint8 item_count = (*itr)->items.size(); // max count is MAX_MAIL_ITEMS (12) size_t next_mail_size = 2+4+1+8+4*8+((*itr)->subject.size()+1)+1+item_count*(1+4+4+6*3*4+4+4+1+4+4+4); if(data.wpos()+next_mail_size > maxPacketSize) break; data << (uint16) 0x0040; // unknown 2.3.0, different values data << (uint32) (*itr)->messageID; // Message ID data << (uint8) (*itr)->messageType; // Message Type switch((*itr)->messageType) { case MAIL_NORMAL: // sender guid data << uint64(MAKE_NEW_GUID((*itr)->sender, 0, HIGHGUID_PLAYER)); break; case MAIL_CREATURE: case MAIL_GAMEOBJECT: case MAIL_AUCTION: data << (uint32) (*itr)->sender; // creature/gameobject entry, auction id break; case MAIL_ITEM: // item entry (?) sender = "Unknown", NYI break; } data << (uint32) (*itr)->COD; // COD data << (uint32) (*itr)->itemTextId; // sure about this data << (uint32) 0; // unknown data << (uint32) (*itr)->stationery; // stationery (Stationery.dbc) data << (uint32) (*itr)->money; // Gold data << (uint32) 0x04; // unknown, 0x4 - auction, 0x10 - normal // Time data << (float) ((*itr)->expire_time-time(NULL))/DAY; data << (uint32) (*itr)->mailTemplateId; // mail template (MailTemplate.dbc) data << (*itr)->subject; // Subject string - once 00, when mail type = 3 data << (uint8) item_count; for(uint8 i = 0; i < item_count; ++i) { Item *item = pl->GetMItem((*itr)->items[i].item_guid); // item index (0-6?) data << (uint8) i; // item guid low? data << (uint32) (item ? item->GetGUIDLow() : 0); // entry data << (uint32) (item ? item->GetEntry() : 0); for(uint8 j = 0; j < 6; ++j) { // unsure data << (uint32) (item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0); // unsure data << (uint32) (item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0); // unsure data << (uint32) (item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0); } // can be negative data << (uint32) (item ? item->GetItemRandomPropertyId() : 0); // unk data << (uint32) (item ? item->GetItemSuffixFactor() : 0); // stack count data << (uint8) (item ? item->GetCount() : 0); // charges data << (uint32) (item ? item->GetSpellCharges() : 0); // durability data << (uint32) (item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0); // durability data << (uint32) (item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0); } mails_count += 1; } data.put<uint8>(0, mails_count); // set real send mails to client SendPacket(&data); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); }
/** * Handles the packet sent by the client when requesting the current mail list. * It will send a list of all available mails in the players mailbox to the client. */ void WorldSession::HandleGetMailList(WorldPacket& recv_data) { ObjectGuid mailboxGuid; recv_data >> mailboxGuid; if (!CheckMailBox(mailboxGuid)) return; // client can't work with packets > max int16 value const uint32 maxPacketSize = 32767; uint32 mailsCount = 0; // send to client mails amount WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); // guess size data << uint8(0); // mail's count time_t cur_time = time(nullptr); for (PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr) { // packet send mail count as uint8, prevent overflow if (mailsCount >= 254) break; // skip deleted or not delivered (deliver delay not expired) mails if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time) continue; uint8 item_count = (*itr)->items.size(); // max count is MAX_MAIL_ITEMS (12) size_t next_mail_size = 2 + 4 + 1 + 8 + 4 * 8 + ((*itr)->subject.size() + 1) + 1 + item_count * (1 + 4 + 4 + 6 * 3 * 4 + 4 + 4 + 1 + 4 + 4 + 4); if (data.wpos() + next_mail_size > maxPacketSize) break; data << uint16(next_mail_size); // Message size data << uint32((*itr)->messageID); // Message ID data << uint8((*itr)->messageType); // Message Type switch ((*itr)->messageType) { case MAIL_NORMAL: // sender guid data << ObjectGuid(HIGHGUID_PLAYER, (*itr)->sender); break; case MAIL_CREATURE: case MAIL_GAMEOBJECT: case MAIL_AUCTION: data << uint32((*itr)->sender); // creature/gameobject entry, auction id break; case MAIL_ITEM: // item entry (?) sender = "Unknown", NYI data << uint32(0); // item entry break; } data << uint32((*itr)->COD); // COD data << uint32((*itr)->itemTextId); // item text data << uint32(0); // unknown data << uint32((*itr)->stationery); // stationery (Stationery.dbc) data << uint32((*itr)->money); // copper data << uint32((*itr)->checked); // flags data << float(float((*itr)->expire_time - time(nullptr)) / float(DAY));// Time data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc) data << (*itr)->subject; // Subject string - once 00, when mail type = 3, max 256 data << (uint8)item_count; for (uint8 i = 0; i < item_count; ++i) { Item* item = _player->GetMItem((*itr)->items[i].item_guid); // item index (0-6?) data << uint8(i); // item guid low? data << uint32(item ? item->GetGUIDLow() : 0); // entry data << uint32(item ? item->GetEntry() : 0); for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j) { // unsure data << uint32(item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0); // unsure data << uint32(item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0); // unsure data << uint32(item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0); } // can be negative data << uint32(item ? item->GetItemRandomPropertyId() : 0); // unk data << uint32(item ? item->GetItemSuffixFactor() : 0); // stack count data << (uint8)(item ? item->GetCount() : 0); // charges data << uint32(item ? item->GetSpellCharges() : 0); // durability data << uint32(item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0); // durability data << uint32(item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0); } mailsCount += 1; } data.put<uint8>(0, mailsCount); // set real send mails to client SendPacket(data); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); }
void WorldSession::HandleSocketOpcode(WorldPacket& recv_data) { DEBUG_LOG("WORLD: CMSG_SOCKET_GEMS"); ObjectGuid itemGuid; ObjectGuid gemGuids[MAX_GEM_SOCKETS]; recv_data >> itemGuid; if (!itemGuid.IsItem()) return; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) recv_data >> gemGuids[i]; // cheat -> tried to socket same gem multiple times for (int i = 0; i < MAX_GEM_SOCKETS; ++i) { ObjectGuid gemGuid = gemGuids[i]; if (!gemGuid) continue; if (!gemGuid.IsItem()) return; for (int j = i + 1; j < MAX_GEM_SOCKETS; ++j) if (gemGuids[j] == gemGuid) return; } Item* itemTarget = _player->GetItemByGuid(itemGuid); if (!itemTarget) // missing item to socket return; ItemPrototype const* itemProto = itemTarget->GetProto(); if (!itemProto) return; // this slot is excepted when applying / removing meta gem bonus uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT); Item* Gems[MAX_GEM_SOCKETS]; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) Gems[i] = gemGuids[i] ? _player->GetItemByGuid(gemGuids[i]) : NULL; GemPropertiesEntry const* GemProps[MAX_GEM_SOCKETS]; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) // get geminfo from dbc storage GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetProto()->GemProperties) : NULL; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) // check for hack maybe { if (!GemProps[i]) continue; // tried to put gem in socket where no socket exists if (!itemProto->Socket[i].Color) return; // tried to put normal gem in meta socket if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META) return; // tried to put meta gem in normal socket if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META) return; } uint32 GemEnchants[MAX_GEM_SOCKETS]; uint32 OldEnchants[MAX_GEM_SOCKETS]; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) // get new and old enchantments { GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0; OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + i)); } // check unique-equipped conditions for (int i = 0; i < MAX_GEM_SOCKETS; ++i) { if (!Gems[i]) continue; // continue check for case when attempt add 2 similar unique equipped gems in one item. ItemPrototype const* iGemProto = Gems[i]->GetProto(); // unique item (for new and already placed bit removed enchantments if (iGemProto->Flags & ITEM_FLAG_UNIQUE_EQUIPPED) { for (int j = 0; j < MAX_GEM_SOCKETS; ++j) { if (i == j) // skip self continue; if (Gems[j]) { if (iGemProto->ItemId == Gems[j]->GetEntry()) { _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); return; } } else if (OldEnchants[j]) { if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) { if (iGemProto->ItemId == enchantEntry->GemID) { _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); return; } } } } } // for equipped item check all equipment for duplicate equipped gems if (itemTarget->IsEquipped()) { if (InventoryResult res = _player->CanEquipUniqueItem(Gems[i], slot)) { _player->SendEquipError(res, itemTarget, NULL); return; } } } bool SocketBonusActivated = itemTarget->GemsFitSockets(); // save state of socketbonus _player->ToggleMetaGemsActive(slot, false); // turn off all metagems (except for the target item) // if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met // remove ALL enchants for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot) _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), false); for (int i = 0; i < MAX_GEM_SOCKETS; ++i) { if (GemEnchants[i]) { itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + i), GemEnchants[i], 0, 0); if (Item* guidItem = gemGuids[i] ? _player->GetItemByGuid(gemGuids[i]) : NULL) _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true); } } for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot) _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), true); bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();// current socketbonus state if (SocketBonusActivated != SocketBonusToBeActivated) // if there was a change... { _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, false); itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetProto()->socketBonus : 0), 0, 0); _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, true); // it is not displayed, client has an inbuilt system to determine if the bonus is activated } _player->ToggleMetaGemsActive(slot, true); // turn on all metagems (except for target item) }
/// \todo refactoring bool MailMessage::AddMessageDataToPacket(WorldPacket& data) { uint8 i = 0; uint32 j; std::vector<uint32>::iterator itr; Item* pItem; // add stuff if (deleted_flag) return false; uint8 guidsize; if (message_type == 0) guidsize = 8; else guidsize = 4; size_t msize = 2 + 4 + 1 + guidsize + 7 * 4 + (subject.size() + 1) + (body.size() + 1) + 1 + (items.size() * (1 + 2 * 4 + 7 * (3 * 4) + 6 * 4 + 1)); data << uint16(msize); // message size data << uint32(message_id); data << uint8(message_type); switch (message_type) { case NORMAL: data << uint64(sender_guid); break; case COD: case AUCTION: case GAMEOBJECT: case ITEM: data << uint32(Arcemu::Util::GUID_LOPART(sender_guid)); break; case CREATURE: data << uint32(Arcemu::Util::GET_CREATURE_ENTRY_FROM_GUID(sender_guid)); break; } data << uint32(cod); // cod data << uint32(0); data << uint32(stationery); data << uint32(money); // money data << uint32(checked_flag); // "checked" flag data << float((expire_time - uint32(UNIXTIME)) / 86400.0f); data << uint32(0); // mail template data << subject; data << body; data << uint8(items.size()); // item count if (!items.empty()) { for (itr = items.begin(); itr != items.end(); ++itr) { pItem = objmgr.LoadItem(*itr); if (pItem == NULL) continue; data << uint8(i++); data << uint32(pItem->GetLowGUID()); data << uint32(pItem->GetEntry()); for (j = 0; j < 7; ++j) { data << uint32(pItem->GetEnchantmentId(j)); data << uint32(pItem->GetEnchantmentDuration(j)); data << uint32(0); } data << uint32(pItem->GetItemRandomPropertyId()); data << uint32(pItem->GetItemRandomSuffixFactor()); data << uint32(pItem->GetStackCount()); data << uint32(pItem->GetChargesLeft()); data << uint32(pItem->GetDurabilityMax()); data << uint32(pItem->GetDurability()); data << uint8(0); // unknown delete pItem; } } return true; }
void WorldSession::HandleSocketGems(WorldPackets::Item::SocketGems& socketGems) { if (!socketGems.ItemGuid) return; //cheat -> tried to socket same gem multiple times if ((!socketGems.GemItem[0].IsEmpty() && (socketGems.GemItem[0] == socketGems.GemItem[1] || socketGems.GemItem[0] == socketGems.GemItem[2])) || (!socketGems.GemItem[1].IsEmpty() && (socketGems.GemItem[1] == socketGems.GemItem[2]))) return; Item* itemTarget = _player->GetItemByGuid(socketGems.ItemGuid); if (!itemTarget) //missing item to socket return; ItemTemplate const* itemProto = itemTarget->GetTemplate(); if (!itemProto) return; //this slot is excepted when applying / removing meta gem bonus uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT); Item* gems[MAX_GEM_SOCKETS]; memset(gems, 0, sizeof(gems)); ItemDynamicFieldGems gemData[MAX_GEM_SOCKETS]; memset(gemData, 0, sizeof(gemData)); GemPropertiesEntry const* gemProperties[MAX_GEM_SOCKETS]; memset(gemProperties, 0, sizeof(gemProperties)); ItemDynamicFieldGems const* oldGemData[MAX_GEM_SOCKETS]; memset(oldGemData, 0, sizeof(oldGemData)); for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) { if (Item* gem = _player->GetItemByGuid(socketGems.GemItem[i])) { gems[i] = gem; gemData[i].ItemId = gem->GetEntry(); gemData[i].Context = gem->GetUInt32Value(ITEM_FIELD_CONTEXT); for (std::size_t b = 0; b < gem->GetDynamicValues(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS).size() && b < 16; ++b) gemData[i].BonusListIDs[b] = gem->GetDynamicValue(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS, b); gemProperties[i] = sGemPropertiesStore.LookupEntry(gem->GetTemplate()->GetGemProperties()); } oldGemData[i] = itemTarget->GetGem(i); } // Find first prismatic socket uint32 firstPrismatic = 0; while (firstPrismatic < MAX_GEM_SOCKETS && itemTarget->GetSocketColor(firstPrismatic)) ++firstPrismatic; for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe { if (!gemProperties[i]) continue; // tried to put gem in socket where no socket exists (take care about prismatic sockets) if (!itemTarget->GetSocketColor(i)) { // no prismatic socket if (!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)) return; if (i != firstPrismatic) return; } // Gem must match socket color if (SocketColorToGemTypeMask[itemTarget->GetSocketColor(i)] != gemProperties[i]->Type) { // unless its red, blue, yellow or prismatic if (!(SocketColorToGemTypeMask[itemTarget->GetSocketColor(i)] & SOCKET_COLOR_PRISMATIC) || !(gemProperties[i]->Type & SOCKET_COLOR_PRISMATIC)) return; } } // check unique-equipped conditions for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) { if (!gems[i]) continue; // continue check for case when attempt add 2 similar unique equipped gems in one item. ItemTemplate const* iGemProto = gems[i]->GetTemplate(); // unique item (for new and already placed bit removed enchantments if (iGemProto->GetFlags() & ITEM_FLAG_UNIQUE_EQUIPPABLE) { for (uint32 j = 0; j < MAX_GEM_SOCKETS; ++j) { if (i == j) // skip self continue; if (gems[j]) { if (iGemProto->GetId() == gems[j]->GetEntry()) { _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); return; } } else if (oldGemData[j]) { if (iGemProto->GetId() == oldGemData[j]->ItemId) { _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); return; } } } } // unique limit type item int32 limit_newcount = 0; if (iGemProto->GetItemLimitCategory()) { if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->GetItemLimitCategory())) { // NOTE: limitEntry->mode is not checked because if item has limit then it is applied in equip case for (int j = 0; j < MAX_GEM_SOCKETS; ++j) { if (gems[j]) { // new gem if (iGemProto->GetItemLimitCategory() == gems[j]->GetTemplate()->GetItemLimitCategory()) ++limit_newcount; } else if (oldGemData[j]) { // existing gem if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(oldGemData[j]->ItemId)) if (iGemProto->GetItemLimitCategory() == jProto->GetItemLimitCategory()) ++limit_newcount; } } if (limit_newcount > 0 && uint32(limit_newcount) > limitEntry->Quantity) { _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); return; } } } // for equipped item check all equipment for duplicate equipped gems if (itemTarget->IsEquipped()) { if (InventoryResult res = _player->CanEquipUniqueItem(gems[i], slot, std::max(limit_newcount, 0))) { _player->SendEquipError(res, itemTarget, NULL); return; } } } bool SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus _player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item) //if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met //remove ALL mods - gem can change item level if (itemTarget->IsEquipped()) _player->_ApplyItemMods(itemTarget, itemTarget->GetSlot(), false); for (uint16 i = 0; i < MAX_GEM_SOCKETS; ++i) { if (gems[i]) { uint32 gemScalingLevel = _player->getLevel(); if (uint32 fixedLevel = gems[i]->GetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL)) gemScalingLevel = fixedLevel; itemTarget->SetGem(i, &gemData[i], gemScalingLevel); if (gemProperties[i] && gemProperties[i]->EnchantID) itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + i), gemProperties[i]->EnchantID, 0, 0, _player->GetGUID()); uint32 gemCount = 1; _player->DestroyItemCount(gems[i], gemCount, true); } } if (itemTarget->IsEquipped()) _player->_ApplyItemMods(itemTarget, itemTarget->GetSlot(), true); if (Item* childItem = _player->GetChildItemByGuid(itemTarget->GetChildItem())) { if (childItem->IsEquipped()) _player->_ApplyItemMods(childItem, childItem->GetSlot(), false); childItem->CopyArtifactDataFromParent(itemTarget); if (childItem->IsEquipped()) _player->_ApplyItemMods(childItem, childItem->GetSlot(), true); } bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change... { _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, false); itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetTemplate()->GetSocketBonus() : 0), 0, 0, _player->GetGUID()); _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, true); //it is not displayed, client has an inbuilt system to determine if the bonus is activated } _player->ToggleMetaGemsActive(slot, true); //turn on all metagems (except for target item) _player->RemoveTradeableItem(itemTarget); itemTarget->ClearSoulboundTradeable(_player); // clear tradeable flag itemTarget->SendUpdateSockets(); }
/** * Handles the packet sent by the client when requesting the current mail list. * It will send a list of all available mails in the players mailbox to the client. */ void WorldSession::HandleGetMailList(WorldPacket& recv_data) { ObjectGuid mailboxGuid; recv_data >> mailboxGuid; if (!CheckMailBox(mailboxGuid)) return; // client can't work with packets > max int16 value const uint32 maxPacketSize = 32767; uint32 mailsCount = 0; // send to client mails amount WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); // guess size data << uint8(0); // mail's count time_t cur_time = time(NULL); for (PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr) { // packet send mail count as uint8, prevent overflow if (mailsCount >= 254) break; // skip deleted or not delivered (deliver delay not expired) mails if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time) continue; /*[-ZERO] TODO recheck this size_t next_mail_size = 4+1+8+((*itr)->subject.size()+1)+4*7+1+item_count*(1+4+4+6*3*4+4+4+1+4+4+4); if(data.wpos()+next_mail_size > maxPacketSize) break; */ data << uint32((*itr)->messageID); // Message ID data << uint8((*itr)->messageType); // Message Type switch ((*itr)->messageType) { case MAIL_NORMAL: // sender guid data << ObjectGuid(HIGHGUID_PLAYER, (*itr)->sender); break; case MAIL_CREATURE: case MAIL_GAMEOBJECT: case MAIL_AUCTION: data << (uint32)(*itr)->sender; // creature/gameobject entry, auction id break; case MAIL_ITEM: // item entry (?) sender = "Unknown", NYI break; } data << (*itr)->subject; // Subject string - once 00, when mail type = 3 data << uint32((*itr)->itemTextId); // sure about this data << uint32(0); // unknown data << uint32((*itr)->stationery); // stationery (Stationery.dbc) // 1.12.1 can have only single item Item* item = (*itr)->items.size() > 0 ? _player->GetMItem((*itr)->items[0].item_guid) : NULL; data << uint32(item ? item->GetEntry() : 0); // entry // permanent enchantment data << uint32(item ? item->GetEnchantmentId((EnchantmentSlot)PERM_ENCHANTMENT_SLOT) : 0); // can be negative data << uint32(item ? item->GetItemRandomPropertyId() : 0); // unk data << uint32(item ? item->GetItemSuffixFactor() : 0); data << uint8(item ? item->GetCount() : 0); // stack count data << uint32(item ? item->GetSpellCharges() : 0); // charges // durability data << uint32(item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0); // durability data << uint32(item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0); data << uint32((*itr)->money); // copper data << uint32((*itr)->COD); // Cash on delivery data << uint32((*itr)->checked); // flags data << float(float((*itr)->expire_time - time(NULL)) / float(DAY));// Time data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc) mailsCount += 1; } data.put<uint8>(0, mailsCount); // set real send mails to client SendPacket(&data); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); }
//called when player lists his received mails void WorldSession::HandleGetMailList(WorldPacket & recv_data) { uint64 mailbox; recv_data >> mailbox; if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; Player* pl = _player; //load players mails, and mailed items if (!pl->m_mailsLoaded) pl ->_LoadMail(); // client can't work with packets > max int16 value const uint32 maxPacketSize = 32767; uint32 mailsCount = 0; // real send to client mails amount uint32 realCount = 0; // real mails amount WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); data << uint32(0); // real mail's count data << uint8(0); // mail's count time_t cur_time = time(NULL); for (PlayerMails::iterator itr = pl->GetMailBegin(); itr != pl->GetMailEnd(); ++itr) { // packet send mail count as uint8, prevent overflow if (mailsCount >= 254) { realCount += 1; continue; } // skip deleted or not delivered (deliver delay not expired) mails if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time) continue; uint8 item_count = (*itr)->items.size(); // max count is MAX_MAIL_ITEMS (12) size_t next_mail_size = 2+4+1+((*itr)->messageType == MAIL_NORMAL ? 8 : 4)+4*8+((*itr)->subject.size()+1)+((*itr)->body.size()+1)+1+item_count*(1+4+4+7*3*4+4+4+4+4+4+4+1); if (data.wpos()+next_mail_size > maxPacketSize) { realCount += 1; continue; } data << uint16(next_mail_size); // Message size data << uint32((*itr)->messageID); // Message ID data << uint8((*itr)->messageType); // Message Type switch((*itr)->messageType) { case MAIL_NORMAL: // sender guid data << uint64(MAKE_NEW_GUID((*itr)->sender, 0, HIGHGUID_PLAYER)); break; case MAIL_CREATURE: case MAIL_GAMEOBJECT: case MAIL_AUCTION: data << uint32((*itr)->sender); // creature/gameobject entry, auction id break; case MAIL_ITEM: // item entry (?) sender = "Unknown", NYI data << uint32(0); // item entry break; } data << uint64((*itr)->COD); // COD data << uint32(0); // probably changed in 3.3.3 data << uint32((*itr)->stationery); // stationery (Stationery.dbc) data << uint64((*itr)->money); // Gold data << uint32((*itr)->checked); // flags data << float(((*itr)->expire_time-time(NULL))/DAY); // Time data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc) data << (*itr)->subject; // Subject string - once 00, when mail type = 3, max 256 data << (*itr)->body; // message? max 8000 data << uint8(item_count); // client limit is 0x10 for (uint8 i = 0; i < item_count; ++i) { Item *item = pl->GetMItem((*itr)->items[i].item_guid); // item index (0-6?) data << uint8(i); // item guid low? data << uint32((item ? item->GetGUIDLow() : 0)); // entry data << uint32((item ? item->GetEntry() : 0)); for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j) { data << uint32((item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0)); data << uint32((item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0)); data << uint32((item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0)); } for (uint8 j = 0; j < 2; ++j) { data << uint32(0); data << uint32(0); data << uint32(0); } // can be negative data << int32((item ? item->GetItemRandomPropertyId() : 0)); // unk data << uint32((item ? item->GetItemSuffixFactor() : 0)); // stack count data << uint32((item ? item->GetCount() : 0)); // charges data << uint32((item ? item->GetSpellCharges() : 0)); // durability data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0)); // durability data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0)); // unknown wotlk data << uint8(0); } realCount += 1; mailsCount += 1; } data.put<uint32>(0, realCount); // this will display warning about undelivered mail to player if realCount > mailsCount data.put<uint8>(4, mailsCount); // set real send mails to client SendPacket(&data); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); }
void WorldSession::SendUpdateTrade() { Item *item = NULL; if( !_player || !_player->pTrader ) return; // reset trade status if (_player->acceptTrade) { _player->acceptTrade = false; SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); } if (_player->pTrader->acceptTrade) { _player->pTrader->acceptTrade = false; _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); } WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, (100)); // guess size data << (uint8 ) 1; // can be different (only seen 0 and 1) data << (uint32) 0; // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) data << (uint32) TRADE_SLOT_COUNT; // trade slots count/number?, = next field in most cases data << (uint32) TRADE_SLOT_COUNT; // trade slots count/number?, = prev field in most cases data << (uint32) _player->pTrader->tradeGold; // trader gold data << (uint32) 0; // spell casted on lowest slot item for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { item = (_player->pTrader->tradeItems[i] != NULL_SLOT ? _player->pTrader->GetItemByPos( _player->pTrader->tradeItems[i] ) : NULL); data << (uint8) i; // trade slot number, if not specified, then end of packet if(item) { data << (uint32) item->GetProto()->ItemId; // entry // display id data << (uint32) item->GetProto()->DisplayInfoID; // stack count data << (uint32) item->GetUInt32Value(ITEM_FIELD_STACK_COUNT); data << (uint32) 0; // probably gift=1, created_by=0? // gift creator data << (uint64) item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR); data << (uint32) item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT); for (uint8 j = 0; j < 3; ++j) data << (uint32) 0; // enchantment id (permanent/gems?) // creator data << (uint64) item->GetUInt64Value(ITEM_FIELD_CREATOR); data << (uint32) item->GetSpellCharges(); // charges data << (uint32) item->GetItemSuffixFactor(); // SuffixFactor // random properties id data << (uint32) item->GetItemRandomPropertyId(); data << (uint32) item->GetProto()->LockID; // lock id // max durability data << (uint32) item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); // durability data << (uint32) item->GetUInt32Value(ITEM_FIELD_DURABILITY); } else { for (uint8 j = 0; j < 18; j++) data << uint32(0); } } SendPacket(&data); }
void WorldSession::HandleSocketOpcode(WorldPacket& recvData) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SOCKET_GEMS"); uint64 item_guid; uint64 gem_guids[MAX_GEM_SOCKETS]; recvData >> item_guid; if (!item_guid) return; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) recvData >> gem_guids[i]; //cheat -> tried to socket same gem multiple times if ((gem_guids[0] && (gem_guids[0] == gem_guids[1] || gem_guids[0] == gem_guids[2])) || (gem_guids[1] && (gem_guids[1] == gem_guids[2]))) return; Item* itemTarget = _player->GetItemByGuid(item_guid); if (!itemTarget) //missing item to socket return; ItemTemplate const* itemProto = itemTarget->GetTemplate(); if (!itemProto) return; //this slot is excepted when applying / removing meta gem bonus uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT); Item* Gems[MAX_GEM_SOCKETS]; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) Gems[i] = gem_guids[i] ? _player->GetItemByGuid(gem_guids[i]) : NULL; GemPropertiesEntry const* GemProps[MAX_GEM_SOCKETS]; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get geminfo from dbc storage GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetTemplate()->GemProperties) : NULL; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe { if (!GemProps[i]) continue; // tried to put gem in socket where no socket exists (take care about prismatic sockets) if (!itemProto->Socket[i].Color) { // no prismatic socket if (!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)) return; // not first not-colored (not normaly used) socket if (i != 0 && !itemProto->Socket[i-1].Color && (i+1 >= MAX_GEM_SOCKETS || itemProto->Socket[i+1].Color)) return; // ok, this is first not colored socket for item with prismatic socket } // tried to put normal gem in meta socket if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META) return; // tried to put meta gem in normal socket if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META) return; } uint32 GemEnchants[MAX_GEM_SOCKETS]; uint32 OldEnchants[MAX_GEM_SOCKETS]; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get new and old enchantments { GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0; OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i)); } // check unique-equipped conditions for (int i = 0; i < MAX_GEM_SOCKETS; ++i) { if (!Gems[i]) continue; // continue check for case when attempt add 2 similar unique equipped gems in one item. ItemTemplate const* iGemProto = Gems[i]->GetTemplate(); // unique item (for new and already placed bit removed enchantments if (iGemProto->Flags & ITEM_PROTO_FLAG_UNIQUE_EQUIPPED) { for (int j = 0; j < MAX_GEM_SOCKETS; ++j) { if (i == j) // skip self continue; if (Gems[j]) { if (iGemProto->ItemId == Gems[j]->GetEntry()) { _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); return; } } else if (OldEnchants[j]) { if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) { if (iGemProto->ItemId == enchantEntry->GemID) { _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); return; } } } } } // unique limit type item int32 limit_newcount = 0; if (iGemProto->ItemLimitCategory) { if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->ItemLimitCategory)) { // NOTE: limitEntry->mode is not checked because if item has limit then it is applied in equip case for (int j = 0; j < MAX_GEM_SOCKETS; ++j) { if (Gems[j]) { // new gem if (iGemProto->ItemLimitCategory == Gems[j]->GetTemplate()->ItemLimitCategory) ++limit_newcount; } else if (OldEnchants[j]) { // existing gem if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(enchantEntry->GemID)) if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory) ++limit_newcount; } } if (limit_newcount > 0 && uint32(limit_newcount) > limitEntry->maxCount) { _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); return; } } } // for equipped item check all equipment for duplicate equipped gems if (itemTarget->IsEquipped()) { if (InventoryResult res = _player->CanEquipUniqueItem(Gems[i], slot, std::max(limit_newcount, 0))) { _player->SendEquipError(res, itemTarget, NULL); return; } } } bool SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus _player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item) //if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met //remove ALL enchants for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot) _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), false); for (int i = 0; i < MAX_GEM_SOCKETS; ++i) { if (GemEnchants[i]) { itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i], 0, 0); if (Item* guidItem = _player->GetItemByGuid(gem_guids[i])) _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true); } } for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), true); bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change... { _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, false); itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetTemplate()->socketBonus : 0), 0, 0); _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, true); //it is not displayed, client has an inbuilt system to determine if the bonus is activated } _player->ToggleMetaGemsActive(slot, true); //turn on all metagems (except for target item) _player->RemoveTradeableItem(itemTarget); itemTarget->ClearSoulboundTradeable(_player); // clear tradeable flag }
void HandleAfterHit() { if (_stackAmount < 5) return; Player* player = GetCaster()->ToPlayer(); if (Unit* target = GetHitUnit()) { Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); if (item == GetCastItem()) item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); if (!item) return; // item combat enchantments for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot) { SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(EnchantmentSlot(slot))); if (!enchant) continue; for (uint8 s = 0; s < 3; ++s) { if (enchant->type[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) continue; SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(enchant->spellid[s]); if (!spellInfo) { sLog->outError("Player::CastItemCombatSpell Enchant %i, player (Name: %s, GUID: %u) cast unknown spell %i", enchant->ID, player->GetName(), player->GetGUIDLow(), enchant->spellid[s]); continue; } // Proc only rogue poisons if (spellInfo->SpellFamilyName != SPELLFAMILY_ROGUE || spellInfo->Dispel != DISPEL_POISON) continue; // Do not reproc deadly if (spellInfo->SpellFamilyFlags.IsEqual(0x10000, 0x80000, 0)) continue; if (spellInfo->IsPositive()) player->CastSpell(player, enchant->spellid[s], true, item); else player->CastSpell(target, enchant->spellid[s], true, item); } } } }