mirror of
https://github.com/correl/mage.git
synced 2024-11-15 03:00:16 +00:00
* Library of Leng - fixed that it triggers on discarded cards from cost part instead only effect part (#3047);
This commit is contained in:
parent
d6c99437f3
commit
79d40754ed
3 changed files with 57 additions and 41 deletions
|
@ -1,17 +1,11 @@
|
|||
|
||||
package mage.cards.l;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.cards.*;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
|
@ -22,14 +16,15 @@ import mage.game.events.GameEvent.EventType;
|
|||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public final class LibraryOfLeng extends CardImpl {
|
||||
|
||||
public LibraryOfLeng(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}");
|
||||
|
||||
// You have no maximum hand size.
|
||||
Effect effect = new MaximumHandSizeControllerEffect(Integer.MAX_VALUE, Duration.WhileOnBattlefield, MaximumHandSizeControllerEffect.HandSizeModification.SET);
|
||||
|
@ -79,14 +74,15 @@ class LibraryOfLengEffect extends ReplacementEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (event.getType() == EventType.DISCARD_CARD) {
|
||||
// rules:
|
||||
// You can’t use the Library of Leng ability to place a discarded card on top of your library when you discard a card as a cost,
|
||||
// because costs aren’t effects. (2004-10-04)
|
||||
if (event.getType() == EventType.DISCARD_CARD && event.getFlag()) {
|
||||
return event.getPlayerId().equals(source.getControllerId());
|
||||
}
|
||||
if (event.getType() == EventType.ZONE_CHANGE) {
|
||||
if (event.getTargetId().equals(cardId) && game.getState().getZoneChangeCounter(event.getTargetId()) == zoneChangeCounter) {
|
||||
if (((ZoneChangeEvent) event).getFromZone() == Zone.HAND && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD) {
|
||||
return true;
|
||||
}
|
||||
return ((ZoneChangeEvent) event).getFromZone() == Zone.HAND && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -21,6 +21,7 @@ public class GameEvent implements Serializable {
|
|||
// flags:
|
||||
// for counters: event is result of effect (+1 from planeswalkers is cost, not effect)
|
||||
// for combat damage: event is preventable damage
|
||||
// for discard: event is result of effect (1) or result of cost (0)
|
||||
protected boolean flag;
|
||||
protected String data;
|
||||
protected Zone zone;
|
||||
|
|
|
@ -792,20 +792,23 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
about the discarded card, that cost payment is illegal; the game returns to
|
||||
the moment before the cost was paid (see rule 717, "Handling Illegal Actions").
|
||||
*/
|
||||
if (card != null
|
||||
&& !game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DISCARD_CARD, card.getId(), source == null ? null : source.getSourceId(), playerId), source)) {
|
||||
// write info to game log first so game log infos from triggered or replacement effects follow in the game log
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(getLogName() + " discards " + card.getLogName());
|
||||
if (card != null) {
|
||||
GameEvent gameEvent = GameEvent.getEvent(GameEvent.EventType.DISCARD_CARD, card.getId(), source == null ? null : source.getSourceId(), playerId);
|
||||
gameEvent.setFlag(source != null); // event from effect or from cost (source == null)
|
||||
if (!game.replaceEvent(gameEvent, source)) {
|
||||
// write info to game log first so game log infos from triggered or replacement effects follow in the game log
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(getLogName() + " discards " + card.getLogName());
|
||||
}
|
||||
/* If a card is discarded while Rest in Peace is on the battlefield, abilities that function
|
||||
* when a card is discarded (such as madness) still work, even though that card never reaches
|
||||
* a graveyard. In addition, spells or abilities that check the characteristics of a discarded
|
||||
* card (such as Chandra Ablaze's first ability) can find that card in exile. */
|
||||
card.moveToZone(Zone.GRAVEYARD, source == null ? null : source.getSourceId(), game, false);
|
||||
// So discard is also successful if card is moved to another zone by replacement effect!
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DISCARDED_CARD, card.getId(), source == null ? null : source.getSourceId(), playerId));
|
||||
return true;
|
||||
}
|
||||
/* If a card is discarded while Rest in Peace is on the battlefield, abilities that function
|
||||
* when a card is discarded (such as madness) still work, even though that card never reaches
|
||||
* a graveyard. In addition, spells or abilities that check the characteristics of a discarded
|
||||
* card (such as Chandra Ablaze's first ability) can find that card in exile. */
|
||||
card.moveToZone(Zone.GRAVEYARD, source == null ? null : source.getSourceId(), game, false);
|
||||
// So discard is also successful if card is moved to another zone by replacement effect!
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DISCARDED_CARD, card.getId(), source == null ? null : source.getSourceId(), playerId));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1014,7 +1017,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setCastSourceIdWithAlternateMana(UUID sourceId, ManaCosts<ManaCost> manaCosts, Costs<Cost> costs) {
|
||||
public void setCastSourceIdWithAlternateMana(UUID
|
||||
sourceId, ManaCosts<ManaCost> manaCosts, Costs<Cost> costs) {
|
||||
castSourceIdWithAlternateMana = sourceId;
|
||||
castSourceIdManaCosts = manaCosts;
|
||||
castSourceIdCosts = costs;
|
||||
|
@ -1046,7 +1050,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, MageObjectReference reference) {
|
||||
public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, MageObjectReference
|
||||
reference) {
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1063,7 +1068,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(SpellAbility originalAbility, Game game, boolean noMana, MageObjectReference permittingObject) {
|
||||
public boolean cast(SpellAbility originalAbility, Game game, boolean noMana, MageObjectReference
|
||||
permittingObject) {
|
||||
if (game == null || originalAbility == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1426,7 +1432,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
// Get the usable activated abilities for a *single card object*, that is, either a card or half of a split card.
|
||||
// Also called on the whole split card but only passing the fuse ability and other whole-split-card shared abilities
|
||||
// as candidates.
|
||||
private void getUseableActivatedAbilitiesHalfImpl(MageObject object, Zone zone, Game game, Abilities<Ability> candidateAbilites, LinkedHashMap<UUID, ActivatedAbility> output) {
|
||||
private void getUseableActivatedAbilitiesHalfImpl(MageObject object, Zone zone, Game
|
||||
game, Abilities<Ability> candidateAbilites, LinkedHashMap<UUID, ActivatedAbility> output) {
|
||||
boolean canUse = !(object instanceof Permanent) || ((Permanent) object).canUseActivatedAbilities(game);
|
||||
ManaOptions availableMana = null;
|
||||
// ManaOptions availableMana = getManaAvailable(game); // can only be activated if mana calculation works flawless otherwise player can't play spells they could play if calculation would work correctly
|
||||
|
@ -1496,7 +1503,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public LinkedHashMap<UUID, ActivatedAbility> getUseableActivatedAbilities(MageObject object, Zone zone, Game game) {
|
||||
public LinkedHashMap<UUID, ActivatedAbility> getUseableActivatedAbilities(MageObject object, Zone zone, Game
|
||||
game) {
|
||||
LinkedHashMap<UUID, ActivatedAbility> useable = new LinkedHashMap<>();
|
||||
if (object instanceof StackAbility) { // It may not be possible to activate abilities of stack abilities
|
||||
return useable;
|
||||
|
@ -1515,7 +1523,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
// Adds special abilities that are given to non permanents by continuous effects
|
||||
private void getOtherUseableActivatedAbilities(MageObject object, Zone zone, Game game, Map<UUID, ActivatedAbility> useable) {
|
||||
private void getOtherUseableActivatedAbilities(MageObject object, Zone zone, Game
|
||||
game, Map<UUID, ActivatedAbility> useable) {
|
||||
Abilities<ActivatedAbility> otherAbilities = game.getState().getActivatedOtherAbilities(object.getId(), zone);
|
||||
if (otherAbilities != null) {
|
||||
boolean canUse = !(object instanceof Permanent) || ((Permanent) object).canUseActivatedAbilities(game);
|
||||
|
@ -1561,7 +1570,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
protected LinkedHashMap<UUID, ActivatedManaAbilityImpl> getUseableManaAbilities(MageObject object, Zone zone, Game game) {
|
||||
protected LinkedHashMap<UUID, ActivatedManaAbilityImpl> getUseableManaAbilities(MageObject object, Zone
|
||||
zone, Game game) {
|
||||
LinkedHashMap<UUID, ActivatedManaAbilityImpl> useable = new LinkedHashMap<>();
|
||||
boolean canUse = !(object instanceof Permanent) || ((Permanent) object).canUseActivatedAbilities(game);
|
||||
for (ActivatedManaAbilityImpl ability : object.getAbilities().getActivatedManaAbilities(zone)) {
|
||||
|
@ -1813,7 +1823,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
private List<Permanent> getPermanentsThatCanBeUntapped(Game game, List<Permanent> canBeUntapped, RestrictionUntapNotMoreThanEffect handledEffect, Map<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> notMoreThanEffectsUsage) {
|
||||
private List<Permanent> getPermanentsThatCanBeUntapped(Game
|
||||
game, List<Permanent> canBeUntapped, RestrictionUntapNotMoreThanEffect
|
||||
handledEffect, Map<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> notMoreThanEffectsUsage) {
|
||||
List<Permanent> leftForUntap = new ArrayList<>();
|
||||
// select permanents that can still be untapped
|
||||
for (Permanent permanent : canBeUntapped) {
|
||||
|
@ -1996,12 +2008,14 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List<UUID> appliedEffects) {
|
||||
public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List<
|
||||
UUID> appliedEffects) {
|
||||
return doDamage(damage, sourceId, game, combatDamage, preventable, appliedEffects);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"null", "ConstantConditions"})
|
||||
private int doDamage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List<UUID> appliedEffects) {
|
||||
private int doDamage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List<
|
||||
UUID> appliedEffects) {
|
||||
if (damage > 0) {
|
||||
if (canDamage(game.getObject(sourceId), game)) {
|
||||
GameEvent event = new DamagePlayerEvent(playerId, sourceId, playerId, damage, preventable, combatDamage);
|
||||
|
@ -2503,7 +2517,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId, boolean triggerEvents) {
|
||||
public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId,
|
||||
boolean triggerEvents) {
|
||||
//20091005 - 701.14c
|
||||
Library searchedLibrary = null;
|
||||
String searchInfo = null;
|
||||
|
@ -2745,7 +2760,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
* or NilRoll
|
||||
*/
|
||||
@Override
|
||||
public PlanarDieRoll rollPlanarDie(Game game, ArrayList<UUID> appliedEffects, int numberChaosSides, int numberPlanarSides) {
|
||||
public PlanarDieRoll rollPlanarDie(Game game, ArrayList<UUID> appliedEffects, int numberChaosSides,
|
||||
int numberPlanarSides) {
|
||||
int result = RandomUtil.nextInt(9) + 1;
|
||||
PlanarDieRoll roll = PlanarDieRoll.NIL_ROLL;
|
||||
if (numberChaosSides + numberPlanarSides > 9) {
|
||||
|
@ -2965,7 +2981,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected boolean canPlayCardByAlternateCost(Card sourceObject, ManaOptions available, Ability ability, Game game) {
|
||||
protected boolean canPlayCardByAlternateCost(Card sourceObject, ManaOptions available, Ability ability, Game
|
||||
game) {
|
||||
if (sourceObject != null && !(sourceObject instanceof Permanent)) {
|
||||
for (Ability alternateSourceCostsAbility : sourceObject.getAbilities()) {
|
||||
// if cast for noMana no Alternative costs are allowed
|
||||
|
@ -3029,7 +3046,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected boolean canLandPlayAlternateSourceCostsAbility(Card sourceObject, ManaOptions available, Ability ability, Game game) {
|
||||
protected boolean canLandPlayAlternateSourceCostsAbility(Card sourceObject, ManaOptions available, Ability
|
||||
ability, Game game) {
|
||||
if (!(sourceObject instanceof Permanent)) {
|
||||
Ability sourceAbility = null;
|
||||
for (Ability landAbility : sourceObject.getAbilities()) {
|
||||
|
@ -3064,7 +3082,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void getPlayableFromGraveyardCard(Game game, Card card, Abilities<Ability> candidateAbilities, ManaOptions availableMana, List<Ability> output) {
|
||||
private void getPlayableFromGraveyardCard(Game game, Card
|
||||
card, Abilities<Ability> candidateAbilities, ManaOptions availableMana, List<Ability> output) {
|
||||
MageObjectReference permittingObject = game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, card.getSpellAbility(), this.getId(), game);
|
||||
for (ActivatedAbility ability : candidateAbilities.getActivatedAbilities(Zone.ALL)) {
|
||||
boolean possible = false;
|
||||
|
|
Loading…
Reference in a new issue