diff --git a/src/main/java/forge/card/ability/effects/ChooseNumberEffect.java b/src/main/java/forge/card/ability/effects/ChooseNumberEffect.java index 19a866feb35..384b470a9aa 100644 --- a/src/main/java/forge/card/ability/effects/ChooseNumberEffect.java +++ b/src/main/java/forge/card/ability/effects/ChooseNumberEffect.java @@ -11,7 +11,6 @@ import forge.card.cardfactory.CardFactoryUtil; import forge.card.spellability.SpellAbility; import forge.card.spellability.TargetRestrictions; import forge.game.player.Player; -import forge.gui.GuiDialog; public class ChooseNumberEffect extends SpellAbilityEffect { @@ -51,11 +50,11 @@ public class ChooseNumberEffect extends SpellAbilityEffect { if (random) { final Random randomGen = new Random(); chosen = randomGen.nextInt(max - min) + min; - final String message = "Randomly chosen number: " + chosen; - GuiDialog.message(message, card.toString()); + p.getGame().getAction().nofityOfValue(sa, p, Integer.toString(chosen), null); } else { String title = sa.hasParam("ListTitle") ? sa.getParam("ListTitle") : "Choose a number"; chosen = p.getController().chooseNumber(sa, title, min, max); + // don't notify here, because most scripts I've seen don't store that number in a long term } card.setChosenNumber(chosen); } diff --git a/src/main/java/forge/card/ability/effects/FlipCoinEffect.java b/src/main/java/forge/card/ability/effects/FlipCoinEffect.java index d7264b14d5c..997baa8e9c4 100644 --- a/src/main/java/forge/card/ability/effects/FlipCoinEffect.java +++ b/src/main/java/forge/card/ability/effects/FlipCoinEffect.java @@ -11,8 +11,6 @@ import forge.card.spellability.SpellAbility; import forge.card.trigger.TriggerType; import forge.game.event.GameEventFlipCoin; import forge.game.player.Player; -import forge.gui.GuiChoose; -import forge.gui.GuiDialog; import forge.util.MyRandom; public class FlipCoinEffect extends SpellAbilityEffect { @@ -54,7 +52,7 @@ public class FlipCoinEffect extends SpellAbilityEffect { boolean victory = false; if (!noCall) { flipMultiplier = getFilpMultiplier(caller.get(0)); - victory = flipCoinCall(caller.get(0), host, flipMultiplier); + victory = flipCoinCall(caller.get(0), sa, flipMultiplier); } // Run triggers @@ -68,7 +66,7 @@ public class FlipCoinEffect extends SpellAbilityEffect { for (final Player flipper : playersToFlip) { if (noCall) { flipMultiplier = getFilpMultiplier(flipper); - final boolean resultIsHeads = FlipCoinEffect.flipCoinNoCall(sa.getSourceCard(), flipper, flipMultiplier); + final boolean resultIsHeads = flipCoinNoCall(sa, flipper, flipMultiplier); if (rememberResult) { host.addFlipResult(flipper, resultIsHeads ? "Heads" : "Tails"); } @@ -132,25 +130,17 @@ public class FlipCoinEffect extends SpellAbilityEffect { * @param multiplier * @return a boolean. */ - public static boolean flipCoinNoCall(final Card source, final Player flipper, final int multiplier) { - String[] results = new String[multiplier]; - String result; + public boolean flipCoinNoCall(final SpellAbility sa, final Player flipper, final int multiplier) { + boolean[] results = new boolean[multiplier]; for (int i = 0; i < multiplier; i++) { final boolean resultIsHeads = MyRandom.getRandom().nextBoolean(); flipper.getGame().fireEvent(new GameEventFlipCoin()); - results[i] = resultIsHeads ? " heads." : " tails."; + results[i] = resultIsHeads; } - if (multiplier == 1) { - result = results[0]; - } else { - result = flipper.getController().chooseFilpResult(source, flipper, results, false); - } - final StringBuilder sb = new StringBuilder(); - sb.append(flipper.getName()); - sb.append("'s flip comes up"); - sb.append(result); - GuiDialog.message(sb.toString(), source + " Flip result:"); - return result.equals(" heads."); + boolean result = multiplier == 1 ? results[0] : flipper.getController().chooseFilpResult(sa, flipper, results, false); + + flipper.getGame().getAction().nofityOfValue(sa, flipper, result ? "heads" : "tails", null); + return result; } /** @@ -165,36 +155,22 @@ public class FlipCoinEffect extends SpellAbilityEffect { * @param multiplier * @return a boolean. */ - public static boolean flipCoinCall(final Player caller, final Card source, final int multiplier) { - String choice; - final String[] choices = { "heads", "tails" }; - String[] results = new String[multiplier]; + public boolean flipCoinCall(final Player caller, final SpellAbility sa, final int multiplier) { + boolean [] results = new boolean [multiplier]; for (int i = 0; i < multiplier; i++) { + final boolean choice = caller.getController().chooseBinary(sa, sa.getSourceCard().getName() + " - Call coin flip", true); // Play the Flip A Coin sound caller.getGame().fireEvent(new GameEventFlipCoin()); final boolean flip = MyRandom.getRandom().nextBoolean(); - if (caller.isHuman()) { - choice = GuiChoose.one(source.getName() + " - Call coin flip", choices); - } else { - choice = choices[MyRandom.getRandom().nextInt(2)]; - } - final boolean winFlip = flip == choice.equals(choices[0]); - final String winMsg = winFlip ? " wins flip." : " loses flip."; - results[i] = winMsg; - } - String result; - if (multiplier == 1) { - result = results[0]; - } else { - result = caller.getController().chooseFilpResult(source, caller, results, true); + results[i] = flip == choice; } + boolean result = multiplier == 1 ? results[0] : caller.getController().chooseFilpResult(sa, caller, results, true); - GuiDialog.message(source.getName() + " - " + caller + result, source.getName()); - - return result.equals(" wins flip."); + caller.getGame().getAction().nofityOfValue(sa, caller, result ? "win" : "lose", null); + return result; } - public static int getFilpMultiplier(final Player flipper) { + public int getFilpMultiplier(final Player flipper) { int i = 0; for (String kw : flipper.getKeywords()) { if (kw.startsWith("If you would flip a coin")) { diff --git a/src/main/java/forge/game/Game.java b/src/main/java/forge/game/Game.java index 875675ffc56..b46e9146226 100644 --- a/src/main/java/forge/game/Game.java +++ b/src/main/java/forge/game/Game.java @@ -106,8 +106,6 @@ public class Game { pl.setTeam(psc.getTeamNumber()); } - - action = new GameAction(this); stack = new MagicStack(this); phaseHandler = new PhaseHandler(this); diff --git a/src/main/java/forge/game/GameAction.java b/src/main/java/forge/game/GameAction.java index 05280ea25b3..0570ab70446 100644 --- a/src/main/java/forge/game/GameAction.java +++ b/src/main/java/forge/game/GameAction.java @@ -40,6 +40,7 @@ import forge.CounterType; import forge.FThreads; import forge.GameEntity; import forge.GameLogEntryType; +import forge.ITargetable; import forge.card.CardType; import forge.card.TriggerReplacementBase; import forge.card.ability.AbilityFactory; @@ -1423,6 +1424,15 @@ public class GameAction { } } + /** Delivers a message to all players. (use reveal to show Cards) */ + public void nofityOfValue(SpellAbility saSource, ITargetable relatedTarget, String value, Player playerExcept) { + for(Player p : game.getPlayers()) { + if (playerExcept == p) continue; + p.getController().notifyOfValue(saSource, relatedTarget, value); + } + + } + public void startGame() { Player first = determineFirstTurnPlayer(game.getMatch().getLastGameOutcome()); diff --git a/src/main/java/forge/game/player/PlayerController.java b/src/main/java/forge/game/player/PlayerController.java index ccd85789686..24a18872a81 100644 --- a/src/main/java/forge/game/player/PlayerController.java +++ b/src/main/java/forge/game/player/PlayerController.java @@ -124,6 +124,8 @@ public abstract class PlayerController { /** Shows the card to this player*/ public abstract void reveal(String string, Collection cards, ZoneType zone, Player owner); + /** Shows message to player to reveal chosen cardName, creatureType, number etc. AI must analyze API to understand what that is */ + public abstract void notifyOfValue(SpellAbility saSource, ITargetable realtedTarget, String value); public abstract ImmutablePair, List> arrangeForScry(List topN); public abstract boolean willPutCardOnTop(Card c); public abstract List orderMoveToZoneList(List cards, ZoneType destinationZone); @@ -153,6 +155,10 @@ public abstract class PlayerController { public abstract int chooseNumber(SpellAbility sa, String title, int min, int max); - public abstract String chooseFilpResult(Card source, Player flipper, String[] results, boolean call); + public abstract boolean chooseBinary(SpellAbility sa, String question, boolean isCoin); + public abstract boolean chooseFilpResult(SpellAbility sa, Player flipper, boolean[] results, boolean call); + + + } diff --git a/src/main/java/forge/game/player/PlayerControllerAi.java b/src/main/java/forge/game/player/PlayerControllerAi.java index a498a2d9032..109198b38cc 100644 --- a/src/main/java/forge/game/player/PlayerControllerAi.java +++ b/src/main/java/forge/game/player/PlayerControllerAi.java @@ -377,19 +377,19 @@ public class PlayerControllerAi extends PlayerController { * @see forge.game.player.PlayerController#chooseFilpResult(forge.Card, forge.game.player.Player, java.lang.String[], boolean) */ @Override - public String chooseFilpResult(Card source, Player flipper, String[] results, boolean call) { + public boolean chooseFilpResult(SpellAbility sa, Player flipper, boolean[] results, boolean call) { if (call) { - // Win if possible - String result = " loses flip."; - for (String s : results) { - if (s.equals(" wins flip.")) { + // Win if possible + boolean result = false; + for (boolean s : results) { + if (s) { result = s; break; } } return result; } else { - // heads or tails, AI doesn't know which is better now + // heads or tails, AI doesn't know which is better now int i = MyRandom.getRandom().nextInt(results.length); return results[i]; } @@ -400,4 +400,15 @@ public class PlayerControllerAi extends PlayerController { // TODO Teach AI how to use Spellskite return allTargets.get(0); } + + + @Override + public void notifyOfValue(SpellAbility saSource, ITargetable realtedTarget, String value) { + // AI should take into consideration creature types, numbers and other information (mostly choices) arriving through this channel + } + + @Override + public boolean chooseBinary(SpellAbility sa, String question, boolean isCoin) { + return MyRandom.getRandom().nextBoolean(); + } } diff --git a/src/main/java/forge/game/player/PlayerControllerHuman.java b/src/main/java/forge/game/player/PlayerControllerHuman.java index ca1c20ccd80..9eb977c6320 100644 --- a/src/main/java/forge/game/player/PlayerControllerHuman.java +++ b/src/main/java/forge/game/player/PlayerControllerHuman.java @@ -49,6 +49,7 @@ import forge.gui.input.InputSelectCardsFromList; import forge.gui.match.CMatchUI; import forge.item.PaperCard; import forge.properties.ForgePreferences.FPref; +import forge.util.Lang; import forge.util.TextUtil; @@ -621,13 +622,23 @@ public class PlayerControllerHuman extends PlayerController { return result; } - + // end of not related candidates for move. + + /* (non-Javadoc) - * @see forge.game.player.PlayerController#chooseFilpResult(forge.game.player.Player, java.lang.String[], boolean) + * @see forge.game.player.PlayerController#chooseBinary(java.lang.String, boolean) */ @Override - public String chooseFilpResult(Card source, Player flipper, String[] results, boolean call) { - return GuiChoose.one(source.getName() + " - Choose a result", results); + public boolean chooseBinary(SpellAbility sa, String question, boolean isCoin) { + String[] labels = isCoin ? new String[]{"Heads", "Tails"} : new String[]{"Odds", "Evens"}; + return GuiDialog.confirm(sa.getSourceCard(), question, labels); + } + + + @Override + public boolean chooseFilpResult(SpellAbility sa, Player flipper, boolean[] results, boolean call) { + String[] labels = call ? new String[]{"heads", "tails"} : new String[]{"win the flip", "lose the flip"}; + return GuiChoose.one(sa.getSourceCard().getName() + " - Choose a result", labels) == labels[0]; } @@ -646,4 +657,32 @@ public class PlayerControllerHuman extends PlayerController { List> chosen = GuiChoose.getChoices(saSpellskite.getSourceCard().getName(), 1, 1, allTargets, null, fnToString); return Iterables.getFirst(chosen, null); } + + @Override + public void notifyOfValue(SpellAbility sa, ITargetable realtedTarget, String value) { + String message = formatNotificationMessage(sa, realtedTarget, value); + GuiDialog.message(message, sa.getSourceCard().getName()); + } + + + // These are not much related to PlayerController + private String formatNotificationMessage(SpellAbility sa, ITargetable target, String value) { + switch(sa.getApi()) { + case ChooseNumber: + final boolean random = sa.hasParam("Random"); + return String.format(random ? "Randomly chosen number for %s is %s" : "%s choses number: %s", mayBeYou(target, player), value); + case FlipACoin: + String flipper = StringUtils.capitalize(mayBeYou(target, player)); + return sa.hasParam("NoCall") + ? String.format("%s flip comes up %s", Lang.getPossesive(flipper), value) + : String.format("%s %s the flip", flipper, Lang.joinVerb(flipper, value)); + default: + return String.format("%s effect's value for %s is %s", sa.getSourceCard().getName(), mayBeYou(target, player), value); + } + } + + private String mayBeYou(ITargetable what, Player you) { + return what == you ? "you" : what.toString(); + } + // end of not related candidates for move. } diff --git a/src/main/java/forge/util/Lang.java b/src/main/java/forge/util/Lang.java index 291fa9b78d7..2a8c4fd2a2f 100644 --- a/src/main/java/forge/util/Lang.java +++ b/src/main/java/forge/util/Lang.java @@ -6,6 +6,7 @@ import java.util.List; import org.apache.commons.lang3.StringUtils; import com.google.common.base.Function; +import com.google.common.collect.Iterables; /** * TODO: Write javadoc for this type. @@ -57,8 +58,21 @@ public class Lang { public static String joinVerb(List subjects, String verb) { + return subjects.size() > 1 || !subjectIsSingle3rdPerson(Iterables.getFirst(subjects, "it").toString()) ? verb : verbs3rdPersonSingular(verb); + } + + public static String joinVerb(String subject, String verb) { + return !Lang.subjectIsSingle3rdPerson(subject) ? verb : verbs3rdPersonSingular(verb); + } + + public static boolean subjectIsSingle3rdPerson(String subject) { + // Will be most simple + return !"You".equalsIgnoreCase(subject); + } + + public static String verbs3rdPersonSingular(String verb) { // English is simple - just add (s) for multiple objects. - return subjects.size() > 1 ? verb : verb + "s"; + return verb + "s"; } public static String getPlural(String noun) { @@ -79,12 +93,9 @@ public class Lang { String countedForm = cnt <= 1 ? noun : getPlural(noun); return getNumeral(cnt) + " " + countedForm; } - /** - * TODO: Write javadoc for this method. - * @param name - * @return - */ + public static String getPossesive(String name) { + if ("You".equalsIgnoreCase(name)) return name + "r"; // to get "your" return name.endsWith("s") ? name + "'" : name + "'s"; }