diff --git a/.gitattributes b/.gitattributes index 5209ebb1668..45372e727f1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6367,9 +6367,7 @@ src/forge/ImagePreviewPanel.java -text svneol=native#text/plain src/forge/Input.java svneol=native#text/plain src/forge/InputControl.java svneol=native#text/plain src/forge/Input_Attack.java svneol=native#text/plain -src/forge/Input_Attack_Planeswalker.java svneol=native#text/plain src/forge/Input_Block.java svneol=native#text/plain -src/forge/Input_Block_Planeswalker.java svneol=native#text/plain src/forge/Input_Cleanup.java svneol=native#text/plain src/forge/Input_Mulligan.java svneol=native#text/plain src/forge/Input_PassPriority.java -text svneol=native#text/plain diff --git a/src/forge/AbilityFactory_GainControl.java b/src/forge/AbilityFactory_GainControl.java index 01758150e8a..76173824f90 100644 --- a/src/forge/AbilityFactory_GainControl.java +++ b/src/forge/AbilityFactory_GainControl.java @@ -346,9 +346,6 @@ public class AbilityFactory_GainControl { CardList list = new CardList(AllZone.Combat.getAttackers()); if(list.contains(c)) AllZone.Combat.removeFromCombat(c); - CardList pwlist = new CardList(AllZone.pwCombat.getAttackers()); - if(pwlist.contains(c)) AllZone.pwCombat.removeFromCombat(c); - PlayerZone to = AllZone.getZone(Constant.Zone.Battlefield, c.getOwner()); to.add(c); diff --git a/src/forge/AllZone.java b/src/forge/AllZone.java index 703425a7724..8a2a1815aa5 100644 --- a/src/forge/AllZone.java +++ b/src/forge/AllZone.java @@ -42,7 +42,6 @@ public class AllZone implements NewConstants { //shared between Input_Attack, Input_Block, Input_CombatDamage , InputState_Computer public static Combat Combat = new Combat(); - public static Combat pwCombat = new Combat();//for Planeswalker combat //Human_Play, Computer_Play is different because Card.comesIntoPlay() is called when a card is added by PlayerZone.add(Card) public final static PlayerZone Human_Battlefield = new PlayerZone_ComesIntoPlay(Constant.Zone.Battlefield, AllZone.HumanPlayer); diff --git a/src/forge/Card.java b/src/forge/Card.java index 4d6584b7a72..70720e2c076 100644 --- a/src/forge/Card.java +++ b/src/forge/Card.java @@ -2710,14 +2710,11 @@ public class Card extends MyObservable { } public boolean isAttacking() { - CardList attackers = new CardList(AllZone.Combat.getAttackers()); - attackers.addAll(AllZone.pwCombat.getAttackers()); - return attackers.contains(this); + return AllZone.Combat.isAttacking(this); } public boolean isBlocking() { CardList blockers = AllZone.Combat.getAllBlockers(); - blockers.add(AllZone.pwCombat.getAllBlockers()); return blockers.contains(this); } diff --git a/src/forge/CardFactory_Creatures.java b/src/forge/CardFactory_Creatures.java index 05fed87f2a9..048d0f52d46 100644 --- a/src/forge/CardFactory_Creatures.java +++ b/src/forge/CardFactory_Creatures.java @@ -5802,9 +5802,6 @@ public class CardFactory_Creatures { CardList list = new CardList(AllZone.Combat.getAttackers()); if(list.contains(c)) AllZone.Combat.removeFromCombat(c); - CardList pwlist = new CardList(AllZone.pwCombat.getAttackers()); - if(pwlist.contains(c)) AllZone.pwCombat.removeFromCombat(c); - PlayerZone to = AllZone.getZone(Constant.Zone.Battlefield, c.getOwner()); to.add(c); diff --git a/src/forge/CardFactory_Planeswalkers.java b/src/forge/CardFactory_Planeswalkers.java index 31267de02d3..76d1faadabd 100644 --- a/src/forge/CardFactory_Planeswalkers.java +++ b/src/forge/CardFactory_Planeswalkers.java @@ -2902,7 +2902,7 @@ class CardFactory_Planeswalkers { { public boolean addCard(Card crd) { - return crd.isCreature() && CombatUtil.canAttack(crd); + return CombatUtil.canAttack(crd); } }); diff --git a/src/forge/Combat.java b/src/forge/Combat.java index 3054013d2d6..b0a04b7dc03 100644 --- a/src/forge/Combat.java +++ b/src/forge/Combat.java @@ -13,31 +13,28 @@ public class Combat { private HashMap defendingFirstStrikeDamageMap = new HashMap(); private HashMap defendingDamageMap = new HashMap(); - private int attackingDamage; - // private int defendingDamage; - - // private int defendingFirstStrikeDamage; - // private int trampleDamage; - // private int trampleFirstStrikeDamage; - - private Player attackingPlayer; - private Player defendingPlayer; - - private int declaredAttackers; - - private Card planeswalker; + // Defenders are the Defending Player + Each Planeswalker that player controls + private ArrayList defenders = new ArrayList(); + private int currentDefender = 0; + private int nextDefender = 0; + // This Hash keeps track of + private HashMap attackerToDefender = new HashMap(); + + private int attackingDamage; + + private Player attackingPlayer = null; + private Player defendingPlayer = null; + private CardList attackersWithLure = new CardList(); private CardList canBlockAttackerWithLure = new CardList(); public Combat() { - reset(); + // Let the Begin Turn/Untap Phase Reset Combat properly } public void reset() { - planeswalker = null; - - map.clear(); + resetAttackers(); blocked.clear(); unblockedMap.clear(); @@ -46,24 +43,70 @@ public class Combat { defendingDamageMap.clear(); defendingFirstStrikeDamageMap.clear(); - declaredAttackers = 0; attackingPlayer = null; defendingPlayer = null; - attackersWithLure = new CardList(); - canBlockAttackerWithLure = new CardList(); + attackersWithLure.clear(); + canBlockAttackerWithLure.clear(); + + defenders.clear(); + currentDefender = 0; + nextDefender = 0; + + initiatePossibleDefenders(AllZone.Phase.getPlayerTurn().getOpponent()); } - public void setPlaneswalker(Card c) { - planeswalker = c; + public void initiatePossibleDefenders(Player defender){ + defenders.add(defender); + CardList planeswalkers = AllZoneUtil.getPlayerCardsInPlay(defender); + planeswalkers = planeswalkers.getType("Planeswalker"); + for(Card pw : planeswalkers) + defenders.add(pw); } + + public Object nextDefender(){ + if (nextDefender >= defenders.size()) + return null; + + currentDefender = nextDefender; + nextDefender++; - public Card getPlaneswalker() { - return planeswalker; + return defenders.get(currentDefender); + } + + public void setCurrentDefender(int def){ + currentDefender = def; + } + + public int getRemainingDefenders(){ + return defenders.size() - nextDefender; + } + + public ArrayList getDefenders(){ + return defenders; + } + + public void setDefenders(ArrayList newDef){ + defenders = newDef; + } + + public Card[] getDefendingPlaneswalkers(){ + Card[] pwDefending = new Card[defenders.size()-1]; + + int i = 0; + + for(Object o : defenders){ + if (o instanceof Card){ + pwDefending[i] = (Card)o; + i++; + } + } + + return pwDefending; } public int getDeclaredAttackers() { - return declaredAttackers; + return attackerToDefender.size(); } public void setAttackingPlayer(Player player) { @@ -162,12 +205,9 @@ public class Combat { damageDealt = att.get(i).getNetDefense(); if (damageDealt > 0) { - // if the creature has first strike do not do damage in the - // normal combat phase - // if(att.get(i).hasSecondStrike()) + // if the creature has first strike do not do damage in the normal combat phase if (!att.get(i).hasFirstStrike() - || (att.get(i).hasFirstStrike() && att.get(i) - .hasDoubleStrike())) + || (att.get(i).hasFirstStrike() && att.get(i).hasDoubleStrike())) addDefendingDamage(damageDealt, att.get(i)); } } // ! isBlocked... @@ -185,8 +225,7 @@ public class Combat { damageDealt = att.get(i).getNetDefense(); if (damageDealt > 0) { - // if the creature has first strike or double strike do - // damage in the first strike combat phase + // if the creature has first strike or double strike do damage in the first strike combat phase if (att.get(i).hasFirstStrike() || att.get(i).hasDoubleStrike()) { addDefendingFirstStrikeDamage(damageDealt, att.get(i)); @@ -197,6 +236,16 @@ public class Combat { } public void addDefendingDamage(int n, Card source) { + String slot = getDefenderByAttacker(source).toString(); + Object o = defenders.get(Integer.parseInt(slot)); + + if (o instanceof Card){ + Card pw = (Card)o; + pw.addAssignedDamage(n, source); + + return; + } + if (!defendingDamageMap.containsKey(source)) defendingDamageMap.put(source, n); else { @@ -205,11 +254,21 @@ public class Combat { } public void addDefendingFirstStrikeDamage(int n, Card source) { + String slot = getDefenderByAttacker(source).toString(); + Object o = defenders.get(Integer.parseInt(slot)); + + if (o instanceof Card){ + Card pw = (Card)o; + pw.addAssignedDamage(n, source); + + return; + } + if (!defendingFirstStrikeDamageMap.containsKey(source)) defendingFirstStrikeDamageMap.put(source, n); else { defendingFirstStrikeDamageMap.put(source, - defendingFirstStrikeDamageMap.get(source) + n); + defendingFirstStrikeDamageMap.get(source) + n); } } @@ -221,19 +280,41 @@ public class Combat { return attackingDamage; } + public CardList[] sortAttackerByDefender(){ + CardList attackers[] = new CardList[defenders.size()]; + for(int i = 0; i < attackers.length; i++) + attackers[i] = new CardList(); + + for(Card atk : attackerToDefender.keySet()){ + Object o = attackerToDefender.get(atk); + int i = Integer.parseInt(o.toString()); + attackers[i].add(atk); + } + + return attackers; + } + + public boolean isAttacking(Card c) { + return map.get(c) != null; + } + public void addAttacker(Card c) { map.put(c, new CardList()); - declaredAttackers++; + attackerToDefender.put(c, currentDefender); + } + + public Object getDefenderByAttacker(Card c) { + return attackerToDefender.get(c); } public void resetAttackers() { map.clear(); + attackerToDefender.clear(); } public Card[] getAttackers() { CardList out = new CardList(); Iterator it = map.keySet().iterator(); - // int i = 0; //unused while (it.hasNext()) { out.add((Card) it.next()); @@ -284,8 +365,10 @@ public class Combat { public void removeFromCombat(Card c) { // is card an attacker? CardList att = new CardList(getAttackers()); - if (att.contains(c)) + if (att.contains(c)){ map.remove(c); + attackerToDefender.remove(c); + } else// card is a blocker { for (int i = 0; i < att.size(); i++) @@ -312,8 +395,6 @@ public class Combat { CardList block; CardList attacking = new CardList(getAttackers()); for (int i = 0; i < attacking.size(); i++) { - // if(attacking.get(i).hasFirstStrike() || - // (attacking.get(i).hasDoubleStrike() )){ block = getBlockers(attacking.get(i)); // attacker always gets all blockers' attack @@ -327,16 +408,12 @@ public class Combat { } } - if (block.size() == 0)// this damage is assigned to a player by - // setPlayerDamage() - { - // GameActionUtil.executePlayerCombatDamageEffects(attacking.get(i)); + if (block.size() == 0){ + // this damage is assigned to a player by setPlayerDamage() addUnblockedAttacker(attacking.get(i)); } - else if (attacking.get(i).hasFirstStrike() - || (attacking.get(i).hasDoubleStrike())) { - + else if (attacking.get(i).hasFirstStrike() || (attacking.get(i).hasDoubleStrike())) { if (block.size() == 1) { if (attacking.get(i).hasFirstStrike() || attacking.get(i).hasDoubleStrike()) { @@ -371,49 +448,20 @@ public class Combat { addAssignedFirstStrikeDamage(attacking.get(i), block, damageDealt); } - } else// human - { - if (attacking.get(i).hasFirstStrike() - || attacking.get(i).hasDoubleStrike()) { - // GuiDisplay2 gui = (GuiDisplay2) AllZone.Display; + } + else{ + // human + if (attacking.get(i).hasFirstStrike() || attacking.get(i).hasDoubleStrike()) { int damageDealt = attacking.get(i).getNetAttack(); if (CombatUtil.isDoranInPlay()) damageDealt = attacking.get(i).getNetDefense(); - AllZone.Display.assignDamage(attacking.get(i), block, - damageDealt); + AllZone.Display.assignDamage(attacking.get(i), block, damageDealt); - /* - * for (Card b : block) { - * AllZone.Display.assignDamage(attacking.get(i), b, - * damageDealt);//System.out.println( - * "setAssignedFirstStrikeDmg called for:" + damageDealt - * + " damage."); } - * AllZone.Display.addAssignDamage(attacking - * .get(i),damageDealt); - */ } } }// if(hasFirstStrike || doubleStrike) }// for - - // should first strike affect the following? - if (getPlaneswalker() != null) { - // System.out.println("defendingDmg (setAssignedFirstStrikeDamage) :" - // +defendingFirstStrikeDamage); - // - - Iterator iter = defendingFirstStrikeDamageMap.keySet() - .iterator(); - while (iter.hasNext()) { - Card crd = iter.next(); - planeswalker.addAssignedDamage(defendingFirstStrikeDamageMap - .get(crd), crd); - } - - defendingFirstStrikeDamageMap.clear(); - } - }// setAssignedFirstStrikeDamage() private void addAssignedFirstStrikeDamage(Card attacker, CardList block, @@ -449,16 +497,9 @@ public class Combat { CardList block; CardList attacking = new CardList(getAttackers()); for (int i = 0; i < attacking.size(); i++) { - // if(!attacking.get(i).hasSecondStrike() ){ - // if(!attacking.get(i).hasFirstStrike() || - // (attacking.get(i).hasFirstStrike() && - // attacking.get(i).hasDoubleStrike() )){ block = getBlockers(attacking.get(i)); // attacker always gets all blockers' attack - // attacking.get(i).setAssignedDamage(CardListUtil.sumAttack(block)); - // AllZone.GameAction.setAssignedDamage(attacking.get(i), block, - // CardListUtil.sumAttack(block)); for (Card b : block) { if (!b.hasFirstStrike() @@ -470,17 +511,12 @@ public class Combat { } } - if (block.size() == 0)// this damage is assigned to a player by - // setPlayerDamage() - { - // GameActionUtil.executePlayerCombatDamageEffects(attacking.get(i)); + if (block.size() == 0){ + // this damage is assigned to a player by setPlayerDamage() addUnblockedAttacker(attacking.get(i)); } - else if (!attacking.get(i).hasFirstStrike() - || (attacking.get(i).hasFirstStrike() && attacking.get(i) - .hasDoubleStrike())) { - + else if (!attacking.get(i).hasFirstStrike() || attacking.get(i).hasDoubleStrike()) { if (block.size() == 1) { int damageDealt = attacking.get(i).getNetAttack(); if (CombatUtil.isDoranInPlay()) @@ -503,70 +539,22 @@ public class Combat { damageDealt = attacking.get(i).getNetDefense(); addAssignedDamage(attacking.get(i), block, damageDealt); - } else// human attacks - { - // GuiDisplay2 gui = (GuiDisplay2) AllZone.Display; + } + else{ // human attacks int damageDealt = attacking.get(i).getNetAttack(); if (CombatUtil.isDoranInPlay()) damageDealt = attacking.get(i).getNetDefense(); - AllZone.Display.assignDamage(attacking.get(i), block, - damageDealt); + AllZone.Display.assignDamage(attacking.get(i), block, damageDealt); - /* - * - * - * for (Card b :block) - * AllZone.Display.addAssignDamage(attacking.get(i), b, - * damageDealt); - * //System.out.println("setAssignedDmg called for:" + - * damageDealt + " damage."); - */ } }// if !hasFirstStrike ... - // hacky code, to ensure surviving non-first-strike blockers will - // hit first strike attackers: - /* - * else { block = getBlockers(attacking.get(i)); - * //System.out.println("block size: " + block.size()); if( - * (attacking.get(i).hasFirstStrike() || - * attacking.get(i).hasDoubleStrike()) ) { for(int j=0; j < - * block.size(); j++) { //blockerDamage += - * block.get(j).getNetAttack(); int damage = - * block.get(j).getNetAttack(); if (CombatUtil.isDoranInPlay()) - * damage = block.get(j).getNetDefense(); - * AllZone.GameAction.addAssignedDamage(attacking.get(i), - * block.get(j), damage); } - * //attacking.get(i).setAssignedDamage(blockerDamage); - * //AllZone.GameAction.setAssignedDamage(attacking.get(i), block , - * blockerDamage); } } - */ }// for // should first strike affect the following? - if (getPlaneswalker() != null) { - // System.out.println("defendingDmg (setAssignedDamage): " + - // defendingDamage); - Iterator iter = defendingDamageMap.keySet().iterator(); - while (iter.hasNext()) { - Card crd = iter.next(); - planeswalker - .addAssignedDamage(defendingDamageMap.get(crd), crd); - } - defendingDamageMap.clear(); - } - }// assignDamage() - /* - * private void setAssignedDamage(Card attacker, CardList list, int damage) - * { CardListUtil.sortAttack(list); Card c; for(int i = 0; i < list.size(); - * i++) { c = list.get(i); //if(!c.hasFirstStrike() || (c.hasFirstStrike() - * && c.hasDoubleStrike()) ){ if(c.getKillDamage() <= damage) { damage -= - * c.getKillDamage(); CardList cl = new CardList(); cl.add(attacker); - * AllZone.GameAction.addAssignedDamage(c, cl, c.getKillDamage()); - * //c.setAssignedDamage(c.getKillDamage()); } //} }//for }//assignDamage() - */ + }// assignDamage() private void addAssignedDamage(Card attacker, CardList block, int damage) { Card c = attacker; @@ -617,85 +605,33 @@ public class Combat { } } - /* - if (bFirstStrike){ - CardList pwAttackers = new CardList(AllZone.pwCombat.getAttackers()); - CardList pwBlockers = new CardList(AllZone.pwCombat.getAllBlockers().toArray()); - - - for(int i = 0; i < pwAttackers.size(); i++) { - if((pwAttackers.getCard(i).hasFirstStrike() || pwAttackers.getCard(i).hasDoubleStrike())) { - CombatUtil.executeCombatDamageEffects(pwAttackers.getCard(i)); - } - } - for(int i = 0; i < pwBlockers.size(); i++) { - if((pwBlockers.getCard(i).hasFirstStrike() || pwBlockers.getCard(i).hasDoubleStrike())) { - CombatUtil.executeCombatDamageEffects(pwBlockers.getCard(i)); - } - } - }*/ - - //get all attackers and blockers - CardList check = new CardList(); - check.addAll(AllZone.Human_Battlefield.getCards()); - check.addAll(AllZone.Computer_Battlefield.getCards()); - - CardList all = check.getType("Creature"); - - if(AllZone.pwCombat.getPlaneswalker() != null) all.add(AllZone.pwCombat.getPlaneswalker()); - - - CardList pwAttackers = new CardList(AllZone.pwCombat.getAttackers()); - CardList pwBlockers = new CardList(AllZone.pwCombat.getAllBlockers().toArray()); - - if (!bFirstStrike){ - /* - for(int i = 0; i < pwAttackers.size(); i++) { - //System.out.println("attacker #" + i + ": " + attackers.getCard(i).getName() +" " + attackers.getCard(i).getAttack()); - if((!pwAttackers.getCard(i).hasFirstStrike() || (pwAttackers.getCard(i).hasFirstStrike() && pwAttackers.getCard( - i).hasDoubleStrike()))) { - CombatUtil.executeCombatDamageEffects(pwAttackers.getCard(i)); - } - } - for(int i = 0; i < pwBlockers.size(); i++) { - if((!pwBlockers.getCard(i).hasFirstStrike() || (pwBlockers.getCard(i).hasFirstStrike() && pwBlockers.getCard( - i).hasDoubleStrike()))) { - CombatUtil.executeCombatDamageEffects(pwBlockers.getCard(i)); - - } - } - */ - - //hacky stuff, hope it won't cause any bugs: - for(int i = 0; i < pwAttackers.size(); i++) { - AllZone.pwCombat.removeFromCombat(pwAttackers.get(i)); - } - - for(int i = 0; i < pwBlockers.size(); i++) { - AllZone.pwCombat.removeFromCombat(pwBlockers.get(i)); - } - } + // this can be much better below here... + CardList combatants = new CardList(); + combatants.addAll(AllZone.Combat.getAttackers()); + combatants.add(AllZone.Combat.getAllBlockers()); + combatants.addAll(AllZone.Combat.getDefendingPlaneswalkers()); Card c; - for(int i = 0; i < all.size(); i++) { - c = all.get(i); - //because this sets off Jackal Pup, and Filthly Cur damage ability - //and the stack says "Jack Pup causes 0 damage to the Computer" - if(c.getTotalAssignedDamage() != 0) { - HashMap assignedDamageMap = c.getAssignedDamageHashMap(); - HashMap damageMap = new HashMap(); - - for(Entry entry : assignedDamageMap.entrySet()){ - Card crd = entry.getKey(); - if(CardFactoryUtil.canDamage(crd, c)) - damageMap.put(crd, entry.getValue()); - } - c.addCombatDamage(damageMap); - - damageMap.clear(); - c.clearAssignedDamage(); + for(int i = 0; i < combatants.size(); i++) { + c = combatants.get(i); + + // if no assigned damage to resolve, move to next + if(c.getTotalAssignedDamage() == 0) + continue; + + HashMap assignedDamageMap = c.getAssignedDamageHashMap(); + HashMap damageMap = new HashMap(); + + for(Entry entry : assignedDamageMap.entrySet()){ + Card crd = entry.getKey(); + if(CardFactoryUtil.canDamage(crd, c)) + damageMap.put(crd, entry.getValue()); } + c.addCombatDamage(damageMap); + + damageMap.clear(); + c.clearAssignedDamage(); } } diff --git a/src/forge/CombatUtil.java b/src/forge/CombatUtil.java index 37b8611f797..3298dd0a985 100644 --- a/src/forge/CombatUtil.java +++ b/src/forge/CombatUtil.java @@ -350,7 +350,8 @@ public class CombatUtil { //can a creature attack att all? public static boolean canAttack(Card c) { - + if (!c.isCreature()) return false; + if(AllZoneUtil.isCardInPlay("Peacekeeper")) return false; if((AllZoneUtil.isCardInPlay("Moat") || AllZoneUtil.isCardInPlay("Magus of the Moat")) @@ -412,7 +413,7 @@ public class CombatUtil { if(allislands.size() < 5) return false; } - if(c.isTapped() || c.hasSickness() + if(c.isTapped() || c.isSick() || AllZoneUtil.isCardInPlay("Blazing Archon", c.getController().getOpponent()) || c.getKeyword().contains("CARDNAME can't attack.") || c.getKeyword().contains("CARDNAME can't attack or block.") @@ -459,7 +460,7 @@ public class CombatUtil { return false; } } - //if Card has Haste, Card.hasSickness() will return false + return true; }//canAttack() @@ -522,10 +523,12 @@ public class CombatUtil { //Checks if the life of the attacked Player/Planeswalker is in danger public static boolean lifeInDanger(Combat combat) { - + // life in danger only cares about the player's life. Not about a Planeswalkers life + int damage = 0; int poison = 0; - CardList attackers = new CardList(combat.getAttackers()); + + CardList attackers = combat.sortAttackerByDefender()[0]; CardList unblocked = new CardList(); CardList blockers = new CardList(); Card attacker = new Card(); @@ -549,14 +552,7 @@ public class CombatUtil { damage += sumAttack(unblocked, AllZone.ComputerPlayer); poison += sumPoison(unblocked, AllZone.ComputerPlayer); - if (combat.getPlaneswalker() == null) { - if (damage + 3 > AllZone.ComputerPlayer.getLife() || poison + 2 > 10 - AllZone.ComputerPlayer.getPoisonCounters()) - return true; - } else { - if (damage + 1 > combat.getPlaneswalker().getCounters(Counters.LOYALTY)) - return true; - } - return false; + return (damage + 3 > AllZone.ComputerPlayer.getLife() || poison + 2 > 10 - AllZone.ComputerPlayer.getPoisonCounters()); } // This calculates the amount of damage a blockgang can deal to the attacker (first strike not supported) @@ -816,104 +812,59 @@ public class CombatUtil { } public static void showCombat() { - //clear AllZone.Display.showCombat(""); Card attack[] = AllZone.Combat.getAttackers(); Card defend[] = null; StringBuilder display = new StringBuilder(); - String attackerName = ""; - String blockerName = ""; - //loop through attackers - for(int i = 0; i < attack.length; i++) { - //GameActionUtil.executeExaltedEffects2(attack[i], AllZone.Combat); - //checkDeclareAttackers(attack[i]); - attackerName = attack[i].getName(); - if(attack[i].isFaceDown()) attackerName = "Morph"; - display.append(attackerName); - display.append(" ("); - display.append(attack[i].getUniqueNumber()); - display.append(") "); - display.append(attack[i].getNetAttack()); - display.append("/"); - display.append(attack[i].getNetDefense()); - display.append(" is attacking \n"); - - defend = AllZone.Combat.getBlockers(attack[i]).toArray(); - - //loop through blockers - for(int inner = 0; inner < defend.length; inner++) { - //checkDeclareBlockers(defend[inner]); - blockerName = defend[inner].getName(); - if(defend[inner].isFaceDown()) blockerName = "Morph"; - - display.append(" "); - display.append(blockerName); - display.append(" ("); - display.append(defend[inner].getUniqueNumber()); - display.append(") "); - display.append(defend[inner].getNetAttack()); - display.append("/"); - display.append(defend[inner].getNetDefense()); - display.append(" is blocking \n"); - - } - }//while - loop through attackers - String s = display.toString() + getPlaneswalkerBlockers(); - AllZone.Display.showCombat(s.trim()); + // Loop through Defenders + // Append Defending Player/Planeswalker + ArrayList defenders = AllZone.Combat.getDefenders(); + CardList attackers[] = AllZone.Combat.sortAttackerByDefender(); + + // Not a big fan of the triple nested loop here + for(int def = 0; def < defenders.size(); def++){ + if (attackers[def] == null || attackers[def].size() == 0) + continue; + + if (def > 0) + display.append("\n"); + + display.append("Defender - "); + display.append(defenders.get(def).toString()); + display.append("\n"); + + int len = attackers[def].size(); + //loop through attackers + for(int i = 0; i < len; i++) { + display.append("-> "); + display.append(combatantToString(attack[i])).append("\n"); + + defend = AllZone.Combat.getBlockers(attack[i]).toArray(); + + //loop through blockers + for(int inner = 0; inner < defend.length; inner++) { + display.append("---< "); + display.append(combatantToString(defend[inner])).append("\n"); + } + }//loop through attackers + } + AllZone.Display.showCombat(display.toString().trim()); }//showBlockers() - private static String getPlaneswalkerBlockers() { - Card attack[] = AllZone.pwCombat.getAttackers(); - Card defend[] = null; - StringBuilder display = new StringBuilder(); - - if(attack.length != 0) display.append("Planeswalker Combat\r\n"); - - String attackerName = ""; - String blockerName = ""; - //loop through attackers - for(int i = 0; i < attack.length; i++) { - //GameActionUtil.executeExaltedEffects2(attack[i], AllZone.pwCombat); - - //checkDeclareAttackers(attack[i]); - attackerName = attack[i].getName(); - if(attack[i].isFaceDown()) attackerName = "Morph"; - - display.append(attackerName); - display.append(" ("); - display.append(attack[i].getUniqueNumber()); - display.append(") "); - display.append(attack[i].getNetAttack()); - display.append("/"); - display.append(attack[i].getNetDefense()); - display.append(" is attacking \n"); - - defend = AllZone.pwCombat.getBlockers(attack[i]).toArray(); - - //loop through blockers - for(int inner = 0; inner < defend.length; inner++) { - //checkDeclareBlockers(defend[inner]); - blockerName = defend[inner].getName(); - if(defend[inner].isFaceDown()) blockerName = "Morph"; - - display.append(" "); - display.append(blockerName); - display.append(" ("); - display.append(defend[inner].getUniqueNumber()); - display.append(") "); - display.append(defend[inner].getNetAttack()); - display.append("/"); - display.append(defend[inner].getNetDefense()); - display.append(" is blocking \n"); - } - }//while - loop through attackers - - return display.toString(); - }//getPlaneswalkerBlockers() - + private static String combatantToString(Card c){ + StringBuilder sb = new StringBuilder(); + + String name = (c.isFaceDown()) ? "Morph" : c.getName(); + + sb.append(name); + sb.append(" (").append(c.getUniqueNumber()).append(") "); + sb.append(c.getNetAttack()).append("/").append(c.getNetDefense()); + + return sb.toString(); + } public static boolean isDoranInPlay() { return AllZoneUtil.isCardInPlay("Doran, the Siege Tower"); @@ -921,14 +872,19 @@ public class CombatUtil { public static boolean checkPropagandaEffects(Card c) { String cost = CardFactoryUtil.getPropagandaCost(c); - if(cost.equals("0")) + if(cost.equals("0")){ + if(!c.getKeyword().contains("Vigilance")) + c.tap(); return true; + } final Card crd = c; final boolean[] canAttack = new boolean[1]; canAttack[0] = false; - if( AllZone.Phase.getPhase().equals(Constant.Phase.Combat_Declare_Attackers)) { + String phase = AllZone.Phase.getPhase(); + + if(phase.equals(Constant.Phase.Combat_Declare_Attackers) || phase.equals(Constant.Phase.Combat_Declare_Attackers)) { if(!cost.equals("0")) { final Ability ability = new Ability(c, cost) { @Override @@ -943,8 +899,8 @@ public class CombatUtil { public void execute() { canAttack[0] = false; + // TODO: remove the below line after Propaganda occurs during Declare_Attackers AllZone.Combat.removeFromCombat(crd); - crd.untap(); } }; @@ -952,6 +908,9 @@ public class CombatUtil { private static final long serialVersionUID = -8303368287601871955L; public void execute() { + // if Propaganda is paid, tap this card + if(!crd.getKeyword().contains("Vigilance")) + crd.tap(); canAttack[0] = true; } }; @@ -959,13 +918,18 @@ public class CombatUtil { if(c.getController().isHuman()) { AllZone.InputControl.setInput(new Input_PayManaCost_Ability(c + " - Pay to Attack\r\n", ability.getManaCost(), paidCommand, unpaidCommand)); - } else //computer - { - if(ComputerUtil.canPayCost(ability)) ComputerUtil.playNoStack(ability); + } + else{ //computer + if(ComputerUtil.canPayCost(ability)){ + ComputerUtil.playNoStack(ability); + if(!crd.getKeyword().contains("Vigilance")) + crd.tap(); + } else { canAttack[0] = false; + // TODO: remove the below two lines after Propaganda occurs during Declare_Attackers AllZone.Combat.removeFromCombat(crd); - crd.untap(); + //crd.untap(); } } } @@ -1105,7 +1069,7 @@ public class CombatUtil { } }//Raging Ravine - if ((AllZone.Combat.getAttackers().length + AllZone.pwCombat.getAttackers().length) == 1) + if (AllZone.Combat.getAttackers().length == 1) { if (c.getKeyword().contains("Whenever this creature attacks alone, it gets +2/+0 until end of turn.") || c.getKeyword().contains("Whenever CARDNAME attacks alone, it gets +2/+0 until end of turn.")) @@ -1568,13 +1532,9 @@ public class CombatUtil { public void resolve() { CardList list = new CardList(); list.addAll(AllZone.Combat.getAttackers()); - list.addAll(AllZone.pwCombat.getAttackers()); - list = list.filter(new CardListFilter() { - public boolean addCard(Card card) { - return (!card.equals(piledriver) && card.isCreature() && (card.getType().contains( - "Goblin") || card.getKeyword().contains("Changeling"))); - } - }); + list = list.getType("Goblin"); + list.remove(piledriver); + final int otherGoblins = list.size(); final Command untilEOT = new Command() { diff --git a/src/forge/ComputerAI_General.java b/src/forge/ComputerAI_General.java index f42e9c96b5a..0de65a8e4d5 100644 --- a/src/forge/ComputerAI_General.java +++ b/src/forge/ComputerAI_General.java @@ -183,25 +183,17 @@ public class ComputerAI_General implements Computer { } public void declare_attackers() { - final Combat c = ComputerUtil.getAttackers(); - c.setAttackingPlayer(AllZone.Combat.getAttackingPlayer()); - c.setDefendingPlayer(AllZone.Combat.getDefendingPlayer()); - - //check for planeswalker - Card walker = AllZone.HumanPlayer.getPlaneswalker(); - - if(walker != null && MyRandom.random.nextBoolean()) { - c.setPlaneswalker(walker); - AllZone.pwCombat = c; - } else AllZone.Combat = c; - + // 12/2/10(sol) the decision making here has moved to getAttackers() + + AllZone.Combat = ComputerUtil.getAttackers(); - Card[] att = c.getAttackers(); + Card[] att = AllZone.Combat.getAttackers(); if (att.length > 0) AllZone.Phase.setCombat(true); for(int i = 0; i < att.length; i++) { - if(!att[i].getKeyword().contains("Vigilance")) att[i].tap(); + // tapping of attackers happens after Propaganda is paid for + //if(!att[i].getKeyword().contains("Vigilance")) att[i].tap(); Log.debug("Computer just assigned " + att[i].getName() + " as an attacker."); } @@ -218,24 +210,8 @@ public class ComputerAI_General implements Computer { public void declare_blockers() { CardList blockers = AllZoneUtil.getCreaturesInPlay(AllZone.ComputerPlayer); - - //If Player life is in danger protect it first - if(CombatUtil.lifeInDanger(AllZone.Combat)) { - AllZone.Combat = ComputerUtil_Block2.getBlockers(AllZone.Combat, blockers); - CardList remove = AllZone.Combat.getAllBlockers(); - for(int i = 0; i < remove.size(); i++) - blockers.remove(remove.get(i)); - - AllZone.pwCombat = ComputerUtil_Block2.getBlockers(AllZone.pwCombat, blockers); - } else { // Otherwise protect Planeswalkers first - AllZone.pwCombat = ComputerUtil_Block2.getBlockers(AllZone.pwCombat, blockers); - - CardList remove = AllZone.pwCombat.getAllBlockers(); - for(int i = 0; i < remove.size(); i++) - blockers.remove(remove.get(i)); - - AllZone.Combat = ComputerUtil_Block2.getBlockers(AllZone.Combat, blockers); - } + + AllZone.Combat = ComputerUtil_Block2.getBlockers(AllZone.Combat, blockers); CombatUtil.showCombat(); @@ -245,27 +221,7 @@ public class ComputerAI_General implements Computer { public void declare_blockers_after() { stackResponse(); } - - /* - private Combat getCombat(Card[] attackers, CardList availableBlockers) { - - - ComputerUtil_Block2 com = new ComputerUtil_Block2(attackers, availableBlockers.toArray(), - AllZone.ComputerPlayer.getLife()); - - Combat c = com.getBlockers(); - c.setAttackingPlayer(AllZone.Combat.getAttackingPlayer()); - c.setDefendingPlayer(AllZone.Combat.getDefendingPlayer()); - - - CardList attacks = new CardList(attackers); - - Combat c = ComputerUtil_Block2.getBlockers(attacks,availableBlockers); - - return c; - } - */ - + public void end_of_combat(){ stackResponse(); } diff --git a/src/forge/ComputerUtil.java b/src/forge/ComputerUtil.java index ef366ecbaff..b817cb477a6 100644 --- a/src/forge/ComputerUtil.java +++ b/src/forge/ComputerUtil.java @@ -743,7 +743,7 @@ public class ComputerUtil list = list.filter(new CardListFilter() { public boolean addCard(Card c) { - return c.isCreature() && CombatUtil.canAttack(c); + return CombatUtil.canAttack(c); } }); return list; diff --git a/src/forge/ComputerUtil_Attack2.java b/src/forge/ComputerUtil_Attack2.java index 7874f25ad5c..d3fb93fd92e 100644 --- a/src/forge/ComputerUtil_Attack2.java +++ b/src/forge/ComputerUtil_Attack2.java @@ -32,6 +32,7 @@ public class ComputerUtil_Attack2 { blockers = getPossibleBlockers(possibleBlockers); this.blockerLife = blockerLife; + // todo: get rid of valuable final ArrayList valuable = new ArrayList(); valuable.add("Kamahl, Pit Fighter"); valuable.add("Elvish Piper"); @@ -50,7 +51,7 @@ public class ComputerUtil_Attack2 { CardList list = new CardList(in.toArray()); list = list.filter(new CardListFilter() { - public boolean addCard(Card c) { return c.isCreature() && CombatUtil.canAttack(c); } + public boolean addCard(Card c) { return CombatUtil.canAttack(c); } }); return list; }//getUntappedCreatures() @@ -159,6 +160,24 @@ public class ComputerUtil_Attack2 { return blockerLife <= totalAttack; }//doAssault() + public void chooseDefender(Combat c, boolean bAssault){ + // TODO: split attackers to different planeswalker/human + // AI will only attack one Defender per combat for now + ArrayList defs = c.getDefenders(); + + if (defs.size() == 1 || bAssault){ + c.setCurrentDefender(0); + return; + } + + // Randomnly determine who EVERYONE is attacking + // would be better to determine more individually + int n = MyRandom.random.nextInt(defs.size()); + c.setCurrentDefender(n); + return; + } + + public Combat getAttackers() { //if this method is called multiple times during a turn, @@ -169,11 +188,19 @@ public class ComputerUtil_Attack2 { random.setSeed(AllZone.Phase.getTurn() + randomInt); Combat combat = new Combat(); + combat.setAttackingPlayer(AllZone.Combat.getAttackingPlayer()); + combat.setDefendingPlayer(AllZone.Combat.getDefendingPlayer()); + + combat.setDefenders(AllZone.Combat.getDefenders()); + + boolean bAssault = doAssault(); + // Determine who will be attacked + chooseDefender(combat, bAssault); CardList attackersLeft = new CardList(attackers.toArray()); //Atackers that don't really have a choice - for (int i=0; i= 3 || AllZoneUtil.isCardInPlay("Rafiq of the Many", AllZone.ComputerPlayer) || AllZoneUtil.getPlayerCardsInPlay(AllZone.ComputerPlayer, "Battlegrace Angel").size() >= 2 || - (AllZoneUtil.getPlayerCardsInPlay(AllZone.ComputerPlayer, "Finest Hour").size()>=1) && AllZone.Phase.isFirstCombat()) - && !doAssault()) + (AllZoneUtil.getPlayerCardsInPlay(AllZone.ComputerPlayer, "Finest Hour").size()>=1) && + AllZone.Phase.isFirstCombat()) + && !bAssault) { int biggest = 0; Card att = null; @@ -209,7 +237,7 @@ public class ComputerUtil_Attack2 { //do assault (all creatures attack) if the computer would win the game //or if the computer has 4 creatures and the player has 1 - else if(doAssault() || (humanList.size() == 1 && 3 < attackers.size())) + else if(bAssault || (humanList.size() == 1 && 3 < attackers.size())) { CardListUtil.sortAttack(attackersLeft); for(int i = 0; i < attackersLeft.size(); i++) @@ -254,32 +282,11 @@ public class ComputerUtil_Attack2 { } }//getAttackers() + + return combat; }//getAttackers() - /* - //returns null if no blockers found - public Card getBiggestAttack(Card attack) - { - CardListUtil.sortAttack(blockers); - for(int i = 0; i < blockers.size(); i++) - if(CombatUtil.canBlock(attack, blockers.get(i))) - return blockers.get(i); - - return null; - } - - //returns null if no blockers found - public Card getBiggestDefense(Card attack) - { - CardListUtil.sortDefense(blockers); - for(int i = 0; i < blockers.size(); i++) - if(CombatUtil.canBlock(attack, blockers.get(i))) - return blockers.get(i); - - return null; - }*/ - public int countExaltedBonus(Player player) { PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, player); @@ -348,9 +355,7 @@ public class ComputerUtil_Attack2 { if(CombatUtil.canAttack(c, combat)) attackersLeft.add(c); else if(CombatUtil.canBlock(c)) plannedBlockers.add(c); } - - - + return combat; } } diff --git a/src/forge/ComputerUtil_Block2.java b/src/forge/ComputerUtil_Block2.java index 38c2bc05289..f12401a99ca 100644 --- a/src/forge/ComputerUtil_Block2.java +++ b/src/forge/ComputerUtil_Block2.java @@ -1,6 +1,8 @@ package forge; +import java.util.ArrayList; + public class ComputerUtil_Block2 { @@ -481,7 +483,7 @@ public class ComputerUtil_Block2 if(CombatUtil.canBlock(attacker,blocker,combat)) blockers.add(blocker); } - return blockers; + return blockers; } //finds blockers that won't be destroyed @@ -493,7 +495,7 @@ public class ComputerUtil_Block2 if(!CombatUtil.canDestroyBlocker(b,attacker)) blockers.add(b); } - return blockers; + return blockers; } //finds blockers that destroy the attacker @@ -505,14 +507,49 @@ public class ComputerUtil_Block2 if(CombatUtil.canDestroyAttacker(attacker,b)) blockers.add(b); } - return blockers; + return blockers; } - public static Combat getBlockers(Combat originalCombat, CardList possibleBlockers) { + public static CardList sortPotentialAttackers(Combat combat){ + CardList[] attackerLists = combat.sortAttackerByDefender(); + CardList sortedAttackers = new CardList(); + + ArrayList defenders = combat.getDefenders(); + + // If I don't have any planeswalkers than sorting doesn't really matter + if (defenders.size() == 1) + return attackerLists[0]; + + boolean bLifeInDanger = CombatUtil.lifeInDanger(combat); + + // todo: Add creatures attacking Planeswalkers in order of which we want to protect + // defend planeswalkers with more loyalty before planeswalkers with less loyalty + // if planeswalker will be too difficult to defend don't even bother + for(int i = 1; i < attackerLists.length; i++){ + for(Card c : attackerLists[i]) + sortedAttackers.add(c); + } + + if(bLifeInDanger) { + // add creatures attacking the Player to the front of the list + for(Card c : attackerLists[0]) + sortedAttackers.add(0, c); + + } + else{ + // add creatures attacking the Player to the back of the list + for(Card c : attackerLists[0]) + sortedAttackers.add(c); + } + + return sortedAttackers; + } + + public static Combat getBlockers(Combat originalCombat, CardList possibleBlockers) { Combat combat = originalCombat; - CardList attackers = new CardList(combat.getAttackers()); + CardList attackers = sortPotentialAttackers(combat); if (attackers.size() == 0) return combat; @@ -564,8 +601,10 @@ public class ComputerUtil_Block2 if(!CombatUtil.canBlock(b, combat)) blockersLeft.remove(b); } + boolean bLifeInDanger = CombatUtil.lifeInDanger(combat); + //These creatures won't prevent any damage - if (CombatUtil.lifeInDanger(combat)) + if (bLifeInDanger) blockersLeft = blockersLeft.getNotKeyword("Whenever CARDNAME is dealt damage, you lose that much life."); if (blockersLeft.size() == 0) @@ -624,7 +663,7 @@ public class ComputerUtil_Block2 if(blockersLeft.size() == 0) return combat; //choose necessary trade blocks if life is in danger - if (CombatUtil.lifeInDanger(combat)) + if (bLifeInDanger) for(int i = 0; i < attackersLeft.size(); i++) { attacker = attackersLeft.get(i); killingBlockers = @@ -640,7 +679,7 @@ public class ComputerUtil_Block2 attackersLeft = new CardList(currentAttackers.toArray()); //choose necessary chump blocks if life is still in danger - if (CombatUtil.lifeInDanger(combat)) + if (bLifeInDanger) for(int i = 0; i < attackersLeft.size(); i++) { attacker = attackersLeft.get(i); chumpBlockers = getPossibleBlockers(attacker, blockersLeft, combat); @@ -656,7 +695,7 @@ public class ComputerUtil_Block2 attackersLeft = new CardList(currentAttackers.toArray()); //Reinforce blockers blocking attackers with trample if life is still in danger - if (CombatUtil.lifeInDanger(combat)) { + if (bLifeInDanger) { tramplingAttackers = attackers.getKeyword("Trample"); tramplingAttackers = tramplingAttackers.getKeywordsDontContain("Rampage"); //Don't make it worse tramplingAttackers = tramplingAttackers. diff --git a/src/forge/InputControl.java b/src/forge/InputControl.java index 862c217f14f..c1d9b0faac3 100644 --- a/src/forge/InputControl.java +++ b/src/forge/InputControl.java @@ -98,6 +98,7 @@ public class InputControl extends MyObservable implements java.io.Serializable { // Special Inputs needed for the following phases: if(phase.equals(Constant.Phase.Combat_Declare_Attackers)) { AllZone.Stack.freezeStack(); + if (playerTurn.isHuman()) return new Input_Attack(); } @@ -109,11 +110,7 @@ public class InputControl extends MyObservable implements java.io.Serializable { return null; } else{ - // test this. probably should just call Input_Block and let block pass along? if(AllZone.Combat.getAttackers().length == 0){ - if (AllZone.pwCombat.getAttackers().length != 0) - return new Input_Block_Planeswalker(); - // no active attackers, skip the Blocking phase AllZone.Phase.setNeedToNextPhase(true); return null; diff --git a/src/forge/Input_Attack.java b/src/forge/Input_Attack.java index c098b9e5cfa..2bdc24c0887 100644 --- a/src/forge/Input_Attack.java +++ b/src/forge/Input_Attack.java @@ -7,20 +7,31 @@ public class Input_Attack extends Input { @Override public void showMessage() { + // TODO: still seems to have some issues with multiple planeswalkers + ButtonUtil.enableOnlyOK(); - AllZone.Display.showMessage("Declare Attackers: Select creatures that you want to attack with"); + + Object o = AllZone.Combat.nextDefender(); + if (o == null){ + return; + } + + StringBuilder sb = new StringBuilder(); + sb.append("Declare Attackers: Select Creatures to Attack "); + sb.append(o.toString()); - PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, AllZone.HumanPlayer); - CardList creats = new CardList(play.getCards()); - creats = creats.getType("Creature"); + AllZone.Display.showMessage(sb.toString()); - if(getPlaneswalker() == null) { - for(int i = 0; i < creats.size(); i++) { - Card c = creats.get(i); - if(CombatUtil.canAttack(c) && c.getKeyword().contains("CARDNAME attacks each turn if able.")) { - + if(AllZone.Combat.getRemainingDefenders() == 0) { + // Nothing left to attack, has to attack this defender + CardList possibleAttackers = AllZoneUtil.getPlayerCardsInPlay(AllZone.HumanPlayer); + possibleAttackers = possibleAttackers.getType("Creature"); + for(int i = 0; i < possibleAttackers.size(); i++) { + Card c = possibleAttackers.get(i); + if(c.getKeyword().contains("CARDNAME attacks each turn if able.") && CombatUtil.canAttack(c) && !c.isAttacking()) { AllZone.Combat.addAttacker(c); - if(!c.getKeyword().contains("Vigilance")) c.tap(); + //if(!c.getKeyword().contains("Vigilance")) + // c.tap(); } } } @@ -30,38 +41,24 @@ public class Input_Attack extends Input { public void selectButtonOK() { if (AllZone.Combat.getAttackers().length > 0) AllZone.Phase.setCombat(true); - - Card check = getPlaneswalker(); - if(check == null) { - AllZone.Phase.setNeedToNextPhase(true); - } else { - AllZone.pwCombat.setPlaneswalker(check); - AllZone.InputControl.setInput(new Input_Attack_Planeswalker()); - } - } - //return Computer's planeswalker if there is one - //just returns 1, does not return multiple planeswalkers - private Card getPlaneswalker() { - CardList c = new CardList(AllZone.Computer_Battlefield.getCards()); - c = c.getType("Planeswalker"); - - if(c.isEmpty()) return null; - - return c.get(0); + if (AllZone.Combat.getRemainingDefenders() != 0) + AllZone.Phase.repeatPhase(); + + AllZone.Phase.setNeedToNextPhase(true); + AllZone.InputControl.resetInput(); } @Override public void selectCard(Card card, PlayerZone zone) { - if(zone.is(Constant.Zone.Battlefield, AllZone.HumanPlayer) && card.isCreature() && card.isUntapped() - && CombatUtil.canAttack(card)) { + if(zone.is(Constant.Zone.Battlefield, AllZone.HumanPlayer) && CombatUtil.canAttack(card) && !card.isAttacking()) { - if(!card.getKeyword().contains("Vigilance")) { - card.tap(); - //otherwise cards stay untapped, not sure why this is needed but it works - AllZone.Human_Battlefield.updateObservers(); - } + // todo add the propaganda code here and remove it in Phase.nextPhase() + // if (!CombatUtil.checkPropagandaEffects(card)) + // return; + AllZone.Combat.addAttacker(card); + AllZone.Human_Battlefield.updateObservers(); // just to make sure the attack symbol is marked //for Castle Raptors, since it gets a bonus if untapped for(String effect:AllZone.StaticEffects.getStateBasedMap().keySet()) { diff --git a/src/forge/Input_Attack_Planeswalker.java b/src/forge/Input_Attack_Planeswalker.java deleted file mode 100644 index 91258d94169..00000000000 --- a/src/forge/Input_Attack_Planeswalker.java +++ /dev/null @@ -1,60 +0,0 @@ - -package forge; - - -public class Input_Attack_Planeswalker extends Input { - private static final long serialVersionUID = 5738375759147611797L; - - @Override - public void showMessage() { - ButtonUtil.enableOnlyOK(); - AllZone.Display.showMessage("Planeswalker Declare Attackers:\r\nSelect creatures that you want to attack " - + AllZone.pwCombat.getPlaneswalker()); - - PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, AllZone.HumanPlayer); - CardList creats = new CardList(play.getCards()); - creats = creats.getType("Creature"); - CardList attackers = new CardList(AllZone.Combat.getAttackers()); - - for(int i = 0; i < creats.size(); i++) { - Card c = creats.get(i); - if(CombatUtil.canAttack(c) && c.getKeyword().contains("CARDNAME attacks each turn if able.") - && !attackers.contains(c)) { - AllZone.pwCombat.addAttacker(c); - if(!c.getKeyword().contains("Vigilance")) c.tap(); - } - } - } - - @Override - public void selectButtonOK() { - if (AllZone.pwCombat.getAttackers().length > 0) - AllZone.Phase.setCombat(true); - AllZone.Phase.setNeedToNextPhase(true); - this.stop(); - } - - @Override - public void selectCard(Card card, PlayerZone zone) { - if(zone.is(Constant.Zone.Battlefield, AllZone.HumanPlayer) && card.isCreature() && card.isUntapped() - && CombatUtil.canAttack(card)) { - if(!card.getKeyword().contains("Vigilance")) { - card.tap(); - - //otherwise cards stay untapped, not sure why this is needed but it works - AllZone.Human_Battlefield.updateObservers(); - } - AllZone.pwCombat.addAttacker(card); - - //for Castle Raptors, since it gets a bonus if untapped - for(String effect:AllZone.StaticEffects.getStateBasedMap().keySet()) { - Command com = GameActionUtil.commands.get(effect); - com.execute(); - } - - GameActionUtil.executeCardStateEffects(); - - CombatUtil.showCombat(); - } - }//selectCard() -} diff --git a/src/forge/Input_Block.java b/src/forge/Input_Block.java index 900503a2819..76fc537f2d0 100644 --- a/src/forge/Input_Block.java +++ b/src/forge/Input_Block.java @@ -52,15 +52,10 @@ public class Input_Block extends Input { @Override public void selectButtonOK() { + // Done blocking ButtonUtil.reset(); - if(AllZone.pwCombat.getAttackers().length == 0) { - - //AllZone.Phase.nextPhase(); - //for debugging: System.out.println("need to nextPhase(Input_Cleanup.showMessage(), n<=7) = true"); - AllZone.Phase.setNeedToNextPhase(true); - } else { - AllZone.InputControl.setInput(new Input_Block_Planeswalker()); - } + + AllZone.Phase.setNeedToNextPhase(true); } @Override diff --git a/src/forge/Input_Block_Planeswalker.java b/src/forge/Input_Block_Planeswalker.java deleted file mode 100644 index 9ec53bdb2ac..00000000000 --- a/src/forge/Input_Block_Planeswalker.java +++ /dev/null @@ -1,78 +0,0 @@ - -package forge; - - -import java.util.ArrayList; - - -public class Input_Block_Planeswalker extends Input { - private static final long serialVersionUID = 8504632360578751473L; - - private Card currentAttacker = null; - private ArrayList allBlocking = new ArrayList(); - - @Override - public void showMessage() { - //for Castle Raptors, since it gets a bonus if untapped - for(String effect:AllZone.StaticEffects.getStateBasedMap().keySet()) { - Command com = GameActionUtil.commands.get(effect); - com.execute(); - } - GameActionUtil.executeCardStateEffects(); - - //could add "Reset Blockers" button - ButtonUtil.enableOnlyOK(); - - if(currentAttacker == null) { - //Lure - CardList attackers = new CardList(AllZone.Combat.getAttackers()); - for(Card attacker:attackers) { - if(attacker.hasKeyword("All creatures able to block CARDNAME do so.")) { - CardList bls = AllZoneUtil.getCreaturesInPlay(AllZone.HumanPlayer); - for(Card bl:bls) { - if(CombatUtil.canBlock(attacker, bl, AllZone.Combat)) { - allBlocking.add(bl); - AllZone.Combat.addBlocker(attacker, bl); - } - } - } - } - - AllZone.Display.showMessage("Planeswalker Combat\r\nTo Block, click on your Opponents attacker first , then your blocker(s)"); - } - else { - String attackerName = currentAttacker.isFaceDown() ? "Morph" : currentAttacker.getName(); - AllZone.Display.showMessage("Select a creature to block " + attackerName + " (" - + currentAttacker.getUniqueNumber() + ") "); - } - - CombatUtil.showCombat(); - } - - @Override - public void selectButtonOK() { - if (AllZone.Combat.getAttackers().length > 0) - AllZone.Phase.setCombat(true); - ButtonUtil.reset(); - - //AllZone.Phase.nextPhase(); - //for debugging: System.out.println("need to nextPhase(Input_Block_Planeswalker.selectButtonOK) = true; Note, this has not been tested, did it work?"); - AllZone.Phase.setNeedToNextPhase(true); - this.stop(); - } - - @Override - public void selectCard(Card card, PlayerZone zone) { - //is attacking? - if(CardUtil.toList(AllZone.pwCombat.getAttackers()).contains(card)) { - currentAttacker = card; - } else if(zone.is(Constant.Zone.Battlefield, AllZone.HumanPlayer) && card.isCreature() - && CombatUtil.canBlock(currentAttacker, card, AllZone.Combat)) { - if(currentAttacker != null && (!allBlocking.contains(card))) { - allBlocking.add(card); - AllZone.pwCombat.addBlocker(currentAttacker, card); - } - } - showMessage(); - }//selectCard() -} diff --git a/src/forge/Phase.java b/src/forge/Phase.java index 0fe32d0bbfc..a29fe2bc56e 100644 --- a/src/forge/Phase.java +++ b/src/forge/Phase.java @@ -191,8 +191,7 @@ public class Phase extends MyObservable else if(phase.equals(Constant.Phase.Combat_Begin)){ if (AllZone.Display.stopAtPhase(turn, phase)){ - AllZone.Combat.verifyCreaturesInPlay(); - CombatUtil.showCombat(); + PhaseUtil.verifyCombat(); } else { this.setNeedToNextPhase(true); @@ -201,8 +200,7 @@ public class Phase extends MyObservable else if (phase.equals(Constant.Phase.Combat_Declare_Attackers_InstantAbility)){ if(inCombat()) { - AllZone.Combat.verifyCreaturesInPlay(); - CombatUtil.showCombat(); + PhaseUtil.handleDeclareAttackers(); } else AllZone.Phase.setNeedToNextPhase(true); @@ -211,8 +209,7 @@ public class Phase extends MyObservable // we can skip AfterBlockers and AfterAttackers if necessary else if(phase.equals(Constant.Phase.Combat_Declare_Blockers)){ if(inCombat()) { - AllZone.Combat.verifyCreaturesInPlay(); - CombatUtil.showCombat(); + PhaseUtil.verifyCombat(); } else AllZone.Phase.setNeedToNextPhase(true); @@ -223,40 +220,7 @@ public class Phase extends MyObservable if(!inCombat()) AllZone.Phase.setNeedToNextPhase(true); else{ - AllZone.Combat.verifyCreaturesInPlay(); - - AllZone.Stack.freezeStack(); - CardList list = new CardList(); - list.addAll(AllZone.Combat.getAllBlockers().toArray()); - list.addAll(AllZone.pwCombat.getAllBlockers().toArray()); - list = list.filter(new CardListFilter(){ - public boolean addCard(Card c) - { - return !c.getCreatureBlockedThisCombat(); - } - }); - - CardList attList = new CardList(); - attList.addAll(AllZone.Combat.getAttackers()); - - CardList pwAttList = new CardList(); - pwAttList.addAll(AllZone.pwCombat.getAttackers()); - - CombatUtil.checkDeclareBlockers(list); - - for (Card a:attList){ - CardList blockList = AllZone.Combat.getBlockers(a); - for (Card b:blockList) - CombatUtil.checkBlockedAttackers(a, b); - } - - for (Card a:pwAttList){ - CardList blockList = AllZone.pwCombat.getBlockers(a); - for (Card b:blockList) - CombatUtil.checkBlockedAttackers(a, b); - } - AllZone.Stack.unfreezeStack(); - CombatUtil.showCombat(); + PhaseUtil.handleDeclareBlockers(); } } @@ -265,10 +229,8 @@ public class Phase extends MyObservable AllZone.Phase.setNeedToNextPhase(true); else{ AllZone.Combat.verifyCreaturesInPlay(); - AllZone.pwCombat.verifyCreaturesInPlay(); AllZone.Combat.setAssignedFirstStrikeDamage(); - AllZone.pwCombat.setAssignedFirstStrikeDamage(); if (!AllZone.GameInfo.isPreventCombatDamageThisTurn()) Combat.dealAssignedDamage(); @@ -283,10 +245,8 @@ public class Phase extends MyObservable AllZone.Phase.setNeedToNextPhase(true); else{ AllZone.Combat.verifyCreaturesInPlay(); - AllZone.pwCombat.verifyCreaturesInPlay(); AllZone.Combat.setAssignedDamage(); - AllZone.pwCombat.setAssignedDamage(); if (!AllZone.GameInfo.isPreventCombatDamageThisTurn()) Combat.dealAssignedDamage(); @@ -350,33 +310,6 @@ public class Phase extends MyObservable if (getPhase().equals(Constant.Phase.Combat_Declare_Attackers)) { AllZone.Stack.unfreezeStack(); nCombatsThisTurn++; - CardList list = new CardList(); - list.addAll(AllZone.Combat.getAttackers()); - - // Remove illegal Propaganda attacks first only for attacking the Player - for(Card c:list) - CombatUtil.checkPropagandaEffects(c); - - list.addAll(AllZone.pwCombat.getAttackers()); - - // Then run other Attacker bonuses - //check for exalted: - if (list.size() == 1){ - AllZone.GameAction.checkWheneverKeyword(list.get(0), "Attack - Alone", null); - Player attackingPlayer = AllZone.Combat.getAttackingPlayer(); - PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, attackingPlayer); - CardList exalted = new CardList(play.getCards()); - exalted = exalted.filter(new CardListFilter() { - public boolean addCard(Card c) { - return c.getKeyword().contains("Exalted"); - } - }); - if(exalted.size() > 0) CombatUtil.executeExaltedAbility(list.get(0), exalted.size()); - // Make sure exalted effects get applied only once per combat - } - - for(Card c:list) - CombatUtil.checkDeclareAttackers(c); } else if (getPhase().equals(Constant.Phase.Untap)) { nCombatsThisTurn = 0; @@ -384,7 +317,6 @@ public class Phase extends MyObservable if (getPhase().equals(Constant.Phase.Combat_End)) { AllZone.Combat.reset(); - AllZone.pwCombat.reset(); AllZone.Display.showCombat(""); resetAttackedThisCombat(getPlayerTurn()); this.bCombat = false; @@ -410,9 +342,6 @@ public class Phase extends MyObservable AllZone.Combat.reset(); AllZone.Combat.setAttackingPlayer(player); AllZone.Combat.setDefendingPlayer(opp); - AllZone.pwCombat.reset(); - AllZone.Combat.setAttackingPlayer(player); - AllZone.Combat.setDefendingPlayer(opp); phaseIndex = findIndex(Constant.Phase.Combat_Declare_Attackers); } else { diff --git a/src/forge/PhaseUtil.java b/src/forge/PhaseUtil.java index c476634fd74..7a8ebf40ebe 100644 --- a/src/forge/PhaseUtil.java +++ b/src/forge/PhaseUtil.java @@ -30,10 +30,6 @@ public class PhaseUtil { AllZone.Combat.setAttackingPlayer(turn); AllZone.Combat.setDefendingPlayer(turn.getOpponent()); - AllZone.pwCombat.reset(); - AllZone.pwCombat.setAttackingPlayer(turn); - AllZone.pwCombat.setDefendingPlayer(turn.getOpponent()); - // For tokens a player starts the game with they don't recover from Sum. Sickness on first turn if (turn.getTurn() > 0){ for(int i = 0; i < c.length; i++) @@ -349,6 +345,77 @@ public class PhaseUtil { return false; } + // ********* Declare Attackers *********** + + public static void verifyCombat(){ + AllZone.Combat.verifyCreaturesInPlay(); + CombatUtil.showCombat(); + } + + public static void handleDeclareAttackers(){ + verifyCombat(); + CardList list = new CardList(); + list.addAll(AllZone.Combat.getAttackers()); + + // TODO move propaganda to happen as the Attacker is Declared + // Remove illegal Propaganda attacks first only for attacking the Player + for(Card c:list) + CombatUtil.checkPropagandaEffects(c); + + AllZone.Stack.freezeStack(); + // Then run other Attacker bonuses + //check for exalted: + if (list.size() == 1){ + AllZone.GameAction.checkWheneverKeyword(list.get(0), "Attack - Alone", null); + Player attackingPlayer = AllZone.Combat.getAttackingPlayer(); + PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, attackingPlayer); + CardList exalted = new CardList(play.getCards()); + exalted = exalted.filter(new CardListFilter() { + public boolean addCard(Card c) { + return c.getKeyword().contains("Exalted"); + } + }); + if(exalted.size() > 0) CombatUtil.executeExaltedAbility(list.get(0), exalted.size()); + // Make sure exalted effects get applied only once per combat + } + + for(Card c:list) + CombatUtil.checkDeclareAttackers(c); + AllZone.Stack.unfreezeStack(); + } + + public static void handleDeclareBlockers(){ + verifyCombat(); + + AllZone.Stack.freezeStack(); + CardList list = new CardList(); + list.addAll(AllZone.Combat.getAllBlockers().toArray()); + + list = list.filter(new CardListFilter(){ + public boolean addCard(Card c) + { + return !c.getCreatureBlockedThisCombat(); + } + }); + + CardList attList = new CardList(); + attList.addAll(AllZone.Combat.getAttackers()); + + CombatUtil.checkDeclareBlockers(list); + + for (Card a:attList){ + CardList blockList = AllZone.Combat.getBlockers(a); + for (Card b:blockList) + CombatUtil.checkBlockedAttackers(a, b); + } + + AllZone.Stack.unfreezeStack(); + CombatUtil.showCombat(); + } + + + // ***** Combat Utility ********** + // todo: the below functions should be removed and the code blocks that use them should instead use SA_Restriction public static boolean isBeforeAttackersAreDeclared() { String phase = AllZone.Phase.getPhase(); return phase.equals(Constant.Phase.Untap) || phase.equals(Constant.Phase.Upkeep)