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() {
|
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 combat = getCombat(AllZone.pwCombat.getAttackers(), blockers);
|
||||||
|
|
||||||
combat.setPlaneswalker(AllZone.pwCombat.getPlaneswalker());
|
combat.setPlaneswalker(AllZone.pwCombat.getPlaneswalker());
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public class ComputerUtil_Block2
|
|||||||
|
|
||||||
//finds a blocker, both the attacker and blocker are destroyed
|
//finds a blocker, both the attacker and blocker are destroyed
|
||||||
//returns null if no blocker is found
|
//returns null if no blocker is found
|
||||||
Card tradeSingleBlock(Card attacker)
|
Card tradeDownSingleBlock(Card attacker)
|
||||||
{
|
{
|
||||||
CardList c = getPossibleBlockers(attacker);
|
CardList c = getPossibleBlockers(attacker);
|
||||||
|
|
||||||
@@ -115,6 +115,21 @@ public class ComputerUtil_Block2
|
|||||||
return null;
|
return null;
|
||||||
}//tradeSingleBlock()
|
}//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
|
//finds a blocker, neither attacker and blocker are destroyed
|
||||||
@@ -237,19 +252,20 @@ public class ComputerUtil_Block2
|
|||||||
|
|
||||||
public Combat getBlockers()
|
public Combat getBlockers()
|
||||||
{
|
{
|
||||||
//if this method is called multiple times during a turn,
|
// TODO: this function fucking sucks
|
||||||
//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();
|
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;
|
boolean shouldBlock;
|
||||||
|
|
||||||
//if this isn't done, the attackers are shown backwards 3,2,1,
|
//if this isn't done, the attackers are shown backwards 3,2,1,
|
||||||
//reverse the order here because below reverses the order again
|
//reverse the order here because below reverses the order again
|
||||||
attackers.reverse();
|
//attackers.reverse();
|
||||||
|
|
||||||
//add attackers to combat
|
//add attackers to combat
|
||||||
//this has to be done before the code below because sumUnblockedAttackers()
|
//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++)
|
for(int i = 0; i < attackers.size(); i++)
|
||||||
{
|
{
|
||||||
|
Card c = null;
|
||||||
|
Card attack = attackers.get(i);
|
||||||
|
|
||||||
boolean doubleStrike = attackers.get(i).hasDoubleStrike();
|
boolean doubleStrike = attack.hasDoubleStrike();
|
||||||
boolean trample = attackers.get(i).getKeyword().contains("Trample");
|
boolean trample = attack.getKeyword().contains("Trample");
|
||||||
|
|
||||||
//the computer blocks 50% of the time or if the computer would lose the game
|
//the computer blocks 50% of the time or if the computer would lose the game
|
||||||
shouldBlock = random.nextBoolean() || blockersLife <= sumUnblockedAttackers(combat);
|
shouldBlock = random.nextBoolean() || blockersLife <= sumUnblockedAttackers(combat);
|
||||||
|
|
||||||
|
|
||||||
testing("shouldBlock - " +shouldBlock);
|
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
|
//Lure
|
||||||
if(attackers.get(i).isEnchantedBy("Lure")) {
|
if(attack.isEnchantedBy("Lure")) {
|
||||||
for(Card blocker:possibleBlockers) {
|
for(Card blocker:possibleBlockers) {
|
||||||
if(CombatUtil.canBlock(attackers.get(i), blocker)) {
|
if(CombatUtil.canBlock(attack, blocker)) {
|
||||||
System.out.println("Computer adding "+blocker+" to block "+attackers.get(i));
|
System.out.println("Computer adding "+blocker+" to block "+attack);
|
||||||
possibleBlockers.remove(blocker);
|
possibleBlockers.remove(blocker);
|
||||||
combat.addBlocker(attackers.get(i), blocker);
|
combat.addBlocker(attack, blocker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -289,75 +307,85 @@ public class ComputerUtil_Block2
|
|||||||
Random random = new Random();
|
Random random = new Random();
|
||||||
int randomInt = random.nextInt(100);
|
int randomInt = random.nextInt(100);
|
||||||
|
|
||||||
boolean multiTrample = false;
|
|
||||||
//multiblocks for trample
|
//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++)
|
for(int inner = 0; inner < m.length; inner++)
|
||||||
{
|
{
|
||||||
if(m.length != 1)
|
if(m.length != 1)
|
||||||
{
|
{
|
||||||
possibleBlockers.remove(m[inner]);
|
possibleBlockers.remove(m[inner]);
|
||||||
combat.addBlocker(attackers.get(i), m[inner]);
|
combat.addBlocker(attack, m[inner]);
|
||||||
multiTrample = true;
|
System.out.println(m[inner].toString() + " is blocking " + attack.toString());
|
||||||
}
|
}
|
||||||
}//for
|
}//for
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!multiTrample)
|
do{ // inside a do-while "loop", so we can break out of it
|
||||||
{
|
|
||||||
if (randomInt >= 10)
|
if (randomInt >= 10)
|
||||||
{
|
{
|
||||||
c = safeSingleBlock(attackers.get(i));
|
// Safe Block - Attacker dies, blocker lives
|
||||||
|
c = safeSingleBlock(attack);
|
||||||
if(c != null)
|
if(c != null)
|
||||||
testing("safe");
|
break;
|
||||||
}
|
}
|
||||||
if(c == null && randomInt >= 15)
|
if(randomInt >= 15)
|
||||||
{
|
{
|
||||||
//shield block - attacker lives, blocker lives
|
//shield block - attacker lives, blocker lives
|
||||||
c = shieldSingleBlock(attackers.get(i));
|
c = shieldSingleBlock(attack);
|
||||||
if(c != null)
|
if(c != null)
|
||||||
testing("shield");
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c == null && shouldBlock)
|
if(randomInt >= 20)
|
||||||
{
|
{
|
||||||
//trade block - attacker dies, blocker dies
|
//trade block - attacker dies, blocker dies
|
||||||
c = tradeSingleBlock(attackers.get(i));
|
c = tradeUpSingleBlock(attack);
|
||||||
|
|
||||||
if(c != null)
|
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
|
//chump block - attacker lives, blocker dies
|
||||||
c = chumpSingleBlock(attackers.get(i));
|
c = chumpSingleBlock(attack);
|
||||||
if(c != null)
|
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)
|
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
|
||||||
//if (!c.getKeyword().contains("This card can block any number of creatures."))
|
|
||||||
possibleBlockers.remove(c);
|
possibleBlockers.remove(c);
|
||||||
combat.addBlocker(attackers.get(i), c);
|
combat.addBlocker(attack, c);
|
||||||
|
System.out.println(c.toString() + " is blocking " + attack.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//multiple blockers
|
//multiple blockers
|
||||||
if(c == null && shouldBlock)
|
else if(shouldBlock)
|
||||||
{
|
{
|
||||||
Card[] m = multipleBlock(attackers.get(i));
|
Card[] m = multipleBlock(attack);
|
||||||
for(int inner = 0; inner < m.length; inner++)
|
for(int inner = 0; inner < m.length; inner++)
|
||||||
{
|
{
|
||||||
//to prevent a single flyer from blocking a single non-flyer
|
//to prevent a single flyer from blocking a single non-flyer
|
||||||
@@ -365,10 +393,13 @@ public class ComputerUtil_Block2
|
|||||||
if(m.length != 1)
|
if(m.length != 1)
|
||||||
{
|
{
|
||||||
possibleBlockers.remove(m[inner]);
|
possibleBlockers.remove(m[inner]);
|
||||||
combat.addBlocker(attackers.get(i), m[inner]);
|
System.out.println(c.toString() + " is blocking " + attack.toString());
|
||||||
|
combat.addBlocker(attack, m[inner]);
|
||||||
}
|
}
|
||||||
}//for
|
}//for
|
||||||
}//if
|
}//if
|
||||||
|
else{
|
||||||
|
System.out.println(attack.toString() + " is unblocked");
|
||||||
}
|
}
|
||||||
}//for attackers
|
}//for attackers
|
||||||
|
|
||||||
|
|||||||
@@ -206,8 +206,7 @@ public class Phase extends MyObservable
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we can skip AfterBlockers and AfterAttackers if necessary
|
// we can skip AfterBlockers and AfterAttackers if necessary
|
||||||
else if(phase.equals(Constant.Phase.Combat_Declare_Blockers) ||
|
else if(phase.equals(Constant.Phase.Combat_Declare_Blockers)){
|
||||||
phase.equals(Constant.Phase.Combat_Declare_Blockers_InstantAbility)){
|
|
||||||
if(inCombat()) {
|
if(inCombat()) {
|
||||||
AllZone.Combat.verifyCreaturesInPlay();
|
AllZone.Combat.verifyCreaturesInPlay();
|
||||||
CombatUtil.showCombat();
|
CombatUtil.showCombat();
|
||||||
@@ -216,6 +215,48 @@ public class Phase extends MyObservable
|
|||||||
AllZone.Phase.setNeedToNextPhase(true);
|
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)){
|
else if (phase.equals(Constant.Phase.Combat_FirstStrikeDamage)){
|
||||||
if(!inCombat())
|
if(!inCombat())
|
||||||
AllZone.Phase.setNeedToNextPhase(true);
|
AllZone.Phase.setNeedToNextPhase(true);
|
||||||
@@ -350,38 +391,7 @@ public class Phase extends MyObservable
|
|||||||
AllZone.Phase.setPlayerTurn(handleNextTurn());
|
AllZone.Phase.setPlayerTurn(handleNextTurn());
|
||||||
|
|
||||||
if (is(Constant.Phase.Combat_Declare_Blockers)){
|
if (is(Constant.Phase.Combat_Declare_Blockers)){
|
||||||
// Before damage is assigned, confirm how things are blocked/blocking
|
|
||||||
AllZone.Stack.unfreezeStack();
|
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_End) && extraCombats > 0){
|
if (is(Constant.Phase.Combat_End) && extraCombats > 0){
|
||||||
|
|||||||
Reference in New Issue
Block a user