public static function init($firstrun = false) { self::$defaultExecTime = ini_get('max_execution_time'); $doScripts = []; if (getopt(self::$shortOpts, self::$longOpts) || $firstrun) { self::handleCLIOpts($doScripts); } else { self::printCLIHelp(); exit; } // check passed subscript names; limit to real scriptNames self::$subScripts = array_merge(array_keys(self::$tplFiles), array_keys(self::$datasets)); if ($doScripts) { self::$subScripts = array_intersect($doScripts, self::$subScripts); } if (!CLISetup::$localeIds) { CLISetup::log('No valid locale specified. Check your config or --locales parameter, if used', CLISetup::LOG_ERROR); exit; } // create directory structure CLISetup::log('FileGen::init() - creating required directories'); $pathOk = 0; foreach (self::$reqDirs as $rd) { if (CLISetup::writeDir($rd)) { $pathOk++; } } CLISetup::log('created ' . $pathOk . ' extra paths' . ($pathOk == count(self::$reqDirs) ? '' : ' with errors')); CLISetup::log(); }
function build() { require_once 'setup/tools/fileGen.class.php'; FileGen::init(); if (FileGen::$subScripts) { $allOk = true; // start file generation CLISetup::log('begin generation of ' . implode(', ', FileGen::$subScripts)); CLISetup::log(); // files with template foreach (FileGen::$tplFiles as $name => list($file, $destPath, $deps)) { $reqDBC = []; if (!in_array($name, FileGen::$subScripts)) { continue; } if (!file_exists(FileGen::$tplPath . $file . '.in')) { CLISetup::log(sprintf(ERR_MISSING_FILE, FileGen::$tplPath . $file . '.in'), CLISetup::LOG_ERROR); $allOk = false; continue; } if (!CLISetup::writeDir($destPath)) { continue; } $syncIds = []; // todo: fetch what exactly must be regenerated $ok = FileGen::generate($name, $syncIds); if (!$ok) { $allOk = false; } CLISetup::log(' - subscript \'' . $file . '\' returned ' . ($ok ? 'sucessfully' : 'with errors'), $ok ? CLISetup::LOG_OK : CLISetup::LOG_ERROR); set_time_limit(FileGen::$defaultExecTime); // reset to default for the next script } // files without template foreach (FileGen::$datasets as $file => $deps) { if (!in_array($file, FileGen::$subScripts)) { continue; } $syncIds = []; // todo: fetch what exactly must be regenerated $ok = FileGen::generate($file, $syncIds); if (!$ok) { $allOk = false; } CLISetup::log(' - subscript \'' . $file . '\' returned ' . ($ok ? 'sucessfully' : 'with errors'), $ok ? CLISetup::LOG_OK : CLISetup::LOG_ERROR); set_time_limit(FileGen::$defaultExecTime); // reset to default for the next script } // end CLISetup::log(); if ($allOk) { CLISetup::log('successfully finished file generation', CLISetup::LOG_OK); } else { CLISetup::log('finished file generation with errors', CLISetup::LOG_ERROR); } } else { CLISetup::log('no valid script names supplied', CLISetup::LOG_ERROR); } }
function gems() { // sketchy, but should work // Id < 36'000 || ilevel < 70 ? BC : WOTLK $gems = DB::Aowow()->Select('SELECT i.id AS itemId, i.name_loc0, i.name_loc2, i.name_loc3, i.name_loc4, i.name_loc6, i.name_loc8, IF (i.id < 36000 OR i.itemLevel < 70, 1 , 2) AS expansion, i.quality, ic.iconString AS icon, i.gemEnchantmentId AS enchId, i.gemColorMask AS colors FROM ?_items i JOIN ?_icons ic ON ic.id = -i.displayId WHERE i.gemEnchantmentId <> 0 ORDER BY i.id DESC'); $success = true; // check directory-structure foreach (Util::$localeStrings as $dir) { if (!CLISetup::writeDir('datasets/' . $dir)) { $success = false; } } $enchIds = []; foreach ($gems as $pop) { $enchIds[] = $pop['enchId']; } $enchantments = new EnchantmentList(array(['id', $enchIds], CFG_SQL_LIMIT_NONE)); if ($enchantments->error) { CLISetup::log('Required table ?_itemenchantment seems to be empty! Leaving gems()...', CLISetup::LOG_ERROR); CLISetup::log(); return false; } foreach (CLISetup::$localeIds as $lId) { set_time_limit(5); User::useLocale($lId); Lang::load(Util::$localeStrings[$lId]); $gemsOut = []; foreach ($gems as $pop) { if (!$enchantments->getEntry($pop['enchId'])) { CLISetup::log(' * could not find enchantment #' . $pop['enchId'] . ' referenced by item #' . $gem['itemId'], CLISetup::LOG_WARN); continue; } $gemsOut[$pop['itemId']] = array('name' => Util::localizedString($pop, 'name'), 'quality' => $pop['quality'], 'icon' => strToLower($pop['icon']), 'enchantment' => $enchantments->getField('name', true), 'jsonequip' => $enchantments->getStatGain(), 'colors' => $pop['colors'], 'expansion' => $pop['expansion']); } $toFile = "var g_gems = " . Util::toJSON($gemsOut) . ";"; $file = 'datasets/' . User::$localeString . '/gems'; if (!CLISetup::writeFile($file, $toFile)) { $success = false; } } return $success; }
function glyphs() { $success = true; $glyphList = DB::Aowow()->Select('SELECT i.id AS itemId, i.*, IF (g.typeFlags & 0x1, 2, 1) AS type, i.subclass AS classs, i.requiredLevel AS level, s1.Id AS glyphSpell, ic.iconString AS icon, s1.skillLine1 AS skillId, s2.Id AS glyphEffect, s2.Id AS ARRAY_KEY FROM ?_items i JOIN ?_spell s1 ON s1.Id = i.spellid1 JOIN ?_glyphproperties g ON g.Id = s1.effect1MiscValue JOIN ?_spell s2 ON s2.Id = g.spellId JOIN ?_icons ic ON ic.Id = s1.iconIdAlt WHERE i.classBak = 16'); // check directory-structure foreach (Util::$localeStrings as $dir) { if (!CLISetup::writeDir('datasets/' . $dir)) { $success = false; } } $glyphSpells = new SpellList(array(['s.id', array_keys($glyphList)], CFG_SQL_LIMIT_NONE)); foreach (CLISetup::$localeIds as $lId) { set_time_limit(30); User::useLocale($lId); Lang::load(Util::$localeStrings[$lId]); $glyphsOut = []; foreach ($glyphSpells->iterate() as $__) { $pop = $glyphList[$glyphSpells->id]; if (!$pop['glyphEffect']) { continue; } if ($glyphSpells->getField('effect1Id') != 6 && $glyphSpells->getField('effect2Id') != 6 && $glyphSpells->getField('effect3Id') != 6) { continue; } $glyphsOut[$pop['itemId']] = array('name' => Util::localizedString($pop, 'name'), 'description' => $glyphSpells->parseText()[0], 'icon' => $pop['icon'], 'type' => $pop['type'], 'classs' => $pop['classs'], 'skill' => $pop['skillId'], 'level' => $pop['level']); } $toFile = "var g_glyphs = " . Util::toJSON($glyphsOut) . ";"; $file = 'datasets/' . User::$localeString . '/glyphs'; if (!CLISetup::writeFile($file, $toFile)) { $success = false; } } return $success; }
function pets() { $success = true; $locations = []; $petList = DB::Aowow()->Select('SELECT cr. id, cr.name_loc0, cr.name_loc2, cr.name_loc3, cr.name_loc6, cr.name_loc8, cr.minLevel, cr.maxLevel, ft.A, ft.H, cr.rank AS classification, cr.family, cr.displayId1 AS displayId, cr.textureString AS skin, LOWER(SUBSTRING_INDEX(cf.iconString, "\\\\", -1)) AS icon, cf.petTalentType AS type FROM ?_creature cr JOIN ?_factiontemplate ft ON ft.Id = cr.faction JOIN dbc_creaturefamily cf ON cf.id = cr.family WHERE cr.typeFlags & 0x1 AND (cr.cuFlags & 0x2) = 0 ORDER BY cr.id ASC'); // check directory-structure foreach (Util::$localeStrings as $dir) { if (!CLISetup::writeDir('datasets/' . $dir)) { $success = false; } } foreach (CLISetup::$localeIds as $lId) { User::useLocale($lId); Lang::load(Util::$localeStrings[$lId]); $petsOut = []; foreach ($petList as $pet) { // get locations // again: caching will save you time and nerves if (!isset($locations[$pet['id']])) { $locations[$pet['id']] = DB::Aowow()->SelectCol('SELECT DISTINCT areaId FROM ?_spawns WHERE type = ?d AND typeId = ?d', TYPE_NPC, $pet['id']); } $petsOut[$pet['id']] = array('id' => $pet['id'], 'name' => Util::localizedString($pet, 'name'), 'minlevel' => $pet['minLevel'], 'maxlevel' => $pet['maxLevel'], 'location' => $locations[$pet['id']], 'react' => [$pet['A'], $pet['H']], 'classification' => $pet['classification'], 'family' => $pet['family'], 'displayId' => $pet['displayId'], 'skin' => $pet['skin'], 'icon' => $pet['icon'], 'type' => $pet['type']); } $toFile = "var g_pets = " . Util::toJSON($petsOut) . ";"; $file = 'datasets/' . User::$localeString . '/pets'; if (!CLISetup::writeFile($file, $toFile)) { $success = false; } } return $success; }
function gems() { // sketchy, but should work // Id < 36'000 || ilevel < 70 ? BC : WOTLK $gems = DB::Aowow()->Select('SELECT i.id AS itemId, i.name_loc0, i.name_loc2, i.name_loc3, i.name_loc6, i.name_loc8, IF (i.id < 36000 OR i.itemLevel < 70, 1 , 2) AS expansion, i.quality, ic.iconString AS icon, i.gemEnchantmentId AS enchId, i.gemColorMask AS colors FROM ?_items i JOIN ?_icons ic ON ic.id = -i.displayId WHERE i.gemEnchantmentId <> 0 ORDER BY i.id DESC'); $success = true; // check directory-structure foreach (Util::$localeStrings as $dir) { if (!CLISetup::writeDir('datasets/' . $dir)) { $success = false; } } $enchIds = []; foreach ($gems as $pop) { $enchIds[] = $pop['enchId']; } $enchMisc = []; $enchJSON = Util::parseItemEnchantment($enchIds, false, $enchMisc); foreach (CLISetup::$localeIds as $lId) { set_time_limit(5); User::useLocale($lId); Lang::load(Util::$localeStrings[$lId]); $gemsOut = []; foreach ($gems as $pop) { $gemsOut[$pop['itemId']] = array('name' => Util::localizedString($pop, 'name'), 'quality' => $pop['quality'], 'icon' => strToLower($pop['icon']), 'enchantment' => Util::localizedString(@$enchMisc[$pop['enchId']]['text'] ?: [], 'text'), 'jsonequip' => @$enchJSON[$pop['enchId']] ?: [], 'colors' => $pop['colors'], 'expansion' => $pop['expansion']); } $toFile = "var g_gems = " . Util::toJSON($gemsOut) . ";"; $file = 'datasets/' . User::$localeString . '/gems'; if (!CLISetup::writeFile($file, $toFile)) { $success = false; } } return $success; }
function weightPresets() { // check directory-structure if (!CLISetup::writeDir('datasets/')) { return false; } $wtPresets = []; $scales = DB::Aowow()->select('SELECT id, name, icon, class FROM ?_account_weightscales WHERE userId = 0 ORDER BY class, id ASC'); foreach ($scales as $s) { $weights = DB::Aowow()->selectCol('SELECT field AS ARRAY_KEY, val FROM ?_account_weightscale_data WHERE id = ?d', $s['id']); if (!$weights) { CLISetup::log('WeightScale \'' . CLISetup::bold($s['name']) . '\' has no data set. Skipping...', CLISetup::LOG_WARN); continue; } $wtPresets[$s['class']]['pve'][$s['name']] = array_merge(['__icon' => $s['icon']], $weights); } $toFile = "var wt_presets = " . Util::toJSON($wtPresets) . ";"; $file = 'datasets/weight-presets'; if (!CLISetup::writeFile($file, $toFile)) { return false; } return true; }
function simpleImg() { // prefer manually converted PNG files (as the imagecreatefromblp-script has issues with some formats) // see: https://github.com/Kanma/BLPConverter $loadImageFile = function ($path) { $result = null; if (in_array(mb_substr($path, -4, 4), ['.png', '.blp', '.BLP', '.PNG'])) { $path = mb_substr($path, 0, mb_strlen($path) - 4); } $file = $path . '.png'; if (CLISetup::fileExists($file)) { CLISetup::log('manually converted png file present for ' . $path . '.', CLISetup::LOG_INFO); $result = imagecreatefrompng($file); } if (!$result) { $file = $path . '.blp'; if (CLISetup::fileExists($file)) { $result = imagecreatefromblp($file); } } return $result; }; if (isset(FileGen::$cliOpts['help'])) { echo "\n"; echo "available options for subScript 'simpleImg':\n"; echo " --icons (generates square icons that are used for basicly everything)\n"; echo " --glyphs (decorative tidbit displayed on Infobox for Glyph Spells)\n"; echo " --pagetexts (imagery contained in PageTexts on readable GameObjects or Items)\n"; echo " --loadingscreens (loading screens (not used, skipped by default))\n"; return true; } $locStr = null; $groups = []; $dbcPath = CLISetup::$srcDir . '%sDBFilesClient/'; $imgPath = CLISetup::$srcDir . '%sInterface/'; $destDir = 'static/images/wow/'; $success = true; $iconDirs = array(['icons/large/', 'jpg', 0, 56, 4], ['icons/medium/', 'jpg', 0, 36, 4], ['icons/small/', 'jpg', 0, 18, 4], ['icons/tiny/', 'gif', 0, 15, 4]); $calendarDirs = array(['icons/large/', 'jpg', 90, 56, 4], ['icons/medium/', 'jpg', 90, 36, 4], ['icons/small/', 'jpg', 90, 18, 4], ['icons/tiny/', 'gif', 90, 15, 4]); $loadScreenDirs = array(['loadingscreens/large/', 'jpg', 0, 1024, 0], ['loadingscreens/medium/', 'jpg', 0, 488, 0], ['loadingscreens/original/', 'png', 0, 0, 0], ['loadingscreens/small/', 'jpg', 0, 244, 0]); $paths = array(0 => ['Icons/', $iconDirs, '/*.[bB][lL][pP]', true, 0], 1 => ['Spellbook/', [['Interface/Spellbook/', 'png', 0, 0, 0]], '/UI-Glyph-Rune*.blp', true, 0], 2 => ['PaperDoll/', array_slice($iconDirs, 0, 3), '/UI-{Backpack,PaperDoll}-*.blp', true, 0], 3 => ['GLUES/CHARACTERCREATE/UI-CharacterCreate-Races.blp', $iconDirs, '', true, 64], 4 => ['GLUES/CHARACTERCREATE/UI-CharacterCreate-CLASSES.blp', $iconDirs, '', true, 64], 5 => ['GLUES/CHARACTERCREATE/UI-CharacterCreate-Factions.blp', $iconDirs, '', true, 64], 7 => ['FlavorImages/', [['Interface/FlavorImages/', 'png', 0, 0, 0]], '/*.[bB][lL][pP]', false, 0], 8 => ['Pictures/', [['Interface/Pictures/', 'png', 0, 0, 0]], '/*.[bB][lL][pP]', false, 0], 9 => ['PvPRankBadges/', [['Interface/PvPRankBadges/', 'png', 0, 0, 0]], '/*.[bB][lL][pP]', false, 0], 10 => ['Calendar/Holidays/', $calendarDirs, '/*{rt,a,y,h,s}.[bB][lL][pP]', true, 0], 11 => ['GLUES/LOADINGSCREENS/', $loadScreenDirs, '/[lL][oO]*.[bB][lL][pP]', false, 0]); // textures are composed of 64x64 icons // numeric indexed arrays mimick the position on the texture $cuNames = array(2 => array('ui-paperdoll-slot-chest' => 'inventoryslot_chest', 'ui-backpack-emptyslot' => 'inventoryslot_empty', 'ui-paperdoll-slot-feet' => 'inventoryslot_feet', 'ui-paperdoll-slot-finger' => 'inventoryslot_finger', 'ui-paperdoll-slot-hands' => 'inventoryslot_hands', 'ui-paperdoll-slot-head' => 'inventoryslot_head', 'ui-paperdoll-slot-legs' => 'inventoryslot_legs', 'ui-paperdoll-slot-mainhand' => 'inventoryslot_mainhand', 'ui-paperdoll-slot-neck' => 'inventoryslot_neck', 'ui-paperdoll-slot-secondaryhand' => 'inventoryslot_offhand', 'ui-paperdoll-slot-ranged' => 'inventoryslot_ranged', 'ui-paperdoll-slot-relic' => 'inventoryslot_relic', 'ui-paperdoll-slot-shirt' => 'inventoryslot_shirt', 'ui-paperdoll-slot-shoulder' => 'inventoryslot_shoulder', 'ui-paperdoll-slot-tabard' => 'inventoryslot_tabard', 'ui-paperdoll-slot-trinket' => 'inventoryslot_trinket', 'ui-paperdoll-slot-waist' => 'inventoryslot_waist', 'ui-paperdoll-slot-wrists' => 'inventoryslot_wrists'), 3 => array(['race_human_male', 'race_dwarf_male', 'race_gnome_male', 'race_nightelf_male', 'race_draenei_male'], ['race_tauren_male', 'race_scourge_male', 'race_troll_male', 'race_orc_male', 'race_bloodelf_male'], ['race_human_female', 'race_dwarf_female', 'race_gnome_female', 'race_nightelf_female', 'race_draenei_female'], ['race_tauren_female', 'race_scourge_female', 'race_troll_female', 'race_orc_female', 'race_bloodelf_female']), 4 => array(['class_warrior', 'class_mage', 'class_rogue', 'class_druid'], ['class_hunter', 'class_shaman', 'class_priest', 'class_warlock'], ['class_paladin', 'class_deathknight']), 5 => array(['faction_alliance', 'faction_horde']), 6 => array([], [null, 'quest_start', 'quest_end', 'quest_start_daily', 'quest_end_daily']), 10 => array('calendar_winterveilstart' => 'calendar_winterveilstart', 'calendar_noblegardenstart' => 'calendar_noblegardenstart', 'calendar_childrensweekstart' => 'calendar_childrensweekstart', 'calendar_fishingextravaganza' => 'calendar_fishingextravaganzastart', 'calendar_harvestfestivalstart' => 'calendar_harvestfestivalstart', 'calendar_hallowsendstart' => 'calendar_hallowsendstart', 'calendar_lunarfestivalstart' => 'calendar_lunarfestivalstart', 'calendar_loveintheairstart' => 'calendar_loveintheairstart', 'calendar_midsummerstart' => 'calendar_midsummerstart', 'calendar_brewfeststart' => 'calendar_brewfeststart', 'calendar_darkmoonfaireelwynnstart' => 'calendar_darkmoonfaireelwynnstart', 'calendar_darkmoonfairemulgorestart' => 'calendar_darkmoonfairemulgorestart', 'calendar_darkmoonfaireterokkarstart' => 'calendar_darkmoonfaireterokkarstart', 'calendar_piratesday' => 'calendar_piratesdaystart', 'calendar_wotlklaunch' => 'calendar_wotlklaunchstart', 'calendar_dayofthedeadstart' => 'calendar_dayofthedeadstart', 'calendar_fireworks' => 'calendar_fireworksstart')); $writeImage = function ($name, $ext, $src, $srcDims, $destDims, $done) { $ok = false; $dest = imagecreatetruecolor($destDims['w'], $destDims['h']); imagesavealpha($dest, true); if ($ext == 'png') { imagealphablending($dest, false); } imagecopyresampled($dest, $src, $destDims['x'], $destDims['x'], $srcDims['x'], $srcDims['y'], $destDims['w'], $destDims['h'], $srcDims['w'], $srcDims['h']); switch ($ext) { case 'jpg': $ok = imagejpeg($dest, $name . '.' . $ext, 85); break; case 'gif': $ok = imagegif($dest, $name . '.' . $ext); break; case 'png': $ok = imagepng($dest, $name . '.' . $ext); break; default: CLISetup::log($done . ' - unsupported file fromat: ' . $ext, CLISetup::LOG_WARN); } imagedestroy($dest); if ($ok) { chmod($name . '.' . $ext, Util::FILE_ACCESS); CLISetup::log($done . ' - image ' . $name . '.' . $ext . ' written', CLISetup::LOG_OK); } else { CLISetup::log($done . ' - could not create image ' . $name . '.' . $ext, CLISetup::LOG_ERROR); } return $ok; }; $checkSourceDirs = function ($sub, &$missing = []) use($imgPath, $dbcPath, $paths) { $hasMissing = false; foreach (array_column($paths, 0) as $subDir) { $p = sprintf($imgPath, $sub) . $subDir; if (!CLISetup::fileExists($p)) { $hasMissing = true; $missing[] = $p; } } $p = sprintf($dbcPath, $sub); if (!CLISetup::fileExists($p)) { $hasMissing = true; $missing[] = $p; } return !$hasMissing; }; if (isset(FileGen::$cliOpts['icons'])) { array_push($groups, 0, 2, 3, 4, 5, 10); } if (isset(FileGen::$cliOpts['glyphs'])) { $groups[] = 1; } if (isset(FileGen::$cliOpts['pagetexts'])) { array_push($groups, 7, 8, 9); } if (isset(FileGen::$cliOpts['loadingscreens'])) { $groups[] = 11; } // filter by pasaed options if (!$groups) { // by default do not generate loadingscreens unset($paths[11]); } else { foreach (array_keys($paths) as $k) { if (!in_array($k, $groups)) { unset($paths[$k]); } } } foreach (CLISetup::$expectedPaths as $xp => $__) { if ($xp) { // if in subDir add trailing slash $xp .= '/'; } if ($checkSourceDirs($xp, $missing)) { $locStr = $xp; break; } } // if no subdir had sufficient data, diaf if ($locStr === null) { CLISetup::log('one or more required directories are missing:', CLISetup::LOG_ERROR); foreach ($missing as $m) { CLISetup::log(' - ' . $m, CLISetup::LOG_ERROR); } return; } // init directories foreach (array_column($paths, 1) as $subDirs) { foreach ($subDirs as $sd) { if (!CLISetup::writeDir($destDir . $sd[0])) { $success = false; } } } // ok, departure from std::procedure here // scan ItemDisplayInfo.dbc and SpellIcon.dbc for expected images and save them to an array // load all icon paths into another array and xor these two // excess entries for the directory are fine, excess entries for the dbc's are not $dbcEntries = []; if (isset($paths[0]) || isset($paths[1])) { if (isset($paths[0]) && !isset($paths[1])) { $siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon WHERE iconPath NOT LIKE "%glyph-rune%"'); } else { if (!isset($paths[0]) && isset($paths[1])) { $siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon WHERE iconPath LIKE "%glyph-rune%"'); } else { $siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon'); } } foreach ($siRows as $icon) { $dbcEntries[] = strtolower(sprintf('setup/mpqdata/%s', $locStr) . strtr($icon, ['\\' => '/']) . '.blp'); } } if (isset($paths[0])) { $itemIcons = DB::Aowow()->selectCol('SELECT inventoryIcon1 FROM dbc_itemdisplayinfo WHERE inventoryIcon1 <> ""'); foreach ($itemIcons as $icon) { $dbcEntries[] = strtolower(sprintf($imgPath, $locStr) . 'Icons/' . $icon . '.blp'); } $eventIcons = DB::Aowow()->selectCol('SELECT textureString FROM dbc_holidays WHERE textureString <> ""'); foreach ($eventIcons as $icon) { $dbcEntries[] = strtolower(sprintf($imgPath, $locStr) . 'Calendar/Holidays/' . $icon . 'Start.blp'); } } // case-insensitive array_unique *vomits silently into a corner* $dbcEntries = array_intersect_key($dbcEntries, array_unique($dbcEntries)); $allPaths = []; foreach ($paths as $i => $p) { $path = sprintf($imgPath, $locStr) . $p[0]; if (!CLISetup::fileExists($path)) { continue; } $files = glob($path . $p[2], GLOB_BRACE); $allPaths = array_merge($allPaths, $files); CLISetup::log('processing ' . count($files) . ' files in ' . $path . '...'); $j = 0; foreach ($files as $f) { ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time) $src = null; $img = explode('.', array_pop(explode('/', $f))); array_pop($img); // there are a hand full of images with multiple file endings or random dots in the name $img = implode('.', $img); // file not from dbc -> name from array or skip file if (!empty($cuNames[$i])) { if (!empty($cuNames[$i][strtolower($img)])) { $img = $cuNames[$i][strtolower($img)]; } else { if (!$p[4]) { $j += count($p[1]); CLISetup::log('skipping extraneous file ' . $img . ' (+' . count($p[1]) . ')'); continue; } } } $nFiles = count($p[1]) * ($p[4] ? array_sum(array_map('count', $cuNames[$i])) : count($files)); foreach ($p[1] as $info) { if ($p[4]) { foreach ($cuNames[$i] as $y => $row) { foreach ($row as $x => $name) { $j++; $img = $p[3] ? strtolower($name) : $name; $done = ' - ' . str_pad($j . '/' . $nFiles, 12) . str_pad('(' . number_format($j * 100 / $nFiles, 2) . '%)', 9); if (!isset(FileGen::$cliOpts['force']) && file_exists($destDir . $info[0] . $img . '.' . $info[1])) { CLISetup::log($done . ' - file ' . $info[0] . $img . '.' . $info[1] . ' was already processed'); continue; } if (!$src) { $src = $loadImageFile($f); } if (!$src) { // error should be created by imagecreatefromblp continue; } $from = array('x' => $info[4] + $p[4] * $x, 'y' => $info[4] + $p[4] * $y, 'w' => $p[4] - $info[4] * 2, 'h' => $p[4] - $info[4] * 2); $to = array('x' => 0, 'y' => 0, 'w' => $info[3], 'h' => $info[3]); if (!$writeImage($destDir . $info[0] . $img, $info[1], $src, $from, $to, $done)) { $success = false; } } } // custom handle for combined icon 'quest_startend' /* not used due to alphaChannel issues if ($p[4] == 32) { $dest = imagecreatetruecolor(19, 16); imagesavealpha($dest, true); imagealphablending($dest, true); // excalmationmark, questionmark imagecopyresampled($dest, $src, 0, 1, 32 + 5, 32 + 2, 8, 15, 18, 30); imagecopyresampled($dest, $src, 5, 0, 64 + 1, 32 + 1, 10, 16, 18, 28); if (imagegif($dest, $destDir.$info[0].'quest_startend.gif')) CLISetup::log(' extra - image '.$destDir.$info[0].'quest_startend.gif written', CLISetup::LOG_OK); else { CLISetup::log(' extra - could not create image '.$destDir.$info[0].'quest_startend.gif', CLISetup::LOG_ERROR); $success = false; } imagedestroy($dest); } */ } else { // icon -> lowercase if ($p[3]) { $img = strtolower($img); } $j++; $done = ' - ' . str_pad($j . '/' . $nFiles, 12) . str_pad('(' . number_format($j * 100 / $nFiles, 2) . '%)', 9); if (!isset(FileGen::$cliOpts['force']) && file_exists($destDir . $info[0] . $img . '.' . $info[1])) { CLISetup::log($done . ' - file ' . $info[0] . $img . '.' . $info[1] . ' was already processed'); continue; } if (!$src) { $src = $loadImageFile($f); } if (!$src) { // error should be created by imagecreatefromblp continue; } $from = array('x' => $info[4], 'y' => $info[4], 'w' => ($info[2] ?: imagesx($src)) - $info[4] * 2, 'h' => ($info[2] ?: imagesy($src)) - $info[4] * 2); $to = array('x' => 0, 'y' => 0, 'w' => $info[3] ?: imagesx($src), 'h' => $info[3] ?: imagesy($src)); if (!$writeImage($destDir . $info[0] . $img, $info[1], $src, $from, $to, $done)) { $success = false; } } } unset($src); } } // reset execTime ini_set('max_execution_time', FileGen::$defaultExecTime); if ($missing = array_diff(array_map('strtolower', $dbcEntries), array_map('strtolower', $allPaths))) { asort($missing); CLISetup::log('the following ' . count($missing) . ' images where referenced by DBC but not in the mpqData directory. They may need to be converted by hand later on.', CLISetup::LOG_WARN); foreach ($missing as $m) { CLISetup::log(' - ' . $m); } } return $success; }
function complexImg() { if (isset(FileGen::$cliOpts['help'])) { echo "\n"; echo "available options for subScript 'complexImg':\n"; // modeMask echo "--talentbgs (backgrounds for talent calculator)\n"; // 0x01 echo "--maps (generates worldmaps)\n"; // 0x02 echo "--spawn-maps (creates alphaMasks of each zone to check spawns against)\n"; // 0x04 echo "--artwork (optional: imagery from /glues/credits (not used, skipped by default))\n"; // 0x08 echo "--area-maps (optional: renders maps with highlighted subZones for each area)\n"; // 0x10 return true; } $mapWidth = 1002; $mapHeight = 668; $threshold = 95; // alpha threshold to define subZones: set it too low and you have unspawnable areas inside a zone; set it too high and the border regions overlap $runTime = ini_get('max_execution_time'); $locStr = null; $dbcPath = CLISetup::$srcDir . '%sDBFilesClient/'; $imgPath = CLISetup::$srcDir . '%sInterface/'; $destDir = 'static/images/wow/'; $success = true; $paths = ['WorldMap/', 'TalentFrame/', 'Glues/Credits/']; $modeMask = 0x7; // talentBGs, regular maps, spawn-related alphaMaps $createAlphaImage = function ($w, $h) { $img = imagecreatetruecolor($w, $h); imagesavealpha($img, true); imagealphablending($img, false); $bgColor = imagecolorallocatealpha($img, 0, 0, 0, 127); imagefilledrectangle($img, 0, 0, imagesx($img) - 1, imagesy($img) - 1, $bgColor); imagecolortransparent($img, $bgColor); imagealphablending($img, true); imagecolordeallocate($img, $bgColor); return $img; }; // prefer manually converted PNG files (as the imagecreatefromblp-script has issues with some formats) // alpha channel issues observed with locale deDE Hilsbrad and Elwynn - maps // see: https://github.com/Kanma/BLPConverter $loadImageFile = function ($path) { $result = null; $file = $path . '.png'; if (CLISetup::fileExists($file)) { CLISetup::log('manually converted png file present for ' . $path . '.', CLISetup::LOG_WARN); $result = imagecreatefrompng($file); } if (!$result) { $file = $path . '.blp'; if (CLISetup::fileExists($file)) { $result = imagecreatefromblp($file); } } return $result; }; $assembleImage = function ($baseName, $order, $w, $h) use($loadImageFile) { $dest = imagecreatetruecolor($w, $h); imagesavealpha($dest, true); imagealphablending($dest, false); $_h = $h; foreach ($order as $y => $row) { $_w = $w; foreach ($row as $x => $suffix) { $src = $loadImageFile($baseName . $suffix); if (!$src) { CLISetup::log(' - complexImg: tile ' . $baseName . $suffix . '.blp missing.', CLISetup::LOG_ERROR); unset($dest); return null; } imagecopyresampled($dest, $src, 256 * $x, 256 * $y, 0, 0, min($_w, 256), min($_h, 256), min($_w, 256), min($_h, 256)); $_w -= 256; unset($src); } $_h -= 256; } return $dest; }; $writeImage = function ($name, $ext, $src, $w, $h, $done) { $ok = false; $dest = imagecreatetruecolor($w, $h); imagesavealpha($dest, true); imagealphablending($dest, false); imagecopyresampled($dest, $src, 0, 0, 0, 0, $w, $h, imagesx($src), imagesy($src)); switch ($ext) { case 'jpg': $ok = imagejpeg($dest, $name . '.' . $ext, 85); break; case 'png': $ok = imagepng($dest, $name . '.' . $ext); break; default: CLISetup::log($done . ' - unsupported file fromat: ' . $ext, CLISetup::LOG_WARN); } imagedestroy($dest); if ($ok) { chmod($name . '.' . $ext, CLISetup::FILE_ACCESS); CLISetup::log($done . ' - image ' . $name . '.' . $ext . ' written', CLISetup::LOG_OK); } else { CLISetup::log($done . ' - could not create image ' . $name . '.' . $ext, CLISetup::LOG_ERROR); } return $ok; }; $createSpawnMap = function ($img, $zoneId) use($mapHeight, $mapWidth, $threshold) { CLISetup::log(' - creating spawn map'); $tmp = imagecreate(1000, 1000); $cbg = imagecolorallocate($tmp, 255, 255, 255); $cfg = imagecolorallocate($tmp, 0, 0, 0); for ($y = 0; $y < 1000; $y++) { for ($x = 0; $x < 1000; $x++) { $a = imagecolorat($img, $x * $mapWidth / 1000, $y * $mapHeight / 1000) >> 24; imagesetpixel($tmp, $x, $y, $a < $threshold ? $cfg : $cbg); } } imagepng($tmp, 'setup/generated/alphaMaps/' . $zoneId . '.png'); imagecolordeallocate($tmp, $cbg); imagecolordeallocate($tmp, $cfg); imagedestroy($tmp); }; $checkSourceDirs = function ($sub, &$missing = []) use($imgPath, $dbcPath, $paths, &$modeMask) { $hasMissing = false; foreach ($paths as $idx => $subDir) { if ($idx == 0 && !($modeMask & 0x16)) { // map related continue; } else { if ($idx == 1 && !($modeMask & 0x1)) { // talentBGs continue; } else { if ($idx == 2 && !($modeMask & 0x8)) { // artwork continue; } } } $p = sprintf($imgPath, $sub) . $subDir; if (!CLISetup::fileExists($p)) { $hasMissing = true; $missing[] = $p; } } if ($modeMask & 0x17) { $p = sprintf($dbcPath, $sub); if (!CLISetup::fileExists($p)) { $hasMissing = true; $missing[] = $p; } } return !$hasMissing; }; // do not change order of params! if ($_ = FileGen::hasOpt('talentbgs', 'maps', 'spawn-maps', 'artwork', 'area-maps')) { $modeMask = $_; } foreach (CLISetup::$expectedPaths as $xp => $__) { if ($xp) { // if in subDir add trailing slash $xp .= '/'; } if ($checkSourceDirs($xp, $missing)) { $locStr = $xp; break; } } // if no subdir had sufficient data, diaf if ($locStr === null) { CLISetup::log('one or more required directories are missing:', CLISetup::LOG_ERROR); foreach ($missing as $m) { CLISetup::log(' - ' . $m, CLISetup::LOG_ERROR); } return; } /**************/ /* TalentTabs */ /**************/ if ($modeMask & 0x1) { if (CLISetup::writeDir($destDir . 'hunterpettalents/') && CLISetup::writeDir($destDir . 'talents/backgrounds/')) { // [classMask, creatureFamilyMask, tabNr, textureStr] $tTabs = DB::Aowow()->select('SELECT tt.creatureFamilyMask, tt.textureFile, tt.tabNumber, cc.fileString FROM dbc_talenttab tt LEFT JOIN dbc_chrclasses cc ON cc.Id = (LOG(2, tt.classMask) + 1)'); $order = array(['-TopLeft', '-TopRight'], ['-BottomLeft', '-BottomRight']); if ($tTabs) { $sum = 0; $total = count($tTabs); CLISetup::log('Processing ' . $total . ' files from TalentFrame/ ...'); foreach ($tTabs as $tt) { ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time) $sum++; $done = ' - ' . str_pad($sum . '/' . $total, 8) . str_pad('(' . number_format($sum * 100 / $total, 2) . '%)', 9); if ($tt['creatureFamilyMask']) { $size = [244, 364]; $name = $destDir . 'hunterpettalents/bg_' . (log($tt['creatureFamilyMask'], 2) + 1); } else { $size = [204, 554]; $name = $destDir . 'talents/backgrounds/' . strtolower($tt['fileString']) . '_' . ($tt['tabNumber'] + 1); } if (!isset(FileGen::$cliOpts['force']) && file_exists($name . '.jpg')) { CLISetup::log($done . ' - file ' . $name . '.jpg was already processed'); continue; } $im = $assembleImage(sprintf($imgPath, $locStr) . 'TalentFrame/' . $tt['textureFile'], $order, 256 + 44, 256 + 75); if (!$im) { CLISetup::log(' - could not assemble file ' . $tt['textureFile'], CLISetup::LOG_ERROR); continue; } if (!$writeImage($name, 'jpg', $im, $size[0], $size[1], $done)) { $success = false; } } } else { $success = false; } ini_set('max_execution_time', $runTime); } else { $success = false; } } /************/ /* Worldmap */ /************/ if ($modeMask & 0x16) { $mapDirs = array(['maps/%snormal/', 'jpg', 488, 325], ['maps/%soriginal/', 'jpg', 0, 0], ['maps/%ssmall/', 'jpg', 224, 163], ['maps/%szoom/', 'jpg', 772, 515]); // as the js expects them $baseLevelFix = array(4264 => 1, 4265 => 1, 4415 => 1, 4416 => 1, 4493 => 0, 4500 => 1, 4603 => 1, 4723 => 1, 4809 => 1, 4813 => 1, 4820 => 1, 717 => 1, 3713 => 1, 2437 => 1, 3716 => 1, 3847 => 1, 718 => 1, 3717 => 1, 3714 => 1, 3562 => 1, 722 => 1, 491 => 1, 3792 => 1, 3789 => 1, 1477 => 1, 3959 => 0, 3845 => 1, 2717 => 1, 3923 => 1, 3607 => 1, 3836 => 1, 2159 => 1, 4075 => 0); $wmo = DB::Aowow()->select('SELECT *, worldMapAreaId AS ARRAY_KEY, Id AS ARRAY_KEY2 FROM dbc_worldmapoverlay WHERE textureString <> ""'); $wma = DB::Aowow()->select('SELECT * FROM dbc_worldmaparea'); if (!$wma || !$wmo) { $success = false; CLISetup::log(' - could not read required dbc files: WorldMapArea.dbc [' . count($wma) . ' entries]; WorldMapOverlay.dbc [' . count($wmo) . ' entries]', CLISetup::LOG_ERROR); return; } // fixups... foreach ($wma as &$a) { if ($a['areaId']) { continue; } switch ($a['Id']) { case 13: $a['areaId'] = -6; break; // Kalimdor // Kalimdor case 14: $a['areaId'] = -3; break; // Eastern Kingdoms // Eastern Kingdoms case 466: $a['areaId'] = -2; break; // Outland // Outland case 485: $a['areaId'] = -5; break; // Northrend } } array_unshift($wma, ['Id' => -1, 'areaId' => -1, 'nameINT' => 'World'], ['Id' => -4, 'areaId' => -4, 'nameINT' => 'Cosmic']); $sumMaps = count(CLISetup::$localeIds) * count($wma); CLISetup::log('Processing ' . $sumMaps . ' files from WorldMap/ ...'); foreach (CLISetup::$localeIds as $progressLoc => $l) { // create destination directories $dirError = false; foreach ($mapDirs as $md) { if (!CLISetup::writeDir($destDir . sprintf($md[0], strtolower(Util::$localeStrings[$l]) . '/'))) { $dirError = true; } } if ($modeMask & 0x4) { if (!CLISetup::writeDir('setup/generated/alphaMaps')) { $dirError = true; } } if ($dirError) { $success = false; CLISetup::log(' - complexImg: could not create map directories for locale ' . $l . '. skipping...', CLISetup::LOG_ERROR); continue; } // source for mapFiles $mapSrcDir = null; $locDirs = array_filter(CLISetup::$expectedPaths, function ($var) use($l) { return !$var || $var == $l; }); foreach ($locDirs as $mapLoc => $__) { if ($mapLoc) { // and trailing slash again $mapLoc .= '/'; } $p = sprintf($imgPath, $mapLoc) . $paths[0]; if (CLISetup::fileExists($p)) { CLISetup::log(' - using files from ' . ($mapLoc ?: '/') . ' for locale ' . Util::$localeStrings[$l], CLISetup::LOG_WARN); $mapSrcDir = $p . '/'; break; } } if ($mapSrcDir === null) { $success = false; CLISetup::log(' - no suitable localized map files found for locale ' . $l, CLISetup::LOG_ERROR); continue; } foreach ($wma as $progressArea => $areaEntry) { $curMap = $progressArea + count($wma) * $progressLoc; $progress = ' - ' . str_pad($curMap . '/' . $sumMaps, 10) . str_pad('(' . number_format($curMap * 100 / $sumMaps, 2) . '%)', 9); $wmaId = $areaEntry['Id']; $zoneId = $areaEntry['areaId']; $textureStr = $areaEntry['nameINT']; $path = $mapSrcDir . $textureStr; if (!CLISetup::fileExists($path)) { $success = false; CLISetup::log('worldmap file ' . $path . ' missing for selected locale ' . Util::$localeStrings[$l], CLISetup::LOG_ERROR); continue; } $fmt = array([1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]); CLISetup::log($textureStr . " [" . $zoneId . "]"); $overlay = $createAlphaImage($mapWidth, $mapHeight); // zone has overlays (is in open world; is not multiLeveled) if (isset($wmo[$wmaId])) { CLISetup::log(' - area has ' . count($wmo[$wmaId]) . ' overlays'); foreach ($wmo[$wmaId] as &$row) { $i = 1; $y = 0; while ($y < $row['h']) { $x = 0; while ($x < $row['w']) { $img = $loadImageFile($path . '/' . $row['textureString'] . $i); if (!$img) { CLISetup::log(' - complexImg: tile ' . $path . '/' . $row['textureString'] . $i . '.blp missing.', CLISetup::LOG_ERROR); break 2; } imagecopy($overlay, $img, $row['x'] + $x, $row['y'] + $y, 0, 0, imagesx($img), imagesy($img)); // prepare subzone image if ($modeMask & 0x10) { if (!isset($row['maskimage'])) { $row['maskimage'] = $createAlphaImage($row['w'], $row['h']); $row['maskcolor'] = imagecolorallocatealpha($row['maskimage'], 255, 64, 192, 64); } for ($my = 0; $my < imagesy($img); $my++) { for ($mx = 0; $mx < imagesx($img); $mx++) { if (imagecolorat($img, $mx, $my) >> 24 < $threshold) { imagesetpixel($row['maskimage'], $x + $mx, $y + $my, $row['maskcolor']); } } } } imagedestroy($img); $x += 256; $i++; } $y += 256; } } // create spawn-maps if wanted if ($modeMask & 0x4) { $createSpawnMap($overlay, $zoneId); } } // check, if the current zone is multiLeveled // if there are also files present without layer-suffix assume them as layer: 0 $multiLeveled = false; $multiLevel = 0; do { if (!CLISetup::filesInPath('/' . $textureStr . '\\/' . $textureStr . ($multiLevel + 1) . '_\\d\\.blp/i', true)) { break; } $multiLevel++; $multiLeveled = true; } while ($multiLevel < 18); // Karazhan has 17 frickin floors // check if we can create base map anyway $file = $path . '/' . $textureStr . '1.blp'; $hasBaseMap = CLISetup::fileExists($file); CLISetup::log(' - area has ' . ($multiLeveled ? $multiLevel . ' levels' : 'only base level')); $map = null; for ($i = 0; $i <= $multiLevel; $i++) { ini_set('max_execution_time', 120); // max 120sec per image $file = $path . '/' . $textureStr; if (!$i && !$hasBaseMap) { continue; } // if $multiLeveled also suffix -0 to baseMap if it exists if ($i && $multiLeveled) { $file .= $i . '_'; } $doSkip = 0x0; $outFile = []; foreach ($mapDirs as $idx => $info) { $outFile[$idx] = $destDir . sprintf($info[0], strtolower(Util::$localeStrings[$l]) . '/') . $zoneId; $floor = $i; if ($zoneId == 4100) { // ToCStratholme: map order fix $floor += 1; } if ($multiLeveled && !(isset($baseLevelFix[$zoneId]) && $i == $baseLevelFix[$zoneId])) { $outFile[$idx] .= '-' . $floor; } if (!isset(FileGen::$cliOpts['force']) && file_exists($outFile[$idx] . '.' . $info[1])) { CLISetup::log($progress . ' - file ' . $outFile[$idx] . '.' . $info[1] . ' was already processed'); $doSkip |= 1 << $idx; } } if ($doSkip == 0xf) { continue; } $map = $assembleImage($file, $fmt, $mapWidth, $mapHeight); if (!$map) { $success = false; CLISetup::log(' - could not create image resource for map ' . $zoneId . ($multiLevel ? ' level ' . $i : '')); continue; } if (!$multiLeveled) { imagecopymerge($map, $overlay, 0, 0, 0, 0, imagesx($overlay), imagesy($overlay), 100); imagedestroy($overlay); } // create map if ($modeMask & 0x2) { foreach ($mapDirs as $idx => $info) { if ($doSkip & 1 << $idx) { continue; } if (!$writeImage($outFile[$idx], $info[1], $map, $info[2] ?: $mapWidth, $info[3] ?: $mapHeight, $progress)) { $success = false; } } } } // also create subzone-maps if ($map && isset($wmo[$wmaId]) && $modeMask & 0x10) { foreach ($wmo[$wmaId] as &$row) { $doSkip = 0x0; $outFile = []; foreach ($mapDirs as $idx => $info) { $outFile[$idx] = $destDir . sprintf($info[0], strtolower(Util::$localeStrings[$l]) . '/') . $row['areaTableId']; if (!isset(FileGen::$cliOpts['force']) && file_exists($outFile[$idx] . '.' . $info[1])) { CLISetup::log($progress . ' - file ' . $outFile[$idx] . '.' . $info[1] . ' was already processed'); $doSkip |= 1 << $idx; } } if ($doSkip == 0xf) { continue; } $subZone = imagecreatetruecolor($mapWidth, $mapHeight); imagecopy($subZone, $map, 0, 0, 0, 0, imagesx($map), imagesy($map)); imagecopy($subZone, $row['maskimage'], $row['x'], $row['y'], 0, 0, imagesx($row['maskimage']), imagesy($row['maskimage'])); foreach ($mapDirs as $idx => $info) { if ($doSkip & 1 << $idx) { continue; } if (!$writeImage($outFile[$idx], $info[1], $subZone, $info[2] ?: $mapWidth, $info[3] ?: $mapHeight, $progress)) { $success = false; } } imagedestroy($subZone); } } if ($map) { imagedestroy($map); } } } } /***********/ /* Credits */ /***********/ if ($modeMask & 0x8) { if (CLISetup::writeDir($destDir . 'Interface/Glues/Credits/')) { // tile ordering $order = array(1 => array([1]), 2 => array([1], [2]), 4 => array([1, 2], [3, 4]), 6 => array([1, 2, 3], [4, 5, 6]), 8 => array([1, 2, 3, 4], [5, 6, 7, 8])); $imgGroups = []; $srcPath = sprintf($imgPath, $locStr) . 'Glues/Credits/'; $files = CLISetup::filesInPath($srcPath); foreach ($files as $f) { if (preg_match('/([^\\/]+)(\\d).blp/i', $f, $m)) { if ($m[1] && $m[2]) { if (!isset($imgGroups[$m[1]])) { $imgGroups[$m[1]] = $m[2]; } else { if ($imgGroups[$m[1]] < $m[2]) { $imgGroups[$m[1]] = $m[2]; } } } } } // errör-korrekt $imgGroups['Desolace'] = 4; $imgGroups['BloodElf_Female'] = 6; $total = count($imgGroups); $sum = 0; CLISetup::log('Processing ' . $total . ' files from Glues/Credits/...'); foreach ($imgGroups as $file => $fmt) { ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time) $sum++; $done = ' - ' . str_pad($sum . '/' . $total, 8) . str_pad('(' . number_format($sum * 100 / $total, 2) . '%)', 9); $name = $destDir . 'Interface/Glues/Credits/' . $file; if (!isset(FileGen::$cliOpts['force']) && file_exists($name . '.png')) { CLISetup::log($done . ' - file ' . $name . '.png was already processed'); continue; } if (!isset($order[$fmt])) { CLISetup::log(' - pattern for file ' . $name . ' not set. skipping', CLISetup::LOG_WARN); continue; } $im = $assembleImage($srcPath . $file, $order[$fmt], count($order[$fmt][0]) * 256, count($order[$fmt]) * 256); if (!$im) { CLISetup::log(' - could not assemble file ' . $name, CLISetup::LOG_ERROR); continue; } if (!$writeImage($name, 'png', $im, count($order[$fmt][0]) * 256, count($order[$fmt]) * 256, $done)) { $success = false; } } ini_set('max_execution_time', $runTime); } else { $success = false; } } return $success; }
function profiler() { $success = true; $scripts = []; /**********/ /* Quests */ /**********/ $scripts[] = function () { $success = true; $condition = [CFG_SQL_LIMIT_NONE, 'AND', [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW], 0], [['flags', QUEST_FLAG_DAILY | QUEST_FLAG_WEEKLY | QUEST_FLAG_REPEATABLE | QUEST_FLAG_AUTO_REWARDED, '&'], 0], [['specialFlags', QUEST_FLAG_SPECIAL_REPEATABLE | QUEST_FLAG_SPECIAL_DUNGEON_FINDER | QUEST_FLAG_SPECIAL_MONTHLY, '&'], 0]]; $questz = new QuestList($condition); $_ = []; $currencies = array_column($questz->rewards, TYPE_CURRENCY); foreach ($currencies as $curr) { foreach ($curr as $cId => $qty) { $_[] = $cId; } } $relCurr = new CurrencyList(array(['id', $_])); foreach (CLISetup::$localeIds as $l) { set_time_limit(20); User::useLocale($l); Lang::load(Util::$localeStrings[$l]); $buff = "var _ = g_gatheredcurrencies;\n"; foreach ($relCurr->getListviewData() as $id => $data) { $buff .= '_[' . $id . '] = ' . Util::toJSON($data) . ";\n"; } $buff .= "\n\nvar _ = g_quests;\n"; foreach ($questz->getListviewData() as $id => $data) { $buff .= '_[' . $id . '] = ' . Util::toJSON($data) . ";\n"; } $buff .= "\ng_quest_catorder = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n"; if (!CLISetup::writeFile('datasets/' . User::$localeString . '/p-quests', $buff)) { $success = false; } } return $success; }; /****************/ /* Achievements */ /****************/ $scripts[] = function () { $success = true; $condition = array(CFG_SQL_LIMIT_NONE, [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0], [['flags', 1, '&'], 0]); $achievez = new AchievementList($condition); foreach (CLISetup::$localeIds as $l) { set_time_limit(5); User::useLocale($l); Lang::load(Util::$localeStrings[$l]); $sumPoints = 0; $buff = "var _ = g_achievements;\n"; foreach ($achievez->getListviewData(ACHIEVEMENTINFO_PROFILE) as $id => $data) { $sumPoints += $data['points']; $buff .= '_[' . $id . '] = ' . Util::toJSON($data) . ";\n"; } // categories to sort by $buff .= "\ng_achievement_catorder = [92, 14863, 97, 169, 170, 171, 172, 14802, 14804, 14803, 14801, 95, 161, 156, 165, 14806, 14921, 96, 201, 160, 14923, 14808, 14805, 14778, 14865, 14777, 14779, 155, 14862, 14861, 14864, 14866, 158, 162, 14780, 168, 14881, 187, 14901, 163, 14922, 159, 14941, 14961, 14962, 14981, 15003, 15002, 15001, 15041, 15042, 81]"; // sum points $buff .= "\ng_achievement_points = [" . $sumPoints . "];\n"; if (!CLISetup::writeFile('datasets/' . User::$localeString . '/p-achievements', $buff)) { $success = false; } } return $success; }; /**********/ /* Titles */ /**********/ $scripts[] = function () { $success = true; $condition = array(CFG_SQL_LIMIT_NONE, [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0]); $titlez = new TitleList($condition); foreach (CLISetup::$localeIds as $l) { set_time_limit(5); User::useLocale($l); Lang::load(Util::$localeStrings[$l]); foreach ([0, 1] as $g) { $buff = "var _ = g_titles;\n"; foreach ($titlez->getListviewData() as $id => $data) { $data['name'] = Util::localizedString($titlez->getEntry($id), $g ? 'female' : 'male'); unset($data['namefemale']); $buff .= '_[' . $id . '] = ' . Util::toJSON($data) . ";\n"; } if (!CLISetup::writeFile('datasets/' . User::$localeString . '/p-titles-' . $g, $buff)) { $success = false; } } } return $success; }; /**********/ /* Mounts */ /**********/ $scripts[] = function () { $success = true; $condition = array(CFG_SQL_LIMIT_NONE, [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0], ['typeCat', -5]); $mountz = new SpellList($condition); foreach (CLISetup::$localeIds as $l) { set_time_limit(5); User::useLocale($l); Lang::load(Util::$localeStrings[$l]); $buff = "var _ = g_spells;\n"; foreach ($mountz->getListviewData(ITEMINFO_MODEL) as $id => $data) { $data['quality'] = $data['name'][0]; $data['name'] = mb_substr($data['name'], 1); $buff .= '_[' . $id . '] = ' . Util::toJSON($data) . ";\n"; } if (!CLISetup::writeFile('datasets/' . User::$localeString . '/p-mounts', $buff)) { $success = false; } } return $success; }; /**************/ /* Companions */ /**************/ $scripts[] = function () { $success = true; $condition = array(CFG_SQL_LIMIT_NONE, [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0], ['typeCat', -6]); $companionz = new SpellList($condition); foreach (CLISetup::$localeIds as $l) { set_time_limit(5); User::useLocale($l); Lang::load(Util::$localeStrings[$l]); $buff = "var _ = g_spells;\n"; foreach ($companionz->getListviewData(ITEMINFO_MODEL) as $id => $data) { $data['quality'] = $data['name'][0]; $data['name'] = mb_substr($data['name'], 1); $buff .= '_[' . $id . '] = ' . Util::toJSON($data) . ";\n"; } if (!CLISetup::writeFile('datasets/' . User::$localeString . '/p-companions', $buff)) { $success = false; } } return $success; }; /************/ /* Factions */ /************/ $scripts[] = function () { $success = true; $condition = array(CFG_SQL_LIMIT_NONE, [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0]); $factionz = new FactionList($condition); foreach (CLISetup::$localeIds as $l) { set_time_limit(5); User::useLocale($l); Lang::load(Util::$localeStrings[$l]); $buff = "var _ = g_factions;\n"; foreach ($factionz->getListviewData() as $id => $data) { $buff .= '_[' . $id . '] = ' . Util::toJSON($data) . ";\n"; } $buff .= "\ng_faction_order = [0, 469, 891, 1037, 1118, 67, 1052, 892, 936, 1117, 169, 980, 1097];\n"; if (!CLISetup::writeFile('datasets/' . User::$localeString . '/p-factions', $buff)) { $success = false; } } return $success; }; /***********/ /* Recipes */ /***********/ $scripts[] = function () { // special case: secondary skills are always requested, so put them in one single file (185, 129, 356); it also contains g_skill_order $skills = [171, 164, 333, 202, 182, 773, 755, 165, 186, 393, 197, [185, 129, 356]]; $success = true; $baseCnd = array(CFG_SQL_LIMIT_NONE, [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0], ['effect1Id', [6, 45, 57, 127, 33, 158, 99, 28, 95], '!'], ['effect2Id', [118, 60], '!'], ['OR', ['typeCat', 9], ['typeCat', 11]]); foreach ($skills as $s) { $file = is_array($s) ? 'sec' : (string) $s; $cnd = array_merge($baseCnd, [['skillLine1', $s]]); $recipez = new SpellList($cnd); $created = ''; foreach ($recipez->iterate() as $__) { foreach ($recipez->canCreateItem() as $idx) { $id = $recipez->getField('effect' . $idx . 'CreateItemId'); $created .= "g_items.add(" . $id . ", {'icon':'" . $recipez->relItems->getEntry($id)['iconString'] . "'});\n"; } } foreach (CLISetup::$localeIds as $l) { set_time_limit(10); User::useLocale($l); Lang::load(Util::$localeStrings[$l]); $buff = ''; foreach ($recipez->getListviewData() as $id => $data) { $buff .= '_[' . $id . '] = ' . Util::toJSON($data) . ";\n"; } if (!$buff) { // this behaviour is intended, do not create an error CLISetup::log('profiler - file datasets/' . User::$localeString . '/p-recipes-' . $file . ' has no content => skipping', CLISetup::LOG_WARN); continue; } $buff = $created . "\nvar _ = g_spells;\n" . $buff; if (is_array($s)) { $buff .= "\ng_skill_order = [171, 164, 333, 202, 182, 773, 755, 165, 186, 393, 197, 185, 129, 356];\n"; } if (!CLISetup::writeFile('datasets/' . User::$localeString . '/p-recipes-' . $file, $buff)) { $success = false; } } } return $success; }; // check directory-structure foreach (Util::$localeStrings as $dir) { if (!CLISetup::writeDir('datasets/' . $dir)) { $success = false; } } // run scripts foreach ($scripts as $func) { if (!$func()) { $success = false; } } return $success; }
function enchants() { // from g_item_slots: 13:"One-Hand", 26:"Ranged", 17:"Two-Hand", $slotPointer = [13, 17, 26, 26, 13, 17, 17, 13, 17, null, 17, null, null, 13, null, 13, null, null, null, null, 17]; $castItems = []; $successs = true; $enchantSpells = new SpellList([['effect1Id', 53], ['name_loc0', 'QA%', '!'], CFG_SQL_LIMIT_NONE]); // enchantItemPermanent && !qualityAssurance // check directory-structure foreach (Util::$localeStrings as $dir) { if (!CLISetup::writeDir('datasets/' . $dir)) { $success = false; } } $enchIds = []; foreach ($enchantSpells->iterate() as $__) { $enchIds[] = $enchantSpells->getField('effect1MiscValue'); } $enchMisc = []; $enchJSON = Util::parseItemEnchantment($enchIds, false, $enchMisc); foreach (CLISetup::$localeIds as $lId) { set_time_limit(120); User::useLocale($lId); Lang::load(Util::$localeStrings[$lId]); $enchantsOut = []; foreach ($enchantSpells->iterate() as $__) { // slots have to be recalculated $slot = 0; if ($enchantSpells->getField('equippedItemClass') == 4) { if ($invType = $enchantSpells->getField('equippedItemInventoryTypeMask')) { $slot = $invType >> 1; } else { /* if (equippedItemSubClassMask == 64) */ // shields have it their own way <_< $slot = 1 << 14 - 1; } } else { if ($enchantSpells->getField('equippedItemClass') == 2) { foreach ($slotPointer as $i => $sp) { if (!$sp) { continue; } if (1 << $i & $enchantSpells->getField('equippedItemSubClassMask')) { if ($sp == 13) { // also mainHand & offHand *siiigh* $slot |= 1 << 21 - 1 | 1 << 22 - 1; } $slot |= 1 << $sp - 1; } } } } $eId = $enchantSpells->getField('effect1MiscValue'); // defaults $ench = array('name' => [], 'quality' => -1, 'icon' => strToLower($enchantSpells->getField('iconString')), 'source' => [], 'skill' => -1, 'slots' => [], 'enchantment' => Util::localizedString($enchMisc[$eId]['text'], 'text'), 'jsonequip' => @$enchJSON[$eId] ?: [], 'temp' => 0, 'classes' => 0); if (isset($enchMisc[$eId]['reqskill'])) { $ench['jsonequip']['reqskill'] = $enchMisc[$eId]['reqskill']; } if (isset($enchMisc[$eId]['reqskillrank'])) { $ench['jsonequip']['reqskill'] = $enchMisc[$eId]['reqskillrank']; } if (isset($enchMisc[$eId]['requiredLevel'])) { $ench['jsonequip']['requiredLevel'] = $enchMisc[$eId]['requiredLevel']; } // check if the spell has an entry in skill_line_ability -> Source:Profession if ($skills = $enchantSpells->getField('skillLines')) { $ench['name'][] = $enchantSpells->getField('name', true); $ench['source'][] = $enchantSpells->id; $ench['skill'] = $skills[0]; $ench['slots'][] = $slot; } // check if this spell can be cast via item -> Source:Item if (!isset($castItems[$enchantSpells->id])) { $castItems[$enchantSpells->id] = new ItemList([['spellId1', $enchantSpells->id], ['name_loc0', 'Scroll of Enchant%', '!']]); } // do not reuse enchantment scrolls $cI =& $castItems[$enchantSpells->id]; // this construct is a bit .. unwieldy foreach ($cI->iterate() as $__) { $ench['name'][] = $cI->getField('name', true); $ench['source'][] = -$cI->id; $ench['icon'] = strTolower($cI->getField('iconString')); $ench['slots'][] = $slot; if ($cI->getField('quality') > $ench['quality']) { $ench['quality'] = $cI->getField('quality'); } if ($cI->getField('requiredClass') > 0) { $ench['classes'] = $cI->getField('requiredClass'); $ench['jsonequip']['classes'] = $cI->getField('requiredClass'); } if (!isset($ench['jsonequip']['reqlevel'])) { if ($cI->getField('requiredLevel') > 0) { $ench['jsonequip']['reqlevel'] = $cI->getField('requiredLevel'); } } } // enchant spell not in use if (empty($ench['source'])) { continue; } // everything gathered if (isset($enchantsOut[$eId])) { foreach ($enchantsOut[$eId] as $k => $v) { if (is_array($v)) { while ($pop = array_pop($ench[$k])) { $enchantsOut[$eId][$k][] = $pop; } } else { if ($k == 'quality') { if ($enchantsOut[$eId]['source'][0] > 0 && $ench['source'][0] < 0) { $enchantsOut[$eId][$k] = -1; } else { if ($enchantsOut[$eId]['source'][0] < 0 && $ench['source'][0] > 0) { $enchantsOut[$eId][$k] = -1; } else { $enchantsOut[$eId][$k] = $ench[$k]; } } } else { if ($enchantsOut[$eId][$k] <= 0) { $enchantsOut[$eId][$k] = $ench[$k]; } } } } } else { // nothing yet, create new $enchantsOut[$eId] = $ench; } } // walk over each entry and strip single-item arrays foreach ($enchantsOut as &$ench) { foreach ($ench as $k => $v) { if (is_array($v) && count($v) == 1 && $k != 'jsonequip') { $ench[$k] = $v[0]; } } } $toFile = "var g_enchants = " . Util::toJSON($enchantsOut) . ";"; $file = 'datasets/' . User::$localeString . '/enchants'; if (!CLISetup::writeFile($file, $toFile)) { $success = false; } } return $successs; }
function talents() { $success = true; $buildTree = function ($class) use(&$petFamIcons, &$tSpells) { $petCategories = []; $mask = $class ? 1 << $class - 1 : 0; // All "tabs" of a given class talent $tabs = DB::Aowow()->select('SELECT * FROM dbc_talenttab WHERE classMask = ?d ORDER BY `tabNumber`, `creatureFamilyMask`', $mask); $result = []; for ($l = 0; $l < count($tabs); $l++) { $talents = DB::Aowow()->select('SELECT t.id AS tId, t.*, s.name_loc0, s.name_loc2, s.name_loc3, s.name_loc6, s.name_loc8, LOWER(SUBSTRING_INDEX(si.iconPath, "\\\\", -1)) AS iconString FROM dbc_talent t, dbc_spell s, dbc_spellicon si WHERE si.`Id` = s.`iconId` AND t.`tabId`= ?d AND s.`Id` = t.`rank1` ORDER by t.`row`, t.`column`', $tabs[$l]['Id']); $result[$l] = array('n' => Util::localizedString($tabs[$l], 'name'), 't' => []); if (!$class) { $petFamId = log($tabs[$l]['creatureFamilyMask'], 2); $result[$l]['icon'] = $petFamIcons[$petFamId]; $petCategories = DB::Aowow()->SelectCol('SELECT Id AS ARRAY_KEY, categoryEnumID FROM dbc_creaturefamily WHERE petTalentType = ?d', $petFamId); $result[$l]['f'] = array_keys($petCategories); } // talent dependencies go here $depLinks = []; $tNums = []; for ($j = 0; $j < count($talents); $j++) { $tNums[$talents[$j]['tId']] = $j; $d = []; $s = []; $i = $talents[$j]['tId']; $n = Util::localizedString($talents[$j], 'name'); $x = $talents[$j]['column']; $y = $talents[$j]['row']; $r = null; $t = []; $icon = $talents[$j]['iconString']; $m = $talents[$j]['rank2'] == 0 ? 1 : ($talents[$j]['rank3'] == 0 ? 2 : ($talents[$j]['rank4'] == 0 ? 3 : ($talents[$j]['rank5'] == 0 ? 4 : 5))); // duplet handling $f = []; foreach ($petCategories as $k => $v) { // cant handle 64bit integer .. split if ($v >= 32 && 1 << $v - 32 & $talents[$j]['petCategory2']) { $f[] = $k; } else { if ($v < 32 && 1 << $v & $talents[$j]['petCategory1']) { $f[] = $k; } } } for ($k = 0; $k <= $m - 1; $k++) { if (!$tSpells->getEntry($talents[$j]['rank' . ($k + 1)])) { continue; } $d[] = $tSpells->parseText()[0]; $s[] = $talents[$j]['rank' . ($k + 1)]; if ($talents[$j]['talentSpell']) { $t[] = $tSpells->getTalentHeadForCurrent(); } } if ($talents[$j]['reqTalent']) { // we didn't encounter the required talent yet => create reference if (!isset($tNums[$talents[$j]['reqTalent']])) { $depLinks[$talents[$j]['reqTalent']] = $j; } $r = @[$tNums[$talents[$j]['reqTalent']], $talents[$j]['reqRank'] + 1]; } $result[$l]['t'][$j] = array('i' => $i, 'n' => $n, 'm' => $m, 'd' => $d, 's' => $s, 'x' => $x, 'y' => $y); if (isset($r)) { $result[$l]['t'][$j]['r'] = $r; } if (!empty($t)) { $result[$l]['t'][$j]['t'] = $t; } if (!empty($f)) { $result[$l]['t'][$j]['f'] = $f; } if ($class) { $result[$l]['t'][$j]['iconname'] = $icon; } // If this talent is a reference, add it to the array of talent dependencies if (isset($depLinks[$talents[$j]['tId']])) { $result[$l]['t'][$depLinks[$talents[$j]['tId']]]['r'][0] = $j; unset($depLinks[$talents[$j]['tId']]); } } // Remove all dependencies for which the talent has not been found foreach ($depLinks as $dep_link) { unset($result[$l]['t'][$dep_link]['r']); } } return $result; }; // my neighbour is noisy as f**k and my head hurts, so .. $petFamIcons = ['Ability_Druid_KingoftheJungle', 'Ability_Druid_DemoralizingRoar', 'Ability_EyeOfTheOwl']; // .. i've no idea where to fetch these from $classes = [CLASS_WARRIOR, CLASS_PALADIN, CLASS_HUNTER, CLASS_ROGUE, CLASS_PRIEST, CLASS_DEATHKNIGHT, CLASS_SHAMAN, CLASS_MAGE, CLASS_WARLOCK, CLASS_DRUID]; $petIcons = ''; // check directory-structure foreach (Util::$localeStrings as $dir) { if (!CLISetup::writeDir('datasets/' . $dir)) { $success = false; } } $tSpellIds = DB::Aowow()->selectCol('SELECT rank1 FROM dbc_talent UNION SELECT rank2 FROM dbc_talent UNION SELECT rank3 FROM dbc_talent UNION SELECT rank4 FROM dbc_talent UNION SELECT rank5 FROM dbc_talent'); $tSpells = new SpellList(array(['s.id', $tSpellIds], CFG_SQL_LIMIT_NONE)); foreach (CLISetup::$localeIds as $lId) { User::useLocale($lId); Lang::load(Util::$localeStrings[$lId]); // TalentCalc foreach ($classes as $cMask) { set_time_limit(20); $cId = log($cMask, 2) + 1; $file = 'datasets/' . User::$localeString . '/talents-' . $cId; $toFile = '$WowheadTalentCalculator.registerClass(' . $cId . ', ' . Util::toJSON($buildTree($cId)) . ')'; if (!CLISetup::writeFile($file, $toFile)) { $success = false; } } // PetCalc if (empty($petIcons)) { $pets = DB::Aowow()->SelectCol('SELECT Id AS ARRAY_KEY, LOWER(SUBSTRING_INDEX(iconString, "\\\\", -1)) AS iconString FROM dbc_creaturefamily WHERE petTalentType IN (0, 1, 2)'); $petIcons = Util::toJSON($pets); } $toFile = "var g_pet_icons = " . $petIcons . ";\n\n"; $toFile .= 'var g_pet_talents = ' . Util::toJSON($buildTree(0)) . ';'; $file = 'datasets/' . User::$localeString . '/pet-talents'; if (!CLISetup::writeFile($file, $toFile)) { $success = false; } } return $success; }
function itemsets() { $success = true; $setList = DB::Aowow()->Select('SELECT * FROM ?_itemset ORDER BY refSetId DESC'); $jsonBonus = []; // check directory-structure foreach (Util::$localeStrings as $dir) { if (!CLISetup::writeDir('datasets/' . $dir)) { $success = false; } } foreach (CLISetup::$localeIds as $lId) { User::useLocale($lId); Lang::load(Util::$localeStrings[$lId]); $itemsetOut = []; foreach ($setList as $set) { set_time_limit(15); $setOut = array('id' => $set['id'], 'name' => 7 - $set['quality'] . Util::jsEscape(Util::localizedString($set, 'name')), 'pieces' => [], 'heroic' => !!$set['heroic'], 'maxlevel' => $set['maxLevel'], 'minlevel' => $set['minLevel'], 'type' => $set['type'], 'setbonus' => []); if ($set['classMask']) { $setOut['reqclass'] = $set['classMask']; $setOut['classes'] = []; for ($i = 0; $i < 12; $i++) { if ($set['classMask'] & 1 << $i - 1) { $setOut['classes'][] = $i; } } } if ($set['contentGroup']) { $setOut['note'] = $set['contentGroup']; } if ($set['id'] < 0) { $setOut['idbak'] = $set['refSetId']; } for ($i = 1; $i < 11; $i++) { if ($set['item' . $i]) { $setOut['pieces'][] = $set['item' . $i]; } } for ($i = 1; $i < 9; $i++) { if (!$set['bonus' . $i] || !$set['spell' . $i]) { continue; } // costy and locale-independant -> cache if (!isset($jsonBonus[$set['spell' . $i]])) { $jsonBonus[$set['spell' . $i]] = (new SpellList(array(['s.id', (int) $set['spell' . $i]])))->getStatGain()[$set['spell' . $i]]; } if (!isset($setOut['setbonus'][$set['bonus' . $i]])) { $setOut['setbonus'][$set['bonus' . $i]] = $jsonBonus[$set['spell' . $i]]; } else { foreach ($jsonBonus[$set['spell' . $i]] as $k => $v) { @($setOut['setbonus'][$set['bonus' . $i]][$k] += $v); } } } foreach ($setOut['setbonus'] as $k => $v) { if (empty($v)) { unset($setOut['setbonus'][$k]); } else { foreach ($v as $sk => $sv) { if ($str = Util::$itemMods[$sk]) { $setOut['setbonus'][$k][$str] = $sv; unset($setOut['setbonus'][$k][$sk]); } } } } if (empty($setOut['setbonus'])) { unset($setOut['setbonus']); } $itemsetOut[$setOut['id']] = $setOut; } $toFile = "var g_itemsets = " . Util::toJSON($itemsetOut) . ";"; $file = 'datasets/' . User::$localeString . '/itemsets'; if (!CLISetup::writeFile($file, $toFile)) { $success = false; } } return $success; }
function talentIcons() { $success = true; $query = 'SELECT ic.iconString FROM ?_icons ic JOIN dbc_spell s ON s.iconId = ic.Id JOIN dbc_talent t ON t.rank1 = s.Id JOIN dbc_talenttab tt ON tt.Id = t.tabId WHERE tt.?# = ?d AND tt.tabNumber = ?d ORDER BY t.row, t.column, t.petCategory1 ASC'; $dims = 36; //v-pets $filenames = ['icons', 'warrior', 'paladin', 'hunter', 'rogue', 'priest', 'deathknight', 'shaman', 'mage', 'warlock', null, 'druid']; // create directory if missing if (!CLISetup::writeDir('static/images/wow/talents/icons')) { $success = false; } if (!CLISetup::writeDir('static/images/wow/hunterpettalents')) { $success = false; } foreach ($filenames as $k => $v) { if (!$v) { continue; } set_time_limit(10); for ($tree = 0; $tree < 3; $tree++) { $what = $k ? 'classMask' : 'creatureFamilyMask'; $set = $k ? 1 << $k - 1 : 1 << $tree; $subset = $k ? $tree : 0; $path = $k ? 'talents/icons' : 'hunterpettalents'; $outFile = 'static/images/wow/' . $path . '/' . $v . '_' . ($tree + 1) . '.jpg'; $icons = DB::Aowow()->SelectCol($query, $what, $set, $subset); if (empty($icons)) { CLISetup::log('talentIcons - query for ' . $v . ' tree: ' . $k . ' returned empty', CLISetup::LOG_ERROR); $success = false; continue; } if ($res = imageCreateTrueColor(count($icons) * $dims, 2 * $dims)) { for ($i = 0; $i < count($icons); $i++) { $imgFile = 'static/images/wow/icons/medium/' . strtolower($icons[$i]) . '.jpg'; if (!file_exists($imgFile)) { CLISetup::log('talentIcons - raw image ' . CLISetup::bold($imgFile) . ' not found', CLISetup::LOG_ERROR); $success = false; break; } $im = imagecreatefromjpeg($imgFile); // colored imagecopymerge($res, $im, $i * $dims, 0, 0, 0, imageSX($im), imageSY($im), 100); // grayscale if (imageistruecolor($im)) { imagetruecolortopalette($im, false, 256); } for ($j = 0; $j < imagecolorstotal($im); $j++) { $color = imagecolorsforindex($im, $j); $gray = round(0.299 * $color['red'] + 0.587 * $color['green'] + 0.114 * $color['blue']); imagecolorset($im, $j, $gray, $gray, $gray); } imagecopymerge($res, $im, $i * $dims, $dims, 0, 0, imageSX($im), imageSY($im), 100); } if (@imagejpeg($res, $outFile)) { CLISetup::log(sprintf(ERR_NONE, CLISetup::bold($outFile)), CLISetup::LOG_OK); } else { $success = false; CLISetup::log('talentIcons - ' . CLISetup::bold($outFile . '.jpg') . ' could not be written', CLISetup::LOG_ERROR); } } else { $success = false; CLISetup::log('talentIcons - image resource not created', CLISetup::LOG_ERROR); continue; } } } return $success; }