mirror of
https://github.com/correl/mage.git
synced 2025-01-12 03:00:13 +00:00
Merge branch 'master' of https://github.com/magefree/mage
This commit is contained in:
commit
4928c52204
8 changed files with 275 additions and 16 deletions
|
@ -1,7 +1,6 @@
|
|||
package mage.cards.f;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.abilities.common.BecomesTargetTriggeredAbility;
|
||||
|
@ -15,13 +14,11 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterSpell;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
|
@ -32,7 +29,6 @@ public final class ForceProjection extends CardImpl {
|
|||
|
||||
public ForceProjection(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}{U}");
|
||||
|
||||
|
||||
// Create a token that is a copy of target creature you control except that it is an Illusion in addition to its other types and gains "When this creature becomes the target of a spell, sacrifice it."
|
||||
this.getSpellAbility().addEffect(new ForceProjectionEffect());
|
||||
|
@ -56,8 +52,8 @@ class ForceProjectionEffect extends OneShotEffect {
|
|||
|
||||
public ForceProjectionEffect() {
|
||||
super(Outcome.Copy);
|
||||
this.staticText = "Create a token that is a copy of target creature you control except that it is an Illusion " +
|
||||
"in addition to its other types and gains \"When this creature becomes the target of a spell, sacrifice it.\"";
|
||||
this.staticText = "Create a token that is a copy of target creature you control except that it is an Illusion "
|
||||
+ "in addition to its other types and gains \"When this creature becomes the target of a spell, sacrifice it.\"";
|
||||
}
|
||||
|
||||
public ForceProjectionEffect(final ForceProjectionEffect effect) {
|
||||
|
|
260
Mage.Sets/src/mage/cards/t/ThiefOfSanity.java
Normal file
260
Mage.Sets/src/mage/cards/t/ThiefOfSanity.java
Normal file
|
@ -0,0 +1,260 @@
|
|||
package mage.cards.t;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.AsThoughManaEffect;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.ExileZone;
|
||||
import mage.game.Game;
|
||||
import mage.players.ManaPoolItem;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public final class ThiefOfSanity extends CardImpl {
|
||||
|
||||
protected static final String VALUE_PREFIX = "ExileZones";
|
||||
|
||||
public ThiefOfSanity(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}");
|
||||
|
||||
this.subtype.add(SubType.SPECTER);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// Whenever Thief of Sanity deals combat damage to a player, look at the top three cards of that player's library, exile one of them face down, then put the rest into their graveyard. For as long as that card remains exiled, you may look at it, you may cast it, and you may spend mana as though it were mana of any type to cast it.
|
||||
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ThiefOfSanityEffect(), false, true));
|
||||
|
||||
Ability ability = new SimpleStaticAbility(Zone.ALL, new ThiefOfSanityLookEffect());
|
||||
ability.setRuleVisible(false);
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public ThiefOfSanity(final ThiefOfSanity card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThiefOfSanity copy() {
|
||||
return new ThiefOfSanity(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ThiefOfSanityEffect extends OneShotEffect {
|
||||
|
||||
public ThiefOfSanityEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "look at the top three cards of that player's library, exile one of them face down, then put the rest into their graveyard. For as long as that card remains exiled, you may look at it, you may cast it, and you may spend mana as though it were mana of any type to cast it";
|
||||
}
|
||||
|
||||
public ThiefOfSanityEffect(final ThiefOfSanityEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThiefOfSanityEffect copy() {
|
||||
return new ThiefOfSanityEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Player damagedPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (controller != null && damagedPlayer != null && sourceObject != null) {
|
||||
Cards topCards = new CardsImpl();
|
||||
topCards.addAll(damagedPlayer.getLibrary().getTopCards(game, 3));
|
||||
TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to exile face down"));
|
||||
if (controller.choose(outcome, topCards, target, game)) {
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
topCards.remove(card);
|
||||
// move card to exile
|
||||
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||
card.setFaceDown(true, game);
|
||||
if (controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName())) {
|
||||
card.setFaceDown(true, game);
|
||||
Set<UUID> exileZones = (Set<UUID>) game.getState().getValue(ThiefOfSanity.VALUE_PREFIX + source.getSourceId().toString());
|
||||
if (exileZones == null) {
|
||||
exileZones = new HashSet<>();
|
||||
game.getState().setValue(ThiefOfSanity.VALUE_PREFIX + source.getSourceId().toString(), exileZones);
|
||||
}
|
||||
exileZones.add(exileZoneId);
|
||||
// allow to cast the card
|
||||
ContinuousEffect effect = new ThiefOfSanityCastFromExileEffect();
|
||||
effect.setTargetPointer(new FixedTarget(card.getId(), game));
|
||||
game.addEffect(effect, source);
|
||||
// and you may spend mana as though it were mana of any color to cast it
|
||||
effect = new ThiefOfSanitySpendAnyManaEffect();
|
||||
effect.setTargetPointer(new FixedTarget(card.getId(), game));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
// put the rest into their graveyard
|
||||
controller.moveCards(topCards, Zone.GRAVEYARD, source, game);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class ThiefOfSanityCastFromExileEffect extends AsThoughEffectImpl {
|
||||
|
||||
public ThiefOfSanityCastFromExileEffect() {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit);
|
||||
staticText = "You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast that spell";
|
||||
}
|
||||
|
||||
public ThiefOfSanityCastFromExileEffect(final ThiefOfSanityCastFromExileEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThiefOfSanityCastFromExileEffect copy() {
|
||||
return new ThiefOfSanityCastFromExileEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
UUID targetId = getTargetPointer().getFirst(game, source);
|
||||
if (targetId == null) {
|
||||
this.discard();
|
||||
} else if (objectId.equals(targetId)
|
||||
&& affectedControllerId.equals(source.getControllerId())) {
|
||||
Card card = game.getCard(objectId);
|
||||
// TODO: Allow to cast Zoetic Cavern face down
|
||||
return card != null && !card.isLand();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class ThiefOfSanitySpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect {
|
||||
|
||||
public ThiefOfSanitySpendAnyManaEffect() {
|
||||
super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.Custom, Outcome.Benefit);
|
||||
staticText = "you may spend mana as though it were mana of any color to cast it";
|
||||
}
|
||||
|
||||
public ThiefOfSanitySpendAnyManaEffect(final ThiefOfSanitySpendAnyManaEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThiefOfSanitySpendAnyManaEffect copy() {
|
||||
return new ThiefOfSanitySpendAnyManaEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
if (objectId.equals(((FixedTarget) getTargetPointer()).getTarget())
|
||||
&& game.getState().getZoneChangeCounter(objectId) <= ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) {
|
||||
|
||||
if (affectedControllerId.equals(source.getControllerId())) {
|
||||
// if the card moved from exile to spell the zone change counter is increased by 1
|
||||
if (game.getState().getZoneChangeCounter(objectId) == ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (((FixedTarget) getTargetPointer()).getTarget().equals(objectId)) {
|
||||
// object has moved zone so effect can be discarted
|
||||
this.discard();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) {
|
||||
return mana.getFirstAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
class ThiefOfSanityLookEffect extends AsThoughEffectImpl {
|
||||
|
||||
public ThiefOfSanityLookEffect() {
|
||||
super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit);
|
||||
staticText = "You may look at the cards exiled with {this}";
|
||||
}
|
||||
|
||||
public ThiefOfSanityLookEffect(final ThiefOfSanityLookEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThiefOfSanityLookEffect copy() {
|
||||
return new ThiefOfSanityLookEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
if (affectedControllerId.equals(source.getControllerId()) && game.getState().getZone(objectId) == Zone.EXILED) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (controller != null && sourceObject != null) {
|
||||
Card card = game.getCard(objectId);
|
||||
if (card != null && card.isFaceDown(game)) {
|
||||
Set<UUID> exileZones = (Set<UUID>) game.getState().getValue(ThiefOfSanity.VALUE_PREFIX + source.getSourceId().toString());
|
||||
if (exileZones != null) {
|
||||
for (ExileZone exileZone : game.getExile().getExileZones()) {
|
||||
if (exileZone.contains(objectId)) {
|
||||
if (!exileZones.contains(exileZone.getId())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -259,6 +259,7 @@ public final class GuildsOfRavnica extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Take Heart", 28, Rarity.COMMON, mage.cards.t.TakeHeart.class));
|
||||
cards.add(new SetCardInfo("Temple Garden", 258, Rarity.RARE, mage.cards.t.TempleGarden.class));
|
||||
cards.add(new SetCardInfo("Tenth District Guard", 29, Rarity.COMMON, mage.cards.t.TenthDistrictGuard.class));
|
||||
cards.add(new SetCardInfo("Thief of Sanity", 205, Rarity.RARE, mage.cards.t.ThiefOfSanity.class));
|
||||
cards.add(new SetCardInfo("Thought Erasure", 206, Rarity.UNCOMMON, mage.cards.t.ThoughtErasure.class));
|
||||
cards.add(new SetCardInfo("Thoughtbound Phantasm", 55, Rarity.UNCOMMON, mage.cards.t.ThoughtboundPhantasm.class));
|
||||
cards.add(new SetCardInfo("Torch Courier", 119, Rarity.COMMON, mage.cards.t.TorchCourier.class));
|
||||
|
|
|
@ -12,7 +12,7 @@ import mage.game.Game;
|
|||
*/
|
||||
public interface AsThoughEffect extends ContinuousEffect {
|
||||
|
||||
boolean applies(UUID sourceId, Ability affectedAbility, Ability source, Game game);
|
||||
boolean applies(UUID sourceId, Ability affectedAbility, Ability source, Game game, UUID playerId);
|
||||
|
||||
boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game);
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.effects;
|
||||
|
||||
import java.util.UUID;
|
||||
|
@ -29,8 +28,12 @@ public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game) {
|
||||
return applies(objectId, source, affectedAbility.getControllerId(), game);
|
||||
public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) {
|
||||
if (getAsThoughEffectType().equals(AsThoughEffectType.LOOK_AT_FACE_DOWN)) {
|
||||
return applies(objectId, source, playerId, game);
|
||||
} else {
|
||||
return applies(objectId, source, affectedAbility.getControllerId(), game);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.effects;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
@ -496,7 +495,7 @@ public class ContinuousEffects implements Serializable {
|
|||
if (effect.applies(objectId, ability, controllerId, game)) {
|
||||
return new MageObjectReference(ability.getSourceObject(game), game);
|
||||
}
|
||||
} else if (effect.applies(objectId, affectedAbility, ability, game)) {
|
||||
} else if (effect.applies(objectId, affectedAbility, ability, game, controllerId)) {
|
||||
return new MageObjectReference(ability.getSourceObject(game), game);
|
||||
}
|
||||
}
|
||||
|
@ -512,7 +511,7 @@ public class ContinuousEffects implements Serializable {
|
|||
Set<Ability> abilities = asThoughEffectsMap.get(AsThoughEffectType.SPEND_ONLY_MANA).getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
if ((affectedAbility == null && effect.applies(objectId, ability, controllerId, game))
|
||||
|| effect.applies(objectId, affectedAbility, ability, game)) {
|
||||
|| effect.applies(objectId, affectedAbility, ability, game, controllerId)) {
|
||||
if (((AsThoughManaEffect) effect).getAsThoughManaType(manaType, mana, controllerId, ability, game) == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -525,7 +524,7 @@ public class ContinuousEffects implements Serializable {
|
|||
Set<Ability> abilities = asThoughEffectsMap.get(AsThoughEffectType.SPEND_OTHER_MANA).getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
if ((affectedAbility == null && effect.applies(objectId, ability, controllerId, game))
|
||||
|| effect.applies(objectId, affectedAbility, ability, game)) {
|
||||
|| effect.applies(objectId, affectedAbility, ability, game, controllerId)) {
|
||||
ManaType usableManaType = ((AsThoughManaEffect) effect).getAsThoughManaType(manaType, mana, controllerId, ability, game);
|
||||
if (usableManaType != null) {
|
||||
return usableManaType;
|
||||
|
|
|
@ -43,7 +43,7 @@ public class ActivateAbilitiesAnyTimeYouCouldCastInstantEffect extends AsThoughE
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game) {
|
||||
public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) {
|
||||
return affectedAbility.isControlledBy(source.getControllerId())
|
||||
&& activatedAbility.isInstance(affectedAbility);
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID sourceId, Ability affectedAbility, Ability source, Game game) {
|
||||
public boolean applies(UUID sourceId, Ability affectedAbility, Ability source, Game game, UUID playerId) {
|
||||
if (sourceId.equals(source.getSourceId())) {
|
||||
Card card = game.getCard(sourceId);
|
||||
if (!card.isOwnedBy(source.getControllerId())) {
|
||||
|
|
Loading…
Reference in a new issue