diff --git a/game/debug/debug_pokemon_panel.gd b/game/debug/debug_pokemon_panel.gd new file mode 100644 index 0000000..9171926 --- /dev/null +++ b/game/debug/debug_pokemon_panel.gd @@ -0,0 +1,222 @@ +extends CanvasLayer +# Autoload : DebugPokemonPanel +#panneau de test (build de debug uniquement) : liste des pokemon du Pokedex, un clic ajoute a l'equipe + +const TOGGLE_ACTION : StringName = &"debug_pokemon_panel" +const DEFAULT_LEVEL : int = 10 + +var _root : Control +var _filter : LineEdit +var _level_spin : SpinBox +var _team_label : Label +var _scroll : ScrollContainer +var _list : VBoxContainer +var _message : Label +var _buttons : Array[Button] = [] +var _populated : bool = false +var _was_paused : bool = false +var _prev_mouse_mode : Input.MouseMode = Input.MOUSE_MODE_VISIBLE + +func _ready() -> void: + if !OS.is_debug_build(): + queue_free() + return + layer = 100 + process_mode = Node.PROCESS_MODE_ALWAYS #le panneau reste utilisable pendant que le jeu est en pause + _setup_input() + _build_ui() + _root.visible = false + +func _setup_input() -> void: + if InputMap.has_action(TOGGLE_ACTION): return + InputMap.add_action(TOGGLE_ACTION) + var key := InputEventKey.new() + key.physical_keycode = KEY_F3 + InputMap.action_add_event(TOGGLE_ACTION, key) + var pad := InputEventJoypadButton.new() + pad.button_index = JOY_BUTTON_BACK + InputMap.action_add_event(TOGGLE_ACTION, pad) + +func _unhandled_input(event : InputEvent) -> void: + if _root == null: return + if event.is_action_pressed(TOGGLE_ACTION): + if _root.visible: _close() + else: _open() + get_viewport().set_input_as_handled() + elif _root.visible and event.is_action_pressed(&"ui_cancel"): + _close() + get_viewport().set_input_as_handled() + +#---------- ouverture / fermeture ---------- + +func _open() -> void: + if !_populated: _populate() + _was_paused = get_tree().paused + _prev_mouse_mode = Input.mouse_mode + get_tree().paused = true + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + _root.visible = true + _message.text = "" + _refresh_team() + _focus_first.call_deferred() + +func _close() -> void: + _root.visible = false + get_tree().paused = _was_paused + Input.mouse_mode = _prev_mouse_mode + +func _focus_first() -> void: + for b in _buttons: + if b.is_visible_in_tree(): + b.grab_focus() + return + +#---------- interface ---------- + +func _build_ui() -> void: + _root = Control.new() + _root.set_anchors_preset(Control.PRESET_FULL_RECT) + add_child(_root) + + var dim := ColorRect.new() + dim.color = Color(0.0, 0.0, 0.0, 0.6) + dim.set_anchors_preset(Control.PRESET_FULL_RECT) + _root.add_child(dim) + + var center := CenterContainer.new() + center.set_anchors_preset(Control.PRESET_FULL_RECT) + _root.add_child(center) + + var panel := PanelContainer.new() + panel.custom_minimum_size = Vector2(580, 640) + center.add_child(panel) + + var margin := MarginContainer.new() + for side in ["left", "right", "top", "bottom"]: + margin.add_theme_constant_override("margin_" + side, 16) + panel.add_child(margin) + + var box := VBoxContainer.new() + box.add_theme_constant_override("separation", 8) + margin.add_child(box) + + var title := Label.new() + title.text = "Debug : ajouter un Pokémon à l'équipe" + title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + box.add_child(title) + + var level_row := HBoxContainer.new() + box.add_child(level_row) + var level_label := Label.new() + level_label.text = "Niveau" + level_row.add_child(level_label) + _level_spin = SpinBox.new() + _level_spin.min_value = 1 + _level_spin.max_value = PokemonInstance.MAX_LEVEL + _level_spin.step = 1 + _level_spin.value = DEFAULT_LEVEL + level_row.add_child(_level_spin) + _filter = LineEdit.new() + _filter.placeholder_text = "Rechercher (nom, type, id)..." + _filter.clear_button_enabled = true + _filter.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _filter.text_changed.connect(_on_filter_changed) + level_row.add_child(_filter) + + _team_label = Label.new() + _team_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + box.add_child(_team_label) + + _scroll = ScrollContainer.new() + _scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL + _scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED + _scroll.follow_focus = true + box.add_child(_scroll) + + _list = VBoxContainer.new() + _list.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _scroll.add_child(_list) + + _message = Label.new() + box.add_child(_message) + + var actions := HBoxContainer.new() + actions.add_theme_constant_override("separation", 8) + box.add_child(actions) + actions.add_child(_make_action_button("Soigner l'équipe", _on_heal_pressed)) + actions.add_child(_make_action_button("Vider l'équipe", _on_clear_pressed)) + actions.add_child(_make_action_button("Fermer", _close)) + + var hint := Label.new() + hint.text = "F3 / Select : ouvrir-fermer | Échap / B : fermer" + hint.modulate = Color(1.0, 1.0, 1.0, 0.5) + hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + box.add_child(hint) + +func _make_action_button(label : String, callback : Callable) -> Button: + var button := Button.new() + button.text = label + button.size_flags_horizontal = Control.SIZE_EXPAND_FILL + button.pressed.connect(callback) + return button + +func _populate() -> void: + _populated = true + for id in Pokedex.all_ids(): + var data : PokemonData = Pokedex.get_pokemon(id) + if data == null: continue + + var types_text : String = ", ".join(data.types.filter(func(t : TypeData) -> bool: return t != null).map(func(t : TypeData) -> String: return t.get_display_name())) + var button := Button.new() + button.alignment = HORIZONTAL_ALIGNMENT_LEFT + button.text = "#%d %s (%s)" % [data.id, data.get_display_name(), types_text] + button.icon = data.menu_sprite + button.expand_icon = true + button.add_theme_constant_override("icon_max_width", 32) + button.set_meta("search", ("%d %s %s %s" % [data.id, data.api_name, data.get_display_name(), types_text]).to_lower()) + button.pressed.connect(_on_pokemon_pressed.bind(data)) + _list.add_child(button) + _buttons.append(button) + + if _buttons.is_empty(): + _message.text = "Aucun Pokémon dans le Pokedex." + +#---------- actions ---------- + +func _on_pokemon_pressed(data : PokemonData) -> void: + var team : PokemonTeam = GameData.player_team + if team.is_full(): + _message.text = "Équipe pleine (%d/%d)" % [team.size(), PokemonTeam.MAX_SIZE] + return + + var pokemon := PokemonInstance.create(data, int(_level_spin.value)) + GameData.give_pokemon(pokemon) + _message.text = "%s Lv.%d ajouté (%d/%d)" % [pokemon.get_display_name(), pokemon.level, team.size(), PokemonTeam.MAX_SIZE] + _refresh_team() + +func _on_clear_pressed() -> void: + var team : PokemonTeam = GameData.player_team + while !team.is_empty(): + team.remove_at(team.size() - 1) + GameData.validate_selection() + _message.text = "Équipe vidée" + _refresh_team() + +func _on_heal_pressed() -> void: + GameData.player_team.heal_all() + _message.text = "Équipe soignée" + +func _on_filter_changed(text : String) -> void: + var needle : String = text.strip_edges().to_lower() + for b in _buttons: + b.visible = needle == "" or needle in String(b.get_meta("search")) + +func _refresh_team() -> void: + var team : PokemonTeam = GameData.player_team + if team.is_empty(): + _team_label.text = "Équipe : (vide)" + return + var names : Array[String] = [] + for p in team.members: + names.append("%s Lv.%d" % [p.get_display_name(), p.level]) + _team_label.text = "Équipe (%d/%d) : %s" % [team.size(), PokemonTeam.MAX_SIZE, ", ".join(names)] diff --git a/game/debug/debug_pokemon_panel.gd.uid b/game/debug/debug_pokemon_panel.gd.uid new file mode 100644 index 0000000..e1738d4 --- /dev/null +++ b/game/debug/debug_pokemon_panel.gd.uid @@ -0,0 +1 @@ +uid://b3058rssf6ud5 diff --git a/project.godot b/project.godot index 6dc7a03..19cf74b 100644 --- a/project.godot +++ b/project.godot @@ -27,6 +27,7 @@ ControllerIcons="*uid://b7ho1rjcpht1d" GameData="*uid://d4beiel88cwc7" UiAudio="*uid://7e7fe2xk3aue" Pokedex="*uid://dijnkrewbwgmx" +DebugPokemonPanel="*uid://b3058rssf6ud5" [display]