Fixed various potential null pointer exceptions

This commit is contained in:
Evan Kranzler 2018-05-31 21:03:40 -04:00
parent 86f7a663b4
commit ab3cd76d3e
44 changed files with 438 additions and 439 deletions

View file

@ -155,7 +155,7 @@ class BalduvianWarlordUnblockEffect extends OneShotEffect {
return true;
}
Permanent chosenPermanent = game.getPermanent(target.getFirstTarget());
if (chosenPermanent != null && permanent != null && chosenPermanent.isCreature() && controller != null) {
if (chosenPermanent != null && chosenPermanent.isCreature()) {
CombatGroup chosenGroup = game.getCombat().findGroup(chosenPermanent.getId());
if (chosenGroup != null) {
// Relevant ruling for Balduvian Warlord:

View file

@ -59,7 +59,7 @@ import mage.util.CardUtil;
public final class BaronVonCount extends CardImpl {
public BaronVonCount(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{R}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.VILLAIN);
@ -152,22 +152,23 @@ class BaronVonCountTriggeredAbility extends TriggeredAbilityImpl {
Permanent sourcePermanent = game.getPermanent(getSourceId());
MageObject mageObject = game.getObject(getSourceId());
Spell spell = game.getStack().getSpell(event.getTargetId());
if (game.getState().getValue(mageObject.getId() + "_doom") == null) {
if (spell == null || sourcePermanent == null || mageObject == null) {
return false;
}
Integer doomNumber = (Integer) game.getState().getValue(mageObject.getId() + "_doom");
if (spell != null && sourcePermanent != null && mageObject != null && doomNumber > 0) {
if (!spell.isFaceDown(game)) {
String doomString = doomNumber.toString();
if (spell.getCard().getManaCost().getText().contains(doomString)
|| String.valueOf(spell.getPower().getBaseValue()).contains(doomString)
|| String.valueOf(spell.getToughness().getBaseValue()).contains(doomString)) {
return true;
} else {
for (String string : spell.getCard().getRules()) {
if (string.contains(doomString)) {
return true;
}
if (doomNumber == null || doomNumber == 0) {
return false;
}
if (!spell.isFaceDown(game)) {
String doomString = doomNumber.toString();
if (spell.getCard().getManaCost().getText().contains(doomString)
|| String.valueOf(spell.getPower().getBaseValue()).contains(doomString)
|| String.valueOf(spell.getToughness().getBaseValue()).contains(doomString)) {
return true;
} else {
for (String string : spell.getCard().getRules()) {
if (string.contains(doomString)) {
return true;
}
}
}

View file

@ -56,7 +56,7 @@ import mage.target.common.TargetControlledCreaturePermanent;
public final class BloodfireInfusion extends CardImpl {
public BloodfireInfusion(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}");
this.subtype.add(SubType.AURA);
// Enchant creature you control
@ -90,10 +90,11 @@ class AttachedPermanentPowerCount implements DynamicValue {
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
Permanent attachment = game.getPermanentOrLKIBattlefield(sourceAbility.getSourceId());
if (attachment == null) {
return 0;
}
Permanent permanent = game.getPermanentOrLKIBattlefield(attachment.getAttachedTo());
if (attachment != null
&& permanent != null
&& (permanent.getPower().getValue() >= 0)) {
if (permanent != null && (permanent.getPower().getValue() >= 0)) {
return permanent.getPower().getValue();
}
return 0;

View file

@ -86,10 +86,12 @@ class NumberOfCapitalsInTextOfTargetCreatureCount implements DynamicValue {
if (cards != null) {
for (CardInfo cardInfo : cards) {
Card dummy = cardInfo != null ? cardInfo.getCard() : null;
for (String line : dummy.getRules()) {
line = line.replaceAll("(?i)<i.*?</i>", ""); // Ignoring reminder text in italic
line = line.replaceAll("\\{this\\}", permanent.getName());
capitals += line.length() - line.replaceAll("[A-Z]", "").length();
if (dummy != null) {
for (String line : dummy.getRules()) {
line = line.replaceAll("(?i)<i.*?</i>", ""); // Ignoring reminder text in italic
line = line.replaceAll("\\{this\\}", permanent.getName());
capitals += line.length() - line.replaceAll("[A-Z]", "").length();
}
}
return -1 * capitals;
}

View file

@ -92,7 +92,7 @@ class CloneShellEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (controller == null) {
return false;
}
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4));

View file

@ -103,46 +103,47 @@ class CrownOfTheAgesEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
UUID auraId = getTargetPointer().getFirst(game, source);
Permanent aura = game.getPermanent(auraId);
Permanent aura = game.getPermanent(source.getFirstTarget());
if (aura == null) {
return false;
}
Permanent fromPermanent = game.getPermanent(aura.getAttachedTo());
Player controller = game.getPlayer(source.getControllerId());
if (fromPermanent != null && controller != null) {
boolean passed = true;
FilterCreaturePermanent filterChoice = new FilterCreaturePermanent("another creature");
filterChoice.add(Predicates.not(new PermanentIdPredicate(fromPermanent.getId())));
if (fromPermanent == null || controller == null) {
return false;
}
boolean passed = true;
FilterCreaturePermanent filterChoice = new FilterCreaturePermanent("another creature");
filterChoice.add(Predicates.not(new PermanentIdPredicate(fromPermanent.getId())));
Target chosenCreatureToAttachAura = new TargetPermanent(filterChoice);
chosenCreatureToAttachAura.setNotTarget(true);
Target chosenCreatureToAttachAura = new TargetPermanent(filterChoice);
chosenCreatureToAttachAura.setNotTarget(true);
if (chosenCreatureToAttachAura.canChoose(source.getSourceId(), source.getControllerId(), game)
&& controller.choose(Outcome.Neutral, chosenCreatureToAttachAura, source.getSourceId(), game)) {
Permanent creatureToAttachAura = game.getPermanent(chosenCreatureToAttachAura.getFirstTarget());
if (creatureToAttachAura != null) {
if (aura != null && passed) {
// Check the target filter
Target target = aura.getSpellAbility().getTargets().get(0);
if (target instanceof TargetPermanent) {
if (!target.getFilter().match(creatureToAttachAura, game)) {
passed = false;
}
}
// Check for protection
MageObject auraObject = game.getObject(auraId);
if (creatureToAttachAura.cantBeAttachedBy(auraObject, game)) {
if (chosenCreatureToAttachAura.canChoose(source.getSourceId(), source.getControllerId(), game)
&& controller.choose(Outcome.Neutral, chosenCreatureToAttachAura, source.getSourceId(), game)) {
Permanent creatureToAttachAura = game.getPermanent(chosenCreatureToAttachAura.getFirstTarget());
if (creatureToAttachAura != null) {
if (passed) {
// Check the target filter
Target target = aura.getSpellAbility().getTargets().get(0);
if (target instanceof TargetPermanent) {
if (!target.getFilter().match(creatureToAttachAura, game)) {
passed = false;
}
}
if (passed) {
fromPermanent.removeAttachment(aura.getId(), game);
creatureToAttachAura.addAttachment(aura.getId(), game);
return true;
// Check for protection
MageObject auraObject = game.getObject(aura.getId());
if (creatureToAttachAura.cantBeAttachedBy(auraObject, game)) {
passed = false;
}
}
if (passed) {
fromPermanent.removeAttachment(aura.getId(), game);
creatureToAttachAura.addAttachment(aura.getId(), game);
return true;
}
}
return true;
}
return false;
return true;
}
}

View file

@ -71,7 +71,7 @@ public final class CrypticGateway extends CardImpl {
TargetControlledPermanent target;
public CrypticGateway(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}");
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}");
// Tap two untapped creatures you control: You may put a creature card from your hand that shares a creature type with each creature tapped this way onto the battlefield.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CrypticGatewayEffect(), new CrypticGatewayCost(new TargetControlledPermanent(filter))));
@ -173,7 +173,7 @@ class CrypticGatewayEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (source == null || source.getCosts() == null) {
if (source.getCosts() == null) {
return false;
}

View file

@ -112,7 +112,7 @@ class DrainPowerEffect extends OneShotEffect {
for (Ability ability : permanent.getAbilities()) {
if (ability instanceof ActivatedAbility && ability.getAbilityType() == AbilityType.MANA) {
ActivatedManaAbilityImpl manaAbility = (ActivatedManaAbilityImpl) ability;
if (manaAbility != null && manaAbility.canActivate(targetPlayer.getId(), game).canActivate()) {
if (manaAbility.canActivate(targetPlayer.getId(), game).canActivate()) {
// canActivate can't check for mana abilities that require a mana cost, if the payment isn't possible (Cabal Coffers etc)
// so it's necessary to filter them out manually - might be buggy in some fringe cases
for (ManaCost manaCost : manaAbility.getManaCosts()) {

View file

@ -98,44 +98,47 @@ class BecomesColorOrColorsEnchantedEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (enchantment == null) {
return false;
}
Permanent permanent = game.getPermanent(enchantment.getAttachedTo());
StringBuilder sb = new StringBuilder();
if (controller != null && enchantment != null && permanent != null) {
for (int i = 0; i < 5; i++) {
if (i > 0) {
if (!controller.chooseUse(Outcome.Neutral, "Do you wish to choose another color?", source, game)) {
break;
}
}
ChoiceColor choiceColor = new ChoiceColor();
if (!controller.choose(Outcome.Benefit, choiceColor, game)) {
return false;
}
if (!game.isSimulation()) {
game.informPlayers(permanent.getName() + ": " + controller.getLogName() + " has chosen " + choiceColor.getChoice());
}
if (choiceColor.getColor().isBlack()) {
sb.append('B');
} else if (choiceColor.getColor().isBlue()) {
sb.append('U');
} else if (choiceColor.getColor().isRed()) {
sb.append('R');
} else if (choiceColor.getColor().isGreen()) {
sb.append('G');
} else if (choiceColor.getColor().isWhite()) {
sb.append('W');
if (controller == null || permanent == null) {
return false;
}
for (int i = 0; i < 5; i++) {
if (i > 0) {
if (!controller.chooseUse(Outcome.Neutral, "Do you wish to choose another color?", source, game)) {
break;
}
}
String colors = new String(sb);
ObjectColor chosenColors = new ObjectColor(colors);
ContinuousEffect effect = new BecomesColorTargetEffect(chosenColors, Duration.Custom);
effect.setTargetPointer(new FixedTarget(permanent.getId()));
game.addEffect(effect, source);
return true;
ChoiceColor choiceColor = new ChoiceColor();
if (!controller.choose(Outcome.Benefit, choiceColor, game)) {
return false;
}
if (!game.isSimulation()) {
game.informPlayers(permanent.getName() + ": " + controller.getLogName() + " has chosen " + choiceColor.getChoice());
}
if (choiceColor.getColor().isBlack()) {
sb.append('B');
} else if (choiceColor.getColor().isBlue()) {
sb.append('U');
} else if (choiceColor.getColor().isRed()) {
sb.append('R');
} else if (choiceColor.getColor().isGreen()) {
sb.append('G');
} else if (choiceColor.getColor().isWhite()) {
sb.append('W');
}
}
return false;
String colors = new String(sb);
ObjectColor chosenColors = new ObjectColor(colors);
ContinuousEffect effect = new BecomesColorTargetEffect(chosenColors, Duration.Custom);
effect.setTargetPointer(new FixedTarget(permanent.getId()));
game.addEffect(effect, source);
return true;
}
@Override

View file

@ -121,85 +121,87 @@ class FalseOrdersUnblockEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getTargets().getFirstTarget());
if (controller != null && permanent != null) {
if (controller == null || permanent == null) {
return false;
}
// Remove target creature from combat
Effect effect = new RemoveFromCombatTargetEffect();
effect.apply(game, source);
// Remove target creature from combat
Effect effect = new RemoveFromCombatTargetEffect();
effect.apply(game, source);
// Make blocked creatures unblocked
BlockedByOnlyOneCreatureThisCombatWatcher watcher = (BlockedByOnlyOneCreatureThisCombatWatcher) game.getState().getWatchers().get(BlockedByOnlyOneCreatureThisCombatWatcher.class.getSimpleName());
if (watcher != null) {
Set<CombatGroup> combatGroups = watcher.getBlockedOnlyByCreature(permanent.getId());
if (combatGroups != null) {
for (CombatGroup combatGroup : combatGroups) {
if (combatGroup != null) {
combatGroup.setBlocked(false, game);
}
// Make blocked creatures unblocked
BlockedByOnlyOneCreatureThisCombatWatcher watcher = (BlockedByOnlyOneCreatureThisCombatWatcher) game.getState().getWatchers().get(BlockedByOnlyOneCreatureThisCombatWatcher.class.getSimpleName());
if (watcher != null) {
Set<CombatGroup> combatGroups = watcher.getBlockedOnlyByCreature(permanent.getId());
if (combatGroups != null) {
for (CombatGroup combatGroup : combatGroups) {
if (combatGroup != null) {
combatGroup.setBlocked(false, game);
}
}
}
// Choose new creature to block
if (permanent.isCreature()) {
if (controller.chooseUse(Outcome.Benefit, "Do you want " + permanent.getLogName() + " to block an attacking creature?", source, game)) {
// according to the following mail response from MTG Rules Management about False Orders:
// "if Player A attacks Players B and C, Player B's creatures cannot block creatures attacking Player C"
// therefore we need to single out creatures attacking the target blocker's controller (disappointing, I know)
List<Permanent> list = new ArrayList<>();
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
if (combatGroup.getDefendingPlayerId().equals(permanent.getControllerId())) {
for (UUID attackingCreatureId : combatGroup.getAttackers()) {
Permanent targetsControllerAttacker = game.getPermanent(attackingCreatureId);
list.add(targetsControllerAttacker);
}
}
}
Player targetsController = game.getPlayer(permanent.getControllerId());
if (targetsController != null) {
FilterAttackingCreature filter = new FilterAttackingCreature("creature attacking " + targetsController.getLogName());
filter.add(new PermanentInListPredicate(list));
TargetAttackingCreature target = new TargetAttackingCreature(1, 1, filter, true);
if (target.canChoose(source.getSourceId(), controller.getId(), game)) {
while (!target.isChosen() && target.canChoose(controller.getId(), game) && controller.canRespond()) {
controller.chooseTarget(outcome, target, source, game);
}
} else {
return true;
}
Permanent chosenPermanent = game.getPermanent(target.getFirstTarget());
if (chosenPermanent != null && permanent != null && chosenPermanent.isCreature() && controller != null) {
CombatGroup chosenGroup = game.getCombat().findGroup(chosenPermanent.getId());
if (chosenGroup != null) {
// Relevant ruling for Balduvian Warlord:
// 7/15/2006 If an attacking creature has an ability that triggers When this creature becomes blocked,
// it triggers when a creature blocks it due to the Warlords ability only if it was unblocked at that point.
boolean notYetBlocked = chosenGroup.getBlockers().isEmpty();
chosenGroup.addBlockerToGroup(permanent.getId(), controller.getId(), game);
game.getCombat().addBlockingGroup(permanent.getId(), chosenPermanent.getId(), controller.getId(), game); // 702.21h
if (notYetBlocked) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, chosenPermanent.getId(), null));
for (UUID bandedId : chosenPermanent.getBandedCards()) {
CombatGroup bandedGroup = game.getCombat().findGroup(bandedId);
if (bandedGroup != null && chosenGroup.getBlockers().size() == 1) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, bandedId, null));
}
}
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BLOCKER_DECLARED, chosenPermanent.getId(), permanent.getId(), permanent.getControllerId()));
}
CombatGroup blockGroup = findBlockingGroup(permanent, game); // a new blockingGroup is formed, so it's necessary to find it again
if (blockGroup != null) {
blockGroup.pickAttackerOrder(permanent.getControllerId(), game);
}
}
}
}
return true;
}
}
return false;
if (!permanent.isCreature()
|| !controller.chooseUse(Outcome.Benefit, "Do you want " + permanent.getLogName() + " to block an attacking creature?", source, game)) {
return false;
}
// Choose new creature to block
// according to the following mail response from MTG Rules Management about False Orders:
// "if Player A attacks Players B and C, Player B's creatures cannot block creatures attacking Player C"
// therefore we need to single out creatures attacking the target blocker's controller (disappointing, I know)
List<Permanent> list = new ArrayList<>();
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
if (combatGroup.getDefendingPlayerId().equals(permanent.getControllerId())) {
for (UUID attackingCreatureId : combatGroup.getAttackers()) {
Permanent targetsControllerAttacker = game.getPermanent(attackingCreatureId);
list.add(targetsControllerAttacker);
}
}
}
Player targetsController = game.getPlayer(permanent.getControllerId());
if (targetsController == null) {
return false;
}
FilterAttackingCreature filter = new FilterAttackingCreature("creature attacking " + targetsController.getLogName());
filter.add(new PermanentInListPredicate(list));
TargetAttackingCreature target = new TargetAttackingCreature(1, 1, filter, true);
if (target.canChoose(source.getSourceId(), controller.getId(), game)) {
while (!target.isChosen() && target.canChoose(controller.getId(), game) && controller.canRespond()) {
controller.chooseTarget(outcome, target, source, game);
}
} else {
return true;
}
Permanent chosenPermanent = game.getPermanent(target.getFirstTarget());
if (chosenPermanent == null || !chosenPermanent.isCreature()) {
return false;
}
CombatGroup chosenGroup = game.getCombat().findGroup(chosenPermanent.getId());
if (chosenGroup != null) {
// Relevant ruling for Balduvian Warlord:
// 7/15/2006 If an attacking creature has an ability that triggers When this creature becomes blocked,
// it triggers when a creature blocks it due to the Warlords ability only if it was unblocked at that point.
boolean notYetBlocked = chosenGroup.getBlockers().isEmpty();
chosenGroup.addBlockerToGroup(permanent.getId(), controller.getId(), game);
game.getCombat().addBlockingGroup(permanent.getId(), chosenPermanent.getId(), controller.getId(), game); // 702.21h
if (notYetBlocked) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, chosenPermanent.getId(), null));
for (UUID bandedId : chosenPermanent.getBandedCards()) {
CombatGroup bandedGroup = game.getCombat().findGroup(bandedId);
if (bandedGroup != null && chosenGroup.getBlockers().size() == 1) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, bandedId, null));
}
}
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BLOCKER_DECLARED, chosenPermanent.getId(), permanent.getId(), permanent.getControllerId()));
}
CombatGroup blockGroup = findBlockingGroup(permanent, game); // a new blockingGroup is formed, so it's necessary to find it again
if (blockGroup != null) {
blockGroup.pickAttackerOrder(permanent.getControllerId(), game);
}
return true;
}
private CombatGroup findBlockingGroup(Permanent blocker, Game game) {

View file

@ -93,8 +93,8 @@ class GildedCerodonCondition implements Condition {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null
&& !game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game).isEmpty()
|| controller.getGraveyard().count(filter2, game) > 0) {
&& (!game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game).isEmpty()
|| controller.getGraveyard().count(filter2, game) > 0)) {
return true;
}
return false;

View file

@ -98,6 +98,10 @@ class GlissaSunseekerEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (controller == null || permanent == null) {
return false;
}
ManaPool pool = controller.getManaPool();
int blackMana = pool.getBlack();
int whiteMana = pool.getWhite();
@ -106,11 +110,8 @@ class GlissaSunseekerEffect extends OneShotEffect {
int redMana = pool.getRed();
int colorlessMana = pool.getColorless();
int manaPoolTotal = blackMana + whiteMana + blueMana + greenMana + redMana + colorlessMana;
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (controller != null && permanent != null) {
if (permanent.getConvertedManaCost() == manaPoolTotal) {
return permanent.destroy(source.getSourceId(), game, false);
}
if (permanent.getConvertedManaCost() == manaPoolTotal) {
return permanent.destroy(source.getSourceId(), game, false);
}
return false;
}

View file

@ -51,7 +51,7 @@ import mage.players.Player;
public final class GoblinPsychopath extends CardImpl {
public GoblinPsychopath(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}");
this.subtype.add(SubType.GOBLIN);
this.subtype.add(SubType.MUTANT);
this.power = new MageInt(5);
@ -97,9 +97,9 @@ class GoblinPsychopathEffect extends ReplacementEffectImpl {
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGE_CREATURE ||
event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER ||
event.getType() == GameEvent.EventType.DAMAGE_PLAYER;
return event.getType() == GameEvent.EventType.DAMAGE_CREATURE
|| event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER
|| event.getType() == GameEvent.EventType.DAMAGE_PLAYER;
}
@Override
@ -116,21 +116,19 @@ class GoblinPsychopathEffect extends ReplacementEffectImpl {
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
MageObject object = game.getObject(event.getSourceId());
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && object != null) {
if (this.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0) {
DamageEvent damageEvent = (DamageEvent) event;
if (damageEvent.isCombatDamage()) {
if (!wonFlip) {
// TODO: make this redirect damage from all blockers
controller.damage(event.getAmount(), source.getSourceId(), game, false, true);
String sourceLogName = source != null ? game.getObject(source.getSourceId()).getLogName() + ": " : "";
game.informPlayers(sourceLogName + "Redirected " + event.getAmount() + " damage to " + controller.getLogName());
this.discard();
return true;
}
}
}
if (controller == null || object == null
|| !(this.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0)) {
return false;
}
return false;
DamageEvent damageEvent = (DamageEvent) event;
if (!damageEvent.isCombatDamage() || wonFlip) {
return false;
}
// TODO: make this redirect damage from all blockers
controller.damage(event.getAmount(), source.getSourceId(), game, false, true);
String sourceLogName = game.getObject(source.getSourceId()).getLogName() + ": ";
game.informPlayers(sourceLogName + "Redirected " + event.getAmount() + " damage to " + controller.getLogName());
this.discard();
return true;
}
}

View file

@ -51,7 +51,7 @@ import mage.target.common.TargetLandPermanent;
public final class Helldozer extends CardImpl {
public Helldozer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}{B}");
this.subtype.add(SubType.ZOMBIE);
this.subtype.add(SubType.GIANT);
@ -96,13 +96,12 @@ class HelldozerEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Permanent helldozer = game.getPermanent(source.getSourceId());
Permanent landTarget = game.getPermanent(source.getFirstTarget());
if (landTarget != null) {
landTarget.destroy(id, game, false);
if (landTarget == null) {
return false;
}
Permanent landPermanent = (Permanent) game.getLastKnownInformation(landTarget.getId(), Zone.BATTLEFIELD);
if (landPermanent != null
&& !landPermanent.isBasic()
&& helldozer != null) {
boolean wasNonBasic = !landTarget.isBasic();
landTarget.destroy(id, game, false);
if (wasNonBasic && helldozer != null) {
return helldozer.untap(game);
}
return false;

View file

@ -61,15 +61,16 @@ import mage.target.targetpointer.FixedTarget;
public final class Heroism extends CardImpl {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a white creature");
static {
filter.add(new ColorPredicate(ObjectColor.WHITE));
}
public Heroism(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
// Sacrifice a white creature: For each attacking red creature, prevent all combat damage that would be dealt by that creature this turn unless its controller pays {2}{R}.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new HeroismEffect(), new SacrificeTargetCost(new TargetControlledCreaturePermanent(1,1, filter, true))));
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new HeroismEffect(), new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true))));
}
public Heroism(final Heroism card) {
@ -85,6 +86,7 @@ public final class Heroism extends CardImpl {
class HeroismEffect extends OneShotEffect {
private static final FilterAttackingCreature filter = new FilterAttackingCreature("attacking red creature");
static {
filter.add(new ColorPredicate(ObjectColor.RED));
}
@ -111,7 +113,7 @@ class HeroismEffect extends OneShotEffect {
Player player = game.getPlayer(game.getActivePlayerId());
Cost cost = new ManaCostsImpl("{2}{R}");
List<Permanent> permanentsToPrevent = new ArrayList<>();
for (Permanent permanent : game.getState().getBattlefield().getAllActivePermanents(filter, player.getId(), game)) {
for (Permanent permanent : game.getState().getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game)) {
cost.clearPaid();
String message = "Pay " + cost.getText() + "? If you don't, " + permanent.getLogName() + "'s combat damage will be prevented this turn.";
if (player != null && player.chooseUse(Outcome.Neutral, message, source, game)) {

View file

@ -48,12 +48,10 @@ import mage.players.Player;
public final class ImmortalServitude extends CardImpl {
public ImmortalServitude(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{W/B}{W/B}{W/B}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{W/B}{W/B}{W/B}");
// Return each creature card with converted mana cost X from your graveyard to the battlefield.
this.getSpellAbility().addEffect(new ImmortalServitudeEffect());
}
public ImmortalServitude(final ImmortalServitude card) {
@ -88,8 +86,7 @@ class ImmortalServitudeEffect extends OneShotEffect {
int count = source.getManaCostsToPay().getX();
Set<Card> cards = you.getGraveyard().getCards(new FilterCreatureCard(), game);
for (Card card : cards) {
if (card.getConvertedManaCost() == count
&& card != null) {
if (card != null && card.getConvertedManaCost() == count) {
card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false);
}
}

View file

@ -47,7 +47,7 @@ import mage.players.Player;
public final class IronMaiden extends CardImpl {
public IronMaiden(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}");
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// At the beginning of each opponent's upkeep, Iron Maiden deals X damage to that player, where X is the number of cards in their hand minus 4.
Ability ability = new BeginningOfUpkeepTriggeredAbility(new IronMaidenEffect(), TargetController.OPPONENT, false);
@ -63,10 +63,8 @@ public final class IronMaiden extends CardImpl {
return new IronMaiden(this);
}
}
class IronMaidenEffect extends OneShotEffect {
private IronMaidenEffect(final IronMaidenEffect effect) {
@ -80,16 +78,11 @@ class IronMaidenEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
if(player != null)
{
if (player != null) {
int amount = player.getHand().size() - 4;
if(amount > 0)
{
if (player != null) {
player.damage(amount, source.getSourceId(), game, false, true);
return true;
}
if (amount > 0) {
player.damage(amount, source.getSourceId(), game, false, true);
return true;
}
}
return false;

View file

@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.i;
import java.util.UUID;
@ -55,7 +54,7 @@ import mage.target.common.TargetCreaturePermanent;
public final class IronclawCurse extends CardImpl {
public IronclawCurse(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{R}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}");
this.subtype.add(SubType.AURA);
// Enchant creature
@ -101,8 +100,11 @@ class IronclawCurseEffect extends CantBlockAttachedEffect {
@Override
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
Permanent enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (enchantment == null) {
return false;
}
Permanent enchantedCreature = game.getPermanent(enchantment.getAttachedTo());
if (enchantment != null && enchantment.getAttachedTo() != null) {
if (enchantment.getAttachedTo() != null) {
return !(attacker.getPower().getValue() >= enchantedCreature.getToughness().getValue());
}
return true;

View file

@ -265,15 +265,14 @@ class KarnPlayerExileEffect extends OneShotEffect {
if (sourceObject == null) {
return false;
}
if (player != null) {
TargetCardInHand target = new TargetCardInHand();
if (target != null
&& target.canChoose(source.getSourceId(), player.getId(), game)) {
if (target.chooseTarget(Outcome.Exile, player.getId(), source, game)) {
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
return player.moveCardsToExile(new CardsImpl(target.getTargets()).getCards(game), source, game, true, exileId, sourceObject.getIdName());
}
}
if (player == null) {
return false;
}
TargetCardInHand target = new TargetCardInHand();
if (target.canChoose(source.getSourceId(), player.getId(), game)
&& target.chooseTarget(Outcome.Exile, player.getId(), source, game)) {
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
return player.moveCardsToExile(new CardsImpl(target.getTargets()).getCards(game), source, game, true, exileId, sourceObject.getIdName());
}
return false;
}

View file

@ -48,8 +48,7 @@ import java.util.*;
public final class KillingWave extends CardImpl {
public KillingWave(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{B}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}");
// For each creature, its controller sacrifices it unless he or she pays X life.
this.getSpellAbility().addEffect(new KillingWaveEffect());
@ -96,21 +95,23 @@ class KillingWaveEffect extends OneShotEffect {
FilterCreaturePermanent filter = new FilterCreaturePermanent();
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
List<Permanent> creatures = game.getBattlefield().getAllActivePermanents(filter, playerId, game);
if (player != null) {
List<Permanent> creatures = game.getBattlefield().getAllActivePermanents(filter, playerId, game);
int lifePaid = 0;
int playerLife = player.getLife();
for (Permanent creature : creatures) {
String message = "Pay " + amount + " life? If you don't, " + creature.getName() + " will be sacrificed.";
if (playerLife - amount - lifePaid >= 0 && player != null && player.chooseUse(Outcome.Neutral, message, source, game)) {
game.informPlayers(player.getLogName() + " pays " + amount + " life. He will not sacrifice " + creature.getName());
lifePaid += amount;
} else {
game.informPlayers(player.getLogName() + " will sacrifice " + creature.getName());
sacrifices.add(creature);
int lifePaid = 0;
int playerLife = player.getLife();
for (Permanent creature : creatures) {
String message = "Pay " + amount + " life? If you don't, " + creature.getName() + " will be sacrificed.";
if (playerLife - amount - lifePaid >= 0 && player.chooseUse(Outcome.Neutral, message, source, game)) {
game.informPlayers(player.getLogName() + " pays " + amount + " life. He will not sacrifice " + creature.getName());
lifePaid += amount;
} else {
game.informPlayers(player.getLogName() + " will sacrifice " + creature.getName());
sacrifices.add(creature);
}
}
lifePaidAmounts.put(playerId, lifePaid);
}
lifePaidAmounts.put(playerId, lifePaid);
}
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {

View file

@ -57,7 +57,7 @@ import mage.target.targetpointer.FixedTarget;
public final class LastRites extends CardImpl {
public LastRites(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}");
// Discard any number of cards. Target player reveals their hand, then you choose a nonland card from it for each card discarded this way. That player discards those cards.
this.getSpellAbility().addEffect(new LastRitesEffect());
@ -107,16 +107,12 @@ class LastRitesEffect extends OneShotEffect {
controller.discard(card, source, game);
}
}
if (targetPlayer != null) {
FilterCard filter = new FilterCard((discardCount > 1 ? "" : "a") + " nonland card" + (discardCount > 1 ? "s" : ""));
filter.add(Predicates.not(new CardTypePredicate(CardType.LAND)));
StaticValue discardValue = new StaticValue(discardCount);
Effect effect = new DiscardCardYouChooseTargetEffect(discardValue, filter, TargetController.ANY);
effect.setTargetPointer(new FixedTarget(targetPlayer.getId()));
effect.apply(game, source);
} else {
return false;
}
FilterCard filter = new FilterCard((discardCount > 1 ? "" : "a") + " nonland card" + (discardCount > 1 ? "s" : ""));
filter.add(Predicates.not(new CardTypePredicate(CardType.LAND)));
StaticValue discardValue = new StaticValue(discardCount);
Effect effect = new DiscardCardYouChooseTargetEffect(discardValue, filter, TargetController.ANY);
effect.setTargetPointer(new FixedTarget(targetPlayer.getId()));
effect.apply(game, source);
}
return true;
}

View file

@ -85,13 +85,14 @@ class LudevicNecroAlchemistCondition implements Condition {
Player currentPlayer = null;
UUID sourcePlayerId = source.getControllerId();
Player firstPlayer = null;
if (playerList != null) {
firstPlayer = playerList.getCurrent(game);
currentPlayer = playerList.getNext(game);
if (playerList == null) {
return false;
}
firstPlayer = playerList.getCurrent(game);
currentPlayer = playerList.getNext(game);
while (watcher != null && currentPlayer != null) {
if (currentPlayer != null && !Objects.equals(currentPlayer.getId(), sourcePlayerId) && watcher.getLiveLost(currentPlayer.getId()) > 0) {
if (!Objects.equals(currentPlayer.getId(), sourcePlayerId) && watcher.getLiveLost(currentPlayer.getId()) > 0) {
return true;
}
if (Objects.equals(currentPlayer, firstPlayer)) {

View file

@ -60,7 +60,7 @@ import mage.target.targetpointer.FixedTarget;
public final class MammothHarness extends CardImpl {
public MammothHarness(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{G}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}");
this.subtype.add(SubType.AURA);
// Enchant creature
@ -103,20 +103,18 @@ class MammothHarnessTriggeredAbility extends BlocksOrBecomesBlockedTriggeredAbil
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(this.getSourceId());
if (sourcePermanent != null) {
Permanent attachedTo = game.getPermanentOrLKIBattlefield(sourcePermanent.getAttachedTo());
if (sourcePermanent != null) {
if (event.getSourceId().equals(attachedTo.getId())) {
Permanent blocked = game.getPermanent(event.getTargetId());
if (blocked != null && filter.match(blocked, game)) {
this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId()));
return true;
}
if (event.getSourceId().equals(attachedTo.getId())) {
Permanent blocked = game.getPermanent(event.getTargetId());
if (blocked != null && filter.match(blocked, game)) {
this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId()));
return true;
}
if (event.getTargetId().equals(attachedTo.getId())) {
Permanent blocker = game.getPermanent(event.getSourceId());
if (blocker != null) {
this.getEffects().setTargetPointer(new FixedTarget(event.getSourceId()));
return true;
}
}
if (event.getTargetId().equals(attachedTo.getId())) {
Permanent blocker = game.getPermanent(event.getSourceId());
if (blocker != null) {
this.getEffects().setTargetPointer(new FixedTarget(event.getSourceId()));
return true;
}
}
}

View file

@ -125,14 +125,12 @@ class MaralenOfTheMornsongEffect2 extends OneShotEffect {
Player player = game.getPlayer(activePlayerId);
if (player != null) {
player.loseLife(3, game, false);
if (player != null) {
TargetCardInLibrary target = new TargetCardInLibrary();
if (player.searchLibrary(target, game)) {
player.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game);
}
player.shuffleLibrary(source, game);
return true;
TargetCardInLibrary target = new TargetCardInLibrary();
if (player.searchLibrary(target, game)) {
player.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game);
}
player.shuffleLibrary(source, game);
return true;
}
return false;
}

View file

@ -97,10 +97,8 @@ class PerishTheThoughtEffect extends OneShotEffect {
if (you.choose(Outcome.Neutral, targetOpponent.getHand(), target, game)) {
Card chosenCard = targetOpponent.getHand().get(target.getFirstTarget(), game);
if (chosenCard != null) {
if (targetOpponent != null) {
chosenCard.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false);
targetOpponent.shuffleLibrary(source, game);
}
chosenCard.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false);
targetOpponent.shuffleLibrary(source, game);
}
}
return true;

View file

@ -60,7 +60,7 @@ import mage.target.targetpointer.FixedTarget;
public final class PowerLeak extends CardImpl {
public PowerLeak(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}");
this.subtype.add(SubType.AURA);
// Enchant enchantment
@ -103,31 +103,31 @@ class PowerLeakEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getActivePlayerId());
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (player != null && permanent != null) {
ManaCosts<ManaCost> cost = new ManaCostsImpl<>("{X}");
String message = "Pay {X} to prevent X damage from " + permanent.getLogName() + "?";
int xValue = 0;
if (player != null && player.chooseUse(Outcome.Neutral, message, source, game)) {
xValue = player.announceXMana(0, Integer.MAX_VALUE, "Choose the amount of mana to pay", game, source);
cost.add(new GenericManaCost(xValue));
if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) {
game.informPlayers(player.getLogName() + " paid {" + xValue + "} for " + permanent.getLogName());
} else {
game.informPlayers(player.getLogName() + " didn't pay {X} for " + permanent.getLogName());
}
if (player == null || permanent == null) {
return false;
}
ManaCosts<ManaCost> cost = new ManaCostsImpl<>("{X}");
String message = "Pay {X} to prevent X damage from " + permanent.getLogName() + "?";
int xValue = 0;
if (player.chooseUse(Outcome.Neutral, message, source, game)) {
xValue = player.announceXMana(0, Integer.MAX_VALUE, "Choose the amount of mana to pay", game, source);
cost.add(new GenericManaCost(xValue));
if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) {
game.informPlayers(player.getLogName() + " paid {" + xValue + "} for " + permanent.getLogName());
} else {
game.informPlayers(player.getLogName() + " didn't pay {X} for " + permanent.getLogName());
}
PreventDamageByTargetEffect effect = new PreventDamageByTargetEffect(Duration.OneUse, xValue, false);
if (xValue != 0 && cost.isPaid()) {
effect.setTargetPointer(new FixedTarget(permanent.getId()));
game.addEffect(effect, source);
}
player.damage(2, source.getSourceId(), game, false, true);
effect.discard();
return true;
} else {
game.informPlayers(player.getLogName() + " didn't pay {X} for " + permanent.getLogName());
}
return false;
PreventDamageByTargetEffect effect = new PreventDamageByTargetEffect(Duration.OneUse, xValue, false);
if (xValue != 0 && cost.isPaid()) {
effect.setTargetPointer(new FixedTarget(permanent.getId()));
game.addEffect(effect, source);
}
player.damage(2, source.getSourceId(), game, false, true);
effect.discard();
return true;
}
}

View file

@ -58,7 +58,7 @@ public final class QuietSpeculation extends CardImpl {
}
public QuietSpeculation(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}");
// Search target player's library for up to three cards with flashback and put them into that player's graveyard. Then the player shuffles their library.
TargetCardInLibrary target = new TargetCardInLibrary(0, 3, filterCard);
@ -96,7 +96,10 @@ class SearchLibraryPutInGraveEffect extends SearchEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
UUID targetPlayerID = source.getFirstTarget();
if (controller != null && targetPlayerID != null && controller.searchLibrary(target, game, targetPlayerID)) {
if (controller == null) {
return false;
}
if (targetPlayerID != null && controller.searchLibrary(target, game, targetPlayerID)) {
if (!target.getTargets().isEmpty()) {
Cards cards = new CardsImpl(target.getTargets());
controller.revealCards("Quiet Speculation", cards, game);
@ -108,5 +111,4 @@ class SearchLibraryPutInGraveEffect extends SearchEffect {
controller.shuffleLibrary(source, game);
return false;
}
}

View file

@ -47,7 +47,7 @@ import mage.target.TargetPermanent;
public final class Recoil extends CardImpl {
public Recoil(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}{B}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{B}");
// Return target permanent to its owner's hand. Then that player discards a card.
this.getSpellAbility().addEffect(new RecoilEffect());
@ -84,8 +84,11 @@ class RecoilEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent target = game.getPermanent(source.getFirstTarget());
if (target == null) {
return false;
}
Player controller = game.getPlayer(target.getControllerId());
if (target != null && controller != null) {
if (controller != null) {
controller.moveCards(target, Zone.HAND, source, game);
controller.discard(1, false, source, game);
return true;

View file

@ -157,10 +157,8 @@ class SavingGraceReplacementEffect extends ReplacementEffectImpl {
}
game.informPlayers(message.toString());
// Redirect damage
if (creature != null) {
creature.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects());
return true;
}
creature.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects());
return true;
}
return false;
}

View file

@ -121,18 +121,22 @@ class SerraBestiaryRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Permanent enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (enchantment == null) {
return false;
}
Permanent enchantedCreature = game.getPermanent(enchantment.getAttachedTo());
if (enchantment != null && enchantment.getAttachedTo() != null) {
MageObject object = game.getObject(event.getSourceId());
Optional<Ability> ability = game.getAbility(event.getTargetId(), event.getSourceId());
if (ability.isPresent()
&& object != null
&& object.isCreature()
&& object.getId().equals(enchantedCreature.getId())
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())) {
if (ability.get().getCosts().stream().anyMatch((cost) -> (cost instanceof TapSourceCost))) {
return true;
}
if (enchantedCreature == null) {
return false;
}
MageObject object = game.getObject(event.getSourceId());
Optional<Ability> ability = game.getAbility(event.getTargetId(), event.getSourceId());
if (ability.isPresent()
&& object != null
&& object.isCreature()
&& object.getId().equals(enchantedCreature.getId())
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())) {
if (ability.get().getCosts().stream().anyMatch((cost) -> (cost instanceof TapSourceCost))) {
return true;
}
}
return false;

View file

@ -127,7 +127,7 @@ class ShadesBreathSetSubtypeEffect extends ContinuousEffectImpl {
for (Permanent permanent : permanents) {
if (permanent != null) {
SubTypeList subtype = permanent.getSubtype(game);
if (subtype != null && subtype.size() != 1 || !subtype.contains(SubType.SHADE)) {
if (subtype != null && (subtype.size() != 1 || !subtype.contains(SubType.SHADE))) {
subtype.removeAll(SubType.getCreatureTypes(false));
subtype.add(SubType.SHADE);
}

View file

@ -56,10 +56,9 @@ import mage.target.common.TargetCreaturePermanent;
public final class SlowMotion extends CardImpl {
public SlowMotion(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
this.subtype.add(SubType.AURA);
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
@ -68,7 +67,7 @@ public final class SlowMotion extends CardImpl {
this.addAbility(ability);
// At the beginning of the upkeep of enchanted creature's controller, that player sacrifices that creature unless he or she pays {2}.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeEquipedUnlessPaysEffect(new GenericManaCost(2)), TargetController.CONTROLLER_ATTACHED_TO, false ));
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeEquipedUnlessPaysEffect(new GenericManaCost(2)), TargetController.CONTROLLER_ATTACHED_TO, false));
// When Slow Motion is put into a graveyard from the battlefield, return Slow Motion to its owner's hand.
this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new ReturnToHandSourceEffect()));
@ -85,13 +84,14 @@ public final class SlowMotion extends CardImpl {
}
class SacrificeEquipedUnlessPaysEffect extends OneShotEffect {
protected Cost cost;
public SacrificeEquipedUnlessPaysEffect(Cost cost) {
super(Outcome.Sacrifice);
this.cost = cost;
staticText = "that player sacrifices that creature unless he or she pays {2}";
}
}
public SacrificeEquipedUnlessPaysEffect(final SacrificeEquipedUnlessPaysEffect effect) {
super(effect);
@ -101,25 +101,29 @@ class SacrificeEquipedUnlessPaysEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent equipment = game.getPermanent(source.getSourceId());
if (equipment != null && equipment.getAttachedTo() != null) {
Permanent equipped = game.getPermanent(equipment.getAttachedTo());
Player player = game.getPlayer(equipped.getControllerId());
if (player != null && equipped != null) {
if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? (Or " + equipped.getName() + " will be sacrificed.)", source, game)) {
cost.clearPaid();
if (cost.pay(source, game, source.getSourceId(), equipped.getControllerId(), false, null)) {
return true;
}
}
equipped.sacrifice(source.getSourceId(), game);
if (equipment == null) {
return false;
}
Permanent equipped = game.getPermanent(equipment.getAttachedTo());
if (equipped == null) {
return false;
}
Player player = game.getPlayer(equipped.getControllerId());
if (player == null) {
return false;
}
if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? (Or " + equipped.getName() + " will be sacrificed.)", source, game)) {
cost.clearPaid();
if (cost.pay(source, game, source.getSourceId(), equipped.getControllerId(), false, null)) {
return true;
}
}
return false;
equipped.sacrifice(source.getSourceId(), game);
return true;
}
@Override
public SacrificeEquipedUnlessPaysEffect copy() {
return new SacrificeEquipedUnlessPaysEffect(this);
}
}
}

View file

@ -114,10 +114,8 @@ class SpikeCannibalEffect extends OneShotEffect {
}
if (countersRemoved > 0) {
if (sourcePermanent != null) {
sourcePermanent.addCounters(CounterType.P1P1.createInstance(countersRemoved), source, game);
return true;
}
sourcePermanent.addCounters(CounterType.P1P1.createInstance(countersRemoved), source, game);
return true;
}
}

View file

@ -55,7 +55,7 @@ import mage.target.common.TargetCreaturePermanent;
public final class SpyNetwork extends CardImpl {
public SpyNetwork(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}");
// Look at target player's hand, the top card of that player's library, and any face-down creatures he or she controls. Look at the top four cards of your library, then put them back in any order.
this.getSpellAbility().addEffect(new SpyNetworkLookAtTargetPlayerHandEffect());
@ -133,7 +133,7 @@ class SpyNetworkFaceDownEffect extends OneShotEffect {
filter.add(new ControllerIdPredicate(player.getId()));
TargetCreaturePermanent target = new TargetCreaturePermanent(1, 1, filter, true);
if (target.canChoose(source.getSourceId(), controller.getId(), game)) {
while (player != null && controller.chooseUse(outcome, "Look at a face down creature controlled by " + player.getLogName() + "?", source, game)) {
while (controller.chooseUse(outcome, "Look at a face down creature controlled by " + player.getLogName() + "?", source, game)) {
target.clearChosen();
while (!target.isChosen() && target.canChoose(controller.getId(), game) && controller.canRespond()) {
controller.chooseTarget(outcome, target, source, game);
@ -145,9 +145,7 @@ class SpyNetworkFaceDownEffect extends OneShotEffect {
Cards cards = new CardsImpl();
cards.add(copyFaceDown);
controller.lookAtCards("face down card - " + mageObject.getName(), cards, game);
if (player != null) {
game.informPlayers(controller.getLogName() + " looks at a face down creature controlled by " + player.getLogName());
}
game.informPlayers(controller.getLogName() + " looks at a face down creature controlled by " + player.getLogName());
}
}
}

View file

@ -112,8 +112,8 @@ class SummonThePackEffect extends OneShotEffect {
StringBuilder message = new StringBuilder(controller.getLogName()).append(" opened: ");
for (Card c : boosterPack) {
message.append(c.getName()).append(" ");
if (c != null && c.isCreature()) {
message.append(c.getName()).append(" ");
message.append(" (creature card) ");
ContinuousEffect effect2 = new BecomesBlackZombieAdditionEffect(false);
effect2.setTargetPointer(new FixedTarget(c.getId()));
@ -124,7 +124,7 @@ class SummonThePackEffect extends OneShotEffect {
}
if (creatureCards.size() > 0) {
Set<Card> ccs = new HashSet<Card>(creatureCards);
Set<Card> ccs = new HashSet<>(creatureCards);
game.loadCards(ccs, controller.getId());
controller.moveCards(ccs, Zone.BATTLEFIELD, source, game);
}

View file

@ -50,7 +50,7 @@ import mage.target.common.TargetOpponent;
public final class TheBattleOfYavin extends CardImpl {
public TheBattleOfYavin(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}{B}");
// For each nonland permanent target opponent controls, that player sacrificies it unless he or she pays X life.
this.getSpellAbility().addEffect(new TheBattleOfYavinEffect());
@ -102,7 +102,7 @@ class TheBattleOfYavinEffect extends OneShotEffect {
int playerLife = opponent.getLife();
for (Permanent permanent : permanents) {
String message = "Pay " + amount + " life? If you don't, " + permanent.getName() + " will be sacrificed.";
if (playerLife - amount - lifePaid >= 0 && opponent != null && opponent.chooseUse(Outcome.Neutral, message, source, game)) {
if (playerLife - amount - lifePaid >= 0 && opponent.chooseUse(Outcome.Neutral, message, source, game)) {
game.informPlayers(opponent.getLogName() + " pays " + amount + " life. He will not sacrifice " + permanent.getName());
lifePaid += amount;
} else {

View file

@ -62,7 +62,7 @@ import mage.target.targetpointer.FixedTarget;
public final class TidalFlats extends CardImpl {
public TidalFlats(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{U}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}");
// {U}{U}: For each attacking creature without flying, its controller may pay {1}. If he or she doesn't, creatures you control blocking that creature gain first strike until end of turn.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new TidalFlatsEffect(), new ManaCostsImpl("{U}{U}")));
@ -81,6 +81,7 @@ public final class TidalFlats extends CardImpl {
class TidalFlatsEffect extends OneShotEffect {
private static final FilterAttackingCreature filter = new FilterAttackingCreature("attacking creature without flying");
static {
filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
}
@ -103,43 +104,45 @@ class TidalFlatsEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
game.getPlayerList();
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Player player = game.getPlayer(game.getActivePlayerId());
Cost cost = new ManaCostsImpl("{1}");
List<Permanent> affectedPermanents = new ArrayList<>();
for (Permanent permanent : game.getState().getBattlefield().getAllActivePermanents(filter, player.getId(), game)) {
cost.clearPaid();
String message = "Pay " + cost.getText() + " for " + permanent.getLogName() + "? If you don't, creatures " + controller.getLogName() + " controls blocking it gain first strike until end of turn.";
if (player != null && player.chooseUse(Outcome.Benefit, message, source, game)) {
if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) {
game.informPlayers(player.getLogName() + " paid " + cost.getText() + " for " + permanent.getLogName());
continue;
} else {
game.informPlayers(player.getLogName() + " didn't pay " + cost.getText() + " for " + permanent.getLogName());
affectedPermanents.add(permanent);
}
if (controller == null) {
return false;
}
Player player = game.getPlayer(game.getActivePlayerId());
if (player == null) {
return false;
}
Cost cost = new ManaCostsImpl("{1}");
List<Permanent> affectedPermanents = new ArrayList<>();
for (Permanent permanent : game.getState().getBattlefield().getAllActivePermanents(filter, player.getId(), game)) {
cost.clearPaid();
String message = "Pay " + cost.getText() + " for " + permanent.getLogName() + "? If you don't, creatures " + controller.getLogName() + " controls blocking it gain first strike until end of turn.";
if (player.chooseUse(Outcome.Benefit, message, source, game)) {
if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) {
game.informPlayers(player.getLogName() + " paid " + cost.getText() + " for " + permanent.getLogName());
} else {
game.informPlayers(player.getLogName() + " didn't pay " + cost.getText() + " for " + permanent.getLogName());
affectedPermanents.add(permanent);
}
} else {
game.informPlayers(player.getLogName() + " didn't pay " + cost.getText() + " for " + permanent.getLogName());
affectedPermanents.add(permanent);
}
}
for (Permanent permanent : affectedPermanents) {
CombatGroup group = game.getCombat().findGroup(permanent.getId());
if (group != null) {
for (UUID blockerId : group.getBlockers()) {
Permanent blocker = game.getPermanent(blockerId);
if (blocker != null && Objects.equals(blocker.getControllerId(), controller.getId())) {
ContinuousEffect effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(blocker.getId()));
game.addEffect(effect, source);
}
for (Permanent permanent : affectedPermanents) {
CombatGroup group = game.getCombat().findGroup(permanent.getId());
if (group != null) {
for (UUID blockerId : group.getBlockers()) {
Permanent blocker = game.getPermanent(blockerId);
if (blocker != null && Objects.equals(blocker.getControllerId(), controller.getId())) {
ContinuousEffect effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(blocker.getId()));
game.addEffect(effect, source);
}
}
}
return true;
}
return false;
return true;
}
}

View file

@ -122,7 +122,7 @@ class TorrentialGearhulkEffect extends OneShotEffect {
game.addEffect(effect, source);
}
}
} else {
} else if (card != null) {
Logger.getLogger(TorrentialGearhulkEffect.class).error("Torrential Gearhulk - Instant card without spellAbility : " + card.getName());
return false;
}

View file

@ -55,7 +55,7 @@ import mage.target.common.TargetCreaturePermanent;
public final class TreacherousLink extends CardImpl {
public TreacherousLink(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
this.subtype.add(SubType.AURA);
// Enchant creature
@ -109,12 +109,15 @@ class TreacherousLinkEffect extends ReplacementEffectImpl {
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
DamageEvent damageEvent = (DamageEvent) event;
Permanent enchantedCreature = game.getPermanentOrLKIBattlefield(damageEvent.getTargetId());
Player controller = game.getPlayer(enchantedCreature.getControllerId());
if (enchantedCreature != null && controller != null) {
controller.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects());
return true;
if (enchantedCreature == null) {
return false;
}
return false;
Player controller = game.getPlayer(enchantedCreature.getControllerId());
if (controller == null) {
return false;
}
controller.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects());
return true;
}
@Override

View file

@ -83,7 +83,7 @@ public final class WallOfPutridFlesh extends CardImpl {
class PreventDamageToSourceByEnchantedCreatures extends PreventAllDamageToSourceEffect {
public PreventDamageToSourceByEnchantedCreatures(){
public PreventDamageToSourceByEnchantedCreatures() {
super(Duration.WhileOnBattlefield);
}
@ -100,10 +100,10 @@ class PreventDamageToSourceByEnchantedCreatures extends PreventAllDamageToSource
}
public boolean isEnchantedCreature(MageObject input, Game game) {
if (input != null && !input.isCreature()) {
if (input == null || input.isCreature()) {
return false;
}
for (UUID attachmentId : ((Permanent)input).getAttachments()) {
for (UUID attachmentId : ((Permanent) input).getAttachments()) {
Permanent attachment = game.getPermanent(attachmentId);
if (attachment != null && attachment.isEnchantment()) {
return true;

View file

@ -47,7 +47,7 @@ import mage.players.Player;
public final class WheelOfTorture extends CardImpl {
public WheelOfTorture(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}");
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// At the beginning of each opponent's upkeep, Wheel of Torture deals X damage to that player, where X is 3 minus the number of cards in their hand.
Ability ability = new BeginningOfUpkeepTriggeredAbility(new WheelOfTortureEffect(), TargetController.OPPONENT, false);
@ -64,7 +64,6 @@ public final class WheelOfTorture extends CardImpl {
}
}
class WheelOfTortureEffect extends OneShotEffect {
private WheelOfTortureEffect(final WheelOfTortureEffect effect) {
@ -78,16 +77,11 @@ class WheelOfTortureEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
if(player != null)
{
if (player != null) {
int amount = 3 - player.getHand().size();
if(amount > 0)
{
if (player != null) {
player.damage(amount, source.getSourceId(), game, false, true);
return true;
}
if (amount > 0) {
player.damage(amount, source.getSourceId(), game, false, true);
return true;
}
}
return false;
@ -103,5 +97,4 @@ class WheelOfTortureEffect extends OneShotEffect {
return "Wheel of Torture deals X damage to that player, where X is 3 minus the number of cards in their hand";
}
}

View file

@ -83,6 +83,9 @@ class WretchedBanquetEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent targetCreature = game.getPermanent(source.getFirstTarget());
if (targetCreature == null) {
return false;
}
List<Permanent> creatures = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game);
int minPower = targetCreature.getPower().getValue() + 1;
@ -92,7 +95,7 @@ class WretchedBanquetEffect extends OneShotEffect {
}
}
if (targetCreature != null && targetCreature.getPower().getValue() <= minPower) {
if (targetCreature.getPower().getValue() <= minPower) {
targetCreature.destroy(source.getSourceId(), game, false);
return true;
}

View file

@ -1,6 +1,5 @@
package mage.verify;
import javassist.bytecode.SignatureAttribute;
import mage.ObjectColor;
import mage.cards.*;
import mage.cards.basiclands.BasicLand;
@ -352,9 +351,7 @@ public class VerifyCardDataTest {
//Assert.assertNotNull("Can't create token by default constructor", token);
if (token == null) {
Assert.fail("Can't create token by default constructor: " + className);
}
if (tokDataNamesIndex.getOrDefault(token.getName(), "").isEmpty()) {
} else if (tokDataNamesIndex.getOrDefault(token.getName(), "").isEmpty()) {
errorsList.add("error, can't find data in card-pictures-tok.txt for token: " + tokenClass.getName() + " -> " + token.getName());
}
}

View file

@ -103,7 +103,7 @@ public class DoUnlessTargetPlayerOrTargetsControllerPaysEffect extends OneShotEf
}
if (targetController != null) {
MageObject sourceObject = game.getObject(source.getSourceId());
if (targetController != null && sourceObject != null) {
if (sourceObject != null) {
Cost costToPay;
if (cost != null) {
costToPay = cost.copy();