...
 
Commits (234)

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

......@@ -1288,11 +1288,14 @@ public class AiBlockController {
if (!attackersLeft.isEmpty()) {
oppCreatureCount = ComputerUtil.countUsefulCreatures(attackersLeft.get(0).getController());
}
try {
if (attacker.getOwner().equals(ai) && "6".equals(attacker.getSVar("SacMe"))) {
// Temporarily controlled object - don't trade with it
// TODO: find a more reliable way to figure out that control will be reestablished next turn
return false;
}
} catch (Exception e){
if (attacker.getOwner().equals(ai) && "6".equals(attacker.getSVar("SacMe"))) {
// Temporarily controlled object - don't trade with it
// TODO: find a more reliable way to figure out that control will be reestablished next turn
return false;
}
int numSteps = ai.getStartingLife() - 5; // e.g. 15 steps between 5 life and 20 life
......
......@@ -99,6 +99,8 @@ public abstract class GameState {
private int turn = 1;
private boolean removeSummoningSickness = false;
// Targeting for precast spells in a game state (mostly used by Puzzle Mode game states)
private final int TARGET_NONE = -1; // untargeted spell (e.g. Joraga Invocation)
private final int TARGET_HUMAN = -2;
......@@ -448,6 +450,10 @@ public abstract class GameState {
turn = Integer.parseInt(categoryValue);
}
else if (categoryName.equals("removesummoningsickness")) {
removeSummoningSickness = categoryValue.equalsIgnoreCase("true");
}
else if (categoryName.endsWith("life")) {
if (isHuman)
humanLife = Integer.parseInt(categoryValue);
......@@ -622,6 +628,12 @@ public abstract class GameState {
game.getPhaseHandler().devAdvanceToPhase(advPhase);
}
if (removeSummoningSickness) {
for (Card card : game.getCardsInGame()) {
card.setSickness(false);
}
}
game.getAction().checkStateEffects(true); //ensure state based effects and triggers are updated
}
......@@ -1070,7 +1082,6 @@ public abstract class GameState {
zone.setCards(kv.getValue());
}
}
}
/**
......
......@@ -953,17 +953,14 @@ public class PlayerControllerAi extends PlayerController {
return true;
}
@Override
public Map<GameEntity, CounterType> chooseProliferation(SpellAbility sa) {
return brains.chooseProliferation(sa);
}
@Override
public boolean chooseTargetsFor(SpellAbility currentAbility) {
return brains.doTrigger(currentAbility, true);
}
@Override
public boolean chooseCardsPile(SpellAbility sa, CardCollectionView pile1, CardCollectionView pile2, String faceUp) {
if (faceUp.equals("True")) {
// AI will choose the first pile if it is larger or the same
......
......@@ -145,8 +145,13 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
// get the one with the most in graveyard
// zone is visible so evaluate which would be hurt the most
Player oppTarget = Collections.max(Lists.newArrayList(oppList),
PlayerPredicates.compareByZoneSize(origin));
Player oppTarget;
try {
oppTarget = Collections.max(Lists.newArrayList(oppList),
PlayerPredicates.compareByZoneSize(origin));
} catch ( Exception e ){
return false;
}
// set the target
if (oppTarget != null && !oppTarget.getCardsIn(ZoneType.Graveyard).isEmpty()) {
......
package forge.ai.ability;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.game.GameEntity;
import forge.game.card.Card;
import forge.game.card.CardLists;
import forge.game.card.CardUtil;
import forge.game.card.CounterType;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
......@@ -95,4 +100,52 @@ public class CountersProliferateAi extends SpellAbilityAi {
return canPlayAI(ai, sa);
}
/*
* (non-Javadoc)
* @see forge.ai.SpellAbilityAi#chooseSingleEntity(forge.game.player.Player, forge.game.spellability.SpellAbility, java.util.Collection, boolean, forge.game.player.Player)
*/
@SuppressWarnings("unchecked")
@Override
public <T extends GameEntity> T chooseSingleEntity(Player ai, SpellAbility sa, Collection<T> options, boolean isOptional, Player targetedPlayer) {
// Proliferate is always optional for all, no need to select best
// because countertype can't be chosen anymore, only look for posion counters
for (final Player p : Iterables.filter(options, Player.class)) {
if (p.isOpponentOf(ai)) {
if (p.getCounters(CounterType.POISON) > 0 && p.canReceiveCounters(CounterType.POISON)) {
return (T)p;
}
} else {
if (p.getCounters(CounterType.POISON) <= 5 || p.canReceiveCounters(CounterType.POISON)) {
return (T)p;
}
}
}
for (final Card c : Iterables.filter(options, Card.class)) {
final Card lki = CardUtil.getLKICopy(c);
// update all the counters there
boolean hasNegative = false;
for (final CounterType ct : c.getCounters().keySet()) {
hasNegative = hasNegative || ComputerUtil.isNegativeCounter(ct, c);
lki.setCounters(ct, lki.getCounters(ct) + 1);
}
// TODO need more logic there?
// it tries to evaluate the creatures
if (c.isCreature()) {
if (c.getController().isOpponentOf(ai) ==
(ComputerUtilCard.evaluateCreature(lki, true, false)
< ComputerUtilCard.evaluateCreature(c, true, false))) {
return (T)c;
}
} else {
if (!c.getController().isOpponentOf(ai) && !hasNegative) {
return (T)c;
}
}
}
return null;
}
}
package forge.ai.ability;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CounterType;
......@@ -26,12 +24,21 @@ public class TapAi extends TapAiBase {
if (turn.isOpponentOf(ai) && phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
// Tap things down if it's Human's turn
} else if (turn == ai && phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
// Tap creatures down if in combat -- handled in tapPrefTargeting().
} else if (SpellAbilityAi.isSorcerySpeed(sa)) {
// Cast it if it's a sorcery.
} else if (turn.equals(ai)) {
if (SpellAbilityAi.isSorcerySpeed(sa) && phase.getPhase().isBefore(PhaseType.COMBAT_BEGIN)) {
// Cast it if it's a sorcery.
} else if (phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
// Aggro Brains are willing to use TapEffects aggressively instead of defensively
AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
if (!aic.getBooleanProperty(AiProps.PLAY_AGGRO)) {
return false;
}
} else {
// Don't tap down after blockers
return false;
}
} else if (!SpellAbilityAi.playReusable(ai, sa)){
// Generally don't want to tap things with an Instant during AI turn outside of combat
// Generally don't want to tap things with an Instant during Players turn outside of combat
return false;
}
......
......@@ -21,7 +21,6 @@ import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.StaticData;
import forge.card.CardDb.SetPreference;
import forge.deck.CardPool;
......@@ -31,7 +30,6 @@ import forge.util.*;
import forge.util.storage.StorageBase;
import forge.util.storage.StorageReaderBase;
import forge.util.storage.StorageReaderFolder;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
......@@ -123,17 +121,17 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
private boolean smallSetOverride = false;
private String boosterMustContain = "";
private final CardInSet[] cards;
private final String[] tokenNormalized;
private final Map<String, Integer> tokenNormalized;
private int boosterArts = 1;
private SealedProduct.Template boosterTpl = null;
private CardEdition(CardInSet[] cards) {
this.cards = cards;
tokenNormalized = null;
tokenNormalized = new HashMap<>();
}
private CardEdition(CardInSet[] cards, String[] tokens) {
private CardEdition(CardInSet[] cards, Map<String, Integer> tokens) {
this.cards = cards;
this.tokenNormalized = tokens;
}
......@@ -191,6 +189,8 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
public String getBoosterMustContain() { return boosterMustContain; }
public CardInSet[] getCards() { return cards; }
public Map<String, Integer> getTokens() { return tokenNormalized; };
public static final Function<CardEdition, String> FN_GET_CODE = new Function<CardEdition, String>() {
@Override
public String apply(final CardEdition arg1) {
......@@ -261,7 +261,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
protected CardEdition read(File file) {
final Map<String, List<String>> contents = FileSection.parseSections(FileUtil.readFile(file));
List<String> tokenNormalized = new ArrayList<>();
Map<String, Integer> tokenNormalized = new HashMap<>();
List<CardEdition.CardInSet> processedCards = new ArrayList<>();
if (contents.containsKey("cards")) {
for(String line : contents.get("cards")) {
......@@ -290,13 +290,17 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
if (StringUtils.isBlank(line))
continue;
tokenNormalized.add(line);
if (!tokenNormalized.containsKey(line)) {
tokenNormalized.put(line, 1);
} else {
tokenNormalized.put(line, tokenNormalized.get(line) + 1);
}
}
}
CardEdition res = new CardEdition(
processedCards.toArray(new CardInSet[processedCards.size()]),
tokenNormalized.toArray(new String[tokenNormalized.size()])
tokenNormalized
);
//System.out.println(file.toString());
FileSection section = FileSection.parse(contents.get("metadata"), "=");
......
......@@ -581,12 +581,11 @@ public final class CardRulesPredicates {
public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardType.CoreType.Vanguard);
public static final Predicate<CardRules> IS_CONSPIRACY = CardRulesPredicates.coreType(true, CardType.CoreType.Conspiracy);
public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardType.CoreType.Land);
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = Predicates.not(Predicates.or(Presets.IS_CREATURE, Presets.IS_LAND));
public static final Predicate<CardRules> CAN_BE_BRAWL_COMMANDER = Predicates.or(Presets.IS_PLANESWALKER,
Predicates.and(Presets.IS_CREATURE, Presets.IS_LEGENDARY));
/** The Constant IS_NONCREATURE_SPELL_FOR_GENERATOR. **/
public static final Predicate<CardRules> IS_NONCREATURE_SPELL_FOR_GENERATOR = com.google.common.base.Predicates
/** The Constant IS_NON_CREATURE_SPELL. **/
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = com.google.common.base.Predicates
.or(Presets.IS_SORCERY, Presets.IS_INSTANT, Presets.IS_PLANESWALKER, Presets.IS_ENCHANTMENT,
Predicates.and(Presets.IS_ARTIFACT, Predicates.not(Presets.IS_CREATURE)));
......
......@@ -100,7 +100,7 @@ public abstract class DeckGeneratorBase {
trace.append("Creatures to add:").append(creatCnt).append("\n");
addCmcAdjusted(creatures, creatCnt, cmcLevels);
Predicate<PaperCard> preSpells = Predicates.compose(CardRulesPredicates.Presets.IS_NONCREATURE_SPELL_FOR_GENERATOR, PaperCard.FN_GET_RULES);
Predicate<PaperCard> preSpells = Predicates.compose(CardRulesPredicates.Presets.IS_NON_CREATURE_SPELL, PaperCard.FN_GET_RULES);
final Iterable<PaperCard> spells = Iterables.filter(cards, preSpells);
final int spellCnt = (int) Math.ceil(getSpellPercentage() * size);
trace.append("Spells to add:").append(spellCnt).append("\n");
......
......@@ -5,6 +5,7 @@ import forge.card.CardEdition;
import forge.card.CardRarity;
import forge.card.CardRules;
import forge.card.ColorSet;
import forge.util.MyRandom;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
......@@ -13,8 +14,9 @@ import java.util.Locale;
public class PaperToken implements InventoryItemFromSet, IPaperCard {
private String name;
private CardEdition edition;
private String imageFileName;
private ArrayList<String> imageFileName = new ArrayList<>();
private CardRules card;
private int artIndex = 1;
// takes a string of the form "<colors> <power> <toughness> <name>" such as: "B 0 0 Germ"
public static String makeTokenFileName(String in) {
......@@ -108,12 +110,20 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
this.name = c.getName();
this.edition = edition0;
if (edition != null && edition.getTokens().containsKey(imageFileName)) {
this.artIndex = edition.getTokens().get(imageFileName);
}
if (imageFileName == null) {
// This shouldn't really happen. We can just use the normalized name again for the base image name
this.imageFileName = makeTokenFileName(c, edition0);
this.imageFileName.add(makeTokenFileName(c, edition0));
} else {
String formatEdition = null == edition || CardEdition.UNKNOWN == edition ? "" : "_" + edition.getCode().toLowerCase();
this.imageFileName = String.format("%s%s", imageFileName, formatEdition);
this.imageFileName.add(String.format("%s%s", imageFileName, formatEdition));
for(int idx = 2; idx <= this.artIndex; idx++) {
this.imageFileName.add(String.format("%s%d%s", imageFileName, idx, formatEdition));
}
}
}
......@@ -121,14 +131,14 @@ public class PaperToken implements Inventor