- moved shared setup functions from FileGen to new CLISetup

- removed web-setup
- new CLI parameters
  --account    : create initial account(s)
  --siteconfig : edit php/aowow config values
  --dbconfig   : set up db connection
  --sql        : create db content from world/dbc-tables
  --firstrun   : [NYI] step by step initial setup

- some fixes by the wayside
  * display required arena bracket for extendedCost
  * achievement chains are searchable again
  * category trees for factions should now be correct
  * trainer tab on spell detail page reapeared
  * userMenu item 'Settings' no longer breaks the page
  * display abilities of shapeshift in tab on spell detail page
  * corrected reading ?_sourcestrings for titles
  * fixed error on race detail page
  * added simple descriptions to skill detail page
  * fixed tab "reward from" (achievement) on title detail page
  * fixed alphabetical order of some filter-dropdowns
  * fixed skill colors for spells
  * fixed power display for rune-based spells, that also cost mana
  * added more information to zones
  * also check mail_loot_template for achivements
  * fixed bug, where loot_template-ids would be reused for multiple templates
  * display sourcemore for pvp-sources
This commit is contained in:
Sarjuuk
2015-04-04 11:12:58 +02:00
parent 37be1b8113
commit 51f2828f6f
115 changed files with 7785 additions and 2804 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
setup/db_structure.7z Normal file

Binary file not shown.

View File

@@ -3,374 +3,84 @@
if (!defined('AOWOW_REVISION'))
die('invalid access');
function buildDirStruct($dir, &$idx = 1, $parent = [], $depths = 0) {
$struct = [];
if ($depths > 3)
return 'null';
$iterator = new RecursiveDirectoryIterator($dir);
$iterator->setFlags(RecursiveDirectoryIterator::SKIP_DOTS);
$basePath = '';
foreach ($iterator as $path)
{
$path = $path->getPathname();
if (!is_dir($path) || $path[0] == '.') // also skip hidden dirs
continue;
$idx++;
$newParent = $parent;
$newParent[] = basename($path);
$struct[] = "[".$idx.", \"".basename($path)."\", setPath.bind(this, el, '/".implode($newParent, '/')."'), ".buildDirStruct($path, $idx, $newParent, $depths + 1)."]";
}
return empty($struct) ? 'null' : '['.implode($struct, ",").']';
}
function checkDbcDir($dir, $reqFiles) {
$handle = opendir($dir);
$content = array();
while (false !== ($entry = readdir($handle))) {
if (is_dir($dir.'\\'.$entry))
continue;
$file = explode('.', $entry);
if ($file[1] == 'dbc')
$content[] = strToLower($file[0]);
}
if (!CLI)
die('not in cli mode');
if (empty($content))
return array(-4, null); // arbitrary directory .. silent death
foreach ($reqFiles as $k => $v) {
if (in_array(strToLower($v), $content))
unset($reqFiles[$k]);
}
if (empty($reqFiles)) {
$f = fopen($dir.'\\Resistances.dbc', 'rb');
// shared strings
define('ERR_CREATE_FILE', 'could not create file at destination %s' );
define('ERR_WRITE_FILE', 'could not write to file at destination %s' );
define('ERR_READ_FILE', 'file %s could not be read' );
define('ERR_MISSING_FILE', 'file %s not found' );
define('ERR_NONE', 'created file %s' );
define('ERR_MISSING_INCL', 'required function %s() could not be found at %s');
if (fread($f, 4) != "WDBC" || filesize($dir.'\\Resistances.dbc') < 20)
return array(-1, 'File looks like DBC but is not in proper format!');
require_once 'setup/tools/CLISetup.class.php';
require_once 'setup/tools/dbc.class.php';
require_once 'setup/tools/imagecreatefromblp.func.php';
$parse = dbc2array($dir.'\\Resistances.dbc', "xxxsssssssssxxxxxxxx");
for ($i = 0; $i <= 8; $i++) {
if (empty($parse[0][$i]))
continue;
if (in_array($i, array(0, 2, 3, 6, 8))) // en, X, fr, de, X, X, es, ru
return array($i, count($content));
else
return array(-2, 'locale ":$i." not supported!');
}
}
$path = array_pop(explode('\\', $dir));
return array(-3, 'Requird files are missing!', '<div>- '.str_replace($cwDir, '', $path).'\\'.implode($reqFiles, '.dbc<br />- '.str_replace($cwDir, '', $path).'\\').'.dbc</div>');
}
if (CLI || defined('TMP_BUILD'))
function finish()
{
require_once 'tools/filegen/fileGen.class.php';
require_once 'tools/dbc.class.php';
require_once 'tools/imagecreatefromblp.php';
if (!getopt('d', ['delete'])) // generated with TEMPORARY keyword. Manual deletion is not needed
CLISetup::log('generated dbc_* - tables kept available', CLISetup::LOG_WARN);
FileGen::init(@$pageParam ?: '');
if (FileGen::$subScripts)
/* send "i'm in use @" - ping
if ($ch = curl_init('http://aowow.meedns.com/pingback'))
{
// start file generation
FileGen::status('begin generation of '. implode(', ', FileGen::$subScripts));
FileGen::status();
// files with template
foreach (FileGen::$tplFiles as $name => list($file, $destPath))
{
if (!in_array($name, FileGen::$subScripts))
continue;
if (!file_exists(FileGen::$tplPath.$file.'.in'))
{
FileGen::status(sprintf(ERR_MISSING_FILE, FileGen::$tplPath.$file.'.in'), MSG_LVL_ERROR);
continue;
}
if (!FileGen::writeDir($destPath))
continue;
if ($content = file_get_contents(FileGen::$tplPath.$file.'.in'))
{
if ($dest = @fOpen($destPath.$file, "w"))
{
// replace constants
$content = strtr($content, FileGen::$txtConstants);
// must generate content
// PH format: /*setup:<setupFunc>*/
if (preg_match('/\/\*setup:([\w\d_-]+)\*\//i', $content, $m))
{
if (file_exists('setup/tools/filegen/'.$m[1].'.func.php'))
require_once 'setup/tools/filegen/'.$m[1].'.func.php';
else
{
FileGen::status(sprintf(ERR_MISSING_INCL, $m[1], 'setup/tools/filegen/'.$m[1].'.func.php'), MSG_LVL_ERROR);
continue;
}
if (function_exists($m[1]))
$content = str_replace('/*setup:'.$m[1].'*/', $m[1](), $content);
else
{
$content = '';
FileGen::status('Placeholder in template file does not match any known function name.', MSG_LVL_ERROR);
}
}
if (fWrite($dest, $content))
FileGen::status(sprintf(ERR_NONE, $destPath.$file), MSG_LVL_OK);
else
FileGen::status(sprintf(ERR_WRITE_FILE, $destPath.$file, MSG_LVL_ERROR));
fClose($dest);
}
else
FileGen::status(sprintf(ERR_CREATE_FILE, $destPath.$file), MSG_LVL_ERROR);
}
else
FileGen::status(sprintf(ERR_READ_FILE, FileGen::$tplPath.$file.'.in'), MSG_LVL_ERROR);
}
// files without template
foreach (FileGen::$datasets as $file)
{
if (!in_array($file, FileGen::$subScripts))
continue;
if (file_exists('setup/tools/filegen/'.$file.'.func.php'))
{
require_once 'setup/tools/filegen/'.$file.'.func.php';
if (function_exists($file))
FileGen::status(' - subscript \''.$file.'\' returned '.($file() ? 'sucessfully' : 'with errors'));
else
FileGen::status(' - subscript \''.$file.'\' not defined in included file', MSG_LVL_ERROR);
set_time_limit(FileGen::$defaultExecTime); // reset to default for the next script
}
else
FileGen::status(sprintf(ERR_MISSING_INCL, $file, 'setup/tools/filegen/'.$file.'.func.php', MSG_LVL_ERROR));
}
// end
FileGen::status();
FileGen::status('finished file generation');
$u = !empty($_SERVER['USER']) ? $_SERVER['USER'] : 'NULL';
$s = !empty($_SERVER['SSH_CONNECTION']) ? explode(' ', $_SERVER['SSH_CONNECTION'])[2] : 'NULL';
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "u=".$u."&s=".$s);
curl_exec($ch);
curl_close($ch);
}
else
FileGen::status('no valid script names supplied');
}
/*
else
{
if (isset($_GET['pathMenu'])) {
// set_time_limit(240); // parsing directory-structures seems to be costy...
die(buildDirStruct($cwDir.'/setup', $c));
}
$step = @intVal($_GET['step']);
$fields = @explode(';', $_GET['fields']);
if ($step == 1) {
// unset saved credentials
$_SESSION['step1']['progress'] &= ~(1 << $fields[0]);
$_SESSION['step1'][$fields[0]] = array($fields[1], $fields[3], $fields[4], $fields[2]);
// try to connect to db with data provided
$link = @mysql_connect($fields[1], $fields[3], $fields[4], true);
if ($link) {
switch ($fields[0]) {
case 0:
if (mysql_select_db($fields[2], $link)) {
if (mysql_fetch_row(mysql_query("SHOW TABLES FROM ".$fields[2]." LIKE '".$fields[5]."glyphpropperties'")))
die('{"errno":-1, "errstr":"Tables already present in this database will be overwritten!"}');
else {
$_SESSION['step1']['progress'] |= 0x1;
die('{"errno":0, "errstr":""}');
}
}
else if (mysql_errno() == 1044) // why doesn't this occur earlier?
die('{"errno":'.mysql_errno().', "errstr":"'.mysql_error().'"}');
else {
$_SESSION['step1']['progress'] |= 0x1;
die('{"errno":-1, "errstr":"Database will be created during installation!"}');
}
case 1:
if (mysql_select_db($fields[2], $link)) {
if (mysql_fetch_row(mysql_query("SHOW TABLES FROM ".$fields[2]." LIKE '".$fields[5]."item_template'"))) {
$_SESSION['step1']['progress'] |= 0x2;
die('{"errno":0, "errstr":""}');
}
}
break;
case 2:
if (mysql_select_db($fields[2], $link)) {
if (mysql_fetch_row(mysql_query("SHOW TABLES FROM ".$fields[2]." LIKE '".$fields[5]."account'"))) {
$_SESSION['step1']['progress'] |= 0x4;
die('{"errno":0, "errstr":""}');
}
}
break;
case 3:
if (mysql_select_db($fields[2], $link)) {
if (mysql_fetch_row(mysql_query("SHOW TABLES FROM ".$fields[2]." LIKE '".$fields[5]."characters'"))) {
$_SESSION['step1']['progress'] |= 0x8;
die('{"errno":0, "errstr":""}');
}
}
break;
}
if(!mysql_errno())
die('{"errno":-1, "errstr":"Required table not found in selected database!"}');
else
die('{"errno":'.mysql_errno().', "errstr":"'.mysql_error().'"}');
}
else
die('{"errno":'.mysql_errno().', "errstr":"'.mysql_error().'"}');
}
else if ($step == 2) {
$final = array();
// sanitize .. clamp dir-choice to DOCUMENT_ROOT
$dir = $cwDir.'/setup'.str_replace(['/..', '/.', '../', './'], '', str_replace(',', '/', $fields[1]));
// unset saved credentials
$_SESSION['step2']['progress'] &= ~(1 << $fields[0]);
$_SESSION['step2'][$fields[0]] = $dir;
if (!is_dir($dir))
die(json_encode(array(str_replace($cwDir, '', $dir) => array("errno" => 5, "errstr" => "Not a directory!"))));
$handle = opendir($dir);
switch ($fields[0]) {
case 0: {
$reqDBCs = array_keys($dbcStructure);
// check this directory
$result = checkDbcDir($dir, $reqDBCs);
if ($result[0] < 0 && isset($result[1]))
$final[str_replace($cwDir, '', $dir)] = array('errno' => -$result[0], 'errstr' => $result[1], 'tooltip' => $result[2]);
else if ($result[0] >= 0) {
if ($result[1] == 246)
$final[str_replace($cwDir, '', $dir)] = array('locale' => $result[0], 'errno' => 0, 'errstr' => '');
else
$final[str_replace($cwDir, '', $dir)] = array('locale' => $result[0], 'errno' => -1, 'errstr' => (246 - $result[1]).' optional files missing.');
}
// check first-level child direcotries
while (false !== ($entry = readdir($handle))) {
if ($entry == "." || $entry == "..")
continue;
if (is_dir($dir.'\\'.$entry) === true) {
$result = checkDbcDir($dir.'\\'.$entry, $reqDBCs);
if ($result[0] < 0 && isset($result[1]))
$final[$entry] = array('errno' => -$result[0], 'errstr' => $result[1], 'tooltip' => $result[2]);
else if ($result[0] >= 0) {
if ($result[1] == 246)
$final[$entry] = array('locale' => $result[0], 'errno' => 0, 'errstr' => '');
else
$final[$entry] = array('locale' => $result[0], 'errno' => -1, 'errstr' => (246 - $result[1]).' optional files missing.');
}
}
}
foreach ($final as $v)
if ($v['errno'] <= 0)
$_SESSION['step2']['progress'] |= 0x1;
die(json_encode($final));
}
case 1: {
$loc = array('enUS' => 0, 'enGB' => 0, 'frFR' => 2, 'deDE' => 3, 'esES' => 6, 'esMX' => 6, 'ruRU' => 8);
$expectDir = array('Icons' => array(6308, "/[\w\d\_]+[\.tga|\s|\.]?.blp/i"), 'Spellbook' => array(20, "/UI\-Glyph\-Rune\-[0-9]+\.blp/i"), 'Worldmap' => array(117));
foreach ($loc as $k => $v) {
if (!is_dir($dir.'\\'.$k))
continue;
if (isset($final[$v]))
continue;
$final[$v] = array();
$j = 0;
foreach ($expectDir as $sk => $sv) {
if (!is_dir($dir.'\\'.$k.'\\'.$sk))
break;
$handle = opendir($dir.'\\'.$k.'\\'.$sk);
$i = 0;
while (false !== ($entry = readdir($handle))) {
if (isset($sv[1])) {
if (is_dir($dir.'\\'.$k.'\\'.$sk.'\\'.$entry) === true)
continue;
if (preg_match($sv[1], $entry, $result))
$i++;
}
else {
if (is_dir($dir.'\\'.$k.'\\'.$sk.'\\'.$entry) === false || $entry == '.' || $entry == '..')
continue;
$i++;
}
}
if ($i == $sv[0]) {
$final[$v][$sk] = array('errno' => 0, 'errstr' => '');
$final['total'] |= (1 << $j);
}
else
$final[$v][$sk] = array('errno' => 1, 'errstr' => ($sv[0] - $i).' files missing in '.$k.'\\'.$sk.'!');
$j++;
}
if (empty($final[$v]))
$final[$v] = array('errno' => 3, 'errstr' => 'locale directory '.$k.' is empty!');
}
if ($final['total'] == 0x7)
$_SESSION['step2']['progress'] |= 0x2;
die(json_encode($final));
}
case 2: {
while (false !== ($entry = readdir($handle))) {
if (is_dir($entry) === true)
continue;
$file = explode('.', $entry);
if ($file[1] != 'sql')
continue;
$fRes = fopen($dir."\\".$entry, 'rb');
if (preg_match('/\/\* AoWoW 3\.3\.5 (en|fr|de|es|ru)[a-z]{2} locales \*\//i', fread($fRes, 30), $result))
$final[$result[1]] = str_replace($cwDir, '', $dir).'\\'.$entry;
}
if (!empty($final))
$_SESSION['step2']['progress'] |= 0x4;
die(json_encode($final));
}
}
}
include 'setup.tpl.php';
}
*/
die("\n");
}
$scriptOpt = getopt('', ['account', 'dbconfig', 'siteconfig', 'sql', 'build', 'sync']);
if (!$scriptOpt)
{
echo "\nAowow Setup\n";
echo "--dbconfig : set up db connection\n";
echo "--siteconfig : set up site variables\n";
echo "--account : create an account with admin privileges\n";
echo "--sql : generate db content from your world tables\n";
echo "--build : create server specific files\n";
echo "--sync=<tabelList,> : regenerate tables/files that depend on given world-table\n";
// echo "--firstrun : goes through the nessecary hoops of the initial setup. Can be interrupted and --resume'd";
echo "additional options\n";
echo "--log logfile : write ouput to file\n";
echo "--locales=<regionCodes,> : limit setup to enUS, frFR, deDE, esES and/or ruRU (does not override config settings)\n";
echo "--mpqDataDir=path/ : manually point to directory with extracted mpq files (default: setup/mpqData/)\n";
echo "--delete | -d : delete generated dbc_* tables when script finishes\n";
echo "--help | -h : contextual help\n";
die("\n");
}
else
CLISetup::init();
$cmd = array_pop(array_keys($scriptOpt));
switch ($cmd) // we accept only one main parameter
{
case 'account':
case 'dbconfig':
case 'siteconfig':
case 'sql':
case 'build':
require_once 'setup/tools/clisetup/'.$cmd.'.func.php';
$cmd();
finish();
case 'sync':
require_once 'setup/tools/clisetup/sql.func.php';
require_once 'setup/tools/clisetup/build.func.php';
sql();
build();
finish();
}
?>

View File

@@ -0,0 +1,401 @@
<?php
if (!defined('AOWOW_REVISION'))
die('invalid access');
if (!CLI)
die('not in cli mode');
class CLISetup
{
const CHR_BELL = 7;
const CHR_BACK = 8;
const CHR_TAB = 9;
const CHR_RETURN = 10;
const CHR_ESC = 27;
const CHR_BACKSPACE = 127;
const FILE_ACCESS = 0755;
const LOG_OK = 0;
const LOG_WARN = 1;
const LOG_ERROR = 2;
private static $win = true;
private static $logFile = '';
private static $logHandle = null;
public static $locales = [];
public static $localeIds = [];
public static $srcDir = 'setup/mpqdata/';
public static $tmpDBC = false;
private static $mpqFiles = [];
public static $expectedPaths = array( // update paths [yes, you can have en empty string as key]
'' => LOCALE_EN, 'enGB' => LOCALE_EN, 'enUS' => LOCALE_EN,
'frFR' => LOCALE_FR,
'deDE' => LOCALE_DE,
'esES' => LOCALE_ES, 'esMX' => LOCALE_ES,
'ruRU' => LOCALE_RU
);
public static function init()
{
self::$win = substr(PHP_OS, 0, 3) == 'WIN';
if ($_ = getopt('d', ['log::', 'locales::', 'mpqDataDir::', 'delete']))
{
// optional logging
if (!empty($_['log']))
self::$logFile = trim($_['log']);
// alternative data source (no quotes, use forward slash)
if (!empty($_['mpqDataDir']))
self::$srcDir = str_replace(['\\', '"', '\''], ['/', '', ''], $_['mpqDataDir']);
// optional limit handled locales
if (!empty($_['locales']))
{
// engb and enus are identical for all intents and purposes
$from = ['engb', 'esmx'];
$to = ['enus', 'eses'];
$_['locales'] = str_ireplace($from, $to, strtolower($_['locales']));
self::$locales = array_intersect(Util::$localeStrings, explode(',', $_['locales']));
}
if (isset($_['d']) || isset($_['delete']))
self::$tmpDBC = true;
}
if (!self::$locales)
self::$locales = array_filter(Util::$localeStrings);
// restrict actual locales
foreach (self::$locales as $idx => $str)
if (!defined('CFG_LOCALES') || CFG_LOCALES & (1 << $idx))
self::$localeIds[] = $idx;
}
/*******************/
/* MPQ-file access */
/*******************/
/* the problem
1) paths provided in dbc files are case-insensitive and random
2) paths to the actual textures contained in the mpq archives are case-insensitive and random
unix systems will throw a fit if you try to get from one to the other, so lets save the paths from 2) and cast it to lowecase
lookups will be done in lowercase. A successfull match will return the real path.
*/
private static function buildFileList()
{
self::log();
self::log('reading MPQdata from '.self::$srcDir.' to list for first time use...');
$setupDirs = glob('setup/*');
foreach ($setupDirs as $sd)
{
if (substr(self::$srcDir, -1) == '/')
self::$srcDir = substr(self::$srcDir, 0, -1);
if (substr($sd, -1) == '/')
$sd = substr($sd, 0, -1);
if (strtolower($sd) == strtolower(self::$srcDir))
{
self::$srcDir = $sd.'/';
break;
}
}
try
{
$iterator = new RecursiveDirectoryIterator(self::$srcDir);
$iterator->setFlags(RecursiveDirectoryIterator::SKIP_DOTS);
foreach (new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::SELF_FIRST) as $path)
{
$_ = str_replace('\\', '/', $path->getPathname());
self::$mpqFiles[strtolower($_)] = $_;
}
self::log('done');
self::log();
}
catch (UnexpectedValueException $e)
{
self::log('- mpqData dir '.self::$srcDir.' does not exist', self::LOG_ERROR);
return false;
}
return true;
}
public static function fileExists(&$file)
{
// read mpq source file structure to tree
if (!self::$mpqFiles)
if (!self::buildFileList())
return false;
// backslash to forward slash
$_ = strtolower(str_replace('\\', '/', $file));
// remove trailing slash
if (substr($_, -1, 1) == '/')
$_ = substr($_, 0, -1);
if (isset(self::$mpqFiles[$_]))
{
$file = self::$mpqFiles[$_];
return true;
}
return false;
}
public static function filesInPath($path, $useRegEx = false)
{
$result = [];
// read mpq source file structure to tree
if (!self::$mpqFiles)
if (!self::buildFileList())
return [];
// backslash to forward slash
$_ = strtolower(str_replace('\\', '/', $path));
foreach (self::$mpqFiles as $lowerFile => $realFile)
{
if (!$useRegEx && strstr($lowerFile, $_))
$result[] = $realFile;
else if ($useRegEx && preg_match($path, $lowerFile))
$result[] = $realFile;
}
return $result;
}
/***********/
/* logging */
/***********/
public static function red($str)
{
return "\e[31m".$str."\e[0m";
}
public static function green($str)
{
return "\e[32m".$str."\e[0m";
}
public static function yellow($str)
{
return "\e[33m".$str."\e[0m";
}
public static function bold($str)
{
return "\e[1m".$str."\e[0m";
}
public static function log($txt = '', $lvl = -1)
{
if (self::$logFile && !self::$logHandle)
{
if (!file_exists(self::$logFile))
self::$logHandle = fopen(self::$logFile, 'w');
else
{
$logFileParts = pathinfo(self::$logFile);
$i = 1;
while (file_exists($logFileParts['dirname'].'/'.$logFileParts['filename'].$i.(isset($logFileParts['extension']) ? '.'.$logFileParts['extension'] : '')))
$i++;
self::$logFile = $logFileParts['dirname'].'/'.$logFileParts['filename'].$i.(isset($logFileParts['extension']) ? '.'.$logFileParts['extension'] : '');
self::$logHandle = fopen(self::$logFile, 'w');
}
}
$msg = "\n";
if ($txt)
{
$msg = str_pad(date('H:i:s'), 10);
switch ($lvl)
{
case self::LOG_ERROR: // red error
$msg .= '['.self::red('ERR').'] ';
break;
case self::LOG_WARN: // yellow warn
$msg .= '['.self::yellow('INFO').'] ';
break;
case self::LOG_OK: // green success
$msg .= '['.self::green('OK').'] ';
break;
default:
$msg .= ' ';
}
$msg .= $txt."\n";
}
// remove highlights for logging & win
$raw = preg_replace(["/\e\[\d+m/", "/\e\[0m/"], '', $msg);
echo self::$win ? $raw : $msg;
if (self::$logHandle)
fwrite(self::$logHandle, $raw);
flush();
}
/*****************/
/* file handling */
/*****************/
public static function writeFile($file, $content)
{
$success = false;
if ($handle = @fOpen($file, "w"))
{
if (fWrite($handle, $content))
{
$success = true;
self::log(sprintf(ERR_NONE, self::bold($file)), self::LOG_OK);
}
else
self::log(sprintf(ERR_WRITE_FILE, self::bold($file)), self::LOG_ERROR);
fClose($handle);
}
else
self::log(sprintf(ERR_CREATE_FILE, self::bold($file)), self::LOG_ERROR);
if ($success)
@chmod($file, self::FILE_ACCESS);
return $success;
}
public static function writeDir($dir)
{
if (is_dir($dir))
{
if (!is_writable($dir) && !@chmod($dir, self::FILE_ACCESS))
self::log('cannot write into output directory '.$dir, self::LOG_ERROR);
return is_writable($dir);
}
if (@mkdir($dir, self::FILE_ACCESS, true))
return true;
self::log('could not create output directory '.$dir, self::LOG_ERROR);
return false;
}
public static function loadDBC($name)
{
if (DB::Aowow()->selectCell('SHOW TABLES LIKE ?', 'dbc_'.$name) && DB::Aowow()->selectCell('SELECT count(1) FROM ?#', 'dbc_'.$name))
return true;
$dbc = new DBC($name, self::$tmpDBC);
if ($dbc->error)
return false;
if ($dbc->readFromFile())
{
$dbc->writeToDB();
return true;
}
self::log('SqlGen::generate() - required DBC '.$name.'.dbc found neither in DB nor as file!', self::LOG_ERROR);
return false;
}
/**************/
/* read input */
/**************/
public static function readInput(&$fields, $singleChar = false)
{
// prevent default output
readline_callback_handler_install('', function() { });
foreach ($fields as $name => $data)
{
$vars = ['desc', 'isHidden', 'validPattern'];
foreach ($vars as $idx => $v)
$$v = isset($data[$idx]) ? $data[$idx] : false;
$charBuff = '';
if ($desc)
echo "\n".$desc.": ";
while (true) {
$r = [STDIN];
$w = $e = null;
$n = stream_select($r, $w, $e, 200000);
if ($n && in_array(STDIN, $r)) {
$char = stream_get_contents(STDIN, 1);
$keyId = ord($char);
if ($keyId == self::CHR_TAB) // ignore this one
continue;
if ($keyId == self::CHR_ESC)
{
echo chr(self::CHR_BELL);
return false;
}
else if ($keyId == self::CHR_BACKSPACE)
{
if (!$charBuff)
continue;
$charBuff = substr($charBuff, 0, -1);
echo chr(self::CHR_BACK)." ".chr(self::CHR_BACK);
}
else if ($keyId == self::CHR_RETURN)
{
$fields[$name] = $charBuff;
break;
}
else if (!$validPattern || preg_match($validPattern, $char))
{
$charBuff .= $char;
if (!$isHidden)
echo $char;
if ($singleChar)
{
$fields[$name] = $charBuff;
break;
}
}
}
}
}
echo chr(self::CHR_BELL);
foreach ($fields as $f)
if (strlen($f))
return true;
$fields = null;
return true;
}
}
?>

View File

@@ -0,0 +1,62 @@
<?php
if (!defined('AOWOW_REVISION'))
die('invalid access');
if (!CLI)
die('not in cli mode');
/********************/
/* Account creation */
/********************/
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);
}
}
?>

View File

@@ -0,0 +1,118 @@
<?php
if (!defined('AOWOW_REVISION'))
die('invalid access');
if (!CLI)
die('not in cli mode');
/*************************/
/* Create required files */
/*************************/
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))
{
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;
$ok = false;
if ($content = file_get_contents(FileGen::$tplPath.$file.'.in'))
{
if ($dest = @fOpen($destPath.$file, "w"))
{
// replace constants
$content = strtr($content, FileGen::$txtConstants);
// must generate content
// PH format: /*setup:<setupFunc>*/
if (preg_match('/\/\*setup:([\w\d_-]+)\*\//i', $content, $m))
{
$content = '';
if (file_exists('setup/tools/filegen/'.$m[1].'.func.php'))
{
require_once 'setup/tools/filegen/'.$m[1].'.func.php';
if (function_exists($m[1]))
$content = str_replace('/*setup:'.$m[1].'*/', $m[1](), $content);
else
CLISetup::log('Placeholder in template file does not match any known function name.', CLISetup::LOG_ERROR);
}
else
CLISetup::log(sprintf(ERR_MISSING_INCL, $m[1], 'setup/tools/filegen/'.$m[1].'.func.php'), CLISetup::LOG_ERROR);
}
if (fWrite($dest, $content))
{
CLISetup::log(sprintf(ERR_NONE, CLISetup::bold($destPath.$file)), CLISetup::LOG_OK);
if ($content)
$ok = 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);
if (!$ok)
$allOk = false;
}
// 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(SqlGen::$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);
}
?>

View File

@@ -0,0 +1,142 @@
<?php
if (!defined('AOWOW_REVISION'))
die('invalid access');
if (!CLI)
die('not in cli mode');
/**************************/
/* Configure DB connection*/
/**************************/
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, 12);
$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 ($name == 'characters' && empty($AoWoWconf[$name][0]))
$AoWoWconf[$name][0] = array_combine(array_keys($dbFields), ['', '', '', '', '']);
else if (empty($AoWoWconf[$name]))
$AoWoWconf[$name] = array_combine(array_keys($dbFields), ['', '', '', '', '']);
}
while (true)
{
CLISetup::log();
CLISetup::log("select a numerical index to use the corresponding entry");
$charOffset = 0;
foreach ($databases as $idx => $name)
{
if ($idx != 3)
CLISetup::log($testDB($idx, $name, $AoWoWconf[$name]));
else
foreach ($AoWoWconf[$name] as $charIdx => $dbInfo)
CLISetup::log($testDB($idx + $charOffset++, $name, $AoWoWconf[$name][$charIdx]));
}
CLISetup::log("[".CLISetup::bold(3 + $charOffset)."] add an additional Character DB");
while (true)
{
$inp = ['idx' => ['', true, '/\d/']];
if (CLISetup::readInput($inp, true) && $inp)
{
if (is_numeric($inp['idx']) && $inp['idx'] >= 0 && $inp['idx'] <= (3 + $charOffset))
{
$curFields = $dbFields;
if (CLISetup::readInput($curFields))
{
if ($inp['idx'] < 3)
$AoWoWconf[$databases[$inp['idx']]] = $curFields ?: array_combine(array_keys($dbFields), ['', '', '', '', '']);
else if ($inp['idx'] == 3 + $charOffset)
{
if ($curFields)
$AoWoWconf[$databases[3]][] = $curFields;
}
else
{
$i = 0;
foreach ($AoWoWconf[$databases[3]] as $offset => &$dbInfo)
{
if ($inp['idx'] - 3 != $i++)
continue;
if ($curFields)
$dbInfo = $curFields;
else
unset($AoWoWconf[$databases[3]][$offset]);
}
}
// 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;
}
}
}
}
?>

View File

@@ -0,0 +1,318 @@
<?php
if (!defined('AOWOW_REVISION'))
die('invalid access');
if (!CLI)
die('not in cli mode');
/****************************/
/* Configure Site variables */
/****************************/
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;
}
}
}
// edit existing setting
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 ($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;
}
}
}
?>

View File

@@ -0,0 +1,52 @@
<?php
if (!defined('AOWOW_REVISION'))
die('invalid access');
if (!CLI)
die('not in cli mode');
/************************************************/
/* Create content from world tables / dbc files */
/************************************************/
function sql($syncMe = [])
{
require_once 'setup/tools/sqlGen.class.php';
SqlGen::init();
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;
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);
}
?>

View File

@@ -22,77 +22,224 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/*
Supported format characters:
x - not used/unknown, 4 bytes
X - not used/unknown, 1 byte
s - char*
f - float, 4 bytes (rounded to 4 digits after comma)
u - unsigned int, 4 bytes
i - signed int, 4 bytes
b - unsigned char, 1 byte
d - sorted by this field, not included in array
n - same, but field included in array
*/
class DBC
{
private $_formats = array(
'talent' => 'niiiiiiiixxxxixxixxixii',
'talenttab' => 'nsxssxxsxsxxxxxxxxiiiiis',
'gtchancetomeleecrit' => 'f',
'gtchancetomeleecritbase' => 'f',
'gtchancetospellcrit' => 'f',
'gtchancetospellcritbase' => 'f',
'gtoctregenhp' => 'f',
'gtregenmpperspt' => 'f',
'gtregenhpperspt' => 'f',
'spellicon' => 'ns',
'itemdisplayinfo' => 'nssxxsxxxxxxxxxxxxxxxxxxx',
'holidays' => 'nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxxxxxxxiisxix',
'chrclasses' => 'nxixsxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxsxixi',
'worldmaparea' => 'niisffffxix', // 4.x - niisffffxixxxx
'worldmapoverlay' => 'niixxxxxsiiiixxxx', // 4.x - niixxxsiiiixxxx
private $_formats = array( // locales block for copy pasta: sxssxxsxsxxxxxxxx | xxxxxxxxxxxxxxxxx
'achievement' => 'niiisxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxiiiiisxssxxsxsxxxxxxxxii',
'achievement_category' => 'nisxssxxsxsxxxxxxxxx',
'achievement_criteria' => 'niiiiiiiisxssxxsxsxxxxxxxxiixii',
'areatable' => 'niixixxxxxxsxssxxsxsxxxxxxxxixxxxxxx',
'battlemasterlist' => 'niixxxxxxixxxxxxxxxxxxxxxxxxixii',
'charbaseinfo' => 'bb',
'charstartoutfit' => 'nbbbXiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'chartitles' => 'nxsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxx',
'chrclasses' => 'nxixsxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxsxixi',
'chrraces' => 'niixxxxixxxsxisxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi',
'creaturedisplayinfo' => 'nixixxssssxxxxxx',
'creaturedisplayinfoextra' => 'nxxxxxxxxxxxxxxxxxxxs',
'creaturefamily' => 'nxxxxixiiisxssxxsxsxxxxxxxxs',
'currencytypes' => 'niix',
'dungeonmap' => 'niiffffi',
'durabilitycosts' => 'niiiiiiiiixiiiiiiiiiiixiiiixix',
'durabilityquality' => 'nf',
'faction' => 'nixxxxxxxxxxxxixxxiffixsxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxx',
'factiontemplate' => 'nixiiiiiiiiiii',
'gemproperties' => 'nixxi',
'glyphproperties' => 'niii',
'gtchancetomeleecrit' => 'f',
'gtchancetomeleecritbase' => 'f',
'gtchancetospellcrit' => 'f',
'gtchancetospellcritbase' => 'f',
'gtoctregenhp' => 'f',
'gtregenmpperspt' => 'f',
'gtregenhpperspt' => 'f',
'holidays' => 'nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxxxxxxxiisxix',
'holidaydescriptions' => 'nsxssxxsxsxxxxxxxx',
'holidaynames' => 'nsxssxxsxsxxxxxxxx',
'itemdisplayinfo' => 'nssxxsxxxxxxxxxxxxxxxxxxx',
'itemextendedcost' => 'niiiiiiiiiiiiiix',
'itemlimitcategory' => 'nsxssxxsxsxxxxxxxxii',
'itemrandomproperties' => 'nsiiiiisxssxxsxsxxxxxxxx',
'itemrandomsuffix' => 'nsxssxxsxsxxxxxxxxsiiiiiiiiii',
'itemset' => 'nsxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiiiii',
'lfgdungeons' => 'nsxssxxsxsxxxxxxxxiiiiiiixiixixixxxxxxxxxxxxxxxxx',
'lock' => 'niiiiixxxiiiiixxxiiiiixxxxxxxxxxx',
'mailtemplate' => 'nsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxx',
'map' => 'nsixisxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiffxixi',
'mapdifficulty' => 'niixxxxxxxxxxxxxxxxxxis',
'powerdisplay' => 'nisbbb',
'questfactionreward' => 'niiiiiiiiii',
'questxp' => 'niiiiiiiiii',
'randproppoints' => 'niiiiiiiiiiiiiii',
'scalingstatdistribution' => 'niiiiiiiiiiiiiiiiiiiii',
'scalingstatvalues' => 'niiiiiiiiiiiiiiiiiiiiiii',
'skillline' => 'nixsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxixxxxxxxxxxxxxxxxxx',
'skilllineability' => 'niiiixxixiiixx',
'skillraceclassinfo' => 'niiiiixx',
'spell' => 'niiiuuuuuuuuixixxxixxxxxxxxxiiixxxxiiiiiiiiiiiixxiiiiiiiiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffiiiiiiiiixxiixsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxiiiiiiiiiixxfffxxxiixiixifffii',
'spellcasttimes' => 'nixx',
'spelldescriptionvariables' => 'ns',
'spelldifficulty' => 'xiiii',
'spellduration' => 'nixx',
'spellfocusobject' => 'nsxssxxsxsxxxxxxxx',
'spellicon' => 'ns',
'spellitemenchantment' => 'nxiiiiiixxxiiisxssxxsxsxxxxxxxxxxiiiii',
'spellitemenchantmentcondition' => 'nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX',
'spellradius' => 'nfxf',
'spellrange' => 'nffffisxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxx',
'spellrunecost' => 'niiii',
'spellshapeshiftform' => 'nxsxssxxsxsxxxxxxxxiixxiixxiiiiiiii',
'talent' => 'niiiiiiiixxxxixxixxixii',
'talenttab' => 'nsxssxxsxsxxxxxxxxiiiiis',
'taxinodes' => 'niffxsxssxxsxsxxxxxxxxxx',
'taxipath' => 'niix',
'taxipathnode' => 'niiiffxxxxx',
'totemcategory' => 'nsxssxxsxsxxxxxxxxiu',
'worldmaparea' => 'niisffffxix', // 4.x - niisffffxixxxx
'worldmapoverlay' => 'niixxxxxsiiiixxxx', // 4.x - niixxxsiiiixxxx
'worldmaptransforms' => 'niffffiffi',
);
private $_fields = array(
'talent' => 'Id,tabId,row,column,rank1,rank2,rank3,rank4,rank5,reqTalent,reqRank,talentSpell,petCategory1,petCategory2',
'talenttab' => 'Id,nameEN,nameFR,nameDE,nameES,nameRU,iconId,raceMask,classMask,creatureFamilyMask,tabNumber,textureFile',
'gtchancetomeleecrit' => 'chance',
'gtchancetomeleecritbase' => 'chance',
'gtchancetospellcrit' => 'chance',
'gtchancetospellcritbase' => 'chance',
'gtoctregenhp' => 'ratio',
'gtregenmpperspt' => 'ratio',
'gtregenhpperspt' => 'ratio',
'spellicon' => 'Id,iconPath',
'itemdisplayinfo' => 'Id,leftModelName,rightModelName,inventoryIcon1',
'holidays' => 'Id,looping,nameId,descriptionId,textureString,scheduleType',
'chrclasses' => 'Id,powerType,nameMaleEN,nameMaleFR,nameMaleDE,nameMaleES,nameMaleRU,nameINT,flags,addon',
'worldmaparea' => 'Id,mapId,areaId,nameINT,left,right,top,bottom,defaultDungeonMapId',
'worldmapoverlay' => 'Id,worldMapAreaId,areaTableId,textureString,w,h,x,y',
'achievement' => 'Id,faction,map,previous,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,description_loc0,description_loc2,description_loc3,description_loc6,description_loc8,category,points,orderInGroup,flags,iconId,reward_loc0,reward_loc2,reward_loc3,reward_loc6,reward_loc8,reqCriteriaCount,refAchievement',
'achievement_category' => 'Id,parentCategory,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8',
'achievement_criteria' => 'Id,refAchievementId,type,value1,value2,value3,value4,value5,value6,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,completionFlags,groupFlags,timeLimit,order',
'areatable' => 'Id,mapId,areaTable,flags,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,factionGroupMask',
'battlemasterlist' => 'Id,mapId,moreMapId,areaType,maxPlayers,minLevel,maxLevel',
'charbaseinfo' => 'raceId,classId',
'charstartoutfit' => 'Id,raceId,classId,gender,item1,item2,item3,item4,item5,item6,item7,item8,item9,item10,item11,item12,item13,item14,item15,item16,item17,item18,item19,item20',
'chartitles' => 'Id,male_loc0,male_loc2,male_loc3,male_loc6,male_loc8,female_loc0,female_loc2,female_loc3,female_loc6,female_loc8',
'chrclasses' => 'Id,powerType,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,fileString,flags,expansion',
'chrraces' => 'Id,flags,factionId,baseLanguage,fileString,side,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,expansion',
'creaturedisplayinfo' => 'Id,modelid,extraInfoId,skin1,skin2,skin3,iconString',
'creaturedisplayinfoextra' => 'Id,textureString',
'creaturefamily' => 'Id,skillLine1,petFoodMask,petTalentType,categoryEnumID,name_loc0,name_loc2,name_loc3,name_lo6,name_loc8,iconString',
'currencytypes' => 'Id,itemId,category',
'dungeonmap' => 'Id,mapId,floor,minY,maxY,minX,maxX,areaId',
'durabilitycosts' => 'Id,w0,w1,w2,w3,w4,w5,w6,w7,w8,w10,w11,w12,w13,w14,w15,w16,w17,w18,w19,w20,a1,a2,a3,a4,a6',
'durabilityquality' => 'Id,mod',
'faction' => 'Id,repIdx,repFlags1,parentFaction,spilloverRateIn,spilloverRateOut,spilloverMaxRank,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8',
'factiontemplate' => 'Id,factionId,ourMask,friendlyMask,hostileMask,enemyFactionId1,enemyFactionId2,enemyFactionId3,enemyFactionId4,friendFactionId1,friendFactionId2,friendFactionId3,friendFactionId4',
'gemproperties' => 'Id,enchantmentId,colorMask',
'glyphproperties' => 'Id,spellId,typeFlags,iconId',
'gtchancetomeleecrit' => 'chance',
'gtchancetomeleecritbase' => 'chance',
'gtchancetospellcrit' => 'chance',
'gtchancetospellcritbase' => 'chance',
'gtoctregenhp' => 'ratio',
'gtregenmpperspt' => 'ratio',
'gtregenhpperspt' => 'ratio',
'holidays' => 'Id,looping,nameId,descriptionId,textureString,scheduleType',
'holidaydescriptions' => 'Id,description_loc0,description_loc2,description_loc3,description_loc6,description_loc8',
'holidaynames' => 'Id,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8',
'itemdisplayinfo' => 'Id,leftModelName,rightModelName,inventoryIcon1',
'itemextendedcost' => 'Id,reqHonorPoints,reqArenaPoints,reqArenaSlot,reqItemId1,reqItemId2,reqItemId3,reqItemId4,reqItemId5,itemCount1,itemCount2,itemCount3,itemCount4,itemCount5,reqPersonalRating',
'itemlimitcategory' => 'Id,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,count,isGem',
'itemrandomproperties' => 'Id,nameINT,enchantId1,enchantId2,enchantId3,enchantId4,enchantId5,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8',
'itemrandomsuffix' => 'Id,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,nameINT,enchantId1,enchantId2,enchantId3,enchantId4,enchantId5,allocationPct1,allocationPct2,allocationPct3,allocationPct4,allocationPct5',
'itemset' => 'Id,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,spellId1,spellId2,spellId3,spellId4,spellId5,spellId6,spellId7,spellId8,itemCount1,itemCount2,itemCount3,itemCount4,itemCount5,itemCount6,itemCount7,itemCount8,reqSkillId,reqSkillLevel',
'lfgdungeons' => 'Id,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,levelMin,levelMax,targetLevel,targetLevelMin,targetLevelMax,mapId,difficulty,type,faction,expansion,groupId',
'lock' => 'Id,type1,type2,type3,type4,type5,properties1,properties2,properties3,properties4,properties5,reqSkill1,reqSkill2,reqSkill3,reqSkill4,reqSkill5',
'mailtemplate' => 'Id,subject_loc0,subject_loc2,subject_loc3,subject_loc6,subject_loc8,text_loc0,text_loc2,text_loc3,text_loc6,text_loc8',
'map' => 'Id,nameINT,areaType,isBG,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,parentMapId,parentX,parentY,expansion,maxPlayers',
'mapdifficulty' => 'Id,mapId,difficulty,nPlayer,nPlayerString',
'powerdisplay' => 'Id,realType,globalString,r,g,b',
'questfactionreward' => 'Id,field1,field2,field3,field4,field5,field6,field7,field8,field9,field10',
'questxp' => 'Id,field1,field2,field3,field4,field5,field6,field7,field8,field9,field10',
'randproppoints' => 'Id,epic1,epic2,epic3,epic4,epic5,rare1,rare2,rare3,rare4,rare5,uncommon1,uncommon2,uncommon3,uncommon4,uncommon5',
'scalingstatdistribution' => 'Id,statMod1,statMod2,statMod3,statMod4,statMod5,statMod6,statMod7,statMod8,statMod9,statMod10,modifier1,modifier2,modifier3,modifier4,modifier5,modifier6,modifier7,modifier8,modifier9,modifier10,maxLevel',
'scalingstatvalues' => 'Id,charLevel,shoulderMultiplier,trinketMultiplier,weaponMultiplier,rangedMultiplier,clothShoulderArmor,leatherShoulderArmor,mailShoulderArmor,plateShoulderArmor,weaponDPS1H,weaponDPS2H,casterDPS1H,casterDPS2H,rangedDPS,wandDPS,spellPower,primBudged,tertBudged,clothCloakArmor,clothChestArmor,leatherChestArmor,mailChestArmor,plateChestArmor',
'skillline' => 'Id,categoryId,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,description_loc0,description_loc2,description_loc3,description_loc6,description_loc8,iconId',
'skilllineability' => 'Id,skillLineId,spellId,reqRaceMask,reqClassMask,reqSkillLevel,acquireMethod,skillLevelGrey,skillLevelYellow',
'skillraceclassinfo' => 'Id,skillLine,raceMask,classMask,flags,reqLevel',
'spell' => 'Id,category,dispelType,mechanic,attributes0,attributes1,attributes2,attributes3,attributes4,attributes5,attributes6,attributes7,stanceMask,stanceMaskNot,spellFocus,castTimeId,recoveryTime,recoveryTimeCategory,procChance,procCharges,maxLevel,baseLevel,spellLevel,durationId,powerType,powerCost,powerCostPerLevel,powerPerSecond,powerPerSecondPerLevel,rangeId,stackAmount,tool1,tool2,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,effect1RadiusId,effect2RadiusId,effect3RadiusId,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,iconId,iconIdActive,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,rank_loc0,rank_loc2,rank_loc3,rank_loc6,rank_loc8,description_loc0,description_loc2,description_loc3,description_loc6,description_loc8,buff_loc0,buff_loc2,buff_loc3,buff_loc6,buff_loc8,powerCostPercent,startRecoveryCategory,startRecoveryTime,maxTargetLevel,spellFamilyId,spellFamilyFlags1,spellFamilyFlags2,spellFamilyFlags3,maxAffectedTargets,damageClass,effect1DamageMultiplier,effect2DamageMultiplier,effect3DamageMultiplier,toolCategory1,toolCategory2,schoolMask,runeCostId,powerDisplayId,effect1BonusMultiplier,effect2BonusMultiplier,effect3BonusMultiplier,spellDescriptionVariable,spellDifficulty',
'spellcasttimes' => 'Id,baseTime',
'spelldescriptionvariables' => 'Id,vars',
'spellduration' => 'Id,baseTime',
'spelldifficulty' => 'normal10,normal25,heroic10,heroic25',
'spellfocusobject' => 'Id,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8',
'spellicon' => 'Id,iconPath',
'spellitemenchantment' => 'Id,type1,type2,type3,amount1,amount2,amount3,object1,object2,object3,text_loc0,text_loc2,text_loc3,text_loc6,text_loc8,gemReference,conditionId,skillLine,skillLevel,requiredLevel',
'spellitemenchantmentcondition' => 'Id,color1,color2,color3,color4,color5,comparator1,comparator2,comparator3,comparator4,comparator5,cmpColor1,cmpColor2,cmpColor3,cmpColor4,cmpColor5,value1,value2,value3,value4,value5',
'spellradius' => 'Id,radiusMin,radiusMax',
'spellrange' => 'Id,rangeMinHostile,rangeMinFriend,rangeMaxHostile,rangeMaxFriend,rangeType,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8',
'spellrunecost' => 'Id,costBlood,costUnholy,costFrost,runicPowerGain',
'spellshapeshiftform' => 'Id,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,flags,creatureType,displayIdA,displayIdH,spellId1,spellId2,spellId3,spellId4,spellId5,spellId6,spellId7,spellId8',
'talent' => 'Id,tabId,row,column,rank1,rank2,rank3,rank4,rank5,reqTalent,reqRank,talentSpell,petCategory1,petCategory2',
'talenttab' => 'Id,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,iconId,raceMask,classMask,creatureFamilyMask,tabNumber,textureFile',
'taxinodes' => 'Id,mapId,posX,posY,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8',
'taxipath' => 'Id,startNodeId,endNodeId',
'taxipathnode' => 'Id,pathId,nodeIdx,mapId,posX,posY',
'totemcategory' => 'Id,name_loc0,name_loc2,name_loc3,name_loc6,name_loc8,category,categoryMask',
'worldmaparea' => 'Id,mapId,areaId,nameINT,left,right,top,bottom,defaultDungeonMapId',
'worldmapoverlay' => 'Id,worldMapAreaId,areaTableId,textureString,w,h,x,y',
'worldmaptransforms' => 'Id,sourceMapId,minX,minY,maxX,maxY,targetMapId,offsetX,offsetY,dungeonMapId',
);
private $isGameTable = false;
private $localized = false;
private $tempTable = true;
public $error = true;
public $result = [];
public $fields = [];
public $format = '';
public $file = '';
public function __construct($file)
public function __construct($file, $tmpTbl = null)
{
$file = strtolower($file);
if (empty($this->_fields[$file]) || empty($this->_formats[$file]))
{
FileGen::status('no structure known for '.$file.'.dbc, aborting.', MSG_LVL_ERROR);
CLISetup::log('no structure known for '.$file.'.dbc, aborting.', CLISetup::LOG_ERROR);
return;
}
$this->fields = explode(',', $this->_fields[$file]);
$this->format = $this->_formats[$file];
$this->file = $file;
$this->localized = !!strstr($this->format, 'sxssxxsxsxxxxxxxx');
if (is_bool($tmpTbl))
$this->tempTable = $tmpTbl;
if (count($this->fields) != strlen(str_ireplace('x', '', $this->format)))
{
CLISetup::log('known field types ['.count($this->fields).'] and names ['.strlen(str_ireplace('x', '', $this->format)).'] do not match for '.$file.'.dbc, aborting.', CLISetup::LOG_ERROR);
return;
}
// gameTable-DBCs don't have an index and are accessed through value order
// allas, you cannot do this with mysql, so we add a 'virtual' index
$this->isGameTable = $this->format == 'f' && substr($file, 0, 2) == 'gt';
$this->error = false;
}
public function writeToDB()
{
if (!$this->result)
if (!$this->result || $this->error)
return false;
$n = 0;
$pKey = $this->fields[0];
$query = 'CREATE TABLE `dbc_'.$this->file.'` (';
$pKey = '';
$query = 'CREATE '.($this->tempTable ? 'TEMPORARY' : '').' TABLE `dbc_'.$this->file.'` (';
if ($this->isGameTable)
{
@@ -102,20 +249,36 @@ class DBC
foreach (str_split($this->format) as $idx => $f)
{
if ($f == 'f')
$query .= '`'.$this->fields[$n].'` FLOAT NOT NULL, ';
else if ($f == 's' || $f == 'b')
$query .= '`'.$this->fields[$n].'` TEXT NOT NULL, ';
else if ($f == 'i' || $f == 'n')
$query .= '`'.$this->fields[$n].'` BIGINT(20) NOT NULL, ';
switch ($f)
{
case 'f':
$query .= '`'.$this->fields[$n].'` FLOAT NOT NULL, ';
break;
case 's':
$query .= '`'.$this->fields[$n].'` TEXT NOT NULL, ';
break;
case 'i':
case 'n':
case 'b':
case 'u':
$query .= '`'.$this->fields[$n].'` BIGINT(20) NOT NULL, ';
break;
default: // 'x', 'X', 'd'
continue 2;
}
if ($f == 'n')
$pKey = $this->fields[$n];
if ($f != 'x')
$n++;
$n++;
}
$query .= 'PRIMARY KEY (`'.$pKey.'`)) COLLATE=\'utf8_general_ci\' ENGINE=MyISAM';
if ($pKey)
$query .= 'PRIMARY KEY (`'.$pKey.'`) ';
else
$query = substr($query, 0, -2);
$query .= ') COLLATE=\'utf8_general_ci\' ENGINE=MyISAM';
DB::Aowow()->query('DROP TABLE IF EXISTS ?#', 'dbc_'.$this->file);
DB::Aowow()->query($query);
@@ -134,9 +297,9 @@ class DBC
return true;
}
public function readFiltered(Closure $filterFunc = null, $localized = false, $safeIf = true)
public function readFiltered(Closure $filterFunc = null, $doSave = true)
{
$result = $this->readArbitrary($localized, $safeIf);
$result = $this->readArbitrary($doSave);
if (is_object($filterFunc))
foreach ($result as $key => &$val)
@@ -146,15 +309,18 @@ class DBC
return $result;
}
public function readArbitrary($localized = false, $safeIf = true)
public function readArbitrary($doSave = true)
{
if ($this->error)
return [];
// try DB first
if (!$this->result)
$this->readFromDB();
// try file second
if (!$this->result)
if ($this->readFromFile($localized) && $safeIf)
if ($this->readFromFile() && $doSave)
$this->writeToDB();
return $this->getIndexed();
@@ -162,6 +328,9 @@ class DBC
public function readFromDB()
{
if ($this->error)
return [];
if (!DB::Aowow()->selectCell('SHOW TABLES LIKE ?', 'dbc_'.$this->file))
return [];
@@ -172,69 +341,58 @@ class DBC
return $this->result;
}
public function readFromFile($localized = false)
public function readFromFile()
{
if (!$this->file)
if (!$this->file || $this->error)
return [];
$foundMask = 0x0;
foreach (FileGen::$expectedPaths as $locStr => $locId)
foreach (CLISetup::$expectedPaths as $locStr => $locId)
{
if (!in_array($locId, CLISetup::$localeIds))
continue;
if ($foundMask & (1 << $locId))
continue;
$fullpath = FileGen::$srcDir.($locStr ? $locStr.'/' : '').'DBFilesClient/'.$this->file.'.dbc';
if (!FileGen::fileExists($fullpath))
$fullpath = CLISetup::$srcDir.($locStr ? $locStr.'/' : '').'DBFilesClient/'.$this->file.'.dbc';
if (!CLISetup::fileExists($fullpath))
continue;
FileGen::status(' - reading '.($localized ? 'and merging ' : '').'data from '.$fullpath);
CLISetup::log(' - reading '.($this->localized ? 'and merging ' : '').'data from '.$fullpath);
if (!$this->read($fullpath, $localized))
FileGen::status(' - DBC::read() returned with error', MSG_LVL_ERROR);
if (!$this->read($fullpath))
CLISetup::log(' - DBC::read() returned with error', CLISetup::LOG_ERROR);
else
$foundMask |= (1 << $locId);
if (!$localized) // one match is enough
if (!$this->localized) // one match is enough
break;
}
return $this->getIndexed();
}
/*
Convert DBC file content into a 2-dimentional array
$filename - name of the file
$format - format string, that contains 1 character for each field
Supported format characters:
x - not used/unknown, 4 bytes
X - not used/unknown, 1 byte
s - char*
f - float, 4 bytes (rounded to 4 digits after comma)
i - unsigned int, 4 bytes
b - unsigned char, 1 byte
d - sorted by this field, not included in array
n - same, but field included in array
*/
private function read($filename, $mergeStrings = false)
private function read($filename)
{
$file = fopen($filename, 'rb');
if (!$file)
{
FileGen::status('cannot open file '.$filename, MSG_LVL_ERROR);
CLISetup::log('cannot open file '.$filename, CLISetup::LOG_ERROR);
return false;
}
$filesize = filesize($filename);
if ($filesize < 20)
{
FileGen::status('file '.$filename.' is too small for a DBC file', MSG_LVL_ERROR);
CLISetup::log('file '.$filename.' is too small for a DBC file', CLISetup::LOG_ERROR);
return false;
}
if (fread($file, 4) != 'WDBC')
{
FileGen::status('file '.$filename.' has incorrect magic bytes', MSG_LVL_ERROR);
CLISetup::log('file '.$filename.' has incorrect magic bytes', CLISetup::LOG_ERROR);
return false;
}
@@ -248,13 +406,13 @@ class DBC
if ($header['recordCount'] * $header['recordSize'] + $header['stringSize'] + 20 != $filesize)
{
FileGen::status('file '.$filename.' has incorrect size '.$filesize.': '.$debugstr, MSG_LVL_ERROR);
CLISetup::log('file '.$filename.' has incorrect size '.$filesize.': '.$debugStr, CLISetup::LOG_ERROR);
return false;
}
if ($header['fieldCount'] != strlen($this->format))
{
FileGen::status('incorrect format string ('.$this->format.') specified for file '.$filename.' fieldCount='.$header['fieldCount'], MSG_LVL_ERROR);
CLISetup::log('incorrect format string ('.$this->format.') specified for file '.$filename.' fieldCount='.$header['fieldCount'], CLISetup::LOG_ERROR);
return false;
}
@@ -264,7 +422,8 @@ class DBC
'X' => 'x',
's' => 'V',
'f' => 'f',
'i' => 'V',
'i' => 'V', // maybe use 'l' [signed long; 32bit; machine dependent byte order]
'u' => 'V',
'b' => 'C',
'd' => 'x4',
'n' => 'V'
@@ -282,7 +441,7 @@ class DBC
if (!isset($unpackFmt[$ch]))
{
FileGen::status('unknown format parameter \''.$ch.'\' in format string', MSG_LVL_ERROR);
CLISetup::log('unknown format parameter \''.$ch.'\' in format string', CLISetup::LOG_ERROR);
return false;
}
@@ -301,26 +460,21 @@ class DBC
// The last debug check (most of the code in this function is for debug checks)
if ($recSize != $header['recordSize'])
{
FileGen::status('format string size ('.$recSize.') for file '.$filename.' does not match actual size ('.$header['recordSize'].') '.$debugstr, MSG_LVL_ERROR);
CLISetup::log('format string size ('.$recSize.') for file '.$filename.' does not match actual size ('.$header['recordSize'].') '.$debugStr, CLISetup::LOG_ERROR);
return false;
}
// Cache the data to make it faster
$data = fread($file, $header['recordCount'] * $header['recordSize']);
$strings = fread($file, $header['stringSize']);
fclose($file);
// And, finally, extract the records
$cache = [];
$rSize = $header['recordSize'];
$rCount = $header['recordCount'];
$fCount = strlen($this->format);
$strings = [];
$rSize = $header['recordSize'];
$rCount = $header['recordCount'];
$fCount = strlen($this->format);
for ($i = 0; $i < $rCount; $i++)
{
$row = [];
$idx = $i;
$record = unpack($unpackStr, substr($data, $i * $rSize, $rSize));
$rec = unpack($unpackStr, fread($file, $header['recordSize']));
// add 'virtual' enumerator for gt*-dbcs
if ($this->isGameTable)
@@ -328,32 +482,35 @@ class DBC
for ($j = 0; $j < $fCount; $j++)
{
if (!isset($record['f'.$j]))
if (!isset($rec['f'.$j]))
continue;
$value = $record['f'.$j];
if ($this->format[$j] == 's')
switch ($this->format[$j])
{
if (isset($cache[$value]))
$value = $cache[$value];
else
{
$s = substr($strings, $value);
$s = substr($s, 0, strpos($s, "\000"));
$cache[$value] = $s;
$value = $s;
}
case 's':
$val = intVal($rec['f'.$j]);
if (isset($strings[$val]))
$strings[$val] = '';
$row[] = &$strings[$val];
continue 2;
case 'i':
if ($rec['f'.$j] & 0x80000000) // i suspect this will not work on 32bit machines
$row[] = $rec['f'.$j] - 0x100000000;
else
$row[] = $rec['f'.$j];
break;
case 'f':
$row[] = round($rec['f'.$j], 8);
break;
case 'n': // DO NOT BREAK!
$idx = $rec['f'.$j];
default: // nothing special .. 'u' and the likes
$row[] = $rec['f'.$j];
}
else if ($this->format[$j] == 'f')
$value = round($value, 8);
$row[] = $value;
if ($this->format[$j] == 'n')
$idx = $value;
}
if (!$mergeStrings || empty($this->result[$idx]))
if (!$this->localized || empty($this->result[$idx]))
$this->result[$idx] = $row;
else
{
@@ -361,8 +518,8 @@ class DBC
for ($j = 0; $j < $fCount; $j++)
{
if ($this->format[$j] == 's')
if (!$this->result[$idx][$n] && $row[$n])
$this->result[$idx][$n] = $row[$n];
if (!$this->result[$idx][$n])
$this->result[$idx][$n] = &$row[$n];
if ($this->format[$j] != 'x')
$n++;
@@ -370,6 +527,15 @@ class DBC
}
}
// apply strings
$strBlock = fread($file, $header['stringSize']);
foreach ($strings as $offset => &$str)
{
$_ = substr($strBlock, $offset);
$str = substr($_, 0, strpos($_, "\000"));
}
fclose($file);
return !empty($this->result);
}

View File

@@ -0,0 +1,211 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
class FileGen
{
public static $tplPath = 'setup/tools/filegen/templates/';
public static $cliOpts = [];
private static $shortOpts = 'fh';
private static $longOpts = array(
'build::', 'help', 'force', 'sync:', // general
'icons', 'glyphs', 'pagetexts', 'loadingscreens', // whole images
'artwork', 'talentbgs', 'maps', 'spawn-maps', 'area-maps' // images from image parts
);
public static $subScripts = [];
public static $tplFiles = array(
'searchplugin' => ['aowow.xml', 'static/download/searchplugins/', []],
'power' => ['power.js', 'static/widgets/', []],
'searchboxScript' => ['searchbox.js', 'static/widgets/', []],
'demo' => ['demo.html', 'static/widgets/power/', []],
'searchboxBody' => ['searchbox.html', 'static/widgets/searchbox/', []],
'realmMenu' => ['profile_all.js', 'static/js/', ['realmlist']],
'locales' => ['locale.js', 'static/js/', []],
// 'itemScaling => ['item-scaling', 'datasets/', []], # provided 'as is', as dbc-content doesn't usualy change
);
public static $datasets = array( // name => [AowowDeps, TCDeps]
'realms' => [null, ['realmlist']],
'statistics' => [null, ['player_levelstats', 'player_classlevelstats']],
'simpleImg' => [null, null],
'complexImg' => [null, null],
'talents' => [null, null],
'pets' => [['spawns', 'creature'], null],
'talentIcons' => [null, null],
'glyphs' => [['items', 'spell'], null],
'itemsets' => [['itemset'], null],
'enchants' => [['items'], null],
'gems' => [['items'], null],
'profiler' => [['quests', 'quests_startend', 'spell', 'currencies', 'achievement', 'titles'], null]
);
public static $defaultExecTime = 30;
private static $reqDirs = array(
'static/uploads/screenshots/normal',
'static/uploads/screenshots/pending',
'static/uploads/screenshots/resized',
'static/uploads/screenshots/temp',
'static/uploads/screenshots/thumb',
'static/uploads/temp/'
);
public static $txtConstants = array(
'CFG_NAME' => CFG_NAME,
'CFG_NAME_SHORT' => CFG_NAME_SHORT,
'HOST_URL' => HOST_URL,
'STATIC_URL' => STATIC_URL
);
public static function init()
{
self::$defaultExecTime = ini_get('max_execution_time');
$doScripts = [];
if (getopt(self::$shortOpts, self::$longOpts))
self::handleCLIOpts($doScripts);
else
{
self::printCLIHelp();
exit;
}
// check passed subscript names; limit to real scriptNames
self::$subScripts = array_merge(array_keys(self::$tplFiles), array_keys(self::$datasets));
if ($doScripts)
self::$subScripts = array_intersect($doScripts, self::$subScripts);
if (!CLISetup::$localeIds /* todo: && this script has localized text */)
{
CLISetup::log('No valid locale specified. Check your config or --locales parameter, if used', CLISetup::LOG_ERROR);
exit;
}
// create directory structure
CLISetup::log('FileGen::init() - creating required directories');
$pathOk = 0;
foreach (self::$reqDirs as $rd)
if (CLISetup::writeDir($rd))
$pathOk++;
CLISetup::log('created '.$pathOk.' extra paths'.($pathOk == count(self::$reqDirs) ? '' : ' with errors'));
CLISetup::log();
}
private static function handleCLIOpts(&$doScripts)
{
$_ = getopt(self::$shortOpts, self::$longOpts);
if ((isset($_['help']) || isset($_['h'])) && empty($_['build']))
{
self::printCLIHelp();
exit;
}
// required subScripts
if (!empty($_['sync']))
{
$sync = explode(',', $_['sync']);
foreach (self::$tplFiles as $name => $info)
if (!empty($info[2]) && array_intersect($sync, $info[2]))
$doScripts[] = $name;
foreach (self::$datasets as $name => $info)
{
// recursive deps from SqlGen
if (!empty($info[0]) && array_intersect(SqlGen::$subScripts, $info[0]))
$doScripts[] = $name;
else if (!empty($info[1]) && array_intersect($sync, $info[1]))
$doScripts[] = $name;
}
$doScripts = array_unique($doScripts);
}
else if (!empty($_['build']))
$doScripts = explode(',', $_['build']);
// optional, overwrite existing files
if (isset($_['f']))
self::$cliOpts['force'] = true;
if (isset($_['h']))
self::$cliOpts['help'] = true;
// mostly build-instructions from longOpts
foreach (self::$longOpts as $opt)
if (!strstr($opt, ':') && isset($_[$opt]))
self::$cliOpts[$opt] = true;
}
public static function hasOpt(/* ...$opt */)
{
$result = 0x0;
foreach (func_get_args() as $idx => $arg)
{
if (!is_string($arg))
continue;
if (isset(self::$cliOpts[$arg]))
$result |= (1 << $idx);
}
return $result;
}
public static function printCLIHelp()
{
echo "\nusage: php index.php --build=<subScriptList,> [-h --help] [-f --force]\n\n";
echo "--build : available subScripts:\n";
foreach (array_merge(array_keys(self::$tplFiles), array_keys(self::$datasets)) as $s)
{
echo " * ".str_pad($s, 20).str_pad(isset(self::$tplFiles[$s]) ? self::$tplFiles[$s][1].self::$tplFiles[$s][0] : 'static data file', 45).
(!empty(self::$tplFiles[$s][2]) ? ' - TC deps: '.implode(', ', self::$tplFiles[$s][2]) : (!empty(self::$datasets[$s][1]) ? ' - TC deps: '.implode(', ', self::$datasets[$s][1]) : '')).
(!empty(self::$datasets[$s][0]) ? ' - Aowow deps: '.implode(', ', self::$datasets[$s][0]) : '')."\n";
}
echo "-h --help : shows this info\n";
echo "-f --force : enforces overwriting existing files\n";
}
public static function generate($file, array $updateIds = [])
{
$success = false;
if (file_exists('setup/tools/filegen/'.$file.'.func.php'))
{
$reqDBC = [];
CLISetup::log('FileGen::generate() - gathering data for '.$file);
require_once 'setup/tools/filegen/'.$file.'.func.php';
if (function_exists($file))
{
// check for required auxiliary DBC files
foreach ($reqDBC as $req)
if (!CLISetup::loadDBC($req))
return false;
$success = $file($updateIds);
}
else
CLISetup::log(' - subscript \''.$file.'\' not defined in included file', CLISetup::LOG_ERROR);
set_time_limit(FileGen::$defaultExecTime); // reset to default for the next script
}
else
CLISetup::log(sprintf(ERR_MISSING_INCL, $file, 'setup/tools/filegen/'.$file.'.func.php', CLISetup::LOG_ERROR));
return $success;
}
}
?>

View File

@@ -21,7 +21,13 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// note: for the sake of simplicity, this function handles all images, that must be stitched together (which are mostly maps)
$reqDBC = ['talenttab', 'chrclasses', 'worldmapoverlay', 'worldmaparea'];
function complexImg()
{
if (isset(FileGen::$cliOpts['help']))
@@ -37,25 +43,13 @@ if (!defined('AOWOW_REVISION'))
return true;
}
if (!class_exists('DBC'))
{
FileGen::status(' - simpleImg: required class DBC was not included', MSG_LVL_ERROR);
return false;
}
if (!function_exists('imagecreatefromblp'))
{
FileGen::status(' - complexImg: required include imagecreatefromblp() was not included', MSG_LVL_ERROR);
return false;
}
$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 = FileGen::$srcDir.'%sDBFilesClient/';
$imgPath = FileGen::$srcDir.'%sInterface/';
$dbcPath = CLISetup::$srcDir.'%sDBFilesClient/';
$imgPath = CLISetup::$srcDir.'%sInterface/';
$destDir = 'static/images/wow/';
$success = true;
$paths = ['WorldMap/', 'TalentFrame/', 'Glues/Credits/'];
@@ -87,13 +81,13 @@ if (!defined('AOWOW_REVISION'))
$result = null;
$file = $path.'.png';
if (FileGen::fileExists($file))
if (CLISetup::fileExists($file))
$result = imagecreatefrompng($file);
if (!$result)
{
$file = $path.'.blp';
if (FileGen::fileExists($file))
if (CLISetup::fileExists($file))
$result = imagecreatefromblp($file);
}
@@ -115,7 +109,7 @@ if (!defined('AOWOW_REVISION'))
$src = $loadImageFile($baseName.$suffix);
if (!$src)
{
FileGen::status(' - complexImg: tile '.$baseName.$suffix.'.blp missing.', MSG_LVL_ERROR);
CLISetup::log(' - complexImg: tile '.$baseName.$suffix.'.blp missing.', CLISetup::LOG_ERROR);
unset($dest);
return null;
}
@@ -148,25 +142,25 @@ if (!defined('AOWOW_REVISION'))
$ok = imagepng($dest, $name.'.'.$ext);
break;
default:
FileGen::status($done.' - unsupported file fromat: '.$ext, MSG_LVL_WARN);
CLISetup::log($done.' - unsupported file fromat: '.$ext, CLISetup::LOG_WARN);
}
imagedestroy($dest);
if ($ok)
{
chmod($name.'.'.$ext, FileGen::$accessMask);
FileGen::status($done.' - image '.$name.'.'.$ext.' written', MSG_LVL_OK);
chmod($name.'.'.$ext, CLISetup::FILE_ACCESS);
CLISetup::log($done.' - image '.$name.'.'.$ext.' written', CLISetup::LOG_OK);
}
else
FileGen::status($done.' - could not create image '.$name.'.'.$ext, MSG_LVL_ERROR);
CLISetup::log($done.' - could not create image '.$name.'.'.$ext, CLISetup::LOG_ERROR);
return $ok;
};
$createSpawnMap = function($img, $zoneId) use ($mapHeight, $mapWidth, $threshold)
{
FileGen::status(' - creating spawn map');
CLISetup::log(' - creating spawn map');
$tmp = imagecreate(1000, 1000);
$cbg = imagecolorallocate($tmp, 255, 255, 255);
@@ -190,7 +184,7 @@ if (!defined('AOWOW_REVISION'))
$checkSourceDirs = function($sub, &$missing = []) use ($imgPath, $dbcPath, $paths, &$modeMask)
{
$incomplete = false;
$hasMissing = false;
foreach ($paths as $idx => $subDir)
{
if ($idx == 0 && !($modeMask & 0x16)) // map related
@@ -201,24 +195,24 @@ if (!defined('AOWOW_REVISION'))
continue;
$p = sprintf($imgPath, $sub).$subDir;
if (!FileGen::fileExists($p))
if (!CLISetup::fileExists($p))
{
$hasMissing = true;
$missing[] = $p;
$incomplete = true;
}
}
if ($modeMask & 0x17)
{
$p = sprintf($dbcPath, $sub);
if (!FileGen::fileExists($p))
if (!CLISetup::fileExists($p))
{
$hasMissing = true;
$missing[] = $p;
$incomplete = true;
}
}
return !$incomplete;
return !$hasMissing;
};
@@ -226,9 +220,9 @@ if (!defined('AOWOW_REVISION'))
if ($_ = FileGen::hasOpt('talentbgs', 'maps', 'spawn-maps', 'artwork', 'area-maps'))
$modeMask = $_;
foreach (FileGen::$expectedPaths as $xp => $__)
foreach (CLISetup::$expectedPaths as $xp => $__)
{
if ($xp) // if sun subDir add trailing slash
if ($xp) // if in subDir add trailing slash
$xp .= '/';
if ($checkSourceDirs($xp, $missing))
@@ -241,9 +235,9 @@ if (!defined('AOWOW_REVISION'))
// if no subdir had sufficient data, diaf
if ($locStr === null)
{
FileGen::status('one or more required directories are missing:', MSG_LVL_ERROR);
CLISetup::log('one or more required directories are missing:', CLISetup::LOG_ERROR);
foreach ($missing as $m)
FileGen::status(' - '.$m, MSG_LVL_ERROR);
CLISetup::log(' - '.$m, CLISetup::LOG_ERROR);
return;
}
@@ -255,23 +249,23 @@ if (!defined('AOWOW_REVISION'))
if ($modeMask & 0x01)
{
if (FileGen::writeDir($destDir.'hunterpettalents/') && FileGen::writeDir($destDir.'talents/backgrounds/'))
if (CLISetup::writeDir($destDir.'hunterpettalents/') && CLISetup::writeDir($destDir.'talents/backgrounds/'))
{
// [classMask, creatureFamilyMask, tabNr, textureStr]
$talentTab = (new DBC('TalentTab'))->readArbitrary();
$chrClass = (new DBC('ChrClasses'))->readArbitrary();
$order = array(
$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 ($chrClass && $talentTab)
if ($tTabs)
{
$sum = 0;
$total = count($talentTab);
FileGen::status('Processing '.$total.' files from TalentFrame/ ...');
$total = count($tTabs);
CLISetup::log('Processing '.$total.' files from TalentFrame/ ...');
foreach ($talentTab as $tt)
foreach ($tTabs as $tt)
{
ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time)
$sum++;
@@ -285,20 +279,19 @@ if (!defined('AOWOW_REVISION'))
else
{
$size = [204, 554];
$name = $destDir.'talents/backgrounds/'.strtolower($chrClass[log($tt['classMask'], 2) + 1]['nameINT']).'_'.($tt['tabNumber'] + 1);
$name = $destDir.'talents/backgrounds/'.strtolower($tt['fileString']).'_'.($tt['tabNumber'] + 1);
}
if (!isset(FileGen::$cliOpts['force']) && file_exists($name.'.jpg'))
{
FileGen::status($done.' - file '.$name.'.jpg was already processed');
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)
{
FileGen::status(' - could not assemble file '.$tt['textureFile'], MSG_LVL_ERROR);
CLISetup::log(' - could not assemble file '.$tt['textureFile'], CLISetup::LOG_ERROR);
continue;
}
@@ -340,75 +333,67 @@ if (!defined('AOWOW_REVISION'))
3789 => 1, 1477 => 1, 3959 => 0, 3845 => 1, 2717 => 1, 3923 => 1, 3607 => 1, 3836 => 1, 2159 => 1, 4075 => 0
);
$tmp = (new DBC('WorldMapArea'))->readArbitrary();
$wma = [];
foreach ($tmp as $row)
{
// fixups...
if (!$row['areaId'])
{
switch ($row['Id'])
{
case 13: $row['areaId'] = -6; break; // Kalimdor
case 14: $row['areaId'] = -3; break; // Eastern Kingdoms
case 466: $row['areaId'] = -2; break; // Outland
case 485: $row['areaId'] = -5; break; // Northrend
}
}
$wma[] = $row;
}
$tmp = (new DBC('WorldMapOverlay'))->readFiltered(function(&$val) { return !empty($val['textureString']); });
$wmo = [];
foreach ($tmp as $row)
$wmo[$row['worldMapAreaId']][] = $row;
$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;
FileGen::status(' - could not read required dbc files: WorldMapArea.dbc ['.count($wma).' entries]; WorldMapOverlay.dbc ['.count($wmo).' entries]', MSG_LVL_ERROR);
CLISetup::log(' - could not read required dbc files: WorldMapArea.dbc ['.count($wma).' entries]; WorldMapOverlay.dbc ['.count($wmo).' entries]', CLISetup::LOG_ERROR);
return;
}
// more fixups to WorldMapArea
// fixups...
foreach ($wma as &$a)
{
if ($a['areaId'])
continue;
switch ($a['Id'])
{
case 13: $a['areaId'] = -6; break; // Kalimdor
case 14: $a['areaId'] = -3; break; // Eastern Kingdoms
case 466: $a['areaId'] = -2; break; // 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(FileGen::$localeIds) * count($wma);
$sumMaps = count(CLISetup::$localeIds) * count($wma);
FileGen::status('Processing '.$sumMaps.' files from WorldMap/ ...');
CLISetup::log('Processing '.$sumMaps.' files from WorldMap/ ...');
foreach (FileGen::$localeIds as $progressLoc => $l)
foreach (CLISetup::$localeIds as $progressLoc => $l)
{
// create destination directories
$dirError = false;
foreach ($mapDirs as $md)
if (!FileGen::writeDir($destDir . sprintf($md[0], strtolower(Util::$localeStrings[$l]).'/')))
if (!CLISetup::writeDir($destDir . sprintf($md[0], strtolower(Util::$localeStrings[$l]).'/')))
$dirError = true;
if ($modeMask & 0x04)
if (!FileGen::writeDir('cache/alphaMaps'))
if (!CLISetup::writeDir('cache/alphaMaps'))
$dirError = true;
if ($dirError)
{
$success = false;
FileGen::status(' - complexImg: could not create map directories for locale '.$l.'. skipping...', MSG_LVL_ERROR);
CLISetup::log(' - complexImg: could not create map directories for locale '.$l.'. skipping...', CLISetup::LOG_ERROR);
continue;
}
// source for mapFiles
$mapSrcDir = null;
$locDirs = array_filter(FileGen::$expectedPaths, function($var) use ($l) { return !$var || $var == $l; });
$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 (FileGen::fileExists($p))
if (CLISetup::fileExists($p))
{
FileGen::status(' - using files from '.($mapLoc ?: '/').' for locale '.Util::$localeStrings[$l], MSG_LVL_WARN);
CLISetup::log(' - using files from '.($mapLoc ?: '/').' for locale '.Util::$localeStrings[$l], CLISetup::LOG_WARN);
$mapSrcDir = $p.'/';
break;
}
@@ -417,7 +402,7 @@ if (!defined('AOWOW_REVISION'))
if ($mapSrcDir === null)
{
$success = false;
FileGen::status(' - no suitable localized map files found for locale '.$l, MSG_LVL_ERROR);
CLISetup::log(' - no suitable localized map files found for locale '.$l, CLISetup::LOG_ERROR);
continue;
}
@@ -432,10 +417,10 @@ if (!defined('AOWOW_REVISION'))
$textureStr = $areaEntry['nameINT'];
$path = $mapSrcDir.$textureStr;
if (!FileGen::fileExists($path))
if (!CLISetup::fileExists($path))
{
$success = false;
FileGen::status('worldmap file '.$path.' missing for selected locale '.Util::$localeStrings[$l], MSG_LVL_ERROR);
CLISetup::log('worldmap file '.$path.' missing for selected locale '.Util::$localeStrings[$l], CLISetup::LOG_ERROR);
continue;
}
@@ -445,14 +430,14 @@ if (!defined('AOWOW_REVISION'))
[9, 10, 11, 12]
);
FileGen::status($textureStr . " [" . $zoneId . "]");
CLISetup::log($textureStr . " [" . $zoneId . "]");
$overlay = $createAlphaImage($mapWidth, $mapHeight);
// zone has overlays (is in open world; is not multiLeveled)
if (isset($wmo[$wmaId]))
{
FileGen::status(' - area has '.count($wmo[$wmaId]).' overlays');
CLISetup::log(' - area has '.count($wmo[$wmaId]).' overlays');
foreach ($wmo[$wmaId] as &$row)
{
@@ -466,7 +451,7 @@ if (!defined('AOWOW_REVISION'))
$img = $loadImageFile($path . '/' . $row['textureString'] . $i);
if (!$img)
{
FileGen::status(' - complexImg: tile '.$path.'/'.$row['textureString'].$i.'.blp missing.', MSG_LVL_ERROR);
CLISetup::log(' - complexImg: tile '.$path.'/'.$row['textureString'].$i.'.blp missing.', CLISetup::LOG_ERROR);
break 2;
}
@@ -507,7 +492,7 @@ if (!defined('AOWOW_REVISION'))
$multiLevel = 0;
do
{
if (!FileGen::filesInPath('/'.$textureStr.'\/'.$textureStr.($multiLevel + 1).'_\d\.blp/i', true))
if (!CLISetup::filesInPath('/'.$textureStr.'\/'.$textureStr.($multiLevel + 1).'_\d\.blp/i', true))
break;
$multiLevel++;
@@ -517,9 +502,9 @@ if (!defined('AOWOW_REVISION'))
// check if we can create base map anyway
$file = $path.'/'.$textureStr.'1.blp';
$hasBaseMap = FileGen::fileExists($file);
$hasBaseMap = CLISetup::fileExists($file);
FileGen::status(' - area has '.($multiLeveled ? $multiLevel . ' levels' : 'only base level'));
CLISetup::log(' - area has '.($multiLeveled ? $multiLevel . ' levels' : 'only base level'));
$map = null;
for ($i = 0; $i <= $multiLevel; $i++)
@@ -551,7 +536,7 @@ if (!defined('AOWOW_REVISION'))
if (!isset(FileGen::$cliOpts['force']) && file_exists($outFile[$idx].'.'.$info[1]))
{
FileGen::status($progress.' - file '.$outFile[$idx].'.'.$info[1].' was already processed');
CLISetup::log($progress.' - file '.$outFile[$idx].'.'.$info[1].' was already processed');
$doSkip |= (1 << $idx);
}
}
@@ -563,7 +548,7 @@ if (!defined('AOWOW_REVISION'))
if (!$map)
{
$success = false;
FileGen::status(' - could not create image resource for map '.$zoneId.($multiLevel ? ' level '.$i : ''));
CLISetup::log(' - could not create image resource for map '.$zoneId.($multiLevel ? ' level '.$i : ''));
continue;
}
@@ -600,7 +585,7 @@ if (!defined('AOWOW_REVISION'))
$outFile[$idx] = $destDir . sprintf($info[0], strtolower(Util::$localeStrings[$l]).'/') . $row['areaTableId'];
if (!isset(FileGen::$cliOpts['force']) && file_exists($outFile[$idx].'.'.$info[1]))
{
FileGen::status($progress.' - file '.$outFile[$idx].'.'.$info[1].' was already processed');
CLISetup::log($progress.' - file '.$outFile[$idx].'.'.$info[1].' was already processed');
$doSkip |= (1 << $idx);
}
}
@@ -637,7 +622,7 @@ if (!defined('AOWOW_REVISION'))
if ($modeMask & 0x08) // optional tidbits (not used by default)
{
if (FileGen::writeDir($destDir.'Interface/Glues/Credits/'))
if (CLISetup::writeDir($destDir.'Interface/Glues/Credits/'))
{
// tile ordering
$order = array(
@@ -664,7 +649,7 @@ if (!defined('AOWOW_REVISION'))
$imgGroups = [];
$srcPath = sprintf($imgPath, $locStr).'Glues/Credits/';
$files = FileGen::filesInPath($srcPath);
$files = CLISetup::filesInPath($srcPath);
foreach ($files as $f)
{
if (preg_match('/([^\/]+)(\d).blp/i', $f, $m))
@@ -686,7 +671,7 @@ if (!defined('AOWOW_REVISION'))
$total = count($imgGroups);
$sum = 0;
FileGen::status('Processing '.$total.' files from Glues/Credits/...');
CLISetup::log('Processing '.$total.' files from Glues/Credits/...');
foreach ($imgGroups as $file => $fmt)
{
@@ -698,20 +683,20 @@ if (!defined('AOWOW_REVISION'))
if (!isset(FileGen::$cliOpts['force']) && file_exists($name.'.png'))
{
FileGen::status($done.' - file '.$name.'.png was already processed');
CLISetup::log($done.' - file '.$name.'.png was already processed');
continue;
}
if (!isset($order[$fmt]))
{
FileGen::status(' - pattern for file '.$name.' not set. skipping', MSG_LVL_WARN);
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)
{
FileGen::status(' - could not assemble file '.$name, MSG_LVL_ERROR);
CLISetup::log(' - could not assemble file '.$name, CLISetup::LOG_ERROR);
continue;
}

View File

@@ -3,6 +3,9 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// Create 'enchants'-file for available locales
// this script requires the following dbc-files to be parsed and available
@@ -62,7 +65,7 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!FileGen::writeDir('datasets/'.$dir))
if (!CLISetup::writeDir('datasets/'.$dir))
$success = false;
$enchIds = [];
@@ -72,7 +75,7 @@ if (!defined('AOWOW_REVISION'))
$enchMisc = [];
$enchJSON = Util::parseItemEnchantment($enchIds, false, $enchMisc);
foreach (FileGen::$localeIds as $lId)
foreach (CLISetup::$localeIds as $lId)
{
set_time_limit(120);
@@ -211,7 +214,7 @@ if (!defined('AOWOW_REVISION'))
$toFile = "var g_enchants = ".Util::toJSON($enchantsOut).";";
$file = 'datasets/'.User::$localeString.'/enchants';
if (!FileGen::writeFile($file, $toFile))
if (!CLISetup::writeFile($file, $toFile))
$success = false;
}

View File

@@ -1,423 +0,0 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
// shared strings
define('ERR_CREATE_FILE', 'could not create file at destination %s' );
define('ERR_WRITE_FILE', 'could not write to file at destination %s' );
define('ERR_READ_FILE', 'file %s could not be read' );
define('ERR_MISSING_FILE', 'file %s not found' );
define('ERR_NONE', 'created file %s' );
define('ERR_MISSING_INCL', 'required function %s() could not be found at %s');
define('MSG_LVL_OK', 0);
define('MSG_LVL_WARN', 1);
define('MSG_LVL_ERROR', 2);
class FileGen
{
public static $success = false;
public static $srcDir = 'setup/mpqData/';
public static $tplPath = 'setup/tools/filegen/templates/';
// update paths [yes, you can have en empty string as key]
public static $expectedPaths = array(
'frFR' => 2,
'deDE' => 3,
'esES' => 6, 'esMX' => 6,
'ruRU' => 8,
'' => 0, 'enGB' => 0, 'enUS' => 0,
);
public static $cliOpts = [];
private static $shortOpts = 'fh';
private static $longOpts = array(
'build:', 'log::', 'help', 'locales::', 'force', 'mpqDataDir::', // general
'icons', 'glyphs', 'pagetexts', 'loadingscreens', // whole images
'artwork', 'talentbgs', 'maps', 'spawn-maps', 'area-maps' // images from image parts
);
public static $subScripts = [];
public static $tplFiles = array(
'searchplugin' => ['aowow.xml', 'static/download/searchplugins/'],
'power' => ['power.js', 'static/widgets/' ],
'searchboxScript' => ['searchbox.js', 'static/widgets/' ],
'demo' => ['demo.html', 'static/widgets/power/' ],
'searchboxBody' => ['searchbox.html', 'static/widgets/searchbox/' ],
'realmMenu' => ['profile_all.js', 'static/js/' ],
'locales' => ['locale.js', 'static/js/' ],
// 'itemScaling => ['item-scaling', 'datasets/' ], # provided 'as is', as dbc-content doesn't usualy change
);
public static $datasets = array(
'pets', 'simpleImg', 'complexImg',
'realms', 'statistics', 'profiler', // profiler related
'talents', 'talentIcons', 'glyphs', // talentCalc related
'itemsets', 'enchants', 'gems' // comparison related
);
public static $defaultExecTime = 30;
public static $accessMask = 0755;
private static $logFile = '';
private static $logHandle = null;
private static $mpqFiles = [];
private static $locales = [];
public static $localeIds = [];
private static $reqDirs = array(
'static/uploads/screenshots/normal',
'static/uploads/screenshots/pending',
'static/uploads/screenshots/resized',
'static/uploads/screenshots/temp',
'static/uploads/screenshots/thumb',
'static/uploads/temp/'
);
public static $txtConstants = array(
'CFG_NAME' => CFG_NAME,
'CFG_NAME_SHORT' => CFG_NAME_SHORT,
'HOST_URL' => HOST_URL,
'STATIC_URL' => STATIC_URL
);
public static function init($scriptList = '')
{
self::$defaultExecTime = ini_get('max_execution_time');
$doScripts = [];
if (CLI)
{
if (getopt(self::$shortOpts, self::$longOpts))
self::handleCLIOpts($doScripts);
else
{
self::printCLIHelp(array_merge(array_keys(self::$tplFiles), self::$datasets));
exit;
}
}
else
{
$doScripts = explode(',', $scriptList);
self::$locales = Util::$localeStrings;
}
// check passed subscript names; limit to real scriptNames
self::$subScripts = array_merge(array_keys(self::$tplFiles), self::$datasets);
if ($doScripts)
self::$subScripts = array_intersect($doScripts, self::$subScripts);
// restrict actual locales
foreach (self::$locales as $idx => $str)
{
if (!$str)
continue;
if (!defined('CFG_LOCALES'))
self::$localeIds[] = $idx;
else if (CFG_LOCALES & (1 << $idx))
self::$localeIds[] = $idx;
}
if (!self::$localeIds)
{
self::status('No valid locale specified. Check your config or --locales parameter, if used', MSG_LVL_ERROR);
exit;
}
// create directory structure
self::status('FileGen::init() - creating required directories');
$pathOk = 0;
foreach (self::$reqDirs as $rd)
if (self::writeDir($rd))
$pathOk++;
FileGen::status('created '.$pathOk.' extra paths'.($pathOk == count(self::$reqDirs) ? '' : ' with errors'));
FileGen::status();
}
// shared funcs
public static function writeFile($file, $content)
{
$success = false;
if ($handle = @fOpen($file, "w"))
{
if (fWrite($handle, $content))
{
$success = true;
self::status(sprintf(ERR_NONE, $file), MSG_LVL_OK);
}
else
self::status(sprintf(ERR_WRITE_FILE, $file), MSG_LVL_ERROR);
fClose($handle);
}
else
self::status(sprintf(ERR_CREATE_FILE, $file), MSG_LVL_ERROR);
if ($success)
@chmod($file, FileGen::$accessMask);
return $success;
}
public static function writeDir($dir)
{
if (is_dir($dir))
{
if (!is_writable($dir) && !@chmod($dir, FileGen::$accessMask))
self::status('cannot write into output directory '.$dir, MSG_LVL_ERROR);
return is_writable($dir);
}
if (@mkdir($dir, FileGen::$accessMask, true))
return true;
self::status('could not create output directory '.$dir, MSG_LVL_ERROR);
return false;
}
public static function status($txt = '', $lvl = -1)
{
if (isset(self::$cliOpts['help']))
return;
$cliColor = "\033[%sm%s\033[0m";
$htmlColor = '<span style="color:%s;">%s</span>';
if (self::$logFile && !self::$logHandle)
{
if (!file_exists(self::$logFile))
self::$logHandle = fopen(self::$logFile, 'w');
else
{
$logFileParts = pathinfo(self::$logFile);
$i = 1;
while (file_exists($logFileParts['dirname'].'/'.$logFileParts['filename'].$i.'.'.$logFileParts['extension']))
$i++;
self::$logFile = $logFileParts['dirname'].'/'.$logFileParts['filename'].$i.'.'.$logFileParts['extension'];
self::$logHandle = fopen(self::$logFile, 'w');
}
}
$msg = $raw = "\n";
if ($txt)
{
$msg = $raw = str_pad(date('H:i:s'), 10);
switch ($lvl)
{
case MSG_LVL_ERROR: // red error
$str = 'Error: ';
$raw .= $str;
$msg .= CLI ? sprintf($cliColor, '0;31', $str) : sprintf($htmlColor, 'darkred', $str);
break;
case MSG_LVL_WARN: // yellow warn
$str = 'Notice: ';
$raw .= $str;
$msg .= CLI ? sprintf($cliColor, '0;33', $str) : sprintf($htmlColor, 'orange', $str);
break;
case MSG_LVL_OK: // green success
$str = 'Success:';
$raw = $raw . $str;
$msg .= CLI ? sprintf($cliColor, '0;32', $str) : sprintf($htmlColor, 'darkgreen', $str);
break;
default:
$msg .= ' ';
$raw .= ' ';
}
$msg .= ' '.$txt."\n";
$raw .= ' '.$txt."\n";
}
if (CLI)
{
// maybe for future use: writing \x08 deletes the last char, use to repeatedly update single line (and even WIN should be able to handle it)
echo substr(PHP_OS, 0, 3) == 'WIN' ? $raw : $msg;
if (self::$logHandle)
fwrite(self::$logHandle, $raw);
@ob_flush();
flush();
@ob_end_flush();
}
else
echo "<pre>".$msg."</pre>\n";
}
private static function handleCLIOpts(&$doScripts)
{
$_ = getopt(self::$shortOpts, self::$longOpts);
if ((isset($_['help']) || isset($_['h'])) && empty($_['build']))
{
self::printCLIHelp(array_merge(array_keys(self::$tplFiles), self::$datasets));
exit;
}
// required subScripts
if (!empty($_['build']))
$doScripts = explode(',', $_['build']);
// optional logging
if (!empty($_['log']))
self::$logFile = trim($_['log']);
// optional, overwrite existing files
if (isset($_['f']))
self::$cliOpts['force'] = true;
// alternative data source (no quotes, use forward slash)
if (!empty($_['mpqDataDir']))
self::$srcDir = str_replace(['\\', '"', '\''], ['/', '', ''], $_['mpqDataDir']);
if (isset($_['h']))
self::$cliOpts['help'] = true;
// optional limit handled locales
if (!empty($_['locales']))
{
// engb and enus are identical for all intents and purposes
$from = ['engb', 'esmx'];
$to = ['enus', 'eses'];
$_['locales'] = str_replace($from, $to, strtolower($_['locales']));
self::$locales = array_intersect(Util::$localeStrings, explode(',', $_['locales']));
}
else
self::$locales = Util::$localeStrings;
// mostly build-instructions from longOpts
foreach (self::$longOpts as $opt)
if (!strstr($opt, ':') && isset($_[$opt]))
self::$cliOpts[$opt] = true;
}
public static function hasOpt(/* ...$opt */)
{
$result = 0x0;
foreach (func_get_args() as $idx => $arg)
{
if (!is_string($arg))
continue;
if (isset(self::$cliOpts[$arg]))
$result |= (1 << $idx);
}
return $result;
}
/* the problem
1) paths provided in dbc files are case-insensitive and random
2) paths to the actual textures contained in the mpq archives are case-insensitive and random
unix systems will throw a fit if you try to get from one to the other, so lets save the paths from 2) and cast it to lowecase
lookups will be done in lowercase. A successfull match will return the real path.
*/
private static function buildFileList()
{
self::status('FileGen::init() - reading MPQdata from '.self::$srcDir.' to list for first time use...');
$setupDirs = glob('setup/*');
foreach ($setupDirs as $sd)
{
if (substr(self::$srcDir, -1) == '/')
self::$srcDir = substr(self::$srcDir, 0, -1);
if (substr($sd, -1) == '/')
$sd = substr($sd, 0, -1);
if (strtolower($sd) == strtolower(self::$srcDir))
{
self::$srcDir = $sd.'/';
break;
}
}
try
{
$iterator = new RecursiveDirectoryIterator(self::$srcDir);
$iterator->setFlags(RecursiveDirectoryIterator::SKIP_DOTS);
foreach (new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::SELF_FIRST) as $path)
{
$_ = str_replace('\\', '/', $path->getPathname());
self::$mpqFiles[strtolower($_)] = $_;
}
self::status('done');
self::status();
}
catch (UnexpectedValueException $e) { self::status('- mpqData dir '.self::$srcDir.' does not exist', MSG_LVL_ERROR); }
}
public static function fileExists(&$file)
{
// read mpq source file structure to tree
if (!self::$mpqFiles)
self::buildFileList();
// backslash to forward slash
$_ = strtolower(str_replace('\\', '/', $file));
// remove trailing slash
if (substr($_, -1, 1) == '/')
$_ = substr($_, 0, -1);
if (isset(self::$mpqFiles[$_]))
{
$file = self::$mpqFiles[$_];
return true;
}
return false;
}
public static function filesInPath($path, $useRegEx = false)
{
$result = [];
// read mpq source file structure to tree
if (!self::$mpqFiles)
self::buildFileList();
// backslash to forward slash
$_ = strtolower(str_replace('\\', '/', $path));
foreach (self::$mpqFiles as $lowerFile => $realFile)
{
if (!$useRegEx && strstr($lowerFile, $_))
$result[] = $realFile;
else if ($useRegEx && preg_match($path, $lowerFile))
$result[] = $realFile;
}
return $result;
}
public static function printCLIHelp($scripts)
{
echo "usage: php index.php --build=<subScriptList,> [-h --help] [--log logfile] [-f --force] [--mpqDataDir=path/to/mpqData/] [--locales=<regionCodes,>]\n\n";
echo "build -> available subScripts:\n";
foreach ($scripts as $s)
echo " - ".str_pad($s, 20).(isset(self::$tplFiles[$s]) ? self::$tplFiles[$s][1].self::$tplFiles[$s][0] : 'static data file')."\n";
echo "help -> shows this info\n";
echo "log -> writes ouput to file\n";
echo "force -> enforces overwriting existing files\n";
echo "locales -> limits setup to enUS, frFR, deDE, esES and/or ruRU (does not override config settings)\n";
echo "mpqDataDir -> manually point to directory with extracted mpq data (default: setup/mpqData/)\n";
}
}
?>

View File

@@ -3,6 +3,9 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// Create 'gems'-file for available locales
// this script requires the following dbc-files to be parsed and available
@@ -30,10 +33,11 @@ if (!defined('AOWOW_REVISION'))
i.name_loc0, i.name_loc2, i.name_loc3, i.name_loc6, i.name_loc8,
IF (i.id < 36000 OR i.itemLevel < 70, 1 , 2) AS expansion,
i.quality,
i.iconString AS icon,
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;
@@ -41,7 +45,7 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!FileGen::writeDir('datasets/'.$dir))
if (!CLISetup::writeDir('datasets/'.$dir))
$success = false;
$enchIds = [];
@@ -51,7 +55,7 @@ if (!defined('AOWOW_REVISION'))
$enchMisc = [];
$enchJSON = Util::parseItemEnchantment($enchIds, false, $enchMisc);
foreach (FileGen::$localeIds as $lId)
foreach (CLISetup::$localeIds as $lId)
{
set_time_limit(5);
@@ -75,7 +79,7 @@ if (!defined('AOWOW_REVISION'))
$toFile = "var g_gems = ".Util::toJSON($gemsOut).";";
$file = 'datasets/'.User::$localeString.'/gems';
if (!FileGen::writeFile($file, $toFile))
if (!CLISetup::writeFile($file, $toFile))
$success = false;
}

View File

@@ -3,10 +3,9 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// Create 'glyphs'-file for available locales
// this script requires the following dbc-files to be parsed and available
// GlyphProperties, Spells, SkillLineAbility
/* Example
40896: {
@@ -20,6 +19,9 @@ if (!defined('AOWOW_REVISION'))
},
*/
// Create 'glyphs'-file for available locales
// this script requires the following dbc-files to be parsed and available
function glyphs()
{
$success = true;
@@ -30,7 +32,7 @@ if (!defined('AOWOW_REVISION'))
i.subclass AS classs,
i.requiredLevel AS level,
s1.Id AS glyphSpell,
s1.iconStringAlt AS icon,
ic.iconString AS icon,
s1.skillLine1 AS skillId,
s2.Id AS glyphEffect,
s2.Id AS ARRAY_KEY
@@ -38,16 +40,17 @@ if (!defined('AOWOW_REVISION'))
JOIN ?_spell s1 ON s1.Id = i.spellid1
JOIN ?_glyphproperties g ON g.Id = s1.effect1MiscValue
JOIN ?_spell s2 ON s2.Id = g.spellId
JOIN ?_icons ic ON ic.Id = s1.iconIdAlt
WHERE i.classBak = 16');
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!FileGen::writeDir('datasets/'.$dir))
if (!CLISetup::writeDir('datasets/'.$dir))
$success = false;
$glyphSpells = new SpellList(array(['s.id', array_keys($glyphList)], CFG_SQL_LIMIT_NONE));
foreach (FileGen::$localeIds as $lId)
foreach (CLISetup::$localeIds as $lId)
{
set_time_limit(30);
@@ -79,7 +82,7 @@ if (!defined('AOWOW_REVISION'))
$toFile = "var g_glyphs = ".Util::toJSON($glyphsOut).";";
$file = 'datasets/'.User::$localeString.'/glyphs';
if (!FileGen::writeFile($file, $toFile))
if (!CLISetup::writeFile($file, $toFile))
$success = false;
}

View File

@@ -3,10 +3,9 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// Create 'itemsets'-file for available locales
// this script requires the following dbc-files to be parsed and available
// GlyphProperties, Spells, SkillLineAbility
/* Example
"-447": { // internal id, freely chosen
@@ -29,6 +28,9 @@ if (!defined('AOWOW_REVISION'))
},
*/
// Create 'itemsets'-file for available locales
// this script requires the following dbc-files to be parsed and available
function itemsets()
{
$success = true;
@@ -37,10 +39,10 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!FileGen::writeDir('datasets/'.$dir))
if (!CLISetup::writeDir('datasets/'.$dir))
$success = false;
foreach (FileGen::$localeIds as $lId)
foreach (CLISetup::$localeIds as $lId)
{
User::useLocale($lId);
Lang::load(Util::$localeStrings[$lId]);
@@ -54,7 +56,7 @@ if (!defined('AOWOW_REVISION'))
'id' => $set['id'],
'name' => (7 - $set['quality']).Util::jsEscape(Util::localizedString($set, 'name')),
'pieces' => [],
'heroic' => DB::Aowow()->SelectCell('SELECT IF (flags & 0x8, "true", "false") FROM ?_items WHERE id = ?d', $set['item1']),
'heroic' => !!$set['heroic'], // should be bool
'maxlevel' => $set['maxLevel'],
'minlevel' => $set['minLevel'],
'type' => $set['type'],
@@ -123,7 +125,7 @@ if (!defined('AOWOW_REVISION'))
$toFile = "var g_itemsets = ".Util::toJSON($itemsetOut).";";
$file = 'datasets/'.User::$localeString.'/itemsets';
if (!FileGen::writeFile($file, $toFile))
if (!CLISetup::writeFile($file, $toFile))
$success = false;
}

View File

@@ -3,6 +3,9 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// Create 'locale.js'-file in static/js
// available locales have to be set in aowow.aowow_config
@@ -43,7 +46,7 @@ if (!defined('AOWOW_REVISION'))
" }",
);
foreach (FileGen::$localeIds as $l)
foreach (CLISetup::$localeIds as $l)
if (isset($available[$l]))
$result[] = $available[$l];

View File

@@ -3,6 +3,9 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// builds 'pets'-file for available locales
@@ -23,6 +26,8 @@ if (!defined('AOWOW_REVISION'))
},
*/
$reqDBC = ['creatureFamily'];
function pets()
{
$success = true;
@@ -32,25 +37,26 @@ if (!defined('AOWOW_REVISION'))
cr.name_loc0, cr.name_loc2, cr.name_loc3, cr.name_loc6, cr.name_loc8,
cr.minLevel,
cr.maxLevel,
CONCAT("[", ft.A, ", ", ft.H, "]") AS react,
ft.A,
ft.H,
cr.rank AS classification,
cr.family,
cr.displayId1 AS displayId,
cr.textureString AS skin,
p.iconString AS icon,
p.type
LOWER(SUBSTRING_INDEX(cf.iconString, "\\\\", -1)) AS icon,
cf.petTalentType AS type
FROM ?_creature cr
JOIN ?_factiontemplate ft ON ft.Id = cr.faction
JOIN ?_pet p ON p.id = cr.family
JOIN ?_factiontemplate ft ON ft.Id = cr.faction
JOIN dbc_creaturefamily cf ON cf.id = cr.family
WHERE cr.typeFlags & 0x1 AND (cr.cuFlags & 0x2) = 0
ORDER BY cr.id ASC');
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!FileGen::writeDir('datasets/'.$dir))
if (!CLISetup::writeDir('datasets/'.$dir))
$success = false;
foreach (FileGen::$localeIds as $lId)
foreach (CLISetup::$localeIds as $lId)
{
User::useLocale($lId);
Lang::load(Util::$localeStrings[$lId]);
@@ -69,7 +75,7 @@ if (!defined('AOWOW_REVISION'))
'minlevel' => $pet['minLevel'],
'maxlevel' => $pet['maxLevel'],
'location' => $locations[$pet['id']],
'react' => $pet['react'],
'react' => [$pet['A'], $pet['H']],
'classification' => $pet['classification'],
'family' => $pet['family'],
'displayId' => $pet['displayId'],
@@ -82,7 +88,7 @@ if (!defined('AOWOW_REVISION'))
$toFile = "var g_pets = ".Util::toJSON($petsOut).";";
$file = 'datasets/'.User::$localeString.'/pets';
if (!FileGen::writeFile($file, $toFile))
if (!CLISetup::writeFile($file, $toFile))
$success = false;
}

View File

@@ -3,6 +3,9 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// gatheres quasi-static data used in profiler: all available quests, achievements, titles, mounts, companions, factions, recipes
// this script requires a fully set up database and is expected to be run last
@@ -35,7 +38,7 @@ if (!defined('AOWOW_REVISION'))
$relCurr = new CurrencyList(array(['id', $_]));
foreach (FileGen::$localeIds as $l)
foreach (CLISetup::$localeIds as $l)
{
set_time_limit(20);
@@ -52,7 +55,7 @@ if (!defined('AOWOW_REVISION'))
$buff .= "\ng_quest_catorder = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n";
if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-quests', $buff))
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-quests', $buff))
$success = false;
}
@@ -72,7 +75,7 @@ if (!defined('AOWOW_REVISION'))
);
$achievez = new AchievementList($condition);
foreach (FileGen::$localeIds as $l)
foreach (CLISetup::$localeIds as $l)
{
set_time_limit(5);
@@ -92,7 +95,7 @@ if (!defined('AOWOW_REVISION'))
// sum points
$buff .= "\ng_achievement_points = [".$sumPoints."];\n";
if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-achievements', $buff))
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-achievements', $buff))
$success = false;
}
@@ -111,7 +114,7 @@ if (!defined('AOWOW_REVISION'))
);
$titlez = new TitleList($condition);
foreach (FileGen::$localeIds as $l)
foreach (CLISetup::$localeIds as $l)
{
set_time_limit(5);
@@ -128,7 +131,7 @@ if (!defined('AOWOW_REVISION'))
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
}
if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-titles-'.$g, $buff))
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-titles-'.$g, $buff))
$success = false;
}
}
@@ -149,7 +152,7 @@ if (!defined('AOWOW_REVISION'))
);
$mountz = new SpellList($condition);
foreach (FileGen::$localeIds as $l)
foreach (CLISetup::$localeIds as $l)
{
set_time_limit(5);
@@ -164,7 +167,7 @@ if (!defined('AOWOW_REVISION'))
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
}
if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-mounts', $buff))
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-mounts', $buff))
$success = false;
}
@@ -184,7 +187,7 @@ if (!defined('AOWOW_REVISION'))
);
$companionz = new SpellList($condition);
foreach (FileGen::$localeIds as $l)
foreach (CLISetup::$localeIds as $l)
{
set_time_limit(5);
@@ -199,7 +202,7 @@ if (!defined('AOWOW_REVISION'))
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
}
if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-companions', $buff))
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-companions', $buff))
$success = false;
}
@@ -218,7 +221,7 @@ if (!defined('AOWOW_REVISION'))
);
$factionz = new FactionList($condition);
foreach (FileGen::$localeIds as $l)
foreach (CLISetup::$localeIds as $l)
{
set_time_limit(5);
@@ -231,7 +234,7 @@ if (!defined('AOWOW_REVISION'))
$buff .= "\ng_faction_order = [0, 469, 891, 1037, 1118, 67, 1052, 892, 936, 1117, 169, 980, 1097];\n";
if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-factions', $buff))
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-factions', $buff))
$success = false;
}
@@ -269,7 +272,7 @@ if (!defined('AOWOW_REVISION'))
}
}
foreach (FileGen::$localeIds as $l)
foreach (CLISetup::$localeIds as $l)
{
set_time_limit(10);
@@ -283,7 +286,7 @@ if (!defined('AOWOW_REVISION'))
if (!$buff)
{
// this behaviour is intended, do not create an error
FileGen::status('profiler - file datasets/'.User::$localeString.'/p-recipes-'.$file.' has no content => skipping', MSG_LVL_WARN);
CLISetup::log('profiler - file datasets/'.User::$localeString.'/p-recipes-'.$file.' has no content => skipping', CLISetup::LOG_WARN);
continue;
}
@@ -292,7 +295,7 @@ if (!defined('AOWOW_REVISION'))
if (is_array($s))
$buff .= "\ng_skill_order = [171, 164, 333, 202, 182, 773, 755, 165, 186, 393, 197, 185, 129, 356];\n";
if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-recipes-'.$file, $buff))
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-recipes-'.$file, $buff))
$success = false;
}
}
@@ -302,7 +305,7 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!FileGen::writeDir('datasets/'.$dir))
if (!CLISetup::writeDir('datasets/'.$dir))
$success = false;
// run scripts

View File

@@ -3,6 +3,9 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// Create 'profile_all.js'-file in static/js;
// this script requires all realms in use to be defined in auth.realmlist
@@ -37,27 +40,32 @@ if (!defined('AOWOW_REVISION'))
{
$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]]]
];
$rows = DB::Auth()->select('SELECT name, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0');
$set = 0x0;
foreach ($rows as $row)
if (DB::isConnectable(DB_AUTH))
{
if ($row['region'] == 'eu')
$rows = DB::Auth()->select('SELECT name, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0');
foreach ($rows as $row)
{
$set |= 0x1;
$subEU[] = [Util::urlize($row['name']), $row['name']];
}
else if ($row['region'] == 'us')
{
$set |= 0x2;
$subUS[] = [Util::urlize($row['name']), $row['name']];
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);

View File

@@ -3,6 +3,9 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// Create 'realms'-file in datasets
// this script requires all realms in use to be defined in auth.realmlist
@@ -25,12 +28,16 @@ if (!defined('AOWOW_REVISION'))
function realms()
{
$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', CFG_BATTLEGROUP);
$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', CFG_BATTLEGROUP);
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 FileGen::writeFile($file, $toFile);
return CLISetup::writeFile($file, $toFile);
}
?>

View File

@@ -1,13 +1,18 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// note: for the sake of simplicity, this function handles all whole images (which are mostly icons)
// quest icons from GossipFrame have an alphaChannel that cannot be handled by this script
// lfgFrame/lfgIcon*.blp .. candidates for zonePage, but in general too detailed to scale them down from 128 to 56, 36, ect
$reqDBC = ['holidays', 'spellicon', 'itemdisplayinfo'];
function simpleImg()
{
if (isset(FileGen::$cliOpts['help']))
@@ -22,22 +27,10 @@ if (!defined('AOWOW_REVISION'))
return true;
}
if (!class_exists('DBC'))
{
FileGen::status(' - simpleImg: required class DBC was not included', MSG_LVL_ERROR);
return false;
}
if (!function_exists('imagecreatefromblp'))
{
FileGen::status(' - simpleImg: required include imagecreatefromblp() was not included', MSG_LVL_ERROR);
return false;
}
$locStr = '';
$locStr = null;
$groups = [];
$dbcPath = FileGen::$srcDir.'%sDBFilesClient/';
$imgPath = FileGen::$srcDir.'%sInterface/';
$dbcPath = CLISetup::$srcDir.'%sDBFilesClient/';
$imgPath = CLISetup::$srcDir.'%sInterface/';
$destDir = 'static/images/wow/';
$success = true;
$iconDirs = array(
@@ -154,36 +147,43 @@ if (!defined('AOWOW_REVISION'))
$ok = imagepng($dest, $name.'.'.$ext);
break;
default:
FileGen::status($done.' - unsupported file fromat: '.$ext, MSG_LVL_WARN);
CLISetup::log($done.' - unsupported file fromat: '.$ext, CLISetup::LOG_WARN);
}
imagedestroy($dest);
if ($ok)
{
chmod($name.'.'.$ext, FileGen::$accessMask);
FileGen::status($done.' - image '.$name.'.'.$ext.' written', MSG_LVL_OK);
chmod($name.'.'.$ext, CLISetup::FILE_ACCESS);
CLISetup::log($done.' - image '.$name.'.'.$ext.' written', CLISetup::LOG_OK);
}
else
FileGen::status($done.' - could not create image '.$name.'.'.$ext, MSG_LVL_ERROR);
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 (!FileGen::fileExists($p))
$missing[] = $p;
if (!CLISetup::fileExists($p))
{
$hasMissing = true;
$missing[] = $p;
}
}
$p = sprintf($dbcPath, $sub);
if (!FileGen::fileExists($p))
$missing[] = $p;
if (!CLISetup::fileExists($p))
{
$hasMissing = true;
$missing[] = $p;
}
return !$missing;
return !$hasMissing;
};
if (isset(FileGen::$cliOpts['icons']))
@@ -203,25 +203,24 @@ if (!defined('AOWOW_REVISION'))
if (!in_array($k, $groups))
unset($paths[$k]);
foreach (FileGen::$localeIds as $l)
foreach (CLISetup::$expectedPaths as $xp => $__)
{
if ($checkSourceDirs(Util::$localeStrings[$l].'/'))
if ($xp) // if in subDir add trailing slash
$xp .= '/';
if ($checkSourceDirs($xp, $missing))
{
$locStr = Util::$localeStrings[$l].'/';
$locStr = $xp;
break;
}
}
// manually check for enGB
if (!$locStr && $checkSourceDirs('enGB/'))
$locStr = 'enGB/';
// if no subdir had sufficient data, check mpq-root
if (!$locStr && !$checkSourceDirs('', $missing))
// if no subdir had sufficient data, diaf
if ($locStr === null)
{
FileGen::status('one or more required directories are missing:', MSG_LVL_ERROR);
CLISetup::log('one or more required directories are missing:', CLISetup::LOG_ERROR);
foreach ($missing as $m)
FileGen::status(' - '.$m, MSG_LVL_ERROR);
CLISetup::log(' - '.$m, CLISetup::LOG_ERROR);
return;
}
@@ -229,7 +228,7 @@ if (!defined('AOWOW_REVISION'))
// init directories
foreach (array_column($paths, 1) as $subDirs)
foreach ($subDirs as $sd)
if (!FileGen::writeDir($destDir.$sd[0]))
if (!CLISetup::writeDir($destDir.$sd[0]))
$success = false;
// ok, departure from std::procedure here
@@ -240,44 +239,42 @@ if (!defined('AOWOW_REVISION'))
if (isset($paths[0]) || isset($paths[1])) // generates icons or glyphs
{
$spellIcon = new DBC('SpellIcon');
if (isset($paths[0]) && !isset($paths[1]))
$siRows = $spellIcon->readFiltered(function(&$val) { return !stripos($val['iconPath'], 'glyph-rune'); });
$siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon WHERE iconPath NOT LIKE "glyph-rune"');
else if (!isset($paths[0]) && isset($paths[1]))
$siRows = $spellIcon->readFiltered(function(&$val) { return stripos($val['iconPath'], 'glyph-rune'); });
$siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon WHERE iconPath LIKE "glyph-rune"');
else
$siRows = $spellIcon->readArbitrary();
$siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon');
foreach ($siRows as $row)
$dbcEntries[] = sprintf('setup/mpqdata/%s', $locStr).strtr($row['iconPath'], ['\\' => '/']).'.blp';
foreach ($siRows as $icon)
$dbcEntries[] = strtolower(sprintf('setup/mpqdata/%s', $locStr).strtr($icon, ['\\' => '/']).'.blp');
}
if (isset($paths[0]))
{
$itemDisplayInfo = new DBC('ItemDisplayInfo');
foreach ($itemDisplayInfo->readArbitrary() as $row)
$dbcEntries[] = sprintf($imgPath, $locStr).'Icons/'.$row['inventoryIcon1'].'.blp';
$itemIcons = DB::Aowow()->selectCol('SELECT inventoryIcon1 FROM dbc_itemdisplayinfo WHERE inventoryIcon1 <> ""');
foreach ($itemIcons as $icon)
$dbcEntries[] = strtolower(sprintf($imgPath, $locStr).'Icons/'.$icon.'.blp');
$holidays = new DBC('Holidays');
$holiRows = $holidays->readFiltered(function(&$val) { return !empty($val['textureString']); });
foreach ($holiRows as $row)
$dbcEntries[] = sprintf($imgPath, $locStr).'Calendar/Holidays/'.$row['textureString'].'Start.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(array_map('strtolower',$dbcEntries)));
$dbcEntries = array_intersect_key($dbcEntries, array_unique($dbcEntries));
$allPaths = [];
foreach ($paths as $i => $p)
{
$path = sprintf($imgPath, $locStr).$p[0];
if (!FileGen::fileExists($path))
if (!CLISetup::fileExists($path))
continue;
$files = glob($path.$p[2], GLOB_BRACE);
$allPaths = array_merge($allPaths, $files);
FileGen::status('processing '.count($files).' files in '.$path.'...');
CLISetup::log('processing '.count($files).' files in '.$path.'...');
$j = 0;
foreach ($files as $f)
@@ -297,7 +294,7 @@ if (!defined('AOWOW_REVISION'))
else if (!$p[4])
{
$j += count($p[1]);
FileGen::status('skipping extraneous file '.$img.' (+'.count($p[1]).')');
CLISetup::log('skipping extraneous file '.$img.' (+'.count($p[1]).')');
continue;
}
}
@@ -318,7 +315,7 @@ if (!defined('AOWOW_REVISION'))
if (!isset(FileGen::$cliOpts['force']) && file_exists($destDir.$info[0].$img.'.'.$info[1]))
{
FileGen::status($done.' - file '.$info[0].$img.'.'.$info[1].' was already processed');
CLISetup::log($done.' - file '.$info[0].$img.'.'.$info[1].' was already processed');
continue;
}
@@ -359,10 +356,10 @@ if (!defined('AOWOW_REVISION'))
imagecopyresampled($dest, $src, 5, 0, 64 + 1, 32 + 1, 10, 16, 18, 28);
if (imagegif($dest, $destDir.$info[0].'quest_startend.gif'))
FileGen::status(' extra - image '.$destDir.$info[0].'quest_startend.gif written', MSG_LVL_OK);
CLISetup::log(' extra - image '.$destDir.$info[0].'quest_startend.gif written', CLISetup::LOG_OK);
else
{
FileGen::status(' extra - could not create image '.$destDir.$info[0].'quest_startend.gif', MSG_LVL_ERROR);
CLISetup::log(' extra - could not create image '.$destDir.$info[0].'quest_startend.gif', CLISetup::LOG_ERROR);
$success = false;
}
@@ -381,7 +378,7 @@ if (!defined('AOWOW_REVISION'))
if (!isset(FileGen::$cliOpts['force']) && file_exists($destDir.$info[0].$img.'.'.$info[1]))
{
FileGen::status($done.' - file '.$info[0].$img.'.'.$info[1].' was already processed');
CLISetup::log($done.' - file '.$info[0].$img.'.'.$info[1].' was already processed');
continue;
}
@@ -419,9 +416,9 @@ if (!defined('AOWOW_REVISION'))
if ($missing = array_diff(array_map('strtolower', $dbcEntries), array_map('strtolower', $allPaths)))
{
asort($missing);
FileGen::status('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.', MSG_LVL_WARN);
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)
FileGen::status(' - '.$m);
CLISetup::log(' - '.$m);
}
return $success;

View File

@@ -3,27 +3,21 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* player_classlevelstats
* player_levelstats
*/
// Create 'statistics'-file in datasets
// this script requires the following dbcs to be available
// gtChanceToMeleeCrit.dbc, gtChanceToSpellCrit.dbc, gtChanceToMeleeCritBase.dbc, gtChanceToSpellCritBase.dbc, gtOCTRegenHP.dbc, gtRegenMPPerSpt.dbc, gtRegenHPPerSpt.dbc
$reqDBC = ['gtchancetomeleecrit', 'gtchancetomeleecritbase', 'gtchancetospellcrit', 'gtchancetospellcritbase', 'gtoctregenhp', 'gtregenmpperspt', 'gtregenhpperspt'];
function statistics()
{
// expected dbcs
$req = ['dbc_gtchancetomeleecrit', 'dbc_gtchancetomeleecritbase', 'dbc_gtchancetospellcrit', 'dbc_gtchancetospellcritbase', 'dbc_gtoctregenhp', 'dbc_gtregenmpperspt', 'dbc_gtregenhpperspt'];
$found = DB::Aowow()->selectCol('SHOW TABLES LIKE "dbc_%"');
if ($missing = array_diff($req, $found))
{
foreach ($missing as $m)
{
$file = explode('_', $m)[1];
$dbc = new DBC($file);
if ($dbc->readFromFile())
$dbc->writeToDB();
}
}
$classs = function()
{
// constants and mods taken from TrinityCore (Player.cpp, StatSystem.cpp)
@@ -101,22 +95,38 @@ if (!defined('AOWOW_REVISION'))
else
$offset = [20, 20, 20, 20, 20];
$rows = DB::Aowow()->select('SELECT pls.level AS ARRAY_KEY, str-?d, agi-?d, sta-?d, inte-?d, spi-?d, basehp, IF(basemana <> 0, basemana, 100), mlecrt.chance*100, splcrt.chance*100, mlecrt.chance*100 * ?f, baseHP5.ratio*1, extraHP5.ratio*1 ' .
'FROM player_levelstats pls JOIN player_classlevelstats pcls ON pls.level = pcls.level AND pls.class = pcls.class JOIN' .
' dbc_gtchancetomeleecrit mlecrt ON mlecrt.idx = ((pls.class - 1) * 100) + (pls.level - 1) JOIN' .
' dbc_gtchancetospellcrit splcrt ON splcrt.idx = ((pls.class - 1) * 100) + (pls.level - 1) JOIN' .
' dbc_gtoctregenhp baseHP5 ON baseHP5.idx = ((pls.class - 1) * 100) + (pls.level - 1) JOIN' .
' dbc_gtregenhpperspt extraHP5 ON extraHP5.idx = ((pls.class - 1) * 100) + (pls.level - 1) ' .
'WHERE pls.race = ?d AND pls.class = ?d ORDER BY pls.level ASC',
$offset[0], $offset[1], $offset[2], $offset[3], $offset[4],
$gtData = DB::Aowow()->select('
SELECT mlecrt.idx - ?d AS ARRAY_KEY, mlecrt.chance * 100, splcrt.chance * 100, mlecrt.chance * 100 * ?f, baseHP5.ratio * 1, extraHP5.ratio * 1
FROM dbc_gtchancetomeleecrit mlecrt
JOIN dbc_gtchancetospellcrit splcrt ON splcrt.idx = mlecrt.idx
JOIN dbc_gtoctregenhp baseHP5 ON baseHP5.idx = mlecrt.idx
JOIN dbc_gtregenhpperspt extraHP5 ON extraHP5.idx = mlecrt.idx
WHERE mlecrt.idx BETWEEN ?d AND ?d',
(($class - 1) * 100) - 1, // class-offset
$mod,
(($class - 1) * 100) + 0, // lvl 1
(($class - 1) * 100) + 79 // lvl 80
);
$rows = DB::World()->select('
SELECT
pls.level AS ARRAY_KEY,
pls.str - ?d, pls.agi - ?d, pls.sta - ?d, pls.inte - ?d, pls.spi - ?d,
pcls.basehp, IF(pcls.basemana <> 0, pcls.basemana, 100)
FROM
player_levelstats pls
JOIN
player_classlevelstats pcls ON pls.level = pcls.level AND pls.class = pcls.class
WHERE
pls.race = ?d AND pls.class = ?d ORDER BY pls.level ASC',
$offset[0], $offset[1], $offset[2], $offset[3], $offset[4],
in_array($class, [3, 7, 11]) ? 6 : 1,
$class
);
$result[$class] = [];
foreach ($rows as $k => $row)
$result[$class][$k] = array_values($row);
foreach ($rows as $lvl => $row)
$result[$class][$lvl] = array_values(array_merge($row, $gtData[$lvl]));
}
return $result;
@@ -149,14 +159,14 @@ if (!defined('AOWOW_REVISION'))
$out[$s] = $res;
if (!$res)
{
FileGen::status('statistics - generator $'.$s.'() returned empty', MSG_LVL_WARN);
CLISetup::log('statistics - generator $'.$s.'() returned empty', CLISetup::LOG_WARN);
$success = false;
}
}
$toFile = 'g_statistics = '.preg_replace('/"\$([^$"]+)"/', '\1', Util::toJSON($out)).';';
if (!FileGen::writeFile('datasets/statistics', $toFile))
if (!CLISetup::writeFile('datasets/statistics', $toFile))
$success = false;
return $success;

View File

@@ -3,38 +3,27 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// builds image-textures for the talent-calculator
// spellIcons must be extracted and converted to at least medium size
// this script requires the following dbc-files to be available
// Talent.dbc, TalentTab.dbc
$reqDBC = ['talenttab', 'talent', 'spell'];
function talentIcons()
{
// expected dbcs
$req = ['dbc_talenttab', 'dbc_talent'];
$found = DB::Aowow()->selectCol('SHOW TABLES LIKE "dbc_%"');
if ($missing = array_diff($req, $found))
{
foreach ($missing as $m)
{
$file = explode('_', $m)[1];
$dbc = new DBC($file);
if ($dbc->readFromFile($file == 'talenttab'))
$dbc->writeToDB();
}
}
$success = true;
$query = 'SELECT s.iconString FROM ?_spell s JOIN dbc_talent t ON t.rank1 = s.Id JOIN dbc_talenttab tt ON tt.Id = t.tabId WHERE tt.?# = ?d AND tt.tabNumber = ?d ORDER BY t.row, t.column, t.petCategory1 ASC;';
$query = 'SELECT ic.iconString FROM ?_icons ic JOIN dbc_spell s ON s.iconId = ic.Id JOIN dbc_talent t ON t.rank1 = s.Id JOIN dbc_talenttab tt ON tt.Id = t.tabId WHERE tt.?# = ?d AND tt.tabNumber = ?d ORDER BY t.row, t.column, t.petCategory1 ASC';
$dims = 36; //v-pets
$filenames = ['icons', 'warrior', 'paladin', 'hunter', 'rogue', 'priest', 'deathknight', 'shaman', 'mage', 'warlock', null, 'druid'];
// create directory if missing
if (!FileGen::writeDir('static/images/wow/talents/icons'))
if (!CLISetup::writeDir('static/images/wow/talents/icons'))
$success = false;
if (!FileGen::writeDir('static/images/wow/hunterpettalents'))
if (!CLISetup::writeDir('static/images/wow/hunterpettalents'))
$success = false;
foreach ($filenames as $k => $v)
@@ -55,7 +44,7 @@ if (!defined('AOWOW_REVISION'))
if (empty($icons))
{
FileGen::status('talentIcons - query for '.$v.' tree: '.$k.' returned empty', MSG_LVL_ERROR);
CLISetup::log('talentIcons - query for '.$v.' tree: '.$k.' returned empty', CLISetup::LOG_ERROR);
$success = false;
continue;
}
@@ -67,7 +56,7 @@ if (!defined('AOWOW_REVISION'))
$imgFile = 'static/images/wow/icons/medium/'.strtolower($icons[$i]).'.jpg';
if (!file_exists($imgFile))
{
FileGen::status('talentIcons - raw image '.$imgFile. ' not found', MSG_LVL_ERROR);
CLISetup::log('talentIcons - raw image '.CLISetup::bold($imgFile). ' not found', CLISetup::LOG_ERROR);
$success = false;
break;
}
@@ -91,17 +80,17 @@ if (!defined('AOWOW_REVISION'))
}
if (@imagejpeg($res, $outFile))
FileGen::status(sprintf(ERR_NONE, $outFile), MSG_LVL_OK);
CLISetup::log(sprintf(ERR_NONE, CLISetup::bold($outFile)), CLISetup::LOG_OK);
else
{
$success = false;
FileGen::status('talentIcons - '.$outFile.'.jpg could not be written', MSG_LVL_ERROR);
CLISetup::log('talentIcons - '.CLISetup::bold($outFile.'.jpg').' could not be written', CLISetup::LOG_ERROR);
}
}
else
{
$success = false;
FileGen::status('talentIcons - image resource not created', MSG_LVL_ERROR);
CLISetup::log('talentIcons - image resource not created', CLISetup::LOG_ERROR);
continue;
}
}

View File

@@ -3,10 +3,9 @@
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// builds talent-tree-data for the talent-calculator
// this script requires the following dbc-files to be available
// Talent.dbc, TalentTab.dbc
// talents
// i - int talentId (id of aowow_talent)
@@ -25,22 +24,12 @@ if (!defined('AOWOW_REVISION'))
// t - array of talent-objects
// f - array:int [pets only] creatureFamilies in that category
// builds talent-tree-data for the talent-calculator
// this script requires the following dbc-files to be available
$reqDBC = ['talenttab', 'talent', 'spell', 'creaturefamily', 'spellicon'];
function talents()
{
// expected dbcs
$req = ['dbc_talenttab', 'dbc_talent'];
$found = DB::Aowow()->selectCol('SHOW TABLES LIKE "dbc_%"');
if ($missing = array_diff($req, $found))
{
foreach ($missing as $m)
{
$file = explode('_', $m)[1];
$dbc = new DBC($file);
if ($dbc->readFromFile($file == 'talenttab'))
$dbc->writeToDB();
}
}
$success = true;
$buildTree = function ($class) use (&$petFamIcons, &$tSpells)
{
@@ -54,7 +43,7 @@ if (!defined('AOWOW_REVISION'))
for ($l = 0; $l < count($tabs); $l++)
{
$talents = DB::Aowow()->select('SELECT t.id AS tId, t.*, s.* FROM dbc_talent t, ?_spell s WHERE t.`tabId`= ?d AND s.`Id` = t.`rank1` ORDER by t.`row`, t.`column`', $tabs[$l]['Id']);
$talents = DB::Aowow()->select('SELECT t.id AS tId, t.*, s.name_loc0, s.name_loc2, s.name_loc3, s.name_loc6, s.name_loc8, LOWER(SUBSTRING_INDEX(si.iconPath, "\\\\", -1)) AS iconString FROM dbc_talent t, dbc_spell s, dbc_spellicon si WHERE si.`Id` = s.`iconId` AND t.`tabId`= ?d AND s.`Id` = t.`rank1` ORDER by t.`row`, t.`column`', $tabs[$l]['Id']);
$result[$l] = array(
'n' => Util::localizedString($tabs[$l], 'name'),
't' => []
@@ -64,7 +53,7 @@ if (!defined('AOWOW_REVISION'))
{
$petFamId = log($tabs[$l]['creatureFamilyMask'], 2);
$result[$l]['icon'] = $petFamIcons[$petFamId];
$petCategories = DB::Aowow()->SelectCol('SELECT Id AS ARRAY_KEY, category FROM ?_pet WHERE type = ?d', $petFamId);
$petCategories = DB::Aowow()->SelectCol('SELECT Id AS ARRAY_KEY, categoryEnumID FROM dbc_creaturefamily WHERE petTalentType = ?d', $petFamId);
$result[$l]['f'] = array_keys($petCategories);
}
@@ -170,13 +159,13 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!FileGen::writeDir('datasets/'.$dir))
if (!CLISetup::writeDir('datasets/'.$dir))
$success = false;
$tSpellIds = DB::Aowow()->selectCol('SELECT rank1 FROM dbc_talent UNION SELECT rank2 FROM dbc_talent UNION SELECT rank3 FROM dbc_talent UNION SELECT rank4 FROM dbc_talent UNION SELECT rank5 FROM dbc_talent');
$tSpells = new SpellList(array(['s.id', $tSpellIds], CFG_SQL_LIMIT_NONE));
foreach (FileGen::$localeIds as $lId)
foreach (CLISetup::$localeIds as $lId)
{
User::useLocale($lId);
Lang::load(Util::$localeStrings[$lId]);
@@ -190,14 +179,14 @@ if (!defined('AOWOW_REVISION'))
$file = 'datasets/'.User::$localeString.'/talents-'.$cId;
$toFile = '$WowheadTalentCalculator.registerClass('.$cId.', '.Util::toJSON($buildTree($cId)).')';
if (!FileGen::writeFile($file, $toFile))
if (!CLISetup::writeFile($file, $toFile))
$success = false;
}
// PetCalc
if (empty($petIcons))
{
$pets = DB::Aowow()->SelectCol('SELECT Id AS ARRAY_KEY, iconString FROM ?_pet');
$pets = DB::Aowow()->SelectCol('SELECT Id AS ARRAY_KEY, LOWER(SUBSTRING_INDEX(iconString, "\\\\", -1)) AS iconString FROM dbc_creaturefamily WHERE petTalentType IN (0, 1, 2)');
$petIcons = Util::toJSON($pets);
}
@@ -205,7 +194,7 @@ if (!defined('AOWOW_REVISION'))
$toFile .= 'var g_pet_talents = '.Util::toJSON($buildTree(0)).';';
$file = 'datasets/'.User::$localeString.'/pet-talents';
if (!FileGen::writeFile($file, $toFile))
if (!CLISetup::writeFile($file, $toFile))
$success = false;
}

View File

@@ -22,11 +22,18 @@
// imagejpeg($img);
// imagedestroy($img);
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
function imagecreatefromblp($fileName, $imgId = 0)
{
if (!FileGen::fileExists($fileName))
if (!CLISetup::fileExists($fileName))
{
FileGen::status('file '.$fileName.' could not be found', MSG_LVL_ERROR);
CLISetup::log('file '.$fileName.' could not be found', MSG_LVL_ERROR);
return;
}
@@ -34,14 +41,14 @@
if (!$file)
{
FileGen::status('could not open file '.$fileName, MSG_LVL_ERROR);
CLISetup::log('could not open file '.$fileName, MSG_LVL_ERROR);
return;
}
$fileSize = fileSize($fileName);
if ($fileSize < 16)
{
FileGen::status('file '.$fileName.' is too small for a BLP file', MSG_LVL_ERROR);
CLISetup::log('file '.$fileName.' is too small for a BLP file', MSG_LVL_ERROR);
return;
}
@@ -57,14 +64,14 @@
$data = substr($data, 0x44);
else
{
FileGen::status('file '.$fileName.' is an incremental patch file and cannot be used by this script.', MSG_LVL_ERROR);
CLISetup::log('file '.$fileName.' is an incremental patch file and cannot be used by this script.', MSG_LVL_ERROR);
return;
}
}
if (substr($data, 0, 4) != "BLP2")
{
FileGen::status('file '.$fileName.' has incorrect/unsupported magic bytes', MSG_LVL_ERROR);
CLISetup::log('file '.$fileName.' has incorrect/unsupported magic bytes', MSG_LVL_ERROR);
return;
}
@@ -76,7 +83,7 @@
if ($header['format'] != 1)
{
FileGen::status('file '.$fileName.' has unsupported format'.$debugStr, MSG_LVL_ERROR);
CLISetup::log('file '.$fileName.' has unsupported format'.$debugStr, MSG_LVL_ERROR);
return;
}
@@ -92,12 +99,12 @@
if ($size == 0)
{
FileGen::status('file '.$fileName.' contains zeroes in a mips table'.$debugStr, MSG_LVL_ERROR);
CLISetup::log('file '.$fileName.' contains zeroes in a mips table'.$debugStr, MSG_LVL_ERROR);
return;
}
if ($offs + $size > $fileSize)
{
FileGen::status('file '.$fileName.' is corrupted/incomplete'.$debugStr, MSG_LVL_ERROR);
CLISetup::log('file '.$fileName.' is corrupted/incomplete'.$debugStr, MSG_LVL_ERROR);
return;
}
@@ -109,7 +116,7 @@
$img = icfb3($header['width'], $header['height'], substr($data, $offs, $size));
else
{
FileGen::status('file '.$fileName.' has unsupported type'.$debugStr, MSG_LVL_ERROR);
CLISetup::log('file '.$fileName.' has unsupported type'.$debugStr, MSG_LVL_ERROR);
return;
}
@@ -145,7 +152,7 @@
{
if (!in_array($alphaBits * 10 + $alphaType, [0, 10, 41, 81, 87, 88]))
{
FileGen::status('unsupported compression type', MSG_LVL_ERROR);
CLISetup::log('unsupported compression type', MSG_LVL_ERROR);
return;
}

View File

@@ -1,431 +0,0 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
/*
-- custom itemSubClass
itemClass: itemSubClass - diff to Client
0: {
6: "Perm. Enhancement",
"-3": "Temp. Enhancement",
},
15: {
"-7": "Flying Mount",
"-6": "Combat Pet",
"-2": "Armor Token",
},
}
DROP TABLE IF EXISTS `aowow_item_stats`;
CREATE TABLE `aowow_item_stats` (
`id` mediumint(8) UNSIGNED NOT NULL ,
`nsockets` mediumint(8) NOT NULL ,
`dmgmin1` mediumint(8) NOT NULL ,
`dmgmax1` mediumint(8) NOT NULL ,
`speed` float(8,2) NOT NULL ,
`dps` float(8,2) NOT NULL ,
`mledmgmin` mediumint(8) NOT NULL ,
`mledmgmax` mediumint(8) NOT NULL ,
`mlespeed` float(8,2) NOT NULL ,
`mledps` float(8,2) NOT NULL ,
`rgddmgmin` mediumint(8) NOT NULL ,
`rgddmgmax` mediumint(8) NOT NULL ,
`rgdspeed` float(8,2) NOT NULL ,
`rgddps` float(8,2) NOT NULL ,
`dmg` float(8,2) NOT NULL ,
`damagetype` mediumint(8) NOT NULL ,
`mana` mediumint(8) NOT NULL ,
`health` mediumint(8) NOT NULL ,
`agi` mediumint(8) NOT NULL ,
`str` mediumint(8) NOT NULL ,
`int` mediumint(8) NOT NULL ,
`spi` mediumint(8) NOT NULL ,
`sta` mediumint(8) NOT NULL ,
`energy` mediumint(8) NOT NULL ,
`rage` mediumint(8) NOT NULL ,
`focus` mediumint(8) NOT NULL ,
`runicpwr` mediumint(8) NOT NULL ,
`defrtng` mediumint(8) NOT NULL ,
`dodgertng` mediumint(8) NOT NULL ,
`parryrtng` mediumint(8) NOT NULL ,
`blockrtng` mediumint(8) NOT NULL ,
`mlehitrtng` mediumint(8) NOT NULL ,
`rgdhitrtng` mediumint(8) NOT NULL ,
`splhitrtng` mediumint(8) NOT NULL ,
`mlecritstrkrtng` mediumint(8) NOT NULL ,
`rgdcritstrkrtng` mediumint(8) NOT NULL ,
`splcritstrkrtng` mediumint(8) NOT NULL ,
`_mlehitrtng` mediumint(8) NOT NULL ,
`_rgdhitrtng` mediumint(8) NOT NULL ,
`_splhitrtng` mediumint(8) NOT NULL ,
`_mlecritstrkrtng` mediumint(8) NOT NULL ,
`_rgdcritstrkrtng` mediumint(8) NOT NULL ,
`_splcritstrkrtng` mediumint(8) NOT NULL ,
`mlehastertng` mediumint(8) NOT NULL ,
`rgdhastertng` mediumint(8) NOT NULL ,
`splhastertng` mediumint(8) NOT NULL ,
`hitrtng` mediumint(8) NOT NULL ,
`critstrkrtng` mediumint(8) NOT NULL ,
`_hitrtng` mediumint(8) NOT NULL ,
`_critstrkrtng` mediumint(8) NOT NULL ,
`resirtng` mediumint(8) NOT NULL ,
`hastertng` mediumint(8) NOT NULL ,
`exprtng` mediumint(8) NOT NULL ,
`atkpwr` mediumint(8) NOT NULL ,
`mleatkpwr` mediumint(8) NOT NULL ,
`rgdatkpwr` mediumint(8) NOT NULL ,
`feratkpwr` mediumint(8) NOT NULL ,
`splheal` mediumint(8) NOT NULL ,
`spldmg` mediumint(8) NOT NULL ,
`manargn` mediumint(8) NOT NULL ,
`armorpenrtng` mediumint(8) NOT NULL ,
`splpwr` mediumint(8) NOT NULL ,
`healthrgn` mediumint(8) NOT NULL ,
`splpen` mediumint(8) NOT NULL ,
`block` mediumint(8) NOT NULL ,
`mastrtng` mediumint(8) NOT NULL ,
`armor` mediumint(8) NOT NULL ,
`armorbonus` mediumint(8) NOT NULL ,
`firres` mediumint(8) NOT NULL ,
`frores` mediumint(8) NOT NULL ,
`holres` mediumint(8) NOT NULL ,
`shares` mediumint(8) NOT NULL ,
`natres` mediumint(8) NOT NULL ,
`arcres` mediumint(8) NOT NULL ,
`firsplpwr` mediumint(8) NOT NULL ,
`frosplpwr` mediumint(8) NOT NULL ,
`holsplpwr` mediumint(8) NOT NULL ,
`shasplpwr` mediumint(8) NOT NULL ,
`natsplpwr` mediumint(8) NOT NULL ,
`arcsplpwr` mediumint(8) NOT NULL ,
PRIMARY KEY (`id`),
INDEX `item` (`id`)
) ENGINE=MyISAM DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE aowow_items LIKE item_template;
INSERT INTO aowow_items SELECT * FROM item_template;
ALTER TABLE `aowow_items`
DROP COLUMN `SoundOverrideSubclass`,
DROP COLUMN `StatsCount`,
DROP COLUMN `Material`,
DROP COLUMN `sheath`,
DROP COLUMN `WDBVerified`,
CHANGE COLUMN `entry` `id` mediumint(8) UNSIGNED NOT NULL DEFAULT 0 FIRST ,
ADD COLUMN `classBak` tinyint(3) NOT NULL AFTER `class`,
CHANGE COLUMN `subclass` `subClass` tinyint(3) NOT NULL DEFAULT 0 AFTER `classBak`,
ADD COLUMN `subClassBak` tinyint(3) NOT NULL AFTER `subClass`,
ADD COLUMN `subSubClass` tinyint(3) NOT NULL AFTER `subClassBak`,
CHANGE COLUMN `name` `name_loc0` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' AFTER `subSubClass`,
ADD COLUMN `name_loc2` varchar(255) NOT NULL AFTER `name_loc0`,
ADD COLUMN `name_loc3` varchar(255) NOT NULL AFTER `name_loc2`,
ADD COLUMN `name_loc6` varchar(255) NOT NULL AFTER `name_loc3`,
ADD COLUMN `name_loc8` varchar(255) NOT NULL AFTER `name_loc6`,
CHANGE COLUMN `displayid` `displayId` mediumint(8) UNSIGNED NOT NULL DEFAULT 0 AFTER `name_loc8`,
ADD COLUMN `model`varchar(127) NOT NULL AFTER `displayId`,
ADD COLUMN `iconString` varchar(127) NOT NULL AFTER `model`,
CHANGE COLUMN `Quality` `quality` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `displayId`,
CHANGE COLUMN `Flags` `flags` bigint(20) NOT NULL DEFAULT 0 AFTER `quality`,
CHANGE COLUMN `FlagsExtra` `flagsExtra` int(10) UNSIGNED NOT NULL DEFAULT 0 AFTER `flags`,
ADD COLUMN `cuFlags` int(10) NOT NULL AFTER `flagsExtra`,
CHANGE COLUMN `BuyCount` `buyCount` tinyint(3) UNSIGNED NOT NULL DEFAULT 1 AFTER `flagsExtra`,
CHANGE COLUMN `BuyPrice` `buyPrice` bigint(20) NOT NULL DEFAULT 0 AFTER `buyCount`,
CHANGE COLUMN `SellPrice` `sellPrice` int(10) UNSIGNED NOT NULL DEFAULT 0 AFTER `buyPrice`,
ADD COLUMN `repairPrice` int(10) UNSIGNED NOT NULL AFTER `sellPrice`,
ADD COLUMN `slot` tinyint(3) NOT NULL AFTER `repairPrice`,
CHANGE COLUMN `InventoryType` `slotBak` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `slot`,
CHANGE COLUMN `AllowableClass` `requiredClass` int(11) NOT NULL DEFAULT '-1' AFTER `slotBak`,
CHANGE COLUMN `AllowableRace` `requiredRace` int(11) NOT NULL DEFAULT '-1' AFTER `requiredClass`,
CHANGE COLUMN `ItemLevel` `itemLevel` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `requiredRace`,
CHANGE COLUMN `RequiredLevel` `requiredLevel` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `itemLevel`,
CHANGE COLUMN `RequiredSkill` `requiredSkill` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `requiredLevel`,
CHANGE COLUMN `RequiredSkillRank` `requiredSkillRank` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `requiredSkill`,
CHANGE COLUMN `requiredspell` `requiredSpell` mediumint(8) UNSIGNED NOT NULL DEFAULT 0 AFTER `requiredSkillRank`,
CHANGE COLUMN `requiredhonorrank` `requiredHonorRank` mediumint(8) UNSIGNED NOT NULL DEFAULT 0 AFTER `requiredSpell`,
CHANGE COLUMN `RequiredCityRank` `requiredCityRank` mediumint(8) UNSIGNED NOT NULL DEFAULT 0 AFTER `requiredHonorRank`,
CHANGE COLUMN `RequiredReputationFaction` `requiredFaction` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `requiredCityRank`,
CHANGE COLUMN `RequiredReputationRank` `requiredFactionRank` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `requiredFaction`,
CHANGE COLUMN `maxcount` `maxCount` int(11) NOT NULL DEFAULT 0 AFTER `requiredFactionRank`,
CHANGE COLUMN `ContainerSlots` `slots` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `stackable`,
CHANGE COLUMN `stat_type1` `statType1` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `slots`,
CHANGE COLUMN `stat_value1` `statValue1` smallint(6) NOT NULL DEFAULT 0 AFTER `statType1`,
CHANGE COLUMN `stat_type2` `statType2` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `statValue1`,
CHANGE COLUMN `stat_value2` `statValue2` smallint(6) NOT NULL DEFAULT 0 AFTER `statType2`,
CHANGE COLUMN `stat_type3` `statType3` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `statValue2`,
CHANGE COLUMN `stat_value3` `statValue3` smallint(6) NOT NULL DEFAULT 0 AFTER `statType3`,
CHANGE COLUMN `stat_type4` `statType4` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `statValue3`,
CHANGE COLUMN `stat_value4` `statValue4` smallint(6) NOT NULL DEFAULT 0 AFTER `statType4`,
CHANGE COLUMN `stat_type5` `statType5` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `statValue4`,
CHANGE COLUMN `stat_value5` `statValue5` smallint(6) NOT NULL DEFAULT 0 AFTER `statType5`,
CHANGE COLUMN `stat_type6` `statType6` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `statValue5`,
CHANGE COLUMN `stat_value6` `statValue6` smallint(6) NOT NULL DEFAULT 0 AFTER `statType6`,
CHANGE COLUMN `stat_type7` `statType7` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `statValue6`,
CHANGE COLUMN `stat_value7` `statValue7` smallint(6) NOT NULL DEFAULT 0 AFTER `statType7`,
CHANGE COLUMN `stat_type8` `statType8` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `statValue7`,
CHANGE COLUMN `stat_value8` `statValue8` smallint(6) NOT NULL DEFAULT 0 AFTER `statType8`,
CHANGE COLUMN `stat_type9` `statType9` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `statValue8`,
CHANGE COLUMN `stat_value9` `statValue9` smallint(6) NOT NULL DEFAULT 0 AFTER `statType9`,
CHANGE COLUMN `stat_type10` `statType10` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `statValue9`,
CHANGE COLUMN `stat_value10` `statValue10` smallint(6) NOT NULL DEFAULT 0 AFTER `statType10`,
CHANGE COLUMN `ScalingStatDistribution` `scalingStatDistribution` smallint(6) NOT NULL DEFAULT 0 AFTER `statValue10`,
CHANGE COLUMN `ScalingStatValue` `scalingStatValue` int(10) UNSIGNED NOT NULL DEFAULT 0 AFTER `scalingStatDistribution`,
CHANGE COLUMN `dmg_min1` `dmgMin1` float NOT NULL DEFAULT 0 AFTER `scalingStatValue`,
CHANGE COLUMN `dmg_max1` `dmgMax1` float NOT NULL DEFAULT 0 AFTER `dmgMin1`,
CHANGE COLUMN `dmg_type1` `dmgType1` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `dmgMax1`,
CHANGE COLUMN `dmg_min2` `dmgMin2` float NOT NULL DEFAULT 0 AFTER `dmgType1`,
CHANGE COLUMN `dmg_max2` `dmgMax2` float NOT NULL DEFAULT 0 AFTER `dmgMin2`,
CHANGE COLUMN `dmg_type2` `dmgType2` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `dmgMax2`,
MODIFY COLUMN `delay` smallint(5) UNSIGNED NOT NULL DEFAULT 1000 AFTER `dmgType2`,
MODIFY COLUMN `armor` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `delay`,
CHANGE COLUMN `ArmorDamageModifier` `armorDamageModifier` float NOT NULL DEFAULT 0 AFTER `armor`,
MODIFY COLUMN `block` mediumint(8) UNSIGNED NOT NULL DEFAULT 0 AFTER `armorDamageModifier`,
CHANGE COLUMN `holy_res` `resHoly` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `block`,
CHANGE COLUMN `fire_res` `resFire` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `resHoly`,
CHANGE COLUMN `nature_res` `resNature` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `resFire`,
CHANGE COLUMN `frost_res` `resFrost` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `resNature`,
CHANGE COLUMN `shadow_res` `resShadow` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `resFrost`,
CHANGE COLUMN `arcane_res` `resArcane` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `resShadow`,
CHANGE COLUMN `ammo_type` `ammoType` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `resArcane`,
CHANGE COLUMN `RangedModRange` `rangedModRange` float NOT NULL DEFAULT 0 AFTER `ammoType`,
CHANGE COLUMN `spellid_1` `spellId1` mediumint(8) NOT NULL DEFAULT 0 AFTER `rangedModRange`,
CHANGE COLUMN `spelltrigger_1` `spellTrigger1` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `spellId1`,
CHANGE COLUMN `spellcharges_1` `spellCharges1` smallint(6) NULL DEFAULT NULL AFTER `spellTrigger1`,
CHANGE COLUMN `spellppmRate_1` `spellppmRate1` float NOT NULL DEFAULT 0 AFTER `spellCharges1`,
CHANGE COLUMN `spellcooldown_1` `spellCooldown1` int(11) NOT NULL DEFAULT '-1' AFTER `spellppmRate1`,
CHANGE COLUMN `spellcategory_1` `spellCategory1` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `spellCooldown1`,
CHANGE COLUMN `spellcategorycooldown_1` `spellCategoryCooldown1` int(11) NOT NULL DEFAULT '-1' AFTER `spellCategory1`,
CHANGE COLUMN `spellid_2` `spellId2` mediumint(8) NOT NULL DEFAULT 0 AFTER `spellCategoryCooldown1`,
CHANGE COLUMN `spelltrigger_2` `spellTrigger2` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `spellId2`,
CHANGE COLUMN `spellcharges_2` `spellCharges2` smallint(6) NULL DEFAULT NULL AFTER `spellTrigger2`,
CHANGE COLUMN `spellppmRate_2` `spellppmRate2` float NOT NULL DEFAULT 0 AFTER `spellCharges2`,
CHANGE COLUMN `spellcooldown_2` `spellCooldown2` int(11) NOT NULL DEFAULT '-1' AFTER `spellppmRate2`,
CHANGE COLUMN `spellcategory_2` `spellCategory2` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `spellCooldown2`,
CHANGE COLUMN `spellcategorycooldown_2` `spellCategoryCooldown2` int(11) NOT NULL DEFAULT '-1' AFTER `spellCategory2`,
CHANGE COLUMN `spellid_3` `spellId3` mediumint(8) NOT NULL DEFAULT 0 AFTER `spellCategoryCooldown2`,
CHANGE COLUMN `spelltrigger_3` `spellTrigger3` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `spellId3`,
CHANGE COLUMN `spellcharges_3` `spellCharges3` smallint(6) NULL DEFAULT NULL AFTER `spellTrigger3`,
CHANGE COLUMN `spellppmRate_3` `spellppmRate3` float NOT NULL DEFAULT 0 AFTER `spellCharges3`,
CHANGE COLUMN `spellcooldown_3` `spellCooldown3` int(11) NOT NULL DEFAULT '-1' AFTER `spellppmRate3`,
CHANGE COLUMN `spellcategory_3` `spellCategory3` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `spellCooldown3`,
CHANGE COLUMN `spellcategorycooldown_3` `spellCategoryCooldown3` int(11) NOT NULL DEFAULT '-1' AFTER `spellCategory3`,
CHANGE COLUMN `spellid_4` `spellId4` mediumint(8) NOT NULL DEFAULT 0 AFTER `spellCategoryCooldown3`,
CHANGE COLUMN `spelltrigger_4` `spellTrigger4` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `spellId4`,
CHANGE COLUMN `spellcharges_4` `spellCharges4` smallint(6) NULL DEFAULT NULL AFTER `spellTrigger4`,
CHANGE COLUMN `spellppmRate_4` `spellppmRate4` float NOT NULL DEFAULT 0 AFTER `spellCharges4`,
CHANGE COLUMN `spellcooldown_4` `spellCooldown4` int(11) NOT NULL DEFAULT '-1' AFTER `spellppmRate4`,
CHANGE COLUMN `spellcategory_4` `spellCategory4` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `spellCooldown4`,
CHANGE COLUMN `spellcategorycooldown_4` `spellCategoryCooldown4` int(11) NOT NULL DEFAULT '-1' AFTER `spellCategory4`,
CHANGE COLUMN `spellid_5` `spellId5` mediumint(8) NOT NULL DEFAULT 0 AFTER `spellCategoryCooldown4`,
CHANGE COLUMN `spelltrigger_5` `spellTrigger5` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `spellId5`,
CHANGE COLUMN `spellcharges_5` `spellCharges5` smallint(6) NULL DEFAULT NULL AFTER `spellTrigger5`,
CHANGE COLUMN `spellppmRate_5` `spellppmRate5` float NOT NULL DEFAULT 0 AFTER `spellCharges5`,
CHANGE COLUMN `spellcooldown_5` `spellCooldown5` int(11) NOT NULL DEFAULT '-1' AFTER `spellppmRate5`,
CHANGE COLUMN `spellcategory_5` `spellCategory5` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `spellCooldown5`,
CHANGE COLUMN `spellcategorycooldown_5` `spellCategoryCooldown5` int(11) NOT NULL DEFAULT '-1' AFTER `spellCategory5`,
CHANGE COLUMN `description` `description_loc0` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' AFTER `bonding`,
ADD COLUMN `description_loc2` varchar(255) NOT NULL AFTER `description_loc0`,
ADD COLUMN `description_loc3` varchar(255) NOT NULL AFTER `description_loc2`,
ADD COLUMN `description_loc6` varchar(255) NOT NULL AFTER `description_loc3`,
ADD COLUMN `description_loc8` varchar(255) NOT NULL AFTER `description_loc6`,
CHANGE COLUMN `PageText` `pageTextId` mediumint(8) UNSIGNED NOT NULL DEFAULT 0 AFTER `description_loc8`,
CHANGE COLUMN `LanguageID` `languageId` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `pageTextId`,
CHANGE COLUMN `PageMaterial` `pageMaterial` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `languageId`,
CHANGE COLUMN `startquest` `startQuest` mediumint(8) UNSIGNED NOT NULL DEFAULT 0 AFTER `pageMaterial`,
CHANGE COLUMN `lockid` `lockId` mediumint(8) UNSIGNED NOT NULL DEFAULT 0 AFTER `startQuest`,
CHANGE COLUMN `RandomProperty` `randomEnchant` mediumint(8) NOT NULL DEFAULT 0 AFTER `lockId`;
MODIFY COLUMN `itemset` mediumint(8) UNSIGNED NOT NULL DEFAULT 0 AFTER `randomSuffix`,
CHANGE COLUMN `MaxDurability` `durability` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `itemset`,
CHANGE COLUMN `Map` `map` smallint(6) NOT NULL DEFAULT 0 AFTER `area`,
CHANGE COLUMN `BagFamily` `bagFamily` mediumint(8) NOT NULL DEFAULT 0 AFTER `map`,
CHANGE COLUMN `TotemCategory` `totemCategory` mediumint(8) NOT NULL DEFAULT 0 AFTER `bagFamily`,
CHANGE COLUMN `socketColor_1` `socketColor1` tinyint(4) NOT NULL DEFAULT 0 AFTER `totemCategory`,
CHANGE COLUMN `socketContent_1` `socketContent1` mediumint(8) NOT NULL DEFAULT 0 AFTER `socketColor1`,
CHANGE COLUMN `socketColor_2` `socketColor2` tinyint(4) NOT NULL DEFAULT 0 AFTER `socketContent1`,
CHANGE COLUMN `socketContent_2` `socketContent2` mediumint(8) NOT NULL DEFAULT 0 AFTER `socketColor2`,
CHANGE COLUMN `socketColor_3` `socketColor3` tinyint(4) NOT NULL DEFAULT 0 AFTER `socketContent2`,
CHANGE COLUMN `socketContent_3` `socketContent3` mediumint(8) NOT NULL DEFAULT 0 AFTER `socketColor3`,
CHANGE COLUMN `GemProperties` `gemColorMask` mediumint(8) NOT NULL DEFAULT 0 AFTER `socketBonus`,
ADD COLUMN `gemEnchantmentId` mediumint(8) NOT NULL AFTER `gemColorMask`,
CHANGE COLUMN `RequiredDisenchantSkill` `requiredDisenchantSkill` smallint(6) NOT NULL DEFAULT '-1' AFTER `gemProperties`,
CHANGE COLUMN `DisenchantID` `disenchantId` mediumint(8) UNSIGNED NOT NULL DEFAULT 0 AFTER `requiredDisenchantSkill`,
MODIFY COLUMN `duration` int(10) UNSIGNED NOT NULL DEFAULT 0 AFTER `disenchantId`,
CHANGE COLUMN `ItemLimitCategory` `itemLimitCategory` smallint(6) NOT NULL DEFAULT 0 AFTER `duration`,
CHANGE COLUMN `HolidayId` `holidayId` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `itemLimitCategory`,
CHANGE COLUMN `ScriptName` `scriptName` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' AFTER `holidayId`,
CHANGE COLUMN `FoodType` `foodType` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `scriptName`,
DROP PRIMARY KEY,
ADD PRIMARY KEY (`id`);
-- random Attribs
UPDATE aowow_items SET randomEnchant = -RandomSuffix WHERE RandomSuffix <> 0;
ALTER TABLE `aowow_items` DROP COLUMN `RandomSuffix`,
-- localization
UPDATE aowow_items a, locales_item b SET
a.name_loc2 = b.name_loc2,
a.name_loc3 = b.name_loc3,
a.name_loc6 = b.name_loc6,
a.name_loc8 = b.name_loc8,
a.description_loc2 = b.description_loc2,
a.description_loc3 = b.description_loc3,
a.description_loc6 = b.description_loc6,
a.description_loc8 = b.description_loc8
WHERE a.id = b.entry;
-- merge with gemProperties
UPDATE aowow_items a, dbc.gemProperties b SET
a.gemEnchantmentId = b.spellItemEnchantmentId,
a.gemColorMask = b.colorMask
WHERE a.gemColorMask = b.id;
-- icon
UPDATE aowow_items a, dbc.itemDisplayInfo b SET
a.iconString = b.inventoryIcon1,
a.model = (leftModelName = '', rightModelName, leftModelName)
WHERE a.displayId = b.id;
-- Robes => Chest and Ranged (right) => Ranged
UPDATE aowow_items SET slot = 15 WHERE slotbak = 26;
UPDATE aowow_items SET slot = 5 WHERE slotbak = 20;
-- custom sub-classes
UPDATE aowow_items SET subClassBak = subClass, classBak = class, slot = slotBak;
UPDATE aowow_items SET subclass = IF(
slot = 4, -8, IF( -- shirt
slot = 19, -7, IF( -- tabard
slot = 16, -6, IF( -- cloak
slot = 23, -5, IF( -- held in offhand
slot = 12, -4, IF( -- trinket
slot = 2, -3, IF( -- amulet
slot = 11, -2, subClassBak -- ring
)
)
)
)
)
)
)
WHERE class = 4;
// move alchemist stones to trinkets (Armor)
UPDATE aowow_items SET class = 4, subClass = -4 WHERE classBak = 7 AND subClassBak = 11 AND slotBak = 12;
// mark keys as key (if not quest items)
UPDATE aowow_items SET class = 13, subClass = 0 WHERE classBak IN (0, 15) AND bagFamily & 0x100;
// set subSubClass for Glyphs (major/minor (requires spells to be set up))
UPDATE aowow_items i, dbc.spell s, dbc.glyphProperties gp SET i.subSubClass = IF(gp.typeFlags & 0x1, 2, 1) WHERE i.spellId1 = s.id AND s.effectMiscValue1 = gp.id AND i.classBak = 16;
// elixir-subClasses - spell_group.id = item.subSubClass (1:battle; 2:guardian)
// query takes ~1min
UPDATE aowow_items i, world.spell_group sg SET i.subSubClass = sg.id WHERE sg.spell_id = i.spellId1 AND i.classBak = 0 AND i.subClassBak = 2;
// filter misc(class:15) junk(subclass:0) to appropriate categories
// assign pets and mounts to category
UPDATE aowow_items i, dbc.spell s SET
subClass = IF(effectAuraId1 <> 78, 2, IF(effectAuraId2 = 207 OR effectAuraId3 = 207 OR (s.id <> 65917 AND effectAuraId2 = 4 AND effectId3 = 77), -7, 5))
WHERE
s.id = spellId2 AND class = 15 AND spellId1 IN (483, 55884); -- misc items with learn-effect
// more corner cases (mounts that are not actualy learned)
UPDATE aowow_items i, dbc.spell s SET i.subClass = -7 WHERE
(effectId1 = 64 OR (effectAuraId1 = 78 AND effectAuraId2 = 4 AND effectId3 = 77) OR effectAuraId1 = 207 OR effectAuraId2 = 207 OR effectAuraId3 = 207)
AND s.id = i.spellId1 AND i.class = 15 AND i.subClass = 5;
UPDATE aowow_items i, dbc.spell s SET i.subClass = 5 WHERE s.effectAuraId1 = 78 AND s.id = i.spellId1 AND i.class = 15 AND i.subClass = 0;
UPDATE aowow_items i, dbc.spell s SET i.class = 0, i.subClass = 6 WHERE s.effectId1 = 53 AND s.id = i.spellId1 AND i.class = 15 AND i.subClassBak = 0;
UPDATE aowow_items i, dbc.spell s SET i.subClass = -3 WHERE s.effectId1 = 54 AND s.id = i.spellId1 AND i.class = 0 AND i.subClassBak = 8;
// one stray enchanting recipe .. with a strange icon
UPDATE aowow_items SET class = 9, subClass = 8 WHERE id = 33147;
UPDATE aowow_items SET subClass = -2 WHERE quality = 4 AND class = 15 AND subClassBak = 0 AND requiredClass AND (requiredClass & 0x5FF) <> 0x5FF;
*/
class ItemSetup extends ItemList
{
private $cols = [];
public function __construct($start, $end) // i suggest steps of 3k at max (20 steps (0 - 60k)); otherwise eats your ram for breakfast
{
$this->cols = DB::Aowow()->selectCol('SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA`="world" AND `TABLE_NAME`="aowow_item_stats"');
set_time_limit(300);
$conditions = array(
['i.id', $start, '>'],
['i.id', $end, '<='],
['class', [ITEM_CLASS_WEAPON, ITEM_CLASS_GEM, ITEM_CLASS_ARMOR, ITEM_CLASS_CONSUMABLE]],
0
);
parent::__construct($conditions);
}
public function calcRepairCost()
{
foreach ($this->iterate() as $id => $__)
{
$cls = $this->curTpl['class'];
$scb = $this->curTpl['subClassBak'];
$dur = $this->curTpl['durability'];
$qu = $this->curTpl['quality'];
// has no durability
if (!in_array($cls, [ITEM_CLASS_WEAPON, ITEM_CLASS_ARMOR]) || $dur <= 0)
continue;
// is relic, misc or obsolete
if ($cls == ITEM_CLASS_ARMOR && !in_array($scb, [1, 2, 3, 4, 6]))
continue;
$cost = DB::Aowow()->selectCell('SELECT ?# FROM ?_durabilityCost WHERE itemLevel = ?',
'class'.$cls.'Sub'.$scb,
$this->curTpl['itemLevel']
);
$qMod = Util::$itemDurabilityQualityMod[(($qu + 1) * 2)];
DB::Aowow()->query('UPDATE ?_items SET repairPrice = ?d WHERE id = ?d', intVal($dur * $cost * $qMod), $id);
}
}
public function writeStatsTable()
{
foreach ($this->iterate() as $__)
{
$this->extendJsonStats();
$updateFields = [];
foreach (@$this->json[$this->id] as $k => $v)
{
if (!in_array($k, $this->cols) || !$v || $k == 'id')
continue;
$updateFields[$k] = number_format($v, 2, '.', '');
}
if (isset($this->itemMods[$this->id]))
{
foreach ($this->itemMods[$this->id] as $k => $v)
{
if (!$v)
continue;
if ($str = Util::$itemMods[$k])
$updateFields[$str] = number_format($v, 2, '.', '');
}
}
if ($updateFields)
DB::Aowow()->query('REPLACE INTO ?_item_stats (`id`, `'.implode('`, `', array_keys($updateFields)).'`) VALUES (?d, "'.implode('", "', $updateFields).'")', $this->id);
}
}
}
?>

View File

@@ -1,487 +0,0 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
/*
this will probably screw the order of your set-pieces and will not result in the same virtualIds like wowhead, but
they are years beyond our content anyway, so what gives...
since there are some unused itemsets and and items flying around in a default database this script will create about 20 sets more than you'd expect.
and i have no idea how to merge the prefixes/suffixes for wotlk-raidsets and arena-sets in gereral onto the name.. at least not for all locales and i'll be damned if i have to skip one
*/
/*
ALTER TABLE `aowow_itemset` ADD COLUMN `npieces` tinyint(3) NOT NULL AFTER `bonusParsed`;
UPDATE `aowow_itemset`SET npieces = (
IF(item1 > 0, 1, 0) + IF(item2 > 0, 1, 0) + IF(item3 > 0, 1, 0) + IF(item4 > 0, 1, 0) + IF(item5 > 0, 1, 0) +
IF(item6 > 0, 1, 0) + IF(item7 > 0, 1, 0) + IF(item8 > 0, 1, 0) + IF(item9 > 0, 1, 0) + IF(item10 > 0, 1, 0)
);
*/
// script terminates self unexpectedly.. i don't know why..; split calls via ajax
if (!isset($_GET['setId']))
{
$setIds = DB::Aowow()->selectCol('SELECT id FROM dbc.itemset');
DB::Aowow()->query('TRUNCATE aowow_itemset');
?>
<html>
<head>
<script type="text/javascript">
var
httpRequest,
setIds = <?=json_encode($setIds, JSON_NUMERIC_CHECK);?>,
url = document.URL,
active = false;
function ge(el) {
return document.getElementById(el);
}
function ce(str) {
return document.createElement(str);
}
Element.prototype.ae = function(el) {
this.appendChild(el);
}
function makeRequest(url) {
httpRequest.open('GET', url);
httpRequest.send();
}
function toggle() {
active = !active;
ge('toggle').value = active ? 'Stop' : 'Start';
if (active)
run();
}
function run() {
ge('count').innerHTML = setIds.length;
if (id = setIds.shift()) {
if (active)
makeRequest(url + '&setId=' + id);
ge('dummy').scrollIntoView();
}
else
alert('we\'re done!');
};
function print() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
var
o = ge('out'),
p = ce('pre');
p.innerHTML = httpRequest.responseText;
o.appendChild(p);
if (active)
run();
}
else {
alert('There was a problem with the request, canceling...');
}
}
}
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
httpRequest = new XMLHttpRequest();
}
else if (window.ActiveXObject) { // IE
try {
httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {}
}
}
if (!httpRequest) {
alert('Giving up :( Cannot create an XMLHTTP instance');
}
else {
httpRequest.onreadystatechange = print;
}
window.onload = function() {
ge('max').innerHTML = setIds.length;
ge('count').innerHTML = setIds.length;
ge('toggle').onclick = toggle;
};
</script>
</head>
<body>
<div id="out"></div>
<span id="dummy" />
<br><br>
<pre style="position:fixed; right:50px; bottom:10px; margin:5px"><input type="button" id="toggle" value="start" />&nbsp;<span id="count"></span> / <span id="max"></span></pre>
</body>
</html>
<?php
die();
}
$locales = [LOCALE_EN, LOCALE_FR, LOCALE_DE, LOCALE_ES, LOCALE_RU];
$query = [];
$virtualId = 0;
$setToHoliday = array (
761 => 141, // Winterveil
762 => 372, // Brewfest
785 => 341, // Midsummer
812 => 181, // Noblegarden
);
// 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], // "Dungeon Set 1"
2 => [511,512,513,514,515,516,517,518,519], // "Dungeon Set 2"
3 => [201,202,203,204,205,206,207,208,209], // "Tier 1 Raid Set"
4 => [210,211,212,213,214,215,216,217,218], // "Tier 2 Raid Set"
5 => [521,523,524,525,526,527,528,529,530], // "Tier 3 Raid Set"
6 => [522,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,697,718], // "Level 60 PvP Rare Set"
7 => [281,282,301,341,342,343,344,345,346,347,348,361,362,381,382,401], // "Level 60 PvP Rare Set (Old)"
8 => [383,384,386,387,388,389,390,391,392,393,394,395,396,397,398,402,717,698], // "Level 60 PvP Epic Set"
9 => [494,495,498,500,502,504,506,508,510], // "Ruins of Ahn'Qiraj Set"
10 => [493,496,497,499,501,503,505,507,509], // "Temple of Ahn'Qiraj Set"
11 => [477,480,474,475,476,478,479,481,482], // "Zul'Gurub Set"
12 => [621,624,625,626,631,632,633,638,639,640,645,648,651,654,655,663,664], // "Tier 4 Raid Set"
13 => [622,627,628,629,634,635,636,641,642,643,646,649,652,656,657,665,666], // "Tier 5 Raid Set",
14 => [620,623,630,637,644,647,650,653,658,659,660,661,662], // "Dungeon Set 3",
15 => [467,468,469,470,471,472,473,483,484,485,486,487,488, 908], // "Arathi Basin Set",
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], // "Level 70 PvP Rare Set",
18 => [668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684], // "Tier 6 Raid Set",
21 => [738,739,740,741,742,743,744,745,746,747,748,749,750,751,752], // "Level 70 PvP Rare Set 2",
23 => [795,805,804,803,802,801,800,799,798,797,796,794,793,792,791,790,789,788,787], // "Tier 7 Raid Set",
25 => [838,837,836,835,834,833,832,831,830,829,828,827,826,825,824,823,822,821,820], // "Tier 8 Raid Set",
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], // "Tier 9 Raid Set",
29 => [901,900,899,898,897,896,895,894,893,892,891,890,889,888,887,886,885,884,883] // "Tier 10 Raid Set",
);
// well .. fuck
$tagsByNamePart = array(
17 => ['gladiator'], // "Arena Season 1 Set",
19 => ['merciless'], // "Arena Season 2 Set",
20 => ['vengeful'], // "Arena Season 3 Set",
22 => ['brutal'], // "Arena Season 4 Set",
24 => ['deadly', 'hateful', 'savage'], // "Arena Season 5 Set",
26 => ['furious'], // "Arena Season 6 Set",
28 => ['relentless'], // "Arena Season 7 Set",
30 => ['wrathful'] // "Arena Season 8 Set",
);
$setId = intVal($_GET['setId']);
if (!$setId)
die($_GET['setId']." is not a valid Id");
$_ = DB::Aowow()->selectCell('SELECT MIN(id) FROM aowow_itemset');
if ($_ < 0)
$virtualId = $_;
$set = DB::Aowow()->selectRow('SELECT *, id AS ARRAY_KEY FROM dbc.itemset WHERE id = ?d', $setId);
$id = $set['Id'];
$holiday = isset($setToHoliday[$id]) ? $setToHoliday[$id] : 0;
$pieces = DB::Aowow()->select('SELECT *, entry AS ARRAY_KEY FROM world.item_template WHERE itemset = ?d ORDER BY itemLevel ASC', $id);
$type = $classMask = 0;
$hasRing = false;
foreach ($pieces as $piece)
{
$classMask |= $piece['AllowableClass'];
// skip cloaks, they mess with armor classes
if ($piece['InventoryType'] == 16)
continue;
// skip event-sets
if ($piece['Quality'] == 1)
continue;
if ($piece['class'] == 2 && $piece['subclass'] == 0) // 1H-Axe
$type = 8;
else if ($piece['class'] == 2 && $piece['subclass'] == 4) // 1H-Mace
$type = 9;
else if ($piece['class'] == 2 && $piece['subclass'] == 7) // 1H-Sword
$type = 10;
else if ($piece['class'] == 2 && $piece['subclass'] == 13) // Fist Weapon
$type = 7;
else if ($piece['class'] == 2 && $piece['subclass'] == 15) // Dagger
$type = 5;
if ($type)
break;
if ($piece['class'] == 4 && $piece['InventoryType'] == 12) // trinket
$type = 11;
else if ($piece['class'] == 4 && $piece['InventoryType'] == 2) // amulet
$type = 12;
else if ($piece['class'] == 4 && $piece['subclass'] != 0) // 'armor' set
$type = $piece['subclass'];
if ($piece['class'] == 4 && $piece['InventoryType'] == 11) // contains ring
$hasRing = true;
}
$classMask &= CLASS_MASK_ALL; // clamp to available classes..
if (!$classMask || $classMask == CLASS_MASK_ALL) // available to all classes
$classMask = 0;
if ($hasRing && !$type)
$type = 6; // pure ring-set
$spells = $mods = $descText = $name = $gains = [];
// if slots conflict, group by itemlevel
// assume, that all items in multiSets have the same Itemlevel per group
// they don't .. consider quality!
$base = 0;
$multiSet = false;
foreach ($pieces as $pId => $piece)
{
// only armor and not a trinket, ring or neck, rare or higher
if ($piece['class'] != 4 || $piece['subclass'] == 0 || $piece['Quality'] < 3)
continue;
if (!$base)
{
$base = $piece['InventoryType'];
continue;
}
if ($base == $piece['InventoryType'])
{
$multiSet = true;
break;
}
}
for ($i = 1; $i < 9; $i++)
if ($set['spellId'.$i] > 0)
$spells[] = (int)$set['spellId'.$i];
$bonusSpells = new SpellList(array(['s.id', $spells]));
$mods = $bonusSpells->getStatGain();
for ($i = 1; $i < 9; $i++)
if ($set['itemCount'.$i] > 0)
$gains[$set['itemCount'.$i]] = $mods[$set['spellId'.$i]];
foreach ($locales as $loc)
{
User::useLocale($loc);
$name[$loc] = '"'.Util::sqlEscape(Util::localizedString($set, 'name')).'"';
foreach ($bonusSpells->iterate() as $__)
@$descText[$loc] .= $bonusSpells->parseText()[0]."\n";
$descText[$loc] = '"'.Util::sqlEscape($descText[$loc]).'"';
}
$items = [];
$max = $req = $min = $quality = 0;
if ($holiday || !$multiSet)
{
$row = [];
$heroic = false;
foreach ($pieces as $pId => $piece)
{
if ($piece['Quality'] > $quality)
$quality = $piece['Quality'];
if ($piece['Flags'] & ITEM_FLAG_HEROIC)
$heroic = true;
if ($piece['RequiredLevel'] > $req)
$req = $piece['RequiredLevel'];
if (!$min || $piece['ItemLevel'] < $min)
$min = $piece['ItemLevel'];
if ($piece['ItemLevel'] > $max)
$max = $piece['ItemLevel'];
if (isset($items[$piece['InventoryType']]))
{
if ($piece['class'] != 4 || $piece['subclass'] == 0) // jewelry, insert anyway
$items[$piece['InventoryType'].$pId] = $pId;
else
echo "<pre>set: ".$id." - conflict between item: ".$items[$piece['InventoryType']]." and item: ".$pId." choosing lower Id</pre>" ;
}
else
$items[$piece['InventoryType']] = $pId;
}
while (count($items) < 10)
$items[] = 0;
$note = 0;
foreach ($tagsById as $tag => $sets)
{
if (in_array($id, $sets))
{
$note = $tag;
break;
}
}
$row[] = $id;
$row[] = $id; //refSetId
$row = array_merge($row, $name, $items);
for ($i = 1; $i < 9; $i++)
$row[] = $set['spellId'.$i];
for ($i = 1; $i < 9; $i++)
$row[] = $set['itemCount'.$i];
$row = array_merge($row, $descText);
$row[] = !empty($gains) ? '"'.serialize($gains).'"' : '';
$row[] = $min;
$row[] = $max;
$row[] = $req;
$row[] = $classMask;
$row[] = $heroic ? 1 : 0;
$row[] = $quality;
$row[] = $type;
$row[] = $note; // contentGroup
$row[] = $holiday;
$row[] = $set['reqSkillLineId'];
$row[] = $set['reqSkillLevel'];
$query[] = '('.implode(', ', $row).')';
echo "<pre>set: ".$id." done</pre>";
}
else
{
$min = $max = $req = $heroic = $tmp = $vIds = [];
// map virtual Ids to itemlevel
$j = 0;
foreach ($pieces as $pId => $piece)
{
$key = $piece['Quality'].$piece['ItemLevel'];
if (!isset($tmp[$key]))
$tmp[$key] = $j++;
$vId = $tmp[$key];
if ($piece['Flags'] & ITEM_FLAG_HEROIC)
$heroic[$vId] = 1;
if (!isset($req[$vId]) || $piece['RequiredLevel'] > $req[$vId])
$req[$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['InventoryType']]))
{
echo "<pre>set: ".$id." ilvl: ".$piece['ItemLevel']." - conflict between item: ".$items[$vId][$piece['InventoryType']]." and item: ".$pId." choosing lower Id</pre>" ;
if ($items[$vId][$piece['InventoryType']] > $pId)
$items[$vId][$piece['InventoryType']] = $pId;
}
else
$items[$vId][$piece['InventoryType']] = $pId;
}
foreach ($items as &$list)
while (count($list) < 10)
$list[] = 0;
$rId = $id;
foreach ($items as $vId => $vSet)
{
if ($vId)
{
$id = --$virtualId;
$vIds[] = $id;
}
$quality = 0;
foreach ($vSet as $itm)
if ($itm && $pieces[$itm]['Quality'] > $quality)
$quality = $piece['Quality'];
$note = 0;
foreach ($tagsById as $tag => $sets)
{
if (in_array($rId, $sets))
{
$note = $tag;
break;
}
}
if (!$note)
{
foreach ($tagsByNamePart as $tag => $strings)
{
foreach ($strings as $str)
{
if (@stripos($pieces[reset($vSet)]['name'], $str) === 0)
{
$note = $tag;
break 2;
}
}
}
}
$row = [];
$row[] = $id;
$row[] = $rId; //refSetId
$row = array_merge($row, $name, $vSet);
for ($i = 1; $i < 9; $i++)
$row[] = $set['spellId'.$i];
for ($i = 1; $i < 9; $i++)
$row[] = $set['itemCount'.$i];
$row = array_merge($row, $descText);
$row[] = !empty($gains) ? "'".serialize($gains)."'" : '';
$row[] = $min[$vId];
$row[] = $max[$vId];
$row[] = $req[$vId];
$row[] = $classMask;
$row[] = isset($heroic[$vId]) ? 1 : 0;
$row[] = $quality;
$row[] = $type;
$row[] = $note; // contentGroup
$row[] = $holiday;
$row[] = $set['reqSkillLineId'];
$row[] = $set['reqSkillLevel'];
$query[] = '('.implode(', ', $row).')';
}
echo "<pre>set: ".$rId." done ".($vIds ? "as (".$rId.", ".implode(', ', $vIds).")" : null)."</pre>";
}
DB::Aowow()->query('REPLACE INTO aowow_itemset VALUES '.implode(', ', $query));
?>

View File

@@ -1,128 +0,0 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
class PetSetup extends PetList
{
private static $setup = array(
'CREATE TABLE `aowow_pet` (
`id` int(11) NOT NULL ,
`category` mediumint(8) NOT NULL ,
`minLevel` smallint(6) NOT NULL ,
`maxLevel` smallint(6) NOT NULL ,
`foodMask` int(11) NOT NULL ,
`type` tinyint(4) NOT NULL ,
`exotic` tinyint(4) NOT NULL ,
`expansion` tinyint(4) NOT NULL ,
`name_loc0` varchar(64) NOT NULL ,
`name_loc2` varchar(64) NOT NULL ,
`name_loc3` varchar(64) NOT NULL ,
`name_loc6` varchar(64) NOT NULL ,
`name_loc8` varchar(64) NOT NULL ,
`iconString` varchar(128) NOT NULL ,
`skillLineId` mediumint(9) NOT NULL ,
`spellId1` mediumint(9) NOT NULL ,
`spellId2` mediumint(9) NOT NULL ,
`spellId3` mediumint(9) NOT NULL ,
`spellId4` mediumint(9) NOT NULL ,
`armor` mediumint(9) NOT NULL ,
`damage` mediumint(9) NOT NULL ,
`health` mediumint(9) NOT NULL ,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci ENGINE=MyISAM',
'INSERT INTO aowow_pet SELECT
f.id,
categoryEnumId,
min(ct.minlevel),
max(ct.maxlevel),
itemPetFoodMask,
petTalentType,
IF(ct.type_flags & 0x10000, 1, 0), -- exotic
0, -- expansion (static data :/)
nameEN, nameFR, nameDE, nameES, nameRU,
SUBSTRING_INDEX(iconFile, '\\', -1),
skillLine1,
0, 0, 0, 0, -- spells
0, 0, 0 -- mods (from "Tamed Pet Passive (DND)")
FROM
dbc.creatureFamily f
LEFT JOIN
?_creature ct ON
f.id = ct.family
JOIN
world.creature c ON -- check if it is spawned (for min/max level)
ct.id = c.id
WHERE
pettalentType <> -1 AND
ct.type_flags & 0x1
GROUP BY
f.id;
',
'UPDATE aowow_pet SET expansion = 1 WHERE id IN (30, 31, 32, 33, 34)',
'UPDATE aowow_pet SET expansion = 2 WHERE id IN (37, 38, 39, 41, 42, 43, 44, 45, 46)'
);
private static $classicMods = array( // [Armor, Damage, Health] (see related "Tamed Pet Passive (DND)" spells per family. All values are set to +5% in wotlk)
1 => [ 5, 0, 0], // Wolf
2 => [ 0, 10, -2], // Cat
3 => [ 0, 7, 0], // Spider
4 => [ 5, -9, 8], // Bear
5 => [ 9, -10, 4], // Boar
6 => [ 10, 0, -5], // Crocolisk
7 => [ 5, 0, 0], // Carrion bird
8 => [ 13, -5, -4], // Crab
9 => [ 0, 2, 4], // Gorilla
11 => [ 3, 10, -5], // Raptor
12 => [ 0, 0, 5], // Tallstrider
20 => [ 10, -6, 0], // Scorpid
21 => [ 13, -10, 0], // Turtle
24 => [ 0, 7, 0], // Bat
25 => [ 5, 0, 0], // Hyena
26 => [ 0, 7, 0], // Bord of Prey (Owl)
27 => [ 0, 7, 0], // Wind serpent
30 => [ 0, 0, 0], // Dragonhawk
31 => [ 5, 10, -7], // Ravager
32 => [ 5, -6, 0], // Warp stalker
33 => [ 0, 0, 0], // Sporebat
34 => [-10, 3, 10], // Nether ray
35 => [ 0, 0, 0] // Serpent
);
public function __construct($params)
{
foreach ($this->setup as $query)
DB::Aowow()->query($query);
}
function setupPetSpells()
{
$ids = DB::Aowow()->selectCol('SELECT id AS ARRAY_KEY, skillLine1 FROM dbc.creatureFamily WHERE petTalentType <> -1');
foreach ($ids as $family => $skillLine)
{
$rows = DB::Aowow()->select('SELECT MAX(s.id) as Id, IF(t.id, 1, 0) AS isTalent FROM dbc.spell s JOIN dbc.skillLineAbility sla ON sla.spellId = s.id LEFT JOIN dbc.talent t ON t.rank1 = s.id WHERE (s.attributes0 & 0x40) = 0 AND sla.skillLineId = ?d GROUP BY s.nameEN', $skillLine);
$i = 1;
foreach ($rows as $row)
{
if ($row['isTalent'])
continue;
DB::Aowow()->query('UPDATE ?_pet SET spellId'.$i.' = ?d WHERE id = ?d', $row['Id'], $family);
$i++;
}
}
echo 'done';
}
function setupClassicMods()
{
foreach ($this->classicMods as $pet => $mods)
DB::Aowow()->query('UPDATE ?_pet SET armor = ?d, damage = ?d, health = ?d WHERE id = ?d', $mods[0], $mods[1], $mods[2], $pet);
}
}
?>

View File

@@ -1,63 +0,0 @@
/*
* Skills
*/
CREATE TABLE world.aowow_skillLine LIKE dbc.skillLine;
INSERT world.aowow_skillLine SELECT * FROM dbc.skillLine;
ALTER TABLE `aowow_skillline`
ADD COLUMN `typeCat` bigint(20) NOT NULL AFTER `Id`,
CHANGE COLUMN `nameEN` `name_loc0` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `skillCostId`,
CHANGE COLUMN `nameFR` `name_loc2` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `name_loc0`,
CHANGE COLUMN `nameDE` `name_loc3` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `name_loc2`,
CHANGE COLUMN `nameES` `name_loc6` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `name_loc3`,
CHANGE COLUMN `nameRU` `name_loc8` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `name_loc6`,
CHANGE COLUMN `descriptionEN` `description_loc0` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `name_loc8`,
CHANGE COLUMN `descriptionFR` `description_loc2` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `description_loc0`,
CHANGE COLUMN `descriptionDE` `description_loc3` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `description_loc2`,
CHANGE COLUMN `descriptionES` `description_loc6` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `description_loc3`,
CHANGE COLUMN `descriptionRU` `description_loc8` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `description_loc6`,
ADD COLUMN `iconString` varchar(40) NOT NULL AFTER `spellIconId`,
CHANGE COLUMN `verbEN` `verb_loc0` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `iconString`,
CHANGE COLUMN `verbFR` `verb_loc2` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `verb_loc0`,
CHANGE COLUMN `verbDE` `verb_loc3` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `verb_loc2`,
CHANGE COLUMN `verbES` `verb_loc6` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `verb_loc3`,
CHANGE COLUMN `verbRU` `verb_loc8` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `verb_loc6`,
ADD COLUMN `professionMask` bigint(20) NOT NULL AFTER `canLink`,
ADD COLUMN `recipeSubClass` bigint(20) NOT NULL AFTER `professionMask`,
ADD COLUMN `specializations` text NOT NULL COMMENT 'spcae-separated spellIds' AFTER `recipeSubClass`;
-- manual data for professions
UPDATE aowow_skillLine SET professionMask = 0 WHERE id = 393;
UPDATE aowow_skillLine SET professionMask = 1, recipeSubClass = 6, specializations = '28677 28675 28672' WHERE id = 171;
UPDATE aowow_skillLine SET professionMask = 2, recipeSubClass = 4, specializations = '9788 9787 17041 17040 17039' WHERE id = 164;
UPDATE aowow_skillLine SET professionMask = 4, recipeSubClass = 5 WHERE id = 185;
UPDATE aowow_skillLine SET professionMask = 8, recipeSubClass = 8 WHERE id = 333;
UPDATE aowow_skillLine SET professionMask = 16, recipeSubClass = 3, specializations = '20219 20222' WHERE id = 202;
UPDATE aowow_skillLine SET professionMask = 32, recipeSubClass = 7 WHERE id = 129;
UPDATE aowow_skillLine SET professionMask = 64, recipeSubClass = 10 WHERE id = 755;
UPDATE aowow_skillLine SET professionMask = 128, recipeSubClass = 1, specializations = '10656 10658 10660' WHERE id = 165;
UPDATE aowow_skillLine SET professionMask = 256 WHERE id = 186;
UPDATE aowow_skillLine SET professionMask = 512, recipeSubClass = 2, specializations = '26798 26801 26797' WHERE id = 197;
UPDATE aowow_skillLine SET professionMask = 1024, recipeSubClass = 9 WHERE id = 356;
UPDATE aowow_skillLine SET professionMask = 2048 WHERE id = 182;
UPDATE aowow_skillLine SET professionMask = 4096, recipeSubClass = 11 WHERE id = 773;
-- fixups
UPDATE aowow_skillLine SET spellIconId = 736 WHERE id = 393; -- skinning has generic icon
UPDATE aowow_skillLine SET spellIconId = 936 WHERE id = 633; -- lockpicking has generic icon
UPDATE aowow_skillLine SET name_loc0 = 'Pet - Wasp' WHERE id = 785; -- the naming in general is fubar inconsistent
UPDATE aowow_skillLine SET name_loc2 = 'Familier - diablosaure exotique' WHERE id = 781;
UPDATE aowow_skillLine SET name_loc6 = 'Mascota: Evento - Control remoto', name_loc3 = 'Tier - Ereignis Ferngesteuert' WHERE id = 758;
UPDATE aowow_skillLine SET name_loc8 = REPLACE(name_loc8, ' - ', ': ') WHERE categoryId = 7;
UPDATE aowow_skillLine SET categoryId = 7 WHERE id IN (758, 788); -- spirit beast listed under Attributes; remote controled pet listed under bogus
-- iconstrings
UPDATE aowow_skillLine sl, dbc.spell s, dbc.skillLineAbility sla SET sl.spellIconId = s.spellIconId WHERE (s.effectId1 IN (25, 26, 40) OR s.effectId2 = 60) AND sla.spellId = s.id AND sl.id = sla.skillLineId;
UPDATE aowow_skillLine sl, dbc.spellIcon si SET sl.iconString = SUBSTRING_INDEX(si.string, '\\', -1) WHERE sl.spellIconId = si.id;
UPDATE aowow_skillLine SET iconString = 'inv_misc_questionmark' WHERE spellIconId = 0;
-- categorization
UPDATE aowow_skillLine SET typeCat = -5 WHERE id = 777 OR (categoryId = 9 AND id NOT IN (356, 129, 185, 142, 155));
UPDATE aowow_skillLine SET typeCat = -4 WHERE categoryId = 9 AND name_loc0 LIKE '%racial%';
UPDATE aowow_skillLine SET typeCat = -6 WHERE id = 778 OR (categoryId = 7 AND name_loc0 LIKE '%pet%');
UPDATE aowow_skillLine SET typeCat = categoryId WHERE typeCat = 0;

View File

@@ -0,0 +1,198 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* provide these with basic content
aowow_announcements 1 P
aowow_articles 1 P
aowow_config 1 P
aowow_news 1 P
aowow_news_overlay 1 E
aowow_sourcestrings 2 P
*/
class SqlGen
{
private static $tables = array( // [dbcName, saveDbc, AowowDeps, TCDeps]
'achievementcategory' => ['achievement_category', false, null, null],
'achievementcriteria' => ['achievement_criteria', false, null, null],
'glyphproperties' => ['glyphproperties', true, null, null],
'itemenchantment' => ['spellitemenchantment', false, null, null],
'itemenchantmentcondition' => ['spellitemenchantmentcondition', false, null, null],
'itemextendedcost' => ['itemextendedcost', false, null, null],
'itemlimitcategory' => ['itemlimitcategory', false, null, null],
'itemrandomproppoints' => ['randproppoints', false, null, null],
'lock' => ['lock', true, null, null],
'mailtemplate' => ['mailtemplate', false, null, null],
'scalingstatdistribution' => ['scalingstatdistribution', false, null, null],
'scalingstatvalues' => ['scalingstatvalues', false, null, null],
'spellfocusobject' => ['spellfocusobject', false, null, null],
'spellrange' => ['spellrange', false, null, null],
'spellvariables' => ['spelldescriptionvariables', false, null, null],
'totemcategory' => ['totemcategory', false, null, null],
'classes' => [null, null, null, null],
'factions' => [null, null, null, null],
'factiontemplate' => [null, null, null, null],
'holidays' => [null, null, null, null],
'icons' => [null, null, null, null],
'itemrandomenchant' => [null, null, null, null],
'races' => [null, null, null, null],
'shapeshiftforms' => [null, null, null, null],
'skillline' => [null, null, null, null],
'achievement' => [null, null, null, ['dbc_achievement']],
'creature' => [null, null, null, ['creature_template', 'locales_creature', 'creature_classlevelstats', 'instance_encounters']],
'currencies' => [null, null, null, ['item_template', 'locales_item']],
'events' => [null, null, null, ['game_event', 'game_event_prerequisite']],
'objects' => [null, null, null, ['gameobject_template', 'locales_gameobject']],
'pet' => [null, null, null, ['creature_template', 'creature']],
'quests' => [null, null, null, ['quest_template', 'locales_quest', 'game_event', 'game_event_seasonal_questrelation']],
'quests_startend' => [null, null, null, ['creature_queststarter', 'creature_questender', 'game_event_creature_quest', 'gameobject_queststarter', 'gameobject_questender', 'game_event_gameobject_quest', 'item_template']],
'spell' => [null, null, null, ['skill_discovery_template', 'item_template', 'creature_template', 'creature_template_addon', 'smart_scripts', 'npc_trainer', 'disables', 'spell_ranks', 'spell_dbc']],
'spelldifficulty' => [null, null, null, ['spelldifficulty_dbc']],
'taxi' /* nodes + paths */ => [null, null, null, ['creature_template', 'creature']],
'titles' => [null, null, null, ['quest_template', 'game_event_seasonal_questrelation', 'game_event', 'achievement_reward']],
'items' => [null, null, null, ['item_template', 'locales_item', 'spell_group']],
'spawns' /* + waypoints */ => [null, null, null, ['creature', 'creature_addon', 'gameobject', 'gameobject_template', 'vehicle_accessory', 'vehicle_accessory_template', 'script_waypoint', 'waypoints', 'waypoint_data']],
'zones' => [null, null, null, ['access_requirement']],
'itemset' => [null, null, ['spell'], ['item_template']],
'item_stats' => [null, null, ['items', 'spell'], null],
'source' => [null, null, ['spell', 'achievements'], ['npc_vendor', 'game_event_npc_vendor', 'creature', 'quest_template', 'playercreateinfo_item', 'npc_trainer', 'skill_discovery_template', 'playercreateinfo_spell', 'achievement_reward']]
);
public static $cliOpts = [];
private static $shortOpts = 'h';
private static $longOpts = ['sql::', 'help', 'sync:']; // general
public static $subScripts = [];
public static $defaultExecTime = 30;
public static $stepSize = 1000;
public static function init()
{
self::$defaultExecTime = ini_get('max_execution_time');
$doScripts = [];
if (getopt(self::$shortOpts, self::$longOpts))
self::handleCLIOpts($doScripts);
else
{
self::printCLIHelp();
exit;
}
// check passed subscript names; limit to real scriptNames
self::$subScripts = array_keys(self::$tables);
if ($doScripts)
self::$subScripts = array_intersect($doScripts, self::$subScripts);
if (!CLISetup::$localeIds /* && this script has localized text */)
{
CLISetup::log('No valid locale specified. Check your config or --locales parameter, if used', CLISetup::LOG_ERROR);
exit;
}
}
private static function handleCLIOpts(&$doTbls)
{
$doTbls = [];
$_ = getopt(self::$shortOpts, self::$longOpts);
if ((isset($_['help']) || isset($_['h'])) && empty($_['sql']))
{
self::printCLIHelp();
exit;
}
// required subScripts
if (!empty($_['sync']))
{
$sync = explode(',', $_['sync']);
foreach (self::$tables as $name => $info)
if (!empty($info[3]) && array_intersect($sync, $info[3]))
$doTbls[] = $name;
// recursive dependencies
foreach (self::$tables as $name => $info)
if (!empty($info[2]) && array_intersect($doTbls, $info[2]))
$doTbls[] = $name;
$doTbls = array_unique($doTbls);
}
else if (!empty($_['sql']))
$doTbls = explode(',', $_['sql']);
}
public static function printCLIHelp()
{
echo "\nusage: php index.php --sql=<tableList,> [-h --help]\n\n";
echo "--sql : available tables:\n";
foreach (self::$tables as $t => $info)
echo " * ".str_pad($t, 24).(isset($info[3]) ? ' - TC deps: '.implode(', ', $info[3]) : '').(isset($info[2]) ? ' - Aowow deps: '.implode(', ', $info[2]) : '')."\n";
echo "-h --help : shows this info\n";
}
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])) // straight copy from dbc source
{
$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);
}
}
?>

View File

@@ -0,0 +1,66 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* dbc_achievement
*/
// Higher Learning - item rewarded through gossip
$customData = array(
1956 => ['itemExtra' => 44738]
);
$reqDBC = ['achievement_category', 'achievement'];
function achievement(array $ids = [])
{
if ($ids)
DB::Aowow()->query('DELETE FROM ?_achievement WHERE id IN (?a)', $ids);
else
DB::Aowow()->query('INSERT IGNORE INTO ?_achievement SELECT a.id, 2 - a.faction, a.map, 0, 0, a.category, ac.parentCategory, a.points, a.orderInGroup, a.iconId, a.flags, a.reqCriteriaCount, a.refAchievement, 0, 0, a.name_loc0, a.name_loc2, a.name_loc3, a.name_loc6, a.name_loc8, a.description_loc0, a.description_loc2, a.description_loc3, a.description_loc6, a.description_loc8, a.reward_loc0, a.reward_loc2, a.reward_loc3, a.reward_loc6, a.reward_loc8 FROM dbc_achievement a LEFT JOIN dbc_achievement_category ac ON ac.id = a.category');
// serverside achievements
$serverAchievements = DB::World()->select('SELECT ID, IF(requiredFaction = -1, 3, IF(requiredFaction = 0, 2, 1)) AS "faction", mapID, points, flags, count, refAchievement FROM achievement_dbc{ WHERE id IN (?a)}',
$ids ?: DBSIMPLE_SKIP
);
foreach ($serverAchievements as $sa)
DB::Aowow()->query('REPLACE INTO ?_achievement (id, faction, map, points, flags, reqCriteriaCount, refAchievement, cuFlags, name_loc0, name_loc2, name_loc3, name_loc6, name_loc8) VALUES (?d, ?d, ?d, ?d, ?d, ?d, ?d, ?d, ?, ?, ?, ?, ?)',
$sa['ID'], $sa['faction'], $sa['mapID'], $sa['points'], $sa['flags'], $sa['count'], $sa['refAchievement'], CUSTOM_SERVERSIDE,
'Serverside - #'.$sa['ID'], 'Serverside - #'.$sa['ID'], 'Serverside - #'.$sa['ID'], 'Serverside - #'.$sa['ID'], 'Serverside - #'.$sa['ID']
);
if ($ids)
return true;
// create chain of achievements
$chainIdx = 0;
$parents = DB::Aowow()->selectCol('SELECT a.id FROM dbc_achievement a JOIN dbc_achievement b ON b.previous = a.id WHERE a.previous = 0');
foreach ($parents as $chainId => $next)
{
$tree = [null, $next];
while ($next = DB::Aowow()->selectCell('SELECT id FROM dbc_achievement WHERE previous = ?d', $next))
$tree[] = $next;
foreach ($tree as $idx => $aId)
{
if (!$aId)
continue;
DB::Aowow()->query('UPDATE ?_achievement SET cuFlags = cuFlags | ?d, chainId = ?d, chainPos = ?d WHERE id = ?d',
$idx == 1 ? ACHIEVEMENT_CU_FIRST_SERIES : (count($tree) == $idx + 1 ? ACHIEVEMENT_CU_LAST_SERIES : 0),
$chainId + 1,
$idx,
$aId
);
}
}
return true;
}
?>

View File

@@ -0,0 +1,50 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// roles (1:heal; 2:mleDPS; 4:rngDPS; 8:tank)
$customData = array(
1 => ['roles' => 0xA],
2 => ['roles' => 0xB],
3 => ['roles' => 0x4],
4 => ['roles' => 0x2],
5 => ['roles' => 0x5],
6 => ['roles' => 0xA],
7 => ['roles' => 0x7],
8 => ['roles' => 0x4],
9 => ['roles' => 0x4],
11 => ['roles' => 0xF],
);
$reqDBC = ['spell', 'charbaseinfo', 'skillraceclassinfo', 'skilllineability', 'chrclasses'];
function classes()
{
$classes = DB::Aowow()->select('SELECT *, Id AS ARRAY_KEY FROM dbc_chrclasses');
// add raceMask
$races = DB::Aowow()->select('SELECT classId AS ARRAY_KEY, BIT_OR(1 << (raceId - 1)) AS raceMask FROM dbc_charbaseinfo GROUP BY classId');
Util::arraySumByKey($classes, $races);
// add skills
$skills = DB::Aowow()->select('SELECT LOG(2, classMask) + 1 AS ARRAY_KEY, GROUP_CONCAT(skillLine SEPARATOR \' \') AS skills FROM dbc_skillraceclassinfo WHERE flags = 1040 GROUP BY classMask HAVING ARRAY_KEY = CAST(LOG(2, classMask) + 1 AS SIGNED)');
Util::arraySumByKey($classes, $skills);
// add weaponTypeMask & armorTypeMask
foreach ($classes as $id => &$data)
{
$data['weaponTypeMask'] = DB::Aowow()->selectCell('SELECT BIT_OR(equippedItemSubClassMask) FROM dbc_spell s JOIN dbc_skilllineability sla ON sla.spellId = s.id JOIN dbc_skillraceclassinfo srci ON srci.skillLine = sla.skillLineId AND srci.classMask & ?d WHERE sla.skilllineid <> 183 AND (sla.reqClassMask & ?d OR sla.reqClassMask = 0) AND equippedItemClass = ?d AND (effect1Id = 60 OR effect2Id = 60)', 1 << ($id - 1), 1 << ($id - 1), ITEM_CLASS_WEAPON);
$data['armorTypeMask'] = DB::Aowow()->selectCell('SELECT BIT_OR(equippedItemSubClassMask) FROM dbc_spell s JOIN dbc_skilllineability sla ON sla.spellId = s.id JOIN dbc_skillraceclassinfo srci ON srci.skillLine = sla.skillLineId AND srci.classMask & ?d WHERE sla.reqClassMask & ?d AND equippedItemClass = ?d AND (effect1Id = 60 OR effect2Id = 60)', 1 << ($id - 1), 1 << ($id - 1), ITEM_CLASS_ARMOR);
}
foreach ($classes as $cl)
DB::Aowow()->query('REPLACE INTO ?_classes (?#) VALUES (?a)', array_keys($cl), array_values($cl));
return true;
}
?>

View File

@@ -0,0 +1,145 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* creature_template
* locales_creature
* creature_classlevelstats
* instance_encounters
*/
$customData = array(
);
$reqDBC = ['creaturedisplayinfo', 'creaturedisplayinfoextra'];
function creature(array $ids = [])
{
$baseQuery = '
SELECT
ct.entry,
IF(ie.entry IS NULL, 0, ?d) AS cuFlags, -- cuFlags
difficulty_entry_1, difficulty_entry_2, difficulty_entry_3,
KillCredit1, KillCredit2,
modelid1, modelid2, modelid3, modelid4,
"" AS textureString, -- textureString
0 AS modelId, -- modelId
"" AS iconString, -- iconString
name, IFNULL(name_loc2, ""), IFNULL(name_loc3, ""), IFNULL(name_loc6, ""), IFNULL(name_loc8, ""),
subname, IFNULL(subname_loc2, ""), IFNULL(subname_loc3, ""), IFNULL(subname_loc6, ""), IFNULL(subname_loc8, ""),
minLevel, maxLevel,
exp,
faction,
npcflag,
rank,
dmgSchool,
DamageModifier,
BaseAttackTime,
RangeAttackTime,
BaseVariance,
RangeVariance,
unit_class,
unit_flags, unit_flags2, dynamicflags,
family,
trainer_type,
trainer_spell,
trainer_class,
trainer_race,
(CASE ct.exp WHEN 0 THEN min.damage_base WHEN 1 THEN min.damage_exp1 ELSE min.damage_exp2 END) AS dmgMin,
(CASE ct.exp WHEN 0 THEN max.damage_base WHEN 1 THEN max.damage_exp1 ELSE max.damage_exp2 END) AS dmgMax,
min.attackpower AS mleAtkPwrMin,
max.attackpower AS mleAtkPwrMax,
min.rangedattackpower AS rmgAtkPwrMin,
max.rangedattackpower AS rmgAtkPwrMax,
type,
type_flags,
lootid, pickpocketloot, skinloot,
spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8,
PetSpellDataId,
VehicleId,
mingold, maxgold,
AIName,
(CASE ct.exp WHEN 0 THEN min.basehp0 WHEN 1 THEN min.basehp1 ELSE min.basehp2 END) * ct.HealthModifier AS healthMin,
(CASE ct.exp WHEN 0 THEN max.basehp0 WHEN 1 THEN max.basehp1 ELSE max.basehp2 END) * ct.HealthModifier AS healthMax,
min.basemana * ct.ManaModifier AS manaMin,
max.basemana * ct.ManaModifier AS manaMax,
min.basearmor * ct.ArmorModifier AS armorMin,
max.basearmor * ct.ArmorModifier AS armorMax,
RacialLeader,
questItem1, questItem2, questItem3, questItem4, questItem5, questItem6,
mechanic_immune_mask,
flags_extra,
ScriptName
FROM
creature_template ct
JOIN
creature_classlevelstats min ON ct.unit_class = min.class AND ct.minlevel = min.level
JOIN
creature_classlevelstats max ON ct.unit_class = max.class AND ct.maxlevel = max.level
LEFT JOIN
locales_creature lc ON lc.entry = ct.entry
LEFT JOIN
instance_encounters ie ON ie.creditEntry = ct.entry AND ie.creditType = 0
{
WHERE
ct.entry IN (?a)
}
LIMIT
?d, ?d';
$dummyQuery = '
UPDATE
?_creature a
JOIN
(
SELECT b.difficultyEntry1 AS dummy FROM ?_creature b UNION
SELECT c.difficultyEntry2 AS dummy FROM ?_creature c UNION
SELECT d.difficultyEntry3 AS dummy FROM ?_creature d
) j
SET
a.cuFlags = a.cuFlags | ?d
WHERE
a.id = j.dummy';
$displayInfoQuery = '
UPDATE
?_creature c
JOIN
dbc_creaturedisplayinfo cdi ON c.displayId1 = cdi.id
LEFT JOIN
dbc_creaturedisplayinfoextra cdie ON cdi.extraInfoId = cdie.id
SET
c.textureString = IFNULL(cdie.textureString, cdi.skin1),
c.modelId = cdi.modelId,
c.iconString = cdi.iconString';
$offset = 0;
while ($npcs = DB::World()->select($baseQuery, NPC_CU_INSTANCE_BOSS, $ids ?: DBSIMPLE_SKIP, $offset, SqlGen::$stepSize))
{
CLISetup::log(' * sets '.($offset + 1).' - '.($offset + count($npcs)));
$offset += SqlGen::$stepSize;
foreach ($npcs as $npc)
DB::Aowow()->query('REPLACE INTO ?_creature VALUES (?a)', array_values($npc));
}
// apply "textureString", "modelId" and "iconSring"
DB::Aowow()->query($displayInfoQuery);
// apply cuFlag: difficultyDummy
DB::Aowow()->query($dummyQuery, NPC_CU_DIFFICULTY_DUMMY | CUSTOM_EXCLUDE_FOR_LISTVIEW);
// apply cuFlag: excludeFromListview [for trigger-creatures]
DB::Aowow()->query('UPDATE ?_creature SET cuFlags = cuFlags | ?d WHERE flagsExtra & ?d', CUSTOM_EXCLUDE_FOR_LISTVIEW, 0x80);
return true;
}
?>

View File

@@ -0,0 +1,55 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* item_template
* locales_item
*/
// hide test tokens and move them to unused
$customData = array(
1 => ['cuFlags' => CUSTOM_EXCLUDE_FOR_LISTVIEW, 'category' => 3],
2 => ['cuFlags' => CUSTOM_EXCLUDE_FOR_LISTVIEW, 'category' => 3],
4 => ['cuFlags' => CUSTOM_EXCLUDE_FOR_LISTVIEW, 'category' => 3],
22 => ['cuFlags' => CUSTOM_EXCLUDE_FOR_LISTVIEW, 'category' => 3],
141 => ['cuFlags' => CUSTOM_EXCLUDE_FOR_LISTVIEW, 'category' => 3]
);
$reqDBC = ['itemdisplayinfo', 'currencytypes'];
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;
}
?>

View File

@@ -0,0 +1,52 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* game_event
* game_event_prerequisite
*/
$customData = array(
);
$reqDBC = array(
);
function events(array $ids = [])
{
$eventQuery = '
SELECT
ge.eventEntry,
holiday,
0, -- cuFlags
UNIX_TIMESTAMP(start_time),
UNIX_TIMESTAMP(end_time),
occurence * 60,
length * 60,
IF (gep.eventEntry IS NOT NULL, GROUP_CONCAT(prerequisite_event SEPARATOR " "), NULL),
description
FROM
game_event ge
LEFT JOIN
game_event_prerequisite gep ON gep.eventEntry = ge.eventEntry
{
WHERE
ge.eventEntry IN (?a)
}
GROUP BY
ge.eventEntry';
$events = DB::World()->select($eventQuery, $ids ?: DBSIMPLE_SKIP);
foreach ($events as $e)
DB::Aowow()->query('REPLACE INTO ?_events VALUES (?a)', array_values($e));
return true;
}
?>

View File

@@ -0,0 +1,129 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
$customData = array(
47 => ['qmNpcIds' => '33310'],
68 => ['qmNpcIds' => '33555'],
69 => ['qmNpcIds' => '33653'],
72 => ['qmNpcIds' => '33307'],
76 => ['qmNpcIds' => '33553'],
81 => ['qmNpcIds' => '33556'],
922 => ['qmNpcIds' => '16528'],
930 => ['qmNpcIds' => '33657'],
932 => ['qmNpcIds' => '19321'],
933 => ['qmNpcIds' => '20242 23007'],
935 => ['qmNpcIds' => '21432'],
941 => ['qmNpcIds' => '20241'],
942 => ['qmNpcIds' => '17904'],
946 => ['qmNpcIds' => '17657'],
947 => ['qmNpcIds' => '17585'],
970 => ['qmNpcIds' => '18382'],
978 => ['qmNpcIds' => '20240'],
989 => ['qmNpcIds' => '21643'],
1011 => ['qmNpcIds' => '21655'],
1012 => ['qmNpcIds' => '23159'],
1037 => ['qmNpcIds' => '32773 32564'],
1038 => ['qmNpcIds' => '23428'],
1052 => ['qmNpcIds' => '32774 32565'],
1073 => ['qmNpcIds' => '31916 32763'],
1090 => ['qmNpcIds' => '32287'],
1091 => ['qmNpcIds' => '32533'],
1094 => ['qmNpcIds' => '34881'],
1105 => ['qmNpcIds' => '31910'],
1106 => ['qmNpcIds' => '30431'],
1119 => ['qmNpcIds' => '32540'],
1124 => ['qmNpcIds' => '34772'],
1156 => ['qmNpcIds' => '37687'],
1082 => ['cuFlags' => CUSTOM_EXCLUDE_FOR_LISTVIEW],
952 => ['cuFlags' => CUSTOM_EXCLUDE_FOR_LISTVIEW],
);
$reqDBC = ['faction', 'factiontemplate'];
function factions()
{
$factionQuery = '
REPLACE INTO
?_factions
SELECT
f.id,
f.repIdx,
IF(SUM(ft.ourMask & 0x6) / COUNT(1) = 0x4, 2, IF(SUM(ft.ourMask & 0x6) / COUNT(1) = 0x2, 1, 0)) as side,
0, -- expansion
"", -- quartermasterNpcIds
"", -- factionTemplateIds
0, -- cuFlags
parentFaction,
spilloverRateIn, spilloverRateOut, spilloverMaxRank,
name_loc0, name_loc2, name_loc3, name_loc6, name_loc8
FROM
dbc_faction f
LEFT JOIN
dbc_factiontemplate ft ON ft.factionid = f.id
GROUP BY
f.id';
$templateQuery = '
UPDATE
?_factions f
JOIN
(SELECT ft.factionId, GROUP_CONCAT(ft.Id SEPARATOR " ") AS tplIds FROM dbc_factiontemplate ft GROUP BY ft.factionId) temp ON f.id = temp.factionId
SET
f.templateIds = temp.tplIds';
$recursiveUpdateQuery = '
UPDATE
?_factions top
JOIN
(SELECT id, parentFactionId FROM ?_factions) mid ON mid.parentFactionId IN (?a)
LEFT JOIN
(SELECT id, parentFactionId FROM ?_factions) low ON low.parentFactionId = mid.id
SET
?a
WHERE
repIdx > 0 AND (
top.id IN (?a) OR
top.id = mid.id OR
top.id = low.id
)';
$excludeQuery = '
UPDATE
?_factions x
JOIN
dbc_faction f ON f.id = x.id
LEFT JOIN
dbc_factiontemplate ft ON f.Id = ft.factionId
SET
cuFlags = cuFlags | ?d
WHERE
f.repIdx < 0 OR
(
f.repIdx > 0 AND
(f.repFlags1 & 0x8 OR ft.id IS NULL) AND
(f.repFlags1 & 0x80) = 0
)';
$pairs = array(
[[980], ['expansion' => 1]],
[[1097], ['expansion' => 2]],
[[469, 891, 1037], ['side' => 1]],
[[ 67, 892, 1052], ['side' => 2]],
);
DB::Aowow()->query($factionQuery);
DB::Aowow()->query($templateQuery);
DB::Aowow()->query($excludeQuery, CUSTOM_EXCLUDE_FOR_LISTVIEW);
foreach ($pairs as $p)
DB::Aowow()->query($recursiveUpdateQuery, $p[0], $p[1], $p[0]);
return true;
}
?>

View File

@@ -0,0 +1,38 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
$customData = array(
);
$reqDBC = ['factiontemplate'];
function factiontemplate()
{
$query = '
REPLACE INTO
?_factiontemplate
SELECT
id,
factionId,
IF(friendFactionId1 = 1 OR friendFactionId2 = 1 OR friendFactionId3 = 1 OR friendFactionId4 = 1 OR friendlyMask & 0x3,
1,
IF(enemyFactionId1 = 1 OR enemyFactionId2 = 1 OR enemyFactionId3 = 1 OR enemyFactionId4 = 1 OR hostileMask & 0x3, -1, 0)
),
IF(friendFactionId1 = 2 OR friendFactionId2 = 2 OR friendFactionId3 = 2 OR friendFactionId4 = 2 OR friendlyMask & 0x5,
1,
IF(enemyFactionId1 = 2 OR enemyFactionId2 = 2 OR enemyFactionId3 = 2 OR enemyFactionId4 = 2 OR hostileMask & 0x5, -1, 0)
)
FROM
dbc_factiontemplate';
DB::Aowow()->query($query);
return true;
}
?>

View File

@@ -0,0 +1,59 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
$customData = array(
62 => ['iconString' => 'inv_misc_missilelarge_red' ],
141 => ['iconString' => 'calendar_winterveilstart', 'achievementCatOrId' => 156 ],
181 => ['iconString' => 'calendar_noblegardenstart', 'achievementCatOrId' => 159 ],
201 => ['iconString' => 'calendar_childrensweekstart', 'achievementCatOrId' => 163 ],
283 => ['iconString' => 'inv_jewelry_necklace_21' ],
284 => ['iconString' => 'inv_misc_rune_07' ],
285 => ['iconString' => 'inv_jewelry_amulet_07' ],
301 => ['iconString' => 'calendar_fishingextravaganzastart' ],
321 => ['iconString' => 'calendar_harvestfestivalstart' ],
324 => ['iconString' => 'calendar_hallowsendstart', 'bossCreature' => 23682, 'achievementCatOrId' => 158 ],
327 => ['iconString' => 'calendar_lunarfestivalstart', 'bossCreature' => 15467, 'achievementCatOrId' => 160 ],
335 => ['iconString' => 'calendar_loveintheairstart' ],
341 => ['iconString' => 'calendar_midsummerstart', 'bossCreature' => 25740, 'achievementCatOrId' => 161 ],
353 => ['iconString' => 'spell_nature_eyeofthestorm' ],
372 => ['iconString' => 'calendar_brewfeststart', 'bossCreature' => 23872, 'achievementCatOrId' => 162 ],
374 => ['iconString' => 'calendar_darkmoonfaireelwynnstart' ],
375 => ['iconString' => 'calendar_darkmoonfairemulgorestart' ],
376 => ['iconString' => 'calendar_darkmoonfaireterokkarstart' ],
398 => ['iconString' => 'calendar_piratesdaystart', 'achievementCatOrId' => -3457],
400 => ['iconString' => 'achievement_bg_winsoa' ],
404 => ['iconString' => 'calendar_harvestfestivalstart', 'achievementCatOrId' => 14981],
406 => ['iconString' => 'achievement_boss_lichking' ],
409 => ['iconString' => 'calendar_dayofthedeadstart', 'achievementCatOrId' => -3456],
420 => ['iconString' => 'achievement_bg_winwsg' ],
423 => ['iconString' => 'calendar_loveintheairstart', 'bossCreature' => 36296, 'achievementCatOrId' => 187 ],
424 => ['iconString' => 'calendar_fishingextravaganzastart' ],
);
$reqDBC = ['holidays', 'holidaydescriptions', 'holidaynames'];
function holidays()
{
$query = '
REPLACE INTO
?_holidays (id, name_loc0, name_loc2, name_loc3, name_loc6, name_loc8, description_loc0, description_loc2, description_loc3, description_loc6, description_loc8, looping, scheduleType, textureString)
SELECT
h.id, n.name_loc0, n.name_loc2, n.name_loc3, n.name_loc6, n.name_loc8, d.description_loc0, d.description_loc2, d.description_loc3, d.description_loc6, d.description_loc8, h.looping, h.scheduleType, h.textureString
FROM
dbc_holidays h
LEFT JOIN
dbc_holidaynames n ON n.id = h.nameId
LEFT JOIN
dbc_holidaydescriptions d ON d.id = h.descriptionId';
DB::Aowow()->query($query);
return true;
}
?>

View File

@@ -0,0 +1,28 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
$customData = array(
);
$reqDBC = ['spellicon', 'itemdisplayinfo'];
function icons()
{
$baseQuery = '
REPLACE INTO
?_icons
SELECT Id, LOWER(SUBSTRING_INDEX(iconPath, "\\\\", -1)) FROM dbc_spellicon
UNION
SELECT -Id, LOWER(inventoryIcon1) FROM dbc_itemdisplayinfo';
DB::Aowow()->query($baseQuery);
return true;
}
?>

View File

@@ -0,0 +1,160 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* ?_items finalized
* ?_spell finalized
*/
$customData = array(
);
$reqDBC = [];
class ItemStatSetup extends ItemList
{
private $statCols = [];
public function __construct($start, $limit, array $ids)
{
$this->statCols = DB::Aowow()->selectCol('SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_NAME` LIKE "%item_stats"');
$this->queryOpts['i']['o'] = 'i.id ASC';
unset($this->queryOpts['is']); // do not reference the stats table we are going to write to
$conditions = array(
['i.id', $start, '>'],
['class', [ITEM_CLASS_WEAPON, ITEM_CLASS_GEM, ITEM_CLASS_ARMOR, ITEM_CLASS_CONSUMABLE]],
$limit
);
if ($ids)
$conditions[] = ['id', $ids];
parent::__construct($conditions);
}
public function writeStatsTable()
{
$enchantments = []; // buffer Ids for lookup id => src; src>0: socketBonus; src<0: gemEnchant
foreach ($this->iterate() as $__)
{
$this->itemMods[$this->id] = [];
// convert itemMods to stats
for ($h = 1; $h <= 10; $h++)
{
$mod = $this->curTpl['statType'.$h];
$val = $this->curTpl['statValue'.$h];
if (!$mod || !$val)
continue;
Util::arraySumByKey($this->itemMods[$this->id], [$mod => $val]);
}
// convert spells to stats
$equipSpells = [];
for ($h = 1; $h <= 5; $h++)
{
if ($this->curTpl['spellId'.$h] <= 0)
continue;
// armor & weapons only onEquip && consumables only onUse
if (!(in_array($this->curTpl['class'], [ITEM_CLASS_WEAPON, ITEM_CLASS_ARMOR]) && $this->curTpl['spellTrigger'.$h] == 1) &&
!( $this->curTpl['class'] == ITEM_CLASS_CONSUMABLE && $this->curTpl['spellTrigger'.$h] == 0))
continue;
$equipSpells[] = $this->curTpl['spellId'.$h];
}
if ($equipSpells)
{
$eqpSplList = new SpellList(array(['s.id', $equipSpells]));
foreach ($eqpSplList->getStatGain() as $stats)
Util::arraySumByKey($this->itemMods[$this->id], $stats);
}
// prepare: convert enchantments to stats
if (!empty($this->json[$this->id]['socketbonus']))
$enchantments[$this->json[$this->id]['socketbonus']][] = $this->id;
if ($geId = $this->curTpl['gemEnchantmentId'])
$enchantments[$geId][] = -$this->id;
}
// execute: convert enchantments to stats
if ($enchantments)
{
$parsed = Util::parseItemEnchantment(array_keys($enchantments));
// and merge enchantments back
foreach ($parsed as $eId => $stats)
{
foreach ($enchantments[$eId] as $item)
{
if ($item > 0) // apply socketBonus
$this->json[$item]['socketbonusstat'] = $stats;
else /* if ($item < 0) */ // apply gemEnchantment
Util::arraySumByKey($this->json[-$item][$mod], $stats);
}
}
}
// collect data and write to DB
foreach ($this->iterate() as $__)
{
$updateFields = ['id' => $this->id];
foreach (@$this->json[$this->id] as $k => $v)
{
if (!in_array($k, $this->statCols) || !$v || $k == 'id')
continue;
$updateFields[$k] = number_format($v, 2, '.', '');
}
if (isset($this->itemMods[$this->id]))
{
foreach ($this->itemMods[$this->id] as $k => $v)
{
if (!$v)
continue;
if ($str = Util::$itemMods[$k])
$updateFields[$str] = number_format($v, 2, '.', '');
}
}
if (count($updateFields) > 1)
DB::Aowow()->query('REPLACE INTO ?_item_stats (?#) VALUES (?a)', array_keys($updateFields), array_values($updateFields), $this->id);
}
}
}
function item_stats(array $ids = [])
{
$offset = 0;
while (true)
{
$items = new ItemStatSetup($offset, SqlGen::$stepSize, $ids);
if ($items->error)
break;
$max = max($items->getFoundIDs());
$num = count($items->getFoundIDs());
CLISetup::log(' * sets '.($offset + 1).' - '.($max));
$offset = $max;
$items->writeStatsTable();
}
return true;
}
?>

View File

@@ -0,0 +1,27 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
$customData = array(
);
$reqDBC = ['itemrandomsuffix', 'itemrandomproperties'];
function itemrandomenchant()
{
$query = '
REPLACE INTO ?_itemrandomenchant
SELECT -id, name_loc0, name_loc2, name_loc3, name_loc6, name_loc8, nameINT, enchantId1, enchantId2, enchantId3, enchantId4, enchantId5, allocationPct1, allocationPct2, allocationPct3, allocationPct4, allocationPct5 FROM dbc_itemrandomsuffix
UNION
SELECT id, name_loc0, name_loc2, name_loc3, name_loc6, name_loc8, nameINT, enchantId1, enchantId2, enchantId3, enchantId4, enchantId5, 0, 0, 0, 0, 0 FROM dbc_itemrandomproperties';
DB::Aowow()->query($query);
return true;
}
?>

View File

@@ -0,0 +1,210 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* item_template
* locales_item
* spell_group
*/
$customData = array(
33147 => ['class' => 9, 'subClass' => 8], // one stray enchanting recipe .. with a strange icon
7948 => ['itemset' => 221], // v unsure if this should be fixed v
7949 => ['itemset' => 221],
7950 => ['itemset' => 221],
7951 => ['itemset' => 221],
7952 => ['itemset' => 221],
7953 => ['itemset' => 221]
);
$reqDBC = ['gemproperties', 'itemdisplayinfo', 'spell', 'glyphproperties', 'durabilityquality', 'durabilitycosts'];
function items(array $ids = [])
{
$baseQuery = '
SELECT
it.entry,
class, class as classBak,
subclass, subclass AS subClassBak,
IFNULL(sg.id, 0) AS subSubClass,
name, name_loc2, name_loc3, name_loc6, name_loc8,
displayid,
Quality,
Flags, FlagsExtra,
BuyCount, BuyPrice, SellPrice,
0 AS repairPrice,
InventoryType AS slot, InventoryType AS slotBak,
AllowableClass, AllowableRace,
ItemLevel,
RequiredLevel,
RequiredSkill, RequiredSkillRank,
requiredspell,
requiredhonorrank,
RequiredCityRank,
RequiredReputationFaction,
RequiredReputationRank,
maxcount,
0 AS cuFlags,
0 AS model,
stackable,
ContainerSlots,
stat_type1, stat_value1,
stat_type2, stat_value2,
stat_type3, stat_value3,
stat_type4, stat_value4,
stat_type5, stat_value5,
stat_type6, stat_value6,
stat_type7, stat_value7,
stat_type8, stat_value8,
stat_type9, stat_value9,
stat_type10, stat_value10,
ScalingStatDistribution,
ScalingStatValue,
dmg_min1, dmg_max1, dmg_type1,
dmg_min2, dmg_max2, dmg_type2,
delay,
armor, ArmorDamageModifier,
block,
holy_res, fire_res, nature_res, frost_res, shadow_res, arcane_res,
ammo_type,
RangedModRange,
spellid_1, spelltrigger_1, spellcharges_1, spellppmRate_1, spellcooldown_1, spellcategory_1, spellcategorycooldown_1,
spellid_2, spelltrigger_2, spellcharges_2, spellppmRate_2, spellcooldown_2, spellcategory_2, spellcategorycooldown_2,
spellid_3, spelltrigger_3, spellcharges_3, spellppmRate_3, spellcooldown_3, spellcategory_3, spellcategorycooldown_3,
spellid_4, spelltrigger_4, spellcharges_4, spellppmRate_4, spellcooldown_4, spellcategory_4, spellcategorycooldown_4,
spellid_5, spelltrigger_5, spellcharges_5, spellppmRate_5, spellcooldown_5, spellcategory_5, spellcategorycooldown_5,
bonding,
description, description_loc2, description_loc3, description_loc6, description_loc8,
PageText,
LanguageID,
startquest,
lockid,
IF(RandomProperty > 0, RandomProperty, -RandomSuffix) AS randomEnchant,
itemset,
MaxDurability,
area,
Map,
BagFamily,
TotemCategory,
socketColor_1, socketContent_1,
socketColor_2, socketContent_2,
socketColor_3, socketContent_3,
socketBonus,
GemProperties,
RequiredDisenchantSkill,
DisenchantID,
duration,
ItemLimitCategory,
HolidayId,
ScriptName,
FoodType,
0 AS gemEnchantmentId,
minMoneyLoot, maxMoneyLoot,
flagsCustom
FROM
item_template it
LEFT JOIN
locales_item li ON li.entry = it.entry
LEFT JOIN
spell_group sg ON sg.spell_id = it.spellid_1 AND it.class = 0 AND it.subclass = 2 AND sg.id IN (1, 2)
{
WHERE
ct.entry IN (?a)
}
LIMIT
?d, ?d';
$offset = 0;
while ($items = DB::World()->select($baseQuery, $ids ?: DBSIMPLE_SKIP, $offset, SqlGen::$stepSize))
{
CLISetup::log(' * sets '.($offset + 1).' - '.($offset + count($items)));
$offset += SqlGen::$stepSize;
foreach ($items as $item)
DB::Aowow()->query('REPLACE INTO ?_items VALUES (?a)', array_values($item));
}
// merge with gemProperties
DB::Aowow()->query('UPDATE ?_items i, dbc_gemproperties gp SET i.gemEnchantmentId = gp.enchantmentId, i.gemColorMask = gp.colorMask WHERE i.gemColorMask = gp.id');
// get modelString
DB::Aowow()->query('UPDATE ?_items i, dbc_itemdisplayinfo idi SET i.model = IF(idi.leftModelName = "", idi.rightModelName, idi.leftModelName) WHERE i.displayId = idi.id');
// unify slots: Robes => Chest; Ranged (right) => Ranged
DB::Aowow()->query('UPDATE ?_items SET slot = 15 WHERE slotbak = 26');
DB::Aowow()->query('UPDATE ?_items SET slot = 5 WHERE slotbak = 20');
// custom sub-classes
DB::Aowow()->query('
UPDATE ?_items SET subclass = IF(
slotbak = 4, -8, IF( -- shirt
slotbak = 19, -7, IF( -- tabard
slotbak = 16, -6, IF( -- cloak
slotbak = 23, -5, IF( -- held in offhand
slotbak = 12, -4, IF( -- trinket
slotbak = 2, -3, IF( -- amulet
slotbak = 11, -2, subClassBak -- ring
))))))) WHERE class = 4');
// move alchemist stones to trinkets (Armor)
DB::Aowow()->query('UPDATE ?_items SET class = 4, subClass = -4 WHERE classBak = 7 AND subClassBak = 11 AND slotBak = 12');
// mark keys as key (if not quest items)
DB::Aowow()->query('UPDATE ?_items SET class = 13, subClass = 0 WHERE classBak IN (0, 15) AND bagFamily & 0x100');
// set subSubClass for Glyphs (major/minor)
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s, dbc_glyphproperties gp SET i.subSubClass = IF(gp.typeFlags & 0x1, 2, 1) WHERE i.spellId1 = s.id AND s.effect1MiscValue = gp.id AND i.classBak = 16');
// filter misc(class:15) junk(subclass:0) to appropriate categories
// assign pets and mounts to category
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s SET subClass = IF(effect1AuraId <> 78, 2, IF(effect2AuraId = 207 OR effect3AuraId = 207 OR (s.id <> 65917 AND effect2AuraId = 4 AND effect3Id = 77), -7, 5)) WHERE s.id = spellId2 AND class = 15 AND spellId1 IN (483, 55884)');
// more corner cases (mounts that are not actualy learned)
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s SET i.subClass = -7 WHERE (effect1Id = 64 OR (effect1AuraId = 78 AND effect2AuraId = 4 AND effect3Id = 77) OR effect1AuraId = 207 OR effect2AuraId = 207 OR effect3AuraId = 207) AND s.id = i.spellId1 AND i.class = 15 AND i.subClass = 5');
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s SET i.subClass = 5 WHERE s.effect1AuraId = 78 AND s.id = i.spellId1 AND i.class = 15 AND i.subClass = 0');
// move some permanent enchantments to own category
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s SET i.class = 0, i.subClass = 6 WHERE s.effect1Id = 53 AND s.id = i.spellId1 AND i.class = 15');
// move temporary enchantments to own category
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s SET i.subClass = -3 WHERE s.effect1Id = 54 AND s.id = i.spellId1 AND i.class = 0 AND i.subClassBak = 8');
// move armor tokens to own category
DB::Aowow()->query('UPDATE ?_items SET subClass = -2 WHERE quality = 4 AND class = 15 AND subClassBak = 0 AND requiredClass AND (requiredClass & 0x5FF) <> 0x5FF');
// calculate durabilityCosts
DB::Aowow()->query('
UPDATE
?_items i
JOIN
dbc_durabilityquality dq ON dq.id = ((i.quality + 1) * 2)
JOIN
dbc_durabilitycosts dc ON dc.id = i.itemLevel
SET
i.repairPrice = (durability* dq.mod * IF(i.classBak = 2,
CASE i.subClassBak
WHEN 0 THEN w0 WHEN 1 THEN w1 WHEN 2 THEN w2 WHEN 3 THEN w3 WHEN 4 THEN w4
WHEN 5 THEN w5 WHEN 6 THEN w6 WHEN 7 THEN w7 WHEN 8 THEN w8 WHEN 10 THEN w10
WHEN 11 THEN w11 WHEN 12 THEN w12 WHEN 13 THEN w13 WHEN 14 THEN w14 WHEN 15 THEN w15
WHEN 16 THEN w16 WHEN 17 THEN w17 WHEN 18 THEN w18 WHEN 19 THEN w19 WHEN 20 THEN w20
END,
CASE i.subClassBak
WHEN 1 THEN a1 WHEN 2 THEN a2 WHEN 3 THEN a3 WHEN 4 THEN a4 WHEN 6 THEN a6
END
))
WHERE
durability > 0 AND ((classBak = 4 AND subClassBak IN (1, 2, 3, 4, 6)) OR (classBak = 2 AND subClassBak <> 9))');
return true;
}
?>

View File

@@ -0,0 +1,365 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/*
note: the virtual set-ids wont match the ones of wowhead
since there are some unused itemsets and and items flying around in a default database this script will create about 20 sets more than you'd expect.
and i have no idea how to merge the prefixes/suffixes for wotlk-raidsets and arena-sets in gereral onto the name.. at least not for all locales and i'll be damned if i have to skip one
*/
/* deps:
* item_template
*/
$customData = array(
221 => ['item1' => 7948, 'item2' => 7949, 'item3' => 7950, 'item4' => 7951, 'item5' => 7952, 'item6' => 7953]
);
$reqDBC = ['itemset'];
function itemset()
{
$locales = [LOCALE_EN, LOCALE_FR, LOCALE_DE, LOCALE_ES, LOCALE_RU];
$setToHoliday = array (
761 => 141, // Winterveil
762 => 372, // Brewfest
785 => 341, // Midsummer
812 => 181, // Noblegarden
);
// tags where refId == virtualId
// in pve sets are not recycled beyond the contentGroup
$tagsById = array(
// "Dungeon Set 1"
1 => [181, 182, 183, 184, 185, 186, 187, 188, 189],
// "Dungeon Set 2"
2 => [511, 512, 513, 514, 515, 516, 517, 518, 519],
// "Tier 1 Raid Set"
3 => [201, 202, 203, 204, 205, 206, 207, 208, 209],
// "Tier 2 Raid Set"
4 => [210, 211, 212, 213, 214, 215, 216, 217, 218],
// "Tier 3 Raid Set"
5 => [521, 523, 524, 525, 526, 527, 528, 529, 530],
// "Level 60 PvP Rare Set"
6 => [522, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 697, 718],
// "Level 60 PvP Rare Set (Old)"
7 => [281, 282, 301, 341, 342, 343, 344, 345, 346, 347, 348, 361, 362, 381, 382, 401],
// "Level 60 PvP Epic Set"
8 => [383, 384, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 402, 717, 698],
// "Ruins of Ahn'Qiraj Set"
9 => [494, 495, 498, 500, 502, 504, 506, 508, 510],
// "Temple of Ahn'Qiraj Set"
10 => [493, 496, 497, 499, 501, 503, 505, 507, 509],
// "Zul'Gurub Set"
11 => [477, 480, 474, 475, 476, 478, 479, 481, 482],
// "Tier 4 Raid Set"
12 => [621, 624, 625, 626, 631, 632, 633, 638, 639, 640, 645, 648, 651, 654, 655, 663, 664],
// "Tier 5 Raid Set",
13 => [622, 627, 628, 629, 634, 635, 636, 641, 642, 643, 646, 649, 652, 656, 657, 665, 666],
// "Dungeon Set 3",
14 => [620, 623, 630, 637, 644, 647, 650, 653, 658, 659, 660, 661, 662],
// "Arathi Basin Set",
15 => [467, 468, 469, 470, 471, 472, 473, 483, 484, 485, 486, 487, 488, 908],
// "Level 70 PvP Rare Set",
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],
// "Tier 6 Raid Set",
18 => [668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684],
// "Level 70 PvP Rare Set 2",
21 => [738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752],
// "Tier 7 Raid Set",
23 => [795, 805, 804, 803, 802, 801, 800, 799, 798, 797, 796, 794, 793, 792, 791, 790, 789, 788, 787],
// "Tier 8 Raid Set",
25 => [838, 837, 836, 835, 834, 833, 832, 831, 830, 829, 828, 827, 826, 825, 824, 823, 822, 821, 820],
// "Tier 9 Raid Set",
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],
// "Tier 10 Raid Set",
29 => [901, 900, 899, 898, 897, 896, 895, 894, 893, 892, 891, 890, 889, 888, 887, 886, 885, 884, 883]
);
// well .. fuck
$tagsByNamePart = array(
17 => ['gladiator'], // "Arena Season 1 Set",
19 => ['merciless'], // "Arena Season 2 Set",
20 => ['vengeful'], // "Arena Season 3 Set",
22 => ['brutal'], // "Arena Season 4 Set",
24 => ['deadly', 'hateful', 'savage'], // "Arena Season 5 Set",
26 => ['furious'], // "Arena Season 6 Set",
28 => ['relentless'], // "Arena Season 7 Set",
30 => ['wrathful'] // "Arena Season 8 Set",
);
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; // 1H-Axe
else if ($piece['class'] == 2 && $piece['subclass'] == 4)
$type = 9; // 1H-Mace
else if ($piece['class'] == 2 && $piece['subclass'] == 7)
$type = 10; // 1H-Sword
else if ($piece['class'] == 2 && $piece['subclass'] == 13)
$type = 7; // Fist Weapon
else if ($piece['class'] == 2 && $piece['subclass'] == 15)
$type = 5; // Dagger
if (!$type)
{
if ($piece['class'] == 4 && $piece['slot'] == 12)
$type = 11; // trinket
else if ($piece['class'] == 4 && $piece['slot'] == 2)
$type = 12; // amulet
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&nbsp;<small>(<!--rtg%19-->0.30%&nbsp;@&nbsp;L<!--lvl-->80)</small>
$descText[$loc] = preg_replace('/<!--rtg\d+-->(\d+)&nbsp.*?<\/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;
}
?>

View File

@@ -0,0 +1,106 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* gameobject_template
* locales_gameobject
*/
$customData = array(
);
$reqDBC = ['lock'];
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 questitem1 <> 0, -2, -- quests 2
IF(`type` IN (3, 9, 25), `type`, 0)))), -- regular chests, books, pools
0 AS event, -- linked worldevent
displayId,
name, name_loc2, name_loc3, name_loc6, name_loc8,
faction,
flags,
0 AS cuFlags, -- custom Flags
questItem1, questItem2, questItem3, questItem4, questItem5, questItem6,
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
locales_gameobject lgo ON go.entry = lgo.entry
{
WHERE
go.entry IN (?a)
}
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;
}
?>

View File

@@ -0,0 +1,125 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* creature_template
* creature
*/
$customData = array(
);
$reqDBC = ['talent', 'spell', 'skilllineability', 'creaturefamily'];
function pet(array $ids = [])
{
$baseQuery = '
REPLACE INTO
?_pet
SELECT
f.id,
categoryEnumId,
0, -- cuFlags
0, -- minLevel
0, -- maxLevel
petFoodMask,
petTalentType,
0, -- exotic
0, -- expansion
name_loc0, name_loc2, name_loc3, name_lo6, name_loc8,
LOWER(SUBSTRING_INDEX(iconString, "\\\\", -1)),
skillLine1,
0, 0, 0, 0, -- spell[1-4]
0, 0, 0 -- armor, damage, health
FROM
dbc_creaturefamily f
WHERE
petTalentType <> -1';
$spawnQuery = '
SELECT
ct.family AS ARRAY_KEY,
MIN(ct.minlevel) AS minLevel,
MAX(ct.maxlevel) AS maxLevel,
IF(ct.type_flags & 0x10000, 1, 0) AS exotic
FROM
creature_template ct
JOIN
creature c ON ct.entry = c.id
WHERE
ct.type_flags & 0x1
GROUP BY
ct.family';
$bonusQuery = '
UPDATE
?_pet p,
dbc_skilllineability sla,
dbc_spell s
SET
armor = s.effect2BasePoints + s.effect2DieSides,
damage = s.effect1BasePoints + s.effect1DieSides,
health = s.effect3BasePoints + s.effect3DieSides
WHERE
p.skillLineId = sla.skillLineId AND
sla.spellId = s.id AND
s.name_loc0 = "Tamed Pet Passive (DND)"';
$spellQuery = '
SELECT
p.id,
MAX(s.id) AS spell
FROM
dbc_skilllineability sla
JOIN
?_pet p ON p.skillLineId = sla.skillLineId
JOIN
dbc_spell s ON sla.spellId = s.id
LEFT OUTER JOIN
dbc_talent t ON s.id = t.rank1
WHERE
(s.attributes0 & 0x40) = 0 AND
t.id IS NULL
GROUP BY
s.name_loc0, p.id';
// basic copy from creaturefamily.dbc
DB::Aowow()->query($baseQuery);
// stats from craeture_template
$spawnInfo = DB::World()->query($spawnQuery);
foreach ($spawnInfo as $id => $info)
DB::Aowow()->query('UPDATE ?_pet SET ?a WHERE id = ?d', $info, $id);
// add petFamilyModifier to health, mana, dmg
DB::Aowow()->query($bonusQuery);
// add expansion manually
DB::Aowow()->query('UPDATE ?_pet SET expansion = 1 WHERE id IN (30, 31, 32, 33, 34)');
DB::Aowow()->query('UPDATE ?_pet SET expansion = 2 WHERE id IN (37, 38, 39, 41, 42, 43, 44, 45, 46)');
// assign pet spells
$pets = DB::Aowow()->select($spellQuery);
$res = [];
foreach ($pets as $set) // convert to usable structure
{
if (!isset($res[$set['id']]))
$res[$set['id']] = [];
$res[$set['id']]['spellId'.(count($res[$set['id']]) + 1)] = $set['spell'];
}
foreach ($res as $pId => $row)
DB::Aowow()->query('UPDATE ?_pet SET ?a WHERE id = ?d', $row, $pId);
return true;
}
?>

View File

@@ -0,0 +1,203 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* quest_template
* locales_quest
* game_event
* game_event_seasonal_questrelation
*/
$customData = array(
);
$reqDBC = ['questxp', 'questfactionreward'];
function quests(array $ids = [])
{
$baseQuery = '
SELECT
q.Id,
Method,
Level,
MinLevel,
MaxLevel,
ZoneOrSort,
ZoneOrSort AS zoneOrSortBak, -- ZoneOrSortBak
Type,
SuggestedPlayers,
LimitTime,
0 AS holidayId, -- holidayId
PrevQuestId,
NextQuestId,
ExclusiveGroup,
NextQuestIdChain,
Flags,
SpecialFlags,
0 AS cuFlags, -- cuFlags
RequiredClasses, RequiredRaces,
RequiredSkillId, RequiredSkillPoints,
RequiredFactionId1, RequiredFactionId2,
RequiredFactionValue1, RequiredFactionValue2,
RequiredMinRepFaction, RequiredMaxRepFaction,
RequiredMinRepValue, RequiredMaxRepValue,
RequiredPlayerKills,
SourceItemId, SourceItemCount,
SourceSpellId,
RewardXPId, -- QuestXP.dbc x level
RewardOrRequiredMoney,
RewardMoneyMaxLevel,
RewardSpell, RewardSpellCast,
RewardHonor * 124 * RewardHonorMultiplier, -- alt calculation in QuestDef.cpp -> Quest::CalculateHonorGain(playerLevel)
RewardMailTemplateId, RewardMailDelay,
RewardTitleId,
RewardTalents,
RewardArenaPoints,
RewardItemId1, RewardItemId2, RewardItemId3, RewardItemId4,
RewardItemCount1, RewardItemCount2, RewardItemCount3, RewardItemCount4,
RewardChoiceItemId1, RewardChoiceItemId2, RewardChoiceItemId3, RewardChoiceItemId4, RewardChoiceItemId5, RewardChoiceItemId6,
RewardChoiceItemCount1, RewardChoiceItemCount2, RewardChoiceItemCount3, RewardChoiceItemCount4, RewardChoiceItemCount5, RewardChoiceItemCount6,
RewardFactionId1, RewardFactionId2, RewardFactionId3, RewardFactionId4, RewardFactionId5,
IF (RewardFactionValueIdOverride1 <> 0, RewardFactionValueIdOverride1 / 100, RewardFactionValueId1),
IF (RewardFactionValueIdOverride2 <> 0, RewardFactionValueIdOverride2 / 100, RewardFactionValueId2),
IF (RewardFactionValueIdOverride3 <> 0, RewardFactionValueIdOverride3 / 100, RewardFactionValueId3),
IF (RewardFactionValueIdOverride4 <> 0, RewardFactionValueIdOverride4 / 100, RewardFactionValueId4),
IF (RewardFactionValueIdOverride5 <> 0, RewardFactionValueIdOverride5 / 100, RewardFactionValueId5),
Title, Title_loc2, Title_loc3, Title_loc6, Title_loc8,
Objectives, Objectives_loc2, Objectives_loc3, Objectives_loc6, Objectives_loc8,
Details, Details_loc2, Details_loc3, Details_loc6, Details_loc8,
EndText, EndText_loc2, EndText_loc3, EndText_loc6, EndText_loc8,
OfferRewardText, OfferRewardText_loc2, OfferRewardText_loc3, OfferRewardText_loc6, OfferRewardText_loc8,
RequestItemsText, RequestItemsText_loc2, RequestItemsText_loc3, RequestItemsText_loc6, RequestItemsText_loc8,
CompletedText, CompletedText_loc2, CompletedText_loc3, CompletedText_loc6, CompletedText_loc8,
RequiredNpcOrGo1, RequiredNpcOrGo2, RequiredNpcOrGo3, RequiredNpcOrGo4,
RequiredNpcOrGoCount1, RequiredNpcOrGoCount2, RequiredNpcOrGoCount3, RequiredNpcOrGoCount4,
RequiredSourceItemId1, RequiredSourceItemId2, RequiredSourceItemId3, RequiredSourceItemId4,
RequiredSourceItemCount1,RequiredSourceItemCount2,RequiredSourceItemCount3,RequiredSourceItemCount4,
RequiredItemId1, RequiredItemId2, RequiredItemId3, RequiredItemId4, RequiredItemId5, RequiredItemId6,
RequiredItemCount1, RequiredItemCount2, RequiredItemCount3, RequiredItemCount4, RequiredItemCount5, RequiredItemCount6,
ObjectiveText1, ObjectiveText1_loc2, ObjectiveText1_loc3, ObjectiveText1_loc6, ObjectiveText1_loc8,
ObjectiveText2, ObjectiveText2_loc2, ObjectiveText2_loc3, ObjectiveText2_loc6, ObjectiveText2_loc8,
ObjectiveText3, ObjectiveText3_loc2, ObjectiveText3_loc3, ObjectiveText3_loc6, ObjectiveText3_loc8,
ObjectiveText4, ObjectiveText4_loc2, ObjectiveText4_loc3, ObjectiveText4_loc6, ObjectiveText4_loc8
FROM
quest_template q
LEFT JOIN
locales_quest lq ON q.Id = lq.Id
{
WHERE
q.Id IN (?a)
}
LIMIT
?d, ?d';
$xpQuery = '
UPDATE
?_quests q,
dbc_questxp xp
SET
rewardXP = (CASE rewardXP
WHEN 1 THEN xp.Field1 WHEN 2 THEN xp.Field2 WHEN 3 THEN xp.Field3 WHEN 4 THEN xp.Field4 WHEN 5 THEN xp.Field5
WHEN 6 THEN xp.Field6 WHEN 7 THEN xp.Field7 WHEN 8 THEN xp.Field8 WHEN 9 THEN xp.Field9 WHEN 10 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 1 THEN rep.Field1 WHEN 2 THEN rep.Field2 WHEN 3 THEN rep.Field3 WHEN 4 THEN rep.Field4 WHEN 5 THEN rep.Field5
WHEN 6 THEN rep.Field6 WHEN 7 THEN rep.Field7 WHEN 8 THEN rep.Field8 WHEN 9 THEN rep.Field9 WHEN 10 THEN rep.Field10
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 .. well .. now "not documenting" bites me in the ass .. ~700 quests were changed, i don't know by what method
$questByHoliday = DB::World()->selectCol('SELECT sq.questId AS ARRAY_KEY, ge.holiday FROM game_event_seasonal_questrelation sq JOIN game_event ge ON ge.eventEntry = sq.eventEntry');
$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 ($questByHoliday as $qId => $hId)
if ($hId)
DB::Aowow()->query('UPDATE ?_quests SET zoneOrSort = ?d WHERE id = ?d{ AND id IN (?a)}', $holidaySorts[$hId], $qId, $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);
// finally link related events (after zoneorSort has been updated)
foreach ($holidaySorts as $hId => $sort)
DB::Aowow()->query('UPDATE ?_quests SET holidayId = ?d WHERE zoneOrSort = ?d{ AND id IN (?a)}', $hId, $sort, $ids ?: DBSIMPLE_SKIP);
return true;
}
?>

View File

@@ -0,0 +1,54 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* creature_queststarter
* creature_questender
* game_event_creature_quest
* gameobject_queststarter
* gameobject_questender
* game_event_gameobject_quest
* item_template
*/
$customData = array(
);
$reqDBC = array(
);
function quests_startend(/* array $ids = [] */)
{
$query['creature'] = '
SELECT 1 AS type, id AS typeId, quest AS questId, 1 AS method, 0 AS eventId FROM creature_queststarter UNION
SELECT 1 AS type, id AS typeId, quest AS questId, 2 AS method, 0 AS eventId FROM creature_questender UNION
SELECT 1 AS type, id AS typeId, quest AS questId, 1 AS method, eventEntry AS eventId FROM game_event_creature_quest';
$query['object'] = '
SELECT 2 AS type, id AS typeId, quest AS questId, 1 AS method, 0 AS eventId FROM gameobject_queststarter UNION
SELECT 2 AS type, id AS typeId, quest AS questId, 2 AS method, 0 AS eventId FROM gameobject_questender UNION
SELECT 2 AS type, id AS typeId, quest AS questId, 1 AS method, eventEntry AS eventId FROM game_event_gameobject_quest';
$query['item'] = 'SELECT 3 AS type, entry AS typeId, startquest AS questId, 1 AS method, 0 AS eventId FROM item_template WHERE startquest <> 0';
// always rebuild this table from scratch
// or how would i know what to fetch specifically
DB::Aowow()->query('TRUNCATE TABLE ?_quests_startend');
foreach ($query as $q)
{
$data = DB::World()->select($q);
foreach ($data as $d)
DB::Aowow()->query('INSERT INTO ?_quests_startend (?#) VALUES (?a) ON DUPLICATE KEY UPDATE method = method | VALUES(method), eventId = IF(eventId = 0, VALUES(eventId), eventId)', array_keys($d), array_values($d));
}
return true;
}
?>

View File

@@ -0,0 +1,47 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
$customData = array(
null,
['leader' => 29611, 'factionId' => 72, 'startAreaId' => 12],
['leader' => 4949, 'factionId' => 76, 'startAreaId' => 14],
['leader' => 2784, 'factionId' => 47, 'startAreaId' => 1],
['leader' => 7999, 'factionId' => 96, 'startAreaId' => 141],
['leader' => 10181, 'factionId' => 68, 'startAreaId' => 85],
['leader' => 3057, 'factionId' => 81, 'startAreaId' => 215],
['leader' => 7937, 'factionId' => 54, 'startAreaId' => 1],
['leader' => 10540, 'factionId' => 530, 'startAreaId' => 14],
null,
['leader' => 16802, 'factionId' => 911, 'startAreaId' => 3430],
['leader' => 17468, 'factionId' => 930, 'startAreaId' => 3524]
);
$reqDBC = ['chrraces', 'charbaseinfo'];
function races()
{
$baseQuery = '
REPLACE INTO
?_races
SELECT
Id, 0, flags, 0, factionId, 0, 0, baseLanguage, IF(side = 2, 0, side + 1), fileString, name_loc0, name_loc2, name_loc3, name_loc6, name_loc8, expansion
FROM
dbc_chrraces';
DB::Aowow()->query($baseQuery);
// add classMask
DB::Aowow()->query('UPDATE ?_races r JOIN (SELECT BIT_OR(1 << (classId - 1)) as classMask, raceId FROM dbc_charbaseinfo GROUP BY raceId) cbi ON cbi.raceId = r.id SET r.classMask = cbi.classMask');
// add cuFlags
DB::Aowow()->query('UPDATE ?_races SET cuFlags = ?d WHERE flags & ?d', CUSTOM_EXCLUDE_FOR_LISTVIEW, 0x1);
return true;
}
?>

View File

@@ -0,0 +1,28 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
$customData = array(
1 => ['displayIdH' => 8571],
15 => ['displayIdH' => 8571],
5 => ['displayIdH' => 2289],
8 => ['displayIdH' => 2289],
14 => ['displayIdH' => 2289],
27 => ['displayIdH' => 21244],
29 => ['displayIdH' => 20872],
);
$reqDBC = ['spellshapeshiftform'];
function shapeshiftforms()
{
DB::Aowow()->query('REPLACE INTO ?_shapeshiftforms SELECT * FROM dbc_spellshapeshiftform');
return true;
}
?>

View File

@@ -0,0 +1,58 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
$customData = array(
393 => ['professionMask' => 0x0000, 'iconId' => 736], // Skinning
171 => ['professionMask' => 0x0001, 'recipeSubClass' => 6, 'specializations' => '28677 28675 28672'], // Alchemy
164 => ['professionMask' => 0x0002, 'recipeSubClass' => 4, 'specializations' => '9788 9787 17041 17040 17039'], // Blacksmithing
185 => ['professionMask' => 0x0004, 'recipeSubClass' => 5], // Cooking
333 => ['professionMask' => 0x0008, 'recipeSubClass' => 8], // Enchanting
202 => ['professionMask' => 0x0010, 'recipeSubClass' => 3, 'specializations' => '20219 20222'], // Engineering
129 => ['professionMask' => 0x0020, 'recipeSubClass' => 7], // First Aid
755 => ['professionMask' => 0x0040, 'recipeSubClass' => 10], // Jewelcrafting
165 => ['professionMask' => 0x0080, 'recipeSubClass' => 1, 'specializations' => '10656 10658 10660'], // Leatherworking
186 => ['professionMask' => 0x0100], // Mining
197 => ['professionMask' => 0x0200, 'recipeSubClass' => 2, 'specializations' => '26798 26801 26797'], // Tailoring
356 => ['professionMask' => 0x0400, 'recipeSubClass' => 9], // Fishing
182 => ['professionMask' => 0x0800], // Herbalism
773 => ['professionMask' => 0x1000, 'recipeSubClass' => 11], // Inscription
633 => ['iconId' => 936], // lockpicking
785 => ['name_loc0' => 'Pet - Wasp'], // Pet - Wasp
781 => ['name_loc2' => 'Familier - diablosaure exotique'], // Pet - Exotic Devilsaur
758 => ['name_loc6' => 'Mascota: Evento - Control remoto', 'name_loc3' => 'Tier - Ereignis Ferngesteuert', 'categoryId' => 7], // Pet - Event - Remote Control
788 => ['categoryId' => 7], // Pet - Exotic Spirit Beast
);
$reqDBC = ['skillline', 'spell', 'skilllineability'];
function skillline()
{
$baseQuery = '
REPLACE INTO
?_skillline
SELECT
Id, categoryId, 0, categoryId, name_loc0, name_loc2, name_loc3, name_loc6, name_loc8, description_loc0, description_loc2, description_loc3, description_loc6, description_loc8, iconId, 0, 0, ""
FROM
dbc_skillline';
DB::Aowow()->query($baseQuery);
// categorization
DB::Aowow()->query('UPDATE ?_skillline SET typeCat = -5 WHERE id = 777 OR (categoryId = 9 AND id NOT IN (356, 129, 185, 142, 155))');
DB::Aowow()->query('UPDATE ?_skillline SET typeCat = -4 WHERE categoryId = 9 AND name_loc0 LIKE "%racial%"');
DB::Aowow()->query('UPDATE ?_skillline SET typeCat = -6 WHERE id IN (778, 788, 758) OR (categoryId = 7 AND name_loc0 LIKE "%pet%")');
// more complex fixups
DB::Aowow()->query('UPDATE ?_skillline sl, dbc_spell s, dbc_skilllineability sla SET sl.iconId = s.iconId WHERE (s.effect1Id IN (25, 26, 40) OR s.effect2Id = 60) AND sla.spellId = s.id AND sl.id = sla.skillLineId');
DB::Aowow()->query('UPDATE ?_skillline SET name_loc8 = REPLACE(name_loc8, " - ", ": ") WHERE categoryId = 7 OR id IN (758, 788)');
DB::Aowow()->query('UPDATE ?_skillline SET iconId = ?d WHERE iconId = 0', 1776); // inv_misc_questionmark
DB::Aowow()->query('UPDATE ?_skillline SET cuFlags = ?d WHERE id IN (?a)', CUSTOM_EXCLUDE_FOR_LISTVIEW, [142, 148, 149, 150, 152, 155, 183, 533, 553, 554, 713, 769]);
return true;
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,260 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
// requires https://github.com/TrinityCore/TrinityCore/commit/f989c7182c4cc30f1d0ffdc566c7624a5e108a2f
/* deps:
* creature
* creature_addon
* gameobject
* gameobject_template
* vehicle_accessory
* vehicle_accessory_template
* script_waypoint
* waypoints
* waypoint_data
*/
$customData = array(
);
$reqDBC = ['worldmaparea', 'map', 'worldmaptransforms', 'dungeonmap', 'taxipathnode'];
function spawns() // and waypoints
{
$alphaMapCache = [];
$alphaMapCheck = function ($areaId, array &$set) use (&$alphaMapCache)
{
$file = 'cache/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( // capitals take precedence over their surroundings
1497, 1637, 1638, 3487, // Undercity, Ogrimmar, Thunder Bluff, Silvermoon City
1519, 1537, 1657, 3557 // Stormwind City, Ironforge, Darnassus, The Exodar
);
foreach ($points as $res)
{
// 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 (in_array($res['areaId'], $capitals)) // capitals may also be auto-discovered
return $res;
else if ($alphaMapCheck($res['areaId'], $res))
{
if (!$res)
continue;
if (empty($result) || $result[0] > $q)
$result = [$q, $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';
/**************************/
/* 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) // still impossible (there are areas that are intentionally off the map (e.g. the isles south of tanaris))
{
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;
}
?>

View File

@@ -0,0 +1,736 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* item_template
* creature_template
* creature_template_addon
* smart_scripts
* npc_trainer
* disables
* spell_ranks
* spell_dbc
* skill_discovery_template
*/
$customData = array(
);
$reqDBC = [
'spell',
'spellradius',
'spellduration',
'spellrunecost',
'spellcasttimes',
'skillline',
'skilllineability',
'skillraceclassinfo',
'talent',
'talenttab',
'glyphproperties'
];
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_loc6,CONCAT("Serverside - ",Comment) AS name_loc8,
"" AS rank_loc0, "" AS rank_loc2, "" AS rank_loc3, "" AS rank_loc6, "" AS rank_loc8,
"" AS description_loc0, "" AS description_loc2, "" AS description_loc3, "" AS description_loc6, "" AS description_loc8,
"" AS buff_loc0, "" AS buff_loc2, "" AS buff_loc3, "" 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_loc6, name_loc8,
rank_loc0, rank_loc2, rank_loc3, rank_loc6, rank_loc8,
description_loc0, description_loc2, description_loc3, description_loc6, description_loc8,
buff_loc0, buff_loc2, buff_loc3, 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
case 'reqClassMask':
if (((int)$update[$names[$i]] & (int)$field) != $field)
(int)$update[$names[$i]] |= (int)$field;
break;
case 'reqSkillLevel': // 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 spell AS ARRAY_KEY, MIN(reqskillvalue) AS reqSkill, MIN(spellcost) AS cost, COUNT(*) as count FROM npc_trainer GROUP BY spell'))
{
$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
$items = DB::Aowow()->selectCol('SELECT Id AS ARRAY_KEY, effect1CreateItemId FROM dbc_spell WHERE effect1CreateItemId > 0 AND effect1Id <> 53'); // no enchant-spells!
$info = DB::World()->select('SELECT entry AS ARRAY_KEY, displayId AS d, Quality AS q FROM item_template WHERE entry IN (?a)', $items);
foreach ($info as $id => $data)
DB::Aowow()->query('UPDATE ?_spell SET iconIdAlt = ?d, cuFlags = cuFlags | ?d WHERE effect1CreateItemId = ?', -$data['d'], ((7 - $data['q']) << 8), $id);
// 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 spell FROM npc_trainer WHERE entry = ?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), // hunter pets
array_column(Util::$skillLineMask[-2], 1), // warlock pets
[270, 782], // hunter generic, DK - Ghoul
[-1, -2] // super categories
)
);
// 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, // Pestilence
58723 => 55090, // Scourge Strike
58721 => 46584, // Raise Dead
58711 => 52375, // Death Coil
54857 => 33876, // Mangle (Cat)
56881 => 13165, // Aspect of the Hawk
56598 => 27101, // Conjure Mana Gem (Rank 5)
63871 => 1038, // Hand of Salvation
55003 => 53407, // Judgement of Justice
63873 => 47788, // Guardian Spirit
58258 => 2983, // Sprint
55535 => 52127, // Water Shield
55558 => 16190, // Mana Tide Totem
56302 => 697, // Summon Voidwalker
56299 => 712, // Summon Succubus
58272 => 126, // Summon Eye of Kilrogg
56292 => 688, // Summon Imp
56286 => 691, // Summon Felhunter
56285 => 30146, // Summon Felguard
58275 => 29893, // Ritual of Souls
63941 => 1454, // Life Tap
56289 => 5699, // Create Healthstone
56297 => 693, // Create Soulstone
58271 => 1120, // Drain Soul
58281 => 34428, // Victory Rush
58397 => 23922, // Shield Slam
63949 => 50720 // Vigilance
);
$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) // has no skillLine.. :/
{
$icons = [
'skill' => 253,
'icon' => 163 // ability_poisonsting
];
}
// 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;
}
?>

View File

@@ -0,0 +1,32 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* spelldifficulty_dbc
*/
$customData = array(
);
$reqDBC = ['spelldifficulty'];
function spelldifficulty(array $ids = [])
{
// has no unique keys..
DB::Aowow()->query('TRUNCATE TABLE ?_spelldifficulty');
DB::Aowow()->query('INSERT INTO ?_spelldifficulty SELECT * FROM dbc_spelldifficulty');
$rows = DB::World()->select('SELECT spellid0, spellid1, spellid2, spellid3 FROM spelldifficulty_dbc');
foreach ($rows as $r)
DB::Aowow()->query('INSERT INTO ?_spelldifficulty VALUES (?a)', array_values($r));
return true;
}
?>

View File

@@ -0,0 +1,173 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps
* creature_template
* creature
*/
$customData = array(
);
$reqDBC = ['taxipath', 'taxinodes', 'worldmaparea', 'worldmaptransforms', 'factiontemplate'];
function taxi() // path & nodes
{
/*********/
/* paths */
/*********/
DB::Aowow()->query('REPLACE INTO ?_taxipath SELECT tp.id, tp.startNodeId, tp.endNodeId FROM dbc_taxipath tp WHERE tp.startNodeId > 0 AND tp.EndNodeId > 0');
// paths are monodirectional and thus exist twice for regular flight travel (which is bidirectional)
$paths = DB::Aowow()->select('SELECT id AS ARRAY_KEY, tp.* FROM ?_taxipath tp');
foreach ($paths as $i => $p)
{
foreach ($paths as $j => $_)
{
if ($_['startNodeId'] == $p['endNodeId'] AND $_['endNodeId'] == $p['startNodeId'])
{
DB::Aowow()->query('DELETE FROM ?_taxipath WHERE Id = ?d', $j);
unset($paths[$j]);
unset($paths[$i]);
break;
}
}
}
/*********/
/* nodes */
/*********/
// all sensible nodes
$fNodes = DB::Aowow()->select(
'SELECT
tn.id,
tn.mapId,
100 - ROUND((tn.posY - wma.right) * 100 / (wma.left - wma.right), 1) AS posX,
100 - ROUND((tn.posX - wma.bottom) * 100 / (wma.top - wma.bottom), 1) AS poxY,
1 AS type,
0 AS typeId,
1 AS reactA,
1 AS reactH,
tn.name_loc0, tn.name_loc2, tn.name_loc3, tn.name_loc6, tn.name_loc8,
tn.mapId AS origMap,
tn.posX AS origPosX,
tn.posY AS origPosY
FROM
dbc_taxinodes tn
JOIN
dbc_worldmaparea wma ON ( tn.mapId = wma.mapId AND tn.posX BETWEEN wma.bottom AND wma.top AND tn.posY BETWEEN wma.right AND wma.left)
WHERE
wma.areaId = 0 AND
wma.mapId = tn.mapId AND
tn.id NOT IN (15, 148, 225, 235) AND
(
tn.id IN (64, 250) OR
(
tn.name_loc0 NOT LIKE "%Transport%" AND
tn.name_loc0 NOT LIKE "%Quest%" AND
tn.name_loc0 NOT LIKE "%Start%" AND
tn.name_loc0 NOT LIKE "%End%"
)
)
UNION
SELECT
tn.id,
wmt.targetMapId,
100 - ROUND((tn.posY + wmt.offsetY - wma.right) * 100 / (wma.left - wma.right), 1) AS posX,
100 - ROUND((tn.posX + wmt.offsetX - wma.bottom) * 100 / (wma.top - wma.bottom), 1) AS poxY,
1 AS type,
0 AS typeId,
1 AS reactA,
1 AS reactH,
tn.name_loc0, tn.name_loc2, tn.name_loc3, tn.name_loc6, tn.name_loc8,
tn.mapId AS origMap,
tn.posX AS origPosX,
tn.posY AS origPosY
FROM
dbc_taxinodes tn
JOIN
dbc_worldmaptransforms wmt ON ( tn.mapId = wmt.sourceMapId AND tn.posX BETWEEN wmt.minX AND wmt.maxX AND tn.posY BETWEEN wmt.minY AND wmt.maxY)
JOIN
dbc_worldmaparea wma ON ( wmt.targetMapId = wma.mapId AND tn.posX + wmt.offsetX BETWEEN wma.bottom AND wma.top AND tn.posY + wmt.offsetY BETWEEN wma.right AND wma.left)
WHERE
wma.areaId = 0 AND
wmt.sourcemapId = tn.mapId AND
tn.name_loc0 NOT LIKE "%Transport%" AND
tn.name_loc0 NOT LIKE "%Quest%" AND
tn.name_loc0 NOT LIKE "%Start%" AND
tn.name_loc0 NOT LIKE "%End%"');
// all available flightmaster
$fMaster = DB::World()->select(
'SELECT ct.entry, ct.faction, c.map, c.position_x AS posX, c.position_y AS posY FROM creature_template ct JOIN creature c ON c.id = ct.entry WHERE ct.npcflag & ?d OR c.npcflag & ?d',
NPC_FLAG_FLIGHT_MASTER, NPC_FLAG_FLIGHT_MASTER
);
// assign nearest flightmaster to node
foreach ($fNodes as &$n)
{
foreach ($fMaster as &$c)
{
if ($c['map'] != $n['origMap'])
continue;
$dist = pow($c['posX'] - $n['origPosX'], 2) + pow($c['posY'] - $n['origPosY'], 2);
if ($dist > 1000)
continue;
if (!isset($n['dist']) || $n['dist'] < $dist)
{
$n['dist'] = $dist;
$n['typeId'] = $c['entry'];
$n['faction'] = $c['faction'];
}
}
}
unset($n);
// fetch reactions per faction
$factions = DB::Aowow()->query('
SELECT
Id AS ARRAY_KEY,
IF(enemyFactionId1 = 1 OR enemyFactionId2 = 1 OR enemyFactionId3 = 1 OR enemyFactionId4 = 1 OR hostileMask & 0x3, -1, 1) AS reactA,
IF(enemyFactionId1 = 2 OR enemyFactionId2 = 2 OR enemyFactionId3 = 2 OR enemyFactionId4 = 2 OR hostileMask & 0x5, -1, 1) AS reactH
FROM
dbc_factiontemplate
WHERE
Id IN (?a)',
array_column($fNodes, 'faction')
);
foreach ($fNodes as $n)
{
if (empty($n['faction']))
{
CLISetup::log(' - ['.$n['id'].'] "'.$n['name_loc0'].'" has no NPC assigned ... skipping', CLISetup::LOG_WARN);
continue;
}
if (isset($factions[$n['faction']]))
{
$n['reactA'] = $factions[$n['faction']]['reactA'];
$n['reactH'] = $factions[$n['faction']]['reactH'];
}
unset($n['faction'], $n['origMap'], $n['origPosX'], $n['origPosY'], $n['dist']);
DB::Aowow()->query('REPLACE INTO ?_taxinodes VALUES (?a)', array_values($n));
}
return true;
}
?>

View File

@@ -0,0 +1,97 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps:
* quest_template
* game_event_seasonal_questrelation
* game_event
* achievement_reward
*/
$customData = array(
137 => ['holidayId' => 201, 'gender' => 2],
138 => ['holidayId' => 201, 'gender' => 1],
124 => ['holidayId' => 324],
135 => ['holidayId' => 423],
155 => ['holidayId' => 181],
133 => ['holidayId' => 372],
74 => ['holidayId' => 327],
75 => ['holidayId' => 341],
76 => ['holidayId' => 341],
134 => ['holidayId' => 141],
168 => ['holidayId' => 404]
);
$reqDBC = ['chartitles'];
function titles()
{
$questQuery = '
SELECT
qt.RewardTitleId AS ARRAY_KEY,
qt.RequiredRaces,
ge.holiday
FROM
quest_template qt
LEFT JOIN
game_event_seasonal_questrelation sq ON sq.questId = qt.id
LEFT JOIN
game_event ge ON ge.eventEntry = sq.eventEntry
WHERE
qt.RewardTitleId <> 0';
DB::Aowow()->query('REPLACE INTO ?_titles SELECT Id, 0, 0, 0, 0, 0, 0, 0, male_loc0, male_loc2, male_loc3, male_loc6, male_loc8, female_loc0, female_loc2, female_loc3, female_loc6, female_loc8 FROM dbc_chartitles');
// hide unused titles
DB::Aowow()->query('UPDATE ?_titles SET cuFlags = ?d WHERE id BETWEEN 85 AND 123 AND id NOT IN (113, 120, 121, 122)', CUSTOM_EXCLUDE_FOR_LISTVIEW);
// set expansion
DB::Aowow()->query('UPDATE ?_titles SET expansion = 2 WHERE id >= 72 AND id <> 80');
DB::Aowow()->query('UPDATE ?_titles SET expansion = 1 WHERE id >= 42 AND id <> 46 AND expansion = 0');
// set category
DB::Aowow()->query('UPDATE ?_titles SET category = 1 WHERE id <= 28 OR id IN (42, 43, 44, 45, 47, 48, 62, 71, 72, 80, 82, 126, 127, 128, 157, 163, 167, 169, 177)');
DB::Aowow()->query('UPDATE ?_titles SET category = 5 WHERE id BETWEEN 96 AND 109 OR id IN (83, 84)');
DB::Aowow()->query('UPDATE ?_titles SET category = 2 WHERE id BETWEEN 144 AND 156 OR id IN (63, 77, 79, 113, 123, 130, 131, 132, 176)');
DB::Aowow()->query('UPDATE ?_titles SET category = 6 WHERE id IN (46, 74, 75, 76, 124, 133, 134, 135, 137, 138, 155, 168)');
DB::Aowow()->query('UPDATE ?_titles SET category = 4 WHERE id IN (81, 125)');
DB::Aowow()->query('UPDATE ?_titles SET category = 3 WHERE id IN (53, 64, 120, 121, 122, 129, 139, 140, 141, 142) OR (id >= 158 AND category = 0)');
// update side
$questInfo = DB::World()->select($questQuery);
$sideUpd = DB::World()->selectCol('SELECT IF (title_A, title_A, title_H) AS ARRAY_KEY, BIT_OR(IF(title_A, 1, 2)) AS side FROM achievement_reward WHERE (title_A <> 0 AND title_H = 0) OR (title_H <> 0 AND title_A = 0) GROUP BY ARRAY_KEY HAVING side <> 3');
foreach ($questInfo as $tId => $data)
{
if ($data['holiday'])
DB::Aowow()->query('UPDATE ?_titles SET holidayId = ?d WHERE id = ?d', $data['holiday'], $tId);
$side = Util::sideByRaceMask($data['RequiredRaces']);
if ($side == 3)
continue;
if (!isset($sideUpd[$tId]))
$sideUpd[$tId] = $side;
else
$sideUpd[$tId] |= $side;
}
foreach ($sideUpd as $tId => $side)
if ($side != 3)
DB::Aowow()->query("UPDATE ?_titles SET side = ?d WHERE id = ?d", $side, $tId);
// update side - sourceless titles (maintain query order)
DB::Aowow()->query('UPDATE ?_titles SET side = 2 WHERE id <= 28 OR id IN (118, 119, 116, 117, 110, 127)');
DB::Aowow()->query('UPDATE ?_titles SET side = 1 WHERE id <= 14 OR id IN (111, 115, 112, 114, 126)');
// ! src12Ext pendant in source-script !
$doubles = DB::World()->selectCol('SELECT IF(title_A, title_A, title_H) AS ARRAY_KEY, GROUP_CONCAT(entry SEPARATOR " "), count(1) FROM achievement_reward WHERE title_A <> 0 OR title_H <> 0 GROUP BY ARRAY_KEY HAVING count(1) > 1');
foreach ($doubles as $tId => $acvIds)
DB::Aowow()->query('UPDATE ?_titles SET src12Ext = ?d WHERE id = ?d', explode(' ', $acvIds)[1], $tId);
return true;
}
?>

View File

@@ -0,0 +1,231 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
if (!CLI)
die('not in cli mode');
/* deps
* access_requirement
*/
$customData = array(
2257 => ['cuFlags' => 0, 'category' => 0, 'type' => 1], // deeprun tram => type: transit
3698 => ['expansion' => 1], // arenas
3702 => ['expansion' => 1],
3968 => ['expansion' => 1],
4378 => ['expansion' => 2],
4406 => ['expansion' => 2],
2597 => ['maxPlayer' => 40], // is 5 in battlemasterlist ... dafuque?
4710 => ['maxPlayer' => 40],
3456 => ['parentAreaId' => 65, 'parentX' => 87.3, 'parentY' => 51.1], // has no coordinates set in map.dbc
3849 => ['parentAreaId' => 3523, 'parentX' => 70.5, 'parentY' => 69.6],
3847 => ['parentAreaId' => 3523, 'parentX' => 71.7, 'parentY' => 55.1],
3848 => ['parentAreaId' => 3523, 'parentX' => 74.3, 'parentY' => 57.8],
3456 => ['parentAreaId' => 3523, 'parentX' => 73.5, 'parentY' => 63.7]
);
$reqDBC = ['worldmaptransforms', 'worldmaparea', 'map', 'mapdifficulty', 'areatable', 'lfgdungeons', 'battlemasterlist'];
function zones()
{
// base query
DB::Aowow()->query('
REPLACE INTO ?_zones
SELECT
a.id,
IFNULL(wmt.targetMapId, a.mapId), -- map
a.mapId, -- mapBak
a.areaTable, -- parentArea
IFNULL(wmt.targetMapId, -- g_zone_categories
IF(m.areaType = 1, 2,
IF(m.areaType = 2, 3,
IF(m.areaType = 4, 9,
IF(m.isBG = 1, 6,
IF(a.mapId = 571, 10,
IF(a.mapId = 530, 8, 0))))))),
a.flags,
IF(wma.id IS NULL AND m.areaType <> 4, ?d, 0), -- cuFlags,
IF(a.flags & 0x01000000, 5, -- g_zone_territories
IF(m.isBG = 1, 4,
IF(m.areaType = 4, 4,
IF(a.flags & 0x00000800, 3,
IF(a.factionGroupMask = 6, 2,
IF(a.factionGroupMask > 0, LOG2(a.factionGroupMask) - 1, 2)))))),
m.expansion,
IF(m.areaType = 0, 0, -- g_zone_instancetypes
IF(m.isBG = 1, 4,
IF(m.areaType = 4, 6,
IF(md.modeMask & 0xC, 8,
IF(md.minPl = 10 AND md.maxPL = 25, 7,
IF(m.areaType = 2, 3,
IF(m.areaType = 1 AND md.modeMask & 0x2, 5, 2))))))),
IF (md.minPl = 10 AND md.maxPl = 25, -2,
IFNULL(bm.maxPlayers, IFNULL(md.maxPl, m.maxPlayers))),
0, -- itemLevelN
0, -- itemLevelH
0, -- levelReq
IFNULL(lfgIni.levelLFG, 0), -- levelReqLFG
0, -- levelHeroic
IF(a.flags & 0x8, 1, -- levelMin
IFNULL(bm.minLevel,
IFNULL(lfgIni.levelMin,
IFNULL(lfgOpen.levelMin, 0)))),
IF(a.flags & 0x8, ?d, -- levelMax
IFNULL(bm.maxLevel,
IFNULL(lfgIni.levelMax,
IFNULL(lfgOpen.levelMax, 0)))),
"", -- attunements
"", -- heroic attunements
IFNULL(pa.areaId, 0),
IFNULL(pa.posX, 0),
IFNULL(pa.posY, 0),
IF(wma.id IS NULL OR m.areaType = 0 OR a.mapId IN (269, 560) OR a.areaTable, a.name_loc0, m.name_loc0),
IF(wma.id IS NULL OR m.areaType = 0 OR a.mapId IN (269, 560) OR a.areaTable, a.name_loc2, m.name_loc2),
IF(wma.id IS NULL OR m.areaType = 0 OR a.mapId IN (269, 560) OR a.areaTable, a.name_loc3, m.name_loc3),
IF(wma.id IS NULL OR m.areaType = 0 OR a.mapId IN (269, 560) OR a.areaTable, a.name_loc6, m.name_loc6),
IF(wma.id IS NULL OR m.areaType = 0 OR a.mapId IN (269, 560) OR a.areaTable, a.name_loc8, m.name_loc8)
FROM
dbc_areatable a
JOIN
dbc_map m ON a.mapId = m.id
LEFT JOIN (
SELECT mapId, BIT_OR(1 << difficulty) AS modeMask, MIN(nPlayer) AS minPl, MAX(nPlayer) AS maxPl FROM dbc_mapdifficulty GROUP BY mapId
) md ON md.mapId = a.mapId
LEFT JOIN
dbc_lfgdungeons lfgOpen ON a.mapId IN (0, 1, 530, 571) AND a.name_loc0 LIKE CONCAT("%", lfgOpen.name_loc0) AND lfgOpen.type = 4
LEFT JOIN (
SELECT
mapId, m.id, `left`, `right`, `top`, `bottom`,
IF((abs(((m.parentY - `right`) * 100 / (`left` - `right`)) - 50)) > abs(((m.parentX - `bottom`) * 100 / (`top` - `bottom`)) - 50),
(abs(((m.parentY - `right`) * 100 / (`left` - `right`)) - 50)),
(abs(((m.parentX - `bottom`) * 100 / (`top` - `bottom`)) - 50))) AS diff,
areaId, -- parentArea
100 - ROUND((m.parentY - `right`) * 100 / (`left` - `right`), 1) as posX,
100 - ROUND((m.parentX - `bottom`) * 100 / (`top` - `bottom`), 1) as posY
FROM
dbc_worldmaparea wma
JOIN
dbc_map m ON m.parentMapId = wma.mapid
WHERE
m.parentMapId IN (0, 1, 530, 571) AND areaId <> 0 AND
m.parentY BETWEEN `right` AND `left` AND
m.parentX BETWEEN bottom AND top
ORDER BY
diff ASC
) pa ON pa.id = m.id AND m.parentMapId > -1 AND m.parentX <> 0 AND m.parentY <> 0 AND m.parentMapId = pa.mapId AND m.parentY BETWEEN pa.`right` AND pa.`left` AND m.parentX BETWEEN pa.bottom AND pa.top
LEFT JOIN (
SELECT
mapId,
MIN(IF(targetLevelMin, targetLevelMin, levelMin)) AS levelMin,
MAX(IF(targetLevelMax, targetLevelMax, targetLevel)) AS levelMax,
MIN(IF(levelMin, levelMin, targetLevel)) AS levelLFG
FROM
dbc_lfgdungeons
WHERE
type NOT IN (4, 6) AND
groupId <> 11
GROUP BY
mapId
) lfgIni ON lfgIni.mapId = a.mapId
LEFT JOIN
dbc_battlemasterlist bm ON bm.mapId = a.mapId AND bm.moreMapId < 0
LEFT JOIN
dbc_worldmaparea wma ON wma.areaId = a.id
LEFT JOIN
dbc_worldmaptransforms wmt ON
wmt.targetMapId <> wmt.sourceMapId AND
wma.mapId = wmt.sourceMapId AND
wma.left < wmt.maxY AND
wma.right > wmt.minY AND
wma.top < wmt.maxX AND
wma.bottom > wmt.minX
GROUP BY
a.id
', CUSTOM_EXCLUDE_FOR_LISTVIEW, MAX_LEVEL);
// get requirements from world.access_requirement
$zoneReq = DB::World()->select('
SELECT
mapId AS ARRAY_KEY,
MIN(level_min) AS reqLevel,
MAX(IF(difficulty > 0, level_min, 0)) AS heroicLevel,
MAX(IF(difficulty = 0, item_level, 0)) AS reqItemLevelN,
MAX(IF(difficulty > 0, item_level, 0)) AS reqItemLevelH,
CONCAT_WS(" ", GROUP_CONCAT(IF(difficulty = 0 AND item, item, NULL) SEPARATOR " "), GROUP_CONCAT(IF(difficulty = 0 AND item2 AND item2 <> item, item2, NULL) SEPARATOR " ")) AS reqItemN,
CONCAT_WS(" ", GROUP_CONCAT(IF(difficulty > 0 AND item, item, NULL) SEPARATOR " "), GROUP_CONCAT(IF(difficulty > 0 AND item2 AND item2 <> item, item2, NULL) SEPARATOR " ")) AS reqItemH,
CONCAT_WS(" ", GROUP_CONCAT(IF(difficulty = 0 AND quest_done_A, quest_done_A, NULL) SEPARATOR " "), GROUP_CONCAT(IF(difficulty = 0 AND quest_done_H AND quest_done_H <> quest_done_A, quest_done_H, NULL) SEPARATOR " ")) AS reqQuestN,
CONCAT_WS(" ", GROUP_CONCAT(IF(difficulty > 0 AND quest_done_A, quest_done_A, NULL) SEPARATOR " "), GROUP_CONCAT(IF(difficulty > 0 AND quest_done_H AND quest_done_H <> quest_done_A, quest_done_H, NULL) SEPARATOR " ")) AS reqQuestH,
CONCAT_WS(" ", GROUP_CONCAT(IF(difficulty = 0 AND completed_achievement, completed_achievement, NULL) SEPARATOR " ")) AS reqAchievementN,
CONCAT_WS(" ", GROUP_CONCAT(IF(difficulty > 0 AND completed_achievement, completed_achievement, NULL) SEPARATOR " ")) AS reqAchievementH
FROM
access_requirement
GROUP BY
mapId
');
foreach ($zoneReq as $mapId => $req)
{
$update = ['levelReq' => $req['reqLevel']];
$aN = $aH = [];
if ($req['heroicLevel'])
$update['levelHeroic'] = $req['heroicLevel'];
if ($req['reqItemLevelN'])
$update['itemLevelReqN'] = $req['reqItemLevelN'];
if ($req['reqItemLevelH'] && $req['reqItemLevelH'] > $req['reqItemLevelN'])
$update['itemLevelReqH'] = $req['reqItemLevelH'];
if ($req['reqItemN'] && ($entries = explode(' ', $req['reqItemN'])))
foreach ($entries as $_)
$aN[TYPE_ITEM][] = $_;
if ($req['reqItemH'] && ($entries = explode(' ', $req['reqItemH'])))
if ($entries = array_diff($entries, @(array)$aN[TYPE_ITEM]))
foreach ($entries as $_)
$aH[TYPE_ITEM][] = $_;
if ($req['reqQuestN'] && ($entries = explode(' ', $req['reqQuestN'])))
foreach ($entries as $_)
$aN[TYPE_QUEST][] = $_;
if ($req['reqQuestH'] && ($entries = explode(' ', $req['reqQuestH'])))
if ($entries = array_diff($entries, @(array)$aN[TYPE_QUEST]))
foreach ($entries as $_)
$aH[TYPE_QUEST][] = $_;
if ($req['reqAchievementN'] && ($entries = explode(' ', $req['reqAchievementN'])))
foreach ($entries as $_)
$aN[TYPE_ACHIEVEMENT][] = $_;
if ($req['reqAchievementH'] && ($entries = explode(' ', $req['reqAchievementH'])))
if ($entries = array_diff($entries, @(array)$aN[TYPE_ACHIEVEMENT]))
foreach ($entries as $_)
$aH[TYPE_ACHIEVEMENT][] = $_;
if ($aN)
{
foreach ($aN as $type => $entries)
$aN[$type] = $type.':'.implode(' '.$type.':', $entries);
$update['attunementsN'] = implode(' ', $aN);
}
if ($aH)
{
foreach ($aH as $type => $entries)
$aH[$type] = $type.':'.implode(' '.$type.':', $entries);
$update['attunementsH'] = implode(' ', $aH);
}
DB::Aowow()->query('UPDATE ?_zones SET ?a WHERE mapId = ?d', $update, $mapId);
}
return true;
}
?>

View File

@@ -0,0 +1,31 @@
CREATE TABLE `aowow_sync` (
`table` VARCHAR(50) NOT NULL,
`entry` INT NOT NULL,
`action` TINYINT NOT NULL COMMENT '0:delete; 1:insert; 2:update'
) COLLATE='utf8_general_ci' ENGINE=MyISAM;
delimiter |
CREATE TRIGGER aowow_sync_<table>_delete BEFORE DELETE ON <table>
FOR EACH ROW
BEGIN
REPLACE INTO aowow_sync (`table`, `entry`, `action`) VALUES ('<table>', OLD.entry, 0);
END;
|
CREATE TRIGGER aowow_sync_<table>_insert AFTER INSERT ON <table>
FOR EACH ROW
BEGIN
REPLACE INTO aowow_sync (`table`, `entry`, `action`) VALUES ('<table>', NEW.entry, 1);
END;
|
CREATE TRIGGER aowow_sync_<table>_update AFTER UPDATE ON <table>
FOR EACH ROW
BEGIN
REPLACE INTO aowow_sync (`table`, `entry`, `action`) VALUES ('<table>', NEW.entry, 2);
END;
|
delimiter ;