diff --git a/frontend/src/constants.ts b/frontend/src/constants.ts new file mode 100644 index 0000000..8e8eeb1 --- /dev/null +++ b/frontend/src/constants.ts @@ -0,0 +1,72 @@ +// ── Game Constants — Source unique frontend ── +// Centralise toutes les constantes dupliquées dans les pages. + +export const RARITY_COLORS: Record = { + common: '#9ca3af', + rare: '#5ba4f5', + epic: '#a78bfa', + legendary: '#f4c94e', +}; + +export const RARITY_LABELS: Record = { + common: 'Commun', + rare: 'Rare', + epic: 'Épique', + legendary: 'Légendaire', +}; + +export const ZONE_INFO: Record = { + marais: { name: 'Les Marais', emoji: '🌿', color: '#3ddc84' }, + egouts: { name: 'Les Égouts', emoji: '🕳️', color: '#5ba4f5' }, + desert: { name: 'Le Désert', emoji: '🏜️', color: '#f4c94e' }, +}; + +export const STAT_LABELS: Record = { + force: 'Force', + agilite: 'Agilité', + intelligence: 'Intelligence', + chance: 'Chance', + vitalite: 'Vitalité', +}; + +export const TYPE_EMOJI: Record = { + weapon: '⚔️', + armor: '🛡️', + consumable: '🧪', +}; + +// ── Coûts de jeu ── + +export const COMBAT_COST = 5; +export const REST_COST = 10; +export const FORGE_ENDURANCE_COST = 10; + +export const FORGE_GOLD_COST: Record = { + 1: 50, + 2: 100, + 3: 200, + 4: 400, + 5: 700, +}; + +export const FORGE_FAIL_CHANCE: Record = { + 1: 0, + 2: 0, + 3: 20, + 4: 30, + 5: 40, +}; + +export const FORGE_TABLE = [ + { level: 1, gold: 50, endurance: 10, risk: '0%', bonus: '+2' }, + { level: 2, gold: 100, endurance: 10, risk: '0%', bonus: '+4' }, + { level: 3, gold: 200, endurance: 10, risk: '20%', bonus: '+6' }, + { level: 4, gold: 400, endurance: 10, risk: '30%', bonus: '+8' }, + { level: 5, gold: 700, endurance: 10, risk: '40%', bonus: '+10' }, +]; + +export const ATTACK_TYPES = [ + { id: 'melee', label: 'Mêlée', emoji: '⚔️', stat: 'Force × 1.5' }, + { id: 'ranged', label: 'Distance', emoji: '🏹', stat: 'Agilité × 1.5' }, + { id: 'magic', label: 'Magie', emoji: '✨', stat: 'Intelligence × 1.5' }, +]; diff --git a/frontend/src/pages/CombatPage.tsx b/frontend/src/pages/CombatPage.tsx index a50fb78..28b2c28 100644 --- a/frontend/src/pages/CombatPage.tsx +++ b/frontend/src/pages/CombatPage.tsx @@ -5,14 +5,7 @@ import { combatApi, characterApi } from '../api/endpoints'; import type { Monster, CombatResult, MultiCombatResult, CombatLog } from '../api/types'; import { Swords, Trophy, Skull, Clock, Zap, Heart, Lock } from 'lucide-react'; -const COMBAT_COST = 5; -const REST_COST = 10; - -const ATTACK_TYPES = [ - { id: 'melee', label: 'Mêlée', emoji: '⚔️', stat: 'Force × 1.5' }, - { id: 'ranged', label: 'Distance', emoji: '🏹', stat: 'Agilité × 1.5' }, - { id: 'magic', label: 'Magie', emoji: '✨', stat: 'Intelligence × 1.5' }, -]; +import { COMBAT_COST, REST_COST, ATTACK_TYPES, ZONE_INFO } from '../constants'; function MonsterCard({ m, selected, onSelect, playerLevel }: { m: Monster; selected: boolean; onSelect: () => void; playerLevel: number }) { const tooHard = m.minLevel > playerLevel + 2; @@ -211,11 +204,7 @@ export function CombatPage() { monstersByZone.set(zone, list); } - const ZONE_LABELS: Record = { - marais: { name: 'Les Marais', emoji: '🌿' }, - egouts: { name: 'Les Égouts', emoji: '🕳️' }, - desert: { name: 'Le Désert', emoji: '🏜️' }, - }; + const ZONE_LABELS = ZONE_INFO; // Locked zones (zones not in monsters response = locked) const lockedZones = (zones ?? []).filter((z: any) => !z.unlocked); diff --git a/frontend/src/pages/ForgePage.tsx b/frontend/src/pages/ForgePage.tsx index 17d9af4..aa7a0e0 100644 --- a/frontend/src/pages/ForgePage.tsx +++ b/frontend/src/pages/ForgePage.tsx @@ -5,10 +5,10 @@ import { itemApi, forgeApi, characterApi } from '../api/endpoints'; import type { CharacterItem } from '../api/types'; import { Shield, CheckCircle, XCircle, AlertTriangle, Zap, Coins } from 'lucide-react'; -const FORGE_RISK = [0, 0, 0, 20, 30, 40]; -const FORGE_LABEL = ['—', '—', 'Garanti', '20% échec', '30% échec', '40% échec']; -const FORGE_ENDURANCE_COST = 10; -const FORGE_GOLD_COST: Record = { 1: 50, 2: 100, 3: 200, 4: 400, 5: 700 }; +import { FORGE_FAIL_CHANCE, FORGE_ENDURANCE_COST, FORGE_GOLD_COST } from '../constants'; + +const FORGE_RISK = [0, 0, 0, FORGE_FAIL_CHANCE[3], FORGE_FAIL_CHANCE[4], FORGE_FAIL_CHANCE[5]]; +const FORGE_LABEL = ['—', '—', 'Garanti', `${FORGE_FAIL_CHANCE[3]}% échec`, `${FORGE_FAIL_CHANCE[4]}% échec`, `${FORGE_FAIL_CHANCE[5]}% échec`]; function ForgePanel({ nextLevel, risk, endurance, gold, isPending, onForge }: { nextLevel: number; risk: number; endurance: number; gold: number; isPending: boolean; onForge: () => void; diff --git a/frontend/src/pages/GuidePage.tsx b/frontend/src/pages/GuidePage.tsx index 60476b8..32d4b43 100644 --- a/frontend/src/pages/GuidePage.tsx +++ b/frontend/src/pages/GuidePage.tsx @@ -3,29 +3,12 @@ import { useNavigate } from 'react-router-dom'; import type { Monster, Item, Recipe } from '../api/types'; import { Swords, Shield, Map as MapIcon, Hammer, ShoppingBag, BookOpen, Sparkles, Search, Gamepad2 } from 'lucide-react'; import { useGuideData } from '../hooks/useGuideData'; - -// ── Constants ── +import { RARITY_COLORS, RARITY_LABELS, FORGE_TABLE, ZONE_INFO } from '../constants'; const ZONES = [ - { id: 'marais', name: 'Les Marais', emoji: '🌿', desc: 'Zone de départ. Monstres niv. 1-9. Terre de boue et de brume.', color: '#3ddc84' }, - { id: 'egouts', name: 'Les Égouts', emoji: '🕳️', desc: 'Sous-terrain infesté. Monstres niv. 4-10. Rats, slimes et croco.', color: '#5ba4f5' }, - { id: 'desert', name: 'Le Désert', emoji: '🏜️', desc: 'Sable brûlant. Monstres niv. 8-15. Scorpions, momies et le Sphinx.', color: '#f4c94e' }, -]; - -const RARITY_COLORS: Record = { - common: '#9ca3af', rare: '#5ba4f5', epic: '#a78bfa', legendary: '#f4c94e', -}; - -const RARITY_LABELS: Record = { - common: 'Commun', rare: 'Rare', epic: 'Épique', legendary: 'Légendaire', -}; - -const FORGE_TABLE = [ - { level: 1, gold: 50, endurance: 10, risk: '0%', bonus: '+2' }, - { level: 2, gold: 100, endurance: 10, risk: '0%', bonus: '+4' }, - { level: 3, gold: 200, endurance: 10, risk: '20%', bonus: '+6' }, - { level: 4, gold: 400, endurance: 10, risk: '30%', bonus: '+8' }, - { level: 5, gold: 700, endurance: 10, risk: '40%', bonus: '+10' }, + { id: 'marais', ...ZONE_INFO.marais, desc: 'Zone de départ. Monstres niv. 1-9. Terre de boue et de brume.' }, + { id: 'egouts', ...ZONE_INFO.egouts, desc: 'Sous-terrain infesté. Monstres niv. 4-10. Rats, slimes et croco.' }, + { id: 'desert', ...ZONE_INFO.desert, desc: 'Sable brûlant. Monstres niv. 8-15. Scorpions, momies et le Sphinx.' }, ]; const TABS = [ diff --git a/frontend/src/pages/InventoryPage.tsx b/frontend/src/pages/InventoryPage.tsx index eaa834b..e950e79 100644 --- a/frontend/src/pages/InventoryPage.tsx +++ b/frontend/src/pages/InventoryPage.tsx @@ -5,9 +5,7 @@ import { api } from '../api/client'; import type { CharacterItem } from '../api/types'; import { Package, Sword, Shield, Coins } from 'lucide-react'; -const RARITY_LABEL: Record = { - common: 'Commun', rare: 'Rare', epic: 'Épique', legendary: 'Légendaire', -}; +import { RARITY_LABELS as RARITY_LABEL, FORGE_GOLD_COST as FORGE_COSTS_MAP } from '../constants'; function ItemCard({ ci, onEquip, onUnequip, onSell, selling }: { ci: CharacterItem; onEquip: () => void; onUnequip: () => void; onSell: () => void; selling: boolean; @@ -17,9 +15,8 @@ function ItemCard({ ci, onEquip, onUnequip, onSell, selling }: { const forgeBonusDEF = item.type === 'armor' ? ci.forgeLevel * 2 : 0; const totalATK = item.attackBonus + forgeBonusATK; const totalDEF = item.defenseBonus + forgeBonusDEF; - const FORGE_COSTS: Record = { 1: 50, 2: 100, 3: 200, 4: 400, 5: 700 }; let forgeInvestment = 0; - for (let i = 1; i <= ci.forgeLevel; i++) forgeInvestment += FORGE_COSTS[i] ?? 0; + for (let i = 1; i <= ci.forgeLevel; i++) forgeInvestment += FORGE_COSTS_MAP[i] ?? 0; const sellPrice = Math.floor(((item as any).buyPrice || 0) * 0.4 + forgeInvestment * 0.5); const bonuses = [ diff --git a/frontend/src/pages/ShopPage.tsx b/frontend/src/pages/ShopPage.tsx index 013e0e0..2df0d36 100644 --- a/frontend/src/pages/ShopPage.tsx +++ b/frontend/src/pages/ShopPage.tsx @@ -4,24 +4,7 @@ import { characterApi } from '../api/endpoints'; import { api } from '../api/client'; import { Coins, ShoppingBag, Sword, Shield, Heart, Zap } from 'lucide-react'; -const RARITY_COLORS: Record = { - common: '#9ca3af', - rare: '#5ba4f5', - epic: '#a78bfa', - legendary: '#f4c94e', -}; - -const TYPE_EMOJI: Record = { - weapon: '⚔️', - armor: '🛡️', - consumable: '🧪', -}; - -const ZONE_LABELS: Record = { - marais: '🌿 Marais', - egouts: '🕳️ Égouts', - desert: '🏜️ Désert', -}; +import { RARITY_COLORS, TYPE_EMOJI, ZONE_INFO } from '../constants'; interface ShopItem { id: string; @@ -153,7 +136,7 @@ export function ShopPage() { {sortedZones.map(([zone, items]) => (

- {zone === 'general' ? '🧪 Consommables' : ZONE_LABELS[zone] ?? zone} + {zone === 'general' ? '🧪 Consommables' : ZONE_INFO[zone] ? `${ZONE_INFO[zone].emoji} ${ZONE_INFO[zone].name}` : zone}

{items.map(item => (