From 8b3064fc17dee9da191e0840a6d066bde87f3d3e Mon Sep 17 00:00:00 2001 From: Evan Kranzler <theelk801@gmail.com> Date: Tue, 10 Nov 2020 20:31:54 -0500 Subject: [PATCH] [CMR] Implemented Malcolm, Keen-Eyed Navigator --- .../cards/m/MalcolmKeenEyedNavigator.java | 106 ++++++++++++++++++ Mage.Sets/src/mage/sets/CommanderLegends.java | 1 + Mage/src/main/java/mage/game/GameState.java | 19 +++- .../mage/game/events/DamagedBatchEvent.java | 45 ++++++++ .../events/DamagedCreatureBatchEvent.java | 11 ++ .../events/DamagedPlaneswalkerBatchEvent.java | 11 ++ .../game/events/DamagedPlayerBatchEvent.java | 11 ++ .../main/java/mage/game/events/GameEvent.java | 5 +- .../mage/game/permanent/PermanentImpl.java | 8 +- .../main/java/mage/players/PlayerImpl.java | 4 +- 10 files changed, 213 insertions(+), 8 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/m/MalcolmKeenEyedNavigator.java create mode 100644 Mage/src/main/java/mage/game/events/DamagedBatchEvent.java create mode 100644 Mage/src/main/java/mage/game/events/DamagedCreatureBatchEvent.java create mode 100644 Mage/src/main/java/mage/game/events/DamagedPlaneswalkerBatchEvent.java create mode 100644 Mage/src/main/java/mage/game/events/DamagedPlayerBatchEvent.java diff --git a/Mage.Sets/src/mage/cards/m/MalcolmKeenEyedNavigator.java b/Mage.Sets/src/mage/cards/m/MalcolmKeenEyedNavigator.java new file mode 100644 index 0000000000..6278dcc58d --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MalcolmKeenEyedNavigator.java @@ -0,0 +1,106 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.PartnerAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.DamagedEvent; +import mage.game.events.DamagedPlayerBatchEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.TreasureToken; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MalcolmKeenEyedNavigator extends CardImpl { + + public MalcolmKeenEyedNavigator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SIREN); + this.subtype.add(SubType.PIRATE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever one or more Pirates you control deal damage to your opponents, you create a Treasure token for each opponent dealt damage. + this.addAbility(new MalcolmKeenEyedNavigatorTriggeredAbility()); + + // Partner + this.addAbility(PartnerAbility.getInstance()); + } + + private MalcolmKeenEyedNavigator(final MalcolmKeenEyedNavigator card) { + super(card); + } + + @Override + public MalcolmKeenEyedNavigator copy() { + return new MalcolmKeenEyedNavigator(this); + } +} + +class MalcolmKeenEyedNavigatorTriggeredAbility extends TriggeredAbilityImpl { + + MalcolmKeenEyedNavigatorTriggeredAbility() { + super(Zone.BATTLEFIELD, null); + } + + private MalcolmKeenEyedNavigatorTriggeredAbility(final MalcolmKeenEyedNavigatorTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER_BATCH; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + DamagedPlayerBatchEvent dEvent = (DamagedPlayerBatchEvent) event; + Set<UUID> opponents = new HashSet<>(); + for (DamagedEvent damagedEvent : dEvent.getEvents()) { + Permanent permanent = game.getPermanent(damagedEvent.getSourceId()); + if (permanent == null + || !permanent.isControlledBy(getControllerId()) + || !permanent.hasSubtype(SubType.PIRATE, game) + || !game.getOpponents(getControllerId()).contains(damagedEvent.getTargetId())) { + continue; + } + opponents.add(damagedEvent.getTargetId()); + } + if (opponents.size() < 1) { + return false; + } + this.getEffects().clear(); + this.addEffect(new CreateTokenEffect(new TreasureToken(), opponents.size())); + return true; + } + + @Override + public MalcolmKeenEyedNavigatorTriggeredAbility copy() { + return new MalcolmKeenEyedNavigatorTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever one or more Pirates you control deal damage to your opponents, " + + "you create a Treasure token for each opponent dealt damage."; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/CommanderLegends.java b/Mage.Sets/src/mage/sets/CommanderLegends.java index f2e9fcba1b..b615a126ec 100644 --- a/Mage.Sets/src/mage/sets/CommanderLegends.java +++ b/Mage.Sets/src/mage/sets/CommanderLegends.java @@ -287,6 +287,7 @@ public final class CommanderLegends extends ExpansionSet { cards.add(new SetCardInfo("Magus of the Order", 242, Rarity.RARE, mage.cards.m.MagusOfTheOrder.class)); cards.add(new SetCardInfo("Make a Stand", 32, Rarity.UNCOMMON, mage.cards.m.MakeAStand.class)); cards.add(new SetCardInfo("Makeshift Munitions", 191, Rarity.COMMON, mage.cards.m.MakeshiftMunitions.class)); + cards.add(new SetCardInfo("Malcolm, Keen-Eyed Navigator", 79, Rarity.UNCOMMON, mage.cards.m.MalcolmKeenEyedNavigator.class)); cards.add(new SetCardInfo("Mana Confluence", 721, Rarity.MYTHIC, mage.cards.m.ManaConfluence.class)); cards.add(new SetCardInfo("Mana Drain", 80, Rarity.MYTHIC, mage.cards.m.ManaDrain.class)); cards.add(new SetCardInfo("Marath, Will of the Wild", 527, Rarity.MYTHIC, mage.cards.m.MarathWillOfTheWild.class)); diff --git a/Mage/src/main/java/mage/game/GameState.java b/Mage/src/main/java/mage/game/GameState.java index bb0379e2e2..7b135157ad 100644 --- a/Mage/src/main/java/mage/game/GameState.java +++ b/Mage/src/main/java/mage/game/GameState.java @@ -18,9 +18,7 @@ import mage.game.combat.CombatGroup; import mage.game.command.Command; import mage.game.command.CommandObject; import mage.game.command.Plane; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; -import mage.game.events.ZoneChangeGroupEvent; +import mage.game.events.*; import mage.game.permanent.Battlefield; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; @@ -732,6 +730,21 @@ public class GameState implements Serializable, Copyable<GameState> { return !simultaneousEvents.isEmpty(); } + public void addSimultaneousDamage(DamagedEvent damagedEvent, Game game) { + boolean flag = false; + for (GameEvent event : simultaneousEvents) { + if ((event instanceof DamagedBatchEvent) + && ((DamagedBatchEvent) event).getDamageClazz().isInstance(damagedEvent)) { + ((DamagedBatchEvent) event).addEvent(damagedEvent); + flag = true; + break; + } + } + if (!flag) { + addSimultaneousEvent(DamagedBatchEvent.makeEvent(damagedEvent), game); + } + } + public void handleEvent(GameEvent event, Game game) { watchers.watch(event, game); delayed.checkTriggers(event, game); diff --git a/Mage/src/main/java/mage/game/events/DamagedBatchEvent.java b/Mage/src/main/java/mage/game/events/DamagedBatchEvent.java new file mode 100644 index 0000000000..a5dad5832b --- /dev/null +++ b/Mage/src/main/java/mage/game/events/DamagedBatchEvent.java @@ -0,0 +1,45 @@ +package mage.game.events; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author TheElk801 + */ +public abstract class DamagedBatchEvent extends GameEvent { + + private final Class<? extends DamagedEvent> damageClazz; + private final Set<DamagedEvent> events = new HashSet<>(); + + public DamagedBatchEvent(EventType type, Class<? extends DamagedEvent> damageClazz) { + super(EventType.DAMAGED_PLAYER_BATCH, null, null, null); + this.damageClazz = damageClazz; + } + + public Set<DamagedEvent> getEvents() { + return events; + } + + public void addEvent(DamagedEvent event) { + this.events.add(event); + } + + public Class<? extends DamagedEvent> getDamageClazz() { + return damageClazz; + } + + public static DamagedBatchEvent makeEvent(DamagedEvent damagedEvent) { + DamagedBatchEvent event = null; + if (damagedEvent instanceof DamagedPlayerEvent) { + event = new DamagedPlayerBatchEvent(); + event.addEvent(damagedEvent); + } else if (damagedEvent instanceof DamagedCreatureEvent) { + event = new DamagedCreatureBatchEvent(); + event.addEvent(damagedEvent); + } else if (damagedEvent instanceof DamagedPlaneswalkerEvent) { + event = new DamagedPlaneswalkerBatchEvent(); + event.addEvent(damagedEvent); + } + return event; + } +} diff --git a/Mage/src/main/java/mage/game/events/DamagedCreatureBatchEvent.java b/Mage/src/main/java/mage/game/events/DamagedCreatureBatchEvent.java new file mode 100644 index 0000000000..8f2c23d57a --- /dev/null +++ b/Mage/src/main/java/mage/game/events/DamagedCreatureBatchEvent.java @@ -0,0 +1,11 @@ +package mage.game.events; + +/** + * @author TheElk801 + */ +public class DamagedCreatureBatchEvent extends DamagedBatchEvent { + + public DamagedCreatureBatchEvent() { + super(EventType.DAMAGED_CREATURE_BATCH, DamagedCreatureEvent.class); + } +} diff --git a/Mage/src/main/java/mage/game/events/DamagedPlaneswalkerBatchEvent.java b/Mage/src/main/java/mage/game/events/DamagedPlaneswalkerBatchEvent.java new file mode 100644 index 0000000000..17b981b43a --- /dev/null +++ b/Mage/src/main/java/mage/game/events/DamagedPlaneswalkerBatchEvent.java @@ -0,0 +1,11 @@ +package mage.game.events; + +/** + * @author TheElk801 + */ +public class DamagedPlaneswalkerBatchEvent extends DamagedBatchEvent { + + public DamagedPlaneswalkerBatchEvent() { + super(EventType.DAMAGED_PLANESWALKER_BATCH, DamagedPlaneswalkerEvent.class); + } +} diff --git a/Mage/src/main/java/mage/game/events/DamagedPlayerBatchEvent.java b/Mage/src/main/java/mage/game/events/DamagedPlayerBatchEvent.java new file mode 100644 index 0000000000..c7f38a687d --- /dev/null +++ b/Mage/src/main/java/mage/game/events/DamagedPlayerBatchEvent.java @@ -0,0 +1,11 @@ +package mage.game.events; + +/** + * @author TheElk801 + */ +public class DamagedPlayerBatchEvent extends DamagedBatchEvent { + + public DamagedPlayerBatchEvent() { + super(EventType.DAMAGED_PLAYER_BATCH, DamagedPlayerEvent.class); + } +} diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index 9dc99fbc7c..e6014fed0c 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -100,6 +100,7 @@ public class GameEvent implements Serializable { flag true = comabat damage - other damage = false */ DAMAGED_PLAYER, + DAMAGED_PLAYER_BATCH, DAMAGE_CAUSES_LIFE_LOSS, PLAYER_LIFE_CHANGE, GAIN_LIFE, GAINED_LIFE, @@ -311,8 +312,8 @@ public class GameEvent implements Serializable { flag not used for this event */ OPTION_USED, - DAMAGE_CREATURE, DAMAGED_CREATURE, - DAMAGE_PLANESWALKER, DAMAGED_PLANESWALKER, + DAMAGE_CREATURE, DAMAGED_CREATURE, DAMAGED_CREATURE_BATCH, + DAMAGE_PLANESWALKER, DAMAGED_PLANESWALKER, DAMAGED_PLANESWALKER_BATCH, DESTROY_PERMANENT, /* DESTROY_PERMANENT_BY_LEGENDARY_RULE targetId id of the permanent to destroy diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 8f1818a89b..351dc8ffdd 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -980,7 +980,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { countersToRemove = getCounters(game).getCount(CounterType.LOYALTY); } removeCounters(CounterType.LOYALTY.getName(), countersToRemove, game); - game.fireEvent(new DamagedPlaneswalkerEvent(objectId, sourceId, controllerId, actualDamage, combat)); + DamagedEvent damagedEvent = new DamagedPlaneswalkerEvent(objectId, sourceId, controllerId, actualDamage, combat); + game.fireEvent(damagedEvent); + game.getState().addSimultaneousDamage(damagedEvent, game); return actualDamage; } } @@ -1011,7 +1013,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } else { this.damage = CardUtil.addWithOverflowCheck(this.damage, actualDamage); } - game.fireEvent(new DamagedCreatureEvent(objectId, sourceId, controllerId, actualDamage, combat)); + DamagedEvent damagedEvent = new DamagedCreatureEvent(objectId, sourceId, controllerId, actualDamage, combat); + game.fireEvent(damagedEvent); + game.getState().addSimultaneousDamage(damagedEvent, game); return actualDamage; } } diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index efed0eb952..14dedf50a1 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -2157,7 +2157,9 @@ public abstract class PlayerImpl implements Player, Serializable { Player player = game.getPlayer(sourceControllerId); new SquirrelToken().putOntoBattlefield(actualDamage, game, sourceId, player.getId()); } - game.fireEvent(new DamagedPlayerEvent(playerId, sourceId, playerId, actualDamage, combatDamage)); + DamagedEvent damagedEvent = new DamagedPlayerEvent(playerId, sourceId, playerId, actualDamage, combatDamage); + game.fireEvent(damagedEvent); + game.getState().addSimultaneousDamage(damagedEvent, game); return actualDamage; } }