Regelwerk trennt verbindliche Produktregeln, Arbeitsannahmen A-F und eigene Detailentscheidungen. Assetmatrix wird aus den Manifesten erzeugt. Baseline-Tests (Legacy) 209/33/463/206/1665 bestanden, Logs unter docs/luneraria/logs/m0-baseline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
97 lines
7.9 KiB
Python
97 lines
7.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Asset reuse matrix for Champions of Luneraria, generated from the runtime manifests.
|
|
|
|
Run: python3 tools/luneraria/build_asset_matrix.py -> docs/luneraria/ASSETMATRIX.md
|
|
Roles marked "vorläufig" are provisional assignments of existing models, not new peoples.
|
|
"""
|
|
from pathlib import Path
|
|
import json
|
|
|
|
P = Path(__file__).resolve().parents[2]
|
|
phase4 = {a['id']: a for a in json.loads((P / 'assets/phase4_manifest.json').read_text())['assets']}
|
|
skeletal = {}
|
|
for name in ['phase11', 'phase12', 'phase15', 'phase16', 'phase18', 'phase19']:
|
|
for a in json.loads((P / f'assets/{name}_manifest.json').read_text())['assets']:
|
|
skeletal[a['id']] = (a, name)
|
|
|
|
# id -> (bisherige Rolle, neue Rolle, Volk/Bund-Zuordnung, Eingriff)
|
|
ROLES = {
|
|
'g01': ('Glutpakt Nahkampf', 'Truppe Nahkampf', 'Glutkonstrukt / Glutpakt', 'keiner'),
|
|
'g02': ('Glutpakt Nahkampf+', 'Truppenaufwertung', 'Glutkonstrukt / Glutpakt', 'keiner'),
|
|
'g03': ('Glutpakt Tank', 'Truppe Front', 'Glutkonstrukt / Glutpakt', 'keiner'),
|
|
'g04': ('Glutpakt Tank+', 'Truppenaufwertung', 'Glutkonstrukt / Glutpakt', 'keiner'),
|
|
'g05': ('Glutpakt Fernkampf', 'Truppe Fernkampf; M2 zusätzlich Held „Funkenlanze“ (vorläufig, mit Heldenmarkierung)', 'Glutkonstrukt / Glutpakt', 'Heldenkennzeichnung in der Darstellung'),
|
|
'g06': ('Glutpakt Fernkampf+', 'Truppenaufwertung (Belagerung)', 'Glutkonstrukt / Glutpakt', 'keiner'),
|
|
'g07': ('Glutpakt Fläche', 'Truppe Fläche', 'Glutkonstrukt / Glutpakt', 'keiner'),
|
|
'g08': ('Glutpakt Fläche+', 'Truppenaufwertung', 'Glutkonstrukt / Glutpakt', 'keiner'),
|
|
'g09': ('Glutpakt Unterstützung', 'Truppe Unterstützung', 'Glutkonstrukt / Glutpakt', 'keiner'),
|
|
'g10': ('Glutpakt Unterstützung+', 'Truppenaufwertung', 'Glutkonstrukt / Glutpakt', 'keiner'),
|
|
'w01': ('Wurzelbund Nahkampf', 'Truppe Nahkampf', 'Wurzelwesen / Wurzelbund', 'keiner'),
|
|
'w02': ('Wurzelbund Nahkampf+', 'Truppenaufwertung', 'Wurzelwesen / Wurzelbund', 'keiner'),
|
|
'w03': ('Wurzelbund Tank', 'Truppe Front', 'Wurzelwesen / Wurzelbund', 'keiner'),
|
|
'w04': ('Wurzelbund Tank+', 'Truppenaufwertung; M2 zusätzlich Held „Ringborke“ (vorläufig)', 'Wurzelwesen / Wurzelbund', 'Heldenkennzeichnung'),
|
|
'w05': ('Wurzelbund Fernkampf', 'Truppe Fernkampf', 'Wurzelwesen / Wurzelbund', 'keiner'),
|
|
'w06': ('Wurzelbund Fernkampf+', 'Truppenaufwertung', 'Wurzelwesen / Wurzelbund', 'keiner'),
|
|
'w07': ('Wurzelbund Fläche', 'Truppe Fläche', 'Wurzelwesen / Wurzelbund', 'keiner'),
|
|
'w08': ('Wurzelbund Fläche+', 'Truppenaufwertung', 'Wurzelwesen / Wurzelbund', 'keiner'),
|
|
'w09': ('Wurzelbund Heiler', 'Truppe Unterstützung', 'Wurzelwesen / Wurzelbund', 'keiner'),
|
|
'w10': ('Wurzelbund Heiler+', 'Truppenaufwertung; M2 zusätzlich Held „Quellgeflecht“ (vorläufig)', 'Wurzelwesen / Wurzelbund', 'Heldenkennzeichnung'),
|
|
'e01': ('Wellengegner', 'Monsterwelle (teamgebunden, rotierend)', 'Riftbrut (neutral, pro Team eingefärbt)', 'Teamkennzeichnung'),
|
|
'e02': ('Wellengegner', 'Monsterwelle', 'Riftbrut', 'Teamkennzeichnung'),
|
|
'e03': ('Wellengegner', 'Monsterwelle', 'Riftbrut', 'Teamkennzeichnung'),
|
|
'e04': ('Wellengegner', 'Monsterwelle', 'Riftbrut', 'Teamkennzeichnung'),
|
|
'e05': ('Wellengegner', 'Monsterwelle (späte Variante)', 'Riftbrut', 'Teamkennzeichnung'),
|
|
'e06': ('Wellengegner', 'Monsterwelle (Unterstützer)', 'Riftbrut', 'Teamkennzeichnung'),
|
|
'e07': ('Boss Welle 5', 'Reserve (Wellen-Elite ab höheren Indizes)', 'Riftbrut', 'offen'),
|
|
'e08': ('Boss Welle 8', 'Reserve (Wellen-Elite)', 'Riftbrut', 'offen'),
|
|
'e09': ('Boss Welle 15', 'Reserve', 'Riftbrut', 'offen'),
|
|
'e10': ('Boss Welle 20', 'M2: neutraler Grottenboss und entsandter Boss', 'Riftbrut / Grotte', 'Bossdarstellung, Skalierung'),
|
|
's01': ('Söldner', 'Reserve Angriffschampion', 'Söldner', 'offen'),
|
|
's02': ('Söldner', 'M2: Angriffschampion Schutz', 'Söldner', 'keiner'),
|
|
's03': ('Söldner', 'M2: Angriffschampion Druck auf Unterstützer', 'Söldner', 'keiner'),
|
|
's04': ('Söldner', 'M2: Angriffschampion Belagerung', 'Söldner', 'keiner'),
|
|
's05': ('Söldner', 'Reserve Angriffschampion', 'Söldner', 'offen'),
|
|
'core_team0': ('Saumkern Team 0', 'Ancient Blau (SW)', '—', 'keiner'),
|
|
'core_team1': ('Saumkern Team 1', 'Ancient Rot (NO)', '—', 'keiner'),
|
|
'worker': ('Arbeiter/Funken', 'nicht im neuen Modus (Arbeitsannahme E); Modell bleibt erhalten', '—', 'keiner'),
|
|
'map_lane_segment': ('Lane-Kachel alt', 'nicht verwendet; Lanes neu erzeugt', '—', 'keiner'),
|
|
}
|
|
for prefix, people in (('m', 'Nietenkonvent (nicht spielbar)'), ('n', 'Nebelchor (nicht spielbar)')):
|
|
for i in range(1, 11):
|
|
ROLES[f'{prefix}{i:02d}'] = ('nicht spielbar, niedrige Detailstufe', 'Reserve für spätere Völker', people, 'Neuaufbau nötig vor Nutzung')
|
|
|
|
rows = []
|
|
for asset_id in sorted(set(phase4) | set(skeletal)):
|
|
base = phase4.get(asset_id, {})
|
|
path = base.get('resource_path', '')
|
|
source = str(base.get('blend_path', '')).replace(str(P) + '/', '')
|
|
tris = base.get('triangles', '')
|
|
rig = 'starre Gelenkgruppen'
|
|
material = 'HD, starre Teile' if base.get('detail_level') == 'high' else 'niedrige Detailstufe'
|
|
if asset_id in skeletal:
|
|
record, manifest = skeletal[asset_id]
|
|
path = record['resource_path']
|
|
source = record.get('source', source)
|
|
tris = record['triangles']
|
|
rig = '%d Knochen · %d Clips' % (record['bones'], len(record['clips']))
|
|
material = 'gewichtetes Skelett (%s)' % manifest
|
|
old, new, people, work = ROLES.get(asset_id, ('?', 'offen', '?', 'Prüfung nötig'))
|
|
rows.append((asset_id, base.get('name') or base.get('display_name') or skeletal.get(asset_id, ({},))[0].get('name', ''), path, source, rig, tris, old, new, people, material, work))
|
|
|
|
extra = [
|
|
('menu-stage', 'Menü-Diorama', 'res://assets/environment/menu-stage.glb', 'assets-source/phase20/build_menu_stage.py', 'statisch', '48660', 'Hauptmenü Phase 20A', 'Hauptmenü (Titel angepasst)', '—', 'Kluft-Shader', 'keiner'),
|
|
('verdant-rift', 'Grüne Kluft (2-Bretter-Arena)', 'res://assets/environment/verdant-rift.glb', 'assets-source/phase10/verdant-rift.blend', 'statisch', '—', 'Spielfeld Saumwacht', 'Legacy-Modus; Materialien/Shader für die neue Karte wiederverwendet', '—', 'triplanare Kluft-Shader', 'keine neue Nutzung als Karte'),
|
|
('compare-rock / compare-tree', 'Fels, Baum', 'res://assets/compare/', 'assets-source/phase14/build_compare_props.py', 'statisch', '360 / 852', 'Vergleichsszene', 'Kartendekoration Dschungel', '—', 'einfach', 'keiner'),
|
|
('Türme', '—', '(fehlt)', '—', '—', '—', '—', '16 Lanetürme/Basistürme', '—', '—', 'neu: Blender-Generator (M1)'),
|
|
('Bossgrotte', '—', '(fehlt)', '—', '—', '—', '—', 'Grottenbau nahe Zentrum', '—', '—', 'neu (M2)'),
|
|
('Emblem/Theme', 'Saumwacht-Theme', 'scripts/ui/theme/, assets/ui/', 'Code / SVG', '—', '—', 'Menü 20A', 'Theme weiterverwendet, Titel/Emblem Luneraria', '—', 'Vektor', 'Titelschrift/Emblem ergänzen'),
|
|
]
|
|
lines = ['# Asset-Wiederverwendungsmatrix', '',
|
|
'Erzeugt mit `python3 tools/luneraria/build_asset_matrix.py` aus den Laufzeitmanifesten. „Volk/Bund“ ist die Datenzuordnung. Die sieben Zielvölker (Menschen, Elfen, Zwerge, Trolle, Feen, Orks, Biestmenschen) haben noch **keine eigenen Modelle**; bestehende Wesen bleiben als eigene Bünde Teil der Welt. Als „vorläufig“ markierte Rollen sind Zuordnungen vorhandener Modelle, keine neu erstellten Völker.', '',
|
|
'| ID | Name | Pfad | Quelle | Rig / Clips | Dreiecke | bisherige Rolle | neue Rolle | Volk / Bund | Materialzustand | Eingriff |',
|
|
'| --- | --- | --- | --- | --- | ---: | --- | --- | --- | --- | --- |']
|
|
for row in rows + extra:
|
|
lines.append('| ' + ' | '.join(str(x) for x in row) + ' |')
|
|
(P / 'docs/luneraria').mkdir(parents=True, exist_ok=True)
|
|
(P / 'docs/luneraria/ASSETMATRIX.md').write_text('\n'.join(lines) + '\n')
|
|
print('ASSET_MATRIX', len(rows) + len(extra), 'rows')
|