mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-01 15:32:25 +00:00
[Feature] Add Bot/Client Specific Stat Caps
This commit is contained in:
parent
1eb89edbbd
commit
aba58172f4
@ -7188,6 +7188,21 @@ CHANGE COLUMN `field221` `caster_requirement_id` int(11) NULL DEFAULT 0 AFTER `n
|
|||||||
CHANGE COLUMN `field222` `spell_class` int(11) NULL DEFAULT 0 AFTER `caster_requirement_id`,
|
CHANGE COLUMN `field222` `spell_class` int(11) NULL DEFAULT 0 AFTER `caster_requirement_id`,
|
||||||
CHANGE COLUMN `field223` `spell_subclass` int(11) NULL DEFAULT 0 AFTER `spell_class`,
|
CHANGE COLUMN `field223` `spell_subclass` int(11) NULL DEFAULT 0 AFTER `spell_class`,
|
||||||
CHANGE COLUMN `field232` `no_remove` int(11) NOT NULL DEFAULT 0 AFTER `min_range`;
|
CHANGE COLUMN `field232` `no_remove` int(11) NOT NULL DEFAULT 0 AFTER `min_range`;
|
||||||
|
)"
|
||||||
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9329,
|
||||||
|
.description = "2025_08_20_character_stat_caps.sql",
|
||||||
|
.check = "SHOW TABLES LIKE 'character_stat_caps'",
|
||||||
|
.condition = "empty",
|
||||||
|
.match = "",
|
||||||
|
.sql = R"(
|
||||||
|
CREATE TABLE `character_stat_caps` (
|
||||||
|
`character_id` int(11) UNSIGNED NOT NULL,
|
||||||
|
`stat_id` tinyint(3) UNSIGNED NULL,
|
||||||
|
`stat_cap` int(11) NOT NULL DEFAULT -1,
|
||||||
|
PRIMARY KEY (`character_id`, `stat_id`)
|
||||||
|
)
|
||||||
)"
|
)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2122,7 +2122,21 @@ WHERE NOT EXISTS
|
|||||||
FROM spells_new
|
FROM spells_new
|
||||||
WHERE bot_spells_entries.spell_id = spells_new.id);
|
WHERE bot_spells_entries.spell_id = spells_new.id);
|
||||||
)",
|
)",
|
||||||
}
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9055,
|
||||||
|
.description = "08_20_2025_bot_stat_caps.sql",
|
||||||
|
.check = "SHOW TABLES LIKE 'bot_stat_caps'",
|
||||||
|
.condition = "empty",
|
||||||
|
.match = "",
|
||||||
|
.sql = R"(
|
||||||
|
CREATE TABLE `bot_stat_caps` (
|
||||||
|
`bot_id` int(11) UNSIGNED NOT NULL,
|
||||||
|
`stat_id` tinyint(3) UNSIGNED NULL,
|
||||||
|
`stat_cap` int(11) NOT NULL DEFAULT -1,
|
||||||
|
PRIMARY KEY (`bot_id`, `stat_id`)
|
||||||
|
)"
|
||||||
|
},
|
||||||
// -- template; copy/paste this when you need to create a new entry
|
// -- template; copy/paste this when you need to create a new entry
|
||||||
// ManifestEntry{
|
// ManifestEntry{
|
||||||
// .version = 9228,
|
// .version = 9228,
|
||||||
|
|||||||
@ -69,6 +69,7 @@ namespace DatabaseSchema {
|
|||||||
{"character_potionbelt", "id"},
|
{"character_potionbelt", "id"},
|
||||||
{"character_skills", "id"},
|
{"character_skills", "id"},
|
||||||
{"character_spells", "id"},
|
{"character_spells", "id"},
|
||||||
|
{"character_stat_caps", "character_id"},
|
||||||
{"character_stats_record", "character_id"},
|
{"character_stats_record", "character_id"},
|
||||||
{"character_task_timers", "character_id"},
|
{"character_task_timers", "character_id"},
|
||||||
{"character_tasks", "charid"},
|
{"character_tasks", "charid"},
|
||||||
@ -144,6 +145,7 @@ namespace DatabaseSchema {
|
|||||||
"character_potionbelt",
|
"character_potionbelt",
|
||||||
"character_skills",
|
"character_skills",
|
||||||
"character_spells",
|
"character_spells",
|
||||||
|
"character_stat_caps",
|
||||||
"character_stats_record",
|
"character_stats_record",
|
||||||
"character_task_timers",
|
"character_task_timers",
|
||||||
"character_tasks",
|
"character_tasks",
|
||||||
|
|||||||
@ -919,4 +919,29 @@ namespace PetType {
|
|||||||
bool IsValid(uint8 pet_type);
|
bool IsValid(uint8 pet_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace StatCap {
|
||||||
|
constexpr uint8 Accuracy = 0;
|
||||||
|
constexpr uint8 Attack = 1;
|
||||||
|
constexpr uint8 Avoidance = 2;
|
||||||
|
constexpr uint8 Clairvoyance = 3;
|
||||||
|
constexpr uint8 CombatEffects = 4;
|
||||||
|
constexpr uint8 DamageShield = 5;
|
||||||
|
constexpr uint8 DOTShielding = 6;
|
||||||
|
constexpr uint8 DSMitigation = 7;
|
||||||
|
constexpr uint8 EnduranceRegen = 8;
|
||||||
|
constexpr uint8 ExtraDamage = 9;
|
||||||
|
constexpr uint8 Haste = 10;
|
||||||
|
constexpr uint8 HasteV3 = 11;
|
||||||
|
constexpr uint8 HealAmount = 12;
|
||||||
|
constexpr uint8 HealthRegen = 13;
|
||||||
|
constexpr uint8 ManaRegen = 14;
|
||||||
|
constexpr uint8 QuiverHaste = 15;
|
||||||
|
constexpr uint8 Shielding = 16;
|
||||||
|
constexpr uint8 SpellDamage = 17;
|
||||||
|
constexpr uint8 SpellShielding = 18;
|
||||||
|
constexpr uint8 Stat = 19;
|
||||||
|
constexpr uint8 Strikethrough = 20;
|
||||||
|
constexpr uint8 StunResist = 21;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /*COMMON_EMU_CONSTANTS_H*/
|
#endif /*COMMON_EMU_CONSTANTS_H*/
|
||||||
|
|||||||
404
common/repositories/base/base_bot_stat_caps_repository.h
Normal file
404
common/repositories/base/base_bot_stat_caps_repository.h
Normal file
@ -0,0 +1,404 @@
|
|||||||
|
/**
|
||||||
|
* DO NOT MODIFY THIS FILE
|
||||||
|
*
|
||||||
|
* This repository was automatically generated and is NOT to be modified directly.
|
||||||
|
* Any repository modifications are meant to be made to the repository extending the base.
|
||||||
|
* Any modifications to base repositories are to be made by the generator only
|
||||||
|
*
|
||||||
|
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||||
|
* @docs https://docs.eqemu.io/developer/repositories
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EQEMU_BASE_BOT_STAT_CAPS_REPOSITORY_H
|
||||||
|
#define EQEMU_BASE_BOT_STAT_CAPS_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "../../database.h"
|
||||||
|
#include "../../strings.h"
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
class BaseBotStatCapsRepository {
|
||||||
|
public:
|
||||||
|
struct BotStatCaps {
|
||||||
|
uint32_t bot_id;
|
||||||
|
uint8_t stat_id;
|
||||||
|
int32_t stat_cap;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string PrimaryKey()
|
||||||
|
{
|
||||||
|
return std::string("bot_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> Columns()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"bot_id",
|
||||||
|
"stat_id",
|
||||||
|
"stat_cap",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> SelectColumns()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"bot_id",
|
||||||
|
"stat_id",
|
||||||
|
"stat_cap",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string ColumnsRaw()
|
||||||
|
{
|
||||||
|
return std::string(Strings::Implode(", ", Columns()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string SelectColumnsRaw()
|
||||||
|
{
|
||||||
|
return std::string(Strings::Implode(", ", SelectColumns()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string TableName()
|
||||||
|
{
|
||||||
|
return std::string("bot_stat_caps");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseSelect()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"SELECT {} FROM {}",
|
||||||
|
SelectColumnsRaw(),
|
||||||
|
TableName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseInsert()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"INSERT INTO {} ({}) ",
|
||||||
|
TableName(),
|
||||||
|
ColumnsRaw()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BotStatCaps NewEntity()
|
||||||
|
{
|
||||||
|
BotStatCaps e{};
|
||||||
|
|
||||||
|
e.bot_id = 0;
|
||||||
|
e.stat_id = 0;
|
||||||
|
e.stat_cap = -1;
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BotStatCaps GetBotStatCaps(
|
||||||
|
const std::vector<BotStatCaps> &bot_stat_capss,
|
||||||
|
int bot_stat_caps_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (auto &bot_stat_caps : bot_stat_capss) {
|
||||||
|
if (bot_stat_caps.bot_id == bot_stat_caps_id) {
|
||||||
|
return bot_stat_caps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
static BotStatCaps FindOne(
|
||||||
|
Database& db,
|
||||||
|
int bot_stat_caps_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} WHERE {} = {} LIMIT 1",
|
||||||
|
BaseSelect(),
|
||||||
|
PrimaryKey(),
|
||||||
|
bot_stat_caps_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto row = results.begin();
|
||||||
|
if (results.RowCount() == 1) {
|
||||||
|
BotStatCaps e{};
|
||||||
|
|
||||||
|
e.bot_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||||
|
e.stat_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
|
e.stat_cap = row[2] ? static_cast<int32_t>(atoi(row[2])) : -1;
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DeleteOne(
|
||||||
|
Database& db,
|
||||||
|
int bot_stat_caps_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"DELETE FROM {} WHERE {} = {}",
|
||||||
|
TableName(),
|
||||||
|
PrimaryKey(),
|
||||||
|
bot_stat_caps_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int UpdateOne(
|
||||||
|
Database& db,
|
||||||
|
const BotStatCaps &e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
auto columns = Columns();
|
||||||
|
|
||||||
|
v.push_back(columns[0] + " = " + std::to_string(e.bot_id));
|
||||||
|
v.push_back(columns[1] + " = " + std::to_string(e.stat_id));
|
||||||
|
v.push_back(columns[2] + " = " + std::to_string(e.stat_cap));
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"UPDATE {} SET {} WHERE {} = {}",
|
||||||
|
TableName(),
|
||||||
|
Strings::Implode(", ", v),
|
||||||
|
PrimaryKey(),
|
||||||
|
e.bot_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BotStatCaps InsertOne(
|
||||||
|
Database& db,
|
||||||
|
BotStatCaps e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.bot_id));
|
||||||
|
v.push_back(std::to_string(e.stat_id));
|
||||||
|
v.push_back(std::to_string(e.stat_cap));
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES ({})",
|
||||||
|
BaseInsert(),
|
||||||
|
Strings::Implode(",", v)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (results.Success()) {
|
||||||
|
e.bot_id = results.LastInsertedID();
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
e = NewEntity();
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int InsertMany(
|
||||||
|
Database& db,
|
||||||
|
const std::vector<BotStatCaps> &entries
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> insert_chunks;
|
||||||
|
|
||||||
|
for (auto &e: entries) {
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.bot_id));
|
||||||
|
v.push_back(std::to_string(e.stat_id));
|
||||||
|
v.push_back(std::to_string(e.stat_cap));
|
||||||
|
|
||||||
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES {}",
|
||||||
|
BaseInsert(),
|
||||||
|
Strings::Implode(",", insert_chunks)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<BotStatCaps> All(Database& db)
|
||||||
|
{
|
||||||
|
std::vector<BotStatCaps> all_entries;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{}",
|
||||||
|
BaseSelect()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.reserve(results.RowCount());
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
BotStatCaps e{};
|
||||||
|
|
||||||
|
e.bot_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||||
|
e.stat_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
|
e.stat_cap = row[2] ? static_cast<int32_t>(atoi(row[2])) : -1;
|
||||||
|
|
||||||
|
all_entries.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<BotStatCaps> GetWhere(Database& db, const std::string &where_filter)
|
||||||
|
{
|
||||||
|
std::vector<BotStatCaps> all_entries;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} WHERE {}",
|
||||||
|
BaseSelect(),
|
||||||
|
where_filter
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.reserve(results.RowCount());
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
BotStatCaps e{};
|
||||||
|
|
||||||
|
e.bot_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||||
|
e.stat_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
|
e.stat_cap = row[2] ? static_cast<int32_t>(atoi(row[2])) : -1;
|
||||||
|
|
||||||
|
all_entries.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DeleteWhere(Database& db, const std::string &where_filter)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"DELETE FROM {} WHERE {}",
|
||||||
|
TableName(),
|
||||||
|
where_filter
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Truncate(Database& db)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"TRUNCATE TABLE {}",
|
||||||
|
TableName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64 GetMaxId(Database& db)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"SELECT COALESCE(MAX({}), 0) FROM {}",
|
||||||
|
PrimaryKey(),
|
||||||
|
TableName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64 Count(Database& db, const std::string &where_filter = "")
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"SELECT COUNT(*) FROM {} {}",
|
||||||
|
TableName(),
|
||||||
|
(where_filter.empty() ? "" : "WHERE " + where_filter)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseReplace()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"REPLACE INTO {} ({}) ",
|
||||||
|
TableName(),
|
||||||
|
ColumnsRaw()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ReplaceOne(
|
||||||
|
Database& db,
|
||||||
|
const BotStatCaps &e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.bot_id));
|
||||||
|
v.push_back(std::to_string(e.stat_id));
|
||||||
|
v.push_back(std::to_string(e.stat_cap));
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES ({})",
|
||||||
|
BaseReplace(),
|
||||||
|
Strings::Implode(",", v)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ReplaceMany(
|
||||||
|
Database& db,
|
||||||
|
const std::vector<BotStatCaps> &entries
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> insert_chunks;
|
||||||
|
|
||||||
|
for (auto &e: entries) {
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.bot_id));
|
||||||
|
v.push_back(std::to_string(e.stat_id));
|
||||||
|
v.push_back(std::to_string(e.stat_cap));
|
||||||
|
|
||||||
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES {}",
|
||||||
|
BaseReplace(),
|
||||||
|
Strings::Implode(",", insert_chunks)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //EQEMU_BASE_BOT_STAT_CAPS_REPOSITORY_H
|
||||||
404
common/repositories/base/base_character_stat_caps_repository.h
Normal file
404
common/repositories/base/base_character_stat_caps_repository.h
Normal file
@ -0,0 +1,404 @@
|
|||||||
|
/**
|
||||||
|
* DO NOT MODIFY THIS FILE
|
||||||
|
*
|
||||||
|
* This repository was automatically generated and is NOT to be modified directly.
|
||||||
|
* Any repository modifications are meant to be made to the repository extending the base.
|
||||||
|
* Any modifications to base repositories are to be made by the generator only
|
||||||
|
*
|
||||||
|
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||||
|
* @docs https://docs.eqemu.io/developer/repositories
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EQEMU_BASE_CHARACTER_STAT_CAPS_REPOSITORY_H
|
||||||
|
#define EQEMU_BASE_CHARACTER_STAT_CAPS_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "../../database.h"
|
||||||
|
#include "../../strings.h"
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
class BaseCharacterStatCapsRepository {
|
||||||
|
public:
|
||||||
|
struct CharacterStatCaps {
|
||||||
|
uint32_t character_id;
|
||||||
|
uint8_t stat_id;
|
||||||
|
int32_t stat_cap;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string PrimaryKey()
|
||||||
|
{
|
||||||
|
return std::string("character_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> Columns()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"character_id",
|
||||||
|
"stat_id",
|
||||||
|
"stat_cap",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> SelectColumns()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"character_id",
|
||||||
|
"stat_id",
|
||||||
|
"stat_cap",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string ColumnsRaw()
|
||||||
|
{
|
||||||
|
return std::string(Strings::Implode(", ", Columns()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string SelectColumnsRaw()
|
||||||
|
{
|
||||||
|
return std::string(Strings::Implode(", ", SelectColumns()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string TableName()
|
||||||
|
{
|
||||||
|
return std::string("character_stat_caps");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseSelect()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"SELECT {} FROM {}",
|
||||||
|
SelectColumnsRaw(),
|
||||||
|
TableName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseInsert()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"INSERT INTO {} ({}) ",
|
||||||
|
TableName(),
|
||||||
|
ColumnsRaw()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CharacterStatCaps NewEntity()
|
||||||
|
{
|
||||||
|
CharacterStatCaps e{};
|
||||||
|
|
||||||
|
e.character_id = 0;
|
||||||
|
e.stat_id = 0;
|
||||||
|
e.stat_cap = -1;
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CharacterStatCaps GetCharacterStatCaps(
|
||||||
|
const std::vector<CharacterStatCaps> &character_stat_capss,
|
||||||
|
int character_stat_caps_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (auto &character_stat_caps : character_stat_capss) {
|
||||||
|
if (character_stat_caps.character_id == character_stat_caps_id) {
|
||||||
|
return character_stat_caps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
static CharacterStatCaps FindOne(
|
||||||
|
Database& db,
|
||||||
|
int character_stat_caps_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} WHERE {} = {} LIMIT 1",
|
||||||
|
BaseSelect(),
|
||||||
|
PrimaryKey(),
|
||||||
|
character_stat_caps_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto row = results.begin();
|
||||||
|
if (results.RowCount() == 1) {
|
||||||
|
CharacterStatCaps e{};
|
||||||
|
|
||||||
|
e.character_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||||
|
e.stat_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
|
e.stat_cap = row[2] ? static_cast<int32_t>(atoi(row[2])) : -1;
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DeleteOne(
|
||||||
|
Database& db,
|
||||||
|
int character_stat_caps_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"DELETE FROM {} WHERE {} = {}",
|
||||||
|
TableName(),
|
||||||
|
PrimaryKey(),
|
||||||
|
character_stat_caps_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int UpdateOne(
|
||||||
|
Database& db,
|
||||||
|
const CharacterStatCaps &e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
auto columns = Columns();
|
||||||
|
|
||||||
|
v.push_back(columns[0] + " = " + std::to_string(e.character_id));
|
||||||
|
v.push_back(columns[1] + " = " + std::to_string(e.stat_id));
|
||||||
|
v.push_back(columns[2] + " = " + std::to_string(e.stat_cap));
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"UPDATE {} SET {} WHERE {} = {}",
|
||||||
|
TableName(),
|
||||||
|
Strings::Implode(", ", v),
|
||||||
|
PrimaryKey(),
|
||||||
|
e.character_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CharacterStatCaps InsertOne(
|
||||||
|
Database& db,
|
||||||
|
CharacterStatCaps e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.character_id));
|
||||||
|
v.push_back(std::to_string(e.stat_id));
|
||||||
|
v.push_back(std::to_string(e.stat_cap));
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES ({})",
|
||||||
|
BaseInsert(),
|
||||||
|
Strings::Implode(",", v)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (results.Success()) {
|
||||||
|
e.character_id = results.LastInsertedID();
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
e = NewEntity();
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int InsertMany(
|
||||||
|
Database& db,
|
||||||
|
const std::vector<CharacterStatCaps> &entries
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> insert_chunks;
|
||||||
|
|
||||||
|
for (auto &e: entries) {
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.character_id));
|
||||||
|
v.push_back(std::to_string(e.stat_id));
|
||||||
|
v.push_back(std::to_string(e.stat_cap));
|
||||||
|
|
||||||
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES {}",
|
||||||
|
BaseInsert(),
|
||||||
|
Strings::Implode(",", insert_chunks)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<CharacterStatCaps> All(Database& db)
|
||||||
|
{
|
||||||
|
std::vector<CharacterStatCaps> all_entries;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{}",
|
||||||
|
BaseSelect()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.reserve(results.RowCount());
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
CharacterStatCaps e{};
|
||||||
|
|
||||||
|
e.character_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||||
|
e.stat_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
|
e.stat_cap = row[2] ? static_cast<int32_t>(atoi(row[2])) : -1;
|
||||||
|
|
||||||
|
all_entries.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<CharacterStatCaps> GetWhere(Database& db, const std::string &where_filter)
|
||||||
|
{
|
||||||
|
std::vector<CharacterStatCaps> all_entries;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} WHERE {}",
|
||||||
|
BaseSelect(),
|
||||||
|
where_filter
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.reserve(results.RowCount());
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
CharacterStatCaps e{};
|
||||||
|
|
||||||
|
e.character_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||||
|
e.stat_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
|
e.stat_cap = row[2] ? static_cast<int32_t>(atoi(row[2])) : -1;
|
||||||
|
|
||||||
|
all_entries.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DeleteWhere(Database& db, const std::string &where_filter)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"DELETE FROM {} WHERE {}",
|
||||||
|
TableName(),
|
||||||
|
where_filter
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Truncate(Database& db)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"TRUNCATE TABLE {}",
|
||||||
|
TableName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64 GetMaxId(Database& db)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"SELECT COALESCE(MAX({}), 0) FROM {}",
|
||||||
|
PrimaryKey(),
|
||||||
|
TableName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64 Count(Database& db, const std::string &where_filter = "")
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"SELECT COUNT(*) FROM {} {}",
|
||||||
|
TableName(),
|
||||||
|
(where_filter.empty() ? "" : "WHERE " + where_filter)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseReplace()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"REPLACE INTO {} ({}) ",
|
||||||
|
TableName(),
|
||||||
|
ColumnsRaw()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ReplaceOne(
|
||||||
|
Database& db,
|
||||||
|
const CharacterStatCaps &e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.character_id));
|
||||||
|
v.push_back(std::to_string(e.stat_id));
|
||||||
|
v.push_back(std::to_string(e.stat_cap));
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES ({})",
|
||||||
|
BaseReplace(),
|
||||||
|
Strings::Implode(",", v)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ReplaceMany(
|
||||||
|
Database& db,
|
||||||
|
const std::vector<CharacterStatCaps> &entries
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> insert_chunks;
|
||||||
|
|
||||||
|
for (auto &e: entries) {
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.character_id));
|
||||||
|
v.push_back(std::to_string(e.stat_id));
|
||||||
|
v.push_back(std::to_string(e.stat_cap));
|
||||||
|
|
||||||
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES {}",
|
||||||
|
BaseReplace(),
|
||||||
|
Strings::Implode(",", insert_chunks)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //EQEMU_BASE_CHARACTER_STAT_CAPS_REPOSITORY_H
|
||||||
50
common/repositories/bot_stat_caps_repository.h
Normal file
50
common/repositories/bot_stat_caps_repository.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef EQEMU_BOT_STAT_CAPS_REPOSITORY_H
|
||||||
|
#define EQEMU_BOT_STAT_CAPS_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "../database.h"
|
||||||
|
#include "../strings.h"
|
||||||
|
#include "base/base_bot_stat_caps_repository.h"
|
||||||
|
|
||||||
|
class BotStatCapsRepository: public BaseBotStatCapsRepository {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file was auto generated and can be modified and extended upon
|
||||||
|
*
|
||||||
|
* Base repository methods are automatically
|
||||||
|
* generated in the "base" version of this repository. The base repository
|
||||||
|
* is immutable and to be left untouched, while methods in this class
|
||||||
|
* are used as extension methods for more specific persistence-layer
|
||||||
|
* accessors or mutators.
|
||||||
|
*
|
||||||
|
* Base Methods (Subject to be expanded upon in time)
|
||||||
|
*
|
||||||
|
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
||||||
|
*
|
||||||
|
* InsertOne
|
||||||
|
* UpdateOne
|
||||||
|
* DeleteOne
|
||||||
|
* FindOne
|
||||||
|
* GetWhere(std::string where_filter)
|
||||||
|
* DeleteWhere(std::string where_filter)
|
||||||
|
* InsertMany
|
||||||
|
* All
|
||||||
|
*
|
||||||
|
* Example custom methods in a repository
|
||||||
|
*
|
||||||
|
* BotStatCapsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||||
|
* BotStatCapsRepository::GetWhereNeverExpires()
|
||||||
|
* BotStatCapsRepository::GetWhereXAndY()
|
||||||
|
* BotStatCapsRepository::DeleteWhereXAndY()
|
||||||
|
*
|
||||||
|
* Most of the above could be covered by base methods, but if you as a developer
|
||||||
|
* find yourself re-using logic for other parts of the code, its best to just make a
|
||||||
|
* method that can be re-used easily elsewhere especially if it can use a base repository
|
||||||
|
* method and encapsulate filters there
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Custom extended repository methods here
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //EQEMU_BOT_STAT_CAPS_REPOSITORY_H
|
||||||
50
common/repositories/character_stat_caps_repository.h
Normal file
50
common/repositories/character_stat_caps_repository.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef EQEMU_CHARACTER_STAT_CAPS_REPOSITORY_H
|
||||||
|
#define EQEMU_CHARACTER_STAT_CAPS_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "../database.h"
|
||||||
|
#include "../strings.h"
|
||||||
|
#include "base/base_character_stat_caps_repository.h"
|
||||||
|
|
||||||
|
class CharacterStatCapsRepository: public BaseCharacterStatCapsRepository {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file was auto generated and can be modified and extended upon
|
||||||
|
*
|
||||||
|
* Base repository methods are automatically
|
||||||
|
* generated in the "base" version of this repository. The base repository
|
||||||
|
* is immutable and to be left untouched, while methods in this class
|
||||||
|
* are used as extension methods for more specific persistence-layer
|
||||||
|
* accessors or mutators.
|
||||||
|
*
|
||||||
|
* Base Methods (Subject to be expanded upon in time)
|
||||||
|
*
|
||||||
|
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
||||||
|
*
|
||||||
|
* InsertOne
|
||||||
|
* UpdateOne
|
||||||
|
* DeleteOne
|
||||||
|
* FindOne
|
||||||
|
* GetWhere(std::string where_filter)
|
||||||
|
* DeleteWhere(std::string where_filter)
|
||||||
|
* InsertMany
|
||||||
|
* All
|
||||||
|
*
|
||||||
|
* Example custom methods in a repository
|
||||||
|
*
|
||||||
|
* CharacterStatCapsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||||
|
* CharacterStatCapsRepository::GetWhereNeverExpires()
|
||||||
|
* CharacterStatCapsRepository::GetWhereXAndY()
|
||||||
|
* CharacterStatCapsRepository::DeleteWhereXAndY()
|
||||||
|
*
|
||||||
|
* Most of the above could be covered by base methods, but if you as a developer
|
||||||
|
* find yourself re-using logic for other parts of the code, its best to just make a
|
||||||
|
* method that can be re-used easily elsewhere especially if it can use a base repository
|
||||||
|
* method and encapsulate filters there
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Custom extended repository methods here
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //EQEMU_CHARACTER_STAT_CAPS_REPOSITORY_H
|
||||||
@ -42,8 +42,8 @@
|
|||||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CURRENT_BINARY_DATABASE_VERSION 9328
|
#define CURRENT_BINARY_DATABASE_VERSION 9329
|
||||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9054
|
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9055
|
||||||
#define CUSTOM_BINARY_DATABASE_VERSION 0
|
#define CUSTOM_BINARY_DATABASE_VERSION 0
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -6701,7 +6701,7 @@ void Client::SetAttackTimer()
|
|||||||
if (ItemToUse && ItemToUse->ItemType == EQ::item::ItemTypeBow) {
|
if (ItemToUse && ItemToUse->ItemType == EQ::item::ItemTypeBow) {
|
||||||
// Live actually had a bug here where they would return the non-modified attack speed
|
// Live actually had a bug here where they would return the non-modified attack speed
|
||||||
// rather than the cap ...
|
// rather than the cap ...
|
||||||
speed = std::max(speed - GetQuiverHaste(speed), RuleI(Combat, QuiverHasteCap));
|
speed = std::max(speed - GetQuiverHaste(speed), GetStatCap(StatCap::QuiverHaste));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (RuleB(Spells, Jun182014HundredHandsRevamp))
|
if (RuleB(Spells, Jun182014HundredHandsRevamp))
|
||||||
|
|||||||
156
zone/bonuses.cpp
156
zone/bonuses.cpp
@ -246,12 +246,22 @@ void Mob::ProcessItemCaps()
|
|||||||
|
|
||||||
itembonuses.ATK = std::min(itembonuses.ATK, CalcItemATKCap());
|
itembonuses.ATK = std::min(itembonuses.ATK, CalcItemATKCap());
|
||||||
|
|
||||||
if (IsOfClientBotMerc() && itembonuses.SpellDmg > RuleI(Character, ItemSpellDmgCap)) {
|
int spell_damage_cap = (
|
||||||
itembonuses.SpellDmg = RuleI(Character, ItemSpellDmgCap);
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::SpellDamage) :
|
||||||
|
RuleI(Character, ItemSpellDmgCap)
|
||||||
|
);
|
||||||
|
if (IsOfClientBotMerc() && itembonuses.SpellDmg > spell_damage_cap) {
|
||||||
|
itembonuses.SpellDmg = spell_damage_cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsOfClientBotMerc() && itembonuses.HealAmt > RuleI(Character, ItemHealAmtCap)) {
|
int heal_amount_cap = (
|
||||||
itembonuses.HealAmt = RuleI(Character, ItemHealAmtCap);
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::HealAmount) :
|
||||||
|
RuleI(Character, ItemHealAmtCap)
|
||||||
|
);
|
||||||
|
if (IsOfClientBotMerc() && itembonuses.HealAmt > heal_amount_cap) {
|
||||||
|
itembonuses.HealAmt = heal_amount_cap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,33 +361,139 @@ void Mob::AddItemBonuses(const EQ::ItemInstance* inst, StatBonuses* b, bool is_a
|
|||||||
b->ManaRegen += CalcItemBonus(item->ManaRegen);
|
b->ManaRegen += CalcItemBonus(item->ManaRegen);
|
||||||
b->EnduranceRegen += CalcItemBonus(item->EnduranceRegen);
|
b->EnduranceRegen += CalcItemBonus(item->EnduranceRegen);
|
||||||
|
|
||||||
|
int accuracy_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Accuracy) :
|
||||||
|
RuleI(Character, ItemAccuracyCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int attack_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Attack) :
|
||||||
|
RuleI(Character, ItemATKCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int avoidance_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Avoidance) :
|
||||||
|
RuleI(Character, ItemAvoidanceCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int clairvoyance_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Clairvoyance) :
|
||||||
|
RuleI(Character, ItemClairvoyanceCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int combat_effects_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::CombatEffects) :
|
||||||
|
RuleI(Character, ItemCombatEffectsCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int damage_shield_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::DamageShield) :
|
||||||
|
RuleI(Character, ItemDamageShieldCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int dot_shielding_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::DOTShielding) :
|
||||||
|
RuleI(Character, ItemDoTShieldingCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int dsmitigation_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::DSMitigation) :
|
||||||
|
RuleI(Character, ItemDSMitigationCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int heal_amount_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::HealAmount) :
|
||||||
|
RuleI(Character, ItemHealAmtCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int shielding_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Shielding) :
|
||||||
|
RuleI(Character, ItemShieldingCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int spell_damage_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::SpellDamage) :
|
||||||
|
RuleI(Character, ItemSpellDmgCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int spell_shielding_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::SpellShielding) :
|
||||||
|
RuleI(Character, ItemSpellShieldingCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int strikethrough_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Strikethrough) :
|
||||||
|
RuleI(Character, ItemStrikethroughCap)
|
||||||
|
);
|
||||||
|
|
||||||
|
int stun_resist_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::StunResist) :
|
||||||
|
RuleI(Character, ItemStunResistCap)
|
||||||
|
);
|
||||||
|
|
||||||
// These have rule-configured caps.
|
// These have rule-configured caps.
|
||||||
b->ATK = CalcCappedItemBonus(b->ATK, item->Attack, RuleI(Character, ItemATKCap) + itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap);
|
b->ATK = CalcCappedItemBonus(
|
||||||
b->DamageShield = CalcCappedItemBonus(b->DamageShield, item->DamageShield, RuleI(Character, ItemDamageShieldCap));
|
b->ATK,
|
||||||
b->SpellShield = CalcCappedItemBonus(b->SpellShield, item->SpellShield, RuleI(Character, ItemSpellShieldingCap));
|
item->Attack,
|
||||||
b->MeleeMitigation = CalcCappedItemBonus(b->MeleeMitigation, item->Shielding, RuleI(Character, ItemShieldingCap));
|
(
|
||||||
b->StunResist = CalcCappedItemBonus(b->StunResist, item->StunResist, RuleI(Character, ItemStunResistCap));
|
attack_cap +
|
||||||
b->StrikeThrough = CalcCappedItemBonus(b->StrikeThrough, item->StrikeThrough, RuleI(Character, ItemStrikethroughCap));
|
itembonuses.ItemATKCap +
|
||||||
b->AvoidMeleeChance = CalcCappedItemBonus(b->AvoidMeleeChance, item->Avoidance, RuleI(Character, ItemAvoidanceCap));
|
spellbonuses.ItemATKCap +
|
||||||
b->HitChance = CalcCappedItemBonus(b->HitChance, item->Accuracy, RuleI(Character, ItemAccuracyCap));
|
aabonuses.ItemATKCap
|
||||||
b->ProcChance = CalcCappedItemBonus(b->ProcChance, item->CombatEffects, RuleI(Character, ItemCombatEffectsCap));
|
)
|
||||||
b->DoTShielding = CalcCappedItemBonus(b->DoTShielding, item->DotShielding, RuleI(Character, ItemDoTShieldingCap));
|
);
|
||||||
b->HealAmt = CalcCappedItemBonus(b->HealAmt, item->HealAmt, RuleI(Character, ItemHealAmtCap));
|
b->DamageShield = CalcCappedItemBonus(b->DamageShield, item->DamageShield, damage_shield_cap);
|
||||||
b->SpellDmg = CalcCappedItemBonus(b->SpellDmg, item->SpellDmg, RuleI(Character, ItemSpellDmgCap));
|
b->SpellShield = CalcCappedItemBonus(b->SpellShield, item->SpellShield, spell_shielding_cap);
|
||||||
b->Clairvoyance = CalcCappedItemBonus(b->Clairvoyance, item->Clairvoyance, RuleI(Character, ItemClairvoyanceCap));
|
b->MeleeMitigation = CalcCappedItemBonus(b->MeleeMitigation, item->Shielding, shielding_cap);
|
||||||
b->DSMitigation = CalcCappedItemBonus(b->DSMitigation, item->DSMitigation, RuleI(Character, ItemDSMitigationCap));
|
b->StunResist = CalcCappedItemBonus(b->StunResist, item->StunResist, stun_resist_cap);
|
||||||
|
b->StrikeThrough = CalcCappedItemBonus(b->StrikeThrough, item->StrikeThrough, strikethrough_cap);
|
||||||
|
b->AvoidMeleeChance = CalcCappedItemBonus(b->AvoidMeleeChance, item->Avoidance, avoidance_cap);
|
||||||
|
b->HitChance = CalcCappedItemBonus(b->HitChance, item->Accuracy, accuracy_cap);
|
||||||
|
b->ProcChance = CalcCappedItemBonus(b->ProcChance, item->CombatEffects, combat_effects_cap);
|
||||||
|
b->DoTShielding = CalcCappedItemBonus(b->DoTShielding, item->DotShielding, dot_shielding_cap);
|
||||||
|
b->HealAmt = CalcCappedItemBonus(b->HealAmt, item->HealAmt, heal_amount_cap);
|
||||||
|
b->SpellDmg = CalcCappedItemBonus(b->SpellDmg, item->SpellDmg, spell_damage_cap);
|
||||||
|
b->Clairvoyance = CalcCappedItemBonus(b->Clairvoyance, item->Clairvoyance, clairvoyance_cap);
|
||||||
|
b->DSMitigation = CalcCappedItemBonus(b->DSMitigation, item->DSMitigation, dsmitigation_cap);
|
||||||
|
|
||||||
if (b->haste < item->Haste) {
|
if (b->haste < item->Haste) {
|
||||||
b->haste = item->Haste;
|
b->haste = item->Haste;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->ExtraDmgAmt != 0 && item->ExtraDmgSkill <= EQ::skills::HIGHEST_SKILL) {
|
if (item->ExtraDmgAmt != 0 && item->ExtraDmgSkill <= EQ::skills::HIGHEST_SKILL) {
|
||||||
|
int extra_damage_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::ExtraDamage) :
|
||||||
|
RuleI(Character, ItemExtraDmgCap)
|
||||||
|
);
|
||||||
if (item->ExtraDmgSkill == ALL_SKILLS) {
|
if (item->ExtraDmgSkill == ALL_SKILLS) {
|
||||||
for (const auto &skill_id: EQ::skills::GetExtraDamageSkills()) {
|
for (const auto &skill_id: EQ::skills::GetExtraDamageSkills()) {
|
||||||
b->SkillDamageAmount[skill_id] = CalcCappedItemBonus(b->SkillDamageAmount[skill_id], item->ExtraDmgAmt, RuleI(Character, ItemExtraDmgCap));
|
b->SkillDamageAmount[skill_id] = CalcCappedItemBonus(
|
||||||
|
b->SkillDamageAmount[skill_id],
|
||||||
|
item->ExtraDmgAmt,
|
||||||
|
extra_damage_cap
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
b->SkillDamageAmount[item->ExtraDmgSkill] = CalcCappedItemBonus(b->SkillDamageAmount[item->ExtraDmgSkill], item->ExtraDmgAmt, RuleI(Character, ItemExtraDmgCap));
|
b->SkillDamageAmount[item->ExtraDmgSkill] = CalcCappedItemBonus(
|
||||||
|
b->SkillDamageAmount[item->ExtraDmgSkill],
|
||||||
|
item->ExtraDmgAmt,
|
||||||
|
extra_damage_cap
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -268,6 +268,8 @@ Bot::Bot(
|
|||||||
LoadDefaultBotSettings();
|
LoadDefaultBotSettings();
|
||||||
database.botdb.LoadBotSettings(this);
|
database.botdb.LoadBotSettings(this);
|
||||||
|
|
||||||
|
database.LoadStatCaps(this);
|
||||||
|
|
||||||
if (RuleB(Bots, AllowBotBlockedBuffs)) {
|
if (RuleB(Bots, AllowBotBlockedBuffs)) {
|
||||||
bot_blocked_buffs.clear();
|
bot_blocked_buffs.clear();
|
||||||
database.botdb.LoadBotBlockedBuffs(this);
|
database.botdb.LoadBotBlockedBuffs(this);
|
||||||
@ -1420,6 +1422,7 @@ bool Bot::Save()
|
|||||||
database.botdb.SaveTimers(this);
|
database.botdb.SaveTimers(this);
|
||||||
database.botdb.SaveStance(this);
|
database.botdb.SaveStance(this);
|
||||||
database.botdb.SaveBotSettings(this);
|
database.botdb.SaveBotSettings(this);
|
||||||
|
database.SaveStatCaps(this);
|
||||||
|
|
||||||
if (RuleB(Bots, AllowBotBlockedBuffs)) {
|
if (RuleB(Bots, AllowBotBlockedBuffs)) {
|
||||||
database.botdb.SaveBotBlockedBuffs(this);
|
database.botdb.SaveBotBlockedBuffs(this);
|
||||||
|
|||||||
@ -1210,7 +1210,6 @@ private:
|
|||||||
bool _hasLoS;
|
bool _hasLoS;
|
||||||
bool _commandedSpell;
|
bool _commandedSpell;
|
||||||
bool _pullingSpell;
|
bool _pullingSpell;
|
||||||
|
|
||||||
bool _illusionBlock;
|
bool _illusionBlock;
|
||||||
std::vector<BotSpellSettings> m_bot_spell_settings;
|
std::vector<BotSpellSettings> m_bot_spell_settings;
|
||||||
std::vector<Mob*> _spell_target_list;
|
std::vector<Mob*> _spell_target_list;
|
||||||
|
|||||||
@ -1103,6 +1103,8 @@ bool Client::Save(uint8 iCommitNow) {
|
|||||||
|
|
||||||
database.SaveCharacterEXPModifier(this);
|
database.SaveCharacterEXPModifier(this);
|
||||||
|
|
||||||
|
database.SaveStatCaps(this);
|
||||||
|
|
||||||
if (RuleB(Bots, Enabled)) {
|
if (RuleB(Bots, Enabled)) {
|
||||||
database.botdb.SaveBotSettings(this);
|
database.botdb.SaveBotSettings(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,23 +32,24 @@
|
|||||||
|
|
||||||
int32 Client::GetMaxStat() const
|
int32 Client::GetMaxStat() const
|
||||||
{
|
{
|
||||||
if ((RuleI(Character, StatCap)) > 0) {
|
int character_cap = GetStatCap(StatCap::Stat);
|
||||||
return (RuleI(Character, StatCap));
|
if (character_cap > 0) {
|
||||||
|
return character_cap;
|
||||||
}
|
}
|
||||||
int level = GetLevel();
|
|
||||||
int32 base = 0;
|
uint8 level = GetLevel();
|
||||||
|
int base = 0;
|
||||||
|
|
||||||
if (level < 61) {
|
if (level < 61) {
|
||||||
base = 255;
|
base = 255;
|
||||||
}
|
} else if (ClientVersion() >= EQ::versions::ClientVersion::SoF) {
|
||||||
else if (ClientVersion() >= EQ::versions::ClientVersion::SoF) {
|
|
||||||
base = 255 + 5 * (level - 60);
|
base = 255 + 5 * (level - 60);
|
||||||
}
|
} else if (level < 71) {
|
||||||
else if (level < 71) {
|
|
||||||
base = 255 + 5 * (level - 60);
|
base = 255 + 5 * (level - 60);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
base = 330;
|
base = 330;
|
||||||
}
|
}
|
||||||
|
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,7 +301,7 @@ int64 Client::CalcHPRegen(bool bCombat)
|
|||||||
|
|
||||||
int64 Client::CalcHPRegenCap()
|
int64 Client::CalcHPRegenCap()
|
||||||
{
|
{
|
||||||
int64 cap = RuleI(Character, ItemHealthRegenCap);
|
int64 cap = GetStatCap(StatCap::HealthRegen);
|
||||||
if (GetLevel() > 60) {
|
if (GetLevel() > 60) {
|
||||||
cap = std::max(cap, static_cast<int64>(GetLevel() - 30)); // if the rule is set greater than normal I guess
|
cap = std::max(cap, static_cast<int64>(GetLevel() - 30)); // if the rule is set greater than normal I guess
|
||||||
}
|
}
|
||||||
@ -717,7 +718,7 @@ int64 Client::CalcManaRegen(bool bCombat)
|
|||||||
|
|
||||||
int64 Client::CalcManaRegenCap()
|
int64 Client::CalcManaRegenCap()
|
||||||
{
|
{
|
||||||
int64 cap = RuleI(Character, ItemManaRegenCap) + aabonuses.ItemManaRegenCap + itembonuses.ItemManaRegenCap + spellbonuses.ItemManaRegenCap;
|
int64 cap = GetStatCap(StatCap::ManaRegen) + aabonuses.ItemManaRegenCap + itembonuses.ItemManaRegenCap + spellbonuses.ItemManaRegenCap;
|
||||||
return (cap * RuleI(Character, ManaRegenMultiplier) / 100);
|
return (cap * RuleI(Character, ManaRegenMultiplier) / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -976,7 +977,7 @@ int Client::CalcHaste()
|
|||||||
}
|
}
|
||||||
// 60+ 100, 51-59 85, 1-50 level+25
|
// 60+ 100, 51-59 85, 1-50 level+25
|
||||||
if (level > 59 || RuleB(Character, IgnoreLevelBasedHasteCaps)) { // 60+
|
if (level > 59 || RuleB(Character, IgnoreLevelBasedHasteCaps)) { // 60+
|
||||||
cap = RuleI(Character, HasteCap);
|
cap = GetStatCap(StatCap::Haste);
|
||||||
}
|
}
|
||||||
else if (level > 50) { // 51-59
|
else if (level > 50) { // 51-59
|
||||||
cap = 85;
|
cap = 85;
|
||||||
@ -989,7 +990,7 @@ int Client::CalcHaste()
|
|||||||
}
|
}
|
||||||
// 51+ 25 (despite there being higher spells...), 1-50 10
|
// 51+ 25 (despite there being higher spells...), 1-50 10
|
||||||
if (level > 50 || RuleB(Character, IgnoreLevelBasedHasteCaps)) { // 51+
|
if (level > 50 || RuleB(Character, IgnoreLevelBasedHasteCaps)) { // 51+
|
||||||
cap = RuleI(Character, Hastev3Cap);
|
cap = GetStatCap(StatCap::HasteV3);
|
||||||
if (spellbonuses.hastetype3 > cap) {
|
if (spellbonuses.hastetype3 > cap) {
|
||||||
h += cap;
|
h += cap;
|
||||||
} else {
|
} else {
|
||||||
@ -1745,13 +1746,13 @@ int64 Client::CalcEnduranceRegen(bool bCombat)
|
|||||||
|
|
||||||
int64 Client::CalcEnduranceRegenCap()
|
int64 Client::CalcEnduranceRegenCap()
|
||||||
{
|
{
|
||||||
int64 cap = RuleI(Character, ItemEnduranceRegenCap) + aabonuses.ItemEnduranceRegenCap + itembonuses.ItemEnduranceRegenCap + spellbonuses.ItemEnduranceRegenCap;
|
int64 cap = GetStatCap(StatCap::EnduranceRegen) + aabonuses.ItemEnduranceRegenCap + itembonuses.ItemEnduranceRegenCap + spellbonuses.ItemEnduranceRegenCap;
|
||||||
return (cap * RuleI(Character, EnduranceRegenMultiplier) / 100);
|
return (cap * RuleI(Character, EnduranceRegenMultiplier) / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Client::CalcItemATKCap()
|
int32 Client::CalcItemATKCap()
|
||||||
{
|
{
|
||||||
int cap = RuleI(Character, ItemATKCap) + itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap;
|
int cap = GetStatCap(StatCap::Attack) + itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap;
|
||||||
return cap;
|
return cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1386,6 +1386,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
|||||||
database.LoadCharacterTribute(this); /* Load CharacterTribute */
|
database.LoadCharacterTribute(this); /* Load CharacterTribute */
|
||||||
database.LoadCharacterEXPModifier(this); /* Load Character EXP Modifier */
|
database.LoadCharacterEXPModifier(this); /* Load Character EXP Modifier */
|
||||||
database.LoadCharacterTitleSets(this); /* Load Character Title Sets */
|
database.LoadCharacterTitleSets(this); /* Load Character Title Sets */
|
||||||
|
database.LoadStatCaps(this); /* Load Character Stat Caps */
|
||||||
|
|
||||||
// this pattern is strange
|
// this pattern is strange
|
||||||
// this is remnants of the old way of doing things
|
// this is remnants of the old way of doing things
|
||||||
|
|||||||
@ -664,6 +664,18 @@ void Lua_Bot::RaidGroupSay(const char* message) {
|
|||||||
self->RaidGroupSay(message);
|
self->RaidGroupSay(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Lua_Bot::GetStatCap(uint8 stat_id)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return self->GetStatCap(stat_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Bot::SetStatCap(uint8 stat_id, int stat_cap)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->SetStatCap(stat_id, stat_cap, true);
|
||||||
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_bot() {
|
luabind::scope lua_register_bot() {
|
||||||
return luabind::class_<Lua_Bot, Lua_Mob>("Bot")
|
return luabind::class_<Lua_Bot, Lua_Mob>("Bot")
|
||||||
.def(luabind::constructor<>())
|
.def(luabind::constructor<>())
|
||||||
@ -747,6 +759,7 @@ luabind::scope lua_register_bot() {
|
|||||||
.def("GetSpellDamage", (int(Lua_Bot::*)(void))&Lua_Bot::GetSpellDamage)
|
.def("GetSpellDamage", (int(Lua_Bot::*)(void))&Lua_Bot::GetSpellDamage)
|
||||||
.def("GetSpellRecastTimer", (uint32(Lua_Bot::*)())&Lua_Bot::GetSpellRecastTimer)
|
.def("GetSpellRecastTimer", (uint32(Lua_Bot::*)())&Lua_Bot::GetSpellRecastTimer)
|
||||||
.def("GetSpellRecastTimer", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetSpellRecastTimer)
|
.def("GetSpellRecastTimer", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetSpellRecastTimer)
|
||||||
|
.def("GetStatCap", (int(Lua_Bot::*)(uint8))&Lua_Bot::GetStatCap)
|
||||||
.def("HasAugmentEquippedByID", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasAugmentEquippedByID)
|
.def("HasAugmentEquippedByID", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasAugmentEquippedByID)
|
||||||
.def("HasBotItem", (int16(Lua_Bot::*)(uint32))&Lua_Bot::HasBotItem)
|
.def("HasBotItem", (int16(Lua_Bot::*)(uint32))&Lua_Bot::HasBotItem)
|
||||||
.def("HasBotSpellEntry", (bool(Lua_Bot::*)(uint16))&Lua_Bot::HasBotSpellEntry)
|
.def("HasBotSpellEntry", (bool(Lua_Bot::*)(uint16))&Lua_Bot::HasBotSpellEntry)
|
||||||
@ -783,6 +796,7 @@ luabind::scope lua_register_bot() {
|
|||||||
.def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int,bool,bool))&Lua_Bot::SetSpellDurationRaid)
|
.def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int,bool,bool))&Lua_Bot::SetSpellDurationRaid)
|
||||||
.def("SetSpellRecastTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::SetSpellRecastTimer)
|
.def("SetSpellRecastTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::SetSpellRecastTimer)
|
||||||
.def("SetSpellRecastTimer", (void(Lua_Bot::*)(uint16, uint32))&Lua_Bot::SetSpellRecastTimer)
|
.def("SetSpellRecastTimer", (void(Lua_Bot::*)(uint16, uint32))&Lua_Bot::SetSpellRecastTimer)
|
||||||
|
.def("SetStatCap", (void(Lua_Bot::*)(uint8,int))&Lua_Bot::SetStatCap)
|
||||||
.def("SendPayload", (void(Lua_Bot::*)(int))&Lua_Bot::SendPayload)
|
.def("SendPayload", (void(Lua_Bot::*)(int))&Lua_Bot::SendPayload)
|
||||||
.def("SendPayload", (void(Lua_Bot::*)(int,std::string))&Lua_Bot::SendPayload)
|
.def("SendPayload", (void(Lua_Bot::*)(int,std::string))&Lua_Bot::SendPayload)
|
||||||
.def("Signal", (void(Lua_Bot::*)(int))&Lua_Bot::Signal)
|
.def("Signal", (void(Lua_Bot::*)(int))&Lua_Bot::Signal)
|
||||||
|
|||||||
@ -126,6 +126,8 @@ public:
|
|||||||
void SetItemReuseTimer(uint32 item_id, uint32 reuse_timer);
|
void SetItemReuseTimer(uint32 item_id, uint32 reuse_timer);
|
||||||
void SetSpellRecastTimer(uint16 spell_id);
|
void SetSpellRecastTimer(uint16 spell_id);
|
||||||
void SetSpellRecastTimer(uint16 spell_id, uint32 reuse_timer);
|
void SetSpellRecastTimer(uint16 spell_id, uint32 reuse_timer);
|
||||||
|
int GetStatCap(uint8 stat_id);
|
||||||
|
void SetStatCap(uint8 stat_id, int stat_cap);
|
||||||
|
|
||||||
uint32 CountAugmentEquippedByID(uint32 item_id);
|
uint32 CountAugmentEquippedByID(uint32 item_id);
|
||||||
uint32 CountItemEquippedByID(uint32 item_id);
|
uint32 CountItemEquippedByID(uint32 item_id);
|
||||||
|
|||||||
@ -3624,6 +3624,18 @@ luabind::object Lua_Client::GetKeyRing(lua_State* L)
|
|||||||
return lua_table;
|
return lua_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Lua_Client::GetStatCap(uint8 stat_id)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return self->GetStatCap(stat_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Client::SetStatCap(uint8 stat_id, int stat_cap)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->SetStatCap(stat_id, stat_cap, true);
|
||||||
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_client() {
|
luabind::scope lua_register_client() {
|
||||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||||
.def(luabind::constructor<>())
|
.def(luabind::constructor<>())
|
||||||
@ -3898,6 +3910,7 @@ luabind::scope lua_register_client() {
|
|||||||
.def("GetSpellDamage", (int(Lua_Client::*)(void))&Lua_Client::GetSpellDamage)
|
.def("GetSpellDamage", (int(Lua_Client::*)(void))&Lua_Client::GetSpellDamage)
|
||||||
.def("GetSpellIDByBookSlot", (uint32(Lua_Client::*)(int))&Lua_Client::GetSpellIDByBookSlot)
|
.def("GetSpellIDByBookSlot", (uint32(Lua_Client::*)(int))&Lua_Client::GetSpellIDByBookSlot)
|
||||||
.def("GetSpentAA", (int(Lua_Client::*)(void))&Lua_Client::GetSpentAA)
|
.def("GetSpentAA", (int(Lua_Client::*)(void))&Lua_Client::GetSpentAA)
|
||||||
|
.def("GetStatCap", (int(Lua_Client::*)(uint8))&Lua_Client::GetStatCap)
|
||||||
.def("GetStartZone", (int(Lua_Client::*)(void))&Lua_Client::GetStartZone)
|
.def("GetStartZone", (int(Lua_Client::*)(void))&Lua_Client::GetStartZone)
|
||||||
.def("GetTargetRingX", (float(Lua_Client::*)(void))&Lua_Client::GetTargetRingX)
|
.def("GetTargetRingX", (float(Lua_Client::*)(void))&Lua_Client::GetTargetRingX)
|
||||||
.def("GetTargetRingY", (float(Lua_Client::*)(void))&Lua_Client::GetTargetRingY)
|
.def("GetTargetRingY", (float(Lua_Client::*)(void))&Lua_Client::GetTargetRingY)
|
||||||
@ -4163,6 +4176,7 @@ luabind::scope lua_register_client() {
|
|||||||
.def("SetStartZone", (void(Lua_Client::*)(int,float))&Lua_Client::SetStartZone)
|
.def("SetStartZone", (void(Lua_Client::*)(int,float))&Lua_Client::SetStartZone)
|
||||||
.def("SetStartZone", (void(Lua_Client::*)(int,float,float))&Lua_Client::SetStartZone)
|
.def("SetStartZone", (void(Lua_Client::*)(int,float,float))&Lua_Client::SetStartZone)
|
||||||
.def("SetStartZone", (void(Lua_Client::*)(int,float,float,float))&Lua_Client::SetStartZone)
|
.def("SetStartZone", (void(Lua_Client::*)(int,float,float,float))&Lua_Client::SetStartZone)
|
||||||
|
.def("SetStatCap", (void(Lua_Client::*)(uint8,int))&Lua_Client::SetStatCap)
|
||||||
.def("SetStats", (void(Lua_Client::*)(int,int))&Lua_Client::SetStats)
|
.def("SetStats", (void(Lua_Client::*)(int,int))&Lua_Client::SetStats)
|
||||||
.def("SetThirst", (void(Lua_Client::*)(int))&Lua_Client::SetThirst)
|
.def("SetThirst", (void(Lua_Client::*)(int))&Lua_Client::SetThirst)
|
||||||
.def("SetTint", (void(Lua_Client::*)(int,uint32))&Lua_Client::SetTint)
|
.def("SetTint", (void(Lua_Client::*)(int,uint32))&Lua_Client::SetTint)
|
||||||
|
|||||||
@ -607,6 +607,8 @@ public:
|
|||||||
bool RemoveAAPoints(uint32 points);
|
bool RemoveAAPoints(uint32 points);
|
||||||
bool RemoveAlternateCurrencyValue(uint32 currency_id, uint32 amount);
|
bool RemoveAlternateCurrencyValue(uint32 currency_id, uint32 amount);
|
||||||
bool AreTasksCompleted(luabind::object task_ids);
|
bool AreTasksCompleted(luabind::object task_ids);
|
||||||
|
int GetStatCap(uint8 stat_id);
|
||||||
|
void SetStatCap(uint8 stat_id, int stat_cap);
|
||||||
|
|
||||||
void DialogueWindow(std::string markdown);
|
void DialogueWindow(std::string markdown);
|
||||||
|
|
||||||
|
|||||||
195
zone/mob.cpp
195
zone/mob.cpp
@ -22,7 +22,9 @@
|
|||||||
#include "../common/misc_functions.h"
|
#include "../common/misc_functions.h"
|
||||||
|
|
||||||
#include "../common/repositories/bot_data_repository.h"
|
#include "../common/repositories/bot_data_repository.h"
|
||||||
|
#include "../common/repositories/bot_stat_caps_repository.h"
|
||||||
#include "../common/repositories/character_data_repository.h"
|
#include "../common/repositories/character_data_repository.h"
|
||||||
|
#include "../common/repositories/character_stat_caps_repository.h"
|
||||||
|
|
||||||
#include "../common/data_bucket.h"
|
#include "../common/data_bucket.h"
|
||||||
#include "quest_parser_collection.h"
|
#include "quest_parser_collection.h"
|
||||||
@ -2059,10 +2061,20 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
for (auto mod2_row_counter = 0; mod2_row_counter < mod2_rows; mod2_row_counter++) {
|
for (auto mod2_row_counter = 0; mod2_row_counter < mod2_rows; mod2_row_counter++) {
|
||||||
switch (mod2_row_counter) {
|
switch (mod2_row_counter) {
|
||||||
case 0: {
|
case 0: {
|
||||||
|
int avoidance_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Avoidance) :
|
||||||
|
RuleI(Character, ItemAvoidanceCap)
|
||||||
|
);
|
||||||
|
int combat_effects_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::CombatEffects) :
|
||||||
|
RuleI(Character, ItemCombatEffectsCap)
|
||||||
|
);
|
||||||
mod2a_name = "Avoidance";
|
mod2a_name = "Avoidance";
|
||||||
mod2b_name = "Combat Effects";
|
mod2b_name = "Combat Effects";
|
||||||
mod2a_cap = Strings::Commify(RuleI(Character, ItemAvoidanceCap));
|
mod2a_cap = Strings::Commify(avoidance_cap);
|
||||||
mod2b_cap = Strings::Commify(RuleI(Character, ItemCombatEffectsCap));
|
mod2b_cap = Strings::Commify(combat_effects_cap);
|
||||||
|
|
||||||
if (IsBot()) {
|
if (IsBot()) {
|
||||||
mod2a = Strings::Commify(CastToBot()->GetAvoidance());
|
mod2a = Strings::Commify(CastToBot()->GetAvoidance());
|
||||||
@ -2079,10 +2091,20 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1: {
|
case 1: {
|
||||||
|
int accuracy_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Accuracy) :
|
||||||
|
RuleI(Character, ItemAccuracyCap)
|
||||||
|
);
|
||||||
|
int strikethrough_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Strikethrough) :
|
||||||
|
RuleI(Character, ItemStrikethroughCap)
|
||||||
|
);
|
||||||
mod2a_name = "Accuracy";
|
mod2a_name = "Accuracy";
|
||||||
mod2b_name = "Strikethrough";
|
mod2b_name = "Strikethrough";
|
||||||
mod2a_cap = Strings::Commify(RuleI(Character, ItemAccuracyCap));
|
mod2a_cap = Strings::Commify(accuracy_cap);
|
||||||
mod2b_cap = Strings::Commify(RuleI(Character, ItemStrikethroughCap));
|
mod2b_cap = Strings::Commify(strikethrough_cap);
|
||||||
|
|
||||||
if (IsBot()) {
|
if (IsBot()) {
|
||||||
mod2a = Strings::Commify(CastToBot()->GetAccuracy());
|
mod2a = Strings::Commify(CastToBot()->GetAccuracy());
|
||||||
@ -2099,10 +2121,20 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: {
|
case 2: {
|
||||||
|
int shielding_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Shielding) :
|
||||||
|
RuleI(Character, ItemShieldingCap)
|
||||||
|
);
|
||||||
|
int spell_shielding_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::SpellShielding) :
|
||||||
|
RuleI(Character, ItemSpellShieldingCap)
|
||||||
|
);
|
||||||
mod2a_name = "Shielding";
|
mod2a_name = "Shielding";
|
||||||
mod2b_name = "Spell Shielding";
|
mod2b_name = "Spell Shielding";
|
||||||
mod2a_cap = Strings::Commify(RuleI(Character, ItemShieldingCap));
|
mod2a_cap = Strings::Commify(shielding_cap);
|
||||||
mod2b_cap = Strings::Commify(RuleI(Character, ItemSpellShieldingCap));
|
mod2b_cap = Strings::Commify(spell_shielding_cap);
|
||||||
|
|
||||||
if (IsBot()) {
|
if (IsBot()) {
|
||||||
mod2a = Strings::Commify(CastToBot()->GetShielding());
|
mod2a = Strings::Commify(CastToBot()->GetShielding());
|
||||||
@ -2120,10 +2152,20 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3: {
|
case 3: {
|
||||||
|
int dot_shielding_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::DOTShielding) :
|
||||||
|
RuleI(Character, ItemDoTShieldingCap)
|
||||||
|
);
|
||||||
|
int stun_resist_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::StunResist) :
|
||||||
|
RuleI(Character, ItemStunResistCap)
|
||||||
|
);
|
||||||
mod2a_name = "Stun Resist";
|
mod2a_name = "Stun Resist";
|
||||||
mod2b_name = "DOT Shielding";
|
mod2b_name = "DOT Shielding";
|
||||||
mod2a_cap = Strings::Commify(RuleI(Character, ItemStunResistCap));
|
mod2a_cap = Strings::Commify(stun_resist_cap);
|
||||||
mod2b_cap = Strings::Commify(RuleI(Character, ItemDoTShieldingCap));
|
mod2b_cap = Strings::Commify(dot_shielding_cap);
|
||||||
|
|
||||||
if (IsBot()) {
|
if (IsBot()) {
|
||||||
mod2a = Strings::Commify(CastToBot()->GetStunResist());
|
mod2a = Strings::Commify(CastToBot()->GetStunResist());
|
||||||
@ -2359,6 +2401,11 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
|
|
||||||
final_string += DialogueWindow::Break(1);
|
final_string += DialogueWindow::Break(1);
|
||||||
|
|
||||||
|
int attack_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Attack) :
|
||||||
|
RuleI(Character, ItemATKCap)
|
||||||
|
);
|
||||||
// Attack 2
|
// Attack 2
|
||||||
final_string += fmt::format(
|
final_string += fmt::format(
|
||||||
"Offense: {}{}{}{}",
|
"Offense: {}{}{}{}",
|
||||||
@ -2368,7 +2415,7 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
fmt::format(
|
fmt::format(
|
||||||
" | Item: {} / {} | Used: {}",
|
" | Item: {} / {} | Used: {}",
|
||||||
Strings::Commify(itembonuses.ATK),
|
Strings::Commify(itembonuses.ATK),
|
||||||
Strings::Commify(RuleI(Character, ItemATKCap)),
|
Strings::Commify(attack_cap),
|
||||||
Strings::Commify(static_cast<int>(itembonuses.ATK * 1.342))
|
Strings::Commify(static_cast<int>(itembonuses.ATK * 1.342))
|
||||||
) :
|
) :
|
||||||
""
|
""
|
||||||
@ -2415,6 +2462,11 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
|
|
||||||
final_string += DialogueWindow::CenterMessage("Haste");
|
final_string += DialogueWindow::CenterMessage("Haste");
|
||||||
|
|
||||||
|
int haste_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Haste) :
|
||||||
|
RuleI(Character, HasteCap)
|
||||||
|
);
|
||||||
// Haste Table
|
// Haste Table
|
||||||
const auto& haste_table = DialogueWindow::Table(
|
const auto& haste_table = DialogueWindow::Table(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -2433,7 +2485,7 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
fmt::format(
|
fmt::format(
|
||||||
"{} ({})",
|
"{} ({})",
|
||||||
IsClient() ? Strings::Commify(CastToClient()->GetHaste()) : Strings::Commify(GetHaste()),
|
IsClient() ? Strings::Commify(CastToClient()->GetHaste()) : Strings::Commify(GetHaste()),
|
||||||
Strings::Commify(RuleI(Character, HasteCap))
|
Strings::Commify(haste_cap)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -2468,26 +2520,41 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
|
|
||||||
// Heal Amount
|
// Heal Amount
|
||||||
if (GetHealAmt()) {
|
if (GetHealAmt()) {
|
||||||
|
int cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::HealAmount) :
|
||||||
|
RuleI(Character, ItemHealAmtCap)
|
||||||
|
);
|
||||||
final_string += fmt::format(
|
final_string += fmt::format(
|
||||||
"Heal Amount: {} / {}{}",
|
"Heal Amount: {} / {}{}",
|
||||||
Strings::Commify(GetHealAmt()),
|
Strings::Commify(GetHealAmt()),
|
||||||
Strings::Commify(RuleI(Character, ItemHealAmtCap)),
|
Strings::Commify(cap),
|
||||||
DialogueWindow::Break(1)
|
DialogueWindow::Break(1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heal Amount
|
// Spell Damage
|
||||||
if (GetSpellDmg()) {
|
if (GetSpellDmg()) {
|
||||||
|
int cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::SpellDamage) :
|
||||||
|
RuleI(Character, ItemSpellDmgCap)
|
||||||
|
);
|
||||||
final_string += fmt::format(
|
final_string += fmt::format(
|
||||||
"Spell Damage: {} / {}{}",
|
"Spell Damage: {} / {}{}",
|
||||||
Strings::Commify(GetSpellDmg()),
|
Strings::Commify(GetSpellDmg()),
|
||||||
Strings::Commify(RuleI(Character, ItemSpellDmgCap)),
|
Strings::Commify(cap),
|
||||||
DialogueWindow::Break(1)
|
DialogueWindow::Break(1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Damage Shield
|
// Damage Shield
|
||||||
if (itembonuses.DamageShield || spellbonuses.DamageShield) {
|
if (itembonuses.DamageShield || spellbonuses.DamageShield) {
|
||||||
|
int cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::DamageShield) :
|
||||||
|
RuleI(Character, ItemDamageShieldCap)
|
||||||
|
);
|
||||||
final_string += fmt::format(
|
final_string += fmt::format(
|
||||||
"Damage Shield: {}{}{}{}",
|
"Damage Shield: {}{}{}{}",
|
||||||
Strings::Commify(itembonuses.DamageShield + spellbonuses.DamageShield),
|
Strings::Commify(itembonuses.DamageShield + spellbonuses.DamageShield),
|
||||||
@ -2501,7 +2568,7 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
fmt::format(
|
fmt::format(
|
||||||
" | Item: {} / {}",
|
" | Item: {} / {}",
|
||||||
Strings::Commify(itembonuses.DamageShield),
|
Strings::Commify(itembonuses.DamageShield),
|
||||||
Strings::Commify(RuleI(Character, ItemDamageShieldCap))
|
Strings::Commify(cap)
|
||||||
) :
|
) :
|
||||||
""
|
""
|
||||||
),
|
),
|
||||||
@ -2512,10 +2579,15 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
// Clairvoyance
|
// Clairvoyance
|
||||||
const auto clairvoyance = IsBot() ? CastToBot()->GetClair() : CastToClient()->GetClair();
|
const auto clairvoyance = IsBot() ? CastToBot()->GetClair() : CastToClient()->GetClair();
|
||||||
if (clairvoyance) {
|
if (clairvoyance) {
|
||||||
|
int cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Clairvoyance) :
|
||||||
|
RuleI(Character, ItemClairvoyanceCap)
|
||||||
|
);
|
||||||
final_string += fmt::format(
|
final_string += fmt::format(
|
||||||
"Clairvoyance: {} / {}{}",
|
"Clairvoyance: {} / {}{}",
|
||||||
Strings::Commify(clairvoyance),
|
Strings::Commify(clairvoyance),
|
||||||
Strings::Commify(RuleI(Character, ItemClairvoyanceCap)),
|
Strings::Commify(cap),
|
||||||
DialogueWindow::Break(1)
|
DialogueWindow::Break(1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -2523,10 +2595,15 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
// Damage Shield Mitigation
|
// Damage Shield Mitigation
|
||||||
const auto ds_mitigation = IsBot() ? CastToBot()->GetDSMit() : CastToClient()->GetDSMit();
|
const auto ds_mitigation = IsBot() ? CastToBot()->GetDSMit() : CastToClient()->GetDSMit();
|
||||||
if (ds_mitigation) {
|
if (ds_mitigation) {
|
||||||
|
int cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::DSMitigation) :
|
||||||
|
RuleI(Character, ItemDSMitigationCap)
|
||||||
|
);
|
||||||
final_string += fmt::format(
|
final_string += fmt::format(
|
||||||
"DS Mitigation: {} / {}{}",
|
"DS Mitigation: {} / {}{}",
|
||||||
Strings::Commify(ds_mitigation),
|
Strings::Commify(ds_mitigation),
|
||||||
Strings::Commify(RuleI(Character, ItemDSMitigationCap)),
|
Strings::Commify(cap),
|
||||||
DialogueWindow::Break(1)
|
DialogueWindow::Break(1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -2555,6 +2632,12 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
final_string += faction_item_string;
|
final_string += faction_item_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int damage_shield_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::DamageShield) :
|
||||||
|
RuleI(Character, ItemDamageShieldCap)
|
||||||
|
);
|
||||||
|
|
||||||
if (use_window) {
|
if (use_window) {
|
||||||
if (final_string.size() < 4096) {
|
if (final_string.size() < 4096) {
|
||||||
const uint32 popup_buttons = (c->ClientVersion() < EQ::versions::ClientVersion::SoD) ? 0 : 1;
|
const uint32 popup_buttons = (c->ClientVersion() < EQ::versions::ClientVersion::SoD) ? 0 : 1;
|
||||||
@ -2596,7 +2679,7 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
GetRaceIDName(GetRace()),
|
GetRaceIDName(GetRace()),
|
||||||
GetRace(),
|
GetRace(),
|
||||||
IsBot() ? Strings::Commify(CastToBot()->GetDS()) : Strings::Commify(CastToClient()->GetDS()),
|
IsBot() ? Strings::Commify(CastToBot()->GetDS()) : Strings::Commify(CastToClient()->GetDS()),
|
||||||
Strings::Commify(RuleI(Character, ItemDamageShieldCap)),
|
Strings::Commify(damage_shield_cap),
|
||||||
GetSize(),
|
GetSize(),
|
||||||
GetRunspeed(),
|
GetRunspeed(),
|
||||||
IsBot() ? static_cast<float>(CastToBot()->CalcCurrentWeight()) / 10.0f : static_cast<float>(CastToClient()->CalcCurrentWeight()) / 10.0f,
|
IsBot() ? static_cast<float>(CastToBot()->CalcCurrentWeight()) / 10.0f : static_cast<float>(CastToClient()->CalcCurrentWeight()) / 10.0f,
|
||||||
@ -2694,18 +2777,23 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
"Attack: {} Item and Spell Attack: {}/{} Server Side Attack: {}",
|
"Attack: {} Item and Spell Attack: {}/{} Server Side Attack: {}",
|
||||||
IsBot() ? Strings::Commify(CastToBot()->GetTotalATK()) : Strings::Commify(CastToClient()->GetTotalATK()),
|
IsBot() ? Strings::Commify(CastToBot()->GetTotalATK()) : Strings::Commify(CastToClient()->GetTotalATK()),
|
||||||
Strings::Commify(GetATKBonus()),
|
Strings::Commify(GetATKBonus()),
|
||||||
Strings::Commify(RuleI(Character, ItemATKCap)),
|
Strings::Commify(attack_cap),
|
||||||
Strings::Commify(GetATK())
|
Strings::Commify(GetATK())
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
|
|
||||||
if ((IsClient() && CastToClient()->GetHaste()) || (!IsClient() && GetHaste())) {
|
if ((IsClient() && CastToClient()->GetHaste()) || (!IsClient() && GetHaste())) {
|
||||||
|
int haste_cap = (
|
||||||
|
IsOfClientBot() ?
|
||||||
|
GetStatCap(StatCap::Haste) :
|
||||||
|
RuleI(Character, HasteCap)
|
||||||
|
);
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::White,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"Haste: {}/{} (Item: {} + Spell: {} + Over: {})",
|
"Haste: {}/{} (Item: {} + Spell: {} + Over: {})",
|
||||||
IsClient() ? Strings::Commify(CastToClient()->GetHaste()) : Strings::Commify(GetHaste()),
|
IsClient() ? Strings::Commify(CastToClient()->GetHaste()) : Strings::Commify(GetHaste()),
|
||||||
Strings::Commify(RuleI(Character, HasteCap)),
|
Strings::Commify(haste_cap),
|
||||||
Strings::Commify(itembonuses.haste),
|
Strings::Commify(itembonuses.haste),
|
||||||
Strings::Commify(spellbonuses.haste + spellbonuses.hastetype2),
|
Strings::Commify(spellbonuses.haste + spellbonuses.hastetype2),
|
||||||
Strings::Commify(spellbonuses.hastetype3 + extra_haste)
|
Strings::Commify(spellbonuses.hastetype3 + extra_haste)
|
||||||
@ -8793,3 +8881,72 @@ bool Mob::LoadDataBucketsCache()
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Mob::GetStatCap(uint8 stat_id) const
|
||||||
|
{
|
||||||
|
if (HasStatCap(stat_id)) {
|
||||||
|
return m_stat_caps.at(stat_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const std::map<uint8, int> default_caps = {
|
||||||
|
{ StatCap::Accuracy, RuleI(Character, ItemAccuracyCap) },
|
||||||
|
{ StatCap::Attack, RuleI(Character, ItemATKCap) },
|
||||||
|
{ StatCap::Avoidance, RuleI(Character, ItemAvoidanceCap) },
|
||||||
|
{ StatCap::Clairvoyance, RuleI(Character, ItemClairvoyanceCap) },
|
||||||
|
{ StatCap::CombatEffects, RuleI(Character, ItemCombatEffectsCap) },
|
||||||
|
{ StatCap::DamageShield, RuleI(Character, ItemDamageShieldCap) },
|
||||||
|
{ StatCap::DOTShielding, RuleI(Character, ItemDoTShieldingCap) },
|
||||||
|
{ StatCap::DSMitigation, RuleI(Character, ItemDSMitigationCap) },
|
||||||
|
{ StatCap::EnduranceRegen, RuleI(Character, ItemEnduranceRegenCap) },
|
||||||
|
{ StatCap::ExtraDamage, RuleI(Character, ItemExtraDmgCap) },
|
||||||
|
{ StatCap::Haste, RuleI(Character, HasteCap) },
|
||||||
|
{ StatCap::HasteV3, RuleI(Character, Hastev3Cap) },
|
||||||
|
{ StatCap::HealAmount, RuleI(Character, ItemHealAmtCap) },
|
||||||
|
{ StatCap::HealthRegen, RuleI(Character, ItemHealthRegenCap) },
|
||||||
|
{ StatCap::ManaRegen, RuleI(Character, ItemManaRegenCap) },
|
||||||
|
{ StatCap::QuiverHaste, RuleI(Combat, QuiverHasteCap) },
|
||||||
|
{ StatCap::Shielding, RuleI(Character, ItemShieldingCap) },
|
||||||
|
{ StatCap::SpellDamage, RuleI(Character, ItemSpellDmgCap) },
|
||||||
|
{ StatCap::SpellShielding, RuleI(Character, ItemSpellShieldingCap) },
|
||||||
|
{ StatCap::Stat, RuleI(Character, StatCap) },
|
||||||
|
{ StatCap::Strikethrough, RuleI(Character, ItemStrikethroughCap) },
|
||||||
|
{ StatCap::StunResist, RuleI(Character, ItemStunResistCap) },
|
||||||
|
};
|
||||||
|
|
||||||
|
auto it = default_caps.find(stat_id);
|
||||||
|
if (it != default_caps.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::SetStatCap(uint8 stat_id, int stat_cap, bool save)
|
||||||
|
{
|
||||||
|
m_stat_caps[stat_id] = stat_cap;
|
||||||
|
|
||||||
|
if (!save) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsBot()) {
|
||||||
|
BotStatCapsRepository::ReplaceOne(
|
||||||
|
database,
|
||||||
|
BotStatCapsRepository::BotStatCaps{
|
||||||
|
.bot_id = CastToBot()->GetBotID(),
|
||||||
|
.stat_id = stat_id,
|
||||||
|
.stat_cap = stat_cap
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (IsClient()) {
|
||||||
|
CharacterStatCapsRepository::ReplaceOne(
|
||||||
|
database,
|
||||||
|
CharacterStatCapsRepository::CharacterStatCaps{
|
||||||
|
.character_id = CastToClient()->CharacterID(),
|
||||||
|
.stat_id = stat_id,
|
||||||
|
.stat_cap = stat_cap
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1519,6 +1519,11 @@ public:
|
|||||||
bool IsGuildmaster() const;
|
bool IsGuildmaster() const;
|
||||||
bool IsDestroying() const { return m_destroying; }
|
bool IsDestroying() const { return m_destroying; }
|
||||||
|
|
||||||
|
int GetStatCap(uint8 stat_id) const;
|
||||||
|
std::map<uint8, int> GetStatCaps() { return m_stat_caps; }
|
||||||
|
bool HasStatCap(uint8 stat_id) const { return m_stat_caps.count(stat_id); }
|
||||||
|
void SetStatCap(uint8 stat_id, int stat_cap, bool save = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void CommonDamage(Mob* other, int64 &damage, const uint16 spell_id, const EQ::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks specal = eSpecialAttacks::None);
|
void CommonDamage(Mob* other, int64 &damage, const uint16 spell_id, const EQ::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks specal = eSpecialAttacks::None);
|
||||||
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
|
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
|
||||||
@ -1802,6 +1807,8 @@ protected:
|
|||||||
|
|
||||||
CombatRecord m_combat_record{};
|
CombatRecord m_combat_record{};
|
||||||
|
|
||||||
|
std::map<uint8, int> m_stat_caps;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const CombatRecord &GetCombatRecord() const;
|
const CombatRecord &GetCombatRecord() const;
|
||||||
|
|
||||||
|
|||||||
@ -620,6 +620,16 @@ void Perl_Bot_RaidGroupSay(Bot* self, const char* message) // @categories Script
|
|||||||
self->RaidGroupSay(message);
|
self->RaidGroupSay(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Perl_Bot_GetStatCap(Bot* self, uint8 stat_id)
|
||||||
|
{
|
||||||
|
return self->GetStatCap(stat_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Perl_Bot_SetStatCap(Bot* self, uint8 stat_id, int stat_cap)
|
||||||
|
{
|
||||||
|
self->SetStatCap(stat_id, stat_cap, true);
|
||||||
|
}
|
||||||
|
|
||||||
void perl_register_bot()
|
void perl_register_bot()
|
||||||
{
|
{
|
||||||
perl::interpreter state(PERL_GET_THX);
|
perl::interpreter state(PERL_GET_THX);
|
||||||
@ -683,27 +693,28 @@ void perl_register_bot()
|
|||||||
package.add("GetBotItem", &Perl_Bot_GetBotItem);
|
package.add("GetBotItem", &Perl_Bot_GetBotItem);
|
||||||
package.add("GetBotItemIDBySlot", &Perl_Bot_GetBotItemIDBySlot);
|
package.add("GetBotItemIDBySlot", &Perl_Bot_GetBotItemIDBySlot);
|
||||||
package.add("GetClassAbbreviation", &Perl_Bot_GetClassAbbreviation);
|
package.add("GetClassAbbreviation", &Perl_Bot_GetClassAbbreviation);
|
||||||
|
package.add("GetDisciplineReuseTimer", (uint32(*)(Bot*))&Perl_Bot_GetDisciplineReuseTimer);
|
||||||
|
package.add("GetDisciplineReuseTimer", (uint32(*)(Bot*, uint16))&Perl_Bot_GetDisciplineReuseTimer);
|
||||||
package.add("GetExpansionBitmask", &Perl_Bot_GetExpansionBitmask);
|
package.add("GetExpansionBitmask", &Perl_Bot_GetExpansionBitmask);
|
||||||
package.add("GetGroup", &Perl_Bot_GetGroup);
|
package.add("GetGroup", &Perl_Bot_GetGroup);
|
||||||
package.add("GetHealAmount", &Perl_Bot_GetHealAmount);
|
package.add("GetHealAmount", &Perl_Bot_GetHealAmount);
|
||||||
package.add("GetInstrumentMod", &Perl_Bot_GetInstrumentMod);
|
package.add("GetInstrumentMod", &Perl_Bot_GetInstrumentMod);
|
||||||
package.add("GetItemAt", &Perl_Bot_GetItemAt);
|
package.add("GetItemAt", &Perl_Bot_GetItemAt);
|
||||||
|
package.add("GetItemEquippedByID", &Perl_Bot_HasItemEquippedByID);
|
||||||
package.add("GetItemIDAt", &Perl_Bot_GetItemIDAt);
|
package.add("GetItemIDAt", &Perl_Bot_GetItemIDAt);
|
||||||
|
package.add("GetItemReuseTimer", (uint32(*)(Bot*))&Perl_Bot_GetItemReuseTimer);
|
||||||
|
package.add("GetItemReuseTimer", (uint32(*)(Bot*, uint32))&Perl_Bot_GetItemReuseTimer);
|
||||||
package.add("GetOwner", &Perl_Bot_GetOwner);
|
package.add("GetOwner", &Perl_Bot_GetOwner);
|
||||||
package.add("GetRaceAbbreviation", &Perl_Bot_GetRaceAbbreviation);
|
package.add("GetRaceAbbreviation", &Perl_Bot_GetRaceAbbreviation);
|
||||||
package.add("GetRawItemAC", &Perl_Bot_GetRawItemAC);
|
package.add("GetRawItemAC", &Perl_Bot_GetRawItemAC);
|
||||||
package.add("GetSpellDamage", &Perl_Bot_GetSpellDamage);
|
package.add("GetSpellDamage", &Perl_Bot_GetSpellDamage);
|
||||||
|
package.add("GetSpellRecastTimer", (uint32(*)(Bot*))&Perl_Bot_GetSpellRecastTimer);
|
||||||
|
package.add("GetSpellRecastTimer", (uint32(*)(Bot*, uint16))&Perl_Bot_GetSpellRecastTimer);
|
||||||
|
package.add("GetStatCap", &Perl_Bot_GetStatCap);
|
||||||
package.add("HasAugmentEquippedByID", &Perl_Bot_HasAugmentEquippedByID);
|
package.add("HasAugmentEquippedByID", &Perl_Bot_HasAugmentEquippedByID);
|
||||||
package.add("HasBotItem", &Perl_Bot_HasBotItem);
|
package.add("HasBotItem", &Perl_Bot_HasBotItem);
|
||||||
package.add("HasBotSpellEntry", &Perl_Bot_HasBotSpellEntry);
|
package.add("HasBotSpellEntry", &Perl_Bot_HasBotSpellEntry);
|
||||||
package.add("HasItemEquippedByID", &Perl_Bot_HasItemEquippedByID);
|
package.add("HasItemEquippedByID", &Perl_Bot_HasItemEquippedByID);
|
||||||
package.add("GetDisciplineReuseTimer", (uint32(*)(Bot*))&Perl_Bot_GetDisciplineReuseTimer);
|
|
||||||
package.add("GetDisciplineReuseTimer", (uint32(*)(Bot*, uint16))&Perl_Bot_GetDisciplineReuseTimer);
|
|
||||||
package.add("GetItemEquippedByID", &Perl_Bot_HasItemEquippedByID);
|
|
||||||
package.add("GetItemReuseTimer", (uint32(*)(Bot*))&Perl_Bot_GetItemReuseTimer);
|
|
||||||
package.add("GetItemReuseTimer", (uint32(*)(Bot*, uint32))&Perl_Bot_GetItemReuseTimer);
|
|
||||||
package.add("GetSpellRecastTimer", (uint32(*)(Bot*))&Perl_Bot_GetSpellRecastTimer);
|
|
||||||
package.add("GetSpellRecastTimer", (uint32(*)(Bot*, uint16))&Perl_Bot_GetSpellRecastTimer);
|
|
||||||
package.add("IsGrouped", &Perl_Bot_IsGrouped);
|
package.add("IsGrouped", &Perl_Bot_IsGrouped);
|
||||||
package.add("IsSitting", &Perl_Bot_IsSitting);
|
package.add("IsSitting", &Perl_Bot_IsSitting);
|
||||||
package.add("IsStanding", &Perl_Bot_IsStanding);
|
package.add("IsStanding", &Perl_Bot_IsStanding);
|
||||||
@ -736,6 +747,7 @@ void perl_register_bot()
|
|||||||
package.add("SetSpellDurationRaid", (void(*)(Bot*, int, int, int, bool, bool))&Perl_Bot_SetSpellDurationRaid);
|
package.add("SetSpellDurationRaid", (void(*)(Bot*, int, int, int, bool, bool))&Perl_Bot_SetSpellDurationRaid);
|
||||||
package.add("SetSpellRecastTimer", (void(*)(Bot*, uint16))&Perl_Bot_SetSpellRecastTimer);
|
package.add("SetSpellRecastTimer", (void(*)(Bot*, uint16))&Perl_Bot_SetSpellRecastTimer);
|
||||||
package.add("SetSpellRecastTimer", (void(*)(Bot*, uint16, uint32))&Perl_Bot_SetSpellRecastTimer);
|
package.add("SetSpellRecastTimer", (void(*)(Bot*, uint16, uint32))&Perl_Bot_SetSpellRecastTimer);
|
||||||
|
package.add("SetStatCap", &Perl_Bot_SetStatCap);
|
||||||
package.add("Signal", &Perl_Bot_Signal);
|
package.add("Signal", &Perl_Bot_Signal);
|
||||||
package.add("Sit", &Perl_Bot_Sit);
|
package.add("Sit", &Perl_Bot_Sit);
|
||||||
package.add("Stand", &Perl_Bot_Stand);
|
package.add("Stand", &Perl_Bot_Stand);
|
||||||
|
|||||||
@ -3363,6 +3363,16 @@ perl::array Perl_Client_GetKeyRing(Client* self)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Perl_Client_GetStatCap(Client* self, uint8 stat_id)
|
||||||
|
{
|
||||||
|
return self->GetStatCap(stat_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Perl_Client_SetStatCap(Client* self, uint8 stat_id, int stat_cap)
|
||||||
|
{
|
||||||
|
self->SetStatCap(stat_id, stat_cap, true);
|
||||||
|
}
|
||||||
|
|
||||||
void perl_register_client()
|
void perl_register_client()
|
||||||
{
|
{
|
||||||
perl::interpreter perl(PERL_GET_THX);
|
perl::interpreter perl(PERL_GET_THX);
|
||||||
@ -3635,6 +3645,7 @@ void perl_register_client()
|
|||||||
package.add("GetSpellBookSlotBySpellID", &Perl_Client_GetSpellBookSlotBySpellID);
|
package.add("GetSpellBookSlotBySpellID", &Perl_Client_GetSpellBookSlotBySpellID);
|
||||||
package.add("GetSpellIDByBookSlot", &Perl_Client_GetSpellIDByBookSlot);
|
package.add("GetSpellIDByBookSlot", &Perl_Client_GetSpellIDByBookSlot);
|
||||||
package.add("GetSpentAA", &Perl_Client_GetSpentAA);
|
package.add("GetSpentAA", &Perl_Client_GetSpentAA);
|
||||||
|
package.add("GetStatCap", &Perl_Client_GetStatCap);
|
||||||
package.add("GetStartZone", &Perl_Client_GetStartZone);
|
package.add("GetStartZone", &Perl_Client_GetStartZone);
|
||||||
package.add("GetTargetRingX", &Perl_Client_GetTargetRingX);
|
package.add("GetTargetRingX", &Perl_Client_GetTargetRingX);
|
||||||
package.add("GetTargetRingY", &Perl_Client_GetTargetRingY);
|
package.add("GetTargetRingY", &Perl_Client_GetTargetRingY);
|
||||||
@ -3899,6 +3910,7 @@ void perl_register_client()
|
|||||||
package.add("SetStartZone", (void(*)(Client*, uint32))&Perl_Client_SetStartZone);
|
package.add("SetStartZone", (void(*)(Client*, uint32))&Perl_Client_SetStartZone);
|
||||||
package.add("SetStartZone", (void(*)(Client*, uint32, float, float, float))&Perl_Client_SetStartZone);
|
package.add("SetStartZone", (void(*)(Client*, uint32, float, float, float))&Perl_Client_SetStartZone);
|
||||||
package.add("SetStartZone", (void(*)(Client*, uint32, float, float, float, float))&Perl_Client_SetStartZone);
|
package.add("SetStartZone", (void(*)(Client*, uint32, float, float, float, float))&Perl_Client_SetStartZone);
|
||||||
|
package.add("SetStatCap", &Perl_Client_SetStatCap);
|
||||||
package.add("SetStats", &Perl_Client_SetStats);
|
package.add("SetStats", &Perl_Client_SetStats);
|
||||||
package.add("SetThirst", &Perl_Client_SetThirst);
|
package.add("SetThirst", &Perl_Client_SetThirst);
|
||||||
package.add("SetTint", &Perl_Client_SetTint);
|
package.add("SetTint", &Perl_Client_SetTint);
|
||||||
|
|||||||
@ -50,6 +50,8 @@
|
|||||||
#include "../common/repositories/character_corpses_repository.h"
|
#include "../common/repositories/character_corpses_repository.h"
|
||||||
#include "../common/repositories/character_corpse_items_repository.h"
|
#include "../common/repositories/character_corpse_items_repository.h"
|
||||||
#include "../common/repositories/zone_repository.h"
|
#include "../common/repositories/zone_repository.h"
|
||||||
|
#include "../common/repositories/bot_stat_caps_repository.h"
|
||||||
|
#include "../common/repositories/character_stat_caps_repository.h"
|
||||||
|
|
||||||
#include "../common/repositories/trader_repository.h"
|
#include "../common/repositories/trader_repository.h"
|
||||||
#include "../common/repositories/character_evolving_items_repository.h"
|
#include "../common/repositories/character_evolving_items_repository.h"
|
||||||
@ -4297,3 +4299,83 @@ void ZoneDatabase::LoadCharacterTitleSets(Client* c)
|
|||||||
c->EnableTitle(e.title_set, false);
|
c->EnableTitle(e.title_set, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZoneDatabase::LoadStatCaps(Mob* m)
|
||||||
|
{
|
||||||
|
if (!zone || !m) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m->IsBot()) {
|
||||||
|
const auto& l = BotStatCapsRepository::GetWhere(
|
||||||
|
*this,
|
||||||
|
fmt::format(
|
||||||
|
"`bot_id` = {}",
|
||||||
|
m->CastToBot()->GetBotID()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (l.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& e : l) {
|
||||||
|
m->SetStatCap(e.stat_id, e.stat_cap);
|
||||||
|
}
|
||||||
|
} else if (m->IsClient()) {
|
||||||
|
const auto& l = CharacterStatCapsRepository::GetWhere(
|
||||||
|
*this,
|
||||||
|
fmt::format(
|
||||||
|
"`character_id` = {}",
|
||||||
|
m->CastToClient()->CharacterID()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (l.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& e : l) {
|
||||||
|
m->SetStatCap(e.stat_id, e.stat_cap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneDatabase::SaveStatCaps(Mob* m)
|
||||||
|
{
|
||||||
|
if (m->IsBot()) {
|
||||||
|
std::vector<BotStatCapsRepository::BotStatCaps> v;
|
||||||
|
|
||||||
|
BotStatCapsRepository::BotStatCaps stat_cap;
|
||||||
|
|
||||||
|
stat_cap.bot_id = m->CastToBot()->GetBotID();
|
||||||
|
|
||||||
|
for (const auto& e: m->GetStatCaps()) {
|
||||||
|
stat_cap.stat_id = e.first;
|
||||||
|
stat_cap.stat_cap = e.second;
|
||||||
|
|
||||||
|
v.emplace_back(stat_cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!v.empty()) {
|
||||||
|
BotStatCapsRepository::ReplaceMany(*this, v);
|
||||||
|
}
|
||||||
|
} else if (m->IsClient()) {
|
||||||
|
std::vector<CharacterStatCapsRepository::CharacterStatCaps> v;
|
||||||
|
|
||||||
|
CharacterStatCapsRepository::CharacterStatCaps stat_cap;
|
||||||
|
|
||||||
|
stat_cap.character_id = m->CastToClient()->CharacterID();
|
||||||
|
|
||||||
|
for (const auto& e: m->GetStatCaps()) {
|
||||||
|
stat_cap.stat_id = e.first;
|
||||||
|
stat_cap.stat_cap = e.second;
|
||||||
|
|
||||||
|
v.emplace_back(stat_cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!v.empty()) {
|
||||||
|
CharacterStatCapsRepository::ReplaceMany(*this, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -465,6 +465,10 @@ public:
|
|||||||
void LoadCharacterEXPModifier(Client* c);
|
void LoadCharacterEXPModifier(Client* c);
|
||||||
void SaveCharacterEXPModifier(Client *c);
|
void SaveCharacterEXPModifier(Client *c);
|
||||||
|
|
||||||
|
/* Stat Caps */
|
||||||
|
void LoadStatCaps(Mob* m);
|
||||||
|
void SaveStatCaps(Mob* m);
|
||||||
|
|
||||||
/* Player Title Sets */
|
/* Player Title Sets */
|
||||||
void LoadCharacterTitleSets(Client* c);
|
void LoadCharacterTitleSets(Client* c);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user