diff --git a/.htaccess b/.htaccess
index f9875a4d..1628a258 100644
--- a/.htaccess
+++ b/.htaccess
@@ -25,7 +25,7 @@ RewriteEngine on
# RewriteBase /~user/localPath/ # enable if the rules do not work, when they should
# Mapper-Helper: If you cant provide maps for all locales, redirect the browser
-RewriteRule ^(.*/?)static/images/wow/maps/(frfr|dede|eses|ruru)/(.*)$ $1static/images/wow/maps/enus/$3 [NC]
+# RewriteRule ^(.*/?)static/images/wow/maps/(frfr|dede|eses|ruru)/(.*)$ $1static/images/wow/maps/enus/$3 [NC]
# accept flattened urls | NYI - need more work :x
# RewriteRule ^([a-z0-9\-]+)$ ?$1 [NC] # /items => ?items
diff --git a/includes/database.class.php b/includes/database.class.php
index 9124dcbe..23cc9db3 100644
--- a/includes/database.class.php
+++ b/includes/database.class.php
@@ -28,11 +28,10 @@ class DB
$options = &self::$optionsCache[$idx];
$interface = DbSimple_Generic::connect(self::createConnectSyntax($options));
- $interface->setErrorHandler(['DB', 'errorHandler']);
-
- if ($interface->error)
+ if (!$interface || $interface->error)
die('Failed to connect to database.');
+ $interface->setErrorHandler(['DB', 'errorHandler']);
$interface->query('SET NAMES ?', 'utf8');
if ($options['prefix'])
$interface->setIdentPrefix($options['prefix']);
diff --git a/includes/defines.php b/includes/defines.php
index 77a02974..b605ee60 100644
--- a/includes/defines.php
+++ b/includes/defines.php
@@ -219,9 +219,11 @@ define('SPELL_CU_PET_TALENT_TYPE2', 0x0020); // Cunning
define('SPELL_CU_GLYPH_MAJOR', 0x0040);
define('SPELL_CU_GLYPH_MINOR', 0x0080);
define('SPELL_CU_QUALITY_MASK', 0x0F00); // set if spell creates an item: (7 - Quality) << 8
-// define('SPELL_CU_EXCLUDE_CATEGORY_SEARCH', 0x1000); // migrate to CUSTOM_EXCLUDE_FOR_LISTVIEW
-define('SPELL_CU_FIRST_RANK', 0x2000); // used by filter
-define('SPELL_CU_LAST_RANK', 0x4000);
+define('SPELL_CU_FIRST_RANK', 0x1000); // used by filter
+define('SPELL_CU_LAST_RANK', 0x2000);
+
+define('ACHIEVEMENT_CU_FIRST_SERIES', 0x01);
+define('ACHIEVEMENT_CU_LAST_SERIES', 0x02);
define('OBJECT_CU_DESTRUCTABLE', 0x01);
define('OBJECT_CU_CHECK_LOS', 0x02);
diff --git a/includes/kernel.php b/includes/kernel.php
index df88e1bb..3cbcef25 100644
--- a/includes/kernel.php
+++ b/includes/kernel.php
@@ -96,7 +96,7 @@ foreach ($sets as $k => $v)
// handle occuring errors
-error_reporting($AoWoWconf && CFG_DEBUG ? (E_ALL & ~(E_DEPRECATED | E_USER_DEPRECATED | E_STRICT)) : 0);
+error_reporting(!empty($AoWoWconf['aowow']) && CFG_DEBUG ? (E_ALL & ~(E_DEPRECATED | E_USER_DEPRECATED | E_STRICT)) : 0);
$errHandled = false;
set_error_handler(function($errNo, $errStr, $errFile, $errLine) use (&$errHandled) {
$errName = 'unknown error'; // errors not in this list can not be handled by set_error_handler (as per documentation) or are ignored
@@ -126,15 +126,16 @@ set_error_handler(function($errNo, $errStr, $errFile, $errLine) use (&$errHandle
Util::addNote(U_GROUP_STAFF, $errName.' - '.$errStr.' @ '.$errFile. ':'.$errLine);
}
- DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
- AOWOW_REVISION, $errNo, $errFile, $errLine, CLI ? 'CLI' : $_SERVER['QUERY_STRING'], User::$groups, $errStr
- );
+ if (DB::isConnectable(DB_AOWOW))
+ DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
+ AOWOW_REVISION, $errNo, $errFile, $errLine, CLI ? 'CLI' : $_SERVER['QUERY_STRING'], User::$groups, $errStr
+ );
- return !(User::isInGroup(U_GROUP_STAFF) && defined('CFG_DEBUG') && CFG_DEBUG);
+ return !((User::isInGroup(U_GROUP_STAFF) && defined('CFG_DEBUG') && CFG_DEBUG) || CLI);
}, E_ALL & ~(E_DEPRECATED | E_USER_DEPRECATED | E_STRICT));
-$secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || ($AoWoWconf && CFG_FORCE_SSL);
+$secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || (!empty($AoWoWconf['aowow']) && CFG_FORCE_SSL);
if (defined('CFG_STATIC_HOST')) // points js to images & scripts
define('STATIC_URL', ($secure ? 'https://' : 'http://').CFG_STATIC_HOST);
@@ -148,7 +149,7 @@ if (!CLI)
session_set_cookie_params(15 * YEAR, '/', '', $secure, true);
session_cache_limiter('private');
session_start();
- if ($AoWoWconf && User::init())
+ if (!empty($AoWoWconf['aowow']) && User::init())
User::save(); // save user-variables in session
// todo: (low) - move to setup web-interface (when it begins its existance)
@@ -158,7 +159,7 @@ if (!CLI)
define('HOST_URL', ($secure ? 'https://' : 'http://').$host);
define('STATIC_URL', ($secure ? 'https://' : 'http://').$host.'/static');
- if (User::isInGroup(U_GROUP_ADMIN) && $AoWoWconf) // initial set
+ if (User::isInGroup(U_GROUP_ADMIN) && !empty($AoWoWconf['aowow'])) // initial set
{
DB::Aowow()->query('INSERT IGNORE INTO ?_config VALUES (?, ?, ?d, ?), (?, ?, ?d, ?)',
'site_host', $host, CON_FLAG_TYPE_STRING | CON_FLAG_PERSISTENT, 'default: '.$host.' - points js to executable files (automaticly set on first run)',
@@ -169,7 +170,7 @@ if (!CLI)
// hard-override locale for this call (should this be here..?)
// all strings attached..
- if ($AoWoWconf)
+ if (!empty($AoWoWconf['aowow']))
{
if (isset($_GET['locale']) && (CFG_LOCALES & (1 << (int)$_GET['locale'])))
User::useLocale($_GET['locale']);
@@ -185,10 +186,9 @@ if (!CLI)
Util::$wowheadLink = 'http://'.Util::$subDomains[User::$localeId].'.wowhead.com/'.$str;
}
-else if ($AoWoWconf)
+else if (!empty($AoWoWconf['aowow']))
Lang::load('enus');
-
$AoWoWconf = null; // empty auths
?>
diff --git a/includes/loot.class.php b/includes/loot.class.php
index 84c01c27..5e95d0bf 100644
--- a/includes/loot.class.php
+++ b/includes/loot.class.php
@@ -36,7 +36,7 @@ class Loot
LOOT_SKINNING, // npc (see its flags for mining, herbing, salvaging or actual skinning)
LOOT_FISHING, // zone
LOOT_GAMEOBJECT, // object (see its lockType for mining, herbing, fishing or generic looting)
- LOOT_MAIL, // quest
+ LOOT_MAIL, // quest + achievement
LOOT_SPELL // spell
);
@@ -330,23 +330,24 @@ class Loot
// [fileName, tabData, tabName, tabId, extraCols, hiddenCols, visibleCols]
$tabsFinal = array(
- ['item', [], '$LANG.tab_containedin', 'contained-in-item', [], [], []],
- ['item', [], '$LANG.tab_disenchantedfrom', 'disenchanted-from', [], [], []],
- ['item', [], '$LANG.tab_prospectedfrom', 'prospected-from', [], [], []],
- ['item', [], '$LANG.tab_milledfrom', 'milled-from', [], [], []],
- ['creature', [], '$LANG.tab_droppedby', 'dropped-by', [], [], []],
- ['creature', [], '$LANG.tab_pickpocketedfrom', 'pickpocketed-from', [], [], []],
- ['creature', [], '$LANG.tab_skinnedfrom', 'skinned-from', [], [], []],
- ['creature', [], '$LANG.tab_minedfromnpc', 'mined-from-npc', [], [], []],
- ['creature', [], '$LANG.tab_salvagedfrom', 'salvaged-from', [], [], []],
- ['creature', [], '$LANG.tab_gatheredfromnpc', 'gathered-from-npc', [], [], []],
- ['quest', [], '$LANG.tab_rewardfrom', 'reward-from-quest', [], [], []],
- ['zone', [], '$LANG.tab_fishedin', 'fished-in-zone', [], [], []],
- ['object', [], '$LANG.tab_containedin', 'contained-in-object', [], [], []],
- ['object', [], '$LANG.tab_minedfrom', 'mined-from-object', [], [], []],
- ['object', [], '$LANG.tab_gatheredfrom', 'gathered-from-object', [], [], []],
- ['object', [], '$LANG.tab_fishedin', 'fished-in-object', [], [], []],
- ['spell', [], '$LANG.tab_createdby', 'created-by', [], [], []]
+ ['item', [], '$LANG.tab_containedin', 'contained-in-item', [], [], []],
+ ['item', [], '$LANG.tab_disenchantedfrom', 'disenchanted-from', [], [], []],
+ ['item', [], '$LANG.tab_prospectedfrom', 'prospected-from', [], [], []],
+ ['item', [], '$LANG.tab_milledfrom', 'milled-from', [], [], []],
+ ['creature', [], '$LANG.tab_droppedby', 'dropped-by', [], [], []],
+ ['creature', [], '$LANG.tab_pickpocketedfrom', 'pickpocketed-from', [], [], []],
+ ['creature', [], '$LANG.tab_skinnedfrom', 'skinned-from', [], [], []],
+ ['creature', [], '$LANG.tab_minedfromnpc', 'mined-from-npc', [], [], []],
+ ['creature', [], '$LANG.tab_salvagedfrom', 'salvaged-from', [], [], []],
+ ['creature', [], '$LANG.tab_gatheredfromnpc', 'gathered-from-npc', [], [], []],
+ ['quest', [], '$LANG.tab_rewardfrom', 'reward-from-quest', [], [], []],
+ ['zone', [], '$LANG.tab_fishedin', 'fished-in-zone', [], [], []],
+ ['object', [], '$LANG.tab_containedin', 'contained-in-object', [], [], []],
+ ['object', [], '$LANG.tab_minedfrom', 'mined-from-object', [], [], []],
+ ['object', [], '$LANG.tab_gatheredfrom', 'gathered-from-object', [], [], []],
+ ['object', [], '$LANG.tab_fishedin', 'fished-in-object', [], [], []],
+ ['spell', [], '$LANG.tab_createdby', 'created-by', [], [], []],
+ ['achievement', [], '$LANG.tab_rewardfrom', 'reward-from-achievement', [], [], []]
);
$refResults = [];
$chanceMods = [];
@@ -382,7 +383,7 @@ class Loot
if ($ref['isGrouped'] && $ref['sumChance'] > 100)
Util::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: group with Item/Ref '.$ref['item'].' has '.number_format($ref['sumChance'], 2).'% total chance! Some items cannot drop!');
- if ($ref['isGrouped'] && $ref['sumChance'] == 100 && !$ref['chance'])
+ if ($ref['isGrouped'] && $ref['sumChance'] >= 100 && !$ref['chance'])
Util::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: Item/Ref '.$ref['item'].' with adaptive chance cannot drop. Group already at 100%!');
$chance = abs($ref['chance'] ?: (100 - $ref['sumChance']) / $ref['nZeroItems']) / 100;
@@ -482,11 +483,11 @@ class Loot
case LOOT_FISHING: $field = 'id'; $tabId = 11; break; // subAreas are currently ignored
case LOOT_GAMEOBJECT:
if (!$ids)
- break;
+ continue 2;
$srcObj = new GameObjectList(array(['lootId', $ids]));
if ($srcObj->error)
- break;
+ continue 2;
$srcData = $srcObj->getListviewData();
@@ -505,8 +506,9 @@ class Loot
if ($tabId != 15)
$tabsFinal[$tabId][6][] = 'skill';
}
- break;
+ continue 2;
case LOOT_MAIL:
+ // quest part
$conditions = array(['rewardChoiceItemId1', $this->entry], ['rewardChoiceItemId2', $this->entry], ['rewardChoiceItemId3', $this->entry], ['rewardChoiceItemId4', $this->entry], ['rewardChoiceItemId5', $this->entry],
['rewardChoiceItemId6', $this->entry], ['rewardItemId1', $this->entry], ['rewardItemId2', $this->entry], ['rewardItemId3', $this->entry], ['rewardItemId4', $this->entry],
'OR');
@@ -522,7 +524,25 @@ class Loot
foreach ($srcObj->iterate() as $_)
$tabsFinal[10][1][] = array_merge($srcData[$srcObj->id], empty($result[$srcObj->id]) ? ['percent' => -1] : $result[$srcObj->id]);
}
- break;
+
+ // achievement part
+ $conditions = array(['itemExtra', $this->entry]);
+ if ($ar = DB::World()->selectCol('SELECT entry FROM achievement_reward WHERE item = ?d{ OR mailTemplate IN (?a)}', $this->entry, $ids ?: DBSIMPLE_SKIP))
+ array_push($conditions, ['id', $ar], 'OR');
+
+ $srcObj = new AchievementList($conditions);
+ if (!$srcObj->error)
+ {
+ self::storeJSGlobals($srcObj->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS));
+ $srcData = $srcObj->getListviewData();
+
+ foreach ($srcObj->iterate() as $_)
+ $tabsFinal[17][1][] = array_merge($srcData[$srcObj->id], empty($result[$srcObj->id]) ? ['percent' => -1] : $result[$srcObj->id]);
+
+ $tabsFinal[17][5][] = 'rewards';
+ $tabsFinal[17][6][] = 'category';
+ }
+ continue 2;
case LOOT_SPELL:
$conditions = ['OR', ['effect1CreateItemId', $this->entry], ['effect2CreateItemId', $this->entry], ['effect3CreateItemId', $this->entry]];
if ($ids)
@@ -543,7 +563,7 @@ class Loot
foreach ($srcObj->iterate() as $_)
$tabsFinal[16][1][] = array_merge($srcData[$srcObj->id], empty($result[$srcObj->id]) ? ['percent' => -1] : $result[$srcObj->id]);
}
- break;
+ continue 2;
}
if (!$ids)
diff --git a/includes/types/achievement.class.php b/includes/types/achievement.class.php
index 59d20f59..3a2c1224 100644
--- a/includes/types/achievement.class.php
+++ b/includes/types/achievement.class.php
@@ -16,7 +16,7 @@ class AchievementList extends BaseType
protected $queryBase = 'SELECT `a`.*, `a`.`id` AS ARRAY_KEY FROM ?_achievement a';
protected $queryOpts = array(
'a' => [['si'], 'o' => 'orderInGroup ASC'],
- 'si' => ['j' => ['?_spellicon si ON si.id = a.iconId', true], 's' => ', si.iconString'],
+ 'si' => ['j' => ['?_icons si ON si.id = a.iconId', true], 's' => ', si.iconString'],
'ac' => ['j' => ['?_achievementcriteria AS `ac` ON `ac`.`refAchievementId` = `a`.`id`', true], 'g' => '`a`.`id`']
);
@@ -39,11 +39,28 @@ class AchievementList extends BaseType
foreach ($this->iterate() as $_id => &$_curTpl)
{
+ $_curTpl['rewards'] = [];
+
if (!empty($rewards[$_id]))
+ {
$_curTpl = array_merge($rewards[$_id], $_curTpl);
+ if ($rewards[$_id]['mailTemplate'])
+ {
+ // using class Loot creates an inifinite loop cirling between Loot, ItemList and SpellList or something
+ // $mailSrc = new Loot();
+ // $mailSrc->getByContainer(LOOT_MAIL, $rewards[$_id]['mailTemplate']);
+ // foreach ($mailSrc->iterate() as $loot)
+ // $_curTpl['rewards'][] = [TYPE_ITEM, $loot['id']];
+
+ // lets just assume for now, that mailRewards for achievements do not contain references
+ $mailRew = DB::World()->selectCol('SELECT Item FROM mail_loot_template WHERE Reference <= 0 AND entry = ?d', $rewards[$_id]['mailTemplate']);
+ foreach ($mailRew AS $mr)
+ $_curTpl['rewards'][] = [TYPE_ITEM, $mr];
+ }
+ }
+
//"rewards":[[11,137],[3,138]] [type, typeId]
- $_curTpl['rewards'] = [];
if (!empty($_curTpl['item']))
$_curTpl['rewards'][] = [TYPE_ITEM, $_curTpl['item']];
if (!empty($_curTpl['itemExtra']))
@@ -264,10 +281,10 @@ class AchievementListFilter extends Filter
protected $genericFilter = array( // misc (bool): _NUMERIC => useFloat; _STRING => localized; _FLAG => match Value; _BOOLEAN => stringSet
2 => [FILTER_CR_BOOLEAN, 'reward_loc0', true ], // givesreward
3 => [FILTER_CR_STRING, 'reward', true ], // rewardtext
- 7 => [FILTER_CR_BOOLEAN, 'series', ], // givesreward
+ 7 => [FILTER_CR_BOOLEAN, 'chainId', ], // partseries
9 => [FILTER_CR_NUMERIC, 'id', null, true], // id
10 => [FILTER_CR_STRING, 'si.iconString', ], // icon
- 18 => [FILTER_CR_STAFFFLAG, 'flags', ], // lastrank
+ 18 => [FILTER_CR_STAFFFLAG, 'flags', ], // flags
14 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_COMMENT ], // hascomments
15 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_SCREENSHOT ], // hasscreenshots
16 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_VIDEO ], // hasvideos
@@ -290,9 +307,15 @@ class AchievementListFilter extends Filter
case 4: // location [enum]
/* todo */ return [1]; // no plausible locations parsed yet
case 5: // first in series [yn]
- return $this->int2Bool($cr[1]) ? ['AND', ['series', 0, '!'], [['series', 0xFFFF0000, '&'], 0]] : [['series', 0xFFFF0000, '&'], 0, '!'];
+ if ($this->int2Bool($cr[1]))
+ return $cr[1] ? ['AND', ['chainId', 0, '!'], ['cuFlags', ACHIEVEMENT_CU_FIRST_SERIES, '&']] : ['AND', ['chainId', 0, '!'], [['cuFlags', ACHIEVEMENT_CU_FIRST_SERIES, '&'], 0]];
+
+ break;
case 6: // last in series [yn]
- return $this->int2Bool($cr[1]) ? ['AND', ['series', 0, '!'], [['series', 0xFFFF, '&'], 0]] : [['series', 0xFFFF, '&'], 0, '!'];
+ if ($this->int2Bool($cr[1]))
+ return $cr[1] ? ['AND', ['chainId', 0, '!'], ['cuFlags', ACHIEVEMENT_CU_LAST_SERIES, '&']] : ['AND', ['chainId', 0, '!'], [['cuFlags', ACHIEVEMENT_CU_LAST_SERIES, '&'], 0]];
+
+ break;
case 11: // Related Event [enum]
$_ = isset($this->enums[$cr[0]][$cr[1]]) ? $this->enums[$cr[0]][$cr[1]] : null;
if ($_ !== null)
diff --git a/includes/types/basetype.class.php b/includes/types/basetype.class.php
index 703d975c..fb17643b 100644
--- a/includes/types/basetype.class.php
+++ b/includes/types/basetype.class.php
@@ -221,7 +221,7 @@ abstract class BaseType
// insert additional selected fields
if ($s = array_column($this->queryOpts, 's'))
- $this->queryBase = str_replace(' FROM', implode('', $s).' FROM', $this->queryBase);
+ $this->queryBase = str_replace('ARRAY_KEY', 'ARRAY_KEY '.implode('', $s), $this->queryBase);
// append joins
if ($j = array_column($this->queryOpts, 'j'))
diff --git a/includes/types/creature.class.php b/includes/types/creature.class.php
index 544ffef1..eff8c617 100644
--- a/includes/types/creature.class.php
+++ b/includes/types/creature.class.php
@@ -17,7 +17,7 @@ class CreatureList extends BaseType
'ft' => ['j' => '?_factiontemplate ft ON ft.id = ct.faction', 's' => ', ft.A, ft.H, ft.factionId'],
'qse' => ['j' => ['?_quests_startend qse ON qse.type = 1 AND qse.typeId = ct.id', true], 's' => ', IF(min(qse.method) = 1 OR max(qse.method) = 3, 1, 0) AS startsQuests, IF(min(qse.method) = 2 OR max(qse.method) = 3, 1, 0) AS endsQuests', 'g' => 'ct.id'],
'qt' => ['j' => '?_quests qt ON qse.questId = qt.id'],
- 's' => ['j' => '?_spawns s ON s.type = 1 AND s.typeId = ct.id']
+ 's' => ['j' => ['?_spawns s ON s.type = 1 AND s.typeId = ct.id', true]]
);
public function __construct($conditions = [], $miscData = null)
diff --git a/includes/types/currency.class.php b/includes/types/currency.class.php
index ca373009..8b219883 100644
--- a/includes/types/currency.class.php
+++ b/includes/types/currency.class.php
@@ -9,7 +9,11 @@ class CurrencyList extends BaseType
public static $type = TYPE_CURRENCY;
public static $brickFile = 'currency';
- protected $queryBase = 'SELECT *, id AS ARRAY_KEY FROM ?_currencies c';
+ protected $queryBase = 'SELECT *, c.id AS ARRAY_KEY FROM ?_currencies c';
+ protected $queryOpts = array(
+ 'c' => [['ic']],
+ 'ic' => ['j' => ['?_icons ic ON ic.id = c.iconId', true], 's' => ', ic.iconString']
+ );
public function getListviewData()
{
diff --git a/includes/types/faction.class.php b/includes/types/faction.class.php
index f6d5881f..9c0ef6ba 100644
--- a/includes/types/faction.class.php
+++ b/includes/types/faction.class.php
@@ -47,13 +47,23 @@ class FactionList extends BaseType
foreach ($this->iterate() as $__)
{
$data[$this->id] = array(
- 'category' => $this->curTpl['cat'],
- 'category2' => $this->curTpl['cat2'],
'expansion' => $this->curTpl['expansion'],
'id' => $this->id,
'side' => $this->curTpl['side'],
'name' => $this->getField('name', true)
);
+
+ if ($this->curTpl['cat2'])
+ {
+ $data[$this->id]['category'] = $this->curTpl['cat'];
+ $data[$this->id]['category2'] = $this->curTpl['cat2'];
+ }
+ else
+ {
+ $data[$this->id]['category'] = $this->curTpl['cat2'];
+ $data[$this->id]['category2'] = $this->curTpl['cat'];
+ }
+
}
return $data;
diff --git a/includes/types/item.class.php b/includes/types/item.class.php
index 13c9eaf1..2f35f74b 100644
--- a/includes/types/item.class.php
+++ b/includes/types/item.class.php
@@ -23,11 +23,12 @@ class ItemList extends BaseType
private $vendors = [];
private $jsGlobals = []; // getExtendedCost creates some and has no access to template
- protected $queryBase = 'SELECT i.*, `is`.*, i.id AS id, i.id AS ARRAY_KEY FROM ?_items i';
+ protected $queryBase = 'SELECT i.*, i.id AS ARRAY_KEY, i.id AS id FROM ?_items i';
protected $queryOpts = array(
- 'i' => [['is', 'src'], 'o' => 'i.quality DESC, i.itemLevel DESC'],
- 'is' => ['j' => ['?_item_stats AS `is` ON `is`.`id` = `i`.`id`', true]],
- 's' => ['j' => ['?_spell AS `s` ON s.effect1CreateItemId = i.id', true], 'g' => 'i.id'],
+ 'i' => [['is', 'src', 'ic'], 'o' => 'i.quality DESC, i.itemLevel DESC'],
+ 'ic' => ['j' => ['?_icons ic ON ic.id = -i.displayId', true], 's' => ', ic.iconString'],
+ 'is' => ['j' => ['?_item_stats `is` ON `is`.`id` = `i`.`id`', true], 's' => ', `is`.*'],
+ 's' => ['j' => ['?_spell `s` ON s.effect1CreateItemId = i.id', true], 'g' => 'i.id'],
'src' => ['j' => ['?_source src ON type = 3 AND typeId = i.id', true], 's' => ', moreType, moreTypeId, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10, src11, src12, src13, src14, src15, src16, src17, src18, src19, src20, src21, src22, src23, src24']
);
@@ -79,8 +80,11 @@ class ItemList extends BaseType
// todo (med): information will get lost if one vendor sells one item multiple times with different costs (e.g. for item 54637)
// wowhead seems to have had the same issues
- public function getExtendedCost($filter = [], &$reqRating = 0)
+ public function getExtendedCost($filter = [], &$reqRating = [])
{
+ if ($this->error)
+ return [];
+
if (empty($this->vendors))
{
$itemz = DB::World()->select('
@@ -110,9 +114,10 @@ class ItemList extends BaseType
$costs = $xCosts[$vInfo['extendedCost']];
$data = array(
- 'stock' => $vInfo['maxcount'] ?: -1,
- 'event' => $vInfo['eventId'],
- 'reqRtg' => $costs ? $costs['reqPersonalRating'] : 0
+ 'stock' => $vInfo['maxcount'] ?: -1,
+ 'event' => $vInfo['eventId'],
+ 'reqRating' => $costs ? $costs['reqPersonalRating'] : 0,
+ 'reqBracket' => $costs ? $costs['reqArenaSlot'] : 0
);
// hardcode arena(103) & honor(104)
@@ -197,7 +202,7 @@ class ItemList extends BaseType
foreach ($result as $itemId => &$data)
{
- $reqRating = 0;
+ $reqRating = [];
foreach ($data as $npcId => $costs)
{
if ($tok || $cur) // bought with specific token or currency
@@ -218,13 +223,12 @@ class ItemList extends BaseType
// reqRating ins't really a cost .. so pass it by ref instead of return
// use highest total value
- // note: how to distinguish between brackets .. or team/pers-rating?
- if (isset($data[$npcId]) && ($reqRating < $costs['reqRtg']))
- $reqRating = $costs['reqRtg'];
+ if (isset($data[$npcId]) && $costs['reqRating'] && (!$reqRating || $reqRating[0] < $costs['reqRating']))
+ $reqRating = [$costs['reqRating'], $costs['reqBracket']];
}
if ($reqRating)
- $data['reqRating'] = $reqRating;
+ $data['reqRating'] = $reqRating[0];
if (empty($data))
unset($result[$itemId]);
@@ -316,7 +320,7 @@ class ItemList extends BaseType
if ($cost['event'])
{
$this->jsGlobals[TYPE_WORLDEVENT][$cost['event']] = $cost['event'];
- $row['condition'][0][$this->typeId][] = [[CND_ACTIVE_EVENT, $cost['event']]];
+ $row['condition'][0][$this->id][] = [[CND_ACTIVE_EVENT, $cost['event']]];
}
if ($currency || $tokens) // fill idx:3 if required
@@ -382,6 +386,8 @@ class ItemList extends BaseType
$data[$this->id]['source'] = array_keys($this->sources[$this->id]);
if ($this->curTpl['moreType'] && $this->curTpl['moreTypeId'] && !empty($this->sourceMore[$this->curTpl['moreType']][$this->curTpl['moreTypeId']]))
$data[$this->id]['sourcemore'] = [$this->sourceMore[$this->curTpl['moreType']][$this->curTpl['moreTypeId']]];
+ else if (!empty($this->sources[$this->id][3]))
+ $data[$this->id]['sourcemore'] = [['p' => $this->sources[$this->id][3][0]]];
}
}
@@ -805,7 +811,7 @@ class ItemList extends BaseType
// required arena team rating / personal rating / todo (low): sort out what kind of rating
if (!empty($this->getExtendedCost([], $reqRating)[$this->id]) && $reqRating)
- $x .= sprintf(Lang::item('reqRating'), $reqRating).'
';
+ $x .= sprintf(Lang::item('reqRating', $reqRating[1]), $reqRating[0]).'
';
// item level
if (in_array($_class, [ITEM_CLASS_ARMOR, ITEM_CLASS_WEAPON]))
@@ -895,75 +901,77 @@ class ItemList extends BaseType
// Item Set
$pieces = [];
- $condition = ['OR', ['item1', $this->id], ['item2', $this->id], ['item3', $this->id], ['item4', $this->id], ['item5', $this->id], ['item6', $this->id], ['item7', $this->id], ['item8', $this->id], ['item9', $this->id], ['item10', $this->id]];
- $itemset = new ItemsetList($condition);
-
- if (!$itemset->error)
+ if ($setId = $this->getField('itemset'))
{
- $pieces = DB::Aowow()->select('
- SELECT b.id AS ARRAY_KEY, b.name_loc0, b.name_loc2, b.name_loc3, b.name_loc6, b.name_loc8, GROUP_CONCAT(a.id SEPARATOR \':\') AS equiv
- FROM ?_items a, ?_items b
- WHERE a.slotBak = b.slotBak AND a.itemset = b.itemset AND b.id IN (?a)
- GROUP BY b.id;',
- array_keys($itemset->pieceToSet)
- );
-
- foreach ($pieces as $k => &$p)
- $p = ''.Util::localizedString($p, 'name').'';
-
- $xSet = '
'.$itemset->getField('name', true).' (0/'.count($pieces).')';
-
- if ($skId = $itemset->getField('skillId')) // bonus requires skill to activate
+ // while Ids can technically be used multiple times the only difference in data are the items used. So it doesn't matter what we get
+ $itemset = new ItemsetList(array(['id', $setId]));
+ if (!$itemset->error && $itemset->pieceToSet)
{
- $xSet .= '
'.sprintf(Lang::game('requires'), ''.SkillList::getName($skId).'');
+ $pieces = DB::Aowow()->select('
+ SELECT b.id AS ARRAY_KEY, b.name_loc0, b.name_loc2, b.name_loc3, b.name_loc6, b.name_loc8, GROUP_CONCAT(a.id SEPARATOR \':\') AS equiv
+ FROM ?_items a, ?_items b
+ WHERE a.slotBak = b.slotBak AND a.itemset = b.itemset AND b.id IN (?a)
+ GROUP BY b.id;',
+ array_keys($itemset->pieceToSet)
+ );
- if ($_ = $itemset->getField('skillLevel'))
- $xSet .= ' ('.$_.')';
+ foreach ($pieces as $k => &$p)
+ $p = ''.Util::localizedString($p, 'name').'';
- $xSet .= '
';
- }
+ $xSet = '
'.$itemset->getField('name', true).' (0/'.count($pieces).')';
- // list pieces
- $xSet .= '
'.implode('
', $pieces).'
';
-
- // get bonuses
- $setSpellsAndIdx = [];
- for ($j = 1; $j <= 8; $j++)
- if ($_ = $itemset->getField('spell'.$j))
- $setSpellsAndIdx[$_] = $j;
-
- $setSpells = [];
- if ($setSpellsAndIdx)
- {
- $boni = new SpellList(array(['s.id', array_keys($setSpellsAndIdx)]));
- foreach ($boni->iterate() as $__)
+ if ($skId = $itemset->getField('skillId')) // bonus requires skill to activate
{
- $setSpells[] = array(
- 'tooltip' => $boni->parseText('description', $_reqLvl > 1 ? $_reqLvl : MAX_LEVEL, false, $causesScaling)[0],
- 'entry' => $itemset->getField('spell'.$setSpellsAndIdx[$boni->id]),
- 'bonus' => $itemset->getField('bonus'.$setSpellsAndIdx[$boni->id])
- );
- }
- }
+ $xSet .= '
'.sprintf(Lang::game('requires'), ''.SkillList::getName($skId).'');
- // sort and list bonuses
- $xSet .= '';
- for ($i = 0; $i < count($setSpells); $i++)
- {
- for ($j = $i; $j < count($setSpells); $j++)
- {
- if ($setSpells[$j]['bonus'] >= $setSpells[$i]['bonus'])
- continue;
+ if ($_ = $itemset->getField('skillLevel'))
+ $xSet .= ' ('.$_.')';
- $tmp = $setSpells[$i];
- $setSpells[$i] = $setSpells[$j];
- $setSpells[$j] = $tmp;
- }
- $xSet .= '('.$setSpells[$i]['bonus'].') '.Lang::item('set').': '.$setSpells[$i]['tooltip'].'';
- if ($i < count($setSpells) - 1)
$xSet .= '
';
+ }
+
+ // list pieces
+ $xSet .= ''.implode('
', $pieces).'
';
+
+ // get bonuses
+ $setSpellsAndIdx = [];
+ for ($j = 1; $j <= 8; $j++)
+ if ($_ = $itemset->getField('spell'.$j))
+ $setSpellsAndIdx[$_] = $j;
+
+ $setSpells = [];
+ if ($setSpellsAndIdx)
+ {
+ $boni = new SpellList(array(['s.id', array_keys($setSpellsAndIdx)]));
+ foreach ($boni->iterate() as $__)
+ {
+ $setSpells[] = array(
+ 'tooltip' => $boni->parseText('description', $_reqLvl > 1 ? $_reqLvl : MAX_LEVEL, false, $causesScaling)[0],
+ 'entry' => $itemset->getField('spell'.$setSpellsAndIdx[$boni->id]),
+ 'bonus' => $itemset->getField('bonus'.$setSpellsAndIdx[$boni->id])
+ );
+ }
+ }
+
+ // sort and list bonuses
+ $xSet .= '';
+ for ($i = 0; $i < count($setSpells); $i++)
+ {
+ for ($j = $i; $j < count($setSpells); $j++)
+ {
+ if ($setSpells[$j]['bonus'] >= $setSpells[$i]['bonus'])
+ continue;
+
+ $tmp = $setSpells[$i];
+ $setSpells[$i] = $setSpells[$j];
+ $setSpells[$j] = $tmp;
+ }
+ $xSet .= '('.$setSpells[$i]['bonus'].') '.Lang::item('set').': '.$setSpells[$i]['tooltip'].'';
+ if ($i < count($setSpells) - 1)
+ $xSet .= '
';
+ }
+ $xSet .= '';
}
- $xSet .= '';
}
// recipes, vanity pets, mounts
diff --git a/includes/types/skill.class.php b/includes/types/skill.class.php
index fdd6149d..2b2d0865 100644
--- a/includes/types/skill.class.php
+++ b/includes/types/skill.class.php
@@ -6,10 +6,14 @@ if (!defined('AOWOW_REVISION'))
class SkillList extends BaseType
{
- public static $type = TYPE_SKILL;
- public static $brickFile = 'skill';
+ public static $type = TYPE_SKILL;
+ public static $brickFile = 'skill';
- protected $queryBase = 'SELECT *, id AS ARRAY_KEY FROM ?_skillline sl';
+ protected $queryBase = 'SELECT *, sl.id AS ARRAY_KEY FROM ?_skillline sl';
+ protected $queryOpts = array(
+ 'sl' => [['si']],
+ 'si' => ['j' => '?_icons si ON si.id = sl.iconId', 's' => ', si.iconString'],
+ );
public function __construct($conditions = [])
{
diff --git a/includes/types/spell.class.php b/includes/types/spell.class.php
index 0e94ff8c..5c49e1bb 100644
--- a/includes/types/spell.class.php
+++ b/includes/types/spell.class.php
@@ -34,7 +34,7 @@ class SpellList extends BaseType
'damage' => [ 0, 2, 3, 9, 62 ], // , Dummy, School Damage, Health Leech, Power Burn
'itemCreate' => [24, 34, 59, 66, 157 ], // createItem, changeItem, randomItem, createManaGem, createItem2
'trigger' => [ 3, 32, 64, 101, 142, 148, 151, 152, 155, 160, 164], // dummy, trigger missile, trigger spell, feed pet, force cast, force cast with value, unk, trigger spell 2, unk, dualwield 2H, unk, remove aura
- 'teach' => [36, 57, 133 ] // learn spell, learn pet spell, unlearn specialization
+ 'teach' => [36, 57, /*133*/ ] // learn spell, learn pet spell, /*unlearn specialization*/
);
public static $auras = array(
'heal' => [ 4, 8, 62, 69, 97, 226 ], // Dummy, Periodic Heal, Periodic Health Funnel, School Absorb, Mana Shield, Periodic Dummy
@@ -52,7 +52,9 @@ class SpellList extends BaseType
protected $queryBase = 'SELECT s.*, s.id AS ARRAY_KEY FROM ?_spell s';
protected $queryOpts = array(
- 's' => [['src', 'sr']], // 6: TYPE_SPELL
+ 's' => [['src', 'sr', 'si', 'si', 'sia']], // 6: TYPE_SPELL
+ 'si' => ['j' => ['?_icons si ON si.id = s.iconId', true], 's' => ', IFNULL (si.iconString, "inv_misc_questionmark") AS iconString'],
+ 'sia' => ['j' => ['?_icons sia ON sia.id = s.iconIdAlt', true], 's' => ', sia.iconString AS iconStringAlt'],
'sr' => ['j' => ['?_spellrange sr ON sr.id = s.rangeId'], 's' => ', sr.rangeMinHostile, sr.rangeMinFriend, sr.rangeMaxHostile, sr.rangeMaxFriend, sr.name_loc0 AS rangeText_loc0, sr.name_loc2 AS rangeText_loc2, sr.name_loc3 AS rangeText_loc3, sr.name_loc6 AS rangeText_loc6, sr.name_loc8 AS rangeText_loc8'],
'src' => ['j' => ['?_source src ON type = 6 AND typeId = s.id', true], 's' => ', src1, src2, src3, src4, src5, src6, src7, src8, src9, src10, src11, src12, src13, src14, src15, src16, src17, src18, src19, src20, src21, src22, src23, src24']
);
@@ -136,7 +138,7 @@ class SpellList extends BaseType
}
// end static use
- // required for itemSet-bonuses and socket-bonuses
+ // required for item-comparison
public function getStatGain()
{
$data = [];
@@ -154,8 +156,8 @@ class SpellList extends BaseType
// Enchant Item Permanent (53) / Temporary (54)
if (in_array($this->curTpl['effect'.$i.'Id'], [53, 54]))
{
- if ($mv)
- Util::arraySumByKey($stats, Util::parseItemEnchantment($mv, true));
+ if ($mv && ($_ = Util::parseItemEnchantment($mv, true)))
+ Util::arraySumByKey($stats, $_[$mv]);
continue;
}
@@ -523,14 +525,9 @@ class SpellList extends BaseType
$str = '';
// check for custom PowerDisplay
- $pt = $this->curTpl['powerDisplayString'] ? $this->curTpl['powerDisplayString'] : $this->curTpl['powerType'];
+ $pt = $this->curTpl['powerType'];
- // power cost: pct over static
- if ($this->curTpl['powerCostPercent'] > 0)
- $str .= $this->curTpl['powerCostPercent']."% ".sprintf(Lang::spell('pctCostOf'), strtolower(Lang::spell('powerTypes', $pt)));
- else if ($this->curTpl['powerCost'] > 0 || $this->curTpl['powerPerSecond'] > 0 || $this->curTpl['powerCostPerLevel'] > 0)
- $str .= ($pt == POWER_RAGE || $pt == POWER_RUNIC_POWER ? $this->curTpl['powerCost'] / 10 : $this->curTpl['powerCost']).' '.Util::ucFirst(Lang::spell('powerTypes', $pt));
- else if ($rCost = ($this->curTpl['powerCostRunes'] & 0x333))
+ if ($pt == POWER_RUNE && ($rCost = ($this->curTpl['powerCostRunes'] & 0x333)))
{ // Blood 2|1 - Unholy 2|1 - Frost 2|1
$runes = [];
if ($_ = (($rCost & 0x300) >> 8))
@@ -542,6 +539,10 @@ class SpellList extends BaseType
$str .= implode(', ', $runes);
}
+ else if ($this->curTpl['powerCostPercent'] > 0) // power cost: pct over static
+ $str .= $this->curTpl['powerCostPercent']."% ".sprintf(Lang::spell('pctCostOf'), strtolower(Lang::spell('powerTypes', $pt)));
+ else if ($this->curTpl['powerCost'] > 0 || $this->curTpl['powerPerSecond'] > 0 || $this->curTpl['powerCostPerLevel'] > 0)
+ $str .= ($pt == POWER_RAGE || $pt == POWER_RUNIC_POWER ? $this->curTpl['powerCost'] / 10 : $this->curTpl['powerCost']).' '.Util::ucFirst(Lang::spell('powerTypes', $pt));
// append periodic cost
if ($this->curTpl['powerPerSecond'] > 0)
@@ -556,7 +557,7 @@ class SpellList extends BaseType
public function createCastTimeForCurrent($short = true, $noInstant = true)
{
- if ($this->curTpl['interruptFlagsChannel'])
+ if ($this->isChanneledSpell())
return Lang::spell('channeled');
else if ($this->curTpl['castTime'] > 0)
return $short ? sprintf(Lang::spell('castIn'), $this->curTpl['castTime'] / 1000) : Util::formatTime($this->curTpl['castTime']);
@@ -683,10 +684,8 @@ class SpellList extends BaseType
{
// see Traits in javascript locales
- // if (character level is set manually (profiler only))
- // $pl = $PL = $this->charLevel;
-
$PlayerName = Lang::main('name');
+ $pl = $PL = /* playerLevel set manually ? $this->charLevel : */ $this->interactive ? sprintf(Util::$dfnString, 'LANG.level', Lang::game('level')) : Lang::game('level');
$ap = $AP = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.atkpwr[0]', Lang::spell('traitShort', 'atkpwr')) : Lang::spell('traitShort', 'atkpwr');
$rap = $RAP = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.rgdatkpwr[0]', Lang::spell('traitShort', 'rgdatkpwr')) : Lang::spell('traitShort', 'rgdatkpwr');
$sp = $SP = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.splpwr[0]', Lang::spell('traitShort', 'splpwr')) : Lang::spell('traitShort', 'splpwr');
@@ -698,6 +697,17 @@ class SpellList extends BaseType
$sps = $SPS = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.shasplpwr[0]', Lang::spell('traitShort', 'shasplpwr')) : Lang::spell('traitShort', 'shasplpwr');
$bh = $BH = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.splheal[0]', Lang::spell('traitShort', 'splheal')) : Lang::spell('traitShort', 'splheal');
+ // only 'ron test spell', guess its %-dmg mod; no idea what bc2 might be
+ $pa = '<$PctArcane>'; // %arcane
+ $pfi = '<$PctFire>'; // %fire
+ $pfr = '<$PctFrost>'; // %frost
+ $ph = '<$PctHoly>'; // %holy
+ $pn = '<$PctNature>'; // %nature
+ $ps = '<$PctShadow>'; // %shadow
+ $pbh = '<$PctHeal>'; // %heal
+ $pbhd = '<$PctHealDone>'; // %heal done
+ $bc2 = '<$bc2>'; // bc2
+
$HND = $hnd = $this->interactive ? sprintf(Util::$dfnString, '[Hands required by weapon]', 'HND') : 'HND'; // todo (med): localize this one
$MWS = $mws = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.mlespeed[0]', 'MWS') : 'MWS';
$mw = $this->interactive ? sprintf(Util::$dfnString, 'LANG.traits.dmgmin1[0]', 'mw') : 'mw';
@@ -715,17 +725,25 @@ class SpellList extends BaseType
$max = $MAX = function($a, $b) { return max($a, $b); };
$min = $MIN = function($a, $b) { return min($a, $b); };
- if (preg_match_all('/\$[a-z]+\b/i', $formula, $vars))
+ if (preg_match_all('/\$\w+\b/i', $formula, $vars))
{
+
$evalable = true;
foreach ($vars[0] as $var) // oh lord, forgive me this sin .. but is_callable seems to bug out and function_exists doesn't find lambda-functions >.<
{
- $eval = eval('return @'.$var.';'); // attention: error suppression active here
- if (getType($eval) == 'object')
- continue;
- else if (is_numeric($eval))
- continue;
+ $var = substr($var, 1);
+
+ if (isset($$var))
+ {
+ $eval = eval('return @$'.$var.';'); // attention: error suppression active here (will be logged anyway)
+ if (getType($eval) == 'object')
+ continue;
+ else if (is_numeric($eval))
+ continue;
+ }
+ else
+ $$var = '';
$evalable = false;
break;
@@ -1456,8 +1474,9 @@ Lasts 5 min. $?$gte($pl,68)[][Cannot be used on items level 138 and higher.]
$x .= ''.$this->getField('name', true).' | ';
// dispelType (if applicable)
- if ($dispel = Lang::game('dt', $this->curTpl['dispelType']))
- $x .= ''.$dispel.' | ';
+ if ($this->curTpl['dispelType'])
+ if ($dispel = Lang::game('dt', $this->curTpl['dispelType']))
+ $x .= ''.$dispel.' | ';
$x .= '';
@@ -1672,8 +1691,16 @@ Lasts 5 min. $?$gte($pl,68)[][Cannot be used on items level 138 and higher.]
$grn = (int)(($ylw + $gry) / 2);
$org = $this->curTpl['learnedAt'];
- if ($ylw > 1)
- return [$org, $ylw, $grn, $gry];
+ if (($org && $ylw < $org) || $ylw >= $gry)
+ $ylw = 0;
+
+ if (($org && $grn < $org) || $grn >= $gry)
+ $grn = 0;
+
+ if (($grn && $org >= $grn) || $org >= $gry)
+ $org = 0;
+
+ return $gry > 1 ? [$org, $ylw, $grn, $gry] : null;
}
public function getListviewData($addInfoMask = 0x0)
@@ -1691,7 +1718,7 @@ Lasts 5 min. $?$gte($pl,68)[][Cannot be used on items level 138 and higher.]
$data[$this->id] = array(
'id' => $this->id,
'name' => ($quality ?: '@').$this->getField('name', true),
- 'icon' => $this->curTpl['iconStringAlt'] ? $this->curTpl['iconStringAlt'] : $this->curTpl['iconString'],
+ 'icon' => $this->curTpl['iconStringAlt'] ?: $this->curTpl['iconString'],
'level' => $talent ? $this->curTpl['talentLevel'] : $this->curTpl['spellLevel'],
'school' => $this->curTpl['schoolMask'],
'cat' => $this->curTpl['typeCat'],
@@ -1703,8 +1730,12 @@ Lasts 5 min. $?$gte($pl,68)[][Cannot be used on items level 138 and higher.]
);
// Sources
- if (!empty($this->sources[$this->id]) && ($s = $this->sources[$this->id]))
- $data[$this->id]['source'] = array_keys($s);
+ if (!empty($this->sources[$this->id]))
+ {
+ $data[$this->id]['source'] = array_keys($this->sources[$this->id]);
+ if (!empty($this->sources[$this->id][3]))
+ $data[$this->id]['sourcemore'] = [['p' => $this->sources[$this->id][3][0]]];
+ }
// Proficiencies
if ($this->curTpl['typeCat'] == -11)
@@ -1937,9 +1968,9 @@ class SpellListFilter extends Filter
5 => [FILTER_CR_BOOLEAN, 'reqSpellId' ], // requiresprofspec
10 => [FILTER_CR_FLAG, 'cuFlags', SPELL_CU_FIRST_RANK ], // firstrank
12 => [FILTER_CR_FLAG, 'cuFlags', SPELL_CU_LAST_RANK ], // lastrank
- 13 => [FILTER_CR_NUMERIC, 'rankId', ], // rankno
+ 13 => [FILTER_CR_NUMERIC, 'rankNo', ], // rankno
14 => [FILTER_CR_NUMERIC, 'id', null, true], // id
- 15 => [FILTER_CR_STRING, 'iconString', ], // icon
+ 15 => [FILTER_CR_STRING, 'si.iconString', ], // icon
19 => [FILTER_CR_FLAG, 'attributes0', 0x80000 ], // scaling
25 => [FILTER_CR_BOOLEAN, 'skillLevelYellow' ], // rewardsskillups
11 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_COMMENT ], // hascomments
diff --git a/includes/types/title.class.php b/includes/types/title.class.php
index 4efa39bc..ef979af3 100644
--- a/includes/types/title.class.php
+++ b/includes/types/title.class.php
@@ -16,7 +16,7 @@ class TitleList extends BaseType
protected $queryBase = 'SELECT t.*, id AS ARRAY_KEY FROM ?_titles t';
protected $queryOpts = array(
't' => [['src']], // 11: TYPE_TITLE
- 'src' => ['j' => ['?_source src ON type = 11 AND typeId = t.id', true], 's' => ', src3, moreType, moreTypeId']
+ 'src' => ['j' => ['?_source src ON type = 11 AND typeId = t.id', true], 's' => ', src13, moreType, moreTypeId']
);
public function __construct($conditions = [])
@@ -31,8 +31,8 @@ class TitleList extends BaseType
$this->sources[$this->id][12][] = $_curTpl['moreTypeId'];
else if ($_curTpl['moreType'] == TYPE_QUEST)
$this->sources[$this->id][4][] = $_curTpl['moreTypeId'];
- else if ($_curTpl['src3'])
- $this->sources[$this->id][3][] = $_curTpl['src3'];
+ else if ($_curTpl['src13'])
+ $this->sources[$this->id][13][] = $_curTpl['src13'];
// titles display up to two achievements at once
if ($_curTpl['src12Ext'])
@@ -60,7 +60,7 @@ class TitleList extends BaseType
$data[$this->id] = array(
'id' => $this->id,
'name' => $this->getField('male', true),
- 'namefemale' => $this->getField('namefemale', true),
+ 'namefemale' => $this->getField('female', true),
'side' => $this->curTpl['side'],
'gender' => $this->curTpl['gender'],
'expansion' => $this->curTpl['expansion'],
diff --git a/includes/types/zone.class.php b/includes/types/zone.class.php
index 3a1c3009..52dea10f 100644
--- a/includes/types/zone.class.php
+++ b/includes/types/zone.class.php
@@ -6,11 +6,50 @@ if (!defined('AOWOW_REVISION'))
class ZoneList extends BaseType
{
+ use listviewHelper;
+
public static $type = TYPE_ZONE;
public static $brickFile = 'zone';
protected $queryBase = 'SELECT *, id AS ARRAY_KEY FROM ?_zones z';
+ public function __construct($conditions = [], $miscData = null)
+ {
+ parent::__construct($conditions, $miscData);
+
+ foreach ($this->iterate() as &$_curTpl)
+ {
+ // unpack attunements
+ $_curTpl['attunes'] = [];
+
+ if ($_curTpl['attunementsN'])
+ {
+ foreach (explode(' ', $_curTpl['attunementsN']) as $req)
+ {
+ $req = explode(':', $req);
+ if (!isset($_curTpl['attunes'][$req[0]]))
+ $_curTpl['attunes'][$req[0]] = [$req[1]];
+ else
+ $_curTpl['attunes'][$req[0]][] = $req[1];
+ }
+ }
+ if ($_curTpl['attunementsH'])
+ {
+ foreach (explode(' ', $_curTpl['attunementsH']) as $req)
+ {
+ $req = explode(':', $req);
+ if (!isset($_curTpl['attunes'][$req[0]]))
+ $_curTpl['attunes'][$req[0]] = [-$req[1]];
+ else
+ $_curTpl['attunes'][$req[0]][] = -$req[1];
+ }
+ }
+
+ unset($_curTpl['attunementsN']);
+ unset($_curTpl['attunementsH']);
+ }
+ }
+
// use if you JUST need the name
public static function getName($id)
{
diff --git a/includes/utilities.php b/includes/utilities.php
index ec0a5a34..17897e30 100644
--- a/includes/utilities.php
+++ b/includes/utilities.php
@@ -195,10 +195,6 @@ class Util
null, 4, 10, 9, 8, 6, 15, 11, 3, 5, null, 7
);
- public static $itemDurabilityQualityMod = array( // from DurabilityQuality.dbc
- null, 1.0, 0.6, 1.0, 0.8, 1.0, 1.0, 1.2, 1.25, 1.44, 2.5, 1.728, 3.0, 0.0, 0.0, 1.2, 1.25
- );
-
// todo: translate and move to Lang
public static $spellEffectStrings = array(
0 => 'None',
@@ -1026,31 +1022,21 @@ class Util
public static function localizedString($data, $field, $silent = false)
{
- $sqlLocales = ['EN', 2 => 'FR', 3 => 'DE', 6 => 'ES', 8 => 'RU'];
-
// default back to enUS if localization unavailable
// default case: selected locale available
if (!empty($data[$field.'_loc'.User::$localeId]))
return $data[$field.'_loc'.User::$localeId];
- // dbc-case
- else if (!empty($data[$field.$sqlLocales[User::$localeId]]))
- return $data[$field.$sqlLocales[User::$localeId]];
-
// locale not enUS; aowow-type localization available; add brackets if not silent
else if (User::$localeId != LOCALE_EN && isset($data[$field.'_loc0']) && !empty($data[$field.'_loc0']))
return $silent ? $data[$field.'_loc0'] : '['.$data[$field.'_loc0'].']';
- // dbc-case
- else if (User::$localeId != LOCALE_EN && isset($data[$field.$sqlLocales[0]]) && !empty($data[$field.$sqlLocales[0]]))
- return $silent ? $data[$field.$sqlLocales[0]] : '['.$data[$field.$sqlLocales[0]].']';
-
- // locale not enUS; TC localization; add brackets if not silent
+ // OBSOLETE - locale not enUS; TC localization; add brackets if not silent
else if (User::$localeId != LOCALE_EN && isset($data[$field]) && !empty($data[$field]))
return $silent ? $data[$field] : '['.$data[$field].']';
- // locale enUS; TC localization; return normal
+ // OBSOLETE - locale enUS; TC localization; return normal
else if (User::$localeId == LOCALE_EN && isset($data[$field]) && !empty($data[$field]))
return $data[$field];
@@ -1560,31 +1546,6 @@ class Util
*/
}
- // setup only
- private static $alphaMapCache = [];
- public static function alphaMapCheck($areaId, array &$set)
- {
- $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(self::$alphaMapCache[$areaId]))
- self::$alphaMapCache[$areaId] = imagecreatefrompng($file);
-
- // alphaMaps are 1000 x 1000, adapt points [black => valid point]
- if (!imagecolorat(self::$alphaMapCache[$areaId], $set['posX'] * 10, $set['posY'] * 10))
- $set = null;
-
- return true;
- }
-
public static function getServerConditions($srcType, $srcGroup = null, $srcEntry = null)
{
if (!$srcGroup && !$srcEntry)
diff --git a/index.php b/index.php
index d733e820..9c951bab 100644
--- a/index.php
+++ b/index.php
@@ -28,14 +28,18 @@ if ($error)
require_once 'includes/kernel.php';
-if (CLI || !file_exists('config/config.php'))
+if (CLI)
{
- $cwDir = /*$_SERVER['DOCUMENT_ROOT']; //*/getcwd();
require 'setup/setup.php';
die();
}
+// maybe add additional setup checks?
+if (!DB::isConnectable(DB_AOWOW) || !DB::isConnectable(DB_WORLD))
+ (new GenericPage($pageCall))->maintenance();
+
+
$altClass = '';
switch ($pageCall)
{
@@ -142,20 +146,6 @@ switch ($pageCall)
die((string)$_);
}
break;
- /* setup */
- case 'build':
- if (User::isInGroup(U_GROUP_EMPLOYEE))
- {
- define('TMP_BUILD', 1); // todo (med): needs better solution
- require 'setup/setup.php';
- break;
- }
- case 'sql':
- if (User::isInGroup(U_GROUP_EMPLOYEE))
- {
- require 'setup/tools/database/_'.$pageParam.'.php';
- break;
- }
default: // unk parameter given -> ErrorPage
if (isset($_GET['power']))
die('$WowheadPower.register(0, '.User::$localeId.', {})');
diff --git a/localization/lang.class.php b/localization/lang.class.php
index c21c8a70..87ec371f 100644
--- a/localization/lang.class.php
+++ b/localization/lang.class.php
@@ -9,7 +9,6 @@ class Lang
private static $game;
private static $achievement;
- private static $class;
private static $currency;
private static $event;
private static $faction;
@@ -20,6 +19,7 @@ class Lang
private static $npc;
private static $pet;
private static $quest;
+ private static $race;
private static $skill;
private static $spell;
private static $title;
@@ -41,20 +41,20 @@ class Lang
}
// todo: make static props private and access through this
- public static function __callStatic($name, $args)
+ public static function __callStatic($prop, $args)
{
- if (!isset(self::$$name))
+ if (!isset(self::$$prop))
{
- Util::addNote(U_GROUP_STAFF, 'Lang: tried to use undefined property Lang::$'.$name);
+ Util::addNote(U_GROUP_STAFF, 'Lang::__callStatic() - tried to use undefined property Lang::$'.$prop);
return null;
}
- $var = self::$$name;
+ $var = self::$$prop;
foreach ($args as $key)
{
if (!isset($var[$key]))
{
- Util::addNote(U_GROUP_STAFF, 'Lang: undefined key "'.$key.'" in property Lang::$'.$name.'. Full key chain: '.implode(', ', $args));
+ Util::addNote(U_GROUP_STAFF, 'Lang::__callStatic() - undefined key "'.$key.'" in property Lang::$'.$prop.'[\''.implode('\'][\'', $args).'\']');
return null;
}
@@ -64,6 +64,25 @@ class Lang
return $var;
}
+ public static function sort($prop, $group, $method = SORT_NATURAL)
+ {
+
+ if (!isset(self::$$prop))
+ {
+ Util::addNote(U_GROUP_STAFF, 'Lang::sort() - tried to use undefined property Lang::$'.$prop);
+ return null;
+ }
+
+ $var = &self::$$prop;
+ if (!isset($var[$group]))
+ {
+ Util::addNote(U_GROUP_STAFF, 'Lang::sort() - tried to use undefined property Lang::$'.$prop.'[\''.$group.'\']');
+ return null;
+ }
+
+ asort($var[$group], $method);
+ }
+
// todo: expand
public static function getInfoBoxForFlags($flags)
{
diff --git a/localization/locale_dede.php b/localization/locale_dede.php
index 4b3e6bad..69171b6d 100644
--- a/localization/locale_dede.php
+++ b/localization/locale_dede.php
@@ -439,7 +439,7 @@ $lang = array(
'reqNumCrt' => "Benötigt",
'_transfer' => 'Dieser Erfolg wird mit %s vertauscht, wenn Ihr zur %s wechselt.',
),
- 'class' => array(
+ 'race' => array(
'racialLeader' => "Volksanführer",
'startZone' => "Startgebiet",
),
@@ -461,7 +461,14 @@ $lang = array(
'CosmicMap' => "Kosmische Karte",
),
'zone' => array(
- // 'zonePartOf' => "Diese Zone ist Teil der Zone",
+ 'attunement' => ["Einstimmung", "Heroische Einstimmung"],
+ 'key' => ["Schlüssel", "Heroischer Schlüssel"],
+ 'location' => "Ort",
+ 'raidFaction' => "Schlachtzugsfraktion",
+ 'boss' => "Endboss",
+ 'reqLevels' => "Mindeststufe: [tooltip=instancereqlevel_tip]%d[/tooltip], [tooltip=lfgreqlevel_tip]%d[/tooltip]",
+ 'zonePartOf' => "Diese Zone ist Teil von [zone=%d].",
+ 'autoRez' => "Automatische Wiederbelebung",
'city' => "Stadt",
'territory' => "Territorium",
'instanceType' => "Instanzart",
@@ -714,9 +721,12 @@ $lang = array(
),
'powerRunes' => ["Frost", "Unheilig", "Blut", "Tod"],
'powerTypes' => array(
- -2 => "Gesundheit", -1 => null, "Mana", "Wut", "Fokus", "Energie", "Zufriedenheit", "Runen", "Runenmacht",
- 'AMMOSLOT' => "Munition", 'STEAM' => "Dampfdruck", 'WRATH' => "Wrath", 'PYRITE' => "Pyrit",
- 'HEAT' => "Hitze", 'OOZE' => "Schlamm", 'BLOOD_POWER' => "Blutmacht"
+ // conventional
+ -2 => "Gesundheit", 0 => "Mana", 1 => "Wut", 2 => "Fokus", 3 => "Energie", 4 => "Zufriedenheit",
+ 5 => "Runen", 6 => "Runenmacht",
+ // powerDisplay
+ -1 => "Munition", -41 => "Pyrit", -61 => "Dampfdruck", -101 => "Hitze", -121 => "Schlamm", -141 => "Blutmacht",
+ -142 => "Wrath"
),
'relItems' => array(
'base' => "%s im Zusammenhang mit %s anzeigen",
@@ -857,7 +867,6 @@ $lang = array(
'_unavailable' => "Dieser Gegenstand ist nicht für Spieler verfügbar.",
'_rndEnchants' => "Zufällige Verzauberungen",
'_chance' => "(Chance von %s%%)",
- 'reqRating' => "Benötigt eine persönliche Arenawertung und Teamwertung von %d.",
'slot' => "Platz",
'_quality' => "Qualität",
'usableBy' => "Benutzbar von",
@@ -877,6 +886,11 @@ $lang = array(
3 => "mehr Edelsteine der Kategorie %s als Edelsteine der Kategorie %s",
5 => ["mindestens %d Edelstein der Kategorie %s", "mindestens %d Edelsteine der Kategorie %s"]
),
+ 'reqRating' => array( // ITEM_REQ_ARENA_RATING*
+ "Benötigt eine persönliche Arenawertung und Teamwertung von %d.",
+ "Benötigt eine persönliche und eine Teamwertung von %d
in 3v3- oder 5v5-Turnieren",
+ "Benötigt eine persönliche und eine Teamwertung von %d
in 5v5-Turnieren"
+ ),
'quality' => array(
"Schlecht", "Verbreitet", "Selten", "Rar",
"Episch", "Legendär", "Artefakt", "Erbstücke",
diff --git a/localization/locale_enus.php b/localization/locale_enus.php
index c5f87a14..49c5fbce 100644
--- a/localization/locale_enus.php
+++ b/localization/locale_enus.php
@@ -434,7 +434,7 @@ $lang = array(
'reqNumCrt' => "Requires",
'_transfer' => 'This achievement will be converted to %s if you transfer to %s.',
),
- 'class' => array(
+ 'race' => array(
'racialLeader' => "Racial leader",
'startZone' => "Starting zone",
),
@@ -456,7 +456,14 @@ $lang = array(
'CosmicMap' => "Cosmic Map",
),
'zone' => array(
- // 'zonePartOf' => "This zone is part of",
+ 'attunement' => ["Attunement", "Heroic attunement"],
+ 'key' => ["Key", "Heroic key"],
+ 'location' => "Location",
+ 'raidFaction' => "Raid faction",
+ 'boss' => "Final boss",
+ 'reqLevels' => "Required levels: [tooltip=instancereqlevel_tip]%d[/tooltip], [tooltip=lfgreqlevel_tip]%d[/tooltip]",
+ 'zonePartOf' => "This zone is part of [zone=%].",
+ 'autoRez' => "Automatic resurrection",
'city' => "City",
'territory' => "Territory",
'instanceType' => "Instance type",
@@ -709,9 +716,12 @@ $lang = array(
),
'powerRunes' => ["Frost", "Unholy", "Blood", "Death"],
'powerTypes' => array(
- -2 => "Health", -1 => null, "Mana", "Rage", "Focus", "Energy", "Happiness", "Runes", "Runic Power",
- 'AMMOSLOT' => "Ammo", 'STEAM' => "Steam Pressure", 'WRATH' => "Wrath", 'PYRITE' => "Pyrite",
- 'HEAT' => "Heat", 'OOZE' => "Ooze", 'BLOOD_POWER' => "Blood Power"
+ // conventional
+ -2 => "Health", 0 => "Mana", 1 => "Rage", 2 => "Focus", 3 => "Energy", 4 => "Happiness",
+ 5 => "Rune", 6 => "Runic Power",
+ // powerDisplay
+ -1 => "Ammo", -41 => "Pyrite", -61 => "Steam Pressure", -101 => "Heat", -121 => "Ooze", -141 => "Blood Power",
+ -142 => "Wrath"
),
'relItems' => array(
'base' => "Show %s related to %s",
@@ -852,7 +862,6 @@ $lang = array(
'_unavailable' => "This item is not available to players.",
'_rndEnchants' => "Random Enchantments",
'_chance' => "(%s%% chance)",
- 'reqRating' => "Requires personal and team arena rating of %d in 3v3 or 5v5 brackets",
'slot' => "Slot",
'_quality' => "Quality",
'usableBy' => "Usable by",
@@ -872,6 +881,11 @@ $lang = array(
3 => "more %s gems than %s gems",
5 => ["at least %d %s gem", "at least %d %s gems"]
),
+ 'reqRating' => array( // ITEM_REQ_ARENA_RATING*
+ "Requires personal and team arena rating of %d",
+ "Requires personal and team arena rating of %d
in 3v3 or 5v5 brackets",
+ "Requires personal and team arena rating of %d
in 5v5 brackets"
+ ),
'quality' => array(
"Poor", "Common", "Uncommon", "Rare",
"Epic", "Legendary", "Artifact", "Heirloom"
diff --git a/localization/locale_eses.php b/localization/locale_eses.php
index d89d43a6..0e3f2f87 100644
--- a/localization/locale_eses.php
+++ b/localization/locale_eses.php
@@ -438,7 +438,7 @@ $lang = array(
'reqNumCrt' => "Requiere",
'_transfer' => 'Este logro será convertido a %s si lo transfieres a la %s.',
),
- 'class' => array(
+ 'race' => array(
'racialLeader' => "Lider racial",
'startZone' => "Zona de inicio",
),
@@ -460,7 +460,14 @@ $lang = array(
'CosmicMap' => "Mapa cósmico",
),
'zone' => array(
- // 'zonePartOf' => "Cette zone fait partie de la zone",
+ 'attunement' => ["Requisito", "Requisito heroica"],
+ 'key' => ["Llave", "Llave heroica"],
+ 'location' => "Ubicación",
+ 'raidFaction' => "[Raid faction]",
+ 'boss' => "Jefe Final",
+ 'reqLevels' => "Niveles requeridos: [tooltip=instancereqlevel_tip]%d[/tooltip], [tooltip=lfgreqlevel_tip]%d[/tooltip]",
+ 'zonePartOf' => "Cette zone fait partie de la zone [zone=%d].",
+ 'autoRez' => "Resurrección automática",
'city' => "Ciudad",
'territory' => "Territorio",
'instanceType' => "Tipo de instancia",
@@ -713,9 +720,12 @@ $lang = array(
),
'powerRunes' => ["Escarcha", "Profano", "Sangre", "Muerte"],
'powerTypes' => array(
- -2 => "Salud", -1 => null, "Maná", "Ira", "Enfoque", "Energía", "Felicidad", "Runa", "Poder rúnico",
- 'AMMOSLOT' => "Munición", 'STEAM' => "Presión de vapor", 'WRATH' => "Cólera", 'PYRITE' => "Pirita",
- 'HEAT' => "Calor", 'OOZE' => "Moco", 'BLOOD_POWER' => "Poder de sangre"
+ // conventional
+ -2 => "Salud", 0 => "Maná", 1 => "Ira", 2 => "Enfoque", 3 => "Energía", 4 => "Felicidad",
+ 5 => "Runa", 6 => "Poder rúnico",
+ // powerDisplay
+ -1 => "Munición", -41 => "Pirita", -61 => "Presión de vapor", -101 => "Calor", -121 => "Moco", -141 => "Poder de sangre",
+ -142 => "Cólera"
),
'relItems' => array(
'base' => "Muestra %s relacionados con %s",
@@ -856,7 +866,6 @@ $lang = array(
'_unavailable' => "Este objeto no está disponible para los jugadores.",
'_rndEnchants' => "Encantamientos aleatorios",
'_chance' => "(probabilidad %s%%)",
- 'reqRating' => "Requiere un índice de arena personal y de equipo de %d",
'slot' => "Casilla",
'_quality' => "Calidad",
'usableBy' => "Usable por",
@@ -876,6 +885,11 @@ $lang = array(
3 => "más gemas %s que gemas %s",
5 => ["al menos %d %s gema", "al menos %d %s gemas"]
),
+ 'reqRating' => array( // ITEM_REQ_ARENA_RATING*
+ "Requiere un índice de arena personal y de equipo de %d",
+ "Requiere un índice de arena personal y de equipo de %d
en la rama de 3c3 o de 5c5",
+ "Requiere un índice de arena personal y de equipo de %d
en la rama de 5c5"
+ ),
'quality' => array(
"Pobre", "Común", "Poco Común", "Raro",
"Épica", "Legendaria", "Artefacto", "Reliquia"
diff --git a/localization/locale_frfr.php b/localization/locale_frfr.php
index af8d7795..9d8678a2 100644
--- a/localization/locale_frfr.php
+++ b/localization/locale_frfr.php
@@ -437,7 +437,7 @@ $lang = array(
'reqNumCrt' => "Nécessite",
'_transfer' => 'Cet haut fait sera converti en %s si vous transférez en %s.',
),
- 'class' => array(
+ 'race' => array(
'racialLeader' => "Leader racial",
'startZone' => "Zone initiales",
),
@@ -459,7 +459,14 @@ $lang = array(
'CosmicMap' => "Carte cosmique",
),
'zone' => array(
- // 'zonePartOf' => "Cette zone fait partie de la zone",
+ 'attunement' => ["Accès", "Accès Héroïque"],
+ 'key' => ["Clef", "Clef Héroïque"],
+ 'location' => "Localisation",
+ 'raidFaction' => "Faction de raid",
+ 'boss' => "Boss final",
+ 'reqLevels' => "Niveaux requis : [tooltip=instancereqlevel_tip]%d[/tooltip], [tooltip=lfgreqlevel_tip]%d[/tooltip]",
+ 'zonePartOf' => "Cette zone fait partie de la zone [zone=%d].",
+ 'autoRez' => "Résurrection automatique",
'city' => "Город",
'territory' => "Territoire",
'instanceType' => "Type d'instance",
@@ -695,7 +702,7 @@ $lang = array(
'instantPhys' => "Incantation immédiate",
'instantMagic' => "Instantanée",
'channeled' => "Canalisée",
- 'range' => "m de portée",
+ 'range' => "%s m de portée",
'meleeRange' => "Allonge",
'unlimRange' => "Portée illimitée",
'reagents' => "Composants",
@@ -711,9 +718,12 @@ $lang = array(
),
'powerRunes' => ["Givre", "Impie", "Sang", "Mort"],
'powerTypes' => array(
- -2 => "vie", -1 => null, "mana", "rage", "focus", "énergie", "Satisfaction", "Runes", "puissance runique",
- 'AMMOSLOT' => "Munitions", 'STEAM' => "Pression vapeur", 'WRATH' => "Courroux", 'PYRITE' => "Pyrite",
- 'HEAT' => "Chaleur", 'OOZE' => "Limon", 'BLOOD_POWER' => "Puissance de sang"
+ // conventional
+ -2 => "vie", 0 => "mana", 1 => "rage", 2 => "focus", 3 => "énergie", 4 => "Satisfaction",
+ 5 => "Runes", 6 => "puissance runique",
+ // powerDisplay
+ -1 => "Munitions", -41 => "Pyrite", -61 => "Pression vapeur", -101 => "Chaleur", -121 => "Limon", -141 => "Puissance de sang",
+ -142 => "Courroux"
),
'relItems' => array(
'base' => "Montre %s reliés à %s",
@@ -854,7 +864,6 @@ $lang = array(
'_unavailable' => "Este objeto no está disponible para los jugadores.",
'_rndEnchants' => "Enchantements aléatoires",
'_chance' => "(%s%% de chance)",
- 'reqRating' => "Nécessite une cote d'arène personnelle et en équipe de %d en arène de 3c3 ou 5c5.",
'slot' => "Emplacement",
'_quality' => "Qualité",
'usableBy' => "Utilisable par",
@@ -874,6 +883,11 @@ $lang = array(
3 => "plus de gemmes %s que de %s", // plus de gemmes %s que |2 %s
5 => ["au moins %d gemme %s", "au moins %d gemmes %s"]
),
+ 'reqRating' => array( // ITEM_REQ_ARENA_RATING*
+ "Nécessite une cote d'arène personnelle et en équipe de %d",
+ "Nécessite une cote d'arène personnelle et en équipe de %d
en arène de 3c3 ou 5c5.",
+ "Nécessite une cote d'arène personnelle et en équipe de %d
en arène de 5c5."
+ ),
'quality' => array(
"Médiocre", "Classique", "Bonne", "Rare",
"Épique", "Légendaire", "Artefact", "Héritage"
diff --git a/localization/locale_ruru.php b/localization/locale_ruru.php
index 6a59a202..f4e47d0e 100644
--- a/localization/locale_ruru.php
+++ b/localization/locale_ruru.php
@@ -437,7 +437,7 @@ $lang = array(
'reqNumCrt' => "Требуется",
'_transfer' => 'Этот предмет превратится в %s, если вы перейдете за %s.',
),
- 'class' => array(
+ 'race' => array(
'racialLeader' => "Лидер расы",
'startZone' => "Начальная локация",
),
@@ -459,7 +459,14 @@ $lang = array(
'CosmicMap' => "Звёздная карта",
),
'zone' => array(
- // 'zonePartOf' => "Эта игровая локация является частью локации",
+ 'attunement' => ["[Attunement]", "[Heroic attunement]"],
+ 'key' => ["[Key]", "[Heroic key]"],
+ 'location' => "Местоположение",
+ 'raidFaction' => "Фракция рейда",
+ 'boss' => "Последний босс",
+ 'reqLevels' => "Требуемые уровни: [tooltip=instancereqlevel_tip]%d[/tooltip], [tooltip=lfgreqlevel_tip]%d[/tooltip]",
+ 'zonePartOf' => "Эта игровая локация является частью локации [zone=%d].",
+ 'autoRez' => "Автоматическое воскрешение",
'city' => "Город",
'territory' => "Территория",
'instanceType' => "Тип подземелья",
@@ -713,9 +720,12 @@ $lang = array(
),
'powerRunes' => ["Лед", "Руна льда", "Руна крови", "Смерти"],
'powerTypes' => array(
- -2 => "Здоровье", -1 => null, "Мана", "Ярость", "Тонус", "Энергия", "Настроение", "Руны", "Руническая сила",
- 'AMMOSLOT' => "Боеприпасы", 'STEAM' => "Давление пара", 'WRATH' => "Гнев", 'PYRITE' => "Колчедан",
- 'HEAT' => "Жар", 'OOZE' => "Слизнюк", 'BLOOD_POWER' => "Сила крови"
+ // conventional
+ -2 => "Здоровье", 0 => "Мана", 1 => "Ярость", 2 => "Тонус", 3 => "Энергия", 4 => "Настроение",
+ 5 => "Руны", 6 => "Руническая сила",
+ // powerDisplay
+ -1 => "Боеприпасы", -41 => "Колчедан", -61 => "Давление пара", -101 => "Жар", -121 => "Слизнюк", -141 => "Сила крови",
+ -142 => "Гнев"
),
'relItems' => array(
'base' => "Показать %s, относящиеся к профессии %s",
@@ -856,7 +866,6 @@ $lang = array(
'_unavailable' => "Этот предмет не доступен игрокам.",
'_rndEnchants' => "Случайные улучшения",
'_chance' => "(шанс %s%%)",
- 'reqRating' => "Требуется личный и командный рейтинг на арене не ниже %d",
'slot' => "Слот",
'_quality' => "Качество",
'usableBy' => "Используется (кем)",
@@ -876,6 +885,11 @@ $lang = array(
3 => "больше %s, чем %s камней", // больше |3-7(%s), чем |3-7(%s) камней
5 => ["хотя бы %d камень %s цвета", "хотя бы %d камня %s цвета"] // хотя бы %d |4камень:камня:камней; |3-1(%s) цвета; same here
),
+ 'reqRating' => array( // ITEM_REQ_ARENA_RATING*
+ "Требуется личный и командный рейтинг на арене не ниже %d",
+ "Требуется личный рейтинг и рейтинг команды Арены %d
в команде 3 на 3 или 5 на 5",
+ "Требуется личный рейтинг и рейтинг команды Арены %d
в команде 5 на 5"
+ ),
'quality' => array(
"Низкий", "Обычный", "Необычный", "Редкий",
"Эпический", "Легендарный", "Артефакт", "Фамильная черта"
diff --git a/pages/account.php b/pages/account.php
index 2f83eb44..bcfa3c49 100644
--- a/pages/account.php
+++ b/pages/account.php
@@ -24,6 +24,9 @@ class AccountPage extends GenericPage
protected $error = '';
protected $next = '';
+ protected $lvTabs = [];
+ protected $banned = [];
+
private $_post = array(
'username' => [FILTER_SANITIZE_SPECIAL_CHARS, 0xC], // FILTER_FLAG_STRIP_LOW | *_HIGH
'password' => [FILTER_UNSAFE_RAW, null],
@@ -196,7 +199,6 @@ class AccountPage extends GenericPage
/* Ban Popup */
/*************/
- $this->banned = [];
foreach ($bans as $b)
{
if (!($b['typeMask'] & (ACC_BAN_TEMP | ACC_BAN_PERM)) || ($b['end'] && $b['end'] <= time()))
diff --git a/pages/achievements.php b/pages/achievements.php
index 968e0937..ffc95e2b 100644
--- a/pages/achievements.php
+++ b/pages/achievements.php
@@ -121,7 +121,7 @@ class AchievementsPage extends GenericPage
);
// sort for dropdown-menus in filter
- asort(Lang::game('si'));
+ Lang::sort('game', 'si');
}
protected function generateTitle()
diff --git a/pages/admin.php b/pages/admin.php
index f189ff0e..f8a3726c 100644
--- a/pages/admin.php
+++ b/pages/admin.php
@@ -256,7 +256,7 @@ class AdminPage extends GenericPage
}
else if (node.tagName == 'INPUT') // string or numeric
{
- if (!node.value.search(/[\d\s\/\*\-\+]/i))
+ if (node.value.search(/[^\d\s\/\*\-\+\.]/i) == -1)
node.value = eval(node.value);
value = node.value;
diff --git a/pages/class.php b/pages/class.php
index d94963c6..28fa49f4 100644
--- a/pages/class.php
+++ b/pages/class.php
@@ -125,7 +125,7 @@ class ClassPage extends GenericPage
[ // last rank or unranked
'OR',
['s.cuFlags', SPELL_CU_LAST_RANK, '&'],
- ['s.rankId', 0]
+ ['s.rankNo', 0]
]
);
diff --git a/pages/currency.php b/pages/currency.php
index 2e590169..97ff3166 100644
--- a/pages/currency.php
+++ b/pages/currency.php
@@ -200,7 +200,7 @@ class CurrencyPage extends GenericPage
}
$xCosts = DB::Aowow()->selectCol('SELECT id FROM ?_itemextendedcost WHERE '.$w);
- $boughtBy = DB::World()->selectCol('SELECT item FROM npc_vendor WHERE extendedCost IN (?a) UNION SELECT item FROM game_event_npc_vendor WHERE extendedCost IN (?a)', $xCosts, $xCosts);
+ $boughtBy = $xCosts ? DB::World()->selectCol('SELECT item FROM npc_vendor WHERE extendedCost IN (?a) UNION SELECT item FROM game_event_npc_vendor WHERE extendedCost IN (?a)', $xCosts, $xCosts) : [];
if ($boughtBy)
{
$boughtBy = new ItemList(array(['id', $boughtBy]));
diff --git a/pages/faction.php b/pages/faction.php
index 17e45ebe..9012dfb3 100644
--- a/pages/faction.php
+++ b/pages/faction.php
@@ -25,7 +25,7 @@ class FactionPage extends GenericPage
$this->subject = new FactionList(array(['id', $this->typeId]));
if ($this->subject->error)
- $smarty->notFound(Lang::game('faction'));
+ $this->notFound(Lang::game('faction'));
$this->name = $this->subject->getField('name', true);
}
@@ -103,7 +103,7 @@ class FactionPage extends GenericPage
$conditions = array(
['id', $this->typeId, '!'], // not self
- ['reputationIndex', -1, '!'] // only gainable
+ ['repIdx', -1, '!'] // only gainable
);
if ($p = $this->subject->getField('parentFactionId')) // linked via parent
@@ -196,10 +196,10 @@ class FactionPage extends GenericPage
{
// inherit siblings/children from $spillover
$cIds = DB::World()->selectCol('SELECT DISTINCT creature_id FROM creature_onkill_reputation WHERE
- (RewOnKillRepValue1 > 0 AND (RewOnKillRepFaction1 = ?d OR (RewOnKillRepFaction1 IN (?a) AND IsTeamAward1 <> 0))) OR
- (RewOnKillRepValue2 > 0 AND (RewOnKillRepFaction2 = ?d OR (RewOnKillRepFaction2 IN (?a) AND IsTeamAward2 <> 0)))',
- $this->typeId, $spillover->getFoundIDs(),
- $this->typeId, $spillover->getFoundIDs()
+ (RewOnKillRepValue1 > 0 AND (RewOnKillRepFaction1 = ?d{ OR (RewOnKillRepFaction1 IN (?a) AND IsTeamAward1 <> 0)})) OR
+ (RewOnKillRepValue2 > 0 AND (RewOnKillRepFaction2 = ?d{ OR (RewOnKillRepFaction2 IN (?a) AND IsTeamAward2 <> 0)}))',
+ $this->typeId, $spillover->getFoundIDs() ?: DBSIMPLE_SKIP,
+ $this->typeId, $spillover->getFoundIDs() ?: DBSIMPLE_SKIP
);
if ($cIds)
diff --git a/pages/factions.php b/pages/factions.php
index 1cde6a3d..1323c72a 100644
--- a/pages/factions.php
+++ b/pages/factions.php
@@ -42,13 +42,12 @@ class FactionsPage extends GenericPage
$conditions[] = ['parentFactionId', $this->category[1]];
else if (isset($this->category[0]))
{
- if (!$this->category[0])
- $conditions[] = ['parentFactionId', [1118, 980, 1097, 469, 891, 67, 892, 169, 1037, 1052, 1117, 936], '!'];
- else
- {
+ if ($this->category[0])
$subs = DB::Aowow()->selectCol('SELECT id FROM ?_factions WHERE parentFactionId = ?d', $this->category[0]);
- $conditions[] = ['OR', ['parentFactionId', $subs], ['id', $subs]];
- }
+ else
+ $subs = [0];
+
+ $conditions[] = ['OR', ['parentFactionId', $subs], ['id', $subs]];
}
$data = [];
diff --git a/pages/genericPage.class.php b/pages/genericPage.class.php
index c2331a30..c9fcc4be 100644
--- a/pages/genericPage.class.php
+++ b/pages/genericPage.class.php
@@ -109,7 +109,7 @@ class GenericPage
$this->gUser = User::getUserGlobals();
$this->pageTemplate['pageName'] = strtolower($pageCall);
- if (!$this->isValidPage() || !$this->tpl)
+ if (!$this->isValidPage())
$this->error();
}
@@ -216,7 +216,7 @@ class GenericPage
$this->applyGlobals();
}
- $this->time = microtime(true) - $this->time;
+ $this->time = microtime(true) - $this->time;
Util::arraySumByKey($this->mysql, DB::Aowow()->getStatistics(), DB::World()->getStatistics());
}
@@ -417,7 +417,7 @@ class GenericPage
include('template/pages/'.$override.'.tpl.php');
die();
}
- else
+ else if ($this->tpl)
{
$this->prepareContent();
@@ -429,6 +429,8 @@ class GenericPage
include('template/pages/'.$this->tpl.'.tpl.php');
die();
}
+ else
+ $this->error();
}
public function writeGlobalVars() // load jsGlobal
diff --git a/pages/item.php b/pages/item.php
index 29fb825a..d0b02be8 100644
--- a/pages/item.php
+++ b/pages/item.php
@@ -234,11 +234,11 @@ class ItemPage extends genericPage
$res = [];
$i = 0;
$len = 0;
- $parts = explode(' ', sprintf(Lang::item('reqRating'), $_reqRating));
+ $parts = explode(' ', str_replace('
', ' ', sprintf(Lang::item('reqRating', $_reqRating[1]), $_reqRating[0])));
foreach ($parts as $p)
{
$res[$i][] = $p;
- $len += mb_strlen($p);
+ $len += (mb_strlen($p) + 1);
if ($len < 30)
continue;
@@ -419,30 +419,13 @@ class ItemPage extends genericPage
'name' => $tab[2],
'id' => $tab[3],
'extraCols' => $tab[4] ? '$['.implode(', ', array_unique($tab[4])).']' : null,
- 'hiddenCols' => $tab[5] ? '$['.implode(', ', array_unique($tab[5])).']' : null,
+ 'hiddenCols' => $tab[5] ? '$ '.Util::toJSON( array_unique($tab[5])) : null,
'visibleCols' => $tab[6] ? '$'. Util::toJSON( array_unique($tab[6])) : null
]
);
}
}
- // tab: achievement reward
- $acvReward = new AchievementList(array(['ar.item', $this->typeId], ['a.itemExtra', $this->typeId], 'OR'));
- if (!$acvReward->error)
- {
- $this->extendGlobalData($acvReward->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS));
-
- $this->lvTabs[] = array(
- 'file' => 'achievement',
- 'data' => $acvReward->getListviewData(),
- 'params' => [
- 'name' => '$LANG.tab_rewardfrom',
- 'id' => 'reward-from-achievement',
- 'visibleCols' => "$['category']"
- ]
- );
- }
-
// tabs: this item contains..
$sourceFor = array(
[LOOT_ITEM, $this->subject->id, '$LANG.tab_contains', 'contains', ['Listview.extraCols.percent'], [] , []],
@@ -762,7 +745,7 @@ class ItemPage extends genericPage
}
// tab: sold by
- if (!empty($this->subject->getExtendedCost([], $_reqRating)[$this->subject->id]))
+ if (!empty($this->subject->getExtendedCost()[$this->subject->id]))
{
$vendors = $this->subject->getExtendedCost()[$this->subject->id];
$soldBy = new CreatureList(array(['id', array_keys($vendors)]));
diff --git a/pages/items.php b/pages/items.php
index 0ba752a6..37d68e36 100644
--- a/pages/items.php
+++ b/pages/items.php
@@ -87,7 +87,7 @@ class ItemsPage extends GenericPage
parent::__construct($pageCall, $pageParam);
$this->name = Util::ucFirst(Lang::game('items'));
- $this->subCat = $pageParam ? '='.$pageParam : '';
+ $this->subCat = is_numeric($pageParam) ? '='.$pageParam : '';
}
protected function generateContent()
@@ -427,8 +427,8 @@ class ItemsPage extends GenericPage
}
// sort for dropdown-menus
- asort(Lang::game('ra'));
- asort(Lang::game('cl'));
+ Lang::sort('game', 'ra');
+ Lang::sort('game', 'cl');
}
protected function generateTitle()
diff --git a/pages/itemsets.php b/pages/itemsets.php
index 064a8a98..d0e87428 100644
--- a/pages/itemsets.php
+++ b/pages/itemsets.php
@@ -69,8 +69,8 @@ class ItemsetsPage extends GenericPage
$this->lvTabs[] = $lv;
// sort for dropdown-menus
- asort(Lang::itemset('notes'), SORT_NATURAL);
- asort(Lang::game('cl'));
+ Lang::sort('itemset', 'notes', SORT_NATURAL);
+ Lang::sort('game', 'si');
}
protected function generateTitle()
diff --git a/pages/npc.php b/pages/npc.php
index 49ec7957..3482a478 100644
--- a/pages/npc.php
+++ b/pages/npc.php
@@ -89,9 +89,14 @@ class NpcPage extends GenericPage
{
if (count($maps) == 1) // should only exist in one instance
{
- $map = new ZoneList(array(['id', $maps], 1));
- if (!$map->error)
- $mapType = $map->getField('areaType');
+ switch ((new ZoneList(array(['id', $maps], 1)))->getField('type'))
+ {
+ case 2:
+ case 5: $mapType = 1; break;
+ case 3:
+ case 7:
+ case 8: $mapType = 2; break;
+ }
}
}
else if ($_altIds) // not spawned, but has difficultyDummies
@@ -315,7 +320,6 @@ class NpcPage extends GenericPage
// consider pooled spawns
-
$this->map = $map;
$this->infobox = '[ul][li]'.implode('[/li][li]', $infobox).'[/li][/ul]';
$this->position = $position;
@@ -865,7 +869,7 @@ class NpcPage extends GenericPage
$reputation[] = [Lang::npc('modes', 1, 0), $base];
// difficulty dummys
- if ($dummyIds)
+ if ($dummyIds && ($mapType == 1 || $mapType == 2))
{
$alt = [];
$rep = $this->getRepForId(array_keys($dummyIds), $spilledParents);
diff --git a/pages/npcs.php b/pages/npcs.php
index 245c5077..ccea9ddf 100644
--- a/pages/npcs.php
+++ b/pages/npcs.php
@@ -82,7 +82,7 @@ class NpcsPage extends GenericPage
$this->lvTabs[] = $lv;
// sort for dropdown-menus
- asort(Lang::game('fa'));
+ Lang::sort('game', 'fa');
}
protected function generateTitle()
diff --git a/pages/pet.php b/pages/pet.php
index ee5468dd..dadda193 100644
--- a/pages/pet.php
+++ b/pages/pet.php
@@ -169,7 +169,7 @@ class PetPage extends GenericPage
[ // last rank or unranked
'OR',
['s.cuFlags', SPELL_CU_LAST_RANK, '&'],
- ['s.rankId', 0]
+ ['s.rankNo', 0]
]
);
diff --git a/pages/profiles.php b/pages/profiles.php
index 01572848..4c164ba2 100644
--- a/pages/profiles.php
+++ b/pages/profiles.php
@@ -113,8 +113,8 @@ class ProfilesPage extends GenericPage
$this->filter = ['query' => 1];
- asort(Lang::game('cl'));
- asort(Lang::game('ra'));
+ Lang::sort('game', 'cl');
+ Lang::sort('game', 'ra');
}
private function getTalentDistribution($tString)
diff --git a/pages/quest.php b/pages/quest.php
index bad87059..89945189 100644
--- a/pages/quest.php
+++ b/pages/quest.php
@@ -84,11 +84,11 @@ class QuestPage extends GenericPage
}
// loremaster (i dearly hope those flags cover every case...)
- if ($this->subject->getField('zoneOrSort') > 0 && !$this->subject->isRepeatable())
+ if ($this->subject->getField('zoneOrSortBak') > 0 && !$this->subject->isRepeatable())
{
$conditions = array(
['ac.type', ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE],
- ['ac.value1', $this->subject->getField('zoneOrSort')],
+ ['ac.value1', $this->subject->getField('zoneOrSortBak')],
['a.faction', $_side, '&']
);
$loremaster = new AchievementList($conditions);
diff --git a/pages/race.php b/pages/race.php
index e8913fcf..ca938153 100644
--- a/pages/race.php
+++ b/pages/race.php
@@ -64,7 +64,7 @@ class RacePage extends GenericPage
// faction
if ($_ = $this->subject->getField('factionId'))
{
- $fac = new FactionList(array(['ft.id', $_]));
+ $fac = new FactionList(array(['f.id', $_]));
$this->extendGlobalData($fac->getJSGlobals());
$infobox[] = Util::ucFirst(Lang::game('faction')).Lang::main('colon').'[faction='.$fac->id.']';
}
@@ -73,14 +73,14 @@ class RacePage extends GenericPage
if ($_ = $this->subject->getField('leader'))
{
$this->extendGlobalIds(TYPE_NPC, $_);
- $infobox[] = Lang::class('racialLeader').Lang::main('colon').'[npc='.$_.']';
+ $infobox[] = Lang::race('racialLeader').Lang::main('colon').'[npc='.$_.']';
}
// start area
if ($_ = $this->subject->getField('startAreaId'))
{
$this->extendGlobalIds(TYPE_ZONE, $_);
- $infobox[] = Lang::class('startZone').Lang::main('colon').'[zone='.$_.']';
+ $infobox[] = Lang::race('startZone').Lang::main('colon').'[zone='.$_.']';
}
diff --git a/pages/skill.php b/pages/skill.php
index 2f1d452a..ad576c01 100644
--- a/pages/skill.php
+++ b/pages/skill.php
@@ -55,6 +55,9 @@ class SkillPage extends GenericPage
BUTTON_LINKS => true
);
+ if ($_ = $this->subject->getField('description', true))
+ $this->extraText = $_;
+
/**************/
/* Extra Tabs */
/**************/
@@ -275,7 +278,7 @@ class SkillPage extends GenericPage
{
$this->addJS('?data=zones&locale='.User::$localeId.'&t='.$_SESSION['dataKey']);
- $trainer = new CreatureList(array(CFG_SQL_LIMIT_NONE, ['ct.id', $list], ['ct.spawns', 0, '>'], ['ct.npcflag', 0x10, '&']));
+ $trainer = new CreatureList(array(CFG_SQL_LIMIT_NONE, ['ct.id', $list], ['s.guid', NULL, '!'], ['ct.npcflag', 0x10, '&']));
if (!$trainer->error)
{
diff --git a/pages/spell.php b/pages/spell.php
index 8166c929..0ff6ddb7 100644
--- a/pages/spell.php
+++ b/pages/spell.php
@@ -50,14 +50,14 @@ class SpellPage extends GenericPage
$this->typeId, $this->typeId, $this->typeId, $this->typeId
);
- // returns self or firstRank
- $this->firstRank = DB::Aowow()->selectCell(
- 'SELECT IF(s1.rankId <> 1 AND s2.id, s2.id, s1.id)
+ // returns self or firstRank
+ $this->firstRank = DB::Aowow()->selectCell(
+ 'SELECT IF(s1.RankNo <> 1 AND s2.id, s2.id, s1.id)
FROM ?_spell s1
LEFT JOIN ?_spell s2
ON s1.SpellFamilyId = s2.SpelLFamilyId AND s1.SpellFamilyFlags1 = s2.SpelLFamilyFlags1 AND
s1.SpellFamilyFlags2 = s2.SpellFamilyFlags2 AND s1.SpellFamilyFlags3 = s2.SpellFamilyFlags3 AND
- s1.name_loc0 = s2.name_loc0 AND s2.RankId = 1
+ s1.name_loc0 = s2.name_loc0 AND s2.RankNo = 1
WHERE s1.id = ?d',
$this->typeId
);
@@ -137,9 +137,9 @@ class SpellPage extends GenericPage
if (!in_array($_cat, [-5, -6])) // not mount or vanity pet
{
if ($_ = $this->subject->getField('talentLevel'))
- $infobox[] = '[li]'.(in_array($_cat, [-2, 7, -13]) ? sprintf(Lang::game('reqLevel'), $_) : Lang::game('level').Lang::main('colon').$_).'[/li]';
+ $infobox[] = (in_array($_cat, [-2, 7, -13]) ? sprintf(Lang::game('reqLevel'), $_) : Lang::game('level').Lang::main('colon').$_);
else if ($_ = $this->subject->getField('spellLevel'))
- $infobox[] = '[li]'.(in_array($_cat, [-2, 7, -13]) ? sprintf(Lang::game('reqLevel'), $_) : Lang::game('level').Lang::main('colon').$_).'[/li]';
+ $infobox[] = (in_array($_cat, [-2, 7, -13]) ? sprintf(Lang::game('reqLevel'), $_) : Lang::game('level').Lang::main('colon').$_);
}
// races
@@ -149,7 +149,7 @@ class SpellPage extends GenericPage
{
$this->extendGlobalIds(TYPE_RACE, $jsg);
$t = $n == 1 ? Lang::game('race') : Lang::game('races');
- $infobox[] = '[li]'.Util::ucFirst($t).Lang::main('colon').$_.'[/li]';
+ $infobox[] = Util::ucFirst($t).Lang::main('colon').$_;
}
}
@@ -158,7 +158,7 @@ class SpellPage extends GenericPage
{
$this->extendGlobalIds(TYPE_CLASS, $jsg);
$t = $n == 1 ? Lang::game('class') : Lang::game('classes');
- $infobox[] = '[li]'.Util::ucFirst($t).Lang::main('colon').$_.'[/li]';
+ $infobox[] = Util::ucFirst($t).Lang::main('colon').$_;
}
// spell focus
@@ -166,7 +166,7 @@ class SpellPage extends GenericPage
{
$bar = DB::Aowow()->selectRow('SELECT * FROM ?_spellfocusobject WHERE id = ?d', $_);
$focus = new GameObjectList(array(['spellFocusId', $_], 1));
- $infobox[] = '[li]'.Lang::game('requires2').' '.($focus->error ? Util::localizedString($bar, 'name') : '[url=?object='.$focus->id.']'.Util::localizedString($bar, 'name').'[/url]').'[/li]';
+ $infobox[] = Lang::game('requires2').' '.($focus->error ? Util::localizedString($bar, 'name') : '[url=?object='.$focus->id.']'.Util::localizedString($bar, 'name').'[/url]');
}
// primary & secondary trades
@@ -184,7 +184,7 @@ class SpellPage extends GenericPage
if ($_ = $this->subject->getField('learnedAt'))
$bar .= ' ('.$_.')';
- $infobox[] = '[li]'.$bar.'[/li]';
+ $infobox[] = $bar;
}
}
@@ -195,7 +195,7 @@ class SpellPage extends GenericPage
if (!$rSpell->error)
{
$this->extendGlobalData($rSpell->getJSGlobals());
- $infobox[] = '[li]'.Lang::game('requires2').' [spell='.$rSpell->id.'][/li]';
+ $infobox[] = Lang::game('requires2').' [spell='.$rSpell->id.'][/li]';
}
}
@@ -207,27 +207,27 @@ class SpellPage extends GenericPage
if ($_[$i])
$bar[] = '[color=r'.($i + 1).']'.$_[$i].'[/color]';
- $infobox[] = '[li]'.Lang::game('difficulty').Lang::main('colon').implode(' ', $bar).'[/li]';
+ $infobox[] = Lang::game('difficulty').Lang::main('colon').implode(' ', $bar);
}
}
// accquisition.. 10: starter spell; 7: discovery
if (isset($this->subject->sources[$this->subject->id][10]))
- $infobox[] = '[li]'.Lang::spell('starter').'[/li]';
+ $infobox[] = Lang::spell('starter');
else if (isset($this->subject->sources[$this->subject->id][7]))
- $infobox[] = '[li]'.Lang::spell('discovered').'[/li]';
+ $infobox[] = Lang::spell('discovered');
// training cost
- if ($cost = DB::World()->selectCell('SELECT spellcost FROM npc_trainer WHERE spell = ?d', $this->subject->id))
- $infobox[] = '[li]'.Lang::spell('trainingCost').Lang::main('colon').'[money='.$cost.'][/li]';
+ if ($cost = $this->subject->getField('trainingCost'))
+ $infobox[] = Lang::spell('trainingCost').Lang::main('colon').'[money='.$cost.'][/li]';
// used in mode
foreach ($this->difficulties as $n => $id)
if ($id == $this->typeId) // "Mode" seems to be multilingual acceptable
- $infobox[] = '[li]Mode'.Lang::main('colon').Lang::game('modes', $n).'[/li]';
+ $infobox[] = 'Mode'.Lang::main('colon').Lang::game('modes', $n);
$effects = $this->createEffects($infobox, $redButtons);
- $infobox = $infobox ? '[ul]'.implode('', $infobox).'[/ul]' : '';
+ $infobox = $infobox ? '[ul][li]'.implode('[/li][li]', $infobox).'[/li][/ul]' : '';
// append glyph symbol if available
$glyphId = 0;
@@ -235,7 +235,7 @@ class SpellPage extends GenericPage
if ($this->subject->getField('effect'.$i.'Id') == 74)
$glyphId = $this->subject->getField('effect'.$i.'MiscValue');
- if ($_ = DB::Aowow()->selectCell('SELECT si.iconString FROM ?_glyphproperties gp JOIN ?_spellicon si ON gp.iconId = si.id WHERE gp.spellId = ?d { OR gp.id = ?d }', $this->typeId, $glyphId ?: DBSIMPLE_SKIP))
+ if ($_ = DB::Aowow()->selectCell('SELECT si.iconString FROM ?_glyphproperties gp JOIN ?_icons si ON gp.iconId = si.id WHERE gp.spellId = ?d { OR gp.id = ?d }', $this->typeId, $glyphId ?: DBSIMPLE_SKIP))
if (file_exists('static/images/wow/Interface/Spellbook/'.$_.'.png'))
$infobox .= '[img src='.STATIC_URL.'/images/wow/Interface/Spellbook/'.$_.'.png border=0 float=center margin=15]';
@@ -260,8 +260,8 @@ class SpellPage extends GenericPage
$this->gcd = Util::formatTime($this->subject->getField('startRecoveryTime'));
$this->gcdCat = null; // todo (low): nyi; find out how this works [n/a; normal; ..]
$this->school = [Util::asHex($this->subject->getField('schoolMask')), Lang::getMagicSchools($this->subject->getField('schoolMask'))];
- $this->dispel = Lang::game('dt', $this->subject->getField('dispelType'));
- $this->mechanic = Lang::game('me', $this->subject->getField('mechanic'));
+ $this->dispel = $this->subject->getField('dispelType') ? Lang::game('dt', $this->subject->getField('dispelType')) : null;
+ $this->mechanic = $this->subject->getField('mechanic') ? Lang::game('me', $this->subject->getField('mechanic')) : null;
$this->unavailable = $this->subject->getField('cuFlags') & CUSTOM_UNAVAILABLE;
$this->redButtons = $redButtons;
@@ -302,6 +302,37 @@ class SpellPage extends GenericPage
$j = [null, 'A', 'B', 'C'];
+ // tab: abilities [of shapeshift form]
+ for ($i = 1; $i < 4; $i++)
+ {
+ if ($this->subject->getField('effect'.$i.'AuraId') != 36)
+ continue;
+
+ $formSpells = DB::Aowow()->selectRow('SELECT spellId1, spellId2, spellId3, spellId4, spellId5, spellId6, spellId7, spellId8 FROM ?_shapeshiftforms WHERE id = ?d', $this->subject->getField('effect'.$i.'MiscValue'));
+ if (!$formSpells)
+ continue;
+
+ $abilities = new SpellList(array(['id', $formSpells]));
+ if (!$abilities->error)
+ {
+ if (!$abilities->hasSetFields(['skillLines']))
+ $abH = "$['skill']";
+
+ $this->lvTabs[] = array(
+ 'file' => 'spell',
+ 'data' => $abilities->getListviewData(),
+ 'params' => array(
+ 'id' => 'controlledabilities',
+ 'name' => '$LANG.tab_controlledabilities',
+ 'visibleCols' => "$['level']",
+ 'hiddenCols' => isset($abH) ? $abH : null
+ )
+ );
+
+ $this->extendGlobalData($abilities->getJSGlobals(GLOBALINFO_SELF));
+ }
+ }
+
// tab: modifies $this
$sub = ['OR'];
$conditions = [
@@ -778,15 +809,15 @@ class SpellPage extends GenericPage
$lvZones = $zones->getListviewData();
$this->extendGlobalData($zones->getJSGlobals());
- $lv = [];
+ $lv = [];
$parents = [];
+ $extra = false;
foreach ($areas as $a)
{
if (empty($lvZones[$a['area']]))
continue;
$condition = [];
- $extra = false;
if ($a['aura_spell'])
{
$this->extendGlobalIds(TYPE_SPELL, abs($a['aura_spell']));
@@ -957,7 +988,7 @@ class SpellPage extends GenericPage
{
$src = $this->subject->sources[$this->typeId][6];
$list = [];
- if (count($src) == 1 && $src[0] == 0) // multiple trainer
+ if (count($src) == 1 && $src[0] == 1) // multiple trainer
{
$tt = null;
// Professions
@@ -995,7 +1026,7 @@ class SpellPage extends GenericPage
if ($list)
{
- $tbTrainer = new CreatureList(array(CFG_SQL_LIMIT_NONE, ['ct.id', $list], ['ct.spawns', 0, '>'], ['ct.npcflag', 0x10, '&']));
+ $tbTrainer = new CreatureList(array(CFG_SQL_LIMIT_NONE, ['ct.id', $list], ['s.guid', NULL, '!'], ['ct.npcflag', 0x10, '&']));
if (!$tbTrainer->error)
{
$this->extendGlobalData($tbTrainer->getJSGlobals());
@@ -1171,14 +1202,15 @@ class SpellPage extends GenericPage
return false;
$item = DB::Aowow()->selectRow('
- SELECT name_loc0, name_loc2, name_loc3, name_loc6, name_loc8, id, iconString, quality,
+ SELECT name_loc0, name_loc2, name_loc3, name_loc6, name_loc8, i.id, ic.iconString, quality,
IF ( (spellId1 > 0 AND spellCharges1 < 0) OR
(spellId2 > 0 AND spellCharges2 < 0) OR
(spellId3 > 0 AND spellCharges3 < 0) OR
(spellId4 > 0 AND spellCharges4 < 0) OR
(spellId5 > 0 AND spellCharges5 < 0), 1, 0) AS consumed
- FROM ?_items
- WHERE id = ?d',
+ FROM ?_items i
+ LEFT JOIN ?_icons ic ON ic.id = i.displayId
+ WHERE i.id = ?d',
$_iId
);
@@ -1222,8 +1254,9 @@ class SpellPage extends GenericPage
SELECT reagent1, reagent2, reagent3, reagent4, reagent5, reagent6, reagent7, reagent8,
reagentCount1, reagentCount2, reagentCount3, reagentCount4, reagentCount5, reagentCount6, reagentCount7, reagentCount8,
name_loc0, name_loc2, name_loc3, name_loc6, name_loc8,
- id AS ARRAY_KEY, iconString
- FROM ?_spell
+ s.id AS ARRAY_KEY, iconString
+ FROM ?_spell s
+ JOIN ?_icons si ON iconId = si.id
WHERE (effect1CreateItemId = ?d AND effect1Id = 24)',// OR
// (effect2CreateItemId = ?d AND effect2Id = 24) OR
// (effect3CreateItemId = ?d AND effect3Id = 24)',
@@ -1528,7 +1561,7 @@ class SpellPage extends GenericPage
$foo['icon']['count'] = "'".($effBP + 1).'-'.$foo['icon']['count']."'";
}
// .. from spell
- else if (in_array($i, $spellIdx))
+ else if (in_array($i, $spellIdx) || $effId == 133)
{
$_ = $this->subject->getField('effect'.$i.'TriggerSpell');
if (!$_)
@@ -1779,7 +1812,7 @@ class SpellPage extends GenericPage
);
if ($st['creatureType'] > 0)
- $infobox[] = '[li]'.Lang::game('type').Lang::main('colon').Lang::game('ct', $st['creatureType']).'[/li]';
+ $infobox[] = Lang::game('type').Lang::main('colon').Lang::game('ct', $st['creatureType']);
if ($_ = $st['displayName'])
$bar = User::isInGroup(U_GROUP_EMPLOYEE) ? sprintf(Util::$dfnString, Lang::spell('_value').Lang::main('colon').$effMV, $_) : $_;
diff --git a/pages/spells.php b/pages/spells.php
index 84df1d76..fbbb0f1e 100644
--- a/pages/spells.php
+++ b/pages/spells.php
@@ -404,10 +404,10 @@ class SpellsPage extends GenericPage
$this->lvTabs[] = $tab;
// sort for dropdown-menus
- asort(Lang::game('ra'));
- asort(Lang::game('cl'));
- asort(Lang::game('sc'));
- asort(Lang::game('me'));
+ Lang::sort('game', 'ra');
+ Lang::sort('game', 'cl');
+ Lang::sort('game', 'sc');
+ Lang::sort('game', 'me');
}
protected function generateTitle()
@@ -418,7 +418,7 @@ class SpellsPage extends GenericPage
array_unshift($foo, Lang::spell('cat', $c[0], $c[1], $c[2]));
else if (isset($c[1]))
{
- $_ = in_array($c[0], [-2, -13, 7]) ? Lang::game('cl') : Lang::spell('cat', $c[0])];
+ $_ = in_array($c[0], [-2, -13, 7]) ? Lang::game('cl') : Lang::spell('cat', $c[0]);
array_unshift($foo, is_array($_[$c[1]]) ? $_[$c[1]][0] : $_[$c[1]]);
}
diff --git a/pages/title.php b/pages/title.php
index ae280a1c..e5de6125 100644
--- a/pages/title.php
+++ b/pages/title.php
@@ -4,11 +4,6 @@ if (!defined('AOWOW_REVISION'))
die('illegal access');
-/*
- icons: data/interface/calendar/calendar_[a-z]start.blp
-*/
-
-
// menuId 10: Title g_initPath()
// tabId 0: Database g_initHeader()
class TitlePage extends GenericPage
@@ -66,7 +61,7 @@ class TitlePage extends GenericPage
if ($g = $this->subject->getField('gender'))
$infobox[] = Lang::main('gender').Lang::main('colon').'[span class=icon-'.($g == 2 ? 'female' : 'male').']'.Lang::main('sex', $g).'[/span]';
- if ($e = $this->subject->getField('eventId'))
+ if ($e = $this->subject->getField('holidayId'))
$infobox[] = Lang::game('eventShort').Lang::main('colon').'[url=?event='.$e.']'.WorldEventList::getName($e).'[/url]';
/****************/
@@ -119,21 +114,24 @@ class TitlePage extends GenericPage
}
// tab: achievement source
- $acvs = new AchievementList(array(['ar.title_A', $this->typeId], ['ar.title_H', $this->typeId], 'OR'));
- if (!$acvs->error)
+ if ($aIds = DB::World()->selectCol('SELECT entry FROM achievement_reward WHERE title_A = ?d OR title_H = ?d', $this->typeId, $this->typeId))
{
- $this->extendGlobalData($acvs->getJSGlobals());
+ $acvs = new AchievementList(array(['id', $aIds]));
+ if (!$acvs->error)
+ {
+ $this->extendGlobalData($acvs->getJSGlobals());
- $this->lvTabs[] = array(
- 'file' => 'achievement',
- 'data' => $acvs->getListviewData(),
- 'params' => array(
- 'id' => 'reward-from-achievement',
- 'name' => '$LANG.tab_rewardfrom',
- 'visibleCols' => "$['category']",
- 'sort' => "$['reqlevel', 'name']"
- )
- );
+ $this->lvTabs[] = array(
+ 'file' => 'achievement',
+ 'data' => $acvs->getListviewData(),
+ 'params' => array(
+ 'id' => 'reward-from-achievement',
+ 'name' => '$LANG.tab_rewardfrom',
+ 'visibleCols' => "$['category']",
+ 'sort' => "$['reqlevel', 'name']"
+ )
+ );
+ }
}
// tab: criteria of (to be added by TC)
diff --git a/pages/zone.php b/pages/zone.php
index 84ecd1c1..85a6d3a7 100644
--- a/pages/zone.php
+++ b/pages/zone.php
@@ -40,9 +40,13 @@ class ZonePage extends GenericPage
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
// City
- if ($this->subject->getField('flags') & 0x200000 && !$this->subject->getField('parentArea'))
+ if ($this->subject->getField('flags') & 0x8 && !$this->subject->getField('parentArea'))
$infobox[] = Lang::zone('city');
+ // Auto repop
+ if ($this->subject->getField('flags') & 0x1000 && !$this->subject->getField('parentArea'))
+ $infobox[] = Lang::zone('autoRez');
+
// Level
if ($_ = $this->subject->getField('levelMin'))
{
@@ -53,7 +57,15 @@ class ZonePage extends GenericPage
}
// required Level
- // [li]Requires level 80[/li] || [li]Required levels: [tooltip=instancereqlevel_tip]80[/tooltip], [tooltip=lfgreqlevel_tip]80[/tooltip][/li]
+ if ($_ = $this->subject->getField('levelReq'))
+ {
+ if ($__ = $this->subject->getField('levelReqLFG'))
+ $buff = sprintf(Lang::zone('reqLevels'), $_, $__);
+ else
+ $buff = Lang::main('_reqLevel').Lang::main('colon').$_;
+
+ $infobox[] = $buff;
+ }
// Territory
$_ = $this->subject->getField('faction');
@@ -78,29 +90,59 @@ class ZonePage extends GenericPage
if ($_ = $this->subject->getField('maxPlayer'))
$infobox[] = Lang::zone('numPlayers').Lang::main('colon').($_ == -2 ? '10/25' : $_);
- // attunement
- // [li]Attunement: [quest=24712][/li]
+ // Attunement Quest/Achievements & Keys
+ if ($attmnt = $this->subject->getField('attunes'))
+ {
+ foreach ($attmnt as $type => $ids)
+ {
+ $this->extendGlobalIds($type, array_map('abs', $ids));
+ foreach ($ids as $id)
+ {
+ if ($type == TYPE_ITEM)
+ $infobox[] = Lang::zone('key', (int)($id < 0)).Lang::main('colon').'[item='.abs($id).']';
+ else
+ $infobox[] = Lang::zone('attunement', (int)($id < 0)).Lang::main('colon').'['.Util::$typeStrings[$type].'='.abs($id).']';
+ }
+ }
+ }
+
+ // Instances
+ if ($_ = DB::Aowow()->selectCol('SELECT id FROM ?_zones WHERE parentAreaId = ?d AND (flags & ?d) = 0', $this->typeId, CUSTOM_EXCLUDE_FOR_LISTVIEW))
+ {
+ $this->extendGlobalIds(TYPE_ZONE, $_);
+ $infobox[] = Lang::maps('Instances').Lang::main('colon')."\n[zone=".implode("], \n[zone=", $_).']';
+ }
// location (if instance)
- // [li]Location: [lightbox=map zone=210 pins=514883]Icecrown[/lightbox][/li]
+ if ($pa = $this->subject->getField('parentAreaId'))
+ {
+ $paO = new ZoneList(array(['id', $pa]));
+ if (!$paO->error)
+ {
+ $pins = str_pad($this->subject->getField('parentX') * 10, 3, '0', STR_PAD_LEFT) . str_pad($this->subject->getField('parentY') * 10, 3, '0', STR_PAD_LEFT);
+ $infobox[] = Lang::zone('location').Lang::main('colon').'[lightbox=map zone='.$pa.' pins='.$pins.']'.$paO->getField('name', true).'[/lightbox]';
+ }
+ }
- // Continent (if zone)
- // Continent: Outland
+/* has to be defined in an article, i think
- // instances in this zone
- // Instance: The Slave Pens, The Steamvault, The Underbog, Serpentshrine Cavern
-
- // faction(s) / Reputation Hub / Raid Faction
- // [li]Raid faction: [faction=1156][/li] || [li]Factions: [faction=1156]/[faction=1156][/li]
-
- // final boss
- // [li]Final boss: [icon preset=boss][npc=37226][/icon][/li]
+ // faction(s) / Reputation Hub / Raid Faction
+ // [li]Raid faction: [faction=1156][/li] || [li]Factions: [faction=1156]/[faction=1156][/li]
+ // final boss
+ // [li]Final boss: [icon preset=boss][npc=37226][/icon][/li]
+*/
/****************/
/* Main Content */
/****************/
+ if ($_ = $this->subject->getField('parentArea'))
+ {
+ $this->extraText = sprintf(Lang::zone('zonePartOf'), $_);
+ $this->extendGlobalIds(TYPE_ZONE, $_);
+ }
+
$oSpawns = DB::Aowow()->select('SELECT * FROM ?_spawns WHERE areaId = ?d AND type = ?d', $this->typeId, TYPE_OBJECT);
$conditions = [['id', array_column($oSpawns, 'typeId')]];
if (!User::isInGroup(U_GROUP_STAFF))
@@ -340,7 +382,7 @@ class ZonePage extends GenericPage
}
// preselect bosses for raids/dungeons
- if (in_array($this->subject->getField('areaType'), [1, 2]))
+ if (in_array($this->subject->getField('type'), [2, 3, 4, 5, 7, 8]))
$som['instance'] = true;
/*
@@ -368,10 +410,7 @@ class ZonePage extends GenericPage
);
/*
- - sub zones..?
- - parent zone..?
- associated with holiday?
- - spell_area ?
*/
/**************/
@@ -450,6 +489,123 @@ class ZonePage extends GenericPage
]
);
}
+
+ // tab: spells
+ if ($saData = DB::World()->select('SELECT * FROM spell_area WHERE area = ?d', $this->typeId))
+ {
+ $spells = new SpellList(array(['id', array_column($saData, 'spell')]));
+ if (!$spells->error)
+ {
+ $lvSpells = $spells->getListviewData();
+ $this->extendGlobalData($spells->getJSGlobals());
+
+ $extra = false;
+ foreach ($saData as $a)
+ {
+ if (empty($lvSpells[$a['spell']]))
+ continue;
+
+ $condition = [];
+ if ($a['aura_spell'])
+ {
+ $this->extendGlobalIds(TYPE_SPELL, abs($a['aura_spell']));
+ $condition[0][$this->typeId][] = [[$a['aura_spell'] > 0 ? CND_AURA : -CND_AURA, abs($a['aura_spell'])]];
+ }
+
+ if ($a['quest_start']) // status for quests needs work
+ {
+ $this->extendGlobalIds(TYPE_QUEST, $a['quest_start']);
+ $group = [];
+ for ($i = 0; $i < 7; $i++)
+ {
+ if (!($a['quest_start_status'] & (1 << $i)))
+ continue;
+
+ if ($i == 0)
+ $group[] = [CND_QUEST_NONE, $a['quest_start']];
+ else if ($i == 1)
+ $group[] = [CND_QUEST_COMPLETE, $a['quest_start']];
+ else if ($i == 3)
+ $group[] = [CND_QUESTTAKEN, $a['quest_start']];
+ else if ($i == 6)
+ $group[] = [CND_QUESTREWARDED, $a['quest_start']];
+ }
+
+ if ($group)
+ $condition[0][$this->typeId][] = $group;
+ }
+
+ if ($a['quest_end'] && $a['quest_end'] != $a['quest_start'])
+ {
+ $this->extendGlobalIds(TYPE_QUEST, $a['quest_end']);
+ $group = [];
+ for ($i = 0; $i < 7; $i++)
+ {
+ if (!($a['quest_end_status'] & (1 << $i)))
+ continue;
+
+ if ($i == 0)
+ $group[] = [-CND_QUEST_NONE, $a['quest_end']];
+ else if ($i == 1)
+ $group[] = [-CND_QUEST_COMPLETE, $a['quest_end']];
+ else if ($i == 3)
+ $group[] = [-CND_QUESTTAKEN, $a['quest_end']];
+ else if ($i == 6)
+ $group[] = [-CND_QUESTREWARDED, $a['quest_end']];
+ }
+
+ if ($group)
+ $condition[0][$this->typeId][] = $group;
+ }
+
+ if ($a['racemask'])
+ {
+ $foo = [];
+ for ($i = 0; $i < 11; $i++)
+ if ($a['racemask'] & (1 << $i))
+ $foo[] = $i + 1;
+
+ $this->extendGlobalIds(TYPE_RACE, $foo);
+ $condition[0][$this->typeId][] = [[CND_RACE, $a['racemask']]];
+ }
+
+ if ($a['gender'] != 2) // 2: both
+ $condition[0][$this->typeId][] = [[CND_GENDER, $a['gender'] + 1]];
+
+ if ($condition)
+ {
+ $extra = true;
+ $lvSpells[$a['spell']] = array_merge($lvSpells[$a['spell']], ['condition' => $condition]);
+ }
+ }
+
+ $this->lvTabs[] = array(
+ 'file' => 'spell',
+ 'data' => $lvSpells,
+ 'params' => array(
+ 'extraCols' => $extra ? '$[Listview.extraCols.condition]' : null,
+ 'hiddenCols' => "$['skill']"
+ )
+ );
+ }
+ }
+
+ // tab: subzones
+ $subZones = new ZoneList(array(['parentArea', $this->typeId]));
+ if (!$subZones->error)
+ {
+ $this->lvTabs[] = array(
+ 'file' => 'zone',
+ 'data' => $subZones->getListviewData(),
+ 'params' => [
+ 'name' => '$LANG.tab_zones',
+ 'id' => 'subzones',
+ 'hiddenCols' => "$['territory', 'instancetype']"
+ ]
+ );
+
+ $this->extendGlobalData($subZones->getJSGlobals(GLOBALINFO_SELF));
+ }
}
protected function generatePath()
diff --git a/pages/zones.php b/pages/zones.php
index 5ffc31e7..af16e7ef 100644
--- a/pages/zones.php
+++ b/pages/zones.php
@@ -56,15 +56,12 @@ class ZonesPage extends GenericPage
case 8: $mapFile = -2; $spawnMap = 530; break;
case 10: $mapFile = -5; $spawnMap = 571; break;
}
-
- $hiddenCols[] = 'instancetype';
}
switch ($this->category[0])
{
case 6:
case 2:
- case 2:
case 3:
array_push($visibleCols, 'level', 'players');
case 9:
@@ -75,6 +72,8 @@ class ZonesPage extends GenericPage
$zones = new ZoneList($conditions);
+ if (!$zones->hasSetFields(['type']))
+ $hiddenCols[] = 'instancetype';
if ($visibleCols)
$params['visibleCols'] = "$['".implode("', '", $visibleCols)."']";
diff --git a/setup/db_setup_1.zip b/setup/db_setup_1.zip
deleted file mode 100644
index ffc77049..00000000
Binary files a/setup/db_setup_1.zip and /dev/null differ
diff --git a/setup/db_setup_2.zip b/setup/db_setup_2.zip
deleted file mode 100644
index 73145f0a..00000000
Binary files a/setup/db_setup_2.zip and /dev/null differ
diff --git a/setup/db_setup_3.zip b/setup/db_setup_3.zip
deleted file mode 100644
index 94d0a701..00000000
Binary files a/setup/db_setup_3.zip and /dev/null differ
diff --git a/setup/db_structure.7z b/setup/db_structure.7z
new file mode 100644
index 00000000..93801e31
Binary files /dev/null and b/setup/db_structure.7z differ
diff --git a/setup/setup.php b/setup/setup.php
index 9015024d..8cd69c94 100644
--- a/setup/setup.php
+++ b/setup/setup.php
@@ -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!', '- '.str_replace($cwDir, '', $path).'\\'.implode($reqFiles, '.dbc
- '.str_replace($cwDir, '', $path).'\\').'.dbc
');
-}
-
-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:*/
- 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= : 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= : 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();
+}
?>
diff --git a/setup/tools/CLISetup.class.php b/setup/tools/CLISetup.class.php
new file mode 100644
index 00000000..df3dfdff
--- /dev/null
+++ b/setup/tools/CLISetup.class.php
@@ -0,0 +1,401 @@
+ 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;
+ }
+}
+
+?>
diff --git a/setup/tools/clisetup/account.func.php b/setup/tools/clisetup/account.func.php
new file mode 100644
index 00000000..2ca70a85
--- /dev/null
+++ b/setup/tools/clisetup/account.func.php
@@ -0,0 +1,62 @@
+ ['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);
+ }
+}
+
+?>
diff --git a/setup/tools/clisetup/build.func.php b/setup/tools/clisetup/build.func.php
new file mode 100644
index 00000000..941c6553
--- /dev/null
+++ b/setup/tools/clisetup/build.func.php
@@ -0,0 +1,118 @@
+ 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:*/
+ 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);
+}
+
+?>
diff --git a/setup/tools/clisetup/dbconfig.func.php b/setup/tools/clisetup/dbconfig.func.php
new file mode 100644
index 00000000..cf9af00a
--- /dev/null
+++ b/setup/tools/clisetup/dbconfig.func.php
@@ -0,0 +1,142 @@
+ ['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('');
+
+ 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 = " $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;
+ }
+ }
+ }
+}
+
+?>
diff --git a/setup/tools/clisetup/siteconfig.func.php b/setup/tools/clisetup/siteconfig.func.php
new file mode 100644
index 00000000..da93c325
--- /dev/null
+++ b/setup/tools/clisetup/siteconfig.func.php
@@ -0,0 +1,318 @@
+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('');
+ else
+ {
+ $info = explode(' - ', $data['comment']);
+
+ if ($data['flags'] & CON_FLAG_TYPE_BOOL)
+ $buff .= '[bool] '.($data['value'] ? '' : '');
+ 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'] ? '' : '';
+ 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;
+ }
+ }
+}
+
+?>
diff --git a/setup/tools/clisetup/sql.func.php b/setup/tools/clisetup/sql.func.php
new file mode 100644
index 00000000..ad30dfcf
--- /dev/null
+++ b/setup/tools/clisetup/sql.func.php
@@ -0,0 +1,52 @@
+
diff --git a/setup/tools/dbc.class.php b/setup/tools/dbc.class.php
index 72a72573..ad4170c1 100644
--- a/setup/tools/dbc.class.php
+++ b/setup/tools/dbc.class.php
@@ -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);
}
diff --git a/setup/tools/fileGen.class.php b/setup/tools/fileGen.class.php
new file mode 100644
index 00000000..88c93a16
--- /dev/null
+++ b/setup/tools/fileGen.class.php
@@ -0,0 +1,211 @@
+ ['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= [-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;
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/filegen/complexImg.func.php b/setup/tools/filegen/complexImg.func.php
index 7b0d11c5..068b94a5 100644
--- a/setup/tools/filegen/complexImg.func.php
+++ b/setup/tools/filegen/complexImg.func.php
@@ -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;
}
diff --git a/setup/tools/filegen/enchants.func.php b/setup/tools/filegen/enchants.func.php
index 61a5bc4b..040b5e8f 100644
--- a/setup/tools/filegen/enchants.func.php
+++ b/setup/tools/filegen/enchants.func.php
@@ -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;
}
diff --git a/setup/tools/filegen/fileGen.class.php b/setup/tools/filegen/fileGen.class.php
deleted file mode 100644
index 41021881..00000000
--- a/setup/tools/filegen/fileGen.class.php
+++ /dev/null
@@ -1,423 +0,0 @@
- 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 = '%s';
-
- 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 "".$msg."
\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= [-h --help] [--log logfile] [-f --force] [--mpqDataDir=path/to/mpqData/] [--locales=]\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";
- }
-}
-
-?>
\ No newline at end of file
diff --git a/setup/tools/filegen/gems.func.php b/setup/tools/filegen/gems.func.php
index 50bbc9bd..68f6723e 100644
--- a/setup/tools/filegen/gems.func.php
+++ b/setup/tools/filegen/gems.func.php
@@ -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;
}
diff --git a/setup/tools/filegen/glyphs.func.php b/setup/tools/filegen/glyphs.func.php
index dbaf8b3a..b8688200 100644
--- a/setup/tools/filegen/glyphs.func.php
+++ b/setup/tools/filegen/glyphs.func.php
@@ -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;
}
diff --git a/setup/tools/filegen/itemsets.func.php b/setup/tools/filegen/itemsets.func.php
index 14820b00..e3c053e1 100644
--- a/setup/tools/filegen/itemsets.func.php
+++ b/setup/tools/filegen/itemsets.func.php
@@ -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;
}
diff --git a/setup/tools/filegen/locales.func.php b/setup/tools/filegen/locales.func.php
index 24eb2a31..69a07859 100644
--- a/setup/tools/filegen/locales.func.php
+++ b/setup/tools/filegen/locales.func.php
@@ -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];
diff --git a/setup/tools/filegen/pets.func.php b/setup/tools/filegen/pets.func.php
index af06d3ac..64ac91bb 100644
--- a/setup/tools/filegen/pets.func.php
+++ b/setup/tools/filegen/pets.func.php
@@ -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;
}
diff --git a/setup/tools/filegen/profiler.func.php b/setup/tools/filegen/profiler.func.php
index 7ea99bc1..f739f5f2 100644
--- a/setup/tools/filegen/profiler.func.php
+++ b/setup/tools/filegen/profiler.func.php
@@ -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
diff --git a/setup/tools/filegen/realmMenu.func.php b/setup/tools/filegen/realmMenu.func.php
index ba9b90fb..aac92394 100644
--- a/setup/tools/filegen/realmMenu.func.php
+++ b/setup/tools/filegen/realmMenu.func.php
@@ -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);
diff --git a/setup/tools/filegen/realms.func.php b/setup/tools/filegen/realms.func.php
index af251468..6cb0882a 100644
--- a/setup/tools/filegen/realms.func.php
+++ b/setup/tools/filegen/realms.func.php
@@ -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);
}
?>
diff --git a/setup/tools/filegen/simpleImg.func.php b/setup/tools/filegen/simpleImg.func.php
index b7ad71a6..924eaa13 100644
--- a/setup/tools/filegen/simpleImg.func.php
+++ b/setup/tools/filegen/simpleImg.func.php
@@ -1,13 +1,18 @@
$__)
{
- 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;
diff --git a/setup/tools/filegen/statistics.func.php b/setup/tools/filegen/statistics.func.php
index 084cdac7..318b995c 100644
--- a/setup/tools/filegen/statistics.func.php
+++ b/setup/tools/filegen/statistics.func.php
@@ -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;
diff --git a/setup/tools/filegen/talentIcons.func.php b/setup/tools/filegen/talentIcons.func.php
index 30546328..949a2d9c 100644
--- a/setup/tools/filegen/talentIcons.func.php
+++ b/setup/tools/filegen/talentIcons.func.php
@@ -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;
}
}
diff --git a/setup/tools/filegen/talents.func.php b/setup/tools/filegen/talents.func.php
index 6cbda54b..7ce062a2 100644
--- a/setup/tools/filegen/talents.func.php
+++ b/setup/tools/filegen/talents.func.php
@@ -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;
}
diff --git a/setup/tools/imagecreatefromblp.php b/setup/tools/imagecreatefromblp.func.php
similarity index 90%
rename from setup/tools/imagecreatefromblp.php
rename to setup/tools/imagecreatefromblp.func.php
index 4c319b56..dd226ed7 100644
--- a/setup/tools/imagecreatefromblp.php
+++ b/setup/tools/imagecreatefromblp.func.php
@@ -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;
}
diff --git a/setup/tools/sql/_item.php b/setup/tools/sql/_item.php
deleted file mode 100644
index 2b350d82..00000000
--- a/setup/tools/sql/_item.php
+++ /dev/null
@@ -1,431 +0,0 @@
- 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);
- }
- }
-}
-
-?>
diff --git a/setup/tools/sql/_itemset.php b/setup/tools/sql/_itemset.php
deleted file mode 100644
index ff9e2745..00000000
--- a/setup/tools/sql/_itemset.php
+++ /dev/null
@@ -1,487 +0,0 @@
- 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');
-
-
-?>
-
-
-
-
-
-
-
-
-
- /
-
-
-
- 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 "set: ".$id." - conflict between item: ".$items[$piece['InventoryType']]." and item: ".$pId." choosing lower Id
" ;
- }
- 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 "set: ".$id." done
";
-}
-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 "set: ".$id." ilvl: ".$piece['ItemLevel']." - conflict between item: ".$items[$vId][$piece['InventoryType']]." and item: ".$pId." choosing lower Id
" ;
- 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 "set: ".$rId." done ".($vIds ? "as (".$rId.", ".implode(', ', $vIds).")" : null)."";
-}
-
-DB::Aowow()->query('REPLACE INTO aowow_itemset VALUES '.implode(', ', $query));
-
-?>
diff --git a/setup/tools/sql/_pet.php b/setup/tools/sql/_pet.php
deleted file mode 100644
index 5e5ea6ee..00000000
--- a/setup/tools/sql/_pet.php
+++ /dev/null
@@ -1,128 +0,0 @@
- -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);
- }
-}
-
-?>
diff --git a/setup/tools/sql/skills.sql b/setup/tools/sql/skills.sql
deleted file mode 100644
index 16f0f075..00000000
--- a/setup/tools/sql/skills.sql
+++ /dev/null
@@ -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;
diff --git a/setup/tools/sqlGen.class.php b/setup/tools/sqlGen.class.php
new file mode 100644
index 00000000..62668d11
--- /dev/null
+++ b/setup/tools/sqlGen.class.php
@@ -0,0 +1,198 @@
+ ['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= [-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);
+
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/achievement.func.php b/setup/tools/sqlgen/achievement.func.php
new file mode 100644
index 00000000..73d3cb18
--- /dev/null
+++ b/setup/tools/sqlgen/achievement.func.php
@@ -0,0 +1,66 @@
+ ['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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/classes.func.php b/setup/tools/sqlgen/classes.func.php
new file mode 100644
index 00000000..7853223f
--- /dev/null
+++ b/setup/tools/sqlgen/classes.func.php
@@ -0,0 +1,50 @@
+ ['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;
+}
+
+?>
diff --git a/setup/tools/sqlgen/creature.func.php b/setup/tools/sqlgen/creature.func.php
new file mode 100644
index 00000000..adc958b3
--- /dev/null
+++ b/setup/tools/sqlgen/creature.func.php
@@ -0,0 +1,145 @@
+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;
+}
+
+?>
diff --git a/setup/tools/sqlgen/currencies.func.php b/setup/tools/sqlgen/currencies.func.php
new file mode 100644
index 00000000..5d45b716
--- /dev/null
+++ b/setup/tools/sqlgen/currencies.func.php
@@ -0,0 +1,55 @@
+ ['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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/events.func.php b/setup/tools/sqlgen/events.func.php
new file mode 100644
index 00000000..b4d54813
--- /dev/null
+++ b/setup/tools/sqlgen/events.func.php
@@ -0,0 +1,52 @@
+select($eventQuery, $ids ?: DBSIMPLE_SKIP);
+
+ foreach ($events as $e)
+ DB::Aowow()->query('REPLACE INTO ?_events VALUES (?a)', array_values($e));
+
+ return true;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/factions.func.php b/setup/tools/sqlgen/factions.func.php
new file mode 100644
index 00000000..d30fe671
--- /dev/null
+++ b/setup/tools/sqlgen/factions.func.php
@@ -0,0 +1,129 @@
+ ['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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/factiontemplate.func.php b/setup/tools/sqlgen/factiontemplate.func.php
new file mode 100644
index 00000000..e49c5965
--- /dev/null
+++ b/setup/tools/sqlgen/factiontemplate.func.php
@@ -0,0 +1,38 @@
+query($query);
+
+ return true;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/holidays.func.php b/setup/tools/sqlgen/holidays.func.php
new file mode 100644
index 00000000..d1f6c7f7
--- /dev/null
+++ b/setup/tools/sqlgen/holidays.func.php
@@ -0,0 +1,59 @@
+ ['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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/icons.func.php b/setup/tools/sqlgen/icons.func.php
new file mode 100644
index 00000000..bb9134e0
--- /dev/null
+++ b/setup/tools/sqlgen/icons.func.php
@@ -0,0 +1,28 @@
+query($baseQuery);
+
+ return true;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/item_stats.func.php b/setup/tools/sqlgen/item_stats.func.php
new file mode 100644
index 00000000..72160672
--- /dev/null
+++ b/setup/tools/sqlgen/item_stats.func.php
@@ -0,0 +1,160 @@
+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;
+}
+
+?>
diff --git a/setup/tools/sqlgen/itemrandomenchant.func.php b/setup/tools/sqlgen/itemrandomenchant.func.php
new file mode 100644
index 00000000..725415a8
--- /dev/null
+++ b/setup/tools/sqlgen/itemrandomenchant.func.php
@@ -0,0 +1,27 @@
+query($query);
+
+ return true;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/items.func.php b/setup/tools/sqlgen/items.func.php
new file mode 100644
index 00000000..c4fc34f5
--- /dev/null
+++ b/setup/tools/sqlgen/items.func.php
@@ -0,0 +1,210 @@
+ ['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;
+}
+
+?>
diff --git a/setup/tools/sqlgen/itemset.func.php b/setup/tools/sqlgen/itemset.func.php
new file mode 100644
index 00000000..f82b84a5
--- /dev/null
+++ b/setup/tools/sqlgen/itemset.func.php
@@ -0,0 +1,365 @@
+ ['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. 14 (0.30% @ L80)
+ $descText[$loc] = preg_replace('/(\d+) .*?<\/small>/i', '\1', $descText[$loc]);
+ }
+
+ /****************************/
+ /* finalaize data and write */
+ /****************************/
+
+ foreach ($items as $vId => $vSet)
+ {
+ $note = 0;
+ foreach ($tagsById as $tag => $sets)
+ {
+ if (!in_array($setId, $sets))
+ continue;
+
+ $note = $tag;
+ }
+
+ if (!$note && $min > 120 && $classMask && $classMask != CLASS_MASK_ALL)
+ {
+ foreach ($tagsByNamePart as $tag => $strings)
+ {
+ foreach ($strings as $str)
+ {
+ if (isset($pieces[reset($vSet)]) && stripos($pieces[reset($vSet)]['name'], $str) === 0)
+ {
+ $note = $tag;
+ break 2;
+ }
+ }
+ }
+ }
+
+ $row = [];
+
+ $row[] = $vId < 0 ? --$virtualId : $setId;
+ $row[] = $setId; // refSetId
+ $row[] = 0; // cuFlags
+ $row = array_merge($row, $name, $vSet);
+ foreach (array_column($spells, 0) as $spellId)
+ $row[] = $spellId;
+ foreach (array_column($spells, 1) as $nItems)
+ $row[] = $nItems;
+ $row = array_merge($row, $descText);
+ $row[] = serialize($gains);
+ $row[] = $nPieces[$vId];
+ $row[] = $min[$vId];
+ $row[] = $max[$vId];
+ $row[] = $reqLvl[$vId];
+ $row[] = $classMask == CLASS_MASK_ALL ? 0 : $classMask;
+ $row[] = !empty($heroic[$vId]) ? 1 : 0;
+ $row[] = $quality[$vId];
+ $row[] = $type;
+ $row[] = $note; // contentGroup
+ $row[] = $holiday;
+ $row[] = $setData['reqSkillId'];
+ $row[] = $setData['reqSkillLevel'];
+
+ DB::Aowow()->query('REPLACE INTO ?_itemset VALUES (?a)', array_values($row));
+ }
+ }
+
+ // hide empty sets
+ DB::Aowow()->query('UPDATE ?_itemset SET cuFlags = cuFlags | ?d WHERE item1 = 0', CUSTOM_EXCLUDE_FOR_LISTVIEW);
+
+ return true;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/objects.func.php b/setup/tools/sqlgen/objects.func.php
new file mode 100644
index 00000000..9c0b2e69
--- /dev/null
+++ b/setup/tools/sqlgen/objects.func.php
@@ -0,0 +1,106 @@
+ 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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/pet.func.php b/setup/tools/sqlgen/pet.func.php
new file mode 100644
index 00000000..b79eace3
--- /dev/null
+++ b/setup/tools/sqlgen/pet.func.php
@@ -0,0 +1,125 @@
+ -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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/quests.func.php b/setup/tools/sqlgen/quests.func.php
new file mode 100644
index 00000000..358c403e
--- /dev/null
+++ b/setup/tools/sqlgen/quests.func.php
@@ -0,0 +1,203 @@
+ 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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/quests_startend.func.php b/setup/tools/sqlgen/quests_startend.func.php
new file mode 100644
index 00000000..ce1ec56a
--- /dev/null
+++ b/setup/tools/sqlgen/quests_startend.func.php
@@ -0,0 +1,54 @@
+ 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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/races.func.php b/setup/tools/sqlgen/races.func.php
new file mode 100644
index 00000000..c94c5be9
--- /dev/null
+++ b/setup/tools/sqlgen/races.func.php
@@ -0,0 +1,47 @@
+ 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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/shapeshiftforms.func.php b/setup/tools/sqlgen/shapeshiftforms.func.php
new file mode 100644
index 00000000..a03b1f3c
--- /dev/null
+++ b/setup/tools/sqlgen/shapeshiftforms.func.php
@@ -0,0 +1,28 @@
+ ['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;
+}
+
+?>
diff --git a/setup/tools/sqlgen/skillline.func.php b/setup/tools/sqlgen/skillline.func.php
new file mode 100644
index 00000000..03fa245f
--- /dev/null
+++ b/setup/tools/sqlgen/skillline.func.php
@@ -0,0 +1,58 @@
+ ['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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/source.func.php b/setup/tools/sqlgen/source.func.php
new file mode 100644
index 00000000..e290876f
--- /dev/null
+++ b/setup/tools/sqlgen/source.func.php
@@ -0,0 +1,1195 @@
+ 0 && $item['spelltrigger_2'] == 6)
+ return $item['spellid_2'];
+
+ // deprecated system
+ if ($item['spellid_1'] != 483 && $item['spellid_1'] != 55884 && $item['spellid_1'] > 0 && $item['spelltrigger_1'] == 0)
+ return $item['spellid_1'];
+
+ return 0;
+ }
+
+ // cant update existing rows
+ if ($ids)
+ DB::Aowow()->query('DELETE FROM ?_source WHERE `type` = ?d AND typeId IN (?a)', $well, $wellll);
+ else
+ DB::Aowow()->query('TRUNCATE TABLE ?_source');
+
+
+ /***************************/
+ /* Item & inherited Spells */
+ /***************************/
+
+ CLISetup::log(' - Items & Spells [inherited]');
+ # also everything from items that teach spells, is src of spell
+ # todo: check if items have learn-spells (effect: 36)
+
+ CLISetup::log(' * resolve ref-loot tree');
+ $refLoot = DB::World()->select('
+ SELECT
+ rlt.Entry AS ARRAY_KEY,
+ IF(Reference, -Reference, Item) AS ARRAY_KEY2,
+ it.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2,
+ COUNT(1) AS qty
+ FROM
+ reference_loot_template rlt
+ LEFT JOIN
+ item_template it ON rlt.Reference = 0 AND rlt.Item = it.entry
+ GROUP BY
+ ARRAY_KEY, ARRAY_KEY2
+ ');
+
+ $hasChanged = true;
+ while ($hasChanged)
+ {
+ $hasChanged = false;
+ foreach ($refLoot as $entry => &$refData)
+ {
+ foreach ($refData as $itemOrRef => $data)
+ {
+ if ($itemOrRef > 0)
+ continue;
+
+ if (!empty($refLoot[-$itemOrRef]))
+ {
+ foreach ($refLoot[-$itemOrRef] AS $key => $data)
+ {
+ if (!empty($refData[$key]))
+ $refData[$key]['qty'] += $data['qty'];
+ else
+ $refLoot[-$itemOrRef][$key] = $data;
+ }
+ }
+
+ unset($refData[$itemOrRef]);
+ $hasChanged = true;
+ }
+ }
+ }
+
+
+ ###############
+ # 1: Crafted #
+ ###############
+ CLISetup::log(' * #1 Crafted');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $itemSpells = DB::Aowow()->selectCol('
+ SELECT
+ effect1CreateItemId AS ARRAY_KEY, s.id AS spell
+ FROM
+ dbc_spell s JOIN dbc_skilllineability sla ON s.id = sla.spellId
+ WHERE
+ effect1CreateItemId > 0 AND sla.skillLineId IN (?a)
+ GROUP BY
+ ARRAY_KEY',
+ [164, 165, 171, 182, 186, 197, 202, 333, 393, 755, 773, 129, 185, 356, 762]
+ );
+ $spellItems = DB::World()->select('SELECT entry AS ARRAY_KEY, class, subclass, spellid_1, spelltrigger_1, spellid_2, spelltrigger_2 FROM item_template WHERE entry IN (?a)', array_keys($itemSpells));
+
+ foreach ($spellItems as $iId => $si)
+ {
+ if ($_ = taughtSpell($si))
+ $spellBuff[$_] = [TYPE_SPELL, $_, 1, TYPE_SPELL, $itemSpells[$iId]];
+
+ $itemBuff[$iId] = [TYPE_ITEM, $iId, 1, TYPE_SPELL, $itemSpells[$iId]];
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 1, 1, 1);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 1, 1, 1);
+
+
+ ############
+ # 2: Drop #
+ ############
+ CLISetup::log(' * #2 Drop');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $creatureLoot = DB::World()->select('
+ SELECT
+ IF(clt.Reference > 0, -clt.Reference, clt.Item) AS ARRAY_KEY,
+ ct.entry,
+ it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2,
+ count(1) AS qty
+ FROM
+ creature_loot_template clt
+ JOIN
+ creature_template ct ON clt.entry = ct.lootid
+ LEFT JOIN
+ item_template it ON it.entry = clt.Item AND clt.Reference <= 0
+ WHERE
+ ct.lootid > 0
+ GROUP BY
+ ARRAY_KEY
+ ');
+
+ foreach ($creatureLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry'] /*, $lootmode */);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry'] /*, $lootmode */);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry'] /*, $lootmode */);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry'] /*, $lootmode */);
+ }
+
+ $objectOT = [];
+ $exclLocks = DB::Aowow()->selectCol('SELECT id FROM dbc_lock WHERE properties1 IN (2, 3)');
+ $objectLoot = DB::World()->select('
+ SELECT
+ IF(glt.Reference > 0, -glt.Reference, glt.Item) AS ARRAY_KEY,
+ gt.entry,
+ it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2,
+ count(1) AS qty
+ FROM
+ gameobject_loot_template glt
+ JOIN
+ gameobject_template gt ON glt.entry = gt.data1
+ LEFT JOIN
+ item_template it ON it.entry = glt.Item AND glt.Reference <= 0
+ WHERE
+ `type` = 3 AND gt.data1 > 0 AND gt.data0 NOT IN (?a)
+ GROUP BY
+ ARRAY_KEY',
+ $exclLocks
+ );
+
+ foreach ($objectLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']);
+
+ $objectOT[] = $iId;
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']);
+
+ $objectOT[] = $roi;
+ pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']);
+ }
+
+ $itemOT = [];
+ $itemLoot = DB::World()->select('
+ SELECT
+ IF(ilt.Reference > 0, -ilt.Reference, ilt.Item) AS ARRAY_KEY,
+ itA.entry,
+ itB.class, itB.subclass, itB.spellid_1, itB.spelltrigger_1, itB.spellid_2, itB.spelltrigger_2,
+ count(1) AS qty
+ FROM
+ item_loot_template ilt
+ JOIN
+ item_template itA ON ilt.entry = itA.entry
+ LEFT JOIN
+ item_template itB ON itB.entry = ilt.Item AND ilt.Reference <= 0
+ WHERE
+ itA.flags & 0x4
+ GROUP BY
+ ARRAY_KEY
+ ');
+
+ foreach ($itemLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_ITEM, $l['entry']);
+
+ $itemOT[] = $iId;
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_ITEM, $l['entry']);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_ITEM, $l['entry']);
+
+ $itemOT[] = $roi;
+ pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_ITEM, $l['entry']);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 2, 2, 2);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 2, 2, 2);
+
+ DB::Aowow()->query('UPDATE ?_items SET cuFLags = cuFlags | ?d WHERE id IN (?a)', ITEM_CU_OT_ITEMLOOT, $itemOT);
+ DB::Aowow()->query('UPDATE ?_items SET cuFLags = cuFlags | ?d WHERE id IN (?a)', ITEM_CU_OT_OBJECTLOOT, $objectOT);
+
+
+ ###########
+ # 3: PvP # (Vendors w/ xCost Arena/Honor)
+ ###########
+ CLISetup::log(' * #3 PvP');
+
+// var g_sources_pvp = {
+ // 1: 'Arena',
+ // 2: 'Battleground',
+ // 4: 'World' basicly the tokens you get for openPvP .. manual data
+// };
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $xCostH = DB::Aowow()->selectCol('SELECT Id FROM dbc_itemextendedcost WHERE reqHonorPoints > 0 AND reqArenaPoints = 0');
+ $xCostA = DB::Aowow()->selectCol('SELECT Id FROM dbc_itemextendedcost WHERE reqArenaPoints > 0');
+ $vendorQuery = 'SELECT n.item AS ARRAY_KEY, SUM(n.qty) AS qty, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2 FROM (
+ SELECT item, COUNT(1) AS qty FROM npc_vendor WHERE ExtendedCost IN (?a) GROUP BY item
+ UNION
+ SELECT item, COUNT(1) AS qty FROM game_event_npc_vendor genv JOIN creature c ON c.guid = genv.guid WHERE ExtendedCost IN (?a) GROUP BY item
+ ) n JOIN item_template it ON it.entry = n.item
+ GROUP BY item';
+
+ foreach (DB::World()->select($vendorQuery, $xCostA, $xCostA) as $iId => $v)
+ {
+ if ($_ = taughtSpell($v))
+ $spellBuff[$_] = [TYPE_SPELL, $_, 1];
+
+ $itemBuff[$iId] = [TYPE_ITEM, $iId, 1];
+ }
+
+ foreach (DB::World()->select($vendorQuery, $xCostH, $xCostH) as $iId => $v)
+ {
+ if ($_ = taughtSpell($v))
+ $spellBuff[$_] = [TYPE_SPELL, $_, 2];
+
+ $itemBuff[$iId] = [TYPE_ITEM, $iId, 2];
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insBasic), 3, 3, 3);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insBasic), 3, 3, 3);
+
+
+ #############
+ # 4: Quest #
+ #############
+ CLISetup::log(' * #4 Quest');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $quests = DB::World()->select(
+ 'SELECT n.item AS ARRAY_KEY, n.Id AS quest, SUM(n.qty) AS qty, BIT_OR(n.side) AS side, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2 FROM (
+ SELECT rewardChoiceItemId1 AS item, Id, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE rewardChoiceItemId1 > 0 GROUP BY item UNION
+ SELECT rewardChoiceItemId2 AS item, Id, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE rewardChoiceItemId2 > 0 GROUP BY item UNION
+ SELECT rewardChoiceItemId3 AS item, Id, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE rewardChoiceItemId3 > 0 GROUP BY item UNION
+ SELECT rewardChoiceItemId4 AS item, Id, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE rewardChoiceItemId4 > 0 GROUP BY item UNION
+ SELECT rewardChoiceItemId5 AS item, Id, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE rewardChoiceItemId5 > 0 GROUP BY item UNION
+ SELECT rewardChoiceItemId6 AS item, Id, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE rewardChoiceItemId6 > 0 GROUP BY item UNION
+ SELECT rewardItemId1 AS item, Id, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE rewardItemId1 > 0 GROUP BY item UNION
+ SELECT rewardItemId2 AS item, Id, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE rewardItemId2 > 0 GROUP BY item UNION
+ SELECT rewardItemId3 AS item, Id, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE rewardItemId3 > 0 GROUP BY item UNION
+ SELECT rewardItemId4 AS item, Id, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE rewardItemId4 > 0 GROUP BY item
+ ) n JOIN item_template it ON it.entry = n.item
+ GROUP BY item'
+ );
+ foreach ($quests as $iId => $q)
+ {
+ if ($_ = taughtSpell($q))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $q['qty'] > 1 ? 0 : TYPE_QUEST, $q['quest'], $q['side']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $q['qty'] > 1 ? 0 : TYPE_QUEST, $q['quest'], $q['side']);
+ }
+
+ $mailLoot = DB::World()->select('
+ SELECT
+ IF(mlt.Reference > 0, -mlt.Reference, mlt.Item) AS ARRAY_KEY,
+ qt.Id AS entry,
+ it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2,
+ count(1) AS qty,
+ BIT_OR(IF(qt.RequiredRaces & 0x2B2 AND !(qt.RequiredRaces & 0x44D), 2, IF(qt.RequiredRaces & 0x44D AND !(qt.RequiredRaces & 0x2B2), 1, 3))) AS side
+ FROM
+ mail_loot_template mlt
+ JOIN
+ quest_template qt ON qt.RewardMailTemplateId = mlt.entry
+ LEFT JOIN
+ item_template it ON it.entry = mlt.Item AND mlt.Reference <= 0
+ WHERE
+ qt.RewardMailTemplateId > 0
+ GROUP BY
+ ARRAY_KEY
+ ');
+
+ foreach ($mailLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_QUEST, $l['entry'], $l['side']);
+
+ $itemOT[] = $iId;
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_QUEST, $l['entry'], $l['side']);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_QUEST, $l['entry'], $l['side']);
+
+ $itemOT[] = $roi;
+ pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_QUEST, $l['entry'], $l['side']);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 4, 4, 4);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 4, 4, 4);
+
+
+ ##############
+ # 5: Vendor # (w/o xCost Arena/Honor)
+ ##############
+ CLISetup::log(' * #5 Vendor');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $xCostIds = DB::Aowow()->selectCol('SELECT Id FROM dbc_itemextendedcost WHERE reqHonorPoints <> 0 OR reqArenaPoints <> 0');
+ $vendors = DB::World()->select(
+ 'SELECT n.item AS ARRAY_KEY, n.npc, SUM(n.qty) AS qty, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2 FROM (
+ SELECT item, entry AS npc, COUNT(1) AS qty FROM npc_vendor WHERE ExtendedCost NOT IN (?a) GROUP BY item
+ UNION
+ SELECT item, c.id AS npc, COUNT(1) AS qty FROM game_event_npc_vendor genv JOIN creature c ON c.guid = genv.guid WHERE ExtendedCost NOT IN (?a) GROUP BY item
+ ) n JOIN item_template it ON it.entry = n.item
+ GROUP BY item',
+ $xCostIds,
+ $xCostIds
+ );
+
+ foreach ($vendors as $iId => $v)
+ {
+ if ($_ = taughtSpell($v))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $v['qty'] > 1 ? 0 : TYPE_NPC, $v['npc']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $v['qty'] > 1 ? 0 : TYPE_NPC, $v['npc']);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 5, 5, 5);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 5, 5, 5);
+
+
+ ###############
+ # 10: Starter #
+ ###############
+ CLISetup::log(' * #10 Starter');
+
+ if ($pcii = DB::World()->select('SELECT ?d, itemid, 1 FROM playercreateinfo_item', TYPE_ITEM))
+ DB::Aowow()->query(queryfy('[V]', $pcii, $insBasic), 10, 10, 10);
+
+ for ($i = 1; $i < 21; $i++)
+ DB::Aowow()->query($insSub, 10, DB::Aowow()->subquery('SELECT ?d, item?d, 1, NULL AS m, NULL AS mt FROM dbc_charstartoutfit WHERE item?d > 0', TYPE_ITEM, $i, $i), 10, 10);
+
+
+ ###################
+ # 12: Achievement #
+ ###################
+ CLISetup::log(' * #12 Achievement');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $xItems = DB::Aowow()->select('SELECT id AS entry, itemExtra AS ARRAY_KEY, COUNT(1) AS qty FROM ?_achievement WHERE itemExtra > 0 GROUP BY itemExtra');
+ $rewItems = DB::World()->select('
+ SELECT
+ src.item AS ARRAY_KEY,
+ src.entry,
+ it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2,
+ COUNT(1) AS qty
+ FROM (
+ SELECT IFNULL(IF(mlt.Reference > 0, -mlt.Reference, mlt.Item), ar.item) AS item, ar.entry
+ FROM achievement_reward ar LEFT JOIN mail_loot_template mlt ON mlt.entry = ar.mailTemplate
+ WHERE ar.mailTemplate > 0 OR ar.item > 0
+ ) src
+ LEFT JOIN
+ item_template it ON src.item = it.entry
+ GROUP BY
+ ARRAY_KEY
+ ');
+
+ $extraItems = DB::World()->select('SELECT entry AS ARRAY_KEY, class, subclass, spellid_1, spelltrigger_1, spellid_2, spelltrigger_2 FROM item_template WHERE entry IN (?a)', array_keys($xItems));
+ foreach ($extraItems as $iId => $l)
+ {
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $xItems[$iId]['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $xItems[$iId]['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $xItems[$iId]['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $xItems[$iId]['entry']);
+ }
+
+ foreach ($rewItems as $iId => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $l['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $l['entry']);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $l['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $l['entry']);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 12, 12, 12);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 12, 12, 12);
+
+
+ ####################
+ # 15: Disenchanted #
+ ####################
+ CLISetup::log(' * #15 Disenchanted');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $deLoot = DB::World()->select('
+ SELECT
+ IF(dlt.Reference > 0, -dlt.Reference, dlt.Item) AS ARRAY_KEY,
+ itA.entry,
+ itB.class, itB.subclass, itB.spellid_1, itB.spelltrigger_1, itB.spellid_2, itB.spelltrigger_2,
+ count(1) AS qty
+ FROM
+ disenchant_loot_template dlt
+ JOIN
+ item_template itA ON dlt.entry = itA.DisenchantId
+ LEFT JOIN
+ item_template itB ON itB.entry = dlt.Item AND dlt.Reference <= 0
+ WHERE
+ itA.DisenchantId > 0
+ GROUP BY
+ ARRAY_KEY
+ ');
+
+ foreach ($deLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $roi);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 15, 15, 15);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 15, 15, 15);
+
+
+ ##############
+ # 16: Fished #
+ ##############
+ CLISetup::log(' * #16 Fished');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $fishLoot = DB::World()->select('
+ SELECT
+ src.itemOrRef AS ARRAY_KEY,
+ src.entry,
+ it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2,
+ count(1) AS qty
+ FROM (
+ SELECT 0 AS entry, IF(flt.Reference > 0, -flt.Reference, flt.Item) itemOrRef FROM fishing_loot_template flt UNION
+ SELECT gt.entry, IF(glt.Reference > 0, -glt.Reference, glt.Item) itemOrRef FROM gameobject_template gt JOIN gameobject_loot_template glt ON glt.entry = gt.data1 WHERE `type` = 25 AND gt.data1 > 0
+ ) src
+ LEFT JOIN
+ item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry
+ GROUP BY
+ ARRAY_KEY
+ ');
+
+ foreach ($fishLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 16, 16, 16);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 16, 16, 16);
+
+
+ ################
+ # 17: Gathered #
+ ################
+ CLISetup::log(' * #17 Gathered');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $herbLocks = DB::Aowow()->selectCol('SELECT id FROM dbc_lock WHERE properties1 = 2');
+ $herbLoot = DB::World()->select('
+ SELECT
+ src.itemOrRef AS ARRAY_KEY,
+ src.entry,
+ it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2,
+ count(1) AS qty,
+ src.srcType
+ FROM (
+ SELECT ct.entry, IF(slt.Reference > 0, -slt.Reference, slt.Item) itemOrRef, ?d AS srcType FROM creature_template ct JOIN skinning_loot_template slt ON slt.entry = ct.skinloot WHERE (type_flags & ?d) AND ct.skinloot > 0 UNION
+ SELECT gt.entry, IF(glt.Reference > 0, -glt.Reference, glt.Item) itemOrRef, ?d AS srcType FROM gameobject_template gt JOIN gameobject_loot_template glt ON glt.entry = gt.data1 WHERE gt.`type` = 3 AND gt.data1 > 0 AND data0 IN (?a)
+ ) src
+ LEFT JOIN
+ item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry
+ GROUP BY
+ ARRAY_KEY',
+ TYPE_NPC, NPC_TYPEFLAG_HERBLOOT,
+ TYPE_OBJECT, $herbLocks
+ );
+
+ foreach ($herbLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : $l['srcType'], $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : $l['srcType'], $l['entry']);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : $l['srcType'], $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : $l['srcType'], $l['entry']);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 17, 17, 17);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 17, 17, 17);
+
+
+ ##############
+ # 18: Milled #
+ ##############
+ CLISetup::log(' * #18 Milled');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $millLoot = DB::World()->select('
+ SELECT
+ IF(mlt.Reference > 0, -mlt.Reference, mlt.Item) AS ARRAY_KEY,
+ itA.entry,
+ itB.class, itB.subclass, itB.spellid_1, itB.spelltrigger_1, itB.spellid_2, itB.spelltrigger_2,
+ count(1) AS qty
+ FROM
+ milling_loot_template mlt
+ JOIN
+ item_template itA ON mlt.entry = itA.entry
+ LEFT JOIN
+ item_template itB ON itB.entry = mlt.Item AND mlt.Reference <= 0
+ GROUP BY
+ ARRAY_KEY
+ ');
+
+ foreach ($millLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $roi);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 18, 18, 18);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 18, 18, 18);
+
+
+ #############
+ # 19: Mined #
+ #############
+ CLISetup::log(' * #19 Mined');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $mineLocks = DB::Aowow()->selectCol('SELECT id FROM dbc_lock WHERE properties1 = 3');
+ $mineLoot = DB::World()->select('
+ SELECT
+ src.itemOrRef AS ARRAY_KEY,
+ src.entry,
+ it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2,
+ count(1) AS qty,
+ src.srcType
+ FROM (
+ SELECT ct.entry, IF(slt.Reference > 0, -slt.Reference, slt.Item) itemOrRef, ?d AS srcType FROM creature_template ct JOIN skinning_loot_template slt ON slt.entry = ct.skinloot WHERE (type_flags & ?d) AND ct.skinloot > 0 UNION
+ SELECT gt.entry, IF(glt.Reference > 0, -glt.Reference, glt.Item) itemOrRef, ?d AS srcType FROM gameobject_template gt JOIN gameobject_loot_template glt ON glt.entry = gt.data1 WHERE gt.`type` = 3 AND gt.data1 > 0 AND data0 IN (?a)
+ ) src
+ LEFT JOIN
+ item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry
+ GROUP BY
+ ARRAY_KEY',
+ TYPE_NPC, NPC_TYPEFLAG_MININGLOOT,
+ TYPE_OBJECT, $mineLocks
+ );
+
+ foreach ($mineLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : $l['srcType'], $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : $l['srcType'], $l['entry']);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : $l['srcType'], $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : $l['srcType'], $l['entry']);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 19, 19, 19);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 19, 19, 19);
+
+
+ ##################
+ # 20: Prospected #
+ ##################
+ CLISetup::log(' * #20 Prospected');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $prospectLoot = DB::World()->select('
+ SELECT
+ IF(plt.Reference > 0, -plt.Reference, plt.Item) AS ARRAY_KEY,
+ itA.entry,
+ itB.class, itB.subclass, itB.spellid_1, itB.spelltrigger_1, itB.spellid_2, itB.spelltrigger_2,
+ count(1) AS qty
+ FROM
+ prospecting_loot_template plt
+ JOIN
+ item_template itA ON plt.entry = itA.entry
+ LEFT JOIN
+ item_template itB ON itB.entry = plt.Item AND plt.Reference <= 0
+ GROUP BY
+ ARRAY_KEY
+ ');
+
+ foreach ($prospectLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $roi);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 20, 20, 20);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 20, 20, 20);
+
+
+ ##################
+ # 21: Pickpocket #
+ ##################
+ CLISetup::log(' * #21 Pickpocket');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $theftLoot = DB::World()->select('
+ SELECT
+ src.itemOrRef AS ARRAY_KEY,
+ src.entry,
+ it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2,
+ COUNT(1) AS qty
+ FROM (
+ SELECT ct.entry, IF(plt.Reference > 0, -plt.Reference, plt.Item) itemOrRef FROM creature_template ct JOIN pickpocketing_loot_template plt ON plt.entry = ct.pickpocketloot WHERE ct.pickpocketloot > 0
+ ) src
+ LEFT JOIN
+ item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry
+ GROUP BY
+ ARRAY_KEY
+ ');
+
+ foreach ($theftLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 21, 21, 21);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 21, 21, 21);
+
+
+ ################
+ # 22: Salvaged #
+ ################
+ CLISetup::log(' * #22 Salvaged');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $salvageLoot = DB::World()->select('
+ SELECT
+ src.itemOrRef AS ARRAY_KEY,
+ src.entry,
+ it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2,
+ COUNT(1) AS qty
+ FROM (
+ SELECT ct.entry, IF(slt.Reference > 0, -slt.Reference, slt.Item) itemOrRef FROM creature_template ct JOIN skinning_loot_template slt ON slt.entry = ct.skinloot WHERE (type_flags & ?d) AND ct.skinloot > 0
+ ) src
+ LEFT JOIN
+ item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry
+ GROUP BY
+ ARRAY_KEY',
+ NPC_TYPEFLAG_ENGINEERLOOT
+ );
+
+ foreach ($salvageLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 22, 22, 22);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 22, 22, 22);
+
+ ###############
+ # 23: Skinned #
+ ###############
+ CLISetup::log(' * #23 Skinned');
+
+ $spellBuff = [];
+ $itemBuff = [];
+ $skinLoot = DB::World()->select('
+ SELECT
+ src.itemOrRef AS ARRAY_KEY,
+ src.entry,
+ it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2,
+ COUNT(1) AS qty
+ FROM (
+ SELECT ct.entry, IF(slt.Reference > 0, -slt.Reference, slt.Item) itemOrRef FROM creature_template ct JOIN skinning_loot_template slt ON slt.entry = ct.skinloot WHERE (type_flags & ?d) = 0 AND ct.skinloot > 0
+ ) src
+ LEFT JOIN
+ item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry
+ GROUP BY
+ ARRAY_KEY',
+ (NPC_TYPEFLAG_HERBLOOT | NPC_TYPEFLAG_MININGLOOT | NPC_TYPEFLAG_ENGINEERLOOT)
+ );
+
+ foreach ($skinLoot as $roi => $l)
+ {
+ if ($roi < 0 && !empty($refLoot[-$roi]))
+ {
+ foreach ($refLoot[-$roi] as $iId => $r)
+ {
+ if ($_ = taughtSpell($r))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']);
+ }
+
+ continue;
+ }
+
+ if ($_ = taughtSpell($l))
+ pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']);
+
+ pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']);
+ }
+
+ if ($itemBuff)
+ DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 23, 23, 23);
+
+ if ($spellBuff)
+ DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 23, 23, 23);
+
+
+
+ /*********/
+ /* Spell */
+ /*********/
+
+ CLISetup::log(' - Spells [original]');
+
+ # 4: Quest
+ CLISetup::log(' * #4 Quest');
+ $quests = DB::World()->select('
+ SELECT spell AS ARRAY_KEY, id, SUM(qty) AS qty, BIT_OR(side) AS side FROM (
+ SELECT IF(rewardSpellCast = 0, rewardSpell, rewardSpellCast) AS spell, Id, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE IF(rewardSpellCast = 0, rewardSpell, rewardSpellCast) > 0 GROUP BY spell
+ UNION
+ SELECT SourceSpellId AS spell, Id, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE SourceSpellId > 0 GROUP BY spell
+ ) t GROUP BY spell');
+
+ if ($quests)
+ {
+ $qSpells = DB::Aowow()->select('SELECT id AS ARRAY_KEY, effect1Id, effect2Id, effect3Id, effect1TriggerSpell, effect2TriggerSpell, effect3TriggerSpell FROM dbc_spell WHERE id IN (?a) AND (effect1Id = 36 OR effect2Id = 36 OR effect3Id = 36)', array_keys($quests));
+ $buff = [];
+
+ foreach ($qSpells as $sId => $spell)
+ {
+ for ($i = 1; $i <= 3; $i++)
+ {
+ if ($spell['effect'.$i.'Id'] != 36) // effect: learnSpell
+ continue;
+
+ pushBuffer($buff, TYPE_SPELL, $spell['effect'.$i.'TriggerSpell'], $quests[$sId]['qty'] > 1 ? 0 : TYPE_QUEST, $quests[$sId]['qty'] > 1 ? 0 : $quests[$sId]['id'], $quests[$sId]['side']);
+ }
+ }
+
+ DB::Aowow()->query(queryfy('[V]', $buff, $insMore), 4, 4, 4);
+ }
+
+ # 6: Trainer
+ CLISetup::log(' * #6 Trainer');
+ if ($tNpcs = DB::World()->select('SELECT spell AS ARRAY_KEY, entry, COUNT(1) AS qty FROM npc_trainer WHERE spell > 0 GROUP BY ARRAY_KEY'))
+ {
+ $tSpells = DB::Aowow()->select('SELECT Id AS ARRAY_KEY, effect1Id, effect2Id, effect3Id, effect1TriggerSpell, effect2TriggerSpell, effect3TriggerSpell FROM dbc_spell WHERE Id IN (?a)', array_keys($tNpcs));
+ $buff = [];
+
+ // todo (med): this skips some spells (e.g. riding)
+ foreach ($tNpcs as $spellId => $npc)
+ {
+ if (!isset($tSpells[$spellId]))
+ continue;
+
+ $effects = $tSpells[$spellId];
+ $trainerId = $npc['entry'] > 200000 || $npc['qty'] > 1 ? null : $npc['entry'];
+
+ $triggered = false;
+ for ($i = 1; $i <= 3; $i++)
+ {
+ if ($effects['effect'.$i.'Id'] != 36) // effect: learnSpell
+ continue;
+
+ $triggered = true;
+ pushBuffer($buff, TYPE_SPELL, $effects['effect'.$i.'TriggerSpell'], $trainerId ? TYPE_NPC : 0, $trainerId);
+ }
+
+ if (!$triggered)
+ pushBuffer($buff, TYPE_SPELL, $spellId, $trainerId ? TYPE_NPC : 0, $trainerId);
+ }
+
+ DB::Aowow()->query(queryfy('[V]', $buff, $insMore), 6, 6, 6);
+ }
+
+ # 7: Discovery
+ CLISetup::log(' * #7 Discovery');
+ // 61756: Northrend Inscription Research (FAST QA VERSION);
+ if ($disco = DB::World()->select('SELECT ?d, spellId, 1 FROM skill_discovery_template WHERE reqSpell <> ?d', TYPE_SPELL, 61756))
+ DB::Aowow()->query(queryfy('[V]', $disco, $insBasic), 7, 7, 7);
+
+ # 9: Talent
+ CLISetup::log(' * #9 Talent');
+ $tSpells = DB::Aowow()->select('
+ SELECT s.Id AS ARRAY_KEY, s.effect1Id, s.effect2Id, s.effect3Id, s.effect1TriggerSpell, s.effect2TriggerSpell, s.effect3TriggerSpell
+ FROM dbc_talent t
+ JOIN dbc_spell s ON s.Id = t.rank1
+ WHERE t.rank2 < 1 AND (t.talentSpell = 1 OR (s.effect1Id = 36 OR s.effect2Id = 36 OR s.effect3Id = 36))
+ ');
+
+ $n = 0;
+ $buff = [];
+ while ($tSpells)
+ {
+ CLISetup::log(' - '.++$n.'. pass');
+
+ $recurse = [];
+ foreach ($tSpells as $tId => $spell)
+ {
+ for ($i = 1; $i <= 3; $i++)
+ if ($spell['effect'.$i.'Id'] == 36) // effect: learnSpell
+ $recurse[$spell['effect'.$i.'TriggerSpell']] = $tId;
+
+ if (array_search($tId, $recurse))
+ unset($tSpells[$tId]);
+ }
+
+ foreach ($tSpells as $tId => $__)
+ $buff[$tId] = [TYPE_SPELL, $tId, 1];
+
+ if (!$recurse)
+ break;
+
+ $tSpells = DB::Aowow()->select('SELECT Id AS ARRAY_KEY, effect1Id, effect2Id, effect3Id, effect1TriggerSpell, effect2TriggerSpell, effect3TriggerSpell FROM dbc_spell WHERE Id IN (?a)', array_keys($recurse));
+ }
+
+ DB::Aowow()->query(queryfy('[V]', $buff, $insBasic), 9, 9, 9);
+
+ # 10: Starter
+ CLISetup::log(' * #10 Starter');
+ /* acquireMethod
+ ABILITY_LEARNED_ON_GET_PROFESSION_SKILL = 1, learnedAt = 1 && source10 = 1
+ ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL = 2 not used for now
+ */
+
+ $subSkills = DB::Aowow()->subquery('SELECT ?d, spellId, 1, NULL AS m, NULL AS mt FROM dbc_skilllineability WHERE acquireMethod = 1 AND (reqSkillLevel = 1 OR skillLineId = 129) GROUP BY spellId', TYPE_SPELL);
+ DB::Aowow()->query($insSub, 10, $subSkills, 10, 10);
+
+ if ($pcis = DB::World()->select('SELECT ?d, Spell, 1 FROM playercreateinfo_spell', TYPE_SPELL))
+ DB::Aowow()->query(queryfy('[V]', $pcis, $insBasic), 10, 10, 10);
+
+
+ /**********/
+ /* Titles */
+ /**********/
+
+ CLISetup::log(' - Titles');
+
+ # 4: Quest
+ CLISetup::log(' * #4 Quest');
+ if ($quests = DB::World()->select('SELECT ?d, RewardTitleId, 1, ?d, Id FROM quest_template WHERE RewardTitleId > 0', TYPE_TITLE, TYPE_QUEST))
+ DB::Aowow()->query(queryfy('[V]', $quests, $insMore), 4, 4, 4);
+
+ # 12: Achievement
+ CLISetup::log(' * #12 Achievement');
+ $sets = DB::World()->select('
+ SELECT ?d, IF (title_A <> 0, title_A, title_H) AS title, 1, ?d, entry FROM achievement_reward WHERE title_A <> 0 OR title_H <> 0 GROUP BY title
+ UNION
+ SELECT ?d, title_H AS title, 1, ?d, entry FROM achievement_reward WHERE title_A <> title_H AND title_A <> 0 AND title_H <> 0',
+ TYPE_TITLE, TYPE_ACHIEVEMENT,
+ TYPE_TITLE, TYPE_ACHIEVEMENT
+ );
+ if ($sets)
+ DB::Aowow()->query(queryfy('[V]', $sets, $insMore), 12, 12, 12);
+
+ # 13: Source-String
+ CLISetup::log(' * #13 cuStrings');
+ $src13 = [null, 42, 52, 71, 80, 157, 163, 167, 169, 177];
+ foreach ($src13 as $src => $tId)
+ if ($tId)
+ DB::Aowow()->query(queryfy('[V]', [[TYPE_TITLE, $tId, $src]], $insBasic), 13, 13, 13);
+
+ return true;
+}
+
+?>
diff --git a/setup/tools/sqlgen/spawns.func.php b/setup/tools/sqlgen/spawns.func.php
new file mode 100644
index 00000000..af7463fb
--- /dev/null
+++ b/setup/tools/sqlgen/spawns.func.php
@@ -0,0 +1,260 @@
+= 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;
+}
+
+?>
diff --git a/setup/tools/sqlgen/spell.func.php b/setup/tools/sqlgen/spell.func.php
new file mode 100644
index 00000000..60ef5423
--- /dev/null
+++ b/setup/tools/sqlgen/spell.func.php
@@ -0,0 +1,736 @@
+ -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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/spelldifficulty.func.php b/setup/tools/sqlgen/spelldifficulty.func.php
new file mode 100644
index 00000000..a58ea721
--- /dev/null
+++ b/setup/tools/sqlgen/spelldifficulty.func.php
@@ -0,0 +1,32 @@
+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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/taxi.func.php b/setup/tools/sqlgen/taxi.func.php
new file mode 100644
index 00000000..0ae0a125
--- /dev/null
+++ b/setup/tools/sqlgen/taxi.func.php
@@ -0,0 +1,173 @@
+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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/titles.func.php b/setup/tools/sqlgen/titles.func.php
new file mode 100644
index 00000000..1ea1aaa4
--- /dev/null
+++ b/setup/tools/sqlgen/titles.func.php
@@ -0,0 +1,97 @@
+ ['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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/sqlgen/zones.func.php b/setup/tools/sqlgen/zones.func.php
new file mode 100644
index 00000000..064229b7
--- /dev/null
+++ b/setup/tools/sqlgen/zones.func.php
@@ -0,0 +1,231 @@
+ ['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;
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/trigger_example.txt b/setup/tools/trigger_example.txt
new file mode 100644
index 00000000..74a512a3
--- /dev/null
+++ b/setup/tools/trigger_example.txt
@@ -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__delete BEFORE DELETE ON
+ FOR EACH ROW
+ BEGIN
+ REPLACE INTO aowow_sync (`table`, `entry`, `action`) VALUES ('', OLD.entry, 0);
+ END;
+|
+
+CREATE TRIGGER aowow_sync__insert AFTER INSERT ON
+ FOR EACH ROW
+ BEGIN
+ REPLACE INTO aowow_sync (`table`, `entry`, `action`) VALUES ('', NEW.entry, 1);
+ END;
+|
+
+CREATE TRIGGER aowow_sync__update AFTER UPDATE ON
+ FOR EACH ROW
+ BEGIN
+ REPLACE INTO aowow_sync (`table`, `entry`, `action`) VALUES ('', NEW.entry, 2);
+ END;
+|
+
+delimiter ;
diff --git a/static/js/locale_dede.js b/static/js/locale_dede.js
index b883d98b..aa4e10ee 100644
--- a/static/js/locale_dede.js
+++ b/static/js/locale_dede.js
@@ -1663,15 +1663,15 @@ var g_spell_skills = {
78: 'Schattenmagie',
95: 'Verteidigung',
98: 'Sprache: Gemeinsprache',
- 101: 'Zwergenvolk',
+ 101: 'Volk - Zwerge',
109: 'Sprache: Orcisch',
111: 'Sprache: Zwergisch',
113: 'Sprache: Darnassisch',
115: 'Sprache: Taurisch',
118: 'Beidhändigkeit',
- 124: 'Taurenvolk',
- 125: 'Orcvolk',
- 126: 'Nachtelfenvolk',
+ 124: 'Volk - Tauren',
+ 125: 'Volk - Orc',
+ 126: 'Volk - Nachtelfen',
129: 'Erste Hilfe',
134: 'Wilder Kampf',
136: 'Stäbe',
@@ -1700,37 +1700,37 @@ var g_spell_skills = {
184: 'Vergeltung',
185: 'Kochkunst',
186: 'Bergbau',
- 188: 'Tier - Wichtel',
- 189: 'Tier - Teufelsjäger',
+ 188: 'Begleiter - Wichtel',
+ 189: 'Begleiter - Teufelsjäger',
197: 'Schneiderei',
202: 'Ingenieurskunst',
- 203: 'Tier - Spinne',
- 204: 'Tier - Leerwandler',
- 205: 'Tier - Sukkubus',
- 206: 'Tier - Höllenbestie',
- 207: 'Tier - Verdammniswache',
- 208: 'Tier - Wolf',
- 209: 'Tier - Katze',
- 210: 'Tier - Bär',
- 211: 'Tier - Eber',
- 212: 'Tier - Krokilisk',
- 213: 'Tier - Aasvogel',
- 214: 'Tier - Krebs',
- 215: 'Tier - Gorilla',
- 217: 'Tier - Raptor',
- 218: 'Tier - Weitschreiter',
+ 203: 'Begleiter - Spinne',
+ 204: 'Begleiter - Leerwandler',
+ 205: 'Begleiter - Sukkubus',
+ 206: 'Begleiter - Höllenbestie',
+ 207: 'Begleiter - Verdammniswache',
+ 208: 'Begleiter - Wolf',
+ 209: 'Begleiter - Katze',
+ 210: 'Begleiter - Bär',
+ 211: 'Begleiter - Eber',
+ 212: 'Begleiter - Krokilisk',
+ 213: 'Begleiter - Aasvogel',
+ 214: 'Begleiter - Krebs',
+ 215: 'Begleiter - Gorilla',
+ 217: 'Begleiter - Raptor',
+ 218: 'Begleiter - Weitschreiter',
220: 'Volk - Untote',
226: 'Armbrüste',
228: 'Zauberstäbe',
229: 'Stangenwaffen',
- 236: 'Tier - Skorpid',
+ 236: 'Begleiter - Skorpid',
237: 'Arkan',
- 251: 'Tier - Schildkröte',
+ 251: 'Begleiter - Schildkröte',
253: 'Meucheln',
256: 'Furor',
257: 'Schutz',
267: 'Schutz',
- 270: 'Tier - Jäger allgemein',
+ 270: 'Begleiter - Jäger allgemein',
293: 'Plattenpanzer',
313: 'Sprache: Gnomisch',
315: 'Sprache: Trollisch',
@@ -1756,39 +1756,39 @@ var g_spell_skills = {
594: 'Heilig',
613: 'Disziplin',
633: 'Schlossknacken',
- 653: 'Tier - Fledermaus',
- 654: 'Tier - Hyäne',
- 655: 'Tier - Raubvogel',
- 656: 'Tier - Windnatter',
+ 653: 'Begleiter - Fledermaus',
+ 654: 'Begleiter - Hyäne',
+ 655: 'Begleiter - Raubvogel',
+ 656: 'Begleiter - Windnatter',
673: 'Sprache: Gossensprache',
713: 'Kodoreiten',
733: 'Volk - Trolle',
753: 'Volk - Gnome',
754: 'Volk - Menschen',
755: 'Juwelenschleifen',
- 756: 'Blutelfenvolk',
- 758: 'Tier - Ereignis Ferngesteuert',
+ 756: 'Volk - Blutelfen',
+ 758: 'Begleiter - Ereignis Ferngesteuert',
759: 'Sprache: Draenei',
- 760: 'Draeneivolk',
- 761: 'Tier - Teufelswache',
+ 760: 'Volk - Draenei',
+ 761: 'Begleiter - Teufelswache',
762: 'Reiten',
- 763: 'Tier - Drachenfalke',
- 764: 'Tier - Netherrochen',
- 765: 'Tier - Sporensegler',
- 766: 'Tier - Sphärenjäger',
- 767: 'Tier - Felshetzer',
- 768: 'Tier - Schlange',
+ 763: 'Begleiter - Drachenfalke',
+ 764: 'Begleiter - Netherrochen',
+ 765: 'Begleiter - Sporensegler',
+ 766: 'Begleiter - Sphärenjäger',
+ 767: 'Begleiter - Felshetzer',
+ 768: 'Begleiter - Schlange',
769: 'Intern',
770: 'Blut',
771: 'Frost',
772: 'Unheilig',
773: 'Inschriftenkunde',
- 775: 'Tier - Motte',
+ 775: 'Begleiter - Motte',
776: 'Runen schmieden',
777: 'Reittiere',
778: 'Begleiter',
- 780: 'Tier - Exotische Schimäre',
- 781: 'Tier - Exotischer Teufelssaurier',
+ 780: 'Begleiter - Exotische Schimäre',
+ 781: 'Begleiter - Exotischer Teufelssaurier',
782: 'Begleiter - Ghul',
783: 'Begleiter - Exotischer Silithid',
784: 'Begleiter - Exotischer Wurm',
@@ -1804,7 +1804,7 @@ var g_skill_categories = {
"-4": 'Völkerfertigkeiten',
5: 'Attribute',
6: 'Waffenfertigkeiten',
- 6: 'Klassenfertigkeiten',
+ 7: 'Klassenfertigkeiten',
8: 'Rüstungssachverstand',
9: 'Nebenberufe',
10: 'Sprachen',
diff --git a/static/js/locale_enus.js b/static/js/locale_enus.js
index 0e38f598..14be7ad5 100644
--- a/static/js/locale_enus.js
+++ b/static/js/locale_enus.js
@@ -1709,15 +1709,15 @@ var g_spell_skills = {
78: 'Shadow Magic',
95: 'Defense',
98: 'Language: Common',
- 101: 'Dwarven Racial',
+ 101: 'Racial - Dwarven',
109: 'Language: Orcish',
111: 'Language: Dwarven',
113: 'Language: Darnassian',
115: 'Language: Taurahe',
118: 'Dual Wield',
- 124: 'Tauren Racial',
- 125: 'Orc Racial',
- 126: 'Night Elf Racial',
+ 124: 'Racial - Tauren',
+ 125: 'Racial - Orc',
+ 126: 'Racial - Night Elf',
129: 'First Aid',
134: 'Feral Combat',
136: 'Staves',
@@ -1812,10 +1812,10 @@ var g_spell_skills = {
753: 'Racial - Gnome',
754: 'Racial - Human',
755: 'Jewelcrafting',
- 756: 'Blood Elf Racial',
+ 756: 'Racial - Blood Elf',
758: 'Pet - Event - Remote Control',
759: 'Language: Draenei',
- 760: 'Draenei Racial',
+ 760: 'Racial - Draenei',
761: 'Pet - Felguard',
762: 'Riding',
763: 'Pet - Dragonhawk',
diff --git a/static/js/locale_eses.js b/static/js/locale_eses.js
index 3cdaa4af..5ddd19b2 100644
--- a/static/js/locale_eses.js
+++ b/static/js/locale_eses.js
@@ -1664,15 +1664,15 @@ var g_spell_skills = {
78: 'Magia sombría',
95: 'Defensa',
98: 'Idioma: común',
- 101: 'Racial enano',
+ 101: 'Racial: enano',
109: 'Idioma: orco',
111: 'Idioma: enánico',
113: 'Idioma: darnassiano',
115: 'Idioma: taurahe',
118: 'Doble empuñadura',
- 124: 'Racial tauren',
- 125: 'Racial orco',
- 126: 'Racial elfo de la noche',
+ 124: 'Racial: tauren',
+ 125: 'Racial: orco',
+ 126: 'Racial: elfo de la noche',
129: 'Primeros auxilios',
134: 'Combate feral',
136: 'Bastones',
@@ -1767,10 +1767,10 @@ var g_spell_skills = {
753: 'Racial: gnomo',
754: 'Racial: humano',
755: 'Joyería',
- 756: 'Racial elfo de sangre',
+ 756: 'Racial: elfo de sangre',
758: 'Mascota - Evento - Control remoto',
759: 'Idioma: draenei',
- 760: 'Racial draenei',
+ 760: 'Racial: draenei',
761: 'Mascota: guardia vil',
762: 'Equitación',
763: 'Mascota: dracohalcón',
diff --git a/static/js/locale_frfr.js b/static/js/locale_frfr.js
index 60f947aa..738f351b 100644
--- a/static/js/locale_frfr.js
+++ b/static/js/locale_frfr.js
@@ -1651,24 +1651,24 @@ var g_spell_skills = {
56: 'Sacré',
78: 'Magie de l\'ombre',
95: 'Défense',
- 98: 'Langue : commun',
- 101: 'Raciale nain',
- 109: 'Langue : orc',
- 111: 'Langue : nain',
- 113: 'Langue : darnassien',
- 115: 'Langue : taurahe',
+ 98: 'Langue : commun',
+ 101: 'Racial - nain',
+ 109: 'Langue : orc',
+ 111: 'Langue : nain',
+ 113: 'Langue : darnassien',
+ 115: 'Langue : taurahe',
118: 'Ambidextrie',
- 124: 'Raciale tauren',
- 125: 'Raciale orc',
- 126: 'Raciale elfe de la nuit',
+ 124: 'Racial - tauren',
+ 125: 'Racial - orc',
+ 126: 'Racial - elfe de la nuit',
129: 'Secourisme',
134: 'Combat farouche',
136: 'Bâtons',
- 137: 'Langue : thalassien',
- 138: 'Langue : draconique',
- 139: 'Langue : démoniaque',
- 140: 'Langue : titan',
- 141: 'Langue : langue ancienne',
+ 137: 'Langue : thalassien',
+ 138: 'Langue : draconique',
+ 139: 'Langue : démoniaque',
+ 140: 'Langue : titan',
+ 141: 'Langue : langue ancienne',
142: 'Survie',
148: 'Equitation',
149: 'Monte de loup',
@@ -1749,16 +1749,16 @@ var g_spell_skills = {
654: 'Familier - hyène',
655: 'Familier - oiseau de proie',
656: 'Familier - serpent des vents',
- 673: 'Langue : bas-parler',
+ 673: 'Langue : bas-parler',
713: 'Monte de kodo',
733: 'Racial - troll',
753: 'Racial - gnome',
754: 'Racial - humain',
755: 'Joaillerie',
- 756: 'Raciale elfe de sang',
+ 756: 'Racial - elfe de sang',
758: 'Familier - Evénement - Télécommande',
- 759: 'Langue : draeneï',
- 760: 'Raciale draeneï',
+ 759: 'Langue : draeneï',
+ 760: 'Racial - draeneï',
761: 'Familier - gangregarde',
762: 'Monte',
763: 'Familier - faucon-dragon',
diff --git a/static/js/locale_ruru.js b/static/js/locale_ruru.js
index 7dcabb34..c174fec5 100644
--- a/static/js/locale_ruru.js
+++ b/static/js/locale_ruru.js
@@ -1689,37 +1689,37 @@ var g_spell_skills = {
184: 'Воздаяние',
185: 'Кулинария',
186: 'Горное дело',
- 188: 'Питомец: бес',
+ 188: 'Питомец - бес',
189: 'Прислужник: охотник Скверны',
197: 'Портняжное дело',
202: 'Инженерное дело',
- 203: 'Питомец: паук',
+ 203: 'Питомец - паук',
204: 'Прислужник: демон Бездны',
205: 'Прислужник: суккуб',
206: 'Прислужник: огненный голем',
207: 'Прислужник: Стражник Ужаса',
- 208: 'Питомец: волк',
- 209: 'Питомец: кошка',
- 210: 'Питомец: медведь',
- 211: 'Питомец: кабан',
+ 208: 'Питомец - волк',
+ 209: 'Питомец - кошка',
+ 210: 'Питомец - медведь',
+ 211: 'Питомец - кабан',
212: 'Питомец - кроколиск',
- 213: 'Питомец: падальщик',
- 214: 'Питомец: краб',
- 215: 'Питомец: горилла',
- 217: 'Питомец: ящер',
- 218: 'Питомец: долгоног',
+ 213: 'Питомец - падальщик',
+ 214: 'Питомец - краб',
+ 215: 'Питомец - горилла',
+ 217: 'Питомец - ящер',
+ 218: 'Питомец - долгоног',
220: 'Расовый навык нежити',
226: 'Арбалеты',
228: 'Жезлы',
229: 'Древковое оружие',
- 236: 'Питомец: скорпид',
+ 236: 'Питомец - скорпид',
237: 'Тайная магия',
- 251: 'Питомец: черепаха',
+ 251: 'Питомец - черепаха',
253: 'Ликвидация',
256: 'Неистовство',
257: 'Защита',
267: 'Защита',
- 270: 'Питомец: любой',
+ 270: 'Питомец - любой',
293: 'Латы',
313: 'Язык: гномский',
315: 'Язык: наречие троллей',
@@ -1745,15 +1745,15 @@ var g_spell_skills = {
594: 'Свет',
613: 'Послушание',
633: 'Взлом',
- 653: 'Питомец: летучая мышь',
- 654: 'Питомец: гиена',
+ 653: 'Питомец - летучая мышь',
+ 654: 'Питомец - гиена',
655: 'Питомец - сова',
- 656: 'Питомец: крылатый змей',
+ 656: 'Питомец - крылатый змей',
673: 'Язык: наречие нежити',
713: 'Езда на кодо',
733: 'Расовый навык троллей',
753: 'Расовый навык гномов',
- 754: 'Расовый: люди',
+ 754: 'Расовый люди',
755: 'Ювелирное дело',
756: 'Расовый навык эльфов крови',
758: 'Питомец - управление',
@@ -1761,12 +1761,12 @@ var g_spell_skills = {
760: 'Расовый навык дренея',
761: 'Прислужник: страж Скверны',
762: 'Верховая езда',
- 763: 'Питомец: дракондор',
- 764: 'Питомец: скат Пустоты',
- 765: 'Питомец: Спороскат',
- 766: 'Питомец: астральная игуана',
- 767: 'Питомец: опустошитель',
- 768: 'Питомец: змей',
+ 763: 'Питомец - дракондор',
+ 764: 'Питомец - скат Пустоты',
+ 765: 'Питомец - Спороскат',
+ 766: 'Питомец - астральная игуана',
+ 767: 'Питомец - опустошитель',
+ 768: 'Питомец - змей',
769: 'Внутренний',
770: 'Кровь',
771: 'Лед',
@@ -1783,8 +1783,8 @@ var g_spell_skills = {
784: 'Питомец - редкий червь',
785: 'Питомец - оса',
786: 'Питомец - редкий люторог',
- 787: 'Питомец: экзотическая гончая Недр',
- 788: 'Питомец: экзотический зверек'
+ 787: 'Питомец - экзотическая гончая Недр',
+ 788: 'Питомец - экзотический зверек'
};
var g_skill_categories = {
diff --git a/template/pages/items.tpl.php b/template/pages/items.tpl.php
index b83c6147..311475cf 100644
--- a/template/pages/items.tpl.php
+++ b/template/pages/items.tpl.php
@@ -55,7 +55,7 @@ if (!empty($f['type'])):
diff --git a/template/pages/spell.tpl.php b/template/pages/spell.tpl.php
index a6f529a9..fd58e553 100644
--- a/template/pages/spell.tpl.php
+++ b/template/pages/spell.tpl.php
@@ -47,7 +47,7 @@ if ($this->reagents[1]):
tools as $i => $t):
if (isset($t['itemId'])):
- echo " $WH.ge('iconlist-icon.".($i + 1)."').appendChild(g_items.createIcon(".$t['itemId'].", 0, 1));\n";
+ echo " \$WH.ge('iconlist-icon.".($i + 1)."').appendChild(g_items.createIcon(".$t['itemId'].", 0, 1));\n";
endif;
endforeach;
?>
@@ -90,7 +90,7 @@ endif;
|
- school[0], $this->school[1]) : $this->school[1]; ?> |
+ school[1]) ? (User::isInGroup(U_GROUP_STAFF) ? sprintf(Util::$dfnString, $this->school[0], $this->school[1]) : $this->school[1]) : ''.Lang::main('n_a').''; ?> |
|