v1.2: Log zeigt gewaehlte Sequenz (nie zweimal dieselbe), Anleitung vor Moduswahl (jede Runde), Roll-Sound-Kanal reserviert (Fix kein Sound), frueheres Abbremsen + Snap-Fenster 160px, 10s Cooldown am Ende, Sprueche nach Prozent (sayings.py), 56 Tests.
This commit is contained in:
1 parent
d970185e75
commit
e3a0c5a57d
11 files changed
+319
-37
No files matched your search
+84
-4
@@ -20,6 +20,7 @@ from loader_game.difficulty import DEFAULT_DIFFICULTY, DIFFICULTIES, by_key
|
||||
from loader_game.game import Game, HandleResult, State
|
||||
from loader_game.input_map import Action
|
||||
from loader_game.menu import DifficultyMenu
|
||||
from loader_game.sayings import saying_for
|
||||
from loader_game.sequences import CaseSpec, load_sequences, parse_sequences
|
||||
from loader_game.trailer import Trailer
|
||||
|
||||
@@ -131,8 +132,8 @@ class CaseTests(unittest.TestCase):
|
||||
case.move(1 / 60, wall_x=0)
|
||||
self.assertFalse(case.allow_snap)
|
||||
|
||||
case = self.make_case(x=config.SNAP_THRESHOLD + 2)
|
||||
case.move(1 / 60, wall_x=0)
|
||||
case = self.make_case(x=config.SNAP_WINDOW + 2)
|
||||
case.move(1 / 60, wall_x=0, difficulty=DIFFICULTIES[0])
|
||||
self.assertTrue(case.allow_snap)
|
||||
|
||||
def test_placed_case_does_not_move(self) -> None:
|
||||
@@ -207,7 +208,7 @@ class TrailerTests(unittest.TestCase):
|
||||
def test_gap_placement_leaves_hole(self) -> None:
|
||||
case = self.make_case(2, 1)
|
||||
self.trailer.stack_with_gap(case)
|
||||
self.assertEqual(case.x, self.trailer.x + config.SNAP_THRESHOLD)
|
||||
self.assertEqual(case.x, self.trailer.x + config.FAIL_GAP)
|
||||
self.assertFalse(case.snapped)
|
||||
|
||||
def test_platform_on_flat_ground_case_is_allowed(self) -> None:
|
||||
@@ -321,7 +322,7 @@ class GameTests(unittest.TestCase):
|
||||
rng=random.Random(1),
|
||||
)
|
||||
case = game.current
|
||||
case.x = float(game.trailer.wall_x + config.SNAP_THRESHOLD + 1)
|
||||
case.x = float(game.trailer.wall_x + config.SNAP_WINDOW + 1)
|
||||
case.allow_snap = True
|
||||
game.handle(Action.LEFT)
|
||||
self.update_until(game, lambda: game.animation is None)
|
||||
@@ -393,6 +394,10 @@ class GameTests(unittest.TestCase):
|
||||
game.handle(Action.PRIMARY)
|
||||
game.update(1 / 60)
|
||||
self.assertIs(game.state, State.FINISHED)
|
||||
# Cooldown: erst nach Ablauf darf die nächste Runde starten
|
||||
self.assertIs(game.handle(Action.PRIMARY), HandleResult.CONTINUE)
|
||||
for _ in range(int(config.RESULT_COOLDOWN * 60) + 5):
|
||||
game.update(1 / 60)
|
||||
self.assertIs(game.handle(Action.PRIMARY), HandleResult.NEW_ROUND)
|
||||
|
||||
def test_result_lines_show_difficulty_and_percent(self) -> None:
|
||||
@@ -404,6 +409,81 @@ class GameTests(unittest.TestCase):
|
||||
self.assertTrue(any("ESC" in line for line in lines))
|
||||
|
||||
|
||||
|
||||
class SayingTests(unittest.TestCase):
|
||||
def test_full_load_gets_the_contract_line(self) -> None:
|
||||
self.assertIn("Vertrag", saying_for(100))
|
||||
self.assertIn("Vertrag", saying_for(100.0))
|
||||
|
||||
def test_every_percent_gets_a_saying(self) -> None:
|
||||
rng = random.Random(5)
|
||||
for percent in range(0, 101, 5):
|
||||
self.assertTrue(saying_for(percent, rng).strip())
|
||||
|
||||
def test_high_and_low_use_different_pools(self) -> None:
|
||||
rng = random.Random(1)
|
||||
high = {saying_for(90, rng) for _ in range(40)}
|
||||
low = {saying_for(10, rng) for _ in range(40)}
|
||||
self.assertFalse(high & low)
|
||||
|
||||
def test_no_harsh_words(self) -> None:
|
||||
# Zielgruppe Jugendliche: frech ja, beleidigend nein.
|
||||
bad = ("dumm", "idiot", "blöd", "bloed", "versager", "looser", "hässlich")
|
||||
rng = random.Random(4)
|
||||
for percent in range(0, 101, 5):
|
||||
text = saying_for(percent, rng).lower()
|
||||
for word in bad:
|
||||
self.assertNotIn(word, text)
|
||||
|
||||
|
||||
class ResultCooldownTests(unittest.TestCase):
|
||||
def finish_a_round(self) -> Game:
|
||||
game = Game(
|
||||
None,
|
||||
[[CaseSpec(1, 1)]],
|
||||
difficulty=DIFFICULTIES[1],
|
||||
rng=random.Random(2),
|
||||
)
|
||||
for _ in range(4000):
|
||||
if game.state is State.FINISHED:
|
||||
break
|
||||
game.update(1 / 60)
|
||||
self.assertIs(game.state, State.FINISHED)
|
||||
return game
|
||||
|
||||
def test_countdown_then_hint(self) -> None:
|
||||
game = self.finish_a_round()
|
||||
lines = game.result_lines()
|
||||
self.assertEqual(len(lines), 3)
|
||||
self.assertIn("Neue Runde in", lines[2])
|
||||
self.assertIn("%", lines[0])
|
||||
|
||||
for _ in range(int(config.RESULT_COOLDOWN * 60) + 5):
|
||||
game.update(1 / 60)
|
||||
self.assertIn("ESC", game.result_lines()[2])
|
||||
|
||||
def test_primary_is_ignored_during_cooldown(self) -> None:
|
||||
game = self.finish_a_round()
|
||||
self.assertIs(game.handle(Action.PRIMARY), HandleResult.CONTINUE)
|
||||
game.update(config.RESULT_COOLDOWN / 2)
|
||||
self.assertIs(game.handle(Action.PRIMARY), HandleResult.CONTINUE)
|
||||
|
||||
|
||||
class SequenceChoiceTests(unittest.TestCase):
|
||||
def test_never_repeats_the_previous_sequence(self) -> None:
|
||||
sequences = [[CaseSpec(1, 1)] for _ in range(4)]
|
||||
rng = random.Random(11)
|
||||
previous = None
|
||||
for _ in range(40):
|
||||
game = Game(None, sequences, rng=rng, previous_sequence=previous)
|
||||
self.assertNotEqual(game.sequence_index, previous)
|
||||
previous = game.sequence_index
|
||||
|
||||
def test_single_sequence_is_allowed(self) -> None:
|
||||
game = Game(None, [[CaseSpec(1, 1)]], rng=random.Random(1), previous_sequence=0)
|
||||
self.assertEqual(game.sequence_index, 0)
|
||||
|
||||
|
||||
class RenderTests(unittest.TestCase):
|
||||
"""Rendert je ein Bild von Intro, Menü und Spiel (ohne Fenster).
|
||||
|
||||
|
||||
Reference in new issue
Block a user