Butin WoD/Legion : brancher les boss sur le Guide d aventure

Signalement Discord : les instances haut niveau ne lachent aucun equipement.

Sur ce core, le butin d equipement des boss modernes ne vient pas de
creature_loot_template mais de Unit::Kill, qui lit creature_template_journal
(entree -> JournalEncounterID) puis tire 2 objets dans JournalEncounterItem.db2
avec le bon masque de difficulte et le bon contexte d objet. Cette table ne
contenait que 45 lignes, toutes Burning Crusade : aucun boss de Draenor ni de
Legion, et ces boss ont lootid = 0. Ils ne lachaient donc rigoureusement rien.

44 correspondances ajoutees, etablies depuis les DB2 officiels du client
(JournalInstance -> JournalEncounter -> JournalEncounterCreature ->
CreatureDisplayInfoID -> creature_template.modelid), une seule creature par
rencontre et uniquement celles sans table de butin, pour ne rien doubler.
Couvre entre autres la Fonderie des Rochenoire (10 boss), les Docks de fer,
Haut-perchoir, le Pic Rochenoire, la Floraison eternelle, le Siege du
Triumvirat (4 boss), le Tombeau de Sargeras (6), Gul dan et Elisande.

Les scripts de generation et de verification sont dans chantiers/butin-journal.
This commit is contained in:
BlaMacfly
2026-09-10 19:50:19 +02:00
parent afb770d096
commit fa6d14c4a0
4 changed files with 219 additions and 0 deletions
@@ -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"))
@@ -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)