[Spells] Rework for SPA 413 SE_FcBaseEffects and Bard updates (#1629)

* baseline start

* update1

* updates

* base effect implemented for bard

* instrument mod updates

amplification amps itself

* updates

* updates

* debug

* base effect updates

* baseeffects for spell focus updated

* update skill attack baseeffects

* focus will remain for quest functions

* song cap mod added back in

* remove debugs1

* fix cr

* base effects functionalish

* remove debug

* Update client_mods.cpp

* spdat instrumentmod

* Update spell_effects.cpp

* Update spdat.h

* remove new instrument mod check

split PR
This commit is contained in:
KayenEQ 2021-10-24 19:38:28 -04:00 committed by GitHub
parent 060be606e7
commit 987de17e93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 179 additions and 121 deletions

View File

@ -815,7 +815,7 @@ typedef enum {
#define SE_Hunger 115 // implemented - Song of Sustenance #define SE_Hunger 115 // implemented - Song of Sustenance
#define SE_CurseCounter 116 // implemented #define SE_CurseCounter 116 // implemented
#define SE_MagicWeapon 117 // implemented - makes weapon magical #define SE_MagicWeapon 117 // implemented - makes weapon magical
#define SE_Amplification 118 // implemented - Harmonize/Amplification (stacks with other singing mods) #define SE_Amplification 118 // implemented, @Song, stackable singing mod, base: mod%, limit: none, max: none, Note: Can focus itself.
#define SE_AttackSpeed3 119 // implemented #define SE_AttackSpeed3 119 // implemented
#define SE_HealRate 120 // implemented - reduces healing by a % #define SE_HealRate 120 // implemented - reduces healing by a %
#define SE_ReverseDS 121 // implemented #define SE_ReverseDS 121 // implemented
@ -876,7 +876,7 @@ typedef enum {
#define SE_DualWieldChance 176 // implemented #define SE_DualWieldChance 176 // implemented
#define SE_DoubleAttackChance 177 // implemented #define SE_DoubleAttackChance 177 // implemented
#define SE_MeleeLifetap 178 // implemented #define SE_MeleeLifetap 178 // implemented
#define SE_AllInstrumentMod 179 // implemented #define SE_AllInstrumentMod 179 // implemented, @Song, set mod for ALL instrument/singing skills that will be used if higher then item mods, base: mod%, limit: none, max: none
#define SE_ResistSpellChance 180 // implemented #define SE_ResistSpellChance 180 // implemented
#define SE_ResistFearChance 181 // implemented #define SE_ResistFearChance 181 // implemented
#define SE_HundredHands 182 // implemented #define SE_HundredHands 182 // implemented
@ -957,8 +957,8 @@ typedef enum {
#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold - official name is GivePetHold #define SE_PetDiscipline 257 // not implemented as bonus - /pet hold - official name is GivePetHold
#define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab #define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab
#define SE_CombatStability 259 // implemented[AA] - damage mitigation #define SE_CombatStability 259 // implemented[AA] - damage mitigation
#define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType #define SE_AddSingingMod 260 // implemented, @Song, set mod for specific instrument/singing skills that will be used if higher then item mods, base: mod%, limit: ItemType ID, max: none
#define SE_SongModCap 261 // implemented[AA] - Song Mod cap increase (no longer used on live) #define SE_SongModCap 261 // implemented, @Song, raise max song modifier cap, base: amt, limit: none, max: none, Note: No longer used on live
#define SE_RaiseStatCap 262 // implemented #define SE_RaiseStatCap 262 // implemented
#define SE_TradeSkillMastery 263 // implemented - lets you raise more than one tradeskill above master. #define SE_TradeSkillMastery 263 // implemented - lets you raise more than one tradeskill above master.
#define SE_HastenedAASkill 264 // implemented #define SE_HastenedAASkill 264 // implemented
@ -967,7 +967,7 @@ typedef enum {
#define SE_AddPetCommand 267 // implemented - sets command base2 to base1 #define SE_AddPetCommand 267 // implemented - sets command base2 to base1
#define SE_ReduceTradeskillFail 268 // implemented - reduces chance to fail with given tradeskill by a percent chance #define SE_ReduceTradeskillFail 268 // implemented - reduces chance to fail with given tradeskill by a percent chance
#define SE_MaxBindWound 269 // implemented[AA] - Increase max HP you can bind wound. #define SE_MaxBindWound 269 // implemented[AA] - Increase max HP you can bind wound.
#define SE_BardSongRange 270 // implemented[AA] - increase range of beneficial bard songs (Sionachie's Crescendo) #define SE_BardSongRange 270 // implemented, @Song, increase range of beneficial bard songs, base: mod%, limit: none, max: none , Note: example Sionachie's Crescendo
#define SE_BaseMovementSpeed 271 // implemented[AA] - mods basemove speed, doesn't stack with other move mods #define SE_BaseMovementSpeed 271 // implemented[AA] - mods basemove speed, doesn't stack with other move mods
#define SE_CastingLevel2 272 // implemented #define SE_CastingLevel2 272 // implemented
#define SE_CriticalDoTChance 273 // implemented #define SE_CriticalDoTChance 273 // implemented

View File

@ -1687,6 +1687,10 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
newbon->SpellDamageShield += base1; newbon->SpellDamageShield += base1;
break; break;
case SE_Amplification:
newbon->Amplification += base1;
break;
// to do // to do
case SE_PetDiscipline: case SE_PetDiscipline:
break; break;
@ -1795,18 +1799,19 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
if (focus) if (focus)
{ {
if (WornType){ if (WornType){
if (RuleB(Spells, UseAdditiveFocusFromWornSlot)) if (RuleB(Spells, UseAdditiveFocusFromWornSlot)) {
new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base[i]; new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base[i];
}
} }
else {
else
new_bonus->FocusEffects[focus] = static_cast<uint8>(spells[spell_id].effectid[i]); new_bonus->FocusEffects[focus] = static_cast<uint8>(spells[spell_id].effectid[i]);
}
continue; continue;
} }
if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType)) if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType)) {
AdditiveWornBonus = true; AdditiveWornBonus = true;
}
effectid = spells[spell_id].effectid[i]; effectid = spells[spell_id].effectid[i];
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, instrument_mod, nullptr, ticsremaining, casterId); effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, instrument_mod, nullptr, ticsremaining, casterId);

View File

@ -1508,22 +1508,25 @@ int32 Client::CalcATK()
return (ATK); return (ATK);
} }
uint32 Mob::GetInstrumentMod(uint16 spell_id) const uint32 Mob::GetInstrumentMod(uint16 spell_id)
{ {
if (GetClass() != BARD || spells[spell_id].IsDisciplineBuff) // Puretone is Singing but doesn't get any mod if (GetClass() != BARD) {
//Other classes can get a base effects mod using SPA 413
if (HasBaseEffectFocus()) {
return (10 + (GetFocusEffect(focusFcBaseEffects, spell_id) / 10));//TODO: change action->instrument mod to float to support < 10% focus values
}
return 10; return 10;
}
uint32 effectmod = 10; uint32 effectmod = 10;
int effectmodcap = 0; int effectmodcap = 0;
bool nocap = false;
if (RuleB(Character, UseSpellFileSongCap)) { if (RuleB(Character, UseSpellFileSongCap)) {
effectmodcap = spells[spell_id].songcap / 10; effectmodcap = spells[spell_id].songcap / 10;
// this looks a bit weird, but easiest way I could think to keep both systems working if (effectmodcap) {
if (effectmodcap == 0) effectmodcap += 10; //Actual calculated cap is 100 greater than songcap value.
nocap = true; }
else }
effectmodcap += 10; else {
} else {
effectmodcap = RuleI(Character, BaseInstrumentSoftCap); effectmodcap = RuleI(Character, BaseInstrumentSoftCap);
} }
// this should never use spell modifiers... // this should never use spell modifiers...
@ -1532,6 +1535,39 @@ uint32 Mob::GetInstrumentMod(uint16 spell_id) const
// item mods are in 10ths of percent increases // item mods are in 10ths of percent increases
// clickies (Symphony of Battle) that have a song skill don't get AA bonus for some reason // clickies (Symphony of Battle) that have a song skill don't get AA bonus for some reason
// but clickies that are songs (selo's on Composers Greaves) do get AA mod as well // but clickies that are songs (selo's on Composers Greaves) do get AA mod as well
/*Mechanics: updated 10/19/21 ~Kayen
Bard Spell Effects
Mod uses the highest bonus from either of these for each instrument
SPA 179 SE_AllInstrumentMod is used for instrument spellbonus.______Mod. This applies to ALL instrument mods (Puretones Discipline)
SPA 260 SE_AddSingingMod is used for instrument spellbonus.______Mod. This applies to indiviual instrument mods. (Instrument mastery AA)
-Example usage: From AA a value of 4 = 40%
SPA 118 SE_Amplification is a stackable singing mod, on live it exists as both spell and AA bonus (stackable)
- Live Behavior: Amplifcation can be modified by singing mods and amplification itself, thus on the second cast of Amplification you will recieve
the mod from the first cast, this continues until you reach the song mod cap.
SPA 261 SE_SongModCap raises song focus cap (No longer used on live)
SPA 270 SE_BardSongRange increase range of beneficial bard songs (Sionachie's Crescendo)
SPA 413 SE_FcBaseEffects focus effect that replaced item instrument mods
Issues 10-15-21:
Bonuses are not applied, unless song is stopped and restarted due to pulse keeping it continues. -> Need to recode songs to recast when duration ends.
Formula Live Bards:
mod = (10 + (aabonus.____Mod [SPA 260 AA Instrument Mastery]) + (SE_FcBaseEffect[SPA 413])/10 + (spellbonus.______Mod [SPA 179 Puretone Disc]) + (Amplication [SPA 118])/10
TODO: Spell Table Fields that need to be implemented
Field 225 //float base_effects_focus_slope; // -- BASE_EFFECTS_FOCUS_SLOPE
Field 226 //float base_effects_focus_offset; // -- BASE_EFFECTS_FOCUS_OFFSET (35161 Ruaabri's Reckless Renewal -120)
Based on description possibly works as a way to quickly balance instrument mods to a song.
Using a standard slope formula: y = mx + b
modified_base_value = (base_effects_focus_slope x effectmod)(base_value) + (base_effects_focus_offset)
Will need to confirm on live before implementing.
*/
switch (spells[spell_id].skill) { switch (spells[spell_id].skill) {
case EQ::skills::SkillPercussionInstruments: case EQ::skills::SkillPercussionInstruments:
if (itembonuses.percussionMod == 0 && spellbonuses.percussionMod == 0) if (itembonuses.percussionMod == 0 && spellbonuses.percussionMod == 0)
@ -1589,18 +1625,34 @@ uint32 Mob::GetInstrumentMod(uint16 spell_id) const
else else
effectmod = spellbonuses.singingMod; effectmod = spellbonuses.singingMod;
if (IsBardSong(spell_id)) if (IsBardSong(spell_id))
effectmod += aabonuses.singingMod + spellbonuses.Amplification; effectmod += aabonuses.singingMod + (spellbonuses.Amplification + itembonuses.Amplification + aabonuses.Amplification); //SPA 118 SE_Amplification
break; break;
default: default:
effectmod = 10; effectmod = 10;
return effectmod; return effectmod;
} }
if (!RuleB(Character, UseSpellFileSongCap))
effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap; if (HasBaseEffectFocus()) {
if (effectmod < 10) effectmod += (GetFocusEffect(focusFcBaseEffects, spell_id) / 10);
}
if (effectmod < 10) {
effectmod = 10; effectmod = 10;
if (!nocap && effectmod > effectmodcap) // if the cap is calculated to be 0 using new rules, no cap. }
effectmod = effectmodcap;
if (effectmodcap) {
effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap; //SPA 261 SE_SongModCap (not used on live)
//Incase a negative modifier is used.
if (effectmodcap <= 0) {
effectmodcap = 10;
}
if (effectmod > effectmodcap) { // if the cap is calculated to be 0 using new rules, no cap.
effectmod = effectmodcap;
}
}
LogSpells("[{}]::GetInstrumentMod() spell=[{}] mod=[{}] modcap=[{}]\n", GetName(), spell_id, effectmod, effectmodcap); LogSpells("[{}]::GetInstrumentMod() spell=[{}] mod=[{}] modcap=[{}]\n", GetName(), spell_id, effectmod, effectmodcap);

View File

@ -49,11 +49,9 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
value += value*CastToNPC()->GetSpellFocusDMG()/100; value += value*CastToNPC()->GetSpellFocusDMG()/100;
bool Critical = false; bool Critical = false;
int32 value_BaseEffect = 0; int32 base_value = value;
int chance = 0; int chance = 0;
value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);
// 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;
@ -97,16 +95,16 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
if (Critical){ if (Critical){
value = value_BaseEffect*ratio/100; value = base_value*ratio/100;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100; value += base_value*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage2, spell_id)/100; value += base_value*GetFocusEffect(focusImprovedDamage2, spell_id)/100;
value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100; value += int(base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
value += int(value_BaseEffect*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100)*ratio / 100; value += int(base_value*GetFocusEffect(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);
} }
@ -117,10 +115,10 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
value -= GetFocusEffect(focusFcAmplifyAmt, spell_id); value -= GetFocusEffect(focusFcAmplifyAmt, spell_id);
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg)
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value_BaseEffect)*ratio / 100; 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) 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, value_BaseEffect)*ratio/100; value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value)*ratio/100;
else if (IsNPC() && CastToNPC()->GetSpellScale()) else if (IsNPC() && CastToNPC()->GetSpellScale())
value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f); value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f);
@ -136,16 +134,16 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
} }
} }
//Non Crtical Hit Calculation pathway //Non Crtical Hit Calculation pathway
value = value_BaseEffect; value = base_value;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100; value += base_value*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage2, spell_id)/100; value += base_value*GetFocusEffect(focusImprovedDamage2, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100; value += base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusFcAmplifyMod, spell_id)/100; value += base_value*GetFocusEffect(focusFcAmplifyMod, 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);
} }
@ -156,10 +154,10 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
value -= GetFocusEffect(focusFcAmplifyAmt, spell_id); value -= GetFocusEffect(focusFcAmplifyAmt, spell_id);
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg)
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value_BaseEffect); 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) 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, value_BaseEffect); value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value);
if (IsNPC() && CastToNPC()->GetSpellScale()) if (IsNPC() && CastToNPC()->GetSpellScale())
value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f); value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f);
@ -199,10 +197,11 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
if (target == nullptr) if (target == nullptr)
return value; return value;
if (IsNPC()) if (IsNPC()) {
value += value*CastToNPC()->GetSpellFocusDMG()/100; value += value * CastToNPC()->GetSpellFocusDMG() / 100;
}
int32 value_BaseEffect = 0; int32 base_value = value;
int32 extra_dmg = 0; int32 extra_dmg = 0;
int16 chance = 0; int16 chance = 0;
chance += itembonuses.CriticalDoTChance + spellbonuses.CriticalDoTChance + aabonuses.CriticalDoTChance; chance += itembonuses.CriticalDoTChance + spellbonuses.CriticalDoTChance + aabonuses.CriticalDoTChance;
@ -213,17 +212,15 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
if (spells[spell_id].override_crit_chance > 0 && chance > spells[spell_id].override_crit_chance) if (spells[spell_id].override_crit_chance > 0 && chance > spells[spell_id].override_crit_chance)
chance = spells[spell_id].override_crit_chance; chance = spells[spell_id].override_crit_chance;
value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);
if (chance > 0 && (zone->random.Roll(chance))) { if (chance > 0 && (zone->random.Roll(chance))) {
int32 ratio = 200; int32 ratio = 200;
ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease; ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease;
value = value_BaseEffect*ratio/100; value = base_value*ratio/100;
value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100; value += int(base_value*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100;
value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage2, spell_id)/100)*ratio/100; value += int(base_value*GetFocusEffect(focusImprovedDamage2, spell_id)/100)*ratio/100;
value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100; value += int(base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
value += int(value_BaseEffect*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100)*ratio/100; value += int(base_value*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100)*ratio/100;
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;
extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) + extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) + int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) +
GetFocusEffect(focusFcDamageAmt, spell_id) + GetFocusEffect(focusFcDamageAmt, spell_id) +
@ -240,12 +237,12 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
} }
else { else {
value = value_BaseEffect; value = base_value;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100; value += base_value*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage2, spell_id)/100; value += base_value*GetFocusEffect(focusImprovedDamage2, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100; value += base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusFcAmplifyMod, spell_id)/100; value += base_value*GetFocusEffect(focusFcAmplifyMod, spell_id)/100;
value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100; value += base_value*target->GetVulnerability(this, spell_id, 0)/100;
extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) + extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
GetFocusEffect(focusFcDamageAmtCrit, spell_id) + GetFocusEffect(focusFcDamageAmtCrit, spell_id) +
GetFocusEffect(focusFcDamageAmt, spell_id) + GetFocusEffect(focusFcDamageAmt, spell_id) +
@ -301,7 +298,7 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
value += value * CastToNPC()->GetSpellFocusHeal() / 100; value += value * CastToNPC()->GetSpellFocusHeal() / 100;
} }
int32 value_BaseEffect = 0; int32 base_value = value;
int16 critical_chance = 0; int16 critical_chance = 0;
int8 critical_modifier = 1; int8 critical_modifier = 1;
@ -331,28 +328,24 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
} }
} }
value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id) / 100);
value = value_BaseEffect;
if (GetClass() == CLERIC) { if (GetClass() == CLERIC) {
value += int(value_BaseEffect*RuleI(Spells, ClericInnateHealFocus) / 100); //confirmed on live parsing clerics get an innate 5 pct heal focus value += int(base_value*RuleI(Spells, ClericInnateHealFocus) / 100); //confirmed on live parsing clerics get an innate 5 pct heal focus
} }
value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id) / 100); value += int(base_value*GetFocusEffect(focusImprovedHeal, spell_id) / 100);
value += int(value_BaseEffect*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100); value += int(base_value*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100);
// Instant Heals // Instant Heals
if (spells[spell_id].buffduration < 1) { if (spells[spell_id].buffduration < 1) {
if (target) { if (target) {
value += int(value_BaseEffect * target->GetFocusEffect(focusFcHealPctIncoming, spell_id)/100); //SPA 393 Add before critical value += int(base_value * target->GetFocusEffect(focusFcHealPctIncoming, spell_id)/100); //SPA 393 Add before critical
value += int(value_BaseEffect * target->GetFocusEffect(focusFcHealPctCritIncoming, spell_id)/100); //SPA 395 Add before critical (?) value += int(base_value * target->GetFocusEffect(focusFcHealPctCritIncoming, spell_id)/100); //SPA 395 Add before critical (?)
} }
value += GetFocusEffect(focusFcHealAmtCrit, spell_id); //SPA 396 Add before critical value += GetFocusEffect(focusFcHealAmtCrit, spell_id); //SPA 396 Add before critical
if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) { 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, value_BaseEffect); //Item Heal Amt Add before critical value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, base_value); //Item Heal Amt Add before critical
} }
if (target) { if (target) {

View File

@ -834,7 +834,6 @@ public:
int16 GetPositionalDmgAmt(Mob* defender); int16 GetPositionalDmgAmt(Mob* defender);
inline bool CanBlockSpell() const { return(spellbonuses.FocusEffects[focusBlockNextSpell]); } inline bool CanBlockSpell() const { return(spellbonuses.FocusEffects[focusBlockNextSpell]); }
bool DoHPToManaCovert(uint16 mana_cost = 0); bool DoHPToManaCovert(uint16 mana_cost = 0);
int32 ApplySpellEffectiveness(int16 spell_id, int32 value, bool IsBard = false, uint16 caster_id=0);
int8 GetDecayEffectValue(uint16 spell_id, uint16 spelleffect); int8 GetDecayEffectValue(uint16 spell_id, uint16 spelleffect);
int32 GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg); int32 GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg);
void MeleeLifeTap(int32 damage); void MeleeLifeTap(int32 damage);
@ -851,6 +850,7 @@ public:
int GetFocusRandomEffectivenessValue(int focus_base, int focus_base2, bool best_focus = 0); int GetFocusRandomEffectivenessValue(int focus_base, int focus_base2, bool best_focus = 0);
int GetHealRate() const { return itembonuses.HealRate + spellbonuses.HealRate + aabonuses.HealRate; } int GetHealRate() const { return itembonuses.HealRate + spellbonuses.HealRate + aabonuses.HealRate; }
int GetMemoryBlurChance(int base_chance); int GetMemoryBlurChance(int base_chance);
inline bool HasBaseEffectFocus() const { return (spellbonuses.FocusEffects[focusFcBaseEffects] || aabonuses.FocusEffects[focusFcBaseEffects] || itembonuses.FocusEffects[focusFcBaseEffects]); }
bool TryDoubleMeleeRoundEffect(); bool TryDoubleMeleeRoundEffect();
bool GetUseDoubleMeleeRoundDmgBonus() const { return use_double_melee_round_dmg_bonus; } bool GetUseDoubleMeleeRoundDmgBonus() const { return use_double_melee_round_dmg_bonus; }
@ -1113,7 +1113,8 @@ public:
virtual int32 CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc = false); virtual int32 CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc = false);
virtual int32 CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possible = 0); virtual int32 CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possible = 0);
uint32 GetInstrumentMod(uint16 spell_id) const; //uint32 GetInstrumentMod(uint16 spell_id) const;
uint32 GetInstrumentMod(uint16 spell_id);
int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0,uint16 casterid=0); int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0,uint16 casterid=0);
int CalcSpellEffectValue_formula(int formula, int base, int max, int caster_level, uint16 spell_id, int ticsremaining = 0); int CalcSpellEffectValue_formula(int formula, int base, int max, int caster_level, uint16 spell_id, int ticsremaining = 0);
virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr, int buffslot = -1); virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr, int buffslot = -1);

View File

@ -838,9 +838,9 @@ void Mob::DoArcheryAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, co
return; return;
} }
// unsure when this should happen if (focus) {
if (focus) // From FcBaseEffects
WDmg += WDmg * focus / 100; WDmg += WDmg * focus / 100;
}
if (WDmg > 0 || ADmg > 0) { if (WDmg > 0 || ADmg > 0) {
if (WDmg < 0) if (WDmg < 0)
@ -2158,8 +2158,9 @@ void Mob::DoMeleeSkillAttackDmg(Mob *other, uint16 weapon_damage, EQ::skills::Sk
hate = weapon_damage; hate = weapon_damage;
if (weapon_damage > 0) { if (weapon_damage > 0) {
if (focus) // From FcBaseEffects if (focus) {
weapon_damage += weapon_damage * focus / 100; weapon_damage += weapon_damage * focus / 100;
}
if (skillinuse == EQ::skills::SkillBash) { if (skillinuse == EQ::skills::SkillBash) {
if (IsClient()) { if (IsClient()) {

View File

@ -197,6 +197,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
// if buff slot, use instrument mod there, otherwise calc it // if buff slot, use instrument mod there, otherwise calc it
uint32 instrument_mod = buffslot > -1 ? buffs[buffslot].instrument_mod : caster ? caster->GetInstrumentMod(spell_id) : 10; uint32 instrument_mod = buffslot > -1 ? buffs[buffslot].instrument_mod : caster ? caster->GetInstrumentMod(spell_id) : 10;
// iterate through the effects in the spell // iterate through the effects in the spell
for (i = 0; i < EFFECT_COUNT; i++) for (i = 0; i < EFFECT_COUNT; i++)
{ {
@ -1325,9 +1326,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
#ifdef SPELL_EFFECT_SPAM #ifdef SPELL_EFFECT_SPAM
snprintf(effect_desc, _EDLEN, "Melee Absorb Rune: %+i", effect_value); snprintf(effect_desc, _EDLEN, "Melee Absorb Rune: %+i", effect_value);
#endif #endif
if (caster)
effect_value = caster->ApplySpellEffectiveness(spell_id, effect_value);
buffs[buffslot].melee_rune = effect_value; buffs[buffslot].melee_rune = effect_value;
break; break;
} }
@ -2356,22 +2354,20 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
???? = spells[spell_id].max[i] - MOST of the effects have this value. ???? = spells[spell_id].max[i] - MOST of the effects have this value.
*Max is lower value then Weapon base, possibly min hit vs Weapon Damage range ie. MakeRandInt(max,base) *Max is lower value then Weapon base, possibly min hit vs Weapon Damage range ie. MakeRandInt(max,base)
*/ */
int16 focus = 0;
int ReuseTime = spells[spell_id].recast_time + spells[spell_id].recovery_time; int ReuseTime = spells[spell_id].recast_time + spells[spell_id].recovery_time;
if (!caster) if (!caster) {
break; break;
}
focus = caster->GetFocusEffect(focusFcBaseEffects, spell_id);
switch(spells[spell_id].skill) { switch(spells[spell_id].skill) {
case EQ::skills::SkillThrowing: case EQ::skills::SkillThrowing:
caster->DoThrowingAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i], focus, ReuseTime); caster->DoThrowingAttackDmg(this, nullptr, nullptr, effect_value,spells[spell_id].base2[i], 0, ReuseTime);
break; break;
case EQ::skills::SkillArchery: case EQ::skills::SkillArchery:
caster->DoArcheryAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i],focus, ReuseTime); caster->DoArcheryAttackDmg(this, nullptr, nullptr, effect_value,spells[spell_id].base2[i], 0, ReuseTime);
break; break;
default: default:
caster->DoMeleeSkillAttackDmg(this, spells[spell_id].base[i], spells[spell_id].skill, spells[spell_id].base2[i], focus, false, ReuseTime); caster->DoMeleeSkillAttackDmg(this, effect_value, spells[spell_id].skill, spells[spell_id].base2[i], 0, false, ReuseTime);
break; break;
} }
break; break;
@ -3335,9 +3331,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
} }
int Mob::CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level, uint32 instrument_mod, Mob *caster, int Mob::CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level, uint32 instrument_mod, Mob *caster,
int ticsremaining, uint16 caster_id) int ticsremaining, uint16 caster_id)
{ {
int formula, base, max, effect_value; int formula, base, max, effect_value, oval;
if (!IsValidSpell(spell_id) || effect_id < 0 || effect_id >= EFFECT_COUNT) if (!IsValidSpell(spell_id) || effect_id < 0 || effect_id >= EFFECT_COUNT)
return 0; return 0;
@ -3355,16 +3351,49 @@ int Mob::CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level,
if (EQ::skills::IsBardInstrumentSkill(spells[spell_id].skill) if (EQ::skills::IsBardInstrumentSkill(spells[spell_id].skill)
&& IsInstrumentModAppliedToSpellEffect(spell_id, spells[spell_id].effectid[effect_id])){ && IsInstrumentModAppliedToSpellEffect(spell_id, spells[spell_id].effectid[effect_id])){
oval = effect_value;
effect_value = effect_value * instrument_mod / 10;
int oval = effect_value;
int mod = ApplySpellEffectiveness(spell_id, instrument_mod, true, caster_id);
effect_value = effect_value * mod / 10;
LogSpells("Effect value [{}] altered with bard modifier of [{}] to yeild [{}]", LogSpells("Effect value [{}] altered with bard modifier of [{}] to yeild [{}]",
oval, mod, effect_value); oval, instrument_mod, effect_value);
}
/*
SPA 413 SE_FcBaseEffects, modifies base value of a spell effect after formula calcultion, but before other focuses.
This is applied to non-Bards in Mob::GetInstrumentMod
Like bard modifiers, this is sent in the action_struct using action->instrument_mod (which is a base effect modifier)
Issue: value sent with action->instrument_mod needs to be 10 or higher. Therefore lowest possible percent chance would be 11 (calculated to 10%)
there are modern spells that use less than 10% but we send as a uint where lowest value has to be 10, where it should be a float for current clients.
Though not ideal, at the moment for spells that are instant effects, the action packet doesn't matter and we will calculate the actual percent here correctly.
Logic here is, caster_id is only sent from ApplySpellBonuses. Thus if it is a buff a long as the base effects is set to over 10% and at +10% intervals
it will focus the base value correctly.
*/
if (GetClass() != BARD) {
if (caster_id && instrument_mod > 10) {
//This is checked from Mob::ApplySpellBonuses, applied to buffs that receive bonuses. See above, must be in 10% intervals to work.
oval = effect_value;
effect_value = effect_value * instrument_mod / 10;
LogSpells("Bonus Effect value [{}] altered with base effects modifier of [{}] to yeild [{}]",
oval, instrument_mod, effect_value);
}
else if (!caster_id) {
//This is checked from Mob::SpellEffects and applied to instant spells and runes.
if (caster && caster->HasBaseEffectFocus()) {
oval = effect_value;
int mod = caster->GetFocusEffect(focusFcBaseEffects, spell_id);
effect_value += effect_value * mod / 100;
LogSpells("Instant Effect value [{}] altered with base effects modifier of [{}] to yeild [{}]",
oval, mod, effect_value);
}
}
} }
effect_value = mod_effect_value(effect_value, spell_id, spells[spell_id].effectid[effect_id], caster, caster_id); effect_value = mod_effect_value(effect_value, spell_id, spells[spell_id].effectid[effect_id], caster, caster_id);
return effect_value; return effect_value;
} }
@ -3505,7 +3534,8 @@ snare has both of them negative, yet their range should work the same:
break; break;
case 119: // confirmed 2/6/04 case 119: // confirmed 2/6/04
result = ubase + (caster_level / 8); break; result = ubase + (caster_level / 8);
break;
case 120: case 120:
{ {
int ticdif = CalcBuffDuration_formula(caster_level, spells[spell_id].buffdurationformula, spells[spell_id].buffduration) - std::max((ticsremaining - 1), 0); int ticdif = CalcBuffDuration_formula(caster_level, spells[spell_id].buffdurationformula, spells[spell_id].buffduration) - std::max((ticsremaining - 1), 0);
@ -6994,30 +7024,6 @@ int32 Mob::GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spel
return value; return value;
} }
int32 Mob::ApplySpellEffectiveness(int16 spell_id, int32 value, bool IsBard, uint16 caster_id) {
// 9-17-12: This is likely causing crashes, disabled till can resolve.
if (IsBard)
return value;
Mob* caster = this;
if (caster_id && caster_id != GetID())//Make sure we are checking the casters focus
caster = entity_list.GetMob(caster_id);
if (!caster)
return value;
int16 focus = caster->GetFocusEffect(focusFcBaseEffects, spell_id);
if (IsBard)
value += focus;
else
value += value*focus/100;
return value;
}
bool Mob::PassLimitClass(uint32 Classes_, uint16 Class_) bool Mob::PassLimitClass(uint32 Classes_, uint16 Class_)
{ {
//The class value for SE_LimitClass is +1 to its equivelent value in item dbase //The class value for SE_LimitClass is +1 to its equivelent value in item dbase