mirror of
https://github.com/magefree/mage.git
synced 2025-12-26 05:22:02 -08:00
* Fixed problems of Yixlid Jailer that removed abilities from cards in graveyard permanently (fixes #1147).
This commit is contained in:
parent
893bcbb01f
commit
8854871c15
28 changed files with 248 additions and 180 deletions
|
|
@ -5,17 +5,13 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
import mage.abilities.costs.*;
|
||||
import mage.abilities.costs.common.PayLifeCost;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.*;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.Effects;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.ManaEffect;
|
||||
import mage.abilities.effects.mana.DynamicManaEffect;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.cards.Card;
|
||||
|
|
@ -25,7 +21,6 @@ import mage.game.Game;
|
|||
import mage.game.command.Emblem;
|
||||
import mage.game.command.Plane;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ManaEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackAbility;
|
||||
|
|
@ -952,7 +947,12 @@ public abstract class AbilityImpl implements Ability {
|
|||
return false;
|
||||
}
|
||||
return ((Permanent) object).isPhasedIn();
|
||||
} else if (!object.getAbilities().contains(this)) {
|
||||
} else if (object instanceof Card) {
|
||||
if (!((Card) object).getAbilities(game).contains(this)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (!object.getAbilities().contains(this)) { // not sure which object it can still be
|
||||
// check if it's an ability that is temporary gained to a card
|
||||
Abilities<Ability> otherAbilities = game.getState().getAllOtherAbilities(this.getSourceId());
|
||||
return otherAbilities != null && otherAbilities.contains(this);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package mage.cards;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Abilities;
|
||||
|
|
@ -14,9 +16,6 @@ import mage.game.Game;
|
|||
import mage.game.GameState;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface Card extends MageObject {
|
||||
|
||||
UUID getOwnerId();
|
||||
|
|
@ -77,15 +76,15 @@ public interface Card extends MageObject {
|
|||
* @param zone
|
||||
* @param sourceId
|
||||
* @param game
|
||||
* @param flag If zone
|
||||
* <ul>
|
||||
* <li>LIBRARY: <ul><li>true - put on top</li><li>false - put on
|
||||
* bottom</li></ul></li>
|
||||
* <li>BATTLEFIELD: <ul><li>true - tapped</li><li>false -
|
||||
* untapped</li></ul></li>
|
||||
* <li>GRAVEYARD: <ul><li>true - not from Battlefield</li><li>false - from
|
||||
* Battlefield</li></ul></li>
|
||||
* </ul>
|
||||
* @param flag If zone
|
||||
* <ul>
|
||||
* <li>LIBRARY: <ul><li>true - put on top</li><li>false - put on
|
||||
* bottom</li></ul></li>
|
||||
* <li>BATTLEFIELD: <ul><li>true - tapped</li><li>false -
|
||||
* untapped</li></ul></li>
|
||||
* <li>GRAVEYARD: <ul><li>true - not from Battlefield</li><li>false - from
|
||||
* Battlefield</li></ul></li>
|
||||
* </ul>
|
||||
* @return true if card was moved to zone
|
||||
*/
|
||||
boolean moveToZone(Zone zone, UUID sourceId, Game game, boolean flag);
|
||||
|
|
@ -95,8 +94,8 @@ public interface Card extends MageObject {
|
|||
/**
|
||||
* Moves the card to an exile zone
|
||||
*
|
||||
* @param exileId set to null for generic exile zone
|
||||
* @param name used for exile zone with the specified exileId
|
||||
* @param exileId set to null for generic exile zone
|
||||
* @param name used for exile zone with the specified exileId
|
||||
* @param sourceId
|
||||
* @param game
|
||||
* @return true if card was moved to zone
|
||||
|
|
@ -132,6 +131,8 @@ public interface Card extends MageObject {
|
|||
|
||||
void addAbility(Ability ability);
|
||||
|
||||
void looseAllAbilities(Game game);
|
||||
|
||||
boolean addCounters(Counter counter, Ability source, Game game);
|
||||
|
||||
boolean addCounters(Counter counter, Ability source, Game game, boolean isEffect);
|
||||
|
|
@ -148,8 +149,8 @@ public interface Card extends MageObject {
|
|||
Card copy();
|
||||
|
||||
/**
|
||||
* @return The main card of a split half card or adventure spell card, otherwise the card itself is
|
||||
* returned
|
||||
* @return The main card of a split half card or adventure spell card,
|
||||
* otherwise the card itself is returned
|
||||
*/
|
||||
Card getMainCard();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
package mage.cards;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectImpl;
|
||||
import mage.Mana;
|
||||
|
|
@ -26,13 +32,6 @@ import mage.util.SubTypeList;
|
|||
import mage.watchers.Watcher;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
@ -240,19 +239,12 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
@Override
|
||||
public List<String> getRules(Game game) {
|
||||
try {
|
||||
List<String> rules = getRules();
|
||||
List<String> rules = getAbilities(game).getRules(getName());
|
||||
if (game != null) {
|
||||
// debug state
|
||||
CardState cardState = game.getState().getCardState(objectId);
|
||||
if (cardState != null) {
|
||||
for (String data : cardState.getInfo().values()) {
|
||||
rules.add(data);
|
||||
}
|
||||
for (Ability ability : cardState.getAbilities()) {
|
||||
rules.add(ability.getRule());
|
||||
}
|
||||
for (String data : game.getState().getCardState(objectId).getInfo().values()) {
|
||||
rules.add(data);
|
||||
}
|
||||
|
||||
// ability hints
|
||||
List<String> abilityHints = new ArrayList<>();
|
||||
if (HintUtils.ABILITY_HINTS_ENABLE) {
|
||||
|
|
@ -267,7 +259,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
}
|
||||
|
||||
// restrict hints only for permanents, not cards
|
||||
|
||||
// total hints
|
||||
if (!abilityHints.isEmpty()) {
|
||||
rules.add(HintUtils.HINT_START_MARK);
|
||||
|
|
@ -301,21 +292,31 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
*/
|
||||
@Override
|
||||
public Abilities<Ability> getAbilities(Game game) {
|
||||
Abilities<Ability> otherAbilities = game.getState().getAllOtherAbilities(objectId);
|
||||
if (otherAbilities == null || otherAbilities.isEmpty()) {
|
||||
CardState cardState = game.getState().getCardState(this.getId());
|
||||
if (!cardState.hasLostAllAbilities() && (cardState.getAbilities() == null || cardState.getAbilities().isEmpty())) {
|
||||
return abilities;
|
||||
}
|
||||
Abilities<Ability> all = new AbilitiesImpl<>();
|
||||
all.addAll(abilities);
|
||||
all.addAll(otherAbilities);
|
||||
if (!cardState.hasLostAllAbilities()) {
|
||||
all.addAll(abilities);
|
||||
}
|
||||
all.addAll(cardState.getAbilities());
|
||||
return all;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void looseAllAbilities(Game game) {
|
||||
CardState cardState = game.getState().getCardState(this.getId());
|
||||
cardState.setLostAllAbilities(true);
|
||||
cardState.getAbilities().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Public in order to support adding abilities to SplitCardHalf's
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
@Override
|
||||
public void addAbility(Ability ability) {
|
||||
ability.setSourceId(this.getId());
|
||||
abilities.add(ability);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ public class CardState implements Serializable {
|
|||
protected Map<String, String> info;
|
||||
protected Counters counters;
|
||||
protected Abilities<Ability> abilities;
|
||||
protected boolean lostAllAbilities;
|
||||
|
||||
private static final Map<String, String> emptyInfo = new HashMap<>();
|
||||
private static final Abilities<Ability> emptyAbilities = new AbilitiesImpl<>();
|
||||
|
|
@ -39,6 +40,7 @@ public class CardState implements Serializable {
|
|||
abilities.add(ability.copy());
|
||||
}
|
||||
}
|
||||
this.lostAllAbilities = state.lostAllAbilities;
|
||||
}
|
||||
|
||||
public CardState copy() {
|
||||
|
|
@ -90,20 +92,29 @@ public class CardState implements Serializable {
|
|||
abilities.addAll(ability.getSubAbilities());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from applyEffects reset, to reset all layered effects
|
||||
*/
|
||||
public void clearAbilities() {
|
||||
if (abilities != null) {
|
||||
// for (Ability ability: abilities) { // Causes problems if temporary (gained) continuous effects are removed
|
||||
// ability.setSourceId(null);
|
||||
// ability.setControllerId(null);
|
||||
// }
|
||||
abilities = null;
|
||||
}
|
||||
setLostAllAbilities(false);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
counters.clear();
|
||||
info = null;
|
||||
clearAbilities();
|
||||
lostAllAbilities = false;
|
||||
}
|
||||
|
||||
public boolean hasLostAllAbilities() {
|
||||
return lostAllAbilities;
|
||||
}
|
||||
|
||||
public void setLostAllAbilities(boolean lostAllAbilities) {
|
||||
this.lostAllAbilities = lostAllAbilities;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
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;
|
||||
|
|
@ -34,10 +37,6 @@ import mage.util.ThreadLocalStringBuilder;
|
|||
import mage.watchers.Watcher;
|
||||
import mage.watchers.Watchers;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
* <p>
|
||||
|
|
@ -602,7 +601,6 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
// public void addMessage(String message) {
|
||||
// this.messages.add(message);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns a list of all players of the game ignoring range or if a player
|
||||
* has lost or left the game.
|
||||
|
|
@ -636,8 +634,9 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
* also setting the playerId to the first/current player of the list. Also
|
||||
* returning the other players in turn order.
|
||||
* <p>
|
||||
* Not safe for continuous effects, see rule 800.4k (effects must work until end of turn even after player leaves)
|
||||
* Use Player.InRange() to find active players list at the start of the turn
|
||||
* Not safe for continuous effects, see rule 800.4k (effects must work until
|
||||
* end of turn even after player leaves) Use Player.InRange() to find active
|
||||
* players list at the start of the turn
|
||||
*
|
||||
* @param playerId
|
||||
* @param game
|
||||
|
|
@ -775,7 +774,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
for (Map.Entry<ZoneChangeData, List<GameEvent>> entry : eventsByKey.entrySet()) {
|
||||
Set<Card> movedCards = new LinkedHashSet<>();
|
||||
Set<PermanentToken> movedTokens = new LinkedHashSet<>();
|
||||
for (Iterator<GameEvent> it = entry.getValue().iterator(); it.hasNext(); ) {
|
||||
for (Iterator<GameEvent> it = entry.getValue().iterator(); it.hasNext();) {
|
||||
GameEvent event = it.next();
|
||||
ZoneChangeEvent castEvent = (ZoneChangeEvent) event;
|
||||
UUID targetId = castEvent.getTargetId();
|
||||
|
|
@ -1008,7 +1007,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
* @param attachedTo
|
||||
* @param ability
|
||||
* @param copyAbility copies non MageSingleton abilities before adding to
|
||||
* state
|
||||
* state
|
||||
*/
|
||||
public void addOtherAbility(Card attachedTo, Ability ability, boolean copyAbility) {
|
||||
Ability newAbility;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package mage.game.stack;
|
||||
|
||||
import java.util.*;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
|
|
@ -31,8 +32,6 @@ import mage.players.Player;
|
|||
import mage.util.GameLog;
|
||||
import mage.util.SubTypeList;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
|
@ -1045,4 +1044,9 @@ public class Spell extends StackObjImpl implements Card {
|
|||
return commandedBy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void looseAllAbilities(Game game) {
|
||||
throw new UnsupportedOperationException("Spells should not loose all abilities. Check if this operation is correct.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue