mirror of
https://github.com/correl/mage.git
synced 2024-11-22 03:00:11 +00:00
Combat.getAttackers and Combat.getBlockers now return a Set instead of a List, so that two-headed blockers aren't included twice
This commit is contained in:
parent
efaccf8564
commit
a6c5209a2a
20 changed files with 192 additions and 354 deletions
|
@ -844,7 +844,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
|||
}
|
||||
|
||||
private List<Permanent> getAttackers(Game game) {
|
||||
List<UUID> attackersUUID = game.getCombat().getAttackers();
|
||||
Set<UUID> attackersUUID = game.getCombat().getAttackers();
|
||||
if (attackersUUID.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -2815,7 +2815,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
log.debug(sb.toString());
|
||||
}
|
||||
|
||||
private void playRemoval(List<UUID> creatures, Game game) {
|
||||
private void playRemoval(Set<UUID> creatures, Game game) {
|
||||
for (UUID creatureId : creatures) {
|
||||
for (Card card : this.playableInstant) {
|
||||
if (card.getSpellAbility().canActivate(playerId, game).canActivate()) {
|
||||
|
@ -2833,7 +2833,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
}
|
||||
|
||||
private void playDamage(List<UUID> creatures, Game game) {
|
||||
private void playDamage(Set<UUID> creatures, Game game) {
|
||||
for (UUID creatureId : creatures) {
|
||||
Permanent creature = game.getPermanent(creatureId);
|
||||
for (Card card : this.playableInstant) {
|
||||
|
|
|
@ -2,25 +2,19 @@ package mage.cards.f;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.common.AttacksAloneControlledTriggeredAbility;
|
||||
import mage.abilities.condition.common.FirstCombatPhaseCondition;
|
||||
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
|
||||
import mage.abilities.effects.common.UntapTargetEffect;
|
||||
import mage.abilities.effects.common.AdditionalCombatPhaseEffect;
|
||||
import mage.abilities.keyword.ExaltedAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TurnPhase;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.turn.TurnMod;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
* @author awjackson
|
||||
*/
|
||||
public final class FinestHour extends CardImpl {
|
||||
|
||||
|
@ -32,7 +26,14 @@ public final class FinestHour extends CardImpl {
|
|||
|
||||
// Whenever a creature you control attacks alone, if it's the first combat phase of the turn, untap that
|
||||
// creature. After this phase, there is an additional combat phase.
|
||||
this.addAbility(new FinestHourAbility());
|
||||
Ability ability = new ConditionalInterveningIfTriggeredAbility(
|
||||
new AttacksAloneControlledTriggeredAbility(new UntapTargetEffect("untap that creature"), true, false),
|
||||
FirstCombatPhaseCondition.instance,
|
||||
"Whenever a creature you control attacks alone, if it's the first combat phase of the turn, " +
|
||||
"untap that creature. After this phase, there is an additional combat phase."
|
||||
);
|
||||
ability.addEffect(new AdditionalCombatPhaseEffect());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
private FinestHour(final FinestHour card) {
|
||||
|
@ -43,78 +44,4 @@ public final class FinestHour extends CardImpl {
|
|||
public FinestHour copy() {
|
||||
return new FinestHour(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FinestHourAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public FinestHourAbility() {
|
||||
super(Zone.BATTLEFIELD, new FinestHourEffect());
|
||||
}
|
||||
|
||||
public FinestHourAbility(final FinestHourAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FinestHourAbility copy() {
|
||||
return new FinestHourAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (game.isActivePlayer(this.controllerId)) {
|
||||
if (game.getCombat().attacksAlone()) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(game.getCombat().getAttackers().get(0), game));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkInterveningIfClause(Game game) {
|
||||
return game.getTurn().getPhase(TurnPhase.COMBAT).getCount() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever a creature you control attacks alone, if it's the first combat phase of the turn, untap that creature. After this phase, there is an additional combat phase.";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FinestHourEffect extends OneShotEffect {
|
||||
|
||||
public FinestHourEffect() {
|
||||
super(Outcome.Benefit);
|
||||
}
|
||||
|
||||
public FinestHourEffect(final FinestHourEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FinestHourEffect copy() {
|
||||
return new FinestHourEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source));
|
||||
if (permanent != null) {
|
||||
permanent.untap(game);
|
||||
game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), TurnPhase.COMBAT, null, false));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,10 +8,7 @@ import mage.abilities.effects.OneShotEffect;
|
|||
import mage.abilities.keyword.EquipAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.*;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
@ -37,7 +34,7 @@ public final class FractalHarness extends CardImpl {
|
|||
|
||||
// Whenever equipped creature attacks, double the number of +1/+1 counters on it.
|
||||
this.addAbility(new AttacksAttachedTriggeredAbility(
|
||||
new FractalHarnessDoubleEffect(), AttachmentType.EQUIPMENT, false, true
|
||||
new FractalHarnessDoubleEffect(), AttachmentType.EQUIPMENT, false, SetTargetPointer.PERMANENT
|
||||
));
|
||||
|
||||
// Equip {2}
|
||||
|
|
|
@ -15,7 +15,7 @@ import mage.game.permanent.Permanent;
|
|||
import mage.game.turn.Phase;
|
||||
import mage.game.turn.TurnMod;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -62,7 +62,7 @@ class IllusionistsGambitRemoveFromCombatEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
List<UUID> attackers = game.getCombat().getAttackers();
|
||||
Set<UUID> attackers = game.getCombat().getAttackers();
|
||||
for (UUID attackerId : attackers) {
|
||||
Permanent creature = game.getPermanent(attackerId);
|
||||
if (creature != null) {
|
||||
|
@ -85,10 +85,10 @@ class IllusionistsGambitRemoveFromCombatEffect extends OneShotEffect {
|
|||
|
||||
class IllusionistsGambitRequirementEffect extends RequirementEffect {
|
||||
|
||||
private List attackers;
|
||||
private Set<UUID> attackers;
|
||||
private Phase phase;
|
||||
|
||||
public IllusionistsGambitRequirementEffect(List attackers, Phase phase) {
|
||||
public IllusionistsGambitRequirementEffect(Set<UUID> attackers, Phase phase) {
|
||||
super(Duration.Custom);
|
||||
this.attackers = attackers;
|
||||
this.phase = phase;
|
||||
|
@ -135,10 +135,10 @@ class IllusionistsGambitRequirementEffect extends RequirementEffect {
|
|||
|
||||
class IllusionistsGambitRestrictionEffect extends RestrictionEffect {
|
||||
|
||||
private final List attackers;
|
||||
private final Set<UUID> attackers;
|
||||
private final Phase phase;
|
||||
|
||||
public IllusionistsGambitRestrictionEffect(List attackers, Phase phase) {
|
||||
public IllusionistsGambitRestrictionEffect(Set<UUID> attackers, Phase phase) {
|
||||
super(Duration.Custom, Outcome.Benefit);
|
||||
this.attackers = attackers;
|
||||
this.phase = phase;
|
||||
|
|
|
@ -4,7 +4,7 @@ import mage.MageInt;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
|
||||
import mage.abilities.common.ChooseABackgroundAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.condition.common.FirstCombatPhaseCondition;
|
||||
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
|
||||
import mage.abilities.effects.common.AdditionalCombatPhaseEffect;
|
||||
import mage.abilities.effects.common.UntapAllEffect;
|
||||
|
@ -32,11 +32,11 @@ public final class KarlachFuryOfAvernus extends CardImpl {
|
|||
this.power = new MageInt(5);
|
||||
this.toughness = new MageInt(4);
|
||||
|
||||
// Whenever you attack, if its the first combat phase of the turn, untap all attacking creatures. They gain first strike until end of turn. After this phase, there is an additional combat phase.
|
||||
// Whenever you attack, if it's the first combat phase of the turn, untap all attacking creatures. They gain first strike until end of turn. After this phase, there is an additional combat phase.
|
||||
Ability ability = new ConditionalInterveningIfTriggeredAbility(
|
||||
new AttacksWithCreaturesTriggeredAbility(
|
||||
new UntapAllEffect(StaticFilters.FILTER_ATTACKING_CREATURES), 1
|
||||
), KarlachFuryOfAvernusCondition.instance, "Whenever you attack, if its the first " +
|
||||
), FirstCombatPhaseCondition.instance, "Whenever you attack, if it's the first " +
|
||||
"combat phase of the turn, untap all attacking creatures. They gain first strike " +
|
||||
"until end of turn. After this phase, there is an additional combat phase."
|
||||
);
|
||||
|
@ -60,12 +60,3 @@ public final class KarlachFuryOfAvernus extends CardImpl {
|
|||
return new KarlachFuryOfAvernus(this);
|
||||
}
|
||||
}
|
||||
|
||||
enum KarlachFuryOfAvernusCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return game.getTurn().getPhase(TurnPhase.COMBAT).getCount() == 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
|
||||
package mage.cards.l;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
|
@ -99,10 +97,9 @@ class LightmineFieldEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
List<UUID> attackers = game.getCombat().getAttackers();
|
||||
int damage = attackers.size();
|
||||
int damage = game.getCombat().getAttackers().size();
|
||||
Set<MageObjectReference> attackSet = (Set<MageObjectReference>) getValue("Lightmine Field");
|
||||
if (!attackers.isEmpty()) {
|
||||
if (damage > 0) {
|
||||
for (Iterator<MageObjectReference> it = attackSet.iterator(); it.hasNext();) {
|
||||
MageObjectReference attacker = it.next();
|
||||
Permanent creature = attacker.getPermanent(game);
|
||||
|
|
|
@ -1,24 +1,19 @@
|
|||
|
||||
package mage.cards.m;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksAttachedTriggeredAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.EquipAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
* @author awjackson
|
||||
*/
|
||||
public final class MageSlayer extends CardImpl {
|
||||
|
||||
|
@ -26,11 +21,13 @@ public final class MageSlayer extends CardImpl {
|
|||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{R}{G}");
|
||||
this.subtype.add(SubType.EQUIPMENT);
|
||||
|
||||
// Whenever equipped creature attacks, it deals damage equal to its power to defending player.
|
||||
this.addAbility(new AttacksAttachedTriggeredAbility(new MageSlayerEffect(), false));
|
||||
// Whenever equipped creature attacks, it deals damage equal to its power to the player or planeswalker it's attacking
|
||||
this.addAbility(new AttacksAttachedTriggeredAbility(
|
||||
new MageSlayerEffect(), AttachmentType.EQUIPMENT, false, SetTargetPointer.PERMANENT
|
||||
));
|
||||
|
||||
// Equip {3}
|
||||
this.addAbility(new EquipAbility(Outcome.Benefit, new GenericManaCost(3), new TargetControlledCreaturePermanent(), false));
|
||||
this.addAbility(new EquipAbility(3, false));
|
||||
}
|
||||
|
||||
private MageSlayer(final MageSlayer card) {
|
||||
|
@ -61,18 +58,19 @@ class MageSlayerEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent equipment = game.getPermanent(source.getSourceId());
|
||||
if (equipment != null && equipment.getAttachedTo() != null) {
|
||||
int power = game.getPermanent(equipment.getAttachedTo()).getPower().getValue();
|
||||
UUID defenderId = game.getCombat().getDefenderId(equipment.getAttachedTo());
|
||||
if (power > 0 && defenderId != null) {
|
||||
UUID sourceId = (UUID) this.getValue("sourceId");
|
||||
if (sourceId != null) {
|
||||
game.damagePlayerOrPlaneswalker(defenderId, power, source.getSourceId(), source, game, false, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
Permanent attacker = getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
|
||||
if (attacker == null) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
game.damagePlayerOrPlaneswalker(
|
||||
game.getCombat().getDefenderId(attacker.getId()),
|
||||
attacker.getPower().getValue(),
|
||||
attacker.getId(),
|
||||
source,
|
||||
game,
|
||||
false,
|
||||
true
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package mage.cards.m;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
@ -108,8 +108,8 @@ class MandateOfPeaceEndCombatEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Combat combat = game.getCombat();
|
||||
List<UUID> attackerIds = combat.getAttackers();
|
||||
List<UUID> blockerIds = combat.getBlockers();
|
||||
Set<UUID> attackerIds = combat.getAttackers();
|
||||
Set<UUID> blockerIds = combat.getBlockers();
|
||||
Stream.concat(blockerIds.stream(), attackerIds.stream())
|
||||
.map(id -> game.getPermanent(id))
|
||||
.filter(e -> e != null)
|
||||
|
|
|
@ -2,9 +2,9 @@ package mage.cards.r;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksAloneAttachedTriggeredAbility;
|
||||
import mage.abilities.common.AttacksAttachedTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.GainLifeEffect;
|
||||
import mage.abilities.effects.common.LoseLifeTargetEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
||||
|
@ -13,14 +13,10 @@ import mage.abilities.keyword.EquipAbility;
|
|||
import mage.constants.*;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author weirddan455
|
||||
* @author awjackson
|
||||
*/
|
||||
public final class ReapersTalisman extends CardImpl {
|
||||
|
||||
|
@ -38,7 +34,12 @@ public final class ReapersTalisman extends CardImpl {
|
|||
)));
|
||||
|
||||
// Whenever equipped creature attacks alone, defending player loses 2 life and you gain 2 life.
|
||||
this.addAbility(new ReapersTalismanAttacksLoneTriggeredAbility());
|
||||
Ability ability = new AttacksAloneAttachedTriggeredAbility(
|
||||
new LoseLifeTargetEffect(2).setText("defending player loses 2 life"),
|
||||
AttachmentType.EQUIPMENT, false, SetTargetPointer.PLAYER
|
||||
);
|
||||
ability.addEffect(new GainLifeEffect(2).concatBy("and"));
|
||||
this.addAbility(ability);
|
||||
|
||||
// Equip {2}
|
||||
this.addAbility(new EquipAbility(2));
|
||||
|
@ -53,48 +54,3 @@ public final class ReapersTalisman extends CardImpl {
|
|||
return new ReapersTalisman(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ReapersTalismanAttacksLoneTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public ReapersTalismanAttacksLoneTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new LoseLifeTargetEffect(2));
|
||||
this.addEffect(new GainLifeEffect(2));
|
||||
}
|
||||
|
||||
private ReapersTalismanAttacksLoneTriggeredAbility(final ReapersTalismanAttacksLoneTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReapersTalismanAttacksLoneTriggeredAbility copy() {
|
||||
return new ReapersTalismanAttacksLoneTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (game.isActivePlayer(this.controllerId) && game.getCombat().attacksAlone()) {
|
||||
Permanent equipment = game.getPermanent(this.sourceId);
|
||||
UUID attackerId = game.getCombat().getAttackers().get(0);
|
||||
if (equipment != null && equipment.isAttachedTo(attackerId)) {
|
||||
UUID defender = game.getCombat().getDefendingPlayerId(attackerId, game);
|
||||
if (defender != null) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(defender));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever equipped creature attacks alone, defending player loses 2 life and you gain 2 life.";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package mage.cards.s;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.common.AttacksAloneAttachedTriggeredAbility;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.continuous.BoostTargetEffect;
|
||||
|
@ -10,19 +9,15 @@ import mage.abilities.keyword.EquipAbility;
|
|||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.CardIdPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
* @author awjackson
|
||||
*/
|
||||
public final class SigilOfValor extends CardImpl {
|
||||
|
||||
|
@ -31,10 +26,13 @@ public final class SigilOfValor extends CardImpl {
|
|||
this.subtype.add(SubType.EQUIPMENT);
|
||||
|
||||
// Whenever equipped creature attacks alone, it gets +1/+1 until end of turn for each other creature you control.
|
||||
this.addAbility(new SigilOfValorTriggeredAbility(new SigilOfValorCount()));
|
||||
this.addAbility(new AttacksAloneAttachedTriggeredAbility(
|
||||
new BoostTargetEffect(SigilOfValorCount.instance, SigilOfValorCount.instance, Duration.EndOfTurn),
|
||||
AttachmentType.EQUIPMENT, false, SetTargetPointer.PERMANENT
|
||||
));
|
||||
|
||||
// Equip {1}
|
||||
this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(1)));
|
||||
this.addAbility(new EquipAbility(1));
|
||||
}
|
||||
|
||||
private SigilOfValor(final SigilOfValor card) {
|
||||
|
@ -47,81 +45,32 @@ public final class SigilOfValor extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class SigilOfValorTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public SigilOfValorTriggeredAbility(DynamicValue boostValue) {
|
||||
super(Zone.BATTLEFIELD, new BoostTargetEffect(boostValue, boostValue, Duration.EndOfTurn));
|
||||
}
|
||||
|
||||
public SigilOfValorTriggeredAbility(final SigilOfValorTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SigilOfValorTriggeredAbility copy() {
|
||||
return new SigilOfValorTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (game.isActivePlayer(getControllerId())) {
|
||||
if (game.getCombat().attacksAlone()) {
|
||||
Permanent equipment = game.getPermanent(getSourceId());
|
||||
UUID attackerId = game.getCombat().getAttackers().get(0);
|
||||
if (equipment != null
|
||||
&& equipment.isAttachedTo(attackerId)) {
|
||||
this.getEffects().get(0).setTargetPointer(new FixedTarget(attackerId, game));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever equipped creature attacks alone, it gets +1/+1 until end of turn for each other creature you control.";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SigilOfValorCount implements DynamicValue {
|
||||
|
||||
public SigilOfValorCount() {
|
||||
}
|
||||
|
||||
public SigilOfValorCount(final SigilOfValorCount dynamicValue) {
|
||||
super();
|
||||
}
|
||||
enum SigilOfValorCount implements DynamicValue {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
Permanent equipment = game.getPermanent(sourceAbility.getSourceId());
|
||||
if (equipment != null && equipment.getAttachedTo() != null) {
|
||||
FilterPermanent filterPermanent = new FilterControlledCreaturePermanent();
|
||||
filterPermanent.add(Predicates.not(new CardIdPredicate(equipment.getAttachedTo())));
|
||||
return game.getBattlefield().count(filterPermanent, sourceAbility.getControllerId(), sourceAbility, game);
|
||||
UUID attackerId = effect.getTargetPointer().getFirst(game, sourceAbility);
|
||||
if (attackerId != null) {
|
||||
FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
|
||||
filter.add(Predicates.not(new CardIdPredicate(attackerId)));
|
||||
return game.getBattlefield().count(filter, sourceAbility.getControllerId(), sourceAbility, game);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicValue copy() {
|
||||
return new SigilOfValorCount(this);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "X";
|
||||
return "1";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "";
|
||||
return "other creature you control";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import mage.abilities.keyword.EquipAbility;
|
|||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.SubType;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -37,7 +38,7 @@ public final class SpikedRipsaw extends CardImpl {
|
|||
// Whenever equipped creature attacks, you may sacrifice a Forest. If you do, that creature gains trample until end of turn.
|
||||
this.addAbility(new AttacksAttachedTriggeredAbility(
|
||||
new DoIfCostPaid(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, "that creature gains trample until end of turn"), new SacrificeTargetCost(filter)),
|
||||
AttachmentType.EQUIPMENT, false, true
|
||||
AttachmentType.EQUIPMENT, false, SetTargetPointer.PERMANENT
|
||||
));
|
||||
|
||||
// Equip {3}
|
||||
|
|
|
@ -10,10 +10,7 @@ import mage.abilities.keyword.DoubleStrikeAbility;
|
|||
import mage.abilities.keyword.EquipAbility;
|
||||
import mage.cards.AdventureCard;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
@ -33,7 +30,7 @@ public final class TwoHandedAxe extends AdventureCard {
|
|||
|
||||
// Whenever equipped creature attacks, double its power until end of turn.
|
||||
this.addAbility(new AttacksAttachedTriggeredAbility(
|
||||
new TwoHandedAxeEffect(), AttachmentType.EQUIPMENT, false, true
|
||||
new TwoHandedAxeEffect(), AttachmentType.EQUIPMENT, false, SetTargetPointer.PERMANENT
|
||||
));
|
||||
|
||||
// Equip {1}{R}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
||||
/**
|
||||
* @author awjackson
|
||||
*/
|
||||
public class AttacksAloneAttachedTriggeredAbility extends AttacksAttachedTriggeredAbility {
|
||||
|
||||
public AttacksAloneAttachedTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
}
|
||||
|
||||
public AttacksAloneAttachedTriggeredAbility(Effect effect, boolean optional) {
|
||||
this(effect, AttachmentType.EQUIPMENT, optional);
|
||||
}
|
||||
|
||||
public AttacksAloneAttachedTriggeredAbility(Effect effect, AttachmentType attachmentType, boolean optional) {
|
||||
this(effect, attachmentType, optional, SetTargetPointer.NONE);
|
||||
}
|
||||
|
||||
public AttacksAloneAttachedTriggeredAbility(Effect effect, AttachmentType attachmentType, boolean optional, SetTargetPointer setTargetPointer) {
|
||||
super(effect, attachmentType, optional, setTargetPointer);
|
||||
setTriggerPhrase("Whenever " + attachmentType.verb().toLowerCase() + " creature attacks alone, ");
|
||||
}
|
||||
|
||||
protected AttacksAloneAttachedTriggeredAbility(final AttacksAloneAttachedTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttacksAloneAttachedTriggeredAbility copy() {
|
||||
return new AttacksAloneAttachedTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
return game.getCombat().attacksAlone() && super.checkTrigger(event, game);
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@ import mage.game.events.GameEvent;
|
|||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
|
@ -39,7 +38,7 @@ public class AttacksAloneControlledTriggeredAbility extends TriggeredAbilityImpl
|
|||
setTriggerPhrase("Whenever " + CardUtil.addArticle(filter.getMessage()) + " attacks alone, ");
|
||||
}
|
||||
|
||||
private AttacksAloneControlledTriggeredAbility(final AttacksAloneControlledTriggeredAbility ability) {
|
||||
protected AttacksAloneControlledTriggeredAbility(final AttacksAloneControlledTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filter = ability.filter;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
|
@ -52,7 +51,7 @@ public class AttacksAloneControlledTriggeredAbility extends TriggeredAbilityImpl
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS;
|
||||
return event.getType() == GameEvent.EventType.ATTACKER_DECLARED;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,7 +59,7 @@ public class AttacksAloneControlledTriggeredAbility extends TriggeredAbilityImpl
|
|||
if (!game.getCombat().attacksAlone()) {
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanent(game.getCombat().getAttackers().get(0));
|
||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||
if (permanent == null || !filter.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
|
@ -21,7 +18,7 @@ public class AttacksAloneSourceTriggeredAbility extends TriggeredAbilityImpl {
|
|||
setTriggerPhrase("Whenever {this} attacks alone, ");
|
||||
}
|
||||
|
||||
public AttacksAloneSourceTriggeredAbility(final AttacksAloneSourceTriggeredAbility ability) {
|
||||
protected AttacksAloneSourceTriggeredAbility(final AttacksAloneSourceTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
|
@ -32,25 +29,15 @@ public class AttacksAloneSourceTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS;
|
||||
return event.getType() == GameEvent.EventType.ATTACKER_DECLARED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if(game.isActivePlayer(this.controllerId) ) {
|
||||
UUID creatureId = this.getSourceId();
|
||||
if(creatureId != null) {
|
||||
if(game.getCombat().attacksAlone() && Objects.equals(creatureId, game.getCombat().getAttackers().get(0))) {
|
||||
UUID defender = game.getCombat().getDefenderId(creatureId);
|
||||
if(defender != null) {
|
||||
for(Effect effect: getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(defender));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!getSourceId().equals(event.getSourceId()) || !game.getCombat().attacksAlone()) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
getEffects().setTargetPointer(new FixedTarget(game.getCombat().getDefendingPlayerId(getSourceId(), game)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* "When enchanted/equipped creature attacks " triggered ability
|
||||
|
@ -20,7 +20,7 @@ import java.util.Locale;
|
|||
public class AttacksAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final AttachmentType attachmentType;
|
||||
private final boolean setTargetPointer;
|
||||
private final SetTargetPointer setTargetPointer;
|
||||
|
||||
public AttacksAttachedTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
|
@ -31,20 +31,20 @@ public class AttacksAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
|
||||
public AttacksAttachedTriggeredAbility(Effect effect, AttachmentType attachmentType, boolean optional) {
|
||||
this(effect, attachmentType, optional, false);
|
||||
this(effect, attachmentType, optional, SetTargetPointer.NONE);
|
||||
}
|
||||
|
||||
public AttacksAttachedTriggeredAbility(Effect effect, AttachmentType attachmentType, boolean optional, boolean setTargetPointer) {
|
||||
public AttacksAttachedTriggeredAbility(Effect effect, AttachmentType attachmentType, boolean optional, SetTargetPointer setTargetPointer) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.attachmentType = attachmentType;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
setTriggerPhrase("Whenever " + attachmentType.verb().toLowerCase(Locale.ENGLISH) + " creature attacks, ");
|
||||
setTriggerPhrase("Whenever " + attachmentType.verb().toLowerCase() + " creature attacks, ");
|
||||
}
|
||||
|
||||
public AttacksAttachedTriggeredAbility(final AttacksAttachedTriggeredAbility abiltity) {
|
||||
super(abiltity);
|
||||
this.attachmentType = abiltity.attachmentType;
|
||||
this.setTargetPointer = abiltity.setTargetPointer;
|
||||
protected AttacksAttachedTriggeredAbility(final AttacksAttachedTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.attachmentType = ability.attachmentType;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -59,20 +59,19 @@ public class AttacksAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent equipment = game.getPermanent(this.sourceId);
|
||||
if (equipment != null && equipment.getAttachedTo() != null
|
||||
&& event.getSourceId().equals(equipment.getAttachedTo())) {
|
||||
getEffects().setValue("sourceId", event.getSourceId());
|
||||
// TODO: Passing a permanent object like this can cause bugs. May need refactoring to use UUID instead.
|
||||
// See https://github.com/magefree/mage/issues/8377
|
||||
// 11-08-2021: Added a new constructor to set target pointer. Should probably be using this instead.
|
||||
Permanent attachedPermanent = game.getPermanent(event.getSourceId());
|
||||
getEffects().setValue("attachedPermanent", attachedPermanent);
|
||||
if (setTargetPointer && attachedPermanent != null) {
|
||||
getEffects().setTargetPointer(new FixedTarget(attachedPermanent, game));
|
||||
}
|
||||
return true;
|
||||
Permanent attachment = getSourcePermanentOrLKI(game);
|
||||
UUID attackerId = event.getSourceId();
|
||||
if (attachment == null || !attackerId.equals(attachment.getAttachedTo())) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
switch (setTargetPointer) {
|
||||
case PERMANENT:
|
||||
getEffects().setTargetPointer(new FixedTarget(attackerId, game));
|
||||
break;
|
||||
case PLAYER:
|
||||
getEffects().setTargetPointer(new FixedTarget(game.getCombat().getDefendingPlayerId(attackerId, game)));
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.constants.TurnPhase;
|
||||
import mage.game.Game;
|
||||
|
||||
public enum FirstCombatPhaseCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return game.getTurn().getPhase(TurnPhase.COMBAT).getCount() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "it's the first combat phase of the turn";
|
||||
}
|
||||
}
|
|
@ -1,25 +1,19 @@
|
|||
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.AttacksAloneControlledTriggeredAbility;
|
||||
import mage.abilities.effects.common.continuous.BoostTargetEffect;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
* @author awjackson
|
||||
*/
|
||||
public class ExaltedAbility extends TriggeredAbilityImpl {
|
||||
public class ExaltedAbility extends AttacksAloneControlledTriggeredAbility {
|
||||
|
||||
public ExaltedAbility() {
|
||||
super(Zone.BATTLEFIELD, new BoostTargetEffect(1, 1, Duration.EndOfTurn));
|
||||
super(new BoostTargetEffect(1, 1), true, false);
|
||||
}
|
||||
|
||||
public ExaltedAbility(final ExaltedAbility ability) {
|
||||
private ExaltedAbility(final ExaltedAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
|
@ -28,25 +22,8 @@ public class ExaltedAbility extends TriggeredAbilityImpl {
|
|||
return new ExaltedAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (game.isActivePlayer(this.controllerId)) {
|
||||
if (game.getCombat().attacksAlone()) {
|
||||
this.getEffects().get(0).setTargetPointer(new FixedTarget(game.getCombat().getAttackers().get(0)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "exalted <i>(Whenever a creature you control attacks alone, that creature gets +1/+1 until end of turn.)</i>";
|
||||
return "Exalted <i>(Whenever a creature you control attacks alone, that creature gets +1/+1 until end of turn.)</i>";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -115,16 +115,16 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
return defenders;
|
||||
}
|
||||
|
||||
public List<UUID> getAttackers() {
|
||||
List<UUID> attackers = new ArrayList<>();
|
||||
public Set<UUID> getAttackers() {
|
||||
Set<UUID> attackers = new HashSet<>();
|
||||
for (CombatGroup group : groups) {
|
||||
attackers.addAll(group.attackers);
|
||||
}
|
||||
return attackers;
|
||||
}
|
||||
|
||||
public List<UUID> getBlockers() {
|
||||
List<UUID> blockers = new ArrayList<>();
|
||||
public Set<UUID> getBlockers() {
|
||||
Set<UUID> blockers = new HashSet<>();
|
||||
for (CombatGroup group : groups) {
|
||||
blockers.addAll(group.blockers);
|
||||
}
|
||||
|
@ -1160,14 +1160,13 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
Set<UUID> blockedSet = mustBeBlockedByAtLeastX.get(blockedAttackerId);
|
||||
Set<UUID> toBlockSet = mustBeBlockedByAtLeastX.get(toBeBlockedCreatureId);
|
||||
if (toBlockSet == null) {
|
||||
// This should never happen.
|
||||
// This should never happen.
|
||||
return null;
|
||||
} else if (toBlockSet.containsAll(blockedSet)) {
|
||||
// the creature already blocks alone a creature that has to be blocked by at least one
|
||||
// and has more possible blockers, so this is ok
|
||||
// the creature already blocks alone a creature that has to be blocked by at least one
|
||||
// and has more possible blockers, so this is ok
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
// TODO: Check if the attacker is already blocked by another creature
|
||||
// and despite there is need that this attacker blocks this attacker also
|
||||
|
|
Loading…
Reference in a new issue