added scripts to generate datasets and icon-textures for the talent-calculator

that should make everyone with some client-mods or custom database entires happy

removed previously supplied datasets (which were partially erronous anyway)

usage:
    - read the requirements per file and run via ?build=<filename> This may take up to several minutes, depending on the complexity and your machine

todo:
    - expects parsed dbcs in DB named "dbc" and world-DB to be named "world". Needs to be configurable
    - no error handling. If it fails, it fails badly.
    - pets: locations are inaccurate (see comment in file)
    - itemsets: the fragmented data in itemsets.dbc has to be fixed manually before this script yields propper results (see comment in file)
This commit is contained in:
Sarjuuk
2012-12-27 19:53:44 +01:00
parent 7c723068f5
commit 19d08d1d18
118 changed files with 1341 additions and 92769 deletions

View File

@@ -0,0 +1,234 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
// Create 'enchants'-file for available locales
// this script requires the following dbc-files to be parsed and available
// Spells, SkillLineAbility, SpellItemEnchantment
/* Examples
15: {
name:'Leichtes R<>stungsset',
quality:1,
icon:'INV_Misc_ArmorKit_17',
source:-2304,
skill:-1,
slots:525008,
enchantment:'Verst<73>rkt (+8 R<>stung)',
jsonequip:{"armor":8,"reqlevel":1},
temp:0,
classes:0,
gearscore:1
},
2928: {
name:'Ring - Zaubermacht',
quality:-1,
icon:'INV_Misc_Note_01',
source:27924,
skill:333,
slots:1024,
enchantment:'+12 Zaubermacht',
jsonequip:{"splpwr":12},
temp:0,
classes:0,
gearscore:15
},
3231: {
name:['Handschuhe - Waffenkunde','Armschiene - Waffenkunde'],
quality:-1,
icon:'spell_holy_greaterheal',
source:[44484,44598],
skill:333,
slots:[512,256],
enchantment:'+15 Waffenkundewertung',
jsonequip:{reqlevel:60,"exprtng":15},
temp:0,
classes:0,
gearscore:20 // nope, i'm not doing this
},
*/
include 'includes/class.spell.php';
include 'includes/class.item.php';
set_time_limit(300);
// from g_item_slots: 13:"One-Hand", 26:"Ranged", 17:"Two-Hand",
$slotPointer = [13, 17, 26, 26, 13, 17, 17, 13, 17, null, 17, null, null, 13, null, 13, null, null, null, null, 17];
$locales = [LOCALE_EN, LOCALE_FR, LOCALE_DE, LOCALE_ES, LOCALE_RU];
$enchantSpells = new SpellList([['effect1Id', '=', '53'], ['name_loc0', 'NOT LIKE', 'QA%']]); // enchantItemPermanent && !qualityAssurance
$castItems = array();
$jsonEnchants = array();
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!is_dir('datasets\\'.$dir))
mkdir('datasets\\'.$dir, 0755, true);
echo "script set up in ".Util::execTime()."<br>\n";
foreach ($locales as $lId)
{
User::useLocale($lId);
$enchantsOut = array();
foreach ($enchantSpells->spellList as $spl)
{
$enchant = DB::Aowow()->SelectRow('SELECT * FROM ?_itemEnchantment WHERE Id = ?d', $spl->template['effect1MiscValue']);
if (!$enchant) // 'shouldn't' happen
continue;
// slots have to be recalculated
$slot = 0;
if ($spl->template['equippedItemClass'] == 4) // armor
{
if ($invType = $spl->template['equippedItemInventoryTypeMask'])
$slot = $spl->template['equippedItemInventoryTypeMask'] >> 1;
else /* if (equippedItemSubClassMask == 64) */ // shields have it their own way <_<
$slot = (1 << (14 - 1));
}
else if ($spl->template['equippedItemClass'] == 2) // weapon
{
foreach ($slotPointer as $i => $sp)
{
if (!$sp)
continue;
if ((1 << $i) & $spl->template['equippedItemSubClassMask'])
{
if ($sp == 13) // also mainHand & offHand *siiigh*
$slot |= ((1 << (21 - 1)) | (1 << (22 - 1)));
$slot |= (1 << ($sp - 1));
}
}
}
// costy and locale-independant -> cache
if (!isset($jsonEnchants[$enchant['Id']]))
$jsonEnchants[$enchant['Id']] = Util::parseItemEnchantment($enchant);
// defaults
$ench = array(
'name' => [], // set by skill or item
'quality' => -1, // modified if item
'icon' => strToLower($spl->template['iconString']), // item over spell
'source' => [], // <0: item; >0:spell
'skill' => -1, // modified if skill
'slots' => [], // determied per spell but set per item
'enchantment' => Util::jsEscape(Util::localizedString($enchant, 'text')),
'jsonequip' => $jsonEnchants[$enchant['Id']],
'temp' => 0, // always 0
'classes' => 0, // modified by item
);
if ($enchant['skillLine'] > 0)
$ench['jsonequip']['reqskill'] = $enchant['skillLine'];
if ($enchant['skillLevel'] > 0)
$ench['jsonequip']['reqskillrank'] = $enchant['skillLevel'];
if ($enchant['requiredLevel'] > 0)
$ench['jsonequip']['reqlevel'] = $enchant['requiredLevel'];
// check if the spell has an entry in skill_line_ability -> Source:Profession
if ($skill = DB::Aowow()->SelectCell('SELECT skillId FROM ?_skill_line_ability WHERE spellId = ?d', $spl->Id))
{
$ench['name'][] = Util::jsEscape(Util::localizedString($spl->template, 'name'));
$ench['source'][] = $spl->Id;
$ench['skill'] = $skill;
$ench['slots'][] = $slot;
}
// check if this item can be cast via item -> Source:Item
if (!isset($castItems[$spl->Id]))
$castItems[$spl->Id] = new ItemList([['spellid_1', '=', $spl->Id], ['name', 'NOT LIKE', 'Scroll of Enchant%']]); // do not reuse enchantment scrolls
foreach ($castItems[$spl->Id]->itemList as $item)
{
$ench['name'][] = Util::jsEscape(Util::localizedString($item->template, 'name'));
$ench['source'][] = -$item->Id;
$ench['icon'] = strTolower($item->template['icon']);
$ench['slots'][] = $slot;
if ($item->template['Quality'] > $ench['quality'])
$ench['quality'] = $item->template['Quality'];
if ($item->template['AllowableClass'] > 0)
{
$ench['classes'] = $item->template['AllowableClass'];
$ench['jsonequip']['classes'] = $item->template['AllowableClass'];
}
if (!isset($ench['jsonequip']['reqlevel']))
if ($item->template['RequiredLevel'] > 0)
$ench['jsonequip']['reqlevel'] = $item->template['RequiredLevel'];
}
// enchant spell not in use
if (empty($ench['source']))
continue;
// everything gathered
if (isset($enchantsOut[$enchant['Id']])) // already found, append data
{
foreach ($enchantsOut[$enchant['Id']] as $k => $v)
{
if (is_array($v))
{
while ($pop = array_pop($ench[$k]))
$enchantsOut[$enchant['Id']][$k][] = $pop;
}
else
{
if ($k == 'quality') // quality:-1 if spells and items are mixed
{
if ($enchantsOut[$enchant['Id']]['source'][0] > 0 && $ench['source'][0] < 0)
$enchantsOut[$enchant['Id']][$k] = -1;
else if ($enchantsOut[$enchant['Id']]['source'][0] < 0 && $ench['source'][0] > 0)
$enchantsOut[$enchant['Id']][$k] = -1;
else
$enchantsOut[$enchant['Id']][$k] = $ench[$k];
}
else if ($enchantsOut[$enchant['Id']][$k] <= 0)
$enchantsOut[$enchant['Id']][$k] = $ench[$k];
}
}
}
else // nothing yet, create new
$enchantsOut[$enchant['Id']] = $ench;
}
// walk over each entry and strip single-item arrays
foreach ($enchantsOut as $eId => $ench)
{
foreach ($ench as $k => $v)
if (is_array($v) && count($v) == 1 && $k != 'jsonequip')
$enchantsOut[$eId][$k] = $v[0];
}
ksort($enchantsOut);
$toFile = "var g_enchants = ";
$toFile .= json_encode($enchantsOut, JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK);
$toFile .= ";";
$file = 'datasets\\'.User::$localeString.'\\enchants';
$handle = fOpen($file, "w");
fWrite($handle, $toFile);
fClose($handle);
echo "done enchants loc: ".$lId." in ".Util::execTime()."<br>\n";
}
echo "<br>\nall done";
User::useLocale(LOCALE_EN);
$stats = DB::Aowow()->getStatistics();
echo "<br>\n".$stats['count']." queries in: ".Util::formatTime($stats['time'] * 1000);
?>

View File

@@ -0,0 +1,108 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
// Create 'gems'-file for available locales
// this script requires the following dbc-files to be parsed and available
// ItemEnchantment, GemProperties, Spells, Icons
/* Example
22460: {
name:'Prismatic Sphere',
quality:3,
icon:'INV_Enchant_PrismaticSphere',
enchantment:'+3 Resist All',
jsonequip:{"arcres":3,"avgbuyout":242980,"firres":3,"frores":3,"holres":3,"natres":3,"shares":3},
colors:14,
expansion:1
gearscore:8 // as if.....
},
*/
// sketchy, but should work
// Id < 36'000 || ilevel < 70 ? BC : WOTLK
include 'includes/class.spell.php';
$gemQuery = "
SELECT
it.entry,
it.name,
li.*,
IF (it.entry < 36000 OR it.ItemLevel < 70, 1 , 2) AS expansion,
(it.Quality) AS quality,
i.iconname as icon,
ie.*,
gp.colorMask as colors
FROM
item_template it,
locales_item li,
?_gemProperties gp,
?_icons i,
?_itemEnchantment ie
WHERE
it.GemProperties <> 0 AND
li.entry = it.entry AND
gp.Id = it.GemProperties AND
i.Id = it.displayid AND
gp.itemEnchantmentId = ie.Id
ORDER BY
it.entry DESC
;
";
$gems = Db::Aowow()->Select($gemQuery);
$locales = [LOCALE_EN, LOCALE_FR, LOCALE_DE, LOCALE_ES, LOCALE_RU];
$jsonGems = [];
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!is_dir('datasets\\'.$dir))
mkdir('datasets\\'.$dir, 0755, true);
echo "script set up in ".Util::execTime()."<br>\n";
foreach ($locales as $lId)
{
User::useLocale($lId);
$gemsOut = [];
foreach ($gems as $pop)
{
// costy and locale-independant -> cache
if (!isset($jsonGems[$pop['entry']]))
$jsonGems[$pop['entry']] = Util::parseItemEnchantment($pop);
$gemsOut[$pop['entry']] = array(
'name' => Util::jsEscape(Util::localizedString($pop, 'name')),
'quality' => $pop['quality'],
'icon' => strToLower($pop['icon']),
'enchantment' => Util::jsEscape(Util::localizedString($pop, 'text')),
'jsonequip' => $jsonGems[$pop['entry']],
'colors' => $pop['colors'],
'expansion' => $pop['expansion']
);
}
$toFile = "var g_gems = ";
$toFile .= json_encode($gemsOut, JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK);
$toFile .= ";";
$file = 'datasets\\'.User::$localeString.'\\gems';
$handle = fOpen($file, "w");
fWrite($handle, $toFile);
fClose($handle);
echo "done gems loc: ".$lId." in ".Util::execTime()."<br>\n";
}
echo "<br>\nall done";
User::useLocale(LOCALE_EN);
$stats = DB::Aowow()->getStatistics();
echo "<br>\n".$stats['count']." queries in: ".Util::formatTime($stats['time'] * 1000);
?>

View File

@@ -0,0 +1,239 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
// Create 'glyphs'-file for available locales
// this script requires the following dbc-files to be parsed and available
// GlyphProperties, Spells, SkillLineAbility
/* Example
40896: {
"name":"Glyph of Frenzied Regeneration",
"description":"For 6 sec after activating Frenzied Regeneration, healing effects on you are 40% more powerful. However, your Frenzied Regeneration now always costs 60 Rage and no longer converts Rage into health.",
"icon":"ability_bullrush",
"type":1,
"classs":11,
"skill":798,
"level":25,
},
*/
$queryIcons = '
SELECT
s.Id,
name_loc0 as name,
sk.classMask,
sk.skillId,
s.iconString as icon
FROM
aowow_spell s
JOIN
aowow_skill_line_ability sk ON
sk.spellId = s.Id
WHERE
[WHERE]
LIMIT
1
';
$queryGlyphs = '
SELECT
i.entry as itemId,
i.name,
li.*,
IF (g.typeFlags & 0x1, 2, 1) as type,
i.subclass as classs,
i.requiredLevel as level,
s1.Id as glyphSpell,
s2.Id as glyphEffect
FROM
item_template i
LEFT JOIN
locales_item li ON
i.entry = li.entry
LEFT JOIN
?_spell s1 ON
s1.Id = i.spellid_1
LEFT JOIN
?_glyphProperties g ON
g.Id = s1.effect1MiscValue
LEFT JOIN
?_spell s2 ON
s2.Id = g.spellId
WHERE
i.class = 16
;
';
$class2Family = array(
8 => 3, // Mage
1 => 4, // Warrior
9 => 5, // Warlock
5 => 6, // Priest
11 => 7, // Druid
4 => 8, // Rogue
3 => 9, // Hunter
2 => 10, // Paladin
7 => 11, // Shaman
6 => 15, // Death Knight
);
// generic rules are nowhere to be found :(
$spellNameHelp = array(
// itemId => correctNameString/spellId
43362 => 'Polymorph',
50077 => 'Corruption',
50125 => 'Rejuvenation',
45805 => 'Pestilence',
45804 => 'Death Coil',
45793 => 50720, // Vigilance - no SpellFamilyId
44928 => 'Starfall',
43549 => 'Raise Dead',
43539 => 'Death Coil',
43430 => 'Thunder Clap',
43425 => 'Shield Slam',
43423 => 'Rend',
43420 => 'Mocking Blow',
43416 => 'Execute',
43414 => 'Cleave',
43413 => 'Charge',
43400 => 'Victory Rush',
43394 => 'Ritual of Souls',
43385 => 'Reincarnation',
43379 => 'Sprint',
43361 => 'Polymorph',
43354 => 'Eyes of the Beast',
43342 => 'Fade',
43331 => 'Rebirth',
42900 => 'Mend Pet',
42469 => 63108, // Siphon Life is passive <_<
42417 => 20711, // Spirit of Redemption .. another false passive :/
42407 => 'Shadow Form',
41524 => 'lava burst',
41108 => 'Lay on Hands'
);
include 'includes/class.spell.php';
set_time_limit(300);
$glyphList = DB::Aowow()->Select($queryGlyphs);
$locales = [LOCALE_EN, LOCALE_FR, LOCALE_DE, LOCALE_ES, LOCALE_RU];
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!is_dir('datasets\\'.$dir))
mkdir('datasets\\'.$dir, 0755, true);
echo "script set up in ".Util::execTime()."<br>\n";
foreach ($locales as $lId)
{
User::useLocale($lId);
$glyphsOut = [];
foreach ($glyphList as $pop)
{
if (!$pop['glyphEffect'])
continue;
$spl = new Spell($pop['glyphEffect']);
if ($spl->template['effect1Id'] != 6)
continue;
if ($pop['itemId'] == 42958) // Crippling Poison has no skillLine.. oO => hardcode
{
$glyphsOut[$pop['itemId']] = array(
'name' => Util::jsEscape(Util::localizedString($pop, 'name')),
'description' => Util::jsEscape($spl->parseText()),
'icon' => 'ability_poisonsting',
'type' => 0,
'classs' => $pop['classs'],
'skill' => 253,
'level' => $pop['level']
);
continue;
}
$description = $spl->parseText();
$spellFamily = $class2Family[$pop['classs']];
$classId = $pop['classs'] - 1;
$skill = 0;
$icon = '';
$search = @$spellNameHelp[$pop['itemId']] ? $spellNameHelp[$pop['itemId']] : '%'.str_replace('Glyph of ', '', $pop['name']).'%';
if (is_int($search))
$where = "?d AND s.id = ?d";
else
$where = "sk.skillID <> 0 AND SpellFamilyId = ?d AND name_loc0 LIKE ?s AND (attributes0 & 0x40) = 0";
$icons = DB::Aowow()->Select(
str_replace('[WHERE]', $where, $queryIcons),
$spellFamily,
$search
);
$l = [null, 'A', 'B', 'C'];
$i = 0;
while (empty($icons) && $i < 3)
{
$i++;
$m1 = $spl->template['effect1SpellClassMask'.$l[$i]];
$m2 = $spl->template['effect2SpellClassMask'.$l[$i]];
$m3 = $spl->template['effect3SpellClassMask'.$l[$i]];
if ($spl->template['effect'.$i.'Id'] != 6 || (!$m1 && !$m2 && !$m3))
continue;
$where = "SpellFamilyId = ?d AND ((SpellFamilyFlags3 & 0xFFFFFFFF) & ?d OR (SpellFamilyFlags2 & 0xFFFFFFFF) & ?d OR (SpellFamilyFlags1 & 0xFFFFFFFF) & ?d)";
$icons = DB::Aowow()->Select(
str_replace ('[WHERE]', $where, $queryIcons),
$spellFamily,
$m1,
$m2,
$m3
);
}
while ($iPop = array_pop($icons))
{
$skill = $iPop['skillId'];
$icon = $iPop['icon'];
}
$glyphsOut[$pop['itemId']] = array(
'name' => Util::jsEscape(Util::localizedString($pop, 'name')),
'description' => Util::jsEscape($description),
'icon' => strToLower($icon),
'type' => $pop['type'],
'classs' => $pop['classs'],
'skill' => $skill,
'level' => $pop['level']
);
}
$toFile = "var g_glyphs = ";
$toFile .= json_encode($glyphsOut, JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK);
$toFile .= ";";
$file = 'datasets\\'.User::$localeString.'\\glyphs';
$handle = fOpen($file, "w");
fWrite($handle, $toFile);
fClose($handle);
echo "done glyphs loc: ".$lId." in ".Util::execTime()."<br>\n";
}
echo "<br>\nall done";
User::useLocale(LOCALE_EN);
$stats = DB::Aowow()->getStatistics();
echo "<br>\n".$stats['count']." queries in: ".Util::formatTime($stats['time'] * 1000);
?>

View File

@@ -0,0 +1,173 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
// Create 'itemsets'-file for available locales (and should probably order the itemests_dbc-table too (see below))
// this script requires the following dbc-files to be parsed and available
// GlyphProperties, Spells, SkillLineAbility
/* Example
"-447": { // internal id, freely chosen
"classes":["6"], // array
"elite":true,
"heroic":false,
"id":"-447",
"idbak":"924", // actual setId
"maxlevel":"390",
"minlevel":"390",
"name":"3Cataclysmic Gladiator's Desecration",
"note":"37", // contentGroup
"pieces":["73742","73741","73740","73739","73738"],
"reqclass":"32", // mask
"type":"4",
"setbonus":{
"2":{"resirtng":"400","str":"70"},
"4":{"str":"90"}
}
},
*/
/* Todo:
well .. strictly spoken this script is bogus. All data has to be assembled beforehand either by hand or by querying wowhead
we would need this script to prevent this type-fest and do it propperly ourselves.. *dang*
probably like this:
virtualId = 0
get itemsetIds ordered ascending
foreach itemsetId
lookup pieces
sort pieces by slot
if slots conflict
group items by ItemLevel ordered ascending
assign: first group => regularId
assign: other groups => --virtualId
end if
end foreach
this will probably screw the order of your set-pieces and will not result in the same virtualIds like wowhead, but
they are years beyond our content anyway, so what gives...
lets assume, you've done something like that, so ...
... onwards!
*/
include 'includes/class.spell.php';
$setList = DB::Aowow()->Select('SELECT * FROM ?_itemset ORDER BY refSetId DESC');
$locales = [LOCALE_EN, LOCALE_FR, LOCALE_DE, LOCALE_ES, LOCALE_RU];
$jsonBonus = [];
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!is_dir('datasets\\'.$dir))
mkdir('datasets\\'.$dir, 0755, true);
echo "script set up in ".Util::execTime()."<br>\n";
foreach ($locales as $lId)
{
User::useLocale($lId);
$itemsetOut = [];
foreach ($setList as $set)
{
$setOut = array(
'id' => $set['itemsetID'],
'name' => (7 - $set['quality']).Util::jsEscape(Util::localizedString($set, 'name')),
'pieces' => [],
'heroic' => DB::Aowow()->SelectCell('SELECT IF (Flags & 0x8, "true", "false") FROM item_template WHERE entry = ?d', $set['item1']),
'maxlevel' => $set['maxLevel'],
'minlevel' => $set['minLevel'],
'type' => $set['type'],
'setbonus' => []
);
if ($set['classMask'])
{
$setOut['reqclass'] = $set['classMask'];
$setOut['classes'] = [];
for ($i = 0; $i < 12; $i++)
if ($set['classMask'] & (1 << ($i - 1)))
$setOut['classes'][] = $i;
}
if ($set['contentGroup'])
$setOut['note'] = $set['contentGroup'];
if ($set['itemsetID'] < 0)
$setOut['idbak'] = $set['refSetId'];
for ($i = 1; $i < 11; $i++)
if ($set['item'.$i])
$setOut['pieces'][] = $set['item'.$i];
for ($i = 1; $i < 9; $i++)
{
if (!$set['bonus'.$i] || !$set['spell'.$i])
continue;
// costy and locale-independant -> cache
if (!isset($jsonBonus[$set['spell'.$i]]))
{
$bSpell = new Spell($set['spell'.$i]);
$jsonBonus[$set['spell'.$i]] = $bSpell->getStatGain();
}
if (isset($setOut['setbonus'][$set['bonus'.$i]]))
{
foreach ($jsonBonus[$set['spell'.$i]] as $k => $v)
@$setOut['setbonus'][$set['bonus'.$i]][$k] += $v;
}
else
$setOut['setbonus'][$set['bonus'.$i]] = $jsonBonus[$set['spell'.$i]];
}
foreach ($setOut['setbonus'] as $k => $v)
{
if (empty($v))
unset($setOut['setbonus'][$k]);
else
{
foreach ($v as $sk => $sv)
{
if ($str = Util::$itemMods[$sk])
{
$setOut['setbonus'][$k][$str] = $sv;
unset($setOut['setbonus'][$k][$sk]);
}
}
}
}
if (empty($setOut['setbonus']))
unset($setOut['setbonus']);
$itemsetOut[$setOut['id']] = $setOut;
}
$toFile = "var g_itemsets = ";
$toFile .= json_encode($itemsetOut, JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK);
$toFile .= ";";
$file = 'datasets\\'.User::$localeString.'\\itemsets';
$handle = fOpen($file, "w");
fWrite($handle, $toFile);
fClose($handle);
echo "done itemsets loc: ".$lId." in ".Util::execTime()."<br>\n";
}
echo "<br>\nall done";
User::useLocale(LOCALE_EN);
$stats = DB::Aowow()->getStatistics();
echo "<br>\n".$stats['count']." queries in: ".Util::formatTime($stats['time'] * 1000);
?>

View File

@@ -0,0 +1,164 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
// builds 'pets'-file for available locales
// this script requires the following dbc-files to be parsed and available
// CreatureFamily, CreatureDisplayInfo, FactionTemplate, AreaTable
// Todo:
// locations are a tiny bit wide at the moment.
// I'm still undecided wether the old system is pure genius or pure madness. While building the zone-maps it also generated masks for that zone, using the alpha-channel in the *.blp
// When deciding what spawn lies where you could check against the relative coordinates of that mask. black => isInZone; white => notInZone
// Since i'm lacking other options this will probably be reimplemented.
/* Example data
30: {
id:30,
name:'Forest Spider',
minlevel:5,
maxlevel:6,
location:[12], // master-AreaTableId's (?)
react:[-1,-1],
classification:0, // 0:"Normal", 1:"Elite", 2:"Rar Elite", 3:"Boss", 4:"Rar"
family:3, // creatureFamily
displayId:382,
skin:'TarantulaSkinOrange',
icon:'Ability_Hunter_Pet_Spider', // from creatureFamily.dbc
type:2 // 0:Ferocity, 1:Tenacity, 2:Cunning
},
*/
$petQuery = '
SELECT
ct.entry as id,
ct.name,
lc.*,
ct.minlevel,
ct.maxlevel,
CONCAT("[", ft.A, ", ", ft.H, "]") as react,
ct.rank as classification,
ct.family,
ct.modelId1 as displayId,
cdi.skin1 as skin,
cf.iconString as icon,
cf.petTalentType as type
FROM
world.creature_template ct
JOIN
?_factionTemplate ft ON
ft.Id = ct.faction_A -- no beast has different faction set for Horde
JOIN
?_creatureFamily cf ON
cf.Id = ct.family
JOIN
world.locales_creature lc ON
lc.entry = ct.entry
JOIN
dbc.creatureDisplayInfo cdi ON
cdi.id = ct.modelId1
WHERE
cf.petTalentType <> -1 AND
ct.type_flags & 0x1
ORDER BY
ct.entry ASC;
';
$queryZones = '
SELECT DISTINCT
z.areatableId AS location
FROM
world.creature c
JOIN
?_zones z ON
z.x_min < c.position_x AND
z.x_max > c.position_x AND
z.y_min < c.position_y AND
z.y_max > c.position_y AND
z.mapId = c.map
WHERE
c.id = ?d;
';
$queryInstanceZone = '
SELECT DISTINCT
z.areatableId AS location
FROM
world.creature c,
?_zones z
WHERE
z.mapId = c.map AND
c.id = ?d;
';
$petList = DB::Aowow()->Select($petQuery);
$locales = [LOCALE_EN, LOCALE_FR, LOCALE_DE, LOCALE_ES, LOCALE_RU];
$locations = [];
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!is_dir('datasets\\'.$dir))
mkdir('datasets\\'.$dir, 0755, true);
echo "script set up in ".Util::execTime()."<br>\n";
foreach ($locales as $lId)
{
User::useLocale($lId);
$petsOut = [];
foreach ($petList as $pet)
{
// get locations
// again: caching will save you time and nerves
if (!isset($locations[$pet['id']]))
{
$locations[$pet['id']] = DB::Aowow()->SelectCol($queryZones, $pet['id']);
// probably instanced, map <=> areaId _should_ be bijective
if (empty($locations[$pet['id']]))
if ($z = DB::Aowow()->SelectCell($queryInstanceZone, $pet['id']))
$locations[$pet['id']][] = $z;
}
$pet = array(
'id' => $pet['id'],
'name' => Util::localizedString($pet, 'name'),
'minlevel' => $pet['minlevel'],
'maxlevel' => $pet['maxlevel'],
'location' => $locations[$pet['id']],
'react' => $pet['react'],
'classification' => $pet['classification'],
'family' => $pet['family'],
'displayId' => $pet['displayId'],
'skin' => $pet['skin'],
'icon' => $pet['icon'],
'type' => $pet['type']
);
$petsOut[$pet['id']] = $pet;
}
$toFile = "var g_pets = ";
$toFile .= json_encode($petsOut, JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK);
$toFile .= ";";
$file = 'datasets\\'.User::$localeString.'\\pets';
$handle = fOpen($file, "w");
fWrite($handle, $toFile);
fClose($handle);
echo "done pets loc: ".$lId." in ".Util::execTime()."<br>\n";
}
echo "<br>\nall done";
User::useLocale(LOCALE_EN);
$stats = DB::Aowow()->getStatistics();
echo "<br>\n".$stats['count']." queries in: ".Util::formatTime($stats['time'] * 1000);
?>

View File

@@ -0,0 +1,94 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
// 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 parsed and available
// Talent, TalentTab, Spell
$query = '
SELECT
s.iconString
FROM
?_spell s
JOIN
?_talent t On
t.rank1 = s.Id
JOIN
?_talenttab tt ON
tt.Id = t.tab
WHERE
tt.?# = ?d AND
tt.order = ?d
ORDER BY
t.row, t.col, t.petmask ASC ;
';
$dims = 36; //v-pets
$filenames = ['icons', 'warrior', 'paladin', 'hunter', 'rogue', 'priest', 'deathknight', 'shaman', 'mage', 'warlock', null, 'druid'];
// create directory if missing
if (!is_dir('images\\talent\\classes\\icons'))
mkdir('images\\talent\\classes\\icons', 0755, true);
echo "script set up in ".Util::execTime()."<br>\n";
foreach ($filenames as $k => $v)
{
if (!$v)
continue;
for ($tree = 0; $tree < 3; $tree++)
{
$what = $k ? 'classes' : 'pets';
$set = $k ? 1 << ($k - 1) : 1 << $tree;
$subset = $k ? $tree : 0;
$path = $k ? 'classes\\icons' : 'pets';
$icons = DB::Aowow()->SelectCol($query, $what, $set, $subset);
if (empty($icons))
die('error: query for '.$v.' tree: '.$k.' empty');
$res = imageCreateTrueColor(count($icons) * $dims, 2 * $dims);
for($i = 0; $i < count($icons); $i++)
{
$im = @imagecreatefromjpeg('images\\icons\\medium\\'.$icons[$i].'.jpg');
if(!$im)
die('error: raw image '.$icons[$i]. ' not found');
// colored
imagecopymerge($res, $im, $i * $dims, 0, 0, 0, imageSX($im), imageSY($im), 100);
// grayscale
if (imageistruecolor($im))
imagetruecolortopalette($im, false, 256);
for ($j = 0; $j < imagecolorstotal($im); $j++)
{
$color = imagecolorsforindex($im, $j);
$gray = round(0.299 * $color['red'] + 0.587 * $color['green'] + 0.114 * $color['blue']);
imagecolorset($im, $j, $gray, $gray, $gray);
}
imagecopymerge($res, $im, $i * $dims, $dims, 0, 0, imageSX($im), imageSY($im), 100);
if (!@imagejpeg($res, 'images\\talent\\'.$path.'\\'.$v.'_'.($tree + 1).'.jpg'))
die('error: '.$v.'_'.($tree + 1).'.jpg could not be written!');
}
}
echo "textures for ".($k ? ucFirst($v) : "Pet")." done in ".Util::execTime()."<br>\n";
}
echo "<br>\nall done";
User::useLocale(LOCALE_EN);
$stats = DB::Aowow()->getStatistics();
echo "<br>\n".$stats['count']." queries in: ".Util::formatTime($stats['time'] * 1000);
?>

View File

@@ -0,0 +1,230 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
// builds talent-tree-data for the talent-calculator
// this script requires the following dbc-files to be parsed and available
// Talent, TalentTab, Spell, CreatureFamily
// talents
// i - int talentId (id of aowow_talent)
// n - str name (spellname of aowow_spell for spellID = rank1)
// m - int number of ranks (6+ are empty)
// s - array:int spells to ranks (rank1, rank2, ..., rank5 of aowow_talent)
// d - array:str description of spells
// x - int column (col from aowow_talent)
// y - int row (row of aowow_talent)
// r - array:int on what the talent depends on: "r:[u, v]", u - nth talent in tree, v - required rank of u
// f - array:int [pets only] creatureFamilies, that use this spell
// t - array:str if the talent teaches a spell, this is the upper tooltip-table containing castTime, cost, cooldown
// tabs
// n - name of the tab
// t - array of talent-objects
// f - array:int [pets only] creatureFamilies in that category
include 'includes/class.spell.php';
function buildTree($class)
{
global $petFamIcons; // h8!
$petCategories = [];
$mask = $class ? 1 << ($class - 1) : 0;
// All "tabs" of a given class talent
$tabs = DB::Aowow()->select('
SELECT
*
FROM
?_talenttab
WHERE
classes = ?d
ORDER BY
`order`, `pets`',
$mask
);
$result = [];
for ($l = 0; $l < count($tabs); $l++)
{
$talents = DB::Aowow()->select('
SELECT
t.*,
s.*
FROM
?_talent t,
?_spell s
WHERE
t.`tab`= ?d AND
s.`Id` = t.`rank1`
ORDER by t.`row`, t.`col`
',
$tabs[$l]['id']
);
$result[$l] = array(
'n' => Util::localizedString($tabs[$l], 'name'),
't' => []
);
if (!$class)
{
$petFamId = log($tabs[$l]['pets'], 2);
$result[$l]['icon'] = $petFamIcons[$petFamId];
$petCategories = DB::Aowow()->SelectCol('SELECT Id AS ARRAY_KEY, categoryEnumId FROM ?_creatureFamily WHERE petTalentType = ?d', $petFamId);
$result[$l]['f'] = array_keys($petCategories);
}
// talent dependencies go here
$depLinks = [];
$tNums = [];
for($j = 0; $j < count($talents); $j++)
{
$tNums[$talents[$j]['id']] = $j;
$d = [];
$s = [];
$i = $talents[$j]['id'];
$n = Util::localizedString($talents[$j], 'name');
$x = $talents[$j]['col'];
$y = $talents[$j]['row'];
$r = null;
$t = [];
$icon = $talents[$j]['iconString'];
$m = $talents[$j]['rank2'] == 0 ? 1 : (
$talents[$j]['rank3'] == 0 ? 2 : (
$talents[$j]['rank4'] == 0 ? 3 : (
$talents[$j]['rank5'] == 0 ? 4 : 5
)
)
);
// duplet handling
$f = [];
foreach ($petCategories as $k => $v)
{
// cant handle 64bit integer .. split
if ($v >= 32 && ((1 << ($v - 32)) & $talents[$j]['petmask2']))
$f[] = $k;
else if ($v < 32 && ((1 << $v) & $talents[$j]['petmask']))
$f[] = $k;
}
for ($k = 0; $k <= ($m - 1); $k++)
{
$tSpell = new Spell($talents[$j]['rank'.($k + 1)]);
$d[] = $tSpell->parseText();
$s[] = $talents[$j]['rank'.($k + 1)];
if ($talents[$j]['isSpell'])
$t[] = $tSpell->getTalentHead();
}
if ($talents[$j]['dependsOn'])
{
// we didn't encounter the required talent yet => create reference
if (!isset($tNums[$talents[$j]['dependsOn']]))
$depLinks[$talents[$j]['dependsOn']] = $j;
$r = [$tNums[$talents[$j]['dependsOn']], $talents[$j]['dependsOnRank'] + 1];
}
$result[$l]['t'][$j] = array(
'i' => $i,
'n' => $n,
'm' => $m,
'd' => $d,
's' => $s,
'x' => $x,
'y' => $y,
);
if (isset($r))
$result[$l]['t'][$j]['r'] = $r;
if (!empty($t))
$result[$l]['t'][$j]['t'] = $t;
if (!empty($f))
$result[$l]['t'][$j]['f'] = $f;
if ($class)
$result[$l]['t'][$j]['iconname'] = $icon;
// If this talent is a reference, add it to the array of talent dependencies
if (isset($depLinks[$talents[$j]['id']]))
{
$result[$l]['t'][$depLinks[$talents[$j]['id']]]['r'][0] = $j;
unset($depLinks[$talents[$j]['id']]);
}
}
// Remove all dependencies for which the talent has not been found
foreach ($depLinks as $dep_link)
unset($result[$l]['t'][$dep_link]['r']);
}
return $result;
}
$classes = [CLASS_WARRIOR, CLASS_PALADIN, CLASS_HUNTER, CLASS_ROGUE, CLASS_PRIEST, CLASS_DEATHKNIGHT, CLASS_SHAMAN, CLASS_MAGE, CLASS_WARLOCK, CLASS_DRUID];
$locales = [LOCALE_EN, LOCALE_FR, LOCALE_DE, LOCALE_ES, LOCALE_RU];
// my neighbour is noisy as fuck and my head hurts, so ..
$petFamIcons = ['Ability_Druid_KingoftheJungle', 'Ability_Druid_DemoralizingRoar', 'Ability_EyeOfTheOwl']; // .. i've no idea where to fetch these from
$petIcons = '';
// check directory-structure
foreach (Util::$localeStrings as $dir)
if (!is_dir('datasets\\'.$dir))
mkdir('datasets\\'.$dir, 0755, true);
echo "script set up in ".Util::execTime()."<br>\n";
foreach ($locales as $lId)
{
User::useLocale($lId);
// TalentCalc
foreach ($classes as $cMask)
{
$cId = log($cMask, 2) + 1;
$file = 'datasets\\'.User::$localeString.'\\talents-'.$cId;
$toFile = '$WowheadTalentCalculator.registerClass('.$cId.', '.json_encode(buildTree($cId), JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK).')';
$handle = fOpen($file, "w");
fWrite($handle, $toFile);
fClose($handle);
echo "done class: ".$cId." loc: ".$lId." in ".Util::execTime()."<br>\n";
}
// PetCalc
if (empty($petIcons))
{
$pets = DB::Aowow()->SelectCol('SELECT Id AS ARRAY_KEY, iconString FROM ?_creatureFamily WHERE petTalentType <> -1');
$petIcons = json_encode($pets, JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK);
}
$toFile = "var g_pet_icons = ".$petIcons."\n\n";
$toFile .= 'var g_pet_talents = '.json_encode(buildTree(0), JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK);
$file = 'datasets\\'.User::$localeString.'\\pet-talents';
$handle = fOpen($file, "w");
fWrite($handle, $toFile);
fClose($handle);
echo "done pets loc: ".$lId." in ".Util::execTime()."<br>\n";
}
echo "<br>\nall done";
User::useLocale(LOCALE_EN);
$stats = DB::Aowow()->getStatistics();
echo "<br>\n".$stats['count']." queries in: ".Util::formatTime($stats['time'] * 1000);
?>