Hello.
I have two ring in the beginning of a game.
One is a wizards ring of massacre (5%).
One is a duelist ring of see invisible (+3 dex)
When I test them the second ring gives me 1 point extra damage on both daggers.
Will this always be the case, I mean that the +3dex is worth more than +5% physical?
Or can the percentage to physical be worth more later on with other daggers and more stats?
Yes, I am aware that I can test it out, but what does the code say about this?
Tom
b34 Damage question (duelist ring vs massacre)
Moderator: Moderator
Re: b34 Damage question (duelist ring vs massacre)
The 5% will be worth more later in the game, whilst the +3 Dex will always give +1.5 damage (though it also helps other things like talents and accuracy).
Re: b34 Damage question (duelist ring vs massacre)
I can't really figure out how dex influences the final damage versus modifiers.
This is what I am looking at right now:
combat.lua
This is what I am looking at right now:
combat.lua
Code: Select all
function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
damtype = damtype or (weapon and weapon.damtype) or DamageType.PHYSICAL
mult = mult or 1
-- Does the blow connect? yes .. complex :/
local atk, def = self:combatAttack(weapon), target:combatDefense()
if not self:canSee(target) then atk = atk / 3 end
local dam, apr, armor = force_dam or self:combatDamage(weapon), self:combatAPR(weapon), target:combatArmor()
print("[ATTACK] to ", target.name, " :: ", dam, apr, armor, def, "::", mult)
if target:knowTalent(target.T_DUCK_AND_DODGE) then
local diff = util.bound((self.size_category or 3) - (target.size_category or 2), 0, 5)
def = def + diff * target:getTalentLevelRaw(target.T_DUCK_AND_DODGE) * 1.2
end
-- If hit is over 0 it connects, if it is 0 we still have 50% chance
local hitted = false
local crit = false
local evaded = false
if self:checkEvasion(target) then
evaded = true
game.logSeen(target, "%s evades %s.", target.name:capitalize(), self.name)
elseif self:checkHit(atk, def) then
local pres = util.bound(target:combatArmorHardiness() / 100, 0, 1)
print("[ATTACK] raw dam", dam, "versus", armor, pres, "with APR", apr)
armor = math.max(0, armor - apr)
dam = math.max(dam * pres - armor, 0) + (dam * (1 - pres))
print("[ATTACK] after armor", dam)
local damrange = self:combatDamageRange(weapon)
dam = rng.range(dam, dam * damrange)
print("[ATTACK] after range", dam)
dam, crit = self:physicalCrit(dam, weapon, target)
print("[ATTACK] after crit", dam)
dam = dam * mult
print("[ATTACK] after mult", dam)
if weapon and weapon.inc_damage_type then
for t, idt in pairs(weapon.inc_damage_type) do
if target.type.."/"..target.subtype == t or target.type == t then dam = dam + dam * idt / 100 break end
end
print("[ATTACK] after inc by type", dam)
end
if crit then game.logSeen(self, "#{bold}#%s performs a critical strike!#{normal}#", self.name:capitalize()) end
DamageType:get(damtype).projector(self, target.x, target.y, damtype, math.max(0, dam))
hitted = true
else
local srcname = game.level.map.seens(self.x, self.y) and self.name:capitalize() or "Something"
game.logSeen(target, "%s misses %s.", srcname, target.name)
end
-- Spread diseases
if hitted and self:knowTalent(self.T_CARRIER) and rng.percent(4 * self:getTalentLevelRaw(self.T_CARRIER)) then
-- Use epidemic talent spreading
local t = self:getTalentFromId(self.T_EPIDEMIC)
t.do_spread(self, t, target)
end
-- Melee project
if hitted and not target.dead and weapon and weapon.melee_project then for typ, dam in pairs(weapon.melee_project) do
if dam > 0 then
DamageType:get(typ).projector(self, target.x, target.y, typ, dam)
end
end end
if hitted and not target.dead then for typ, dam in pairs(self.melee_project) do
if dam > 0 then
DamageType:get(typ).projector(self, target.x, target.y, typ, dam)
end
end end
-- Weapon of light cast
if hitted and not target.dead and self:knowTalent(self.T_WEAPON_OF_LIGHT) and self:isTalentActive(self.T_WEAPON_OF_LIGHT) then
local dam = 7 + self:getTalentLevel(self.T_WEAPON_OF_LIGHT) * self:combatSpellpower(0.092)
DamageType:get(DamageType.LIGHT).projector(self, target.x, target.y, DamageType.LIGHT, dam)
self:incPositive(-3)
if self:getPositive() <= 0 then
self:forceUseTalent(self.T_WEAPON_OF_LIGHT, {ignore_energy=true})
end
end
-- Shadow cast
if hitted and not target.dead and self:knowTalent(self.T_SHADOW_COMBAT) and self:isTalentActive(self.T_SHADOW_COMBAT) and self:getMana() > 0 then
local dam = 2 + self:combatTalentSpellDamage(self.T_SHADOW_COMBAT, 2, 50)
local mana = 2
if self:getMana() > mana then
DamageType:get(DamageType.DARKNESS).projector(self, target.x, target.y, DamageType.DARKNESS, dam)
self:incMana(-mana)
end
end
-- Temporal cast
if hitted and not target.dead and self:knowTalent(self.T_WEAPON_FOLDING) and self:isTalentActive(self.T_WEAPON_FOLDING) then
local t = self:getTalentFromId(self.T_WEAPON_FOLDING)
local dam = t.getDamage(self, t)
DamageType:get(DamageType.TEMPORAL).projector(self, target.x, target.y, DamageType.TEMPORAL, dam)
end
-- Autospell cast
if hitted and not target.dead and self:knowTalent(self.T_ARCANE_COMBAT) and self:isTalentActive(self.T_ARCANE_COMBAT) then
local t = self:getTalentFromId(self.T_ARCANE_COMBAT)
t.do_trigger(self, t, target)
end
-- On hit talent
if hitted and not target.dead and weapon and weapon.talent_on_hit and next(weapon.talent_on_hit) then
for tid, data in pairs(weapon.talent_on_hit) do
if rng.percent(data.chance) then
self:forceUseTalent(tid, {ignore_cd=true, ignore_energy=true, force_target=target, force_level=data.level, ignore_ressources=true})
end
end
end
-- Shattering Impact
if hitted and self:attr("shattering_impact") and (not self.shattering_impact_last_turn or self.shattering_impact_last_turn < game.turn) then
local dam = dam * self.shattering_impact
self:project({type="ball", radius=1, selffire=false}, target.x, target.y, DamageType.PHYSICAL, dam)
self:incStamina(-15)
self.shattering_impact_last_turn = game.turn
end
-- Onslaught
if hitted and self:attr("onslaught") then
local dir = util.getDir(target.x, target.y, self.x, self.y)
local lx, ly = util.coordAddDir(self.x, self.y, dir_sides[dir or 6].left)
local rx, ry = util.coordAddDir(self.x, self.y, dir_sides[dir or 6].right)
local lt, rt = game.level.map(lx, ly, Map.ACTOR), game.level.map(rx, ry, Map.ACTOR)
if target:checkHit(self:combatAttack(weapon), target:combatPhysicalResist(), 0, 95, 10) and target:canBe("knockback") then
target:knockback(self.x, self.y, self:attr("onslaught"))
end
if lt and lt:checkHit(self:combatAttack(weapon), lt:combatPhysicalResist(), 0, 95, 10) and lt:canBe("knockback") then
lt:knockback(self.x, self.y, self:attr("onslaught"))
end
if rt and rt:checkHit(self:combatAttack(weapon), rt:combatPhysicalResist(), 0, 95, 10) and rt:canBe("knockback") then
rt:knockback(self.x, self.y, self:attr("onslaught"))
end
end
-- Reactive target on hit damage
if hitted then for typ, dam in pairs(target.on_melee_hit) do
if dam > 0 then
DamageType:get(typ).projector(target, self.x, self.y, typ, dam)
end
end end
-- Acid splash
if hitted and target:knowTalent(target.T_ACID_BLOOD) then
local t = target:getTalentFromId(target.T_ACID_BLOOD)
t.do_splash(target, t, self)
end
-- Bloodbath
if hitted and crit and self:knowTalent(self.T_BLOODBATH) then
local t = self:getTalentFromId(self.T_BLOODBATH)
t.do_bloodbath(self, t)
end
-- Mortal Terror
if hitted and not target.dead and self:knowTalent(self.T_MORTAL_TERROR) then
local t = self:getTalentFromId(self.T_MORTAL_TERROR)
t.do_terror(self, t, target, dam)
end
-- Dwarves stoneskin
if hitted and not target.dead and target:attr("auto_stoneskin") and rng.percent(15) then
target:setEffect(target.EFF_STONE_SKIN, 5, {power=target:attr("auto_stoneskin")})
end
-- Conduit (Psi)
if hitted and not target.dead and self:knowTalent(self.T_CONDUIT) and self:isTalentActive(self.T_CONDUIT) and self.use_psi_combat then
local t = self:getTalentFromId(self.T_CONDUIT)
t.do_combat(self, t, target)
end
-- Exploit Weakness
if hitted and not target.dead and self:knowTalent(self.T_EXPLOIT_WEAKNESS) and self:isTalentActive(self.T_EXPLOIT_WEAKNESS) then
local t = self:getTalentFromId(self.T_EXPLOIT_WEAKNESS)
t.do_weakness(self, t, target)
end
-- Special effect
if hitted and not target.dead and weapon and weapon.special_on_hit and weapon.special_on_hit.fct then
weapon.special_on_hit.fct(weapon, self, target)
end
-- Poison coating
if hitted and not target.dead and self.vile_poisons and next(self.vile_poisons) and target:canBe("poison") then
local tid = rng.table(table.keys(self.vile_poisons))
if tid then
local t = self:getTalentFromId(tid)
t.proc(self, t, target, weapon)
end
end
-- Regen on being hit
if hitted and not target.dead and target:attr("stamina_regen_on_hit") then target:incStamina(target.stamina_regen_on_hit) end
if hitted and not target.dead and target:attr("mana_regen_on_hit") then target:incMana(target.mana_regen_on_hit) end
if hitted and not target.dead and target:attr("equilibrium_regen_on_hit") then target:incEquilibrium(-target.equilibrium_regen_on_hit) end
if hitted and self:attr("stamina_use_on_hit") then
self:incStamina(-self.stamina_use_on_hit)
end
if hitted and not target.dead and target:knowTalent(target.T_STONESHIELD) then
local t = target:getTalentFromId(target.T_STONESHIELD)
local m, mm, e, em = t.getValues(self, t)
target:incMana(math.min(dam * m, mm))
target:incEquilibrium(-math.min(dam * e, em))
end
-- Ablative Armor
if hitted and not target.dead and target:attr("carbon_spikes") then
local t = target:getTalentFromId(target.T_CARBON_SPIKES)
t.do_carbonLoss(target, t)
end
-- Riposte!
if not hitted and not target.dead and not evaded and not target:attr("stunned") and not target:attr("dazed") and not target:attr("stoned") and target:knowTalent(target.T_RIPOSTE) and rng.percent(target:getTalentLevel(target.T_RIPOSTE) * (5 + target:getDex(5, true))) then
game.logSeen(self, "%s ripostes!", target.name:capitalize())
target:attackTarget(self, nil, nil, true)
end
-- Set Up
if not hitted and not target.dead and not evaded and not target:attr("stunned") and not target:attr("dazed") and not target:attr("stoned") and target:hasEffect(target.EFF_DEFENSIVE_MANEUVER) then
local t = target:getTalentFromId(target.T_SET_UP)
local power = t.getPower(target, t)
self:setEffect(self.EFF_SET_UP, 2, {src = target, power=power})
end
-- Counter Attack!
if not hitted and not target.dead and not evaded and not target:attr("stunned") and not target:attr("dazed") and not target:attr("stoned") and target:knowTalent(target.T_COUNTER_ATTACK) and rng.percent(target:getTalentLevel(target.T_COUNTER_ATTACK) * (5 + target:getCun(5, true))) then
game.logSeen(self, "%s counters the attack!", target.name:capitalize())
local t = target:getTalentFromId(target.T_COUNTER_ATTACK)
target:attackTarget(self, nil, t.getDamage(target, t), true)
end
-- Defensive Throw!
if not hitted and not target.dead and not evaded and not target:attr("stunned") and not target:attr("dazed") and not target:attr("stoned") and target:knowTalent(target.T_DEFENSIVE_THROW) and rng.percent(target:getTalentLevel(target.T_DEFENSIVE_THROW) * (5 + target:getCun(5, true))) then
local t = target:getTalentFromId(target.T_DEFENSIVE_THROW)
t.do_throw(target, self, t)
end
-- Greater Weapon Focus
local gwf = self:hasEffect(self.EFF_GREATER_WEAPON_FOCUS)
if hitted and not target.dead and weapon and gwf and not gwf.inside and rng.percent(gwf.chance) then
gwf.inside = true
game.logSeen(self, "%s focuses and gains an extra blow!", self.name:capitalize())
self:attackTargetWith(target, weapon, damtype, mult)
gwf.inside = nil
end
-- Zero gravity
if hitted and game.level.data.zero_gravity and rng.percent(util.bound(dam, 0, 100)) then
target:knockback(self.x, self.y, math.ceil(math.log(dam)))
end
-- Visual feedback
if hitted then game.level.map:particleEmitter(target.x, target.y, 1, "melee_attack", {color=target.blood_color}) end
return self:combatSpeed(weapon), hitted
end
Re: b34 Damage question (duelist ring vs massacre)
Code: Select all
function _M:combatDamage(weapon)
Code: Select all
local dam, apr, armor = force_dam or self:combatDamage(weapon), self:combatAPR(weapon), target:combatArmor()
Re: b34 Damage question (duelist ring vs massacre)
I'm fairly sure I can say that statement is incorrect.Grey wrote:the +3 Dex will always give +1.5 damage (though it also helps other things like talents and accuracy).
+3 Dex on a (45% Dex) weapon gives 1.35 points toward the totstat variable in combatDamage. And totstat is one of the inputs used here:
Code: Select all
rescaleDamage(totstat / 1.5 * power * talented_mod)
Code: Select all
function _M:rescaleDamage(dam)
if dam <= 0 then return dam end
return dam * (1 - math.log10(dam * 2) / 7)
end
Let's take an example, with totstat = 10, and all the other gibberish (power * talented_mod / 1.5) = 2. We'll call rescaleDamage(2*10) =~ 15.4. Now if we add 3 Dex, totstat becomes 11.35, so we call rescaleDamage(2*11.35) =~ 17.3. So we gained about 1.9 points of damage in that case. Assuming I didn't screw up the logarithm change of base calculation. Or anything else.