package net.uomc.mineshaft; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import com.mouldycheerio.dbot.commands.CommandDetails; import com.mouldycheerio.dbot.commands.cooldowns.CooldownCommand; import com.mouldycheerio.dbot.util.EventWaiter; import com.mouldycheerio.dbot.util.PeelingUtils; import com.vdurmont.emoji.EmojiParser; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.entities.emoji.UnicodeEmoji; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; import net.uomc.mineshaft.blacksmith.Sword; public class RobCommand extends CooldownCommand { private static final UnicodeEmoji FLEE_EMOJI = Emoji.fromUnicode(EmojiParser.parseToUnicode(":runner:")); private static final UnicodeEmoji FIGHT_EMOJI = Emoji.fromUnicode(EmojiParser.parseToUnicode(":crossed_swords:")); private static final long BASE_DAMAGE = 14; private static final long CONFIRM_WAIT_SECONDS = 10; private static final double FLEE_CHANCE = 0.3; private Mineshaft bot; private String pvpEmoji; protected RobCommand(Mineshaft bot) { super(bot); // TODO reset this setCooldown(60l * 15l * 1000l); //setCooldown(0l); this.bot = bot; setDetails(CommandDetails.from("kill,pvp,rob,fight,challenge", "kill another player")); pvpEmoji = EmojiParser.parseToUnicode(":crossed_swords:"); } @Override public boolean trigger(MessageReceivedEvent e) { String[] args = e.getMessage().getContentRaw().split(" "); if (args.length < 2) { e.getMessage().reply(":x: Please specify a target! `kill @user`").queue(); return false; } Optional mentionToMember = PeelingUtils.mentionToMember(args[1], e.getGuild()); if (!mentionToMember.isPresent()) { e.getMessage().reply(":x: Invalid Target! `kill @user`").queue(); return false; } Member target = mentionToMember.get(); if (target.equals(e.getMember())) { e.getMessage().reply(":x: You cannot fight yourself!").queue(); return false; } if (!canFight(e.getMember())) { e.getMessage().reply(":x: You need at least "+ Sword.swordToEmoji(1) + "to fight.\n💡 Use `m!blacksmith` to forge one").queue(); return false; } if (bot.getPlayerStats().isInBattle(e.getMember())) { e.getMessage().reply(":x: You are already fighting someone else!").queue(); return false; } if (bot.getPlayerStats().isInBattle(target)) { e.getMessage().reply(":x: " + target.getAsMention() + " is already fighting someone else!").queue(); return false; } if (bot.getPlayerStats().isNether(target) != bot.getPlayerStats().isNether(e.getMember())) { e.getMessage().reply( ":x: You tried to kill " + target.getAsMention() + " but they were in a different dimension!") .queue(); return false; } e.getMessage().addReaction(Emoji.fromUnicode(pvpEmoji)).queue(); bot.getPlayerStats().setInBattle(target, true); bot.getPlayerStats().setInBattle(e.getMember(), true); EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("pvp"); String startString = e.getAuthor().getAsMention() + " is fighting " + target.getAsMention() + "...\n\n"; eb.getDescriptionBuilder().append(startString); eb.appendDescription(target.getAsMention() + ": React with " + FLEE_EMOJI.getFormatted() + " to flee"); if (canFight(target)) { eb.appendDescription(" or " + FIGHT_EMOJI.getFormatted() + " to fight back!"); } eb.appendDescription("\n"); eb.appendDescription(":warning: This chance will expire " + PeelingUtils.formatTimeRelativeFromNow(CONFIRM_WAIT_SECONDS * 1000l) + "\n"); eb.setColor(bot.color); long damage = bot.getHealths().calculateDamage(target, e.getMember(), false, BASE_DAMAGE); e.getMessage().replyEmbeds(eb.build()).queue(message -> { message.addReaction(FLEE_EMOJI).queue(); if (canFight(target)) { message.addReaction(FIGHT_EMOJI).queue(); } message.addReaction(FLEE_EMOJI).queue((Void ignored) -> { EventWaiter eventWaiter = new EventWaiter(); e.getChannel().getJDA().addEventListener(eventWaiter); eventWaiter.waitForEvent(MessageReactionAddEvent.class, e1 -> e1.getMessageId().equals(message.getId()) && e1.getUser().getId().equals(target.getId()) && (FLEE_EMOJI.equals(e1.getReaction().getEmoji().asUnicode()) || FIGHT_EMOJI.equals(e1.getReaction().getEmoji().asUnicode())), e1 -> { message.clearReactions().queue(); eb.setDescription(startString); // target has a chance to evade the battle entirely if (FLEE_EMOJI.equals(e1.getReaction().getEmoji().asUnicode())) { if (Math.random() < FLEE_CHANCE) { eb.appendDescription(FLEE_EMOJI.getFormatted() + target.getAsMention() + " Managed to escape!\n"); message.editMessageEmbeds(eb.build()).queueAfter(1, TimeUnit.SECONDS, m -> { m.editMessageEmbeds(eb.build()).queue(); endFight(target, e.getMember()); }); return; } else { // fight happens anyway, if they can fight they will fight second eb.appendDescription( ":x:" + target.getAsMention() + " tried running away but failed!\n\n"); message.editMessageEmbeds(eb.build()).queueAfter(1, TimeUnit.SECONDS, m1 -> { fightBack(m1, e.getMember(), target, damage, eb); }); return; } } // target gets to fight first then attacker fights if (FIGHT_EMOJI.equals(e1.getReaction().getEmoji().asUnicode()) && canFight(target)) { eb.appendDescription(FIGHT_EMOJI.getFormatted() + target.getAsMention() + " Anticipated the attack and got the first strike\n"); message.editMessageEmbeds(eb.build()).queueAfter(1, TimeUnit.SECONDS, m1 -> { fightBack(m1, target, e.getMember(), damage, eb); }); return; } // attacker gets an attack and thats it addFightMessage(message, target, e.getMember(), eb, damage, null); }, CONFIRM_WAIT_SECONDS, TimeUnit.SECONDS, () -> { message.clearReactions().queue(); eb.setDescription(startString); message.editMessageEmbeds(eb.build()).queueAfter(1, TimeUnit.SECONDS, m -> { // attacker gets an attack (ambush) addFightMessage(m, target, e.getMember(), eb, damage, null); }); }); }); }); return true; } public void fightBack(Message message, Member target, Member agressor, long attackerDamage, EmbedBuilder eb) { long damage = bot.getHealths().calculateDamage(agressor, target, false, BASE_DAMAGE); addFightMessage(message, agressor, target, eb, damage, m -> { addFightMessage(message, target, agressor, eb, attackerDamage, null); }); } public void addFightMessage(Message message, Member target, Member attacker, EmbedBuilder eb, long damage, Consumer callback) { String damageString = " (" + PlayerHealths.getHPString(-damage) + ")"; String swordEmoji = bot.getSword(attacker).getEmoji(); String deathMessage = swordEmoji + target.getAsMention() + " was slain by " + attacker.getAsMention() + damageString; long hp = bot.getHealths().damage(message, target, damage, deathMessage); if (hp <= 0) { endFight(target, attacker); return; } eb.appendDescription( swordEmoji + attacker.getAsMention() + " attacked " + target.getAsMention() + damageString + "\n"); if (callback != null) { message.editMessageEmbeds(eb.build()).queue(callback); } else { eb.appendDescription("\n" + target.getAsMention() + " is now on " + bot.getHealths().getHPString(target)); message.editMessageEmbeds(eb.build()).queue(); endFight(target, attacker); } return; } private void endFight(Member target, Member attacker) { bot.getPlayerStats().setInBattle(target, false); bot.getPlayerStats().setInBattle(attacker, false); } public boolean canFight(Member member) { return bot.getSword(member).getLevel() != 0; } }