mirror of
https://github.com/correl/mage.git
synced 2024-12-26 19:16:54 +00:00
Amonket Aftermath ability and card frame changes Completed
* Aftermath Ability implementation complete (At least until we see comprehensive rules that contradict the way I assumed it will work) * Aftermath Card Frame rendering complete * Normal Split and Fuse Split card frame rendering complete * Amonket Split card CMC changes NOT made, but left for a separate commit
This commit is contained in:
parent
a96a7f89f5
commit
18663f0a7a
11 changed files with 278 additions and 41 deletions
|
@ -35,9 +35,9 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
private int dividerAt;
|
private int dividerAt;
|
||||||
private int dividerSize;
|
private int dividerSize;
|
||||||
|
|
||||||
// Is fuse / consequence
|
// Is fuse / aftermath
|
||||||
private boolean isFuse = false;
|
private boolean isFuse = false;
|
||||||
private boolean isConsequence = false;
|
private boolean isAftermath = false;
|
||||||
|
|
||||||
public ModernSplitCardRenderer(CardView view, boolean isTransformed) {
|
public ModernSplitCardRenderer(CardView view, boolean isTransformed) {
|
||||||
super(view, isTransformed);
|
super(view, isTransformed);
|
||||||
|
@ -54,26 +54,31 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
rightHalf.name = cardView.getRightSplitName();
|
rightHalf.name = cardView.getRightSplitName();
|
||||||
leftHalf.name = cardView.getLeftSplitName();
|
leftHalf.name = cardView.getLeftSplitName();
|
||||||
|
|
||||||
isConsequence = cardView.getName().equalsIgnoreCase("fire // ice");
|
|
||||||
for (String rule: view.getRules()) {
|
for (String rule: view.getRules()) {
|
||||||
if (rule.contains("Fuse")) {
|
if (rule.contains("Fuse")) {
|
||||||
isFuse = true;
|
isFuse = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (String rule: view.getRightSplitRules()) {
|
||||||
|
if (rule.contains("Aftermath")) {
|
||||||
|
isAftermath = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// It's easier for rendering to swap the card halves here because for consequence cards
|
// It's easier for rendering to swap the card halves here because for aftermath cards
|
||||||
// they "rotate" in opposite directions making consquence and normal split cards
|
// they "rotate" in opposite directions making consquence and normal split cards
|
||||||
// have the "right" vs "left" as the top half.
|
// have the "right" vs "left" as the top half.
|
||||||
if (!isConsequence()) {
|
if (!isAftermath()) {
|
||||||
HalfCardProps tmp = leftHalf;
|
HalfCardProps tmp = leftHalf;
|
||||||
leftHalf = rightHalf;
|
leftHalf = rightHalf;
|
||||||
rightHalf = tmp;
|
rightHalf = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isConsequence() {
|
private boolean isAftermath() {
|
||||||
return isConsequence;
|
return isAftermath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isFuse() {
|
private boolean isFuse() {
|
||||||
|
@ -86,7 +91,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
super.layout(cardWidth, cardHeight);
|
super.layout(cardWidth, cardHeight);
|
||||||
|
|
||||||
// Decide size of divider
|
// Decide size of divider
|
||||||
if (isConsequence()) {
|
if (isAftermath()) {
|
||||||
dividerSize = borderWidth;
|
dividerSize = borderWidth;
|
||||||
dividerAt = (int)(cardHeight*0.54);
|
dividerAt = (int)(cardHeight*0.54);
|
||||||
} else {
|
} else {
|
||||||
|
@ -104,7 +109,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
rightHalf.h = cardHeight - rightHalf.y - borderWidth*3;
|
rightHalf.h = cardHeight - rightHalf.y - borderWidth*3;
|
||||||
|
|
||||||
// Content width / height (Exchanged from width / height if the card part is rotated)
|
// Content width / height (Exchanged from width / height if the card part is rotated)
|
||||||
if (isConsequence()) {
|
if (isAftermath()) {
|
||||||
leftHalf.cw = leftHalf.w;
|
leftHalf.cw = leftHalf.w;
|
||||||
leftHalf.ch = leftHalf.h;
|
leftHalf.ch = leftHalf.h;
|
||||||
} else {
|
} else {
|
||||||
|
@ -190,7 +195,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
@Override
|
@Override
|
||||||
protected void drawArt(Graphics2D g) {
|
protected void drawArt(Graphics2D g) {
|
||||||
if (artImage != null && !cardView.isFaceDown()) {
|
if (artImage != null && !cardView.isFaceDown()) {
|
||||||
if (isConsequence()) {
|
if (isAftermath()) {
|
||||||
Rectangle2D topRect = new Rectangle2D.Double(0.075, 0.113, 0.832, 0.227);
|
Rectangle2D topRect = new Rectangle2D.Double(0.075, 0.113, 0.832, 0.227);
|
||||||
int topLineY = (int) (leftHalf.ch * TYPE_LINE_Y_FRAC);
|
int topLineY = (int) (leftHalf.ch * TYPE_LINE_Y_FRAC);
|
||||||
drawArtIntoRect(g,
|
drawArtIntoRect(g,
|
||||||
|
@ -273,7 +278,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
return g2;
|
return g2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Graphics2D getConsequenceHalfContext(Graphics2D g) {
|
private Graphics2D getAftermathHalfContext(Graphics2D g) {
|
||||||
Graphics2D g2 = (Graphics2D)g.create();
|
Graphics2D g2 = (Graphics2D)g.create();
|
||||||
g2.translate(rightHalf.x, rightHalf.y);
|
g2.translate(rightHalf.x, rightHalf.y);
|
||||||
g2.rotate(Math.PI / 2);
|
g2.rotate(Math.PI / 2);
|
||||||
|
@ -299,9 +304,9 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void drawFrame(Graphics2D g) {
|
protected void drawFrame(Graphics2D g) {
|
||||||
if (isConsequence()) {
|
if (isAftermath()) {
|
||||||
drawSplitHalfFrame(getUnmodifiedHalfContext(g), leftHalf, (int)(leftHalf.ch * TYPE_LINE_Y_FRAC));
|
drawSplitHalfFrame(getUnmodifiedHalfContext(g), leftHalf, (int)(leftHalf.ch * TYPE_LINE_Y_FRAC));
|
||||||
drawSplitHalfFrame(getConsequenceHalfContext(g), rightHalf, (rightHalf.ch - boxHeight) / 2);
|
drawSplitHalfFrame(getAftermathHalfContext(g), rightHalf, (rightHalf.ch - boxHeight) / 2);
|
||||||
} else {
|
} else {
|
||||||
drawSplitHalfFrame(getLeftHalfContext(g), leftHalf, (int)(leftHalf.ch * TYPE_LINE_Y_FRAC));
|
drawSplitHalfFrame(getLeftHalfContext(g), leftHalf, (int)(leftHalf.ch * TYPE_LINE_Y_FRAC));
|
||||||
drawSplitHalfFrame(getRightHalfContext(g), rightHalf, (int)(rightHalf.ch * TYPE_LINE_Y_FRAC));
|
drawSplitHalfFrame(getRightHalfContext(g), rightHalf, (int)(rightHalf.ch * TYPE_LINE_Y_FRAC));
|
||||||
|
|
101
Mage.Sets/src/mage/cards/d/DestinedLead.java
Normal file
101
Mage.Sets/src/mage/cards/d/DestinedLead.java
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are
|
||||||
|
* permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The views and conclusions contained in the software and documentation are those of the
|
||||||
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package mage.cards.d;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.*;
|
||||||
|
import mage.abilities.effects.common.combat.MustBeBlockedByAllTargetEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.BoostTargetEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||||
|
import mage.abilities.keyword.AftermathAbility;
|
||||||
|
import mage.abilities.keyword.IndestructibleAbility;
|
||||||
|
import mage.abilities.keyword.LifelinkAbility;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.SplitCard;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.filter.Filter;
|
||||||
|
import mage.filter.FilterCard;
|
||||||
|
import mage.filter.common.FilterCreatureCard;
|
||||||
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
|
import mage.filter.predicate.mageobject.PowerPredicate;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.common.TargetCreaturePermanent;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author stravant
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
public class DestinedLead extends SplitCard {
|
||||||
|
|
||||||
|
public DestinedLead(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId,setInfo,new CardType[]{CardType.INSTANT}, new CardType[]{CardType.SORCERY},"{1}{B}","{3}{G}",false);
|
||||||
|
|
||||||
|
// Destined
|
||||||
|
// Target creature gets +1/+0 and gains indestructible until end of turn.
|
||||||
|
getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||||
|
Effect effect = new BoostTargetEffect(1, 0, Duration.EndOfTurn);
|
||||||
|
effect.setText("Target creature gets +1/+0");
|
||||||
|
getLeftHalfCard().getSpellAbility().addEffect(effect);
|
||||||
|
|
||||||
|
effect = new GainAbilityTargetEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn);
|
||||||
|
effect.setText("and gains indestructible until end of turn");
|
||||||
|
getLeftHalfCard().getSpellAbility().addEffect(effect);
|
||||||
|
|
||||||
|
// to
|
||||||
|
|
||||||
|
// Lead
|
||||||
|
// All creatures able to block target creature this turn must do so.
|
||||||
|
((CardImpl)(getRightHalfCard())).addAbility(new AftermathAbility());
|
||||||
|
getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||||
|
getRightHalfCard().getSpellAbility().addEffect(new MustBeBlockedByAllTargetEffect(Duration.EndOfTurn));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DestinedLead(final DestinedLead card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DestinedLead copy() {
|
||||||
|
return new DestinedLead(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -53,5 +53,6 @@ public class Amonkhet extends ExpansionSet {
|
||||||
this.numBoosterRare = 1;
|
this.numBoosterRare = 1;
|
||||||
this.ratioBoosterMythic = 8;
|
this.ratioBoosterMythic = 8;
|
||||||
cards.add(new SetCardInfo("Dusk // Dawn", 210, Rarity.RARE, mage.cards.d.DuskDawn.class));
|
cards.add(new SetCardInfo("Dusk // Dawn", 210, Rarity.RARE, mage.cards.d.DuskDawn.class));
|
||||||
|
cards.add(new SetCardInfo("Destined // Lead", 217, Rarity.UNCOMMON, mage.cards.d.DestinedLead.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,23 +27,19 @@
|
||||||
*/
|
*/
|
||||||
package mage.abilities.keyword;
|
package mage.abilities.keyword;
|
||||||
|
|
||||||
|
import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.SpellAbility;
|
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.Cost;
|
|
||||||
import mage.abilities.costs.Costs;
|
|
||||||
import mage.abilities.costs.mana.ManaCost;
|
|
||||||
import mage.abilities.effects.*;
|
import mage.abilities.effects.*;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.SplitCard;
|
import mage.cards.SplitCardHalf;
|
||||||
|
import mage.cards.SplitCardHalfImpl;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
|
||||||
import org.junit.After;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,8 +53,9 @@ import java.util.UUID;
|
||||||
*/
|
*/
|
||||||
public class AftermathAbility extends SimpleStaticAbility {
|
public class AftermathAbility extends SimpleStaticAbility {
|
||||||
public AftermathAbility() {
|
public AftermathAbility() {
|
||||||
super(Zone.ALL, new AftermathCantCastFromHand());
|
super(Zone.ALL, new AftermathCastFromGraveyard());
|
||||||
addEffect(new AftermathCastFromGraveyard());
|
addEffect(new AftermathCantCastFromHand());
|
||||||
|
addEffect(new AftermathExileAsResolvesFromGraveyard());
|
||||||
}
|
}
|
||||||
|
|
||||||
public AftermathAbility(final AftermathAbility ability) {
|
public AftermathAbility(final AftermathAbility ability) {
|
||||||
|
@ -101,9 +98,13 @@ class AftermathCastFromGraveyard extends AsThoughEffectImpl {
|
||||||
return new AftermathCastFromGraveyard(this);
|
return new AftermathCastFromGraveyard(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String msb(UUID id) {
|
||||||
|
return Integer.toUnsignedString((int)id.getMostSignificantBits(), 16);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||||
if (objectId.equals(source.getSourceId()) &&
|
if (objectId.equals(source.getSourceId()) &
|
||||||
affectedControllerId.equals(source.getControllerId())) {
|
affectedControllerId.equals(source.getControllerId())) {
|
||||||
Card card = game.getCard(source.getSourceId());
|
Card card = game.getCard(source.getSourceId());
|
||||||
if (card != null && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) {
|
if (card != null && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) {
|
||||||
|
@ -152,3 +153,75 @@ class AftermathCantCastFromHand extends ContinuousRuleModifyingEffectImpl {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AftermathExileAsResolvesFromGraveyard extends ReplacementEffectImpl {
|
||||||
|
|
||||||
|
AftermathExileAsResolvesFromGraveyard() {
|
||||||
|
super(Duration.WhileOnStack, Outcome.Detriment);
|
||||||
|
this.staticText = "Exile it afterwards.";
|
||||||
|
}
|
||||||
|
|
||||||
|
AftermathExileAsResolvesFromGraveyard(AftermathExileAsResolvesFromGraveyard effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checksEventType(GameEvent event, Game game) {
|
||||||
|
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(GameEvent evt, Ability source, Game game) {
|
||||||
|
ZoneChangeEvent event = (ZoneChangeEvent) evt;
|
||||||
|
if (event.getFromZone() == Zone.STACK && event.getToZone() != Zone.EXILED) {
|
||||||
|
// Moving something from stack to somewhere else
|
||||||
|
|
||||||
|
// Get the source id, getting the whole split card's ID, because
|
||||||
|
// that's the card that is changing zones in the event, but
|
||||||
|
// source.getSourceId is only the split card half.
|
||||||
|
// If branch so that we also support putting Aftermath on
|
||||||
|
// non-split cards for... whatever reason, in case somebody
|
||||||
|
// wants to do that in the future.
|
||||||
|
UUID sourceId = source.getSourceId();
|
||||||
|
Card sourceCard = game.getCard(source.getSourceId());
|
||||||
|
if (sourceCard != null && sourceCard instanceof SplitCardHalf) {
|
||||||
|
sourceCard = ((SplitCardHalf) sourceCard).getParentCard();
|
||||||
|
sourceId = sourceCard.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getTargetId() == sourceId) {
|
||||||
|
// Moving this spell from stack to yard
|
||||||
|
Spell spell = game.getStack().getSpell(source.getSourceId());
|
||||||
|
if (spell != null && spell.getFromZone() == Zone.GRAVEYARD) {
|
||||||
|
// And this spell was cast from the graveyard, so we need to exile it
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||||
|
UUID sourceId = source.getSourceId();
|
||||||
|
Card sourceCard = game.getCard(source.getSourceId());
|
||||||
|
if (sourceCard != null && sourceCard instanceof SplitCardHalf) {
|
||||||
|
sourceCard = ((SplitCardHalf) sourceCard).getParentCard();
|
||||||
|
sourceId = sourceCard.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceCard != null) {
|
||||||
|
Player player = game.getPlayer(sourceCard.getOwnerId());
|
||||||
|
if (player != null) {
|
||||||
|
return player.moveCardToExileWithInfo(sourceCard, null, "", sourceId, game, ((ZoneChangeEvent)event).getFromZone(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AftermathExileAsResolvesFromGraveyard copy() {
|
||||||
|
return new AftermathExileAsResolvesFromGraveyard(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -28,8 +28,11 @@
|
||||||
package mage.cards;
|
package mage.cards;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.sun.deploy.util.ArrayUtil;
|
||||||
import mage.abilities.Abilities;
|
import mage.abilities.Abilities;
|
||||||
import mage.abilities.AbilitiesImpl;
|
import mage.abilities.AbilitiesImpl;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
@ -49,10 +52,14 @@ public abstract class SplitCard extends CardImpl {
|
||||||
protected Card rightHalfCard;
|
protected Card rightHalfCard;
|
||||||
|
|
||||||
public SplitCard(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costsLeft, String costsRight, boolean fused) {
|
public SplitCard(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costsLeft, String costsRight, boolean fused) {
|
||||||
super(ownerId, setInfo, cardTypes, costsLeft + costsRight, (fused ? SpellAbilityType.SPLIT_FUSED : SpellAbilityType.SPLIT));
|
this(ownerId, setInfo, cardTypes, cardTypes, costsLeft, costsRight, fused);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SplitCard(UUID ownerId, CardSetInfo setInfo, CardType[] typesLeft, CardType[] typesRight, String costsLeft, String costsRight, boolean fused) {
|
||||||
|
super(ownerId, setInfo, CardType.mergeTypes(typesLeft, typesRight), costsLeft + costsRight, (fused ? SpellAbilityType.SPLIT_FUSED : SpellAbilityType.SPLIT));
|
||||||
String[] names = setInfo.getName().split(" // ");
|
String[] names = setInfo.getName().split(" // ");
|
||||||
leftHalfCard = new SplitCardHalfImpl(this.getOwnerId(), new CardSetInfo(names[0], setInfo.getExpansionSetCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), cardTypes, costsLeft, this, SpellAbilityType.SPLIT_LEFT);
|
leftHalfCard = new SplitCardHalfImpl(this.getOwnerId(), new CardSetInfo(names[0], setInfo.getExpansionSetCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), typesLeft, costsLeft, this, SpellAbilityType.SPLIT_LEFT);
|
||||||
rightHalfCard = new SplitCardHalfImpl(this.getOwnerId(), new CardSetInfo(names[1], setInfo.getExpansionSetCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), cardTypes, costsRight, this, SpellAbilityType.SPLIT_RIGHT);
|
rightHalfCard = new SplitCardHalfImpl(this.getOwnerId(), new CardSetInfo(names[1], setInfo.getExpansionSetCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), typesRight, costsRight, this, SpellAbilityType.SPLIT_RIGHT);
|
||||||
this.splitCard = true;
|
this.splitCard = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +146,14 @@ public abstract class SplitCard extends CardImpl {
|
||||||
return allAbilites;
|
return allAbilites;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently only gets the fuse SpellAbility if there is one, but generally gets
|
||||||
|
* any abilities on a split card as a whole, and not on either half individually.
|
||||||
|
**/
|
||||||
|
public Abilities<Ability> getSharedAbilities() {
|
||||||
|
return super.getAbilities();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Abilities<Ability> getAbilities(Game game) {
|
public Abilities<Ability> getAbilities(Game game) {
|
||||||
Abilities<Ability> allAbilites = new AbilitiesImpl<>();
|
Abilities<Ability> allAbilites = new AbilitiesImpl<>();
|
||||||
|
|
|
@ -15,4 +15,6 @@ public interface SplitCardHalf extends Card {
|
||||||
SplitCardHalf copy();
|
SplitCardHalf copy();
|
||||||
|
|
||||||
void setParentCard(SplitCard card);
|
void setParentCard(SplitCard card);
|
||||||
|
|
||||||
|
SplitCard getParentCard();
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,4 +82,8 @@ public class SplitCardHalfImpl extends CardImpl implements SplitCardHalf {
|
||||||
this.splitCardParent = card;
|
this.splitCardParent = card;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SplitCard getParentCard() {
|
||||||
|
return this.splitCardParent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,4 +55,9 @@ public class MockSplitCardHalf extends MockCard implements SplitCardHalf {
|
||||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SplitCard getParentCard() {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ public enum CardRepository {
|
||||||
// raise this if db structure was changed
|
// raise this if db structure was changed
|
||||||
private static final long CARD_DB_VERSION = 50;
|
private static final long CARD_DB_VERSION = 50;
|
||||||
// raise this if new cards were added to the server
|
// raise this if new cards were added to the server
|
||||||
private static final long CARD_CONTENT_VERSION = 71;
|
private static final long CARD_CONTENT_VERSION = 74;
|
||||||
private final TreeSet<String> landTypes = new TreeSet<>();
|
private final TreeSet<String> landTypes = new TreeSet<>();
|
||||||
private Dao<CardInfo, Object> cardDao;
|
private Dao<CardInfo, Object> cardDao;
|
||||||
private Set<String> classNames;
|
private Set<String> classNames;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package mage.constants;
|
package mage.constants;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author North
|
* @author North
|
||||||
|
@ -26,4 +28,19 @@ public enum CardType {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all of the card types from two lists of card types.
|
||||||
|
* Duplicates are eliminated.
|
||||||
|
*/
|
||||||
|
public static CardType[] mergeTypes(CardType[] a, CardType[] b) {
|
||||||
|
HashSet<CardType> cardTypes = new HashSet<>();
|
||||||
|
for (CardType t: a) {
|
||||||
|
cardTypes.add(t);
|
||||||
|
}
|
||||||
|
for (CardType t: b) {
|
||||||
|
cardTypes.add(t);
|
||||||
|
}
|
||||||
|
return cardTypes.toArray(new CardType[0]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1245,29 +1245,30 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
return useable;
|
return useable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// Get the usable activated abilities for a *single card object*, that is, either a card or half of a split card.
|
||||||
public LinkedHashMap<UUID, ActivatedAbility> getUseableActivatedAbilities(MageObject object, Zone zone, Game game) {
|
// Also called on the whole split card but only passing the fuse ability and other whole-split-card shared abilities
|
||||||
LinkedHashMap<UUID, ActivatedAbility> useable = new LinkedHashMap<>();
|
// as candidates.
|
||||||
|
private void getUseableActivatedAbilitiesHalfImpl(MageObject object, Zone zone, Game game, Abilities<Ability> candidateAbilites, LinkedHashMap<UUID, ActivatedAbility> output) {
|
||||||
boolean canUse = !(object instanceof Permanent) || ((Permanent) object).canUseActivatedAbilities(game);
|
boolean canUse = !(object instanceof Permanent) || ((Permanent) object).canUseActivatedAbilities(game);
|
||||||
ManaOptions availableMana = null;
|
ManaOptions availableMana = null;
|
||||||
// ManaOptions availableMana = getManaAvailable(game); // can only be activated if mana calculation works flawless otherwise player can't play spells they could play if calculation would work correctly
|
// ManaOptions availableMana = getManaAvailable(game); // can only be activated if mana calculation works flawless otherwise player can't play spells they could play if calculation would work correctly
|
||||||
// availableMana.addMana(manaPool.getMana());
|
// availableMana.addMana(manaPool.getMana());
|
||||||
for (Ability ability : object.getAbilities()) {
|
for (Ability ability : candidateAbilites) {
|
||||||
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
|
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
|
||||||
if (ability.getZone().match(zone)) {
|
if (ability.getZone().match(zone)) {
|
||||||
if (ability instanceof ActivatedAbility) {
|
if (ability instanceof ActivatedAbility) {
|
||||||
if (ability instanceof ActivatedManaAbilityImpl) {
|
if (ability instanceof ActivatedManaAbilityImpl) {
|
||||||
if (((ActivatedAbility) ability).canActivate(playerId, game)) {
|
if (((ActivatedAbility) ability).canActivate(playerId, game)) {
|
||||||
useable.put(ability.getId(), (ActivatedAbility) ability);
|
output.put(ability.getId(), (ActivatedAbility) ability);
|
||||||
}
|
}
|
||||||
} else if (canPlay(((ActivatedAbility) ability), availableMana, object, game)) {
|
} else if (canPlay(((ActivatedAbility) ability), availableMana, object, game)) {
|
||||||
useable.put(ability.getId(), (ActivatedAbility) ability);
|
output.put(ability.getId(), (ActivatedAbility) ability);
|
||||||
}
|
}
|
||||||
} else if (ability instanceof AlternativeSourceCosts) {
|
} else if (ability instanceof AlternativeSourceCosts) {
|
||||||
if (object.isLand()) {
|
if (object.isLand()) {
|
||||||
for (Ability ability2 : object.getAbilities().copy()) {
|
for (Ability ability2 : object.getAbilities().copy()) {
|
||||||
if (ability2 instanceof PlayLandAbility) {
|
if (ability2 instanceof PlayLandAbility) {
|
||||||
useable.put(ability2.getId(), (ActivatedAbility) ability2);
|
output.put(ability2.getId(), (ActivatedAbility) ability2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1277,19 +1278,19 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
if (zone != Zone.HAND) {
|
if (zone != Zone.HAND) {
|
||||||
if (Zone.GRAVEYARD == zone && canPlayCardsFromGraveyard()) {
|
if (Zone.GRAVEYARD == zone && canPlayCardsFromGraveyard()) {
|
||||||
for (ActivatedAbility ability : object.getAbilities().getPlayableAbilities(Zone.HAND)) {
|
for (ActivatedAbility ability : candidateAbilites.getPlayableAbilities(Zone.HAND)) {
|
||||||
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
|
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
|
||||||
if (ability.getManaCosts().isEmpty() && ability.getCosts().isEmpty() && ability instanceof SpellAbility) {
|
if (ability.getManaCosts().isEmpty() && ability.getCosts().isEmpty() && ability instanceof SpellAbility) {
|
||||||
continue; // You can't play spells from graveyard that have no costs
|
continue; // You can't play spells from graveyard that have no costs
|
||||||
}
|
}
|
||||||
if (ability.canActivate(playerId, game)) {
|
if (ability.canActivate(playerId, game)) {
|
||||||
useable.put(ability.getId(), ability);
|
output.put(ability.getId(), ability);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (zone != Zone.BATTLEFIELD && game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) {
|
if (zone != Zone.BATTLEFIELD && game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) {
|
||||||
for (Ability ability : object.getAbilities()) {
|
for (Ability ability : candidateAbilites) {
|
||||||
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
|
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
|
||||||
if (ability.getManaCosts().isEmpty() && ability.getCosts().isEmpty() && ability instanceof SpellAbility && !(Objects.equals(ability.getSourceId(), getCastSourceIdWithAlternateMana()))) {
|
if (ability.getManaCosts().isEmpty() && ability.getCosts().isEmpty() && ability instanceof SpellAbility && !(Objects.equals(ability.getSourceId(), getCastSourceIdWithAlternateMana()))) {
|
||||||
continue; // You can't play spells that have no costs, unless you can play them without paying their mana costs
|
continue; // You can't play spells that have no costs, unless you can play them without paying their mana costs
|
||||||
|
@ -1297,12 +1298,25 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
ability.setControllerId(this.getId());
|
ability.setControllerId(this.getId());
|
||||||
if (ability instanceof ActivatedAbility && ability.getZone().match(Zone.HAND)
|
if (ability instanceof ActivatedAbility && ability.getZone().match(Zone.HAND)
|
||||||
&& ((ActivatedAbility) ability).canActivate(playerId, game)) {
|
&& ((ActivatedAbility) ability).canActivate(playerId, game)) {
|
||||||
useable.put(ability.getId(), (ActivatedAbility) ability);
|
output.put(ability.getId(), (ActivatedAbility) ability);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LinkedHashMap<UUID, ActivatedAbility> getUseableActivatedAbilities(MageObject object, Zone zone, Game game) {
|
||||||
|
LinkedHashMap<UUID, ActivatedAbility> useable = new LinkedHashMap<>();
|
||||||
|
if (object instanceof SplitCard) {
|
||||||
|
SplitCard splitCard = (SplitCard) object;
|
||||||
|
getUseableActivatedAbilitiesHalfImpl(splitCard.getLeftHalfCard(), zone, game, splitCard.getLeftHalfCard().getAbilities(), useable);
|
||||||
|
getUseableActivatedAbilitiesHalfImpl(splitCard.getRightHalfCard(), zone, game, splitCard.getRightHalfCard().getAbilities(), useable);
|
||||||
|
getUseableActivatedAbilitiesHalfImpl(splitCard, zone, game, splitCard.getSharedAbilities(), useable);
|
||||||
|
} else {
|
||||||
|
getUseableActivatedAbilitiesHalfImpl(object, zone, game, object.getAbilities(), useable);
|
||||||
|
}
|
||||||
getOtherUseableActivatedAbilities(object, zone, game, useable);
|
getOtherUseableActivatedAbilities(object, zone, game, useable);
|
||||||
|
|
||||||
return useable;
|
return useable;
|
||||||
|
|
Loading…
Reference in a new issue