From 5f508e5d17087b798402a2b1048e579aa405a669 Mon Sep 17 00:00:00 2001 From: Sol Date: Fri, 14 Jun 2013 15:19:21 +0000 Subject: [PATCH] - Human may now declare attacks in a band - Added Benalish Hero --- .gitattributes | 1 + res/cardsfolder/b/benalish_hero.txt | 7 ++ src/main/java/forge/game/phase/Combat.java | 24 +++++- .../java/forge/gui/input/InputAttack.java | 79 +++++++++++++++++-- .../forge/gui/match/controllers/CCombat.java | 28 ++++--- 5 files changed, 119 insertions(+), 20 deletions(-) create mode 100644 res/cardsfolder/b/benalish_hero.txt diff --git a/.gitattributes b/.gitattributes index 291efde6a81..3d3846459f7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -912,6 +912,7 @@ res/cardsfolder/b/benalish_cavalry.txt svneol=native#text/plain res/cardsfolder/b/benalish_commander.txt -text res/cardsfolder/b/benalish_emissary.txt svneol=native#text/plain res/cardsfolder/b/benalish_heralds.txt svneol=native#text/plain +res/cardsfolder/b/benalish_hero.txt -text res/cardsfolder/b/benalish_knight.txt svneol=native#text/plain res/cardsfolder/b/benalish_lancer.txt -text res/cardsfolder/b/benalish_missionary.txt svneol=native#text/plain diff --git a/res/cardsfolder/b/benalish_hero.txt b/res/cardsfolder/b/benalish_hero.txt new file mode 100644 index 00000000000..4f5b01f4afa --- /dev/null +++ b/res/cardsfolder/b/benalish_hero.txt @@ -0,0 +1,7 @@ +Name:Benalish Hero +ManaCost:W +Types:Creature Human Soldier +PT:1/1 +K:Banding +SVar:Picture:http://www.wizards.com/global/images/magic/general/benalish_hero.jpg +Oracle:Banding (Any creatures with banding, and up to one without, can attack in a band. Bands are blocked as a group. If any creatures with banding you control are blocking or being blocked by a creature, you divide that creature's combat damage, not its controller, among any of the creatures it's being blocked by or is blocking.) diff --git a/src/main/java/forge/game/phase/Combat.java b/src/main/java/forge/game/phase/Combat.java index 8d0b2c92823..6bd959d9e99 100644 --- a/src/main/java/forge/game/phase/Combat.java +++ b/src/main/java/forge/game/phase/Combat.java @@ -206,6 +206,16 @@ public class Combat { public final List getAttackersOf(GameEntity defender) { return defenderMap.get(defender); } + + public final List getAttackingBandsOf(GameEntity defender) { + List bands = new ArrayList(); + for(AttackingBand band : this.attackingBands) { + if (band.getDefender().equals(defender)) { + bands.add(band); + } + } + return bands; + } /** *

@@ -503,11 +513,17 @@ public class Combat { this.blockerToBandsMap.get(b).remove(c); } // Clear removed attacker from assignment order - this.blockerDamageAssignmentOrder.get(b).remove(c); + if (this.blockerDamageAssignmentOrder.containsKey(b)) { + this.blockerDamageAssignmentOrder.get(b).remove(c); + } } this.defenderMap.get(band.getDefender()).remove(c); - } else if (this.blockerDamageAssignmentOrder.containsKey(c)) { // card is a blocker + + if (band.getAttackers().isEmpty() && band.getBlockers().isEmpty()) { + this.getAttackingBands().remove(band); + } + } else if (this.blockerToBandsMap.containsKey(c)) { // card is a blocker List attackers = this.blockerToBandsMap.get(c); this.blockerToBandsMap.remove(c); @@ -515,7 +531,9 @@ public class Combat { for (AttackingBand a : attackers) { a.removeBlocker(c); for(Card atk : a.getAttackers()) { - this.attackerDamageAssignmentOrder.get(atk).remove(c); + if (this.attackerDamageAssignmentOrder.containsKey(atk)) { + this.attackerDamageAssignmentOrder.get(atk).remove(c); + } } } } diff --git a/src/main/java/forge/gui/input/InputAttack.java b/src/main/java/forge/gui/input/InputAttack.java index 46d6c45ccf7..fe233ed3170 100644 --- a/src/main/java/forge/gui/input/InputAttack.java +++ b/src/main/java/forge/gui/input/InputAttack.java @@ -26,6 +26,7 @@ import com.google.common.collect.Iterables; import forge.Card; import forge.CardPredicates; import forge.GameEntity; +import forge.game.combat.AttackingBand; import forge.game.phase.Combat; import forge.game.phase.CombatUtil; import forge.game.player.Player; @@ -52,6 +53,7 @@ public class InputAttack extends InputSyncronizedBase { private GameEntity currentDefender; private final Player playerAttacks; private final Player playerDeclares; + private AttackingBand activeBand = null; public InputAttack(Player attacks, Player declares, Combat combat) { this.playerAttacks = attacks; @@ -97,8 +99,10 @@ public class InputAttack extends InputSyncronizedBase { /** {@inheritDoc} */ @Override protected final void onOk() { + // TODO Add check to see if each must attack creature is attacking // Propaganda costs could have been paid here. setCurrentDefender(null); // remove highlights + activateBand(null); stop(); } @@ -115,12 +119,33 @@ public class InputAttack extends InputSyncronizedBase { protected final void onCardSelected(final Card card, boolean isMetaDown) { final List att = combat.getAttackers(); if (isMetaDown && att.contains(card) && !card.hasKeyword("CARDNAME attacks each turn if able.")) { + // TODO Is there no way to attacks each turn cards to attack Planeswalkers? combat.removeFromCombat(card); + card.setUsedToPay(false); showCombat(); + // When removing an attacker should I clear the attacking band? + this.activateBand(this.activeBand); return; } if (card.isAttacking(currentDefender)) { + // Activate band by selecting/deselecting a band member + if (this.activeBand == null) { + this.activateBand(combat.getBandByAttacker(card)); + } else if (this.activeBand.getAttackers().contains(card)) { + this.activateBand(null); + } else { // Join a band by selecting a non-active band member after activating a band + if (this.activeBand.canJoinBand(card)) { + combat.removeFromCombat(card); + combat.addAttacker(card, currentDefender, this.activeBand); + this.activateBand(this.activeBand); + updateMessage(); + } else { + flashIncorrectAction(); + } + } + + updateMessage(); return; } @@ -132,10 +157,20 @@ public class InputAttack extends InputSyncronizedBase { } if (playerAttacks.getZone(ZoneType.Battlefield).contains(card) && CombatUtil.canAttack(card, currentDefender, combat)) { - if( combat.isAttacking(card)) { - combat.removeFromCombat(card); + if (this.activeBand != null && !this.activeBand.canJoinBand(card)) { + this.activateBand(null); + updateMessage(); + flashIncorrectAction(); + return; } - combat.addAttacker(card, currentDefender); + + if(combat.isAttacking(card)) { + combat.removeFromCombat(card); + } + + combat.addAttacker(card, currentDefender, this.activeBand); + this.activateBand(this.activeBand); + updateMessage(); showCombat(); } else { @@ -157,13 +192,45 @@ public class InputAttack extends InputSyncronizedBase { } } - String header = playerAttacks == playerDeclares ? "declare attackers." : "declare attackers for " + playerAttacks.getName(); - showMessage(playerDeclares.getName() + ", " + header + "\nSelecting Creatures to Attack " + currentDefender + - "\n\nTo attack other players or their planewalkers just click on them"); + updateMessage(); // This will instantly highlight targets for(MyObservable updateable : toUpdate) { updateable.updateObservers(); } } + + private final void activateBand(AttackingBand band) { + Set toUpdate = new HashSet(); + if (this.activeBand != null) { + for(Card card : this.activeBand.getAttackers()) { + card.setUsedToPay(false); + toUpdate.add(card.getController().getZone(ZoneType.Battlefield)); + } + } + this.activeBand = band; + + if (this.activeBand != null) { + for(Card card : this.activeBand.getAttackers()) { + card.setUsedToPay(true); + toUpdate.add(card.getController().getZone(ZoneType.Battlefield)); + } + } + + // This will instantly highlight targets + for(MyObservable updateable : toUpdate) { + updateable.updateObservers(); + } + } + + private void updateMessage() { + StringBuilder sb = new StringBuilder(); + sb.append(playerDeclares.getName()).append(", "); + sb.append(playerAttacks == playerDeclares ? "declare attackers." : "declare attackers for " + playerAttacks.getName()).append("\n"); + sb.append("Selecting Creatures to Attack ").append(currentDefender).append("\n\n"); + sb.append("To change the current defender, click on the player or planeswalker you wish to attack.\n"); + sb.append("To attack as a band, click an attacking creature to activate its 'band', select another to join the band."); + + showMessage(sb.toString()); + } } diff --git a/src/main/java/forge/gui/match/controllers/CCombat.java b/src/main/java/forge/gui/match/controllers/CCombat.java index 34ec796b0cf..623ee8b7d94 100644 --- a/src/main/java/forge/gui/match/controllers/CCombat.java +++ b/src/main/java/forge/gui/match/controllers/CCombat.java @@ -6,6 +6,7 @@ import forge.Card; import forge.Command; import forge.GameEntity; import forge.game.Game; +import forge.game.combat.AttackingBand; import forge.game.phase.Combat; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; @@ -70,8 +71,8 @@ public enum CCombat implements ICDoc { // Not a big fan of the triple nested loop here for (GameEntity defender : combat.getDefenders()) { - List atk = combat.getAttackersOf(defender); - if (atk == null || atk.isEmpty()) { + List bands = combat.getAttackingBandsOf(defender); + if (bands == null || bands.isEmpty()) { continue; } @@ -86,18 +87,23 @@ public enum CCombat implements ICDoc { display.append(defender.getName()).append(" is attacked by:\n"); - for (final Card c : atk) { - // loop through attackers - display.append(" > "); - display.append(combatantToString(c)).append("\n"); + // Associate Bands, Attackers Blockers + for(AttackingBand band : bands) { + display.append(" BAND"); + if (band.getBlocked()) { + display.append(" (blocked)"); + } + display.append("\n"); + + for (final Card c : band.getAttackers()) { + display.append(" > "); + display.append(combatantToString(c)).append("\n"); + } - List blockers = combat.getBlockers(c, true); - - // loop through blockers - for (final Card element : blockers) { + for (final Card element : band.getBlockers()) { display.append(" < ").append(combatantToString(element)).append("\n"); } - } // loop through attackers + } } return display.toString().trim(); }