feat: 15.25 Base Spell Power#797
Conversation
|
I did a small study on spell formulas, based on tooling to estimate damage and datapoints collected from global tibia. These are by no means final, but should provide a decent starting/base point to progress from. — Spell Damage Formulas (Finalized 2026-06-23)Level Contribution: B(L)All spells — damage, healing, every vocation — include B(L) as a base component. Quick reference:
Skill Spells (Knight / Monk)Formula:
Projections (typical gear):
Magic Spells (Sorcerer / Druid / Paladin)Formula:
Projections (typical magic levels):
Shielding Spells (Shield Bash / Shield Slam)Formula: Same structure as melee —
Auto-Attack (All Vocations)Formula:
No Base Power ReferenceAttack Spells — Magic Level (Sorcerer / Druid / Paladin)
Attack Spells — Skill (Knight / Monk / Paladin)
Attack Spells — Shielding (Knight)
Runes — Magic Level (all vocations)
Healing Spells — Magic Level
Healing Spells — Magic Level + Shielding (Knight)Uses the same avg formula but with an extra shielding term (formula TBD):
Notes
|
|
My entire PR was built based on the issue, and all |
Spell Damage Formula ReworkProblem with the current approachThe current implementation handles spell damage in two inconsistent ways: Skill spells (knight) compute min/max inline in each callback using hardcoded range coefficients applied to -- current berserk
local min = B(level) + (skill + attack) * 0.5
local max = B(level) + (skill + attack) * 1.5
return -min * 1.1, -max * 1.1Magic spells (sorc/druid/paladin) hardcode ml coefficients per spell, completely ignoring -- current energy strike / flame strike
local min = B(level) + maglevel * 1.403 + 8
local max = B(level) + maglevel * 2.203 + 13Issues with this approach:
Proposed approachTwo unified helper functions driven by a single Skill-based spells (knight, monk): Magic-based spells (sorc, druid, paladin): Both return a symmetric ±10% range around Where The coefficients To adjust a spell up or down, you change one number: spell:basePower(44) -- increase to buff, decrease to nerfA server-wide What it looks like in practiceBerserk (skill-based) — before vs after: -- CURRENT
function onGetFormulaValues(player, skill, attack, factor)
local level = player:getLevel()
local min = (calculateBaseDamageHealing(level)) + (skill + attack) * 0.5
local max = (calculateBaseDamageHealing(level)) + (skill + attack) * 1.5
return -min * 1.1, -max * 1.1
end-- PROPOSED
function onGetFormulaValues(player, skill, attack, factor)
local avg = spellSkillDamage(44, player:getLevel(), skill, attack)
return -math.floor(avg * 0.9), -math.ceil(avg * 1.1)
endEnergy Strike (magic-based) — before vs after: -- CURRENT
function onGetFormulaValues(player, level, maglevel, basePower)
local min = (calculateBaseDamageHealing(level)) + (maglevel * 1.403) + 8
local max = (calculateBaseDamageHealing(level)) + (maglevel * 2.203) + 13
return -min, -max
end-- PROPOSED
function onGetFormulaValues(player, level, maglevel)
local avg = spellMagicDamage(45, level, maglevel)
return -math.floor(avg * 0.9), -math.ceil(avg * 1.1)
endThe helper functions ( Side-by-side comparisonNumbers below use Berserk (exori) — bp=44
Fierce Berserk (exori gran) — bp=92
Energy Strike / Flame Strike — Sorc/Druid — bp=45
Summary
|
|
Now you can test latest charges |
15.25 — Spell Base Power & combat formula update
Summary
This PR aligns spell damage/healing with Tibia 15.25 mechanics, introducing per-spell Base Power as a first-class attribute and updating level contribution to the post-patch B(L) formula (13.05.12657). It also includes related protocol fixes from the same release cycle.
Spell Base Power
C++
basePowertoSpell(getBasePower()/setBasePower()).spell:basePower(value)/spell:basePower()(getter).basePowerautomatically:CALLBACK_PARAM_LEVELMAGICVALUE→(player, level, maglevel, basePower)CALLBACK_PARAM_SKILLVALUE→(player, skill, attack, factor, basePower)instantSpellName/runeSpellName).Level contribution — B(L)
New helper
getBaseDamageHealing(level)intools.cpp/tools.hpp:Combat::getLevelFormulanow usesB(L) * 2 + ml * 3instead oflevel * 2 + ml * 3.Replaces legacy
level / 5andlevel * 0.2in Lua spell scripts.Lua helpers (
register_spells.lua)calculateBaseDamageHealing(level)calculateAttackValue(player, skill, weaponDamage)calculateMonkSpellDamage(...)(basePower * attackValue) / 100 + (spellFactor * attackValue)calculateKnightHealing(...)calculateLevelMagicDamage(...)Spell scripts updated
spell:basePower(N)from Tibia Wiki data.calculateMonkSpellDamagewith callbackbasePower.calculateKnightHealing.basePowerfrom callback instead of hardcoded constants.level / 5→calculateBaseDamageHealing(level).Example:
Banners
New banner types registered and wired:
BANNER_TYPE_WEEKLY_TASK_ANY_CREATUREioweeklytasks.cpp)BANNER_TYPE_PROMOTION_GRANTEDmodules.lua) and!promotion/bannervalidates against a whitelist ofBANNER_TYPE_*constants.Files changed (high level)
spells.hpp,spells.cpp,spell_functions.cpp,combat.cpp,tools.cppdata/scripts/lib/register_spells.lua,data/scripts/spells/**Test plan
45, Annihilation125, Swift Jab12) and compare damage vs Cyclopedia expectations at multiple levels.basePowerfrom spell.Breaking changes
onGetFormulaValuescallbacks receive an extrabasePowerargument (backward compatible — unused params are ignored in Lua).level/5toB(L)— damage/healing curves differ at high levels (intended, matches Tibia 13.05.12657+).Notes
Lesser Mystic Repulsehas base power on the wiki but no spell script in this repo yet.spell:basePower()for metadata/future use.base_powerand use outdated level scaling #792