From 68ca4973b116b114b037546f411be77b70869b93 Mon Sep 17 00:00:00 2001 From: Sarjuuk Date: Thu, 12 Feb 2026 12:11:00 +0100 Subject: [PATCH] Items/Filter * implement 'effect text' filter * slight cleanup in itemset setup to match changes for effect text --- includes/dbtypes/item.class.php | 2 +- includes/dbtypes/spell.class.php | 110 +++++++++++++----------- includes/utilities.php | 6 +- localization/locale_frfr.php | 2 +- setup/sql/01-db_structure.sql | 6 ++ setup/sql/02-db_initial_data.sql | 2 +- setup/sql/04-db_optional_mysql_only.sql | 10 +-- setup/sql/updates/1770889048_01.sql | 9 ++ setup/tools/sqlgen/items.ss.php | 65 ++++++++++++-- setup/tools/sqlgen/itemset.ss.php | 48 +++++------ 10 files changed, 170 insertions(+), 90 deletions(-) create mode 100644 setup/sql/updates/1770889048_01.sql diff --git a/includes/dbtypes/item.class.php b/includes/dbtypes/item.class.php index 50869817..7d075ef0 100644 --- a/includes/dbtypes/item.class.php +++ b/includes/dbtypes/item.class.php @@ -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 diff --git a/includes/dbtypes/spell.class.php b/includes/dbtypes/spell.class.php index 1336eeca..bee1233c 100644 --- a/includes/dbtypes/spell.class.php +++ b/includes/dbtypes/spell.class.php @@ -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(a, b, c)
a ? b : c', 'COND'); - $eq = $EQ = !$this->interactive ? 'EQ' : sprintf(Util::$dfnString, 'EQ(a, b)
a == b', 'EQ'); - $gt = $GT = !$this->interactive ? 'GT' : sprintf(Util::$dfnString, 'GT(a, b)
a > b', 'GT'); - $gte = $GTE = !$this->interactive ? 'GTE' : sprintf(Util::$dfnString, 'GTE(a, b)
a >= b', 'GTE'); - $floor = $FLOOR = !$this->interactive ? 'FLOOR' : sprintf(Util::$dfnString, 'FLOOR(a)', 'FLOOR'); - $min = $MIN = !$this->interactive ? 'MIN' : sprintf(Util::$dfnString, 'MIN(a, b)', 'MIN'); - $max = $MAX = !$this->interactive ? 'MAX' : sprintf(Util::$dfnString, 'MAX(a, b)', 'MAX'); - $pl = $PL = !$this->interactive ? 'PL' : sprintf(Util::$dfnString, 'LANG.level', 'PL'); + $cond = $COND = $this->dfnText('COND(a, b, c)
a ? b : c', 'COND'); + $eq = $EQ = $this->dfnText('EQ(a, b)
a == b', 'EQ'); + $gt = $GT = $this->dfnText('GT(a, b)
a > b', 'GT'); + $gte = $GTE = $this->dfnText('GTE(a, b)
a >= b', 'GTE'); + $floor = $FLOOR = $this->dfnText('FLOOR(a)', 'FLOOR'); + $min = $MIN = $this->dfnText('MIN(a, b)', 'MIN'); + $max = $MAX = $this->dfnText('MAX(a, b)', '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 = '%s (%s)'; $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*$} 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 = '%s (%s)'; $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" => '
']); // 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 = []; diff --git a/includes/utilities.php b/includes/utilities.php index 0857a4f0..61d8319a 100644 --- a/includes/utilities.php +++ b/includes/utilities.php @@ -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) diff --git a/localization/locale_frfr.php b/localization/locale_frfr.php index 578e13dc..10ae87b5 100644 --- a/localization/locale_frfr.php +++ b/localization/locale_frfr.php @@ -1713,7 +1713,7 @@ $lang = array( ), 'duration' => array( "jusqu’à annulation", - "%.2G sec.", + "%.2G sec", "%.2G min", "%.2G h", "%.2G |4jour:jours;" diff --git a/setup/sql/01-db_structure.sql b/setup/sql/01-db_structure.sql index 4196c9da..99d8df6b 100644 --- a/setup/sql/01-db_structure.sql +++ b/setup/sql/01-db_structure.sql @@ -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`), diff --git a/setup/sql/02-db_initial_data.sql b/setup/sql/02-db_initial_data.sql index 40fbdae8..be9f609a 100644 --- a/setup/sql/02-db_initial_data.sql +++ b/setup/sql/02-db_initial_data.sql @@ -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; diff --git a/setup/sql/04-db_optional_mysql_only.sql b/setup/sql/04-db_optional_mysql_only.sql index 51f2003a..80561cb0 100644 --- a/setup/sql/04-db_optional_mysql_only.sql +++ b/setup/sql/04-db_optional_mysql_only.sql @@ -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; diff --git a/setup/sql/updates/1770889048_01.sql b/setup/sql/updates/1770889048_01.sql new file mode 100644 index 00000000..54df351e --- /dev/null +++ b/setup/sql/updates/1770889048_01.sql @@ -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'); diff --git a/setup/tools/sqlgen/items.ss.php b/setup/tools/sqlgen/items.ss.php index 80dea78e..ae1e2451 100644 --- a/setup/tools/sqlgen/items.ss.php +++ b/setup/tools/sqlgen/items.ss.php @@ -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; diff --git a/setup/tools/sqlgen/itemset.ss.php b/setup/tools/sqlgen/itemset.ss.php index 32704569..090db02e 100644 --- a/setup/tools/sqlgen/itemset.ss.php +++ b/setup/tools/sqlgen/itemset.ss.php @@ -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. 14 (0.30% @ L80) - $row['bonusText_loc'.$locId] = preg_replace('/(\d+) .*?<\/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]))