From 5b0af6dba79f260ce19871dbcc8d4274d5ed987c Mon Sep 17 00:00:00 2001 From: LATCHIMY Nicolas Date: Fri, 20 Feb 2026 23:28:34 +0400 Subject: [PATCH] card cosmo ambient --- src/components/Card.astro | 145 ++++++++++++++++++++++++-------------- src/pages/index.astro | 110 ++++++++++++++++++----------- 2 files changed, 158 insertions(+), 97 deletions(-) diff --git a/src/components/Card.astro b/src/components/Card.astro index d46d184..d29f123 100644 --- a/src/components/Card.astro +++ b/src/components/Card.astro @@ -1,8 +1,8 @@ --- -const { frontmatter } = Astro.props; -const { birthDate, health, manifestations, date } = frontmatter; +const { frontmatter, streakCount = 1 } = Astro.props; +const { birthDate, health, manifestations, date, name } = frontmatter; -// 1. CALCUL DU NIVEAU +// 1. CALCUL DU NIVEAU ET VARIABLES DE BASE [cite: 25, 26, 27] const referenceDate = new Date(date); const birth = new Date(birthDate); let age = referenceDate.getFullYear() - birth.getFullYear(); @@ -12,11 +12,11 @@ if ( ) age--; -// 2. VARIABLES ET COMPTAGES const stress = health?.somatic?.stress_level ?? 2; const hallucinations = health?.mental?.hallucinations ?? 0; const sleepBase = health?.somatic?.sleep_avg ?? 7.5; +// 2. RÉINTÉGRATION DES COMPTAGES (Le fix pour l'erreur) [cite: 28, 29, 30, 31] const counts = { PRO: manifestations?.filter((m) => m.cercle === "PRO").length || 0, SAN: manifestations?.filter((m) => m.cercle === "SAN").length || 0, @@ -24,54 +24,64 @@ const counts = { FLX: manifestations?.filter((m) => m.cercle === "FLX").length || 0, }; -// 3. SCORE D'HARMONIE -const harmonyScore = +// 3. SCORE D'HARMONIE RAFFINÉ [cite: 32, 33] +const rawHarmony = manifestations?.reduce((acc, m) => { if (m.type === "pos") return acc + 1; if (m.type === "neg") return acc - 1; return acc; }, 0) || 0; -// 4. STATS TCG const uniqueCercles = new Set(manifestations?.map((m) => m.cercle)).size; +const hasAllCercles = uniqueCercles === 4; +const harmonyScore = rawHarmony + (hasAllCercles ? 2 : 0); + +// 4. SYSTÈME DE RARETÉ ET SHINY +let rarity = "COMMUNE"; +let isShiny = false; + +// Condition Shiny : Dès 3 jours de série + équilibre des cercles +if (streakCount >= 3 && uniqueCercles >= 3) { + isShiny = true; +} + +// Paliers de Rareté +if (streakCount >= 3) rarity = "PEU COMMUNE"; +if (streakCount >= 6) rarity = "RARE"; // Ta situation actuelle +if (streakCount >= 10 && harmonyScore >= 4) rarity = "LÉGENDAIRE"; +if (streakCount >= 20 && hallucinations === 0) rarity = "MYTHIQUE"; + +// 5. STATS TCG (Avec bonus de série) const autoMotivation = health?.mental?.motivation ?? Math.min(10, uniqueCercles * 2.5); -const harmonyAtkBonus = harmonyScore > 0 ? 1 : 0; -const harmonyDefPenalty = harmonyScore < -2 ? 2 : 0; - +const streakBonus = Math.floor(streakCount / 7); const autoAtk = Math.min( - 10, - counts.PRO * 2 + Math.floor(autoMotivation / 4) + harmonyAtkBonus, + 12, + counts.PRO * 2 + + Math.floor(autoMotivation / 4) + + (harmonyScore > 0 ? 1 : 0) + + streakBonus, ); const sleepPenalty = sleepBase - (counts.PRO > 5 ? 1 : 0) < 6 ? 2 : 0; const autoDef = Math.max( 0, - 10 - stress - hallucinations - sleepPenalty - harmonyDefPenalty, + 10 - stress - hallucinations - sleepPenalty + streakBonus, ); const autoCost = Math.max(1, Math.ceil((manifestations?.length || 0) / 2)); -// 5. LOGIQUE DES BIOMES (L'ÉQUILIBRE FINAL) +// 6. LOGIQUE DES BIOMES [cite: 39, 40, 41, 42, 43, 44] let autoBiome = "SAVANE"; let biomeReason = "Équilibre par défaut"; - -// 1. SANTÉ (ÉTANG) - Priorité critique if (stress > 7 || hallucinations >= 2 || harmonyScore <= -3) { autoBiome = "ETANG"; biomeReason = "Alerte Santé / Harmonie critique"; -} -// 2. ÉQUILIBRE RICHE (BELOUVE) - Priorité si diversité de vie -else if (uniqueCercles >= 3 && counts.SAN > 0) { +} else if (uniqueCercles >= 3 && counts.SAN > 0) { autoBiome = "BELOUVE"; biomeReason = "Harmonie des Cercles"; -} -// 3. FLUX SOCIAL (OCEAN) - Si le social domine le pro -else if (counts.SOC > counts.PRO || counts.FLX > 2) { +} else if (counts.SOC > counts.PRO || counts.FLX > 2) { autoBiome = "OCEAN"; biomeReason = "Flux Social & Émotionnel"; -} -// 4. LA FORGE (FOURNAISE) - Si le pro domine OU si on a une accumulation (>= 2) -// mais qu'on n'est pas déjà tombé dans Belouve ou Ocean -else if (counts.PRO >= 2 && counts.PRO >= counts.SOC) { +} else if (counts.PRO >= 2 && counts.PRO >= counts.SOC) { autoBiome = "FOURNAISE"; biomeReason = "Dominance Technique (PRO)"; } @@ -108,7 +118,6 @@ const biomes = { weak: "OCEAN", }, }; - const currentBiome = biomes[autoBiome] || biomes.SAVANE; const circleSummaries = Object.entries(counts) @@ -122,20 +131,25 @@ const circleSummaries = Object.entries(counts) })); --- -
+
- {frontmatter.name} + {name} {autoCost}
{autoBiome}
{currentBiome.label}
+
{rarity}
Niveau {age} — {frontmatter.identity?.job || "PROTO"} + streak {streakCount}
@@ -157,19 +171,14 @@ const circleSummaries = Object.entries(counts)
    -
  • Origine Biome : {biomeReason}
  • +
  • Origine : {biomeReason}
  • - Surcharge : PRO > 5 ➔ Sommeil -1h + Série : Bonus +{streakBonus} ATK/DEF
  • - Apports : Stress {stress} • Sommeil { - sleepBase - }h • Hallu {hallucinations} -
  • -
  • - Harmonie : Score { + Stress {stress} • Sommeil {sleepBase}h • Harmonie { harmonyScore > 0 ? `+${harmonyScore}` : harmonyScore - } (Motiv. +{autoMotivation}) + }
@@ -178,7 +187,6 @@ const circleSummaries = Object.entries(counts)
VS {currentBiome.strong} (+) - VS {currentBiome.weak} (-)
{autoAtk} / {autoDef} @@ -188,7 +196,7 @@ const circleSummaries = Object.entries(counts)
diff --git a/src/pages/index.astro b/src/pages/index.astro index dad0fd1..e52e956 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -4,12 +4,51 @@ import Layout from "../layouts/Layout.astro"; import Card from "../components/Card.astro"; const allHumans = await getCollection("humans"); -// 1. On trie d'abord par date décroissante pour avoir les plus récents en premier [cite: 65] + +// 1. Tri par date décroissante const sortedAll = allHumans.sort( (a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime(), ); -// 2. On utilise une Map pour ne garder que la première occurrence (la plus récente) de chaque nom +// 2. Fonction de calcul de Streak (Série) corrigée +const getStreak = (name, entries) => { + // On extrait toutes les dates pour cet utilisateur au format YYYY-MM-DD + const userDates = entries + .filter((e) => e.data.name === name) + .map((e) => new Date(e.data.date).toISOString().split("T")[0]); + + // On dédoublonne et on trie (plus récent au plus ancien) + const uniqueDates = [...new Set(userDates)].sort().reverse(); + + let streak = 0; + let today = new Date(); + // On cale la date de vérification sur aujourd'hui à minuit + let checkDate = new Date( + today.getFullYear(), + today.getMonth(), + today.getDate(), + ); + + for (let i = 0; i < 31; i++) { + const dateStr = checkDate.toISOString().split("T")[0]; + + if (uniqueDates.includes(dateStr)) { + streak++; + checkDate.setDate(checkDate.getDate() - 1); + } else { + // Tolérance : si pas de note aujourd'hui, on vérifie si la série continue depuis hier + if (i === 0) { + checkDate.setDate(checkDate.getDate() - 1); + const yesterdayStr = checkDate.toISOString().split("T")[0]; + if (uniqueDates.includes(yesterdayStr)) continue; + } + break; + } + } + return streak; +}; + +// 3. Unicité par utilisateur pour l'affichage (dernière version de chaque profil) const latestPerUser = Array.from( sortedAll .reduce((map, obj) => { @@ -33,25 +72,33 @@ const latestPerUser = Array.from(
{ - latestPerUser.map((entry) => ( -
- - - )) + ); + }) }