package org.royaldev.thehumanity.commands.impl; import org.jetbrains.annotations.NotNull; import org.kitteh.irc.client.library.element.Channel; import org.kitteh.irc.client.library.element.User; import org.kitteh.irc.client.library.event.channel.ChannelMessageEvent; import org.kitteh.irc.client.library.event.helper.ActorEvent; import org.kitteh.irc.client.library.util.Format; import org.royaldev.thehumanity.TheHumanity; import org.royaldev.thehumanity.cards.play.Play; import org.royaldev.thehumanity.cards.types.WhiteCard; import org.royaldev.thehumanity.game.HouseRule; import org.royaldev.thehumanity.game.TheHumanityGame; import org.royaldev.thehumanity.game.TheHumanityGame.GameStatus; import org.royaldev.thehumanity.game.round.CAHRound; import org.royaldev.thehumanity.game.round.CAHRound.RoundState; import org.royaldev.thehumanity.game.round.CurrentRound; import org.royaldev.thehumanity.player.TheHumanityPlayer; import xyz.cardstock.cardstock.commands.BaseCommand; import xyz.cardstock.cardstock.commands.CallInfo; import xyz.cardstock.cardstock.commands.Command; import xyz.cardstock.cardstock.players.hands.Hand; import java.util.ArrayList; import java.util.List; import java.util.Optional; @Command( name = "pick", description = "Chooses a card.", aliases = {"pickcard", "p", "pc", "play", "playcard"}, usage = "<command> [number]" ) public class PickCardCommand extends BaseCommand { private final TheHumanity humanity; public PickCardCommand(final TheHumanity instance) { this.humanity = instance; } /** * Processes any use of this command during the WAITING_FOR_CZAR stage. * * @param g TheHumanityGame the command was used in * @param u User using command * @param p Player representative of the User * @param args Arguments supplied */ private void czarPick(final TheHumanityGame g, final User u, final TheHumanityPlayer p, final List<String> args) { final CurrentRound r = g.getCurrentRound(); if (r == null) { u.sendNotice("No round to play in."); return; } if (g.hasHouseRule(HouseRule.GOD_IS_DEAD)) { this.vote(g, u, p, args); return; } if (!this.isCzar(r, p)) { u.sendNotice("You can't pick any cards right now."); return; } final int winningPlay; try { winningPlay = Integer.parseInt(args.get(0)); } catch (NumberFormatException ex) { u.sendNotice(args.get(0) + " is not a valid number."); return; } final int index = winningPlay - 1; u.sendNotice((index < 0 || index >= r.getPlays().size()) ? "Invalid play." : "Play picked!"); r.chooseWinningPlay(winningPlay); } /** * Checks if the given Player is the czar of the given CAHRound. * * @param r CAHRound to check * @param p Player to check * @return true if Player is czar of the CAHRound, false if otherwise */ private boolean isCzar(final CAHRound r, final TheHumanityPlayer p) { return p.equals(r.getCzar()); } /** * Processes any use of this command during the WAITING_FOR_PLAYERS stage. * * @param g TheHumanityGame the command was used in * @param u User using command * @param p Player representative of the User * @param args Arguments supplied */ private void playerPick(final TheHumanityGame g, final User u, final TheHumanityPlayer p, final List<String> args) { final CurrentRound r = g.getCurrentRound(); if (r == null) { u.sendNotice("No round to play in."); return; } if (!g.hasHouseRule(HouseRule.GOD_IS_DEAD) && this.isCzar(r, p)) { u.sendNotice("You're the card czar! Wait until all the players have chosen their cards."); return; } if (r.hasPlayed(p)) { u.sendNotice("You've already played!"); return; } if (args.size() != r.getBlackCard().getBlanks()) { u.sendNotice(Format.BOLD + "Wrong amount of cards!" + Format.RESET + " You need to pick exactly " + r.getBlackCard().getBlanks() + " cards."); return; } final Hand<WhiteCard> hand = p.getHand(); final List<WhiteCard> play = this.processPicks(u, hand, args); if (play == null) return; u.sendNotice("Card" + (play.size() == 1 ? "" : "s") + " picked."); r.addPlay(new Play(p, play)); } /** * Returns a list of WhiteCards from the given Hand, given their numbers as Strings. * * @param u User who used command * @param hand Hand to use cards from * @param picks Supplied numbers * @return List of WhiteCards or null if there was an issue */ private List<WhiteCard> processPicks(final User u, final Hand<WhiteCard> hand, final List<String> picks) { final List<WhiteCard> play = new ArrayList<>(); for (final String number : picks) { int card; try { card = Integer.parseInt(number); } catch (NumberFormatException ex) { u.sendNotice(number + " is not a valid number."); return null; } card--; if (card < 0 || card >= hand.size()) { u.sendNotice((card + 1) + " is not a valid choice."); return null; } final WhiteCard toPlay = hand.get(card); if (play.contains(toPlay)) { u.sendNotice("You cannot play the same card twice!"); return null; } play.add(toPlay); } return play; } private void vote(final TheHumanityGame g, final User u, final TheHumanityPlayer p, final List<String> args) { final CurrentRound r = g.getCurrentRound(); if (r == null) { u.sendNotice("No round to vote in."); return; } final int winningPlay; try { winningPlay = Integer.parseInt(args.get(0)); } catch (NumberFormatException ex) { u.sendNotice(args.get(0) + " is not a valid number."); return; } final int index = winningPlay - 1; if (index < 0 || index >= r.getPlays().size()) { u.sendNotice("Invalid play."); return; } u.sendNotice(r.hasVoted(p) ? "You have already voted!" : "Vote cast!"); r.addVote(p, winningPlay); } @Override public void run(@NotNull ActorEvent<User> event, @NotNull CallInfo callInfo, @NotNull List<String> arguments) { final User u = event.getActor(); final Channel channel; if (callInfo.getUsageType() == CallInfo.UsageType.PRIVATE) { if (arguments.size() < 2) { u.sendMessage("Please use the syntax `!pick [channel] [numbers]` when picking from private message."); return; } final String channelName = arguments.get(0); arguments = arguments.subList(1, arguments.size()); final Optional<Channel> optionalChannel = u.getClient().getChannel(channelName); if (!optionalChannel.isPresent()) { u.sendMessage(String.format("Could not get channel %s.", channelName)); return; } channel = optionalChannel.get(); } else { if (!(event instanceof ChannelMessageEvent)) { u.sendNotice("Command used in a channel, but event isn't a ChannelMessageEvent. This is a bug."); return; } channel = ((ChannelMessageEvent) event).getChannel(); } final TheHumanityGame game = this.humanity.getGameRegistrar().find(channel); if (game == null) { u.sendNotice(String.format("Could not get game in channel %s.", channel.getName())); return; } final TheHumanityPlayer player = game.getPlayer(u); if (player == null) { u.sendNotice(String.format("You are not in the game in channel %s.", channel.getName())); return; } if (arguments.size() < 1) { u.sendNotice("Usage: " + this.getUsage().replace("<command>", callInfo.getLabel())); return; } if (!game.getState().getUniqueName().equals(GameStatus.PLAYING.name())) { u.sendNotice("The game has not started!"); return; } final CurrentRound r = game.getCurrentRound(); if (r == null) { u.sendNotice("No round to play in."); return; } if (r.getState().getUniqueName().equals(RoundState.WAITING_FOR_CZAR.name())) { this.czarPick(game, u, player, arguments); } else if (r.getState().getUniqueName().equals(RoundState.WAITING_FOR_PLAYERS.name())) { this.playerPick(game, u, player, arguments); } else { u.sendNotice("You cannot pick a card right now."); } } }