mirror of
https://github.com/magefree/mage.git
synced 2025-12-25 04:52:07 -08:00
* Redirection effect - Added possibility to last for one applyEffect cycle instead of only one absolute use.
This commit is contained in:
parent
b3d62865d9
commit
29605bc5ae
26 changed files with 149 additions and 99 deletions
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.effects;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.EffectType;
|
||||
|
|
@ -44,26 +45,34 @@ import mage.target.Target;
|
|||
*/
|
||||
public abstract class RedirectionEffect extends ReplacementEffectImpl {
|
||||
|
||||
protected Target redirectTarget;
|
||||
protected int amountToRedirect;
|
||||
protected boolean oneUsage;
|
||||
|
||||
public RedirectionEffect(Duration duration) {
|
||||
this(duration, Integer.MAX_VALUE, false);
|
||||
public enum UsageType {
|
||||
ACCORDING_DURATION,
|
||||
ONE_USAGE_ABSOLUTE,
|
||||
ONE_USAGE_AT_THE_SAME_TIME; // all damage dealt at the same time
|
||||
}
|
||||
|
||||
public RedirectionEffect(Duration duration, int amountToRedirect, boolean oneUsage) {
|
||||
protected Target redirectTarget;
|
||||
protected int amountToRedirect;
|
||||
protected UsageType usageType;
|
||||
protected int applyEffectsCounter;
|
||||
|
||||
public RedirectionEffect(Duration duration) {
|
||||
this(duration, Integer.MAX_VALUE, UsageType.ACCORDING_DURATION);
|
||||
applyEffectsCounter = -1;
|
||||
}
|
||||
|
||||
public RedirectionEffect(Duration duration, int amountToRedirect, UsageType usageType) {
|
||||
super(duration, Outcome.RedirectDamage);
|
||||
this.effectType = EffectType.REDIRECTION;
|
||||
this.amountToRedirect = amountToRedirect;
|
||||
this.oneUsage = oneUsage;
|
||||
this.usageType = usageType;
|
||||
}
|
||||
|
||||
public RedirectionEffect(final RedirectionEffect effect) {
|
||||
super(effect);
|
||||
this.redirectTarget = effect.redirectTarget;
|
||||
this.amountToRedirect = effect.amountToRedirect;
|
||||
this.oneUsage = effect.oneUsage;
|
||||
this.usageType = effect.usageType;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -79,26 +88,38 @@ public abstract class RedirectionEffect extends ReplacementEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
int damageToRedirect = event.getAmount();
|
||||
if (damageToRedirect < 1) { // if multiple replacement effect apply, the rest damage can be 0, so the effect is not applied/replaced
|
||||
return false;
|
||||
}
|
||||
String sourceLogName = source != null ? game.getObject(source.getSourceId()).getLogName() + ": " : "";
|
||||
DamageEvent damageEvent = (DamageEvent) event;
|
||||
int restDamage = 0;
|
||||
int damageToRedirect = event.getAmount();
|
||||
if (damageEvent.getAmount() > amountToRedirect) {
|
||||
restDamage = damageEvent.getAmount() - amountToRedirect;
|
||||
damageToRedirect = amountToRedirect;
|
||||
}
|
||||
if (damageToRedirect > 0 && oneUsage) {
|
||||
this.discard();
|
||||
if (damageToRedirect > 0 && usageType != UsageType.ACCORDING_DURATION) {
|
||||
if (UsageType.ONE_USAGE_ABSOLUTE == usageType) {
|
||||
this.discard();
|
||||
}
|
||||
if (applyEffectsCounter > 0) {
|
||||
if (applyEffectsCounter < game.getState().getApplyEffectsCounter()) {
|
||||
this.discard();
|
||||
}
|
||||
} else {
|
||||
applyEffectsCounter = game.getState().getApplyEffectsCounter();
|
||||
}
|
||||
}
|
||||
Permanent permanent = game.getPermanent(redirectTarget.getFirstTarget());
|
||||
if (permanent != null) {
|
||||
permanent.damage(damageToRedirect, event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects());
|
||||
game.informPlayers(sourceLogName + "Redirected " + damageToRedirect + " damage to " + permanent.getLogName());
|
||||
game.informPlayers(sourceLogName + "Redirected " + damageToRedirect + " damage" + getRedirectedFromText(event, game) + " to " + permanent.getLogName());
|
||||
} else {
|
||||
Player player = game.getPlayer(redirectTarget.getFirstTarget());
|
||||
if (player != null) {
|
||||
player.damage(damageToRedirect, event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects());
|
||||
game.informPlayers(sourceLogName + "Redirected " + damageToRedirect + " damage to " + player.getLogName());
|
||||
game.informPlayers(sourceLogName + "Redirected " + damageToRedirect + " damage" + getRedirectedFromText(event, game) + " to " + player.getLogName());
|
||||
}
|
||||
}
|
||||
if (restDamage > 0) {
|
||||
|
|
@ -108,4 +129,16 @@ public abstract class RedirectionEffect extends ReplacementEffectImpl {
|
|||
return true;
|
||||
}
|
||||
|
||||
private String getRedirectedFromText(GameEvent event, Game game) {
|
||||
Player player = game.getPlayer(event.getTargetId());
|
||||
if (player != null) {
|
||||
return " from " + player.getLogName();
|
||||
}
|
||||
MageObject mageObject = game.getObject(event.getTargetId());
|
||||
if (mageObject != null) {
|
||||
return " from " + mageObject.getLogName();
|
||||
}
|
||||
return "";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ import mage.game.permanent.Permanent;
|
|||
*/
|
||||
public class RedirectDamageFromSourceToTargetEffect extends RedirectionEffect {
|
||||
|
||||
public RedirectDamageFromSourceToTargetEffect(Duration duration, int amountToRedirect, boolean oneUsage) {
|
||||
super(duration, amountToRedirect, oneUsage);
|
||||
public RedirectDamageFromSourceToTargetEffect(Duration duration, int amountToRedirect, UsageType usageType) {
|
||||
super(duration, amountToRedirect, usageType);
|
||||
staticText = "The next " + amountToRedirect + " damage that would be dealt to {this} this turn is dealt to target creature you control instead.";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ package mage.game;
|
|||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.*;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
|
|
@ -121,6 +120,8 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
private Map<UUID, Card> copiedCards = new HashMap<>();
|
||||
private int permanentOrderNumber;
|
||||
|
||||
private int applyEffectsCounter; // Upcounting number of each applyEffects execution
|
||||
|
||||
public GameState() {
|
||||
players = new Players();
|
||||
playerList = new PlayerList();
|
||||
|
|
@ -137,6 +138,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
combat = new Combat();
|
||||
turnMods = new TurnMods();
|
||||
watchers = new Watchers();
|
||||
applyEffectsCounter = 0;
|
||||
}
|
||||
|
||||
public GameState(final GameState state) {
|
||||
|
|
@ -193,6 +195,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
this.zoneChangeCounter.putAll(state.zoneChangeCounter);
|
||||
this.copiedCards.putAll(state.copiedCards);
|
||||
this.permanentOrderNumber = state.permanentOrderNumber;
|
||||
this.applyEffectsCounter = state.applyEffectsCounter;
|
||||
}
|
||||
|
||||
public void restoreForRollBack(GameState state) {
|
||||
|
|
@ -210,7 +213,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
this.command = state.command;
|
||||
this.isPlaneChase = state.isPlaneChase;
|
||||
this.seenPlanes = state.seenPlanes;
|
||||
this.designations = state.designations;
|
||||
this.designations = state.designations;
|
||||
this.exile = state.exile;
|
||||
this.battlefield = state.battlefield;
|
||||
this.turnNum = state.turnNum;
|
||||
|
|
@ -237,6 +240,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
this.zoneChangeCounter = state.zoneChangeCounter;
|
||||
this.copiedCards = state.copiedCards;
|
||||
this.permanentOrderNumber = state.permanentOrderNumber;
|
||||
this.applyEffectsCounter = state.applyEffectsCounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -466,12 +470,12 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<String> getSeenPlanes() {
|
||||
return seenPlanes;
|
||||
}
|
||||
|
||||
|
||||
public boolean isPlaneChase() {
|
||||
return isPlaneChase;
|
||||
}
|
||||
|
|
@ -574,6 +578,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
}
|
||||
|
||||
public void applyEffects(Game game) {
|
||||
applyEffectsCounter++;
|
||||
for (Player player : players.values()) {
|
||||
player.reset();
|
||||
}
|
||||
|
|
@ -881,13 +886,13 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
addAbility(ability, designation.getId(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addSeenPlane(Plane plane, Game game, UUID controllerId) {
|
||||
if (plane != null) {
|
||||
getSeenPlanes().add(plane.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void resetSeenPlanes() {
|
||||
getSeenPlanes().clear();
|
||||
}
|
||||
|
|
@ -1169,4 +1174,9 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
public int getNextPermanentOrderNumber() {
|
||||
return permanentOrderNumber++;
|
||||
}
|
||||
|
||||
public int getApplyEffectsCounter() {
|
||||
return applyEffectsCounter;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue