feat: permettre au joueur de choisir sa cible parmi plusieurs ennemis (#27) #34

Merged
Reliodas merged 1 commit from feature/27-selection-cible into develop 2026-06-20 10:49:02 +00:00
Owner

Closes #27

Le contrôleur acceptait déjà plusieurs ennemis et les jetons attaquables étaient surlignés, mais le bouton Attaquer appelait player_attack() sans cible : le contrôleur frappait automatiquement la première cible valide, et le panneau de PV ennemi restait lié au seul ennemi primaire. Cette MR rend la sélection de cible explicite.

Changements

  • scripts/combat_controller.gd : selected_target + select_target(creature) (n'accepte qu'une cible attaquable ce tour). player_attack(target) refuse une cible non valide / morte / hors portée / hors vue sans consommer l'Action (plus de repli automatique sur la première). Cible par défaut = l'unique cible attaquable (cas 1v1 direct) ; avec plusieurs ennemis et aucune sélection, l'attaque est refusée jusqu'au choix. selected_target est remise à zéro à chaque tour et invalidée après un déplacement ou une mort (_validate_selected_target). Nouveau has_attack_target() pour piloter l'activation du bouton.
  • scenes/exploration/world.gd : au tour du joueur hors mode déplacement, le clic gauche est converti en cellule (_cell_at) puis résolu via les tables de participants (_creature_at_cell) — pas via un événement reçu par Enemy, qui reste un simple Node2D. Un jeton attaquable sous le clic est sélectionné (select_target).
  • scenes/exploration/enemy.gd : état « sélectionné » distinct (set_selected, teinte orange) qui prime sur l'état « attaquable » (doré), retiré quand la cible devient invalide.
  • scenes/combat/combat_overlay.gd : _on_attack transmet _controller.selected_target ; le panneau de PV ennemi suit la cible sélectionnée (rebind au changement), à défaut l'ennemi primaire (mono-ennemi inchangé). Les boutons (Control) consomment leurs propres clics : un clic sur la barre d'actions n'atteint pas le gestionnaire d'arrière-plan de World.

Critères d'acceptation

  • le joueur sélectionne explicitement un jeton ennemi attaquable ;
  • l'attaque est transmise à player_attack avec la Creature choisie ;
  • une cible non valide, morte, hors portée ou hors vue est refusée sans dépenser l'Action ;
  • le panneau / retour UI affiche la cible sélectionnée ;
  • le cas un seul ennemi reste direct et ergonomique ;
  • un test couvre deux ennemis simultanément attaquables et confirme lequel reçoit les dégâts.

Tests

  • tests/unit/test_combat_controller.gd : test_select_target_directs_damage_to_chosen_enemy (deux cibles, la choisie encaisse, l'autre intacte), test_default_target_when_single_attackable, test_no_default_target_with_multiple_attackable, test_invalid_explicit_target_refused_without_spending_action, test_move_invalidates_out_of_reach_selection ; test_attack_only_targets_adjacent_enemy mis à jour (refus sans dépense d'Action) et la boucle multi-ennemis sélectionne désormais une cible.
  • Suite GUT complète verte : 162 tests, 510 assertions.
Closes #27 Le contrôleur acceptait déjà plusieurs ennemis et les jetons attaquables étaient surlignés, mais le bouton Attaquer appelait `player_attack()` **sans cible** : le contrôleur frappait automatiquement la première cible valide, et le panneau de PV ennemi restait lié au seul ennemi primaire. Cette MR rend la sélection de cible explicite. ## Changements - `scripts/combat_controller.gd` : `selected_target` + `select_target(creature)` (n'accepte qu'une cible **attaquable** ce tour). `player_attack(target)` **refuse** une cible non valide / morte / hors portée / hors vue **sans consommer l'Action** (plus de repli automatique sur la première). Cible par défaut = l'**unique** cible attaquable (cas 1v1 direct) ; avec plusieurs ennemis et aucune sélection, l'attaque est refusée jusqu'au choix. `selected_target` est remise à zéro à chaque tour et invalidée après un déplacement ou une mort (`_validate_selected_target`). Nouveau `has_attack_target()` pour piloter l'activation du bouton. - `scenes/exploration/world.gd` : au tour du joueur hors mode déplacement, le clic gauche est converti en cellule (`_cell_at`) puis résolu via les tables de participants (`_creature_at_cell`) — pas via un événement reçu par `Enemy`, qui reste un simple `Node2D`. Un jeton attaquable sous le clic est sélectionné (`select_target`). - `scenes/exploration/enemy.gd` : état « sélectionné » distinct (`set_selected`, teinte orange) qui prime sur l'état « attaquable » (doré), retiré quand la cible devient invalide. - `scenes/combat/combat_overlay.gd` : `_on_attack` transmet `_controller.selected_target` ; le panneau de PV ennemi suit la cible sélectionnée (rebind au changement), à défaut l'ennemi primaire (mono-ennemi inchangé). Les boutons (Control) consomment leurs propres clics : un clic sur la barre d'actions n'atteint pas le gestionnaire d'arrière-plan de `World`. ## Critères d'acceptation - [x] le joueur sélectionne explicitement un jeton ennemi attaquable ; - [x] l'attaque est transmise à `player_attack` avec la `Creature` choisie ; - [x] une cible non valide, morte, hors portée ou hors vue est refusée sans dépenser l'Action ; - [x] le panneau / retour UI affiche la cible sélectionnée ; - [x] le cas un seul ennemi reste direct et ergonomique ; - [x] un test couvre deux ennemis simultanément attaquables et confirme lequel reçoit les dégâts. ## Tests - `tests/unit/test_combat_controller.gd` : `test_select_target_directs_damage_to_chosen_enemy` (deux cibles, la choisie encaisse, l'autre intacte), `test_default_target_when_single_attackable`, `test_no_default_target_with_multiple_attackable`, `test_invalid_explicit_target_refused_without_spending_action`, `test_move_invalidates_out_of_reach_selection` ; `test_attack_only_targets_adjacent_enemy` mis à jour (refus sans dépense d'Action) et la boucle multi-ennemis sélectionne désormais une cible. - Suite GUT complète verte : **162 tests, 510 assertions**.
feat: permettre au joueur de choisir sa cible parmi plusieurs ennemis (#27)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful
a11914f2aa
Le bouton Attaquer appelait player_attack() sans cible, le contrôleur frappant
la première cible valide ; le panneau de PV ennemi restait lié au primaire.
Ajout de CombatController.selected_target + select_target() (cible attaquable
seulement) ; player_attack(target) refuse une cible invalide/morte/hors
portée/hors vue sans consommer l'Action, la cible par défaut restant l'unique
ennemi attaquable (1v1 inchangé), et la sélection s'invalide après
déplacement/mort/changement de tour. World convertit le clic gauche en cellule
(_creature_at_cell) pour sélectionner le jeton attaquable ; Enemy.set_selected
ajoute une surbrillance distincte ; l'overlay transmet la cible et fait suivre
le panneau de PV ennemi.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reliodas merged commit 657daea97f into develop 2026-06-20 10:49:02 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: jeux/beaulieu-sur-brume#34
No description provided.