346 lines
9.2 KiB
Python
346 lines
9.2 KiB
Python
import math
|
|
import copy
|
|
import random
|
|
import renderers
|
|
import arcade
|
|
import gamestate
|
|
from PIL import Image
|
|
|
|
from battle import Combatant, Action, Damage, StatusChange
|
|
from menu import MenuItem
|
|
from text import TextRenderer
|
|
|
|
import assets
|
|
import battle_data
|
|
|
|
enemies = []
|
|
party_members = []
|
|
enemy_turn = None
|
|
battle_music = None
|
|
enemy_ai_data = {}
|
|
party_menus = []
|
|
spells = []
|
|
inventory = []
|
|
|
|
enemy_sprites = []
|
|
party_sprites = []
|
|
gray_cache = {}
|
|
|
|
action_queue = []
|
|
cur_action = None
|
|
action_timer = 0
|
|
|
|
menu_text = TextRenderer(6, 76, 210)
|
|
action_text = TextRenderer(110, 215, 210)
|
|
|
|
menu_open = 0
|
|
menu_queue = []
|
|
menu = []
|
|
panel = renderers.NineSlicesPanel(0,0,230,100)
|
|
|
|
battle_id = 0
|
|
|
|
def enemy_pos(i):
|
|
return (185, 195 - i * 40)
|
|
|
|
def party_pos(i):
|
|
return (40 + (i % 2) * 30, 165 - i * 35)
|
|
|
|
def switch(game):
|
|
global enemies, party_members, battle_music, enemy_turn, enemy_ai_data, party_menus, spells, inventory, enemy_sprites, party_sprites
|
|
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"])
|
|
enemy_sprites = battle_data.battles[battle_id]["enemy_sprites"]
|
|
party_sprites = battle_data.battles[battle_id]["party_sprites"]
|
|
battle_music = assets.sounds[battle_data.battles[battle_id]["mus_id"]].play(loops=True)
|
|
close_menu()
|
|
|
|
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),
|
|
open_menu
|
|
)
|
|
)
|
|
|
|
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_name, func, target_type) = spell
|
|
|
|
open_target_menu(
|
|
user, aparty, eparty, target_type,
|
|
lambda targets: action_queue.append(func(user, targets[0])),
|
|
lambda *a: open_spell_menu(user, aparty, eparty))
|
|
|
|
|
|
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),
|
|
open_menu
|
|
)
|
|
)
|
|
|
|
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_name, func, target_type) = item
|
|
|
|
def use(targets):
|
|
action_queue.append(func(user, targets[0]))
|
|
item[1] -= 1
|
|
|
|
open_target_menu(user, aparty, eparty, target_type, use,
|
|
lambda *a: open_item_menu(user, aparty, eparty))
|
|
|
|
def open_target_menu(user, aparty, eparty, target_type, on_pick, back):
|
|
"""
|
|
target_type: "enemy", "ally", "self", "all_enemies", "all_allies"
|
|
on_pick: called with a LIST of targets
|
|
back: called when the player cancels (reopens the previous menu)
|
|
"""
|
|
global menu
|
|
|
|
# No selection needed
|
|
if target_type == "self":
|
|
on_pick([user]); close_menu(); return
|
|
|
|
pool = eparty if target_type in ["ene", "ene_rev"] else aparty
|
|
candidates = [c for c in pool if not c.ko] if target_type not in ["ene_rev", "all_rev"] else pool
|
|
if not candidates:
|
|
return
|
|
|
|
menu = []
|
|
for i, c in enumerate(candidates):
|
|
name = c.name + "(" + str(c.hp) + ("," if c.def_up or c.stone else "") + ("Kő" if c.stone else "") + (", " if c.def_up and c.stone else "") + ("Védés" if c.def_up else "") + ")"
|
|
|
|
menu.append(MenuItem(
|
|
name,
|
|
19, 64 - (i * 13),
|
|
None, None, None, None,
|
|
target_picked, (c, on_pick),
|
|
back
|
|
))
|
|
|
|
for i, m in enumerate(menu):
|
|
m.up = menu[(i - 1) % len(menu)]
|
|
m.down = menu[(i + 1) % len(menu)]
|
|
menu[0].select()
|
|
|
|
|
|
def target_picked(data):
|
|
target, on_pick = data
|
|
on_pick([target])
|
|
close_menu()
|
|
|
|
def open_menu(data):
|
|
global menu
|
|
|
|
whose, junk, aparty, eparty = data
|
|
menu = []
|
|
|
|
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, aparty, eparty, 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 menu_action(data):
|
|
user, aparty, eparty, action = data
|
|
|
|
match action:
|
|
|
|
case "unselectable":
|
|
return
|
|
|
|
case "phys_att":
|
|
def queue_attack(targets):
|
|
action_queue.append(Action(
|
|
"Támadás", user, targets[0],
|
|
Damage(user.attack, 0, 0, 0), StatusChange(0, 0, 0),
|
|
battle_data.anim_default))
|
|
|
|
open_target_menu(user, aparty, eparty, "ene", queue_attack,
|
|
lambda *a: open_menu((user, 0, aparty, eparty)))
|
|
case "magic":
|
|
open_spell_menu(user, aparty, eparty)
|
|
|
|
case "items":
|
|
open_item_menu(user, aparty, eparty)
|
|
|
|
case _:
|
|
print(f"Unknown action: {action}")
|
|
close_menu()
|
|
|
|
# !!! CHATGPT VÉGE !!!
|
|
def update(game, dt):
|
|
global menu_open, cur_action, action_timer
|
|
|
|
for e in enemies:
|
|
if e.ko or e.stone:
|
|
continue
|
|
e.atb -= 1
|
|
if e.atb <= 0:
|
|
act = enemy_turn(e, enemies, party_members, enemy_ai_data)
|
|
if act:
|
|
action_queue.append(act)
|
|
e.atb = math.inf
|
|
|
|
for p in party_members:
|
|
if p.ko or p.stone:
|
|
continue
|
|
p.atb -= 1
|
|
if p.atb <= 0:
|
|
print(f"{p.name} is ready to act!")
|
|
menu_queue.append(p)
|
|
p.atb = math.inf
|
|
|
|
if len(action_queue) != 0 and cur_action == None:
|
|
action = action_queue.pop(0)
|
|
print(f"Executing: {action}")
|
|
cur_action = action
|
|
action_timer = 0
|
|
|
|
if cur_action != None:
|
|
if cur_action.animation(cur_action, action_text, action_timer, dt):
|
|
cur_action = None
|
|
else:
|
|
action_timer += dt
|
|
|
|
if len(menu_queue) != 0 and menu_open == 0:
|
|
whose = menu_queue.pop(0)
|
|
menu_open = whose
|
|
menu_text.reset(f"{whose.name} menüje")
|
|
menu_text.type_all()
|
|
open_menu((whose, 67, party_members, enemies))
|
|
|
|
for m in menu:
|
|
m.update()
|
|
|
|
if len(enemies) != 0 and all(e.ko or e.stone 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 or a.stone for a in party_members):
|
|
print("\nGAME OVER! the party was defeated.")
|
|
battle_music.stop()
|
|
gamestate.switch_gamestate(game,"gameover")
|
|
return
|
|
|
|
# !!! CHATGPT !!!
|
|
def make_gray(tex, key):
|
|
img = tex.image.convert("RGBA")
|
|
a = img.getchannel("A")
|
|
l = img.convert("L")
|
|
out = Image.merge("RGBA", (l, l, l, a))
|
|
return arcade.Texture(out)
|
|
|
|
def get_texture(sprite_id, gray=False):
|
|
asset = assets.sprites[sprite_id]
|
|
tex = getattr(asset, "texture", asset)
|
|
if not gray:
|
|
return tex
|
|
if sprite_id not in gray_cache:
|
|
gray_cache[sprite_id] = make_gray(tex, sprite_id)
|
|
return gray_cache[sprite_id]
|
|
|
|
def pick_sprite_id(c, ids):
|
|
if c.ko:
|
|
return ids[2]
|
|
if c.hp <= c.maxhp * 0.1:
|
|
return ids[1]
|
|
return ids[0]
|
|
|
|
def draw_tex(tex, cx, cy):
|
|
arcade.draw_texture_rect(tex, arcade.LRBT(
|
|
cx - tex.width / 2, cx + tex.width / 2,
|
|
cy - tex.height / 2, cy + tex.height / 2))
|
|
|
|
def draw_battlers(combatants, sprite_table, pos_func):
|
|
for i, c in enumerate(combatants):
|
|
sid = pick_sprite_id(c, sprite_table[i])
|
|
tex = get_texture(sid, gray=bool(c.stone and not c.ko))
|
|
draw_tex(tex, *pos_func(i))
|
|
|
|
def draw(game):
|
|
draw_battlers(enemies, enemy_sprites, enemy_pos)
|
|
draw_battlers(party_members, party_sprites, party_pos)
|
|
panel.render()
|
|
for m in menu:
|
|
m.render()
|
|
|
|
menu_text.render()
|
|
action_text.render()
|
|
|