0.4.23 Dual wield + Twist the knife: secondary weapon benefits from primary weapon damage

Prince Charming

Active Member
Mar 18, 2020
30
33
I am using Microsoft Edge version 96.0.1054.41

this one is a little technical, so hold on to your butts if you have the time to get to the end:
when proccing "twist the knife" with your secondary weapon when dual wielding, you should make an attack with +50 attack power with your secondary weapon.
because of the bug, instead of the +50 attack power bonus on your secondary weapon, 50% of the base damage from your primary weapon gets added to the damage of your secondary weapon.
to show the bug in action, i did the following setup:
i attack ninian (nothing personal) with a short sword (35 base damage) as my primary weapon, and a kunai (10 base damage) as my secondary weapon; ninian already has a debuff (terrify), so both attacks will proc twist the knife:Untitled2.png
i have 12 attack power, so the kunai attack (procing twist the knife) should do no more than 10 * (1 + (12 + 50) / 100) ~= 16 damage (in case ninian had 0 armor)
intead it does 27 damage, which matches "base kunai damage + base short sword damage * 50 / 100" = 10 + 35 * 50 / 100 = 10 + 35 / 2 ~= 27

now let's dive deep into the code shall we:
here is NormalAttack's doCombat function
Code:
key: "doCombat",
value: function(e, t, o, n) {
    var a = this
      , s = arguments.length > 4 && void 0 !== arguments[4] ? arguments[4] : 0
      , i = arguments.length > 5 && void 0 !== arguments[5] ? arguments[5] : 0
      , r = window.hitObj = this.attemptWeaponHit(this.owner, o, i)
      , h = r.hit
      , l = r.crit
      , u = CombatHelper.weaponDamage(this.owner, l, !1, s)
      , y = h ? this.applyDamage(this.owner, o, u) : [0, 0]
      , g = this.owner.weaponSecondary && this.owner.weaponSecondary.canDualWield() ? function() {
        var e = a.attemptWeaponHitSecondary(a.owner, o)
          , t = e.hit
          , n = e.crit
          , s = CombatHelper.weaponDamageSecondary(a.owner, n);
        return {
            hit: t,
            crit: n,
            resultDamage: t ? a.applyDamage(a.owner, o, s) : [0, 0]
        }
    }() : null;
    return n ? (output(textify(d, CombatHelper.output(y, l))),
    handleSecondary(g),
    {
        hit: h,
        crit: l,
        resultDamage: y,
        secondary: g
    }) : {
        hit: h,
        crit: l,
        resultDamage: y,
        secondary: g
    }
}
you can see line 19 that we use NormalAttack.applyDamage with the base damage of the secondary weapon (argument "s")
here is NormalAttack's (and any power's for that matter) applyDamage function:
Code:
key: "applyDamage",
value: function(e, t, o) {
    CombatManager.pushAliases(),
    window.char = t;
    var n = this.executingPower();
    if (n && n.isStealable() && t.isPC() && t.hasStance(POWERS.MirrorStance) && !t.hasPower(n.constructor) && (t.addPower(n.constructor),
    CombatManager.buffer("\nFor the briefest second, [char.combatName's] mind is as sharp as dragonglass. <b>[char.CombatName] [tps|has|have] learned " + n.name + "!</b>")),
    t.itemIsEquipped(ITEMS.PainSlutChoker) && o.preCritDamage) {
        var a = 0;
        if (o.damage.forEach(function(e, t) {
            if (!b.CombatHelper.hitsResolve(e)) {
                var n = o.preCritDamage.damage[t];
                if (n) {
                    var s = e.amount - n.amount;
                    s <= 0 || (e.amount -= s,
                    a += s)
                }
            }
        }),
        a > 0) {
            o = b.CombatHelper.damageAdd(o, {
                type: GLOBALS.DMG_TEASE,
                amount: Math.ceil(.3 * a)
            });
            var s = t.canAdjustUp("libido", 100);
            CombatManager.buffer(ui.parserInjection('\nAs [attacker.combatName] land[tps|s] a particularly harsh hit on [target.combatName], [target.resolveRange 50|[target.combatName] bite[tps|s] [target.combatHisHer] [target.lips] to keep from moaning in pleasure.|[target.combatName] let[tps|s] out a moan of ecstasy, [silly|exclaiming, "Harder [attacker.mf|daddy|mommy]!" at the blow.|doing [target.combatHisHer] best to keep from orgasming on the spot.]] [target.isPC|That may have hurt, but some part of you really wants more of that.[var0| <b>Your libido has increased!</b>]|While that blow definitely had an impact on [target.combatName], it also seems to have made [target.combatHimHer] more excitable!]', [function() {
                return s
            }
            ])),
            s && t.adjustUp("libido", 100, 3)
        }
    }
    (e.itemIsEquipped(ITEMS.RosebloomShield) || e.hasStatusEffect(SEFFECTS.HiveKnightsScent)) && (o.damage = o.damage.map(function(e) {
        var t = e.type
          , o = e.amount;
        return {
            type: t === GLOBALS.DMG_TEASE ? GLOBALS.DMG_PHEROMONE : t,
            amount: o
        }
    }));
    var i = o.damage.some(function(e) {
        var t = e.type;
        return !!e.amount && [GLOBALS.DMG_TEASE, GLOBALS.DMG_DRUG, GLOBALS.DMG_PHEROMONE].includes(t)
    })
      , r = b.CombatHelper.calculateDamage(e, t, o, this.tags)
      , h = r.resolved
      , l = r.postResistObj;
    i && !h[1] && t.isLustImmune && CombatManager.buffer("\n<b>[char.CombatName] [tps|is|are] immune to erotic warfare!</b>");
    var u = this.onDamage(h, l, o, this.allyParty, this.enemyParty, t, e)
      , d = b.CombatHelper.applyDamage(e, t, u);
    return CombatManager.popAliases(),
    d
}
nothing special to see here except line 45, where we call CombatHelper's calculateDamage function where the twist the knife magic will occur; keep in mind that here, argument "o" is the base damage of the secondary weapon.
here is CombatHelper's calculateDamage:
Code:
key: "calculateDamage",
value: function(t, o, a, s) {
    var i = Object.assign({}, a)
      , l = s.includes(GLOBALS.POWER_TAG_SPELL)
      , d = s.includes(GLOBALS.POWER_TAG_WEAPON)
      , y = s.includes(GLOBALS.POWER_TAG_TEASE)
      , g = [];
    l && g.push(t.spellPenetration()),
    d && g.push(t.armorPenetration()),
    y && g.push(t.temptation());
    var c = g.length ? Math.max.apply(Math, g) : t.penetration();
    if (y && (i = e.teaseLikeDislikeStuff(t, o, i, s)),
    t.getCombatEffect(CEFFECTS.Staggered) && (i = e.damageMult(i, .9)),
    t.getPerk(PERKS.TwistTheKnife) && o.hasNegativeEffect() && d) {
        var f = e.damageMult(t.safeWeaponPrimary().damage, .5).damage;
        i = e.damageAdd.apply(e, [i].concat(n(f)))
    }
    switch (i.attackType) {
    case GLOBALS.ATK_PHYSICAL:
        i = e.damageMult(i, e.effectiveDamageMultiplier(o.armor() - c));
        break;
    case GLOBALS.ATK_MAGICAL:
        i = e.damageMult(i, e.effectiveDamageMultiplier(o.warding() - c));
        break;
    case GLOBALS.ATK_MENTAL:
    case GLOBALS.ATK_SEXUAL:
        i = e.damageMult(i, e.effectiveDamageMultiplier(o.focus() - c))
    }
    o.hasStance(POWERS.Tranquility) && (i.damage = i.damage.map(function(t) {
        if (!e.hitsResolve(t))
            return t;
        var n = t.amount * (o.itemIsEquipped(ITEMS.SilverMask) ? .8 : .7);
        return h({}, t, {
            amount: n
        })
    }));
    var m = rand(11)
      , p = u[Options.charOptions.easyMode]
      , w = i.damage.map(function(e) {
        var n = e.type
          , a = e.amount
          , s = o.getResist(n) / 100
          , i = t.isAlly() ? p[0] : o.isAlly() ? p[1] : 1
          , r = (95 + m) / 100;
        return {
            type: n,
            amount: Math.ceil((a - a * s) * r * i)
        }
    })
      , b = {
        attackType: i.attackType,
        damage: w
    }
      , k = w.reduce(function(t, o) {
        var n = r(t, 2)
          , a = n[0]
          , s = n[1]
          , i = o.type
          , h = o.amount;
        return e.hitsResolve({
            type: i
        }) ? [a, s + h] : [a + h, s]
    }, [0, 0])
      , v = r(k, 2);
    return {
        resolved: [v[0], v[1]],
        postResistObj: b
    }
}
here, the twist the knife magic happens line 14 -> 16:
Code:
if ([...], t.getPerk(PERKS.TwistTheKnife) && o.hasNegativeEffect() && d) {
    var f = e.damageMult(t.safeWeaponPrimary().damage, .5).damage;
    i = e.damageAdd.apply(e, [i].concat(n(f)))
}
you can see that even though we're applying damage for the secondary attack, twist the knife still essentially adds half of the primary weapon's base damage.
only solution i can think of would be to add another parameter to calculateDamage to inform what weapon is used, without breaking everything.
Good luck!
 

Balaknightfang

Resident Coke Addict
Moderator
Aug 5, 2018
1,206
1,476
Right so
HAHAHAHAHAAHHA
I'm going to save this for the combat rebalance because WOW
there's a lot more that goes into this and it'll have to be fixed when I'm bad touching the entire system as a whole