Some more rework of prevention effects.

This commit is contained in:
LevelX2 2014-04-24 16:39:03 +02:00
parent 0490c73924
commit b57b91150b
9 changed files with 180 additions and 232 deletions

View file

@ -39,6 +39,7 @@ import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.PreventionEffectImpl;
import mage.abilities.effects.common.PreventAllDamageToAttachedEffect;
import mage.abilities.effects.common.continious.GainAbilityAttachedEffect;
import mage.abilities.keyword.EquipAbility;
import mage.abilities.keyword.ShroudAbility;
@ -63,7 +64,7 @@ public class GeneralsKabuto extends CardImpl<GeneralsKabuto> {
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ShroudAbility.getInstance(), AttachmentType.EQUIPMENT)));
// Prevent all combat damage that would be dealt to equipped creature
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GeneralsKabutoEffect()));
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PreventAllDamageToAttachedEffect(Duration.WhileOnBattlefield, "equipped creature", true)));
// Equip {2}
this.addAbility(new EquipAbility(Outcome.PreventDamage, new GenericManaCost(2)));
@ -78,65 +79,3 @@ public class GeneralsKabuto extends CardImpl<GeneralsKabuto> {
return new GeneralsKabuto(this);
}
}
class GeneralsKabutoEffect extends PreventionEffectImpl<GeneralsKabutoEffect> {
public GeneralsKabutoEffect() {
super(Duration.WhileOnBattlefield);
staticText = "Prevent all combat damage that would be dealt to equipped creature";
}
public GeneralsKabutoEffect(final GeneralsKabutoEffect effect) {
super(effect);
}
@Override
public GeneralsKabutoEffect copy() {
return new GeneralsKabutoEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
GameEvent preventEvent = new GameEvent(
GameEvent.EventType.PREVENT_DAMAGE,
source.getFirstTarget(),
source.getId(),
source.getControllerId(),
event.getAmount(),
false);
if (!game.replaceEvent(preventEvent)) {
int damage = event.getAmount();
event.setAmount(0);
game.fireEvent(GameEvent.getEvent(
GameEvent.EventType.PREVENTED_DAMAGE,
source.getFirstTarget(),
source.getId(),
source.getControllerId(),
damage));
}
return false;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (super.applies(event, source, game) && event instanceof DamageEvent) {
DamageEvent damageEvent = (DamageEvent) event;
if (damageEvent.isCombatDamage()) {
Permanent aura = game.getPermanent(source.getSourceId());
if (aura != null && aura.getAttachedTo() != null) {
if (event.getTargetId().equals(aura.getAttachedTo())) {
return true;
}
}
}
}
return false;
}
}

View file

@ -67,10 +67,13 @@ public class KitsuneHealer extends CardImpl<KitsuneHealer> {
this.color.setWhite(true);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// {T}: Prevent the next 1 damage that would be dealt to target creature or player this turn.
Ability firstAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new TapSourceCost());
firstAbility.addTarget(new TargetCreatureOrPlayer());
this.addAbility(firstAbility);
Ability secondAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new KitsuneHealerEffect(), new TapSourceCost());
// {T}: Prevent all damage that would be dealt to target legendary creature this turn.
Ability secondAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, Integer.MAX_VALUE), new TapSourceCost());
secondAbility.addTarget(new TargetCreaturePermanent(filter));
this.addAbility(secondAbility);
}
@ -85,37 +88,3 @@ public class KitsuneHealer extends CardImpl<KitsuneHealer> {
}
}
class KitsuneHealerEffect extends PreventionEffectImpl<KitsuneHealerEffect> {
public KitsuneHealerEffect() {
super(Duration.EndOfTurn);
staticText = "Prevent all damage that would be dealt to target legendary creature this turn";
}
public KitsuneHealerEffect(final KitsuneHealerEffect effect) {
super(effect);
}
@Override
public KitsuneHealerEffect copy() {
return new KitsuneHealerEffect();
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), event.getAmount(), false);
if (!game.replaceEvent(preventEvent)) {
int damage = event.getAmount();
event.setAmount(0);
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), damage));
}
return false;
}
}

View file

@ -31,6 +31,7 @@ import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.PreventionEffectData;
import mage.abilities.effects.PreventionEffectImpl;
import mage.cards.CardImpl;
import mage.constants.CardType;
@ -80,17 +81,13 @@ public class VassalsDuty extends CardImpl<VassalsDuty> {
class VassalsDutyPreventDamageTargetEffect extends PreventionEffectImpl<VassalsDutyPreventDamageTargetEffect> {
private int amount;
public VassalsDutyPreventDamageTargetEffect(Duration duration, int amount) {
super(duration);
this.amount = amount;
super(duration, amount, false);
staticText = "The next " + amount + " damage that would be dealt to target legendary creature you control this turn is dealt to you instead";
}
public VassalsDutyPreventDamageTargetEffect(final VassalsDutyPreventDamageTargetEffect effect) {
super(effect);
this.amount = effect.amount;
}
@Override
@ -98,52 +95,28 @@ class VassalsDutyPreventDamageTargetEffect extends PreventionEffectImpl<VassalsD
return new VassalsDutyPreventDamageTargetEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, event.getTargetId(), source.getSourceId(), source.getControllerId(), event.getAmount(), false);
if (!game.replaceEvent(preventEvent)) {
int prevented;
if (event.getAmount() >= this.amount) {
int damage = amount;
event.setAmount(event.getAmount() - amount);
this.used = true;
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, event.getTargetId(), source.getSourceId(), source.getControllerId(), damage));
prevented = damage;
} else {
int damage = event.getAmount();
event.setAmount(0);
amount -= damage;
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, event.getTargetId(), source.getSourceId(), source.getControllerId(), damage));
prevented = damage;
}
// deal damage now
if (prevented > 0) {
UUID redirectTo = source.getControllerId();
Player player = game.getPlayer(redirectTo);
if (player != null) {
game.informPlayers("Dealing " + prevented + " to " + player.getName() + " instead");
// keep the original source id as it is redirecting
player.damage(prevented, event.getSourceId(), game, true, false);
}
PreventionEffectData preventionResult = preventDamageAction(event, source, game);
// deal damage now
if (preventionResult.getPreventedDamage() > 0) {
UUID redirectTo = source.getControllerId();
Player player = game.getPlayer(redirectTo);
if (player != null) {
game.informPlayers("Dealing " + preventionResult.getPreventedDamage() + " to " + player.getName() + " instead");
// keep the original source id as it is redirecting
player.damage(preventionResult.getPreventedDamage(), event.getSourceId(), game, false, true);
}
}
// damage amount is reduced or set to 0 so complete replacement of damage event is never neccessary
return false;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (!this.used && super.applies(event, source, game)) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null) {
if (permanent.getId().equals(this.getTargetPointer().getFirst(game, source))) {
return true;
}
if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) {
return game.getPermanent(event.getTargetId()) != null;
}
}
return false;

View file

@ -114,14 +114,8 @@ class PhantomNantukoPreventionEffect extends PreventionEffectImpl<PhantomNantuko
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
boolean retValue = false;
GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getSourceId(), event.getSourceId(), source.getControllerId(), event.getAmount(), false);
int damage = event.getAmount();
if (!game.replaceEvent(preventEvent)) {
event.setAmount(0);
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getSourceId(), event.getSourceId(), source.getControllerId(), damage));
retValue = true;
}
preventDamageAction(event, source, game);
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
boolean removeCounter = true;
@ -135,15 +129,16 @@ class PhantomNantukoPreventionEffect extends PreventionEffectImpl<PhantomNantuko
combatPhaseStep = game.getTurn().getStep();
}
}
StringBuilder sb = new StringBuilder(permanent.getName()).append(": ");
if(removeCounter && permanent.getCounters().containsKey(CounterType.P1P1)) {
StringBuilder sb = new StringBuilder(permanent.getName()).append(": ");
permanent.removeCounters(CounterType.P1P1.createInstance(), game);
sb.append("removed a +1/+1 counter ");
}
game.informPlayers(sb.append(" prevented ").append(damage).append(" Damage").toString());
sb.append("Removed a +1/+1 counter ");
game.informPlayers(sb.toString());
}
}
return retValue;
return false;
}
@Override

View file

@ -85,7 +85,7 @@ class ThunderstaffPreventionEffect extends PreventionEffectImpl<ThunderstaffPrev
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
public ThunderstaffPreventionEffect() {
super(Duration.WhileOnBattlefield);
super(Duration.WhileOnBattlefield, 1, true, false);
staticText = "As long as {this} is untapped, if a creature would deal combat damage to you, prevent 1 of that damage";
}
@ -98,30 +98,6 @@ class ThunderstaffPreventionEffect extends PreventionEffectImpl<ThunderstaffPrev
return new ThunderstaffPreventionEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getControllerId(), source.getSourceId(), source.getControllerId(), 1, false);
if (!game.replaceEvent(preventEvent)) {
event.setAmount(event.getAmount() - 1);
Permanent permanent = game.getPermanent(event.getSourceId());
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (permanent != null && sourcePermanent != null) {
StringBuilder sb = new StringBuilder();
sb.append(sourcePermanent.getName()).append(": ");
sb.append(1).append(" damage").append(" from ").append(permanent.getName());
sb.append(" has been prevented");
game.informPlayers(sb.toString());
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getControllerId(), source.getSourceId(), source.getControllerId(), 1));
}
return false;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (super.applies(event, source, game)) {

View file

@ -0,0 +1,81 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects;
/**
*
* @author LevelX2
*/
public class PreventionEffectData {
private boolean error;
private int preventedDamage;
private int remainingAmount;
private boolean replaced;
public PreventionEffectData(int remainingAmount) {
this.error = false;
this.preventedDamage = 0;
this.remainingAmount = remainingAmount;
this.replaced = false;
}
public boolean isError() {
return error;
}
public void setError(boolean error) {
this.error = error;
}
public int getPreventedDamage() {
return preventedDamage;
}
public void setPreventedDamage(int preventedDamage) {
this.preventedDamage = preventedDamage;
}
public int getRemainingAmount() {
return remainingAmount;
}
public void setRemainingAmount(int remainingAmount) {
this.remainingAmount = remainingAmount;
}
public boolean isReplaced() {
return replaced;
}
public void setReplaced(boolean replaced) {
this.replaced = replaced;
}
}

View file

@ -43,15 +43,19 @@ import mage.game.events.GameEvent;
* @param <T>
*/
public abstract class PreventionEffectImpl<T extends PreventionEffectImpl<T>> extends ReplacementEffectImpl<T> implements PreventionEffect<T> {
protected int amountToPrevent;
protected final boolean onlyCombat;
protected boolean consumable;
public PreventionEffectImpl(Duration duration) {
this(duration, Integer.MAX_VALUE, false);
}
public PreventionEffectImpl(Duration duration, int amountToPrevent, boolean onlyCombat) {
this(duration, amountToPrevent, onlyCombat, true);
}
public PreventionEffectImpl(Duration duration, int amountToPrevent, boolean onlyCombat, boolean consumable) {
super(duration, Outcome.PreventDamage);
this.effectType = EffectType.PREVENTION;
this.amountToPrevent = amountToPrevent;
@ -62,6 +66,7 @@ public abstract class PreventionEffectImpl<T extends PreventionEffectImpl<T>> ex
super(effect);
this.amountToPrevent = effect.amountToPrevent;
this.onlyCombat = effect.onlyCombat;
this.consumable = effect.consumable;
}
@ -71,18 +76,23 @@ public abstract class PreventionEffectImpl<T extends PreventionEffectImpl<T>> ex
return true;
}
protected PreventionEffectData preventDamageAction(GameEvent event, Ability source, Game game) {
PreventionEffectData preventionData = game.preventDamage(event, source, game, amountToPrevent);
if (!preventionData.isError() && !preventionData.isReplaced()) {
if (consumable) {
amountToPrevent = preventionData.getRemainingAmount();
}
if (amountToPrevent == 0) {
this.used = true;
}
}
return preventionData;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
game.preventDamage(event, source, game, amountToPrevent);
String data = event.getData();
if (amountToPrevent != Integer.MAX_VALUE && data != null && !data.isEmpty()) {
// update the amount to the amount not prevented yet
amountToPrevent = Integer.parseInt(event.getData());
}
if (amountToPrevent == 0) {
this.used = true;
}
// damage amount is reduced or set to 0 so replace of damage event is never neccessary
preventDamageAction(event, source, game);
// damage amount is reduced or set to 0 so complete replacement of damage event is never neccessary
return false;
}

View file

@ -66,6 +66,7 @@ import mage.util.functions.ApplyToPermanent;
import java.io.Serializable;
import java.util.*;
import mage.abilities.effects.PreventionEffectData;
import mage.game.command.Commander;
public interface Game extends MageItem, Serializable {
@ -190,7 +191,7 @@ public interface Game extends MageItem, Serializable {
* @param amountToPrevent max preventable amount
* @return true prevention was successfull / false prevention was replaced
*/
boolean preventDamage(GameEvent damageEvent, Ability source, Game game, int amountToPrevent);
PreventionEffectData preventDamage(GameEvent damageEvent, Ability source, Game game, int amountToPrevent);
/**
* Creates and fires an damage prevention event
*
@ -200,7 +201,7 @@ public interface Game extends MageItem, Serializable {
* @param preventAllDamage true if there is no limit to the damage that can be prevented
* @return true prevention was successfull / false prevention was replaced
*/
boolean preventDamage(GameEvent event, Ability source, Game game, boolean preventAllDamage);
PreventionEffectData preventDamage(GameEvent event, Ability source, Game game, boolean preventAllDamage);
//game play methods
void start(UUID choosingPlayerId);

View file

@ -54,6 +54,7 @@ import mage.abilities.common.ChancellorAbility;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.ContinuousEffects;
import mage.abilities.effects.Effect;
import mage.abilities.effects.PreventionEffectData;
import mage.abilities.effects.common.CopyEffect;
import mage.abilities.effects.common.continious.SourceEffect;
import mage.abilities.keyword.LeylineAbility;
@ -1832,57 +1833,60 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
}
@Override
public boolean preventDamage(GameEvent event, Ability source, Game game, boolean preventAllDamage) {
public PreventionEffectData preventDamage(GameEvent event, Ability source, Game game, boolean preventAllDamage) {
return preventDamage(event, source, game, Integer.MAX_VALUE);
}
@Override
public boolean preventDamage(GameEvent event, Ability source, Game game, int amountToPrevent) {
public PreventionEffectData preventDamage(GameEvent event, Ability source, Game game, int amountToPrevent) {
PreventionEffectData result = new PreventionEffectData(amountToPrevent);
if (!(event instanceof DamageEvent)) {
return false;
result.setError(true);
return result;
}
DamageEvent damageEvent = (DamageEvent) event;
GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, damageEvent.getTargetId(), damageEvent.getSourceId(), source.getControllerId(), damageEvent.getAmount(), false);
if (!game.replaceEvent(preventEvent)) {
int preventedDamage;
if (event.getAmount() > amountToPrevent) {
preventedDamage = amountToPrevent;
damageEvent.setAmount(event.getAmount() - amountToPrevent);
} else {
preventedDamage = event.getAmount();
damageEvent.setAmount(0);
}
if (amountToPrevent != Integer.MAX_VALUE) {
amountToPrevent -= preventedDamage;
// set remaining amount
event.setData(Integer.toString(amountToPrevent));
}
MageObject damageSource = game.getObject(damageEvent.getSourceId());
MageObject preventionSource = game.getObject(source.getSourceId());
if (damageSource != null && preventionSource != null) {
MageObject targetObject = game.getObject(event.getTargetId());
String targetName = "";
if (targetObject == null) {
Player targetPlayer = game.getPlayer(event.getTargetId());
if (targetPlayer != null) {
targetName = targetPlayer.getName();
}
} else {
targetName = targetObject.getName();
}
StringBuilder message = new StringBuilder(preventionSource.getName()).append(": Prevented ");
message.append(Integer.toString(preventedDamage)).append(" damage from ").append(damageSource.getName());
if (!targetName.isEmpty()) {
message.append(" to ").append(targetName);
}
game.informPlayers(message.toString());
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, damageEvent.getTargetId(), source.getSourceId(), source.getControllerId(), preventedDamage));
return true;
if (game.replaceEvent(preventEvent)) {
result.setReplaced(true);
return result;
}
return false;
if (event.getAmount() > amountToPrevent) {
result.setPreventedDamage(amountToPrevent);
damageEvent.setAmount(event.getAmount() - amountToPrevent);
} else {
result.setPreventedDamage(event.getAmount());
damageEvent.setAmount(0);
}
if (amountToPrevent != Integer.MAX_VALUE) {
// set remaining amount
event.setData(Integer.toString(amountToPrevent -= result.getPreventedDamage()));
}
MageObject damageSource = game.getObject(damageEvent.getSourceId());
MageObject preventionSource = game.getObject(source.getSourceId());
if (damageSource != null && preventionSource != null) {
MageObject targetObject = game.getObject(event.getTargetId());
String targetName = "";
if (targetObject == null) {
Player targetPlayer = game.getPlayer(event.getTargetId());
if (targetPlayer != null) {
targetName = targetPlayer.getName();
}
} else {
targetName = targetObject.getName();
}
StringBuilder message = new StringBuilder(preventionSource.getName()).append(": Prevented ");
message.append(Integer.toString(result.getPreventedDamage())).append(" damage from ").append(damageSource.getName());
if (!targetName.isEmpty()) {
message.append(" to ").append(targetName);
}
game.informPlayers(message.toString());
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, damageEvent.getTargetId(), source.getSourceId(), source.getControllerId(), result.getPreventedDamage()));
return result;
}