mirror of
https://github.com/correl/mage.git
synced 2024-11-14 19:19:32 +00:00
Added Spellweaver Volute.
This commit is contained in:
parent
bec07fb530
commit
bc490ef91a
14 changed files with 835 additions and 353 deletions
150
Mage.Sets/src/mage/cards/s/SpellweaverVolute.java
Normal file
150
Mage.Sets/src/mage/cards/s/SpellweaverVolute.java
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* 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.cards.s;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.FilterSpell;
|
||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInGraveyard;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class SpellweaverVolute extends CardImpl {
|
||||
|
||||
public SpellweaverVolute(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}");
|
||||
|
||||
this.subtype.add(SubType.AURA);
|
||||
|
||||
// Enchant instant card in a graveyard
|
||||
FilterCard filter = new FilterCard("instant card in a graveyard");
|
||||
filter.add(new CardTypePredicate(CardType.INSTANT));
|
||||
TargetCardInGraveyard auraTarget = new TargetCardInGraveyard(filter);
|
||||
this.getSpellAbility().addTarget(auraTarget);
|
||||
this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment));
|
||||
Ability ability = new EnchantAbility(auraTarget.getTargetName());
|
||||
this.addAbility(ability);
|
||||
|
||||
// Whenever you cast a sorcery spell, copy the enchanted instant card. You may cast the copy without paying its mana cost.
|
||||
// If you do, exile the enchanted card and attach Spellweaver Volute to another instant card in a graveyard.
|
||||
FilterSpell filterSpell = new FilterSpell("a sorcery spell");
|
||||
filterSpell.add(new CardTypePredicate(CardType.SORCERY));
|
||||
this.addAbility(new SpellCastControllerTriggeredAbility(new SpellweaverVoluteEffect(), filterSpell, false));
|
||||
}
|
||||
|
||||
public SpellweaverVolute(final SpellweaverVolute card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellweaverVolute copy() {
|
||||
return new SpellweaverVolute(this);
|
||||
}
|
||||
}
|
||||
|
||||
class SpellweaverVoluteEffect extends OneShotEffect {
|
||||
|
||||
public SpellweaverVoluteEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "copy the enchanted instant card. You may cast the copy without paying its mana cost. \n"
|
||||
+ "If you do, exile the enchanted card and attach {this} to another instant card in a graveyard";
|
||||
}
|
||||
|
||||
public SpellweaverVoluteEffect(final SpellweaverVoluteEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellweaverVoluteEffect copy() {
|
||||
return new SpellweaverVoluteEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
if (sourcePermanent != null && sourcePermanent.getAttachedTo() != null) {
|
||||
Card enchantedCard = game.getCard(sourcePermanent.getAttachedTo());
|
||||
if (enchantedCard != null && game.getState().getZone(enchantedCard.getId()) == Zone.GRAVEYARD) {
|
||||
Player ownerEnchanted = game.getPlayer(enchantedCard.getOwnerId());
|
||||
if (ownerEnchanted != null
|
||||
&& controller.chooseUse(outcome, "Create a copy of " + enchantedCard.getName() + '?', source, game)) {
|
||||
Card copiedCard = game.copyCard(enchantedCard, source, source.getControllerId());
|
||||
if (copiedCard != null) {
|
||||
ownerEnchanted.getGraveyard().add(copiedCard);
|
||||
game.getState().setZone(copiedCard.getId(), Zone.GRAVEYARD);
|
||||
if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) {
|
||||
if (copiedCard.getSpellAbility() != null) {
|
||||
controller.cast(copiedCard.getSpellAbility(), game, true);
|
||||
}
|
||||
if (controller.moveCards(enchantedCard, Zone.EXILED, source, game)) {
|
||||
FilterCard filter = new FilterCard("instant card in a graveyard");
|
||||
filter.add(new CardTypePredicate(CardType.INSTANT));
|
||||
TargetCardInGraveyard auraTarget = new TargetCardInGraveyard(filter);
|
||||
if (auraTarget.canChoose(source.getSourceId(), controller.getId(), game)) {
|
||||
controller.choose(outcome, auraTarget, source.getSourceId(), game);
|
||||
Card newAuraTarget = game.getCard(auraTarget.getFirstTarget());
|
||||
if (newAuraTarget != null) {
|
||||
if (enchantedCard.getId().equals(newAuraTarget.getId())) {
|
||||
} else if (newAuraTarget.addAttachment(sourcePermanent.getId(), game)) {
|
||||
game.informPlayers(sourcePermanent.getLogName() + " was attached to " + newAuraTarget.getLogName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -200,6 +200,7 @@ public class FutureSight extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Snake Cult Initiation", 89, Rarity.UNCOMMON, mage.cards.s.SnakeCultInitiation.class));
|
||||
cards.add(new SetCardInfo("Soultether Golem", 164, Rarity.UNCOMMON, mage.cards.s.SoultetherGolem.class));
|
||||
cards.add(new SetCardInfo("Sparkspitter", 109, Rarity.UNCOMMON, mage.cards.s.Sparkspitter.class));
|
||||
cards.add(new SetCardInfo("Spellweaver Volute", 59, Rarity.RARE, mage.cards.s.SpellweaverVolute.class));
|
||||
cards.add(new SetCardInfo("Spellwild Ouphe", 151, Rarity.UNCOMMON, mage.cards.s.SpellwildOuphe.class));
|
||||
cards.add(new SetCardInfo("Spin into Myth", 60, Rarity.UNCOMMON, mage.cards.s.SpinIntoMyth.class));
|
||||
cards.add(new SetCardInfo("Spirit en-Dal", 17, Rarity.UNCOMMON, mage.cards.s.SpiritEnDal.class));
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* 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.enchantments;
|
||||
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.permanent.Permanent;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class EnchantingGraveyardCardsTest extends CardTestPlayerBase {
|
||||
|
||||
static final String LIGHTNING_BOLT = "Lightning Bolt";
|
||||
static final String SPELLWEAVER_VOLUTE = "Spellweaver Volute";
|
||||
|
||||
/**
|
||||
* Test that a card in the graveyard can be enchanted
|
||||
*/
|
||||
@Test
|
||||
public void testSpellwaeverVoluteNormal() {
|
||||
// Enchant instant card in a graveyard
|
||||
// Whenever you cast a sorcery spell, copy the enchanted instant card. You may cast the copy without paying its mana cost.
|
||||
// If you do, exile the enchanted card and attach Spellweaver Volute to another instant card in a graveyard.
|
||||
addCard(Zone.HAND, playerA, SPELLWEAVER_VOLUTE, 1); // Enchantment Aura {3}{U}{U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||
|
||||
// Lightning Bolt deals 3 damage to target creature or player.
|
||||
addCard(Zone.GRAVEYARD, playerB, "Lightning Bolt", 1); // Instant {R}
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, SPELLWEAVER_VOLUTE, LIGHTNING_BOLT);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 20);
|
||||
|
||||
assertHandCount(playerA, 0);
|
||||
assertPermanentCount(playerA, SPELLWEAVER_VOLUTE, 1);
|
||||
assertGraveyardCount(playerB, LIGHTNING_BOLT, 1);
|
||||
|
||||
Permanent spellweaver = getPermanent(SPELLWEAVER_VOLUTE);
|
||||
Card attachedToCard = null;
|
||||
if (spellweaver != null) {
|
||||
attachedToCard = playerB.getGraveyard().get(spellweaver.getAttachedTo(), currentGame);
|
||||
}
|
||||
Assert.assertTrue(SPELLWEAVER_VOLUTE + " has to be attached to Lightning Bolt in graveyard", attachedToCard != null && attachedToCard.getName().equals(LIGHTNING_BOLT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a card in the graveyard can be enchanted and the enchanted card
|
||||
* switches to a new one
|
||||
*/
|
||||
@Test
|
||||
public void testSpellwaeverVoluteAndSorcery() {
|
||||
|
||||
// Enchant instant card in a graveyard
|
||||
// Whenever you cast a sorcery spell, copy the enchanted instant card. You may cast the copy without paying its mana cost.
|
||||
// If you do, exile the enchanted card and attach Spellweaver Volute to another instant card in a graveyard.
|
||||
addCard(Zone.HAND, playerA, SPELLWEAVER_VOLUTE, 1); // Enchantment Aura {3}{U}{U}
|
||||
addCard(Zone.HAND, playerA, "Cloak of Feathers"); // Sorcery {U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Aerial Volley", 1); // Instant {G}
|
||||
|
||||
// Lightning Bolt deals 3 damage to target creature or player.
|
||||
addCard(Zone.GRAVEYARD, playerB, "Lightning Bolt", 1); // Instant {R}
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, SPELLWEAVER_VOLUTE, LIGHTNING_BOLT);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cloak of Feathers", "Silvercoat Lion");
|
||||
setChoice(playerA, "Yes"); // play the L. Bold
|
||||
addTarget(playerA, playerB); // Add Target for the L. Bold
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 17);
|
||||
|
||||
assertHandCount(playerA, 1);
|
||||
assertGraveyardCount(playerA, "Cloak of Feathers", 1);
|
||||
assertPermanentCount(playerA, SPELLWEAVER_VOLUTE, 1);
|
||||
assertGraveyardCount(playerA, "Aerial Volley", 1);
|
||||
assertExileCount(playerB, LIGHTNING_BOLT, 1);
|
||||
assertAbility(playerA, "Silvercoat Lion", FlyingAbility.getInstance(), true);
|
||||
Permanent spellweaver = getPermanent(SPELLWEAVER_VOLUTE);
|
||||
Card attachedToCard = null;
|
||||
if (spellweaver != null) {
|
||||
attachedToCard = playerA.getGraveyard().get(spellweaver.getAttachedTo(), currentGame);
|
||||
}
|
||||
Assert.assertTrue(SPELLWEAVER_VOLUTE + " has to be attached to Aerial Volley in graveyard", attachedToCard != null && attachedToCard.getName().equals("Aerial Volley"));
|
||||
|
||||
assertHandCount(playerA, 1);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a card in the graveyard can be enchanted and the enchanted card
|
||||
* switches to a new one
|
||||
*/
|
||||
@Test
|
||||
public void testSpellwaeverVoluteAndSorceryWithoutNewTarget() {
|
||||
|
||||
// Enchant instant card in a graveyard
|
||||
// Whenever you cast a sorcery spell, copy the enchanted instant card. You may cast the copy without paying its mana cost.
|
||||
// If you do, exile the enchanted card and attach Spellweaver Volute to another instant card in a graveyard.
|
||||
addCard(Zone.HAND, playerA, SPELLWEAVER_VOLUTE, 1); // Enchantment Aura {3}{U}{U}
|
||||
addCard(Zone.HAND, playerA, "Cloak of Feathers"); // Sorcery {U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||
|
||||
// Lightning Bolt deals 3 damage to target creature or player.
|
||||
addCard(Zone.GRAVEYARD, playerB, "Lightning Bolt", 1); // Instant {R}
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, SPELLWEAVER_VOLUTE, LIGHTNING_BOLT);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cloak of Feathers", "Silvercoat Lion");
|
||||
setChoice(playerA, "Yes"); // play the L. Bold
|
||||
addTarget(playerA, playerB); // Add Target for the L. Bold
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 17);
|
||||
|
||||
assertHandCount(playerA, 1);
|
||||
assertGraveyardCount(playerA, "Cloak of Feathers", 1);
|
||||
assertPermanentCount(playerA, SPELLWEAVER_VOLUTE, 0);
|
||||
assertGraveyardCount(playerA, SPELLWEAVER_VOLUTE, 1);
|
||||
assertExileCount(playerB, LIGHTNING_BOLT, 1);
|
||||
assertAbility(playerA, "Silvercoat Lion", FlyingAbility.getInstance(), true);
|
||||
|
||||
assertGraveyardCount(playerA, SPELLWEAVER_VOLUTE, 1);
|
||||
|
||||
for (Card card : currentGame.getExile().getAllCards(currentGame)) {
|
||||
if (card.getName().equals(LIGHTNING_BOLT)) {
|
||||
Assert.assertTrue(LIGHTNING_BOLT + " may not have any attachments", card.getAttachments().isEmpty());
|
||||
|
||||
}
|
||||
}
|
||||
assertHandCount(playerA, 1);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a card in the graveyard can be enchanted and if the Enchantment
|
||||
* returns to hand, the enchanting ends
|
||||
*/
|
||||
@Test
|
||||
public void testSpellwaeverVoluteAndReturnToHand() {
|
||||
|
||||
// Enchant instant card in a graveyard
|
||||
// Whenever you cast a sorcery spell, copy the enchanted instant card. You may cast the copy without paying its mana cost.
|
||||
// If you do, exile the enchanted card and attach Spellweaver Volute to another instant card in a graveyard.
|
||||
addCard(Zone.HAND, playerA, SPELLWEAVER_VOLUTE, 1); // Enchantment Aura {3}{U}{U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||
|
||||
// Lightning Bolt deals 3 damage to target creature or player.
|
||||
addCard(Zone.GRAVEYARD, playerB, "Lightning Bolt", 1); // Instant {R}
|
||||
|
||||
// Return target permanent to its owner's hand.
|
||||
addCard(Zone.HAND, playerB, "Boomerang", 1); // Instant {U}{U}
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, SPELLWEAVER_VOLUTE, LIGHTNING_BOLT);
|
||||
|
||||
castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Boomerang", SPELLWEAVER_VOLUTE);
|
||||
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 20);
|
||||
|
||||
assertHandCount(playerA, SPELLWEAVER_VOLUTE, 1);
|
||||
assertGraveyardCount(playerB, "Boomerang", 1);
|
||||
assertPermanentCount(playerA, SPELLWEAVER_VOLUTE, 0);
|
||||
|
||||
for (Card card : playerB.getGraveyard().getCards(currentGame)) {
|
||||
if (card.getName().equals(LIGHTNING_BOLT)) {
|
||||
Assert.assertTrue(LIGHTNING_BOLT + " may not have any attachments", card.getAttachments().isEmpty());
|
||||
|
||||
}
|
||||
}
|
||||
assertHandCount(playerA, 1);
|
||||
|
||||
}
|
||||
}
|
|
@ -29,10 +29,12 @@ package mage.abilities.effects.common;
|
|||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -72,9 +74,16 @@ public class AttachEffect extends OneShotEffect {
|
|||
if (player != null) {
|
||||
return player.addAttachment(source.getSourceId(), game);
|
||||
}
|
||||
if (source.getTargets().get(0) instanceof TargetCard) { // e.g. Spellweaver Volute
|
||||
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
||||
if (card != null) {
|
||||
return card.addAttachment(source.getSourceId(), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,14 +27,11 @@
|
|||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.choices.Choice;
|
||||
import mage.choices.ChoiceCreatureType;
|
||||
import mage.choices.ChoiceImpl;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.game.Game;
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
*/
|
||||
package mage.cards;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
import mage.ObjectColor;
|
||||
|
@ -42,19 +44,14 @@ 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 {
|
||||
|
||||
|
||||
final String regexBlack = ".*\\x7b.{0,2}B.{0,2}\\x7d.*";
|
||||
final String regexBlue = ".*\\x7b.{0,2}U.{0,2}\\x7d.*";
|
||||
final String regexRed = ".*\\x7b.{0,2}R.{0,2}\\x7d.*";
|
||||
final String regexGreen = ".*\\x7b.{0,2}G.{0,2}\\x7d.*";
|
||||
final String regexWhite = ".*\\x7b.{0,2}W.{0,2}\\x7d.*";
|
||||
|
||||
|
||||
UUID getOwnerId();
|
||||
|
||||
String getCardNumber();
|
||||
|
@ -248,4 +245,9 @@ public interface Card extends MageObject {
|
|||
return mana;
|
||||
}
|
||||
|
||||
List<UUID> getAttachments();
|
||||
|
||||
boolean addAttachment(UUID permanentId, Game game);
|
||||
|
||||
boolean removeAttachment(UUID permanentId, Game game);
|
||||
}
|
||||
|
|
|
@ -94,6 +94,8 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
protected boolean morphCard;
|
||||
protected boolean allCreatureTypes;
|
||||
|
||||
protected List<UUID> attachments = new ArrayList<>();
|
||||
|
||||
public CardImpl(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costs) {
|
||||
this(ownerId, setInfo, cardTypes, costs, SpellAbilityType.BASE);
|
||||
}
|
||||
|
@ -169,6 +171,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
flipCardName = card.flipCardName;
|
||||
splitCard = card.splitCard;
|
||||
usesVariousArt = card.usesVariousArt;
|
||||
this.attachments.addAll(card.attachments);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -840,11 +843,53 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
return super.getSubtype(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllCreatureTypes() {
|
||||
return allCreatureTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIsAllCreatureTypes(boolean value) {
|
||||
allCreatureTypes = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UUID> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAttachment(UUID permanentId, Game game) {
|
||||
if (!this.attachments.contains(permanentId)) {
|
||||
Permanent attachment = game.getPermanent(permanentId);
|
||||
if (attachment == null) {
|
||||
attachment = game.getPermanentEntering(permanentId);
|
||||
}
|
||||
if (attachment != null) {
|
||||
if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ATTACH, objectId, permanentId, attachment.getControllerId()))) {
|
||||
this.attachments.add(permanentId);
|
||||
attachment.attachTo(objectId, game);
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.ATTACHED, objectId, permanentId, attachment.getControllerId()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAttachment(UUID permanentId, Game game) {
|
||||
if (this.attachments.contains(permanentId)) {
|
||||
Permanent attachment = game.getPermanent(permanentId);
|
||||
if (attachment != null) {
|
||||
attachment.unattach(game);
|
||||
}
|
||||
if (!game.replaceEvent(new GameEvent(GameEvent.EventType.UNATTACH, objectId, permanentId, attachment != null ? attachment.getControllerId() : null))) {
|
||||
this.attachments.remove(permanentId);
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, objectId, permanentId, attachment != null ? attachment.getControllerId() : null));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1901,6 +1901,15 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (target instanceof TargetCard) {
|
||||
Card attachedTo = getCard(perm.getAttachedTo());
|
||||
if (attachedTo == null
|
||||
|| !((TargetCard) spellAbility.getTargets().get(0)).canTarget(perm.getControllerId(), perm.getAttachedTo(), spellAbility, this)) {
|
||||
if (movePermanentToGraveyardWithInfo(perm)) {
|
||||
attachedTo.removeAttachment(perm.getId(), this);
|
||||
somethingHappened = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -233,7 +233,8 @@ public class GameEvent implements Serializable {
|
|||
PAID_CUMULATIVE_UPKEEP,
|
||||
DIDNT_PAY_CUMULATIVE_UPKEEP,
|
||||
//permanent events
|
||||
ENTERS_THE_BATTLEFIELD_SELF, // 616.1a If any of the replacement and/or prevention effects are self-replacement effects (see rule 614.15), one of them must be chosen. If not, proceed to rule 616.1b.
|
||||
ENTERS_THE_BATTLEFIELD_SELF, /* 616.1a If any of the replacement and/or prevention effects are self-replacement effects (see rule 614.15),
|
||||
one of them must be chosen. If not, proceed to rule 616.1b. */
|
||||
ENTERS_THE_BATTLEFIELD_CONTROL, // 616.1b
|
||||
ENTERS_THE_BATTLEFIELD_COPY, // 616.1c
|
||||
ENTERS_THE_BATTLEFIELD, // 616.1d
|
||||
|
|
|
@ -116,10 +116,11 @@ public interface Permanent extends Card, Controllable {
|
|||
|
||||
void attachTo(UUID permanentId, Game game);
|
||||
|
||||
boolean addAttachment(UUID permanentId, Game game);
|
||||
|
||||
boolean removeAttachment(UUID permanentId, Game game);
|
||||
void unattach(Game game);
|
||||
|
||||
// boolean addAttachment(UUID permanentId, Game game);
|
||||
//
|
||||
// boolean removeAttachment(UUID permanentId, Game game);
|
||||
boolean canBeTargetedBy(MageObject source, UUID controllerId, Game game);
|
||||
|
||||
boolean hasProtectionFrom(MageObject source, Game game);
|
||||
|
|
|
@ -56,6 +56,7 @@ import mage.game.permanent.token.SquirrelToken;
|
|||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.GameLog;
|
||||
import mage.util.ThreadLocalStringBuilder;
|
||||
|
@ -103,7 +104,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
protected int maxBlockedBy = 0;
|
||||
protected boolean removedFromCombat;
|
||||
protected boolean deathtouched;
|
||||
protected List<UUID> attachments = new ArrayList<>();
|
||||
|
||||
protected Map<String, List<UUID>> connectedCards = new HashMap<>();
|
||||
protected Set<MageObjectReference> dealtDamageByThisTurn;
|
||||
protected UUID attachedTo;
|
||||
|
@ -147,7 +148,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
this.blocking = permanent.blocking;
|
||||
this.maxBlocks = permanent.maxBlocks;
|
||||
this.deathtouched = permanent.deathtouched;
|
||||
this.attachments.addAll(permanent.attachments);
|
||||
// this.attachments.addAll(permanent.attachments);
|
||||
for (Map.Entry<String, List<UUID>> entry : permanent.connectedCards.entrySet()) {
|
||||
this.connectedCards.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
@ -626,47 +627,46 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
//
|
||||
// @Override
|
||||
// public List<UUID> getAttachments() {
|
||||
// return attachments;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public List<UUID> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAttachment(UUID permanentId, Game game) {
|
||||
if (!this.attachments.contains(permanentId)) {
|
||||
if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ATTACH, objectId, permanentId, controllerId))) {
|
||||
this.attachments.add(permanentId);
|
||||
Permanent attachment = game.getPermanent(permanentId);
|
||||
if (attachment == null) {
|
||||
attachment = game.getPermanentEntering(permanentId);
|
||||
}
|
||||
if (attachment != null) {
|
||||
attachment.attachTo(objectId, game);
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.ATTACHED, objectId, permanentId, controllerId));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAttachment(UUID permanentId, Game game) {
|
||||
if (this.attachments.contains(permanentId)) {
|
||||
if (!game.replaceEvent(new GameEvent(GameEvent.EventType.UNATTACH, objectId, permanentId, controllerId))) {
|
||||
this.attachments.remove(permanentId);
|
||||
Permanent attachment = game.getPermanent(permanentId);
|
||||
if (attachment != null) {
|
||||
attachment.attachTo(null, game);
|
||||
}
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, objectId, permanentId, controllerId));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean addAttachment(UUID permanentId, Game game) {
|
||||
// if (!this.attachments.contains(permanentId)) {
|
||||
// if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ATTACH, objectId, permanentId, controllerId))) {
|
||||
// this.attachments.add(permanentId);
|
||||
// Permanent attachment = game.getPermanent(permanentId);
|
||||
// if (attachment == null) {
|
||||
// attachment = game.getPermanentEntering(permanentId);
|
||||
// }
|
||||
// if (attachment != null) {
|
||||
// attachment.attachTo(objectId, game);
|
||||
// game.fireEvent(new GameEvent(GameEvent.EventType.ATTACHED, objectId, permanentId, controllerId));
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean removeAttachment(UUID permanentId, Game game) {
|
||||
// if (this.attachments.contains(permanentId)) {
|
||||
// if (!game.replaceEvent(new GameEvent(GameEvent.EventType.UNATTACH, objectId, permanentId, controllerId))) {
|
||||
// this.attachments.remove(permanentId);
|
||||
// Permanent attachment = game.getPermanent(permanentId);
|
||||
// if (attachment != null) {
|
||||
// attachment.attachTo(null, game);
|
||||
// }
|
||||
// game.fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, objectId, permanentId, controllerId));
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
@Override
|
||||
public UUID getAttachedTo() {
|
||||
return attachedTo;
|
||||
|
@ -705,15 +705,27 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void attachTo(UUID permanentId, Game game) {
|
||||
if (this.attachedTo != null && !Objects.equals(this.attachedTo, permanentId)) {
|
||||
Permanent attachment = game.getPermanent(this.attachedTo);
|
||||
if (attachment != null) {
|
||||
attachment.removeAttachment(this.objectId, game);
|
||||
public void unattach(Game game) {
|
||||
this.attachedTo = null;
|
||||
this.addInfo("attachedToCard", null, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachTo(UUID attachToObjectId, Game game) {
|
||||
if (this.attachedTo != null && !Objects.equals(this.attachedTo, attachToObjectId)) {
|
||||
Permanent attachedToUntilNowObject = game.getPermanent(this.attachedTo);
|
||||
if (attachedToUntilNowObject != null) {
|
||||
attachedToUntilNowObject.removeAttachment(this.objectId, game);
|
||||
} else {
|
||||
Card attachedToUntilNowCard = game.getCard(this.attachedTo);
|
||||
if (attachedToUntilNowCard != null) {
|
||||
attachedToUntilNowCard.removeAttachment(this.objectId, game);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
this.attachedTo = permanentId;
|
||||
this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(permanentId);
|
||||
this.attachedTo = attachToObjectId;
|
||||
this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(attachToObjectId);
|
||||
for (Ability ability : this.getAbilities()) {
|
||||
for (Iterator<Effect> ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext();) {
|
||||
ContinuousEffect effect = (ContinuousEffect) ite.next();
|
||||
|
@ -726,6 +738,13 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!getSpellAbility().getTargets().isEmpty() && (getSpellAbility().getTargets().get(0) instanceof TargetCard)) {
|
||||
Card attachedToCard = game.getCard(this.getAttachedTo());
|
||||
if (attachedToCard != null) {
|
||||
// Because cards are not on the battlefield, the relation has to be shown in the card tooltip (e.g. the enchanted card in graveyard)
|
||||
this.addInfo("attachedToCard", CardUtil.addToolTipMarkTags("Enchanted card: " + attachedToCard.getIdName()), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -955,4 +955,19 @@ public class Spell extends StackObjImpl implements Card {
|
|||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UUID> getAttachments() {
|
||||
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAttachment(UUID permanentId, Game game) {
|
||||
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAttachment(UUID permanentId, Game game) {
|
||||
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -817,6 +817,11 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
Player attachedToPlayer = game.getPlayer(permanent.getAttachedTo());
|
||||
if (attachedToPlayer != null) {
|
||||
attachedToPlayer.removeAttachment(permanent, game);
|
||||
} else {
|
||||
Card attachedToCard = game.getCard(permanent.getAttachedTo());
|
||||
if (attachedToCard != null) {
|
||||
attachedToCard.removeAttachment(permanent.getId(), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2326,7 +2331,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
newTarget.setCardLimit(Math.min(librarySearchLimit, cardsFromTop.size()));
|
||||
count = Math.min(searchedLibrary.count(target.getFilter(), game), librarySearchLimit);
|
||||
}
|
||||
|
||||
|
||||
if (count < target.getNumberOfTargets()) {
|
||||
newTarget.setMinNumberOfTargets(count);
|
||||
}
|
||||
|
@ -3278,9 +3283,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Card card, Zone toZone,
|
||||
Ability source, Game game
|
||||
) {
|
||||
public boolean moveCards(Card card, Zone toZone, Ability source, Game game) {
|
||||
return moveCards(card, toZone, source, game, false, false, false, null);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,288 +1,298 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
#author: North
|
||||
|
||||
use Text::Template;
|
||||
use strict;
|
||||
|
||||
|
||||
my $authorFile = 'author.txt';
|
||||
my $dataFile = "mtg-cards-data.txt";
|
||||
my $setsFile = "mtg-sets-data.txt";
|
||||
my $knownSetsFile = "known-sets.txt";
|
||||
|
||||
|
||||
my %cards;
|
||||
my %sets;
|
||||
my %knownSets;
|
||||
|
||||
my @setCards;
|
||||
|
||||
# gets the set name
|
||||
my $setName = $ARGV[0];
|
||||
if(!$setName) {
|
||||
print 'Enter a set name: ';
|
||||
$setName = <STDIN>;
|
||||
chomp $setName;
|
||||
}
|
||||
|
||||
my $template = Text::Template->new(TYPE => 'FILE', SOURCE => 'cardExtendedClass.tmpl', DELIMITERS => [ '[=', '=]' ]);
|
||||
my $templateBasicLand = Text::Template->new(TYPE => 'FILE', SOURCE => 'cardExtendedLandClass.tmpl', DELIMITERS => [ '[=', '=]' ]);
|
||||
|
||||
sub toCamelCase {
|
||||
my $string = $_[0];
|
||||
$string =~ s/\b([\w']+)\b/ucfirst($1)/ge;
|
||||
$string =~ s/[-,\s\'\/]//g;
|
||||
$string;
|
||||
}
|
||||
|
||||
my $author;
|
||||
if (-e $authorFile) {
|
||||
open (DATA, $authorFile);
|
||||
$author = <DATA>;
|
||||
close(DATA);
|
||||
} else {
|
||||
$author = 'anonymous';
|
||||
}
|
||||
|
||||
my $cardsFound = 0;
|
||||
my %all_sets;
|
||||
|
||||
print ("Opening $dataFile\n");
|
||||
open (DATA, $dataFile) || die "can't open $dataFile";
|
||||
while(my $line = <DATA>) {
|
||||
my @data = split('\\|', $line);
|
||||
$cards{$data[0]}{$data[1]} = \@data;
|
||||
|
||||
if ($data[1] eq $setName) {
|
||||
my $cardInfo = "$data[0],,,$data[2]";
|
||||
|
||||
push(@setCards, $cardInfo);
|
||||
} else {
|
||||
$all_sets {$data[1]} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Fix up split cards
|
||||
my $potentialSideA;
|
||||
my @tempSetCards;
|
||||
|
||||
foreach $potentialSideA (sort @setCards) {
|
||||
#print (">>$potentialSideA\n");
|
||||
if ($potentialSideA =~ m/.*,,,(\d+)(a)$/) {
|
||||
my $cardNumSideB = $1 . "b";
|
||||
my $orig_cardNumSideB = $1 . "b";
|
||||
my $val;
|
||||
foreach $val (sort @setCards) {
|
||||
if ($val =~ m/$cardNumSideB$/) {
|
||||
$potentialSideA =~ s/,,,.*//;
|
||||
$val =~ s/,,,.*//;
|
||||
|
||||
# Add 'SideaSideb' to %cards
|
||||
my $ds = $cards{$val}{$setName};
|
||||
print ("$potentialSideA$val,,,$cardNumSideB\n");
|
||||
my @newCard;
|
||||
push (@newCard, "$potentialSideA$val");
|
||||
push (@newCard, "$setName");
|
||||
push (@newCard, "SPLIT");
|
||||
push (@newCard, @$ds[3]);
|
||||
push (@newCard, "$potentialSideA // $val");
|
||||
$cards{$newCard[0]}{$newCard[1]} = \@newCard;
|
||||
|
||||
$cardNumSideB =~ s/.$//;
|
||||
push (@tempSetCards, "$potentialSideA$val,,,$cardNumSideB");
|
||||
|
||||
print ("Adding in: $potentialSideA \/\/ $val,,,$cardNumSideB\n");
|
||||
$cardsFound = $cardsFound - 1;
|
||||
$cardNumSideB = $orig_cardNumSideB;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($potentialSideA =~ m/.*,,,(\d+)(b)$/) {
|
||||
next;
|
||||
}
|
||||
else {
|
||||
$cardsFound = $cardsFound + 1;
|
||||
push (@tempSetCards, $potentialSideA);
|
||||
}
|
||||
}
|
||||
@setCards = @tempSetCards;
|
||||
|
||||
close(DATA);
|
||||
print "Number of cards found for set " . $setName . ": " . $cardsFound . "\n";
|
||||
|
||||
|
||||
if ($cardsFound == 0) {
|
||||
$setName =~ s/^(...).*/$1/;
|
||||
my $poss;
|
||||
my $foundPossibleSet = 0;
|
||||
my $numPossibleSets = 0;
|
||||
foreach $poss (sort keys (%all_sets)) {
|
||||
$numPossibleSets++;
|
||||
if ($poss =~ m/^$setName/i) {
|
||||
print ("Did you possibly mean: $poss ?\n");
|
||||
$foundPossibleSet = 1;
|
||||
}
|
||||
}
|
||||
if (!$foundPossibleSet) {
|
||||
print ("Couldn't find any matching set for '$setName'. \n");
|
||||
}
|
||||
|
||||
print "(Note: Looked at $numPossibleSets sets in total).\nPress the enter key to exit.";
|
||||
$setName = <STDIN>;
|
||||
exit;
|
||||
}
|
||||
|
||||
open (DATA, $setsFile) || die "can't open $setsFile";
|
||||
|
||||
while(my $line = <DATA>) {
|
||||
my @data = split('\\|', $line);
|
||||
$sets{$data[0]}= $data[1];
|
||||
}
|
||||
close(DATA);
|
||||
|
||||
open (DATA, $knownSetsFile) || die "can't open $knownSetsFile";
|
||||
while(my $line = <DATA>) {
|
||||
my @data = split('\\|', $line);
|
||||
$knownSets{$data[0]}= $data[1];
|
||||
}
|
||||
close(DATA);
|
||||
|
||||
my %raritiesConversion;
|
||||
$raritiesConversion{'C'} = 'COMMON';
|
||||
$raritiesConversion{'U'} = 'UNCOMMON';
|
||||
$raritiesConversion{'R'} = 'RARE';
|
||||
$raritiesConversion{'M'} = 'MYTHIC';
|
||||
$raritiesConversion{'Special'} = 'SPECIAL';
|
||||
$raritiesConversion{'Bonus'} = 'BONUS';
|
||||
sub getRarity
|
||||
{
|
||||
my $val = $_ [0];
|
||||
if (exists ($raritiesConversion {$val}))
|
||||
{
|
||||
return $raritiesConversion {$val};
|
||||
}
|
||||
print ("ERROR DETECTED! - Incorrect rarity.. --- $val,,,$_[1]\n");
|
||||
sleep (10);
|
||||
print "Press the enter key to exit.";
|
||||
$setName = <STDIN>;
|
||||
exit;
|
||||
}
|
||||
|
||||
# Generate the cards
|
||||
|
||||
my %vars;
|
||||
$vars{'author'} = $author;
|
||||
$vars{'set'} = $knownSets{$setName};
|
||||
$vars{'expansionSetCode'} = $sets{$setName};
|
||||
|
||||
my $landForest = 0;
|
||||
my $landMountain = 0;
|
||||
my $landSwamp = 0;
|
||||
my $landPlains = 0;
|
||||
my $landIsland = 0;
|
||||
|
||||
print ("Reading in existing cards in set\n");
|
||||
open (SET_FILE, "../../mage/Mage.Sets/src/mage/sets/$knownSets{$setName}.java") || die "can't open $dataFile";
|
||||
my %alreadyIn;
|
||||
while (<SET_FILE>) {
|
||||
my $line = $_;
|
||||
if ($line =~ m/SetCardInfo.*\("(.*)", (\d+).*/)
|
||||
{
|
||||
$alreadyIn {$2} = $1;
|
||||
}
|
||||
}
|
||||
close SET_FILE;
|
||||
|
||||
my $name_collectorid;
|
||||
my %implemented;
|
||||
my %implementedButNotInSetYet;
|
||||
my %unimplemented;
|
||||
|
||||
|
||||
my %githubTask;
|
||||
|
||||
foreach $name_collectorid (sort @setCards)
|
||||
{
|
||||
my $cardName;
|
||||
my $cardNr;
|
||||
$name_collectorid =~ m/^(.*),,,(.*)$/;
|
||||
$cardName = $1;
|
||||
$cardNr = $2;
|
||||
{
|
||||
if($cardName eq "Forest" || $cardName eq "Island" || $cardName eq "Plains" || $cardName eq "Swamp" || $cardName eq "Mountain") {
|
||||
my $found = 0;
|
||||
if ($cardName eq "Forest") {
|
||||
$landForest++;
|
||||
}
|
||||
if ($cardName eq "Mountain") {
|
||||
$landMountain++;
|
||||
}
|
||||
if ($cardName eq "Swamp") {
|
||||
$landSwamp++;
|
||||
}
|
||||
if ($cardName eq "Plains") {
|
||||
$landPlains++;
|
||||
}
|
||||
if ($cardName eq "Island") {
|
||||
$landIsland++;
|
||||
}
|
||||
if (!exists ($alreadyIn{$cardNr})) {
|
||||
print (" cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity.LAND, mage.cards.basiclands.$cardName.class, USE_RANDOM_ART));\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
my $ds;
|
||||
$ds = $cards{$cardName}{$setName};
|
||||
my $className = toCamelCase($cardName);
|
||||
my $setId = lc($cardName);
|
||||
$setId =~ s/^(.).*/$1/;
|
||||
my $googleSetName = $setName;
|
||||
$googleSetName =~ s/ /+/img;
|
||||
my $fn = "..\\Mage.Sets\\src\\mage\\cards\\$setId\\$className.java";
|
||||
my $str = " cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity." . getRarity ($cards{$cardName}{$setName}[3], $cardName) . ", mage.cards.$setId.$className.class));\n";
|
||||
|
||||
if (@$ds[2] eq "SPLIT") {
|
||||
my $oldCardName = $cardName;
|
||||
$cardName = @$ds[4];
|
||||
$str = " cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity." . getRarity ($cards{$oldCardName}{$setName}[3], $oldCardName) . ", mage.cards.$setId.$className.class));\n";
|
||||
}
|
||||
|
||||
my $plus_cardName = $cardName;
|
||||
$plus_cardName =~ s/ /+/img;
|
||||
$plus_cardName =~ s/,/+/img;
|
||||
$plus_cardName = "intext:\"$plus_cardName\"";
|
||||
|
||||
if (!exists ($alreadyIn{$cardNr})) {
|
||||
# Go Looking for the existing implementation..
|
||||
if (-e $fn) {
|
||||
$implementedButNotInSetYet {$str} = 1;
|
||||
$githubTask {"- [ ] Implemented but have to add to set -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1;
|
||||
} else {
|
||||
$unimplemented {"$str"} = 1;
|
||||
$githubTask {"- [ ] Not done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1;
|
||||
}
|
||||
} else {
|
||||
if (-e $fn) {
|
||||
$implemented {$str} = 1;
|
||||
$githubTask {"- [x] Done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1;
|
||||
} else {
|
||||
$unimplemented {$str} = 1;
|
||||
$githubTask {"- [ ] Not done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print "Implemented cards:\n";
|
||||
print (join ("", sort keys (%implemented)));
|
||||
print "\n\n\nImplemented but-not-yet-added-to-set cards:\n";
|
||||
print (join ("", sort keys (%implementedButNotInSetYet)));
|
||||
print "\n\n\nUnimplemented cards:\n";
|
||||
print (join ("", sort keys (%unimplemented)));
|
||||
print "\n\n\nGithub Task:\n";
|
||||
print (join ("", sort keys (%githubTask)));
|
||||
print ("\nData from reading: ../../mage/Mage.Sets/src/mage/sets/$knownSets{$setName}.java\n");
|
||||
print "\n\nYou are done. Press the enter key to exit.";
|
||||
$setName = <STDIN>;
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
#author: North
|
||||
|
||||
use Text::Template;
|
||||
use strict;
|
||||
|
||||
|
||||
my $authorFile = 'author.txt';
|
||||
my $dataFile = "mtg-cards-data.txt";
|
||||
my $setsFile = "mtg-sets-data.txt";
|
||||
my $knownSetsFile = "known-sets.txt";
|
||||
|
||||
|
||||
my %cards;
|
||||
my %sets;
|
||||
my %knownSets;
|
||||
|
||||
my @setCards;
|
||||
|
||||
# gets the set name
|
||||
my $setName = $ARGV[0];
|
||||
if(!$setName) {
|
||||
print 'Enter a set name: ';
|
||||
$setName = <STDIN>;
|
||||
chomp $setName;
|
||||
}
|
||||
|
||||
my $template = Text::Template->new(TYPE => 'FILE', SOURCE => 'cardExtendedClass.tmpl', DELIMITERS => [ '[=', '=]' ]);
|
||||
my $templateBasicLand = Text::Template->new(TYPE => 'FILE', SOURCE => 'cardExtendedLandClass.tmpl', DELIMITERS => [ '[=', '=]' ]);
|
||||
|
||||
sub toCamelCase {
|
||||
my $string = $_[0];
|
||||
$string =~ s/\b([\w']+)\b/ucfirst($1)/ge;
|
||||
$string =~ s/[-,\s\'\/]//g;
|
||||
$string;
|
||||
}
|
||||
|
||||
my $author;
|
||||
if (-e $authorFile) {
|
||||
open (DATA, $authorFile);
|
||||
$author = <DATA>;
|
||||
close(DATA);
|
||||
} else {
|
||||
$author = 'anonymous';
|
||||
}
|
||||
|
||||
my $cardsFound = 0;
|
||||
my %all_sets;
|
||||
|
||||
print ("Opening $dataFile\n");
|
||||
open (DATA, $dataFile) || die "can't open $dataFile";
|
||||
while(my $line = <DATA>) {
|
||||
my @data = split('\\|', $line);
|
||||
$cards{$data[0]}{$data[1]} = \@data;
|
||||
|
||||
if ($data[1] eq $setName) {
|
||||
my $cardInfo = "$data[0],,,$data[2]";
|
||||
|
||||
push(@setCards, $cardInfo);
|
||||
} else {
|
||||
$all_sets {$data[1]} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Fix up split cards
|
||||
my $potentialSideA;
|
||||
my @tempSetCards;
|
||||
|
||||
foreach $potentialSideA (sort @setCards) {
|
||||
#print (">>$potentialSideA\n");
|
||||
if ($potentialSideA =~ m/.*,,,(\d+)(a)$/) {
|
||||
my $cardNumSideB = $1 . "b";
|
||||
my $orig_cardNumSideB = $1 . "b";
|
||||
my $val;
|
||||
foreach $val (sort @setCards) {
|
||||
if ($val =~ m/$cardNumSideB$/) {
|
||||
$potentialSideA =~ s/,,,.*//;
|
||||
$val =~ s/,,,.*//;
|
||||
|
||||
# Add 'SideaSideb' to %cards
|
||||
my $ds = $cards{$val}{$setName};
|
||||
print ("$potentialSideA$val,,,$cardNumSideB\n");
|
||||
my @newCard;
|
||||
push (@newCard, "$potentialSideA$val");
|
||||
push (@newCard, "$setName");
|
||||
push (@newCard, "SPLIT");
|
||||
push (@newCard, @$ds[3]);
|
||||
push (@newCard, "$potentialSideA // $val");
|
||||
$cards{$newCard[0]}{$newCard[1]} = \@newCard;
|
||||
|
||||
$cardNumSideB =~ s/.$//;
|
||||
push (@tempSetCards, "$potentialSideA$val,,,$cardNumSideB");
|
||||
|
||||
print ("Adding in: $potentialSideA \/\/ $val,,,$cardNumSideB\n");
|
||||
$cardsFound = $cardsFound - 1;
|
||||
$cardNumSideB = $orig_cardNumSideB;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($potentialSideA =~ m/.*,,,(\d+)(b)$/) {
|
||||
next;
|
||||
}
|
||||
else {
|
||||
$cardsFound = $cardsFound + 1;
|
||||
push (@tempSetCards, $potentialSideA);
|
||||
}
|
||||
}
|
||||
@setCards = @tempSetCards;
|
||||
|
||||
close(DATA);
|
||||
print "Number of cards found for set " . $setName . ": " . $cardsFound . "\n";
|
||||
|
||||
|
||||
if ($cardsFound == 0) {
|
||||
$setName =~ s/^(...).*/$1/;
|
||||
my $poss;
|
||||
my $foundPossibleSet = 0;
|
||||
my $numPossibleSets = 0;
|
||||
foreach $poss (sort keys (%all_sets)) {
|
||||
$numPossibleSets++;
|
||||
if ($poss =~ m/^$setName/i) {
|
||||
print ("Did you possibly mean: $poss ?\n");
|
||||
$foundPossibleSet = 1;
|
||||
}
|
||||
}
|
||||
if (!$foundPossibleSet) {
|
||||
print ("Couldn't find any matching set for '$setName'. \n");
|
||||
}
|
||||
|
||||
print "(Note: Looked at $numPossibleSets sets in total).\nPress the enter key to exit.";
|
||||
$setName = <STDIN>;
|
||||
exit;
|
||||
}
|
||||
|
||||
open (DATA, $setsFile) || die "can't open $setsFile";
|
||||
|
||||
while(my $line = <DATA>) {
|
||||
my @data = split('\\|', $line);
|
||||
$sets{$data[0]}= $data[1];
|
||||
}
|
||||
close(DATA);
|
||||
|
||||
open (DATA, $knownSetsFile) || die "can't open $knownSetsFile";
|
||||
while(my $line = <DATA>) {
|
||||
my @data = split('\\|', $line);
|
||||
$knownSets{$data[0]}= $data[1];
|
||||
}
|
||||
close(DATA);
|
||||
|
||||
my %raritiesConversion;
|
||||
$raritiesConversion{'C'} = 'COMMON';
|
||||
$raritiesConversion{'U'} = 'UNCOMMON';
|
||||
$raritiesConversion{'R'} = 'RARE';
|
||||
$raritiesConversion{'M'} = 'MYTHIC';
|
||||
$raritiesConversion{'Special'} = 'SPECIAL';
|
||||
$raritiesConversion{'Bonus'} = 'BONUS';
|
||||
sub getRarity
|
||||
{
|
||||
my $val = $_ [0];
|
||||
if (exists ($raritiesConversion {$val}))
|
||||
{
|
||||
return $raritiesConversion {$val};
|
||||
}
|
||||
print ("ERROR DETECTED! - Incorrect rarity.. --- $val,,,$_[1]\n");
|
||||
sleep (10);
|
||||
print "Press the enter key to exit.";
|
||||
$setName = <STDIN>;
|
||||
exit;
|
||||
}
|
||||
|
||||
# Generate the cards
|
||||
|
||||
my %vars;
|
||||
$vars{'author'} = $author;
|
||||
$vars{'set'} = $knownSets{$setName};
|
||||
$vars{'expansionSetCode'} = $sets{$setName};
|
||||
|
||||
my $landForest = 0;
|
||||
my $landMountain = 0;
|
||||
my $landSwamp = 0;
|
||||
my $landPlains = 0;
|
||||
my $landIsland = 0;
|
||||
|
||||
print ("Reading in existing cards in set\n");
|
||||
open (SET_FILE, "../../mage/Mage.Sets/src/mage/sets/$knownSets{$setName}.java") || die "can't open $dataFile";
|
||||
my %alreadyIn;
|
||||
while (<SET_FILE>) {
|
||||
my $line = $_;
|
||||
if ($line =~ m/SetCardInfo.*\("(.*)", (\d+).*/)
|
||||
{
|
||||
$alreadyIn {$2} = $1;
|
||||
}
|
||||
}
|
||||
close SET_FILE;
|
||||
|
||||
my $name_collectorid;
|
||||
my %implemented;
|
||||
my %implementedButNotInSetYet;
|
||||
my %unimplemented;
|
||||
|
||||
|
||||
my %githubTask;
|
||||
|
||||
foreach $name_collectorid (sort @setCards)
|
||||
{
|
||||
my $cardName;
|
||||
my $cardNr;
|
||||
$name_collectorid =~ m/^(.*),,,(.*)$/;
|
||||
$cardName = $1;
|
||||
$cardNr = $2;
|
||||
{
|
||||
if($cardName eq "Forest" || $cardName eq "Island" || $cardName eq "Plains" || $cardName eq "Swamp" || $cardName eq "Mountain") {
|
||||
my $found = 0;
|
||||
if ($cardName eq "Forest") {
|
||||
$landForest++;
|
||||
}
|
||||
if ($cardName eq "Mountain") {
|
||||
$landMountain++;
|
||||
}
|
||||
if ($cardName eq "Swamp") {
|
||||
$landSwamp++;
|
||||
}
|
||||
if ($cardName eq "Plains") {
|
||||
$landPlains++;
|
||||
}
|
||||
if ($cardName eq "Island") {
|
||||
$landIsland++;
|
||||
}
|
||||
if (!exists ($alreadyIn{$cardNr})) {
|
||||
print (" cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity.LAND, mage.cards.basiclands.$cardName.class, USE_RANDOM_ART));\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
my $ds;
|
||||
$ds = $cards{$cardName}{$setName};
|
||||
my $className = toCamelCase($cardName);
|
||||
my $setId = lc($cardName);
|
||||
$setId =~ s/^(.).*/$1/;
|
||||
my $googleSetName = $setName;
|
||||
$googleSetName =~ s/ /+/img;
|
||||
my $fn = "..\\Mage.Sets\\src\\mage\\cards\\$setId\\$className.java";
|
||||
my $str = " cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity." . getRarity ($cards{$cardName}{$setName}[3], $cardName) . ", mage.cards.$setId.$className.class));\n";
|
||||
|
||||
if (@$ds[2] eq "SPLIT") {
|
||||
my $oldCardName = $cardName;
|
||||
$cardName = @$ds[4];
|
||||
$str = " cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity." . getRarity ($cards{$oldCardName}{$setName}[3], $oldCardName) . ", mage.cards.$setId.$className.class));\n";
|
||||
}
|
||||
|
||||
my $plus_cardName = $cardName;
|
||||
$plus_cardName =~ s/ /+/img;
|
||||
$plus_cardName =~ s/,/+/img;
|
||||
$plus_cardName = "intext:\"$plus_cardName\"";
|
||||
|
||||
if (!exists ($alreadyIn{$cardNr})) {
|
||||
# Go Looking for the existing implementation..
|
||||
if (-e $fn) {
|
||||
$implementedButNotInSetYet {$str} = 1;
|
||||
$githubTask {"- [ ] Implemented but have to add to set -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1;
|
||||
} else {
|
||||
$unimplemented {"$str"} = 1;
|
||||
$githubTask {"- [ ] Not done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1;
|
||||
}
|
||||
} else {
|
||||
if (-e $fn) {
|
||||
$implemented {$str} = 1;
|
||||
$githubTask {"- [x] Done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1;
|
||||
} else {
|
||||
$unimplemented {$str} = 1;
|
||||
$githubTask {"- [ ] Not done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Add logic to add the missing card lines to set file automatically
|
||||
#my $setFileName = "../Mage.Sets/src/mage/sets/".$knownSets{$setName}.".java";
|
||||
#print (join("","Add already implemented cards to set file: ", $setFileName,"\n"));
|
||||
#foreach my $line (sort keys (%implementedButNotInSetYet)) {
|
||||
# - Do action to add the line
|
||||
# print $line;
|
||||
#}
|
||||
|
||||
|
||||
print "Implemented cards:\n";
|
||||
print (join ("", sort keys (%implemented)));
|
||||
print "\n\n\nImplemented but-not-yet-added-to-set cards:\n";
|
||||
print (join ("", sort keys (%implementedButNotInSetYet)));
|
||||
print "\n\n\nUnimplemented cards:\n";
|
||||
print (join ("", sort keys (%unimplemented)));
|
||||
print "\n\n\nGithub Task:\n";
|
||||
print (join ("", sort keys (%githubTask)));
|
||||
print ("\nData from reading: ../../mage/Mage.Sets/src/mage/sets/$knownSets{$setName}.java\n");
|
||||
|
||||
print "\n\nYou are done. Press the enter key to exit.";
|
||||
$setName = <STDIN>;
|
||||
|
|
Loading…
Reference in a new issue