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.");
}
}
}