From 0b0a73d1140456044f5e0594a9249a2f36b2e788 Mon Sep 17 00:00:00 2001 From: shni Date: Thu, 9 Oct 2025 01:49:36 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20agregar=20penalizaci=C3=B3n=20por=20fat?= =?UTF-8?q?iga=20en=20recompensas=20de=20minijuegos;=20ajustar=20l=C3=B3gi?= =?UTF-8?q?ca=20de=20recompensas=20y=20modificar=20tipos=20para=20incluir?= =?UTF-8?q?=20modificadores?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/messages/game/mina.ts | 11 +++++- src/commands/messages/game/pelear.ts | 11 +++++- src/commands/messages/game/pescar.ts | 11 +++++- src/game/minigames/service.ts | 54 +++++++++++++++++++++++----- src/game/minigames/types.ts | 5 +++ 5 files changed, 80 insertions(+), 12 deletions(-) diff --git a/src/commands/messages/game/mina.ts b/src/commands/messages/game/mina.ts index 30364ca..d13fb9e 100644 --- a/src/commands/messages/game/mina.ts +++ b/src/commands/messages/game/mina.ts @@ -91,7 +91,7 @@ export const command: CommandMessage = { "mine_count" ); - const rewardLines = result.rewards.length + let rewardLines = result.rewards.length ? result.rewards .map((r) => { if (r.type === "coins") return `• 🪙 +${r.amount}`; @@ -103,6 +103,15 @@ export const command: CommandMessage = { }) .join("\n") : "• —"; + if ( + result.rewardModifiers?.fatigueCoinMultiplier != null && + result.rewardModifiers.fatigueCoinMultiplier < 1 + ) { + const pct = Math.round( + (1 - result.rewardModifiers.fatigueCoinMultiplier) * 100 + ); + rewardLines += `\n (⚠️ Fatiga -${pct}% monedas)`; + } const mobsLines = result.mobs.length ? result.mobs.map((m) => `• ${m}`).join("\n") : "• —"; diff --git a/src/commands/messages/game/pelear.ts b/src/commands/messages/game/pelear.ts index 18a110e..472d4f8 100644 --- a/src/commands/messages/game/pelear.ts +++ b/src/commands/messages/game/pelear.ts @@ -101,7 +101,7 @@ export const command: CommandMessage = { "fight_count" ); - const rewardLines = result.rewards.length + let rewardLines = result.rewards.length ? result.rewards .map((r) => { if (r.type === "coins") return `• 🪙 +${r.amount}`; @@ -113,6 +113,15 @@ export const command: CommandMessage = { }) .join("\n") : "• —"; + if ( + result.rewardModifiers?.fatigueCoinMultiplier != null && + result.rewardModifiers.fatigueCoinMultiplier < 1 + ) { + const pct = Math.round( + (1 - result.rewardModifiers.fatigueCoinMultiplier) * 100 + ); + rewardLines += `\n (⚠️ Fatiga -${pct}% monedas)`; + } const mobsLines = result.mobs.length ? result.mobs.map((m) => `• ${m}`).join("\n") : "• —"; diff --git a/src/commands/messages/game/pescar.ts b/src/commands/messages/game/pescar.ts index f0474a0..1041d2b 100644 --- a/src/commands/messages/game/pescar.ts +++ b/src/commands/messages/game/pescar.ts @@ -87,7 +87,7 @@ export const command: CommandMessage = { "fish_count" ); - const rewardLines = result.rewards.length + let rewardLines = result.rewards.length ? result.rewards .map((r) => { if (r.type === "coins") return `• 🪙 +${r.amount}`; @@ -99,6 +99,15 @@ export const command: CommandMessage = { }) .join("\n") : "• —"; + if ( + result.rewardModifiers?.fatigueCoinMultiplier != null && + result.rewardModifiers.fatigueCoinMultiplier < 1 + ) { + const pct = Math.round( + (1 - result.rewardModifiers.fatigueCoinMultiplier) * 100 + ); + rewardLines += `\n (⚠️ Fatiga -${pct}% monedas)`; + } const mobsLines = result.mobs.length ? result.mobs.map((m) => `• ${m}`).join("\n") : "• —"; diff --git a/src/game/minigames/service.ts b/src/game/minigames/service.ts index 17a3387..7e4eb62 100644 --- a/src/game/minigames/service.ts +++ b/src/game/minigames/service.ts @@ -1,4 +1,7 @@ -import { applyDeathFatigue } from "../combat/statusEffectsService"; +import { + applyDeathFatigue, + getActiveStatusEffects, +} from "../combat/statusEffectsService"; import { getOrCreateWallet } from "../economy/service"; import { prisma } from "../../core/database/prisma"; import { @@ -201,19 +204,42 @@ async function applyRewards( userId: string, guildId: string, rewards?: RewardsTable -): Promise { +): Promise<{ + rewards: RunResult["rewards"]; + modifiers?: RunResult["rewardModifiers"]; +}> { const results: RunResult["rewards"] = []; if (!rewards || !Array.isArray(rewards.table) || rewards.table.length === 0) - return results; + return { rewards: results }; + + // Detectar efecto FATIGUE activo para penalizar SOLO monedas. + let fatigueMagnitude: number | undefined; + try { + const effects = await getActiveStatusEffects(userId, guildId); + const fatigue = effects.find((e) => e.type === "FATIGUE"); + if (fatigue && typeof fatigue.magnitude === "number") { + fatigueMagnitude = Math.max(0, Math.min(0.9, fatigue.magnitude)); + } + } catch { + // silencioso + } + const coinMultiplier = fatigueMagnitude + ? Math.max(0, 1 - fatigueMagnitude) + : 1; + const draws = Math.max(1, rewards.draws ?? 1); for (let i = 0; i < draws; i++) { const pick = pickWeighted(rewards.table); if (!pick) continue; if (pick.type === "coins") { - const amt = Math.max(0, pick.amount); - if (amt > 0) { - await adjustCoins(userId, guildId, amt); - results.push({ type: "coins", amount: amt }); + const baseAmt = Math.max(0, pick.amount); + if (baseAmt > 0) { + const adjusted = Math.max(0, Math.floor(baseAmt * coinMultiplier)); + const finalAmt = coinMultiplier < 1 && adjusted === 0 ? 1 : adjusted; // al menos 1 si había algo base + if (finalAmt > 0) { + await adjustCoins(userId, guildId, finalAmt); + results.push({ type: "coins", amount: finalAmt }); + } } } else if (pick.type === "item") { const qty = Math.max(1, pick.qty); @@ -221,7 +247,11 @@ async function applyRewards( results.push({ type: "item", itemKey: pick.itemKey, qty }); } } - return results; + const modifiers = + coinMultiplier < 1 + ? { fatigueCoinMultiplier: coinMultiplier, fatigueMagnitude } + : undefined; + return { rewards: results, modifiers }; } async function sampleMobs(mobs?: MobsTable): Promise { @@ -381,7 +411,11 @@ export async function runMinigame( ); // Aplicar recompensas y samplear mobs - const delivered = await applyRewards(userId, guildId, rewards); + const { rewards: delivered, modifiers: rewardModifiers } = await applyRewards( + userId, + guildId, + rewards + ); const mobsSpawned = await sampleMobs(mobs); // Reducir durabilidad de herramienta si se usó @@ -729,6 +763,7 @@ export async function runMinigame( mobs: mobsSpawned, tool: toolInfo, combat: combatSummary, + rewardModifiers, notes: "auto", } as unknown as Prisma.InputJsonValue; @@ -776,6 +811,7 @@ export async function runMinigame( mobs: mobsSpawned, tool: toolInfo, combat: combatSummary, + rewardModifiers, }; } diff --git a/src/game/minigames/types.ts b/src/game/minigames/types.ts index b249c6f..7e43e02 100644 --- a/src/game/minigames/types.ts +++ b/src/game/minigames/types.ts @@ -62,6 +62,11 @@ export type RunResult = { toolSource?: "provided" | "equipped" | "auto"; // origen de la selección }; combat?: CombatSummary; // resumen de combate si hubo mobs y se procesó + // Modificadores aplicados a las recompensas (ej: penalización por FATIGUE sobre monedas) + rewardModifiers?: { + fatigueCoinMultiplier?: number; // 0.85 si hay -15% + fatigueMagnitude?: number; // magnitud original del efecto + }; }; // --- Combate Básico ---