It is currently 26 Apr 2024, 21:42
   
Text Size

MTG Forge 07-17 Version

Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins

MTG Forge 07-17 Version

Postby 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. :lol:)

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

Postby 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!
](*,) = coder at work, according to a coder.It does explain some of the bugs. :wink:
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

Postby 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

Postby Mr.Chaos » 20 Jul 2009, 06:02

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."
That is strange. I just put this file into the folder of the 07-05 beta released by Dennis and everything works fine.
](*,) = coder at work, according to a coder.It does explain some of the bugs. :wink:
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

Postby 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

Postby DennisBergkamp » 21 Jul 2009, 13:41

Thanks for this update :) I have merged these changes into my local version now.
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time


Return to Forge

Who is online

Users browsing this forum: No registered users and 185 guests


Who is online

In total there are 185 users online :: 0 registered, 0 hidden and 185 guests (based on users active over the past 10 minutes)
Most users ever online was 4143 on 23 Jan 2024, 08:21

Users browsing this forum: No registered users and 185 guests

Login Form