Files
amayo/src/commands/messages/game/mina.ts

200 lines
6.8 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { CommandMessage } from "../../../core/types/commands";
import type Amayo from "../../../core/client";
import { runMinigame } from "../../../game/minigames/service";
import {
getDefaultLevel,
findBestToolKey,
parseGameArgs,
resolveGuildAreaWithFallback,
resolveAreaByType,
sendDisplayReply,
fetchItemBasics,
formatItemLabel,
} from "./_helpers";
import { updateStats } from "../../../game/stats/service";
import { updateQuestProgress } from "../../../game/quests/service";
import { checkAchievements } from "../../../game/achievements/service";
import {
buildDisplay,
dividerBlock,
textBlock,
} from "../../../core/lib/componentsV2";
import { formatToolLabel, combatSummaryRPG } from "../../../game/lib/rpgFormat";
import { buildAreaMetadataBlocks } from "./_helpers";
const MINING_ACCENT = 0xc27c0e;
export const command: CommandMessage = {
name: "mina",
type: "message",
aliases: ["minar"],
cooldown: 5,
description:
"Ir a la mina (usa pico si está disponible) y obtener recompensas según el nivel.",
usage: "mina [nivel] [toolKey] [area:clave] (ej: mina 2 tool.pickaxe.basic)",
run: async (message, args, _client: Amayo) => {
const userId = message.author.id;
const guildId = message.guild!.id;
const { levelArg, providedTool, areaOverride } = parseGameArgs(args);
const areaInfo = areaOverride
? await resolveGuildAreaWithFallback(guildId, areaOverride)
: await resolveAreaByType(guildId, "MINE");
if (!areaInfo.area) {
if (areaOverride) {
await message.reply(
`⚠️ No existe un área con key \`${areaOverride}\` para este servidor.`
);
} else {
await message.reply(
"⚠️ No hay un área de tipo **MINE** configurada. Crea una con `!area-crear` o especifica `area:<key>`."
);
}
return;
}
const { area, source } = areaInfo;
const globalNotice =
source === "global"
? ` Usando configuración global para \`${area.key}\`. Puedes crear \`gameArea\` tipo **MINE** para personalizarla en este servidor.`
: null;
const level = levelArg ?? (await getDefaultLevel(userId, guildId, area.id));
const toolKey =
providedTool ?? (await findBestToolKey(userId, guildId, "pickaxe"));
try {
const result = await runMinigame(userId, guildId, area.key, level, {
toolKey: toolKey ?? undefined,
});
const rewardKeys = result.rewards
.filter(
(r): r is { type: "item"; itemKey: string; qty?: number } =>
r.type === "item" && Boolean(r.itemKey)
)
.map((r) => r.itemKey!);
if (result.tool?.key) rewardKeys.push(result.tool.key);
const rewardItems = await fetchItemBasics(guildId, rewardKeys);
// Actualizar stats
await updateStats(userId, guildId, { minesCompleted: 1 });
// Actualizar progreso de misiones
await updateQuestProgress(userId, guildId, "mine_count", 1);
// Verificar logros
const newAchievements = await checkAchievements(
userId,
guildId,
"mine_count"
);
let rewardLines = result.rewards.length
? result.rewards
.map((r) => {
if (r.type === "coins") return `• 🪙 +${r.amount}`;
const info = rewardItems.get(r.itemKey!);
const label = formatItemLabel(
info ?? { key: r.itemKey!, name: null, icon: null }
);
return `${label} x${r.qty ?? 1}`;
})
.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")
: "• —";
const toolInfo = result.tool?.key
? formatToolLabel({
key: result.tool.key,
displayName: formatItemLabel(
rewardItems.get(result.tool.key) ?? {
key: result.tool.key,
name: null,
icon: null,
},
{ fallbackIcon: "🔧" }
),
instancesRemaining: result.tool.instancesRemaining,
broken: result.tool.broken,
brokenInstance: result.tool.brokenInstance,
durabilityDelta: result.tool.durabilityDelta,
remaining: result.tool.remaining,
max: result.tool.max,
source: result.tool.toolSource,
})
: "—";
const combatSummary = result.combat
? combatSummaryRPG({
mobs: result.mobs.length,
mobsDefeated: result.combat.mobsDefeated,
totalDamageDealt: result.combat.totalDamageDealt,
totalDamageTaken: result.combat.totalDamageTaken,
playerStartHp: result.combat.playerStartHp,
playerEndHp: result.combat.playerEndHp,
outcome: result.combat.outcome,
})
: null;
const blocks = [textBlock("# ⛏️ Mina")];
if (globalNotice) {
blocks.push(dividerBlock({ divider: false, spacing: 1 }));
blocks.push(textBlock(globalNotice));
}
blocks.push(dividerBlock());
const areaScope =
source === "global"
? "🌐 Configuración global"
: "📍 Configuración local";
blocks.push(
textBlock(
`**Área:** \`${area.key}\`${areaScope}\n**Nivel:** ${level}\n**Herramienta:** ${toolInfo}`
)
);
blocks.push(dividerBlock({ divider: false, spacing: 1 }));
blocks.push(textBlock(`**Recompensas**\n${rewardLines}`));
blocks.push(dividerBlock({ divider: false, spacing: 1 }));
blocks.push(textBlock(`**Mobs**\n${mobsLines}`));
if (combatSummary) {
blocks.push(dividerBlock({ divider: false, spacing: 1 }));
blocks.push(textBlock(combatSummary));
}
// Añadir metadata del área (imagen/descripcion) si existe
const metaBlocks = buildAreaMetadataBlocks(area);
if (metaBlocks.length) {
blocks.push(dividerBlock({ divider: false, spacing: 1 }));
blocks.push(...metaBlocks);
}
if (newAchievements.length > 0) {
blocks.push(dividerBlock({ divider: false, spacing: 2 }));
const achLines = newAchievements
.map((ach) => `✨ **${ach.name}** — ${ach.description}`)
.join("\n");
blocks.push(textBlock(`🏆 ¡Logro desbloqueado!\n${achLines}`));
}
const display = buildDisplay(MINING_ACCENT, blocks);
await sendDisplayReply(message, display);
} catch (e: any) {
await message.reply(`❌ No se pudo minar: ${e?.message ?? e}`);
}
},
};