mirror of
https://github.com/correl/mage.git
synced 2024-11-15 11:09:30 +00:00
Implement Shape of the Wiitigo
This commit is contained in:
parent
9f06046f22
commit
258384fae7
4 changed files with 227 additions and 4 deletions
133
Mage.Sets/src/mage/cards/s/ShapeOfTheWiitigo.java
Normal file
133
Mage.Sets/src/mage/cards/s/ShapeOfTheWiitigo.java
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
package mage.cards.s;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import mage.MageObjectReference;
|
||||||
|
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||||
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
|
import mage.abilities.condition.Condition;
|
||||||
|
import mage.abilities.decorator.ConditionalOneShotEffect;
|
||||||
|
import mage.abilities.effects.common.counter.AddCountersAttachedEffect;
|
||||||
|
import mage.abilities.effects.common.counter.RemoveCountersAttachedEffect;
|
||||||
|
import mage.constants.*;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.target.common.TargetCreaturePermanent;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
|
import mage.target.TargetPermanent;
|
||||||
|
import mage.abilities.keyword.EnchantAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.watchers.Watcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author noahg
|
||||||
|
*/
|
||||||
|
public final class ShapeOfTheWiitigo extends CardImpl {
|
||||||
|
|
||||||
|
public ShapeOfTheWiitigo(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}{G}{G}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.AURA);
|
||||||
|
|
||||||
|
// Enchant creature
|
||||||
|
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||||
|
this.getSpellAbility().addTarget(auraTarget);
|
||||||
|
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||||
|
Ability ability = new EnchantAbility(auraTarget.getTargetName());
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
|
// When Shape of the Wiitigo enters the battlefield, put six +1/+1 counters on enchanted creature.
|
||||||
|
this.addAbility(new EntersBattlefieldTriggeredAbility(new AddCountersAttachedEffect(CounterType.P1P1.createInstance(6), "enchanted creature")));
|
||||||
|
|
||||||
|
// At the beginning of your upkeep, put a +1/+1 counter on enchanted creature if it attacked or blocked since your last upkeep. Otherwise, remove a +1/+1 counter from it.
|
||||||
|
Ability triggeredAbility = new BeginningOfUpkeepTriggeredAbility(
|
||||||
|
new ConditionalOneShotEffect(new AddCountersAttachedEffect(CounterType.P1P1.createInstance(1), "enchanted creature"),
|
||||||
|
new RemoveCountersAttachedEffect(CounterType.P1P1.createInstance(1), "it"),
|
||||||
|
new AttachedAttackedOrBlockedSinceYourLastUpkeepCondition(),
|
||||||
|
"put a +1/+1 counter on enchanted creature if it attacked or blocked since your last " +
|
||||||
|
"upkeep. Otherwise, remove a +1/+1 counter from it"), TargetController.YOU, false);
|
||||||
|
triggeredAbility.addWatcher(new AttackedOrBlockedSinceYourLastUpkeepWatcher());
|
||||||
|
this.addAbility(triggeredAbility);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShapeOfTheWiitigo(final ShapeOfTheWiitigo card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShapeOfTheWiitigo copy() {
|
||||||
|
return new ShapeOfTheWiitigo(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AttachedAttackedOrBlockedSinceYourLastUpkeepCondition implements Condition {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId());
|
||||||
|
AttackedOrBlockedSinceYourLastUpkeepWatcher watcher = (AttackedOrBlockedSinceYourLastUpkeepWatcher) game.getState().getWatchers().get(AttackedOrBlockedSinceYourLastUpkeepWatcher.class.getSimpleName());
|
||||||
|
if (permanent != null && permanent.getAttachedTo() != null && watcher != null) {
|
||||||
|
Permanent attachedTo = game.getBattlefield().getPermanent(permanent.getAttachedTo());
|
||||||
|
if (attachedTo == null) {
|
||||||
|
attachedTo = (Permanent) game.getLastKnownInformation(permanent.getAttachedTo(), Zone.BATTLEFIELD);
|
||||||
|
}
|
||||||
|
if (attachedTo != null) {
|
||||||
|
return watcher.attackedSinceLastUpkeep(new MageObjectReference(attachedTo.getId(), attachedTo.getZoneChangeCounter(game), game), source.getControllerId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "it attacked or blocked since your last upkeep";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AttackedOrBlockedSinceYourLastUpkeepWatcher extends Watcher{
|
||||||
|
|
||||||
|
//Map of each player to the creatures that attacked or blocked since their last upkeep
|
||||||
|
private final Map<UUID, Set<MageObjectReference>> attackedOrBlockedCreatures = new HashMap<>();
|
||||||
|
|
||||||
|
public AttackedOrBlockedSinceYourLastUpkeepWatcher() {
|
||||||
|
super(AttackedOrBlockedSinceYourLastUpkeepWatcher.class.getSimpleName(), WatcherScope.GAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttackedOrBlockedSinceYourLastUpkeepWatcher(AttackedOrBlockedSinceYourLastUpkeepWatcher watcher) {
|
||||||
|
super(watcher);
|
||||||
|
for (Map.Entry<UUID, Set<MageObjectReference>> entry : watcher.attackedOrBlockedCreatures.entrySet()) {
|
||||||
|
Set<MageObjectReference> allAttackersCopy = new HashSet<>(entry.getValue());
|
||||||
|
attackedOrBlockedCreatures.put(entry.getKey(), allAttackersCopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void watch(GameEvent event, Game game) {
|
||||||
|
if (event.getType() == GameEvent.EventType.UPKEEP_STEP_POST){
|
||||||
|
//Clear
|
||||||
|
attackedOrBlockedCreatures.put(event.getPlayerId(), new HashSet<>());
|
||||||
|
} else if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED || event.getType() == GameEvent.EventType.BLOCKER_DECLARED) {
|
||||||
|
MageObjectReference mor = new MageObjectReference(event.getSourceId(), game);
|
||||||
|
for (UUID player : game.getPlayerList()){
|
||||||
|
if (!attackedOrBlockedCreatures.containsKey(player)) {
|
||||||
|
attackedOrBlockedCreatures.put(player, new HashSet<>());
|
||||||
|
}
|
||||||
|
attackedOrBlockedCreatures.get(player).add(mor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean attackedSinceLastUpkeep(MageObjectReference mor, UUID upkeepPlayer){
|
||||||
|
return attackedOrBlockedCreatures.get(upkeepPlayer).contains(mor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AttackedOrBlockedSinceYourLastUpkeepWatcher copy() {
|
||||||
|
return new AttackedOrBlockedSinceYourLastUpkeepWatcher(this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -141,6 +141,7 @@ public final class Coldsnap extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Rune Snag", 46, Rarity.COMMON, mage.cards.r.RuneSnag.class));
|
cards.add(new SetCardInfo("Rune Snag", 46, Rarity.COMMON, mage.cards.r.RuneSnag.class));
|
||||||
cards.add(new SetCardInfo("Scrying Sheets", 149, Rarity.RARE, mage.cards.s.ScryingSheets.class));
|
cards.add(new SetCardInfo("Scrying Sheets", 149, Rarity.RARE, mage.cards.s.ScryingSheets.class));
|
||||||
cards.add(new SetCardInfo("Sek'Kuar, Deathkeeper", 131, Rarity.RARE, mage.cards.s.SekKuarDeathkeeper.class));
|
cards.add(new SetCardInfo("Sek'Kuar, Deathkeeper", 131, Rarity.RARE, mage.cards.s.SekKuarDeathkeeper.class));
|
||||||
|
cards.add(new SetCardInfo("Shape of the Wiitigo", 120, Rarity.RARE, mage.cards.s.ShapeOfTheWiitigo.class));
|
||||||
cards.add(new SetCardInfo("Sheltering Ancient", 121, Rarity.UNCOMMON, mage.cards.s.ShelteringAncient.class));
|
cards.add(new SetCardInfo("Sheltering Ancient", 121, Rarity.UNCOMMON, mage.cards.s.ShelteringAncient.class));
|
||||||
cards.add(new SetCardInfo("Simian Brawler", 122, Rarity.COMMON, mage.cards.s.SimianBrawler.class));
|
cards.add(new SetCardInfo("Simian Brawler", 122, Rarity.COMMON, mage.cards.s.SimianBrawler.class));
|
||||||
cards.add(new SetCardInfo("Skred", 97, Rarity.COMMON, mage.cards.s.Skred.class));
|
cards.add(new SetCardInfo("Skred", 97, Rarity.COMMON, mage.cards.s.Skred.class));
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
|
||||||
|
package mage.abilities.effects.common.counter;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
|
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.counters.Counter;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author noahg
|
||||||
|
*/
|
||||||
|
public class RemoveCountersAttachedEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
private Counter counter;
|
||||||
|
private DynamicValue amount;
|
||||||
|
private String textEnchanted;
|
||||||
|
|
||||||
|
public RemoveCountersAttachedEffect(Counter counter, String textEnchanted) {
|
||||||
|
this(counter, new StaticValue(0), textEnchanted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param counter
|
||||||
|
* @param amount this amount will be added to the counter instances
|
||||||
|
* @param textEnchanted text used for the enchanted permanent in rule text
|
||||||
|
*/
|
||||||
|
public RemoveCountersAttachedEffect(Counter counter, DynamicValue amount, String textEnchanted) {
|
||||||
|
super(Outcome.UnboostCreature);
|
||||||
|
this.counter = counter.copy();
|
||||||
|
this.amount = amount;
|
||||||
|
this.textEnchanted = textEnchanted;
|
||||||
|
setText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemoveCountersAttachedEffect(final RemoveCountersAttachedEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
if (effect.counter != null) {
|
||||||
|
this.counter = effect.counter.copy();
|
||||||
|
}
|
||||||
|
this.amount = effect.amount;
|
||||||
|
this.textEnchanted = effect.textEnchanted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||||
|
if (permanent != null && permanent.getAttachedTo() != null) {
|
||||||
|
Permanent attachedTo = game.getPermanent(permanent.getAttachedTo());
|
||||||
|
if (attachedTo != null && counter != null) {
|
||||||
|
Counter newCounter = counter.copy();
|
||||||
|
newCounter.add(amount.calculate(game, source, this));
|
||||||
|
attachedTo.removeCounters(newCounter, game);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setText() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
// put a +1/+1 counter on it
|
||||||
|
sb.append("remove ");
|
||||||
|
if (counter.getCount() > 1) {
|
||||||
|
sb.append(CardUtil.numberToText(counter.getCount())).append(' ');
|
||||||
|
sb.append(counter.getName().toLowerCase(Locale.ENGLISH)).append(" counters from ");
|
||||||
|
} else {
|
||||||
|
sb.append("a ");
|
||||||
|
sb.append(counter.getName().toLowerCase(Locale.ENGLISH)).append(" counter from ");
|
||||||
|
}
|
||||||
|
sb.append(textEnchanted);
|
||||||
|
if (!amount.getMessage().isEmpty()) {
|
||||||
|
sb.append(" for each ").append(amount.getMessage());
|
||||||
|
}
|
||||||
|
staticText = sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RemoveCountersAttachedEffect copy() {
|
||||||
|
return new RemoveCountersAttachedEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -30,13 +30,11 @@ public class AttackedLastTurnWatcher extends Watcher {
|
||||||
public AttackedLastTurnWatcher(final AttackedLastTurnWatcher watcher) {
|
public AttackedLastTurnWatcher(final AttackedLastTurnWatcher watcher) {
|
||||||
super(watcher);
|
super(watcher);
|
||||||
for (Entry<UUID, Set<MageObjectReference>> entry : watcher.attackedLastTurnCreatures.entrySet()) {
|
for (Entry<UUID, Set<MageObjectReference>> entry : watcher.attackedLastTurnCreatures.entrySet()) {
|
||||||
Set<MageObjectReference> allAttackersCopy = new HashSet<>();
|
Set<MageObjectReference> allAttackersCopy = new HashSet<>(entry.getValue());
|
||||||
allAttackersCopy.addAll(entry.getValue());
|
|
||||||
attackedLastTurnCreatures.put(entry.getKey(), allAttackersCopy);
|
attackedLastTurnCreatures.put(entry.getKey(), allAttackersCopy);
|
||||||
}
|
}
|
||||||
for (Entry<UUID, Set<MageObjectReference>> entry : watcher.attackedThisTurnCreatures.entrySet()) {
|
for (Entry<UUID, Set<MageObjectReference>> entry : watcher.attackedThisTurnCreatures.entrySet()) {
|
||||||
Set<MageObjectReference> allAttackersCopy = new HashSet<>();
|
Set<MageObjectReference> allAttackersCopy = new HashSet<>(entry.getValue());
|
||||||
allAttackersCopy.addAll(entry.getValue());
|
|
||||||
attackedThisTurnCreatures.put(entry.getKey(), allAttackersCopy);
|
attackedThisTurnCreatures.put(entry.getKey(), allAttackersCopy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue