From 20a1829317c365074af4ef48a25b06e4982f736b Mon Sep 17 00:00:00 2001 From: Sarjuuk Date: Mon, 6 Mar 2017 15:16:34 +0100 Subject: [PATCH] implementation of Sound DB Client sounds are cross-referenced with as many other DB-Types as possible. Including, but not limited to: * Character VOs (Errors, Emotes) * Creature VOs (Boss Dialogue) * Zone Music and Ambience * Sounds triggerd by spells * Sounds from general item/spell usage, creature behavior Restrictions: * only one locale is supported. Choose wisely! --- .gitattributes | 1 + README.md | Bin 9684 -> 5699 bytes includes/basetype.class.php | 12 +- includes/defines.php | 7 +- includes/types/sound.class.php | 137 +++++++++ includes/types/spell.class.php | 5 + includes/utilities.php | 3 +- index.php | 4 +- localization/lang.class.php | 1 + localization/locale_dede.php | 13 + localization/locale_enus.php | 13 + localization/locale_eses.php | 13 + localization/locale_frfr.php | 13 + localization/locale_ruru.php | 13 + pages/emote.php | 22 ++ pages/genericPage.class.php | 3 + pages/item.php | 39 +++ pages/npc.php | 64 +++- pages/objects.php | 2 + pages/race.php | 18 ++ pages/search.php | 34 ++- pages/sound.php | 369 ++++++++++++++++++++++ pages/sounds.php | 82 +++++ pages/spell.php | 28 +- pages/zone.php | 57 +++- setup/db_structure.sql | 142 ++++++++- setup/tools/CLISetup.class.php | 36 +++ setup/tools/dbc.class.php | 52 +++- setup/tools/fileGen.class.php | 6 +- setup/tools/filegen/sounds.func.php | 62 ++++ setup/tools/sqlGen.class.php | 1 + setup/tools/sqlgen/emotes.func.php | 6 +- setup/tools/sqlgen/items.func.php | 7 + setup/tools/sqlgen/races.func.php | 4 + setup/tools/sqlgen/sounds.func.php | 426 ++++++++++++++++++++++++++ setup/tools/sqlgen/spawns.func.php | 30 +- setup/tools/sqlgen/spell.func.php | 2 + setup/updates/1487858459_01.sql | 214 ++++++------- setup/updates/1488745158_01.sql | 23 ++ setup/updates/1488745158_02.sql | 164 ++++++++++ static/css/aowow.css | 30 +- static/js/Markup.js | 132 ++++++++ static/js/basic.js | 183 +++++++++++ static/js/global.js | 454 +++++++++++++++++++++++++++- static/js/locale_dede.js | 89 +++++- static/js/locale_enus.js | 88 +++++- static/js/locale_eses.js | 88 +++++- static/js/locale_frfr.js | 88 +++++- static/js/locale_ruru.js | 88 +++++- template/bricks/mapper.tpl.php | 2 +- template/bricks/redButtons.tpl.php | 5 + template/pages/sound.tpl.php | 145 +++++++++ template/pages/sounds.tpl.php | 60 ++++ template/pages/spell.tpl.php | 43 ++- 54 files changed, 3454 insertions(+), 169 deletions(-) create mode 100644 includes/types/sound.class.php create mode 100644 pages/sound.php create mode 100644 pages/sounds.php create mode 100644 setup/tools/filegen/sounds.func.php create mode 100644 setup/tools/sqlgen/sounds.func.php create mode 100644 setup/updates/1488745158_01.sql create mode 100644 setup/updates/1488745158_02.sql create mode 100644 template/pages/sound.tpl.php create mode 100644 template/pages/sounds.tpl.php diff --git a/.gitattributes b/.gitattributes index 6d14ad78..91362a8e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,5 @@ *.php text eol=lf *.js text eol=lf *.css text eol=lf +*.sql text eol=lf diff --git a/README.md b/README.md index a803038e9e46844f55330f7cecf6cf2017ca458c..c3adf7a580ffb19ece6350589422129d185603c1 100644 GIT binary patch literal 5699 zcmbVQ>vr455&n;-7~4N0DI#E7aoQ+pYTYa|M@|%xsnV!9<`P&CYc8D~lH|Z#noClS1RV=6rou_`#%Kb2x-=G&n367q z&8;XsE%wsA^a*WEgN%HOQnR4RyDJ* z!eY6rmF8z_^11YBa#<-2fxxd+)_Jm0OYGw)7Y$AE)^trl!jTkKulVNi!-s#|g$jjO zvDF}$s$1innld9p4)2$hq1<9~?C2|ywAQ?mIrba#6aECjq^*`-V#}pf_=Oo*4kztG zTBiz0ZPkJdHv%$rZ2^9~15@Q%$;Jn&S7IStZdL0YmDbcj!XOFUj@_Z{Mcy%>CKBT?9C+U}uW2QKy%1rsHn}#eIW2y41 zBV%Q@dEWF$!A4fXM#>wj zU?{dp*=u{GJ2BI;xR7CDi1^LK>>5JHD+$ zO=yVHK)Ho<2~n>f0=QQW&R8y&=^Oc`(;{u8&t#L;?d$iprHrmNrM{JP!2vbC&KUcDoPR@2Djj*n(G z+m3YvmE^gaRY1iH8Pc~YWPx~g(tB2o;iNQLnJ3CB?=w;`zi&2$gRllk9H!BTX)uL!} zLKhMigwq;ac6Q*6;sZ|0&<))1`#_KYhO)_JirnX-YduX6ZC#rc)0fU$^c?JP0Qm$l zv#yjutN}oKg39+=)1ald9CU+XIzR^@f1__WWIx6v`69)qP;-^%Vis#2E#-%G5G zEn@j+31WKyKjsxvWf1Y-+8@0RPzQeE%UBN}{5 zU-9LDFTVh_iPAI_9*O#}B5iU3P9L}ov4et3AvM2=L`P_7zRivgpD`{Tg*GNj-uX6c zfbyltWfuCw7oxqB;F(4KqK;>$+DwIxh1;dN6G=$kD5pWpaQ7h_)6FXA+aea( zTDOAXkx8~cF7&NnV`$s>u=|~|oifB_fFYD8cPG^l&cFNXsFhkzjhWxM{#>-u9s_3Y zq&PkM>1320JwLcOI2xZ^99^6oj8E>QK35@$++8j?Uz}fvW`4+H!JS0Uv_KIVh8g58 zMnG!W6vAfDjaF!;-#5aDJ8!()^kd6yjeys-xaWxz07A_DuD_xU&VD#J9)5p1f(cH( zA4S$*rT|`m3b)xD3$a3nqMg#^!Cwa9mKw>eeCSzw@-P-mP!F?MFk>=1G~EF2z1YkE z_8PCs5N0*{Zq7wO>4alXp;?AHnaRDx9OZ$DHRG1^07tHFlOPMa7de|SJ{+2>(`rFqK3I86TWz&-RF*x-1Op^Q`V%6>5r-@Y(NH?X!Bez44 zIpr@b-deOkxE2lf{5gizAK?5hmND+ydHM*Y;1)=a&W1GMIV{v{8Xz1nCSuVfr6JGE zro#j~>v&va^z)Ss7_-DgKsA`w;HjDxBhyWN4?`N4AOKRqjtxU$=y<|Z7DC7?s1ng= zm!xYY&qj#+SReZS>J9phL7eqd`U!;^-36i)Q!&O|Vbz-;l?@YL5Q#&4Jvnzx7||Ve z0X9axQRh?ot8}|G{H(@Mfj~rKt}tTn)6S`Z4tNs^3}WKm4x1pzT}j;r{gJb1I_%CI=5#D_G>+9smO?_g`b!6h#)sHr!bz$&dT6nWS@^ zaWITyHg{ahyhKR@D;`jJbaZ}&RhUI1c`Ujt5Qf1px$`(Wm2AvHxfY|XETI0n0g~W^ zMCd}FJ{p~cT7A>xbWLCPF?ylKvpT?}(fD9IJbL;3htas7cMFL$0D80rNUc{XokYe< zwEn^L{ZWIu2Gv6G(E#_#@5UXbJ#^Xp9z7}aA2H6%BvLh;GQ=2I8-uk$)4`_?5UCOi zSV^~)7~~ZvHv-Z*)TUsV0Ma3JSW5xiWB5y`o!x!b-d33@H*dUiaFgLEwPk z&I0%#bkQN;(F(#Ov#l2*G$WoYaE(L6x3CqR@IgH5%c3iBd z7$^C}3MXs>Qgl9)z$D zrd)>}W;dhATtf%n<3 zmi9S{lvsuF$UZt}@3q(EUDxCP{QI-iNcYm4G)PzJM4x}82WgaU(!M@tsh`^VeW7nB z=}7n6vvpjbYW;=ox6*aG)QT_CTK@SgLG@`GYwsW(>bf_jI2MhyeBQC1_S3nZo#|Oa z_fK_oJ^cy*Ae`}&S1-la# zd^Obdu}-?s9c*!Tu6NUK^4=ruzR}*HB**6EjG<2A^pU7z_jryDvGkGlwWPh>Z0W&N zL+0;TtB2Z&{Lta4wFr-WT_epw-h(d3`p#LbY2>wN^>%jWp)~Ym`hDgZD;#PiPmMKe z3|yn9k$%oZJ2<-1y3us~M7;7H`&e?zh&D~-T2HRhPkIVQkZ))9tYE_^z0POcWGSFG z(Ox*Rg+N2t3;Ya)1b)NaVP11B%6JIWd(n#t2hWApPg?y>pHY?# z&*LfRK%NU-g$|))o!HwgyKT>!bs-W-PqXxEsiVCY(l#;-GRE-=?B5U%MVp6N_Tn2M z`(l2pd>UEc5iKCoi70~xYh$3RTb(o(=hg$7360n{txIA7wk`65HMEGQAU77>kQ^gj zbE2h3Q+3NnBtSyWA}+#@&qZpZ7q2shA|@CctS1hfX%`XWTHG6*NQei64=94;bFD+x zd*Y5CN8Hz<@mBlrrK8M&ZO)2cYuB#s9^~@_TX-A3beZYl&E51uANkb%hT;z~s3jXC z-KDr2Xf<}T^^elek`H8I10v2y(Rxj*IjyIAco=^5_w*{goITlAtc+E!GE&}Z)!FRc zg}5YRM2s=_tn8(4MW@c)Bk|`IZ{&N=ly@3J&g zBF}EqrX)g-ZBaER^Y?jLjZ|&zBU7>iKB`=h8_~*+sFD+~Df^4P@M|(Hp7K~vyA|4A zd#opc%RsX&gH7J)L#{G@pl$rXHIfhm?BRT~@4zpy+K9xiMkRcdjAwhkkqx`j|5mm- z`HF}Kt-EWur(Huu%dvjWrKe>S(N>)LR2J`MYg|qvqW$xipSp}~G@0-bxI{ zqn$&@RgN=g*4YRAS8d~cVIxNz>|)L@r`jdHQx7%r59la5c66NAuF*SD=9mb#@3sHE zcqHDn#1k2|t>2gWjpx19-$PkwqC3=gR81|R{zgv+svsJA&Y8>fad!=OvqWHwOus4b z8H)BYy6D+4%W><4_MM0?XYkjOpu|Kp4La>TXp*WhB2eTEP&>#nPG--b0iK~vy;2ZO zjfFMFqUP92_Hf3)Gs54iQGl8N3p*z_q*MHcNPVKat_{pTyhXiW%LkWuOn=HtU*|1;$-CG&JS5;t~RF6TC=*ek^U@t>!P}d z*0!jUgQ~U6-KYhJk%c;v-yH<{!P4vEry-8|wP;r|DZJNX6}s7zX6<3*9c)Pj;d@V} zf9nzavGPMbzU*t?B!5~nYUSRZczd{%H%^1I5}~QIh3o$U)RTNI&WhHITc{@bHoFIM8b6eb89!RkYQd z)#n?0>9d4nBm zxsr6(MOJmaRJ6X#3vFfB$WbkoU3ZtF+LMJ2sy&kZ5ecaQozd`0W225MR|SFN&<9;^ zNJW+7-ToW?O@_M3dL(NNg&fyAOpC@sIC=KxT(_=Eo6YpKe*a;1wK2Q;Ax|#Ae=DQL z^(Ix6Gb@pwXphz0k$>999CheC_VUk~P+X-!B@e$}%d?1l&!^IklnG03+}8f(`#M>p z$jtl%KWh zo0^IV5@?TV1wQG?&~u<^k*@qSsC<$8x=(9&k(PF{Ebw$A&4;|J>k7@dVrx$;AJ@oC z_*T_>NBTl*zhrMu`lIg~D2h=F(8sKLKJ_wGhQgyO*VSokt1tRa-B?fOZ>nqGNU!zT zRQ0;0t4)2j^qp_3)9wl{#8PJ+D$&(EqbqOjiUXqRxjZiBwX0KlEKIu1GcvuWkIeAsanKXhS5(Bo8MOiV6VHrEoNZ3Dh};j4)w%b3 zJ)<|_Z9>5(714L1<*1B2&c~j<6OFMA9Wz~g)Yj-Yrlv(p5vS`@eCBreXiVO0eM?`p zw`+0u`Cha~xdQ5>&&8`}K=`JsH@HC;Ov$L-xAo0-@S5NQZIDmz<%-@YDEg+O7)Xa9 z6J3G3cq1q(El@MjD(l7ZxOD62q|~#eKEsl9i>@$@7`VU9+HhZPY!!@rtcC|UF^zEN zj|N%%(v1OcJZVc z%?I^rmFoJF9O_IOxjyF2OqT zuvO!DA`YU8F;~=#ms%I^iKs|Ti`gje=&C6DSiD0QmZkIpbOK@jo_KTo!1{1ZUBeDI zuf~BoGVnNfMPu}RUT-bor_{jgz<>DO6vzB!LXTJ3>Qvly#FWff`V``)-)$j7;04{_ z8MZ9l;bQ+Z7Qil1lilz|%vfZ5SO1PcoQf348JrdmfNreAQb_t*>xnRE(UJVAVkZcR z3=)>L{oE;lGUFG{=s=7;>(rFVcG1~zvXKfB{Kk6zd7;P~KwEgex4g|BUGQ^OxLWMY7a>G2Yo}5?*-}h_`X7 z-&Ii&QE_>iWIa1>mYRb(Hm5_8^U({}_A1Ne$i&^S6;-!+Fh0;}9hUIj8otk zj8*Bw)wxdd6l0jVs#Bu^Bjezg__8NBj&6QG>bJR62=sPf1e`NdqsIk@wpYxm-OEL- z=gfW*& z@RCDGNd%$l@T7@q-V%|mVmdPKu`x5V71$5T4%7XdvHU+xMzwXxNzfhD-j4q7|H~9- PG^ML@MoZ_!|1kX*DJ7nK diff --git a/includes/basetype.class.php b/includes/basetype.class.php index 9141d7f9..1b84f07d 100644 --- a/includes/basetype.class.php +++ b/includes/basetype.class.php @@ -352,6 +352,16 @@ abstract class BaseType return $value; } + public function getAllFields($field, $localized = false, $silent = false) + { + $data = []; + + foreach ($this->iterate() as $__) + $data[$this->id] = $this->getField($field, $localized, $silent); + + return $data; + } + public function getRandomId() { // ORDER BY RAND() is not optimal, so if anyone has an alternative idea.. @@ -668,7 +678,7 @@ trait spawnHelper public function getSpawns($mode) { // ony Creatures and GOs can be spawned - if (!self::$type || (self::$type != TYPE_NPC && self::$type != TYPE_OBJECT)) + if (!self::$type || (self::$type != TYPE_NPC && self::$type != TYPE_OBJECT && self::$type != TYPE_SOUND)) return []; switch ($mode) diff --git a/includes/defines.php b/includes/defines.php index 816881df..6539bd10 100644 --- a/includes/defines.php +++ b/includes/defines.php @@ -24,6 +24,7 @@ define('TYPE_CLASS', 13); define('TYPE_RACE', 14); define('TYPE_SKILL', 15); define('TYPE_CURRENCY', 17); +define('TYPE_SOUND', 19); // internal types (not published to js) define('TYPE_USER', 500); define('TYPE_EMOTE', 501); @@ -42,7 +43,7 @@ define('SEARCH_TYPE_REGULAR', 0x10000000); define('SEARCH_TYPE_OPEN', 0x20000000); define('SEARCH_TYPE_JSON', 0x40000000); define('SEARCH_MASK_OPEN', 0x007DC1FF); // open search -define('SEARCH_MASK_ALL', 0x07FFFFFF); // normal search +define('SEARCH_MASK_ALL', 0x0FFFFFFF); // normal search // Databases define('DB_AOWOW', 0); @@ -158,6 +159,7 @@ define('BUTTON_LINKS', 4); define('BUTTON_FORUM', 5); define('BUTTON_TALENT', 6); define('BUTTON_EQUIP', 7); +define('BUTTON_PLAYLIST', 8); // generic filter handler define('FILTER_CR_BOOLEAN', 1); @@ -200,6 +202,9 @@ define('CC_FLAG_DELETED', 0x2); define('CC_FLAG_OUTDATED', 0x4); define('CC_FLAG_APPROVED', 0x8); +define('SOUND_TYPE_OGG', 1); +define('SOUND_TYPE_MP3', 2); + /* * Game */ diff --git a/includes/types/sound.class.php b/includes/types/sound.class.php new file mode 100644 index 00000000..b71e466a --- /dev/null +++ b/includes/types/sound.class.php @@ -0,0 +1,137 @@ + 'audio/ogg; codecs="vorbis"', + SOUND_TYPE_MP3 => 'audio/mpeg' + ); + + public function __construct($conditions = []) + { + parent::__construct($conditions); + + // post processing + foreach ($this->iterate() as $id => &$_curTpl) + { + $_curTpl['files'] = []; + for ($i = 1; $i < 11; $i++) + { + if ($_curTpl['soundFile'.$i]) + { + $this->fileBuffer[$_curTpl['soundFile'.$i]] = null; + $_curTpl['files'][] = &$this->fileBuffer[$_curTpl['soundFile'.$i]]; + } + + unset($_curTpl['soundFile'.$i]); + } + } + + if ($this->fileBuffer) + { + $files = DB::Aowow()->select('SELECT id AS ARRAY_KEY, `id`, `file` AS title, `type` FROM ?_sounds_files sf WHERE id IN (?a)', array_keys($this->fileBuffer)); + foreach ($files as $id => $data) + { + // skipp file extension + $data['title'] = substr($data['title'], 0, -4); + // enum to string + $data['type'] = self::$fileTypes[$data['type']]; + // get real url + $data['url'] = STATIC_URL . '/wowsounds/' . $data['id']; + // v push v + $this->fileBuffer[$id] = $data; + } + } + } + + public static function getName($id) + { + $this->getEntry($id); + + return $this->getField('name'); + } + + public function getListviewData() + { + $data = []; + + foreach ($this->iterate() as $__) + { + $data[$this->id] = array( + 'id' => $this->id, + 'type' => $this->getField('cat'), + 'name' => $this->getField('name'), + 'files' => array_values(array_filter($this->getField('files'))) + ); + } + + return $data; + } + + public function getJSGlobals($addMask = 0) + { + $data = []; + + foreach ($this->iterate() as $__) + $data[self::$type][$this->id] = array( + 'name' => Util::jsEscape($this->getField('name', true)), + 'type' => $this->getField('cat'), + 'files' => array_values(array_filter($this->getField('files'))) + ); + + return $data; + } + + public function renderTooltip() { } +} + +class SoundListFilter extends Filter +{ + // we have no criteria for this one... + protected function createSQLForCriterium(&$cr) + { + unset($cr); + $this->error = true; + return [1]; + } + + protected function createSQLForValues() + { + $parts = []; + $_v = &$this->fiData['v']; + + // name [str] + if (isset($_v['na'])) + if ($_ = $this->modularizeString(['name'])) + $parts[] = $_; + + // type [list] + if (isset($_v['ty'])) + { + if ($_ = array_intersect((array)$_v['ty'], [1, 2, 3, 4, 6, 9, 10, 12, 13, 14, 16, 17, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 50, 52, 53])) + $parts[] = ['cat', $_]; + else + { + $this->error = true; + unset($_v['ty']); + } + } + + return $parts; + } +} + +?> diff --git a/includes/types/spell.class.php b/includes/types/spell.class.php index 371bf850..0889e7d2 100644 --- a/includes/types/spell.class.php +++ b/includes/types/spell.class.php @@ -1998,6 +1998,11 @@ class SpellList extends BaseType for ($i = 0; $i < 11; $i++) if ($mask & (1 << $i)) $data[TYPE_RACE][$i + 1] = $i + 1; + + // play sound effect + for ($i = 1; $i < 4; $i++) + if ($this->getField('effect'.$i.'Id') == 132) + $data[TYPE_SOUND][$this->getField('effect'.$i.'MiscValue')] = $this->getField('effect'.$i.'MiscValue'); } if ($addMask & GLOBALINFO_SELF) diff --git a/includes/utilities.php b/includes/utilities.php index 6c1b74a1..8954aec7 100644 --- a/includes/utilities.php +++ b/includes/utilities.php @@ -39,7 +39,7 @@ class Util public static $typeClasses = array( null, 'CreatureList', 'GameObjectList', 'ItemList', 'ItemsetList', 'QuestList', 'SpellList', 'ZoneList', 'FactionList', 'PetList', 'AchievementList', 'TitleList', 'WorldEventList', 'CharClassList', - 'CharRaceList', 'SkillList', null, 'CurrencyList', + 'CharRaceList', 'SkillList', null, 'CurrencyList', null, 'SoundList', TYPE_EMOTE => 'EmoteList', TYPE_ENCHANTMENT => 'EnchantmentList' ); @@ -47,6 +47,7 @@ class Util public static $typeStrings = array( // zero-indexed null, 'npc', 'object', 'item', 'itemset', 'quest', 'spell', 'zone', 'faction', 'pet', 'achievement', 'title', 'event', 'class', 'race', 'skill', null, 'currency', + null, 'sound', TYPE_USER => 'user', TYPE_EMOTE => 'emote', TYPE_ENCHANTMENT => 'enchantment' diff --git a/index.php b/index.php index 8dff9d3b..3ba578e5 100644 --- a/index.php +++ b/index.php @@ -64,8 +64,8 @@ switch ($pageCall) case 'search': // tool: searches case 'skill': case 'skills': - // case 'sound': // db: sounds for zone, creature, spell, ... - // case 'sounds': + case 'sound': // db: sounds for zone, creature, spell, ... + case 'sounds': case 'spell': case 'spells': case 'talent': // tool: talent calculator diff --git a/localization/lang.class.php b/localization/lang.class.php index e6954331..cbe02c58 100644 --- a/localization/lang.class.php +++ b/localization/lang.class.php @@ -25,6 +25,7 @@ class Lang private static $quest; private static $race; private static $skill; + private static $sound; private static $spell; private static $title; private static $zone; diff --git a/localization/locale_dede.php b/localization/locale_dede.php index e591f46c..034b27c6 100644 --- a/localization/locale_dede.php +++ b/localization/locale_dede.php @@ -214,6 +214,8 @@ $lang = array( 'school' => "Magieart", 'skill' => "Fertigkeit", 'skills' => "Fertigkeiten", + 'sound' => "Klang", + 'sounds' => "Klänge", 'spell' => "Zauber", 'spells' => "Zauber", 'type' => "Art", @@ -675,6 +677,17 @@ $lang = array( 1 => "Verschiedenes", 2 => "Spieler gegen Spieler", 4 => "Classic", 21 => "Wrath of the Lich King", 22 => "Dungeon und Schlachtzug", 23 => "Burning Crusade", 41 => "Test", 3 => "Unbenutzt" ) ), + 'sound' => array( + 'notFound' => "Dieser Klang existiert nicht.", + 'foundIn' => "Dieser Klang befindet sich in", + 'goToPlaylist' => "Gehe zu meiner Playlist", + 'cat' => array( + null, "Spells", "User Interface", "Footsteps", "Weapons Impacts", null, "Weapons Misses", null, null, "Pick Up/Put Down", + "NPC Combat", null, "Errors", "Nature", "Objects", null, "Death", "NPC Greetings", null, "Armor", + "Footstep Splash", "Water (Character)", "Water", "Tradeskills", "Misc Ambience", "Doodads", "Spell Fizzle", "NPC Loops", "Zone Music", "Emotes", + "Narration Music", "Narration", 50 => "Zone Ambience", 52 => "Emitters", 53 => "Vehicles", 1000 => "Meine Playlist" + ) + ), 'pet' => array( 'notFound' => "Diese Tierart existiert nicht.", 'exotic' => "Exotisch", diff --git a/localization/locale_enus.php b/localization/locale_enus.php index d95880c3..3a093df7 100644 --- a/localization/locale_enus.php +++ b/localization/locale_enus.php @@ -209,6 +209,8 @@ $lang = array( 'school' => "School", 'skill' => "skill", 'skills' => "Skills", + 'sound' => "sound", + 'sounds' => "Sounds", 'spell' => "spell", 'spells' => "Spells", 'type' => "Type", @@ -670,6 +672,17 @@ $lang = array( 1 => "Miscellaneous", 2 => "Player vs. Player", 4 => "Classic", 21 => "Wrath of the Lich King", 22 => "Dungeon and Raid", 23 => "Burning Crusade", 41 => "Test", 3 => "Unused" ) ), + 'sound' => array( + 'notFound' => "This sound doesn't exist.", + 'foundIn' => "This sound can be found in", + 'goToPlaylist' => "Go to My Playlist", + 'cat' => array( + null, "Spells", "User Interface", "Footsteps", "Weapons Impacts", null, "Weapons Misses", null, null, "Pick Up/Put Down", + "NPC Combat", null, "Errors", "Nature", "Objects", null, "Death", "NPC Greetings", null, "Armor", + "Footstep Splash", "Water (Character)", "Water", "Tradeskills", "Misc Ambience", "Doodads", "Spell Fizzle", "NPC Loops", "Zone Music", "Emotes", + "Narration Music", "Narration", 50 => "Zone Ambience", 52 => "Emitters", 53 => "Vehicles", 1000 => "My Playlist" + ) + ), 'pet' => array( 'notFound' => "This pet family doesn't exist.", 'exotic' => "Exotic", diff --git a/localization/locale_eses.php b/localization/locale_eses.php index e748d45d..6393f227 100644 --- a/localization/locale_eses.php +++ b/localization/locale_eses.php @@ -214,6 +214,8 @@ $lang = array( 'school' => "Escuela", 'skill' => "habilidad", 'skills' => "Habilidades", + 'sound' => "sonido", + 'sounds' => "Sonidos", 'spell' => "hechizo", 'spells' => "Hechizos", 'type' => "Tipo", @@ -676,6 +678,17 @@ $lang = array( 1 => "Miscelánea", 2 => "Jugador contra Jugador", 4 => "Clásico", 21 => "Wrath of the Lich King", 22 => "Mazmorra y banda", 23 => "Burning Crusade", 41 => "Prueba", 3 => "No las uso" ) ), + 'sound' => array( + 'notFound' => "Este sonido no existe.", + 'foundIn' => "Este sonido se puede encontrar en", + 'goToPlaylist' => "Ir a mi lista de reproducción", + 'cat' => array( + null, "Spells", "User Interface", "Footsteps", "Weapons Impacts", null, "Weapons Misses", null, null, "Pick Up/Put Down", + "NPC Combat", null, "Errors", "Nature", "Objects", null, "Death", "NPC Greetings", null, "Armor", + "Footstep Splash", "Water (Character)", "Water", "Tradeskills", "Misc Ambience", "Doodads", "Spell Fizzle", "NPC Loops", "Zone Music", "Emotes", + "Narration Music", "Narration", 50 => "Zone Ambience", 52 => "Emitters", 53 => "Vehicles", 1000 => "Mi Lista de Reproducción" + ) + ), 'pet' => array( 'notFound' => "Esta familia de mascotas no existe.", 'exotic' => "Exótica", diff --git a/localization/locale_frfr.php b/localization/locale_frfr.php index 1fc72e27..099cf130 100644 --- a/localization/locale_frfr.php +++ b/localization/locale_frfr.php @@ -214,6 +214,8 @@ $lang = array( 'school' => "École", 'skill' => "compétence", 'skills' => "Compétences", + 'sound' => "son", + 'sounds' => "Sons", 'spell' => "sort", 'spells' => "Sorts", 'type' => "Type", @@ -674,6 +676,17 @@ $lang = array( 1 => "Divers", 2 => "JcJ", 4 => "Classique", 21 => "Wrath of the Lich King", 22 => "Raid", 23 => "Burning Crusade", 41 => "Test", 3 => "Inutilisées" ) ), + 'sound' => array( + 'notFound' => "Ce son n'existe pas.", + 'foundIn' => "Ce son se trouve dans", + 'goToPlaylist' => "Aller à votre playlist", + 'cat' => array( + null, "Spells", "User Interface", "Footsteps", "Weapons Impacts", null, "Weapons Misses", null, null, "Pick Up/Put Down", + "NPC Combat", null, "Errors", "Nature", "Objects", null, "Death", "NPC Greetings", null, "Armor", + "Footstep Splash", "Water (Character)", "Water", "Tradeskills", "Misc Ambience", "Doodads", "Spell Fizzle", "NPC Loops", "Zone Music", "Emotes", + "Narration Music", "Narration", 50 => "Zone Ambience", 52 => "Emitters", 53 => "Vehicles", 1000 => "Ma playlist" + ) + ), 'pet' => array( 'notFound' => "Cette famille de familiers n'existe pas.", 'exotic' => "Exotique", diff --git a/localization/locale_ruru.php b/localization/locale_ruru.php index ab65acec..0893806c 100644 --- a/localization/locale_ruru.php +++ b/localization/locale_ruru.php @@ -214,6 +214,8 @@ $lang = array( 'school' => "Школа", 'skill' => "Уровень навыка", 'skills' => "Умения", + 'sound' => "Звук", + 'sounds' => "Звуки", 'spell' => "заклинание", 'spells' => "Заклинания", 'type' => "Тип", @@ -675,6 +677,17 @@ $lang = array( 1 => "Разное", 2 => "PvP", 4 => "World of Warcraft", 21 => "Wrath of the Lich King", 22 => "Подземелья и рейды", 23 => "Burning Crusade", 41 => "Test", 3 => "Неактивно" ) ), + 'sound' => array( + 'notFound' => "Этот звук не существует.", + 'foundIn' => "Этот Звук может быть найден в следующих зонах:", + 'goToPlaylist' => "Перейти к плейлисту", + 'cat' => array( + null, "Spells", "User Interface", "Footsteps", "Weapons Impacts", null, "Weapons Misses", null, null, "Pick Up/Put Down", + "NPC Combat", null, "Errors", "Nature", "Objects", null, "Death", "NPC Greetings", null, "Armor", + "Footstep Splash", "Water (Character)", "Water", "Tradeskills", "Misc Ambience", "Doodads", "Spell Fizzle", "NPC Loops", "Zone Music", "Emotes", + "Narration Music", "Narration", 50 => "Zone Ambience", 52 => "Emitters", 53 => "Vehicles", 1000 => "Мой плейлист" + ) + ), 'pet' => array( 'notFound' => "Такой породы питомцев не существует.", 'exotic' => "Экзотический", diff --git a/pages/emote.php b/pages/emote.php index 28a23284..d70a0c80 100644 --- a/pages/emote.php +++ b/pages/emote.php @@ -100,6 +100,28 @@ class EmotePage extends GenericPage $this->lvTabs[] = ['achievement', ['data' => array_values($acv->getListviewData())]]; $this->extendGlobalData($acv->getJsGlobals()); + + // tab: sound + if ($em = DB::Aowow()->select('SELECT soundId AS ARRAY_KEY, BIT_OR(1 << (raceId - 1)) AS raceMask, BIT_OR(1 << (gender - 1)) AS gender FROM aowow_emotes_sounds WHERE emoteId = ?d GROUP BY soundId', $this->typeId)) + { + $sounds = new SoundList(array(['id', array_keys($em)])); + if (!$sounds->error) + { + $this->extendGlobalData($sounds->getJSGlobals(GLOBALINFO_SELF)); + $data = $sounds->getListviewData(); + foreach($data as $id => &$d) + { + $d['races'] = $em[$id]['raceMask']; + $d['gender'] = $em[$id]['gender']; + } + + $this->lvTabs[] = ['sound', array( + 'data' => array_values($data), + // gender races + 'extraCols' => ['$Listview.templates.title.columns[1]', '$Listview.templates.classs.columns[1]'] + )]; + } + } } } diff --git a/pages/genericPage.class.php b/pages/genericPage.class.php index 801fa10f..0d8e53bc 100644 --- a/pages/genericPage.class.php +++ b/pages/genericPage.class.php @@ -129,6 +129,7 @@ class GenericPage 'reputationhistory' => ['template' => 'reputationhistory', 'id' => 'reputation', 'parent' => 'lv-generic', 'data' => [], 'name' => '$LANG.tab_reputation' ], 'screenshot' => ['template' => 'screenshot', 'id' => 'screenshots', 'parent' => 'lv-generic', 'data' => [], 'name' => '$LANG.tab_screenshots' ], 'skill' => ['template' => 'skill', 'id' => 'skills', 'parent' => 'lv-generic', 'data' => [], 'name' => '$LANG.tab_skills' ], + 'sound' => ['template' => 'sound', 'id' => 'sounds', 'parent' => 'lv-generic', 'data' => [], 'name' => '$LANG.types[19][2]' ], 'spell' => ['template' => 'spell', 'id' => 'spells', 'parent' => 'lv-generic', 'data' => [], 'name' => '$LANG.tab_spells' ], 'title' => ['template' => 'title', 'id' => 'titles', 'parent' => 'lv-generic', 'data' => [], 'name' => '$LANG.tab_titles' ], 'video' => ['template' => 'video', 'id' => 'videos', 'parent' => 'lv-generic', 'data' => [], 'name' => '$LANG.tab_videos' ], @@ -641,6 +642,7 @@ class GenericPage case TYPE_RACE: $jsg[TYPE_RACE] = ['g_races', [], []]; break; case TYPE_SKILL: $jsg[TYPE_SKILL] = ['g_skills', [], []]; break; case TYPE_CURRENCY: $jsg[TYPE_CURRENCY] = ['g_gatheredcurrencies', [], []]; break; + case TYPE_SOUND: $jsg[TYPE_SOUND] = ['g_sounds', [], []]; break; // well, this is awkward case TYPE_USER: $jsg[TYPE_USER] = ['g_users', [], []]; break; case TYPE_EMOTE: $jsg[TYPE_EMOTE] = ['g_emotes', [], []]; break; @@ -681,6 +683,7 @@ class GenericPage case TYPE_RACE: $obj = new CharRaceList($cnd); break; case TYPE_SKILL: $obj = new SkillList($cnd); break; case TYPE_CURRENCY: $obj = new CurrencyList($cnd); break; + case TYPE_SOUND: $obj = new SoundList($cnd); break; // "um, eh":, he ums and ehs. case TYPE_USER: $obj = new UserList($cnd); break; case TYPE_EMOTE: $obj = new EmoteList($cnd); break; diff --git a/pages/item.php b/pages/item.php index 67107190..42164e51 100644 --- a/pages/item.php +++ b/pages/item.php @@ -953,6 +953,45 @@ class ItemPage extends genericPage } } + + // tab: sounds + $soundIds = []; + if ($_class == ITEM_CLASS_WEAPON) + { + $scm = (1 << $_subClass); + if ($this->subject->getField('soundOverrideSubclass') > 0) + $scm = (1 << $this->subject->getField('soundOverrideSubclass')); + + $soundIds = DB::Aowow()->selectCol('SELECT soundId FROM ?_items_sounds WHERE subClassMask & ?d', $scm); + } + + $fields = ['pickUpSoundId', 'dropDownSoundId', 'sheatheSoundId', 'unsheatheSoundId']; + foreach ($fields as $f) + if ($x = $this->subject->getField($f)) + $soundIds[] = $x; + + if ($x = $this->subject->getField('spellVisualId')) + { + if ($spellSounds = DB::Aowow()->selectRow('SELECT * FROM ?_spell_sounds WHERE id = ?d', $x)) + { + array_shift($spellSounds); // bye 'id'-field + foreach ($spellSounds as $ss) + if ($ss) + $soundIds[] = $ss; + } + } + + if ($soundIds) + { + $sounds = new SoundList(array(['id', $soundIds])); + if (!$sounds->error) + { + $this->extendGlobalData($sounds->getJSGlobals(GLOBALINFO_SELF)); + $this->lvTabs[] = ['sound', ['data' => array_values($sounds->getListviewData())]]; + } + } + + // // todo - tab: taught by // use var $createdBy to find source of this spell // id: 'taught-by-X', diff --git a/pages/npc.php b/pages/npc.php index 1c1148a4..8e12bd2d 100644 --- a/pages/npc.php +++ b/pages/npc.php @@ -18,6 +18,8 @@ class NpcPage extends GenericPage protected $mode = CACHE_TYPE_PAGE; protected $js = ['swfobject.js']; + private $soundIds = []; + public function __construct($pageCall, $id) { parent::__construct($pageCall, $id); @@ -581,7 +583,7 @@ class NpcPage extends GenericPage { $mode = ($_altIds[$id] + 1) * ($mapType == 1 ? -1 : 1); if ($lootGO = DB::Aowow()->selectRow('SELECT o.id, o.lootId, o.name_loc0, o.name_loc2, o.name_loc3, o.name_loc6, o.name_loc8 FROM ?_loot_link l JOIN ?_objects o ON o.id = l.objectId WHERE l.npcId = ?d', $id)) - array_splice($sourceFor, 1, 0, [[LOOT_GAMEOBJECT, $lootGO['lootId'], $langref[$mode], 'drops-object-'.abs($mode), [], 'note' => '$$WH.sprintf(LANG.lvnote_npcobjectsource, '.$lootGO['id'].', \''.Util::jsEscape(Util::localizedString($lootGO, 'name')).'\')']]); + array_splice($sourceFor, 1, 0, [[LOOT_GAMEOBJECT, $lootGO['lootId'], $langref[$mode], 'drops-object-'.abs($mode), [], 'note' => '$$WH.sprintf(LANG.lvnote_npcobjectsource, '.$lootGO['id'].', "'.Util::localizedString($lootGO, 'name').'")']]); if ($lootId = $_altNPCs->getField('lootId')) array_splice($sourceFor, 1, 0, [[LOOT_CREATURE, $lootId, $langref[$mode], 'drops-'.abs($mode), []]]); } @@ -589,7 +591,7 @@ class NpcPage extends GenericPage if ($lootGOs = DB::Aowow()->select('SELECT o.id, IF(npcId < 0, 1, 0) AS modeDummy, o.lootId, o.name_loc0, o.name_loc2, o.name_loc3, o.name_loc6, o.name_loc8 FROM ?_loot_link l JOIN ?_objects o ON o.id = l.objectId WHERE ABS(l.npcId) = ?d', $this->typeId)) foreach ($lootGOs as $idx => $lgo) - array_splice($sourceFor, 1, 0, [[LOOT_GAMEOBJECT, $lgo['lootId'], $mapType ? $langref[($mapType == 1 ? -1 : 1) + ($lgo['modeDummy'] ? 1 : 0)] : '$LANG.tab_drops', 'drops-object-'.$idx, [], 'note' => '$$WH.sprintf(LANG.lvnote_npcobjectsource, '.$lgo['id'].', \''.Util::jsEscape(Util::localizedString($lgo, 'name')).'\')']]); + array_splice($sourceFor, 1, 0, [[LOOT_GAMEOBJECT, $lgo['lootId'], $mapType ? $langref[($mapType == 1 ? -1 : 1) + ($lgo['modeDummy'] ? 1 : 0)] : '$LANG.tab_drops', 'drops-object-'.$idx, [], 'note' => '$$WH.sprintf(LANG.lvnote_npcobjectsource, '.$lgo['id'].', "'.Util::localizedString($lgo, 'name').'")']]); $reqQuest = []; foreach ($sourceFor as $sf) @@ -752,6 +754,58 @@ class NpcPage extends GenericPage $this->lvTabs[] = ['creature', $tabData]; } } + + /* tab sounds: + * activity sounds => CreatureDisplayInfo.dbc => (CreatureModelData.dbc => ) CreatureSoundData.dbc + * AI => smart_scripts + * Dialogue VO => creature_text + * onClick VO => CreatureDisplayInfo.dbc => NPCSounds.dbc + */ + $ssActionLists = DB::World()->select('SELECT action_type, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6 FROM smart_scripts WHERE entryorguid = ?d AND source_type = 0 AND action_type IN (80, 87, 88)', $this->typeId); + $actionListIds = []; + foreach ($ssActionLists as $sal) + { + $iMax = 0; + switch ($sal['action_type']) + { + case 80: $iMax = 1; break; + case 87: $iMax = 6; break; + case 88: $iMax = 2; break; + default: continue; + } + + for ($i = 1; $i <= $iMax; $i++) + if ($sal['action_param'.$i]) + $actionListIds[] = $sal['action_param'.$i]; + } + + // not going for a per guid basis. The infos are nested enough as is. + $smartScripts = DB::World()->selectCol('SELECT action_param1 FROM smart_scripts WHERE action_type = 4 AND ((source_type = 0 AND entryorguid = ?d) { OR (source_type = 9 AND entryorguid IN (?a)) } )', $this->typeId, $actionListIds ?: DBSIMPLE_SKIP); + $this->soundIds = array_merge($this->soundIds, $smartScripts); + + // up to 4 possible displayIds .. for the love of things betwixt, just use the first! + $activitySounds = DB::Aowow()->selectRow('SELECT * FROM ?_creature_sounds WHERE id = ?d', $this->subject->getField('displayId1')); + array_shift($activitySounds); // remove id-column + $this->soundIds = array_merge($this->soundIds, array_values($activitySounds)); + + if ($this->soundIds) + { + $sounds = new SoundList(array(['id', $this->soundIds])); + if (!$sounds->error) + { + $data = $sounds->getListviewData(); + foreach ($activitySounds as $activity => $id) + if (isset($data[$id])) + $data[$id]['activity'] = $activity; // no index, js wants a string :( + + $tabData = ['data' => array_values($data)]; + if ($activitySounds) + $tabData['visibleCols'] = ['activity']; + + $this->extendGlobalData($sounds->getJSGlobals(GLOBALINFO_SELF)); + $this->lvTabs[] = ['sound', $tabData]; + } + } } protected function generateTooltip($asError = false) @@ -908,7 +962,8 @@ class NpcPage extends GenericPage IFNULL(NULLIF(lbct.MaleText_loc2, ""), IFNULL(NULLIF(lbct.FemaleText_loc2, ""), IFNULL(lct.text_loc2, ""))) AS text_loc2, IFNULL(NULLIF(lbct.MaleText_loc3, ""), IFNULL(NULLIF(lbct.FemaleText_loc3, ""), IFNULL(lct.text_loc3, ""))) AS text_loc3, IFNULL(NULLIF(lbct.MaleText_loc6, ""), IFNULL(NULLIF(lbct.FemaleText_loc6, ""), IFNULL(lct.text_loc6, ""))) AS text_loc6, - IFNULL(NULLIF(lbct.MaleText_loc8, ""), IFNULL(NULLIF(lbct.FemaleText_loc8, ""), IFNULL(lct.text_loc8, ""))) AS text_loc8 + IFNULL(NULLIF(lbct.MaleText_loc8, ""), IFNULL(NULLIF(lbct.FemaleText_loc8, ""), IFNULL(lct.text_loc8, ""))) AS text_loc8, + IF(bct.SoundId > 0, bct.SoundId, ct.sound) AS soundId FROM creature_text ct LEFT JOIN @@ -927,6 +982,9 @@ class NpcPage extends GenericPage $group = []; foreach ($text as $t) { + if ($t['soundId']) + $this->soundIds[] = $t['soundId']; + $msg = Util::localizedString($t, 'text'); if (!$msg) continue; diff --git a/pages/objects.php b/pages/objects.php index 3087bfe4..a8f7eac3 100644 --- a/pages/objects.php +++ b/pages/objects.php @@ -31,6 +31,8 @@ class ObjectsPage extends GenericPage protected function generateContent() { + $this->addJS('?data=zones&locale='.User::$localeId.'&t='.$_SESSION['dataKey']); + $conditions = []; if (!User::isInGroup(U_GROUP_EMPLOYEE)) diff --git a/pages/race.php b/pages/race.php index fd5ddcc9..d21d0a33 100644 --- a/pages/race.php +++ b/pages/race.php @@ -183,6 +183,24 @@ class RacePage extends GenericPage 'hiddenCols' => ['slot', 'type'] )]; } + + // Sounds + if ($vo = DB::Aowow()->selectCol('SELECT soundId AS ARRAY_KEY, gender FROM ?_races_sounds WHERE raceId = ?d', $this->typeId)) + { + $sounds = new SoundList(array(['id', array_keys($vo)])); + if (!$sounds->error) + { + $this->extendGlobalData($sounds->getJSGlobals(GLOBALINFO_SELF)); + $data = $sounds->getListviewData(); + foreach ($data as $id => &$d) + $d['gender'] = $vo[$id]; + + $this->lvTabs[] = ['sound', array( + 'data' => array_values($data), + 'extraCols' => ['$Listview.templates.title.columns[1]'] + )]; + } + } } } diff --git a/pages/search.php b/pages/search.php index 90810d1f..6c4cfd1e 100644 --- a/pages/search.php +++ b/pages/search.php @@ -52,7 +52,7 @@ class SearchPage extends GenericPage '_searchProficiency', '_searchProfession', '_searchCompanion', '_searchMount', '_searchCreature', '_searchQuest', '_searchAchievement', '_searchStatistic', '_searchZone', '_searchObject', '_searchFaction', '_searchSkill', '_searchPet', '_searchCreatureAbility', '_searchSpell', - '_searchEmote', '_searchEnchantment' + '_searchEmote', '_searchEnchantment', '_searchSound' ); public function __construct($pageCall, $pageParam) @@ -1359,9 +1359,35 @@ class SearchPage extends GenericPage return false; } - // private function _searchCharacter($cndBase) { } // 27 Characters $searchMask & 0x8000000 - // private function _searchGuild($cndBase) { } // 28 Guilds $searchMask & 0x10000000 - // private function _searchArenaTeam($cndBase) { } // 29 Arena Teams $searchMask & 0x20000000 + private function _searchSound($cndBase) // 27 Sounds $searchMask & 0x8000000 + { + $cnd = array_merge($cndBase, [$this->createLookup(['name'])]); + $sounds = new SoundList($cnd); + + if ($data = $sounds->getListviewData()) + { + if ($this->searchMask & SEARCH_TYPE_REGULAR) + $this->extendGlobalData($sounds->getJSGlobals()); + + $osInfo = [TYPE_SOUND, ' (Sound)', $sounds->getMatches()]; + $result['data'] = array_values($data); + + if ($sounds->getMatches() > $this->maxResults) + { + $result['note'] = sprintf(Util::$tryNarrowingString, 'LANG.lvnote_soundsfound', $sounds->getMatches(), $this->maxResults); + $result['_truncated'] = 1; + } + + return ['sound', $result, null, $osInfo]; + } + + return false; + } + + + // private function _searchCharacter($cndBase) { } // 28 Characters $searchMask & 0x10000000 + // private function _searchGuild($cndBase) { } // 29 Guilds $searchMask & 0x20000000 + // private function _searchArenaTeam($cndBase) { } // 30 Arena Teams $searchMask & 0x40000000 } ?> diff --git a/pages/sound.php b/pages/sound.php new file mode 100644 index 00000000..c125965a --- /dev/null +++ b/pages/sound.php @@ -0,0 +1,369 @@ +special = true; + $this->name = Lang::sound('cat', 1000); + $this->cat = 1000; + $this->typeId = -1000; + } + // regular case + else + { + $this->typeId = intVal($id); + + $this->subject = new SoundList(array(['id', $this->typeId])); + if ($this->subject->error) + $this->notFound(Lang::game('sound'), Lang::sound('notFound')); + + $this->name = $this->subject->getField('name'); + $this->cat = $this->subject->getField('cat'); + } + } + + protected function generatePath() + { + $this->path[] = $this->cat; + } + + protected function generateTitle() + { + array_unshift($this->title, $this->name, Util::ucFirst(Lang::game('sound'))); + } + + protected function generateContent() + { + if ($this->special) + $this->generatePlaylistContent(); + else + $this->generateDefaultContent(); + } + + private function generatePlaylistContent() + { + + } + + private function generateDefaultContent() + { + /****************/ + /* Main Content */ + /****************/ + + $this->addJS('?data=zones&locale='.User::$localeId.'&t='.$_SESSION['dataKey']); + + // get spawns + $map = null; + if ($spawns = $this->subject->getSpawns(SPAWNINFO_FULL)) + { + $map = ['data' => ['parent' => 'mapper-generic'], 'mapperData' => &$spawns]; + foreach ($spawns as $areaId => &$areaData) + $map['extra'][$areaId] = ZoneList::getName($areaId); + } + + // get full path ingame for sound (workaround for missing PlaySoundKit()) + $fullpath = DB::Aowow()->selectCell('SELECT IF(sf.`path`, CONCAT(sf.`path`, "\\\\", sf.`file`), sf.`file`) FROM ?_sounds_files sf JOIN ?_sounds s ON s.soundFile1 = sf.id WHERE s.id = ?d', $this->typeId); + + $this->map = $map; + $this->headIcons = [$this->subject->getField('iconString')]; + $this->redButtons = array( + BUTTON_WOWHEAD => true, + BUTTON_PLAYLIST => true, + BUTTON_LINKS => array( + 'type' => TYPE_SOUND, + 'typeId' => $this->typeId, + 'sound' => str_replace('\\', '\\\\', $fullpath) // escape for wow client + ) + ); + + $this->extendGlobalData($this->subject->getJSGlobals()); + + + /**************/ + /* Extra Tabs */ + /**************/ + + // tab: Spells + // skipping (always empty): ready, castertargeting, casterstate, targetstate + $displayIds = DB::Aowow()->selectCol(' + SELECT id FROM ?_spell_sounds WHERE + animation = ?d OR + precast = ?d OR + cast = ?d OR + impact = ?d OR + state = ?d OR + statedone = ?d OR + channel = ?d OR + casterimpact = ?d OR + targetimpact = ?d OR + missiletargeting = ?d OR + instantarea = ?d OR + persistentarea = ?d OR + missile = ?d OR + impactarea = ?d + ', $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId); + + $cnd = array( + 'OR', + ['AND', ['effect1Id', 132], ['effect1MiscValue', $this->typeId]], + ['AND', ['effect2Id', 132], ['effect2MiscValue', $this->typeId]], + ['AND', ['effect3Id', 132], ['effect3MiscValue', $this->typeId]] + ); + + if ($displayIds) + $cnd[] = ['spellVisualId', $displayIds]; + + $spells = new SpellList($cnd); + if (!$spells->error) + { + $data = $spells->getListviewData(); + $this->extendGlobalData($spells->getJSGlobals(GLOBALINFO_SELF)); + + $this->lvTabs[] = ['spell', array( + 'data' => array_values($data), + )]; + } + + + // tab: Items + $subClasses = []; + if ($subClassMask = DB::Aowow()->selectCell('SELECT subClassMask FROM ?_items_sounds WHERE soundId = ?d', $this->typeId)) + for ($i = 0; $i <= 20; $i++) + if ($subClassMask & (1 << $i)) + $subClasses[] = $i; + + $itemIds = DB::Aowow()->selectCol(' + SELECT + id + FROM + ?_items + WHERE + {spellVisualId IN (?a) OR } + pickUpSoundId = ?d OR + dropDownSoundId = ?d OR + sheatheSoundId = ?d OR + unsheatheSoundId = ?d {OR + ( + IF (soundOverrideSubclass > 0, soundOverrideSubclass, subclass) IN (?a) AND + class = ?d + )} + ', $displayIds ?: DBSIMPLE_SKIP, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $subClasses ?: DBSIMPLE_SKIP, ITEM_CLASS_WEAPON); + if ($itemIds) + { + $items = new ItemList(array(['id', $itemIds])); + if (!$items->error) + { + $this->extendGlobalData($items->getJSGlobals(GLOBALINFO_SELF)); + $this->lvTabs[] = ['item', ['data' => array_values($items->getListviewData())]]; + } + } + + + // tab: Zones + if ($zoneIds = DB::Aowow()->select('SELECT id, worldStateId, worldStateValue FROM ?_zones_sounds WHERE ambienceDay = ?d OR ambienceNight = ?d OR musicDay = ?d OR musicNight = ?d OR intro = ?d', $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId)) + { + $zones = new ZoneList(array(['id', array_column($zoneIds, 'id')])); + if (!$zones->error) + { + $this->extendGlobalData($zones->getJSGlobals(GLOBALINFO_SELF)); + + $zoneData = $zones->getListviewData(); + $parents = $zones->getAllFields('parentArea'); + $tabData = []; + $pIds = array_filter(array_unique(array_values($parents))); + if ($pIds) + { + $pZones = new ZoneList(array(['id', $pIds])); + if (!$pZones->error) + { + $this->extendGlobalData($pZones->getJSGlobals(GLOBALINFO_SELF)); + + $pData = $pZones->getListviewData(); + foreach ($parents as $child => $parent) + { + if (!$parent || empty($pData[$parent])) + continue; + + if (!isset($pData[$parent]['subzones'])) + $pData[$parent]['subzones'] = []; + + $pData[$parent]['subzones'][] = $child; + unset($parents[$child]); + } + + // these are original parents + foreach ($parents as $parent => $__) + if (empty($pData[$parent])) + $pData[$parent] = $zoneData[$parent]; + + $zoneData = $pData; + } + } + + if (array_filter(array_column($zoneIds, 'worldStateId'))) + { + $tabData['extraCols'] = ['$Listview.extraCols.condition']; + + foreach ($zoneIds as $zData) + if ($zData['worldStateId']) + $zoneData[$zData['id']]['condition'][0][$this->typeId][] = [[CND_WORLD_STATE, $zData['worldStateId'], $zData['worldStateValue']]]; + } + + $tabData['data'] = array_values($zoneData); + $tabData['hiddenCols'] = ['territory']; + + $this->lvTabs[] = ['zone', $tabData]; + } + } + + + // tab: Races (VocalUISounds (containing error voice overs)) + if ($vo = DB::Aowow()->selectCol('SELECT raceId FROM ?_races_sounds WHERE soundId = ?d GROUP BY raceId', $this->typeId)) + { + $races = new CharRaceList(array(['id', $vo])); + if (!$races->error) + { + $this->extendGlobalData($races->getJSGlobals(GLOBALINFO_SELF)); + $this->lvTabs[] = ['race', ['data' => array_values($races->getListviewData())]]; + } + } + + + // tab: Emotes (EmotesTextSound (containing emote audio)) + if ($em = DB::Aowow()->selectCol('SELECT emoteId FROM ?_emotes_sounds WHERE soundId = ?d GROUP BY emoteId', $this->typeId)) + { + $races = new EmoteList(array(['id', $em])); + if (!$races->error) + { + $this->extendGlobalData($races->getJSGlobals(GLOBALINFO_SELF)); + $this->lvTabs[] = ['emote', array( + 'data' => array_values($races->getListviewData()), + 'name' => Util::ucFirst(Lang::game('emotes')) + ), 'emote']; + } + } + + $ssQuery = ' + SELECT + source_type AS ARRAY_KEY, + entryorguid AS ARRAY_KEY2, + 0 + FROM + smart_scripts + WHERE + (action_type = 4 AND action_param1 = ?d AND source_type <> 9) { + OR (action_type = 80 AND (action_param1 IN (?a))) + OR (action_type = 87 AND (action_param1 IN (?a) OR action_param2 IN (?a) OR action_param3 IN (?a) OR action_param4 IN (?a) OR action_param5 IN (?a) OR action_param6 IN (?a))) + OR (action_type = 88 AND (action_param1 IN (?a) OR action_param2 IN (?a))) + } + '; + + $ssActionLists = DB::World()->selectCol('SELECT entryorguid FROM smart_scripts WHERE action_type = 4 AND action_param1 = ?d AND source_type = 9', $this->typeId); + $smartScripts = DB::World()->selectCol($ssQuery, $this->typeId, $ssActionLists ?: DBSIMPLE_SKIP, $ssActionLists, $ssActionLists, $ssActionLists, $ssActionLists, $ssActionLists, $ssActionLists, $ssActionLists, $ssActionLists); + + $creatureIds = DB::World()->selectCol('SELECT entry FROM creature_text ct LEFT JOIN broadcast_text bct ON bct.ID = ct.BroadCastTextId WHERE bct.SoundId = ?d OR ct.sound = ?d', $this->typeId, $this->typeId); + foreach ($smartScripts as $source => $ids) + { + switch($source) + { + case 0: // npc + // filter for guids (id < 0) + $creatureIds = array_merge($creatureIds, array_keys(array_filter($ids, function($x) { return $x > 0; })) ); + break; + case 1: // gameobject + default: + break; + } + } + + + // tab: NPC (dialogues...?, generic creature sound) + // skipping (always empty): transforms, footsteps + $displayIds = DB::Aowow()->selectCol(' + SELECT id FROM ?_creature_sounds WHERE + greeting = ?d OR + farewell = ?d OR + angry = ?d OR + exertion = ?d OR + exertioncritical = ?d OR + injury = ?d OR + injurycritical = ?d OR + death = ?d OR + stun = ?d OR + stand = ?d OR + aggro = ?d OR + wingflap = ?d OR + wingglide = ?d OR + alert = ?d OR + fidget = ?d OR + customattack = ?d OR + `loop` = ?d OR + jumpstart = ?d OR + jumpend = ?d OR + petattack = ?d OR + petorder = ?d OR + petdismiss = ?d OR + birth = ?d OR + spellcast = ?d OR + submerge = ?d OR + submerged = ?d + ', $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId); + + // broadcast_text <-> creature_text + if ($creatureIds || $displayIds) + { + $extra = []; + $cnds = [CFG_SQL_LIMIT_NONE, &$extra]; + if (!User::isInGroup(U_GROUP_STAFF)) + $cnds[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0]; + + if ($creatureIds) + $extra[] = ['id', $creatureIds]; + + if ($displayIds) + $extra[] = ['displayId1', $displayIds]; + + if (count($extra) > 1) + array_unshift($extra, 'OR'); + else + $extra = array_pop($extra); + + $npcs = new CreatureList($cnds); + if (!$npcs->error) + { + $this->addJS('?data=zones&locale='.User::$localeId.'&t='.$_SESSION['dataKey']); + + $this->extendGlobalData($npcs->getJSGlobals(GLOBALINFO_SELF)); + $this->lvTabs[] = ['creature', ['data' => array_values($npcs->getListviewData())]]; + } + } + } +} + + +?> diff --git a/pages/sounds.php b/pages/sounds.php new file mode 100644 index 00000000..17ff3e37 --- /dev/null +++ b/pages/sounds.php @@ -0,0 +1,82 @@ +filterObj = new SoundListFilter(); + + parent::__construct($pageCall, $pageParam); + + $this->name = Util::ucFirst(Lang::game('sounds')); + } + + protected function generateContent() + { + $this->addJs('filters.js'); + + $this->redButtons = array( + BUTTON_WOWHEAD => true, + BUTTON_PLAYLIST => true + ); + + $conditions = []; + if ($_ = $this->filterObj->getConditions()) + $conditions[] = $_; + + $this->filter = array_merge($this->filterObj->getForm('form'), $this->filter); + $this->filter['query'] = isset($_GET['filter']) ? $_GET['filter'] : null; + $this->filter['fi'] = $this->filterObj->getForm(); + + $sounds = new SoundList($conditions); + $tabData = []; + if (!$sounds->error) + { + $tabData['data'] = array_values($sounds->getListviewData()); + + // create note if search limit was exceeded; overwriting 'note' is intentional + if ($sounds->getMatches() > CFG_SQL_LIMIT_DEFAULT) + { + $tabData['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_soundsfound', $sounds->getMatches(), CFG_SQL_LIMIT_DEFAULT); + $tabData['_truncated'] = 1; + } + + if ($this->filterObj->error) + $tabData['_errors'] = 1; + } + $this->lvTabs[] = ['sound', $tabData]; + + Lang::sort('sound', 'cat'); + } + + protected function generateTitle() + { + $form = $this->filterObj->getForm('form'); + if (isset($form['ty']) && !is_array($form['ty'])) + array_unshift($this->title, Lang::sound('cat', $form['ty'])); + } + + protected function generatePath() + { + $form = $this->filterObj->getForm('form'); + if (isset($form['ty']) && !is_array($form['ty'])) + $this->path[] = $form['ty']; + } +} + +?> diff --git a/pages/spell.php b/pages/spell.php index 5d0f8da0..3f3027ff 100644 --- a/pages/spell.php +++ b/pages/spell.php @@ -1083,6 +1083,29 @@ class SpellPage extends GenericPage $this->extendGlobalData($enchList->getJSGlobals()); } + // tab: sounds + $activitySounds = DB::Aowow()->selectRow('SELECT * FROM ?_spell_sounds WHERE id = ?d', $this->subject->getField('spellVisualId')); + array_shift($activitySounds); // remove id-column + if ($activitySounds) + { + $sounds = new SoundList(array(['id', $activitySounds])); + if (!$sounds->error) + { + $data = $sounds->getListviewData(); + foreach ($activitySounds as $activity => $id) + if (isset($data[$id])) + $data[$id]['activity'] = $activity; // no index, js wants a string :( + + $tabData = ['data' => array_values($data)]; + if ($activitySounds) + $tabData['visibleCols'] = ['activity']; + + $this->extendGlobalData($sounds->getJSGlobals(GLOBALINFO_SELF)); + $this->lvTabs[] = ['sound', $tabData]; + } + } + + // find associated NPC, Item and merge results // taughtbypets (unused..?) // taughtbyquest (usually the spell casted as quest reward teaches something; exclude those seplls from taughtBySpell) @@ -1726,6 +1749,9 @@ class SpellPage extends GenericPage $foo['name'] .= ' ('.$_.')'; break; + case 132: // Play Sound + $foo['sound'] = $effMV; + break; case 123: // Send Taxi - effMV is taxiPathId. We only use paths for flightmasters for now, so spell-triggered paths are not in the table default: { @@ -1978,7 +2004,7 @@ class SpellPage extends GenericPage } // cases where we dont want 'Value' to be displayed - if (in_array($effAura, [11, 12, 36, 77]) || in_array($effId, []) || empty($foo['value'])) + if (in_array($effAura, [11, 12, 36, 77]) || in_array($effId, [132]) || empty($foo['value'])) unset($foo['value']); } diff --git a/pages/zone.php b/pages/zone.php index 53a7cb05..6bbb34d3 100644 --- a/pages/zone.php +++ b/pages/zone.php @@ -392,6 +392,8 @@ class ZonePage extends GenericPage } } + unset($data); + // append paths between nodes if ($flightNodes) { @@ -494,7 +496,7 @@ class ZonePage extends GenericPage { $this->lvTabs[] = ['quest', array( 'data' => array_values($questsLV), - 'note' => '$$WH.sprintf(LANG.lvnote_zonequests, '.$this->subject->getField('mapId').', '.$this->typeId.', \''.Util::jsEscape($this->subject->getField('name', true)).'\', '.$this->typeId.')' + 'note' => '$$WH.sprintf(LANG.lvnote_zonequests, '.$this->subject->getField('mapId').', '.$this->typeId.',"'.$this->subject->getField('name', true).'", '.$this->typeId.')' )]; } @@ -685,6 +687,59 @@ class ZonePage extends GenericPage $this->extendGlobalData($subZones->getJSGlobals(GLOBALINFO_SELF)); } + + // tab: sound (including subzones; excluding parents) + $areaIds = []; + if (!$subZones->error) + $areaIds = $subZones->getFoundIDs(); + + $areaIds[] = $this->typeId; + + $soundIds = []; + $zoneMusic = DB::Aowow()->select(' + SELECT + x.soundId, x.worldStateId, x.worldStateValue + FROM ( + SELECT ambienceDay AS soundId, worldStateId, worldStateValue FROM ?_zones_sounds WHERE id IN (?a) AND ambienceDay > 0 UNION + SELECT ambienceNight AS soundId, worldStateId, worldStateValue FROM ?_zones_sounds WHERE id IN (?a) AND ambienceNight > 0 UNION + SELECT musicDay AS soundId, worldStateId, worldStateValue FROM ?_zones_sounds WHERE id IN (?a) AND musicDay > 0 UNION + SELECT musicNight AS soundId, worldStateId, worldStateValue FROM ?_zones_sounds WHERE id IN (?a) AND musicNight > 0 UNION + SELECT intro AS soundId, worldStateId, worldStateValue FROM ?_zones_sounds WHERE id IN (?a) AND intro > 0 + ) x + GROUP BY + x.soundId, x.worldStateId, x.worldStateValue + ', $areaIds, $areaIds, $areaIds, $areaIds, $areaIds); + + if ($sSpawns = DB::Aowow()->selectCol('SELECT typeId FROM ?_spawns WHERE areaId = ?d AND type = ?d', $this->typeId, TYPE_SOUND)) + $soundIds = array_merge($soundIds, $sSpawns); + + if ($zoneMusic) + $soundIds = array_merge($soundIds, array_column($zoneMusic, 'soundId')); + + if ($soundIds) + { + $music = new SoundList(array(['id', array_unique($soundIds)])); + if (!$music->error) + { + $data = $music->getListviewData(); + $tabData = []; + + if (array_filter(array_column($soundIds, 'worldStateId'))) + { + $tabData['extraCols'] = ['$Listview.extraCols.condition']; + + foreach ($soundIds as $sData) + if ($sData['worldStateId']) + $data[$sData['soundId']]['condition'][0][$this->typeId][] = [[CND_WORLD_STATE, $sData['worldStateId'], $sData['worldStateValue']]]; + } + + $tabData['data'] = array_values($data); + + $this->lvTabs[] = ['sound', $tabData]; + + $this->extendGlobalData($music->getJSGlobals(GLOBALINFO_SELF)); + } + } } protected function generatePath() diff --git a/setup/db_structure.sql b/setup/db_structure.sql index 6d4e2cd8..8f121dd4 100644 --- a/setup/db_structure.sql +++ b/setup/db_structure.sql @@ -1136,6 +1136,7 @@ CREATE TABLE `aowow_items` ( `classBak` tinyint(3) NOT NULL, `subClass` tinyint(3) NOT NULL DEFAULT '0', `subClassBak` tinyint(3) NOT NULL, + `soundOverrideSubclass` tinyint(3) NOT NULL, `subSubClass` tinyint(3) NOT NULL, `name_loc0` varchar(127) NOT NULL DEFAULT '', `name_loc2` varchar(127) DEFAULT NULL, @@ -1143,6 +1144,7 @@ CREATE TABLE `aowow_items` ( `name_loc6` varchar(127) DEFAULT NULL, `name_loc8` varchar(127) DEFAULT NULL, `displayId` mediumint(8) unsigned NOT NULL DEFAULT '0', + `spellVisualId` smallint(5) unsigned NOT NULL DEFAULT '0', `quality` tinyint(3) unsigned NOT NULL DEFAULT '0', `flags` bigint(20) NOT NULL DEFAULT '0', `flagsExtra` int(10) unsigned NOT NULL DEFAULT '0', @@ -1253,6 +1255,7 @@ CREATE TABLE `aowow_items` ( `languageId` tinyint(3) unsigned NOT NULL DEFAULT '0', `startQuest` mediumint(8) unsigned NOT NULL DEFAULT '0', `lockId` mediumint(8) unsigned NOT NULL DEFAULT '0', + `material` tinyint(3) NOT NULL DEFAULT '0', `randomEnchant` mediumint(8) NOT NULL DEFAULT '0', `itemset` mediumint(8) unsigned NOT NULL DEFAULT '0', `durability` smallint(5) unsigned NOT NULL DEFAULT '0', @@ -1278,6 +1281,10 @@ CREATE TABLE `aowow_items` ( `gemEnchantmentId` mediumint(8) NOT NULL, `minMoneyLoot` int(10) unsigned NOT NULL DEFAULT '0', `maxMoneyLoot` int(10) unsigned NOT NULL DEFAULT '0', + `pickUpSoundId` smallint(5) unsigned NOT NULL DEFAULT '0', + `dropDownSoundId` smallint(5) unsigned NOT NULL DEFAULT '0', + `sheatheSoundId` smallint(5) unsigned NOT NULL DEFAULT '0', + `unsheatheSoundId` smallint(5) unsigned NOT NULL DEFAULT '0', `flagsCustom` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `idx_name` (`name_loc0`), @@ -2119,6 +2126,7 @@ CREATE TABLE `aowow_spell` ( `iconId` smallint(5) unsigned NOT NULL, `iconIdAlt` mediumint(9) NOT NULL, `rankNo` tinyint(3) unsigned NOT NULL, + `spellVisualId` smallint(5) unsigned NOT NULL, `name_loc0` varchar(85) NOT NULL, `name_loc2` varchar(85) NOT NULL, `name_loc3` varchar(85) NOT NULL, @@ -2420,6 +2428,138 @@ CREATE TABLE `aowow_zones` ( /*!40101 SET character_set_client = @saved_cs_client */; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; +DROP TABLE IF EXISTS `aowow_zones_sounds`; +CREATE TABLE `aowow_zones_sounds` ( + `id` smallint(5) unsigned NOT NULL, + `ambienceDay` smallint(5) unsigned NOT NULL, + `ambienceNight` smallint(5) unsigned NOT NULL, + `musicDay` smallint(5) unsigned NOT NULL, + `musicNight` smallint(5) unsigned NOT NULL, + `intro` smallint(5) unsigned NOT NULL, + `worldStateId` smallint(5) unsigned NOT NULL, + `worldStateValue` smallint(6) NOT NULL, + INDEX `id` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `aowow_creature_sounds`; +CREATE TABLE IF NOT EXISTS `aowow_creature_sounds` ( + `id` smallint(5) unsigned NOT NULL COMMENT 'CreatureDisplayInfo.dbc/id', + `greeting` smallint(5) unsigned NOT NULL, + `farewell` smallint(5) unsigned NOT NULL, + `angry` smallint(5) unsigned NOT NULL, + `exertion` smallint(5) unsigned NOT NULL, + `exertioncritical` smallint(5) unsigned NOT NULL, + `injury` smallint(5) unsigned NOT NULL, + `injurycritical` smallint(5) unsigned NOT NULL, + `death` smallint(5) unsigned NOT NULL, + `stun` smallint(5) unsigned NOT NULL, + `stand` smallint(5) unsigned NOT NULL, + `footstep` smallint(5) unsigned NOT NULL, + `aggro` smallint(5) unsigned NOT NULL, + `wingflap` smallint(5) unsigned NOT NULL, + `wingglide` smallint(5) unsigned NOT NULL, + `alert` smallint(5) unsigned NOT NULL, + `fidget` smallint(5) unsigned NOT NULL, + `customattack` smallint(5) unsigned NOT NULL, + `loop` smallint(5) unsigned NOT NULL, + `jumpstart` smallint(5) unsigned NOT NULL, + `jumpend` smallint(5) unsigned NOT NULL, + `petattack` smallint(5) unsigned NOT NULL, + `petorder` smallint(5) unsigned NOT NULL, + `petdismiss` smallint(5) unsigned NOT NULL, + `birth` smallint(5) unsigned NOT NULL, + `spellcast` smallint(5) unsigned NOT NULL, + `submerge` smallint(5) unsigned NOT NULL, + `submerged` smallint(5) unsigned NOT NULL, + `transform` smallint(5) unsigned NOT NULL, + `transformanimated` smallint(5) unsigned NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='!ATTENTION!\r\nthe primary key of this table is NOT a creatureId, but displayId\r\n\r\ncolumn names from LANG.sound_activities'; + +DROP TABLE IF EXISTS `aowow_emotes_sounds`; +CREATE TABLE IF NOT EXISTS `aowow_emotes_sounds` ( + `emoteId` smallint(5) unsigned NOT NULL, + `raceId` tinyint(3) unsigned NOT NULL, + `gender` tinyint(1) unsigned NOT NULL, + `soundId` smallint(5) unsigned NOT NULL, + UNIQUE KEY `emoteId_raceId_gender_soundId` (`emoteId`,`raceId`,`gender`,`soundId`), + KEY `emoteId` (`emoteId`), + KEY `raceId` (`raceId`), + KEY `soundId` (`soundId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `aowow_races_sounds`; +CREATE TABLE IF NOT EXISTS `aowow_races_sounds` ( + `raceId` tinyint(3) unsigned NOT NULL, + `soundId` smallint(5) unsigned NOT NULL, + `gender` tinyint(1) unsigned NOT NULL, + UNIQUE KEY `race_soundId_gender` (`raceId`,`soundId`,`gender`), + KEY `race` (`raceId`), + KEY `soundId` (`soundId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `aowow_sounds`; +CREATE TABLE IF NOT EXISTS `aowow_sounds` ( + `id` smallint(5) unsigned NOT NULL, + `cat` tinyint(3) unsigned NOT NULL, + `name` varchar(100) NOT NULL, + `cuFlags` int(10) unsigned NOT NULL, + `soundFile1` smallint(5) unsigned DEFAULT NULL, + `soundFile2` smallint(5) unsigned DEFAULT NULL, + `soundFile3` smallint(5) unsigned DEFAULT NULL, + `soundFile4` smallint(5) unsigned DEFAULT NULL, + `soundFile5` smallint(5) unsigned DEFAULT NULL, + `soundFile6` smallint(5) unsigned DEFAULT NULL, + `soundFile7` smallint(5) unsigned DEFAULT NULL, + `soundFile8` smallint(5) unsigned DEFAULT NULL, + `soundFile9` smallint(5) unsigned DEFAULT NULL, + `soundFile10` smallint(5) unsigned DEFAULT NULL, + `flags` mediumint(8) unsigned NOT NULL, + PRIMARY KEY (`id`), + KEY `cat` (`cat`), + KEY `name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `aowow_sounds_files`; +CREATE TABLE IF NOT EXISTS `aowow_sounds_files` ( + `id` smallint(6) NOT NULL COMMENT '<0 not found in client files', + `file` varchar(75) NOT NULL, + `path` varchar(75) NOT NULL COMMENT 'in client', + `type` tinyint(1) unsigned NOT NULL COMMENT '1: ogg; 2: mp3', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `aowow_spell_sounds`; +CREATE TABLE IF NOT EXISTS `aowow_spell_sounds` ( + `id` smallint(5) unsigned NOT NULL COMMENT 'SpellVisual.dbc/id', + `animation` smallint(5) unsigned NOT NULL, + `ready` smallint(5) unsigned NOT NULL, + `precast` smallint(5) unsigned NOT NULL, + `cast` smallint(5) unsigned NOT NULL, + `impact` smallint(5) unsigned NOT NULL, + `state` smallint(5) unsigned NOT NULL, + `statedone` smallint(5) unsigned NOT NULL, + `channel` smallint(5) unsigned NOT NULL, + `casterimpact` smallint(5) unsigned NOT NULL, + `targetimpact` smallint(5) unsigned NOT NULL, + `castertargeting` smallint(5) unsigned NOT NULL, + `missiletargeting` smallint(5) unsigned NOT NULL, + `instantarea` smallint(5) unsigned NOT NULL, + `persistentarea` smallint(5) unsigned NOT NULL, + `casterstate` smallint(5) unsigned NOT NULL, + `targetstate` smallint(5) unsigned NOT NULL, + `missile` smallint(5) unsigned NOT NULL COMMENT 'not predicted by js', + `impactarea` smallint(5) unsigned NOT NULL COMMENT 'not predicted by js', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='!ATTENTION!\r\nthe primary key of this table is NOT a spellId, but spellVisualId\r\n\r\ncolumn names from LANG.sound_activities'; + +DROP TABLE IF EXISTS `aowow_items_sounds`; +CREATE TABLE `aowow_items_sounds` ( + `soundId` smallint(5) unsigned NOT NULL, + `subClassMask` mediumint(8) unsigned NOT NULL, + PRIMARY KEY (`soundId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='actually .. its only weapon related sounds in here'; + /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; @@ -2513,7 +2653,7 @@ UNLOCK TABLES; LOCK TABLES `aowow_dbversion` WRITE; /*!40000 ALTER TABLE `aowow_dbversion` DISABLE KEYS */; -INSERT INTO `aowow_dbversion` VALUES (1484926142,0,NULL,NULL); +INSERT INTO `aowow_dbversion` VALUES (1488745159,0,NULL,NULL); /*!40000 ALTER TABLE `aowow_dbversion` ENABLE KEYS */; UNLOCK TABLES; diff --git a/setup/tools/CLISetup.class.php b/setup/tools/CLISetup.class.php index 9fcfef14..5c4ed55e 100644 --- a/setup/tools/CLISetup.class.php +++ b/setup/tools/CLISetup.class.php @@ -328,6 +328,42 @@ class CLISetup return false; } + public static function nicePath(/* $file = '', ...$pathParts */) + { + $path = ''; + + switch (func_num_args()) + { + case 0: + return ''; + case 1: + $path = func_get_arg(0); + break; + default: + $args = func_get_args(); + $file = array_shift($args); + $path = implode(DIRECTORY_SEPARATOR, $args).DIRECTORY_SEPARATOR.$file; + } + + if (DIRECTORY_SEPARATOR == '/') // *nix + { + $path = str_replace('\\', '/', $path); + $path = preg_replace('/\/+/i', '/', $path); + } + else if (DIRECTORY_SEPARATOR == '\\') // win + { + $path = str_replace('/', '\\', $path); + $path = preg_replace('/\\\\+/i', '\\', $path); + } + else + CLISetup::log('Dafuq! Your directory separator is "'.DIRECTORY_SEPARATOR.'". Please report this!', CLISetup::LOG_ERROR); + + if ($path[0] == DIRECTORY_SEPARATOR) + $path = substr($path, 1); + + return $path; + } + /**************/ /* read input */ /**************/ diff --git a/setup/tools/dbc.class.php b/setup/tools/dbc.class.php index 5e997b39..d42928f0 100644 --- a/setup/tools/dbc.class.php +++ b/setup/tools/dbc.class.php @@ -44,16 +44,18 @@ class DBC 'achievement' => 'niiisxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxiiiiisxssxxsxsxxxxxxxxii', 'achievement_category' => 'nisxssxxsxsxxxxxxxxx', 'achievement_criteria' => 'niiiiiiiisxssxxsxsxxxxxxxxiixii', - 'areatable' => 'niixixxxxxxsxssxxsxsxxxxxxxxixxxxxxx', + 'areatable' => 'niixixxiiixsxssxxsxsxxxxxxxxixxxxxxx', 'battlemasterlist' => 'niixxxxxxixxxxxxxxxxxxxxxxxxixii', 'charbaseinfo' => 'bb', 'charstartoutfit' => 'nbbbXiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'chartitles' => 'nxsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxi', 'chrclasses' => 'nxixsxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxsxixi', 'chrraces' => 'niixxxxixxxsxisxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi', - 'creaturedisplayinfo' => 'nixixxssssxxxxxx', + 'creaturedisplayinfo' => 'niiixxssssxxixxx', 'creaturedisplayinfoextra' => 'nxxxxxxxxxxxxxxxxxxxs', 'creaturefamily' => 'nxxxxixiiisxssxxsxsxxxxxxxxs', + 'creaturemodeldata' => 'nxxxxxxxxxxxxixxxxxxxxxxxxxx', + 'creaturesounddata' => 'niiiixiiiiiiiiixxxxixxxxixiiiiixxiiiix', 'currencytypes' => 'niix', 'dungeonmap' => 'niiffffi', 'durabilitycosts' => 'niiiiiiiiixiiiiiiiiiiixiiiixix', @@ -61,6 +63,7 @@ class DBC 'emotes' => 'nxixxxx', 'emotestext' => 'nsiixxxixixxxxxxxxx', 'emotestextdata' => 'nsxssxxsxsxxxxxxxx', + 'emotestextsound' => 'niiii', 'faction' => 'nixxxxxxxxxxxxixxxiffixsxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxx', 'factiontemplate' => 'nixiiiiiiiiiii', 'gemproperties' => 'nixxi', @@ -77,17 +80,21 @@ class DBC 'holidays' => 'nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxxxxxxxiisxix', 'holidaydescriptions' => 'nsxssxxsxsxxxxxxxx', 'holidaynames' => 'nsxssxxsxsxxxxxxxx', - 'itemdisplayinfo' => 'nssxxsxxxxxxxxxxxxxxxxxxx', + 'itemdisplayinfo' => 'nssxxsxxxxxiixxxxxxxxxxxx', + 'itemgroupsounds' => 'niixx', 'itemextendedcost' => 'niiiiiiiiiiiiiix', 'itemlimitcategory' => 'nsxssxxsxsxxxxxxxxii', 'itemrandomproperties' => 'nsiiiiisxssxxsxsxxxxxxxx', 'itemrandomsuffix' => 'nsxssxxsxsxxxxxxxxsiiiiiiiiii', 'itemset' => 'nsxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiiiii', + 'itemsubclass' => 'iixxxxxxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'lfgdungeons' => 'nsxssxxsxsxxxxxxxxiiiiiiixiixixixxxxxxxxxxxxxxxxx', 'lock' => 'niiiiixxxiiiiixxxiiiiixxxxxxxxxxx', 'mailtemplate' => 'nsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxx', 'map' => 'nsixisxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiffxixi', 'mapdifficulty' => 'niixxxxxxxxxxxxxxxxxxis', + 'material' => 'nxxii', + 'npcsounds' => 'niiix', 'powerdisplay' => 'nisbbb', 'questfactionreward' => 'niiiiiiiiii', 'questxp' => 'niiiiiiiiii', @@ -97,7 +104,10 @@ class DBC 'skillline' => 'nixsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxixxxxxxxxxxxxxxxxxx', 'skilllineability' => 'niiiixxixiiixx', 'skillraceclassinfo' => 'niiiiixx', - 'spell' => 'niiiuuuuuuuuixixxxixxxxxxxxxiiixxxxiiiiiiiiiiiixxiiiiiiiiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffiiiiiiiiixxiixsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxiiiiiiiiiixxfffxxxiixiixifffii', + 'soundambience' => 'nii', + 'soundemitters' => 'nffxxxxiix', + 'soundentries' => 'nisssssssssssxxxxxxxxxxsxixxxx', + 'spell' => 'niiiuuuuuuuuixixxxixxxxxxxxxiiixxxxiiiiiiiiiiiixxiiiiiiiiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffiiiiiiiiiiiiixsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxsxssxxsxsxxxxxxxxiiiiiiiiiixxfffxxxiixiixifffii', 'spellcasttimes' => 'nixx', 'spelldescriptionvariables' => 'ns', 'spelldifficulty' => 'xiiii', @@ -110,15 +120,23 @@ class DBC 'spellrange' => 'nffffisxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxx', 'spellrunecost' => 'niiii', 'spellshapeshiftform' => 'nxsxssxxsxsxxxxxxxxiixxiixxiiiiiiii', + 'spellvisual' => 'niiiiiixxxxiixiixxxxxxiiiixxxxxx', + 'spellvisualkit' => 'nxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxxxxxx', 'talent' => 'niiiiiiiixxxxixxixxixii', 'talenttab' => 'nsxssxxsxsxxxxxxxxiiiiis', 'taxinodes' => 'niffxsxssxxsxsxxxxxxxxxx', 'taxipath' => 'niix', 'taxipathnode' => 'niiiffxxxxx', 'totemcategory' => 'nsxssxxsxsxxxxxxxxiu', + 'vocaluisounds' => 'nxiiixx', + 'weaponimpactsounds' => 'nixiiiiiiiiiiiiiiiiiiii', + 'weaponswingsounds2' => 'nixi', 'worldmaparea' => 'niisffffxix', // 4.x - niisffffxixxxx 'worldmapoverlay' => 'niixxxxxsiiiixxxx', // 4.x - niixxxsiiiixxxx 'worldmaptransforms' => 'niffffiffi', + 'worldstatezonesounds' => 'iiiiiiix', + 'zoneintromusictable' => 'nxixx', + 'zonemusic' => 'nxxxxxii' ); @@ -126,22 +144,25 @@ class DBC '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', + 'areatable' => 'Id,mapId,areaTable,flags,soundAmbience,zoneMusic,zoneIntroMusic,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,bitIdx', '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', + 'creaturedisplayinfo' => 'Id,modelId,creatureSoundId,extraInfoId,skin1,skin2,skin3,iconString,npcSoundId', 'creaturedisplayinfoextra' => 'Id,textureString', 'creaturefamily' => 'Id,skillLine1,petFoodMask,petTalentType,categoryEnumID,name_loc0,name_loc2,name_loc3,name_lo6,name_loc8,iconString', + 'creaturemodeldata' => 'Id,creatureSoundId', + 'creaturesounddata' => 'Id,exertion,exertionCritical,injury,injuryCritical,death,stun,stand,footstepTerrainId,aggro,wingFlap,wingGlide,alert,fidget,customAttack,loop,jumpStart,jumpEnd,petAttack,petOrder,petDismiss,birth,spellcast,submerge,submerged', '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', 'emotes' => 'Id,animationId', 'emotestext' => 'Id,command,emoteId,targetId,noTargetId,selfId', + 'emotestextsound' => 'Id,emotesTextId,raceId,gender,soundId', 'emotestextdata' => 'Id,text_loc0,text_loc2,text_loc3,text_loc6,text_loc8', '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', @@ -159,17 +180,21 @@ class DBC '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', + 'itemdisplayinfo' => 'Id,leftModelName,rightModelName,inventoryIcon1,spellVisualId,groupSoundId', + 'itemgroupsounds' => 'Id,pickUpSoundId,dropDownSoundId', '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', + 'itemsubclass' => 'class,subClass,weaponSize', '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', + 'material' => 'Id,sheatheSoundId,unsheatheSoundId', + 'npcsounds' => 'Id,greetSoundId,byeSoundId,angrySoundId', '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', @@ -179,7 +204,10 @@ class DBC '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', + 'soundambience' => 'Id,soundIdDay,soundIdNight', + 'soundemitters' => 'Id,posY,posX,soundId,mapId', + 'soundentries' => 'Id,type,name,file1,file2,file3,file4,file5,file6,file7,file8,file9,file10,path,flags', + '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,spellVisualId1,spellVisualId2,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', @@ -192,15 +220,23 @@ class DBC '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', + 'spellvisual' => 'Id,precastKitId,castKitId,impactKitId,stateKitId,statedoneKitId,channelKitId,missileSoundId,animationSoundId,casterImpactKitId,targetImpactKitId,missileTargetingKitId,instantAreaKitId,impactAreaKitId,persistentAreaKitId', + 'spellvisualkit' => 'Id,soundId', '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', + 'vocaluisounds' => 'Id,raceId,soundIdMale,soundIdFemale', + 'weaponimpactsounds' => 'Id,subClass,hit1,hit2,hit3,hit4,hit5,hit6,hit7,hit8,hit9,hit10,crit1,crit2,crit3,crit4,crit5,crit6,crit7,crit8,crit9,crit10', + 'weaponswingsounds2' => 'Id,weaponSize,soundId', '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', + 'worldstatezonesounds' => 'stateId,value,areaId,wmoAreaId,zoneIntroMusicId,zoneMusicId,soundAmbienceId', + 'zoneintromusictable' => 'Id,soundId', + 'zonemusic' => 'Id,soundIdDay,soundIdNight' ); private $isGameTable = false; diff --git a/setup/tools/fileGen.class.php b/setup/tools/fileGen.class.php index 72dde13b..d1da2583 100644 --- a/setup/tools/fileGen.class.php +++ b/setup/tools/fileGen.class.php @@ -48,7 +48,8 @@ class FileGen 'enchants' => [['items', 'spell', 'itemenchantment'], null], 'gems' => [['items', 'spell', 'itemenchantment'], null], 'profiler' => [['quests', 'quests_startend', 'spell', 'currencies', 'achievement', 'titles'], null], - 'weightPresets' => [null, null] + 'weightPresets' => [null, null], + 'sounds' => [['sounds_files'], null] ); public static $defaultExecTime = 30; @@ -60,7 +61,8 @@ class FileGen 'static/uploads/screenshots/temp', 'static/uploads/screenshots/thumb', 'static/uploads/temp/', - 'static/download/searchplugins/' + 'static/download/searchplugins/', + 'static/wowsounds/' ); public static $txtConstants = array( diff --git a/setup/tools/filegen/sounds.func.php b/setup/tools/filegen/sounds.func.php new file mode 100644 index 00000000..39960ddc --- /dev/null +++ b/setup/tools/filegen/sounds.func.php @@ -0,0 +1,62 @@ +selectCol('SELECT ABS(id) AS ARRAY_KEY, CONCAT(path, "/", `file`) FROM ?_sounds_files'); + $nFiles = count($files); + $itr = $i = 0; + $nStep = 1000; + foreach ($files as $fileId => $filePath) + { + $i++; + $itr++; + if ($i == $step) + { + $i = 0; + CLISetup::log(' - '.$itr.'/'.$nFiles.' ('.(intVal(100 * $itr / $nFiles).'%) done')); + } + + if (stristr($filePath, '.wav')) // expected file.wav.ogg + $filePath .= '.ogg'; + else // expected file.mp3.mp3 + $filePath .= '.mp3'; + + // just use the first locale available .. i there is no support for multiple audio files anyway + foreach (CLISetup::$expectedPaths as $locStr => $__) + { + // get your paths straight! + $p = CLISetup::nicePath($filePath, CLISetup::$srcDir, $locStr); + + if (CLISetup::fileExists($p)) + { + // copy over to static/wowsounds/ + if (!copy($p, 'static/wowsounds/'.$fileId)) + { + $ok = false; + CLISetup::log(' - could not copy '.CLISetup::bold($p).' into '.CLISetup::bold('static/wowsounds/'.$fileId), CLISetup::LOG_ERROR); + die(); + } + + continue 2; + } + } + + CLISetup::log(' - did not find file: '.CLISetup::bold(CLISetup::nicePath($filePath, CLISetup::$srcDir, '')), CLISetup::LOG_WARN); + // flag as unusable in DB + DB::Aowow()->query('UPDATE ?_sounds_files SET id = ?d WHERE ABS(id) = ?d', -$fileId, $fileId); + } + + return $ok; + } + +?> + diff --git a/setup/tools/sqlGen.class.php b/setup/tools/sqlGen.class.php index 828dde0e..125e4dc3 100644 --- a/setup/tools/sqlGen.class.php +++ b/setup/tools/sqlGen.class.php @@ -52,6 +52,7 @@ class SqlGen 'shapeshiftforms' => [null, null, null, null], 'skillline' => [null, null, null, null], 'emotes' => [null, null, null, null], + 'sounds' => [null, null, null, null], 'itemenchantment' => [null, null, null, ['spell_enchant_proc_data']], 'achievement' => [null, null, null, ['dbc_achievement']], 'creature' => [null, null, null, ['creature_template', 'creature_template_locale', 'creature_classlevelstats', 'instance_encounters']], diff --git a/setup/tools/sqlgen/emotes.func.php b/setup/tools/sqlgen/emotes.func.php index 4299e802..c037d350 100644 --- a/setup/tools/sqlgen/emotes.func.php +++ b/setup/tools/sqlgen/emotes.func.php @@ -9,10 +9,14 @@ if (!CLI) $customData = array( ); -$reqDBC = ['emotes', 'emotestext', 'emotestextdata' /*, 'emotestextsound' */]; +$reqDBC = ['emotes', 'emotestext', 'emotestextdata']; function emotes(/*array $ids = [] */) { + /**********/ + /* Basics */ + /**********/ + $globStrPath = CLISetup::$srcDir.'%sInterface/FrameXML/GlobalStrings.lua'; $allOK = true; $locPath = []; diff --git a/setup/tools/sqlgen/items.func.php b/setup/tools/sqlgen/items.func.php index 7ef6de01..1ffd9612 100644 --- a/setup/tools/sqlgen/items.func.php +++ b/setup/tools/sqlgen/items.func.php @@ -33,9 +33,11 @@ function items(array $ids = []) it.entry, class, class as classBak, subclass, subclass AS subClassBak, + SoundOverrideSubclass, IFNULL(sg.id, 0) AS subSubClass, name, IFNULL(li.name_loc2, ""), IFNULL(li.name_loc3, ""), IFNULL(li.name_loc6, ""), IFNULL(li.name_loc8, ""), displayid, + 0 AS spellVisualId, Quality, Flags, FlagsExtra, BuyCount, BuyPrice, SellPrice, @@ -86,6 +88,7 @@ function items(array $ids = []) LanguageID, startquest, lockid, + Material, IF(RandomProperty > 0, RandomProperty, -RandomSuffix) AS randomEnchant, itemset, MaxDurability, @@ -107,6 +110,10 @@ function items(array $ids = []) FoodType, 0 AS gemEnchantmentId, minMoneyLoot, maxMoneyLoot, + 0 AS pickUpSoundId, + 0 AS dropDownSoundId, + 0 AS sheatheSoundId, + 0 AS unsheatheSoundId, flagsCustom FROM item_template it diff --git a/setup/tools/sqlgen/races.func.php b/setup/tools/sqlgen/races.func.php index 77738acf..33f75d9c 100644 --- a/setup/tools/sqlgen/races.func.php +++ b/setup/tools/sqlgen/races.func.php @@ -25,6 +25,10 @@ $reqDBC = ['chrraces', 'charbaseinfo']; function races() { + /**********/ + /* Basics */ + /**********/ + $baseQuery = ' REPLACE INTO ?_races diff --git a/setup/tools/sqlgen/sounds.func.php b/setup/tools/sqlgen/sounds.func.php new file mode 100644 index 00000000..bba88142 --- /dev/null +++ b/setup/tools/sqlgen/sounds.func.php @@ -0,0 +1,426 @@ + ['cat' => 10] // UR_Algalon_Summon03 (this is not an item pickup) +); +$reqDBC = array( + // base emotes race + 'soundentries', 'emotestextsound', 'vocaluisounds', + // creatures + 'npcsounds', 'creaturesounddata', 'creaturedisplayinfo', 'creaturemodeldata', + // spells + 'spell', 'spellvisual', 'spellvisualkit', + // zones + 'soundambience', 'zonemusic', 'zoneintromusictable', 'worldstatezonesounds', 'areatable', + // items + 'material', 'itemgroupsounds', 'itemdisplayinfo', 'weaponimpactsounds', 'itemsubclass', 'weaponswingsounds2' /*, 'sheathesoundlookups' data is redundant with material..? */ +); + + +function sounds(/*array $ids = [] */) +{ + /* + okay, here's the thing. WMOAreaTable.dbc references WMO-files to get its position in the world (AreTable) and has sparse information on the related AreaTables themself. + Though it has sets for ZoneAmbience, ZoneMusic and ZoneIntroMusic, these can't be linked for this very reason and are omitted for now. + content: e.g. Tavern Music + */ + + // WMOAreaTable.dbc/Id => AreaTable.dbc/Id + $worldStateZoneSoundFix = array( + 18153 => 2119, + 18154 => 2119, + 47321 => 4273, // The Spark of Imagination + 43600 => 4273, // The Celestial Planetarium + 47478 => 4273 // The Prison of Yogg-Saron + ); + + + /***********/ + /* M A I N */ + /***********/ + + CLISetup::log(' - sounds main data'); + + // file extraction and conversion in build step. data here is purely structural + // reality check ... thats probably gigabytes worth of sound.. only growing in size with every locale added on top (RedRocketSite didn't do it. Should i then?) + + // .wav => audio/ogg; codecs="vorbis" + // .mp3 => audio/mpeg + + $query = ' + SELECT Id AS `id`, `type` AS `cat`, `name`, 0 AS cuFlags, + `file1` AS soundFile1, `file2` AS soundFile2, `file3` AS soundFile3, `file4` AS soundFile4, `file5` AS soundFile5, + `file6` AS soundFile6, `file7` AS soundFile7, `file8` AS soundFile8, `file9` AS soundFile9, `file10` AS soundFile10, + path, flags + FROM dbc_soundentries + WHERE id > ?d LIMIT ?d + '; + + DB::Aowow()->query('TRUNCATE ?_sounds'); + DB::Aowow()->query('TRUNCATE ?_sounds_files'); + + $lastMax = 0; + $soundFileIdx = 0; + $soundIndex = []; + while ($sounds = DB::Aowow()->select($query, $lastMax, SqlGen::$stepSize)) + { + $newMax = max(array_column($sounds, 'id')); + + CLISetup::log(' * sets '.($lastMax + 1).' - '.$newMax); + + $lastMax = $newMax; + + $groupSets = []; + foreach ($sounds as $s) + { + /* attention! + + one sound can be used in 20 or more locations but may appear as multiple files, + because of different cases, path being attached to file and other shenanigans + + build a usable path and create full index to compensate + 25.6k raw files => expect ~21k filtered files + */ + + $fileSets = []; + $hasDupes = false; + for ($i = 1; $i < 11; $i++) + { + $nicePath = CLISetup::nicePath($s['soundFile'.$i], $s['path']); + if ($s['soundFile'.$i] && array_key_exists($nicePath, $soundIndex)) + { + $s['soundFile'.$i] = $soundIndex[$nicePath]; + $hasDupes = true; + continue; + } + + // convert to something web friendly => ogg + if (stristr($s['soundFile'.$i], '.wav')) + { + $soundIndex[$nicePath] = ++$soundFileIdx; + + $fileSets[] = array( + $soundFileIdx, + strtolower($s['soundFile'.$i]), + strtolower($s['path']), + SOUND_TYPE_OGG + ); + $s['soundFile'.$i] = $soundFileIdx; + } + // mp3 .. keep as is + else if (stristr($s['soundFile'.$i], '.mp3')) + { + $soundIndex[$nicePath] = ++$soundFileIdx; + + $fileSets[] = array( + $soundFileIdx, + strtolower($s['soundFile'.$i]), + strtolower($s['path']), + SOUND_TYPE_MP3 + ); + $s['soundFile'.$i] = $soundFileIdx; + } + // i call bullshit + else if ($s['soundFile'.$i]) + { + CLISetup::log(' - sound group #'.$s['id'].' "'.$s['name'].'" has invalid sound file "'.$s['soundFile'.$i].'" on index '.$i.'! Skipping...', CLISetup::LOG_WARN); + $s['soundFile'.$i] = null; + } + // empty case + else + $s['soundFile'.$i] = null; + } + + if (!$fileSets && !$hasDupes) + { + CLISetup::log(' - sound group #'.$s['id'].' "'.$s['name'].'" contains no sound files! Skipping...', CLISetup::LOG_WARN); + continue; + } + else if ($fileSets) + DB::Aowow()->query('INSERT INTO ?_sounds_files VALUES (?a)', array_values($fileSets)); + + unset($s['path']); + + $groupSets[] = array_values($s); + } + + DB::Aowow()->query('REPLACE INTO ?_sounds VALUES (?a)', array_values($groupSets)); + } + + + /******************/ + /* VocalUI Sounds */ + /******************/ + + CLISetup::log(' - linking to race'); + + DB::Aowow()->query('TRUNCATE ?_races_sounds'); + DB::Aowow()->query('INSERT IGNORE INTO ?_races_sounds SELECT raceId, soundIdMale, 1 FROM dbc_vocaluisounds WHERE soundIdMale <> soundIdFemale AND soundIdMale > 0'); + DB::Aowow()->query('INSERT IGNORE INTO ?_races_sounds SELECT raceId, soundIdFemale, 2 FROM dbc_vocaluisounds WHERE soundIdMale <> soundIdFemale AND soundIdFemale > 0'); + + // ps: im too dumb to union this + + + /***************/ + /* Emote Sound */ + /***************/ + + CLISetup::log(' - linking to emotes'); + + DB::Aowow()->query('TRUNCATE ?_emotes_sounds'); + DB::Aowow()->query('INSERT IGNORE INTO ?_emotes_sounds SELECT emotesTextId, raceId, gender + 1, soundId FROM dbc_emotestextsound'); + + + /*******************/ + /* Creature Sounds */ + /*******************/ + + CLISetup::log(' - linking to creatures'); + + // currently ommitting: + // * footsteps (matrix of: creature + terrain + humidity) + // * fidget2 through 5 + // * customattack2 through 3 + // in case of conflicting data CreatureDisplayInfo overrides CreatureModelData (seems to be more specialized (Thral > MaleOrc / Maiden > FemaleTitan)) + + DB::Aowow()->query('TRUNCATE ?_creature_sounds'); + DB::Aowow()->query(' + INSERT INTO + ?_creature_sounds (`id`, `greeting`, `farewell`, `angry`, `exertion`, `exertioncritical`, `injury`, `injurycritical`, `death`, `stun`, `stand`, `aggro`, `wingflap`, `wingglide`, `alert`, `fidget`, `customattack`, `loop`, `jumpstart`, `jumpend`, `petattack`, `petorder`, `petdismiss`, `birth`, `spellcast`, `submerge`, `submerged`) + SELECT + cdi.Id, + IFNULL(ns.greetSoundId, 0), + IFNULL(ns.byeSoundId, 0), + IFNULL(ns.angrySoundId, 0), + IF(csdA.exertion, csdA.exertion, IFNULL(csdB.exertion, 0)), + IF(csdA.exertionCritical, csdA.exertionCritical, IFNULL(csdB.exertionCritical, 0)), + IF(csdA.injury, csdA.injury, IFNULL(csdB.injury, 0)), + IF(csdA.injuryCritical, csdA.injuryCritical, IFNULL(csdB.injuryCritical, 0)), + IF(csdA.death, csdA.death, IFNULL(csdB.death, 0)), + IF(csdA.stun, csdA.stun, IFNULL(csdB.stun, 0)), + IF(csdA.stand, csdA.stand, IFNULL(csdB.stand, 0)), + IF(csdA.aggro, csdA.aggro, IFNULL(csdB.aggro, 0)), + IF(csdA.wingFlap, csdA.wingFlap, IFNULL(csdB.wingFlap, 0)), + IF(csdA.wingGlide, csdA.wingGlide, IFNULL(csdB.wingGlide, 0)), + IF(csdA.alert, csdA.alert, IFNULL(csdB.alert, 0)), + IF(csdA.fidget, csdA.fidget, IFNULL(csdB.fidget, 0)), + IF(csdA.customAttack, csdA.customAttack, IFNULL(csdB.customAttack, 0)), + IF(csdA.loop, csdA.loop, IFNULL(csdB.loop, 0)), + IF(csdA.jumpStart, csdA.jumpStart, IFNULL(csdB.jumpStart, 0)), + IF(csdA.jumpEnd, csdA.jumpEnd, IFNULL(csdB.jumpEnd, 0)), + IF(csdA.petAttack, csdA.petAttack, IFNULL(csdB.petAttack, 0)), + IF(csdA.petOrder, csdA.petOrder, IFNULL(csdB.petOrder, 0)), + IF(csdA.petDismiss, csdA.petDismiss, IFNULL(csdB.petDismiss, 0)), + IF(csdA.birth, csdA.birth, IFNULL(csdB.birth, 0)), + IF(csdA.spellcast, csdA.spellcast, IFNULL(csdB.spellcast, 0)), + IF(csdA.submerge, csdA.submerge, IFNULL(csdB.submerge, 0)), + IF(csdA.submerged, csdA.submerged, IFNULL(csdB.submerged, 0)) + FROM + dbc_creaturedisplayinfo cdi + LEFT JOIN + dbc_creaturemodeldata cmd ON cmd.Id = cdi.modelId + LEFT JOIN + dbc_creaturesounddata csdA ON cdi.creatureSoundId = csdA.Id + LEFT JOIN + dbc_creaturesounddata csdB ON cmd.creatureSoundId = csdB.Id + LEFT JOIN + dbc_npcsounds ns ON cdi.npcSoundId = ns.Id + '); + + + /****************/ + /* Spell Sounds */ + /****************/ + + CLISetup::log(' - linking to spells'); + + // issues: (probably because of 335-data) + // * animate is probably wrong + // * missile and impactarea not in js + // * ready, castertargeting, casterstate and targetstate not in dbc + + DB::Aowow()->query('TRUNCATE ?_spell_sounds'); + DB::Aowow()->query(' + INSERT INTO + ?_spell_sounds (`Id`, `precast`, `cast`, `impact`, `state`, `statedone`, `channel`, `missile`, `animation`, `casterimpact`, `targetimpact`, `missiletargeting`, `instantarea`, `impactarea`, `persistentarea`) + SELECT + sv.Id, + IFNULL(svk1.soundId, 0), + IFNULL(svk2.soundId, 0), + IFNULL(svk3.soundId, 0), + IFNULL(svk4.soundId, 0), + IFNULL(svk5.soundId, 0), + IFNULL(svk6.soundId, 0), + missileSoundId, + animationSoundId, + IFNULL(svk7.soundId, 0), + IFNULL(svk8.soundId, 0), + IFNULL(svk9.soundId, 0), + IFNULL(svk10.soundId, 0), + IFNULL(svk11.soundId, 0), + IFNULL(svk12.soundId, 0) + FROM + dbc_spellvisual sv + LEFT JOIN + dbc_spellvisualkit svk1 ON svk1.Id = sv.precastKitId + LEFT JOIN + dbc_spellvisualkit svk2 ON svk2.Id = sv.castKitId + LEFT JOIN + dbc_spellvisualkit svk3 ON svk3.Id = sv.impactKitId + LEFT JOIN + dbc_spellvisualkit svk4 ON svk4.Id = sv.stateKitId + LEFT JOIN + dbc_spellvisualkit svk5 ON svk5.Id = sv.statedoneKitId + LEFT JOIN + dbc_spellvisualkit svk6 ON svk6.Id = sv.channelKitId + LEFT JOIN + dbc_spellvisualkit svk7 ON svk7.Id = sv.casterImpactKitId + LEFT JOIN + dbc_spellvisualkit svk8 ON svk8.Id = sv.targetImpactKitId + LEFT JOIN + dbc_spellvisualkit svk9 ON svk9.Id = sv.missileTargetingKitId + LEFT JOIN + dbc_spellvisualkit svk10 ON svk10.Id = sv.instantAreaKitId + LEFT JOIN + dbc_spellvisualkit svk11 ON svk11.Id = sv.impactAreaKitId + LEFT JOIN + dbc_spellvisualkit svk12 ON svk12.Id = sv.persistentAreaKitId + '); + + + /***************/ + /* Zone Sounds */ + /***************/ + + CLISetup::log(' - linking to zones'); + + // omiting data from WMOAreaTable, as its at the moment impossible to link to actual zones + + DB::Aowow()->query('TRUNCATE ?_zones_sounds'); + DB::Aowow()->query(' + INSERT INTO + ?_zones_sounds (id, ambienceDay, ambienceNight, musicDay, musicNight, intro, worldStateId, worldStateValue) + SELECT + a.id, + IFNULL(sa1.soundIdDay, 0), + IFNULL(sa1.soundIdNight, 0), + IFNULL(zm1.soundIdDay, 0), + IFNULL(zm1.soundIdNight, 0), + IFNULL(zimt1.soundId, 0), + 0, + 0 + FROM + dbc_areatable a + LEFT JOIN + dbc_soundambience sa1 ON sa1.id = a.soundAmbience + LEFT JOIN + dbc_zonemusic zm1 ON zm1.id = a.zoneMusic + LEFT JOIN + dbc_zoneintromusictable zimt1 ON zimt1.id = a.zoneIntroMusic + WHERE + a.soundAmbience > 0 OR a.zoneMusic > 0 OR a.zoneIntroMusic + UNION + SELECT + IF(wszs.areaId, wszs.areaId, wszs.wmoAreaId), + IFNULL(sa2.soundIdDay, 0), + IFNULL(sa2.soundIdNight, 0), + IFNULL(zm2.soundIdDay, 0), + IFNULL(zm2.soundIdNight, 0), + IFNULL(zimt2.soundId, 0), + wszs.stateId, + wszs.value + FROM + dbc_worldstatezonesounds wszs + LEFT JOIN + dbc_soundambience sa2 ON sa2.id = wszs.soundAmbienceId + LEFT JOIN + dbc_zonemusic zm2 ON zm2.id = wszs.zoneMusicId + LEFT JOIN + dbc_zoneintromusictable zimt2 ON zimt2.id = wszs.zoneIntroMusicId + WHERE + wszs.zoneMusicId > 0 AND (wszs.areaId OR wszs.wmoAreaId IN (?a)) + ', array_keys($worldStateZoneSoundFix)); + + // apply post-fix + foreach ($worldStateZoneSoundFix as $old => $new) + DB::Aowow()->query('UPDATE ?_zones_sounds SET id = ?d WHERE id = ?d', $new, $old); + + + /***************/ + /* Item Sounds */ + /***************/ + + CLISetup::log(' - linking to items'); + + DB::Aowow()->query(' + UPDATE + ?_items i + LEFT JOIN + dbc_itemdisplayinfo idi ON + idi.id = i.displayId + LEFT JOIN + dbc_itemgroupsounds igs ON + igs.id = idi.groupSoundId + LEFT JOIN + dbc_material m ON + m.id = i.material + SET + i.spellVisualId = IFNULL(idi.spellVisualId, 0), + i.pickUpSoundId = IFNULL(igs.pickUpSoundId, 0), + i.dropDownSoundId = IFNULL(igs.dropDownSoundId, 0), + i.sheatheSoundId = IFNULL(m.sheatheSoundId, 0), + i.unsheatheSoundId = IFNULL(m.unsheatheSoundId, 0) + '); + + DB::Aowow()->query('TRUNCATE ?_items_sounds'); + + $fields = ['hit', 'crit']; + foreach ($fields as $f) + { + for ($i = 1; $i <= 10; $i++) + { + DB::Aowow()->query(' + INSERT INTO + ?_items_sounds + SELECT + ?#, + (1 << wis.subClass) + FROM + dbc_weaponimpactsounds wis + WHERE + ?# > 0 + ON DUPLICATE KEY UPDATE + subClassMask = subClassMask | (1 << wis.subClass) + ', $f.$i, $f.$i); + } + } + + + DB::Aowow()->query(' + INSERT INTO + ?_items_sounds + SELECT + wss.soundId, + (1 << isc.subClass) + FROM + dbc_itemsubclass isc + JOIN + dbc_weaponswingsounds2 wss ON + wss.weaponSize = isc.weaponSize + WHERE + isc.class = 2 + ON DUPLICATE KEY UPDATE + subClassMask = subClassMask | (1 << isc.subClass) + '); + + return true; +} + +?> diff --git a/setup/tools/sqlgen/spawns.func.php b/setup/tools/sqlgen/spawns.func.php index 68b17dcd..9da4dd0f 100644 --- a/setup/tools/sqlgen/spawns.func.php +++ b/setup/tools/sqlgen/spawns.func.php @@ -23,7 +23,7 @@ if (!CLI) $customData = array( ); -$reqDBC = ['worldmaparea', 'map', 'worldmaptransforms', 'dungeonmap', 'taxipathnode']; +$reqDBC = ['worldmaparea', 'map', 'dungeonmap', 'taxipathnode', 'soundemitters']; function spawns() // and waypoints { @@ -98,15 +98,19 @@ function spawns() // and waypoints '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` ' . + $query[3] = ['SELECT Id AS "guid", 19 AS "type", soundId AS typeId, 0 AS respawn, 0 AS phaseMask, 0 AS areaId, mapId AS "map", 0 AS pathId, posX, posY ' . + 'FROM dbc_soundemitters', + ' - assembling '.CLISetup::bold('sound emitter').' spawns']; + + $query[4] = ['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` ' . + $query[5] = ['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` ' . + $query[6] = ['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 WHERE ca.path_id <> 0', ' - assembling waypoints from '.CLISetup::bold('waypoint_data')]; @@ -118,7 +122,7 @@ function spawns() // and waypoints 'FROM dbc_worldmaparea wma ' . 'LEFT JOIN dbc_dungeonmap dm ON dm.mapId = IF(?d AND (wma.mapId NOT IN (0, 1, 530, 571) OR wma.areaId = 4395), 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) ' . + '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'; @@ -149,7 +153,13 @@ function spawns() // and waypoints $n = 0; $sum = 0; - foreach (DB::World()->select($q[0]) as $spawn) + + if ($idx == 3) + $queryResult = DB::Aowow()->select($q[0]); + else + $queryResult = DB::World()->select($q[0]); + + foreach ($queryResult as $spawn) { if (!$n) CLISetup::log(' * sets '.($sum + 1).' - '.($sum += SqlGen::$stepSize)); @@ -167,20 +177,20 @@ function spawns() // and waypoints $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); + $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); + $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); + CLISetup::log('GUID '.$spawn['guid'].($idx < 4 ? '' : ' 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) + if ($idx < 4) { $set = array( 'guid' => $spawn['guid'], diff --git a/setup/tools/sqlgen/spell.func.php b/setup/tools/sqlgen/spell.func.php index f3da6335..f213fc7d 100644 --- a/setup/tools/sqlgen/spell.func.php +++ b/setup/tools/sqlgen/spell.func.php @@ -85,6 +85,7 @@ function spell() EffectSpellClassMaskA1, EffectSpellClassMaskA2, EffectSpellClassMaskA3, EffectSpellClassMaskB1, EffectSpellClassMaskB2, EffectSpellClassMaskB3, EffectSpellClassMaskC1, EffectSpellClassMaskC2, EffectSpellClassMaskC3, + 0 AS spellVisualId1, 0 AS spellVisualId2, 0 AS iconId, 0 AS iconIdActive, CONCAT("Serverside - ",Comment) AS name_loc0,CONCAT("Serverside - ",Comment) AS name_loc2,CONCAT("Serverside - ",Comment) AS name_loc3,CONCAT("Serverside - ",Comment) AS name_loc6,CONCAT("Serverside - ",Comment) AS name_loc8, "" AS rank_loc0, "" AS rank_loc2, "" AS rank_loc3, "" AS rank_loc6, "" AS rank_loc8, @@ -176,6 +177,7 @@ function spell() effect1BonusMultiplier, effect2BonusMultiplier, effect3BonusMultiplier, iconId, 0 AS iconIdAlt, 0 AS rankId, + spellVisualId1, 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, diff --git a/setup/updates/1487858459_01.sql b/setup/updates/1487858459_01.sql index a4f4e559..11b398b9 100644 --- a/setup/updates/1487858459_01.sql +++ b/setup/updates/1487858459_01.sql @@ -1,107 +1,107 @@ --- TYPE_NPC:1 -UPDATE aowow_creature a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 1 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_OBJECT:2 -UPDATE aowow_objects a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 2 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_ITEM:3 -UPDATE aowow_items a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 3 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_ITEMSET:4 -UPDATE aowow_itemset a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 4 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_QUEST:5 -UPDATE aowow_quests a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 5 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_SPELL:6 -UPDATE aowow_spell a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 6 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_ZONE:7 -UPDATE aowow_zones a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 7 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_FACTION:8 -UPDATE aowow_factions a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 8 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_PET:9 -UPDATE aowow_pet a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 9 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_ACHIEVEMENT:10 -UPDATE aowow_achievement a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 10 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_TITLE:11 -UPDATE aowow_titles a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 11 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_WORLDEVENT:12 -UPDATE aowow_events a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 12 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_CLASS:13 -UPDATE aowow_classes a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 13 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_RACE:14 -UPDATE aowow_races a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 14 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_SKILL:15 -UPDATE aowow_skillline a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 15 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_CURRENCY:17 -UPDATE aowow_currencies a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 17 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_EMOTE:501 -UPDATE aowow_emotes a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 501 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; - --- TYPE_ENCHANTMENT:502 -UPDATE aowow_itemenchantment a -JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 502 GROUP BY typeId) b ON a.id = b.typeId -SET a.cuFlags = a.cuFlags | 0x02000000 -WHERE b.ccFlags & 0x8; +-- TYPE_NPC:1 +UPDATE aowow_creature a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 1 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_OBJECT:2 +UPDATE aowow_objects a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 2 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_ITEM:3 +UPDATE aowow_items a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 3 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_ITEMSET:4 +UPDATE aowow_itemset a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 4 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_QUEST:5 +UPDATE aowow_quests a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 5 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_SPELL:6 +UPDATE aowow_spell a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 6 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_ZONE:7 +UPDATE aowow_zones a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 7 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_FACTION:8 +UPDATE aowow_factions a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 8 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_PET:9 +UPDATE aowow_pet a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 9 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_ACHIEVEMENT:10 +UPDATE aowow_achievement a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 10 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_TITLE:11 +UPDATE aowow_titles a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 11 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_WORLDEVENT:12 +UPDATE aowow_events a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 12 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_CLASS:13 +UPDATE aowow_classes a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 13 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_RACE:14 +UPDATE aowow_races a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 14 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_SKILL:15 +UPDATE aowow_skillline a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 15 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_CURRENCY:17 +UPDATE aowow_currencies a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 17 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_EMOTE:501 +UPDATE aowow_emotes a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 501 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; + +-- TYPE_ENCHANTMENT:502 +UPDATE aowow_itemenchantment a +JOIN (SELECT typeId, BIT_OR(`status`) AS `ccFlags` FROM aowow_screenshots WHERE `type` = 502 GROUP BY typeId) b ON a.id = b.typeId +SET a.cuFlags = a.cuFlags | 0x02000000 +WHERE b.ccFlags & 0x8; diff --git a/setup/updates/1488745158_01.sql b/setup/updates/1488745158_01.sql new file mode 100644 index 00000000..7e45757e --- /dev/null +++ b/setup/updates/1488745158_01.sql @@ -0,0 +1,23 @@ +-- drop deprecatede dbc-tables +DROP TABLE IF EXISTS `dbc_areatable`; +DROP TABLE IF EXISTS `dbc_creaturedisplayinfo`; +DROP TABLE IF EXISTS `dbc_creaturemodeldata`; +DROP TABLE IF EXISTS `dbc_creaturesounddata`; +DROP TABLE IF EXISTS `dbc_emotestextsound`; +DROP TABLE IF EXISTS `dbc_itemdisplayinfo`; +DROP TABLE IF EXISTS `dbc_itemgroupsounds`; +DROP TABLE IF EXISTS `dbc_itemsubclass`; +DROP TABLE IF EXISTS `dbc_material`; +DROP TABLE IF EXISTS `dbc_npcsounds`; +DROP TABLE IF EXISTS `dbc_soundambience`; +DROP TABLE IF EXISTS `dbc_soundemitters`; +DROP TABLE IF EXISTS `dbc_soundentries`; +DROP TABLE IF EXISTS `dbc_spell`; +DROP TABLE IF EXISTS `dbc_spellvisual`; +DROP TABLE IF EXISTS `dbc_spellvisualkit`; +DROP TABLE IF EXISTS `dbc_vocaluisounds`; +DROP TABLE IF EXISTS `dbc_weaponimpactsounds`; +DROP TABLE IF EXISTS `dbc_weaponswingsounds2`; +DROP TABLE IF EXISTS `dbc_worldstatezonesound`; +DROP TABLE IF EXISTS `dbc_zoneintromusictable`; +DROP TABLE IF EXISTS `dbc_zonemusic`; diff --git a/setup/updates/1488745158_02.sql b/setup/updates/1488745158_02.sql new file mode 100644 index 00000000..9fbb753f --- /dev/null +++ b/setup/updates/1488745158_02.sql @@ -0,0 +1,164 @@ +-- alterations + +ALTER TABLE `aowow_spell` + ADD COLUMN `spellVisualId` smallint(5) unsigned NOT NULL AFTER `rankNo`; + +ALTER TABLE `aowow_items` + ADD COLUMN `spellVisualId` smallint(5) unsigned NOT NULL DEFAULT '0' AFTER `displayId`, + ADD COLUMN `material` tinyint(3) NOT NULL DEFAULT '0' AFTER `lockId`, + ADD COLUMN `soundOverrideSubclass` tinyint(3) NOT NULL AFTER `subClassBak`, + ADD COLUMN `pickUpSoundId` smallint(5) unsigned NOT NULL DEFAULT '0' AFTER `maxMoneyLoot`, + ADD COLUMN `dropDownSoundId` smallint(5) unsigned NOT NULL DEFAULT '0' AFTER `pickUpSoundId`, + ADD COLUMN `sheatheSoundId` smallint(5) unsigned NOT NULL DEFAULT '0' AFTER `dropDownSoundId`, + ADD COLUMN `unsheatheSoundId` smallint(5) unsigned NOT NULL DEFAULT '0' AFTER `sheatheSoundId`; + + +-- additions + +REPLACE INTO `aowow_articles` (`type`, `typeId`, `locale`, `article`, `quickInfo`) + VALUES (19, -1000, 0, 'Here you can set up a playlist of sounds and music. \n\nJust click the "Add" button near an audio control, then return to this page to listen to the list you\'ve created.', NULL); + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + +DROP TABLE IF EXISTS `aowow_items_sounds`; +CREATE TABLE `aowow_items_sounds` ( + `soundId` smallint(5) unsigned NOT NULL, + `subClassMask` mediumint(8) unsigned NOT NULL, + PRIMARY KEY (`soundId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='actually .. its only weapon related sounds in here'; + +DROP TABLE IF EXISTS `aowow_zones_sounds`; +CREATE TABLE `aowow_zones_sounds` ( + `id` smallint(5) unsigned NOT NULL, + `ambienceDay` smallint(5) unsigned NOT NULL, + `ambienceNight` smallint(5) unsigned NOT NULL, + `musicDay` smallint(5) unsigned NOT NULL, + `musicNight` smallint(5) unsigned NOT NULL, + `intro` smallint(5) unsigned NOT NULL, + `worldStateId` smallint(5) unsigned NOT NULL, + `worldStateValue` smallint(6) NOT NULL, + INDEX `id` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `aowow_creature_sounds`; +CREATE TABLE IF NOT EXISTS `aowow_creature_sounds` ( + `id` smallint(5) unsigned NOT NULL COMMENT 'CreatureDisplayInfo.dbc/id', + `greeting` smallint(5) unsigned NOT NULL, + `farewell` smallint(5) unsigned NOT NULL, + `angry` smallint(5) unsigned NOT NULL, + `exertion` smallint(5) unsigned NOT NULL, + `exertioncritical` smallint(5) unsigned NOT NULL, + `injury` smallint(5) unsigned NOT NULL, + `injurycritical` smallint(5) unsigned NOT NULL, + `death` smallint(5) unsigned NOT NULL, + `stun` smallint(5) unsigned NOT NULL, + `stand` smallint(5) unsigned NOT NULL, + `footstep` smallint(5) unsigned NOT NULL, + `aggro` smallint(5) unsigned NOT NULL, + `wingflap` smallint(5) unsigned NOT NULL, + `wingglide` smallint(5) unsigned NOT NULL, + `alert` smallint(5) unsigned NOT NULL, + `fidget` smallint(5) unsigned NOT NULL, + `customattack` smallint(5) unsigned NOT NULL, + `loop` smallint(5) unsigned NOT NULL, + `jumpstart` smallint(5) unsigned NOT NULL, + `jumpend` smallint(5) unsigned NOT NULL, + `petattack` smallint(5) unsigned NOT NULL, + `petorder` smallint(5) unsigned NOT NULL, + `petdismiss` smallint(5) unsigned NOT NULL, + `birth` smallint(5) unsigned NOT NULL, + `spellcast` smallint(5) unsigned NOT NULL, + `submerge` smallint(5) unsigned NOT NULL, + `submerged` smallint(5) unsigned NOT NULL, + `transform` smallint(5) unsigned NOT NULL, + `transformanimated` smallint(5) unsigned NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='!ATTENTION!\r\nthe primary key of this table is NOT a creatureId, but displayId\r\n\r\ncolumn names from LANG.sound_activities'; + +DROP TABLE IF EXISTS `aowow_emotes_sounds`; +CREATE TABLE IF NOT EXISTS `aowow_emotes_sounds` ( + `emoteId` smallint(5) unsigned NOT NULL, + `raceId` tinyint(3) unsigned NOT NULL, + `gender` tinyint(1) unsigned NOT NULL, + `soundId` smallint(5) unsigned NOT NULL, + UNIQUE KEY `emoteId_raceId_gender_soundId` (`emoteId`,`raceId`,`gender`,`soundId`), + KEY `emoteId` (`emoteId`), + KEY `raceId` (`raceId`), + KEY `soundId` (`soundId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `aowow_races_sounds`; +CREATE TABLE IF NOT EXISTS `aowow_races_sounds` ( + `raceId` tinyint(3) unsigned NOT NULL, + `soundId` smallint(5) unsigned NOT NULL, + `gender` tinyint(1) unsigned NOT NULL, + UNIQUE KEY `race_soundId_gender` (`raceId`,`soundId`,`gender`), + KEY `race` (`raceId`), + KEY `soundId` (`soundId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `aowow_sounds`; +CREATE TABLE IF NOT EXISTS `aowow_sounds` ( + `id` smallint(5) unsigned NOT NULL, + `cat` tinyint(3) unsigned NOT NULL, + `name` varchar(100) NOT NULL, + `cuFlags` int(10) unsigned NOT NULL, + `soundFile1` smallint(5) unsigned DEFAULT NULL, + `soundFile2` smallint(5) unsigned DEFAULT NULL, + `soundFile3` smallint(5) unsigned DEFAULT NULL, + `soundFile4` smallint(5) unsigned DEFAULT NULL, + `soundFile5` smallint(5) unsigned DEFAULT NULL, + `soundFile6` smallint(5) unsigned DEFAULT NULL, + `soundFile7` smallint(5) unsigned DEFAULT NULL, + `soundFile8` smallint(5) unsigned DEFAULT NULL, + `soundFile9` smallint(5) unsigned DEFAULT NULL, + `soundFile10` smallint(5) unsigned DEFAULT NULL, + `flags` mediumint(8) unsigned NOT NULL, + PRIMARY KEY (`id`), + KEY `cat` (`cat`), + KEY `name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `aowow_sounds_files`; +CREATE TABLE IF NOT EXISTS `aowow_sounds_files` ( + `id` smallint(6) NOT NULL COMMENT '<0 not found in client files', + `file` varchar(75) NOT NULL, + `path` varchar(75) NOT NULL COMMENT 'in client', + `type` tinyint(1) unsigned NOT NULL COMMENT '1: ogg; 2: mp3', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `aowow_spell_sounds`; +CREATE TABLE IF NOT EXISTS `aowow_spell_sounds` ( + `id` smallint(5) unsigned NOT NULL COMMENT 'SpellVisual.dbc/id', + `animation` smallint(5) unsigned NOT NULL, + `ready` smallint(5) unsigned NOT NULL, + `precast` smallint(5) unsigned NOT NULL, + `cast` smallint(5) unsigned NOT NULL, + `impact` smallint(5) unsigned NOT NULL, + `state` smallint(5) unsigned NOT NULL, + `statedone` smallint(5) unsigned NOT NULL, + `channel` smallint(5) unsigned NOT NULL, + `casterimpact` smallint(5) unsigned NOT NULL, + `targetimpact` smallint(5) unsigned NOT NULL, + `castertargeting` smallint(5) unsigned NOT NULL, + `missiletargeting` smallint(5) unsigned NOT NULL, + `instantarea` smallint(5) unsigned NOT NULL, + `persistentarea` smallint(5) unsigned NOT NULL, + `casterstate` smallint(5) unsigned NOT NULL, + `targetstate` smallint(5) unsigned NOT NULL, + `missile` smallint(5) unsigned NOT NULL COMMENT 'not predicted by js', + `impactarea` smallint(5) unsigned NOT NULL COMMENT 'not predicted by js', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='!ATTENTION!\r\nthe primary key of this table is NOT a spellId, but spellVisualId\r\n\r\ncolumn names from LANG.sound_activities'; + +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; + +UPDATE aowow_dbversion SET `build` = CONCAT(IFNULL(`build`, ''), ' sounds'), `sql` = CONCAT(IFNULL(`sql`, ''), ' spell creature sounds spawns'); diff --git a/static/css/aowow.css b/static/css/aowow.css index f9429e75..3af95628 100644 --- a/static/css/aowow.css +++ b/static/css/aowow.css @@ -114,7 +114,7 @@ h5 a.icontiny span { text-decoration:none !important; } .entryc .quote, .comment-body .quote, .text .quote, .text blockquote, -.quote-blizz, .quote-wh, .minibox { +.quote-blizz, .quote-wh { background:#1b1b1b; padding: 15px; margin:15px 0; @@ -150,6 +150,14 @@ h5 a.icontiny span { text-decoration:none !important; } overflow:auto; } +div.audiomarkup +{ + text-align:center; + display:inline-block; + font-size:13px; + line-height:normal +} + .quote-blizz,.quote-wh { clear:both; @@ -1826,6 +1834,10 @@ td.checked .listview-cb:hover { background-color: #343434; } +.listview-cleartext { + font-family:Verdana, "Open Sans", Arial, "Helvetica Neue", Helvetica, sans-serif; +} + .live-search { position: absolute; z-index: 100000001; @@ -3975,6 +3987,22 @@ div.captcha-center { font-size: 11px; } +.audio-controls td { + text-align:center +} + +.audio-controls-title { + padding:0 15px 5px; + word-break:break-word; + word-wrap:break-word; + overflow-wrap:break-word +} + +.audio-controls-pagination-track { + display:inline-block; + min-width:50px +} + /************************************************/ /* aowow: deprecated stuff that might be of use */ diff --git a/static/js/Markup.js b/static/js/Markup.js index 889172be..7d94054b 100644 --- a/static/js/Markup.js +++ b/static/js/Markup.js @@ -2249,6 +2249,138 @@ var Markup = { return str.replace(/([\s\S]*?)<\/small>/gi, '[small]$1[/small]'); } }, + sound: { + empty: true, + attr: + { + unnamed: { req: false, valid: /^[0-9]+$/ }, + src: { req: false, valid: /\S+/ }, + title: { req: false, valid: /\S+/ }, + type: { req: false, valid: /\S+/ }, + src2: { req: false, valid: /\S+/ }, + type2: { req: false, valid: /\S+/ }, + domain: { req: false, valid: /^(beta|mop|ptr|www|de|es|fr|ru|pt)$/ } + }, + validate: function (attr) + { + if(attr.unnamed) + return true; + + if(!attr.src) + return false; + + return true; + }, + toHtml: function (attr) + { + var + type, + src, + title, + href, + src2, + type2; + + var domainInfo = Markup._getDatabaseDomainInfo(attr); + var url = domainInfo[0]; + if (attr.unnamed) + { + if (!(attr.unnamed in g_sounds)) + return ''; + + if (!g_sounds[attr.unnamed].hasOwnProperty("files")) + return ''; + + if (g_sounds[attr.unnamed].files.length == 0) + return ''; + + if (!g_sounds[attr.unnamed].files[0].hasOwnProperty('type')) + return ''; + + type = g_sounds[attr.unnamed].files[0].type; + src = g_sounds[attr.unnamed].files[0].url; + title = g_sounds[attr.unnamed].name ? g_sounds[attr.unnamed].name: g_sounds[attr.unnamed].files[0].title; + href = url + '?sound=' + attr.unnamed; + } + else + { + if (Markup.allow < MARKUP_CLASS_STAFF) + return ''; + + src = attr.src; + title = attr.title ? attr.title: '(Unknown)'; + if (attr.hasOwnProperty('type')) + type = attr.type; + else + { + switch (attr.src.toLowerCase().substr(-4)) + { + case '.mp3': + type = 'audio/mpeg'; + break; + case '.ogg': + type = 'audio/ogg; codecs="vorbis"'; + break; + } + } + + if (attr.src2) + { + src2 = attr.src2; + if (attr.hasOwnProperty('type2')) + type2 = attr.type2; + else + { + switch (attr.src2.toLowerCase().substr(-4)) + { + case '.mp3': + type2 = 'audio/mpeg'; + break; + case '.ogg': + type2 = 'audio/ogg; codecs="vorbis"'; + break; + } + } + } + } + + var str = '