Initial commit
**Motivations:** - Initialisation du versionning git pour le projet **Root causes:** - N/A (Nouveau projet) **Correctifs:** - N/A **Evolutions:** - Structure initiale du projet - Ajout du .gitignore **Pages affectées:** - Tous les fichiers
This commit is contained in:
50
docs/features/attractivite-visiteurs-phase8.md
Normal file
50
docs/features/attractivite-visiteurs-phase8.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Phase 8 – Attractivité et visiteurs (billeterie, cap, score)
|
||||
|
||||
**Objectif :** Plafonner les visiteurs par la capacité billeterie, calculer un score d’attractivité (valeur, espèces, rareté, remplissage, pénalités morts, bonus naissances) et l’afficher sur la carte du monde.
|
||||
|
||||
**Référence :** `docs/plan-implementation-rappel-grandes-regles.md` phase 8.
|
||||
|
||||
## Impacts
|
||||
|
||||
- Les visiteurs sont plafonnés par la capacité billeterie (20 × niveau total billeterie). Sans billeterie, le plafond n’est pas appliqué (comportement inchangé).
|
||||
- Nouveau score d’attractivité exposé dans `state.attractivityScore` et affiché sous le nom du zoo (joueur) sur la carte du monde.
|
||||
- La formule d’attractivité pourra servir plus tard à l’allocation des visiteurs depuis les villes (phase 11).
|
||||
|
||||
## Modifications
|
||||
|
||||
- **income.js** : suppression des imports dupliqués ; `getBilleterieCapacity(state)` ; dans `getVisitorParams`, plafonnement de `visitorCount` par `getBilleterieCapacity(state)` ; `getAttractivityScore(state)` (valeur cumulée, nombre d’espèces, rareté moyenne, taux de remplissage, pénalité morts, bonus naissances).
|
||||
- **config.js** : `Visitor.AttractivityDeathPenalty`, `Visitor.AttractivityBirthBonus`.
|
||||
- **types.js** : `GameState.attractivityScore?`.
|
||||
- **game-loop.js** : import `getAttractivityScore` ; après `tickResearch`, `state.attractivityScore = getAttractivityScore(state)`.
|
||||
- **ui.js** : pour le zoo joueur, ligne « Score attractivité: X.X » sous le score de reproduction (classe `world-map-zoo-attractivity-score`).
|
||||
- **main.css** : style `.world-map-zoo-attractivity-score`.
|
||||
|
||||
## Disparition des animaux non visités (§2)
|
||||
|
||||
- **Config** : `Visitor.MaxSecondsWithoutVisit` (300 s par défaut). Un animal dont aucune visite n’a été enregistrée sur sa case depuis plus de cette durée est retiré (case vidée, `deathCountRecent` incrémenté).
|
||||
- **animal-visits.js** : `tickAnimalVisits(state, nowUnix, nowMs)` met à jour `lastVisitedAt` des cases animales sous la position actuelle des visiteurs (orbites autour du centre d’attraction).
|
||||
- **food.js** : `checkDeathCauses(state, nowUnix)` utilise `MaxSecondsWithoutVisit` ; si `nowUnix - lastVisitedAt >= maxVisit`, le bloc animal est supprimé.
|
||||
- **game-loop.js** : `tickAnimalVisits` est appelé avant `tickFeeding` et `checkDeathCauses`.
|
||||
|
||||
## Stagnation (§3)
|
||||
|
||||
- **Config** : `Visitor.StagnationDecayAfterSeconds` (60 s), `Visitor.StagnationDecayPerMinute` (0.05). Après ce délai sans action d’évolution, le multiplicateur de demande visiteurs décroît (plancher 10 %).
|
||||
- **income.js** : `getStagnationMultiplier(state, nowUnix)` utilise `state.lastEvolutionAt` ; appliqué dans `getVisitorDemand(state, nowUnix)`.
|
||||
- **lastEvolutionAt** est mis à jour sur : upgrade (plot, conveyor, truck, world map, school, nursery, shop, research, billeterie, food, reception, biome), place (egg, baby, reception animal), vente (sellAnimalToNpc, addMatureBabyToSale, addReceptionAnimalToSale), prestige, moveCell.
|
||||
|
||||
## Implémenté ultérieurement (modèle visiteurs par entité)
|
||||
|
||||
- **Durée max 1 journée par visiteur** : `state.visitorArrivals[]` avec `{ arrivedAt }` ; base = `Time.DayLengthSeconds` (1 jour) ; sortie quand `now > arrivedAt + getStayDurationSeconds(state)`.
|
||||
- **Prolongation par boutiques et diversité** : `getStayMultiplier(state)` = 1 + (niveaux boutique × `Visitor.StayMultiplierPerShopLevel`) + (espèces distinctes × `Visitor.StayMultiplierPerSpecies`) ; `getStayDurationSeconds(state) = base × getStayMultiplier(state)`.
|
||||
- **Config** : `Visitor.StayMultiplierPerShopLevel`, `Visitor.StayMultiplierPerSpecies` (base jour = `Time.DayLengthSeconds`).
|
||||
- **Game loop** : `tickVisitorArrivals(state, nowUnix)` appelé avant `incomeTick` ; `getVisitorParams(state)` utilise `state.visitorArrivals.length` ; sans billeterie, fallback sur l’ancienne formule pour rétrocompatibilité.
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
- Aucun déploiement serveur. Rechargement client suffit.
|
||||
|
||||
## Modalités d’analyse
|
||||
|
||||
- Sans billeterie : le nombre de visiteurs reste calculé comme avant (sans plafond).
|
||||
- Avec au moins une case billeterie : le nombre de visiteurs affiché et utilisé pour les revenus ne dépasse pas (niveau total billeterie × 20).
|
||||
- Carte du monde, zoo joueur : affichage « Score attractivité: X.X » mis à jour à chaque tick.
|
||||
28
docs/features/carte-monde-recherche-compteurs-phase9.md
Normal file
28
docs/features/carte-monde-recherche-compteurs-phase9.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Phase 9 – Carte du monde : agrandissement en recherche et compteurs
|
||||
|
||||
**Objectif :** Agrandissement de la carte payé en unités de recherche (plus en pièces) ; affichage des compteurs (bébés à vendre, animaux à vendre, laboratoires, zoos, villes).
|
||||
|
||||
**Référence :** `docs/plan-implementation-rappel-grandes-regles.md` phase 9.
|
||||
|
||||
## Impacts
|
||||
|
||||
- L’agrandissement de la carte consomme `state.researchPoints` au lieu de `state.coins`. Le bouton est grisé si `researchPoints` insuffisants.
|
||||
- Compteurs affichés sous la zone « Agrandir carte » : Bébés à vendre, Animaux à vendre, Laboratoires, Zoos, Villes.
|
||||
|
||||
## Modifications
|
||||
|
||||
- **config.js** : `WorldMap.MapUpgrade.BaseResearchCost`, `ResearchUpgradeGrowth` (coût en unités de recherche par palier).
|
||||
- **economy.js** : `getWorldMapUpgradeResearchCost(currentLevel)` ; `getWorldMapUpgradeCost` conservé pour compatibilité.
|
||||
- **zoo.js** : `tryUpgradeWorldMap` utilise `getWorldMapUpgradeResearchCost`, déduit `state.researchPoints` au lieu de `state.coins` ; retourne `NotEnoughResearch` si pas assez de points.
|
||||
- **ui.js** : zone agrandissement carte affiche le coût en recherche (`X 🔬`) et le titre avec le coût ; `canUpgradeMap` basé sur `researchPoints >= getWorldMapUpgradeResearchCost(mapLevel)` ; nouvelle zone `world-map-counters` avec cinq compteurs mis à jour au refresh.
|
||||
- **texts-fr.js** : `errorMessage.NotEnoughResearch`.
|
||||
- **main.css** : `.world-map-upgrade-zone-cost`, `.world-map-counters`, `.world-map-counter`.
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
- Aucun déploiement serveur. Rechargement client suffit.
|
||||
|
||||
## Modalités d’analyse
|
||||
|
||||
- Agrandir la carte : coût affiché en unités de recherche ; si pas assez de `researchPoints`, le bouton est grisé et un clic affiche « Pas assez d’unités de recherche ».
|
||||
- Compteurs : Bébés à vendre = `saleListings` avec `isBaby` ; Animaux à vendre = `saleListings` sans `isBaby` ; Laboratoires = 1 ; Zoos = `worldZoos.length` ; Villes = `WorldMap.Cities.length`.
|
||||
41
docs/features/causes-mort-audit.md
Normal file
41
docs/features/causes-mort-audit.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Audit des causes de mort (§12)
|
||||
|
||||
**Référence :** Cahier des charges §12 (Mort).
|
||||
|
||||
## Liste du cahier
|
||||
|
||||
1. Seuls
|
||||
2. Pas visités
|
||||
3. Manque de nourriture
|
||||
4. Tué par un autre animal d'un autre zoo
|
||||
5. Niveau de recherche trop inférieur par rapport au niveau de l'animal
|
||||
6. Bébé non vendu dans les délais
|
||||
7. Bébé de nurserie prêt non placé dans les délais
|
||||
8. Animal d'accueil prêt non placé sur la carte après un délai
|
||||
9. Animal non placé sur la carte dans les délais (vente échouée)
|
||||
10. Température trop en écart avec la température de l'animal
|
||||
11. Milieu (couleur) trop en écart avec la température de l'animal
|
||||
|
||||
## Implémenté
|
||||
|
||||
- **Pas visités** : `Visitor.MaxSecondsWithoutVisit`, `checkDeathCauses` → `maybeDeathBlock` (visitedOk), `food.js` + `animal-visits.js`.
|
||||
- **Manque de nourriture** : `Food.MaxSecondsWithoutFood`, `maybeDeathBlock` (fedOk), `tickFeeding` / `checkDeathCauses`.
|
||||
- **Température en écart** : `maybeDeathBlock` (tempOk), `getDisplayTemperature`, `idealTemperature` / `temperatureTolerance` (loot-tables).
|
||||
- **Milieu (couleur) en écart** : `maybeDeathBlock` (biomeOk), `isAnimalAllowedOnBiome`, `getDisplayBiome`.
|
||||
- **Bébé nurserie prêt non placé** : `Nursery.MaxSecondsMatureNotPlaced`, `filterPendingBabies` dans `checkDeathCauses`.
|
||||
- **Animal accueil prêt non placé** : `Reception.MaxSecondsReadyNotPlaced`, `filterReceptionAnimals` dans `checkDeathCauses`.
|
||||
- **Bébé non vendu dans les délais** : `Sale.ListingDurationSeconds`, `tickSaleListings` (trade.js) ; annonce expirée et `isBaby` → `deathCountRecent` incrémenté. Côté serveur : `expireSaleListings` (db.js).
|
||||
|
||||
## Non implémenté
|
||||
|
||||
- **Seuls** : pas de règle « animal seul meurt ».
|
||||
- **Tué par un autre animal d'un autre zoo** : pas de mécanique inter-zoo.
|
||||
- **Niveau de recherche trop inférieur** : pas de vérification niveau recherche vs niveau animal.
|
||||
- **Animal (adulte) vente échouée** : à l'expiration d'une annonce adulte (`isBaby: false`), `deathCountRecent` n'est pas incrémenté (actuellement seul le bébé invendu est compté).
|
||||
|
||||
## Fichiers
|
||||
|
||||
- `web/js/food.js` : `checkDeathCauses`, `maybeDeathBlock`, `filterPendingBabies`, `filterReceptionAnimals`.
|
||||
- `web/js/trade.js` : `tickSaleListings` (expiration bébé).
|
||||
- `web/js/animal-visits.js` : `lastVisitedAt` pour cause « pas visités ».
|
||||
- `server/db.js` : `expireSaleListings` (bébé invendu).
|
||||
39
docs/features/centralisations-mutualisations.md
Normal file
39
docs/features/centralisations-mutualisations.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Centralisations et mutualisations
|
||||
|
||||
**Objectif :** Réduire la duplication et centraliser les helpers réutilisables.
|
||||
|
||||
## Modifications récentes
|
||||
|
||||
### server/db.js
|
||||
|
||||
- **mapZooRowBase(row)** : id, name, x, y (Number) partagés par `getAllZoos`, `getZooById`, `getBotZoosForTick`. Chaque fonction étend avec ses champs spécifiques (animal_weights/game_state, is_bot/account_id, animalWeights/botState).
|
||||
- **mapSaleListingRow(row)** : mapping unique des lignes `sale_listings` pour `getSaleListingById`, `getActiveSaleListings`, `getSalesForZoo` (asSeller, asBuyerUndelivered, active). Colonnes absentes dans le SELECT deviennent `undefined`.
|
||||
- **validateListingForSeller(listingId, sellerZooId)** : chargement + vérifications (ListingNotFound, ListingNotActive, NotSeller) utilisées par `acceptSale` et `rejectSale`. Retourne `{ ok: true, listing }` ou `{ ok: false, reason }`.
|
||||
- **processValidatedSales** : boucle refactorée sans `continue` (blocs imbriqués) pour respecter la règle no-continue.
|
||||
|
||||
### web/js/loot-tables.js
|
||||
|
||||
- **zeroAnimalWeights()** : retourne un objet `{ [colorName]: 0 }` pour toutes les couleurs. Utilisé pour agrégations et valeurs initiales.
|
||||
|
||||
### web/js/state.js
|
||||
|
||||
- **defaultAnimalWeights()** : s’appuie sur `zeroAnimalWeights()` puis met la première couleur à 1.
|
||||
- **normalizeZooWeights(legacy)** : utilise `zeroAnimalWeights()` au lieu de recréer l’objet à la main.
|
||||
- **setScalarDefault(data, key, defaultVal)** : assigne `data[key]` si null/undefined ; `defaultVal` peut être une fonction (ex. `lastEvolutionAt`). Utilisé dans **applyLoadStateScalarDefaults** avec la liste **LOAD_STATE_SCALAR_DEFAULTS** (tableau [key, default]) pour éviter la répétition des ~25 lignes `if (data.x === null || ...) data.x = default`.
|
||||
|
||||
### web/js/bot-zoo.js
|
||||
|
||||
- **getNeighborColorWeights** : utilise `zeroAnimalWeights()` pour initialiser `out` au lieu de `Object.fromEntries(colorNames.map(...))`.
|
||||
|
||||
### web/js/auto-mode-profiles.js + bot-zoo.js (déjà documenté)
|
||||
|
||||
- Bots : `LEGACY_PROFILE_TO_ID` + `getProfileParams(profileId)` pour toutes les décisions (upgrade, sell, buy) ; plus de ternaires sur "fast"|"slow"|"balanced".
|
||||
|
||||
## Fichiers concernés
|
||||
|
||||
- server/db.js
|
||||
- web/js/loot-tables.js
|
||||
- web/js/state.js
|
||||
- web/js/bot-zoo.js
|
||||
- docs/features/ventes-encheres-phase10.md (référence mapSaleListingRow, validateListingForSeller)
|
||||
- docs/features/mode-auto-50-profils.md (référence bots + profils)
|
||||
45
docs/features/grille-lancement.md
Normal file
45
docs/features/grille-lancement.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Grille au lancement et 3 couples reproducteurs
|
||||
|
||||
**Objectif :** Au premier lancement (nouveau zoo ou après prestige), le joueur dispose d’une grille zoo complète (recherche, billeterie, nurserie, accueil, nourriture, école) et de 3 couples reproducteurs d’animaux basiques déjà placés.
|
||||
|
||||
**Référence :** Cahier des charges §1 (garanties au démarrage), §10 (carte du zoo, layout).
|
||||
|
||||
## Impacts
|
||||
|
||||
- **Nouveau zoo / pas de sauvegarde :** `defaultState()` produit une grille 6×6 avec 6 cases fixes en ligne 1 et 6 animaux (3 couples) en ligne 2. Les 24 autres cases restent vides (3 biomes visuels par tiers de largeur, pas de champ biome sur les cases).
|
||||
- **Prestige :** `doPrestige()` réinitialise la grille avec le même layout et les mêmes 3 couples.
|
||||
- **Chargement ancienne sauvegarde :** `applyLoadStateLegacyCells` et `ensureSchoolCell` conservent la compatibilité (2_1 forcé en nurserie si manquant ou ancien plotUpgrade ; école ajoutée en 1_1 si absente). Les anciennes parties gardent 1_1 école et 2_1 nurserie tant qu’elles ne sont pas réinitialisées.
|
||||
|
||||
## Modifications
|
||||
|
||||
- **web/js/default-grid-layout.js** (nouveau, partagé) : `buildDefaultRow1Cells()`, `STARTER_ANIMAL_IDS_BY_BIOME`, `STARTER_ANIMAL_POSITIONS`, `addStarterAnimals(state)`.
|
||||
- **state.js**
|
||||
- `buildDefaultCells()` : appelle `buildDefaultRow1Cells()` du module partagé `default-grid-layout.js` (research, billeterie, nursery, reception, food, school en ligne 1).
|
||||
- `addStarterAnimals(state)` : importée depuis `default-grid-layout.js` ; place 6 animaux (3 couples) sur la ligne 2.
|
||||
- `defaultState()` : construit le state puis appelle `addDefaultStarterAnimals(state)` avant retour.
|
||||
- **prestige.js**
|
||||
- Même layout de grille et mêmes 3 couples après reset, via `buildDefaultRow1Cells()` et `addStarterAnimals()` importés de `default-grid-layout.js`. Réinitialisation de `pendingBabies` et `receptionAnimals`.
|
||||
|
||||
## Layout détaillé
|
||||
|
||||
- **Niveau 1 (6×6) :** `plotSizeFromLevel(1)` → largeur 6, hauteur 6.
|
||||
- **Ligne 1 :** 1_1 research, 2_1 billeterie, 3_1 nursery, 4_1 reception, 5_1 food, 6_1 school.
|
||||
- **Ligne 2 :** 1_2 et 2_2 = couple Meadow (c0_r0), 3_2 et 4_2 = couple Ocean (c5_r0), 5_2 et 6_2 = couple Mountain (c10_r0).
|
||||
- **Lignes 3–6 :** vides ; 24 cases libres pour placement (affichage 3 couleurs/biomes par tiers de largeur, sans donnée biome sur cellule).
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
- Client uniquement. Aucune migration BDD. Rechargement suffit. Les nouveaux zoos et les resets prestige utilisent le nouveau layout ; les sauvegardes existantes ne sont pas modifiées de force.
|
||||
|
||||
## Modalités d’analyse
|
||||
|
||||
- Nouveau jeu : grille avec 6 bâtiments ligne 1, 6 animaux ligne 2, 24 cases vides.
|
||||
- Prestige : même grille + 3 couples ; pièces à 0, niveaux plot/conveyor/camion/carte à 1, listes pendingBabies/receptionAnimals vides.
|
||||
- Chargement ancienne sauvegarde : pas de réécriture des cases 1_1/2_1 si déjà présentes (sauf correction legacy 2_1 = nursery si manquant ou ancien plotUpgrade).
|
||||
|
||||
## Carte du monde au lancement (§11)
|
||||
|
||||
- **Agrandissement carte** : niveau `worldMapLevel` (1 par défaut) ; zone d’upgrade en unités de recherche (config `WorldMap.MapUpgrade`). Affichage dans la vue carte du monde.
|
||||
- **Compteurs** : affichés en haut de la vue carte (Bébés à vendre, Animaux à vendre, Laboratoires, Zoos, Villes). Valeurs dérivées du state et de la config (`state.saleListings`, `state.worldZoos`, `GameConfig.WorldMap.Cities`, etc.).
|
||||
- **Accueil / Nourriture / Camion** : sur la carte du monde, ces fonctions sont couvertes par la même zone « camion » (achat d’œufs, vente) et les panneaux ventes (Mes ventes, À récupérer, Enchères). Pas de grille dédiée « 24 cases 3 couleurs » sur la carte du monde dans l’implémentation actuelle ; la carte affiche zoos, villes, laboratoire, compteurs et panneaux ventes.
|
||||
- **Layout actuel** : zone carte (zoos, villes, labo), panneau ventes à gauche, compteurs en haut. Alignement §11 partiel (compteurs + agrandissement carte) ; les « 24 cases 3 couleurs » et les cases Accueil/Nourriture/Camion sur la carte monde restent optionnels ou à préciser en design.
|
||||
34
docs/features/incidents-visiteurs-phase4.md
Normal file
34
docs/features/incidents-visiteurs-phase4.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Incidents visiteurs (§4.2)
|
||||
|
||||
**Objectif :** Visiteurs peuvent rencontrer des incidents (soif, poubelle pleine, banc requis, animal trop loin, envie de photo). Apparition plus fréquente en phase d’attente. Bulle au-dessus du visiteur ; clic = résolution (bonus pièces + attractivité) ; non résolu = timeout puis départ du visiteur et pénalité d’attractivité.
|
||||
|
||||
**Référence :** Cahier des charges §2 (Visiteurs et Incidents).
|
||||
|
||||
## Impacts
|
||||
|
||||
- **State :** `VisitorEntry` étendu avec `incidentType?` ("thirst"|"bin"|"bench"|"animalFar"|"photo"), `incidentSince?`. `attractivityBonusFromIncidents?` (cumul résolus − non résolus).
|
||||
- **Phase d’attente :** camion en cours (`eggPurchaseTruck`, `truckSale`) ou vente en attente de validation (`asBuyerUndelivered` avec `validated_at` dans le futur).
|
||||
- **Résolution :** clic sur la bulle → suppression de l’incident, ajout de pièces et bonus d’attractivité.
|
||||
- **Timeout :** après `IncidentTimeoutSeconds` sans résolution, le visiteur est retiré et une pénalité d’attractivité est appliquée.
|
||||
|
||||
## Modifications
|
||||
|
||||
- **types.js** : `VisitorEntry` avec `incidentType?`, `incidentSince?` ; `GameState.attractivityBonusFromIncidents?`.
|
||||
- **config.js** : `Visitor.IncidentChanceBase`, `IncidentChanceWaitMultiplier`, `IncidentTimeoutSeconds`, `IncidentResolveAttractivityBonus`, `IncidentResolveCoinBonus`, `IncidentUnresolvedAttractivityPenalty`.
|
||||
- **visitor-incidents.js** (nouveau) : `isInWaitPhase(state)`, `tickVisitorIncidents(state, nowUnix)`, `resolveIncident(state, visitorIndex)`, `INCIDENT_TYPES`, `INCIDENT_EMOJI`.
|
||||
- **game-loop.js** : appel à `tickVisitorIncidents` après `tickVisitorArrivals`.
|
||||
- **income.js** : `getAttractivityScore` inclut `state.attractivityBonusFromIncidents`.
|
||||
- **state.js** : au chargement, défaut `attractivityBonusFromIncidents = 0`.
|
||||
- **main.js** : boucle visiteurs basée sur `state.visitorArrivals.length` ; pour chaque visiteur avec incident, affichage d’une bulle (emoji + tooltip) ; clic appelle `resolveIncident` puis `fullRender`.
|
||||
- **texts-fr.js** : `incidentLabel` (soif, poubelle pleine, etc.), `incidentBubbleAria`.
|
||||
- **main.css** : `.visitor-incident-bubble` (position au-dessus du sprite, cliquable).
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
- Client uniquement. Rechargement suffit.
|
||||
|
||||
## Modalités d’analyse
|
||||
|
||||
- Avoir des visiteurs (billeterie) et attendre ou déclencher une phase d’attente (achat œuf, vente en cours) : des bulles d’incident apparaissent au-dessus de certains visiteurs.
|
||||
- Clic sur une bulle : incident disparaît, pièces et attractivité augmentent.
|
||||
- Ne pas cliquer : après le délai configuré, le visiteur disparaît et l’attractivité baisse.
|
||||
35
docs/features/mode-auto-50-profils.md
Normal file
35
docs/features/mode-auto-50-profils.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Mode automatique – 50 profils et sélection hiérarchique
|
||||
|
||||
**Objectif :** Proposer 50 profils de mode automatique répartis en 5 familles, avec une interface de sélection en deux étapes (Famille → Spécialisation) et utilisation des paramètres du profil choisi pour les décisions d’upgrade du joueur.
|
||||
|
||||
**Référence :** Cahier des charges §5 ; plan d’action BLOC 3.
|
||||
|
||||
## Impacts
|
||||
|
||||
- **State :** `autoModeProfileId` (1–50) stocke le profil choisi ; `autoModeProfile` ("fast"|"slow"|"balanced") reste pour rétrocompatibilité et est mappé à un profil par défaut (balanced→25, fast→33, slow→7).
|
||||
- **Mode auto joueur :** Les décisions d’upgrade (parcelle, compétences, camion) utilisent les paramètres du profil (seuil de dépense, probabilité d’upgrade) au lieu des 3 profils legacy uniquement.
|
||||
- **UI :** Clic sur le bouton mode auto quand il est inactif ouvre un panneau (Famille → Spécialisation) ; choix d’une spécialisation active le mode auto avec ce profil. Clic quand le mode auto est actif le désactive.
|
||||
- **Bots :** Les décisions upgrade/sell/buy utilisent `getProfileParams(LEGACY_PROFILE_TO_ID[profile])` ; paramètres centralisés dans auto-mode-profiles (plus de ternaires fast/slow/balanced).
|
||||
|
||||
## Modifications
|
||||
|
||||
- **web/js/auto-mode-profiles.js** (nouveau) : 50 profils avec id, familyId (1–5), spendThreshold, upgradeChance, sellChance, clés i18n (label, priorities, risks). Familles : Conservateurs (1–10), Éleveurs (11–20), Commerçants (21–30), Expansionnistes (31–40), Scientifiques (41–50). `getEffectiveProfileId(state)`, `getProfileParams(profileId)`, `getProfilesByFamily(familyId)`, `getAllProfiles()`.
|
||||
- **web/js/types.js** : `GameState.autoModeProfileId?`, `autoProfilePickerOpen?`, `autoProfilePickerFamily?`.
|
||||
- **web/js/state.js** : `saveState` omet les champs `autoProfilePickerOpen` et `autoProfilePickerFamily` avant persistance ; `applyLoadStateScalarDefaults` remet ces champs à false/undefined au chargement.
|
||||
- **web/js/bot-zoo.js** : `tickPlayerAutoMode` utilise `getEffectiveProfileId(state)` et `getProfileParams(profileId)` ; `playerAutoDoOneUpgrade(state, params, rng)` reçoit des paramètres numériques. Pour les bots, `tickBotDecisions` utilise `LEGACY_PROFILE_TO_ID[b.profile]` et `getProfileParams(profileId)` ; `botDecideUpgrade`, `botDecideSell`, `botDecideBuy` reçoivent un objet `params` (spendThreshold, upgradeChance, sellChance) au lieu du libellé.
|
||||
- **web/js/ui.js** : Clic sur le bouton mode auto ouvre le picker si inactif ; panneau avec 5 familles puis 10 spécialisations, bouton Annuler. Au choix d’une spécialisation : `autoModeProfileId`, `autoMode: true`, fermeture du picker.
|
||||
- **web/js/texts-fr.js** : `autoProfileFamilyLabel` (5 familles), `autoProfileSpecialisationLabel` (1–50), `autoProfilePrioritiesLabel`, `autoProfileRisksLabel` (placeholders), libellés du picker.
|
||||
- **web/css/main.css** : `.auto-profile-picker-wrap`, `.auto-profile-picker-title`, `.auto-profile-picker-step`, `.auto-profile-picker-families`, `.auto-profile-picker-specialisations`, boutons famille/spécialisation, bouton Annuler.
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
- Client uniquement. Rechargement suffit.
|
||||
|
||||
## Modalités d’analyse
|
||||
|
||||
- Désactiver le mode auto, cliquer sur le bouton mode auto : le panneau « Choisir le profil » s’affiche avec 5 familles.
|
||||
- Choisir une famille : affichage des 10 spécialisations.
|
||||
- Choisir une spécialisation : le mode auto s’active avec le profil correspondant (🤖), le panneau se ferme.
|
||||
- Annuler : le panneau se ferme sans activer le mode auto.
|
||||
- Avec le mode auto actif, les upgrades automatiques utilisent les paramètres du profil sélectionné (seuil de dépense et probabilité d’upgrade).
|
||||
- Ancienne sauvegarde sans `autoModeProfileId` : comportement identique à « balanced » (profil 25).
|
||||
28
docs/features/reproduction-phase6.md
Normal file
28
docs/features/reproduction-phase6.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Phase 6 – Reproduction
|
||||
|
||||
**Objectif :** Deux animaux de même type, dont au moins un provient d’un autre zoo, en proximité produisent un bébé après un délai. Le délai est réduit par le score de reproduction du zoo et l’adéquation température/milieu.
|
||||
|
||||
**Référence :** `docs/plan-implementation-rappel-grandes-regles.md` phase 6.
|
||||
|
||||
## Impacts
|
||||
|
||||
- Nouveau module `web/js/reproduction.js` (détection de paires, timers, naissances).
|
||||
- État : `reproductionTimers`, `fromOtherZoo` sur animaux et bébés.
|
||||
- Bébés créés par reproduction vont en nurserie si place libre, sinon en `saleListings` (vente phase 10).
|
||||
|
||||
## Modifications
|
||||
|
||||
- **types.js** : `AnimalCell.fromOtherZoo?`, `PendingBaby.fromOtherZoo?`, `GameState.reproductionTimers?`.
|
||||
- **config.js** : `Reproduction.BaseSeconds`, `Reproduction.MaxDistance`.
|
||||
- **state.js** : `defaultState.reproductionTimers`, migration `loadState` pour `reproductionTimers`.
|
||||
- **zoo.js** : `addPendingBaby(state, animalId, fromOtherZoo?)`, `placeMatureBabyOnCell` / `placeReceptionAnimalOnCell` renseignent `fromOtherZoo` sur l’animal placé ; `tryBuyBaby` appelle `addPendingBaby(..., true)`.
|
||||
- **reproduction.js** : `getReproductionScore`, `getBiomeReproductionFactor`, `getTemperatureFactor`, `findReproductionPairs`, `tickReproduction` ; appel depuis la game loop après `checkDeathCauses`.
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
- Aucun déploiement serveur. Rechargement client suffit.
|
||||
|
||||
## Modalités d’analyse
|
||||
|
||||
- Vérifier en jeu : placer deux animaux de même type (dont un acheté en accueil/conveyor) sur deux cases adjacentes ; après le délai (réduit par score/biome/temp), un bébé apparaît en nurserie ou en vente.
|
||||
- `state.reproductionTimers` doit contenir les paires en attente avec `dueAt` ; après échéance, entrée retirée et `birthCount` incrémenté.
|
||||
28
docs/features/score-reproduction-phase7.md
Normal file
28
docs/features/score-reproduction-phase7.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Phase 7 – Score de reproduction du zoo
|
||||
|
||||
**Objectif :** Exposer un score de reproduction agrégé (birthCount, feedingRate) pour affichage et pour attacher à l’entité vendue (reproductionScoreAtSale). Réutiliser `getReproductionScore` pour le délai de reproduction (phase 6) et pour l’affichage.
|
||||
|
||||
**Référence :** `docs/plan-implementation-rappel-grandes-regles.md` phase 7.
|
||||
|
||||
## Impacts
|
||||
|
||||
- Un seul « zoo score » : `getReproductionScore(state)` utilisé dans la game loop pour le délai de reproduction et pour remplir `state.reproductionScore` (affichage).
|
||||
- Carte du monde : case « Score repro » sous le nom du zoo (joueur).
|
||||
- Vente : les entrées `saleListings` créées (nursery full en reproduction) portent `reproductionScoreAtSale` pour usage côté acheteur (phase 10).
|
||||
|
||||
## Modifications
|
||||
|
||||
- **types.js** : `GameState.reproductionScore?`.
|
||||
- **game-loop.js** : après `tickReproduction`, `state.reproductionScore = getReproductionScore(state)` ; import de `getReproductionScore` depuis `reproduction.js`.
|
||||
- **reproduction.js** : lors du push en `saleListings` (NoFreeNursery), ajout de `reproductionScoreAtSale: getReproductionScore(state)`.
|
||||
- **ui.js** : pour le zoo joueur sur la carte du monde, ajout d’une ligne « Score repro: X.X » sous le nom (classe `world-map-zoo-reproduction-score`).
|
||||
- **main.css** : style `.world-map-zoo-reproduction-score`.
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
- Aucun déploiement serveur. Rechargement client suffit.
|
||||
|
||||
## Modalités d’analyse
|
||||
|
||||
- En jeu : onglet carte du monde, zoo joueur → sous le nom, affichage « Score repro: X.X » (mis à jour à chaque tick).
|
||||
- Après une naissance (reproduction) sans place en nurserie, une entrée dans `saleListings` doit contenir `reproductionScoreAtSale` égal au score courant du zoo.
|
||||
51
docs/features/ventes-encheres-phase10.md
Normal file
51
docs/features/ventes-encheres-phase10.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Phase 10 – Ventes et enchères (bébés et animaux adultes)
|
||||
|
||||
**Objectif :** Mise en vente de bébés et d’animaux depuis le camion ; affichage des ventes sur la carte du monde ; expiration des annonces (bébé invendu meurt) ; enchères (offres joueurs/bots), validation par le vendeur, transfert vers l’acheteur (nurserie/accueil), persistance serveur (API/BDD).
|
||||
|
||||
**Référence :** `docs/plan-implementation-rappel-grandes-regles.md` phase 10.
|
||||
|
||||
## Vérification des phases précédentes
|
||||
|
||||
Voir `docs/plan-verification-phases-0-a-9.md`. Les prérequis (4, 6, 7, 9) sont en place.
|
||||
|
||||
## Impacts
|
||||
|
||||
- Glisser un **bébé mature** (nurserie) ou un **animal prêt** (accueil) sur la zone camion (vente) → l’entité est retirée de la nurserie/accueil et ajoutée à `state.saleListings` ; création côté serveur via `POST /api/sales` ; l’annonce apparaît sur la carte du monde dans la case du zoo joueur.
|
||||
- Les annonces expirent après un délai configurable (côté client via `tickSaleListings` et côté serveur via `expireSaleListings`) ; si l’annonce concernait un **bébé** et n’a pas été vendue, le bébé est considéré mort (`deathCountRecent` incrémenté côté client et serveur).
|
||||
- **Enchères :** les joueurs et les bots peuvent enchérir sur les ventes actives (`POST /api/sales/:id/bid`). Le vendeur peut accepter ou refuser la meilleure enchère (`POST /api/sales/:id/accept`, `POST /api/sales/:id/reject`). À l’acceptation, la vente passe en statut `sold` avec un délai de **validation différée de 10 minutes** : les pièces ne sont pas transférées immédiatement ; `validated_at = now() + 10 min`. Un traitement à la lecture (`processValidatedSales`) exécute le transfert (débit acheteur, crédit vendeur) et passe le statut à `validated` lorsque `validated_at <= now()`. L’acheteur ne peut « Récupérer » qu’après validation ; un **sablier** (compte à rebours) s’affiche pour les ventes en attente.
|
||||
|
||||
## Modifications
|
||||
|
||||
- **config.js** : `Sale.ListingDurationSeconds` (3600), `Sale.DefaultPrice` (50).
|
||||
- **trade.js** : `addMatureBabyToSale`, `addReceptionAnimalToSale`, `tickSaleListings`.
|
||||
- **game-loop.js** : appel à `tickSaleListings` après `tickReproduction`.
|
||||
- **ui.js** : zone camion (drop) crée la vente localement et appelle `createSale` si API configurée ; carte du monde : affichage des ventes (sync avec `getSales()` à l’ouverture) ; panneau « Mes ventes » (Accepter / Refuser), « À récupérer » (Récupérer), « Enchères » (saisie montant + Enchérir).
|
||||
- **types.js** : `SaleListing` étendu avec `serverId?`, `bestBidAmount?`, `bestBidderZooId?`, `status?` ; `GameState.salesFromApi?` pour les données renvoyées par `GET /api/sales`.
|
||||
- **api-client.js** : `getSales()`, `createSale(payload)`, `placeBid(listingId, amount)`, `acceptSale(listingId)`, `rejectSale(listingId)`, `deliverSale(listingId)`.
|
||||
- **Serveur**
|
||||
- **server/migrations/001_sale_listings.sql** : tables `sale_listings` (…), **002_sale_listings_validated_at.sql** : colonne `validated_at TIMESTAMPTZ`, statut `validated` ajouté au CHECK.
|
||||
- **server/db.js** : `mapSaleListingRow(row)` centralise le mapping des lignes `sale_listings` (utilisé par `getSaleListingById`, `getActiveSaleListings`, `getSalesForZoo`). `mapZooRowBase(row)` pour zoos (getAllZoos, getZooById, getBotZoosForTick). `validateListingForSeller(listingId, sellerZooId)` pour les vérifications vendeur (acceptSale, rejectSale). … `acceptSale` (ne transfère plus les pièces ; pose `sold_at`, `validated_at = now() + 10 min`), `processValidatedSales()` (transfert et passage à `validated`), `markSaleDelivered` (exige `status = 'validated'`).
|
||||
- **server/routes/sales.js** : GET `/api/sales` appelle `processValidatedSales()` avant `getSalesForZoo` si auth. Réponses incluent `validated_at`.
|
||||
- **server/bot-tick.js** : après `expireSaleListings`, récupération des ventes actives et enchère aléatoire d’un bot (si assez de pièces, pas vendeur).
|
||||
- **web** : panneau « À récupérer » : sablier et compte à rebours (ex. « Validation dans X min ») pour les ventes `status === 'sold'` avec `validated_at` dans le futur ; bouton « Récupérer » désactivé jusqu’à validation. **texts-fr.js** : `salesPendingValidation`, `salesValidationInMinutes`.
|
||||
- **texts-fr.js** : `errorMessage.BabyNotMature`, `NoBabyInNursery`, `AnimalNotReady`, `NoAnimalInReception`.
|
||||
- **web/css/main.css** : styles `.world-map-sales-panel`, `.sales-panel-title`, `.sales-panel-row`, boutons Accepter/Refuser/Récupérer/Enchérir.
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
- **Base de données :** exécuter la migration `server/migrations/001_sale_listings.sql`, puis `server/migrations/002_sale_listings_validated_at.sql` (validation différée).
|
||||
- Redémarrage serveur et rechargement client.
|
||||
|
||||
## Modalités d’analyse
|
||||
|
||||
- Glisser un bébé mature / animal prêt sur la zone camion : annonce créée localement et sur le serveur (si API configurée) ; affichage sur la carte du monde.
|
||||
- Ouvrir la carte du monde avec API + auth : `getSales()` est appelé ; panneau « Mes ventes », « À récupérer », « Enchères » affiché selon les données.
|
||||
- Enchérir sur une vente active : saisir un montant > meilleure enchère puis « Enchérir ».
|
||||
- En tant que vendeur : « Accepter » ou « Refuser » sur la meilleure enchère ; à l’acceptation, vente en statut `sold`, `validated_at = now() + 10 min` ; pas de transfert de pièces immédiat.
|
||||
- En tant qu’acheteur ayant gagné une vente : affichage sablier « Validation dans X min » tant que `validated_at > now()` ; après 10 min, un prochain GET exécute `processValidatedSales`, la vente passe en `validated`, le bouton « Récupérer » s’active ; clic ajoute le bébé/animal à la nurserie/accueil puis appelle `deliverSale`.
|
||||
- Expiration : après `end_at`, la vente passe en `expired` ; si bébé, `deathCountRecent` du vendeur incrémenté (GET /api/sales ou bot tick).
|
||||
- Bots : à chaque tick, un bot peut placer une enchère sur une vente active (autre zoo, assez de pièces).
|
||||
|
||||
## Phase suivante
|
||||
|
||||
Phase 11 – Villes : `docs/features/villes-phase11.md`.
|
||||
25
docs/features/villes-phase11.md
Normal file
25
docs/features/villes-phase11.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Phase 11 – Villes
|
||||
|
||||
**Objectif :** Cases des villes sur la carte du monde avec nom et nombre maximum de visiteurs vers les zoos ; plafond ou répartition des visiteurs depuis les villes.
|
||||
|
||||
**Référence :** `docs/plan-implementation-rappel-grandes-regles.md` phase 11.
|
||||
|
||||
## Dépendances
|
||||
|
||||
- Phase 8 (Attractivité et visiteurs).
|
||||
|
||||
## Livrables (implémentés)
|
||||
|
||||
- **Cases des villes :** Sur la carte du monde, chaque ville affiche le nom et le « nombre maximum de visiteurs vers les zoos » (`maxVisitorsTowardZoos`). Rendu : icône 🏙️ + libellé nom + ligne « max N ».
|
||||
- **Règle d'attraction :** Dans `getCityAttraction` (income.js), la contribution de chaque ville est plafonnée par `city.maxVisitorsTowardZoos` : `contrib = min(maxVisitorsTowardZoos, raw * 100)` avec `raw = 1/(1+distance)`, puis somme × `CityAttractionScale`. Les villes proches contribuent plus, sans dépasser leur plafond.
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
- **config.js** : `WorldMap.Cities[].maxVisitorsTowardZoos` (ex. 80, 100).
|
||||
- **income.js** : `getCityAttraction()` utilise le plafond par ville.
|
||||
- **ui.js** : Rendu des villes avec nom et « max N » ; tooltip et aria-label avec « max N visiteurs vers zoos ».
|
||||
- **main.css** : `.world-map-city-label`, `.world-map-city-max-visitors`.
|
||||
|
||||
## Phase précédente
|
||||
|
||||
Phase 10 – Ventes et enchères : `docs/features/ventes-encheres-phase10.md`.
|
||||
Reference in New Issue
Block a user