This commit is contained in:
Northmoc
2022-05-08 09:07:14 -04:00
32 changed files with 361 additions and 123 deletions

View File

@@ -398,7 +398,7 @@ public class PumpAi extends PumpAiBase {
if (!mandatory
&& !immediately
&& game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
&& (game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS) && !"AnyPhase".equals(sa.getParam("AILogic")))
&& !(sa.isCurse() && defense < 0)
&& !containsNonCombatKeyword(keywords)
&& !"UntilYourNextTurn".equals(sa.getParam("Duration"))

View File

@@ -275,7 +275,12 @@ public class GameAction {
lastKnownInfo = CardUtil.getLKICopy(c);
}
copied = CardFactory.copyCard(c, false);
// CR 707.12 casting of a card copy, don't copy it again
if (zoneTo.is(ZoneType.Stack) && c.isRealToken()) {
copied = c;
} else {
copied = CardFactory.copyCard(c, false);
}
if (zoneTo.is(ZoneType.Stack)) {
// when moving to stack, copy changed card information

View File

@@ -34,7 +34,7 @@ public class AbandonEffect extends SpellAbilityEffect {
if (sa.hasParam("RememberAbandoned")) {
source.addRemembered(source);
}
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
controller.getZone(ZoneType.Command).remove(source);
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);

View File

@@ -35,13 +35,13 @@ public class BalanceEffect extends SpellAbilityEffect {
Game game = activator.getGame();
String valid = sa.getParamOrDefault("Valid", "Card");
ZoneType zone = sa.hasParam("Zone") ? ZoneType.smartValueOf(sa.getParam("Zone")) : ZoneType.Battlefield;
int min = Integer.MAX_VALUE;
final FCollectionView<Player> players = game.getPlayersInTurnOrder();
final List<CardCollection> validCards = new ArrayList<>(players.size());
Map<Player, CardCollectionView> discardedMap = Maps.newHashMap();
for (int i = 0; i < players.size(); i++) {
// Find the minimum of each Valid per player
validCards.add(CardLists.getValidCards(players.get(i).getCardsIn(zone), valid, activator, source, sa));

View File

@@ -33,7 +33,7 @@ public class BidLifeEffect extends SpellAbilityEffect {
} else {
startBidding = 0;
}
if (sa.hasParam("OtherBidder")) {
bidPlayers.add(activator);
bidPlayers.addAll(AbilityUtils.getDefinedPlayers(host, sa.getParam("OtherBidder"), sa));
@@ -62,7 +62,7 @@ public class BidLifeEffect extends SpellAbilityEffect {
}
}
}
host.setChosenNumber(bid);
host.addRemembered(winner);
final SpellAbility action = sa.getAdditionalAbility("BidSubAbility");

View File

@@ -34,54 +34,85 @@ import forge.util.Localizer;
public class CountersPutEffect extends SpellAbilityEffect {
@Override
protected String getStackDescription(SpellAbility spellAbility) {
protected String getStackDescription(SpellAbility sa) {
final StringBuilder stringBuilder = new StringBuilder();
final Card card = spellAbility.getHostCard();
final Card card = sa.getHostCard();
final String who = sa.getActivatingPlayer().getName();
boolean pronoun = false;
final int amount = AbilityUtils.calculateAmount(card,
spellAbility.getParamOrDefault("CounterNum", "1"), spellAbility);
if (spellAbility.hasParam("CounterTypes")) {
stringBuilder.append(spellAbility.getActivatingPlayer()).append(" ");
String desc = spellAbility.getDescription();
if (desc.contains("Put")) {
desc = desc.substring(desc.indexOf("Put"), desc.indexOf(" on ") + 4)
.replaceFirst("Put", "puts");
if (sa.hasParam("IfDesc")) {
final String ifD = sa.getParam("IfDesc");
if (ifD.equals("True")) {
String ifDesc = sa.getDescription();
if (ifDesc.contains(",")) {
if (ifDesc.contains(" you ")) {
ifDesc = ifDesc.replaceFirst(" you ", " " + who + " ");
pronoun = true;
if (ifDesc.contains(" you ")) {
ifDesc = ifDesc.replaceAll(" you ", " they ");
}
if (ifDesc.contains(" your ")) {
ifDesc = ifDesc.replaceAll(" your ", " their ");
}
}
stringBuilder.append(ifDesc, 0, ifDesc.indexOf(",") + 1);
} else {
stringBuilder.append("[CountersPutEffect IfDesc parsing error]");
}
} else {
stringBuilder.append(ifD);
}
stringBuilder.append(desc).append(Lang.joinHomogenous(getTargets(spellAbility))).append(".");
stringBuilder.append(" ");
}
stringBuilder.append(pronoun ? who : "they").append(" ");
if (sa.hasParam("CounterTypes")) {
String desc = sa.getDescription();
if (desc.contains("Put ") && desc.contains(" on ")) {
desc = desc.substring(desc.indexOf("Put "), desc.indexOf(" on ") + 4)
.replaceFirst("Put ", "puts ");
}
stringBuilder.append(desc).append(Lang.joinHomogenous(getTargets(sa))).append(".");
return stringBuilder.toString();
}
// skip the StringBuilder if no targets are chosen ("up to" scenario)
if (spellAbility.usesTargeting()) {
final List<Card> targetCards = SpellAbilityEffect.getTargetCards(spellAbility);
if (sa.usesTargeting()) {
final List<Card> targetCards = SpellAbilityEffect.getTargetCards(sa);
if (targetCards.size() == 0) {
return stringBuilder.toString();
}
}
if (spellAbility.hasParam("Bolster")) {
stringBuilder.append("Bolster ").append(amount);
final int amount = AbilityUtils.calculateAmount(card,
sa.getParamOrDefault("CounterNum", "1"), sa);
if (sa.hasParam("Bolster")) {
stringBuilder.append("bolsters ").append(amount).append(".");
return stringBuilder.toString();
}
boolean divAsChoose = spellAbility.isDividedAsYouChoose();
boolean divAsChoose = sa.isDividedAsYouChoose();
final boolean divRandom = sa.hasParam("DividedRandomly");
if (divAsChoose) {
stringBuilder.append("Distribute ");
} else if (spellAbility.hasParam("DividedRandomly")) {
stringBuilder.append("Randomly distribute ");
stringBuilder.append(pronoun ? "distribute " : "distributes ");
} else if (divRandom) {
stringBuilder.append(pronoun ? "randomly distribute " : "randomly distributes ");
} else {
stringBuilder.append("Put ");
stringBuilder.append(pronoun ? "put " : "puts ");
}
if (spellAbility.hasParam("UpTo")) {
if (sa.hasParam("UpTo")) {
stringBuilder.append("up to ");
}
final String typeName = CounterType.getType(spellAbility.getParam("CounterType")).getName().toLowerCase();
final String typeName = CounterType.getType(sa.getParam("CounterType")).getName().toLowerCase();
stringBuilder.append(Lang.nounWithNumeralExceptOne(amount, typeName + " counter"));
stringBuilder.append(divAsChoose || spellAbility.hasParam("DividedRandomly") ? " among " : " on ");
stringBuilder.append(divAsChoose || divRandom ? " among " : " on ");
// special handling for multiple Defined
if (spellAbility.hasParam("Defined") && spellAbility.getParam("Defined").contains(" & ")) {
String[] def = spellAbility.getParam("Defined").split(" & ");
if (sa.hasParam("Defined") && sa.getParam("Defined").contains(" & ")) {
String[] def = sa.getParam("Defined").split(" & ");
for (int i = 0; i < def.length; i++) {
stringBuilder.append(AbilityUtils.getDefinedEntities(card, def[i], spellAbility).toString()
stringBuilder.append(AbilityUtils.getDefinedEntities(card, def[i], sa).toString()
.replaceAll("[\\[\\]]", ""));
if (i + 1 < def.length) {
stringBuilder.append(" and ");
@@ -89,12 +120,12 @@ public class CountersPutEffect extends SpellAbilityEffect {
}
}
// if use targeting we show all targets and corresponding counters
} else if (spellAbility.usesTargeting()) {
final List<Card> targetCards = SpellAbilityEffect.getTargetCards(spellAbility);
} else if (sa.usesTargeting()) {
final List<Card> targetCards = SpellAbilityEffect.getTargetCards(sa);
for (int i = 0; i < targetCards.size(); i++) {
Card targetCard = targetCards.get(i);
stringBuilder.append(targetCard);
Integer v = spellAbility.getDividedValue(targetCard);
Integer v = sa.getDividedValue(targetCard);
if (v != null) // fix null counter stack description
stringBuilder.append(" (").append(v).append(v == 1 ? " counter)" : " counters)");
@@ -104,8 +135,12 @@ public class CountersPutEffect extends SpellAbilityEffect {
stringBuilder.append(", ");
}
}
} else if (sa.hasParam("Choices")) {
int n = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("ChoiceAmount", "1"), sa);
String what = (sa.getParamOrDefault("ChoicesDesc", sa.getParam("Choices")));
stringBuilder.append(Lang.nounWithNumeralExceptOne(n, what));
} else {
final List<Card> targetCards = SpellAbilityEffect.getTargetCards(spellAbility);
final List<Card> targetCards = SpellAbilityEffect.getTargetCards(sa);
final Iterator<Card> it = targetCards.iterator();
while (it.hasNext()) {
final Card targetCard = it.next();
@@ -135,6 +170,8 @@ public class CountersPutEffect extends SpellAbilityEffect {
boolean existingCounter = sa.hasParam("CounterType") && sa.getParam("CounterType").equals("ExistingCounter");
boolean eachExistingCounter = sa.hasParam("EachExistingCounter");
boolean putOnEachOther = sa.hasParam("PutOnEachOther");
boolean putOnDefined = sa.hasParam("PutOnDefined");
if (sa.hasParam("Optional") && !pc.confirmAction
(sa, null, Localizer.getInstance().getMessage("lblDoYouWantPutCounter"))) {
@@ -153,7 +190,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
Iterables.addAll(tgtObjects, activator.getController().chooseCardsForEffect(leastToughness, sa,
Localizer.getInstance().getMessage("lblChooseACreatureWithLeastToughness"), 1, 1, false, params));
} else if (sa.hasParam("Choices") && counterType != null) {
} else if (sa.hasParam("Choices") && (counterType != null || putOnEachOther || putOnDefined)) {
ZoneType choiceZone = ZoneType.Battlefield;
if (sa.hasParam("ChoiceZone")) {
choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone"));
@@ -186,6 +223,11 @@ public class CountersPutEffect extends SpellAbilityEffect {
}
if ((sa.hasParam("ChoiceTitle") || sa.hasParam("SpecifyCounter")) && counterType != null) {
title += " (" + counterType.getName() + ")";
} else if (putOnEachOther || putOnDefined) {
title += Localizer.getInstance().getMessage("lblWithKindCounter");
if (putOnEachOther) {
title += " " + Localizer.getInstance().getMessage("lblEachOther");
}
}
Map<String, Object> params = Maps.newHashMap();
@@ -298,6 +340,10 @@ public class CountersPutEffect extends SpellAbilityEffect {
}
}
for (CounterType ct : counterTypes) {
if (sa.hasParam("AltChoiceForEach")) {
String typeChoices = sa.getParam("AltChoiceForEach") + "," + ct.toString();
ct = chooseTypeFromList(sa, typeChoices, obj, pc);
}
resolvePerType(sa, placer, ct, counterAmount, table, false);
}
} else {
@@ -319,7 +365,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
final List<CounterType> choices = Lists.newArrayList();
// get types of counters
for (CounterType ct : obj.getCounters().keySet()) {
if (obj.canReceiveCounters(ct)) {
if (obj.canReceiveCounters(ct) || putOnEachOther) {
choices.add(ct);
}
}
@@ -343,10 +389,30 @@ public class CountersPutEffect extends SpellAbilityEffect {
} else {
Map<String, Object> params = Maps.newHashMap();
params.put("Target", obj);
StringBuilder sb = new StringBuilder();
sb.append(Localizer.getInstance().getMessage("lblSelectCounterTypeAddTo") + " ");
sb.append(obj);
counterType = pc.chooseCounterType(choices, sa, sb.toString(), params);
String sb = Localizer.getInstance().getMessage("lblSelectCounterTypeAddTo") +
" " + (putOnEachOther ? Localizer.getInstance().getMessage("lblEachOther") : obj);
counterType = pc.chooseCounterType(choices, sa, sb, params);
}
if (putOnEachOther) {
List<Card> others = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield),
sa.getParam("PutOnEachOther"), activator, card, sa);
for (Card other : others) {
if (other.equals(obj)) {
continue;
}
Card otherGCard = game.getCardState(other, null);
otherGCard.addCounter(counterType, counterAmount, placer, table);
}
continue;
} else if (putOnDefined) {
List<Card> defs = AbilityUtils.getDefinedCards(card, sa.getParam("PutOnDefined"), sa);
for (Card c : defs) {
Card gCard = game.getCardState(c, null);
if (!sa.hasParam("OnlyNewKind") || gCard.getCounters(counterType) < 1) {
gCard.addCounter(counterType, counterAmount, placer, table);
}
}
continue;
}
}
@@ -528,7 +594,8 @@ public class CountersPutEffect extends SpellAbilityEffect {
CounterType counterType = null;
if (!sa.hasParam("EachExistingCounter") && !sa.hasParam("EachFromSource")
&& !sa.hasParam("UniqueType") && !sa.hasParam("CounterTypePerDefined")
&& !sa.hasParam("CounterTypes") && !sa.hasParam("ChooseDifferent")) {
&& !sa.hasParam("CounterTypes") && !sa.hasParam("ChooseDifferent")
&& !sa.hasParam("PutOnEachOther") && !sa.hasParam("PutOnDefined")) {
try {
counterType = chooseTypeFromList(sa, sa.getParam("CounterType"), null,
placer.getController());
@@ -596,7 +663,10 @@ public class CountersPutEffect extends SpellAbilityEffect {
List<CounterType> choices = Lists.newArrayList();
for (String s : list.split(",")) {
if (!s.equals("") && (!sa.hasParam("UniqueType") || obj.getCounters(CounterType.getType(s)) == 0)) {
choices.add(CounterType.getType(s));
CounterType type = CounterType.getType(s);
if (!choices.contains(type)) {
choices.add(type);
}
}
}
if (sa.hasParam("RandomType")) {

View File

@@ -92,6 +92,7 @@ public class Forge implements ApplicationListener {
public static String extrawide = "default";
public static float heigtModifier = 0.0f;
private static boolean isloadingaMatch = false;
public static boolean autoAIDeckSelection = false;
public static boolean showFPS = false;
public static boolean allowCardBG = false;
public static boolean altPlayerLayout = false;
@@ -189,6 +190,7 @@ public class Forge implements ApplicationListener {
textureFiltering = prefs.getPrefBoolean(FPref.UI_LIBGDX_TEXTURE_FILTERING);
showFPS = prefs.getPrefBoolean(FPref.UI_SHOW_FPS);
autoAIDeckSelection = prefs.getPrefBoolean(FPref.UI_AUTO_AIDECK_SELECTION);
altPlayerLayout = prefs.getPrefBoolean(FPref.UI_ALT_PLAYERINFOLAYOUT);
altZoneTabs = prefs.getPrefBoolean(FPref.UI_ALT_PLAYERZONETABS);
animatedCardTapUntap = prefs.getPrefBoolean(FPref.UI_ANIMATED_CARD_TAPUNTAP);

View File

@@ -92,7 +92,7 @@ public class SaveLoadScene extends UIScene {
previewImage.setVisible(true);
previewDate.setVisible(true);
if (header.saveDate != null)
previewDate.setText(DateFormat.getDateInstance().format(header.saveDate));
previewDate.setText(DateFormat.getDateInstance().format(header.saveDate)+"\n"+DateFormat.getTimeInstance(DateFormat.SHORT).format(header.saveDate));
else
previewDate.setText("");
}
@@ -305,7 +305,6 @@ public class SaveLoadScene extends UIScene {
dialog.getColor().a = 0;
previewImage = ui.findActor("preview");
previewDate = ui.findActor("saveDate");
previewBorder = ui.findActor("preview_border");
header = Controls.newLabel(Forge.getLocalizer().getMessage("lblSave"));
header.setAlignment(Align.center);
layout.add(header).pad(2).colspan(4).align(Align.center).expandX();

View File

@@ -48,7 +48,9 @@ public class GameHUD extends Stage {
instance = this;
this.gameStage = gameStage;
ui = new UIActor(Config.instance().getFile(Forge.isLandscapeMode()?"ui/hud.json":"ui/hud_portrait.json"));
ui = new UIActor(Config.instance().getFile(GuiBase.isAndroid()
? Forge.isLandscapeMode() ? "ui/hud_landscape.json" : "ui/hud_portrait.json"
: Forge.isLandscapeMode() ? "ui/hud.json" : "ui/hud_portrait.json"));
blank = ui.findActor("blank");
miniMap = ui.findActor("map");
@@ -144,12 +146,8 @@ public class GameHUD extends Stage {
float x=(c.x-miniMap.getX())/miniMap.getWidth();
float y=(c.y-miniMap.getY())/miniMap.getHeight();
float mMapX = ui.findActor("map").getX();
float mMapY = ui.findActor("map").getY();
float mMapT = ui.findActor("map").getTop();
float mMapR = ui.findActor("map").getRight();
//map bounds
if (c.x>=mMapX&&c.x<=mMapR&&c.y>=mMapY&&c.y<=mMapT) {
if (Controls.actorContainsVector(miniMap,c)) {
touchpad.setVisible(false);
if (MapStage.getInstance().isInMap())
return true;
@@ -163,10 +161,6 @@ public class GameHUD extends Stage {
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button)
{
return setPosition(screenX, screenY, pointer, button);
}
boolean setPosition(int screenX, int screenY, int pointer, int button) {
Vector2 c=new Vector2();
Vector2 touch =new Vector2();
screenToStageCoordinates(touch.set(screenX, screenY));
@@ -174,48 +168,31 @@ public class GameHUD extends Stage {
float x=(c.x-miniMap.getX())/miniMap.getWidth();
float y=(c.y-miniMap.getY())/miniMap.getHeight();
float uiX = gamehud.getX();
float uiY = gamehud.getY();
float uiTop = gamehud.getTop();
float uiRight = gamehud.getRight();
//gamehud bounds
if (c.x>=uiX&&c.x<=uiRight&&c.y>=uiY&&c.y<=uiTop) {
if (Controls.actorContainsVector(gamehud,c)) {
super.touchDown(screenX, screenY, pointer, button);
return true;
}
float mMapX = miniMap.getX();
float mMapY = miniMap.getY();
float mMapT = miniMap.getTop();
float mMapR = miniMap.getRight();
//map bounds
if (c.x>=mMapX&&c.x<=mMapR&&c.y>=mMapY&&c.y<=mMapT) {
if (Controls.actorContainsVector(miniMap,c)) {
if (MapStage.getInstance().isInMap())
return true;
if(Current.isInDebug())
WorldStage.getInstance().GetPlayer().setPosition(x*WorldSave.getCurrentSave().getWorld().getWidthInPixels(),y*WorldSave.getCurrentSave().getWorld().getHeightInPixels());
return true;
}
//display bounds
float displayX = ui.getX();
float displayY = ui.getY();
float displayT = ui.getTop();
float displayR = ui.getRight();
//menu Y bounds
float menuY = menuActor.getY();
//auto follow touchpad
if (GuiBase.isAndroid()) {
if (!(touch.x>=mMapX&&touch.x<=mMapR&&touch.y>=mMapY&&touch.y<=mMapT) // not inside map bounds
&& !(touch.x>=uiX&&touch.x<=uiRight&&touch.y>=menuY&&touch.y<=uiTop) //not inside gamehud bounds and menu Y bounds
&& (touch.x>=displayX&&touch.x<=displayR&&touch.y>=displayY&&touch.y<=displayT) //inside display bounds
if (!(Controls.actorContainsVector(miniMap,touch)) // not inside map bounds
&& !(Controls.actorContainsVector(gamehud,touch)) //not inside gamehud bounds
&& !(Controls.actorContainsVector(menuActor,touch)) //not inside menu button
&& !(Controls.actorContainsVector(deckActor,touch)) //not inside deck button
&& !(Controls.actorContainsVector(statsActor,touch)) //not inside stats button
&& !(Controls.actorContainsVector(inventoryActor,touch)) //not inside inventory button
&& (Controls.actorContainsVector(ui,touch)) //inside display bounds
&& pointer < 1) { //not more than 1 pointer
touchpad.setBounds(touch.x-TOUCHPAD_SCALE/2, touch.y-TOUCHPAD_SCALE/2, TOUCHPAD_SCALE, TOUCHPAD_SCALE);
touchpad.setVisible(true);
touchpad.setResetOnTouchUp(true);
if (!Forge.isLandscapeMode())
hideButtons();
hideButtons();
return super.touchDown(screenX, screenY, pointer, button);
}
}
@@ -292,12 +269,10 @@ public class GameHUD extends Stage {
return true;
}
if (keycode == Input.Keys.BACK) {
if (!Forge.isLandscapeMode()) {
menuActor.setVisible(!menuActor.isVisible());
statsActor.setVisible(!statsActor.isVisible());
inventoryActor.setVisible(!inventoryActor.isVisible());
deckActor.setVisible(!deckActor.isVisible());
}
menuActor.setVisible(!menuActor.isVisible());
statsActor.setVisible(!statsActor.isVisible());
inventoryActor.setVisible(!inventoryActor.isVisible());
deckActor.setVisible(!deckActor.isVisible());
}
return super.keyDown(keycode);
}

View File

@@ -30,7 +30,8 @@ public class Controls {
return new Rectangle(actor.getX(),actor.getY(),actor.getWidth(),actor.getHeight());
}
static public boolean actorContainsVector (Actor actor, Vector2 point) {
if (!actor.isVisible())
return false;
return getBoundingRect(actor).contains(point);
}

View File

@@ -199,7 +199,7 @@ public class FDeckChooser extends FScreen {
}
else {
int size = 0;
if (isAi && !isGeneratedDeck(selectedDeckType)) {
if (isAi && !isGeneratedDeck(selectedDeckType) && Forge.autoAIDeckSelection) {
AIDecks = lstDecks.getPool().toFlatList().parallelStream().filter(deckProxy -> deckProxy.getAI().inMainDeck == 0).collect(Collectors.toList());
size = AIDecks.size();
}

View File

@@ -610,6 +610,16 @@ public class SettingsPage extends TabPage<SettingsScreen> {
}
},4);
}
lstSettings.addItem(new BooleanSetting(FPref.UI_AUTO_AIDECK_SELECTION,
Forge.getLocalizer().getMessage("lblAutoAIDeck"),
Forge.getLocalizer().getMessage("nlAutoAIDeck")){
@Override
public void select() {
super.select();
//update
Forge.autoAIDeckSelection = FModel.getPreferences().getPrefBoolean(FPref.UI_AUTO_AIDECK_SELECTION);
}
},4);
lstSettings.addItem(new BooleanSetting(FPref.UI_SHOW_FPS,
Forge.getLocalizer().getMessage("lblShowFPSDisplay"),
Forge.getLocalizer().getMessage("nlShowFPSDisplay")){

View File

@@ -0,0 +1,114 @@
{
"width": 480,
"height": 270,
"yDown": true,
"elements": [
{
"type": "Image",
"name": "gamehud",
"width": 64,
"height": 104,
"image": "ui/hud_portrait.png",
"x": 416,
"y": 0
},
{
"type": "Image",
"name": "map",
"width": 80,
"height": 80,
"x": 0,
"y": 0
},
{
"type": "Image",
"name": "mapborder",
"image": "ui/minimap.png",
"width": 80,
"height": 80,
"x": 0,
"y": 0
},
{
"type": "Image",
"name": "blank",
"image": "ui/blank.png",
"width": 46,
"height": 46,
"x": 425,
"y": 10
},
{
"type": "Image",
"name": "avatar",
"width": 46,
"height": 46,
"x": 425,
"y": 10
},
{
"type": "Image",
"name": "avatarborder",
"image": "ui/avatarhud.png",
"width": 46,
"height": 46,
"x": 425,
"y": 10
},
{
"type": "Label",
"name": "lifePoints",
"font": "default",
"width": 64,
"height": 16,
"x": 442,
"y": 64
},
{
"type": "Label",
"name": "money",
"font": "default",
"width": 64,
"height": 16,
"x": 442,
"y": 82
},
{
"type": "TextButton",
"name": "deck",
"text": "Deck",
"width": 64,
"height": 36,
"x": 416,
"y": 106
},
{
"type": "TextButton",
"name": "inventory",
"text": "Inventory",
"width": 64,
"height": 36,
"x": 416,
"y": 146
},
{
"type": "TextButton",
"name": "statistic",
"text": "Status",
"width": 64,
"height": 36,
"x": 416,
"y": 186
},
{
"type": "TextButton",
"name": "menu",
"text": "Menu",
"width": 64,
"height": 36,
"x": 416,
"y": 226
}
]
}

View File

@@ -81,7 +81,7 @@
"width": 64,
"height": 32,
"x": 206,
"y": 106
"y": 306
},
{
"type": "TextButton",
@@ -90,7 +90,7 @@
"width": 64,
"height": 32,
"x": 206,
"y": 146
"y": 346
},
{
@@ -100,7 +100,7 @@
"width": 64,
"height": 32,
"x": 206,
"y": 186
"y": 386
},
{
"type": "TextButton",
@@ -109,7 +109,7 @@
"width": 64,
"height": 32,
"x": 206,
"y": 226
"y": 426
}
]
}

View File

@@ -20,33 +20,24 @@
{
"type": "Image",
"image": "ui/blank.png",
"width": 96,
"height": 54,
"x": 370,
"y": 30
},
{
"type": "Image",
"name" : "preview_border",
"image": "ui/avatarhud.png",
"width": 96,
"height": 54,
"x": 370,
"y": 30
"width": 100,
"height": 100,
"x": 368,
"y": 22
},
{
"type": "Image",
"name": "preview",
"width": 86,
"height": 48,
"x": 376,
"y": 33
"width": 96,
"height": 96,
"x": 370,
"y": 24
},
{
"type": "Label",
"name": "saveDate",
"x": 376,
"y": 85,
"x": 390,
"y": 125,
"width": 86,
"height": 32
},
@@ -57,7 +48,7 @@
"width": 100,
"height": 30,
"x": 368,
"y": 125
"y": 160
},
{
"type": "TextButton",
@@ -66,7 +57,7 @@
"width": 100,
"height": 30,
"x": 368,
"y": 195
"y": 220
},
{
"type": "Table",

View File

@@ -37,7 +37,7 @@
"type": "Label",
"name": "saveDate",
"x": 70,
"y": 4,
"y": 40,
"width": 96,
"height": 16
},

View File

@@ -0,0 +1,8 @@
Name:Citadel Gate
ManaCost:no cost
Types:Land Gate
K:CARDNAME enters the battlefield tapped.
K:ETBReplacement:Other:ChooseColor
SVar:ChooseColor:DB$ ChooseColor | Defined$ You | Exclude$ white | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color other than white.
A:AB$ Mana | Cost$ T | Produced$ Combo W Chosen | SpellDescription$ Add {W} or one mana of the chosen color.
Oracle:Citadel Gate enters the battlefield tapped.\nAs Citadel Gate enters the battlefield, choose a color other than white.\n{T}: Add {W} or one mana of the chosen color.

View File

@@ -0,0 +1,6 @@
Name:Summon Undead
ManaCost:4 B
Types:Sorcery
A:SP$ Mill | NumCards$ 3 | Defined$ You | Optional$ True | SubAbility$ DBChangeZone | SpellDescription$ You may mill three cards. Then return a creature card from your graveyard to the battlefield. (To mill a card, put the top card of your library into your graveyard.)
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouOwn | ChangeTypeDesc$ creature | ChangeNum$ 1 | Hidden$ True | Mandatory$ True
Oracle:You may mill three cards. Then return a creature card from your graveyard to the battlefield. (To mill a card, put the top card of your library into your graveyard.)

View File

@@ -1,8 +1,8 @@
Name:Unbreakable Formation
ManaCost:2 W
Types:Instant
A:SP$ PumpAll | Cost$ 2 W | ValidCards$ Creature.YouCtrl | KW$ Indestructible | SubAbility$ DBAddendum | SpellDescription$ Creatures you control gain indestructible until end of turn.
A:SP$ PumpAll | ValidCards$ Creature.YouCtrl | KW$ Indestructible | SubAbility$ DBAddendum | SpellDescription$ Creatures you control gain indestructible until end of turn.
SVar:DBAddendum:DB$ PumpAll | ValidCards$ Creature.YouCtrl | KW$ Vigilance | ConditionPlayerTurn$ True | ConditionPhases$ Main1,Main2 | ConditionDefined$ Self | ConditionPresent$ Card.wasCast | SubAbility$ DBPutCounters | SpellDescription$ Addendum — If you cast this spell during your main phase, put a +1/+1 counter on each of those creatures and they gain vigilance until end of turn.
SVar:DBPutCounters:DB$ PutCounterAll | ValidCards$ Creature.YouCtrl | ConditionPlayerTurn$ True | ConditionPhases$ Main1,Main2 | ConditionDefined$ Self | ConditionPresent$ Card.wasCast | CounterType$ P1P1 | CounterNum$ 1
DeckHas:Ability$LifeGain|Counters
DeckHas:Ability$Counters
Oracle:Creatures you control gain indestructible until end of turn.\nAddendum — If you cast this spell during your main phase, put a +1/+1 counter on each of those creatures and they gain vigilance until end of turn.

View File

@@ -0,0 +1,10 @@
Name:Aven Courier
ManaCost:1 U
Types:Creature Bird Advisor
PT:1/1
K:Flying
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME attacks, choose a counter on a permanent you control. Put a counter of that kind on target permanent you control if it doesn't have a counter of that kind on it.
SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Permanent.YouCtrl | TgtPrompt$ Select target permanent you control | CounterType$ ExistingCounter | Choices$ Permanent.YouCtrl+HasCounters | PutOnDefined$ Targeted | OnlyNewKind$ True
DeckNeeds:Ability$Counters
SVar:HasAttackEffect:TRUE
Oracle:Flying\nWhenever Aven Courier attacks, choose a counter on a permanent you control. Put a counter of that kind on target permanent you control if it doesn't have a counter of that kind on it.

View File

@@ -0,0 +1,10 @@
Name:Bribe Taker
ManaCost:5 G
Types:Creature Rhino Warrior
PT:6/6
K:Trample
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPutCounter | TriggerDescription$ When CARDNAME enters the battlefield, for each kind of counter on permanents you control, you may put your choice of a +1/+1 counter or a counter of that kind on CARDNAME.
SVar:TrigPutCounter:DB$ PutCounter | CounterTypes$ EachType_Permanent.YouCtrl | AltChoiceForEach$ P1P1
DeckNeeds:Ability$Counters
DeckHas:Ability$Counters
Oracle:Trample\nWhen Bribe Taker enters the battlefield, for each kind of counter on permanents you control, you may put your choice of a +1/+1 counter or a counter of that kind on Bribe Taker.

View File

@@ -0,0 +1,8 @@
Name:Contractual Safeguard
ManaCost:2 W
Types:Instant
A:SP$ PutCounter | Choices$ Creature.YouCtrl | ChoicesDesc$ creature they control | CounterType$ SHIELD | ConditionPlayerTurn$ True | ConditionPhases$ Main1,Main2 | ConditionDefined$ Self | ConditionPresent$ Card.wasCast | SubAbility$ DBPutCounter | IfDesc$ True | SpellDescription$ Addendum — If you cast this spell during your main phase, put a shield counter on a creature you control. (If it would be dealt damage or destroyed, remove a shield counter from it instead.)
SVar:DBPutCounter:DB$ PutCounter | CounterType$ ExistingCounter | Choices$ Creature.YouCtrl+HasCounters | PutOnEachOther$ Creature.YouCtrl | StackDescription$ {p:You} chooses a kind of counter on a creature they control, and puts a counter of that kind on each other creature they control. | SpellDescription$ Choose a kind of counter on a creature you control. Put a counter of that kind on each other creature you control.
DeckHas:Ability$Counters
DeckHints:Ability$Counters
Oracle:Addendum — If you cast this spell during your main phase, put a shield counter on a creature you control. (If it would be dealt damage or destroyed, remove a shield counter from it instead.)\nChoose a kind of counter on a creature you control. Put a counter of that kind on each other creature you control.

View File

@@ -1,8 +1,7 @@
Name:Witness the Future
ManaCost:2 U
Types:Sorcery
A:SP$ Pump | ValidTgts$ Player | TgtPrompt$ Select target player | SubAbility$ DBChangeZone | StackDescription$ {p:Targeted} | SpellDescription$ Target player
A:SP$ Pump | ValidTgts$ Player | TgtPrompt$ Select target player | SubAbility$ DBChangeZone | AILogic$ AnyPhase | StackDescription$ {p:Targeted} | SpellDescription$ Target player
SVar:DBChangeZone:DB$ ChangeZone | TargetMin$ 0 | TargetMax$ 4 | TargetsWithDefinedController$ ParentTarget | Origin$ Graveyard | Destination$ Library | Shuffle$ True | TgtPrompt$ Select up to four target cards | ValidTgts$ Card | SubAbility$ DBDig | StackDescription$ SpellDescription | SpellDescription$ shuffles up to four target cards from their graveyard into their library.
SVar:DBDig:DB$ Dig | DigNum$ 4 | ChangeNum$ 1 | RestRandomOrder$ True | StackDescription$ SpellDescription | SpellDescription$ You look at the top four cards of your library, then put one of those cards into your hand and the rest on the bottom of your library in a random order.
AI:RemoveDeck:All
Oracle:Target player shuffles up to four target cards from their graveyard into their library. You look at the top four cards of your library, then put one of those cards into your hand and the rest on the bottom of your library in a random order.

View File

@@ -521,6 +521,7 @@ ScryfallCode=SLD
587 R Spellskite @Thomas M. Baxa
588 R Sphere of Safety @Johannes Voss
589 R Arcane Signet @Dan Frazier
590 R Lurking Crocodile @Crocodile Jackson
591 R Crash Through @Tyler Walpole
593 R Persistent Petitioners @Brandi Milne
596 R Persistent Petitioners @Crom

View File

@@ -130,6 +130,8 @@ lblPreferredArt=Kartenbild-Präferenz
nlPreferredArt=Gibt an, welche Grafik für Karten ausgewählt werden soll, wenn keine Edition angegeben ist.
lblPrefArtExpansionOnly=Kartenbilder aus Haupt-, Erweiterungs- und Reprint-Sets bevorzugen
nlPrefArtExpansionOnly=Bevorzugt, wann immer möglich, Kartenbilder aus Haupt-, Erweiterungs- und Reprint-Sets (z. B. keine Promo, keine Online-Editionen).
lblAutoAIDeck=Aktivieren Sie die automatische AI -Deckauswahl
nlAutoAIDeck=Wenn es aktiviert ist, werden KI -kompatible Decks automatisch für den AI -Player ausgewählt, wenn das zufällige Deck gedrückt wird (wenn Sie eine Leistungsprobleme haben, deaktivieren Sie diese Option).
lblSmartCardArtOpt=Aktiviert die intelligente Auswahl für Kartenbilder in Decks
nlSmartCardArtOpt=Wenn diese Option aktiviert ist, werden Kartenbilder in Decks automatisch optimiert, um mit Kartenrahmen, Editionen und mehrfachen Bildvarianten zusammenzupassen.
nlSmartCardArtOptNote=HINWEIS: Diese Option wirkt sich nur auf Karten aus, die keine angegebene Edition haben. Andere Karten bleiben unverändert. Warnung: Experimentell!!!
@@ -1904,6 +1906,8 @@ lblChooseProliferateTarget=Wähle eine beliebige Anzahl bleibender Karten und/od
lblDoYouWantPutCounter=Möchtest du die Marke legen?
lblChooseACreatureWithLeastToughness=Wähle eine Kreatur mit der geringsten Widerstandskraft
lblSelectCounterTypeAddTo=Wähle Markentyp zum Hinzufügen
lblWithKindCounter=with the kind of counter you want to put on
lblEachOther=each other creature you control
lblSelectCounterType=Wähle Markentyp
lblHowManyCountersThis=Wie viele Marken möchtest du auf {0} legen?
lblChooseAnOpponent=Wähle Gegner

View File

@@ -131,6 +131,8 @@ lblPreferredArt=Card Art Preference
nlPreferredArt=Specifies which Card Art should be selected when no edition is specified.
lblPrefArtExpansionOnly=Prefer Card Art from Core, Expansions, and Reprint Sets
nlPrefArtExpansionOnly=Whenever possible, prefer card arts gathered from Core, Expansion, and Reprint Sets (e.g. No Promo, No Online Editions).
lblAutoAIDeck=Enable Automatic AI Deck Selection
nlAutoAIDeck=If enabled, AI Compatible Decks will be automatically selected for AI Player when Random Deck is pressed (If you have performance issue, disable this option).
lblSmartCardArtOpt=Enable Smart Selection for Card Art in Decks
nlSmartCardArtOpt=If enabled, Card Art in Decks will be automatically optimized to match up with card frames, editions and multiple art illustrations.
nlSmartCardArtOptNote=NOTE: This option will only affect cards that have no specified edition. Other cards will be kept unchanged. (Warning: Experimental)
@@ -1905,6 +1907,8 @@ lblChooseProliferateTarget=Choose any number of permanents and/or players for pr
lblDoYouWantPutCounter=Do you want to put the counter?
lblChooseACreatureWithLeastToughness=Choose a creature with the least toughness
lblSelectCounterTypeAddTo=Select counter type to add to
lblWithKindCounter=with the kind of counter you want to put on
lblEachOther=each other creature you control
lblSelectCounterType=Select counter type
lblHowManyCountersThis=How many counters do you want to put on {0}?
lblChooseAnOpponent=Choose an opponent

View File

@@ -131,6 +131,8 @@ lblPreferredArt=Preferencia de arte de carta
nlPreferredArt=Especifica qué arte debe seleccionarse para las cartas cuando no se especifica ninguna edición.
lblPrefArtExpansionOnly=Prefiere el arte de la carta de los conjuntos básicos, de expansión y de reimpresión
nlPrefArtExpansionOnly=Siempre que sea posible, prefiera las artes de las cartas recopiladas de los conjuntos básicos, de expansión y de reimpresión (por ejemplo, sin promociones, sin Online ediciones).
lblAutoAIDeck=Habilitar la selección automática de mazo de AI
nlAutoAIDeck=Si está habilitado, las cubiertas compatibles con AI se seleccionarán automáticamente para el reproductor AI cuando se presiona el mazo aleatorio (si tiene un problema de rendimiento, deshabilite esta opción).
lblSmartCardArtOpt=Habilitar la selección inteligente para el arte de la carta en los mazos
nlSmartCardArtOpt=Si está habilitado, Card Art in Decks se optimizará automáticamente para que coincida con marcos de cartas, ediciones y múltiples ilustraciones artísticas.
nlSmartCardArtOptNote=NOTA: Esta opción solo afectará a las cartas que no tengan una edición especificada. Las demás cartas se mantendrán sin cambios. (Advertencia: experimental)
@@ -1903,6 +1905,8 @@ lblChooseProliferateTarget=Elige cualquier número de permanentes y/o jugadores
lblDoYouWantPutCounter=¿Quieres poner el contador?
lblChooseACreatureWithLeastToughness=Elige una criatura con la menor resistencia
lblSelectCounterTypeAddTo=Selecciona el tipo de contador para añadirlo a
lblWithKindCounter=with the kind of counter you want to put on
lblEachOther=each other creature you control
lblSelectCounterType=Selecciona el tipo de contador
lblHowManyCountersThis=¿Cuántos contadores quieres poner en {0}?
lblChooseAnOpponent=Elige un adversario

View File

@@ -130,6 +130,8 @@ lblPreferredArt=Preferenza per Illustrazione delle Carte
nlPreferredArt=Specifica quale illustrazione preferire per le carte, quando nessuna edizione è specificata.
lblPrefArtExpansionOnly=Seleziona esclusivamente carte da Set Base, Espansioni, e Set Ristampa
nlPrefArtExpansionOnly=Quando possibile, seleziona l\'illustrazione di una carta esclusivamente da da Set Base, Espansioni, o Set Ristampa (e.g. No Set Promo, No Set Online).
lblAutoAIDeck=Abilita selezione automatica del mazzo AI
nlAutoAIDeck=Se abilitato, i mazzi compatibili AI verranno automaticamente selezionati per AI Player quando viene premuto Random Deck (se hai un problema di prestazioni, disabilita questa opzione).
lblSmartCardArtOpt=Abilita la selezione intelligente delle illustrazioni per le carte nei mazzi.
nlSmartCardArtOpt=Se abilitato, l'illustrazione delle carte in un mazzo sarà automatizzata per allineare i frame, le espansioni, e le illustrazioni multiple.
nlSmartCardArtOptNote=NOTA: Questa opzione sarà applicata esclusivamente alle carte in un mazzo che non hanno una edizione specificata. Le altre carte rimarranno inalterate. (Attenzione: Sperimentale)
@@ -1902,6 +1904,8 @@ lblChooseProliferateTarget=Scegli un numero qualsiasi di permanenti e/o giocator
lblDoYouWantPutCounter=Vuoi aggiungere il segnalino?
lblChooseACreatureWithLeastToughness=Scegli una creatura con la minor costituzione
lblSelectCounterTypeAddTo=Scegli il tipo di segnalino da aggiungere
lblWithKindCounter=with the kind of counter you want to put on
lblEachOther=each other creature you control
lblSelectCounterType=Scegli il tipo di segnalino
lblHowManyCountersThis=Quanti segnalini vuoi aggiungere a {0}?
lblChooseAnOpponent=Scegli un avversario

View File

@@ -131,6 +131,8 @@ lblPreferredArt=カードアートの好み
nlPreferredArt=エディションが指定されていない場合にカードに選択するアートを指定します。
lblPrefArtExpansionOnly=コア、拡張、および再版セットからカードアートを好む
nlPrefArtExpansionOnly=可能な限り、コア、拡張、および再版セットから収集されたカードアートを優先します(例:プロモーションなし、オンライン版なし)。
lblAutoAIDeck=自動AIデッキの選択を有効にします
nlAutoAIDeck=有効にすると、ランダムデッキが押されたときにAI互換性のあるデッキがAIプレーヤーに対して自動的に選択されますパフォーマンスの問題がある場合は、このオプションを無効にします
lblSmartCardArtOpt=デッキのカードアートのスマートセレクションを有効にする
nlSmartCardArtOpt=有効にすると、デッキのカードアートは、カードフレーム、エディション、複数のアートイラストと一致するように自動的に最適化されます。
nlSmartCardArtOptNote=注:このオプションは、エディションが指定されていないカードにのみ影響します。 他のカードは変更されません。 (警告:実験的)
@@ -1902,6 +1904,8 @@ lblChooseProliferateTarget=増殖を行う望む数のパーマネントやプ
lblDoYouWantPutCounter=カウンターを置きますか?
lblChooseACreatureWithLeastToughness=タフネスが一番低いクリーチャーを選ぶ
lblSelectCounterTypeAddTo=置けるカウンターの種類を選ぶ
lblWithKindCounter=with the kind of counter you want to put on
lblEachOther=each other creature you control
lblSelectCounterType=Select counter type
lblHowManyCounters={0}に何個のカウンターを置きますか?
lblChooseAnOpponent=対戦相手一人を選ぶ

View File

@@ -132,6 +132,8 @@ lblPreferredArt=Preferência da Arte na Carta
nlPreferredArt=Define qual Arte da Carta a ser usada quando nenhuma edição é especificada.
lblPrefArtExpansionOnly=Preferir a Arte das Coleções Core, Expansões e Reimpressões
nlPrefArtExpansionOnly=Sempre que possível, prefira artes das cartas das Coleções Core, Expansão e Reimpressão (por exemplo, Sem Promo, Sem Edição Online).
lblAutoAIDeck=Ativar seleção automática de deck AI
nlAutoAIDeck=Se ativado, os decks compatíveis com AI serão selecionados automaticamente para o player de IA quando o deck aleatório for pressionado (se você tiver um problema de desempenho, desative esta opção).
lblSmartCardArtOpt=Ativar Seleção Inteligente de Arte de Cartas em Decks
nlSmartCardArtOpt=Se ativado, a Arte da Carta em Decks será automaticamente otimizada para combinar com as ilustrações do quadro da carta, edições e múltiplas artes.
nlSmartCardArtOptNote=NOTA\: Esta opção afetará apenas cartas que não têm edição especificada. As demais serão mantidas inalteradas. (Atenção\: Experimental)
@@ -1964,6 +1966,8 @@ lblChooseProliferateTarget=Escolha qualquer número de permanentes e/ou jogadore
lblDoYouWantPutCounter=Você quer colocar o marcador?
lblChooseACreatureWithLeastToughness=Escolha uma criatura com a menor resistência
lblSelectCounterTypeAddTo=Selecione o tipo de marcador para adicionar a
lblWithKindCounter=with the kind of counter you want to put on
lblEachOther=each other creature you control
lblSelectCounterType=Selecione o tipo de marcador
lblHowManyCountersThis=Quantos marcadores você quer colocar em {0}?
lblChooseAnOpponent=Escolha um adversário

View File

@@ -131,6 +131,8 @@ lblPreferredArt=卡片艺术偏好
nlPreferredArt=指定在未指定版本时应为卡片选择哪种艺术。
lblPrefArtExpansionOnly=首选核心、扩展和重印套装中的卡片艺术
nlPrefArtExpansionOnly=只要有可能,就更喜欢从核心、扩展和重印套装中收集的卡片艺术(例如,无促销、无在线版本)。
lblAutoAIDeck=启用自动AI甲板选择
nlAutoAIDeck=如果启用了当按下随机甲板时将自动选择AI兼容甲板如果您有性能问题请禁用此选项
lblSmartCardArtOpt=为卡组中的卡片艺术启用智能选择
nlSmartCardArtOpt=如果启用,牌组中的卡片艺术将自动优化以匹配卡片框架、版本和多个艺术插图。
nlSmartCardArtOptNote=注意:此选项只会影响没有指定版本的卡。 其他卡将保持不变。 (警告:实验性)
@@ -1906,6 +1908,8 @@ lblChooseProliferateTarget=选择任意数量的永久物和或牌手进行增
lblDoYouWantPutCounter=你想要放置指示物吗?
lblChooseACreatureWithLeastToughness=选择防御力最小的生物
lblSelectCounterTypeAddTo=选择指示物类型以添加到
lblWithKindCounter=with the kind of counter you want to put on
lblEachOther=each other creature you control
lblSelectCounterType=选择指示物类别
lblHowManyCountersThis=你想要在{0}上放置多少个指示物?
lblChooseAnOpponent=选择一个对手

View File

@@ -85,6 +85,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
UI_ENABLE_ONLINE_IMAGE_FETCHER ("false"),
UI_PREFERRED_ART("LATEST_ART_ALL_EDITIONS"),
UI_SMART_CARD_ART("false"),
UI_AUTO_AIDECK_SELECTION("true"),
UI_DISABLE_CARD_IMAGES ("false"),
UI_IMAGE_CACHE_MAXIMUM("400"),
UI_OVERLAY_FOIL_EFFECT ("true"),