Initial: desk + ncantu placeholder + per-project cursor configs

**Motivations:**
- Centraliser les fichiers Cursor (rules, skills, agents, commands, hooks) par user et par projet

**Root causes:**
- N/A

**Correctifs:**
- N/A

**Evolutions:**
- desk: rules, skills-cursor, agents, commands, hooks, argv/hooks/mcp.json
- ncantu: README placeholder
- 4NK_node, algo, builazoo, ia_local, lecoffre_ng, lecoffre_ng_pprod, lecoffre_ng_test: .cursor contents

**Pages affectées:**
- cursor/desk/, cursor/ncantu/, cursor/<project>/
This commit is contained in:
2026-03-03 23:29:29 +01:00
commit 785868b53b
114 changed files with 6455 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
# Plan Cursor Action cahier des charges
Exécution dans lordre : BLOC 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10 → 11.
Référence : `docs/plan-action-cahier-des-charges.md` et `docs/cahier des charges.md`.
---
## BLOC 1 Grille au lancement + 3 couples reproducteurs (§1, §10)
**FILES:** `web/js/state.js` | `web/js/config.js` | `web/js/placement.js` | `web/js/grid-utils.js` | `web/js/main-bootstrap.js` | `web/js/loot-tables.js`
**STEPS:**
1. Définir en config (ou dans `state.js`) le **layout de grille zoo au premier lancement** : positions fixes pour 1 Recherche, 1 Billeterie, 1 Nurserie, 1 Accueil, 1 Nourriture, 1 Camion, 1 zone Agrandissement zoo, et 24 cases vides avec 3 couleurs/biomes.
2. Adapter `buildDefaultCells()` pour générer cette grille (au lieu de seulement school 1_1 + nursery 2_1). Inclure research, billeterie, food, reception, plotUpgrade (agrandissement zoo), et 24 cases avec biome réparti sur 3 couleurs.
3. Au premier démarrage (nouveau zoo ou `defaultState()`), **placer 3 couples reproducteurs** : choisir des animaux basiques selon biome de départ (ex. depuis loot-tables), placer sur des cases vides de la grille (ou en pendingBabies/reception si pas assez de place). Définir quels animalIds = « basiques » par biome.
4. Documenter le **layout carte du monde au lancement** (§11) : compteurs (bébés, animaux, labos, zoos, villes), cases Accueil/Nourriture/Camion, 24 cases 3 couleurs. Implémenter si lUI actuelle en dévie.
5. Créer ou mettre à jour une fiche `docs/features/grille-lancement.md` (objectif, impacts, modifications, déploiement, analyse).
**DONE_WHEN:** Nouveau zoo démarre avec grille complète (recherche, billeterie, nurserie, accueil, nourriture, camion, 24 cases 3 couleurs) et 3 couples reproducteurs placés ; doc à jour.
---
## BLOC 2 Ventes : validation différée 10 min + sablier (§13)
**FILES:** `server/migrations/` | `server/db.js` | `server/routes/sales.js` | `web/js/api-client.js` | `web/js/ui.js` | `web/js/types.js` | `docs/features/ventes-encheres-phase10.md`
**STEPS:**
1. **Migration BDD** : ajouter sur `sale_listings` un champ `validated_at TIMESTAMPTZ` (NULL = pas encore validé définitivement). Conserver `sold_at` = date dacceptation par le vendeur. Statut intermédiaire : `sold_pending` ou utiliser `validated_at IS NULL AND sold_at IS NOT NULL`.
2. **Logique serveur** : à laccept, ne pas transférer les pièces immédiatement ; enregistrer `sold_at = now()`, `validated_at = now() + 10 minutes`. Créer un traitement (cron ou à la lecture) qui pour les lignes `sold_at IS NOT NULL AND validated_at IS NOT NULL AND validated_at <= now()` effectue le transfert de pièces (buyer -= amount, seller += amount) et marque la vente comme validée (ex. `validated_at` déjà renseigné ou champ `status = 'validated'`). Lacheteur ne peut appeler `deliver` quaprès validation.
3. **API** : exposer `validated_at` et/ou temps restant pour chaque vente (asSeller, asBuyerUndelivered). Le client calcule « en attente de validation » si `sold_at` présent et `validated_at` dans le futur.
4. **Client** : afficher un **sablier** (ou compte à rebours) pour les ventes vendues mais pas encore validées ; désactiver « Récupérer » jusquà `validated_at <= now`. Après validation, comportement actuel (Récupérer disponible).
5. Mettre à jour `docs/features/ventes-encheres-phase10.md` (validation différée, sablier, migration).
**DONE_WHEN:** Acceptation met la vente en attente 10 min ; transfert de pièces et possibilité de récupérer uniquement après 10 min ; sablier visible côté client.
---
## BLOC 3 Mode automatique : 50 profils et UI hiérarchique (§5)
**FILES:** `web/js/types.js` | `web/js/auto-mode-profiles.js` (new) | `web/js/bot-zoo.js` | `web/js/game-loop.js` | `web/js/ui.js` | `web/js/texts-fr.js`
**STEPS:**
1. Créer **web/js/auto-mode-profiles.js** : modèle des 50 profils (id, famille, spécialisation, libellé, paramètres : seuil dépense, fréquence, types danimaux préférés, etc., priorité et risques en clés i18n). Familles : Conservateurs (110), Éleveurs (1120), Commerçants (2130), Expansionnistes (3140), Scientifiques (4150).
2. **types.js** : étendre le state pour stocker le profil choisi (ex. `autoModeProfileId: string` ou `autoModeFamily` + `autoModeSpecialisation`) ; garder rétrocompat avec `autoModeProfile` pour migration.
3. **bot-zoo.js** / **game-loop.js** : adapter la logique mode auto pour utiliser les paramètres du profil sélectionné (seuils, fréquences, priorités) au lieu des 3 profils fast/slow/balanced uniquement. Mapper les 50 profils vers les paramètres numériques utilisés par `playerAutoDoOneUpgrade` et les décisions bot.
4. **ui.js** : ajouter une **interface de sélection hiérarchique** : étape 1 = choix de la Famille (5 boutons ou cartes), étape 2 = choix de la Spécialisation dans la famille (liste des 10 profils), affichage des priorités et risques pour le profil sélectionné. Remplacer ou compléter le simple toggle mode auto par louverture de cette interface (ex. au clic sur le bouton mode auto quand inactif).
5. **texts-fr.js** : ajouter les libellés des 5 familles, des 50 spécialisations, et les textes priorités/risques par profil.
**DONE_WHEN:** 50 profils définis et sélectionnables via Famille → Spécialisation ; mode auto utilise le profil choisi ; libellés centralisés.
---
## BLOC 4 Visitor.MaxSecondsWithoutVisit + disparition animaux (§2)
**FILES:** `web/js/config.js` | `web/js/game-loop.js` | `web/js/income.js` ou module visiteurs | `web/js/state.js`
**STEPS:**
1. **config.js** : ajouter `Visitor.MaxSecondsWithoutVisit` (ex. 300 pour 5 min).
2. Dans la boucle de jeu (ou module qui gère les visites), pour chaque animal : si `now - lastVisitedAt > MaxSecondsWithoutVisit`, retirer lanimal de la grille et incrémenter `deathCountRecent` (ou appliquer la règle de mort « pas visité » déjà existante si présente).
3. Sassurer que `lastVisitedAt` est mis à jour quand un visiteur « visite » lanimal (vérifier income.js / visitor logic).
**DONE_WHEN:** Un animal non visité pendant la durée configurée est retiré et compte comme mort ; config lisible.
---
## BLOC 5 Interface : barre non reconstruite, erreur masquée (§4)
**FILES:** `web/js/ui.js`
**STEPS:**
1. **Barre** : identifier les parties dynamiques (indicateurs : pièces, parcelle, case, compétences, visiteurs, œufs, météo ; icônes musique, quêtes, prestige, restart, mode auto, vue zoo/monde). Ne pas recréer tout le DOM de la barre à chaque `setState()` ; ne mettre à jour que les nœuds dont le contenu change (ex. `statusBarCoins.valueEl.textContent`, etc.). Si le rendu actuel recrée tout le contenu à chaque appel, refactorer pour garder des références aux éléments et les mettre à jour dans une fonction dédiée (ex. `updateStatus()` déjà partiellement en place).
2. **Onglets** : vérifier quil ny a pas de titres « Carte du zoo » / « Carte du monde » affichés comme onglets ; garder uniquement le sélecteur icônes (🦒 / 🗺️). Supprimer ou masquer les titres donglets sils existent.
3. **Erreur** : sassurer que le message derreur est `hidden` ou `display: none` quand `errorMsg.current` est vide, et quil ne réserve pas despace (éviter un bloc vide visible).
**DONE_WHEN:** Barre mise à jour par mise à jour ciblée des indicateurs ; pas de titres donglets ; message derreur invisible et sans emprise quand vide.
---
## BLOC 6 Villes : formule attraction + cases (§3, §11)
**FILES:** `web/js/config.js` | `web/js/income.js` ou module attractivité | `web/js/ui.js` | `docs/features/villes-phase11.md`
**STEPS:**
1. Vérifier / implémenter la **formule dattraction** : proximité zooville + valeur des animaux. Config ou state pour le plafond « max visiteurs vers zoos » par ville (ex. sur chaque ville dans `GameConfig.WorldMap.Cities` : `maxVisitorsToZoos`).
2. **Carte du monde** : afficher pour chaque ville 1 case nom et 1 case « nombre max visiteurs vers zoos » (lecture depuis config ou state). Voir `docs/features/villes-phase11.md`.
3. Utiliser ce plafond dans le calcul des visiteurs alloués aux zoos (répartition ou limite depuis les villes).
**DONE_WHEN:** Villes affichent nom et max visiteurs ; formule dattraction et plafond pris en compte dans le flux visiteurs.
---
## BLOC 7 Stagnation (§3)
**FILES:** `web/js/config.js` | `web/js/income.js` | `web/js/state.js` | `web/js/game-loop.js`
**STEPS:**
1. Définir en config : délai sans action dévolution (ex. en secondes), plancher du multiplicateur (ex. 0.1 pour 10 %).
2. Suivre la **dernière action dévolution** par zoo (ou par joueur) : timestamp de dernière action (upgrade, achat, vente, placement, etc.). Stocker dans le state (ex. `lastEvolutionAt` déjà présent ; vérifier quil est mis à jour sur toutes les actions pertinentes).
3. Dans le calcul du nombre de visiteurs (ou du multiplicateur de revenus visiteurs), appliquer un **multiplicateur dégressif** : si `now - lastEvolutionAt > seuil`, réduire le multiplicateur jusquau plancher (interpolation linéaire ou par paliers).
**DONE_WHEN:** Zoos sans évolution depuis le délai configuré subissent une baisse du multiplicateur visiteurs jusquau plancher.
---
## BLOC 8 Incidents visiteurs + invités de luxe (§2)
**FILES:** `web/js/config.js` | `web/js/income.js` | `web/js/game-loop.js` | `web/js/ui.js` | `web/js/types.js` | `web/js/texts-fr.js`
**STEPS:**
1. **Incidents** : modéliser les types (soif, poubelle pleine, banc requis, animal trop loin, envie de photo). Associer à un visiteur (ex. `visitorArrivals[].incident?: string`, `incidentAt?: number`). Config : fréquence en phase dattente (camion en route, enchère en cours, éclosion longue).
2. **Affichage** : bulle dicône au-dessus du visiteur concerné ; au clic sur la bulle ou action correctrice (poser banc, etc.), marquer résolu et appliquer gain attractivité + pièces ; si ignoré, perte attractivité et départ prématuré.
3. **Invités de luxe** : config `Visitor.LuxuryShare` (ex. 0.08). Pour une part des visiteurs, flag `isLuxury` ; dans le calcul des revenus (entrée + boutique), appliquer un multiplicateur (ex. 1.5 ou 2) pour ces visiteurs.
**DONE_WHEN:** Incidents apparaissent, affichage bulle, résolution/ignorance avec impact ; 8 % des visiteurs paient plus (entrée + boutique).
---
## BLOC 9 Animaux : feedbacks visuels + causes de mort (§12)
**FILES:** `web/js/loot-tables.js` | `web/js/game-loop.js` | `web/js/income.js` | `web/js/ui.js` | `web/js/config.js` | `web/js/types.js`
**STEPS:**
1. **Feedbacks visuels** : à partir des données déjà calculées (température, nourriture, lastVisitedAt, etc.), dériver des états (froid, chaud, faim, maladie, heureux). Rendu : teinte CSS ou classe sur la case/sprite (bleuâtre/givre, rougeâtre/vapeur, icône faim, couché/ternes, cœurs/couleurs vives). Pas de jauges.
2. **Morts** : auditer le code (game-loop, trade, etc.) et comparer à la liste §12 (seuls, pas visités, nourriture, tué autre zoo, recherche trop basse, bébé non vendu à temps, bébé mature non placé à temps, animal accueil non placé à temps, vente échouée, température/milieu en écart). Implémenter les causes manquantes (délais, température, milieu).
3. Documenter dans `docs/features/` ou `docs/fixKnowledge/` les causes de mort et les règles associées.
**DONE_WHEN:** États visuels animaux affichés ; toutes les causes de mort du §12 branchées ou documentées comme différées.
---
## BLOC 10 Saisons (§12)
**FILES:** `web/js/config.js` | `web/js/state.js` | `web/js/game-loop.js` | `web/js/income.js` | `web/js/reproduction.js` | `web/js/ui.js` | `web/js/texts-fr.js`
**STEPS:**
1. Introduire une **saison** (Printemps, Été, Automne, Hiver) : dérivée du temps de jeu (ex. cycle sur N jours) ou de la date réelle. Stocker dans le state (ex. `season: string`).
2. Faire évoluer **météo** et **température** selon la saison (config : plages par saison). Adapter les formules de **reproduction** et **survie** (bonus/malus par type danimal et saison).
3. Affichage : indiquer la saison dans la barre ou sur la carte (texte ou icône).
**DONE_WHEN:** Les 4 saisons alternent ; météo/température et bonus/malus reproduction/survie dépendent de la saison ; affichage à jour.
---
## BLOC 11 Billeterie : flux complet (§7, §10)
**FILES:** `web/js/income.js` | `web/js/config.js` | `web/js/state.js` | `docs/features/`
**STEPS:**
1. Clarifier le **design** : arrivée des visiteurs depuis les villes → billeterie (cap 20 × niveau), durée max 1 journée par visiteur, départ par la billeterie, retour selon attractivité. Documenter dans `docs/features/billeterie-flux.md`.
2. Implémenter le flux dans le module visiteurs / income : génération des arrivées (selon attractivité et plafond villes), entrée via billeterie (cap), suivi du temps passé dans le zoo, départ avant fin de journée, réinjection vers les zoos selon attractivité.
**DONE_WHEN:** Flux arrivée → billeterie → séjour max 1 jour → départ → retour selon attractivité documenté et codé.
---
## Références transverses
- **Compatibilité** : `normalizeLoadedCells` / loadState (animal inconnu → c0_r0, œuf → Color_1) : à conserver.
- **Sécurité** : pas de confiance client, limitation fréquence, traçabilité (API/serveur).
- **BDD** : aligné avec `docs/bdd-comptes.md` pour schéma et flux 401/404/200.

View File

@@ -0,0 +1,208 @@
# Plan Cursor Rappel des grandes règles (174-324)
Exécution dans lordre : Phase 0 → 1 → 3 → 4 → 2 → 5 → 6 → 7 → 8 → 9 → 10 → 11 → 12 → 13.
Référence détaillée : `docs/plan-implementation-rappel-grandes-regles.md`.
---
## PHASE 0 Modèle de données et configuration
**FILES:** `web/js/types.js` | `web/js/config.js` | `web/js/state.js` | `web/js/loot-tables.js`
**STEPS:**
1. **types.js** Ajouter/étendre :
- `biome?: string` et `temperature?: number` sur les cases (ou sur la grille par case).
- Nouveaux kinds de cell : `research`, `billeterie`, `food`, `reception`, `biomeChangeColor`, `biomeChangeTemp`. Garder `souvenirShop` (alias boutique), `nursery`, camion reste zone/state.
- Types pour bébé/vente : `PendingBaby`, `ReceptionAnimal`, `SaleListing` (babyId/animalId, zooId, price, endAt, reproductionScoreAtSale?).
- Animal multi-case : sur `AnimalCell` ajouter `originKey?: string`, `cellsWide?: number`, `cellsHigh?: number` (optionnel, défaut 1).
- GameState : `researchPoints?: number`, `pendingBabies?: PendingBaby[]`, `receptionAnimals?: ReceptionAnimal[]`, `saleListings?: SaleListing[]`, `deathCountRecent?: number`, `birthCount?: number`, `feedingRate?: number`.
2. **config.js** Ajouter blocs (tous MaxLevel: 7 sauf si indiqué) :
- `Research: { MaxLevel: 7, ZoosPerUnit: 10, BaseUpgradeCost, UpgradeGrowth, PointsPerTickPerLevel }`
- `Billeterie: { MaxLevel: 7, VisitorsPerUnit: 20, BaseUpgradeCost, UpgradeGrowth }`
- `Food: { MaxLevel: 7, AnimalsPerUnit: 5, BaseUpgradeCost, UpgradeGrowth }`
- `Reception: { MaxLevel: 7, AnimalsPerUnit: 1, BaseUpgradeCost, UpgradeGrowth, AcclimatationSecondsBase }`
- `BiomeChangeColor: { MaxLevel: 7, BaseUpgradeCost, UpgradeGrowth }`
- `BiomeChangeTemp: { MaxLevel: 7, BaseUpgradeCost, UpgradeGrowth }`
- Mettre `Nursery.MaxLevel = 7`, `SouvenirShop.MaxLevel = 7`, `Truck.MaxLevel = 7`.
3. **state.js** Dans `defaultState()` : `researchPoints: 0`, `pendingBabies: []`, `receptionAnimals: []`, `saleListings: []`, `deathCountRecent: 0`, `birthCount: 0`. Prévoir cellules initiales pour recherche, billeterie, nourriture, accueil (voir phase 12 pour positions exactes).
4. **loot-tables.js** Pour chaque animal : `cellsWide: 1`, `cellsHigh: 1` (extensible en 2x2 plus tard), `idealTemperature?: number`, `temperatureTolerance?: number`, `reproductionScoreByBiome?: Record<string,number>`, `survivalScoreByBiome?: Record<string,number>`.
**DONE_WHEN:** Types compilent, config lue, defaultState contient les nouveaux champs, loot-tables exporte les champs animaux. Pas de régression sur le jeu actuel (ancien state reste valide).
---
## PHASE 1 Cartes : couleurs et températures
**FILES:** `web/js/biome-rules.js` | `web/js/grid-utils.js` | `web/css/main.css` | `web/js/ui.js`
**STEPS:**
1. Étendre biomes : eau douce, eau salée, montagne, prairie, forêt (au moins 5). Attribuer à chaque case un `biome` et un `temperature` (dérivés de la position ou stockés).
2. Exporter `getDisplayBiome(x, y, grid)` et `getDisplayTemperature(x, y, grid)` avec interpolation des voisins.
3. Rendu CSS : classes ou variables par biome et par plage de température ; dégradés entre cases.
4. Grille zoo et monde utilisent ces fonctions pour le fond des cases.
**DONE_WHEN:** Les cases affichent une couleur/milieu et une température avec transition douce.
---
## PHASE 3 Bâtiments zoo (7 niveaux)
**FILES:** `web/js/config.js` | `web/js/state.js` | `web/js/economy.js` | `web/js/placement.js` | `web/js/zoo.js` | `web/js/ui.js`
**STEPS:**
1. Coûts dupgrade pour research, billeterie, food, reception, biomeChangeColor, biomeChangeTemp (formules exponentielle comme Plot).
2. Placement : construction sur case vide pour research, billeterie, food, reception, biomeChangeColor, biomeChangeTemp. Upgrade sur clic comme aujourdhui pour nursery/souvenirShop.
3. Recherche : tick produit researchPoints (formule par niveau des cells research). Agrandissement carte consomme researchPoints (phase 9).
4. Billeterie / Boutique : capacités (visiteurs/unité) utilisées en phase 8.
5. UI : icônes et libellés pour chaque type de bâtiment ; affichage niveau et flèche upgrade si possible.
**DONE_WHEN:** Tous les bâtiments sont constructibles et upgradeables à 7 niveaux ; recherche produit des points.
---
## PHASE 4 Bébés et flux (remplacement œufs)
**FILES:** `web/js/state.js` | `web/js/zoo.js` | `web/js/placement.js` | `web/js/hatching.js` | `web/js/conveyor.js` | `web/js/ui.js` | `web/js/world-map.js`
**STEPS:**
1. Remplacer `pendingEggTokens` / œufs par `pendingBabies` (bébé en croissance en nurserie) et offres = bébés ou animaux adultes.
2. Nurserie : slot avec bébé en croissance ; durée selon niveau nurserie ; à la fin état « bébé mature » déplaçable (case zoo → animal, ou camion → vente).
3. Accueil : animal acheté/reçu va en `receptionAnimals` ; durée acclimatation ; à la fin « animal prêt » déplaçable (case zoo ou camion).
4. Conveyor/offres : générer offres de bébés et danimaux (pas dœufs). Achat envoie en nurserie (bébé) ou en accueil (animal).
5. UI : afficher bébé mature / animal prêt ; glisser vers case vide ou camion.
**DONE_WHEN:** Plus dœufs ; achat bébé/animal → nurserie/accueil → mature/prêt → placement ou vente.
---
## PHASE 2 Animaux multi-cases
**FILES:** `web/js/loot-tables.js` | `web/js/placement.js` | `web/js/grid-utils.js` | `web/js/ui.js` | `web/js/state.js`
**STEPS:**
1. Définir `cellsWide`, `cellsHigh` dans loot-tables (par défaut 1).
2. Placement : vérifier que toutes les cases (originKey + largeur/hauteur) sont vides et dans les limites.
3. Stockage : une entrée par case avec référence à lorigine (originKey) ou une entité avec originKey + dimensions.
4. Suppression / déplacement : libérer ou déplacer tout le bloc.
5. UI : dessiner lanimal sur plusieurs cases ; drag déplace le bloc.
**DONE_WHEN:** Au moins un type danimal 2x2 (ou 1x2) placeable et déplaçable.
---
## PHASE 5 Nourriture, consommation, morts
**FILES:** `web/js/config.js` | `web/js/state.js` | `web/js/food.js` (new) | `web/js/game-loop.js` | `web/js/animal-visits.js` | `web/js/loot-tables.js`
**STEPS:**
1. Module `food.js` : par tick, calculer consommation totale ; capacité nourriture = sum(food buildings × AnimalsPerUnit) ; répartir ; animaux non nourris reçoivent un déficit ou timer.
2. Mort si pas nourri au-delà dun seuil ; retirer de la grille ; incrémenter deathCountRecent.
3. Implémenter toutes les autres causes de mort (seul, pas visité, recherche trop basse, bébé non vendu à temps, bébé mature non placé à temps, animal accueil non placé à temps, vente échouée, température/milieu en écart). Appeler une fonction `checkDeathCauses(state, nowUnix)` dans la game loop.
4. loot-tables : température idéale et tolérances par animal.
**DONE_WHEN:** Les animaux non nourris meurent ; les autres causes de mort sont branchées (même si certaines règles sont simplifiées au début).
---
## PHASE 6 Reproduction
**FILES:** `web/js/loot-tables.js` | `web/js/reproduction.js` (new) | `web/js/state.js` | `web/js/game-loop.js`
**STEPS:**
1. Détecter paires danimaux même type, origine « autre zoo » pour au moins un, en proximité (adjacent ou distance N).
2. Timer par paire ou par animal ; à léchéance créer un bébé → nurserie si place, sinon en vente. Utiliser score de reproduction du zoo et adéquation température/milieu pour réduire le délai.
3. Exposer score de reproduction par milieu et survie par milieu depuis loot-tables.
**DONE_WHEN:** Une paire admissible peut produire un bébé après un délai ; le bébé va en nurserie ou en vente.
---
## PHASE 7 Score de reproduction du zoo
**FILES:** `web/js/state.js` | `web/js/food.js` | `web/js/reproduction.js` | `web/js/trade.js` | `web/js/world-map.js`
**STEPS:**
1. birthCount incrémenté à chaque naissance ; feedingRate = ratio nourris/total (ou fenêtre glissante).
2. Formule score agrégé = f(birthCount, feedingRate, …). Exposer dans state et sur la carte du monde (case sous le nom du zoo).
3. À la vente, attacher `reproductionScoreAtSale` à lentité vendue (pour phase 6 côté acheteur).
**DONE_WHEN:** Score de reproduction affiché ; vendu porte le score du zoo vendeur.
---
## PHASE 8 Attractivité et visiteurs
**FILES:** `web/js/income.js` | `web/js/visitor-attraction.js` | `web/js/config.js` | `web/js/state.js` | `web/js/ui.js` | `web/js/world-map.js`
**STEPS:**
1. Entrée visiteurs uniquement via billeterie ; cap = Billeterie.VisitorsPerUnit × niveau total billeterie.
2. Durée max 1 journée par visiteur ; sortie par billeterie. Temps passé prolongé par boutiques et diversité animaux.
3. Formule attractivité : valeur cumulée, nombre despèces, rareté, taux remplissage ; pénalités morts ; bonus naissances.
4. Affichage score dattractivité sous le nom du zoo sur la carte du monde.
**DONE_WHEN:** Visiteurs plafonnés par billeterie ; attractivité calculée et affichée.
---
## PHASE 9 Carte du monde (recherche + compteurs)
**FILES:** `web/js/state.js` | `web/js/economy.js` | `web/js/world-map.js` | `web/js/ui.js` | `web/js/config.js`
**STEPS:**
1. Agrandissement carte payé en researchPoints (pas en pièces). Coût par palier en unités de recherche. Bouton grisé si pas assez.
2. Compteurs : bébés à vendre, animaux à vendre, laboratoires, zoos, villes (affichage sur la carte ou barre).
3. Case zoo : nom, score attractivité, score reproduction, case de vente (phase 10).
**DONE_WHEN:** Agrandissement carte consomme researchPoints ; compteurs affichés.
---
## PHASE 10 Ventes et enchères
**FILES:** `web/js/state.js` | `web/js/trade.js` | `web/js/world-map.js` | `web/js/ui.js` | `server/routes/zoos.js` ou `server/routes/trades.js` | `server/db.js`
**STEPS:**
1. Cases de vente sous chaque zoo sur la carte du monde ; afficher bébé ou animal à vendre + dernier montant enchère.
2. Depuis le zoo : glisser bébé mature ou animal sur le camion → création dune entrée saleListings (zoo du joueur).
3. API enchères : créer/consulter offres, enchérir, valider/refuser vente par le vendeur. Si délai dépassé sans vente validée pour un bébé → mort du bébé.
4. Vente validée : acheteur reçoit bébé (nurserie) ou animal (accueil) ; reproductionScoreAtSale attaché.
**DONE_WHEN:** Mise en vente depuis le zoo ; enchères joueurs/bots ; validation vendeur ; bébé invendu meurt.
---
## PHASE 11 Villes
**FILES:** `web/js/config.js` | `web/js/world-map.js` | `web/js/income.js` | `web/js/ui.js`
**STEPS:**
1. Chaque ville : 1 case nom, 1 case « nombre max visiteurs vers zoos ». Config ou state.
2. Répartir ou limiter les visiteurs vers les zoos selon ce plafond et lattractivité.
**DONE_WHEN:** Villes affichent le max visiteurs ; la règle limite ou répartit les visiteurs.
---
## PHASE 12 UI et grilles au lancement
**FILES:** `web/js/state.js` | `web/js/ui.js` | `web/js/world-map.js` | `web/css/main.css`
**STEPS:**
1. Grille zoo au lancement : 1 agrandissement, 1 recherche, 1 billeterie, 1 nurserie, 1 accueil, 1 nourriture, 1 camion, 24 cases 3 couleurs. Positions fixes dans defaultState().
2. Grille monde au lancement : 1 agrandissement carte (recherche), compteurs, 1 accueil, 1 nourriture, 1 camion, 24 cases 3 couleurs.
3. Transitions douces visibles (phase 1). Actions : achat sur case vide (tous les types), déplacement bébé mature / animal prêt. Accessibilité ARIA/clavier/contraste.
**DONE_WHEN:** Les deux grilles de lancement sont conformes au cahier ; toutes les actions sont accessibles.
---
## PHASE 13 Migration et compatibilité
**FILES:** `web/js/state.js` | `server/routes/zoos.js`
**STEPS:**
1. specVersion ou version dans game_state (ex. 1 = ancien œufs/école, 2 = rappel grandes règles).
2. Au load : si version 1, soit migration (œufs → bébés, école → research niv 1, etc.), soit message « sauvegarde incompatible ».
3. API accepte game_state étendu (JSONB) sans casser les anciens champs.
**DONE_WHEN:** Anciennes sauvegardes migrées ou refusées proprement ; nouvelles sauvegardes complètes.