diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index d186bc69fa..661965db50 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -1187,7 +1187,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements } @Override - public void selectAttackers(Game game) { + public void selectAttackers(Game game, UUID attackingPlayerId) { logger.debug("selectAttackers"); declareAttackers(game, playerId); /*if (combat != null) { @@ -1206,7 +1206,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements } @Override - public void selectBlockers(Game game) { + public void selectBlockers(Game game, UUID defendingPlayerId) { logger.debug("selectBlockers"); if (combat != null && combat.getGroups().size() > 0) { List<CombatGroup> groups = game.getCombat().getGroups(); diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index bc275425fb..deab60f3c1 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -978,7 +978,7 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i } @Override - public void selectAttackers(Game game) { + public void selectAttackers(Game game, UUID attackingPlayerId) { log.debug("selectAttackers"); UUID opponentId = game.getCombat().getDefenders().iterator().next(); Attackers attackers = getPotentialAttackers(game); @@ -1005,7 +1005,7 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i } @Override - public void selectBlockers(Game game) { + public void selectBlockers(Game game, UUID defendingPlayerId) { log.debug("selectBlockers"); List<Permanent> blockers = getAvailableBlockers(game); diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/ComputerPlayerMCTS.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/ComputerPlayerMCTS.java index a88bf8ff84..c2b9801ce8 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/ComputerPlayerMCTS.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/ComputerPlayerMCTS.java @@ -214,7 +214,7 @@ public class ComputerPlayerMCTS extends ComputerPlayer<ComputerPlayerMCTS> imple // } @Override - public void selectAttackers(Game game) { + public void selectAttackers(Game game, UUID attackingPlayerId) { getNextAction(game, NextAction.SELECT_ATTACKERS); Combat combat = root.getCombat(); UUID opponentId = game.getCombat().getDefenders().iterator().next(); @@ -224,7 +224,7 @@ public class ComputerPlayerMCTS extends ComputerPlayer<ComputerPlayerMCTS> imple } @Override - public void selectBlockers(Game game) { + public void selectBlockers(Game game, UUID defendingPlayerId) { getNextAction(game, NextAction.SELECT_BLOCKERS); Combat combat = root.getCombat(); List<CombatGroup> groups = game.getCombat().getGroups(); diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSPlayer.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSPlayer.java index bd53638be9..2bb73f66a6 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSPlayer.java @@ -27,10 +27,6 @@ */ package mage.player.ai; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import mage.Constants.Outcome; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.PassAbility; @@ -39,6 +35,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; import org.apache.log4j.Logger; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** * * @author BetaSteward_at_googlemail.com @@ -269,13 +269,13 @@ public class MCTSPlayer extends ComputerPlayer<MCTSPlayer> { // } @Override - public void selectAttackers(Game game) { + public void selectAttackers(Game game, UUID attackingPlayerId) { game.pause(); nextAction = NextAction.SELECT_ATTACKERS; } @Override - public void selectBlockers(Game game) { + public void selectBlockers(Game game, UUID defendingPlayerId) { game.pause(); nextAction = NextAction.SELECT_BLOCKERS; } diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java index d2a26c3647..750fb1e519 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java @@ -27,21 +27,9 @@ */ package mage.player.ai; -import java.io.Serializable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.UUID; import mage.Constants.Outcome; import mage.Constants.Zone; -import mage.abilities.Ability; -import mage.abilities.ActivatedAbility; -import mage.abilities.Mode; -import mage.abilities.Modes; -import mage.abilities.TriggeredAbilities; -import mage.abilities.TriggeredAbility; +import mage.abilities.*; import mage.abilities.common.PassAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCost; @@ -62,6 +50,9 @@ import mage.target.TargetAmount; import mage.target.TargetCard; import org.apache.log4j.Logger; +import java.io.Serializable; +import java.util.*; + /** * * plays randomly @@ -187,7 +178,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { } @Override - public void selectAttackers(Game game) { + public void selectAttackers(Game game, UUID attackingPlayerId) { //useful only for two player games - will only attack first opponent // logger.info("select attackers"); UUID defenderId = game.getOpponents(playerId).iterator().next(); @@ -208,7 +199,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { } @Override - public void selectBlockers(Game game) { + public void selectBlockers(Game game, UUID defendingPlayerId) { // logger.info("select blockers"); int numGroups = game.getCombat().getGroups().size(); if (numGroups == 0) return; diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java index 64c41e0b5d..ffcc7b150d 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java @@ -654,7 +654,7 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements } @Override - public void selectAttackers(Game game) { + public void selectAttackers(Game game, UUID attackingPlayerId) { if (logger.isDebugEnabled() && (combat == null || combat.getGroups().isEmpty())) logger.debug("not attacking"); if (combat != null) { @@ -671,7 +671,7 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements } @Override - public void selectBlockers(Game game) { + public void selectBlockers(Game game, UUID defendingPlayerId) { logger.debug("selectBlockers"); if (combat != null && combat.getGroups().size() > 0) { List<CombatGroup> groups = game.getCombat().getGroups(); diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 637d85ae62..40dd05f68b 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -30,7 +30,6 @@ package mage.player.human; import mage.Constants.Outcome; import mage.Constants.RangeOfInfluence; -import mage.Constants.TargetController; import mage.Constants.Zone; import mage.MageObject; import mage.abilities.*; @@ -46,7 +45,7 @@ import mage.choices.ChoiceImpl; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterBlockingCreature; import mage.filter.common.FilterCreatureForCombat; -import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.draft.Draft; import mage.game.match.Match; @@ -74,7 +73,7 @@ public class HumanPlayer extends PlayerImpl<HumanPlayer> { private final transient PlayerResponse response = new PlayerResponse(); - protected static FilterCreatureForCombat filter = new FilterCreatureForCombat(); + protected static FilterCreatureForCombat filterCreatureForCombat = new FilterCreatureForCombat(); protected static FilterAttackingCreature filterAttack = new FilterAttackingCreature(); protected static FilterBlockingCreature filterBlock = new FilterBlockingCreature(); protected static Choice replacementEffectChoice = new ChoiceImpl(true); @@ -83,7 +82,7 @@ public class HumanPlayer extends PlayerImpl<HumanPlayer> { private static final Logger log = Logger.getLogger(HumanPlayer.class); static { - filter.add(new ControllerPredicate(TargetController.YOU)); + //filter.add(new ControllerPredicate(TargetController.YOU)); replacementEffectChoice.setMessage("Choose replacement effect"); staticOptions.put("UI.right.btn.text", "Done"); } @@ -491,8 +490,10 @@ public class HumanPlayer extends PlayerImpl<HumanPlayer> { } @Override - public void selectAttackers(Game game) { + public void selectAttackers(Game game, UUID attackingPlayerId) { updateGameStatePriority("selectAttackers", game); + FilterCreatureForCombat filter = filterCreatureForCombat.copy(); + filter.add(new ControllerIdPredicate(attackingPlayerId)); while (!abort) { if (passedAllTurns || passedTurn) { return; @@ -510,7 +511,7 @@ public class HumanPlayer extends PlayerImpl<HumanPlayer> { } else if (response.getUUID() != null) { Permanent attacker = game.getPermanent(response.getUUID()); if (attacker != null) { - if (filter.match(attacker, null, playerId, game)) { + if (filterCreatureForCombat.match(attacker, null, playerId, game)) { selectDefender(game.getCombat().getDefenders(), attacker.getId(), game); } else if (filterAttack.match(attacker, null, playerId, game) && game.getStack().isEmpty()) { @@ -538,8 +539,10 @@ public class HumanPlayer extends PlayerImpl<HumanPlayer> { } @Override - public void selectBlockers(Game game) { + public void selectBlockers(Game game, UUID defendingPlayerId) { updateGameStatePriority("selectBlockers", game); + FilterCreatureForCombat filter = filterCreatureForCombat.copy(); + filter.add(new ControllerIdPredicate(defendingPlayerId)); while (!abort) { game.fireSelectEvent(playerId, "Select blockers"); waitForResponse(); diff --git a/Mage.Server/plugins/mage-player-ai-draft-bot.jar b/Mage.Server/plugins/mage-player-ai-draft-bot.jar index d2a9daa014..f03c3ade7f 100644 Binary files a/Mage.Server/plugins/mage-player-ai-draft-bot.jar and b/Mage.Server/plugins/mage-player-ai-draft-bot.jar differ diff --git a/Mage.Server/plugins/mage-player-ai-ma.jar b/Mage.Server/plugins/mage-player-ai-ma.jar index c9cc6732d2..d8d96ca6da 100644 Binary files a/Mage.Server/plugins/mage-player-ai-ma.jar and b/Mage.Server/plugins/mage-player-ai-ma.jar differ diff --git a/Mage.Server/plugins/mage-player-ai.jar b/Mage.Server/plugins/mage-player-ai.jar index 7c22e8cd91..152af7c1b8 100644 Binary files a/Mage.Server/plugins/mage-player-ai.jar and b/Mage.Server/plugins/mage-player-ai.jar differ diff --git a/Mage.Server/plugins/mage-player-aimcts.jar b/Mage.Server/plugins/mage-player-aimcts.jar index 1d820de797..a3d2089b02 100644 Binary files a/Mage.Server/plugins/mage-player-aimcts.jar and b/Mage.Server/plugins/mage-player-aimcts.jar differ diff --git a/Mage.Server/plugins/mage-player-aiminimax.jar b/Mage.Server/plugins/mage-player-aiminimax.jar index eac2decfb2..9f8516089c 100644 Binary files a/Mage.Server/plugins/mage-player-aiminimax.jar and b/Mage.Server/plugins/mage-player-aiminimax.jar differ diff --git a/Mage.Server/plugins/mage-player-human.jar b/Mage.Server/plugins/mage-player-human.jar index eb77c127bf..61d79465e3 100644 Binary files a/Mage.Server/plugins/mage-player-human.jar and b/Mage.Server/plugins/mage-player-human.jar differ diff --git a/Mage.Sets/src/mage/sets/magic2013/OdricMasterTactician.java b/Mage.Sets/src/mage/sets/magic2013/OdricMasterTactician.java new file mode 100644 index 0000000000..58489b1153 --- /dev/null +++ b/Mage.Sets/src/mage/sets/magic2013/OdricMasterTactician.java @@ -0,0 +1,174 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.magic2013; + +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author noxx + */ +public class OdricMasterTactician extends CardImpl<OdricMasterTactician> { + + public OdricMasterTactician(UUID ownerId) { + super(ownerId, 23, "Odric, Master Tactician", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); + this.expansionSetCode = "M13"; + this.supertype.add("Legendary"); + this.subtype.add("Human"); + this.subtype.add("Soldier"); + + this.color.setWhite(true); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Whenever Odric, Master Tactician and at least three other creatures attack, you choose which creatures block this combat and how those creatures block. + this.addAbility(new OdricMasterTacticianTriggeredAbility()); + } + + public OdricMasterTactician(final OdricMasterTactician card) { + super(card); + } + + @Override + public OdricMasterTactician copy() { + return new OdricMasterTactician(this); + } +} + +class OdricMasterTacticianTriggeredAbility extends TriggeredAbilityImpl<OdricMasterTacticianTriggeredAbility> { + + public OdricMasterTacticianTriggeredAbility() { + super(Constants.Zone.BATTLEFIELD, new OdricMasterTacticianEffect()); + } + + public OdricMasterTacticianTriggeredAbility(final OdricMasterTacticianTriggeredAbility ability) { + super(ability); + } + + @Override + public OdricMasterTacticianTriggeredAbility copy() { + return new OdricMasterTacticianTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DECLARED_ATTACKERS) { + resetEffect(); + if (game.getCombat().getAttackers().size() >= 4 && game.getCombat().getAttackers().contains(this.sourceId)) { + enableEffect(); + return true; + } + } + return false; + } + + @Override + public void reset(Game game) { + resetEffect(); + } + + private void resetEffect() { + getEffects().get(0).setValue("apply_" + sourceId, false); + } + + private void enableEffect() { + getEffects().get(0).setValue("apply_" + sourceId, true); + } + + @Override + public String getRule() { + return "Whenever Odric, Master Tactician and at least three other creatures attack, you choose which creatures block this combat and how those creatures block"; + } + +} + +class OdricMasterTacticianEffect extends ReplacementEffectImpl<OdricMasterTacticianEffect> { + + public OdricMasterTacticianEffect() { + super(Constants.Duration.WhileOnBattlefield, Constants.Outcome.Benefit); + } + + public OdricMasterTacticianEffect(final OdricMasterTacticianEffect effect) { + super(effect); + } + + @Override + public OdricMasterTacticianEffect copy() { + return new OdricMasterTacticianEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player player = game.getPlayer(source.getControllerId()); + //20101001 - 509.1c + game.getCombat().checkBlockRequirements(player, game); + for (UUID defenderId : game.getCombat().getPlayerDefenders(game)) { + game.getPlayer(source.getControllerId()).selectBlockers(game, defenderId); + if (game.isPaused() || game.isGameOver()) { + return true; + } + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, defenderId, defenderId)); + } + + return true; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getType() == GameEvent.EventType.DECLARING_BLOCKERS) { + Object object = getValue("apply_" + source.getSourceId()); + if (object != null && object instanceof Boolean) { + if ((Boolean)object) { + return true; // replace event + } + } + } + + return false; + } +} diff --git a/Mage/src/mage/game/combat/Combat.java b/Mage/src/mage/game/combat/Combat.java index 4078656937..5f50600a14 100644 --- a/Mage/src/mage/game/combat/Combat.java +++ b/Mage/src/mage/game/combat/Combat.java @@ -125,7 +125,7 @@ public class Combat implements Serializable, Copyable<Combat> { Player player = game.getPlayer(attackerId); //20101001 - 508.1d checkAttackRequirements(player, game); - player.selectAttackers(game); + player.selectAttackers(game, attackerId); if (game.isPaused() || game.isGameOver()) return; resumeSelectAttackers(game); @@ -173,7 +173,7 @@ public class Combat implements Serializable, Copyable<Combat> { //20101001 - 509.1c checkBlockRequirements(player, game); for (UUID defenderId : getPlayerDefenders(game)) { - game.getPlayer(defenderId).selectBlockers(game); + game.getPlayer(defenderId).selectBlockers(game, defenderId); if (game.isPaused() || game.isGameOver()) return; game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, defenderId, defenderId)); @@ -188,7 +188,7 @@ public class Combat implements Serializable, Copyable<Combat> { } } - protected void checkBlockRequirements(Player player, Game game) { + public void checkBlockRequirements(Player player, Game game) { //20101001 - 509.1c //TODO: handle case where more than one attacker must be blocked for (Permanent creature : game.getBattlefield().getActivePermanents(filterBlockers, player.getId(), game)) { @@ -381,7 +381,7 @@ public class Combat implements Serializable, Copyable<Combat> { return defenderId; } - private Set<UUID> getPlayerDefenders(Game game) { + public Set<UUID> getPlayerDefenders(Game game) { Set<UUID> playerDefenders = new HashSet<UUID>(); for (CombatGroup group : groups) { if (group.defenderIsPlaneswalker) { diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index cbc9eeaebd..5bd3e80ac2 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -229,8 +229,8 @@ public interface Player extends MageItem, Copyable<Player> { public abstract int chooseEffect(List<ReplacementEffect> rEffects, Game game); public abstract TriggeredAbility chooseTriggeredAbility(List<TriggeredAbility> abilities, Game game); public abstract Mode chooseMode(Modes modes, Ability source, Game game); - public abstract void selectAttackers(Game game); - public abstract void selectBlockers(Game game); + public abstract void selectAttackers(Game game, UUID attackingPlayerId); + public abstract void selectBlockers(Game game, UUID defendingPlayerId); public abstract UUID chooseAttackerOrder(List<Permanent> attacker, Game game); public abstract UUID chooseBlockerOrder(List<Permanent> blockers, Game game); public abstract void assignDamage(int damage, List<UUID> targets, String singleTargetName, UUID sourceId, Game game);