267 lines
8.7 KiB
C++
267 lines
8.7 KiB
C++
/*
|
|
* Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
|
|
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "DB2Stores.h"
|
|
#include "World.h"
|
|
#include "ItemTemplate.h"
|
|
#include "Player.h"
|
|
|
|
int32 const SocketColorToGemTypeMask[19] =
|
|
{
|
|
0,
|
|
SOCKET_COLOR_META,
|
|
SOCKET_COLOR_RED,
|
|
SOCKET_COLOR_YELLOW,
|
|
SOCKET_COLOR_BLUE,
|
|
SOCKET_COLOR_HYDRAULIC,
|
|
SOCKET_COLOR_COGWHEEL,
|
|
SOCKET_COLOR_PRISMATIC,
|
|
SOCKET_COLOR_RELIC_IRON,
|
|
SOCKET_COLOR_RELIC_BLOOD,
|
|
SOCKET_COLOR_RELIC_SHADOW,
|
|
SOCKET_COLOR_RELIC_FEL,
|
|
SOCKET_COLOR_RELIC_ARCANE,
|
|
SOCKET_COLOR_RELIC_FROST,
|
|
SOCKET_COLOR_RELIC_FIRE,
|
|
SOCKET_COLOR_RELIC_WATER,
|
|
SOCKET_COLOR_RELIC_LIFE,
|
|
SOCKET_COLOR_RELIC_WIND,
|
|
SOCKET_COLOR_RELIC_HOLY
|
|
};
|
|
|
|
char const* ItemTemplate::GetName(LocaleConstant locale) const
|
|
{
|
|
if (!strlen(ExtendedData->Display->Str[locale]))
|
|
return GetDefaultLocaleName();
|
|
|
|
return ExtendedData->Display->Str[locale];
|
|
}
|
|
|
|
|
|
bool ItemTemplate::CanChangeEquipStateInCombat() const
|
|
{
|
|
switch (GetInventoryType())
|
|
{
|
|
case INVTYPE_RELIC:
|
|
case INVTYPE_SHIELD:
|
|
case INVTYPE_HOLDABLE:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (GetClass())
|
|
{
|
|
case ITEM_CLASS_WEAPON:
|
|
case ITEM_CLASS_PROJECTILE:
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
uint32 ItemTemplate::GetSkill() const
|
|
{
|
|
static uint32 const itemWeaponSkills[MAX_ITEM_SUBCLASS_WEAPON] =
|
|
{
|
|
SKILL_AXES, SKILL_TWO_HANDED_AXES, SKILL_BOWS, SKILL_GUNS, SKILL_MACES,
|
|
SKILL_TWO_HANDED_MACES, SKILL_POLEARMS, SKILL_SWORDS, SKILL_TWO_HANDED_SWORDS, SKILL_WARGLAIVES,
|
|
SKILL_STAVES, 0, 0, SKILL_FIST_WEAPONS, 0,
|
|
SKILL_DAGGERS, 0, 0, SKILL_CROSSBOWS, SKILL_WANDS,
|
|
SKILL_FISHING
|
|
};
|
|
|
|
static uint32 const itemArmorSkills[MAX_ITEM_SUBCLASS_ARMOR] =
|
|
{
|
|
0, SKILL_CLOTH, SKILL_LEATHER, SKILL_MAIL, SKILL_PLATE_MAIL, 0, SKILL_SHIELD, 0, 0, 0, 0
|
|
};
|
|
|
|
|
|
switch (GetClass())
|
|
{
|
|
case ITEM_CLASS_WEAPON:
|
|
if (GetSubClass() >= MAX_ITEM_SUBCLASS_WEAPON)
|
|
return 0;
|
|
else
|
|
return itemWeaponSkills[GetSubClass()];
|
|
|
|
case ITEM_CLASS_ARMOR:
|
|
if (GetSubClass() >= MAX_ITEM_SUBCLASS_ARMOR)
|
|
return 0;
|
|
else
|
|
return itemArmorSkills[GetSubClass()];
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
char const* ItemTemplate::GetDefaultLocaleName() const
|
|
{
|
|
return ExtendedData->Display->Str[sWorld->GetDefaultDbcLocale()];
|
|
}
|
|
|
|
uint32 ItemTemplate::GetArmor(uint32 itemLevel) const
|
|
{
|
|
uint32 quality = ItemQualities(GetQuality()) != ITEM_QUALITY_HEIRLOOM ? ItemQualities(GetQuality()) : ITEM_QUALITY_RARE;
|
|
if (quality > ITEM_QUALITY_ARTIFACT)
|
|
return 0;
|
|
|
|
// all items but shields
|
|
if (GetClass() != ITEM_CLASS_ARMOR || GetSubClass() != ITEM_SUBCLASS_ARMOR_SHIELD)
|
|
{
|
|
ItemArmorQualityEntry const* armorQuality = sItemArmorQualityStore.LookupEntry(itemLevel);
|
|
ItemArmorTotalEntry const* armorTotal = sItemArmorTotalStore.LookupEntry(itemLevel);
|
|
if (!armorQuality || !armorTotal)
|
|
return 0;
|
|
|
|
uint32 inventoryType = GetInventoryType();
|
|
if (inventoryType == INVTYPE_ROBE)
|
|
inventoryType = INVTYPE_CHEST;
|
|
|
|
ArmorLocationEntry const* location = sArmorLocationStore.LookupEntry(inventoryType);
|
|
if (!location)
|
|
return 0;
|
|
|
|
if (GetSubClass() < ITEM_SUBCLASS_ARMOR_CLOTH || GetSubClass() > ITEM_SUBCLASS_ARMOR_PLATE)
|
|
return 0;
|
|
|
|
float total = 1.0f;
|
|
float locationModifier = 1.0f;
|
|
switch (GetSubClass())
|
|
{
|
|
case ITEM_SUBCLASS_ARMOR_CLOTH:
|
|
total = armorTotal->Cloth;
|
|
locationModifier = location->Clothmodifier;
|
|
break;
|
|
case ITEM_SUBCLASS_ARMOR_LEATHER:
|
|
total = armorTotal->Leather;
|
|
locationModifier = location->Leathermodifier;
|
|
break;
|
|
case ITEM_SUBCLASS_ARMOR_MAIL:
|
|
total = armorTotal->Mail;
|
|
locationModifier = location->Chainmodifier;
|
|
break;
|
|
case ITEM_SUBCLASS_ARMOR_PLATE:
|
|
total = armorTotal->Plate;
|
|
locationModifier = location->Platemodifier;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return uint32(armorQuality->Qualitymod[quality] * total * locationModifier + 0.5f);
|
|
}
|
|
|
|
// shields
|
|
ItemArmorShieldEntry const* shield = sItemArmorShieldStore.LookupEntry(itemLevel);
|
|
if (!shield)
|
|
return 0;
|
|
|
|
return uint32(shield->Quality[quality] + 0.5f);
|
|
}
|
|
|
|
void ItemTemplate::GetDamage(uint32 itemLevel, float& minDamage, float& maxDamage) const
|
|
{
|
|
minDamage = maxDamage = 0.0f;
|
|
uint32 quality = ItemQualities(GetQuality()) != ITEM_QUALITY_HEIRLOOM ? ItemQualities(GetQuality()) : ITEM_QUALITY_RARE;
|
|
if (GetClass() != ITEM_CLASS_WEAPON || quality > ITEM_QUALITY_ARTIFACT)
|
|
return;
|
|
|
|
// get the right store here
|
|
if (GetInventoryType() > INVTYPE_RANGEDRIGHT)
|
|
return;
|
|
|
|
float dps = 0.0f;
|
|
switch (GetInventoryType())
|
|
{
|
|
case INVTYPE_AMMO:
|
|
dps = sItemDamageAmmoStore.AssertEntry(itemLevel)->Quality[quality];
|
|
break;
|
|
case INVTYPE_2HWEAPON:
|
|
if (GetFlags2() & ITEM_FLAG2_CASTER_WEAPON)
|
|
dps = sItemDamageTwoHandCasterStore.AssertEntry(itemLevel)->Quality[quality];
|
|
else
|
|
dps = sItemDamageTwoHandStore.AssertEntry(itemLevel)->Quality[quality];
|
|
break;
|
|
case INVTYPE_RANGED:
|
|
case INVTYPE_THROWN:
|
|
case INVTYPE_RANGEDRIGHT:
|
|
switch (GetSubClass())
|
|
{
|
|
case ITEM_SUBCLASS_WEAPON_WAND:
|
|
dps = sItemDamageOneHandCasterStore.AssertEntry(itemLevel)->Quality[quality];
|
|
break;
|
|
case ITEM_SUBCLASS_WEAPON_BOW:
|
|
case ITEM_SUBCLASS_WEAPON_GUN:
|
|
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
|
|
if (GetFlags2() & ITEM_FLAG2_CASTER_WEAPON)
|
|
dps = sItemDamageTwoHandCasterStore.AssertEntry(itemLevel)->Quality[quality];
|
|
else
|
|
dps = sItemDamageTwoHandStore.AssertEntry(itemLevel)->Quality[quality];
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
break;
|
|
case INVTYPE_WEAPON:
|
|
case INVTYPE_WEAPONMAINHAND:
|
|
case INVTYPE_WEAPONOFFHAND:
|
|
if (GetFlags2() & ITEM_FLAG2_CASTER_WEAPON)
|
|
dps = sItemDamageOneHandCasterStore.AssertEntry(itemLevel)->Quality[quality];
|
|
else
|
|
dps = sItemDamageOneHandStore.AssertEntry(itemLevel)->Quality[quality];
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
float avgDamage = dps * GetDelay() * 0.001f;
|
|
minDamage = (GetDmgVariance() * -0.5f + 1.0f) * avgDamage;
|
|
maxDamage = floor(float(avgDamage * (GetDmgVariance() * 0.5f + 1.0f) + 0.5f));
|
|
}
|
|
|
|
bool ItemTemplate::IsUsableByLootSpecialization(Player const* player, bool alwaysAllowBoundToAccount) const
|
|
{
|
|
if (GetFlags() & ITEM_FLAG_IS_BOUND_TO_ACCOUNT && alwaysAllowBoundToAccount)
|
|
return true;
|
|
|
|
uint32 spec = player->GetUInt32Value(ACTIVE_PLAYER_FIELD_LOOT_SPEC_ID);
|
|
if (!spec)
|
|
spec = player->GetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID);
|
|
if (!spec)
|
|
spec = player->GetDefaultSpecId();
|
|
|
|
ChrSpecializationEntry const* chrSpecialization = sChrSpecializationStore.LookupEntry(spec);
|
|
if (!chrSpecialization)
|
|
return false;
|
|
|
|
std::size_t levelIndex = 0;
|
|
if (player->getLevel() >= 110)
|
|
levelIndex = 2;
|
|
else if (player->getLevel() > 40)
|
|
levelIndex = 1;
|
|
|
|
return Specializations[levelIndex].test(CalculateItemSpecBit(chrSpecialization));
|
|
}
|
|
|
|
std::size_t ItemTemplate::CalculateItemSpecBit(ChrSpecializationEntry const* spec)
|
|
{
|
|
return (spec->ClassID - 1) * MAX_SPECIALIZATIONS + spec->OrderIndex;
|
|
}
|