# Plan d'implémentation – Specs Animaux, Morts, Saisons, Billeterie

Références : `docs/plan-action-cahier-des-charges.md` (§7 Animaux/morts/saisons, §8 Billeterie), `docs/features/causes-mort-audit.md`, et tous les fichiers de `docs/specs/` concernés.

---

## Spécifications couvertes

| Spec | Périmètre implémenté |
|------|----------------------|
| **animal_generique.md** | États faim/température/santé ; feedbacks visuels (froid=bleu/givre, chaud=rouge/vapeur, faim=icône, heureux=cœurs) ; pas de jauges. |
| **mort_bebe.md** | Causes déjà en place ; conséquence mort adulte vente échouée (aligné). |
| **inventaire_saisons.md** | Cycle 4 saisons ; modificateurs météo/température/reproduction/survie/visiteurs. |
| **temperature.md** | Modificateur saison (+0 Printemps, +10 Été, -2 Automne, -15 Hiver) ; modificateur jour/nuit (+5 jour, -5 nuit) ; feedback critique (spec déjà partiellement en place via tolerance). |
| **reproduction.md** | Impact saisons : Printemps +20% chance, Hiver -50% (sauf animaux froids). |
| **billeterie.md** | Flux entrée/sortie ; capacité 20/unité ; ouverture 08h–20h ; 1 visiteur/s max entrée ; modificateurs saison (été +20% prix, hiver -10%). |
| **visiteur.md** | Arrivée par billeterie ; durée max (1 journée / stayDuration) ; départ par billeterie ; affluence selon heure (08h–10h faible, 10h–16h fort, >18h nul) ; multiplicateur saison (été x1.5, hiver x0.6, etc.). |
| **inventaire_heures.md** | Cycle jour/nuit (déjà timeOfDay) ; billeterie fermée la nuit. |
| **centre_recherche.md** | Niveau recherche (skill level) : si rareté animal > niveau recherche → mort (cause « niveau de recherche trop inférieur »). |
| **causes-mort-audit.md** | Seuls (animal seul meurt) ; recherche trop basse ; vente adulte échouée (deathCountRecent). |

---

## Phase 1 – Causes de mort manquantes

**Objectif :** Compléter les causes de mort listées dans `docs/features/causes-mort-audit.md` (Non implémenté).

### 1.1 Vente adulte échouée

- **Fichier :** `web/js/trade.js`
- **Changement :** Dans `tickSaleListings`, lorsque `nowUnix >= listing.endAt` et `listing.isBaby === false`, incrémenter `state.deathCountRecent` (comme pour les bébés).
- **Spec :** causes-mort-audit §9.

### 1.2 Niveau de recherche trop inférieur

- **Fichier :** `web/js/food.js` (ou module commun appelé par `checkDeathCauses`)
- **Logique :** Pour chaque bloc animal sur la grille, récupérer `LootTables.Animals[cell.id].rarityLevel` et le comparer à `getSkillLevel(state)` (depuis `conveyor.js`). Si `rarityLevel > getSkillLevel(state)`, retirer le bloc et incrémenter `deathCountRecent`.
- **Config optionnelle :** `GameConfig.Research?.MaxRarityAllowed` ou utiliser directement skill level (1–8) vs rarityLevel (1–5) ; si le projet utilise skill level comme “niveau école” et que la spec centre_recherche parle de “rareté visible”, interpréter : animal de rareté > niveau compétence → mort.
- **Fichiers :** `web/js/food.js`, `web/js/config.js` (si config ajoutée), `docs/features/causes-mort-audit.md` (mise à jour).

### 1.3 Animal seul (solitude)

- **Spec :** animal_generique “Besoin de congénères (reproduction) ou de solitude (selon espèce)” ; causes-mort-audit §1 “Seuls”.
- **Interprétation :** Au moins une règle “animal seul meurt” : si aucun autre animal de la même espèce (même `cell.id`) dans un rayon de N cases (ex. 5), après un délai configurable, retirer l’animal et incrémenter `deathCountRecent`.
- **Fichiers :** `web/js/config.js` (`Animal.MinSameSpeciesInRadius`, `Animal.MaxSecondsAlone`), `web/js/food.js` dans `checkDeathCauses` (ou helper) : pour chaque origine animal, compter les autres blocs même `id` dans le rayon ; si 0 et `nowUnix - placedAt > MaxSecondsAlone`, retirer.
- **État :** Optionnel si “selon espèce” complique (toutes espèces = besoin congénères par défaut).

---

## Phase 2 – Config et données saisons

**Objectif :** Introduire le cycle de saisons et la config sans encore brancher tous les impacts.

### 2.1 Config saisons

- **Fichier :** `web/js/config.js`
- **Ajout :** `Season: { DayLengthSeconds: 120, DaysPerSeason: 7 }` (ou 30 jours in-game). `Season.TemperatureModifier: { spring: 0, summer: 10, autumn: -2, winter: -15 }`. `Season.VisitorMultiplier: { spring: 1, summer: 1.5, autumn: 0.8, winter: 0.6 }`. `Season.ReproductionBonus: { spring: 0.2, summer: 0, autumn: 0, winter: -0.5 }` (Hiver -50% sauf animaux froids à traiter dans reproduction).
- **Référence :** `docs/specs/inventaire_saisons.md`, `temperature.md`, `visiteur.md`, `reproduction.md`.

### 2.2 State et temps de jeu “jour”

- **Fichier :** `web/js/types.js`
- **Ajout :** `gameDay?: number` (jour de jeu absolu, dérivé de `timeOfDay` et `DayLengthSeconds`) ou `season?: 'spring'|'summer'|'autumn'|'winter'`, `seasonDay?: number` (jour dans la saison).
- **Fichier :** `web/js/time-weather.js` ou nouveau `web/js/seasons.js`
- **Logique :** À partir de `state.timeOfDay` et `GameConfig.Time.DayLengthSeconds`, calculer un “game day” (entier). À partir de `gameDay` et `DaysPerSeason`, calculer `season` et `seasonDay`. Exporter `getCurrentSeason(state)`, `getSeasonTemperatureModifier(season)`, `getSeasonVisitorMultiplier(season)`, `getSeasonReproductionBonus(season)`.

---

## Phase 3 – Cycle saisons et impacts

**Objectif :** Brancher la saison sur température, reproduction, visiteurs, billeterie.

### 3.1 Température affichée / calculée avec saison

- **Fichiers :** `web/js/placement.js` ou module température existant (ex. `getDisplayTemperature` dans food.js / grid-utils)
- **Changement :** `currentTemp = baseBiomeTemp + seasonMod + dayNightMod + caseRegulatorOffset`. Récupérer `seasonMod` depuis `getSeasonTemperatureModifier(getCurrentSeason(state))`.
- **Spec :** `temperature.md` (Impact Saisons, Impact Heure / Jour-Nuit).

### 3.2 Reproduction et saison

- **Fichier :** `web/js/reproduction.js`
- **Changement :** Intégrer un bonus/malus de saison (Printemps +20%, Hiver -50% sauf animaux “froids” selon biome) dans le calcul de chance de reproduction.
- **Spec :** `reproduction.md`, `inventaire_saisons.md`.

### 3.3 Visiteurs et saison

- **Fichier :** `web/js/income.js`
- **Changement :** Dans `getVisitorDemand`, multiplier par `getSeasonVisitorMultiplier(getCurrentSeason(state))`.
- **Spec :** `visiteur.md` (Impact Saisons).

### 3.4 Billeterie – modificateur prix ticket par saison

- **Fichier :** `web/js/income.js` (ou economy)
- **Changement :** Prix ticket base ; si saison été : *1.2 ; si saison hiver : *0.9. Appliquer dans le calcul de `paymentPerVisitor` (entrée).
- **Spec :** `billeterie.md` (Impact Saisons).

### 3.5 Notification changement de saison

- **Fichier :** `web/js/ui.js` ou game-loop
- **Changement :** Lors d’un changement de saison (comparer `getCurrentSeason(state)` à une valeur stockée), afficher un message type “C’est le [Saison] !” (toast ou texte temporaire). Stocker `lastSeason` dans le state si nécessaire.
- **Spec :** `inventaire_saisons.md` (Messages SEASON_CHANGE).

---

## Phase 4 – Flux billeterie complet

**Objectif :** Heures d’ouverture, départs explicites, limite 1 visiteur/s à l’entrée.

### 4.1 Heures d’ouverture (08h–20h)

- **Fichier :** `web/js/config.js`
- **Ajout :** `Billeterie.OpenHour: 8`, `Billeterie.CloseHour: 20` (ou 20h = fermeture, pas d’entrée après).
- **Fichier :** `web/js/income.js`
- **Changement :** Dans `tickVisitorArrivals`, ne pas ajouter de nouveaux visiteurs si `timeOfDay` est en dehors de [8, 20] (ou équivalent en phase “night”). Utiliser `getTimePhase(state.timeOfDay)` ; si phase “night” ou `timeOfDay < 8` ou `timeOfDay >= 20`, ne pas pousser de nouveaux `{ arrivedAt }`.
- **Spec :** `billeterie.md`, `inventaire_heures.md`.

### 4.2 Départs par billeterie (durée max “1 journée”)

- **Déjà en place :** `getStayDurationSeconds` et filtre `nowUnix < v.arrivedAt + stayDuration`. S’assurer que la durée est bien “1 journée” (DayLengthSeconds × facteur) selon spec. Optionnel : faire partir les visiteurs vers la “sortie” (billeterie) visuellement.
- **Spec :** `visiteur.md` (Durée max, Départ).

### 4.3 Limite 1 visiteur / seconde à l’entrée

- **Fichier :** `web/js/income.js`
- **Changement :** Dans `tickVisitorArrivals`, au lieu d’ajouter `target - current` d’un coup, limiter le nombre d’entrées sur ce tick à au plus `ceil(dt)` ou 1 par tick si tick = 1s, ou stocker `lastVisitorSpawnAt` et n’ajouter qu’un visiteur par seconde réelle. Adapter selon `IncomeTickMs` (ex. si tick 5s, ajouter au plus 5 nouveaux visiteurs par tick, ou 1 par seconde en interpolant).
- **Spec :** `billeterie.md` (“1 visiteur / seconde max”).

### 4.4 Affluence selon l’heure (optionnel)

- **Fichier :** `web/js/income.js`
- **Changement :** Dans `getVisitorDemand`, appliquer un coefficient selon `timeOfDay` : 08h–10h faible, 10h–16h fort, 16h–18h décroissant, >18h nul (ou très faible). Utiliser `state.timeOfDay` et `getTimePhase`.
- **Spec :** `visiteur.md` (Impact Heure / Jour-Nuit).

---

## Phase 5 – Feedbacks visuels animaux

**Objectif :** Pas de jauges ; états visuels dérivés des données existantes (température, nourriture, visite, reproduction).

### 5.1 Détection des états par cellule animal

- **Fichier :** nouveau `web/js/animal-visual-state.js` ou dans `web/js/ui.js` / module rendu
- **Logique :** Pour une cellule animal (origine) : `getDisplayTemperature`, `lastFedAt`, `lastVisitedAt`, état reproduction (paire proche). Exporter `getAnimalVisualState(cell, state, grid)` → `{ cold: boolean, hot: boolean, hungry: boolean, sick: boolean, happy: boolean }` (sick si proche mort / mal nourri ; happy si récemment visité et nourri et temp ok, ou en reproduction).
- **Spec :** `animal_generique.md`, `temperature.md` (Feedback critique).

### 5.2 Rendu CSS / classes

- **Fichier :** `web/js/ui.js` (rendu grille)
- **Changement :** Pour chaque bloc animal rendu, ajouter des classes CSS selon `getAnimalVisualState` : ex. `animal-cold`, `animal-hot`, `animal-hungry`, `animal-sick`, `animal-happy`. Pas de jauges.
- **Fichier :** `web/css/main.css`
- **Changement :** Styles pour ces classes : teinte bleutée/givre (froid), rougeâtre/vapeur (chaud), icône faim (lent/maigre), ternes/mouches (malade), cœurs/couleurs vives (heureux). Utiliser filter, box-shadow ou pseudo-éléments pour icônes.
- **Spec :** `animal_generique.md` (Vie Quotidienne), `temperature.md` (Feedback critique).

---

## Phase 6 – Documentation et clôture

- Mettre à jour `docs/features/causes-mort-audit.md` (causes implémentées : seuls, recherche, vente adulte).
- Créer ou mettre à jour `docs/features/saisons-phase.md` (cycle, config, impacts).
- Créer ou mettre à jour `docs/features/billeterie-flux.md` (heures, 1/s, départs).
- Créer `docs/features/feedbacks-visuels-animaux.md` (états, classes CSS, pas de jauges).
- Vérifier lint, types, compilation.

---

## Ordre d’exécution recommandé

1. **Phase 1** – Causes de mort (trade.js adulte, food.js recherche, optionnel solitude).
2. **Phase 2** – Config et module saisons (config.js, seasons.js, types.js).
3. **Phase 3** – Impacts saisons (température, reproduction, visiteurs, billeterie, notification).
4. **Phase 4** – Flux billeterie (heures, 1/s, affluence heure).
5. **Phase 5** – Feedbacks visuels animaux (animal-visual-state.js, ui.js, main.css).
6. **Phase 6** – Documentation.

---

## Fichiers principaux impactés

| Fichier | Phases |
|---------|--------|
| `web/js/trade.js` | 1.1 |
| `web/js/food.js` | 1.2, 1.3 |
| `web/js/config.js` | 1.2, 1.3, 2.1, 4.1 |
| `web/js/types.js` | 2.2 |
| `web/js/time-weather.js` ou `web/js/seasons.js` | 2.2, 3.1 |
| `web/js/placement.js` ou module température | 3.1 |
| `web/js/reproduction.js` | 3.2 |
| `web/js/income.js` | 3.3, 3.4, 4.1, 4.3, 4.4 |
| `web/js/ui.js` | 3.5, 5.2 |
| `web/js/animal-visual-state.js` (nouveau) | 5.1 |
| `web/css/main.css` | 5.2 |
| `docs/features/*.md` | 6 |
