MTG Forge 07-17 Version
by mtgrares
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
MTG Forge 07-17 Version
by mtgrares » 17 Jul 2009, 17:40
This is a small update. Now the computer will block in order to stay alive. Also I've tried to fix the situation where the computer attacks and then on your next turn you attack and win. The computer will hold back a few creatures in order to stay alive. The computer still incorrectly blocks first strike (it will block a 2/2 first strike creature with just a 2/2) and will also lose to trample damage (if the computer is at 1 life and you attack with a 2/2 trampler, the AI might block it with just a 1/1).
Also the New Game menu has an "option menu" that lets you remove artifacts and 1/1 creatures from the decks that the sealed and constructed generated decks. (Actually the remove 1/1 creature option removes creatures with a power of 0 or 1.) I like these options because I think they help improve the quality of a completely random deck. (I keep thinking that I should improve the generate deck option to curve the mana cost of the cards but frankly it scares me because I know it will be complicated. )
This really changes the feeling of the AI and it feels like you are playing a different person.
Download 07-17 Jar File
p.s.
And for Dennis I hope you enjoyed/are enjoying your vacation. I tried not to change any of the stuff that you may have added to attacking or block code.
Also the New Game menu has an "option menu" that lets you remove artifacts and 1/1 creatures from the decks that the sealed and constructed generated decks. (Actually the remove 1/1 creature option removes creatures with a power of 0 or 1.) I like these options because I think they help improve the quality of a completely random deck. (I keep thinking that I should improve the generate deck option to curve the mana cost of the cards but frankly it scares me because I know it will be complicated. )
This really changes the feeling of the AI and it feels like you are playing a different person.
Download 07-17 Jar File
p.s.
And for Dennis I hope you enjoyed/are enjoying your vacation. I tried not to change any of the stuff that you may have added to attacking or block code.
- Code: Select all
1. changed Gui_NewGame - added 2 variables and slightly changed setupMenu()
2. changed GenerateConstructedDeck.get2Colors()
3. changed GenerateSealedDeck.get2Colors()
4. changed ComputerUtil_Attack2
5. changed ComputerUtil_Block2
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
1. changed Gui_NewGame - added 2 variables and slightly changed setupMenu()
//GenerateConstructedDeck.get2Colors() and GenerateSealedDeck.get2Colors() use these two variables
public static JCheckBox removeSmallCreatures = new JCheckBox("Remove 1/1 and 0/X Creatures");
public static JCheckBox removeArtifacts = new JCheckBox("Remove Artifacts");
private void setupMenu()
{
JMenuItem lookAndFeel = new JMenuItem("Display Options");
JMenuItem download = new JMenuItem("Download Card Pictures");
JMenuItem cardSizes = new JMenuItem("Specify Card Size");
JMenuItem about = new JMenuItem("About");
JMenu menu = new JMenu("Menu");
menu.add(lookAndFeel);
menu.add(cardSizes);
menu.add(download);
menu.add(about);
//new stuff
JMenu generatedDeck = new JMenu("Generate Deck");
generatedDeck.add(removeSmallCreatures);
generatedDeck.add(removeArtifacts);
JMenu optionsMenu = new JMenu("Options");
optionsMenu.add(generatedDeck);
JMenuBar bar = new JMenuBar();
bar.add(menu);
bar.add(optionsMenu);
bar.add(new MenuItem_HowToPlay());
setJMenuBar(bar);
final HashMap<String,String> map = new HashMap<String,String>();
map.put("Metal", "javax.swing.plaf.metal.MetalLookAndFeel");
map.put("Motif", "com.sun.java.swing.plaf.motif.MotifLookAndFeel");
map.put("Windows", "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
final HashMap<String, Integer> cardMap = new HashMap<String, Integer>();
cardMap.put("Small", 0);
cardMap.put("Medium", 1);
cardMap.put("Large", 2);
//add action listeners
lookAndFeel.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent a)
{
JList list = new JList(map.keySet().toArray());
int n = JOptionPane.showConfirmDialog(null, list, "Choose one", JOptionPane.OK_CANCEL_OPTION);
if(n == JOptionPane.CANCEL_OPTION)
return;
try{
String data = (String) map.get(list.getSelectedValue());
UIManager.setLookAndFeel(data);
SwingUtilities.updateComponentTreeUI(Gui_NewGame.this);
}catch(Exception ex) {}
}
});
cardSizes.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent a)
{
//JList list = new JList(cardMap.keySet().toArray());
String[] selections = {"Tiny", "Small", "Medium", "Large"};
JList list = new JList(selections);
int n = JOptionPane.showConfirmDialog(null, list, "Choose one", JOptionPane.OK_CANCEL_OPTION);
if(n == JOptionPane.CANCEL_OPTION)
return;
try{
String choice = (String)list.getSelectedValue();
if (choice.equals("Tiny"))
{
Constant.Runtime.width[0] = 42;
Constant.Runtime.height[0]= 59;
}
else if (choice.equals("Small"))
{
Constant.Runtime.width[0] = 63;
Constant.Runtime.height[0]= 88;
}
else if (choice.equals("Medium"))
{
Constant.Runtime.width[0] = 70;
Constant.Runtime.height[0]= 98;
}
else if (choice.equals("Large"))
{
Constant.Runtime.width[0] = 93;
Constant.Runtime.height[0]= 130;
}
else
{
Constant.Runtime.width[0] = 70;
Constant.Runtime.height[0]= 98;
}
SwingUtilities.updateComponentTreeUI(Gui_NewGame.this);
}catch(Exception ex) {}
}
});
download.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent a)
{
Gui_DownloadPictures.startDownload(Gui_NewGame.this);
}
});
about.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent a)
{
JTextArea area = new JTextArea(8, 25);
Font f = new Font(area.getFont().getName(), Font.PLAIN, 13);
area.setFont(f);
area.setText("I enjoyed programming this project. I'm glad other people also enjoy my program. MTG Forge has turned out to be very successful.\n\nmtgrares@yahoo.com\nhttp://mtgrares.blogspot.com\n\nWritten by: Forge");
area.setWrapStyleWord(true);
area.setLineWrap(true);
area.setEditable(false);
JPanel p =new JPanel();
area.setBackground(p.getBackground());
JOptionPane.showMessageDialog(Gui_NewGame.this, area, "About", JOptionPane.INFORMATION_MESSAGE);
}
});
}//setupMenu()
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
2. changed GenerateConstructedDeck.get2Colors()
private CardList get2Colors(CardList in)
{
int a;
int b;
do{
a = CardUtil.getRandomIndex(Constant.Color.onlyColors);
b = CardUtil.getRandomIndex(Constant.Color.onlyColors);
}while(a == b);//do not want to get the same color twice
color1 = Constant.Color.onlyColors[a];
color2 = Constant.Color.onlyColors[b];
CardList out = new CardList();
out.addAll(CardListUtil.getColor(in, color1).toArray());
out.addAll(CardListUtil.getColor(in, color2).toArray());
CardList artifact = in.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
//is this really a colorless artifact and not something
//wierd like Sarcomite Myr which is a colored artifact
return c.isArtifact() &&
CardUtil.getColors(c).contains(Constant.Color.Colorless) &&
!Gui_NewGame.removeArtifacts.isSelected();
}
});
out.addAll(artifact.toArray());
out = out.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
if(c.isCreature() &&
c.getNetAttack() <= 1 &&
Gui_NewGame.removeSmallCreatures.isSelected())
{
return false;
}
return true;
}
});
out = filterBadCards(out);
return out;
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
3. changed GenerateSealedDeck.get2Colors()
private CardList get2Colors(CardList in)
{
int a;
int b;
do{
a = CardUtil.getRandomIndex(Constant.Color.onlyColors);
b = CardUtil.getRandomIndex(Constant.Color.onlyColors);
}while(a == b);//do not want to get the same color twice
color1 = Constant.Color.onlyColors[a];
color2 = Constant.Color.onlyColors[b];
CardList out = new CardList();
out.addAll(CardListUtil.getColor(in, color1).toArray());
out.addAll(CardListUtil.getColor(in, color2).toArray());
CardList artifact = in.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
//is this really a colorless artifact and not something
//wierd like Sarcomite Myr which is a colored artifact
return c.isArtifact() &&
CardUtil.getColors(c).contains(Constant.Color.Colorless) &&
!Gui_NewGame.removeArtifacts.isSelected();
}
});
out.addAll(artifact.toArray());
out = out.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
if(c.isCreature() &&
c.getNetAttack() <= 1 &&
Gui_NewGame.removeSmallCreatures.isSelected())
{
return false;
}
return true;
}
});
out = filterBadCards(out);
return out;
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
4. changed ComputerUtil_Attack2
import java.util.*;
//doesHumanAttackAndWin() uses the global variable AllZone.Computer_Life
public class ComputerUtil_Attack2
{
//possible attackers and blockers
private CardList attackers;
private CardList blockers;
private int blockerLife;
private Random random = new Random();
private final int randomInt = random.nextInt();
private CardList humanList; //holds human player creatures
private CardList computerList;//holds computer creatures
public ComputerUtil_Attack2(Card[] possibleAttackers, Card[] possibleBlockers, int blockerLife)
{
this(new CardList(possibleAttackers), new CardList(possibleBlockers), blockerLife);
}
public ComputerUtil_Attack2(CardList possibleAttackers, CardList possibleBlockers, int blockerLife)
{
humanList = new CardList(possibleBlockers.toArray());
humanList = humanList.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
return c.isCreature();
}
});
computerList = new CardList(possibleAttackers.toArray());
computerList = computerList.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
return c.isCreature();
}
});
attackers = getUntappedCreatures(possibleAttackers, true);
blockers = getUntappedCreatures(possibleBlockers , false);
this.blockerLife = blockerLife;
final ArrayList<String> valuable = new ArrayList<String>();
valuable.add("Kamahl, Pit Fighter");
valuable.add("Elvish Piper");
attackers = attackers.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
return (0 < getAttack(c) || c.getName().equals("Guiltfeeder")) && ! valuable.contains(c.getName());
}
});
}//constructor
public CardList getUntappedCreatures(CardList in, final boolean checkCanAttack)
{
CardList list = new CardList(in.toArray());
list = list.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
boolean b = c.isCreature() && c.isUntapped();
if(checkCanAttack)
return b && CombatUtil.canAttack(c);
return b;
}
});
return list;
}//getUntappedCreatures()
//this checks to make sure that the computer player
//doesn't lose when the human player attacks
//this method is used by getAttackers()
public int getStartIndex()
{
CardListUtil.sortAttack(humanList);
for(int i = 0; i < computerList.size(); i++)
if(!doesHumanAttackAndWin(i))
return i;
return computerList.size();
}
//this uses a global variable, which isn't perfect
public boolean doesHumanAttackAndWin(int nBlockingCreatures)
{
int totalAttack = 0;
int stop = humanList.size() - nBlockingCreatures;
for(int i = 0; i < stop; i++)
totalAttack += getAttack(humanList.get(i));
//-3 so the computer will try to stay at 3 life
return (AllZone.Computer_Life.getLife() - 3) <= totalAttack;
}
private boolean doAssault()
{
//I think this is right but the assault code may still be a little off
CardListUtil.sortAttackLowFirst(attackers);
int totalAttack = 0;
//presumes the Human will block
for(int i = 0; i < (attackers.size() - blockers.size()); i++)
totalAttack += getAttack(attackers.get(i));
return blockerLife <= totalAttack;
}//doAssault()
public Combat getAttackers()
{
//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);
Combat combat = new Combat();
for (int i=0; i<attackers.size();i++)
{
if (attackers.get(i).getKeyword().contains("This card attacks each turn if able."))
combat.addAttacker(attackers.get(i));
}
if (combat.getAttackers().length == 0 && (countExaltedCreatures() >= 3 ||
GameActionUtil.isRafiqInPlay(Constant.Player.Computer) ||
GameActionUtil.getBattleGraceAngels(Constant.Player.Computer) >= 2) && !doAssault())
{
int biggest = 0;
Card att = null;
for(int i=0; i<attackers.size();i++){
if (getAttack(attackers.get(i)) > biggest) {
biggest = getAttack(attackers.get(i));
att = attackers.get(i);
}
}
if (att!= null)
combat.addAttacker(att);
}
//do assault (all creatures attack) if the computer would win the game
//or if the computer has 4 creatures and the player has 1
else if(doAssault() || (humanList.size() == 1 && 3 < attackers.size()))
{
for(int i = 0; i < attackers.size(); i++)
combat.addAttacker(attackers.get(i));
}
else
{
Card bigDef;
@SuppressWarnings("unused") // bigAtt
Card bigAtt;
//should the computer randomly not attack with one attacker?
//this should only happen 10% of the time when the computer
//has at least 3 creatures
boolean notAttack = (Math.abs(random.nextInt(100)) <= 10);
if(notAttack && 3 <= attackers.size())
{
attackers.shuffle();
attackers.remove(0);
}
//this has to be before the sorting below
//because this sorts attackers
int i = getStartIndex(); //new
//so the biggest creature will usually attack
//I think this works, not sure, may have to change it
//sortNonFlyingFirst has to be done first, because it reverses everything
CardListUtil.sortNonFlyingFirst(attackers);
CardListUtil.sortAttackLowFirst(attackers);
for(; i < attackers.size(); i++)
{
bigAtt = getBiggestAttack(attackers.get(i));
bigDef = getBiggestDefense(attackers.get(i));
/*
System.out.println("bigDef: " + bigDef.getName());
System.out.println("attackers.get(i): " + attackers.get(i).getName());
if (CombatUtil.canDestroyBlocker(bigDef, attackers.get(i)))
System.out.println(attackers.get(i).getName() + " can destroy blocker " +bigDef.getName());
*/
//if attacker can destroy biggest blocker or
//biggest blocker cannot destroy attacker
if(CombatUtil.canDestroyBlocker(bigDef, attackers.get(i)) ||
(! CombatUtil.canDestroyAttacker(attackers.get(i), bigAtt))){
combat.addAttacker(attackers.get(i));
}
else if(attackers.get(i).getSacrificeAtEOT()){
combat.addAttacker(attackers.get(i));
}
}
}//getAttackers()
return combat;
}//getAttackers()
//returns 0/1 Card if no blockers found
public Card getBiggestAttack(Card attack)
{
CardListUtil.sortAttack(blockers);
for(int i = 0; i < blockers.size(); i++)
if(CombatUtil.canBlock(attack, blockers.get(i)))
return blockers.get(i);
return AllZone.CardFactory.getCard("Birds of Paradise", "");
}
//returns 1/1 Card if no blockers found
public Card getBiggestDefense(Card attack)
{
CardListUtil.sortDefense(blockers);
for(int i = 0; i < blockers.size(); i++)
if(CombatUtil.canBlock(attack, blockers.get(i)))
return blockers.get(i);
return AllZone.CardFactory.getCard("Elvish Piper", "");
}
public int countExaltedCreatures()
{
PlayerZone play = AllZone.getZone(Constant.Zone.Play, Constant.Player.Computer);
CardList list = new CardList();
list.addAll(play.getCards());
list = list.filter(new CardListFilter(){
public boolean addCard(Card c) {
return c.getKeyword().contains("Exalted");
}
});
return list.size();
}
public void assignDamage(CardList list, int damage)
{
CardListUtil.sortAttack(list);
int kill;
for(int i = 0; i < list.size(); i++)
{
kill = list.get(i).getKillDamage();
if(kill <= damage)
{
damage -= kill;
list.get(i).setAssignedDamage(kill);
}
}
}//assignDamage()
public int getAttack(Card c)
{
int n = c.getNetAttack();
if(CombatUtil.isDoranInPlay())
n = c.getNetDefense();
if(c.getKeyword().contains("Double Strike"))
n *= 2;
return n;
}
}
/*
//this returns the attacking power that is needed to destroy
//Card c and takes into account first and double strike
//
//Doran, the Siege Tower doesn't change a card's defense
//used by sortDefense()
private int getDefense(Card c)
{
int n = c.getNetDefense();
//is the defense is less than attack and the card has
//first or double strike?
if(hasStrike(c) && n < getAttack_FirstStrike(c))
n = getAttack_FirstStrike(c);
return n;
}
//does this card have first or double strike?
private boolean hasStrike(Card c)
{
return c.getKeyword.contains("First Strike") ||
c.getKeyword.contains("Double Strike")
}
//the higher the defense the better
@SuppressWarnings("unchecked") // Comparator needs <type>
private void sortDefense(CardList list)
{
Comparator com = new Comparator()
{
public int compare(Object a1, Object b1)
{
Card a = (Card)a1;
Card b = (Card)b1;
return getDefense(b) - getDefense(a);
}
};
list.sort(com);
}//sortDefense()
//use this method if you need to know about first strike
public int getAttack_FirstStrike(Card c)
{
int n = getAttack(c);
//adding 1 is a little bit hacky bit it shows
//that first strike is a little better
//than a average creature
if(c.getKeyword().contains("First Strike"))
n += 1;
return n;
}
//returns lowest attack first
private void sortAttackLowFirst(CardList list)
{
sortAttack(list);
list.reverse();
return list;
}
//the higher the attack the better
@SuppressWarnings("unchecked") // Comparator needs type
private void sortAttack(CardList list)
{
Comparator com = new Comparator()
{
public int compare(Object a1, Object b1)
{
Card a = (Card)a1;
Card b = (Card)b1;
return getAttack_FirstStrike(b) - getAttack_FirstStrike(a);
}
};
list.sort(com);
}//sortAttack()
*/
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
5. changed ComputerUtil_Block2
import java.util.*;
public class ComputerUtil_Block2
{
private CardList attackers;
private CardList possibleBlockers;
private int blockersLife;
//making this static helped in testing
//random.nextBoolean() wasn't true 50% of the time
private static Random random = new Random();
private final int randomInt = random.nextInt();
public ComputerUtil_Block2(Card[] attackers, Card[] possibleBlockers, int blockerLife)
{
this(new CardList(attackers), new CardList(possibleBlockers), blockerLife);
}
public ComputerUtil_Block2(CardList in_attackers, CardList in_possibleBlockers, int in_blockersLife)
{
attackers = new CardList(in_attackers.toArray());
possibleBlockers = getUntappedCreatures(new CardList(in_possibleBlockers.toArray()));
//so the computer won't just have 1 life left
//the computer will try to stay at 3 life
blockersLife = in_blockersLife;
if(3 < blockersLife)
blockersLife -= 3;;
attackers.shuffle();
CardListUtil.sortAttackLowFirst(possibleBlockers);
possibleBlockers = removeValuableBlockers(possibleBlockers);
}
private CardList getUntappedCreatures(CardList list)
{
list = list.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
return c.isCreature() && c.isUntapped();
}
});
return list;
}//getUntappedCreatures()
private CardList removeValuableBlockers(CardList in)
{
final String[] noBlock = {"Elvish Piper", "Urborg Syphon-Mage", "Sparksmith", "Royal Assassin", "Marble Titan", "Kamahl, Pit Fighter"};
CardList out = in.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
for(int i = 0; i < noBlock.length; i++)
if(c.getName().equals(noBlock[i]))
return false;
return true;
}
});//CardListFilter
return out;
}
//checks for flying and stuff like that
private CardList getPossibleBlockers(Card attacker)
{
CardList list = new CardList();
for(int i = 0; i < possibleBlockers.size(); i++)
if(CombatUtil.canBlock(attacker, possibleBlockers.get(i)))
list.add(possibleBlockers.get(i));
return list;
}
//finds a blocker that destroys the attacker, the blocker is not destroyed
//returns null if no blocker is found
Card safeSingleBlock(Card attacker)
{
CardList c = getPossibleBlockers(attacker);
for(int i = 0; i < c.size(); i++)
if(CombatUtil.canDestroyAttacker(attacker, c.get(i)) &&
(! CombatUtil.canDestroyBlocker(c.get(i), attacker)))
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)
{
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);
}
return null;
}//tradeSingleBlock()
//finds a blocker, neither attacker and blocker are destroyed
//returns null if no blocker is found
Card shieldSingleBlock(Card attacker)
{
CardList c = getPossibleBlockers(attacker);
for(int i = 0; i < c.size(); i++)
if(! CombatUtil.canDestroyBlocker(c.get(i), attacker))
return c.get(i);
return null;
}//shieldSingleBlock()
//finds multiple blockers
//returns an array of size 0 if not multiple blocking
Card[] multipleBlock(Card attacker)
{
CardList c = getPossibleBlockers(attacker);
int defense = getDefense(attacker) - attacker.getDamage();
//if attacker cannot be destroyed
if(defense > CardListUtil.sumAttack(c))
return new Card[] {};
CardList block = new CardList();
c.shuffle();
while(defense > CardListUtil.sumAttack(block))
block.add(c.remove(0));
Card check[] = block.toArray();
//no single blockers, that should be handled somewhere else
if(check.length == 1)
return new Card[] {};
return check;
}//multipleBlock()
//finds a blocker, both the attacker lives and blockers dies
//returns null if no blocker is found
Card chumpSingleBlock(Card attacker)
{
if(blockersLife <= CardListUtil.sumAttack(attackers))
{
CardList c = getPossibleBlockers(attacker);
CardListUtil.sortAttackLowFirst(c);
if(! c.isEmpty())
return c.get(0);
}
return null;
}//tradeSingleBlock()
//force block if lethal damage somehow slips through checks (happens often with doublestrike)
Card forceBlock(Card attacker)
{
CardList c = getPossibleBlockers(attacker);
CardListUtil.sortAttackLowFirst(c);
if(! c.isEmpty())
return c.get(0);
return null;
}
private void testing(String s)
{
boolean print = false;
if(print)
System.out.println("combat testing: " +s);
}
private int sumUnblockedAttackers(Combat combat)
{
int sum = 0;
Card c[] = combat.getAttackers();
for(int i = 0; i < c.length; i++)
if(! combat.isBlocked(c[i]))
sum += getAttack(c[i]);
return sum;
}
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();
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();
//add attackers to combat
//this has to be done before the code below because sumUnblockedAttackers()
//uses combat to get the attackers and total their power
for(int i = 0; i < attackers.size(); i++)
combat.addAttacker(attackers.get(i));
for(int i = 0; i < attackers.size(); i++)
{
boolean doubleStrike = false;
if(attackers.get(i).hasDoubleStrike() || attackers.get(i).getKeyword().contains("Double Strike"))
doubleStrike = true;
//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;
//safe block - attacker dies, blocker lives
//if there is only one attacker it might be a trap
//if holding a Giant Growth and a 2/2 attacking into a 3/3
if(shouldBlock)
{
c = safeSingleBlock(attackers.get(i));
if(c != null)
testing("safe");
}
if(c == null && shouldBlock)
{
//shield block - attacker lives, blocker lives
c = shieldSingleBlock(attackers.get(i));
if(c != null)
testing("shield");
}
if(c == null && shouldBlock)
{
//trade block - attacker dies, blocker dies
c = tradeSingleBlock(attackers.get(i));
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.Computer_Life.getLife() <= (getAttack(attackers.get(i))*2))
{
c = forceBlock(attackers.get(i));
if (c != null)
testing("forcing");
}
if(c != null)
{
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
}//for attackers
return combat;
}//getBlockers()
//Doran, the Siege Tower doesn't change a card's defense
public int getDefense(Card c)
{
return c.getNetDefense();
}
//this doesn't take into account first strike,
//use CombatUtil.canDestroyAttacker()
public int getAttack(Card c)
{
int n = c.getNetAttack();
if(CombatUtil.isDoranInPlay())
n = c.getNetDefense();
if(c.getKeyword().contains("Double Strike"))
n *= 2;
return n;
}
}
- mtgrares
- DEVELOPER
- Posts: 1352
- Joined: 08 Sep 2008, 22:10
- Has thanked: 3 times
- Been thanked: 12 times
Re: MTG Forge 07-17 Version
by Mr.Chaos » 18 Jul 2009, 06:05
Thanks for the combat update, it should make games a bit more interesting.
As for the removal option of small critters, that also removes Soul Warden, Llanowar Elves and the likes.
There are a lot of useful/powerful tiny giants out there you know!
As for the removal option of small critters, that also removes Soul Warden, Llanowar Elves and the likes.
There are a lot of useful/powerful tiny giants out there you know!
= coder at work, according to a coder.It does explain some of the bugs.
- Mr.Chaos
- Tester
- Posts: 625
- Joined: 06 Sep 2008, 08:15
- Has thanked: 0 time
- Been thanked: 0 time
Re: MTG Forge 07-17 Version
by Joku » 19 Jul 2009, 21:58
Ahh! This update broke the game for me. Now when I try to start it up I get an error saying "Could not find the main class. Program will exit."
- Joku
- Posts: 7
- Joined: 28 Jan 2009, 22:26
- Has thanked: 0 time
- Been thanked: 0 time
Re: MTG Forge 07-17 Version
by Mr.Chaos » 20 Jul 2009, 06:02
That is strange. I just put this file into the folder of the 07-05 beta released by Dennis and everything works fine.Joku wrote:Ahh! This update broke the game for me. Now when I try to start it up I get an error saying "Could not find the main class. Program will exit."
= coder at work, according to a coder.It does explain some of the bugs.
- Mr.Chaos
- Tester
- Posts: 625
- Joined: 06 Sep 2008, 08:15
- Has thanked: 0 time
- Been thanked: 0 time
Re: MTG Forge 07-17 Version
by Joku » 20 Jul 2009, 22:29
I figured out the problem. My Java wasn't up to date.
- Joku
- Posts: 7
- Joined: 28 Jan 2009, 22:26
- Has thanked: 0 time
- Been thanked: 0 time
Re: MTG Forge 07-17 Version
by DennisBergkamp » 21 Jul 2009, 13:41
Thanks for this update I have merged these changes into my local version now.
-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
6 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 185 guests