2023-11-21 20:17:15 +01:00
import { GuildMember , CommandInteraction , SlashCommandBuilder } from 'discord.js' ;
2023-11-22 20:02:00 +01:00
import { getItem , getItemQuantity , formatItems , formatItem , weaponInventoryAutocomplete } from '../lib/rpg/items' ;
2023-11-21 20:17:15 +01:00
import { Command } from '../types/index' ;
2023-11-21 21:28:32 +01:00
import { initHealth , dealDamage , BLOOD_ITEM , BLOOD_ID , resetInvincible , INVINCIBLE_TIMER , getInvincibleMs } from '../lib/rpg/pvp' ;
2023-11-25 17:21:19 +01:00
import { getBehavior , getBehaviors } from '../lib/rpg/behaviors' ;
import { Right } from '../lib/util' ;
2023-11-21 20:17:15 +01:00
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 ) ) ;
2023-11-25 17:21:19 +01:00
const target = interaction . options . getUser ( 'user' , true ) ;
2023-11-21 20:17:15 +01:00
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!' ) ;
2023-11-22 13:05:18 +01:00
const inv = await getItemQuantity ( member . id , weapon . id ) ;
if ( inv . quantity === 0 ) return interaction . followUp ( 'You do not have this weapon!' ) ;
2023-11-25 17:21:19 +01:00
const invinTimer = await getInvincibleMs ( target . id ) ;
2023-11-21 21:28:32 +01:00
if ( invinTimer > 0 ) return interaction . followUp ( ` You can only attack this user <t: ${ Math . floor ( ( Date . now ( ) + invinTimer ) / 1000 ) } :R> (or if they perform an action first)! ` ) ;
2023-11-21 20:17:15 +01:00
2023-11-25 17:21:19 +01:00
let dmg = weapon . maxStack ;
const messages = [ ] ;
2023-11-21 20:17:15 +01:00
2023-11-25 17:21:19 +01:00
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 <t: ${ Math . floor ( ( Date . now ( ) + INVINCIBLE_TIMER ) / 1000 ) } :R> (or if they perform an action first). ` ) ;
2023-11-21 20:17:15 +01:00
} ,
2023-11-22 20:02:00 +01:00
autocomplete : weaponInventoryAutocomplete ,
2023-11-21 20:17:15 +01:00
} satisfies Command ;