Base data for hp/mana/end calcs, mostly but not completely correct

This commit is contained in:
KimLS 2013-10-18 00:09:00 -07:00
parent 17729365db
commit cdcda943be
10 changed files with 305 additions and 94 deletions

View File

@ -91,6 +91,7 @@ SET(common_sources
SET(common_headers
BasePacket.h
base_data.h
bodytypes.h
breakdowns.h
classes.h

34
common/base_data.h Normal file
View File

@ -0,0 +1,34 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2013 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __EQEMU_COMMON_BASE_DATA_H
#define __EQEMU_COMMON_BASE_DATA_H
struct BaseDataStruct
{
double base_hp;
double base_mana;
double base_end;
double unk1;
double unk2;
double hp_factor;
double mana_factor;
double endurance_factor;
};
#endif

View File

@ -21,14 +21,14 @@
SharedDatabase::SharedDatabase()
: Database(), skill_caps_mmf(nullptr), items_mmf(nullptr), items_hash(nullptr), faction_mmf(nullptr), faction_hash(nullptr),
loot_table_mmf(nullptr), loot_table_hash(nullptr), loot_drop_mmf(nullptr), loot_drop_hash(nullptr)
loot_table_mmf(nullptr), loot_table_hash(nullptr), loot_drop_mmf(nullptr), loot_drop_hash(nullptr), base_data_mmf(nullptr)
{
}
SharedDatabase::SharedDatabase(const char* host, const char* user, const char* passwd, const char* database, uint32 port)
: Database(host, user, passwd, database, port), skill_caps_mmf(nullptr), items_mmf(nullptr), items_hash(nullptr),
faction_mmf(nullptr), faction_hash(nullptr), loot_table_mmf(nullptr), loot_table_hash(nullptr), loot_drop_mmf(nullptr),
loot_drop_hash(nullptr)
loot_drop_hash(nullptr), base_data_mmf(nullptr)
{
}
@ -42,6 +42,7 @@ SharedDatabase::~SharedDatabase() {
safe_delete(loot_drop_mmf);
safe_delete(loot_table_hash);
safe_delete(loot_drop_hash);
safe_delete(base_data_mmf);
}
bool SharedDatabase::SetHideMe(uint32 account_id, uint8 hideme)
@ -1742,6 +1743,136 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
}
}
int SharedDatabase::GetMaxBaseDataLevel() {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = "SELECT MAX(level) FROM base_data";
MYSQL_RES *result;
MYSQL_ROW row;
int32 ret = 0;
if(RunQuery(query, strlen(query), errbuf, &result)) {
row = mysql_fetch_row(result);
if(row) {
ret = atoi(row[0]);
mysql_free_result(result);
} else {
ret = -1;
mysql_free_result(result);
}
} else {
_log(SPELLS__LOAD_ERR, "Error in GetMaxBaseDataLevel query '%s' %s", query, errbuf);
ret = -1;
}
return ret;
}
bool SharedDatabase::LoadBaseData() {
if(base_data_mmf) {
return true;
}
try {
EQEmu::IPCMutex mutex("base_data");
mutex.Lock();
base_data_mmf = new EQEmu::MemoryMappedFile("shared/base_data");
int size = 16 * (GetMaxBaseDataLevel() + 1) * sizeof(BaseDataStruct);
if(size == 0) {
EQ_EXCEPT("SharedDatabase", "Base Data size is zero");
}
if(base_data_mmf->Size() != size) {
EQ_EXCEPT("SharedDatabase", "Couldn't load base data because base_data_mmf->Size() != size");
}
mutex.Unlock();
} catch(std::exception& ex) {
LogFile->write(EQEMuLog::Error, "Error Loading Base Data: %s", ex.what());
return false;
}
return true;
}
void SharedDatabase::LoadBaseData(void *data, int max_level) {
char *base_ptr = reinterpret_cast<char*>(data);
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = "SELECT * FROM base_data ORDER BY level, class ASC";
MYSQL_RES *result;
MYSQL_ROW row;
if(RunQuery(query, strlen(query), errbuf, &result)) {
int lvl = 0;
int cl = 0;
while (row = mysql_fetch_row(result)) {
lvl = atoi(row[0]);
cl = atoi(row[1]);
if(lvl <= 0) {
LogFile->write(EQEMuLog::Error, "Non fatal error: base_data.level <= 0, ignoring.");
continue;
}
if(lvl >= max_level) {
LogFile->write(EQEMuLog::Error, "Non fatal error: base_data.level >= max_level, ignoring.");
continue;
}
if(cl <= 0) {
LogFile->write(EQEMuLog::Error, "Non fatal error: base_data.cl <= 0, ignoring.");
continue;
}
if(cl > 16) {
LogFile->write(EQEMuLog::Error, "Non fatal error: base_data.class > 16, ignoring.");
continue;
}
BaseDataStruct *bd = reinterpret_cast<BaseDataStruct*>(base_ptr + (((16 * (lvl - 1)) + (cl - 1)) * sizeof(BaseDataStruct)));
bd->base_hp = atof(row[2]);
bd->base_mana = atof(row[3]);
bd->base_end = atof(row[4]);
bd->unk1 = atof(row[5]);
bd->unk2 = atof(row[6]);
bd->hp_factor = atof(row[7]);
bd->mana_factor = atof(row[8]);
bd->endurance_factor = atof(row[9]);
}
mysql_free_result(result);
} else {
LogFile->write(EQEMuLog::Error, "Error in LoadBaseData query '%s' %s", query, errbuf);
safe_delete_array(query);
}
}
const BaseDataStruct* SharedDatabase::GetBaseData(int lvl, int cl) {
if(!base_data_mmf) {
return nullptr;
}
if(lvl <= 0) {
return nullptr;
}
if(cl <= 0) {
return nullptr;
}
if(cl > 16) {
return nullptr;
}
char *base_ptr = reinterpret_cast<char*>(base_data_mmf->Get());
uint32 offset = ((16 * (lvl - 1)) + (cl - 1)) * sizeof(BaseDataStruct);
if(offset >= base_data_mmf->Size()) {
return nullptr;
}
BaseDataStruct *bd = reinterpret_cast<BaseDataStruct*>(base_ptr + offset);
return bd;
}
void SharedDatabase::GetLootTableInfo(uint32 &loot_table_count, uint32 &max_loot_table, uint32 &loot_table_entries) {
loot_table_count = 0;
max_loot_table = 0;

View File

@ -7,6 +7,7 @@
#include "skills.h"
#include "spdat.h"
#include "Item.h"
#include "base_data.h"
#include "fixed_memory_hash_set.h"
#include "fixed_memory_variable_hash_set.h"
@ -110,6 +111,11 @@ public:
void LoadSpells(void *data, int max_spells);
void LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpellID);
int GetMaxBaseDataLevel();
bool LoadBaseData();
void LoadBaseData(void *data, int max_level);
const BaseDataStruct* GetBaseData(int lvl, int cl);
protected:
EQEmu::MemoryMappedFile *skill_caps_mmf;
@ -121,6 +127,7 @@ protected:
EQEmu::FixedMemoryVariableHashSet<LootTable_Struct> *loot_table_hash;
EQEmu::MemoryMappedFile *loot_drop_mmf;
EQEmu::FixedMemoryVariableHashSet<LootDrop_Struct> *loot_drop_hash;
EQEmu::MemoryMappedFile *base_data_mmf;
};
#endif /*SHAREDDB_H_*/

View File

@ -1,6 +1,7 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
SET(shared_memory_sources
base_data.cpp
items.cpp
loot.cpp
main.cpp
@ -10,6 +11,7 @@ SET(shared_memory_sources
)
SET(shared_memory_headers
base_data.h
items.h
loot.h
npc_faction.h

View File

@ -0,0 +1,42 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2013 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "base_data.h"
#include "../common/debug.h"
#include "../common/shareddb.h"
#include "../common/ipc_mutex.h"
#include "../common/memory_mapped_file.h"
#include "../common/eqemu_exception.h"
void LoadBaseData(SharedDatabase *database) {
EQEmu::IPCMutex mutex("base_data");
mutex.Lock();
int records = (database->GetMaxBaseDataLevel() + 1);
if(records == 0) {
EQ_EXCEPT("Shared Memory", "Unable to get base data from the database.");
}
uint32 size = records * 16 * sizeof(BaseDataStruct);
EQEmu::MemoryMappedFile mmf("shared/base_data", size);
mmf.ZeroFile();
void *ptr = mmf.Get();
database->LoadBaseData(ptr, records);
mutex.Unlock();
}

25
shared_memory/base_data.h Normal file
View File

@ -0,0 +1,25 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2013 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __EQEMU_SHARED_MEMORY_BASE_DATA_H
#define __EQEMU_SHARED_MEMORY_BASE_DATA_H
class SharedDatabase;
void LoadBaseData(SharedDatabase *database);
#endif

View File

@ -29,6 +29,7 @@
#include "loot.h"
#include "skill_caps.h"
#include "spells.h"
#include "base_data.h"
int main(int argc, char **argv) {
RegisterExecutablePlatform(ExePlatformSharedMemory);
@ -55,18 +56,14 @@ int main(int argc, char **argv) {
}
bool load_all = true;
bool load_items = true;
bool load_factions = true;
bool load_loot = true;
bool load_skill_caps = true;
bool load_spells = true;
bool load_items = false;
bool load_factions = false;
bool load_loot = false;
bool load_skill_caps = false;
bool load_spells = false;
bool load_bd = false;
if(argc > 1) {
load_all = false;
load_items = false;
load_factions = false;
load_loot = false;
load_skill_caps = false;
load_spells = false;
for(int i = 1; i < argc; ++i) {
switch(argv[i][0]) {
@ -76,6 +73,12 @@ int main(int argc, char **argv) {
}
break;
case 'b':
if(strcasecmp("base_data", argv[i]) == 0) {
load_bd = true;
}
break;
case 'i':
if(strcasecmp("items", argv[i]) == 0) {
load_items = true;
@ -155,5 +158,15 @@ int main(int argc, char **argv) {
}
}
if(load_all || load_bd) {
LogFile->write(EQEMuLog::Status, "Loading base data...");
try {
LoadBaseData(&database);
} catch(std::exception &ex) {
LogFile->write(EQEMuLog::Error, "%s", ex.what());
return 1;
}
}
return 0;
}

View File

@ -371,34 +371,19 @@ uint16 Mob::GetClassLevelFactor(){
int32 Client::CalcBaseHP()
{
if(GetClientVersion() >= EQClientSoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
float SoDPost255;
uint16 NormalSTA = GetSTA();
if(((NormalSTA - 255) / 2) > 0)
SoDPost255 = ((NormalSTA - 255) / 2);
else
SoDPost255 = 0;
int hp_factor = GetClassHPFactor();
if (level < 41) {
base_hp = (5 + (GetLevel() * hp_factor / 12) +
((NormalSTA - SoDPost255) * GetLevel() * hp_factor / 3600));
}
else if (level < 81) {
base_hp = (5 + (40 * hp_factor / 12) + ((GetLevel() - 40) * hp_factor / 6) +
((NormalSTA - SoDPost255) * hp_factor / 90) +
((NormalSTA - SoDPost255) * (GetLevel() - 40) * hp_factor / 1800));
}
else {
base_hp = (5 + (80 * hp_factor / 8) + ((GetLevel() - 80) * hp_factor / 10) +
((NormalSTA - SoDPost255) * hp_factor / 90) +
((NormalSTA - SoDPost255) * hp_factor / 45));
if(GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
int stats = GetSTA();
if(stats > 255) {
stats = (stats - 255) / 2;
stats += 255;
}
base_hp = 5;
auto base_data = database.GetBaseData(GetLevel(), GetClass());
if(base_data) {
base_hp += base_data->base_hp + (base_data->hp_factor * stats);
base_hp += (GetHeroicSTA() * 10);
}
}
else {
uint16 Post255;
@ -991,7 +976,7 @@ int32 Client::CalcBaseMana()
case 'I':
WisInt = GetINT();
if (GetClientVersion() >= EQClientSoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
if (GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
if (WisInt > 100) {
ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100);
@ -1003,19 +988,10 @@ int32 Client::CalcBaseMana()
ConvertedWisInt = WisInt;
}
if (GetLevel() < 41) {
wisint_mana = (GetLevel() * 75 * ConvertedWisInt / 1000);
base_mana = (GetLevel() * 15);
auto base_data = database.GetBaseData(GetLevel(), GetClass());
if(base_data) {
max_m = base_data->base_mana + (ConvertedWisInt * base_data->mana_factor) + (GetHeroicINT() * 10);
}
else if (GetLevel() < 81) {
wisint_mana = ((3 * ConvertedWisInt) + ((GetLevel() - 40) * 15 * ConvertedWisInt / 100));
base_mana = (600 + ((GetLevel() - 40) * 30));
}
else {
wisint_mana = (9 * ConvertedWisInt);
base_mana = (1800 + ((GetLevel() - 80) * 18));
}
max_m = base_mana + wisint_mana + (GetHeroicINT() * 10);
}
else
{
@ -1035,7 +1011,7 @@ int32 Client::CalcBaseMana()
case 'W':
WisInt = GetWIS();
if (GetClientVersion() >= EQClientSoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
if (GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
if (WisInt > 100) {
ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100);
@ -1047,19 +1023,10 @@ int32 Client::CalcBaseMana()
ConvertedWisInt = WisInt;
}
if (GetLevel() < 41) {
wisint_mana = (GetLevel() * 75 * ConvertedWisInt / 1000);
base_mana = (GetLevel() * 15);
auto base_data = database.GetBaseData(GetLevel(), GetClass());
if(base_data) {
max_m = base_data->base_mana + (ConvertedWisInt * base_data->mana_factor) + (GetHeroicWIS() * 10);
}
else if (GetLevel() < 81) {
wisint_mana = ((3 * ConvertedWisInt) + ((GetLevel() - 40) * 15 * ConvertedWisInt / 100));
base_mana = (600 + ((GetLevel() - 40) * 30));
}
else {
wisint_mana = (9 * ConvertedWisInt);
base_mana = (1800 + ((GetLevel() - 80) * 18));
}
max_m = base_mana + wisint_mana + (GetHeroicWIS() * 10);
}
else
{
@ -1934,44 +1901,25 @@ void Client::CalcMaxEndurance()
int32 Client::CalcBaseEndurance()
{
int32 base_end = 0;
int32 base_endurance = 0;
int32 ConvertedStats = 0;
int32 sta_end = 0;
int Stats = 0;
if(GetClientVersion() >= EQClientSoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
int HeroicStats = 0;
if(GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
double heroic_stats = (GetHeroicSTR() + GetHeroicSTA() + GetHeroicDEX() + GetHeroicAGI()) / 4.0f;
double stats = (GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4.0f;
Stats = ((GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4);
HeroicStats = ((GetHeroicSTR() + GetHeroicSTA() + GetHeroicDEX() + GetHeroicAGI()) / 4);
if (Stats > 100) {
ConvertedStats = (((Stats - 100) * 5 / 2) + 100);
if (Stats > 201) {
ConvertedStats -= ((Stats - 201) * 5 / 4);
}
}
else {
ConvertedStats = Stats;
if(stats > 201.0f) {
stats = 1.25f * (stats - 201.0f) + 352.5f;
} else if(stats > 100.0f) {
stats = 2.5f * (stats - 100.0f) + 100.0f;
}
if (GetLevel() < 41) {
sta_end = (GetLevel() * 75 * ConvertedStats / 1000);
base_endurance = (GetLevel() * 15);
auto base_data = database.GetBaseData(GetLevel(), GetClass());
if(base_data) {
base_end = base_data->base_end + (heroic_stats * 10.0f) + (base_data->endurance_factor * static_cast<int>(stats));
}
else if (GetLevel() < 81) {
sta_end = ((3 * ConvertedStats) + ((GetLevel() - 40) * 15 * ConvertedStats / 100));
base_endurance = (600 + ((GetLevel() - 40) * 30));
}
else {
sta_end = (9 * ConvertedStats);
base_endurance = (1800 + ((GetLevel() - 80) * 18));
}
base_end = (base_endurance + sta_end + (HeroicStats * 10));
}
else
{
Stats = GetSTR()+GetSTA()+GetDEX()+GetAGI();
int Stats = GetSTR()+GetSTA()+GetDEX()+GetAGI();
int LevelBase = GetLevel() * 15;
int at_most_800 = Stats;
@ -2000,6 +1948,7 @@ int32 Client::CalcBaseEndurance()
//take all of the sums from above, then multiply by level*0.075
base_end += ( bonus_sum * 3 * GetLevel() ) / 40;
}
return base_end;
}

View File

@ -235,6 +235,13 @@ int main(int argc, char** argv) {
EQEmu::MemoryMappedFile *mmf = nullptr;
LoadSpells(&mmf);
_log(ZONE__INIT, "Loading base data");
if (!database.LoadBaseData()) {
_log(ZONE__INIT_ERR, "Loading base data FAILED!");
CheckEQEMuErrorAndPause();
return 1;
}
_log(ZONE__INIT, "Loading guilds");
guild_mgr.LoadGuilds();
_log(ZONE__INIT, "Loading factions");