This commit is contained in:
Alessandro Coli
2019-09-15 14:10:20 +02:00
200 changed files with 52969 additions and 811 deletions

View File

@@ -1601,8 +1601,8 @@ public class ComputerUtilCard {
} }
pumped.addNewPT(c.getCurrentPower(), c.getCurrentToughness(), timestamp); pumped.addNewPT(c.getCurrentPower(), c.getCurrentToughness(), timestamp);
pumped.setPTBoost(c.getPTBoostMap()); pumped.setPTBoost(c.getPTBoostTable());
pumped.addPTBoost(power + berserkPower, toughness, timestamp); pumped.addPTBoost(power + berserkPower, toughness, timestamp, null);
pumped.addChangedCardKeywords(kws, null, false, false, timestamp); pumped.addChangedCardKeywords(kws, null, false, false, timestamp);
Set<CounterType> types = c.getCounters().keySet(); Set<CounterType> types = c.getCounters().keySet();
for(CounterType ct : types) { for(CounterType ct : types) {
@@ -1649,8 +1649,8 @@ public class ComputerUtilCard {
list.add(vCard); // account for the static abilities that may be present on the card itself list.add(vCard); // account for the static abilities that may be present on the card itself
for (final Card c : list) { for (final Card c : list) {
// remove old boost that might be copied // remove old boost that might be copied
vCard.removePTBoost(c.getTimestamp());
for (final StaticAbility stAb : c.getStaticAbilities()) { for (final StaticAbility stAb : c.getStaticAbilities()) {
vCard.removePTBoost(c.getTimestamp(), stAb.getId());
final Map<String, String> params = stAb.getMapParams(); final Map<String, String> params = stAb.getMapParams();
if (!params.get("Mode").equals("Continuous")) { if (!params.get("Mode").equals("Continuous")) {
continue; continue;
@@ -1683,7 +1683,7 @@ public class ComputerUtilCard {
def = AbilityUtils.calculateAmount(c, addT, stAb); def = AbilityUtils.calculateAmount(c, addT, stAb);
} }
} }
vCard.addPTBoost(att, def, c.getTimestamp()); vCard.addPTBoost(att, def, c.getTimestamp(), stAb.getId());
} }
} }
} }

View File

@@ -25,6 +25,7 @@ import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.AbilityManaPart; import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.ability.AbilityKey;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
import forge.game.zone.PlayerZone; import forge.game.zone.PlayerZone;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
@@ -719,10 +720,10 @@ public abstract class GameState {
for (final Card c : combat.getAttackers()) { for (final Card c : combat.getAttackers()) {
attackedTarget.add(combat.getDefenderByAttacker(c)); attackedTarget.add(combat.getDefenderByAttacker(c));
} }
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = Maps.newEnumMap(AbilityKey.class);
runParams.put("Attackers", combat.getAttackers()); runParams.put(AbilityKey.Attackers, combat.getAttackers());
runParams.put("AttackingPlayer", combat.getAttackingPlayer()); runParams.put(AbilityKey.AttackingPlayer, combat.getAttackingPlayer());
runParams.put("AttackedTarget", attackedTarget); runParams.put(AbilityKey.AttackedTarget, attackedTarget);
game.getTriggerHandler().runTrigger(TriggerType.AttackersDeclared, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.AttackersDeclared, runParams, false);
} }

View File

@@ -246,7 +246,7 @@ public class GameCopier {
newCard.addType(type); newCard.addType(type);
} }
for (StaticAbility stAb : c.getStaticAbilities()) { for (StaticAbility stAb : c.getStaticAbilities()) {
newCard.addStaticAbility(stAb); newCard.addStaticAbility(stAb.copy(newCard, true));
} }
for (SpellAbility sa : c.getSpellAbilities()) { for (SpellAbility sa : c.getSpellAbilities()) {
SpellAbility saCopy = sa.copy(newCard, true); SpellAbility saCopy = sa.copy(newCard, true);
@@ -277,7 +277,7 @@ public class GameCopier {
// TODO: Copy the full list with timestamps. // TODO: Copy the full list with timestamps.
newCard.addNewPT(setPower, setToughness, newGame.getNextTimestamp()); newCard.addNewPT(setPower, setToughness, newGame.getNextTimestamp());
} }
newCard.setPTBoost(c.getPTBoostMap()); newCard.setPTBoost(c.getPTBoostTable());
newCard.setDamage(c.getDamage()); newCard.setDamage(c.getDamage());
newCard.setChangedCardTypes(c.getChangedCardTypesMap()); newCard.setChangedCardTypes(c.getChangedCardTypesMap());

View File

@@ -27,6 +27,7 @@ import forge.util.ItemPoolSorter;
import forge.util.MyRandom; import forge.util.MyRandom;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
@@ -197,7 +198,7 @@ public class CardPool extends ItemPool<PaperCard> {
public String toCardList(String separator) { public String toCardList(String separator) {
List<Entry<PaperCard, Integer>> main2sort = Lists.newArrayList(this); List<Entry<PaperCard, Integer>> main2sort = Lists.newArrayList(this);
main2sort.sort(ItemPoolSorter.BY_NAME_THEN_SET); Collections.sort(main2sort, ItemPoolSorter.BY_NAME_THEN_SET);
final CardDb commonDb = StaticData.instance().getCommonCards(); final CardDb commonDb = StaticData.instance().getCommonCards();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();

View File

@@ -123,7 +123,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
result.add(c.getKey()); result.add(c.getKey());
} }
if (result.size() > 1) { //sort by type so signature spell comes after oathbreaker if (result.size() > 1) { //sort by type so signature spell comes after oathbreaker
result.sort(new Comparator<PaperCard>() { Collections.sort(result, new Comparator<PaperCard>() {
@Override @Override
public int compare(final PaperCard c1, final PaperCard c2) { public int compare(final PaperCard c1, final PaperCard c2) {
return Boolean.compare(c1.getRules().canBeSignatureSpell(), c2.getRules().canBeSignatureSpell()); return Boolean.compare(c1.getRules().canBeSignatureSpell(), c2.getRules().canBeSignatureSpell());

View File

@@ -79,7 +79,7 @@ public class DeckGroup extends DeckBase {
if (aiDecks.size() < 2) { if (aiDecks.size() < 2) {
return; return;
} }
aiDecks.sort(comparator); Collections.sort(aiDecks, comparator);
} }
@Override @Override

View File

@@ -1,9 +1,11 @@
package forge.util; package forge.util;
import java.io.File; import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.*; import java.util.*;
@@ -33,6 +35,25 @@ public class Localizer {
setLanguage(localeID, languagesDirectory); setLanguage(localeID, languagesDirectory);
} }
public String convert(String value, String fromEncoding, String toEncoding) throws UnsupportedEncodingException {
return new String(value.getBytes(fromEncoding), toEncoding);
}
public String charset(String value, String charsets[]) {
String probe = StandardCharsets.UTF_8.name();
for(String c : charsets) {
Charset charset = Charset.forName(c);
if(charset != null) {
try {
if (value.equals(convert(convert(value, charset.name(), probe), probe, charset.name()))) {
return c;
}
} catch(UnsupportedEncodingException ignored) {}
}
}
return StandardCharsets.UTF_8.name();
}
public String getMessage(final String key, final Object... messageArguments) { public String getMessage(final String key, final Object... messageArguments) {
MessageFormat formatter = null; MessageFormat formatter = null;
@@ -51,10 +72,14 @@ public class Localizer {
formatter.setLocale(locale); formatter.setLocale(locale);
String formattedMessage = "CHAR ENCODING ERROR"; String formattedMessage = "CHAR ENCODING ERROR";
//Support non-English-standard characters //Support non-English-standard characters
formattedMessage = new String(formatter.format(messageArguments).getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); String detectedCharset = charset(new String(formatter.format(messageArguments)), new String[] { "ISO-8859-1", "UTF-8" });
return formattedMessage; try {
formattedMessage = new String(formatter.format(messageArguments).getBytes(detectedCharset), StandardCharsets.UTF_8);
} catch(UnsupportedEncodingException ignored) {}
return formattedMessage;
} }
@@ -112,7 +137,7 @@ public class Localizer {
public static class Language { public static class Language {
public String languageName; public String languageName;
public String langaugeID; public String languageID;
} }
} }

View File

@@ -506,7 +506,7 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
* {@inheritDoc} * {@inheritDoc}
*/ */
public void sort(final Comparator<? super T> comparator) { public void sort(final Comparator<? super T> comparator) {
list.sort(comparator); Collections.sort(list, comparator);
} }
/** /**

View File

@@ -132,7 +132,7 @@ public final class MapToAmountUtil {
for (final Entry<T, Integer> entry : map.entrySet()) { for (final Entry<T, Integer> entry : map.entrySet()) {
entries.add(Pair.of(entry.getKey(), entry.getValue())); entries.add(Pair.of(entry.getKey(), entry.getValue()));
} }
entries.sort(new Comparator<Entry<T, Integer>>() { Collections.sort(entries, new Comparator<Entry<T, Integer>>() {
@Override @Override
public int compare(final Entry<T, Integer> o1, final Entry<T, Integer> o2) { public int compare(final Entry<T, Integer> o1, final Entry<T, Integer> o2) {
return o1.getValue().compareTo(o2.getValue()); return o1.getValue().compareTo(o2.getValue());

View File

@@ -27,6 +27,7 @@ import com.google.common.eventbus.EventBus;
import forge.card.CardRarity; import forge.card.CardRarity;
import forge.card.CardStateName; import forge.card.CardStateName;
import forge.card.CardType.Supertype; import forge.card.CardType.Supertype;
import forge.game.ability.AbilityKey;
import forge.game.card.*; import forge.game.card.*;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.event.Event; import forge.game.event.Event;
@@ -713,8 +714,8 @@ public class Game {
ingamePlayers.remove(p); ingamePlayers.remove(p);
lostPlayers.add(p); lostPlayers.add(p);
final Map<String, Object> runParams = new TreeMap<>(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Player", p); runParams.put(AbilityKey.Player, p);
getTriggerHandler().runTrigger(TriggerType.LosesGame, runParams, false); getTriggerHandler().runTrigger(TriggerType.LosesGame, runParams, false);
} }

View File

@@ -23,6 +23,7 @@ import forge.GameCommand;
import forge.StaticData; import forge.StaticData;
import forge.card.CardStateName; import forge.card.CardStateName;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.ability.effects.AttachEffect; import forge.game.ability.effects.AttachEffect;
@@ -79,7 +80,7 @@ public class GameAction {
return changeZone(zoneFrom, zoneTo, c, position, cause, null); return changeZone(zoneFrom, zoneTo, c, position, cause, null);
} }
public Card changeZone(final Zone zoneFrom, Zone zoneTo, final Card c, Integer position, SpellAbility cause, Map<String, Object> params) { private Card changeZone(final Zone zoneFrom, Zone zoneTo, final Card c, Integer position, SpellAbility cause, Map<AbilityKey, Object> params) {
if (c.isCopiedSpell() || (c.isImmutable() && zoneTo.is(ZoneType.Exile))) { if (c.isCopiedSpell() || (c.isImmutable() && zoneTo.is(ZoneType.Exile))) {
// Remove Effect from command immediately, this is essential when some replacement // Remove Effect from command immediately, this is essential when some replacement
// effects happen during the resolving of a spellability ("the next time ..." effect) // effects happen during the resolving of a spellability ("the next time ..." effect)
@@ -284,19 +285,19 @@ public class GameAction {
copied.getOwner().addInboundToken(copied); copied.getOwner().addInboundToken(copied);
} }
Map<String, Object> repParams = Maps.newHashMap(); Map<AbilityKey, Object> repParams = AbilityKey.newMap();
repParams.put("Event", "Moved"); repParams.put(AbilityKey.Event, "Moved");
repParams.put("Affected", copied); repParams.put(AbilityKey.Affected, copied);
repParams.put("CardLKI", lastKnownInfo); repParams.put(AbilityKey.CardLKI, lastKnownInfo);
repParams.put("Cause", cause); repParams.put(AbilityKey.Cause, cause);
repParams.put("Origin", zoneFrom != null ? zoneFrom.getZoneType() : null); repParams.put(AbilityKey.Origin, zoneFrom != null ? zoneFrom.getZoneType() : null);
repParams.put("Destination", zoneTo.getZoneType()); repParams.put(AbilityKey.Destination, zoneTo.getZoneType());
if (params != null) { if (params != null) {
repParams.putAll(params); repParams.putAll(params);
} }
ReplacementResult repres = game.getReplacementHandler().run(repParams); ReplacementResult repres = game.getReplacementHandler().run(EnumMapUtil.toStringMap(repParams));
if (repres != ReplacementResult.NotReplaced) { if (repres != ReplacementResult.NotReplaced) {
// reset failed manifested Cards back to original // reset failed manifested Cards back to original
if (c.isManifested()) { if (c.isManifested()) {
@@ -399,13 +400,12 @@ public class GameAction {
// play the change zone sound // play the change zone sound
game.fireEvent(new GameEventCardChangeZone(c, zoneFrom, zoneTo)); game.fireEvent(new GameEventCardChangeZone(c, zoneFrom, zoneTo));
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(lastKnownInfo);
runParams.put("Card", lastKnownInfo); runParams.put(AbilityKey.Cause, cause);
runParams.put("Cause", cause); runParams.put(AbilityKey.Origin, zoneFrom != null ? zoneFrom.getZoneType().name() : null);
runParams.put("Origin", zoneFrom != null ? zoneFrom.getZoneType().name() : null); runParams.put(AbilityKey.Destination, zoneTo.getZoneType().name());
runParams.put("Destination", zoneTo.getZoneType().name()); runParams.put(AbilityKey.SpellAbilityStackInstance, game.stack.peek());
runParams.put("SpellAbilityStackInstance", game.stack.peek()); runParams.put(AbilityKey.IndividualCostPaymentInstance, game.costPaymentStack.peek());
runParams.put("IndividualCostPaymentInstance", game.costPaymentStack.peek());
if (params != null) { if (params != null) {
runParams.putAll(params); runParams.putAll(params);
@@ -413,9 +413,8 @@ public class GameAction {
game.getTriggerHandler().runTrigger(TriggerType.ChangesZone, runParams, true); game.getTriggerHandler().runTrigger(TriggerType.ChangesZone, runParams, true);
if (zoneFrom != null && zoneFrom.is(ZoneType.Battlefield) && !zoneFrom.getPlayer().equals(zoneTo.getPlayer())) { if (zoneFrom != null && zoneFrom.is(ZoneType.Battlefield) && !zoneFrom.getPlayer().equals(zoneTo.getPlayer())) {
final Map<String, Object> runParams2 = Maps.newHashMap(); final Map<AbilityKey, Object> runParams2 = AbilityKey.mapFromCard(lastKnownInfo);
runParams2.put("Card", lastKnownInfo); runParams2.put(AbilityKey.OriginalController, zoneFrom.getPlayer());
runParams2.put("OriginalController", zoneFrom.getPlayer());
if(params != null) { if(params != null) {
runParams2.putAll(params); runParams2.putAll(params);
} }
@@ -529,17 +528,17 @@ public class GameAction {
return moveTo(zoneTo, c, cause, null); return moveTo(zoneTo, c, cause, null);
} }
public final Card moveTo(final Zone zoneTo, Card c, SpellAbility cause, Map<String, Object> params) {
// FThreads.assertExecutedByEdt(false); // This code must never be executed from EDT,
// use FThreads.invokeInNewThread to run code in a pooled thread
return moveTo(zoneTo, c, null, cause, params);
}
public final Card moveTo(final Zone zoneTo, Card c, Integer position, SpellAbility cause) { public final Card moveTo(final Zone zoneTo, Card c, Integer position, SpellAbility cause) {
return moveTo(zoneTo, c, position, cause, null); return moveTo(zoneTo, c, position, cause, null);
} }
public final Card moveTo(final Zone zoneTo, Card c, Integer position, SpellAbility cause, Map<String, Object> params) { private Card moveTo(final Zone zoneTo, Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
// FThreads.assertExecutedByEdt(false); // This code must never be executed from EDT,
// use FThreads.invokeInNewThread to run code in a pooled thread
return moveTo(zoneTo, c, null, cause, params);
}
private Card moveTo(final Zone zoneTo, Card c, Integer position, SpellAbility cause, Map<AbilityKey, Object> params) {
// Ideally move to should never be called without a prevZone // Ideally move to should never be called without a prevZone
// Remove card from Current Zone, if it has one // Remove card from Current Zone, if it has one
final Zone zoneFrom = game.getZoneOf(c); final Zone zoneFrom = game.getZoneOf(c);
@@ -599,9 +598,8 @@ public class GameAction {
c.setTurnInZone(tiz); c.setTurnInZone(tiz);
c.setCameUnderControlSinceLastUpkeep(true); c.setCameUnderControlSinceLastUpkeep(true);
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
runParams.put("Card", c); runParams.put(AbilityKey.OriginalController, original);
runParams.put("OriginalController", original);
game.getTriggerHandler().runTrigger(TriggerType.ChangesController, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.ChangesController, runParams, false);
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
@@ -612,17 +610,14 @@ public class GameAction {
} }
public final Card moveToStack(final Card c, SpellAbility cause) { public final Card moveToStack(final Card c, SpellAbility cause) {
return moveToStack(c, cause, null);
}
public final Card moveToStack(final Card c, SpellAbility cause, Map<String, Object> params) {
final Zone stack = game.getStackZone(); final Zone stack = game.getStackZone();
return moveTo(stack, c, cause, params); return moveTo(stack, c, cause);
} }
public final Card moveToGraveyard(final Card c, SpellAbility cause) { public final Card moveToGraveyard(final Card c, SpellAbility cause) {
return moveToGraveyard(c, cause, null); return moveToGraveyard(c, cause, null);
} }
public final Card moveToGraveyard(final Card c, SpellAbility cause, Map<String, Object> params) { public final Card moveToGraveyard(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
final PlayerZone grave = c.getOwner().getZone(ZoneType.Graveyard); final PlayerZone grave = c.getOwner().getZone(ZoneType.Graveyard);
// must put card in OWNER's graveyard not controller's // must put card in OWNER's graveyard not controller's
return moveTo(grave, c, cause, params); return moveTo(grave, c, cause, params);
@@ -632,25 +627,21 @@ public class GameAction {
return moveToHand(c, cause, null); return moveToHand(c, cause, null);
} }
public final Card moveToHand(final Card c, SpellAbility cause, Map<String, Object> params) { public final Card moveToHand(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
final PlayerZone hand = c.getOwner().getZone(ZoneType.Hand); final PlayerZone hand = c.getOwner().getZone(ZoneType.Hand);
return moveTo(hand, c, cause, params); return moveTo(hand, c, cause, params);
} }
public final Card moveToPlay(final Card c, SpellAbility cause) { public final Card moveToPlay(final Card c, SpellAbility cause) {
return moveToPlay(c, cause, null);
}
public final Card moveToPlay(final Card c, SpellAbility cause, Map<String, Object> params) {
final PlayerZone play = c.getController().getZone(ZoneType.Battlefield); final PlayerZone play = c.getController().getZone(ZoneType.Battlefield);
return moveTo(play, c, cause, params); return moveTo(play, c, cause, null);
} }
public final Card moveToPlay(final Card c, final Player p, SpellAbility cause) { public final Card moveToPlay(final Card c, final Player p, SpellAbility cause) {
return moveToPlay(c, p, cause, null); return moveToPlay(c, p, cause, null);
} }
public final Card moveToPlay(final Card c, final Player p, SpellAbility cause, Map<String, Object> params) { public final Card moveToPlay(final Card c, final Player p, SpellAbility cause, Map<AbilityKey, Object> params) {
// move to a specific player's Battlefield // move to a specific player's Battlefield
final PlayerZone play = p.getZone(ZoneType.Battlefield); final PlayerZone play = p.getZone(ZoneType.Battlefield);
return moveTo(play, c, cause, params); return moveTo(play, c, cause, params);
@@ -660,7 +651,7 @@ public class GameAction {
return moveToBottomOfLibrary(c, cause, null); return moveToBottomOfLibrary(c, cause, null);
} }
public final Card moveToBottomOfLibrary(final Card c, SpellAbility cause, Map<String, Object> params) { public final Card moveToBottomOfLibrary(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
return moveToLibrary(c, -1, cause, params); return moveToLibrary(c, -1, cause, params);
} }
@@ -668,7 +659,7 @@ public class GameAction {
return moveToLibrary(c, cause, null); return moveToLibrary(c, cause, null);
} }
public final Card moveToLibrary(final Card c, SpellAbility cause, Map<String, Object> params) { public final Card moveToLibrary(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
return moveToLibrary(c, 0, cause, params); return moveToLibrary(c, 0, cause, params);
} }
@@ -676,7 +667,7 @@ public class GameAction {
return moveToLibrary(c, libPosition, cause, null); return moveToLibrary(c, libPosition, cause, null);
} }
public final Card moveToLibrary(Card c, int libPosition, SpellAbility cause, Map<String, Object> params) { public final Card moveToLibrary(Card c, int libPosition, SpellAbility cause, Map<AbilityKey, Object> params) {
final PlayerZone library = c.getOwner().getZone(ZoneType.Library); final PlayerZone library = c.getOwner().getZone(ZoneType.Library);
if (libPosition == -1 || libPosition > library.size()) { if (libPosition == -1 || libPosition > library.size()) {
libPosition = library.size(); libPosition = library.size();
@@ -685,21 +676,17 @@ public class GameAction {
} }
public final Card moveToVariantDeck(Card c, ZoneType zone, int deckPosition, SpellAbility cause) { public final Card moveToVariantDeck(Card c, ZoneType zone, int deckPosition, SpellAbility cause) {
return moveToVariantDeck(c, zone, deckPosition, cause, null);
}
public final Card moveToVariantDeck(Card c, ZoneType zone, int deckPosition, SpellAbility cause, Map<String, Object> params) {
final PlayerZone deck = c.getOwner().getZone(zone); final PlayerZone deck = c.getOwner().getZone(zone);
if (deckPosition == -1 || deckPosition > deck.size()) { if (deckPosition == -1 || deckPosition > deck.size()) {
deckPosition = deck.size(); deckPosition = deck.size();
} }
return changeZone(game.getZoneOf(c), deck, c, deckPosition, cause, params); return changeZone(game.getZoneOf(c), deck, c, deckPosition, cause);
} }
public final Card exile(final Card c, SpellAbility cause) { public final Card exile(final Card c, SpellAbility cause) {
return exile(c, cause, null); return exile(c, cause, null);
} }
public final Card exile(final Card c, SpellAbility cause, Map<String, Object> params) { public final Card exile(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
if (game.isCardExiled(c)) { if (game.isCardExiled(c)) {
return c; return c;
} }
@@ -709,10 +696,9 @@ public class GameAction {
final Card copied = moveTo(removed, c, cause, params); final Card copied = moveTo(removed, c, cause, params);
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
runParams.put("Card", c); runParams.put(AbilityKey.Cause, cause);
runParams.put("Cause", cause); runParams.put(AbilityKey.Origin, origin.getZoneType().name());
runParams.put("Origin", origin.getZoneType().name());
if (params != null) { if (params != null) {
runParams.putAll(params); runParams.putAll(params);
} }
@@ -723,30 +709,22 @@ public class GameAction {
} }
public final Card moveTo(final ZoneType name, final Card c, SpellAbility cause) { public final Card moveTo(final ZoneType name, final Card c, SpellAbility cause) {
return moveTo(name, c, cause, null); return moveTo(name, c, 0, cause);
}
public final Card moveTo(final ZoneType name, final Card c, SpellAbility cause, Map<String, Object> params) {
return moveTo(name, c, 0, cause, params);
} }
public final Card moveTo(final ZoneType name, final Card c, final int libPosition, SpellAbility cause) { public final Card moveTo(final ZoneType name, final Card c, final int libPosition, SpellAbility cause) {
return moveTo(name, c, libPosition, cause, null);
}
public final Card moveTo(final ZoneType name, final Card c, final int libPosition, SpellAbility cause, Map<String, Object> params) {
// Call specific functions to set PlayerZone, then move onto moveTo // Call specific functions to set PlayerZone, then move onto moveTo
switch(name) { switch(name) {
case Hand: return moveToHand(c, cause, params); case Hand: return moveToHand(c, cause);
case Library: return moveToLibrary(c, libPosition, cause, params); case Library: return moveToLibrary(c, libPosition, cause);
case Battlefield: return moveToPlay(c, cause, params); case Battlefield: return moveToPlay(c, cause);
case Graveyard: return moveToGraveyard(c, cause, params); case Graveyard: return moveToGraveyard(c, cause);
case Exile: return exile(c, cause, params); case Exile: return exile(c, cause);
case Stack: return moveToStack(c, cause, params); case Stack: return moveToStack(c, cause);
case PlanarDeck: return moveToVariantDeck(c, ZoneType.PlanarDeck, libPosition, cause, params); case PlanarDeck: return moveToVariantDeck(c, ZoneType.PlanarDeck, libPosition, cause);
case SchemeDeck: return moveToVariantDeck(c, ZoneType.SchemeDeck, libPosition, cause, params); case SchemeDeck: return moveToVariantDeck(c, ZoneType.SchemeDeck, libPosition, cause);
default: // sideboard will also get there default: // sideboard will also get there
return moveTo(c.getOwner().getZone(name), c, cause, params); return moveTo(c.getOwner().getZone(name), c, cause);
} }
} }
@@ -912,7 +890,7 @@ public class GameAction {
// preList means that this is run by a pre Check with LKI objects // preList means that this is run by a pre Check with LKI objects
// in that case Always trigger should not Run // in that case Always trigger should not Run
if (preList.isEmpty()) { if (preList.isEmpty()) {
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
game.getTriggerHandler().runTrigger(TriggerType.Always, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Always, runParams, false);
game.getTriggerHandler().runTrigger(TriggerType.Immediate, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Immediate, runParams, false);
@@ -1434,9 +1412,8 @@ public class GameAction {
game.fireEvent(new GameEventCardDestroyed()); game.fireEvent(new GameEventCardDestroyed());
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
runParams.put("Card", c); runParams.put(AbilityKey.Causer, activator);
runParams.put("Causer", activator);
game.getTriggerHandler().runTrigger(TriggerType.Destroyed, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Destroyed, runParams, false);
final Card sacrificed = sacrificeDestroy(c, sa, table); final Card sacrificed = sacrificeDestroy(c, sa, table);
@@ -1614,8 +1591,7 @@ public class GameAction {
checkStateEffects(true); // why? checkStateEffects(true); // why?
// Run Trigger beginning of the game // Run Trigger beginning of the game
final Map<String, Object> runParams = Maps.newHashMap(); game.getTriggerHandler().runTrigger(TriggerType.NewGame, AbilityKey.newMap(), true);
game.getTriggerHandler().runTrigger(TriggerType.NewGame, runParams, true);
//</THIS CODE WILL WORK WITH PHASE = NULL> //</THIS CODE WILL WORK WITH PHASE = NULL>
@@ -1778,8 +1754,8 @@ public class GameAction {
game.setMonarch(p); game.setMonarch(p);
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Player", p); runParams.put(AbilityKey.Player, p);
game.getTriggerHandler().runTrigger(TriggerType.BecomeMonarch, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.BecomeMonarch, runParams, false);
} }
@@ -1840,8 +1816,8 @@ public class GameAction {
if (cause != null) { if (cause != null) {
// set up triggers (but not actually do them until later) // set up triggers (but not actually do them until later)
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Player", p); runParams.put(AbilityKey.Player, p);
game.getTriggerHandler().runTrigger(TriggerType.Scry, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Scry, runParams, false);
} }
} }

View File

@@ -17,6 +17,7 @@
*/ */
package forge.game; package forge.game;
import forge.game.ability.AbilityKey;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView; import forge.game.card.CardCollectionView;
@@ -214,11 +215,11 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
int prevent = damage - restDamage; int prevent = damage - restDamage;
preventMap.put(source, this, damage - restDamage); preventMap.put(source, this, damage - restDamage);
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("DamageTarget", this); runParams.put(AbilityKey.DamageTarget, this);
runParams.put("DamageAmount", prevent); runParams.put(AbilityKey.DamageAmount, prevent);
runParams.put("DamageSource", source); runParams.put(AbilityKey.DamageSource, source);
runParams.put("IsCombatDamage", isCombat); runParams.put(AbilityKey.IsCombatDamage, isCombat);
getGame().getTriggerHandler().runTrigger(TriggerType.DamagePrevented, runParams, false); getGame().getTriggerHandler().runTrigger(TriggerType.DamagePrevented, runParams, false);
} }

View File

@@ -7,6 +7,7 @@ import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Table; import com.google.common.collect.Table;
import forge.game.ability.AbilityKey;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CounterType; import forge.game.card.CounterType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
@@ -47,8 +48,8 @@ public class GameEntityCounterTable extends ForwardingTable<GameEntity, CounterT
public void triggerCountersPutAll(final Game game) { public void triggerCountersPutAll(final Game game) {
if (!isEmpty()) { if (!isEmpty()) {
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Objects", this); runParams.put(AbilityKey.Objects, this);
game.getTriggerHandler().runTrigger(TriggerType.CounterAddedAll, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.CounterAddedAll, runParams, false);
} }
} }

View File

@@ -1,9 +1,10 @@
package forge.game; package forge.game;
import forge.game.ability.AbilityKey;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
import java.util.HashMap; import java.util.Map;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@@ -36,9 +37,9 @@ public enum PlanarDice {
trigRes = Chaos; trigRes = Chaos;
} }
HashMap<String,Object> runParams = new HashMap<>(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Player", roller); runParams.put(AbilityKey.Player, roller);
runParams.put("Result", trigRes); runParams.put(AbilityKey.Result, trigRes);
roller.getGame().getTriggerHandler().runTrigger(TriggerType.PlanarDice, runParams,false); roller.getGame().getTriggerHandler().runTrigger(TriggerType.PlanarDice, runParams,false);

View File

@@ -798,7 +798,7 @@ public class StaticEffect {
} }
// remove P/T bonus // remove P/T bonus
affectedCard.removePTBoost(getTimestamp()); affectedCard.removePTBoost(getTimestamp(), ability.getId());
// the view is updated in GameAction#checkStaticAbilities to avoid flickering // the view is updated in GameAction#checkStaticAbilities to avoid flickering

View File

@@ -0,0 +1,93 @@
package forge.game.ability;
import java.util.EnumMap;
import java.util.Map;
/**
* Keys for Ability parameter maps.
*/
public enum AbilityKey {
AbilityMana("AbilityMana"),
Affected("Affected"),
Attach("Attach"),
AllVotes("AllVotes"),
AttachSource("AttachSource"),
AttachTarget("AttachTarget"),
Attacked("Attacked"),
Attacker("Attacker"),
Attackers("Attackers"),
AttackingPlayer("AttackingPlayer"),
AttackedTarget("AttackedTarget"),
Blocker("Blocker"),
Blockers("Blockers"),
Card("Card"),
Cards("Cards"),
CardLKI("CardLKI"),
Cause("Cause"),
Causer("Causer"),
Championed("Championed"),
CounterAmount("CounterAmount"),
CounteredSA("CounteredSA"),
CounterType("CounterType"),
CumulativeUpkeepPaid("CumulativeUpkeepPaid"),
DamageAmount("DamageAmount"),
DamageSource("DamageSource"),
DamageSources("DamageSources"),
DamageTarget("DamageTarget"),
DamageTargets("DamageTargets"),
Defender("Defender"),
Defenders("Defenders"),
DefendingPlayer("DefendingPlayer"),
Destination("Destination"),
Devoured("Devoured"),
EchoPaid("EchoPaid"),
Exploited("Exploited"),
Event("Event"),
Fighter("Fighter"),
Fizzle("Fizzle"),
IsCombatDamage("IsCombatDamage"),
PayingMana("PayingMana"),
Player("Player"),
IndividualCostPaymentInstance("IndividualCostPaymentInstance"),
MonstrosityAmount("MonstrosityAmount"),
NewCounterAmount("NewCounterAmount"),
NumBlockers("NumBlockers"),
Object("Object"),
Objects("Objects"),
OtherAttackers("OtherAttackers"),
Origin("Origin"),
OriginalController("OriginalController"),
Produced("Produced"),
Result("Result"),
Scheme("Scheme"),
Source("Source"),
SpellAbilityStackInstance("SpellAbilityStackInstance"),
StackSa("StackSa"),
StackSi("StackSi"),
Target("Target"),
Transformer("Transformer"),
Won("Won");
private String key;
AbilityKey(String key) {
this.key = key;
}
@Override
public String toString() {
return key;
}
public static <V> EnumMap<AbilityKey, V> newMap() {
return new EnumMap<>(AbilityKey.class);
}
public static Map<AbilityKey, Object> mapFromCard(forge.game.card.Card card) {
final Map<AbilityKey, Object> runParams = newMap();
runParams.put(Card, card);
return runParams;
}
}

View File

@@ -1,7 +1,7 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import com.google.common.collect.Maps;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.player.Player; import forge.game.player.Player;
@@ -40,8 +40,8 @@ public class AbandonEffect extends SpellAbilityEffect {
controller.getZone(ZoneType.SchemeDeck).add(source); controller.getZone(ZoneType.SchemeDeck).add(source);
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Scheme", source); runParams.put(AbilityKey.Scheme, source);
game.getTriggerHandler().runTrigger(TriggerType.Abandoned, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Abandoned, runParams, false);
} }

View File

@@ -1,6 +1,7 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.event.GameEventCombatChanged; import forge.game.event.GameEventCombatChanged;
@@ -11,7 +12,6 @@ import forge.game.trigger.TriggerType;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -40,12 +40,12 @@ public class BecomesBlockedEffect extends SpellAbilityEffect {
game.getCombat().setBlocked(c, true); game.getCombat().setBlocked(c, true);
if (!c.getDamageHistory().getCreatureGotBlockedThisCombat()) { if (!c.getDamageHistory().getCreatureGotBlockedThisCombat()) {
isCombatChanged = true; isCombatChanged = true;
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Attacker", c); runParams.put(AbilityKey.Attacker, c);
runParams.put("Blockers", Lists.<Card>newArrayList()); runParams.put(AbilityKey.Blockers, Lists.<Card>newArrayList());
runParams.put("NumBlockers", 0); runParams.put(AbilityKey.NumBlockers, 0);
runParams.put("Defender", game.getCombat().getDefenderByAttacker(c)); runParams.put(AbilityKey.Defender, game.getCombat().getDefenderByAttacker(c));
runParams.put("DefendingPlayer", game.getCombat().getDefenderPlayerByAttacker(c)); runParams.put(AbilityKey.DefendingPlayer, game.getCombat().getDefenderPlayerByAttacker(c));
game.getTriggerHandler().runTrigger(TriggerType.AttackerBlocked, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.AttackerBlocked, runParams, false);
} }
} }

View File

@@ -1,6 +1,6 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import com.google.common.collect.Maps; import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
@@ -53,25 +53,27 @@ public class BlockEffect extends SpellAbilityEffect {
blocker.addBlockedThisTurn(attacker); blocker.addBlockedThisTurn(attacker);
attacker.addBlockedByThisTurn(blocker); attacker.addBlockedByThisTurn(blocker);
Map<String, Object> runParams = Maps.newHashMap(); {
runParams.put("Attacker", attacker); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Blocker", blocker); runParams.put(AbilityKey.Attacker, attacker);
game.getTriggerHandler().runTrigger(TriggerType.AttackerBlockedByCreature, runParams, false); runParams.put(AbilityKey.Blocker, blocker);
game.getTriggerHandler().runTrigger(TriggerType.AttackerBlockedByCreature, runParams, false);
}
runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Blocker", blocker); runParams.put(AbilityKey.Blocker, blocker);
runParams.put("Attackers", attacker); runParams.put(AbilityKey.Attackers, attacker);
game.getTriggerHandler().runTrigger(TriggerType.Blocks, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Blocks, runParams, false);
} }
attacker.getDamageHistory().setCreatureGotBlockedThisCombat(true); attacker.getDamageHistory().setCreatureGotBlockedThisCombat(true);
if (!wasBlocked) { if (!wasBlocked) {
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Attacker", attacker); runParams.put(AbilityKey.Attacker, attacker);
runParams.put("Blockers", blockers); runParams.put(AbilityKey.Blockers, blockers);
runParams.put("NumBlockers", blockers.size()); runParams.put(AbilityKey.NumBlockers, blockers.size());
runParams.put("Defender", combat.getDefenderByAttacker(attacker)); runParams.put(AbilityKey.Defender, combat.getDefenderByAttacker(attacker));
runParams.put("DefendingPlayer", combat.getDefenderPlayerByAttacker(attacker)); runParams.put(AbilityKey.DefendingPlayer, combat.getDefenderPlayerByAttacker(attacker));
game.getTriggerHandler().runTrigger(TriggerType.AttackerBlocked, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.AttackerBlocked, runParams, false);
combat.orderBlockersForDamageAssignment(attacker, new CardCollection(blockers)); combat.orderBlockersForDamageAssignment(attacker, new CardCollection(blockers));

View File

@@ -1,9 +1,9 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import forge.game.Game; import forge.game.Game;
import forge.game.GameActionUtil; import forge.game.GameActionUtil;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.*; import forge.game.card.*;
@@ -79,9 +79,9 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
if (!libCards.isEmpty()) { if (!libCards.isEmpty()) {
sa.getActivatingPlayer().getController().reveal(libCards, ZoneType.Library, libCards.get(0).getOwner()); sa.getActivatingPlayer().getController().reveal(libCards, ZoneType.Library, libCards.get(0).getOwner());
} }
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Player", sa.getActivatingPlayer()); runParams.put(AbilityKey.Player, sa.getActivatingPlayer());
runParams.put("Target", tgtPlayers); runParams.put(AbilityKey.Target, tgtPlayers);
game.getTriggerHandler().runTrigger(TriggerType.SearchedLibrary, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.SearchedLibrary, runParams, false);
} }
if (origin.contains(ZoneType.Hand) && sa.hasParam("Search")) { if (origin.contains(ZoneType.Hand) && sa.hasParam("Search")) {

View File

@@ -4,12 +4,12 @@ import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.GameCommand; import forge.GameCommand;
import forge.card.CardStateName; import forge.card.CardStateName;
import forge.game.Game; import forge.game.Game;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.GameObject; import forge.game.GameObject;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.*; import forge.game.card.*;
@@ -470,7 +470,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
} }
movedCard = game.getAction().moveToLibrary(tgtC, libraryPosition, sa, null); movedCard = game.getAction().moveToLibrary(tgtC, libraryPosition, sa);
} else { } else {
if (destination.equals(ZoneType.Battlefield)) { if (destination.equals(ZoneType.Battlefield)) {
@@ -534,7 +534,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
movedCard = game.getAction().moveTo( movedCard = game.getAction().moveTo(
tgtC.getController().getZone(destination), tgtC, sa, null); tgtC.getController().getZone(destination), tgtC, sa);
if (sa.hasParam("Unearth")) { if (sa.hasParam("Unearth")) {
movedCard.setUnearthed(true); movedCard.setUnearthed(true);
movedCard.addChangedCardKeywords(Lists.newArrayList("Haste"), null, false, false, movedCard.addChangedCardKeywords(Lists.newArrayList("Haste"), null, false, false,
@@ -591,7 +591,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
tgtC.setExiledWith(host); tgtC.setExiledWith(host);
} }
movedCard = game.getAction().moveTo(destination, tgtC, sa, null); movedCard = game.getAction().moveTo(destination, tgtC, sa);
// If a card is Exiled from the stack, remove its spells from the stack // If a card is Exiled from the stack, remove its spells from the stack
if (sa.hasParam("Fizzle")) { if (sa.hasParam("Fizzle")) {
if (tgtC.isInZone(ZoneType.Exile) || tgtC.isInZone(ZoneType.Hand) if (tgtC.isInZone(ZoneType.Exile) || tgtC.isInZone(ZoneType.Hand)
@@ -830,9 +830,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
} }
} }
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Player", decider); runParams.put(AbilityKey.Player, decider);
runParams.put("Target", Lists.newArrayList(player)); runParams.put(AbilityKey.Target, Lists.newArrayList(player));
decider.getGame().getTriggerHandler().runTrigger(TriggerType.SearchedLibrary, runParams, false); decider.getGame().getTriggerHandler().runTrigger(TriggerType.SearchedLibrary, runParams, false);
} }
@@ -967,7 +967,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
Card movedCard = null; Card movedCard = null;
final Zone originZone = game.getZoneOf(c); final Zone originZone = game.getZoneOf(c);
if (destination.equals(ZoneType.Library)) { if (destination.equals(ZoneType.Library)) {
movedCard = game.getAction().moveToLibrary(c, libraryPos, sa, null); movedCard = game.getAction().moveToLibrary(c, libraryPos, sa);
} }
else if (destination.equals(ZoneType.Battlefield)) { else if (destination.equals(ZoneType.Battlefield)) {
if (sa.hasParam("Tapped")) { if (sa.hasParam("Tapped")) {
@@ -1096,7 +1096,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
c.addFaceupCommand(unanimate); c.addFaceupCommand(unanimate);
} }
} }
movedCard = game.getAction().moveTo(c.getController().getZone(destination), c, sa, null); movedCard = game.getAction().moveTo(c.getController().getZone(destination), c, sa);
if (sa.hasParam("Tapped")) { if (sa.hasParam("Tapped")) {
movedCard.setTapped(true); movedCard.setTapped(true);
} }
@@ -1108,7 +1108,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
movedCard.setTimestamp(ts); movedCard.setTimestamp(ts);
} }
else if (destination.equals(ZoneType.Exile)) { else if (destination.equals(ZoneType.Exile)) {
movedCard = game.getAction().exile(c, sa, null); movedCard = game.getAction().exile(c, sa);
if (!c.isToken()) { if (!c.isToken()) {
Card host = sa.getOriginalHost(); Card host = sa.getOriginalHost();
if (host == null) { if (host == null) {
@@ -1121,7 +1121,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
} }
else { else {
movedCard = game.getAction().moveTo(destination, c, sa, null); movedCard = game.getAction().moveTo(destination, c, sa);
} }
movedCards.add(movedCard); movedCards.add(movedCard);
@@ -1131,9 +1131,8 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
if (champion) { if (champion) {
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(source);
runParams.put("Card", source); runParams.put(AbilityKey.Championed, c);
runParams.put("Championed", c);
game.getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false);
} }
@@ -1199,9 +1198,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
final Zone originZone = tgtHost.getZone(); final Zone originZone = tgtHost.getZone();
game.getStack().remove(si); game.getStack().remove(si);
Map<String,Object> params = Maps.newHashMap(); Map<AbilityKey,Object> params = AbilityKey.newMap();
params.put("StackSa", tgtSA); params.put(AbilityKey.StackSa, tgtSA);
params.put("StackSi", si); params.put(AbilityKey.StackSi, si);
Card movedCard = null; Card movedCard = null;
if (srcSA.hasParam("Destination")) { if (srcSA.hasParam("Destination")) {

View File

@@ -8,6 +8,7 @@ import forge.game.card.Card;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.AbilitySub; import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.util.Aggregates;
import forge.util.Lang; import forge.util.Lang;
import forge.util.collect.FCollection; import forge.util.collect.FCollection;
@@ -57,6 +58,7 @@ public class CharmEffect extends SpellAbilityEffect {
int num = Integer.parseInt(sa.getParamOrDefault("CharmNum", "1")); int num = Integer.parseInt(sa.getParamOrDefault("CharmNum", "1"));
int min = Integer.parseInt(sa.getParamOrDefault("MinCharmNum", String.valueOf(num))); int min = Integer.parseInt(sa.getParamOrDefault("MinCharmNum", String.valueOf(num)));
boolean repeat = sa.hasParam("CanRepeatModes"); boolean repeat = sa.hasParam("CanRepeatModes");
boolean random = sa.hasParam("Random");
boolean oppChooses = "Opponent".equals(sa.getParam("Chooser")); boolean oppChooses = "Opponent".equals(sa.getParam("Chooser"));
List<AbilitySub> list = CharmEffect.makePossibleOptions(sa); List<AbilitySub> list = CharmEffect.makePossibleOptions(sa);
@@ -73,6 +75,9 @@ public class CharmEffect extends SpellAbilityEffect {
sb.append(Lang.getNumeral(min)).append(" or ").append(list.size() == 2 ? "both" : "more"); sb.append(Lang.getNumeral(min)).append(" or ").append(list.size() == 2 ? "both" : "more");
} }
if (random) {
sb.append("at random.");
}
if (repeat) { if (repeat) {
sb.append(". You may choose the same mode more than once."); sb.append(". You may choose the same mode more than once.");
} }
@@ -93,6 +98,7 @@ public class CharmEffect extends SpellAbilityEffect {
int num = Integer.parseInt(sa.getParamOrDefault("CharmNum", "1")); int num = Integer.parseInt(sa.getParamOrDefault("CharmNum", "1"));
int min = Integer.parseInt(sa.getParamOrDefault("MinCharmNum", String.valueOf(num))); int min = Integer.parseInt(sa.getParamOrDefault("MinCharmNum", String.valueOf(num)));
boolean repeat = sa.hasParam("CanRepeatModes"); boolean repeat = sa.hasParam("CanRepeatModes");
boolean random = sa.hasParam("Random");
boolean oppChooses = "Opponent".equals(sa.getParam("Chooser")); boolean oppChooses = "Opponent".equals(sa.getParam("Chooser"));
List<AbilitySub> list = CharmEffect.makePossibleOptions(sa); List<AbilitySub> list = CharmEffect.makePossibleOptions(sa);
@@ -116,6 +122,9 @@ public class CharmEffect extends SpellAbilityEffect {
} }
} }
if (random) {
sb.append("at random.");
}
if (repeat) { if (repeat) {
sb.append(". You may choose the same mode more than once."); sb.append(". You may choose the same mode more than once.");
} }
@@ -165,6 +174,11 @@ public class CharmEffect extends SpellAbilityEffect {
: Integer.parseInt(sa.getParamOrDefault("CharmNum", "1")); : Integer.parseInt(sa.getParamOrDefault("CharmNum", "1"));
final int min = sa.hasParam("MinCharmNum") ? Integer.parseInt(sa.getParam("MinCharmNum")) : num; final int min = sa.hasParam("MinCharmNum") ? Integer.parseInt(sa.getParam("MinCharmNum")) : num;
if (sa.hasParam("Random")) {
chainAbilities(sa, Aggregates.random(makePossibleOptions(sa), num));
return true;
}
Card source = sa.getHostCard(); Card source = sa.getHostCard();
Player activator = sa.getActivatingPlayer(); Player activator = sa.getActivatingPlayer();
Player chooser = sa.getActivatingPlayer(); Player chooser = sa.getActivatingPlayer();

View File

@@ -2,6 +2,7 @@ package forge.game.ability.effects;
import forge.game.GameAction; import forge.game.GameAction;
import forge.game.GameLogEntryType; import forge.game.GameLogEntryType;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
@@ -12,7 +13,7 @@ import forge.game.trigger.TriggerType;
import forge.game.zone.PlayerZone; import forge.game.zone.PlayerZone;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import java.util.HashMap; import java.util.Map;
public class ClashEffect extends SpellAbilityEffect { public class ClashEffect extends SpellAbilityEffect {
@@ -32,8 +33,8 @@ public class ClashEffect extends SpellAbilityEffect {
final boolean victory = clashWithOpponent(sa); final boolean victory = clashWithOpponent(sa);
// Run triggers // Run triggers
final HashMap<String, Object> runParams = new HashMap<>(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Player", sa.getHostCard().getController()); runParams.put(AbilityKey.Player, sa.getHostCard().getController());
if (victory) { if (victory) {
@@ -42,14 +43,14 @@ public class ClashEffect extends SpellAbilityEffect {
AbilityUtils.resolve(sub); AbilityUtils.resolve(sub);
} }
runParams.put("Won", "True"); runParams.put(AbilityKey.Won, "True");
} else { } else {
AbilitySub sub = sa.getAdditionalAbility("OtherwiseSubAbility"); AbilitySub sub = sa.getAdditionalAbility("OtherwiseSubAbility");
if (sub != null) { if (sub != null) {
AbilityUtils.resolve(sub); AbilityUtils.resolve(sub);
} }
runParams.put("Won", "False"); runParams.put(AbilityKey.Won, "False");
} }

View File

@@ -181,7 +181,7 @@ public class CopyPermanentEffect extends SpellAbilityEffect {
// Temporarily register triggers of an object created with CopyPermanent // Temporarily register triggers of an object created with CopyPermanent
//game.getTriggerHandler().registerActiveTrigger(copy, false); //game.getTriggerHandler().registerActiveTrigger(copy, false);
final Card copyInPlay = game.getAction().moveToPlay(t, sa, null); final Card copyInPlay = game.getAction().moveToPlay(t, sa);
if (copyInPlay.getZone() != null) { if (copyInPlay.getZone() != null) {
triggerList.put(ZoneType.None, copyInPlay.getZone().getZoneType(), copyInPlay); triggerList.put(ZoneType.None, copyInPlay.getZone().getZoneType(), copyInPlay);

View File

@@ -2,6 +2,7 @@ package forge.game.ability.effects;
import forge.game.Game; import forge.game.Game;
import forge.game.GameLogEntryType; import forge.game.GameLogEntryType;
import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardFactoryUtil; import forge.game.card.CardFactoryUtil;
@@ -168,9 +169,9 @@ public class CounterEffect extends SpellAbilityEffect {
tgtSA.getHostCard().unanimateBestow(true); tgtSA.getHostCard().unanimateBestow(true);
} }
Map<String, Object> params = Maps.newHashMap(); Map<AbilityKey, Object> params = AbilityKey.newMap();
params.put("StackSa", tgtSA); params.put(AbilityKey.StackSa, tgtSA);
params.put("StackSi", si); params.put(AbilityKey.StackSi, si);
String destination = srcSA.hasParam("Destination") ? srcSA.getParam("Destination") : tgtSA.isAftermath() ? "Exile" : "Graveyard"; String destination = srcSA.hasParam("Destination") ? srcSA.getParam("Destination") : tgtSA.isAftermath() ? "Exile" : "Graveyard";
if (srcSA.hasParam("DestinationChoice")) {//Hinder if (srcSA.hasParam("DestinationChoice")) {//Hinder
@@ -208,11 +209,10 @@ public class CounterEffect extends SpellAbilityEffect {
+ srcSA.getHostCard().getName()); + srcSA.getHostCard().getName());
} }
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(tgtSA.getHostCard());
runParams.put("Player", tgtSA.getActivatingPlayer()); runParams.put(AbilityKey.Player, tgtSA.getActivatingPlayer());
runParams.put("Card", tgtSA.getHostCard()); runParams.put(AbilityKey.Cause, srcSA.getHostCard());
runParams.put("Cause", srcSA.getHostCard()); runParams.put(AbilityKey.CounteredSA, tgtSA);
runParams.put("CounteredSA", tgtSA);
game.getTriggerHandler().runTrigger(TriggerType.Countered, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Countered, runParams, false);

View File

@@ -8,6 +8,7 @@ import forge.game.Game;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.GameEntityCounterTable; import forge.game.GameEntityCounterTable;
import forge.game.GameObject; import forge.game.GameObject;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
@@ -189,11 +190,10 @@ public class CountersPutEffect extends SpellAbilityEffect {
} }
if (obj instanceof Card) { if (obj instanceof Card) {
Card tgtCard = gameCard; counterAmount = sa.usesTargeting() && sa.hasParam("DividedAsYouChoose") ? sa.getTargetRestrictions().getDividedValue(gameCard) : counterAmount;
counterAmount = sa.usesTargeting() && sa.hasParam("DividedAsYouChoose") ? sa.getTargetRestrictions().getDividedValue(tgtCard) : counterAmount; if (!sa.usesTargeting() || gameCard.canBeTargetedBy(sa)) {
if (!sa.usesTargeting() || tgtCard.canBeTargetedBy(sa)) {
if (max != -1) { if (max != -1) {
counterAmount = Math.max(Math.min(max - tgtCard.getCounters(counterType), counterAmount), 0); counterAmount = Math.max(Math.min(max - gameCard.getCounters(counterType), counterAmount), 0);
} }
if (sa.hasParam("UpTo")) { if (sa.hasParam("UpTo")) {
Map<String, Object> params = Maps.newHashMap(); Map<String, Object> params = Maps.newHashMap();
@@ -204,15 +204,15 @@ public class CountersPutEffect extends SpellAbilityEffect {
// Adapt need extra logic // Adapt need extra logic
if (sa.hasParam("Adapt")) { if (sa.hasParam("Adapt")) {
if (!(tgtCard.getCounters(CounterType.P1P1) == 0 if (!(gameCard.getCounters(CounterType.P1P1) == 0
|| tgtCard.hasKeyword("CARDNAME adapts as though it had no +1/+1 counters"))) { || gameCard.hasKeyword("CARDNAME adapts as though it had no +1/+1 counters"))) {
continue; continue;
} }
} }
if (sa.hasParam("Tribute")) { if (sa.hasParam("Tribute")) {
// make a copy to check if it would be on the battlefield // make a copy to check if it would be on the battlefield
Card noTributeLKI = CardUtil.getLKICopy(tgtCard); Card noTributeLKI = CardUtil.getLKICopy(gameCard);
// this check needs to check if this card would be on the battlefield // this check needs to check if this card would be on the battlefield
noTributeLKI.setLastKnownZone(activator.getZone(ZoneType.Battlefield)); noTributeLKI.setLastKnownZone(activator.getZone(ZoneType.Battlefield));
@@ -235,65 +235,58 @@ public class CountersPutEffect extends SpellAbilityEffect {
continue; continue;
} }
String message = "Do you want to put " + counterAmount + " +1/+1 counters on " + tgtCard + " ?"; String message = "Do you want to put " + counterAmount + " +1/+1 counters on " + gameCard + " ?";
Player chooser = pc.chooseSingleEntityForEffect(activator.getOpponents(), sa, "Choose an opponent"); Player chooser = pc.chooseSingleEntityForEffect(activator.getOpponents(), sa, "Choose an opponent");
if (chooser.getController().confirmAction(sa, PlayerActionConfirmMode.Tribute, message)) { if (chooser.getController().confirmAction(sa, PlayerActionConfirmMode.Tribute, message)) {
tgtCard.setTributed(true); gameCard.setTributed(true);
} else { } else {
continue; continue;
} }
} }
if (rememberCards) { if (rememberCards) {
card.addRemembered(tgtCard); card.addRemembered(gameCard);
} }
final Zone zone = tgtCard.getGame().getZoneOf(tgtCard); final Zone zone = gameCard.getGame().getZoneOf(gameCard);
if (zone == null || zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Stack)) { if (zone == null || zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Stack)) {
if (etbcounter) { if (etbcounter) {
tgtCard.addEtbCounter(counterType, counterAmount, placer); gameCard.addEtbCounter(counterType, counterAmount, placer);
} else { } else {
tgtCard.addCounter(counterType, counterAmount, placer, true, table); gameCard.addCounter(counterType, counterAmount, placer, true, table);
} }
if (remember) { if (remember) {
final int value = tgtCard.getTotalCountersToAdd(); final int value = gameCard.getTotalCountersToAdd();
tgtCard.addCountersAddedBy(card, counterType, value); gameCard.addCountersAddedBy(card, counterType, value);
} }
if (sa.hasParam("Evolve")) { if (sa.hasParam("Evolve")) {
final Map<String, Object> runParams = Maps.newHashMap(); game.getTriggerHandler().runTrigger(TriggerType.Evolved, AbilityKey.mapFromCard(gameCard), false);
runParams.put("Card", tgtCard);
game.getTriggerHandler().runTrigger(TriggerType.Evolved, runParams, false);
} }
if (sa.hasParam("Monstrosity")) { if (sa.hasParam("Monstrosity")) {
tgtCard.setMonstrous(true); gameCard.setMonstrous(true);
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(gameCard);
runParams.put("Card", tgtCard); runParams.put(AbilityKey.MonstrosityAmount, counterAmount);
runParams.put("MonstrosityAmount", counterAmount);
game.getTriggerHandler().runTrigger(TriggerType.BecomeMonstrous, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.BecomeMonstrous, runParams, false);
} }
if (sa.hasParam("Renown")) { if (sa.hasParam("Renown")) {
tgtCard.setRenowned(true); gameCard.setRenowned(true);
final Map<String, Object> runParams = Maps.newHashMap(); game.getTriggerHandler().runTrigger(TriggerType.BecomeRenowned, AbilityKey.mapFromCard(gameCard), false);
runParams.put("Card", tgtCard);
game.getTriggerHandler().runTrigger(TriggerType.BecomeRenowned, runParams, false);
} }
if (sa.hasParam("Adapt")) { if (sa.hasParam("Adapt")) {
// need to remove special keyword // need to remove special keyword
tgtCard.removeHiddenExtrinsicKeyword("CARDNAME adapts as though it had no +1/+1 counters"); gameCard.removeHiddenExtrinsicKeyword("CARDNAME adapts as though it had no +1/+1 counters");
final Map<String, Object> runParams = Maps.newHashMap(); game.getTriggerHandler().runTrigger(TriggerType.Adapt, AbilityKey.mapFromCard(gameCard), false);
runParams.put("Card", tgtCard);
game.getTriggerHandler().runTrigger(TriggerType.Adapt, runParams, false);
} }
} else { } else {
// adding counters to something like re-suspend cards // adding counters to something like re-suspend cards
// etbcounter should apply multiplier // etbcounter should apply multiplier
if (etbcounter) { if (etbcounter) {
tgtCard.addEtbCounter(counterType, counterAmount, placer); gameCard.addEtbCounter(counterType, counterAmount, placer);
} else { } else {
tgtCard.addCounter(counterType, counterAmount, placer, false, table); gameCard.addCounter(counterType, counterAmount, placer, false, table);
} }
} }
game.updateLastStateForCard(tgtCard); game.updateLastStateForCard(gameCard);
} }
} else if (obj instanceof Player) { } else if (obj instanceof Player) {
// Add Counters to players! // Add Counters to players!

View File

@@ -1,9 +1,9 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.game.Game; import forge.game.Game;
import forge.game.GameEntityCounterTable; import forge.game.GameEntityCounterTable;
import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
@@ -16,7 +16,6 @@ import forge.game.zone.ZoneType;
import forge.util.Lang; import forge.util.Lang;
import java.util.List; import java.util.List;
import java.util.Map;
public class ExploreEffect extends SpellAbilityEffect { public class ExploreEffect extends SpellAbilityEffect {
@@ -83,9 +82,7 @@ public class ExploreEffect extends SpellAbilityEffect {
} }
// a creature does explore even if it isn't on the battlefield anymore // a creature does explore even if it isn't on the battlefield anymore
final Map<String, Object> runParams = Maps.newHashMap(); game.getTriggerHandler().runTrigger(TriggerType.Explores, AbilityKey.mapFromCard(c), false);
runParams.put("Card", c);
game.getTriggerHandler().runTrigger(TriggerType.Explores, runParams, false);
} }
table.triggerCountersPutAll(game); table.triggerCountersPutAll(game);
} }

View File

@@ -1,10 +1,10 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.game.Game; import forge.game.Game;
import forge.game.GameEntityCounterTable; import forge.game.GameEntityCounterTable;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardDamageMap; import forge.game.card.CardDamageMap;
@@ -59,8 +59,8 @@ public class FightEffect extends DamageBaseEffect {
dealDamage(sa, fighters.get(0), fighters.get(1)); dealDamage(sa, fighters.get(0), fighters.get(1));
for (Card c : fighters) { for (Card c : fighters) {
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Fighter", c); runParams.put(AbilityKey.Fighter, c);
game.getTriggerHandler().runTrigger(TriggerType.Fight, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Fight, runParams, false);
} }
} }

View File

@@ -1,7 +1,7 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import com.google.common.collect.Maps;
import forge.game.GameObject; import forge.game.GameObject;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
@@ -209,9 +209,9 @@ public class FlipCoinEffect extends SpellAbilityEffect {
caller.getGame().getAction().nofityOfValue(sa, caller, wonFlip ? "win" : "lose", null); caller.getGame().getAction().nofityOfValue(sa, caller, wonFlip ? "win" : "lose", null);
// Run triggers // Run triggers
Map<String,Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Player", caller); runParams.put(AbilityKey.Player, caller);
runParams.put("Result", Boolean.valueOf(wonFlip)); runParams.put(AbilityKey.Result, wonFlip);
caller.getGame().getTriggerHandler().runTrigger(TriggerType.FlippedCoin, runParams, false); caller.getGame().getTriggerHandler().runTrigger(TriggerType.FlippedCoin, runParams, false);
} while (sa.hasParam("FlipUntilYouLose") && wonFlip); } while (sa.hasParam("FlipUntilYouLose") && wonFlip);

View File

@@ -4,12 +4,12 @@ import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.StaticData; import forge.StaticData;
import forge.card.CardRulesPredicates; import forge.card.CardRulesPredicates;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardFactory; import forge.game.card.CardFactory;
@@ -23,7 +23,6 @@ import forge.item.PaperCard;
import forge.util.Aggregates; import forge.util.Aggregates;
import java.util.List; import java.util.List;
import java.util.Map;
public class PlayLandVariantEffect extends SpellAbilityEffect { public class PlayLandVariantEffect extends SpellAbilityEffect {
@@ -80,9 +79,7 @@ public class PlayLandVariantEffect extends SpellAbilityEffect {
game.fireEvent(new GameEventLandPlayed(activator, source)); game.fireEvent(new GameEventLandPlayed(activator, source));
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); game.getTriggerHandler().runTrigger(TriggerType.LandPlayed, AbilityKey.mapFromCard(source), false);
runParams.put("Card", source);
game.getTriggerHandler().runTrigger(TriggerType.LandPlayed, runParams, false);
game.getStack().unfreezeStack(); game.getStack().unfreezeStack();
activator.addLandPlayedThisTurn(); activator.addLandPlayedThisTurn();
} }

View File

@@ -52,7 +52,7 @@ public class PumpAllEffect extends SpellAbilityEffect {
boolean redrawPT = false; boolean redrawPT = false;
if (a != 0 || d != 0) { if (a != 0 || d != 0) {
tgtC.addPTBoost(a, d, timestamp); tgtC.addPTBoost(a, d, timestamp, 0);
redrawPT = true; redrawPT = true;
} }
@@ -76,7 +76,7 @@ public class PumpAllEffect extends SpellAbilityEffect {
@Override @Override
public void run() { public void run() {
tgtC.removePTBoost(timestamp); tgtC.removePTBoost(timestamp, 0);
tgtC.removeChangedCardKeywords(timestamp); tgtC.removeChangedCardKeywords(timestamp);
for (String kw : hiddenkws) { for (String kw : hiddenkws) {

View File

@@ -56,7 +56,7 @@ public class PumpEffect extends SpellAbilityEffect {
} }
if (a != 0 || d != 0) { if (a != 0 || d != 0) {
gameCard.addPTBoost(a, d, timestamp); gameCard.addPTBoost(a, d, timestamp, 0);
redrawPT = true; redrawPT = true;
} }
@@ -84,7 +84,7 @@ public class PumpEffect extends SpellAbilityEffect {
@Override @Override
public void run() { public void run() {
gameCard.removePTBoost(timestamp); gameCard.removePTBoost(timestamp, 0);
boolean updateText = false; boolean updateText = false;
updateText = gameCard.removeCanBlockAny(timestamp) || updateText; updateText = gameCard.removeCanBlockAny(timestamp) || updateText;
updateText = gameCard.removeCanBlockAdditional(timestamp) || updateText; updateText = gameCard.removeCanBlockAdditional(timestamp) || updateText;

View File

@@ -1,6 +1,7 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.event.GameEventCardRegenerated; import forge.game.event.GameEventCardRegenerated;
@@ -9,8 +10,6 @@ import forge.game.trigger.TriggerType;
import java.util.Map; import java.util.Map;
import com.google.common.collect.Maps;
public class RegenerationEffect extends SpellAbilityEffect { public class RegenerationEffect extends SpellAbilityEffect {
/* /*
@@ -44,9 +43,8 @@ public class RegenerationEffect extends SpellAbilityEffect {
} }
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
runParams.put("Card", c); runParams.put(AbilityKey.Cause, host);
runParams.put("Cause", host);
game.getTriggerHandler().runTrigger(TriggerType.Regenerated, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Regenerated, runParams, false);
} }

View File

@@ -1,6 +1,7 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
@@ -14,9 +15,7 @@ import forge.game.zone.ZoneType;
import forge.util.Aggregates; import forge.util.Aggregates;
import java.util.List; import java.util.List;
import java.util.Map;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
public class RevealEffect extends SpellAbilityEffect { public class RevealEffect extends SpellAbilityEffect {
@@ -74,14 +73,7 @@ public class RevealEffect extends SpellAbilityEffect {
game.getAction().reveal(revealed, p); game.getAction().reveal(revealed, p);
for (final Card c : revealed) { for (final Card c : revealed) {
Map<String, Object> runParams = Maps.newHashMap(); game.getTriggerHandler().runTrigger(TriggerType.Revealed, AbilityKey.mapFromCard(c), false);
runParams.put("Card", c);
/*
if (sa.hasParam("MiracleCost")) {
runParams.put("Miracle", true);
}
//*/
game.getTriggerHandler().runTrigger(TriggerType.Revealed, runParams, false);
if (sa.hasParam("RememberRevealed")) { if (sa.hasParam("RememberRevealed")) {
host.addRemembered(c); host.addRemembered(c);
} }

View File

@@ -1,10 +1,10 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import com.google.common.collect.Maps;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.game.Game; import forge.game.Game;
import forge.game.GameActionUtil; import forge.game.GameActionUtil;
import forge.game.GameEntityCounterTable; import forge.game.GameEntityCounterTable;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.*; import forge.game.card.*;
@@ -36,9 +36,8 @@ public class SacrificeEffect extends SpellAbilityEffect {
isPaid = activator.getController().payManaOptional(card, new Cost(sa.getParam("Echo"), true), isPaid = activator.getController().payManaOptional(card, new Cost(sa.getParam("Echo"), true),
sa, "Pay Echo", ManaPaymentPurpose.Echo); sa, "Pay Echo", ManaPaymentPurpose.Echo);
} }
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(card);
runParams.put("EchoPaid", Boolean.valueOf(isPaid)); runParams.put(AbilityKey.EchoPaid, isPaid);
runParams.put("Card", card);
game.getTriggerHandler().runTrigger(TriggerType.PayEcho, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.PayEcho, runParams, false);
if (isPaid || !card.getController().equals(activator)) { if (isPaid || !card.getController().equals(activator)) {
return; return;
@@ -65,10 +64,9 @@ public class SacrificeEffect extends SpellAbilityEffect {
sb.append("Cumulative upkeep for ").append(card); sb.append("Cumulative upkeep for ").append(card);
boolean isPaid = activator.getController().payManaOptional(card, payCost, sa, sb.toString(), ManaPaymentPurpose.CumulativeUpkeep); boolean isPaid = activator.getController().payManaOptional(card, payCost, sa, sb.toString(), ManaPaymentPurpose.CumulativeUpkeep);
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(card);
runParams.put("CumulativeUpkeepPaid", Boolean.valueOf(isPaid)); runParams.put(AbilityKey.CumulativeUpkeepPaid, isPaid);
runParams.put("Card", card); runParams.put(AbilityKey.PayingMana, StringUtils.join(sa.getPayingMana(), ""));
runParams.put("PayingMana", StringUtils.join(sa.getPayingMana(), ""));
game.getTriggerHandler().runTrigger(TriggerType.PayCumulativeUpkeep, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.PayCumulativeUpkeep, runParams, false);
if (isPaid || !card.getController().equals(activator)) { if (isPaid || !card.getController().equals(activator)) {
return; return;
@@ -147,15 +145,14 @@ public class SacrificeEffect extends SpellAbilityEffect {
// Run Devour Trigger // Run Devour Trigger
if (devour) { if (devour) {
card.addDevoured(lKICopy); card.addDevoured(lKICopy);
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Devoured", sac); runParams.put(AbilityKey.Devoured, sac);
game.getTriggerHandler().runTrigger(TriggerType.Devoured, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Devoured, runParams, false);
} }
if (exploit) { if (exploit) {
card.addExploited(lKICopy); card.addExploited(lKICopy);
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(card);
runParams.put("Exploited", lKICopy); runParams.put(AbilityKey.Exploited, lKICopy);
runParams.put("Card", card);
game.getTriggerHandler().runTrigger(TriggerType.Exploited, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Exploited, runParams, false);
} }
if (wasDestroyed || wasSacrificed) { if (wasDestroyed || wasSacrificed) {

View File

@@ -1,8 +1,8 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import com.google.common.collect.Maps;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
@@ -46,8 +46,8 @@ public class SetInMotionEffect extends SpellAbilityEffect {
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Scheme", controller.getActiveScheme()); runParams.put(AbilityKey.Scheme, controller.getActiveScheme());
game.getTriggerHandler().runTrigger(TriggerType.SetInMotion, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.SetInMotion, runParams, false);
} else { } else {
controller.setSchemeInMotion(); controller.setSchemeInMotion();

View File

@@ -5,13 +5,13 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import forge.game.ability.AbilityKey;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap; import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
@@ -99,8 +99,8 @@ public class VoteEffect extends SpellAbilityEffect {
} }
} }
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("AllVotes", votes); runParams.put(AbilityKey.AllVotes, votes);
game.getTriggerHandler().runTrigger(TriggerType.Vote, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Vote, runParams, false);
List<String> subAbs = Lists.newArrayList(); List<String> subAbs = Lists.newArrayList();

View File

@@ -30,6 +30,7 @@ import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostParser; import forge.card.mana.ManaCostParser;
import forge.game.*; import forge.game.*;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.ability.effects.CharmEffect; import forge.game.ability.effects.CharmEffect;
@@ -197,7 +198,9 @@ public class Card extends GameEntity implements Comparable<Card> {
// stack of set power/toughness // stack of set power/toughness
private Map<Long, Pair<Integer,Integer>> newPT = Maps.newTreeMap(); private Map<Long, Pair<Integer,Integer>> newPT = Maps.newTreeMap();
private Map<Long, Pair<Integer,Integer>> newPTCharacterDefining = Maps.newTreeMap(); private Map<Long, Pair<Integer,Integer>> newPTCharacterDefining = Maps.newTreeMap();
private Map<Long, Pair<Integer,Integer>> boostPT = Maps.newTreeMap();
// x=Static Avility id or 0, y=timestamp
private Table<Integer, Long, Pair<Integer,Integer>> boostPT = TreeBasedTable.create();
private String basePowerString = null; private String basePowerString = null;
private String baseToughnessString = null; private String baseToughnessString = null;
@@ -567,8 +570,8 @@ public class Card extends GameEntity implements Comparable<Card> {
// Clear old dfc trigger from the trigger handler // Clear old dfc trigger from the trigger handler
getGame().getTriggerHandler().clearInstrinsicActiveTriggers(this, null); getGame().getTriggerHandler().clearInstrinsicActiveTriggers(this, null);
getGame().getTriggerHandler().registerActiveTrigger(this, false); getGame().getTriggerHandler().registerActiveTrigger(this, false);
Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Transformer", this); runParams.put(AbilityKey.Transformer, this);
getGame().getTriggerHandler().runTrigger(TriggerType.Transformed, runParams, false); getGame().getTriggerHandler().runTrigger(TriggerType.Transformed, runParams, false);
incrementTransformedTimestamp(); incrementTransformedTimestamp();
@@ -687,9 +690,7 @@ public class Card extends GameEntity implements Comparable<Card> {
// Run triggers // Run triggers
getGame().getTriggerHandler().registerActiveTrigger(this, false); getGame().getTriggerHandler().registerActiveTrigger(this, false);
final Map<String, Object> runParams = Maps.newTreeMap(); getGame().getTriggerHandler().runTrigger(TriggerType.TurnFaceUp, AbilityKey.mapFromCard(this), false);
runParams.put("Card", this);
getGame().getTriggerHandler().runTrigger(TriggerType.TurnFaceUp, runParams, false);
} }
return result; return result;
} }
@@ -1281,17 +1282,16 @@ public class Card extends GameEntity implements Comparable<Card> {
} }
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this);
runParams.put("Card", this); runParams.put(AbilityKey.Source, source);
runParams.put("Source", source); runParams.put(AbilityKey.CounterType, counterType);
runParams.put("CounterType", counterType);
for (int i = 0; i < addAmount; i++) { for (int i = 0; i < addAmount; i++) {
runParams.put("CounterAmount", oldValue + i + 1); runParams.put(AbilityKey.CounterAmount, oldValue + i + 1);
getGame().getTriggerHandler().runTrigger( getGame().getTriggerHandler().runTrigger(
TriggerType.CounterAdded, Maps.newHashMap(runParams), false); TriggerType.CounterAdded, Maps.newHashMap(runParams), false);
} }
if (addAmount > 0) { if (addAmount > 0) {
runParams.put("CounterAmount", addAmount); runParams.put(AbilityKey.CounterAmount, addAmount);
getGame().getTriggerHandler().runTrigger( getGame().getTriggerHandler().runTrigger(
TriggerType.CounterAddedOnce, Maps.newHashMap(runParams), false); TriggerType.CounterAddedOnce, Maps.newHashMap(runParams), false);
} }
@@ -1340,10 +1340,10 @@ public class Card extends GameEntity implements Comparable<Card> {
@Override @Override
public final void subtractCounter(final CounterType counterName, final int n) { public final void subtractCounter(final CounterType counterName, final int n) {
Integer oldValue = getCounters(counterName); int oldValue = getCounters(counterName);
int newValue = oldValue == null ? 0 : Math.max(oldValue - n, 0); int newValue = Math.max(oldValue - n, 0);
final int delta = (oldValue == null ? 0 : oldValue) - newValue; final int delta = oldValue - newValue;
if (delta == 0) { return; } if (delta == 0) { return; }
int powerBonusBefore = getPowerBonusFromCounters(); int powerBonusBefore = getPowerBonusFromCounters();
@@ -1359,18 +1359,17 @@ public class Card extends GameEntity implements Comparable<Card> {
} }
// Play the Subtract Counter sound // Play the Subtract Counter sound
getGame().fireEvent(new GameEventCardCounters(this, counterName, oldValue == null ? 0 : oldValue, newValue)); getGame().fireEvent(new GameEventCardCounters(this, counterName, oldValue, newValue));
// Run triggers // Run triggers
int curCounters = oldValue == null ? 0 : oldValue; int curCounters = oldValue;
final Map<String, Object> runParams = Maps.newTreeMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this);
runParams.put("Card", this); runParams.put(AbilityKey.CounterType, counterName);
runParams.put("CounterType", counterName);
for (int i = 0; i < delta && curCounters != 0; i++) { for (int i = 0; i < delta && curCounters != 0; i++) {
runParams.put("NewCounterAmount", --curCounters); runParams.put(AbilityKey.NewCounterAmount, --curCounters);
getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemoved, runParams, false); getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemoved, runParams, false);
} }
runParams.put("CounterAmount", delta); runParams.put(AbilityKey.CounterAmount, delta);
getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemovedOnce, runParams, false); getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemovedOnce, runParams, false);
} }
@@ -2935,9 +2934,9 @@ public class Card extends GameEntity implements Comparable<Card> {
getGame().fireEvent(new GameEventCardAttachment(this, oldTarget, entity)); getGame().fireEvent(new GameEventCardAttachment(this, oldTarget, entity));
// run trigger // run trigger
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("AttachSource", this); runParams.put(AbilityKey.AttachSource, this);
runParams.put("AttachTarget", entity); runParams.put(AbilityKey.AttachTarget, entity);
getController().getGame().getTriggerHandler().runTrigger(TriggerType.Attached, runParams, false); getController().getGame().getTriggerHandler().runTrigger(TriggerType.Attached, runParams, false);
} }
@@ -2957,9 +2956,9 @@ public class Card extends GameEntity implements Comparable<Card> {
getGame().fireEvent(new GameEventCardAttachment(this, entity, null)); getGame().fireEvent(new GameEventCardAttachment(this, entity, null));
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newTreeMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Attach", this); runParams.put(AbilityKey.Attach, this);
runParams.put("Object", entity); runParams.put(AbilityKey.Object, entity);
getGame().getTriggerHandler().runTrigger(TriggerType.Unattach, runParams, false); getGame().getTriggerHandler().runTrigger(TriggerType.Unattach, runParams, false);
runUnattachCommands(); runUnattachCommands();
} }
@@ -3477,23 +3476,21 @@ public class Card extends GameEntity implements Comparable<Card> {
return result; return result;
} }
public void addPTBoost(final Integer power, final Integer toughness, final long timestamp) { public void addPTBoost(final Integer power, final Integer toughness, final long timestamp, final Integer staticId) {
boostPT.put(timestamp, Pair.of(power, toughness)); boostPT.put(staticId == null ? 0 : staticId, timestamp, Pair.of(power, toughness));
} }
public void removePTBoost(final long timestamp) { public void removePTBoost(final long timestamp, final Integer staticId) {
boostPT.remove(timestamp); boostPT.remove(staticId, timestamp);
} }
public Map<Long, Pair<Integer, Integer>> getPTBoostMap() { public Table<Integer, Long, Pair<Integer, Integer>> getPTBoostTable() {
return ImmutableMap.copyOf(boostPT); return ImmutableTable.copyOf(boostPT);
} }
public void setPTBoost(Map<Long, Pair<Integer, Integer>> map) { public void setPTBoost(Table<Integer, Long, Pair<Integer, Integer>> table) {
this.boostPT.clear(); this.boostPT.clear();
for (Map.Entry<Long, Pair<Integer,Integer>> e : map.entrySet()) { boostPT.putAll(table);
this.boostPT.put(e.getKey(), Pair.of(e.getValue().getLeft(), e.getValue().getRight()));
}
} }
public final boolean isUntapped() { public final boolean isUntapped() {
@@ -3516,9 +3513,8 @@ public class Card extends GameEntity implements Comparable<Card> {
if (tapped) { return; } if (tapped) { return; }
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newTreeMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this);
runParams.put("Card", this); runParams.put(AbilityKey.Attacker, attacker);
runParams.put("Attacker", attacker);
getGame().getTriggerHandler().runTrigger(TriggerType.Taps, runParams, false); getGame().getTriggerHandler().runTrigger(TriggerType.Taps, runParams, false);
setTapped(true); setTapped(true);
@@ -3538,9 +3534,7 @@ public class Card extends GameEntity implements Comparable<Card> {
} }
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newTreeMap(); getGame().getTriggerHandler().runTrigger(TriggerType.Untaps, AbilityKey.mapFromCard(this), false);
runParams.put("Card", this);
getGame().getTriggerHandler().runTrigger(TriggerType.Untaps, runParams, false);
for (final GameCommand var : untapCommandList) { for (final GameCommand var : untapCommandList) {
var.run(); var.run();
@@ -3971,12 +3965,8 @@ public class Card extends GameEntity implements Comparable<Card> {
return null; return null;
} }
public final StaticAbility addStaticAbility(final StaticAbility stAb) { public final StaticAbility addStaticAbility(final StaticAbility stAb) {
return addStaticAbility(stAb, false); currentState.addStaticAbility(stAb);
} return stAb;
public final StaticAbility addStaticAbility(final StaticAbility stAb, boolean intrinsic) {
final StaticAbility stAbCopy = new StaticAbility(stAb, this);
currentState.addStaticAbility(stAbCopy);
return stAbCopy;
} }
public final void removeStaticAbility(StaticAbility stAb) { public final void removeStaticAbility(StaticAbility stAb) {
currentState.removeStaticAbility(stAb); currentState.removeStaticAbility(stAb);
@@ -4099,8 +4089,7 @@ public class Card extends GameEntity implements Comparable<Card> {
return false; return false;
} }
final Map<String, Object> runParams = Maps.newTreeMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this);
runParams.put("Card", this);
if (!isPhasedOut()) { if (!isPhasedOut()) {
// If this is currently PhasedIn, it's about to phase out. // If this is currently PhasedIn, it's about to phase out.
@@ -4900,16 +4889,16 @@ public class Card extends GameEntity implements Comparable<Card> {
source.addDealtDamageToThisTurn(this, damageIn); source.addDealtDamageToThisTurn(this, damageIn);
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newTreeMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("DamageSource", source); runParams.put(AbilityKey.DamageSource, source);
runParams.put("DamageTarget", this); runParams.put(AbilityKey.DamageTarget, this);
runParams.put("DamageAmount", damageIn); runParams.put(AbilityKey.DamageAmount, damageIn);
runParams.put("IsCombatDamage", isCombat); runParams.put(AbilityKey.IsCombatDamage, isCombat);
if (!isCombat) { if (!isCombat) {
runParams.put("SpellAbilityStackInstance", game.stack.peek()); runParams.put(AbilityKey.SpellAbilityStackInstance, game.stack.peek());
} }
// Defending player at the time the damage was dealt // Defending player at the time the damage was dealt
runParams.put("DefendingPlayer", game.getCombat() != null ? game.getCombat().getDefendingPlayerRelatedTo(source) : null); runParams.put(AbilityKey.DefendingPlayer, game.getCombat() != null ? game.getCombat().getDefendingPlayerRelatedTo(source) : null);
getGame().getTriggerHandler().runTrigger(TriggerType.DamageDone, runParams, false); getGame().getTriggerHandler().runTrigger(TriggerType.DamageDone, runParams, false);
GameEventCardDamaged.DamageType damageType = DamageType.Normal; GameEventCardDamaged.DamageType damageType = DamageType.Normal;
@@ -5008,9 +4997,8 @@ public class Card extends GameEntity implements Comparable<Card> {
exertedByPlayer.add(getController()); exertedByPlayer.add(getController());
exertThisTurn++; exertThisTurn++;
view.updateExertedThisTurn(this, true); view.updateExertedThisTurn(this, true);
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this);
runParams.put("Card", this); runParams.put(AbilityKey.Player, getController());
runParams.put("Player", getController());
game.getTriggerHandler().runTrigger(TriggerType.Exerted, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Exerted, runParams, false);
} }

View File

@@ -7,11 +7,11 @@ import java.util.Map;
import com.google.common.collect.ForwardingTable; import com.google.common.collect.ForwardingTable;
import com.google.common.collect.HashBasedTable; import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.collect.Table; import com.google.common.collect.Table;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.ability.AbilityKey;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
@@ -34,10 +34,10 @@ public class CardDamageMap extends ForwardingTable<Card, GameEntity, Integer> {
} }
if (sum > 0) { if (sum > 0) {
final GameEntity ge = e.getKey(); final GameEntity ge = e.getKey();
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("DamageTarget", ge); runParams.put(AbilityKey.DamageTarget, ge);
runParams.put("DamageAmount", sum); runParams.put(AbilityKey.DamageAmount, sum);
runParams.put("IsCombatDamage", isCombat); runParams.put(AbilityKey.IsCombatDamage, isCombat);
ge.getGame().getTriggerHandler().runTrigger(TriggerType.DamagePreventedOnce, runParams, false); ge.getGame().getTriggerHandler().runTrigger(TriggerType.DamagePreventedOnce, runParams, false);
} }
@@ -53,11 +53,11 @@ public class CardDamageMap extends ForwardingTable<Card, GameEntity, Integer> {
sum += i; sum += i;
} }
if (sum > 0) { if (sum > 0) {
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("DamageSource", sourceLKI); runParams.put(AbilityKey.DamageSource, sourceLKI);
runParams.put("DamageTargets", Sets.newHashSet(e.getValue().keySet())); runParams.put(AbilityKey.DamageTargets, Sets.newHashSet(e.getValue().keySet()));
runParams.put("DamageAmount", sum); runParams.put(AbilityKey.DamageAmount, sum);
runParams.put("IsCombatDamage", isCombat); runParams.put(AbilityKey.IsCombatDamage, isCombat);
sourceLKI.getGame().getTriggerHandler().runTrigger(TriggerType.DamageDealtOnce, runParams, false); sourceLKI.getGame().getTriggerHandler().runTrigger(TriggerType.DamageDealtOnce, runParams, false);
@@ -74,11 +74,11 @@ public class CardDamageMap extends ForwardingTable<Card, GameEntity, Integer> {
} }
if (sum > 0) { if (sum > 0) {
final GameEntity ge = e.getKey(); final GameEntity ge = e.getKey();
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("DamageTarget", ge); runParams.put(AbilityKey.DamageTarget, ge);
runParams.put("DamageSources", Sets.newHashSet(e.getValue().keySet())); runParams.put(AbilityKey.DamageSources, Sets.newHashSet(e.getValue().keySet()));
runParams.put("DamageAmount", sum); runParams.put(AbilityKey.DamageAmount, sum);
runParams.put("IsCombatDamage", isCombat); runParams.put(AbilityKey.IsCombatDamage, isCombat);
ge.getGame().getTriggerHandler().runTrigger(TriggerType.DamageDoneOnce, runParams, false); ge.getGame().getTriggerHandler().runTrigger(TriggerType.DamageDoneOnce, runParams, false);
} }

View File

@@ -529,7 +529,7 @@ public class CardState extends GameObject {
staticAbilities.clear(); staticAbilities.clear();
for (StaticAbility sa : source.staticAbilities) { for (StaticAbility sa : source.staticAbilities) {
if (sa.isIntrinsic()) { if (sa.isIntrinsic()) {
staticAbilities.add(new StaticAbility(sa, this.card)); staticAbilities.add(sa.copy(card, lki));
} }
} }
} }

View File

@@ -536,27 +536,50 @@ public class CardView extends GameEntityView {
} }
public String getText() { public String getText() {
return getText(getCurrentState()); return getText(getCurrentState(), null);
} }
public String getText(CardStateView state) { public String getText(CardStateView state, HashMap<String, String> translationsText) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
//final boolean isSplitCard = (state.getState() == CardStateName.LeftSplit); //final boolean isSplitCard = (state.getState() == CardStateName.LeftSplit);
String tname = "", toracle = "", taltname = "", taltoracle = "";
// If we have translations, use them
if (translationsText != null) {
tname = translationsText.get("name");
taltname = translationsText.get("altname");
// Don't translate oracles if the card is a cloned one
if (((String) get(TrackableProperty.Cloner)).isEmpty()) {
toracle = translationsText.get("oracle");
taltoracle = translationsText.get("altoracle");
}
}
tname = tname.isEmpty() ? state.getName() : tname;
toracle = toracle.isEmpty() ? state.getOracleText() : toracle;
if (isSplitCard()) {
taltname = getAlternateState().getName();
taltoracle = getAlternateState().getOracleText();
}
if (getId() < 0) { if (getId() < 0) {
if (isSplitCard()) { if (isSplitCard()) {
sb.append("(").append(state.getName()).append(") "); sb.append("(").append(tname).append(") ");
sb.append(state.getOracleText()); sb.append(toracle);
sb.append("\r\n\r\n"); sb.append("\r\n\r\n");
sb.append("(").append(getAlternateState().getName()).append(") "); sb.append("(").append(taltname).append(") ");
sb.append(getAlternateState().getOracleText()); sb.append(taltoracle);
return sb.toString().trim(); return sb.toString().trim();
} else { } else {
return state.getOracleText(); return toracle;
} }
} }
final String rulesText = state.getRulesText(); final String rulesText = state.getRulesText();
if (!rulesText.isEmpty()) { if (!toracle.isEmpty()) {
sb.append(toracle).append("\r\n\r\n");
} else if (!rulesText.isEmpty()) {
sb.append(rulesText).append("\r\n\r\n"); sb.append(rulesText).append("\r\n\r\n");
} }
if (isCommander()) { if (isCommander()) {
@@ -565,6 +588,7 @@ public class CardView extends GameEntityView {
} }
if (isSplitCard() && !isFaceDown()) { if (isSplitCard() && !isFaceDown()) {
// TODO: Translation?
CardStateView view = state.getState() == CardStateName.LeftSplit ? state : getAlternateState(); CardStateView view = state.getState() == CardStateName.LeftSplit ? state : getAlternateState();
if (getZone() != ZoneType.Stack) { if (getZone() != ZoneType.Stack) {
sb.append("("); sb.append("(");
@@ -573,12 +597,12 @@ public class CardView extends GameEntityView {
} }
sb.append(view.getAbilityText()); sb.append(view.getAbilityText());
} else { } else {
sb.append(state.getAbilityText()); if (toracle.isEmpty()) sb.append(state.getAbilityText());
} }
if (isSplitCard() && !isFaceDown() && getZone() != ZoneType.Stack) { if (isSplitCard() && !isFaceDown() && getZone() != ZoneType.Stack) {
//ensure ability text for right half of split card is included unless spell is on stack //ensure ability text for right half of split card is included unless spell is on stack
sb.append("\r\n\r\n").append("(").append(getAlternateState().getName()).append(") ").append(getAlternateState().getOracleText()); sb.append("\r\n\r\n").append("(").append(taltname).append(") ").append(taltoracle);
} }
String nonAbilityText = get(TrackableProperty.NonAbilityText); String nonAbilityText = get(TrackableProperty.NonAbilityText);

View File

@@ -7,10 +7,10 @@ import java.util.Map;
import com.google.common.collect.ForwardingTable; import com.google.common.collect.ForwardingTable;
import com.google.common.collect.HashBasedTable; import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Maps;
import com.google.common.collect.Table; import com.google.common.collect.Table;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
@@ -54,8 +54,8 @@ public class CardZoneTable extends ForwardingTable<ZoneType, ZoneType, CardColle
public void triggerChangesZoneAll(final Game game) { public void triggerChangesZoneAll(final Game game) {
if (!isEmpty()) { if (!isEmpty()) {
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Cards", new CardZoneTable(this)); runParams.put(AbilityKey.Cards, new CardZoneTable(this));
game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false);
} }
} }

View File

@@ -147,6 +147,8 @@ public enum CounterType {
KI("KI", 190, 189, 255), KI("KI", 190, 189, 255),
KNOWLEDGE("KNOWLEDGE", 0, 115, 255),
LANDMARK("LNMRK", 186, 28, 28), LANDMARK("LNMRK", 186, 28, 28),
LEVEL("LEVEL", 60, 222, 185), LEVEL("LEVEL", 60, 222, 185),

View File

@@ -24,6 +24,7 @@ import forge.game.GameEntity;
import forge.game.GameEntityCounterTable; import forge.game.GameEntityCounterTable;
import forge.game.GameLogEntryType; import forge.game.GameLogEntryType;
import forge.game.GameObjectMap; import forge.game.GameObjectMap;
import forge.game.ability.AbilityKey;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView; import forge.game.card.CardCollectionView;
@@ -632,10 +633,10 @@ public class Combat {
defenders.add(getDefenderByAttacker(ab)); defenders.add(getDefenderByAttacker(ab));
for (Card attacker : ab.getAttackers()) { for (Card attacker : ab.getAttackers()) {
// Run Unblocked Trigger // Run Unblocked Trigger
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Attacker", attacker); runParams.put(AbilityKey.Attacker, attacker);
runParams.put("Defender",getDefenderByAttacker(attacker)); runParams.put(AbilityKey.Defender,getDefenderByAttacker(attacker));
runParams.put("DefendingPlayer", getDefenderPlayerByAttacker(attacker)); runParams.put(AbilityKey.DefendingPlayer, getDefenderPlayerByAttacker(attacker));
game.getTriggerHandler().runTrigger(TriggerType.AttackerUnblocked, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.AttackerUnblocked, runParams, false);
} }
} }
@@ -644,9 +645,9 @@ public class Combat {
// triggers for Coveted Jewel // triggers for Coveted Jewel
// currently there is only one attacking player // currently there is only one attacking player
// should be updated when two-headed-giant is done // should be updated when two-headed-giant is done
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("AttackingPlayer", getAttackingPlayer()); runParams.put(AbilityKey.AttackingPlayer, getAttackingPlayer());
runParams.put("Defenders", defenders); runParams.put(AbilityKey.Defenders, defenders);
game.getTriggerHandler().runTrigger(TriggerType.AttackerUnblockedOnce, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.AttackerUnblockedOnce, runParams, false);
} }
} }

View File

@@ -20,13 +20,13 @@ package forge.game.combat;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.card.CardType; import forge.card.CardType;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.game.Game; import forge.game.Game;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.GlobalRuleChange; import forge.game.GlobalRuleChange;
import forge.game.ability.AbilityKey;
import forge.game.card.*; import forge.game.card.*;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
@@ -305,14 +305,14 @@ public class CombatUtil {
*/ */
public static void checkDeclaredAttacker(final Game game, final Card c, final Combat combat) { public static void checkDeclaredAttacker(final Game game, final Card c, final Combat combat) {
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put("Attacker", c); runParams.put(AbilityKey.Attacker, c);
final List<Card> otherAttackers = combat.getAttackers(); final List<Card> otherAttackers = combat.getAttackers();
otherAttackers.remove(c); otherAttackers.remove(c);
runParams.put("OtherAttackers", otherAttackers); runParams.put(AbilityKey.OtherAttackers, otherAttackers);
runParams.put("Attacked", combat.getDefenderByAttacker(c)); runParams.put(AbilityKey.Attacked, combat.getDefenderByAttacker(c));
runParams.put("DefendingPlayer", combat.getDefenderPlayerByAttacker(c)); runParams.put(AbilityKey.DefendingPlayer, combat.getDefenderPlayerByAttacker(c));
runParams.put("Defenders", combat.getDefenders()); runParams.put(AbilityKey.Defenders, combat.getDefenders());
game.getTriggerHandler().runTrigger(TriggerType.Attacks, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Attacks, runParams, false);
c.getDamageHistory().setCreatureAttackedThisCombat(true); c.getDamageHistory().setCreatureAttackedThisCombat(true);

View File

@@ -223,7 +223,7 @@ public class CostAdjustment {
cardsToDelveOut.add(c); cardsToDelveOut.add(c);
} else if (!test) { } else if (!test) {
sa.getHostCard().addDelved(c); sa.getHostCard().addDelved(c);
final Card d = game.getAction().exile(c, null, null); final Card d = game.getAction().exile(c, null);
table.put(ZoneType.Graveyard, d.getZone().getZoneType(), d); table.put(ZoneType.Graveyard, d.getZone().getZoneType(), d);
} }
} }

View File

@@ -228,7 +228,7 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
result.staticAbilities = Lists.newArrayList(); result.staticAbilities = Lists.newArrayList();
for (StaticAbility sa : this.staticAbilities) { for (StaticAbility sa : this.staticAbilities) {
result.staticAbilities.add(new StaticAbility(sa, host)); result.staticAbilities.add(sa.copy(host, lki));
} }
return result; return result;

View File

@@ -192,7 +192,7 @@ public class KeywordsChange implements Cloneable {
result.removeKeywordInterfaces = Lists.newArrayList(); result.removeKeywordInterfaces = Lists.newArrayList();
for (KeywordInterface ki : this.removeKeywordInterfaces) { for (KeywordInterface ki : this.removeKeywordInterfaces) {
removeKeywordInterfaces.add(ki.copy(host, lki)); result.removeKeywordInterfaces.add(ki.copy(host, lki));
} }
return result; return result;

View File

@@ -30,7 +30,7 @@ public abstract class AbstractMulligan {
CardCollection toMulligan = new CardCollection(player.getCardsIn(ZoneType.Hand)); CardCollection toMulligan = new CardCollection(player.getCardsIn(ZoneType.Hand));
revealPreMulligan(toMulligan); revealPreMulligan(toMulligan);
for (final Card c : toMulligan) { for (final Card c : toMulligan) {
player.getGame().getAction().moveToLibrary(c, null, null); player.getGame().getAction().moveToLibrary(c, null);
} }
try { try {
Thread.sleep(100); //delay for a tiny bit to give UI a chance catch up Thread.sleep(100); //delay for a tiny bit to give UI a chance catch up

View File

@@ -415,7 +415,7 @@ public class PhaseHandler implements java.io.Serializable {
final Map<String, Object> runParams = Maps.newHashMap(); final Map<String, Object> runParams = Maps.newHashMap();
runParams.put("Phase", phase.nameForScripts); runParams.put("Phase", phase.nameForScripts);
runParams.put("Player", playerTurn); runParams.put("Player", playerTurn);
game.getTriggerHandler().runTrigger(TriggerType.Phase, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.Phase, runParams, false);
} }
// This line fixes Combat Damage triggers not going off when they should // This line fixes Combat Damage triggers not going off when they should
@@ -489,7 +489,7 @@ public class PhaseHandler implements java.io.Serializable {
// "Trigger" for begin turn to get around a phase skipping // "Trigger" for begin turn to get around a phase skipping
final Map<String, Object> runParams = Maps.newHashMap(); final Map<String, Object> runParams = Maps.newHashMap();
runParams.put("Player", playerTurn); runParams.put("Player", playerTurn);
game.getTriggerHandler().runTrigger(TriggerType.TurnBegin, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.TurnBegin, runParams, false);
} }
planarDiceRolledthisTurn = 0; planarDiceRolledthisTurn = 0;
// Play the End Turn sound // Play the End Turn sound
@@ -581,7 +581,7 @@ public class PhaseHandler implements java.io.Serializable {
runParams.put("Attackers", combat.getAttackers()); runParams.put("Attackers", combat.getAttackers());
runParams.put("AttackingPlayer", combat.getAttackingPlayer()); runParams.put("AttackingPlayer", combat.getAttackingPlayer());
runParams.put("AttackedTarget", attackedTarget); runParams.put("AttackedTarget", attackedTarget);
game.getTriggerHandler().runTrigger(TriggerType.AttackersDeclared, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.AttackersDeclared, runParams, false);
} }
for (final Card c : combat.getAttackers()) { for (final Card c : combat.getAttackers()) {
@@ -693,7 +693,7 @@ public class PhaseHandler implements java.io.Serializable {
final Map<String, Object> bdRunParams = Maps.newHashMap(); final Map<String, Object> bdRunParams = Maps.newHashMap();
bdRunParams.put("Blockers", declaredBlockers); bdRunParams.put("Blockers", declaredBlockers);
bdRunParams.put("Attackers", blockedAttackers); bdRunParams.put("Attackers", blockedAttackers);
game.getTriggerHandler().runTrigger(TriggerType.BlockersDeclared, bdRunParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.BlockersDeclared, bdRunParams, false);
} }
for (final Card c1 : combat.getAllBlockers()) { for (final Card c1 : combat.getAllBlockers()) {
@@ -706,7 +706,7 @@ public class PhaseHandler implements java.io.Serializable {
final Map<String, Object> runParams = Maps.newHashMap(); final Map<String, Object> runParams = Maps.newHashMap();
runParams.put("Blocker", c1); runParams.put("Blocker", c1);
runParams.put("Attackers", combat.getAttackersBlockedBy(c1)); runParams.put("Attackers", combat.getAttackersBlockedBy(c1));
game.getTriggerHandler().runTrigger(TriggerType.Blocks, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.Blocks, runParams, false);
} }
c1.getDamageHistory().setCreatureBlockedThisCombat(true); c1.getDamageHistory().setCreatureBlockedThisCombat(true);
@@ -730,7 +730,7 @@ public class PhaseHandler implements java.io.Serializable {
runParams.put("NumBlockers", blockers.size()); runParams.put("NumBlockers", blockers.size());
runParams.put("Defender", combat.getDefenderByAttacker(a)); runParams.put("Defender", combat.getDefenderByAttacker(a));
runParams.put("DefendingPlayer", combat.getDefenderPlayerByAttacker(a)); runParams.put("DefendingPlayer", combat.getDefenderPlayerByAttacker(a));
game.getTriggerHandler().runTrigger(TriggerType.AttackerBlocked, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.AttackerBlocked, runParams, false);
// Run this trigger once for each blocker // Run this trigger once for each blocker
for (final Card b : blockers) { for (final Card b : blockers) {
@@ -741,7 +741,7 @@ public class PhaseHandler implements java.io.Serializable {
final Map<String, Object> runParams2 = Maps.newHashMap(); final Map<String, Object> runParams2 = Maps.newHashMap();
runParams2.put("Attacker", a); runParams2.put("Attacker", a);
runParams2.put("Blocker", b); runParams2.put("Blocker", b);
game.getTriggerHandler().runTrigger(TriggerType.AttackerBlockedByCreature, runParams2, false); game.getTriggerHandler().runTriggerOld(TriggerType.AttackerBlockedByCreature, runParams2, false);
} }
a.getDamageHistory().setCreatureGotBlockedThisCombat(true); a.getDamageHistory().setCreatureGotBlockedThisCombat(true);
@@ -1073,6 +1073,14 @@ public class PhaseHandler implements java.io.Serializable {
game.fireEvent(new GameEventGameRestarted(playerTurn)); game.fireEvent(new GameEventGameRestarted(playerTurn));
return; return;
} }
// update Priority for all players
for (final Player p : game.getPlayers()) {
if(getPriorityPlayer() == p)
p.setHasPriority(true);
else
p.setHasPriority(false);
}
} }
} }

View File

@@ -242,13 +242,13 @@ public class Player extends GameEntity implements Comparable<Player> {
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
activeScheme = getZone(ZoneType.SchemeDeck).get(0); activeScheme = getZone(ZoneType.SchemeDeck).get(0);
// gameAction moveTo ? // gameAction moveTo ?
game.getAction().moveTo(ZoneType.Command, activeScheme, null, null); game.getAction().moveTo(ZoneType.Command, activeScheme, null);
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); final Map<String, Object> runParams = Maps.newHashMap();
runParams.put("Scheme", activeScheme); runParams.put("Scheme", activeScheme);
game.getTriggerHandler().runTrigger(TriggerType.SetInMotion, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.SetInMotion, runParams, false);
} }
@@ -450,7 +450,7 @@ public class Player extends GameEntity implements Comparable<Player> {
runParams.put("LifeAmount", lifeGain); runParams.put("LifeAmount", lifeGain);
runParams.put("Source", source); runParams.put("Source", source);
runParams.put("SourceSA", sa); runParams.put("SourceSA", sa);
game.getTriggerHandler().runTrigger(TriggerType.LifeGained, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.LifeGained, runParams, false);
game.fireEvent(new GameEventPlayerLivesChanged(this, oldLife, life)); game.fireEvent(new GameEventPlayerLivesChanged(this, oldLife, life));
} }
@@ -504,7 +504,7 @@ public class Player extends GameEntity implements Comparable<Player> {
runParams.put("Player", this); runParams.put("Player", this);
runParams.put("LifeAmount", toLose); runParams.put("LifeAmount", toLose);
runParams.put("FirstTime", firstLost); runParams.put("FirstTime", firstLost);
game.getTriggerHandler().runTrigger(TriggerType.LifeLost, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.LifeLost, runParams, false);
return lifeLost; return lifeLost;
} }
@@ -531,7 +531,7 @@ public class Player extends GameEntity implements Comparable<Player> {
final Map<String, Object> runParams = Maps.newHashMap(); final Map<String, Object> runParams = Maps.newHashMap();
runParams.put("Player", this); runParams.put("Player", this);
runParams.put("LifeAmount", lifePayment); runParams.put("LifeAmount", lifePayment);
game.getTriggerHandler().runTrigger(TriggerType.PayLife, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.PayLife, runParams, false);
return true; return true;
} }
@@ -618,7 +618,7 @@ public class Player extends GameEntity implements Comparable<Player> {
runParams.put("IsCombatDamage", isCombat); runParams.put("IsCombatDamage", isCombat);
// Defending player at the time the damage was dealt // Defending player at the time the damage was dealt
runParams.put("DefendingPlayer", game.getCombat() != null ? game.getCombat().getDefendingPlayerRelatedTo(source) : null); runParams.put("DefendingPlayer", game.getCombat() != null ? game.getCombat().getDefendingPlayerRelatedTo(source) : null);
game.getTriggerHandler().runTrigger(TriggerType.DamageDone, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.DamageDone, runParams, false);
game.fireEvent(new GameEventPlayerDamaged(this, source, amount, isCombat, infect)); game.fireEvent(new GameEventPlayerDamaged(this, source, amount, isCombat, infect));
@@ -941,10 +941,10 @@ public class Player extends GameEntity implements Comparable<Player> {
runParams.put("Source", this); runParams.put("Source", this);
runParams.put("CounterType", counterType); runParams.put("CounterType", counterType);
for (int i = 0; i < addAmount; i++) { for (int i = 0; i < addAmount; i++) {
getGame().getTriggerHandler().runTrigger(TriggerType.CounterAdded, runParams, false); getGame().getTriggerHandler().runTriggerOld(TriggerType.CounterAdded, runParams, false);
} }
if (addAmount > 0) { if (addAmount > 0) {
getGame().getTriggerHandler().runTrigger(TriggerType.CounterAddedOnce, runParams, false); getGame().getTriggerHandler().runTriggerOld(TriggerType.CounterAddedOnce, runParams, false);
} }
if (table != null) { if (table != null) {
table.put(this, counterType, addAmount); table.put(this, counterType, addAmount);
@@ -1308,7 +1308,7 @@ public class Player extends GameEntity implements Comparable<Player> {
if (toGrave != null) { if (toGrave != null) {
for(Card c : toGrave) { for(Card c : toGrave) {
getGame().getAction().moveToGraveyard(c, cause, null); getGame().getAction().moveToGraveyard(c, cause);
numToGrave++; numToGrave++;
} }
} }
@@ -1316,7 +1316,7 @@ public class Player extends GameEntity implements Comparable<Player> {
if (toTop != null) { if (toTop != null) {
Collections.reverse(toTop); // the last card in list will become topmost in library, have to revert thus. Collections.reverse(toTop); // the last card in list will become topmost in library, have to revert thus.
for(Card c : toTop) { for(Card c : toTop) {
getGame().getAction().moveToLibrary(c, cause, null); getGame().getAction().moveToLibrary(c, cause);
numToTop++; numToTop++;
} }
} }
@@ -1327,7 +1327,7 @@ public class Player extends GameEntity implements Comparable<Player> {
final Map<String, Object> runParams = Maps.newHashMap(); final Map<String, Object> runParams = Maps.newHashMap();
runParams.put("Player", this); runParams.put("Player", this);
runParams.put("NumThisTurn", surveilThisTurn); runParams.put("NumThisTurn", surveilThisTurn);
getGame().getTriggerHandler().runTrigger(TriggerType.Surveil, runParams, false); getGame().getTriggerHandler().runTriggerOld(TriggerType.Surveil, runParams, false);
} }
public int getSurveilThisTurn() { public int getSurveilThisTurn() {
@@ -1399,7 +1399,7 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
} }
c = game.getAction().moveToHand(c, null, null); c = game.getAction().moveToHand(c, null);
drawn.add(c); drawn.add(c);
if (topCardRevealed) { if (topCardRevealed) {
@@ -1419,7 +1419,7 @@ public class Player extends GameEntity implements Comparable<Player> {
runParams.put("Card", c); runParams.put("Card", c);
runParams.put("Number", numDrawnThisTurn); runParams.put("Number", numDrawnThisTurn);
runParams.put("Player", this); runParams.put("Player", this);
game.getTriggerHandler().runTrigger(TriggerType.Drawn, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.Drawn, runParams, false);
} }
else { // Lose by milling is always on. Give AI many cards it cannot play if you want it not to undertake actions else { // Lose by milling is always on. Give AI many cards it cannot play if you want it not to undertake actions
triedToDrawFromEmptyLibrary = true; triedToDrawFromEmptyLibrary = true;
@@ -1574,16 +1574,16 @@ public class Player extends GameEntity implements Comparable<Player> {
sb.append(this).append(" discards ").append(c); sb.append(this).append(" discards ").append(c);
final Card newCard; final Card newCard;
if (discardToTopOfLibrary) { if (discardToTopOfLibrary) {
newCard = game.getAction().moveToLibrary(c, 0, sa, null); newCard = game.getAction().moveToLibrary(c, 0, sa);
sb.append(" to the library"); sb.append(" to the library");
// Play the Discard sound // Play the Discard sound
} }
else if (discardMadness) { else if (discardMadness) {
newCard = game.getAction().exile(c, sa, null); newCard = game.getAction().exile(c, sa);
sb.append(" with Madness"); sb.append(" with Madness");
} }
else { else {
newCard = game.getAction().moveToGraveyard(c, sa, null); newCard = game.getAction().moveToGraveyard(c, sa);
// Play the Discard sound // Play the Discard sound
} }
if (table != null) { if (table != null) {
@@ -1608,7 +1608,7 @@ public class Player extends GameEntity implements Comparable<Player> {
runParams.put("Card", c); runParams.put("Card", c);
runParams.put("Cause", cause); runParams.put("Cause", cause);
runParams.put("IsMadness", Boolean.valueOf(discardMadness)); runParams.put("IsMadness", Boolean.valueOf(discardMadness));
game.getTriggerHandler().runTrigger(TriggerType.Discarded, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.Discarded, runParams, false);
game.getGameLog().add(GameLogEntryType.DISCARD, sb.toString()); game.getGameLog().add(GameLogEntryType.DISCARD, sb.toString());
return newCard; return newCard;
} }
@@ -1651,7 +1651,7 @@ public class Player extends GameEntity implements Comparable<Player> {
for (Card m : milledView) { for (Card m : milledView) {
final ZoneType origin = m.getZone().getZoneType(); final ZoneType origin = m.getZone().getZoneType();
final Card d = game.getAction().moveTo(destination, m, sa, null); final Card d = game.getAction().moveTo(destination, m, sa);
table.put(origin, d.getZone().getZoneType(), d); table.put(origin, d.getZone().getZoneType(), d);
} }
@@ -1689,7 +1689,7 @@ public class Player extends GameEntity implements Comparable<Player> {
final Map<String, Object> runParams = Maps.newHashMap(); final Map<String, Object> runParams = Maps.newHashMap();
runParams.put("Player", this); runParams.put("Player", this);
runParams.put("Source", sa); runParams.put("Source", sa);
game.getTriggerHandler().runTrigger(TriggerType.Shuffled, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.Shuffled, runParams, false);
// Play the shuffle sound // Play the shuffle sound
game.fireEvent(new GameEventShuffle(this)); game.fireEvent(new GameEventShuffle(this));
@@ -1711,7 +1711,7 @@ public class Player extends GameEntity implements Comparable<Player> {
if (land.isFaceDown()) { if (land.isFaceDown()) {
land.turnFaceUp(); land.turnFaceUp();
} }
game.getAction().moveTo(getZone(ZoneType.Battlefield), land, null, new HashMap<>()); game.getAction().moveTo(getZone(ZoneType.Battlefield), land, null);
// play a sound // play a sound
game.fireEvent(new GameEventLandPlayed(this, land)); game.fireEvent(new GameEventLandPlayed(this, land));
@@ -1719,7 +1719,7 @@ public class Player extends GameEntity implements Comparable<Player> {
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); final Map<String, Object> runParams = Maps.newHashMap();
runParams.put("Card", land); runParams.put("Card", land);
game.getTriggerHandler().runTrigger(TriggerType.LandPlayed, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.LandPlayed, runParams, false);
game.getStack().unfreezeStack(); game.getStack().unfreezeStack();
addLandPlayedThisTurn(); addLandPlayedThisTurn();
} }
@@ -2155,7 +2155,7 @@ public class Player extends GameEntity implements Comparable<Player> {
Map<String,Object> runParams = Maps.newHashMap(); Map<String,Object> runParams = Maps.newHashMap();
runParams.put("Player", this); runParams.put("Player", this);
runParams.put("Num", investigatedThisTurn); runParams.put("Num", investigatedThisTurn);
game.getTriggerHandler().runTrigger(TriggerType.Investigated, runParams,false); game.getTriggerHandler().runTriggerOld(TriggerType.Investigated, runParams,false);
} }
public final void resetInvestigatedThisTurn() { public final void resetInvestigatedThisTurn() {
investigatedThisTurn = 0; investigatedThisTurn = 0;
@@ -2180,7 +2180,7 @@ public class Player extends GameEntity implements Comparable<Player> {
runParams.put("Cause", source); runParams.put("Cause", source);
runParams.put("CostStack", game.costPaymentStack); runParams.put("CostStack", game.costPaymentStack);
runParams.put("IndividualCostPaymentInstance", game.costPaymentStack.peek()); runParams.put("IndividualCostPaymentInstance", game.costPaymentStack.peek());
game.getTriggerHandler().runTrigger(TriggerType.Sacrificed, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.Sacrificed, runParams, false);
} }
public final void resetSacrificedThisTurn() { public final void resetSacrificedThisTurn() {
@@ -2512,7 +2512,7 @@ public class Player extends GameEntity implements Comparable<Player> {
game.getView().updatePlanarPlayer(getView()); game.getView().updatePlanarPlayer(getView());
for (Card c : currentPlanes) { for (Card c : currentPlanes) {
game.getAction().moveTo(ZoneType.Command,c, null, null); game.getAction().moveTo(ZoneType.Command,c, null);
//getZone(ZoneType.PlanarDeck).remove(c); //getZone(ZoneType.PlanarDeck).remove(c);
//getZone(ZoneType.Command).add(c); //getZone(ZoneType.Command).add(c);
} }
@@ -2526,7 +2526,7 @@ public class Player extends GameEntity implements Comparable<Player> {
//Run PlaneswalkedTo triggers here. //Run PlaneswalkedTo triggers here.
Map<String,Object> runParams = Maps.newHashMap(); Map<String,Object> runParams = Maps.newHashMap();
runParams.put("Cards", currentPlanes); runParams.put("Cards", currentPlanes);
game.getTriggerHandler().runTrigger(TriggerType.PlaneswalkedTo, runParams,false); game.getTriggerHandler().runTriggerOld(TriggerType.PlaneswalkedTo, runParams,false);
view.updateCurrentPlaneName(currentPlanes.toString().replaceAll(" \\(.*","").replace("[","")); view.updateCurrentPlaneName(currentPlanes.toString().replaceAll(" \\(.*","").replace("[",""));
} }
@@ -2536,13 +2536,13 @@ public class Player extends GameEntity implements Comparable<Player> {
public void leaveCurrentPlane() { public void leaveCurrentPlane() {
final Map<String, Object> runParams = new ImmutableMap.Builder<String, Object>().put("Cards", new CardCollection(currentPlanes)).build(); final Map<String, Object> runParams = new ImmutableMap.Builder<String, Object>().put("Cards", new CardCollection(currentPlanes)).build();
game.getTriggerHandler().runTrigger(TriggerType.PlaneswalkedFrom, runParams,false); game.getTriggerHandler().runTriggerOld(TriggerType.PlaneswalkedFrom, runParams,false);
for (final Card plane : currentPlanes) { for (final Card plane : currentPlanes) {
//game.getZoneOf(plane).remove(plane); //game.getZoneOf(plane).remove(plane);
plane.clearControllers(); plane.clearControllers();
//getZone(ZoneType.PlanarDeck).add(plane); //getZone(ZoneType.PlanarDeck).add(plane);
game.getAction().moveTo(ZoneType.PlanarDeck, plane,-1, null, null); game.getAction().moveTo(ZoneType.PlanarDeck, plane,-1, null);
} }
currentPlanes.clear(); currentPlanes.clear();
@@ -2672,6 +2672,12 @@ public class Player extends GameEntity implements Comparable<Player> {
public void setExtraTurnCount(final int val) { public void setExtraTurnCount(final int val) {
view.setExtraTurnCount(val); view.setExtraTurnCount(val);
} }
public void setHasPriority(final boolean val) {
view.setHasPriority(val);
}
public boolean isAI() {
return view.isAI();
}
public void initVariantsZones(RegisteredPlayer registeredPlayer) { public void initVariantsZones(RegisteredPlayer registeredPlayer) {
PlayerZone bf = getZone(ZoneType.Battlefield); PlayerZone bf = getZone(ZoneType.Battlefield);

View File

@@ -205,6 +205,13 @@ public class PlayerView extends GameEntityView {
set(TrackableProperty.ExtraTurnCount, val); set(TrackableProperty.ExtraTurnCount, val);
} }
public boolean getHasPriority() {
return get(TrackableProperty.HasPriority);
}
public void setHasPriority(final boolean val) {
set(TrackableProperty.HasPriority, val);
}
public int getMaxHandSize() { public int getMaxHandSize() {
return get(TrackableProperty.MaxHandSize); return get(TrackableProperty.MaxHandSize);
} }

View File

@@ -27,6 +27,7 @@ import forge.util.TextUtil;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
/** /**
* TODO: Write javadoc for this type. * TODO: Write javadoc for this type.
@@ -261,6 +262,6 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public int hashCode() { public int hashCode() {
return 42 * (42 + this.getId()); return Objects.hash(ReplacementEffect.class, getId());
} }
} }

View File

@@ -23,6 +23,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import forge.card.mana.ManaAtom; import forge.card.mana.ManaAtom;
import forge.game.ability.AbilityKey;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler; import forge.game.trigger.TriggerHandler;
import forge.util.TextUtil; import forge.util.TextUtil;
@@ -166,12 +167,10 @@ public class AbilityManaPart implements java.io.Serializable {
manaPool.add(this.lastManaProduced); manaPool.add(this.lastManaProduced);
// Run triggers // Run triggers
final Map<String, Object> runParams = Maps.newHashMap(); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(source);
runParams.put(AbilityKey.Player, player);
runParams.put("Card", source); runParams.put(AbilityKey.AbilityMana, sa);
runParams.put("Player", player); runParams.put(AbilityKey.Produced, afterReplace);
runParams.put("AbilityMana", sa);
runParams.put("Produced", afterReplace);
player.getGame().getTriggerHandler().runTrigger(TriggerType.TapsForMana, runParams, false); player.getGame().getTriggerHandler().runTrigger(TriggerType.TapsForMana, runParams, false);
if (source.isLand()) { if (source.isLand()) {
player.setTappedLandForManaThisTurn(true); player.setTappedLandForManaThisTurn(true);

View File

@@ -205,7 +205,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
} }
@Override @Override
public int hashCode() { public int hashCode() {
return getId(); return Objects.hash(SpellAbility.class, getId());
} }
@Override @Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {

View File

@@ -355,10 +355,10 @@ public class SpellAbilityStackInstance implements IIdentifiable, IHasCardView {
((Card) tgt).setBecameTargetThisTurn(true); ((Card) tgt).setBecameTargetThisTurn(true);
} }
runParams.put("Target", tgt); runParams.put("Target", tgt);
getSourceCard().getGame().getTriggerHandler().runTrigger(TriggerType.BecomesTarget, runParams, false); getSourceCard().getGame().getTriggerHandler().runTriggerOld(TriggerType.BecomesTarget, runParams, false);
} }
runParams.put("Targets", target.getTargets()); runParams.put("Targets", target.getTargets());
getSourceCard().getGame().getTriggerHandler().runTrigger(TriggerType.BecomesTargetOnce, runParams, false); getSourceCard().getGame().getTriggerHandler().runTriggerOld(TriggerType.BecomesTargetOnce, runParams, false);
} }
} }

View File

@@ -17,6 +17,7 @@
*/ */
package forge.game.staticability; package forge.game.staticability;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import forge.card.MagicColor; import forge.card.MagicColor;
@@ -24,6 +25,7 @@ import forge.game.CardTraitBase;
import forge.game.Game; import forge.game.Game;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.GameStage; import forge.game.GameStage;
import forge.game.IIdentifiable;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
@@ -43,18 +45,38 @@ import forge.util.TextUtil;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
/** /**
* The Class StaticAbility. * The Class StaticAbility.
*/ */
public class StaticAbility extends CardTraitBase implements Comparable<StaticAbility> { public class StaticAbility extends CardTraitBase implements IIdentifiable, Cloneable, Comparable<StaticAbility> {
private static int maxId = 0;
private static int nextId() { return ++maxId; }
private final Set<StaticAbilityLayer> layers; private int id;
private Set<StaticAbilityLayer> layers;
private CardCollectionView ignoreEffectCards = new CardCollection(); private CardCollectionView ignoreEffectCards = new CardCollection();
private final List<Player> ignoreEffectPlayers = Lists.newArrayList(); private final List<Player> ignoreEffectPlayers = Lists.newArrayList();
private int mayPlayTurn = 0; private int mayPlayTurn = 0;
@Override
public final int getId() {
return id;
}
@Override
public int hashCode() {
return Objects.hash(StaticAbility.class, getId());
}
@Override
public boolean equals(final Object obj) {
return obj instanceof StaticAbility && this.id == ((StaticAbility) obj).id;
}
/** /**
* <p> * <p>
* Getter for the field <code>mapParams</code>. * Getter for the field <code>mapParams</code>.
@@ -228,6 +250,7 @@ public class StaticAbility extends CardTraitBase implements Comparable<StaticAbi
* the host * the host
*/ */
private StaticAbility(final Map<String, String> params, final Card host) { private StaticAbility(final Map<String, String> params, final Card host) {
this.id = nextId();
this.originalMapParams.putAll(params); this.originalMapParams.putAll(params);
this.mapParams.putAll(params); this.mapParams.putAll(params);
this.layers = this.generateLayer(); this.layers = this.generateLayer();
@@ -235,19 +258,6 @@ public class StaticAbility extends CardTraitBase implements Comparable<StaticAbi
buildCommonAttributes(host); buildCommonAttributes(host);
} }
public StaticAbility(StaticAbility stAb, Card host) {
this.originalMapParams.putAll(stAb.originalMapParams);
this.mapParams.putAll(stAb.mapParams);
this.layers = this.generateLayer();
this.hostCard = host;
this.intrinsic = stAb.intrinsic;
// Copy old sVars
this.sVars.putAll(stAb.sVars);
// but if they are References use this ones
buildCommonAttributes(host);
}
public final CardCollectionView applyContinuousAbilityBefore(final StaticAbilityLayer layer, final CardCollectionView preList) { public final CardCollectionView applyContinuousAbilityBefore(final StaticAbilityLayer layer, final CardCollectionView preList) {
if (!shouldApplyContinuousAbility(layer, false)) { if (!shouldApplyContinuousAbility(layer, false)) {
return null; return null;
@@ -769,6 +779,32 @@ public class StaticAbility extends CardTraitBase implements Comparable<StaticAbi
@Override @Override
public int compareTo(StaticAbility arg0) { public int compareTo(StaticAbility arg0) {
return getHostCard().compareTo(arg0.getHostCard()); return ComparisonChain.start()
.compare(getHostCard(),arg0.getHostCard())
.compare(getId(), arg0.getId())
.result();
}
public StaticAbility copy(Card host, final boolean lki) {
StaticAbility clone = null;
try {
clone = (StaticAbility) clone();
clone.id = lki ? id : nextId();
// dont use setHostCard to not trigger the not copied parts yet
clone.hostCard = host;
// need to clone the maps too so they can be changed
clone.originalMapParams = Maps.newHashMap(this.originalMapParams);
clone.mapParams = Maps.newHashMap(this.mapParams);
clone.sVars = Maps.newHashMap(this.sVars);
clone.layers = this.generateLayer();
clone.buildCommonAttributes(host);
} catch (final CloneNotSupportedException e) {
System.err.println(e);
}
return clone;
} }
} // end class StaticAbility } // end class StaticAbility

View File

@@ -532,7 +532,7 @@ public final class StaticAbilityContinuous {
if (addT.startsWith("AffectedX")) { if (addT.startsWith("AffectedX")) {
toughnessBonus = CardFactoryUtil.xCount(affectedCard, AbilityUtils.getSVar(stAb, addT)); toughnessBonus = CardFactoryUtil.xCount(affectedCard, AbilityUtils.getSVar(stAb, addT));
} }
affectedCard.addPTBoost(powerBonus, toughnessBonus, se.getTimestamp()); affectedCard.addPTBoost(powerBonus, toughnessBonus, se.getTimestamp(), stAb.getId());
} }
// add keywords // add keywords

View File

@@ -431,7 +431,7 @@ public abstract class Trigger extends TriggerReplacementBase {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public int hashCode() { public int hashCode() {
return 41 * (41 + this.getId()); return Objects.hash(Trigger.class, getId());
} }
/** /**

View File

@@ -23,6 +23,7 @@ import forge.game.GlobalRuleChange;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.ability.AbilityKey;
import forge.game.ability.effects.CharmEffect; import forge.game.ability.effects.CharmEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardLists; import forge.game.card.CardLists;
@@ -51,6 +52,8 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Multimaps; import com.google.common.collect.Multimaps;
import static forge.util.EnumMapUtil.toStringMap;
public class TriggerHandler { public class TriggerHandler {
private final List<TriggerType> suppressedModes = Collections.synchronizedList(new ArrayList<>()); private final List<TriggerType> suppressedModes = Collections.synchronizedList(new ArrayList<>());
private final List<Trigger> activeTriggers = Collections.synchronizedList(new ArrayList<>()); private final List<Trigger> activeTriggers = Collections.synchronizedList(new ArrayList<>());
@@ -318,12 +321,18 @@ public class TriggerHandler {
return false; return false;
} }
public final void runTrigger(final TriggerType mode, final Map<String, Object> runParams, boolean holdTrigger) { public final void runTrigger(final TriggerType mode, final Map<AbilityKey, Object> runParams, boolean holdTrigger) {
runTriggerOld(mode, toStringMap(runParams), holdTrigger);
}
// The plan is to slowly refactor any usages of `runTriggerOld` to use `runTrigger`. Then we can just inline
// `runTriggerOld` into `runTrigger` and change the code inside to just always use a `Map<TriggerKey, Object>`.
// The reason we can't just call them both `runTrigger` is because we get a `same erasure` compile error if we do.
@Deprecated
public final void runTriggerOld(final TriggerType mode, final Map<String, Object> runParams, boolean holdTrigger) {
if (suppressedModes.contains(mode)) { if (suppressedModes.contains(mode)) {
return; return;
} }
//runWaitingTrigger(new TriggerWaiting(mode, runParams));
if (mode == TriggerType.Always) { if (mode == TriggerType.Always) {
runStateTrigger(runParams); runStateTrigger(runParams);
} else if (game.getStack().isFrozen() || holdTrigger) { } else if (game.getStack().isFrozen() || holdTrigger) {
@@ -331,20 +340,14 @@ public class TriggerHandler {
} else { } else {
runWaitingTrigger(new TriggerWaiting(mode, runParams)); runWaitingTrigger(new TriggerWaiting(mode, runParams));
} }
// Tell auto stop to stop
} }
public final boolean runStateTrigger(Map<String, Object> runParams) { private void runStateTrigger(Map<String, Object> runParams) {
boolean checkStatics = false;
// only cards in play can run state triggers
for (final Trigger t: activeTriggers) { for (final Trigger t: activeTriggers) {
if (canRunTrigger(t, TriggerType.Always, runParams)) { if (canRunTrigger(t, TriggerType.Always, runParams)) {
runSingleTrigger(t, runParams); runSingleTrigger(t, runParams);
checkStatics = true;
} }
} }
return checkStatics;
} }
public final boolean runWaitingTriggers() { public final boolean runWaitingTriggers() {
@@ -362,7 +365,7 @@ public class TriggerHandler {
return haveWaiting; return haveWaiting;
} }
public final boolean runWaitingTrigger(final TriggerWaiting wt) { private boolean runWaitingTrigger(final TriggerWaiting wt) {
final TriggerType mode = wt.getMode(); final TriggerType mode = wt.getMode();
final Map<String, Object> runParams = wt.getParams(); final Map<String, Object> runParams = wt.getParams();

View File

@@ -36,6 +36,7 @@ import forge.GameCommand;
import forge.game.Game; import forge.game.Game;
import forge.game.GameLogEntryType; import forge.game.GameLogEntryType;
import forge.game.GameObject; import forge.game.GameObject;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.card.Card;
@@ -136,7 +137,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
// on the stack zone, move there // on the stack zone, move there
if (ability.isSpell()) { if (ability.isSpell()) {
if (!source.isCopiedSpell() && !source.isInZone(ZoneType.Stack)) { if (!source.isCopiedSpell() && !source.isInZone(ZoneType.Stack)) {
ability.setHostCard(game.getAction().moveToStack(source, ability, null)); ability.setHostCard(game.getAction().moveToStack(source, ability));
} }
} }
@@ -294,7 +295,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
runParams.put("CastSACMC", si.getSpellAbility(true).getHostCard().getCMC()); runParams.put("CastSACMC", si.getSpellAbility(true).getHostCard().getCMC());
runParams.put("CurrentStormCount", thisTurnCast.size()); runParams.put("CurrentStormCount", thisTurnCast.size());
runParams.put("CurrentCastSpells", new CardCollection(thisTurnCast)); runParams.put("CurrentCastSpells", new CardCollection(thisTurnCast));
game.getTriggerHandler().runTrigger(TriggerType.SpellAbilityCast, runParams, true); game.getTriggerHandler().runTriggerOld(TriggerType.SpellAbilityCast, runParams, true);
// Run SpellCast triggers // Run SpellCast triggers
if (sp.isSpell()) { if (sp.isSpell()) {
@@ -302,27 +303,27 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
&& source.getOwner().equals(activator)) { && source.getOwner().equals(activator)) {
activator.incCommanderCast(source); activator.incCommanderCast(source);
} }
game.getTriggerHandler().runTrigger(TriggerType.SpellCast, runParams, true); game.getTriggerHandler().runTriggerOld(TriggerType.SpellCast, runParams, true);
executeCastCommand(si.getSpellAbility(true).getHostCard()); executeCastCommand(si.getSpellAbility(true).getHostCard());
} }
// Run AbilityCast triggers // Run AbilityCast triggers
if (sp.isAbility() && !sp.isTrigger()) { if (sp.isAbility() && !sp.isTrigger()) {
game.getTriggerHandler().runTrigger(TriggerType.AbilityCast, runParams, true); game.getTriggerHandler().runTriggerOld(TriggerType.AbilityCast, runParams, true);
} }
// Run Cycled triggers // Run Cycled triggers
if (sp.isCycling()) { if (sp.isCycling()) {
runParams.clear(); runParams.clear();
runParams.put("Card", sp.getHostCard()); runParams.put("Card", sp.getHostCard());
game.getTriggerHandler().runTrigger(TriggerType.Cycled, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.Cycled, runParams, false);
} }
if (sp.hasParam("Crew")) { if (sp.hasParam("Crew")) {
// Trigger crews! // Trigger crews!
runParams.put("Vehicle", sp.getHostCard()); runParams.put("Vehicle", sp.getHostCard());
runParams.put("Crew", sp.getPaidList("TappedCards")); runParams.put("Crew", sp.getPaidList("TappedCards"));
game.getTriggerHandler().runTrigger(TriggerType.Crewed, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.Crewed, runParams, false);
} }
} }
@@ -332,9 +333,9 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
runParams.put("CopySA", si.getSpellAbility(true)); runParams.put("CopySA", si.getSpellAbility(true));
// Run SpellCopy triggers // Run SpellCopy triggers
if (sp.isSpell()) { if (sp.isSpell()) {
game.getTriggerHandler().runTrigger(TriggerType.SpellCopy, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.SpellCopy, runParams, false);
} }
game.getTriggerHandler().runTrigger(TriggerType.SpellAbilityCopy, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.SpellAbilityCopy, runParams, false);
} }
// Run BecomesTarget triggers // Run BecomesTarget triggers
@@ -364,10 +365,10 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
((Card) tgt).setBecameTargetThisTurn(true); ((Card) tgt).setBecameTargetThisTurn(true);
} }
runParams.put("Target", tgt); runParams.put("Target", tgt);
game.getTriggerHandler().runTrigger(TriggerType.BecomesTarget, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.BecomesTarget, runParams, false);
} }
runParams.put("Targets", tc.getTargets()); runParams.put("Targets", tc.getTargets());
game.getTriggerHandler().runTrigger(TriggerType.BecomesTargetOnce, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.BecomesTargetOnce, runParams, false);
} }
} }
} }
@@ -376,10 +377,10 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
else if (sp.getTargetCard() != null) { else if (sp.getTargetCard() != null) {
runParams.put("Target", sp.getTargetCard()); runParams.put("Target", sp.getTargetCard());
game.getTriggerHandler().runTrigger(TriggerType.BecomesTarget, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.BecomesTarget, runParams, false);
runParams.put("Targets", Lists.newArrayList(sp.getTargetCard())); runParams.put("Targets", Lists.newArrayList(sp.getTargetCard()));
game.getTriggerHandler().runTrigger(TriggerType.BecomesTargetOnce, runParams, false); game.getTriggerHandler().runTriggerOld(TriggerType.BecomesTargetOnce, runParams, false);
} }
game.fireEvent(new GameEventZone(ZoneType.Stack, sp.getActivatingPlayer(), EventValueChangeType.Added, source)); game.fireEvent(new GameEventZone(ZoneType.Stack, sp.getActivatingPlayer(), EventValueChangeType.Added, source));
@@ -531,10 +532,10 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
else if ((source.isInstant() || source.isSorcery() || fizzle) && else if ((source.isInstant() || source.isSorcery() || fizzle) &&
source.isInZone(ZoneType.Stack)) { source.isInZone(ZoneType.Stack)) {
// If Spell and still on the Stack then let it goto the graveyard or replace its own movement // If Spell and still on the Stack then let it goto the graveyard or replace its own movement
Map<String, Object> params = Maps.newHashMap(); Map<AbilityKey, Object> params = AbilityKey.newMap();
params.put("StackSa", sa); params.put(AbilityKey.StackSa, sa);
params.put("StackSi", si); params.put(AbilityKey.StackSi, si);
params.put("Fizzle", fizzle); params.put(AbilityKey.Fizzle, fizzle);
game.getAction().moveToGraveyard(source, null, params); game.getAction().moveToGraveyard(source, null, params);
} }
} }

View File

@@ -120,6 +120,7 @@ public enum TrackableProperty {
Mana(TrackableTypes.ManaMapType, FreezeMode.IgnoresFreeze), Mana(TrackableTypes.ManaMapType, FreezeMode.IgnoresFreeze),
IsExtraTurn(TrackableTypes.BooleanType), IsExtraTurn(TrackableTypes.BooleanType),
ExtraTurnCount(TrackableTypes.IntegerType), ExtraTurnCount(TrackableTypes.IntegerType),
HasPriority(TrackableTypes.BooleanType),
//SpellAbility //SpellAbility
HostCard(TrackableTypes.CardViewType), HostCard(TrackableTypes.CardViewType),

View File

@@ -0,0 +1,18 @@
package forge.util;
import java.util.HashMap;
import java.util.Map;
public final class EnumMapUtil {
private EnumMapUtil() { };
public static <K extends Enum<K>, V> HashMap<String, V> toStringMap(Map<K, V> map) {
HashMap<String, V> output = new HashMap<>(map.size());
for (Map.Entry<K, V> entry : map.entrySet()) {
output.put(entry.getKey().toString(), entry.getValue());
}
return output;
}
}

View File

@@ -35,6 +35,7 @@ import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.LinkedList; import java.util.LinkedList;
@@ -164,9 +165,8 @@ public final class ItemListView<T extends InventoryItem> extends ItemView<T> {
columns.add(colOverrides.get(colConfig.getDef())); columns.add(colOverrides.get(colConfig.getDef()));
} }
} }
columns.sort(new Comparator<ItemTableColumn>() { Collections.sort(columns, new Comparator<ItemTableColumn>() {
@Override @Override public int compare(final ItemTableColumn arg0, final ItemTableColumn arg1) {
public int compare(final ItemTableColumn arg0, final ItemTableColumn arg1) {
return Integer.compare(arg0.getIndex(), arg1.getIndex()); return Integer.compare(arg0.getIndex(), arg1.getIndex());
} }
}); });

View File

@@ -4,6 +4,7 @@ import java.awt.Color;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@@ -46,7 +47,7 @@ public class ContestGauntletLister extends JPanel {
final List<RowPanel> tempRows = new ArrayList<>(); final List<RowPanel> tempRows = new ArrayList<>();
final List<GauntletData> sorted = new ArrayList<>(); final List<GauntletData> sorted = new ArrayList<>();
sorted.addAll(gd0); sorted.addAll(gd0);
sorted.sort(new Comparator<GauntletData>() { Collections.sort(sorted, new Comparator<GauntletData>() {
@Override @Override
public int compare(final GauntletData x, final GauntletData y) { public int compare(final GauntletData x, final GauntletData y) {
return x.getName().compareTo(y.getName()); return x.getName().compareTo(y.getName());

View File

@@ -4,6 +4,7 @@ import java.awt.Color;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@@ -65,7 +66,7 @@ public class QuickGauntletLister extends JPanel {
final List<RowPanel> tempRows = new ArrayList<>(); final List<RowPanel> tempRows = new ArrayList<>();
final List<GauntletData> sorted = new ArrayList<>(); final List<GauntletData> sorted = new ArrayList<>();
sorted.addAll(gauntlets); sorted.addAll(gauntlets);
sorted.sort(new Comparator<GauntletData>() { Collections.sort(sorted, new Comparator<GauntletData>() {
@Override @Override
public int compare(final GauntletData x, final GauntletData y) { public int compare(final GauntletData x, final GauntletData y) {
return x.getName().toLowerCase().compareTo(y.getName().toLowerCase()); return x.getName().toLowerCase().compareTo(y.getName().toLowerCase());

View File

@@ -67,7 +67,7 @@ public class QuestFileLister extends JPanel {
List<RowPanel> tempRows = new ArrayList<>(); List<RowPanel> tempRows = new ArrayList<>();
List<QuestData> sorted = new ArrayList<>(); List<QuestData> sorted = new ArrayList<>();
sorted.addAll(qd0); sorted.addAll(qd0);
sorted.sort(new Comparator<QuestData>() { Collections.sort(sorted, new Comparator<QuestData>() {
@Override @Override
public int compare(final QuestData x, final QuestData y) { public int compare(final QuestData x, final QuestData y) {
return x.getName().toLowerCase().compareTo(y.getName().toLowerCase()); return x.getName().toLowerCase().compareTo(y.getName().toLowerCase());

View File

@@ -355,7 +355,21 @@ public enum CSubmenuPreferences implements ICDoc {
} }
private void initializeDefaultLanguageComboBox() { private void initializeDefaultLanguageComboBox() {
final String [] choices = {"en-US", "es-ES", "de-DE"}; final File lang_root = new File(ForgeConstants.LANG_DIR);
final File[] files = lang_root.listFiles();
final List<String> allLanguages = new ArrayList<>();
for ( File file : files ) {
if ( !file.isFile() ) {
continue;
}
String languageName = file.getName();
if (!languageName.endsWith(".properties")) {
continue;
}
allLanguages.add(languageName.replace(".properties", ""));
}
final String [] choices = new String[ allLanguages.size() ];
allLanguages.toArray( choices );
final FPref userSetting = FPref.UI_LANGUAGE; final FPref userSetting = FPref.UI_LANGUAGE;
final FComboBoxPanel<String> panel = this.view.getCbpDefaultLanguageComboBoxPanel(); final FComboBoxPanel<String> panel = this.view.getCbpDefaultLanguageComboBoxPanel();
final FComboBox<String> comboBox = createComboBox(choices, userSetting); final FComboBox<String> comboBox = createComboBox(choices, userSetting);

View File

@@ -21,6 +21,7 @@ import forge.CachedCardImage;
import forge.FThreads; import forge.FThreads;
import forge.StaticData; import forge.StaticData;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.card.CardTranslation;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardView; import forge.game.card.CardView;
@@ -690,7 +691,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
} }
// Card name overlay // Card name overlay
titleText.setText(card.getCurrentState().getName()); titleText.setText(CardTranslation.getTranslatedName(card.getCurrentState().getName()));
final int damage = card.getDamage(); final int damage = card.getDamage();
damageText.setText(damage > 0 ? "\u00BB " + damage + " \u00AB" : ""); damageText.setText(damage > 0 ? "\u00BB " + damage + " \u00AB" : "");

View File

@@ -19,6 +19,7 @@ package forge.view.arcane;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
@@ -126,7 +127,7 @@ public class FloatingZone extends FloatingCardArea {
if ( zoneCards != null ) { if ( zoneCards != null ) {
cardList = new FCollection<>(zoneCards); cardList = new FCollection<>(zoneCards);
if ( sortedByName ) { if ( sortedByName ) {
cardList.sort(comp); Collections.sort(cardList, comp);
} }
return cardList; return cardList;
} else { } else {

View File

@@ -2036,4 +2036,23 @@ public class GameSimulatorTest extends SimulationTestCase {
assertTrue(dimirdgAfterCopy2.isFlipped()); assertTrue(dimirdgAfterCopy2.isFlipped());
assertFalse(dimirdgAfterCopy2.getType().isLegendary()); assertFalse(dimirdgAfterCopy2.getType().isLegendary());
} }
public void testStaticMultiPump() {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
Card c1 = addCard("Creakwood Liege", p);
Card c2 = addCard("Creakwood Liege", p);
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
// update stats state
game.getAction().checkStateEffects(true);
assertTrue(c1.getNetPower() == 4);
assertTrue(c1.getNetToughness() == 4);
assertTrue(c2.getNetPower() == 4);
assertTrue(c2.getNetToughness() == 4);
}
} }

View File

@@ -2,6 +2,7 @@ package forge.gamesimulationtests.util;
import forge.deck.Deck; import forge.deck.Deck;
import forge.game.*; import forge.game.*;
import forge.game.ability.AbilityKey;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.event.GameEventGameFinished; import forge.game.event.GameEventGameFinished;
import forge.game.player.Player; import forge.game.player.Player;
@@ -137,8 +138,8 @@ public class GameWrapper {
//game.getAction().startGame( null ) determines starting player, draws starting hands, handles mulligans, and initiates the first turn //game.getAction().startGame( null ) determines starting player, draws starting hands, handles mulligans, and initiates the first turn
//skip drawing initial hand and mulliganing //skip drawing initial hand and mulliganing
game.setAge( GameStage.Play ); game.setAge( GameStage.Play );
final HashMap<String, Object> runParams = new HashMap<>(); game.getTriggerHandler().runTrigger(TriggerType.NewGame, AbilityKey.newMap(), false);
game.getTriggerHandler().runTrigger( TriggerType.NewGame, runParams, false );
//first player in the list starts, no coin toss etc //first player in the list starts, no coin toss etc
game.getPhaseHandler().startFirstTurn( game.getPlayers().get( 0 ) ); game.getPhaseHandler().startFirstTurn( game.getPlayers().get( 0 ) );
game.fireEvent( new GameEventGameFinished() ); game.fireEvent( new GameEventGameFinished() );

View File

@@ -10,6 +10,7 @@ import forge.assets.AssetsDownloader;
import forge.assets.FSkin; import forge.assets.FSkin;
import forge.assets.FSkinFont; import forge.assets.FSkinFont;
import forge.assets.ImageCache; import forge.assets.ImageCache;
import forge.card.CardTranslation;
import forge.error.BugReporter; import forge.error.BugReporter;
import forge.error.ExceptionHandler; import forge.error.ExceptionHandler;
import forge.interfaces.IDeviceAdapter; import forge.interfaces.IDeviceAdapter;
@@ -51,7 +52,8 @@ public class Forge implements ApplicationListener {
private static boolean textureFiltering = false; private static boolean textureFiltering = false;
private static boolean destroyThis = false; private static boolean destroyThis = false;
public static String extrawide = "default"; public static String extrawide = "default";
public static float heigtModifier = 0.0f; public static float heigtModifier = 0.0f;
private static boolean isloadingaMatch = false;
public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0) { public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0) {
if (GuiBase.getInterface() == null) { if (GuiBase.getInterface() == null) {
@@ -107,6 +109,9 @@ public class Forge implements ApplicationListener {
splashScreen.getProgressBar().setDescription("Loading fonts..."); splashScreen.getProgressBar().setDescription("Loading fonts...");
FSkinFont.preloadAll(); FSkinFont.preloadAll();
splashScreen.getProgressBar().setDescription("Loading card translations...");
CardTranslation.preloadTranslation(prefs.getPref(FPref.UI_LANGUAGE));
splashScreen.getProgressBar().setDescription("Finishing startup..."); splashScreen.getProgressBar().setDescription("Finishing startup...");
Gdx.app.postRunnable(new Runnable() { Gdx.app.postRunnable(new Runnable() {
@@ -307,6 +312,14 @@ public class Forge implements ApplicationListener {
return screenWidth > screenHeight; return screenWidth > screenHeight;
} }
public static boolean isLoadingaMatch() {
return isloadingaMatch;
}
public static void setLoadingaMatch(boolean value) {
isloadingaMatch = value;
}
public static int getScreenWidth() { public static int getScreenWidth() {
return screenWidth; return screenWidth;
} }

View File

@@ -533,6 +533,7 @@ public class Graphics {
alphaComposite = 1; alphaComposite = 1;
batch.setColor(Color.WHITE); batch.setColor(Color.WHITE);
} }
public float getfloatAlphaComposite() { return alphaComposite; }
public void drawImage(FImage image, float x, float y, float w, float h) { public void drawImage(FImage image, float x, float y, float w, float h) {
drawImage(image, x, y, w, h, false); drawImage(image, x, y, w, h, false);

View File

@@ -5,8 +5,12 @@ import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.*; import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData; import com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData;
import com.badlogic.gdx.graphics.g2d.BitmapFont.Glyph;
import com.badlogic.gdx.graphics.g2d.PixmapPacker;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter; import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.glutils.PixmapTextureData; import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
@@ -26,7 +30,6 @@ public class FSkinFont {
private static final String TTF_FILE = "font1.ttf"; private static final String TTF_FILE = "font1.ttf";
private static final Map<Integer, FSkinFont> fonts = new HashMap<>(); private static final Map<Integer, FSkinFont> fonts = new HashMap<>();
private static final GlyphLayout layout = new GlyphLayout();
static { static {
FileUtil.ensureDirectoryExists(ForgeConstants.FONTS_DIR); FileUtil.ensureDirectoryExists(ForgeConstants.FONTS_DIR);
@@ -90,26 +93,188 @@ public class FSkinFont {
fontSize = fontSize0; fontSize = fontSize0;
updateFont(); updateFont();
} }
static int indexOf (CharSequence text, char ch, int start) {
final int n = text.length();
for (; start < n; start++)
if (text.charAt(start) == ch) return start;
return n;
}
public int computeVisibleGlyphs (CharSequence str, int start, int end, float availableWidth) {
BitmapFontData data = font.getData();
int index = start;
float width = 0;
Glyph lastGlyph = null;
availableWidth /= data.scaleX;
for (; index < end; index++) {
char ch = str.charAt(index);
if (ch == '[' && data.markupEnabled) {
index++;
if (!(index < end && str.charAt(index) == '[')) { // non escaped '['
while (index < end && str.charAt(index) != ']')
index++;
continue;
}
}
Glyph g = data.getGlyph(ch);
if (g != null) {
if (lastGlyph != null) width += lastGlyph.getKerning(ch);
if ((width + g.xadvance) - availableWidth > 0.001f) break;
width += g.xadvance;
lastGlyph = g;
}
}
return index - start;
}
public boolean isBreakChar (char c) {
BitmapFontData data = font.getData();
if (data.breakChars == null) return false;
for (char br : data.breakChars)
if (c == br) return true;
return false;
}
static boolean isWhitespace (char c) {
switch (c) {
case '\n':
case '\r':
case '\t':
case ' ':
return true;
default:
return false;
}
}
// Expose methods from font that updates scale as needed // Expose methods from font that updates scale as needed
public TextBounds getBounds(CharSequence str) { public TextBounds getBounds(CharSequence str) {
updateScale(); //must update scale before measuring text updateScale(); //must update scale before measuring text
layout.setText(font, str); return getBounds(str, 0, str.length());
return new TextBounds(layout.width, layout.height); }
public TextBounds getBounds(CharSequence str, int start, int end) {
BitmapFontData data = font.getData();
//int start = 0;
//int end = str.length();
int width = 0;
Glyph lastGlyph = null;
while (start < end) {
char ch = str.charAt(start++);
if (ch == '[' && data.markupEnabled) {
if (!(start < end && str.charAt(start) == '[')) { // non escaped '['
while (start < end && str.charAt(start) != ']')
start++;
start++;
continue;
}
start++;
}
lastGlyph = data.getGlyph(ch);
if (lastGlyph != null) {
width = lastGlyph.xadvance;
break;
}
}
while (start < end) {
char ch = str.charAt(start++);
if (ch == '[' && data.markupEnabled) {
if (!(start < end && str.charAt(start) == '[')) { // non escaped '['
while (start < end && str.charAt(start) != ']')
start++;
start++;
continue;
}
start++;
}
Glyph g = data.getGlyph(ch);
if (g != null) {
width += lastGlyph.getKerning(ch);
lastGlyph = g;
width += g.xadvance;
}
}
return new TextBounds(width * data.scaleX, data.capHeight);
} }
public TextBounds getMultiLineBounds(CharSequence str) { public TextBounds getMultiLineBounds(CharSequence str) {
updateScale(); updateScale();
layout.setText(font, str); BitmapFontData data = font.getData();
return new TextBounds(layout.width, layout.height); int start = 0;
float maxWidth = 0;
int numLines = 0;
int length = str.length();
while (start < length) {
int lineEnd = indexOf(str, '\n', start);
float lineWidth = getBounds(str, start, lineEnd).width;
maxWidth = Math.max(maxWidth, lineWidth);
start = lineEnd + 1;
numLines++;
}
return new TextBounds(maxWidth, data.capHeight + (numLines - 1) * data.lineHeight);
} }
public TextBounds getWrappedBounds(CharSequence str, float wrapWidth) { public TextBounds getWrappedBounds(CharSequence str, float wrapWidth) {
updateScale(); updateScale();
layout.setText(font, str); BitmapFontData data = font.getData();
layout.width = wrapWidth; if (wrapWidth <= 0) wrapWidth = Integer.MAX_VALUE;
return new TextBounds(layout.width, layout.height); int start = 0;
int numLines = 0;
int length = str.length();
float maxWidth = 0;
while (start < length) {
int newLine = indexOf(str, '\n', start);
int lineEnd = start + computeVisibleGlyphs(str, start, newLine, wrapWidth);
int nextStart = lineEnd + 1;
if (lineEnd < newLine) {
// Find char to break on.
while (lineEnd > start) {
if (isWhitespace(str.charAt(lineEnd))) break;
if (isBreakChar(str.charAt(lineEnd - 1))) break;
lineEnd--;
}
if (lineEnd == start) {
if (nextStart > start + 1) nextStart--;
lineEnd = nextStart; // If no characters to break, show all.
} else {
nextStart = lineEnd;
// Eat whitespace at start of wrapped line.
while (nextStart < length) {
char c = str.charAt(nextStart);
if (!isWhitespace(c)) break;
nextStart++;
if (c == '\n') break; // Eat only the first wrapped newline.
}
// Eat whitespace at end of line.
while (lineEnd > start) {
if (!isWhitespace(str.charAt(lineEnd - 1))) break;
lineEnd--;
}
}
}
if (lineEnd > start) {
float lineWidth = getBounds(str, start, lineEnd).width;
maxWidth = Math.max(maxWidth, lineWidth);
}
start = nextStart;
numLines++;
}
return new TextBounds(maxWidth, data.capHeight + (numLines - 1) * data.lineHeight);
} }
public float getAscent() { public float getAscent() {
updateScale(); updateScale();
@@ -187,30 +352,115 @@ public class FSkinFont {
//only generate images for characters that could be used by Forge //only generate images for characters that could be used by Forge
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\"!?'.,;:()[]{}<>|/@\\^$-%+=#_&*\u2014\u2022"; String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\"!?'.,;:()[]{}<>|/@\\^$-%+=#_&*\u2014\u2022";
chars += "ÁÉÍÓÚáéíóúÀÈÌÒÙàèìòùÑñÄËÏÖÜäëïöüẞß"; chars += "ÁÉÍÓÚáéíóúÀÈÌÒÙàèìòùÑñÄËÏÖÜäëïöüẞß";
//generate from zh-CN.properties //generate from zh-CN.properties,and cardnames-zh-CN.txt
chars += "“”、一三上下不与专且东两个中临为主么义之乐也了争事二于五些交产" //forge generate 3000+ characters cache need Take some time(MIN_FONT_SIZE - MAX_FONT_SIZE all size)
+ "亮人什仅从他付代以们件价任优会传伤但位低住体何作你使例供侧侵便" //maybe using libgdx-hiero generate font cache is better
+ "保信倍候值偏做停偿像允元充先克入全关其具兼兽内再冒决况准减凑几" chars += "·âéöû—“”•−●、。「」『』一丁七万三!(),/:;?~鼹鼻齐齑"
+ "出击分切列则创初删利到制刷前剪副力功加动助励势包化匹区十协单卖" + "上下不与丑专且世丘业丛东丝两严丧个中丰临丸丹为丽举乃久么义"
+ "博卡印即原去参双发取受变叠口句只召可台史右号司合同名后向吗否含" + "之乌乍乐乔乖乘乙九也乡书乱乳乾了予争事二于云互五井亘亚些亡"
+ "启告员周命和咒品哪唤售商喜器回因团困围图在地场均坊坏坟型域基堆" + "交亥亦产享京亮亲亵人亿什仁仅仆仇今介仍从仑仓仕他仗付仙代令"
+ "塞境墓增声处备复多大天太失头夹奇奖套好如始子字存它完宏官定宝实" + "以仪们仰仲件价任份仿伊伍伏伐休众优伙会伟传伤伦伪伯伴伶伺似"
+ "宠客害家容对导将小少尝就局层屏展属巅左差已市布带帮常幕并幻序库" + "伽但位低住佐佑体何余佚佛作你佣佩佳使例侍侏供依侠侣侦侧侬侮"
+ "应底店度建开异弊式引张弧强当录形征很得御徽必志快忽态性总恢息您" + "侯侵便促俄俊俐俑俘保信修俯俸個倍倒候借倡倦倨倪债值倾假偏做"
+ "悬情惊惰想意慢戏成我或战户所手才打执找把抓抗折报拉拟拥择括持指" + "停偶偷偿傀傍储催傲像僧僭僵僻儒儡儿兀允元充兆先光克免兔兕党"
+ "按挑挡挥损换据捷排探接控掷描提摩摸撤播操擎支收改攻放故效数文斗" + "入全八公六兰共关兴兵其具典兹养兼兽内册再冒冕写军农冠冢冥冬"
+ "斯新方旅无日旧时明易星是显景暂暴更替最有服期未本术机权束来杯松" + "冰冲决况冶冷冻净准凋凌减凑凛凝几凡凤凭凯凰凶出击凿刀刃分切"
+ "板构果柄染查标栏样格框档检植模次止正此死殊段每比池没法注洗洛活" + "刈刍刑划列则刚创初删判利别刮到制刷刹刺刻刽剂剃削剌前剎剑剖"
+ "测消涵混添清渐温渲游源滤灵灼点烁烧然片版牌物特状独率王玩环现珍" + "剜剥剧剩剪副割剽劈力劝办功加务劣动助努劫励劲劳势勃勇勉勋勒"
+ "理瓦生用由画界留略登白百的盒盖盘目直相省看着瞄瞬知破确磨示神票" + "勘募勤勾包匍匐匕化北匙匠匪匹区医匿十千升午半华协卑卒卓单卖"
+ "禁离种秘积称移稀程空窗立竞章第等筑筛简管箭类精系素索紧红级线组" + "南博卜占卡卢卦卫印危即却卵卷卸厂厄厅历厉压厚原厢厥厦厨去参"
+ "细终经结给络统继绩续维绿缓编缩缺网置者而联肥背胜能脚自至致舒航" + "叉及友双反发叔取受变叙叛叠口古句另叨只叫召叮可台史右叶号司"
+ "般艇色节英范莫获菜蓝薪藏行衍衡补表被西要覆观规视览觉角解触言誓" + "叹吁吃各合吉吊同名后吏吐向吓吕吗君吞吟否含听吮启吱吸吹吻吼"
+ "警计认让记许论设证评试诗诡该详语误说请读调谋谜象败费资赌赛赢起" + "呆告呕员周味呼命咆和咏咒咕咬咯咳咽哀品哈响哑哗哥哨哩哪哭哮"
+ "距跳踢转轮轻载较辑输辨边过运近返还这进远连述退适选逐递速造道那" + "哲哺唐唤售唯唱啃啄商啜啪啮啸喀喂善喉喊喋喘喙喜喝喧喷嗅嗔嗜"
+ "部都配醒释里重量金钮铁银销锁锋错锦键长门闪闭间队防阴阶阻限除险" + "嗡嗣嗫嘉嘎嘘嘲嘴嘶噜噤器噬嚎嚼囊囚四回因团囤园困围固国图圆"
+ "隆随隐障难雄集雪需静非靠面音页顶项顺须顿预题颜风飞首验骰高魔鹏" + "圈團土圣在地场圾均坊坍坎坏坐坑块坚坛坝坞坟坠坤坦坪坷垂垃型"
+ "黑默鼠!(),:?"; + "垒垛垠垢垣垦埃埋城域培基堂堆堕堡堤堪堰塌塑塔塘塞填境墓墙增"
+ "墟墨壁壅壕壤士壬壮声壳壶处备复夏外多夜够大天太夫央失头夷夸"
+ "夹夺奇奈奉奋奎契奔奖套奢奥女奴她好如妃妄妆妇妈妖妙妥妪妮妲"
+ "妹姆姊始姓姜姥姬姿威娃娅娜婆婉婪婶媒嫁嫩嬉子孑孔孕字存孚孢"
+ "季孤学孪孳孵孽宁它宅宇守安完宏宗官宙定宜宝实宠审客宣室宪宫"
+ "宰害宴家容宾宿寂寄密寇富寒寓寝察寡寨寰寸对寺寻导封射将尉尊"
+ "小少尔尖尘尚尝尤尬就尸尹尺尼尽尾局层居屈屋屏屑展属屠履屯山"
+ "屹岁岑岔岖岗岚岛岩岱岳岸峡峭峰峻崇崎崔崖崩崽嵌巅巍川巡巢工"
+ "左巧巨巫差己已巳巴巷币市布帅帆师希帕帖帘帜帝带席帮帷常帽幅"
+ "幔幕干平年并幸幻幼幽广庄庆庇床序库应底店庙府庞废度座庭庶廉"
+ "廊延建开异弃弄弊式弑弓引弗弘弟张弥弦弧弩弯弱張弹强归当录彗"
+ "形彩彰影役彻彼往征径待很徊律後徒徕得徘徙從御復循微徵德徽心"
+ "必忆忌忍忒志忘忠忧快忱念忽忾忿怀态怒怖思急性怨怪怯总恍恐恒"
+ "恕恢恣恨恩恫息恰恳恶恸恼悉悍悔悖悟患悦您悬悯悲悼情惊惑惘惚"
+ "惠惧惨惩惫惰想惹愁愈愎意愚感愣愤愧愿慈慌慎慑慕慢慧慨慰慷憎"
+ "憩懦戈戏成我戒戕或战戟截戮戳戴户戾房所扁扇扈手才扎扑扒打托"
+ "扣执扩扫扬扭扮扯扰找承技抄抉把抑抓投抖抗折抚抛抢护报披抱抵"
+ "抹押抽拂拆拉拍拒拓拔拖拘招拜拟拣拥拦拧拨择括拯拱拳拷拼拽拾"
+ "拿持挂指按挑挖挚挟挠挡挣挥挪挫振挺挽捆捉捍捕捞损换捣捧据捷"
+ "捻掀授掉掌掐排掘掠探接控推掩措掮掳掷揍描提插握揭援揽搁搅搏"
+ "搐搜搞搬搭携摄摆摇摘摧摩摸摹撒撕撞撤撬播撵撼擅操擎擒擞擦攀"
+ "攫支收改攻放政故效敌敏救敕教敞敢散敦敬数敲整文斐斑斓斗斤斥"
+ "斧斩断斯新方施旁旅旋族旗无既日旧旨早旭时旷旸旺昂昆昌明昏易"
+ "昔昙星映春昨昭是昵昼显晃晋晓晕晖晚晨普景晰晴晶晷智暂暗暮暴"
+ "曙曜曝曦曲曳更曼曾替最月有服朗望朝期木未末本札术朵机朽杀杂"
+ "权杉李村杖杜束条来杨杯杰松板极构析林枚果枝枢枪枭枯架枷柄柏"
+ "某染柜查柩柯柱柳栅标栈栋栏树栓栖栗株样核根格栽桂框案桌桎桑"
+ "桓桠档桥桨桩桶梁梅梓梢梣梦梧梨梭梯械检棄棍棒棕棘棚森棱棺椁"
+ "植椎椒椽楂楔楚楣楼概榄榆榔榨榴槌槛模横樱樵橇橡橫檀檐次欢欣"
+ "欧欲欺歇歌止正此步武歪死歼殁殆殇殉殊残殍殒殓殖殡殴段殷殿毁"
+ "毅母每毒比毕毛毡氅氏民氓气氤氦氧氲水永汀汁求汇汉汐汗汛池污"
+ "汤汨汪汰汲汹汽沃沈沉沌沐沙沟没沥沦沮河沸油治沼沾沿泄泉泊法"
+ "泛泞泡波泣泥注泪泯泰泽洁洋洒洗洛洞津洪洲活洼派流浅浆浇浊测"
+ "济浑浓浚浩浪浮浴海浸涅消涉涌涎涛涟涡涤润涨涩液涵淋淘淤淬深"
+ "混淹添清渊渎渐渔渗渝渠渡渣渥温港渲渴游湍湖湛湮湾湿溃溅源溜"
+ "溢溪溯溶溺滋滑滓滔滚滞满滤滥滨滴漂漏演漠漩漫潘潜潭潮澄澈澹"
+ "激濑濒瀑瀚灌火灭灯灰灵灼灾灿炉炎炙炫炬炭炮炸点炼炽烁烂烈烙"
+ "烛烟烤烦烧烫烬热烽焉焊焚焦焰然煌煎煞煤照煮煽熄熊熏熔熟熠熵"
+ "燃燎燕燧爆爪爬爱爵父片版牌牒牙牛牝牡牢牦牧物牲牵特牺犀犁犄"
+ "犧犬犯状狂狄狈狐狗狙狞狡狩独狭狮狰狱狷狸狼猁猎猛猜猪猫献猴"
+ "猿獒獠獾玄率玉王玖玛玩玫环现玷玻珀珂珊珍珠班球理琉琐琥琳琴"
+ "琵琼瑕瑙瑚瑞瑟瑰璃璞璧瓜瓣瓦瓮瓯瓶瓷甘生用甩甫田由甲电画畅"
+ "界畏留略畸畿疆疏疑疗疚疡疣疤疫疮疯疲疵疹疽疾病症痕痛痞痢痨"
+ "痪痴痹瘟瘠瘤瘫瘴癣癫癸登白百的皆皇皈皮皱皿盆盈盐监盒盔盖盗"
+ "盘盛盟目盲直相盾省看真眠眨眩眷眺眼着睁睡督睥睨睿瞄瞒瞥瞪瞬"
+ "瞭瞰瞳矛矢知矫短矮石矾矿码砂砍研砖砦砧破砸砾础硕硫硬确碍碎"
+ "碑碟碧碰碳碻碾磁磊磨磷磺礁示礼社祀祈祖祝神祟祠祥票祭祷祸禁"
+ "禄福离禽私秃秉秋种科秘秣秤秩积称移秽稀程税稚稳稻穆穗穴究穷"
+ "穹空穿突窃窍窒窖窗窘窜窝窟窥立竖站竞章童竭端竹笏笑笔笛笞符"
+ "第笼等筑筒答策筛筝筹签简箔算箝管箭箱篓篮篱篷簇簧簪米类粉粒"
+ "粗粮粹精糊糙糟系素索紧紫累繁纂纠红约级纪纬纯纱纳纵纷纸纹纺"
+ "纽线练组绅细织终绊绍经绒结绕绘给绚络绝绞统绥继绩绪续绮绯绳"
+ "维绵综绽绿缀缄缅缆缇缉缎缓缕编缘缚缝缠缩缪缰缸缺罅网罔罗罚"
+ "罡罩罪置羁羊美羚羞群羽翁翅翎翔翠翡翰翱翻翼耀老考者而耍耐耕"
+ "耗耘耙耳耶职联聚聪肃肆肇肉肌肖肝肠肢肤肥肩肯育肴肺肿胀胁胃"
+ "胆背胎胖胜胞胡胧胫胶胸能脂脆脉脊脏脑脓脚脱脸腐腔腕腥腱腹腾"
+ "腿膂膏膛膜膝臂臃臣自臭至致舌舍舒舞舟航般舰舱船艇良艰色艺艾"
+ "节芒芙芜芥芬芭芮花芳芽苇苍苏苔苗苛苜苟若苦英茁茂范茉茎茜茧"
+ "茨茫茸荆草荒荚荡荣荨荫药荷莉莎莓莫莱莲莳获莽菁菇菊菌菜菲萃"
+ "萌萍萎萝营萦萧萨萼落著葛葬葵蒂蒙蒸蓄蓑蓝蓟蓿蔑蔓蔚蔷蔻蔽蕈"
+ "蕊蕨蕴蕾薄薇薙薪藏藐藓藤藻虎虏虐虑虔虚虫虱虹蚀蚁蚊蚋蚣蚺蛆"
+ "蛇蛊蛋蛎蛙蛛蛞蛭蛮蛰蛸蛾蜂蜈蜉蜒蜕蜗蜘蜜蜡蜥蜴蜷蜿蝇蝎蝓蝗"
+ "蝙蝠蝣蝾螂螅融螫螳螺蟀蟋蟑蟒蟹蠕蠢血行衍街衡衣补表衫衰袂袋"
+ "袍袖被袭裁裂装裔裘褐褛褪褫褴褶襄西要覆见观规觅视览觉觊角解"
+ "触言詹誉誓警计认讧讨让训议讯记讲许论讽设访诀证评诅识诈诉词"
+ "试诗诘诚诛话诞诡该详诫语误诱诲说诵请诸诺读调谆谈谊谋谍谐谕"
+ "谗谜谟谢谣谦谧谨谬谭谱谴谵谷豁象豪豹豺貂貌贝贞负贡财责贤败"
+ "货质贩贪贫贬购贮贯贱贴贵贷贸费贺贼贾贿赂赃资赋赌赎赏赐赖赘"
+ "赛赞赠赢赤赦赫走赶起超越趋足跃跑跖跚跛距跟跨路跳践跺踏踝踢"
+ "踩踪踵踽蹂蹄蹊蹋蹒蹦蹬躁躏身躯躲車车轨轩转轭轮软轰轴轻载较"
+ "辉辑输辖辗辙辛辜辞辟辨辩辫辰辱边达迁迂迅过迈迎运近返还这进"
+ "远违连迟迦迩迪迫迭述迳迷迸迹追退送适逃逆选逊透逐递途通逝逞"
+ "速造逢逮逸逻逼遁遇遍遏道遗遣遥遨遭遮避邀還那邦邪邬邸郊郎部"
+ "都鄙酋配酒酬酷酸酿醉醒采釉释里重野量金鉴针钉钓钗钙钜钝钟钢"
+ "钥钦钨钩钮钯钱钳钵钻钽铁铃铅铎铜铠铬铭铲银铸铺链销锁锄锅锈"
+ "锋锐错锡锢锤锥锦锭键锯锻镇镖镜镬镰镶长間闇门闩闪闭问闯闲间"
+ "闷闸闹闻阀阁阅队阱防阳阴阵阶阻阿陀附际陆陋降限院除陨险陪陲"
+ "陵陶陷隆随隐隔隘障隧隶隼难雀雄雅集雇雏雕雨雪雯雳零雷雹雾需"
+ "霆震霉霍霓霖霜霞霰露霸霹青靖静非靠靡面革靴靶鞍鞑鞭韧音韵韶"
+ "页顶项顺须顽顾顿颂预颅领颈颊题颚颜额颠颤风飒飓飘飙飞食餍餐"
+ "餮饕饥饭饮饰饱饵饶饿馆馈馐馑首香馨马驭驮驯驰驱驳驹驻驼驽驾"
+ "驿骁骂骄骆骇验骏骐骑骗骚骤骨骰骷骸骼髅髓高鬃鬓鬣鬼魁魂魄魅"
+ "魇魈魏魔鰴鱼鲁鲜鲤鲨鲮鲸鲽鳃鳄鳍鳐鳗鳝鳞鸟鸠鸡鸢鸣鸦鸽鹅鹉"
+ "鹊鹏鹗鹞鹤鹦鹫鹭鹰鹿麋麒麟麦麻黄黎黏黑默黛黜點黠黯鼎鼓鼠鼬"
+ "齿龇龙龟";
final PixmapPacker packer = new PixmapPacker(pageSize, pageSize, Pixmap.Format.RGBA8888, 2, false); final PixmapPacker packer = new PixmapPacker(pageSize, pageSize, Pixmap.Format.RGBA8888, 2, false);
final FreeTypeFontParameter parameter = new FreeTypeFontParameter(); final FreeTypeFontParameter parameter = new FreeTypeFontParameter();
parameter.characters = chars; parameter.characters = chars;

View File

@@ -183,7 +183,7 @@ public class CardImageRenderer {
//draw name for card //draw name for card
x += padding; x += padding;
w -= 2 * padding; w -= 2 * padding;
g.drawText(state.getName(), NAME_FONT, Color.BLACK, x, y, w - manaCostWidth - padding, h, false, Align.left, true); g.drawText(CardTranslation.getTranslatedName(state.getName()), NAME_FONT, Color.BLACK, x, y, w - manaCostWidth - padding, h, false, Align.left, true);
} }
public static final FBufferedImage forgeArt; public static final FBufferedImage forgeArt;
@@ -260,7 +260,7 @@ public class CardImageRenderer {
g.drawImage(image, x + (w - iconSize) / 2, y + (h - iconSize) / 2, iconSize, iconSize); g.drawImage(image, x + (w - iconSize) / 2, y + (h - iconSize) / 2, iconSize, iconSize);
} }
else { else {
final String text = card.getText(state); final String text = card.getText(state, CardTranslation.getTranslationTexts(state.getName(), ""));
if (StringUtils.isEmpty(text)) { return; } if (StringUtils.isEmpty(text)) { return; }
float padding = TEXT_FONT.getCapHeight() * 0.75f; float padding = TEXT_FONT.getCapHeight() * 0.75f;

View File

@@ -255,7 +255,7 @@ public class CardRenderer {
state.getLoyalty(), count, suffix, x, y, w, h, compactMode); state.getLoyalty(), count, suffix, x, y, w, h, compactMode);
} }
else { //if fake card, just draw card name centered else { //if fake card, just draw card name centered
String name = state.getName(); String name = CardTranslation.getTranslatedName(state.getName());
if (count > 0) { //preface name with count if applicable if (count > 0) { //preface name with count if applicable
name = count + " " + name; name = count + " " + name;
} }
@@ -317,7 +317,7 @@ public class CardRenderer {
CardFaceSymbols.drawManaCost(g, mainManaCost, x + w - manaCostWidth, y, MANA_SYMBOL_SIZE); CardFaceSymbols.drawManaCost(g, mainManaCost, x + w - manaCostWidth, y, MANA_SYMBOL_SIZE);
x += cardArtWidth; x += cardArtWidth;
String name = card.getCurrentState().getName(); String name = CardTranslation.getTranslatedName(card.getCurrentState().getName());
if (count > 0) { //preface name with count if applicable if (count > 0) { //preface name with count if applicable
name = count + " " + name; name = count + " " + name;
} }
@@ -448,7 +448,7 @@ public class CardRenderer {
//draw name and mana cost overlays if card is small or default card image being used //draw name and mana cost overlays if card is small or default card image being used
if (h <= NAME_COST_THRESHOLD && canShow) { if (h <= NAME_COST_THRESHOLD && canShow) {
if (showCardNameOverlay(card)) { if (showCardNameOverlay(card)) {
g.drawOutlinedText(details.getName(), FSkinFont.forHeight(h * 0.18f), Color.WHITE, Color.BLACK, x + padding, y + padding, w - 2 * padding, h * 0.4f, true, Align.left, false); g.drawOutlinedText(CardTranslation.getTranslatedName(details.getName()), FSkinFont.forHeight(h * 0.18f), Color.WHITE, Color.BLACK, x + padding, y + padding, w - 2 * padding, h * 0.4f, true, Align.left, false);
} }
if (showCardManaCostOverlay(card)) { if (showCardManaCostOverlay(card)) {
float manaSymbolSize = w / 4; float manaSymbolSize = w / 4;
@@ -558,39 +558,37 @@ public class CardRenderer {
} }
//if (counterBoxBaseWidth + font.getBounds(String.valueOf(maxCounters)).width > w) { //if (counterBoxBaseWidth + font.getBounds(String.valueOf(maxCounters)).width > w) {
layout.setText(font, String.valueOf(maxCounters)); if(font != null && !String.valueOf(maxCounters).isEmpty()){
layout.setText(font, String.valueOf(maxCounters));
if (counterBoxBaseWidth + layout.width > w) { if (counterBoxBaseWidth + layout.width > w) {
drawCounterImage(card, g, x, y, w, h);
drawCounterImage(card, g, x, y, w, h); return;
return; }
} }
} }
for (Map.Entry<CounterType, Integer> counterEntry : card.getCounters().entrySet()) { for (Map.Entry<CounterType, Integer> counterEntry : card.getCounters().entrySet()) {
final CounterType counter = counterEntry.getKey(); final CounterType counter = counterEntry.getKey();
final int numberOfCounters = counterEntry.getValue(); final int numberOfCounters = counterEntry.getValue();
//final float counterBoxRealWidth = counterBoxBaseWidth + font.getBounds(String.valueOf(numberOfCounters)).width + 4; //final float counterBoxRealWidth = counterBoxBaseWidth + font.getBounds(String.valueOf(numberOfCounters)).width + 4;
layout.setText(font, String.valueOf(numberOfCounters)); if(font != null && !String.valueOf(numberOfCounters).isEmpty()){
final float counterBoxRealWidth = counterBoxBaseWidth + layout.width + 4; layout.setText(font, String.valueOf(numberOfCounters));
final float counterBoxRealWidth = counterBoxBaseWidth + layout.width + 4;
final float counterYOffset = spaceFromTopOfCard - (currentCounter++ * (counterBoxHeight + counterBoxSpacing)); final float counterYOffset = spaceFromTopOfCard - (currentCounter++ * (counterBoxHeight + counterBoxSpacing));
g.fillRect(counterBackgroundColor, x - 3, counterYOffset, counterBoxRealWidth, counterBoxHeight); g.fillRect(counterBackgroundColor, x - 3, counterYOffset, counterBoxRealWidth, counterBoxHeight);
if (!counterColorCache.containsKey(counter)) { if (!counterColorCache.containsKey(counter)) {
counterColorCache.put(counter, new Color(counter.getRed() / 255.0f, counter.getGreen() / 255.0f, counter.getBlue() / 255.0f, 1.0f)); counterColorCache.put(counter, new Color(counter.getRed() / 255.0f, counter.getGreen() / 255.0f, counter.getBlue() / 255.0f, 1.0f));
}
Color counterColor = counterColorCache.get(counter);
drawText(g, counter.getCounterOnCardDisplayName(), font, counterColor, x + 2 + additionalXOffset, counterYOffset, counterBoxRealWidth, counterBoxHeight, Align.left);
drawText(g, String.valueOf(numberOfCounters), font, counterColor, x + counterBoxBaseWidth - 4f - additionalXOffset, counterYOffset, counterBoxRealWidth, counterBoxHeight, Align.left);
} }
Color counterColor = counterColorCache.get(counter);
drawText(g, counter.getCounterOnCardDisplayName(), font, counterColor, x + 2 + additionalXOffset, counterYOffset, counterBoxRealWidth, counterBoxHeight, Align.left);
drawText(g, String.valueOf(numberOfCounters), font, counterColor, x + counterBoxBaseWidth - 4f - additionalXOffset, counterYOffset, counterBoxRealWidth, counterBoxHeight, Align.left);
} }
} }
private static final int GL_BLEND = GL20.GL_BLEND; private static final int GL_BLEND = GL20.GL_BLEND;
@@ -600,22 +598,22 @@ public class CardRenderer {
if (color.a < 1) { //enable blending so alpha colored shapes work properly if (color.a < 1) { //enable blending so alpha colored shapes work properly
Gdx.gl.glEnable(GL_BLEND); Gdx.gl.glEnable(GL_BLEND);
} }
if(font != null && !text.isEmpty()) {
layout.setText(font, text);
TextBounds textBounds = new TextBounds(layout.width, layout.height);
layout.setText(font, text); float textHeight = textBounds.height;
TextBounds textBounds = new TextBounds(layout.width, layout.height); if (h > textHeight) {
y += (h - textHeight) / 2;
}
float textHeight = textBounds.height; font.setColor(color);
if (h > textHeight) { font.draw(g.getBatch(), text, g.adjustX(x), g.adjustY(y, 0), w, horizontalAlignment, true);
y += (h - textHeight) / 2;
if (color.a < 1) {
Gdx.gl.glDisable(GL_BLEND);
}
} }
font.setColor(color);
font.draw(g.getBatch(), text, g.adjustX(x), g.adjustY(y, 0), w, horizontalAlignment, true);
if (color.a < 1) {
Gdx.gl.glDisable(GL_BLEND);
}
} }
private static void drawCounterImage(final CardView card, final Graphics g, final float x, final float y, final float w, final float h) { private static void drawCounterImage(final CardView card, final Graphics g, final float x, final float y, final float w, final float h) {

View File

@@ -36,6 +36,7 @@ import forge.toolbox.ListChooser;
import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FOptionPane; import forge.toolbox.FOptionPane;
import forge.util.Callback; import forge.util.Callback;
import forge.util.Localizer;
import forge.util.Utils; import forge.util.Utils;
import forge.util.storage.IStorage; import forge.util.storage.IStorage;
@@ -63,10 +64,10 @@ public class FDeckChooser extends FScreen {
private boolean refreshingDeckType; private boolean refreshingDeckType;
private final DeckManager lstDecks; private final DeckManager lstDecks;
private final FButton btnNewDeck = new FButton("New Deck"); private final FButton btnNewDeck = new FButton(Localizer.getInstance().getMessage("lblNewDeck"));
private final FButton btnEditDeck = new FButton("Edit Deck"); private final FButton btnEditDeck = new FButton(Localizer.getInstance().getMessage("btnEditDeck"));
private final FButton btnViewDeck = new FButton("View Deck"); private final FButton btnViewDeck = new FButton(Localizer.getInstance().getMessage("lblViewDeck"));
private final FButton btnRandom = new FButton("Random Deck"); private final FButton btnRandom = new FButton(Localizer.getInstance().getMessage("lblRandomDeck"));
private RegisteredPlayer player; private RegisteredPlayer player;
private boolean isAi; private boolean isAi;

View File

@@ -36,6 +36,7 @@ import forge.toolbox.FEvent.FEventType;
import forge.util.Callback; import forge.util.Callback;
import forge.util.ItemPool; import forge.util.ItemPool;
import forge.util.Lang; import forge.util.Lang;
import forge.util.Localizer;
import forge.util.Utils; import forge.util.Utils;
import forge.util.storage.IStorage; import forge.util.storage.IStorage;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -163,6 +164,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
private static DeckEditorPage[] getPages(EditorType editorType) { private static DeckEditorPage[] getPages(EditorType editorType) {
final Localizer localizer = Localizer.getInstance();
switch (editorType) { switch (editorType) {
default: default:
case Constructed: case Constructed:
@@ -195,7 +197,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
return new DeckEditorPage[] { return new DeckEditorPage[] {
new CatalogPage(ItemManagerConfig.CARD_CATALOG), new CatalogPage(ItemManagerConfig.CARD_CATALOG),
new DeckSectionPage(DeckSection.Main), new DeckSectionPage(DeckSection.Main),
new DeckSectionPage(DeckSection.Commander, ItemManagerConfig.OATHBREAKER_SECTION, "Oathbreaker", FSkinImage.COMMANDER), new DeckSectionPage(DeckSection.Commander, ItemManagerConfig.OATHBREAKER_SECTION, localizer.getMessage("lblOathbreaker"), FSkinImage.COMMANDER),
new DeckSectionPage(DeckSection.Sideboard) new DeckSectionPage(DeckSection.Sideboard)
}; };
case Archenemy: case Archenemy:
@@ -210,7 +212,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
}; };
case Quest: case Quest:
return new DeckEditorPage[] { return new DeckEditorPage[] {
new CatalogPage(ItemManagerConfig.QUEST_EDITOR_POOL, "Inventory", FSkinImage.QUEST_BOX), new CatalogPage(ItemManagerConfig.QUEST_EDITOR_POOL, localizer.getMessage("lblInventory"), FSkinImage.QUEST_BOX),
new DeckSectionPage(DeckSection.Main, ItemManagerConfig.QUEST_DECK_EDITOR), new DeckSectionPage(DeckSection.Main, ItemManagerConfig.QUEST_DECK_EDITOR),
new DeckSectionPage(DeckSection.Sideboard, ItemManagerConfig.QUEST_DECK_EDITOR) new DeckSectionPage(DeckSection.Sideboard, ItemManagerConfig.QUEST_DECK_EDITOR)
}; };
@@ -222,8 +224,8 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
}; };
case PlanarConquest: case PlanarConquest:
return new DeckEditorPage[] { return new DeckEditorPage[] {
new CatalogPage(ItemManagerConfig.CONQUEST_COLLECTION, "Collection", FSkinImage.SPELLBOOK), new CatalogPage(ItemManagerConfig.CONQUEST_COLLECTION, localizer.getMessage("lblCollection"), FSkinImage.SPELLBOOK),
new DeckSectionPage(DeckSection.Main, ItemManagerConfig.CONQUEST_DECK_EDITOR, "Deck", FSkinImage.DECKLIST), new DeckSectionPage(DeckSection.Main, ItemManagerConfig.CONQUEST_DECK_EDITOR, localizer.getMessage("lblDeck"), FSkinImage.DECKLIST),
new DeckSectionPage(DeckSection.Commander, ItemManagerConfig.COMMANDER_SECTION) new DeckSectionPage(DeckSection.Commander, ItemManagerConfig.COMMANDER_SECTION)
}; };
} }
@@ -334,7 +336,9 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
FPopupMenu menu = new FPopupMenu() { FPopupMenu menu = new FPopupMenu() {
@Override @Override
protected void buildMenu() { protected void buildMenu() {
addItem(new FMenuItem("Add Basic Lands", FSkinImage.LAND, new FEventHandler() { final Localizer localizer = Localizer.getInstance();
addItem(new FMenuItem(localizer.getMessage("lblAddBasicLands"), FSkinImage.LAND, new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
CardEdition defaultLandSet; CardEdition defaultLandSet;
@@ -367,7 +371,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
})); }));
if (!isLimitedEditor()) { if (!isLimitedEditor()) {
addItem(new FMenuItem("Import from Clipboard", FSkinImage.OPEN, new FEventHandler() { addItem(new FMenuItem(localizer.getMessage("lblImportFromClipboard"), FSkinImage.OPEN, new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
FDeckImportDialog dialog = new FDeckImportDialog(!deck.isEmpty(), new Callback<Deck>() { FDeckImportDialog dialog = new FDeckImportDialog(!deck.isEmpty(), new Callback<Deck>() {
@@ -386,11 +390,11 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
setSelectedPage(getMainDeckPage()); //select main deck page if needed so main deck if visible below dialog setSelectedPage(getMainDeckPage()); //select main deck page if needed so main deck if visible below dialog
} }
})); }));
addItem(new FMenuItem("Save As...", FSkinImage.SAVEAS, new FEventHandler() { addItem(new FMenuItem(localizer.getMessage("lblSaveAs"), FSkinImage.SAVEAS, new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
String defaultName = editorType.getController().getNextAvailableName(); String defaultName = editorType.getController().getNextAvailableName();
FOptionPane.showInputDialog("Enter name for new copy of deck", defaultName, new Callback<String>() { FOptionPane.showInputDialog(localizer.getMessage("lblNameNewCopyDeck"), defaultName, new Callback<String>() {
@Override @Override
public void run(String result) { public void run(String result) {
if (!StringUtils.isEmpty(result)) { if (!StringUtils.isEmpty(result)) {
@@ -402,10 +406,10 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
})); }));
} }
if (allowRename()) { if (allowRename()) {
addItem(new FMenuItem("Rename Deck", FSkinImage.EDIT, new FEventHandler() { addItem(new FMenuItem(localizer.getMessage("lblRenameDeck"), FSkinImage.EDIT, new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
FOptionPane.showInputDialog("Enter new name for deck", deck.getName(), new Callback<String>() { FOptionPane.showInputDialog(localizer.getMessage("lblNewNameDeck"), deck.getName(), new Callback<String>() {
@Override @Override
public void run(String result) { public void run(String result) {
editorType.getController().rename(result); editorType.getController().rename(result);
@@ -415,12 +419,12 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
})); }));
} }
if (allowDelete()) { if (allowDelete()) {
addItem(new FMenuItem("Delete Deck", FSkinImage.DELETE, new FEventHandler() { addItem(new FMenuItem(localizer.getMessage("lblDeleteDeck"), FSkinImage.DELETE, new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
FOptionPane.showConfirmDialog( FOptionPane.showConfirmDialog(
"Are you sure you want to delete '" + deck.getName() + "'?", localizer.getMessage("lblConfirmDelete") + " '" + deck.getName() + "'?",
"Delete Deck", "Delete", "Cancel", false, new Callback<Boolean>() { localizer.getMessage("lblDeleteDeck"), localizer.getMessage("lblDelete"), localizer.getMessage("lblCancel"), false, new Callback<Boolean>() {
@Override @Override
public void run(Boolean result) { public void run(Boolean result) {
if (result) { if (result) {
@@ -432,7 +436,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
})); }));
} }
addItem(new FMenuItem("Copy to Clipboard", new FEventHandler() { addItem(new FMenuItem(localizer.getMessage("btnCopyToClipboard"), new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
FDeckViewer.copyDeckToClipboard(deck); FDeckViewer.copyDeckToClipboard(deck);
@@ -538,7 +542,8 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
if (StringUtils.isEmpty(deck.getName())) { if (StringUtils.isEmpty(deck.getName())) {
List<PaperCard> commanders = deck.getCommanders(); //use commander name as default deck name List<PaperCard> commanders = deck.getCommanders(); //use commander name as default deck name
String initialInput = Lang.joinHomogenous(commanders); String initialInput = Lang.joinHomogenous(commanders);
FOptionPane.showInputDialog("Enter name for new deck", initialInput, new Callback<String>() { final Localizer localizer = Localizer.getInstance();
FOptionPane.showInputDialog(localizer.getMessage("lblNameNewDeck"), initialInput, new Callback<String>() {
@Override @Override
public void run(String result) { public void run(String result) {
if (StringUtils.isEmpty(result)) { return; } if (StringUtils.isEmpty(result)) { return; }
@@ -566,7 +571,8 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
super.onClose(canCloseCallback); //can skip prompt if draft saved super.onClose(canCloseCallback); //can skip prompt if draft saved
return; return;
} }
FOptionPane.showOptionDialog("Save changes to current deck?", "", final Localizer localizer = Localizer.getInstance();
FOptionPane.showOptionDialog(localizer.getMessage("lblSaveChangesCurrentDeck"), "",
FOptionPane.QUESTION_ICON, onCloseOptions, new Callback<Integer>() { FOptionPane.QUESTION_ICON, onCloseOptions, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
@@ -828,7 +834,8 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
callback.run(max); callback.run(max);
} }
else { else {
GuiChoose.getInteger(cardManager.getSelectedItem() + " - " + verb + " how many?", 1, max, 20, callback); final Localizer localizer = Localizer.getInstance();
GuiChoose.getInteger(cardManager.getSelectedItem() + " - " + verb + " " + localizer.getMessage("lblHowMany"), 1, max, 20, callback);
} }
} }
})); }));
@@ -962,7 +969,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
private boolean initialized, needRefreshWhenShown; private boolean initialized, needRefreshWhenShown;
protected CatalogPage(ItemManagerConfig config) { protected CatalogPage(ItemManagerConfig config) {
this(config, "Catalog", FSkinImage.FOLDER); this(config, Localizer.getInstance().getMessage("lblCatalog"), FSkinImage.FOLDER);
} }
protected CatalogPage(ItemManagerConfig config, String caption0, FImage icon0) { protected CatalogPage(ItemManagerConfig config, String caption0, FImage icon0) {
super(config, caption0, icon0); super(config, caption0, icon0);
@@ -993,13 +1000,14 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
protected String getItemManagerCaption() { protected String getItemManagerCaption() {
final Localizer localizer = Localizer.getInstance();
switch (parentScreen.getEditorType()) { switch (parentScreen.getEditorType()) {
case Archenemy: case Archenemy:
return "Schemes"; return localizer.getMessage("lblSchemes");
case Planechase: case Planechase:
return "Planes"; return localizer.getMessage("lblPlanes");
default: default:
return "Cards"; return localizer.getMessage("lblCards");
} }
} }
@@ -1018,6 +1026,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
public void refresh() { public void refresh() {
Predicate<PaperCard> additionalFilter = null; Predicate<PaperCard> additionalFilter = null;
final EditorType editorType = parentScreen.getEditorType(); final EditorType editorType = parentScreen.getEditorType();
final Localizer localizer = Localizer.getInstance();
switch (editorType) { switch (editorType) {
case Archenemy: case Archenemy:
cardManager.setPool(ItemPool.createFrom(FModel.getMagicDb().getVariantCards().getAllCards(Predicates.compose(CardRulesPredicates.Presets.IS_SCHEME, PaperCard.FN_GET_RULES)), PaperCard.class), true); cardManager.setPool(ItemPool.createFrom(FModel.getMagicDb().getVariantCards().getAllCards(Predicates.compose(CardRulesPredicates.Presets.IS_SCHEME, PaperCard.FN_GET_RULES)), PaperCard.class), true);
@@ -1047,19 +1056,19 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
switch (editorType) { switch (editorType) {
case Commander: case Commander:
additionalFilter = DeckFormat.Commander.isLegalCommanderPredicate(); additionalFilter = DeckFormat.Commander.isLegalCommanderPredicate();
cardManager.setCaption("Commanders"); cardManager.setCaption(localizer.getMessage("lblCommanders"));
break; break;
case Oathbreaker: case Oathbreaker:
additionalFilter = DeckFormat.Oathbreaker.isLegalCommanderPredicate(); additionalFilter = DeckFormat.Oathbreaker.isLegalCommanderPredicate();
cardManager.setCaption("Oathbreakers"); cardManager.setCaption(localizer.getMessage("lblOathbreakers"));
break; break;
case TinyLeaders: case TinyLeaders:
additionalFilter = DeckFormat.TinyLeaders.isLegalCommanderPredicate(); additionalFilter = DeckFormat.TinyLeaders.isLegalCommanderPredicate();
cardManager.setCaption("Commanders"); cardManager.setCaption(localizer.getMessage("lblCommanders"));
break; break;
case Brawl: case Brawl:
additionalFilter = DeckFormat.Brawl.isLegalCommanderPredicate(); additionalFilter = DeckFormat.Brawl.isLegalCommanderPredicate();
cardManager.setCaption("Commanders"); cardManager.setCaption(localizer.getMessage("lblCommanders"));
break; break;
default: default:
// Do nothing // Do nothing
@@ -1083,7 +1092,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
default: default:
// Do nothing // Do nothing
} }
cardManager.setCaption("Cards"); cardManager.setCaption(localizer.getMessage("lblCards"));
} }
// fall through to below // fall through to below
default: default:
@@ -1117,8 +1126,10 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
@Override @Override
protected void buildMenu(final FDropDownMenu menu, final PaperCard card) { protected void buildMenu(final FDropDownMenu menu, final PaperCard card) {
final Localizer localizer = Localizer.getInstance();
if (!needsCommander() && !canOnlyBePartnerCommander(card)) { if (!needsCommander() && !canOnlyBePartnerCommander(card)) {
addItem(menu, "Add", "to " + parentScreen.getMainDeckPage().cardManager.getCaption(), parentScreen.getMainDeckPage().getIcon(), true, true, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblAdd"), localizer.getMessage("lblTo") + " " + parentScreen.getMainDeckPage().cardManager.getCaption(), parentScreen.getMainDeckPage().getIcon(), true, true, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { return; } if (result == null || result <= 0) { return; }
@@ -1130,7 +1141,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
}); });
if (parentScreen.getSideboardPage() != null) { if (parentScreen.getSideboardPage() != null) {
addItem(menu, "Add", "to Sideboard", parentScreen.getSideboardPage().getIcon(), true, true, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblAdd"), localizer.getMessage("lbltosideboard"), parentScreen.getSideboardPage().getIcon(), true, true, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { return; } if (result == null || result <= 0) { return; }
@@ -1150,7 +1161,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
//add option to add or remove card from favorites //add option to add or remove card from favorites
final CardPreferences prefs = CardPreferences.getPrefs(card); final CardPreferences prefs = CardPreferences.getPrefs(card);
if (prefs.getStarCount() == 0) { if (prefs.getStarCount() == 0) {
menu.addItem(new FMenuItem("Add to Favorites", FSkinImage.STAR_FILLED, new FEventHandler() { menu.addItem(new FMenuItem(localizer.getMessage("lblAddFavorites"), FSkinImage.STAR_FILLED, new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
prefs.setStarCount(1); prefs.setStarCount(1);
@@ -1159,7 +1170,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
})); }));
} }
else { else {
menu.addItem(new FMenuItem("Remove from Favorites", FSkinImage.STAR_OUTINE, new FEventHandler() { menu.addItem(new FMenuItem(localizer.getMessage("lblRemoveFavorites"), FSkinImage.STAR_OUTINE, new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
prefs.setStarCount(0); prefs.setStarCount(0);
@@ -1171,7 +1182,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
//if card has more than one art option, add item to change user's preferred art //if card has more than one art option, add item to change user's preferred art
final List<PaperCard> artOptions = FModel.getMagicDb().getCommonCards().getAllCards(card.getName()); final List<PaperCard> artOptions = FModel.getMagicDb().getCommonCards().getAllCards(card.getName());
if (artOptions != null && artOptions.size() > 1) { if (artOptions != null && artOptions.size() > 1) {
menu.addItem(new FMenuItem("Change Preferred Art", FSkinImage.SETTINGS, new FEventHandler() { menu.addItem(new FMenuItem(localizer.getMessage("lblChangePreferredArt"), FSkinImage.SETTINGS, new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
//sort options so current option is on top and selected by default //sort options so current option is on top and selected by default
@@ -1182,7 +1193,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
sortedOptions.add(option); sortedOptions.add(option);
} }
} }
GuiChoose.oneOrNone("Select preferred art for " + card.getName(), sortedOptions, new Callback<PaperCard>() { GuiChoose.oneOrNone(localizer.getMessage("lblSelectPreferredArt") + " " + card.getName(), sortedOptions, new Callback<PaperCard>() {
@Override @Override
public void run(PaperCard result) { public void run(PaperCard result) {
if (result != null) { if (result != null) {
@@ -1203,7 +1214,8 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
@Override @Override
protected void buildDeckMenu(FPopupMenu menu) { protected void buildDeckMenu(FPopupMenu menu) {
if (cardManager.getConfig().getShowUniqueCardsOption()) { if (cardManager.getConfig().getShowUniqueCardsOption()) {
menu.addItem(new FCheckBoxMenuItem("Unique Cards Only", cardManager.getWantUnique(), new FEventHandler() { final Localizer localizer = Localizer.getInstance();
menu.addItem(new FCheckBoxMenuItem(localizer.getMessage("lblUniqueCardsOnly"), cardManager.getWantUnique(), new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
boolean wantUnique = !cardManager.getWantUnique(); boolean wantUnique = !cardManager.getWantUnique();
@@ -1226,37 +1238,39 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
protected DeckSectionPage(DeckSection deckSection0, ItemManagerConfig config) { protected DeckSectionPage(DeckSection deckSection0, ItemManagerConfig config) {
super(config, null, null); super(config, null, null);
final Localizer localizer = Localizer.getInstance();
deckSection = deckSection0; deckSection = deckSection0;
switch (deckSection) { switch (deckSection) {
default: default:
case Main: case Main:
captionPrefix = "Main"; captionPrefix = localizer.getMessage("lblMain");
cardManager.setCaption("Main Deck"); cardManager.setCaption(localizer.getMessage("ttMain"));
icon = MAIN_DECK_ICON; icon = MAIN_DECK_ICON;
break; break;
case Sideboard: case Sideboard:
captionPrefix = "Side"; captionPrefix = localizer.getMessage("lblSide");
cardManager.setCaption("Sideboard"); cardManager.setCaption(localizer.getMessage("lblSideboard"));
icon = SIDEBOARD_ICON; icon = SIDEBOARD_ICON;
break; break;
case Commander: case Commander:
captionPrefix = "Commander"; captionPrefix = localizer.getMessage("lblCommander");
cardManager.setCaption("Commander"); cardManager.setCaption(localizer.getMessage("lblCommander"));
icon = FSkinImage.COMMANDER; icon = FSkinImage.COMMANDER;
break; break;
case Avatar: case Avatar:
captionPrefix = "Avatar"; captionPrefix = localizer.getMessage("lblAvatar");
cardManager.setCaption("Avatar"); cardManager.setCaption(localizer.getMessage("lblAvatar"));
icon = new FTextureRegionImage(FSkin.getAvatars().get(0)); icon = new FTextureRegionImage(FSkin.getAvatars().get(0));
break; break;
case Planes: case Planes:
captionPrefix = "Planes"; captionPrefix = localizer.getMessage("lblPlanes");
cardManager.setCaption("Planes"); cardManager.setCaption(localizer.getMessage("lblPlanes"));
icon = FSkinImage.CHAOS; icon = FSkinImage.CHAOS;
break; break;
case Schemes: case Schemes:
captionPrefix = "Schemes"; captionPrefix = localizer.getMessage("lblSchemes");
cardManager.setCaption("Schemes"); cardManager.setCaption(localizer.getMessage("lblSchemes"));
icon = FSkinImage.POISON; icon = FSkinImage.POISON;
break; break;
} }
@@ -1317,10 +1331,11 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
@Override @Override
protected void buildMenu(final FDropDownMenu menu, final PaperCard card) { protected void buildMenu(final FDropDownMenu menu, final PaperCard card) {
final Localizer localizer = Localizer.getInstance();
switch (deckSection) { switch (deckSection) {
default: default:
case Main: case Main:
addItem(menu, "Add", null, FSkinImage.PLUS, true, false, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblAdd"), null, FSkinImage.PLUS, true, false, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { return; } if (result == null || result <= 0) { return; }
@@ -1335,7 +1350,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
}); });
if (!parentScreen.isLimitedEditor()) { if (!parentScreen.isLimitedEditor()) {
addItem(menu, "Remove", null, FSkinImage.MINUS, false, false, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblRemove"), null, FSkinImage.MINUS, false, false, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { return; } if (result == null || result <= 0) { return; }
@@ -1348,7 +1363,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
}); });
} }
if (parentScreen.getSideboardPage() != null) { if (parentScreen.getSideboardPage() != null) {
addItem(menu, "Move", "to Sideboard", parentScreen.getSideboardPage().getIcon(), false, false, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblMove"), localizer.getMessage("lbltosideboard"), parentScreen.getSideboardPage().getIcon(), false, false, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { return; } if (result == null || result <= 0) { return; }
@@ -1361,7 +1376,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
addCommanderItems(menu, card, false, false); addCommanderItems(menu, card, false, false);
break; break;
case Sideboard: case Sideboard:
addItem(menu, "Add", null, FSkinImage.PLUS, true, false, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblAdd"), null, FSkinImage.PLUS, true, false, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { return; } if (result == null || result <= 0) { return; }
@@ -1376,7 +1391,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
}); });
if (!parentScreen.isLimitedEditor()) { if (!parentScreen.isLimitedEditor()) {
addItem(menu, "Remove", null, FSkinImage.MINUS, false, false, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblRemove"), null, FSkinImage.MINUS, false, false, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { return; } if (result == null || result <= 0) { return; }
@@ -1388,7 +1403,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
}); });
} }
addItem(menu, "Move", "to Main Deck", parentScreen.getMainDeckPage().getIcon(), false, false, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblMove"), localizer.getMessage("lblToMainDeck"), parentScreen.getMainDeckPage().getIcon(), false, false, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { return; } if (result == null || result <= 0) { return; }
@@ -1401,7 +1416,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
break; break;
case Commander: case Commander:
if (parentScreen.editorType != EditorType.PlanarConquest || isPartnerCommander(card)) { if (parentScreen.editorType != EditorType.PlanarConquest || isPartnerCommander(card)) {
addItem(menu, "Remove", null, FSkinImage.MINUS, false, false, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblRemove"), null, FSkinImage.MINUS, false, false, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { if (result == null || result <= 0) {
@@ -1416,7 +1431,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
break; break;
case Avatar: case Avatar:
addItem(menu, "Remove", null, FSkinImage.MINUS, false, false, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblRemove"), null, FSkinImage.MINUS, false, false, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { return; } if (result == null || result <= 0) { return; }
@@ -1434,7 +1449,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
addCard(card, result); addCard(card, result);
} }
}); });
addItem(menu, "Remove", null, FSkinImage.MINUS, false, false, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblRemove"), null, FSkinImage.MINUS, false, false, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { return; } if (result == null || result <= 0) { return; }
@@ -1444,7 +1459,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
}); });
break; break;
case Planes: case Planes:
addItem(menu, "Add", null, FSkinImage.PLUS, true, false, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblAdd"), null, FSkinImage.PLUS, true, false, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { return; } if (result == null || result <= 0) { return; }
@@ -1452,7 +1467,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
addCard(card, result); addCard(card, result);
} }
}); });
addItem(menu, "Remove", null, FSkinImage.MINUS, false, false, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblRemove"), null, FSkinImage.MINUS, false, false, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { public void run(Integer result) {
if (result == null || result <= 0) { return; } if (result == null || result <= 0) { return; }
@@ -1513,14 +1528,15 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
@Override @Override
protected void buildMenu(final FDropDownMenu menu, final PaperCard card) { protected void buildMenu(final FDropDownMenu menu, final PaperCard card) {
addItem(menu, "Add", "to Main Deck", parentScreen.getMainDeckPage().getIcon(), true, true, new Callback<Integer>() { final Localizer localizer = Localizer.getInstance();
addItem(menu, localizer.getMessage("lblAdd"), localizer.getMessage("lblToMainDeck"), parentScreen.getMainDeckPage().getIcon(), true, true, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { //ignore quantity public void run(Integer result) { //ignore quantity
parentScreen.getMainDeckPage().addCard(card); parentScreen.getMainDeckPage().addCard(card);
afterCardPicked(card); afterCardPicked(card);
} }
}); });
addItem(menu, "Add", "to Sideboard", parentScreen.getSideboardPage().getIcon(), true, true, new Callback<Integer>() { addItem(menu, localizer.getMessage("lblAdd"), localizer.getMessage("lbltosideboard"), parentScreen.getSideboardPage().getIcon(), true, true, new Callback<Integer>() {
@Override @Override
public void run(Integer result) { //ignore quantity public void run(Integer result) { //ignore quantity
parentScreen.getSideboardPage().addCard(card); parentScreen.getSideboardPage().addCard(card);
@@ -1630,7 +1646,8 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
if (editor != null) { if (editor != null) {
String name = this.getModelName(); String name = this.getModelName();
if (name.isEmpty()) { if (name.isEmpty()) {
name = "[New Deck]"; final Localizer localizer = Localizer.getInstance();
name = "[" + localizer.getMessage("lblNewDeck") + "]";
} }
if (!saved) { if (!saved) {
name = "*" + name; name = "*" + name;

View File

@@ -229,7 +229,7 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
cols.add(colOverrides.get(colConfig.getDef())); cols.add(colOverrides.get(colConfig.getDef()));
} }
} }
cols.sort(new Comparator<ItemColumn>() { Collections.sort(cols, new Comparator<ItemColumn>() {
@Override @Override
public int compare(ItemColumn arg0, ItemColumn arg1) { public int compare(ItemColumn arg0, ItemColumn arg1) {
return Integer.compare(arg0.getConfig().getIndex(), arg1.getConfig().getIndex()); return Integer.compare(arg0.getConfig().getIndex(), arg1.getConfig().getIndex());

View File

@@ -2,6 +2,7 @@ package forge.screens;
import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.Input.Keys;
import forge.Forge;
import forge.Graphics; import forge.Graphics;
import forge.assets.FSkinImage; import forge.assets.FSkinImage;
import forge.menu.FPopupMenu; import forge.menu.FPopupMenu;
@@ -63,6 +64,7 @@ public abstract class LaunchScreen extends FScreen {
@Override @Override
public final boolean tap(float x, float y, int count) { public final boolean tap(float x, float y, int count) {
if (count == 1) { if (count == 1) {
btnStart.setEnabled(false);
startMatch(); startMatch();
} }
return true; return true;
@@ -72,6 +74,11 @@ public abstract class LaunchScreen extends FScreen {
public void draw(Graphics g) { public void draw(Graphics g) {
g.drawImage(pressed ? FSkinImage.BTN_START_DOWN : FSkinImage.BTN_START_UP, g.drawImage(pressed ? FSkinImage.BTN_START_DOWN : FSkinImage.BTN_START_UP,
0, 0, getWidth(), getHeight()); 0, 0, getWidth(), getHeight());
//its must be enabled or you can't start any game modes
if (!Forge.isLoadingaMatch()) {
if(!btnStart.isEnabled())
btnStart.setEnabled(true);
}
} }
} }

View File

@@ -1,5 +1,6 @@
package forge.screens; package forge.screens;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Align;
import forge.FThreads; import forge.FThreads;
@@ -32,6 +33,7 @@ public class LoadingOverlay extends FOverlay {
public void run() { public void run() {
runnable.run(); runnable.run();
loader.hide(); loader.hide();
loader.finishedloading(); //setLoadingaMatch to false
} }
}); });
} }
@@ -90,6 +92,12 @@ public class LoadingOverlay extends FOverlay {
float panelHeight = logoSize + fontHeight + 4 * padding; float panelHeight = logoSize + fontHeight + 4 * padding;
float y = (getHeight() - panelHeight) / 2; float y = (getHeight() - panelHeight) / 2;
float oldAlpha = g.getfloatAlphaComposite();
//dark translucent back..
g.setAlphaComposite(0.6f);
g.fillRect(Color.BLACK, 0, 0, getWidth(), getHeight());
g.setAlphaComposite(oldAlpha);
//overlay
g.fillRect(BACK_COLOR, x, y, panelWidth, panelHeight); g.fillRect(BACK_COLOR, x, y, panelWidth, panelHeight);
g.drawRect(Utils.scale(2), FORE_COLOR, x, y, panelWidth, panelHeight); g.drawRect(Utils.scale(2), FORE_COLOR, x, y, panelWidth, panelHeight);
y += padding; y += padding;

View File

@@ -94,7 +94,7 @@ public class SplashScreen extends FContainer {
String disclaimer = "Forge is not affiliated in any way with Wizards of the Coast.\n" String disclaimer = "Forge is not affiliated in any way with Wizards of the Coast.\n"
+ "Forge is open source software, released under the GNU Public License."; + "Forge is open source software, released under the GNU Public License.";
g.drawText(disclaimer, disclaimerFont, FProgressBar.SEL_FORE_COLOR, g.drawText(disclaimer, disclaimerFont, FProgressBar.SEL_FORE_COLOR,
x, y, w, disclaimerHeight, false, Align.center, true); x, y, w, disclaimerHeight, true, Align.center, true);
float padding = 20f / 450f * w; float padding = 20f / 450f * w;
float pbHeight = 57f / 450f * h; float pbHeight = 57f / 450f * h;

View File

@@ -269,8 +269,11 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
@Override @Override
protected void startMatch() { protected void startMatch() {
for (int i = 0; i < getNumPlayers(); i++) { for (int i = 0; i < getNumPlayers(); i++) {
updateDeck(i); updateDeck(i);//TODO: Investigate why AI names cannot be overriden?
updateName(i, getPlayerName(i));
} }
//set this so we cant get any multi/rapid tap on start button
Forge.setLoadingaMatch(true);
FThreads.invokeInBackgroundThread(new Runnable() { //must call startGame in background thread in case there are alerts FThreads.invokeInBackgroundThread(new Runnable() { //must call startGame in background thread in case there are alerts
@Override @Override
public void run() { public void run() {
@@ -612,6 +615,12 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
} }
} }
private void updateName(final int playerIndex, final String name) {
if (playerChangeListener != null) {
playerChangeListener.update(playerIndex, UpdateLobbyPlayerEvent.nameUpdate(name));
}
}
void setReady(final int index, final boolean ready) { void setReady(final int index, final boolean ready) {
if (ready) { if (ready) {
updateDeck(index); updateDeck(index);

View File

@@ -3,6 +3,7 @@ package forge.screens.gauntlet;
import java.io.File; import java.io.File;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Align;
@@ -296,7 +297,7 @@ public class LoadGauntletScreen extends LaunchScreen {
public void refresh() { public void refresh() {
List<GauntletData> sorted = new ArrayList<>(); List<GauntletData> sorted = new ArrayList<>();
sorted.addAll(gauntlets); sorted.addAll(gauntlets);
sorted.sort(new Comparator<GauntletData>() { Collections.sort(sorted, new Comparator<GauntletData>() {
@Override @Override
public int compare(final GauntletData x, final GauntletData y) { public int compare(final GauntletData x, final GauntletData y) {
return x.getName().toLowerCase().compareTo(y.getName().toLowerCase()); return x.getName().toLowerCase().compareTo(y.getName().toLowerCase());

View File

@@ -3,6 +3,11 @@ package forge.screens.match;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import com.badlogic.gdx.graphics.Color;
import forge.util.Localizer;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.Input.Keys;
@@ -136,17 +141,18 @@ public class MatchScreen extends FScreen {
stack.setDropDownContainer(this); stack.setDropDownContainer(this);
FMenuBar menuBar = (FMenuBar)getHeader(); FMenuBar menuBar = (FMenuBar)getHeader();
final Localizer localizer = Localizer.getInstance();
if (topPlayerPrompt == null) { if (topPlayerPrompt == null) {
menuBar.addTab("Game", gameMenu); menuBar.addTab(localizer.getMessage("lblGame"), gameMenu);
menuBar.addTab("Players (" + playerPanels.size() + ")", players); menuBar.addTab(localizer.getMessage("lblPlayers") + " (" + playerPanels.size() + ")", players);
menuBar.addTab("Log", log); menuBar.addTab(localizer.getMessage("lblLog"), log);
menuBar.addTab("Dev", devMenu); menuBar.addTab(localizer.getMessage("lblDev"), devMenu);
menuBar.addTab("Stack (0)", stack); menuBar.addTab( localizer.getMessage("lblStack") + " (0)", stack);
} }
else { else {
menuBar.addTab("\u2022 \u2022 \u2022", new PlayerSpecificMenu(true)); menuBar.addTab("\u2022 \u2022 \u2022", new PlayerSpecificMenu(true));
stack.setRotate90(true); stack.setRotate90(true);
menuBar.addTab("Stack (0)", stack); menuBar.addTab(localizer.getMessage("Stack") + " (0)", stack);
menuBar.addTab("\u2022 \u2022 \u2022", new PlayerSpecificMenu(false)); menuBar.addTab("\u2022 \u2022 \u2022", new PlayerSpecificMenu(false));
//create fake menu tabs for other drop downs so they can be positioned as needed //create fake menu tabs for other drop downs so they can be positioned as needed
@@ -223,16 +229,18 @@ public class MatchScreen extends FScreen {
@Override @Override
protected void buildMenu() { protected void buildMenu() {
final Localizer localizer = Localizer.getInstance();
if (isTopHumanPlayerActive() == getRotate180()) { if (isTopHumanPlayerActive() == getRotate180()) {
addItem(new MenuItem("Game", gameMenu)); addItem(new MenuItem(localizer.getMessage("lblGame"), gameMenu));
addItem(new MenuItem("Players (" + playerPanels.size() + ")", players)); addItem(new MenuItem(localizer.getMessage("lblPlayers") + " (" + playerPanels.size() + ")", players));
addItem(new MenuItem("Log", log)); addItem(new MenuItem(localizer.getMessage("lblLog"), log));
if (ForgePreferences.DEV_MODE) { if (ForgePreferences.DEV_MODE) {
addItem(new MenuItem("Dev", devMenu)); addItem(new MenuItem(localizer.getMessage("lblDev"), devMenu));
} }
} }
else { //TODO: Support using menu when player doesn't have priority else { //TODO: Support using menu when player doesn't have priority
FMenuItem item = new FMenuItem("Must wait for priority...", null); FMenuItem item = new FMenuItem(localizer.getMessage("lblMustWaitPriority"), null);
item.setEnabled(false); item.setEnabled(false);
addItem(item); addItem(item);
} }
@@ -565,6 +573,23 @@ public class MatchScreen extends FScreen {
y = bottomPlayerPanel.getTop() + bottomPlayerPanel.getField().getHeight(); y = bottomPlayerPanel.getTop() + bottomPlayerPanel.getField().getHeight();
g.drawLine(1, BORDER_COLOR, x, y, w, y); g.drawLine(1, BORDER_COLOR, x, y, w, y);
} }
//Draw Priority Human Multiplayer 2 player
float oldAlphaComposite = g.getfloatAlphaComposite();
if ((getPlayerPanels().keySet().size() == 2) && (countHuman() == 2)){
for (VPlayerPanel playerPanel: playerPanelsList){
midField = playerPanel.getTop();
y = midField - 0.5f;
float adjustY = Forge.isLandscapeMode() ? y + 1f : midField;
float adjustH = Forge.isLandscapeMode() ? playerPanel.getField().getBottom() - 1f : playerPanel.getBottom() - 1f;
if(playerPanel.getPlayer().getHasPriority() && !playerPanel.getPlayer().isAI())
g.setAlphaComposite(0.8f);
else
g.setAlphaComposite(0f);
g.drawRect(4f, Color.CYAN, playerPanel.getField().getLeft(), adjustY, playerPanel.getField().getWidth(), adjustH);
g.setAlphaComposite(oldAlphaComposite);
}
}
} }
protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) { protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) {
@@ -665,9 +690,17 @@ public class MatchScreen extends FScreen {
private boolean hasActivePlane(){ private boolean hasActivePlane(){
if(MatchController.instance.getGameView() != null) if(MatchController.instance.getGameView() != null)
if(MatchController.instance.getGameView().getPlanarPlayer() != null) { if(MatchController.instance.getGameView().getPlanarPlayer() != null) {
return MatchController.instance.getGameView().getPlanarPlayer().getCurrentPlaneName() != ""; return !MatchController.instance.getGameView().getPlanarPlayer().getCurrentPlaneName().equals("");
} }
return false; return false;
} }
private int countHuman(){
int humanplayers = 0;
for (VPlayerPanel playerPanel: playerPanelsList) {
if(!playerPanel.getPlayer().isAI())
humanplayers++;
}
return humanplayers;
}
} }
} }

View File

@@ -2,6 +2,7 @@ package forge.screens.planarconquest;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -335,7 +336,7 @@ public class LoadConquestScreen extends LaunchScreen {
public void setConquests(List<ConquestData> qd0) { public void setConquests(List<ConquestData> qd0) {
List<ConquestData> sorted = new ArrayList<>(); List<ConquestData> sorted = new ArrayList<>();
sorted.addAll(qd0); sorted.addAll(qd0);
sorted.sort(new Comparator<ConquestData>() { Collections.sort(sorted, new Comparator<ConquestData>() {
@Override @Override
public int compare(final ConquestData x, final ConquestData y) { public int compare(final ConquestData x, final ConquestData y) {
return x.getName().toLowerCase().compareTo(y.getName().toLowerCase()); return x.getName().toLowerCase().compareTo(y.getName().toLowerCase());

View File

@@ -4,6 +4,7 @@ import java.io.File;
import java.io.FilenameFilter; import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -336,7 +337,7 @@ public class LoadQuestScreen extends LaunchScreen {
public void setQuests(List<QuestData> qd0) { public void setQuests(List<QuestData> qd0) {
List<QuestData> sorted = new ArrayList<>(); List<QuestData> sorted = new ArrayList<>();
sorted.addAll(qd0); sorted.addAll(qd0);
sorted.sort(new Comparator<QuestData>() { Collections.sort(sorted, new Comparator<QuestData>() {
@Override @Override
public int compare(final QuestData x, final QuestData y) { public int compare(final QuestData x, final QuestData y) {
return x.getName().toLowerCase().compareTo(y.getName().toLowerCase()); return x.getName().toLowerCase().compareTo(y.getName().toLowerCase());

View File

@@ -26,6 +26,7 @@ import forge.toolbox.FGroupList;
import forge.toolbox.FList; import forge.toolbox.FList;
import forge.toolbox.FOptionPane; import forge.toolbox.FOptionPane;
import forge.util.Callback; import forge.util.Callback;
import forge.util.Localizer;
import forge.util.Utils; import forge.util.Utils;
import java.util.ArrayList; import java.util.ArrayList;
@@ -38,28 +39,30 @@ public class SettingsPage extends TabPage<SettingsScreen> {
public SettingsPage() { public SettingsPage() {
super("Settings", FSkinImage.SETTINGS); super("Settings", FSkinImage.SETTINGS);
final Localizer localizer = Localizer.getInstance();
lstSettings.setListItemRenderer(new SettingRenderer()); lstSettings.setListItemRenderer(new SettingRenderer());
lstSettings.addGroup("General Settings"); lstSettings.addGroup(localizer.getMessage("lblGeneralSettings"));
lstSettings.addGroup("Gameplay Options"); lstSettings.addGroup(localizer.getMessage("lblGameplayOptions"));
lstSettings.addGroup("Random Deck Generation"); lstSettings.addGroup(localizer.getMessage("RandomDeckGeneration"));
lstSettings.addGroup("Advanced Settings"); lstSettings.addGroup(localizer.getMessage("AdvancedSettings"));
lstSettings.addGroup("Graphic Options"); lstSettings.addGroup(localizer.getMessage("GraphicOptions"));
lstSettings.addGroup("Card Overlays"); lstSettings.addGroup(localizer.getMessage("lblCardOverlays"));
lstSettings.addGroup("Vibration Options"); lstSettings.addGroup(localizer.getMessage("lblVibrationOptions"));
lstSettings.addGroup("Sound Options"); lstSettings.addGroup(localizer.getMessage("SoundOptions"));
//General Settings //General Settings
lstSettings.addItem(new CustomSelectSetting(FPref.UI_LANGUAGE, "Language", lstSettings.addItem(new CustomSelectSetting(FPref.UI_LANGUAGE, localizer.getMessage("cbpSelectLanguage"),
"Select Language (Excluded Game part. Still a work in progress) (RESTART REQUIRED)", localizer.getMessage("nlSelectLanguage"),
FLanguage.getAllLanguages()) { FLanguage.getAllLanguages()) {
@Override @Override
public void valueChanged(String newValue) { public void valueChanged(String newValue) {
FLanguage.changeLanguage(newValue); FLanguage.changeLanguage(newValue);
} }
}, 0); }, 0);
lstSettings.addItem(new CustomSelectSetting(FPref.UI_SKIN, "Theme", lstSettings.addItem(new CustomSelectSetting(FPref.UI_SKIN, localizer.getMessage("lblTheme"),
"Sets the theme that determines how display components are skinned.", localizer.getMessage("nlTheme"),
FSkin.getAllSkins()) { FSkin.getAllSkins()) {
@Override @Override
public void valueChanged(String newValue) { public void valueChanged(String newValue) {
@@ -67,15 +70,15 @@ public class SettingsPage extends TabPage<SettingsScreen> {
} }
}, 0); }, 0);
lstSettings.addItem(new BooleanSetting(FPref.UI_LANDSCAPE_MODE, lstSettings.addItem(new BooleanSetting(FPref.UI_LANDSCAPE_MODE,
"Landscape Mode", localizer.getMessage("lblLandscapeMode"),
"Use landscape (horizontal) orientation for app instead of portrait (vertical).") { localizer.getMessage("nlLandscapeMode")) {
@Override @Override
public void select() { public void select() {
super.select(); super.select();
boolean landscapeMode = FModel.getPreferences().getPrefBoolean(FPref.UI_LANDSCAPE_MODE); boolean landscapeMode = FModel.getPreferences().getPrefBoolean(FPref.UI_LANDSCAPE_MODE);
Forge.getDeviceAdapter().setLandscapeMode(landscapeMode); //ensure device able to save off ini file so landscape change takes effect Forge.getDeviceAdapter().setLandscapeMode(landscapeMode); //ensure device able to save off ini file so landscape change takes effect
if (Forge.isLandscapeMode() != landscapeMode) { if (Forge.isLandscapeMode() != landscapeMode) {
FOptionPane.showConfirmDialog("You must restart Forge for this change to take effect.", "Restart Forge", "Restart", "Later", new Callback<Boolean>() { FOptionPane.showConfirmDialog(localizer.getMessage("lblRestartForgeDescription"), localizer.getMessage("lblRestartForge"), "Restart", localizer.getMessage("lblLater"), new Callback<Boolean>() {
@Override @Override
public void run(Boolean result) { public void run(Boolean result) {
if (result) { if (result) {
@@ -87,17 +90,17 @@ public class SettingsPage extends TabPage<SettingsScreen> {
} }
}, 0); }, 0);
lstSettings.addItem(new BooleanSetting(FPref.UI_ANDROID_MINIMIZE_ON_SCRLOCK, lstSettings.addItem(new BooleanSetting(FPref.UI_ANDROID_MINIMIZE_ON_SCRLOCK,
"Minimize on Screen Lock", localizer.getMessage("lblMinimizeScreenLock"),
"Minimize Forge when screen is locked (enable if you experience graphic glitches after locking your screen)."), localizer.getMessage("nlMinimizeScreenLock")),
0); 0);
lstSettings.addItem(new BooleanSetting(FPref.USE_SENTRY, lstSettings.addItem(new BooleanSetting(FPref.USE_SENTRY,
"Automatic Bug Reports", localizer.getMessage("lblAutomaticBugReports"),
"Automatically send bug reports to the developers, without prompting."), localizer.getMessage("nlAutomaticBugReports")),
0); 0);
//Gameplay Options //Gameplay Options
lstSettings.addItem(new CustomSelectSetting(FPref.MULLIGAN_RULE, "Mulligan Rule", lstSettings.addItem(new CustomSelectSetting(FPref.MULLIGAN_RULE, localizer.getMessage("cbpMulliganRule"),
"Choose the version of the Mulligan rule.", localizer.getMessage("nlpMulliganRule"),
MulliganDefs.getMulliganRuleNames()) { MulliganDefs.getMulliganRuleNames()) {
@Override @Override
public void valueChanged(String newValue) { public void valueChanged(String newValue) {
@@ -107,108 +110,108 @@ public class SettingsPage extends TabPage<SettingsScreen> {
}, 1); }, 1);
lstSettings.addItem(new CustomSelectSetting(FPref.UI_CURRENT_AI_PROFILE, lstSettings.addItem(new CustomSelectSetting(FPref.UI_CURRENT_AI_PROFILE,
"AI Personality", "AI Personality",
"Choose your AI opponent.", localizer.getMessage("nlpAiProfiles"),
AiProfileUtil.getProfilesArray()), AiProfileUtil.getProfilesArray()),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.UI_ANTE, lstSettings.addItem(new BooleanSetting(FPref.UI_ANTE,
"Play for Ante", localizer.getMessage("cbAnte"),
"Determines whether or not the game is played for ante."), localizer.getMessage("nlAnte")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.UI_ANTE_MATCH_RARITY, lstSettings.addItem(new BooleanSetting(FPref.UI_ANTE_MATCH_RARITY,
"Match Ante Rarity", localizer.getMessage("cbAnteMatchRarity"),
"Attempts to make antes the same rarity for all players."), localizer.getMessage("nlAnteMatchRarity")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.MATCH_HOT_SEAT_MODE, lstSettings.addItem(new BooleanSetting(FPref.MATCH_HOT_SEAT_MODE,
"Hot Seat Mode", localizer.getMessage("lblHotSeatMode"),
"When starting a game with 2 human players, use single prompt to control both players."), localizer.getMessage("nlHotSeatMode")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_AI_CHEATS, lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_AI_CHEATS,
"Allow AI Cheating", localizer.getMessage("cbEnableAICheats"),
"Allow the AI to cheat to gain advantage (for personalities that have cheat shuffling options set)."), localizer.getMessage("nlEnableAICheats")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.UI_MANABURN, lstSettings.addItem(new BooleanSetting(FPref.UI_MANABURN,
"Mana Burn", localizer.getMessage("cbManaBurn"),
"Play with mana burn (from pre-Magic 2010 rules)."), localizer.getMessage("nlManaBurn")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.UI_MANA_LOST_PROMPT, lstSettings.addItem(new BooleanSetting(FPref.UI_MANA_LOST_PROMPT,
"Prompt Mana Pool Emptying", localizer.getMessage("cbManaLostPrompt"),
"When enabled, you get a warning if passing priority would cause you to lose mana in your mana pool."), localizer.getMessage("nlManaLostPrompt")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.ENFORCE_DECK_LEGALITY, lstSettings.addItem(new BooleanSetting(FPref.ENFORCE_DECK_LEGALITY,
"Deck Conformance", localizer.getMessage("cbEnforceDeckLegality"),
"Enforces deck legality relevant to each environment (minimum deck sizes, max card count etc)."), localizer.getMessage("nlEnforceDeckLegality")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.PERFORMANCE_MODE, lstSettings.addItem(new BooleanSetting(FPref.PERFORMANCE_MODE,
"Performance Mode", localizer.getMessage("cbPerformanceMode"),
"Disables additional static abilities checks to speed up the game engine. (Warning: breaks some 'as if had flash' scenarios when casting cards owned by opponents)."), localizer.getMessage("nlPerformanceMode")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.MATCH_SIDEBOARD_FOR_AI, lstSettings.addItem(new BooleanSetting(FPref.MATCH_SIDEBOARD_FOR_AI,
"Human Sideboard for AI", localizer.getMessage("cbSideboardForAI"),
"Allows users to sideboard with the AIs deck and sideboard in constructed game formats."), localizer.getMessage("nlSideboardForAI")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.FILTERED_HANDS, lstSettings.addItem(new BooleanSetting(FPref.FILTERED_HANDS,
"Filtered Hands", localizer.getMessage("cbFilteredHands"),
"Generates two starting hands and keeps the one with the closest to average land count for the deck. (Requires restart)"), localizer.getMessage("nlFilteredHands")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.UI_CLONE_MODE_SOURCE, lstSettings.addItem(new BooleanSetting(FPref.UI_CLONE_MODE_SOURCE,
"Clones Use Original Card Art", localizer.getMessage("cbCloneImgSource"),
"When enabled clones will use their original art instead of the cloned card's art."), localizer.getMessage("nlCloneImgSource")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.MATCHPREF_PROMPT_FREE_BLOCKS, lstSettings.addItem(new BooleanSetting(FPref.MATCHPREF_PROMPT_FREE_BLOCKS,
"Free Block Handling", localizer.getMessage("cbPromptFreeBlocks"),
"When enabled, if you would have to pay 0 to block, pay automatically without prompt."), localizer.getMessage("nlPromptFreeBlocks")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.UI_DETAILED_SPELLDESC_IN_PROMPT, lstSettings.addItem(new BooleanSetting(FPref.UI_DETAILED_SPELLDESC_IN_PROMPT,
"Spell Description in Payment Prompt", localizer.getMessage("cbDetailedPaymentDesc"),
"When enabled, detailed spell/ability descriptions are shown when choosing targets and paying costs."), localizer.getMessage("nlDetailedPaymentDesc")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.UI_SHOW_STORM_COUNT_IN_PROMPT, lstSettings.addItem(new BooleanSetting(FPref.UI_SHOW_STORM_COUNT_IN_PROMPT,
"Show Storm Count in Prompt Panel", localizer.getMessage("cbShowStormCount"),
"When enabled, displays the current storm count in the prompt panel."), localizer.getMessage("nlShowStormCount")),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.UI_PRESELECT_PREVIOUS_ABILITY_ORDER, lstSettings.addItem(new BooleanSetting(FPref.UI_PRESELECT_PREVIOUS_ABILITY_ORDER,
"Preselect Last Order of Abilities", localizer.getMessage("cbPreselectPrevAbOrder"),
"When enabled, preselects the last defined simultaneous ability order in the ordering dialog."), localizer.getMessage("nlPreselectPrevAbOrder")),
1); 1);
lstSettings.addItem(new CustomSelectSetting(FPref.UI_ALLOW_ORDER_GRAVEYARD_WHEN_NEEDED, lstSettings.addItem(new CustomSelectSetting(FPref.UI_ALLOW_ORDER_GRAVEYARD_WHEN_NEEDED,
"Order Graveyard", localizer.getMessage("lblOrderGraveyard"),
"Determines when to allow to order cards going to graveyard (never/always/only with relevant cards).", localizer.getMessage("nlOrderGraveyard"),
new String[]{ new String[]{
ForgeConstants.GRAVEYARD_ORDERING_NEVER, ForgeConstants.GRAVEYARD_ORDERING_OWN_CARDS, ForgeConstants.GRAVEYARD_ORDERING_NEVER, ForgeConstants.GRAVEYARD_ORDERING_OWN_CARDS,
ForgeConstants.GRAVEYARD_ORDERING_ALWAYS}), ForgeConstants.GRAVEYARD_ORDERING_ALWAYS}),
1); 1);
lstSettings.addItem(new CustomSelectSetting(FPref.UI_AUTO_YIELD_MODE, lstSettings.addItem(new CustomSelectSetting(FPref.UI_AUTO_YIELD_MODE,
"Auto-Yield", localizer.getMessage("lblAutoYields"),
"Defines the granularity level of auto-yields (yield to each unique ability or to each unique card).", localizer.getMessage("nlpAutoYieldMode"),
new String[]{ForgeConstants.AUTO_YIELD_PER_ABILITY, ForgeConstants.AUTO_YIELD_PER_CARD}), new String[]{ForgeConstants.AUTO_YIELD_PER_ABILITY, ForgeConstants.AUTO_YIELD_PER_CARD}),
1); 1);
lstSettings.addItem(new BooleanSetting(FPref.UI_ALLOW_ESC_TO_END_TURN, lstSettings.addItem(new BooleanSetting(FPref.UI_ALLOW_ESC_TO_END_TURN,
"Use Escape Key To End Turn", localizer.getMessage("cbEscapeEndsTurn"),
"Allows to use Esc keyboard shortcut to end turn prematurely"), localizer.getMessage("nlEscapeEndsTurn")),
1); 1);
//Random Deck Generation //Random Deck Generation
lstSettings.addItem(new BooleanSetting(FPref.DECKGEN_NOSMALL, lstSettings.addItem(new BooleanSetting(FPref.DECKGEN_NOSMALL,
"Remove Small Creatures", localizer.getMessage("cbRemoveSmall"),
"Disables 1/1 and 0/X creatures in generated decks."), localizer.getMessage("nlRemoveSmall")),
2); 2);
lstSettings.addItem(new BooleanSetting(FPref.DECKGEN_CARDBASED, lstSettings.addItem(new BooleanSetting(FPref.DECKGEN_CARDBASED,
"Include Card-based Deck Generation", localizer.getMessage("cbCardBased"),
"Builds more synergistic random decks"), localizer.getMessage("nlCardBased")),
2); 2);
lstSettings.addItem(new BooleanSetting(FPref.DECKGEN_SINGLETONS, lstSettings.addItem(new BooleanSetting(FPref.DECKGEN_SINGLETONS,
"Singleton Mode", localizer.getMessage("cbSingletons"),
"Disables non-land duplicates in generated decks."), localizer.getMessage("nlSingletons")),
2); 2);
lstSettings.addItem(new BooleanSetting(FPref.DECKGEN_ARTIFACTS, lstSettings.addItem(new BooleanSetting(FPref.DECKGEN_ARTIFACTS,
"Remove Artifacts", localizer.getMessage("cbRemoveArtifacts"),
"Disables artifact cards in generated decks."), localizer.getMessage("nlRemoveArtifacts")),
2); 2);
//Advanced Settings //Advanced Settings
lstSettings.addItem(new BooleanSetting(FPref.DEV_MODE_ENABLED, lstSettings.addItem(new BooleanSetting(FPref.DEV_MODE_ENABLED,
"Developer Mode", localizer.getMessage("cbDevMode"),
"Enables menu with functions for testing during development.") { localizer.getMessage("nlDevMode")) {
@Override @Override
public void select() { public void select() {
super.select(); super.select();
@@ -217,37 +220,39 @@ public class SettingsPage extends TabPage<SettingsScreen> {
} }
}, 3); }, 3);
lstSettings.addItem(new CustomSelectSetting(FPref.DEV_LOG_ENTRY_TYPE, lstSettings.addItem(new CustomSelectSetting(FPref.DEV_LOG_ENTRY_TYPE,
"Game Log Verbosity", localizer.getMessage("cbpGameLogEntryType"),
"Changes how much information is displayed in the game log. Sorted by least to most verbose.", localizer.getMessage("nlGameLogEntryType"),
GameLogEntryType.class), GameLogEntryType.class),
3); 3);
lstSettings.addItem(new BooleanSetting(FPref.LOAD_CARD_SCRIPTS_LAZILY, lstSettings.addItem(new BooleanSetting(FPref.LOAD_CARD_SCRIPTS_LAZILY,
"Load Card Scripts Lazily", localizer.getMessage("cbLoadCardsLazily"),
"If turned on, Forge will load card scripts as they're needed instead of at start up. (Warning: Experimental)"), 3); localizer.getMessage("nlLoadCardsLazily")),
3);
lstSettings.addItem(new BooleanSetting(FPref.LOAD_HISTORIC_FORMATS, lstSettings.addItem(new BooleanSetting(FPref.LOAD_HISTORIC_FORMATS,
"Load Historic Formats", localizer.getMessage("cbLoadHistoricFormats"),
"If turned on, Forge will load all historic format definitions, this may take slightly longer to load at startup."), 3); localizer.getMessage("nlLoadHistoricFormats")),
3);
//Graphic Options //Graphic Options
lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER, lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER,
"Download missing card art", localizer.getMessage("cbImageFetcher"),
"Automatically download missing card art"), localizer.getMessage("nlImageFetcher")),
4); 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_OVERLAY_FOIL_EFFECT, lstSettings.addItem(new BooleanSetting(FPref.UI_OVERLAY_FOIL_EFFECT,
"Display Foil Overlay", localizer.getMessage("cbDisplayFoil"),
"Displays foil cards with the visual foil overlay effect."), localizer.getMessage("nlDisplayFoil")),
4); 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_RANDOM_FOIL, lstSettings.addItem(new BooleanSetting(FPref.UI_RANDOM_FOIL,
"Random Foil", localizer.getMessage("cbRandomFoil"),
"Adds foil effect to random cards."), localizer.getMessage("nlRandomFoil")),
4); 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_RANDOM_ART_IN_POOLS, lstSettings.addItem(new BooleanSetting(FPref.UI_RANDOM_ART_IN_POOLS,
"Randomize Card Art", localizer.getMessage("cbRandomArtInPools"),
"Generates cards with random art in generated limited mode card pools."), localizer.getMessage("nlRandomArtInPools")),
4); 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_COMPACT_TABS, lstSettings.addItem(new BooleanSetting(FPref.UI_COMPACT_TABS,
"Compact Tabs", localizer.getMessage("lblCompactTabs"),
"Show smaller tabs on the top of tab page screens (such as this screen).") { localizer.getMessage("nlCompactTabs")) {
@Override @Override
public void select() { public void select() {
super.select(); super.select();
@@ -257,49 +262,49 @@ public class SettingsPage extends TabPage<SettingsScreen> {
} }
}, 4); }, 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_COMPACT_LIST_ITEMS, lstSettings.addItem(new BooleanSetting(FPref.UI_COMPACT_LIST_ITEMS,
"Compact List Items", localizer.getMessage("lblCompactListItems"),
"Show only a single line of text for cards and decks on all list views by default."), localizer.getMessage("nlCompactListItems")),
4); 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_HIDE_REMINDER_TEXT, lstSettings.addItem(new BooleanSetting(FPref.UI_HIDE_REMINDER_TEXT,
"Hide Reminder Text", localizer.getMessage("cbHideReminderText"),
"Hide reminder text in Card Detail pane."), localizer.getMessage("nlHideReminderText")),
4); 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_MATCH_IMAGE_VISIBLE, lstSettings.addItem(new BooleanSetting(FPref.UI_MATCH_IMAGE_VISIBLE,
"Show Match Background", localizer.getMessage("lblShowMatchBackground"),
"Show match background image on battlefield, otherwise background texture shown instead."), localizer.getMessage("nlShowMatchBackground")),
4); 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_LIBGDX_TEXTURE_FILTERING, lstSettings.addItem(new BooleanSetting(FPref.UI_LIBGDX_TEXTURE_FILTERING,
"Battlefield Texture Filtering", localizer.getMessage("lblBattlefieldTextureFiltering"),
"Filter card art on battlefield to make it less pixelated on large screens (restart required, may reduce performance)."), localizer.getMessage("nlBattlefieldTextureFiltering")),
4); 4);
lstSettings.addItem(new CustomSelectSetting(FPref.UI_DISPLAY_CURRENT_COLORS, lstSettings.addItem(new CustomSelectSetting(FPref.UI_DISPLAY_CURRENT_COLORS,
"Detailed Card Color", localizer.getMessage("cbpDisplayCurrentCardColors"),
"Displays the breakdown of the current color of cards in the card detail information panel.", localizer.getMessage("nlDisplayCurrentCardColors"),
new String[]{ new String[]{
ForgeConstants.DISP_CURRENT_COLORS_NEVER, ForgeConstants.DISP_CURRENT_COLORS_MULTICOLOR, ForgeConstants.DISP_CURRENT_COLORS_NEVER, ForgeConstants.DISP_CURRENT_COLORS_MULTICOLOR,
ForgeConstants.DISP_CURRENT_COLORS_CHANGED, ForgeConstants.DISP_CURRENT_COLORS_MULTI_OR_CHANGED, ForgeConstants.DISP_CURRENT_COLORS_CHANGED, ForgeConstants.DISP_CURRENT_COLORS_MULTI_OR_CHANGED,
ForgeConstants.DISP_CURRENT_COLORS_ALWAYS}), ForgeConstants.DISP_CURRENT_COLORS_ALWAYS}),
4); 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_ROTATE_SPLIT_CARDS, lstSettings.addItem(new BooleanSetting(FPref.UI_ROTATE_SPLIT_CARDS,
"Rotate Zoom Image of Split Cards", localizer.getMessage("lblRotateZoomSplit"),
"Rotates the zoomed image of split cards."), localizer.getMessage("nlRotateZoomSplit")),
4); 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_ROTATE_PLANE_OR_PHENOMENON, lstSettings.addItem(new BooleanSetting(FPref.UI_ROTATE_PLANE_OR_PHENOMENON,
"Rotate Zoom Image of Planes/Phenomena", localizer.getMessage("lblRotateZoomPlanesPhenomena"),
"Rotates the zoomed image of Plane or Phenomenon cards."), localizer.getMessage("nlRotateZoomPlanesPhenomena")),
4); 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_DYNAMIC_PLANECHASE_BG, lstSettings.addItem(new BooleanSetting(FPref.UI_DYNAMIC_PLANECHASE_BG,
"Dynamic Background Planechase", localizer.getMessage("lblDynamicBackgroundPlanechase"),
"Use current plane images as background (Planes Card images must be on the cache/pics/planechase folder)."), localizer.getMessage("nlDynamicBackgroundPlanechase")),
4); 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_DISABLE_IMAGES_EFFECT_CARDS, lstSettings.addItem(new BooleanSetting(FPref.UI_DISABLE_IMAGES_EFFECT_CARDS,
"Disable Card 'Effect' Images", localizer.getMessage("lblDisableCardEffect"),
"Disable the zoomed image for the 'Effect' cards."), localizer.getMessage("nlDisableCardEffect")),
4); 4);
lstSettings.addItem(new CustomSelectSetting(FPref.UI_CARD_COUNTER_DISPLAY_TYPE, lstSettings.addItem(new CustomSelectSetting(FPref.UI_CARD_COUNTER_DISPLAY_TYPE,
"Counter Display Type", localizer.getMessage("cbpCounterDisplayType"),
"Selects the style of the in-game counter display for cards. Text-based is a new tab-like display on the cards. Image-based is the old counter image. Hybrid displays both at once.", localizer.getMessage("nlCounterDisplayType"),
new String[]{ new String[]{
ForgeConstants.CounterDisplayType.TEXT.getName(), ForgeConstants.CounterDisplayType.IMAGE.getName(), ForgeConstants.CounterDisplayType.TEXT.getName(), ForgeConstants.CounterDisplayType.IMAGE.getName(),
ForgeConstants.CounterDisplayType.HYBRID.getName(), ForgeConstants.CounterDisplayType.OLD_WHEN_SMALL.getName()}), ForgeConstants.CounterDisplayType.HYBRID.getName(), ForgeConstants.CounterDisplayType.OLD_WHEN_SMALL.getName()}),
@@ -307,44 +312,44 @@ public class SettingsPage extends TabPage<SettingsScreen> {
//Card Overlays //Card Overlays
lstSettings.addItem(new BooleanSetting(FPref.UI_SHOW_CARD_OVERLAYS, lstSettings.addItem(new BooleanSetting(FPref.UI_SHOW_CARD_OVERLAYS,
"Show Card Overlays", localizer.getMessage("lblShowCardOverlays"),
"Show name, mana cost, p/t, and id overlays for cards, otherwise they're hidden."), localizer.getMessage("nlShowCardOverlays")),
5); 5);
lstSettings.addItem(new BooleanSetting(FPref.UI_OVERLAY_CARD_NAME, lstSettings.addItem(new BooleanSetting(FPref.UI_OVERLAY_CARD_NAME,
"Show Card Name Overlays", localizer.getMessage("lblShowCardNameOverlays"),
"Show name overlays for cards, otherwise they're hidden."), localizer.getMessage("nlShowCardNameOverlays")),
5); 5);
lstSettings.addItem(new BooleanSetting(FPref.UI_OVERLAY_CARD_MANA_COST, lstSettings.addItem(new BooleanSetting(FPref.UI_OVERLAY_CARD_MANA_COST,
"Show Card Mana Cost Overlays", localizer.getMessage("lblShowCardManaCostOverlays"),
"Show mana cost overlays for cards, otherwise they're hidden."), localizer.getMessage("nlShowCardManaCostOverlays")),
5); 5);
lstSettings.addItem(new BooleanSetting(FPref.UI_OVERLAY_CARD_POWER, lstSettings.addItem(new BooleanSetting(FPref.UI_OVERLAY_CARD_POWER,
"Show Card P/T Overlays", localizer.getMessage("lblShowCardPTOverlays"),
"Show power/toughness/loyalty overlays for cards, otherwise they're hidden."), localizer.getMessage("nlShowCardPTOverlays")),
5); 5);
lstSettings.addItem(new BooleanSetting(FPref.UI_OVERLAY_CARD_ID, lstSettings.addItem(new BooleanSetting(FPref.UI_OVERLAY_CARD_ID,
"Show Card ID Overlays", localizer.getMessage("lblShowCardIDOverlays"),
"Show id overlays for cards, otherwise they're hidden."), localizer.getMessage("nlShowCardIDOverlays")),
5); 5);
//Vibration Options //Vibration Options
lstSettings.addItem(new BooleanSetting(FPref.UI_VIBRATE_ON_LIFE_LOSS, lstSettings.addItem(new BooleanSetting(FPref.UI_VIBRATE_ON_LIFE_LOSS,
"Vibrate When Losing Life", localizer.getMessage("lblVibrateWhenLosingLife"),
"Enable vibration when your player loses life or takes damage during a game."), localizer.getMessage("nlVibrateWhenLosingLife")),
6); 6);
lstSettings.addItem(new BooleanSetting(FPref.UI_VIBRATE_ON_LONG_PRESS, lstSettings.addItem(new BooleanSetting(FPref.UI_VIBRATE_ON_LONG_PRESS,
"Vibrate After Long Press", localizer.getMessage("lblVibrateAfterLongPress"),
"Enable quick vibration to signify a long press, such as for card zooming."), localizer.getMessage("nlVibrateAfterLongPress")),
6); 6);
//Sound Options //Sound Options
lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_SOUNDS, lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_SOUNDS,
"Enable Sounds", localizer.getMessage("cbEnableSounds"),
"Enable sound effects during the game."), localizer.getMessage("nlEnableSounds")),
7); 7);
lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_MUSIC, lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_MUSIC,
"Enable Music", localizer.getMessage("cbEnableMusic"),
"Enable background music during the game.") { localizer.getMessage("nlEnableMusic")) {
@Override @Override
public void select() { public void select() {
super.select(); super.select();
@@ -513,7 +518,7 @@ public class SettingsPage extends TabPage<SettingsScreen> {
g.drawText(value.label, font, foreColor, x, y, w, h, false, Align.left, false); g.drawText(value.label, font, foreColor, x, y, w, h, false, Align.left, false);
value.drawPrefValue(g, font, foreColor, x, y, w, h); value.drawPrefValue(g, font, foreColor, x, y, w, h);
h += SettingsScreen.SETTING_PADDING;//TODO: adjust settings page description bounds h += SettingsScreen.SETTING_PADDING;
g.drawText(value.description, SettingsScreen.DESC_FONT, SettingsScreen.DESC_COLOR, x, y + h, w, totalHeight - h + SettingsScreen.getInsets(w), true, Align.left, false); g.drawText(value.description, SettingsScreen.DESC_FONT, SettingsScreen.DESC_COLOR, x, y + h, w, totalHeight - h + SettingsScreen.getInsets(w), true, Align.left, false);
} }
} }

View File

@@ -85,6 +85,10 @@ public abstract class FOverlay extends FContainer {
setVisible(false); setVisible(false);
} }
public void finishedloading() {
Forge.setLoadingaMatch(false);
}
public boolean isVisibleOnScreen(FScreen screen) { public boolean isVisibleOnScreen(FScreen screen) {
return (openedOnScreen == screen); //by default, only show overlay on the same screen it's opened on return (openedOnScreen == screen); //by default, only show overlay on the same screen it's opened on
} }

View File

@@ -334,7 +334,7 @@ public class GuiChoose {
// If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine // If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine
public static <T> void sortedGetChoices(final String message, final int min, final int max, final List<T> choices, Comparator<T> comparer, final Callback<List<T>> callback) { public static <T> void sortedGetChoices(final String message, final int min, final int max, final List<T> choices, Comparator<T> comparer, final Callback<List<T>> callback) {
// You may create a copy of source list if callers expect the collection to be unchanged // You may create a copy of source list if callers expect the collection to be unchanged
choices.sort(comparer); Collections.sort(choices, comparer);
getChoices(message, min, max, choices, callback); getChoices(message, min, max, choices, callback);
} }
} }

View File

@@ -2,16 +2,11 @@ Name:Bloom Tender
ManaCost:1 G ManaCost:1 G
Types:Creature Elf Druid Types:Creature Elf Druid
PT:1/1 PT:1/1
A:AB$ Mana | Cost$ T | Produced$ W | ConditionCheckSVar$ CheckW | References$ CheckW | ConditionSVarCompare$ GE1 | SubAbility$ DBManaU | SpellDescription$ For each color among permanents you control, add one mana of that color. A:AB$ Mana | Cost$ T | Produced$ W | ConditionPresent$ Permanent.YouCtrl+White | SubAbility$ DBManaU | SpellDescription$ For each color among permanents you control, add one mana of that color.
SVar:DBManaU:DB$ Mana | Produced$ U | ConditionCheckSVar$ CheckU | References$ CheckU | ConditionSVarCompare$ GE1 | SubAbility$ DBManaB SVar:DBManaU:DB$ Mana | Produced$ U | ConditionPresent$ Permanent.YouCtrl+Blue | SubAbility$ DBManaB
SVar:DBManaB:DB$ Mana | Produced$ B | ConditionCheckSVar$ CheckB | References$ CheckB | ConditionSVarCompare$ GE1 | SubAbility$ DBManaR SVar:DBManaB:DB$ Mana | Produced$ B | ConditionPresent$ Permanent.YouCtrl+Black | SubAbility$ DBManaR
SVar:DBManaR:DB$ Mana | Produced$ R | ConditionCheckSVar$ CheckR | References$ CheckR | ConditionSVarCompare$ GE1 | SubAbility$ DBManaG SVar:DBManaR:DB$ Mana | Produced$ R | ConditionPresent$ Permanent.YouCtrl+Red | SubAbility$ DBManaG
SVar:DBManaG:DB$ Mana | Produced$ G | ConditionCheckSVar$ CheckG | References$ CheckG | ConditionSVarCompare$ GE1 SVar:DBManaG:DB$ Mana | Produced$ G | ConditionPresent$ Permanent.YouCtrl+Green
SVar:CheckW:Count$Valid Permanent.YouCtrl+White
SVar:CheckU:Count$Valid Permanent.YouCtrl+Blue
SVar:CheckB:Count$Valid Permanent.YouCtrl+Black
SVar:CheckR:Count$Valid Permanent.YouCtrl+Red
SVar:CheckG:Count$Valid Permanent.YouCtrl+Green
AI:RemoveDeck:All AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/bloom_tender.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/bloom_tender.jpg
Oracle:{T}: For each color among permanents you control, add one mana of that color. Oracle:{T}: For each color among permanents you control, add one mana of that color.

View File

@@ -3,5 +3,5 @@ ManaCost:3 U R
Types:Instant Types:Instant
A:SP$ Draw | Cost$ 3 U R | NumCards$ 2 | SubAbility$ DBImmediateTrigger | SpellDescription$ Draw two cards. Then you may discard a nonland card. When you do, CARDNAME deals 4 damage to target creature. A:SP$ Draw | Cost$ 3 U R | NumCards$ 2 | SubAbility$ DBImmediateTrigger | SpellDescription$ Draw two cards. Then you may discard a nonland card. When you do, CARDNAME deals 4 damage to target creature.
SVar:DBImmediateTrigger:DB$ ImmediateTrigger | Execute$ TrigDealDmg | TriggerDescription$ You may discard a nonland card. When you do, CARDNAME deals 4 damage to target creature. | UnlessCost$ Discard<1/Card.nonLand/nonland card> | UnlessPayer$ You | UnlessSwitched$ True SVar:DBImmediateTrigger:DB$ ImmediateTrigger | Execute$ TrigDealDmg | TriggerDescription$ You may discard a nonland card. When you do, CARDNAME deals 4 damage to target creature. | UnlessCost$ Discard<1/Card.nonLand/nonland card> | UnlessPayer$ You | UnlessSwitched$ True
SVar:TrigDealDmg:DB$ DealDamage | Cost$ Discard<1/Card.nonLand/nonland card> | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 4 | SpellDescription$ CARDNAME deals 4 damage to target creature. SVar:TrigDealDmg:DB$ DealDamage | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 4 | SpellDescription$ CARDNAME deals 4 damage to target creature.
Oracle:Draw two cards. Then you may discard a nonland card. When you do, Hypothesizzle deals 4 damage to target creature. Oracle:Draw two cards. Then you may discard a nonland card. When you do, Hypothesizzle deals 4 damage to target creature.

View File

@@ -3,7 +3,7 @@ ManaCost:2 G G
Types:Enchantment Types:Enchantment
T:Mode$ Drawn | ValidCard$ Card.YouOwn | Number$ 1 | Static$ True | Execute$ DBReveal | TriggerZones$ Battlefield | TriggerDescription$ Reveal the first card you draw each turn. Whenever you reveal a creature card this way, draw a card. T:Mode$ Drawn | ValidCard$ Card.YouOwn | Number$ 1 | Static$ True | Execute$ DBReveal | TriggerZones$ Battlefield | TriggerDescription$ Reveal the first card you draw each turn. Whenever you reveal a creature card this way, draw a card.
SVar:DBReveal:DB$ Reveal | Defined$ You | RevealDefined$ TriggeredCard | RememberRevealed$ True | SubAbility$ DBTrigger SVar:DBReveal:DB$ Reveal | Defined$ You | RevealDefined$ TriggeredCard | RememberRevealed$ True | SubAbility$ DBTrigger
SVar:DBTrigger:DB$ ImmediateTrigger | ConditionDefined$ Remembered | ConditionPresent$ Creature+YouCtrl | SubAbility$ DBCleanup | Execute$ TrigDraw | TriggerDescription$ Whenever you reveal a creature card this way, draw a card. SVar:DBTrigger:DB$ ImmediateTrigger | ConditionDefined$ Remembered | ConditionPresent$ Card.Creature+YouCtrl | SubAbility$ DBCleanup | Execute$ TrigDraw | TriggerDescription$ Whenever you reveal a creature card this way, draw a card.
SVar:TrigDraw:DB$Draw | NumCards$ 1 SVar:TrigDraw:DB$Draw | NumCards$ 1
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:Picture:http://www.wizards.com/global/images/magic/general/primitive_etchings.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/primitive_etchings.jpg

View File

@@ -1,12 +1,14 @@
Name:Sorcerous Spyglass Name:Sorcerous Spyglass
ManaCost:2 ManaCost:2
Types:Artifact Types:Artifact
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPeek | TriggerDescription$ As CARDNAME enters the battlefield, look at an opponent's hand, then choose any card name. K:ETBReplacement:Other:ChoosePlayer
SVar:TrigPeek:DB$ RevealHand | ValidTgts$ Opponent | TgtPrompt$ Select an opponent | SubAbility$ DBNameCard SVar:ChoosePlayer:DB$ ChoosePlayer | Defined$ You | Choices$ Player.Opponent | ChoiceTitle$ Choose an opponent to look at the hand: | SubAbility$ DBLook | SpellDescription$ As CARDNAME enters the battlefield, look at an opponent's hand, then choose any card name.
SVar:DBNameCard:DB$ NameCard | Defined$ You SVar:DBLook:DB$ RevealHand | Defined$ ChosenPlayer | SubAbility$ DBNameCard
SVar:DBNameCard:DB$ NameCard | Defined$ You | SubAbility$ DBClear
SVar:DBClear:DB$ Cleanup | ClearChosenPlayer$ True
S:Mode$ CantBeActivated | ValidCard$ Card.NamedCard | NonMana$ True | Description$ Activated abilities of sources with the chosen name can't be activated unless they're mana abilities. S:Mode$ CantBeActivated | ValidCard$ Card.NamedCard | NonMana$ True | Description$ Activated abilities of sources with the chosen name can't be activated unless they're mana abilities.
AI:RemoveDeck:Random AI:RemoveDeck:Random
# TODO: Might improve AI logic to support it (the AI needs to pick cards that actually have activated nonmana abilities on them) # TODO: Might improve AI logic to support it (the AI needs to pick cards that actually have activated nonmana abilities on them)
AI:RemoveDeck:All AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/sorcerous_spyglass.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/sorcerous_spyglass.jpg
Oracle:As Sorcerous Spyglass enters the battlefield, look at an opponent's hand, then choose any card name. Activated abilities of sources with the chosen name can't be activated unless they're mana abilities. Oracle:As Sorcerous Spyglass enters the battlefield, look at an opponent's hand, then choose any card name.\nActivated abilities of sources with the chosen name can't be activated unless they're mana abilities.

View File

@@ -1,7 +1,7 @@
Name:Tishana, Voice of Thunder Name:Tishana, Voice of Thunder
ManaCost:5 G U ManaCost:5 G U
Types:Legendary Creature Merfolk Shaman Types:Legendary Creature Merfolk Shaman
PT:0/0 PT:*/*
S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | References$ X | Description$ CARDNAME's power and toughness are each equal to the number of cards in your hand. S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | References$ X | Description$ CARDNAME's power and toughness are each equal to the number of cards in your hand.
S:Mode$ Continuous | Affected$ You | SetMaxHandSize$ Unlimited | Description$ You have no maximum hand size. S:Mode$ Continuous | Affected$ You | SetMaxHandSize$ Unlimited | Description$ You have no maximum hand size.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ When CARDNAME enters the battlefield, draw a card for each creature you control. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ When CARDNAME enters the battlefield, draw a card for each creature you control.

View File

@@ -0,0 +1,11 @@
Name:Ayara, First of Locthwain
ManaCost:B B B
Types:Legendary Creature Elf Noble
PT:2/3
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDrain | TriggerDescription$ Whenever CARDNAME or another black creature enters the battlefield under your control, each opponent loses 1 life and you gain 1 life.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Black+Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDrain | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another black creature enters the battlefield under your control, each opponent loses 1 life and you gain 1 life.
SVar:TrigDrain:DB$ LoseLife | Defined$ Player.Opponent | LifeAmount$ 1 | SubAbility$ DBGainLife
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 1
A:AB$ Draw | Cost$ T Sac<1/Creature.Other+Black/another black creature> | NumCards$ 1 | SpellDescription$ Draw a card.
AI:RemoveDeck:Random
Oracle:Whenever Ayara, First of Locthwain or another black creature enters the battlefield under your control, each opponent loses 1 life and you gain 1 life.\n{T}, Sacrifice another black creature: Draw a card.

View File

@@ -0,0 +1,7 @@
Name:Beloved Princess
ManaCost:W
Types:Creature Human Noble
PT:1/1
K:Lifelink
K:CantBeBlockedBy Creature.powerGE3
Oracle:Lifelink\nBeloved Princess can't be blocked by creatures with power 3 or greater.

View File

@@ -0,0 +1,8 @@
Name:Bog Naughty
ManaCost:3 B B
Types:Creature Faerie
PT:3/3
K:Flying
A:AB$ Pump | Cost$ 2 B Sac<1/Food> | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -3 | NumDef$ -3 | IsCurse$ True | SpellDescription$ Target creature gets -3/-3 until end of turn.
AI:RemoveDeck:All
Oracle:Flying\n{2}{B}, Sacrifice a Food: Target creature gets -3/-3 until end of turn.

View File

@@ -0,0 +1,7 @@
Name:Bramblefort Fink
ManaCost:1 G
Types:Creature Ouphe
PT:2/2
A:AB$ Animate | Cost$ 8 | Defined$ Self | Power$ 10 | Toughness$ 10 | IsPresent$ Planeswalker.YouCtrl+Oko | SpellDescription$ CARDNAME has base power and toughness 10/10 until end of turn. Activate this ability only if you control an Oko planeswalker.
AI:RemoveDeck:Random
Oracle:{8}: Bramblefort Fink has base power and toughness 10/10 until end of turn. Activate this ability only if you control an Oko planeswalker.

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