"""Manifest slotu zapisu — co, gdzie i pod jaką nazwą. Wszystkie listy pochodzą wprost ze skryptów gry: SCENES Game.cnv → G_ARRDATAS (BFITMP125) CHARACTERS MAINMENU.class:652 → M_ARRCHARACTERS (CONSTRUCTOR) MINIGAMES MAINMENU.class:652 → M_ARRPIOTR (CONSTRUCTOR) układ plików slotu → SAVEGAME (:667) i LOADGAME (:672) """ from __future__ import annotations from dataclasses import dataclass #: Lokacje mające własny plik .DTA. Kolejność jak w G_ARRDATAS. SCENES: tuple[str, ...] = ( "PODWIECZOREK1", "PODWIECZOREK2", "PODWIECZOREK3", "TRZYWEJSCIA", "DOMALCHOMIKA", "GABINETDYR", "HOLGLOWNY", "UNIVFRONT", "BIALO", "MIASTO", "LUSTRO", "TELEP_PODWORKO", "TELEP_WARSZTAT", "TELEP_KURNIKI", "PIWNICA", "ALCHEMY", "RATUSZ", "LABIRYNTH", "PIKLIBIA", "DOMSPIEL", "PRZEPASC", "MIOTLISKO", "KAPTUREK", "CALINECZKA", "DRATEWKA", "SNIEZKA", "KROLEWNA", "JAGA", "OLBRZYM", "SZREKSIO", "TROL", "NORASZ", "SEZAM", "PRZEDSEZAMEM", "KROLOWA", "SMOK", "RATUSZIN", "GULDRYK", "KORYTARZ", "SALA", "UNIVBACK", "UNIVPIWNICA", "MIOTSHOP", "PRZYSTAN", "GABINETSNEJKA", "BARANMIOT", "WMWEJSCIE", "WMWNETRZE", "PIKMIOT", "SKLEPALCH", "ARRAS", "POMPA", ) #: Sceny samodzielne z Application.def (PRZYGODA:SCENES) — intro, outro, minigry, #: dialogi. Nie mają własnego .DTA. G_SARCADEOBJECTS może wskazywać i na nie: #: _LOADGAME_ sprawdza G_ARRDATAS^FIND() i albo podmienia .DTA w scenie ARCADE, #: albo robi PRZYGODA^GOTO() do sceny o tej nazwie (Arcade.cnv:1533). STANDALONE_SCENES: tuple[str, ...] = ( "ARCADE", "INTRO_1", "INTRO_2", "INTRO_3", "INTRO_4", "MAGIC", "HILLS", "LIMBO", "DIALOGS", "CHOICE", "START", "LEBIODKA", "C_UCIECZKA", "CREDITS", "OUTRO_1", "OUTRO_2", "OUTRO_3", "OUTRO_4", "OUTRO_5", "OUTRO_6", "OUTRO_7", "OFERTA", "PRZYLOT", "PRZYLOT_2", "TELE_1", "TELE_2", "KONTROLA", "BARANDALF", "CAT", "FRED", "KUBKI", "MIOTLY", "LABIRYNT", "DRAGON", "SHOOTER", ) #: Wszystko, co może legalnie stać w G_SARCADEOBJECTS. VALID_LOCATIONS: frozenset[str] = frozenset(SCENES) | frozenset(STANDALONE_SCENES) #: Postacie z historią dialogową _HIST.ARR. CHARACTERS: tuple[str, ...] = ( "BUREKTOR", "GULDRYK", "SNEJK", "WALDIMORS", "SPIELMAUSTER", "CHRUMBURAK", "BARANDALF", "KROLOWA", "KAMIEN", "SMOK", "GASIENICA", ) #: Minigry z własnym .ARR. MINIGAMES: tuple[str, ...] = ( "LABIRYNT", "MIOTLY", "CAT", "BARANDALF", "DRAGON", "SHOOTER", ) #: Sloty widoczne w menu gry. Slot 0 to żywy stan rozgrywki, nie pozycja w menu. MENU_SLOTS: tuple[int, ...] = (1, 2, 3, 4) LIVE_SLOT = 0 #: Stała liczba slotów ekwipunku — pętle w Arcade.cnv są zahardkodowane na 0..10. ITEM_SLOTS = 10 #: Wymagana długość SPELLS.ARR; krótsza → gra po cichu resetuje. SPELLS_LEN = 17 #: Wymagana długość GAME.ARR; krótsza → DEFSETS, czyli utrata pozycji. GAMESETS_LEN = 6 @dataclass(frozen=True) class Entry: """Jeden plik należący do slotu.""" key: str # stabilny identyfikator, np. "scene:GULDRYK" kind: str # "dta" | "arr" template: str # nazwa pliku z {slot} do podstawienia label: str def filename(self, slot: int) -> str: return self.template.format(slot=slot) def manifest() -> list[Entry]: """Pełna lista plików tworzących jeden slot (bez miniaturki m_shot).""" entries: list[Entry] = [ Entry("game", "arr", "GAME{slot}.ARR", "Zmienne globalne rozgrywki"), Entry("items", "dta", "ITEMS{slot}.DTA", "Ekwipunek"), Entry("spells", "arr", "SPELLS{slot}.ARR", "Znane czary"), Entry("cutscenes", "arr", "CUTSCENES{slot}.ARR", "Obejrzane przerywniki"), Entry("invest", "arr", "INVEST{slot}.ARR", "Karta śledztwa"), Entry("questions", "arr", "QUESTIONS{slot}.ARR", "Dostępne pytania"), Entry("questions_asked", "arr", "QUESTIONS_ASKED{slot}.ARR", "Zadane pytania"), ] entries += [ Entry(f"scene:{name}", "dta", name + "{slot}.DTA", f"Lokacja {name}") for name in SCENES ] entries += [ Entry(f"hist:{name}", "arr", name + "_HIST{slot}.ARR", f"Rozmowy: {name}") for name in CHARACTERS ] entries += [ Entry(f"minigame:{name}", "arr", name + "{slot}.ARR", f"Minigra {name}") for name in MINIGAMES ] return entries MANIFEST: tuple[Entry, ...] = tuple(manifest()) BY_KEY: dict[str, Entry] = {e.key: e for e in MANIFEST} def screenshot_filename(slot: int) -> str: """Miniaturka zapisu pokazywana w menu — istnieje tylko dla slotów 1..4.""" return f"m_shot{slot}.img" #: Pliki stanu leżące w common/, ale POZA manifestem slotu — nie są kopiowane przy #: zapisie/wczytaniu, więc przeciekają między rozgrywkami. Głównie alchemia. UNSLOTTED_GLOBS: tuple[str, ...] = ( "SETTINGS.ARR", # globalne ustawienia: [?, głośność 0..800] "SLOT_*.SAV", # utrwalone mikstury (Alchemy.cnv:BEHSAVESLOTS) "DODOS_*.SAV", # stan dodo (Alchemy.cnv:BEHSAVEDODOS) )