diff --git a/.gitattributes b/.gitattributes index 85b76be240e..eb340a4617f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15072,16 +15072,13 @@ forge-gui/src/main/java/forge/game/phase/Untap.java -text forge-gui/src/main/java/forge/game/phase/Upkeep.java svneol=native#text/plain forge-gui/src/main/java/forge/game/phase/package-info.java svneol=native#text/plain forge-gui/src/main/java/forge/game/player/GameLossReason.java -text -forge-gui/src/main/java/forge/game/player/HumanPlay.java -text forge-gui/src/main/java/forge/game/player/LobbyPlayer.java -text forge-gui/src/main/java/forge/game/player/LobbyPlayerAi.java -text -forge-gui/src/main/java/forge/game/player/LobbyPlayerHuman.java -text forge-gui/src/main/java/forge/game/player/LobbyPlayerRemote.java -text forge-gui/src/main/java/forge/game/player/Player.java svneol=native#text/plain forge-gui/src/main/java/forge/game/player/PlayerActionConfirmMode.java -text forge-gui/src/main/java/forge/game/player/PlayerController.java -text forge-gui/src/main/java/forge/game/player/PlayerControllerAi.java -text -forge-gui/src/main/java/forge/game/player/PlayerControllerHuman.java -text forge-gui/src/main/java/forge/game/player/PlayerOutcome.java -text forge-gui/src/main/java/forge/game/player/PlayerStatistics.java -text forge-gui/src/main/java/forge/game/player/PlayerType.java svneol=native#text/plain @@ -15421,6 +15418,10 @@ forge-gui/src/main/java/forge/gui/menus/IMenuProvider.java -text forge-gui/src/main/java/forge/gui/menus/LayoutMenu.java -text forge-gui/src/main/java/forge/gui/menus/MenuUtil.java -text forge-gui/src/main/java/forge/gui/package-info.java svneol=native#text/plain +forge-gui/src/main/java/forge/gui/player/HumanPlay.java -text +forge-gui/src/main/java/forge/gui/player/LobbyPlayerHuman.java -text +forge-gui/src/main/java/forge/gui/player/PlayerControllerHuman.java -text +forge-gui/src/main/java/forge/gui/player/package-info.java -text forge-gui/src/main/java/forge/gui/toolbox/CardFaceSymbols.java svneol=native#text/plain forge-gui/src/main/java/forge/gui/toolbox/FAbsolutePositioner.java -text forge-gui/src/main/java/forge/gui/toolbox/FButton.java -text diff --git a/forge-gui/src/main/java/forge/control/FControl.java b/forge-gui/src/main/java/forge/control/FControl.java index 27eaef157da..398c6036dba 100644 --- a/forge-gui/src/main/java/forge/control/FControl.java +++ b/forge-gui/src/main/java/forge/control/FControl.java @@ -46,7 +46,7 @@ import forge.game.Match; import forge.game.card.Card; import forge.game.player.LobbyPlayer; import forge.game.player.LobbyPlayerAi; -import forge.game.player.LobbyPlayerHuman; +import forge.gui.player.LobbyPlayerHuman; import forge.game.player.Player; import forge.game.player.RegisteredPlayer; import forge.gui.GuiDialog; diff --git a/forge-gui/src/main/java/forge/game/ability/AbilityUtils.java b/forge-gui/src/main/java/forge/game/ability/AbilityUtils.java index 09d67bfaecc..cf1230b55b8 100644 --- a/forge-gui/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-gui/src/main/java/forge/game/ability/AbilityUtils.java @@ -3,8 +3,6 @@ package forge.game.ability; import java.util.ArrayList; import java.util.List; -import forge.ai.ComputerUtil; -import forge.ai.ComputerUtilCost; import forge.card.MagicColor; import forge.card.mana.ManaCostShard; @@ -21,10 +19,7 @@ import forge.game.card.CardUtil; import forge.game.card.CounterType; import forge.game.cost.Cost; import forge.game.mana.ManaCostBeingPaid; -import forge.game.player.HumanPlay; import forge.game.player.Player; -import forge.game.spellability.Ability; -import forge.game.spellability.AbilityStatic; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; @@ -1198,7 +1193,7 @@ public class AbilityUtils { // The player who has the chance to cancel the ability final String pays = sa.hasParam("UnlessPayer") ? sa.getParam("UnlessPayer") : "TargetedController"; - final List payers = getDefinedPlayers(sa.getSourceCard(), pays, sa); + final List allPayers = getDefinedPlayers(sa.getSourceCard(), pays, sa); final String resolveSubs = sa.getParam("UnlessResolveSubs"); // no value means 'Always' final boolean execSubsWhenPaid = "WhenPaid".equals(resolveSubs) || StringUtils.isBlank(resolveSubs); final boolean execSubsWhenNotPaid = "WhenNotPaid".equals(resolveSubs) || StringUtils.isBlank(resolveSubs); @@ -1233,27 +1228,16 @@ public class AbilityUtils { cost = new Cost(unlessCost, true); } - boolean paid = false; - for (Player payer : payers) { - final Ability ability = new AbilityStatic(source, cost, sa.getTargetRestrictions()) { @Override public void resolve() { } }; - ability.setActivatingPlayer(payer); - if (payer.isComputer()) { - if (ComputerUtilCost.willPayUnlessCost(sa, payer, cost, paid, payers) && ComputerUtilCost.canPayCost(ability, payer)) { - ComputerUtil.playNoStack(payer, ability, game); // Unless cost was payed - no resolve - paid = true; - } - } - else { - // if it's paid by the AI already the human can pay, but it won't change anything - paid |= HumanPlay.payCostDuringAbilityResolve(payer, source, cost, sa, null); - } + boolean alreadyPaid = false; + for (Player payer : allPayers) { + alreadyPaid |= payer.getController().payCostToPreventEffect(cost, sa, alreadyPaid, allPayers); } - if (paid == isSwitched) { + if (alreadyPaid == isSwitched) { sa.resolve(); } - if (paid && execSubsWhenPaid || !paid && execSubsWhenNotPaid) { // switched refers only to main ability! + if (alreadyPaid && execSubsWhenPaid || !alreadyPaid && execSubsWhenNotPaid) { // switched refers only to main ability! resolveSubAbilities(sa, game); } } diff --git a/forge-gui/src/main/java/forge/game/ability/effects/PlayEffect.java b/forge-gui/src/main/java/forge/game/ability/effects/PlayEffect.java index a8fafddb530..5601c27aaaf 100644 --- a/forge-gui/src/main/java/forge/game/ability/effects/PlayEffect.java +++ b/forge-gui/src/main/java/forge/game/ability/effects/PlayEffect.java @@ -11,7 +11,6 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import forge.Singletons; -import forge.ai.ComputerUtil; import forge.card.CardCharacteristicName; import forge.card.CardRulesPredicates; import forge.game.Game; @@ -19,7 +18,6 @@ import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.cost.Cost; -import forge.game.player.HumanPlay; import forge.game.player.Player; import forge.game.spellability.Spell; import forge.game.spellability.SpellAbility; @@ -217,22 +215,9 @@ public class PlayEffect extends SpellAbilityEffect { if (tgtSA.usesTargeting() && !optional) { tgtSA.getTargetRestrictions().setMandatory(true); } - - if (controller.isHuman()) { - HumanPlay.playSpellAbility(activator, tgtSA); - } else { - if (tgtSA instanceof Spell) { // Isn't it ALWAYS a spell? - Spell spell = (Spell) tgtSA; - if (spell.canPlayFromEffectAI(controller, !optional, noManaCost) || !optional) { - if (noManaCost) { - ComputerUtil.playSpellAbilityWithoutPayingManaCost(controller, tgtSA, game); - } else { - ComputerUtil.playStack(tgtSA, controller, game); - } - } else - remember = false; // didn't play spell - } - } + + + remember = controller.getController().playSaFromPlayEffect(tgtSA); if (remember) { source.addRemembered(tgtSA.getSourceCard()); } diff --git a/forge-gui/src/main/java/forge/game/player/PlayerController.java b/forge-gui/src/main/java/forge/game/player/PlayerController.java index 5a78f78efdc..b03d98bafdd 100644 --- a/forge-gui/src/main/java/forge/game/player/PlayerController.java +++ b/forge-gui/src/main/java/forge/game/player/PlayerController.java @@ -30,6 +30,7 @@ import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.TargetChoices; import forge.game.trigger.Trigger; +import forge.game.trigger.WrappedAbility; import forge.game.zone.ZoneType; import forge.item.PaperCard; @@ -197,4 +198,11 @@ public abstract class PlayerController { public abstract boolean confirmPayment(CostPart costPart, String string); public abstract ReplacementEffect chooseSingleReplacementEffect(String prompt, List possibleReplacers, HashMap runParams); public abstract String chooseProtectionType(String string, SpellAbility sa, List choices); + + // these 4 need some refining. + public abstract boolean payCostToPreventEffect(Cost cost, SpellAbility sa, boolean alreadyPaid, List allPayers); + public abstract void orderAndPlaySimultaneousSa(List activePlayerSAs); + public abstract void playTrigger(Card host, WrappedAbility wrapperAbility, boolean isMandatory); + + public abstract boolean playSaFromPlayEffect(SpellAbility tgtSA); } diff --git a/forge-gui/src/main/java/forge/game/player/PlayerControllerAi.java b/forge-gui/src/main/java/forge/game/player/PlayerControllerAi.java index 1e340354432..e75c53d1c9e 100644 --- a/forge-gui/src/main/java/forge/game/player/PlayerControllerAi.java +++ b/forge-gui/src/main/java/forge/game/player/PlayerControllerAi.java @@ -32,6 +32,7 @@ import forge.game.Game; import forge.game.GameEntity; import forge.game.GameObject; import forge.game.GameType; +import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.card.Card; import forge.game.card.CardLists; @@ -49,7 +50,9 @@ import forge.game.spellability.Spell; import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.TargetChoices; +import forge.game.spellability.TargetSelection; import forge.game.trigger.Trigger; +import forge.game.trigger.WrappedAbility; import forge.game.zone.ZoneType; import forge.item.PaperCard; import forge.util.Aggregates; @@ -604,4 +607,63 @@ public class PlayerControllerAi extends PlayerController { } return choice; } + + @Override + public boolean payCostToPreventEffect(Cost cost, SpellAbility sa, boolean alreadyPaid, List allPayers) { + final Card source = sa.getSourceCard(); + final Ability emptyAbility = new AbilityStatic(source, cost, sa.getTargetRestrictions()) { @Override public void resolve() { } }; + emptyAbility.setActivatingPlayer(player); + if (ComputerUtilCost.willPayUnlessCost(sa, player, cost, alreadyPaid, allPayers) && ComputerUtilCost.canPayCost(emptyAbility, player)) { + ComputerUtil.playNoStack(player, emptyAbility, game); // AI needs something to resolve to pay that cost + return true; + } + return false; + } + + @Override + public void orderAndPlaySimultaneousSa(List activePlayerSAs) { + for (final SpellAbility sa : activePlayerSAs) { + prepareSingleSa(sa.getSourceCard(),sa,true); + ComputerUtil.playStack(sa, player, game); + } + } + + private void prepareSingleSa(final Card host, final SpellAbility sa, boolean isMandatory){ + if (sa.hasParam("TargetingPlayer")) { + Player targetingPlayer = AbilityUtils.getDefinedPlayers(host, sa.getParam("TargetingPlayer"), sa).get(0); + if (targetingPlayer.isHuman()) { + final TargetSelection select = new TargetSelection(sa); + select.chooseTargets(null); + } else { //AI + sa.doTrigger(true, targetingPlayer); + } + } else { + sa.doTrigger(isMandatory, player); + } + } + + @Override + public void playTrigger(Card host, WrappedAbility wrapperAbility, boolean isMandatory) { + prepareSingleSa(host, wrapperAbility, isMandatory); + ComputerUtil.playNoStack(wrapperAbility.getActivatingPlayer(), wrapperAbility, game); + } + + @Override + public boolean playSaFromPlayEffect(SpellAbility tgtSA) { + boolean optional = tgtSA.hasParam("Optional"); + boolean noManaCost = tgtSA.hasParam("WithoutManaCost"); + if (tgtSA instanceof Spell) { // Isn't it ALWAYS a spell? + Spell spell = (Spell) tgtSA; + if (spell.canPlayFromEffectAI(player, !optional, noManaCost) || !optional) { + if (noManaCost) { + ComputerUtil.playSpellAbilityWithoutPayingManaCost(player, tgtSA, game); + } else { + ComputerUtil.playStack(tgtSA, player, game); + } + } else + return false; // didn't play spell + } + return true; + } + } diff --git a/forge-gui/src/main/java/forge/game/trigger/TriggerHandler.java b/forge-gui/src/main/java/forge/game/trigger/TriggerHandler.java index 97cf7a78f16..7f9988193e8 100644 --- a/forge-gui/src/main/java/forge/game/trigger/TriggerHandler.java +++ b/forge-gui/src/main/java/forge/game/trigger/TriggerHandler.java @@ -23,7 +23,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import forge.ai.ComputerUtil; import forge.card.mana.ManaCost; import forge.game.Game; import forge.game.GlobalRuleChange; @@ -33,12 +32,10 @@ import forge.game.ability.ApiType; import forge.game.ability.effects.CharmEffect; import forge.game.card.Card; import forge.game.phase.PhaseType; -import forge.game.player.HumanPlay; import forge.game.player.Player; import forge.game.spellability.Ability; import forge.game.spellability.SpellAbility; import forge.game.spellability.TargetRestrictions; -import forge.game.spellability.TargetSelection; import forge.game.zone.ZoneType; public class TriggerHandler { @@ -413,23 +410,7 @@ public class TriggerHandler { wrapperAbility.setDescription(wrapperAbility.getStackDescription()); if (regtrig.isStatic()) { - if (wrapperAbility.getActivatingPlayer().isHuman()) { - HumanPlay.playSpellAbilityNoStack(wrapperAbility.getActivatingPlayer(), wrapperAbility); - } else { - if (wrapperAbility.hasParam("TargetingPlayer")) { - Player targetingPlayer = AbilityUtils.getDefinedPlayers(host, wrapperAbility.getParam("TargetingPlayer"), wrapperAbility).get(0); - if (targetingPlayer.isHuman()) { - wrapperAbility.resetTargets(); - final TargetSelection select = new TargetSelection(wrapperAbility); - select.chooseTargets(null); - } else { //AI - wrapperAbility.doTrigger(true, targetingPlayer); - } - } else { - wrapperAbility.doTrigger(isMandatory, wrapperAbility.getActivatingPlayer()); - } - ComputerUtil.playNoStack(wrapperAbility.getActivatingPlayer(), wrapperAbility, game); - } + wrapperAbility.getActivatingPlayer().getController().playTrigger(host, wrapperAbility, isMandatory); } else { game.getStack().addSimultaneousStackEntry(wrapperAbility); } diff --git a/forge-gui/src/main/java/forge/game/zone/MagicStack.java b/forge-gui/src/main/java/forge/game/zone/MagicStack.java index 1b483f6f425..be79a3efca2 100644 --- a/forge-gui/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-gui/src/main/java/forge/game/zone/MagicStack.java @@ -31,7 +31,6 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import forge.FThreads; -import forge.ai.ComputerUtil; import forge.ai.ComputerUtilCard; import forge.card.mana.ManaCost; import forge.game.Game; @@ -50,7 +49,6 @@ import forge.game.event.GameEventCardStatsChanged; import forge.game.event.GameEventSpellAbilityCast; import forge.game.event.GameEventSpellRemovedFromStack; import forge.game.event.GameEventSpellResolved; -import forge.game.player.HumanPlay; import forge.game.player.Player; import forge.game.player.PlayerController.ManaPaymentPurpose; import forge.game.replacement.ReplacementEffect; @@ -65,10 +63,8 @@ import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.TargetChoices; import forge.game.spellability.TargetRestrictions; -import forge.game.spellability.TargetSelection; import forge.game.trigger.Trigger; import forge.game.trigger.TriggerType; -import forge.gui.GuiChoose; import forge.gui.input.InputSelectCards; import forge.gui.input.InputSelectCardsFromList; @@ -865,37 +861,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable orderedSAs = activePlayerSAs; - if (activePlayerSAs.size() > 1) { // give a dual list form to create instead of needing to do it one at a time - orderedSAs = GuiChoose.order("Select order for Simultaneous Spell Abilities", "Resolve first", 0, activePlayerSAs, null, null); - } - int size = orderedSAs.size(); - for (int i = size - 1; i >= 0; i--) { - SpellAbility next = orderedSAs.get(i); - if (next.isTrigger()) { - HumanPlay.playSpellAbility(activePlayer, next); - } else { - this.add(next); - } - } - } - + activePlayer.getController().orderAndPlaySimultaneousSa(activePlayerSAs); } /** diff --git a/forge-gui/src/main/java/forge/gui/GuiDisplayUtil.java b/forge-gui/src/main/java/forge/gui/GuiDisplayUtil.java index 7bb9a5b5572..623a312f963 100644 --- a/forge-gui/src/main/java/forge/gui/GuiDisplayUtil.java +++ b/forge-gui/src/main/java/forge/gui/GuiDisplayUtil.java @@ -46,7 +46,7 @@ import forge.game.card.CardLists; import forge.game.card.CardPredicates; import forge.game.card.CounterType; import forge.game.phase.PhaseType; -import forge.game.player.HumanPlay; +import forge.gui.player.HumanPlay; import forge.game.player.Player; import forge.game.spellability.AbilityManaPart; import forge.game.spellability.SpellAbility; diff --git a/forge-gui/src/main/java/forge/gui/input/InputPayMana.java b/forge-gui/src/main/java/forge/gui/input/InputPayMana.java index ba20edbfb62..310f6346dcb 100644 --- a/forge-gui/src/main/java/forge/gui/input/InputPayMana.java +++ b/forge-gui/src/main/java/forge/gui/input/InputPayMana.java @@ -17,7 +17,7 @@ import forge.game.ability.ApiType; import forge.game.card.Card; import forge.game.card.CardUtil; import forge.game.mana.ManaCostBeingPaid; -import forge.game.player.HumanPlay; +import forge.gui.player.HumanPlay; import forge.game.player.Player; import forge.game.player.PlayerControllerAi; import forge.game.replacement.ReplacementEffect; diff --git a/forge-gui/src/main/java/forge/gui/match/controllers/CField.java b/forge-gui/src/main/java/forge/gui/match/controllers/CField.java index 6538af3ab5a..a28c644088c 100644 --- a/forge-gui/src/main/java/forge/gui/match/controllers/CField.java +++ b/forge-gui/src/main/java/forge/gui/match/controllers/CField.java @@ -30,7 +30,7 @@ import forge.Singletons; import forge.Constant.Preferences; import forge.game.Game; import forge.game.card.Card; -import forge.game.player.HumanPlay; +import forge.gui.player.HumanPlay; import forge.game.player.LobbyPlayer; import forge.game.player.Player; import forge.game.spellability.SpellAbility; diff --git a/forge-gui/src/main/java/forge/game/player/HumanPlay.java b/forge-gui/src/main/java/forge/gui/player/HumanPlay.java similarity index 96% rename from forge-gui/src/main/java/forge/game/player/HumanPlay.java rename to forge-gui/src/main/java/forge/gui/player/HumanPlay.java index 406744d0bba..95d817faa1c 100644 --- a/forge-gui/src/main/java/forge/game/player/HumanPlay.java +++ b/forge-gui/src/main/java/forge/gui/player/HumanPlay.java @@ -1,4 +1,4 @@ -package forge.game.player; +package forge.gui.player; import java.util.ArrayList; import java.util.List; @@ -47,6 +47,7 @@ import forge.game.cost.CostReveal; import forge.game.cost.CostSacrifice; import forge.game.cost.CostTapType; import forge.game.mana.ManaCostBeingPaid; +import forge.game.player.Player; import forge.game.spellability.Ability; import forge.game.spellability.HumanPlaySpellAbility; import forge.game.spellability.SpellAbility; @@ -343,16 +344,9 @@ public class HumanPlay { return false; } - StringBuilder sb = new StringBuilder(); - - sb.append("Do you want to "); + StringBuilder sb = new StringBuilder("Do you want to "); sb.append(res.contains(p) ? "" : "let that player "); - sb.append("draw " + amount); - sb.append(" card"); - if (amount != 1) { - sb.append("s"); - } - sb.append("?" + orString); + sb.append("draw " + Lang.nounWithAmount(amount, " card") + "?" + orString); if (!p.getController().confirmPayment(part, sb.toString())) { return false; diff --git a/forge-gui/src/main/java/forge/game/player/LobbyPlayerHuman.java b/forge-gui/src/main/java/forge/gui/player/LobbyPlayerHuman.java similarity index 78% rename from forge-gui/src/main/java/forge/game/player/LobbyPlayerHuman.java rename to forge-gui/src/main/java/forge/gui/player/LobbyPlayerHuman.java index a79ef8eb74e..cedcdcf428b 100644 --- a/forge-gui/src/main/java/forge/game/player/LobbyPlayerHuman.java +++ b/forge-gui/src/main/java/forge/gui/player/LobbyPlayerHuman.java @@ -1,6 +1,10 @@ -package forge.game.player; +package forge.gui.player; import forge.game.Game; +import forge.game.player.LobbyPlayer; +import forge.game.player.Player; +import forge.game.player.PlayerController; +import forge.game.player.PlayerType; import forge.gui.FNetOverlay; public class LobbyPlayerHuman extends LobbyPlayer { diff --git a/forge-gui/src/main/java/forge/game/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/gui/player/PlayerControllerHuman.java similarity index 93% rename from forge-gui/src/main/java/forge/game/player/PlayerControllerHuman.java rename to forge-gui/src/main/java/forge/gui/player/PlayerControllerHuman.java index 7bedef205ee..0d53445910d 100644 --- a/forge-gui/src/main/java/forge/game/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/gui/player/PlayerControllerHuman.java @@ -1,4 +1,4 @@ -package forge.game.player; +package forge.gui.player; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; @@ -44,6 +44,10 @@ import forge.game.cost.Cost; import forge.game.cost.CostPart; import forge.game.mana.Mana; import forge.game.phase.PhaseType; +import forge.game.player.LobbyPlayer; +import forge.game.player.Player; +import forge.game.player.PlayerActionConfirmMode; +import forge.game.player.PlayerController; import forge.game.replacement.ReplacementEffect; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; @@ -51,6 +55,7 @@ import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.TargetChoices; import forge.game.spellability.TargetSelection; import forge.game.trigger.Trigger; +import forge.game.trigger.WrappedAbility; import forge.game.zone.Zone; import forge.game.zone.ZoneType; import forge.gui.GuiChoose; @@ -948,4 +953,39 @@ public class PlayerControllerHuman extends PlayerController { public String chooseProtectionType(String string, SpellAbility sa, List choices) { return GuiChoose.one(string, choices); } + + @Override + public boolean payCostToPreventEffect(Cost cost, SpellAbility sa, boolean alreadyPaid, List allPayers) { + // if it's paid by the AI already the human can pay, but it won't change anything + final Card source = sa.getSourceCard(); + return HumanPlay.payCostDuringAbilityResolve(player, source, cost, sa, null); + } + + @Override + public void orderAndPlaySimultaneousSa(List activePlayerSAs) { + List orderedSAs = activePlayerSAs; + if (activePlayerSAs.size() > 1) { // give a dual list form to create instead of needing to do it one at a time + orderedSAs = GuiChoose.order("Select order for Simultaneous Spell Abilities", "Resolve first", 0, activePlayerSAs, null, null); + } + int size = orderedSAs.size(); + for (int i = size - 1; i >= 0; i--) { + SpellAbility next = orderedSAs.get(i); + if (next.isTrigger()) { + HumanPlay.playSpellAbility(player, next); + } else { + player.getGame().getStack().add(next); + } + } + } + + @Override + public void playTrigger(Card host, WrappedAbility wrapperAbility, boolean isMandatory) { + HumanPlay.playSpellAbilityNoStack(player, wrapperAbility); + } + + @Override + public boolean playSaFromPlayEffect(SpellAbility tgtSA) { + HumanPlay.playSpellAbility(player, tgtSA); + return true; + } } diff --git a/forge-gui/src/main/java/forge/gui/player/package-info.java b/forge-gui/src/main/java/forge/gui/player/package-info.java new file mode 100644 index 00000000000..e9f09169937 --- /dev/null +++ b/forge-gui/src/main/java/forge/gui/player/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author Max + * + */ +package forge.gui.player; \ No newline at end of file diff --git a/forge-gui/src/main/java/forge/net/FServer.java b/forge-gui/src/main/java/forge/net/FServer.java index 42008a09f46..ee8be5e8a24 100644 --- a/forge-gui/src/main/java/forge/net/FServer.java +++ b/forge-gui/src/main/java/forge/net/FServer.java @@ -8,13 +8,17 @@ import java.util.concurrent.CountDownLatch; import org.apache.commons.lang3.time.StopWatch; +import com.google.common.base.Supplier; + import forge.Singletons; import forge.deck.Deck; import forge.game.Game; import forge.game.GameLogEntry; import forge.game.GameType; import forge.game.Match; +import forge.game.player.LobbyPlayer; import forge.game.player.RegisteredPlayer; +import forge.gui.player.LobbyPlayerHuman; import forge.util.Lang; @@ -30,7 +34,14 @@ public enum FServer { public Lobby getLobby() { if (lobby == null) { - lobby = new Lobby(); + //not a very good solution still + lobby = new Lobby(new Supplier() { + @Override + public LobbyPlayer get() { + // TODO Auto-generated method stub + return new LobbyPlayerHuman("Human"); + } + }); } return lobby; } diff --git a/forge-gui/src/main/java/forge/net/Lobby.java b/forge-gui/src/main/java/forge/net/Lobby.java index 61b55d58dcb..a221979463c 100644 --- a/forge-gui/src/main/java/forge/net/Lobby.java +++ b/forge-gui/src/main/java/forge/net/Lobby.java @@ -4,10 +4,11 @@ import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; +import com.google.common.base.Supplier; + import forge.control.ChatArea; import forge.game.player.LobbyPlayer; import forge.game.player.LobbyPlayerAi; -import forge.game.player.LobbyPlayerHuman; import forge.game.player.LobbyPlayerRemote; import forge.gui.GuiDisplayUtil; import forge.gui.toolbox.FSkin; @@ -20,7 +21,6 @@ import forge.util.MyRandom; */ public class Lobby { - private final String[] opponentNames = new String[] { "Abigail", "Ada", "Adeline", "Adriana", "Agatha", "Agnes", "Aileen", "Alba", "Alcyon", "Alethea", "Alice", "Alicia", "Alison", "Amanda", "Amelia", "Amy", "Andrea", "Angelina", @@ -62,8 +62,14 @@ public class Lobby { "Walter", "Wilfred", "William", "Winston" }; + private final LobbyPlayer guiPlayer; + public Lobby(Supplier humanFactory){ + guiPlayer = humanFactory.get(); + } + + private Map remotePlayers = new ConcurrentHashMap(); - private final LobbyPlayerHuman guiPlayer = new LobbyPlayerHuman("Human"); + private final LobbyPlayerAi system = new LobbyPlayerAi("System"); public final LobbyPlayer getGuiPlayer() { diff --git a/forge-gui/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java b/forge-gui/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java index b6952187b0d..27592efd2a1 100644 --- a/forge-gui/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java +++ b/forge-gui/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java @@ -14,6 +14,7 @@ import org.apache.commons.lang3.tuple.Pair; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; +import forge.ai.ComputerUtil; import forge.ai.ability.ChangeZoneAi; import forge.ai.ability.DrawAi; import forge.ai.ability.GameWinAi; @@ -24,6 +25,7 @@ import forge.game.Game; import forge.game.GameEntity; import forge.game.GameObject; import forge.game.GameType; +import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CounterType; import forge.game.combat.Combat; @@ -31,17 +33,20 @@ import forge.game.combat.CombatUtil; import forge.game.cost.Cost; import forge.game.cost.CostPart; import forge.game.mana.Mana; -import forge.game.player.HumanPlay; +import forge.gui.player.HumanPlay; import forge.game.player.LobbyPlayer; import forge.game.player.Player; import forge.game.player.PlayerActionConfirmMode; import forge.game.player.PlayerController; import forge.game.replacement.ReplacementEffect; import forge.game.spellability.AbilitySub; +import forge.game.spellability.Spell; import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.TargetChoices; +import forge.game.spellability.TargetSelection; import forge.game.trigger.Trigger; +import forge.game.trigger.WrappedAbility; import forge.game.zone.ZoneType; import forge.gamesimulationtests.util.card.CardSpecification; import forge.gamesimulationtests.util.card.CardSpecificationHandler; @@ -473,4 +478,58 @@ public class PlayerControllerForTests extends PlayerController { public String chooseProtectionType(String string, SpellAbility sa, List choices) { return choices.get(0); } + + @Override + public boolean payCostToPreventEffect(Cost cost, SpellAbility sa, boolean alreadyPaid, List allPayers) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void orderAndPlaySimultaneousSa(List activePlayerSAs) { + for (final SpellAbility sa : activePlayerSAs) { + prepareSingleSa(sa.getSourceCard(),sa,true); + ComputerUtil.playStack(sa, player, game); + } + } + + private void prepareSingleSa(final Card host, final SpellAbility sa, boolean isMandatory){ + if (sa.hasParam("TargetingPlayer")) { + Player targetingPlayer = AbilityUtils.getDefinedPlayers(host, sa.getParam("TargetingPlayer"), sa).get(0); + if (targetingPlayer.isHuman()) { + final TargetSelection select = new TargetSelection(sa); + select.chooseTargets(null); + } else { //AI + sa.doTrigger(true, targetingPlayer); + } + } else { + sa.doTrigger(isMandatory, player); + } + } + + @Override + public void playTrigger(Card host, WrappedAbility wrapperAbility, boolean isMandatory) { + prepareSingleSa(host, wrapperAbility, isMandatory); + ComputerUtil.playNoStack(wrapperAbility.getActivatingPlayer(), wrapperAbility, game); + } + + @Override + public boolean playSaFromPlayEffect(SpellAbility tgtSA) { + // TODO Auto-generated method stub + boolean optional = tgtSA.hasParam("Optional"); + boolean noManaCost = tgtSA.hasParam("WithoutManaCost"); + if (tgtSA instanceof Spell) { // Isn't it ALWAYS a spell? + Spell spell = (Spell) tgtSA; + if (spell.canPlayFromEffectAI(player, !optional, noManaCost) || !optional) { + if (noManaCost) { + ComputerUtil.playSpellAbilityWithoutPayingManaCost(player, tgtSA, game); + } else { + ComputerUtil.playStack(tgtSA, player, game); + } + } else + return false; // didn't play spell + } + return true; + + } }