void WorldSession::HandleArtifactSetAppearance(WorldPackets::Artifact::ArtifactSetAppearance& artifactSetAppearance)
{
    if (!_player->GetGameObjectIfCanInteractWith(artifactSetAppearance.ForgeGUID, GAMEOBJECT_TYPE_ARTIFACT_FORGE))
        return;

    ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifactSetAppearance.ArtifactAppearanceID);
    if (!artifactAppearance)
        return;

    Item* artifact = _player->GetItemByGuid(artifactSetAppearance.ArtifactGUID);
    if (!artifact)
        return;

    ArtifactAppearanceSetEntry const* artifactAppearanceSet = sArtifactAppearanceSetStore.LookupEntry(artifactAppearance->ArtifactAppearanceSetID);
    if (!artifactAppearanceSet || artifactAppearanceSet->ArtifactID != artifact->GetTemplate()->GetArtifactID())
        return;

    if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(artifactAppearance->UnlockPlayerConditionID))
        if (!sConditionMgr->IsPlayerMeetingCondition(_player, playerCondition))
            return;

    artifact->SetAppearanceModId(artifactAppearance->ItemAppearanceModifierID);
    artifact->SetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID, artifactAppearance->ID);
    artifact->SetState(ITEM_CHANGED, _player);
    Item* childItem = _player->GetChildItemByGuid(artifact->GetChildItem());
    if (childItem)
    {
        childItem->SetAppearanceModId(artifactAppearance->ItemAppearanceModifierID);
        childItem->SetState(ITEM_CHANGED, _player);
    }

    if (artifact->IsEquipped())
    {
        // change weapon appearance
        _player->SetVisibleItemSlot(artifact->GetSlot(), artifact);
        if (childItem)
            _player->SetVisibleItemSlot(childItem->GetSlot(), childItem);

        // change druid form appearance
        if (artifactAppearance->OverrideShapeshiftDisplayID && artifactAppearance->OverrideShapeshiftFormID && _player->GetShapeshiftForm() == ShapeshiftForm(artifactAppearance->OverrideShapeshiftFormID))
            _player->RestoreDisplayId();
    }
}
Beispiel #2
0
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();
}
Beispiel #3
0
void WorldSession::HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem& autoEquipItem)
{
    if (autoEquipItem.Inv.Items.size() != 1)
    {
        TC_LOG_ERROR("network", "HandleAutoEquipItemOpcode - Invalid itemCount (" SZFMTD ")", autoEquipItem.Inv.Items.size());
        return;
    }

    TC_LOG_DEBUG("network", "HandleAutoEquipItemOpcode: receive PackSlot: %u, Slot: %u",
        autoEquipItem.PackSlot, autoEquipItem.Slot);

    Item* srcItem  = _player->GetItemByPos(autoEquipItem.PackSlot, autoEquipItem.Slot);
    if (!srcItem)
        return;                                         // only at cheat

    uint16 dest;
    InventoryResult msg = _player->CanEquipItem(NULL_SLOT, dest, srcItem, !srcItem->IsBag());
    if (msg != EQUIP_ERR_OK)
    {
        _player->SendEquipError(msg, srcItem);
        return;
    }

    uint16 src = srcItem->GetPos();
    if (dest == src)                                    // prevent equip in same slot, only at cheat
        return;

    Item* dstItem = _player->GetItemByPos(dest);
    if (!dstItem)                                      // empty slot, simple case
    {
        if (!srcItem->GetChildItem().IsEmpty())
        {
            InventoryResult childEquipResult = _player->CanEquipChildItem(srcItem);
            if (childEquipResult != EQUIP_ERR_OK)
            {
                _player->SendEquipError(msg, srcItem);
                return;
            }
        }

        _player->RemoveItem(autoEquipItem.PackSlot, autoEquipItem.Slot, true);
        _player->EquipItem(dest, srcItem, true);
        if (!srcItem->GetChildItem().IsEmpty())
            _player->EquipChildItem(autoEquipItem.PackSlot, autoEquipItem.Slot, srcItem);

        _player->AutoUnequipOffhandIfNeed();
    }
    else                                                    // have currently equipped item, not simple case
    {
        uint8 dstbag = dstItem->GetBagSlot();
        uint8 dstslot = dstItem->GetSlot();

        msg = _player->CanUnequipItem(dest, !srcItem->IsBag());
        if (msg != EQUIP_ERR_OK)
        {
            _player->SendEquipError(msg, dstItem);
            return;
        }

        if (!dstItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD))
        {
            // check dest->src move possibility
            ItemPosCountVec sSrc;
            uint16 eSrc = 0;
            if (_player->IsInventoryPos(src))
            {
                msg = _player->CanStoreItem(autoEquipItem.PackSlot, autoEquipItem.Slot, sSrc, dstItem, true);
                if (msg != EQUIP_ERR_OK)
                    msg = _player->CanStoreItem(autoEquipItem.PackSlot, NULL_SLOT, sSrc, dstItem, true);
                if (msg != EQUIP_ERR_OK)
                    msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true);
            }
            else if (_player->IsBankPos(src))
            {
                msg = _player->CanBankItem(autoEquipItem.PackSlot, autoEquipItem.Slot, sSrc, dstItem, true);
                if (msg != EQUIP_ERR_OK)
                    msg = _player->CanBankItem(autoEquipItem.PackSlot, NULL_SLOT, sSrc, dstItem, true);
                if (msg != EQUIP_ERR_OK)
                    msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true);
            }
            else if (_player->IsEquipmentPos(src))
            {
                msg = _player->CanEquipItem(autoEquipItem.Slot, eSrc, dstItem, true);
                if (msg == EQUIP_ERR_OK)
                    msg = _player->CanUnequipItem(eSrc, true);
            }

            if (msg == EQUIP_ERR_OK && Player::IsEquipmentPos(dest) && !srcItem->GetChildItem().IsEmpty())
                msg = _player->CanEquipChildItem(srcItem);

            if (msg != EQUIP_ERR_OK)
            {
                _player->SendEquipError(msg, dstItem, srcItem);
                return;
            }

            // now do moves, remove...
            _player->RemoveItem(dstbag, dstslot, false);
            _player->RemoveItem(autoEquipItem.PackSlot, autoEquipItem.Slot, false);

            // add to dest
            _player->EquipItem(dest, srcItem, true);

            // add to src
            if (_player->IsInventoryPos(src))
                _player->StoreItem(sSrc, dstItem, true);
            else if (_player->IsBankPos(src))
                _player->BankItem(sSrc, dstItem, true);
            else if (_player->IsEquipmentPos(src))
                _player->EquipItem(eSrc, dstItem, true);

            if (Player::IsEquipmentPos(dest) && !srcItem->GetChildItem().IsEmpty())
                _player->EquipChildItem(autoEquipItem.PackSlot, autoEquipItem.Slot, srcItem);
        }
        else
        {
            if (Item* parentItem = _player->GetItemByGuid(dstItem->GetGuidValue(ITEM_FIELD_CREATOR)))
            {
                if (Player::IsEquipmentPos(dest))
                {
                    _player->AutoUnequipChildItem(parentItem);
                    // dest is now empty
                    _player->SwapItem(src, dest);
                    // src is now empty
                    _player->SwapItem(parentItem->GetPos(), src);
                }
            }
        }

        _player->AutoUnequipOffhandIfNeed();
    }
}