Implement Shape of the Wiitigo

This commit is contained in:
Noah Gleason 2018-07-04 11:31:03 -04:00
parent 9f06046f22
commit 258384fae7
No known key found for this signature in database
GPG key ID: EC030EC6B0650A40
4 changed files with 227 additions and 4 deletions

View 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);
}
}

View file

@ -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("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("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("Simian Brawler", 122, Rarity.COMMON, mage.cards.s.SimianBrawler.class));
cards.add(new SetCardInfo("Skred", 97, Rarity.COMMON, mage.cards.s.Skred.class));

View file

@ -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);
}
}

View file

@ -30,13 +30,11 @@ public class AttackedLastTurnWatcher extends Watcher {
public AttackedLastTurnWatcher(final AttackedLastTurnWatcher watcher) {
super(watcher);
for (Entry<UUID, Set<MageObjectReference>> entry : watcher.attackedLastTurnCreatures.entrySet()) {
Set<MageObjectReference> allAttackersCopy = new HashSet<>();
allAttackersCopy.addAll(entry.getValue());
Set<MageObjectReference> allAttackersCopy = new HashSet<>(entry.getValue());
attackedLastTurnCreatures.put(entry.getKey(), allAttackersCopy);
}
for (Entry<UUID, Set<MageObjectReference>> entry : watcher.attackedThisTurnCreatures.entrySet()) {
Set<MageObjectReference> allAttackersCopy = new HashSet<>();
allAttackersCopy.addAll(entry.getValue());
Set<MageObjectReference> allAttackersCopy = new HashSet<>(entry.getValue());
attackedThisTurnCreatures.put(entry.getKey(), allAttackersCopy);
}
}