Spells/Scaling

* implement tooltip scaling calculation for spells with attribute
   SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION
 * I don't know why i loaded item scales as spell scales a decade ago.
   Lets hope removing that didn't break stuff.
This commit is contained in:
Sarjuuk 2026-02-05 17:47:41 +01:00
parent 55f599bbb8
commit 3510c8211c
10 changed files with 165 additions and 24 deletions

View file

@ -31,7 +31,7 @@ class DataBaseResponse extends TextResponse
foreach ($this->params as $set)
{
// requires valid token to hinder automated access
if ($set != 'item-scaling' && (!$this->_get['t'] || empty($_SESSION['dataKey']) || $this->_get['t'] != $_SESSION['dataKey']))
if ($set != 'item-scaling' && $set != 'spell-scaling' && (!$this->_get['t'] || empty($_SESSION['dataKey']) || $this->_get['t'] != $_SESSION['dataKey']))
{
trigger_error('DataBaseResponse::generate - session data key empty or expired', E_USER_ERROR);
continue;
@ -54,6 +54,7 @@ class DataBaseResponse extends TextResponse
'quick-excludes',
'weight-presets',
'item-scaling',
'spell-scaling',
'realms',
'statistics' => $this->loadAgnosticFile($set),
// localized

View file

@ -29,6 +29,11 @@ class SpellList extends DBTypeList
public const EFFECTS_SCALING_DAMAGE = array( // as per Unit::SpellDamageBonusDone() calls in TC
SPELL_EFFECT_SCHOOL_DAMAGE, SPELL_EFFECT_HEALTH_LEECH, SPELL_EFFECT_POWER_BURN
);
public const EFFECTS_LDC_SCALING = array(
SPELL_EFFECT_SCHOOL_DAMAGE, SPELL_EFFECT_DUMMY, SPELL_EFFECT_POWER_DRAIN, SPELL_EFFECT_HEALTH_LEECH, SPELL_EFFECT_HEAL,
SPELL_EFFECT_WEAPON_DAMAGE, SPELL_EFFECT_POWER_BURN, SPELL_EFFECT_SCRIPT_EFFECT, SPELL_EFFECT_NORMALIZED_WEAPON_DMG, SPELL_EFFECT_FORCE_CAST_WITH_VALUE,
SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE, SPELL_EFFECT_TRIGGER_MISSILE_SPELL_WITH_VALUE
);
public const EFFECTS_ITEM_CREATE = array(
SPELL_EFFECT_CREATE_ITEM, SPELL_EFFECT_SUMMON_CHANGE_ITEM, SPELL_EFFECT_CREATE_RANDOM_ITEM, SPELL_EFFECT_CREATE_MANA_GEM, SPELL_EFFECT_CREATE_ITEM_2
);
@ -61,6 +66,10 @@ class SpellList extends DBTypeList
public const AURAS_SCALING_DAMAGE = array( // as per Unit::SpellDamageBonusDone() calls in TC
SPELL_AURA_PERIODIC_DAMAGE, SPELL_AURA_PERIODIC_LEECH, SPELL_AURA_DAMAGE_SHIELD, SPELL_AURA_PROC_TRIGGER_DAMAGE
);
public const AURAS_LDC_SCALING = array(
SPELL_AURA_PERIODIC_DAMAGE, SPELL_AURA_DUMMY, SPELL_AURA_PERIODIC_HEAL, SPELL_AURA_DAMAGE_SHIELD, SPELL_AURA_PROC_TRIGGER_DAMAGE,
SPELL_AURA_PERIODIC_LEECH, SPELL_AURA_PERIODIC_MANA_LEECH, SPELL_AURA_SCHOOL_ABSORB, SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE
);
public const AURAS_ITEM_CREATE = array(
SPELL_AURA_CHANNEL_DEATH_ITEM
);
@ -648,6 +657,9 @@ class SpellList extends DBTypeList
$str .= $pcp."% ".Lang::spell('pctCostOf', [mb_strtolower(Lang::spell('powerTypes', $pt))]);
else if ($pc > 0 || $pps > 0 || $pcpl > 0)
{
if ($this->curTpl['attributes0'] & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION)
$str .= '<!--pts'.$this->curTpl['baseLevel'].':'.$pc.'-->';
if (Lang::exist('spell', 'powerCost', $pt))
$str .= Lang::spell('powerCost', $pt, intVal($pps > 0), [$pc, $pps]);
else
@ -690,13 +702,17 @@ class SpellList extends DBTypeList
// formulae base from TC
private function calculateAmountForCurrent(int $effIdx, int $nTicks = 1) : array
{
$level = $this->charLevel;
$maxBase = 0;
$rppl = $this->getField('effect'.$effIdx.'RealPointsPerLevel');
$base = $this->getField('effect'.$effIdx.'BasePoints');
$add = $this->getField('effect'.$effIdx.'DieSides');
$maxLvl = $this->getField('maxLevel');
$baseLvl = $this->getField('baseLevel');
$level = $this->charLevel;
$maxBase = 0;
$rppl = $this->getField('effect'.$effIdx.'RealPointsPerLevel');
$base = $this->getField('effect'.$effIdx.'BasePoints');
$add = $this->getField('effect'.$effIdx.'DieSides');
$maxLvl = $this->getField('maxLevel');
$baseLvl = $this->getField('baseLevel');
$spellLvl = $this->getField('spellLevel');
$LDSEffs = $this->canLevelDamageScale();
$modMin =
$modMax = null;
if ($rppl)
{
@ -705,22 +721,29 @@ class SpellList extends DBTypeList
else if ($level < $baseLvl)
$level = $baseLvl;
if (!$this->getField('atributes0') & SPELL_ATTR0_PASSIVE)
$level -= $this->getField('spellLevel');
if (!$this->getField('attributes0') & SPELL_ATTR0_PASSIVE)
$level -= $spellLvl;
$maxBase += (int)(($level - $baseLvl) * $rppl);
$maxBase *= $nTicks;
}
$min = $nTicks * ($add ? $base + 1 : $base);
$max = $nTicks * ($add + $base);
return [
$min + $maxBase,
$max + $maxBase,
$rppl ? '<!--ppl'.$baseLvl.':'.($maxLvl ?: $level).':'.$min.':'.($rppl * 100 * $nTicks).'-->' : null,
$rppl ? '<!--ppl'.$baseLvl.':'.($maxLvl ?: $level).':'.$max.':'.($rppl * 100 * $nTicks).'-->' : null
];
if ($rppl)
{
$modMin = '<!--ppl'.$baseLvl.':'.($maxLvl ?: $level).':'.$min.':'.($rppl * 100 * $nTicks).'-->';
$modMax = '<!--ppl'.$baseLvl.':'.($maxLvl ?: $level).':'.$max.':'.($rppl * 100 * $nTicks).'-->';
}
else if ($this->getField('attributes0') & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION && in_array($effIdx, $LDSEffs) && $spellLvl)
{
$modMin = '<!--pts'.$spellLvl.':'.abs($min).'-->';
$modMax = '<!--pts'.$spellLvl.':'.abs($max).'-->';
}
return [$min + $maxBase, $max + $maxBase, $modMin, $modMax];
}
public function canCreateItem() : array
@ -766,6 +789,16 @@ class SpellList extends DBTypeList
return $idx;
}
public function canLevelDamageScale() : array
{
$idx = [];
for ($i = 1; $i < 4; $i++)
if (in_array($this->curTpl['effect'.$i.'Id'], SpellList::EFFECTS_LDC_SCALING) || in_array($this->curTpl['effect'.$i.'AuraId'], SpellList::AURAS_LDC_SCALING))
$idx[] = $i;
return $idx;
}
public function isChanneledSpell() : bool
{
return $this->curTpl['attributes1'] & (SPELL_ATTR1_CHANNELED_1 | SPELL_ATTR1_CHANNELED_2);
@ -1970,10 +2003,23 @@ class SpellList extends DBTypeList
if ($xTmp)
$x .= '<table><tr><td>'.implode('<br />', $xTmp).'</td></tr></table>';
$min = $this->scaling[$this->id] ? ($this->getField('baseLevel') ?: 1) : 1;
$max = $this->scaling[$this->id] ? ($this->getField('maxLevel') ?: MAX_LEVEL) : 1;
// scaling information - spellId:min:max:curr
$x .= '<!--?'.$this->id.':'.$min.':'.$max.':'.min($this->charLevel, $max).'-->';
// scaling information - spellId:min:max:curr[:scalingDistribution:ScalingFlags]
$scalingInfo = array(
$this->id,
$this->scaling[$this->id] ? ($this->getField('baseLevel') ?: 1) : 1,
$this->scaling[$this->id] ? ($this->getField('maxLevel') ?: MAX_LEVEL) : 1
);
if ($this->getField('attributes0') & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION)
{
$scalingInfo[] = $this->getField('spellLevel') ?: 1;
$scalingInfo[] = 1; // in 4.x+ proper scaling information; for us just to flag a npc spell as level damage scaling
$scalingInfo[] = 1;
}
else
$scalingInfo[] = min($this->charLevel, $scalingInfo[2]);
$x .= '<!--?'.implode(':', $scalingInfo).'-->';
return $x;
}

View file

@ -7,7 +7,7 @@ mb_substitute_character('none'); // drop invalid char
error_reporting(E_ALL);
mysqli_report(MYSQLI_REPORT_ERROR);
define('AOWOW_REVISION', 45);
define('AOWOW_REVISION', 46);
define('OS_WIN', substr(PHP_OS, 0, 3) == 'WIN'); // OS_WIN as per compile info of php
define('CLI', PHP_SAPI === 'cli');
define('CLI_HAS_E', CLI && // WIN10 and later usually support ANSI escape sequences

View file

@ -0,0 +1 @@
UPDATE `aowow_dbversion` SET `build` = CONCAT(IFNULL(`build`, ''), ' spellscaling itemscaling');

View file

@ -476,6 +476,9 @@ chance = f
[gtcombatratings]
ratio = f
[gtnpcmanacostscaler]
factor = f
[gtoctclasscombatratingscalar]
idx = n
ratio = f

View file

@ -0,0 +1,42 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
CLISetup::registerSetup("build", new class extends SetupScript
{
use TrTemplateFile;
protected $info = array(
'spellscaling' => [[], CLISetup::ARGV_PARAM, 'Compiles spell scaling data to file for spells with attribute SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION.']
);
protected $fileTemplateDest = ['datasets/spell-scaling'];
protected $fileTemplateSrc = ['spell-scaling.in'];
protected $dbcSourceFiles = ['gtnpcmanacostscaler'];
private function debugify(array $data) : string
{
$buff = [];
foreach ($data as $id => $row)
$buff[] = str_pad($id, 7, " ", STR_PAD_LEFT).": ".$row;
return "{\r\n".implode(",\r\n", $buff)."\r\n}";
}
private function spellScalingSV() : string
{
$data = DB::Aowow()->selectCol('SELECT `idx` + 1 AS ARRAY_KEY, `factor` FROM dbc_gtnpcmanacostscaler');
return Cfg::get('DEBUG') ? $this->debugify($data) : Util::toJSON($data);
}
})
?>

View file

@ -6,5 +6,4 @@ $WH.g_convertScalingFactor.SD = /*setup:itemScalingSD*/;
if ($WH.isset('$WowheadPower')) {
$WowheadPower.loadScales(3);
$WowheadPower.loadScales(6);
}

View file

@ -90,7 +90,7 @@ if (typeof $WowheadPower == "undefined") {
},
SCALES = {
3: { url: "?data=item-scaling" },
6: { url: "?data=item-scaling" }
6: { url: "?data=spell-scaling" }
},
LOCALES = {
0: "enus",

View file

@ -0,0 +1,5 @@
$WH.g_convertScalingSpell.SV = /*setup:spellScalingSV*/;
if ($WH.isset('$WowheadPower')) {
$WowheadPower.loadScales(6);
}

View file

@ -1224,6 +1224,24 @@ if (!$WH.wowheadRemote) {
$WH.g_ajaxIshRequest('?data=item-scaling');
}
// aowow - custom..ish
$WH.g_convertScalingSpell = function(base, spellLevel, level) {
let scaler = $WH.g_convertScalingSpell.SV;
if (!scaler[level] || !scaler[spellLevel]) {
if (g_user.roles & U_GROUP_ADMIN) {
alert('There are no spell scaling values for level ' + level);
}
return base;
}
return base *= scaler[level] / scaler[spellLevel];
}
if(!$WH.wowheadRemote)
$WH.g_ajaxIshRequest('?data=spell-scaling');
$WH.g_getDataSource = function() {
if ($WH.isset('g_pageInfo')) {
switch (g_pageInfo.type) {
@ -1330,6 +1348,14 @@ $WH.g_setJsonItemLevel = function (json, level) {
}
};
$WH.g_setJsonSpellLevel = function(json, level)
{
if (!json.scadist)
return;
$WH.cO(json, $WH.g_convertScalingSpell(level, json.scadist));
}
$WH.g_setTooltipLevel = function(tooltip, level) {
var _ = typeof tooltip;
@ -1359,7 +1385,8 @@ $WH.g_setTooltipLevel = function(tooltip, level) {
// Update the tooltip
if (scaDist) {
if (!tooltip.match(/<!--pts[0-9](:[0-9])?-->/g)) { // Not a spell
// if (!tooltip.match(/<!--pts[0-9](:[0-9])?-->/g)) { // Not a spell
if (!tooltip.match(/<!--pts[0-9]+(:[0-9]+)?-->/g)) { // aowow - appropriated for 335a
var
scaFlags = parseInt(_[5]) || 0,
speed = tooltip.match(/<!--spd-->(\d\.\d+)/);
@ -1458,6 +1485,23 @@ $WH.g_setTooltipLevel = function(tooltip, level) {
return '<span class="q2"' + style + '>' + prefix + '<!--rtg' + ratingId + '-->' + value + suffix + '</span>' + br;
});
}
else
{
var json = {
scadist: scaDist
};
// $WH.g_setJsonSpellLevel(json, level);
// Cast time
// tooltip = tooltip.replace(/<!--cast-->\d+\.\d+/, '<!--cast-->' + json.cast);
// Spell effects
// aowow - custom: spell level damage calculation
tooltip = tooltip.replace(/<!--pts(\d+):(\d+)-->\s*\d+/gi, function(_all, spellLvl, base) {
return '<!--pts' + spellLvl + ':' + base + '-->' + Math.round($WH.g_convertScalingSpell(base, parseInt(spellLvl), parseInt(level)));
});
}
}
// Points per level