From 514962321c11c84f5827b872cdcfb227d4fb77f6 Mon Sep 17 00:00:00 2001 From: Niklas Haiden Date: Fri, 8 May 2026 19:37:57 +0200 Subject: [PATCH] fix highscore implementation and decrease projectile damage --- src/endscreen.py | 1 + src/highscore.json | 30 ------------------------- src/highscore.py | 56 ++++++++++++++++++++++++++++++++++++++++------ src/settings.py | 4 ++-- 4 files changed, 52 insertions(+), 39 deletions(-) diff --git a/src/endscreen.py b/src/endscreen.py index 075cda4..4c056bb 100644 --- a/src/endscreen.py +++ b/src/endscreen.py @@ -55,6 +55,7 @@ class Endscreen: ) self.highscore = Highscore() + self.highscore.add_score(self.player_name or "Student", self.score_ects, self.time_survived, self.won) def run(self): # get events diff --git a/src/highscore.json b/src/highscore.json index 7ef8cca..3634832 100644 --- a/src/highscore.json +++ b/src/highscore.json @@ -4,35 +4,5 @@ "ects": 55, "time": "02:00", "won": true - }, - { - "name": "Anna", - "ects": 48, - "time": "01:35", - "won": true - }, - { - "name": "Kevin", - "ects": 42, - "time": "01:58", - "won": true - }, - { - "name": "Lena", - "ects": 35, - "time": "01:44", - "won": false - }, - { - "name": "Lukas", - "ects": 20, - "time": "00:58", - "won": false - }, - { - "name": "Max", - "ects": 12, - "time": "00:30", - "won": false } ] \ No newline at end of file diff --git a/src/highscore.py b/src/highscore.py index 625b8e9..6aa0d53 100644 --- a/src/highscore.py +++ b/src/highscore.py @@ -3,9 +3,9 @@ import pygame from src.settings import HIGHSCORE_COLOR_FONT, HIGHSCORE_COLOR_TABLE class Highscore: - def __init__(self): + def __init__(self, path="src/highscore.json"): # fix path to json file with highscores - self.path = "src/highscore.json" + self.path = path self.font_title = pygame.font.SysFont("Arial", 28, bold=True) self.font_score = pygame.font.SysFont("Arial", 18, bold=True) @@ -23,7 +23,9 @@ class Highscore: :return: All scores form json file. """ with open(self.path, "r") as f: - return json.load(f) + scores = json.load(f) + + return scores if isinstance(scores, list) else [] def save_scores(self, scores): """ @@ -57,8 +59,7 @@ class Highscore: } scores.append(new_score) - # sort by ects descending - scores.sort(key=lambda score: score["ects"], reverse=True) + self.sort_scores(scores) # keep only top 50 elements scores = scores[:50] @@ -71,9 +72,50 @@ class Highscore: :return: Return top 5 scores as list. """ scores = self.load_scores() - scores.sort(key=lambda score: score["ects"], reverse=True) + self.sort_scores(scores) return scores[:5] + @classmethod + def sort_scores(cls, scores): + scores.sort(key=cls.get_rank_key) + + @staticmethod + def get_rank_key(score): + return ( + not bool(score.get("won", False)), + -Highscore.safe_int(score.get("ects", 0)), + -Highscore.parse_time(score.get("time", 0)), + str(score.get("name", "")).lower(), + ) + + @staticmethod + def safe_int(value): + try: + return int(value) + except (TypeError, ValueError): + return 0 + + @staticmethod + def parse_time(value): + if isinstance(value, (int, float)): + return int(value) + if isinstance(value, str): + parts = value.split(":") + try: + if len(parts) == 2: + return int(parts[0]) * 60 + int(parts[1]) + return int(value) + except ValueError: + return 0 + return 0 + + @staticmethod + def format_time(value): + total_seconds = Highscore.parse_time(value) + minutes = total_seconds // 60 + seconds = total_seconds % 60 + return f"{minutes:02}:{seconds:02}" + def get_top_scores_formatted(self): """ Get top 5 scores from highscore file in nice format. @@ -88,7 +130,7 @@ class Highscore: line = ( f"{index + 1}. {score['name']} | " f"ECTS: {score['ects']} | " - f"Time: {score['time']} | " + f"Time: {self.format_time(score['time'])} | " f"Result: {result}" ) diff --git a/src/settings.py b/src/settings.py index 2bad6f1..aa427a5 100644 --- a/src/settings.py +++ b/src/settings.py @@ -64,7 +64,7 @@ COFFEE_HEAL_VALUE = 20 # --- TOWER --- TOWER_COST = 10 -PROJECTILE_DMG = 7 +PROJECTILE_DMG = 4 PROJECTILE_SPEED = 7 COLOR_PROJECTILE = (200, 200, 0) TOWER_TIMER = 30000 # how long the tower stays and attack before it disappears @@ -90,7 +90,7 @@ MONSTER_MAX_COUNT = 1 MONSTER_SPAWN_INTERVAL = 8000 # ms until a replacement monster spawns MONSTER_SPEED = 90.0 MONSTER_DOOR_DAMAGE = ZOMBIE_MEDIUM_DMG -MONSTER_ATTACK_INTERVAL = 1000 # ms between door attacks +MONSTER_ATTACK_INTERVAL = 2000 # ms between door attacks # --- HUD --- HUD_FONT = "Arial"