Core/DataStores: Implemented all curve types from Curve.db2

This commit is contained in:
Shauren
2016-08-10 00:05:56 +02:00
parent 51657e44d1
commit bd3541d106
9 changed files with 207 additions and 45 deletions

View File

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

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);

View File

@@ -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;

View File

@@ -628,6 +628,13 @@ struct CurrencyTypesEntry
uint32 SpellWeight;
};
struct CurveEntry
{
uint32 ID;
uint8 Type;
uint8 Unused;
};
struct CurvePointEntry
{
uint32 ID;

View File

@@ -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)))

View File

@@ -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,

View File

@@ -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;