mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 18:28:00 +00:00
- Initial checkin for Combat refactor.
- Introduction of AttackingBands which group Attackers, Blockers and Blocked state.
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -14405,6 +14405,7 @@ src/main/java/forge/game/ai/ComputerUtilCard.java -text
|
||||
src/main/java/forge/game/ai/ComputerUtilCombat.java -text
|
||||
src/main/java/forge/game/ai/ComputerUtilCost.java -text
|
||||
src/main/java/forge/game/ai/ComputerUtilMana.java -text
|
||||
src/main/java/forge/game/combat/AttackingBand.java -text
|
||||
src/main/java/forge/game/event/GameEvent.java -text
|
||||
src/main/java/forge/game/event/GameEventAnteCardsSelected.java -text
|
||||
src/main/java/forge/game/event/GameEventAttackersDeclared.java -text
|
||||
|
||||
@@ -199,8 +199,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
if (ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DAMAGE)) {
|
||||
return false;
|
||||
}
|
||||
List<Card> attackers = new ArrayList<Card>();
|
||||
attackers.addAll(ai.getGame().getCombat().getUnblockedAttackers());
|
||||
List<Card> attackers = ai.getGame().getCombat().getUnblockedAttackers();
|
||||
boolean lowerCMC = false;
|
||||
for (Card attacker : attackers) {
|
||||
if (attacker.getCMC() < source.getCMC()) {
|
||||
@@ -499,6 +498,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
* @return Card
|
||||
*/
|
||||
private static Card chooseCreature(final Player ai, List<Card> list) {
|
||||
// Creating a new combat for testing purposes.
|
||||
Combat combat = new Combat();
|
||||
combat.initiatePossibleDefenders(ai);
|
||||
List<Card> attackers = ai.getOpponent().getCreaturesInPlay();
|
||||
|
||||
@@ -18,6 +18,7 @@ import forge.game.ai.ComputerUtil;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
import forge.game.ai.ComputerUtilCombat;
|
||||
import forge.game.ai.ComputerUtilCost;
|
||||
import forge.game.phase.Combat;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -68,6 +69,7 @@ public class ProtectAi extends SpellAbilityAi {
|
||||
private static List<Card> getProtectCreatures(final Player ai, final SpellAbility sa) {
|
||||
final ArrayList<String> gains = AbilityUtils.getProtectionList(sa);
|
||||
final Game game = ai.getGame();
|
||||
final Combat combat = game.getCombat();
|
||||
|
||||
List<Card> list = ai.getCreaturesInPlay();
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@@ -97,9 +99,10 @@ public class ProtectAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
// is the creature in blocked and the blocker would survive
|
||||
if (game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|
||||
&& game.getCombat().isAttacking(c) && game.getCombat().isBlocked(c)
|
||||
&& ComputerUtilCombat.blockerWouldBeDestroyed(ai, game.getCombat().getBlockers(c).get(0))) {
|
||||
// TODO Potential NPE here if no blockers are actually left
|
||||
if (game.getPhaseHandler().getPhase().equals(PhaseType.COMBAT_DECLARE_BLOCKERS)
|
||||
&& combat.isAttacking(c) && game.getCombat().isBlocked(c)
|
||||
&& ComputerUtilCombat.blockerWouldBeDestroyed(ai, combat.getBlockers(c).get(0))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -386,6 +386,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
protected boolean shouldPumpCard(final Player ai, final SpellAbility sa, final Card c, final int defense, final int attack,
|
||||
final List<String> keywords) {
|
||||
final Game game = ai.getGame();
|
||||
final Combat combat = game.getCombat();
|
||||
PhaseHandler phase = game.getPhaseHandler();
|
||||
|
||||
if (!c.canBeTargetedBy(sa)) {
|
||||
@@ -437,22 +438,22 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
|
||||
// is the creature unblocked and the spell will pump its power?
|
||||
if (phase.is(PhaseType.COMBAT_DECLARE_BLOCKERS)
|
||||
&& game.getCombat().isAttacking(c) && game.getCombat().isUnblocked(c) && attack > 0) {
|
||||
&& combat.isAttacking(c) && combat.isUnblocked(c) && attack > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// is the creature blocked and the blocker would survive
|
||||
if (phase.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && attack > 0
|
||||
&& game.getCombat().isAttacking(c)
|
||||
&& game.getCombat().isBlocked(c)
|
||||
&& game.getCombat().getBlockers(c) != null
|
||||
&& !game.getCombat().getBlockers(c).isEmpty()
|
||||
&& !ComputerUtilCombat.blockerWouldBeDestroyed(ai, game.getCombat().getBlockers(c).get(0))) {
|
||||
&& combat.isAttacking(c)
|
||||
&& combat.isBlocked(c)
|
||||
&& combat.getBlockers(c) != null
|
||||
&& !combat.getBlockers(c).isEmpty()
|
||||
&& !ComputerUtilCombat.blockerWouldBeDestroyed(ai, combat.getBlockers(c).get(0))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if the life of the computer is in danger, try to pump blockers blocking Tramplers
|
||||
List<Card> blockedBy = game.getCombat().getAttackersBlockedBy(c);
|
||||
List<Card> blockedBy = combat.getAttackersBlockedBy(c);
|
||||
boolean attackerHasTrample = false;
|
||||
for (Card b : blockedBy) {
|
||||
attackerHasTrample |= b.hasKeyword("Trample");
|
||||
|
||||
@@ -91,7 +91,7 @@ public class PumpAllAi extends PumpAiBase {
|
||||
}
|
||||
totalPower += Math.min(c.getNetAttack(), power * -1);
|
||||
if (phase == PhaseType.COMBAT_DECLARE_BLOCKERS
|
||||
&& game.getCombat().getUnblockedAttackers().contains(c)) {
|
||||
&& game.getCombat().isUnblocked(c)) {
|
||||
if (ComputerUtilCombat.lifeInDanger(sa.getActivatingPlayer(), game.getCombat())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -507,10 +507,11 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
|
||||
if (sa.hasParam("Ninjutsu") || sa.hasParam("Attacking")) {
|
||||
// What should they attack?
|
||||
// TODO Ninjutsu needs to actually select the Defender, instead of auto selecting player
|
||||
List<GameEntity> defenders = game.getCombat().getDefenders();
|
||||
if (!defenders.isEmpty()) {
|
||||
game.getCombat().addAttacker(tgtC, defenders.get(0));
|
||||
game.getCombat().addUnblockedAttacker(tgtC);
|
||||
// Blockeres are already declared, set this to unblocked
|
||||
game.getCombat().addAttacker(tgtC, defenders.get(0), false);
|
||||
}
|
||||
}
|
||||
if (sa.hasParam("Tapped") || sa.hasParam("Ninjutsu")) {
|
||||
|
||||
@@ -787,7 +787,7 @@ public class AiAttackController {
|
||||
final int blockNum = this.blockers.size();
|
||||
int attackNum = 0;
|
||||
int damage = 0;
|
||||
List<Card> attacking = combat.getAttackersByDefenderSlot(iDefender);
|
||||
List<Card> attacking = combat.getAttackersOf(defender);
|
||||
CardLists.sortByPowerAsc(attacking);
|
||||
for (Card atta : attacking) {
|
||||
if (attackNum >= blockNum || !CombatUtil.canBeBlocked(attacker, this.blockers)) {
|
||||
|
||||
@@ -219,7 +219,7 @@ public class ComputerUtilCombat {
|
||||
|
||||
int damage = 0;
|
||||
|
||||
final List<Card> attackers = combat.getAttackersByDefenderSlot(0);
|
||||
final List<Card> attackers = combat.getAttackersOf(ai);
|
||||
final List<Card> unblocked = new ArrayList<Card>();
|
||||
|
||||
for (final Card attacker : attackers) {
|
||||
@@ -261,7 +261,7 @@ public class ComputerUtilCombat {
|
||||
|
||||
int poison = 0;
|
||||
|
||||
final List<Card> attackers = combat.getAttackersByDefenderSlot(0);
|
||||
final List<Card> attackers = combat.getAttackersOf(ai);
|
||||
final List<Card> unblocked = new ArrayList<Card>();
|
||||
|
||||
for (final Card attacker : attackers) {
|
||||
@@ -305,7 +305,7 @@ public class ComputerUtilCombat {
|
||||
}
|
||||
|
||||
// check for creatures that must be blocked
|
||||
final List<Card> attackers = combat.getAttackersByDefenderSlot(0);
|
||||
final List<Card> attackers = combat.getAttackersOf(ai);
|
||||
|
||||
for (final Card attacker : attackers) {
|
||||
|
||||
@@ -359,7 +359,7 @@ public class ComputerUtilCombat {
|
||||
}
|
||||
|
||||
// check for creatures that must be blocked
|
||||
final List<Card> attackers = combat.getAttackersByDefenderSlot(0);
|
||||
final List<Card> attackers = combat.getAttackersOf(ai);
|
||||
|
||||
for (final Card attacker : attackers) {
|
||||
|
||||
@@ -551,7 +551,8 @@ public class ComputerUtilCombat {
|
||||
*/
|
||||
public static boolean attackerWouldBeDestroyed(Player ai, final Card attacker) {
|
||||
final Game game = ai.getGame();
|
||||
final List<Card> blockers = game.getCombat().getBlockers(attacker);
|
||||
final Combat combat = game.getCombat();
|
||||
final List<Card> blockers = combat.getBlockers(attacker);
|
||||
|
||||
for (final Card defender : blockers) {
|
||||
if (ComputerUtilCombat.canDestroyAttacker(ai, attacker, defender, game.getCombat(), true)
|
||||
|
||||
91
src/main/java/forge/game/combat/AttackingBand.java
Normal file
91
src/main/java/forge/game/combat/AttackingBand.java
Normal file
@@ -0,0 +1,91 @@
|
||||
package forge.game.combat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.GameEntity;
|
||||
import forge.item.IPaperCard.Predicates;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class AttackingBand implements Comparable<AttackingBand> {
|
||||
|
||||
private List<Card> attackers = new ArrayList<Card>();
|
||||
private List<Card> blockers = new ArrayList<Card>();
|
||||
private GameEntity defender = null;
|
||||
private Boolean blocked = null;
|
||||
|
||||
public AttackingBand(List<Card> band, GameEntity def) {
|
||||
attackers.addAll(band);
|
||||
this.defender = def;
|
||||
}
|
||||
|
||||
public AttackingBand(Card card, GameEntity def) {
|
||||
attackers.add(card);
|
||||
this.defender = def;
|
||||
}
|
||||
|
||||
public List<Card> getAttackers() { return this.attackers; }
|
||||
public List<Card> getBlockers() { return this.blockers; }
|
||||
public GameEntity getDefender() { return this.defender; }
|
||||
|
||||
public void addAttacker(Card card) { attackers.add(card); }
|
||||
public void removeAttacker(Card card) { attackers.remove(card); }
|
||||
|
||||
public void addBlocker(Card card) { blockers.add(card); }
|
||||
public void removeBlocker(Card card) { blockers.remove(card); }
|
||||
public void setBlockers(List<Card> blockers) { this.blockers = blockers; }
|
||||
|
||||
public void setDefender(GameEntity def) { this.defender = def; }
|
||||
|
||||
public void setBlocked(boolean blocked) { this.blocked = blocked; }
|
||||
public boolean getBlocked() { return this.blocked != null && this.blocked.booleanValue(); }
|
||||
|
||||
public void calculateBlockedState() { this.blocked = !this.blockers.isEmpty(); }
|
||||
|
||||
public boolean canJoinBand(Card card) {
|
||||
// If this card has banding it can definitely join
|
||||
if (card.hasKeyword("Banding")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If all of the cards in the Band have banding, it can definitely join
|
||||
if (attackers.size() == CardLists.getKeyword(attackers, "Banding").size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO add checks for bands with other
|
||||
//List<Card> bandsWithOther = CardLists.getKeyword(attackers, "Bands with Other");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(AttackingBand o) {
|
||||
if (o == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
List<Card> compareAttackers = o.getAttackers();
|
||||
|
||||
int sizeDiff = this.attackers.size() - compareAttackers.size();
|
||||
if (sizeDiff > 0) {
|
||||
return 1;
|
||||
} else if (sizeDiff < 0) {
|
||||
return -1;
|
||||
} else if (sizeDiff == 0 && this.attackers.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this.attackers.get(0).compareTo(compareAttackers.get(0));
|
||||
}
|
||||
}
|
||||
@@ -19,11 +19,9 @@ package forge.game.phase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -33,6 +31,7 @@ import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.GameEntity;
|
||||
import forge.card.trigger.TriggerType;
|
||||
import forge.game.combat.AttackingBand;
|
||||
import forge.game.event.GameEventBlockerAssigned;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -46,34 +45,23 @@ import forge.game.zone.ZoneType;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class Combat {
|
||||
// key is attacker Card
|
||||
// value is List<Card> of blockers
|
||||
private final Map<Card, List<Card>> attackerMap = new TreeMap<Card, List<Card>>();
|
||||
private final Map<Card, List<Card>> blockerMap = new TreeMap<Card, List<Card>>();
|
||||
// List of AttackingBands
|
||||
private final List<AttackingBand> attackingBands = new ArrayList<AttackingBand>();
|
||||
// Attacker -> AttackingBand (Attackers can only be in a single band)
|
||||
private final Map<Card, AttackingBand> attackerToBandMap = new TreeMap<Card, AttackingBand>();
|
||||
// Blocker -> AttackingBands (Blockers can block multiple bands/creatures
|
||||
private final Map<Card, List<AttackingBand>> blockerToBandsMap = new TreeMap<Card, List<AttackingBand>>();
|
||||
|
||||
private final Set<Card> blocked = new HashSet<Card>();
|
||||
private final Set<Card> unblocked = new HashSet<Card>();
|
||||
private final HashMap<Card, Integer> defendingDamageMap = new HashMap<Card, Integer>();
|
||||
|
||||
// Defenders are the Defending Player + Each controlled Planeswalker
|
||||
private List<GameEntity> defenders = new ArrayList<GameEntity>();
|
||||
// Defenders are all Opposing Players + Planeswalker's Controller By Opposing Players
|
||||
private Map<GameEntity, List<Card>> defenderMap = new HashMap<GameEntity, List<Card>>();
|
||||
|
||||
|
||||
// This Hash keeps track of
|
||||
private final HashMap<Card, GameEntity> attackerToDefender = new HashMap<Card, GameEntity>();
|
||||
|
||||
private Map<Card, List<Card>> blockerDamageAssignmentOrder = new TreeMap<Card, List<Card>>();
|
||||
private Map<Card, List<Card>> attackerDamageAssignmentOrder = new TreeMap<Card, List<Card>>();
|
||||
|
||||
private Player attackingPlayer = null;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor for Combat.
|
||||
* </p>
|
||||
*/
|
||||
public Combat() {
|
||||
// Let the Begin Turn/Untap Phase Reset Combat properly
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* reset.
|
||||
@@ -81,11 +69,7 @@ public class Combat {
|
||||
*/
|
||||
public final void reset(Player playerTurn) {
|
||||
this.resetAttackers();
|
||||
this.blocked.clear();
|
||||
|
||||
this.unblocked.clear();
|
||||
this.defendingDamageMap.clear();
|
||||
|
||||
this.attackingPlayer = playerTurn;
|
||||
|
||||
this.initiatePossibleDefenders(playerTurn.getOpponents());
|
||||
@@ -100,7 +84,6 @@ public class Combat {
|
||||
* a {@link forge.game.player.Player} object.
|
||||
*/
|
||||
public final void initiatePossibleDefenders(final Iterable<Player> defenders) {
|
||||
this.defenders.clear();
|
||||
this.defenderMap.clear();
|
||||
for (Player defender : defenders) {
|
||||
fillDefenderMaps(defender);
|
||||
@@ -108,22 +91,19 @@ public class Combat {
|
||||
}
|
||||
|
||||
public final void initiatePossibleDefenders(final Player defender) {
|
||||
this.defenders.clear();
|
||||
this.defenderMap.clear();
|
||||
fillDefenderMaps(defender);
|
||||
}
|
||||
|
||||
public final boolean isCombat() {
|
||||
return !attackerMap.isEmpty();
|
||||
return !attackingBands.isEmpty();
|
||||
}
|
||||
|
||||
private void fillDefenderMaps(final Player defender) {
|
||||
this.defenders.add(defender);
|
||||
this.defenderMap.put(defender, new ArrayList<Card>());
|
||||
List<Card> planeswalkers =
|
||||
CardLists.filter(defender.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.PLANEWALKERS);
|
||||
for (final Card pw : planeswalkers) {
|
||||
this.defenders.add(pw);
|
||||
this.defenderMap.put(pw, new ArrayList<Card>());
|
||||
}
|
||||
}
|
||||
@@ -136,7 +116,7 @@ public class Combat {
|
||||
* @return a {@link java.util.ArrayList} object.
|
||||
*/
|
||||
public final List<GameEntity> getDefenders() {
|
||||
return this.defenders;
|
||||
return new ArrayList<GameEntity>(this.defenderMap.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,8 +128,8 @@ public class Combat {
|
||||
* a {@link java.util.ArrayList} object.
|
||||
*/
|
||||
public final void setDefenders(final List<GameEntity> newDef) {
|
||||
this.defenders = newDef;
|
||||
for (GameEntity entity : this.defenders) {
|
||||
this.defenderMap.clear();
|
||||
for (GameEntity entity : newDef) {
|
||||
this.defenderMap.put(entity, new ArrayList<Card>());
|
||||
}
|
||||
}
|
||||
@@ -164,7 +144,7 @@ public class Combat {
|
||||
public final List<Card> getDefendingPlaneswalkers() {
|
||||
final List<Card> pwDefending = new ArrayList<Card>();
|
||||
|
||||
for (final GameEntity o : this.defenders) {
|
||||
for (final GameEntity o : this.defenderMap.keySet()) {
|
||||
if (o instanceof Card) {
|
||||
pwDefending.add((Card) o);
|
||||
}
|
||||
@@ -196,18 +176,6 @@ public class Combat {
|
||||
return this.attackingPlayer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Getter for the field <code>defendingDamageMap</code>.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link java.util.HashMap} object.
|
||||
*/
|
||||
public final HashMap<Card, Integer> getDefendingDamageMap() {
|
||||
return this.defendingDamageMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* addDefendingDamage.
|
||||
@@ -235,11 +203,6 @@ public class Combat {
|
||||
}
|
||||
}
|
||||
|
||||
public final List<Card> getAttackersByDefenderSlot(int slot) {
|
||||
GameEntity entity = this.defenders.get(slot);
|
||||
return this.defenderMap.get(entity);
|
||||
}
|
||||
|
||||
public final List<Card> getAttackersOf(GameEntity defender) {
|
||||
return defenderMap.get(defender);
|
||||
}
|
||||
@@ -254,28 +217,39 @@ public class Combat {
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean isAttacking(final Card c) {
|
||||
return this.attackerMap.containsKey(c);
|
||||
return this.attackerToBandMap.containsKey(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* addAttacker.
|
||||
* </p>
|
||||
*
|
||||
* @param c
|
||||
* a {@link forge.Card} object.
|
||||
* @param defender
|
||||
* a GameEntity object.
|
||||
*/
|
||||
public final void addAttacker(final Card c, GameEntity defender) {
|
||||
if (!defenders.contains(defender)) {
|
||||
addAttacker(c, defender, null);
|
||||
}
|
||||
|
||||
public final void addAttacker(final Card c, GameEntity defender, AttackingBand band) {
|
||||
addAttacker(c, defender, band, null);
|
||||
}
|
||||
|
||||
public final void addAttacker(final Card c, GameEntity defender, boolean blocked) {
|
||||
addAttacker(c, defender, null, blocked);
|
||||
}
|
||||
|
||||
public final void addAttacker(final Card c, GameEntity defender, AttackingBand band, Boolean blocked) {
|
||||
if (!defenderMap.containsKey(defender)) {
|
||||
System.out.println("Trying to add Attacker " + c + " to missing defender " + defender);
|
||||
return;
|
||||
}
|
||||
|
||||
this.attackerMap.put(c, new ArrayList<Card>());
|
||||
this.attackerToDefender.put(c, defender);
|
||||
|
||||
if (band == null || !this.attackingBands.contains(band)) {
|
||||
band = new AttackingBand(c, defender);
|
||||
if (blocked != null) {
|
||||
band.setBlocked(blocked.booleanValue());
|
||||
}
|
||||
this.attackingBands.add(band);
|
||||
} else {
|
||||
band.addAttacker(c);
|
||||
}
|
||||
// Attacker -> Defender and Defender -> Attacker map to Bands?
|
||||
this.defenderMap.get(defender).add(c);
|
||||
this.attackerToBandMap.put(c, band);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,7 +262,7 @@ public class Combat {
|
||||
* @return a {@link java.lang.Object} object.
|
||||
*/
|
||||
public final GameEntity getDefenderByAttacker(final Card c) {
|
||||
return this.attackerToDefender.get(c);
|
||||
return this.attackerToBandMap.get(c).getDefender();
|
||||
}
|
||||
|
||||
public final Player getDefenderPlayerByAttacker(final Card c) {
|
||||
@@ -307,26 +281,30 @@ public class Combat {
|
||||
}
|
||||
|
||||
public final GameEntity getDefendingEntity(final Card c) {
|
||||
GameEntity defender = this.attackerToDefender.get(c);
|
||||
|
||||
if (this.defenders.contains(defender)) {
|
||||
GameEntity defender = this.getDefenderByAttacker(c);
|
||||
if (this.defenderMap.containsKey(defender)) {
|
||||
return defender;
|
||||
}
|
||||
|
||||
System.out.println("Attacker " + c + " missing defender " + defender);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public final AttackingBand getBandByAttacker(final Card c) {
|
||||
return this.attackerToBandMap.get(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* resetAttackers.
|
||||
* </p>
|
||||
*/
|
||||
public final void resetAttackers() {
|
||||
this.attackerMap.clear();
|
||||
this.attackerToDefender.clear();
|
||||
this.blockerMap.clear();
|
||||
this.attackingBands.clear();
|
||||
this.blockerToBandsMap.clear();
|
||||
this.attackerToBandMap.clear();
|
||||
this.blockerDamageAssignmentOrder.clear();
|
||||
this.attackerDamageAssignmentOrder.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,28 +314,24 @@ public class Combat {
|
||||
*
|
||||
* @return an array of {@link forge.Card} objects.
|
||||
*/
|
||||
public final List<Card> getAttackers() {
|
||||
return new ArrayList<Card>(this.attackerMap.keySet());
|
||||
public final List<AttackingBand> getAttackingBands() {
|
||||
return attackingBands;
|
||||
} // getAttackers()
|
||||
|
||||
public final List<Card> getAttackers() {
|
||||
List<Card> attackers = new ArrayList<Card>();
|
||||
for(AttackingBand band : attackingBands) {
|
||||
attackers.addAll(band.getAttackers());
|
||||
}
|
||||
return attackers;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* isBlocked.
|
||||
* </p>
|
||||
*
|
||||
* @param attacker
|
||||
* a {@link forge.Card} object.
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean isBlocked(final Card attacker) {
|
||||
return this.blocked.contains(attacker);
|
||||
return this.attackerToBandMap.get(attacker).getBlocked();
|
||||
}
|
||||
|
||||
public final void setBlocked(final Card attacker) {
|
||||
if (!this.blocked.contains(attacker)) {
|
||||
this.blocked.add(attacker);
|
||||
this.unblocked.remove(attacker);
|
||||
}
|
||||
this.attackerToBandMap.get(attacker).setBlocked(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -371,24 +345,23 @@ public class Combat {
|
||||
* a {@link forge.Card} object.
|
||||
*/
|
||||
public final void addBlocker(final Card attacker, final Card blocker) {
|
||||
this.blocked.add(attacker);
|
||||
this.attackerMap.get(attacker).add(blocker);
|
||||
if (!this.blockerMap.containsKey(blocker)) {
|
||||
this.blockerMap.put(blocker, Lists.newArrayList(attacker));
|
||||
AttackingBand band = this.attackerToBandMap.get(attacker);
|
||||
band.addBlocker(blocker);
|
||||
|
||||
if (!this.blockerToBandsMap.containsKey(blocker)) {
|
||||
this.blockerToBandsMap.put(blocker, Lists.newArrayList(band));
|
||||
} else {
|
||||
this.blockerMap.get(blocker).add(attacker);
|
||||
this.blockerToBandsMap.get(blocker).add(band);
|
||||
}
|
||||
attacker.getGame().fireEvent(new GameEventBlockerAssigned());
|
||||
}
|
||||
|
||||
public final void removeBlockAssignment(final Card attacker, final Card blocker) {
|
||||
this.attackerMap.get(attacker).remove(blocker);
|
||||
this.blockerMap.get(blocker).remove(attacker);
|
||||
if (this.attackerMap.get(attacker).isEmpty()) {
|
||||
this.blocked.remove(attacker);
|
||||
}
|
||||
if (this.blockerMap.get(blocker).isEmpty()) {
|
||||
this.blockerMap.remove(blocker);
|
||||
AttackingBand band = this.attackerToBandMap.get(attacker);
|
||||
band.removeBlocker(blocker);
|
||||
this.blockerToBandsMap.get(blocker).remove(attacker);
|
||||
if (this.blockerToBandsMap.get(blocker).isEmpty()) {
|
||||
this.blockerToBandsMap.remove(blocker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,17 +374,12 @@ public class Combat {
|
||||
* a {@link forge.Card} object.
|
||||
*/
|
||||
public final void undoBlockingAssignment(final Card blocker) {
|
||||
final List<Card> att = this.getAttackers();
|
||||
for (final Card attacker : att) {
|
||||
if (this.getBlockers(attacker).contains(blocker)) {
|
||||
this.getBlockingAttackerList(attacker).remove(blocker);
|
||||
if (this.getBlockers(attacker).isEmpty()) {
|
||||
this.blocked.remove(attacker);
|
||||
}
|
||||
}
|
||||
final List<AttackingBand> att = this.blockerToBandsMap.get(blocker);
|
||||
for (final AttackingBand band : att) {
|
||||
band.removeBlocker(blocker);
|
||||
}
|
||||
this.blockerMap.remove(blocker);
|
||||
} // undoBlockingAssignment(Card)
|
||||
this.blockerToBandsMap.remove(blocker);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -422,25 +390,37 @@ public class Combat {
|
||||
*/
|
||||
public final List<Card> getAllBlockers() {
|
||||
final List<Card> block = new ArrayList<Card>();
|
||||
block.addAll(blockerMap.keySet());
|
||||
block.addAll(blockerToBandsMap.keySet());
|
||||
|
||||
return block;
|
||||
} // getAllBlockers()
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getBlockers.
|
||||
* </p>
|
||||
*
|
||||
* @param attacker
|
||||
* a {@link forge.Card} object.
|
||||
* @return a {@link forge.CardList} object.
|
||||
*/
|
||||
public final List<Card> getBlockers(final Card attacker) {
|
||||
if (this.getBlockingAttackerList(attacker) == null) {
|
||||
public final List<Card> getBlockers(final AttackingBand band) {
|
||||
List<Card> list = band.getBlockers();
|
||||
if (list == null) {
|
||||
return new ArrayList<Card>();
|
||||
} else {
|
||||
return new ArrayList<Card>(this.getBlockingAttackerList(attacker));
|
||||
return new ArrayList<Card>(list);
|
||||
}
|
||||
}
|
||||
|
||||
public final List<Card> getBlockers(final Card card) {
|
||||
return getBlockers(card, false);
|
||||
}
|
||||
|
||||
public final List<Card> getBlockers(final Card card, boolean ordered) {
|
||||
// If requesting the ordered blocking lsit pass true, directly.
|
||||
List<Card> list = null;
|
||||
if (ordered) {
|
||||
list = this.attackerDamageAssignmentOrder.containsKey(card) ? this.attackerDamageAssignmentOrder.get(card) : null;
|
||||
} else {
|
||||
list = this.getBandByAttacker(card).getBlockers();
|
||||
}
|
||||
|
||||
if (list == null) {
|
||||
return new ArrayList<Card>();
|
||||
} else {
|
||||
return new ArrayList<Card>(list);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,26 +434,16 @@ public class Combat {
|
||||
* @return a {@link forge.Card} object.
|
||||
*/
|
||||
public final List<Card> getAttackersBlockedBy(final Card blocker) {
|
||||
if (blockerMap.containsKey(blocker)) {
|
||||
return blockerMap.get(blocker);
|
||||
List<Card> blocked = new ArrayList<Card>();
|
||||
|
||||
if (blockerToBandsMap.containsKey(blocker)) {
|
||||
for(AttackingBand band : blockerToBandsMap.get(blocker)) {
|
||||
blocked.addAll(band.getAttackers());
|
||||
}
|
||||
}
|
||||
return new ArrayList<Card>();
|
||||
return blocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getList.
|
||||
* </p>
|
||||
*
|
||||
* @param attacker
|
||||
* a {@link forge.Card} object.
|
||||
* @return a {@link forge.CardList} object.
|
||||
*/
|
||||
private List<Card> getBlockingAttackerList(final Card attacker) {
|
||||
return this.attackerMap.get(attacker);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getDefendingPlayer.
|
||||
@@ -499,7 +469,8 @@ public class Combat {
|
||||
return players;
|
||||
}
|
||||
|
||||
// return all defenders
|
||||
// Can't figure out who it's related to... just return all???
|
||||
// return all defending players
|
||||
List<GameEntity> defenders = this.getDefenders();
|
||||
for (GameEntity ge : defenders) {
|
||||
if (ge instanceof Player) {
|
||||
@@ -509,56 +480,42 @@ public class Combat {
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* setBlockerList.
|
||||
* </p>
|
||||
*
|
||||
* @param attacker
|
||||
* a {@link forge.Card} object.
|
||||
* @param blockers
|
||||
* a {@link forge.CardList} object.
|
||||
*/
|
||||
public void setBlockerList(final Card attacker, final List<Card> blockers) {
|
||||
this.attackerMap.put(attacker, blockers);
|
||||
public void setAttackerDamageAssignmentOrder(final Card attacker, final List<Card> blockers) {
|
||||
this.attackerDamageAssignmentOrder.put(attacker, blockers);
|
||||
}
|
||||
|
||||
public void setAttackersBlockedByList(final Card blocker, final List<Card> attackers) {
|
||||
this.blockerMap.put(blocker, attackers);
|
||||
public void setBlockerDamageAssignmentOrder(final Card blocker, final List<Card> attackers) {
|
||||
this.blockerDamageAssignmentOrder.put(blocker, attackers);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* removeFromCombat.
|
||||
* </p>
|
||||
*
|
||||
* @param c
|
||||
* a {@link forge.Card} object.
|
||||
*/
|
||||
public final void removeFromCombat(final Card c) {
|
||||
// todo(sol) add some more solid error checking in here
|
||||
// is card an attacker?
|
||||
if (this.attackerMap.containsKey(c)) {
|
||||
// Keep track of all of the different maps
|
||||
List<Card> blockers = this.attackerMap.get(c);
|
||||
this.attackerMap.remove(c);
|
||||
if (this.attackerToBandMap.containsKey(c)) {
|
||||
// Soooo many maps to keep track of
|
||||
AttackingBand band = this.attackerToBandMap.get(c);
|
||||
band.removeAttacker(c);
|
||||
this.attackerToBandMap.remove(c);
|
||||
this.attackerDamageAssignmentOrder.remove(c);
|
||||
|
||||
List<Card> blockers = band.getBlockers();
|
||||
for (Card b : blockers) {
|
||||
this.blockerMap.get(b).remove(c);
|
||||
if (band.getAttackers().isEmpty()) {
|
||||
this.blockerToBandsMap.get(b).remove(c);
|
||||
}
|
||||
// Clear removed attacker from assignment order
|
||||
this.blockerDamageAssignmentOrder.get(b).remove(c);
|
||||
}
|
||||
|
||||
// Keep track of all of the different maps
|
||||
GameEntity entity = this.attackerToDefender.get(c);
|
||||
this.attackerToDefender.remove(c);
|
||||
this.defenderMap.get(entity).remove(c);
|
||||
} else if (this.blockerMap.containsKey(c)) { // card is a blocker
|
||||
List<Card> attackers = this.blockerMap.get(c);
|
||||
this.defenderMap.get(band.getDefender()).remove(c);
|
||||
} else if (this.blockerDamageAssignmentOrder.containsKey(c)) { // card is a blocker
|
||||
List<AttackingBand> attackers = this.blockerToBandsMap.get(c);
|
||||
|
||||
boolean stillDeclaring = c.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS);
|
||||
this.blockerMap.remove(c);
|
||||
for (Card a : attackers) {
|
||||
this.attackerMap.get(a).remove(c);
|
||||
if (stillDeclaring && this.attackerMap.get(a).isEmpty()) {
|
||||
this.blocked.remove(a);
|
||||
this.blockerToBandsMap.remove(c);
|
||||
this.blockerDamageAssignmentOrder.remove(c);
|
||||
for (AttackingBand a : attackers) {
|
||||
a.removeBlocker(c);
|
||||
for(Card atk : a.getAttackers()) {
|
||||
this.attackerDamageAssignmentOrder.get(atk).remove(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -571,7 +528,9 @@ public class Combat {
|
||||
*/
|
||||
public final void removeAbsentCombatants() {
|
||||
final List<Card> all = new ArrayList<Card>();
|
||||
all.addAll(this.getAttackers());
|
||||
for(AttackingBand band : this.getAttackingBands()) {
|
||||
all.addAll(band.getAttackers());
|
||||
}
|
||||
all.addAll(this.getAllBlockers());
|
||||
|
||||
for (int i = 0; i < all.size(); i++) {
|
||||
@@ -587,21 +546,18 @@ public class Combat {
|
||||
* </p>
|
||||
*/
|
||||
public final void setUnblockedAttackers() {
|
||||
final List<Card> attacking = this.getAttackers();
|
||||
|
||||
for (final Card attacker : attacking) {
|
||||
final List<Card> block = this.getBlockers(attacker);
|
||||
|
||||
if (block.isEmpty()) {
|
||||
// this damage is assigned to a player by setPlayerDamage()
|
||||
this.addUnblockedAttacker(attacker);
|
||||
|
||||
// Run Unblocked Trigger
|
||||
final HashMap<String, Object> runParams = new HashMap<String, Object>();
|
||||
runParams.put("Attacker", attacker);
|
||||
runParams.put("Defender",this.getDefenderByAttacker(attacker));
|
||||
attacker.getGame().getTriggerHandler().runTrigger(TriggerType.AttackerUnblocked, runParams, false);
|
||||
final List<AttackingBand> attacking = this.getAttackingBands();
|
||||
for (final AttackingBand band : attacking) {
|
||||
band.calculateBlockedState();
|
||||
|
||||
if (band.getBlocked()) {
|
||||
for (Card attacker : band.getAttackers()) {
|
||||
// Run Unblocked Trigger
|
||||
final HashMap<String, Object> runParams = new HashMap<String, Object>();
|
||||
runParams.put("Attacker", attacker);
|
||||
runParams.put("Defender",this.getDefenderByAttacker(attacker));
|
||||
attacker.getGame().getTriggerHandler().runTrigger(TriggerType.AttackerUnblocked, runParams, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -612,13 +568,25 @@ public class Combat {
|
||||
|
||||
for (final Card blocker : blockers) {
|
||||
if (blocker.hasDoubleStrike() || blocker.hasFirstStrike() == firstStrikeDamage) {
|
||||
List<Card> attackers = this.getAttackersBlockedBy(blocker);
|
||||
List<Card> attackers = this.blockerDamageAssignmentOrder.get(blocker);
|
||||
|
||||
final int damage = blocker.getNetCombatDamage();
|
||||
|
||||
if (!attackers.isEmpty()) {
|
||||
Player attackingPlayer = this.getAttackingPlayer();
|
||||
Player assigningPlayer = blocker.getController();
|
||||
|
||||
List<Card> bandingAttackers = CardLists.getKeyword(attackers, "Banding");
|
||||
if (!bandingAttackers.isEmpty()) {
|
||||
assigningPlayer = attackingPlayer;
|
||||
} else {
|
||||
// TODO Get each bands with other creature
|
||||
// Check if any other valid creatures matches the bands with other
|
||||
// assigningPlayer = blockingBand.get(0).getController();
|
||||
}
|
||||
|
||||
assignedDamage = true;
|
||||
Map<Card, Integer> map = blocker.getController().getController().assignCombatDamage(blocker, attackers, damage, null, false);
|
||||
Map<Card, Integer> map = blocker.getController().getController().assignCombatDamage(blocker, attackers, damage, null, assigningPlayer != blocker.getController());
|
||||
for (Entry<Card, Integer> dt : map.entrySet()) {
|
||||
dt.getKey().addAssignedDamage(dt.getValue(), blocker);
|
||||
dt.getKey().updateObservers();
|
||||
@@ -646,31 +614,32 @@ public class Combat {
|
||||
if (damageDealt <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AttackingBand band = this.getBandByAttacker(attacker);
|
||||
|
||||
boolean trampler = attacker.hasKeyword("Trample");
|
||||
blockers = this.getBlockers(attacker);
|
||||
blockers = this.attackerDamageAssignmentOrder.get(attacker);
|
||||
assignedDamage = true;
|
||||
// If the Attacker is unblocked, or it's a trampler and has 0 blockers, deal damage to defender
|
||||
if (blockers.isEmpty()) {
|
||||
if (trampler || this.isUnblocked(attacker)) {
|
||||
if (trampler || !band.getBlocked()) {
|
||||
this.addDefendingDamage(damageDealt, attacker);
|
||||
} else {
|
||||
// Else no damage can be dealt anywhere
|
||||
continue;
|
||||
}
|
||||
} // No damage happens if blocked but no blockers left
|
||||
} else {
|
||||
GameEntity defender = this.getDefenderByAttacker(attacker);
|
||||
GameEntity defender = band.getDefender();
|
||||
Player assigningPlayer = this.getAttackingPlayer();
|
||||
// Defensive Formation is very similar to Banding with Blockers
|
||||
// It allows the defending player to assign damage instead of the attacking player
|
||||
if (defender instanceof Player && defender.hasKeyword("You assign combat damage of each creature attacking you.")) {
|
||||
assigningPlayer = (Player)defender;
|
||||
}
|
||||
|
||||
if (!assigningPlayer.equals(defender)) {
|
||||
} else {
|
||||
List<Card> blockingBand = CardLists.getKeyword(blockers, "Banding");
|
||||
if (!blockingBand.isEmpty()) {
|
||||
assigningPlayer = blockingBand.get(0).getController();
|
||||
} else {
|
||||
// TODO Get each bands with other creature
|
||||
// Check if any other valid creatures matches the bands with other
|
||||
// assigningPlayer = blockingBand.get(0).getController();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,7 +673,7 @@ public class Combat {
|
||||
public void dealAssignedDamage() {
|
||||
// This function handles both Regular and First Strike combat assignment
|
||||
|
||||
final HashMap<Card, Integer> defMap = this.getDefendingDamageMap();
|
||||
final HashMap<Card, Integer> defMap = this.defendingDamageMap;
|
||||
final HashMap<GameEntity, List<Card>> wasDamaged = new HashMap<GameEntity, List<Card>>();
|
||||
|
||||
for (final Entry<Card, Integer> entry : defMap.entrySet()) {
|
||||
@@ -784,7 +753,7 @@ public class Combat {
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean isUnblocked(final Card att) {
|
||||
return this.unblocked.contains(att);
|
||||
return !this.attackerToBandMap.get(att).getBlocked();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -795,56 +764,26 @@ public class Combat {
|
||||
* @return an array of {@link forge.Card} objects.
|
||||
*/
|
||||
public final List<Card> getUnblockedAttackers() {
|
||||
final List<Card> out = new ArrayList<Card>();
|
||||
for (Card c : this.unblocked) {
|
||||
if (!c.hasFirstStrike()) {
|
||||
out.add(c);
|
||||
ArrayList<Card> unblocked = new ArrayList<Card>();
|
||||
for (AttackingBand band : this.attackingBands) {
|
||||
if (!band.getBlocked()) {
|
||||
unblocked.addAll(band.getAttackers());
|
||||
}
|
||||
}
|
||||
return out;
|
||||
} // getUnblockedAttackers()
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getUnblockedFirstStrikeAttackers.
|
||||
* </p>
|
||||
*
|
||||
* @return an array of {@link forge.Card} objects.
|
||||
*/
|
||||
public final List<Card> getUnblockedFirstStrikeAttackers() {
|
||||
final List<Card> out = new ArrayList<Card>();
|
||||
for (Card c : this.unblocked) { // only add creatures without firstStrike to this
|
||||
if (c.hasFirstStrike() || c.hasDoubleStrike()) {
|
||||
out.add(c);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
} // getUnblockedAttackers()
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* addUnblockedAttacker.
|
||||
* </p>
|
||||
*
|
||||
* @param c
|
||||
* a {@link forge.Card} object.
|
||||
*/
|
||||
public final void addUnblockedAttacker(final Card c) {
|
||||
if (!this.unblocked.contains(c)) {
|
||||
this.unblocked.add(c);
|
||||
}
|
||||
return unblocked;
|
||||
}
|
||||
|
||||
public boolean isPlayerAttacked(Player priority) {
|
||||
|
||||
// System.out.println("\nWho attacks attacks " + priority.toString() + "?");
|
||||
for (Card c : getAttackers()) {
|
||||
|
||||
if (priority.equals(getDefenderPlayerByAttacker(c))) {
|
||||
return true;
|
||||
for(GameEntity defender : defenderMap.keySet()) {
|
||||
if ((defender instanceof Player && priority.equals(defender)) ||
|
||||
(defender instanceof Card && priority.equals(((Card)defender).getController()))) {
|
||||
List<Card> attackers = defenderMap.get(priority);
|
||||
if (attackers != null && !attackers.isEmpty())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // Class Combat
|
||||
|
||||
@@ -46,6 +46,7 @@ import forge.card.staticability.StaticAbility;
|
||||
import forge.card.trigger.TriggerType;
|
||||
import forge.game.Game;
|
||||
import forge.game.GlobalRuleChange;
|
||||
import forge.game.combat.AttackingBand;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerController.ManaPaymentPurpose;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -179,11 +180,10 @@ public class CombatUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (attacker.hasKeyword("CARDNAME can't be blocked by more than one creature.")
|
||||
&& (combat.getBlockers(attacker).size() > 0)) {
|
||||
if (attacker.hasKeyword("CARDNAME can't be blocked by more than one creature.") &&
|
||||
!combat.getBlockers(attacker).isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return CombatUtil.canBeBlocked(attacker);
|
||||
}
|
||||
|
||||
@@ -425,33 +425,43 @@ public class CombatUtil {
|
||||
private static void orderMultipleBlockers(final Combat combat) {
|
||||
// If there are multiple blockers, the Attacker declares the Assignment Order
|
||||
final Player player = combat.getAttackingPlayer();
|
||||
for (final Card attacker : combat.getAttackers()) {
|
||||
List<Card> blockers = combat.getBlockers(attacker);
|
||||
if (blockers.size() <= 1) {
|
||||
for (final AttackingBand band : combat.getAttackingBands()) {
|
||||
List<Card> attackers = band.getAttackers();
|
||||
if (attackers.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
List<Card> orderedBlockers = player.getController().orderBlockers(attacker, blockers);
|
||||
combat.setBlockerList(attacker, orderedBlockers);
|
||||
}
|
||||
|
||||
// Refresh Combat Panel
|
||||
List<Card> blockers = combat.getBlockers(band);
|
||||
for(Card attacker : attackers) {
|
||||
List<Card> orderedBlockers = null;
|
||||
if (blockers.size() <= 1) {
|
||||
orderedBlockers = blockers;
|
||||
} else {
|
||||
// Damage Ordering needs to take cards like Melee into account, is that happening?
|
||||
orderedBlockers = player.getController().orderBlockers(attacker, blockers);
|
||||
}
|
||||
combat.setAttackerDamageAssignmentOrder(attacker, orderedBlockers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void orderBlockingMultipleAttackers(final Combat combat) {
|
||||
// If there are multiple blockers, the Attacker declares the Assignment Order
|
||||
for (final Card blocker : combat.getAllBlockers()) {
|
||||
List<Card> attackers = combat.getAttackersBlockedBy(blocker);
|
||||
List<Card> orderedAttacker = null;
|
||||
|
||||
if (attackers.size() <= 1) {
|
||||
continue;
|
||||
orderedAttacker = attackers;
|
||||
} else {
|
||||
// Damage Ordering needs to take cards like Melee into account, is that happening?
|
||||
orderedAttacker = blocker.getController().getController().orderAttackers(blocker, attackers);
|
||||
}
|
||||
|
||||
List<Card> orderedAttacker = blocker.getController().getController().orderAttackers(blocker, attackers);
|
||||
combat.setAttackersBlockedByList(blocker, orderedAttacker);
|
||||
combat.setBlockerDamageAssignmentOrder(blocker, orderedAttacker);
|
||||
}
|
||||
// Refresh Combat Panel
|
||||
}
|
||||
|
||||
|
||||
// can the blocker block an attacker with a lure effect?
|
||||
/**
|
||||
* <p>
|
||||
@@ -465,7 +475,6 @@ public class CombatUtil {
|
||||
* @return a boolean.
|
||||
*/
|
||||
public static boolean mustBlockAnAttacker(final Card blocker, final Combat combat) {
|
||||
|
||||
if (blocker == null || combat == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -1108,7 +1117,7 @@ public class CombatUtil {
|
||||
* a {@link forge.Card} object.
|
||||
*/
|
||||
public static void checkBlockedAttackers(final Game game, final Card a, final List<Card> blockers) {
|
||||
|
||||
final Combat combat = game.getCombat();
|
||||
if (blockers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -1135,7 +1144,7 @@ public class CombatUtil {
|
||||
if (m.find()) {
|
||||
final String[] k = keyword.split(" ");
|
||||
final int magnitude = Integer.valueOf(k[1]);
|
||||
final int numBlockers = game.getCombat().getBlockers(a).size();
|
||||
final int numBlockers = combat.getBlockers(a).size();
|
||||
if (numBlockers > 1) {
|
||||
CombatUtil.executeRampageAbility(game, a, magnitude, numBlockers);
|
||||
}
|
||||
@@ -1253,60 +1262,6 @@ public class CombatUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public static void souverignsOfAlara2ndAbility(final Game game, final Card attacker) {
|
||||
final Ability ability4 = new Ability(attacker, ManaCost.ZERO) {
|
||||
@Override
|
||||
public void resolve() {
|
||||
List<Card> enchantments =
|
||||
CardLists.filter(attacker.getController().getCardsIn(ZoneType.Library), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
if (attacker.hasKeyword("Protection from enchantments")
|
||||
|| (attacker.hasKeyword("Protection from everything"))) {
|
||||
return false;
|
||||
}
|
||||
return (c.isEnchantment() && c.hasKeyword("Enchant creature") && !CardFactoryUtil
|
||||
.hasProtectionFrom(c, attacker));
|
||||
}
|
||||
});
|
||||
final Player player = attacker.getController();
|
||||
Card enchantment = null;
|
||||
if (player.isHuman()) {
|
||||
final Card[] target = new Card[enchantments.size()];
|
||||
for (int j = 0; j < enchantments.size(); j++) {
|
||||
final Card crd = enchantments.get(j);
|
||||
target[j] = crd;
|
||||
}
|
||||
final Object check = GuiChoose.oneOrNone(
|
||||
"Select enchantment to enchant exalted creature", target);
|
||||
if (check != null) {
|
||||
enchantment = ((Card) check);
|
||||
}
|
||||
} else {
|
||||
enchantment = ComputerUtilCard.getBestEnchantmentAI(enchantments, this, false);
|
||||
}
|
||||
if ((enchantment != null) && attacker.isInPlay()) {
|
||||
game.getAction().changeZone(game.getZoneOf(enchantment),
|
||||
enchantment.getOwner().getZone(ZoneType.Battlefield), enchantment, null);
|
||||
enchantment.enchantEntity(attacker);
|
||||
}
|
||||
attacker.getController().shuffle();
|
||||
} // resolve
|
||||
}; // ability4
|
||||
|
||||
final StringBuilder sb4 = new StringBuilder();
|
||||
sb4.append(attacker).append(
|
||||
" - (Exalted) searches library for an Aura card that could enchant that creature, ");
|
||||
sb4.append("put it onto the battlefield attached to that creature, then shuffles library.");
|
||||
ability4.setDescription(sb4.toString());
|
||||
ability4.setStackDescription(sb4.toString());
|
||||
|
||||
game.getStack().addSimultaneousStackEntry(ability4);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* executes Rampage abilities for a given card.
|
||||
* @param game
|
||||
|
||||
@@ -91,7 +91,7 @@ public enum CCombat implements ICDoc {
|
||||
display.append(" > ");
|
||||
display.append(combatantToString(c)).append("\n");
|
||||
|
||||
List<Card> blockers = combat.getBlockers(c);
|
||||
List<Card> blockers = combat.getBlockers(c, true);
|
||||
|
||||
// loop through blockers
|
||||
for (final Card element : blockers) {
|
||||
|
||||
Reference in New Issue
Block a user