Revision to spell damage calculations

This commit is contained in:
KayenEQ 2014-02-02 23:23:41 -05:00
parent 8b1262b198
commit 72cec5608d
16 changed files with 478 additions and 403 deletions

View File

@ -1,5 +1,12 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 02/2/2014 ==
Kayen: Revised how spell/dot damage is calculated to properly incorporated all current focus effects/bonuses.
Required SQL: utils/sql/git/2014_02_02_SpellCriticalsAA.sql
== 01/27/2014 ==
Kayen: Implemented SE_CriticalMend (chance to critical monk mend)
Kayen: Implemented SE_IncreaseChanceMemwipe (increases the chance to wipe hate with memory blurr)

View File

@ -301,7 +301,7 @@ typedef enum {
#define SE_TemporaryPets 152 // implemented
#define SE_BalanceHP 153 // implemented
#define SE_DispelDetrimental 154 // implemented
#define SE_SpellCritDmgIncrease 155 // implemented
#define SE_SpellCritDmgIncrease 155 // implemented - no known live spells use this currently
#define SE_IllusionCopy 156 // implemented - Deception
#define SE_SpellDamageShield 157 // implemented - Petrad's Protection
#define SE_Reflect 158 // implemented
@ -432,7 +432,7 @@ typedef enum {
#define SE_DoubleSpecialAttack 283 // implemented[AA] - Chance to perform second special attack as monk
//#define SE_LoHSetHeal 284 // not used
#define SE_NimbleEvasion 285 // *not implemented - base1 = 100 for max
#define SE_SpellDamage 286 // implemented - adds direct spell damage
#define SE_FcDamageAmt 286 // implemented - adds direct spell damage
#define SE_SpellDurationIncByTic 287 // implemented
#define SE_SpecialAttackKBProc 288 // implemented[AA] - Chance to to do a knockback from special attacks [AA Dragon Punch].
#define SE_ImprovedSpellEffect 289 // implemented - Triggers only if fades after natural duration.
@ -440,16 +440,16 @@ typedef enum {
#define SE_Purify 291 // implemented - Removes determental effects
#define SE_StrikeThrough2 292 // implemented[AA] - increasing chance of bypassing an opponent's special defenses, such as dodge, block, parry, and riposte.
#define SE_FrontalStunResist 293 // implemented[AA] - Reduce chance to be stunned from front.
#define SE_CriticalSpellChance 294 // implemented
#define SE_CriticalSpellChance 294 // implemented - increase chance to critical hit and critical damage modifier.
//#define SE_ReduceTimerSpecial 295 // not used
#define SE_SpellVulnerability 296 // implemented - increase in incoming spell damage
#define SE_Empathy 297 // implemented - debuff that adds points damage to spells cast on target (focus effect).
#define SE_FcDamageAmtIncoming 297 // implemented - debuff that adds points damage to spells cast on target (focus effect).
#define SE_ChangeHeight 298 // implemented
#define SE_WakeTheDead 299 // implemented
#define SE_Doppelganger 300 // implemented
#define SE_ArcheryDamageModifier 301 // implemented[AA] - increase archery damage by percent
#define SE_ImprovedDamage2 302 // implemented - spell damage focus
#define SE_FF_Damage_Amount 303 // implemented - adds direct spell damage
#define SE_FcDamagePctCrit 302 // implemented - spell focus that is applied after critical hits has been calculated.
#define SE_FcDamageAmtCrit 303 // implemented - adds direct spell damage
#define SE_OffhandRiposteFail 304 // implemented as bonus - enemy cannot riposte offhand attacks
#define SE_MitigateDamageShield 305 // implemented - off hand attacks only (Shielding Resistance)
#define SE_ArmyOfTheDead 306 // *not implemented NecroAA - This ability calls up to five shades of nearby corpses back to life to serve the necromancer. The soulless abominations will mindlessly fight the target until called back to the afterlife some time later. The first rank summons up to three shades that serve for 60 seconds, and each additional rank adds one more possible shade and increases their duration by 15 seconds
@ -559,7 +559,7 @@ typedef enum {
#define SE_LimitEndPercent 410 // implemented - limited to a certain percent of your end
#define SE_LimitClass 411 // implemented - Limits to spells of a certain class (Note: The class value in dbase is +1 in relation to item class value)
#define SE_LimitRace 412 // implemented - Limits to spells cast by a certain race (Note: not used in any known live spells)
#define SE_IncreaseSpellPower 413 // implemented - Increases the power of bard songs, skill attacks, runes, bard allowed foci, damage/heal
#define SE_FcBaseEffects 413 // implemented - Increases the power of bard songs, skill attacks, runes, bard allowed foci, damage/heal
#define SE_LimitSpellSkill 414 // implemented - Limit a focus to include spells cast using a specific skill.
//#define SE_FFItemClass 415 // not used
#define SE_ACv2 416 // implemented - New AC spell effect

View File

@ -0,0 +1,24 @@
-- Destructive Fury II
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('4755', '1', '294', '0', '130');
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('4756', '1', '294', '0', '135');
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('4757', '1', '294', '0', '140');
-- Set correct base2 values for effect 294
UPDATE aa_effects SET base2 = 100 WHERE effectid = 294 AND base2 = 0;
-- Consumption of Soul (Need live values - These are what had hard coded, but using spell effect)
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('589', '1', '303', '200', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('589', '2', '139', '2766', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('560', '1', '303', '400', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('560', '2', '139', '2766', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('561', '1', '303', '600', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('561', '2', '139', '2766', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('893', '1', '303', '800', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('893', '2', '139', '2766', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('894', '1', '303', '1000', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('894', '2', '139', '2766', '0');

View File

@ -1058,8 +1058,8 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
{
newbon->CriticalSpellChance += base1;
if (base2 > 100)
newbon->SpellCritDmgIncrease += (base2 - 100);
if (base2 > newbon->SpellCritDmgIncNoStack)
newbon->SpellCritDmgIncNoStack = base2;
break;
}
@ -1980,8 +1980,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
case SE_CriticalSpellChance:
{
newbon->CriticalSpellChance += effect_value;
if (spells[spell_id].base2[i] > 100)
newbon->SpellCritDmgIncrease += (spells[spell_id].base2[i] - 100);
if (spells[spell_id].base2[i] > newbon->SpellCritDmgIncNoStack)
newbon->SpellCritDmgIncNoStack = spells[spell_id].base2[i];
break;
}
@ -2781,20 +2782,20 @@ uint8 Mob::IsFocusEffect(uint16 spell_id,int effect_index, bool AA,uint32 aa_eff
return focusTwincast;
case SE_SympatheticProc:
return focusSympatheticProc;
case SE_SpellDamage:
return focusSpellDamage;
case SE_FF_Damage_Amount:
return focusFF_Damage_Amount;
case SE_ImprovedDamage2:
return focusImprovedDamage2;
case SE_Empathy:
return focusAdditionalDamage;
case SE_FcDamageAmt:
return focusFcDamageAmt;
case SE_FcDamageAmtCrit:
return focusFcDamageAmtCrit;
case SE_FcDamagePctCrit:
return focusFcDamagePctCrit;
case SE_FcDamageAmtIncoming:
return focusFcDamageAmtIncoming;
case SE_FcHealAmtIncoming:
return focusFcHealAmtIncoming;
case SE_HealRate2:
return focusHealRate;
case SE_IncreaseSpellPower:
return focusSpellEffectiveness;
case SE_FcBaseEffects:
return focusFcBaseEffects;
case SE_IncreaseNumHits:
return focusIncreaseNumHits;
case SE_FcLimitUse:

View File

@ -1971,8 +1971,8 @@ void Bot::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
{
newbon->CriticalSpellChance += base1;
if (base2 > 100)
newbon->SpellCritDmgIncrease += (base2 - 100);
if (base2 > newbon->SpellCritDmgIncrease)
newbon->SpellCritDmgIncrease = base2;
break;
}
@ -3335,7 +3335,7 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
if(damage > 0) {
damage += damage*focus/100;
ApplyMeleeDamageBonus(skillinuse, damage);
damage += other->GetAdditionalDamage(this, 0, true, skillinuse);
damage += other->GetFcDamageAmtIncoming(this, 0, true, skillinuse);
damage += (itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse);
TryCriticalHit(other, skillinuse, damage, nullptr);
}
@ -6986,25 +6986,25 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id)
break;
}
*/
case SE_SpellDamage:
case SE_FcDamageAmt:
{
if(type == focusSpellDamage)
if(type == focusFcDamageAmt)
value = base1;
break;
}
case SE_FF_Damage_Amount:
case SE_FcDamageAmtCrit:
{
if(type == focusFF_Damage_Amount)
if(type == focusFcDamageAmtCrit)
value = base1;
break;
}
case SE_Empathy:
case SE_FcDamageAmtIncoming:
{
if(type == focusAdditionalDamage)
if(type == focusFcDamageAmtIncoming)
value = base1;
break;
@ -7042,16 +7042,16 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id)
break;
}
case SE_IncreaseSpellPower:
case SE_FcBaseEffects:
{
if (type == focusSpellEffectiveness)
if (type == focusFcBaseEffects)
value = base1;
break;
}
case SE_ImprovedDamage2:
case SE_FcDamagePctCrit:
{
if(type == focusImprovedDamage2)
if(type == focusFcDamagePctCrit)
value = base1;
break;
@ -7080,7 +7080,7 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id)
}
int16 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) {
if (IsBardSong(spell_id) && bottype != BotfocusSpellEffectiveness)
if (IsBardSong(spell_id) && bottype != BotfocusFcBaseEffects)
return 0;
int16 realTotal = 0;
@ -7644,25 +7644,25 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel
}
break;
}
case SE_SpellDamage:
case SE_FcDamageAmt:
{
if(bottype == BotfocusSpellDamage)
if(bottype == BotfocusFcDamageAmt)
value = focus_spell.base[i];
break;
}
case SE_FF_Damage_Amount:
case SE_FcDamageAmtCrit:
{
if(bottype == BotfocusFF_Damage_Amount)
if(bottype == BotfocusFcDamageAmtCrit)
value = focus_spell.base[i];
break;
}
case SE_Empathy:
case SE_FcDamageAmtIncoming:
{
if(bottype == BotfocusAdditionalDamage)
if(bottype == BotfocusFcDamageAmtIncoming)
value = focus_spell.base[i];
break;
@ -7700,16 +7700,16 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel
break;
}
case SE_IncreaseSpellPower:
case SE_FcBaseEffects:
{
if (bottype == BotfocusSpellEffectiveness)
if (bottype == BotfocusFcBaseEffects)
value = focus_spell.base[i];
break;
}
case SE_ImprovedDamage2:
case SE_FcDamagePctCrit:
{
if(bottype == BotfocusImprovedDamage2)
if(bottype == BotfocusFcDamagePctCrit)
value = focus_spell.base[i];
break;
@ -8091,7 +8091,7 @@ void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
if(max_damage > 0) {
ApplyMeleeDamageBonus(skill, max_damage);
max_damage += who->GetAdditionalDamage(this, 0, true, skill);
max_damage += who->GetFcDamageAmtIncoming(this, 0, true, skill);
max_damage += (itembonuses.HeroicSTR / 10) + (max_damage * who->GetSkillDmgTaken(skill) / 100) + GetSkillDmgAmt(skill);
TryCriticalHit(who, skill, max_damage);
}
@ -9122,8 +9122,8 @@ void Bot::SetAttackTimer() {
int32 Bot::Additional_SpellDmg(uint16 spell_id, bool bufftick)
{
int32 spell_dmg = 0;
spell_dmg += GetBotFocusEffect(BotfocusFF_Damage_Amount, spell_id);
spell_dmg += GetBotFocusEffect(BotfocusSpellDamage, spell_id);
spell_dmg += GetBotFocusEffect(BotfocusFcDamageAmtCrit, spell_id);
spell_dmg += GetBotFocusEffect(BotfocusFcDamageAmt, spell_id);
//For DOTs you need to apply the damage over the duration of the dot to each tick (this is how live did it)
if (bufftick){
@ -9136,123 +9136,94 @@ int32 Bot::Additional_SpellDmg(uint16 spell_id, bool bufftick)
return spell_dmg;
}
int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value) {
// Important variables:
// value: the actual damage after resists, passed from Mob::SpellEffect
// modifier: modifier to damage (from spells & focus effects?)
// ratio: % of the modifier to apply (from AAs & natural bonus?)
// chance: critital chance %
int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
if (spells[spell_id].targettype == ST_Self)
return value;
int32 modifier = 100;
int16 spell_dmg = 0;
bool Critical = false;
int32 value_BaseEffect = 0;
//Dunno if this makes sense:
if (spells[spell_id].resisttype > 0)
modifier += GetBotFocusEffect((BotfocusType)(0-spells[spell_id].resisttype), spell_id);
int tt = spells[spell_id].targettype;
if (tt == ST_UndeadAE || tt == ST_Undead || tt == ST_Summoned) {
//undead/summoned spells
modifier += GetBotFocusEffect(BotfocusImprovedUndeadDamage, spell_id);
} else {
//damage spells.
modifier += GetBotFocusEffect(BotfocusImprovedDamage, spell_id);
modifier += GetBotFocusEffect(BotfocusSpellEffectiveness, spell_id);
modifier += GetBotFocusEffect(BotfocusImprovedDamage2, spell_id);
}
value_BaseEffect = value + (value*GetBotFocusEffect(BotfocusFcBaseEffects, 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.
if ( spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) {
if (this->GetLevel() > 40)
value -= (this->GetLevel() - 40) * 20;
}
if ( (spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) && GetLevel() > 40)
value -= (GetLevel() - 40) * 20;
//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
value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch
}
//these spell IDs could be wrong
if (spell_id == SPELL_LEECH_TOUCH) { //leech touch
value -= GetAA(aaConsumptionoftheSoul) * 200; //Consumption of the Soul
value -= GetAA(aaImprovedConsumptionofSoul) * 200; //Improved Consumption of the Soul
}
//spell crits, dont make sense if cast on self.
if(tt != ST_Self) {
// item SpellDmg bonus
// Formula = SpellDmg * (casttime + recastime) / 7; Cant trigger off spell less than 5 levels below and cant cause more dmg than the spell itself.
if(this->itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) {
spell_dmg = this->itembonuses.SpellDmg * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000;
if(spell_dmg > -value)
spell_dmg = -value;
}
// Spell-based SpellDmg adds directly but it restricted by focuses.
spell_dmg += Additional_SpellDmg(spell_id);
int chance = RuleI(Spells, BaseCritChance);
int32 ratio = RuleI(Spells, BaseCritRatio);
if (spell_id == SPELL_IMP_HARM_TOUCH) //Improved Harm Touch
value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch
int chance = RuleI(Spells, BaseCritChance);
chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
if(GetClass() == WIZARD) {
if (GetLevel() >= RuleI(Spells, WizCritLevel)) {
chance += RuleI(Spells, WizCritChance);
ratio += RuleI(Spells, WizCritRatio);
}
if(aabonuses.SpellCritDmgIncrease > 0) // wizards get an additional bonus
ratio += aabonuses.SpellCritDmgIncrease * 1.5; //108%, 115%, 124%, close to Graffe's 207%, 215%, & 225%
}
if (chance > 0){
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) {
if ( (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0) )
chance = 100;
if (spell_id == SPELL_IMP_HARM_TOUCH && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0))
chance = 100;
if (MakeRandomInt(1,100) <= chance){
Critical = true;
ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack;
}
/*
//Handled in aa_effects will focus spells from 'spellgroup=99'. (SK life tap from buff procs)
//If you are using an older spell file table (Pre SOF)...
//Use SQL optional_EnableSoulAbrasionAA to update your spells table to properly use the effect.
//If you do not want to update your table then you may want to enable this.
if(tt == ST_Tap) {
if(spells[spell_id].classes[SHADOWKNIGHT-1] >= 254 && spell_id != SPELL_LEECH_TOUCH){
if(ratio < 100) //chance increase and ratio are made up, not confirmed
ratio = 100;
else if (GetClass() == WIZARD && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (MakeRandomInt(1,100) <= RuleI(Spells, WizCritChance))) {
ratio = MakeRandomInt(1,100); //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio.
Critical = true;
}
switch (GetAA(aaSoulAbrasion))
{
case 1:
modifier += 100;
break;
case 2:
modifier += 200;
break;
case 3:
modifier += 300;
break;
}
ratio += RuleI(Spells, WizCritRatio); //Default is zero
if (Critical){
value = value_BaseEffect*ratio/100;
value += value_BaseEffect*GetFocusEffect(BotfocusImprovedDamage, spell_id)/100;
value += int(value_BaseEffect*GetFocusEffect(BotfocusFcDamagePctCrit, spell_id)/100)*ratio/100;
if (target) {
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
value -= target->GetFcDamageAmtIncoming(this, spell_id);
}
}
*/
if (chance > 0) {
mlog(SPELLS__CRITS, "Attempting spell crit. Spell: %s (%d), Value: %d, Modifier: %d, Chance: %d, Ratio: %d", spells[spell_id].name, spell_id, value, modifier, chance, ratio);
if(MakeRandomInt(0,100) <= chance) {
modifier += modifier*ratio/100;
spell_dmg *= 2;
mlog(SPELLS__CRITS, "Spell crit successful. Final damage modifier: %d, Final Damage: %d", modifier, (value * modifier / 100) - spell_dmg);
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), (-value * modifier / 100) + spell_dmg);
} else
mlog(SPELLS__CRITS, "Spell crit failed. Final Damage Modifier: %d, Final Damage: %d", modifier, (value * modifier / 100) - spell_dmg);
value -= GetFocusEffect(BotfocusFcDamageAmtCrit, spell_id)*ratio/100;
value -= GetFocusEffect(BotfocusFcDamageAmt, spell_id);
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value)*ratio/100;
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), -value);
return value;
}
}
return ((value * modifier / 100) - spell_dmg);
}
value = value_BaseEffect;
value += value_BaseEffect*GetFocusEffect(BotfocusImprovedDamage, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(BotfocusFcDamagePctCrit, spell_id)/100;
if (target) {
value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
value -= target->GetFcDamageAmtIncoming(this, spell_id);
}
value -= GetFocusEffect(BotfocusFcDamageAmtCrit, spell_id);
value -= GetFocusEffect(BotfocusFcDamageAmt, spell_id);
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value);
return value;
}
int32 Bot::Additional_Heal(uint16 spell_id)
{
@ -9274,7 +9245,7 @@ int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value) {
int32 modifier = 100;
int16 heal_amt = 0;
modifier += GetBotFocusEffect(BotfocusImprovedHeal, spell_id);
modifier += GetBotFocusEffect(BotfocusSpellEffectiveness, spell_id);
modifier += GetBotFocusEffect(BotfocusFcBaseEffects, spell_id);
heal_amt += Additional_Heal(spell_id);
int chance = 0;

View File

@ -71,7 +71,7 @@ public:
BotfocusImprovedHeal,
BotfocusImprovedDamage,
BotfocusImprovedDOT, //i dont know about this...
BotfocusImprovedDamage2,
BotfocusFcDamagePctCrit,
BotfocusImprovedUndeadDamage,
BotfocusPetPower,
BotfocusResistRate,
@ -80,15 +80,15 @@ public:
BotfocusSpellVulnerability,
BotfocusTwincast,
BotfocusSympatheticProc,
BotfocusSpellDamage,
BotfocusFF_Damage_Amount,
BotfocusFcDamageAmt,
BotfocusFcDamageAmtCrit,
BotfocusSpellDurByTic,
BotfocusSwarmPetDuration,
BotfocusReduceRecastTime,
BotfocusBlockNextSpell,
BotfocusHealRate,
BotfocusAdditionalDamage,
BotfocusSpellEffectiveness,
BotfocusFcDamageAmtIncoming,
BotfocusFcBaseEffects,
BotfocusIncreaseNumHits,
BotfocusCriticalHealRate,
BotfocusAdditionalHeal2,
@ -303,7 +303,7 @@ public:
virtual void SpellProcess();
int32 Additional_SpellDmg(uint16 spell_id, bool bufftick = false);
int32 Additional_Heal(uint16 spell_id);
virtual int32 GetActSpellDamage(uint16 spell_id, int32 value);
virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target);
virtual int32 GetActSpellHealing(uint16 spell_id, int32 value);
virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime);
virtual int32 GetActSpellCost(uint16 spell_id, int32 cost);

View File

@ -475,13 +475,13 @@ public:
int32 Additional_SpellDmg(uint16 spell_id, bool bufftick = false);
int32 Additional_Heal(uint16 spell_id);
float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false);
int32 GetActSpellDamage(uint16 spell_id, int32 value);
int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob *target = nullptr);
int32 GetActSpellHealing(uint16 spell_id, int32 value);
int32 GetActSpellCost(uint16 spell_id, int32);
int32 GetActSpellDuration(uint16 spell_id, int32);
int32 GetActSpellCasttime(uint16 spell_id, int32);
int32 GetDotFocus(uint16 spell_id, int32 value);
int32 GetActDoTDamage(uint16 spell_id, int32 value);
int32 GetActDoTDamage(uint16 spell_id, int32 value, Mob* target = nullptr);
virtual bool CheckFizzle(uint16 spell_id);
virtual bool CheckSpellLevelRestriction(uint16 spell_id);
virtual int GetCurrentBuffSlots() const;

View File

@ -56,7 +56,7 @@ typedef enum { //focus types
focusImprovedHeal,
focusImprovedDamage,
focusImprovedDOT, //i dont know about this...
focusImprovedDamage2,
focusFcDamagePctCrit,
focusImprovedUndeadDamage,
focusPetPower,
focusResistRate,
@ -65,16 +65,16 @@ typedef enum { //focus types
focusSpellVulnerability,
focusTwincast,
focusSympatheticProc,
focusSpellDamage,
focusFF_Damage_Amount,
focusFcDamageAmt,
focusFcDamageAmtCrit,
focusSpellDurByTic,
focusSwarmPetDuration,
focusReduceRecastTime,
focusBlockNextSpell,
focusHealRate,
focusAdditionalDamage,
focusFcDamageAmtIncoming,
focusFcHealAmtIncoming,
focusSpellEffectiveness,
focusFcBaseEffects,
focusIncreaseNumHits,
focusFcLimitUse,
focusFcMute,
@ -242,6 +242,7 @@ struct StatBonuses {
int16 CriticalHitChance[HIGHEST_SKILL+2]; //i
int16 CriticalSpellChance; //i
int16 SpellCritDmgIncrease; //i
int16 SpellCritDmgIncNoStack; // increase
int16 DotCritDmgIncrease; //i
int16 CriticalHealChance; //i
int16 CriticalHealOverTime; //i

View File

@ -43,8 +43,8 @@ float Client::GetActSpellRange(uint16 spell_id, float range, bool IsBard)
int32 Client::Additional_SpellDmg(uint16 spell_id, bool bufftick)
{
int32 spell_dmg = 0;
spell_dmg += GetFocusEffect(focusFF_Damage_Amount, spell_id);
spell_dmg += GetFocusEffect(focusSpellDamage, spell_id);
spell_dmg += GetFocusEffect(focusFcDamageAmtCrit, spell_id);
spell_dmg += GetFocusEffect(focusFcDamageAmt, spell_id);
//For DOTs you need to apply the damage over the duration of the dot to each tick (this is how live did it)
if (bufftick){
@ -57,139 +57,178 @@ int32 Client::Additional_SpellDmg(uint16 spell_id, bool bufftick)
return spell_dmg;
}
//Scale all NPC spell Damage via $npc->SetSpellFocusDMG(value)
//Direct Damage is checked in Mob::SpellEffect [spell_effects.cpp]
//DoT Damage is checked in Mob::DoBuffTic [spell_effects.cpp] (This was added for npcs in that routine)
int32 NPC::GetActSpellDamage(uint16 spell_id, int32 value) {
int32 NPC::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
int32 modifier = 100;
//Quest scale all NPC spell damage via $npc->SetSpellFocusDMG(value)
//DoT Damage - Mob::DoBuffTic [spell_effects.cpp] / Direct Damage Mob::SpellEffect [spell_effects.cpp]
modifier += SpellFocusDMG;
int32 dmg = value;
return (value * modifier / 100);
if (target) {
value += dmg*target->GetVulnerability(this, spell_id, 0)/100;
if (spells[spell_id].buffduration == 0)
value -= target->GetFcDamageAmtIncoming(this, spell_id);
else
value -= target->GetFcDamageAmtIncoming(this, spell_id)/spells[spell_id].buffduration;
}
value += dmg*SpellFocusDMG/100;
return value;
}
int32 Client::GetActSpellDamage(uint16 spell_id, int32 value) {
// Important variables:
// value: the actual damage after resists, passed from Mob::SpellEffect
// modifier: modifier to damage (from spells & focus effects?)
// ratio: % of the modifier to apply (from AAs & natural bonus?)
// chance: critital chance %
int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
if (spells[spell_id].targettype == ST_Self)
return value;
int32 modifier = 100;
int16 spell_dmg = 0;
bool Critical = false;
int32 value_BaseEffect = 0;
//Dunno if this makes sense:
if (spells[spell_id].resisttype > 0)
modifier += GetFocusEffect((focusType)(0-spells[spell_id].resisttype), spell_id);
int tt = spells[spell_id].targettype;
if (tt == ST_UndeadAE || tt == ST_Undead || tt == ST_Summoned) {
//undead/summoned spells
modifier += GetFocusEffect(focusImprovedUndeadDamage, spell_id);
} else {
//damage spells.
modifier += GetFocusEffect(focusImprovedDamage, spell_id);
modifier += GetFocusEffect(focusSpellEffectiveness, spell_id);
modifier += GetFocusEffect(focusImprovedDamage2, spell_id);
}
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.
if ( spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) {
if (this->GetLevel() > 40)
value -= (this->GetLevel() - 40) * 20;
}
if ( (spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) && GetLevel() > 40)
value -= (GetLevel() - 40) * 20;
//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
value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch
}
// This adds the extra damage for the AA's Consumption of the Soul and Improved Consumption of the Soul, 200 per level to the AA Leech Curse for Shadowknights.
if (spell_id == SPELL_LEECH_TOUCH) { //Leech Touch
value -= GetAA(aaConsumptionoftheSoul) * 200; //Consumption of the Soul
value -= GetAA(aaImprovedConsumptionofSoul) * 200; //Improved Consumption of the Soul
}
//spell crits, dont make sense if cast on self.
if(tt != ST_Self) {
// item SpellDmg bonus
// Formula = SpellDmg * (casttime + recastime) / 7; Cant trigger off spell less than 5 levels below and cant cause more dmg than the spell itself.
if(this->itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) {
spell_dmg = this->itembonuses.SpellDmg * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000;
if(spell_dmg > -value)
spell_dmg = -value;
}
// Spell-based SpellDmg adds directly but it restricted by focuses.
spell_dmg += Additional_SpellDmg(spell_id);
int chance = RuleI(Spells, BaseCritChance);
int32 ratio = RuleI(Spells, BaseCritRatio);
if (spell_id == SPELL_IMP_HARM_TOUCH) //Improved Harm Touch
value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch
int chance = RuleI(Spells, BaseCritChance);
chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
if(GetClass() == WIZARD) {
if (GetLevel() >= RuleI(Spells, WizCritLevel)) {
chance += RuleI(Spells, WizCritChance);
ratio += RuleI(Spells, WizCritRatio);
}
if(aabonuses.SpellCritDmgIncrease > 0) // wizards get an additional bonus
ratio += aabonuses.SpellCritDmgIncrease * 1.5; //108%, 115%, 124%, close to Graffe's 207%, 215%, & 225%
}
if (chance > 0){
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) {
if ( (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0) )
chance = 100;
if (spell_id == SPELL_IMP_HARM_TOUCH && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0))
chance = 100;
if (MakeRandomInt(1,100) <= chance){
Critical = true;
ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack;
}
/*
//Handled in aa_effects will focus spells from 'spellgroup=99'. (SK life tap from buff procs)
//If you are using an older spell file table (Pre SOF)...
//Use SQL optional_EnableSoulAbrasionAA to update your spells table to properly use the effect.
//If you do not want to update your table then you may want to enable this.
if(tt == ST_Tap) {
if(spells[spell_id].classes[SHADOWKNIGHT-1] >= 254 && spell_id != SPELL_LEECH_TOUCH){
if(ratio < 100) //chance increase and ratio are made up, not confirmed
ratio = 100;
else if (GetClass() == WIZARD && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (MakeRandomInt(1,100) <= RuleI(Spells, WizCritChance))) {
ratio = MakeRandomInt(1,100); //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio.
Critical = true;
}
switch (GetAA(aaSoulAbrasion))
{
case 1:
modifier += 100;
break;
case 2:
modifier += 200;
break;
case 3:
modifier += 300;
break;
}
ratio += RuleI(Spells, WizCritRatio); //Default is zero
if (Critical){
value = value_BaseEffect*ratio/100;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
if (target) {
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
value -= target->GetFcDamageAmtIncoming(this, spell_id);
}
}
*/
if (chance > 0) {
mlog(SPELLS__CRITS, "Attempting spell crit. Spell: %s (%d), Value: %d, Modifier: %d, Chance: %d, Ratio: %d", spells[spell_id].name, spell_id, value, modifier, chance, ratio);
if(MakeRandomInt(0,100) <= chance) {
modifier += modifier*ratio/100;
spell_dmg *= 2;
mlog(SPELLS__CRITS, "Spell crit successful. Final damage modifier: %d, Final Damage: %d", modifier, (value * modifier / 100) - spell_dmg);
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), (-value * modifier / 100) + spell_dmg);
} else
mlog(SPELLS__CRITS, "Spell crit failed. Final Damage Modifier: %d, Final Damage: %d", modifier, (value * modifier / 100) - spell_dmg);
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100;
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value)*ratio/100;
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), -value);
return value;
}
}
return ((value * modifier / 100) - spell_dmg);
value = value_BaseEffect;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
if (target) {
value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
value -= target->GetFcDamageAmtIncoming(this, spell_id);
}
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id);
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value);
return value;
}
int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
if (target == nullptr)
return value;
int32 value_BaseEffect = 0;
int32 extra_dmg = 0;
int16 chance = 0;
chance += itembonuses.CriticalDoTChance + spellbonuses.CriticalDoTChance + aabonuses.CriticalDoTChance;
if (spellbonuses.CriticalDotDecay)
chance += GetDecayEffectValue(spell_id, SE_CriticalDotDecay);
value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);
if (chance > 0 && (MakeRandomInt(1, 100) <= chance)) {
int32 ratio = 100;
ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease;
value = value_BaseEffect*ratio/100;
value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100;
value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) +
GetFocusEffect(focusFcDamageAmt, spell_id);
if (extra_dmg)
extra_dmg /= CalcBuffDuration(this, this, spell_id);
value -= extra_dmg;
return value;
}
value = value_BaseEffect;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
GetFocusEffect(focusFcDamageAmtCrit, spell_id) +
GetFocusEffect(focusFcDamageAmt, spell_id);
if (extra_dmg)
extra_dmg /= CalcBuffDuration(this, this, spell_id);
value -= extra_dmg;
return value;
}
int32 Client::GetActDoTDamage(uint16 spell_id, int32 value) {
/*
int32 modifier = 100;
int16 spell_dmg = 0;
int16 critChance = 0;
@ -200,11 +239,6 @@ int32 Client::GetActDoTDamage(uint16 spell_id, int32 value) {
ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease;
spell_dmg += Additional_SpellDmg(spell_id,true);
// since DOTs are the Necromancer forte, give an innate bonus (Kayen: Is this a real bonus?)
// however, no chance to crit unless they've trained atleast one level in the AA first
if (GetClass() == NECROMANCER && critChance > 0)
critChance += 5;
if (spellbonuses.CriticalDotDecay)
critChance += GetDecayEffectValue(spell_id, SE_CriticalDotDecay);
@ -216,9 +250,35 @@ int32 Client::GetActDoTDamage(uint16 spell_id, int32 value) {
}
return ((value*modifier/100)-spell_dmg);
*/
int32 Mob::GetExtraSpellDmg(uint16 spell_id, int32 extra_spell_dmg, int32 base_spell_dmg)
{
int total_cast_time = 0;
if (spells[spell_id].recast_time >= spells[spell_id].recovery_time)
total_cast_time = spells[spell_id].recast_time + spells[spell_id].cast_time;
else
total_cast_time = spells[spell_id].recovery_time + spells[spell_id].cast_time;
if (total_cast_time > 0 && total_cast_time <= 2500)
extra_spell_dmg = extra_spell_dmg*25/100;
else if (total_cast_time > 2500 && total_cast_time < 7000)
extra_spell_dmg = extra_spell_dmg*(0.167*((total_cast_time - 1000)/1000));
else
extra_spell_dmg = extra_spell_dmg * total_cast_time / 7000;
extra_spell_dmg = -extra_spell_dmg;
if(extra_spell_dmg*2 < base_spell_dmg)
return 0;
return extra_spell_dmg;
}
//Scale all NPC spell healing via SetSpellFocusHeal(value)
int32 NPC::GetActSpellHealing(uint16 spell_id, int32 value) {
@ -256,7 +316,7 @@ int32 Client::GetActSpellHealing(uint16 spell_id, int32 value) {
int32 modifier = 100;
int16 heal_amt = 0;
modifier += GetFocusEffect(focusImprovedHeal, spell_id);
modifier += GetFocusEffect(focusSpellEffectiveness, spell_id);
modifier += GetFocusEffect(focusFcBaseEffects, spell_id);
heal_amt += Additional_Heal(spell_id);
int chance = 0;

View File

@ -2774,8 +2774,8 @@ int16 Merc::GetFocusEffect(focusType type, uint16 spell_id) {
int32 Merc::Additional_SpellDmg(uint16 spell_id, bool bufftick)
{
int32 spell_dmg = 0;
spell_dmg += GetFocusEffect(focusFF_Damage_Amount, spell_id);
spell_dmg += GetFocusEffect(focusSpellDamage, spell_id);
spell_dmg += GetFocusEffect(focusFcDamageAmtCrit, spell_id);
spell_dmg += GetFocusEffect(focusFcDamageAmt, spell_id);
//For DOTs you need to apply the damage over the duration of the dot to each tick (this is how live did it)
if (bufftick){
@ -2788,79 +2788,86 @@ int32 Merc::Additional_SpellDmg(uint16 spell_id, bool bufftick)
return spell_dmg;
}
int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value) {
// Important variables:
// value: the actual damage after resists, passed from Mob::SpellEffect
// modifier: modifier to damage (from spells & focus effects?)
// ratio: % of the modifier to apply (from AAs & natural bonus?)
// chance: critital chance %
int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
if (spells[spell_id].targettype == ST_Self)
return value;
int32 modifier = 100;
int16 spell_dmg = 0;
bool Critical = false;
int32 value_BaseEffect = 0;
value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);
//Dunno if this makes sense:
if (spells[spell_id].resisttype > 0)
modifier += GetFocusEffect((focusType)(0-spells[spell_id].resisttype), spell_id);
int tt = spells[spell_id].targettype;
if (tt == ST_UndeadAE || tt == ST_Undead || tt == ST_Summoned) {
//undead/summoned spells
modifier += GetFocusEffect(focusImprovedUndeadDamage, spell_id);
} else {
//damage spells.
modifier += GetFocusEffect(focusImprovedDamage, spell_id);
modifier += GetFocusEffect(focusSpellEffectiveness, spell_id);
modifier += GetFocusEffect(focusImprovedDamage2, spell_id);
}
//spell crits, dont make sense if cast on self.
if(tt != ST_Self) {
// item SpellDmg bonus
// Formula = SpellDmg * (casttime + recastime) / 7; Cant trigger off spell less than 5 levels below and cant cause more dmg than the spell itself.
if(this->itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) {
spell_dmg = this->itembonuses.SpellDmg * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000;
if(spell_dmg > -value)
spell_dmg = -value;
}
// Spell-based SpellDmg adds directly but it restricted by focuses.
spell_dmg += Additional_SpellDmg(spell_id);
int chance = RuleI(Spells, BaseCritChance);
int32 ratio = RuleI(Spells, BaseCritRatio);
int chance = RuleI(Spells, BaseCritChance);
chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
if (chance > 0){
int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals.
if(GetClass() == CASTERDPS) {
if (GetLevel() >= RuleI(Spells, WizCritLevel)) {
chance += RuleI(Spells, WizCritChance);
ratio += RuleI(Spells, WizCritRatio);
}
if(aabonuses.SpellCritDmgIncrease > 0) // wizards get an additional bonus
ratio += aabonuses.SpellCritDmgIncrease * 1.5; //108%, 115%, 124%, close to Graffe's 207%, 215%, & 225%
if (MakeRandomInt(1,100) <= chance){
Critical = true;
ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack;
}
else if (GetClass() == CASTERDPS && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (MakeRandomInt(1,100) <= RuleI(Spells, WizCritChance))) {
ratio = MakeRandomInt(1,100); //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio.
Critical = true;
}
if (chance > 0) {
mlog(SPELLS__CRITS, "Attempting spell crit. Spell: %s (%d), Value: %d, Modifier: %d, Chance: %d, Ratio: %d", spells[spell_id].name, spell_id, value, modifier, chance, ratio);
if(MakeRandomInt(0,100) <= chance) {
modifier += modifier*ratio/100;
spell_dmg *= 2;
mlog(SPELLS__CRITS, "Spell crit successful. Final damage modifier: %d, Final Damage: %d", modifier, (value * modifier / 100) - spell_dmg);
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), (-value * modifier / 100) + spell_dmg);
} else
mlog(SPELLS__CRITS, "Spell crit failed. Final Damage Modifier: %d, Final Damage: %d", modifier, (value * modifier / 100) - spell_dmg);
ratio += RuleI(Spells, WizCritRatio); //Default is zero
if (Critical){
value = value_BaseEffect*ratio/100;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
if (target) {
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
value -= target->GetFcDamageAmtIncoming(this, spell_id);
}
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100;
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value)*ratio/100;
value = (value * GetSpellScale() / 100);
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), -value);
return value;
}
}
spell_dmg = ((value * modifier / 100) - spell_dmg);
spell_dmg = (spell_dmg * GetSpellScale() / 100);
value = value_BaseEffect;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
return spell_dmg;
}
if (target) {
value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
value -= target->GetFcDamageAmtIncoming(this, spell_id);
}
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id);
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value);
value = (value * GetSpellScale() / 100);
return value;
}
int32 Merc::Additional_Heal(uint16 spell_id)
{
@ -2884,7 +2891,7 @@ int32 Merc::GetActSpellHealing(uint16 spell_id, int32 value) {
int32 modifier = 100;
int16 heal_amt = 0;
modifier += GetFocusEffect(focusImprovedHeal, spell_id);
modifier += GetFocusEffect(focusSpellEffectiveness, spell_id);
modifier += GetFocusEffect(focusFcBaseEffects, spell_id);
heal_amt += Additional_Heal(spell_id);
int chance = 0;

View File

@ -79,7 +79,7 @@ public:
// Merc Spell Casting Methods
int32 Additional_SpellDmg(uint16 spell_id, bool bufftick = false);
int32 Additional_Heal(uint16 spell_id);
virtual int32 GetActSpellDamage(uint16 spell_id, int32 value);
virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr);
virtual int32 GetActSpellHealing(uint16 spell_id, int32 value);
virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime);
virtual int32 GetActSpellCost(uint16 spell_id, int32 cost);

View File

@ -3351,17 +3351,23 @@ void Mob::TryTwincast(Mob *caster, Mob *target, uint32 spell_id)
}
}
int32 Mob::GetVulnerability(int32 damage, Mob *caster, uint32 spell_id, uint32 ticsremaining)
int32 Mob::GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining)
{
if (!IsValidSpell(spell_id))
return 0;
if (!caster)
return damage;
return 0;
int32 value = 0;
//Apply innate vulnerabilities
if (Vulnerability_Mod[GetSpellResistType(spell_id)] != 0)
damage += damage * Vulnerability_Mod[GetSpellResistType(spell_id)] / 100;
value = Vulnerability_Mod[GetSpellResistType(spell_id)];
else if (Vulnerability_Mod[HIGHEST_RESIST+1] != 0)
damage += damage * Vulnerability_Mod[HIGHEST_RESIST+1] / 100;
value = Vulnerability_Mod[HIGHEST_RESIST+1];
//Apply spell derived vulnerabilities
if (spellbonuses.FocusEffects[focusSpellVulnerability]){
@ -3395,12 +3401,12 @@ int32 Mob::GetVulnerability(int32 damage, Mob *caster, uint32 spell_id, uint32 t
if (tmp_focus < -99)
tmp_focus = -99;
damage += damage * tmp_focus / 100;
value += tmp_focus;
if (tmp_buffslot >= 0)
CheckNumHitsRemaining(7, tmp_buffslot);
}
return damage;
return value;
}
int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used)

View File

@ -171,7 +171,7 @@ public:
bool item_bonus = false, uint32 ticsremaining = 0, int buffslot = -1);
void NegateSpellsBonuses(uint16 spell_id);
virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false) { return range;}
virtual int32 GetActSpellDamage(uint16 spell_id, int32 value) { return value; }
virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr) { return value; }
virtual int32 GetActSpellHealing(uint16 spell_id, int32 value) { return value; }
virtual int32 GetActSpellCost(uint16 spell_id, int32 cost){ return cost;}
virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration){ return duration;}
@ -550,8 +550,8 @@ public:
uint16 GetSpellEffectResistChance(uint16 spell_id);
int16 GetHealRate(uint16 spell_id);
int16 GetCriticalHealRate(uint16 spell_id);
int32 GetVulnerability(int32 damage, Mob *caster, uint32 spell_id, uint32 ticsremaining);
int32 GetAdditionalDamage(Mob *caster, uint32 spell_id, bool use_skill = false, uint16 skill=0);
int32 GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining);
int32 GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill = false, uint16 skill=0);
int16 GetSkillDmgTaken(const SkillUseTypes skill_used);
void DoKnockback(Mob *caster, uint32 pushback, uint32 pushup);
int16 CalcResistChanceBonus();
@ -574,6 +574,7 @@ public:
bool DoHPToManaCovert(uint16 mana_cost = 0);
int32 ApplySpellEffectiveness(Mob* caster, int16 spell_id, int32 value, bool IsBard = false);
int8 GetDecayEffectValue(uint16 spell_id, uint16 spelleffect);
int32 GetExtraSpellDmg(uint16 spell_id, int32 extra_spell_dmg, int32 base_spell_dmg);
void ModSkillDmgTaken(SkillUseTypes skill_num, int value);
int16 GetModSkillDmgTaken(const SkillUseTypes skill_num);

View File

@ -109,7 +109,7 @@ public:
void CalcNPCDamage();
int32 GetActSpellDamage(uint16 spell_id, int32 value);
int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr);
int32 GetActSpellHealing(uint16 spell_id, int32 value);
inline void SetSpellFocusDMG(int32 NewSpellFocusDMG) {SpellFocusDMG = NewSpellFocusDMG;}
inline void SetSpellFocusHeal(int32 NewSpellFocusHeal) {SpellFocusHeal = NewSpellFocusHeal;}

View File

@ -140,7 +140,7 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
if(max_damage > 0) {
ApplyMeleeDamageBonus(skill, max_damage);
max_damage += who->GetAdditionalDamage(this, 0, true, skill);
max_damage += who->GetFcDamageAmtIncoming(this, 0, true, skill);
max_damage += (itembonuses.HeroicSTR / 10) + (max_damage * who->GetSkillDmgTaken(skill) / 100) + GetSkillDmgAmt(skill);
TryCriticalHit(who, skill, max_damage);
}
@ -941,7 +941,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
{
TotalDmg += TotalDmg*focus/100;
ApplyMeleeDamageBonus(SkillArchery, TotalDmg);
TotalDmg += other->GetAdditionalDamage(this, 0, true, SkillArchery);
TotalDmg += other->GetFcDamageAmtIncoming(this, 0, true, SkillArchery);
TotalDmg += (itembonuses.HeroicDEX / 10) + (TotalDmg * other->GetSkillDmgTaken(SkillArchery) / 100) + GetSkillDmgAmt(SkillArchery);
TotalDmg = mod_archery_damage(TotalDmg, dobonus, RangeWeapon);
@ -1265,7 +1265,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
{
TotalDmg += TotalDmg*focus/100;
ApplyMeleeDamageBonus(SkillThrowing, TotalDmg);
TotalDmg += other->GetAdditionalDamage(this, 0, true, SkillThrowing);
TotalDmg += other->GetFcDamageAmtIncoming(this, 0, true, SkillThrowing);
TotalDmg += (itembonuses.HeroicDEX / 10) + (TotalDmg * other->GetSkillDmgTaken(SkillThrowing) / 100) + GetSkillDmgAmt(SkillThrowing);
TryCriticalHit(other, SkillThrowing, TotalDmg);
int32 hate = (2*WDmg);
@ -2139,7 +2139,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
if(damage > 0) {
damage += damage*focus/100;
ApplyMeleeDamageBonus(skillinuse, damage);
damage += other->GetAdditionalDamage(this, 0, true, skillinuse);
damage += other->GetFcDamageAmtIncoming(this, 0, true, skillinuse);
damage += (itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse);
TryCriticalHit(other, skillinuse, damage);
}

View File

@ -301,11 +301,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
//handles AAs and what not...
if(caster)
{
dmg = GetVulnerability(dmg, caster, spell_id, 0);
dmg -= GetAdditionalDamage(caster, spell_id);
dmg = caster->GetActSpellDamage(spell_id, dmg);
}
dmg = caster->GetActSpellDamage(spell_id, dmg, this);
dmg = -dmg;
Damage(caster, dmg, spell_id, spell.skill, false, buffslot, false);
}
@ -2308,7 +2305,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
int16 focus = 0;
if(caster->IsClient())
focus = caster->CastToClient()->GetFocusEffect(focusSpellEffectiveness, spell_id);
focus = caster->CastToClient()->GetFocusEffect(focusFcBaseEffects, spell_id);
switch(spells[spell_id].skill)
{
@ -2847,7 +2844,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
case SE_EffectOnFade:
case SE_MaxHPChange:
case SE_SympatheticProc:
case SE_SpellDamage:
case SE_FcDamageAmt:
case SE_CriticalSpellChance:
case SE_SpellCritChance:
case SE_SpellCritDmgIncrease:
@ -2869,7 +2866,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
case SE_IncreaseBlockChance:
case SE_AntiGate:
case SE_Fearless:
case SE_FF_Damage_Amount:
case SE_FcDamageAmtCrit:
case SE_AdditionalHeal:
case SE_CastOnCurer:
case SE_CastOnCure:
@ -2880,15 +2877,15 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
case SE_BardSongRange:
case SE_ACv2:
case SE_ManaRegen_v2:
case SE_ImprovedDamage2:
case SE_FcDamagePctCrit:
case SE_AdditionalHeal2:
case SE_HealRate2:
case SE_CriticalHealDecay:
case SE_CriticalRegenDecay:
case SE_Empathy:
case SE_FcDamageAmtIncoming:
case SE_LimitSpellSkill:
case SE_MitigateDamageShield:
case SE_IncreaseSpellPower:
case SE_FcBaseEffects:
case SE_LimitClass:
case SE_LimitExcludeSkill:
case SE_BlockBehind:
@ -3310,8 +3307,8 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
effect_value = CalcSpellEffectValue(spell_id, i, caster_level, caster, ticsremaining);
//Handle client cast DOTs here.
if (caster && caster->IsClient() && IsDetrimentalSpell(spell_id) && effect_value < 0) {
effect_value = GetVulnerability(effect_value, caster, spell_id, ticsremaining);
effect_value = caster->CastToClient()->GetActDoTDamage(spell_id, effect_value);
effect_value = caster->CastToClient()->GetActDoTDamage(spell_id, effect_value, this);
if (!caster->CastToClient()->GetFeigned())
AddToHateList(caster, -effect_value);
@ -3322,13 +3319,13 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
if(caster)
{
if(!caster->IsClient()){
effect_value = GetVulnerability(effect_value, caster, spell_id, ticsremaining);
if (!IsClient()) //Allow NPC's to generate hate if casted on other NPC's.
AddToHateList(caster, -effect_value);
}
if(caster->IsNPC())
effect_value = caster->CastToNPC()->GetActSpellDamage(spell_id, effect_value);
effect_value = caster->CastToNPC()->GetActSpellDamage(spell_id, effect_value, this);
}
effect_value = -effect_value;
@ -4328,25 +4325,25 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
break;
}
*/
case SE_SpellDamage:
case SE_FcDamageAmt:
{
if(type == focusSpellDamage)
if(type == focusFcDamageAmt)
value = base1;
break;
}
case SE_FF_Damage_Amount:
case SE_FcDamageAmtCrit:
{
if(type == focusFF_Damage_Amount)
if(type == focusFcDamageAmtCrit)
value = base1;
break;
}
case SE_Empathy:
case SE_FcDamageAmtIncoming:
{
if(type == focusAdditionalDamage)
if(type == focusFcDamageAmtIncoming)
value = base1;
break;
@ -4392,16 +4389,16 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
break;
}
case SE_IncreaseSpellPower:
case SE_FcBaseEffects:
{
if (type == focusSpellEffectiveness)
if (type == focusFcBaseEffects)
value = base1;
break;
}
case SE_ImprovedDamage2:
case SE_FcDamagePctCrit:
{
if(type == focusImprovedDamage2)
if(type == focusFcDamagePctCrit)
value = base1;
break;
@ -4861,25 +4858,25 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
}
break;
}
case SE_SpellDamage:
case SE_FcDamageAmt:
{
if(type == focusSpellDamage)
if(type == focusFcDamageAmt)
value = focus_spell.base[i];
break;
}
case SE_FF_Damage_Amount:
case SE_FcDamageAmtCrit:
{
if(type == focusFF_Damage_Amount)
if(type == focusFcDamageAmtCrit)
value = focus_spell.base[i];
break;
}
case SE_Empathy:
case SE_FcDamageAmtIncoming:
{
if(type == focusAdditionalDamage)
if(type == focusFcDamageAmtIncoming)
value = focus_spell.base[i];
break;
@ -4925,16 +4922,16 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
break;
}
case SE_IncreaseSpellPower:
case SE_FcBaseEffects:
{
if (type == focusSpellEffectiveness)
if (type == focusFcBaseEffects)
value = focus_spell.base[i];
break;
}
case SE_ImprovedDamage2:
case SE_FcDamagePctCrit:
{
if(type == focusImprovedDamage2)
if(type == focusFcDamagePctCrit)
value = focus_spell.base[i];
break;
@ -5095,7 +5092,7 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
int16 Client::GetFocusEffect(focusType type, uint16 spell_id) {
if (IsBardSong(spell_id) && type != focusSpellEffectiveness)
if (IsBardSong(spell_id) && type != focusFcBaseEffects)
return 0;
int16 realTotal = 0;
@ -5611,9 +5608,9 @@ bool Mob::DoHPToManaCovert(uint16 mana_cost)
return false;
}
int32 Mob::GetAdditionalDamage(Mob *caster, uint32 spell_id, bool use_skill, uint16 skill )
int32 Mob::GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill, uint16 skill )
{
//Used to check focus derived from SE_Empathy which adds direct damage to Spells or Skill based attacks.
//Used to check focus derived from SE_FcDamageAmtIncoming which adds direct damage to Spells or Skill based attacks.
int32 dmg = 0;
bool limit_exists = false;
bool skill_found = false;
@ -5621,17 +5618,17 @@ int32 Mob::GetAdditionalDamage(Mob *caster, uint32 spell_id, bool use_skill, uin
if (!caster)
return 0;
if (spellbonuses.FocusEffects[focusAdditionalDamage]){
if (spellbonuses.FocusEffects[focusFcDamageAmtIncoming]){
uint32 buff_count = GetMaxTotalSlots();
for(int i = 0; i < buff_count; i++){
if( (IsValidSpell(buffs[i].spellid) && (IsEffectInSpell(buffs[i].spellid, SE_Empathy))) ){
if( (IsValidSpell(buffs[i].spellid) && (IsEffectInSpell(buffs[i].spellid, SE_FcDamageAmtIncoming))) ){
if (use_skill){
int32 temp_dmg = 0;
for (int e = 0; e < EFFECT_COUNT; e++) {
if (spells[buffs[i].spellid].effectid[e] == SE_Empathy){
if (spells[buffs[i].spellid].effectid[e] == SE_FcDamageAmtIncoming){
temp_dmg += spells[buffs[i].spellid].base[e];
continue;
}
@ -5653,7 +5650,7 @@ int32 Mob::GetAdditionalDamage(Mob *caster, uint32 spell_id, bool use_skill, uin
}
else{
int32 focus = caster->CalcFocusEffect(focusAdditionalDamage, buffs[i].spellid, spell_id);
int32 focus = caster->CalcFocusEffect(focusFcDamageAmtIncoming, buffs[i].spellid, spell_id);
if(focus){
dmg += focus;
CheckNumHitsRemaining(7,i);
@ -5675,7 +5672,7 @@ int32 Mob::ApplySpellEffectiveness(Mob* caster, int16 spell_id, int32 value, boo
return value;
if (caster->IsClient()){
int16 focus = caster->CastToClient()->GetFocusEffect(focusSpellEffectiveness, spell_id);
int16 focus = caster->CastToClient()->GetFocusEffect(focusFcBaseEffects, spell_id);
if (IsBard)
value += focus;