From cdcda943be4a9f8fafe45299cb271ee7ae453601 Mon Sep 17 00:00:00 2001 From: KimLS Date: Fri, 18 Oct 2013 00:09:00 -0700 Subject: [PATCH] Base data for hp/mana/end calcs, mostly but not completely correct --- common/CMakeLists.txt | 1 + common/base_data.h | 34 +++++++++ common/shareddb.cpp | 135 ++++++++++++++++++++++++++++++++++- common/shareddb.h | 7 ++ shared_memory/CMakeLists.txt | 2 + shared_memory/base_data.cpp | 42 +++++++++++ shared_memory/base_data.h | 25 +++++++ shared_memory/main.cpp | 33 ++++++--- zone/client_mods.cpp | 113 ++++++++--------------------- zone/net.cpp | 7 ++ 10 files changed, 305 insertions(+), 94 deletions(-) create mode 100644 common/base_data.h create mode 100644 shared_memory/base_data.cpp create mode 100644 shared_memory/base_data.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 3d0c95f52..a63563983 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -91,6 +91,7 @@ SET(common_sources SET(common_headers BasePacket.h + base_data.h bodytypes.h breakdowns.h classes.h diff --git a/common/base_data.h b/common/base_data.h new file mode 100644 index 000000000..fb2766f45 --- /dev/null +++ b/common/base_data.h @@ -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 diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 00f5355ab..e5357000b 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -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(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(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(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(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; diff --git a/common/shareddb.h b/common/shareddb.h index d10ec894e..ab7a1fce7 100644 --- a/common/shareddb.h +++ b/common/shareddb.h @@ -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 *loot_table_hash; EQEmu::MemoryMappedFile *loot_drop_mmf; EQEmu::FixedMemoryVariableHashSet *loot_drop_hash; + EQEmu::MemoryMappedFile *base_data_mmf; }; #endif /*SHAREDDB_H_*/ diff --git a/shared_memory/CMakeLists.txt b/shared_memory/CMakeLists.txt index da4e6d609..863b5633f 100644 --- a/shared_memory/CMakeLists.txt +++ b/shared_memory/CMakeLists.txt @@ -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 diff --git a/shared_memory/base_data.cpp b/shared_memory/base_data.cpp new file mode 100644 index 000000000..c473101da --- /dev/null +++ b/shared_memory/base_data.cpp @@ -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(); +} + diff --git a/shared_memory/base_data.h b/shared_memory/base_data.h new file mode 100644 index 000000000..c1f6c87ea --- /dev/null +++ b/shared_memory/base_data.h @@ -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 diff --git a/shared_memory/main.cpp b/shared_memory/main.cpp index fb4461d0d..1c15b0a8e 100644 --- a/shared_memory/main.cpp +++ b/shared_memory/main.cpp @@ -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; } diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index b05b30e77..94d7909b5 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -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)); + if(GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { + int stats = GetSTA(); + if(stats > 255) { + stats = (stats - 255) / 2; + stats += 255; } - 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)); + + 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 { - base_hp = (5 + (80 * hp_factor / 8) + ((GetLevel() - 80) * hp_factor / 10) + - ((NormalSTA - SoDPost255) * hp_factor / 90) + - ((NormalSTA - SoDPost255) * hp_factor / 45)); - } - - 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(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; } diff --git a/zone/net.cpp b/zone/net.cpp index a3b75dbaa..98ef19362 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -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");