[0023] Use DBC data to set the correct amount of hp and mana based on player level and class. Patch by Subv

Signed-off-by: Salja <salja2012@hotmail.de>
This commit is contained in:
Salja 2012-08-08 15:47:10 +02:00 committed by Antz
parent 6092ba754f
commit 0d7006dd23
12 changed files with 48 additions and 142 deletions

View file

@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
`cache_id` int(10) default '0',
`required_0001_xxxxx_01_mangos` bit(1) default NULL
`required_0023_xxxxx_01_mangos_player_classlevelstats` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
--

View file

@ -0,0 +1,3 @@
ALTER TABLE db_version CHANGE COLUMN required_0001_xxxxx_01_mangos required_0023_xxxxx_01_mangos_player_classlevelstats bit;
DROP TABLE IF EXISTS `player_classlevelstats`;

View file

@ -106,6 +106,8 @@ DBCStorage <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStor
//DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore(GtOCTRegenMPfmt); -- not used currently
//DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore(GtRegenHPPerSptfmt);
DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptfmt);
DBCStorage <GtOCTBaseHPByClassEntry> sGtOCTBaseHPByClassStore(GtOCTBaseHPByClassfmt);
DBCStorage <GtOCTBaseMPByClassEntry> sGtOCTBaseMPByClassStore(GtOCTBaseMPByClassfmt);
DBCStorage <HolidaysEntry> sHolidaysStore(Holidaysfmt);
@ -480,6 +482,8 @@ void LoadDBCStores(const std::string& dataPath)
//LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTRegenMPStore, dbcPath,"gtOCTRegenMP.dbc"); -- not used currently
//LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtRegenHPPerSptStore, dbcPath,"gtRegenHPPerSpt.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtRegenMPPerSptStore, dbcPath,"gtRegenMPPerSpt.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTBaseHPByClassStore, dbcPath,"gtOCTBaseHPByClass.dbc"); // 15595
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTBaseMPByClassStore, dbcPath,"gtOCTBaseMPByClass.dbc"); // 15595
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sHolidaysStore, dbcPath,"Holidays.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemBagFamilyStore, dbcPath,"ItemBagFamily.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemClassStore, dbcPath,"ItemClass.dbc");

View file

@ -142,6 +142,8 @@ extern DBCStorage <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingSca
//extern DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore; -- not used currently
//extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore;
extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore;
extern DBCStorage <GtOCTBaseHPByClassEntry> sGtOCTBaseHPByClassStore;
extern DBCStorage <GtOCTBaseMPByClassEntry> sGtOCTBaseMPByClassStore;
extern DBCStorage <HolidaysEntry> sHolidaysStore;
extern DBCStorage <ItemArmorQualityEntry> sItemArmorQualityStore;
extern DBCStorage <ItemArmorShieldEntry> sItemArmorShieldStore;

View file

@ -1058,6 +1058,16 @@ struct GtRegenMPPerSptEntry
float ratio;
};
struct GtOCTBaseHPByClassEntry
{
float ratio;
};
struct GtOCTBaseMPByClassEntry
{
float ratio;
};
/*struct HolidayDescriptionsEntry
{
uint32 ID; // 0, m_ID this is NOT holiday id

View file

@ -64,6 +64,8 @@ const char GtOCTRegenHPfmt[]="xf";
//const char GtOCTRegenMPfmt[]="f";
const char GtRegenHPPerSptfmt[]="xf";
const char GtRegenMPPerSptfmt[]="xf";
const char GtOCTBaseHPByClassfmt[]="df";
const char GtOCTBaseMPByClassfmt[]="df";
const char Holidaysfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char ItemClassfmt[]="nixxxs";
const char ItemArmorQualityfmt[]="nfffffffi";

View file

@ -165,10 +165,6 @@ ObjectMgr::~ObjectMgr()
for (PetLevelInfoMap::iterator i = petInfo.begin(); i != petInfo.end(); ++i)
delete[] i->second;
// free only if loaded
for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
delete[] playerClassInfo[class_].levelInfo;
for (int race = 0; race < MAX_RACES; ++race)
for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
delete[] playerInfo[race][class_].levelInfo;
@ -3003,104 +2999,6 @@ void ObjectMgr::LoadPlayerInfo()
}
}
// Loading levels data (class only dependent)
{
// 0 1 2 3
QueryResult* result = WorldDatabase.Query("SELECT class, level, basehp, basemana FROM player_classlevelstats");
uint32 count = 0;
if (!result)
{
BarGoLink bar(1);
sLog.outString();
sLog.outString(">> Loaded %u level health/mana definitions", count);
sLog.outErrorDb("Error loading `player_classlevelstats` table or empty table.");
Log::WaitBeforeContinueIfNeed();
exit(1);
}
BarGoLink bar(result->GetRowCount());
do
{
Field* fields = result->Fetch();
uint32 current_class = fields[0].GetUInt32();
if (current_class >= MAX_CLASSES)
{
sLog.outErrorDb("Wrong class %u in `player_classlevelstats` table, ignoring.", current_class);
continue;
}
uint32 current_level = fields[1].GetUInt32();
if (current_level == 0)
{
sLog.outErrorDb("Wrong level %u in `player_classlevelstats` table, ignoring.", current_level);
continue;
}
else if (current_level > sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL))
{
if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
sLog.outErrorDb("Wrong (> %u) level %u in `player_classlevelstats` table, ignoring.", STRONG_MAX_LEVEL, current_level);
else
{
DETAIL_LOG("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `player_classlevelstats` table, ignoring.", current_level);
++count; // make result loading percent "expected" correct in case disabled detail mode for example.
}
continue;
}
PlayerClassInfo* pClassInfo = &playerClassInfo[current_class];
if (!pClassInfo->levelInfo)
pClassInfo->levelInfo = new PlayerClassLevelInfo[sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)];
PlayerClassLevelInfo* pClassLevelInfo = &pClassInfo->levelInfo[current_level - 1];
pClassLevelInfo->basehealth = fields[2].GetUInt16();
pClassLevelInfo->basemana = fields[3].GetUInt16();
bar.step();
++count;
}
while (result->NextRow());
delete result;
sLog.outString();
sLog.outString(">> Loaded %u level health/mana definitions", count);
}
// Fill gaps and check integrity
for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
{
// skip nonexistent classes
if (!sChrClassesStore.LookupEntry(class_))
continue;
PlayerClassInfo* pClassInfo = &playerClassInfo[class_];
// fatal error if no level 1 data
if (!pClassInfo->levelInfo || pClassInfo->levelInfo[0].basehealth == 0)
{
sLog.outErrorDb("Class %i Level 1 does not have health/mana data!", class_);
Log::WaitBeforeContinueIfNeed();
exit(1);
}
// fill level gaps
for (uint32 level = 1; level < sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL); ++level)
{
if (pClassInfo->levelInfo[level].basehealth == 0)
{
sLog.outErrorDb("Class %i Level %i does not have health/mana data. Using stats data of level %i.", class_, level + 1, level);
pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level - 1];
}
}
}
// Loading levels data (class/race dependent)
{
// 0 1 2 3 4 5 6 7
@ -3289,17 +3187,25 @@ void ObjectMgr::LoadPlayerInfo()
}
}
void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint32 level, PlayerClassLevelInfo* info) const
void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint32 level, uint32& baseHP, uint32& baseMana) const
{
if (level < 1 || class_ >= MAX_CLASSES)
return;
PlayerClassInfo const* pInfo = &playerClassInfo[class_];
if (level > sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL))
level = sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL);
*info = pInfo->levelInfo[level - 1];
GtOCTBaseHPByClassEntry const* hp = sGtOCTBaseHPByClassStore.LookupEntry((class_-1) * GT_MAX_LEVEL + level-1);
GtOCTBaseMPByClassEntry const* mp = sGtOCTBaseMPByClassStore.LookupEntry((class_-1) * GT_MAX_LEVEL + level-1);
if (!hp || !mp)
{
sLog.outError("Tried to get non-existant Class-Level combination data for base hp/mp. Class %u Level %u", class_, level);
return;
}
baseHP = uint32(hp->ratio);
baseMana = uint32(mp->ratio);
}
void ObjectMgr::GetPlayerLevelInfo(uint32 race, uint32 class_, uint32 level, PlayerLevelInfo* info) const

View file

@ -509,12 +509,7 @@ class ObjectMgr
PetLevelInfo const* GetPetLevelInfo(uint32 creature_id, uint32 level) const;
PlayerClassInfo const* GetPlayerClassInfo(uint32 class_) const
{
if (class_ >= MAX_CLASSES) return NULL;
return &playerClassInfo[class_];
}
void GetPlayerClassLevelInfo(uint32 class_, uint32 level, PlayerClassLevelInfo* info) const;
void GetPlayerClassLevelInfo(uint32 class_, uint32 level, uint32& baseHP, uint32& baseMana) const;
PlayerInfo const* GetPlayerInfo(uint32 race, uint32 class_) const
{
@ -1174,8 +1169,6 @@ class ObjectMgr
// PetLevelInfoMap[creature_id][level]
PetLevelInfoMap petInfo; // [creature_id][level]
PlayerClassInfo playerClassInfo[MAX_CLASSES];
void BuildPlayerLevelInfo(uint8 race, uint8 class_, uint8 level, PlayerLevelInfo* plinfo) const;
PlayerInfo playerInfo[MAX_RACES][MAX_CLASSES];

View file

@ -2530,15 +2530,15 @@ void Player::GiveLevel(uint32 level)
PlayerLevelInfo info;
sObjectMgr.GetPlayerLevelInfo(getRace(), getClass(), level, &info);
PlayerClassLevelInfo classInfo;
sObjectMgr.GetPlayerClassLevelInfo(getClass(), level, &classInfo);
uint32 basehp = 0, basemana = 0;
sObjectMgr.GetPlayerClassLevelInfo(getClass(), level, basehp, basemana);
// send levelup info to client
WorldPacket data(SMSG_LEVELUP_INFO, (4 + 4 + MAX_POWERS * 4 + MAX_STATS * 4));
data << uint32(level);
data << uint32(int32(classInfo.basehealth) - int32(GetCreateHealth()));
data << uint32(int32(basehp) - int32(GetCreateHealth()));
// for(int i = 0; i < MAX_POWERS; ++i) // Powers loop (0-4)
data << uint32(int32(classInfo.basemana) - int32(GetCreateMana()));
data << uint32(int32(basemana) - int32(GetCreateMana()));
data << uint32(0);
data << uint32(0);
data << uint32(0);
@ -2564,8 +2564,8 @@ void Player::GiveLevel(uint32 level)
for (int i = STAT_STRENGTH; i < MAX_STATS; ++i)
SetCreateStat(Stats(i), info.stats[i]);
SetCreateHealth(classInfo.basehealth);
SetCreateMana(classInfo.basemana);
SetCreateHealth(basehp);
SetCreateMana(basemana);
InitTalentForLevel();
InitTaxiNodesForLevel();
@ -2639,8 +2639,8 @@ void Player::InitStatsForLevel(bool reapplyMods)
if (reapplyMods) // reapply stats values only on .reset stats (level) command
_RemoveAllStatBonuses();
PlayerClassLevelInfo classInfo;
sObjectMgr.GetPlayerClassLevelInfo(getClass(), getLevel(), &classInfo);
uint32 basehp = 0, basemana = 0;
sObjectMgr.GetPlayerClassLevelInfo(getClass(), getLevel(), basehp, basemana);
PlayerLevelInfo info;
sObjectMgr.GetPlayerLevelInfo(getRace(), getClass(), getLevel(), &info);
@ -2663,10 +2663,10 @@ void Player::InitStatsForLevel(bool reapplyMods)
for (int i = STAT_STRENGTH; i < MAX_STATS; ++i)
SetStat(Stats(i), info.stats[i]);
SetCreateHealth(classInfo.basehealth);
SetCreateHealth(basehp);
// set create powers
SetCreateMana(classInfo.basemana);
SetCreateMana(basemana);
SetArmor(int32(m_createStats[STAT_AGILITY] * 2));
@ -2750,7 +2750,7 @@ void Player::InitStatsForLevel(bool reapplyMods)
for (int i = POWER_MANA; i < MAX_POWERS; ++i)
SetMaxPower(Powers(i), GetCreatePowers(Powers(i)));
SetMaxHealth(classInfo.basehealth); // stamina bonus will applied later
SetMaxHealth(basehp); // stamina bonus will applied later
// cleanup mounted state (it will set correctly at aura loading if player saved at mount.
SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0);

View file

@ -265,20 +265,6 @@ struct PlayerCreateInfoItem
typedef std::list<PlayerCreateInfoItem> PlayerCreateInfoItems;
struct PlayerClassLevelInfo
{
PlayerClassLevelInfo() : basehealth(0), basemana(0) {}
uint16 basehealth;
uint16 basemana;
};
struct PlayerClassInfo
{
PlayerClassInfo() : levelInfo(NULL) { }
PlayerClassLevelInfo* levelInfo; //[level-1] 0..MaxPlayerLevel-1
};
struct PlayerLevelInfo
{
PlayerLevelInfo() { for (int i = 0; i < MAX_STATS; ++i) stats[i] = 0; }

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "0022"
#define REVISION_NR "0023"
#endif // __REVISION_NR_H__

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_0001_xxxxx_01_characters"
#define REVISION_DB_MANGOS "required_0001_xxxxx_01_mangos"
#define REVISION_DB_MANGOS "required_0023_xxxxx_01_mangos_player_classlevelstats"
#define REVISION_DB_REALMD "required_0014_xxxxx_01_realmd_account_access"
#endif // __REVISION_SQL_H__