diff --git a/frontend/src/pages/ShopPage.tsx b/frontend/src/pages/ShopPage.tsx index 6f674ab..93342dc 100644 --- a/frontend/src/pages/ShopPage.tsx +++ b/frontend/src/pages/ShopPage.tsx @@ -1,7 +1,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { characterApi } from '../api/endpoints'; import { api } from '../api/client'; -import { Coins, ShoppingBag, Sword, Shield, Heart } from 'lucide-react'; +import { Coins, ShoppingBag, Sword, Shield, Heart, Zap } from 'lucide-react'; const RARITY_COLORS: Record = { common: '#9ca3af', @@ -58,7 +58,10 @@ function ShopItemCard({ item, onBuy, buying }: { item: ShopItem; onBuy: () => vo
{item.attackBonus > 0 && +{item.attackBonus} ATK} {item.defenseBonus > 0 && +{item.defenseBonus} DEF} - {item.type === 'consumable' && +50% PV} + {item.type === 'consumable' && (item as any).forceBonus > 0 + ? +{(item as any).forceBonus} endurance + : item.type === 'consumable' && +50% PV + } {item.minLevel > 1 && Niv. {item.minLevel}+}
@@ -131,8 +134,10 @@ export function ShopPage() { {buyMut.isSuccess && (
- {(buyMut.data as any)?.type === 'consumable' - ? `🧪 ${(buyMut.data as any)?.item} utilisé ! +${(buyMut.data as any)?.effect?.healed} PV` + {(buyMut.data as any)?.effectType === 'endurance' + ? `⚡ ${(buyMut.data as any)?.item} — +${(buyMut.data as any)?.effect?.restored} endurance` + : (buyMut.data as any)?.effectType === 'hp' + ? `🧪 ${(buyMut.data as any)?.item} — +${(buyMut.data as any)?.effect?.healed} PV` : `✅ ${(buyMut.data as any)?.item} acheté ! (-${(buyMut.data as any)?.goldSpent} or)` }
diff --git a/src/combat/combat.service.ts b/src/combat/combat.service.ts index 38bd7ce..42f57a9 100644 --- a/src/combat/combat.service.ts +++ b/src/combat/combat.service.ts @@ -57,7 +57,7 @@ export class CombatService { // Calculer l'endurance actuelle (lazy pattern) const elapsedMinutes = (Date.now() - character.lastEnduranceTs.getTime()) / 60_000; - const recharge = Math.floor(elapsedMinutes / 6); + const recharge = Math.floor(elapsedMinutes / 3); const enduranceCurrent = Math.min(character.enduranceSaved + recharge, character.enduranceMax); if (enduranceCurrent < COMBAT_ENDURANCE_COST) { diff --git a/src/craft/craft.service.ts b/src/craft/craft.service.ts index 61c3bb5..70e56ff 100644 --- a/src/craft/craft.service.ts +++ b/src/craft/craft.service.ts @@ -40,7 +40,7 @@ export class CraftService { // Calculer endurance actuelle (lazy pattern) const elapsedMinutes = (Date.now() - char.lastEnduranceTs.getTime()) / 60_000; - const recharge = Math.floor(elapsedMinutes / 6); + const recharge = Math.floor(elapsedMinutes / 3); const enduranceCurrent = Math.min(char.enduranceSaved + recharge, char.enduranceMax); if (enduranceCurrent < recipe.enduranceCost) { diff --git a/src/database/zones-seed.ts b/src/database/zones-seed.ts index 817e700..ee8c170 100644 --- a/src/database/zones-seed.ts +++ b/src/database/zones-seed.ts @@ -47,8 +47,11 @@ const ITEMS = [ { name: 'Armure du Pharaon', type: 'armor', rarity: 'epic', attackBonus: 0, defenseBonus: 18, buyPrice: 1300, minLevel: 13, zone: 'desert', description: 'Dorée et ancienne, elle irradie de puissance.' }, // Potions — consommables - { name: 'Potion de soin', type: 'consumable', rarity: 'common', attackBonus: 0, defenseBonus: 0, buyPrice: 15, minLevel: 1, zone: null, description: 'Restaure 50% des PV.' }, - { name: 'Grande potion de soin', type: 'consumable', rarity: 'rare', attackBonus: 0, defenseBonus: 0, buyPrice: 40, minLevel: 5, zone: null, description: 'Restaure 50% des PV. (même effet, plus cher — placeholder pour futur)' }, + // HP potions: forceBonus = 0 → heal 50% HP + { name: 'Potion de soin', type: 'consumable', rarity: 'common', attackBonus: 0, defenseBonus: 0, forceBonus: 0, buyPrice: 15, minLevel: 1, zone: null, description: 'Restaure 50% des PV.' }, + // Endurance potions: forceBonus > 0 → restore N endurance + { name: 'Potion d\'énergie', type: 'consumable', rarity: 'common', attackBonus: 0, defenseBonus: 0, forceBonus: 30, buyPrice: 20, minLevel: 1, zone: null, description: 'Restaure 30 points d\'endurance.' }, + { name: 'Grande potion d\'énergie', type: 'consumable', rarity: 'rare', attackBonus: 0, defenseBonus: 0, forceBonus: 60, buyPrice: 45, minLevel: 3, zone: null, description: 'Restaure 60 points d\'endurance.' }, ]; export async function seedZones(dataSource: DataSource) { diff --git a/src/forge/forge.service.ts b/src/forge/forge.service.ts index 75d2134..75b5345 100644 --- a/src/forge/forge.service.ts +++ b/src/forge/forge.service.ts @@ -70,7 +70,7 @@ export class ForgeService { // Vérifier endurance const elapsedMinutes = (Date.now() - char.lastEnduranceTs.getTime()) / 60_000; - const recharge = Math.floor(elapsedMinutes / 6); + const recharge = Math.floor(elapsedMinutes / 3); const enduranceCurrent = Math.min(char.enduranceSaved + recharge, char.enduranceMax); if (enduranceCurrent < FORGE_ENDURANCE_COST) { diff --git a/src/shop/shop.service.ts b/src/shop/shop.service.ts index 1bcff40..af40c6b 100644 --- a/src/shop/shop.service.ts +++ b/src/shop/shop.service.ts @@ -62,12 +62,42 @@ export class ShopService { // Consumable = effet immédiat, pas d'inventaire if (item.type === 'consumable') { - char.gold -= item.buyPrice; + // Endurance potion: forceBonus > 0 = endurance restore amount + const isEndurancePotion = item.forceBonus > 0; + if (isEndurancePotion) { + // Calc current endurance (lazy) + const elapsed = (Date.now() - char.lastEnduranceTs.getTime()) / 60_000; + const recharge = Math.floor(elapsed / 3); + const currentEndurance = Math.min(char.enduranceSaved + recharge, char.enduranceMax); + + if (currentEndurance >= char.enduranceMax) { + throw new BadRequestException('Endurance déjà au maximum'); + } + + char.gold -= item.buyPrice; + const endBefore = currentEndurance; + const restored = Math.min(item.forceBonus, char.enduranceMax - currentEndurance); + char.enduranceSaved = currentEndurance + restored; + char.lastEnduranceTs = new Date(); + await manager.save(char); + + return { + bought: true, + item: item.name, + type: 'consumable', + effectType: 'endurance', + goldSpent: item.buyPrice, + effect: { enduranceBefore: endBefore, enduranceAfter: char.enduranceSaved, restored }, + }; + } + + // HP potion if (char.hpCurrent >= char.hpMax) { throw new BadRequestException('PV déjà au maximum'); } + char.gold -= item.buyPrice; const hpBefore = char.hpCurrent; char.hpCurrent = Math.min(char.hpMax, char.hpCurrent + Math.floor(char.hpMax * POTION_HEAL_RATIO)); await manager.save(char); @@ -76,6 +106,7 @@ export class ShopService { bought: true, item: item.name, type: 'consumable', + effectType: 'hp', goldSpent: item.buyPrice, effect: { hpBefore, hpAfter: char.hpCurrent, healed: char.hpCurrent - hpBefore }, };