import gradio as gr import random import time from typing import Dict, List, Tuple # Game state storage game_rooms = {} class Player: def __init__(self, name: str): self.name = name self.hp = 100 self.max_hp = 100 self.attack = 15 self.potions = 3 self.gold = 0 self.x = 0 self.y = 0 self.level = 1 self.exp = 0 class Room: def __init__(self, x: int, y: int): self.x = x self.y = y self.monster = None self.treasure = None self.explored = False self.generate_content() def generate_content(self): rand = random.randint(1,100) if rand <= 50: monsters = [ ("Goblin", 30, 8, 10, 15), ("Orc", 50, 12, 20, 25), ("Skeleton", 40, 10, 15, 20), ("Dark Mage", 35, 15, 25, 30), ("Dragon Whelp", 60, 18, 30, 40) ] name, hp, atk, gold, exp = random.choice(monsters) self.monster = {"name": name, "hp": hp, "max_hp": hp, "attack": atk, "gold": gold, "exp": exp} elif rand <= 75: self.treasure = random.randint(10, 40) elif rand <= 90: self.treasure = "potion" elif rand <= 95: self.treasure = "weapon" class GameRoom: def __init__(self, room_id: str): self.room_id = room_id self.players: Dict[str, Player] = {} self.grid: Dict[Tuple[int, int], Room] = {} self.current_player = "" self.turn_count = 0 self.battle_active = False self.current_monster = None self.log = ["๐Ÿฐ Game dimulai! Gabung sekarang!"] # Generate dungeon grid (7x7 for more exploration) for x in range(7): for y in range(7): self.grid[(x, y)] = Room(x, y) # Place exit exit_x, exit_y = 6, 6 self.grid[(exit_x, exit_y)].treasure = "exit" # Place special rooms self.grid[(3, 3)].treasure = "boss" self.grid[(0, 6)].treasure = "artifact" def add_player(self, player_name: str) -> str: if player_name in self.players: return f"{player_name} sudah ada dalam room!" if len(self.players) >= 4: return "Room penuh! Maksimal 4 pemain." self.players[player_name] = Player(player_name) self.log.append(f"๐ŸŽฎ {player_name} bergabung dalam petualangan!") if not self.current_player: self.current_player = player_name self.log.append(f"๐Ÿ‘‘ {player_name} memulai petualangan!") return f"๐ŸŽ‰ {player_name} berhasil bergabung!" def get_player_status(self, player_name: str) -> str: if player_name not in self.players: return "Pemain tidak ditemukan!" p = self.players[player_name] # Create HP bar hp_percent = (p.hp / p.max_hp) * 100 hp_bar = self.create_progress_bar(hp_percent, "โค๏ธ") exp_bar = self.create_progress_bar(p.exp, "๐ŸŒŸ") return f"""

๐Ÿน {p.name}

{hp_bar}
โš”๏ธ Attack: {p.attack}
๐Ÿงช Potions: {p.potions}
๐Ÿ’ฐ Gold: {p.gold}
๐ŸŽฏ Level: {p.level}
{exp_bar}
๐Ÿ“ Position: ({p.x}, {p.y})
""" def create_progress_bar(self, percent, label): width = min(percent, 100) color = "#2ecc71" if percent > 70 else "#f39c12" if percent > 30 else "#e74c3c" return f"""
{label} {percent:.1f}%
""" def move_player(self, player_name: str, direction: str) -> Tuple[bool, str]: if player_name != self.current_player: return False, "โŒ Bukan giliranmu!" if player_name not in self.players: return False, "โŒ Pemain tidak ada!" if self.battle_active: return False, "โŒ Sedang dalam pertarungan!" p = self.players[player_name] new_x, new_y = p.x, p.y if direction == "utara" and p.y > 0: new_y -= 1 elif direction == "selatan" and p.y < 6: new_y += 1 elif direction == "barat" and p.x > 0: new_x -= 1 elif direction == "timur" and p.x < 6: new_x += 1 else: return False, "โŒ Tidak bisa bergerak ke arah itu!" p.x, p.y = new_x, new_y room = self.grid[(new_x, new_y)] if not room.explored: room.explored = True self.log.append(f"๐Ÿ” {p.name} menemukan ruangan ({new_x}, {new_y})") if room.monster: self.battle_active = True self.current_monster = room.monster return True, self.create_battle_alert(f"โš”๏ธ {room.monster['name']} muncul!", f"โค๏ธ HP: {room.monster['hp']} | โš”๏ธ Attack: {room.monster['attack']}") elif room.treasure: if room.treasure == "potion": p.potions += 1 self.log.append(f"๐Ÿงช {p.name} menemukan ramuan penyembuh!") return True, self.create_success_alert("๐Ÿงช Kamu menemukan ramuan penyembuh!") elif room.treasure == "weapon": p.attack += 5 self.log.append(f"โš”๏ธ {p.name} menemukan senjata legendaris! Attack +5") return True, self.create_success_alert("โš”๏ธ Kamu menemukan senjata legendaris! Attack +5") elif room.treasure == "exit": self.log.append(f"๐ŸŽ‰ {p.name} menemukan pintu keluar! Kemenangan!") return True, self.create_victory_alert("๐ŸŽ‰ Selamat! Kamu menemukan pintu keluar!") elif room.treasure == "boss": boss = {"name": "Dragon Lord", "hp": 100, "max_hp": 100, "attack": 25, "gold": 100, "exp": 100} self.battle_active = True self.current_monster = boss return True, self.create_battle_alert("๐Ÿ‰ BOSS BESAR! Dragon Lord muncul!", f"โค๏ธ HP: {boss['hp']} | โš”๏ธ Attack: {boss['attack']}") elif room.treasure == "artifact": p.max_hp += 25 p.hp = p.max_hp self.log.append(f"๐Ÿ’Ž {p.name} menemukan artifact! Max HP +25") return True, self.create_success_alert("๐Ÿ’Ž Kamu menemukan artifact kuno! Max HP +25") else: p.gold += room.treasure self.log.append(f"๐Ÿ’ฐ {p.name} menemukan {room.treasure} emas!") return True, self.create_success_alert(f"๐Ÿ’ฐ Kamu menemukan {room.treasure} emas!") return True, "๐Ÿ“ Bergerak ke ruangan yang sudah dijelajahi." def create_battle_alert(self, title, content): return f"""

{title}

{content}

""" def create_success_alert(self, message): return f"""

{message}

""" def create_victory_alert(self, message): return f"""

๐ŸŽ‰ {message} ๐ŸŽ‰

""" def battle_action(self, player_name: str, action: str) -> Tuple[bool, str]: if player_name != self.current_player: return False, "โŒ Bukan giliranmu!" if not self.battle_active: return False, "โŒ Tidak ada pertarungan!" p = self.players[player_name] m = self.current_monster if action == "attack": dmg = random.randint(p.attack-3, p.attack+5) m["hp"] -= dmg msg = f"

โš”๏ธ {p.name} menyerang {m['name']}!

๐Ÿ’ฅ Damage: {dmg}

" if m["hp"] <= 0: p.gold += m["gold"] p.exp += m["exp"] msg += f"

๐Ÿ’€ {m['name']} dikalahkan!

๐Ÿ’ฐ +{m['gold']} emas | ๐ŸŒŸ +{m['exp']} EXP

" # Level up check if p.exp >= 100: p.level += 1 p.exp = 0 p.max_hp += 10 p.hp = p.max_hp p.attack += 3 msg += f"

๐ŸŽ‰ LEVEL UP! Sekarang Level {p.level}!

" self.battle_active = False self.current_monster = None self.log.append(f"๐ŸŽฏ {p.name} mengalahkan {m['name']}!") else: mdmg = random.randint(m["attack"]-2, m["attack"]+3) p.hp -= mdmg msg += f"

๐Ÿฉธ {m['name']} menyerang balik!

๐Ÿ’” Damage: {mdmg}

" self.log.append(f"โš”๏ธ Pertarungan {p.name} vs {m['name']}!") if p.hp <= 0: self.log.append(f"๐Ÿ’€ {p.name} tewas dalam pertarungan!") return True, self.create_battle_alert("๐Ÿ’€ Kamu tewas dalam pertempuran!", "Game over!") msg += "
" elif action == "potion": if p.potions > 0: heal = random.randint(25, 40) p.hp = min(p.hp + heal, p.max_hp) p.potions -= 1 msg = f"

๐Ÿงช {p.name} menggunakan ramuan!

๐Ÿ’š +{heal} HP

" mdmg = random.randint(m["attack"]-2, m["attack"]+3) p.hp -= mdmg msg += f"

๐Ÿฉธ {m['name']} menyerang!

๐Ÿ’” Damage: {mdmg}

" if p.hp <= 0: self.log.append(f"๐Ÿ’€ {p.name} tewas setelah menggunakan ramuan!") return True, self.create_battle_alert("๐Ÿ’€ Kamu tewas dalam pertempuran!", "Game over!") msg += "
" else: return False, "โŒ Tidak punya ramuan!" elif action == "flee": flee_chance = random.randint(1, 100) if flee_chance > 50: self.battle_active = False self.current_monster = None msg = self.create_success_alert("๐Ÿƒโ€โ™‚๏ธ Kamu berhasil melarikan diri!") self.log.append(f"๐Ÿƒโ€โ™‚๏ธ {p.name} melarikan diri dari pertarungan!") else: mdmg = random.randint(m["attack"]-2, m["attack"]+3) p.hp -= mdmg msg = f"

โŒ Gagal melarikan diri!

๐Ÿฉธ {m['name']} menyerang! Damage: {mdmg}

" if p.hp <= 0: self.log.append(f"๐Ÿ’€ {p.name} tewas saat mencoba melarikan diri!") return True, self.create_battle_alert("๐Ÿ’€ Kamu tewas dalam pertempuran!", "Game over!") return True, msg def end_turn(self, player_name: str) -> Tuple[bool, str]: if player_name != self.current_player: return False, "โŒ Bukan giliranmu!" player_names = list(self.players.keys()) if len(player_names) <= 1: return False, "โŒ Butuh minimal 2 pemain!" current_idx = player_names.index(player_name) next_idx = (current_idx + 1) % len(player_names) self.current_player = player_names[next_idx] self.turn_count += 1 # Heal 5 HP at turn start p = self.players[self.current_player] old_hp = p.hp p.hp = min(p.hp + 5, p.max_hp) heal_amount = p.hp - old_hp self.log.append(f"๐Ÿ”„ Giliran {self.current_player} (+{heal_amount} HP)") return True, f"""

โœ… Giliran {self.current_player}!

+{heal_amount} HP regenerasi

""" def create_dungeon_map_html(self) -> str: html = """

๐Ÿ—บ๏ธ Peta Dungeon

""" for y in range(7): for x in range(7): room = self.grid[(x, y)] players_here = [p for p in self.players.values() if p.x == x and p.y == y] room_class = "room " room_text = "?" room_title = f"Position: ({x}, {y})" if players_here: room_class += "player-room" room_text = "๐Ÿ‘ค" room_title += f"\nPlayers: {', '.join([p.name for p in players_here])}" elif room.treasure == "exit": room_class += "exit-room" room_text = "๐Ÿšช" room_title += "\nEXIT" elif room.treasure == "boss": room_class += "boss-room" room_text = "๐Ÿ‰" room_title += "\nBOSS ROOM" elif room.treasure == "artifact": room_class += "artifact-room" room_text = "๐Ÿ’Ž" room_title += "\nARTIFACT" elif room.monster and not room.explored: room_class += "monster-room" room_text = "๐Ÿ‘น" room_title += f"\nMonster: {room.monster['name']}" elif room.treasure and not room.explored and room.treasure not in ["exit", "boss", "artifact"]: if room.treasure == "potion": room_class += "potion-room" room_text = "๐Ÿงช" room_title += "\nPotion" elif room.treasure == "weapon": room_class += "weapon-room" room_text = "โš”๏ธ" room_title += "\nWeapon" else: room_class += "treasure-room" room_text = "๐Ÿ’ฐ" room_title += f"\nGold: {room.treasure}" elif room.explored: room_class += "explored-room" room_text = "โœ“" room_title += "\nExplored" else: room_class += "unexplored-room" room_text = "?" room_title += "\nUnexplored" html += f"""
{room_text}
""" html += """
๐Ÿ‘ค = Pemain
๐Ÿšช = Exit
๐Ÿ‰ = Boss
๐Ÿ‘น = Monster
๐Ÿ’ฐ = Treasure
๐Ÿงช = Potion
""" return html def get_all_players_html(self) -> str: if not self.players: return "
Belum ada pemain
" html = """

๐Ÿ‘ฅ Tim Petualang

""" for name, p in self.players.items(): current = "๐Ÿ‘‘" if name == self.current_player else "๐Ÿ‘ค" hp_percent = (p.hp / p.max_hp) * 100 hp_color = "#2ecc71" if hp_percent > 70 else "#f39c12" if hp_percent > 30 else "#e74c3c" html += f"""
{current} {name} Lvl {p.level}
โค๏ธ {p.hp}/{p.max_hp} | โš”๏ธ {p.attack} | ๐Ÿ’ฐ {p.gold}
""" html += "
" return html def get_logs_html(self) -> str: logs = self.log[-8:] if self.log else ["Tidak ada aktivitas"] html = """

๐Ÿ“œ Catatan Petualangan

""" for log in logs: html += f"""
{log}
""" html += "
" return html # Gradio interface dengan tema yang lebih keren def create_interface(): with gr.Blocks( title="Dungeon Crawler RPG", theme=gr.themes.Soft(primary_hue="red", secondary_hue="slate"), css=""" .dungeon-title { text-align: center; background: linear-gradient(45deg, #8B4513, #D2691E); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: bold; font-size: 2.5em; text-shadow: 2px 2px 4px rgba(0,0,0,0.3); } .game-container { border: 2px solid #8B4513; border-radius: 10px; padding: 15px; background: #f5f5dc; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } """ ) as demo: gr.Markdown("""
๐Ÿฐ Dungeon Crawler RPG
Petualangan Multiplayer - Jelajahi dungeon, kalahkan monster, dan temukan harta karun!
""") with gr.Row(): with gr.Column(scale=1): with gr.Group(): gr.Markdown("### ๐ŸŽฎ Masuk Game") room_id = gr.Textbox( label="๐Ÿ  Room ID", placeholder="Masukkan Room ID (contoh: dragon_lair)", info="Buat room baru atau gabung yang sudah ada" ) player_name = gr.Textbox( label="๐Ÿ‘ค Nama Petualang", placeholder="Nama pahlawan kamu", info="Gunakan nama yang keren!" ) join_btn = gr.Button("๐Ÿšช Masuk Dungeon", variant="primary", size="lg") with gr.Column(scale=2): with gr.Group(): gr.Markdown("### ๐Ÿ“Š Status Petualang") status_box = gr.HTML(label="Status", value="
Bergabunglah untuk memulai...
") with gr.Row(): with gr.Column(scale=2): with gr.Group(): gr.Markdown("### ๐Ÿ—บ๏ธ Peta Dungeon") map_box = gr.HTML(label="Peta") with gr.Column(scale=1): with gr.Group(): gr.Markdown("### ๐Ÿ‘ฅ Tim Petualang") players_box = gr.HTML(label="Pemain") with gr.Group(): gr.Markdown("### ๐Ÿ”„ Kontrol Game") turn_info = gr.HTML(label="Giliran", value="
Menunggu pemain...
") with gr.Row(): refresh_btn = gr.Button("๐Ÿ”„ Refresh", variant="secondary") end_turn_btn = gr.Button("โญ๏ธ Akhiri Giliran", variant="primary") with gr.Row(): with gr.Column(scale=1): with gr.Group(): gr.Markdown("### ๐ŸŽฏ Aksi Petualangan") with gr.Row(): move_choice = gr.Radio( choices=["โฌ†๏ธ Utara", "โฌ‡๏ธ Selatan", "โฌ…๏ธ Barat", "โžก๏ธ Timur"], label="๐Ÿšถ Arah Gerakan", value="โฌ†๏ธ Utara" ) move_btn = gr.Button("๐ŸŽฏ Jelajahi", variant="primary", size="lg") with gr.Column(scale=1): with gr.Group(): gr.Markdown("### โš”๏ธ Aksi Pertempuran") battle_choice = gr.Radio( choices=["โš”๏ธ Serang", "๐Ÿงช Gunakan Ramuan", "๐Ÿƒโ€โ™‚๏ธ Kabur"], label="Pilih Strategi", value="โš”๏ธ Serang" ) battle_btn = gr.Button("โšก Eksekusi", variant="primary", size="lg") with gr.Row(): with gr.Group(): gr.Markdown("### ๐Ÿ“œ Catatan Petualangan") log_box = gr.HTML(label="Activity Log") # Event handlers def join_room(room_id_str, name_str): if not room_id_str or not name_str: return ( "โŒ Room ID dan nama harus diisi!", "
Bergabunglah untuk memulai...
", "
Peta akan muncul di sini...
", "
Belum ada pemain
", "
Menunggu pemain...
", "
Log akan muncul di sini...
" ) if room_id_str not in game_rooms: game_rooms[room_id_str] = GameRoom(room_id_str) room = game_rooms[room_id_str] result = room.add_player(name_str) status = room.get_player_status(name_str) turn = f"
๐Ÿ‘‘ Giliran: {room.current_player}
" map_html = room.create_dungeon_map_html() players = room.get_all_players_html() logs = room.get_logs_html() return result, status, map_html, players, turn, logs def handle_move(room_id_str, name_str, direction): direction = direction.replace("โฌ†๏ธ ", "").replace("โฌ‡๏ธ ", "").replace("โฌ…๏ธ ", "").replace("โžก๏ธ ", "").lower() if not room_id_str or not name_str: return "โŒ Room ID dan nama harus diisi!", "", "", "" if room_id_str not in game_rooms: return "โŒ Room tidak ditemukan!", "", "", "" room = game_rooms[room_id_str] success, msg = room.move_player(name_str, direction) status = room.get_player_status(name_str) map_html = room.create_dungeon_map_html() logs = room.get_logs_html() return msg, status, map_html, logs def handle_battle(room_id_str, name_str, action): action_map = { "โš”๏ธ Serang": "attack", "๐Ÿงช Gunakan Ramuan": "potion", "๐Ÿƒโ€โ™‚๏ธ Kabur": "flee" } action = action_map.get(action, "attack") if not room_id_str or not name_str: return "โŒ Room ID dan nama harus diisi!", "", "", "" if room_id_str not in game_rooms: return "โŒ Room tidak ditemukan!", "", "", "" room = game_rooms[room_id_str] success, msg = room.battle_action(name_str, action) status = room.get_player_status(name_str) map_html = room.create_dungeon_map_html() logs = room.get_logs_html() return msg, status, map_html, logs def handle_end_turn(room_id_str, name_str): if not room_id_str or not name_str: return "โŒ Room ID dan nama harus diisi!", "", "", "", "" if room_id_str not in game_rooms: return "โŒ Room tidak ditemukan!", "", "", "", "" room = game_rooms[room_id_str] success, msg = room.end_turn(name_str) turn = f"
๐Ÿ‘‘ Giliran: {room.current_player}
" map_html = room.create_dungeon_map_html() players = room.get_all_players_html() logs = room.get_logs_html() return msg, turn, map_html, players, logs def refresh_all(room_id_str, name_str): if not room_id_str or not name_str: return "", "", "", "" if room_id_str not in game_rooms: return "", "", "", "" room = game_rooms[room_id_str] status = room.get_player_status(name_str) turn = f"
๐Ÿ‘‘ Giliran: {room.current_player}
" map_html = room.create_dungeon_map_html() logs = room.get_logs_html() return status, turn, map_html, logs # Event handlers join_btn.click( fn=join_room, inputs=[room_id, player_name], outputs=[status_box, status_box, map_box, players_box, turn_info, log_box] ) move_btn.click( fn=handle_move, inputs=[room_id, player_name, move_choice], outputs=[status_box, status_box, map_box, log_box] ) battle_btn.click( fn=handle_battle, inputs=[room_id, player_name, battle_choice], outputs=[status_box, status_box, map_box, log_box] ) end_turn_btn.click( fn=handle_end_turn, inputs=[room_id, player_name], outputs=[status_box, turn_info, map_box, players_box, log_box] ) refresh_btn.click( fn=refresh_all, inputs=[room_id, player_name], outputs=[status_box, turn_info, map_box, log_box] ) return demo # Create and launch the interface if __name__ == "__main__": demo = create_interface() demo.launch(share=True)