mirror of
https://github.com/correl/mage.git
synced 2024-12-25 11:11:16 +00:00
Merge origin/master
This commit is contained in:
commit
f03ac0374d
17 changed files with 605 additions and 62 deletions
|
@ -106,6 +106,7 @@ class FeldonOfTheThirdPathEffect extends OneShotEffect {
|
||||||
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
||||||
if (card != null) {
|
if (card != null) {
|
||||||
EmptyToken token = new EmptyToken();
|
EmptyToken token = new EmptyToken();
|
||||||
|
// This fails if a card will be copied, that uses adjustTargets() method.
|
||||||
CardUtil.copyTo(token).from(card);
|
CardUtil.copyTo(token).from(card);
|
||||||
|
|
||||||
token.addAbility(HasteAbility.getInstance());
|
token.addAbility(HasteAbility.getInstance());
|
||||||
|
|
|
@ -28,15 +28,18 @@
|
||||||
package mage.sets.darkascension;
|
package mage.sets.darkascension;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import mage.abilities.Ability;
|
||||||
import mage.constants.AttachmentType;
|
import mage.constants.AttachmentType;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Rarity;
|
import mage.constants.Rarity;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.abilities.ActivatedAbilityImpl;
|
import mage.abilities.ActivatedAbilityImpl;
|
||||||
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.common.TapSourceCost;
|
import mage.abilities.costs.common.TapSourceCost;
|
||||||
import mage.abilities.costs.mana.GenericManaCost;
|
import mage.abilities.costs.mana.GenericManaCost;
|
||||||
|
import mage.abilities.effects.Effect;
|
||||||
import mage.abilities.effects.common.DamageTargetEffect;
|
import mage.abilities.effects.common.DamageTargetEffect;
|
||||||
import mage.abilities.effects.common.continious.GainAbilityAttachedEffect;
|
import mage.abilities.effects.common.continious.GainAbilityAttachedEffect;
|
||||||
import mage.abilities.keyword.EquipAbility;
|
import mage.abilities.keyword.EquipAbility;
|
||||||
|
@ -65,11 +68,20 @@ public class WolfhuntersQuiver extends CardImpl {
|
||||||
this.subtype.add("Equipment");
|
this.subtype.add("Equipment");
|
||||||
|
|
||||||
// Equipped creature has "{tap}: This creature deals 1 damage to target creature or player"
|
// Equipped creature has "{tap}: This creature deals 1 damage to target creature or player"
|
||||||
WolfhuntersQuiverAbility ability = new WolfhuntersQuiverAbility(1, new TargetCreatureOrPlayer());
|
Ability abilityToGain = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost());
|
||||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability, AttachmentType.EQUIPMENT)));
|
abilityToGain.addTarget(new TargetCreatureOrPlayer());
|
||||||
// and "{tap}: This creature deals 3 damage to target Werewolf creature."
|
Effect effect = new GainAbilityAttachedEffect(abilityToGain, AttachmentType.EQUIPMENT);
|
||||||
ability = new WolfhuntersQuiverAbility(3, new TargetCreaturePermanent(filter));
|
effect.setText("Equipped creature has \"{tap}: This creature deals 1 damage to target creature or player\"");
|
||||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability, AttachmentType.EQUIPMENT)));
|
SimpleStaticAbility ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect);
|
||||||
|
|
||||||
|
// and "{T}: This creature deals 3 damage to target Werewolf creature."
|
||||||
|
abilityToGain = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(3), new TapSourceCost());
|
||||||
|
abilityToGain.addTarget(new TargetCreaturePermanent(filter));
|
||||||
|
effect = new GainAbilityAttachedEffect(abilityToGain, AttachmentType.EQUIPMENT);
|
||||||
|
effect.setText("and \"{T}: This creature deals 3 damage to target Werewolf creature");
|
||||||
|
ability.addEffect(effect);
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Equip {5}
|
// Equip {5}
|
||||||
this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(5)));
|
this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(5)));
|
||||||
}
|
}
|
||||||
|
@ -83,30 +95,3 @@ public class WolfhuntersQuiver extends CardImpl {
|
||||||
return new WolfhuntersQuiver(this);
|
return new WolfhuntersQuiver(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WolfhuntersQuiverAbility extends ActivatedAbilityImpl {
|
|
||||||
|
|
||||||
private String ruleText;
|
|
||||||
|
|
||||||
public WolfhuntersQuiverAbility(int amount, Target target) {
|
|
||||||
super(Zone.BATTLEFIELD, new DamageTargetEffect(amount), new TapSourceCost());
|
|
||||||
this.addTarget(target);
|
|
||||||
|
|
||||||
ruleText = "This creature deals " + amount + " damage to target " + target.getTargetName();
|
|
||||||
}
|
|
||||||
|
|
||||||
public WolfhuntersQuiverAbility(WolfhuntersQuiverAbility ability) {
|
|
||||||
super(ability);
|
|
||||||
this.ruleText = ability.ruleText;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WolfhuntersQuiverAbility copy() {
|
|
||||||
return new WolfhuntersQuiverAbility(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getRule() {
|
|
||||||
return ruleText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ public class NecroticPlague extends CardImpl {
|
||||||
if (creatureController != null) {
|
if (creatureController != null) {
|
||||||
ability.setControllerId(creatureController.getId());
|
ability.setControllerId(creatureController.getId());
|
||||||
ability.getTargets().clear();
|
ability.getTargets().clear();
|
||||||
TargetCreaturePermanent target = new TargetCreaturePermanent(filter);
|
TargetPermanent target = new TargetPermanent(filter);
|
||||||
ability.getTargets().add(target);
|
ability.getTargets().add(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
78
Mage.Sets/src/mage/sets/shadowmoor/GleefulSabotage.java
Normal file
78
Mage.Sets/src/mage/sets/shadowmoor/GleefulSabotage.java
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* 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.sets.shadowmoor;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||||
|
import mage.abilities.keyword.ConspireAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
|
import mage.filter.FilterPermanent;
|
||||||
|
import mage.filter.predicate.Predicates;
|
||||||
|
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||||
|
import mage.target.TargetPermanent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jeffwadsworth
|
||||||
|
*/
|
||||||
|
public class GleefulSabotage extends CardImpl {
|
||||||
|
|
||||||
|
private static final FilterPermanent filter = new FilterPermanent("target artifact or enchantment");
|
||||||
|
|
||||||
|
static {
|
||||||
|
filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT),
|
||||||
|
(new CardTypePredicate(CardType.ENCHANTMENT))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public GleefulSabotage(UUID ownerId) {
|
||||||
|
super(ownerId, 116, "Gleeful Sabotage", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{1}{G}");
|
||||||
|
this.expansionSetCode = "SHM";
|
||||||
|
|
||||||
|
this.color.setGreen(true);
|
||||||
|
|
||||||
|
// Destroy target artifact or enchantment.
|
||||||
|
this.getSpellAbility().addEffect(new DestroyTargetEffect());
|
||||||
|
this.getSpellAbility().addTarget(new TargetPermanent(filter));
|
||||||
|
|
||||||
|
// Conspire
|
||||||
|
this.addAbility(new ConspireAbility(this));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public GleefulSabotage(final GleefulSabotage card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GleefulSabotage copy() {
|
||||||
|
return new GleefulSabotage(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* 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 org.mage.test.cards.abilities.enters;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
public class SepulchralPrimordialTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testETB2Effect() {
|
||||||
|
// When Sepulchral Primordial enters the battlefield, for each opponent, you may put up to one
|
||||||
|
// target creature card from that player's graveyard onto the battlefield under your control.
|
||||||
|
addCard(Zone.HAND, playerA, "Sepulchral Primordial", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 7);
|
||||||
|
|
||||||
|
addCard(Zone.GRAVEYARD, playerB, "Silvercoat Lion", 1);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sepulchral Primordial");
|
||||||
|
addTarget(playerA, "Silvercoat Lion"); // target for ETB Sepulchral Primordial
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Sepulchral Primordial", 1);
|
||||||
|
assertPermanentCount(playerA, "Silvercoat Lion", 1);
|
||||||
|
|
||||||
|
assertLife(playerA, 20);
|
||||||
|
assertLife(playerB, 20);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 org.mage.test.cards.copy;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the funtions of Feldon of the Third Path - {1}{R}{R} Legendary Creature
|
||||||
|
* - Human Artificer 2/3 {2}{R}, {T} : Put a token onto the battlefield that's a
|
||||||
|
* copy of target creature card in your graveyard, except it's an artifact in
|
||||||
|
* addition to its other types. It gains haste. Sacrifice it at the beginning of
|
||||||
|
* the next end step.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
public class FeldonOfTheThirdPathTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checking that enters the battlefield abilities of the copied creature
|
||||||
|
* card works.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testETBEffect() {
|
||||||
|
// When Highway Robber enters the battlefield, target opponent loses 2 life and you gain 2 life.
|
||||||
|
addCard(Zone.GRAVEYARD, playerA, "Highway Robber", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Feldon of the Third Path", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||||
|
|
||||||
|
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA,
|
||||||
|
"{2}{R},{T}: Put a token onto the battlefield that's a copy of target creature card in your graveyard, except it's an artifact in addition to its other types. It gains haste. Sacrifice it at the beginning of the next end step.",
|
||||||
|
"Highway Robber");
|
||||||
|
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Highway Robber", 1);
|
||||||
|
assertPermanentCount(playerA, "Feldon of the Third Path", 1);
|
||||||
|
|
||||||
|
assertLife(playerA, 22); // +2 from Robber
|
||||||
|
assertLife(playerB, 18); // -2 from Robber
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testETB2Effect() {
|
||||||
|
// When Sepulchral Primordial enters the battlefield, for each opponent, you may put up to one
|
||||||
|
// target creature card from that player's graveyard onto the battlefield under your control.
|
||||||
|
addCard(Zone.GRAVEYARD, playerA, "Sepulchral Primordial", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Feldon of the Third Path", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||||
|
|
||||||
|
addCard(Zone.GRAVEYARD, playerB, "Silvercoat Lion", 1);
|
||||||
|
|
||||||
|
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA,
|
||||||
|
"{2}{R},{T}: Put a token onto the battlefield that's a copy of target creature card in your graveyard, except it's an artifact in addition to its other types. It gains haste. Sacrifice it at the beginning of the next end step.",
|
||||||
|
"Sepulchral Primordial");
|
||||||
|
addTarget(playerA, "Silvercoat Lion"); // target for ETB Sepulchral Primordial
|
||||||
|
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Feldon of the Third Path", 1);
|
||||||
|
assertPermanentCount(playerA, "Sepulchral Primordial", 1);
|
||||||
|
assertPermanentCount(playerA, "Silvercoat Lion", 1);
|
||||||
|
|
||||||
|
assertLife(playerA, 20);
|
||||||
|
assertLife(playerB, 20);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -277,7 +277,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
// and/or zones become the target of a spell trigger at this point; they'll wait to be put on
|
// and/or zones become the target of a spell trigger at this point; they'll wait to be put on
|
||||||
// the stack until the spell has finished being cast.)
|
// the stack until the spell has finished being cast.)
|
||||||
|
|
||||||
if (sourceObject != null) {
|
if (sourceObject != null && !this.getAbilityType().equals(AbilityType.TRIGGERED)) { // triggered abilities check this already TriggeredAbilities.checkTriggers()
|
||||||
sourceObject.adjustTargets(this, game);
|
sourceObject.adjustTargets(this, game);
|
||||||
}
|
}
|
||||||
if (getTargets().size() > 0 && getTargets().chooseTargets(getEffects().get(0).getOutcome(), this.controllerId, this, game) == false) {
|
if (getTargets().size() > 0 && getTargets().chooseTargets(getEffects().get(0).getOutcome(), this.controllerId, this, game) == false) {
|
||||||
|
|
|
@ -44,7 +44,6 @@ import mage.game.events.GameEvent;
|
||||||
import mage.game.events.GameEvent.EventType;
|
import mage.game.events.GameEvent.EventType;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.permanent.PermanentCard;
|
import mage.game.permanent.PermanentCard;
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
|
@ -72,7 +72,7 @@ public class LimitedTimesPerTurnActivatedAbility extends ActivatedAbilityImpl {
|
||||||
@Override
|
@Override
|
||||||
public boolean canActivate(UUID playerId, Game game) {
|
public boolean canActivate(UUID playerId, Game game) {
|
||||||
if (super.canActivate(playerId, game)) {
|
if (super.canActivate(playerId, game)) {
|
||||||
ActivationInfo activationInfo = (ActivationInfo) game.getState().getValue(CardUtil.getCardZoneString("activations", sourceId, game));
|
ActivationInfo activationInfo = getActivationInfo(game);
|
||||||
return activationInfo == null || activationInfo.turnNum != game.getTurnNum() || activationInfo.activationCounter < maxActivationsPerTurn;
|
return activationInfo == null || activationInfo.turnNum != game.getTurnNum() || activationInfo.activationCounter < maxActivationsPerTurn;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -82,7 +82,7 @@ public class LimitedTimesPerTurnActivatedAbility extends ActivatedAbilityImpl {
|
||||||
public boolean activate(Game game, boolean noMana) {
|
public boolean activate(Game game, boolean noMana) {
|
||||||
if (canActivate(this.controllerId, game)) {
|
if (canActivate(this.controllerId, game)) {
|
||||||
if (super.activate(game, noMana)) {
|
if (super.activate(game, noMana)) {
|
||||||
ActivationInfo activationInfo = (ActivationInfo) game.getState().getValue(CardUtil.getCardZoneString("activations", sourceId, game));
|
ActivationInfo activationInfo = getActivationInfo(game);
|
||||||
if (activationInfo == null) {
|
if (activationInfo == null) {
|
||||||
activationInfo = new ActivationInfo(game.getTurnNum(), 1);
|
activationInfo = new ActivationInfo(game.getTurnNum(), 1);
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,7 +93,7 @@ public class LimitedTimesPerTurnActivatedAbility extends ActivatedAbilityImpl {
|
||||||
activationInfo.activationCounter++;
|
activationInfo.activationCounter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
game.getState().setValue(CardUtil.getCardZoneString("activations", sourceId, game), activationInfo);
|
setActivationInfo(activationInfo, game);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,5 +126,17 @@ public class LimitedTimesPerTurnActivatedAbility extends ActivatedAbilityImpl {
|
||||||
public LimitedTimesPerTurnActivatedAbility copy() {
|
public LimitedTimesPerTurnActivatedAbility copy() {
|
||||||
return new LimitedTimesPerTurnActivatedAbility(this);
|
return new LimitedTimesPerTurnActivatedAbility(this);
|
||||||
}
|
}
|
||||||
|
private ActivationInfo getActivationInfo(Game game) {
|
||||||
|
Integer turnNum = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsTurn", sourceId, game));
|
||||||
|
Integer activationCount = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsCount", sourceId, game));
|
||||||
|
if (turnNum == null || activationCount == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ActivationInfo(turnNum, activationCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setActivationInfo(ActivationInfo activationInfo, Game game) {
|
||||||
|
game.getState().setValue(CardUtil.getCardZoneString("activationsTurn", sourceId, game), activationInfo.turnNum);
|
||||||
|
game.getState().setValue(CardUtil.getCardZoneString("activationsCount", sourceId, game), activationInfo.activationCounter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
256
Mage/src/mage/abilities/keyword/ConspireAbility.java
Normal file
256
Mage/src/mage/abilities/keyword/ConspireAbility.java
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
/*
|
||||||
|
* 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.keyword;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.SpellAbility;
|
||||||
|
import mage.abilities.StaticAbility;
|
||||||
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
|
import mage.abilities.costs.Cost;
|
||||||
|
import mage.abilities.costs.Costs;
|
||||||
|
import mage.abilities.costs.OptionalAdditionalCost;
|
||||||
|
import mage.abilities.costs.OptionalAdditionalCostImpl;
|
||||||
|
import mage.abilities.costs.OptionalAdditionalSourceCosts;
|
||||||
|
import mage.abilities.costs.common.TapTargetCost;
|
||||||
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||||
|
import mage.filter.predicate.Predicates;
|
||||||
|
import mage.filter.predicate.mageobject.SharesColorWithSourcePredicate;
|
||||||
|
import mage.filter.predicate.permanent.TappedPredicate;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
|
import mage.game.stack.StackObject;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.common.TargetControlledPermanent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 702.77. Conspire 702.77a Conspire is a keyword that represents two abilities.
|
||||||
|
* The first is a static ability that functions while the spell with conspire is
|
||||||
|
* on the stack. The second is a triggered ability that functions while the
|
||||||
|
* spell with conspire is on the stack. "Conspire" means "As an additional cost
|
||||||
|
* to cast this spell, you may tap two untapped creatures you control that each
|
||||||
|
* share a color with it" and "When you cast this spell, if its conspire cost
|
||||||
|
* was paid, copy it. If the spell has any targets, you may choose new targets
|
||||||
|
* for the copy." Paying a spell’s conspire cost follows the rules for paying
|
||||||
|
* additional costs in rules 601.2b and 601.2e–g. 702.77b If a spell has
|
||||||
|
* multiple instances of conspire, each is paid separately and triggers based on
|
||||||
|
* its own payment, not any other instance of conspire. *
|
||||||
|
*
|
||||||
|
* @author jeffwadsworth heavily based off the replicate keyword by LevelX
|
||||||
|
*/
|
||||||
|
public class ConspireAbility extends StaticAbility implements OptionalAdditionalSourceCosts {
|
||||||
|
|
||||||
|
private static final String keywordText = "Conspire";
|
||||||
|
private static final String reminderTextCost = "<i>As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose a new target for the copy.)</i>";
|
||||||
|
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("two untapped creatures you control that share a color with it");
|
||||||
|
|
||||||
|
static {
|
||||||
|
filter.add(Predicates.not(new TappedPredicate()));
|
||||||
|
filter.add(new SharesColorWithSourcePredicate());
|
||||||
|
}
|
||||||
|
|
||||||
|
Cost costConspire = new TapTargetCost(new TargetControlledPermanent(2, 2, filter, false));
|
||||||
|
OptionalAdditionalCost conspireCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderTextCost, costConspire);
|
||||||
|
|
||||||
|
public ConspireAbility(Card card) {
|
||||||
|
super(Zone.STACK, null);
|
||||||
|
setRuleAtTheTop(false);
|
||||||
|
card.addAbility(new ConspireTriggeredAbility());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConspireAbility(final ConspireAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
conspireCost = ability.conspireCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConspireAbility copy() {
|
||||||
|
return new ConspireAbility(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addCost(Cost cost) {
|
||||||
|
if (conspireCost != null) {
|
||||||
|
((Costs) conspireCost).add(cost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActivated() {
|
||||||
|
if (conspireCost != null) {
|
||||||
|
return conspireCost.isActivated();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetConspire() {
|
||||||
|
if (conspireCost != null) {
|
||||||
|
conspireCost.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addOptionalAdditionalCosts(Ability ability, Game game) {
|
||||||
|
if (ability instanceof SpellAbility) {
|
||||||
|
Player player = game.getPlayer(controllerId);
|
||||||
|
if (player != null) {
|
||||||
|
this.resetConspire();
|
||||||
|
if (player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(conspireCost.getText(false)).append(" ?").toString(), game)) {
|
||||||
|
conspireCost.activate();
|
||||||
|
for (Iterator it = ((Costs) conspireCost).iterator(); it.hasNext();) {
|
||||||
|
Cost cost = (Cost) it.next();
|
||||||
|
ability.getCosts().add(cost.copy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRule() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (conspireCost != null) {
|
||||||
|
sb.append(conspireCost.getText(false));
|
||||||
|
sb.append(" ").append(conspireCost.getReminderText());
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCastMessageSuffix() {
|
||||||
|
if (conspireCost != null) {
|
||||||
|
return conspireCost.getCastSuffixMessage(0);
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReminderText() {
|
||||||
|
if (conspireCost != null) {
|
||||||
|
return conspireCost.getReminderText();
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConspireTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
|
public ConspireTriggeredAbility() {
|
||||||
|
super(Zone.STACK, new ConspireEffect());
|
||||||
|
this.setRuleVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConspireTriggeredAbility(final ConspireTriggeredAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConspireTriggeredAbility copy() {
|
||||||
|
return new ConspireTriggeredAbility(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
if (event.getType() == GameEvent.EventType.SPELL_CAST
|
||||||
|
&& event.getSourceId().equals(this.sourceId)) {
|
||||||
|
StackObject spell = game.getStack().getStackObject(this.sourceId);
|
||||||
|
if (spell instanceof Spell) {
|
||||||
|
Card card = game.getCard(spell.getSourceId());
|
||||||
|
if (card != null) {
|
||||||
|
for (Ability ability : card.getAbilities()) {
|
||||||
|
if (ability instanceof ConspireAbility) {
|
||||||
|
if (((ConspireAbility) ability).isActivated()) {
|
||||||
|
for (Effect effect : this.getEffects()) {
|
||||||
|
effect.setValue("ConspireSpell", spell);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRule() {
|
||||||
|
return "Conspire: <i>As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose a new target for the copy.)</i>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConspireEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
public ConspireEffect() {
|
||||||
|
super(Outcome.Copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConspireEffect(final ConspireEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
|
if (controller != null) {
|
||||||
|
Spell spell = (Spell) this.getValue("ConspireSpell");
|
||||||
|
if (spell != null) {
|
||||||
|
Card card = game.getCard(spell.getSourceId());
|
||||||
|
if (card != null) {
|
||||||
|
for (Ability ability : card.getAbilities()) {
|
||||||
|
if (ability instanceof ConspireAbility) {
|
||||||
|
if (((ConspireAbility) ability).isActivated()) {
|
||||||
|
((ConspireAbility) ability).resetConspire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spell copy = spell.copySpell();
|
||||||
|
copy.setControllerId(source.getControllerId());
|
||||||
|
copy.setCopiedSpell(true);
|
||||||
|
game.getStack().push(copy);
|
||||||
|
copy.chooseNewTargets(game, source.getControllerId());
|
||||||
|
game.informPlayers(new StringBuilder(controller.getName()).append(copy.getActivatedMessage(game)).toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConspireEffect copy() {
|
||||||
|
return new ConspireEffect(this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -71,7 +71,7 @@ public class ActivateOncePerTurnManaAbility extends ManaAbility {
|
||||||
@Override
|
@Override
|
||||||
public boolean canActivate(UUID playerId, Game game) {
|
public boolean canActivate(UUID playerId, Game game) {
|
||||||
if (super.canActivate(playerId, game)) {
|
if (super.canActivate(playerId, game)) {
|
||||||
ActivationInfo activationInfo = (ActivationInfo) game.getState().getValue(CardUtil.getCardZoneString("activations", sourceId, game));
|
ActivationInfo activationInfo = getActivationInfo(game);
|
||||||
if (activationInfo == null || activationInfo.turnNum != game.getTurnNum() || activationInfo.activationCounter < 1) {
|
if (activationInfo == null || activationInfo.turnNum != game.getTurnNum() || activationInfo.activationCounter < 1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ public class ActivateOncePerTurnManaAbility extends ManaAbility {
|
||||||
public boolean activate(Game game, boolean noMana) {
|
public boolean activate(Game game, boolean noMana) {
|
||||||
if (canActivate(this.controllerId, game)) {
|
if (canActivate(this.controllerId, game)) {
|
||||||
if (super.activate(game, noMana)) {
|
if (super.activate(game, noMana)) {
|
||||||
ActivationInfo activationInfo = (ActivationInfo) game.getState().getValue(CardUtil.getCardZoneString("activations", sourceId, game));
|
ActivationInfo activationInfo = getActivationInfo(game);
|
||||||
if (activationInfo == null) {
|
if (activationInfo == null) {
|
||||||
activationInfo = new ActivationInfo(game.getTurnNum(), 1);
|
activationInfo = new ActivationInfo(game.getTurnNum(), 1);
|
||||||
} else {
|
} else {
|
||||||
|
@ -94,21 +94,13 @@ public class ActivateOncePerTurnManaAbility extends ManaAbility {
|
||||||
activationInfo.activationCounter++;
|
activationInfo.activationCounter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
game.getState().setValue(CardUtil.getCardZoneString("activations", sourceId, game), activationInfo);
|
setActivationInfo(activationInfo, game);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean resolve(Game game) {
|
|
||||||
if (super.resolve(game)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRule() {
|
public String getRule() {
|
||||||
return super.getRule() + " Activate this ability only once each turn.";
|
return super.getRule() + " Activate this ability only once each turn.";
|
||||||
|
@ -119,4 +111,18 @@ public class ActivateOncePerTurnManaAbility extends ManaAbility {
|
||||||
return new ActivateOncePerTurnManaAbility(this);
|
return new ActivateOncePerTurnManaAbility(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ActivationInfo getActivationInfo(Game game) {
|
||||||
|
Integer turnNum = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsTurn", sourceId, game));
|
||||||
|
Integer activationCount = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsCount", sourceId, game));
|
||||||
|
if (turnNum == null || activationCount == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ActivationInfo(turnNum, activationCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setActivationInfo(ActivationInfo activationInfo, Game game) {
|
||||||
|
game.getState().setValue(CardUtil.getCardZoneString("activationsTurn", sourceId, game), activationInfo.turnNum);
|
||||||
|
game.getState().setValue(CardUtil.getCardZoneString("activationsCount", sourceId, game), activationInfo.activationCounter);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,13 +152,8 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
this.turnMods = state.turnMods.copy();
|
this.turnMods = state.turnMods.copy();
|
||||||
this.watchers = state.watchers.copy();
|
this.watchers = state.watchers.copy();
|
||||||
for (Map.Entry<String, Object> entry: state.values.entrySet()) {
|
for (Map.Entry<String, Object> entry: state.values.entrySet()) {
|
||||||
if (entry.getValue() instanceof Boolean) { // AI changed values of Boolean for cards like Wall of Roots TODO: copy other types than Boolean
|
|
||||||
this.values.put(entry.getKey(), Boolean.valueOf(((Boolean)entry.getValue()).toString()));
|
|
||||||
} else {
|
|
||||||
this.values.put(entry.getKey(), entry.getValue());
|
this.values.put(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
this.zones.putAll(state.zones);
|
this.zones.putAll(state.zones);
|
||||||
for (Map.Entry<UUID, Abilities<Ability>> entry: state.otherAbilities.entrySet()) {
|
for (Map.Entry<UUID, Abilities<Ability>> entry: state.otherAbilities.entrySet()) {
|
||||||
otherAbilities.put(entry.getKey(), entry.getValue().copy());
|
otherAbilities.put(entry.getKey(), entry.getValue().copy());
|
||||||
|
@ -646,6 +641,14 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
return values.get(valueId);
|
return values.get(valueId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Best only use immutable objects, otherwise the states/values of the object may be
|
||||||
|
* changed by AI simulation, because the Value objects are not copied as the state
|
||||||
|
* class is copied.
|
||||||
|
*
|
||||||
|
* @param valueId
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
public void setValue(String valueId, Object value) {
|
public void setValue(String valueId, Object value) {
|
||||||
values.put(valueId, value);
|
values.put(valueId, value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,4 +134,24 @@ public class PermanentToken extends PermanentImpl {
|
||||||
abilities.add(copyAbility);
|
abilities.add(copyAbility);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void adjustTargets(Ability ability, Game game) {
|
||||||
|
if (getToken().getCopySourceCard() != null) {
|
||||||
|
getToken().getCopySourceCard().adjustTargets(ability, game);
|
||||||
|
} else {
|
||||||
|
super.adjustTargets(ability, game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void adjustCosts(Ability ability, Game game) {
|
||||||
|
if (getToken().getCopySourceCard() != null) {
|
||||||
|
getToken().getCopySourceCard().adjustCosts(ability, game);
|
||||||
|
} else {
|
||||||
|
super.adjustCosts(ability, game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,13 +31,13 @@ package mage.game.permanent.token;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.MageObjectImpl;
|
import mage.MageObjectImpl;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
import mage.abilities.Abilities;
|
import mage.abilities.Abilities;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.events.GameEvent.EventType;
|
import mage.game.events.GameEvent.EventType;
|
||||||
|
@ -55,6 +55,7 @@ public class Token extends MageObjectImpl {
|
||||||
private int tokenType;
|
private int tokenType;
|
||||||
private int originalCardNumber;
|
private int originalCardNumber;
|
||||||
private String originalExpansionSetCode;
|
private String originalExpansionSetCode;
|
||||||
|
private Card copySourceCard; // the card the Token is a copy from
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
FIRST(1),
|
FIRST(1),
|
||||||
|
@ -96,6 +97,7 @@ public class Token extends MageObjectImpl {
|
||||||
this.lastAddedTokenIds.addAll(token.lastAddedTokenIds);
|
this.lastAddedTokenIds.addAll(token.lastAddedTokenIds);
|
||||||
this.originalCardNumber = token.originalCardNumber;
|
this.originalCardNumber = token.originalCardNumber;
|
||||||
this.originalExpansionSetCode = token.originalExpansionSetCode;
|
this.originalExpansionSetCode = token.originalExpansionSetCode;
|
||||||
|
this.copySourceCard = token.copySourceCard; // will never be changed
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
|
@ -193,4 +195,15 @@ public class Token extends MageObjectImpl {
|
||||||
this.originalExpansionSetCode = originalExpansionSetCode;
|
this.originalExpansionSetCode = originalExpansionSetCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Card getCopySourceCard() {
|
||||||
|
return copySourceCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCopySourceCard(Card copySourceCard) {
|
||||||
|
if (copySourceCard != null) {
|
||||||
|
this.copySourceCard = copySourceCard.copy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1113,7 +1113,11 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
//20091005 - 603.3c, 603.3d
|
//20091005 - 603.3c, 603.3d
|
||||||
int bookmark = game.bookmarkState();
|
int bookmark = game.bookmarkState();
|
||||||
TriggeredAbility ability = source.copy();
|
TriggeredAbility ability = source.copy();
|
||||||
if (ability != null && ability.canChooseTarget(game)) {
|
MageObject sourceObject = game.getObject(ability.getSourceId());
|
||||||
|
if (sourceObject != null) {
|
||||||
|
sourceObject.adjustTargets(ability, game);
|
||||||
|
}
|
||||||
|
if (ability.canChooseTarget(game)) {
|
||||||
if (ability.isUsesStack()) {
|
if (ability.isUsesStack()) {
|
||||||
game.getStack().push(new StackAbility(ability, playerId));
|
game.getStack().push(new StackAbility(ability, playerId));
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ public class CardUtil {
|
||||||
for (AlternativeCost alternativeCost : ability.getAlternativeCosts()) {
|
for (AlternativeCost alternativeCost : ability.getAlternativeCosts()) {
|
||||||
if (alternativeCost instanceof AlternativeCostImpl) {
|
if (alternativeCost instanceof AlternativeCostImpl) {
|
||||||
AlternativeCostImpl impl = (AlternativeCostImpl) alternativeCost;
|
AlternativeCostImpl impl = (AlternativeCostImpl) alternativeCost;
|
||||||
ManaCosts<ManaCost> adjustedCost = new ManaCostsImpl<ManaCost>();
|
ManaCosts<ManaCost> adjustedCost = new ManaCostsImpl<>();
|
||||||
boolean updated = false;
|
boolean updated = false;
|
||||||
Iterator it = impl.iterator();
|
Iterator it = impl.iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
|
|
|
@ -62,13 +62,18 @@ public class CopyTokenFunction implements Function<Token, Card> {
|
||||||
// to show the source image, the original values have to be used
|
// to show the source image, the original values have to be used
|
||||||
target.setOriginalExpansionSetCode(((Token)sourceObj).getOriginalExpansionSetCode());
|
target.setOriginalExpansionSetCode(((Token)sourceObj).getOriginalExpansionSetCode());
|
||||||
target.setOriginalCardNumber(((Token)sourceObj).getOriginalCardNumber());
|
target.setOriginalCardNumber(((Token)sourceObj).getOriginalCardNumber());
|
||||||
|
target.setCopySourceCard(((PermanentToken)source).getToken().getCopySourceCard());
|
||||||
} else if (source instanceof PermanentCard) {
|
} else if (source instanceof PermanentCard) {
|
||||||
sourceObj = ((PermanentCard) source).getCard();
|
sourceObj = ((PermanentCard) source).getCard();
|
||||||
target.setOriginalExpansionSetCode(source.getExpansionSetCode());
|
target.setOriginalExpansionSetCode(source.getExpansionSetCode());
|
||||||
target.setOriginalCardNumber(source.getCardNumber());
|
target.setOriginalCardNumber(source.getCardNumber());
|
||||||
|
target.setCopySourceCard((Card)sourceObj);
|
||||||
} else {
|
} else {
|
||||||
target.setOriginalExpansionSetCode(source.getExpansionSetCode());
|
target.setOriginalExpansionSetCode(source.getExpansionSetCode());
|
||||||
target.setOriginalCardNumber(source.getCardNumber());
|
target.setOriginalCardNumber(source.getCardNumber());
|
||||||
|
if (source instanceof Card) {
|
||||||
|
target.setCopySourceCard((Card)source);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
target.setName(sourceObj.getName());
|
target.setName(sourceObj.getName());
|
||||||
|
|
Loading…
Reference in a new issue