125 lines
4.6 KiB
Python
125 lines
4.6 KiB
Python
"""Schematy: nazwy kolumn .DTA i znaczenie indeksów w .ARR.
|
|
|
|
Kolumny .DTA nie są zapisane w pliku — pochodzą z definicji STRUCT w Arcade.cnv
|
|
(linie 1455-1489). Znaczenia pól ARR z MAINMENU.class (DEFSETS, SAVEGAME).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
INT = "INTEGER"
|
|
STR = "STRING"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Column:
|
|
name: str
|
|
type: str
|
|
note: str = ""
|
|
|
|
|
|
#: SOBJECT — model bazy obiektów sceny (<SCENA><slot>.DTA).
|
|
SOBJECT: tuple[Column, ...] = (
|
|
Column("NAME", STR, "ścieżka do .ANN/.IMG/.SEK względem katalogu sceny"),
|
|
Column("IDNAME", STR, "identyfikator logiczny, używany przez skrypty sceny"),
|
|
Column("TYPE", INT, "rola wiersza — patrz OBJECT_TYPES"),
|
|
Column("SPARAM0", STR),
|
|
Column("SPARAM1", STR),
|
|
Column("SPARAM2", STR),
|
|
Column("IPARAM0", INT, "dla TYPE==2: 1 = widoczny, 0 = zabrany"),
|
|
Column("IPARAM1", INT),
|
|
Column("IPARAM2", INT),
|
|
)
|
|
|
|
#: SITEM — model ekwipunku (ITEMS<slot>.DTA).
|
|
SITEM: tuple[Column, ...] = (
|
|
Column("GUID", INT, "indeks slotu 0..9, równy numerowi wiersza"),
|
|
Column("NAME", STR, "identyfikator przedmiotu, NULL gdy pusto"),
|
|
Column("PARENT", INT, "indeks wiersza w .DTA lokacji, z której podniesiono (-1 = brak)"),
|
|
Column("BASE", STR, "lokacja pochodzenia"),
|
|
Column("EMPTY", INT, "MYLĄCA NAZWA: 1 = slot ZAJĘTY, 0 = wolny"),
|
|
)
|
|
|
|
DTA_SCHEMAS: dict[str, tuple[Column, ...]] = {
|
|
"scene": SOBJECT,
|
|
"items": SITEM,
|
|
}
|
|
|
|
#: Kolumna TYPE w SOBJECT — dekoder z Arcade.cnv:__LOAD_DB__.
|
|
OBJECT_TYPES: dict[int, str] = {
|
|
101: "tło statyczne (.IMG)",
|
|
102: "maska ścieżek chodzenia (.SEK)",
|
|
103: "aktywacja przejścia: WPATH^SETACTIVE(IPARAM0, IPARAM1, IPARAM2)",
|
|
104: "Reksio; IPARAM0 = prędkość maks.",
|
|
105: "punkt startowy, zestaw 0; IDNAME = scena skąd, IPARAM0/1 = X/Y",
|
|
106: "punkt docelowy, zestaw 0; IPARAM0/1 = X/Y",
|
|
107: "tło animowane; IPARAM0/1 = szerokość/wysokość",
|
|
108: "muzyka lokacji; IDNAME = plik .WAV",
|
|
140: "Kret",
|
|
145: "punkt startowy, zestaw 1",
|
|
146: "punkt docelowy, zestaw 1",
|
|
}
|
|
|
|
|
|
def describe_object_type(value: int) -> str:
|
|
if value in OBJECT_TYPES:
|
|
return OBJECT_TYPES[value]
|
|
if value < 100:
|
|
extra = " — IPARAM0 to flaga widoczności" if value == 2 else ""
|
|
return f"obiekt sceny (ANNOBJECT), podtyp {value}{extra}"
|
|
return f"nieznany typ {value}"
|
|
|
|
|
|
#: GAME<slot>.ARR — 6 elementów, wszystkie zapisane jako STRING.
|
|
GAMESETS: tuple[Column, ...] = (
|
|
Column("G_SARCADEOBJECTS", STR, "bieżąca lokacja"),
|
|
Column("G_SLASTOBJECTS", STR, "poprzednia lokacja — wyznacza punkt wejścia"),
|
|
Column("G_SDIALOGCHARACTER", STR, "rozmówca"),
|
|
Column("G_SDIALOGRETURN", STR, "dokąd wrócić po rozmowie"),
|
|
Column("G_ITKTPM", INT, "identyfikator \"Tego, Który Tak Potwornie Mąci\""),
|
|
Column("G_IKRETACTIVE", INT, "czy Kret towarzyszy Reksiowi (0/1)"),
|
|
)
|
|
|
|
#: Stan fabryczny GAME0.ARR z DEFSETS (indeks 4 jest losowany 0..7).
|
|
GAMESETS_DEFAULT: list[str] = ["INTRO_1", "NULL", "BUREKTOR", "NULL", "0", "0"]
|
|
|
|
#: SPELLS<slot>.ARR — 17 intów. Stan fabryczny z NEWGAME.
|
|
SPELLS_DEFAULT: list[int] = [0] * 12 + [64] + [0] * 4
|
|
|
|
#: Próg doświadczenia na jeden poziom (MAINMENU.class: LEVELUP, BFITMP57/59/61).
|
|
EXP_PER_LEVEL = 150
|
|
|
|
#: Ile klatek animacji klepsydry — klatka = exp // 10 + 1 (BFITMP55).
|
|
EXP_PER_HOURGLASS_FRAME = 10
|
|
|
|
#: Indeksy 0..11 to flagi „czar znany" (0/1). Sześć czarów w wersji zwykłej (0-5)
|
|
#: i obronnej (6-11, sufiks _OBR); czar N ma obronę N+6. Nazwy z uchwytów klikania
|
|
#: kul w gabinetach — Guldryk.cnv, Gabinetsnejka.cnv, Wmwnetrze.cnv.
|
|
SPELL_NAMES: tuple[str, ...] = (
|
|
"Sen", "Zamiana w żabę", "Plaga much", "Kula budyniu", "Koła i wiry", "Ciemność",
|
|
"Obrona przed Snem", "Obrona przed Zamianą w żabę", "Obrona przed Plagą much", "Obrona przed Kulą budyniu",
|
|
"Obrona przed Kołami i wirami", "Obrona przed Ciemnością",
|
|
)
|
|
|
|
#: Indeksy 12..16 — liczniki i flagi stanu klepsydry.
|
|
SPELLS_NOTES: dict[int, str] = {
|
|
12: "startuje na 64, SUBAT(12,3) przy każdym awansie — nikt tego nie czyta",
|
|
13: f"DOŚWIADCZENIE, 0..{EXP_PER_LEVEL - 1}; po przekroczeniu progu reszta przechodzi dalej",
|
|
14: "licznik awansów (ile razy klepsydra się przesypała)",
|
|
15: "1 → klepsydra/różdżka widoczna w menu (SHOWEXP, M_WAND)",
|
|
16: "1 → klepsydra miga, można nauczyć się czaru",
|
|
}
|
|
|
|
#: Indeks doświadczenia w SPELLS<slot>.ARR.
|
|
EXP_INDEX = 13
|
|
LEVEL_INDEX = 14
|
|
HOURGLASS_VISIBLE_INDEX = 15
|
|
HOURGLASS_BLINKING_INDEX = 16
|
|
|
|
|
|
def describe_spell_index(index: int) -> str:
|
|
if index < len(SPELL_NAMES):
|
|
return f"{SPELL_NAMES[index]} (1 = znany)"
|
|
return SPELLS_NOTES.get(index, "nieznane")
|