"""Explorer Tab — location exploration, NPC encounters, quest tracking, actions.""" import random import gradio as gr from core.world import WorldGraph from core.player import load_player, save_player from core.model_manager import ModelManager from ui.i18n import t def _get_location_choices() -> list: """Get list of location names for the dropdown.""" world = WorldGraph() return [loc.name for loc in world.get_entities_by_type("location")] def _render_location(location_name: str) -> str: if not location_name: return f"""

{t('exp_empty')}

""" world = WorldGraph() player = load_player() locations = world.get_entities_by_type("location") location = next((l for l in locations if l.name == location_name), None) if not location: return f"

{t('exp_not_found')}

" player.current_location_id = location.id save_player(player) all_npcs = world.get_entities_by_type("npc") npcs_here = [n for n in all_npcs if n.location_id == location.id] all_quests = world.get_entities_by_type("quest") quests_here = [q for q in all_quests if q.location_id == location.id and not player.is_quest_completed(q.id)] neighbors = world.get_neighbors(location.id, "connects_to") connected = [n.name for n in neighbors if n.name != location_name] html = f"""
{location.name}
{location.description}
""" if npcs_here: html += f'
{t("exp_encounter")}
' for npc in npcs_here: dialog = npc.dialog or "..." html += f"""
{npc.name}
"{dialog}"
""" if quests_here: html += f'
{t("exp_quests")}
' for q in quests_here: html += f"""
{q.name}
{q.description[:100]}...
""" if connected: html += f'
{t("exp_travel")}
' html += '
' for loc_name in connected: html += f"""
{loc_name}
""" html += "
" html += "
" return html def explore_location(location_name: str) -> tuple: if not location_name: return t("exp_select_first"), "" world = WorldGraph() player = load_player() manager = ModelManager() locations = world.get_entities_by_type("location") location = next((l for l in locations if l.name == location_name), None) if not location: return t("exp_not_exist"), "" outcomes = [t("exp_outcome_1"), t("exp_outcome_2"), t("exp_outcome_3"), t("exp_outcome_4"), t("exp_outcome_5")] outcome = outcomes[0] # Default, LLM overrides prompt = f"你在{location.name}探索。{location.description[:100]}\n\n请描述一个有趣的发现(物品或线索),50字以内。用中文回答。" gen = manager.generate_fn discovery = gen(prompt) or outcome level_msg = player.add_xp(15) item_found = None if random.random() > 0.5: item_names = [t("item_key"), t("item_crystal"), t("item_scroll"), t("item_potion"), t("item_dust"), t("item_shard")] item_name = random.choice(item_names) player.add_item(item_name, discovery[:30], "misc") item_found = item_name save_player(player) result = f"{t('exp_discovery')}: {discovery}" if item_found: result += f"\n{t('exp_item_found')}: {item_found} (+15 XP)" if level_msg: result += f"\n{level_msg}" return result, _render_location(location_name) def rest_action(location_name: str) -> tuple: player = load_player() player.heal(hp=30, mp=20) save_player(player) return f"{t('exp_rest_result')} (HP:{player.hp}/{player.max_hp}, MP:{player.mp}/{player.max_mp})", _render_location(location_name) def create_explorer_tab() -> tuple: """Create the Explorer tab.""" with gr.Row(): location_dropdown = gr.Dropdown( label=t("exp_select_label"), choices=_get_location_choices(), interactive=True, ) location_display = gr.HTML( value=f"""

{t('exp_empty')}

""" ) with gr.Row(): explore_btn = gr.Button(t("exp_explore"), variant="primary") rest_btn = gr.Button(t("exp_rest"), variant="secondary") action_result = gr.HTML("") # Location change -> render location_dropdown.change( fn=_render_location, inputs=[location_dropdown], outputs=[location_display], ) # Explore explore_btn.click( fn=explore_location, inputs=[location_dropdown], outputs=[action_result, location_display], ) # Rest rest_btn.click( fn=rest_action, inputs=[location_dropdown], outputs=[action_result, location_display], ) return location_dropdown, location_display, action_result