[Bug Fix] #tune command various fixes (#2046)

* tune fixes

* [Bug Fix] #tune command various fixes

accuracy tune fix
This commit is contained in:
KayenEQ 2022-03-11 10:13:51 -05:00 committed by GitHub
parent 8107ed52e1
commit 0e5d578d71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 160 additions and 17 deletions

View File

@ -5453,7 +5453,7 @@ int32 Mob::RuneAbsorb(int32 damage, uint16 type)
return damage;
}
//SYNC WITH: tune.cpp, mob.h TuneCommonOutgoingHitSucces
void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttackOptions *opts)
{
if (!defender)

View File

@ -1303,6 +1303,7 @@ public:
int Tunecompute_defense(int avoidance_override = 0, int add_avoidance = 0);
bool TuneCheckHitChance(Mob* other, DamageHitInfo &hit, int avoidance_override = 0, int add_avoidance = 0);
EQ::skills::SkillType TuneAttackAnimation(int Hand, const EQ::ItemInstance* weapon, EQ::skills::SkillType skillinuse = EQ::skills::Skill1HBlunt);
void TuneCommonOutgoingHitSuccess(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
//aa new
uint32 GetAA(uint32 rank_id, uint32 *charges = nullptr) const;

View File

@ -101,6 +101,12 @@ void Mob::TuneGetStats(Mob* defender, Mob *attacker)
Message(0, "[#Tune] Parry Chance: %.0f pct ", round(TuneGetAvoidMeleeChance(defender, attacker, DMG_PARRIED)));
Message(0, "[#Tune] Dodge Chance: %.0f pct ", round(TuneGetAvoidMeleeChance(defender, attacker, DMG_DODGED)));
if (defender->IsNPC())
{
Message(0, "[#Tune] NPC STAT AC: %i ", static_cast<int>(defender->CastToNPC()->GetNPCStat("ac")));
Message(0, "[#Tune] NPC STAT Avoidance: %i ", static_cast<int>(defender->CastToNPC()->GetNPCStat("avoidance")));
}
Message(0, "################################################");
Message(0, "[#Tune] Attacker Statistics vs Defender");
Message(0, "[#Tune] Attacker Name: %s", attacker->GetCleanName());
@ -109,8 +115,13 @@ void Mob::TuneGetStats(Mob* defender, Mob *attacker)
Message(0, "[#Tune] Max Damage %i Min Damage %i", max_damage, min_damage);
Message(0, "[#Tune] Total Offense: %i ", TuneGetOffense(defender, attacker));
Message(0, "[#Tune] Chance to hit: %.0f pct", round(hit_chance));
Message(0, "[#Tune] Accuracy: %i ", TuneGetAccuracy( defender,attacker));
Message(0, "[#Tune] Total Accuracy: %i ", TuneGetAccuracy( defender,attacker));
if (attacker->IsNPC())
{
Message(0, "[#Tune] NPC STAT ATK: %i ", static_cast<int>(attacker->CastToNPC()->GetNPCStat("atk")));
Message(0, "[#Tune] NPC STAT Accuracy: %i ", static_cast<int>(attacker->CastToNPC()->GetNPCStat("accuracy")));
}
}
else{
Message(0, "[#Tune] Can not melee this target");
@ -535,6 +546,7 @@ void Mob::TuneGetAccuracyByHitChance(Mob* defender, Mob *attacker, float hit_cha
for (int j = 0; j < max_loop; j++)
{
tmp_hit_chance = TuneGetHitChance(defender, attacker, avoidance_override, 0, 0, loop_add_accuracy);
if (Msg >= 3)
{
@ -559,20 +571,20 @@ void Mob::TuneGetAccuracyByHitChance(Mob* defender, Mob *attacker, float hit_cha
Message(0, "[#Tune] AVOIDANCE STAT OVERRRIDE. This is the amount of ACCURACY adjustment needed if this defender had ( %i ) raw AVOIDANCE stat", avoidance_override);
}
if (defender->IsNPC()) {
Message(0, "[#Tune] Recommended NPC ACCURACY ADJUSTMENT of ( %i ) on ' %s ' will result in ( %.0f pct ) chance to hit ' %s '.", loop_add_accuracy, defender->GetCleanName(), hit_chance, attacker->GetCleanName());
Message(0, "[#Tune] SET NPC 'ACCURACY' stat value = [ %i ]", loop_add_accuracy + defender->CastToNPC()->GetAccuracyRating());
if (attacker->IsNPC()) {
Message(0, "[#Tune] Recommended NPC ACCURACY ADJUSTMENT of ( %i ) on ' %s ' will result in ( %.0f pct ) chance to hit ' %s '.", loop_add_accuracy, attacker->GetCleanName(), hit_chance, defender->GetCleanName());
Message(0, "[#Tune] SET NPC 'ACCURACY' stat value = [ %i ]", loop_add_accuracy + attacker->CastToNPC()->GetAccuracyRating());
Message(0, "###################COMPLETE###################");
}
else if (defender->IsClient()) {
Message(0, "[#Tune] Recommended CLIENT AVOIDANCE ADJUSTMENT of ( %i ) on %s ' will result in ( %.0f pct ) chance to hit ' %s '.", loop_add_accuracy, defender->GetCleanName(), hit_chance, attacker->GetCleanName());
else if (attacker->IsClient()) {
Message(0, "[#Tune] Recommended CLIENT ACCURACY ADJUSTMENT of ( %i ) on %s ' will result in ( %.0f pct ) chance to hit ' %s '.", loop_add_accuracy, attacker->GetCleanName(), hit_chance, defender->GetCleanName());
if (loop_add_accuracy >= 0) {
Message(0, "[#Tune] OPTION1: MODIFY Client Avoidance Mod2 stat or SPA 216 Melee Accuracy (spells/items/aa) [+ %i ]", loop_add_accuracy);
Message(0, "[#Tune] MODIFY Client Accuracy Mod2 stat or SPA 216 Melee Accuracy (spells/items/aa) [+ %i ]", loop_add_accuracy);
}
else {
Message(0, "[#Tune] OPTION1: MODIFY Client Avoidance Mod2 stat or SPA 216 Melee Accuracy (spells/items/aa) [ %i ]", loop_add_accuracy);
Message(0, "[#Tune] Give Client Accuracy Mod2 stat or SPA 216 Melee Accuracy (spells/items/aa) of [ %i ]", loop_add_accuracy);
}
Message(0, "###################COMPLETE###################");
@ -586,7 +598,7 @@ void Mob::TuneGetAccuracyByHitChance(Mob* defender, Mob *attacker, float hit_cha
Message(0, "###################ABORT#######################");
Message(0, "[#Tune] Error: Unable to find desired result for ( %.0f pct) - Increase interval (%i) AND/OR max loop value (%i) and run again.", hit_chance, interval, max_loop);
Message(0, "[#Tune] Parse ended at ACCURACY ADJUSTMENT of ( %i ) on ' %s ' will result in ( %.0f pct ) chance to hit ' %s '.", loop_add_accuracy, defender->GetCleanName(), hit_chance, attacker->GetCleanName());
Message(0, "[#Tune] Parse ended at ACCURACY ADJUSTMENT of ( %i ) on ' %s ' will result in ( %.0f pct ) chance to hit ' %s '.", loop_add_accuracy, attacker->GetCleanName(), hit_chance, defender->GetCleanName());
Message(0, "###################COMPLETE###################");
}
@ -771,11 +783,11 @@ int Mob::TuneCalcEvasionBonus(int final_avoidance, int base_avoidance) {
return eb;
*/
int loop_max = 3000;
int loop_max = 5000;
int evasion_bonus = 10;
int current_avoidance = 0;
int interval = 5;
int interval = 1;
if (base_avoidance > final_avoidance)
{
@ -988,7 +1000,7 @@ void Mob::TuneDoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts,
other->TuneMeleeMitigation(this, hit, ac_override, add_ac);
if (hit.damage_done > 0) {
ApplyDamageTable(hit);
CommonOutgoingHitSuccess(other, hit, opts);
TuneCommonOutgoingHitSuccess(other, hit, opts);
}
LogCombat("Final damage after all reductions: [{}]", hit.damage_done);
}
@ -1022,8 +1034,12 @@ int Mob::TuneACSum(bool skip_caps, int ac_override, int add_ac)
ac += itembonuses.AC; // items + food + tribute
if (IsClient()) {
ac = ac_override;
ac += add_ac;
if (ac_override) {
ac = ac_override;
}
if (add_ac) {
ac += add_ac;
}
}
int shield_ac = 0;
@ -1040,10 +1056,12 @@ int Mob::TuneACSum(bool skip_caps, int ac_override, int add_ac)
}
// EQ math
ac = (ac * 4) / 3;
// anti-twink
if (!skip_caps && IsClient() && GetLevel() < RuleI(Combat, LevelToStopACTwinkControl))
ac = std::min(ac, 25 + 6 * GetLevel());
ac = std::max(0, ac + GetClassRaceACBonus());
if (IsNPC()) {
// This is the developer tweaked number
// for the VAST amount of NPCs in EQ this number didn't exceed 600 until recently (PoWar)
@ -1092,7 +1110,6 @@ int Mob::TuneACSum(bool skip_caps, int ac_override, int add_ac)
ac = softcap + (over_cap * returns);
}
}
return ac;
}
@ -1401,3 +1418,128 @@ bool Mob::TuneCheckHitChance(Mob* other, DamageHitInfo &hit, int avoidance_overr
return zone->random.Roll(50);
return tohit_roll > avoid_roll;
}
void Mob::TuneCommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttackOptions *opts)
{
if (!defender)
return;
#ifdef LUA_EQEMU
bool ignoreDefault = false;
LuaParser::Instance()->CommonOutgoingHitSuccess(this, defender, hit, opts, ignoreDefault);
if (ignoreDefault) {
return;
}
#endif
// BER weren't parsing the halving
if (hit.skill == EQ::skills::SkillArchery ||
(hit.skill == EQ::skills::SkillThrowing && GetClass() != BERSERKER))
hit.damage_done /= 2;
if (hit.damage_done < 1)
hit.damage_done = 1;
if (hit.skill == EQ::skills::SkillArchery) {
int bonus = aabonuses.ArcheryDamageModifier + itembonuses.ArcheryDamageModifier + spellbonuses.ArcheryDamageModifier;
hit.damage_done += hit.damage_done * bonus / 100;
int headshot = TryHeadShot(defender, hit.skill);
if (headshot > 0) {
hit.damage_done = headshot;
}
else if (GetClass() == RANGER && GetLevel() > 50) { // no double dmg on headshot
if ((defender->IsNPC() && !defender->IsMoving() && !defender->IsRooted()) || !RuleB(Combat, ArcheryBonusRequiresStationary)) {
hit.damage_done *= 2;
MessageString(Chat::MeleeCrit, BOW_DOUBLE_DAMAGE);
}
}
}
int extra_mincap = 0;
int min_mod = hit.base_damage * GetMeleeMinDamageMod_SE(hit.skill) / 100;
if (hit.skill == EQ::skills::SkillBackstab) {
extra_mincap = GetLevel() < 7 ? 7 : GetLevel();
if (GetLevel() >= 60)
extra_mincap = GetLevel() * 2;
else if (GetLevel() > 50)
extra_mincap = GetLevel() * 3 / 2;
if (IsSpecialAttack(eSpecialAttacks::ChaoticStab)) {
hit.damage_done = extra_mincap;
}
else {
int ass = TryAssassinate(defender, hit.skill);
if (ass > 0)
hit.damage_done = ass;
}
}
else if (hit.skill == EQ::skills::SkillFrenzy && GetClass() == BERSERKER && GetLevel() > 50) {
extra_mincap = 4 * GetLevel() / 5;
}
// this has some weird ordering
// Seems the crit message is generated before some of them :P
// worn item +skill dmg, SPA 220, 418. Live has a normalized version that should be here too
hit.min_damage += GetSkillDmgAmt(hit.skill) + GetPositionalDmgAmt(defender);
// shielding mod2
if (defender->itembonuses.MeleeMitigation)
hit.min_damage -= hit.min_damage * defender->itembonuses.MeleeMitigation / 100;
ApplyMeleeDamageMods(hit.skill, hit.damage_done, defender, opts);
min_mod = std::max(min_mod, extra_mincap);
if (min_mod && hit.damage_done < min_mod) // SPA 186
hit.damage_done = min_mod;
hit.damage_done += hit.min_damage;
if (IsClient()) {
int extra = 0;
switch (hit.skill) {
case EQ::skills::SkillThrowing:
case EQ::skills::SkillArchery:
extra = CastToClient()->GetHeroicDEX() / 10;
break;
default:
extra = CastToClient()->GetHeroicSTR() / 10;
break;
}
hit.damage_done += extra;
}
// this appears where they do special attack dmg mods
int spec_mod = 0;
if (IsSpecialAttack(eSpecialAttacks::Rampage)) {
int mod = GetSpecialAbilityParam(SPECATK_RAMPAGE, 2);
if (mod > 0)
spec_mod = mod;
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) {
//SE_PC_Pet_Rampage SPA 464 on pet, damage modifier
int spell_mod = spellbonuses.PC_Pet_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] + itembonuses.PC_Pet_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] + aabonuses.PC_Pet_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD];
if (spell_mod > spec_mod)
spec_mod = spell_mod;
}
}
else if (IsSpecialAttack(eSpecialAttacks::AERampage)) {
int mod = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 2);
if (mod > 0)
spec_mod = mod;
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) {
//SE_PC_Pet_AE_Rampage SPA 465 on pet, damage modifier
int spell_mod = spellbonuses.PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] + itembonuses.PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] + aabonuses.PC_Pet_AE_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD];
if (spell_mod > spec_mod)
spec_mod = spell_mod;
}
}
if (spec_mod > 0)
hit.damage_done = (hit.damage_done * spec_mod) / 100;
int pct_damage_reduction = defender->GetSkillDmgTaken(hit.skill, opts) + defender->GetPositionalDmgTaken(this);
hit.damage_done += (hit.damage_done * pct_damage_reduction / 100) + defender->GetPositionalDmgTakenAmt(this);
if (defender->GetShielderID()) {
DoShieldDamageOnShielder(defender, hit.damage_done, hit.skill);
hit.damage_done -= hit.damage_done * defender->GetShieldTargetMitigation() / 100; //Default shielded takes 50 pct damage
}
}