mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
Merge branch 'coremaster' into guildofravnica
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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?
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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")) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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--;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user