/
AZD
/
game_rogue
Обзор
Документация
Войти
/
AZD
/
game_rogue
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
data/save_manager.py
184 строки
7 KB
User
First
14 июл 2026, 13:12
14 июл 2026, 13:12
ffe66af
Код
Авторство
О чём код?
"""Сохранение/загрузка.""" from __future__ import annotations import json import os import shutil from domain.entities import GameSession, Character, Point, Backpack, Item, Room, Corridor, Enemy SAVE_DIR = "data/saves" os.makedirs(SAVE_DIR, exist_ok=True) SAVE_FILE = os.path.join(SAVE_DIR, "current.json") SCORES_FILE = os.path.join(SAVE_DIR, "scores.json") def _serialize_point(p: Point): return {"x": p.x, "y": p.y} def _serialize_item(i: Item): # ✅ key_color = subtype, если type == "key" return { "type": i.type, "subtype": i.subtype, "heal_hp": i.heal_hp, "heal_max_hp": i.heal_max_hp, "bonus_dex": i.bonus_dex, "bonus_str": i.bonus_str, "cost": i.cost, "color": i.color, "name": i.name, "symbol": i.symbol, "key_color": i.subtype if i.type == "key" else None, } def save_session(session: GameSession): # ✅ Создаём резервную копию перед сохранением if os.path.exists(SAVE_FILE): backup_file = SAVE_FILE.replace(".json", "_backup.json") shutil.copy2(SAVE_FILE, backup_file) # Можно также добавить timestamp: # shutil.copy2(SAVE_FILE, SAVE_FILE.replace("current.json", f"current_{datetime.now():%Y%m%d_%H%M%S}.json")) lvl = session.current_level data = { "level_index": session.current_level_index, "difficulty_mod": session.difficulty_mod, "stats": session.stats, "player": { "hp": session.player.hp, "max_hp": session.player.max_hp, "dex": session.player.dex, "strength": session.player.strength, "position": _serialize_point(session.player.position), "asleep": getattr(session.player, "asleep", 0), "backpack": { "items": { "food": [_serialize_item(i) for i in session.player.backpack.foods], "elixir": [_serialize_item(i) for i in session.player.backpack.elixirs], "scroll": [_serialize_item(i) for i in session.player.backpack.scrolls], "weapon": [_serialize_item(i) for i in session.player.backpack.weapons], "treasure": [_serialize_item(i) for i in session.player.backpack.treasures], "key": [_serialize_item(i) for i in session.player.backpack.keys], }, "equipped_weapon": _serialize_item(session.player.backpack.equipped_weapon) if session.player.backpack.equipped_weapon else None, }, }, "level": { "index": lvl.index, "width": lvl.width, "height": lvl.height, "rooms": [r.__dict__ for r in lvl.rooms], "corridors": [{ "points": [_serialize_point(p) for p in c.points], "doors": [[_serialize_point(d[0]), d[1]] for d in c.doors] # ✅ list instead of tuple for JSON } for c in lvl.corridors], "enemies": [{ "kind": e.kind, "hp": e.hp, "max_hp": e.max_hp, "strength": e.strength, "dex": e.dex, "hostility": e.hostility, "position": _serialize_point(e.position), "symbol": e.symbol, "color": e.color, "room_index": e.room_index, "mimic_disguised": e.mimic_disguised, "treasure_drop": _serialize_item(e.treasure_drop) if e.treasure_drop else None, "rest_turns": e.rest_turns, "teleport_cd": e.teleport_cd, "asleep": e.asleep, "first_hit": e.first_hit, } for e in lvl.enemies], "items": [[_serialize_point(p), _serialize_item(i)] for p, i in lvl.items], "stairs": _serialize_point(lvl.stairs), "tiles": lvl.tiles, "visible": [_serialize_point(p) for p in lvl.visible], "seen": [_serialize_point(p) for p in lvl.seen], }, } with open(SAVE_FILE, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) def load_session(): if not os.path.exists(SAVE_FILE): return None with open(SAVE_FILE, "r", encoding="utf-8") as f: data = json.load(f) from domain.generator import restore_level_from_state try: level = restore_level_from_state(data["level"]) except Exception as e: print(f"Ошибка загрузки уровня: {e}") return None # Загрузка backpack bp_data = data["player"]["backpack"] backpack = Backpack() for item_data in bp_data["items"].get("food", []): backpack.foods.append(Item(**{k: v for k, v in item_data.items() if k != "key_color"})) for item_data in bp_data["items"].get("elixir", []): backpack.elixirs.append(Item(**{k: v for k, v in item_data.items() if k != "key_color"})) for item_data in bp_data["items"].get("scroll", []): backpack.scrolls.append(Item(**{k: v for k, v in item_data.items() if k != "key_color"})) for item_data in bp_data["items"].get("weapon", []): backpack.weapons.append(Item(**{k: v for k, v in item_data.items() if k != "key_color"})) for item_data in bp_data["items"].get("treasure", []): backpack.treasures.append(Item(**{k: v for k, v in item_data.items() if k != "key_color"})) for item_data in bp_data["items"].get("key", []): backpack.keys.append(Item(**{k: v for k, v in item_data.items() if k != "key_color"})) if bp_data["equipped_weapon"]: backpack.equipped_weapon = Item(**{k: v for k, v in bp_data["equipped_weapon"].items() if k != "key_color"}) # Загрузка игрока player_data = data["player"] player = Character( hp=player_data["hp"], max_hp=player_data["max_hp"], strength=player_data["strength"], dex=player_data["dex"], backpack=backpack, position=Point(**player_data["position"]), asleep=player_data.get("asleep", 0), ) session = GameSession( player=player, current_level=level, levels=[level], current_level_index=data["level_index"], difficulty_mod=data.get("difficulty_mod", 1.0), stats=data["stats"], messages=data.get("messages", []), ) return session def save_score(session: GameSession): scores = load_scores() scores.append({ "level": session.current_level_index + 1, "treasure": sum(i.cost for i in session.player.backpack.treasures), "kills": session.stats["kills"], "steps": session.stats["steps"], "damage_taken": session.stats["damage_taken"], }) scores.sort(key=lambda s: s["treasure"], reverse=True) scores = scores[:20] with open(SCORES_FILE, "w", encoding="utf-8") as f: json.dump(scores, f, ensure_ascii=False, indent=2) def load_scores(): if not os.path.exists(SCORES_FILE): return [] with open(SCORES_FILE, "r", encoding="utf-8") as f: return json.load(f) def has_save() -> bool: return os.path.exists(SAVE_FILE)