[Bots] Update Bot Heal & Damage methods to more closely match Clients + Bugfixes (#2045)

* - Fixed Bots Spell Damage being negative under some circumstances (heal target)
- Allow Bots to send non-melee damage reports in the same manner as Clients
- Refactor\Update Bots Spell Damage & Heal calculations to match current state of Clients.
- Allow Bots to actually utilize Spell Damage and Heal Amount stats

* Don't send packets to bots

* remove random tab

* align text lol
This commit is contained in:
catapultam-habeo 2022-03-11 15:28:00 -08:00 committed by GitHub
parent 3ed6663c4c
commit abcf8cbce1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 157 additions and 82 deletions

View File

@ -1709,7 +1709,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::Skill
return false; return false;
} }
if (killerMob && killerMob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) { if (killerMob && (killerMob->IsClient() || killerMob->IsBot()) && (spell != SPELL_UNKNOWN) && damage > 0) {
char val1[20] = { 0 }; char val1[20] = { 0 };
entity_list.MessageCloseString( entity_list.MessageCloseString(
@ -2293,7 +2293,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQ::skills::SkillTy
return false; return false;
} }
if (killer_mob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) { if ((killer_mob->IsClient() || killer_mob->IsBot()) && (spell != SPELL_UNKNOWN) && damage > 0) {
char val1[20] = { 0 }; char val1[20] = { 0 };
entity_list.MessageCloseString( entity_list.MessageCloseString(
@ -3935,9 +3935,8 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
} }
else { else {
//attacker is not a pet, send to the attacker //attacker is not a pet, send to the attacker
//if the attacker is a client, try them with the correct filter //if the attacker is a client, try them with the correct filter
if (attacker && attacker->IsClient()) { if (attacker && (attacker->IsClient() || attacker->IsBot())) {
if ((spell_id != SPELL_UNKNOWN || FromDamageShield) && damage > 0) { if ((spell_id != SPELL_UNKNOWN || FromDamageShield) && damage > 0) {
//special crap for spell damage, looks hackish to me //special crap for spell damage, looks hackish to me
char val1[20] = { 0 }; char val1[20] = { 0 };
@ -3958,7 +3957,8 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
); );
} }
} }
else { // Only try to queue these packets to a client
else if (attacker && (attacker->IsClient())) {
if (damage > 0) { if (damage > 0) {
if (spell_id != SPELL_UNKNOWN) if (spell_id != SPELL_UNKNOWN)
filter = iBuffTic ? FilterDOT : FilterSpellDamage; filter = iBuffTic ? FilterDOT : FilterSpellDamage;

View File

@ -6693,135 +6693,210 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
return value; return value;
bool Critical = false; bool Critical = false;
int32 value_BaseEffect = 0; int32 base_value = value;
value_BaseEffect = (value + (value*GetBotFocusEffect(focusFcBaseEffects, spell_id) / 100)); int chance = 0;
// Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40. // Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40.
if ( (spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) && GetLevel() > 40) if ((spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) && GetLevel() > 40)
value -= ((GetLevel() - 40) * 20); value -= (GetLevel() - 40) * 20;
//This adds the extra damage from the AA Unholy Touch, 450 per level to the AA Improved Harm TOuch. //This adds the extra damage from the AA Unholy Touch, 450 per level to the AA Improved Harm TOuch.
if (spell_id == SPELL_IMP_HARM_TOUCH) //Improved Harm Touch if (spell_id == SPELL_IMP_HARM_TOUCH) //Improved Harm Touch
value -= (GetAA(aaUnholyTouch) * 450); //Unholy Touch value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch
int chance = RuleI(Spells, BaseCritChance); chance = RuleI(Spells, BaseCritChance); //Wizard base critical chance is 2% (Does not scale with level)
chance += (itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance); chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
chance += itembonuses.FrenziedDevastation + spellbonuses.FrenziedDevastation + aabonuses.FrenziedDevastation;
if (chance > 0) { //Crtical Hit Calculation pathway
int32 ratio = RuleI(Spells, BaseCritRatio); if (chance > 0 || (GetClass() == WIZARD && GetLevel() >= RuleI(Spells, WizCritLevel))) {
int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals.
//Improved Harm Touch is a guaranteed crit if you have at least one level of SCF.
if (spell_id == SPELL_IMP_HARM_TOUCH && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0)) if (spell_id == SPELL_IMP_HARM_TOUCH && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0))
chance = 100; chance = 100;
if (zone->random.Int(1, 100) <= chance){ if (spells[spell_id].override_crit_chance > 0 && chance > spells[spell_id].override_crit_chance)
Critical = true; chance = spells[spell_id].override_crit_chance;
ratio += (itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease);
ratio += (itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack); if (zone->random.Roll(chance)) {
} else if (GetClass() == WIZARD && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (zone->random.Int(1, 100) <= RuleI(Spells, WizCritChance))) {
ratio = zone->random.Int(1, 100);
Critical = true; Critical = true;
ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack;
} }
ratio += RuleI(Spells, WizCritRatio);
else if (GetClass() == WIZARD || (IsMerc() && GetClass() == CASTERDPS)) {
if ((GetLevel() >= RuleI(Spells, WizCritLevel)) && zone->random.Roll(RuleI(Spells, WizCritChance))){
//Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. (20-70 is parse confirmed)
ratio += zone->random.Int(20,70);
Critical = true;
}
}
if (GetClass() == WIZARD)
ratio += RuleI(Spells, WizCritRatio); //Default is zero
if (Critical) { if (Critical) {
value = (value_BaseEffect * ratio / 100);
value += (value_BaseEffect * GetBotFocusEffect(focusImprovedDamage, spell_id) / 100); value = base_value*ratio/100;
value += (value_BaseEffect * GetBotFocusEffect(focusImprovedDamage2, spell_id) / 100);
value += (int(value_BaseEffect * GetBotFocusEffect(focusFcDamagePctCrit, spell_id) / 100) * ratio / 100); value += base_value*GetBotFocusEffect(focusImprovedDamage, spell_id)/100;
value += base_value*GetBotFocusEffect(focusImprovedDamage2, spell_id)/100;
value += int(base_value*GetBotFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
value += int(base_value*GetBotFocusEffect(focusFcAmplifyMod, spell_id) / 100)*ratio / 100;
if (target) { if (target) {
value += (int(value_BaseEffect * target->GetVulnerability(this, spell_id, 0) / 100) * ratio / 100); value += int(base_value*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
value -= target->GetFcDamageAmtIncoming(this, spell_id); value -= target->GetFcDamageAmtIncoming(this, spell_id);
} }
value -= (GetBotFocusEffect(focusFcDamageAmtCrit, spell_id) * ratio / 100); value -= GetBotFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100;
value -= GetBotFocusEffect(focusFcDamageAmt, spell_id); value -= GetBotFocusEffect(focusFcDamageAmt, spell_id);
value -= GetBotFocusEffect(focusFcDamageAmt2, spell_id); value -= GetBotFocusEffect(focusFcDamageAmt2, spell_id);
value -= GetBotFocusEffect(focusFcAmplifyAmt, spell_id);
if ((RuleB(Spells, IgnoreSpellDmgLvlRestriction) || spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) && itembonuses.SpellDmg) if ((RuleB(Spells, IgnoreSpellDmgLvlRestriction) || spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg)
value += (GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value) * ratio / 100); value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value) * ratio / 100;
entity_list.MessageClose(this, false, 100, Chat::SpellCrit, "%s delivers a critical blast! (%d)", GetName(), -value); entity_list.MessageCloseString(
this, true, 100, Chat::SpellCrit,
OTHER_CRIT_BLAST, GetName(), itoa(-value));
return value; return value;
} }
} }
//Non Crtical Hit Calculation pathway
value = base_value;
value += base_value*GetBotFocusEffect(focusImprovedDamage, spell_id)/100;
value += base_value*GetBotFocusEffect(focusImprovedDamage2, spell_id)/100;
value += base_value*GetBotFocusEffect(focusFcDamagePctCrit, spell_id)/100;
value += base_value*GetBotFocusEffect(focusFcAmplifyMod, spell_id)/100;
value = value_BaseEffect;
value += (value_BaseEffect * GetBotFocusEffect(focusImprovedDamage, spell_id) / 100);
value += (value_BaseEffect * GetBotFocusEffect(focusImprovedDamage2, spell_id) / 100);
value += (value_BaseEffect * GetBotFocusEffect(focusFcDamagePctCrit, spell_id) / 100);
if (target) { if (target) {
value += (value_BaseEffect * target->GetVulnerability(this, spell_id, 0) / 100); value += base_value*target->GetVulnerability(this, spell_id, 0)/100;
value -= target->GetFcDamageAmtIncoming(this, spell_id); value -= target->GetFcDamageAmtIncoming(this, spell_id);
} }
value -= GetBotFocusEffect(focusFcDamageAmtCrit, spell_id); value -= GetBotFocusEffect(focusFcDamageAmtCrit, spell_id);
value -= GetBotFocusEffect(focusFcDamageAmt, spell_id); value -= GetBotFocusEffect(focusFcDamageAmt, spell_id);
value -= GetBotFocusEffect(focusFcDamageAmt2, spell_id); value -= GetBotFocusEffect(focusFcDamageAmt2, spell_id);
value -= GetBotFocusEffect(focusFcAmplifyAmt, spell_id);
if ((RuleB(Spells, IgnoreSpellDmgLvlRestriction) || spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) && itembonuses.SpellDmg) if ((RuleB(Spells, IgnoreSpellDmgLvlRestriction) || spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg)
value += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value);
return value; return value;
} }
int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
if (target == nullptr) if (target == nullptr)
target = this; target = this;
int32 value_BaseEffect = 0; int32 base_value = value;
int32 chance = 0; int16 critical_chance = 0;
int8 modifier = 1; int8 critical_modifier = 1;
bool Critical = false;
value_BaseEffect = (value + (value*GetBotFocusEffect(focusFcBaseEffects, spell_id) / 100));
value = value_BaseEffect;
value += int(value_BaseEffect*GetBotFocusEffect(focusImprovedHeal, spell_id) / 100);
if(spells[spell_id].buff_duration < 1) {
chance += (itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance);
chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);
if (spellbonuses.CriticalHealDecay)
chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay);
if(chance && (zone->random.Int(0, 99) < chance)) { if (spells[spell_id].buff_duration < 1) {
Critical = true; critical_chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;
modifier = 2;
if (spellbonuses.CriticalHealDecay) {
critical_chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay);
}
}
else {
critical_chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime;
if (spellbonuses.CriticalRegenDecay) {
critical_chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay);
}
}
if (critical_chance) {
if (spells[spell_id].override_crit_chance > 0 && critical_chance > spells[spell_id].override_crit_chance) {
critical_chance = spells[spell_id].override_crit_chance;
} }
value *= modifier; if (zone->random.Roll(critical_chance)) {
value += (GetBotFocusEffect(focusFcHealAmtCrit, spell_id) * modifier); critical_modifier = 2; //At present time no critical heal amount modifier SPA exists.
value += GetBotFocusEffect(focusFcHealAmt, spell_id); }
value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); }
//Using IgnoreSpellDmgLvlRestriction if (GetClass() == CLERIC) {
if ((RuleB(Spells, IgnoreSpellDmgLvlRestriction) || spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) && itembonuses.HealAmt) value += int(base_value*RuleI(Spells, ClericInnateHealFocus) / 100); //confirmed on live parsing clerics get an innate 5 pct heal focus
value += (GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier); }
value += (value * target->GetHealRate() / 100); value += int(base_value*GetBotFocusEffect(focusImprovedHeal, spell_id) / 100);
if (Critical) value += int(base_value*GetBotFocusEffect(focusFcAmplifyMod, spell_id) / 100);
entity_list.MessageClose(this, false, 100, Chat::SpellCrit, "%s performs an exceptional heal! (%d)", GetName(), value);
// Instant Heals
if (spells[spell_id].buff_duration < 1) {
/* Mob::GetFocusEffect is not accessible from this context. This focus effect was not accounted for in previous version of this method at all, either
if (target) {
value += int(base_value * target->GetFocusEffect(focusFcHealPctIncoming, spell_id, this)/100,nullptr); //SPA 393 Add before critical
value += int(base_value * target->GetFocusEffect(focusFcHealPctCritIncoming, spell_id, this)/100,nullptr); //SPA 395 Add before critical (?)
}
*/
value += GetBotFocusEffect(focusFcHealAmtCrit, spell_id); //SPA 396 Add before critical
//Using IgnoreSpellDmgLvlRestriction to also allow healing to scale
if ((RuleB(Spells, IgnoreSpellDmgLvlRestriction) || spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) && !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 (target) {
value += value * target->GetHealRate() / 100; //SPA 120 modifies value after Focus Applied but before critical
}
/*
Apply critical hit modifier
*/
value *= critical_modifier;
value += GetBotFocusEffect(focusFcHealAmt, spell_id); //SPA 392 Add after critical
value += GetBotFocusEffect(focusFcAmplifyAmt, spell_id); //SPA 508 ? Add after critical
/*
if (target) {
value += target->GetBotFocusEffect(focusFcHealAmtIncoming, spell_id, this); //SPA 394 Add after critical
}
*/
if (critical_modifier > 1) {
entity_list.MessageCloseString(
this, true, 100, Chat::SpellCrit,
OTHER_CRIT_HEAL, GetName(), itoa(value));
}
return value; return value;
} else { }
int32 extra_heal = 0;
//Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value]
else {
//Using IgnoreSpellDmgLvlRestriction to also allow healing to scale //Using IgnoreSpellDmgLvlRestriction to also allow healing to scale
if (RuleB(Spells, HOTsScaleWithHealAmt)) { if (RuleB(Spells, HOTsScaleWithHealAmt)) {
if ((RuleB(Spells, IgnoreSpellDmgLvlRestriction) || spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) && itembonuses.HealAmt)
extra_heal += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value);
}
if (extra_heal) {
int duration = CalcBuffDuration(this, target, spell_id); int duration = CalcBuffDuration(this, target, spell_id);
if (duration > 0) { int32 extra_heal = 0;
if ((RuleB(Spells, IgnoreSpellDmgLvlRestriction) || spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt) {
extra_heal += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, base_value);
}
if (duration > 0 && extra_heal > 0) {
extra_heal /= duration; extra_heal /= duration;
value += extra_heal; value += extra_heal;
} }
} }
chance = (itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime); if (critical_chance && zone->random.Roll(critical_chance))
chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); value *= critical_modifier;
if (spellbonuses.CriticalRegenDecay)
chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay);
if(chance && (zone->random.Int(0,99) < chance))
return (value * 2);
} }
return value; return value;
} }