Levelende v1: Exit-Zone -> Zusammenfassungstafel (Original-Layout) -> Kartenfortschritt; TIME-OUT/Levelende-Tafeln bleiben bis Enter/Space stehen
This commit is contained in:
@@ -2089,3 +2089,23 @@ die "Absprung-Hocke" komplett entfernt (Sprung ist jetzt nur 8 hoch /
|
|||||||
(Slot 10). Slot 17 (frontal) ist damit nirgends mehr in Gebrauch;
|
(Slot 10). Slot 17 (frontal) ist damit nirgends mehr in Gebrauch;
|
||||||
die sess_level-"Frontal am Levelstart"-Deutung aus Eintrag (26) war
|
die sess_level-"Frontal am Levelstart"-Deutung aus Eintrag (26) war
|
||||||
wohl eine Fehlinterpretation der kleinen Crops.
|
wohl eine Fehlinterpretation der kleinen Crops.
|
||||||
|
|
||||||
|
## 26.07.2026 (35) -- Levelende v1 + Tafeln bleiben stehen
|
||||||
|
|
||||||
|
Stefans Regeln: TIME-OUT-Tafel (und Levelende-Tafel) bleiben STEHEN bis
|
||||||
|
Enter/Leertaste (_wait_panel). NEU Levelende v1:
|
||||||
|
- Exit-Zone erreicht -> Zusammenfassungstafel (SCORE/MAXIMUM/GESAMMELT/
|
||||||
|
VITAMINE/"0 X" -- nach Stefans Original-Screenshot; Werte noch 0, bis
|
||||||
|
Items gebaut sind; MAXIMUM = echte ARE-Zaehlung 151+154) -> 'completed'
|
||||||
|
-> intro.py laesst die Kartenfigur zum naechsten Punkt weiterwandern
|
||||||
|
(Punkt + Spur werden blau, Original-Regeln aus (31)/(33)).
|
||||||
|
- Exit-Zone W1L1 = SCHAETZUNG (rechtes Ende, um ARE-Objekt 194 bei
|
||||||
|
(3168,432)): exit_px=(3140,300,348,452). Echte Stelle + Aussehen des
|
||||||
|
Ausgangs von Stefan/DOSBox zu verifizieren!
|
||||||
|
- MAXIMUM-Diskrepanz: wir zaehlen 137 (151er+154er), Stefans Original-
|
||||||
|
Screen zeigte 158 -- vermutlich zaehlen ?-Box-Inhalte (71-76) und/oder
|
||||||
|
15x-Typen mit. Offen.
|
||||||
|
- ctype-Nibble-12 (44) liegt NICHT am Levelende (2 Tiles bei (91/99,17))
|
||||||
|
-- also kein Exit-Marker; Bedeutung offen. Bit 8 steckt zudem in
|
||||||
|
Standard-Boden (40=32+8) => Coco-Ast-Trigger (Bit 8) ist FALSCH und
|
||||||
|
muss neu bestimmt werden (aktuell greift Coco evtl. am Boden?? pruefen).
|
||||||
|
|||||||
+9
-1
@@ -990,7 +990,15 @@ def main():
|
|||||||
elif state == 'level':
|
elif state == 'level':
|
||||||
r = level_mod.run_level(clock, assets, audio_paths,
|
r = level_mod.run_level(clock, assets, audio_paths,
|
||||||
map_name=pending_map)
|
map_name=pending_map)
|
||||||
if r == 'map':
|
if r == 'completed':
|
||||||
|
# Level geschafft: Kartenfigur laeuft zum
|
||||||
|
# naechsten Punkt weiter (Punkt/Spur werden blau)
|
||||||
|
wm = map_state.get('wm')
|
||||||
|
if wm is not None and wm.current < len(wm.segments) - 1:
|
||||||
|
wm.current += 1
|
||||||
|
play_title_music()
|
||||||
|
state = 'map'
|
||||||
|
elif r == 'map':
|
||||||
play_title_music() # Karte/Menue laufen mit Titelmusik
|
play_title_music() # Karte/Menue laufen mit Titelmusik
|
||||||
state = 'map'
|
state = 'map'
|
||||||
else:
|
else:
|
||||||
|
|||||||
+82
-10
@@ -144,6 +144,10 @@ LEVEL_INFO = {
|
|||||||
chars=['TONY', 'SMACKS'], # Level 1: nur die beiden (Stefan)
|
chars=['TONY', 'SMACKS'], # Level 1: nur die beiden (Stefan)
|
||||||
water_y=42 * TILE, # Wasseroberflaeche unter der Bruecke
|
water_y=42 * TILE, # Wasseroberflaeche unter der Bruecke
|
||||||
door_px=(12 * TILE, 37 * TILE, 2 * TILE, 3 * TILE), # Haus-Tuer (x,y,w,h)
|
door_px=(12 * TILE, 37 * TILE, 2 * TILE, 3 * TILE), # Haus-Tuer (x,y,w,h)
|
||||||
|
# Levelende-Zone (v1-SCHAETZUNG: rechtes Levelende um das letzte
|
||||||
|
# ARE-Objekt Typ 194 bei (3168,432) -- echte Stelle noch per
|
||||||
|
# Stefan/DOSBox zu verifizieren)
|
||||||
|
exit_px=(3140, 300, 348, 452),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
WATER_TINT = (10, 20, 120, 110) # dunkelblaues Overlay
|
WATER_TINT = (10, 20, 120, 110) # dunkelblaues Overlay
|
||||||
@@ -741,6 +745,65 @@ def run_character_select(clock, assets, available, current):
|
|||||||
clock.tick(30)
|
clock.tick(30)
|
||||||
|
|
||||||
|
|
||||||
|
def _wait_panel(clock, panel):
|
||||||
|
'''Tafel anzeigen, bis Enter/Leertaste gedrueckt wird (Stefans Regel
|
||||||
|
fuer TIME-OUT- und Levelende-Tafel). Rueckgabe: 'ok' | 'quit'.'''
|
||||||
|
pygame.event.clear()
|
||||||
|
while True:
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == pygame.QUIT:
|
||||||
|
return 'quit'
|
||||||
|
if event.type == pygame.KEYDOWN and event.key in (
|
||||||
|
pygame.K_RETURN, pygame.K_SPACE):
|
||||||
|
return 'ok'
|
||||||
|
intro._blit_centered(intro.build_letterboxed(panel))
|
||||||
|
pygame.display.flip()
|
||||||
|
clock.tick(30)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_are_objects(are_bytes, map_w_tiles, map_h_tiles):
|
||||||
|
'''Objektliste (x_px, y_px, typ) aus einer .ARE (Format: NOTES (24)).'''
|
||||||
|
import struct
|
||||||
|
d = are_bytes
|
||||||
|
sec_w = (map_w_tiles * 16 + 63) // 64
|
||||||
|
sec_h = (map_h_tiles * 16 + 63) // 64
|
||||||
|
objs = []
|
||||||
|
for sy in range(sec_h):
|
||||||
|
for sx in range(sec_w):
|
||||||
|
off = struct.unpack('>H', d[352 + (sy * sec_w + sx) * 2:
|
||||||
|
354 + (sy * sec_w + sx) * 2])[0]
|
||||||
|
if off == 0xffff:
|
||||||
|
continue
|
||||||
|
q = 352 + off
|
||||||
|
while q < len(d) - 1:
|
||||||
|
v = struct.unpack('>H', d[q:q + 2])[0]
|
||||||
|
if v == 0xffff:
|
||||||
|
if q == 352 + off:
|
||||||
|
q += 2
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
typ, dx, dy = struct.unpack('>3H', d[q:q + 6])
|
||||||
|
objs.append((sx * 64 + dx, sy * 64 + dy, typ))
|
||||||
|
q += 6
|
||||||
|
return objs
|
||||||
|
|
||||||
|
|
||||||
|
def _summary_panel(assets, collected, maximum, vitamins, score):
|
||||||
|
'''Levelende-Tafel nach Stefans Original-Screenshot: SCORE, MAXIMUM/
|
||||||
|
GESAMMELT (Cerealien), VITAMINE, Bonusleben-Zeile.'''
|
||||||
|
from .menu import MenuAssets
|
||||||
|
m = MenuAssets(assets)
|
||||||
|
panel = m.menu_bg.copy()
|
||||||
|
def line(text, y):
|
||||||
|
surf = m.font_big.render(text)
|
||||||
|
panel.blit(surf, ((320 - surf.get_width()) // 2, y))
|
||||||
|
line(f'SCORE: {score}', 48)
|
||||||
|
line(f'MAXIMUM {maximum} GESAMMELT {collected}', 66)
|
||||||
|
line(f'VITAMINE {vitamins}', 84)
|
||||||
|
line('0 X', 116)
|
||||||
|
return panel
|
||||||
|
|
||||||
|
|
||||||
def run_level(clock, assets, audio_paths, map_name='W1L1'):
|
def run_level(clock, assets, audio_paths, map_name='W1L1'):
|
||||||
'''Level spielen. ESC -> 'map', Fenster-X -> 'quit'.'''
|
'''Level spielen. ESC -> 'map', Fenster-X -> 'quit'.'''
|
||||||
level = Level(assets, map_name)
|
level = Level(assets, map_name)
|
||||||
@@ -808,6 +871,23 @@ def run_level(clock, assets, audio_paths, map_name='W1L1'):
|
|||||||
vx=55.0 * player.facing, t=0.0))
|
vx=55.0 * player.facing, t=0.0))
|
||||||
|
|
||||||
keys = pygame.key.get_pressed()
|
keys = pygame.key.get_pressed()
|
||||||
|
# Levelende erreicht? -> Zusammenfassungstafel, dann Karte (Punkt
|
||||||
|
# wird blau, Figur wandert weiter -- intro.py behandelt 'completed')
|
||||||
|
exit_zone = info.get('exit_px')
|
||||||
|
if (dying is None and exit_zone
|
||||||
|
and pygame.Rect(exit_zone).collidepoint(player.x, player.y - 8)):
|
||||||
|
w, h = level.width, level.height
|
||||||
|
try:
|
||||||
|
objs = _parse_are_objects(
|
||||||
|
assets.container.entries[map_name + '.ARE'], w, h)
|
||||||
|
maximum = sum(1 for _, _, t in objs if t in (151, 154))
|
||||||
|
except Exception:
|
||||||
|
maximum = 0
|
||||||
|
panel = _summary_panel(assets, collected=0, maximum=maximum,
|
||||||
|
vitamins=0, score=0)
|
||||||
|
if _wait_panel(clock, panel) == 'quit':
|
||||||
|
return 'quit'
|
||||||
|
return 'completed'
|
||||||
time_left = info['time'] - (time.monotonic() - start)
|
time_left = info['time'] - (time.monotonic() - start)
|
||||||
# Zeit abgelaufen -> TIME-OUT-Tafel (Original-Screen, Stefans
|
# Zeit abgelaufen -> TIME-OUT-Tafel (Original-Screen, Stefans
|
||||||
# Screenshot: Menue-Rahmen + "TIME OUT"), dann Leben -1 und Respawn
|
# Screenshot: Menue-Rahmen + "TIME OUT"), dann Leben -1 und Respawn
|
||||||
@@ -817,16 +897,8 @@ def run_level(clock, assets, audio_paths, map_name='W1L1'):
|
|||||||
panel = m.menu_bg.copy()
|
panel = m.menu_bg.copy()
|
||||||
txt = m.font_big.render('TIME OUT')
|
txt = m.font_big.render('TIME OUT')
|
||||||
panel.blit(txt, ((320 - txt.get_width()) // 2, 72))
|
panel.blit(txt, ((320 - txt.get_width()) // 2, 72))
|
||||||
end = time.monotonic() + 2.5
|
if _wait_panel(clock, panel) == 'quit':
|
||||||
while time.monotonic() < end:
|
return 'quit'
|
||||||
for event in pygame.event.get():
|
|
||||||
if event.type == pygame.QUIT:
|
|
||||||
return 'quit'
|
|
||||||
if event.type == pygame.KEYDOWN:
|
|
||||||
end = 0
|
|
||||||
intro._blit_centered(intro.build_letterboxed(panel))
|
|
||||||
pygame.display.flip()
|
|
||||||
clock.tick(30)
|
|
||||||
lives -= 1
|
lives -= 1
|
||||||
if lives <= 0:
|
if lives <= 0:
|
||||||
return 'map'
|
return 'map'
|
||||||
|
|||||||
Reference in New Issue
Block a user