EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Spell Support (https://www.eqemulator.org/forums/forumdisplay.php?f=664)
-   -   Awkward Scaling involving ImprovedDamage (Bug?) (https://www.eqemulator.org/forums/showthread.php?t=39264)

Hateborne 01-23-2015 03:47 PM

Awkward Scaling involving ImprovedDamage (Bug?)
 
Afternoon ladies/gents/trolls,

Using a spell with effectid1 = 124, effect_base_value1 = 500 as a focus on a spell with base damage 375000, with no other affecting foci, the damage scales weirdly or breaks (goes negative). This is being cast as a wizard.

Base Damage: 375,000
Crit Damage: 900,000
With Focus: 13,500,000
Crit With Focus: -10,549,672

Any ideas?


-Hate


https://github.com/EQEmu/Server/issues/347 Issue Started as well.

Kayen 01-23-2015 08:38 PM

Sounds like an overflow issue.

However, just reviewing the code those numbers aren't really hitting the int32 limits.

Question is it healing the NPC when you negative crit?

Kayen 01-23-2015 08:40 PM

This is the function that handles it. Maybe somebody else will see something obviously wrong.

Code:

int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {

        if (spells[spell_id].targettype == ST_Self)
                return value;

        if (IsNPC())
                value += value*CastToNPC()->GetSpellFocusDMG()/100;

        bool Critical = false;
        int32 value_BaseEffect = 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.
        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 && IsClient()) //Improved Harm Touch
                value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch

                chance = RuleI(Spells, BaseCritChance); //Wizard base critical chance is 2% (Does not scale with level)
                chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
                chance += itembonuses.FrenziedDevastation + spellbonuses.FrenziedDevastation + aabonuses.FrenziedDevastation;

        //Crtical Hit Calculation pathway
        if (chance > 0 || (IsClient() && GetClass() == WIZARD && GetLevel() >= RuleI(Spells, WizCritLevel))) {

                int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals.

                //Improved Harm Touch is a guaranteed crit if you have at least one level of SCF.
                if (spell_id == SPELL_IMP_HARM_TOUCH && IsClient() && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0))
                        chance = 100;

                if (zone->random.Roll(chance)) {
                        Critical = true;
                        ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
                        ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack;
                }

                else if ((IsClient() && GetClass() == WIZARD) || (IsMerc() && GetClass() == CASTERDPS)) {
                        if ((GetLevel() >= RuleI(Spells, WizCritLevel)) && zone->random.Roll(RuleI(Spells, WizCritChance))){
                                //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. (20-70 is parse confirmed)
                                ratio += zone->random.Int(20,70);
                                Critical = true;
                        }
                }

                if (IsClient() && GetClass() == WIZARD)
                        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 -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100;

                        else if (IsNPC() && CastToNPC()->GetSpellScale())
                                value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f);

                        entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits,
                                        OTHER_CRIT_BLAST, GetName(), itoa(-value));

                        if (IsClient())
                                Message_StringID(MT_SpellCrits, YOU_CRIT_BLAST, itoa(-value));

                        return value;
                }
        }
        //Non Crtical Hit Calculation pathway
        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 -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value);

        if (IsNPC() && CastToNPC()->GetSpellScale())
                value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f);

        return value;
}


Hateborne 01-23-2015 09:14 PM

Kayen,

The healing part I cannot tell as it's a target dummy npc that heals to full every 3 seconds with millions of HP. The code block you sent was one the bit I was pouring over. I'm going to setup a devbox and attach a debugger to trace the values when a crit lands. It seems to be only crits. I should have something by Monday, unless you beat me to it. :-)


-Hate

Zaela_S 01-23-2015 10:31 PM

Code:

...
                if (Critical){

                        value = value_BaseEffect*ratio/100;

                        value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;

int value = 375000 * 240 / 100 => 900000
int focus = 3600

value *= focus => 3,240,000,000 <-- overflow for signed 32bit
value /= 100 ....

?

edit:
3,240,000,000 - 2^32 => -1,054,967,296
-1,054,967,296 / 100 => -10,549,672

Seems pretty likely.

Zaela_S 01-24-2015 03:16 AM

If the final damage would be over ~21 million it seems like it would inevitably hit overflow somewhere in there. Dunno if it would be worth bumping the temporaries up to int64 for most servers, though.

Kayen 01-24-2015 08:54 AM

At some point a custom server has to take responsibility for what it sets as values for things.

Given all things are relative there is no logical reason to have numbers that high.

Hateborne 01-27-2015 02:01 PM

Quote:

Originally Posted by Kayen (Post 237138)
At some point a custom server has to take responsibility for what it sets as values for things.

Given all things are relative there is no logical reason to have numbers that high.

I'll be sure to tell Hunter the next time I see him that his custom damage and HP values are too high.

Rude comments aside, I am trying to take responsibility and bring up things I find as potential bugs or awkwardly scaling. This scaled so high because another augment was in my test gear that I was unaware of that added an additional 500% via FcDamagePctCrit (302) which was causing the explosive scaling, which created the potential for -2,700,000,000 in the formula on line 99 in effects.cpp (as shown below). Without the extra 500%, it scaled normally (without code changes) and gave appropriate values.

Code:

value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
value += int(-2250000 * 500 / 100) * 240 / 100;


Thanks to those that contributed and this thread can be closed/locked/marked-as-resolved/etc. :-)


-Hate


All times are GMT -4. The time now is 09:55 AM.

Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.