mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 20:58:03 +00:00
- 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.
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -92,29 +92,44 @@ 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
|
||||
@@ -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");
|
||||
break;
|
||||
}
|
||||
|
||||
if(randomInt >= 25)
|
||||
{
|
||||
//trade block - attacker dies, blocker dies
|
||||
c = tradeDownSingleBlock(attack);
|
||||
|
||||
if(c == null && shouldBlock)
|
||||
if(c != null)
|
||||
break;
|
||||
}
|
||||
|
||||
if(shouldBlock)
|
||||
{
|
||||
//chump block - attacker lives, blocker dies
|
||||
c = chumpSingleBlock(attackers.get(i));
|
||||
c = chumpSingleBlock(attack);
|
||||
if(c != null)
|
||||
testing("chumping");
|
||||
break;
|
||||
}
|
||||
|
||||
if(c == null && doubleStrike && AllZone.ComputerPlayer.getLife() <= (getAttack(attackers.get(i))*2))
|
||||
if(doubleStrike && AllZone.ComputerPlayer.getLife() <= (getAttack(attack)*2))
|
||||
{
|
||||
c = forceBlock(attackers.get(i));
|
||||
c = forceBlock(attack);
|
||||
if (c != null)
|
||||
testing("forcing");
|
||||
break;
|
||||
}
|
||||
}while(false);
|
||||
|
||||
if(c != null)
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
//if (!c.getKeyword().contains("This card can block any number of creatures."))
|
||||
possibleBlockers.remove(c);
|
||||
combat.addBlocker(attackers.get(i), c);
|
||||
}
|
||||
|
||||
//multiple blockers
|
||||
if(c == null && 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
|
||||
//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
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -350,38 +391,7 @@ public class Phase extends MyObservable
|
||||
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);
|
||||
}
|
||||
AllZone.Stack.unfreezeStack();
|
||||
}
|
||||
|
||||
if (is(Constant.Phase.Combat_End) && extraCombats > 0){
|
||||
|
||||
Reference in New Issue
Block a user