2025-10-05 01:54:12 -05:00
|
|
|
|
import type { CommandMessage } from '../../../core/types/commands';
|
|
|
|
|
|
import type Amayo from '../../../core/client';
|
|
|
|
|
|
import { runMinigame } from '../../../game/minigames/service';
|
2025-10-05 21:37:54 -05:00
|
|
|
|
import { getDefaultLevel, findBestToolKey, parseGameArgs, resolveGuildAreaWithFallback, resolveAreaByType, sendDisplayReply, fetchItemBasics, formatItemLabel } from './_helpers';
|
2025-10-05 05:35:32 -05:00
|
|
|
|
import { updateStats } from '../../../game/stats/service';
|
|
|
|
|
|
import { updateQuestProgress } from '../../../game/quests/service';
|
|
|
|
|
|
import { checkAchievements } from '../../../game/achievements/service';
|
2025-10-05 21:37:54 -05:00
|
|
|
|
import { buildDisplay, dividerBlock, textBlock } from '../../../core/lib/componentsV2';
|
|
|
|
|
|
|
|
|
|
|
|
const MINING_ACCENT = 0xC27C0E;
|
2025-10-05 01:54:12 -05:00
|
|
|
|
|
|
|
|
|
|
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.',
|
2025-10-05 19:34:45 -05:00
|
|
|
|
usage: 'mina [nivel] [toolKey] [area:clave] (ej: mina 2 tool.pickaxe.basic)',
|
2025-10-05 01:54:12 -05:00
|
|
|
|
run: async (message, args, _client: Amayo) => {
|
|
|
|
|
|
const userId = message.author.id;
|
|
|
|
|
|
const guildId = message.guild!.id;
|
2025-10-05 19:58:26 -05:00
|
|
|
|
const { levelArg, providedTool, areaOverride } = parseGameArgs(args);
|
2025-10-05 01:54:12 -05:00
|
|
|
|
|
2025-10-05 19:58:26 -05:00
|
|
|
|
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>`.');
|
|
|
|
|
|
}
|
2025-10-05 19:34:45 -05:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-10-05 19:58:26 -05:00
|
|
|
|
|
|
|
|
|
|
const { area, source } = areaInfo;
|
2025-10-05 19:44:54 -05:00
|
|
|
|
const globalNotice = source === 'global'
|
2025-10-05 19:58:26 -05:00
|
|
|
|
? `ℹ️ Usando configuración global para \`${area.key}\`. Puedes crear \`gameArea\` tipo **MINE** para personalizarla en este servidor.`
|
2025-10-05 19:44:54 -05:00
|
|
|
|
: null;
|
2025-10-05 01:54:12 -05:00
|
|
|
|
|
|
|
|
|
|
const level = levelArg ?? await getDefaultLevel(userId, guildId, area.id);
|
|
|
|
|
|
const toolKey = providedTool ?? await findBestToolKey(userId, guildId, 'pickaxe');
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
2025-10-05 19:34:45 -05:00
|
|
|
|
const result = await runMinigame(userId, guildId, area.key, level, { toolKey: toolKey ?? undefined });
|
2025-10-05 21:37:54 -05:00
|
|
|
|
|
|
|
|
|
|
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);
|
2025-10-05 05:35:32 -05:00
|
|
|
|
|
|
|
|
|
|
// Actualizar stats
|
|
|
|
|
|
await updateStats(userId, guildId, { minesCompleted: 1 });
|
2025-10-05 19:44:54 -05:00
|
|
|
|
|
|
|
|
|
|
// Actualizar progreso de misiones
|
|
|
|
|
|
await updateQuestProgress(userId, guildId, 'mine_count', 1);
|
2025-10-05 05:35:32 -05:00
|
|
|
|
|
|
|
|
|
|
// Verificar logros
|
|
|
|
|
|
const newAchievements = await checkAchievements(userId, guildId, 'mine_count');
|
|
|
|
|
|
|
2025-10-05 21:37:54 -05:00
|
|
|
|
const 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')
|
|
|
|
|
|
: '• —';
|
|
|
|
|
|
const mobsLines = result.mobs.length
|
|
|
|
|
|
? result.mobs.map(m => `• ${m}`).join('\n')
|
|
|
|
|
|
: '• —';
|
|
|
|
|
|
const toolInfo = result.tool?.key
|
|
|
|
|
|
? `${formatItemLabel(rewardItems.get(result.tool.key) ?? { key: result.tool.key, name: null, icon: null }, { fallbackIcon: '🔧' })}${result.tool.broken ? ' (rota)' : ` (-${result.tool.durabilityDelta ?? 0} dur.)`}`
|
|
|
|
|
|
: '—';
|
|
|
|
|
|
|
|
|
|
|
|
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}`));
|
2025-10-05 05:35:32 -05:00
|
|
|
|
|
|
|
|
|
|
if (newAchievements.length > 0) {
|
2025-10-05 21:37:54 -05:00
|
|
|
|
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}`));
|
2025-10-05 05:35:32 -05:00
|
|
|
|
}
|
2025-10-05 21:37:54 -05:00
|
|
|
|
|
|
|
|
|
|
const display = buildDisplay(MINING_ACCENT, blocks);
|
|
|
|
|
|
await sendDisplayReply(message, display);
|
2025-10-05 01:54:12 -05:00
|
|
|
|
} catch (e: any) {
|
|
|
|
|
|
await message.reply(`❌ No se pudo minar: ${e?.message ?? e}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|