From e1bfd8a196d67269fae1e0eeefc56e82978f49d1 Mon Sep 17 00:00:00 2001 From: Kevin Shin Date: Sat, 25 Aug 2018 03:18:32 -0500 Subject: [PATCH 1/5] Permanents now detach all attachments when they change zones. Ready to test. --- .../main/java/mage/cards/AuraCreature.java | 39 +++++++++++++++++++ Mage/src/main/java/mage/game/GameImpl.java | 18 +++++---- .../mage/game/permanent/PermanentImpl.java | 29 +++++++++++++- 3 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 Mage/src/main/java/mage/cards/AuraCreature.java diff --git a/Mage/src/main/java/mage/cards/AuraCreature.java b/Mage/src/main/java/mage/cards/AuraCreature.java new file mode 100644 index 00000000000..8e67a9398e9 --- /dev/null +++ b/Mage/src/main/java/mage/cards/AuraCreature.java @@ -0,0 +1,39 @@ +package mage.cards; + +import java.util.List; +import java.util.UUID; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; + +/** + * A class to represent creature cards that can be auras. + * i.e., cards with bestow and licids + * @author kevinwshin + */ +public abstract class AuraCreature extends CardImpl{ + + public AuraCreature(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costs) { + super(ownerId, setInfo, cardTypes, costs); + } + + //unattach all attached permanents after moving to exile + @Override + public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List appliedEffects) { + boolean successfullyMoved = super.moveToExile(exileId, name, sourceId, game, appliedEffects); + unattach(); + return successfullyMoved; + } + + @Override + public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List appliedEffects) { + boolean successfullyMoved = super.moveToZone(toZone, sourceId, game, flag); + unattach(); + return successfullyMoved; + } + + private void unattach() { + //GameImpl.java:1980 + } + +} diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index af68a3a8766..419651fa128 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1980,10 +1980,11 @@ public abstract class GameImpl implements Game, Serializable { // handle bestow unattachment Card card = this.getCard(perm.getId()); if (card != null && card.isCreature()) { - UUID wasAttachedTo = perm.getAttachedTo(); - perm.attachTo(null, this); - BestowAbility.becomeCreature(perm, this); - fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); + //TODO: cleanup + //UUID wasAttachedTo = perm.getAttachedTo(); + //perm.attachTo(null, this); + //BestowAbility.becomeCreature(perm, this); + //fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); } else if (movePermanentToGraveyardWithInfo(perm)) { somethingHappened = true; } @@ -2000,10 +2001,11 @@ public abstract class GameImpl implements Game, Serializable { // handle bestow unattachment Card card = this.getCard(perm.getId()); if (card != null && card.isCreature()) { - UUID wasAttachedTo = perm.getAttachedTo(); - perm.attachTo(null, this); - BestowAbility.becomeCreature(perm, this); - fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); + //TODO: cleanup + //UUID wasAttachedTo = perm.getAttachedTo(); + //perm.attachTo(null, this); + //BestowAbility.becomeCreature(perm, this); + //fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); } else if (movePermanentToGraveyardWithInfo(perm)) { somethingHappened = true; } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 74739b25a37..f4ff85445cf 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -1437,6 +1437,26 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { return color; } + //20180810 - 701.3d + //If an object leaves the zone it's in, all attached permanents become unattached + public void detachAllAttachments(Game game) { + for(UUID attachmentId : getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + Card attachmentCard = game.getCard(attachmentId); + if(attachment != null && attachmentCard != null) { + attachment.attachTo(null, game); + + //make bestow cards and licids into creatures + if(attachmentCard.isCreature()) { + BestowAbility.becomeCreature(attachment, game); + } + + game.fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, + getId(), attachment.getId(), attachment.getControllerId())); + } + } + } + @Override public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List appliedEffects) { Zone fromZone = game.getState().getZone(objectId); @@ -1449,7 +1469,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } else { zoneChangeInfo = new ZoneChangeInfo(event); } - return ZonesHandler.moveCard(zoneChangeInfo, game); + boolean successfullyMoved = ZonesHandler.moveCard(zoneChangeInfo, game); + detachAllAttachments(game); + return successfullyMoved; } return false; } @@ -1459,7 +1481,10 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { Zone fromZone = game.getState().getZone(objectId); ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, ownerId, fromZone, Zone.EXILED, appliedEffects); ZoneChangeInfo.Exile info = new ZoneChangeInfo.Exile(event, exileId, name); - return ZonesHandler.moveCard(info, game); + + boolean successfullyMoved = ZonesHandler.moveCard(info, game); + detachAllAttachments(game); + return successfullyMoved; } } From 3ffd812bc625b4400583eb1aa227a2cd9476c224 Mon Sep 17 00:00:00 2001 From: Kevin Shin Date: Sat, 25 Aug 2018 04:43:38 -0500 Subject: [PATCH 2/5] After some revisions, BestowTest is now fully passed! Now to fix the other tests that don't anymore... --- .../cards/abilities/keywords/BestowTest.java | 2 -- Mage/src/main/java/mage/game/GameImpl.java | 17 ++++++++--------- .../java/mage/game/permanent/PermanentImpl.java | 2 ++ 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BestowTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BestowTest.java index 3950fa971b1..5427cb84607 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BestowTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BestowTest.java @@ -7,7 +7,6 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.game.permanent.Permanent; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -162,7 +161,6 @@ public class BestowTest extends CardTestPlayerBase { * Bestowed creature can be used to sacrifice a creature for the Away part. * http://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/magic-rulings-archives/513828-bestow-far-away */ - @Ignore // TODO: make fused targeting support @Test public void bestowWithFusedSpell() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 419651fa128..6b7eecdb424 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1981,10 +1981,10 @@ public abstract class GameImpl implements Game, Serializable { Card card = this.getCard(perm.getId()); if (card != null && card.isCreature()) { //TODO: cleanup - //UUID wasAttachedTo = perm.getAttachedTo(); - //perm.attachTo(null, this); - //BestowAbility.becomeCreature(perm, this); - //fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); + UUID wasAttachedTo = perm.getAttachedTo(); + perm.attachTo(null, this); + BestowAbility.becomeCreature(perm, this); + fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); } else if (movePermanentToGraveyardWithInfo(perm)) { somethingHappened = true; } @@ -2001,11 +2001,10 @@ public abstract class GameImpl implements Game, Serializable { // handle bestow unattachment Card card = this.getCard(perm.getId()); if (card != null && card.isCreature()) { - //TODO: cleanup - //UUID wasAttachedTo = perm.getAttachedTo(); - //perm.attachTo(null, this); - //BestowAbility.becomeCreature(perm, this); - //fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); + UUID wasAttachedTo = perm.getAttachedTo(); + perm.attachTo(null, this); + BestowAbility.becomeCreature(perm, this); + fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); } else if (movePermanentToGraveyardWithInfo(perm)) { somethingHappened = true; } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index f4ff85445cf..47dbc5b8877 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -1470,6 +1470,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { zoneChangeInfo = new ZoneChangeInfo(event); } boolean successfullyMoved = ZonesHandler.moveCard(zoneChangeInfo, game); + //20180810 - 701.3d detachAllAttachments(game); return successfullyMoved; } @@ -1483,6 +1484,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { ZoneChangeInfo.Exile info = new ZoneChangeInfo.Exile(event, exileId, name); boolean successfullyMoved = ZonesHandler.moveCard(info, game); + //20180810 - 701.3d detachAllAttachments(game); return successfullyMoved; } From 7d2ba0cf2ea2151b01481355b97c82dea94001ee Mon Sep 17 00:00:00 2001 From: Kevin Shin Date: Sat, 25 Aug 2018 23:24:01 -0500 Subject: [PATCH 3/5] all tests passing and satisfied with minimal changes; ready to merge --- Mage/src/main/java/mage/game/GameImpl.java | 3 +-- .../main/java/mage/game/permanent/PermanentImpl.java | 10 ++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 6b7eecdb424..1dfe7b8a0c2 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1980,10 +1980,9 @@ public abstract class GameImpl implements Game, Serializable { // handle bestow unattachment Card card = this.getCard(perm.getId()); if (card != null && card.isCreature()) { - //TODO: cleanup UUID wasAttachedTo = perm.getAttachedTo(); perm.attachTo(null, this); - BestowAbility.becomeCreature(perm, this); + //BestowAbility.becomeCreature(perm, this); fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); } else if (movePermanentToGraveyardWithInfo(perm)) { somethingHappened = true; diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 47dbc5b8877..776f0b775dd 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -1439,20 +1439,18 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { //20180810 - 701.3d //If an object leaves the zone it's in, all attached permanents become unattached + //note that this code doesn't actually detach anything, and is a bit of a bandaid public void detachAllAttachments(Game game) { for(UUID attachmentId : getAttachments()) { Permanent attachment = game.getPermanent(attachmentId); Card attachmentCard = game.getCard(attachmentId); if(attachment != null && attachmentCard != null) { - attachment.attachTo(null, game); - //make bestow cards and licids into creatures - if(attachmentCard.isCreature()) { + //aura test to stop bludgeon brawl shenanigans from using this code + //consider adding code to handle that case? + if(attachment.hasSubtype(SubType.AURA, game) && attachmentCard.isCreature()) { BestowAbility.becomeCreature(attachment, game); } - - game.fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, - getId(), attachment.getId(), attachment.getControllerId())); } } } From 23920a069696122e91738d03260c3599008c63aa Mon Sep 17 00:00:00 2001 From: Kevin Shin Date: Sat, 25 Aug 2018 23:26:55 -0500 Subject: [PATCH 4/5] remove new class that ended unused --- .../main/java/mage/cards/AuraCreature.java | 39 ------------------- 1 file changed, 39 deletions(-) delete mode 100644 Mage/src/main/java/mage/cards/AuraCreature.java diff --git a/Mage/src/main/java/mage/cards/AuraCreature.java b/Mage/src/main/java/mage/cards/AuraCreature.java deleted file mode 100644 index 8e67a9398e9..00000000000 --- a/Mage/src/main/java/mage/cards/AuraCreature.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards; - -import java.util.List; -import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Zone; -import mage.game.Game; - -/** - * A class to represent creature cards that can be auras. - * i.e., cards with bestow and licids - * @author kevinwshin - */ -public abstract class AuraCreature extends CardImpl{ - - public AuraCreature(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costs) { - super(ownerId, setInfo, cardTypes, costs); - } - - //unattach all attached permanents after moving to exile - @Override - public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List appliedEffects) { - boolean successfullyMoved = super.moveToExile(exileId, name, sourceId, game, appliedEffects); - unattach(); - return successfullyMoved; - } - - @Override - public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List appliedEffects) { - boolean successfullyMoved = super.moveToZone(toZone, sourceId, game, flag); - unattach(); - return successfullyMoved; - } - - private void unattach() { - //GameImpl.java:1980 - } - -} From f5498d4cc2f40db610b1b85acdff739e2d5cd84d Mon Sep 17 00:00:00 2001 From: Kevin Shin Date: Sat, 25 Aug 2018 23:29:55 -0500 Subject: [PATCH 5/5] added comment --- Mage/src/main/java/mage/game/GameImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 1dfe7b8a0c2..a05b32f7c33 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1982,6 +1982,7 @@ public abstract class GameImpl implements Game, Serializable { if (card != null && card.isCreature()) { UUID wasAttachedTo = perm.getAttachedTo(); perm.attachTo(null, this); + //moved to mage.game.permanent.PermanentImpl::detachAllAttachments //BestowAbility.becomeCreature(perm, this); fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); } else if (movePermanentToGraveyardWithInfo(perm)) {