feat: modèle Party et modes de contrôle (#49) #59

Merged
Reliodas merged 1 commit from feature/49-party-model into develop 2026-06-22 03:09:33 +00:00
Owner

Closes #49.

Introduit le modèle de domaine Party, première pierre du jalon 0.16.0 « Un groupe contrôlable ». Il remplace progressivement l'hypothèse d'un héros unique sans coupler les Creature aux Node de scène : GameState.party devient la source de vérité runtime et GameState.hero n'est plus qu'une façade transitoire vers le membre protagonist. Le solo 0.15.0 (création de personnage, sauvegarde, combat) reste inchangé. Cette base débloque le recrutement (#51), l'exploration leader/suiveurs (#52) et le combat multi-acteurs (#54).

Changements

  • Nouveau modèle pur PartyMember (scripts/party/party_member.gd) : une Creature, un member_id stable et un control_mode (PLAYER / AUTO_ALLY / SCRIPTED_GUEST). Le mode de contrôle est orthogonal à l'équipe de combat — on ne déduit jamais Creature.team du mode. La Creature se remplace via replace_creature, l'identifiant ne change jamais.
  • Nouveau modèle pur Party (scripts/party/party.gd) distinguant trois cercles emboîtés — roster ⊇ actif ⊇ présents — avec un leader. Ordres déterministes (tableaux d'ids, jamais Dictionary.values()), collections renvoyées en copies, opérations atomiques : toute opération invalide renvoie false sans laisser d'état partiel. Réaffectation déterministe du leader quand il quitte l'actif.
  • GameState : hero devient une propriété calculée vers le membre protagonist (créé actif, joueur, leader) ; ajout de GameState.party (lecture seule) et de GameState.reset_party(). begin_new_game, reset_run et apply_save réinitialisent explicitement le groupe pour ne jamais conserver de compagnon résiduel d'une session précédente.
  • Setups de tests utilisant GameState.hero = null comme nettoyage global migrés vers GameState.reset_party().

Critères d'acceptation

  • roster, groupe actif et présence sont trois notions distinctes et testées ;
  • chaque membre conserve sa Creature et un identifiant stable ;
  • un leader appartient nécessairement au groupe actif ;
  • les modes de contrôle sont représentés sans dépendance à une scène ;
  • les invariants empêchent doublons et références invalides ;
  • aucune nouvelle fonctionnalité 0.16.0 ne dépend directement de GameState.hero lorsqu'une API Party suffit.

Tests

Suite GUT complète verte : 213 tests / 687 assertions (depuis 189 / 599).

  • tests/unit/test_party.gd : roster/actif/présent, ordre déterministe, ids vides et doublons, même Creature inscrite deux fois, références inconnues, retrait en cascade, réaffectation du leader, orthogonalité du mode de contrôle.
  • tests/unit/test_game_state_party.gd : façade hero (création/remplacement du protagoniste, actif/joueur/leader, hero = null n'efface que le protagoniste, begin_new_game vide le groupe, apply_save 0.15.0 remplace un groupe préexistant, ensure_hero conserve la même Creature).
Closes #49. Introduit le modèle de domaine `Party`, première pierre du jalon 0.16.0 « Un groupe contrôlable ». Il remplace progressivement l'hypothèse d'un héros unique sans coupler les `Creature` aux `Node` de scène : `GameState.party` devient la source de vérité runtime et `GameState.hero` n'est plus qu'une façade transitoire vers le membre `protagonist`. Le solo 0.15.0 (création de personnage, sauvegarde, combat) reste inchangé. Cette base débloque le recrutement (#51), l'exploration leader/suiveurs (#52) et le combat multi-acteurs (#54). ## Changements - Nouveau modèle pur **`PartyMember`** (`scripts/party/party_member.gd`) : une `Creature`, un `member_id` stable et un `control_mode` (`PLAYER` / `AUTO_ALLY` / `SCRIPTED_GUEST`). Le mode de contrôle est **orthogonal à l'équipe de combat** — on ne déduit jamais `Creature.team` du mode. La `Creature` se remplace via `replace_creature`, l'identifiant ne change jamais. - Nouveau modèle pur **`Party`** (`scripts/party/party.gd`) distinguant trois cercles emboîtés — **roster ⊇ actif ⊇ présents** — avec un **leader**. Ordres déterministes (tableaux d'ids, jamais `Dictionary.values()`), collections renvoyées en copies, opérations atomiques : toute opération invalide renvoie `false` sans laisser d'état partiel. Réaffectation déterministe du leader quand il quitte l'actif. - **`GameState`** : `hero` devient une **propriété calculée** vers le membre `protagonist` (créé actif, joueur, leader) ; ajout de `GameState.party` (lecture seule) et de `GameState.reset_party()`. `begin_new_game`, `reset_run` et `apply_save` réinitialisent explicitement le groupe pour ne jamais conserver de compagnon résiduel d'une session précédente. - Setups de tests utilisant `GameState.hero = null` comme nettoyage global migrés vers `GameState.reset_party()`. ## Critères d'acceptation - [x] roster, groupe actif et présence sont trois notions distinctes et testées ; - [x] chaque membre conserve sa Creature et un identifiant stable ; - [x] un leader appartient nécessairement au groupe actif ; - [x] les modes de contrôle sont représentés sans dépendance à une scène ; - [x] les invariants empêchent doublons et références invalides ; - [x] aucune nouvelle fonctionnalité 0.16.0 ne dépend directement de GameState.hero lorsqu'une API Party suffit. ## Tests Suite GUT complète verte : **213 tests / 687 assertions** (depuis 189 / 599). - `tests/unit/test_party.gd` : roster/actif/présent, ordre déterministe, ids vides et doublons, même `Creature` inscrite deux fois, références inconnues, retrait en cascade, réaffectation du leader, orthogonalité du mode de contrôle. - `tests/unit/test_game_state_party.gd` : façade `hero` (création/remplacement du protagoniste, actif/joueur/leader, `hero = null` n'efface que le protagoniste, `begin_new_game` vide le groupe, `apply_save` 0.15.0 remplace un groupe préexistant, `ensure_hero` conserve la même `Creature`).
feat: introduit le modèle Party et les modes de contrôle (#49)
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
b54c44f2e9
Ajoute deux modèles de jeu purs sous scripts/party/ :

- PartyMember : Creature + identifiant stable + mode de contrôle
  (PLAYER/AUTO_ALLY/SCRIPTED_GUEST), orthogonal à l'équipe de combat ;
- Party : roster ⊇ actif ⊇ présents avec leader, ordres déterministes
  et opérations atomiques (toute opération invalide renvoie false).

GameState.party devient la source de vérité runtime ; GameState.hero
n'est plus qu'une façade calculée vers le membre « protagonist » (actif,
joueur, leader). Ajoute GameState.reset_party() ; begin_new_game,
reset_run et apply_save l'utilisent pour ne jamais conserver de
compagnon résiduel. Le solo 0.15.0 reste inchangé.

Tests : test_party.gd et test_game_state_party.gd (suite 213 tests verte).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reliodas merged commit b7f01f80ce into develop 2026-06-22 03:09:33 +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#59
No description provided.