mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 12:41:30 +00:00
[Skill Caps] Remove from shared memory and simplify (#4069)
* [Skill Caps] Remove from shared memory and simplify - Removes Skill Caps loading from shared memory and puts it into zone. - Adds `id` column to `skill_caps`. - Remove primary keys and use `id` as primary key. - Add unique index using `skill_id`, `class_id`, `level`, and `cap`. - Renames `class` to `class_id` in `skill_caps` table. - Renames `skillID` to `skill_id` in `skill_caps` table. - Regenerates Skill Caps repository. - Adds `#reload skill_caps` to reload skill caps in real time. * Update groups.cpp * Update groups.cpp
This commit is contained in:
parent
036309ebec
commit
d7ea290b6b
@ -29,6 +29,8 @@
|
||||
#include "../../common/content/world_content_service.h"
|
||||
#include "../../common/zone_store.h"
|
||||
#include "../../common/path_manager.h"
|
||||
#include "../../common/repositories/skill_caps_repository.h"
|
||||
#include "../../common/file.h"
|
||||
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
@ -164,81 +166,76 @@ void ExportSpells(SharedDatabase *db)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
bool SkillUsable(SharedDatabase *db, int skill_id, int class_id)
|
||||
bool SkillUsable(SharedDatabase* db, int skill_id, int class_id)
|
||||
{
|
||||
|
||||
bool res = false;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT max(cap) FROM skill_caps WHERE class=%d AND skillID=%d",
|
||||
class_id, skill_id
|
||||
const auto& l = SkillCapsRepository::GetWhere(
|
||||
*db,
|
||||
fmt::format(
|
||||
"`class_id` = {} AND `skill_id` = {} ORDER BY `cap` DESC LIMIT 1",
|
||||
class_id,
|
||||
skill_id
|
||||
)
|
||||
);
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
if (row[0] && Strings::ToInt(row[0]) > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return !l.empty();
|
||||
}
|
||||
|
||||
int GetSkill(SharedDatabase *db, int skill_id, int class_id, int level)
|
||||
uint32 GetSkill(SharedDatabase* db, int skill_id, int class_id, int level)
|
||||
{
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT cap FROM skill_caps WHERE class=%d AND skillID=%d AND level=%d",
|
||||
class_id, skill_id, level
|
||||
const auto& l = SkillCapsRepository::GetWhere(
|
||||
*db,
|
||||
fmt::format(
|
||||
"`class_id` = {} AND `skill_id` = {} AND `level` = {}",
|
||||
class_id,
|
||||
skill_id,
|
||||
level
|
||||
)
|
||||
);
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
|
||||
if (l.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
return 0;
|
||||
}
|
||||
auto e = l.front();
|
||||
|
||||
auto row = results.begin();
|
||||
return Strings::ToInt(row[0]);
|
||||
return e.cap;
|
||||
}
|
||||
|
||||
void ExportSkillCaps(SharedDatabase *db)
|
||||
void ExportSkillCaps(SharedDatabase* db)
|
||||
{
|
||||
LogInfo("Exporting Skill Caps");
|
||||
|
||||
std::string file = fmt::format("{}/export/SkillCaps.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
if (!f) {
|
||||
std::ofstream file(fmt::format("{}/export/SkillCaps.txt", path.GetServerPath()));
|
||||
if (!file || !file.is_open()) {
|
||||
LogError("Unable to open export/SkillCaps.txt to write, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int cl = 1; cl <= 16; ++cl) {
|
||||
for (int skill = 0; skill <= 77; ++skill) {
|
||||
if (SkillUsable(db, skill, cl)) {
|
||||
int previous_cap = 0;
|
||||
for (int level = 1; level <= 100; ++level) {
|
||||
int cap = GetSkill(db, skill, cl, level);
|
||||
const uint8 skill_cap_max_level = (
|
||||
RuleI(Character, SkillCapMaxLevel) > 0 ?
|
||||
RuleI(Character, SkillCapMaxLevel) :
|
||||
RuleI(Character, MaxLevel)
|
||||
);
|
||||
|
||||
for (uint8 class_id = Class::Warrior; class_id <= Class::Berserker; class_id++) {
|
||||
for (uint8 skill_id = EQ::skills::Skill1HBlunt; skill_id <= EQ::skills::Skill2HPiercing; skill_id++) {
|
||||
if (SkillUsable(db, skill_id, class_id)) {
|
||||
uint32 previous_cap = 0;
|
||||
for (uint8 level = 1; level <= skill_cap_max_level; level++) {
|
||||
uint32 cap = GetSkill(db, skill_id, class_id, level);
|
||||
if (cap < previous_cap) {
|
||||
cap = previous_cap;
|
||||
}
|
||||
|
||||
fprintf(f, "%d^%d^%d^%d^0\n", cl, skill, level, cap);
|
||||
file << fmt::format("{}^{}^{}^{}^0", class_id, skill_id, level, cap) << std::endl;
|
||||
|
||||
previous_cap = cap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
file.close();
|
||||
}
|
||||
|
||||
void ExportBaseData(SharedDatabase *db)
|
||||
|
||||
@ -1150,56 +1150,6 @@ uint8 Database::GetRaceSkill(uint8 skillid, uint8 in_race)
|
||||
return Strings::ToUnsignedInt(row[0]);
|
||||
}
|
||||
|
||||
uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level)
|
||||
{
|
||||
uint8 skill_level = 0, skill_formula = 0;
|
||||
uint16 base_cap = 0, skill_cap = 0, skill_cap2 = 0, skill_cap3 = 0;
|
||||
|
||||
|
||||
//Fetch the data from DB.
|
||||
std::string query = StringFormat("SELECT level, formula, pre50cap, post50cap, post60cap from skillcaps where skill = %i && class = %i", skillid, in_class);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (results.Success() && results.RowsAffected() != 0)
|
||||
{
|
||||
auto row = results.begin();
|
||||
skill_level = Strings::ToUnsignedInt(row[0]);
|
||||
skill_formula = Strings::ToUnsignedInt(row[1]);
|
||||
skill_cap = Strings::ToUnsignedInt(row[2]);
|
||||
if (Strings::ToUnsignedInt(row[3]) > skill_cap)
|
||||
skill_cap2 = (Strings::ToUnsignedInt(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
|
||||
skill_cap3 = Strings::ToUnsignedInt(row[4]);
|
||||
}
|
||||
|
||||
int race_skill = GetRaceSkill(skillid,in_race);
|
||||
|
||||
if (race_skill > 0 && (race_skill > skill_cap || skill_cap == 0 || in_level < skill_level))
|
||||
return race_skill;
|
||||
|
||||
if (skill_cap == 0) //Can't train this skill at all.
|
||||
return 255; //Untrainable
|
||||
|
||||
if (in_level < skill_level)
|
||||
return 254; //Untrained
|
||||
|
||||
//Determine pre-51 level-based cap
|
||||
if (skill_formula > 0)
|
||||
base_cap = in_level*skill_formula+skill_formula;
|
||||
if (base_cap > skill_cap || skill_formula == 0)
|
||||
base_cap = skill_cap;
|
||||
|
||||
//If post 50, add post 50 cap to base cap.
|
||||
if (in_level > 50 && skill_cap2 > 0)
|
||||
base_cap += skill_cap2*(in_level-50);
|
||||
|
||||
//No cap should ever go above its post50cap
|
||||
if (skill_cap3 > 0 && base_cap > skill_cap3)
|
||||
base_cap = skill_cap3;
|
||||
|
||||
//Base cap is now the max value at the person's level, return it!
|
||||
return base_cap;
|
||||
}
|
||||
|
||||
uint32 Database::GetCharacterInfo(std::string character_name, uint32 *account_id, uint32 *zone_id, uint32 *instance_id)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
|
||||
@ -244,7 +244,6 @@ public:
|
||||
uint8 GetMinStatus(uint32 zone_id, uint32 instance_version);
|
||||
uint8 GetRaceSkill(uint8 skillid, uint8 in_race);
|
||||
uint8 GetServerType();
|
||||
uint8 GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level);
|
||||
|
||||
void AddReport(std::string who, std::string against, std::string lines);
|
||||
struct TimeOfDay_Struct LoadTime(time_t &realtime);
|
||||
|
||||
@ -5451,6 +5451,22 @@ DROP PRIMARY KEY,
|
||||
ADD PRIMARY KEY (`group_id`, `character_id`, `bot_id`, `merc_id`) USING BTREE;
|
||||
ALTER TABLE `group_id`
|
||||
MODIFY COLUMN `character_id` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `name`;
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9268,
|
||||
.description = "2024_03_23_skill_caps.sql",
|
||||
.check = "SHOW COLUMNS FROM `skill_caps` LIKE 'skill_id'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `skill_caps`
|
||||
CHANGE COLUMN `skillID` `skill_id` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 FIRST,
|
||||
CHANGE COLUMN `class` `class_id` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `skill_id`,
|
||||
ADD COLUMN `id` int(3) UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
|
||||
DROP PRIMARY KEY,
|
||||
ADD PRIMARY KEY (`id`) USING BTREE,
|
||||
ADD INDEX `level_skill_cap`(`skill_id`, `class_id`, `level`, `cap`);
|
||||
)"
|
||||
}
|
||||
// -- template; copy/paste this when you need to create a new entry
|
||||
|
||||
@ -19,8 +19,9 @@
|
||||
class BaseSkillCapsRepository {
|
||||
public:
|
||||
struct SkillCaps {
|
||||
uint8_t skillID;
|
||||
uint8_t class_;
|
||||
uint32_t id;
|
||||
uint8_t skill_id;
|
||||
uint8_t class_id;
|
||||
uint8_t level;
|
||||
uint32_t cap;
|
||||
uint8_t class_;
|
||||
@ -28,14 +29,15 @@ public:
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("skillID");
|
||||
return std::string("id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"skillID",
|
||||
"`class`",
|
||||
"id",
|
||||
"skill_id",
|
||||
"class_id",
|
||||
"level",
|
||||
"cap",
|
||||
"class_",
|
||||
@ -45,8 +47,9 @@ public:
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"skillID",
|
||||
"`class`",
|
||||
"id",
|
||||
"skill_id",
|
||||
"class_id",
|
||||
"level",
|
||||
"cap",
|
||||
"class_",
|
||||
@ -90,11 +93,12 @@ public:
|
||||
{
|
||||
SkillCaps e{};
|
||||
|
||||
e.skillID = 0;
|
||||
e.class_ = 0;
|
||||
e.level = 0;
|
||||
e.cap = 0;
|
||||
e.class_ = 0;
|
||||
e.id = 0;
|
||||
e.skill_id = 0;
|
||||
e.class_id = 0;
|
||||
e.level = 0;
|
||||
e.cap = 0;
|
||||
e.class_ = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@ -105,7 +109,7 @@ public:
|
||||
)
|
||||
{
|
||||
for (auto &skill_caps : skill_capss) {
|
||||
if (skill_caps.skillID == skill_caps_id) {
|
||||
if (skill_caps.id == skill_caps_id) {
|
||||
return skill_caps;
|
||||
}
|
||||
}
|
||||
@ -131,11 +135,12 @@ public:
|
||||
if (results.RowCount() == 1) {
|
||||
SkillCaps e{};
|
||||
|
||||
e.skillID = row[0] ? static_cast<uint8_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.class_ = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.level = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.cap = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.class_ = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.skill_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.class_id = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.level = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.cap = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.class_ = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@ -169,11 +174,11 @@ public:
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.skillID));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.class_));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.level));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.cap));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.class_));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.skill_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.class_id));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.level));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.cap));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.class_));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@ -181,7 +186,7 @@ public:
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.skillID
|
||||
e.id
|
||||
)
|
||||
);
|
||||
|
||||
@ -195,8 +200,9 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.skillID));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.skill_id));
|
||||
v.push_back(std::to_string(e.class_id));
|
||||
v.push_back(std::to_string(e.level));
|
||||
v.push_back(std::to_string(e.cap));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
@ -210,7 +216,7 @@ public:
|
||||
);
|
||||
|
||||
if (results.Success()) {
|
||||
e.skillID = results.LastInsertedID();
|
||||
e.id = results.LastInsertedID();
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -229,8 +235,9 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.skillID));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.skill_id));
|
||||
v.push_back(std::to_string(e.class_id));
|
||||
v.push_back(std::to_string(e.level));
|
||||
v.push_back(std::to_string(e.cap));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
@ -267,11 +274,12 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SkillCaps e{};
|
||||
|
||||
e.skillID = row[0] ? static_cast<uint8_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.class_ = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.level = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.cap = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.class_ = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.skill_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.class_id = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.level = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.cap = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.class_ = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@ -296,11 +304,12 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SkillCaps e{};
|
||||
|
||||
e.skillID = row[0] ? static_cast<uint8_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.class_ = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.level = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.cap = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.class_ = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.skill_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.class_id = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.level = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.cap = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.class_ = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@ -375,8 +384,9 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.skillID));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.skill_id));
|
||||
v.push_back(std::to_string(e.class_id));
|
||||
v.push_back(std::to_string(e.level));
|
||||
v.push_back(std::to_string(e.cap));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
@ -402,8 +412,9 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.skillID));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.skill_id));
|
||||
v.push_back(std::to_string(e.class_id));
|
||||
v.push_back(std::to_string(e.level));
|
||||
v.push_back(std::to_string(e.cap));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
|
||||
@ -273,6 +273,7 @@
|
||||
#define ServerOP_ReloadFactions 0x4126
|
||||
#define ServerOP_ReloadLoot 0x4127
|
||||
#define ServerOP_ReloadBaseData 0x4128
|
||||
#define ServerOP_ReloadSkillCaps 0x4129
|
||||
|
||||
#define ServerOP_CZDialogueWindow 0x4500
|
||||
#define ServerOP_CZLDoNUpdate 0x4501
|
||||
|
||||
@ -45,6 +45,7 @@
|
||||
#include "repositories/loottable_repository.h"
|
||||
#include "repositories/character_item_recast_repository.h"
|
||||
#include "repositories/character_corpses_repository.h"
|
||||
#include "repositories/skill_caps_repository.h"
|
||||
|
||||
namespace ItemField
|
||||
{
|
||||
@ -1626,136 +1627,6 @@ bool SharedDatabase::GetCommandSubSettings(std::vector<CommandSubsettingsReposit
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SharedDatabase::LoadSkillCaps(const std::string &prefix) {
|
||||
skill_caps_mmf.reset(nullptr);
|
||||
|
||||
try {
|
||||
const auto Config = EQEmuConfig::get();
|
||||
EQ::IPCMutex mutex("skill_caps");
|
||||
mutex.Lock();
|
||||
std::string file_name = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("skill_caps"));
|
||||
LogInfo("Loading [{}]", file_name);
|
||||
skill_caps_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name);
|
||||
|
||||
LogInfo("Loaded skill caps via shared memory");
|
||||
|
||||
mutex.Unlock();
|
||||
} catch(std::exception &ex) {
|
||||
LogError("Error loading skill caps: {}", ex.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SharedDatabase::LoadSkillCaps(void *data) {
|
||||
const uint32 class_count = Class::PLAYER_CLASS_COUNT;
|
||||
const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
|
||||
const uint32 level_count = HARD_LEVEL_CAP + 1;
|
||||
uint16 *skill_caps_table = static_cast<uint16*>(data);
|
||||
|
||||
const std::string query = "SELECT skillID, class, level, cap FROM skill_caps ORDER BY skillID, class, level";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogError("Error loading skill caps from database: {}", results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto& row = results.begin(); row != results.end(); ++row) {
|
||||
const uint8 skillID = Strings::ToUnsignedInt(row[0]);
|
||||
const uint8 class_ = Strings::ToUnsignedInt(row[1]) - 1;
|
||||
const uint8 level = Strings::ToUnsignedInt(row[2]);
|
||||
const uint16 cap = Strings::ToUnsignedInt(row[3]);
|
||||
|
||||
if(skillID >= skill_count || class_ >= class_count || level >= level_count)
|
||||
continue;
|
||||
|
||||
const uint32 index = (((class_ * skill_count) + skillID) * level_count) + level;
|
||||
skill_caps_table[index] = cap;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 SharedDatabase::GetSkillCap(uint8 Class_, EQ::skills::SkillType Skill, uint8 Level) const
|
||||
{
|
||||
if(!skill_caps_mmf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(Class_ == 0)
|
||||
return 0;
|
||||
|
||||
int SkillMaxLevel = RuleI(Character, SkillCapMaxLevel);
|
||||
if(SkillMaxLevel < 1) {
|
||||
SkillMaxLevel = RuleI(Character, MaxLevel);
|
||||
}
|
||||
|
||||
const uint32 class_count = Class::PLAYER_CLASS_COUNT;
|
||||
const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
|
||||
const uint32 level_count = HARD_LEVEL_CAP + 1;
|
||||
if(Class_ > class_count || static_cast<uint32>(Skill) > skill_count || Level > level_count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(Level > static_cast<uint8>(SkillMaxLevel)){
|
||||
Level = static_cast<uint8>(SkillMaxLevel);
|
||||
}
|
||||
|
||||
const uint32 index = ((((Class_ - 1) * skill_count) + Skill) * level_count) + Level;
|
||||
const uint16 *skill_caps_table = static_cast<uint16*>(skill_caps_mmf->Get());
|
||||
return skill_caps_table[index];
|
||||
}
|
||||
|
||||
uint8 SharedDatabase::GetTrainLevel(uint8 Class_, EQ::skills::SkillType Skill, uint8 Level) const
|
||||
{
|
||||
if(!skill_caps_mmf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(Class_ == 0)
|
||||
return 0;
|
||||
|
||||
int SkillMaxLevel = RuleI(Character, SkillCapMaxLevel);
|
||||
if (SkillMaxLevel < 1) {
|
||||
SkillMaxLevel = RuleI(Character, MaxLevel);
|
||||
}
|
||||
|
||||
const uint32 class_count = Class::PLAYER_CLASS_COUNT;
|
||||
const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
|
||||
const uint32 level_count = HARD_LEVEL_CAP + 1;
|
||||
if(Class_ > class_count || static_cast<uint32>(Skill) > skill_count || Level > level_count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 ret = 0;
|
||||
if(Level > static_cast<uint8>(SkillMaxLevel)) {
|
||||
const uint32 index = ((((Class_ - 1) * skill_count) + Skill) * level_count);
|
||||
const uint16 *skill_caps_table = static_cast<uint16*>(skill_caps_mmf->Get());
|
||||
for(uint8 x = 0; x < Level; x++){
|
||||
if(skill_caps_table[index + x]){
|
||||
ret = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint32 index = ((((Class_ - 1) * skill_count) + Skill) * level_count);
|
||||
const uint16 *skill_caps_table = static_cast<uint16*>(skill_caps_mmf->Get());
|
||||
for(int x = 0; x < SkillMaxLevel; x++){
|
||||
if(skill_caps_table[index + x]){
|
||||
ret = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ret > GetSkillCap(Class_, Skill, Level))
|
||||
ret = static_cast<uint8>(GetSkillCap(Class_, Skill, Level));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SharedDatabase::LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpellID) {
|
||||
const std::string query = StringFormat("SELECT `spellid`, `type` FROM `damageshieldtypes` WHERE `spellid` > 0 "
|
||||
"AND `spellid` <= %i", iMaxSpellID);
|
||||
@ -2044,3 +1915,24 @@ void SharedDatabase::SetSharedSpellsCount(uint32 shared_spells_count)
|
||||
{
|
||||
SharedDatabase::m_shared_spells_count = shared_spells_count;
|
||||
}
|
||||
|
||||
uint16 SharedDatabase::GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
|
||||
{
|
||||
const auto& l = SkillCapsRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"`class_id` = {} AND `skill_id` = {} AND `level` = {} LIMIT 1",
|
||||
class_id,
|
||||
static_cast<uint16>(skill_id),
|
||||
level
|
||||
)
|
||||
);
|
||||
|
||||
if (l.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& e = l.front();
|
||||
|
||||
return e.cap;
|
||||
}
|
||||
|
||||
@ -160,13 +160,7 @@ public:
|
||||
uint32 GetSharedItemsCount() { return m_shared_items_count; }
|
||||
uint32 GetItemsCount();
|
||||
|
||||
/**
|
||||
* skills
|
||||
*/
|
||||
void LoadSkillCaps(void *data);
|
||||
bool LoadSkillCaps(const std::string &prefix);
|
||||
uint16 GetSkillCap(uint8 Class_, EQ::skills::SkillType Skill, uint8 Level) const;
|
||||
uint8 GetTrainLevel(uint8 Class_, EQ::skills::SkillType Skill, uint8 Level) const;
|
||||
uint16 GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
|
||||
|
||||
/**
|
||||
* spells
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9267
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9268
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9043
|
||||
|
||||
#endif
|
||||
|
||||
@ -4,13 +4,11 @@ SET(shared_memory_sources
|
||||
items.cpp
|
||||
main.cpp
|
||||
spells.cpp
|
||||
skill_caps.cpp
|
||||
)
|
||||
|
||||
SET(shared_memory_headers
|
||||
items.h
|
||||
spells.h
|
||||
skill_caps.h
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(shared_memory ${shared_memory_sources} ${shared_memory_headers})
|
||||
|
||||
@ -28,7 +28,6 @@
|
||||
#include "../common/eqemu_exception.h"
|
||||
#include "../common/strings.h"
|
||||
#include "items.h"
|
||||
#include "skill_caps.h"
|
||||
#include "spells.h"
|
||||
#include "../common/content/world_content_service.h"
|
||||
#include "../common/zone_store.h"
|
||||
@ -183,7 +182,6 @@ int main(int argc, char **argv)
|
||||
bool load_all = true;
|
||||
bool load_items = false;
|
||||
bool load_loot = false;
|
||||
bool load_skill_caps = false;
|
||||
bool load_spells = false;
|
||||
|
||||
if (argc > 1) {
|
||||
@ -197,11 +195,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (strcasecmp("skill_caps", argv[i]) == 0) {
|
||||
load_skill_caps = true;
|
||||
load_all = false;
|
||||
}
|
||||
else if (strcasecmp("spells", argv[i]) == 0) {
|
||||
if (strcasecmp("spells", argv[i]) == 0) {
|
||||
load_spells = true;
|
||||
load_all = false;
|
||||
}
|
||||
@ -236,16 +230,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (load_all || load_skill_caps) {
|
||||
LogInfo("Loading skill caps");
|
||||
try {
|
||||
LoadSkillCaps(&content_db, hotfix_name);
|
||||
} catch (std::exception &ex) {
|
||||
LogError("{}", ex.what());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (load_all || load_spells) {
|
||||
LogInfo("Loading spells");
|
||||
try {
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
/* 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 "skill_caps.h"
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/shareddb.h"
|
||||
#include "../common/ipc_mutex.h"
|
||||
#include "../common/memory_mapped_file.h"
|
||||
#include "../common/eqemu_exception.h"
|
||||
#include "../common/classes.h"
|
||||
#include "../common/features.h"
|
||||
|
||||
void LoadSkillCaps(SharedDatabase *database, const std::string &prefix) {
|
||||
EQ::IPCMutex mutex("skill_caps");
|
||||
mutex.Lock();
|
||||
|
||||
uint32 class_count = Class::PLAYER_CLASS_COUNT;
|
||||
uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
|
||||
uint32 level_count = HARD_LEVEL_CAP + 1;
|
||||
uint32 size = (class_count * skill_count * level_count * sizeof(uint16));
|
||||
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string file_name = Config->SharedMemDir + prefix + std::string("skill_caps");
|
||||
EQ::MemoryMappedFile mmf(file_name, size);
|
||||
mmf.ZeroFile();
|
||||
|
||||
void *ptr = mmf.Get();
|
||||
database->LoadSkillCaps(ptr);
|
||||
mutex.Unlock();
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
/* 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_SKILL_CAPS_H
|
||||
#define __EQEMU_SHARED_MEMORY_SKILL_CAPS_H
|
||||
|
||||
#include <string>
|
||||
#include "../common/eqemu_config.h"
|
||||
|
||||
class SharedDatabase;
|
||||
void LoadSkillCaps(SharedDatabase *database, const std::string &prefix);
|
||||
|
||||
#endif
|
||||
|
||||
@ -156,6 +156,7 @@ std::vector<Reload> reload_types = {
|
||||
Reload{.command = "opcodes", .opcode = ServerOP_ReloadOpcodes, .desc = "Opcodes"},
|
||||
Reload{.command = "perl_export", .opcode = ServerOP_ReloadPerlExportSettings, .desc = "Perl Event Export Settings"},
|
||||
Reload{.command = "rules", .opcode = ServerOP_ReloadRules, .desc = "Rules"},
|
||||
Reload{.command = "skill_caps", .opcode = ServerOP_ReloadSkillCaps, .desc = "Skill Caps"},
|
||||
Reload{.command = "static", .opcode = ServerOP_ReloadStaticZoneData, .desc = "Static Zone Data"},
|
||||
Reload{.command = "tasks", .opcode = ServerOP_ReloadTasks, .desc = "Tasks"},
|
||||
Reload{.command = "titles", .opcode = ServerOP_ReloadTitles, .desc = "Titles"},
|
||||
|
||||
@ -292,10 +292,6 @@ bool WorldBoot::DatabaseLoadRoutines(int argc, char **argv)
|
||||
LogError("Error: Could not load item data. But ignoring");
|
||||
}
|
||||
|
||||
if (!content_db.LoadSkillCaps(std::string(hotfix_name))) {
|
||||
LogError("Error: Could not load skill cap data. But ignoring");
|
||||
}
|
||||
|
||||
guild_mgr.LoadGuilds();
|
||||
guild_mgr.LoadTributes();
|
||||
|
||||
|
||||
@ -1411,6 +1411,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
case ServerOP_ReloadNPCEmotes:
|
||||
case ServerOP_ReloadObjects:
|
||||
case ServerOP_ReloadPerlExportSettings:
|
||||
case ServerOP_ReloadSkillCaps:
|
||||
case ServerOP_ReloadStaticZoneData:
|
||||
case ServerOP_ReloadTitles:
|
||||
case ServerOP_ReloadTraps:
|
||||
@ -1496,11 +1497,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
LogInfo("Error: Could not load item data. But ignoring");
|
||||
}
|
||||
|
||||
LogInfo("Loading skill caps");
|
||||
if (!content_db.LoadSkillCaps(hotfix_name)) {
|
||||
LogInfo("Error: Could not load skill cap data. But ignoring");
|
||||
}
|
||||
|
||||
zoneserver_list.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -166,6 +166,7 @@ SET(zone_sources
|
||||
zone_event_scheduler.cpp
|
||||
zone_npc_factions.cpp
|
||||
zone_reload.cpp
|
||||
zone_skill_caps.cpp
|
||||
zoning.cpp
|
||||
)
|
||||
|
||||
|
||||
@ -2756,31 +2756,48 @@ void Client::CheckLanguageSkillIncrease(uint8 language_id, uint8 teacher_skill)
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::HasSkill(EQ::skills::SkillType skill_id) const {
|
||||
return((GetSkill(skill_id) > 0) && CanHaveSkill(skill_id));
|
||||
}
|
||||
|
||||
bool Client::CanHaveSkill(EQ::skills::SkillType skill_id) const {
|
||||
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == Class::Berserker && skill_id == EQ::skills::Skill1HPiercing)
|
||||
skill_id = EQ::skills::Skill2HPiercing;
|
||||
|
||||
return(content_db.GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)) > 0);
|
||||
//if you don't have it by max level, then odds are you never will?
|
||||
}
|
||||
|
||||
uint16 Client::MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const {
|
||||
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == Class::Berserker && skillid == EQ::skills::Skill1HPiercing)
|
||||
skillid = EQ::skills::Skill2HPiercing;
|
||||
|
||||
return(content_db.GetSkillCap(class_, skillid, level));
|
||||
}
|
||||
|
||||
uint8 Client::SkillTrainLevel(EQ::skills::SkillType skillid, uint16 class_)
|
||||
bool Client::HasSkill(EQ::skills::SkillType skill_id) const
|
||||
{
|
||||
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == Class::Berserker && skillid == EQ::skills::Skill1HPiercing)
|
||||
skillid = EQ::skills::Skill2HPiercing;
|
||||
return GetSkill(skill_id) > 0 && CanHaveSkill(skill_id);
|
||||
}
|
||||
|
||||
return(content_db.GetTrainLevel(class_, skillid, RuleI(Character, MaxLevel)));
|
||||
bool Client::CanHaveSkill(EQ::skills::SkillType skill_id) const
|
||||
{
|
||||
if (
|
||||
ClientVersion() < EQ::versions::ClientVersion::RoF2 &&
|
||||
class_ == Class::Berserker &&
|
||||
skill_id == EQ::skills::Skill1HPiercing
|
||||
) {
|
||||
skill_id = EQ::skills::Skill2HPiercing;
|
||||
}
|
||||
|
||||
return zone->GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)).cap > 0;
|
||||
}
|
||||
|
||||
uint16 Client::MaxSkill(EQ::skills::SkillType skill_id, uint8 class_id, uint8 level) const
|
||||
{
|
||||
if (
|
||||
ClientVersion() < EQ::versions::ClientVersion::RoF2 &&
|
||||
class_id == Class::Berserker &&
|
||||
skill_id == EQ::skills::Skill1HPiercing
|
||||
) {
|
||||
skill_id = EQ::skills::Skill2HPiercing;
|
||||
}
|
||||
|
||||
return(content_db.GetSkillCap(class_id, skill_id, level));
|
||||
}
|
||||
|
||||
uint8 Client::SkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id)
|
||||
{
|
||||
if (
|
||||
ClientVersion() < EQ::versions::ClientVersion::RoF2 &&
|
||||
class_id == Class::Berserker &&
|
||||
skill_id == EQ::skills::Skill1HPiercing
|
||||
) {
|
||||
skill_id = EQ::skills::Skill2HPiercing;
|
||||
}
|
||||
|
||||
return zone->GetTrainLevel(class_id, skill_id, RuleI(Character, MaxLevel));
|
||||
}
|
||||
|
||||
uint16 Client::GetMaxSkillAfterSpecializationRules(EQ::skills::SkillType skillid, uint16 maxSkill)
|
||||
@ -9226,6 +9243,7 @@ void Client::ShowDevToolsMenu()
|
||||
menu_reload_six += " | " + Saylink::Silent("#reload quest", "Quests");
|
||||
|
||||
menu_reload_seven += Saylink::Silent("#reload rules", "Rules");
|
||||
menu_reload_seven += " | " + Saylink::Silent("#reload skill_caps", "Skill Caps");
|
||||
menu_reload_seven += " | " + Saylink::Silent("#reload static", "Static Zone Data");
|
||||
menu_reload_seven += " | " + Saylink::Silent("#reload tasks", "Tasks");
|
||||
|
||||
@ -11353,6 +11371,16 @@ void Client::SendReloadCommandMessages() {
|
||||
).c_str()
|
||||
);
|
||||
|
||||
auto skill_caps_link = Saylink::Silent("#reload skill_caps");
|
||||
|
||||
Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Usage: {} - Reloads Skill Caps globally",
|
||||
skill_caps_link
|
||||
).c_str()
|
||||
);
|
||||
|
||||
auto static_link = Saylink::Silent("#reload static");
|
||||
|
||||
Message(
|
||||
|
||||
@ -815,9 +815,9 @@ public:
|
||||
void SetHoTT(uint32 mobid);
|
||||
void ShowSkillsWindow();
|
||||
|
||||
uint16 MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const;
|
||||
inline uint16 MaxSkill(EQ::skills::SkillType skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); }
|
||||
uint8 SkillTrainLevel(EQ::skills::SkillType skillid, uint16 class_);
|
||||
uint16 MaxSkill(EQ::skills::SkillType skill_id, uint8 class_id, uint8 level) const;
|
||||
inline uint16 MaxSkill(EQ::skills::SkillType skill_id) const { return MaxSkill(skill_id, GetClass(), GetLevel()); }
|
||||
uint8 SkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id);
|
||||
void MaxSkills();
|
||||
|
||||
void SendTradeskillSearchResults(const std::string &query, unsigned long objtype, unsigned long someid);
|
||||
|
||||
@ -34,6 +34,7 @@ void command_reload(Client *c, const Seperator *sep)
|
||||
bool is_perl_export = !strcasecmp(sep->arg[1], "perl_export");
|
||||
bool is_quest = !strcasecmp(sep->arg[1], "quest") || (is_rq_alias);
|
||||
bool is_rules = !strcasecmp(sep->arg[1], "rules");
|
||||
bool is_skill_caps = !strcasecmp(sep->arg[1], "skill_caps");
|
||||
bool is_static = !strcasecmp(sep->arg[1], "static");
|
||||
bool is_tasks = !strcasecmp(sep->arg[1], "tasks");
|
||||
bool is_titles = !strcasecmp(sep->arg[1], "titles");
|
||||
@ -66,6 +67,7 @@ void command_reload(Client *c, const Seperator *sep)
|
||||
!is_perl_export &&
|
||||
!is_quest &&
|
||||
!is_rules &&
|
||||
!is_skill_caps &&
|
||||
!is_static &&
|
||||
!is_tasks &&
|
||||
!is_titles &&
|
||||
@ -161,6 +163,9 @@ void command_reload(Client *c, const Seperator *sep)
|
||||
} else if (is_rules) {
|
||||
c->Message(Chat::White, "Attempting to reload Rules globally.");
|
||||
pack = new ServerPacket(ServerOP_ReloadRules, 0);
|
||||
} else if (is_skill_caps) {
|
||||
c->Message(Chat::White, "Attempting to reload Skill Caps globally.");
|
||||
pack = new ServerPacket(ServerOP_ReloadSkillCaps, 0);
|
||||
} else if (is_static) {
|
||||
c->Message(Chat::White, "Attempting to reload Static Zone Data globally.");
|
||||
pack = new ServerPacket(ServerOP_ReloadStaticZoneData, 0);
|
||||
|
||||
@ -372,10 +372,6 @@ int main(int argc, char **argv)
|
||||
LogError("Failed. But ignoring error and going on..");
|
||||
}
|
||||
|
||||
if (!content_db.LoadSkillCaps(std::string(hotfix_name))) {
|
||||
LogError("Loading skill caps failed!");
|
||||
return 1;
|
||||
}
|
||||
if (!database.LoadSpells(hotfix_name, &SPDAT_RECORDS, &spells)) {
|
||||
LogError("Loading spells failed!");
|
||||
return 1;
|
||||
|
||||
@ -2097,6 +2097,15 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset(), true);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ReloadSkillCaps:
|
||||
{
|
||||
if (zone && zone->IsLoaded()) {
|
||||
zone->SendReloadMessage("Skill Caps");
|
||||
zone->ReloadSkillCaps();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ServerOP_ReloadDataBucketsCache:
|
||||
{
|
||||
zone->SendReloadMessage("Data buckets cache");
|
||||
@ -3563,11 +3572,6 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
LogError("Loading items failed!");
|
||||
}
|
||||
|
||||
LogInfo("Loading skill caps");
|
||||
if (!content_db.LoadSkillCaps(std::string(hotfix_name))) {
|
||||
LogError("Loading skill caps failed!");
|
||||
}
|
||||
|
||||
LogInfo("Loading spells");
|
||||
if (!content_db.LoadSpells(hotfix_name, &SPDAT_RECORDS, &spells)) {
|
||||
LogError("Loading spells failed!");
|
||||
|
||||
@ -1177,6 +1177,8 @@ bool Zone::Init(bool is_static) {
|
||||
|
||||
LoadBaseData();
|
||||
|
||||
LoadSkillCaps();
|
||||
|
||||
//Load merchant data
|
||||
LoadMerchants();
|
||||
|
||||
|
||||
11
zone/zone.h
11
zone/zone.h
@ -46,6 +46,7 @@
|
||||
#include "../common/repositories/lootdrop_repository.h"
|
||||
#include "../common/repositories/lootdrop_entries_repository.h"
|
||||
#include "../common/repositories/base_data_repository.h"
|
||||
#include "../common/repositories/skill_caps_repository.h"
|
||||
|
||||
struct EXPModifier
|
||||
{
|
||||
@ -452,6 +453,13 @@ public:
|
||||
void LoadBaseData();
|
||||
void ReloadBaseData();
|
||||
|
||||
// Skill Caps
|
||||
inline void ClearSkillCaps() { m_skill_caps.clear(); }
|
||||
SkillCapsRepository::SkillCaps GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
|
||||
uint8 GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
|
||||
void LoadSkillCaps();
|
||||
void ReloadSkillCaps();
|
||||
|
||||
private:
|
||||
bool allow_mercs;
|
||||
bool can_bind;
|
||||
@ -515,6 +523,9 @@ private:
|
||||
|
||||
// Base Data
|
||||
std::vector<BaseDataRepository::BaseData> m_base_data = { };
|
||||
|
||||
// Skill Caps
|
||||
std::vector<SkillCapsRepository::SkillCaps> m_skill_caps = { };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
84
zone/zone_skill_caps.cpp
Normal file
84
zone/zone_skill_caps.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
#include "zone.h"
|
||||
|
||||
SkillCapsRepository::SkillCaps Zone::GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
|
||||
{
|
||||
if (!IsPlayerClass(class_id)) {
|
||||
return SkillCapsRepository::NewEntity();
|
||||
}
|
||||
|
||||
for (const auto& e : m_skill_caps) {
|
||||
if (
|
||||
e.class_id == class_id &&
|
||||
e.level == level &&
|
||||
static_cast<EQ::skills::SkillType>(e.skill_id) == skill_id
|
||||
) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
return SkillCapsRepository::NewEntity();
|
||||
}
|
||||
|
||||
uint8 Zone::GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
|
||||
{
|
||||
if (
|
||||
!IsPlayerClass(class_id) ||
|
||||
class_id > Class::PLAYER_CLASS_COUNT ||
|
||||
static_cast<uint32>(skill_id) > (EQ::skills::HIGHEST_SKILL + 1)
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8 skill_cap_max_level = (
|
||||
RuleI(Character, SkillCapMaxLevel) > 0 ?
|
||||
RuleI(Character, SkillCapMaxLevel) :
|
||||
RuleI(Character, MaxLevel)
|
||||
);
|
||||
|
||||
const uint8 max_level = level > skill_cap_max_level ? level : skill_cap_max_level;
|
||||
|
||||
for (const auto& e : m_skill_caps) {
|
||||
for (uint8 current_level = 1; current_level <= max_level; current_level++) {
|
||||
if (
|
||||
e.class_id == class_id &&
|
||||
static_cast<EQ::skills::SkillType>(e.skill_id) == skill_id &&
|
||||
e.level == current_level
|
||||
) {
|
||||
return current_level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Zone::LoadSkillCaps()
|
||||
{
|
||||
const auto& l = SkillCapsRepository::All(content_db);
|
||||
|
||||
m_skill_caps.reserve(l.size());
|
||||
|
||||
for (const auto& e : l) {
|
||||
if (
|
||||
e.level < 1 ||
|
||||
!IsPlayerClass(e.class_id) ||
|
||||
static_cast<EQ::skills::SkillType>(e.skill_id) >= EQ::skills::SkillCount
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_skill_caps.emplace_back(e);
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"Loaded [{}] Skill Cap Entr{}",
|
||||
l.size(),
|
||||
l.size() != 1 ? "ies" : "y"
|
||||
);
|
||||
}
|
||||
|
||||
void Zone::ReloadSkillCaps()
|
||||
{
|
||||
ClearSkillCaps();
|
||||
LoadSkillCaps();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user