diff --git a/chantiers/butin-journal/build_journal_mapping.py b/chantiers/butin-journal/build_journal_mapping.py new file mode 100644 index 0000000..736fc94 --- /dev/null +++ b/chantiers/butin-journal/build_journal_mapping.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +"""Genere creature_template_journal pour les boss WoD/Legion sans butin. + Source officielle : JournalInstance -> JournalEncounter -> JournalEncounterCreature.""" +import sys, subprocess, collections +sys.path.insert(0, '/home/ubuntu') +from db2read import DB2 +D = '/home/ubuntu/server/data/dbc/enUS/' + +CIBLES = [1175,1176,1182,1195,1209,1279,1358,1205,1228, + 1456,1458,1466,1477,1492,1501,1544,1571,1753,1520,1530,1676] + +# adds / decors qui partagent le modele du boss mais ne doivent rien lacher +EXCLUS = { + 76057, # Carrion Worm (add de Bonemaw) + 76874, 76945, 76884, # Dreadwing / Ironcrusher / Cruelfang (bestioles de Darmac) + 77337, # Aknor Steelbringer (add de Flamebender) + 76810, # Furnace Engineer + 76087, # Defense Construct (Skyreach) + 99801, 105383, 105322, 105304, # tentacules + 117123, # Tidescale Legionnaire + 122571, 125860, 122319, 125340, # adds du Siege du Triumvirat + 118460, # Engine of Souls (l'encontre se termine sur Soul Queen Dejahna) + 76018, 82556, # Drakonid Monstrosity (trash UBRS) + 106482, # Malfurion (PNJ de la rencontre Cenarius) + 120996, # doublon d'Atrigan + 77810, # doublon de Soulbinder Nyami + 84336, # doublon de Yalnu (pre-event) + 83893, 83892, # Protecteurs anciens : on garde Dulhu comme porteur + 76973, # Hans'gar : on garde Franzok + 78237, # Phemos : on garde Pol + 116689, # Atrigan : on garde Belac + 118523, 118374, # Soeurs de la Lune : on garde Priestess Lunaspyre + 102681, 102679, # Dragons du Cauchemar : on garde Lethon + 80808, 80805, # Contremaitres du Rail-de-fer : on garde Ahri'ok Dugru + 83613, # Koramar : on garde Skulloc + 76806, # Haut fourneau : on garde Foreman Feldspar ? non -> voir plus bas + 77231, 77477, # Vierges de fer : on garde Admiral Gar'an +} +# Haut fourneau : la rencontre se termine sur le Coeur de la Montagne +EXCLUS.discard(76806); EXCLUS.add(76809) + +ji = DB2(D+'JournalInstance.db2', "ssiiiihhbbi", [1]*11, 10, -1) +je = DB2(D+'JournalEncounter.db2', "ssfhhhhbbii", [1,1,2,1,1,1,1,1,1,1,1], -1, -1) +jec = DB2(D+'JournalEncounterCreature.db2',"ssiiihbi", [1]*8, 7, 5) +jei = DB2(D+'JournalEncounterItem.db2', "ihbbbi", [1]*6, 5, 1) + +instMap = {ji.getId(i): ji.getRaw(i,6,0,"h") for i in range(ji.recCount)} +encMap = {} +for i in range(je.recCount): + eid = je.getId(i); mid = instMap.get(je.getRaw(i,6,0,"h"), 0) + if mid in CIBLES: encMap[eid] = mid +nbItems = {eid: len(jei.parentMap.get(eid, [])) for eid in encMap} +disp = collections.defaultdict(set) +for eid, idxs in jec.parentMap.items(): + if eid in encMap: + for r in idxs: disp[eid].add(jec.getRaw(r,2,0,"i")) + +q = ("SELECT DISTINCT c.map, ct.entry, ct.name, ct.rank, ct.ScriptName, " + "ct.modelid1, ct.modelid2, ct.modelid3, ct.modelid4, " + "(SELECT COUNT(*) FROM creature c2 WHERE c2.id=ct.entry AND c2.map=c.map), " + "(SELECT COUNT(*) FROM creature_loot_template l WHERE l.entry=ct.lootid) " + "FROM creature c JOIN creature_template ct ON ct.entry=c.id " + "WHERE c.map IN (%s)" % ','.join(map(str, CIBLES))) +out = subprocess.run(['mysql','-N','-B','dc_world','-e',q], capture_output=True, text=True).stdout +byMapModel = collections.defaultdict(list) +for line in out.splitlines(): + f = line.split('\t') + mp, entry, name, rank, script = int(f[0]), int(f[1]), f[2], int(f[3]), f[4] + spawns, butin = int(f[9]), int(f[10]) + for m in (int(x) for x in f[5:9]): + if m: byMapModel[(mp, m)].append((entry, name, rank, script, spawns, butin)) + +rows, rejets = [], [] +for eid, mid in sorted(encMap.items(), key=lambda kv: kv[1]): + cands, seen = [], set() + for d in disp.get(eid, ()): + for c in byMapModel.get((mid, d), []): + if c[0] in seen: continue + seen.add(c[0]); cands.append(c) + # on ne garde que les boss credibles, sans butin, hors liste d'exclusion + keep = [c for c in cands + if c[0] not in EXCLUS and c[5] == 0 + and (c[3].startswith('boss_') or c[2] == 3 or (c[2] >= 1 and c[4] <= 3))] + if not keep: + rejets.append((mid, eid, nbItems.get(eid,0), [(c[0], c[1], c[5]) for c in cands])) + continue + keep.sort(key=lambda c: (0 if c[3].startswith('boss_') else 1, c[4])) + for c in keep: + rows.append((mid, eid, c[0], c[1], nbItems.get(eid,0))) + +print("-- creature_template_journal : %d lignes" % len(rows)) +for mid, eid, entry, name, n in rows: + print("(%d, %d), -- carte %d : %s (%d objets au journal)" % (entry, eid, mid, name, n)) +print() +print("-- rencontres sans candidat retenu : %d" % len(rejets)) +for mid, eid, n, cands in rejets: + print("-- carte %d rencontre %d (%d objets) -> %s" % (mid, eid, n, cands if cands else "aucun PNJ apparu")) diff --git a/chantiers/butin-journal/verify_journal_mapping.py b/chantiers/butin-journal/verify_journal_mapping.py new file mode 100644 index 0000000..e0b6c2e --- /dev/null +++ b/chantiers/butin-journal/verify_journal_mapping.py @@ -0,0 +1,25 @@ +import sys, subprocess, collections +sys.path.insert(0, '/home/ubuntu') +from db2read import DB2 +D = '/home/ubuntu/server/data/dbc/enUS/' +ji = DB2(D+'JournalInstance.db2', "ssiiiihhbbi", [1]*11, 10, -1) +je = DB2(D+'JournalEncounter.db2', "ssfhhhhbbii", [1,1,2,1,1,1,1,1,1,1,1], -1, -1) +jei = DB2(D+'JournalEncounterItem.db2', "ihbbbi", [1]*6, 5, 1) +instMap = {ji.getId(i): ji.getRaw(i,6,0,"h") for i in range(ji.recCount)} +enc = {} +for i in range(je.recCount): + enc[je.getId(i)] = (instMap.get(je.getRaw(i,6,0,"h"),0), je.getRaw(i,9,0,"i")) +rows = subprocess.run(['mysql','-N','-B','dc_world','-e', + "SELECT j.entry, j.JournalEncounterID, ct.name FROM creature_template_journal j " + "JOIN creature_template ct ON ct.entry=j.entry WHERE j.entry>70000"], + capture_output=True, text=True).stdout +print("entry\tenc\tcarte\tordre\tnbObjets\tnom") +bad=0 +for line in rows.splitlines(): + e, eid, name = line.split('\t'); eid=int(eid) + mid, oi = enc.get(eid, (0,0)) + n = len(jei.parentMap.get(eid, [])) + flag = "" if (mid and n) else " <<< PROBLEME" + if flag: bad+=1 + print("%s\t%d\t%d\t%d\t%d\t%s%s" % (e, eid, mid, oi, n, name, flag)) +print("problemes:", bad) diff --git a/sql/sylvania/butin_journal_wod_legion.sql b/sql/sylvania/butin_journal_wod_legion.sql new file mode 100644 index 0000000..bab4a28 --- /dev/null +++ b/sql/sylvania/butin_journal_wod_legion.sql @@ -0,0 +1,91 @@ +-- ===================================================================== +-- Butin des donjons et raids WoD / Legion +-- +-- Signalement Discord : « les instances HL ne loot pas de stuff ». +-- Cause : sur ce core, le butin d'equipement des boss modernes ne vient +-- PAS de `creature_loot_template` mais du Guide d'aventure de Blizzard : +-- `Unit::Kill` lit `creature_template_journal` (entree -> JournalEncounterID) +-- puis tire 2 objets au hasard dans JournalEncounterItem.db2, avec le +-- masque de difficulte et le contexte d'objet corrects. +-- Or `creature_template_journal` ne contenait que 45 lignes, toutes +-- Burning Crusade : aucun boss de Draenor ni de Legion n'y figurait, +-- et ces boss ont `lootid = 0` -> ils ne lachaient rigoureusement rien. +-- +-- Correspondances etablies a partir des DB2 officiels du client : +-- JournalInstance (MapID) -> JournalEncounter -> JournalEncounterCreature +-- (CreatureDisplayInfoID) -> creature_template.modelid1..4 +-- Une seule creature par rencontre (celle qui la conclut), et uniquement +-- celles qui n'ont aucune table de butin, pour ne rien doubler. +-- +-- Applique le 2026-09-10. +-- ===================================================================== + +DELETE FROM `creature_template_journal` WHERE `entry` IN ( + 74366,81297,80816,83612,87420,76865,76814,76906,76806,76974,76877,77692,77182,77557, + 75964,76141,76143,82682,84550,83846,76413,76021,77120,76585,91005,94960,95674,96759, + 102682,104154,106643,116407,115767,116691,118462,117269,118518,122316,122313,122056, + 124729,98965,79852,79912); + +INSERT INTO `creature_template_journal` (`entry`,`JournalEncounterID`) VALUES +-- Mines de Sangyre (1175) +(74366, 893), -- Forgemaster Gog'duh +-- Docks de fer (1195) +(81297, 1235), -- Dreadfang (Fleshrender Nok'gar) +(80816, 1236), -- Ahri'ok Dugru (Contremaitres du Rail-de-fer) +(79852, 1237), -- Oshir +(83612, 1238), -- Skulloc +-- Auchindoun (1182) : PAS de ligne pour Azzakel. Le vrai boss (75927, +-- niveau 97, script boss_azzakel, 49 lignes de butin) n'est PAS apparu ; +-- le PNJ pose dans le donjon est un doublon de niveau 1 sans script. +-- C'est un defaut d'apparition, pas de butin : a corriger separement. +-- Aire de Haut-perchoir (1209) +(75964, 965), -- Ranjit +(76141, 966), -- Araknath +(76143, 967), -- Rukhran +-- Floraison eternelle (1279) +(82682, 1208), -- Archmage Sol +(84550, 1209), -- Xeri'tac +(83846, 1210), -- Yalnu +-- Pic Rochenoire, sommet (1358) +(76413, 1226), -- Orebender Gor'ashan +(76021, 1227), -- Kyrak +(79912, 1228), -- Commander Tharbek +(76585, 1229), -- Ragewing the Untamed +(77120, 1234), -- Warlord Zaela +-- Fonderie des Rochenoire (1205) - raid entier sans butin +(77182, 1202), -- Oregorger +(76974, 1155), -- Franzok (Hans'gar et Franzok) +(76865, 1122), -- Beastlord Darmac +(76877, 1161), -- Gruul +(76814, 1123), -- Flamebender Ka'graz +(76906, 1147), -- Operator Thogar +(76806, 1154), -- Heart of the Mountain (Haut fourneau) +(77692, 1162), -- Kromog +(77557, 1203), -- Admiral Gar'an (Vierges de fer) +(87420, 959), -- Blackhand +-- Repaire de Neltharion (1458) +(91005, 1673), -- Naraxas +-- Salles des Valeureux (1477) +(94960, 1485), -- Hymdall +(95674, 1487), -- Fenryr +-- Gouffre des ames (1492) +(96759, 1663), -- Helya +-- Donjon de Tenebreterre (1501) +(98965, 1672), -- Kur'talos Ravencrest +-- Cauchemar d'emeraude (1520) +(102682, 1704), -- Lethon (Dragons du Cauchemar) +-- Nighthold (1530) +(104154, 1737), -- Gul'dan +(106643, 1743), -- Grande magistrix Elisande +-- Tombeau de Sargeras (1676) +(116407, 1856), -- Harjatan +(115767, 1861), -- Mistress Sassz'ine +(116691, 1867), -- Belac (Inquisition demoniaque) +(118518, 1903), -- Priestess Lunaspyre (Soeurs de la Lune) +(118462, 1896), -- Soul Queen Dejahna (Hote desole) +(117269, 1898), -- Kil'jaeden +-- Siege du Triumvirat (1753) - donjon entier sans butin +(122313, 1979), -- Zuraal the Ascended +(122316, 1980), -- Saprish +(122056, 1981), -- Viceroy Nezhar +(124729, 1982); -- L'ura diff --git a/sql/sylvania/butin_journal_wod_legion_ROLLBACK.sql b/sql/sylvania/butin_journal_wod_legion_ROLLBACK.sql new file mode 100644 index 0000000..6190b21 --- /dev/null +++ b/sql/sylvania/butin_journal_wod_legion_ROLLBACK.sql @@ -0,0 +1,6 @@ +-- Rollback de butin_journal_wod_legion.sql (2026-09-10) +DELETE FROM `creature_template_journal` WHERE `entry` IN ( + 74366,81297,80816,83612,87420,76865,76814,76906,76806,76974,76877,77692,77182,77557, + 75964,76141,76143,82682,84550,83846,76413,76021,77120,76585,91005,94960,95674,96759, + 102682,104154,106643,116407,115767,116691,118462,117269,118518,122316,122313,122056, + 124729,98965,79852,79912);