aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp3
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.h2
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp194
-rw-r--r--src/server/game/DataStores/DB2Stores.h6
-rw-r--r--src/server/game/DataStores/DB2Structure.h7
-rw-r--r--src/server/game/Entities/Item/Item.cpp20
-rw-r--r--src/server/game/Entities/Item/Item.h2
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.h7
8 files changed, 196 insertions, 45 deletions
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp
index 71a874d7198..65d1b825570 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.cpp
+++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp
@@ -183,6 +183,9 @@ void HotfixDatabaseConnection::DoPrepareStatements()
"CategoryID, SpellCategory, Quality, SpellWeight FROM currency_types ORDER BY ID DESC", CONNECTION_SYNCH);
PREPARE_LOCALE_STMT(HOTFIX_SEL_CURRENCY_TYPES, "SELECT ID, Name_lang, Description_lang FROM currency_types_locale WHERE locale = ?", CONNECTION_SYNCH);
+ // Curve.db2
+ PrepareStatement(HOTFIX_SEL_CURVE, "SELECT ID, Type, Unused FROM curve ORDER BY ID DESC", CONNECTION_SYNCH);
+
// CurvePoint.db2
PrepareStatement(HOTFIX_SEL_CURVE_POINT, "SELECT ID, X, Y, CurveID, `Index` FROM curve_point ORDER BY ID DESC", CONNECTION_SYNCH);
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h
index 66d9d65cb07..1b6fef8b5d0 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.h
+++ b/src/server/database/Database/Implementation/HotfixDatabase.h
@@ -114,6 +114,8 @@ enum HotfixDatabaseStatements
HOTFIX_SEL_CURRENCY_TYPES,
HOTFIX_SEL_CURRENCY_TYPES_LOCALE,
+ HOTFIX_SEL_CURVE,
+
HOTFIX_SEL_CURVE_POINT,
HOTFIX_SEL_DESTRUCTIBLE_MODEL_DATA,
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index f86cc7da260..be7e67b49a4 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -57,6 +57,7 @@ DB2Storage<CreatureTypeEntry> sCreatureTypeStore("CreatureType
DB2Storage<CriteriaEntry> sCriteriaStore("Criteria.db2", CriteriaMeta::Instance(), HOTFIX_SEL_CRITERIA);
DB2Storage<CriteriaTreeEntry> sCriteriaTreeStore("CriteriaTree.db2", CriteriaTreeMeta::Instance(), HOTFIX_SEL_CRITERIA_TREE);
DB2Storage<CurrencyTypesEntry> sCurrencyTypesStore("CurrencyTypes.db2", CurrencyTypesMeta::Instance(), HOTFIX_SEL_CURRENCY_TYPES);
+DB2Storage<CurveEntry> sCurveStore("Curve.db2", CurveMeta::Instance(), HOTFIX_SEL_CURVE);
DB2Storage<CurvePointEntry> sCurvePointStore("CurvePoint.db2", CurvePointMeta::Instance(), HOTFIX_SEL_CURVE_POINT);
DB2Storage<DestructibleModelDataEntry> sDestructibleModelDataStore("DestructibleModelData.db2", DestructibleModelDataMeta::Instance(), HOTFIX_SEL_DESTRUCTIBLE_MODEL_DATA);
DB2Storage<DifficultyEntry> sDifficultyStore("Difficulty.db2", DifficultyMeta::Instance(), HOTFIX_SEL_DIFFICULTY);
@@ -319,6 +320,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sCriteriaStore);
LOAD_DB2(sCriteriaTreeStore);
LOAD_DB2(sCurrencyTypesStore);
+ LOAD_DB2(sCurveStore);
LOAD_DB2(sCurvePointStore);
LOAD_DB2(sDestructibleModelDataStore);
LOAD_DB2(sDifficultyStore);
@@ -565,6 +567,13 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
_chrSpecializationsByIndex[storageIndex][chrSpec->OrderIndex] = chrSpec;
}
+ for (CurvePointEntry const* curvePoint : sCurvePointStore)
+ if (sCurveStore.LookupEntry(curvePoint->CurveID))
+ _curvePoints[curvePoint->CurveID].push_back(curvePoint);
+
+ for (auto itr = _curvePoints.begin(); itr != _curvePoints.end(); ++itr)
+ std::sort(itr->second.begin(), itr->second.end(), [](CurvePointEntry const* point1, CurvePointEntry const* point2) { return point1->Index < point2->Index; });
+
ASSERT(MAX_DIFFICULTY >= sDifficultyStore.GetNumRows(),
"MAX_DIFFICULTY is not large enough to contain all difficulties! (current value %d, required %d)",
MAX_DIFFICULTY, sDifficultyStore.GetNumRows());
@@ -626,16 +635,6 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
for (ItemXBonusTreeEntry const* itemBonusTreeAssignment : sItemXBonusTreeStore)
_itemToBonusTree.insert({ itemBonusTreeAssignment->ItemID, itemBonusTreeAssignment->BonusTreeID });
- {
- std::set<uint32> scalingCurves;
- for (ScalingStatDistributionEntry const* ssd : sScalingStatDistributionStore)
- scalingCurves.insert(ssd->ItemLevelCurveID);
-
- for (CurvePointEntry const* curvePoint : sCurvePointStore)
- if (scalingCurves.count(curvePoint->CurveID))
- _heirloomCurvePoints[curvePoint->CurveID][curvePoint->Index] = curvePoint;
- }
-
for (MapDifficultyEntry const* entry : sMapDifficultyStore)
_mapDifficulties[entry->MapID][entry->DifficultyID] = entry;
_mapDifficulties[0][0] = _mapDifficulties[1][0]; // map 0 is missing from MapDifficulty.dbc so we cheat a bit
@@ -997,6 +996,162 @@ char const* DB2Manager::GetCreatureFamilyPetName(uint32 petfamily, uint32 locale
return petFamily->Name->Str[locale][0] != '\0' ? petFamily->Name->Str[locale] : nullptr;
}
+enum class CurveInterpolationMode : uint8
+{
+ Linear = 0,
+ Cosine = 1,
+ CatmullRom = 2,
+ Bezier3 = 3,
+ Bezier4 = 4,
+ Bezier = 5,
+ Constant = 6,
+};
+
+static CurveInterpolationMode DetermineCurveType(CurveEntry const* curve, std::vector<CurvePointEntry const*> const& points)
+{
+ switch (curve->Type)
+ {
+ case 1:
+ return points.size() < 4 ? CurveInterpolationMode::Cosine : CurveInterpolationMode::CatmullRom;
+ case 2:
+ {
+ switch (points.size())
+ {
+ case 1:
+ return CurveInterpolationMode::Constant;
+ case 2:
+ return CurveInterpolationMode::Linear;
+ case 3:
+ return CurveInterpolationMode::Bezier3;
+ case 4:
+ return CurveInterpolationMode::Bezier4;
+ default:
+ break;
+ }
+ return CurveInterpolationMode::Bezier;
+ }
+ case 3:
+ return CurveInterpolationMode::Cosine;
+ default:
+ break;
+ }
+
+ return points.size() != 1 ? CurveInterpolationMode::Linear : CurveInterpolationMode::Constant;
+}
+
+float DB2Manager::GetCurveValueAt(uint32 curveId, float x) const
+{
+ auto itr = _curvePoints.find(curveId);
+ if (itr == _curvePoints.end())
+ return 0.0f;
+
+ CurveEntry const* curve = sCurveStore.AssertEntry(curveId);
+ std::vector<CurvePointEntry const*> const& points = itr->second;
+ if (points.empty())
+ return 0.0f;
+
+ switch (DetermineCurveType(curve, points))
+ {
+ case CurveInterpolationMode::Linear:
+ {
+ std::size_t pointIndex = 0;
+ while (pointIndex < points.size() && points[pointIndex]->X <= x)
+ ++pointIndex;
+ if (!pointIndex)
+ return points[0]->Y;
+ if (pointIndex >= points.size())
+ return points.back()->Y;
+ float xDiff = points[pointIndex]->X - points[pointIndex - 1]->X;
+ if (xDiff == 0.0)
+ return points[pointIndex]->Y;
+ return (((x - points[pointIndex - 1]->X) / xDiff) * (points[pointIndex]->Y - points[pointIndex - 1]->Y)) + points[pointIndex - 1]->Y;
+ }
+ case CurveInterpolationMode::Cosine:
+ {
+ std::size_t pointIndex = 0;
+ while (pointIndex < points.size() && points[pointIndex]->X <= x)
+ ++pointIndex;
+ if (!pointIndex)
+ return points[0]->Y;
+ if (pointIndex >= points.size())
+ return points.back()->Y;
+ float xDiff = points[pointIndex]->X - points[pointIndex - 1]->X;
+ if (xDiff == 0.0)
+ return points[pointIndex]->Y;
+ return ((points[pointIndex]->Y - points[pointIndex - 1]->Y) * (1.0f - std::cos((x - points[pointIndex - 1]->X) / xDiff * float(M_PI))) * 0.5f) + points[pointIndex - 1]->Y;
+ }
+ case CurveInterpolationMode::CatmullRom:
+ {
+ std::size_t pointIndex = 1;
+ while (pointIndex < points.size() && points[pointIndex]->X <= x)
+ ++pointIndex;
+ if (pointIndex == 1)
+ return points[1]->Y;
+ if (pointIndex >= points.size() - 1)
+ return points[points.size() - 2]->Y;
+ float xDiff = points[pointIndex]->X - points[pointIndex - 1]->X;
+ if (xDiff == 0.0)
+ return points[pointIndex]->Y;
+
+ float mu = (x - points[pointIndex - 1]->X) / xDiff;
+ float a0 = -0.5f * points[pointIndex - 2]->Y + 1.5f * points[pointIndex - 1]->Y - 1.5f * points[pointIndex]->Y + 0.5f * points[pointIndex + 1]->Y;
+ float a1 = points[pointIndex - 2]->Y - 2.5f * points[pointIndex - 1]->Y + 2.0f * points[pointIndex]->Y - 0.5f * points[pointIndex + 1]->Y;
+ float a2 = -0.5f * points[pointIndex - 2]->Y + 0.5f * points[pointIndex]->Y;
+ float a3 = points[pointIndex - 1]->Y;
+
+ return a0 * mu * mu * mu + a1 * mu * mu + a2 * mu + a3;
+ }
+ case CurveInterpolationMode::Bezier3:
+ {
+ float xDiff = points[2]->X - points[0]->X;
+ if (xDiff == 0.0)
+ return points[1]->Y;
+ float mu = (x - points[0]->X) / xDiff;
+ return ((1.0f - mu) * (1.0f - mu) * points[0]->Y) + (1.0f - mu) * 2.0f * mu * points[1]->Y + mu * mu * points[2]->Y;
+ }
+ case CurveInterpolationMode::Bezier4:
+ {
+ float xDiff = points[3]->X - points[0]->X;
+ if (xDiff == 0.0)
+ return points[1]->Y;
+ float mu = (x - points[0]->X) / xDiff;
+ return (1.0f - mu) * (1.0f - mu) * (1.0f - mu) * points[0]->Y
+ + 3.0f * mu * (1.0f - mu) * (1.0f - mu) * points[1]->Y
+ + 3.0f * mu * mu * (1.0f - mu) * points[2]->Y
+ + mu * mu * mu * points[3]->Y;
+ }
+ case CurveInterpolationMode::Bezier:
+ {
+ float xDiff = points.back()->X - points[0]->X;
+ if (xDiff == 0.0f)
+ return points.back()->Y;
+
+ std::vector<float> tmp(points.size());
+ for (std::size_t i = 0; i < points.size(); ++i)
+ tmp[i] = points[i]->Y;
+
+ float mu = (x - points[0]->X) / xDiff;
+ int32 i = int32(points.size()) - 1;
+ while (i > 0)
+ {
+ for (int32 k = 0; k < i; ++k)
+ {
+ float val = tmp[k] + mu * (tmp[k + 1] - tmp[k]);
+ tmp[k] = val;
+ }
+ --i;
+ }
+ return tmp[0];
+ }
+ case CurveInterpolationMode::Constant:
+ return points[0]->Y;
+ default:
+ break;
+ }
+
+ return 0.0f;
+}
+
EmotesTextSoundEntry const* DB2Manager::GetTextSoundEmoteFor(uint32 emote, uint8 race, uint8 gender, uint8 class_) const
{
auto itr = _emoteTextSounds.find(EmotesTextSoundContainer::key_type(emote, race, gender, class_));
@@ -1019,25 +1174,6 @@ std::vector<uint32> const* DB2Manager::GetFactionTeamList(uint32 faction) const
return nullptr;
}
-uint32 DB2Manager::GetHeirloomItemLevel(uint32 curveId, uint32 level) const
-{
- // Assuming linear item level scaling for heirlooms
- auto itr = _heirloomCurvePoints.find(curveId);
- if (itr == _heirloomCurvePoints.end())
- return 0;
-
- auto it2 = itr->second.begin(); // Highest scaling point
- if (level >= it2->second->X)
- return it2->second->Y;
-
- auto previousItr = it2++;
- for (; it2 != itr->second.end(); ++it2, ++previousItr)
- if (level >= it2->second->X)
- return uint32((previousItr->second->Y - it2->second->Y) / (previousItr->second->X - it2->second->X) * (float(level) - it2->second->X) + it2->second->Y);
-
- return uint32(previousItr->second->Y); // Lowest scaling point
-}
-
HeirloomEntry const* DB2Manager::GetHeirloomByItemId(uint32 itemId) const
{
auto itr = _heirlooms.find(itemId);
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index 35550f9ce0d..c5715a54fc0 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -224,9 +224,9 @@ public:
typedef std::unordered_multimap<uint32, CharSectionsEntry const*> CharSectionsContainer;
typedef std::unordered_map<uint32, CharStartOutfitEntry const*> CharStartOutfitContainer;
typedef ChrSpecializationEntry const* ChrSpecializationByIndexContainer[MAX_CLASSES + 1][MAX_SPECIALIZATIONS];
+ typedef std::unordered_map<uint32 /*curveID*/, std::vector<CurvePointEntry const*>> CurvePointsContainer;
typedef std::map<std::tuple<uint32, uint8, uint8, uint8>, EmotesTextSoundEntry const*> EmotesTextSoundContainer;
typedef std::unordered_map<uint32, std::vector<uint32>> FactionTeamContainer;
- typedef std::map<uint32 /*curveID*/, std::map<uint32/*index*/, CurvePointEntry const*, std::greater<uint32>>> HeirloomCurvesContainer;
typedef std::unordered_map<uint32, HeirloomEntry const*> HeirloomItemsContainer;
typedef std::vector<ItemBonusEntry const*> ItemBonusList;
typedef std::unordered_map<uint32 /*bonusListId*/, ItemBonusList> ItemBonusListContainer;
@@ -274,9 +274,9 @@ public:
static char const* GetChrRaceName(uint8 race, LocaleConstant locale = DEFAULT_LOCALE);
ChrSpecializationEntry const* GetChrSpecializationByIndex(uint32 class_, uint32 index) const;
static char const* GetCreatureFamilyPetName(uint32 petfamily, uint32 locale);
+ float GetCurveValueAt(uint32 curveId, float x) const;
EmotesTextSoundEntry const* GetTextSoundEmoteFor(uint32 emote, uint8 race, uint8 gender, uint8 class_) const;
std::vector<uint32> const* GetFactionTeamList(uint32 faction) const;
- uint32 GetHeirloomItemLevel(uint32 curveId, uint32 level) const;
HeirloomEntry const* GetHeirloomByItemId(uint32 itemId) const;
ItemBonusList const* GetItemBonusList(uint32 bonusListId) const;
std::set<uint32> GetItemBonusTree(uint32 itemId, uint32 itemBonusTreeMod) const;
@@ -326,10 +326,10 @@ private:
CharStartOutfitContainer _charStartOutfits;
uint32 _powersByClass[MAX_CLASSES][MAX_POWERS];
ChrSpecializationByIndexContainer _chrSpecializationsByIndex;
+ CurvePointsContainer _curvePoints;
EmotesTextSoundContainer _emoteTextSounds;
FactionTeamContainer _factionTeams;
HeirloomItemsContainer _heirlooms;
- HeirloomCurvesContainer _heirloomCurvePoints;
ItemBonusListContainer _itemBonusLists;
ItemBonusTreeContainer _itemBonusTrees;
ItemChildEquipmentContainer _itemChildEquipment;
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index 2101661912a..32868b632c3 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -628,6 +628,13 @@ struct CurrencyTypesEntry
uint32 SpellWeight;
};
+struct CurveEntry
+{
+ uint32 ID;
+ uint8 Type;
+ uint8 Unused;
+};
+
struct CurvePointEntry
{
uint32 ID;
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index 2fb7516ffb6..ce97bca9a35 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -654,9 +654,9 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i)
{
gemData[i].ItemId = fields[29 + i * MAX_GEM_SOCKETS].GetUInt32();
- Tokenizer bonusListIDs(fields[30 + i * MAX_GEM_SOCKETS].GetString(), ' ');
+ Tokenizer gemBonusListIDs(fields[30 + i * MAX_GEM_SOCKETS].GetString(), ' ');
uint32 b = 0;
- for (char const* token : bonusListIDs)
+ for (char const* token : gemBonusListIDs)
if (uint32 bonusListID = atoul(token))
gemData[i].BonusListIDs[b++] = bonusListID;
@@ -1106,8 +1106,8 @@ bool Item::GemsFitSockets() const
uint32 gemSlot = 0;
for (ItemDynamicFieldGems const& gemData : GetGems())
{
- uint8 SocketColor = GetTemplate()->GetSocketColor(gemSlot);
- if (!SocketColor) // no socket slot
+ SocketColor color = GetTemplate()->GetSocketColor(gemSlot);
+ if (!color) // no socket slot
continue;
uint32 GemColor = 0;
@@ -1120,7 +1120,7 @@ bool Item::GemsFitSockets() const
GemColor = gemProperty->Type;
}
- if (!(GemColor & SocketColorToGemTypeMask[SocketColor])) // bad gem color on this socket
+ if (!(GemColor & SocketColorToGemTypeMask[color])) // bad gem color on this socket
return false;
}
return true;
@@ -1128,22 +1128,22 @@ bool Item::GemsFitSockets() const
uint8 Item::GetGemCountWithID(uint32 GemID) const
{
- return std::count_if(GetGems().begin(), GetGems().end(), [GemID](ItemDynamicFieldGems const& gemData)
+ return uint8(std::count_if(GetGems().begin(), GetGems().end(), [GemID](ItemDynamicFieldGems const& gemData)
{
return gemData.ItemId == GemID;
- });
+ }));
}
uint8 Item::GetGemCountWithLimitCategory(uint32 limitCategory) const
{
- return std::count_if(GetGems().begin(), GetGems().end(), [limitCategory](ItemDynamicFieldGems const& gemData)
+ return uint8(std::count_if(GetGems().begin(), GetGems().end(), [limitCategory](ItemDynamicFieldGems const& gemData)
{
ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemData.ItemId);
if (!gemProto)
return false;
return gemProto->GetItemLimitCategory() == limitCategory;
- });
+ }));
}
bool Item::IsLimitedToAnotherMapOrZone(uint32 cur_mapId, uint32 cur_zoneId) const
@@ -1972,7 +1972,7 @@ uint32 Item::GetItemLevel(Player const* owner) const
uint32 itemLevel = stats->GetBaseItemLevel();
if (ScalingStatDistributionEntry const* ssd = sScalingStatDistributionStore.LookupEntry(GetScalingStatDistribution()))
- if (uint32 heirloomIlvl = sDB2Manager.GetHeirloomItemLevel(ssd->ItemLevelCurveID, owner->getLevel()))
+ if (uint32 heirloomIlvl = uint32(sDB2Manager.GetCurveValueAt(ssd->ItemLevelCurveID, owner->getLevel())))
itemLevel = heirloomIlvl;
if (ItemUpgradeEntry const* upgrade = sItemUpgradeStore.LookupEntry(GetModifier(ITEM_MODIFIER_UPGRADE_ID)))
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index 683353a7fe3..fe86591ccc3 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -224,7 +224,7 @@ enum ItemUpdateState
ITEM_REMOVED = 3
};
-enum ItemModifier
+enum ItemModifier : uint16
{
ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS = 0,
ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_1 = 1,
diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h
index d95b361da89..bbf89d18dbf 100644
--- a/src/server/game/Entities/Item/ItemTemplate.h
+++ b/src/server/game/Entities/Item/ItemTemplate.h
@@ -691,8 +691,11 @@ const uint32 MaxItemSubclassValues[MAX_ITEM_CLASS] =
#define MAX_ITEM_SUBCLASS_TOTAL 21
-#define MIN_ITEM_LEVEL 1
-#define MAX_ITEM_LEVEL 1000
+enum ItemLevelConstants : uint32
+{
+ MIN_ITEM_LEVEL = 1,
+ MAX_ITEM_LEVEL = 1300
+};
class Player;
struct ChrSpecializationEntry;