[STX] Implemented Strict Proctor

This commit is contained in:
Evan Kranzler 2021-04-16 18:48:40 -04:00
parent 3ba320257b
commit f9467d5142
18 changed files with 140 additions and 27 deletions

View file

@ -82,7 +82,7 @@ class ForceProjectionEffect extends OneShotEffect {
Effect sacrificeEffect = new SacrificeSourceEffect();
sacrificeEffect.setTargetPointer(new FixedTarget(effect.getAddedPermanent().get(0), game));
TriggeredAbility ability = new BecomesTargetTriggeredAbility(sacrificeEffect, new FilterSpell());
game.addTriggeredAbility(ability);
game.addTriggeredAbility(ability, null);
return true;
}

View file

@ -78,10 +78,10 @@ class HiddenPredatorsStateTriggeredAbility extends StateTriggeredAbility {
}
@Override
public void trigger(Game game, UUID controllerId) {
public void trigger(Game game, UUID controllerId, GameEvent triggeringEvent) {
//20100716 - 603.8
game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.TRUE);
super.trigger(game, controllerId);
super.trigger(game, controllerId, triggeringEvent);
}
@Override

View file

@ -79,10 +79,10 @@ class LurkingJackalsStateTriggeredAbility extends StateTriggeredAbility {
}
@Override
public void trigger(Game game, UUID controllerId) {
public void trigger(Game game, UUID controllerId, GameEvent triggeringEvent) {
//20100716 - 603.8
game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.TRUE);
super.trigger(game, controllerId);
super.trigger(game, controllerId, triggeringEvent);
}
@Override

View file

@ -75,10 +75,10 @@ class OpalAvengerStateTriggeredAbility extends StateTriggeredAbility {
}
@Override
public void trigger(Game game, UUID controllerId) {
public void trigger(Game game, UUID controllerId, GameEvent triggeringEvent) {
//20100716 - 603.8
game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.TRUE);
super.trigger(game, controllerId);
super.trigger(game, controllerId, triggeringEvent);
}
@Override

View file

@ -0,0 +1,84 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.CounterUnlessPaysEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class StrictProctor extends CardImpl {
public StrictProctor(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
this.subtype.add(SubType.SPIRIT);
this.subtype.add(SubType.CLERIC);
this.power = new MageInt(1);
this.toughness = new MageInt(3);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever a permanent entering the battlefield causes a triggered ability to trigger, counter that ability unless its controller pays {2}.
this.addAbility(new StrictProctorTriggeredAbility());
}
private StrictProctor(final StrictProctor card) {
super(card);
}
@Override
public StrictProctor copy() {
return new StrictProctor(this);
}
}
class StrictProctorTriggeredAbility extends TriggeredAbilityImpl {
StrictProctorTriggeredAbility() {
super(Zone.BATTLEFIELD, new CounterUnlessPaysEffect(new GenericManaCost(2)));
}
private StrictProctorTriggeredAbility(final StrictProctorTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ABILITY_TRIGGERED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
GameEvent triggeringEvent = (GameEvent) game.getState().getValue(event.getId().toString());
if (triggeringEvent == null || triggeringEvent.getType() != GameEvent.EventType.ENTERS_THE_BATTLEFIELD) {
return false;
}
getEffects().setTargetPointer(new FixedTarget(triggeringEvent.getTargetId(), game));
return true;
}
@Override
public StrictProctorTriggeredAbility copy() {
return new StrictProctorTriggeredAbility(this);
}
@Override
public String getRule() {
return "Whenever a permanent entering the battlefield causes a triggered ability to trigger, " +
"counter that ability unless its controller pays {2}.";
}
}

View file

@ -80,10 +80,10 @@ class VeiledCrocodileStateTriggeredAbility extends StateTriggeredAbility {
}
@Override
public void trigger(Game game, UUID controllerId) {
public void trigger(Game game, UUID controllerId, GameEvent triggeringEvent) {
//20100716 - 603.8
game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.TRUE);
super.trigger(game, controllerId);
super.trigger(game, controllerId, triggeringEvent);
}
@Override

View file

@ -269,6 +269,7 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet {
cards.add(new SetCardInfo("Stonebound Mentor", 239, Rarity.COMMON, mage.cards.s.StoneboundMentor.class));
cards.add(new SetCardInfo("Stonerise Spirit", 32, Rarity.COMMON, mage.cards.s.StoneriseSpirit.class));
cards.add(new SetCardInfo("Storm-Kiln Artist", 115, Rarity.UNCOMMON, mage.cards.s.StormKilnArtist.class));
cards.add(new SetCardInfo("Strict Proctor", 33, Rarity.RARE, mage.cards.s.StrictProctor.class));
cards.add(new SetCardInfo("Strixhaven Stadium", 259, Rarity.RARE, mage.cards.s.StrixhavenStadium.class));
cards.add(new SetCardInfo("Study Break", 34, Rarity.COMMON, mage.cards.s.StudyBreak.class));
cards.add(new SetCardInfo("Sudden Breakthrough", 116, Rarity.COMMON, mage.cards.s.SuddenBreakthrough.class));

View file

@ -48,7 +48,7 @@ public interface Ability extends Controllable, Serializable {
*
* @see mage.players.PlayerImpl#playAbility(mage.abilities.ActivatedAbility,
* mage.game.Game)
* @see mage.game.GameImpl#addTriggeredAbility(mage.abilities.TriggeredAbility)
* @see Game#addTriggeredAbility(TriggeredAbility, GameEvent)
* @see mage.game.GameImpl#addDelayedTriggeredAbility(mage.abilities.DelayedTriggeredAbility)
*/
void newId();
@ -58,7 +58,7 @@ public interface Ability extends Controllable, Serializable {
*
* @see mage.players.PlayerImpl#playAbility(mage.abilities.ActivatedAbility,
* mage.game.Game)
* @see mage.game.GameImpl#addTriggeredAbility(mage.abilities.TriggeredAbility)
* @see Game#addTriggeredAbility(TriggeredAbility, GameEvent)
* @see mage.game.GameImpl#addDelayedTriggeredAbility(mage.abilities.DelayedTriggeredAbility)
*/
void newOriginalId();

View file

@ -37,7 +37,7 @@ public class DelayedTriggeredAbilities extends AbilitiesImpl<DelayedTriggeredAbi
continue;
}
if (ability.checkTrigger(event, game)) {
ability.trigger(game, ability.controllerId);
ability.trigger(game, ability.controllerId, event);
if (ability.getTriggerOnlyOnce()) {
it.remove();
}

View file

@ -31,10 +31,10 @@ public abstract class StateTriggeredAbility extends TriggeredAbilityImpl {
}
@Override
public void trigger(Game game, UUID controllerId) {
public void trigger(Game game, UUID controllerId, GameEvent triggeringEvent) {
//20100716 - 603.8
game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.TRUE);
super.trigger(game, controllerId);
super.trigger(game, controllerId, triggeringEvent);
}
@Override

View file

@ -95,7 +95,7 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
NumberOfTriggersEvent numberOfTriggersEvent = new NumberOfTriggersEvent(ability, event);
if (!game.replaceEvent(numberOfTriggersEvent)) {
for (int i = 0; i < numberOfTriggersEvent.getAmount(); i++) {
ability.trigger(game, ability.getControllerId());
ability.trigger(game, ability.getControllerId(), event);
}
}
}

View file

@ -11,7 +11,7 @@ import java.util.UUID;
*/
public interface TriggeredAbility extends Ability {
void trigger(Game game, UUID controllerId);
void trigger(Game game, UUID controllerId, GameEvent event);
/**
* This check for the relevant event types is called at first to prevent
@ -52,4 +52,7 @@ public interface TriggeredAbility extends Ability {
@Override
TriggeredAbility copy();
void setTriggerEvent(GameEvent event);
GameEvent getTriggerEvent();
}

View file

@ -24,6 +24,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
protected boolean optional;
protected boolean leavesTheBattlefieldTrigger;
private boolean triggersOnce = false;
private GameEvent triggerEvent = null;
public TriggeredAbilityImpl(Zone zone, Effect effect) {
this(zone, effect, false);
@ -53,15 +54,15 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
}
@Override
public void trigger(Game game, UUID controllerId) {
public void trigger(Game game, UUID controllerId, GameEvent triggeringEvent) {
//20091005 - 603.4
if (checkInterveningIfClause(game)) {
addthing(game);
game.addTriggeredAbility(this);
setLastTrigger(game);
game.addTriggeredAbility(this, triggeringEvent);
}
}
private final void addthing(Game game) {
private final void setLastTrigger(Game game) {
if (!triggersOnce) {
return;
}
@ -70,6 +71,16 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
), game.getTurnNum());
}
@Override
public void setTriggerEvent(GameEvent triggerEvent) {
this.triggerEvent = triggerEvent;
}
@Override
public GameEvent getTriggerEvent() {
return triggerEvent;
}
@Override
public boolean checkTriggeredAlready(Game game) {
if (!triggersOnce) {

View file

@ -11,6 +11,7 @@ import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ConvertedManaCostPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
@ -46,14 +47,14 @@ public class SoulshiftAbility extends DiesSourceTriggeredAbility {
}
@Override
public void trigger(Game game, UUID controllerId) {
public void trigger(Game game, UUID controllerId, GameEvent triggeringEvent) {
this.getTargets().clear();
int intValue = amount.calculate(game, this, null);
FilterCard filter = new FilterCard("Spirit card with converted mana cost " + intValue + " or less from your graveyard");
filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, intValue + 1));
filter.add(SubType.SPIRIT.getPredicate());
this.addTarget(new TargetCardInYourGraveyard(filter));
super.trigger(game, controllerId); //To change body of generated methods, choose Tools | Templates.
super.trigger(game, controllerId, triggeringEvent); //To change body of generated methods, choose Tools | Templates.
}
@Override

View file

@ -421,7 +421,7 @@ public interface Game extends MageItem, Serializable {
Card copyCard(Card cardToCopy, Ability source, UUID newController);
void addTriggeredAbility(TriggeredAbility ability);
void addTriggeredAbility(TriggeredAbility ability, GameEvent triggeringEvent);
UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility);

View file

@ -1742,9 +1742,10 @@ public abstract class GameImpl implements Game, Serializable {
* For internal use only
*
* @param ability
* @param triggeringEvent
*/
@Override
public void addTriggeredAbility(TriggeredAbility ability) {
public void addTriggeredAbility(TriggeredAbility ability, GameEvent triggeringEvent) {
if (ability.getControllerId() == null) {
String sourceName = "no sourceId";
if (ability.getSourceId() != null) {
@ -1770,6 +1771,7 @@ public abstract class GameImpl implements Game, Serializable {
if (newAbility.getSourceObjectZoneChangeCounter() == 0) {
newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(ability.getSourceId()));
}
newAbility.setTriggerEvent(triggeringEvent);
state.addTriggeredAbility(newAbility);
}
}

View file

@ -188,6 +188,7 @@ public class GameEvent implements Serializable {
playerId player that tries to use this ability
*/
TRIGGERED_ABILITY,
ABILITY_TRIGGERED,
RESOLVING_ABILITY,
/* COPY_STACKOBJECT
targetId id of the spell/ability to copy

View file

@ -780,7 +780,7 @@ public abstract class PlayerImpl implements Player, Serializable {
Cards toDiscard = new CardsImpl();
Cards hand = getHand().copy();
for (int i = 0; i < amount; i++) {
if(hand.isEmpty()){
if (hand.isEmpty()) {
break;
}
Card card = hand.getRandom(game);
@ -1496,6 +1496,7 @@ public abstract class PlayerImpl implements Player, Serializable {
if (sourceObject != null) {
sourceObject.adjustTargets(ability, game);
}
UUID triggerId = null;
if (ability.canChooseTarget(game, playerId)) {
if (ability.isUsesStack()) {
game.getStack().push(new StackAbility(ability, playerId));
@ -1509,14 +1510,23 @@ public abstract class PlayerImpl implements Player, Serializable {
if (!ability.isUsesStack()) {
ability.resolve(game);
} else {
game.fireEvent(new GameEvent(GameEvent.EventType.TRIGGERED_ABILITY,
ability.getId(), ability, ability.getControllerId()));
game.fireEvent(new GameEvent(
GameEvent.EventType.TRIGGERED_ABILITY,
ability.getId(), ability, ability.getControllerId()
));
triggerId = ability.getId();
}
game.removeBookmark(bookmark);
return true;
}
}
restoreState(bookmark, triggeredAbility.getRule(), game); // why restore is needed here? (to remove the triggered ability from the stack because of no possible targets)
GameEvent event = new GameEvent(
GameEvent.EventType.ABILITY_TRIGGERED,
triggerId, ability, ability.getControllerId()
);
game.getState().setValue(event.getId().toString(), ability.getTriggerEvent());
game.fireEvent(event);
return false;
}