function realmMenu() { $subEU = []; $subUS = []; $set = 0x0; $menu = [['us', 'US & Oceanic', null, [[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subUS]]], ['eu', 'Europe', null, [[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subEU]]]]; foreach (Util::getRealms() as $row) { if ($row['region'] == 'eu') { $set |= 0x1; $subEU[] = [Util::urlize($row['name']), $row['name']]; } else { if ($row['region'] == 'us') { $set |= 0x2; $subUS[] = [Util::urlize($row['name']), $row['name']]; } } } if (!$set) { CLISetup::log(' - realmMenu: Auth-DB not set up .. menu will be empty', CLISetup::LOG_WARN); } if (!($set & 0x1)) { array_pop($menu); } if (!($set & 0x2)) { array_shift($menu); } return Util::toJSON($menu); }
function realmMenu() { $subEU = []; $subUS = []; $set = 0x0; $menu = [['us', 'US & Oceanic', null, [[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subEU]]], ['eu', 'Europe', null, [[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subUS]]]]; if (DB::isConnectable(DB_AUTH)) { $rows = DB::Auth()->select('SELECT name, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0 AND gamebuild = ?d', WOW_VERSION); foreach ($rows as $row) { if ($row['region'] == 'eu') { $set |= 0x1; $subEU[] = [Util::urlize($row['name']), $row['name']]; } else { if ($row['region'] == 'us') { $set |= 0x2; $subUS[] = [Util::urlize($row['name']), $row['name']]; } } } } else { CLISetup::log(' - realmMenu: Auth-DB not set up .. menu will be empty', CLISetup::LOG_WARN); } if (!($set & 0x1)) { array_shift($menu); } if (!($set & 0x2)) { array_pop($menu); } return Util::toJSON($menu); }
function sql($syncMe = null) { require_once 'setup/tools/sqlGen.class.php'; SqlGen::init($syncMe !== null ? SqlGen::MODE_UPDATE : SqlGen::MODE_NORMAL, $syncMe ?: []); $done = []; if (SqlGen::$subScripts) { $allOk = true; // start file generation CLISetup::log('begin generation of ' . implode(', ', SqlGen::$subScripts)); CLISetup::log(); foreach (SqlGen::$subScripts as $tbl) { $syncIds = []; // todo: fetch what exactly must be regenerated $ok = SqlGen::generate($tbl, $syncIds); if (!$ok) { $allOk = false; } else { $done[] = $tbl; } CLISetup::log(' - subscript \'' . $tbl . '\' returned ' . ($ok ? 'sucessfully' : 'with errors'), $ok ? CLISetup::LOG_OK : CLISetup::LOG_ERROR); set_time_limit(SqlGen::$defaultExecTime); // reset to default for the next script } // end CLISetup::log(); if ($allOk) { CLISetup::log('successfully finished sql generation', CLISetup::LOG_OK); } else { CLISetup::log('finished sql generation with errors', CLISetup::LOG_ERROR); } } else { CLISetup::log('no valid script names supplied', CLISetup::LOG_ERROR); } return $done; }
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 finish() { if (!getopt('d', ['delete'])) { // generated with TEMPORARY keyword. Manual deletion is not needed CLISetup::log('generated dbc_* - tables kept available', CLISetup::LOG_INFO); } die("\n"); }
function realms() { $realms = []; if (DB::isConnectable(DB_AUTH)) { $realms = DB::Auth()->select('SELECT id AS ARRAY_KEY, name, ? AS battlegroup, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0 AND gamebuild = ?d', CFG_BATTLEGROUP, WOW_VERSION); } else { CLISetup::log(' - realms: Auth-DB not set up .. static data g_realms will be empty', CLISetup::LOG_WARN); } $toFile = "var g_realms = " . Util::toJSON($realms) . ";"; $file = 'datasets/realms'; return CLISetup::writeFile($file, $toFile); }
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 realms() { $realms = Util::getRealms(); if (!$realms) { CLISetup::log(' - realms: Auth-DB not set up .. static data g_realms will be empty', CLISetup::LOG_WARN); } else { foreach ($realms as &$r) { $r['battlegroup'] = CFG_BATTLEGROUP; } } $toFile = "var g_realms = " . Util::toJSON($realms) . ";"; $file = 'datasets/realms'; return CLISetup::writeFile($file, $toFile); }
function finish() { if (!getopt('d', ['delete'])) { // generated with TEMPORARY keyword. Manual deletion is not needed CLISetup::log('generated dbc_* - tables kept available', CLISetup::LOG_INFO); } // send "i'm in use @" - ping $u = !empty($_SERVER['USER']) ? $_SERVER['USER'] : '******'; $s = !empty($_SERVER['SSH_CONNECTION']) ? explode(' ', $_SERVER['SSH_CONNECTION'])[2] : 'NULL'; if ($h = @fopen('http://aowow.meedns.com/ref?u=' . $u . '&s=' . $s, 'r')) { fclose($h); } die("\n"); }
function update() { list($date, $part) = array_values(DB::Aowow()->selectRow('SELECT `date`, `part` FROM ?_dbversion')); CLISetup::log('checking sql updates'); $nFiles = 0; foreach (glob('setup/updates/*.sql') as $file) { $pi = pathinfo($file); list($fDate, $fPart) = explode('_', $pi['filename']); if ($date && $fDate < $date) { continue; } else { if ($part && $date && $fDate == $date && $fPart <= $part) { continue; } } $nFiles++; $updQuery = ''; $nQuerys = 0; foreach (file($file) as $line) { // skip comments if (substr($line, 0, 2) == '--' || $line == '') { continue; } $updQuery .= $line; // semicolon at the end -> end of query if (substr(trim($line), -1, 1) == ';') { if (DB::Aowow()->query($updQuery)) { $nQuerys++; } $updQuery = ''; } } DB::Aowow()->query('UPDATE ?_dbversion SET `date`= ?d, `part` = ?d', $fDate, $fPart); CLISetup::log(' -> ' . date('d.m.Y', $fDate) . ' #' . $fPart . ': ' . $nQuerys . ' queries applied', CLISetup::LOG_OK); } CLISetup::log($nFiles ? 'applied ' . $nFiles . ' update(s)' : 'db is already up to date', CLISetup::LOG_OK); // fetch sql/build after applying updates, as they may contain sync-prompts list($sql, $build) = array_values(DB::Aowow()->selectRow('SELECT `sql`, `build` FROM ?_dbversion')); sleep(1); $sql = trim($sql) ? array_unique(explode(' ', trim($sql))) : []; $build = trim($build) ? array_unique(explode(' ', trim($build))) : []; if ($sql) { CLISetup::log('The following table(s) require syncing: ' . implode(', ', $sql)); } if ($build) { CLISetup::log('The following file(s) require syncing: ' . implode(', ', $build)); } return [$sql, $build]; }
function update() { $createQuery = "\r\n CREATE TABLE `aowow_dbversion` (\r\n `date` INT(10) UNSIGNED NOT NULL DEFAULT '0',\r\n `part` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0'\r\n ) ENGINE=MyISAM"; $date = $part = 0; if (!DB::Aowow()->selectCell('SHOW TABLES LIKE "%dbversion"')) { DB::Aowow()->query($createQuery); DB::Aowow()->query('INSERT INTO ?_dbversion VALUES (0, 0)'); } else { list($date, $part) = array_values(DB::Aowow()->selectRow('SELECT `date`, `part` FROM ?_dbversion')); } CLISetup::log('checking sql updates'); $nFiles = 0; foreach (glob('setup/updates/*.sql') as $file) { $pi = pathinfo($file); list($fDate, $fPart) = explode('_', $pi['filename']); if ($date && $fDate < $date) { continue; } else { if ($part && $date && $fDate == $date && $fPart <= $part) { continue; } } $nFiles++; $updQuery = ''; $nQuerys = 0; foreach (file($file) as $line) { // skip comments if (substr($line, 0, 2) == '--' || $line == '') { continue; } $updQuery .= $line; // semicolon at the end -> end of query if (substr(trim($line), -1, 1) == ';') { if (DB::Aowow()->query($updQuery)) { $nQuerys++; } $updQuery = ''; } } DB::Aowow()->query('UPDATE ?_dbversion SET `date`= ?d, `part` = ?d', $fDate, $fPart); CLISetup::log(' -> ' . date('d.m.Y', $fDate) . ' #' . $fPart . ': ' . $nQuerys . ' queries applied', CLISetup::LOG_OK); } CLISetup::log($nFiles ? 'applied ' . $nFiles . ' update(s)' : 'db is already up to date', CLISetup::LOG_OK); }
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 account() { $fields = array('name' => ['Username', false], 'pass1' => ['Enter Password', true], 'pass2' => ['Confirm Password', true]); if (CLISetup::readInput($fields)) { CLISetup::log(); if (!User::isValidName($fields['name'], $e)) { CLISetup::log(Lang::account($e == 1 ? 'errNameLength' : 'errNameChars'), CLISetup::LOG_ERROR); } else { if (!User::isValidPass($fields['pass1'], $e)) { CLISetup::log(Lang::account($e == 1 ? 'errPassLength' : 'errPassChars'), CLISetup::LOG_ERROR); } else { if ($fields['pass1'] != $fields['pass2']) { CLISetup::log(Lang::account('passMismatch'), CLISetup::LOG_ERROR); } else { if ($_ = DB::Aowow()->SelectCell('SELECT 1 FROM ?_account WHERE user = ? AND (status <> ?d OR (status = ?d AND statusTimer > UNIX_TIMESTAMP()))', $fields['name'], ACC_STATUS_NEW, ACC_STATUS_NEW)) { CLISetup::log(Lang::account('nameInUse'), CLISetup::LOG_ERROR); } else { // write to db $ok = DB::Aowow()->query('REPLACE INTO ?_account (user, passHash, displayName, joindate, email, allowExpire, userGroups, userPerms) VALUES (?, ?, ?, UNIX_TIMESTAMP(), ?, 0, ?d, 1)', $fields['name'], User::hashCrypt($fields['pass1']), Util::ucFirst($fields['name']), CFG_CONTACT_EMAIL, U_GROUP_ADMIN); if ($ok) { $newId = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE user = ?', $fields['name']); Util::gainSiteReputation($newId, SITEREP_ACTION_REGISTER); CLISetup::log("account " . $fields['name'] . " created successfully", CLISetup::LOG_OK); } else { // something went wrong CLISetup::log(Lang::main('intError'), CLISetup::LOG_ERROR); } } } } } } else { CLISetup::log(); CLISetup::log("account creation aborted", CLISetup::LOG_WARN); } }
function currencies(array $ids = []) { if (!$ids) { DB::Aowow()->query('REPLACE INTO ?_currencies (id, category, itemId) SELECT Id, category, itemId FROM dbc_currencytypes'); } $moneyItems = DB::Aowow()->selectCol('SELECT id AS ARRAY_KEY, itemId FROM dbc_currencytypes{ WHERE id IN (?a)}', $ids ?: DBSIMPLE_SKIP); // apply names $moneyNames = DB::World()->select('SELECT it.entry AS ARRAY_KEY, name AS name_loc0, name_loc2, name_loc3, name_loc6, name_loc8 FROM item_template it LEFT JOIN locales_item li ON li.entry = it.entry WHERE it.entry IN (?a)', $moneyItems); foreach ($moneyItems as $cId => $itemId) { if (!empty($moneyNames[$itemId])) { $strings = $moneyNames[$itemId]; } else { CLISetup::log('item #' . $itemId . ' required by currency #' . $cId . ' not in item_template', CLISetup::LOG_WARN); $strings = ['name_loc0' => 'Item #' . $itemId . ' not in DB', 'iconId' => -1240, 'cuFlags' => CUSTOM_EXCLUDE_FOR_LISTVIEW, 'category' => 3]; } DB::Aowow()->query('UPDATE ?_currencies SET ?a WHERE itemId = ?d', $strings, $itemId); } // apply icons $displayIds = DB::World()->selectCol('SELECT entry AS ARRAY_KEY, displayid FROM item_template WHERE entry IN (?a)', $moneyItems); foreach ($displayIds as $itemId => $iconId) { DB::Aowow()->query('UPDATE ?_currencies SET iconId = ?d WHERE itemId = ?d', -$iconId, $itemId); } return true; }
function objects(array $ids = []) { $baseQuery = ' SELECT go.entry, `type`, IF(`type` = 2, -2, -- quests 1 IF(`type` = 8 AND Data0 IN (1, 2, 3, 4, 1552), -6, -- tools IF(`type` = 3 AND IFNULL(gqi.ItemId, 0) <> 0, -2, -- quests 2 IF(`type` IN (3, 9, 25), `type`, 0)))), -- regular chests, books, pools 0 AS event, -- linked worldevent displayId, go.name, gtl2.`name` AS name_loc2, gtl3.`name` AS name_loc3, gtl6.`name` AS name_loc6, gtl8.`name` AS name_loc8, faction, flags, 0 AS cuFlags, -- custom Flags IF(`type` IN (3, 25), Data1, 0), -- lootId IF(`type` IN (2, 3, 6, 10, 13, 24, 26), Data0, IF(`type` IN (0, 1), Data1, 0)), -- lockId 0 AS reqSkill, -- reqSkill IF(`type` = 9, Data0, IF(`type` = 10, Data7, 0)), -- pageTextId IF(`type` = 1, Data3, -- linkedTrapIds IF(`type` = 3, Data7, IF(`type` = 10, Data12, IF(`type` = 8, Data2, 0)))), IF(`type` = 5, Data5, -- reqQuest IF(`type` = 3, Data8, IF(`type` = 10, Data1, IF(`type` = 8, Data4, 0)))), IF(`type` = 8, Data0, 0), -- spellFocusId IF(`type` = 10, Data10, -- onUseSpell IF(`type` IN (18, 24), Data1, IF(`type` = 26, Data2, IF(`type` = 22, Data0, 0)))), IF(`type` = 18, Data4, 0), -- onSuccessSpell IF(`type` = 18, Data2, IF(`type` = 24, Data3, 0)), -- auraSpell IF(`type` = 30, Data2, IF(`type` = 24, Data4, IF(`type` = 6, Data3, 0))), -- triggeredSpell IF(`type` = 29, CONCAT_WS(" ", Data14, Data15, Data16, Data17, Data0), -- miscInfo: capturePoint IF(`type` = 3, CONCAT_WS(" ", Data4, Data5, Data2), -- miscInfo: loot v IF(`type` = 25, CONCAT_WS(" ", Data2, Data3, 0), IF(`type` = 23, CONCAT_WS(" ", Data0, Data1, Data2), "")))), -- miscInfo: meetingStone IF(ScriptName <> "", ScriptName, AIName) FROM gameobject_template go LEFT JOIN gameobject_template_locale gtl2 ON go.entry = gtl2.entry AND gtl2.`locale` = "frFR" LEFT JOIN gameobject_template_locale gtl3 ON go.entry = gtl3.entry AND gtl3.`locale` = "deDE" LEFT JOIN gameobject_template_locale gtl6 ON go.entry = gtl6.entry AND gtl6.`locale` = "esES" LEFT JOIN gameobject_template_locale gtl8 ON go.entry = gtl8.entry AND gtl8.`locale` = "ruRU" LEFT JOIN gameobject_questitem gqi ON gqi.GameObjectEntry = go.entry { WHERE go.entry IN (?a) } GROUP BY go.entry LIMIT ?d, ?d'; $updateQuery = ' UPDATE ?_objects o LEFT JOIN dbc_lock l ON l.id = IF(o.`type` = 3, lockId, null) SET typeCat = IF(`type` = 3 AND (l.properties1 = 1 OR l.properties2 = 1), -5, -- footlocker IF(`type` = 3 AND (l.properties1 = 2), -3, -- herb IF(`type` = 3 AND (l.properties1 = 3), -4, typeCat))), -- ore reqSkill = IF(`type` = 3 AND l.properties1 IN (1, 2, 3), IF(l.reqSkill1 > 1, l.reqSkill1, 1), IF(`type` = 3 AND l.properties2 = 1, IF(l.reqSkill2 > 1, l.reqSkill2, 1), 0)) { WHERE o.id IN (?a) }'; $offset = 0; while ($objects = DB::World()->select($baseQuery, $ids ?: DBSIMPLE_SKIP, $offset, SqlGen::$stepSize)) { CLISetup::log(' * sets ' . ($offset + 1) . ' - ' . ($offset + count($objects))); $offset += SqlGen::$stepSize; foreach ($objects as $o) { DB::Aowow()->query('REPLACE INTO ?_objects VALUES (?a)', array_values($o)); } } // apply typeCat and reqSkill depending on locks DB::Aowow()->query($updateQuery, $ids ?: DBSIMPLE_SKIP); return true; }
function firstrun($resume) { require_once 'setup/tools/sqlGen.class.php'; require_once 'setup/tools/fileGen.class.php'; SqlGen::init(true); FileGen::init(true); /****************/ /* define steps */ /****************/ $steps = array(['dbconfig', null, 'testDB', 'Please enter your database credentials.', 'could not establish connection to:'], ['siteconfig', null, 'testSelf', 'SITE_HOST and STATIC_HOST ' . CLISetup::bold('must') . ' be set. Also enable FORCE_SSL if needed. You may also want to change other variables such as NAME, NAME_SHORT OR LOCALES.', 'could not access:'], ['SqlGen::generate', 'achievementcategory', null, null, null], ['SqlGen::generate', 'achievementcriteria', null, null, null], ['SqlGen::generate', 'glyphproperties', null, null, null], ['SqlGen::generate', 'itemenchantment', null, null, null], ['SqlGen::generate', 'itemenchantmentcondition', null, null, null], ['SqlGen::generate', 'itemextendedcost', null, null, null], ['SqlGen::generate', 'itemlimitcategory', null, null, null], ['SqlGen::generate', 'itemrandomproppoints', null, null, null], ['SqlGen::generate', 'lock', null, null, null], ['SqlGen::generate', 'mailtemplate', null, null, null], ['SqlGen::generate', 'scalingstatdistribution', null, null, null], ['SqlGen::generate', 'scalingstatvalues', null, null, null], ['SqlGen::generate', 'spellfocusobject', null, null, null], ['SqlGen::generate', 'spellrange', null, null, null], ['SqlGen::generate', 'spellvariables', null, null, null], ['SqlGen::generate', 'totemcategory', null, null, null], ['SqlGen::generate', 'classes', null, null, null], ['SqlGen::generate', 'factions', null, null, null], ['SqlGen::generate', 'factiontemplate', null, null, null], ['SqlGen::generate', 'holidays', null, null, null], ['SqlGen::generate', 'icons', null, null, null], ['SqlGen::generate', 'itemrandomenchant', null, null, null], ['SqlGen::generate', 'races', null, null, null], ['SqlGen::generate', 'shapeshiftforms', null, null, null], ['SqlGen::generate', 'skillline', null, null, null], ['SqlGen::generate', 'achievement', null, null, null], ['SqlGen::generate', 'creature', null, null, null], ['SqlGen::generate', 'currencies', null, null, null], ['SqlGen::generate', 'events', null, null, null], ['SqlGen::generate', 'objects', null, null, null], ['SqlGen::generate', 'pet', null, null, null], ['SqlGen::generate', 'quests', null, null, null], ['SqlGen::generate', 'quests_startend', null, null, null], ['SqlGen::generate', 'spell', null, null, null], ['SqlGen::generate', 'spelldifficulty', null, null, null], ['SqlGen::generate', 'taxi', null, null, null], ['SqlGen::generate', 'titles', null, null, null], ['SqlGen::generate', 'items', null, null, null], ['FileGen::generate', 'complexImg', null, null, null], ['SqlGen::generate', 'spawns', null, null, null], ['SqlGen::generate', 'zones', null, null, null], ['SqlGen::generate', 'itemset', null, null, null], ['SqlGen::generate', 'item_stats', null, null, null], ['SqlGen::generate', 'source', null, null, null], ['FileGen::generate', 'searchplugin', null, null, null], ['FileGen::generate', 'power', null, null, null], ['FileGen::generate', 'searchboxScript', null, null, null], ['FileGen::generate', 'demo', null, null, null], ['FileGen::generate', 'searchboxBody', null, null, null], ['FileGen::generate', 'realmMenu', null, null, null], ['FileGen::generate', 'locales', null, null, null], ['FileGen::generate', 'itemScaling', null, null, null], ['FileGen::generate', 'realms', null, null, null], ['FileGen::generate', 'statistics', null, null, null], ['FileGen::generate', 'simpleImg', null, null, null], ['FileGen::generate', 'talents', null, null, null], ['FileGen::generate', 'pets', null, null, null], ['FileGen::generate', 'talentIcons', null, null, null], ['FileGen::generate', 'glyphs', null, null, null], ['FileGen::generate', 'itemsets', null, null, null], ['FileGen::generate', 'enchants', null, null, null], ['FileGen::generate', 'gems', null, null, null], ['FileGen::generate', 'profiler', null, null, null], ['FileGen::generate', 'statistics', null, null, null], ['FileGen::generate', 'statistics', null, null, null], ['update', null, null, null, null], ['account', null, 'testAcc', 'Please create your admin account.', 'There is no user with administrator priviledges in the DB.'], ['endSetup', null, null, null, null]); /**********/ /* helper */ /**********/ $saveProgress = function ($nStep) { $h = fopen('cache/firstrun', 'w'); fwrite($h, AOWOW_REVISION . "\n" . ($nStep + 1) . "\n"); fclose($h); }; $testDB = function (&$error) { require 'config/config.php'; $error = []; foreach (['world', 'aowow', 'auth'] as $what) { if ($what == 'auth' && (empty($AoWoWconf['auth']) || empty($AoWoWconf['auth']['host']))) { continue; } if ($link = @mysqli_connect($AoWoWconf[$what]['host'], $AoWoWconf[$what]['user'], $AoWoWconf[$what]['pass'], $AoWoWconf[$what]['db'])) { mysqli_close($link); } else { $error[] = ' * ' . $what . ': ' . '[' . mysqli_connect_errno() . '] ' . mysqli_connect_error(); } } return empty($error); }; $testSelf = function (&$error) { $error = []; $test = function ($url, &$rCode) { $res = get_headers($url, true); if (preg_match("/HTTP\\/[0-9\\.]+\\s+([0-9]+)/", $res[0], $m)) { $rCode = $m[1]; return $m[1] == 200; } $rCode = 0; return false; }; $res = DB::Aowow()->selectCol('SELECT `key` AS ARRAY_KEY, value FROM ?_config WHERE `key` IN ("site_host", "static_host", "force_ssl")'); $prot = $res['force_ssl'] ? 'https://' : 'http://'; if ($res['site_host']) { if (!$test($prot . $res['site_host'] . '/README', $resp)) { $error[] = ' * could not access ' . $prot . $res['site_host'] . '/README [' . $resp . ']'; } } else { $error[] = ' * SITE_HOST is empty'; } if ($res['static_host']) { if (!$test($prot . $res['static_host'] . '/css/aowow.css', $resp)) { $error[] = ' * could not access ' . $prot . $res['static_host'] . '/css/aowow.css [' . $resp . ']'; } } else { $error[] = ' * STATIC_HOST is empty'; } return empty($error); }; $testAcc = function (&$error) { $error = []; return !!DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE userPerms = 1'); }; function endSetup() { return DB::Aowow()->query('UPDATE ?_config SET value = 0 WHERE `key` = "maintenance"'); } /********************/ /* get current step */ /********************/ $startStep = 0; if ($resume) { if (file_exists('cache/firstrun')) { $rows = file('cache/firstrun'); if ((int) $rows[0] == AOWOW_REVISION) { $startStep = (int) $rows[1]; } else { CLISetup::log('firstrun info is outdated! Starting from scratch.', CLISetup::LOG_WARN); } } if (!$startStep) { CLISetup::log('no usable info found.', CLISetup::LOG_WARN); $inp = ['x' => ['start from scratch? (y/n)', true, '/y|n/i']]; if (!CLISetup::readInput($inp, true) || !$inp || strtolower($inp['x']) == 'n') { CLISetup::log(); return; } CLISetup::log(); } else { CLISetup::log('Resuming setup from step ' . $startStep); sleep(1); } } /*******/ /* run */ /*******/ foreach ($steps as $idx => $step) { if ($startStep > $idx) { continue; } if (!strpos($step[0], '::') && !is_callable($step[0])) { require_once 'setup/tools/clisetup/' . $step[0] . '.func.php'; } if ($step[3]) { CLISetup::log($step[3]); $inp = ['x' => ['Press any key to continue', true]]; if (!CLISetup::readInput($inp, true)) { // we don't actually care about the input return; } } while (true) { $res = call_user_func($step[0], $step[1]); // check script result if ($step[2]) { if (!${$step}[2]($errors)) { CLISetup::log($step[4], CLISetup::LOG_ERROR); foreach ($errors as $e) { CLISetup::log($e); } } else { $saveProgress($idx); break; } } else { if ($res !== false) { $saveProgress($idx); break; } } $inp = ['x' => ['[' . CLISetup::bold('c') . ']ontinue anyway? [' . CLISetup::bold('r') . ']etry? [' . CLISetup::bold('a') . ']bort?', true, '/c|r|a/i']]; if (CLISetup::readInput($inp, true) && $inp) { switch (strtolower($inp['x'])) { case 'c': $saveProgress($idx); break 2; case 'r': CLISetup::log(); break; case 'a': CLISetup::log(); return; } } else { CLISetup::log(); return; } } } unlink('cache/firstrun'); CLISetup::log('setup finished', CLISetup::LOG_OK); }
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; }
public static function generate($tableName, array $updateIds = []) { if (!isset(self::$tables[$tableName])) { CLISetup::log('SqlGen::generate - invalid table given', CLISetup::LOG_ERROR); return false; } if (!empty(self::$tables[$tableName][0])) { $tbl = self::$tables[$tableName]; // shorthand CLISetup::log('SqlGen::generate() - copying ' . $tbl[0] . '.dbc into aowow_' . $tableName); $dbc = new DBC($tbl[0], CLISetup::$tmpDBC); if ($dbc->error) { return false; } $dbcData = $dbc->readArbitrary($tbl[1]); foreach ($dbcData as $row) { DB::Aowow()->query('REPLACE INTO ?_' . $tableName . ' (?#) VALUES (?a)', array_keys($row), array_values($row)); } return !!$dbcData; } else { if (file_exists('setup/tools/sqlgen/' . $tableName . '.func.php')) { $customData = $reqDBC = []; CLISetup::log('SqlGen::generate() - filling aowow_' . $tableName . ' with data'); require_once 'setup/tools/sqlgen/' . $tableName . '.func.php'; if (function_exists($tableName)) { // check for required auxiliary DBC files foreach ($reqDBC as $req) { if (!CLISetup::loadDBC($req)) { return false; } } $success = $tableName($updateIds); // apply post generator custom data foreach ($customData as $id => $data) { if ($data) { DB::Aowow()->query('UPDATE ?_' . $tableName . ' SET ?a WHERE id = ?d', $data, $id); } } } else { CLISetup::log(' - subscript \'' . $tableName . '\' not defined in included file', CLISetup::LOG_ERROR); } return $success; } else { CLISetup::log(sprintf(ERR_MISSING_INCL, $tableName, 'setup/tools/sqlgen/' . $tableName . '.func.php'), CLISetup::LOG_ERROR); } } }
function spell() { $ssQuery = ' SELECT Id AS ARRAY_KEY, Id, 0 AS category, Dispel, Mechanic, Attributes, AttributesEx, AttributesEx2, AttributesEx3, AttributesEx4, AttributesEx5, AttributesEx6, AttributesEx7, Stances, StancesNot, 0 AS spellFocus, CastingTimeIndex, 0 AS recoveryTime, 0 AS recoveryTimeCategory, ProcChance, ProcCharges, MaxLevel, BaseLevel, SpellLevel, DurationIndex, 0 AS powerType, 0 AS powerCost, 0 AS powerCostPerLevel, 0 AS powerPerSecond, 0 AS powerPerSecondPerLevel, RangeIndex, StackAmount, 0 AS tool1, 0 AS tool2, 0 AS reagent1, 0 AS reagent2, 0 AS reagent3, 0 AS reagent4, 0 AS reagent5, 0 AS reagent6, 0 AS reagent7, 0 AS reagent8, 0 AS reagentCount1, 0 AS reagentCount2, 0 AS reagentCount3, 0 AS reagentCount4, 0 AS reagentCount5, 0 AS reagentCount6, 0 AS reagentCount7, 0 AS reagentCount8, EquippedItemClass, EquippedItemSubClassMask, EquippedItemInventoryTypeMask, Effect1, Effect2, Effect3, EffectDieSides1, EffectDieSides2, EffectDieSides3, EffectRealPointsPerLevel1, EffectRealPointsPerLevel2, EffectRealPointsPerLevel3, EffectBasePoints1, EffectBasePoints2, EffectBasePoints3, EffectMechanic1, EffectMechanic2, EffectMechanic3, EffectImplicitTargetA1, EffectImplicitTargetA2, EffectImplicitTargetA3, EffectImplicitTargetB1, EffectImplicitTargetB2, EffectImplicitTargetB3, EffectRadiusIndex1, EffectRadiusIndex2, EffectRadiusIndex3, EffectApplyAuraName1, EffectApplyAuraName2, EffectApplyAuraName3, EffectAmplitude1, EffectAmplitude2, EffectAmplitude3, EffectMultipleValue1, EffectMultipleValue2, EffectMultipleValue3, 0 AS effect1ChainTarget, 0 AS effect2ChainTarget, 0 AS effect3ChainTarget, EffectItemType1, EffectItemType2, EffectItemType3, EffectMiscValue1, EffectMiscValue2, EffectMiscValue3, EffectMiscValueB1, EffectMiscValueB2, EffectMiscValueB3, EffectTriggerSpell1, EffectTriggerSpell2, EffectTriggerSpell3, 0 AS effect1PointsPerComboPoint, 0 AS effect2PointsPerComboPoint, 0 AS effect3PointsPerComboPoint, EffectSpellClassMaskA1, EffectSpellClassMaskA2, EffectSpellClassMaskA3, EffectSpellClassMaskB1, EffectSpellClassMaskB2, EffectSpellClassMaskB3, EffectSpellClassMaskC1, EffectSpellClassMaskC2, EffectSpellClassMaskC3, 0 AS iconId, 0 AS iconIdActive, CONCAT("Serverside - ",Comment) AS name_loc0,CONCAT("Serverside - ",Comment) AS name_loc2,CONCAT("Serverside - ",Comment) AS name_loc3,CONCAT("Serverside - ",Comment) AS name_loc4,CONCAT("Serverside - ",Comment) AS name_loc6,CONCAT("Serverside - ",Comment) AS name_loc8, "" AS rank_loc0, "" AS rank_loc2, "" AS rank_loc3, "" AS rank_loc4, "" AS rank_loc6, "" AS rank_loc8, "" AS description_loc0, "" AS description_loc2, "" AS description_loc3, "" AS description_loc4, "" AS description_loc6, "" AS description_loc8, "" AS buff_loc0, "" AS buff_loc2, "" AS buff_loc3, "" AS buff_loc4, "" AS buff_loc6, "" AS buff_loc8, 0 AS powerCostPercent, 0 AS startRecoveryCategory, 0 AS startRecoveryTime, MaxTargetLevel, SpellFamilyName, SpellFamilyFlags1, SpellFamilyFlags2, SpellFamilyFlags3, MaxAffectedTargets, DmgClass, DmgMultiplier1, DmgMultiplier2, DmgMultiplier3, 0 AS toolCategory1, 0 AS toolCategory2, SchoolMask, 0 AS runeCostId, 0 AS powerDisplayId, 0 AS effect1BonusMultiplier, 0 AS effect2BonusMultiplier, 0 AS effect3BonusMultiplier, 0 AS spellDescriptionVariable, 0 AS spellDifficulty FROM spell_dbc LIMIT ?d, ?d'; $baseQuery = ' SELECT s.Id, category, dispelType, mechanic, attributes0, attributes1, attributes2, attributes3, attributes4, attributes5, attributes6, attributes7, 0 AS cuFlags, 0 AS typeCat, stanceMask, stanceMaskNot, spellFocus, IFNULL(sct.baseTime, 0) AS castTime, recoveryTime, recoveryTimeCategory, startRecoveryTime, startRecoveryCategory, procChance, procCharges, 0 AS procCustom, 0 AS procCooldown, maxLevel, baseLevel, spellLevel, 0 AS talentLevel, IF (sd.baseTime <> -1, ABS(sd.baseTime), -1) AS duration, IF (powerDisplayId, -powerDisplayId, powerType) AS powerType, powerCost, powerCostPerLevel, powerCostPercent, powerPerSecond, powerPerSecondPerLevel, IFNULL (src.runicPowerGain, 0) AS powerGainRunicPower, IF (src.Id IS NULL, 0, (src.costBlood << 8) | (src.costUnholy << 4) | src.costFrost) AS powerCostRunes, rangeId, stackAmount, tool1, tool2, toolCategory1, toolCategory2, reagent1, reagent2, reagent3, reagent4, reagent5, reagent6, reagent7, reagent8, reagentCount1, reagentCount2, reagentCount3, reagentCount4, reagentCount5, reagentCount6, reagentCount7, reagentCount8, equippedItemClass, equippedItemSubClassMask, equippedItemInventoryTypeMask, effect1Id, effect2Id, effect3Id, effect1DieSides, effect2DieSides, effect3DieSides, effect1RealPointsPerLevel, effect2RealPointsPerLevel, effect3RealPointsPerLevel, effect1BasePoints, effect2BasePoints, effect3BasePoints, effect1Mechanic, effect2Mechanic, effect3Mechanic, effect1ImplicitTargetA, effect2ImplicitTargetA, effect3ImplicitTargetA, effect1ImplicitTargetB, effect2ImplicitTargetB, effect3ImplicitTargetB, IFNULL (sr1.radiusMin, 0) AS effect1RadiusMin, IFNULL (sr1.radiusMax, 0) AS effect1RadiusMax, IFNULL (sr2.radiusMin, 0) AS effect2RadiusMin, IFNULL (sr2.radiusMax, 0) AS effect2RadiusMax, IFNULL (sr3.radiusMin, 0) AS effect3RadiusMin, IFNULL (sr3.radiusMax, 0) AS effect3RadiusMax, effect1AuraId, effect2AuraId, effect3AuraId, effect1Periode, effect2Periode, effect3Periode, effect1ValueMultiplier, effect2ValueMultiplier, effect3ValueMultiplier, effect1ChainTarget, effect2ChainTarget, effect3ChainTarget, effect1CreateItemId, effect2CreateItemId, effect3CreateItemId, effect1MiscValue, effect2MiscValue, effect3MiscValue, effect1MiscValueB, effect2MiscValueB, effect3MiscValueB, effect1TriggerSpell, effect2TriggerSpell, effect3TriggerSpell, effect1PointsPerComboPoint, effect2PointsPerComboPoint, effect3PointsPerComboPoint, effect1SpellClassMaskA, effect2SpellClassMaskA, effect3SpellClassMaskA, effect1SpellClassMaskB, effect2SpellClassMaskB, effect3SpellClassMaskB, effect1SpellClassMaskC, effect2SpellClassMaskC, effect3SpellClassMaskC, effect1DamageMultiplier, effect2DamageMultiplier, effect3DamageMultiplier, effect1BonusMultiplier, effect2BonusMultiplier, effect3BonusMultiplier, iconId, 0 AS iconIdAlt, 0 AS rankId, name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8, rank_loc0, rank_loc2, rank_loc3, rank_loc4, rank_loc6, rank_loc8, description_loc0, description_loc2, description_loc3, description_loc4, description_loc6, description_loc8, buff_loc0, buff_loc2, buff_loc3, buff_loc4, buff_loc6, buff_loc8, maxTargetLevel, spellFamilyId, spellFamilyFlags1, spellFamilyFlags2, spellFamilyFlags3, maxAffectedTargets, damageClass, 0 AS skillLine1, 0 AS skillLine2OrMask, 0 AS reqRaceMask, 0 AS reqClassMask, 0 AS reqSpellId, 0 AS reqSkillLevel, 0 AS learnedAt, 0 AS skillLevelGrey, 0 AS skillLevelYellow, schoolMask, spellDescriptionVariable, 0 AS trainingCost FROM dbc_spell s LEFT JOIN dbc_spellcasttimes sct ON s.castTimeId = sct.Id LEFT JOIN dbc_spellrunecost src ON s.runeCostId = src.Id LEFT JOIN dbc_spellduration sd ON s.durationId = sd.Id LEFT JOIN dbc_spellradius sr1 ON s.effect1RadiusId = sr1.Id LEFT JOIN dbc_spellradius sr2 ON s.effect2RadiusId = sr2.Id LEFT JOIN dbc_spellradius sr3 ON s.effect3RadiusId = sr3.Id LIMIT ?d, ?d'; $serverside = []; // merge serverside spells into dbc_spell (should not affect other scripts) $offset = 0; CLISetup::log(' - merging serverside spells into spell.dbc'); while ($spells = DB::World()->select($ssQuery, $offset, SqlGen::$stepSize)) { CLISetup::log(' * sets ' . ($offset + 1) . ' - ' . ($offset + count($spells))); $offset += SqlGen::$stepSize; foreach ($spells as $id => $spell) { $serverside[] = $id; DB::Aowow()->query('REPLACE INTO dbc_spell VALUES (?a)', array_values($spell)); } } // merge everything into aowow_spell $offset = 0; CLISetup::log(' - filling aowow_spell'); while ($spells = DB::Aowow()->select($baseQuery, $offset, SqlGen::$stepSize)) { CLISetup::log(' * sets ' . ($offset + 1) . ' - ' . ($offset + count($spells))); $offset += SqlGen::$stepSize; foreach ($spells as $spell) { DB::Aowow()->query('REPLACE INTO ?_spell VALUES (?a)', array_values($spell)); } } // apply flag: CUSTOM_SERVERSIDE if ($serverside) { DB::Aowow()->query('UPDATE ?_spell SET cuFlags = cuFlags | ?d WHERE id IN (?a)', CUSTOM_SERVERSIDE, $serverside); } // apply flag: CUSTOM_DISABLED if ($disables = DB::World()->selectCol('SELECT entry FROM disables WHERE sourceType = 0 AND flags & 0xD')) { // 0xD: players (0x1), pets (0x4), general (0x8) DB::Aowow()->query('UPDATE ?_spell SET cuFlags = cuFlags | ?d WHERE id IN (?a)', CUSTOM_DISABLED, $disables); } // apply spell ranks (can't use skilllineability.dbc, as it does not contain ranks for non-player/pet spells) $ranks = DB::World()->selectCol('SELECT first_spell_id AS ARRAY_KEY, spell_id AS ARRAY_KEY2, rank FROM spell_ranks'); foreach ($ranks as $firstSpell => $sets) { // apply flag: SPELL_CU_FIRST_RANK DB::Aowow()->query('UPDATE ?_spell SET cuFlags = cuFlags | ?d WHERE id = ?d', SPELL_CU_FIRST_RANK, $firstSpell); foreach ($sets as $spell => $rank) { DB::Aowow()->query('UPDATE ?_spell SET rankNo = ?d WHERE id = ?d', $rank, $spell); } // apply flag: SPELL_CU_LAST_RANK end($sets); DB::Aowow()->query('UPDATE ?_spell SET cuFlags = cuFlags | ?d WHERE id = ?d', SPELL_CU_LAST_RANK, key($sets)); } /****** * merge SkillLineAbility into Spell ******/ /* acquireMethod ABILITY_LEARNED_ON_GET_PROFESSION_SKILL = 1, learnedAt = 1 ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL = 2 not used for now */ $results = DB::Aowow()->select('SELECT spellId AS ARRAY_KEY, Id AS ARRAY_KEY2, skillLineId, reqRaceMask, reqClassMask, reqSkillLevel, acquireMethod, skillLevelGrey, skillLevelYellow FROM dbc_skilllineability sla'); foreach ($results as $spellId => $sets) { $names = array_keys(current($sets)); $lines = []; $trainer = false; $update = array('skillLine1' => 0, 'skillLine2OrMask' => 0, 'reqRaceMask' => 0, 'reqClassMask' => 0, 'reqSkillLevel' => 0, 'skillLevelGrey' => 0, 'skillLevelYellow' => 0); foreach ($sets as $set) { $i = 0; while (isset($names[$i])) { $field = $set[$names[$i]]; switch ($names[$i]) { case 'acquireMethod': if ($field == 1) { $trainer = true; } break; case 'skillLineId': // array if (!in_array($field, $lines)) { $lines[] = $field; } break; case 'reqRaceMask': // mask // mask case 'reqClassMask': if (((int) $update[$names[$i]] & (int) $field) != $field) { (int) ($update[$names[$i]] |= (int) $field); } break; case 'reqSkillLevel': // max // max case 'skillLevelYellow': case 'skillLevelGrey': if ($update[$names[$i]] < $field) { $update[$names[$i]] = $field; } break; } $i++; } } if ($trainer) { DB::Aowow()->query('UPDATE ?_spell SET learnedAt = 1 WHERE id = ?d', $spellId); } // check skillLineId against mask switch (count($lines)) { case 2: $update['skillLine2OrMask'] = $lines[1]; case 1: $update['skillLine1'] = $lines[0]; break; default: for ($i = -count(Util::$skillLineMask); $i < 0; $i++) { foreach (Util::$skillLineMask[$i] as $k => $pair) { if (in_array($pair[1], $lines)) { $update['skillLine1'] = $i; $update['skillLine2OrMask'] |= 1 << $k; } } } } DB::Aowow()->query('UPDATE ?_spell SET ?a WHERE id = ?d', $update, $spellId); } // fill learnedAt, trainingCost from trainer if ($trainer = DB::World()->select('SELECT SpellID AS ARRAY_KEY, MIN(ReqSkillRank) AS reqSkill, MIN(MoneyCost) AS cost, COUNT(*) AS count FROM npc_trainer GROUP BY SpellID')) { $spells = DB::Aowow()->select('SELECT Id AS ARRAY_KEY, effect1Id, effect2Id, effect3Id, effect1TriggerSpell, effect2TriggerSpell, effect3TriggerSpell FROM dbc_spell WHERE Id IN (?a)', array_keys($trainer)); $links = []; // todo (med): this skips some spells (e.g. riding) foreach ($trainer as $spell => $tData) { if (!isset($spells[$spell])) { continue; } $triggered = false; $effects = $spells[$spell]; for ($i = 1; $i <= 3; $i++) { if ($effects['effect' . $i . 'Id'] != 36) { // effect: learnSpell continue; } $triggered = true; $l =& $links[$effects['effect' . $i . 'TriggerSpell']]; if (!isset($l)) { $l = [$tData['reqSkill'], $tData['cost']]; } if ($tData['reqSkill'] < $l[0]) { $l[0] = $tData['reqSkill']; } if ($tData['cost'] < $l[1]) { $l[1] = $tData['cost']; } } if (!$triggered) { $l =& $links[$spell]; if (!isset($l)) { $l = [$tData['reqSkill'], $tData['cost']]; } if ($tData['reqSkill'] < $l[0]) { $l[0] = $tData['reqSkill']; } if ($tData['cost'] < $l[1]) { $l[1] = $tData['cost']; } } } foreach ($links as $spell => $link) { DB::Aowow()->query("UPDATE ?_spell s SET s.learnedAt = ?d, s.trainingCost = ?d WHERE s.id = ?d", $link[0], $link[1], $spell); } } // fill learnedAt from recipe-items $recipes = DB::World()->selectCol('SELECT IF(spelltrigger_2 = 6, spellid_2, spellid_1) AS ARRAY_KEY, MIN(RequiredSkillRank) FROM item_template WHERE `class` = 9 AND spelltrigger_1 <> 1 AND RequiredSkillRank > 0 GROUP BY ARRAY_KEY'); foreach ($recipes as $spell => $reqSkill) { DB::Aowow()->query('UPDATE ?_spell SET learnedAt = IF(learnedAt = 0 OR learnedAt > ?d, ?d, learnedAt) WHERE id = ?d', $reqSkill, $reqSkill, $spell); } // fill learnedAt from Discovery // 61756: Northrend Inscription Research (FAST QA VERSION); // 64323: Book of Glyph Mastery (todo: get reqSkill from item [425]) // 28571 - 28576: $element Protection Potion (todo: get reqSkill from teaching spell [360]) $discovery = DB::World()->selectCol(' SELECT spellId AS ARRAY_KEY, IF(reqSpell = ?d, ?d, IF(reqSpell BETWEEN ?d AND ?d, ?d, IF(reqSkillValue, reqSkillValue, 1))) FROM skill_discovery_template WHERE reqSpell NOT IN (?a)', 64323, 425, 28571, 28576, 360, [61756]); foreach ($discovery as $spell => $reqSkill) { DB::Aowow()->query('UPDATE ?_spell SET learnedAt = ?d WHERE id = ?d', $reqSkill, $spell); } // calc reqSkill for gethering-passives (herbing, mining, skinning) (on second thought .. it is set in skilllineability >.<) $sets = DB::World()->selectCol('SELECT spell_id AS ARRAY_KEY, rank * 75 AS reqSkill FROM spell_ranks WHERE first_spell_id IN (?a)', [55428, 53120, 53125]); foreach ($sets as $spell => $reqSkill) { DB::Aowow()->query('UPDATE ?_spell SET learnedAt = ?d WHERE id = ?d', $reqSkill, $spell); } /******************/ /* talent related */ /******************/ for ($i = 1; $i < 6; $i++) { // classMask DB::Aowow()->query('UPDATE ?_spell s, dbc_talent t, dbc_talenttab tt SET s.reqClassMask = tt.classMask WHERE tt.creatureFamilyMask = 0 AND tt.id = t.tabId AND t.rank?d = s.id', $i); // talentLevel DB::Aowow()->query('UPDATE ?_spell s, dbc_talent t, dbc_talenttab tt SET s.talentLevel = (t.row * 5) + 10 + (?d * 1) WHERE tt.id = t.tabId AND tt.creatureFamilyMask = 0 AND t.rank?d = s.id', $i - 1, $i); DB::Aowow()->query('UPDATE ?_spell s, dbc_talent t, dbc_talenttab tt SET s.talentLevel = (t.row * 12) + 20 + (?d * 4) WHERE tt.id = t.tabId AND tt.creatureFamilyMask <> 0 AND t.rank?d = s.id', $i - 1, $i); } // passive talent DB::Aowow()->query('UPDATE ?_spell s, dbc_talent t SET s.cuFlags = s.cuFlags | ?d WHERE t.talentSpell = 0 AND (s.id = t.rank1 OR s.id = t.rank2 OR s.id = t.rank3 OR s.id = t.rank4 OR s.id = t.rank5)', SPELL_CU_TALENT); // spell taught by talent DB::Aowow()->query('UPDATE ?_spell s, dbc_talent t SET s.cuFlags = s.cuFlags | ?d WHERE t.talentSpell = 1 AND (s.id = t.rank1 OR s.id = t.rank2 OR s.id = t.rank3 OR s.id = t.rank4 OR s.id = t.rank5)', SPELL_CU_TALENTSPELL); /*********/ /* Other */ /*********/ // FU [FixUps] DB::Aowow()->query('UPDATE ?_spell SET reqRaceMask = ?d WHERE skillLine1 = ?d', 1 << 10, 760); // Draenai Racials DB::Aowow()->query('UPDATE ?_spell SET reqRaceMask = ?d WHERE skillLine1 = ?d', 1 << 9, 756); // Bloodelf Racials DB::Aowow()->query('UPDATE ?_spell SET reqClassMask = ?d WHERE id = ?d', 1 << 7, 30449); // Mage - Spellsteal // triggered by spell DB::Aowow()->query(' UPDATE ?_spell a JOIN ( SELECT effect1TriggerSpell as id FROM ?_spell WHERE effect1Id NOT IN (36, 57, 133) AND effect1TriggerSpell <> 0 UNION SELECT effect2TriggerSpell as id FROM ?_spell WHERE effect2Id NOT IN (36, 57, 133) AND effect2TriggerSpell <> 0 UNION SELECT effect3TriggerSpell as id FROM ?_spell WHERE effect3Id NOT IN (36, 57, 133) AND effect3TriggerSpell <> 0 ) as b SET cuFlags = cuFlags | ?d WHERE a.id = b.id', SPELL_CU_TRIGGERED); // altIcons and quality for craftSpells $itemSpells = DB::Aowow()->selectCol(' SELECT s.Id AS ARRAY_KEY, effect1CreateItemId FROM dbc_spell s LEFT JOIN dbc_talent t1 ON t1.rank1 = s.id LEFT JOIN dbc_talent t2 ON t2.rank2 = s.id LEFT JOIN dbc_talent t3 ON t3.rank3 = s.id WHERE effect1CreateItemId > 0 AND effect1Id <> 53 AND t1.id IS NULL AND t2.id IS NULL AND t3.id IS NULL '); // no enchant-spells & no talents! $itemInfo = DB::World()->select('SELECT entry AS ARRAY_KEY, displayId AS d, Quality AS q FROM item_template WHERE entry IN (?a)', $itemSpells); foreach ($itemSpells as $sId => $itemId) { if (isset($itemInfo[$itemId])) { DB::Aowow()->query('UPDATE ?_spell SET iconIdAlt = ?d, cuFlags = cuFlags | ?d WHERE id = ?d', -$itemInfo[$itemId]['d'], 7 - $itemInfo[$itemId]['q'] << 8, $sId); } } // apply specializations [trainerTemplate => reqSpell] $specs = array(201007 => 9788, 201008 => 9787, 201015 => 20222, 201016 => 20219, 201030 => 10660, 201031 => 10656, 201032 => 10658); foreach ($specs as $tt => $req) { if ($spells = DB::World()->selectCol('SELECT SpellID FROM npc_trainer WHERE ID = ?d', $tt)) { DB::Aowow()->query('UPDATE ?_spell SET reqSpellId = ?d WHERE id IN (?a)', $req, $spells); } } $itemReqs = DB::World()->selectCol('SELECT entry AS ARRAY_KEY, requiredSpell FROM item_template WHERE requiredSpell NOT IN (?a)', [0, 34090, 34091]); // not riding foreach ($itemReqs as $itemId => $req) { DB::Aowow()->query('UPDATE ?_spell SET reqSpellId = ?d WHERE skillLine1 IN (?a) AND effect1CreateItemId = ?d', $req, [164, 165, 197, 202], $itemId); } DB::Aowow()->query('UPDATE ?_spell SET reqSpellId = id WHERE id IN (?a)', [9788, 9787, 20222, 20219, 10660, 10656, 10658, 26797, 26798, 26801, 17039, 17040, 17041]); /**************/ /* Categories */ /**************/ // player talents (-2) DB::Aowow()->query('UPDATE ?_spell s, dbc_talent t SET s.typeCat = -2 WHERE t.tabId NOT IN (409, 410, 411) AND (s.Id = t.rank1 OR s.Id = t.rank2 OR s.Id = t.rank3 OR s.Id = t.rank4 OR s.Id = t.rank5)'); // pet spells (-3) DB::Aowow()->query('UPDATE ?_spell s SET s.typeCat = -3 WHERE (s.cuFlags & 0x3) = 0 AND s.skillline1 IN (?a)', array_merge(array_column(Util::$skillLineMask[-1], 1), array_column(Util::$skillLineMask[-2], 1), [270, 782], [-1, -2])); // racials (-4) DB::Aowow()->query('UPDATE ?_spell s SET s.typeCat = -4 WHERE s.skillLine1 IN (101, 124, 125, 126, 220, 733, 753, 754, 756, 760)'); // mounts (-5) DB::Aowow()->query('UPDATE ?_spell s SET s.typeCat = -5 WHERE s.effect1AuraId = 78 AND (s.skillLine1 IN (354, 594, 772, 777) OR (s.skillLine1 > 0 AND s.skillLine2OrMask = 777))'); // companions (-6) DB::Aowow()->query('UPDATE ?_spell s SET s.typeCat = -6 WHERE s.skillLine1 = 778'); // pet talents (-7) DB::Aowow()->query('UPDATE ?_spell s, dbc_talent t SET s.typeCat = -7, s.cuFlags = s.cuFlags | 0x10 WHERE t.tabId = 409 AND (s.Id = t.rank1 OR s.Id = t.rank2 OR s.Id = t.rank3)'); DB::Aowow()->query('UPDATE ?_spell s, dbc_talent t SET s.typeCat = -7, s.cuFlags = s.cuFlags | 0x08 WHERE t.tabId = 410 AND (s.Id = t.rank1 OR s.Id = t.rank2 OR s.Id = t.rank3)'); DB::Aowow()->query('UPDATE ?_spell s, dbc_talent t SET s.typeCat = -7, s.cuFlags = s.cuFlags | 0x20 WHERE t.tabId = 411 AND (s.Id = t.rank1 OR s.Id = t.rank2 OR s.Id = t.rank3)'); // internal (-9) by faaaaaar not complete DB::Aowow()->query('UPDATE ?_spell s SET s.typeCat = -9 WHERE s.skillLine1 = 769'); DB::Aowow()->query('UPDATE ?_spell s SET s.typeCat = -9 WHERE s.typeCat = 0 AND s.cuFlags = 0 AND ( s.name_loc0 LIKE "%qa%" OR s.name_loc0 LIKE "%debug%" OR s.name_loc0 LIKE "%internal%" OR s.name_loc0 LIKE "%(NYI)%" OR s.name_loc0 LIKE "%(TEST)%" OR s.name_loc0 LIKE "%(OLD)%")'); // proficiencies (-11) DB::Aowow()->query('UPDATE ?_spell s, dbc_skillline sl SET s.typeCat = -11 WHERE s.skillLine1 = sl.id AND sl.categoryId IN (6, 8, 10)'); // glyphs (-13) DB::Aowow()->query('UPDATE ?_spell s, dbc_glyphproperties gp SET s.cuFlags = s.cuFlags | IF(gp.typeFlags, ?d, ?d), s.typeCat = -13 WHERE gp.typeFlags IN (0, 1) AND gp.id = s.effect1MiscValue AND s.effect1Id = 74', SPELL_CU_GLYPH_MINOR, SPELL_CU_GLYPH_MAJOR); $glyphs = DB::World()->selectCol('SELECT it.spellid_1 AS ARRAY_KEY, it.AllowableClass FROM item_template it WHERE it.class = 16'); foreach ($glyphs as $spell => $classMask) { DB::Aowow()->query('UPDATE ?_spell s, dbc_glyphproperties gp SET s.reqClassMask = ?d WHERE gp.typeFlags IN (0, 1) AND gp.id = s.effect1MiscValue AND s.effect1Id = 74 AND s.id = ?d', $classMask, $spell); } // class Spells (7) DB::Aowow()->query('UPDATE ?_spell s, dbc_skillline sl SET s.typeCat = 7 WHERE s.typeCat = 0 AND s.skillLine1 = sl.id AND sl.categoryId = 7'); // hide some internal class stuffs DB::Aowow()->query('UPDATE ?_spell s SET s.cuFlags = ?d WHERE s.typeCat = 7 AND ( s.name_loc0 LIKE "%passive%" OR s.name_loc0 LIKE "%effect%" OR s.name_loc0 LIKE "%improved%" OR s.name_loc0 LIKE "%prototype%" OR -- can probably be extended (s.id NOT IN (47241, 59879, 59671) AND s.baseLevel <= 1 AND s.reqclassMask = 0) OR -- can probably still be extended (s.SpellFamilyId = 15 AND s.SpellDescriptionVariableId <> 84) OR -- DK: Skill Coil (s.SpellFamilyId = 10 AND s.SpellFamilyFlags2 & 0x1000000 AND s.attributes1 = 0) OR -- Paladin: Bacon of Light hmm.. Bacon.... :] (s.SpellFamilyId = 6 AND s.SpellFamilyFlags3 & 0x4000) OR -- Priest: Lolwell Renew (s.SpellFamilyId = 6 AND s.SpellFamilyFlags1 & 0x8000000 AND s.rank_loc0 <> "") OR -- Priest: Bling Bling (s.SpellFamilyId = 8 AND s.attributes0 = 0x50 AND s.attributes1 & 0x400) OR -- Rogue: Intuition (dropped Talent..? looks nice though) (s.SpellfamilyId = 11 AND s.SpellFamilyFlags1 & 3 AND s.attributes1 = 1024) OR -- Shaman: Lightning Overload procs (s.attributes0 = 0x20000000 AND s.attributes3 = 0x10000000) OR -- Master Demonologist (FamilyId = 0) s.id IN (47633, 22845, 29442, 31643, 44450, 32841, 20154, 34919, 27813, 27817, 27818, 30708, 30874, 379, 21169, 19483, 29886, 58889, 23885, 29841, 29842, 64380, 58427) -- Misc )', CUSTOM_EXCLUDE_FOR_LISTVIEW); foreach ([1, 2, 3, 4, 5, 6, 7, 8, 9, 11] as $classId) { DB::Aowow()->query(' UPDATE ?_spell s, dbc_skillline sl, dbc_skillraceclassinfo srci SET s.reqClassMask = srci.classMask WHERE s.typeCat IN (-2, 7) AND (s.attributes0 & 0x80) = 0 AND s.skillLine1 = srci.skillLine AND sl.categoryId = 7 AND srci.skillline <> 769 AND srci.skillline = sl.id AND srci.flags & 0x90 AND srci.classMask & ?d', 1 << $classId - 1); } // secondary Skills (9) DB::Aowow()->query('UPDATE ?_spell s SET s.typeCat = 9 WHERE s.typeCat = 0 AND (s.skillLine1 IN (129, 185, 356, 762) OR (s.skillLine1 > 0 AND s.skillLine2OrMask IN (129, 185, 356, 762)))'); // primary Skills (11) DB::Aowow()->query('UPDATE ?_spell s SET s.typeCat = 11 WHERE s.typeCat = 0 AND s.skillLine1 IN (164, 165, 171, 182, 186, 197, 202, 333, 393, 755, 773)'); // npc spells (-8) (run as last! .. missing from npc_scripts? "enum Spells { \s+(\w\d_)+\s+=\s(\d+) }" and "#define SPELL_(\d\w_)+\s+(\d+)") // RAID_MODE(1, 2[, 3, 4]) - macro still not considered $world = DB::World()->selectCol(' SELECT ss.action_param1 FROM smart_scripts ss WHERE ss.action_type IN (11, 75, 85, 86) UNION SELECT ct.spell1 FROM creature_template ct WHERE ct.spell1 <> 0 UNION SELECT ct.spell2 FROM creature_template ct WHERE ct.spell2 <> 0 UNION SELECT ct.spell3 FROM creature_template ct WHERE ct.spell3 <> 0 UNION SELECT ct.spell4 FROM creature_template ct WHERE ct.spell4 <> 0 UNION SELECT ct.spell5 FROM creature_template ct WHERE ct.spell5 <> 0 UNION SELECT ct.spell6 FROM creature_template ct WHERE ct.spell6 <> 0 UNION SELECT ct.spell7 FROM creature_template ct WHERE ct.spell7 <> 0 UNION SELECT ct.spell8 FROM creature_template ct WHERE ct.spell8 <> 0'); $auras = DB::World()->selectCol('SELECT cta.auras FROM creature_template_addon cta WHERE auras <> ""'); foreach ($auras as $a) { foreach (explode(' ', $a) as $spell) { $world[] = $spell; } } DB::Aowow()->query('UPDATE ?_spell s SET s.typeCat = -8 WHERE s.typeCat = 0 AND s.id In (?a)', $world); /**********/ /* Glyphs */ /**********/ // glyphSpell => affectedSpell $glyphAffects = array(63959 => 50842, 58723 => 55090, 58721 => 46584, 58711 => 52375, 54857 => 33876, 56881 => 13165, 56598 => 27101, 63871 => 1038, 55003 => 53407, 63873 => 47788, 58258 => 2983, 55535 => 52127, 55558 => 16190, 56302 => 697, 56299 => 712, 58272 => 126, 56292 => 688, 56286 => 691, 56285 => 30146, 58275 => 29893, 63941 => 1454, 56289 => 5699, 56297 => 693, 58271 => 1120, 58281 => 34428, 58397 => 23922, 63949 => 50720); $queryIcons = ' SELECT s.id, s.name_loc0, s.skillLine1 as skill, s.iconId as icon, s.typeCat * s.typeCat AS prio FROM ?_spell s WHERE [WHERE] AND (s.cuFlags & ?d) = 0 AND s.typeCat IN (0, 7, -2) -- not triggered; class spells first, talents second, unk last ORDER BY prio DESC '; $effects = DB::Aowow()->select(' SELECT s2.Id AS ARRAY_KEY, s1.Id, s1.name_loc0, s1.spellFamilyId, s1.spellFamilyFlags1, s1.spellFamilyFlags2, s1.spellFamilyFlags3, s1.effect1Id, s1.effect2Id, s1.effect3Id, s1.effect1SpellClassMaskA, s1.effect1SpellClassMaskB, s1.effect1SpellClassMaskC, s1.effect2SpellClassMaskA, s1.effect2SpellClassMaskB, s1.effect2SpellClassMaskC, s1.effect3SpellClassMaskA, s1.effect3SpellClassMaskB, s1.effect3SpellClassMaskC FROM dbc_glyphproperties gp JOIN ?_spell s1 ON s1.Id = gp.spellId JOIN ?_spell s2 ON s2.effect1MiscValue = gp.id AND s2.effect1Id = 74 WHERE gp.typeFlags IN (0, 1) -- AND s2.Id In (58271, 56297, 56289, 63941, 58275) '); foreach ($effects as $applyId => $glyphEffect) { $l = [null, 'A', 'B', 'C']; $i = 0; $icons = []; $fam = $glyphEffect['spellFamilyId']; // first: manuall replace if ($applyId == 57144) { $icons = ['skill' => 253, 'icon' => 163]; } // second: search by name and Family equality if (!$icons) { $search = !empty($glyphAffects[$applyId]) ? $glyphAffects[$applyId] : str_replace('Glyph of ', '', $glyphEffect['name_loc0']); if (is_int($search)) { $where = "?d AND s.id = ?d"; } else { $where = "s.SpellFamilyId = ?d AND s.name_loc0 LIKE ?"; } $qry = str_replace('[WHERE]', $where, $queryIcons); $icons = DB::Aowow()->selectRow($qry, $fam ?: 1, $search, SPELL_CU_TRIGGERED); } // third: match by SpellFamily affect mask while (empty($icons) && $i < 3) { $i++; $m1 = $glyphEffect['effect1SpellClassMask' . $l[$i]]; $m2 = $glyphEffect['effect2SpellClassMask' . $l[$i]]; $m3 = $glyphEffect['effect3SpellClassMask' . $l[$i]]; if ($glyphEffect['effect' . $i . 'Id'] != 6 || !$m1 && !$m2 && !$m3) { continue; } $where = "s.SpellFamilyId = ?d AND (s.SpellFamilyFlags1 & ?d OR s.SpellFamilyFlags2 & ?d OR s.SpellFamilyFlags3 & ?d)"; $icons = DB::Aowow()->selectRow(str_replace('[WHERE]', $where, $queryIcons), $fam, $m1, $m2, $m3, SPELL_CU_TRIGGERED); } if ($icons) { DB::Aowow()->query('UPDATE ?_spell s SET s.skillLine1 = ?d, s.iconIdAlt = ?d WHERE s.id = ?d', $icons['skill'], $icons['icon'], $applyId); } else { CLISetup::log('could not match ' . $glyphEffect['name_loc0'] . ' (' . $glyphEffect['Id'] . ') with affected spells', CLISetup::LOG_WARN); } } // hide unused glyphs DB::Aowow()->query('UPDATE ?_spell SET skillLine1 = 0, iconIdAlt = 0, cuFlags = cuFlags | ?d WHERE id IN (?a)', CUSTOM_EXCLUDE_FOR_LISTVIEW, [60460, 58166, 58239, 58240, 58261, 58262, 54910]); return true; }
public static function generate($key, array $updateIds = []) { $success = false; $reqDBC = []; if (file_exists('setup/tools/filegen/' . $key . '.func.php')) { require_once 'setup/tools/filegen/' . $key . '.func.php'; } else { if (empty(self::$tplFiles[$key])) { CLISetup::log(sprintf(ERR_MISSING_INCL, $key, 'setup/tools/filegen/' . $key . '.func.php', CLISetup::LOG_ERROR)); return false; } } CLISetup::log('FileGen::generate() - gathering data for ' . $key); if (!empty(self::$tplFiles[$key])) { list($file, $destPath, $deps) = self::$tplFiles[$key]; if ($content = file_get_contents(FileGen::$tplPath . $file . '.in')) { if ($dest = @fOpen($destPath . $file, "w")) { // replace constants $content = strtr($content, FileGen::$txtConstants); // check for required auxiliary DBC files foreach ($reqDBC as $req) { if (!CLISetup::loadDBC($req)) { continue 2; } } // must generate content // PH format: /*setup:<setupFunc>*/ $funcOK = true; if (preg_match_all('/\\/\\*setup:([\\w\\-_]+)\\*\\//i', $content, $m)) { foreach ($m[1] as $func) { if (function_exists($func)) { $content = str_replace('/*setup:' . $func . '*/', $func(), $content); } else { $funcOK = false; CLISetup::log('No function for was registered for placeholder ' . $func . '().', CLISetup::LOG_ERROR); if (!array_reduce(get_included_files(), function ($inArray, $itr) use($func) { return $inArray || false !== strpos($itr, $func); }, false)) { CLISetup::log('Also, expected include setup/tools/filegen/' . $name . '.func.php was not found.'); } } } } if (fWrite($dest, $content)) { CLISetup::log(sprintf(ERR_NONE, CLISetup::bold($destPath . $file)), CLISetup::LOG_OK); if ($content && $funcOK) { $success = true; } } else { CLISetup::log(sprintf(ERR_WRITE_FILE, CLISetup::bold($destPath . $file)), CLISetup::LOG_ERROR); } fClose($dest); } else { CLISetup::log(sprintf(ERR_CREATE_FILE, CLISetup::bold($destPath . $file)), CLISetup::LOG_ERROR); } } else { CLISetup::log(sprintf(ERR_READ_FILE, CLISetup::bold(FileGen::$tplPath . $file . '.in')), CLISetup::LOG_ERROR); } } else { if (!empty(self::$datasets[$key])) { if (function_exists($key)) { // check for required auxiliary DBC files foreach ($reqDBC as $req) { if (!CLISetup::loadDBC($req)) { return false; } } $success = $key($updateIds); } else { CLISetup::log(' - subscript \'' . $key . '\' not defined in included file', CLISetup::LOG_ERROR); } } } set_time_limit(FileGen::$defaultExecTime); // reset to default for the next script return $success; }
function siteconfig() { if (!DB::isConnected(DB_AOWOW)) { CLISetup::log(); CLISetup::log("database not yet set up!\n Please use --dbconfig for setup", CLISetup::LOG_WARN); return; } while (true) { CLISetup::log(); CLISetup::log('select a numerical index to use the corresponding entry'); $results = DB::Aowow()->select('SELECT *, (flags & ?d) AS php FROM ?_config ORDER BY php ASC', CON_FLAG_PHP); $hasEmpty = false; foreach ($results as $idx => $data) { if (!($data['flags'] & CON_FLAG_PHP) && $data['value'] === '') { $hasEmpty = true; } $php = $data['flags'] & CON_FLAG_PHP; $buff = "[" . CLISetup::bold($idx) . "] " . ($idx > 9 ? '' : ' ') . ($php ? ' PHP ' : ' AOWOW '); $buff .= str_pad($php ? strtolower($data['key']) : strtoupper('cfg_' . $data['key']), 35); if ($data['value'] === '') { $buff .= CLISetup::red('<empty>'); } else { $info = explode(' - ', $data['comment']); if ($data['flags'] & CON_FLAG_TYPE_BOOL) { $buff .= '[bool] ' . ($data['value'] ? '<Enabled>' : '<Disabled>'); } else { if ($data['flags'] & CON_FLAG_OPT_LIST && !empty($info[2])) { $buff .= "[opt] "; foreach (explode(', ', $info[2]) as $option) { $opt = explode(':', $option); $buff .= '[' . ($data['value'] == $opt[0] ? 'x' : ' ') . ']' . $opt[1] . ' '; } } else { if ($data['flags'] & CON_FLAG_BITMASK && !empty($info[2])) { $buff .= "[mask] "; foreach (explode(', ', $info[2]) as $option) { $opt = explode(':', $option); $buff .= '[' . ($data['value'] & 1 << $opt[0] ? 'x' : ' ') . ']' . $opt[1] . ' '; } } else { if ($data['flags'] & CON_FLAG_TYPE_STRING) { $buff .= "[str] " . $data['value']; } else { if ($data['flags'] & CON_FLAG_TYPE_FLOAT) { $buff .= "[float] " . floatVal($data['value']); } else { /* if ($data['flags'] & CON_FLAG_TYPE_INT) */ $buff .= "[int] " . intVal($data['value']); } } } } } } CLISetup::log($buff); } CLISetup::log(str_pad("[" . CLISetup::bold(count($results)) . "]", 21) . "add another php configuration"); if ($hasEmpty) { CLISetup::log(); CLISetup::log("please configure the required empty setings", CLISetup::LOG_WARN); } $inp = ['idx' => ['', false, '/\\d/']]; if (CLISetup::readInput($inp) && $inp && $inp['idx'] !== '') { // add new php setting if ($inp['idx'] == count($results)) { CLISetup::log(); CLISetup::log("Adding additional php configuration."); while (true) { $setting = array('key' => ['option name', false, '/[\\w_\\.\\-]/i'], 'val' => ['value']); if (CLISetup::readInput($setting) && $setting) { CLISetup::log(); $key = strtolower($setting['key']); if (ini_get($key) === false || ini_set($key, $setting['val']) === false) { CLISetup::log("this configuration option cannot be set", CLISetup::LOG_ERROR); sleep(1); } else { if (DB::Aowow()->selectCell('SELECT 1 FROM ?_config WHERE `flags` & ?d AND `key` = ?', CON_FLAG_PHP, $key)) { CLISetup::log("this configuration option is already in use", CLISetup::LOG_ERROR); sleep(1); } else { DB::Aowow()->query('INSERT IGNORE INTO ?_config (`key`, `value`, `flags`) VALUES (?, ?, ?d)', $key, $setting['val'], CON_FLAG_TYPE_STRING | CON_FLAG_PHP); CLISetup::log("new php configuration added", CLISetup::LOG_OK); sleep(1); } } break; } else { CLISetup::log(); CLISetup::log("edit canceled! returning to list...", CLISetup::LOG_WARN); sleep(1); break; } } } else { if ($inp['idx'] >= 0 && $inp['idx'] < count($results)) { $conf = $results[$inp['idx']]; $info = explode(' - ', $conf['comment']); $buff = ''; CLISetup::log(); $buff .= $conf['flags'] & CON_FLAG_PHP ? " PHP: " : "AOWOW: "; $buff .= $conf['flags'] & CON_FLAG_PHP ? strtolower($conf['key']) : strtoupper('cfg_' . $conf['key']); if (!empty($info[1])) { $buff .= " - " . $info[1]; } CLISetup::log($buff); $buff = "VALUE: "; if ($conf['flags'] & CON_FLAG_TYPE_BOOL) { $buff .= $conf['value'] ? '<Enabled>' : '<Disabled>'; } else { if ($conf['flags'] & CON_FLAG_OPT_LIST && !empty($info[2])) { foreach (explode(', ', $info[2]) as $option) { $opt = explode(':', $option); $buff .= '[' . ($conf['value'] == $opt[0] ? 'x' : ' ') . '] ' . $opt[1] . ' '; } } else { if ($conf['flags'] & CON_FLAG_BITMASK && !empty($info[2])) { foreach (explode(', ', $info[2]) as $option) { $opt = explode(':', $option); $buff .= '[' . ($conf['value'] & 1 << $opt[0] ? 'x' : ' ') . '] ' . $opt[1] . ' '; } } else { if ($conf['flags'] & CON_FLAG_TYPE_STRING) { $buff .= $conf['value']; } else { if ($conf['flags'] & CON_FLAG_TYPE_FLOAT) { $buff .= floatVal($conf['value']); } else { /* if ($conf['flags'] & CON_FLAG_TYPE_INT) */ $buff .= intVal($conf['value']); } } } } } CLISetup::log($buff); CLISetup::log(); CLISetup::log("[" . CLISetup::bold('E') . "]dit"); if (!($conf['flags'] & CON_FLAG_PERSISTENT)) { CLISetup::log("[" . CLISetup::bold('D') . "]elete"); } if (strstr($info[0], 'default:')) { CLISetup::log("[" . CLISetup::bold('R') . "]estore Default - " . trim(explode('default:', $info[0])[1])); } while (true) { $action = ['idx' => ['', true, '/[edr]/i']]; if (CLISetup::readInput($action, true) && $action) { switch (strtoupper($action['idx'])) { case 'E': // edit value $pattern = false; $single = false; $value = ['idx' => ['Select new value', false, &$pattern]]; if ($conf['flags'] & CON_FLAG_OPT_LIST) { $_valid = []; foreach (explode(', ', $info[2]) as $option) { $opt = explode(':', $option); $_valid[] = $opt[0]; CLISetup::log('[' . CLISetup::bold($opt[0]) . '] ' . $opt[1]); } $single = true; $pattern = '/\\d/'; $validate = function ($v) use($_valid) { return in_array($v, $_valid); }; } else { if ($conf['flags'] & CON_FLAG_BITMASK) { CLISetup::log('Bitmask: sum fields to select multiple options'); $_valid = 0x0; foreach (explode(', ', $info[2]) as $option) { $opt = explode(':', $option); $_valid |= 1 << $opt[0]; CLISetup::log('[' . CLISetup::bold(1 << $opt[0]) . ']' . str_pad('', 4 - strlen(1 << $opt[0])) . $opt[1]); } $pattern = '/\\d+/'; $validate = function ($v) use($_valid) { $v = $v & $_valid; return $v; }; } else { if ($conf['flags'] & CON_FLAG_TYPE_BOOL) { CLISetup::log('[' . CLISetup::bold(0) . '] Disabled'); CLISetup::log('[' . CLISetup::bold(1) . '] Enabled'); $single = true; $pattern = '/[01]/'; $validate = function ($v) { return true; }; } else { if ($conf['flags'] & CON_FLAG_TYPE_INT) { $validate = function ($v) { return preg_match('/^-?\\d+$/i', $v); }; } else { if ($conf['flags'] & CON_FLAG_TYPE_FLOAT) { $validate = function ($v) { return preg_match('/^-?\\d*(,|.)?\\d+$/i', $v); }; } else { // string $validate = function ($v) { return true; }; } } } } } while (true) { $use = $value; if (CLISetup::readInput($use, $single) && $use) { CLISetup::log(); if (!$validate($use['idx'])) { CLISetup::log("value not in range", CLISetup::LOG_ERROR); sleep(1); continue; } else { DB::Aowow()->query('UPDATE ?_config SET `value` = ? WHERE `key` = ?', $use['idx'], strtolower($conf['key'])); CLISetup::log("setting updated", CLISetup::LOG_OK); sleep(1); break 3; } } else { CLISetup::log("edit canceled! returning to selection...", CLISetup::LOG_WARN); sleep(1); break; } } break 2; case 'R': // restore default if (!strstr($info[0], 'default:')) { continue 2; } // @eval .. some dafault values are supplied as bitmask or the likes if (DB::Aowow()->query('UPDATE ?_config SET `value` = ? WHERE `key` = ?', @eval('return (' . trim(explode('default:', $info[0])[1]) . ');'), strtolower($conf['key']))) { CLISetup::log("default value restored", CLISetup::LOG_OK); sleep(1); } break 2; case 'D': // delete config pair if ($conf['flags'] & CON_FLAG_PERSISTENT) { continue 2; } if (DB::Aowow()->query('DELETE FROM ?_config WHERE `key` = ? AND (`flags` & ?d) = 0', strtolower($conf['key']), CON_FLAG_PERSISTENT)) { CLISetup::log("php setting deleted ['" . $conf['key'] . "': '" . $conf['value'] . "']", CLISetup::LOG_OK); sleep(1); } break 2; } } else { CLISetup::log(); CLISetup::log("edit canceled! returning to list...", CLISetup::LOG_WARN); sleep(1); break; } } } else { CLISetup::log(); CLISetup::log("invalid selection", CLISetup::LOG_ERROR); sleep(1); } } } else { CLISetup::log(); CLISetup::log("site configuration aborted", CLISetup::LOG_WARN); break; } } }
function emotes() { $globStrPath = CLISetup::$srcDir . '%sInterface/FrameXML/GlobalStrings.lua'; $allOK = true; $locPath = []; DB::Aowow()->query('TRUNCATE ?_emotes_aliasses'); foreach (CLISetup::$localeIds as $lId) { foreach (CLISetup::$expectedPaths as $xp => $locId) { if ($lId != $locId) { continue; } if ($xp) { // if in subDir add trailing slash $xp .= '/'; } $path = sprintf($globStrPath, $xp); if (CLISetup::fileExists($path)) { $locPath[$lId] = $path; continue 2; } } CLISetup::log('GlobalStrings.lua not found for selected locale ' . CLISetup::bold(Util::$localeStrings[$lId]), CLISetup::LOG_WARN); $allOK = false; } $_ = DB::Aowow()->query('REPLACE INTO ?_emotes SELECT et.Id, LOWER(et.command), IF(e.animationId, 1, 0), 0, -- cuFlags etdT.text_loc0, etdT.text_loc2, etdT.text_loc3, etdT.text_loc6, etdT.text_loc8, etdNT.text_loc0, etdNT.text_loc2, etdNT.text_loc3, etdNT.text_loc6, etdNT.text_loc8, etdS.text_loc0, etdS.text_loc2, etdS.text_loc3, etdS.text_loc6, etdS.text_loc8 FROM dbc_emotestext et LEFT JOIN dbc_emotes e ON e.Id = et.emoteId LEFT JOIN dbc_emotestextdata etdT ON etdT.Id = et.targetId LEFT JOIN dbc_emotestextdata etdNT ON etdNT.Id = et.noTargetId LEFT JOIN dbc_emotestextdata etdS ON etdS.Id = et.selfId'); if (!$_) { $allOK = false; } // i have no idea, how the indexing in this file works. // sometimes the \d+ after EMOTE is the emoteTextId, but not nearly often enough $aliasses = []; foreach ($locPath as $lId => $path) { foreach (file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) { if (preg_match('/^EMOTE(\\d+)_CMD\\d+\\s=\\s\\"\\/([^"]+)\\";$/', $line, $m)) { $aliasses[$m[1]][] = [$lId, $m[2]]; } } } $emotes = DB::Aowow()->selectCol('SELECT id AS ARRAY_KEY, cmd FROM ?_emotes'); foreach ($emotes as $eId => $cmd) { foreach ($aliasses as $gsId => $data) { if (in_array($cmd, array_column($data, 1))) { foreach ($data as $d) { DB::Aowow()->query('INSERT IGNORE INTO ?_emotes_aliasses VALUES (?d, ?d, ?) ON DUPLICATE KEY UPDATE locales = locales | ?d', $eId, 1 << $d[0], strtolower($d[1]), 1 << $d[0]); } break; } } } return $allOK; }
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 dbconfig() { $databases = ['aowow', 'world', 'auth', 'characters']; $AoWoWconf = []; $dbFields = array('host' => ['Server Host', false], 'user' => ['User', false], 'pass' => ['Password', true], 'db' => ['Database Name', false], 'prefix' => ['Table prefix', false]); $testDB = function ($idx, $name, $dbInfo) { $buff = '[' . CLISetup::bold($idx) . '] ' . str_pad($name, 17); $errStr = ''; if ($dbInfo['host']) { // test DB if ($link = @mysqli_connect($dbInfo['host'], $dbInfo['user'], $dbInfo['pass'], $dbInfo['db'])) { mysqli_close($link); } else { $errStr = '[' . mysqli_connect_errno() . '] ' . mysqli_connect_error(); } $buff .= $errStr ? CLISetup::red('ERR ') : CLISetup::green('OK '); $buff .= 'mysqli://' . $dbInfo['user'] . ':' . str_pad('', strlen($dbInfo['pass']), '*') . '@' . $dbInfo['host'] . '/' . $dbInfo['db']; $buff .= ($dbInfo['prefix'] ? ' table prefix: ' . $dbInfo['prefix'] : null) . ' ' . $errStr; } else { $buff .= ' ' . CLISetup::bold('<empty>'); } return $buff; }; if (file_exists('config/config.php')) { require 'config/config.php'; } foreach ($databases as $idx => $name) { if (empty($AoWoWconf[$name]) && $name != 'characters') { $AoWoWconf[$name] = array_combine(array_keys($dbFields), ['', '', '', '', '']); } } while (true) { CLISetup::log(); CLISetup::log("select a numerical index to use the corresponding entry"); $nCharDBs = 0; foreach ($databases as $idx => $name) { if ($idx != 3) { CLISetup::log($testDB($idx, $name, $AoWoWconf[$name])); } else { if (!empty($AoWoWconf[$name])) { foreach ($AoWoWconf[$name] as $charIdx => $dbInfo) { CLISetup::log($testDB($idx + $nCharDBs++, $name . ' [' . $charIdx . ']', $AoWoWconf[$name][$charIdx])); } } } } CLISetup::log("[" . CLISetup::bold(3 + $nCharDBs) . "] add an additional Character DB"); while (true) { $inp = ['idx' => ['', true, '/\\d/']]; if (CLISetup::readInput($inp, true) && $inp) { if ($inp['idx'] >= 0 && $inp['idx'] <= 3 + $nCharDBs) { $curFields = $dbFields; if ($inp['idx'] == 3 + $nCharDBs) { // add new realmDB $curFields['realmId'] = ['Realm Id', false, '/[1-9][0-9]*/']; } if (CLISetup::readInput($curFields)) { // auth, world or aowow if ($inp['idx'] < 3) { $AoWoWconf[$databases[$inp['idx']]] = $curFields ?: array_combine(array_keys($dbFields), ['', '', '', '', '']); } else { if ($inp['idx'] == 3 + $nCharDBs) { if ($curFields) { $_ = $curFields['realmId']; unset($curFields['realmId']); $AoWoWconf[$databases[3]][$_] = $curFields; } } else { $i = 0; foreach ($AoWoWconf[$databases[3]] as $realmId => &$dbInfo) { if ($inp['idx'] - 3 != $i++) { continue; } if ($curFields) { $dbInfo = $curFields; } else { unset($AoWoWconf[$databases[3]][$realmId]); } } } } // write config file $buff = "<?php\n\nif (!defined('AOWOW_REVISION'))\n die('illegal access');\n\n\n"; foreach ($databases as $db) { if ($db != 'characters') { $buff .= '$AoWoWconf[\'' . $db . '\'] = ' . var_export($AoWoWconf[$db], true) . ";\n\n"; } else { foreach ($AoWoWconf[$db] as $idx => $charInfo) { $buff .= '$AoWoWconf[\'' . $db . '\'][\'' . $idx . '\'] = ' . var_export($AoWoWconf[$db][$idx], true) . ";\n\n"; } } } $buff .= "?>\n"; CLISetup::log(); CLISetup::writeFile('config/config.php', $buff); continue 2; } else { CLISetup::log(); CLISetup::log("edit canceled! returning to list...", CLISetup::LOG_WARN); sleep(1); continue 2; } } } else { CLISetup::log(); CLISetup::log("db setup aborted", CLISetup::LOG_WARN); break 2; } } } }
function item_stats(array $ids = []) { $offset = 0; CLISetup::log(' - applying stats for enchantments'); $enchStats = enchantment_stats(); CLISetup::log(' ' . count($enchStats) . ' enchantments parsed'); CLISetup::log(' - applying stats for items'); while (true) { $items = new ItemStatSetup($offset, SqlGen::$stepSize, $ids, $enchStats); if ($items->error) { break; } $max = max($items->getFoundIDs()); $num = count($items->getFoundIDs()); CLISetup::log(' * sets ' . ($offset + 1) . ' - ' . $max); $offset = $max; $items->writeStatsTable(); } return true; }
function quests(array $ids = []) { $baseQuery = ' SELECT q.ID, QuestType, -- Method QuestLevel, MinLevel, MaxLevel, QuestSortID, QuestSortID AS zoneOrSortBak, -- ZoneOrSortBak QuestInfoID, -- QuestType SuggestedGroupNum, TimeAllowed, IFNULL(gesqr.eventEntry, 0) AS eventId, PrevQuestId, NextQuestId, ExclusiveGroup, RewardNextQuest, Flags, SpecialFlags, 0 AS cuFlags, -- cuFlags AllowableClasses, AllowableRaces, RequiredSkillId, RequiredSkillPoints, RequiredFactionId1, RequiredFactionId2, RequiredFactionValue1, RequiredFactionValue2, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, RequiredPlayerKills, StartItem, ProvidedItemCount, SourceSpellId, RewardXPDifficulty, -- QuestXP.dbc x level RewardMoney, RewardBonusMoney, RewardDisplaySpell, RewardSpell, RewardHonor * 124 * RewardKillHonor, -- alt calculation in QuestDef.cpp -> Quest::CalculateHonorGain(playerLevel) RewardMailTemplateId, RewardMailDelay, RewardTitle, RewardTalents, RewardArenaPoints, RewardItem1, RewardItem2, RewardItem3, RewardItem4, RewardAmount1, RewardAmount2, RewardAmount3, RewardAmount4, RewardChoiceItemID1, RewardChoiceItemID2, RewardChoiceItemID3, RewardChoiceItemID4, RewardChoiceItemID5, RewardChoiceItemID6, RewardChoiceItemQuantity1, RewardChoiceItemQuantity2, RewardChoiceItemQuantity3, RewardChoiceItemQuantity4, RewardChoiceItemQuantity5, RewardChoiceItemQuantity6, RewardFactionID1, RewardFactionID2, RewardFactionID3, RewardFactionID4, RewardFactionID5, IF (RewardFactionOverride1 <> 0, RewardFactionOverride1 / 100, RewardFactionValue1), IF (RewardFactionOverride2 <> 0, RewardFactionOverride2 / 100, RewardFactionValue2), IF (RewardFactionOverride3 <> 0, RewardFactionOverride3 / 100, RewardFactionValue3), IF (RewardFactionOverride4 <> 0, RewardFactionOverride4 / 100, RewardFactionValue4), IF (RewardFactionOverride5 <> 0, RewardFactionOverride5 / 100, RewardFactionValue5), LogTitle, Title_loc2, Title_loc3, Title_loc4, Title_loc6, Title_loc8, LogDescription, Objectives_loc2, Objectives_loc3, Objectives_loc4, Objectives_loc6, Objectives_loc8, QuestDescription, Details_loc2, Details_loc3, Details_loc4, Details_loc6, Details_loc8, AreaDescription, EndText_loc2, EndText_loc3, EndText_loc4, EndText_loc6, EndText_loc8, qor.RewardText, OfferRewardText_loc2, OfferRewardText_loc3, OfferRewardText_loc4, OfferRewardText_loc6, OfferRewardText_loc8, qri.CompletionText, RequestItemsText_loc2, RequestItemsText_loc3, RequestItemsText_loc4, RequestItemsText_loc6, RequestItemsText_loc8, QuestCompletionLog, CompletedText_loc2, CompletedText_loc3, CompletedText_loc4, CompletedText_loc6, CompletedText_loc8, RequiredNpcOrGo1, RequiredNpcOrGo2, RequiredNpcOrGo3, RequiredNpcOrGo4, RequiredNpcOrGoCount1, RequiredNpcOrGoCount2, RequiredNpcOrGoCount3, RequiredNpcOrGoCount4, ItemDrop1, ItemDrop2, ItemDrop3, ItemDrop4, ItemDropQuantity1, ItemDropQuantity2, ItemDropQuantity3, ItemDropQuantity4, RequiredItemId1, RequiredItemId2, RequiredItemId3, RequiredItemId4, RequiredItemId5, RequiredItemId6, RequiredItemCount1, RequiredItemCount2, RequiredItemCount3, RequiredItemCount4, RequiredItemCount5, RequiredItemCount6, ObjectiveText1, ObjectiveText1_loc2, ObjectiveText1_loc3, ObjectiveText1_loc4, ObjectiveText1_loc6, ObjectiveText1_loc8, ObjectiveText2, ObjectiveText2_loc2, ObjectiveText2_loc3, ObjectiveText2_loc4, ObjectiveText2_loc6, ObjectiveText2_loc8, ObjectiveText3, ObjectiveText3_loc2, ObjectiveText3_loc3, ObjectiveText3_loc4, ObjectiveText3_loc6, ObjectiveText3_loc8, ObjectiveText4, ObjectiveText4_loc2, ObjectiveText4_loc3, ObjectiveText4_loc4, ObjectiveText4_loc6, ObjectiveText4_loc8 FROM quest_template q LEFT JOIN quest_template_addon qa ON q.ID = qa.ID LEFT JOIN quest_offer_reward qor ON q.ID = qor.ID LEFT JOIN quest_request_items qri ON q.ID = qri.ID LEFT JOIN locales_quest lq ON q.ID = lq.Id LEFT JOIN game_event_seasonal_questrelation gesqr ON gesqr.questId = q.ID { WHERE q.ID IN (?a) } LIMIT ?d, ?d'; $xpQuery = ' UPDATE ?_quests q, dbc_questxp xp SET rewardXP = (CASE rewardXP WHEN 0 THEN xp.Field1 WHEN 1 THEN xp.Field2 WHEN 2 THEN xp.Field3 WHEN 3 THEN xp.Field4 WHEN 4 THEN xp.Field5 WHEN 5 THEN xp.Field6 WHEN 6 THEN xp.Field7 WHEN 7 THEN xp.Field8 WHEN 8 THEN xp.Field9 WHEN 9 THEN xp.Field10 ELSE 0 END) WHERE xp.id = q.level { AND q.id IN(?a) }'; $repQuery = ' UPDATE ?_quests q LEFT JOIN dbc_questfactionreward rep ON rep.Id = IF(rewardFactionValue?d > 0, 1, 2) SET rewardFactionValue?d = (CASE ABS(rewardFactionValue?d) WHEN 0 THEN rep.Field1 WHEN 1 THEN rep.Field2 WHEN 2 THEN rep.Field3 WHEN 3 THEN rep.Field4 WHEN 4 THEN rep.Field5 WHEN 5 THEN rep.Field6 WHEN 6 THEN rep.Field7 WHEN 7 THEN rep.Field8 WHEN 8 THEN rep.Field9 WHEN 9 THEN rep.Field10 ELSE 0 END) WHERE ABS(rewardFactionValue?d) BETWEEN 1 AND 10 { AND q.id IN(?a) }'; $offset = 0; while ($quests = DB::World()->select($baseQuery, $ids ?: DBSIMPLE_SKIP, $offset, SqlGen::$stepSize)) { CLISetup::log(' * sets ' . ($offset + 1) . ' - ' . ($offset + count($quests))); $offset += SqlGen::$stepSize; foreach ($quests as $q) { DB::Aowow()->query('REPLACE INTO ?_quests VALUES (?a)', array_values($q)); } } /* just some random thoughts here .. quest-custom-flags are derived from flags and specialFlags since they are not used further than being sent to JS as wFlags this is fine.. should they be saved to db anyway..? same with QUEST_FLAG_UNAVAILABLE => CUSTOM_EXCLUDE_FOR_LISTVIEW */ // unpack XP-reward DB::Aowow()->query($xpQuery, $ids ?: DBSIMPLE_SKIP); // unpack Rep-rewards for ($i = 1; $i < 6; $i++) { DB::Aowow()->query($repQuery, $i, $i, $i, $i, $ids ?: DBSIMPLE_SKIP); } // update zoneOrSort/QuestSortID .. well .. now "not documenting" bites me in the ass .. ~700 quests were changed, i don't know by what method $eventSet = DB::World()->selectCol('SELECT holiday AS ARRAY_KEY, eventEntry FROM game_event WHERE holiday <> 0'); $holidaySorts = array(141 => -1001, 181 => -374, 201 => -1002, 301 => -101, 321 => -1005, 324 => -1003, 327 => -366, 341 => -369, 372 => -370, 374 => -364, 376 => -364, 404 => -375, 409 => -41, 423 => -376, 424 => -101); foreach ($holidaySorts as $hId => $sort) { if (!empty($eventSet[$hId])) { DB::Aowow()->query('UPDATE ?_quests SET zoneOrSort = ?d WHERE eventId = ?d{ AND id IN (?a)}', $sort, $eventSet[$hId], $ids ?: DBSIMPLE_SKIP); } } /* zoneorsort for quests will need updating points non-instanced area with identic name for instance quests SELECT DISTINCT CONCAT('[',q.zoneorsort,',"',a.name_loc0,'"],') FROM dbc_map m, ?_quests q, dbc_areatable a WHERE a.id = q.zoneOrSort AND q.zoneOrSort > 0 AND a.mapId = m.id AND m.areaType = 1 ORDER BY a.name_loc0 ASC; */ // 'special' special cases // fishing quests to stranglethorn extravaganza DB::Aowow()->query('UPDATE ?_quests SET zoneOrSort = ?d WHERE id IN (?a){ AND id IN (?a)}', -101, [8228, 8229], $ids ?: DBSIMPLE_SKIP); // dungeon quests to Misc/Dungeon Finder DB::Aowow()->query('UPDATE ?_quests SET zoneOrSort = ?d WHERE (specialFlags & ?d OR id IN (?a)){ AND id IN (?a)}', -1010, QUEST_FLAG_SPECIAL_DUNGEON_FINDER, [24789, 24791, 24923], $ids ?: DBSIMPLE_SKIP); return true; }
function source(array $ids = []) { $insBasic = 'INSERT INTO ?_source (`type`, typeId, src?d) VALUES [V] ON DUPLICATE KEY UPDATE moreType = NULL, moreTypeId = NULL, src?d = VALUES(src?d)'; $insMore = 'INSERT INTO ?_source (`type`, typeId, src?d, moreType, moreTypeId) VALUES [V] ON DUPLICATE KEY UPDATE moreType = NULL, moreTypeId = NULL, src?d = VALUES(src?d)'; $insSub = 'INSERT INTO ?_source (`type`, typeId, src?d, moreType, moreTypeId) ?s ON DUPLICATE KEY UPDATE moreType = NULL, moreTypeId = NULL, src?d = VALUES(src?d)'; // please note, this workes without checks, because we do not use strings here function queryfy($ph, array $data, $query) { $buff = []; array_walk_recursive($data, function (&$item) { if ($item === null) { $item = 'NULL'; } }); foreach ($data as $d) { $buff[] = '(' . implode(', ', $d ?: 'NULL') . ')'; } return str_replace($ph, implode(', ', $buff), $query); } function pushBuffer(&$buff, $type, $typeId, $mType = 0, $mTypeId = 0, $src = 1) { $b =& $buff[$typeId]; if (isset($b) && $b[3] === null) { return; } else { if (isset($b) && $b[1] != $typeId) { $b[3] = $b[4] = null; $b[2] |= $src; // only quests atm } else { if ($mType && $mTypeId) { $b = [$type, $typeId, $src, $mType, $mTypeId]; } else { $b = [$type, $typeId, $src, null, null]; } } } } function taughtSpell($item) { # spelltrigger_X (0: onUse; 6: onLearnSpell) # spell: 483 & 55884 are learn spells // should not be able to teach spells (recipe || mount || vanityPet) if ($item['class'] != ITEM_CLASS_RECIPE && ($item['class'] != ITEM_CLASS_MISC || $item['subclass'] != 2 && $item['subclass'] != 5)) { return 0; } // wotlk system if (($item['spellid_1'] == 483 || $item['spellid_1'] == 55884) && $item['spelltrigger_1'] == 0 && $item['spellid_2'] > 0 && $item['spelltrigger_2'] == 6) { return $item['spellid_2']; } // deprecated system if ($item['spellid_1'] != 483 && $item['spellid_1'] != 55884 && $item['spellid_1'] > 0 && $item['spelltrigger_1'] == 0) { return $item['spellid_1']; } return 0; } // cant update existing rows if ($ids) { DB::Aowow()->query('DELETE FROM ?_source WHERE `type` = ?d AND typeId IN (?a)', $well, $wellll); } else { DB::Aowow()->query('TRUNCATE TABLE ?_source'); } /***************************/ /* Item & inherited Spells */ /***************************/ CLISetup::log(' - Items & Spells [inherited]'); # also everything from items that teach spells, is src of spell # todo: check if items have learn-spells (effect: 36) CLISetup::log(' * resolve ref-loot tree'); $refLoot = DB::World()->select(' SELECT rlt.Entry AS ARRAY_KEY, IF(Reference, -Reference, Item) AS ARRAY_KEY2, it.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, COUNT(1) AS qty FROM reference_loot_template rlt LEFT JOIN item_template it ON rlt.Reference = 0 AND rlt.Item = it.entry GROUP BY ARRAY_KEY, ARRAY_KEY2 '); $hasChanged = true; while ($hasChanged) { $hasChanged = false; foreach ($refLoot as $entry => &$refData) { foreach ($refData as $itemOrRef => $data) { if ($itemOrRef > 0) { continue; } if (!empty($refLoot[-$itemOrRef])) { foreach ($refLoot[-$itemOrRef] as $key => $data) { if (!empty($refData[$key])) { $refData[$key]['qty'] += $data['qty']; } else { $refLoot[-$itemOrRef][$key] = $data; } } } unset($refData[$itemOrRef]); $hasChanged = true; } } } ############### # 1: Crafted # ############### CLISetup::log(' * #1 Crafted'); $spellBuff = []; $itemBuff = []; $itemSpells = DB::Aowow()->selectCol(' SELECT effect1CreateItemId AS ARRAY_KEY, s.id AS spell FROM dbc_spell s JOIN dbc_skilllineability sla ON s.id = sla.spellId WHERE effect1CreateItemId > 0 AND sla.skillLineId IN (?a) GROUP BY ARRAY_KEY', [164, 165, 171, 182, 186, 197, 202, 333, 393, 755, 773, 129, 185, 356, 762]); $spellItems = DB::World()->select('SELECT entry AS ARRAY_KEY, class, subclass, spellid_1, spelltrigger_1, spellid_2, spelltrigger_2 FROM item_template WHERE entry IN (?a)', array_keys($itemSpells)); foreach ($spellItems as $iId => $si) { if ($_ = taughtSpell($si)) { $spellBuff[$_] = [TYPE_SPELL, $_, 1, TYPE_SPELL, $itemSpells[$iId]]; } $itemBuff[$iId] = [TYPE_ITEM, $iId, 1, TYPE_SPELL, $itemSpells[$iId]]; } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 1, 1, 1); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 1, 1, 1); } ############ # 2: Drop # ############ CLISetup::log(' * #2 Drop'); $spellBuff = []; $itemBuff = []; $creatureLoot = DB::World()->select(' SELECT IF(clt.Reference > 0, -clt.Reference, clt.Item) AS ARRAY_KEY, ct.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, count(1) 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 WHERE ct.lootid > 0 GROUP BY ARRAY_KEY '); foreach ($creatureLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } $objectOT = []; $exclLocks = DB::Aowow()->selectCol('SELECT id FROM dbc_lock WHERE properties1 IN (2, 3)'); $objectLoot = DB::World()->select(' SELECT IF(glt.Reference > 0, -glt.Reference, glt.Item) AS ARRAY_KEY, gt.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, count(1) 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 WHERE `type` = 3 AND gt.Data1 > 0 AND gt.Data0 NOT IN (?a) GROUP BY ARRAY_KEY', $exclLocks); foreach ($objectLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } $objectOT[] = $iId; pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } $objectOT[] = $roi; pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } $itemOT = []; $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 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 WHERE itA.flags & 0x4 GROUP BY ARRAY_KEY '); foreach ($itemLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_ITEM, $l['entry']); } $itemOT[] = $iId; pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_ITEM, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_ITEM, $l['entry']); } $itemOT[] = $roi; pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_ITEM, $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 2, 2, 2); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 2, 2, 2); } 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); ########### # 3: PvP # (Vendors w/ xCost Arena/Honor) ########### CLISetup::log(' * #3 PvP'); // var g_sources_pvp = { // 1: 'Arena', // 2: 'Battleground', // 4: 'World' basicly the tokens you get for openPvP .. manual data // }; $spellBuff = []; $itemBuff = []; $xCostH = DB::Aowow()->selectCol('SELECT Id FROM dbc_itemextendedcost WHERE reqHonorPoints > 0 AND reqArenaPoints = 0'); $xCostA = DB::Aowow()->selectCol('SELECT Id FROM dbc_itemextendedcost WHERE reqArenaPoints > 0'); $vendorQuery = 'SELECT n.item AS ARRAY_KEY, SUM(n.qty) AS qty, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2 FROM ( SELECT item, COUNT(1) AS qty FROM npc_vendor WHERE ExtendedCost IN (?a) GROUP BY item UNION SELECT item, COUNT(1) AS qty FROM game_event_npc_vendor genv JOIN creature c ON c.guid = genv.guid WHERE ExtendedCost IN (?a) GROUP BY item ) n JOIN item_template it ON it.entry = n.item GROUP BY item'; foreach (DB::World()->select($vendorQuery, $xCostA, $xCostA) as $iId => $v) { if ($_ = taughtSpell($v)) { $spellBuff[$_] = [TYPE_SPELL, $_, 1]; } $itemBuff[$iId] = [TYPE_ITEM, $iId, 1]; } foreach (DB::World()->select($vendorQuery, $xCostH, $xCostH) as $iId => $v) { if ($_ = taughtSpell($v)) { $spellBuff[$_] = [TYPE_SPELL, $_, 2]; } $itemBuff[$iId] = [TYPE_ITEM, $iId, 2]; } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insBasic), 3, 3, 3); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insBasic), 3, 3, 3); } ############# # 4: Quest # ############# CLISetup::log(' * #4 Quest'); $spellBuff = []; $itemBuff = []; $quests = DB::World()->select('SELECT n.item AS ARRAY_KEY, n.ID AS quest, SUM(n.qty) AS qty, BIT_OR(n.side) AS side, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2 FROM ( SELECT RewardChoiceItemID1 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardChoiceItemID1 > 0 GROUP BY item UNION SELECT RewardChoiceItemID2 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardChoiceItemID2 > 0 GROUP BY item UNION SELECT RewardChoiceItemID3 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardChoiceItemID3 > 0 GROUP BY item UNION SELECT RewardChoiceItemID4 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardChoiceItemID4 > 0 GROUP BY item UNION SELECT RewardChoiceItemID5 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardChoiceItemID5 > 0 GROUP BY item UNION SELECT RewardChoiceItemID6 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardChoiceItemID6 > 0 GROUP BY item UNION SELECT RewardItem1 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardItem1 > 0 GROUP BY item UNION SELECT RewardItem2 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardItem2 > 0 GROUP BY item UNION SELECT RewardItem3 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardItem3 > 0 GROUP BY item UNION SELECT RewardItem4 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardItem4 > 0 GROUP BY item ) n JOIN item_template it ON it.entry = n.item GROUP BY item'); foreach ($quests as $iId => $q) { if ($_ = taughtSpell($q)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $q['qty'] > 1 ? 0 : TYPE_QUEST, $q['quest'], $q['side']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $q['qty'] > 1 ? 0 : TYPE_QUEST, $q['quest'], $q['side']); } $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, BIT_OR(IF(qt.RequiredRaces & 0x2B2 AND !(qt.RequiredRaces & 0x44D), 2, IF(qt.RequiredRaces & 0x44D AND !(qt.RequiredRaces & 0x2B2), 1, 3))) AS side FROM mail_loot_template mlt JOIN quest_template qt ON qt.RewardMailTemplateId = mlt.entry LEFT JOIN item_template it ON it.entry = mlt.Item AND mlt.Reference <= 0 WHERE qt.RewardMailTemplateId > 0 GROUP BY ARRAY_KEY '); foreach ($mailLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_QUEST, $l['entry'], $l['side']); } $itemOT[] = $iId; pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_QUEST, $l['entry'], $l['side']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_QUEST, $l['entry'], $l['side']); } $itemOT[] = $roi; pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_QUEST, $l['entry'], $l['side']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 4, 4, 4); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 4, 4, 4); } ############## # 5: Vendor # (w/o xCost Arena/Honor) ############## CLISetup::log(' * #5 Vendor'); $spellBuff = []; $itemBuff = []; $xCostIds = DB::Aowow()->selectCol('SELECT Id FROM dbc_itemextendedcost WHERE reqHonorPoints <> 0 OR reqArenaPoints <> 0'); $vendors = DB::World()->select('SELECT n.item AS ARRAY_KEY, n.npc, SUM(n.qty) AS qty, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2 FROM ( SELECT item, entry AS npc, COUNT(1) AS qty FROM npc_vendor WHERE ExtendedCost NOT IN (?a) GROUP BY item UNION SELECT item, c.id AS npc, COUNT(1) AS qty FROM game_event_npc_vendor genv JOIN creature c ON c.guid = genv.guid WHERE ExtendedCost NOT IN (?a) GROUP BY item ) n JOIN item_template it ON it.entry = n.item GROUP BY item', $xCostIds, $xCostIds); foreach ($vendors as $iId => $v) { if ($_ = taughtSpell($v)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $v['qty'] > 1 ? 0 : TYPE_NPC, $v['npc']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $v['qty'] > 1 ? 0 : TYPE_NPC, $v['npc']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 5, 5, 5); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 5, 5, 5); } ############### # 10: Starter # ############### CLISetup::log(' * #10 Starter'); if ($pcii = DB::World()->select('SELECT ?d, itemid, 1 FROM playercreateinfo_item', TYPE_ITEM)) { DB::Aowow()->query(queryfy('[V]', $pcii, $insBasic), 10, 10, 10); } for ($i = 1; $i < 21; $i++) { DB::Aowow()->query($insSub, 10, DB::Aowow()->subquery('SELECT ?d, item?d, 1, NULL AS m, NULL AS mt FROM dbc_charstartoutfit WHERE item?d > 0', TYPE_ITEM, $i, $i), 10, 10); } ################### # 12: Achievement # ################### CLISetup::log(' * #12 Achievement'); $spellBuff = []; $itemBuff = []; $xItems = DB::Aowow()->select('SELECT id AS entry, itemExtra AS ARRAY_KEY, COUNT(1) AS qty FROM ?_achievement WHERE itemExtra > 0 GROUP BY itemExtra'); $rewItems = DB::World()->select(' SELECT src.item AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, COUNT(1) AS qty FROM ( SELECT IFNULL(IF(mlt.Reference > 0, -mlt.Reference, mlt.Item), ar.item) AS item, ar.entry FROM achievement_reward ar LEFT JOIN mail_loot_template mlt ON mlt.entry = ar.mailTemplate WHERE ar.mailTemplate > 0 OR ar.item > 0 ) src LEFT JOIN item_template it ON src.item = it.entry GROUP BY ARRAY_KEY '); $extraItems = DB::World()->select('SELECT entry AS ARRAY_KEY, class, subclass, spellid_1, spelltrigger_1, spellid_2, spelltrigger_2 FROM item_template WHERE entry IN (?a)', array_keys($xItems)); foreach ($extraItems as $iId => $l) { if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $xItems[$iId]['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $xItems[$iId]['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $xItems[$iId]['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $xItems[$iId]['entry']); } foreach ($rewItems as $iId => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $l['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $l['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 12, 12, 12); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 12, 12, 12); } #################### # 15: Disenchanted # #################### CLISetup::log(' * #15 Disenchanted'); $spellBuff = []; $itemBuff = []; $deLoot = DB::World()->select(' SELECT IF(dlt.Reference > 0, -dlt.Reference, dlt.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 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 WHERE itA.DisenchantId > 0 GROUP BY ARRAY_KEY '); foreach ($deLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_); } pushBuffer($itemBuff, TYPE_ITEM, $iId); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_); } pushBuffer($itemBuff, TYPE_ITEM, $roi); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 15, 15, 15); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 15, 15, 15); } ############## # 16: Fished # ############## CLISetup::log(' * #16 Fished'); $spellBuff = []; $itemBuff = []; $fishLoot = DB::World()->select(' SELECT src.itemOrRef AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, count(1) AS qty FROM ( SELECT 0 AS entry, IF(flt.Reference > 0, -flt.Reference, flt.Item) itemOrRef FROM fishing_loot_template flt UNION SELECT gt.entry, IF(glt.Reference > 0, -glt.Reference, glt.Item) itemOrRef FROM gameobject_template gt JOIN gameobject_loot_template glt ON glt.entry = gt.Data1 WHERE `type` = 25 AND gt.Data1 > 0 ) src LEFT JOIN item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry GROUP BY ARRAY_KEY '); foreach ($fishLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 16, 16, 16); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 16, 16, 16); } ################ # 17: Gathered # ################ CLISetup::log(' * #17 Gathered'); $spellBuff = []; $itemBuff = []; $herbLocks = DB::Aowow()->selectCol('SELECT id FROM dbc_lock WHERE properties1 = 2'); $herbLoot = DB::World()->select(' SELECT src.itemOrRef AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, count(1) 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` = 3 AND gt.Data1 > 0 AND Data0 IN (?a) ) src LEFT JOIN item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry GROUP BY ARRAY_KEY', TYPE_NPC, NPC_TYPEFLAG_HERBLOOT, TYPE_OBJECT, $herbLocks); foreach ($herbLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 17, 17, 17); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 17, 17, 17); } ############## # 18: Milled # ############## CLISetup::log(' * #18 Milled'); $spellBuff = []; $itemBuff = []; $millLoot = DB::World()->select(' SELECT IF(mlt.Reference > 0, -mlt.Reference, mlt.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 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 GROUP BY ARRAY_KEY '); foreach ($millLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_); } pushBuffer($itemBuff, TYPE_ITEM, $iId); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_); } pushBuffer($itemBuff, TYPE_ITEM, $roi); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 18, 18, 18); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 18, 18, 18); } ############# # 19: Mined # ############# CLISetup::log(' * #19 Mined'); $spellBuff = []; $itemBuff = []; $mineLocks = DB::Aowow()->selectCol('SELECT id FROM dbc_lock WHERE properties1 = 3'); $mineLoot = DB::World()->select(' SELECT src.itemOrRef AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, count(1) 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` = 3 AND gt.Data1 > 0 AND Data0 IN (?a) ) src LEFT JOIN item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry GROUP BY ARRAY_KEY', TYPE_NPC, NPC_TYPEFLAG_MININGLOOT, TYPE_OBJECT, $mineLocks); foreach ($mineLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 19, 19, 19); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 19, 19, 19); } ################## # 20: Prospected # ################## CLISetup::log(' * #20 Prospected'); $spellBuff = []; $itemBuff = []; $prospectLoot = DB::World()->select(' SELECT IF(plt.Reference > 0, -plt.Reference, plt.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 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 GROUP BY ARRAY_KEY '); foreach ($prospectLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_); } pushBuffer($itemBuff, TYPE_ITEM, $iId); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_); } pushBuffer($itemBuff, TYPE_ITEM, $roi); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 20, 20, 20); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 20, 20, 20); } ################## # 21: Pickpocket # ################## CLISetup::log(' * #21 Pickpocket'); $spellBuff = []; $itemBuff = []; $theftLoot = DB::World()->select(' SELECT src.itemOrRef AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, COUNT(1) 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 ARRAY_KEY '); foreach ($theftLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 21, 21, 21); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 21, 21, 21); } ################ # 22: Salvaged # ################ CLISetup::log(' * #22 Salvaged'); $spellBuff = []; $itemBuff = []; $salvageLoot = DB::World()->select(' SELECT src.itemOrRef AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, COUNT(1) 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 ARRAY_KEY', NPC_TYPEFLAG_ENGINEERLOOT); foreach ($salvageLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 22, 22, 22); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 22, 22, 22); } ############### # 23: Skinned # ############### CLISetup::log(' * #23 Skinned'); $spellBuff = []; $itemBuff = []; $skinLoot = DB::World()->select(' SELECT src.itemOrRef AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, COUNT(1) 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 ) src LEFT JOIN item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry GROUP BY ARRAY_KEY', NPC_TYPEFLAG_HERBLOOT | NPC_TYPEFLAG_MININGLOOT | NPC_TYPEFLAG_ENGINEERLOOT); foreach ($skinLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 23, 23, 23); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 23, 23, 23); } /*********/ /* Spell */ /*********/ CLISetup::log(' - Spells [original]'); # 4: Quest CLISetup::log(' * #4 Quest'); $quests = DB::World()->select(' SELECT spell AS ARRAY_KEY, id, SUM(qty) AS qty, BIT_OR(side) AS side FROM ( SELECT IF(rewardSpellCast = 0, rewardSpell, rewardSpellCast) AS spell, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE IF(rewardSpellCast = 0, rewardSpell, rewardSpellCast) > 0 GROUP BY spell UNION SELECT SourceSpellId AS spell, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE SourceSpellId > 0 GROUP BY spell ) t GROUP BY spell'); if ($quests) { $qSpells = DB::Aowow()->select('SELECT id AS ARRAY_KEY, effect1Id, effect2Id, effect3Id, effect1TriggerSpell, effect2TriggerSpell, effect3TriggerSpell FROM dbc_spell WHERE id IN (?a) AND (effect1Id = 36 OR effect2Id = 36 OR effect3Id = 36)', array_keys($quests)); $buff = []; foreach ($qSpells as $sId => $spell) { for ($i = 1; $i <= 3; $i++) { if ($spell['effect' . $i . 'Id'] != 36) { // effect: learnSpell continue; } pushBuffer($buff, TYPE_SPELL, $spell['effect' . $i . 'TriggerSpell'], $quests[$sId]['qty'] > 1 ? 0 : TYPE_QUEST, $quests[$sId]['qty'] > 1 ? 0 : $quests[$sId]['id'], $quests[$sId]['side']); } } DB::Aowow()->query(queryfy('[V]', $buff, $insMore), 4, 4, 4); } # 6: Trainer CLISetup::log(' * #6 Trainer'); if ($tNpcs = DB::World()->select('SELECT SpellID AS ARRAY_KEY, ID AS entry, COUNT(1) AS qty FROM npc_trainer WHERE SpellID > 0 GROUP BY ARRAY_KEY')) { $tSpells = DB::Aowow()->select('SELECT Id AS ARRAY_KEY, effect1Id, effect2Id, effect3Id, effect1TriggerSpell, effect2TriggerSpell, effect3TriggerSpell FROM dbc_spell WHERE Id IN (?a)', array_keys($tNpcs)); $buff = []; // todo (med): this skips some spells (e.g. riding) foreach ($tNpcs as $spellId => $npc) { if (!isset($tSpells[$spellId])) { continue; } $effects = $tSpells[$spellId]; $trainerId = $npc['entry'] > 200000 || $npc['qty'] > 1 ? null : $npc['entry']; $triggered = false; for ($i = 1; $i <= 3; $i++) { if ($effects['effect' . $i . 'Id'] != 36) { // effect: learnSpell continue; } $triggered = true; pushBuffer($buff, TYPE_SPELL, $effects['effect' . $i . 'TriggerSpell'], $trainerId ? TYPE_NPC : 0, $trainerId); } if (!$triggered) { pushBuffer($buff, TYPE_SPELL, $spellId, $trainerId ? TYPE_NPC : 0, $trainerId); } } DB::Aowow()->query(queryfy('[V]', $buff, $insMore), 6, 6, 6); } # 7: Discovery CLISetup::log(' * #7 Discovery'); // 61756: Northrend Inscription Research (FAST QA VERSION); if ($disco = DB::World()->select('SELECT ?d, spellId, 1 FROM skill_discovery_template WHERE reqSpell <> ?d', TYPE_SPELL, 61756)) { DB::Aowow()->query(queryfy('[V]', $disco, $insBasic), 7, 7, 7); } # 9: Talent CLISetup::log(' * #9 Talent'); $tSpells = DB::Aowow()->select(' SELECT s.Id AS ARRAY_KEY, s.effect1Id, s.effect2Id, s.effect3Id, s.effect1TriggerSpell, s.effect2TriggerSpell, s.effect3TriggerSpell FROM dbc_talent t JOIN dbc_spell s ON s.Id = t.rank1 WHERE t.rank2 < 1 AND (t.talentSpell = 1 OR (s.effect1Id = 36 OR s.effect2Id = 36 OR s.effect3Id = 36)) '); $n = 0; $buff = []; while ($tSpells) { CLISetup::log(' - ' . ++$n . '. pass'); $recurse = []; foreach ($tSpells as $tId => $spell) { for ($i = 1; $i <= 3; $i++) { if ($spell['effect' . $i . 'Id'] == 36) { // effect: learnSpell $recurse[$spell['effect' . $i . 'TriggerSpell']] = $tId; } } if (array_search($tId, $recurse)) { unset($tSpells[$tId]); } } foreach ($tSpells as $tId => $__) { $buff[$tId] = [TYPE_SPELL, $tId, 1]; } if (!$recurse) { break; } $tSpells = DB::Aowow()->select('SELECT Id AS ARRAY_KEY, effect1Id, effect2Id, effect3Id, effect1TriggerSpell, effect2TriggerSpell, effect3TriggerSpell FROM dbc_spell WHERE Id IN (?a)', array_keys($recurse)); } DB::Aowow()->query(queryfy('[V]', $buff, $insBasic), 9, 9, 9); # 10: Starter CLISetup::log(' * #10 Starter'); /* acquireMethod ABILITY_LEARNED_ON_GET_PROFESSION_SKILL = 1, learnedAt = 1 && source10 = 1 ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL = 2 not used for now */ $subSkills = DB::Aowow()->subquery('SELECT ?d, spellId, 1, NULL AS m, NULL AS mt FROM dbc_skilllineability WHERE acquireMethod = 1 AND (reqSkillLevel = 1 OR skillLineId = 129) GROUP BY spellId', TYPE_SPELL); DB::Aowow()->query($insSub, 10, $subSkills, 10, 10); if ($pcis = DB::World()->select('SELECT ?d, Spell, 1 FROM playercreateinfo_spell', TYPE_SPELL)) { DB::Aowow()->query(queryfy('[V]', $pcis, $insBasic), 10, 10, 10); } /**********/ /* Titles */ /**********/ CLISetup::log(' - Titles'); # 4: Quest CLISetup::log(' * #4 Quest'); if ($quests = DB::World()->select('SELECT ?d, RewardTitle, 1, ?d, ID FROM quest_template WHERE RewardTitle > 0', TYPE_TITLE, TYPE_QUEST)) { DB::Aowow()->query(queryfy('[V]', $quests, $insMore), 4, 4, 4); } # 12: Achievement CLISetup::log(' * #12 Achievement'); $sets = DB::World()->select(' SELECT ?d, IF (title_A <> 0, title_A, title_H) AS title, 1, ?d, entry FROM achievement_reward WHERE title_A <> 0 OR title_H <> 0 GROUP BY title UNION SELECT ?d, title_H AS title, 1, ?d, entry FROM achievement_reward WHERE title_A <> title_H AND title_A <> 0 AND title_H <> 0', TYPE_TITLE, TYPE_ACHIEVEMENT, TYPE_TITLE, TYPE_ACHIEVEMENT); if ($sets) { DB::Aowow()->query(queryfy('[V]', $sets, $insMore), 12, 12, 12); } # 13: Source-String CLISetup::log(' * #13 cuStrings'); $src13 = [null, 42, 52, 71, 80, 157, 163, 167, 169, 177]; foreach ($src13 as $src => $tId) { if ($tId) { DB::Aowow()->query(queryfy('[V]', [[TYPE_TITLE, $tId, $src]], $insBasic), 13, 13, 13); } } return true; }
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 spawns() { $alphaMapCache = []; $alphaMapCheck = function ($areaId, array &$set) use(&$alphaMapCache) { $file = 'setup/generated/alphaMaps/' . $areaId . '.png'; if (!file_exists($file)) { // file does not exist (probably instanced area) return false; } // invalid and corner cases (literally) if (!is_array($set) || empty($set['posX']) || empty($set['posY']) || $set['posX'] >= 100 || $set['posY'] >= 100) { $set = null; return true; } if (empty($alphaMapCache[$areaId])) { $alphaMapCache[$areaId] = imagecreatefrompng($file); } // alphaMaps are 1000 x 1000, adapt points [black => valid point] if (!imagecolorat($alphaMapCache[$areaId], $set['posX'] * 10, $set['posY'] * 10)) { $set = null; } return true; }; $checkCoords = function ($points) use($alphaMapCheck) { $result = []; $capitals = array(1497, 1637, 1638, 3487, 1519, 1537, 1657, 3557, 3703, 4395); foreach ($points as $res) { if ($alphaMapCheck($res['areaId'], $res)) { if (!$res) { continue; } // some rough measure how central the spawn is on the map (the lower the number, the better) // 0: perfect center; 1: touches a border $q = abs(($res['posX'] - 50) / 50 * (($res['posY'] - 50) / 50)); if (empty($result) || $result[0] > $q) { $result = [$q, $res]; } } else { if (in_array($res['areaId'], $capitals)) { // capitals (auto-discovered) and no hand-made alphaMap available return $res; } else { if (empty($result)) { // add with lowest quality if alpha map is missing $result = [1.0, $res]; } } } } // spawn does not really match on a map, but we need at least one result if (!$result) { usort($points, function ($a, $b) { return $a['quality'] < $b['quality'] ? -1 : 1; }); $result = [1.0, $points[0]]; } return $result[1]; }; $query[1] = ['SELECT c.guid, 1 AS "type", c.id AS typeId, c.spawntimesecs AS respawn, c.phaseMask, c.zoneId AS areaId, c.map, IFNULL(ca.path_id, 0) AS pathId, c.position_y AS `posX`, c.position_x AS `posY` ' . 'FROM creature c LEFT JOIN creature_addon ca ON ca.guid = c.guid', ' - assembling ' . CLISetup::bold('creature') . ' spawns']; $query[2] = ['SELECT c.guid, 2 AS "type", c.id AS typeId, ABS(c.spawntimesecs) AS respawn, c.phaseMask, c.zoneId AS areaId, c.map, 0 as pathId, c.position_y AS `posX`, c.position_x AS `posY` ' . 'FROM gameobject c', ' - assembling ' . CLISetup::bold('gameobject') . ' spawns']; $query[3] = ['SELECT c.guid, w.entry AS "npcOrPath", w.pointId AS "point", c.zoneId AS areaId, c.map, w.waittime AS "wait", w.location_y AS `posX`, w.location_x AS `posY` ' . 'FROM creature c JOIN script_waypoint w ON c.id = w.entry', ' - assembling waypoints from ' . CLISetup::bold('script_waypoint')]; $query[4] = ['SELECT c.guid, w.entry AS "npcOrPath", w.pointId AS "point", c.zoneId AS areaId, c.map, 0 AS "wait", w.position_y AS `posX`, w.position_x AS `posY` ' . 'FROM creature c JOIN waypoints w ON c.id = w.entry', ' - assembling waypoints from ' . CLISetup::bold('waypoints')]; $query[5] = ['SELECT c.guid, -w.id AS "npcOrPath", w.point, c.zoneId AS areaId, c.map, w.delay AS "wait", w.position_y AS `posX`, w.position_x AS `posY` ' . 'FROM creature c JOIN creature_addon ca ON ca.guid = c.guid JOIN waypoint_data w ON w.id = ca.path_id', ' - assembling waypoints from ' . CLISetup::bold('waypoint_data')]; $queryPost = 'SELECT dm.Id, wma.areaId, IFNULL(dm.floor, 0) AS floor, ' . '100 - ROUND(IF(dm.Id IS NOT NULL, (?f - dm.minY) * 100 / (dm.maxY - dm.minY), (?f - wma.right) * 100 / (wma.left - wma.right)), 1) AS `posX`, ' . '100 - ROUND(IF(dm.Id IS NOT NULL, (?f - dm.minX) * 100 / (dm.maxX - dm.minX), (?f - wma.bottom) * 100 / (wma.top - wma.bottom)), 1) AS `posY`, ' . '((abs(IF(dm.Id IS NOT NULL, (?f - dm.minY) * 100 / (dm.maxY - dm.minY), (?f - wma.right) * 100 / (wma.left - wma.right)) - 50) / 50) * ' . ' (abs(IF(dm.Id IS NOT NULL, (?f - dm.minX) * 100 / (dm.maxX - dm.minX), (?f - wma.bottom) * 100 / (wma.top - wma.bottom)) - 50) / 50)) AS quality ' . 'FROM dbc_worldmaparea wma ' . 'LEFT JOIN dbc_dungeonmap dm ON dm.mapId = IF(?d AND wma.mapId NOT IN (0, 1, 530), wma.mapId, -1) ' . 'WHERE wma.mapId = ?d AND IF(?d, wma.areaId = ?d, wma.areaId <> 0) ' . 'HAVING (`posX` BETWEEN 0.1 AND 99.9 AND `posY` BETWEEN 0.1 AND 99.9) AND (dm.Id IS NULL OR ?d) ' . 'ORDER BY quality ASC'; /*********************/ /* truncate old data */ /*********************/ DB::Aowow()->query('TRUNCATE TABLE ?_spawns'); DB::Aowow()->query('TRUNCATE TABLE ?_creature_waypoints'); /**************************/ /* offsets for transports */ /**************************/ $transports = DB::World()->selectCol('SELECT Data0 AS pathId, Data6 AS ARRAY_KEY FROM gameobject_template WHERE type = 15 AND Data6 <> 0'); foreach ($transports as &$t) { $t = DB::Aowow()->selectRow('SELECT posX, posY, mapId FROM dbc_taxipathnode tpn WHERE tpn.pathId = ?d AND nodeIdx = 0', $t); } /**************/ /* perform... */ /**************/ foreach ($query as $idx => $q) { CLISetup::log($q[1]); $n = 0; $sum = 0; foreach (DB::World()->select($q[0]) as $spawn) { if (!$n) { CLISetup::log(' * sets ' . ($sum + 1) . ' - ' . ($sum += SqlGen::$stepSize)); } if ($n++ > SqlGen::$stepSize) { $n = 0; } // npc/object is on a transport -> apply offsets to path of transport // note, that the coordinates are mixed up .. again // also note, that transport DO spawn outside of displayable area maps .. another todo i guess.. if (isset($transports[$spawn['map']])) { $spawn['posX'] += $transports[$spawn['map']]['posY']; $spawn['posY'] += $transports[$spawn['map']]['posX']; $spawn['map'] = $transports[$spawn['map']]['mapId']; } $points = DB::Aowow()->select($queryPost, $spawn['posX'], $spawn['posX'], $spawn['posY'], $spawn['posY'], $spawn['posX'], $spawn['posX'], $spawn['posY'], $spawn['posY'], 1, $spawn['map'], $spawn['areaId'], $spawn['areaId'], $spawn['areaId'] ? 1 : 0); if (!$points) { // retry: TC counts pre-instance subareas as instance-maps .. which have no map file $points = DB::Aowow()->select($queryPost, $spawn['posX'], $spawn['posX'], $spawn['posY'], $spawn['posY'], $spawn['posX'], $spawn['posX'], $spawn['posY'], $spawn['posY'], 0, $spawn['map'], 0, 0, 1); } if (!$points) { CLISetup::log('GUID ' . $spawn['guid'] . ($idx < 3 ? '' : ' on path/point ' . $spawn['npcOrPath'] . '/' . $spawn['point']) . ' could not be matched to displayable area [A:' . $spawn['areaId'] . '; X:' . $spawn['posY'] . '; Y:' . $spawn['posX'] . ']', CLISetup::LOG_WARN); continue; } // if areaId is set, area was determined by TC .. we're fine .. mostly $final = $spawn['areaId'] ? $points[0] : $checkCoords($points); if ($idx < 3) { $set = array('guid' => $spawn['guid'], 'type' => $spawn['type'], 'typeId' => $spawn['typeId'], 'respawn' => $spawn['respawn'], 'phaseMask' => $spawn['phaseMask'], 'pathId' => $spawn['pathId'], 'areaId' => $final['areaId'], 'floor' => $final['floor'], 'posX' => $final['posX'], 'posY' => $final['posY']); DB::Aowow()->query('REPLACE INTO ?_spawns (?#) VALUES (?a)', array_keys($set), array_values($set)); } else { $set = array('creatureOrPath' => $spawn['npcOrPath'], 'point' => $spawn['point'], 'wait' => $spawn['wait'], 'areaId' => $final['areaId'], 'floor' => $final['floor'], 'posX' => $final['posX'], 'posY' => $final['posY']); DB::Aowow()->query('REPLACE INTO ?_creature_waypoints (?#) VALUES (?a)', array_keys($set), array_values($set)); } } } /*****************************/ /* spawn vehicle accessories */ /*****************************/ // get vehicle template accessories $accessories = DB::World()->select(' SELECT vta.accessory_entry AS typeId, c.guid, vta.entry, count(1) AS nSeats FROM vehicle_template_accessory vta LEFT JOIN creature c ON c.id = vta.entry GROUP BY accessory_entry, c.guid UNION SELECT va.accessory_entry AS typeId, va.guid, 0 AS entry, count(1) AS nSeats FROM vehicle_accessory va GROUP BY accessory_entry, va.guid'); // accessories may also be vehicles (e.g. "Kor'kron Infiltrator" is seated on "Kor'kron Suppression Turret" is seated on "Kor'kron Troop Transport") // so we will retry finding a spawned vehicle if none were found on the previous pass and a change occured $vGuid = 0; // not really used, but we need some kind of index $n = 0; $matches = -1; while ($matches) { $matches = 0; foreach ($accessories as $idx => $data) { $vehicles = []; if ($data['guid']) { // vehicle already spawned $vehicles = DB::Aowow()->select('SELECT s.areaId, s.posX, s.posY, s.floor FROM ?_spawns s WHERE s.guid = ?d AND s.type = ?d', $data['guid'], TYPE_NPC); } else { if ($data['entry']) { // vehicle on unspawned vehicle action $vehicles = DB::Aowow()->select('SELECT s.areaId, s.posX, s.posY, s.floor FROM ?_spawns s WHERE s.typeId = ?d AND s.type = ?d', $data['entry'], TYPE_NPC); } } if ($vehicles) { $matches++; foreach ($vehicles as $v) { // if there is more than one vehicle, its probably due to overlapping zones for ($i = 0; $i < $data['nSeats']; $i++) { DB::Aowow()->query(' REPLACE INTO ?_spawns (`guid`, `type`, `typeId`, `respawn`, `spawnMask`, `phaseMask`, `areaId`, `floor`, `posX`, `posY`, `pathId`) VALUES (?d, ?d, ?d, 0, 0, 1, ?d, ?d, ?d, ?d, 0)', --$vGuid, TYPE_NPC, $data['typeId'], $v['areaId'], $v['floor'], $v['posX'], $v['posY']); } } unset($accessories[$idx]); } } if ($matches) { CLISetup::log(' * assigned ' . $matches . ' accessories on ' . ++$n . '. pass on vehicle accessories'); } } if ($accessories) { CLISetup::log(count($accessories) . ' accessories could not be fitted onto a spawned vehicle.', CLISetup::LOG_WARN); } /********************************/ /* restrict difficulty displays */ /********************************/ DB::Aowow()->query('UPDATE ?_spawns s, dbc_worldmaparea wma, dbc_map m SET s.spawnMask = 0 WHERE s.areaId = wma.areaId AND wma.mapId = m.Id AND m.areaType IN (0, 3, 4)'); return true; }
function itemset() { $locales = [LOCALE_EN, LOCALE_FR, LOCALE_DE, LOCALE_ES, LOCALE_RU]; $setToHoliday = array(761 => 141, 762 => 372, 785 => 341, 812 => 181); // find events associated with holidayIds if ($pairs = DB::World()->selectCol('SELECT holiday AS ARRAY_KEY, eventEntry FROM game_event WHERE holiday IN (?a)', array_values($setToHoliday))) { foreach ($setToHoliday as &$hId) { $hId = !empty($pairs[$hId]) ? $pairs[$hId] : 0; } } // tags where refId == virtualId // in pve sets are not recycled beyond the contentGroup $tagsById = array(1 => [181, 182, 183, 184, 185, 186, 187, 188, 189], 2 => [511, 512, 513, 514, 515, 516, 517, 518, 519], 3 => [201, 202, 203, 204, 205, 206, 207, 208, 209], 4 => [210, 211, 212, 213, 214, 215, 216, 217, 218], 5 => [521, 523, 524, 525, 526, 527, 528, 529, 530], 6 => [522, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 697, 718], 7 => [281, 282, 301, 341, 342, 343, 344, 345, 346, 347, 348, 361, 362, 381, 382, 401], 8 => [383, 384, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 402, 717, 698], 9 => [494, 495, 498, 500, 502, 504, 506, 508, 510], 10 => [493, 496, 497, 499, 501, 503, 505, 507, 509], 11 => [477, 480, 474, 475, 476, 478, 479, 481, 482], 12 => [621, 624, 625, 626, 631, 632, 633, 638, 639, 640, 645, 648, 651, 654, 655, 663, 664], 13 => [622, 627, 628, 629, 634, 635, 636, 641, 642, 643, 646, 649, 652, 656, 657, 665, 666], 14 => [620, 623, 630, 637, 644, 647, 650, 653, 658, 659, 660, 661, 662], 15 => [467, 468, 469, 470, 471, 472, 473, 483, 484, 485, 486, 487, 488, 908], 16 => [587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 688, 689, 691, 692, 693, 694, 695, 696], 18 => [668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684], 21 => [738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752], 23 => [795, 805, 804, 803, 802, 801, 800, 799, 798, 797, 796, 794, 793, 792, 791, 790, 789, 788, 787], 25 => [838, 837, 836, 835, 834, 833, 832, 831, 830, 829, 828, 827, 826, 825, 824, 823, 822, 821, 820], 27 => [880, 879, 878, 877, 876, 875, 874, 873, 872, 871, 870, 869, 868, 867, 866, 865, 864, 863, 862, 861, 860, 859, 858, 857, 856, 855, 854, 853, 852, 851, 850, 849, 848, 847, 846, 845, 844, 843], 29 => [901, 900, 899, 898, 897, 896, 895, 894, 893, 892, 891, 890, 889, 888, 887, 886, 885, 884, 883]); // well .. f**k $tagsByNamePart = array(17 => ['gladiator'], 19 => ['merciless'], 20 => ['vengeful'], 22 => ['brutal'], 24 => ['deadly', 'hateful', 'savage'], 26 => ['furious'], 28 => ['relentless'], 30 => ['wrathful']); DB::Aowow()->query('TRUNCATE TABLE ?_itemset'); $vIdx = 0; $virtualId = 0; $sets = DB::Aowow()->select('SELECT *, id AS ARRAY_KEY FROM dbc_itemset'); foreach ($sets as $setId => $setData) { $spells = $items = $mods = $descText = $name = $gains = []; $max = $reqLvl = $min = $quality = $heroic = $nPieces = []; $classMask = $type = 0; $hasRing = false; $holiday = isset($setToHoliday[$setId]) ? $setToHoliday[$setId] : 0; $canReuse = !$holiday; // can't reuse holiday-sets $slotList = []; $pieces = DB::World()->select('SELECT *, IF(InventoryType = 15, 26, IF(InventoryType = 5, 20, InventoryType)) AS slot, entry AS ARRAY_KEY FROM item_template WHERE itemset = ?d AND (class <> 4 OR subclass NOT IN (1, 2, 3, 4) OR armor > 0 OR Quality = 1) ORDER BY itemLevel, subclass, slot ASC', $setId); /****************************************/ /* determine type and reuse from pieces */ /****************************************/ // make the first vId always same as setId $firstPiece = reset($pieces); $tmp = [$firstPiece['Quality'] . $firstPiece['ItemLevel'] => $setId]; // walk through all items associated with the set foreach ($pieces as $itemId => $piece) { $classMask |= $piece['AllowableClass'] & CLASS_MASK_ALL; $key = $piece['Quality'] . str_pad($piece['ItemLevel'], 3, 0, STR_PAD_LEFT); if (!isset($tmp[$key])) { $tmp[$key] = --$vIdx; } $vId = $tmp[$key]; // check only actual armor in rare quality or higher (or inherits holiday) if ($piece['class'] != ITEM_CLASS_ARMOR || $piece['subclass'] == 0) { $canReuse = false; } /* gather relevant stats for use */ if (!isset($quality[$vId]) || $piece['Quality'] > $quality[$vId]) { $quality[$vId] = $piece['Quality']; } if ($piece['Flags'] & ITEM_FLAG_HEROIC) { $heroic[$vId] = true; } if (!isset($reqLvl[$vId]) || $piece['RequiredLevel'] > $reqLvl[$vId]) { $reqLvl[$vId] = $piece['RequiredLevel']; } if (!isset($min[$vId]) || $piece['ItemLevel'] < $min[$vId]) { $min[$vId] = $piece['ItemLevel']; } if (!isset($max[$vId]) || $piece['ItemLevel'] > $max[$vId]) { $max[$vId] = $piece['ItemLevel']; } if (!isset($items[$vId][$piece['slot']]) || !$canReuse) { if (!isset($nPieces[$vId])) { $nPieces[$vId] = 1; } else { $nPieces[$vId]++; } } if (isset($items[$vId][$piece['slot']])) { // not reusable -> insert anyway on unique keys if (!$canReuse) { $items[$vId][$piece['slot'] . $itemId] = $itemId; } else { CLISetup::log("set: " . $setId . " ilvl: " . $piece['ItemLevel'] . " - conflict between item: " . $items[$vId][$piece['slot']] . " and item: " . $itemId . " choosing lower itemId", CLISetup::LOG_WARN); if ($items[$vId][$piece['slot']] > $itemId) { $items[$vId][$piece['slot']] = $itemId; } } } else { $items[$vId][$piece['slot']] = $itemId; } /* check for type */ // skip cloaks, they mess with armor classes if ($piece['slot'] == 16) { continue; } // skip event-sets if ($piece['Quality'] == 1) { continue; } if ($piece['class'] == 2 && $piece['subclass'] == 0) { $type = 8; } else { if ($piece['class'] == 2 && $piece['subclass'] == 4) { $type = 9; } else { if ($piece['class'] == 2 && $piece['subclass'] == 7) { $type = 10; } else { if ($piece['class'] == 2 && $piece['subclass'] == 13) { $type = 7; } else { if ($piece['class'] == 2 && $piece['subclass'] == 15) { $type = 5; } } } } } // Dagger if (!$type) { if ($piece['class'] == 4 && $piece['slot'] == 12) { $type = 11; } else { if ($piece['class'] == 4 && $piece['slot'] == 2) { $type = 12; } else { if ($piece['class'] == 4 && $piece['subclass'] != 0) { $type = $piece['subclass']; } } } // 'armor' set if ($piece['class'] == 4 && $piece['slot'] == 11) { $hasRing = true; } // contains ring } } if ($hasRing && !$type) { $type = 6; } // pure ring-set $isMultiSet = false; $oldSlotMask = 0x0; foreach ($items as $subset) { $curSlotMask = 0x0; foreach ($subset as $slot => $item) { $curSlotMask |= 1 << $slot; } if ($oldSlotMask && $oldSlotMask == $curSlotMask) { $isMultiSet = true; break; } $oldSlotMask = $curSlotMask; } if (!$isMultiSet || !$canReuse || $setId == 555) { $temp = []; foreach ($items as $subset) { foreach ($subset as $slot => $item) { if (isset($temp[$slot]) && $temp[$slot] < $item) { CLISetup::log("set: " . $setId . " - conflict between item: " . $item . " and item: " . $temp[$slot] . " choosing lower itemId", CLISetup::LOG_WARN); } else { if ($slot == 13 || ($slot = 11)) { // special case $temp[] = $item; } else { $temp[$slot] = $item; } } } } $items = [$temp]; $heroic = [reset($heroic)]; $nPieces = [count($temp)]; $quality = [reset($quality)]; $reqLvl = [reset($reqLvl)]; $max = $max ? [max($max)] : [0]; $min = $min ? [min($min)] : [0]; } foreach ($items as &$subsets) { $subsets = array_pad($subsets, 10, 0); } /********************/ /* calc statbonuses */ /********************/ for ($i = 1; $i < 9; $i++) { if ($setData['spellId' . $i] > 0 && $setData['itemCount' . $i] > 0) { $spells[] = [$setData['spellId' . $i], $setData['itemCount' . $i]]; } } $bonusSpells = new SpellList(array(['s.id', array_column($spells, 0)])); $mods = $bonusSpells->getStatGain(); $spells = array_pad($spells, 8, [0, 0]); for ($i = 1; $i < 9; $i++) { if ($setData['itemCount' . $i] > 0 && !empty($mods[$setData['spellId' . $i]])) { $gains[$setData['itemCount' . $i]] = $mods[$setData['spellId' . $i]]; } } /**************************/ /* get name & description */ /**************************/ foreach ($locales as $loc) { User::useLocale($loc); $name[$loc] = Util::localizedString($setData, 'name'); foreach ($bonusSpells->iterate() as $__) { if (!isset($descText[$loc])) { $descText[$loc] = ''; } $descText[$loc] .= $bonusSpells->parseText()[0] . "\n"; } // strip rating blocks - e.g. <!--rtg19-->14 <small>(<!--rtg%19-->0.30% @ L<!--lvl-->80)</small> $descText[$loc] = preg_replace('/<!--rtg\\d+-->(\\d+) .*?<\\/small>/i', '\\1', $descText[$loc]); } /****************************/ /* finalaize data and write */ /****************************/ foreach ($items as $vId => $vSet) { $note = 0; foreach ($tagsById as $tag => $sets) { if (!in_array($setId, $sets)) { continue; } $note = $tag; } if (!$note && $min > 120 && $classMask && $classMask != CLASS_MASK_ALL) { foreach ($tagsByNamePart as $tag => $strings) { foreach ($strings as $str) { if (isset($pieces[reset($vSet)]) && stripos($pieces[reset($vSet)]['name'], $str) === 0) { $note = $tag; break 2; } } } } $row = []; $row[] = $vId < 0 ? --$virtualId : $setId; $row[] = $setId; // refSetId $row[] = 0; // cuFlags $row = array_merge($row, $name, $vSet); foreach (array_column($spells, 0) as $spellId) { $row[] = $spellId; } foreach (array_column($spells, 1) as $nItems) { $row[] = $nItems; } $row = array_merge($row, $descText); $row[] = serialize($gains); $row[] = $nPieces[$vId]; $row[] = $min[$vId]; $row[] = $max[$vId]; $row[] = $reqLvl[$vId]; $row[] = $classMask == CLASS_MASK_ALL ? 0 : $classMask; $row[] = !empty($heroic[$vId]) ? 1 : 0; $row[] = $quality[$vId]; $row[] = $type; $row[] = $note; // contentGroup $row[] = $holiday; $row[] = $setData['reqSkillId']; $row[] = $setData['reqSkillLevel']; DB::Aowow()->query('REPLACE INTO ?_itemset VALUES (?a)', array_values($row)); } } // hide empty sets DB::Aowow()->query('UPDATE ?_itemset SET cuFlags = cuFlags | ?d WHERE item1 = 0', CUSTOM_EXCLUDE_FOR_LISTVIEW); return true; }