Weltkarte pixelexakt: gemessene Blit-Anker (Basis=(x,218-y)), Punkt steht + Kopf blinkt darueber, Segment/Name-Zuordnung um 1 korrigiert (W1L0 hat keinen Kartenpunkt)
This commit is contained in:
@@ -1739,3 +1739,41 @@ Binary-KOORDINATEN stimmen, aber der BLIT-ANKER des Originals (topleft vs
|
||||
zentriert) steht nicht im Binary -- wir hatten zentriert geraten. Fix:
|
||||
empirische Offsets MAP_DX=5/MAP_DY=4 in worldmap._tf() (dort feinjustieren,
|
||||
falls noch nicht exakt).
|
||||
|
||||
## 26.07.2026 (16) -- Karte PIXELEXAKT: Template-Matching statt Schaetzung
|
||||
|
||||
Stefans Nachmessung: immer noch daneben ("noch ein bisschen nach rechts
|
||||
und weiter runter"). Diesmal richtig gemessen: KARTE-Sprites per
|
||||
Template-Matching (mit Alpha-Maske) in den DOSBox-Referenzframes gesucht.
|
||||
Ergebnis eindeutig (err ~10 = VGA-DAC-Rauschen, naechster Kandidat >200):
|
||||
|
||||
- KARTE0 (10x7) steht DAUERHAFT, Topleft (58,162) -- in BEIDEN Blinkphasen!
|
||||
- KARTE4-Kopf (14x15) blinkt DARUEBER an/aus, Topleft (53,146) (steht auf
|
||||
dem Punkt). Frueherer Befund "Punkt und Kopf wechseln sich ab" war
|
||||
falsch (Diff-Region war die VEREINIGUNG beider Sprites).
|
||||
- KARTE3 (kleine Punkte): am Spielstart NIRGENDS auf der Karte -- nicht
|
||||
freigeschaltete Level sind unsichtbar (bestaetigt die Netz-Screenshots:
|
||||
dort ist das Spiel durchgespielt).
|
||||
|
||||
Daraus die exakten Anker (Binary-Label (x,y)): Basis = (x, 218-y);
|
||||
KARTE0-Topleft = Basis+(5,0); Kopf-Topleft = Basis+(0,-16); KARTE3
|
||||
zentriert auf dem grossen Punkt = Basis+(7,2) (einzige verbleibende
|
||||
Annahme -- kleine Punkte gibt es in keiner DOS-Referenzaufnahme).
|
||||
|
||||
WICHTIGER NEBENFUND -- Segment/Namens-Zuordnung war um 1 verschoben:
|
||||
Das Start-Label (53,56) gehoert zu SEGMENT 0, und 21 Segmente = exakt
|
||||
die 21 anwaehlbaren Level W1L1..W3L7 (3 Welten x 7). W1L0 (22. Name,
|
||||
MAP existiert) hat KEINEN Kartenpunkt (Bonus-/Geheimlevel?). Also
|
||||
segments[i] = names[i+1]; der "fehlende W3L7-Randfall" aus Eintrag (13)
|
||||
war keiner. Cursorstart = Segment 0 = W1L1.
|
||||
|
||||
Disassembly-Check (Stefans Frage "bekommst du das nicht aus dem
|
||||
Disassembler?"): einziges `mov ax,218` im Binary (Offset 0xf084) ist
|
||||
eine HUD-ZIFFERN-Routine (X-Positionen 186/194/202, Spriteindex =
|
||||
Ziffer+500 -- notiert fuer die Punkteanzeige!). Der Karten-Anker steht
|
||||
nicht als Literal im Code -> Pixelmessung war der richtige Weg.
|
||||
|
||||
Verifikation: eigener Karten-Render vs. DOSBox-Frame, mittlerer
|
||||
Pixelfehler 5.0 (identisch mit dem Ganzbild-Grundrauschen der
|
||||
VGA-DAC-Quantisierung) in beiden Blinkphasen => pixelidentisch.
|
||||
--once exit 0.
|
||||
|
||||
+27
-27
@@ -28,21 +28,22 @@ from . import intro
|
||||
HEAD_SPRITE = {'TONY': 'KARTE4', 'SMACKS': 'KARTE5', 'TOUCAN': 'KARTE6', 'COCO': 'KARTE7'}
|
||||
STEP_SECONDS = 0.18 # Lauftempo der Kartenfigur pro Wegpunkt
|
||||
BLINK_SECONDS = 0.5 # Blinkrhythmus der aktiven Position
|
||||
# Die Binary-Koordinaten sind y-GEFLIPPT (DOSBox-Nachmessung 25.07.2026:
|
||||
# Level-1-Punkt real bei (59,153), Binary-Label (53,56) -> screen_y = 209-y;
|
||||
# damit liegen die fruehen Level im Wald unten und W2/W3 in Bergen/Schloss
|
||||
# oben -- deckungsgleich mit Stefans Original-Screenshots).
|
||||
MAP_Y_FLIP = 209
|
||||
# Blit-Anker-Korrektur (Stefans Abgleich mit Original-Screenshots: "alle
|
||||
# Punkte ein Stueck nach rechts und unten"): die Binary-Koordinaten sind
|
||||
# korrekt, aber das Original ankert die Sprites nicht zentriert -- der
|
||||
# Versatz ist im Binary nicht ablesbar, daher empirisch. Feinjustage hier.
|
||||
MAP_DX = 5
|
||||
MAP_DY = 4
|
||||
# Die Binary-Koordinaten sind y-GEFLIPPT. Pixelexakte DOSBox-Nachmessung
|
||||
# (Template-Matching der KARTE-Sprites, 26.07.2026): Binary-Label von W1L1
|
||||
# ist (53,56); im Original steht KARTE0 (10x7) mit Topleft bei (58,162) und
|
||||
# der Mini-Kopf KARTE4 (14x15) blinkt DARUEBER bei Topleft (53,146) --
|
||||
# der Punkt bleibt also dauerhaft stehen, nur der Kopf geht an/aus.
|
||||
# Daraus: Basis = (x_bin, 218 - y_bin), Punkt-Topleft = Basis+(5,0),
|
||||
# Kopf-Topleft = Basis+(0,-16). Die Anker stehen nicht als Literal im
|
||||
# Binary (Code rechnet sie indirekt), daher per Messung fixiert.
|
||||
MAP_Y_FLIP = 218
|
||||
DOT_OFF = (5, 0) # KARTE0/KARTE2 (10x7), Topleft relativ zur Basis
|
||||
HEAD_OFF = (0, -16) # KARTE4-7 (14x15), steht auf dem Punkt
|
||||
SMALL_OFF = (7, 2) # KARTE3 (6x4), zentriert auf dem grossen Punkt
|
||||
|
||||
|
||||
def _tf(p):
|
||||
return (p[0] + MAP_DX, MAP_Y_FLIP - p[1] + MAP_DY)
|
||||
return (p[0], MAP_Y_FLIP - p[1])
|
||||
|
||||
|
||||
def parse_worldmap(exe_path):
|
||||
@@ -123,8 +124,11 @@ class WorldMap:
|
||||
except Exception as exc:
|
||||
print(f'[worldmap] Binary-Pfaddaten nicht lesbar ({exc}) -- '
|
||||
f'Fallback nur Level 1', file=sys.stderr)
|
||||
self.segments = [dict(waypoints=[(113, 35)], stand=(113, 35), label=(108, 51))]
|
||||
self.names = ['W1L1']
|
||||
self.segments = [dict(waypoints=[(53, 56)], stand=(53, 56), label=(53, 56))]
|
||||
self.names = ['W1L0', 'W1L1']
|
||||
# 21 Segmente fuer 21 anwaehlbare Level (W1L1..W3L7, 3 Welten x 7);
|
||||
# W1L0 (Name Nr. 0) hat KEINEN Kartenpunkt -> segments[i] = names[i+1].
|
||||
self.level_names = self.names[1:]
|
||||
# Positionen ins Screen-System transformieren (y-Flip)
|
||||
for seg in self.segments:
|
||||
seg['waypoints'] = [_tf(p) for p in seg['waypoints']]
|
||||
@@ -137,7 +141,7 @@ class WorldMap:
|
||||
self.dot_small = intro.make_border_bg_transparent(assets.pcc_surface('KARTE3'))
|
||||
self.heads = {c: intro.make_border_bg_transparent(assets.pcc_surface(n))
|
||||
for c, n in HEAD_SPRITE.items()}
|
||||
self.current = 1 if len(self.segments) > 1 else 0 # Start: Level 1 (Index 0 = W1L0)
|
||||
self.current = 0 # Segment 0 = W1L1 (DOSBox-Messung: Startpunkt (53,56))
|
||||
|
||||
def draw(self, canvas, char, t, walk_pos=None):
|
||||
canvas.blit(self.karte, (0, 0))
|
||||
@@ -146,23 +150,19 @@ class WorldMap:
|
||||
for i, seg in enumerate(self.segments):
|
||||
if seg['label'] is None:
|
||||
continue
|
||||
lx, ly = seg['label']
|
||||
bx, by = seg['label']
|
||||
if i == self.current and walk_pos is None:
|
||||
# Original-Verhalten (Netz-Referenzbilder + DOSBox-Diff):
|
||||
# an der aktuellen Position wechseln PUNKT und MINI-KOPF
|
||||
# Original-Verhalten (DOSBox-Messung): der grosse Punkt
|
||||
# steht dauerhaft, der Mini-Kopf blinkt DARUEBER an/aus
|
||||
canvas.blit(self.dot_big_on, (bx + DOT_OFF[0], by + DOT_OFF[1]))
|
||||
if head_phase:
|
||||
canvas.blit(head, (lx - head.get_width() // 2, ly - head.get_height() // 2))
|
||||
else:
|
||||
canvas.blit(self.dot_big_on,
|
||||
(lx - self.dot_big_on.get_width() // 2,
|
||||
ly - self.dot_big_on.get_height() // 2))
|
||||
canvas.blit(head, (bx + HEAD_OFF[0], by + HEAD_OFF[1]))
|
||||
else:
|
||||
dot = self.dot_small
|
||||
canvas.blit(dot, (lx - dot.get_width() // 2, ly - dot.get_height() // 2))
|
||||
canvas.blit(self.dot_small, (bx + SMALL_OFF[0], by + SMALL_OFF[1]))
|
||||
# waehrend des Laufens: Kopf entlang des Pfads
|
||||
if walk_pos is not None:
|
||||
px, py = walk_pos
|
||||
canvas.blit(head, (px - head.get_width() // 2, py - head.get_height()))
|
||||
canvas.blit(head, (px + HEAD_OFF[0], py + HEAD_OFF[1]))
|
||||
|
||||
|
||||
def run_worldmap(clock, assets, menu_assets, char='TONY', state={}):
|
||||
@@ -198,7 +198,7 @@ def run_worldmap(clock, assets, menu_assets, char='TONY', state={}):
|
||||
pts = list(reversed(wm.segments[wm.current]['waypoints']))
|
||||
walking = {'pts': pts, 'i': 0.0, 'target': wm.current - 1}
|
||||
elif event.key in (pygame.K_SPACE, pygame.K_RETURN):
|
||||
return ('level', wm.names[wm.current])
|
||||
return ('level', wm.level_names[wm.current])
|
||||
|
||||
dt = clock.tick(60) / 1000.0
|
||||
walk_pos = None
|
||||
|
||||
Reference in New Issue
Block a user