Core/Misc: Implemented leveling/killing experience loading from gtOCTLevelExperience.dbc
* Updated the xp formula to Warlords of Draenor
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
TRUNCATE `player_xp_for_level`;
|
||||
|
||||
ALTER TABLE `player_xp_for_level`
|
||||
CHANGE `lvl` `Level` TINYINT(3) UNSIGNED NOT NULL,
|
||||
CHANGE `xp_for_next_level` `Experience` FLOAT UNSIGNED NOT NULL;
|
||||
@@ -37,7 +37,7 @@ enum LevelLimit
|
||||
// Client expected level limitation, like as used in DBC item max levels for "until max player level"
|
||||
// use as default max player level, must be fit max level for used client
|
||||
// also see MAX_LEVEL and STRONG_MAX_LEVEL define
|
||||
DEFAULT_MAX_LEVEL = 85,
|
||||
DEFAULT_MAX_LEVEL = 100,
|
||||
|
||||
// client supported max level for player/pets/etc. Avoid overflow or client stability affected.
|
||||
// also see GT_MAX_LEVEL define
|
||||
|
||||
@@ -124,6 +124,7 @@ GameTable <GtNpcTotalHpExp3Entry> sGtNpcTotalHpExp3Store(GtNpcTotalHpExp3
|
||||
GameTable <GtNpcTotalHpExp4Entry> sGtNpcTotalHpExp4Store(GtNpcTotalHpExp4fmt);
|
||||
GameTable <GtNpcTotalHpExp5Entry> sGtNpcTotalHpExp5Store(GtNpcTotalHpExp5fmt);
|
||||
GameTable <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore(GtOCTClassCombatRatingScalarfmt);
|
||||
GameTable <GtOCTLevelExperienceEntry> sGtOCTLevelExperienceStore(GtOCTLevelExperiencefmt);
|
||||
GameTable <GtOCTRegenHPEntry> sGtOCTRegenHPStore(GtOCTRegenHPfmt);
|
||||
GameTable <gtOCTHpPerStaminaEntry> sGtOCTHpPerStaminaStore(GtOCTHpPerStaminafmt);
|
||||
GameTable <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptfmt);
|
||||
@@ -746,6 +747,7 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
LoadGameTable(bad_dbc_files, "NpcTotalHpExp5", sGtNpcTotalHpExp5Store, dbcPath, "gtNpcTotalHpExp5.dbc"); // 19445
|
||||
LoadGameTable(bad_dbc_files, "OCTClassCombatRatingScalar", sGtOCTClassCombatRatingScalarStore, dbcPath, "gtOCTClassCombatRatingScalar.dbc");//19342
|
||||
LoadGameTable(bad_dbc_files, "OCTHPPerStamina", sGtOCTHpPerStaminaStore, dbcPath, "gtOCTHpPerStamina.dbc");//19342
|
||||
LoadGameTable(bad_dbc_files, "OCTLevelExperience", sGtOCTLevelExperienceStore, dbcPath, "gtOCTLevelExperience.dbc"); // 19342
|
||||
LoadGameTable(bad_dbc_files, "RegenMPPerSpt", sGtRegenMPPerSptStore, dbcPath, "gtRegenMPPerSpt.dbc");//19342
|
||||
LoadGameTable(bad_dbc_files, "SpellScaling", sGtSpellScalingStore, dbcPath, "gtSpellScaling.dbc");//19342
|
||||
LoadGameTable(bad_dbc_files, "OCTBaseHPByClass", sGtOCTBaseHPByClassStore, dbcPath, "gtOCTBaseHPByClass.dbc");//19342
|
||||
@@ -897,32 +899,20 @@ uint32 GetMaxLevelForExpansion(uint32 expansion)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Used only for calculate xp gain by content lvl.
|
||||
Calculation on Gilneas and group maps of LostIslands calculated as CONTENT_1_60.
|
||||
*/
|
||||
ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId)
|
||||
uint32 GetExpansionForLevel(uint32 level)
|
||||
{
|
||||
mapid = GetVirtualMapForMapAndZone(mapid, zoneId);
|
||||
if (mapid < 2)
|
||||
return CONTENT_1_60;
|
||||
|
||||
MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
|
||||
if (!mapEntry)
|
||||
return CONTENT_1_60;
|
||||
|
||||
// no need enum all maps from phasing
|
||||
if (mapEntry->ParentMapID >= 0)
|
||||
mapid = mapEntry->ParentMapID;
|
||||
|
||||
switch (mapid)
|
||||
{
|
||||
case 648: //LostIslands
|
||||
case 654: //Gilneas
|
||||
return CONTENT_1_60;
|
||||
default:
|
||||
return ContentLevels(mapEntry->Expansion());
|
||||
}
|
||||
if (level < 60)
|
||||
return EXPANSION_CLASSIC;
|
||||
else if (level < 70)
|
||||
return EXPANSION_THE_BURNING_CRUSADE;
|
||||
else if (level < 80)
|
||||
return EXPANSION_WRATH_OF_THE_LICH_KING;
|
||||
else if (level < 85)
|
||||
return EXPANSION_CATACLYSM;
|
||||
else if (level < 90)
|
||||
return EXPANSION_MISTS_OF_PANDARIA;
|
||||
else if (level < 100)
|
||||
return EXPANSION_WARLORDS_OF_DRAENOR;
|
||||
}
|
||||
|
||||
bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId)
|
||||
|
||||
@@ -59,6 +59,7 @@ enum ContentLevels
|
||||
};
|
||||
|
||||
uint32 GetMaxLevelForExpansion(uint32 expansion);
|
||||
uint32 GetExpansionForLevel(uint32 level);
|
||||
|
||||
ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId);
|
||||
|
||||
@@ -187,6 +188,7 @@ extern GameTable <GtNpcTotalHpExp3Entry> sGtNpcTotalHpExp3Store;
|
||||
extern GameTable <GtNpcTotalHpExp4Entry> sGtNpcTotalHpExp4Store;
|
||||
extern GameTable <GtNpcTotalHpExp5Entry> sGtNpcTotalHpExp5Store;
|
||||
extern GameTable <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore;
|
||||
extern GameTable <GtOCTLevelExperienceEntry> sGtOCTLevelExperienceStore;
|
||||
extern GameTable <gtOCTHpPerStaminaEntry> sGtOCTHpPerStaminaStore;
|
||||
extern GameTable <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore;
|
||||
extern GameTable <GtSpellScalingEntry> sGtSpellScalingStore;
|
||||
|
||||
@@ -890,6 +890,11 @@ struct GtOCTClassCombatRatingScalarEntry
|
||||
float ratio;
|
||||
};
|
||||
|
||||
struct GtOCTLevelExperienceEntry
|
||||
{
|
||||
float Data;
|
||||
};
|
||||
|
||||
struct GtOCTRegenHPEntry
|
||||
{
|
||||
float ratio;
|
||||
|
||||
@@ -68,6 +68,7 @@ char const GlyphSlotfmt[] = "nix";
|
||||
char const GtBarberShopCostBasefmt[] = "xf";
|
||||
char const GtCombatRatingsfmt[] = "xf";
|
||||
char const GtOCTHpPerStaminafmt[] = "df";
|
||||
char const GtOCTLevelExperiencefmt[] = "xf";
|
||||
char const GtChanceToMeleeCritBasefmt[] = "xf";
|
||||
char const GtChanceToMeleeCritfmt[] = "xf";
|
||||
char const GtChanceToSpellCritBasefmt[] = "xf";
|
||||
|
||||
@@ -512,14 +512,10 @@ inline void KillRewarder::_RewardXP(Player* player, float rate)
|
||||
for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
|
||||
AddPct(xp, (*i)->GetAmount());
|
||||
|
||||
// 4.2.3. Calculate expansion penalty
|
||||
if (_victim->GetTypeId() == TYPEID_UNIT && player->getLevel() >= GetMaxLevelForExpansion(_victim->ToCreature()->GetCreatureTemplate()->expansion))
|
||||
xp = CalculatePct(xp, 10); // Players get only 10% xp for killing creatures of lower expansion levels than himself
|
||||
|
||||
// 4.2.4. Give XP to player.
|
||||
// 4.2.3. Give XP to player.
|
||||
player->GiveXP(xp, _victim, _groupRate);
|
||||
if (Pet* pet = player->GetPet())
|
||||
// 4.2.5. If player has pet, reward pet with XP (100% for single player, 50% for group case).
|
||||
// 4.2.4. If player has pet, reward pet with XP (100% for single player, 50% for group case).
|
||||
pet->GivePetXP(_group ? xp / 2 : xp);
|
||||
}
|
||||
}
|
||||
@@ -6630,7 +6626,7 @@ int32 Player::CalculateReputationGain(ReputationSource source, uint32 creatureOr
|
||||
break;
|
||||
}
|
||||
|
||||
if (rate != 1.0f && creatureOrQuestLevel <= Trinity::XP::GetGrayLevel(getLevel()))
|
||||
if (rate != 1.0f && creatureOrQuestLevel < Trinity::XP::GetGrayLevel(getLevel()))
|
||||
percent *= rate;
|
||||
|
||||
if (percent <= 0.0f)
|
||||
@@ -24032,7 +24028,7 @@ bool Player::isHonorOrXPTarget(Unit const* victim) const
|
||||
uint8 k_grey = Trinity::XP::GetGrayLevel(getLevel());
|
||||
|
||||
// Victim level less gray level
|
||||
if (v_level <= k_grey)
|
||||
if (v_level < k_grey)
|
||||
return false;
|
||||
|
||||
if (Creature const* const creature = victim->ToCreature())
|
||||
|
||||
@@ -3293,52 +3293,57 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
for (uint8 level = 0; level < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
|
||||
_playerXPperLevel[level] = 0;
|
||||
|
||||
// 0 1
|
||||
QueryResult result = WorldDatabase.Query("SELECT lvl, xp_for_next_level FROM player_xp_for_level");
|
||||
// 0 1
|
||||
QueryResult result = WorldDatabase.Query("SELECT Level, Experience FROM player_xp_for_level");
|
||||
|
||||
if (!result)
|
||||
// load the DBC's levels at first...
|
||||
GtOCTLevelExperienceEntry const* exp;
|
||||
for (int level = 0; level < MAX_LEVEL; ++level)
|
||||
{
|
||||
TC_LOG_ERROR("server.loading", ">> Loaded 0 xp for level definitions. DB table `player_xp_for_level` is empty.");
|
||||
exit(1);
|
||||
exp = sGtOCTLevelExperienceStore.EvaluateTable(level, 0);
|
||||
_playerXPperLevel[level + 1] = exp->Data;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
// ...overwrite if needed (custom values)
|
||||
if (result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 current_level = fields[0].GetUInt8();
|
||||
uint32 current_xp = fields[1].GetUInt32();
|
||||
|
||||
if (current_level >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
do
|
||||
{
|
||||
if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
|
||||
TC_LOG_ERROR("sql.sql", "Wrong (> %u) level %u in `player_xp_for_level` table, ignoring.", STRONG_MAX_LEVEL, current_level);
|
||||
else
|
||||
{
|
||||
TC_LOG_INFO("misc", "Unused (> MaxPlayerLevel in worldserver.conf) level %u in `player_xp_for_levels` table, ignoring.", current_level);
|
||||
++count; // make result loading percent "expected" correct in case disabled detail mode for example.
|
||||
}
|
||||
continue;
|
||||
}
|
||||
//PlayerXPperLevel
|
||||
_playerXPperLevel[current_level] = current_xp;
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
// fill level gaps
|
||||
uint32 current_level = fields[0].GetUInt16();
|
||||
uint32 current_xp = uint32(fields[1].GetFloat());
|
||||
|
||||
if (current_level >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
|
||||
TC_LOG_ERROR("sql.sql", "Wrong (> %u) level %u in `player_xp_for_level` table, ignoring.", STRONG_MAX_LEVEL, current_level);
|
||||
else
|
||||
{
|
||||
TC_LOG_INFO("misc", "Unused (> MaxPlayerLevel in worldserver.conf) level %u in `player_xp_for_level` table, ignoring.", current_level);
|
||||
++count; // make result loading percent "expected" correct in case disabled detail mode for example.
|
||||
}
|
||||
continue;
|
||||
}
|
||||
//PlayerXPperLevel
|
||||
_playerXPperLevel[current_level] = current_xp;
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
// fill level gaps - only accounting levels > MAX_LEVEL
|
||||
for (uint8 level = 1; level < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
|
||||
{
|
||||
if (_playerXPperLevel[level] == 0)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Level %i does not have XP for level data. Using data of level [%i] + 100.", level + 1, level);
|
||||
_playerXPperLevel[level] = _playerXPperLevel[level - 1] + 100;
|
||||
TC_LOG_ERROR("sql.sql", "Level %i does not have XP for level data. Using data of level [%i] + 12000.", level + 1, level);
|
||||
_playerXPperLevel[level] = _playerXPperLevel[level - 1] + 12000;
|
||||
}
|
||||
}
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u xp for level definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u xp for level definition(s) from database in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8368,7 +8373,7 @@ CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint8 level, uint8 unit
|
||||
void ObjectMgr::LoadCreatureClassLevelStats()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 16
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11
|
||||
QueryResult result = WorldDatabase.Query("SELECT level, class, basemana, basearmor, attackpower, rangedattackpower, damage_base, damage_exp1, damage_exp2, damage_exp3, damage_exp4, damage_exp5 FROM creature_classlevelstats");
|
||||
|
||||
if (!result)
|
||||
|
||||
@@ -47,14 +47,18 @@ namespace Trinity
|
||||
{
|
||||
uint8 level;
|
||||
|
||||
if (pl_level <= 5)
|
||||
if (pl_level < 7)
|
||||
level = 0;
|
||||
else if (pl_level <= 39)
|
||||
level = pl_level - 5 - pl_level / 10;
|
||||
else if (pl_level <= 59)
|
||||
level = pl_level - 1 - pl_level / 5;
|
||||
else if (pl_level < 35)
|
||||
{
|
||||
uint8 count = 0;
|
||||
for (int i = 15; i <= pl_level; ++i)
|
||||
if (i % 5 == 0) ++count;
|
||||
|
||||
level = (pl_level - 7) - (count - 1);
|
||||
}
|
||||
else
|
||||
level = pl_level - 9;
|
||||
level = pl_level - 10;
|
||||
|
||||
sScriptMgr->OnGrayLevelCalculation(level, pl_level);
|
||||
return level;
|
||||
@@ -83,7 +87,7 @@ namespace Trinity
|
||||
{
|
||||
uint8 diff;
|
||||
|
||||
if (pl_level < 8)
|
||||
if (pl_level < 4)
|
||||
diff = 5;
|
||||
else if (pl_level < 10)
|
||||
diff = 6;
|
||||
@@ -112,30 +116,15 @@ namespace Trinity
|
||||
return diff;
|
||||
}
|
||||
|
||||
inline uint32 BaseGain(uint8 pl_level, uint8 mob_level, ContentLevels content)
|
||||
inline uint32 BaseGain(uint8 pl_level, uint8 mob_level)
|
||||
{
|
||||
uint32 baseGain;
|
||||
uint32 nBaseExp;
|
||||
|
||||
switch (content)
|
||||
{
|
||||
case CONTENT_1_60:
|
||||
nBaseExp = 45;
|
||||
break;
|
||||
case CONTENT_61_70:
|
||||
nBaseExp = 235;
|
||||
break;
|
||||
case CONTENT_71_80:
|
||||
nBaseExp = 580;
|
||||
break;
|
||||
case CONTENT_81_85:
|
||||
nBaseExp = 1878;
|
||||
break;
|
||||
default:
|
||||
TC_LOG_ERROR("misc", "BaseGain: Unsupported content level %u", content);
|
||||
nBaseExp = 45;
|
||||
break;
|
||||
}
|
||||
GtOCTLevelExperienceEntry const* BaseExpPlayer = sGtOCTLevelExperienceStore.EvaluateTable(pl_level - 1, 1);
|
||||
GtOCTLevelExperienceEntry const* BaseExpMob = sGtOCTLevelExperienceStore.EvaluateTable(mob_level - 1, 1);
|
||||
|
||||
GtOCTLevelExperienceEntry const* CoefPlayer = sGtOCTLevelExperienceStore.EvaluateTable(pl_level - 1, 4);
|
||||
GtOCTLevelExperienceEntry const* CoefMob = sGtOCTLevelExperienceStore.EvaluateTable(mob_level - 1, 4);
|
||||
|
||||
if (mob_level >= pl_level)
|
||||
{
|
||||
@@ -143,7 +132,7 @@ namespace Trinity
|
||||
if (nLevelDiff > 4)
|
||||
nLevelDiff = 4;
|
||||
|
||||
baseGain = ((pl_level * 5 + nBaseExp) * (20 + nLevelDiff) / 10 + 1) / 2;
|
||||
baseGain = BaseExpPlayer->Data * (1 + 0.05 * nLevelDiff);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -151,13 +140,13 @@ namespace Trinity
|
||||
if (mob_level > gray_level)
|
||||
{
|
||||
uint8 ZD = GetZeroDifference(pl_level);
|
||||
baseGain = (pl_level * 5 + nBaseExp) * (ZD + mob_level - pl_level) / ZD;
|
||||
baseGain = round(BaseExpMob->Data * ((1 - ((pl_level - mob_level) / float(ZD))) * (CoefMob->Data / CoefPlayer->Data)));
|
||||
}
|
||||
else
|
||||
baseGain = 0;
|
||||
}
|
||||
|
||||
sScriptMgr->OnBaseGainCalculation(baseGain, pl_level, mob_level, content);
|
||||
sScriptMgr->OnBaseGainCalculation(baseGain, pl_level, mob_level);
|
||||
return baseGain;
|
||||
}
|
||||
|
||||
@@ -171,10 +160,14 @@ namespace Trinity
|
||||
{
|
||||
float xpMod = 1.0f;
|
||||
|
||||
gain = BaseGain(player->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(u->GetMapId(), u->GetZoneId()));
|
||||
gain = BaseGain(player->getLevel(), u->getLevel());
|
||||
|
||||
if (gain && creature)
|
||||
{
|
||||
// Players get only 10% xp for killing creatures of lower expansion levels than himself
|
||||
if ((creature->GetCreatureTemplate()->expansion < GetExpansionForLevel(player->getLevel())))
|
||||
gain = uint32(round(gain / 10.0f));
|
||||
|
||||
if (creature->isElite())
|
||||
{
|
||||
// Elites in instances have a 2.75x XP bonus instead of the regular 2x world bonus.
|
||||
|
||||
@@ -519,9 +519,9 @@ void ScriptMgr::OnZeroDifferenceCalculation(uint8& diff, uint8 playerLevel)
|
||||
FOREACH_SCRIPT(FormulaScript)->OnZeroDifferenceCalculation(diff, playerLevel);
|
||||
}
|
||||
|
||||
void ScriptMgr::OnBaseGainCalculation(uint32& gain, uint8 playerLevel, uint8 mobLevel, ContentLevels content)
|
||||
void ScriptMgr::OnBaseGainCalculation(uint32& gain, uint8 playerLevel, uint8 mobLevel)
|
||||
{
|
||||
FOREACH_SCRIPT(FormulaScript)->OnBaseGainCalculation(gain, playerLevel, mobLevel, content);
|
||||
FOREACH_SCRIPT(FormulaScript)->OnBaseGainCalculation(gain, playerLevel, mobLevel);
|
||||
}
|
||||
|
||||
void ScriptMgr::OnGainCalculation(uint32& gain, Player* player, Unit* unit)
|
||||
|
||||
@@ -294,7 +294,7 @@ class FormulaScript : public ScriptObject
|
||||
virtual void OnZeroDifferenceCalculation(uint8& /*diff*/, uint8 /*playerLevel*/) { }
|
||||
|
||||
// Called after calculating base experience gain.
|
||||
virtual void OnBaseGainCalculation(uint32& /*gain*/, uint8 /*playerLevel*/, uint8 /*mobLevel*/, ContentLevels /*content*/) { }
|
||||
virtual void OnBaseGainCalculation(uint32& /*gain*/, uint8 /*playerLevel*/, uint8 /*mobLevel*/) { }
|
||||
|
||||
// Called after calculating experience gain.
|
||||
virtual void OnGainCalculation(uint32& /*gain*/, Player* /*player*/, Unit* /*unit*/) { }
|
||||
@@ -944,7 +944,7 @@ class ScriptMgr
|
||||
void OnGrayLevelCalculation(uint8& grayLevel, uint8 playerLevel);
|
||||
void OnColorCodeCalculation(XPColorChar& color, uint8 playerLevel, uint8 mobLevel);
|
||||
void OnZeroDifferenceCalculation(uint8& diff, uint8 playerLevel);
|
||||
void OnBaseGainCalculation(uint32& gain, uint8 playerLevel, uint8 mobLevel, ContentLevels content);
|
||||
void OnBaseGainCalculation(uint32& gain, uint8 playerLevel, uint8 mobLevel);
|
||||
void OnGainCalculation(uint32& gain, Player* player, Unit* unit);
|
||||
void OnGroupRateCalculation(float& rate, uint32 count, bool isRaid);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user