7 Commits

Author SHA1 Message Date
markojozsef
54bc6a733a Normális csata formátum dokumentáció
Some checks failed
Build Windows EXE / build (push) Has been cancelled
2026-10-20 17:28:58 +02:00
markojozsef
b5c6b8a79b Kész a felhasználói útmutató
Some checks failed
Build Windows EXE / build (push) Has been cancelled
2026-10-20 17:19:39 +02:00
markojozsef
42673f4ea4 Elírás javítás
Some checks failed
Build Windows EXE / build (push) Has been cancelled
2026-10-20 16:48:37 +02:00
markojozsef
9469108e8d Prezi kész
Some checks failed
Build Windows EXE / build (push) Has been cancelled
2026-10-20 16:44:16 +02:00
markojozsef
c27b882357 Félkész felhasználói útmutató
Some checks failed
Build Windows EXE / build (push) Has been cancelled
2026-10-20 09:19:24 +02:00
markojozsef
2306fd8060 Végső prezentáció 2026-10-20 08:42:10 +02:00
markojozsef
464e706a5c Első 4 hét a preziben
Some checks failed
Build Windows EXE / build (push) Has been cancelled
2026-10-20 08:17:22 +02:00
3 changed files with 377 additions and 419 deletions

View File

@@ -1,444 +1,402 @@
# Csata objektum
# Csataadatok és csatafüggvények technikai leírása
## Szerkezet
Ez a dokumentum a csatamód (`battle` állapot) forráskódja alapján írja le, hogyan kell felépíteni a `battle_data.battles` bejegyzéseit, és milyen argumentumokkal hívódnak az **MI-függvények**, a **képességek/tárgyak függvényei** és az **akcióanimációk**.
```python
{
"enemies": [...],
"party_members": [...],
"enemy_turn_func": ...,
"mus_id": "...",
"init_ai_data": {...},
"menus": [...],
"spells": [...],
"inventory": [...]
}
```
> **Jelölések:** Ami a csatamód forrásából közvetlenül kiolvasható, azt tényként írom le. Ami következtetés, vagy a nem látott fájlokban (`battle.py`, `battle_data.py`, `menu.py`, `text.py`) dől el, azt **[Feltételezés]** vagy **TODO** jelzi.
---
## enemies
## 1. Terminológia
Az ellenséges egységek listája.
A kód belső nevei eltérnek a játékbeli fogalmaktól, ezért érdemes tisztán tartani:
### Típus
| Kód | Játékbeli jelentés | Képernyőpozíció |
|---|---|---|
| `party_members` | A játékos által irányított karakter(ek), vagyis a megszállt főellenfél (és kísérői) | Bal oldal |
| `enemies` | A **hősök**, akik ellen a játékos harcol | Jobb oldal |
| `enemy_turn_func` | A hősök **MI-függvénye** | |
| `battle_id` | A csata azonosítója (a négy csataszoborhoz tartozik) | |
```python
list[Combatant]
```
### Példa
```python
"enemies": [
Combatant("Six-Seven kid", 120, 30, 80, 20, 0, 50, False, False),
Combatant("Ice Sprite", 60, 15, 150, 10, 0, 200, False, True),
]
```
Minden elem egy `Combatant` objektum.
> **TODO:** Melyik `battle_id` melyik szoborhoz tartozik, és ki állítja be az értékét a csata előtt (feltehetően az overworld).
---
## party_members
## 2. A csata betöltése
A játékos által irányított karakterek listája.
A `switch(game)` a `battle_data.battles[battle_id]` bejegyzésből tölti be a csatát. A következő mezők **mély másolatot** (`copy.deepcopy`) kapnak, tehát a csata közbeni módosításaik **nem maradnak meg** a következő csatára, és az újraindítás mindig tiszta állapotot ad:
### Típus
`enemies`, `party_members`, `enemy_turn_func`, `init_ai_data`, `menus`, `spells`, `inventory`.
```python
list[Combatant]
```
A sprite-ok, a háttér és a zene **nem** másolódnak, csak hivatkozás történik rájuk.
### Példa
```python
"party_members": [
Combatant("Locke", 80, 45, 130, 15, 10, 10, False, False),
Combatant("Terra", 100, 35, 100, 30, 30, 30, False, False),
]
```
A lista sorrendje határozza meg:
- a karakter pozícióját a csatában,
- a menük hozzárendelését,
- a varázslatok hozzárendelését.
> **Fontos:** Mivel a másolat készül, az MI-függvények és képességfüggvények mindig a nekik **átadott** objektumokkal dolgozzanak, ne a `battle_data` modulban lévő eredetikre hivatkozzanak (pl. egy zárványon (closure) keresztül). Különben az eredeti, nem a csatában résztvevő példány módosulna. A `damage_callback` is csak olyan célponttal ad helyes pozíciót, amely a **jelenlegi** `enemies` vagy `party_members` listában van, különben a szám a `(0, 0)` pozícióban jelenik meg.
---
## enemy_turn_func
## 3. A `battle_data.battles[battle_id]` szerkezete
Az ellenséges köröket kezelő függvény.
Egy bejegyzés egy szótár (dict) a következő kulcsokkal:
### Típus
| Kulcs | Típus | Leírás |
|---|---|---|
| `"enemies"` | `list[Combatant]` | A hősök listája |
| `"party_members"` | `list[Combatant]` | A játékos által irányított karakterek listája |
| `"enemy_turn_func"` | függvény | A hősök MI-függvénye (lásd 8. fejezet) |
| `"init_ai_data"` | másolható objektum (általában `dict`) | Az MI kezdeti állapota, a csata elején másolódik |
| `"menus"` | `list[list[tuple[str, str]]]` | Karakterenkénti parancsmenük (lásd 5. fejezet) |
| `"spells"` | `list[list[tuple]]` | Karakterenkénti képességlisták (lásd 6. fejezet) |
| `"inventory"` | `list[list]` | A csatában használható tárgyak, **közösek** (lásd 7. fejezet) |
| `"enemy_sprites"` | `list[list[azonosító]]` | Hősönként 3 sprite-azonosító (lásd 11. fejezet) |
| `"party_sprites"` | `list[list[azonosító]]` | Karakterenként 3 sprite-azonosító |
| `"background"` | azonosító | Kulcs az `assets.sprites` szótárba |
| `"mus_id"` | azonosító | Kulcs az `assets.sounds` szótárba, a zene ismétlődve (`loops=True`) szól |
A `menus`, `spells`, `party_sprites` listák **indexe a `party_members` indexével egyezik**. Az `enemy_sprites` indexe az `enemies` indexével egyezik.
A csatát a `battle_data.battles[battle_id]` alapján választja ki a rendszer. A `battles` tehát olyan tároló, amely a `battle_id` értékkel indexelhető.
### Váz példa
```python
callable
```
### Példa
```python
"enemy_turn_func": enemy_turn_test
```
A függvényt a rendszer az ellenfelek körének feldolgozására használja.
---
## mus_id
A csata alatt lejátszandó zene azonosítója.
### Típus
```python
str
```
### Példa
```python
"mus_id": "mus_fnafsux"
```
---
## init_ai_data
Az MI számára átadott inicializáló adatok.
### Típus
```python
dict
```
---
### moves
Az MI által használható képességek gyűjteménye.
#### Típus
```python
dict[str, tuple]
```
#### Formátum
```python
"azonosító": (
név,
függvény,
célpont_szükséges
)
```
#### Paraméterek
- `név` (`str`)
A képesség megjelenő neve.
- `függvény` (`callable`)
A végrehajtandó függvény.
- `célpont_szükséges`
- `True` → ellenséges célpont szükséges
- `False` → szövetséges célpont szükséges
- `None` → nincs célpont
#### Példa
```python
"attack": (
"Physical attack",
move_attack,
True
)
```
---
### Teljes példa
```python
"moves": {
"attack": ("Physical attack", move_attack, True),
"fire": ("Fira", move_fire, True),
"ice": ("Blizzara", move_ice, True),
"cure": ("Cure", move_cure, False),
"defend": ("Defend", move_defend, None)
}
```
---
## menus
Karakterenként meghatározza a harci főmenüt.
### Típus
```python
list[list]
```
A külső lista a karaktereket reprezentálja.
A sorrendnek meg kell egyeznie a `party_members` listával.
---
### Egy karakter menüje
```python
[
["Attack", "phys_att"],
["Magic", "magic"],
["Item", "items"]
]
```
---
### Menüpont formátuma
```python
[
megjelenő_szöveg,
parancs
]
```
#### Paraméterek
- `megjelenő_szöveg` (`str`)
- `parancs` (`str`)
---
### Speciális parancsok
#### Fizikai támadás
```python
["Attack", "phys_att"]
```
#### Mágia
```python
["Magic", "magic"]
```
#### Tárgyak
```python
["Item", "items"]
```
#### Nem választható hely
```python
["", "unselectable"]
```
Ez egy üres, nem kiválasztható menüpont.
---
## spells
Karakterenként meghatározza az elérhető varázslatokat.
### Típus
```python
list[list]
```
A lista sorrendje megegyezik a `party_members` sorrendjével.
---
### Varázslat formátuma
```python
[
név,
mp_költség,
(
név,
függvény,
célpont_szükséges
)
]
```
#### Paraméterek
- `név` (`str`)
A varázslat megjelenő neve.
- `mp_költség` (`int`)
A varázslat MP költsége.
- `akció` (`tuple`)
A végrehajtandó harci művelet.
---
### Példa
```python
[
"Fira",
15,
("Fira", move_fire, True)
]
```
---
### Teljes példa
```python
"spells": [
[],
[
["Fira", 0, ("Fira", move_fire, True)],
["Blizzara", 0, ("Blizzara", move_ice, True)]
],
[
["Fira", 0, ("Fira", move_fire, True)],
["Blizzara", 0, ("Blizzara", move_ice, True)]
],
[]
]
```
Ebben az esetben:
- Locke nem rendelkezik varázslatokkal,
- Terra használhatja a **Fira** és **Blizzara** varázslatokat,
- Celes használhatja a **Fira** és **Blizzara** varázslatokat,
- Cyan nem rendelkezik varázslatokkal.
---
## inventory
A csatában használható tárgyak listája.
### Típus
```python
list
```
---
### Tárgy formátuma
```python
[
név,
mennyiség,
(
név,
függvény,
célpont_szükséges
)
]
```
#### Paraméterek
- `név` (`str`)
A tárgy megjelenő neve.
- `mennyiség` (`int`)
A rendelkezésre álló darabszám.
- `akció` (`tuple`)
A tárgy használatakor meghívandó művelet.
---
### Példa
```python
[
"Phoenix Down",
67,
(
"Phoenix Down",
move_phoenix,
False
)
]
```
---
### Teljes példa
```python
"inventory": [
[
"Phoenix Down",
67,
(
"Phoenix Down",
move_phoenix,
False
)
]
]
```
---
## Indexkapcsolatok
A következő listák indexei összetartoznak:
```python
party_members[i]
menus[i]
spells[i]
```
Példa:
```python
party_members[1] # Terra
menus[1] # Terra menüje
spells[1] # Terra varázslatai
```
Ez biztosítja, hogy minden karakter saját menüvel és saját varázslistával rendelkezzen.
---
## Összefoglaló
```python
{
"enemies": list[Combatant],
"party_members": list[Combatant],
"enemy_turn_func": callable,
"mus_id": str,
"init_ai_data": {
"moves": dict[str, tuple]
battles = [
{
"enemies": [Combatant(...), Combatant(...)],
"party_members": [Combatant(...)],
"enemy_turn_func": hero_ai_1,
"init_ai_data": {"turn": 0},
"menus": [
[("Támadás", "phys_att"), ("Varázslat", "magic"), ("Tárgyak", "items")],
],
"spells": [
[("Tűzgolyó", 5, ("Tűzgolyó", fireball, "ene"))],
],
"inventory": [
["Gyógyital", 3, ("Gyógyital", use_potion, "ally")],
],
"enemy_sprites": [
["hero1_normal", "hero1_hurt", "hero1_ko"],
["hero2_normal", "hero2_hurt", "hero2_ko"],
],
"party_sprites": [
["boss1_normal", "boss1_hurt", "boss1_ko"],
],
"background": "bg_arena_1",
"mus_id": "mus_battle_1",
},
"menus": list[list],
"spells": list[list],
"inventory": list
}
# ... további 3 csata
]
```
Egy csata teljes egészében leírható egyetlen szótárral, amely tartalmazza az összes résztvevőt, a harci lehetőségeket, az MI által használható képességeket, valamint a játékos számára elérhető menüket, varázslatokat és tárgyakat.
---
## 4. `Combatant`
A `Combatant` osztály (`battle.py`) konstruktora **nem látható** a csatamód forrásában, ezért itt csak az onnan elérhető attribútumokat sorolom fel:
| Attribútum | Használat a csatamódban |
|---|---|
| `name` | Megjelenített név (menü, célpontválasztó) |
| `hp` | Aktuális életerő (célpontválasztóban kijelzett; sprite-váltás) |
| `maxhp` | Maximális életerő. A 10%-os sprite-váltás küszöbe |
| `ko` | Legyőzött-e (a szereplő nem cselekszik, a célpontválasztóból kimarad) |
| `stone` | Kővé változott-e (nem cselekszik, szürke sprite) |
| `def_up` | Védekezik-e (a célpontválasztóban „Védés” felirat) |
| `atb` | Az akcióig hátralévő időzítő (lásd 9. és 12. fejezet) |
| `attack` | Támadóerő, a „Támadás” parancs ezt adja a `Damage`-nek |
> **TODO:** A `Combatant` konstruktorának paraméterei és sorrendje, a kezdő `atb` értékek, további mezők (pl. MP, sebesség).
---
## 5. Menük (`menus`)
Karakterenként egy lista, amelynek elemei `(felirat, művelet)` párok:
```python
("Támadás", "phys_att")
```
A `művelet` értéke a `menu_action` függvényben kerül feldolgozásra:
| Művelet | Hatás |
|---|---|
| `"phys_att"` | Célpontválasztó (`"ene"`), majd egy `Action("Támadás", user, target, Damage(user.attack, 0, 0, 0), StatusChange(0, 0, 0), battle_data.anim_default)` kerül a sorba |
| `"magic"` | Megnyitja a képességmenüt (`spells[karakter_index]`) |
| `"items"` | Megnyitja a tárgymenüt (`inventory`) |
| `"unselectable"` | Nem csinál semmit, a kijelölés a menüben marad |
| *bármi más* | Kiírja az `Unknown action` hibát a konzolra, és **bezárja a menüt** (lásd 12. fejezet) |
A menüpontok `x = 19`, `y = 64 - i * 13` pozícióban jelennek meg, ez a menüpanelen belül **legfeljebb 5 sort** jelent (lásd 12. fejezet).
---
## 6. Képességek (`spells`)
Karakterenként egy lista, amelynek elemei:
```python
(név, mp_költség, (akció_név, függvény, célpont_típus))
```
| Elem | Leírás |
|---|---|
| `név` | A képességmenüben megjelenő felirat |
| `mp_költség` | A kódban kicsomagolódik, de a csatamód **nem használja** (nem ellenőrzi, nem vonja le) |
| `akció_név` | A kódban kicsomagolódik, de a csatamód **nem használja** |
| `függvény` | `függvény(user, target) -> Action`. Lásd lent |
| `célpont_típus` | Lásd 8. fejezet |
A kiválasztott célpont után a csatamód ezt hívja:
```python
action_queue.append(függvény(user, targets[0]))
```
Vagyis a függvény két argumentumot kap: **a cselekvő karaktert** és **a kiválasztott egyetlen célpontot**, és egy `Action` objektumot kell visszaadnia.
> **TODO:** Az MP-költség levonása és ellenőrzése. A csatamódban nincs ilyen, tehát vagy az `Action`/animáció végzi, vagy még nincs megvalósítva.
---
## 7. Tárgyak (`inventory`)
Egyetlen, a csata összes karaktere által **közösen** használt lista. Elemei **módosítható listák** (nem tuple-ök, mert a mennyiség csökken):
```python
[név, mennyiség, (akció_név, függvény, célpont_típus)]
```
| Elem | Leírás |
|---|---|
| `név` | A menüben `név xMENNYISÉG` formában jelenik meg (pl. `Gyógyital x3`) |
| `mennyiség` | `int`. A 0 vagy kisebb értékű tárgyak nem jelennek meg |
| `függvény` | Ugyanaz, mint a képességeknél: `függvény(user, target) -> Action` |
| `célpont_típus` | Lásd 8. fejezet |
A mennyiség **a kiválasztáskor** (az akció sorba állításakor) csökken eggyel, nem a végrehajtáskor.
---
## 8. Célpont-típusok
Az `open_target_menu(user, aparty, eparty, target_type, on_pick, back)` a `target_type` alapján állítja össze a választható célpontokat.
> **Dokumentáció és kód eltérése:** A függvény docstringje az `"enemy"`, `"ally"`, `"self"`, `"all_enemies"`, `"all_allies"` értékeket említi, de a tényleges kód más szavakat vizsgál. **A kód a mérvadó.**
| `target_type` | Célpont-lista | Legyőzöttek? | Megjegyzés |
|---|---|---|---|
| `"self"` | A cselekvő maga | Nem releváns | Nincs célpontválasztó, a menü azonnal bezárul |
| `"ene"` | `eparty` (a hősök) | Kimaradnak | A „Támadás” is ezt használja |
| `"ene_rev"` | `eparty` | **Benne vannak** | |
| `"all_rev"` | `aparty` (a saját oldal) | **Benne vannak** | Újraélesztő képességekhez |
| *bármilyen más szöveg* | `aparty` (a saját oldal) | Kimaradnak | Pl. `"ally"` ide esik |
További tudnivalók:
- Az `aparty` a játékos oldala (`party_members`), az `eparty` a hősöké (`enemies`).
- Ha nincs választható célpont, a függvény visszatér, és az előző menü marad nyitva.
- A célpont-visszahívás (`on_pick`) **mindig egyelemű listát** kap, így a csatamód többcélpontos kijelölést **nem támogat**. A célpontválasztó listája a célpont nevét és az aktuális életerejét mutatja, kiegészítve a `Kő` és `Védés` állapotokkal.
- Ha területi hatást akarsz, azt a függvénynek/animációnak kell kezelnie. **TODO:** A függvény csak a `user` és `target` argumentumot kapja, így a többi szereplő eléréséhez a modul szintű listákra (`battle.enemies`, `battle.party_members`) lenne szükség. Ennek a tervezett módja még tisztázandó.
---
## 9. Az MI-függvény (`enemy_turn_func`)
### Aláírás
```python
def hero_ai(e, enemies, party_members, ai_data):
...
return Action(...) # vagy None
```
| Argumentum | Tartalom |
|---|---|
| `e` | A cselekvésre kész hős (`Combatant`) |
| `enemies` | A hősök (saját oldal) listája |
| `party_members` | A játékos karaktereinek listája (az ellenfél, az MI szemszögéből) |
| `ai_data` | A `init_ai_data` csatánkénti másolata. Az MI ebben tárolhat állapotot (pl. számlálót) |
**Visszatérési érték:**
- **`Action`** (vagy bármi igaz értékű): az akció a sor végére kerül, és a hős `atb` értéke `math.inf` lesz.
- **`None` / hamis érték:** a hős nem csinál semmit **ebben a képkockában**, és az MI-függvény **a következő képkockában újra meghívódik**, amíg nem ad vissza akciót. Ez lehetővé teszi, hogy az MI egy feltételre várjon.
### Mikor hívódik?
A függvény minden képkockában (`update`) meghívódik azokra a hősökre, akik:
1. nincsenek legyőzve és nincsenek kővé változva (`not ko and not stone`), és
2. az `atb` értékük `<= 0`.
Minden képkockában minden hős `atb`-ja eggyel csökken (**képkockafüggő**, nem `dt`-alapú. Lásd 12. fejezet).
### Példa
```python
def hero_ai_1(e, enemies, party_members, ai_data):
targets = [p for p in party_members if not p.ko and not p.stone]
if not targets:
return None
ai_data["turn"] += 1
target = random.choice(targets)
return Action(
"Támadás", e, target,
Damage(e.attack, 0, 0, 0), StatusChange(0, 0, 0),
battle_data.anim_default,
)
```
---
## 10. Az `Action` és az akcióanimáció
### Az `Action` felépítése
A kódban látható hívás alapján:
```python
Action(név, user, target, damage, status_change, animation)
```
| Argumentum | Leírás |
|---|---|
| `név` | Az akció neve (a képernyő alján megjelenő panelhez) |
| `user` | A cselekvő `Combatant` |
| `target` | A célpont `Combatant` |
| `damage` | `Damage(a, b, c, d)`. Az első érték a támadásnál a `user.attack` |
| `status_change` | `StatusChange(a, b, c)`. A „Támadás” csupa nullát ad |
| `animation` | Az animációs függvény (lásd lent) |
A csatamód közvetlenül **csak az `animation` mezőt** olvassa. A többi attribútum nevét (pl. `action.user`, `action.target`) az animációknak kell ismerniük.
> **TODO:** Az `Action`, `Damage`, `StatusChange` pontos attribútumnevei és mezőinek jelentése (a `Damage` és `StatusChange` további paraméterei). Ezek a `battle.py`-ban vannak.
> **TODO:** A `battle_data.anim_default` működése.
### Az animációs függvény aláírása
```python
def animation(action, action_text, timer, dt, damage_callback) -> bool:
...
```
| Argumentum | Tartalom |
|---|---|
| `action` | Az éppen futó `Action` objektum |
| `action_text` | A `TextRenderer(122, 204, None, True)` példány, az akciópanel szövege |
| `timer` | Az animáció kezdete óta eltelt idő másodpercben. Az **első híváskor pontosan `0`** |
| `dt` | Az előző képkocka óta eltelt idő |
| `damage_callback` | `damage_callback(amount, target)`. Lebegő szám létrehozása (lásd lent) |
**Visszatérési érték:**
- **`True`**: az animáció véget ért. A csatamód törli az aktuális akciót, és elrejti az akciópanelt.
- **`False`**: az animáció még fut. A `timer` a `dt`-vel nő, és a következő képkockában újra hívódik.
Az akciópanel (`action_panel`) a teljes animáció ideje alatt látható, de az `action_text` szövegét **az animációnak kell beállítania** (pl. `action_text.reset(...)`, `type_all()`), ahogy a menü szövegét is a csatamód teszi a menüben. Az `action_text.render()` minden képkockában lefut, még ha a panel rejtett is, ezért az animáció végén érdemes **kiüríteni a szöveget** (`action_text.reset("")`) **[Feltételezés]**.
### `damage_callback(amount, target)`
| Paraméter | Jelentés |
|---|---|
| `amount` | **Negatív** szám = sebzés (**fehér** számként, előjel nélkül jelenik meg). **Nem negatív** szám = gyógyulás (**zöld** szám) |
| `target` | A célpont `Combatant`. A szám a sprite pozíciója fölött jelenik meg (a `sprite_pos(target)` alapján) |
A callback **csak a lebegő számot** hozza létre. A HP tényleges módosítása és a `ko` beállítása **nem itt** történik, ezeket az animációnak/akciónak kell elvégeznie **[Feltételezés]**.
A lebegő szám 0,5 másodpercig él, és képkockánként `(0, 0.4)` értékkel mozog felfelé.
### Példa (szemléltető jellegű)
```python
def anim_example(action, action_text, timer, dt, damage_callback):
# Első képkocka: szöveg kiírása
if timer == 0:
action_text.reset(action.name) # [Feltételezés] az attribútum neve
action_text.type_all()
# Egyszeri találat 0,6 mp-nél
if timer >= 0.6 and not getattr(action, "_hit", False):
action._hit = True
action.target.hp -= 5 # [Feltételezés] a HP-módosítás az animáció dolga
damage_callback(-5, action.target)
# Vége 1,2 mp-nél
if timer >= 1.2:
action_text.reset("")
return True
return False
```
---
## 11. Egy akció életciklusa
A `update(game, dt)` minden képkockában a következő sorrendben fut:
1. **Hősök időzítője:** minden él(ő), nem kővé vált hősnél `atb -= 1`. Ha `atb <= 0`, meghívódik az `enemy_turn_func`. Ha akciót ad vissza, az a sorba kerül, és `atb = math.inf`.
2. **Játékos karaktereinek időzítője:** ugyanígy `atb -= 1`. Ha `atb <= 0`, a karakter a `menu_queue`-ba kerül, és `atb = math.inf`.
3. **Következő akció indítása:** ha az `action_queue` nem üres és nincs futó akció, az első elem lesz az aktuális (`cur_action`), az akciópanel megjelenik, `action_timer = 0`.
4. **Futó akció léptetése:** `cur_action.animation(...)` meghívása. `True` esetén vége az akciónak, különben `action_timer += dt`.
5. **Menü megnyitása:** ha van várakozó karakter és nincs nyitott menü, megnyílik a következő karakter menüje. A szöveg: „*név* menüje”.
6. **Menüpontok és lebegő számok frissítése.**
7. **Győzelem ellenőrzése:** ha az összes hős `ko` vagy `stone`, a zene megáll, és a játék átvált az `"overworld"` állapotra.
8. **Vereség ellenőrzése:** ha a játékos összes karaktere `ko` vagy `stone`, a zene megáll, és a játék átvált a `"gameover"` állapotra.
A győzelem-ellenőrzés **a vereségé előtt** fut, ezért ha mindkét feltétel egyszerre teljesül, a játékos nyer.
---
## 12. Elrendezés és sprite-ok
### Pozíciók
| Szereplő | Pozíció (képernyőpont) |
|---|---|
| Hős (`i`. index) | `(185, 175 - i * 20)` |
| Játékos karaktere (`i`. index) | `(40 + (i % 2) * 30, 165 - i * 25)` |
A sprite-ok **középpontja** ezen a ponton van. A pozíciók a lista sorrendjét követik. Az alsó menüpanel `230 × 100` méretű, ezért a lista végén lévő szereplők a panel mögé/fölé kerülhetnek (hősöknél kb. a 4. index után, a játékos karaktereinél kb. a 3. index után).
### Három sprite az állapotokhoz
Az `enemy_sprites[i]` és `party_sprites[i]` **pontosan 3 azonosítót** tartalmaz, ebben a sorrendben:
| Index | Mikor látszik |
|---|---|
| `[0]` | Normál állapot |
| `[1]` | Ha `hp <= maxhp * 0.1` (sebzett) |
| `[2]` | Ha `ko` igaz (a KO sprite elsőbbséget élvez) |
Ha a szereplő `stone` állapotban van (és nem `ko`), akkor az éppen kiválasztott sprite **szürkeárnyalatos** változata látszik. A szürke változatot a csatamód létrehozza és gyorsítótárazza.
Az azonosítók az `assets.sprites` szótár kulcsai. Az asset lehet közvetlenül textúra, vagy lehet `.texture` attribútuma.
---
## 13. Ismert korlátok és buktatók
Ezeket a csatamód forrásából olvastam ki. Érdemes őket a csatatervezés közben szem előtt tartani.
1. **Üres képesség- vagy tárgymenü beragadást okoz.** Az `open_spell_menu` és az `open_item_menu` először kiüríti a `menu` listát, és csak utána ellenőrzi, hogy van-e elem. Ha nincs (pl. egy karakternek nincs képessége, vagy elfogytak a tárgyak), a menü üres marad, a `menu_open` pedig nem nullázódik, így a csata ettől a karaktertől kezdve **megakadhat**. Ezért:
- ne szerepeljen `"magic"` a menüben, ha a karakternek nincs képessége,
- ne szerepeljen `"items"`, ha nincs tárgy a csatában, vagy gondoskodni kell róla, hogy a tárgyak ne fogyjanak el.
2. **Ismeretlen menüművelet elveszíti a kört.** A `menu_action` az ismeretlen értéknél bezárja a menüt (`close_menu()`), ezért a karakter `atb` értéke `math.inf` marad, és **nem fog újra cselekedni**, hacsak más nem állítja vissza.
3. **Az `atb` visszaállítása nem a csatamódban történik.** A csatamód az akciók sorba állításakor `math.inf`-re állítja az `atb`-t, de újra nem tölti fel. Ezért az akcióknak/animációknak kell a `user.atb` értékét pozitív számra visszaállítani a végrehajtás után **[Feltételezés, ellenőrizendő a `battle.py`-ban]**. Ha ez elmarad, a karakter többé nem cselekszik.
4. **Az `atb` képkockafüggő.** Az `atb -= 1` minden `update` híváskor lefut, nem a `dt`-től függ. A csata sebessége így a frissítési gyakoriságtól függ.
5. **Legfeljebb 5 menüsor fér el.** A menüpontok `y = 64 - i * 13` pozícióban vannak. A 6. elem már a képernyőn kívülre esik. Ez a képesség-, tárgy- és célpontlistára egyaránt vonatkozik.
6. **Nincs ellenőrzés az akció végrehajtásakor.** A sorba állított akció akkor is lefut, ha közben a cselekvő vagy a célpont legyőzötté vált. Az animációnak/akciónak kell kezelnie ezt az esetet **[Feltételezés]**.
7. **Többcélpontos akció nincs.** A célpontválasztás mindig egyetlen célpontot ad át.
8. **Az MP nem érvényesül** a csatamódban (lásd 6. fejezet).
---
## 14. Nyitott kérdések (TODO)
- A `Combatant`, `Action`, `Damage`, `StatusChange` osztályok teljes definíciója (`battle.py`).
- A `battle_data.anim_default` és az egyéb beépített animációk működése.
- Az `atb` újratöltésének helye és értékei.
- A HP-módosítás, a `ko`, `stone`, `def_up` állapotok beállításának helye.
- Az MP-rendszer megléte és működése.
- A `TextRenderer` és `MenuItem` pontos API-ja (a csatamódban használt hívások: `reset`, `type_all`, `move`, `render`, `select`, `update`).
- A `battle_id` és a csataszobrok összerendelése.

Binary file not shown.

BIN
userguide.odt Normal file

Binary file not shown.