From ba3b9d82b7c5e2910dcc357a2c169a727af6bb2b Mon Sep 17 00:00:00 2001 From: jendave Date: Sat, 6 Aug 2011 10:30:55 +0000 Subject: [PATCH] - Fix for Combat issues that were noticed through flanking. Blocking was changing mid-block because the Stack wasn't frozen. - Added TradeUp Blocking situation for when the AI can kill a better creature and dying in the process. --- src/forge/ComputerAI_General.java | 3 +- src/forge/ComputerUtil_Block2.java | 187 +++++++++++++++++------------ src/forge/Phase.java | 80 ++++++------ 3 files changed, 156 insertions(+), 114 deletions(-) diff --git a/src/forge/ComputerAI_General.java b/src/forge/ComputerAI_General.java index b7fc7bfc108..696f29c436a 100644 --- a/src/forge/ComputerAI_General.java +++ b/src/forge/ComputerAI_General.java @@ -196,7 +196,8 @@ public class ComputerAI_General implements Computer { } public void declare_blockers() { - CardList blockers = new CardList(AllZone.Computer_Play.getCards()); + CardList blockers = AllZoneUtil.getCreaturesInPlay(AllZone.ComputerPlayer); + Combat combat = getCombat(AllZone.pwCombat.getAttackers(), blockers); combat.setPlaneswalker(AllZone.pwCombat.getPlaneswalker()); diff --git a/src/forge/ComputerUtil_Block2.java b/src/forge/ComputerUtil_Block2.java index b98d164958a..18b2ac09521 100644 --- a/src/forge/ComputerUtil_Block2.java +++ b/src/forge/ComputerUtil_Block2.java @@ -92,30 +92,45 @@ public class ComputerUtil_Block2 CardList c = getPossibleBlockers(attacker); for(int i = 0; i < c.size(); i++) - if(CombatUtil.canDestroyAttacker(attacker, c.get(i)) && + if(CombatUtil.canDestroyAttacker(attacker, c.get(i)) && (! CombatUtil.canDestroyBlocker(c.get(i), attacker))) - return c.get(i); + return c.get(i); return null; }//safeSingleBlock() //finds a blocker, both the attacker and blocker are destroyed //returns null if no blocker is found - Card tradeSingleBlock(Card attacker) + Card tradeDownSingleBlock(Card attacker) { CardList c = getPossibleBlockers(attacker); for(int i = 0; i < c.size(); i++) - if(CombatUtil.canDestroyAttacker(attacker, c.get(i))) - { - //do not block a non-flyer with a flyer - if((! c.get(i).getKeyword().contains("Flying")) || attacker.getKeyword().contains("Flying")) - return c.get(i); - } + if(CombatUtil.canDestroyAttacker(attacker, c.get(i))) + { + //do not block a non-flyer with a flyer + if((! c.get(i).getKeyword().contains("Flying")) || attacker.getKeyword().contains("Flying")) + return c.get(i); + } return null; }//tradeSingleBlock() + Card tradeUpSingleBlock(Card attacker) + { + CardList c = getPossibleBlockers(attacker); + for(int i = 0; i < c.size(); i++){ + Card defender = c.get(i); + if(CombatUtil.canDestroyAttacker(attacker, defender)) + { + // If Attacker has a higher Evaluation then defender, trade up! + if (CardFactoryUtil.evaluateCreature(defender) <= CardFactoryUtil.evaluateCreature(attacker)) + return defender; + } + } + return null; + }//tradeSingleBlock() + //finds a blocker, neither attacker and blocker are destroyed //returns null if no blocker is found @@ -124,8 +139,8 @@ public class ComputerUtil_Block2 CardList c = getPossibleBlockers(attacker); for(int i = 0; i < c.size(); i++) - if(! CombatUtil.canDestroyBlocker(c.get(i), attacker)) - return c.get(i); + if(! CombatUtil.canDestroyBlocker(c.get(i), attacker)) + return c.get(i); return null; }//shieldSingleBlock() @@ -237,19 +252,20 @@ public class ComputerUtil_Block2 public Combat getBlockers() { - //if this method is called multiple times during a turn, - //it will always return the same value - //randomInt is used so that the computer doesn't always - //do the same thing on turn 3 if he had the same creatures in play - //I know this is a little confusing - random.setSeed(AllZone.Phase.getTurn() + randomInt); - Card c; - Combat combat = new Combat(); + // TODO: this function fucking sucks + + Combat combat = new Combat(); + if (attackers.size() == 0) + return combat; + + // Random seed set with time, turn and a randomInt. Should be random enough + random.setSeed(AllZone.Phase.getTurn() + System.currentTimeMillis() + randomInt ); + boolean shouldBlock; //if this isn't done, the attackers are shown backwards 3,2,1, //reverse the order here because below reverses the order again - attackers.reverse(); + //attackers.reverse(); //add attackers to combat //this has to be done before the code below because sumUnblockedAttackers() @@ -259,25 +275,27 @@ public class ComputerUtil_Block2 for(int i = 0; i < attackers.size(); i++) { + Card c = null; + Card attack = attackers.get(i); - boolean doubleStrike = attackers.get(i).hasDoubleStrike(); - boolean trample = attackers.get(i).getKeyword().contains("Trample"); + boolean doubleStrike = attack.hasDoubleStrike(); + boolean trample = attack.getKeyword().contains("Trample"); //the computer blocks 50% of the time or if the computer would lose the game shouldBlock = random.nextBoolean() || blockersLife <= sumUnblockedAttackers(combat); testing("shouldBlock - " +shouldBlock); - c = null; + - System.out.println("Computer checking to block: "+attackers.get(i).getName()); + //System.out.println("Computer checking to block: "+attack.getName()); //Lure - if(attackers.get(i).isEnchantedBy("Lure")) { + if(attack.isEnchantedBy("Lure")) { for(Card blocker:possibleBlockers) { - if(CombatUtil.canBlock(attackers.get(i), blocker)) { - System.out.println("Computer adding "+blocker+" to block "+attackers.get(i)); + if(CombatUtil.canBlock(attack, blocker)) { + System.out.println("Computer adding "+blocker+" to block "+attack); possibleBlockers.remove(blocker); - combat.addBlocker(attackers.get(i), blocker); + combat.addBlocker(attack, blocker); } } } @@ -289,86 +307,99 @@ public class ComputerUtil_Block2 Random random = new Random(); int randomInt = random.nextInt(100); - boolean multiTrample = false; //multiblocks for trample - if (trample && AllZone.ComputerPlayer.getLife() <= getAttack(attackers.get(i)) ) + if (trample && AllZone.ComputerPlayer.getLife() <= getAttack(attack) ) { - Card[] m = multipleTrampleBlock(attackers.get(i)); + // If attacker has trample, block with a few creatures to prevent damage to player + Card[] m = multipleTrampleBlock(attack); for(int inner = 0; inner < m.length; inner++) { if(m.length != 1) { possibleBlockers.remove(m[inner]); - combat.addBlocker(attackers.get(i), m[inner]); - multiTrample = true; + combat.addBlocker(attack, m[inner]); + System.out.println(m[inner].toString() + " is blocking " + attack.toString()); } }//for + continue; } - if (!multiTrample) - { + do{ // inside a do-while "loop", so we can break out of it if (randomInt >= 10) { - c = safeSingleBlock(attackers.get(i)); + // Safe Block - Attacker dies, blocker lives + c = safeSingleBlock(attack); if(c != null) - testing("safe"); + break; } - if(c == null && randomInt >= 15) + if(randomInt >= 15) { //shield block - attacker lives, blocker lives - c = shieldSingleBlock(attackers.get(i)); + c = shieldSingleBlock(attack); if(c != null) - testing("shield"); + break; } - if(c == null && shouldBlock) + if(randomInt >= 20) { //trade block - attacker dies, blocker dies - c = tradeSingleBlock(attackers.get(i)); + c = tradeUpSingleBlock(attack); if(c != null) - testing("trading"); - } - - - if(c == null && shouldBlock) - { - //chump block - attacker lives, blocker dies - c = chumpSingleBlock(attackers.get(i)); - if(c != null) - testing("chumping"); - } - - if(c == null && doubleStrike && AllZone.ComputerPlayer.getLife() <= (getAttack(attackers.get(i))*2)) - { - c = forceBlock(attackers.get(i)); - if (c != null) - testing("forcing"); + break; } - if(c != null) + if(randomInt >= 25) { - - //if (!c.getKeyword().contains("This card can block any number of creatures.")) - possibleBlockers.remove(c); - combat.addBlocker(attackers.get(i), c); + //trade block - attacker dies, blocker dies + c = tradeDownSingleBlock(attack); + + if(c != null) + break; } - //multiple blockers - if(c == null && shouldBlock) + if(shouldBlock) { - Card[] m = multipleBlock(attackers.get(i)); - for(int inner = 0; inner < m.length; inner++) - { - //to prevent a single flyer from blocking a single non-flyer - //tradeSingleBlock() checks for a flyer blocking a non-flyer also - if(m.length != 1) - { - possibleBlockers.remove(m[inner]); - combat.addBlocker(attackers.get(i), m[inner]); - } - }//for - }//if + //chump block - attacker lives, blocker dies + c = chumpSingleBlock(attack); + if(c != null) + break; + } + + if(doubleStrike && AllZone.ComputerPlayer.getLife() <= (getAttack(attack)*2)) + { + c = forceBlock(attack); + if (c != null) + break; + } + }while(false); + + if(c != null) + { + // TODO: creatures that can block more than one don't necessarily get removed + possibleBlockers.remove(c); + combat.addBlocker(attack, c); + System.out.println(c.toString() + " is blocking " + attack.toString()); + } + + //multiple blockers + else if(shouldBlock) + { + Card[] m = multipleBlock(attack); + for(int inner = 0; inner < m.length; inner++) + { + //to prevent a single flyer from blocking a single non-flyer + //tradeSingleBlock() checks for a flyer blocking a non-flyer also + if(m.length != 1) + { + possibleBlockers.remove(m[inner]); + System.out.println(c.toString() + " is blocking " + attack.toString()); + combat.addBlocker(attack, m[inner]); + } + }//for + }//if + else{ + System.out.println(attack.toString() + " is unblocked"); } }//for attackers diff --git a/src/forge/Phase.java b/src/forge/Phase.java index e0942ac7c58..ec7d333fce9 100644 --- a/src/forge/Phase.java +++ b/src/forge/Phase.java @@ -206,8 +206,7 @@ public class Phase extends MyObservable } // we can skip AfterBlockers and AfterAttackers if necessary - else if(phase.equals(Constant.Phase.Combat_Declare_Blockers) || - phase.equals(Constant.Phase.Combat_Declare_Blockers_InstantAbility)){ + else if(phase.equals(Constant.Phase.Combat_Declare_Blockers)){ if(inCombat()) { AllZone.Combat.verifyCreaturesInPlay(); CombatUtil.showCombat(); @@ -216,6 +215,48 @@ public class Phase extends MyObservable AllZone.Phase.setNeedToNextPhase(true); } + else if (phase.equals(Constant.Phase.Combat_Declare_Blockers_InstantAbility)){ + // After declare blockers are finished being declared mark them blocked and trigger blocking things + 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(); + } + } + else if (phase.equals(Constant.Phase.Combat_FirstStrikeDamage)){ if(!inCombat()) AllZone.Phase.setNeedToNextPhase(true); @@ -349,39 +390,8 @@ public class Phase extends MyObservable if (phaseOrder[phaseIndex].equals(Constant.Phase.Cleanup)) AllZone.Phase.setPlayerTurn(handleNextTurn()); - if (is(Constant.Phase.Combat_Declare_Blockers)){ - // Before damage is assigned, confirm how things are blocked/blocking - AllZone.Stack.unfreezeStack(); - - 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); - } + if (is(Constant.Phase.Combat_Declare_Blockers)){ + AllZone.Stack.unfreezeStack(); } if (is(Constant.Phase.Combat_End) && extraCombats > 0){