4.3 KiB
ricsave — edytor zapisów „Reksio i Czarodzieje"
Narzędzie debugowe do zapisów gry z 2004 r. (silnik PIK, PIKLIB8.dll). Gra nie ma
jednego pliku zapisu — stan to 76 plików na slot w katalogu common/, kopiowanych
plik-po-pliku. Ta biblioteka czyta oba formaty, waliduje niezmienniki i daje UI.
Rozpoznanie formatu: docs/format-zapisow.md — to jest właściwa dokumentacja, tu tylko obsługa.
Start
python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"
export RIC_GAME="$HOME/Reksio/Reksio i Czarodzieje"
ricsave info # przegląd slotów
ricsave serve # edytor w przeglądarce (127.0.0.1:8765)
Rdzeń (ricsave/) nie ma żadnych zależności — serwer chodzi na http.server
ze stdliba, front to trzy pliki statyczne bez frameworka.
Zrób kopię zanim cokolwiek zapiszesz: ricsave backup ~/kopia-common.
CLI
ricsave info # które sloty zajęte, gdzie stoisz
ricsave validate 1 # niezmienniki, które gra połyka po cichu
ricsave gamesets 1 # GAME1.ARR z rozwiniętymi nazwami pól
ricsave scene 1 GULDRYK --explain # tabela obiektów lokacji + legenda TYPE
ricsave items 1 # ekwipunek
ricsave dump 1 --key scene:PIWNICA # JSON
ricsave diff 0 1 -v # co się różni między slotami
ricsave set 0 GULDRYK KULA_SEN IPARAM0=1 # punktowa zmiana pola
ricsave copy 1 0 # slot 1 → żywy stan (to samo co LOADGAME)
ricsave newgame # reset żywego stanu z szablonów _DEF
diff jest tu główną bronią: zapisz przed i po jakiejś akcji w grze, porównaj sloty
i od razu widzisz, które pole za nią odpowiada.
Biblioteka
from ricsave import Game
game = Game("~/Reksio/Reksio i Czarodzieje")
slot = game.slot(0) # 0 = żywy stan, 1..4 = sloty menu
slot.summary()
slot.validate() # [] gdy OK
scene = slot.scene("PIWNICA")
i = scene.find("GARNEK") # po IDNAME
scene.set(i, "IPARAM0", 1)
slot.touch("scene:PIWNICA")
slot.flush() # zapisuje tylko dotknięte pliki
Model slotów — jedyna rzecz, którą trzeba zrozumieć
slot 0 ←→ slot 1..4
↑ ↑
| └─ cztery pozycje z menu gry
└─ ŻYWY STAN bieżącej rozgrywki
Gra w trakcie grania czyta i pisze wyłącznie slot 0. Menu „Zapisz"/„Wczytaj" to
zwykłe kopiowanie plików między 0 a n. Praktyczny wniosek: edycja slotu 3 nie zrobi
nic, dopóki nie wczytasz go w grze (albo nie zrobisz ricsave copy 3 0).
Czego pilnować przy edycji
- Nie dodawaj ani nie usuwaj wierszy
.DTA. Skrypty scen adresują je po indeksie (DBOBJECTS^SELECT(10)), więc przesunięcie rozjeżdża logikę.ricsave validatei UI blokują zmianę liczby wierszy. - Za krótkie
GAME<n>.ARRlubSPELLS<n>.ARRgra połknie po cichu i zresetuje do domyślnych — nie zobaczysz błędu, tylko utratę pozycji. EMPTY = 1wITEMSoznacza slot ZAJĘTY, nie pusty.- Edytuj przy zamkniętej grze —
SAVEGAMEnadpisuje slot bez pytania.
Testy
RIC_GAME="$HOME/Reksio/Reksio i Czarodzieje" .venv/bin/python -m pytest
Kluczowe są testy korpusowe: przejeżdżają po wszystkich plikach .ARR/.DTA
w common/ i sprawdzają round-trip bajt w bajt. Jeśli parser i writer się
rozjadą, edytor po cichu zepsułby zapis — to ta siatka bezpieczeństwa.
Układ
ricsave/
arr.py ARRAY (.ARR/.SAV) — binarny, int32 + string
dta.py DATABASE (.DTA) — CRLF + pionowa kreska
catalog.py manifest slotu: 52 lokacje, 11 postaci, 6 minigier
schema.py kolumny STRUCT + znaczenia pól ARR
slot.py Game / Slot / widoki / operacje SAVEGAME-LOADGAME-NEWGAME
cli.py
webapp/
server.py http.server + JSON API
static/ index.html, app.js, style.css
docs/
format-zapisow.md
Co jeszcze nie jest zdekodowane
INVEST<n>.ARR— karta śledztwa, ≥8 elementów (INVESTIGATION.class:622)IPARAM0/1/2dla obiektów scen zTYPE < 100innym niż 2 — znaczą co innego w każdej lokacji, trzeba czytać.cnvsceny- Element 0 w
SETTINGS.ARR(element 1 to głośność 0..800)