Loot/Modes

* work against more correctly assigning instance mode to entities and loot
    - added manually collected data for difficulty versions of gameobjects, just boss chests for now.
      update setup/source to default object source to base difficulty version if able
    - update spelldifficulty table to contain the (likely) mapmode it will be used in
  * refactored class loot
    - implement loot mode indicators on listview for creature and gameobject loot
    - show 'drops' listview tab on instance zone page
    - fixes against tribute chest systems (toc / ulduar)
    - fix icc gunship battle chest ownership
This commit is contained in:
Sarjuuk 2025-11-19 17:01:16 +01:00
parent be3701df91
commit a5051c9bf5
33 changed files with 1550 additions and 1038 deletions

View file

@ -1571,6 +1571,26 @@ CREATE TABLE `aowow_mails` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `aowow_objectdifficulty`
--
DROP TABLE IF EXISTS `aowow_objectdifficulty`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `aowow_objectdifficulty` (
`normal10` mediumint(8) unsigned NOT NULL,
`normal25` mediumint(8) unsigned NOT NULL,
`heroic10` mediumint(8) unsigned NOT NULL,
`heroic25` mediumint(8) unsigned NOT NULL,
`mapType` tinyint(3) unsigned NOT NULL,
KEY `normal10` (`normal10`),
KEY `normal25` (`normal25`),
KEY `heroic10` (`heroic10`),
KEY `heroic25` (`heroic25`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `aowow_objects`
--
@ -2813,6 +2833,7 @@ CREATE TABLE `aowow_spelldifficulty` (
`normal25` mediumint(8) unsigned NOT NULL,
`heroic10` mediumint(8) unsigned NOT NULL,
`heroic25` mediumint(8) unsigned NOT NULL,
`mapType` tinyint(3) unsigned NOT NULL,
KEY `normal10` (`normal10`),
KEY `normal25` (`normal25`),
KEY `heroic10` (`heroic10`),

View file

@ -115,6 +115,17 @@ INSERT INTO `aowow_loot_link` VALUES (19710,184465,1,0,0),(19218,184465,1,1,0),(
/*!40000 ALTER TABLE `aowow_loot_link` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Dumping data for table `aowow_objectdifficulty`
--
LOCK TABLES `aowow_objectdifficulty` WRITE;
/*!40000 ALTER TABLE `aowow_objectdifficulty` DISABLE KEYS */;
INSERT INTO `aowow_objectdifficulty` VALUES (181366,193426,0,0,2),(193905,193967,0,0,2),(194307,194308,194200,194201,2),(194312,194314,194313,194315,2),(194324,194328,194327,194331,2),(194789,194956,194957,194958,2),(194821,194822,0,0,2),(195046,195047,0,0,2),(195631,195632,195633,195635,2),(202178,202180,202177,202179,2),(202239,202240,202238,202241,2),(201959,202339,202338,202340,2),(0,0,195668,195672,2),(0,0,195667,195671,2),(0,0,195666,195670,2),(0,0,195665,195669,2),(185168,185169,0,0,1),(184465,184849,0,0,1),(190586,193996,0,0,1),(190663,193597,0,0,1),(191349,193603,0,0,1),(195709,195710,0,0,1),(195323,195324,0,0,1),(195374,195375,0,0,1),(201710,202336,0,0,1);
/*!40000 ALTER TABLE `aowow_objectdifficulty` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
--
-- Dumping data for table `aowow_profiler_excludes`
--

View file

@ -0,0 +1,42 @@
DROP TABLE IF EXISTS `aowow_objectdifficulty`;
CREATE TABLE `aowow_objectdifficulty` (
`normal10` mediumint(8) unsigned NOT NULL,
`normal25` mediumint(8) unsigned NOT NULL,
`heroic10` mediumint(8) unsigned NOT NULL,
`heroic25` mediumint(8) unsigned NOT NULL,
`mapType` tinyint(3) unsigned NOT NULL,
KEY `normal10` (`normal10`),
KEY `normal25` (`normal25`),
KEY `heroic10` (`heroic10`),
KEY `heroic25` (`heroic25`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `aowow_objectdifficulty` VALUES
(181366, 193426, 0, 0 , 2), -- naxxramas: four horsemen chest
(193905, 193967, 0, 0 , 2), -- eoe: alexstrasza's gift
(194307, 194308, 194200, 194201, 2), -- ulduar: cache of winter
(194312, 194314, 194313, 194315, 2), -- ulduar: cache of storms
(194324, 194328, 194325, 194329, 2), -- ulduar: freya's gift +1 elder
(194324, 194328, 194326, 194330, 2), -- ulduar: freya's gift +2 elder
(194324, 194328, 194327, 194331, 2), -- ulduar: freya's gift +3 elder
(194789, 194956, 194957, 194958, 2), -- ulduar: cache of innovation
(194821, 194822, 0, 0 , 2), -- ulduar: gift of the observer
(195046, 195047, 0, 0 , 2), -- ulduar: cache of living stone
(195631, 195632, 195633, 195635, 2), -- toc25: champions' cache
(202178, 202180, 202177, 202179, 2), -- icc: gunship armory (horde)
(201873, 201874, 201872, 201875, 2), -- icc: gunship armory (alliance)
(202239, 202240, 202238, 202241, 2), -- icc: deathbringer's cache
(201959, 202339, 202338, 202340, 2), -- icc: cache of the dreamwalker
(0, 0, 195668, 195672, 2), -- toc25: argent crusade tribute chest 1TL
(0, 0, 195667, 195671, 2), -- toc25: argent crusade tribute chest 25TL
(0, 0, 195666, 195670, 2), -- toc25: argent crusade tribute chest 45TL
(0, 0, 195665, 195669, 2), -- toc25: argent crusade tribute chest 50TL
(185168, 185169, 0, 0 , 1), -- hellfire ramparts: reinforced fel iron chest
(184465, 184849, 0, 0 , 1), -- mechanar: cache of the legion
(190586, 193996, 0, 0 , 1), -- halls of stone: tribunal chest
(190663, 193597, 0, 0 , 1), -- cot - cos: dark runed chest
(191349, 193603, 0, 0 , 1), -- oculus: cache of eregos
(195709, 195710, 0, 0 , 1), -- toc5: champion's cache
(195323, 195324, 0, 0 , 1), -- toc5: confessor's cache
(195374, 195375, 0, 0 , 1), -- toc5: eadric's cache
(201710, 202336, 0, 0 , 1); -- hor: captain's chest

View file

@ -0,0 +1,18 @@
ALTER TABLE `aowow_spelldifficulty`
ADD COLUMN `mapType` tinyint(3) unsigned NOT NULL AFTER `heroic25`
;
-- move linked chest for icc: gunship battle. duplicate saurfang to muradin
DELETE FROM `aowow_loot_link` WHERE `npcId` IN (36939, 38156, 38637, 38638, 36948, 38157, 38639, 38640);
INSERT INTO `aowow_loot_link` (`npcId`, `objectId`, `difficulty`, `priority`, `encounterId`) VALUES
(36939, 201873, 1, 0, 847),
(38156, 201874, 2, 0, 847),
(38637, 201872, 3, 0, 847),
(38638, 201875, 4, 0, 847),
(36948, 202178, 1, 0, 847),
(38157, 202180, 2, 0, 847),
(38639, 202177, 3, 0, 847),
(38640, 202179, 4, 0, 847)
;
UPDATE `aowow_dbversion` SET `sql` = CONCAT(IFNULL(`sql`, ''), ' source spelldifficulty');

View file

@ -26,7 +26,20 @@ CLISetup::registerSetup("sql", new class extends SetupScript
private array $disables = [];
private const /* array */ PVP_MONEY = [26045, 24581, 24579, 43589, 37836]; // Nagrand, Hellfire Pen. H, Hellfire Pen. A, Wintergrasp, Grizzly Hills
private const /* int */ COMMON_THRESHOLD = 100;
private const /* int */ COMMON_THRESHOLD = 30; // if an item has more than X sources it gets filtered by default in loot listviews; ancient WH versions have chance < 1% instead of checking for commonloot property.
// but that would include the super rare vanity pet drops etc, so.. idk? Make it depend of item class and/or quality? That sounds like pain. :<
private const /* array */ FAKE_CHESTS = array( // special cases where multiple chests share the same loot and are spawned for the same encounter
// icc - gunship armory // if we process it like normal the contained items show up as zone drop because technically they have multiple sources. So lets avoid that!
201873 => 202178, // A -> H
201874 => 202180,
201872 => 202177,
201875 => 202179,
// ulduar freya's gift - point +1 and +2 hardmode chests to max chest
194329 => 194331, // 25
194330 => 194331,
194325 => 194327, // 10
194326 => 194327
);
public function generate(array $ids = []) : bool
{
@ -41,10 +54,10 @@ CLISetup::registerSetup("sql", new class extends SetupScript
);
$this->dummyGOs = DB::Aowow()->select(
'SELECT l1.`objectId` AS ARRAY_KEY, BIT_OR(l1.`difficulty`) AS "0", IFNULL(l2.`npcId`, l1.`npcId`) AS "1"
FROM ?_loot_link l1
LEFT JOIN ?_loot_link l2 ON l1.`objectId` = l2.`objectId` AND l2.`priority` = 1
GROUP BY l1.`objectid`'
'SELECT `normal10` AS ARRAY_KEY, 1 AS "0", `normal10` AS "1", `mapType` AS "2" FROM ?_objectdifficulty WHERE `normal10` > 0 UNION
SELECT `normal25` AS ARRAY_KEY, 2 AS "0", `normal10` AS "1", `mapType` AS "2" FROM ?_objectdifficulty WHERE `normal25` > 0 UNION
SELECT `heroic10` AS ARRAY_KEY, 4 AS "0", `normal10` AS "1", `mapType` AS "2" FROM ?_objectdifficulty WHERE `heroic10` > 0 UNION
SELECT `heroic25` AS ARRAY_KEY, 8 AS "0", `normal10` AS "1", `mapType` AS "2" FROM ?_objectdifficulty WHERE `heroic25` > 0'
);
$this->disables = DB::World()->selectCol(
@ -142,23 +155,27 @@ CLISetup::registerSetup("sql", new class extends SetupScript
$this->itemset(); # Meta category .. inherit from items #
$t = new Timer(500);
$d = new Timer(500);
foreach ($this->srcBuffer as $type => $data)
{
$j = 0;
$rows = [];
$sum = count($data);
foreach ($data as $d)
foreach ($data as [$t, $ti, $mt, $mti, $mz, $mFlags, $modes, $sumSources])
{
$rows[++$j] = array_slice($d, 0, 6);
for ($i = 1; $i < 25; $i++)
$rows[$j][] = $d[6][$i] ?? 0;
// can only ever be either/or .. unset if both
if (($mFlags & (SRC_FLAG_RAID_DROP | SRC_FLAG_DUNGEON_DROP)) == (SRC_FLAG_RAID_DROP | SRC_FLAG_DUNGEON_DROP))
$mFlags &= ~(SRC_FLAG_RAID_DROP | SRC_FLAG_DUNGEON_DROP);
if ($d[7] > self::COMMON_THRESHOLD)
$rows[++$j] = [$t, $ti, $mt, $mti, $mz, $mFlags];
for ($i = 1; $i < 25; $i++)
$rows[$j][] = $modes[$i] ?? 0;
if ($sumSources > self::COMMON_THRESHOLD)
$rows[$j][5] |= SRC_FLAG_COMMON;
if ($t->update())
CLI::write('[source] - Inserting... (['.$type.'] '.$j.' / '.$sum.')', CLI::LOG_BLANK, true, true);
if ($d->update())
CLI::write('[source] - Inserting... (['.Type::getFileString($type).'] '.$j.' / '.$sum.')', CLI::LOG_BLANK, true, true);
if (!($j % 300))
$this->insert($rows);
@ -196,7 +213,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
return true;
}
private function pushBuffer(int $type, int $typeId, int $srcId, int $srcBit = 1, int $mType = 0, int $mTypeId = 0, ?int $mZoneId = null, int $mMask = 0x0, int $qty = 1) : void
private function pushBuffer(int $type, int $typeId, int $srcId, int $srcBit = 1, int $mType = 0, int $mTypeId = 0, ?int $mZoneId = null, ?int $mMask = null, int $qty = 1) : void
{
if (!isset($this->srcBuffer[$type]))
$this->srcBuffer[$type] = [];
@ -207,19 +224,26 @@ CLISetup::registerSetup("sql", new class extends SetupScript
return;
}
$b = &$this->srcBuffer[$type][$typeId];
[, , &$bType, &$bTypeId, &$bZone, &$bFlags, &$bSrc, &$bQty] = $this->srcBuffer[$type][$typeId];
if ($mType != $b[2] || $mTypeId != $b[3])
$b[2] = $b[3] = null;
if ($mType != $bType || $mTypeId != $bTypeId)
$bType = $bTypeId = null;
if ($mZoneId && $b[4] === null)
$b[4] = $mZoneId;
else if ($mZoneId && $b[4] && $mZoneId != $b[4])
$b[4] = 0;
if ($bZone === null)
$bZone = $mZoneId;
else if ($mZoneId !== null && $mZoneId != $bZone)
$bZone = 0;
$b[5] = ($b[5] ?? 0) & $mMask; // only bossdrop for now .. remove flag if regular source is available
$b[6][$srcId] = ($b[6][$srcId] ?? 0) | $srcBit; // SIDE_X for quests, modeMask for drops, subSrc for pvp, else: 1
$b[7] += $qty;
if ($bFlags === null) // bossdrop, raid drop, dungeon drop .. remove flag if regular source is available
$bFlags = $mMask;
else if ($mMask !== null)
{
$bFlags &= ($mMask & SRC_FLAG_BOSSDROP);
$bFlags |= ($mMask & (SRC_FLAG_DUNGEON_DROP | SRC_FLAG_RAID_DROP));
}
$bSrc[$srcId] = ($bSrc[$srcId] ?? 0) | $srcBit; // SIDE_X for quests, modeMask for drops, subSrc for pvp, else: 1
$bQty += $qty;
}
private function insert(array &$rows) : void
@ -293,7 +317,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
CLI::write('[source] * #2 Drop [NPC]', CLI::LOG_BLANK, true, true);
$creatureLoot = DB::World()->select(
'SELECT IF(clt.`Reference` > 0, -clt.`Reference`, clt.`Item`) AS "refOrItem", ct.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(1) AS "qty"
'SELECT IF(clt.`Reference` > 0, -clt.`Reference`, clt.`Item`) AS "refOrItem", ct.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(DISTINCT clt.`Reference`) AS "qty"
FROM creature_loot_template clt
JOIN creature_template ct ON clt.`entry` = ct.`lootid`
LEFT JOIN item_template it ON it.`entry` = clt.`Item` AND clt.`Reference` <= 0
@ -301,20 +325,21 @@ CLISetup::registerSetup("sql", new class extends SetupScript
GROUP BY `refOrItem`, ct.`entry`'
);
$npcSpawns = DB::Aowow()->select('SELECT `typeId` AS ARRAY_KEY, IF(COUNT(DISTINCT s.`areaId`) > 1, 0, s.`areaId`) AS "areaId", z.`type` FROM ?_spawns s JOIN ?_zones z ON z.`id` = s.`areaId` WHERE s.`type` = ?d AND `typeId`IN (?a) GROUP BY `typeId`', Type::NPC, array_merge(array_column($this->dummyGOs, 1), array_filter(array_column($creatureLoot, 'entry'))));
$bosses = DB::Aowow()->selectCol('SELECT `id` AS ARRAY_KEY, IF(`cuFlags` & ?d, 1, IF(`typeFlags` & 0x4 AND `rank` > 0, 1, 0)) FROM ?_creature WHERE `id` IN (?a)', NPC_CU_INSTANCE_BOSS, array_filter(array_column($creatureLoot, 'entry')));
$linkedNpcs = DB::Aowow()->selectCol('SELECT l1.`objectId` AS ARRAY_KEY, IFNULL(l2.`npcId`, l1.`npcId`) FROM ?_loot_link l1 LEFT JOIN ?_loot_link l2 ON l1.`objectId` = l2.`objectId` AND l2.`priority` = 1 GROUP BY l1.`objectid`');
$npcSpawns = DB::Aowow()->select('SELECT `typeId` AS ARRAY_KEY, IF(COUNT(DISTINCT s.`areaId`) > 1, 0, s.`areaId`) AS "areaId", z.`type` FROM ?_spawns s JOIN ?_zones z ON z.`id` = s.`areaId` WHERE s.`type` = ?d AND `typeId` IN (?a) GROUP BY `typeId`', Type::NPC, array_merge($linkedNpcs, array_filter(array_column($creatureLoot, 'entry'))));
$bosses = DB::Aowow()->selectCol('SELECT `id` AS ARRAY_KEY, IF(`cuFlags` & ?d, 1, IF(`typeFlags` & 0x4 AND `rank` > 0, 1, 0)) FROM ?_creature WHERE `id` IN (?a)', NPC_CU_INSTANCE_BOSS, array_filter(array_column($creatureLoot, 'entry')));
foreach ($creatureLoot as $l)
{
$roi = $l['refOrItem'];
$entry = $l['entry'];
$mode = 1;
$zoneId = 0;
$zoneId = null;
$mMask = 0x0;
if (isset($this->dummyNPCs[$l['entry']]))
[$mode, $entry] = $this->dummyNPCs[$l['entry']];
if (isset($bosses[$entry]) && $bosses[$entry]) // can be empty...?
if (!empty($bosses[$entry]))
$mMask |= SRC_FLAG_BOSSDROP;
if (isset($npcSpawns[$entry]))
@ -355,10 +380,11 @@ CLISetup::registerSetup("sql", new class extends SetupScript
$this->pushBuffer(Type::ITEM, $roi, SRC_DROP, $mode, $l['qty'] > 1 ? 0 : Type::NPC, $entry, $zoneId, $mMask, $l['qty']);
}
CLI::write('[source] * #2 Drop [Object]', CLI::LOG_BLANK, true, true);
$objectLoot = DB::World()->select(
'SELECT IF(glt.`Reference` > 0, -glt.`Reference`, glt.`Item`) AS "refOrItem", gt.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(1) AS "qty"
'SELECT IF(glt.`Reference` > 0, -glt.`Reference`, glt.`Item`) AS "refOrItem", gt.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(DISTINCT glt.`Reference`) AS "qty"
FROM gameobject_loot_template glt
JOIN gameobject_template gt ON glt.`entry` = gt.`data1`
LEFT JOIN item_template it ON it.`entry` = glt.`Item` AND glt.`Reference` <= 0
@ -373,23 +399,25 @@ CLISetup::registerSetup("sql", new class extends SetupScript
foreach ($objectLoot as $l)
{
$roi = $l['refOrItem'];
$entry = $l['entry'];
$mode = 1 | ($this->dummyGOs[$entry][0] ?? 0);
$zoneId = 0;
$entry = self::FAKE_CHESTS[$l['entry']] ?? $l['entry'];
$mode = 1;
$zoneId = null;
$mMask = 0x0;
$spawn = [];
if (isset($this->dummyGOs[$entry])) // we know these are all boss drops
$mMask |= SRC_FLAG_BOSSDROP;
if (isset($goSpawns[$entry]))
$spawn = $goSpawns[$entry];
else if (isset($this->dummyGOs[$entry]) && isset($npcSpawns[$this->dummyGOs[$entry][1]]))
$spawn = $npcSpawns[$this->dummyGOs[$entry][1]];
if ($spawn)
if ([$modeBit, $baseEntry, $mapType] = ($this->dummyGOs[$entry] ?? null))
{
switch ($spawn['type'])
$mMask |= SRC_FLAG_BOSSDROP; // we know these are all boss drops
$mode = $modeBit;
$entry = $baseEntry ?: $entry;
if ($mapType == 1)
$mMask |= SRC_FLAG_DUNGEON_DROP;
if ($mapType == 2)
$mMask |= SRC_FLAG_RAID_DROP;
}
else if (isset($goSpawns[$entry]))
{
switch ($goSpawns[$entry]['type'])
{
case MAP_TYPE_DUNGEON_HC:
$mMask |= SRC_FLAG_DUNGEON_DROP; break;
@ -397,8 +425,16 @@ CLISetup::registerSetup("sql", new class extends SetupScript
case MAP_TYPE_MMODE_RAID_HC:
$mMask |= SRC_FLAG_RAID_DROP; break;
}
}
$zoneId = $spawn['areaId'];
if (isset($goSpawns[$entry]))
$zoneId = $goSpawns[$entry]['areaId'];
else if (isset($linkedNpcs[$entry]))
{
if (!empty($bosses[$linkedNpcs[$entry]]))
$mMask |= SRC_FLAG_BOSSDROP;
if (isset($npcSpawns[$linkedNpcs[$entry]]))
$zoneId = $npcSpawns[$linkedNpcs[$entry]]['areaId'];
}
if ($roi < 0 && !empty($this->refLoot[-$roi]))
@ -406,26 +442,27 @@ CLISetup::registerSetup("sql", new class extends SetupScript
foreach ($this->refLoot[-$roi] as $iId => $r)
{
if ($_ = $this->taughtSpell($r))
$this->pushBuffer(Type::SPELL, $_, SRC_DROP, $mode, $l['qty'] > 1 ? 0 : Type::OBJECT, $l['entry'], $zoneId, $mMask, $l['qty']);
$this->pushBuffer(Type::SPELL, $_, SRC_DROP, $mode, $l['qty'] > 1 ? 0 : Type::OBJECT, $entry, $zoneId, $mMask, $l['qty']);
$objectOT[] = $iId;
$this->pushBuffer(Type::ITEM, $iId, SRC_DROP, $mode, $l['qty'] > 1 ? 0 : Type::OBJECT, $l['entry'], $zoneId, $mMask, $l['qty']);
$this->pushBuffer(Type::ITEM, $iId, SRC_DROP, $mode, $l['qty'] > 1 ? 0 : Type::OBJECT, $entry, $zoneId, $mMask, $l['qty']);
}
continue;
}
if ($_ = $this->taughtSpell($l))
$this->pushBuffer(Type::SPELL, $_, SRC_DROP, $mode, $l['qty'] > 1 ? 0 : Type::OBJECT, $l['entry'], $zoneId, $mMask, $l['qty']);
$this->pushBuffer(Type::SPELL, $_, SRC_DROP, $mode, $l['qty'] > 1 ? 0 : Type::OBJECT, $entry, $zoneId, $mMask, $l['qty']);
$objectOT[] = $roi;
$this->pushBuffer(Type::ITEM, $roi, SRC_DROP, $mode, $l['qty'] > 1 ? 0 : Type::OBJECT, $l['entry'], $zoneId, $mMask, $l['qty']);
$this->pushBuffer(Type::ITEM, $roi, SRC_DROP, $mode, $l['qty'] > 1 ? 0 : Type::OBJECT, $entry, $zoneId, $mMask, $l['qty']);
}
CLI::write('[source] * #2 Drop [Item]', CLI::LOG_BLANK, true, true);
$itemLoot = DB::World()->select(
'SELECT IF(ilt.`Reference` > 0, -ilt.`Reference`, ilt.`Item`) AS ARRAY_KEY, itA.`entry`, itB.`class`, itB.`subclass`, itB.`spellid_1`, itB.`spelltrigger_1`, itB.`spellid_2`, itB.`spelltrigger_2`, COUNT(1) AS "qty"
'SELECT IF(ilt.`Reference` > 0, -ilt.`Reference`, ilt.`Item`) AS ARRAY_KEY, itA.`entry`, itB.`class`, itB.`subclass`, itB.`spellid_1`, itB.`spelltrigger_1`, itB.`spellid_2`, itB.`spelltrigger_2`, COUNT(DISTINCT ilt.`Reference`) AS "qty"
FROM item_loot_template ilt
JOIN item_template itA ON ilt.`entry` = itA.`entry`
LEFT JOIN item_template itB ON itB.`entry` = ilt.`Item` AND ilt.`Reference` <= 0
@ -441,24 +478,26 @@ CLISetup::registerSetup("sql", new class extends SetupScript
foreach ($this->refLoot[-$roi] as $iId => $r)
{
if ($_ = $this->taughtSpell($r))
$this->pushBuffer(Type::SPELL, $_, SRC_DROP, 1, $l['qty'] > 1 ? 0 : Type::ITEM, $l['entry'], 0, $l['qty']);
$this->pushBuffer(Type::SPELL, $_, SRC_DROP, 1, $l['qty'] > 1 ? 0 : Type::ITEM, $l['entry'], qty: $l['qty']);
$itemOT[] = $iId;
$this->pushBuffer(Type::ITEM, $iId, SRC_DROP, 1, $l['qty'] > 1 ? 0 : Type::ITEM, $l['entry'], 0, $l['qty']);
$this->pushBuffer(Type::ITEM, $iId, SRC_DROP, 1, $l['qty'] > 1 ? 0 : Type::ITEM, $l['entry'], qty: $l['qty']);
}
continue;
}
if ($_ = $this->taughtSpell($l))
$this->pushBuffer(Type::SPELL, $_, SRC_DROP, 1, $l['qty'] > 1 ? 0 : Type::ITEM, $l['entry'], 0, $l['qty']);
$this->pushBuffer(Type::SPELL, $_, SRC_DROP, 1, $l['qty'] > 1 ? 0 : Type::ITEM, $l['entry'], qty: $l['qty']);
$itemOT[] = $roi;
$this->pushBuffer(Type::ITEM, $roi, SRC_DROP, 1, $l['qty'] > 1 ? 0 : Type::ITEM, $l['entry'], 0, $l['qty']);
$this->pushBuffer(Type::ITEM, $roi, SRC_DROP, 1, $l['qty'] > 1 ? 0 : Type::ITEM, $l['entry'], qty: $l['qty']);
}
DB::Aowow()->query('UPDATE ?_items SET `cuFLags` = `cuFlags` | ?d WHERE `id` IN (?a)', ITEM_CU_OT_ITEMLOOT, $itemOT);
DB::Aowow()->query('UPDATE ?_items SET `cuFLags` = `cuFlags` | ?d WHERE `id` IN (?a)', ITEM_CU_OT_OBJECTLOOT, $objectOT);
if ($itemOT)
DB::Aowow()->query('UPDATE ?_items SET `cuFLags` = `cuFlags` | ?d WHERE `id` IN (?a)', ITEM_CU_OT_ITEMLOOT, $itemOT);
if ($objectOT)
DB::Aowow()->query('UPDATE ?_items SET `cuFLags` = `cuFlags` | ?d WHERE `id` IN (?a)', ITEM_CU_OT_OBJECTLOOT, $objectOT);
}
private function itemPvP() : void
@ -537,7 +576,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
}
$mailLoot = DB::World()->select(
'SELECT IF(mlt.`Reference` > 0, -mlt.`Reference`, mlt.`Item`) AS ARRAY_KEY, qt.`Id` AS "entry", it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(1) AS "qty", IF(COUNT(DISTINCT `QuestSortID`) > 1, 0, GREATEST(`QuestSortID`, 0)) AS "zone", BIT_OR(IF(qt.`AllowableRaces` & ?d AND NOT (qt.`AllowableRaces` & ?d), ?d, IF(qt.`AllowableRaces` & ?d AND NOT (qt.`AllowableRaces` & ?d), ?d, ?d))) AS "side"
'SELECT IF(mlt.`Reference` > 0, -mlt.`Reference`, mlt.`Item`) AS ARRAY_KEY, qt.`Id` AS "entry", it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(DISTINCT mlt.`Reference`) AS "qty", IF(COUNT(DISTINCT `QuestSortID`) > 1, 0, GREATEST(`QuestSortID`, 0)) AS "zone", BIT_OR(IF(qt.`AllowableRaces` & ?d AND NOT (qt.`AllowableRaces` & ?d), ?d, IF(qt.`AllowableRaces` & ?d AND NOT (qt.`AllowableRaces` & ?d), ?d, ?d))) AS "side"
FROM mail_loot_template mlt
JOIN quest_template_addon qta ON qta.`RewardMailTemplateId` = mlt.`entry`
JOIN quest_template qt ON qt.`ID` = qta.`ID`
@ -659,7 +698,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
CLI::write('[source] * #15 Disenchanted', CLI::LOG_BLANK, true, true);
$deLoot = DB::World()->select(
'SELECT IF(dlt.`Reference` > 0, -dlt.`Reference`, dlt.`Item`) AS "refOrItem", itA.`entry`, itB.`class`, itB.`subclass`, itB.`spellid_1`, itB.`spelltrigger_1`, itB.`spellid_2`, itB.`spelltrigger_2`, COUNT(1) AS "qty"
'SELECT IF(dlt.`Reference` > 0, -dlt.`Reference`, dlt.`Item`) AS "refOrItem", itA.`entry`, itB.`class`, itB.`subclass`, itB.`spellid_1`, itB.`spelltrigger_1`, itB.`spellid_2`, itB.`spelltrigger_2`, COUNT(DISTINCT dlt.`Reference`) AS "qty"
FROM disenchant_loot_template dlt
JOIN item_template itA ON dlt.`entry` = itA.`DisenchantId`
LEFT JOIN item_template itB ON itB.`entry` = dlt.`Item` AND dlt.`Reference` <= 0
@ -696,7 +735,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
CLI::write('[source] * #16 Fished', CLI::LOG_BLANK, true, true);
$fishLoot = DB::World()->select(
'SELECT src.`itemOrRef` AS "refOrItem", src.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(1) AS "qty", IF(COUNT(DISTINCT `zone`) > 2, 0, MAX(`zone`)) AS "zone"
'SELECT src.`itemOrRef` AS "refOrItem", src.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(DISTINCT src.`itemOrRef`) AS "qty", IF(COUNT(DISTINCT `zone`) > 2, 0, MAX(`zone`)) AS "zone"
FROM (SELECT 0 AS "entry", IF(flt.`Reference` > 0, -flt.`Reference`, flt.`Item`) AS "itemOrRef", `entry` AS "zone" FROM fishing_loot_template flt UNION
SELECT gt.`entry`, IF(glt.`Reference` > 0, -glt.`Reference`, glt.`Item`) AS "itemOrRef", 0 AS "zone" FROM gameobject_template gt JOIN gameobject_loot_template glt ON glt.`entry` = gt.`data1` WHERE `type` = ?d AND gt.`data1` > 0) src
LEFT JOIN item_template it ON src.`itemOrRef` > 0 AND src.`itemOrRef` = it.`entry`
@ -717,7 +756,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
{
$roi = $l['refOrItem'];
$l['zone'] = $areaParent[$l['zone']] ?? $l['zone'];
$zoneId = $goSpawns[$l['entry']] ?? 0;
$zoneId = $goSpawns[$l['entry']] ?? null;
if ($l['zone'] != $zoneId)
$zoneId = 0;
@ -746,7 +785,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
CLI::write('[source] * #17 Gathered', CLI::LOG_BLANK, true, true);
$herbLoot = DB::World()->select(
'SELECT src.`itemOrRef` AS "refOrItem", src.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(1) AS "qty", src.`srcType`
'SELECT src.`itemOrRef` AS "refOrItem", src.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(DISTINCT src.`itemOrRef`) AS "qty", src.`srcType`
FROM (SELECT ct.`entry`, IF(slt.`Reference` > 0, -slt.`Reference`, slt.`Item`) `itemOrRef`, ?d AS "srcType" FROM creature_template ct JOIN skinning_loot_template slt ON slt.`entry` = ct.`skinloot` WHERE (`type_flags` & ?d) AND ct.`skinloot` > 0 UNION
SELECT gt.`entry`, IF(glt.`Reference` > 0, -glt.`Reference`, glt.`Item`) `itemOrRef`, ?d AS "srcType" FROM gameobject_template gt JOIN gameobject_loot_template glt ON glt.`entry` = gt.`data1` WHERE gt.`type` = ?d AND gt.`data1` > 0 AND gt.`data0` IN (?a)) src
LEFT JOIN item_template it ON src.itemOrRef > 0 AND src.`itemOrRef` = it.`entry`
@ -761,8 +800,8 @@ CLISetup::registerSetup("sql", new class extends SetupScript
return;
}
$spawns[Type::OBJECT] = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, IF(COUNT(DISTINCT `areaId`) > 1, 0, `areaId`) FROM ?_spawns WHERE `type` = ?d AND `typeId` IN (?a) GROUP BY `typeId`', Type::OBJECT, array_column(array_filter($herbLoot, function($x) { return $x['srcType'] == Type::OBJECT; }), 'entry'));
$spawns[Type::NPC] = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, IF(COUNT(DISTINCT `areaId`) > 1, 0, `areaId`) FROM ?_spawns WHERE `type` = ?d AND `typeId` IN (?a) GROUP BY `typeId`', Type::NPC, array_column(array_filter($herbLoot, function($x) { return $x['srcType'] == Type::NPC; }), 'entry'));
$spawns[Type::OBJECT] = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, IF(COUNT(DISTINCT `areaId`) > 1, 0, `areaId`) FROM ?_spawns WHERE `type` = ?d AND `typeId` IN (?a) GROUP BY `typeId`', Type::OBJECT, array_column(array_filter($herbLoot, fn($x) => $x['srcType'] == Type::OBJECT), 'entry'));
$spawns[Type::NPC] = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, IF(COUNT(DISTINCT `areaId`) > 1, 0, `areaId`) FROM ?_spawns WHERE `type` = ?d AND `typeId` IN (?a) GROUP BY `typeId`', Type::NPC, array_column(array_filter($herbLoot, fn($x) => $x['srcType'] == Type::NPC), 'entry'));
foreach ($herbLoot as $l)
{
@ -772,7 +811,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
if (isset($this->dummyNPCs[$l['entry']]) && $l['srcType'] == Type::NPC)
[$mode, $entry] = $this->dummyNPCs[$l['entry']];
$zoneId = $spawns[$l['srcType']][$l['entry']] ?? 0;
$zoneId = $spawns[$l['srcType']][$l['entry']] ?? null;
if ($roi < 0 && !empty($this->refLoot[-$roi]))
{
@ -799,7 +838,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
CLI::write('[source] * #18 Milled', CLI::LOG_BLANK, true, true);
$millLoot = DB::World()->select(
'SELECT IF(mlt.`Reference` > 0, -mlt.`Reference`, mlt.`Item`) AS "refOrItem", itA.`entry`, itB.`class`, itB.`subclass`, itB.`spellid_1`, itB.`spelltrigger_1`, itB.`spellid_2`, itB.`spelltrigger_2`, COUNT(1) AS "qty"
'SELECT IF(mlt.`Reference` > 0, -mlt.`Reference`, mlt.`Item`) AS "refOrItem", itA.`entry`, itB.`class`, itB.`subclass`, itB.`spellid_1`, itB.`spelltrigger_1`, itB.`spellid_2`, itB.`spelltrigger_2`, COUNT(DISTINCT mlt.`Reference`) AS "qty"
FROM milling_loot_template mlt
JOIN item_template itA ON mlt.`entry` = itA.`entry`
LEFT JOIN item_template itB ON itB.`entry` = mlt.`Item` AND mlt.`Reference` <= 0
@ -835,7 +874,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
CLI::write('[source] * #19 Mined', CLI::LOG_BLANK, true, true);
$mineLoot = DB::World()->select(
'SELECT src.`itemOrRef` AS "refOrItem", src.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(1) AS "qty", src.`srcType`
'SELECT src.`itemOrRef` AS "refOrItem", src.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(DISTINCT src.`itemOrRef`) AS "qty", src.`srcType`
FROM (SELECT ct.`entry`, IF(slt.`Reference` > 0, -slt.`Reference`, slt.`Item`) `itemOrRef`, ?d AS "srcType" FROM creature_template ct JOIN skinning_loot_template slt ON slt.`entry` = ct.`skinloot` WHERE (`type_flags` & ?d) AND ct.`skinloot` > 0 UNION
SELECT gt.`entry`, IF(glt.`Reference` > 0, -glt.`Reference`, glt.`Item`) `itemOrRef`, ?d AS "srcType" FROM gameobject_template gt JOIN gameobject_loot_template glt ON glt.`entry` = gt.`data1` WHERE gt.`type` = ?d AND gt.`data1` > 0 AND gt.`data0` IN (?a)) src
LEFT JOIN item_template it ON src.itemOrRef > 0 AND src.`itemOrRef` = it.`entry`
@ -850,8 +889,8 @@ CLISetup::registerSetup("sql", new class extends SetupScript
return;
}
$spawns[Type::OBJECT] = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, IF(COUNT(DISTINCT `areaId`) > 1, 0, `areaId`) FROM ?_spawns WHERE `type` = ?d AND `typeId`IN (?a) GROUP BY `typeId`', Type::OBJECT, array_column(array_filter($mineLoot, function($x) { return $x['srcType'] == Type::OBJECT; }), 'entry'));
$spawns[Type::NPC] = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, IF(COUNT(DISTINCT `areaId`) > 1, 0, `areaId`) FROM ?_spawns WHERE `type` = ?d AND `typeId`IN (?a) GROUP BY `typeId`', Type::NPC, array_column(array_filter($mineLoot, function($x) { return $x['srcType'] == Type::NPC; }), 'entry'));
$spawns[Type::OBJECT] = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, IF(COUNT(DISTINCT `areaId`) > 1, 0, `areaId`) FROM ?_spawns WHERE `type` = ?d AND `typeId`IN (?a) GROUP BY `typeId`', Type::OBJECT, array_column(array_filter($mineLoot, fn($x) => $x['srcType'] == Type::OBJECT), 'entry'));
$spawns[Type::NPC] = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, IF(COUNT(DISTINCT `areaId`) > 1, 0, `areaId`) FROM ?_spawns WHERE `type` = ?d AND `typeId`IN (?a) GROUP BY `typeId`', Type::NPC, array_column(array_filter($mineLoot, fn($x) => $x['srcType'] == Type::NPC), 'entry'));
foreach ($mineLoot as $l)
{
@ -861,7 +900,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
if (isset($this->dummyNPCs[$l['entry']]) && $l['srcType'] == Type::NPC)
[$mode, $entry] = $this->dummyNPCs[$l['entry']];
$zoneId = $spawns[$l['srcType']][$l['entry']] ?? 0;
$zoneId = $spawns[$l['srcType']][$l['entry']] ?? null;
if ($roi < 0 && !empty($this->refLoot[-$roi]))
{
@ -888,7 +927,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
CLI::write('[source] * #20 Prospected', CLI::LOG_BLANK, true, true);
$prospectLoot = DB::World()->select(
'SELECT IF(plt.`Reference` > 0, -plt.`Reference`, plt.`Item`) AS "refOrItem", itA.`entry`, itB.`class`, itB.`subclass`, itB.`spellid_1`, itB.`spelltrigger_1`, itB.`spellid_2`, itB.`spelltrigger_2`, COUNT(1) AS "qty"
'SELECT IF(plt.`Reference` > 0, -plt.`Reference`, plt.`Item`) AS "refOrItem", itA.`entry`, itB.`class`, itB.`subclass`, itB.`spellid_1`, itB.`spelltrigger_1`, itB.`spellid_2`, itB.`spelltrigger_2`, COUNT(DISTINCT plt.`Reference`) AS "qty"
FROM prospecting_loot_template plt
JOIN item_template itA ON plt.`entry` = itA.`entry`
LEFT JOIN item_template itB ON itB.`entry` = plt.`Item` AND plt.`Reference` <= 0
@ -924,7 +963,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
CLI::write('[source] * #21 Pickpocket', CLI::LOG_BLANK, true, true);
$theftLoot = DB::World()->select(
'SELECT src.`itemOrRef` AS "refOrItem", src.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(1) AS "qty"
'SELECT src.`itemOrRef` AS "refOrItem", src.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(DISTINCT src.`itemOrRef`) AS "qty"
FROM (SELECT ct.`entry`, IF(plt.`Reference` > 0, -plt.`Reference`, plt.`Item`) `itemOrRef` FROM creature_template ct JOIN pickpocketing_loot_template plt ON plt.`entry` = ct.`pickpocketloot` WHERE ct.`pickpocketloot` > 0) src
LEFT JOIN item_template it ON src.`itemOrRef` > 0 AND src.`itemOrRef` = it.`entry`
GROUP BY `refOrItem`, src.`entry`'
@ -946,7 +985,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
if (isset($this->dummyNPCs[$l['entry']]))
[$mode, $entry] = $this->dummyNPCs[$l['entry']];
$zoneId = $spawns[$l['entry']] ?? 0;
$zoneId = $spawns[$l['entry']] ?? null;
if ($roi < 0 && !empty($this->refLoot[-$roi]))
{
@ -973,7 +1012,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
CLI::write('[source] * #22 Salvaged', CLI::LOG_BLANK, true, true);
$salvageLoot = DB::World()->select(
'SELECT src.`itemOrRef` AS "refOrItem", src.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(1) AS "qty"
'SELECT src.`itemOrRef` AS "refOrItem", src.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(DISTINCT src.`itemOrRef`) AS "qty"
FROM (SELECT ct.`entry`, IF(slt.`Reference` > 0, -slt.`Reference`, slt.`Item`) `itemOrRef` FROM creature_template ct JOIN skinning_loot_template slt ON slt.`entry` = ct.`skinloot` WHERE (`type_flags` & ?d) AND ct.`skinloot` > 0) src
LEFT JOIN item_template it ON src.`itemOrRef` > 0 AND src.`itemOrRef` = it.`entry`
GROUP BY `refOrItem`, src.`entry`',
@ -996,7 +1035,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
if (isset($this->dummyNPCs[$l['entry']]))
[$mode, $entry] = $this->dummyNPCs[$l['entry']];
$zoneId = $spawns[$l['entry']] ?? 0;
$zoneId = $spawns[$l['entry']] ?? null;
if ($roi < 0 && !empty($this->refLoot[-$roi]))
{
@ -1023,7 +1062,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
CLI::write('[source] * #23 Skinned', CLI::LOG_BLANK, true, true);
$skinLoot = DB::World()->select(
'SELECT src.`itemOrRef` AS "refOrItem", src.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(1) AS "qty"
'SELECT src.`itemOrRef` AS "refOrItem", src.`entry`, it.`class`, it.`subclass`, it.`spellid_1`, it.`spelltrigger_1`, it.`spellid_2`, it.`spelltrigger_2`, COUNT(DISTINCT src.`itemOrRef`) AS "qty"
FROM (SELECT ct.`entry`, IF(slt.`Reference` > 0, -slt.`Reference`, slt.`Item`) `itemOrRef` FROM creature_template ct JOIN skinning_loot_template slt ON slt.`entry` = ct.`skinloot` WHERE (`type_flags` & ?d) = 0 AND ct.`skinloot` > 0 AND ct.`type` <> 13) src
LEFT JOIN item_template it ON src.`itemOrRef` > 0 AND src.`itemOrRef` = it.`entry`
GROUP BY `refOrItem`, src.`entry`',
@ -1046,7 +1085,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
if (isset($this->dummyNPCs[$l['entry']]))
[$mode, $entry] = $this->dummyNPCs[$l['entry']];
$zoneId = $spawns[$l['entry']] ?? 0;
$zoneId = $spawns[$l['entry']] ?? null;
if ($roi < 0 && !empty($this->refLoot[-$roi]))
{

View file

@ -17,17 +17,64 @@ CLISetup::registerSetup("sql", new class extends SetupScript
protected $dbcSourceFiles = ['spelldifficulty'];
protected $worldDependency = ['spelldifficulty_dbc'];
protected $setupAfter = [['creature', 'spawns'], []];
public function generate(array $ids = []) : bool
{
DB::Aowow()->query('TRUNCATE TABLE ?_spelldifficulty');
DB::Aowow()->query('INSERT INTO ?_spelldifficulty SELECT GREATEST(`normal10`, 0), GREATEST(`normal25`, 0), GREATEST(`heroic10`, 0), GREATEST(`heroic25`, 0) FROM dbc_spelldifficulty');
DB::Aowow()->query('INSERT INTO ?_spelldifficulty SELECT GREATEST(`normal10`, 0), GREATEST(`normal25`, 0), GREATEST(`heroic10`, 0), GREATEST(`heroic25`, 0), IF(`heroic10` > 0, 2, 0) FROM dbc_spelldifficulty');
$rows = DB::World()->select('SELECT `spellid0`, `spellid1`, `spellid2`, `spellid3` FROM spelldifficulty_dbc');
$rows = DB::World()->select('SELECT `spellid0`, `spellid1`, `spellid2`, `spellid3`, IF(`spellid2` > 0, 2, 0) FROM spelldifficulty_dbc');
foreach ($rows as $r)
DB::Aowow()->query('INSERT INTO ?_spelldifficulty VALUES (?a)', array_values($r));
CLI::write('[spelldifficulty] - trying to assign map type by traversing creature spells > spawns');
// try to update mode of ambiguous entries
$baseSpells = DB::Aowow()->selectCol('SELECT `normal10` FROM ?_spelldifficulty WHERE `heroic10` = 0 AND `heroic25` = 0');
for ($i = 1; $i < 9; $i++)
DB::Aowow()->query(
'UPDATE ?_spelldifficulty sd,
(SELECT c.?# AS "spell", BIT_OR(CASE WHEN z.`type` = ?d THEN 1 WHEN z.`type` = ?d THEN 2 WHEN z.`type` = ?d THEN 2 ELSE 0 END) AS "mapType"
FROM ?_creature c
JOIN ?_spawns s ON c.id = s.typeId AND s.type = ?d
JOIN ?_zones z ON z.id = s.areaId
WHERE c.?# IN (?a)
GROUP BY c.?#
HAVING c.?# <> 0) x
SET sd.`mapType` = x.`mapType`
WHERE sd.`normal10` = x.`spell`',
'spell'.$i, MAP_TYPE_DUNGEON_HC, MAP_TYPE_MMODE_RAID, MAP_TYPE_MMODE_RAID_HC,
Type::NPC, 'spell'.$i, $baseSpells, 'spell'.$i, 'spell'.$i
);
CLI::write('[spelldifficulty] - trying to assign map type by traversing smart_scripts > spawns');
$smartCaster = [];
foreach ($baseSpells as $bs)
if ($owner = SmartAI::getOwnerOfSpellCast($bs))
foreach ($owner as $type => $caster)
$smartCaster[$type][$bs] = $caster;
foreach ($smartCaster as $type => $spells)
foreach ($spells as $spellId => $casterEntries)
DB::Aowow()->query(
'UPDATE ?_spelldifficulty sd,
(SELECT BIT_OR(CASE WHEN z.`type` = ?d THEN 1 WHEN z.`type` = ?d THEN 2 WHEN z.`type` = ?d THEN 2 ELSE 0 END) AS "mapType"
FROM ?_spawns s
JOIN ?_zones z ON z.id = s.areaId
WHERE s.type = ?d AND s.typeId IN (?a) ) sp
SET sd.`mapType` = IF(sp.`mapType` > 2, 0, sp.`mapType`)
WHERE sd.`normal10` = ?d',
MAP_TYPE_DUNGEON_HC, MAP_TYPE_MMODE_RAID, MAP_TYPE_MMODE_RAID_HC,
$type, $casterEntries,
$spellId
);
return true;
}
});