import gradio as gr import random import copy from typing import List, Tuple, Dict, Any # 角色屬性基類 class 角色屬性: def __init__(self, 職業, 陣營, 血量, 魔力值, 消耗魔量, 一般攻擊, 大絕招, 防禦, 角色等級): self.__Profession = 職業 self.__campaign = 陣營 self.__hp = 血量 self.__max_hp = 血量 # 保存最大血量 self.__mp = 魔力值 self.__max_mp = 魔力值 # 保存最大魔力 self.__expend_mp = 消耗魔量 self.__normal_attack = 一般攻擊 self.__ultimate_attack = 大絕招 self.__defense = 防禦 self.__level = 角色等級 def getProfession(self): return self.__Profession def getCampaign(self): return self.__campaign def getHp(self): return self.__hp def getMaxHp(self): return self.__max_hp def setHp(self, hp): self.__hp = max(0, hp) def getMp(self): return self.__mp def getMaxMp(self): return self.__max_mp def setMp(self, mp): self.__mp = max(0, mp) def getNormalAttack(self): return self.__normal_attack def getUltimateAttack(self): return self.__ultimate_attack def getDefense(self): return self.__defense def getExpendMp(self): return self.__expend_mp def reset_stats(self): """重置角色狀態""" self.__hp = self.__max_hp self.__mp = self.__max_mp # 角色類別 class 海靈術士(角色屬性): def __init__(self, *args): super().__init__(*args) def normal_attack(self): return self.getNormalAttack(), "使出「水刃擊」!" def ultimate_attack(self): return self.getUltimateAttack(), "使出「海嘯術」!" class 烈焰武士(角色屬性): def __init__(self, *args): super().__init__(*args) def normal_attack(self): return self.getNormalAttack(), "使出「火焰斬」!" def ultimate_attack(self): return self.getUltimateAttack(), "使出「烈焰風暴」!" class 鋼鐵守衛(角色屬性): def __init__(self, *args): super().__init__(*args) def normal_attack(self): return self.getNormalAttack(), "使出「重錘打擊」!" def ultimate_attack(self): return self.getUltimateAttack(), "使出「鋼鐵壁壘」!" class 森林牧者(角色屬性): def __init__(self, *args): super().__init__(*args) def normal_attack(self): return self.getNormalAttack(), "使出「藤蔓鞭擊」!" def ultimate_attack(self): return self.getUltimateAttack(), "使出「自然恩賜」!" class 大地咒師(角色屬性): def __init__(self, *args): super().__init__(*args) def normal_attack(self): return self.getNormalAttack(), "使出「岩石投擲」!" def ultimate_attack(self): return self.getUltimateAttack(), "使出「大地震擊」!" # 屬性相剋設定 campaign_advantage = { "水": "火", # 水剋火 "火": "木", # 火剋木 "木": "土", # 木剋土 "土": "金", # 土剋金 "金": "水" # 金剋水 } def 對戰時屬性相剋比較(攻擊者, 防守者, 攻擊力): """計算屬性相剋後的攻擊力""" 攻擊者陣營 = 攻擊者.getCampaign() 防守者陣營 = 防守者.getCampaign() if campaign_advantage[攻擊者陣營] == 防守者陣營: return 攻擊力 * 1.2, f"{攻擊者.getProfession()} 對 {防守者.getProfession()} 有屬性克制!攻擊力提升 20%!" elif campaign_advantage[防守者陣營] == 攻擊者陣營: return 攻擊力 * 0.8, f"{攻擊者.getProfession()} 被 {防守者.getProfession()} 屬性克制!攻擊力降低 20%!" else: return 攻擊力, "" # 遊戲狀態管理 class GameState: def __init__(self): self.reset_game() def reset_game(self): # 初始化所有角色 self.all_characters = { "海靈術士": 海靈術士("海靈術士", "水", 3500, 5000, 1500, 200, 2000, 0.20, 0), "烈焰武士": 烈焰武士("烈焰武士", "火", 4000, 3000, 1200, 500, 3000, 0.10, 0), "鋼鐵守衛": 鋼鐵守衛("鋼鐵守衛", "金", 5000, 2000, 800, 350, 1800, 0.50, 0), "森林牧者": 森林牧者("森林牧者", "木", 3000, 4500, 1000, 250, 1500, 0.15, 0), "大地咒師": 大地咒師("大地咒師", "土", 4500, 3500, 1000, 300, 2500, 0.30, 0) } self.player_team = [] self.computer_team = [] self.current_player_character = None self.current_computer_character = None self.battle_log = [] self.game_phase = "選擇角色" # 選擇角色, 選擇出戰角色, 戰鬥中, 遊戲結束 self.selected_count = 0 # 全域遊戲狀態 game_state = GameState() def get_character_info(character): """獲取角色資訊字串""" return f""" 職業: {character.getProfession()} 陣營: {character.getCampaign()} HP: {character.getHp()}/{character.getMaxHp()} MP: {character.getMp()}/{character.getMaxMp()} 普攻: {character.getNormalAttack()} 絕招: {character.getUltimateAttack()} 防禦: {character.getDefense()} """ def get_team_status(): """獲取隊伍狀態""" player_info = "玩家隊伍:\n" for i, char in enumerate(game_state.player_team, 1): status = "💀" if char.getHp() <= 0 else "⚔️" if char == game_state.current_player_character else "🛡️" player_info += f"{i}. {status} {char.getProfession()} (HP: {char.getHp()}/{char.getMaxHp()}, MP: {char.getMp()}/{char.getMaxMp()})\n" computer_info = "電腦隊伍:\n" for i, char in enumerate(game_state.computer_team, 1): status = "💀" if char.getHp() <= 0 else "⚔️" if char == game_state.current_computer_character else "🛡️" computer_info += f"{i}. {status} {char.getProfession()} (HP: {char.getHp()}/{char.getMaxHp()}, MP: {char.getMp()}/{char.getMaxMp()})\n" return player_info + "\n" + computer_info def select_character(character_name): """選擇角色""" if game_state.game_phase != "選擇角色": return "現在不是選擇角色的時間!", get_team_status(), "" if game_state.selected_count >= 3: return "已經選擇了3個角色!", get_team_status(), "" if any(char.getProfession() == character_name for char in game_state.player_team): return f"已經選擇過{character_name}了!", get_team_status(), "" # 複製角色避免共用狀態 selected_char = copy.deepcopy(game_state.all_characters[character_name]) game_state.player_team.append(selected_char) game_state.selected_count += 1 message = f"選擇了{character_name}!({game_state.selected_count}/3)" # 如果選擇了3個角色,自動進入下一階段 if game_state.selected_count == 3: # 電腦隨機選擇3個角色 computer_choices = random.sample(list(game_state.all_characters.keys()), 3) game_state.computer_team = [copy.deepcopy(game_state.all_characters[name]) for name in computer_choices] message += f"\n\n電腦選擇了: {', '.join(computer_choices)}" message += "\n\n請選擇出戰角色!" game_state.game_phase = "選擇出戰角色" return message, get_team_status(), "選擇出戰角色" return message, get_team_status(), "" def select_battle_character(player_choice): """選擇出戰角色""" if game_state.game_phase != "選擇出戰角色": return "現在不是選擇出戰角色的時間!", get_team_status(), "", gr.update(), gr.update() try: choice_index = int(player_choice) - 1 if choice_index < 0 or choice_index >= len(game_state.player_team): return "無效的選擇!", get_team_status(), "", gr.update(), gr.update() selected_char = game_state.player_team[choice_index] if selected_char.getHp() <= 0: return "該角色已經陣亡!", get_team_status(), "", gr.update(), gr.update() game_state.current_player_character = selected_char # 電腦隨機選擇一個存活的角色 alive_computer_chars = [char for char in game_state.computer_team if char.getHp() > 0] if alive_computer_chars: game_state.current_computer_character = random.choice(alive_computer_chars) game_state.game_phase = "戰鬥中" battle_message = f"玩家派出 {game_state.current_player_character.getProfession()}!\n" battle_message += f"電腦派出 {game_state.current_computer_character.getProfession()}!\n" battle_message += "戰鬥開始!請選擇攻擊方式:" return battle_message, get_team_status(), "", gr.update(visible=True), gr.update(visible=True) except ValueError: return "請輸入有效的數字!", get_team_status(), "", gr.update(), gr.update() def battle_action(action): """戰鬥行動""" if game_state.game_phase != "戰鬥中": return "現在不是戰鬥時間!", get_team_status(), gr.update(), gr.update() if not game_state.current_player_character or not game_state.current_computer_character: return "戰鬥角色未設定!", get_team_status(), gr.update(), gr.update() battle_log = [] # 玩家攻擊 player_char = game_state.current_player_character computer_char = game_state.current_computer_character # 玩家選擇攻擊方式 if action == "普通攻擊": attack_power, attack_desc = player_char.normal_attack() battle_log.append(f"玩家{player_char.getProfession()} {attack_desc}") else: # 大絕招 if player_char.getMp() >= player_char.getExpendMp(): attack_power, attack_desc = player_char.ultimate_attack() player_char.setMp(player_char.getMp() - player_char.getExpendMp()) battle_log.append(f"玩家{player_char.getProfession()} {attack_desc} (消耗MP: {player_char.getExpendMp()})") else: attack_power, attack_desc = player_char.normal_attack() battle_log.append(f"玩家{player_char.getProfession()} MP不足,改用普通攻擊!{attack_desc}") # 計算屬性相剋 final_attack, element_msg = 對戰時屬性相剋比較(player_char, computer_char, attack_power) if element_msg: battle_log.append(element_msg) # 計算傷害 defense_value = computer_char.getDefense() * attack_power final_damage = max(0, final_attack - defense_value) computer_char.setHp(computer_char.getHp() - final_damage) battle_log.append(f"造成 {final_attack:.0f} 傷害,被防禦擋下 {defense_value:.0f},實際傷害 {final_damage:.0f}") battle_log.append(f"電腦{computer_char.getProfession()} 剩餘HP: {computer_char.getHp()}") # 檢查電腦角色是否陣亡 if computer_char.getHp() <= 0: battle_log.append(f"電腦{computer_char.getProfession()} 陣亡!") game_state.current_computer_character = None # 檢查電腦是否還有存活角色 alive_computer_chars = [char for char in game_state.computer_team if char.getHp() > 0] if not alive_computer_chars: battle_log.append("🎉 恭喜!玩家獲得勝利! 🎉") game_state.game_phase = "遊戲結束" return "\n".join(battle_log), get_team_status(), gr.update(visible=False), gr.update(visible=False) else: battle_log.append("請選擇下一個出戰角色!") game_state.game_phase = "選擇出戰角色" return "\n".join(battle_log), get_team_status(), gr.update(visible=False), gr.update(visible=False) # 電腦反擊 battle_log.append(f"\n電腦{computer_char.getProfession()} 反擊!") # 電腦隨機選擇攻擊方式 computer_action = random.choice(["普通攻擊", "大絕招"]) if computer_action == "普通攻擊": attack_power, attack_desc = computer_char.normal_attack() battle_log.append(f"電腦{computer_char.getProfession()} {attack_desc}") else: if computer_char.getMp() >= computer_char.getExpendMp(): attack_power, attack_desc = computer_char.ultimate_attack() computer_char.setMp(computer_char.getMp() - computer_char.getExpendMp()) battle_log.append(f"電腦{computer_char.getProfession()} {attack_desc} (消耗MP: {computer_char.getExpendMp()})") else: attack_power, attack_desc = computer_char.normal_attack() battle_log.append(f"電腦{computer_char.getProfession()} MP不足,改用普通攻擊!{attack_desc}") # 計算電腦攻擊的屬性相剋 final_attack, element_msg = 對戰時屬性相剋比較(computer_char, player_char, attack_power) if element_msg: battle_log.append(element_msg) # 計算對玩家的傷害 defense_value = player_char.getDefense() * attack_power final_damage = max(0, final_attack - defense_value) player_char.setHp(player_char.getHp() - final_damage) battle_log.append(f"造成 {final_attack:.0f} 傷害,被防禦擋下 {defense_value:.0f},實際傷害 {final_damage:.0f}") battle_log.append(f"玩家{player_char.getProfession()} 剩餘HP: {player_char.getHp()}") # 檢查玩家角色是否陣亡 if player_char.getHp() <= 0: battle_log.append(f"玩家{player_char.getProfession()} 陣亡!") game_state.current_player_character = None # 檢查玩家是否還有存活角色 alive_player_chars = [char for char in game_state.player_team if char.getHp() > 0] if not alive_player_chars: battle_log.append("💀 遊戲結束!電腦獲得勝利! 💀") game_state.game_phase = "遊戲結束" return "\n".join(battle_log), get_team_status(), gr.update(visible=False), gr.update(visible=False) else: battle_log.append("請選擇下一個出戰角色!") game_state.game_phase = "選擇出戰角色" return "\n".join(battle_log), get_team_status(), gr.update(visible=False), gr.update(visible=False) battle_log.append("\n請選擇下一個行動:") return "\n".join(battle_log), get_team_status(), gr.update(), gr.update() def restart_game(): """重新開始遊戲""" game_state.reset_game() return "遊戲重新開始!請選擇3個角色組成你的隊伍:", "", "選擇角色", gr.update(visible=False), gr.update(visible=False) # 創建Gradio界面 def create_interface(): with gr.Blocks(title="決鬥生死戰", theme=gr.themes.Soft()) as demo: gr.HTML("""
選擇你的戰士,擊敗入侵的敵軍!
💧水剋🔥火 | 🔥火剋🌳木 | 🌳木剋🌍土 | 🌍土剋⚡金 | ⚡金剋💧水
💧海靈術士 - 高魔力水系法師
🔥烈焰武士 - 高攻擊火系戰士
⚡鋼鐵守衛 - 高血量金系坦克
🌳森林牧者 - 平衡型木系治療師
🌍大地咒師 - 全能型土系法師