aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTraesh <Traesh@users.noreply.github.com>2018-07-31 23:31:44 +0200
committerShauren <shauren.trinity@gmail.com>2018-07-31 23:31:44 +0200
commit55a0a2d3f6146ace93d5558ce16469d3cca28bdc (patch)
treed1b61e149fcb44c0c153c3ed614e42640a81df28
parent394f9775a7c6d597c9744db37783985b2e228572 (diff)
Core/Artifact Handle Artifact tiers + Artifact unlock (3rd relic bonus) (#21593)
-rw-r--r--sql/base/characters_database.sql4
-rw-r--r--sql/updates/characters/master/2018_07_31_00_characters.sql1
-rw-r--r--sql/updates/hotfixes/master/2018_03_18_00_hotfixes.sql29
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp4
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp8
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.h4
-rw-r--r--src/server/game/DataStores/DB2LoadInfo.h36
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp4
-rw-r--r--src/server/game/DataStores/DB2Stores.h2
-rw-r--r--src/server/game/DataStores/DB2Structure.h20
-rw-r--r--src/server/game/DataStores/DBCEnums.h14
-rw-r--r--src/server/game/Entities/Item/Item.cpp68
-rw-r--r--src/server/game/Entities/Item/Item.h3
-rw-r--r--src/server/game/Entities/Object/Object.cpp11
-rw-r--r--src/server/game/Entities/Object/Object.h1
-rw-r--r--src/server/game/Entities/Player/Player.cpp39
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Handlers/ArtifactHandler.cpp80
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp11
-rw-r--r--src/server/game/Server/Packets/ArtifactPackets.cpp8
-rw-r--r--src/server/game/Server/Packets/ArtifactPackets.h11
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp2
-rw-r--r--src/server/game/World/World.cpp7
-rw-r--r--src/server/game/World/World.h1
-rw-r--r--src/server/worldserver/worldserver.conf.dist8
25 files changed, 320 insertions, 58 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql
index ef73caef3aa..687f66af959 100644
--- a/sql/base/characters_database.sql
+++ b/sql/base/characters_database.sql
@@ -2821,6 +2821,7 @@ CREATE TABLE `item_instance_artifact` (
`itemGuid` bigint(20) unsigned NOT NULL,
`xp` bigint(20) unsigned NOT NULL DEFAULT '0',
`artifactAppearanceId` int(10) unsigned NOT NULL DEFAULT '0',
+ `artifactTierId` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`itemGuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -3564,7 +3565,8 @@ INSERT INTO `updates` VALUES
('2018_02_19_00_characters.sql','75A0FFAFD0633921708DB0F72F9CC9796ACB960B','RELEASED','2018-02-19 22:33:32',117),
('2018_03_04_00_characters.sql','2A4CD2EE2547E718490706FADC78BF36F0DED8D6','RELEASED','2018-03-04 18:15:24',0),
('2018_04_28_00_characters.sql','CBD0FDC0F32DE3F456F7CE3D9CAD6933CD6A50F5','RELEASED','2018-04-28 12:44:09',0),
-('2018_07_28_00_characters.sql','31F66AE7831251A8915625EC7F10FA138AB8B654','RELEASED','2018-07-28 18:30:19',0);
+('2018_07_28_00_characters.sql','31F66AE7831251A8915625EC7F10FA138AB8B654','RELEASED','2018-07-28 18:30:19',0),
+('2018_07_31_00_characters.sql','7DA8D4A4534520B23E6F5BBD5B8EE205B799C798','RELEASED','2018-07-31 20:54:39',0);
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
UNLOCK TABLES;
diff --git a/sql/updates/characters/master/2018_07_31_00_characters.sql b/sql/updates/characters/master/2018_07_31_00_characters.sql
new file mode 100644
index 00000000000..fed2be26b77
--- /dev/null
+++ b/sql/updates/characters/master/2018_07_31_00_characters.sql
@@ -0,0 +1 @@
+ALTER TABLE `item_instance_artifact` ADD `artifactTierId` int(10) unsigned NOT NULL DEFAULT '0' AFTER `artifactAppearanceId`;
diff --git a/sql/updates/hotfixes/master/2018_03_18_00_hotfixes.sql b/sql/updates/hotfixes/master/2018_03_18_00_hotfixes.sql
new file mode 100644
index 00000000000..d4271bb2523
--- /dev/null
+++ b/sql/updates/hotfixes/master/2018_03_18_00_hotfixes.sql
@@ -0,0 +1,29 @@
+--
+-- Table structure for table `artifact_tier`
+--
+DROP TABLE IF EXISTS `artifact_tier`;
+CREATE TABLE `artifact_tier` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `ArtifactTier` int(10) unsigned NOT NULL DEFAULT '0',
+ `MaxNumTraits` int(10) unsigned NOT NULL DEFAULT '0',
+ `MaxArtifactKnowledge` int(10) unsigned NOT NULL DEFAULT '0',
+ `KnowledgePlayerCondition` int(10) unsigned NOT NULL DEFAULT '0',
+ `MinimumEmpowerKnowledge` int(10) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `artifact_unlock`
+--
+DROP TABLE IF EXISTS `artifact_unlock`;
+CREATE TABLE `artifact_unlock` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `ItemBonusListID` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `PowerRank` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `PowerID` int(10) unsigned NOT NULL DEFAULT '0',
+ `PlayerConditionID` int(10) unsigned NOT NULL DEFAULT '0',
+ `ArtifactID` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index 3590fea0414..d0227fde660 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -182,8 +182,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ITEM_INSTANCE_TRANSMOG, "DELETE FROM item_instance_transmog WHERE itemGuid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ITEM_INSTANCE_TRANSMOG_BY_OWNER, "DELETE iit FROM item_instance_transmog iit LEFT JOIN item_instance ii ON iit.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_ITEM_INSTANCE_ARTIFACT, "SELECT a.itemGuid, a.xp, a.artifactAppearanceId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN character_inventory ci ON ci.item = ap.itemGuid WHERE ci.guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_INS_ITEM_INSTANCE_ARTIFACT, "INSERT INTO item_instance_artifact (itemGuid, xp, artifactAppearanceId) VALUES (?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_ITEM_INSTANCE_ARTIFACT, "SELECT a.itemGuid, a.xp, a.artifactAppearanceId, a.artifactTierId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN character_inventory ci ON ci.item = ap.itemGuid WHERE ci.guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_ITEM_INSTANCE_ARTIFACT, "INSERT INTO item_instance_artifact (itemGuid, xp, artifactAppearanceId, artifactTierId) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT, "DELETE FROM item_instance_artifact WHERE itemGuid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_BY_OWNER, "DELETE iia FROM item_instance_artifact iia LEFT JOIN item_instance ii ON iia.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_ITEM_INSTANCE_ARTIFACT_POWERS, "INSERT INTO item_instance_artifact_powers (itemGuid, artifactPowerId, purchasedRank) VALUES (?, ?, ?)", CONNECTION_ASYNC);
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp
index 23772fa2e57..8c1bb487363 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.cpp
+++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp
@@ -95,6 +95,14 @@ void HotfixDatabaseConnection::DoPrepareStatements()
PrepareStatement(HOTFIX_SEL_ARTIFACT_QUEST_XP, "SELECT ID, Difficulty1, Difficulty2, Difficulty3, Difficulty4, Difficulty5, Difficulty6, "
"Difficulty7, Difficulty8, Difficulty9, Difficulty10 FROM artifact_quest_xp ORDER BY ID DESC", CONNECTION_SYNCH);
+ // ArtifactTier.db2
+ PrepareStatement(HOTFIX_SEL_ARTIFACT_TIER, "SELECT ID, ArtifactTier, MaxNumTraits, MaxArtifactKnowledge, KnowledgePlayerCondition, "
+ "MinimumEmpowerKnowledge FROM artifact_tier ORDER BY ID DESC", CONNECTION_SYNCH);
+
+ // ArtifactUnlock.db2
+ PrepareStatement(HOTFIX_SEL_ARTIFACT_UNLOCK, "SELECT ID, ItemBonusListID, PowerRank, PowerID, PlayerConditionID, ArtifactID FROM artifact_unlock"
+ " ORDER BY ID DESC", CONNECTION_SYNCH);
+
// AuctionHouse.db2
PrepareStatement(HOTFIX_SEL_AUCTION_HOUSE, "SELECT ID, Name, FactionID, DepositRate, ConsignmentRate FROM auction_house ORDER BY ID DESC", CONNECTION_SYNCH);
PREPARE_LOCALE_STMT(HOTFIX_SEL_AUCTION_HOUSE, "SELECT ID, Name_lang FROM auction_house_locale WHERE locale = ?", CONNECTION_SYNCH);
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h
index 5f15a3adea1..77f3600ff39 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.h
+++ b/src/server/database/Database/Implementation/HotfixDatabase.h
@@ -66,6 +66,10 @@ enum HotfixDatabaseStatements : uint32
HOTFIX_SEL_ARTIFACT_QUEST_XP,
+ HOTFIX_SEL_ARTIFACT_TIER,
+
+ HOTFIX_SEL_ARTIFACT_UNLOCK,
+
HOTFIX_SEL_AUCTION_HOUSE,
HOTFIX_SEL_AUCTION_HOUSE_LOCALE,
diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h
index 5560141fd7b..a6b4c1c0426 100644
--- a/src/server/game/DataStores/DB2LoadInfo.h
+++ b/src/server/game/DataStores/DB2LoadInfo.h
@@ -345,6 +345,42 @@ struct ArtifactQuestXpLoadInfo
}
};
+struct ArtifactTierLoadInfo
+{
+ static DB2LoadInfo const* Instance()
+ {
+ static DB2FieldMeta const fields[] =
+ {
+ { false, FT_INT, "ID" },
+ { false, FT_INT, "ArtifactTier" },
+ { false, FT_INT, "MaxNumTraits" },
+ { false, FT_INT, "MaxArtifactKnowledge" },
+ { false, FT_INT, "KnowledgePlayerCondition" },
+ { false, FT_INT, "MinimumEmpowerKnowledge" },
+ };
+ static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, ArtifactTierMeta::Instance(), HOTFIX_SEL_ARTIFACT_TIER);
+ return &loadInfo;
+ }
+};
+
+struct ArtifactUnlockLoadInfo
+{
+ static DB2LoadInfo const* Instance()
+ {
+ static DB2FieldMeta const fields[] =
+ {
+ { false, FT_INT, "ID" },
+ { false, FT_SHORT, "ItemBonusListID" },
+ { false, FT_BYTE, "PowerRank" },
+ { false, FT_INT, "PowerID" },
+ { false, FT_INT, "PlayerConditionID" },
+ { false, FT_BYTE, "ArtifactID" },
+ };
+ static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, ArtifactUnlockMeta::Instance(), HOTFIX_SEL_ARTIFACT_UNLOCK);
+ return &loadInfo;
+ }
+};
+
struct AuctionHouseLoadInfo
{
static DB2LoadInfo const* Instance()
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index 7faae631eb9..fe91d679d97 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -50,6 +50,8 @@ DB2Storage<ArtifactPowerLinkEntry> sArtifactPowerLinkStore("Artifac
DB2Storage<ArtifactPowerPickerEntry> sArtifactPowerPickerStore("ArtifactPowerPicker.db2", ArtifactPowerPickerLoadInfo::Instance());
DB2Storage<ArtifactPowerRankEntry> sArtifactPowerRankStore("ArtifactPowerRank.db2", ArtifactPowerRankLoadInfo::Instance());
DB2Storage<ArtifactQuestXPEntry> sArtifactQuestXPStore("ArtifactQuestXP.db2", ArtifactQuestXpLoadInfo::Instance());
+DB2Storage<ArtifactTierEntry> sArtifactTierStore("ArtifactTier.db2", ArtifactTierLoadInfo::Instance());
+DB2Storage<ArtifactUnlockEntry> sArtifactUnlockStore("ArtifactUnlock.db2", ArtifactUnlockLoadInfo::Instance());
DB2Storage<AuctionHouseEntry> sAuctionHouseStore("AuctionHouse.db2", AuctionHouseLoadInfo::Instance());
DB2Storage<BankBagSlotPricesEntry> sBankBagSlotPricesStore("BankBagSlotPrices.db2", BankBagSlotPricesLoadInfo::Instance());
DB2Storage<BannedAddonsEntry> sBannedAddonsStore("BannedAddons.db2", BannedAddonsLoadInfo::Instance());
@@ -488,6 +490,8 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sArtifactPowerLinkStore);
LOAD_DB2(sArtifactPowerPickerStore);
LOAD_DB2(sArtifactPowerRankStore);
+ LOAD_DB2(sArtifactTierStore);
+ LOAD_DB2(sArtifactUnlockStore);
LOAD_DB2(sAuctionHouseStore);
LOAD_DB2(sBankBagSlotPricesStore);
LOAD_DB2(sBannedAddonsStore);
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index a7b070d5492..d5f0af253a0 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -45,6 +45,8 @@ TC_GAME_API extern DB2Storage<ArtifactAppearanceEntry> sArtifactApp
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<ArtifactTierEntry> sArtifactTierStore;
+TC_GAME_API extern DB2Storage<ArtifactUnlockEntry> sArtifactUnlockStore;
TC_GAME_API extern DB2Storage<AuctionHouseEntry> sAuctionHouseStore;
TC_GAME_API extern DB2Storage<BankBagSlotPricesEntry> sBankBagSlotPricesStore;
TC_GAME_API extern DB2Storage<BannedAddonsEntry> sBannedAddonsStore;
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index 639c7b66877..e5f46417a81 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -219,6 +219,26 @@ struct ArtifactQuestXPEntry
uint32 Difficulty[10];
};
+struct ArtifactTierEntry
+{
+ uint32 ID;
+ uint32 ArtifactTier;
+ uint32 MaxNumTraits;
+ uint32 MaxArtifactKnowledge;
+ uint32 KnowledgePlayerCondition;
+ uint32 MinimumEmpowerKnowledge;
+};
+
+struct ArtifactUnlockEntry
+{
+ uint32 ID;
+ uint16 ItemBonusListID;
+ uint8 PowerRank;
+ uint32 PowerID;
+ uint32 PlayerConditionID;
+ uint8 ArtifactID;
+};
+
struct AuctionHouseEntry
{
uint32 ID;
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index 7807bb5538e..80d109a51a1 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -146,15 +146,26 @@ enum AreaMountFlags
AREA_MOUNT_FLAG_UNDERWATER_ALLOWED = 0x8
};
+enum ArtifactCategory : uint32
+{
+ ARTIFACT_CATEGORY_PRIMARY = 1,
+ ARTIFACT_CATEGORY_FISHING = 2
+};
+
enum ArtifactPowerFlag : uint8
{
ARTIFACT_POWER_FLAG_GOLD = 0x01,
- ARTIFACT_POWER_FLAG_FIRST = 0x02,
+ ARTIFACT_POWER_FLAG_NO_LINK_REQUIRED = 0x02,
ARTIFACT_POWER_FLAG_FINAL = 0x04,
ARTIFACT_POWER_FLAG_SCALES_WITH_NUM_POWERS = 0x08,
ARTIFACT_POWER_FLAG_DONT_COUNT_FIRST_BONUS_RANK = 0x10,
+ ARTIFACT_POWER_FLAG_MAX_RANK_WITH_TIER = 0x20,
+
+ ARTIFACT_POWER_FLAG_FIRST = ARTIFACT_POWER_FLAG_NO_LINK_REQUIRED | ARTIFACT_POWER_FLAG_DONT_COUNT_FIRST_BONUS_RANK,
};
+#define MAX_ARTIFACT_TIER 1
+
#define BATTLE_PET_SPECIES_MAX_ID 2164
enum ChrSpecializationFlag
@@ -1050,7 +1061,6 @@ enum CurrencyTypes
CURRENCY_TYPE_JUSTICE_POINTS = 395,
CURRENCY_TYPE_VALOR_POINTS = 396,
CURRENCY_TYPE_APEXIS_CRYSTALS = 823,
- CURRENCY_TYPE_ARTIFACT_KNOWLEDGE = 1171,
};
enum WorldMapTransformsFlags
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index 71bc71f9430..95c4b0f4ac2 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -320,7 +320,7 @@ bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemId, Player const* owne
SetSpellCharges(i, itemProto->Effects[i]->Charges);
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemProto->Effects[i]->SpellID))
if (owner && spellInfo->HasEffect(SPELL_EFFECT_GIVE_ARTIFACT_POWER))
- if (uint32 artifactKnowledgeLevel = owner->GetCurrency(CURRENCY_TYPE_ARTIFACT_KNOWLEDGE))
+ if (uint32 artifactKnowledgeLevel = sWorld->getIntConfig(CONFIG_CURRENCY_START_ARTIFACT_KNOWLEDGE))
SetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL, artifactKnowledgeLevel + 1);
}
@@ -346,6 +346,8 @@ bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemId, Player const* owne
break;
}
}
+
+ CheckArtifactRelicSlotUnlock(owner ? owner : GetOwner());
}
return true;
@@ -536,6 +538,7 @@ void Item::SaveToDB(SQLTransaction& trans)
stmt->setUInt64(0, GetGUID().GetCounter());
stmt->setUInt64(1, GetUInt64Value(ITEM_FIELD_ARTIFACT_XP));
stmt->setUInt32(2, GetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID));
+ stmt->setUInt32(3, GetModifier(ITEM_MODIFIER_ARTIFACT_TIER));
trans->Append(stmt);
for (ItemDynamicFieldArtifactPowers const& artifactPower : GetArtifactPowers())
@@ -794,11 +797,15 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
return true;
}
-void Item::LoadArtifactData(Player* owner, uint64 xp, uint32 artifactAppearanceId, std::vector<ItemDynamicFieldArtifactPowers>& powers)
+void Item::LoadArtifactData(Player* owner, uint64 xp, uint32 artifactAppearanceId, uint32 artifactTier, std::vector<ItemDynamicFieldArtifactPowers>& powers)
{
- InitArtifactPowers(GetTemplate()->GetArtifactID(), 0);
+ for (uint8 i = 0; i <= artifactTier; ++i)
+ InitArtifactPowers(GetTemplate()->GetArtifactID(), i);
+
SetUInt64Value(ITEM_FIELD_ARTIFACT_XP, xp);
SetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID, artifactAppearanceId);
+ SetModifier(ITEM_MODIFIER_ARTIFACT_TIER, artifactTier);
+
if (ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifactAppearanceId))
SetAppearanceModId(artifactAppearance->ItemAppearanceModifierID);
@@ -856,6 +863,23 @@ void Item::LoadArtifactData(Player* owner, uint64 xp, uint32 artifactAppearanceI
power.CurrentRankWithBonus = totalPurchasedRanks + 1;
SetArtifactPower(&power);
}
+
+ CheckArtifactRelicSlotUnlock(owner ? owner : GetOwner());
+}
+
+void Item::CheckArtifactRelicSlotUnlock(Player const* owner)
+{
+ if (!owner)
+ return;
+
+ uint8 artifactId = GetTemplate()->GetArtifactID();
+ if (!artifactId)
+ return;
+
+ for (ArtifactUnlockEntry const* artifactUnlock : sArtifactUnlockStore)
+ if (artifactUnlock->ArtifactID == artifactId)
+ if (owner->MeetPlayerCondition(artifactUnlock->PlayerConditionID))
+ AddBonuses(artifactUnlock->ItemBonusListID);
}
/*static*/
@@ -2371,6 +2395,9 @@ uint16 Item::GetVisibleItemVisual(Player const* owner) const
void Item::AddBonuses(uint32 bonusListID)
{
+ if (HasDynamicValue(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS, bonusListID))
+ return;
+
if (DB2Manager::ItemBonusList const* bonuses = sDB2Manager.GetItemBonusList(bonusListID))
{
AddDynamicValue(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS, bonusListID);
@@ -2426,7 +2453,7 @@ void Item::InitArtifactPowers(uint8 artifactId, uint8 artifactTier)
memset(&powerData, 0, sizeof(powerData));
powerData.ArtifactPowerId = artifactPower->ID;
powerData.PurchasedRank = 0;
- powerData.CurrentRankWithBonus = (artifactPower->Flags & ARTIFACT_POWER_FLAG_FIRST) ? 1 : 0;
+ powerData.CurrentRankWithBonus = (artifactPower->Flags & ARTIFACT_POWER_FLAG_FIRST) == ARTIFACT_POWER_FLAG_FIRST ? 1 : 0;
SetArtifactPower(&powerData, true);
}
}
@@ -2534,24 +2561,21 @@ void Item::GiveArtifactXp(uint64 amount, Item* sourceItem, uint32 artifactCatego
if (artifactCategoryId)
{
- if (ArtifactCategoryEntry const* artifactCategory = sArtifactCategoryStore.LookupEntry(artifactCategoryId))
- {
- uint32 artifactKnowledgeLevel = 1;
- if (sourceItem && sourceItem->GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL))
- artifactKnowledgeLevel = sourceItem->GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL);
- else
- artifactKnowledgeLevel = owner->GetCurrency(artifactCategory->XpMultCurrencyID) + 1;
-
- if (GtArtifactKnowledgeMultiplierEntry const* artifactKnowledge = sArtifactKnowledgeMultiplierGameTable.GetRow(artifactKnowledgeLevel))
- amount = uint64(amount * artifactKnowledge->Multiplier);
-
- if (amount >= 5000)
- amount = 50 * (amount / 50);
- else if (amount >= 1000)
- amount = 25 * (amount / 25);
- else if (amount >= 50)
- amount = 5 * (amount / 5);
- }
+ uint32 artifactKnowledgeLevel = 1;
+ if (sourceItem && sourceItem->GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL))
+ artifactKnowledgeLevel = sourceItem->GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL);
+ else if (artifactCategoryId == ARTIFACT_CATEGORY_PRIMARY)
+ artifactKnowledgeLevel = sWorld->getIntConfig(CONFIG_CURRENCY_START_ARTIFACT_KNOWLEDGE) + 1;
+
+ if (GtArtifactKnowledgeMultiplierEntry const* artifactKnowledge = sArtifactKnowledgeMultiplierGameTable.GetRow(artifactKnowledgeLevel))
+ amount = uint64(amount * artifactKnowledge->Multiplier);
+
+ if (amount >= 5000)
+ amount = 50 * (amount / 50);
+ else if (amount >= 1000)
+ amount = 25 * (amount / 25);
+ else if (amount >= 50)
+ amount = 5 * (amount / 5);
}
SetUInt64Value(ITEM_FIELD_ARTIFACT_XP, GetUInt64Value(ITEM_FIELD_ARTIFACT_XP) + amount);
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index d795983b4ed..a51415abcbb 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -155,7 +155,8 @@ 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(Player* owner, 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, uint32 artifactTier, std::vector<ItemDynamicFieldArtifactPowers>& powers); // must be called after LoadFromDB to have gems (relics) initialized
+ void CheckArtifactRelicSlotUnlock(Player const* owner);
void AddBonuses(uint32 bonusListID);
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 17d767f04e9..36bed0bfd4b 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1433,6 +1433,17 @@ uint32 Object::GetDynamicValue(uint16 index, uint16 offset) const
return _dynamicValues[index][offset];
}
+bool Object::HasDynamicValue(uint16 index, uint32 value)
+{
+ ASSERT(index < _dynamicValuesCount || PrintIndexError(index, false));
+ std::vector<uint32>& values = _dynamicValues[index];
+ for (std::size_t i = 0; i < values.size(); ++i)
+ if (values[i] == value)
+ return true;
+
+ return false;
+}
+
void Object::AddDynamicValue(uint16 index, uint32 value)
{
ASSERT(index < _dynamicValuesCount || PrintIndexError(index, false));
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 539cf8fbccf..2ebea15a58d 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -188,6 +188,7 @@ class TC_GAME_API Object
std::vector<uint32> const& GetDynamicValues(uint16 index) const;
uint32 GetDynamicValue(uint16 index, uint16 offset) const;
+ bool HasDynamicValue(uint16 index, uint32 value);
void AddDynamicValue(uint16 index, uint32 value);
void RemoveDynamicValue(uint16 index, uint32 value);
void ClearDynamicValue(uint16 index);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 456cd7d910e..d8b2e46974e 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -2458,6 +2458,10 @@ void Player::GiveLevel(uint8 level)
_ApplyAllLevelScaleItemMods(true); // Moved to above SetFullHealth so player will have full health from Heirlooms
+ if (Aura const* artifactAura = GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE))
+ if (Item* artifact = GetItemByGuid(artifactAura->GetCastItemGUID()))
+ artifact->CheckArtifactRelicSlotUnlock(this);
+
// Only health and mana are set to maximum.
SetFullHealth();
SetFullPower(POWER_MANA);
@@ -18604,9 +18608,9 @@ void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult arti
//NOTE2: the "order by `slot`" is needed because mainhand weapons are (wrongly?)
//expected to be equipped before offhand items (@todo fixme)
- // 0 1 2 3 4
- // SELECT a.itemGuid, a.xp, a.artifactAppearanceId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN character_inventory ci ON ci.item = ap.guid WHERE ci.guid = ?
- std::unordered_map<ObjectGuid, std::tuple<uint64, uint32, std::vector<ItemDynamicFieldArtifactPowers>>> artifactData;
+ // 0 1 2 3 4 5
+ // SELECT a.itemGuid, a.xp, a.artifactAppearanceId, a.artifactTierId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN character_inventory ci ON ci.item = ap.guid WHERE ci.guid = ?
+ std::unordered_map<ObjectGuid, std::tuple<uint64, uint32, uint32, std::vector<ItemDynamicFieldArtifactPowers>>> artifactData;
if (artifactsResult)
{
do
@@ -18615,17 +18619,23 @@ void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult arti
auto& artifactDataEntry = artifactData[ObjectGuid::Create<HighGuid::Item>(fields[0].GetUInt64())];
std::get<0>(artifactDataEntry) = fields[1].GetUInt64();
std::get<1>(artifactDataEntry) = fields[2].GetUInt32();
+ std::get<2>(artifactDataEntry) = fields[3].GetUInt32();
ItemDynamicFieldArtifactPowers artifactPowerData;
- artifactPowerData.ArtifactPowerId = fields[3].GetUInt32();
- artifactPowerData.PurchasedRank = fields[4].GetUInt8();
+ artifactPowerData.ArtifactPowerId = fields[4].GetUInt32();
+ artifactPowerData.PurchasedRank = fields[5].GetUInt8();
if (ArtifactPowerEntry const* artifactPower = sArtifactPowerStore.LookupEntry(artifactPowerData.ArtifactPowerId))
{
- if (artifactPowerData.PurchasedRank > artifactPower->MaxPurchasableRank)
- artifactPowerData.PurchasedRank = artifactPower->MaxPurchasableRank;
+ uint32 maxRank = artifactPower->MaxPurchasableRank;
+ // allow ARTIFACT_POWER_FLAG_FINAL to overflow maxrank here - needs to be handled in Item::CheckArtifactUnlock (will refund artifact power)
+ if (artifactPower->Flags & ARTIFACT_POWER_FLAG_MAX_RANK_WITH_TIER && artifactPower->Tier < std::get<2>(artifactDataEntry))
+ maxRank += std::get<2>(artifactDataEntry) - artifactPower->Tier;
+
+ if (artifactPowerData.PurchasedRank > maxRank)
+ artifactPowerData.PurchasedRank = maxRank;
- artifactPowerData.CurrentRankWithBonus = (artifactPower->Flags & ARTIFACT_POWER_FLAG_FIRST) ? 1 : 0;
+ artifactPowerData.CurrentRankWithBonus = (artifactPower->Flags & ARTIFACT_POWER_FLAG_FIRST) == ARTIFACT_POWER_FLAG_FIRST ? 1 : 0;
- std::get<2>(artifactDataEntry).push_back(artifactPowerData);
+ std::get<3>(artifactDataEntry).push_back(artifactPowerData);
}
} while (artifactsResult->NextRow());
@@ -18649,7 +18659,7 @@ void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult arti
{
auto artifactDataItr = artifactData.find(item->GetGUID());
if (item->GetTemplate()->GetArtifactID() && artifactDataItr != artifactData.end())
- item->LoadArtifactData(this, 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), std::get<3>(artifactDataItr->second));
ObjectGuid bagGuid = fields[45].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[45].GetUInt64()) : ObjectGuid::Empty;
uint8 slot = fields[46].GetUInt8();
@@ -27663,6 +27673,15 @@ void Player::SendPlayerChoice(ObjectGuid sender, int32 choiceId)
SendDirectMessage(displayPlayerChoice.Write());
}
+bool Player::MeetPlayerCondition(uint32 conditionId) const
+{
+ if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(conditionId))
+ if (!ConditionMgr::IsPlayerMeetingCondition(this, playerCondition))
+ return false;
+
+ return true;
+}
+
float Player::GetCollisionHeight(bool mounted) const
{
if (mounted)
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index e0022324bc6..93dcfb4b593 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2378,6 +2378,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void SendPlayerChoice(ObjectGuid sender, int32 choiceId);
+ bool MeetPlayerCondition(uint32 conditionId) const;
+
protected:
// Gamemaster whisper whitelist
GuidList WhisperList;
diff --git a/src/server/game/Handlers/ArtifactHandler.cpp b/src/server/game/Handlers/ArtifactHandler.cpp
index 774dedff867..8e9451daaf9 100644
--- a/src/server/game/Handlers/ArtifactHandler.cpp
+++ b/src/server/game/Handlers/ArtifactHandler.cpp
@@ -35,9 +35,11 @@ void WorldSession::HandleArtifactAddPower(WorldPackets::Artifact::ArtifactAddPow
if (!artifact)
return;
+ uint32 currentArtifactTier = artifact->GetModifier(ITEM_MODIFIER_ARTIFACT_TIER);
+
uint64 xpCost = 0;
if (GtArtifactLevelXPEntry const* cost = sArtifactLevelXPGameTable.GetRow(artifact->GetTotalPurchasedArtifactPowers() + 1))
- xpCost = uint64(artifact->GetModifier(ITEM_MODIFIER_ARTIFACT_TIER) == 1 ? cost->XP2 : cost->XP);
+ xpCost = uint64(currentArtifactTier == MAX_ARTIFACT_TIER ? cost->XP2 : cost->XP);
if (xpCost > artifact->GetUInt64Value(ITEM_FIELD_ARTIFACT_XP))
return;
@@ -53,32 +55,47 @@ void WorldSession::HandleArtifactAddPower(WorldPackets::Artifact::ArtifactAddPow
if (!artifactPowerEntry)
return;
- if (artifactAddPower.PowerChoices[0].Rank != artifactPower->PurchasedRank + 1 ||
- artifactAddPower.PowerChoices[0].Rank > artifactPowerEntry->MaxPurchasableRank)
+ if (artifactPowerEntry->Tier > currentArtifactTier)
return;
- if (std::unordered_set<uint32> const* artifactPowerLinks = sDB2Manager.GetArtifactPowerLinks(artifactPower->ArtifactPowerId))
+ uint32 maxRank = artifactPowerEntry->MaxPurchasableRank;
+ if (artifactPowerEntry->Tier < currentArtifactTier)
{
- bool hasAnyLink = false;
- for (uint32 artifactPowerLinkId : *artifactPowerLinks)
- {
- ArtifactPowerEntry const* artifactPowerLink = sArtifactPowerStore.LookupEntry(artifactPowerLinkId);
- if (!artifactPowerLink)
- continue;
+ if (artifactPowerEntry->Flags & ARTIFACT_POWER_FLAG_FINAL)
+ maxRank = 1;
+ else if (artifactPowerEntry->Flags & ARTIFACT_POWER_FLAG_MAX_RANK_WITH_TIER)
+ maxRank += currentArtifactTier - artifactPowerEntry->Tier;
+ }
- ItemDynamicFieldArtifactPowers const* artifactPowerLinkLearned = artifact->GetArtifactPower(artifactPowerLinkId);
- if (!artifactPowerLinkLearned)
- continue;
+ if (artifactAddPower.PowerChoices[0].Rank != artifactPower->PurchasedRank + 1 ||
+ artifactAddPower.PowerChoices[0].Rank > maxRank)
+ return;
- if (artifactPowerLinkLearned->PurchasedRank >= artifactPowerLink->MaxPurchasableRank)
+ if (!(artifactPowerEntry->Flags & ARTIFACT_POWER_FLAG_NO_LINK_REQUIRED))
+ {
+ if (std::unordered_set<uint32> const* artifactPowerLinks = sDB2Manager.GetArtifactPowerLinks(artifactPower->ArtifactPowerId))
+ {
+ bool hasAnyLink = false;
+ for (uint32 artifactPowerLinkId : *artifactPowerLinks)
{
- hasAnyLink = true;
- break;
+ ArtifactPowerEntry const* artifactPowerLink = sArtifactPowerStore.LookupEntry(artifactPowerLinkId);
+ if (!artifactPowerLink)
+ continue;
+
+ ItemDynamicFieldArtifactPowers const* artifactPowerLinkLearned = artifact->GetArtifactPower(artifactPowerLinkId);
+ if (!artifactPowerLinkLearned)
+ continue;
+
+ if (artifactPowerLinkLearned->PurchasedRank >= artifactPowerLink->MaxPurchasableRank)
+ {
+ hasAnyLink = true;
+ break;
+ }
}
- }
- if (!hasAnyLink)
- return;
+ if (!hasAnyLink)
+ return;
+ }
}
ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower->ArtifactPowerId, artifactPower->CurrentRankWithBonus + 1 - 1); // need data for next rank, but -1 because of how db2 data is structured
@@ -115,6 +132,31 @@ void WorldSession::HandleArtifactAddPower(WorldPackets::Artifact::ArtifactAddPow
artifact->SetUInt64Value(ITEM_FIELD_ARTIFACT_XP, artifact->GetUInt64Value(ITEM_FIELD_ARTIFACT_XP) - xpCost);
artifact->SetState(ITEM_CHANGED, _player);
+
+ uint32 totalPurchasedArtifactPower = artifact->GetTotalPurchasedArtifactPowers();
+ uint32 artifactTier = 0;
+
+ for (ArtifactTierEntry const* tier : sArtifactTierStore)
+ {
+ if (artifactPowerEntry->Flags & ARTIFACT_POWER_FLAG_FINAL && artifactPowerEntry->Tier < MAX_ARTIFACT_TIER)
+ {
+ artifactTier = artifactPowerEntry->Tier + 1;
+ break;
+ }
+
+ if (totalPurchasedArtifactPower < tier->MaxNumTraits)
+ {
+ artifactTier = tier->ArtifactTier;
+ break;
+ }
+ }
+
+ artifactTier = std::max(artifactTier, currentArtifactTier);
+
+ for (uint32 i = currentArtifactTier; i <= artifactTier; ++i)
+ artifact->InitArtifactPowers(artifact->GetTemplate()->GetArtifactID(), uint8(i));
+
+ artifact->SetModifier(ITEM_MODIFIER_ARTIFACT_TIER, artifactTier);
}
void WorldSession::HandleArtifactSetAppearance(WorldPackets::Artifact::ArtifactSetAppearance& artifactSetAppearance)
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index a428843d6be..3ba93420747 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -20,6 +20,7 @@
#include "AccountMgr.h"
#include "ArenaTeam.h"
#include "ArenaTeamMgr.h"
+#include "ArtifactPackets.h"
#include "AuthenticationPackets.h"
#include "Battleground.h"
#include "BattlegroundPackets.h"
@@ -971,6 +972,16 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
WorldPackets::BattlePet::BattlePetJournalLockAcquired lock;
SendPacket(lock.Write());
+ WorldPackets::Artifact::ArtifactKnowledge artifactKnowledge;
+ artifactKnowledge.ArtifactCategoryID = ARTIFACT_CATEGORY_PRIMARY;
+ artifactKnowledge.KnowledgeLevel = sWorld->getIntConfig(CONFIG_CURRENCY_START_ARTIFACT_KNOWLEDGE);
+ SendPacket(artifactKnowledge.Write());
+
+ WorldPackets::Artifact::ArtifactKnowledge artifactKnowledgeFishingPole;
+ artifactKnowledgeFishingPole.ArtifactCategoryID = ARTIFACT_CATEGORY_FISHING;
+ artifactKnowledgeFishingPole.KnowledgeLevel = 0;
+ SendPacket(artifactKnowledgeFishingPole.Write());
+
pCurrChar->SendInitialPacketsBeforeAddToMap();
//Show cinematic at the first time that player login
diff --git a/src/server/game/Server/Packets/ArtifactPackets.cpp b/src/server/game/Server/Packets/ArtifactPackets.cpp
index 2612b384f8c..8666b709cf0 100644
--- a/src/server/game/Server/Packets/ArtifactPackets.cpp
+++ b/src/server/game/Server/Packets/ArtifactPackets.cpp
@@ -69,3 +69,11 @@ WorldPacket const* WorldPackets::Artifact::ArtifactXpGain::Write()
return &_worldPacket;
}
+
+WorldPacket const* WorldPackets::Artifact::ArtifactKnowledge::Write()
+{
+ _worldPacket << int32(ArtifactCategoryID);
+ _worldPacket << int8(KnowledgeLevel);
+
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/ArtifactPackets.h b/src/server/game/Server/Packets/ArtifactPackets.h
index f208a906413..25934b75c28 100644
--- a/src/server/game/Server/Packets/ArtifactPackets.h
+++ b/src/server/game/Server/Packets/ArtifactPackets.h
@@ -99,6 +99,17 @@ namespace WorldPackets
ObjectGuid ArtifactGUID;
uint64 Amount = 0;
};
+
+ class ArtifactKnowledge final : public ServerPacket
+ {
+ public:
+ ArtifactKnowledge() : ServerPacket(SMSG_ARTIFACT_KNOWLEDGE, 1 + 4) { }
+
+ WorldPacket const* Write() override;
+
+ int32 ArtifactCategoryID = 0;
+ int8 KnowledgeLevel = 0;
+ };
}
}
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index aabd733d554..77690ba7354 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -894,7 +894,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_PREP_OPPONENT_SPECIALIZATIONS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_FORGE_OPENED, STATUS_NEVER, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_KNOWLEDGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_KNOWLEDGE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_RESPEC_CONFIRM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_TRAITS_REFUNDED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_XP_GAIN, STATUS_NEVER, CONNECTION_TYPE_REALM);
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index f90fc39c36d..23a62783c83 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -956,6 +956,13 @@ void World::LoadConfigSettings(bool reload)
}
m_int_configs[CONFIG_CURRENCY_MAX_JUSTICE_POINTS] *= 100; //precision mod
+ m_int_configs[CONFIG_CURRENCY_START_ARTIFACT_KNOWLEDGE] = sConfigMgr->GetIntDefault("Currency.StartArtifactKnowledge", 55);
+ if (int32(m_int_configs[CONFIG_CURRENCY_START_ARTIFACT_KNOWLEDGE]) < 0)
+ {
+ TC_LOG_ERROR("server.loading", "Currency.StartArtifactKnowledge (%i) must be >= 0, set to default 0.", m_int_configs[CONFIG_CURRENCY_START_ARTIFACT_KNOWLEDGE]);
+ m_int_configs[CONFIG_CURRENCY_START_ARTIFACT_KNOWLEDGE] = 0;
+ }
+
m_int_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL] = sConfigMgr->GetIntDefault("RecruitAFriend.MaxLevel", 85);
if (m_int_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL] > m_int_configs[CONFIG_MAX_PLAYER_LEVEL])
{
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 7b0ad97cd8c..16850da37ae 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -253,6 +253,7 @@ enum WorldIntConfigs
CONFIG_CURRENCY_START_APEXIS_CRYSTALS,
CONFIG_CURRENCY_MAX_APEXIS_CRYSTALS,
CONFIG_CURRENCY_START_JUSTICE_POINTS,
+ CONFIG_CURRENCY_START_ARTIFACT_KNOWLEDGE,
CONFIG_CURRENCY_MAX_JUSTICE_POINTS,
CONFIG_CURRENCY_RESET_HOUR,
CONFIG_CURRENCY_RESET_DAY,
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 1a514e87d05..6f187fca25d 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -3947,6 +3947,14 @@ Currency.StartJusticePoints = 0
Currency.MaxJusticePoints = 4000
#
+# Currency.StartArtifactKnowledge
+# Amount artifact knowledge that new players will start with
+# Default: 55 (max)
+#
+
+Currency.StartArtifactKnowledge = 55
+
+#
###################################################################################################
###################################################################################################