mirror of
https://github.com/magefree/mage.git
synced 2025-12-23 12:02:01 -08:00
Added Spellweaver Volute.
This commit is contained in:
parent
bec07fb530
commit
bc490ef91a
14 changed files with 835 additions and 353 deletions
|
|
@ -29,10 +29,12 @@ package mage.abilities.effects.common;
|
|||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -72,9 +74,16 @@ public class AttachEffect extends OneShotEffect {
|
|||
if (player != null) {
|
||||
return player.addAttachment(source.getSourceId(), game);
|
||||
}
|
||||
if (source.getTargets().get(0) instanceof TargetCard) { // e.g. Spellweaver Volute
|
||||
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
||||
if (card != null) {
|
||||
return card.addAttachment(source.getSourceId(), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,14 +27,11 @@
|
|||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.choices.Choice;
|
||||
import mage.choices.ChoiceCreatureType;
|
||||
import mage.choices.ChoiceImpl;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.game.Game;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
*/
|
||||
package mage.cards;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
import mage.ObjectColor;
|
||||
|
|
@ -42,19 +44,14 @@ import mage.game.Game;
|
|||
import mage.game.GameState;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface Card extends MageObject {
|
||||
|
||||
|
||||
final String regexBlack = ".*\\x7b.{0,2}B.{0,2}\\x7d.*";
|
||||
final String regexBlue = ".*\\x7b.{0,2}U.{0,2}\\x7d.*";
|
||||
final String regexRed = ".*\\x7b.{0,2}R.{0,2}\\x7d.*";
|
||||
final String regexGreen = ".*\\x7b.{0,2}G.{0,2}\\x7d.*";
|
||||
final String regexWhite = ".*\\x7b.{0,2}W.{0,2}\\x7d.*";
|
||||
|
||||
|
||||
UUID getOwnerId();
|
||||
|
||||
String getCardNumber();
|
||||
|
|
@ -248,4 +245,9 @@ public interface Card extends MageObject {
|
|||
return mana;
|
||||
}
|
||||
|
||||
List<UUID> getAttachments();
|
||||
|
||||
boolean addAttachment(UUID permanentId, Game game);
|
||||
|
||||
boolean removeAttachment(UUID permanentId, Game game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
protected boolean morphCard;
|
||||
protected boolean allCreatureTypes;
|
||||
|
||||
protected List<UUID> attachments = new ArrayList<>();
|
||||
|
||||
public CardImpl(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costs) {
|
||||
this(ownerId, setInfo, cardTypes, costs, SpellAbilityType.BASE);
|
||||
}
|
||||
|
|
@ -169,6 +171,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
flipCardName = card.flipCardName;
|
||||
splitCard = card.splitCard;
|
||||
usesVariousArt = card.usesVariousArt;
|
||||
this.attachments.addAll(card.attachments);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -840,11 +843,53 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
return super.getSubtype(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllCreatureTypes() {
|
||||
return allCreatureTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIsAllCreatureTypes(boolean value) {
|
||||
allCreatureTypes = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UUID> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAttachment(UUID permanentId, Game game) {
|
||||
if (!this.attachments.contains(permanentId)) {
|
||||
Permanent attachment = game.getPermanent(permanentId);
|
||||
if (attachment == null) {
|
||||
attachment = game.getPermanentEntering(permanentId);
|
||||
}
|
||||
if (attachment != null) {
|
||||
if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ATTACH, objectId, permanentId, attachment.getControllerId()))) {
|
||||
this.attachments.add(permanentId);
|
||||
attachment.attachTo(objectId, game);
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.ATTACHED, objectId, permanentId, attachment.getControllerId()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAttachment(UUID permanentId, Game game) {
|
||||
if (this.attachments.contains(permanentId)) {
|
||||
Permanent attachment = game.getPermanent(permanentId);
|
||||
if (attachment != null) {
|
||||
attachment.unattach(game);
|
||||
}
|
||||
if (!game.replaceEvent(new GameEvent(GameEvent.EventType.UNATTACH, objectId, permanentId, attachment != null ? attachment.getControllerId() : null))) {
|
||||
this.attachments.remove(permanentId);
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, objectId, permanentId, attachment != null ? attachment.getControllerId() : null));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1901,6 +1901,15 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (target instanceof TargetCard) {
|
||||
Card attachedTo = getCard(perm.getAttachedTo());
|
||||
if (attachedTo == null
|
||||
|| !((TargetCard) spellAbility.getTargets().get(0)).canTarget(perm.getControllerId(), perm.getAttachedTo(), spellAbility, this)) {
|
||||
if (movePermanentToGraveyardWithInfo(perm)) {
|
||||
attachedTo.removeAttachment(perm.getId(), this);
|
||||
somethingHappened = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,7 +233,8 @@ public class GameEvent implements Serializable {
|
|||
PAID_CUMULATIVE_UPKEEP,
|
||||
DIDNT_PAY_CUMULATIVE_UPKEEP,
|
||||
//permanent events
|
||||
ENTERS_THE_BATTLEFIELD_SELF, // 616.1a If any of the replacement and/or prevention effects are self-replacement effects (see rule 614.15), one of them must be chosen. If not, proceed to rule 616.1b.
|
||||
ENTERS_THE_BATTLEFIELD_SELF, /* 616.1a If any of the replacement and/or prevention effects are self-replacement effects (see rule 614.15),
|
||||
one of them must be chosen. If not, proceed to rule 616.1b. */
|
||||
ENTERS_THE_BATTLEFIELD_CONTROL, // 616.1b
|
||||
ENTERS_THE_BATTLEFIELD_COPY, // 616.1c
|
||||
ENTERS_THE_BATTLEFIELD, // 616.1d
|
||||
|
|
|
|||
|
|
@ -116,10 +116,11 @@ public interface Permanent extends Card, Controllable {
|
|||
|
||||
void attachTo(UUID permanentId, Game game);
|
||||
|
||||
boolean addAttachment(UUID permanentId, Game game);
|
||||
|
||||
boolean removeAttachment(UUID permanentId, Game game);
|
||||
void unattach(Game game);
|
||||
|
||||
// boolean addAttachment(UUID permanentId, Game game);
|
||||
//
|
||||
// boolean removeAttachment(UUID permanentId, Game game);
|
||||
boolean canBeTargetedBy(MageObject source, UUID controllerId, Game game);
|
||||
|
||||
boolean hasProtectionFrom(MageObject source, Game game);
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import mage.game.permanent.token.SquirrelToken;
|
|||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.GameLog;
|
||||
import mage.util.ThreadLocalStringBuilder;
|
||||
|
|
@ -103,7 +104,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
protected int maxBlockedBy = 0;
|
||||
protected boolean removedFromCombat;
|
||||
protected boolean deathtouched;
|
||||
protected List<UUID> attachments = new ArrayList<>();
|
||||
|
||||
protected Map<String, List<UUID>> connectedCards = new HashMap<>();
|
||||
protected Set<MageObjectReference> dealtDamageByThisTurn;
|
||||
protected UUID attachedTo;
|
||||
|
|
@ -147,7 +148,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
this.blocking = permanent.blocking;
|
||||
this.maxBlocks = permanent.maxBlocks;
|
||||
this.deathtouched = permanent.deathtouched;
|
||||
this.attachments.addAll(permanent.attachments);
|
||||
// this.attachments.addAll(permanent.attachments);
|
||||
for (Map.Entry<String, List<UUID>> entry : permanent.connectedCards.entrySet()) {
|
||||
this.connectedCards.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
|
@ -626,47 +627,46 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
//
|
||||
// @Override
|
||||
// public List<UUID> getAttachments() {
|
||||
// return attachments;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public List<UUID> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAttachment(UUID permanentId, Game game) {
|
||||
if (!this.attachments.contains(permanentId)) {
|
||||
if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ATTACH, objectId, permanentId, controllerId))) {
|
||||
this.attachments.add(permanentId);
|
||||
Permanent attachment = game.getPermanent(permanentId);
|
||||
if (attachment == null) {
|
||||
attachment = game.getPermanentEntering(permanentId);
|
||||
}
|
||||
if (attachment != null) {
|
||||
attachment.attachTo(objectId, game);
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.ATTACHED, objectId, permanentId, controllerId));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAttachment(UUID permanentId, Game game) {
|
||||
if (this.attachments.contains(permanentId)) {
|
||||
if (!game.replaceEvent(new GameEvent(GameEvent.EventType.UNATTACH, objectId, permanentId, controllerId))) {
|
||||
this.attachments.remove(permanentId);
|
||||
Permanent attachment = game.getPermanent(permanentId);
|
||||
if (attachment != null) {
|
||||
attachment.attachTo(null, game);
|
||||
}
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, objectId, permanentId, controllerId));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean addAttachment(UUID permanentId, Game game) {
|
||||
// if (!this.attachments.contains(permanentId)) {
|
||||
// if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ATTACH, objectId, permanentId, controllerId))) {
|
||||
// this.attachments.add(permanentId);
|
||||
// Permanent attachment = game.getPermanent(permanentId);
|
||||
// if (attachment == null) {
|
||||
// attachment = game.getPermanentEntering(permanentId);
|
||||
// }
|
||||
// if (attachment != null) {
|
||||
// attachment.attachTo(objectId, game);
|
||||
// game.fireEvent(new GameEvent(GameEvent.EventType.ATTACHED, objectId, permanentId, controllerId));
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean removeAttachment(UUID permanentId, Game game) {
|
||||
// if (this.attachments.contains(permanentId)) {
|
||||
// if (!game.replaceEvent(new GameEvent(GameEvent.EventType.UNATTACH, objectId, permanentId, controllerId))) {
|
||||
// this.attachments.remove(permanentId);
|
||||
// Permanent attachment = game.getPermanent(permanentId);
|
||||
// if (attachment != null) {
|
||||
// attachment.attachTo(null, game);
|
||||
// }
|
||||
// game.fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, objectId, permanentId, controllerId));
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
@Override
|
||||
public UUID getAttachedTo() {
|
||||
return attachedTo;
|
||||
|
|
@ -705,15 +705,27 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void attachTo(UUID permanentId, Game game) {
|
||||
if (this.attachedTo != null && !Objects.equals(this.attachedTo, permanentId)) {
|
||||
Permanent attachment = game.getPermanent(this.attachedTo);
|
||||
if (attachment != null) {
|
||||
attachment.removeAttachment(this.objectId, game);
|
||||
public void unattach(Game game) {
|
||||
this.attachedTo = null;
|
||||
this.addInfo("attachedToCard", null, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachTo(UUID attachToObjectId, Game game) {
|
||||
if (this.attachedTo != null && !Objects.equals(this.attachedTo, attachToObjectId)) {
|
||||
Permanent attachedToUntilNowObject = game.getPermanent(this.attachedTo);
|
||||
if (attachedToUntilNowObject != null) {
|
||||
attachedToUntilNowObject.removeAttachment(this.objectId, game);
|
||||
} else {
|
||||
Card attachedToUntilNowCard = game.getCard(this.attachedTo);
|
||||
if (attachedToUntilNowCard != null) {
|
||||
attachedToUntilNowCard.removeAttachment(this.objectId, game);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
this.attachedTo = permanentId;
|
||||
this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(permanentId);
|
||||
this.attachedTo = attachToObjectId;
|
||||
this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(attachToObjectId);
|
||||
for (Ability ability : this.getAbilities()) {
|
||||
for (Iterator<Effect> ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext();) {
|
||||
ContinuousEffect effect = (ContinuousEffect) ite.next();
|
||||
|
|
@ -726,6 +738,13 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!getSpellAbility().getTargets().isEmpty() && (getSpellAbility().getTargets().get(0) instanceof TargetCard)) {
|
||||
Card attachedToCard = game.getCard(this.getAttachedTo());
|
||||
if (attachedToCard != null) {
|
||||
// Because cards are not on the battlefield, the relation has to be shown in the card tooltip (e.g. the enchanted card in graveyard)
|
||||
this.addInfo("attachedToCard", CardUtil.addToolTipMarkTags("Enchanted card: " + attachedToCard.getIdName()), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -955,4 +955,19 @@ public class Spell extends StackObjImpl implements Card {
|
|||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UUID> getAttachments() {
|
||||
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAttachment(UUID permanentId, Game game) {
|
||||
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAttachment(UUID permanentId, Game game) {
|
||||
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -817,6 +817,11 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
Player attachedToPlayer = game.getPlayer(permanent.getAttachedTo());
|
||||
if (attachedToPlayer != null) {
|
||||
attachedToPlayer.removeAttachment(permanent, game);
|
||||
} else {
|
||||
Card attachedToCard = game.getCard(permanent.getAttachedTo());
|
||||
if (attachedToCard != null) {
|
||||
attachedToCard.removeAttachment(permanent.getId(), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2326,7 +2331,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
newTarget.setCardLimit(Math.min(librarySearchLimit, cardsFromTop.size()));
|
||||
count = Math.min(searchedLibrary.count(target.getFilter(), game), librarySearchLimit);
|
||||
}
|
||||
|
||||
|
||||
if (count < target.getNumberOfTargets()) {
|
||||
newTarget.setMinNumberOfTargets(count);
|
||||
}
|
||||
|
|
@ -3278,9 +3283,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Card card, Zone toZone,
|
||||
Ability source, Game game
|
||||
) {
|
||||
public boolean moveCards(Card card, Zone toZone, Ability source, Game game) {
|
||||
return moveCards(card, toZone, source, game, false, false, false, null);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue