feat: add TypeScript type checking task to VSCode configuration
feat: implement area metadata blocks in game commands for enhanced area details fix: refactor game commands to utilize new area metadata blocks and improve code consistency feat: enhance Appwrite API integration with additional collections and storage support refactor: update componentsV2 to support image blocks in display rendering
This commit is contained in:
@@ -1,21 +1,36 @@
|
||||
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 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 { buildAreaMetadataBlocks } from "./_helpers";
|
||||
|
||||
const FIGHT_ACCENT = 0x992D22;
|
||||
const FIGHT_ACCENT = 0x992d22;
|
||||
|
||||
export const command: CommandMessage = {
|
||||
name: 'pelear',
|
||||
type: 'message',
|
||||
aliases: ['fight','arena'],
|
||||
name: "pelear",
|
||||
type: "message",
|
||||
aliases: ["fight", "arena"],
|
||||
cooldown: 8,
|
||||
description: 'Entra a la arena y pelea (usa espada si está disponible).',
|
||||
usage: 'pelear [nivel] [toolKey] [area:clave] (ej: pelear 1 weapon.sword.iron)',
|
||||
description: "Entra a la arena y pelea (usa espada si está disponible).",
|
||||
usage:
|
||||
"pelear [nivel] [toolKey] [area:clave] (ej: pelear 1 weapon.sword.iron)",
|
||||
run: async (message, args, _client: Amayo) => {
|
||||
const userId = message.author.id;
|
||||
const guildId = message.guild!.id;
|
||||
@@ -23,63 +38,98 @@ export const command: CommandMessage = {
|
||||
|
||||
const areaInfo = areaOverride
|
||||
? await resolveGuildAreaWithFallback(guildId, areaOverride)
|
||||
: await resolveAreaByType(guildId, 'FIGHT');
|
||||
: await resolveAreaByType(guildId, "FIGHT");
|
||||
|
||||
if (!areaInfo.area) {
|
||||
if (areaOverride) {
|
||||
await message.reply(`⚠️ No existe un área con key \`${areaOverride}\` para este servidor.`);
|
||||
await message.reply(
|
||||
`⚠️ No existe un área con key \`${areaOverride}\` para este servidor.`
|
||||
);
|
||||
} else {
|
||||
await message.reply('⚠️ No hay un área de tipo **FIGHT** configurada. Crea una con `!area-crear` o especifica `area:<key>`.');
|
||||
await message.reply(
|
||||
"⚠️ No hay un área de tipo **FIGHT** 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 **FIGHT** para personalizarla en este servidor.`
|
||||
: null;
|
||||
const globalNotice =
|
||||
source === "global"
|
||||
? `ℹ️ Usando configuración global para \`${area.key}\`. Puedes crear \`gameArea\` tipo **FIGHT** para personalizarla en este servidor.`
|
||||
: null;
|
||||
|
||||
const level = levelArg ?? await getDefaultLevel(userId, guildId, area.id);
|
||||
const toolKey = providedTool ?? await findBestToolKey(userId, guildId, 'sword');
|
||||
const level = levelArg ?? (await getDefaultLevel(userId, guildId, area.id));
|
||||
const toolKey =
|
||||
providedTool ?? (await findBestToolKey(userId, guildId, "sword"));
|
||||
|
||||
try {
|
||||
const result = await runMinigame(userId, guildId, area.key, level, { toolKey: toolKey ?? undefined });
|
||||
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))
|
||||
.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 y misiones
|
||||
await updateStats(userId, guildId, { fightsCompleted: 1 });
|
||||
await updateQuestProgress(userId, guildId, 'fight_count', 1);
|
||||
|
||||
await updateQuestProgress(userId, guildId, "fight_count", 1);
|
||||
|
||||
// Contar mobs derrotados
|
||||
const mobsCount = result.mobs.length;
|
||||
if (mobsCount > 0) {
|
||||
await updateStats(userId, guildId, { mobsDefeated: mobsCount });
|
||||
await updateQuestProgress(userId, guildId, 'mob_defeat_count', mobsCount);
|
||||
await updateQuestProgress(
|
||||
userId,
|
||||
guildId,
|
||||
"mob_defeat_count",
|
||||
mobsCount
|
||||
);
|
||||
}
|
||||
|
||||
const newAchievements = await checkAchievements(userId, guildId, 'fight_count');
|
||||
|
||||
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('# ⚔️ Arena')];
|
||||
const newAchievements = await checkAchievements(
|
||||
userId,
|
||||
guildId,
|
||||
"fight_count"
|
||||
);
|
||||
|
||||
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("# ⚔️ Arena")];
|
||||
|
||||
if (globalNotice) {
|
||||
blocks.push(dividerBlock({ divider: false, spacing: 1 }));
|
||||
@@ -87,16 +137,32 @@ export const command: CommandMessage = {
|
||||
}
|
||||
|
||||
blocks.push(dividerBlock());
|
||||
const areaScope = source === 'global' ? '🌐 Configuración global' : '📍 Configuración local';
|
||||
blocks.push(textBlock(`**Área:** \`${area.key}\` • ${areaScope}\n**Nivel:** ${level}\n**Arma:** ${toolInfo}`));
|
||||
const areaScope =
|
||||
source === "global"
|
||||
? "🌐 Configuración global"
|
||||
: "📍 Configuración local";
|
||||
blocks.push(
|
||||
textBlock(
|
||||
`**Área:** \`${area.key}\` • ${areaScope}\n**Nivel:** ${level}\n**Arma:** ${toolInfo}`
|
||||
)
|
||||
);
|
||||
blocks.push(dividerBlock({ divider: false, spacing: 1 }));
|
||||
blocks.push(textBlock(`**Recompensas**\n${rewardLines}`));
|
||||
blocks.push(dividerBlock({ divider: false, spacing: 1 }));
|
||||
blocks.push(textBlock(`**Enemigos**\n${mobsLines}`));
|
||||
|
||||
// Añadir metadata del área
|
||||
const metaBlocks = buildAreaMetadataBlocks(area);
|
||||
if (metaBlocks.length) {
|
||||
blocks.push(dividerBlock());
|
||||
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');
|
||||
const achLines = newAchievements
|
||||
.map((ach) => `✨ **${ach.name}** — ${ach.description}`)
|
||||
.join("\n");
|
||||
blocks.push(textBlock(`🏆 ¡Logro desbloqueado!\n${achLines}`));
|
||||
}
|
||||
|
||||
@@ -105,6 +171,5 @@ export const command: CommandMessage = {
|
||||
} catch (e: any) {
|
||||
await message.reply(`❌ No se pudo pelear: ${e?.message ?? e}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user