From bab2bfa8af55f3cc1f0c2fd9aa2d54a61b696931 Mon Sep 17 00:00:00 2001 From: Sol Date: Mon, 10 Sep 2012 00:39:36 +0000 Subject: [PATCH] - Lots of Combat simplification. Including maps of Attackers Block By a Blocker, and Attackers attacking a Defender for simpler access. - Adding support for Block Any Creatures and Block Additional Creatures --- .gitattributes | 2 + res/cardsfolder/f/foriysian_brigade.txt | 11 ++ res/cardsfolder/w/wall_of_glare.txt | 12 ++ src/main/java/forge/Card.java | 4 +- .../abilityfactory/AbilityFactoryPump.java | 22 ++- .../java/forge/control/input/InputBlock.java | 37 +++- src/main/java/forge/game/phase/Combat.java | 159 ++++++++++-------- .../java/forge/game/phase/CombatUtil.java | 72 +++++++- .../forge/game/player/ComputerAIGeneral.java | 2 +- .../forge/game/player/ComputerUtilAttack.java | 2 +- .../forge/game/player/ComputerUtilBlock.java | 13 ++ src/main/java/forge/game/player/Player.java | 16 +- 12 files changed, 251 insertions(+), 101 deletions(-) create mode 100644 res/cardsfolder/f/foriysian_brigade.txt create mode 100644 res/cardsfolder/w/wall_of_glare.txt diff --git a/.gitattributes b/.gitattributes index 73b28c82cb5..be060d74960 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3431,6 +3431,7 @@ res/cardsfolder/f/forget.txt -text res/cardsfolder/f/forgotten_ancient.txt svneol=native#text/plain res/cardsfolder/f/forgotten_cave.txt svneol=native#text/plain res/cardsfolder/f/forgotten_harvest.txt svneol=native#text/plain +res/cardsfolder/f/foriysian_brigade.txt -text res/cardsfolder/f/fork.txt svneol=native#text/plain res/cardsfolder/f/forked_bolt.txt svneol=native#text/plain res/cardsfolder/f/forked_branch_garami.txt svneol=native#text/plain @@ -10612,6 +10613,7 @@ res/cardsfolder/w/wall_of_essence.txt svneol=native#text/plain res/cardsfolder/w/wall_of_faith.txt svneol=native#text/plain res/cardsfolder/w/wall_of_fire.txt svneol=native#text/plain res/cardsfolder/w/wall_of_frost.txt svneol=native#text/plain +res/cardsfolder/w/wall_of_glare.txt -text res/cardsfolder/w/wall_of_granite.txt svneol=native#text/plain res/cardsfolder/w/wall_of_heat.txt svneol=native#text/plain res/cardsfolder/w/wall_of_hope.txt svneol=native#text/plain diff --git a/res/cardsfolder/f/foriysian_brigade.txt b/res/cardsfolder/f/foriysian_brigade.txt new file mode 100644 index 00000000000..2ab604e4c2b --- /dev/null +++ b/res/cardsfolder/f/foriysian_brigade.txt @@ -0,0 +1,11 @@ +Name:Foriysian Brigade +ManaCost:3 W +Types:Creature Human Soldier +Text:no text +PT:2/4 +K:CARDNAME can block an additional creature. +SVar:Rarity:Uncommon +SVar:Picture:http://www.wizards.com/global/images/magic/general/foriysian_brigade.jpg +SetInfo:WTH|Uncommon|http://magiccards.info/scans/en/wl/130.jpg +Oracle:Foriysian Brigade can block an additional creature. +End \ No newline at end of file diff --git a/res/cardsfolder/w/wall_of_glare.txt b/res/cardsfolder/w/wall_of_glare.txt new file mode 100644 index 00000000000..4882346afdf --- /dev/null +++ b/res/cardsfolder/w/wall_of_glare.txt @@ -0,0 +1,12 @@ +Name:Wall of Glare +ManaCost:1 W +Types:Creature Wall +Text:no text +PT:0/5 +K:Defender +K:CARDNAME can block any number of creatures. +SVar:Rarity:Common +SVar:Picture:http://www.wizards.com/global/images/magic/general/wall_of_glare.jpg +SetInfo:UDS|Common|http://magiccards.info/scans/en/ud/25.jpg +Oracle:Defender (This creature can't attack.)\nWall of Glare can block any number of creatures. +End \ No newline at end of file diff --git a/src/main/java/forge/Card.java b/src/main/java/forge/Card.java index 6d18d855664..904aea9774f 100644 --- a/src/main/java/forge/Card.java +++ b/src/main/java/forge/Card.java @@ -7526,7 +7526,7 @@ public class Card extends GameEntity implements Comparable { * @return a boolean. */ public final boolean isBlocking(final Card attacker) { - return attacker.equals(AllZone.getCombat().getAttackerBlockedBy(this)); + return AllZone.getCombat().getAttackersBlockedBy(this).contains(attacker); } /** @@ -7539,7 +7539,7 @@ public class Card extends GameEntity implements Comparable { * @return a boolean. */ public final boolean isBlockedBy(final Card blocker) { - return this.equals(AllZone.getCombat().getAttackerBlockedBy(blocker)); + return AllZone.getCombat().getAttackersBlockedBy(blocker).contains(this); } // ///////////////////////// diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryPump.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryPump.java index 6f6e0be59bb..390949218c2 100644 --- a/src/main/java/forge/card/abilityfactory/AbilityFactoryPump.java +++ b/src/main/java/forge/card/abilityfactory/AbilityFactoryPump.java @@ -595,10 +595,16 @@ public class AbilityFactoryPump { // is the creature blocking and unable to destroy the attacker // or would be destroyed itself? - if (c.isBlocking() - && (CombatUtil.blockerWouldBeDestroyed(c) || !CombatUtil.attackerWouldBeDestroyed(AllZone - .getCombat().getAttackerBlockedBy(c)))) { - return true; + if (c.isBlocking()) { + if (CombatUtil.blockerWouldBeDestroyed(c)) { + return true; + } + CardList blockedBy = AllZone.getCombat().getAttackersBlockedBy(c); + // For now, Only care the first creature blocked by a card. + // TODO Add in better BlockAdditional support + if (blockedBy.size() != 0 && !CombatUtil.attackerWouldBeDestroyed(blockedBy.get(0))) { + return true; + } } // is the creature unblocked and the spell will pump its power? @@ -617,11 +623,17 @@ public class AbilityFactoryPump { } // if the life of the computer is in danger, try to pump blockers blocking Tramplers + CardList blockedBy = AllZone.getCombat().getAttackersBlockedBy(c); + boolean attackerHasTrample = false; + for(Card b : blockedBy) { + attackerHasTrample |= b.hasKeyword("Trample"); + } + if (phase.getPhase().equals(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY) && phase.isPlayerTurn(AllZone.getHumanPlayer()) && c.isBlocking() && defense > 0 - && AllZone.getCombat().getAttackerBlockedBy(c).hasKeyword("Trample") + && attackerHasTrample && (sa.isAbility() || CombatUtil.lifeInDanger(AllZone.getCombat()))) { return true; } diff --git a/src/main/java/forge/control/input/InputBlock.java b/src/main/java/forge/control/input/InputBlock.java index 984e24f7b9b..da4782382dd 100644 --- a/src/main/java/forge/control/input/InputBlock.java +++ b/src/main/java/forge/control/input/InputBlock.java @@ -17,10 +17,11 @@ */ package forge.control.input; -import java.util.ArrayList; +import java.util.HashMap; import forge.AllZone; import forge.Card; +import forge.CardList; import forge.Singletons; import forge.game.phase.CombatUtil; import forge.game.zone.PlayerZone; @@ -43,7 +44,7 @@ public class InputBlock extends Input { private static final long serialVersionUID = 6120743598368928128L; private Card currentAttacker = null; - private final ArrayList allBlocking = new ArrayList(); + private final HashMap allBlocking = new HashMap(); /** *

@@ -88,7 +89,7 @@ public class InputBlock extends Input { // Done blocking ButtonUtil.reset(); - CombatUtil.orderMultipleBlockers(AllZone.getCombat()); + CombatUtil.orderMultipleCombatants(AllZone.getCombat()); Singletons.getModel().getGameState().getPhaseHandler().setNeedToNextPhase(true); } @@ -98,17 +99,35 @@ public class InputBlock extends Input { @Override public final void selectCard(final Card card, final PlayerZone zone) { // is attacking? + boolean reminder = true; + if (AllZone.getCombat().getAttackers().contains(card)) { this.currentAttacker = card; - } else if (zone.is(ZoneType.Battlefield, AllZone.getHumanPlayer()) && card.isCreature() - && CombatUtil.canBlock(this.currentAttacker, card, AllZone.getCombat()) - && this.currentAttacker != null && !this.allBlocking.contains(card) - && card.getController().isHuman()) { - this.allBlocking.add(card); - AllZone.getCombat().addBlocker(this.currentAttacker, card); + reminder = false; } else { + // Make sure this card is valid to even be a blocker + if (this.currentAttacker != null && card.isCreature() && card.getController().isHuman() + && zone.is(ZoneType.Battlefield, AllZone.getHumanPlayer())) { + // Create a new blockedBy list if it doesn't exist + if (!this.allBlocking.containsKey(card)) { + this.allBlocking.put(card, new CardList()); + } + + CardList attackersBlocked = this.allBlocking.get(card); + if (!attackersBlocked.contains(this.currentAttacker) && + CombatUtil.canBlock(this.currentAttacker, card, AllZone.getCombat()) && + CombatUtil.canBlockMoreCreatures(card, attackersBlocked)) { + attackersBlocked.add(this.currentAttacker); + AllZone.getCombat().addBlocker(this.currentAttacker, card); + reminder = false; + } + } + } + + if (reminder) { SDisplayUtil.remind(VMessage.SINGLETON_INSTANCE); } + this.showMessage(); } // selectCard() } diff --git a/src/main/java/forge/game/phase/Combat.java b/src/main/java/forge/game/phase/Combat.java index 3bdaca261fe..5bb71a48825 100644 --- a/src/main/java/forge/game/phase/Combat.java +++ b/src/main/java/forge/game/phase/Combat.java @@ -49,21 +49,21 @@ import forge.gui.match.CMatchUI; public class Combat { // key is attacker Card // value is CardList of blockers - private final Map map = new TreeMap(); + private final Map attackerMap = new TreeMap(); + private final Map blockerMap = new TreeMap(); + private final Set blocked = new HashSet(); - private final HashMap unblockedMap = new HashMap(); private final HashMap defendingDamageMap = new HashMap(); - // Defenders are the Defending Player + Each Planeswalker that player - // controls + // Defenders are the Defending Player + Each controlled Planeswalker private List defenders = new ArrayList(); + private Map defenderMap = new TreeMap(); private int currentDefender = 0; private int nextDefender = 0; // This Hash keeps track of - private final HashMap attackerToDefender = new HashMap(); - + private final HashMap attackerToDefender = new HashMap(); private Player attackingPlayer = null; private Player defendingPlayer = null; @@ -107,11 +107,14 @@ public class Combat { */ public final void initiatePossibleDefenders(final Player defender) { this.defenders.clear(); - this.defenders.add(defender); + this.defenderMap.clear(); + this.defenders.add((GameEntity)defender); + this.defenderMap.put((GameEntity)defender, new CardList()); CardList planeswalkers = defender.getCardsIn(ZoneType.Battlefield); planeswalkers = planeswalkers.getType("Planeswalker"); for (final Card pw : planeswalkers) { - this.defenders.add(pw); + this.defenders.add((GameEntity)pw); + this.defenderMap.put((GameEntity)pw, new CardList()); } } @@ -199,6 +202,9 @@ public class Combat { */ public final void setDefenders(final List newDef) { this.defenders = newDef; + for(GameEntity entity : this.defenders) { + this.defenderMap.put(entity, new CardList()); + } } /** @@ -296,8 +302,7 @@ public class Combat { * a {@link forge.Card} object. */ public final void addDefendingDamage(final int n, final Card source) { - final int slot = this.getDefenderByAttacker(source); - final GameEntity ge = this.defenders.get(slot); + final GameEntity ge = this.getDefenderByAttacker(source); if (ge instanceof Card) { final Card pw = (Card) ge; @@ -321,18 +326,19 @@ public class Combat { * @return an array of {@link forge.CardList} objects. */ public final CardList[] sortAttackerByDefender() { - final CardList[] attackers = new CardList[this.defenders.size()]; - for (int i = 0; i < attackers.length; i++) { - attackers[i] = new CardList(); - } - - for (final Card atk : this.attackerToDefender.keySet()) { - final int i = this.attackerToDefender.get(atk); - attackers[i].add(atk); + int size = this.defenders.size(); + final CardList[] attackers = new CardList[size]; + for (int i = 0; i < size; i++) { + attackers[i] = getAttackersByDefenderSlot(i); } return attackers; } + + public final CardList getAttackersByDefenderSlot(int slot) { + GameEntity entity = this.defenders.get(slot); + return this.defenderMap.get(entity); + } /** *

@@ -344,7 +350,7 @@ public class Combat { * @return a boolean. */ public final boolean isAttacking(final Card c) { - return this.map.get(c) != null; + return this.attackerMap.get(c) != null; } /** @@ -356,8 +362,7 @@ public class Combat { * a {@link forge.Card} object. */ public final void addAttacker(final Card c) { - this.map.put(c, new CardList()); - this.attackerToDefender.put(c, this.currentDefender); + this.addAttacker(c, defenders.get(this.currentDefender)); } /** @@ -371,13 +376,14 @@ public class Combat { * a GameEntity object. */ public final void addAttacker(final Card c, GameEntity defender) { - int n = defenders.indexOf(defender); - if (-1 == n) { + if (!defenders.contains(defender)) { System.out.println("Trying to add Attacker " + c + " to missing defender " + defender); - } else { - this.map.put(c, new CardList()); - this.attackerToDefender.put(c, n); + return; } + + this.attackerMap.put(c, new CardList()); + this.attackerToDefender.put(c, defender); + this.defenderMap.get(defender).add(c); } /** @@ -389,12 +395,20 @@ public class Combat { * a {@link forge.Card} object. * @return a {@link java.lang.Object} object. */ - public final Integer getDefenderByAttacker(final Card c) { + public final GameEntity getDefenderByAttacker(final Card c) { return this.attackerToDefender.get(c); } public final GameEntity getDefendingEntity(final Card c) { - return this.getDefenders().get(this.attackerToDefender.get(c)); + GameEntity defender = this.attackerToDefender.get(c); + + if (this.defenders.contains(defender)) { + return defender; + } + + System.out.println("Attacker " + c + " missing defender " + defender); + + return null; } /** @@ -403,8 +417,9 @@ public class Combat { *

*/ public final void resetAttackers() { - this.map.clear(); + this.attackerMap.clear(); this.attackerToDefender.clear(); + this.blockerMap.clear(); } /** @@ -415,7 +430,7 @@ public class Combat { * @return an array of {@link forge.Card} objects. */ public final List getAttackers() { - return new ArrayList(this.map.keySet()); + return new ArrayList(this.attackerMap.keySet()); } // getAttackers() /** @@ -426,7 +441,7 @@ public class Combat { * @return an array of {@link forge.Card} objects. */ public final CardList getAttackerList() { - return new CardList(this.map.keySet()); + return new CardList(this.attackerMap.keySet()); } // getAttackers() /** @@ -454,7 +469,13 @@ public class Combat { */ public final void addBlocker(final Card attacker, final Card blocker) { this.blocked.add(attacker); - this.getBlockerList(attacker).add(blocker); + this.attackerMap.get(attacker).add(blocker); + if (!this.blockerMap.containsKey(blocker)) { + this.blockerMap.put(blocker, new CardList(attacker)); + } + else { + this.blockerMap.get(blocker).add(attacker); + } } /** @@ -465,12 +486,8 @@ public class Combat { * @return a {@link forge.CardList} object. */ public final CardList getAllBlockers() { - final CardList att = this.getAttackerList(); final CardList block = new CardList(); - - for (int i = 0; i < att.size(); i++) { - block.addAll(this.getBlockers(att.get(i))); - } + block.addAll(blockerMap.keySet()); return block; } // getAllBlockers() @@ -485,10 +502,10 @@ public class Combat { * @return a {@link forge.CardList} object. */ public final CardList getBlockers(final Card attacker) { - if (this.getBlockerList(attacker) == null) { + if (this.getBlockingAttackerList(attacker) == null) { return new CardList(); } else { - return new CardList(this.getBlockerList(attacker)); + return new CardList(this.getBlockingAttackerList(attacker)); } } @@ -501,17 +518,11 @@ public class Combat { * a {@link forge.Card} object. * @return a {@link forge.Card} object. */ - public final Card getAttackerBlockedBy(final Card blocker) { - // TODO(sol) Return CardList instead of a card - final CardList att = this.getAttackerList(); - - for (int i = 0; i < att.size(); i++) { - if (this.getBlockers(att.get(i)).contains(blocker)) { - return att.get(i); - } - } // for - - return null; + public final CardList getAttackersBlockedBy(final Card blocker) { + if (blockerMap.containsKey(blocker)) { + return blockerMap.get(blocker); + } + return new CardList(); } /** @@ -523,8 +534,8 @@ public class Combat { * a {@link forge.Card} object. * @return a {@link forge.CardList} object. */ - private CardList getBlockerList(final Card attacker) { - return this.map.get(attacker); + private CardList getBlockingAttackerList(final Card attacker) { + return this.attackerMap.get(attacker); } /** @@ -537,7 +548,11 @@ public class Combat { * @return a {@link forge.CardList} object. */ public void setBlockerList(final Card attacker, final CardList blockers) { - this.map.put(attacker, blockers); + this.attackerMap.put(attacker, blockers); + } + + public void setAttackersBlockedByList(final Card blocker, final CardList attackers) { + this.blockerMap.put(blocker, attackers); } /** @@ -549,21 +564,24 @@ public class Combat { * 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? - final CardList att = this.getAttackerList(); - if (att.contains(c)) { - this.map.remove(c); + if (this.attackerMap.containsKey(c)) { + CardList blockers = this.attackerMap.get(c); + this.attackerMap.remove(c); + for(Card b : blockers) { + this.blockerMap.get(b).remove(c); + } this.attackerToDefender.remove(c); - } else { // card is a blocker - for (final Card a : att) { - if (this.getBlockers(a).contains(c)) { - this.getBlockerList(a).remove(c); - // TODO if Declare Blockers and Declare Blockers (Abilities) - // merge this logic needs to be tweaked - if ((this.getBlockers(a).size() == 0) - && Singletons.getModel().getGameState().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) { - this.blocked.remove(a); - } + } else if (this.blockerMap.containsKey(c)){ // card is a blocker + CardList attackers = this.blockerMap.get(c); + + boolean stillDeclaring = Singletons.getModel().getGameState().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).size() == 0) { + this.blocked.remove(a); } } } @@ -581,7 +599,7 @@ public class Combat { final CardList att = this.getAttackerList(); for (final Card attacker : att) { if (this.getBlockers(attacker).contains(blocker)) { - this.getBlockerList(attacker).remove(blocker); + this.getBlockingAttackerList(attacker).remove(blocker); if (this.getBlockers(attacker).size() == 0) { this.blocked.remove(attacker); } @@ -636,10 +654,7 @@ public class Combat { for (final Card blocker : blockers) { if (blocker.hasDoubleStrike() || blocker.hasFirstStrike() == firstStrikeDamage) { - // TODO Switch comment lines when Blockers can block more than one creature - final Card attacker = this.getAttackerBlockedBy(blocker); - CardList attackers = new CardList(attacker); - //CardList attackers = this.getAttackersBlockedBy(b); + CardList attackers = this.getAttackersBlockedBy(blocker); final int damage = blocker.getNetCombatDamage(); @@ -647,7 +662,7 @@ public class Combat { // Just in case it was removed or something } else { assignedDamage = true; - if (this.getAttackingPlayer().isHuman()) { // human attacks + if (this.getAttackingPlayer().isComputer()) { // ai attacks if (attackers.size() > 1) { CMatchUI.SINGLETON_INSTANCE.assignDamage(blocker, attackers, damage); } else { diff --git a/src/main/java/forge/game/phase/CombatUtil.java b/src/main/java/forge/game/phase/CombatUtil.java index 29557289fd3..bce6e0bd6ad 100644 --- a/src/main/java/forge/game/phase/CombatUtil.java +++ b/src/main/java/forge/game/phase/CombatUtil.java @@ -157,6 +157,17 @@ public class CombatUtil { return true; } + + public static boolean canBlockMoreCreatures(final Card blocker, final CardList blockedBy) { + // TODO(sol) expand this for the additional blocking keyword + int size = blockedBy.size(); + + if (size == 0 || blocker.hasKeyword("CARDNAME can block any number of creatures.")) { + return true; + } + + return blocker.getKeywordAmount("CARDNAME can block an additional creature.") >= size; + } // can the attacker be blocked at all? /** @@ -387,7 +398,12 @@ public class CombatUtil { return true; } - public static void orderMultipleBlockers(final Combat combat) { + public static void orderMultipleCombatants(final Combat combat) { + CombatUtil.orderMultipleBlockers(combat); + CombatUtil.orderBlockingMultipleAttackers(combat); + } + + private static void orderMultipleBlockers(final Combat combat) { // If there are multiple blockers, the Attacker declares the Assignment Order final Player player = combat.getAttackingPlayer(); final CardList attackers = combat.getAttackerList(); @@ -415,6 +431,34 @@ public class CombatUtil { // Refresh Combat Panel } + private static void orderBlockingMultipleAttackers(final Combat combat) { + // If there are multiple blockers, the Attacker declares the Assignment Order + final Player player = combat.getDefendingPlayer(); + final CardList blockers = combat.getAllBlockers(); + for (final Card blocker : blockers) { + CardList attackers = combat.getAttackersBlockedBy(blocker); + if (attackers.size() <= 1) { + continue; + } + + CardList orderedAttacker = null; + if (player.isHuman()) { + List ordered = GuiUtils.getOrderChoices("Choose Blocking Order", "Damaged First", true, (Object[])attackers.toArray()); + + orderedAttacker = new CardList(); + for(Object o : ordered) { + orderedAttacker.add((Card)o); + } + } + else { + orderedAttacker = ComputerUtilBlock.orderAttackers(blocker, attackers); + } + combat.setAttackersBlockedByList(blocker, orderedAttacker); + } + CombatUtil.showCombat(); + // Refresh Combat Panel + } + // can the blocker block an attacker with a lure effect? /** @@ -1040,7 +1084,7 @@ public class CombatUtil { int damage = 0; - final CardList attackers = combat.sortAttackerByDefender()[0]; + final CardList attackers = combat.getAttackersByDefenderSlot(0); final CardList unblocked = new CardList(); for (final Card attacker : attackers) { @@ -1082,7 +1126,7 @@ public class CombatUtil { int poison = 0; - final CardList attackers = combat.sortAttackerByDefender()[0]; + final CardList attackers = combat.getAttackersByDefenderSlot(0); final CardList unblocked = new CardList(); for (final Card attacker : attackers) { @@ -1127,7 +1171,7 @@ public class CombatUtil { } // check for creatures that must be blocked - final CardList attackers = combat.sortAttackerByDefender()[0]; + final CardList attackers = combat.getAttackersByDefenderSlot(0); for (final Card attacker : attackers) { @@ -1181,7 +1225,7 @@ public class CombatUtil { } // check for creatures that must be blocked - final CardList attackers = combat.sortAttackerByDefender()[0]; + final CardList attackers = combat.getAttackersByDefenderSlot(0); for (final Card attacker : attackers) { @@ -2215,11 +2259,15 @@ public class CombatUtil { * @return a boolean. */ public static boolean blockerWouldBeDestroyed(final Card blocker) { - final Card attacker = AllZone.getCombat().getAttackerBlockedBy(blocker); + // TODO THis function only checks if a single attacker at a time would destroy a blocker + // This needs to expand to tally up damage + final CardList attackers = AllZone.getCombat().getAttackersBlockedBy(blocker); - if (CombatUtil.canDestroyBlocker(blocker, attacker, AllZone.getCombat(), true) - && !(attacker.hasKeyword("Wither") || attacker.hasKeyword("Infect"))) { - return true; + for(Card attacker : attackers) { + if (CombatUtil.canDestroyBlocker(blocker, attacker, AllZone.getCombat(), true) + && !(attacker.hasKeyword("Wither") || attacker.hasKeyword("Infect"))) { + return true; + } } return false; } @@ -2436,7 +2484,13 @@ public class CombatUtil { *

*/ public static void showCombat() { + // TODO(sol) ShowCombat seems to be resetting itself when switching away and switching back? final StringBuilder display = new StringBuilder(); + + if (!Singletons.getModel().getGameState().getPhaseHandler().inCombat()) { + VCombat.SINGLETON_INSTANCE.updateCombat(display.toString().trim()); + return; + } // Loop through Defenders // Append Defending Player/Planeswalker diff --git a/src/main/java/forge/game/player/ComputerAIGeneral.java b/src/main/java/forge/game/player/ComputerAIGeneral.java index 5b6e22c2c83..39453eb5b3a 100644 --- a/src/main/java/forge/game/player/ComputerAIGeneral.java +++ b/src/main/java/forge/game/player/ComputerAIGeneral.java @@ -281,7 +281,7 @@ public class ComputerAIGeneral implements Computer { AllZone.setCombat(ComputerUtilBlock.getBlockers(AllZone.getCombat(), blockers)); - CombatUtil.orderMultipleBlockers(AllZone.getCombat()); + CombatUtil.orderMultipleCombatants(AllZone.getCombat()); Singletons.getModel().getGameState().getPhaseHandler().setNeedToNextPhase(true); } diff --git a/src/main/java/forge/game/player/ComputerUtilAttack.java b/src/main/java/forge/game/player/ComputerUtilAttack.java index ac67847b6cb..cd303588602 100644 --- a/src/main/java/forge/game/player/ComputerUtilAttack.java +++ b/src/main/java/forge/game/player/ComputerUtilAttack.java @@ -781,7 +781,7 @@ public class ComputerUtilAttack { final int blockNum = this.blockers.size(); int attackNum = 0; int damage = 0; - CardList attacking = combat.sortAttackerByDefender()[combat.getCurrentDefenderNumber()]; + CardList attacking = combat.getAttackersByDefenderSlot(combat.getCurrentDefenderNumber()); CardListUtil.sortAttackLowFirst(attacking); for (Card atta : attacking) { if (attackNum >= blockNum || !CombatUtil.canBeBlocked(attacker, this.blockers)) { diff --git a/src/main/java/forge/game/player/ComputerUtilBlock.java b/src/main/java/forge/game/player/ComputerUtilBlock.java index c6949214956..fc832edaea9 100644 --- a/src/main/java/forge/game/player/ComputerUtilBlock.java +++ b/src/main/java/forge/game/player/ComputerUtilBlock.java @@ -928,4 +928,17 @@ public class ComputerUtilBlock { return blockers; } + + public static CardList orderAttackers(Card attacker, CardList blockers) { + // This shouldn't really take trample into account, but otherwise should be pretty similar to orderBlockers + // very very simple ordering of attackers, sort by evaluate, then sort by attack + //final int damage = attacker.getNetCombatDamage(); + CardListUtil.sortByEvaluateCreature(blockers); + CardListUtil.sortAttack(blockers); + + // TODO: Take total damage, and attempt to maximize killing the greatest evaluation of creatures + // It's probably generally better to kill the largest creature, but sometimes its better to kill a few smaller ones + + return blockers; + } } diff --git a/src/main/java/forge/game/player/Player.java b/src/main/java/forge/game/player/Player.java index f4569576cee..17f7f2a684f 100644 --- a/src/main/java/forge/game/player/Player.java +++ b/src/main/java/forge/game/player/Player.java @@ -61,8 +61,7 @@ import forge.util.MyRandom; * @author Forge * @version $Id$ */ -public abstract class Player extends GameEntity { - +public abstract class Player extends GameEntity implements Comparable { /** The poison counters. */ private int poisonCounters; @@ -2681,6 +2680,19 @@ public abstract class Player extends GameEntity { } } + @Override + public int compareTo(Player o) { + if (o == null) { + return +1; + } + int subtractedHash = o.hashCode() - this.hashCode(); + if (subtractedHash == 0) { + return 0; + } + + return Math.abs(subtractedHash)/subtractedHash; + } + /** {@inheritDoc} */ @Override public int hashCode() {