Items/Filter

* implement 'effect text' filter
 * slight cleanup in itemset setup to match changes for effect text
This commit is contained in:
Sarjuuk 2026-02-12 12:11:00 +01:00
parent 84d2e30940
commit 68ca4973b1
10 changed files with 170 additions and 90 deletions

View file

@ -1922,7 +1922,7 @@ class ItemListFilter extends Filter
104 => [parent::CR_STRING, 'description', STR_LOCALIZED ], // flavortext
105 => [parent::CR_CALLBACK, 'cbDropsInInstance', SRC_FLAG_DUNGEON_DROP, 1 ], // dropsinnormal [heroicdungeon-any]
106 => [parent::CR_CALLBACK, 'cbDropsInInstance', SRC_FLAG_DUNGEON_DROP, 2 ], // dropsinheroic [heroicdungeon-any]
107 => [parent::CR_NYI_PH, null, 1, ], // effecttext [str] not yet parsed ['effectsParsed_loc'.Lang::getLocale()->value, $crv]
107 => [parent::CR_STRING, 'effects', STR_LOCALIZED ], // effecttext [str]
109 => [parent::CR_CALLBACK, 'cbArmorBonus', null, null ], // armorbonus [op] [int]
111 => [parent::CR_NUMERIC, 'requiredSkillRank', NUM_CAST_INT, true ], // reqskillrank
113 => [parent::CR_FLAG, 'cuFlags', CUSTOM_HAS_SCREENSHOT ], // hasscreenshots

View file

@ -10,6 +10,10 @@ class SpellList extends DBTypeList
{
use listviewHelper, sourceHelper;
public const /* int */ INTERACTIVE_NONE = 0;
public const /* int */ INTERACTIVE_EMBEDDED = 1; // parse combat ratings to %
public const /* int */ INTERACTIVE_FULL = 2; // additionaly allow links and hover tooltips
public static int $type = Type::SPELL;
public static string $brickFile = 'spell';
public static string $dataTable = '?_spell';
@ -88,7 +92,7 @@ class SpellList extends DBTypeList
private array $spellVars = [];
private array $refSpells = [];
private array $tools = [];
private bool $interactive = false;
private int $interactive = self::INTERACTIVE_EMBEDDED;
private int $charLevel = MAX_LEVEL;
private array $scaling = [];
private array $parsedText = [];
@ -833,28 +837,36 @@ class SpellList extends DBTypeList
return $effMask;
}
private function dfnText(string $tooltip, string $text) : string
{
if ($this->interactive < self::INTERACTIVE_FULL)
return $text;
return sprintf(Util::$dfnString, $tooltip, $text);
}
// description-, buff-parsing component
private function resolveEvaluation(string $formula) : string
{
// see Traits in javascript locales
$PlayerName = Lang::main('name');
$pl = $PL = /* playerLevel set manually ? $this->charLevel : */ $this->interactive ? sprintf(Util::$dfnString, 'LANG.level', Lang::game('level')) : Lang::game('level');
$ap = $AP = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.atkpwr[0]', Lang::spell('traitShort', 'atkpwr')) : Lang::spell('traitShort', 'atkpwr');
$rap = $RAP = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.rgdatkpwr[0]', Lang::spell('traitShort', 'rgdatkpwr')) : Lang::spell('traitShort', 'rgdatkpwr');
$sp = $SP = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.splpwr[0]', Lang::spell('traitShort', 'splpwr')) : Lang::spell('traitShort', 'splpwr');
$spa = $SPA = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.arcsplpwr[0]', Lang::spell('traitShort', 'arcsplpwr')) : Lang::spell('traitShort', 'arcsplpwr');
$spfi = $SPFI = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.firsplpwr[0]', Lang::spell('traitShort', 'firsplpwr')) : Lang::spell('traitShort', 'firsplpwr');
$spfr = $SPFR = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.frosplpwr[0]', Lang::spell('traitShort', 'frosplpwr')) : Lang::spell('traitShort', 'frosplpwr');
$sph = $SPH = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.holsplpwr[0]', Lang::spell('traitShort', 'holsplpwr')) : Lang::spell('traitShort', 'holsplpwr');
$spn = $SPN = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.natsplpwr[0]', Lang::spell('traitShort', 'natsplpwr')) : Lang::spell('traitShort', 'natsplpwr');
$sps = $SPS = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.shasplpwr[0]', Lang::spell('traitShort', 'shasplpwr')) : Lang::spell('traitShort', 'shasplpwr');
$bh = $BH = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.splheal[0]', Lang::spell('traitShort', 'splheal')) : Lang::spell('traitShort', 'splheal');
$spi = $SPI = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.spi[0]', Lang::spell('traitShort', 'spi')) : Lang::spell('traitShort', 'spi');
$sta = $STA = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.sta[0]', Lang::spell('traitShort', 'sta')) : Lang::spell('traitShort', 'sta');
$str = $STR = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.str[0]', Lang::spell('traitShort', 'str')) : Lang::spell('traitShort', 'str');
$agi = $AGI = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.agi[0]', Lang::spell('traitShort', 'agi')) : Lang::spell('traitShort', 'agi');
$int = $INT = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.int[0]', Lang::spell('traitShort', 'int')) : Lang::spell('traitShort', 'int');
$pl = $PL = /* playerLevel set manually ? $this->charLevel : */ $this->dfnText('LANG.level', Lang::game('level'));
$ap = $AP = $this->dfnText('LANG.traits.atkpwr[0]', Lang::spell('traitShort', 'atkpwr'));
$rap = $RAP = $this->dfnText('LANG.traits.rgdatkpwr[0]', Lang::spell('traitShort', 'rgdatkpwr'));
$sp = $SP = $this->dfnText('LANG.traits.splpwr[0]', Lang::spell('traitShort', 'splpwr'));
$spa = $SPA = $this->dfnText('LANG.traits.arcsplpwr[0]', Lang::spell('traitShort', 'arcsplpwr'));
$spfi = $SPFI = $this->dfnText('LANG.traits.firsplpwr[0]', Lang::spell('traitShort', 'firsplpwr'));
$spfr = $SPFR = $this->dfnText('LANG.traits.frosplpwr[0]', Lang::spell('traitShort', 'frosplpwr'));
$sph = $SPH = $this->dfnText('LANG.traits.holsplpwr[0]', Lang::spell('traitShort', 'holsplpwr'));
$spn = $SPN = $this->dfnText('LANG.traits.natsplpwr[0]', Lang::spell('traitShort', 'natsplpwr'));
$sps = $SPS = $this->dfnText('LANG.traits.shasplpwr[0]', Lang::spell('traitShort', 'shasplpwr'));
$bh = $BH = $this->dfnText('LANG.traits.splheal[0]', Lang::spell('traitShort', 'splheal'));
$spi = $SPI = $this->dfnText('LANG.traits.spi[0]', Lang::spell('traitShort', 'spi'));
$sta = $STA = $this->dfnText('LANG.traits.sta[0]', Lang::spell('traitShort', 'sta'));
$str = $STR = $this->dfnText('LANG.traits.str[0]', Lang::spell('traitShort', 'str'));
$agi = $AGI = $this->dfnText('LANG.traits.agi[0]', Lang::spell('traitShort', 'agi'));
$int = $INT = $this->dfnText('LANG.traits.int[0]', Lang::spell('traitShort', 'int'));
// only 'ron test spell', guess its %-dmg mod; no idea what bc2 might be
$pa = '<$PctArcane>'; // %arcane
@ -867,14 +879,14 @@ class SpellList extends DBTypeList
$pbhd = '<$PctHealDone>'; // %heal done
$bc2 = '<$bc2>'; // bc2
$HND = $hnd = $this->interactive ? sprintf(Util::$dfnString, '[Hands required by weapon]', 'HND') : 'HND'; // todo (med): localize this one
$MWS = $mws = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.mlespeed[0]', 'MWS') : 'MWS';
$mw = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.dmgmin1[0]', 'mw') : 'mw';
$MW = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.dmgmax1[0]', 'MW') : 'MW';
$mwb = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.mledmgmin[0]', 'mwb') : 'mwb';
$MWB = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.mledmgmax[0]', 'MWB') : 'MWB';
$rwb = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.rgddmgmin[0]', 'rwb') : 'rwb';
$RWB = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.rgddmgmax[0]', 'RWB') : 'RWB';
$HND = $hnd = $this->dfnText('[Hands required by weapon]', 'HND'); // todo (med): localize this one
$MWS = $mws = $this->dfnText('LANG.traits.mlespeed[0]', 'MWS');
$mw = $this->dfnText('LANG.traits.dmgmin1[0]', 'mw');
$MW = $this->dfnText('LANG.traits.dmgmax1[0]', 'MW');
$mwb = $this->dfnText('LANG.traits.mledmgmin[0]', 'mwb');
$MWB = $this->dfnText('LANG.traits.mledmgmax[0]', 'MWB');
$rwb = $this->dfnText('LANG.traits.rgddmgmin[0]', 'rwb');
$RWB = $this->dfnText('LANG.traits.rgddmgmax[0]', 'RWB');
$cond = $COND = fn($a, $b, $c) => $a ? $b : $c;
$eq = $EQ = fn($a, $b) => $a == $b;
@ -911,14 +923,14 @@ class SpellList extends DBTypeList
if (!$evalable)
{
// can't eval constructs because of strings present. replace constructs with strings
$cond = $COND = !$this->interactive ? 'COND' : sprintf(Util::$dfnString, 'COND(<span class=\'q1\'>a</span>, <span class=\'q1\'>b</span>, <span class=\'q1\'>c</span>)<br /> <span class=\'q1\'>a</span> ? <span class=\'q1\'>b</span> : <span class=\'q1\'>c</span>', 'COND');
$eq = $EQ = !$this->interactive ? 'EQ' : sprintf(Util::$dfnString, 'EQ(<span class=\'q1\'>a</span>, <span class=\'q1\'>b</span>)<br /> <span class=\'q1\'>a</span> == <span class=\'q1\'>b</span>', 'EQ');
$gt = $GT = !$this->interactive ? 'GT' : sprintf(Util::$dfnString, 'GT(<span class=\'q1\'>a</span>, <span class=\'q1\'>b</span>)<br /> <span class=\'q1\'>a</span> > <span class=\'q1\'>b</span>', 'GT');
$gte = $GTE = !$this->interactive ? 'GTE' : sprintf(Util::$dfnString, 'GTE(<span class=\'q1\'>a</span>, <span class=\'q1\'>b</span>)<br /> <span class=\'q1\'>a</span> >= <span class=\'q1\'>b</span>', 'GTE');
$floor = $FLOOR = !$this->interactive ? 'FLOOR' : sprintf(Util::$dfnString, 'FLOOR(<span class=\'q1\'>a</span>)', 'FLOOR');
$min = $MIN = !$this->interactive ? 'MIN' : sprintf(Util::$dfnString, 'MIN(<span class=\'q1\'>a</span>, <span class=\'q1\'>b</span>)', 'MIN');
$max = $MAX = !$this->interactive ? 'MAX' : sprintf(Util::$dfnString, 'MAX(<span class=\'q1\'>a</span>, <span class=\'q1\'>b</span>)', 'MAX');
$pl = $PL = !$this->interactive ? 'PL' : sprintf(Util::$dfnString, 'LANG.level', 'PL');
$cond = $COND = $this->dfnText('COND(<span class=\'q1\'>a</span>, <span class=\'q1\'>b</span>, <span class=\'q1\'>c</span>)<br /> <span class=\'q1\'>a</span> ? <span class=\'q1\'>b</span> : <span class=\'q1\'>c</span>', 'COND');
$eq = $EQ = $this->dfnText('EQ(<span class=\'q1\'>a</span>, <span class=\'q1\'>b</span>)<br /> <span class=\'q1\'>a</span> == <span class=\'q1\'>b</span>', 'EQ');
$gt = $GT = $this->dfnText('GT(<span class=\'q1\'>a</span>, <span class=\'q1\'>b</span>)<br /> <span class=\'q1\'>a</span> > <span class=\'q1\'>b</span>', 'GT');
$gte = $GTE = $this->dfnText('GTE(<span class=\'q1\'>a</span>, <span class=\'q1\'>b</span>)<br /> <span class=\'q1\'>a</span> >= <span class=\'q1\'>b</span>', 'GTE');
$floor = $FLOOR = $this->dfnText('FLOOR(<span class=\'q1\'>a</span>)', 'FLOOR');
$min = $MIN = $this->dfnText('MIN(<span class=\'q1\'>a</span>, <span class=\'q1\'>b</span>)', 'MIN');
$max = $MAX = $this->dfnText('MAX(<span class=\'q1\'>a</span>, <span class=\'q1\'>b</span>)', 'MAX');
$pl = $PL = $this->dfnText('LANG.level', 'PL');
// space out operators for better readability
$formula = preg_replace('/(\+|-|\*|\/)/', ' \1 ', $formula);
@ -1116,14 +1128,14 @@ class SpellList extends DBTypeList
$this->scaling[$this->id] = true;
// Aura end
if ($stats)
if ($stats && $this->interactive >= self::INTERACTIVE_EMBEDDED)
{
$fmtStringMin = '<!--rtg%s-->%s&nbsp;<small>(%s)</small>';
$statId = $stats[0]; // could be multiple ratings in theory, but not expected to be
}
/*
todo: export to and solve formulas in javascript e.g.: spell 10187 - ${$42213m1*8*$<mult>} with $mult = ${${$?s31678[${1.05}][${${$?s31677[${1.04}][${${$?s31676[${1.03}][${${$?s31675[${1.02}][${${$?s31674[${1.01}][${1}]}}]}}]}}]}}]}*${$?s12953[${1.06}][${${$?s12952[${1.04}][${${$?s11151[${1.02}][${1}]}}]}}]}}
else if ($this->interactive && ($modStrMin || $modStrMax))
else if ($this->interactive == self::INTERACTIVE_FULL && ($modStrMin || $modStrMax))
{
$this->scaling[$this->id] = true;
$fmtStringMin = $modStrMin.'%s';
@ -1163,7 +1175,7 @@ class SpellList extends DBTypeList
eval("\$max = $max $op $oparg;");
}
if ($this->interactive && ($modStrMin || $modStrMax))
if ($this->interactive >= self::INTERACTIVE_EMBEDDED && ($modStrMin || $modStrMax))
{
$this->scaling[$this->id] = true;
@ -1210,12 +1222,12 @@ class SpellList extends DBTypeList
$this->scaling[$this->id] = true;
// Aura end
if ($stats)
if ($stats && $this->interactive >= self::INTERACTIVE_EMBEDDED)
{
$fmtStringMin = '<!--rtg%s-->%s&nbsp;<small>(%s)</small>';
$statId = $stats[0]; // could be multiple ratings in theory, but not expected to be
}
else if (($modStrMin || $modStrMax) && $this->interactive)
else if (($modStrMin || $modStrMax) && $this->interactive == self::INTERACTIVE_FULL)
{
$this->scaling[$this->id] = true;
$fmtStringMin = $modStrMin.'%s';
@ -1468,8 +1480,8 @@ class SpellList extends DBTypeList
$this->charLevel = $level;
// step -1: already handled?
if (isset($this->parsedText[$this->id][$type][Lang::getLocale()->value][$this->charLevel][(int)$this->interactive]))
return $this->parsedText[$this->id][$type][Lang::getLocale()->value][$this->charLevel][(int)$this->interactive];
if (isset($this->parsedText[$this->id][$type][Lang::getLocale()->value][$this->charLevel][$this->interactive]))
return $this->parsedText[$this->id][$type][Lang::getLocale()->value][$this->charLevel][$this->interactive];
// step 0: get text
$data = $this->getField($type, true);
@ -1575,7 +1587,7 @@ class SpellList extends DBTypeList
$data = strtr($data, ["\r" => '', "\n" => '<br />']);
// cache result
$this->parsedText[$this->id][$type][Lang::getLocale()->value][$this->charLevel][(int)$this->interactive] = [$data, $relSpells, $this->scaling[$this->id]];
$this->parsedText[$this->id][$type][Lang::getLocale()->value][$this->charLevel][$this->interactive] = [$data, $relSpells, $this->scaling[$this->id]];
return [$data, $relSpells, $this->scaling[$this->id]];
}
@ -1621,10 +1633,8 @@ class SpellList extends DBTypeList
}
[$formOutVal, $formOutStr, $statId] = $this->resolveFormulaString($formOutStr, $formPrecision ?: ($topLevel ? 0 : 10));
if ($statId && Util::checkNumeric($formOutVal) && $this->interactive)
$resolved = sprintf($formOutStr, $statId, abs($formOutVal), sprintf(Util::$setRatingLevelString, $this->charLevel, $statId, abs($formOutVal), Util::setRatingLevel($this->charLevel, $statId, abs($formOutVal))));
else if ($statId && Util::checkNumeric($formOutVal))
$resolved = sprintf($formOutStr, $statId, abs($formOutVal), Util::setRatingLevel($this->charLevel, $statId, abs($formOutVal)));
if ($statId && Util::checkNumeric($formOutVal))
$resolved = sprintf($formOutStr, $statId, abs($formOutVal), Util::setRatingLevel($this->charLevel, $statId, abs($formOutVal), $this->interactive == self::INTERACTIVE_FULL));
else
$resolved = sprintf($formOutStr, Util::checkNumeric($formOutVal) ? abs($formOutVal) : $formOutVal);
@ -1661,10 +1671,8 @@ class SpellList extends DBTypeList
$resolved = is_numeric($minPoints) ? abs($minPoints) : $minPoints;
if (isset($fmtStringMin))
{
if (isset($statId) && $this->interactive)
$resolved = sprintf($fmtStringMin, $statId, abs($minPoints), sprintf(Util::$setRatingLevelString, $this->charLevel, $statId, abs($minPoints), Util::setRatingLevel($this->charLevel, $statId, abs($minPoints))));
else if (isset($statId))
$resolved = sprintf($fmtStringMin, $statId, abs($minPoints), Util::setRatingLevel($this->charLevel, $statId, abs($minPoints)));
if (isset($statId))
$resolved = sprintf($fmtStringMin, $statId, abs($minPoints), Util::setRatingLevel($this->charLevel, $statId, abs($minPoints), $this->interactive == self::INTERACTIVE_FULL));
else
$resolved = sprintf($fmtStringMin, $resolved);
}
@ -1799,7 +1807,7 @@ class SpellList extends DBTypeList
return $data;
}
public function renderBuff($level = MAX_LEVEL, $interactive = false, ?array &$buffSpells = []) : ?string
public function renderBuff(int $level = MAX_LEVEL, int $interactive = self::INTERACTIVE_EMBEDDED, ?array &$buffSpells = []) : ?string
{
$buffSpells = [];
@ -1848,7 +1856,7 @@ class SpellList extends DBTypeList
return $x;
}
public function renderTooltip(?int $level = MAX_LEVEL, ?bool $interactive = false, ?array &$ttSpells = []) : ?string
public function renderTooltip(int $level = MAX_LEVEL, int $interactive = self::INTERACTIVE_EMBEDDED, ?array &$ttSpells = []) : ?string
{
$ttSpells = [];

View file

@ -315,7 +315,7 @@ abstract class Util
}
// for item and spells
public static function setRatingLevel(int $level, int $statId, int $val) : string
public static function setRatingLevel(int $level, int $statId, int $val, bool $interactive = false) : string
{
if (in_array($statId, [Stat::DEFENSE_RTG, Stat::DODGE_RTG, Stat::PARRY_RTG, Stat::BLOCK_RTG, Stat::RESILIENCE_RTG]) && $level < 34)
$level = 34;
@ -341,7 +341,9 @@ abstract class Util
if (!in_array($statId, [Stat::DEFENSE_RTG, Stat::EXPERTISE_RTG]))
$result .= '%';
return Lang::item('ratingString', [$statId, $result, $level]);
$result = Lang::item('ratingString', [$statId, $result, $level]);
return $interactive ? sprintf(self::$setRatingLevelString, $level, $statId, $val, $result) : $result;
}
// default ucFirst doesn't convert UTF-8 chars (php 8.4 finally implemented this .. see ya in 2027)

View file

@ -1713,7 +1713,7 @@ $lang = array(
),
'duration' => array(
"jusquà annulation",
"%.2G sec.",
"%.2G sec",
"%.2G min",
"%.2G h",
"%.2G |4jour:jours;"

View file

@ -1460,6 +1460,12 @@ CREATE TABLE `aowow_items` (
`sheatheSoundId` smallint(5) unsigned NOT NULL DEFAULT 0,
`unsheatheSoundId` smallint(5) unsigned NOT NULL DEFAULT 0,
`flagsCustom` int(10) unsigned NOT NULL DEFAULT 0,
`effects_loc0` text DEFAULT NULL,
`effects_loc2` text DEFAULT NULL,
`effects_loc3` text DEFAULT NULL,
`effects_loc4` text DEFAULT NULL,
`effects_loc6` text DEFAULT NULL,
`effects_loc8` text DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `items_index` (`class`),
KEY `idx_model` (`displayId`),

View file

@ -71,7 +71,7 @@ UNLOCK TABLES;
LOCK TABLES `aowow_dbversion` WRITE;
/*!40000 ALTER TABLE `aowow_dbversion` DISABLE KEYS */;
INSERT INTO `aowow_dbversion` VALUES (1769622383,0,NULL,NULL);
INSERT INTO `aowow_dbversion` VALUES (1770889049,0,NULL,NULL);
/*!40000 ALTER TABLE `aowow_dbversion` ENABLE KEYS */;
UNLOCK TABLES;

View file

@ -1,5 +1,5 @@
ALTER TABLE `aowow_creature` ADD FULLTEXT `idx_name4` (`name_loc4`) WITH PARSER ngram;
ALTER TABLE `aowow_items` ADD FULLTEXT `idx_name4` (`name_loc4`) WITH PARSER ngram;
ALTER TABLE `aowow_objects` ADD FULLTEXT `idx_name4` (`name_loc4`) WITH PARSER ngram;
ALTER TABLE `aowow_quests` ADD FULLTEXT `idx_name4` (`name_loc4`) WITH PARSER ngram;
ALTER TABLE `aowow_spell` ADD FULLTEXT `idx_name4` (`name_loc4`) WITH PARSER ngram;
ALTER TABLE `aowow_creature` ADD FULLTEXT `idx_ft_name4` (`name_loc4`) WITH PARSER ngram;
ALTER TABLE `aowow_items` ADD FULLTEXT `idx_ft_name4` (`name_loc4`) WITH PARSER ngram;
ALTER TABLE `aowow_objects` ADD FULLTEXT `idx_ft_name4` (`name_loc4`) WITH PARSER ngram;
ALTER TABLE `aowow_quests` ADD FULLTEXT `idx_ft_name4` (`name_loc4`) WITH PARSER ngram;
ALTER TABLE `aowow_spell` ADD FULLTEXT `idx_ft_name4` (`name_loc4`) WITH PARSER ngram;

View file

@ -0,0 +1,9 @@
ALTER TABLE aowow_items
ADD COLUMN `effects_loc0` text DEFAULT NULL AFTER `flagsCustom`,
ADD COLUMN `effects_loc2` text DEFAULT NULL AFTER `effects_loc0`,
ADD COLUMN `effects_loc3` text DEFAULT NULL AFTER `effects_loc2`,
ADD COLUMN `effects_loc4` text DEFAULT NULL AFTER `effects_loc3`,
ADD COLUMN `effects_loc6` text DEFAULT NULL AFTER `effects_loc4`,
ADD COLUMN `effects_loc8` text DEFAULT NULL AFTER `effects_loc6`;
UPDATE `aowow_dbversion` SET `sql` = CONCAT(IFNULL(`sql`, ''), ' items');

View file

@ -19,9 +19,9 @@ CLISetup::registerSetup("sql", new class extends SetupScript
protected $dbcSourceFiles = ['gemproperties', 'itemdisplayinfo', 'spell', 'glyphproperties', 'durabilityquality', 'durabilitycosts'];
protected $worldDependency = ['item_template', 'item_template_locale', 'spell_group', 'game_event'];
protected $setupAfter = [['icons'], []];
protected $setupAfter = [['icons', 'spell', 'spellvariables', 'spellrange'], []];
private $skill2cat = array(
private const /* array */ SKILL_CATG = array(
SKILL_INSCRIPTION => 11,
SKILL_FISHING => 9,
SKILL_MINING => 12,
@ -118,7 +118,8 @@ CLISetup::registerSetup("sql", new class extends SetupScript
0 AS dropDownSoundId,
0 AS sheatheSoundId,
0 AS unsheatheSoundId,
flagsCustom
flagsCustom,
null AS effects_loc0, null AS effects_loc2, null AS effects_loc3, null AS effects_loc4, null AS effects_loc6, null AS effects_loc8
FROM item_template it
LEFT JOIN item_template_locale itl2 ON it.entry = itl2.ID AND itl2.locale = "frFR"
LEFT JOIN item_template_locale itl3 ON it.entry = itl3.ID AND itl3.locale = "deDE"
@ -136,12 +137,14 @@ CLISetup::registerSetup("sql", new class extends SetupScript
$i = 0;
while ($items = DB::World()->select($baseQuery, $ids ?: DBSIMPLE_SKIP, CLISetup::SQL_BATCH * $i, CLISetup::SQL_BATCH))
{
CLI::write(' * batch #' . ++$i . ' (' . count($items) . ')', CLI::LOG_BLANK, true, true);
CLI::write(' * batch #' . ++$i . ' (' . count($items) . ')', tmpRow: true);
foreach ($items as $item)
DB::Aowow()->query('INSERT INTO ?_items VALUES (?a)', array_values($item));
}
CLI::write('[items] - applying misc data & fixes');
// merge with gemProperties
DB::Aowow()->query('UPDATE ?_items i, dbc_gemproperties gp SET i.gemEnchantmentId = gp.enchantmentId, i.gemColorMask = gp.colorMask WHERE i.gemColorMask = gp.id');
@ -205,7 +208,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s SET i.class = 0, i.subClass = 6 WHERE s.id = i.spellId1 AND s.effect1Id = 53 AND i.classBak = 12');
// move some generic recipes into appropriate sub-categories
foreach ($this->skill2cat as $skill => $cat)
foreach (self::SKILL_CATG as $skill => $cat)
DB::Aowow()->query('UPDATE ?_items SET subClass = ?d WHERE classBak = 9 AND subClassBak = 0 AND requiredSkill = ?d', $cat, $skill);
// assign slot from onUse spell to item (todo (med): handle multi slot enchantments (like armor kits))
@ -262,6 +265,58 @@ CLISetup::registerSetup("sql", new class extends SetupScript
foreach ($checks as [$slots, $subclasses])
DB::Aowow()->query('UPDATE ?_items SET `cuFlags` = `cuFlags` | ?d WHERE `class`= ?d AND `slotBak` IN (?a) AND `subClass` NOT IN (?a)', CUSTOM_EXCLUDE_FOR_LISTVIEW, ITEM_CLASS_WEAPON, $slots, $subclasses);
CLI::write('[items] - collecting spell descriptions');
CLI::write(' * fetching', tmpRow: true);
$itemSpellData = DB::Aowow()->select(
'SELECT `id` AS "0", `spellId1` AS "1" FROM ?_items WHERE `spellId1` > 0 UNION
SELECT `id` AS "0", `spellId2` AS "1" FROM ?_items WHERE `spellId2` > 0 UNION
SELECT `id` AS "0", `spellId3` AS "1" FROM ?_items WHERE `spellId3` > 0 UNION
SELECT `id` AS "0", `spellId4` AS "1" FROM ?_items WHERE `spellId4` > 0 UNION
SELECT `id` AS "0", `spellId5` AS "1" FROM ?_items WHERE `spellId5` > 0'
);
$itemSpells = new SpellList(array(['id', array_column($itemSpellData, 1)]), ['interactive' => SpellList::INTERACTIVE_NONE]);
$items = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, `spellId1`, `spellId2`, `spellId3`, `spellId4`, `spellId5` FROM ?_items WHERE `id` IN (?a)', array_column($itemSpellData, 0));
if (!$itemSpells->error)
{
$i = 0;
$total = count($items) * count(CLISetup::$locales);
$update = [];
foreach (CLISetup::$locales as $locId => $loc)
{
Lang::load($loc);
foreach ($items as $itemId => $spells)
{
CLI::write(' * applying ' . str_pad(++$i, strlen($total), pad_type: STR_PAD_LEFT) . ' / ' . $total . str_pad('('.number_format(100 * $i / $total, 1).'%)', 8, pad_type: STR_PAD_LEFT), tmpRow: true);
foreach ($spells as $spellId)
{
if (!$itemSpells->getEntry($spellId))
continue;
if ($_ = $itemSpells->parseText('description'))
{
if (!isset($update[$itemId]['effects_loc'.$locId]))
$update[$itemId]['effects_loc'.$locId] = '';
$update[$itemId]['effects_loc'.$locId] .= $_[0]."\n";
}
}
}
}
$i = 0;
$total = count($update);
foreach ($update as $itemId => $upd)
{
CLI::write(' * writing ' . str_pad(++$i, strlen($total), pad_type: STR_PAD_LEFT) . ' / ' . $total . str_pad('('.number_format(100 * $i / $total, 1).'%)', 8, pad_type: STR_PAD_LEFT), tmpRow: true);
DB::Aowow()->query('UPDATE ?_items SET ?a WHERE `id` = ?d', $upd, $itemId);
}
}
$this->reapplyCCFlags('items', Type::ITEM);
return true;

View file

@ -196,6 +196,15 @@ CLISetup::registerSetup("sql", new class extends SetupScript
$virtualId = 0;
$sets = DB::Aowow()->select('SELECT *, `id` AS ARRAY_KEY FROM dbc_itemset');
$spells = array_merge(
array_column($sets, 'spellId1'), array_column($sets, 'spellId2'), array_column($sets, 'spellId3'),
array_column($sets, 'spellId4'), array_column($sets, 'spellId5'), array_column($sets, 'spellId6'),
array_column($sets, 'spellId7'), array_column($sets, 'spellId8'), array_column($sets, 'spellId9')
);
$bonusSpells = new SpellList(array(['s.id', array_unique($spells)]), ['interactive' => SpellList::INTERACTIVE_NONE]);
$pieces = DB::World()->select('SELECT `itemset` AS ARRAY_KEY, `entry` AS ARRAY_KEY2, `entry`, `name`, `class`, `subclass`, `Quality`, `AllowableClass`, `ItemLevel`, `RequiredLevel`, `itemset`, IF (`Flags` & ?d, 1, 0) AS "heroic", IF(`InventoryType` = 15, 26, IF(`InventoryType` = 5, 20, `InventoryType`)) AS "slot" FROM item_template WHERE `itemset` > 0', ITEM_FLAG_HEROIC);
foreach ($sets as $setId => $setData)
{
@ -210,25 +219,16 @@ CLISetup::registerSetup("sql", new class extends SetupScript
if ($setData['reqSkillLevel'])
$row['skillLevel'] = $setData['reqSkillLevel'];
/********************/
/* calc statbonuses */
/********************/
$spells = [];
$j = 1;
for ($i = 1; $i < 9; $i++)
if ($setData['spellId'.$i] > 0 && $setData['itemCount'.$i] > 0)
$spells[$i] = [$setData['spellId'.$i], $setData['itemCount'.$i]];
{
if ($setData['spellId'.$i] <= 0 || $setData['itemCount'.$i] <= 0)
continue;
$bonusSpells = new SpellList(array(['s.id', array_column($spells, 0)]));
$spells = array_pad($spells, 8, [0, 0]);
foreach (array_column($spells, 0) as $idx => $spellId)
$row['spell'.($idx+1)] = $spellId;
foreach (array_column($spells, 1) as $idx => $nItems)
$row['bonus'.($idx+1)] = $nItems;
$row['spell'.$j] = $setData['spellId'.$i];
$row['bonus'.$j] = $setData['itemCount'.$i];
$j++;
}
/**************************/
@ -243,16 +243,18 @@ CLISetup::registerSetup("sql", new class extends SetupScript
$row['name_loc'.$locId] = Util::localizedString($setData, 'name');
foreach ($bonusSpells->iterate() as $__)
for ($i = 1; $i < 9; $i++)
{
if (!$setData['spellId'.$i] || !$bonusSpells->getEntry($setData['spellId'.$i]))
continue;
if (!isset($descText[$locId]))
$descText[$locId] = '';
$descText[$locId] .= $bonusSpells->parseText()[0]."\n";
}
// strip rating blocks - e.g. <!--rtg19-->14&nbsp;<small>(<!--rtg%19-->0.30%&nbsp;@&nbsp;L<!--lvl-->80)</small>
$row['bonusText_loc'.$locId] = preg_replace('/<!--rtg\d+-->(\d+)&nbsp.*?<\/small>/i', '\1', $descText[$locId]);
$row['bonusText_loc'.$locId] = $descText[$locId];
}
@ -260,8 +262,6 @@ CLISetup::registerSetup("sql", new class extends SetupScript
/* determine type and reuse from pieces */
/****************************************/
$pieces = DB::World()->select('SELECT `entry`, `name`, `class`, `subclass`, `Quality`, `AllowableClass`, `ItemLevel`, `RequiredLevel`, `itemset`, IF (`Flags` & ?d, 1, 0) AS "heroic", IF(`InventoryType` = 15, 26, IF(`InventoryType` = 5, 20, `InventoryType`)) AS "slot", `entry` AS ARRAY_KEY FROM item_template WHERE `itemset` = ?d', ITEM_FLAG_HEROIC, $setId);
/*
possible cases:
1) unused entry (empty data)
@ -269,7 +269,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
3) one itemset from one dbc entry (basic case). duplicate items per slot possible
*/
if (count($pieces) < 2)
if (count($pieces[$setId] ?? []) < 2)
{
$row['cuFlags'] = CUSTOM_EXCLUDE_FOR_LISTVIEW;
DB::Aowow()->query('INSERT INTO ?_itemset (?#) VALUES (?a)', array_keys($row), array_values($row));
@ -279,7 +279,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
$sorted = [];
// sort available items by slot, sort slot by itemID ASC
foreach ($pieces as $data)
foreach ($pieces[$setId] as $data)
{
$data['note'] = $this->getContentGroup($data);
if (in_array($data['note'], [23, 25, 27, 29, 17, 19, 20, 22, 24, 26, 28, 30]))