Merge remote-tracking branch 'upstream/master' into adventureupdatee

This commit is contained in:
Simisays
2023-03-25 08:51:17 +01:00
58 changed files with 252 additions and 104 deletions

View File

@@ -35,16 +35,11 @@ import forge.util.TextUtil;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
public class AiCostDecision extends CostDecisionMakerBase { public class AiCostDecision extends CostDecisionMakerBase {
private final SpellAbility ability;
private final Card source;
private final CardCollection discarded; private final CardCollection discarded;
private final CardCollection tapped; private final CardCollection tapped;
public AiCostDecision(Player ai0, SpellAbility sa, final boolean effect) { public AiCostDecision(Player ai0, SpellAbility sa, final boolean effect) {
super(ai0, effect); super(ai0, effect, sa, sa.getHostCard());
ability = sa;
source = ability.getHostCard();
discarded = new CardCollection(); discarded = new CardCollection();
tapped = new CardCollection(); tapped = new CardCollection();

View File

@@ -26,7 +26,7 @@ public class CharmAi extends SpellAbilityAi {
@Override @Override
protected boolean checkApiLogic(Player ai, SpellAbility sa) { protected boolean checkApiLogic(Player ai, SpellAbility sa) {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
List<AbilitySub> choices = CharmEffect.makePossibleOptions(sa, false); List<AbilitySub> choices = CharmEffect.makePossibleOptions(sa);
final int num; final int num;
final int min; final int min;

View File

@@ -943,7 +943,6 @@ public class Game {
public GameStage getAge() { public GameStage getAge() {
return age; return age;
} }
public void setAge(GameStage value) { public void setAge(GameStage value) {
age = value; age = value;
} }

View File

@@ -20,7 +20,7 @@ import forge.util.collect.FCollection;
public class CharmEffect extends SpellAbilityEffect { public class CharmEffect extends SpellAbilityEffect {
public static List<AbilitySub> makePossibleOptions(final SpellAbility sa, boolean forDesc) { public static List<AbilitySub> makePossibleOptions(final SpellAbility sa) {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
List<String> restriction = null; List<String> restriction = null;
@@ -30,7 +30,7 @@ public class CharmEffect extends SpellAbilityEffect {
List<AbilitySub> choices = Lists.newArrayList(sa.getAdditionalAbilityList("Choices")); List<AbilitySub> choices = Lists.newArrayList(sa.getAdditionalAbilityList("Choices"));
if (!forDesc) { if (source.getZone() != null) {
List<AbilitySub> toRemove = Lists.newArrayList(); List<AbilitySub> toRemove = Lists.newArrayList();
for (AbilitySub ch : choices) { for (AbilitySub ch : choices) {
// 603.3c If one of the modes would be illegal, that mode can't be chosen. // 603.3c If one of the modes would be illegal, that mode can't be chosen.
@@ -55,7 +55,7 @@ public class CharmEffect extends SpellAbilityEffect {
public static String makeFormatedDescription(SpellAbility sa) { public static String makeFormatedDescription(SpellAbility sa) {
Card source = sa.getHostCard(); Card source = sa.getHostCard();
List<AbilitySub> list = CharmEffect.makePossibleOptions(sa, true); List<AbilitySub> list = CharmEffect.makePossibleOptions(sa);
final int num; final int num;
boolean additionalDesc = sa.hasParam("AdditionalDescription"); boolean additionalDesc = sa.hasParam("AdditionalDescription");
boolean optional = sa.hasParam("Optional"); boolean optional = sa.hasParam("Optional");
@@ -169,7 +169,7 @@ public class CharmEffect extends SpellAbilityEffect {
//this resets all previous choices //this resets all previous choices
sa.setSubAbility(null); sa.setSubAbility(null);
List<AbilitySub> choices = makePossibleOptions(sa, false); List<AbilitySub> choices = makePossibleOptions(sa);
// Entwine does use all Choices // Entwine does use all Choices
if (sa.isEntwine()) { if (sa.isEntwine()) {

View File

@@ -176,7 +176,6 @@ public class CountersPutEffect extends SpellAbilityEffect {
final Player activator = sa.getActivatingPlayer(); final Player activator = sa.getActivatingPlayer();
final PlayerController pc = activator.getController(); final PlayerController pc = activator.getController();
final boolean etbcounter = sa.hasParam("ETB"); final boolean etbcounter = sa.hasParam("ETB");
final int max = sa.hasParam("MaxFromEffect") ? Integer.parseInt(sa.getParam("MaxFromEffect")) : -1;
boolean existingCounter = sa.hasParam("CounterType") && sa.getParam("CounterType").equals("ExistingCounter"); boolean existingCounter = sa.hasParam("CounterType") && sa.getParam("CounterType").equals("ExistingCounter");
boolean eachExistingCounter = sa.hasParam("EachExistingCounter"); boolean eachExistingCounter = sa.hasParam("EachExistingCounter");
@@ -453,10 +452,6 @@ public class CountersPutEffect extends SpellAbilityEffect {
} }
counterAmount = sa.usesTargeting() && sa.isDividedAsYouChoose() ? sa.getDividedValue(gameCard) counterAmount = sa.usesTargeting() && sa.isDividedAsYouChoose() ? sa.getDividedValue(gameCard)
: counterAmount; : counterAmount;
if (max != -1) {
counterAmount = Math.max(Math.min(max - gameCard.getCounters(counterType), counterAmount),
0);
}
if (sa.hasParam("UpTo")) { if (sa.hasParam("UpTo")) {
int min = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("UpToMin", "0"), sa); int min = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("UpToMin", "0"), sa);
Map<String, Object> params = Maps.newHashMap(); Map<String, Object> params = Maps.newHashMap();

View File

@@ -526,7 +526,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
if (state == CardStateName.FaceDown) { if (state == CardStateName.FaceDown) {
view.updateHiddenId(game.nextHiddenCardId()); view.updateHiddenId(game.nextHiddenCardId());
} }
game.fireEvent(new GameEventCardStatsChanged(this, true)); //ensure stats updated for new characteristics game.fireEvent(new GameEventCardStatsChanged(this)); //ensure stats updated for new characteristics
} }
} }
return true; return true;
@@ -1427,6 +1427,10 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
@Override @Override
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) { public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
int addAmount = n; int addAmount = n;
// Rules say it is only a SBA, but is it checked there too?
if (counterType.is(CounterEnumType.DREAM) && hasKeyword("CARDNAME can't have more than seven dream counters on it.")) {
addAmount = Math.min(addAmount, 7 - getCounters(CounterEnumType.DREAM));
}
if (addAmount <= 0 || !canReceiveCounters(counterType)) { if (addAmount <= 0 || !canReceiveCounters(counterType)) {
// As per rule 107.1b // As per rule 107.1b
return; return;
@@ -7115,8 +7119,12 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
public void resetChosenModeTurn() { public void resetChosenModeTurn() {
boolean updateView = !chosenModesTurn.isEmpty() || !chosenModesTurnStatic.isEmpty();
chosenModesTurn.clear(); chosenModesTurn.clear();
chosenModesTurnStatic.clear(); chosenModesTurnStatic.clear();
if (updateView) {
updateAbilityTextForView();
}
} }
public int getPlaneswalkerAbilityActivated() { public int getPlaneswalkerAbilityActivated() {

View File

@@ -984,11 +984,24 @@ public class CardProperty {
if (card.getTurnInZone() <= sourceController.getLastTurnNr()) { if (card.getTurnInZone() <= sourceController.getLastTurnNr()) {
return false; return false;
} }
} else if (property.equals("ThisTurnEntered")) { } else if (property.startsWith("ThisTurnEntered")) {
// only check if it entered the Zone this turn // only check if it entered the Zone this turn
if (card.getTurnInZone() != game.getPhaseHandler().getTurn()) { if (card.getTurnInZone() != game.getPhaseHandler().getTurn()) {
return false; return false;
} }
if (!property.equals("ThisTurnEntered")) { // to confirm specific zones / player
final boolean your = property.contains("Your");
final ZoneType where = ZoneType.smartValueOf(property.substring(your ? 19 : 15));
final Zone z = sourceController.getZone(where);
if (!z.getCardsAddedThisTurn(null).contains(card)) {
return false;
}
if (your) { // for corner cases of controlling other player
if (!card.getOwner().equals(sourceController)) {
return false;
}
}
}
} else if (property.equals("NotThisTurnEntered")) { } else if (property.equals("NotThisTurnEntered")) {
// only check if it entered the Zone this turn // only check if it entered the Zone this turn
if (card.getTurnInZone() == game.getPhaseHandler().getTurn()) { if (card.getTurnInZone() == game.getPhaseHandler().getTurn()) {

View File

@@ -1,15 +1,23 @@
package forge.game.cost; package forge.game.cost;
import forge.game.card.Card;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
public abstract class CostDecisionMakerBase implements ICostVisitor<PaymentDecision> { public abstract class CostDecisionMakerBase implements ICostVisitor<PaymentDecision> {
protected final Player player; protected final Player player;
protected final SpellAbility ability;
protected final Card source;
private boolean effect; private boolean effect;
public CostDecisionMakerBase(Player player0, boolean effect0) {
public CostDecisionMakerBase(Player player0, boolean effect0, SpellAbility ability0, Card source0) {
player = player0; player = player0;
effect = effect0; effect = effect0;
ability = ability0;
source = source0;
} }
public Player getPlayer() { return player; } public Player getPlayer() { return player; }
public abstract boolean paysRightAfterDecision(); public abstract boolean paysRightAfterDecision();
public boolean isEffect() { public boolean isEffect() {

View File

@@ -22,7 +22,9 @@ public class GameEventCardStatsChanged extends GameEvent {
public GameEventCardStatsChanged(Card affected, boolean isTransform) { public GameEventCardStatsChanged(Card affected, boolean isTransform) {
cards = Arrays.asList(affected); cards = Arrays.asList(affected);
transform = isTransform; //the transform should only fire once so the flip effect sound will trigger once every transformation...
// disable for now
transform = false;
} }
public GameEventCardStatsChanged(Collection<Card> affected) { public GameEventCardStatsChanged(Collection<Card> affected) {

View File

@@ -57,7 +57,7 @@
<dependency> <dependency>
<groupId>com.github.tommyettinger</groupId> <groupId>com.github.tommyettinger</groupId>
<artifactId>textratypist</artifactId> <artifactId>textratypist</artifactId>
<version>0.7.9</version> <version>0.8.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.badlogicgames.gdx-controllers</groupId> <groupId>com.badlogicgames.gdx-controllers</groupId>

View File

@@ -2,6 +2,7 @@ package forge.adventure.scene;
import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.scenes.scene2d.Action;
import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Group; import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.actions.Actions; import com.badlogic.gdx.scenes.scene2d.actions.Actions;
@@ -55,6 +56,7 @@ public class ArenaScene extends UIScene implements IAfterMatch {
final Sprite edgeM; final Sprite edgeM;
final Sprite edgeWin; final Sprite edgeWin;
final Sprite edgeWinM; final Sprite edgeWinM;
boolean enable = true;
boolean arenaStarted = false; boolean arenaStarted = false;
private ArenaScene() { private ArenaScene() {
@@ -76,6 +78,8 @@ public class ArenaScene extends UIScene implements IAfterMatch {
goldLabel = ui.findActor("gold"); goldLabel = ui.findActor("gold");
ui.onButtonPress("done", () -> { ui.onButtonPress("done", () -> {
if (!enable)
return;
if (!arenaStarted) if (!arenaStarted)
ArenaScene.this.done(); ArenaScene.this.done();
else else
@@ -107,6 +111,8 @@ public class ArenaScene extends UIScene implements IAfterMatch {
} }
private void startButton() { private void startButton() {
if (!enable)
return;
if (roundsWon == 0) { if (roundsWon == 0) {
Dialog startDialog = prepareDialog(Forge.getLocalizer().getMessage("lblStart"), ButtonYes | ButtonNo, () -> startArena()); Dialog startDialog = prepareDialog(Forge.getLocalizer().getMessage("lblStart"), ButtonYes | ButtonNo, () -> startArena());
startDialog.text("Do you want to go into the Arena?"); startDialog.text("Do you want to go into the Arena?");
@@ -119,6 +125,7 @@ public class ArenaScene extends UIScene implements IAfterMatch {
int roundsWon = 0; int roundsWon = 0;
private void startArena() { private void startArena() {
enable = false;
goldLabel.setVisible(false); goldLabel.setVisible(false);
arenaStarted = true; arenaStarted = true;
startButton.setText("[%80]" + Forge.getLocalizer().getMessage("lblContinue")); startButton.setText("[%80]" + Forge.getLocalizer().getMessage("lblContinue"));
@@ -132,6 +139,7 @@ public class ArenaScene extends UIScene implements IAfterMatch {
@Override @Override
public void setWinner(boolean winner) { public void setWinner(boolean winner) {
enable = false;
Array<ArenaRecord> winners = new Array<>(); Array<ArenaRecord> winners = new Array<>();
Array<EnemySprite> winnersEnemies = new Array<>(); Array<EnemySprite> winnersEnemies = new Array<>();
for (int i = 0; i < fighters.size - 2; i += 2) { for (int i = 0; i < fighters.size - 2; i += 2) {
@@ -189,7 +197,15 @@ public class ArenaScene extends UIScene implements IAfterMatch {
} }
if (Forge.isLandscapeMode()) { if (Forge.isLandscapeMode()) {
actor.toFront(); actor.toFront();
actor.addAction(Actions.sequence(Actions.moveBy(0f, gridSize * 2f, 1), Actions.moveBy((float) (gridSize * stepsToTheSide * (leftPlayer ? 1 : -1)), 0f, 1))); actor.addAction(Actions.sequence(Actions.moveBy(0f, gridSize * 2f, 1), Actions.moveBy((float) (gridSize * stepsToTheSide * (leftPlayer ? 1 : -1)), 0f, 1), new Action() {
@Override
public boolean act(float v) {
enable = true;
return true;
}
}));
} else {
enable = true;
} }
} }

View File

@@ -8,15 +8,9 @@ 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.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Action; import com.badlogic.gdx.scenes.scene2d.*;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.Actions; import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Button; import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.ui.Dialog;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Touchpad;
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener; import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
@@ -48,20 +42,11 @@ public class GameHUD extends Stage {
static public GameHUD instance; static public GameHUD instance;
private final GameStage gameStage; private final GameStage gameStage;
private final Image avatar; private final Image avatar, miniMapPlayer;
private final Image miniMapPlayer; private final TextraLabel lifePoints, money, shards, keys;
private final TextraLabel lifePoints;
private final TextraLabel money;
private final TextraLabel shards;
private final Image miniMap, gamehud, mapborder, avatarborder, blank; private final Image miniMap, gamehud, mapborder, avatarborder, blank;
private final InputEvent eventTouchDown; private final InputEvent eventTouchDown, eventTouchUp;
private final InputEvent eventTouchUp; private final TextraButton deckActor, openMapActor, menuActor, statsActor, inventoryActor, exitToWorldMapActor;
private final TextraButton deckActor;
private final TextraButton openMapActor;
private final TextraButton menuActor;
private final TextraButton statsActor;
private final TextraButton inventoryActor;
private final TextraButton exitToWorldMapActor;
public final UIActor ui; public final UIActor ui;
private final Touchpad touchpad; private final Touchpad touchpad;
private final Console console; private final Console console;
@@ -73,8 +58,10 @@ public class GameHUD extends Stage {
private final Dialog dialog; private final Dialog dialog;
private boolean dialogOnlyInput; private boolean dialogOnlyInput;
private final Array<TextraButton> dialogButtonMap = new Array<>(); private final Array<TextraButton> dialogButtonMap = new Array<>();
private final Array<String> questKeys = new Array<>();
private String lifepointsTextColor = ""; private String lifepointsTextColor = "";
TextraButton selectedKey; private TextraButton selectedKey;
private final ScrollPane scrollPane;
private GameHUD(GameStage gameStage) { private GameHUD(GameStage gameStage) {
super(new ScalingViewport(Scaling.stretch, Scene.getIntendedWidth(), Scene.getIntendedHeight()), gameStage.getBatch()); super(new ScalingViewport(Scaling.stretch, Scene.getIntendedWidth(), Scene.getIntendedHeight()), gameStage.getBatch());
@@ -137,6 +124,11 @@ public class GameHUD extends Stage {
shards.setText("[%95][+Shards] 0"); shards.setText("[%95][+Shards] 0");
money.setText("[%95][+Gold] "); money.setText("[%95][+Gold] ");
lifePoints.setText("[%95][+Life] 20/20"); lifePoints.setText("[%95][+Life] 20/20");
keys = Controls.newTextraLabel("");
scrollPane = new ScrollPane(keys);
scrollPane.setPosition(2, 2);
scrollPane.setStyle(Controls.getSkin().get("transluscent", ScrollPane.ScrollPaneStyle.class));
addActor(scrollPane);
AdventurePlayer.current().onLifeChange(() -> lifePoints.setText("[%95][+Life]" + lifepointsTextColor + " " + AdventurePlayer.current().getLife() + "/" + AdventurePlayer.current().getMaxLife())); AdventurePlayer.current().onLifeChange(() -> lifePoints.setText("[%95][+Life]" + lifepointsTextColor + " " + AdventurePlayer.current().getLife() + "/" + AdventurePlayer.current().getMaxLife()));
AdventurePlayer.current().onShardsChange(() -> shards.setText("[%95][+Shards] " + AdventurePlayer.current().getShards())); AdventurePlayer.current().onShardsChange(() -> shards.setText("[%95][+Shards] " + AdventurePlayer.current().getShards()));
@@ -291,6 +283,7 @@ public class GameHUD extends Stage {
Pixmap miniMapToolTipPixmap; Pixmap miniMapToolTipPixmap;
public void enter() { public void enter() {
questKeys.clear();
if (miniMapTexture != null) if (miniMapTexture != null)
miniMapTexture.dispose(); miniMapTexture.dispose();
miniMapTexture = new Texture(WorldSave.getCurrentSave().getWorld().getBiomeImage()); miniMapTexture = new Texture(WorldSave.getCurrentSave().getWorld().getBiomeImage());
@@ -304,6 +297,28 @@ public class GameHUD extends Stage {
miniMap.setDrawable(new TextureRegionDrawable(miniMapTexture)); miniMap.setDrawable(new TextureRegionDrawable(miniMapTexture));
avatar.setDrawable(new TextureRegionDrawable(Current.player().avatar())); avatar.setDrawable(new TextureRegionDrawable(Current.player().avatar()));
Deck deck = AdventurePlayer.current().getSelectedDeck(); Deck deck = AdventurePlayer.current().getSelectedDeck();
if (AdventurePlayer.current().hasItem("Red Key"))
questKeys.add("[+RedKey]");
if (AdventurePlayer.current().hasItem("Green Key"))
questKeys.add("[+GreenKey]");
if (AdventurePlayer.current().hasItem("Blue Key"))
questKeys.add("[+BlueKey]");
if (AdventurePlayer.current().hasItem("Black Key"))
questKeys.add("[+BlackKey]");
if (AdventurePlayer.current().hasItem("White Key"))
questKeys.add("[+WhiteKey]");
if (AdventurePlayer.current().hasItem("Strange Key"))
questKeys.add("[+StrangeKey]");
if (!questKeys.isEmpty()) {
keys.setText(String.join("\n", questKeys));
scrollPane.setSize(keys.getWidth() + 8, keys.getHeight() + 5);
scrollPane.layout();
keys.layout();
scrollPane.getColor().a = opacity;
} else {
keys.setText("");
scrollPane.getColor().a = 0;
}
if (deck == null || deck.isEmpty() || deck.getMain().toFlatList().size() < 30) { if (deck == null || deck.isEmpty() || deck.getMain().toFlatList().size() < 30) {
deckActor.setColor(Color.RED); deckActor.setColor(Color.RED);
} else { } else {

View File

@@ -306,7 +306,7 @@ public class MapStage extends GameStage {
dialog.getContentTable().add(group).height(100).width(100).center(); dialog.getContentTable().add(group).height(100).width(100).center();
dialog.getContentTable().add().row(); dialog.getContentTable().add().row();
} else { } else {
TypingLabel label = Controls.newTypingLabel("[%125]"+Controls.colorIdToTypingString(DeckProxy.getColorIdentity(deck)).toUpperCase()+"\n[%]"+deck.getName()); TypingLabel label = Controls.newTypingLabel("[%120]"+Controls.colorIdToTypingString(DeckProxy.getColorIdentity(deck)).toUpperCase()+"\n[%]"+deck.getName());
label.skipToTheEnd(); label.skipToTheEnd();
label.setAlignment(Align.center); label.setAlignment(Align.center);
dialog.getContentTable().add(label).align(Align.center); dialog.getContentTable().add(label).align(Align.center);

View File

@@ -8,6 +8,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.FrameBuffer; import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Align;
import com.github.tommyettinger.textra.TextraLabel;
/* /*
Class to draw directly on a pixmap Class to draw directly on a pixmap
@@ -26,7 +27,6 @@ public abstract class DrawOnPixmap {
on.drawPixmap(textureData.consumePixmap(), x, y, from.getRegionX(), from.getRegionY(), from.getRegionWidth(), from.getRegionHeight()); on.drawPixmap(textureData.consumePixmap(), x, y, from.getRegionX(), from.getRegionY(), from.getRegionWidth(), from.getRegionHeight());
} }
public static void drawText(Pixmap drawingMap, String itemText, int x, int y, float width, boolean bigText, Color color) { public static void drawText(Pixmap drawingMap, String itemText, int x, int y, float width, boolean bigText, Color color) {
//used for big numbers on Gold/Life for reward... //used for big numbers on Gold/Life for reward...
BitmapFont font = bigText ? Controls.getBitmapFont("big") : Controls.getBitmapFont("default"); BitmapFont font = bigText ? Controls.getBitmapFont("big") : Controls.getBitmapFont("default");
@@ -59,4 +59,37 @@ public abstract class DrawOnPixmap {
if (bigText) //don't know why this is needed to circumvent bug getting default size for the same pixelfont if (bigText) //don't know why this is needed to circumvent bug getting default size for the same pixelfont
Controls.getBitmapFont("default"); Controls.getBitmapFont("default");
} }
public static void drawText(Pixmap drawingMap, TextraLabel itemText, int modX, int modY) {
FrameBuffer frameBuffer = new FrameBuffer(Pixmap.Format.RGB888, drawingMap.getWidth(), drawingMap.getHeight(), false);
SpriteBatch batch = new SpriteBatch();
frameBuffer.begin();
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Matrix4 matrix = new Matrix4();
matrix.setToOrtho2D(0, drawingMap.getHeight(), drawingMap.getWidth(), -drawingMap.getHeight());
batch.setProjectionMatrix(matrix);
batch.begin();
//Rendering ends here. Create a new Pixmap to Texture with mipmaps, otherwise will render as full black.
Texture texture = new Texture(drawingMap);
batch.draw(texture, 0, 0);
itemText.setWrap(true);
itemText.setAlignment(1);
itemText.setWidth(texture.getWidth());
itemText.setHeight(texture.getHeight());
itemText.setX(itemText.getX()+modX);
itemText.setY(itemText.getY()+modY);
itemText.draw(batch, 1);
batch.end();
Pixmap pixmap = Pixmap.createFromFrameBuffer(0, 0, drawingMap.getWidth(), drawingMap.getHeight());
drawingMap.drawPixmap(pixmap, 0, 0);
frameBuffer.end();
texture.dispose();
batch.dispose();
pixmap.dispose();
}
} }

View File

@@ -44,13 +44,13 @@ public enum KeyBinding {
public String getLabelText(boolean pressed) { public String getLabelText(boolean pressed) {
if(Controllers.getCurrent()!=null) if(Controllers.getCurrent()!=null)
{ {
return "[%125][+"+controllerPrefix+Input.Keys.toString(bindingController).replace(" Button","")+(pressed?"_pressed]":"]"); return "[%120][+"+controllerPrefix+Input.Keys.toString(bindingController).replace(" Button","")+(pressed?"_pressed]":"]");
} }
else else
{ {
if(GuiBase.isAndroid()) if(GuiBase.isAndroid())
return ""; return "";
return "[%125][+"+Input.Keys.toString(binding)+(pressed?"_pressed]":"]"); return "[%120][+"+Input.Keys.toString(binding)+(pressed?"_pressed]":"]");
} }
} }

View File

@@ -305,7 +305,8 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
DrawOnPixmap.draw(drawingMap, backSprite); DrawOnPixmap.draw(drawingMap, backSprite);
Sprite item = atlas.createSprite(reward.type.toString()); Sprite item = atlas.createSprite(reward.type.toString());
DrawOnPixmap.draw(drawingMap, (int) ((backSprite.getWidth() / 2f) - item.getWidth() / 2f), (int) ((backSprite.getHeight() / 4f) * 1f), item); DrawOnPixmap.draw(drawingMap, (int) ((backSprite.getWidth() / 2f) - item.getWidth() / 2f), (int) ((backSprite.getHeight() / 4f) * 1f), item);
DrawOnPixmap.drawText(drawingMap, String.valueOf(reward.getCount()), 0, (int) ((backSprite.getHeight() / 4f) * 2f) - 1, backSprite.getWidth(), true, Color.WHITE); //DrawOnPixmap.drawText(drawingMap, String.valueOf(reward.getCount()), 0, (int) ((backSprite.getHeight() / 4f) * 2f) - 1, backSprite.getWidth(), true, Color.WHITE);
DrawOnPixmap.drawText(drawingMap, Controls.newTextraLabel("[%200]"+reward.getCount()), 0, -10);
setItemTooltips(item, backSprite, atlas); setItemTooltips(item, backSprite, atlas);
image = new Texture(drawingMap); image = new Texture(drawingMap);

View File

@@ -339,8 +339,10 @@ public class Assets implements Disposable {
textrafonts = new ObjectMap<>(); textrafonts = new ObjectMap<>();
if (!textrafonts.containsKey("textrafont")) { if (!textrafonts.containsKey("textrafont")) {
Font font = new Font(bitmapFont, 0f, 2f, 0f, 0f); Font font = new Font(bitmapFont, 0f, 2f, 0f, 0f);
font.addAtlas(item_atlas, 0f, 0f, 0f); font.addAtlas(item_atlas, 0f, 4f, 0f);
font.addAtlas(pixelmana_atlas, 0f, -12f, 0f); //problematic atlas since some buttons are small, and this is too big for some buttons, need a way to enable
//this via property
//font.addAtlas(pixelmana_atlas, -90f, 20f, 0f);
font.integerPosition = false; font.integerPosition = false;
textrafonts.put("textrafont", font); textrafonts.put("textrafont", font);
} }
@@ -352,7 +354,7 @@ public class Assets implements Disposable {
textrafonts = new ObjectMap<>(); textrafonts = new ObjectMap<>();
if (!textrafonts.containsKey("keysfont")) { if (!textrafonts.containsKey("keysfont")) {
Font font = new Font(bitmapFont); Font font = new Font(bitmapFont);
font.addAtlas(keys_atlas); font.addAtlas(keys_atlas, 0f, 4f, 0f);
font.integerPosition = false; font.integerPosition = false;
textrafonts.put("keysfont", font); textrafonts.put("keysfont", font);
} }
@@ -364,7 +366,7 @@ public class Assets implements Disposable {
textrafonts = new ObjectMap<>(); textrafonts = new ObjectMap<>();
if (!textrafonts.containsKey(name)) { if (!textrafonts.containsKey(name)) {
Font font = new Font(bitmapFont); Font font = new Font(bitmapFont);
font.addAtlas(items_atlas); font.addAtlas(items_atlas, 0f, 4f, 0f);
font.integerPosition = false; font.integerPosition = false;
textrafonts.put(name, font); textrafonts.put(name, font);
} }

View File

@@ -239,7 +239,10 @@ public class SplashScreen extends FContainer {
} }
void drawTransition(Graphics g, boolean openAdventure, float percentage) { void drawTransition(Graphics g, boolean openAdventure, float percentage) {
TextureRegion tr = new TextureRegion(Forge.getAssets().fallback_skins().get("title")); Texture t = Forge.getAssets().fallback_skins().get("title");
TextureRegion tr = null;
if (t != null)
tr = new TextureRegion(t);
float oldAlpha = g.getfloatAlphaComposite(); float oldAlpha = g.getfloatAlphaComposite();
g.setAlphaComposite(percentage); g.setAlphaComposite(percentage);
if (openAdventure) { if (openAdventure) {

View File

@@ -3,7 +3,7 @@ ManaCost:no cost
Types:Enchantment Types:Enchantment
S:Mode$ Continuous | EffectZone$ Command | Affected$ Card.Self | AffectedZone$ Command | RemoveAllAbilities$ True | IsPresent$ Card.namedGarruk's Boss Effect Phase One | PresentZone$ Command | PresentCompare$ EQ1 S:Mode$ Continuous | EffectZone$ Command | Affected$ Card.Self | AffectedZone$ Command | RemoveAllAbilities$ True | IsPresent$ Card.namedGarruk's Boss Effect Phase One | PresentZone$ Command | PresentCompare$ EQ1
S:Mode$ Continuous | EffectZone$ Command | Affected$ Forest.YouCtrl | AddType$ Swamp | Description$ Each Forest you control is a Swamp in addition to its other land types. S:Mode$ Continuous | EffectZone$ Command | Affected$ Forest.YouCtrl | AddType$ Swamp | Description$ Each Forest you control is a Swamp in addition to its other land types.
S:Mode$ Continuous | Affected$ Beast.YouCtrl | AddPower$ 3 | AddToughness 3 | AddKeyword$ Trample & Deathtouch | Description$ Beast creatures you control get +3/+3 and have trample and Deathtouch S:Mode$ Continuous | Affected$ Beast.YouCtrl | AddPower$ 3 | AddToughness$ 3 | AddKeyword$ Trample & Deathtouch | Description$ Beast creatures you control get +3/+3 and have trample and Deathtouch
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | PresentZone$ Command | Execute$ TrigConjure | TriggerDescription$ At the beginning of your upkeep, conjure a card of Garruk Phase 2's Spellbook into your hand. T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | PresentZone$ Command | Execute$ TrigConjure | TriggerDescription$ At the beginning of your upkeep, conjure a card of Garruk Phase 2's Spellbook into your hand.
SVar:TrigConjure:DB$ MakeCard | Conjure$ True | Zone$ Hand | AtRandom$ True | Spellbook$ Garruk; Apex Predator,Garruk; Cursed Huntsman,Garruk Relentless,In Garruk's Wake,Rampaging Baloths,Manglehorn,Elder Gargaroth,Gemrazer,Thragtusk,Sawtusk Demolisher,Avenger of Zendikar,Soul of the Harvest,Kogla; the Titan Ape, Terastodon, Bane of Progress SVar:TrigConjure:DB$ MakeCard | Conjure$ True | Zone$ Hand | AtRandom$ True | Spellbook$ Garruk; Apex Predator,Garruk; Cursed Huntsman,Garruk Relentless,In Garruk's Wake,Rampaging Baloths,Manglehorn,Elder Gargaroth,Gemrazer,Thragtusk,Sawtusk Demolisher,Avenger of Zendikar,Soul of the Harvest,Kogla; the Titan Ape, Terastodon, Bane of Progress
T:Mode$ SpellCast | ValidCard$ Card.nonCreature | ValidActivatingPlayer$ Player.Opponent | Execute$ DBEffect | TriggerZones$ Command | TriggerDescription$ Whenever an opponent casts a noncreature spell,perpetually increase the power and toughness of creatures you control and creature cards in your hand, library, and graveyard by 1. T:Mode$ SpellCast | ValidCard$ Card.nonCreature | ValidActivatingPlayer$ Player.Opponent | Execute$ DBEffect | TriggerZones$ Command | TriggerDescription$ Whenever an opponent casts a noncreature spell,perpetually increase the power and toughness of creatures you control and creature cards in your hand, library, and graveyard by 1.

View File

@@ -9,8 +9,8 @@ SVar:TrigRollDice:DB$ RollDice | Sides$ 20 | ResultSubAbilities$ 1-5:DBConjureSm
SVar:DBConjureSmall:DB$ MakeCard | Conjure$ True | AtRandom$ True | Spellbook$ Chained Brute,Big Spender,Devilish Valet,Gibbering Fiend,Hobblefiend,Footlight Fiend,Forge Devil,Festival Crasher,Hulking Devil,Mayhem Devil,Spiteful Prankster,Vexing Devil,Wildfire Devil | Zone$ Battlefield | SpellDescription$ Conjure a random Devil unto the battlefield. SVar:DBConjureSmall:DB$ MakeCard | Conjure$ True | AtRandom$ True | Spellbook$ Chained Brute,Big Spender,Devilish Valet,Gibbering Fiend,Hobblefiend,Footlight Fiend,Forge Devil,Festival Crasher,Hulking Devil,Mayhem Devil,Spiteful Prankster,Vexing Devil,Wildfire Devil | Zone$ Battlefield | SpellDescription$ Conjure a random Devil unto the battlefield.
SVar:DBRandomLoot:DB$ Draw | Defined$ Player | NumCards$ 3 | SubAbility$ DBDiscard3 | SpellDescription$ Each player draws three cards, then discards three cards at random. SVar:DBRandomLoot:DB$ Draw | Defined$ Player | NumCards$ 3 | SubAbility$ DBDiscard3 | SpellDescription$ Each player draws three cards, then discards three cards at random.
SVar:DBDiscard3:DB$ Discard | Defined$ Player | Mode$ Random | NumCards$ 3 SVar:DBDiscard3:DB$ Discard | Defined$ Player | Mode$ Random | NumCards$ 3
SVar:DBDamage:DB$ DealDamage | NumDmg$ 7 | ValidTgts$ Creature | TargetsAtRandom$ True | SubAbility$ DBChangeZone | SpellDescription$ Tibalt deals seven damage to a creature chosen at random. Then Tibalt returns a random creature card to the battlefield SVar:DBDamage:DB$ DealDamage | NumDmg$ 7 | ValidTgts$ Creature,Player,Planeswalker | TargetsAtRandom$ True | SubAbility$ DBChangeZone | SpellDescription$ Tibalt deals seven damage to a creature chosen at random. Then Tibalt returns a random creature card to the battlefield
SVar:DBChangeZone:DB$ ChangeZone | ChangeType$ Creature | ChangeNum$ 1 | Hidden$ True | Origin$ Graveyard | AtRandom$ True | Destination$ Battlefield SVar:DBChangeZone:DB$ ChangeZone | ChangeType$ Creature | ChangeNum$ 1 | GainControl$ True | Hidden$ True | Origin$ Graveyard | AtRandom$ True | Destination$ Battlefield
SVar:DBCast:DB$ Play | AnySupportedCard$ Names:Hellion Eruption,Insurrection,Warp World,Shahrazad,Possibility Storm,Scrambleverse | RandomCopied$ True | CopyCard$ True | WithoutManaCost$ True | SpellDescription$ Cast a copy of one of the following cards chosen at random—Hellion Eruption, Insurrection, Warp World, Shahrazad, Possibility Storm, Scrambleverse. SVar:DBCast:DB$ Play | AnySupportedCard$ Names:Hellion Eruption,Insurrection,Warp World,Shahrazad,Possibility Storm,Scrambleverse | RandomCopied$ True | CopyCard$ True | WithoutManaCost$ True | SpellDescription$ Cast a copy of one of the following cards chosen at random—Hellion Eruption, Insurrection, Warp World, Shahrazad, Possibility Storm, Scrambleverse.
SVar:DBWheel:DB$ Discard | Mode$ Hand | Defined$ Player | SubAbility$ DBEachDraw | SpellDescription$ Each player discards their hand, then draws seven cards. SVar:DBWheel:DB$ Discard | Mode$ Hand | Defined$ Player | SubAbility$ DBEachDraw | SpellDescription$ Each player discards their hand, then draws seven cards.
SVar:DBEachDraw:DB$ Draw | Defined$ Player | NumCards$ 7 SVar:DBEachDraw:DB$ Draw | Defined$ Player | NumCards$ 7

View File

@@ -2,7 +2,7 @@ Name:Xira's Boss Effect
ManaCost:no cost ManaCost:no cost
Colors:black,green,red Colors:black,green,red
Types:Enchantment Types:Enchantment
S:Mode$ Continuous | Affected$ Insect.YouCtrl | EffectZone$ Command | AddPower$ 1 | AddToughness 1 | AddKeyword$ Double Team | Description$ Nontoken insects you control have +1/+1 and Double Team. S:Mode$ Continuous | Affected$ Insect.YouCtrl | EffectZone$ Command | AddPower$ 1 | AddToughness$ 1 | AddKeyword$ Double Team | Description$ Nontoken insects you control have +1/+1 and Double Team.
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | Execute$ PutCounterAll | TriggerDescription$ At the beginning of your upkeep, put an egg counter on each nontoken creature. T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | Execute$ PutCounterAll | TriggerDescription$ At the beginning of your upkeep, put an egg counter on each nontoken creature.
SVar:PutCounterAll:DB$ PutCounterAll | ValidCards$ Creature.nonToken | CounterType$ EGG | CounterNum$ 1 SVar:PutCounterAll:DB$ PutCounterAll | ValidCards$ Creature.nonToken | CounterType$ EGG | CounterNum$ 1
T:Mode$ ChangesZone | Origin$ Battlefield | TriggerZones$ Command | Destination$ Graveyard | ValidCard$ Creature.counters_GE1_EGG+OppCtrl | Execute$ TrigDraw | TriggerDescription$ Whenever a creature with an egg counter on it dies, draw a card and create X 1/1 black Insect creature token with flying where X is the amount of Egg counters on that creature. T:Mode$ ChangesZone | Origin$ Battlefield | TriggerZones$ Command | Destination$ Graveyard | ValidCard$ Creature.counters_GE1_EGG+OppCtrl | Execute$ TrigDraw | TriggerDescription$ Whenever a creature with an egg counter on it dies, draw a card and create X 1/1 black Insect creature token with flying where X is the amount of Egg counters on that creature.

View File

@@ -5,7 +5,7 @@ Types:Creature Insect
PT:0/2 PT:0/2
K:Defender K:Defender
K:Reach K:Reach
S:Mode$ Continuous | Affected$ Insect.YouCtrl+nonToken | EffectZone$ Battlefield | AddPower$ 1 | AddToughness 1 | AddKeyword$ Double Team | Description$ Nontoken Insects you control have +1/+1 and double team. S:Mode$ Continuous | Affected$ Insect.YouCtrl+nonToken | EffectZone$ Battlefield | AddPower$ 1 | AddToughness$ 1 | AddKeyword$ Double Team | Description$ Nontoken Insects you control have +1/+1 and double team.
T:Mode$ DamageDone | ActivationLimit$ 1 | ValidSource$ Card.OppCtrl,Emblem.OppCtrl | ValidTarget$ You | TriggerZones$ Battlefield | Execute$ TrigCounter | TriggerDescription$ When a source an opponent controls deals damage to you for the first time each turn, put an egg counter on CARDNAME. T:Mode$ DamageDone | ActivationLimit$ 1 | ValidSource$ Card.OppCtrl,Emblem.OppCtrl | ValidTarget$ You | TriggerZones$ Battlefield | Execute$ TrigCounter | TriggerDescription$ When a source an opponent controls deals damage to you for the first time each turn, put an egg counter on CARDNAME.
SVar:TrigCounter:DB$ PutCounter | CounterType$ EGG | CounterNum$ 1 SVar:TrigCounter:DB$ PutCounter | CounterType$ EGG | CounterNum$ 1
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME dies, create X 1/1 black Insect tokens for each egg counter on CARDNAME. T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME dies, create X 1/1 black Insect tokens for each egg counter on CARDNAME.

View File

@@ -136,7 +136,7 @@
<object id="194" template="../obj/collision.tx" x="-16.4079" y="346.105" width="527.5" height="16"/> <object id="194" template="../obj/collision.tx" x="-16.4079" y="346.105" width="527.5" height="16"/>
<object id="195" template="../obj/collision.tx" x="492.342" y="-22.9362" width="16" height="387.083"/> <object id="195" template="../obj/collision.tx" x="492.342" y="-22.9362" width="16" height="387.083"/>
<object id="196" template="../obj/collision.tx" x="-17.6579" y="-19.9362" width="16" height="382.083"/> <object id="196" template="../obj/collision.tx" x="-17.6579" y="-19.9362" width="16" height="382.083"/>
<object id="197" template="../obj/door_up.tx" x="290.342" y="104.105"> <object id="197" template="../obj/door_up.tx" x="284.842" y="71.105">
<properties> <properties>
<property name="teleport" value="maps/map/tibalt_f1.tmx"/> <property name="teleport" value="maps/map/tibalt_f1.tmx"/>
<property name="teleportObjectId" value="114"/> <property name="teleportObjectId" value="114"/>
@@ -144,10 +144,5 @@
</object> </object>
<object id="198" template="../obj/waypoint.tx" x="225.342" y="221.105"/> <object id="198" template="../obj/waypoint.tx" x="225.342" y="221.105"/>
<object id="199" template="../obj/waypoint.tx" x="202.342" y="251.605"/> <object id="199" template="../obj/waypoint.tx" x="202.342" y="251.605"/>
<object id="200" template="../obj/entry_up.tx" x="142.342" y="327.105">
<properties>
<property name="teleport" value="maps/map/tibalt_f2.tmx"/>
</properties>
</object>
</objectgroup> </objectgroup>
</map> </map>

View File

@@ -93,7 +93,7 @@
<property name="waypoints" value="183,181,182,181"/> <property name="waypoints" value="183,181,182,181"/>
</properties> </properties>
</object> </object>
<object id="161" template="../obj/entry_up.tx" x="464.012" y="105.236"> <object id="161" template="../obj/entry_up.tx" x="460.679" y="88.9027" width="31.6667" height="16">
<properties> <properties>
<property name="teleport" value="maps/map/tibalt_f2.tmx"/> <property name="teleport" value="maps/map/tibalt_f2.tmx"/>
</properties> </properties>

View File

@@ -260,6 +260,15 @@ thinwindow
orig: 16, 16 orig: 16, 16
offset: 0, 0 offset: 0, 0
index: -1 index: -1
transwindow
rotate: false
xy: 305, 415
size: 16, 16
split: 2, 2, 2, 2
pad: 0, 0, 0, 0
orig: 16, 16
offset: 0, 0
index: -1
uncheck uncheck
rotate: false rotate: false
xy: 293, 375 xy: 293, 375

View File

@@ -166,6 +166,26 @@
"playMode": 2, "playMode": 2,
"crushMode": 0 "crushMode": 0
}, },
"transwindow10Patch": {
"region": "transwindow",
"horizontalStretchAreas": [ 2, 13 ],
"verticalStretchAreas": [ 2, 13 ],
"tiling": true,
"minWidth": 16,
"minHeight": 16,
"rightWidth": 4,
"leftWidth": 4,
"bottomHeight": 4,
"topHeight": 4,
"offsetX": 0,
"offsetY": 0,
"offsetXspeed": 0,
"offsetYspeed": 0,
"frameDuration": 0.03,
"regions": [],
"playMode": 2,
"crushMode": 0
},
"pressed10Patch": { "pressed10Patch": {
"region": "pressed", "region": "pressed",
"horizontalStretchAreas": [ 3, 10 ], "horizontalStretchAreas": [ 3, 10 ],
@@ -443,6 +463,9 @@
"gold": { "gold": {
"background": "9patch4" "background": "9patch4"
}, },
"transluscent": {
"background": "transwindow10Patch"
},
"nobg": { "nobg": {
"background": "transparent" "background": "transparent"
} }
@@ -549,6 +572,11 @@
"background": "paper10Patch", "background": "paper10Patch",
"titleFont": "default" "titleFont": "default"
}, },
"transluscent": {
"parent": "default",
"background": "transwindow10Patch",
"titleFont": "default"
},
"gold": { "gold": {
"background": "TenPatchGold", "background": "TenPatchGold",
"titleFont": "default" "titleFont": "default"

View File

@@ -86,7 +86,7 @@
"type": "TextButton", "type": "TextButton",
"name": "exittoworldmap", "name": "exittoworldmap",
"style":"menu", "style":"menu",
"text": "[%125][+ExitToWorldMap]", "text": "[%120][+ExitToWorldMap]",
"binding": "ExitToWorldMap", "binding": "ExitToWorldMap",
"width": 48, "width": 48,
"height": 36, "height": 36,
@@ -97,7 +97,7 @@
"type": "TextButton", "type": "TextButton",
"name": "deck", "name": "deck",
"style":"menu", "style":"menu",
"text": "[%125][+Deck]", "text": "[%120][+Deck]",
"binding": "Deck", "binding": "Deck",
"width": 48, "width": 48,
"height": 36, "height": 36,
@@ -108,7 +108,7 @@
"type": "TextButton", "type": "TextButton",
"name": "inventory", "name": "inventory",
"style":"menu", "style":"menu",
"text": "[%125][+Item]", "text": "[%120][+Item]",
"binding": "Inventory", "binding": "Inventory",
"width": 48, "width": 48,
"height": 36, "height": 36,
@@ -120,7 +120,7 @@
"type": "TextButton", "type": "TextButton",
"name": "statistic", "name": "statistic",
"style":"menu", "style":"menu",
"text": "[%125][+Status]", "text": "[%120][+Status]",
"binding": "Status", "binding": "Status",
"width": 48, "width": 48,
"height": 36, "height": 36,
@@ -131,7 +131,7 @@
"type": "TextButton", "type": "TextButton",
"name": "menu", "name": "menu",
"style":"menu", "style":"menu",
"text": "[%125][+Menu]", "text": "[%120][+Menu]",
"binding": "Menu", "binding": "Menu",
"width": 48, "width": 48,
"height": 36, "height": 36,

View File

@@ -86,7 +86,7 @@
"type": "TextButton", "type": "TextButton",
"name": "deck", "name": "deck",
"style":"menu", "style":"menu",
"text": "[%125][+Deck]", "text": "[%120][+Deck]",
"binding": "Deck", "binding": "Deck",
"width": 64, "width": 64,
"height": 36, "height": 36,
@@ -97,7 +97,7 @@
"type": "TextButton", "type": "TextButton",
"name": "inventory", "name": "inventory",
"style":"menu", "style":"menu",
"text": "[%125][+Item]", "text": "[%120][+Item]",
"binding": "Inventory", "binding": "Inventory",
"width": 64, "width": 64,
"height": 36, "height": 36,
@@ -109,7 +109,7 @@
"type": "TextButton", "type": "TextButton",
"name": "statistic", "name": "statistic",
"style":"menu", "style":"menu",
"text": "[%125][+Status]", "text": "[%120][+Status]",
"binding": "Status", "binding": "Status",
"width": 64, "width": 64,
"height": 36, "height": 36,
@@ -120,7 +120,7 @@
"type": "TextButton", "type": "TextButton",
"name": "menu", "name": "menu",
"style":"menu", "style":"menu",
"text": "[%125][+Menu]", "text": "[%120][+Menu]",
"binding": "Menu", "binding": "Menu",
"width": 64, "width": 64,
"height": 36, "height": 36,
@@ -141,7 +141,7 @@
"type": "TextButton", "type": "TextButton",
"name": "exittoworldmap", "name": "exittoworldmap",
"style":"menu", "style":"menu",
"text": "[%125][+ExitToWorldMap]", "text": "[%120][+ExitToWorldMap]",
"binding": "ExitToWorldMap", "binding": "ExitToWorldMap",
"width": 64, "width": 64,
"height": 32, "height": 32,

View File

@@ -85,7 +85,7 @@
"type": "TextButton", "type": "TextButton",
"name": "deck", "name": "deck",
"style":"menu", "style":"menu",
"text": "[%125][+Deck]", "text": "[%120][+Deck]",
"binding": "Deck", "binding": "Deck",
"width": 64, "width": 64,
"height": 32, "height": 32,
@@ -96,7 +96,7 @@
"type": "TextButton", "type": "TextButton",
"name": "inventory", "name": "inventory",
"style":"menu", "style":"menu",
"text": "[%125][+Item]", "text": "[%120][+Item]",
"binding": "Inventory", "binding": "Inventory",
"width": 64, "width": 64,
"height": 32, "height": 32,
@@ -108,7 +108,7 @@
"type": "TextButton", "type": "TextButton",
"name": "statistic", "name": "statistic",
"style":"menu", "style":"menu",
"text": "[%125][+Status]", "text": "[%120][+Status]",
"binding": "Status", "binding": "Status",
"width": 64, "width": 64,
"height": 32, "height": 32,
@@ -119,7 +119,7 @@
"type": "TextButton", "type": "TextButton",
"name": "menu", "name": "menu",
"style":"menu", "style":"menu",
"text": "[%125][+Menu]", "text": "[%120][+Menu]",
"binding": "Menu", "binding": "Menu",
"width": 64, "width": 64,
"height": 32, "height": 32,
@@ -140,7 +140,7 @@
"type": "TextButton", "type": "TextButton",
"name": "exittoworldmap", "name": "exittoworldmap",
"style":"menu", "style":"menu",
"text": "[%125][+ExitToWorldMap]", "text": "[%120][+ExitToWorldMap]",
"binding": "ExitToWorldMap", "binding": "ExitToWorldMap",
"width": 64, "width": 64,
"height": 32, "height": 32,

View File

@@ -130,7 +130,7 @@
{ {
"type": "TextButton", "type": "TextButton",
"name": "toggleAward", "name": "toggleAward",
"text": "[%125][+AWARD]", "text": "[%120][+AWARD]",
"width": 30, "width": 30,
"height": 30, "height": 30,
"x": 315, "x": 315,

View File

@@ -121,7 +121,7 @@
{ {
"type": "TextButton", "type": "TextButton",
"name": "toggleAward", "name": "toggleAward",
"text": "[%125][+AWARD]", "text": "[%120][+AWARD]",
"width": 30, "width": 30,
"height": 30, "height": 30,
"x": 5, "x": 5,

View File

@@ -2,7 +2,7 @@ Name:Cruel Grimnarch
ManaCost:5 B ManaCost:5 B
Types:Creature Phyrexian Cleric Types:Creature Phyrexian Cleric
PT:5/5 PT:5/5
K:Deatchtouch K:Deathtouch
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDiscard | TriggerDescription$ When CARDNAME enters the battlefield, each opponent discards a card. For each opponent who can't, you gain 4 life. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDiscard | TriggerDescription$ When CARDNAME enters the battlefield, each opponent discards a card. For each opponent who can't, you gain 4 life.
SVar:TrigDiscard:DB$ Discard | Mode$ TgtChoose | Defined$ Player.Opponent | NumCards$ 1 | RememberDiscarded$ True | SubAbility$ DBRepeat SVar:TrigDiscard:DB$ Discard | Mode$ TgtChoose | Defined$ Player.Opponent | NumCards$ 1 | RememberDiscarded$ True | SubAbility$ DBRepeat
SVar:DBRepeat:DB$ RepeatEach | RepeatPlayers$ Player.Opponent | RepeatSubAbility$ DBGainLife | SubAbility$ DBCleanup SVar:DBRepeat:DB$ RepeatEach | RepeatPlayers$ Player.Opponent | RepeatSubAbility$ DBGainLife | SubAbility$ DBCleanup

View File

@@ -3,6 +3,6 @@ ManaCost:U U B B
Types:Legendary Creature Shapeshifter Types:Legendary Creature Shapeshifter
PT:3/3 PT:3/3
K:Hexproof K:Hexproof
T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.nonToken+OppOwn | TriggerZones$ Battlefield | Execute$ LazavCopy | OptionalDecider$ You | TriggerDescription$ Whenever a creature card is put into an opponent's graveyard from anywhere, you may have Lazav, Dimir Mastermind become a copy of that card, except its name is Lazav, Dimir Mastermind, it's legendary in addition to its other types, and it has hexproof and this ability. T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.nonToken+OppOwn | TriggerZones$ Battlefield | Execute$ LazavCopy | OptionalDecider$ You | TriggerDescription$ Whenever a creature card is put into an opponent's graveyard from anywhere, you may have CARDNAME become a copy of that card, except its name is Lazav, Dimir Mastermind, it's legendary in addition to its other types, and it has hexproof and this ability.
SVar:LazavCopy:DB$ Clone | Defined$ TriggeredCard | NewName$ Lazav, Dimir Mastermind | AddTypes$ Legendary | AddKeywords$ Hexproof | GainThisAbility$ True | Optional$ True | AddSVars$ LazavCopy | AILogic$ IfDefinedCreatureIsBetter SVar:LazavCopy:DB$ Clone | Defined$ TriggeredCard | NewName$ Lazav, Dimir Mastermind | AddTypes$ Legendary | AddKeywords$ Hexproof | GainThisAbility$ True | Optional$ True | AddSVars$ LazavCopy | AILogic$ IfDefinedCreatureIsBetter
Oracle:Hexproof\nWhenever a creature card is put into an opponent's graveyard from anywhere, you may have Lazav, Dimir Mastermind become a copy of that card, except its name is Lazav, Dimir Mastermind, it's legendary in addition to its other types, and it has hexproof and this ability. Oracle:Hexproof\nWhenever a creature card is put into an opponent's graveyard from anywhere, you may have Lazav, Dimir Mastermind become a copy of that card, except its name is Lazav, Dimir Mastermind, it's legendary in addition to its other types, and it has hexproof and this ability.

View File

@@ -4,9 +4,9 @@ Types:Legendary Creature Human Wizard
PT:4/1 PT:4/1
K:etbCounter:DREAM:7 K:etbCounter:DREAM:7
K:CARDNAME can't have more than seven dream counters on it. K:CARDNAME can't have more than seven dream counters on it.
A:AB$ Mana | Cost$ SubCounter<1/DREAM> | Produced$ C | SpellDescription$ Add {C}. A:AB$ Mana | Cost$ SubCounter<1/DREAM/NICKNAME> | Produced$ C | SpellDescription$ Add {C}.
A:AB$ PreventDamage | Cost$ SubCounter<1/DREAM> | Defined$ Self | Amount$ 1 | SpellDescription$ Prevent the next 1 damage that would be dealt to CARDNAME this turn. A:AB$ PreventDamage | Cost$ SubCounter<1/DREAM/NICKNAME> | Defined$ Self | Amount$ 1 | SpellDescription$ Prevent the next 1 damage that would be dealt to NICKNAME this turn.
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPutCounter | IsPresent$ Card.Self+startedTheTurnUntapped | TriggerDescription$ At the beginning of your upkeep, if CARDNAME started the turn untapped, put a dream counter on it. T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPutCounter | IsPresent$ Card.Self+startedTheTurnUntapped | TriggerDescription$ At the beginning of your upkeep, if NICKNAME started the turn untapped, put a dream counter on it.
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ DREAM | CounterNum$ 1 SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ DREAM | CounterNum$ 1
DeckHas:Ability$Counters DeckHas:Ability$Counters
Oracle:Rasputin Dreamweaver enters the battlefield with seven dream counters on it.\nRemove a dream counter from Rasputin: Add {C}.\nRemove a dream counter from Rasputin: Prevent the next 1 damage that would be dealt to Rasputin this turn.\nAt the beginning of your upkeep, if Rasputin started the turn untapped, put a dream counter on it.\nRasputin can't have more than seven dream counters on it. Oracle:Rasputin Dreamweaver enters the battlefield with seven dream counters on it.\nRemove a dream counter from Rasputin: Add {C}.\nRemove a dream counter from Rasputin: Prevent the next 1 damage that would be dealt to Rasputin this turn.\nAt the beginning of your upkeep, if Rasputin started the turn untapped, put a dream counter on it.\nRasputin can't have more than seven dream counters on it.

View File

@@ -5,7 +5,7 @@ PT:3/4
K:Reach K:Reach
T:Mode$ ChangesZoneAll | ValidCards$ Land.YouOwn+nonToken | Origin$ Any | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigLifegain | TriggerDescription$ Whenever one or more land cards are put into your graveyard from anywhere, you gain 2 life. T:Mode$ ChangesZoneAll | ValidCards$ Land.YouOwn+nonToken | Origin$ Any | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigLifegain | TriggerDescription$ Whenever one or more land cards are put into your graveyard from anywhere, you gain 2 life.
SVar:TrigLifegain:DB$ GainLife | LifeAmount$ 2 SVar:TrigLifegain:DB$ GainLife | LifeAmount$ 2
T:Mode$ Phase | Phase$ Upkeep | CheckSVar$ X | SVarCompare$ GE4 | IsPresent$ Card.Self+YouOwn | IsPresent2$ Land.YouCtrl+YouOwn+namedArgoth; Sanctum of Nature | ValidPlayer$ You | Execute$ Meld | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your upkeep, if you both own and control CARDNAME and a land named Argoth, Sanctum of Nature, exile them, then meld them into Titania, Gaea Incarnate. T:Mode$ Phase | Phase$ Upkeep | CheckSVar$ X | SVarCompare$ GE4 | IsPresent$ Card.Self+YouOwn | IsPresent2$ Land.YouCtrl+YouOwn+namedArgoth; Sanctum of Nature | ValidPlayer$ You | Execute$ Meld | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your upkeep, if there are four or more land cards in your graveyard and you both own and control CARDNAME and a land named Argoth, Sanctum of Nature, exile them, then meld them into Titania, Gaea Incarnate.
SVar:Meld:DB$ Meld | Name$ Titania, Gaea Incarnate | Primary$ Titania, Voice of Gaea | Secondary$ Argoth, Sanctum of Nature | SecondaryType$ Land SVar:Meld:DB$ Meld | Name$ Titania, Gaea Incarnate | Primary$ Titania, Voice of Gaea | Secondary$ Argoth, Sanctum of Nature | SecondaryType$ Land
DeckHints:Name$Argoth, Sanctum of Nature DeckHints:Name$Argoth, Sanctum of Nature
MeldPair:Argoth, Sanctum of Nature MeldPair:Argoth, Sanctum of Nature

View File

@@ -0,0 +1,10 @@
Name:Archangel Elspeth
ManaCost:2 W W
Types:Legendary Planeswalker Elspeth
Loyalty:4
A:AB$ Token | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | TokenScript$ w_1_1_soldier_lifelink | SpellDescription$ Create a 1/1 white Soldier creature token with lifelink.
A:AB$ PutCounter | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | CounterType$ P1P1 | CounterNum$ 2 | ValidTgts$ Creature | SubAbility$ DBAnimate | SpellDescription$ Put two +1/+1 counters on target creature.
SVar:DBAnimate:DB$ Animate | Defined$ Targeted | Types$ Angel | Keywords$ Flying | Duration$ Permanent | StackDescription$ SpellDescription | SpellDescription$ It becomes an Angel in addition to its other types and gains flying.
A:AB$ ChangeZoneAll | Cost$ SubCounter<6/LOYALTY> | Planeswalker$ True | Ultimate$ True | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Permanent.nonLand+YouOwn+cmcLE3 | SpellDescription$ Return all nonland permanent cards with mana value 3 or less from your graveyard to the battlefield.
DeckHas:Ability$Token|LifeGain|Counters|Graveyard & Type$Soldier|Angel
Oracle:[+1]: Create a 1/1 white Soldier creature token with lifelink.\n[-2]: Put two +1/+1 counters on target creature. It becomes an Angel in addition to its other types and gains flying.\n[-6]: Return all nonland permanent cards with mana value 3 or less from your graveyard to the battlefield.

View File

@@ -0,0 +1,10 @@
Name:Quicksilver Servitor
ManaCost:2 U
Types:Creature Phyrexian Cleric
PT:3/3
K:Ward:2
T:Mode$ SpellCast | ValidCard$ Card.ThisTurnEnteredYourHand | ValidActivatingPlayer$ You | Execute$ TrigProliferate | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast a spell from among cards put into your hand this turn, proliferate.
SVar:TrigProliferate:DB$ Proliferate
DeckHas:Ability$Proliferate
DeckNeeds:Ability$Counters
Oracle:Ward {2}\nWhenever you cast a spell from among cards put into your hand this turn, proliferate.

View File

@@ -3,7 +3,7 @@ ManaCost:G
Types:Creature Phyrexian Druid Types:Creature Phyrexian Druid
PT:1/2 PT:1/2
K:Toxic:1 K:Toxic:1
T:Mode$ BecomesTarget | ValidTarget$ Creature.YouCtrl | ValidSource$ Spell | TriggerZones$ Battlefield | Execute$ TrigPoison | TriggerDescription$ Whenever a creature you control becomes the target of a spell, target opponent gets a poison counter. T:Mode$ BecomesTarget | ValidTarget$ Creature.YouCtrl+inZoneBattlefield | ValidSource$ Spell | TriggerZones$ Battlefield | Execute$ TrigPoison | TriggerDescription$ Whenever a creature you control becomes the target of a spell, target opponent gets a poison counter.
SVar:TrigPoison:DB$ Poison | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | Num$ 1 SVar:TrigPoison:DB$ Poison | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | Num$ 1
DeckHas:Ability$Counters DeckHas:Ability$Counters
DeckHints:Type$Aura DeckHints:Type$Aura

View File

@@ -12,6 +12,7 @@ ScryfallCode=MOM
67 C Moment of Truth @Rovina Cai 67 C Moment of Truth @Rovina Cai
94 R Breach the Multiverse @Liiga Smilshkalne 94 R Breach the Multiverse @Liiga Smilshkalne
134 M Chandra, Hope's Beacon @Kieran Yanner 134 M Chandra, Hope's Beacon @Kieran Yanner
217 M Wrenn and Realmbreaker @Cristi Balanescu
222 R Drana and Linvala @Raluca Marinescu 222 R Drana and Linvala @Raluca Marinescu
225 R Ghalta and Mavren @Zezhou Chen 225 R Ghalta and Mavren @Zezhou Chen
249 R Omnath, Locus of All @Bryan Sola 249 R Omnath, Locus of All @Bryan Sola
@@ -33,7 +34,9 @@ ScryfallCode=MOM
313 R Omnath, Locus of All @Jessica Rossier 313 R Omnath, Locus of All @Jessica Rossier
316 M Thalia and The Gitrog Monster @Sami Makkonen 316 M Thalia and The Gitrog Monster @Sami Makkonen
317 R Yargle and Multani @Lisa Heidhoff 317 R Yargle and Multani @Lisa Heidhoff
320 M Archangel Elspeth @Denys Tsiperko
321 M Chandra, Hope's Beacon @Randy Vargas 321 M Chandra, Hope's Beacon @Randy Vargas
322 M Wrenn and Realmbreaker @Jehan Choo
339 M Jin-Gitaxias @Julian Kok Joon Wen 339 M Jin-Gitaxias @Julian Kok Joon Wen
352 R Faerie Mastermind @Joshua Raphael 352 R Faerie Mastermind @Joshua Raphael
358 R Breach the Multiverse @Liiga Smilshkalne 358 R Breach the Multiverse @Liiga Smilshkalne

View File

@@ -896,6 +896,12 @@ ScryfallCode=SLD
1234 R Azusa, Lost but Seeking @Tsubonari 1234 R Azusa, Lost but Seeking @Tsubonari
1235 R Teysa Karlov @Tsubonari 1235 R Teysa Karlov @Tsubonari
1236 R Paradise Mantle @Tsubonari 1236 R Paradise Mantle @Tsubonari
1237 R Xenk, Paladin Unbroken @Tatiana Vetrova & Jason Li
1238 R Simon, Wild Magic Sorcerer @Shuangcheng Leng
1239 R Forge, Neverwinter Charlatan @Liangliang Zhang
1240 R Holga, Relentless Rager @Yang Luo
1241 R Doric, Nature's Warden @Oiya Zhang & Liangliang Zhang
1242 R Edgin, Larcenous Lutenist @Wenfei Ye
1243 R Ugin, the Ineffable @Sansyu 1243 R Ugin, the Ineffable @Sansyu
1244 M Sorin, Imperious Bloodlord @Showichi Furumi 1244 M Sorin, Imperious Bloodlord @Showichi Furumi
1245 M Sarkhan, Dragonsoul @Miyuki Aramaki 1245 M Sarkhan, Dragonsoul @Miyuki Aramaki

View File

@@ -11,7 +11,7 @@ ScryfallCode=SCH
3 R Dark Confidant @Livia Prima 3 R Dark Confidant @Livia Prima
4 R Spell Pierce @Andrew Mar 4 R Spell Pierce @Andrew Mar
5 R Gilded Goose @Chris Seaman 5 R Gilded Goose @Chris Seaman
6 C Omnath, Locus of Creation @John Tedrick 6 M Omnath, Locus of Creation @John Tedrick
7 R Annex Sentry @Sam Guay 7 R Annex Sentry @Sam Guay
8 R Memory Deluge @Sam Guay 8 R Memory Deluge @Sam Guay
9 M Koth, Fire of Resistance @Kieran Yanner 9 R Koth, Fire of Resistance @Kieran Yanner

View File

@@ -32,6 +32,7 @@ public final class ForgeConstants {
public static final String RES_DIR = ASSETS_DIR + "res" + PATH_SEPARATOR; public static final String RES_DIR = ASSETS_DIR + "res" + PATH_SEPARATOR;
public static final String ADVENTURE_DIR = RES_DIR + "adventure" + PATH_SEPARATOR; public static final String ADVENTURE_DIR = RES_DIR + "adventure" + PATH_SEPARATOR;
public static final String ADVENTURE_DEFAULT_PLANE_DIR = ADVENTURE_DIR + "Shandalar" + PATH_SEPARATOR;
public static final String LISTS_DIR = RES_DIR + "lists" + PATH_SEPARATOR; public static final String LISTS_DIR = RES_DIR + "lists" + PATH_SEPARATOR;
public static final String SETLOOKUP_DIR = RES_DIR + "setlookup" + PATH_SEPARATOR; public static final String SETLOOKUP_DIR = RES_DIR + "setlookup" + PATH_SEPARATOR;
public static final String KEYWORD_LIST_FILE = LISTS_DIR + "NonStackingKWList.txt"; public static final String KEYWORD_LIST_FILE = LISTS_DIR + "NonStackingKWList.txt";
@@ -84,7 +85,7 @@ public final class ForgeConstants {
public static final String AI_PROFILE_DIR = RES_DIR + "ai" + PATH_SEPARATOR; public static final String AI_PROFILE_DIR = RES_DIR + "ai" + PATH_SEPARATOR;
public static final String SOUND_DIR = RES_DIR + "sound" + PATH_SEPARATOR; public static final String SOUND_DIR = RES_DIR + "sound" + PATH_SEPARATOR;
public static final String MUSIC_DIR = RES_DIR + "music" + PATH_SEPARATOR; public static final String MUSIC_DIR = RES_DIR + "music" + PATH_SEPARATOR;
public static final String ADVENTURE_MUSIC_DIR = ADVENTURE_DIR + "music" + PATH_SEPARATOR; public static final String ADVENTURE_MUSIC_DIR = ADVENTURE_DEFAULT_PLANE_DIR + "music" + PATH_SEPARATOR;
public static final String LANG_DIR = RES_DIR + "languages" + PATH_SEPARATOR; public static final String LANG_DIR = RES_DIR + "languages" + PATH_SEPARATOR;
public static final String EFFECTS_DIR = RES_DIR + "effects" + PATH_SEPARATOR; public static final String EFFECTS_DIR = RES_DIR + "effects" + PATH_SEPARATOR;
public static final String PUZZLE_DIR = RES_DIR + "puzzle" + PATH_SEPARATOR; public static final String PUZZLE_DIR = RES_DIR + "puzzle" + PATH_SEPARATOR;

View File

@@ -47,20 +47,16 @@ import forge.util.collect.FCollectionView;
public class HumanCostDecision extends CostDecisionMakerBase { public class HumanCostDecision extends CostDecisionMakerBase {
private final PlayerControllerHuman controller; private final PlayerControllerHuman controller;
private final SpellAbility ability;
private final Card source;
private String orString = null; private String orString = null;
private boolean mandatory; private boolean mandatory;
public HumanCostDecision(final PlayerControllerHuman controller, final Player p, final SpellAbility sa, final boolean effect, final Card source) { public HumanCostDecision(final PlayerControllerHuman controller, final Player p, final SpellAbility sa, final boolean effect) {
this(controller, p, sa, effect, source, null); this(controller, p, sa, effect, sa.getHostCard(), null);
} }
public HumanCostDecision(final PlayerControllerHuman controller, final Player p, final SpellAbility sa, final boolean effect, final Card source, final String orString) { public HumanCostDecision(final PlayerControllerHuman controller, final Player p, final SpellAbility sa, final boolean effect, final Card source, final String orString) {
super(p, effect); super(p, effect, sa, source);
this.controller = controller; this.controller = controller;
ability = sa;
mandatory = sa.getPayCosts().isMandatory(); mandatory = sa.getPayCosts().isMandatory();
this.source = source;
this.orString = orString; this.orString = orString;
} }

View File

@@ -165,7 +165,7 @@ public class HumanPlaySpellAbility {
&& ability.canCastTiming(human) && ability.canCastTiming(human)
&& ability.checkRestrictions(human) && ability.checkRestrictions(human)
&& ability.isLegalAfterStack() && ability.isLegalAfterStack()
&& (isFree || payment.payCost(new HumanCostDecision(controller, human, ability, false, ability.getHostCard()))); && (isFree || payment.payCost(new HumanCostDecision(controller, human, ability, false)));
game.clearTopLibsCast(ability); game.clearTopLibsCast(ability);