Merge branch 'coremaster' into guildofravnica

This commit is contained in:
maustin
2018-10-16 21:38:20 +01:00
481 changed files with 3686 additions and 2029 deletions

View File

@@ -6,7 +6,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.16-SNAPSHOT</version>
<version>1.6.18-SNAPSHOT</version>
</parent>
<artifactId>forge-ai</artifactId>
@@ -30,30 +30,4 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>checkstyle-validation</id>
<phase>validate</phase>
<configuration>
<configLocation>../checkstyle.xml</configLocation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -38,6 +38,7 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.SpellApiBased;
import forge.game.card.*;
import forge.game.card.CardPredicates.Accessors;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
@@ -422,7 +423,8 @@ public class AiController {
}
}
}
return true;
return player.canPlayLand(c);
}
});
return landList;
@@ -1174,7 +1176,7 @@ public class AiController {
if (landsWannaPlay != null) {
landsWannaPlay = filterLandsToPlay(landsWannaPlay);
Log.debug("Computer " + game.getPhaseHandler().getPhase().nameForUi);
if (landsWannaPlay != null && !landsWannaPlay.isEmpty() && player.canPlayLand(null)) {
if (landsWannaPlay != null && !landsWannaPlay.isEmpty()) {
// TODO search for other land it might want to play?
Card land = chooseBestLandToPlay(landsWannaPlay);
if (ComputerUtil.getDamageFromETB(player, land) < player.getLife() || !player.canLoseLife()
@@ -1483,23 +1485,25 @@ public class AiController {
boolean hasLeyline1 = false;
SpellAbility saGemstones = null;
for(int i = 0; i < result.size(); i++) {
SpellAbility sa = result.get(i);
List<SpellAbility> toRemove = Lists.newArrayList();
for(SpellAbility sa : result) {
String srcName = sa.getHostCard().getName();
if ("Gemstone Caverns".equals(srcName)) {
if (saGemstones == null)
saGemstones = sa;
else
result.remove(i--);
toRemove.add(sa);
} else if ("Leyline of Singularity".equals(srcName)) {
if (!hasLeyline1)
hasLeyline1 = true;
else
result.remove(i--);
toRemove.add(sa);
}
}
for(SpellAbility sa : toRemove) {
result.remove(sa);
}
// Play them last
if (saGemstones != null) {
@@ -1801,6 +1805,12 @@ public class AiController {
return left.contains(ComputerUtilCard.getBestCreatureAI(all));
}
}
if ("Aminatou".equals(sa.getParam("AILogic")) && game.getPlayers().size() > 2) {
CardCollection all = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.NONLAND_PERMANENTS);
CardCollection left = CardLists.filterControlledBy(all, game.getNextPlayerAfter(player, Direction.Left));
CardCollection right = CardLists.filterControlledBy(all, game.getNextPlayerAfter(player, Direction.Right));
return Aggregates.sum(left, Accessors.fnGetCmc) > Aggregates.sum(right, Accessors.fnGetCmc);
}
return MyRandom.getRandom().nextBoolean();
}

View File

@@ -913,6 +913,10 @@ public class ComputerUtilMana {
// Make mana needed to avoid negative effect a mandatory cost for the AI
for (String manaPart : card.getSVar("ManaNeededToAvoidNegativeEffect").split(",")) {
// convert long color strings to short color strings
if (manaPart.isEmpty()) {
continue;
}
byte mask = ManaAtom.fromName(manaPart);
// make mana mandatory for AI

View File

@@ -26,6 +26,7 @@ import forge.game.card.CardPredicates.Presets;
import forge.game.combat.Combat;
import forge.game.cost.*;
import forge.game.mana.Mana;
import forge.game.mana.ManaConversionMatrix;
import forge.game.mana.ManaCostBeingPaid;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
@@ -921,7 +922,7 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public boolean payManaCost(ManaCost toPay, CostPartMana costPartMana, SpellAbility sa, String prompt /* ai needs hints as well */, boolean isActivatedSa) {
public boolean payManaCost(ManaCost toPay, CostPartMana costPartMana, SpellAbility sa, String prompt /* ai needs hints as well */, ManaConversionMatrix matrix, boolean isActivatedSa) {
// TODO Auto-generated method stub
ManaCostBeingPaid cost = isActivatedSa ? ComputerUtilMana.calculateManaCost(sa, false, 0) : new ManaCostBeingPaid(toPay);
return ComputerUtilMana.payManaCost(cost, sa, player);

View File

@@ -79,12 +79,14 @@ public enum SpellApiToAi {
.put(ApiType.FlipACoin, FlipACoinAi.class)
.put(ApiType.Fog, FogAi.class)
.put(ApiType.GainControl, ControlGainAi.class)
.put(ApiType.GainControlVariant, AlwaysPlayAi.class)
.put(ApiType.GainLife, LifeGainAi.class)
.put(ApiType.GainOwnership, CannotPlayAi.class)
.put(ApiType.GameDrawn, CannotPlayAi.class)
.put(ApiType.GenericChoice, ChooseGenericEffectAi.class)
.put(ApiType.Goad, GoadAi.class)
.put(ApiType.Haunt, HauntAi.class)
.put(ApiType.ImmediateTrigger, AlwaysPlayAi.class)
.put(ApiType.LoseLife, LifeLoseAi.class)
.put(ApiType.LosesGame, GameLossAi.class)
.put(ApiType.Mana, ManaEffectAi.class)

View File

@@ -1,8 +1,16 @@
package forge.ai.ability;
import forge.ai.SpellAbilityAi;
import forge.game.Direction;
import forge.game.Game;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
public class ChooseDirectionAi extends SpellAbilityAi {
@@ -12,10 +20,23 @@ public class ChooseDirectionAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player ai, SpellAbility sa) {
final String logic = sa.getParam("AILogic");
final Game game = sa.getActivatingPlayer().getGame();
if (logic == null) {
return false;
} else {
// TODO: default ai
if ("Aminatou".equals(logic)) {
CardCollection all = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.NONLAND_PERMANENTS);
CardCollection aiPermanent = CardLists.filterControlledBy(all, ai);
aiPermanent.remove(sa.getHostCard());
int aiValue = Aggregates.sum(aiPermanent, CardPredicates.Accessors.fnGetCmc);
CardCollection left = CardLists.filterControlledBy(all, game.getNextPlayerAfter(ai, Direction.Left));
CardCollection right = CardLists.filterControlledBy(all, game.getNextPlayerAfter(ai, Direction.Right));
int leftValue = Aggregates.sum(left, CardPredicates.Accessors.fnGetCmc);
int rightValue = Aggregates.sum(right, CardPredicates.Accessors.fnGetCmc);
if (aiValue > leftValue || aiValue > rightValue) {
return false;
}
}
}
return true;
}

View File

@@ -6,7 +6,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.16-SNAPSHOT</version>
<version>1.6.18-SNAPSHOT</version>
</parent>
<artifactId>forge-core</artifactId>
@@ -25,30 +25,4 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>checkstyle-validation</id>
<phase>validate</phase>
<configuration>
<configLocation>../checkstyle.xml</configLocation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -453,8 +453,6 @@ public final class CardRules implements ICardCharacteristics {
this.removedFromRandomDecks = "True".equalsIgnoreCase(value);
} else if ( "Picture".equals(variable) ) {
this.pictureUrl[this.curFace] = value;
} else if ( "Rarity".equals(variable) ) {
// discard that, they should supply it in SetInfo
} else
this.faces[curFace].addSVar(variable, value);
} else if ("SetInfo".equals(key)) {

View File

@@ -188,6 +188,21 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
return supertypes.remove(st);
}
public boolean remove(final String str) {
boolean changed = false;
if (CardType.isASupertype(str) && supertypes.remove(stringToSupertype.get(str))) {
changed = true;
} else if (CardType.isACardType(str) && coreTypes.remove(stringToCoreType.get(str))) {
changed = true;
} else if (subtypes.remove(str)) {
changed = true;
}
if (changed) {
calculatedType = null;
}
return changed;
}
public boolean setCreatureTypes(Collection<String> ctypes) {
// if it isn't a creature then this has no effect
if (!isCreature() && !isTribal()) {

View File

@@ -103,15 +103,6 @@ public final class MagicColor {
}
}
public static int getIndexOfFirstColor(final byte color){
for (int i = 0; i < NUMBER_OR_COLORS; i++) {
if ((color & WUBRG[i]) != 0) {
return i;
}
}
return -1; // colorless
}
/**
* The Interface Color.
*/

View File

@@ -14,6 +14,9 @@ public abstract class ManaAtom {
public static final byte[] MANACOLORS = new byte[] { WHITE, BLUE, BLACK, RED, GREEN };
public static final byte[] MANATYPES = new byte[] { WHITE, BLUE, BLACK, RED, GREEN, COLORLESS };
public static final byte ALL_MANA_COLORS = WHITE | BLUE | BLACK | RED | GREEN;
public static final byte ALL_MANA_TYPES = ALL_MANA_COLORS | COLORLESS;
public static final int GENERIC = 1 << 6;
// Below here skip due to byte conversion shenanigans
@@ -62,6 +65,6 @@ public abstract class ManaAtom {
return i;
}
}
return -1; // colorless
return -1; // somehow the mana is not colored or colorless?
}
}

View File

@@ -473,6 +473,10 @@ public enum DeckFormat {
if (paperCardPoolFilter != null) {
for (final Entry<PaperCard, Integer> cp : deck.getAllCardsInASinglePool()) {
if (!paperCardPoolFilter.apply(cp.getKey())) {
System.err.println(
"Excluding deck: '" + deck.toString() +
"' Reason: '" + cp.getKey() + "' is not legal."
);
return false;
}
}

View File

@@ -0,0 +1,26 @@
package forge.item.generation;
import forge.card.CardEdition;
import forge.item.BoosterPack;
import forge.item.PaperCard;
import java.util.List;
public class ChaosBoosterSupplier implements IUnOpenedProduct {
private List<CardEdition> sets;
public ChaosBoosterSupplier(List<CardEdition> sets) {
this.sets = sets;
}
@Override
public List<PaperCard> get() {
if (sets.size() == 0) {
System.out.println("No chaos boosters left to supply.");
return null;
}
final CardEdition set = sets.remove(0);
final BoosterPack pack = new BoosterPack(set.getCode(), set.getBoosterTemplate());
return pack.getCards();
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.16-SNAPSHOT</version>
<version>1.6.18-SNAPSHOT</version>
</parent>
<artifactId>forge-game</artifactId>
@@ -37,30 +37,4 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>checkstyle-validation</id>
<phase>validate</phase>
<configuration>
<configLocation>../checkstyle.xml</configLocation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -46,6 +46,11 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
protected Map<String, String> sVars = Maps.newHashMap();
protected Map<String, String> intrinsicChangedTextColors = Maps.newHashMap();
protected Map<String, String> intrinsicChangedTextTypes = Maps.newHashMap();
protected Map<String, String> changedTextColors = Maps.newHashMap();
protected Map<String, String> changedTextTypes = Maps.newHashMap();
/** Keys of descriptive (text) parameters. */
private static final ImmutableList<String> descriptiveKeys = ImmutableList.<String>builder()
.add("Description", "SpellDescription", "StackDescription", "TriggerDescription").build();
@@ -53,6 +58,11 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
private static final ImmutableList<String> mutableKeys = ImmutableList.<String>builder()
.add("AddAbility").build();
/**
* Keys that should not changed
*/
private static final ImmutableList<String> noChangeKeys = ImmutableList.<String>builder()
.add("TokenScript", "LegacyImage", "TokenImage", "NewName").build();
/**
* Sets the temporary.
*
@@ -449,9 +459,15 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
}
public void changeText() {
// copy changed text words into card trait there
this.changedTextColors = getHostCard().getChangedTextColorWords();
this.changedTextTypes = getHostCard().getChangedTextTypeWords();
for (final String key : this.mapParams.keySet()) {
final String value = this.originalMapParams.get(key), newValue;
if (descriptiveKeys.contains(key)) {
if (noChangeKeys.contains(key)) {
continue;
} else if (descriptiveKeys.contains(key)) {
// change descriptions differently
newValue = AbilityUtils.applyDescriptionTextChangeEffects(value, this);
} else if (mutableKeys.contains(key)) {
@@ -515,4 +531,53 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
public Set<String> getSVars() {
return sVars.keySet();
}
public Map<String, String> getChangedTextColors() {
return _combineChangedMap(intrinsicChangedTextColors, changedTextColors);
}
public Map<String, String> getChangedTextTypes() {
return _combineChangedMap(intrinsicChangedTextTypes, changedTextTypes);
}
private Map<String, String> _combineChangedMap(Map<String, String> input, Map<String, String> output) {
// no need to do something, just return hash
if (input.isEmpty()) {
return output;
}
if (output.isEmpty()) {
return input;
}
// magic combine them
Map<String, String> result = Maps.newHashMap(output);
for (Map.Entry<String, String> e : input.entrySet()) {
String value = e.getValue();
result.put(e.getKey(), output.containsKey(value) ? output.get(value) : value);
}
return result;
}
public void changeTextIntrinsic(Map<String,String> colorMap, Map<String,String> typeMap) {
intrinsicChangedTextColors = colorMap;
intrinsicChangedTextTypes = typeMap;
for (final String key : this.mapParams.keySet()) {
final String value = this.originalMapParams.get(key), newValue;
if (noChangeKeys.contains(key)) {
continue;
} else if (descriptiveKeys.contains(key)) {
// change descriptions differently
newValue = AbilityUtils.applyTextChangeEffects(value, true, colorMap, typeMap);
}else if (this.getHostCard().hasSVar(value)) {
// don't change literal SVar names!
continue;
} else {
newValue = AbilityUtils.applyTextChangeEffects(value, false, colorMap, typeMap);
}
if (newValue != null) {
this.mapParams.put(key, newValue);
}
}
// this does overwrite the original MapParams
this.originalMapParams = Maps.newHashMap(this.mapParams);
}
}

View File

@@ -428,6 +428,7 @@ public class GameAction {
if (!c.isToken() && !toBattlefield) {
copied.clearDevoured();
copied.clearDelved();
copied.clearConvoked();
}
// rule 504.6: reveal a face-down card leaving the stack
@@ -785,7 +786,9 @@ public class GameAction {
game.getReplacementHandler().cleanUpTemporaryReplacements();
for (final Player p : game.getPlayers()) {
p.getManaPool().restoreColorReplacements();
if (!game.getStack().isFrozen()) {
p.getManaPool().restoreColorReplacements();
}
p.clearStaticAbilities();
}
@@ -798,16 +801,18 @@ public class GameAction {
public boolean visit(final Card c) {
// need to get Card from preList if able
final Card co = preList.get(c);
for (int i = 0; i < co.getStaticAbilities().size(); i++) {
final StaticAbility stAb = co.getStaticAbilities().get(i);
List<StaticAbility> toRemove = Lists.newArrayList();
for (StaticAbility stAb : co.getStaticAbilities()) {
if (stAb.getMapParams().get("Mode").equals("Continuous")) {
staticAbilities.add(stAb);
}
if (stAb.isTemporary()) {
co.removeStaticAbility(stAb);
i--;
toRemove.add(stAb);
}
}
for (StaticAbility stAb : toRemove) {
co.removeStaticAbility(stAb);
}
if (!co.getStaticCommandList().isEmpty()) {
staticList.add(co);
}
@@ -851,8 +856,8 @@ public class GameAction {
}
for (final Card c : staticList) {
for (int i = 0; i < c.getStaticCommandList().size(); i++) {
final Object[] staticCheck = c.getStaticCommandList().get(i);
List<Object[]> toRemove = Lists.newArrayList();
for (Object[] staticCheck : c.getStaticCommandList()) {
final String leftVar = (String) staticCheck[0];
final String rightVar = (String) staticCheck[1];
final Card affected = (Card) staticCheck[2];
@@ -863,11 +868,13 @@ public class GameAction {
final int operandValue = AbilityUtils.calculateAmount(c, svarOperand, null);
if (Expressions.compare(sVar, svarOperator, operandValue)) {
((GameCommand) staticCheck[3]).run();
c.getStaticCommandList().remove(i);
i--;
toRemove.add(staticCheck);
affectedCards.add(c);
}
}
for (Object[] staticCheck : c.getStaticCommandList()) {
c.getStaticCommandList().remove(staticCheck);
}
}
// Exclude cards in hidden zones from update
Iterator<Card> it = affectedCards.iterator();

View File

@@ -18,6 +18,7 @@ import forge.game.ability.AbilityFactory.AbilityRecordType;
import forge.game.card.*;
import forge.game.cost.Cost;
import forge.game.keyword.KeywordInterface;
import forge.game.mana.ManaConversionMatrix;
import forge.game.mana.ManaCostBeingPaid;
import forge.game.player.Player;
import forge.game.player.PlayerCollection;
@@ -1642,7 +1643,7 @@ public class AbilityUtils {
return CardFactoryUtil.xCount(c, s2);
}
public static final void applyManaColorConversion(final Player p, final Map<String, String> params) {
public static final void applyManaColorConversion(ManaConversionMatrix matrix, final Map<String, String> params) {
String conversionType = params.get("ManaColorConversion");
// Choices are Additives(OR) or Restrictive(AND)
@@ -1655,14 +1656,15 @@ public class AbilityUtils {
String convertTo = params.get(key);
byte convertByte = 0;
if ("All".equals(convertTo)) {
convertByte = ColorSet.ALL_COLORS.getColor();
// IMPORTANT! We need to use Mana Color here not Card Color.
convertByte = ManaAtom.ALL_MANA_TYPES;
} else {
for (final String convertColor : convertTo.split(",")) {
convertByte |= ManaAtom.fromName(convertColor);
}
}
// AdjustColorReplacement has two different matrices handling final mana conversion under the covers
p.getManaPool().adjustColorReplacement(ManaAtom.fromName(c), convertByte, additive);
matrix.adjustColorReplacement(ManaAtom.fromName(c), convertByte, additive);
}
}
}
@@ -1724,12 +1726,18 @@ public class AbilityUtils {
}
private static final String applyTextChangeEffects(final String def, final Card card, final boolean isDescriptive) {
return applyTextChangeEffects(def, isDescriptive,
card.getChangedTextColorWords(), card.getChangedTextTypeWords());
}
public static final String applyTextChangeEffects(final String def, final boolean isDescriptive,
Map<String,String> colorMap, Map<String,String> typeMap) {
if (StringUtils.isEmpty(def)) {
return def;
}
String replaced = def;
for (final Entry<String, String> e : card.getChangedTextColorWords().entrySet()) {
for (final Entry<String, String> e : colorMap.entrySet()) {
final String key = e.getKey();
String value;
if (key.equals("Any")) {
@@ -1750,7 +1758,7 @@ public class AbilityUtils {
replaced = replaced.replaceAll("(?<!>)" + key, value);
}
}
for (final Entry<String, String> e : card.getChangedTextTypeWords().entrySet()) {
for (final Entry<String, String> e : typeMap.entrySet()) {
final String key = e.getKey();
final String pkey = CardType.getPluralType(key);
final String pvalue = getReplacedText(pkey, CardType.getPluralType(e.getValue()), isDescriptive);

View File

@@ -76,6 +76,7 @@ public enum ApiType {
FlipACoin (FlipCoinEffect.class),
Fog (FogEffect.class),
GainControl (ControlGainEffect.class),
GainControlVariant (ControlGainVariantEffect.class),
GainLife (LifeGainEffect.class),
GainOwnership (OwnershipGainEffect.class),
GameDrawn (GameDrawEffect.class),

View File

@@ -892,9 +892,11 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
do {
selectedCards = decider.getController().chooseCardsForZoneChange(destination, origin, sa, fetchList, delayedReveal, selectPrompt, decider);
} while (selectedCards != null && selectedCards.size() > changeNum);
for (Card card : selectedCards) {
chosenCards.add(card);
};
if (selectedCards != null) {
for (Card card : selectedCards) {
chosenCards.add(card);
}
}
// maybe prompt the user if they selected fewer than the maximum possible?
} else {
// one at a time

View File

@@ -113,6 +113,7 @@ public class CloneEffect extends SpellAbilityEffect {
}
final boolean keepName = sa.hasParam("KeepName");
final String newName = sa.getParamOrDefault("NewName", null);
final String originalName = tgtCard.getName();
final boolean copyingSelf = (tgtCard == cardToCopy);
final boolean isTransformed = cardToCopy.getCurrentStateName() == CardStateName.Transformed || cardToCopy.getCurrentStateName() == CardStateName.Meld;
@@ -157,9 +158,13 @@ public class CloneEffect extends SpellAbilityEffect {
}
// restore name if it should be unchanged
// this should only be used for Sakashima the Impostor Avatar
if (keepName) {
tgtCard.setName(originalName);
}
if (newName != null) {
tgtCard.setName(newName);
}
// If target is a flip card, also set characteristics of the flipped
// state.
@@ -168,6 +173,9 @@ public class CloneEffect extends SpellAbilityEffect {
if (keepName) {
flippedState.setName(originalName);
}
if (newName != null) {
tgtCard.setName(newName);
}
//keep the Clone card image for the cloned card
flippedState.setImageKey(imageFileName);
}
@@ -350,6 +358,18 @@ public class CloneEffect extends SpellAbilityEffect {
tgtCard.setBasePower(4);
tgtCard.setBaseToughness(4);
}
if (sa.hasParam("GainThisAbility")) {
SpellAbility root = sa.getRootAbility();
if (root.isTrigger() && root.getTrigger() != null) {
tgtCard.addTrigger(root.getTrigger().copy(tgtCard, false));
} else if (root.isReplacementAbility()) {
tgtCard.addReplacementEffect(root.getReplacementEffect().copy(tgtCard, false));
} else {
tgtCard.addSpellAbility(root.copy(tgtCard, false));
}
}
}
}

View File

@@ -143,24 +143,31 @@ public class ControlGainEffect extends SpellAbilityEffect {
}
if (lose != null) {
final GameCommand loseControl = getLoseControlCommand(tgtC, tStamp, bTapOnLose, source, kws);
if (lose.contains("LeavesPlay")) {
sa.getHostCard().addLeavesPlayCommand(getLoseControlCommand(tgtC, tStamp, bTapOnLose, source, kws));
sa.getHostCard().addLeavesPlayCommand(loseControl);
}
if (lose.contains("Untap")) {
sa.getHostCard().addUntapCommand(getLoseControlCommand(tgtC, tStamp, bTapOnLose, source, kws));
sa.getHostCard().addUntapCommand(loseControl);
}
if (lose.contains("LoseControl")) {
sa.getHostCard().addChangeControllerCommand(getLoseControlCommand(tgtC, tStamp, bTapOnLose, source, kws));
sa.getHostCard().addChangeControllerCommand(loseControl);
}
if (lose.contains("EOT")) {
game.getEndOfTurn().addUntil(getLoseControlCommand(tgtC, tStamp, bTapOnLose, source, kws));
game.getEndOfTurn().addUntil(loseControl);
tgtC.setSVar("SacMe", "6");
}
if (lose.contains("StaticCommandCheck")) {
String leftVar = sa.getSVar(sa.getParam("StaticCommandCheckSVar"));
String rightVar = sa.getParam("StaticCommandSVarCompare");
sa.getHostCard().addStaticCommandList(new Object[]{leftVar, rightVar, tgtC,
getLoseControlCommand(tgtC, tStamp, bTapOnLose, source, kws)});
sa.getHostCard().addStaticCommandList(new Object[]{leftVar, rightVar, tgtC, loseControl});
}
if (lose.contains("UntilTheEndOfYourNextTurn")) {
if (game.getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())) {
game.getEndOfTurn().registerUntilEnd(sa.getActivatingPlayer(), loseControl);
} else {
game.getEndOfTurn().addUntilEnd(sa.getActivatingPlayer(), loseControl);
}
}
}

View File

@@ -0,0 +1,49 @@
package forge.game.ability.effects;
import forge.game.Game;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
public class ControlGainVariantEffect extends SpellAbilityEffect {
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellEffect#getStackDescription(java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
protected String getStackDescription(SpellAbility sa) {
return sa.getDescription();
}
@Override
public void resolve(SpellAbility sa) {
// Aminatou, the Fateshifter (multiple players gain control of multiple permanents in an effect)
// Consider migrating cards with similar effects
// GainControl embedded in RepeatEach effects don't work well with timestamps
final Card source = sa.getHostCard();
final Game game = source.getGame();
CardCollection tgtCards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield),
sa.getParam("AllValid"), source.getController(), source);
if ("NextPlayerInChosenDirection".equals(sa.getParam("ChangeController")) && (source.getChosenDirection() != null) ) {
long tStamp = game.getNextTimestamp();
for (final Player p : game.getPlayers()) {
CardCollection valid = CardLists.filterControlledBy(tgtCards, game.getNextPlayerAfter(p, source.getChosenDirection()));
for (Card tgtC : valid) {
if (!tgtC.isInPlay() || !tgtC.canBeControlledBy(p)) {
continue;
}
tgtC.setController(p, tStamp);
tgtCards.remove(tgtC); // remove from the list if controller is changed
}
}
}
}
}

View File

@@ -8,6 +8,7 @@ import forge.game.GameEntity;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardFactory;
import forge.game.card.CardLists;
import forge.game.player.Player;
@@ -123,7 +124,7 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
}
} else {// Precursor Golem, Ink-Treader Nephilim
final String type = sa.getParam("CopyForEachCanTarget");
List<Card> valid = Lists.newArrayList();
CardCollection valid = new CardCollection();
List<Player> players = Lists.newArrayList();
Player originalTargetPlayer = Iterables.getFirst(getTargetPlayers(chosenSA), null);
for (final GameEntity o : candidates) {
@@ -142,10 +143,17 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
Card originalTarget = Iterables.getFirst(getTargetCards(chosenSA), null);
valid.remove(originalTarget);
mayChooseNewTargets = false;
for (final Card c : valid) {
if (sa.hasParam("ChooseOnlyOne")) {
Card choice = controller.getController().chooseSingleEntityForEffect(valid, sa, "Choose one");
SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(card, chosenSA.getHostCard(), chosenSA, true);
resetFirstTargetOnCopy(copy, c, targetedSA);
resetFirstTargetOnCopy(copy, choice, targetedSA);
copies.add(copy);
} else {
for (final Card c : valid) {
SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(card, chosenSA.getHostCard(), chosenSA, true);
resetFirstTargetOnCopy(copy, c, targetedSA);
copies.add(copy);
}
}
for (final Player p : players) {
SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(card, chosenSA.getHostCard(), chosenSA, true);
@@ -159,7 +167,20 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
"Select a spell to copy", ImmutableMap.of());
chosenSA.setActivatingPlayer(controller);
for (int i = 0; i < amount; i++) {
copies.add(CardFactory.copySpellAbilityAndPossiblyHost(card, chosenSA.getHostCard(), chosenSA, true));
SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(
card, chosenSA.getHostCard(), chosenSA, true);
// extra case for Epic to remove the keyword and the last part of the SpellAbility
if (sa.hasParam("Epic")) {
copy.getHostCard().removeIntrinsicKeyword("Epic");
SpellAbility sub = copy;
while (sub.getSubAbility() != null) {
sub = sub.getSubAbility();
}
sub.getParent().setSubAbility(null);
}
copies.add(copy);
}
}

View File

@@ -286,7 +286,7 @@ public class DigEffect extends SpellAbilityEffect {
}
}
if (!changeValid.isEmpty() && !sa.hasParam("ExileFaceDown")) {
if (!changeValid.isEmpty() && !sa.hasParam("ExileFaceDown") && !sa.hasParam("NoReveal")) {
game.getAction().reveal(movedCards, chooser, true,
chooser + " picked " + (movedCards.size() == 1 ? "this card" : "these cards") + " from ");
}

View File

@@ -105,6 +105,7 @@ public class DigUntilEffect extends SpellAbilityEffect {
final ZoneType digSite = sa.hasParam("DigZone") ? ZoneType.smartValueOf(sa.getParam("DigZone")) : ZoneType.Library;
boolean shuffle = sa.hasParam("Shuffle");
final boolean optional = sa.hasParam("Optional");
final boolean optionalFound = sa.hasParam("OptionalFoundMove");
for (final Player p : getTargetPlayers(sa)) {
if (p == null) {
@@ -156,15 +157,20 @@ public class DigUntilEffect extends SpellAbilityEffect {
final Iterator<Card> itr = found.iterator();
while (itr.hasNext()) {
final Card c = itr.next();
if (sa.hasParam("GainControl") && foundDest.equals(ZoneType.Battlefield)) {
c.setController(sa.getActivatingPlayer(), game.getNextTimestamp());
game.getAction().moveTo(c.getController().getZone(foundDest), c, sa);
} else if (sa.hasParam("NoMoveFound") && foundDest.equals(ZoneType.Library)) {
//Don't do anything
if (optionalFound && !p.getController().confirmAction(sa, null,
"Do you want to put that card to " + foundDest.name() + "?")) {
continue;
} else {
game.getAction().moveTo(foundDest, c, foundLibPos, sa);
if (sa.hasParam("GainControl") && foundDest.equals(ZoneType.Battlefield)) {
c.setController(sa.getActivatingPlayer(), game.getNextTimestamp());
game.getAction().moveTo(c.getController().getZone(foundDest), c, sa);
} else if (sa.hasParam("NoMoveFound") && foundDest.equals(ZoneType.Library)) {
//Don't do anything
} else {
game.getAction().moveTo(foundDest, c, foundLibPos, sa);
}
revealed.remove(c);
}
revealed.remove(c);
}
}

View File

@@ -264,6 +264,13 @@ public class EffectEffect extends SpellAbilityEffect {
else if (duration.equals("UntilEndOfCombat")) {
game.getEndOfCombat().addUntil(endEffect);
}
else if (duration.equals("UntilTheEndOfYourNextTurn")) {
if (game.getPhaseHandler().isPlayerTurn(controller)) {
game.getEndOfTurn().registerUntilEnd(controller, endEffect);
} else {
game.getEndOfTurn().addUntilEnd(controller, endEffect);
}
}
else if (duration.equals("ThisTurnAndNextTurn")) {
game.getUntap().addAt(new GameCommand() {
private static final long serialVersionUID = -5054153666503075717L;

View File

@@ -121,7 +121,7 @@ public class ManaEffect extends SpellAbilityEffect {
mask |= MagicColor.fromName(colorsNeeded.charAt(nChar));
}
colorMenu = mask == 0 ? ColorSet.ALL_COLORS : ColorSet.fromMask(mask);
byte val = act.getController().chooseColor("Select Mana to Produce", sa, colorMenu);
byte val = p.getController().chooseColor("Select Mana to Produce", sa, colorMenu);
if (0 == val) {
throw new RuntimeException("ManaEffect::resolve() /*any mana*/ - " + act + " color mana choice is empty for " + card.getName());
}

View File

@@ -18,7 +18,7 @@ public class SurveilEffect extends SpellAbilityEffect {
num = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("Amount"), sa);
}
sb.append(" surveil (").append(num).append(").");
sb.append(" surveils (").append(num).append(").");
return sb.toString();
}

View File

@@ -98,7 +98,7 @@ public class Card extends GameEntity implements Comparable<Card> {
private final KeywordCollection hiddenExtrinsicKeyword = new KeywordCollection();
// cards attached or otherwise linked to this card
private CardCollection equippedBy, fortifiedBy, hauntedBy, devouredCards, delvedCards, imprintedCards, encodedCards;
private CardCollection equippedBy, fortifiedBy, hauntedBy, devouredCards, delvedCards, convokedCards, imprintedCards, encodedCards;
private CardCollection mustBlockCards, clones, gainControlTargets, chosenCards, blockedThisTurn, blockedByThisTurn;
// if this card is attached or linked to something, what card is it currently attached to
@@ -725,6 +725,20 @@ public class Card extends GameEntity implements Comparable<Card> {
delvedCards = null;
}
public final CardCollectionView getConvoked() {
return CardCollection.getView(convokedCards);
}
public final void addConvoked(final Card c) {
if (convokedCards == null) {
convokedCards = new CardCollection();
}
convokedCards.add(c);
}
public final void clearConvoked() {
convokedCards = null;
}
public MapOfLists<GameEntity, Object> getRememberMap() {
return rememberMap;
}
@@ -3640,6 +3654,12 @@ public class Card extends GameEntity implements Comparable<Card> {
}
}
public final void removeIntrinsicKeyword(final KeywordInterface s) {
if (currentState.removeIntrinsicKeyword(s)) {
currentState.getView().updateKeywords(this, currentState);
}
}
public Collection<KeywordInterface> getExtrinsicKeyword() {
return extrinsicKeyword.getValues();
}

View File

@@ -7,8 +7,6 @@ import java.util.SortedMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import forge.card.CardType;
public final class CardChangedWords {
private final SortedMap<Long, CardChangedWord> map = Maps.newTreeMap();
@@ -68,14 +66,9 @@ public final class CardChangedWords {
// the actual change (b->c)
resultCache.put(ccw.getOriginalWord(), ccw.getNewWord());
// possible plural form
final String singular = CardType.getPluralType(ccw.getOriginalWord());
if (!singular.equals(ccw.getOriginalWord())) {
resultCache.put(singular, ccw.getNewWord());
}
}
// TODO should that be removed?
for (final String key : ImmutableList.copyOf(resultCache.keySet())) {
if (!key.equals("Any")) {
resultCache.put(key.toLowerCase(), resultCache.get(key).toLowerCase());

View File

@@ -842,7 +842,11 @@ public class CardFactoryUtil {
// only used by Opal Palace, and it does add the trigger to the card
return doXMath(cc.getCommanderCast(c), m, c);
}
if (l[0].startsWith("TotalCommanderCastFromCommandZone")) {
return doXMath(cc.getTotalCommanderCast(), m, c);
}
if (l[0].startsWith("MostProminentCreatureType")) {
String restriction = l[0].split(" ")[1];
CardCollection list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), restriction, cc, c);
@@ -2010,18 +2014,6 @@ public class CardFactoryUtil {
inst.createTraits(card, true);
}
// AddCost
if (card.hasSVar("FullCost")) {
String k[] = card.getSVar("FullCost").split(":");
final SpellAbility sa1 = card.getFirstSpellAbility();
if (sa1 != null && sa1.isSpell()) {
sa1.setPayCosts(new Cost(k[0], sa1.isAbility()));
if (k.length > 1) {
sa1.getMapParams().put("AILogic", k[1]);
}
}
}
// AltCost
String altCost = card.getSVar("AltCost");
if (StringUtils.isNotBlank(altCost)) {
@@ -2030,7 +2022,6 @@ public class CardFactoryUtil {
card.addSpellAbility(makeAltCostAbility(card, altCost, sa1));
}
}
}
private static ReplacementEffect createETBReplacement(final Card card, ReplacementLayer layer,
@@ -3755,14 +3746,14 @@ public class CardFactoryUtil {
// Epic does modify existing SA, and does not add new one
// Add the Epic effect as a subAbility
String dbStr = "DB$ Effect | Triggers$ EpicTrigger | SVars$ EpicCopy | StaticAbilities$ EpicCantBeCast | Duration$ Permanent | Unique$ True";
String dbStr = "DB$ Effect | Triggers$ EpicTrigger | SVars$ EpicCopy | StaticAbilities$ EpicCantBeCast | Duration$ Permanent";
final AbilitySub newSA = (AbilitySub) AbilityFactory.getAbility(dbStr.toString(), card);
card.setSVar("EpicCantBeCast", "Mode$ CantBeCast | ValidCard$ Card | Caster$ You | EffectZone$ Command | Description$ For the rest of the game, you can't cast spells.");
card.setSVar("EpicTrigger", "Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ EpicCopy | TriggerDescription$ "
+ "At the beginning of each of your upkeeps, copy " + card.toString() + " except for its epic ability.");
card.setSVar("EpicCopy", "DB$ CopySpellAbility | Defined$ EffectSource");
card.setSVar("EpicCopy", "DB$ CopySpellAbility | Defined$ EffectSource | Epic$ True");
final SpellAbility origSA = card.getFirstSpellAbility();

View File

@@ -1280,7 +1280,12 @@ public class CardProperty {
FCollectionView<Player> p = AbilityUtils.getDefinedPlayers(source, property.split("ControlledBy")[1], null);
cards = CardLists.filterControlledBy(cards, p);
}
cards = CardLists.getType(cards, prop);
if ("NonLandPermanent".equals(prop)) {
cards = CardLists.filter(cards, CardPredicates.Presets.NONLAND_PERMANENTS);
} else {
cards = CardLists.getType(cards, prop);
}
cards = CardLists.getCardsWithHighestCMC(cards);
if (!cards.contains(card)) {
return false;
@@ -1373,6 +1378,10 @@ public class CardProperty {
if (!source.getDelved().contains(card)) {
return false;
}
} else if (property.startsWith("convoked")) {
if (!source.getConvoked().contains(card)) {
return false;
}
} else if (property.startsWith("unequalPT")) {
if (card.getNetPower() == card.getNetToughness()) {
return false;

View File

@@ -231,6 +231,9 @@ public class CardState extends GameObject {
public final boolean removeIntrinsicKeyword(final String s) {
return intrinsicKeywords.remove(s);
}
public final boolean removeIntrinsicKeyword(final KeywordInterface s) {
return intrinsicKeywords.remove(s);
}
public final FCollectionView<SpellAbility> getSpellAbilities() {
FCollection<SpellAbility> newCol = new FCollection<SpellAbility>(manaAbilities);
@@ -539,7 +542,7 @@ public class CardState extends GameObject {
intrinsicKeywords.insert(inst);
}
}
public void updateChangedText() {
final List<CardTraitBase> allAbs = ImmutableList.<CardTraitBase>builder()
.addAll(manaAbilities)
@@ -554,4 +557,19 @@ public class CardState extends GameObject {
}
}
}
public void changeTextIntrinsic(Map<String,String> colorMap, Map<String,String> typeMap) {
final List<CardTraitBase> allAbs = ImmutableList.<CardTraitBase>builder()
.addAll(manaAbilities)
.addAll(nonManaAbilities)
.addAll(triggers)
.addAll(replacementEffects)
.addAll(staticAbilities)
.build();
for (final CardTraitBase ctb : allAbs) {
if (ctb.isIntrinsic()) {
ctb.changeTextIntrinsic(colorMap, typeMap);
}
}
}
}

View File

@@ -281,6 +281,8 @@ public final class CardUtil {
newCopy.setChangedCardKeywords(in.getChangedCardKeywords());
newCopy.setChangedCardTypes(in.getChangedCardTypesMap());
newCopy.copyChangedTextFrom(in);
newCopy.setMeldedWith(in.getMeldedWith());
newCopy.setTimestamp(in.getTimestamp());

View File

@@ -12,6 +12,7 @@ import forge.game.Game;
import forge.game.card.Card;
import forge.game.card.CardFactory;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardUtil;
import forge.game.keyword.KeywordInterface;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -20,6 +21,8 @@ import forge.item.PaperToken;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
public class TokenInfo {
final String name;
final String imageName;
@@ -229,10 +232,121 @@ public class TokenInfo {
String edition = host.getSetCode();
PaperToken token = StaticData.instance().getAllTokens().getToken(script, edition);
// TODO add Card Text Change from SpellAbility
if (token != null) {
return Card.fromPaperCard(token, null, game);
final Card result = Card.fromPaperCard(token, null, game);
// update Token with CardTextChanges
Map<String, String> colorMap = sa.getChangedTextColors();
Map<String, String> typeMap = sa.getChangedTextTypes();
if (!colorMap.isEmpty()) {
if (!result.isColorless()) {
// change Token Colors
byte color = CardUtil.getColors(result).getColor();
for (final Map.Entry<String, String> e : colorMap.entrySet()) {
byte v = MagicColor.fromName(e.getValue());
// Any used by Swirl the Mists
if ("Any".equals(e.getKey())) {
for (final byte c : MagicColor.WUBRG) {
// try to replace color flips
if ((color & c) != 0) {
color &= ~c;
color |= v;
}
}
} else {
byte c = MagicColor.fromName(e.getKey());
// try to replace color flips
if ((color & c) != 0) {
color &= ~c;
color |= v;
}
}
}
result.setColor(color);
}
}
if (!typeMap.isEmpty()) {
String oldName = result.getName();
CardType type = new CardType(result.getType());
String joinedName = StringUtils.join(type.getSubtypes(), " ");
final boolean nameGenerated = oldName.equals(joinedName);
boolean typeChanged = false;
if (!Iterables.isEmpty(type.getSubtypes())) {
for (final Map.Entry<String, String> e : typeMap.entrySet()) {
if (type.hasSubtype(e.getKey())) {
type.remove(e.getKey());
type.add(e.getValue());
typeChanged = true;
}
}
}
if (typeChanged) {
result.setType(type);
// update generated Name
if (nameGenerated) {
result.setName(StringUtils.join(type.getSubtypes(), " "));
}
}
}
// replace Intrinsic Keyword
List<KeywordInterface> toRemove = Lists.newArrayList();
List<String> toAdd = Lists.newArrayList();
for (final KeywordInterface k : result.getCurrentState().getIntrinsicKeywords()) {
final String o = k.getOriginal();
// only Modifiable should go there
if (!CardUtil.isKeywordModifiable(o)) {
continue;
}
String r = new String(o);
// replace types
for (final Map.Entry<String, String> e : typeMap.entrySet()) {
final String key = e.getKey();
final String pkey = CardType.getPluralType(key);
final String value = e.getValue();
final String pvalue = CardType.getPluralType(e.getValue());
r = r.replaceAll(pkey, pvalue);
r = r.replaceAll(key, value);
}
// replace color words
for (final Map.Entry<String, String> e : colorMap.entrySet()) {
final String vName = e.getValue();
final String vCaps = StringUtils.capitalize(vName);
final String vLow = vName.toLowerCase();
if ("Any".equals(e.getKey())) {
for (final byte c : MagicColor.WUBRG) {
final String cName = MagicColor.toLongString(c);
final String cNameCaps = StringUtils.capitalize(cName);
final String cNameLow = cName.toLowerCase();
r = r.replaceAll(cNameCaps, vCaps);
r = r.replaceAll(cNameLow, vLow);
}
} else {
final String cName = e.getKey();
final String cNameCaps = StringUtils.capitalize(cName);
final String cNameLow = cName.toLowerCase();
r = r.replaceAll(cNameCaps, vCaps);
r = r.replaceAll(cNameLow, vLow);
}
}
if (!r.equals(o)) {
toRemove.add(k);
toAdd.add(r);
}
}
for (final KeywordInterface k : toRemove) {
result.getCurrentState().removeIntrinsicKeyword(k);
}
result.addIntrinsicKeywords(toAdd);
result.getCurrentState().changeTextIntrinsic(colorMap, typeMap);
return result;
}
return null;

View File

@@ -613,23 +613,36 @@ public class Combat {
}
// Call this method right after turn-based action of declare blockers has been performed
public final void fireTriggersForUnblockedAttackers() {
public final void fireTriggersForUnblockedAttackers(final Game game) {
boolean bFlag = false;
List<GameEntity> defenders = Lists.newArrayList();
for (AttackingBand ab : attackedByBands.values()) {
Collection<Card> blockers = blockedBands.get(ab);
boolean isBlocked = blockers != null && !blockers.isEmpty();
ab.setBlocked(isBlocked);
if (!isBlocked) {
bFlag = true;
defenders.add(getDefenderByAttacker(ab));
for (Card attacker : ab.getAttackers()) {
// Run Unblocked Trigger
final Map<String, Object> runParams = Maps.newHashMap();
runParams.put("Attacker", attacker);
runParams.put("Defender",getDefenderByAttacker(attacker));
runParams.put("DefendingPlayer", getDefenderPlayerByAttacker(attacker));
attacker.getGame().getTriggerHandler().runTrigger(TriggerType.AttackerUnblocked, runParams, false);
game.getTriggerHandler().runTrigger(TriggerType.AttackerUnblocked, runParams, false);
}
}
}
if (bFlag) {
// triggers for Coveted Jewel
// currently there is only one attacking player
// should be updated when two-headed-giant is done
final Map<String, Object> runParams = Maps.newHashMap();
runParams.put("AttackingPlayer", getAttackingPlayer());
runParams.put("Defenders", defenders);
game.getTriggerHandler().runTrigger(TriggerType.AttackerUnblockedOnce, runParams, false);
}
}
private final boolean assignBlockersDamage(boolean firstStrikeDamage) {

View File

@@ -237,6 +237,7 @@ public class CostAdjustment {
}
}
if (sa.getHostCard().hasKeyword(Keyword.CONVOKE)) {
sa.getHostCard().clearConvoked();
adjustCostByConvokeOrImprovise(cost, sa, false, test);
}
if (sa.getHostCard().hasKeyword(Keyword.IMPROVISE)) {
@@ -270,6 +271,9 @@ public class CostAdjustment {
cost.decreaseShard(conv.getValue(), 1);
if (!test) {
conv.getKey().tap();
if (!improvise) {
sa.getHostCard().addConvoked(conv.getKey());
}
}
}
}
@@ -499,15 +503,6 @@ public class CostAdjustment {
if (!sa.isSpell() || !((Spell) sa).isCastFaceDown()) {
return false;
}
} else if (type.equals("SelfMonstrosity")) {
if (!(sa instanceof AbilityActivated) || !sa.hasParam("Monstrosity") || sa.isTemporary()) {
// Nemesis of Mortals
return false;
}
} else if (type.equals("SelfIntrinsicAbility")) {
if (!(sa instanceof AbilityActivated) || sa.isReplacementAbility() || sa.isTemporary()) {
return false;
}
}
}
if (params.containsKey("AffectedZone")) {

View File

@@ -19,6 +19,7 @@ package forge.game.cost;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
import forge.game.mana.ManaConversionMatrix;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -37,6 +38,9 @@ public class CostPartMana extends CostPart {
private boolean isEnchantedCreatureCost = false;
private final String restriction;
private ManaConversionMatrix cardMatrix = null;
public void setCardMatrix(ManaConversionMatrix mtrx) { cardMatrix = mtrx; }
public int paymentOrder() { return shouldPayLast() ? 200 : 0; }
public boolean shouldPayLast() {
@@ -148,7 +152,7 @@ public class CostPartMana extends CostPart {
sa.clearManaPaid();
// decision not used here, the whole payment is interactive!
return payer.getController().payManaCost(this, sa, null, true);
return payer.getController().payManaCost(this, sa, null, cardMatrix, true);
}
}

View File

@@ -21,6 +21,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.game.Game;
import forge.game.card.Card;
import forge.game.mana.ManaConversionMatrix;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
@@ -35,7 +36,7 @@ import java.util.Map;
* @author Forge
* @version $Id$
*/
public class CostPayment {
public class CostPayment extends ManaConversionMatrix {
private final Cost cost;
private Cost adjustedCost;
private final SpellAbility ability;
@@ -70,6 +71,7 @@ public class CostPayment {
this.cost = cost;
this.adjustedCost = cost;
this.ability = abil;
restoreColorReplacements();
}
/**
@@ -137,6 +139,11 @@ public class CostPayment {
PaymentDecision pd = part.accept(decisionMaker);
// RIght before we start paying as decided, we need to transfer the CostPayments matrix over?
if (part instanceof CostPartMana) {
((CostPartMana)part).setCardMatrix(this);
}
if (pd == null || !part.payAsDecided(decisionMaker.getPlayer(), pd, ability)) {
game.costPaymentStack.pop(); // cost is resolved
return false;

View File

@@ -96,6 +96,10 @@ public class KeywordCollection implements Iterable<String>, Serializable {
return result;
}
public boolean remove(KeywordInterface keyword) {
return map.remove(keyword.getKeyword(), keyword);
}
public boolean removeAll(Iterable<String> keywords) {
boolean result = false;
for (String k : keywords) {

View File

@@ -0,0 +1,45 @@
package forge.game.mana;
import forge.card.mana.ManaAtom;
public class ManaConversionMatrix {
static byte[] identityMatrix = { ManaAtom.WHITE, ManaAtom.BLUE, ManaAtom.BLACK, ManaAtom.RED, ManaAtom.GREEN, ManaAtom.COLORLESS };
// Conversion matrix ORs byte values to make mana more payable
// Restrictive matrix ANDs byte values to make mana less payable
byte[] colorConversionMatrix = new byte[ManaAtom.MANATYPES.length];
byte[] colorRestrictionMatrix = new byte[ManaAtom.MANATYPES.length];
public void adjustColorReplacement(byte originalColor, byte replacementColor, boolean additive) {
// Fix the index without hardcodes
int rowIdx = ManaAtom.getIndexOfFirstManaType(originalColor);
rowIdx = rowIdx < 0 ? identityMatrix.length - 1 : rowIdx;
if (additive) {
colorConversionMatrix[rowIdx] |= replacementColor;
}
else {
colorRestrictionMatrix[rowIdx] &= replacementColor;
}
}
public void applyCardMatrix(ManaConversionMatrix extraMatrix) {
for (int i = 0; i < colorConversionMatrix.length; i++) {
colorConversionMatrix[i] |= extraMatrix.colorConversionMatrix[i];
}
for (int i = 0; i < colorRestrictionMatrix.length; i++) {
colorRestrictionMatrix[i] &= extraMatrix.colorRestrictionMatrix[i];
}
}
public void restoreColorReplacements() {
// By default each color can only be paid by itself ( {G} -> {G}, {C} -> {C}
for (int i = 0; i < colorConversionMatrix.length; i++) {
colorConversionMatrix[i] = identityMatrix[i];
}
// By default all mana types are unrestricted
for (int i = 0; i < colorRestrictionMatrix.length; i++) {
colorRestrictionMatrix[i] = ManaAtom.ALL_MANA_TYPES;
}
}
}

View File

@@ -586,6 +586,7 @@ public class ManaCostBeingPaid {
// Boolean addX used to add Xs into the returned value
final StringBuilder sb = new StringBuilder();
// TODO Prepend a line about paying with any type/color if available
if (addX) {
for (int i = 0; i < this.getXcounter(); i++) {
sb.append("{X}");
@@ -595,10 +596,11 @@ public class ManaCostBeingPaid {
int nGeneric = getGenericManaAmount();
List<ManaCostShard> shards = new ArrayList<ManaCostShard>(unpaidShards.keySet());
if (pool != null) { //replace shards with generic mana if they can be paid with any color mana
// TODO Fix this. Should we really be changing Shards here?
if (false && pool != null) { //replace shards with generic mana if they can be paid with any color mana
for (int i = 0; i < shards.size(); i++) {
ManaCostShard shard = shards.get(i);
if (shard != ManaCostShard.GENERIC && pool.getPossibleColorUses(shard.getColorMask()) == MagicColor.ALL_COLORS) {
if (shard != ManaCostShard.GENERIC && pool.getPossibleColorUses(shard.getColorMask()) == ManaAtom.ALL_MANA_TYPES) {
nGeneric += unpaidShards.get(shard).totalCount;
shards.remove(i);
i--;

View File

@@ -20,9 +20,7 @@ package forge.game.mana;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import forge.GameCommand;
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.card.mana.ManaAtom;
import forge.card.mana.ManaCostShard;
@@ -37,14 +35,9 @@ import forge.game.player.Player;
import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.*;
/**
* <p>
@@ -54,7 +47,7 @@ import java.util.List;
* @author Forge
* @version $Id$
*/
public class ManaPool implements Iterable<Mana> {
public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
private final Player owner;
private final Multimap<Byte, Mana> floatingMana = ArrayListMultimap.create();
@@ -355,37 +348,10 @@ public class ManaPool implements Iterable<Mana> {
Player p = sa.getActivatingPlayer();
p.getGame().fireEvent(new GameEventZone(ZoneType.Battlefield, p, EventValueChangeType.ComplexUpdate, null));
}
// Conversion matrix ORs byte values to make mana more payable
// Restrictive matrix ANDs byte values to make mana less payable
private final byte[] colorConversionMatrix = new byte[ManaAtom.MANATYPES.length];
private final byte[] colorRestrictionMatrix = new byte[ManaAtom.MANATYPES.length];
private static final byte[] identityMatrix = { ManaAtom.WHITE, ManaAtom.BLUE, ManaAtom.BLACK, ManaAtom.RED, ManaAtom.GREEN, ManaAtom.COLORLESS };
public void adjustColorReplacement(byte originalColor, byte replacementColor, boolean additive) {
// Fix the index without hardcodes
int rowIdx = MagicColor.getIndexOfFirstColor(originalColor);
rowIdx = rowIdx < 0 ? identityMatrix.length - 1 : rowIdx;
if (additive) {
colorConversionMatrix[rowIdx] |= replacementColor;
}
else {
colorRestrictionMatrix[rowIdx] &= replacementColor;
}
}
public void restoreColorReplacements() {
for (int i = 0; i < colorConversionMatrix.length; i++) {
colorConversionMatrix[i] = identityMatrix[i];
}
for (int i = 0; i < colorRestrictionMatrix.length; i++) {
colorRestrictionMatrix[i] = ColorSet.ALL_COLORS.getColor();
}
}
public byte getPossibleColorUses(byte color) {
// Take the current conversion value, AND with restrictions to get mana usage
int rowIdx = MagicColor.getIndexOfFirstColor(color);
int rowIdx = ManaAtom.getIndexOfFirstManaType(color);
int matrixIdx = rowIdx < 0 ? identityMatrix.length - 1 : rowIdx;
byte colorUse = colorConversionMatrix[matrixIdx];
@@ -394,14 +360,16 @@ public class ManaPool implements Iterable<Mana> {
}
public boolean canPayForShardWithColor(ManaCostShard shard, byte color) {
// TODO Debug this for Paying Gonti,
byte line = getPossibleColorUses(color);
for (int i = 0; i < MagicColor.NUMBER_OR_COLORS; i++) {
byte outColor = MagicColor.WUBRG[i];
for(byte outColor : ManaAtom.MANATYPES) {
if ((line & outColor) != 0 && shard.canBePaidWithManaOfColor(outColor)) {
return true;
}
}
// TODO The following may not be needed anymore?
if (((color & (byte) ManaAtom.COLORLESS) != 0) && shard.canBePaidWithManaOfColor((byte) (byte)ManaAtom.COLORLESS)) {
return true;
}

View File

@@ -372,6 +372,8 @@ public class PhaseHandler implements java.io.Serializable {
game.getEndOfCombat().executeUntil(); //Repeat here in case Time Stop et. al. ends combat early
game.getEndOfTurn().executeUntil();
game.getEndOfTurn().executeUntilEndOfPhase(playerTurn);
game.getEndOfTurn().registerUntilEndCommand(playerTurn);
for (Player player : game.getPlayers()) {
player.onCleanupPhase();
@@ -664,7 +666,7 @@ public class PhaseHandler implements java.io.Serializable {
combat.removeAbsentCombatants();
combat.fireTriggersForUnblockedAttackers();
combat.fireTriggersForUnblockedAttackers(game);
final List<Card> declaredBlockers = combat.getAllBlockers();
if (!declaredBlockers.isEmpty()) {

View File

@@ -1751,6 +1751,9 @@ public class Player extends GameEntity implements Comparable<Player> {
return canPlayLand(land, false);
}
public final boolean canPlayLand(final Card land, final boolean ignoreZoneAndTiming) {
return canPlayLand(land, ignoreZoneAndTiming, null);
}
public final boolean canPlayLand(final Card land, final boolean ignoreZoneAndTiming, SpellAbility landSa) {
if (!ignoreZoneAndTiming && !canCastSorcery()) {
return false;
}
@@ -1766,7 +1769,7 @@ public class Player extends GameEntity implements Comparable<Player> {
}
if (land != null && !ignoreZoneAndTiming) {
final boolean mayPlay = !land.mayPlay(this).isEmpty();
final boolean mayPlay = landSa == null ? !land.mayPlay(this).isEmpty() : landSa.getMayPlay() != null;
if (land.getOwner() != this && !mayPlay) {
return false;
}
@@ -2662,6 +2665,14 @@ public class Player extends GameEntity implements Comparable<Player> {
commanderCast.put(commander, getCommanderCast(commander) + 1);
}
public int getTotalCommanderCast() {
int result = 0;
for (Integer i : commanderCast.values()) {
result += i;
}
return result;
}
public boolean isPlayingExtraTurn() {
return isPlayingExtraTrun;
}

View File

@@ -20,6 +20,7 @@ import forge.game.cost.Cost;
import forge.game.cost.CostPart;
import forge.game.cost.CostPartMana;
import forge.game.mana.Mana;
import forge.game.mana.ManaConversionMatrix;
import forge.game.replacement.ReplacementEffect;
import forge.game.spellability.*;
import forge.game.trigger.WrappedAbility;
@@ -220,9 +221,13 @@ public abstract class PlayerController {
public abstract void resetAtEndOfTurn(); // currently used by the AI to perform card memory cleanup
public final boolean payManaCost(CostPartMana costPartMana, SpellAbility sa, String prompt, boolean isActivatedAbility) {
return payManaCost(costPartMana.getManaCostFor(sa), costPartMana, sa, prompt, isActivatedAbility);
return payManaCost(costPartMana, sa, prompt, null, isActivatedAbility);
}
public abstract boolean payManaCost(ManaCost toPay, CostPartMana costPartMana, SpellAbility sa, String prompt, boolean isActivatedAbility);
public final boolean payManaCost(CostPartMana costPartMana, SpellAbility sa, String prompt, ManaConversionMatrix matrix, boolean isActivatedAbility) {
return payManaCost(costPartMana.getManaCostFor(sa), costPartMana, sa, prompt, matrix, isActivatedAbility);
}
public abstract boolean payManaCost(ManaCost toPay, CostPartMana costPartMana, SpellAbility sa, String prompt, ManaConversionMatrix matrix, boolean isActivatedAbility);
public abstract Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCards, boolean improvise);

View File

@@ -181,7 +181,7 @@ public class ReplacementHandler {
final String effectAbString = host.getSVar(effectSVar);
// TODO: the source of replacement effect should be the source of the original effect
effectSA = AbilityFactory.getAbility(effectAbString, host);
effectSA.setTrigger(true);
//effectSA.setTrigger(true);
SpellAbility tailend = effectSA;
do {
@@ -209,8 +209,9 @@ public class ReplacementHandler {
if (replacementEffect.isIntrinsic()) {
effectSA.setIntrinsic(true);
effectSA.changeText();
effectSA.setReplacementAbility(true);
}
effectSA.setReplacementAbility(true);
effectSA.setReplacementEffect(replacementEffect);
}
// Decider gets to choose whether or not to apply the replacement.
@@ -309,13 +310,15 @@ public class ReplacementHandler {
game.forEachCardInGame(new Visitor<Card>() {
@Override
public boolean visit(Card c) {
for (int i = 0; i < c.getReplacementEffects().size(); i++) {
ReplacementEffect rep = c.getReplacementEffects().get(i);
List<ReplacementEffect> toRemove = Lists.newArrayList();
for (ReplacementEffect rep : c.getReplacementEffects()) {
if (rep.isTemporary()) {
c.removeReplacementEffect(rep);
i--;
toRemove.add(rep);
}
}
for (ReplacementEffect rep : toRemove) {
c.removeReplacementEffect(rep);
}
return true;
}
});

View File

@@ -17,13 +17,10 @@
*/
package forge.game.spellability;
import forge.game.Game;
import forge.game.card.Card;
import forge.game.cost.Cost;
import forge.game.player.Player;
import forge.game.staticability.StaticAbility;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
public class LandAbility extends Ability {
@@ -33,57 +30,14 @@ public class LandAbility extends Ability {
setMayPlay(mayPlay);
}
public LandAbility(Card sourceCard) {
this(sourceCard, sourceCard.getController(), (StaticAbility)null);
this(sourceCard, sourceCard.getController(), null);
}
@Override
public boolean canPlay() {
final Card land = this.getHostCard();
final Player p = this.getActivatingPlayer();
final Game game = p.getGame();
if (!p.canCastSorcery()) {
return false;
}
// CantBeCast static abilities
for (final Card ca : game.getCardsIn(ZoneType.listValueOf("Battlefield,Command"))) {
final Iterable<StaticAbility> staticAbilities = ca.getStaticAbilities();
for (final StaticAbility stAb : staticAbilities) {
if (stAb.applyAbility("CantPlayLand", land, this)) {
return false;
}
}
}
if (land != null) {
final boolean mayPlay = getMayPlay() != null;
if (land.getOwner() != p && !mayPlay) {
return false;
}
final Zone zone = game.getZoneOf(land);
if (zone != null && (zone.is(ZoneType.Battlefield) || (!zone.is(ZoneType.Hand) && !mayPlay))) {
return false;
}
}
// **** Check for land play limit per turn ****
// Dev Mode
if (p.getController().canPlayUnlimitedLands() || p.hasKeyword("You may play any number of additional lands on each of your turns.")) {
return true;
}
// check for adjusted max lands play per turn
int adjMax = 1;
for (String keyword : p.getKeywords()) {
if (keyword.startsWith("AdjustLandPlays")) {
final String[] k = keyword.split(":");
adjMax += Integer.valueOf(k[1]);
}
}
if (p.getLandsPlayedThisTurn() < adjMax) {
return true;
}
return false;
return p.canPlayLand(land, false, this);
}
@Override
public void resolve() {

View File

@@ -38,7 +38,9 @@ import forge.game.cost.CostRemoveCounter;
import forge.game.keyword.Keyword;
import forge.game.mana.Mana;
import forge.game.player.Player;
import forge.game.replacement.ReplacementEffect;
import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerType;
import forge.game.trigger.WrappedAbility;
import forge.util.Expressions;
@@ -87,8 +89,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
private boolean basicSpell = true;
private boolean trigger = false;
private Trigger triggerObj = null;
private boolean optionalTrigger = false;
private boolean replacementAbility = false;
private ReplacementEffect replacementEffect = null;
private int sourceTrigger = -1;
private List<Object> triggerRemembered = Lists.newArrayList();
@@ -913,6 +917,14 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
trigger = trigger0;
}
public Trigger getTrigger() {
return triggerObj;
}
public void setTrigger(final Trigger t) {
triggerObj = t;
}
public boolean isOptionalTrigger() {
return optionalTrigger;
}
@@ -934,6 +946,14 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
replacementAbility = replacement;
}
public ReplacementEffect getReplacementEffect() {
return replacementEffect;
}
public void setReplacementEffect(final ReplacementEffect re) {
this.replacementEffect = re;
}
public boolean isMandatory() {
return false;
}
@@ -1709,6 +1729,31 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
}
/* (non-Javadoc)
* @see forge.game.CardTraitBase#changeTextIntrinsic(java.util.Map, java.util.Map)
*/
@Override
public void changeTextIntrinsic(Map<String, String> colorMap, Map<String, String> typeMap) {
super.changeTextIntrinsic(colorMap, typeMap);
if (subAbility != null) {
// if the parent of the subability is not this,
// then there might be a loop
if (subAbility.getParent() == this) {
subAbility.changeTextIntrinsic(colorMap, typeMap);
}
}
for (AbilitySub sa : additionalAbilities.values()) {
sa.changeTextIntrinsic(colorMap, typeMap);
}
for (List<AbilitySub> list : additionalAbilityLists.values()) {
for (AbilitySub sa : list) {
sa.changeTextIntrinsic(colorMap, typeMap);
}
}
}
@Override
public void setIntrinsic(boolean i) {
super.setIntrinsic(i);

View File

@@ -160,6 +160,14 @@ public class StaticAbilityCantBeCast {
return false;
}
if (params.containsKey("Origin")) {
List<ZoneType> src = ZoneType.listValueOf(params.get("Origin"));
if (!src.contains(card.getZone().getZoneType())) {
return false;
}
}
if (params.containsKey("Player") && (player != null)
&& !player.isValid(params.get("Player"), hostCard.getController(), hostCard, null)) {
return false;

View File

@@ -41,7 +41,6 @@ import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler;
import forge.game.zone.ZoneType;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
@@ -481,7 +480,7 @@ public final class StaticAbilityContinuous {
}
if (params.containsKey("ManaColorConversion")) {
AbilityUtils.applyManaColorConversion(p, params);
AbilityUtils.applyManaColorConversion(p.getManaPool(), params);
}
}
}

View File

@@ -37,6 +37,7 @@ import java.util.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.util.TextUtil;
/**
@@ -169,11 +170,7 @@ public abstract class Trigger extends TriggerReplacementBase {
if (!desc.contains("ABILITY")) {
return desc;
}
SpellAbility sa = getOverridingAbility();
if (sa == null && this.mapParams.containsKey("Execute")) {
sa = AbilityFactory.getAbility(state, this.mapParams.get("Execute"));
setOverridingAbility(sa);
}
SpellAbility sa = ensureAbility();
return replaceAbilityText(desc, sa);
@@ -338,7 +335,22 @@ public abstract class Trigger extends TriggerReplacementBase {
return false;
}
}
if (this.mapParams.containsKey("TriggerRememberedInZone")) {
// check delayed trigger remembered objects (Mnemonic Betrayal)
// make this check more general if possible
boolean bFlag = true;
for (Object o : getTriggerRemembered()) {
if (o instanceof Card && ((Card) o).isInZone(ZoneType.smartValueOf(this.mapParams.get("TriggerRememberedInZone")))) {
bFlag = false;
break;
}
}
if (bFlag) {
return false;
}
}
if ( !meetsCommonRequirements(this.mapParams))
return false;
@@ -583,4 +595,48 @@ public abstract class Trigger extends TriggerReplacementBase {
throw new RuntimeException("Trigger : clone() error, " + ex);
}
}
/* (non-Javadoc)
* @see forge.game.CardTraitBase#changeText()
*/
@Override
public void changeText() {
if (!isIntrinsic()) {
return;
}
super.changeText();
ensureAbility();
if (getOverridingAbility() != null) {
getOverridingAbility().changeText();
}
}
/* (non-Javadoc)
* @see forge.game.CardTraitBase#changeTextIntrinsic(java.util.Map, java.util.Map)
*/
@Override
public void changeTextIntrinsic(Map<String, String> colorMap, Map<String, String> typeMap) {
if (!isIntrinsic()) {
return;
}
super.changeTextIntrinsic(colorMap, typeMap);
ensureAbility();
if (getOverridingAbility() != null) {
getOverridingAbility().changeTextIntrinsic(colorMap, typeMap);
}
}
private SpellAbility ensureAbility() {
SpellAbility sa = getOverridingAbility();
if (sa == null && hasParam("Execute")) {
sa = AbilityFactory.getAbility(getHostCard(), getParam("Execute"));
setOverridingAbility(sa);
}
return sa;
}
}

View File

@@ -0,0 +1,98 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.game.trigger;
import forge.game.GameEntity;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
import java.util.List;
import java.util.Map;
/**
* <p>
* Trigger_AttackerUnblockedOnce class.
* </p>
*
* @author Forge
* @version $Id$
*/
public class TriggerAttackerUnblockedOnce extends Trigger {
/**
* <p>
* Constructor for Trigger_AttackerUnblocked.
* </p>
*
* @param params
* a {@link java.util.HashMap} object.
* @param host
* a {@link forge.game.card.Card} object.
* @param intrinsic
* the intrinsic
*/
public TriggerAttackerUnblockedOnce(final java.util.Map<String, String> params, final Card host, final boolean intrinsic) {
super(params, host, intrinsic);
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public final boolean performTest(final Map<String, Object> runParams2) {
if (hasParam("ValidDefenders")) {
boolean valid = false;
final List<GameEntity> srcs = (List<GameEntity>) runParams2.get("Defenders");
for (GameEntity c : srcs) {
if (c.isValid(this.mapParams.get("ValidDefenders").split(","), this.getHostCard().getController(), this.getHostCard(), null)) {
valid = true;
}
}
if (!valid) {
return false;
}
/*
if (hasParam("ValidAttackers")) {
// should be updated if a creature of a specific type attackes a defender
}
*/
}
if (hasParam("ValidAttackingPlayer")) {
if (!matchesValid(runParams2.get("AttackingPlayer"),
this.mapParams.get("ValidAttackingPlayer").split(","), this.getHostCard())) {
return false;
}
}
return true;
}
/** {@inheritDoc} */
@Override
public final void setTriggeringObjects(final SpellAbility sa) {
sa.setTriggeringObject("AttackingPlayer", this.getRunParams().get("AttackingPlayer"));
sa.setTriggeringObject("Defenders", this.getRunParams().get("Defenders"));
}
@Override
public String getImportantStackObjects(SpellAbility sa) {
StringBuilder sb = new StringBuilder();
sb.append("AttackingPlayer: ").append(sa.getTriggeringObject("AttackingPlayer"));
sb.append("Defenders: ").append(sa.getTriggeringObject("Defenders"));
return sb.toString();
}
}

View File

@@ -24,8 +24,10 @@ import java.util.Set;
import com.google.common.collect.Sets;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GameObject;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardUtil;
import forge.game.cost.Cost;
@@ -158,6 +160,31 @@ public class TriggerSpellAbilityCast extends Trigger {
}
}
if (hasParam("CanTargetOtherCondition")) {
final CardCollection candidates = new CardCollection();
SpellAbility targetedSA = spellAbility;
while (targetedSA != null) {
if (targetedSA.usesTargeting() && targetedSA.getTargets().getNumTargeted() != 0) {
break;
}
targetedSA = targetedSA.getSubAbility();
}
if (targetedSA == null) {
return false;
}
final List<GameEntity> candidateTargets = targetedSA.getTargetRestrictions().getAllCandidates(targetedSA, true);
for (GameEntity card : candidateTargets) {
if (card instanceof Card) {
candidates.add((Card) card);
}
}
candidates.removeAll(targetedSA.getTargets().getTargetCards());
String valid = this.mapParams.get("CanTargetOtherCondition");
if (CardLists.getValidCards(candidates, valid, spellAbility.getActivatingPlayer(), spellAbility.getHostCard()).isEmpty()) {
return false;
}
}
if (hasParam("NonTapCost")) {
final Cost cost = (Cost) (runParams2.get("Cost"));
if (cost.hasTapCost()) {
@@ -241,6 +268,7 @@ public class TriggerSpellAbilityCast extends Trigger {
sa.setTriggeringObject("Player", getRunParams().get("Player"));
sa.setTriggeringObject("Activator", getRunParams().get("Activator"));
sa.setTriggeringObject("CurrentStormCount", getRunParams().get("CurrentStormCount"));
sa.setTriggeringObject("CurrentCastSpells", getRunParams().get("CurrentCastSpells"));
sa.setTriggeringObject("CastSACMC", getRunParams().get("CastSACMC"));
}

View File

@@ -20,6 +20,7 @@ public enum TriggerType {
AttackerBlockedByCreature(TriggerAttackerBlockedByCreature.class),
AttackersDeclared(TriggerAttackersDeclared.class),
AttackerUnblocked(TriggerAttackerUnblocked.class),
AttackerUnblockedOnce(TriggerAttackerUnblockedOnce.class),
Attacks(TriggerAttacks.class),
BecomeMonarch(TriggerBecomeMonarch.class),
BecomeMonstrous(TriggerBecomeMonstrous.class),

View File

@@ -27,14 +27,13 @@ import com.google.common.collect.Lists;
public class WrappedAbility extends Ability {
private final SpellAbility sa;
private final Trigger regtrig;
private final Player decider;
boolean mandatory = false;
public WrappedAbility(final Trigger regtrig0, final SpellAbility sa0, final Player decider0) {
super(regtrig0.getHostCard(), ManaCost.ZERO, sa0.getView());
regtrig = regtrig0;
setTrigger(regtrig0);
sa = sa0;
decider = decider0;
sa.setDescription(this.getStackDescription());
@@ -49,10 +48,6 @@ public class WrappedAbility extends Ability {
return true;
}
public Trigger getTrigger() {
return regtrig;
}
public Player getDecider() {
return decider;
}
@@ -218,6 +213,7 @@ public class WrappedAbility extends Ability {
@Override
public String getStackDescription() {
final Trigger regtrig = getTrigger();
final StringBuilder sb = new StringBuilder(regtrig.replaceAbilityText(regtrig.toString(true), this));
if (usesTargeting()) {
sb.append(" (Targeting ");
@@ -445,6 +441,7 @@ public class WrappedAbility extends Ability {
@Override
public void resolve() {
final Game game = sa.getActivatingPlayer().getGame();
final Trigger regtrig = getTrigger();
Map<String, String> triggerParams = regtrig.getMapParams();
if (!(regtrig instanceof TriggerAlways) && !triggerParams.containsKey("NoResolvingCheck")) {
@@ -476,6 +473,9 @@ public class WrappedAbility extends Ability {
return;
}
// set Trigger
sa.setTrigger(regtrig);
if (!triggerParams.containsKey("NoTimestampCheck")) {
timestampCheck();
}

View File

@@ -42,6 +42,7 @@ import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardPredicates;
import forge.game.cost.Cost;
@@ -362,11 +363,13 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
runParams.put("CastSA", si.getSpellAbility(true));
runParams.put("CastSACMC", si.getSpellAbility(true).getHostCard().getCMC());
runParams.put("CurrentStormCount", thisTurnCast.size());
runParams.put("CurrentCastSpells", new CardCollection(thisTurnCast));
game.getTriggerHandler().runTrigger(TriggerType.SpellAbilityCast, runParams, true);
// Run SpellCast triggers
if (sp.isSpell()) {
if (source.isCommander()) {
if (source.isCommander() && (ZoneType.Command == source.getCastFrom())
&& source.getOwner().equals(activator)) {
activator.incCommanderCast(source);
}
game.getTriggerHandler().runTrigger(TriggerType.SpellCast, runParams, true);

View File

@@ -63,6 +63,8 @@ public class PlayerZone extends Zone {
return true;
}
boolean graveyardCastable = c.hasKeyword(Keyword.FLASHBACK) ||
c.hasKeyword(Keyword.RETRACE) || c.hasKeyword(Keyword.JUMP_START);
for (final SpellAbility sa : c.getSpellAbilities()) {
final ZoneType restrictZone = sa.getRestrictions().getZone();
@@ -76,7 +78,7 @@ public class PlayerZone extends Zone {
}
if (sa.isSpell()
&& (c.hasKeyword(Keyword.FLASHBACK) && PlayerZone.this.is(ZoneType.Graveyard))
&& (graveyardCastable && PlayerZone.this.is(ZoneType.Graveyard))
&& restrictZone.equals(ZoneType.Hand)) {
return true;
}

View File

@@ -4,9 +4,9 @@
<properties>
<maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format>
<packaging.type>jar</packaging.type>
<build.min.memory>-Xms128m</build.min.memory>
<build.max.memory>-Xmx1024m</build.max.memory>
<alpha-version>1.6.15.003</alpha-version>
<build.min.memory>-Xms1024m</build.min.memory>
<build.max.memory>-Xmx1536m</build.max.memory>
<alpha-version>1.6.17.001</alpha-version>
<sign.keystore>keystore</sign.keystore>
<sign.alias>alias</sign.alias>
<sign.storepass>storepass</sign.storepass>
@@ -19,7 +19,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.16-SNAPSHOT</version>
<version>1.6.18-SNAPSHOT</version>
</parent>
<artifactId>forge-gui-android</artifactId>
@@ -36,28 +36,6 @@
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>checkstyle-validation</id>
<phase>validate</phase>
<configuration>
<configLocation>../checkstyle.xml</configLocation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,7 @@ public class DecksComboBox extends FComboBoxWrapper<DeckType> {
private DeckType selectedDeckType = null;
public DecksComboBox() {
setSkinFont(FSkin.getBoldFont(14));
setSkinFont(FSkin.getRelativeBoldFont(14));
setTextAlignment(TextAlignment.CENTER);
addActionListener(getDeckTypeComboListener());
}

View File

@@ -90,7 +90,7 @@ public class GuiDownloader extends DefaultBoundedRangeModel {
radProxyNone.setSelected(true);
btnClose.setBorder(new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_TEXT)));
btnStart.setFont(FSkin.getFont(18));
btnStart.setFont(FSkin.getRelativeFont(18));
btnStart.setEnabled(false);
progressBar.reset();

View File

@@ -85,13 +85,16 @@ public class CardDetailPanel extends SkinnedPanel {
setInfoLabel = new JLabel();
setInfoLabel.setHorizontalAlignment(SwingConstants.CENTER);
final Font font = new Font("Dialog", 0, 14);
final Integer fontSizeR12 = FSkin.getRelativeFontSize(12);
final Integer fontSizeR14 = FSkin.getRelativeFontSize(14);
final Font font = new Font("Dialog", 0, fontSizeR14);
nameCostLabel.setFont(font);
typeLabel.setFont(font);
idLabel.setFont(font);
powerToughnessLabel.setFont(font);
cdArea = new FHtmlViewer();
cdArea.setFont(new Font("Dialog", 0, fontSizeR12));
cdArea.setBorder(new EmptyBorder(2, 6, 2, 6));
cdArea.setOpaque(false);
scrArea = new FScrollPane(cdArea, false);

View File

@@ -27,7 +27,7 @@ public abstract class ItemFilter<T extends InventoryItem> {
public static void layoutCheckbox(SkinnedCheckBox cb) {
cb.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
cb.setFont(FSkin.getFont(12));
cb.setFont(FSkin.getFont());
cb.setOpaque(false);
cb.setFocusable(false);
}

View File

@@ -63,7 +63,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
private static final float PILE_SPACING_Y = 0.1f;
private static final SkinColor GROUP_HEADER_FORE_COLOR = FSkin.getColor(FSkin.Colors.CLR_TEXT);
private static final SkinColor GROUP_HEADER_LINE_COLOR = GROUP_HEADER_FORE_COLOR.alphaColor(120);
private static final SkinFont GROUP_HEADER_FONT = FSkin.getFont(12);
private static final SkinFont GROUP_HEADER_FONT = FSkin.getFont();
private static final int GROUP_HEADER_HEIGHT = 19;
private static final int GROUP_HEADER_GLYPH_WIDTH = 6;
private static final int MIN_COLUMN_COUNT = 1;

View File

@@ -103,7 +103,7 @@ public final class ItemListView<T extends InventoryItem> extends ItemView<T> {
static final SkinColor ALT_ROW_COLOR = BACK_COLOR.getContrastColor(-20);
private static final SkinColor GRID_COLOR = BACK_COLOR.getContrastColor(20);
private static final SkinBorder HEADER_BORDER = new FSkin.CompoundSkinBorder(new FSkin.MatteSkinBorder(0, 0, 1, 1, GRID_COLOR), new EmptyBorder(0, 1, 0, 0));
private static final SkinFont ROW_FONT = FSkin.getFont(12);
private static final SkinFont ROW_FONT = FSkin.getFont();
private static final int ROW_HEIGHT = 19;
private final ItemTable table = new ItemTable();

View File

@@ -103,7 +103,7 @@ public class AddBasicLandsDialog {
panel.add(pnlForest);
panel.add(lblDeckInfo);
lblDeckInfo.setFont(FSkin.getFont(14));
lblDeckInfo.setFont(FSkin.getRelativeFont(14));
lblDeckInfo.addMouseListener(new FMouseAdapter() {
@Override
public void onLeftDoubleClick(MouseEvent e) {

View File

@@ -257,7 +257,11 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
public abstract DeckController<TModel> getDeckController();
protected Deck getHumanDeck() {
return getDeckController().getModel().getHumanDeck();
try {
return getDeckController().getModel().getHumanDeck();
} catch (NullPointerException ex) {
return null;
}
}
/**

View File

@@ -38,7 +38,7 @@ public class LblGroup extends SkinnedLabel implements ILocalRepaint {
public LblGroup(final EMenuGroup e0) {
super(" " + e0.getTitle());
this.setFont(FSkin.getBoldFont(14));
this.setFont(FSkin.getRelativeBoldFont(14));
this.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
this.addMouseListener(new MouseAdapter() {

View File

@@ -25,7 +25,7 @@ public class LblHeader extends SkinnedLabel {
public LblHeader(final String txt0) {
super(txt0);
this.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
this.setFont(FSkin.getFont(18));
this.setFont(FSkin.getRelativeFont(18));
this.setBorder(new EmptyBorder(5, 30, 0, 0));
}

View File

@@ -36,7 +36,7 @@ public class LblMenuItem extends SkinnedLabel implements ILocalRepaint {
public LblMenuItem(final IVSubmenu<? extends ICDoc> doc0) {
super(" " + doc0.getMenuTitle());
this.setFont(FSkin.getFont(14));
this.setFont(FSkin.getRelativeFont(14));
this.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
this.addMouseListener(new MouseAdapter() {

View File

@@ -663,7 +663,7 @@ public class PlayerPanel extends FPanel {
txtPlayerName.setText(name);
txtPlayerName.setFocusable(true);
txtPlayerName.setFont(FSkin.getFont(14));
txtPlayerName.setFont(FSkin.getRelativeFont(14));
txtPlayerName.addActionListener(lobby.nameListener);
txtPlayerName.addFocusListener(nameFocusListener);
}

View File

@@ -107,7 +107,7 @@ public enum VSubmenuGauntletQuick implements IVSubmenu<CSubmenuGauntletQuick> {
sliOpponents.setSnapToTicks(true);
sliOpponents.setOpaque(false);
sliOpponents.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
sliOpponents.setFont(FSkin.getFont(12));
sliOpponents.setFont(FSkin.getFont());
pnlOptions.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));
pnlOptions.add(lblOptions, "h 30px!, w 96%!, gap 2% 0 0 5px");

View File

@@ -64,7 +64,7 @@ public enum VSubmenuOnlineLobby implements IVSubmenu<CSubmenuOnlineLobby>, IOnli
if (lobby == null) {
final FButton btnConnect = new FButton("Connect to Server");
btnConnect.setFont(FSkin.getFont(20));
btnConnect.setFont(FSkin.getRelativeFont(20));
btnConnect.addActionListener(new ActionListener() {
@Override
public final void actionPerformed(final ActionEvent e) {

View File

@@ -27,17 +27,17 @@ public class PnlDraftEvent extends JPanel {
super();
radButton = new FRadioButton(event.getTitle());
radButton.setFont(FSkin.getBoldFont(20));
radButton.setFont(FSkin.getRelativeBoldFont(20));
radButton.setIconTextGap(10);
final FTextArea eventBoosters = new FTextArea();
final FTextArea eventFee = new FTextArea();
eventBoosters.setText(event.getBoosterList());
eventBoosters.setFont(FSkin.getFont(12));
eventBoosters.setFont(FSkin.getFont());
eventFee.setText(QuestUtil.formatCredits(event.getEntryFee()) + " Credit Entry Fee");
eventFee.setFont(FSkin.getFont(12));
eventFee.setFont(FSkin.getFont());
radButton.addChangeListener(new ChangeListener() {
@Override

View File

@@ -56,11 +56,11 @@ class PnlEvent extends JPanel {
// Title and description
this.rad = new FRadioButton(event.getFullTitle());
this.rad.setFont(FSkin.getBoldFont(16));
this.rad.setFont(FSkin.getRelativeBoldFont(16));
final FTextArea tarDesc = new FTextArea();
tarDesc.setText(event.getDescription());
tarDesc.setFont(FSkin.getItalicFont(12));
tarDesc.setFont(FSkin.getItalicFont());
tarDesc.addMouseListener(new MouseAdapter() {
@Override

View File

@@ -509,7 +509,7 @@ public enum VSubmenuQuestPrefs implements IVSubmenu<CSubmenuQuestPrefs> {
this.setOpaque(false);
this.setBorder((Border)null);
this.setFont(FSkin.getFont(13));
this.setFont(FSkin.getRelativeFont(13));
this.setForeground(clrText);
this.setCaretColor(clrText);
this.setBackground(clrHover);

View File

@@ -80,7 +80,7 @@ public class ViewStall extends JPanel {
this.tpnFluff.setOpaque(false);
this.tpnFluff.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
this.tpnFluff.setFont(FSkin.getItalicFont(15));
this.tpnFluff.setFont(FSkin.getRelativeItalicFont(15));
this.tpnFluff.setFocusable(false);
this.tpnFluff.setEditable(false);
this.tpnFluff.setBorder((Border)null);

View File

@@ -193,7 +193,7 @@ public enum VSubmenuSealed implements IVSubmenu<CSubmenuSealed> {
final SkinnedTextPane tpnDirections = new SkinnedTextPane();
tpnDirections.setOpaque(false);
tpnDirections.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
tpnDirections.setFont(FSkin.getFont(15));
tpnDirections.setFont(FSkin.getRelativeFont(15));
tpnDirections.setAlignmentX(SwingConstants.CENTER);
tpnDirections.setFocusable(false);
tpnDirections.setEditable(false);

View File

@@ -205,6 +205,7 @@ public enum CSubmenuPreferences implements ICDoc {
initializeGameLogVerbosityComboBox();
initializeCloseActionComboBox();
initializeDefaultFontSizeComboBox();
initializeAiProfilesComboBox();
initializeColorIdentityCombobox();
initializeAutoYieldModeComboBox();
@@ -329,6 +330,15 @@ public enum CSubmenuPreferences implements ICDoc {
panel.setComboBox(comboBox, Singletons.getControl().getCloseAction());
}
private void initializeDefaultFontSizeComboBox() {
final String [] choices = {"10", "11", "12", "13", "14", "15", "16", "17", "18"};
final FPref userSetting = FPref.UI_DEFAULT_FONT_SIZE;
final FComboBoxPanel<String> panel = this.view.getCbpDefaultFontSizeComboBoxPanel();
final FComboBox<String> comboBox = createComboBox(choices, userSetting);
final String selectedItem = this.prefs.getPref(userSetting);
panel.setComboBox(comboBox, selectedItem);
}
private void initializeAiProfilesComboBox() {
final FPref userSetting = FPref.UI_CURRENT_AI_PROFILE;
final FComboBoxPanel<String> panel = this.view.getAiProfilesComboBoxPanel();

View File

@@ -48,8 +48,8 @@ public enum VSubmenuAchievements implements IVSubmenu<CSubmenuAchievements> {
private static final int TROPHIES_PER_SHELVE = 4;
private static final int PADDING = 5;
private static final int TROPHY_PADDING = 45;
private static final SkinFont NAME_FONT = FSkin.getBoldFont(14);
private static final SkinFont DESC_FONT = FSkin.getFont(12);
private static final SkinFont NAME_FONT = FSkin.getRelativeBoldFont(14);
private static final SkinFont DESC_FONT = FSkin.getFont();
private static final SkinColor TEXT_COLOR = FSkin.getColor(Colors.CLR_TEXT);
private static final SkinColor NOT_EARNED_COLOR = TEXT_COLOR.alphaColor(128);
private static final SkinColor TEXTURE_OVERLAY_COLOR = FSkin.getColor(Colors.CLR_THEME);
@@ -121,7 +121,7 @@ public enum VSubmenuAchievements implements IVSubmenu<CSubmenuAchievements> {
AchievementCollection.buildComboBox(cbCollections);
cbCollections.setSkinFont(FSkin.getBoldFont(14));
cbCollections.setSkinFont(FSkin.getRelativeBoldFont(14));
cbCollections.setTextAlignment(TextAlignment.CENTER);
cbCollections.addActionListener(new ActionListener() {
@Override
@@ -264,8 +264,8 @@ public enum VSubmenuAchievements implements IVSubmenu<CSubmenuAchievements> {
private static final SkinImage imgTop = FSkin.getImage(FSkinProp.IMG_TROPHY_CASE_TOP);
private static final SkinImage imgShelf = FSkin.getImage(FSkinProp.IMG_TROPHY_SHELF);
private static final SkinImage imgTrophyPlate = FSkin.getImage(FSkinProp.IMG_TROPHY_PLATE);
private static final Font font = FSkin.getFixedFont(14).deriveFont(Font.BOLD);
private static final Font subFont = FSkin.getFixedFont(12);
private static final Font font = FSkin.getRelativeFixedFont(14).deriveFont(Font.BOLD);
private static final Font subFont = FSkin.getFixedFont();
private static final Color foreColor = new Color(239, 220, 144);
private AchievementCollection achievements;

View File

@@ -105,6 +105,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
// ComboBox items are added in CSubmenuPreferences since this is just the View.
private final FComboBoxPanel<GameLogEntryType> cbpGameLogEntryType = new FComboBoxPanel<>("Game Log Verbosity:");
private final FComboBoxPanel<CloseAction> cbpCloseAction = new FComboBoxPanel<>("Close Action:");
private final FComboBoxPanel<String> cbpDefaultFontSize = new FComboBoxPanel<>("Default Font Size:");
private final FComboBoxPanel<String> cbpAiProfiles = new FComboBoxPanel<>("AI Personality:");
private final FComboBoxPanel<String> cbpDisplayCurrentCardColors = new FComboBoxPanel<>("Show Detailed Card Color:");
private final FComboBoxPanel<String> cbpAutoYieldMode = new FComboBoxPanel<>("Auto-Yield:");
@@ -258,6 +259,9 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
// Graphic Options
pnlPrefs.add(new SectionLabel("Graphic Options"), sectionConstraints + ", gaptop 2%");
pnlPrefs.add(cbpDefaultFontSize, comboBoxConstraints);
pnlPrefs.add(new NoteLabel("The default font size within the UI. All font elements are scaled relative to this. (Needs restart)"), descriptionConstraints);
pnlPrefs.add(cbImageFetcher, titleConstraints);
pnlPrefs.add(new NoteLabel("Enables live fetching of missing card images from an online resource."), descriptionConstraints);
@@ -391,7 +395,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final class OptionsCheckBox extends FCheckBox {
private OptionsCheckBox(final String txt0) {
super(txt0);
this.setFont(FSkin.getBoldFont(12));
this.setFont(FSkin.getBoldFont());
}
}
@@ -402,7 +406,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
super(txt0);
this.setBorder(new FSkin.MatteSkinBorder(0, 0, 1, 0, FSkin.getColor(FSkin.Colors.CLR_BORDERS)));
setHorizontalAlignment(SwingConstants.CENTER);
this.setFont(FSkin.getBoldFont(16));
this.setFont(FSkin.getRelativeBoldFont(16));
this.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
}
}
@@ -412,7 +416,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final class NoteLabel extends SkinnedLabel {
private NoteLabel(final String txt0) {
super(txt0);
this.setFont(FSkin.getItalicFont(12));
this.setFont(FSkin.getItalicFont());
this.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
}
}
@@ -436,7 +440,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
public KeyboardShortcutField(final Shortcut shortcut0) {
super();
this.setEditable(false);
this.setFont(FSkin.getFont(14));
this.setFont(FSkin.getRelativeFont(14));
final FPref prefKey = shortcut0.getPrefKey();
reload(prefKey);
@@ -632,6 +636,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
return cbpCloseAction;
}
public FComboBoxPanel<String> getCbpDefaultFontSizeComboBoxPanel() {
return cbpDefaultFontSize;
}
public FComboBoxPanel<String> getAutoYieldModeComboBoxPanel() {
return cbpAutoYieldMode;
}

View File

@@ -60,7 +60,7 @@ public enum VSubmenuReleaseNotes implements IVSubmenu<CSubmenuReleaseNotes> {
tar.setEditable(false);
tar.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
tar.setFont(FSkin.getFixedFont(16));
tar.setFont(FSkin.getRelativeFixedFont(16));
tar.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
tar.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));

View File

@@ -59,7 +59,7 @@ public class LimitedWinLose extends ControlWinLose {
TitleLabel lblTemp1 = new TitleLabel(title);
SkinnedLabel lblTemp2 = new SkinnedLabel(message);
lblTemp2.setHorizontalAlignment(SwingConstants.CENTER);
lblTemp2.setFont(FSkin.getFont(17));
lblTemp2.setFont(FSkin.getRelativeFont(17));
lblTemp2.setForeground(FORE_COLOR);
lblTemp2.setIconTextGap(50);
getView().getPnlCustom().add(lblTemp1, LimitedWinLose.CONSTRAINTS_TITLE);
@@ -136,7 +136,7 @@ public class LimitedWinLose extends ControlWinLose {
private class TitleLabel extends SkinnedLabel {
TitleLabel(final String msg) {
super(msg);
setFont(FSkin.getFont(18));
setFont(FSkin.getRelativeFont(18));
setPreferredSize(new Dimension(200, 40));
setHorizontalAlignment(SwingConstants.CENTER);
setForeground(FORE_COLOR);

View File

@@ -110,24 +110,24 @@ public class ViewWinLose implements IWinLoseView<FButton> {
lblTitle.setForeground(Color.white);
lblTitle.setHorizontalAlignment(SwingConstants.CENTER);
lblTitle.setFont(FSkin.getBoldFont(30));
lblTitle.setFont(FSkin.getRelativeBoldFont(30));
lblStats.setForeground(Color.white);
lblStats.setHorizontalAlignment(SwingConstants.CENTER);
lblStats.setFont(FSkin.getFont(26));
lblStats.setFont(FSkin.getRelativeFont(26));
btnContinue.setText("Next Game");
btnContinue.setFont(FSkin.getFont(22));
btnContinue.setFont(FSkin.getRelativeFont(22));
btnRestart.setText("Start New Match");
btnRestart.setFont(FSkin.getFont(22));
btnRestart.setFont(FSkin.getRelativeFont(22));
btnQuit.setText("Quit Match");
btnQuit.setFont(FSkin.getFont(22));
btnQuit.setFont(FSkin.getRelativeFont(22));
btnContinue.setEnabled(!game0.isMatchOver());
// Assemble game log scroller.
final FTextArea txtLog = new FTextArea();
txtLog.setText(StringUtils.join(game.getGameLog().getLogEntries(null), "\r\n").replace("[COMPUTER]", "[AI]"));
txtLog.setFont(FSkin.getFont(14));
txtLog.setFont(FSkin.getRelativeFont(14));
txtLog.setFocusable(true); // allow highlighting and copying of log
final FLabel btnCopyLog = new FLabel.ButtonBuilder().text("Copy to clipboard").build();
@@ -292,7 +292,7 @@ public class ViewWinLose implements IWinLoseView<FButton> {
message = "<html>" + message.replace("\n", "<br>") + "</html>";
}
final SkinnedLabel lblMessage = new SkinnedLabel(message);
lblMessage.setFont(FSkin.getFont(14));
lblMessage.setFont(FSkin.getRelativeFont(14));
lblMessage.setForeground(FORE_COLOR);
lblMessage.setHorizontalAlignment(SwingConstants.CENTER);
lblMessage.setIconTextGap(50);
@@ -309,7 +309,7 @@ public class ViewWinLose implements IWinLoseView<FButton> {
private class TitleLabel extends SkinnedLabel {
TitleLabel(final String msg) {
super(msg);
setFont(FSkin.getFont(16));
setFont(FSkin.getRelativeFont(16));
setPreferredSize(new Dimension(200, 40));
setHorizontalAlignment(SwingConstants.CENTER);
setForeground(FORE_COLOR);

View File

@@ -116,11 +116,11 @@ public class VPrompt implements IVDoc<CPrompt> {
// wrap : 2 columns required for btnOk and btnCancel.
container.setLayout(new MigLayout("wrap 2, gap 0px!, insets 1px 1px 3px 1px"));
if (prefs.getPrefBoolean(FPref.UI_COMPACT_PROMPT)) { //hide header and use smaller font if compact prompt
tarMessage.setFont(FSkin.getFont(12));
tarMessage.setFont(FSkin.getFont());
}
else {
container.add(lblGames, "span 2, w 10:100%, h 22px!");
tarMessage.setFont(FSkin.getFont(14));
tarMessage.setFont(FSkin.getRelativeFont(14));
}
lblGames.setText("Game Setup");

View File

@@ -191,7 +191,7 @@ public class VStack implements IVDoc<CStack> {
setFocusable(false);
setEditable(false);
setLineWrap(true);
setFont(FSkin.getFont(12));
setFont(FSkin.getFont());
setWrapStyleWord(true);
setMinimumSize(new Dimension(CARD_WIDTH + 2 * PADDING, CARD_HEIGHT + 2 * PADDING));

View File

@@ -82,7 +82,7 @@ public class FComboBoxPanel<E> extends JPanel {
if (comboBoxCaption != null && !comboBoxCaption.isEmpty()) {
final SkinnedLabel comboLabel = new SkinnedLabel(comboBoxCaption);
comboLabel.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
comboLabel.setFont(FSkin.getBoldFont(12));
comboLabel.setFont(FSkin.getBoldFont());
add(comboLabel);
}
}
@@ -91,7 +91,7 @@ public class FComboBoxPanel<E> extends JPanel {
if (comboBox != null) {
comboBox.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));
comboBox.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
comboBox.setFont(FSkin.getFont(12));
comboBox.setFont(FSkin.getFont());
comboBox.setEditable(false);
comboBox.setFocusable(true);
comboBox.setOpaque(true);

View File

@@ -859,8 +859,12 @@ public class FSkin {
private static Map<Integer, SkinImage> avatars;
private static Map<Integer, Font> fixedFonts = new HashMap<>();
public static Font getFixedFont() {
return getFixedFont(defaultFontSize);
}
/** @return {@link java.awt.font} */
public static Font getFixedFont(final int size) {
private static Font getFixedFont(final int size) {
Font fixedFont = fixedFonts.get(size);
if (fixedFont == null) {
fixedFont = new Font("Monospaced", Font.PLAIN, size);
@@ -869,6 +873,20 @@ public class FSkin {
return fixedFont;
}
public static Font getRelativeFixedFont(final int relative) {
return getFixedFont(getRelativeFontSize(relative));
}
private static double getMultiplier(final int relative) {
// don't know of a good way to get the preference default value
return relative / 12.0;
}
public static Integer getRelativeFontSize(final int relative) {
double multiplier = getMultiplier(relative);
return (int)(defaultFontSize * multiplier);
}
/**
* @return {@link forge.toolbox.FSkin.SkinFont}
*/
@@ -884,6 +902,10 @@ public class FSkin {
return SkinFont.get(Font.PLAIN, size);
}
public static SkinFont getRelativeFont(final int relative) {
return SkinFont.get(Font.PLAIN, getRelativeFontSize(relative));
}
/**
* @return {@link forge.toolbox.FSkin.SkinFont}
*/
@@ -899,6 +921,10 @@ public class FSkin {
return SkinFont.get(Font.BOLD, size);
}
public static SkinFont getRelativeBoldFont(final int relative) {
return SkinFont.get(Font.BOLD, getRelativeFontSize(relative));
}
/**
* @return {@link forge.toolbox.FSkin.SkinFont}
*/
@@ -914,6 +940,10 @@ public class FSkin {
return SkinFont.get(Font.ITALIC, size);
}
public static SkinFont getRelativeItalicFont(final int relative) {
return SkinFont.get(Font.ITALIC, getRelativeFontSize(relative));
}
public static void setGraphicsFont(final Graphics g, final SkinFont skinFont) {
g.setFont(skinFont.font);
}
@@ -1172,10 +1202,7 @@ public class FSkin {
// Initialize fonts
if (onInit) { //set default font size only once onInit
final Font f = UIManager.getDefaults().getFont("Label.font");
if (f != null) {
defaultFontSize = f.getSize();
}
defaultFontSize = FModel.getPreferences().getPrefInt(FPref.UI_DEFAULT_FONT_SIZE);
}
SkinFont.setBaseFont(GuiUtils.newFont(preferredDir + ForgeConstants.FONT_FILE));

View File

@@ -19,7 +19,7 @@ public class FTextEditor extends SkinnedScrollPane {
public FTextEditor() {
tarEditor = new SkinnedTextArea();
tarEditor.setFont(FSkin.getFixedFont(16));
tarEditor.setFont(FSkin.getRelativeFixedFont(16));
tarEditor.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
tarEditor.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));
tarEditor.setCaretColor(FSkin.getColor(FSkin.Colors.CLR_TEXT));

View File

@@ -382,7 +382,7 @@ public class FNavigationBar extends FTitleBarBase {
setOpaque(false);
this.setIcon(screen0.getTabIcon());
this.setForeground(foreColor.alphaColor(unhoveredAlpha));
this.setFont(FSkin.getFont(fontSize));
this.setFont(FSkin.getRelativeFont(fontSize));
int closeButtonOffset;
if (screen.allowTabClose()) {
@@ -434,7 +434,7 @@ public class FNavigationBar extends FTitleBarBase {
private void setSelected(final boolean selected0) {
if (this.selected == selected0) { return; }
this.selected = selected0;
this.setFont(selected0 ? FSkin.getBoldFont(fontSize) : FSkin.getFont(fontSize));
this.setFont(selected0 ? FSkin.getRelativeBoldFont(fontSize) : FSkin.getRelativeFont(fontSize));
repaintSelf();
}

View File

@@ -9,7 +9,7 @@ import java.awt.*;
@SuppressWarnings("serial")
public class FTitleBar extends FTitleBarBase {
private static final FSkin.SkinFont skinFont = FSkin.getFont(12);
private static final FSkin.SkinFont skinFont = FSkin.getFont();
private final SkinnedLabel lblTitle = new SkinnedLabel();

View File

@@ -265,7 +265,7 @@ public enum FView {
textPane.setOpaque(false);
textPane.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT).getColor());
textPane.setBorder(null);
textPane.setFont(FSkin.getFont(14).getBaseFont());
textPane.setFont(FSkin.getRelativeFont(14).getBaseFont());
final FLabel btnRemindMeLater = new FLabel.Builder().text("Remind Me Later").hoverable().opaque().build();
final FLabel btnDoNotRemindMe = new FLabel.Builder().text("Don't Remind Me Again").hoverable().opaque().build();

View File

@@ -30,6 +30,7 @@ import forge.game.cost.Cost;
import forge.game.cost.CostPart;
import forge.game.cost.CostPartMana;
import forge.game.mana.Mana;
import forge.game.mana.ManaConversionMatrix;
import forge.game.mana.ManaCostBeingPaid;
import forge.game.player.*;
import forge.game.replacement.ReplacementEffect;
@@ -591,7 +592,7 @@ public class PlayerControllerForTests extends PlayerController {
}
@Override
public boolean payManaCost(ManaCost toPay, CostPartMana costPartMana, SpellAbility sa, String prompt /* ai needs hints as well */, boolean isActivatedSa ) {
public boolean payManaCost(ManaCost toPay, CostPartMana costPartMana, SpellAbility sa, String prompt /* ai needs hints as well */, ManaConversionMatrix matrix, boolean isActivatedSa) {
// TODO Auto-generated method stub
ManaCostBeingPaid cost = new ManaCostBeingPaid(toPay);
return ComputerUtilMana.payManaCost(cost, sa, player);

View File

@@ -6,13 +6,13 @@
<packaging.type>jar</packaging.type>
<build.min.memory>-Xms128m</build.min.memory>
<build.max.memory>-Xmx2048m</build.max.memory>
<alpha-version>1.6.15.003</alpha-version>
<alpha-version>1.6.17.001</alpha-version>
</properties>
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.16-SNAPSHOT</version>
<version>1.6.18-SNAPSHOT</version>
</parent>
<artifactId>forge-gui-ios</artifactId>

View File

@@ -1,110 +1,84 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.16-SNAPSHOT</version>
<version>1.6.18-SNAPSHOT</version>
</parent>
<artifactId>forge-gui-mobile-dev</artifactId>
<packaging>jar</packaging>
<name>Forge Mobile Dev</name>
<artifactId>forge-gui-mobile-dev</artifactId>
<packaging>jar</packaging>
<name>Forge Mobile Dev</name>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<attach>false</attach>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>forge.app.Main</mainClass>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
<manifestEntries>
<Implementation-Version>${fullversionstring}</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!-- this is used for inheritance merges -->
<phase>package</phase>
<!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<attach>false</attach>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>forge.app.Main</mainClass>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!-- this is used for inheritance merges -->
<phase>package</phase>
<!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>checkstyle-validation</id>
<phase>validate</phase>
<configuration>
<configLocation>../checkstyle.xml</configLocation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>forge</groupId>
<artifactId>forge-gui-mobile</artifactId>
<version>${project.version}</version>
</dependency>
<dependencies>
<dependency>
<groupId>forge</groupId>
<artifactId>forge-gui-mobile</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-backend-lwjgl</artifactId>
<version>1.5.5</version>
</dependency>
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-platform</artifactId>
<version>1.2.0</version>
<classifier>natives-desktop</classifier>
</dependency>
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-freetype-platform</artifactId>
<version>1.5.5</version>
<classifier>natives-desktop</classifier>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-platform</artifactId>
<version>1.2.0</version>
<classifier>natives-desktop</classifier>
</dependency>
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-freetype-platform</artifactId>
<version>1.5.5</version>
<classifier>natives-desktop</classifier>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
</project>

View File

@@ -1,65 +1,65 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.16-SNAPSHOT</version>
</parent>
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.18-SNAPSHOT</version>
</parent>
<artifactId>forge-gui-mobile</artifactId>
<packaging>jar</packaging>
<name>Forge Mobile</name>
<artifactId>forge-gui-mobile</artifactId>
<packaging>jar</packaging>
<name>Forge Mobile</name>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>forge</groupId>
<artifactId>forge-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>forge</groupId>
<artifactId>forge-game</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>forge</groupId>
<artifactId>forge-ai</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>forge</groupId>
<artifactId>forge-gui</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>24.1-android</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.7</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<dependencies>
<dependency>
<groupId>forge</groupId>
<artifactId>forge-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>forge</groupId>
<artifactId>forge-game</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>forge</groupId>
<artifactId>forge-ai</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>forge</groupId>
<artifactId>forge-gui</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>24.1-android</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.7</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</artifactId>
@@ -70,6 +70,6 @@
<artifactId>gdx-freetype</artifactId>
<version>1.5.5</version>
</dependency>
</dependencies>
</dependencies>
</project>

View File

@@ -34,7 +34,7 @@ import java.util.List;
import java.util.Stack;
public class Forge implements ApplicationListener {
public static final String CURRENT_VERSION = "1.6.15.003";
public static final String CURRENT_VERSION = "1.6.17.001";
private static final ApplicationListener app = new Forge();
private static Clipboard clipboard;

View File

@@ -1,13 +1,7 @@
package forge.toolbox;
import java.io.File;
import java.io.FilenameFilter;
import org.apache.commons.lang3.StringUtils;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
import forge.Forge;
import forge.Graphics;
import forge.assets.FSkinColor;
@@ -15,11 +9,14 @@ import forge.assets.FSkinFont;
import forge.assets.FSkinImage;
import forge.menu.FMenuItem;
import forge.menu.FPopupMenu;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.util.Callback;
import forge.util.FileUtil;
import forge.util.Utils;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.FilenameFilter;
public class FFileChooser extends FDialog {
private static final float BACK_ICON_THICKNESS = Utils.scale(2);
@@ -321,7 +318,7 @@ public class FFileChooser extends FDialog {
//draw back icon
float w = getHeight();
float h = w;
float x = w * 0.35f;
float x = w * 0.35f;
float y = h / 2;
float offsetX = w / 8;
float offsetY = h / 6;
@@ -395,7 +392,7 @@ public class FFileChooser extends FDialog {
if (value.isDirectory()) {
float iconSize = h;
g.drawImage(FSkinImage.FOLDER, x, y + (h - iconSize) / 2, iconSize, iconSize);
x += iconSize + FList.PADDING;
x += iconSize + FList.PADDING;
}
g.drawText(value.getName(), font, foreColor, x, y, w, h, false, HAlignment.LEFT, true);
}

View File

@@ -6,12 +6,12 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -34,9 +34,7 @@ import forge.itemmanager.filters.ItemFilter;
import forge.itemmanager.filters.ListLabelFilter;
import forge.menu.FMenuItem;
import forge.menu.FPopupMenu;
import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FOptionPane;
import forge.util.Callback;
import forge.util.Utils;
@@ -62,7 +60,7 @@ import java.util.List;
* <li>If the dialog was canceled, the selection will be empty.</li>
* <li>
* </ul>
*
*
* @param <T>
* the generic type
* @author Forge
@@ -228,7 +226,7 @@ public class ListChooser<T> extends FContainer {
/**
* Shows the dialog and returns after the dialog was closed.
*
*
* @param index0 index to select when shown
* @return a boolean.
*/

Some files were not shown because too many files have changed in this diff Show More