Core/Items: Implemented new item bonus and enchantment types

This commit is contained in:
Shauren
2017-05-07 16:47:49 +02:00
parent 8aa516528f
commit 6828c7bc2f
12 changed files with 132 additions and 27 deletions

View File

@@ -0,0 +1,10 @@
--
-- Table structure for table `artifact_power_picker`
--
DROP TABLE IF EXISTS `artifact_power_picker`;
CREATE TABLE `artifact_power_picker` (
`ID` int(10) unsigned NOT NULL DEFAULT '0',
`PlayerConditionID` int(10) unsigned NOT NULL DEFAULT '0',
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

View File

@@ -82,6 +82,9 @@ void HotfixDatabaseConnection::DoPrepareStatements()
// ArtifactPowerLink.db2
PrepareStatement(HOTFIX_SEL_ARTIFACT_POWER_LINK, "SELECT ID, FromArtifactPowerID, ToArtifactPowerID FROM artifact_power_link ORDER BY ID DESC", CONNECTION_SYNCH);
// ArtifactPowerPicker.db2
PrepareStatement(HOTFIX_SEL_ARTIFACT_POWER_PICKER, "SELECT ID, PlayerConditionID FROM artifact_power_picker ORDER BY ID DESC", CONNECTION_SYNCH);
// ArtifactPowerRank.db2
PrepareStatement(HOTFIX_SEL_ARTIFACT_POWER_RANK, "SELECT ID, SpellID, Value, ArtifactPowerID, Unknown, Rank FROM artifact_power_rank"
" ORDER BY ID DESC", CONNECTION_SYNCH);

View File

@@ -61,6 +61,8 @@ enum HotfixDatabaseStatements
HOTFIX_SEL_ARTIFACT_POWER_LINK,
HOTFIX_SEL_ARTIFACT_POWER_PICKER,
HOTFIX_SEL_ARTIFACT_POWER_RANK,
HOTFIX_SEL_ARTIFACT_QUEST_XP,

View File

@@ -290,6 +290,20 @@ struct ArtifactPowerLinkLoadInfo
}
};
struct ArtifactPowerPickerLoadInfo
{
static DB2LoadInfo const* Instance()
{
static DB2FieldMeta const fields[] =
{
{ false, FT_INT, "ID" },
{ false, FT_INT, "PlayerConditionID" },
};
static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, ArtifactPowerPickerMeta::Instance(), HOTFIX_SEL_ARTIFACT_POWER_PICKER);
return &loadInfo;
}
};
struct ArtifactPowerRankLoadInfo
{
static DB2LoadInfo const* Instance()

View File

@@ -36,6 +36,7 @@ DB2Storage<ArtifactAppearanceSetEntry> sArtifactAppearanceSetStore("Art
DB2Storage<ArtifactCategoryEntry> sArtifactCategoryStore("ArtifactCategory.db2", ArtifactCategoryLoadInfo::Instance());
DB2Storage<ArtifactPowerEntry> sArtifactPowerStore("ArtifactPower.db2", ArtifactPowerLoadInfo::Instance());
DB2Storage<ArtifactPowerLinkEntry> sArtifactPowerLinkStore("ArtifactPowerLink.db2", ArtifactPowerLinkLoadInfo::Instance());
DB2Storage<ArtifactPowerPickerEntry> sArtifactPowerPickerStore("ArtifactPowerPicker.db2", ArtifactPowerPickerLoadInfo::Instance());
DB2Storage<ArtifactPowerRankEntry> sArtifactPowerRankStore("ArtifactPowerRank.db2", ArtifactPowerRankLoadInfo::Instance());
DB2Storage<ArtifactQuestXPEntry> sArtifactQuestXPStore("ArtifactQuestXP.db2", ArtifactQuestXpLoadInfo::Instance());
DB2Storage<AuctionHouseEntry> sAuctionHouseStore("AuctionHouse.db2", AuctionHouseLoadInfo::Instance());
@@ -332,6 +333,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sArtifactCategoryStore);
LOAD_DB2(sArtifactPowerStore);
LOAD_DB2(sArtifactPowerLinkStore);
LOAD_DB2(sArtifactPowerPickerStore);
LOAD_DB2(sArtifactPowerRankStore);
LOAD_DB2(sAuctionHouseStore);
LOAD_DB2(sBankBagSlotPricesStore);

View File

@@ -33,6 +33,7 @@ TC_GAME_API extern DB2Storage<ArtifactCategoryEntry> sArtifactCat
TC_GAME_API extern DB2Storage<ArtifactAppearanceEntry> sArtifactAppearanceStore;
TC_GAME_API extern DB2Storage<ArtifactAppearanceSetEntry> sArtifactAppearanceSetStore;
TC_GAME_API extern DB2Storage<ArtifactPowerEntry> sArtifactPowerStore;
TC_GAME_API extern DB2Storage<ArtifactPowerPickerEntry> sArtifactPowerPickerStore;
TC_GAME_API extern DB2Storage<AuctionHouseEntry> sAuctionHouseStore;
TC_GAME_API extern DB2Storage<BankBagSlotPricesEntry> sBankBagSlotPricesStore;
TC_GAME_API extern DB2Storage<BannedAddOnsEntry> sBannedAddOnsStore;

View File

@@ -191,6 +191,12 @@ struct ArtifactPowerLinkEntry
uint16 ToArtifactPowerID;
};
struct ArtifactPowerPickerEntry
{
uint32 ID;
uint32 PlayerConditionID;
};
struct ArtifactPowerRankEntry
{
uint32 ID;

View File

@@ -658,7 +658,8 @@ enum ItemEnchantmentType
ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_TYPE = 9,
ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_ID = 10,
ITEM_ENCHANTMENT_TYPE_BONUS_LIST_ID = 11,
ITEM_ENCHANTMENT_TYPE_BONUS_LIST_CURVE = 12
ITEM_ENCHANTMENT_TYPE_BONUS_LIST_CURVE = 12,
ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_PICKER = 13
};
enum ItemExtendedCostFlags
@@ -686,7 +687,10 @@ enum ItemBonusType
ITEM_BONUS_SCALING_STAT_DISTRIBUTION = 11,
ITEM_BONUS_DISENCHANT_LOOT_ID = 12,
ITEM_BONUS_SCALING_STAT_DISTRIBUTION_2 = 13,
ITEM_BONUS_ITEM_LEVEL_OVERRIDE = 14
ITEM_BONUS_ITEM_LEVEL_OVERRIDE = 14,
ITEM_BONUS_RANDOM_ENCHANTMENT = 15, // Responsible for showing "<Random additional stats>" or "+%d Rank Random Minor Trait" in the tooltip before item is obtained
ITEM_BONUS_BONDING = 16,
ITEM_BONUS_RELIC_TYPE = 17
};
enum ItemLimitCategoryMode

View File

@@ -324,7 +324,7 @@ bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owne
if (itemProto->GetArtifactID())
{
InitArtifactPowers(itemProto->GetArtifactID());
InitArtifactPowers(itemProto->GetArtifactID(), 0);
for (ArtifactAppearanceEntry const* artifactAppearance : sArtifactAppearanceStore)
{
if (ArtifactAppearanceSetEntry const* artifactAppearanceSet = sArtifactAppearanceSetStore.LookupEntry(artifactAppearance->ArtifactAppearanceSetID))
@@ -677,12 +677,6 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
SetSpellCharges(i, atoi(tokens[i]));
SetUInt32Value(ITEM_FIELD_FLAGS, itemFlags);
// Remove bind flag for items vs BIND_NONE set
if (IsSoulBound() && proto->GetBonding() == BIND_NONE)
{
ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND, false);
need_save = true;
}
_LoadIntoDataField(fields[8].GetString(), ITEM_FIELD_ENCHANTMENT, MAX_ENCHANTMENT_SLOT * MAX_ENCHANTMENT_OFFSET);
m_randomEnchantment.Type = ItemRandomEnchantmentType(fields[9].GetUInt8());
@@ -769,6 +763,13 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
SetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL, fields[42].GetUInt32());
SetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL, fields[43].GetUInt32());
// Remove bind flag for items vs BIND_NONE set
if (IsSoulBound() && GetBonding() == BIND_NONE)
{
ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND, false);
need_save = true;
}
if (need_save) // normal item changed state set not work at loading
{
uint8 index = 0;
@@ -784,9 +785,9 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
return true;
}
void Item::LoadArtifactData(uint64 xp, uint32 artifactAppearanceId, std::vector<ItemDynamicFieldArtifactPowers>& powers)
void Item::LoadArtifactData(Player* owner, uint64 xp, uint32 artifactAppearanceId, std::vector<ItemDynamicFieldArtifactPowers>& powers)
{
InitArtifactPowers(GetTemplate()->GetArtifactID());
InitArtifactPowers(GetTemplate()->GetArtifactID(), 0);
SetUInt64Value(ITEM_FIELD_ARTIFACT_XP, xp);
SetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID, artifactAppearanceId);
if (ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifactAppearanceId))
@@ -815,6 +816,18 @@ void Item::LoadArtifactData(uint64 xp, uint32 artifactAppearanceId, std::vector<
if (artifactPower->ID == enchant->EffectSpellID[i])
power.CurrentRankWithBonus += enchant->EffectPointsMin[i];
break;
case ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_PICKER:
if (_bonusData.GemRelicType[e - SOCK_ENCHANTMENT_SLOT] != -1)
{
if (ArtifactPowerPickerEntry const* artifactPowerPicker = sArtifactPowerPickerStore.LookupEntry(enchant->EffectSpellID[i]))
{
PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(artifactPowerPicker->PlayerConditionID);
if (!playerCondition || sConditionMgr->IsPlayerMeetingCondition(GetOwner(), playerCondition))
if (artifactPower->RelicType == _bonusData.GemRelicType[e - SOCK_ENCHANTMENT_SLOT])
power.CurrentRankWithBonus += enchant->EffectPointsMin[i];
}
}
break;
default:
break;
}
@@ -1190,8 +1203,8 @@ void Item::SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint
owner->GetSession()->SendEnchantmentLog(GetOwnerGUID(), caster, GetEntry(), id);
}
ApplyArtifactPowerEnchantmentBonuses(GetEnchantmentId(slot), false, owner);
ApplyArtifactPowerEnchantmentBonuses(id, true, owner);
ApplyArtifactPowerEnchantmentBonuses(slot, GetEnchantmentId(slot), false, owner);
ApplyArtifactPowerEnchantmentBonuses(slot, id, true, owner);
SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_ID_OFFSET, id);
SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET, duration);
@@ -1262,6 +1275,8 @@ void Item::SetGem(uint16 slot, ItemDynamicFieldGems const* gem, uint32 gemScalin
if (uint32 scaledIlvl = uint32(sDB2Manager.GetCurveValueAt(ssd->ItemLevelCurveID, gemScalingLevel)))
gemBaseItemLevel = scaledIlvl;
_bonusData.GemRelicType[slot] = gemBonus.RelicType;
for (uint32 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i)
{
switch (gemEnchant->Effect[i])
@@ -2325,10 +2340,13 @@ void Item::SetArtifactPower(ItemDynamicFieldArtifactPowers const* artifactPower,
SetDynamicStructuredValue(ITEM_DYNAMIC_FIELD_ARTIFACT_POWERS, index, artifactPower);
}
void Item::InitArtifactPowers(uint8 artifactId)
void Item::InitArtifactPowers(uint8 artifactId, uint8 artifactTier)
{
for (ArtifactPowerEntry const* artifactPower : sDB2Manager.GetArtifactPowers(artifactId))
{
if (artifactPower->ArtifactTier != artifactTier)
continue;
if (m_artifactPowerIdToIndex.find(artifactPower->ID) != m_artifactPowerIdToIndex.end())
continue;
@@ -2350,7 +2368,7 @@ uint32 Item::GetTotalPurchasedArtifactPowers() const
return purchasedRanks;
}
void Item::ApplyArtifactPowerEnchantmentBonuses(uint32 enchantId, bool apply, Player* owner)
void Item::ApplyArtifactPowerEnchantmentBonuses(EnchantmentSlot slot, uint32 enchantId, bool apply, Player* owner)
{
if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId))
{
@@ -2393,6 +2411,35 @@ void Item::ApplyArtifactPowerEnchantmentBonuses(uint32 enchantId, bool apply, Pl
SetArtifactPower(&newPower);
}
break;
case ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_PICKER:
if (slot >= SOCK_ENCHANTMENT_SLOT && slot <= SOCK_ENCHANTMENT_SLOT_3 && _bonusData.GemRelicType[slot - SOCK_ENCHANTMENT_SLOT] != -1)
{
if (ArtifactPowerPickerEntry const* artifactPowerPicker = sArtifactPowerPickerStore.LookupEntry(enchant->EffectSpellID[i]))
{
PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(artifactPowerPicker->PlayerConditionID);
if (!playerCondition || sConditionMgr->IsPlayerMeetingCondition(owner, playerCondition))
{
for (ItemDynamicFieldArtifactPowers const& artifactPower : GetArtifactPowers())
{
if (sArtifactPowerStore.AssertEntry(artifactPower.ArtifactPowerId)->RelicType == _bonusData.GemRelicType[slot - SOCK_ENCHANTMENT_SLOT])
{
ItemDynamicFieldArtifactPowers newPower = artifactPower;
if (apply)
newPower.CurrentRankWithBonus += enchant->EffectPointsMin[i];
else
newPower.CurrentRankWithBonus -= enchant->EffectPointsMin[i];
if (IsEquipped())
if (ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower.ArtifactPowerId, newPower.CurrentRankWithBonus ? newPower.CurrentRankWithBonus - 1 : 0))
owner->ApplyArtifactPowerRank(this, artifactPowerRank, newPower.CurrentRankWithBonus != 0);
SetArtifactPower(&newPower);
}
}
}
}
}
break;
default:
break;
}
@@ -2466,12 +2513,17 @@ void BonusData::Initialize(ItemTemplate const* proto)
{
SocketColor[i] = proto->GetSocketColor(i);
GemItemLevelBonus[i] = 0;
GemRelicType[i] = -1;
GemRelicRankBonus[i] = 0;
}
Bonding = proto->GetBonding();
AppearanceModID = 0;
RepairCostMultiplier = 1.0f;
ScalingStatDistribution = proto->GetScalingStatDistribution();
ItemLevelOverride = 0;
RelicType = -1;
HasItemLevelBonus = false;
_state.AppearanceModPriority = std::numeric_limits<int32>::max();
@@ -2567,5 +2619,11 @@ void BonusData::AddBonus(uint32 type, int32 const (&values)[2])
_state.ItemLevelOverridePriority = values[1];
}
break;
case ITEM_BONUS_BONDING:
Bonding = ItemBondingType(values[0]);
break;
case ITEM_BONUS_RELIC_TYPE:
RelicType = values[0];
break;
}
}

View File

@@ -272,11 +272,15 @@ struct BonusData
int32 ItemStatAllocation[MAX_ITEM_PROTO_STATS];
float ItemStatSocketCostMultiplier[MAX_ITEM_PROTO_STATS];
uint32 SocketColor[MAX_ITEM_PROTO_SOCKETS];
ItemBondingType Bonding;
uint32 AppearanceModID;
float RepairCostMultiplier;
uint32 ScalingStatDistribution;
uint32 ItemLevelOverride;
uint32 GemItemLevelBonus[MAX_ITEM_PROTO_SOCKETS];
int32 GemRelicType[MAX_ITEM_PROTO_SOCKETS];
uint16 GemRelicRankBonus[MAX_ITEM_PROTO_SOCKETS];
int32 RelicType;
bool HasItemLevelBonus;
void Initialize(ItemTemplate const* proto);
@@ -328,6 +332,7 @@ class TC_GAME_API Item : public Object
void SetOwnerGUID(ObjectGuid guid) { SetGuidValue(ITEM_FIELD_OWNER, guid); }
Player* GetOwner()const;
ItemBondingType GetBonding() const { return _bonusData.Bonding; }
void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND, val); }
bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND); }
bool IsBoundAccountWide() const { return (GetTemplate()->GetFlags() & ITEM_FLAG_IS_BOUND_TO_ACCOUNT) != 0; }
@@ -336,7 +341,7 @@ class TC_GAME_API Item : public Object
bool IsBoundByEnchant() const;
virtual void SaveToDB(SQLTransaction& trans);
virtual bool LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fields, uint32 entry);
void LoadArtifactData(uint64 xp, uint32 artifactAppearanceId, std::vector<ItemDynamicFieldArtifactPowers>& powers); // must be called after LoadFromDB to have gems (relics) initialized
void LoadArtifactData(Player* owner, uint64 xp, uint32 artifactAppearanceId, std::vector<ItemDynamicFieldArtifactPowers>& powers); // must be called after LoadFromDB to have gems (relics) initialized
void AddBonuses(uint32 bonusListID);
@@ -510,9 +515,9 @@ class TC_GAME_API Item : public Object
ItemDynamicFieldArtifactPowers const* GetArtifactPower(uint32 artifactPowerId) const;
void SetArtifactPower(ItemDynamicFieldArtifactPowers const* artifactPower, bool createIfMissing = false);
void InitArtifactPowers(uint8 artifactId);
void InitArtifactPowers(uint8 artifactId, uint8 artifactTier);
uint32 GetTotalPurchasedArtifactPowers() const;
void ApplyArtifactPowerEnchantmentBonuses(uint32 enchantId, bool apply, Player* owner);
void ApplyArtifactPowerEnchantmentBonuses(EnchantmentSlot slot, uint32 enchantId, bool apply, Player* owner);
void CopyArtifactDataFromParent(Item* parent);
void GiveArtifactXp(uint64 amount, Item* sourceItem, uint32 artifactCategoryId);

View File

@@ -11663,9 +11663,9 @@ Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool
if (!pItem)
return nullptr;
if (pItem->GetTemplate()->GetBonding() == BIND_ON_ACQUIRE ||
pItem->GetTemplate()->GetBonding() == BIND_QUEST ||
(pItem->GetTemplate()->GetBonding() == BIND_ON_EQUIP && IsBagPos(pos)))
if (pItem->GetBonding() == BIND_ON_ACQUIRE ||
pItem->GetBonding() == BIND_QUEST ||
(pItem->GetBonding() == BIND_ON_EQUIP && IsBagPos(pos)))
pItem->SetBinding(true);
Bag* pBag = (bag == INVENTORY_SLOT_BAG_0) ? NULL : GetBagByPos(bag);
@@ -11706,9 +11706,9 @@ Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool
}
else
{
if (pItem2->GetTemplate()->GetBonding() == BIND_ON_ACQUIRE ||
pItem2->GetTemplate()->GetBonding() == BIND_QUEST ||
(pItem2->GetTemplate()->GetBonding() == BIND_ON_EQUIP && IsBagPos(pos)))
if (pItem2->GetBonding() == BIND_ON_ACQUIRE ||
pItem2->GetBonding() == BIND_QUEST ||
(pItem2->GetBonding() == BIND_ON_EQUIP && IsBagPos(pos)))
pItem2->SetBinding(true);
pItem2->SetCount(pItem2->GetCount() + count);
@@ -12016,7 +12016,7 @@ void Player::VisualizeItem(uint8 slot, Item* pItem)
return;
// check also BIND_ON_ACQUIRE and BIND_QUEST for .additem or .additemset case by GM (not binded at adding to inventory)
if (pItem->GetTemplate()->GetBonding() == BIND_ON_EQUIP || pItem->GetTemplate()->GetBonding() == BIND_ON_ACQUIRE || pItem->GetTemplate()->GetBonding() == BIND_QUEST)
if (pItem->GetBonding() == BIND_ON_EQUIP || pItem->GetBonding() == BIND_ON_ACQUIRE || pItem->GetBonding() == BIND_QUEST)
{
pItem->SetBinding(true);
if (IsInWorld())
@@ -18332,7 +18332,7 @@ void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult arti
{
auto artifactDataItr = artifactData.find(item->GetGUID());
if (item->GetTemplate()->GetArtifactID() && artifactDataItr != artifactData.end())
item->LoadArtifactData(std::get<0>(artifactDataItr->second), std::get<1>(artifactDataItr->second), std::get<2>(artifactDataItr->second));
item->LoadArtifactData(this, std::get<0>(artifactDataItr->second), std::get<1>(artifactDataItr->second), std::get<2>(artifactDataItr->second));
ObjectGuid bagGuid = fields[44].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[44].GetUInt64()) : ObjectGuid::Empty;
uint8 slot = fields[45].GetUInt8();

View File

@@ -106,7 +106,7 @@ void WorldSession::HandleUseItemOpcode(WorldPackets::Spells::UseItem& packet)
}
// check also BIND_ON_ACQUIRE and BIND_QUEST for .additem or .additemset case by GM (not binded at adding to inventory)
if (item->GetTemplate()->GetBonding() == BIND_ON_USE || item->GetTemplate()->GetBonding() == BIND_ON_ACQUIRE || item->GetTemplate()->GetBonding() == BIND_QUEST)
if (item->GetBonding() == BIND_ON_USE || item->GetBonding() == BIND_ON_ACQUIRE || item->GetBonding() == BIND_QUEST)
{
if (!item->IsSoulBound())
{