mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-30 15:55:45 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b044d8533e | |||
| d810cb02c3 | |||
| 992a5cc132 | |||
| c50fda0f73 |
+28
-13
@@ -1,3 +1,18 @@
|
||||
## [22.51.1] 5/27/2024
|
||||
|
||||
### Fixes
|
||||
|
||||
* Adjust return for perl release check @Akkadius 2024-05-26
|
||||
* Corrected issue with bazaar purchase via parcels where an incorrect quantity would be calculated. ([#4352](https://github.com/EQEmu/Server/pull/4352)) @neckkola 2024-05-27
|
||||
|
||||
### Performance
|
||||
|
||||
* Improve SkillCaps::GetTrainLevel() Efficiency ([#4350](https://github.com/EQEmu/Server/pull/4350)) @Kinglykrab 2024-05-26
|
||||
|
||||
### Rules
|
||||
|
||||
* Legacy Compute Defense against modern agi based defense. ([#4349](https://github.com/EQEmu/Server/pull/4349)) @fryguy503 2024-05-27
|
||||
|
||||
## [22.51.0] 5/26/2024
|
||||
|
||||
### Commands
|
||||
@@ -1368,7 +1383,7 @@
|
||||
|
||||
### EQTime
|
||||
|
||||
Hotfix for world not spamming save messages by setting to detail level logging @Akkadius 2023-11-20
|
||||
Hotfix for world not spamming save messages by setting to detail level logging @Akkadius 2023-11-20
|
||||
|
||||
## [22.34.0] - 11/19/2023
|
||||
|
||||
@@ -2450,7 +2465,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Telnet encoding fix ([#3269](https://github.com/EQEmu/Server/pull/3269)) @Akkadius 2023-04-05
|
||||
|
||||
## [22.9.1] - 04/03/2023
|
||||
## [22.9.1] - 04/03/2023
|
||||
|
||||
### Code
|
||||
|
||||
@@ -2495,7 +2510,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Change to use Pass by reference where valid. ([#3163](https://github.com/EQEmu/Server/pull/3163)) @Aeadoin 2023-04-02
|
||||
|
||||
## [22.9.0] - 04/01/2023
|
||||
## [22.9.0] - 04/01/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -2519,7 +2534,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Add missing Luabind definitions to lua_general.cpp ([#3167](https://github.com/EQEmu/Server/pull/3167)) @Kinglykrab 2023-04-01
|
||||
|
||||
## [22.8.2] - 03/30/2023
|
||||
## [22.8.2] - 03/30/2023
|
||||
|
||||
### Code
|
||||
|
||||
@@ -2543,13 +2558,13 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Remove Guild Bank Zone ID Rule ([#3156](https://github.com/EQEmu/Server/pull/3156)) @Kinglykrab 2023-03-29
|
||||
|
||||
## [22.8.1] - 03/27/2023
|
||||
## [22.8.1] - 03/27/2023
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix for NPCs having spells interrupted. ([#3150](https://github.com/EQEmu/Server/pull/3150)) @Aeadoin 2023-03-27
|
||||
|
||||
## [22.8.0] - 03/25/2023
|
||||
## [22.8.0] - 03/25/2023
|
||||
|
||||
### Code
|
||||
|
||||
@@ -2569,7 +2584,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
* Fix for Items looted from corpses. ([#3147](https://github.com/EQEmu/Server/pull/3147)) @Aeadoin 2023-03-26
|
||||
* Fix for SQL Query in npc_scale_global_base ([#3144](https://github.com/EQEmu/Server/pull/3144)) @Aeadoin 2023-03-26
|
||||
|
||||
## [22.7.0] - 03/24/2023
|
||||
## [22.7.0] - 03/24/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -2726,7 +2741,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
* Add exception handling to converters themselves ([#3029](https://github.com/EQEmu/Server/pull/3029)) @Akkadius 2023-03-05
|
||||
* Add more number formatters ([#2873](https://github.com/EQEmu/Server/pull/2873)) @Kinglykrab 2023-03-04
|
||||
|
||||
## [22.4.5] - 03/03/2023
|
||||
## [22.4.5] - 03/03/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -2768,7 +2783,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
* Add IsFindable() and IsTrackable() to Perl/Lua ([#2996](https://github.com/EQEmu/Server/pull/2996)) @Kinglykrab 2023-03-01
|
||||
* Add IsUnderwaterOnly() to Perl/Lua ([#2995](https://github.com/EQEmu/Server/pull/2995)) @Kinglykrab 2023-03-01
|
||||
|
||||
## [22.4.4] - 02/24/2023
|
||||
## [22.4.4] - 02/24/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -2815,7 +2830,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Fix for Lore Conflict ([#2977](https://github.com/EQEmu/Server/pull/2977)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-24
|
||||
|
||||
## [22.4.3] - 02/21/2023
|
||||
## [22.4.3] - 02/21/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -2862,7 +2877,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Add date to optional Drakkin Guktan Faction Update ([#2965](https://github.com/EQEmu/Server/pull/2965)) ([joligario](https://github.com/joligario)) 2023-02-19
|
||||
|
||||
## [22.4.2] - 02/18/2023
|
||||
## [22.4.2] - 02/18/2023
|
||||
|
||||
### Content
|
||||
|
||||
@@ -2884,7 +2899,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
|
||||
* Fix regression caused by #2932 ([#2956](https://github.com/EQEmu/Server/pull/2956)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-18
|
||||
|
||||
## [22.4.1] - 02/17/2023
|
||||
## [22.4.1] - 02/17/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -2905,7 +2920,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
|
||||
* Fix rare out of bound issue when loading event types ([#2946](https://github.com/EQEmu/Server/pull/2946)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
|
||||
* Turn off KILLED_NPC (trash) off by default ([#2948](https://github.com/EQEmu/Server/pull/2948)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
|
||||
|
||||
## [22.4.0] - 02/17/2023
|
||||
## [22.4.0] - 02/17/2023
|
||||
|
||||
### Bots
|
||||
|
||||
|
||||
@@ -614,6 +614,7 @@ RULE_INT(Combat, PCAttackPowerScaling, 100, "Applies scaling to PC Attack Power
|
||||
RULE_INT(Combat, PCAccuracyAvoidanceMod2Scale, 100, "Scale Factor for PC Accuracy and Avoidance (Mod2, found on items). Found a value of 100 to make both too strong (75 = x0.75). DEFAULT: 100 to not adjust existing Servers")
|
||||
RULE_BOOL(Combat, AllowRaidTargetBlind, false, "Toggle to allow raid targets to be blinded, default is false (Live-like)")
|
||||
RULE_BOOL(Combat, RogueBackstabHasteCorrection, false, "Toggle to enable correction for Haste impacting Backstab DPS too much. DEFAULT: false")
|
||||
RULE_BOOL(Combat, LegacyComputeDefense, false, "Trim AGI Scaling of defense mostly for lower levels to help compensate for the newer agi based defense system. Default: False")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(NPC)
|
||||
|
||||
+18
-17
@@ -1,4 +1,5 @@
|
||||
#include "skill_caps.h"
|
||||
#include "timer.h"
|
||||
|
||||
SkillCaps *SkillCaps::SetContentDatabase(Database *db)
|
||||
{
|
||||
@@ -13,39 +14,39 @@ SkillCapsRepository::SkillCaps SkillCaps::GetSkillCap(uint8 class_id, EQ::skills
|
||||
return SkillCapsRepository::NewEntity();
|
||||
}
|
||||
|
||||
uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
|
||||
const uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
|
||||
|
||||
auto pos = m_skill_caps.find(key);
|
||||
if (pos != m_skill_caps.end()) {
|
||||
return pos->second;
|
||||
}
|
||||
|
||||
return SkillCapsRepository::NewEntity();
|
||||
}
|
||||
|
||||
uint8 SkillCaps::GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
|
||||
uint8 SkillCaps::GetSkillTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
|
||||
{
|
||||
if (
|
||||
!IsPlayerClass(class_id) ||
|
||||
class_id > Class::PLAYER_CLASS_COUNT ||
|
||||
static_cast<uint32>(skill_id) > (EQ::skills::HIGHEST_SKILL + 1)
|
||||
) {
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8 skill_cap_max_level = (
|
||||
RuleI(Character, SkillCapMaxLevel) > 0 ?
|
||||
RuleI(Character, SkillCapMaxLevel) :
|
||||
RuleI(Character, MaxLevel)
|
||||
RuleI(Character, SkillCapMaxLevel) :
|
||||
RuleI(Character, MaxLevel)
|
||||
);
|
||||
|
||||
const uint8 max_level = level > skill_cap_max_level ? level : skill_cap_max_level;
|
||||
const uint8 max_level = level > skill_cap_max_level ? level : skill_cap_max_level;
|
||||
const uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
|
||||
|
||||
for (const auto &e: m_skill_caps) {
|
||||
for (uint8 current_level = 1; current_level <= max_level; current_level++) {
|
||||
uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
|
||||
auto pos = m_skill_caps.find(key);
|
||||
if (pos != m_skill_caps.end()) {
|
||||
return current_level;
|
||||
}
|
||||
for (uint8 current_level = 1; current_level <= max_level; current_level++) {
|
||||
auto pos = m_skill_caps.find(key);
|
||||
if (pos != m_skill_caps.end()) {
|
||||
return current_level;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,20 +55,20 @@ uint8 SkillCaps::GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, u
|
||||
|
||||
void SkillCaps::LoadSkillCaps()
|
||||
{
|
||||
const auto &l = SkillCapsRepository::All(*m_content_database);
|
||||
const auto& l = SkillCapsRepository::All(*m_content_database);
|
||||
|
||||
m_skill_caps.clear();
|
||||
|
||||
for (const auto &e: l) {
|
||||
for (const auto& e: l) {
|
||||
if (
|
||||
e.level < 1 ||
|
||||
!IsPlayerClass(e.class_id) ||
|
||||
static_cast<EQ::skills::SkillType>(e.skill_id) >= EQ::skills::SkillCount
|
||||
) {
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t key = (e.class_id * 1000000) + (e.level * 1000) + e.skill_id;
|
||||
const uint64_t key = (e.class_id * 1000000) + (e.level * 1000) + e.skill_id;
|
||||
m_skill_caps[key] = e;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ class SkillCaps {
|
||||
public:
|
||||
inline void ClearSkillCaps() { m_skill_caps.clear(); }
|
||||
SkillCapsRepository::SkillCaps GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
|
||||
uint8 GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
|
||||
uint8 GetSkillTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
|
||||
void LoadSkillCaps();
|
||||
void ReloadSkillCaps();
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
// Build variables
|
||||
// these get injected during the build pipeline
|
||||
#define CURRENT_VERSION "22.51.0-dev" // always append -dev to the current version for custom-builds
|
||||
#define CURRENT_VERSION "22.51.1-dev" // always append -dev to the current version for custom-builds
|
||||
#define LOGIN_VERSION "0.8.0"
|
||||
#define COMPILE_DATE __DATE__
|
||||
#define COMPILE_TIME __TIME__
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eqemu-server",
|
||||
"version": "22.51.0",
|
||||
"version": "22.51.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/EQEmu/Server.git"
|
||||
|
||||
+31
-6
@@ -256,19 +256,44 @@ int Mob::GetTotalToHit(EQ::skills::SkillType skill, int chance_mod)
|
||||
int Mob::compute_defense()
|
||||
{
|
||||
int defense = GetSkill(EQ::skills::SkillDefense) * 400 / 225;
|
||||
defense += (8000 * (GetAGI() - 40)) / 36000;
|
||||
if (IsOfClientBot()) {
|
||||
defense += itembonuses.heroic_agi_avoidance;
|
||||
|
||||
// In new code, AGI becomes a large contributor to avoidance at low levels, since AGI isn't capped by Level but Defense is
|
||||
// A scale factor is implemented for PCs to reduce the effect of AGI at low levels. This isn't applied to NPCs since they can be
|
||||
// easily controlled via the Database.
|
||||
if (RuleB(Combat, LegacyComputeDefense)) {
|
||||
int agi_scale_factor = 1000;
|
||||
|
||||
if (IsOfClientBot()) {
|
||||
agi_scale_factor = std::min(1000, static_cast<int>(GetLevel()) * 1000 / 70); // Scales Agi Contribution for PC's Level, max Contribution at Level 70
|
||||
}
|
||||
|
||||
defense += agi_scale_factor * (800 * (GetAGI() - 40)) / 3600 / 1000;
|
||||
|
||||
if (IsOfClientBot()) {
|
||||
defense += GetHeroicAGI() / 10;
|
||||
}
|
||||
|
||||
defense += itembonuses.AvoidMeleeChance * RuleI(Combat, PCAccuracyAvoidanceMod2Scale) / 100; // item mod2
|
||||
} else {
|
||||
defense += (8000 * (GetAGI() - 40)) / 36000;
|
||||
|
||||
if (IsOfClientBot()) {
|
||||
defense += itembonuses.heroic_agi_avoidance;
|
||||
}
|
||||
|
||||
defense += itembonuses.AvoidMeleeChance; // item mod2
|
||||
}
|
||||
|
||||
|
||||
//516 SE_AC_Mitigation_Max_Percent
|
||||
auto ac_bonus = itembonuses.AC_Mitigation_Max_Percent + aabonuses.AC_Mitigation_Max_Percent + spellbonuses.AC_Mitigation_Max_Percent;
|
||||
if (ac_bonus)
|
||||
if (ac_bonus) {
|
||||
defense += round(static_cast<double>(defense) * static_cast<double>(ac_bonus) * 0.0001);
|
||||
}
|
||||
|
||||
defense += itembonuses.AvoidMeleeChance; // item mod2
|
||||
if (IsNPC())
|
||||
if (IsNPC()) {
|
||||
defense += CastToNPC()->GetAvoidanceRating();
|
||||
}
|
||||
|
||||
if (IsClient()) {
|
||||
double reduction = CastToClient()->GetIntoxication() / 2.0;
|
||||
|
||||
+2
-2
@@ -2803,7 +2803,7 @@ uint16 Client::MaxSkill(EQ::skills::SkillType skill_id, uint8 class_id, uint8 le
|
||||
return skill_caps.GetSkillCap(class_id, skill_id, level).cap;
|
||||
}
|
||||
|
||||
uint8 Client::SkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id)
|
||||
uint8 Client::GetSkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id)
|
||||
{
|
||||
if (
|
||||
ClientVersion() < EQ::versions::ClientVersion::RoF2 &&
|
||||
@@ -2813,7 +2813,7 @@ uint8 Client::SkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id)
|
||||
skill_id = EQ::skills::Skill2HPiercing;
|
||||
}
|
||||
|
||||
return skill_caps.GetTrainLevel(class_id, skill_id, RuleI(Character, MaxLevel));
|
||||
return skill_caps.GetSkillTrainLevel(class_id, skill_id, RuleI(Character, MaxLevel));
|
||||
}
|
||||
|
||||
uint16 Client::GetMaxSkillAfterSpecializationRules(EQ::skills::SkillType skillid, uint16 maxSkill)
|
||||
|
||||
+1
-1
@@ -866,7 +866,7 @@ public:
|
||||
|
||||
uint16 MaxSkill(EQ::skills::SkillType skill_id, uint8 class_id, uint8 level) const;
|
||||
inline uint16 MaxSkill(EQ::skills::SkillType skill_id) const { return MaxSkill(skill_id, GetClass(), GetLevel()); }
|
||||
uint8 SkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id);
|
||||
uint8 GetSkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id);
|
||||
void MaxSkills();
|
||||
|
||||
void SendTradeskillSearchResults(const std::string &query, unsigned long objtype, unsigned long someid);
|
||||
|
||||
@@ -1718,7 +1718,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
|
||||
if (skilllevel == 0) {
|
||||
//this is a new skill..
|
||||
uint16 t_level = SkillTrainLevel(skill, GetClass());
|
||||
uint16 t_level = GetSkillTrainLevel(skill, GetClass());
|
||||
|
||||
if (t_level == 0) {
|
||||
LogSkills("Tried to train a new skill [{}] which is invalid for this race/class.", skill);
|
||||
|
||||
@@ -3375,6 +3375,12 @@ void Lua_Client::ResetLeadershipAA()
|
||||
self->ResetLeadershipAA();
|
||||
}
|
||||
|
||||
uint8 Lua_Client::GetSkillTrainLevel(int skill_id)
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetSkillTrainLevel(static_cast<EQ::skills::SkillType>(skill_id), self->GetClass());
|
||||
}
|
||||
|
||||
luabind::scope lua_register_client() {
|
||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||
.def(luabind::constructor<>())
|
||||
@@ -3624,6 +3630,7 @@ luabind::scope lua_register_client() {
|
||||
.def("GetScribeableSpells", (luabind::object(Lua_Client::*)(lua_State* L,uint8,uint8))&Lua_Client::GetScribeableSpells)
|
||||
.def("GetScribedSpells", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetScribedSpells)
|
||||
.def("GetSkillPoints", (int(Lua_Client::*)(void))&Lua_Client::GetSkillPoints)
|
||||
.def("GetSkillTrainLevel", (uint8(Lua_Client::*)(int))&Lua_Client::GetSkillTrainLevel)
|
||||
.def("GetSpellDamage", (int(Lua_Client::*)(void))&Lua_Client::GetSpellDamage)
|
||||
.def("GetSpellIDByBookSlot", (uint32(Lua_Client::*)(int))&Lua_Client::GetSpellIDByBookSlot)
|
||||
.def("GetSpentAA", (int(Lua_Client::*)(void))&Lua_Client::GetSpentAA)
|
||||
|
||||
@@ -504,6 +504,7 @@ public:
|
||||
bool SetAutoLoginCharacterName(std::string character_name);
|
||||
void DescribeSpecialAbilities(Lua_NPC n);
|
||||
void ResetLeadershipAA();
|
||||
uint8 GetSkillTrainLevel(int skill_id);
|
||||
|
||||
void ApplySpell(int spell_id);
|
||||
void ApplySpell(int spell_id, int duration);
|
||||
|
||||
@@ -3173,6 +3173,11 @@ void Perl_Client_ResetLeadershipAA(Client* self)
|
||||
self->ResetLeadershipAA();
|
||||
}
|
||||
|
||||
uint8 Perl_Client_GetSkillTrainLevel(Client* self, int skill_id)
|
||||
{
|
||||
return self->GetSkillTrainLevel(static_cast<EQ::skills::SkillType>(skill_id), self->GetClass());
|
||||
}
|
||||
|
||||
void perl_register_client()
|
||||
{
|
||||
perl::interpreter perl(PERL_GET_THX);
|
||||
@@ -3431,6 +3436,7 @@ void perl_register_client()
|
||||
package.add("GetTaskActivityDoneCount", &Perl_Client_GetTaskActivityDoneCount);
|
||||
package.add("GetThirst", &Perl_Client_GetThirst);
|
||||
package.add("GetTotalSecondsPlayed", &Perl_Client_GetTotalSecondsPlayed);
|
||||
package.add("GetSkillTrainLevel", &Perl_Client_GetSkillTrainLevel);
|
||||
package.add("GetWeight", &Perl_Client_GetWeight);
|
||||
package.add("GetPEQZoneFlags", &Perl_Client_GetPEQZoneFlags);
|
||||
package.add("GetZoneFlags", &Perl_Client_GetZoneFlags);
|
||||
|
||||
@@ -3555,6 +3555,17 @@ void Client::BuyTraderItemOutsideBazaar(TraderBuy_Struct *tbs, const EQApplicati
|
||||
ps.item_slot = parcel_out.slot_id;
|
||||
strn0cpy(ps.send_to, GetCleanName(), sizeof(ps.send_to));
|
||||
|
||||
if (trader_item.item_charges == tbs->quantity) {
|
||||
TraderRepository::DeleteOne(database, trader_item.id);
|
||||
} else {
|
||||
TraderRepository::UpdateQuantity(
|
||||
database,
|
||||
trader_item.char_id,
|
||||
trader_item.item_sn,
|
||||
trader_item.item_charges - tbs->quantity
|
||||
);
|
||||
}
|
||||
|
||||
SendParcelDeliveryToWorld(ps);
|
||||
|
||||
if (RuleB(Bazaar, AuditTrail)) {
|
||||
|
||||
+28
-16
@@ -1347,7 +1347,7 @@ int64 Mob::TuneGetTotalToHit(EQ::skills::SkillType skill, int chance_mod, int ac
|
||||
hit_bonus += spellbonuses.increase_archery + aabonuses.increase_archery + itembonuses.increase_archery;
|
||||
hit_bonus -= hit_bonus * RuleR(Combat, ArcheryHitPenalty);
|
||||
}
|
||||
|
||||
|
||||
accuracy = (accuracy * (100 + hit_bonus)) / 100;
|
||||
return accuracy;
|
||||
}
|
||||
@@ -1381,31 +1381,43 @@ int64 Mob::TuneGetTotalDefense(int avoidance_override, int add_avoidance)
|
||||
int64 Mob::Tunecompute_defense(int avoidance_override, int add_avoidance)
|
||||
{
|
||||
int defense = GetSkill(EQ::skills::SkillDefense) * 400 / 225;
|
||||
defense += (8000 * (GetAGI() - 40)) / 36000;
|
||||
if (IsOfClientBot()) {
|
||||
if (avoidance_override) {
|
||||
defense = avoidance_override;
|
||||
|
||||
// In new code, AGI becomes a large contributor to avoidance at low levels, since AGI isn't capped by Level but Defense is
|
||||
// A scale factor is implemented for PCs to reduce the effect of AGI at low levels. This isn't applied to NPCs since they can be
|
||||
// easily controlled via the Database.
|
||||
if (RuleB(Combat, LegacyComputeDefense)) {
|
||||
int agi_scale_factor = 1000;
|
||||
|
||||
if (IsOfClientBot()) {
|
||||
agi_scale_factor = std::min(1000, static_cast<int>(GetLevel()) * 1000 / 70); // Scales Agi Contribution for PC's Level, max Contribution at Level 70
|
||||
}
|
||||
else {
|
||||
|
||||
defense += agi_scale_factor * (800 * (GetAGI() - 40)) / 3600 / 1000;
|
||||
|
||||
if (IsOfClientBot()) {
|
||||
defense += GetHeroicAGI() / 10;
|
||||
}
|
||||
|
||||
defense += itembonuses.AvoidMeleeChance * RuleI(Combat, PCAccuracyAvoidanceMod2Scale) / 100; // item mod2
|
||||
} else {
|
||||
defense += (8000 * (GetAGI() - 40)) / 36000;
|
||||
|
||||
if (IsOfClientBot()) {
|
||||
defense += itembonuses.heroic_agi_avoidance;
|
||||
}
|
||||
defense += add_avoidance; //1 pt = 10 heroic agi
|
||||
|
||||
defense += itembonuses.AvoidMeleeChance; // item mod2
|
||||
}
|
||||
|
||||
|
||||
//516 SE_AC_Mitigation_Max_Percent
|
||||
auto ac_bonus = itembonuses.AC_Mitigation_Max_Percent + aabonuses.AC_Mitigation_Max_Percent + spellbonuses.AC_Mitigation_Max_Percent;
|
||||
if (ac_bonus)
|
||||
if (ac_bonus) {
|
||||
defense += round(static_cast<double>(defense) * static_cast<double>(ac_bonus) * 0.0001);
|
||||
}
|
||||
|
||||
defense += itembonuses.AvoidMeleeChance; // item mod2
|
||||
if (IsNPC()) {
|
||||
if (avoidance_override) {
|
||||
defense += avoidance_override;
|
||||
}
|
||||
else {
|
||||
defense += CastToNPC()->GetAvoidanceRating();
|
||||
}
|
||||
defense += add_avoidance;
|
||||
defense += CastToNPC()->GetAvoidanceRating();
|
||||
}
|
||||
|
||||
if (IsClient()) {
|
||||
|
||||
@@ -3974,12 +3974,6 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
data->price = in->trader_buy_struct.price * in->trader_buy_struct.quantity;
|
||||
}
|
||||
|
||||
TraderRepository::UpdateQuantity(
|
||||
database,
|
||||
trader_pc->CharacterID(),
|
||||
item_sn,
|
||||
in->item_quantity_available - in->trader_buy_struct.quantity
|
||||
);
|
||||
TraderRepository::UpdateActiveTransaction(database, in->id, false);
|
||||
|
||||
trader_pc->RemoveItemBySerialNumber(item_sn, in->trader_buy_struct.quantity);
|
||||
|
||||
Reference in New Issue
Block a user