v1.1: Stufen Easy/Normal/Hard mit Auswahlmenü (Hard = altes Tempo). Koffer behalten beim Drehen ihre Textur. Name/Punkteliste entfernt, nur Stufe + Prozent. Endlos: Ergebnis -> "Nochmals?" -> Stufenauswahl, Ende nur per Esc. storage.py und net.py gelöscht, 48 Tests.
This commit is contained in:
1 parent
de550e1d4d
commit
d970185e75
15 files changed
+613
-342
No files matched your search
+39
-40
@@ -8,15 +8,23 @@ from dataclasses import dataclass
|
||||
|
||||
from . import config, scene
|
||||
from .case import Case
|
||||
from .difficulty import DEFAULT_DIFFICULTY, Difficulty
|
||||
from .input_map import Action
|
||||
from .net import submit_score
|
||||
from .sequences import CaseSpec, FALLBACK_SEQUENCE
|
||||
from .trailer import Trailer
|
||||
|
||||
|
||||
class State(enum.Enum):
|
||||
PLAYING = "playing"
|
||||
GAME_OVER = "game_over"
|
||||
FINISHED = "finished"
|
||||
|
||||
|
||||
class HandleResult(enum.Enum):
|
||||
"""Was der Aufrufer nach einer Aktion tun soll."""
|
||||
|
||||
CONTINUE = "continue"
|
||||
NEW_ROUND = "new_round" # zurück zur Stufenauswahl
|
||||
QUIT = "quit" # Programm beenden (Esc / B)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -45,14 +53,12 @@ class Game:
|
||||
assets,
|
||||
sequences,
|
||||
*,
|
||||
name: str = config.DEFAULT_PLAYER_NAME,
|
||||
difficulty: Difficulty = DEFAULT_DIFFICULTY,
|
||||
rng: random.Random | None = None,
|
||||
submit_scores: bool = True,
|
||||
) -> None:
|
||||
self.assets = assets
|
||||
self.rng = rng or random.Random()
|
||||
self.name = name
|
||||
self.submit_scores = submit_scores
|
||||
self.difficulty = difficulty
|
||||
|
||||
self.state = State.PLAYING
|
||||
self.trailer = Trailer()
|
||||
@@ -64,8 +70,6 @@ class Game:
|
||||
self.animation: Animation | None = None
|
||||
self.shake = 0.0
|
||||
self.percent = 0.0
|
||||
self.status_line = ""
|
||||
self.status_is_error = False
|
||||
|
||||
self._spawn()
|
||||
|
||||
@@ -98,20 +102,21 @@ class Game:
|
||||
# ------------------------------------------------------------------
|
||||
# Eingabe
|
||||
# ------------------------------------------------------------------
|
||||
def handle(self, action: Action) -> bool:
|
||||
"""Verarbeitet eine Aktion. Rückgabe ``False`` = Spiel beenden."""
|
||||
def handle(self, action: Action) -> HandleResult:
|
||||
if action is Action.BACK:
|
||||
return False
|
||||
return HandleResult.QUIT
|
||||
|
||||
if self.state is State.GAME_OVER:
|
||||
return action is not Action.PRIMARY
|
||||
if self.state is State.FINISHED:
|
||||
if action is Action.PRIMARY:
|
||||
return HandleResult.NEW_ROUND
|
||||
return HandleResult.CONTINUE
|
||||
|
||||
if self.animation is not None or self.current is None:
|
||||
return True
|
||||
return HandleResult.CONTINUE
|
||||
|
||||
case = self.current
|
||||
if case.placed or not case.allow_snap:
|
||||
return True
|
||||
return HandleResult.CONTINUE
|
||||
|
||||
if action is Action.PRIMARY:
|
||||
self._start_snap(case)
|
||||
@@ -119,7 +124,7 @@ class Game:
|
||||
self._start_rotate(case)
|
||||
elif action is Action.UP:
|
||||
self._start_stack(case)
|
||||
return True
|
||||
return HandleResult.CONTINUE
|
||||
|
||||
def _start_snap(self, case: Case) -> None:
|
||||
self._stop_roll()
|
||||
@@ -179,7 +184,7 @@ class Game:
|
||||
self._finish()
|
||||
return
|
||||
|
||||
case.move(dt, self.trailer.wall_x)
|
||||
case.move(dt, self.trailer.wall_x, self.difficulty)
|
||||
if not case.placed and case.x <= self.trailer.wall_x:
|
||||
self._stack_with_gap(case, sound="fail")
|
||||
return
|
||||
@@ -258,25 +263,25 @@ class Game:
|
||||
self._finish()
|
||||
|
||||
def _finish(self) -> None:
|
||||
if self.state is State.GAME_OVER:
|
||||
if self.state is State.FINISHED:
|
||||
return
|
||||
self.state = State.GAME_OVER
|
||||
self.state = State.FINISHED
|
||||
self._stop_roll()
|
||||
self.percent = self.trailer.load_percent()
|
||||
if self.percent >= 99.9:
|
||||
self.percent = 100.0
|
||||
if self.submit_scores:
|
||||
ok, message = submit_score(self.name, self.percent)
|
||||
if ok or config.SCORE_URL:
|
||||
self.status_line = message
|
||||
self.status_is_error = not ok
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Zeichnen
|
||||
# ------------------------------------------------------------------
|
||||
def draw(self, surface) -> None:
|
||||
assets = self.assets
|
||||
scene.draw_top_bar(surface, assets, self.trailer.load_percent())
|
||||
scene.draw_top_bar(
|
||||
surface,
|
||||
assets,
|
||||
self.trailer.load_percent(),
|
||||
subtitle=config.SUBTITLE_TEMPLATE.format(difficulty=self.difficulty.label),
|
||||
)
|
||||
scene.draw_background(surface, assets)
|
||||
|
||||
offset = (0, 0)
|
||||
@@ -304,22 +309,16 @@ class Game:
|
||||
surface, assets, self.trailer.find_platform(case) is not None
|
||||
)
|
||||
|
||||
if self.state is State.GAME_OVER:
|
||||
scene.draw_overlay_lines(
|
||||
surface,
|
||||
assets,
|
||||
self.game_over_lines(),
|
||||
status=self.status_line,
|
||||
status_color=config.COLOR_ERROR if self.status_is_error else config.COLOR_HINT_SNAP,
|
||||
)
|
||||
if self.state is State.FINISHED:
|
||||
scene.draw_overlay_lines(surface, assets, self.result_lines())
|
||||
|
||||
def game_over_lines(self) -> list[str]:
|
||||
percent = int(self.percent)
|
||||
if self.percent >= config.GAME_OVER_GOOD_PERCENT:
|
||||
first = config.GAME_OVER_GOOD.format(name=self.name, percent=percent)
|
||||
else:
|
||||
first = config.GAME_OVER_NORMAL.format(name=self.name, percent=percent)
|
||||
return [first, config.GAME_OVER_HINT]
|
||||
def result_lines(self) -> list[str]:
|
||||
return [
|
||||
config.RESULT_TEMPLATE.format(
|
||||
difficulty=self.difficulty.label, percent=int(self.percent)
|
||||
),
|
||||
config.RESULT_HINT,
|
||||
]
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Hilfen
|
||||
|
||||
Reference in new issue
Block a user