mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
removed the 'currentdefender' field from Combat, each user has to track himself the defenders
canAttack and addAttacker methods now require a defender.
This commit is contained in:
@@ -16,7 +16,6 @@ import forge.CardPredicates;
|
||||
import forge.CardPredicates.Presets;
|
||||
import forge.Constant;
|
||||
import forge.GameEntity;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.ability.ApiType;
|
||||
import forge.card.ability.SpellAbilityAi;
|
||||
@@ -28,6 +27,7 @@ import forge.card.spellability.AbilitySub;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.card.spellability.Target;
|
||||
import forge.card.trigger.TriggerType;
|
||||
import forge.game.GameState;
|
||||
import forge.game.GlobalRuleChange;
|
||||
import forge.game.ai.ComputerUtil;
|
||||
import forge.game.ai.ComputerUtilBlock;
|
||||
@@ -191,17 +191,17 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
//Ninjutsu
|
||||
if (sa.hasParam("Ninjutsu")) {
|
||||
if (source.isType("Legendary")
|
||||
&& !Singletons.getModel().getGame().getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule)) {
|
||||
&& !ai.getGame().getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule)) {
|
||||
final List<Card> list = ai.getCardsIn(ZoneType.Battlefield);
|
||||
if (Iterables.any(list, CardPredicates.nameEquals(source.getName()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DAMAGE)) {
|
||||
if (ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DAMAGE)) {
|
||||
return false;
|
||||
}
|
||||
List<Card> attackers = new ArrayList<Card>();
|
||||
attackers.addAll(Singletons.getModel().getGame().getCombat().getUnblockedAttackers());
|
||||
attackers.addAll(ai.getGame().getCombat().getUnblockedAttackers());
|
||||
boolean lowerCMC = false;
|
||||
for (Card attacker : attackers) {
|
||||
if (attacker.getCMC() < source.getCMC()) {
|
||||
@@ -284,7 +284,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
// don't use fetching to top of library/graveyard before main2
|
||||
if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
|
||||
if (ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
|
||||
&& !sa.hasParam("ActivationPhases")) {
|
||||
if (!destination.equals("Battlefield") && !destination.equals("Hand")) {
|
||||
return false;
|
||||
@@ -495,7 +495,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
combat.initiatePossibleDefenders(ai);
|
||||
List<Card> attackers = ai.getOpponent().getCreaturesInPlay();
|
||||
for (Card att : attackers) {
|
||||
combat.addAttacker(att);
|
||||
combat.addAttacker(att, ai);
|
||||
}
|
||||
combat = ComputerUtilBlock.getBlockers(ai, combat, ai.getCreaturesInPlay());
|
||||
|
||||
@@ -589,7 +589,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
// in general this should only be used to protect from Imminent Harm
|
||||
// (dying or losing control of)
|
||||
if (origin.equals(ZoneType.Battlefield)) {
|
||||
if (Singletons.getModel().getGame().getStack().size() == 0) {
|
||||
if (ai.getGame().getStack().size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -620,14 +620,14 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
// don't return something to your hand if your hand is full of good stuff
|
||||
if (destination.equals(ZoneType.Hand) && origin.equals(ZoneType.Graveyard)) {
|
||||
final int handSize = ai.getCardsIn(ZoneType.Hand).size();
|
||||
if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN1)) {
|
||||
if (ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN1)) {
|
||||
return false;
|
||||
}
|
||||
if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
|
||||
if (ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
|
||||
&& handSize > 1) {
|
||||
return false;
|
||||
}
|
||||
if (Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(ai)
|
||||
if (ai.getGame().getPhaseHandler().isPlayerTurn(ai)
|
||||
&& handSize >= ai.getMaxHandSize()) {
|
||||
return false;
|
||||
}
|
||||
@@ -688,7 +688,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
tgt.resetTargets();
|
||||
List<Card> list = CardLists.getValidCards(Singletons.getModel().getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source);
|
||||
List<Card> list = CardLists.getValidCards(ai.getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source);
|
||||
if (sa.hasParam("AITgts")) {
|
||||
list = CardLists.getValidCards(list, sa.getParam("AITgts"), sa.getActivatingPlayer(), source);
|
||||
}
|
||||
@@ -721,7 +721,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
|
||||
// check stack for something on the stack that will kill
|
||||
// anything i control
|
||||
if (Singletons.getModel().getGame().getStack().size() > 0) {
|
||||
if (ai.getGame().getStack().size() > 0) {
|
||||
final ArrayList<Object> objects = ComputerUtil.predictThreatenedObjects(ai, sa);
|
||||
|
||||
final List<Card> threatenedTargets = new ArrayList<Card>();
|
||||
@@ -739,7 +739,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
// Save combatants
|
||||
else if (Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) {
|
||||
else if (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)) {
|
||||
final List<Card> combatants = CardLists.filter(aiPermanents, CardPredicates.Presets.CREATURES);
|
||||
CardLists.sortByEvaluateCreature(combatants);
|
||||
|
||||
@@ -795,7 +795,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
if (origin.equals(ZoneType.Battlefield)
|
||||
&& destination.equals(ZoneType.Exile)
|
||||
&& (subApi == ApiType.DelayedTrigger || (subApi == ApiType.ChangeZone && subAffected.equals("Remembered")))
|
||||
&& !(Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || sa
|
||||
&& !(ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) || sa
|
||||
.isAbility())) {
|
||||
return false;
|
||||
}
|
||||
@@ -805,8 +805,8 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
|
||||
// don't rush bouncing stuff when not going to attack
|
||||
if (!sa.isTrigger() && sa.getPayCosts() != null
|
||||
&& Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
|
||||
&& Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(ai)
|
||||
&& ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
|
||||
&& ai.getGame().getPhaseHandler().isPlayerTurn(ai)
|
||||
&& ai.getCreaturesInPlay().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -825,7 +825,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
// Only care about combatants during combat
|
||||
if (Singletons.getModel().getGame().getPhaseHandler().inCombat()) {
|
||||
if (ai.getGame().getPhaseHandler().inCombat()) {
|
||||
CardLists.getValidCards(list, "Card.attacking,Card.blocking", null, null);
|
||||
}
|
||||
|
||||
@@ -931,7 +931,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
final ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination"));
|
||||
final Target tgt = sa.getTarget();
|
||||
|
||||
List<Card> list = CardLists.getValidCards(Singletons.getModel().getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source);
|
||||
List<Card> list = CardLists.getValidCards(ai.getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source);
|
||||
|
||||
// Narrow down the list:
|
||||
if (origin.equals(ZoneType.Battlefield)) {
|
||||
@@ -1070,6 +1070,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
final Card card = sa.getSourceCard();
|
||||
final boolean defined = sa.hasParam("Defined");
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final GameState game = ai.getGame();
|
||||
|
||||
if (tgt != null) {
|
||||
if (!tgt.getTargetPlayers().isEmpty()) {
|
||||
@@ -1101,7 +1102,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
} else if (!origin.contains(ZoneType.Library) && !origin.contains(ZoneType.Hand)
|
||||
&& !sa.hasParam("DefinedPlayer")) {
|
||||
fetchList = Singletons.getModel().getGame().getCardsIn(origin);
|
||||
fetchList = game.getCardsIn(origin);
|
||||
fetchList = AbilityUtils.filterListByType(fetchList, type, sa);
|
||||
} else {
|
||||
fetchList = player.getCardsIn(origin);
|
||||
@@ -1253,7 +1254,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
Card movedCard = null;
|
||||
if (ZoneType.Library.equals(destination)) {
|
||||
final int libraryPos = sa.hasParam("LibraryPosition") ? Integer.parseInt(sa.getParam("LibraryPosition")) : 0;
|
||||
movedCard = Singletons.getModel().getGame().getAction().moveToLibrary(c, libraryPos);
|
||||
movedCard = game.getAction().moveToLibrary(c, libraryPos);
|
||||
} else if (ZoneType.Battlefield.equals(destination)) {
|
||||
if (sa.hasParam("Tapped")) {
|
||||
c.setTapped(true);
|
||||
@@ -1261,9 +1262,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
if (sa.hasParam("GainControl")) {
|
||||
if (sa.hasParam("NewController")) {
|
||||
final Player p = AbilityUtils.getDefinedPlayers(sa.getSourceCard(), sa.getParam("DefinedPlayer"), sa).get(0);
|
||||
c.setController(p, Singletons.getModel().getGame().getNextTimestamp());
|
||||
c.setController(p, game.getNextTimestamp());
|
||||
} else {
|
||||
c.setController(sa.getActivatingPlayer(), Singletons.getModel().getGame().getNextTimestamp());
|
||||
c.setController(sa.getActivatingPlayer(), game.getNextTimestamp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1271,7 +1272,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
List<Card> list = AbilityUtils.getDefinedCards(sa.getSourceCard(),
|
||||
sa.getParam("AttachedTo"), sa);
|
||||
if (list.isEmpty()) {
|
||||
list = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield);
|
||||
list = game.getCardsIn(ZoneType.Battlefield);
|
||||
list = CardLists.getValidCards(list, sa.getParam("AttachedTo"), c.getController(), c);
|
||||
}
|
||||
if (!list.isEmpty()) {
|
||||
@@ -1289,7 +1290,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
if (sa.hasParam("Attacking")) {
|
||||
Singletons.getModel().getGame().getCombat().addAttacker(c);
|
||||
List<GameEntity> defenders = game.getCombat().getDefenders();
|
||||
if ( !defenders.isEmpty() )
|
||||
game.getCombat().addAttacker(c, defenders.get(0));
|
||||
}
|
||||
// Auras without Candidates stay in their current location
|
||||
if (c.isAura()) {
|
||||
@@ -1299,24 +1302,24 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
movedCard = Singletons.getModel().getGame().getAction().moveTo(c.getController().getZone(destination), c);
|
||||
movedCard = game.getAction().moveTo(c.getController().getZone(destination), c);
|
||||
if (sa.hasParam("Tapped")) {
|
||||
movedCard.setTapped(true);
|
||||
}
|
||||
} else if (destination.equals(ZoneType.Exile)) {
|
||||
movedCard = Singletons.getModel().getGame().getAction().exile(c);
|
||||
movedCard = game.getAction().exile(c);
|
||||
if (sa.hasParam("ExileFaceDown")) {
|
||||
movedCard.setState(CardCharacteristicName.FaceDown);
|
||||
}
|
||||
} else {
|
||||
movedCard = Singletons.getModel().getGame().getAction().moveTo(destination, c);
|
||||
movedCard = game.getAction().moveTo(destination, c);
|
||||
}
|
||||
|
||||
if (champion) {
|
||||
final HashMap<String, Object> runParams = new HashMap<String, Object>();
|
||||
runParams.put("Card", card);
|
||||
runParams.put("Championed", c);
|
||||
Singletons.getModel().getGame().getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false);
|
||||
}
|
||||
|
||||
if (remember != null) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import forge.CardCharacteristicName;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.GameEntity;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.ability.SpellAbilityEffect;
|
||||
import forge.card.ability.ai.ChangeZoneAi;
|
||||
@@ -20,6 +19,7 @@ import forge.card.spellability.SpellAbility;
|
||||
import forge.card.spellability.SpellAbilityStackInstance;
|
||||
import forge.card.spellability.Target;
|
||||
import forge.card.trigger.TriggerType;
|
||||
import forge.game.GameState;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
import forge.game.player.AIPlayer;
|
||||
import forge.game.player.HumanPlayer;
|
||||
@@ -375,6 +375,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
final Target tgt = sa.getTarget();
|
||||
final Player player = sa.getActivatingPlayer();
|
||||
final Card hostCard = sa.getSourceCard();
|
||||
final GameState game = player.getGame();
|
||||
|
||||
final ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination"));
|
||||
final List<ZoneType> origin = ZoneType.listValueOf(sa.getParam("Origin"));
|
||||
@@ -400,12 +401,12 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
continue;
|
||||
}
|
||||
|
||||
final SpellAbilityStackInstance si = Singletons.getModel().getGame().getStack().getInstanceFromSpellAbility(tgtSA);
|
||||
final SpellAbilityStackInstance si = game.getStack().getInstanceFromSpellAbility(tgtSA);
|
||||
if (si == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
removeFromStack(tgtSA, sa, si);
|
||||
removeFromStack(tgtSA, sa, si, game);
|
||||
} // End of change from stack
|
||||
|
||||
final String remember = sa.getParam("RememberChanged");
|
||||
@@ -431,7 +432,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
if (player.isHuman() && optional && !GuiDialog.confirm(hostCard, prompt)) {
|
||||
continue;
|
||||
}
|
||||
final Zone originZone = Singletons.getModel().getGame().getZoneOf(tgtC);
|
||||
final Zone originZone = game.getZoneOf(tgtC);
|
||||
|
||||
// if Target isn't in the expected Zone, continue
|
||||
|
||||
@@ -445,7 +446,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
// library position is zero indexed
|
||||
final int libraryPosition = sa.hasParam("LibraryPosition") ? Integer.parseInt(sa.getParam("LibraryPosition")) : 0;
|
||||
|
||||
movedCard = Singletons.getModel().getGame().getAction().moveToLibrary(tgtC, libraryPosition);
|
||||
movedCard = game.getAction().moveToLibrary(tgtC, libraryPosition);
|
||||
|
||||
// for things like Gaea's Blessing
|
||||
if (sa.hasParam("Shuffle")) {
|
||||
@@ -459,16 +460,16 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
if (sa.hasParam("GainControl")) {
|
||||
if (sa.hasParam("NewController")) {
|
||||
final Player p = AbilityUtils.getDefinedPlayers(sa.getSourceCard(), sa.getParam("NewController"), sa).get(0);
|
||||
tgtC.setController(p, Singletons.getModel().getGame().getNextTimestamp());
|
||||
tgtC.setController(p, game.getNextTimestamp());
|
||||
} else {
|
||||
tgtC.setController(sa.getActivatingPlayer(), Singletons.getModel().getGame().getNextTimestamp());
|
||||
tgtC.setController(sa.getActivatingPlayer(), game.getNextTimestamp());
|
||||
}
|
||||
}
|
||||
if (sa.hasParam("AttachedTo")) {
|
||||
List<Card> list = AbilityUtils.getDefinedCards(hostCard,
|
||||
sa.getParam("AttachedTo"), sa);
|
||||
if (list.isEmpty()) {
|
||||
list = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield);
|
||||
list = game.getCardsIn(ZoneType.Battlefield);
|
||||
list = CardLists.getValidCards(list, sa.getParam("AttachedTo"), tgtC.getController(), tgtC);
|
||||
}
|
||||
if (!list.isEmpty()) {
|
||||
@@ -511,25 +512,28 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
movedCard = Singletons.getModel().getGame().getAction()
|
||||
.moveTo(tgtC.getController().getZone(destination), tgtC);
|
||||
movedCard = game.getAction().moveTo(tgtC.getController().getZone(destination), tgtC);
|
||||
|
||||
if (sa.hasParam("Ninjutsu") || sa.hasParam("Attacking")) {
|
||||
Singletons.getModel().getGame().getCombat().addAttacker(tgtC);
|
||||
Singletons.getModel().getGame().getCombat().addUnblockedAttacker(tgtC);
|
||||
// What should they attack?
|
||||
List<GameEntity> defenders = game.getCombat().getDefenders();
|
||||
if (!defenders.isEmpty()) {
|
||||
game.getCombat().addAttacker(tgtC, defenders.get(0));
|
||||
game.getCombat().addUnblockedAttacker(tgtC);
|
||||
}
|
||||
}
|
||||
if (sa.hasParam("Tapped") || sa.hasParam("Ninjutsu")) {
|
||||
tgtC.setTapped(true);
|
||||
}
|
||||
} else {
|
||||
movedCard = Singletons.getModel().getGame().getAction().moveTo(destination, tgtC);
|
||||
movedCard = game.getAction().moveTo(destination, tgtC);
|
||||
// If a card is Exiled from the stack, remove its spells from the stack
|
||||
if (sa.hasParam("Fizzle")) {
|
||||
ArrayList<SpellAbility> spells = tgtC.getSpellAbilities();
|
||||
for (SpellAbility spell : spells) {
|
||||
if (tgtC.isInZone(ZoneType.Exile)) {
|
||||
final SpellAbilityStackInstance si = Singletons.getModel().getGame().getStack().getInstanceFromSpellAbility(spell);
|
||||
Singletons.getModel().getGame().getStack().remove(si);
|
||||
final SpellAbilityStackInstance si = game.getStack().getInstanceFromSpellAbility(spell);
|
||||
game.getStack().remove(si);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -615,6 +619,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
final List<Card> movedCards = new ArrayList<Card>();
|
||||
final boolean defined = sa.hasParam("Defined");
|
||||
final boolean optional = sa.hasParam("Optional");
|
||||
final GameState game = player.getGame();
|
||||
|
||||
final Target tgt = sa.getTarget();
|
||||
if (tgt != null) {
|
||||
@@ -675,7 +680,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
}
|
||||
} else if (!origin.contains(ZoneType.Library) && !origin.contains(ZoneType.Hand)
|
||||
&& !sa.hasParam("DefinedPlayer")) {
|
||||
fetchList = Singletons.getModel().getGame().getCardsIn(origin);
|
||||
fetchList = game.getCardsIn(origin);
|
||||
} else {
|
||||
fetchList = player.getCardsIn(origin);
|
||||
}
|
||||
@@ -744,7 +749,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
if (origin.contains(ZoneType.Library) && (i < 1) && !"False".equals(sa.getParam("Shuffle"))) {
|
||||
player.shuffle();
|
||||
}
|
||||
movedCard = Singletons.getModel().getGame().getAction().moveToLibrary(c, libraryPos);
|
||||
movedCard = game.getAction().moveToLibrary(c, libraryPos);
|
||||
} else if (destination.equals(ZoneType.Battlefield)) {
|
||||
if (sa.hasParam("Tapped")) {
|
||||
c.setTapped(true);
|
||||
@@ -752,9 +757,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
if (sa.hasParam("GainControl")) {
|
||||
if (sa.hasParam("NewController")) {
|
||||
final Player p = AbilityUtils.getDefinedPlayers(sa.getSourceCard(), sa.getParam("NewController"), sa).get(0);
|
||||
c.setController(p, Singletons.getModel().getGame().getNextTimestamp());
|
||||
c.setController(p, game.getNextTimestamp());
|
||||
} else {
|
||||
c.setController(sa.getActivatingPlayer(), Singletons.getModel().getGame().getNextTimestamp());
|
||||
c.setController(sa.getActivatingPlayer(), game.getNextTimestamp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -762,7 +767,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
List<Card> list = AbilityUtils.getDefinedCards(sa.getSourceCard(),
|
||||
sa.getParam("AttachedTo"), sa);
|
||||
if (list.isEmpty()) {
|
||||
list = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield);
|
||||
list = game.getCardsIn(ZoneType.Battlefield);
|
||||
list = CardLists.getValidCards(list, sa.getParam("AttachedTo"), c.getController(), c);
|
||||
}
|
||||
if (!list.isEmpty()) {
|
||||
@@ -826,20 +831,20 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
if (sa.hasParam("Attacking")) {
|
||||
final List<GameEntity> e = c.getController().getGame().getCombat().getDefenders();
|
||||
final GameEntity defender = e.size() == 1 ? e.get(0) : GuiChoose.one("Declare " + c, e);
|
||||
Singletons.getModel().getGame().getCombat().addAttacker(c, defender);
|
||||
game.getCombat().addAttacker(c, defender);
|
||||
}
|
||||
|
||||
movedCard = Singletons.getModel().getGame().getAction().moveTo(c.getController().getZone(destination), c);
|
||||
movedCard = game.getAction().moveTo(c.getController().getZone(destination), c);
|
||||
if (sa.hasParam("Tapped")) {
|
||||
movedCard.setTapped(true);
|
||||
}
|
||||
} else if (destination.equals(ZoneType.Exile)) {
|
||||
movedCard = Singletons.getModel().getGame().getAction().exile(c);
|
||||
movedCard = game.getAction().exile(c);
|
||||
if (sa.hasParam("ExileFaceDown")) {
|
||||
movedCard.setState(CardCharacteristicName.FaceDown);
|
||||
}
|
||||
} else {
|
||||
movedCard = Singletons.getModel().getGame().getAction().moveTo(destination, c);
|
||||
movedCard = game.getAction().moveTo(destination, c);
|
||||
}
|
||||
movedCards.add(movedCard);
|
||||
|
||||
@@ -847,7 +852,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
final HashMap<String, Object> runParams = new HashMap<String, Object>();
|
||||
runParams.put("Card", card);
|
||||
runParams.put("Championed", c);
|
||||
Singletons.getModel().getGame().getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false);
|
||||
}
|
||||
|
||||
if (remember != null) {
|
||||
@@ -895,28 +900,29 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
* @param si
|
||||
* a {@link forge.card.spellability.SpellAbilityStackInstance}
|
||||
* object.
|
||||
* @param game
|
||||
*/
|
||||
private static void removeFromStack(final SpellAbility tgtSA, final SpellAbility srcSA, final SpellAbilityStackInstance si) {
|
||||
Singletons.getModel().getGame().getStack().remove(si);
|
||||
private static void removeFromStack(final SpellAbility tgtSA, final SpellAbility srcSA, final SpellAbilityStackInstance si, final GameState game) {
|
||||
game.getStack().remove(si);
|
||||
|
||||
if (srcSA.hasParam("Destination")) {
|
||||
final boolean remember = srcSA.hasParam("RememberChanged");
|
||||
if (tgtSA.isAbility()) {
|
||||
// Shouldn't be able to target Abilities but leaving this in for now
|
||||
} else if (tgtSA.isFlashBackAbility()) {
|
||||
Singletons.getModel().getGame().getAction().exile(tgtSA.getSourceCard());
|
||||
game.getAction().exile(tgtSA.getSourceCard());
|
||||
} else if (srcSA.getParam("Destination").equals("Graveyard")) {
|
||||
Singletons.getModel().getGame().getAction().moveToGraveyard(tgtSA.getSourceCard());
|
||||
game.getAction().moveToGraveyard(tgtSA.getSourceCard());
|
||||
} else if (srcSA.getParam("Destination").equals("Exile")) {
|
||||
Singletons.getModel().getGame().getAction().exile(tgtSA.getSourceCard());
|
||||
game.getAction().exile(tgtSA.getSourceCard());
|
||||
} else if (srcSA.getParam("Destination").equals("TopOfLibrary")) {
|
||||
Singletons.getModel().getGame().getAction().moveToLibrary(tgtSA.getSourceCard());
|
||||
game.getAction().moveToLibrary(tgtSA.getSourceCard());
|
||||
} else if (srcSA.getParam("Destination").equals("Hand")) {
|
||||
Singletons.getModel().getGame().getAction().moveToHand(tgtSA.getSourceCard());
|
||||
game.getAction().moveToHand(tgtSA.getSourceCard());
|
||||
} else if (srcSA.getParam("Destination").equals("BottomOfLibrary")) {
|
||||
Singletons.getModel().getGame().getAction().moveToBottomOfLibrary(tgtSA.getSourceCard());
|
||||
game.getAction().moveToBottomOfLibrary(tgtSA.getSourceCard());
|
||||
} else if (srcSA.getParam("Destination").equals("ShuffleIntoLibrary")) {
|
||||
Singletons.getModel().getGame().getAction().moveToBottomOfLibrary(tgtSA.getSourceCard());
|
||||
game.getAction().moveToBottomOfLibrary(tgtSA.getSourceCard());
|
||||
tgtSA.getSourceCard().getController().shuffle();
|
||||
} else {
|
||||
throw new IllegalArgumentException("AbilityFactory_ChangeZone: Invalid Destination argument for card "
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.util.List;
|
||||
|
||||
import forge.Card;
|
||||
import forge.GameEntity;
|
||||
import forge.Singletons;
|
||||
|
||||
import forge.card.ability.AbilityFactory;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.ability.SpellAbilityEffect;
|
||||
@@ -30,6 +30,7 @@ import forge.card.cardfactory.CardFactory;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.card.trigger.Trigger;
|
||||
import forge.card.trigger.TriggerHandler;
|
||||
import forge.game.GameState;
|
||||
import forge.game.event.TokenCreatedEvent;
|
||||
import forge.game.player.Player;
|
||||
import forge.gui.GuiChoose;
|
||||
@@ -206,9 +207,9 @@ public class TokenEffect extends SpellAbilityEffect {
|
||||
final List<Card> tokens = CardFactory.makeToken(substitutedName, imageName, controller, cost,
|
||||
substitutedTypes, finalPower, finalToughness, this.tokenKeywords);
|
||||
for(Card tok : tokens) {
|
||||
Singletons.getModel().getGame().getAction().moveToPlay(tok);
|
||||
controller.getGame().getAction().moveToPlay(tok);
|
||||
}
|
||||
Singletons.getModel().getGame().getEvents().post(new TokenCreatedEvent());
|
||||
controller.getGame().getEvents().post(new TokenCreatedEvent());
|
||||
|
||||
// Grant rule changes
|
||||
if (this.tokenHiddenKeywords != null) {
|
||||
@@ -274,25 +275,25 @@ public class TokenEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
final GameState game = controller.getGame();
|
||||
for (final Card c : tokens) {
|
||||
if (this.tokenTapped) {
|
||||
c.setTapped(true);
|
||||
}
|
||||
if (this.tokenAttacking) {
|
||||
final List<GameEntity> defs = c.getController().getGame().getCombat().getDefenders();
|
||||
if (c.getController().isHuman()) {
|
||||
final List<GameEntity> e = c.getController().getGame().getCombat().getDefenders();
|
||||
final GameEntity defender = e.size() == 1
|
||||
? e.get(0) : GuiChoose.one("Declare " + c, e);
|
||||
Singletons.getModel().getGame().getCombat().addAttacker(c, defender);
|
||||
final GameEntity defender = defs.size() == 1 ? defs.get(0) : GuiChoose.one("Declare " + c, defs);
|
||||
game.getCombat().addAttacker(c, defender);
|
||||
} else {
|
||||
Singletons.getModel().getGame().getCombat().addAttacker(c);
|
||||
game.getCombat().addAttacker(c, defs.get(0));
|
||||
}
|
||||
}
|
||||
if (remember != null) {
|
||||
Singletons.getModel().getGame().getCardState(sa.getSourceCard()).addRemembered(c);
|
||||
game.getCardState(sa.getSourceCard()).addRemembered(c);
|
||||
}
|
||||
if (sa.getParam("RememberSource") != null) {
|
||||
Singletons.getModel().getGame().getCardState(c).addRemembered(host);
|
||||
game.getCardState(c).addRemembered(host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,8 +76,14 @@ public class InputAttack extends InputBase {
|
||||
|
||||
List<Card> possibleAttackers = player.getCardsIn(ZoneType.Battlefield);
|
||||
for (Card c : Iterables.filter(possibleAttackers, CardPredicates.Presets.CREATURES)) {
|
||||
if (c.hasKeyword("CARDNAME attacks each turn if able.") && CombatUtil.canAttack(c, game.getCombat()) ) {
|
||||
if (!c.hasKeyword("CARDNAME attacks each turn if able."))
|
||||
continue; // do not force
|
||||
|
||||
for(GameEntity def : defenders ) {
|
||||
if( CombatUtil.canAttack(c, def, game.getCombat()) ) {
|
||||
game.getCombat().addAttacker(c, currentDefender);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,7 +131,7 @@ public class InputAttack extends InputBase {
|
||||
}
|
||||
|
||||
Zone zone = game.getZoneOf(card);
|
||||
if (zone.is(ZoneType.Battlefield, player) && CombatUtil.canAttack(card, game.getCombat())) {
|
||||
if (zone.is(ZoneType.Battlefield, player) && CombatUtil.canAttack(card, currentDefender, game.getCombat())) {
|
||||
|
||||
// TODO add the propaganda code here and remove it in
|
||||
// Phase.nextPhase()
|
||||
|
||||
@@ -445,7 +445,7 @@ public class AiAttackController {
|
||||
* @param bAssault
|
||||
* a boolean.
|
||||
*/
|
||||
public final void chooseDefender(final Combat c, final boolean bAssault) {
|
||||
public final GameEntity chooseDefender(final Combat c, final Combat gameCombat, final boolean bAssault) {
|
||||
final List<GameEntity> defs = c.getDefenders();
|
||||
|
||||
// Start with last planeswalker
|
||||
@@ -453,25 +453,19 @@ public class AiAttackController {
|
||||
|
||||
final GameEntity entity = ai.getMustAttackEntity();
|
||||
if (null != entity) {
|
||||
final List<GameEntity> defenders = Singletons.getModel().getGame().getCombat().getDefenders();
|
||||
final List<GameEntity> defenders = gameCombat.getDefenders();
|
||||
n = defenders.indexOf(entity);
|
||||
if (-1 == n) {
|
||||
System.out.println("getMustAttackEntity() returned something not in defenders.");
|
||||
c.setCurrentDefenderNumber(0);
|
||||
return defs.get(0);
|
||||
} else {
|
||||
c.setCurrentDefenderNumber(n);
|
||||
return entity;
|
||||
}
|
||||
} else {
|
||||
if (bAssault) {
|
||||
c.setCurrentDefenderNumber(0);
|
||||
} else {
|
||||
c.setCurrentDefenderNumber(n);
|
||||
return defs.get(bAssault ? 0 : n);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Getter for the field <code>attackers</code>.
|
||||
@@ -501,11 +495,11 @@ public class AiAttackController {
|
||||
|
||||
final boolean bAssault = this.doAssault(ai);
|
||||
// Determine who will be attacked
|
||||
this.chooseDefender(combat, bAssault);
|
||||
GameEntity defender = this.chooseDefender(combat, game.getCombat(), bAssault);
|
||||
List<Card> attackersLeft = new ArrayList<Card>(this.attackers);
|
||||
// Attackers that don't really have a choice
|
||||
for (final Card attacker : this.attackers) {
|
||||
if (!CombatUtil.canAttack(attacker, combat)) {
|
||||
if (!CombatUtil.canAttack(attacker, defender, combat)) {
|
||||
continue;
|
||||
}
|
||||
boolean mustAttack = false;
|
||||
@@ -521,7 +515,7 @@ public class AiAttackController {
|
||||
if (mustAttack || attacker.getSacrificeAtEOT()
|
||||
|| attacker.getController().getMustAttackEntity() != null
|
||||
|| attacker.getSVar("MustAttack").equals("True")) {
|
||||
combat.addAttacker(attacker);
|
||||
combat.addAttacker(attacker, defender);
|
||||
attackersLeft.remove(attacker);
|
||||
}
|
||||
}
|
||||
@@ -532,8 +526,8 @@ public class AiAttackController {
|
||||
System.out.println("Assault");
|
||||
CardLists.sortByPowerDesc(attackersLeft);
|
||||
for (Card attacker : attackersLeft) {
|
||||
if (CombatUtil.canAttack(attacker, combat) && this.isEffectiveAttacker(ai, attacker, combat)) {
|
||||
combat.addAttacker(attacker);
|
||||
if (CombatUtil.canAttack(attacker, defender, combat) && this.isEffectiveAttacker(ai, attacker, combat)) {
|
||||
combat.addAttacker(attacker, defender);
|
||||
}
|
||||
}
|
||||
return combat;
|
||||
@@ -566,8 +560,8 @@ public class AiAttackController {
|
||||
System.out.println("Exalted");
|
||||
this.aiAggression = 6;
|
||||
for (Card attacker : this.attackers) {
|
||||
if (CombatUtil.canAttack(attacker, combat) && this.shouldAttack(ai, attacker, this.blockers, combat)) {
|
||||
combat.addAttacker(attacker);
|
||||
if (CombatUtil.canAttack(attacker, defender, combat) && this.shouldAttack(ai, attacker, this.blockers, combat)) {
|
||||
combat.addAttacker(attacker, defender);
|
||||
return combat;
|
||||
}
|
||||
}
|
||||
@@ -780,6 +774,7 @@ public class AiAttackController {
|
||||
|
||||
attackersLeft = this.sortAttackers(attackersLeft);
|
||||
|
||||
int iDefender = combat.getDefenders().indexOf(defender);
|
||||
for (int i = 0; i < attackersLeft.size(); i++) {
|
||||
final Card attacker = attackersLeft.get(i);
|
||||
if (this.aiAggression < 5 && !attacker.hasFirstStrike() && !attacker.hasDoubleStrike()
|
||||
@@ -788,16 +783,15 @@ public class AiAttackController {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.shouldAttack(ai, attacker, this.blockers, combat)
|
||||
&& CombatUtil.canAttack(attacker, combat)) {
|
||||
combat.addAttacker(attacker);
|
||||
if (this.shouldAttack(ai, attacker, this.blockers, combat) && CombatUtil.canAttack(attacker, defender, combat)) {
|
||||
combat.addAttacker(attacker, defender);
|
||||
// check if attackers are enough to finish the attacked planeswalker
|
||||
if (combat.getCurrentDefenderNumber() > 0) {
|
||||
Card pw = (Card) combat.getDefender();
|
||||
if (iDefender > 0) {
|
||||
Card pw = (Card) defender;
|
||||
final int blockNum = this.blockers.size();
|
||||
int attackNum = 0;
|
||||
int damage = 0;
|
||||
List<Card> attacking = combat.getAttackersByDefenderSlot(combat.getCurrentDefenderNumber());
|
||||
List<Card> attacking = combat.getAttackersByDefenderSlot(iDefender);
|
||||
CardLists.sortByPowerAsc(attacking);
|
||||
for (Card atta : attacking) {
|
||||
if (attackNum >= blockNum || !CombatUtil.canBeBlocked(attacker, this.blockers)) {
|
||||
@@ -808,7 +802,8 @@ public class AiAttackController {
|
||||
}
|
||||
// if enough damage: switch to next planeswalker or player
|
||||
if (damage >= pw.getCounters(CounterType.LOYALTY)) {
|
||||
combat.setCurrentDefenderNumber(combat.getCurrentDefenderNumber() - 1);
|
||||
iDefender--;
|
||||
defender = combat.getDefenders().get(iDefender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -917,7 +917,7 @@ public class ComputerUtil {
|
||||
List<Card> attackers = ai.getOpponent().getCreaturesInPlay();
|
||||
for (Card att : attackers) {
|
||||
if (CombatUtil.canAttackNextTurn(att)) {
|
||||
combat.addAttacker(att);
|
||||
combat.addAttacker(att, att.getController().getOpponent());
|
||||
}
|
||||
}
|
||||
combat = ComputerUtilBlock.getBlockers(ai, combat, ai.getCreaturesInPlay());
|
||||
|
||||
@@ -57,7 +57,6 @@ public class Combat {
|
||||
// Defenders are the Defending Player + Each controlled Planeswalker
|
||||
private List<GameEntity> defenders = new ArrayList<GameEntity>();
|
||||
private Map<GameEntity, List<Card>> defenderMap = new HashMap<GameEntity, List<Card>>();
|
||||
private int currentDefender = 0;
|
||||
|
||||
|
||||
// This Hash keeps track of
|
||||
@@ -87,7 +86,6 @@ public class Combat {
|
||||
this.defendingDamageMap.clear();
|
||||
|
||||
this.attackingPlayer = null;
|
||||
this.currentDefender = 0;
|
||||
|
||||
this.initiatePossibleDefenders(Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().getOpponents());
|
||||
}
|
||||
@@ -125,40 +123,6 @@ public class Combat {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getDefender.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link java.lang.Object} object.
|
||||
*/
|
||||
public final GameEntity getDefender() {
|
||||
return this.defenders.get(this.currentDefender);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Setter for the field <code>currentDefender</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param def
|
||||
* a int.
|
||||
*/
|
||||
public final void setCurrentDefenderNumber(final int def) {
|
||||
this.currentDefender = def;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Setter for the field <code>currentDefender</code>.
|
||||
* </p>
|
||||
*
|
||||
* @return a int.
|
||||
*/
|
||||
public final int getCurrentDefenderNumber() {
|
||||
return this.currentDefender;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Getter for the field <code>defenders</code>.
|
||||
@@ -304,18 +268,6 @@ public class Combat {
|
||||
return this.attackerMap.containsKey(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* addAttacker.
|
||||
* </p>
|
||||
*
|
||||
* @param c
|
||||
* a {@link forge.Card} object.
|
||||
*/
|
||||
public final void addAttacker(final Card c) {
|
||||
this.addAttacker(c, defenders.get(this.currentDefender));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* addAttacker.
|
||||
|
||||
@@ -765,10 +765,9 @@ public class CombatUtil {
|
||||
* a {@link forge.game.phase.Combat} object.
|
||||
* @return a boolean.
|
||||
*/
|
||||
public static boolean canAttack(final Card c, final Combat combat) {
|
||||
|
||||
public static boolean canAttack(final Card c, final GameEntity def, final Combat combat) {
|
||||
int cntAttackers = combat.getAttackers().size();
|
||||
final GameEntity def = combat.getDefender();
|
||||
|
||||
for (final Card card : Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield)) {
|
||||
for (final String keyword : card.getKeyword()) {
|
||||
if (keyword.equals("No more than two creatures can attack each combat.") && cntAttackers > 1) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
|
||||
@@ -191,9 +192,16 @@ public enum CDock implements ICDoc {
|
||||
final PhaseHandler ph = game.getPhaseHandler();
|
||||
|
||||
if (ph.is(PhaseType.COMBAT_DECLARE_ATTACKERS, player)) {
|
||||
List<Player> defenders = player.getOpponents();
|
||||
|
||||
for (Card c : CardLists.filter(player.getCardsIn(ZoneType.Battlefield), Presets.CREATURES)) {
|
||||
if (!c.isAttacking() && CombatUtil.canAttack(c, game.getCombat())) {
|
||||
game.getCombat().addAttacker(c);
|
||||
if (c.isAttacking())
|
||||
continue;
|
||||
|
||||
for(Player defender : defenders)
|
||||
if( CombatUtil.canAttack(c, defender, game.getCombat())) {
|
||||
game.getCombat().addAttacker(c, defender);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//human.updateObservers();
|
||||
|
||||
Reference in New Issue
Block a user