import { GuildMember, CommandInteraction, SlashCommandBuilder } from 'discord.js'; import { getItem, getItemQuantity, formatItems, formatItem, weaponInventoryAutocomplete } from '../lib/rpg/items'; import { Command } from '../types/index'; import { initHealth, dealDamage, BLOOD_ITEM, BLOOD_ID, resetInvincible, INVINCIBLE_TIMER, getInvincibleMs } from '../lib/rpg/pvp'; import { getBehavior, getBehaviors } from '../lib/rpg/behaviors'; import { Right } from '../lib/util'; export default { data: new SlashCommandBuilder() .setName('attack') .setDescription('Attack someone using a weapon you have') .addStringOption(option => option .setName('weapon') .setAutocomplete(true) .setDescription('The weapon to use') .setRequired(true) ) .addUserOption(option => option .setName('user') .setRequired(true) .setDescription('Who to attack with the weapon') ) .setDMPermission(false), execute: async (interaction: CommandInteraction) => { if (!interaction.isChatInputCommand()) return; const member = interaction.member! as GuildMember; await initHealth(member.id); const weaponID = parseInt(interaction.options.getString('weapon', true)); const target = interaction.options.getUser('user', true); await interaction.deferReply({ephemeral: true}); const weapon = await getItem(weaponID); if (!weapon) return interaction.followUp('No such item exists!'); if (weapon.type !== 'weapon') return interaction.followUp('That is not a weapon!'); const inv = await getItemQuantity(member.id, weapon.id); if (inv.quantity === 0) return interaction.followUp('You do not have this weapon!'); const invinTimer = await getInvincibleMs(target.id); if (invinTimer > 0) return interaction.followUp(`You can only attack this user (or if they perform an action first)!`); let dmg = weapon.maxStack; const messages = []; const behaviors = await getBehaviors(weapon); for (const itemBehavior of behaviors) { const behavior = getBehavior(itemBehavior.behavior); if (!behavior) continue; if (!behavior.onAttack) continue; const res = await behavior.onAttack({ value: itemBehavior.value, damage: dmg, item: weapon, user: member.id, target: target.id, }); if (res instanceof Right) { await interaction.followUp(`You tried to attack with ${formatItem(weapon)}... but failed!\n${res.getValue()}`); return; } else { const { message, damage } = res.getValue(); if (message) messages.push(message); if (damage) dmg = damage; } } await dealDamage(target.id, dmg); const newHealth = await getItemQuantity(target.id, BLOOD_ID); if (target.id !== member.id) await resetInvincible(member.id); await interaction.followUp(`You hit ${target} with ${formatItem(weapon)} for ${BLOOD_ITEM.emoji} **${dmg}** damage!\n${messages.map(m => `_${m}_\n`).join('')}They are now at ${formatItems(BLOOD_ITEM, newHealth.quantity)}.\nYou can attack them again (or if they perform an action first).`); }, autocomplete: weaponInventoryAutocomplete, } satisfies Command;