mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
[Feature] Add Data Bucket support for scaling of Heroic Stats. (#3058)
* [Feature] Add Data Bucket support for scaling of Heroic Stats. * update * fixes, still reworking logic * fixes, still reworking logic * logic done * logic done * fixes * Cleanup * Cleanup * Cleanup naming, verify behaviors * formatting * formatting * fix issue with endurance and mana. * update rule desc * cleanup * DataBucket Struct * Cleanup data_bucket.cpp and add constants * cleanup * changes * formatting * fix from merge * escape keyword `key` * Add `key` to generator, run repository-generator.pl * fix for change to key * cleanup * formatting * formatting * typo
This commit is contained in:
parent
abc27ab423
commit
59ad91a140
@ -593,4 +593,29 @@ enum class ApplySpellType {
|
||||
Raid
|
||||
};
|
||||
|
||||
|
||||
namespace HeroicBonusBucket
|
||||
{
|
||||
const std::string WisMaxMana = "HWIS-MaxMana";
|
||||
const std::string WisManaRegen = "HWIS-ManaRegen";
|
||||
const std::string WisHealAmt = "HWIS-HealAmt";
|
||||
const std::string IntMaxMana = "HINT-MaxMana";
|
||||
const std::string IntManaRegen = "HINT-ManaRegen";
|
||||
const std::string IntSpellDmg = "HINT-SpellDmg";
|
||||
const std::string StrMeleeDamage = "HSTR-MeleeDamage";
|
||||
const std::string StrShieldAC = "HSTR-ShieldAC";
|
||||
const std::string StrMaxEndurance = "HSTR-MaxEndurance";
|
||||
const std::string StrEnduranceRegen = "HSTR-EnduranceRegen";
|
||||
const std::string StaMaxHP = "HSTA-MaxHP";
|
||||
const std::string StaHPRegen = "HSTA-HPRegen";
|
||||
const std::string StaMaxEndurance = "HSTA-MaxEndurance";
|
||||
const std::string StaEnduranceRegen = "HSTA-EnduranceRegen";
|
||||
const std::string AgiAvoidance = "HAGI-Avoidance";
|
||||
const std::string AgiMaxEndurance = "HAGI-MaxEndurance";
|
||||
const std::string AgiEnduranceRegen = "HAGI-EnduranceRegen";
|
||||
const std::string DexRangedDamage = "HDEX-RangedDamage";
|
||||
const std::string DexMaxEndurance = "HDEX-MaxEndurance";
|
||||
const std::string DexEnduranceRegen = "HDEX-EnduranceRegen";
|
||||
}
|
||||
|
||||
#endif /*COMMON_EMU_CONSTANTS_H*/
|
||||
|
||||
@ -16,11 +16,12 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseDataBucketsRepository {
|
||||
public:
|
||||
struct DataBuckets {
|
||||
uint64_t id;
|
||||
std::string key;
|
||||
std::string key_;
|
||||
std::string value;
|
||||
uint32_t expires;
|
||||
};
|
||||
@ -34,7 +35,7 @@ public:
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"key",
|
||||
"`key`",
|
||||
"value",
|
||||
"expires",
|
||||
};
|
||||
@ -44,7 +45,7 @@ public:
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"key",
|
||||
"`key`",
|
||||
"value",
|
||||
"expires",
|
||||
};
|
||||
@ -88,7 +89,7 @@ public:
|
||||
DataBuckets e{};
|
||||
|
||||
e.id = 0;
|
||||
e.key = "";
|
||||
e.key_ = "";
|
||||
e.value = "";
|
||||
e.expires = 0;
|
||||
|
||||
@ -116,8 +117,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
data_buckets_id
|
||||
)
|
||||
);
|
||||
@ -127,7 +129,7 @@ public:
|
||||
DataBuckets e{};
|
||||
|
||||
e.id = strtoull(row[0], nullptr, 10);
|
||||
e.key = row[1] ? row[1] : "";
|
||||
e.key_ = row[1] ? row[1] : "";
|
||||
e.value = row[2] ? row[2] : "";
|
||||
e.expires = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
|
||||
|
||||
@ -163,7 +165,7 @@ public:
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[1] + " = '" + Strings::Escape(e.key) + "'");
|
||||
v.push_back(columns[1] + " = '" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back(columns[2] + " = '" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.expires));
|
||||
|
||||
@ -188,7 +190,7 @@ public:
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back("'" + Strings::Escape(e.key) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(std::to_string(e.expires));
|
||||
|
||||
@ -221,7 +223,7 @@ public:
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back("'" + Strings::Escape(e.key) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(std::to_string(e.expires));
|
||||
|
||||
@ -258,7 +260,7 @@ public:
|
||||
DataBuckets e{};
|
||||
|
||||
e.id = strtoull(row[0], nullptr, 10);
|
||||
e.key = row[1] ? row[1] : "";
|
||||
e.key_ = row[1] ? row[1] : "";
|
||||
e.value = row[2] ? row[2] : "";
|
||||
e.expires = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
|
||||
|
||||
@ -286,7 +288,7 @@ public:
|
||||
DataBuckets e{};
|
||||
|
||||
e.id = strtoull(row[0], nullptr, 10);
|
||||
e.key = row[1] ? row[1] : "";
|
||||
e.key_ = row[1] ? row[1] : "";
|
||||
e.value = row[2] ? row[2] : "";
|
||||
e.expires = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
|
||||
|
||||
|
||||
@ -93,6 +93,9 @@ RULE_INT(Character, ItemEnduranceRegenCap, 15, "Limit on endurance regeneration
|
||||
RULE_INT(Character, ItemExtraDmgCap, 150, "Cap for bonuses to melee skills like Bash, Frenzy, etc.")
|
||||
RULE_INT(Character, HasteCap, 100, "Haste cap for non-v3(over haste) haste")
|
||||
RULE_INT(Character, Hastev3Cap, 25, "Haste cap for v3(over haste) haste")
|
||||
RULE_BOOL(Character, HeroicStatsUseDataBucketsToScale, false, "Allows scaling the benefits a character receives from Heroic Stats using Data Buckets. Stacks with other Heroic Stats Mulitplier Rules.")
|
||||
RULE_REAL(Character, HeroicIntelligenceIncreaseSpellDmgMultiplier, 0.00, "Allows Heroic Intelligence to increase a Players Worn Spell Damage Stat from Equipment, for example, setting this rule to 1.00 will always grant 1 Spell Damage per 1 Heroic Intelligence")
|
||||
RULE_REAL(Character, HeroicWisdomIncreaseHealAmtMultiplier, 0.00, "Allows Heroic Wisdom to increase a Players Worn Heal Amount Stat from Equipment, for example, setting this rule to 1.00 will always grant 1 Heal Amount per 1 Heroic Wisdom")
|
||||
RULE_REAL(Character, HeroicStrengthMultiplier, 1.00, "Multplier scales benefits from Heroic Strength. Grants 25 Base Endurance, 0.05 Endurance Regen, 1 Melee Damage each Hit, and 1 Shield AC per 10 Heroic Strength.")
|
||||
RULE_REAL(Character, HeroicStaminaMultiplier, 1.00, "Multplier scales benefits from Heroic Stamina. Grants 25 Base Endurance, 0.05 Endurance Regen, 100 Base HP, and 0.5 HP Regen per 10 Heroic Stamina.")
|
||||
RULE_REAL(Character, HeroicAgilityMultiplier, 1.00, "Multplier scales benefits from Heroic Agility. Grants 25 Base Endurance, 0.05 Endurance Regen, and 1 Avoidance AC per 10 Heroic Agility. (Rule does not change Dodge Chance)")
|
||||
|
||||
@ -585,7 +585,8 @@ sub translate_mysql_data_type_to_c {
|
||||
sub get_reserved_cpp_variable_names {
|
||||
return (
|
||||
"class",
|
||||
"int"
|
||||
"int",
|
||||
"key"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -250,7 +250,7 @@ int Mob::compute_defense()
|
||||
int defense = GetSkill(EQ::skills::SkillDefense) * 400 / 225;
|
||||
defense += (8000 * (GetAGI() - 40)) / 36000;
|
||||
if (IsOfClientBot()) {
|
||||
defense += GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier) / 10;
|
||||
defense += itembonuses.heroic_agi_avoidance;
|
||||
}
|
||||
|
||||
//516 SE_AC_Mitigation_Max_Percent
|
||||
@ -883,7 +883,7 @@ int Mob::ACSum(bool skip_caps)
|
||||
shield_ac = CalcRecommendedLevelBonus(GetLevel(), inst->GetItemRecommendedLevel(true), inst->GetItemArmorClass(true));
|
||||
}
|
||||
}
|
||||
shield_ac += GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 10;
|
||||
shield_ac += itembonuses.heroic_str_shield_ac;
|
||||
}
|
||||
// EQ math
|
||||
ac = (ac * 4) / 3;
|
||||
@ -5909,10 +5909,10 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
|
||||
switch (hit.skill) {
|
||||
case EQ::skills::SkillThrowing:
|
||||
case EQ::skills::SkillArchery:
|
||||
extra = GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier) / 10;
|
||||
extra = itembonuses.heroic_dex_ranged_damage;
|
||||
break;
|
||||
default:
|
||||
extra = GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 10;
|
||||
extra = itembonuses.heroic_str_melee_damage;
|
||||
break;
|
||||
}
|
||||
hit.damage_done += extra;
|
||||
|
||||
143
zone/bonuses.cpp
143
zone/bonuses.cpp
@ -77,6 +77,7 @@ void Client::CalcBonuses()
|
||||
{
|
||||
memset(&itembonuses, 0, sizeof(StatBonuses));
|
||||
CalcItemBonuses(&itembonuses);
|
||||
CalcHeroicBonuses(&itembonuses);
|
||||
CalcEdibleBonuses(&itembonuses);
|
||||
CalcSpellBonuses(&spellbonuses);
|
||||
CalcAABonuses(&aabonuses);
|
||||
@ -204,7 +205,7 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
}
|
||||
|
||||
// These item stat caps depend on spells/AAs so we process them after those are processed
|
||||
void Client::ProcessItemCaps()
|
||||
void Mob::ProcessItemCaps()
|
||||
{
|
||||
itembonuses.HPRegen = std::min(itembonuses.HPRegen, CalcHPRegenCap());
|
||||
itembonuses.ManaRegen = std::min(itembonuses.ManaRegen, CalcManaRegenCap());
|
||||
@ -219,6 +220,15 @@ void Client::ProcessItemCaps()
|
||||
}
|
||||
|
||||
itembonuses.ATK = std::min(itembonuses.ATK, CalcItemATKCap());
|
||||
|
||||
if (itembonuses.SpellDmg > RuleI(Character, ItemSpellDmgCap)) {
|
||||
itembonuses.SpellDmg = RuleI(Character, ItemSpellDmgCap);
|
||||
}
|
||||
|
||||
if (itembonuses.HealAmt > RuleI(Character, ItemHealAmtCap)) {
|
||||
itembonuses.HealAmt = RuleI(Character, ItemHealAmtCap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Client::AddItemBonuses(const EQ::ItemInstance *inst, StatBonuses *newbon, bool isAug, bool isTribute, int rec_override, bool ammo_slot_item)
|
||||
@ -5634,3 +5644,134 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::CalcHeroicBonuses(StatBonuses* newbon)
|
||||
{
|
||||
if (GetHeroicSTR()) {
|
||||
SetHeroicStrBonuses(newbon);
|
||||
}
|
||||
|
||||
if (GetHeroicSTA()) {
|
||||
SetHeroicStaBonuses(newbon);
|
||||
}
|
||||
|
||||
if (GetHeroicAGI()) {
|
||||
SetHeroicAgiBonuses(newbon);
|
||||
}
|
||||
|
||||
if (GetHeroicDEX()) {
|
||||
SetHeroicDexBonuses(newbon);
|
||||
}
|
||||
|
||||
if (GetHeroicINT()) {
|
||||
SetHeroicIntBonuses(newbon);
|
||||
}
|
||||
|
||||
if (GetHeroicWIS()) {
|
||||
SetHeroicWisBonuses(newbon);
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::SetHeroicWisBonuses(StatBonuses* n)
|
||||
{
|
||||
n->heroic_max_mana += IsWISCasterClass(GetClass()) ? GetHeroicWIS() * RuleR(Character, HeroicWisdomMultiplier) * 10 : 0;
|
||||
n->heroic_mana_regen += IsWISCasterClass(GetClass()) ? GetHeroicWIS() * RuleR(Character, HeroicWisdomMultiplier) / 25 : 0;
|
||||
n->HealAmt += GetHeroicWIS() * RuleR(Character, HeroicWisdomIncreaseHealAmtMultiplier);
|
||||
|
||||
if (RuleB(Character, HeroicStatsUseDataBucketsToScale)) {
|
||||
n->heroic_max_mana += IsWISCasterClass(GetClass()) ? GetHeroicWIS() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::WisMaxMana) * 10 : 0;
|
||||
n->heroic_mana_regen += IsWISCasterClass(GetClass()) ? GetHeroicWIS() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::WisManaRegen) / 25 : 0;
|
||||
n->HealAmt += GetHeroicWIS() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::WisHealAmt);
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::SetHeroicIntBonuses(StatBonuses* n)
|
||||
{
|
||||
n->heroic_max_mana += IsINTCasterClass(GetClass()) ? GetHeroicINT() * RuleR(Character, HeroicIntelligenceMultiplier) * 10 : 0;
|
||||
n->heroic_mana_regen += IsINTCasterClass(GetClass()) ? GetHeroicINT() * RuleR(Character, HeroicIntelligenceMultiplier) / 25 : 0;
|
||||
n->SpellDmg += GetHeroicINT() * RuleR(Character, HeroicIntelligenceIncreaseSpellDmgMultiplier);
|
||||
|
||||
if (RuleB(Character, HeroicStatsUseDataBucketsToScale)) {
|
||||
n->heroic_max_mana += IsINTCasterClass(GetClass()) ? GetHeroicINT() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::IntMaxMana) * 10 : 0;
|
||||
n->heroic_mana_regen += IsINTCasterClass(GetClass()) ? GetHeroicINT() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::IntManaRegen) / 25 : 0;
|
||||
n->SpellDmg += GetHeroicINT() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::IntSpellDmg);
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::SetHeroicDexBonuses(StatBonuses* n)
|
||||
{
|
||||
n->heroic_dex_ranged_damage += GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier) / 10;
|
||||
n->heroic_max_end += GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier) / 4 * 10.0f;
|
||||
n->heroic_end_regen += GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier) / 4 / 50;
|
||||
|
||||
if (RuleB(Character, HeroicStatsUseDataBucketsToScale)) {
|
||||
n->heroic_dex_ranged_damage += GetHeroicDEX() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::DexRangedDamage) / 10;
|
||||
n->heroic_max_end += GetHeroicDEX() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::DexMaxEndurance) / 4 * 10.0f;
|
||||
n->heroic_end_regen += GetHeroicDEX() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::DexEnduranceRegen) / 4 / 50;
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::SetHeroicAgiBonuses(StatBonuses* n)
|
||||
{
|
||||
n->heroic_agi_avoidance += GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier) / 10;
|
||||
n->heroic_max_end += GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier) / 4 * 10.0f;
|
||||
n->heroic_end_regen += GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier) / 4 / 50;
|
||||
|
||||
if (RuleB(Character, HeroicStatsUseDataBucketsToScale)) {
|
||||
n->heroic_agi_avoidance += GetHeroicAGI() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::AgiAvoidance) / 10;
|
||||
n->heroic_max_end += GetHeroicAGI() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::AgiMaxEndurance) / 4 * 10.0f;
|
||||
n->heroic_end_regen += GetHeroicAGI() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::AgiEnduranceRegen) / 4 / 50;
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::SetHeroicStaBonuses(StatBonuses* n)
|
||||
{
|
||||
n->heroic_max_hp += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) * 10;
|
||||
n->heroic_hp_regen += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) / 20;
|
||||
n->heroic_max_end += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) / 4 * 10.0f;
|
||||
n->heroic_end_regen += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) / 4 / 50;
|
||||
|
||||
if (RuleB(Character, HeroicStatsUseDataBucketsToScale)) {
|
||||
n->heroic_max_hp += GetHeroicSTA() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StaMaxHP) * 10;
|
||||
n->heroic_hp_regen += GetHeroicSTA() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StaHPRegen) / 20;
|
||||
n->heroic_max_end += GetHeroicSTA() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StaMaxEndurance) / 4 * 10.0f;
|
||||
n->heroic_end_regen += GetHeroicSTA() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StaEnduranceRegen) / 4 / 50;
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::SetHeroicStrBonuses(StatBonuses* n)
|
||||
{
|
||||
n->heroic_str_shield_ac += GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 10;
|
||||
n->heroic_str_melee_damage += GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 10;
|
||||
n->heroic_max_end += GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 4 * 10.0f;
|
||||
n->heroic_end_regen += GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 4 / 50;
|
||||
|
||||
if (RuleB(Character, HeroicStatsUseDataBucketsToScale)) {
|
||||
n->heroic_str_shield_ac += GetHeroicSTR() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StrShieldAC) / 10;
|
||||
n->heroic_str_melee_damage += GetHeroicSTR() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StrMeleeDamage) / 10;
|
||||
n->heroic_max_end += GetHeroicSTR() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StrMaxEndurance) / 4 * 10.0f;
|
||||
n->heroic_end_regen += GetHeroicSTR() * CheckHeroicBonusesDataBuckets(HeroicBonusBucket::StrEnduranceRegen) / 4 / 50;
|
||||
}
|
||||
}
|
||||
|
||||
float Mob::CheckHeroicBonusesDataBuckets(std::string bucket_name)
|
||||
{
|
||||
std::string bucket_value;
|
||||
if (!bucket_name.empty()) {
|
||||
const auto full_name = fmt::format(
|
||||
"{}-{}",
|
||||
GetBucketKey(),
|
||||
bucket_name
|
||||
);
|
||||
|
||||
if (IsOfClientBot()) {
|
||||
bucket_value = DataBucket::CheckBucketKey(this, full_name);
|
||||
}
|
||||
|
||||
if (bucket_value.empty() || !Strings::IsNumber(bucket_value)) {
|
||||
return 0.00f;
|
||||
}
|
||||
}
|
||||
|
||||
return Strings::ToFloat(bucket_value);
|
||||
}
|
||||
113
zone/bot.cpp
113
zone/bot.cpp
@ -3284,8 +3284,7 @@ bool Bot::Spawn(Client* botCharacterOwner) {
|
||||
m_targetable = true;
|
||||
entity_list.AddBot(this, true, true);
|
||||
|
||||
GetBotOwnerDataBuckets();
|
||||
GetBotDataBuckets();
|
||||
DataBucket::GetDataBuckets(this);
|
||||
LoadBotSpellSettings();
|
||||
if (!AI_AddBotSpells(GetBotSpellID())) {
|
||||
GetBotOwner()->CastToClient()->Message(
|
||||
@ -5461,10 +5460,10 @@ int64 Bot::CalcMaxMana() {
|
||||
switch(GetCasterClass()) {
|
||||
case 'I':
|
||||
max_mana = (GenerateBaseManaPoints() + itembonuses.Mana + spellbonuses.Mana + GroupLeadershipAAManaEnhancement());
|
||||
max_mana += (GetHeroicINT() * 10);
|
||||
max_mana += itembonuses.heroic_max_mana;
|
||||
case 'W': {
|
||||
max_mana = (GenerateBaseManaPoints() + itembonuses.Mana + spellbonuses.Mana + GroupLeadershipAAManaEnhancement());
|
||||
max_mana += (GetHeroicWIS() * 10);
|
||||
max_mana += itembonuses.heroic_max_mana;
|
||||
break;
|
||||
}
|
||||
case 'N': {
|
||||
@ -6001,11 +6000,13 @@ void Bot::CalcBonuses() {
|
||||
memset(&itembonuses, 0, sizeof(StatBonuses));
|
||||
GenerateBaseStats();
|
||||
CalcItemBonuses(&itembonuses);
|
||||
CalcHeroicBonuses(&itembonuses);
|
||||
CalcSpellBonuses(&spellbonuses);
|
||||
CalcAABonuses(&aabonuses);
|
||||
SetAttackTimer();
|
||||
CalcSeeInvisibleLevel();
|
||||
CalcInvisibleLevel();
|
||||
ProcessItemCaps();
|
||||
CalcATK();
|
||||
CalcSTR();
|
||||
CalcSTA();
|
||||
@ -6037,15 +6038,7 @@ int64 Bot::CalcHPRegenCap() {
|
||||
}
|
||||
|
||||
int64 Bot::CalcManaRegenCap() {
|
||||
int64 cap = RuleI(Character, ItemManaRegenCap) + aabonuses.ItemManaRegenCap;
|
||||
switch(GetCasterClass()) {
|
||||
case 'I':
|
||||
cap += itembonuses.HeroicINT * RuleR(Character, HeroicIntelligenceMultiplier) / 25;
|
||||
break;
|
||||
case 'W':
|
||||
cap += itembonuses.HeroicWIS * RuleR(Character, HeroicWisdomMultiplier) / 25;
|
||||
break;
|
||||
}
|
||||
int64 cap = RuleI(Character, ItemManaRegenCap) + aabonuses.ItemManaRegenCap + itembonuses.heroic_mana_regen;
|
||||
return (cap * RuleI(Character, ManaRegenMultiplier) / 100);
|
||||
}
|
||||
|
||||
@ -6435,7 +6428,7 @@ int32 Bot::LevelRegen() {
|
||||
|
||||
int64 Bot::CalcHPRegen() {
|
||||
int32 regen = (LevelRegen() + itembonuses.HPRegen + spellbonuses.HPRegen);
|
||||
regen += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) / 20;
|
||||
regen += itembonuses.heroic_hp_regen;
|
||||
regen += (aabonuses.HPRegen + GroupLeadershipAAHealthRegeneration());
|
||||
|
||||
regen = ((regen * RuleI(Character, HPRegenMultiplier)) / 100);
|
||||
@ -6456,15 +6449,8 @@ int64 Bot::CalcManaRegen() {
|
||||
} else
|
||||
regen = (2 + spellbonuses.ManaRegen + itembonuses.ManaRegen);
|
||||
|
||||
if(GetCasterClass() == 'I')
|
||||
regen += itembonuses.HeroicINT * RuleR(Character, HeroicIntelligenceMultiplier) / 25;
|
||||
else if(GetCasterClass() == 'W')
|
||||
regen += itembonuses.HeroicWIS * RuleR(Character, HeroicWisdomMultiplier) / 25;
|
||||
regen += aabonuses.ManaRegen + itembonuses.heroic_mana_regen;
|
||||
|
||||
else
|
||||
regen = 0;
|
||||
|
||||
regen += aabonuses.ManaRegen;
|
||||
regen = ((regen * RuleI(Character, ManaRegenMultiplier)) / 100);
|
||||
float mana_regen_rate = RuleR(Bots, ManaRegen);
|
||||
if (mana_regen_rate < 0.0f)
|
||||
@ -6509,7 +6495,7 @@ int64 Bot::CalcMaxHP() {
|
||||
int32 bot_hp = 0;
|
||||
uint32 nd = 10000;
|
||||
bot_hp += (GenerateBaseHitPoints() + itembonuses.HP);
|
||||
bot_hp += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) * 10;
|
||||
bot_hp += itembonuses.heroic_max_hp;
|
||||
nd += aabonuses.MaxHP;
|
||||
bot_hp = ((float)bot_hp * (float)nd / (float)10000);
|
||||
bot_hp += (spellbonuses.HP + aabonuses.HP);
|
||||
@ -6553,13 +6539,7 @@ int64 Bot::CalcBaseEndurance() {
|
||||
int32 sta_end = 0;
|
||||
int stats = 0;
|
||||
if (GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->ClientVersion() >= EQ::versions::ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
|
||||
double heroic_stats = 0;
|
||||
stats = ((GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4);
|
||||
double heroic_str = GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier);
|
||||
double heroic_sta = GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier);
|
||||
double heroic_dex = GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier);
|
||||
double heroic_agi = GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier);
|
||||
heroic_stats = (heroic_str + heroic_sta + heroic_dex + heroic_agi) / 4;
|
||||
|
||||
if (stats > 100) {
|
||||
converted_stats = (((stats - 100) * 5 / 2) + 100);
|
||||
@ -6580,7 +6560,7 @@ int64 Bot::CalcBaseEndurance() {
|
||||
sta_end = (9 * converted_stats);
|
||||
base_endurance = (1800 + ((GetLevel() - 80) * 18));
|
||||
}
|
||||
base_end = (base_endurance + sta_end + (heroic_stats * 10));
|
||||
base_end = base_endurance + sta_end + itembonuses.heroic_max_end;
|
||||
} else {
|
||||
|
||||
stats = (GetSTR() + GetSTA() + GetDEX() + GetAGI());
|
||||
@ -6593,7 +6573,8 @@ int64 Bot::CalcBaseEndurance() {
|
||||
int HalfBonus400to800 = 0;
|
||||
int Bonus800plus = 0;
|
||||
int HalfBonus800plus = 0;
|
||||
int BonusUpto800 = int(at_most_800 / 4) ;
|
||||
|
||||
auto BonusUpto800 = int(at_most_800 / 4) ;
|
||||
|
||||
if(stats > 400) {
|
||||
Bonus400to800 = int((at_most_800 - 400) / 4);
|
||||
@ -8768,62 +8749,7 @@ void Bot::OwnerMessage(const std::string& message)
|
||||
);
|
||||
}
|
||||
|
||||
bool Bot::GetBotOwnerDataBuckets()
|
||||
{
|
||||
auto bot_owner = GetBotOwner();
|
||||
if (!bot_owner) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto query = fmt::format(
|
||||
"SELECT `key`, `value` FROM data_buckets WHERE `key` LIKE '{}-%'",
|
||||
Strings::Escape(bot_owner->GetBucketKey())
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bot_owner_data_buckets.clear();
|
||||
|
||||
if (!results.RowCount()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto row : results) {
|
||||
bot_owner_data_buckets.insert(std::pair<std::string,std::string>(row[0], row[1]));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bot::GetBotDataBuckets()
|
||||
{
|
||||
const auto query = fmt::format(
|
||||
"SELECT `key`, `value` FROM data_buckets WHERE `key` LIKE '{}-%'",
|
||||
Strings::Escape(GetBucketKey())
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bot_data_buckets.clear();
|
||||
|
||||
if (!results.RowCount()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto row : results) {
|
||||
bot_data_buckets.insert(std::pair<std::string,std::string>(row[0], row[1]));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bot::CheckDataBucket(const std::string& bucket_name, const std::string& bucket_value, uint8 bucket_comparison)
|
||||
bool Bot::CheckDataBucket(std::string bucket_name, const std::string& bucket_value, uint8 bucket_comparison)
|
||||
{
|
||||
if (!bucket_name.empty() && !bucket_value.empty()) {
|
||||
auto full_name = fmt::format(
|
||||
@ -8832,7 +8758,7 @@ bool Bot::CheckDataBucket(const std::string& bucket_name, const std::string& buc
|
||||
bucket_name
|
||||
);
|
||||
|
||||
auto player_value = bot_data_buckets[full_name];
|
||||
auto player_value = DataBucket::CheckBucketKey(this, full_name);
|
||||
if (player_value.empty() && GetBotOwner()) {
|
||||
full_name = fmt::format(
|
||||
"{}-{}",
|
||||
@ -8840,13 +8766,13 @@ bool Bot::CheckDataBucket(const std::string& bucket_name, const std::string& buc
|
||||
bucket_name
|
||||
);
|
||||
|
||||
player_value = bot_owner_data_buckets[full_name];
|
||||
player_value = DataBucket::CheckBucketKey(GetBotOwner(), full_name);
|
||||
if (player_value.empty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (zone->CheckDataBucket(bucket_comparison, bucket_value, player_value)) {
|
||||
if (zone->CompareDataBucket(bucket_comparison, bucket_value, player_value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -9351,6 +9277,12 @@ float Bot::GetBotCasterMaxRange(float melee_distance_max) {// Calculate caster d
|
||||
return caster_distance_max;
|
||||
}
|
||||
|
||||
|
||||
int32 Bot::CalcItemATKCap()
|
||||
{
|
||||
return RuleI(Character, ItemATKCap) + itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap;
|
||||
}
|
||||
|
||||
bool Bot::CheckSpawnConditions(Client* c) {
|
||||
|
||||
if (c->GetFeigned()) {
|
||||
@ -9386,5 +9318,4 @@ bool Bot::CheckSpawnConditions(Client* c) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 };
|
||||
|
||||
19
zone/bot.h
19
zone/bot.h
@ -269,8 +269,8 @@ public:
|
||||
int32 CalcPR();
|
||||
int32 CalcCR();
|
||||
int32 CalcCorrup();
|
||||
int64 CalcHPRegenCap();
|
||||
int64 CalcManaRegenCap();
|
||||
int64 CalcHPRegenCap() final;
|
||||
int64 CalcManaRegenCap() final;
|
||||
int32 LevelRegen();
|
||||
int64 CalcHPRegen();
|
||||
int64 CalcManaRegen();
|
||||
@ -280,6 +280,7 @@ public:
|
||||
int GroupLeadershipAAHealthRegeneration();
|
||||
int GroupLeadershipAAOffenseEnhancement();
|
||||
void CalcRestState();
|
||||
|
||||
int64 CalcMaxEndurance();
|
||||
int64 CalcBaseEndurance();
|
||||
int64 CalcEnduranceRegen();
|
||||
@ -382,9 +383,7 @@ public:
|
||||
[[nodiscard]] int GetMaxDiscSlots() const final { return EQ::spells::DISC_BUFFS; }
|
||||
[[nodiscard]] int GetMaxTotalSlots() const final { return EQ::spells::TOTAL_BUFFS; }
|
||||
|
||||
bool GetBotOwnerDataBuckets();
|
||||
bool GetBotDataBuckets();
|
||||
bool CheckDataBucket(const std::string& bucket_name, const std::string& bucket_value, uint8 bucket_comparison);
|
||||
bool CheckDataBucket(std::string bucket_name, const std::string& bucket_value, uint8 bucket_comparison);
|
||||
|
||||
// Bot Equipment & Inventory Class Methods
|
||||
void BotTradeAddItem(const EQ::ItemInstance* inst, uint16 slot_id, std::string* error_message, bool save_to_database = true);
|
||||
@ -571,8 +570,8 @@ public:
|
||||
inline virtual int32 GetCombatEffects() const { return itembonuses.ProcChance; }
|
||||
inline virtual int32 GetDS() const { return itembonuses.DamageShield; }
|
||||
// Mod3
|
||||
inline virtual int32 GetHealAmt() const { return itembonuses.HealAmt; }
|
||||
inline virtual int32 GetSpellDmg() const { return itembonuses.SpellDmg; }
|
||||
inline int32 GetHealAmt() const override { return itembonuses.HealAmt; }
|
||||
inline int32 GetSpellDmg() const override { return itembonuses.SpellDmg; }
|
||||
inline virtual int32 GetClair() const { return itembonuses.Clairvoyance; }
|
||||
inline virtual int32 GetDSMit() const { return itembonuses.DSMitigation; }
|
||||
|
||||
@ -883,8 +882,6 @@ private:
|
||||
eStandingPetOrder m_previous_pet_order;
|
||||
uint32 m_bot_caster_range;
|
||||
BotCastingRoles m_CastingRoles;
|
||||
std::map<std::string,std::string> bot_data_buckets;
|
||||
std::map<std::string,std::string> bot_owner_data_buckets;
|
||||
|
||||
std::map<uint16, BotSpellSetting> bot_spell_settings;
|
||||
|
||||
@ -937,6 +934,10 @@ private:
|
||||
bool LoadPet(); // Load and spawn bot pet if there is one
|
||||
bool SavePet(); // Save and depop bot pet if there is one
|
||||
bool DeletePet();
|
||||
|
||||
public:
|
||||
|
||||
int32 CalcItemATKCap() final;
|
||||
};
|
||||
|
||||
bool IsSpellInBotList(DBbotspells_Struct* spell_list, uint16 iSpellID);
|
||||
|
||||
@ -6437,8 +6437,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
regen_row_color = color_red;
|
||||
|
||||
base_regen_field = itoa(LevelRegen());
|
||||
item_regen_field = itoa(
|
||||
itembonuses.HPRegen +(GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) / 20));
|
||||
item_regen_field = itoa(itembonuses.HPRegen + itembonuses.heroic_hp_regen);
|
||||
cap_regen_field = itoa(CalcHPRegenCap());
|
||||
spell_regen_field = itoa(spellbonuses.HPRegen);
|
||||
aa_regen_field = itoa(aabonuses.HPRegen);
|
||||
@ -6451,9 +6450,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
regen_row_color = color_blue;
|
||||
|
||||
base_regen_field = itoa(CalcBaseManaRegen());
|
||||
int32 heroic_mana_regen = (GetCasterClass() == 'W') ?
|
||||
GetHeroicWIS() * RuleR(Character, HeroicWisdomMultiplier) / 25 :
|
||||
GetHeroicINT() * RuleR(Character, HeroicIntelligenceMultiplier) / 25;
|
||||
int32 heroic_mana_regen = itembonuses.heroic_mana_regen;
|
||||
item_regen_field = itoa(itembonuses.ManaRegen + heroic_mana_regen);
|
||||
cap_regen_field = itoa(CalcManaRegenCap());
|
||||
spell_regen_field = itoa(spellbonuses.ManaRegen);
|
||||
@ -6468,12 +6465,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
regen_row_color = color_green;
|
||||
|
||||
base_regen_field = itoa(((GetLevel() * 4 / 10) + 2));
|
||||
double heroic_str = GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier);
|
||||
double heroic_sta = GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier);
|
||||
double heroic_dex = GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier);
|
||||
double heroic_agi = GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier);
|
||||
double heroic_stats = (heroic_str + heroic_sta + heroic_dex + heroic_agi) / 4;
|
||||
item_regen_field = itoa(itembonuses.EnduranceRegen + heroic_stats);
|
||||
item_regen_field = itoa(itembonuses.EnduranceRegen + itembonuses.heroic_end_regen);
|
||||
cap_regen_field = itoa(CalcEnduranceRegenCap());
|
||||
spell_regen_field = itoa(spellbonuses.EnduranceRegen);
|
||||
aa_regen_field = itoa(aabonuses.EnduranceRegen);
|
||||
@ -11584,27 +11576,6 @@ void Client::SendReloadCommandMessages() {
|
||||
SendChatLineBreak();
|
||||
}
|
||||
|
||||
std::map<std::string,std::string> Client::GetMerchantDataBuckets()
|
||||
{
|
||||
std::map<std::string,std::string> merchant_data_buckets;
|
||||
|
||||
auto query = fmt::format(
|
||||
"SELECT `key`, `value` FROM data_buckets WHERE `key` LIKE '{}-%'",
|
||||
Strings::Escape(GetBucketKey())
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return merchant_data_buckets;
|
||||
}
|
||||
|
||||
for (auto row : results) {
|
||||
merchant_data_buckets.insert(std::pair<std::string,std::string>(row[0], row[1]));
|
||||
}
|
||||
|
||||
return merchant_data_buckets;
|
||||
}
|
||||
|
||||
void Client::Undye()
|
||||
{
|
||||
for (uint8 slot = EQ::textures::textureBegin; slot <= EQ::textures::LastTexture; slot++) {
|
||||
|
||||
@ -430,7 +430,7 @@ public:
|
||||
int64 CalcMaxMana();
|
||||
int64 CalcBaseMana();
|
||||
const int64& SetMana(int64 amount);
|
||||
int64 CalcManaRegenCap();
|
||||
int64 CalcManaRegenCap() final;
|
||||
|
||||
// guild pool regen shit. Sends a SpawnAppearance with a value that regens to value * 0.001
|
||||
void EnableAreaHPRegen(int value);
|
||||
@ -535,8 +535,8 @@ public:
|
||||
inline virtual int32 GetCombatEffects() const { return itembonuses.ProcChance; }
|
||||
inline virtual int32 GetDS() const { return itembonuses.DamageShield; }
|
||||
// Mod3
|
||||
inline virtual int32 GetHealAmt() const { return itembonuses.HealAmt; }
|
||||
inline virtual int32 GetSpellDmg() const { return itembonuses.SpellDmg; }
|
||||
inline int32 GetHealAmt() const override { return itembonuses.HealAmt; }
|
||||
inline int32 GetSpellDmg() const final { return itembonuses.SpellDmg; }
|
||||
inline virtual int32 GetClair() const { return itembonuses.Clairvoyance; }
|
||||
inline virtual int32 GetDSMit() const { return itembonuses.DSMitigation; }
|
||||
|
||||
@ -578,8 +578,8 @@ public:
|
||||
int64 CalcEnduranceRegen(bool bCombat = false); //Calculates endurance regen used in DoEnduranceRegen()
|
||||
int64 GetEndurance() const {return current_endurance;} //This gets our current endurance
|
||||
int64 GetMaxEndurance() const {return max_end;} //This gets our endurance from the last CalcMaxEndurance() call
|
||||
int64 CalcEnduranceRegenCap();
|
||||
int64 CalcHPRegenCap();
|
||||
int64 CalcEnduranceRegenCap() final;
|
||||
int64 CalcHPRegenCap() final;
|
||||
inline uint8 GetEndurancePercent() { return (uint8)((float)current_endurance / (float)max_end * 100.0f); }
|
||||
void SetEndurance(int32 newEnd); //This sets the current endurance to the new value
|
||||
void DoEnduranceRegen(); //This Regenerates endurance
|
||||
@ -1638,19 +1638,17 @@ public:
|
||||
// rate limit
|
||||
Timer m_list_task_timers_rate_limit = {};
|
||||
|
||||
std::map<std::string,std::string> GetMerchantDataBuckets();
|
||||
|
||||
std::string GetGuildPublicNote();
|
||||
|
||||
PlayerEvent::PlayerEvent GetPlayerEvent();
|
||||
void RecordKilledNPCEvent(NPC *n);
|
||||
|
||||
protected:
|
||||
friend class Mob;
|
||||
void CalcItemBonuses(StatBonuses* newbon);
|
||||
void AddItemBonuses(const EQ::ItemInstance *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false, int rec_override = 0, bool ammo_slot_item = false);
|
||||
void AdditiveWornBonuses(const EQ::ItemInstance *inst, StatBonuses* newbon, bool isAug = false);
|
||||
void CalcEdibleBonuses(StatBonuses* newbon);
|
||||
void ProcessItemCaps();
|
||||
void MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message = true);
|
||||
bool client_data_loaded;
|
||||
|
||||
@ -1701,7 +1699,7 @@ private:
|
||||
|
||||
void HandleTraderPriceUpdate(const EQApplicationPacket *app);
|
||||
|
||||
int32 CalcItemATKCap();
|
||||
int32 CalcItemATKCap() final;
|
||||
int32 CalcHaste();
|
||||
|
||||
int32 CalcAlcoholPhysicalEffect();
|
||||
|
||||
@ -234,7 +234,7 @@ int32 Client::LevelRegen()
|
||||
int64 Client::CalcHPRegen(bool bCombat)
|
||||
{
|
||||
int64 item_regen = itembonuses.HPRegen; // worn spells and +regen, already capped
|
||||
item_regen += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) / 20;
|
||||
item_regen += itembonuses.heroic_hp_regen;
|
||||
|
||||
item_regen += aabonuses.HPRegen;
|
||||
|
||||
@ -491,7 +491,7 @@ int64 Client::CalcBaseHP()
|
||||
auto base_data = database.GetBaseData(GetLevel(), GetClass());
|
||||
if (base_data) {
|
||||
base_hp += base_data->base_hp + (base_data->hp_factor * stats);
|
||||
base_hp += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) * 10;
|
||||
base_hp += itembonuses.heroic_max_hp;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -624,8 +624,7 @@ int64 Client::CalcBaseMana()
|
||||
auto base_data = database.GetBaseData(GetLevel(), GetClass());
|
||||
if (base_data) {
|
||||
max_m = base_data->base_mana +
|
||||
(ConvertedWisInt * base_data->mana_factor) +
|
||||
(GetHeroicINT() * RuleR(Character, HeroicIntelligenceMultiplier) * 10);
|
||||
(ConvertedWisInt * base_data->mana_factor) + itembonuses.heroic_max_mana;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -658,8 +657,7 @@ int64 Client::CalcBaseMana()
|
||||
auto base_data = database.GetBaseData(GetLevel(), GetClass());
|
||||
if (base_data) {
|
||||
max_m = base_data->base_mana +
|
||||
(ConvertedWisInt * base_data->mana_factor) +
|
||||
((GetHeroicWIS() * RuleR(Character, HeroicWisdomMultiplier)) * 10);
|
||||
(ConvertedWisInt * base_data->mana_factor) + itembonuses.heroic_max_mana;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -752,18 +750,7 @@ int64 Client::CalcManaRegen(bool bCombat)
|
||||
// add in + 1 bonus for SE_CompleteHeal, but we don't do anything for it yet?
|
||||
|
||||
int item_bonus = itembonuses.ManaRegen; // this is capped already
|
||||
int heroic_bonus = 0;
|
||||
|
||||
switch (GetCasterClass()) {
|
||||
case 'W':
|
||||
heroic_bonus = GetHeroicWIS() * RuleR(Character, HeroicWisdomMultiplier);
|
||||
break;
|
||||
default:
|
||||
heroic_bonus = GetHeroicINT() * RuleR(Character, HeroicIntelligenceMultiplier);
|
||||
break;
|
||||
}
|
||||
|
||||
item_bonus += heroic_bonus / 25;
|
||||
item_bonus += itembonuses.heroic_mana_regen;
|
||||
regen += item_bonus;
|
||||
|
||||
if (level <= 70 && regen > 65)
|
||||
@ -1690,11 +1677,6 @@ int64 Client::CalcBaseEndurance()
|
||||
{
|
||||
int64 base_end = 0;
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
|
||||
double heroic_str = GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier);
|
||||
double heroic_sta = GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier);
|
||||
double heroic_dex = GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier);
|
||||
double heroic_agi = GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier);
|
||||
double heroic_stats = (heroic_str + heroic_sta + heroic_dex + heroic_agi) / 4;
|
||||
double stats = (GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4.0f;
|
||||
|
||||
if (stats > 201.0f) {
|
||||
@ -1705,7 +1687,7 @@ int64 Client::CalcBaseEndurance()
|
||||
}
|
||||
auto base_data = database.GetBaseData(GetLevel(), GetClass());
|
||||
if (base_data) {
|
||||
base_end = base_data->base_end + (heroic_stats * 10.0f) + (base_data->endurance_factor * static_cast<int>(stats));
|
||||
base_end = base_data->base_end + itembonuses.heroic_max_end + (base_data->endurance_factor * static_cast<int>(stats));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1794,13 +1776,7 @@ int64 Client::CalcEnduranceRegen(bool bCombat)
|
||||
if (encumbered)
|
||||
base += level / -15;
|
||||
|
||||
double heroic_str = GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier);
|
||||
double heroic_sta = GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier);
|
||||
double heroic_dex = GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier);
|
||||
double heroic_agi = GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier);
|
||||
int32 item_bonus = heroic_str + heroic_sta + heroic_dex + heroic_agi;
|
||||
item_bonus = item_bonus / 4 / 50;
|
||||
item_bonus += itembonuses.EnduranceRegen; // this is capped already
|
||||
auto item_bonus = itembonuses.EnduranceRegen + itembonuses.heroic_end_regen; // this is capped already
|
||||
base += item_bonus;
|
||||
|
||||
base = base * AreaEndRegen + 0.5f;
|
||||
|
||||
@ -1380,6 +1380,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
drakkin_tattoo = m_pp.drakkin_tattoo;
|
||||
drakkin_details = m_pp.drakkin_details;
|
||||
|
||||
// Load Data Buckets
|
||||
DataBucket::GetDataBuckets(this);
|
||||
|
||||
// Max Level for Character:PerCharacterQglobalMaxLevel and Character:PerCharacterBucketMaxLevel
|
||||
uint8 client_max_level = 0;
|
||||
if (RuleB(Character, PerCharacterQglobalMaxLevel)) {
|
||||
|
||||
@ -845,18 +845,16 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||
}
|
||||
}
|
||||
|
||||
auto client_data_buckets = GetMerchantDataBuckets();
|
||||
|
||||
auto temporary_merchant_list = zone->tmpmerchanttable[npcid];
|
||||
uint32 slot_id = 1;
|
||||
uint8 handy_chance = 0;
|
||||
for (auto ml : merchant_list) {
|
||||
for (const auto& ml : merchant_list) {
|
||||
if (slot_id > merchant_slots) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto bucket_name = ml.bucket_name;
|
||||
auto bucket_value = ml.bucket_value;
|
||||
auto const& bucket_value = ml.bucket_value;
|
||||
if (!bucket_name.empty() && !bucket_value.empty()) {
|
||||
auto full_name = fmt::format(
|
||||
"{}-{}",
|
||||
@ -864,12 +862,12 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||
bucket_name
|
||||
);
|
||||
|
||||
auto player_value = client_data_buckets[full_name];
|
||||
auto const& player_value = DataBucket::CheckBucketKey(this, full_name);
|
||||
if (player_value.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!zone->CheckDataBucket(ml.bucket_comparison, bucket_value, player_value)) {
|
||||
if (!zone->CompareDataBucket(ml.bucket_comparison, bucket_value, player_value)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -639,6 +639,16 @@ struct StatBonuses {
|
||||
int aura_slots;
|
||||
int trap_slots;
|
||||
bool hunger; // Song of Sustenance -- min caps to 3500
|
||||
int64 heroic_max_hp;
|
||||
int64 heroic_max_mana;
|
||||
int64 heroic_max_end;
|
||||
int64 heroic_hp_regen;
|
||||
int64 heroic_mana_regen;
|
||||
int64 heroic_end_regen;
|
||||
int32 heroic_str_shield_ac;
|
||||
int32 heroic_str_melee_damage;
|
||||
int32 heroic_agi_avoidance;
|
||||
int32 heroic_dex_ranged_damage;
|
||||
};
|
||||
|
||||
// StatBonus Indexes
|
||||
@ -915,5 +925,13 @@ struct ExpeditionInvite
|
||||
std::string swap_remove_name;
|
||||
};
|
||||
|
||||
struct DataBucketCache
|
||||
{
|
||||
uint64_t bucket_id;
|
||||
std::string bucket_key;
|
||||
std::string bucket_value;
|
||||
uint32_t bucket_expires;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
* @param bucket_value
|
||||
* @param expires_time
|
||||
*/
|
||||
void DataBucket::SetData(std::string bucket_key, std::string bucket_value, std::string expires_time) {
|
||||
void DataBucket::SetData(const std::string& bucket_key, const std::string& bucket_value, std::string expires_time) {
|
||||
uint64 bucket_id = DataBucket::DoesBucketExist(bucket_key);
|
||||
|
||||
std::string query;
|
||||
@ -57,7 +57,7 @@ void DataBucket::SetData(std::string bucket_key, std::string bucket_value, std::
|
||||
* @param bucket_key
|
||||
* @return
|
||||
*/
|
||||
std::string DataBucket::GetData(std::string bucket_key) {
|
||||
std::string DataBucket::GetData(const std::string& bucket_key) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT `value` from `data_buckets` WHERE `key` = '%s' AND (`expires` > %lld OR `expires` = 0) LIMIT 1",
|
||||
bucket_key.c_str(),
|
||||
@ -82,7 +82,7 @@ std::string DataBucket::GetData(std::string bucket_key) {
|
||||
* @param bucket_key
|
||||
* @return
|
||||
*/
|
||||
std::string DataBucket::GetDataExpires(std::string bucket_key) {
|
||||
std::string DataBucket::GetDataExpires(const std::string& bucket_key) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT `expires` from `data_buckets` WHERE `key` = '%s' AND (`expires` > %lld OR `expires` = 0) LIMIT 1",
|
||||
bucket_key.c_str(),
|
||||
@ -102,7 +102,7 @@ std::string DataBucket::GetDataExpires(std::string bucket_key) {
|
||||
return std::string(row[0]);
|
||||
}
|
||||
|
||||
std::string DataBucket::GetDataRemaining(std::string bucket_key) {
|
||||
std::string DataBucket::GetDataRemaining(const std::string& bucket_key) {
|
||||
if (DataBucket::GetDataExpires(bucket_key).empty()) {
|
||||
return "0";
|
||||
}
|
||||
@ -130,7 +130,7 @@ std::string DataBucket::GetDataRemaining(std::string bucket_key) {
|
||||
* @param bucket_key
|
||||
* @return
|
||||
*/
|
||||
uint64 DataBucket::DoesBucketExist(std::string bucket_key) {
|
||||
uint64 DataBucket::DoesBucketExist(const std::string& bucket_key) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT `id` from `data_buckets` WHERE `key` = '%s' AND (`expires` > %lld OR `expires` = 0) LIMIT 1",
|
||||
Strings::Escape(bucket_key).c_str(),
|
||||
@ -154,7 +154,7 @@ uint64 DataBucket::DoesBucketExist(std::string bucket_key) {
|
||||
* @param bucket_key
|
||||
* @return
|
||||
*/
|
||||
bool DataBucket::DeleteData(std::string bucket_key) {
|
||||
bool DataBucket::DeleteData(const std::string& bucket_key) {
|
||||
std::string query = StringFormat(
|
||||
"DELETE FROM `data_buckets` WHERE `key` = '%s'",
|
||||
Strings::Escape(bucket_key).c_str()
|
||||
@ -164,3 +164,46 @@ bool DataBucket::DeleteData(std::string bucket_key) {
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool DataBucket::GetDataBuckets(Mob* mob)
|
||||
{
|
||||
auto l = BaseDataBucketsRepository::GetWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"`key` LIKE '{}-%'",
|
||||
Strings::Escape(mob->GetBucketKey())
|
||||
)
|
||||
);
|
||||
|
||||
if (l.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mob->m_data_bucket_cache.clear();
|
||||
|
||||
DataBucketCache d;
|
||||
|
||||
for (const auto& e : l) {
|
||||
d.bucket_id = e.id;
|
||||
d.bucket_key = e.key_;
|
||||
d.bucket_value = e.value;
|
||||
d.bucket_expires = e.expires;
|
||||
|
||||
mob->m_data_bucket_cache.emplace_back(d);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string DataBucket::CheckBucketKey(const Mob* mob, std::string_view full_name)
|
||||
{
|
||||
std::string bucket_value;
|
||||
for (const auto &d : mob->m_data_bucket_cache) {
|
||||
if (d.bucket_key == full_name) {
|
||||
bucket_value = d.bucket_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bucket_value;
|
||||
}
|
||||
|
||||
|
||||
@ -5,20 +5,23 @@
|
||||
#ifndef EQEMU_DATABUCKET_H
|
||||
#define EQEMU_DATABUCKET_H
|
||||
|
||||
|
||||
#include <string>
|
||||
#include "../common/types.h"
|
||||
#include "../common/repositories/data_buckets_repository.h"
|
||||
#include "mob.h"
|
||||
|
||||
class DataBucket {
|
||||
public:
|
||||
static void SetData(std::string bucket_key, std::string bucket_value, std::string expires_time = "");
|
||||
static bool DeleteData(std::string bucket_key);
|
||||
static std::string GetData(std::string bucket_key);
|
||||
static std::string GetDataExpires(std::string bucket_key);
|
||||
static std::string GetDataRemaining(std::string bucket_key);
|
||||
static void SetData(const std::string& bucket_key, const std::string& bucket_value, std::string expires_time = "");
|
||||
static bool DeleteData(const std::string& bucket_key);
|
||||
static std::string GetData(const std::string& bucket_key);
|
||||
static std::string GetDataExpires(const std::string& bucket_key);
|
||||
static std::string GetDataRemaining(const std::string& bucket_key);
|
||||
static bool GetDataBuckets(Mob* mob);
|
||||
static std::string CheckBucketKey(const Mob* mob, std::string_view full_name);
|
||||
|
||||
private:
|
||||
static uint64 DoesBucketExist(std::string bucket_key);
|
||||
static uint64 DoesBucketExist(const std::string& bucket_key);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_DATABUCKET_H
|
||||
|
||||
@ -132,6 +132,7 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
|
||||
|
||||
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) {
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value) * ratio / 100;
|
||||
|
||||
}
|
||||
|
||||
else if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) {
|
||||
@ -140,7 +141,7 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
|
||||
|
||||
entity_list.FilteredMessageCloseString(
|
||||
this, true, 100, Chat::SpellCrit, FilterSpellCrits,
|
||||
OTHER_CRIT_BLAST, 0, GetName(), itoa(-value));
|
||||
OTHER_CRIT_BLAST, nullptr, GetName(), itoa(-value));
|
||||
|
||||
if (IsClient())
|
||||
MessageString(Chat::SpellCrit, YOU_CRIT_BLAST, itoa(-value));
|
||||
@ -175,8 +176,13 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
|
||||
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg)
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value);
|
||||
|
||||
else if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5)
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value);
|
||||
else if (
|
||||
!spells[spell_id].no_heal_damage_item_mod &&
|
||||
GetSpellDmg() &&
|
||||
spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5
|
||||
) {
|
||||
value -= GetExtraSpellAmt(spell_id, GetSpellDmg(), base_value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
@ -260,11 +266,19 @@ int64 Mob::GetActDoTDamage(uint16 spell_id, int64 value, Mob* target, bool from_
|
||||
GetFocusEffect(focusFcAmplifyAmt, spell_id, nullptr, from_buff_tic);
|
||||
|
||||
if (RuleB(Spells, DOTsScaleWithSpellDmg)) {
|
||||
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) {
|
||||
extra_dmg += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value)*ratio/100;
|
||||
if (
|
||||
RuleB(Spells, IgnoreSpellDmgLvlRestriction) &&
|
||||
!spells[spell_id].no_heal_damage_item_mod &&
|
||||
GetSpellDmg()
|
||||
) {
|
||||
extra_dmg += GetExtraSpellAmt(spell_id, GetSpellDmg(), base_value)*ratio/100;
|
||||
}
|
||||
else if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) {
|
||||
extra_dmg += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value)*ratio/100;
|
||||
else if (
|
||||
!spells[spell_id].no_heal_damage_item_mod &&
|
||||
GetSpellDmg() &&
|
||||
spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5
|
||||
) {
|
||||
extra_dmg += GetExtraSpellAmt(spell_id, GetSpellDmg(), base_value)*ratio/100;
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,11 +309,19 @@ int64 Mob::GetActDoTDamage(uint16 spell_id, int64 value, Mob* target, bool from_
|
||||
GetFocusEffect(focusFcAmplifyAmt, spell_id, nullptr, from_buff_tic);
|
||||
|
||||
if (RuleB(Spells, DOTsScaleWithSpellDmg)) {
|
||||
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) {
|
||||
extra_dmg += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value);
|
||||
if (
|
||||
RuleB(Spells, IgnoreSpellDmgLvlRestriction) &&
|
||||
!spells[spell_id].no_heal_damage_item_mod &&
|
||||
GetSpellDmg()
|
||||
) {
|
||||
extra_dmg += GetExtraSpellAmt(spell_id, GetSpellDmg(), base_value);
|
||||
}
|
||||
else if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) {
|
||||
extra_dmg += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value);
|
||||
else if (
|
||||
!spells[spell_id].no_heal_damage_item_mod &&
|
||||
GetSpellDmg() &&
|
||||
spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5
|
||||
) {
|
||||
extra_dmg += GetExtraSpellAmt(spell_id, GetSpellDmg(), base_value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -321,6 +343,7 @@ int64 Mob::GetActDoTDamage(uint16 spell_id, int64 value, Mob* target, bool from_
|
||||
|
||||
int64 Mob::GetExtraSpellAmt(uint16 spell_id, int64 extra_spell_amt, int64 base_spell_dmg)
|
||||
{
|
||||
|
||||
if (RuleB(Spells, FlatItemExtraSpellAmt)) {
|
||||
if (RuleB(Spells, ItemExtraSpellAmtCalcAsPercent)) {
|
||||
return std::abs(base_spell_dmg) * extra_spell_amt / 100;
|
||||
@ -425,11 +448,19 @@ int64 Mob::GetActSpellHealing(uint16 spell_id, int64 value, Mob* target, bool fr
|
||||
value += GetFocusEffect(focusFcHealAmtCrit, spell_id); //SPA 396 Add before critical
|
||||
|
||||
//Using IgnoreSpellDmgLvlRestriction to also allow healing to scale
|
||||
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt) {
|
||||
value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, base_value);//Item Heal Amt Add before critical
|
||||
if (
|
||||
RuleB(Spells, IgnoreSpellDmgLvlRestriction) &&
|
||||
!spells[spell_id].no_heal_damage_item_mod &&
|
||||
GetHealAmt()
|
||||
) {
|
||||
value += GetExtraSpellAmt(spell_id, GetHealAmt(), base_value); //Item Heal Amt Add before critical
|
||||
}
|
||||
else if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) {
|
||||
value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, base_value);//Item Heal Amt Add before critical
|
||||
else if (
|
||||
!spells[spell_id].no_heal_damage_item_mod &&
|
||||
GetHealAmt() &&
|
||||
spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5
|
||||
) {
|
||||
value += GetExtraSpellAmt(spell_id, GetHealAmt(), base_value); //Item Heal Amt Add before critical
|
||||
}
|
||||
|
||||
if (target) {
|
||||
@ -471,11 +502,19 @@ int64 Mob::GetActSpellHealing(uint16 spell_id, int64 value, Mob* target, bool fr
|
||||
}
|
||||
|
||||
if (RuleB(Spells, HOTsScaleWithHealAmt)) {
|
||||
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt) {
|
||||
extra_heal += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, base_value);
|
||||
if (
|
||||
RuleB(Spells, IgnoreSpellDmgLvlRestriction) &&
|
||||
!spells[spell_id].no_heal_damage_item_mod &&
|
||||
GetHealAmt()
|
||||
) {
|
||||
extra_heal += GetExtraSpellAmt(spell_id, GetHealAmt(), base_value);
|
||||
}
|
||||
else if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) {
|
||||
extra_heal += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, base_value);
|
||||
else if (
|
||||
!spells[spell_id].no_heal_damage_item_mod &&
|
||||
GetHealAmt() &&
|
||||
spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5
|
||||
) {
|
||||
extra_heal += GetExtraSpellAmt(spell_id, GetHealAmt(), base_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -112,12 +112,12 @@ void Lua_Bot::SetExpansionBitmask(int expansion_bitmask, bool save) {
|
||||
|
||||
bool Lua_Bot::ReloadBotDataBuckets() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->GetBotDataBuckets();
|
||||
return DataBucket::GetDataBuckets(self);
|
||||
}
|
||||
|
||||
bool Lua_Bot::ReloadBotOwnerDataBuckets() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->GetBotOwnerDataBuckets();
|
||||
return self->HasOwner() && DataBucket::GetDataBuckets(self->GetBotOwner());
|
||||
}
|
||||
|
||||
bool Lua_Bot::ReloadBotSpells() {
|
||||
|
||||
@ -3046,6 +3046,11 @@ bool Lua_Client::IsAutoFireEnabled()
|
||||
return self->AutoFireEnabled();
|
||||
}
|
||||
|
||||
bool Lua_Client::ReloadDataBuckets() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return DataBucket::GetDataBuckets(self);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_client() {
|
||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||
.def(luabind::constructor<>())
|
||||
@ -3394,6 +3399,7 @@ luabind::scope lua_register_client() {
|
||||
.def("QueuePacket", (void(Lua_Client::*)(Lua_Packet,bool,int,int))&Lua_Client::QueuePacket)
|
||||
.def("ReadBookByName", (void(Lua_Client::*)(std::string,uint8))&Lua_Client::ReadBookByName)
|
||||
.def("RefundAA", (void(Lua_Client::*)(void))&Lua_Client::RefundAA)
|
||||
.def("ReloadDataBuckets", (bool(Lua_Client::*)(void))&Lua_Client::ReloadDataBuckets)
|
||||
.def("RemoveAllExpeditionLockouts", (void(Lua_Client::*)(std::string))&Lua_Client::RemoveAllExpeditionLockouts)
|
||||
.def("RemoveAllExpeditionLockouts", (void(Lua_Client::*)(void))&Lua_Client::RemoveAllExpeditionLockouts)
|
||||
.def("RemoveExpeditionLockout", (void(Lua_Client::*)(std::string, std::string))&Lua_Client::RemoveExpeditionLockout)
|
||||
|
||||
@ -534,6 +534,8 @@ public:
|
||||
|
||||
void DialogueWindow(std::string markdown);
|
||||
|
||||
bool ReloadDataBuckets();
|
||||
|
||||
Lua_Expedition CreateExpedition(luabind::object expedition_info);
|
||||
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players);
|
||||
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players, bool disable_messages);
|
||||
|
||||
@ -226,8 +226,8 @@ public:
|
||||
inline virtual int32 GetCombatEffects() const { return itembonuses.ProcChance; }
|
||||
inline virtual int32 GetDS() const { return itembonuses.DamageShield; }
|
||||
// Mod3
|
||||
inline virtual int32 GetHealAmt() const { return itembonuses.HealAmt; }
|
||||
inline virtual int32 GetSpellDmg() const { return itembonuses.SpellDmg; }
|
||||
inline int32 GetHealAmt() const override { return itembonuses.HealAmt; }
|
||||
inline int32 GetSpellDmg() const override { return itembonuses.SpellDmg; }
|
||||
inline virtual int32 GetClair() const { return itembonuses.Clairvoyance; }
|
||||
inline virtual int32 GetDSMit() const { return itembonuses.DSMitigation; }
|
||||
|
||||
|
||||
25
zone/mob.h
25
zone/mob.h
@ -20,6 +20,7 @@
|
||||
#define MOB_H
|
||||
|
||||
#include "common.h"
|
||||
#include "data_bucket.h"
|
||||
#include "entity.h"
|
||||
#include "hate_list.h"
|
||||
#include "pathfinder_interface.h"
|
||||
@ -618,10 +619,13 @@ public:
|
||||
inline int64 GetHP() const { return current_hp; }
|
||||
inline int64 GetMaxHP() const { return max_hp; }
|
||||
virtual int64 CalcMaxHP();
|
||||
virtual int64 CalcHPRegenCap() { return 0; }
|
||||
inline int64 GetMaxMana() const { return max_mana; }
|
||||
virtual int64 CalcManaRegenCap() { return 0; }
|
||||
inline int64 GetMana() const { return current_mana; }
|
||||
virtual int64 GetEndurance() const { return 0; }
|
||||
virtual int64 GetMaxEndurance() const { return 0; }
|
||||
virtual int64 CalcEnduranceRegenCap() { return 0; }
|
||||
virtual void SetEndurance(int32 newEnd) { return; }
|
||||
int64 GetItemHPBonuses();
|
||||
int64 GetSpellHPBonuses();
|
||||
@ -654,7 +658,10 @@ public:
|
||||
inline int32 GetHeroicStrikethrough() const { return heroic_strikethrough; }
|
||||
inline const bool GetKeepsSoldItems() const { return keeps_sold_items; }
|
||||
inline void SetKeepsSoldItems(bool in_keeps_sold_items) { keeps_sold_items = in_keeps_sold_items; }
|
||||
|
||||
virtual int32 GetHealAmt() const { return 0; }
|
||||
virtual int32 GetSpellDmg() const { return 0; }
|
||||
void ProcessItemCaps();
|
||||
virtual int32 CalcItemATKCap() { return 0; }
|
||||
virtual bool IsSitting() const { return false; }
|
||||
|
||||
int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat);
|
||||
@ -1390,6 +1397,9 @@ public:
|
||||
/// this cures timing issues cuz dead animation isn't done but server side feigning is?
|
||||
inline bool GetFeigned() const { return(feigned); }
|
||||
|
||||
std::vector<DataBucketCache> m_data_bucket_cache;
|
||||
|
||||
// Data Bucket Methods
|
||||
void DeleteBucket(std::string bucket_name);
|
||||
std::string GetBucket(std::string bucket_name);
|
||||
std::string GetBucketExpires(std::string bucket_name);
|
||||
@ -1397,6 +1407,9 @@ public:
|
||||
std::string GetBucketRemaining(std::string bucket_name);
|
||||
void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration = "");
|
||||
|
||||
// Heroic Stat Benefits
|
||||
float CheckHeroicBonusesDataBuckets(std::string bucket_name);
|
||||
|
||||
int DispatchZoneControllerEvent(QuestEventID evt, Mob* init, const std::string& data, uint32 extra, std::vector<std::any>* pointers);
|
||||
|
||||
// Bots HealRotation methods
|
||||
@ -1418,6 +1431,8 @@ public:
|
||||
|
||||
void DrawDebugCoordinateNode(std::string node_name, const glm::vec4 vec);
|
||||
|
||||
void CalcHeroicBonuses(StatBonuses* newbon);
|
||||
|
||||
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);
|
||||
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
|
||||
@ -1701,6 +1716,7 @@ protected:
|
||||
bool is_boat;
|
||||
|
||||
CombatRecord m_combat_record{};
|
||||
|
||||
public:
|
||||
const CombatRecord &GetCombatRecord() const;
|
||||
|
||||
@ -1833,6 +1849,13 @@ private:
|
||||
std::shared_ptr<HealRotation> m_target_of_heal_rotation;
|
||||
bool m_manual_follow;
|
||||
|
||||
void SetHeroicStrBonuses(StatBonuses* n);
|
||||
void SetHeroicStaBonuses(StatBonuses* n);
|
||||
void SetHeroicAgiBonuses(StatBonuses* n);
|
||||
void SetHeroicDexBonuses(StatBonuses* n);
|
||||
void SetHeroicIntBonuses(StatBonuses* n);
|
||||
void SetHeroicWisBonuses(StatBonuses* n);
|
||||
|
||||
void DoSpellInterrupt(uint16 spell_id, int32 mana_cost, int my_curmana);
|
||||
};
|
||||
|
||||
|
||||
@ -337,12 +337,12 @@ void Perl_Bot_SetSpellDurationGroup(Bot* self, int spell_id, int duration, bool
|
||||
|
||||
bool Perl_Bot_ReloadBotDataBuckets(Bot* self)
|
||||
{
|
||||
return self->GetBotDataBuckets();
|
||||
return DataBucket::GetDataBuckets(self);
|
||||
}
|
||||
|
||||
bool Perl_Bot_ReloadBotOwnerDataBuckets(Bot* self)
|
||||
{
|
||||
return self->GetBotOwnerDataBuckets();
|
||||
return self->HasOwner() && DataBucket::GetDataBuckets(self->GetBotOwner());
|
||||
}
|
||||
|
||||
bool Perl_Bot_ReloadBotSpells(Bot* self)
|
||||
|
||||
@ -2902,6 +2902,11 @@ bool Perl_Client_IsAutoFireEnabled(Client* self)
|
||||
return self->AutoFireEnabled();
|
||||
}
|
||||
|
||||
bool Perl_Client_ReloadDataBuckets(Client* self)
|
||||
{
|
||||
return DataBucket::GetDataBuckets(self);
|
||||
}
|
||||
|
||||
void perl_register_client()
|
||||
{
|
||||
perl::interpreter perl(PERL_GET_THX);
|
||||
@ -3248,6 +3253,7 @@ void perl_register_client()
|
||||
package.add("ReadBook", &Perl_Client_ReadBook);
|
||||
package.add("ReadBookByName", &Perl_Client_ReadBookByName);
|
||||
package.add("RefundAA", &Perl_Client_RefundAA);
|
||||
package.add("ReloadDataBuckets", &Perl_Client_ReloadDataBuckets);
|
||||
package.add("RemoveAllExpeditionLockouts", (void(*)(Client*))&Perl_Client_RemoveAllExpeditionLockouts);
|
||||
package.add("RemoveAllExpeditionLockouts", (void(*)(Client*, std::string))&Perl_Client_RemoveAllExpeditionLockouts);
|
||||
package.add("RemoveExpeditionLockout", &Perl_Client_RemoveExpeditionLockout);
|
||||
|
||||
@ -1049,7 +1049,7 @@ int64 Mob::TuneACSum(bool skip_caps, int ac_override, int add_ac)
|
||||
shield_ac = CalcRecommendedLevelBonus(GetLevel(), inst->GetItemRecommendedLevel(true),inst->GetItemArmorClass(true));
|
||||
}
|
||||
}
|
||||
shield_ac += GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 10;
|
||||
shield_ac += itembonuses.heroic_str_shield_ac;
|
||||
}
|
||||
// EQ math
|
||||
ac = (ac * 4) / 3;
|
||||
@ -1353,7 +1353,7 @@ int64 Mob::Tunecompute_defense(int avoidance_override, int add_avoidance)
|
||||
defense = avoidance_override;
|
||||
}
|
||||
else {
|
||||
defense += GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier) / 10;
|
||||
defense += itembonuses.heroic_agi_avoidance;
|
||||
}
|
||||
defense += add_avoidance; //1 pt = 10 heroic agi
|
||||
}
|
||||
@ -1495,10 +1495,10 @@ void Mob::TuneCommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraA
|
||||
switch (hit.skill) {
|
||||
case EQ::skills::SkillThrowing:
|
||||
case EQ::skills::SkillArchery:
|
||||
extra = GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier) / 10;
|
||||
extra = itembonuses.heroic_dex_ranged_damage;
|
||||
break;
|
||||
default:
|
||||
extra = GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 10;
|
||||
extra = itembonuses.heroic_str_melee_damage;
|
||||
break;
|
||||
}
|
||||
hit.damage_done += extra;
|
||||
|
||||
@ -2986,7 +2986,7 @@ std::string Zone::GetAAName(int aa_id)
|
||||
return std::string();
|
||||
}
|
||||
|
||||
bool Zone::CheckDataBucket(uint8 bucket_comparison, std::string bucket_value, std::string player_value)
|
||||
bool Zone::CompareDataBucket(uint8 bucket_comparison, const std::string& bucket_value, const std::string& player_value)
|
||||
{
|
||||
std::vector<std::string> bucket_checks;
|
||||
bool found = false;
|
||||
|
||||
@ -311,7 +311,7 @@ public:
|
||||
bool IsQuestHotReloadQueued() const;
|
||||
void SetQuestHotReloadQueued(bool in_quest_hot_reload_queued);
|
||||
|
||||
bool CheckDataBucket(uint8 bucket_comparison, std::string bucket_value, std::string player_value);
|
||||
bool CompareDataBucket(uint8 bucket_comparison, const std::string& bucket_value, const std::string& player_value);
|
||||
|
||||
WaterMap *watermap;
|
||||
ZonePoint *GetClosestZonePoint(const glm::vec3 &location, uint32 to, Client *client, float max_distance = 40000.0f);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user