mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 10:40:06 -08:00
GUI: introduced default card hints:
* refactor: added helper emblems instead rad counter's inherent emblems (use initGameDefaultHelperEmblems to define new card hints or other fake objects); * refactor: added card hints support for emblems, planes and other command objects; * GUI: added storm counter as default card hint (use hints tool to see it, closes #12360);
This commit is contained in:
parent
83823acec7
commit
521a0f6e32
36 changed files with 234 additions and 144 deletions
|
|
@ -152,7 +152,7 @@ public class MageEditorPane extends JEditorPane {
|
||||||
if (cardView == null) {
|
if (cardView == null) {
|
||||||
Plane plane = Plane.createPlaneByFullName(cardName);
|
Plane plane = Plane.createPlaneByFullName(cardName);
|
||||||
if (plane != null) {
|
if (plane != null) {
|
||||||
cardView = new CardView(new PlaneView(plane));
|
cardView = new CardView(new PlaneView(plane, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -423,7 +423,7 @@ public class MageBook extends JComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addEmblem(Emblem emblem, BigCard bigCard, UUID gameId, Rectangle rectangle) {
|
private void addEmblem(Emblem emblem, BigCard bigCard, UUID gameId, Rectangle rectangle) {
|
||||||
CardView cardView = new CardView(new EmblemView(emblem));
|
CardView cardView = new CardView(new EmblemView(emblem, null));
|
||||||
addCard(cardView, bigCard, gameId, rectangle, false);
|
addCard(cardView, bigCard, gameId, rectangle, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -433,7 +433,7 @@ public class MageBook extends JComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPlane(Plane plane, BigCard bigCard, UUID gameId, Rectangle rectangle) {
|
private void addPlane(Plane plane, BigCard bigCard, UUID gameId, Rectangle rectangle) {
|
||||||
CardView cardView = new CardView(new PlaneView(plane));
|
CardView cardView = new CardView(new PlaneView(plane, null));
|
||||||
addCard(cardView, bigCard, gameId, rectangle, false);
|
addCard(cardView, bigCard, gameId, rectangle, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ public class CardHintsHelperDialog extends MageDialog implements MageDesktopIcon
|
||||||
settings.add(this.currentGroup.toString());
|
settings.add(this.currentGroup.toString());
|
||||||
|
|
||||||
// from search
|
// from search
|
||||||
if (this.currentSearch.length() > 0 && !this.currentSearch.equals(SEARCH_EMPTY_TEXT)) {
|
if (!this.currentSearch.isEmpty() && !this.currentSearch.equals(SEARCH_EMPTY_TEXT)) {
|
||||||
settings.add(this.currentSearch);
|
settings.add(this.currentSearch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,6 +235,11 @@ public class CardHintsHelperDialog extends MageDialog implements MageDesktopIcon
|
||||||
this.lastHints.add(new CardHintInfo(currentPlayer, "hand", card));
|
this.lastHints.add(new CardHintInfo(currentPlayer, "hand", card));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// helper emblems for better UX
|
||||||
|
this.lastGameView.getMyHelperEmblems().values().forEach(card -> {
|
||||||
|
this.lastHints.add(new CardHintInfo(currentPlayer, "xmage", card));
|
||||||
|
});
|
||||||
|
|
||||||
// stack
|
// stack
|
||||||
this.lastGameView.getStack().values().forEach(card -> {
|
this.lastGameView.getStack().values().forEach(card -> {
|
||||||
this.lastHints.add(new CardHintInfo(currentPlayer, "stack", card));
|
this.lastHints.add(new CardHintInfo(currentPlayer, "stack", card));
|
||||||
|
|
|
||||||
|
|
@ -223,20 +223,20 @@ public class TestCardRenderDialog extends MageDialog {
|
||||||
return cardView;
|
return cardView;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbilityView createEmblem(Emblem emblem) {
|
private AbilityView createEmblem(Game game, Emblem emblem) {
|
||||||
AbilityView emblemView = new AbilityView(emblem.getAbilities().get(0), emblem.getName(), new CardView(new EmblemView(emblem)));
|
AbilityView emblemView = new AbilityView(emblem.getAbilities().get(0), emblem.getName(), new CardView(new EmblemView(emblem, game)));
|
||||||
emblemView.setName(emblem.getName());
|
emblemView.setName(emblem.getName());
|
||||||
return emblemView;
|
return emblemView;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbilityView createDungeon(Dungeon dungeon) {
|
private AbilityView createDungeon(Game game, Dungeon dungeon) {
|
||||||
AbilityView emblemView = new AbilityView(dungeon.getAbilities().get(0), dungeon.getName(), new CardView(new DungeonView(dungeon)));
|
AbilityView emblemView = new AbilityView(dungeon.getAbilities().get(0), dungeon.getName(), new CardView(new DungeonView(dungeon)));
|
||||||
emblemView.setName(dungeon.getName());
|
emblemView.setName(dungeon.getName());
|
||||||
return emblemView;
|
return emblemView;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbilityView createPlane(Plane plane) {
|
private AbilityView createPlane(Game game, Plane plane) {
|
||||||
AbilityView planeView = new AbilityView(plane.getAbilities().get(0), plane.getName(), new CardView(new PlaneView(plane)));
|
AbilityView planeView = new AbilityView(plane.getAbilities().get(0), plane.getName(), new CardView(new PlaneView(plane, game)));
|
||||||
planeView.setName(plane.getName());
|
planeView.setName(plane.getName());
|
||||||
return planeView;
|
return planeView;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.game.getMyHand().values().forEach(c -> this.allCardsIndex.put(c.getId(), c));
|
this.game.getMyHand().values().forEach(c -> this.allCardsIndex.put(c.getId(), c));
|
||||||
|
this.game.getMyHelperEmblems().values().forEach(c -> this.allCardsIndex.put(c.getId(), c));
|
||||||
this.game.getStack().values().forEach(c -> this.allCardsIndex.put(c.getId(), c));
|
this.game.getStack().values().forEach(c -> this.allCardsIndex.put(c.getId(), c));
|
||||||
this.game.getExile()
|
this.game.getExile()
|
||||||
.stream()
|
.stream()
|
||||||
|
|
|
||||||
|
|
@ -821,7 +821,7 @@ public class CardView extends SimpleCardView {
|
||||||
this.mageObjectType = MageObjectType.EMBLEM;
|
this.mageObjectType = MageObjectType.EMBLEM;
|
||||||
Emblem emblem = (Emblem) object;
|
Emblem emblem = (Emblem) object;
|
||||||
this.rarity = Rarity.SPECIAL;
|
this.rarity = Rarity.SPECIAL;
|
||||||
this.rules = new ArrayList<>(emblem.getAbilities().getRules(emblem.getName()));
|
this.rules = new ArrayList<>(emblem.getAbilities().getRules(game, emblem));
|
||||||
} else if (object instanceof Dungeon) {
|
} else if (object instanceof Dungeon) {
|
||||||
this.mageObjectType = MageObjectType.DUNGEON;
|
this.mageObjectType = MageObjectType.DUNGEON;
|
||||||
Dungeon dungeon = (Dungeon) object;
|
Dungeon dungeon = (Dungeon) object;
|
||||||
|
|
@ -834,14 +834,14 @@ public class CardView extends SimpleCardView {
|
||||||
this.frameStyle = FrameStyle.M15_NORMAL;
|
this.frameStyle = FrameStyle.M15_NORMAL;
|
||||||
// Display in landscape/rotated/on its side
|
// Display in landscape/rotated/on its side
|
||||||
this.rotate = true;
|
this.rotate = true;
|
||||||
this.rules = new ArrayList<>(plane.getAbilities().getRules(plane.getName()));
|
this.rules = new ArrayList<>(plane.getAbilities().getRules(game, plane));
|
||||||
} else if (object instanceof Designation) {
|
} else if (object instanceof Designation) {
|
||||||
this.mageObjectType = MageObjectType.DESIGNATION;
|
this.mageObjectType = MageObjectType.DESIGNATION;
|
||||||
Designation designation = (Designation) object;
|
Designation designation = (Designation) object;
|
||||||
this.rarity = Rarity.SPECIAL;
|
this.rarity = Rarity.SPECIAL;
|
||||||
this.frameStyle = FrameStyle.M15_NORMAL;
|
this.frameStyle = FrameStyle.M15_NORMAL;
|
||||||
// Display in landscape/rotated/on its side
|
// Display in landscape/rotated/on its side
|
||||||
this.rules = new ArrayList<>(designation.getAbilities().getRules(designation.getName()));
|
this.rules = new ArrayList<>(designation.getAbilities().getRules(game, designation));
|
||||||
}
|
}
|
||||||
if (this.rarity == null && object instanceof StackAbility) {
|
if (this.rarity == null && object instanceof StackAbility) {
|
||||||
StackAbility stackAbility = (StackAbility) object;
|
StackAbility stackAbility = (StackAbility) object;
|
||||||
|
|
@ -1106,7 +1106,7 @@ public class CardView extends SimpleCardView {
|
||||||
this.name = token.getName();
|
this.name = token.getName();
|
||||||
this.displayName = token.getName();
|
this.displayName = token.getName();
|
||||||
this.displayFullName = token.getName();
|
this.displayFullName = token.getName();
|
||||||
this.rules = new ArrayList<>(token.getAbilities().getRules(this.name));
|
this.rules = new ArrayList<>(token.getAbilities().getRules(game, token));
|
||||||
this.power = token.getPower().toString();
|
this.power = token.getPower().toString();
|
||||||
this.toughness = token.getToughness().toString();
|
this.toughness = token.getToughness().toString();
|
||||||
this.loyalty = "";
|
this.loyalty = "";
|
||||||
|
|
|
||||||
|
|
@ -107,26 +107,22 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
|
||||||
isCard = true;
|
isCard = true;
|
||||||
}
|
}
|
||||||
if (sourceObject instanceof Emblem) {
|
if (sourceObject instanceof Emblem) {
|
||||||
// Emblems are not normally OUTSIDE, except the special Radiation Emblem from rad counters.
|
// emblems are not normally OUTSIDE, except the helper emblems like Radiation
|
||||||
abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new EmblemView((Emblem) sourceObject)));
|
abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new EmblemView((Emblem) sourceObject, game)));
|
||||||
abilityView.setName(sourceObject.getName());
|
abilityView.setName(sourceObject.getName());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COMMAND:
|
case COMMAND:
|
||||||
sourceObject = game.getObject(ability.getSourceId());
|
sourceObject = game.getObject(ability.getSourceId());
|
||||||
if (sourceObject instanceof Emblem) {
|
if (sourceObject instanceof Emblem) {
|
||||||
// Card sourceCard = (Card) ((Emblem) sourceObject).getSourceObject();
|
abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new EmblemView((Emblem) sourceObject, game)));
|
||||||
// if (sourceCard == null) {
|
|
||||||
// throw new IllegalArgumentException("Source card for emblem not found.");
|
|
||||||
// }
|
|
||||||
abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new EmblemView((Emblem) sourceObject)));
|
|
||||||
abilityView.setName(sourceObject.getName());
|
abilityView.setName(sourceObject.getName());
|
||||||
// abilityView.setExpansionSetCode(sourceCard.getExpansionSetCode());
|
// abilityView.setExpansionSetCode(sourceCard.getExpansionSetCode());
|
||||||
} else if (sourceObject instanceof Dungeon) {
|
} else if (sourceObject instanceof Dungeon) {
|
||||||
abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new DungeonView((Dungeon) sourceObject)));
|
abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new DungeonView((Dungeon) sourceObject)));
|
||||||
abilityView.setName(sourceObject.getName());
|
abilityView.setName(sourceObject.getName());
|
||||||
} else if (sourceObject instanceof Plane) {
|
} else if (sourceObject instanceof Plane) {
|
||||||
abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new PlaneView((Plane) sourceObject)));
|
abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new PlaneView((Plane) sourceObject, game)));
|
||||||
abilityView.setName(sourceObject.getName());
|
abilityView.setName(sourceObject.getName());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package mage.view;
|
package mage.view;
|
||||||
|
|
||||||
|
import mage.game.Game;
|
||||||
import mage.game.command.Emblem;
|
import mage.game.command.Emblem;
|
||||||
import mage.game.command.emblems.EmblemOfCard;
|
import mage.game.command.emblems.EmblemOfCard;
|
||||||
import mage.players.PlayableObjectStats;
|
import mage.players.PlayableObjectStats;
|
||||||
|
|
@ -23,13 +24,13 @@ public class EmblemView implements CommandObjectView, Serializable {
|
||||||
protected List<String> rules;
|
protected List<String> rules;
|
||||||
protected PlayableObjectStats playableStats = new PlayableObjectStats();
|
protected PlayableObjectStats playableStats = new PlayableObjectStats();
|
||||||
|
|
||||||
public EmblemView(Emblem emblem) {
|
public EmblemView(Emblem emblem, Game game) {
|
||||||
this.id = emblem.getId();
|
this.id = emblem.getId();
|
||||||
this.name = emblem.getName();
|
this.name = emblem.getName();
|
||||||
this.imageFileName = emblem.getImageFileName();
|
this.imageFileName = emblem.getImageFileName();
|
||||||
this.imageNumber = emblem.getImageNumber();
|
this.imageNumber = emblem.getImageNumber();
|
||||||
this.expansionSetCode = emblem.getExpansionSetCode();
|
this.expansionSetCode = emblem.getExpansionSetCode();
|
||||||
this.rules = emblem.getAbilities().getRules(emblem.getName());
|
this.rules = emblem.getAbilities().getRules(game, emblem);
|
||||||
if (emblem instanceof EmblemOfCard) {
|
if (emblem instanceof EmblemOfCard) {
|
||||||
cardNumber = emblem.getCardNumber();
|
cardNumber = emblem.getCardNumber();
|
||||||
usesVariousArt = ((EmblemOfCard) emblem).getUsesVariousArt();
|
usesVariousArt = ((EmblemOfCard) emblem).getUsesVariousArt();
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ public class GameView implements Serializable {
|
||||||
private final List<PlayerView> players = new ArrayList<>();
|
private final List<PlayerView> players = new ArrayList<>();
|
||||||
private UUID myPlayerId = null; // null for watcher
|
private UUID myPlayerId = null; // null for watcher
|
||||||
private final CardsView myHand = new CardsView();
|
private final CardsView myHand = new CardsView();
|
||||||
|
private final CardsView myHelperEmblems = new CardsView();
|
||||||
private PlayableObjectsList canPlayObjects;
|
private PlayableObjectsList canPlayObjects;
|
||||||
private final Map<String, SimpleCardsView> opponentHands = new HashMap<>();
|
private final Map<String, SimpleCardsView> opponentHands = new HashMap<>();
|
||||||
private final Map<String, SimpleCardsView> watchedHands = new HashMap<>();
|
private final Map<String, SimpleCardsView> watchedHands = new HashMap<>();
|
||||||
|
|
@ -75,6 +76,11 @@ public class GameView implements Serializable {
|
||||||
createdForPlayer = player;
|
createdForPlayer = player;
|
||||||
this.myPlayerId = player.getId();
|
this.myPlayerId = player.getId();
|
||||||
this.myHand.putAll(new CardsView(game, player.getHand().getCards(game), createdForPlayerId));
|
this.myHand.putAll(new CardsView(game, player.getHand().getCards(game), createdForPlayerId));
|
||||||
|
state.getHelperEmblems().stream()
|
||||||
|
.filter(emblem -> emblem.isControlledBy(player.getId()))
|
||||||
|
.forEach(emblem -> {
|
||||||
|
this.myHelperEmblems.put(emblem.getId(), new CardView(new EmblemView(emblem, game)));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (StackObject stackObject : state.getStack()) {
|
for (StackObject stackObject : state.getStack()) {
|
||||||
|
|
@ -112,7 +118,7 @@ public class GameView implements Serializable {
|
||||||
stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, token.getName(), token, new CardView(token, game)));
|
stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, token.getName(), token, new CardView(token, game)));
|
||||||
checkPaid(stackObject.getId(), (StackAbility) stackObject);
|
checkPaid(stackObject.getId(), (StackAbility) stackObject);
|
||||||
} else if (object instanceof Emblem) {
|
} else if (object instanceof Emblem) {
|
||||||
CardView cardView = new CardView(new EmblemView((Emblem) object));
|
CardView cardView = new CardView(new EmblemView((Emblem) object, game));
|
||||||
// Card sourceCard = (Card) ((Emblem) object).getSourceObject();
|
// Card sourceCard = (Card) ((Emblem) object).getSourceObject();
|
||||||
stackObject.setName(object.getName());
|
stackObject.setName(object.getName());
|
||||||
// ((StackAbility) stackObject).setExpansionSetCode(sourceCard.getExpansionSetCode());
|
// ((StackAbility) stackObject).setExpansionSetCode(sourceCard.getExpansionSetCode());
|
||||||
|
|
@ -126,7 +132,7 @@ public class GameView implements Serializable {
|
||||||
new StackAbilityView(game, (StackAbility) stackObject, object.getName(), object, cardView));
|
new StackAbilityView(game, (StackAbility) stackObject, object.getName(), object, cardView));
|
||||||
checkPaid(stackObject.getId(), ((StackAbility) stackObject));
|
checkPaid(stackObject.getId(), ((StackAbility) stackObject));
|
||||||
} else if (object instanceof Plane) {
|
} else if (object instanceof Plane) {
|
||||||
CardView cardView = new CardView(new PlaneView((Plane) object));
|
CardView cardView = new CardView(new PlaneView((Plane) object, game));
|
||||||
stackObject.setName(object.getName());
|
stackObject.setName(object.getName());
|
||||||
stack.put(stackObject.getId(),
|
stack.put(stackObject.getId(),
|
||||||
new StackAbilityView(game, (StackAbility) stackObject, object.getName(), object, cardView));
|
new StackAbilityView(game, (StackAbility) stackObject, object.getName(), object, cardView));
|
||||||
|
|
@ -239,6 +245,10 @@ public class GameView implements Serializable {
|
||||||
return myHand;
|
return myHand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CardsView getMyHelperEmblems() {
|
||||||
|
return myHelperEmblems;
|
||||||
|
}
|
||||||
|
|
||||||
public PlayerView getMyPlayer() {
|
public PlayerView getMyPlayer() {
|
||||||
if (this.myPlayerId == null) {
|
if (this.myPlayerId == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package mage.view;
|
package mage.view;
|
||||||
|
|
||||||
|
import mage.game.Game;
|
||||||
import mage.game.command.Plane;
|
import mage.game.command.Plane;
|
||||||
import mage.players.PlayableObjectStats;
|
import mage.players.PlayableObjectStats;
|
||||||
|
|
||||||
|
|
@ -20,13 +21,13 @@ public class PlaneView implements CommandObjectView, Serializable {
|
||||||
protected List<String> rules;
|
protected List<String> rules;
|
||||||
protected PlayableObjectStats playableStats = new PlayableObjectStats();
|
protected PlayableObjectStats playableStats = new PlayableObjectStats();
|
||||||
|
|
||||||
public PlaneView(Plane plane) {
|
public PlaneView(Plane plane, Game game) {
|
||||||
this.id = plane.getId();
|
this.id = plane.getId();
|
||||||
this.name = plane.getName();
|
this.name = plane.getName();
|
||||||
this.imageFileName = plane.getImageFileName();
|
this.imageFileName = plane.getImageFileName();
|
||||||
this.imageNumber = plane.getImageNumber();
|
this.imageNumber = plane.getImageNumber();
|
||||||
this.expansionSetCode = plane.getExpansionSetCode();
|
this.expansionSetCode = plane.getExpansionSetCode();
|
||||||
this.rules = plane.getAbilities().getRules(plane.getName());
|
this.rules = plane.getAbilities().getRules(game, plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ public class PlayerView implements Serializable {
|
||||||
private final CardsView graveyard = new CardsView();
|
private final CardsView graveyard = new CardsView();
|
||||||
private final CardsView exile = new CardsView();
|
private final CardsView exile = new CardsView();
|
||||||
private final CardsView sideboard = new CardsView();
|
private final CardsView sideboard = new CardsView();
|
||||||
|
private final CardsView helperCards = new CardsView();
|
||||||
private final Map<UUID, PermanentView> battlefield = new LinkedHashMap<>();
|
private final Map<UUID, PermanentView> battlefield = new LinkedHashMap<>();
|
||||||
private final CardView topCard;
|
private final CardView topCard;
|
||||||
private final UserData userData;
|
private final UserData userData;
|
||||||
|
|
@ -120,7 +121,7 @@ public class PlayerView implements Serializable {
|
||||||
if (commandObject instanceof Emblem) {
|
if (commandObject instanceof Emblem) {
|
||||||
Emblem emblem = (Emblem) commandObject;
|
Emblem emblem = (Emblem) commandObject;
|
||||||
if (emblem.getControllerId().equals(this.playerId)) {
|
if (emblem.getControllerId().equals(this.playerId)) {
|
||||||
commandList.add(new EmblemView(emblem));
|
commandList.add(new EmblemView(emblem, game));
|
||||||
}
|
}
|
||||||
} else if (commandObject instanceof Dungeon) {
|
} else if (commandObject instanceof Dungeon) {
|
||||||
Dungeon dungeon = (Dungeon) commandObject;
|
Dungeon dungeon = (Dungeon) commandObject;
|
||||||
|
|
@ -130,7 +131,7 @@ public class PlayerView implements Serializable {
|
||||||
} else if (commandObject instanceof Plane) {
|
} else if (commandObject instanceof Plane) {
|
||||||
Plane plane = (Plane) commandObject;
|
Plane plane = (Plane) commandObject;
|
||||||
// Planes are universal and all players can see them.
|
// Planes are universal and all players can see them.
|
||||||
commandList.add(new PlaneView(plane));
|
commandList.add(new PlaneView(plane, game));
|
||||||
} else if (commandObject instanceof Commander) {
|
} else if (commandObject instanceof Commander) {
|
||||||
Commander commander = (Commander) commandObject;
|
Commander commander = (Commander) commandObject;
|
||||||
if (commander.getControllerId().equals(this.playerId)) {
|
if (commander.getControllerId().equals(this.playerId)) {
|
||||||
|
|
|
||||||
|
|
@ -156,9 +156,7 @@ public class TappedForManaFromMultipleEffects extends CardTestPlayerBase {
|
||||||
|
|
||||||
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}, Sacrifice a Fo");
|
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}, Sacrifice a Fo");
|
||||||
setChoice(playerA, "Forest"); // sacrifice
|
setChoice(playerA, "Forest"); // sacrifice
|
||||||
setChoice(playerA, "Green");
|
setChoiceAmount(playerA, 0, 3); // x0 red, x3 green
|
||||||
setChoice(playerA, "Green");
|
|
||||||
setChoice(playerA, "Green");
|
|
||||||
checkManaPool("must produce green", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "G", 3);
|
checkManaPool("must produce green", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "G", 3);
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
|
|
@ -177,9 +175,7 @@ public class TappedForManaFromMultipleEffects extends CardTestPlayerBase {
|
||||||
|
|
||||||
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}, Sacrifice a Fo");
|
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}, Sacrifice a Fo");
|
||||||
setChoice(playerA, "Forest"); // sacrifice
|
setChoice(playerA, "Forest"); // sacrifice
|
||||||
setChoice(playerA, "Green");
|
setChoiceAmount(playerA, 0, 3); // x0 red, x3 green
|
||||||
setChoice(playerA, "Green");
|
|
||||||
setChoice(playerA, "Green");
|
|
||||||
checkManaPool("must produce green", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "G", 3 * 2); // double by mana reflect
|
checkManaPool("must produce green", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "G", 3 * 2); // double by mana reflect
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
|
|
|
||||||
|
|
@ -2892,7 +2892,7 @@ public class TestPlayer implements Player {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Assert.fail(String.format("Missing choice in multi amount: %s (pos %d - %s)", type.getHeader(), i + 1, messages.get(i)));
|
Assert.fail(String.format("Missing choice in multi amount: %s (pos %d - %s)", type.getHeader(), i, messages));
|
||||||
}
|
}
|
||||||
|
|
||||||
// extra check
|
// extra check
|
||||||
|
|
|
||||||
|
|
@ -2258,7 +2258,7 @@ public class VerifyCardDataTest {
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println(card.getName() + " " + card.getManaCost().getText());
|
System.out.println(card.getName() + " " + card.getManaCost().getText());
|
||||||
if (card instanceof SplitCard || card instanceof ModalDoubleFacedCard) {
|
if (card instanceof SplitCard || card instanceof ModalDoubleFacedCard) {
|
||||||
card.getAbilities().getRules(card.getName()).forEach(this::printAbilityText);
|
card.getAbilities().getRules().forEach(this::printAbilityText);
|
||||||
} else {
|
} else {
|
||||||
card.getRules().forEach(this::printAbilityText);
|
card.getRules().forEach(this::printAbilityText);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
package mage.abilities;
|
package mage.abilities;
|
||||||
|
|
||||||
|
import mage.MageObject;
|
||||||
import mage.abilities.keyword.ProtectionAbility;
|
import mage.abilities.keyword.ProtectionAbility;
|
||||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
|
@ -18,7 +19,6 @@ import java.util.function.Predicate;
|
||||||
* interface for this.
|
* interface for this.
|
||||||
*
|
*
|
||||||
* @param <T> The ability type this collection will hold.
|
* @param <T> The ability type this collection will hold.
|
||||||
*
|
|
||||||
* @see mage.abilities.AbilitiesImpl
|
* @see mage.abilities.AbilitiesImpl
|
||||||
* @see mage.abilities.DelayedTriggeredAbilities
|
* @see mage.abilities.DelayedTriggeredAbilities
|
||||||
* @see mage.abilities.SpecialActions
|
* @see mage.abilities.SpecialActions
|
||||||
|
|
@ -27,25 +27,27 @@ import java.util.function.Predicate;
|
||||||
public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a {@link List}<{@link String}> of ability texts for the
|
* Return rules as part of another rules. Use it for text generation.
|
||||||
* given source.
|
|
||||||
*
|
|
||||||
* @param source The source to retrieve ability texts.
|
|
||||||
* @return the {@link List}<{@link String}> of ability texts.
|
|
||||||
*
|
|
||||||
* @see mage.cards.CardImpl#getRules()
|
|
||||||
* @see mage.abilities.keyword.LevelAbility#getRule()
|
|
||||||
*/
|
*/
|
||||||
List<String> getRules(String source);
|
List<String> getRules();
|
||||||
|
|
||||||
List<String> getRules(String source, boolean capitalize);
|
/**
|
||||||
|
* Return rules as part of another rules. Use it for text generation.
|
||||||
|
*/
|
||||||
|
List<String> getRules(boolean capitalize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return full rules with card hints. Use it for user's data like GameView
|
||||||
|
*
|
||||||
|
* @param game on null will ignore card hints
|
||||||
|
*/
|
||||||
|
List<String> getRules(Game game, MageObject object);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all activated abilities for the given {@link Zone}.
|
* Retrieves all activated abilities for the given {@link Zone}.
|
||||||
*
|
*
|
||||||
* @param zone The {@link Zone} for which abilities should be retrieved.
|
* @param zone The {@link Zone} for which abilities should be retrieved.
|
||||||
* @return All abilities for the given {@link Zone}
|
* @return All abilities for the given {@link Zone}
|
||||||
*
|
|
||||||
* @see mage.cards.CardImpl#getSpellAbility()
|
* @see mage.cards.CardImpl#getSpellAbility()
|
||||||
*/
|
*/
|
||||||
Abilities<ActivatedAbility> getActivatedAbilities(Zone zone);
|
Abilities<ActivatedAbility> getActivatedAbilities(Zone zone);
|
||||||
|
|
@ -55,7 +57,6 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
*
|
*
|
||||||
* @param zone The {@link Zone} for which abilities should be retrieved.
|
* @param zone The {@link Zone} for which abilities should be retrieved.
|
||||||
* @return All abilities for the given {@link Zone}
|
* @return All abilities for the given {@link Zone}
|
||||||
*
|
|
||||||
* @see mage.cards.CardImpl#getSpellAbility()
|
* @see mage.cards.CardImpl#getSpellAbility()
|
||||||
*/
|
*/
|
||||||
Abilities<ActivatedAbility> getPlayableAbilities(Zone zone);
|
Abilities<ActivatedAbility> getPlayableAbilities(Zone zone);
|
||||||
|
|
@ -68,7 +69,6 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
* {@link ActivatedManaAbilityImpl mana abilities}.
|
* {@link ActivatedManaAbilityImpl mana abilities}.
|
||||||
* @return All {@link ActivatedManaAbilityImpl mana abilities} for the given
|
* @return All {@link ActivatedManaAbilityImpl mana abilities} for the given
|
||||||
* {@link Zone}.
|
* {@link Zone}.
|
||||||
*
|
|
||||||
* @see mage.cards.CardImpl#getMana()
|
* @see mage.cards.CardImpl#getMana()
|
||||||
* @see mage.players.PlayerImpl#getManaAvailable(mage.game.Game)
|
* @see mage.players.PlayerImpl#getManaAvailable(mage.game.Game)
|
||||||
* @see mage.players.PlayerImpl#getAvailableManaProducers(mage.game.Game)
|
* @see mage.players.PlayerImpl#getAvailableManaProducers(mage.game.Game)
|
||||||
|
|
@ -85,7 +85,6 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
* @param playerId The id of the player to check availability for
|
* @param playerId The id of the player to check availability for
|
||||||
* @return All {@link ActivatedManaAbilityImpl mana abilities} for the given
|
* @return All {@link ActivatedManaAbilityImpl mana abilities} for the given
|
||||||
* {@link Zone} that can be used.
|
* {@link Zone} that can be used.
|
||||||
*
|
|
||||||
* @see mage.cards.CardImpl#getMana()
|
* @see mage.cards.CardImpl#getMana()
|
||||||
* @see mage.players.PlayerImpl#getManaAvailable(mage.game.Game)
|
* @see mage.players.PlayerImpl#getManaAvailable(mage.game.Game)
|
||||||
* @see mage.players.PlayerImpl#getAvailableManaProducers(mage.game.Game)
|
* @see mage.players.PlayerImpl#getAvailableManaProducers(mage.game.Game)
|
||||||
|
|
@ -99,22 +98,16 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
* @param zone The {@link Zone} to search for {@link StaticAbility}
|
* @param zone The {@link Zone} to search for {@link StaticAbility}
|
||||||
* @return All {@link StaticAbility static abilities} in the given
|
* @return All {@link StaticAbility static abilities} in the given
|
||||||
* {@link Zone}
|
* {@link Zone}
|
||||||
*
|
* @see mage.abilities.effects.ContinuousEffects#getLayeredEffects(mage.game.Game)
|
||||||
* @see
|
* @see mage.abilities.effects.ContinuousEffects#getApplicableRequirementEffects(mage.game.permanent.Permanent,
|
||||||
* mage.abilities.effects.ContinuousEffects#getLayeredEffects(mage.game.Game)
|
|
||||||
* @see
|
|
||||||
* mage.abilities.effects.ContinuousEffects#getApplicableRequirementEffects(mage.game.permanent.Permanent,
|
|
||||||
* mage.game.Game)
|
* mage.game.Game)
|
||||||
* @see
|
* @see mage.abilities.effects.ContinuousEffects#getApplicableRestrictionEffects(mage.game.permanent.Permanent,
|
||||||
* mage.abilities.effects.ContinuousEffects#getApplicableRestrictionEffects(mage.game.permanent.Permanent,
|
|
||||||
* mage.game.Game)
|
* mage.game.Game)
|
||||||
* @see
|
* @see mage.abilities.effects.ContinuousEffects#getApplicableReplacementEffects(mage.game.events.GameEvent,
|
||||||
* mage.abilities.effects.ContinuousEffects#getApplicableReplacementEffects(mage.game.events.GameEvent,
|
|
||||||
* mage.game.Game)
|
* mage.game.Game)
|
||||||
* @see mage.abilities.effects.ContinuousEffects#asThough(java.util.UUID,
|
* @see mage.abilities.effects.ContinuousEffects#asThough(java.util.UUID,
|
||||||
* mage.constants.AsThoughEffectType, mage.game.Game)
|
* mage.constants.AsThoughEffectType, mage.game.Game)
|
||||||
* @see
|
* @see mage.abilities.effects.ContinuousEffects#costModification(mage.abilities.Ability,
|
||||||
* mage.abilities.effects.ContinuousEffects#costModification(mage.abilities.Ability,
|
|
||||||
* mage.game.Game)
|
* mage.game.Game)
|
||||||
*/
|
*/
|
||||||
Abilities<StaticAbility> getStaticAbilities(Zone zone);
|
Abilities<StaticAbility> getStaticAbilities(Zone zone);
|
||||||
|
|
@ -133,14 +126,11 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
* @param zone The {@link Zone} to search for
|
* @param zone The {@link Zone} to search for
|
||||||
* {@link TriggeredAbility triggered abilities}
|
* {@link TriggeredAbility triggered abilities}
|
||||||
* @return All found {@link TriggeredAbility triggered abilities}.
|
* @return All found {@link TriggeredAbility triggered abilities}.
|
||||||
*
|
|
||||||
* @see mage.cards.CardImpl#checkTriggers(mage.constants.Zone,
|
* @see mage.cards.CardImpl#checkTriggers(mage.constants.Zone,
|
||||||
* mage.game.events.GameEvent, mage.game.Game)
|
* mage.game.events.GameEvent, mage.game.Game)
|
||||||
* @see
|
* @see mage.game.permanent.PermanentImpl#checkTriggers(mage.game.events.GameEvent,
|
||||||
* mage.game.permanent.PermanentImpl#checkTriggers(mage.game.events.GameEvent,
|
|
||||||
* mage.game.Game)
|
* mage.game.Game)
|
||||||
* @see
|
* @see mage.game.permanent.PermanentCard#checkPermanentOnlyTriggers(mage.game.events.ZoneChangeEvent,
|
||||||
* mage.game.permanent.PermanentCard#checkPermanentOnlyTriggers(mage.game.events.ZoneChangeEvent,
|
|
||||||
* mage.game.Game)
|
* mage.game.Game)
|
||||||
*/
|
*/
|
||||||
Abilities<TriggeredAbility> getTriggeredAbilities(Zone zone);
|
Abilities<TriggeredAbility> getTriggeredAbilities(Zone zone);
|
||||||
|
|
@ -149,16 +139,17 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
* Retrieves all {@link ProtectionAbility protection abilities}.
|
* Retrieves all {@link ProtectionAbility protection abilities}.
|
||||||
*
|
*
|
||||||
* @return All found {@link ProtectionAbility protection abilities}.
|
* @return All found {@link ProtectionAbility protection abilities}.
|
||||||
*
|
|
||||||
* @see mage.game.permanent.PermanentImpl#hasProtectionFrom(mage.MageObject)
|
* @see mage.game.permanent.PermanentImpl#hasProtectionFrom(mage.MageObject)
|
||||||
* @see mage.players.PlayerImpl#hasProtectionFrom(mage.MageObject)
|
* @see mage.players.PlayerImpl#hasProtectionFrom(mage.MageObject)
|
||||||
* @see mage.players.PlayerImpl#canDamage(mage.MageObject)
|
* @see mage.players.PlayerImpl#canDamage(mage.MageObject)
|
||||||
*/
|
*/
|
||||||
Abilities<ProtectionAbility> getProtectionAbilities();
|
Abilities<ProtectionAbility> getProtectionAbilities();
|
||||||
|
|
||||||
|
Abilities<Ability> getAllAbilities();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Method is unused, keep it around?
|
* TODO Method is unused, keep it around?
|
||||||
*
|
* <p>
|
||||||
* The only implementation seems to want to use this for totally a set of
|
* The only implementation seems to want to use this for totally a set of
|
||||||
* abilities by some arbitrary numeral value. Possibly a good method to be
|
* abilities by some arbitrary numeral value. Possibly a good method to be
|
||||||
* used by the AI's?
|
* used by the AI's?
|
||||||
|
|
@ -172,7 +163,6 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
* Sets the controller of this set of abilities.
|
* Sets the controller of this set of abilities.
|
||||||
*
|
*
|
||||||
* @param controllerId
|
* @param controllerId
|
||||||
*
|
|
||||||
* @see mage.cards.CardImpl#setControllerId(java.util.UUID)
|
* @see mage.cards.CardImpl#setControllerId(java.util.UUID)
|
||||||
* @see mage.cards.CardImpl#setOwnerId(java.util.UUID)
|
* @see mage.cards.CardImpl#setOwnerId(java.util.UUID)
|
||||||
* @see mage.game.permanent.PermanentImpl#changeControllerId(java.util.UUID,
|
* @see mage.game.permanent.PermanentImpl#changeControllerId(java.util.UUID,
|
||||||
|
|
@ -185,7 +175,6 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
* Sets the source of this set of abilities.
|
* Sets the source of this set of abilities.
|
||||||
*
|
*
|
||||||
* @param sourceId
|
* @param sourceId
|
||||||
*
|
|
||||||
* @see mage.cards.CardImpl#assignNewId()
|
* @see mage.cards.CardImpl#assignNewId()
|
||||||
*/
|
*/
|
||||||
void setSourceId(UUID sourceId);
|
void setSourceId(UUID sourceId);
|
||||||
|
|
@ -212,7 +201,7 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Method is unused, keep it around?
|
* TODO Method is unused, keep it around?
|
||||||
*
|
* <p>
|
||||||
* Gets the ability represented by the given abilityId.
|
* Gets the ability represented by the given abilityId.
|
||||||
*
|
*
|
||||||
* @param abilityId
|
* @param abilityId
|
||||||
|
|
@ -224,7 +213,7 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
* TODO The usage of this method seems redundant to that of
|
* TODO The usage of this method seems redundant to that of
|
||||||
* {@link #containsKey(java.util.UUID)} minus the fact that it searches for
|
* {@link #containsKey(java.util.UUID)} minus the fact that it searches for
|
||||||
* exact instances instead of id's of singleton Abilities.
|
* exact instances instead of id's of singleton Abilities.
|
||||||
*
|
* <p>
|
||||||
* Searches for the exact instance of the passed in ability.
|
* Searches for the exact instance of the passed in ability.
|
||||||
*
|
*
|
||||||
* @param ability
|
* @param ability
|
||||||
|
|
@ -261,6 +250,7 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if one or more of the abilities are activated mana abilities with the pollDependant flag set to true.
|
* Returns true if one or more of the abilities are activated mana abilities with the pollDependant flag set to true.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
boolean hasPoolDependantAbilities();
|
boolean hasPoolDependantAbilities();
|
||||||
|
|
@ -275,12 +265,15 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
|
|
||||||
String getValue();
|
String getValue();
|
||||||
|
|
||||||
@Deprecated // use permanent.removeAbility instead
|
@Deprecated
|
||||||
|
// use permanent.removeAbility instead
|
||||||
boolean remove(Object o);
|
boolean remove(Object o);
|
||||||
|
|
||||||
@Deprecated // use permanent.removeAbility instead
|
@Deprecated
|
||||||
|
// use permanent.removeAbility instead
|
||||||
boolean removeAll(Collection<?> c);
|
boolean removeAll(Collection<?> c);
|
||||||
|
|
||||||
@Deprecated // use permanent.removeAbility instead
|
@Deprecated
|
||||||
|
// use permanent.removeAbility instead
|
||||||
boolean removeIf(Predicate<? super T> filter);
|
boolean removeIf(Predicate<? super T> filter);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package mage.abilities;
|
package mage.abilities;
|
||||||
|
|
||||||
|
import mage.MageObject;
|
||||||
import mage.abilities.common.ZoneChangeTriggeredAbility;
|
import mage.abilities.common.ZoneChangeTriggeredAbility;
|
||||||
import mage.abilities.costs.Cost;
|
import mage.abilities.costs.Cost;
|
||||||
import mage.abilities.keyword.ProtectionAbility;
|
import mage.abilities.keyword.ProtectionAbility;
|
||||||
|
|
@ -7,6 +8,7 @@ import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||||
import mage.abilities.mana.ManaAbility;
|
import mage.abilities.mana.ManaAbility;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
import mage.util.CardUtil;
|
||||||
import mage.util.ThreadLocalStringBuilder;
|
import mage.util.ThreadLocalStringBuilder;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
|
@ -44,12 +46,12 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getRules(String source) {
|
public List<String> getRules() {
|
||||||
return getRules(source, true);
|
return getRules(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getRules(String source, boolean capitalize) {
|
public List<String> getRules(boolean capitalize) {
|
||||||
List<String> rules = new ArrayList<>();
|
List<String> rules = new ArrayList<>();
|
||||||
|
|
||||||
for (T ability : this) {
|
for (T ability : this) {
|
||||||
|
|
@ -102,6 +104,12 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getRules(Game game, MageObject object) {
|
||||||
|
Abilities<Ability> sourceAbilities = this.getAllAbilities();
|
||||||
|
return CardUtil.getCardRulesWithAdditionalInfo(game, object, sourceAbilities, sourceAbilities);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activated Ability in the engine are broader than in the rules.
|
* Activated Ability in the engine are broader than in the rules.
|
||||||
* Notably SpellAbility & PlayLandAbility are ActivatedAbility,
|
* Notably SpellAbility & PlayLandAbility are ActivatedAbility,
|
||||||
|
|
@ -193,6 +201,11 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
|
||||||
.collect(Collectors.toCollection(AbilitiesImpl::new));
|
.collect(Collectors.toCollection(AbilitiesImpl::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Abilities<Ability> getAllAbilities() {
|
||||||
|
return stream().collect(Collectors.toCollection(AbilitiesImpl::new));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setControllerId(UUID controllerId) {
|
public void setControllerId(UUID controllerId) {
|
||||||
for (Ability ability : this) {
|
for (Ability ability : this) {
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ public class CompoundAbility extends AbilitiesImpl<Ability> {
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
List<String> rules = super.getRules(null, false);
|
List<String> rules = super.getRules(false);
|
||||||
for (int index = 0; index < rules.size(); index++) {
|
for (int index = 0; index < rules.size(); index++) {
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
if (index < rules.size() - 1) {
|
if (index < rules.size() - 1) {
|
||||||
|
|
|
||||||
|
|
@ -309,7 +309,7 @@ public class TriggeredAbilities extends LinkedHashMap<String, TriggeredAbility>
|
||||||
public void removeAbilitiesOfNonExistingSources(Game game) {
|
public void removeAbilitiesOfNonExistingSources(Game game) {
|
||||||
// e.g. Token that had triggered abilities
|
// e.g. Token that had triggered abilities
|
||||||
entrySet().removeIf(entry -> game.getObject(entry.getValue().getSourceId()) == null
|
entrySet().removeIf(entry -> game.getObject(entry.getValue().getSourceId()) == null
|
||||||
&& game.getState().getInherentEmblems().stream().noneMatch(emblem -> emblem.getId().equals(entry.getValue().getSourceId()))
|
&& game.getState().getHelperEmblems().stream().noneMatch(emblem -> emblem.getId().equals(entry.getValue().getSourceId()))
|
||||||
&& game.getState().getDesignations().stream().noneMatch(designation -> designation.getId().equals(entry.getValue().getSourceId())));
|
&& game.getState().getDesignations().stream().noneMatch(designation -> designation.getId().equals(entry.getValue().getSourceId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1338,7 +1338,7 @@ public class ContinuousEffects implements Serializable {
|
||||||
effectsMap.put(key, object.getIdName() + ": " + ability.getRule(object.getName()));
|
effectsMap.put(key, object.getIdName() + ": " + ability.getRule(object.getName()));
|
||||||
objectsMap.put(key, object);
|
objectsMap.put(key, object);
|
||||||
} else {
|
} else {
|
||||||
effectsMap.put(key, entry.getKey().getText(null));
|
effectsMap.put(key, entry.getKey().getText(ability.getModes().getMode()));
|
||||||
objectsMap.put(key, null);
|
objectsMap.put(key, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ public class GetEmblemEffect extends OneShotEffect {
|
||||||
public String getText() {
|
public String getText() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("you get an emblem with \"");
|
sb.append("you get an emblem with \"");
|
||||||
List<String> rules = emblem.getAbilities().getRules(null);
|
List<String> rules = emblem.getAbilities().getRules();
|
||||||
sb.append(rules.get(0));
|
sb.append(rules.get(0));
|
||||||
if (rules.size() == 2) {
|
if (rules.size() == 2) {
|
||||||
sb.append("\" and \"");
|
sb.append("\" and \"");
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import mage.game.Game;
|
||||||
import mage.game.command.Emblem;
|
import mage.game.command.Emblem;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -54,6 +55,6 @@ public class GetEmblemTargetPlayerEffect extends OneShotEffect {
|
||||||
return staticText;
|
return staticText;
|
||||||
}
|
}
|
||||||
return getTargetPointer().describeTargets(mode.getTargets(), "that player")
|
return getTargetPointer().describeTargets(mode.getTargets(), "that player")
|
||||||
+ " gets an emblem with \"" + String.join("; ", emblem.getAbilities().getRules(null)) + "\"";
|
+ " gets an emblem with \"" + String.join("; ", emblem.getAbilities().getRules()) + "\"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ public class LevelerCardBuilder {
|
||||||
sb.append(power);
|
sb.append(power);
|
||||||
sb.append('/');
|
sb.append('/');
|
||||||
sb.append(toughness);
|
sb.append(toughness);
|
||||||
List<String> abilityText = abilities.getRules("{this}");
|
List<String> abilityText = abilities.getRules();
|
||||||
if (!abilityText.isEmpty()) {
|
if (!abilityText.isEmpty()) {
|
||||||
sb.append("<br>");
|
sb.append("<br>");
|
||||||
sb.append(abilityText.stream().collect(Collectors.joining("<br>")));
|
sb.append(abilityText.stream().collect(Collectors.joining("<br>")));
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ public abstract class AdventureCard extends CardImpl {
|
||||||
public List<String> getSharedRules(Game game) {
|
public List<String> getSharedRules(Game game) {
|
||||||
// rules without spellcard
|
// rules without spellcard
|
||||||
Abilities<Ability> sourceAbilities = this.getSharedAbilities(game);
|
Abilities<Ability> sourceAbilities = this.getSharedAbilities(game);
|
||||||
return CardUtil.getCardRulesWithAdditionalInfo(game, this.getId(), this.getName(), sourceAbilities, sourceAbilities);
|
return CardUtil.getCardRulesWithAdditionalInfo(game, this, sourceAbilities, sourceAbilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -230,13 +230,13 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
@Override
|
@Override
|
||||||
public List<String> getRules() {
|
public List<String> getRules() {
|
||||||
Abilities<Ability> sourceAbilities = this.getAbilities();
|
Abilities<Ability> sourceAbilities = this.getAbilities();
|
||||||
return CardUtil.getCardRulesWithAdditionalInfo(this.getId(), this.getName(), sourceAbilities, sourceAbilities);
|
return CardUtil.getCardRulesWithAdditionalInfo(this, sourceAbilities, sourceAbilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getRules(Game game) {
|
public List<String> getRules(Game game) {
|
||||||
Abilities<Ability> sourceAbilities = this.getAbilities(game);
|
Abilities<Ability> sourceAbilities = this.getAbilities(game);
|
||||||
return CardUtil.getCardRulesWithAdditionalInfo(game, this.getId(), this.getName(), sourceAbilities, sourceAbilities);
|
return CardUtil.getCardRulesWithAdditionalInfo(game, this, sourceAbilities, sourceAbilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -358,8 +358,7 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH
|
||||||
// rules must show only main side (another side visible by toggle/transform button in GUI)
|
// rules must show only main side (another side visible by toggle/transform button in GUI)
|
||||||
// card hints from both sides
|
// card hints from both sides
|
||||||
return CardUtil.getCardRulesWithAdditionalInfo(
|
return CardUtil.getCardRulesWithAdditionalInfo(
|
||||||
this.getId(),
|
this,
|
||||||
this.getName(),
|
|
||||||
this.getInnerAbilities(true, false),
|
this.getInnerAbilities(true, false),
|
||||||
this.getInnerAbilities(true, true)
|
this.getInnerAbilities(true, true)
|
||||||
);
|
);
|
||||||
|
|
@ -371,8 +370,7 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH
|
||||||
// card hints from both sides
|
// card hints from both sides
|
||||||
return CardUtil.getCardRulesWithAdditionalInfo(
|
return CardUtil.getCardRulesWithAdditionalInfo(
|
||||||
game,
|
game,
|
||||||
this.getId(),
|
this,
|
||||||
this.getName(),
|
|
||||||
this.getInnerAbilities(game, true, false),
|
this.getInnerAbilities(game, true, false),
|
||||||
this.getInnerAbilities(game, true, true)
|
this.getInnerAbilities(game, true, true)
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -189,8 +189,7 @@ public abstract class SplitCard extends CardImpl implements CardWithHalves {
|
||||||
public List<String> getRules() {
|
public List<String> getRules() {
|
||||||
Abilities<Ability> sourceAbilities = this.getAbilities();
|
Abilities<Ability> sourceAbilities = this.getAbilities();
|
||||||
List<String> res = CardUtil.getCardRulesWithAdditionalInfo(
|
List<String> res = CardUtil.getCardRulesWithAdditionalInfo(
|
||||||
this.getId(),
|
this,
|
||||||
this.getName(),
|
|
||||||
sourceAbilities,
|
sourceAbilities,
|
||||||
sourceAbilities
|
sourceAbilities
|
||||||
);
|
);
|
||||||
|
|
@ -205,8 +204,7 @@ public abstract class SplitCard extends CardImpl implements CardWithHalves {
|
||||||
Abilities<Ability> sourceAbilities = this.getAbilities(game);
|
Abilities<Ability> sourceAbilities = this.getAbilities(game);
|
||||||
List<String> res = CardUtil.getCardRulesWithAdditionalInfo(
|
List<String> res = CardUtil.getCardRulesWithAdditionalInfo(
|
||||||
game,
|
game,
|
||||||
this.getId(),
|
this,
|
||||||
this.getName(),
|
|
||||||
sourceAbilities,
|
sourceAbilities,
|
||||||
sourceAbilities
|
sourceAbilities
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -119,8 +119,7 @@ public class MockSplitCard extends SplitCard implements MockableCard {
|
||||||
// so a MockSplitCard must ignore it (duplicate fix)
|
// so a MockSplitCard must ignore it (duplicate fix)
|
||||||
Abilities<Ability> sourceAbilities = this.getAbilities();
|
Abilities<Ability> sourceAbilities = this.getAbilities();
|
||||||
return CardUtil.getCardRulesWithAdditionalInfo(
|
return CardUtil.getCardRulesWithAdditionalInfo(
|
||||||
this.getId(),
|
this,
|
||||||
this.getName(),
|
|
||||||
sourceAbilities,
|
sourceAbilities,
|
||||||
sourceAbilities
|
sourceAbilities
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ public enum TokenRepository {
|
||||||
public static final String XMAGE_IMAGE_NAME_NIGHT = "Night";
|
public static final String XMAGE_IMAGE_NAME_NIGHT = "Night";
|
||||||
public static final String XMAGE_IMAGE_NAME_THE_MONARCH = "The Monarch";
|
public static final String XMAGE_IMAGE_NAME_THE_MONARCH = "The Monarch";
|
||||||
public static final String XMAGE_IMAGE_NAME_RADIATION = "Radiation";
|
public static final String XMAGE_IMAGE_NAME_RADIATION = "Radiation";
|
||||||
|
public static final String XMAGE_IMAGE_NAME_HELPER_EMBLEM = "Helper Emblem";
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(TokenRepository.class);
|
private static final Logger logger = Logger.getLogger(TokenRepository.class);
|
||||||
|
|
||||||
|
|
@ -305,6 +306,10 @@ public enum TokenRepository {
|
||||||
// Radiation (for trigger)
|
// Radiation (for trigger)
|
||||||
res.add(createXmageToken(XMAGE_IMAGE_NAME_RADIATION, 1, "https://api.scryfall.com/cards/tpip/22/en?format=image"));
|
res.add(createXmageToken(XMAGE_IMAGE_NAME_RADIATION, 1, "https://api.scryfall.com/cards/tpip/22/en?format=image"));
|
||||||
|
|
||||||
|
// Helper emblem (for global card hints)
|
||||||
|
// use backface for it
|
||||||
|
res.add(createXmageToken(XMAGE_IMAGE_NAME_HELPER_EMBLEM, 1, "https://upload.wikimedia.org/wikipedia/en/a/aa/Magic_the_gathering-card_back.jpg"));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ import mage.game.command.dungeons.UndercityDungeon;
|
||||||
import mage.game.command.emblems.EmblemOfCard;
|
import mage.game.command.emblems.EmblemOfCard;
|
||||||
import mage.game.command.emblems.RadiationEmblem;
|
import mage.game.command.emblems.RadiationEmblem;
|
||||||
import mage.game.command.emblems.TheRingEmblem;
|
import mage.game.command.emblems.TheRingEmblem;
|
||||||
|
import mage.game.command.emblems.XmageHelperEmblem;
|
||||||
import mage.game.events.*;
|
import mage.game.events.*;
|
||||||
import mage.game.events.TableEvent.EventType;
|
import mage.game.events.TableEvent.EventType;
|
||||||
import mage.game.mulligan.Mulligan;
|
import mage.game.mulligan.Mulligan;
|
||||||
|
|
@ -444,7 +445,7 @@ public abstract class GameImpl implements Game {
|
||||||
return designation;
|
return designation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Emblem emblem : state.getInherentEmblems()) {
|
for (Emblem emblem : state.getHelperEmblems()) {
|
||||||
if (emblem.getId().equals(objectId)) {
|
if (emblem.getId().equals(objectId)) {
|
||||||
return emblem;
|
return emblem;
|
||||||
}
|
}
|
||||||
|
|
@ -1400,13 +1401,7 @@ public abstract class GameImpl implements Game {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rad counter mechanic for every player
|
initGameDefaultHelperEmblems();
|
||||||
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
|
||||||
// This is not a real emblem. Just a fake source for the
|
|
||||||
// inherent trigger ability related to Rad counters
|
|
||||||
// Faking a source just to display something on the stack ability.
|
|
||||||
state.addInherentEmblem(new RadiationEmblem(), playerId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initGameDefaultWatchers() {
|
public void initGameDefaultWatchers() {
|
||||||
|
|
@ -1447,6 +1442,22 @@ public abstract class GameImpl implements Game {
|
||||||
getState().addWatcher(bloodthirstWatcher);
|
getState().addWatcher(bloodthirstWatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void initGameDefaultHelperEmblems() {
|
||||||
|
|
||||||
|
// Rad Counter's trigger source
|
||||||
|
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
||||||
|
// This is not a real emblem. Just a fake source for the
|
||||||
|
// inherent trigger ability related to Rad counters
|
||||||
|
// Faking a source just to display something on the stack ability.
|
||||||
|
state.addHelperEmblem(new RadiationEmblem(), playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// global card hints for better UX
|
||||||
|
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
||||||
|
state.addHelperEmblem(new XmageHelperEmblem().withCardHint("storm counter", StormAbility.getHint()), playerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void sendStartMessage(Player choosingPlayer, Player startingPlayer) {
|
protected void sendStartMessage(Player choosingPlayer, Player startingPlayer) {
|
||||||
StringBuilder message = new StringBuilder();
|
StringBuilder message = new StringBuilder();
|
||||||
if (choosingPlayer != null) {
|
if (choosingPlayer != null) {
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
private boolean isPlaneChase;
|
private boolean isPlaneChase;
|
||||||
private List<String> seenPlanes = new ArrayList<>();
|
private List<String> seenPlanes = new ArrayList<>();
|
||||||
private List<Designation> designations = new ArrayList<>();
|
private List<Designation> designations = new ArrayList<>();
|
||||||
private List<Emblem> inherentEmblems = new ArrayList<>();
|
private List<Emblem> helperEmblems = new ArrayList<>(); // fake emblems for inner usage like better UX
|
||||||
private Exile exile;
|
private Exile exile;
|
||||||
private Battlefield battlefield;
|
private Battlefield battlefield;
|
||||||
private int turnNum = 1;
|
private int turnNum = 1;
|
||||||
|
|
@ -158,7 +158,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
this.isPlaneChase = state.isPlaneChase;
|
this.isPlaneChase = state.isPlaneChase;
|
||||||
this.seenPlanes.addAll(state.seenPlanes);
|
this.seenPlanes.addAll(state.seenPlanes);
|
||||||
this.designations.addAll(state.designations);
|
this.designations.addAll(state.designations);
|
||||||
this.inherentEmblems = CardUtil.deepCopyObject(state.inherentEmblems);
|
this.helperEmblems = CardUtil.deepCopyObject(state.helperEmblems);
|
||||||
this.exile = state.exile.copy();
|
this.exile = state.exile.copy();
|
||||||
this.battlefield = state.battlefield.copy();
|
this.battlefield = state.battlefield.copy();
|
||||||
this.turnNum = state.turnNum;
|
this.turnNum = state.turnNum;
|
||||||
|
|
@ -206,7 +206,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
exile.clear();
|
exile.clear();
|
||||||
command.clear();
|
command.clear();
|
||||||
designations.clear();
|
designations.clear();
|
||||||
inherentEmblems.clear();
|
helperEmblems.clear();
|
||||||
seenPlanes.clear();
|
seenPlanes.clear();
|
||||||
isPlaneChase = false;
|
isPlaneChase = false;
|
||||||
revealed.clear();
|
revealed.clear();
|
||||||
|
|
@ -248,7 +248,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
this.isPlaneChase = state.isPlaneChase;
|
this.isPlaneChase = state.isPlaneChase;
|
||||||
this.seenPlanes = state.seenPlanes;
|
this.seenPlanes = state.seenPlanes;
|
||||||
this.designations = state.designations;
|
this.designations = state.designations;
|
||||||
this.inherentEmblems = state.inherentEmblems;
|
this.helperEmblems = state.helperEmblems;
|
||||||
this.exile = state.exile;
|
this.exile = state.exile;
|
||||||
this.battlefield = state.battlefield;
|
this.battlefield = state.battlefield;
|
||||||
this.turnNum = state.turnNum;
|
this.turnNum = state.turnNum;
|
||||||
|
|
@ -519,12 +519,12 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
return designations;
|
return designations;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Emblem> getInherentEmblems() {
|
public List<Emblem> getHelperEmblems() {
|
||||||
return inherentEmblems;
|
return helperEmblems;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Plane getCurrentPlane() {
|
public Plane getCurrentPlane() {
|
||||||
if (command != null && command.size() > 0) {
|
if (command != null && !command.isEmpty()) {
|
||||||
for (CommandObject cobject : command) {
|
for (CommandObject cobject : command) {
|
||||||
if (cobject instanceof Plane) {
|
if (cobject instanceof Plane) {
|
||||||
return (Plane) cobject;
|
return (Plane) cobject;
|
||||||
|
|
@ -1184,16 +1184,13 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inherent triggers (Rad counters) in the rules have no source.
|
* Add fake/helper emblems for hidden source of inherent triggers like Rad counters,
|
||||||
* However to fit better with the engine, we make a fake emblem source,
|
* additional card hints like storm counter, etc. See GameImpl.initGameDefaultHelperEmblems
|
||||||
* which is not displayed in any game zone. That allows the trigger to
|
|
||||||
* have a source, which helps with a bunch of situation like hosting,
|
|
||||||
* rather than having a trigger.
|
|
||||||
* <p>
|
* <p>
|
||||||
* Should not be used except in very specific situations
|
* It allows game and GUI find and show full card object in stack's triggers, logs and hints popup.
|
||||||
*/
|
*/
|
||||||
public void addInherentEmblem(Emblem emblem, UUID controllerId) {
|
public void addHelperEmblem(Emblem emblem, UUID controllerId) {
|
||||||
getInherentEmblems().add(emblem);
|
helperEmblems.add(emblem);
|
||||||
emblem.setControllerId(controllerId);
|
emblem.setControllerId(controllerId);
|
||||||
for (Ability ability : emblem.getInitAbilities()) {
|
for (Ability ability : emblem.getInitAbilities()) {
|
||||||
ability.setControllerId(controllerId);
|
ability.setControllerId(controllerId);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import mage.constants.SubType;
|
||||||
import mage.constants.SuperType;
|
import mage.constants.SuperType;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
|
import mage.util.CardUtil;
|
||||||
import mage.util.SubTypes;
|
import mage.util.SubTypes;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
@ -37,7 +38,7 @@ public abstract class Emblem extends CommandObjectImpl {
|
||||||
private boolean copy;
|
private boolean copy;
|
||||||
private MageObject copyFrom; // copied card INFO (used to call original adjusters)
|
private MageObject copyFrom; // copied card INFO (used to call original adjusters)
|
||||||
protected FrameStyle frameStyle;
|
protected FrameStyle frameStyle;
|
||||||
private Abilities<Ability> abilites = new AbilitiesImpl<>();
|
private Abilities<Ability> abilities = new AbilitiesImpl<>();
|
||||||
|
|
||||||
public Emblem(String name) {
|
public Emblem(String name) {
|
||||||
super(name);
|
super(name);
|
||||||
|
|
@ -50,7 +51,7 @@ public abstract class Emblem extends CommandObjectImpl {
|
||||||
this.sourceObject = emblem.sourceObject;
|
this.sourceObject = emblem.sourceObject;
|
||||||
this.copy = emblem.copy;
|
this.copy = emblem.copy;
|
||||||
this.copyFrom = emblem.copyFrom;
|
this.copyFrom = emblem.copyFrom;
|
||||||
this.abilites = emblem.abilites.copy();
|
this.abilities = emblem.abilities.copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -73,7 +74,7 @@ public abstract class Emblem extends CommandObjectImpl {
|
||||||
this.setImageFileName(""); // use default
|
this.setImageFileName(""); // use default
|
||||||
this.setImageNumber(foundInfo.getImageNumber());
|
this.setImageNumber(foundInfo.getImageNumber());
|
||||||
} else {
|
} else {
|
||||||
// how-to fix: add emblem to the tokens-database
|
// how-to fix: add emblem to tokens-database.txt
|
||||||
throw new IllegalArgumentException("Wrong code usage: can't find token info for the emblem: " + this.getClass().getName());
|
throw new IllegalArgumentException("Wrong code usage: can't find token info for the emblem: " + this.getClass().getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +99,7 @@ public abstract class Emblem extends CommandObjectImpl {
|
||||||
|
|
||||||
public void setControllerId(UUID controllerId) {
|
public void setControllerId(UUID controllerId) {
|
||||||
this.controllerId = controllerId;
|
this.controllerId = controllerId;
|
||||||
this.abilites.setControllerId(controllerId);
|
this.abilities.setControllerId(controllerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -152,7 +153,7 @@ public abstract class Emblem extends CommandObjectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Abilities<Ability> getAbilities() {
|
public Abilities<Ability> getAbilities() {
|
||||||
return abilites;
|
return abilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -260,7 +261,7 @@ public abstract class Emblem extends CommandObjectImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void discardEffects() {
|
public void discardEffects() {
|
||||||
for (Ability ability : abilites) {
|
for (Ability ability : abilities) {
|
||||||
for (Effect effect : ability.getEffects()) {
|
for (Effect effect : ability.getEffects()) {
|
||||||
if (effect instanceof ContinuousEffect) {
|
if (effect instanceof ContinuousEffect) {
|
||||||
((ContinuousEffect) effect).discard();
|
((ContinuousEffect) effect).discard();
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ public class RadiationEmblem extends Emblem {
|
||||||
this.setImageFileName(""); // use default
|
this.setImageFileName(""); // use default
|
||||||
this.setImageNumber(foundInfo.getImageNumber());
|
this.setImageNumber(foundInfo.getImageNumber());
|
||||||
} else {
|
} else {
|
||||||
// how-to fix: add emblem to the tokens-database
|
// how-to fix: add emblem to the tokens-database TokenRepository->loadXmageTokens
|
||||||
throw new IllegalArgumentException("Wrong code usage: can't find xmage token info for: " + TokenRepository.XMAGE_IMAGE_NAME_RADIATION);
|
throw new IllegalArgumentException("Wrong code usage: can't find xmage token info for: " + TokenRepository.XMAGE_IMAGE_NAME_RADIATION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package mage.game.command.emblems;
|
||||||
|
|
||||||
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.effects.common.InfoEffect;
|
||||||
|
import mage.abilities.hint.Hint;
|
||||||
|
import mage.cards.FrameStyle;
|
||||||
|
import mage.cards.repository.TokenInfo;
|
||||||
|
import mage.cards.repository.TokenRepository;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.command.Emblem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GUI: inner xmage emblem to show additional info for players like global hints
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class XmageHelperEmblem extends Emblem {
|
||||||
|
|
||||||
|
public XmageHelperEmblem() {
|
||||||
|
super("Helper Emblem");
|
||||||
|
this.frameStyle = FrameStyle.M15_NORMAL;
|
||||||
|
|
||||||
|
TokenInfo foundInfo = TokenRepository.instance.findPreferredTokenInfoForXmage(TokenRepository.XMAGE_IMAGE_NAME_HELPER_EMBLEM, null);
|
||||||
|
if (foundInfo != null) {
|
||||||
|
this.setExpansionSetCode(foundInfo.getSetCode());
|
||||||
|
this.setUsesVariousArt(false);
|
||||||
|
this.setCardNumber("");
|
||||||
|
this.setImageFileName(""); // use default
|
||||||
|
this.setImageNumber(foundInfo.getImageNumber());
|
||||||
|
} else {
|
||||||
|
// how-to fix: add emblem to the tokens-database TokenRepository->loadXmageTokens
|
||||||
|
throw new IllegalArgumentException("Wrong code usage: can't find xmage token info for: " + TokenRepository.XMAGE_IMAGE_NAME_HELPER_EMBLEM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private XmageHelperEmblem(final XmageHelperEmblem card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmageHelperEmblem copy() {
|
||||||
|
return new XmageHelperEmblem(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmageHelperEmblem withCardHint(String name, Hint hint) {
|
||||||
|
this.getAbilities().add(new SimpleStaticAbility(
|
||||||
|
Zone.ALL,
|
||||||
|
new InfoEffect(name)).addHint(hint)
|
||||||
|
);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1207,9 +1207,9 @@ public final class CardUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> getCardRulesWithAdditionalInfo(UUID cardId, String cardName,
|
public static List<String> getCardRulesWithAdditionalInfo(MageObject object,
|
||||||
Abilities<Ability> rulesSource, Abilities<Ability> hintAbilities) {
|
Abilities<Ability> rulesSource, Abilities<Ability> hintAbilities) {
|
||||||
return getCardRulesWithAdditionalInfo(null, cardId, cardName, rulesSource, hintAbilities);
|
return getCardRulesWithAdditionalInfo(null, object, rulesSource, hintAbilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1218,10 +1218,10 @@ public final class CardUtil {
|
||||||
* @param rulesSource abilities list to show as rules
|
* @param rulesSource abilities list to show as rules
|
||||||
* @param hintsSource abilities list to show as card hints only (you can add additional hints here; example: from second or transformed side)
|
* @param hintsSource abilities list to show as card hints only (you can add additional hints here; example: from second or transformed side)
|
||||||
*/
|
*/
|
||||||
public static List<String> getCardRulesWithAdditionalInfo(Game game, UUID cardId, String cardName,
|
public static List<String> getCardRulesWithAdditionalInfo(Game game, MageObject object,
|
||||||
Abilities<Ability> rulesSource, Abilities<Ability> hintsSource) {
|
Abilities<Ability> rulesSource, Abilities<Ability> hintsSource) {
|
||||||
try {
|
try {
|
||||||
List<String> rules = rulesSource.getRules(cardName);
|
List<String> rules = rulesSource.getRules();
|
||||||
|
|
||||||
if (game == null || game.getPhase() == null) {
|
if (game == null || game.getPhase() == null) {
|
||||||
// dynamic hints for started game only
|
// dynamic hints for started game only
|
||||||
|
|
@ -1229,7 +1229,10 @@ public final class CardUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
// additional effect's info from card.addInfo methods
|
// additional effect's info from card.addInfo methods
|
||||||
rules.addAll(game.getState().getCardState(cardId).getInfo().values());
|
CardState cardState = game.getState().getCardState(object.getId());
|
||||||
|
if (cardState != null) {
|
||||||
|
rules.addAll(cardState.getInfo().values());
|
||||||
|
}
|
||||||
|
|
||||||
// ability hints
|
// ability hints
|
||||||
List<String> abilityHints = new ArrayList<>();
|
List<String> abilityHints = new ArrayList<>();
|
||||||
|
|
@ -1254,7 +1257,7 @@ public final class CardUtil {
|
||||||
|
|
||||||
return rules;
|
return rules;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Exception in rules generation for card: " + cardName, e);
|
logger.error("Exception in rules generation for object: " + object.getName(), e);
|
||||||
}
|
}
|
||||||
return RULES_ERROR_INFO;
|
return RULES_ERROR_INFO;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -658,7 +658,7 @@ public final class ManaUtil {
|
||||||
return getColorIdentity(
|
return getColorIdentity(
|
||||||
token.getColor(),
|
token.getColor(),
|
||||||
String.join("", token.getManaCostSymbols()),
|
String.join("", token.getManaCostSymbols()),
|
||||||
token.getAbilities().getRules(token.getName()),
|
token.getAbilities().getRules(),
|
||||||
token.getBackFace() == null ? null : token.getBackFace().getCopySourceCard()
|
token.getBackFace() == null ? null : token.getBackFace().getCopySourceCard()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@ package mage.util;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
// Author: alexander-novo
|
/**
|
||||||
// A helper class for facilitating the multi-choose dialog
|
* A helper class for facilitating the multi-choose dialog
|
||||||
|
*
|
||||||
|
* @author alexander-novo
|
||||||
|
*/
|
||||||
public class MultiAmountMessage implements Serializable {
|
public class MultiAmountMessage implements Serializable {
|
||||||
public String message;
|
public String message;
|
||||||
public int min;
|
public int min;
|
||||||
|
|
@ -20,4 +23,9 @@ public class MultiAmountMessage implements Serializable {
|
||||||
this.max = max;
|
this.max = max;
|
||||||
this.defaultValue = defaultValue;
|
this.defaultValue = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("%s - from %d to %d - default %d", message, min, max, defaultValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue