Compare commits
8 Commits
eb57b16544
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b77b110eb9 | ||
|
|
d8ed2afa60 | ||
|
|
68a8e44388 | ||
|
|
2a29f318b4 | ||
|
|
7ac1a8259f | ||
|
|
75fc03a88d | ||
|
|
4de57827b0 | ||
|
|
b30a7c291b |
305
bullshit.py
305
bullshit.py
@@ -1,305 +0,0 @@
|
||||
import math
|
||||
|
||||
K_NORMAL = 100
|
||||
K_DEFUP = 50
|
||||
MIN_DMG = 1
|
||||
|
||||
class Combatant:
|
||||
def __init__(self, name, maxhp, attack, speed, def_phys, def_fire, def_ice, abs_fire, abs_ice):
|
||||
self.name = name
|
||||
self.max_atb = 1000/speed
|
||||
self.atb = self.max_atb
|
||||
self.maxhp = maxhp
|
||||
self.hp = maxhp
|
||||
self.attack = attack
|
||||
self.ko = False
|
||||
self.stone = False
|
||||
self.def_up = False
|
||||
self.def_phys = def_phys
|
||||
self.def_fire = def_fire
|
||||
self.def_ice = def_ice
|
||||
self.abs_fire = abs_fire
|
||||
self.abs_ice = abs_ice
|
||||
|
||||
# POTENTIAL damage before defense effects
|
||||
class Damage:
|
||||
def __init__(self, phys, fire, ice, healing):
|
||||
self.phys= phys
|
||||
self.fire= fire
|
||||
self.ice= ice
|
||||
self.healing = healing
|
||||
|
||||
# 0 = keep, 1 = inflict, 2 = remove
|
||||
class StatusChange:
|
||||
def __init__(self, ko, stone, def_up):
|
||||
self.ko = ko
|
||||
self.stone = stone
|
||||
self.def_up = def_up
|
||||
|
||||
# where = reference to the target, who = reference to the inflictor
|
||||
class Action:
|
||||
def __init__(self, name, who, where, damage, status):
|
||||
self.name = name
|
||||
self.who = who
|
||||
self.where = where
|
||||
self.damage = damage
|
||||
self.status = status
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
f"[{self.name}] {self.who.name} -> {self.where.name} "
|
||||
f"(HP influence: ({self.damage.phys},{self.damage.fire},{self.damage.ice},{self.damage.healing}), Status: {self.status.ko}-{self.status.stone}-{self.status.def_up})"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def execute(self):
|
||||
target = self.where
|
||||
if self.who.ko or self.who.stone:
|
||||
print(f" -> {self.who.name} cannot move!")
|
||||
return
|
||||
|
||||
self.who.atb = self.who.max_atb
|
||||
|
||||
if target.ko and self.status.ko != 2:
|
||||
print(f" -> {target.name} is KO'd, move cancelled!")
|
||||
return
|
||||
|
||||
K = K_DEFUP if target.def_up else K_NORMAL
|
||||
|
||||
delta_hp = self.damage.healing
|
||||
|
||||
if self.damage.phys:
|
||||
delta_hp += -max(MIN_DMG, self.damage.phys * (K / (K + target.def_phys)))
|
||||
|
||||
if self.damage.fire:
|
||||
delta_hp += self.damage.fire if target.abs_fire else -max(MIN_DMG, self.damage.fire * (K / (K + target.def_fire)))
|
||||
|
||||
if self.damage.ice:
|
||||
delta_hp += self.damage.ice if target.abs_ice else -max(MIN_DMG, self.damage.ice * (K / (K + target.def_ice )))
|
||||
|
||||
if self.status.ko == 1:
|
||||
delta_hp = -target.hp
|
||||
elif self.status.ko == 2 and target.ko:
|
||||
target.ko = False
|
||||
print(f" -> {target.name}'s consciousness returned!")
|
||||
|
||||
delta_hp = round(delta_hp)
|
||||
|
||||
if delta_hp > 0:
|
||||
print(f" -> {target.name} got healed for {delta_hp} HP!")
|
||||
elif delta_hp < 0:
|
||||
print(f" -> {target.name} suffered {-delta_hp} damage!")
|
||||
|
||||
target.hp = max(0, min(target.maxhp, target.hp + delta_hp))
|
||||
|
||||
if self.status.stone == 1 and not target.stone:
|
||||
target.stone = True
|
||||
print(f" -> {target.name}'s body petrified!")
|
||||
elif self.status.stone == 2 and target.stone:
|
||||
target.stone = False
|
||||
print(f" -> {target.name}'s body softened back up!")
|
||||
|
||||
if self.status.def_up == 1 and not target.def_up:
|
||||
target.def_up = True
|
||||
print(f" -> {target.name}'s defense was boosted!")
|
||||
elif self.status.def_up == 2 and target.def_up:
|
||||
target.def_up = False
|
||||
print(f" -> {target.name}'s defense returned to normal!")
|
||||
|
||||
if target.hp == 0:
|
||||
target.ko = True
|
||||
target.stone = False
|
||||
target.def_up = False
|
||||
print(f" -> {target.name} got hurt and collapsed!")
|
||||
|
||||
# !!! CHATGPT !!! CSAK TESZT !!!
|
||||
enemies = [
|
||||
# name hp atk spd dphys dfire dice absF absI
|
||||
Combatant("Six-Seven kid", 120, 30, 80, 20, 0, 50, False, False),
|
||||
Combatant("Ice Sprite", 60, 15, 150, 10, 0, 200, False, True ), # ice-immune, fast, fragile
|
||||
Combatant("Magma Brute", 200, 40, 40, 60, 999, -50, True, False), # absorbs fire, weak to ice, slow tank
|
||||
]
|
||||
|
||||
party_members = [
|
||||
# name hp atk spd dphys dfire dice absF absI
|
||||
Combatant("Terra", 100, 35, 100, 30, 30, 30, False, False),
|
||||
Combatant("Locke", 80, 45, 130, 15, 10, 10, False, False), # glass cannon, fast, low def
|
||||
Combatant("Celes", 110, 25, 90, 50, 40, 40, False, False), # tanky
|
||||
Combatant("Cyan", 130, 38, 70, 40, 20, 20, False, False),
|
||||
]
|
||||
|
||||
tick_counter = 0
|
||||
action_queue = []
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Move library — a spread of physical/elemental/status/healing effects
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def move_attack(user, target):
|
||||
return Action("Attack", user, target, Damage(user.attack, 0, 0, 0), StatusChange(0, 0, 0))
|
||||
|
||||
def move_fire(user, target):
|
||||
return Action("Fira", user, target, Damage(0, 45, 0, 0), StatusChange(0, 0, 0))
|
||||
|
||||
def move_ice(user, target):
|
||||
return Action("Blizzara", user, target, Damage(0, 0, 45, 0), StatusChange(0, 0, 0))
|
||||
|
||||
def move_cure(user, target):
|
||||
return Action("Cure", user, target, Damage(0, 0, 0, 42), StatusChange(0, 0, 0))
|
||||
|
||||
def move_defend(user, target):
|
||||
return Action("Defend", user, target, Damage(0, 0, 0, 0), StatusChange(0, 0, 1))
|
||||
|
||||
def move_break(user, target):
|
||||
return Action("Break", user, target, Damage(0, 0, 0, 0), StatusChange(0, 1, 0))
|
||||
|
||||
def move_death(user, target):
|
||||
return Action("Death", user, target, Damage(0, 0, 0, 0), StatusChange(1, 0, 0))
|
||||
|
||||
def move_phoenix(user, target):
|
||||
# revive w/ modest healing; execute() floors it at +1 HP if this isn't enough
|
||||
return Action("Phoenix Down", user, target, Damage(0, 0, 0, 30), StatusChange(2, 0, 0))
|
||||
|
||||
def move_softenup(user, target):
|
||||
return Action("Esuna (remove stoneskin)", user, target, Damage(0, 0, 0, 0), StatusChange(2, 0, 0))
|
||||
|
||||
MOVES = {
|
||||
"attack": ("Physical attack", move_attack, True),
|
||||
"fire": ("Fira (fire magic)", move_fire, True),
|
||||
"ice": ("Blizzara (ice magic)", move_ice, True),
|
||||
"cure": ("Cure (heal ally)", move_cure, False),
|
||||
"defend": ("Defend (self def_up)", move_defend, None), # self-only, forced
|
||||
"break": ("Break (inflict stone)", move_break, True),
|
||||
"death": ("Death (instant KO)", move_death, True),
|
||||
"phoenix": ("Phoenix Down (revive ally)",move_phoenix, False),
|
||||
"unstone": ("Esuna (cure stone)", move_softenup,False),
|
||||
}
|
||||
|
||||
HELP_TEXT = (
|
||||
"\nAvailable moves:\n" +
|
||||
"\n".join(f" {k:8s} - {v[0]}" for k, v in MOVES.items()) +
|
||||
"\n help - show this list\n"
|
||||
)
|
||||
|
||||
|
||||
def choose_target(user, candidates, prompt):
|
||||
alive = [c for c in candidates]
|
||||
print(prompt)
|
||||
for i, c in enumerate(alive):
|
||||
tags = []
|
||||
if c.ko: tags.append("KO")
|
||||
if c.stone: tags.append("STONE")
|
||||
if c.def_up: tags.append("DEF_UP")
|
||||
tagstr = f" [{', '.join(tags)}]" if tags else ""
|
||||
print(f" {i}: {c.name} ({c.hp}/{c.maxhp} HP){tagstr}")
|
||||
while True:
|
||||
raw = input("Target #: ").strip()
|
||||
if raw.isdigit() and 0 <= int(raw) < len(alive):
|
||||
return alive[int(raw)]
|
||||
print("Invalid target index.")
|
||||
|
||||
|
||||
def player_turn(p):
|
||||
print(f"\n{p.name} is ready to act! ({p.hp}/{p.maxhp} HP, def_up={p.def_up}, stone={p.stone})")
|
||||
while True:
|
||||
act = input("Action (or 'help'): ").strip().lower()
|
||||
if act == "help":
|
||||
print(HELP_TEXT)
|
||||
continue
|
||||
if act not in MOVES:
|
||||
print("Unknown move. Type 'help' for the list.")
|
||||
continue
|
||||
|
||||
label, builder, needs_enemy_target = MOVES[act]
|
||||
|
||||
if act == "defend":
|
||||
return builder(p, p)
|
||||
|
||||
if needs_enemy_target is True:
|
||||
target = choose_target(p, enemies, "Choose an enemy target:")
|
||||
elif needs_enemy_target is False:
|
||||
target = choose_target(p, party_members, "Choose a party target:")
|
||||
else:
|
||||
target = p
|
||||
|
||||
return builder(p, target)
|
||||
|
||||
|
||||
import random
|
||||
|
||||
def enemy_turn(e):
|
||||
living = [p for p in party_members if not p.ko]
|
||||
if not living:
|
||||
return None
|
||||
|
||||
# weighted move pool -- enemies get the same toolkit as the party
|
||||
offensive = ["attack", "fire", "ice", "death"]
|
||||
support = ["break"]
|
||||
self_only = ["defend"]
|
||||
|
||||
# if an ally is KO'd, occasionally try to revive/cure instead of attacking
|
||||
ko_allies = [a for a in enemies if a.ko and a is not e]
|
||||
hurt_allies = [a for a in enemies if not a.ko and a.hp < a.maxhp]
|
||||
|
||||
roll = random.random()
|
||||
|
||||
if ko_allies and roll < 0.15:
|
||||
act = "phoenix"
|
||||
target = random.choice(ko_allies)
|
||||
elif hurt_allies and roll < 0.30:
|
||||
act = "cure"
|
||||
target = random.choice(hurt_allies)
|
||||
elif not e.def_up and roll < 0.40:
|
||||
act = "defend"
|
||||
target = e
|
||||
elif roll < 0.55:
|
||||
act = "break"
|
||||
target = random.choice(living)
|
||||
elif roll < 0.65:
|
||||
act = "death"
|
||||
target = random.choice(living)
|
||||
else:
|
||||
act = random.choice(["attack", "fire", "ice"])
|
||||
target = random.choice(living)
|
||||
|
||||
_, builder, _ = MOVES[act]
|
||||
print(f" ({e.name} chooses {act} -> {target.name})")
|
||||
return builder(e, target)
|
||||
|
||||
|
||||
while True:
|
||||
print(f"\n=== Tick #{tick_counter} ===")
|
||||
|
||||
for e in enemies:
|
||||
if e.ko or e.stone:
|
||||
continue
|
||||
e.atb -= 1
|
||||
if e.atb <= 0:
|
||||
act = enemy_turn(e)
|
||||
if act:
|
||||
action_queue.append(act)
|
||||
|
||||
for p in party_members:
|
||||
if p.ko or p.stone:
|
||||
continue
|
||||
p.atb -= 1
|
||||
if p.atb <= 0:
|
||||
action_queue.append(player_turn(p))
|
||||
|
||||
if len(action_queue) != 0:
|
||||
action = action_queue.pop(0)
|
||||
print(f"Executing: {action}")
|
||||
action.execute()
|
||||
|
||||
if all(e.ko for e in enemies):
|
||||
print("\nVICTORY! all enemies were defeated.")
|
||||
break
|
||||
|
||||
if all(p.ko for p in party_members):
|
||||
print("\nGAME OVER! the party was defeated.")
|
||||
break
|
||||
|
||||
tick_counter += 1
|
||||
|
||||
22
doc/AIHasznalat.md
Normal file
22
doc/AIHasznalat.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# AI használat a kódban
|
||||
|
||||
## Jelző
|
||||
Teljesen AI-generált szakaszokat egy `# !!! CHATGPT !!!` komment jelzi
|
||||
|
||||
## AI generálta komponensek:
|
||||
|
||||
### main.py
|
||||
* Game
|
||||
|
||||
### renderers.py
|
||||
* TextureRenderer
|
||||
* NineSlicesPanel
|
||||
|
||||
### battle_data.py
|
||||
* csata függvények
|
||||
|
||||
### gamestates/battle.py
|
||||
* menük
|
||||
|
||||
## Dokumentáció
|
||||
Ezen a fájlon kívül minden dokumentáció AI generálta.
|
||||
444
doc/CsataFormatum.md
Normal file
444
doc/CsataFormatum.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# Csata objektum
|
||||
|
||||
## Szerkezet
|
||||
|
||||
```python
|
||||
{
|
||||
"enemies": [...],
|
||||
"party_members": [...],
|
||||
"enemy_turn_func": ...,
|
||||
"mus_id": "...",
|
||||
"init_ai_data": {...},
|
||||
"menus": [...],
|
||||
"spells": [...],
|
||||
"inventory": [...]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## enemies
|
||||
|
||||
Az ellenséges egységek listája.
|
||||
|
||||
### Típus
|
||||
|
||||
```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.
|
||||
|
||||
---
|
||||
|
||||
## party_members
|
||||
|
||||
A játékos által irányított karakterek listája.
|
||||
|
||||
### Típus
|
||||
|
||||
```python
|
||||
list[Combatant]
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
---
|
||||
|
||||
## enemy_turn_func
|
||||
|
||||
Az ellenséges köröket kezelő függvény.
|
||||
|
||||
### Típus
|
||||
|
||||
```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]
|
||||
},
|
||||
"menus": list[list],
|
||||
"spells": list[list],
|
||||
"inventory": list
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
225
doc/MenuItem.md
Normal file
225
doc/MenuItem.md
Normal file
@@ -0,0 +1,225 @@
|
||||
# MenuItem
|
||||
|
||||
## Áttekintés
|
||||
|
||||
A `MenuItem` osztály egy játék menürendszerének egyetlen választható elemét reprezentálja. Az osztály kezeli:
|
||||
|
||||
- a menüpont szövegének megjelenítését,
|
||||
- a kijelölést,
|
||||
- a menüpontok közötti navigációt,
|
||||
- a kiválasztáskor meghívandó függvényt (akciót),
|
||||
- valamint a kurzor kirajzolását.
|
||||
|
||||
A menüpontok egy irányított hálózatot alkotnak, ahol minden elem ismeri a szomszédait (`up`, `down`, `left`, `right`).
|
||||
|
||||
---
|
||||
|
||||
## Konstruktor
|
||||
|
||||
```python
|
||||
MenuItem(
|
||||
label,
|
||||
x,
|
||||
y,
|
||||
left,
|
||||
right,
|
||||
up,
|
||||
down,
|
||||
action,
|
||||
data=None,
|
||||
back_func=None
|
||||
)
|
||||
```
|
||||
|
||||
### Paraméterek
|
||||
|
||||
- `label` (`str`)
|
||||
A menüpont megjelenő szövege.
|
||||
|
||||
- `x` (`int`)
|
||||
A menüpont vízszintes pozíciója.
|
||||
|
||||
- `y` (`int`)
|
||||
A menüpont függőleges pozíciója.
|
||||
|
||||
- `left` (`MenuItem | None`)
|
||||
A bal oldali szomszédos menüpont.
|
||||
|
||||
- `right` (`MenuItem | None`)
|
||||
A jobb oldali szomszédos menüpont.
|
||||
|
||||
- `up` (`MenuItem | None`)
|
||||
A felső szomszédos menüpont.
|
||||
|
||||
- `down` (`MenuItem | None`)
|
||||
Az alsó szomszédos menüpont.
|
||||
|
||||
- `action` (`callable`)
|
||||
A menüpont kiválasztásakor meghívandó függvény.
|
||||
|
||||
- `data` (`any`, opcionális)
|
||||
A kiválasztáskor az akciónak átadott adat.
|
||||
|
||||
- `back_func` (`callable`)
|
||||
A menüpont kiválasztásakor meghívandó függvény.
|
||||
|
||||
---
|
||||
|
||||
## Attribútumok
|
||||
|
||||
### Navigáció
|
||||
|
||||
```python
|
||||
self.left
|
||||
self.right
|
||||
self.up
|
||||
self.down
|
||||
```
|
||||
|
||||
A szomszédos menüpontokra mutató referenciák.
|
||||
|
||||
Ha egy adott irányban nincs további menüpont, akkor az attribútum értéke:
|
||||
|
||||
```python
|
||||
None
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Akció
|
||||
|
||||
```python
|
||||
self.action
|
||||
```
|
||||
|
||||
A kiválasztás során meghívandó függvény.
|
||||
|
||||
Példa:
|
||||
|
||||
```python
|
||||
def start_game(data):
|
||||
print("Játék indul!")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Vissza
|
||||
|
||||
```python
|
||||
self.back
|
||||
```
|
||||
|
||||
A visszalépés során meghívandó függvény.
|
||||
|
||||
Példa:
|
||||
|
||||
```python
|
||||
def vissza(data):
|
||||
open_menu()
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Adat
|
||||
|
||||
```python
|
||||
self.data
|
||||
```
|
||||
|
||||
A menüelemhez kapcsolódó opcionális adat, amelyet az akció- és visszafüggvény paraméterként kap meg.
|
||||
|
||||
Példa:
|
||||
|
||||
```python
|
||||
MenuItem(
|
||||
"Nehéz",
|
||||
100, 100,
|
||||
None, None, None, None,
|
||||
set_difficulty,
|
||||
"hard"
|
||||
)
|
||||
```
|
||||
|
||||
Kiválasztáskor:
|
||||
|
||||
```python
|
||||
set_difficulty("hard")
|
||||
```
|
||||
|
||||
fut le.
|
||||
|
||||
---
|
||||
|
||||
### Pozíció
|
||||
|
||||
```python
|
||||
self.x
|
||||
self.y
|
||||
```
|
||||
|
||||
A menüpont képernyőn elfoglalt pozíciója.
|
||||
|
||||
---
|
||||
|
||||
### Szövegmegjelenítő
|
||||
|
||||
```python
|
||||
self.text
|
||||
```
|
||||
|
||||
Egy `TextRenderer` objektum, amely a felirat megjelenítéséért felel.
|
||||
|
||||
---
|
||||
|
||||
### Kijelölt állapot
|
||||
|
||||
```python
|
||||
self.selected
|
||||
```
|
||||
|
||||
Logikai érték:
|
||||
|
||||
- `True`: a menüpont jelenleg ki van jelölve;
|
||||
- `False`: a menüpont nincs kijelölve.
|
||||
|
||||
---
|
||||
|
||||
## Metódusok
|
||||
|
||||
### `select()`
|
||||
|
||||
```python
|
||||
select()
|
||||
```
|
||||
|
||||
Kijelöli a menüpontot.
|
||||
|
||||
#### Működés
|
||||
|
||||
```python
|
||||
self.selected = True
|
||||
```
|
||||
|
||||
#### Példa
|
||||
|
||||
```python
|
||||
start_button.select()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `update()`
|
||||
|
||||
```python
|
||||
update()
|
||||
```
|
||||
|
||||
A menüpont állapotának frissítése.
|
||||
|
||||
Ha az elem nincs kijelölve, a függvény azonnal visszatér:
|
||||
|
||||
```python
|
||||
if not self.selected:
|
||||
return
|
||||
```
|
||||
218
doc/TextRenderer.md
Normal file
218
doc/TextRenderer.md
Normal file
@@ -0,0 +1,218 @@
|
||||
# TextRenderer
|
||||
|
||||
A `TextRenderer` osztály egy egyszerű, karakterenként gépelődő (typewriter effektusú) szövegmegjelenítő. A szöveget sprite-okként tárolja és rendereli, támogatja a sortörést meghatározott szélesség esetén, valamint speciális karakterek kezelését egyedi `display()` függvényeken keresztül.
|
||||
|
||||
---
|
||||
|
||||
## Konstruktor
|
||||
|
||||
```python
|
||||
TextRenderer(x, y, width=None)
|
||||
```
|
||||
|
||||
Új szövegmegjelenítőt hoz létre.
|
||||
|
||||
### Paraméterek
|
||||
|
||||
- `x` (`int`) - A szöveg kezdő X koordinátája.
|
||||
- `y` (`int`) - A szöveg kezdő Y koordinátája.
|
||||
- `width` (`int | None`) - Opcionális maximális szélesség pixelekben. Túllépés esetén automatikus sortörés történik.
|
||||
|
||||
### Attribútumok
|
||||
|
||||
- `sprites` - A renderelendő karaktersprite-ok listája.
|
||||
- `base_x` - Kezdő X koordináta.
|
||||
- `base_y` - Kezdő Y koordináta.
|
||||
- `width` - Maximális szövegszélesség.
|
||||
- `text` - A megjelenítendő szöveg.
|
||||
- `textptr` - Az aktuálisan feldolgozott karakter indexe.
|
||||
- `x` - Aktuális rajzolási pozíció X tengelyen.
|
||||
- `y` - Aktuális rajzolási pozíció Y tengelyen.
|
||||
|
||||
---
|
||||
|
||||
## `reset(text)`
|
||||
|
||||
```python
|
||||
reset(text)
|
||||
```
|
||||
|
||||
Visszaállítja a renderelőt alapállapotba, és új szöveget tölt be.
|
||||
|
||||
### Paraméterek
|
||||
|
||||
- `text` (`str`) - A megjelenítendő szöveg.
|
||||
|
||||
### Működés
|
||||
|
||||
- Törli az összes korábbi sprite-ot.
|
||||
- Visszaállítja a rajzolási pozíciót a kezdőkoordinátákra.
|
||||
- Nullázza a karaktermutatót (`textptr`).
|
||||
|
||||
### Példa
|
||||
|
||||
```python
|
||||
renderer.reset("Helló világ!")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `amend(text)`
|
||||
|
||||
```python
|
||||
amend(text)
|
||||
```
|
||||
|
||||
Hozzáfűz további szöveget a már meglévő szöveghez.
|
||||
|
||||
### Paraméterek
|
||||
|
||||
- `text` (`str`) - A hozzáfűzendő szöveg.
|
||||
|
||||
### Példa
|
||||
|
||||
```python
|
||||
renderer.reset("Helló")
|
||||
renderer.amend(" világ!")
|
||||
```
|
||||
|
||||
Eredmény:
|
||||
|
||||
```text
|
||||
Helló világ!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `type_tick()`
|
||||
|
||||
```python
|
||||
type_tick()
|
||||
```
|
||||
|
||||
Egyetlen karakter feldolgozását végzi el. A függvény elsősorban gépelési animációk megvalósítására használható.
|
||||
|
||||
### Visszatérési érték
|
||||
|
||||
```python
|
||||
bool
|
||||
```
|
||||
|
||||
- `True` - a teljes szöveg feldolgozása befejeződött.
|
||||
- `False` - még vannak feldolgozatlan karakterek.
|
||||
|
||||
### Működés
|
||||
|
||||
1. Lekéri az aktuális karakterhez tartozó definíciót a `texttable` szótárból.
|
||||
2. Ismeretlen karakter esetén a `'?'` definíciót használja.
|
||||
3. Látható karakter esetén:
|
||||
- kivágja a megfelelő textúrát a font atlaszból,
|
||||
- létrehozza a sprite adatait,
|
||||
- hozzáadja azokat a `sprites` listához.
|
||||
4. Ha a megadott szélesség elfogyott:
|
||||
- új sorba lép,
|
||||
- az Y koordinátát 13 pixellel csökkenti.
|
||||
5. Nem látható karakter esetén meghívja a karakter:
|
||||
|
||||
```python
|
||||
display(renderer)
|
||||
```
|
||||
|
||||
metódusát.
|
||||
|
||||
### Példa
|
||||
|
||||
```python
|
||||
while not renderer.type_tick():
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `type_all()`
|
||||
|
||||
```python
|
||||
type_all()
|
||||
```
|
||||
|
||||
A teljes szöveget azonnal feldolgozza.
|
||||
|
||||
### Működés
|
||||
|
||||
A `type_tick()` függvényt hívja ismételten addig, amíg minden karakter feldolgozásra nem kerül.
|
||||
|
||||
### Példa
|
||||
|
||||
```python
|
||||
renderer.reset("Szia!")
|
||||
renderer.type_all()
|
||||
```
|
||||
|
||||
A teljes szöveg egyetlen frame alatt elkészül.
|
||||
|
||||
---
|
||||
|
||||
## `render()`
|
||||
|
||||
```python
|
||||
render()
|
||||
```
|
||||
|
||||
Kirajzolja az összes létrehozott karaktersprite-ot.
|
||||
|
||||
### Működés
|
||||
|
||||
A `sprites` listán végighaladva minden karakterhez meghívja:
|
||||
|
||||
```python
|
||||
arcade.draw_texture_rect()
|
||||
```
|
||||
|
||||
függvényt pixelpontos (`pixelated=True`) rendereléssel.
|
||||
|
||||
### Példa
|
||||
|
||||
```python
|
||||
def on_draw(self):
|
||||
arcade.start_render()
|
||||
renderer.render()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Tipikus használat
|
||||
|
||||
## Gépelési effekt
|
||||
|
||||
```python
|
||||
renderer = TextRenderer(10, 100, width=200)
|
||||
|
||||
renderer.reset(
|
||||
"Ez egy hosszabb szöveg, amely több sorba törhet."
|
||||
)
|
||||
|
||||
renderer.type_tick()
|
||||
|
||||
renderer.render()
|
||||
```
|
||||
|
||||
## Azonnali megjelenítés
|
||||
|
||||
```python
|
||||
renderer = TextRenderer(10, 100)
|
||||
|
||||
renderer.reset("Helló világ!")
|
||||
renderer.type_all()
|
||||
|
||||
renderer.render()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Megjegyzések
|
||||
|
||||
- Az osztály nem hoz létre külön `Sprite` objektumot minden karakterhez, hanem csak a szükséges textúrát és pozíciót tárolja.
|
||||
- Ismeretlen karakter esetén automatikusan a `'?'` karakter kerül megjelenítésre.
|
||||
- A sortörés kizárólag a megadott `width` túllépésekor történik.
|
||||
- Speciális vezérlőkarakterek létrehozhatók `visible=False` karakterdefiníciókkal.
|
||||
- Ezek a karakterek tetszőleges működést valósíthatnak meg a `display(renderer)` metóduson keresztül.
|
||||
BIN
screenshots/2026-10-07-13-06.png
Normal file
BIN
screenshots/2026-10-07-13-06.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
@@ -13,6 +13,7 @@ def anim_default(action, text, timer, dt):
|
||||
|
||||
return False
|
||||
|
||||
# !!! CHATGPT !!!
|
||||
def move_attack(user, target):
|
||||
return Action("Attack", user, target, Damage(user.attack, 0, 0, 0), StatusChange(0, 0, 0), anim_default)
|
||||
|
||||
@@ -79,6 +80,8 @@ def enemy_turn_test(e,ep, ap,d):
|
||||
print(f" ({e.name} chooses {act} -> {target.name})")
|
||||
return builder(e, target)
|
||||
|
||||
# !!! CHATGPT VÉGE !!!
|
||||
|
||||
battles = [
|
||||
{ "enemies": [
|
||||
Combatant("Six-Seven kid", 120, 30, 80, 20, 0, 50, False, False),
|
||||
|
||||
@@ -2,12 +2,14 @@ import gamestates.none
|
||||
import gamestates.title
|
||||
import gamestates.overworld
|
||||
import gamestates.battle
|
||||
import gamestates.gameover
|
||||
|
||||
gamestates = {
|
||||
"none": gamestates.none,
|
||||
"title": gamestates.title,
|
||||
"overworld": gamestates.overworld,
|
||||
"battle": gamestates.battle
|
||||
"battle": gamestates.battle,
|
||||
"gameover": gamestates.gameover,
|
||||
}
|
||||
gamestate = "none"
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import math
|
||||
import copy
|
||||
import random
|
||||
import arcade
|
||||
import arcade
|
||||
import gamestate
|
||||
|
||||
from battle import Combatant, Action, Damage, StatusChange
|
||||
from menu import MenuItem
|
||||
@@ -35,30 +37,157 @@ battle_id = 0
|
||||
|
||||
def switch(game):
|
||||
global enemies, party_members, battle_music, enemy_turn, enemy_ai_data, party_menus, spells, inventory
|
||||
enemies = battle_data.battles[battle_id]["enemies"]
|
||||
party_members = battle_data.battles[battle_id]["party_members"]
|
||||
enemy_turn = battle_data.battles[battle_id]["enemy_turn_func"]
|
||||
enemy_ai_data = battle_data.battles[battle_id]["init_ai_data"]
|
||||
party_menus = battle_data.battles[battle_id]["menus"]
|
||||
spells = battle_data.battles[battle_id]["spells"]
|
||||
inventory = battle_data.battles[battle_id]["inventory"]
|
||||
print("asdfasdfasdf")
|
||||
enemies = copy.deepcopy(battle_data.battles[battle_id]["enemies"])
|
||||
party_members = copy.deepcopy(battle_data.battles[battle_id]["party_members"])
|
||||
enemy_turn = copy.deepcopy(battle_data.battles[battle_id]["enemy_turn_func"])
|
||||
enemy_ai_data = copy.deepcopy(battle_data.battles[battle_id]["init_ai_data"])
|
||||
party_menus = copy.deepcopy(battle_data.battles[battle_id]["menus"])
|
||||
spells = copy.deepcopy(battle_data.battles[battle_id]["spells"])
|
||||
inventory = copy.deepcopy(battle_data.battles[battle_id]["inventory"])
|
||||
battle_music = assets.sounds[battle_data.battles[battle_id]["mus_id"]].play(loops=True)
|
||||
|
||||
def open_menu(whose):
|
||||
party_idx = party_members.index(whose)
|
||||
for i, m in enumerate(party_menus[party_idx]):
|
||||
menu.append(MenuItem(m[0], 19, 64-(i*13), None, None, None, None, menu_action, (whose, party_members, enemies, m[1])))
|
||||
|
||||
for i, m in enumerate(menu):
|
||||
m.up = menu[(i - 1) % len(menu)]
|
||||
m.down = menu[(i + 1) % len(menu)]
|
||||
|
||||
menu[0].select()
|
||||
|
||||
def close_menu():
|
||||
global menu, menu_open
|
||||
menu = []
|
||||
menu_open = 0
|
||||
menu_text.reset("")
|
||||
|
||||
# !!! CHATGPT !!!
|
||||
|
||||
def open_spell_menu(user, aparty, eparty):
|
||||
global menu
|
||||
|
||||
party_idx = party_members.index(user)
|
||||
spell_list = spells[party_idx]
|
||||
|
||||
menu = []
|
||||
|
||||
for i, spell in enumerate(spell_list):
|
||||
menu.append(
|
||||
MenuItem(
|
||||
spell[0],
|
||||
19,
|
||||
64 - (i * 13),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
spell_action,
|
||||
(user, spell, aparty, eparty)
|
||||
)
|
||||
)
|
||||
|
||||
if len(menu) == 0:
|
||||
return
|
||||
|
||||
for i, m in enumerate(menu):
|
||||
m.up = menu[(i - 1) % len(menu)]
|
||||
m.down = menu[(i + 1) % len(menu)]
|
||||
|
||||
menu[0].select()
|
||||
|
||||
|
||||
def spell_action(data):
|
||||
user, spell, aparty, eparty = data
|
||||
|
||||
name, mp_cost, action = spell
|
||||
|
||||
action_name, func, target_type = action
|
||||
|
||||
action_queue.append(func(user, [p for p in eparty if not p.ko][0]))
|
||||
|
||||
close_menu()
|
||||
|
||||
|
||||
def open_item_menu(user, aparty, eparty):
|
||||
global menu
|
||||
|
||||
menu = []
|
||||
|
||||
for i, item in enumerate(inventory):
|
||||
if item[1] <= 0:
|
||||
continue
|
||||
|
||||
menu.append(
|
||||
MenuItem(
|
||||
f"{item[0]} x{item[1]}",
|
||||
19,
|
||||
64 - (i * 13),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
item_action,
|
||||
(user, item, aparty, eparty)
|
||||
)
|
||||
)
|
||||
|
||||
if len(menu) == 0:
|
||||
return
|
||||
|
||||
for i, m in enumerate(menu):
|
||||
m.up = menu[(i - 1) % len(menu)]
|
||||
m.down = menu[(i + 1) % len(menu)]
|
||||
|
||||
menu[0].select()
|
||||
|
||||
|
||||
def item_action(data):
|
||||
user, item, aparty, eparty = data
|
||||
|
||||
name, amount, action = item
|
||||
|
||||
action_name, func, target_type = action
|
||||
|
||||
action_queue.append(
|
||||
func(user, user)
|
||||
)
|
||||
|
||||
item[1] -= 1
|
||||
|
||||
close_menu()
|
||||
|
||||
# !!! CHATGPT VÉGE !!!
|
||||
|
||||
def menu_action(data):
|
||||
user, aparty, eparty, action = data
|
||||
|
||||
match action:
|
||||
|
||||
case "unselectable":
|
||||
return
|
||||
|
||||
case "phys_att":
|
||||
action_queue.append(Action("Physical Attack", user, eparty[0], Damage(166, 0, 0, 0), StatusChange(0, 0, 0), battle_data.anim_default))
|
||||
action_queue.append(
|
||||
Action(
|
||||
"Physical Attack",
|
||||
user,
|
||||
[p for p in eparty if not p.ko][0],
|
||||
Damage(166, 0, 0, 0),
|
||||
StatusChange(0, 0, 0),
|
||||
battle_data.anim_default
|
||||
)
|
||||
)
|
||||
close_menu()
|
||||
|
||||
case "magic":
|
||||
open_spell_menu(user, aparty, eparty)
|
||||
|
||||
case "items":
|
||||
open_item_menu(user, aparty, eparty)
|
||||
|
||||
case _:
|
||||
print(f"Unknown action: {action}")
|
||||
close_menu()
|
||||
@@ -113,20 +242,23 @@ def update(game, dt):
|
||||
menu_open = whose
|
||||
menu_text.reset(f"{whose.name}'s Menu")
|
||||
menu_text.type_all()
|
||||
|
||||
party_idx = party_members.index(whose)
|
||||
for i, m in enumerate(party_menus[party_idx]):
|
||||
menu.append(MenuItem(m[0], 19, 64-(i*13), None, None, None, None, menu_action, (whose, party_members, enemies, m[1])))
|
||||
|
||||
for i, m in enumerate(menu):
|
||||
m.up = menu[(i - 1) % len(menu)]
|
||||
m.down = menu[(i + 1) % len(menu)]
|
||||
|
||||
menu[1].select()
|
||||
open_menu(whose)
|
||||
|
||||
for m in menu:
|
||||
m.update()
|
||||
|
||||
if len(enemies) != 0 and all(e.ko for e in enemies):
|
||||
print("\nVICTORY! all enemies were defeated.")
|
||||
battle_music.stop()
|
||||
gamestate.switch_gamestate(game,"overworld")
|
||||
return
|
||||
|
||||
if len(party_members) != 0 and all(a.ko for a in party_members):
|
||||
print("\nGAME OVER! the party was defeated.")
|
||||
battle_music.stop()
|
||||
gamestate.switch_gamestate(game,"gameover")
|
||||
return
|
||||
|
||||
party_text.reset(partytext)
|
||||
ene_text.reset(enetext)
|
||||
party_text.type_all()
|
||||
|
||||
38
src/gamestates/gameover.py
Normal file
38
src/gamestates/gameover.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import menu
|
||||
import text
|
||||
import renderers
|
||||
import gamestate
|
||||
|
||||
text = text.TextRenderer(90, 180, 210)
|
||||
panel = renderers.NineSlicesPanel(84,100,64,100)
|
||||
|
||||
m = []
|
||||
|
||||
def retry(g):
|
||||
gamestate.switch_gamestate(g, "title")
|
||||
|
||||
|
||||
def switch(game):
|
||||
global m
|
||||
m = [
|
||||
menu.MenuItem("Ujrapróba", 98, 150, None, None, None, None, retry, game),
|
||||
menu.MenuItem("Kilépés", 98, 130, None, None, None, None, quit)
|
||||
]
|
||||
|
||||
m[0].down = m[1]
|
||||
m[1].up = m[0]
|
||||
m[0].select()
|
||||
|
||||
text.reset("Játék vége!")
|
||||
text.type_all()
|
||||
|
||||
def update(game, dt):
|
||||
for i in m:
|
||||
i.update()
|
||||
|
||||
def draw(game):
|
||||
panel.render()
|
||||
text.render()
|
||||
for i in m:
|
||||
i.render()
|
||||
|
||||
@@ -34,6 +34,7 @@ def update(game, dt):
|
||||
|
||||
if btrans_timer >= BTRANS_DURATION:
|
||||
game.mos_enabled = False
|
||||
btrans_active = False
|
||||
btrans_sound.stop()
|
||||
gamestate.switch_gamestate(game,"battle")
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import text
|
||||
SCREEN_WIDTH = 256
|
||||
SCREEN_HEIGHT = 224
|
||||
|
||||
# !!! CHATGPT !!!
|
||||
class Game(arcade.Window):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
|
||||
@@ -5,12 +5,13 @@ import controls
|
||||
|
||||
# Választható menüelem több menüelem közt, ha nincs valamelyik irányba másik menüelem, az irányra None értéket adunk
|
||||
class MenuItem:
|
||||
def __init__(self, label, x, y, left, right, up, down, action, data=None):
|
||||
def __init__(self, label, x, y, left, right, up, down, action, data=None, back_func=None):
|
||||
self.left = left
|
||||
self.right = right
|
||||
self.up = up
|
||||
self.down = down
|
||||
self.action = action
|
||||
self.back = back_func
|
||||
self.data = data
|
||||
self.x = x
|
||||
self.y = y
|
||||
@@ -30,6 +31,10 @@ class MenuItem:
|
||||
self.action(self.data)
|
||||
return
|
||||
|
||||
if controls.is_control_pressed(5) and self.back: # Vissza
|
||||
self.back(self.data)
|
||||
return
|
||||
|
||||
if controls.is_control_pressed(0) and self.up: # Fel
|
||||
controls.depress(0)
|
||||
self.selected = False
|
||||
|
||||
Reference in New Issue
Block a user