View Single Post
  #3  
Old 08-05-2023, 04:01 PM
Secrets Secrets is offline
VIP / Contributor

Secrets's Avatar

Join Date: Oct 2009
Posts: 1,354
Default

Quote:
Originally Posted by Homesteaded [You must be logged in to view images. Log in or Register.]
They posted today that NPC bash rate is 100%, will be fixed.
Not 100%. It's not a bug.

Here's the formula. It matches logs Torven has (and actually, Torven was the one who wrote this formula)

Code:
   // this is precise for the vast majority of NPCs
    // at some point around level 61, base stun chance goes from 45 to 40.  not sure why
    int stun_chance = 45;
    int defenderLevel = defender->GetLevel();
    int levelDiff = GetLevel() - defenderLevel;

    if (GetLevel() > 60)
        stun_chance = 40;

    if (levelDiff < 0)
    {
        stun_chance -= levelDiff * levelDiff / 2;
    }
    else
    {
        stun_chance += levelDiff * levelDiff / 2;
    }
    if (stun_chance < 2)
        stun_chance = 2;

    if (defender->IsNPC() && defenderLevel > RuleI(Spells, BaseImmunityLevel))
        stun_chance = 0;

    if (stun_chance && zone->random.Roll(stun_chance))
    {
        Log(Logs::Detail, Logs::Combat, "Stun passed, checking resists. Was %d chance.", stun_chance);

        int stun_resist = 0;

        if (defender->IsClient())
        {
            stun_resist = defender->aabonuses.StunResist;                        // Stalwart Endurance AA
        }

        if (defender->GetBaseRace() == OGRE && !BehindMob(defender, GetX(), GetY()))        // should this work if the ogre is illusioned?
        {
            Log(Logs::Detail, Logs::Combat, "Frontal stun resisted because, Ogre.");
        }
        else
        {
            if (stun_resist && zone->random.Roll(stun_resist))
            {
                defender->Message_StringID(MT_DefaultText, AVOID_STUN);
                Log(Logs::Detail, Logs::Combat, "Stun Resisted. %d chance.", stun_resist);
            }
            else
            {
                Log(Logs::Detail, Logs::Combat, "Stunned. %d resist chance.", stun_resist);
                defender->Stun(2000, this);    // bash/kick stun is always 2 seconds
            }
        }
    }
    else
    {
        Log(Logs::Detail, Logs::Combat, "Stun failed. %d chance.", stun_chance);

        // This is a crude approximation of interrupt chance based on old EQ log parses
        int interruptChance = 100;

        if (IsNPC() && !IsPet())
        {
            if (GetLevel() < defenderLevel)
                interruptChance = 80;        // Daybreak recently confirmed this 80% chance
        }
        else if (defender->IsNPC())
        {
            int levelDiff = GetLevel() - defenderLevel;

            interruptChance += levelDiff * 10;

            if (defenderLevel > 65 && interruptChance > 0)
                interruptChance = 2;
            else if (defenderLevel > 55)
                interruptChance /= 2;
            else if (defenderLevel > 50)
                interruptChance = 3 * interruptChance / 4;
        }

        Log(Logs::Detail, Logs::Combat, "Non-stunning bash/kick interrupt roll: chance = %i", interruptChance);

        if (zone->random.Roll(interruptChance))
        {
            if (IsValidSpell(defender->casting_spell_id) && !spells[defender->casting_spell_id].uninterruptable)
            {
                Log(Logs::Detail, Logs::Combat, "Non-stunning bash/kick successfully interrupted spell");
                defender->InterruptSpell(SPELL_UNKNOWN, true);
            }
        }
    }
And here's the flee stun code. This was taken again from various logs, and additionally happens on Live:

Code:
// 3 second flee stun check.  NPCs can stun players who are running away from them.  10% chance on hit
    if (spell_id == SPELL_UNKNOWN && damage > 0 && other && other->IsNPC() && !other->IsPet() && other->GetLevel() > 4 && EQ::skills::IsMeleeWeaponSkill(attack_skill))
    {
        if (animation > 0 && zone->random.Roll(10) && other->BehindMob(this, other->GetX(), other->GetY()))
        {
            int stun_resist = aabonuses.StunResist;

            if (!stun_resist || zone->random.Roll(100 - stun_resist))
            {
                if (CombatRange(other, 0.0f, false, true)) {
                    Log(Logs::Detail, Logs::Combat, "3 second flee stun sucessful");
                    Stun(3000, other);
                }
            }
            else
            {
                Log(Logs::Detail, Logs::Combat, "Stun Resisted. %d chance.", stun_resist);
                Message_StringID(MT_DefaultText, AVOID_STUN);
            }
        }
    }
__________________
Engineer of Things and Stuff, Wearer of Many Hats

“Knowing yourself is the beginning of all wisdom.” — Aristotle