From ebdccf3f8b9636a6872cd669687f1a9c65abde2c Mon Sep 17 00:00:00 2001 From: jendave Date: Sat, 6 Aug 2011 14:59:11 +0000 Subject: [PATCH] - Cleanup of combat damage assignment. Fixed a bug with Double Strike. - Improved the AI handling of trampling creatures. --- src/forge/Card.java | 25 +++++++ src/forge/Combat.java | 144 ++++++++++++++++++++----------------- src/forge/GuiDisplay3.java | 7 +- src/forge/GuiDisplay4.java | 9 +-- 4 files changed, 106 insertions(+), 79 deletions(-) diff --git a/src/forge/Card.java b/src/forge/Card.java index a1817b653d8..c62978d4808 100644 --- a/src/forge/Card.java +++ b/src/forge/Card.java @@ -2832,6 +2832,31 @@ public class Card extends MyObservable { receivedDamageFromThisTurn.clear(); } + //how much damage is enough to kill the creature (for AI) + public int getEnoughDamageToKill(int maxDamage, Card source, boolean isCombat) { + + int killDamage = getKillDamage(); + + if(getKeyword().contains("Indestructible") || getShield() > 0) { + if(!(source.getKeyword().contains("Wither") || source.getKeyword().contains("Infect"))) + return maxDamage + 1; + } + else + if(source.getKeyword().contains("Deathtouch") + || source.getKeyword().contains("Whenever CARDNAME deals combat damage to a creature, destroy that creature")) + for(int i=1; i < maxDamage+1;i++) { + if (predictDamage(i, source, isCombat) > 0) + return i; + } + + for(int i=1; i < maxDamage+1;i++) { + if (predictDamage(i, source, isCombat) >= killDamage) + return i; + } + + return maxDamage + 1; + } + //the amount of damage needed to kill the creature (for AI) public int getKillDamage() { int killDamage = getLethalDamage() + preventNextDamage; diff --git a/src/forge/Combat.java b/src/forge/Combat.java index 772d2a2d8a8..54d5618bbb4 100644 --- a/src/forge/Combat.java +++ b/src/forge/Combat.java @@ -10,7 +10,7 @@ public class Combat { private Set blocked = new HashSet(); private HashMap unblockedMap = new HashMap(); - private HashMap defendingFirstStrikeDamageMap = new HashMap(); + //private HashMap defendingFirstStrikeDamageMap = new HashMap(); private HashMap defendingDamageMap = new HashMap(); // Defenders are the Defending Player + Each Planeswalker that player controls @@ -41,7 +41,7 @@ public class Combat { attackingDamage = 0; defendingDamageMap.clear(); - defendingFirstStrikeDamageMap.clear(); + //defendingFirstStrikeDamageMap.clear(); attackingPlayer = null; defendingPlayer = null; @@ -163,11 +163,13 @@ public class Combat { public HashMap getDefendingDamageMap() { return defendingDamageMap; } - + + /* public HashMap getDefendingFirstStrikeDamageMap() { return defendingFirstStrikeDamageMap; } - + */ + public int getTotalDefendingDamage() { int total = 0; @@ -179,7 +181,8 @@ public class Combat { return total; } - + + /* public int getTotalFirstStrikeDefendingDamage() { int total = 0; @@ -191,7 +194,8 @@ public class Combat { return total; } - + */ + public void setDefendingDamage() { defendingDamageMap.clear(); CardList att = new CardList(getAttackers()); @@ -211,7 +215,8 @@ public class Combat { } // ! isBlocked... }// for } - + + /* public void setDefendingFirstStrikeDamage() { defendingFirstStrikeDamageMap.clear(); CardList att = new CardList(getAttackers()); @@ -231,6 +236,7 @@ public class Combat { } } // for } + */ public void addDefendingDamage(int n, Card source) { String slot = getDefenderByAttacker(source).toString(); @@ -249,7 +255,8 @@ public class Combat { defendingDamageMap.put(source, defendingDamageMap.get(source) + n); } } - + + /* public void addDefendingFirstStrikeDamage(int n, Card source) { String slot = getDefenderByAttacker(source).toString(); Object o = defenders.get(Integer.parseInt(slot)); @@ -268,6 +275,7 @@ public class Combat { defendingFirstStrikeDamageMap.get(source) + n); } } + */ public void addAttackingDamage(int n) { attackingDamage += n; @@ -388,7 +396,7 @@ public class Combat { // also assigns player damage by setPlayerDamage() public void setAssignedFirstStrikeDamage() { - setDefendingFirstStrikeDamage(); + //setDefendingFirstStrikeDamage(); CardList block; CardList attacking = new CardList(getAttackers()); @@ -396,51 +404,39 @@ public class Combat { for (int i = 0; i < attacking.size(); i++) { - block = getBlockers(attacking.get(i)); + Card attacker = attacking.get(i); + block = getBlockers(attacker); + - int damageDealt = attacking.get(i).getNetCombatDamage(); + int damageDealt = attacker.getNetCombatDamage(); // attacker always gets all blockers' attack for (Card b : block) { if (b.hasFirstStrike() || b.hasDoubleStrike()) { - attacking.get(i).addAssignedDamage(damageDealt, b); + attacker.addAssignedDamage(damageDealt, b); } } if (block.size() == 0){ // this damage is assigned to a player by setPlayerDamage() - addUnblockedAttacker(attacking.get(i)); + addUnblockedAttacker(attacker); } - else if (attacking.get(i).hasFirstStrike() || attacking.get(i).hasDoubleStrike()) { + else if (attacker.hasFirstStrike() || attacker.hasDoubleStrike()) { if (getAttackingPlayer().isHuman()) {// human attacks - AllZone.Display.assignDamage(attacking.get(i), block, damageDealt); + AllZone.Display.assignDamage(attacker, block, damageDealt); } else {// computer attacks - if (block.size() == 1) { - - int trample = damageDealt - block.get(0).getKillDamage(); - - // trample - if (attacking.get(i).getKeyword().contains("Trample") && 0 < trample) { - block.get(0).addAssignedDamage(block.get(0).getKillDamage(), attacking.get(i)); - this.addDefendingDamage(trample, attacking.get(i)); - } - else block.get(0).addAssignedDamage(damageDealt, attacking.get(i)); - }// 1 blocker - else { - distributeAIDamage(attacking.get(i), block, damageDealt); - } - } //Computer - + distributeAIDamage(attacker, block, damageDealt); + } }// if(hasFirstStrike || doubleStrike) }// for }// setAssignedFirstStrikeDamage() /* - private void addAssignedFirstStrikeDamage(Card attacker, CardList block, int damage) { + private void distributeAIFirstStrikeDamage(Card attacker, CardList block, int damage) { Card c = attacker; for (Card b : block) { @@ -496,21 +492,8 @@ public class Combat { AllZone.Display.assignDamage(attacking.get(i), block, damageDealt); } else {// computer attacks - if (block.size() == 1) { - - int trample = damageDealt - block.get(0).getKillDamage(); - - // trample - if (attacking.get(i).getKeyword().contains("Trample") && 0 < trample) { - block.get(0).addAssignedDamage(block.get(0).getKillDamage(), attacking.get(i)); - this.addDefendingDamage(trample, attacking.get(i)); - } - else block.get(0).addAssignedDamage(damageDealt, attacking.get(i)); - }// 1 blocker - else { distributeAIDamage(attacking.get(i), block, damageDealt); - } - } //Computer + } }// if !hasFirstStrike ... }// for @@ -520,25 +503,55 @@ public class Combat { private void distributeAIDamage(Card attacker, CardList block, int damage) { Card c = attacker; - for (Card b : block) { - if (b.getKillDamage() <= damage) { - damage -= b.getKillDamage(); - CardList cl = new CardList(); - cl.add(attacker); - - b.addAssignedDamage(b.getKillDamage(), c); - // c.setAssignedDamage(c.getKillDamage()); + + if (block.size() == 1) { + + Card blocker = block.get(0); + + // trample + if (attacker.getKeyword().contains("Trample")) { + + int damageNeeded = 0; + + //TODO: if the human can be killed distribute only the minimum of damage on the blocker + + damageNeeded = blocker.getEnoughDamageToKill(damage, attacker, true); + + if (damageNeeded > damage) + damageNeeded = blocker.getLethalDamage(); + else + damageNeeded = Math.min(blocker.getLethalDamage(),damageNeeded); + + int trample = damage - damageNeeded; + + if (0 < trample) { + blocker.addAssignedDamage(damageNeeded, attacker); + this.addDefendingDamage(trample, attacker); + } + } + else blocker.addAssignedDamage(damage, attacker); + }// 1 blocker + else { + for (Card b : block) { + if (b.getKillDamage() <= damage) { + damage -= b.getKillDamage(); + CardList cl = new CardList(); + cl.add(attacker); + + b.addAssignedDamage(b.getKillDamage(), c); + // c.setAssignedDamage(c.getKillDamage()); + } + }// for + + // if attacker has no trample, and there's damage left, assign the rest + // to a random blocker + if (damage > 0 && !c.getKeyword().contains("Trample")) { + int index = CardUtil.getRandomIndex(block); + block.get(index).addAssignedDamage(damage, c); + damage = 0; + } else if (c.getKeyword().contains("Trample")) { + this.addDefendingDamage(damage, c); } - }// for - - // if attacker has no trample, and there's damage left, assign the rest - // to a random blocker - if (damage > 0 && !c.getKeyword().contains("Trample")) { - int index = CardUtil.getRandomIndex(block); - block.get(index).addAssignedDamage(damage, c); - damage = 0; - } else if (c.getKeyword().contains("Trample")) { - this.addDefendingDamage(damage, c); } }// setAssignedDamage() @@ -548,8 +561,7 @@ public class Combat { boolean bFirstStrike = AllZone.Phase.is(Constant.Phase.Combat_FirstStrikeDamage); - HashMap defMap = bFirstStrike ? AllZone.Combat.getDefendingFirstStrikeDamageMap() : - AllZone.Combat.getDefendingDamageMap(); + HashMap defMap = AllZone.Combat.getDefendingDamageMap(); for(Entry entry : defMap.entrySet()) { player.addCombatDamage(entry.getValue(), entry.getKey()); diff --git a/src/forge/GuiDisplay3.java b/src/forge/GuiDisplay3.java index aeeaf2b284a..16fabe9b525 100644 --- a/src/forge/GuiDisplay3.java +++ b/src/forge/GuiDisplay3.java @@ -1359,12 +1359,7 @@ class Gui_MultipleBlockers3 extends JFrame { if (c.getName().equals("Player") && att.getKeyword().contains("Trample") && assignedLethalDamageToAllBlockers) { - //what happens with Double Strike??? - if (att.getKeyword().contains("First Strike")) - AllZone.Combat.addDefendingFirstStrikeDamage(1, att); - else - AllZone.Combat.addDefendingDamage(1, att); - + AllZone.Combat.addDefendingDamage(1, att); c.addAssignedDamage(1, att); } else if (!c.getName().equals("Player")){ diff --git a/src/forge/GuiDisplay4.java b/src/forge/GuiDisplay4.java index 92759738666..e317eadf360 100644 --- a/src/forge/GuiDisplay4.java +++ b/src/forge/GuiDisplay4.java @@ -1333,19 +1333,14 @@ class Gui_MultipleBlockers4 extends JFrame { boolean assignedLethalDamageToAllBlockers = true; for (Card crd : blockers ) { - if (crd.getTotalAssignedDamage() < ( crd.getNetDefense() - crd.getDamage() )) + if (crd.getLethalDamage() > 0 && (!att.getKeyword().contains("Deathtouch") || crd.getTotalAssignedDamage() < 1 )) assignedLethalDamageToAllBlockers = false; } if (c.getName().equals("Player") && att.getKeyword().contains("Trample") && assignedLethalDamageToAllBlockers) { - //what happens with Double Strike??? - if (att.getKeyword().contains("First Strike")) - AllZone.Combat.addDefendingFirstStrikeDamage(1, att); - else - AllZone.Combat.addDefendingDamage(1, att); - + AllZone.Combat.addDefendingDamage(1, att); c.addAssignedDamage(1, att); } else if (!c.getName().equals("Player")){