mirror of
https://github.com/correl/mage.git
synced 2024-12-25 11:11:16 +00:00
Add new EventType CREATURE_BLOCKS, which fires once per blocker (rather than once per blocker per attacker). Updated some abilities and cards to use it (still incomplete). Fixes #4285
This commit is contained in:
parent
1c688a0345
commit
d5e56f523d
16 changed files with 50 additions and 39 deletions
|
@ -33,8 +33,7 @@ public final class BalduvianWarlord extends CardImpl {
|
|||
|
||||
public BalduvianWarlord(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}");
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.BARBARIAN);
|
||||
this.subtype.add(SubType.HUMAN, SubType.BARBARIAN);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
|
@ -152,6 +151,7 @@ class BalduvianWarlordUnblockEffect extends OneShotEffect {
|
|||
);
|
||||
}
|
||||
game.fireEvent(new BlockerDeclaredEvent(chosenPermanent.getId(), permanent.getId(), permanent.getControllerId()));
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKS, permanent.getId(), source, null));
|
||||
}
|
||||
CombatGroup blockGroup = findBlockingGroup(permanent, game); // a new blockingGroup is formed, so it's necessary to find it again
|
||||
if (blockGroup != null) {
|
||||
|
|
|
@ -22,7 +22,7 @@ import mage.target.targetpointer.FixedTarget;
|
|||
*/
|
||||
public final class BattleCry extends CardImpl {
|
||||
|
||||
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("");
|
||||
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("white creatures you control");
|
||||
|
||||
static {
|
||||
filter.add(new ColorPredicate(ObjectColor.WHITE));
|
||||
|
@ -65,12 +65,12 @@ class BattleCryTriggeredAbility extends DelayedTriggeredAbility {
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
|
||||
return event.getType() == GameEvent.EventType.CREATURE_BLOCKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(event.getSourceId(), game));
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import mage.constants.CardType;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
|
@ -55,12 +54,12 @@ class BattleStrainTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
|
||||
return event.getType() == GameEvent.EventType.CREATURE_BLOCKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent blocker = game.getPermanent(event.getSourceId());
|
||||
Permanent blocker = game.getPermanent(event.getTargetId());
|
||||
if (blocker != null) {
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(blocker.getControllerId()));
|
||||
return true;
|
||||
|
|
|
@ -3,8 +3,10 @@ package mage.cards.c;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
|
||||
|
@ -71,7 +73,7 @@ class CamouflageEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
public CamouflageEffect copy() {
|
||||
return new CamouflageEffect(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS;
|
||||
|
@ -98,7 +100,7 @@ class CamouflageEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), defenderId, game)) {
|
||||
permanent.setBlocking(0);
|
||||
}
|
||||
|
||||
|
||||
boolean declinedChoice = false;
|
||||
while (masterList.size() < attackerCount) {
|
||||
List<Permanent> newPile = new ArrayList<>();
|
||||
|
@ -133,7 +135,7 @@ class CamouflageEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
}
|
||||
}
|
||||
masterList.add(newPile);
|
||||
|
||||
|
||||
StringBuilder sb = new StringBuilder("Blocker pile of ").append(defender.getLogName()).append(" (no. " + masterList.size() + "): ");
|
||||
int i = 0;
|
||||
for (Permanent permanent : newPile) {
|
||||
|
@ -168,6 +170,7 @@ class CamouflageEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
}
|
||||
|
||||
List<List<Permanent>> allPiles = masterMap.get(playerId);
|
||||
Set<UUID> blockerIds = new HashSet<>();
|
||||
for (List<Permanent> pile : allPiles) {
|
||||
if (available.isEmpty()) {
|
||||
break;
|
||||
|
@ -180,19 +183,22 @@ class CamouflageEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
CombatGroup group = game.getCombat().findGroup(attacker.getId());
|
||||
if (group != null) {
|
||||
if (blocker.canBlock(attacker.getId(), game) && (blocker.getMaxBlocks() == 0 || group.getAttackers().size() <= blocker.getMaxBlocks())) {
|
||||
blockerIds.add(blocker.getId());
|
||||
boolean notYetBlocked = group.getBlockers().isEmpty();
|
||||
group.addBlockerToGroup(blocker.getId(), blocker.getControllerId(), game);
|
||||
game.getCombat().addBlockingGroup(blocker.getId(), attacker.getId(), blocker.getControllerId(), game);
|
||||
if (notYetBlocked) {
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, attacker.getId(), source, null));
|
||||
}
|
||||
// TODO: find an alternate event solution for multi-blockers (as per issue #4285), this will work fine for single blocker creatures though
|
||||
game.fireEvent(new BlockerDeclaredEvent(attacker.getId(), blocker.getId(), blocker.getControllerId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (UUID blockerId : blockerIds) {
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKS, blockerId, source, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
package mage.cards.c;
|
||||
|
||||
import java.util.UUID;
|
||||
|
@ -26,8 +24,7 @@ public final class CarnageGladiator extends CardImpl {
|
|||
|
||||
public CarnageGladiator (UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{R}");
|
||||
this.subtype.add(SubType.SKELETON);
|
||||
this.subtype.add(SubType.WARRIOR);
|
||||
this.subtype.add(SubType.SKELETON, SubType.WARRIOR);
|
||||
|
||||
this.power = new MageInt(4);
|
||||
this.toughness = new MageInt(2);
|
||||
|
@ -69,12 +66,12 @@ class CarnageGladiatorTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
|
||||
return event.getType() == GameEvent.EventType.CREATURE_BLOCKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent blocker = game.getPermanent(event.getSourceId());
|
||||
Permanent blocker = game.getPermanent(event.getTargetId());
|
||||
if (blocker != null) {
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(blocker.getControllerId()));
|
||||
return true;
|
||||
|
@ -86,4 +83,4 @@ class CarnageGladiatorTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public String getRule() {
|
||||
return "Whenever a creature blocks, that creature's controller loses 1 life.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,6 +178,7 @@ class FalseOrdersUnblockEffect extends OneShotEffect {
|
|||
);
|
||||
}
|
||||
game.fireEvent(new BlockerDeclaredEvent(chosenPermanent.getId(), permanent.getId(), permanent.getControllerId()));
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKS, permanent.getId(), source, null));
|
||||
}
|
||||
CombatGroup blockGroup = findBlockingGroup(permanent, game); // a new blockingGroup is formed, so it's necessary to find it again
|
||||
if (blockGroup != null) {
|
||||
|
|
|
@ -48,12 +48,12 @@ class HeatOfBattleTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
|
||||
return event.getType() == GameEvent.EventType.CREATURE_BLOCKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent blocker = game.getPermanent(event.getSourceId());
|
||||
Permanent blocker = game.getPermanent(event.getTargetId());
|
||||
if (blocker != null) {
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(blocker.getControllerId()));
|
||||
return true;
|
||||
|
|
|
@ -56,12 +56,12 @@ class MageHuntersOnslaughtDelayedTriggeredAbility extends DelayedTriggeredAbilit
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
|
||||
return event.getType() == GameEvent.EventType.CREATURE_BLOCKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -121,8 +121,8 @@ class SorrowsPathSwitchBlockersEffect extends OneShotEffect {
|
|||
// not blocking (since they're removed from combat) to blocking. It doesn't matter if those abilities triggered when those creatures blocked the first time. Abilities
|
||||
// that trigger whenever one of the attacking creatures becomes blocked will not trigger again, because they never stopped being blocked creatures. Abilities that
|
||||
// trigger whenever a creature blocks one of the attacking creatures will trigger again, though; those kinds of abilities trigger once for each creature that blocks.
|
||||
reassignBlocker(blocker1, attackers2, game);
|
||||
reassignBlocker(blocker2, attackers1, game);
|
||||
reassignBlocker(blocker1, attackers2, game, source);
|
||||
reassignBlocker(blocker2, attackers1, game, source);
|
||||
Set<MageObjectReference> morSet = new HashSet<>();
|
||||
attackers1
|
||||
.stream()
|
||||
|
@ -171,17 +171,17 @@ class SorrowsPathSwitchBlockersEffect extends OneShotEffect {
|
|||
return true;
|
||||
}
|
||||
|
||||
private void reassignBlocker(Permanent blocker, Set<Permanent> attackers, Game game) {
|
||||
private void reassignBlocker(Permanent blocker, Set<Permanent> attackers, Game game, Ability source) {
|
||||
for (Permanent attacker : attackers) {
|
||||
CombatGroup group = game.getCombat().findGroup(attacker.getId());
|
||||
if (group != null) {
|
||||
group.addBlockerToGroup(blocker.getId(), blocker.getControllerId(), game);
|
||||
game.getCombat().addBlockingGroup(blocker.getId(), attacker.getId(), blocker.getControllerId(), game);
|
||||
// TODO: find an alternate event solution for multi-blockers (as per issue #4285), this will work fine for single blocker creatures though
|
||||
game.fireEvent(new BlockerDeclaredEvent(attacker.getId(), blocker.getId(), blocker.getControllerId()));
|
||||
group.pickBlockerOrder(attacker.getControllerId(), game);
|
||||
}
|
||||
}
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKS, blocker.getId(), source, null));
|
||||
CombatGroup blockGroup = findBlockingGroup(blocker, game); // a new blockingGroup is formed, so it's necessary to find it again
|
||||
if (blockGroup != null) {
|
||||
blockGroup.pickAttackerOrder(blocker.getControllerId(), game);
|
||||
|
|
|
@ -10,6 +10,8 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AttacksOrBlocksAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final AttachmentType attachmentType;
|
||||
|
@ -33,12 +35,16 @@ public class AttacksOrBlocksAttachedTriggeredAbility extends TriggeredAbilityImp
|
|||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ATTACKER_DECLARED
|
||||
|| event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
|
||||
|| event.getType() == GameEvent.EventType.CREATURE_BLOCKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent enchantment = getSourcePermanentOrLKI(game);
|
||||
return enchantment != null && event.getSourceId().equals(enchantment.getAttachedTo());
|
||||
if (enchantment == null) {
|
||||
return false;
|
||||
}
|
||||
UUID idToCheck = (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) ? event.getSourceId() : event.getTargetId();
|
||||
return idToCheck.equals(enchantment.getAttachedTo());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,11 +29,11 @@ public class AttacksOrBlocksTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ATTACKER_DECLARED || event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
|
||||
return event.getType() == GameEvent.EventType.ATTACKER_DECLARED || event.getType() == GameEvent.EventType.CREATURE_BLOCKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
return event.getSourceId().equals(this.getSourceId());
|
||||
return getSourceId().equals((event.getType() == GameEvent.EventType.ATTACKER_DECLARED) ? event.getSourceId() : event.getTargetId());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ public class BecomesTargetTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
public BecomesTargetTriggeredAbility(Effect effect, FilterStackObject filter) {
|
||||
this(effect, filter, SetTargetPointer.NONE);
|
||||
setTriggerPhrase("When {this} becomes the target of " + filter.getMessage() + ", ");
|
||||
}
|
||||
|
||||
public BecomesTargetTriggeredAbility(Effect effect, FilterStackObject filter, SetTargetPointer setTargetPointer) {
|
||||
|
@ -34,13 +33,14 @@ public class BecomesTargetTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
public BecomesTargetTriggeredAbility(Effect effect, FilterStackObject filter, SetTargetPointer setTargetPointer, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filter = filter.copy();
|
||||
this.filter = filter;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
setTriggerPhrase("When {this} becomes the target of " + filter.getMessage() + ", ");
|
||||
}
|
||||
|
||||
public BecomesTargetTriggeredAbility(final BecomesTargetTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filter = ability.filter.copy();
|
||||
this.filter = ability.filter;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,12 +23,12 @@ public class BlocksCreatureTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
public BlocksCreatureTriggeredAbility(Effect effect, boolean optional) {
|
||||
this(effect, StaticFilters.FILTER_PERMANENT_CREATURE, optional);
|
||||
setTriggerPhrase("Whenever {this} blocks " + CardUtil.addArticle(filter.getMessage()) + ", ");
|
||||
}
|
||||
|
||||
public BlocksCreatureTriggeredAbility(Effect effect, FilterCreaturePermanent filter, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filter = filter;
|
||||
setTriggerPhrase("Whenever {this} blocks " + CardUtil.addArticle(filter.getMessage()) + ", ");
|
||||
}
|
||||
|
||||
public BlocksCreatureTriggeredAbility(final BlocksCreatureTriggeredAbility ability) {
|
||||
|
|
|
@ -5,7 +5,6 @@ import mage.abilities.TriggeredAbilityImpl;
|
|||
import mage.abilities.effects.Effect;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -28,13 +27,12 @@ public class BlocksSourceTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DECLARED_BLOCKERS;
|
||||
return event.getType() == GameEvent.EventType.CREATURE_BLOCKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent permanent = game.getPermanent(getSourceId());
|
||||
return permanent != null && permanent.getBlocking() > 0;
|
||||
return event.getTargetId().equals(getSourceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -704,6 +704,9 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
for (CombatGroup group : groups) {
|
||||
group.acceptBlockers(game);
|
||||
}
|
||||
for (UUID blockerId : getBlockers()) {
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKS, blockerId, null));
|
||||
}
|
||||
}
|
||||
|
||||
public void resumeSelectBlockers(Game game) {
|
||||
|
|
|
@ -298,6 +298,7 @@ public class GameEvent implements Serializable {
|
|||
*/
|
||||
BLOCKER_DECLARED,
|
||||
CREATURE_BLOCKED,
|
||||
CREATURE_BLOCKS,
|
||||
BATCH_BLOCK_NONCOMBAT,
|
||||
UNBLOCKED_ATTACKER,
|
||||
SEARCH_LIBRARY, LIBRARY_SEARCHED,
|
||||
|
|
Loading…
Reference in a new issue